aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/linux
diff options
context:
space:
mode:
authorAndrea Adami <andrea.adami@gmail.com>2011-04-26 00:43:47 +0200
committerAndrea Adami <andrea.adami@gmail.com>2011-04-26 01:11:56 +0200
commit1710d7230e1cb23c590533191ddffe2f1de27928 (patch)
tree56dcfcb42d23b803a92b4307c7e61c044779e577 /recipes/linux
parent8d9d67990278381dad7e862fe138399165165e8b (diff)
downloadopenembedded-1710d7230e1cb23c590533191ddffe2f1de27928.tar.gz
mnci: move to nonworking, obsolete mnci-ramses 2.4 kernel
* machines with 2.4 kernels are not supported Signed-off-by: Andrea Adami <andrea.adami@gmail.com>
Diffstat (limited to 'recipes/linux')
-rw-r--r--recipes/linux/mnci-ramses-2.4.21-rmk2-pxa1/diff-2.4.21-rmk2-pxa1.gzbin248024 -> 0 bytes
-rw-r--r--recipes/linux/mnci-ramses-2.4.21-rmk2-pxa1/mnci-combined.patch108070
-rw-r--r--recipes/linux/mnci-ramses_2.4.21-rmk2-pxa1.bb75
3 files changed, 0 insertions, 108145 deletions
diff --git a/recipes/linux/mnci-ramses-2.4.21-rmk2-pxa1/diff-2.4.21-rmk2-pxa1.gz b/recipes/linux/mnci-ramses-2.4.21-rmk2-pxa1/diff-2.4.21-rmk2-pxa1.gz
deleted file mode 100644
index b11188efc1..0000000000
--- a/recipes/linux/mnci-ramses-2.4.21-rmk2-pxa1/diff-2.4.21-rmk2-pxa1.gz
+++ /dev/null
Binary files differ
diff --git a/recipes/linux/mnci-ramses-2.4.21-rmk2-pxa1/mnci-combined.patch b/recipes/linux/mnci-ramses-2.4.21-rmk2-pxa1/mnci-combined.patch
deleted file mode 100644
index efeba8c284..0000000000
--- a/recipes/linux/mnci-ramses-2.4.21-rmk2-pxa1/mnci-combined.patch
+++ /dev/null
@@ -1,108070 +0,0 @@
-
-# This is a cumulative patch consisting of:
-#
-# mtd-cvs.patch
-# linux-vtcomparison.patch
-# linux-mkdep.patch
-# linux-iw241_we16-6.patch
-# arm-noshortloads.patch
-# pxa-pcmcia.patch
-# pxa-smc91x.patch
-# pxa-usb.patch
-# pxa-usbeth.patch
-# pxa-irda.patch
-# pxa-ac97.patch
-# pxa-timerint.patch
-# fb-buffered.patch
-# fb-turn180.patch
-# i2c-ds1337.patch
-# keyb-input.patch
-# keyb-module.patch
-# logo-noscrollregion.patch
-# net-dhcp-timeout.patch
-# pm.patch
-# swap-performance.patch
-# small-nocramdisk.patch
-# smc91x-ethtool.patch
-# ucb1x00.patch
-# vmalloc.patch
-# usb-sl811.patch
-# orinoco013e.patch
-# bluetooth.patch
-# ramses.patch
-# ramses-ac97.patch
-# ramses-keyb.patch
-# ramses-mtd.patch
-# ramses-orinoco-ignorecis.patch
-# ramses-pcmcia.patch
-# ramses-serial.patch
-# ramses-smc91x.patch
-# ramses-sysctl.patch
-# ramses-ucb1x00-dejitter.patch
-# ramses-lcd.patch
-# ramses-usb.patch
-# ramses-corevolt.patch
-# wedge.patch
-# usb-sonycamera.patch
-# ramses-ucb1x00-rotate.patch
-# vt-noblank.patch
-#
-# Patch managed by http://www.holgerschurig.de/patcher.html
-#
-
---- linux-2.4.21/CREDITS~bluetooth
-+++ linux-2.4.21/CREDITS
-@@ -1348,7 +1348,11 @@
- N: Marcel Holtmann
- E: marcel@holtmann.org
- W: http://www.holtmann.org
--D: Author of the Linux Bluetooth Subsystem PC Card drivers
-+D: Maintainer of the Linux Bluetooth Subsystem
-+D: Author and maintainer of the various Bluetooth HCI drivers
-+D: Author and maintainer of the CAPI message transport protocol driver
-+D: Author and maintainer of the Bluetooth HID protocol driver
-+D: Various other Bluetooth related patches, cleanups and fixes
- S: Germany
-
- N: Rob W. W. Hooft
-@@ -2624,6 +2628,7 @@
- N: Aristeu Sergio Rozanski Filho
- E: aris@conectiva.com.br
- D: Support for EtherExpress 10 ISA (i82595) in eepro driver
-+D: User level driver support for input
- S: Conectiva S.A.
- S: R. Tocantins, 89 - Cristo Rei
- S: 80050-430 - Curitiba - Paraná
---- linux-2.4.21/Documentation/Configure.help~bluetooth
-+++ linux-2.4.21/Documentation/Configure.help
-@@ -14071,6 +14071,15 @@
- accessible under char device 13:64+ - /dev/input/eventX in a generic
- way. This is the future ...
-
-+CONFIG_INPUT_UINPUT
-+ Say Y here if you want to support user level drivers for input
-+ subsystem accessible under char device 10:223 - /dev/input/uinput.
-+
-+ This driver is also available as a module ( = code which can be
-+ inserted in and removed from the running kernel whenever you want).
-+ The module will be called uinput.o. If you want to compile it as a
-+ module, say M here and read <file:Documentation/modules.txt>.
-+
- USB Scanner support
- CONFIG_USB_SCANNER
- Say Y here if you want to connect a USB scanner to your computer's
-@@ -21670,21 +21679,21 @@
-
- Linux Bluetooth subsystem consist of several layers:
- BlueZ Core (HCI device and connection manager, scheduler)
-- HCI Device drivers (interface to the hardware)
-- L2CAP Module (L2CAP protocol)
-- SCO Module (SCO links)
-- RFCOMM Module (RFCOMM protocol)
-- BNEP Module (BNEP protocol)
-+ HCI Device drivers (Interface to the hardware)
-+ SCO Module (SCO audio links)
-+ L2CAP Module (Logical Link Control and Adaptation Protocol)
-+ RFCOMM Module (RFCOMM Protocol)
-+ BNEP Module (Bluetooth Network Encapsulation Protocol)
-+ CMTP Module (CAPI Message Transport Protocol)
-+ HIDP Module (Human Interface Device Protocol)
-
-- Say Y here to enable Linux Bluetooth support and to build BlueZ Core
-- layer.
-+ Say Y here to compile Bluetooth support into the kernel or say M to
-+ compile it as module (bluez.o).
-
- To use Linux Bluetooth subsystem, you will need several user-space
- utilities like hciconfig and hcid. These utilities and updates to
- Bluetooth kernel modules are provided in the BlueZ package.
-- For more information, see <http://bluez.sourceforge.net/>.
--
-- If you want to compile BlueZ Core as module (bluez.o) say M here.
-+ For more information, see <http://www.bluez.org/>.
-
- L2CAP protocol support
- CONFIG_BLUEZ_L2CAP
-@@ -21697,7 +21706,7 @@
-
- SCO links support
- CONFIG_BLUEZ_SCO
-- SCO link provides voice transport over Bluetooth. SCO support is
-+ SCO link provides voice transport over Bluetooth. SCO support is
- required for voice applications like Headset and Audio.
-
- Say Y here to compile SCO support into the kernel or say M to
-@@ -21705,7 +21714,7 @@
-
- RFCOMM protocol support
- CONFIG_BLUEZ_RFCOMM
-- RFCOMM provides connection oriented stream transport. RFCOMM
-+ RFCOMM provides connection oriented stream transport. RFCOMM
- support is required for Dialup Networking, OBEX and other Bluetooth
- applications.
-
-@@ -21719,12 +21728,8 @@
- BNEP protocol support
- CONFIG_BLUEZ_BNEP
- BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
-- emulation layer on top of Bluetooth. BNEP is required for Bluetooth
-- PAN (Personal Area Network).
--
-- To use BNEP, you will need user-space utilities provided in the
-- BlueZ-PAN package.
-- For more information, see <http://bluez.sourceforge.net>.
-+ emulation layer on top of Bluetooth. BNEP is required for
-+ Bluetooth PAN (Personal Area Network).
-
- Say Y here to compile BNEP support into the kernel or say M to
- compile it as module (bnep.o).
-@@ -21737,6 +21742,24 @@
- CONFIG_BLUEZ_BNEP_PROTO_FILTER
- This option enables the protocol filter support for BNEP.
-
-+CMTP protocol support
-+CONFIG_BLUEZ_CMTP
-+ CMTP (CAPI Message Transport Protocol) is a transport layer
-+ for CAPI messages. CMTP is required for the Bluetooth Common
-+ ISDN Access Profile.
-+
-+ Say Y here to compile CMTP support into the kernel or say M to
-+ compile it as module (cmtp.o).
-+
-+HIDP protocol support
-+CONFIG_BLUEZ_HIDP
-+ HIDP (Human Interface Device Protocol) is a transport layer
-+ for HID reports. HIDP is required for the Bluetooth Human
-+ Interface Device Profile.
-+
-+ Say Y here to compile HIDP support into the kernel or say M to
-+ compile it as module (hidp.o).
-+
- HCI UART driver
- CONFIG_BLUEZ_HCIUART
- Bluetooth HCI UART driver.
-@@ -21781,7 +21804,7 @@
- kernel or say M to compile it as module (hci_usb.o).
-
- HCI USB SCO (voice) support
--CONFIG_BLUEZ_USB_SCO
-+CONFIG_BLUEZ_HCIUSB_SCO
- This option enables the SCO support in the HCI USB driver. You need this
- to transmit voice data with your Bluetooth USB device. And your device
- must also support sending SCO data over the HCI layer, because some of
-@@ -21789,14 +21812,6 @@
-
- Say Y here to compile support for HCI SCO data.
-
--HCI USB zero packet support
--CONFIG_BLUEZ_USB_ZERO_PACKET
-- This option is provided only as a work around for buggy Bluetooth USB
-- devices. Do NOT enable it unless you know for sure that your device
-- requires zero packets.
--
-- Most people should say N here.
--
- HCI VHCI Virtual HCI device driver
- CONFIG_BLUEZ_HCIVHCI
- Bluetooth Virtual HCI device driver.
-@@ -21805,6 +21820,16 @@
- Say Y here to compile support for virtual HCI devices into the
- kernel or say M to compile it as module (hci_vhci.o).
-
-+HCI BFUSB device driver
-+CONFIG_BLUEZ_HCIBFUSB
-+ Bluetooth HCI BlueFRITZ! USB driver.
-+ This driver provides support for Bluetooth USB devices with AVM
-+ interface:
-+ AVM BlueFRITZ! USB
-+
-+ Say Y here to compile support for HCI BFUSB devices into the
-+ kernel or say M to compile it as module (bfusb.o).
-+
- HCI DTL1 (PC Card) device driver
- CONFIG_BLUEZ_HCIDTL1
- Bluetooth HCI DTL1 (PC Card) driver.
-@@ -21824,9 +21849,6 @@
- 3Com Bluetooth Card (3CRWB6096)
- HP Bluetooth Card
-
-- The HCI BT3C driver uses external firmware loader program provided in
-- the BlueFW package. For more information, see <http://bluez.sf.net>.
--
- Say Y here to compile support for HCI BT3C devices into the
- kernel or say M to compile it as module (bt3c_cs.o).
-
-@@ -26815,6 +26837,12 @@
-
- If unsure, say N.
-
-+Hotplug firmware loading support (EXPERIMENTAL)
-+CONFIG_FW_LOADER
-+ This option is provided for the case where no in-kernel-tree modules require
-+ hotplug firmware loading support, but a module built outside the kernel tree
-+ does.
-+
- NatSemi SCx200 support
- CONFIG_SCx200
- This provides basic support for the National Semiconductor SCx200
---- /dev/null
-+++ linux-2.4.21/Documentation/DocBook/librs.tmpl
-@@ -0,0 +1,287 @@
-+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
-+
-+<book id="Reed-Solomon-Library-Guide">
-+ <bookinfo>
-+ <title>Reed-Solomon Library Programming Interface</title>
-+
-+ <authorgroup>
-+ <author>
-+ <firstname>Thomas</firstname>
-+ <surname>Gleixner</surname>
-+ <affiliation>
-+ <address>
-+ <email>tglx@linutronix.de</email>
-+ </address>
-+ </affiliation>
-+ </author>
-+ </authorgroup>
-+
-+ <copyright>
-+ <year>2004</year>
-+ <holder>Thomas Gleixner</holder>
-+ </copyright>
-+
-+ <legalnotice>
-+ <para>
-+ This documentation 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.
-+ </para>
-+
-+ <para>
-+ This program is distributed in the hope that it will be
-+ useful, but WITHOUT ANY WARRANTY; without even the implied
-+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-+ See the GNU General Public License for more details.
-+ </para>
-+
-+ <para>
-+ You 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
-+ </para>
-+
-+ <para>
-+ For more details see the file COPYING in the source
-+ distribution of Linux.
-+ </para>
-+ </legalnotice>
-+ </bookinfo>
-+
-+<toc></toc>
-+
-+ <chapter id="intro">
-+ <title>Introduction</title>
-+ <para>
-+ The generic Reed-Solomon Library provides encoding, decoding
-+ and error correction functions.
-+ </para>
-+ <para>
-+ Reed-Solomon codes are used in communication and storage
-+ applications to ensure data integrity.
-+ </para>
-+ <para>
-+ This documentation is provided for developers who want to utilize
-+ the functions provided by the library.
-+ </para>
-+ </chapter>
-+
-+ <chapter id="bugs">
-+ <title>Known Bugs And Assumptions</title>
-+ <para>
-+ None.
-+ </para>
-+ </chapter>
-+
-+ <chapter id="usage">
-+ <title>Usage</title>
-+ <para>
-+ This chapter provides examples how to use the library.
-+ </para>
-+ <sect1>
-+ <title>Initializing</title>
-+ <para>
-+ The init function init_rs returns a pointer to a
-+ rs decoder structure, which holds the necessary
-+ information for encoding, decoding and error correction
-+ with the given polynomial. It either uses an existing
-+ matching decoder or creates a new one. On creation all
-+ the lookup tables for fast en/decoding are created.
-+ The function may take a while, so make sure not to
-+ call it in critical code paths.
-+ </para>
-+ <programlisting>
-+/* the Reed Solomon control structure */
-+static struct rs_control *rs_decoder;
-+
-+/* Symbolsize is 10 (bits)
-+ * Primitve polynomial is x^10+x^3+1
-+ * first consecutive root is 0
-+ * primitve element to generate roots = 1
-+ * generator polinomial degree (number of roots) = 6
-+ */
-+rs_decoder = init_rs (10, 0x409, 0, 1, 6);
-+ </programlisting>
-+ </sect1>
-+ <sect1>
-+ <title>Encoding</title>
-+ <para>
-+ The encoder calculates the Reed-Solomon code over
-+ the given data length and stores the result in
-+ the parity buffer. Note that the parity buffer must
-+ be initialized before calling the encoder.
-+ </para>
-+ <para>
-+ The expanded data can be inverted on the fly by
-+ providing a non zero inversion mask. The expanded data is
-+ XOR'ed with the mask. This is used e.g. for FLASH
-+ ECC, where the all 0xFF is inverted to an all 0x00.
-+ The Reed-Solomon code for all 0x00 is all 0x00. The
-+ code is inverted before storing to FLASH so it is 0xFF
-+ too. This prevent's that reading from an erased FLASH
-+ results in ECC errors.
-+ </para>
-+ <para>
-+ The databytes are expanded to the given symbol size
-+ on the fly. There is no support for encoding continuous
-+ bitstreams with a symbol size != 8 at the moment. If
-+ it is necessary it should be not a big deal to implement
-+ such functionality.
-+ </para>
-+ <programlisting>
-+/* Parity buffer. Size = number of roots */
-+uint16_t par[6];
-+/* Initialize the parity buffer */
-+memset(par, 0, sizeof(par));
-+/* Encode 512 byte in data8. Store parity in buffer par */
-+encode_rs8 (rs_decoder, data8, 512, par, 0);
-+ </programlisting>
-+ </sect1>
-+ <sect1>
-+ <title>Decoding</title>
-+ <para>
-+ The decoder calculates the syndrome over
-+ the given data length and the received parity symbols
-+ and corrects errors in the data.
-+ </para>
-+ <para>
-+ If a syndrome is available from a hardware decoder
-+ then the syndrome calculation is skipped.
-+ </para>
-+ <para>
-+ The correction of the data buffer can be suppressed
-+ by providing a correction pattern buffer and an error
-+ location buffer to the decoder. The decoder stores the
-+ calculated error location and the correction bitmask
-+ in the given buffers. This is useful for hardware
-+ decoders which use a weird bit ordering scheme.
-+ </para>
-+ <para>
-+ The databytes are expanded to the given symbol size
-+ on the fly. There is no support for decoding continuous
-+ bitstreams with a symbolsize != 8 at the moment. If
-+ it is necessary it should be not a big deal to implement
-+ such functionality.
-+ </para>
-+
-+ <sect2>
-+ <title>
-+ Decoding with syndrome calculation, direct data correction
-+ </title>
-+ <programlisting>
-+/* Parity buffer. Size = number of roots */
-+uint16_t par[6];
-+uint8_t data[512];
-+int numerr;
-+/* Receive data */
-+.....
-+/* Receive parity */
-+.....
-+/* Decode 512 byte in data8.*/
-+numerr = decode_rs8 (rs_decoder, data8, par, 512, NULL, 0, NULL, 0, NULL);
-+ </programlisting>
-+ </sect2>
-+
-+ <sect2>
-+ <title>
-+ Decoding with syndrome given by hardware decoder, direct data correction
-+ </title>
-+ <programlisting>
-+/* Parity buffer. Size = number of roots */
-+uint16_t par[6], syn[6];
-+uint8_t data[512];
-+int numerr;
-+/* Receive data */
-+.....
-+/* Receive parity */
-+.....
-+/* Get syndrome from hardware decoder */
-+.....
-+/* Decode 512 byte in data8.*/
-+numerr = decode_rs8 (rs_decoder, data8, par, 512, syn, 0, NULL, 0, NULL);
-+ </programlisting>
-+ </sect2>
-+
-+ <sect2>
-+ <title>
-+ Decoding with syndrome given by hardware decoder, no direct data correction.
-+ </title>
-+ <para>
-+ Note: It's not necessary to give data and received parity to the decoder.
-+ </para>
-+ <programlisting>
-+/* Parity buffer. Size = number of roots */
-+uint16_t par[6], syn[6], corr[8];
-+uint8_t data[512];
-+int numerr, errpos[8];
-+/* Receive data */
-+.....
-+/* Receive parity */
-+.....
-+/* Get syndrome from hardware decoder */
-+.....
-+/* Decode 512 byte in data8.*/
-+numerr = decode_rs8 (rs_decoder, NULL, NULL, 512, syn, 0, errpos, 0, corr);
-+for (i = 0; i < numerr; i++) {
-+ do_error_correction_in_your_buffer(errpos[i], corr[i]);
-+}
-+ </programlisting>
-+ </sect2>
-+ </sect1>
-+ <sect1>
-+ <title>Cleanup</title>
-+ <para>
-+ The function free_rs frees the allocated resources,
-+ if the caller is the last user of the decoder.
-+ </para>
-+ <programlisting>
-+/* Release resources */
-+free_rs(rs_decoder);
-+ </programlisting>
-+ </sect1>
-+
-+ </chapter>
-+
-+ <chapter id="structs">
-+ <title>Structures</title>
-+ <para>
-+ This chapter contains the autogenerated documentation of the structures which are
-+ used in the Reed-Solomon Library and are relevant for a developer.
-+ </para>
-+!Iinclude/linux/rslib.h
-+ </chapter>
-+
-+ <chapter id="pubfunctions">
-+ <title>Public Functions Provided</title>
-+ <para>
-+ This chapter contains the autogenerated documentation of the Reed-Solomon functions
-+ which are exported.
-+ </para>
-+!Elib/reed_solomon/reed_solomon.c
-+ </chapter>
-+
-+ <chapter id="credits">
-+ <title>Credits</title>
-+ <para>
-+ The library code for encoding and decoding was written by Phil Karn.
-+ </para>
-+ <programlisting>
-+ Copyright 2002, Phil Karn, KA9Q
-+ May be used under the terms of the GNU General Public License (GPL)
-+ </programlisting>
-+ <para>
-+ The wrapper functions and interfaces are written by Thomas Gleixner
-+ </para>
-+ <para>
-+ Many users have provided bugfixes, improvements and helping hands for testing.
-+ Thanks a lot.
-+ </para>
-+ <para>
-+ The following people have contributed to this document:
-+ </para>
-+ <para>
-+ Thomas Gleixner<email>tglx@linutronix.de</email>
-+ </para>
-+ </chapter>
-+</book>
---- /dev/null
-+++ linux-2.4.21/Documentation/DocBook/mtdnand.tmpl
-@@ -0,0 +1,1318 @@
-+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
-+
-+<book id="MTD-NAND-Guide">
-+ <bookinfo>
-+ <title>MTD NAND Driver Programming Interface</title>
-+
-+ <authorgroup>
-+ <author>
-+ <firstname>Thomas</firstname>
-+ <surname>Gleixner</surname>
-+ <affiliation>
-+ <address>
-+ <email>tglx@linutronix.de</email>
-+ </address>
-+ </affiliation>
-+ </author>
-+ </authorgroup>
-+
-+ <copyright>
-+ <year>2004</year>
-+ <holder>Thomas Gleixner</holder>
-+ </copyright>
-+
-+ <legalnotice>
-+ <para>
-+ This documentation 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.
-+ </para>
-+
-+ <para>
-+ This program is distributed in the hope that it will be
-+ useful, but WITHOUT ANY WARRANTY; without even the implied
-+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-+ See the GNU General Public License for more details.
-+ </para>
-+
-+ <para>
-+ You 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
-+ </para>
-+
-+ <para>
-+ For more details see the file COPYING in the source
-+ distribution of Linux.
-+ </para>
-+ </legalnotice>
-+ </bookinfo>
-+
-+<toc></toc>
-+
-+ <chapter id="intro">
-+ <title>Introduction</title>
-+ <para>
-+ The generic NAND driver supports almost all NAND and AG-AND based
-+ chips and connects them to the Memory Technology Devices (MTD)
-+ subsystem of the Linux Kernel.
-+ </para>
-+ <para>
-+ This documentation is provided for developers who want to implement
-+ board drivers or filesystem drivers suitable for NAND devices.
-+ </para>
-+ </chapter>
-+
-+ <chapter id="bugs">
-+ <title>Known Bugs And Assumptions</title>
-+ <para>
-+ None.
-+ </para>
-+ </chapter>
-+
-+ <chapter id="dochints">
-+ <title>Documentation hints</title>
-+ <para>
-+ The function and structure docs are autogenerated. Each function and
-+ struct member has a short description which is marked with an [XXX] identifier.
-+ The following chapters explain the meaning of those identifiers.
-+ </para>
-+ <sect1>
-+ <title>Function identifiers [XXX]</title>
-+ <para>
-+ The functions are marked with [XXX] identifiers in the short
-+ comment. The identifiers explain the usage and scope of the
-+ functions. Following identifiers are used:
-+ </para>
-+ <itemizedlist>
-+ <listitem><para>
-+ [MTD Interface]</para><para>
-+ These functions provide the interface to the MTD kernel API.
-+ They are not replacable and provide functionality
-+ which is complete hardware independent.
-+ </para></listitem>
-+ <listitem><para>
-+ [NAND Interface]</para><para>
-+ These functions are exported and provide the interface to the NAND kernel API.
-+ </para></listitem>
-+ <listitem><para>
-+ [GENERIC]</para><para>
-+ Generic functions are not replacable and provide functionality
-+ which is complete hardware independent.
-+ </para></listitem>
-+ <listitem><para>
-+ [DEFAULT]</para><para>
-+ Default functions provide hardware related functionality which is suitable
-+ for most of the implementations. These functions can be replaced by the
-+ board driver if neccecary. Those functions are called via pointers in the
-+ NAND chip description structure. The board driver can set the functions which
-+ should be replaced by board dependend functions before calling nand_scan().
-+ If the function pointer is NULL on entry to nand_scan() then the pointer
-+ is set to the default function which is suitable for the detected chip type.
-+ </para></listitem>
-+ </itemizedlist>
-+ </sect1>
-+ <sect1>
-+ <title>Struct member identifiers [XXX]</title>
-+ <para>
-+ The struct members are marked with [XXX] identifiers in the
-+ comment. The identifiers explain the usage and scope of the
-+ members. Following identifiers are used:
-+ </para>
-+ <itemizedlist>
-+ <listitem><para>
-+ [INTERN]</para><para>
-+ These members are for NAND driver internal use only and must not be
-+ modified. Most of these values are calculated from the chip geometry
-+ information which is evaluated during nand_scan().
-+ </para></listitem>
-+ <listitem><para>
-+ [REPLACEABLE]</para><para>
-+ Replaceable members hold hardware related functions which can be
-+ provided by the board driver. The board driver can set the functions which
-+ should be replaced by board dependend functions before calling nand_scan().
-+ If the function pointer is NULL on entry to nand_scan() then the pointer
-+ is set to the default function which is suitable for the detected chip type.
-+ </para></listitem>
-+ <listitem><para>
-+ [BOARDSPECIFIC]</para><para>
-+ Board specific members hold hardware related information which must
-+ be provided by the board driver. The board driver must set the function
-+ pointers and datafields before calling nand_scan().
-+ </para></listitem>
-+ <listitem><para>
-+ [OPTIONAL]</para><para>
-+ Optional members can hold information relevant for the board driver. The
-+ generic NAND driver code does not use this information.
-+ </para></listitem>
-+ </itemizedlist>
-+ </sect1>
-+ </chapter>
-+
-+ <chapter id="basicboarddriver">
-+ <title>Basic board driver</title>
-+ <para>
-+ For most boards it will be sufficient to provide just the
-+ basic functions and fill out some really board dependend
-+ members in the nand chip description structure.
-+ See drivers/mtd/nand/skeleton for reference.
-+ </para>
-+ <sect1>
-+ <title>Basic defines</title>
-+ <para>
-+ At least you have to provide a mtd structure and
-+ a storage for the ioremap'ed chip address.
-+ You can allocate the mtd structure using kmalloc
-+ or you can allocate it statically.
-+ In case of static allocation you have to allocate
-+ a nand_chip structure too.
-+ </para>
-+ <para>
-+ Kmalloc based example
-+ </para>
-+ <programlisting>
-+static struct mtd_info *board_mtd;
-+static unsigned long baseaddr;
-+ </programlisting>
-+ <para>
-+ Static example
-+ </para>
-+ <programlisting>
-+static struct mtd_info board_mtd;
-+static struct nand_chip board_chip;
-+static unsigned long baseaddr;
-+ </programlisting>
-+ </sect1>
-+ <sect1>
-+ <title>Partition defines</title>
-+ <para>
-+ If you want to divide your device into parititions, then
-+ enable the configuration switch CONFIG_MTD_PARITIONS and define
-+ a paritioning scheme suitable to your board.
-+ </para>
-+ <programlisting>
-+#define NUM_PARTITIONS 2
-+static struct mtd_partition partition_info[] = {
-+ { .name = "Flash partition 1",
-+ .offset = 0,
-+ .size = 8 * 1024 * 1024 },
-+ { .name = "Flash partition 2",
-+ .offset = MTDPART_OFS_NEXT,
-+ .size = MTDPART_SIZ_FULL },
-+};
-+ </programlisting>
-+ </sect1>
-+ <sect1>
-+ <title>Hardware control function</title>
-+ <para>
-+ The hardware control function provides access to the
-+ control pins of the NAND chip(s).
-+ The access can be done by GPIO pins or by address lines.
-+ If you use address lines, make sure that the timing
-+ requirements are met.
-+ </para>
-+ <para>
-+ <emphasis>GPIO based example</emphasis>
-+ </para>
-+ <programlisting>
-+static void board_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+ switch(cmd){
-+ case NAND_CTL_SETCLE: /* Set CLE pin high */ break;
-+ case NAND_CTL_CLRCLE: /* Set CLE pin low */ break;
-+ case NAND_CTL_SETALE: /* Set ALE pin high */ break;
-+ case NAND_CTL_CLRALE: /* Set ALE pin low */ break;
-+ case NAND_CTL_SETNCE: /* Set nCE pin low */ break;
-+ case NAND_CTL_CLRNCE: /* Set nCE pin high */ break;
-+ }
-+}
-+ </programlisting>
-+ <para>
-+ <emphasis>Address lines based example.</emphasis> It's assumed that the
-+ nCE pin is driven by a chip select decoder.
-+ </para>
-+ <programlisting>
-+static void board_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+ struct nand_chip *this = (struct nand_chip *) mtd->priv;
-+ switch(cmd){
-+ case NAND_CTL_SETCLE: this->IO_ADDR_W |= CLE_ADRR_BIT; break;
-+ case NAND_CTL_CLRCLE: this->IO_ADDR_W &= ~CLE_ADRR_BIT; break;
-+ case NAND_CTL_SETALE: this->IO_ADDR_W |= ALE_ADRR_BIT; break;
-+ case NAND_CTL_CLRALE: this->IO_ADDR_W &= ~ALE_ADRR_BIT; break;
-+ }
-+}
-+ </programlisting>
-+ </sect1>
-+ <sect1>
-+ <title>Device ready function</title>
-+ <para>
-+ If the hardware interface has the ready busy pin of the NAND chip connected to a
-+ GPIO or other accesible I/O pin, this function is used to read back the state of the
-+ pin. The function has no arguments and should return 0, if the device is busy (R/B pin
-+ is low) and 1, if the device is ready (R/B pin is high).
-+ If the hardware interface does not give access to the ready busy pin, then
-+ the function must not be defined and the function pointer this->dev_ready is set to NULL.
-+ </para>
-+ </sect1>
-+ <sect1>
-+ <title>Init function</title>
-+ <para>
-+ The init function allocates memory and sets up all the board
-+ specific parameters and function pointers. When everything
-+ is set up nand_scan() is called. This function tries to
-+ detect and identify then chip. If a chip is found all the
-+ internal data fields are initialized accordingly.
-+ The structure(s) have to be zeroed out first and then filled with the neccecary
-+ information about the device.
-+ </para>
-+ <programlisting>
-+int __init board_init (void)
-+{
-+ struct nand_chip *this;
-+ int err = 0;
-+
-+ /* Allocate memory for MTD device structure and private data */
-+ board_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL);
-+ if (!board_mtd) {
-+ printk ("Unable to allocate NAND MTD device structure.\n");
-+ err = -ENOMEM;
-+ goto out;
-+ }
-+
-+ /* Initialize structures */
-+ memset ((char *) board_mtd, 0, sizeof(struct mtd_info) + sizeof(struct nand_chip));
-+
-+ /* map physical adress */
-+ baseaddr = (unsigned long)ioremap(CHIP_PHYSICAL_ADDRESS, 1024);
-+ if(!baseaddr){
-+ printk("Ioremap to access NAND chip failed\n");
-+ err = -EIO;
-+ goto out_mtd;
-+ }
-+
-+ /* Get pointer to private data */
-+ this = (struct nand_chip *) ();
-+ /* Link the private data with the MTD structure */
-+ board_mtd->priv = this;
-+
-+ /* Set address of NAND IO lines */
-+ this->IO_ADDR_R = baseaddr;
-+ this->IO_ADDR_W = baseaddr;
-+ /* Reference hardware control function */
-+ this->hwcontrol = board_hwcontrol;
-+ /* Set command delay time, see datasheet for correct value */
-+ this->chip_delay = CHIP_DEPENDEND_COMMAND_DELAY;
-+ /* Assign the device ready function, if available */
-+ this->dev_ready = board_dev_ready;
-+ this->eccmode = NAND_ECC_SOFT;
-+
-+ /* Scan to find existance of the device */
-+ if (nand_scan (board_mtd, 1)) {
-+ err = -ENXIO;
-+ goto out_ior;
-+ }
-+
-+ add_mtd_partitions(board_mtd, partition_info, NUM_PARTITIONS);
-+ goto out;
-+
-+out_ior:
-+ iounmap((void *)baseaddr);
-+out_mtd:
-+ kfree (board_mtd);
-+out:
-+ return err;
-+}
-+module_init(board_init);
-+ </programlisting>
-+ </sect1>
-+ <sect1>
-+ <title>Exit function</title>
-+ <para>
-+ The exit function is only neccecary if the driver is
-+ compiled as a module. It releases all resources which
-+ are held by the chip driver and unregisters the partitions
-+ in the MTD layer.
-+ </para>
-+ <programlisting>
-+#ifdef MODULE
-+static void __exit board_cleanup (void)
-+{
-+ /* Release resources, unregister device */
-+ nand_release (board_mtd);
-+
-+ /* unmap physical adress */
-+ iounmap((void *)baseaddr);
-+
-+ /* Free the MTD device structure */
-+ kfree (board_mtd);
-+}
-+module_exit(board_cleanup);
-+#endif
-+ </programlisting>
-+ </sect1>
-+ </chapter>
-+
-+ <chapter id="boarddriversadvanced">
-+ <title>Advanced board driver functions</title>
-+ <para>
-+ This chapter describes the advanced functionality of the NAND
-+ driver. For a list of functions which can be overridden by the board
-+ driver see the documentation of the nand_chip structure.
-+ </para>
-+ <sect1>
-+ <title>Multiple chip control</title>
-+ <para>
-+ The nand driver can control chip arrays. Therefor the
-+ board driver must provide an own select_chip function. This
-+ function must (de)select the requested chip.
-+ The function pointer in the nand_chip structure must
-+ be set before calling nand_scan(). The maxchip parameter
-+ of nand_scan() defines the maximum number of chips to
-+ scan for. Make sure that the select_chip function can
-+ handle the requested number of chips.
-+ </para>
-+ <para>
-+ The nand driver concatenates the chips to one virtual
-+ chip and provides this virtual chip to the MTD layer.
-+ </para>
-+ <para>
-+ <emphasis>Note: The driver can only handle linear chip arrays
-+ of equally sized chips. There is no support for
-+ parallel arrays which extend the buswidth.</emphasis>
-+ </para>
-+ <para>
-+ <emphasis>GPIO based example</emphasis>
-+ </para>
-+ <programlisting>
-+static void board_select_chip (struct mtd_info *mtd, int chip)
-+{
-+ /* Deselect all chips, set all nCE pins high */
-+ GPIO(BOARD_NAND_NCE) |= 0xff;
-+ if (chip >= 0)
-+ GPIO(BOARD_NAND_NCE) &= ~ (1 << chip);
-+}
-+ </programlisting>
-+ <para>
-+ <emphasis>Address lines based example.</emphasis>
-+ Its assumed that the nCE pins are connected to an
-+ address decoder.
-+ </para>
-+ <programlisting>
-+static void board_select_chip (struct mtd_info *mtd, int chip)
-+{
-+ struct nand_chip *this = (struct nand_chip *) mtd->priv;
-+
-+ /* Deselect all chips */
-+ this->IO_ADDR_R &= ~BOARD_NAND_ADDR_MASK;
-+ this->IO_ADDR_W &= ~BOARD_NAND_ADDR_MASK;
-+ switch (chip) {
-+ case 0:
-+ this->IO_ADDR_R |= BOARD_NAND_ADDR_CHIP0;
-+ this->IO_ADDR_W |= BOARD_NAND_ADDR_CHIP0;
-+ break;
-+ ....
-+ case n:
-+ this->IO_ADDR_R |= BOARD_NAND_ADDR_CHIPn;
-+ this->IO_ADDR_W |= BOARD_NAND_ADDR_CHIPn;
-+ break;
-+ }
-+}
-+ </programlisting>
-+ </sect1>
-+ <sect1>
-+ <title>Hardware ECC support</title>
-+ <sect2>
-+ <title>Functions and constants</title>
-+ <para>
-+ The nand driver supports three different types of
-+ hardware ECC.
-+ <itemizedlist>
-+ <listitem><para>NAND_ECC_HW3_256</para><para>
-+ Hardware ECC generator providing 3 bytes ECC per
-+ 256 byte.
-+ </para> </listitem>
-+ <listitem><para>NAND_ECC_HW3_512</para><para>
-+ Hardware ECC generator providing 3 bytes ECC per
-+ 512 byte.
-+ </para> </listitem>
-+ <listitem><para>NAND_ECC_HW6_512</para><para>
-+ Hardware ECC generator providing 6 bytes ECC per
-+ 512 byte.
-+ </para> </listitem>
-+ <listitem><para>NAND_ECC_HW8_512</para><para>
-+ Hardware ECC generator providing 6 bytes ECC per
-+ 512 byte.
-+ </para> </listitem>
-+ </itemizedlist>
-+ If your hardware generator has a different functionality
-+ add it at the appropriate place in nand_base.c
-+ </para>
-+ <para>
-+ The board driver must provide following functions:
-+ <itemizedlist>
-+ <listitem><para>enable_hwecc</para><para>
-+ This function is called before reading / writing to
-+ the chip. Reset or initialize the hardware generator
-+ in this function. The function is called with an
-+ argument which let you distinguish between read
-+ and write operations.
-+ </para> </listitem>
-+ <listitem><para>calculate_ecc</para><para>
-+ This function is called after read / write from / to
-+ the chip. Transfer the ECC from the hardware to
-+ the buffer. If the option NAND_HWECC_SYNDROME is set
-+ then the function is only called on write. See below.
-+ </para> </listitem>
-+ <listitem><para>correct_data</para><para>
-+ In case of an ECC error this function is called for
-+ error detection and correction. Return 1 respectively 2
-+ in case the error can be corrected. If the error is
-+ not correctable return -1. If your hardware generator
-+ matches the default algorithm of the nand_ecc software
-+ generator then use the correction function provided
-+ by nand_ecc instead of implementing duplicated code.
-+ </para> </listitem>
-+ </itemizedlist>
-+ </para>
-+ </sect2>
-+ <sect2>
-+ <title>Hardware ECC with syndrome calculation</title>
-+ <para>
-+ Many hardware ECC implementations provide Reed-Solomon
-+ codes and calculate an error syndrome on read. The syndrome
-+ must be converted to a standard Reed-Solomon syndrome
-+ before calling the error correction code in the generic
-+ Reed-Solomon library.
-+ </para>
-+ <para>
-+ The ECC bytes must be placed immidiately after the data
-+ bytes in order to make the syndrome generator work. This
-+ is contrary to the usual layout used by software ECC. The
-+ seperation of data and out of band area is not longer
-+ possible. The nand driver code handles this layout and
-+ the remaining free bytes in the oob area are managed by
-+ the autoplacement code. Provide a matching oob-layout
-+ in this case. See rts_from4.c and diskonchip.c for
-+ implementation reference. In those cases we must also
-+ use bad block tables on FLASH, because the ECC layout is
-+ interferring with the bad block marker positions.
-+ See bad block table support for details.
-+ </para>
-+ </sect2>
-+ </sect1>
-+ <sect1>
-+ <title>Bad block table support</title>
-+ <para>
-+ Most NAND chips mark the bad blocks at a defined
-+ position in the spare area. Those blocks must
-+ not be erased under any circumstances as the bad
-+ block information would be lost.
-+ It is possible to check the bad block mark each
-+ time when the blocks are accessed by reading the
-+ spare area of the first page in the block. This
-+ is time consuming so a bad block table is used.
-+ </para>
-+ <para>
-+ The nand driver supports various types of bad block
-+ tables.
-+ <itemizedlist>
-+ <listitem><para>Per device</para><para>
-+ The bad block table contains all bad block information
-+ of the device which can consist of multiple chips.
-+ </para> </listitem>
-+ <listitem><para>Per chip</para><para>
-+ A bad block table is used per chip and contains the
-+ bad block information for this particular chip.
-+ </para> </listitem>
-+ <listitem><para>Fixed offset</para><para>
-+ The bad block table is located at a fixed offset
-+ in the chip (device). This applies to various
-+ DiskOnChip devices.
-+ </para> </listitem>
-+ <listitem><para>Automatic placed</para><para>
-+ The bad block table is automatically placed and
-+ detected either at the end or at the beginning
-+ of a chip (device)
-+ </para> </listitem>
-+ <listitem><para>Mirrored tables</para><para>
-+ The bad block table is mirrored on the chip (device) to
-+ allow updates of the bad block table without data loss.
-+ </para> </listitem>
-+ </itemizedlist>
-+ </para>
-+ <para>
-+ nand_scan() calls the function nand_default_bbt().
-+ nand_default_bbt() selects appropriate default
-+ bad block table desriptors depending on the chip information
-+ which was retrieved by nand_scan().
-+ </para>
-+ <para>
-+ The standard policy is scanning the device for bad
-+ blocks and build a ram based bad block table which
-+ allows faster access than always checking the
-+ bad block information on the flash chip itself.
-+ </para>
-+ <sect2>
-+ <title>Flash based tables</title>
-+ <para>
-+ It may be desired or neccecary to keep a bad block table in FLASH.
-+ For AG-AND chips this is mandatory, as they have no factory marked
-+ bad blocks. They have factory marked good blocks. The marker pattern
-+ is erased when the block is erased to be reused. So in case of
-+ powerloss before writing the pattern back to the chip this block
-+ would be lost and added to the bad blocks. Therefor we scan the
-+ chip(s) when we detect them the first time for good blocks and
-+ store this information in a bad block table before erasing any
-+ of the blocks.
-+ </para>
-+ <para>
-+ The blocks in which the tables are stored are procteted against
-+ accidental access by marking them bad in the memory bad block
-+ table. The bad block table managment functions are allowed
-+ to circumvernt this protection.
-+ </para>
-+ <para>
-+ The simplest way to activate the FLASH based bad block table support
-+ is to set the option NAND_USE_FLASH_BBT in the option field of
-+ the nand chip structure before calling nand_scan(). For AG-AND
-+ chips is this done by default.
-+ This activates the default FLASH based bad block table functionality
-+ of the NAND driver. The default bad block table options are
-+ <itemizedlist>
-+ <listitem><para>Store bad block table per chip</para></listitem>
-+ <listitem><para>Use 2 bits per block</para></listitem>
-+ <listitem><para>Automatic placement at the end of the chip</para></listitem>
-+ <listitem><para>Use mirrored tables with version numbers</para></listitem>
-+ <listitem><para>Reserve 4 blocks at the end of the chip</para></listitem>
-+ </itemizedlist>
-+ </para>
-+ </sect2>
-+ <sect2>
-+ <title>User defined tables</title>
-+ <para>
-+ User defined tables are created by filling out a
-+ nand_bbt_descr structure and storing the pointer in the
-+ nand_chip structure member bbt_td before calling nand_scan().
-+ If a mirror table is neccecary a second structure must be
-+ created and a pointer to this structure must be stored
-+ in bbt_md inside the nand_chip structure. If the bbt_md
-+ member is set to NULL then only the main table is used
-+ and no scan for the mirrored table is performed.
-+ </para>
-+ <para>
-+ The most important field in the nand_bbt_descr structure
-+ is the options field. The options define most of the
-+ table properties. Use the predefined constants from
-+ nand.h to define the options.
-+ <itemizedlist>
-+ <listitem><para>Number of bits per block</para>
-+ <para>The supported number of bits is 1, 2, 4, 8.</para></listitem>
-+ <listitem><para>Table per chip</para>
-+ <para>Setting the constant NAND_BBT_PERCHIP selects that
-+ a bad block table is managed for each chip in a chip array.
-+ If this option is not set then a per device bad block table
-+ is used.</para></listitem>
-+ <listitem><para>Table location is absolute</para>
-+ <para>Use the option constant NAND_BBT_ABSPAGE and
-+ define the absolute page number where the bad block
-+ table starts in the field pages. If you have selected bad block
-+ tables per chip and you have a multi chip array then the start page
-+ must be given for each chip in the chip array. Note: there is no scan
-+ for a table ident pattern performed, so the fields
-+ pattern, veroffs, offs, len can be left uninitialized</para></listitem>
-+ <listitem><para>Table location is automatically detected</para>
-+ <para>The table can either be located in the first or the last good
-+ blocks of the chip (device). Set NAND_BBT_LASTBLOCK to place
-+ the bad block table at the end of the chip (device). The
-+ bad block tables are marked and identified by a pattern which
-+ is stored in the spare area of the first page in the block which
-+ holds the bad block table. Store a pointer to the pattern
-+ in the pattern field. Further the length of the pattern has to be
-+ stored in len and the offset in the spare area must be given
-+ in the offs member of the nand_bbt_descr stucture. For mirrored
-+ bad block tables different patterns are mandatory.</para></listitem>
-+ <listitem><para>Table creation</para>
-+ <para>Set the option NAND_BBT_CREATE to enable the table creation
-+ if no table can be found during the scan. Usually this is done only
-+ once if a new chip is found. </para></listitem>
-+ <listitem><para>Table write support</para>
-+ <para>Set the option NAND_BBT_WRITE to enable the table write support.
-+ This allows the update of the bad block table(s) in case a block has
-+ to be marked bad due to wear. The MTD interface function block_markbad
-+ is calling the update function of the bad block table. If the write
-+ support is enabled then the table is updated on FLASH.</para>
-+ <para>
-+ Note: Write support should only be enabled for mirrored tables with
-+ version control.
-+ </para></listitem>
-+ <listitem><para>Table version control</para>
-+ <para>Set the option NAND_BBT_VERSION to enable the table version control.
-+ It's highly recommended to enable this for mirrored tables with write
-+ support. It makes sure that the risk of loosing the bad block
-+ table information is reduced to the loss of the information about the
-+ one worn out block which should be marked bad. The version is stored in
-+ 4 consecutive bytes in the spare area of the device. The position of
-+ the version number is defined by the member veroffs in the bad block table
-+ descriptor.</para></listitem>
-+ <listitem><para>Save block contents on write</para>
-+ <para>
-+ In case that the block which holds the bad block table does contain
-+ other useful information, set the option NAND_BBT_SAVECONTENT. When
-+ the bad block table is written then the whole block is read the bad
-+ block table is updated and the block is erased and everything is
-+ written back. If this option is not set only the bad block table
-+ is written and everything else in the block is ignored and erased.
-+ </para></listitem>
-+ <listitem><para>Number of reserved blocks</para>
-+ <para>
-+ For automatic placement some blocks must be reserved for
-+ bad block table storage. The number of reserved blocks is defined
-+ in the maxblocks member of the babd block table description structure.
-+ Reserving 4 blocks for mirrored tables should be a reasonable number.
-+ This also limits the number of blocks which are scanned for the bad
-+ block table ident pattern.
-+ </para></listitem>
-+ </itemizedlist>
-+ </para>
-+ </sect2>
-+ </sect1>
-+ <sect1>
-+ <title>Spare area (auto)placement</title>
-+ <para>
-+ The nand driver implements different possibilities for
-+ placement of filesystem data in the spare area,
-+ <itemizedlist>
-+ <listitem><para>Placement defined by fs driver</para></listitem>
-+ <listitem><para>Automatic placement</para></listitem>
-+ </itemizedlist>
-+ The default placement function is automatic placement. The
-+ nand driver has built in default placement schemes for the
-+ various chiptypes. If due to hardware ECC functionality the
-+ default placement does not fit then the board driver can
-+ provide a own placement scheme.
-+ </para>
-+ <para>
-+ File system drivers can provide a own placement scheme which
-+ is used instead of the default placement scheme.
-+ </para>
-+ <para>
-+ Placement schemes are defined by a nand_oobinfo structure
-+ <programlisting>
-+struct nand_oobinfo {
-+ int useecc;
-+ int eccbytes;
-+ int eccpos[24];
-+ int oobfree[8][2];
-+};
-+ </programlisting>
-+ <itemizedlist>
-+ <listitem><para>useecc</para><para>
-+ The useecc member controls the ecc and placement function. The header
-+ file include/mtd/mtd-abi.h contains constants to select ecc and
-+ placement. MTD_NANDECC_OFF switches off the ecc complete. This is
-+ not recommended and available for testing and diagnosis only.
-+ MTD_NANDECC_PLACE selects caller defined placement, MTD_NANDECC_AUTOPLACE
-+ selects automatic placement.
-+ </para></listitem>
-+ <listitem><para>eccbytes</para><para>
-+ The eccbytes member defines the number of ecc bytes per page.
-+ </para></listitem>
-+ <listitem><para>eccpos</para><para>
-+ The eccpos array holds the byte offsets in the spare area where
-+ the ecc codes are placed.
-+ </para></listitem>
-+ <listitem><para>oobfree</para><para>
-+ The oobfree array defines the areas in the spare area which can be
-+ used for automatic placement. The information is given in the format
-+ {offset, size}. offset defines the start of the usable area, size the
-+ length in bytes. More than one area can be defined. The list is terminated
-+ by an {0, 0} entry.
-+ </para></listitem>
-+ </itemizedlist>
-+ </para>
-+ <sect2>
-+ <title>Placement defined by fs driver</title>
-+ <para>
-+ The calling function provides a pointer to a nand_oobinfo
-+ structure which defines the ecc placement. For writes the
-+ caller must provide a spare area buffer along with the
-+ data buffer. The spare area buffer size is (number of pages) *
-+ (size of spare area). For reads the buffer size is
-+ (number of pages) * ((size of spare area) + (number of ecc
-+ steps per page) * sizeof (int)). The driver stores the
-+ result of the ecc check for each tuple in the spare buffer.
-+ The storage sequence is
-+ </para>
-+ <para>
-+ &lt;spare data page 0&gt;&lt;ecc result 0&gt;...&lt;ecc result n&gt;
-+ </para>
-+ <para>
-+ ...
-+ </para>
-+ <para>
-+ &lt;spare data page n&gt;&lt;ecc result 0&gt;...&lt;ecc result n&gt;
-+ </para>
-+ <para>
-+ This is a legacy mode used by YAFFS1.
-+ </para>
-+ <para>
-+ If the spare area buffer is NULL then only the ECC placement is
-+ done according to the given scheme in the nand_oobinfo structure.
-+ </para>
-+ </sect2>
-+ <sect2>
-+ <title>Automatic placement</title>
-+ <para>
-+ Automatic placement uses the built in defaults to place the
-+ ecc bytes in the spare area. If filesystem data have to be stored /
-+ read into the spare area then the calling function must provide a
-+ buffer. The buffer size per page is determined by the oobfree array in
-+ the nand_oobinfo structure.
-+ </para>
-+ <para>
-+ If the spare area buffer is NULL then only the ECC placement is
-+ done according to the default builtin scheme.
-+ </para>
-+ </sect2>
-+ <sect2>
-+ <title>User space placement selection</title>
-+ <para>
-+ All non ecc functions like mtd->read and mtd->write use an internal
-+ structure, which can be set by an ioctl. This structure is preset
-+ to the autoplacement default.
-+ <programlisting>
-+ ioctl (fd, MEMSETOOBSEL, oobsel);
-+ </programlisting>
-+ oobsel is a pointer to a user supplied structure of type
-+ nand_oobconfig. The contents of this structure must match the
-+ criteria of the filesystem, which will be used. See an example in utils/nandwrite.c.
-+ </para>
-+ </sect2>
-+ </sect1>
-+ <sect1>
-+ <title>Spare area autoplacement default schemes</title>
-+ <sect2>
-+ <title>256 byte pagesize</title>
-+<informaltable><tgroup cols="3"><tbody>
-+<row>
-+<entry>Offset</entry>
-+<entry>Content</entry>
-+<entry>Comment</entry>
-+</row>
-+<row>
-+<entry>0x00</entry>
-+<entry>ECC byte 0</entry>
-+<entry>Error correction code byte 0</entry>
-+</row>
-+<row>
-+<entry>0x01</entry>
-+<entry>ECC byte 1</entry>
-+<entry>Error correction code byte 1</entry>
-+</row>
-+<row>
-+<entry>0x02</entry>
-+<entry>ECC byte 2</entry>
-+<entry>Error correction code byte 2</entry>
-+</row>
-+<row>
-+<entry>0x03</entry>
-+<entry>Autoplace 0</entry>
-+<entry></entry>
-+</row>
-+<row>
-+<entry>0x04</entry>
-+<entry>Autoplace 1</entry>
-+<entry></entry>
-+</row>
-+<row>
-+<entry>0x05</entry>
-+<entry>Bad block marker</entry>
-+<entry>If any bit in this byte is zero, then this block is bad.
-+This applies only to the first page in a block. In the remaining
-+pages this byte is reserved</entry>
-+</row>
-+<row>
-+<entry>0x06</entry>
-+<entry>Autoplace 2</entry>
-+<entry></entry>
-+</row>
-+<row>
-+<entry>0x07</entry>
-+<entry>Autoplace 3</entry>
-+<entry></entry>
-+</row>
-+</tbody></tgroup></informaltable>
-+ </sect2>
-+ <sect2>
-+ <title>512 byte pagesize</title>
-+<informaltable><tgroup cols="3"><tbody>
-+<row>
-+<entry>Offset</entry>
-+<entry>Content</entry>
-+<entry>Comment</entry>
-+</row>
-+<row>
-+<entry>0x00</entry>
-+<entry>ECC byte 0</entry>
-+<entry>Error correction code byte 0 of the lower 256 Byte data in
-+this page</entry>
-+</row>
-+<row>
-+<entry>0x01</entry>
-+<entry>ECC byte 1</entry>
-+<entry>Error correction code byte 1 of the lower 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x02</entry>
-+<entry>ECC byte 2</entry>
-+<entry>Error correction code byte 2 of the lower 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x03</entry>
-+<entry>ECC byte 3</entry>
-+<entry>Error correction code byte 0 of the upper 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x04</entry>
-+<entry>reserved</entry>
-+<entry>reserved</entry>
-+</row>
-+<row>
-+<entry>0x05</entry>
-+<entry>Bad block marker</entry>
-+<entry>If any bit in this byte is zero, then this block is bad.
-+This applies only to the first page in a block. In the remaining
-+pages this byte is reserved</entry>
-+</row>
-+<row>
-+<entry>0x06</entry>
-+<entry>ECC byte 4</entry>
-+<entry>Error correction code byte 1 of the upper 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x07</entry>
-+<entry>ECC byte 5</entry>
-+<entry>Error correction code byte 2 of the upper 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x08 - 0x0F</entry>
-+<entry>Autoplace 0 - 7</entry>
-+<entry></entry>
-+</row>
-+</tbody></tgroup></informaltable>
-+ </sect2>
-+ <sect2>
-+ <title>2048 byte pagesize</title>
-+<informaltable><tgroup cols="3"><tbody>
-+<row>
-+<entry>Offset</entry>
-+<entry>Content</entry>
-+<entry>Comment</entry>
-+</row>
-+<row>
-+<entry>0x00</entry>
-+<entry>Bad block marker</entry>
-+<entry>If any bit in this byte is zero, then this block is bad.
-+This applies only to the first page in a block. In the remaining
-+pages this byte is reserved</entry>
-+</row>
-+<row>
-+<entry>0x01</entry>
-+<entry>Reserved</entry>
-+<entry>Reserved</entry>
-+</row>
-+<row>
-+<entry>0x02-0x27</entry>
-+<entry>Autoplace 0 - 37</entry>
-+<entry></entry>
-+</row>
-+<row>
-+<entry>0x28</entry>
-+<entry>ECC byte 0</entry>
-+<entry>Error correction code byte 0 of the first 256 Byte data in
-+this page</entry>
-+</row>
-+<row>
-+<entry>0x29</entry>
-+<entry>ECC byte 1</entry>
-+<entry>Error correction code byte 1 of the first 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x2A</entry>
-+<entry>ECC byte 2</entry>
-+<entry>Error correction code byte 2 of the first 256 Bytes data in
-+this page</entry>
-+</row>
-+<row>
-+<entry>0x2B</entry>
-+<entry>ECC byte 3</entry>
-+<entry>Error correction code byte 0 of the second 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x2C</entry>
-+<entry>ECC byte 4</entry>
-+<entry>Error correction code byte 1 of the second 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x2D</entry>
-+<entry>ECC byte 5</entry>
-+<entry>Error correction code byte 2 of the second 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x2E</entry>
-+<entry>ECC byte 6</entry>
-+<entry>Error correction code byte 0 of the third 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x2F</entry>
-+<entry>ECC byte 7</entry>
-+<entry>Error correction code byte 1 of the third 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x30</entry>
-+<entry>ECC byte 8</entry>
-+<entry>Error correction code byte 2 of the third 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x31</entry>
-+<entry>ECC byte 9</entry>
-+<entry>Error correction code byte 0 of the fourth 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x32</entry>
-+<entry>ECC byte 10</entry>
-+<entry>Error correction code byte 1 of the fourth 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x33</entry>
-+<entry>ECC byte 11</entry>
-+<entry>Error correction code byte 2 of the fourth 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x34</entry>
-+<entry>ECC byte 12</entry>
-+<entry>Error correction code byte 0 of the fifth 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x35</entry>
-+<entry>ECC byte 13</entry>
-+<entry>Error correction code byte 1 of the fifth 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x36</entry>
-+<entry>ECC byte 14</entry>
-+<entry>Error correction code byte 2 of the fifth 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x37</entry>
-+<entry>ECC byte 15</entry>
-+<entry>Error correction code byte 0 of the sixt 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x38</entry>
-+<entry>ECC byte 16</entry>
-+<entry>Error correction code byte 1 of the sixt 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x39</entry>
-+<entry>ECC byte 17</entry>
-+<entry>Error correction code byte 2 of the sixt 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x3A</entry>
-+<entry>ECC byte 18</entry>
-+<entry>Error correction code byte 0 of the seventh 256 Bytes of
-+data in this page</entry>
-+</row>
-+<row>
-+<entry>0x3B</entry>
-+<entry>ECC byte 19</entry>
-+<entry>Error correction code byte 1 of the seventh 256 Bytes of
-+data in this page</entry>
-+</row>
-+<row>
-+<entry>0x3C</entry>
-+<entry>ECC byte 20</entry>
-+<entry>Error correction code byte 2 of the seventh 256 Bytes of
-+data in this page</entry>
-+</row>
-+<row>
-+<entry>0x3D</entry>
-+<entry>ECC byte 21</entry>
-+<entry>Error correction code byte 0 of the eigth 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x3E</entry>
-+<entry>ECC byte 22</entry>
-+<entry>Error correction code byte 1 of the eigth 256 Bytes of data
-+in this page</entry>
-+</row>
-+<row>
-+<entry>0x3F</entry>
-+<entry>ECC byte 23</entry>
-+<entry>Error correction code byte 2 of the eigth 256 Bytes of data
-+in this page</entry>
-+</row>
-+</tbody></tgroup></informaltable>
-+ </sect2>
-+ </sect1>
-+ </chapter>
-+
-+ <chapter id="filesystems">
-+ <title>Filesystem support</title>
-+ <para>
-+ The NAND driver provides all neccecary functions for a
-+ filesystem via the MTD interface.
-+ </para>
-+ <para>
-+ Filesystems must be aware of the NAND pecularities and
-+ restrictions. One major restrictions of NAND Flash is, that you cannot
-+ write as often as you want to a page. The consecutive writes to a page,
-+ before erasing it again, are restricted to 1-3 writes, depending on the
-+ manufacturers specifications. This applies similar to the spare area.
-+ </para>
-+ <para>
-+ Therefor NAND aware filesystems must either write in page size chunks
-+ or hold a writebuffer to collect smaller writes until they sum up to
-+ pagesize. Available NAND aware filesystems: JFFS2, YAFFS.
-+ </para>
-+ <para>
-+ The spare area usage to store filesystem data is controlled by
-+ the spare area placement functionality which is described in one
-+ of the earlier chapters.
-+ </para>
-+ </chapter>
-+ <chapter id="tools">
-+ <title>Tools</title>
-+ <para>
-+ The MTD project provides a couple of helpful tools to handle NAND Flash.
-+ <itemizedlist>
-+ <listitem><para>flasherase, flasheraseall: Erase and format FLASH partitions</para></listitem>
-+ <listitem><para>nandwrite: write filesystem images to NAND FLASH</para></listitem>
-+ <listitem><para>nanddump: dump the contents of a NAND FLASH partitions</para></listitem>
-+ </itemizedlist>
-+ </para>
-+ <para>
-+ These tools are aware of the NAND restrictions. Please use those tools
-+ instead of complaining about errors which are caused by non NAND aware
-+ access methods.
-+ </para>
-+ </chapter>
-+
-+ <chapter id="defines">
-+ <title>Constants</title>
-+ <para>
-+ This chapter describes the constants which might be relevant for a driver developer.
-+ </para>
-+ <sect1>
-+ <title>Chip option constants</title>
-+ <sect2>
-+ <title>Constants for chip id table</title>
-+ <para>
-+ These constants are defined in nand.h. They are ored together to describe
-+ the chip functionality.
-+ <programlisting>
-+/* Chip can not auto increment pages */
-+#define NAND_NO_AUTOINCR 0x00000001
-+/* Buswitdh is 16 bit */
-+#define NAND_BUSWIDTH_16 0x00000002
-+/* Device supports partial programming without padding */
-+#define NAND_NO_PADDING 0x00000004
-+/* Chip has cache program function */
-+#define NAND_CACHEPRG 0x00000008
-+/* Chip has copy back function */
-+#define NAND_COPYBACK 0x00000010
-+/* AND Chip which has 4 banks and a confusing page / block
-+ * assignment. See Renesas datasheet for further information */
-+#define NAND_IS_AND 0x00000020
-+/* Chip has a array of 4 pages which can be read without
-+ * additional ready /busy waits */
-+#define NAND_4PAGE_ARRAY 0x00000040
-+ </programlisting>
-+ </para>
-+ </sect2>
-+ <sect2>
-+ <title>Constants for runtime options</title>
-+ <para>
-+ These constants are defined in nand.h. They are ored together to describe
-+ the functionality.
-+ <programlisting>
-+/* Use a flash based bad block table. This option is parsed by the
-+ * default bad block table function (nand_default_bbt). */
-+#define NAND_USE_FLASH_BBT 0x00010000
-+/* The hw ecc generator provides a syndrome instead a ecc value on read
-+ * This can only work if we have the ecc bytes directly behind the
-+ * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */
-+#define NAND_HWECC_SYNDROME 0x00020000
-+ </programlisting>
-+ </para>
-+ </sect2>
-+ </sect1>
-+
-+ <sect1>
-+ <title>ECC selection constants</title>
-+ <para>
-+ Use these constants to select the ECC algorithm.
-+ <programlisting>
-+/* No ECC. Usage is not recommended ! */
-+#define NAND_ECC_NONE 0
-+/* Software ECC 3 byte ECC per 256 Byte data */
-+#define NAND_ECC_SOFT 1
-+/* Hardware ECC 3 byte ECC per 256 Byte data */
-+#define NAND_ECC_HW3_256 2
-+/* Hardware ECC 3 byte ECC per 512 Byte data */
-+#define NAND_ECC_HW3_512 3
-+/* Hardware ECC 6 byte ECC per 512 Byte data */
-+#define NAND_ECC_HW6_512 4
-+/* Hardware ECC 6 byte ECC per 512 Byte data */
-+#define NAND_ECC_HW8_512 6
-+ </programlisting>
-+ </para>
-+ </sect1>
-+
-+ <sect1>
-+ <title>Hardware control related constants</title>
-+ <para>
-+ These constants describe the requested hardware access function when
-+ the boardspecific hardware control function is called
-+ <programlisting>
-+/* Select the chip by setting nCE to low */
-+#define NAND_CTL_SETNCE 1
-+/* Deselect the chip by setting nCE to high */
-+#define NAND_CTL_CLRNCE 2
-+/* Select the command latch by setting CLE to high */
-+#define NAND_CTL_SETCLE 3
-+/* Deselect the command latch by setting CLE to low */
-+#define NAND_CTL_CLRCLE 4
-+/* Select the address latch by setting ALE to high */
-+#define NAND_CTL_SETALE 5
-+/* Deselect the address latch by setting ALE to low */
-+#define NAND_CTL_CLRALE 6
-+/* Set write protection by setting WP to high. Not used! */
-+#define NAND_CTL_SETWP 7
-+/* Clear write protection by setting WP to low. Not used! */
-+#define NAND_CTL_CLRWP 8
-+ </programlisting>
-+ </para>
-+ </sect1>
-+
-+ <sect1>
-+ <title>Bad block table related constants</title>
-+ <para>
-+ These constants describe the options used for bad block
-+ table descriptors.
-+ <programlisting>
-+/* Options for the bad block table descriptors */
-+
-+/* The number of bits used per block in the bbt on the device */
-+#define NAND_BBT_NRBITS_MSK 0x0000000F
-+#define NAND_BBT_1BIT 0x00000001
-+#define NAND_BBT_2BIT 0x00000002
-+#define NAND_BBT_4BIT 0x00000004
-+#define NAND_BBT_8BIT 0x00000008
-+/* The bad block table is in the last good block of the device */
-+#define NAND_BBT_LASTBLOCK 0x00000010
-+/* The bbt is at the given page, else we must scan for the bbt */
-+#define NAND_BBT_ABSPAGE 0x00000020
-+/* The bbt is at the given page, else we must scan for the bbt */
-+#define NAND_BBT_SEARCH 0x00000040
-+/* bbt is stored per chip on multichip devices */
-+#define NAND_BBT_PERCHIP 0x00000080
-+/* bbt has a version counter at offset veroffs */
-+#define NAND_BBT_VERSION 0x00000100
-+/* Create a bbt if none axists */
-+#define NAND_BBT_CREATE 0x00000200
-+/* Search good / bad pattern through all pages of a block */
-+#define NAND_BBT_SCANALLPAGES 0x00000400
-+/* Scan block empty during good / bad block scan */
-+#define NAND_BBT_SCANEMPTY 0x00000800
-+/* Write bbt if neccecary */
-+#define NAND_BBT_WRITE 0x00001000
-+/* Read and write back block contents when writing bbt */
-+#define NAND_BBT_SAVECONTENT 0x00002000
-+ </programlisting>
-+ </para>
-+ </sect1>
-+
-+ </chapter>
-+
-+ <chapter id="structs">
-+ <title>Structures</title>
-+ <para>
-+ This chapter contains the autogenerated documentation of the structures which are
-+ used in the NAND driver and might be relevant for a driver developer. Each
-+ struct member has a short description which is marked with an [XXX] identifier.
-+ See the chapter "Documentation hints" for an explanation.
-+ </para>
-+!Iinclude/linux/mtd/nand.h
-+ </chapter>
-+
-+ <chapter id="pubfunctions">
-+ <title>Public Functions Provided</title>
-+ <para>
-+ This chapter contains the autogenerated documentation of the NAND kernel API functions
-+ which are exported. Each function has a short description which is marked with an [XXX] identifier.
-+ See the chapter "Documentation hints" for an explanation.
-+ </para>
-+!Edrivers/mtd/nand/nand_base.c
-+!Edrivers/mtd/nand/nand_bbt.c
-+!Edrivers/mtd/nand/nand_ecc.c
-+ </chapter>
-+
-+ <chapter id="intfunctions">
-+ <title>Internal Functions Provided</title>
-+ <para>
-+ This chapter contains the autogenerated documentation of the NAND driver internal functions.
-+ Each function has a short description which is marked with an [XXX] identifier.
-+ See the chapter "Documentation hints" for an explanation.
-+ The functions marked with [DEFAULT] might be relevant for a board driver developer.
-+ </para>
-+!Idrivers/mtd/nand/nand_base.c
-+!Idrivers/mtd/nand/nand_bbt.c
-+!Idrivers/mtd/nand/nand_ecc.c
-+ </chapter>
-+
-+ <chapter id="credits">
-+ <title>Credits</title>
-+ <para>
-+ The following people have contributed to the NAND driver:
-+ <orderedlist>
-+ <listitem><para>Steven J. Hill<email>sjhill@realitydiluted.com</email></para></listitem>
-+ <listitem><para>David Woodhouse<email>dwmw2@infradead.org</email></para></listitem>
-+ <listitem><para>Thomas Gleixner<email>tglx@linutronix.de</email></para></listitem>
-+ </orderedlist>
-+ A lot of users have provided bugfixes, improvements and helping hands for testing.
-+ Thanks a lot.
-+ </para>
-+ <para>
-+ The following people have contributed to this document:
-+ <orderedlist>
-+ <listitem><para>Thomas Gleixner<email>tglx@linutronix.de</email></para></listitem>
-+ </orderedlist>
-+ </para>
-+ </chapter>
-+</book>
---- linux-2.4.21/Documentation/devices.txt~bluetooth
-+++ linux-2.4.21/Documentation/devices.txt
-@@ -419,6 +419,7 @@
- 220 = /dev/mptctl Message passing technology (MPT) control
- 221 = /dev/mvista/hssdsi Montavista PICMG hot swap system driver
- 222 = /dev/mvista/hasi Montavista PICMG high availability
-+ 223 = /dev/input/uinput User level driver support for input
- 240-255 Reserved for local use
-
- 11 char Raw keyboard device
---- /dev/null
-+++ linux-2.4.21/Documentation/firmware_class/README
-@@ -0,0 +1,58 @@
-+
-+ request_firmware() hotplug interface:
-+ ------------------------------------
-+ Copyright (C) 2003 Manuel Estrada Sainz <ranty@debian.org>
-+
-+ Why:
-+ ---
-+
-+ Today, the most extended way to use firmware in the Linux kernel is linking
-+ it statically in a header file. Which has political and technical issues:
-+
-+ 1) Some firmware is not legal to redistribute.
-+ 2) The firmware occupies memory permanently, even though it often is just
-+ used once.
-+ 3) Some people, like the Debian crowd, don't consider some firmware free
-+ enough and remove entire drivers (e.g.: keyspan).
-+
-+ about in-kernel persistence:
-+ ---------------------------
-+ Under some circumstances, as explained below, it would be interesting to keep
-+ firmware images in non-swappable kernel memory or even in the kernel image
-+ (probably within initramfs).
-+
-+ Note that this functionality has not been implemented.
-+
-+ - Why OPTIONAL in-kernel persistence may be a good idea sometimes:
-+
-+ - If the device that needs the firmware is needed to access the
-+ filesystem. When upon some error the device has to be reset and the
-+ firmware reloaded, it won't be possible to get it from userspace.
-+ e.g.:
-+ - A diskless client with a network card that needs firmware.
-+ - The filesystem is stored in a disk behind an scsi device
-+ that needs firmware.
-+ - Replacing buggy DSDT/SSDT ACPI tables on boot.
-+ Note: this would require the persistent objects to be included
-+ within the kernel image, probably within initramfs.
-+
-+ And the same device can be needed to access the filesystem or not depending
-+ on the setup, so I think that the choice on what firmware to make
-+ persistent should be left to userspace.
-+
-+ - Why register_firmware()+__init can be useful:
-+ - For boot devices needing firmware.
-+ - To make the transition easier:
-+ The firmware can be declared __init and register_firmware()
-+ called on module_init. Then the firmware is warranted to be
-+ there even if "firmware hotplug userspace" is not there yet or
-+ it doesn't yet provide the needed firmware.
-+ Once the firmware is widely available in userspace, it can be
-+ removed from the kernel. Or made optional (CONFIG_.*_FIRMWARE).
-+
-+ In either case, if firmware hotplug support is there, it can move the
-+ firmware out of kernel memory into the real filesystem for later
-+ usage.
-+
-+ Note: If persistence is implemented on top of initramfs,
-+ register_firmware() may not be appropriate.
---- /dev/null
-+++ linux-2.4.21/Documentation/firmware_class/firmware_sample_driver.c
-@@ -0,0 +1,121 @@
-+/*
-+ * firmware_sample_driver.c -
-+ *
-+ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
-+ *
-+ * Sample code on how to use request_firmware() from drivers.
-+ *
-+ * Note that register_firmware() is currently useless.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/string.h>
-+
-+#include "linux/firmware.h"
-+
-+#define WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
-+#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
-+char __init inkernel_firmware[] = "let's say that this is firmware\n";
-+#endif
-+
-+static char ghost_device[] = "ghost0";
-+
-+static void sample_firmware_load(char *firmware, int size)
-+{
-+ u8 buf[size+1];
-+ memcpy(buf, firmware, size);
-+ buf[size] = '\0';
-+ printk("firmware_sample_driver: firmware: %s\n", buf);
-+}
-+
-+static void sample_probe_default(void)
-+{
-+ /* uses the default method to get the firmware */
-+ const struct firmware *fw_entry;
-+ printk("firmware_sample_driver: a ghost device got inserted :)\n");
-+
-+ if(request_firmware(&fw_entry, "sample_driver_fw", ghost_device)!=0)
-+ {
-+ printk(KERN_ERR
-+ "firmware_sample_driver: Firmware not available\n");
-+ return;
-+ }
-+
-+ sample_firmware_load(fw_entry->data, fw_entry->size);
-+
-+ release_firmware(fw_entry);
-+
-+ /* finish setting up the device */
-+}
-+static void sample_probe_specific(void)
-+{
-+ /* Uses some specific hotplug support to get the firmware from
-+ * userspace directly into the hardware, or via some sysfs file */
-+
-+ /* NOTE: This currently doesn't work */
-+
-+ printk("firmware_sample_driver: a ghost device got inserted :)\n");
-+
-+ if(request_firmware(NULL, "sample_driver_fw", ghost_device)!=0)
-+ {
-+ printk(KERN_ERR
-+ "firmware_sample_driver: Firmware load failed\n");
-+ return;
-+ }
-+
-+ /* request_firmware blocks until userspace finished, so at
-+ * this point the firmware should be already in the device */
-+
-+ /* finish setting up the device */
-+}
-+static void sample_probe_async_cont(const struct firmware *fw, void *context)
-+{
-+ if(!fw){
-+ printk(KERN_ERR
-+ "firmware_sample_driver: firmware load failed\n");
-+ return;
-+ }
-+
-+ printk("firmware_sample_driver: device pointer \"%s\"\n",
-+ (char *)context);
-+ sample_firmware_load(fw->data, fw->size);
-+}
-+static void sample_probe_async(void)
-+{
-+ /* Let's say that I can't sleep */
-+ int error;
-+ error = request_firmware_nowait (THIS_MODULE,
-+ "sample_driver_fw", ghost_device,
-+ "my device pointer",
-+ sample_probe_async_cont);
-+ if(error){
-+ printk(KERN_ERR
-+ "firmware_sample_driver:"
-+ " request_firmware_nowait failed\n");
-+ }
-+}
-+
-+static int sample_init(void)
-+{
-+#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
-+ register_firmware("sample_driver_fw", inkernel_firmware,
-+ sizeof(inkernel_firmware));
-+#endif
-+ /* since there is no real hardware insertion I just call the
-+ * sample probe functions here */
-+ sample_probe_specific();
-+ sample_probe_default();
-+ sample_probe_async();
-+ return 0;
-+}
-+static void __exit sample_exit(void)
-+{
-+}
-+
-+module_init (sample_init);
-+module_exit (sample_exit);
-+
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ linux-2.4.21/Documentation/firmware_class/hotplug-script
-@@ -0,0 +1,16 @@
-+#!/bin/sh
-+
-+# Simple hotplug script sample:
-+#
-+# Both $DEVPATH and $FIRMWARE are already provided in the environment.
-+
-+HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/
-+
-+echo 1 > /sysfs/$DEVPATH/loading
-+cat $HOTPLUG_FW_DIR/$FIRMWARE > /sysfs/$DEVPATH/data
-+echo 0 > /sysfs/$DEVPATH/loading
-+
-+# To cancel the load in case of error:
-+#
-+# echo -1 > /sysfs/$DEVPATH/loading
-+#
---- linux-2.4.21/MAINTAINERS~bluetooth
-+++ linux-2.4.21/MAINTAINERS
-@@ -302,16 +302,88 @@
- L: linux-kernel@vger.kernel.org
- S: Maintained
-
--BLUETOOTH SUBSYSTEM (BlueZ)
-+BLUETOOTH SUBSYSTEM
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
- P: Maxim Krasnyansky
- M: maxk@qualcomm.com
-+L: bluez-devel@lists.sf.net
- W: http://bluez.sf.net
-+W: http://www.bluez.org
-+W: http://www.holtmann.org/linux/bluetooth/
- S: Maintained
-
--BLUETOOTH SUBSYSTEM (PC Card Drivers)
-+BLUETOOTH RFCOMM LAYER
- P: Marcel Holtmann
- M: marcel@holtmann.org
--W: http://www.holtmann.org/linux/bluetooth/
-+P: Maxim Krasnyansky
-+M: maxk@qualcomm.com
-+S: Maintained
-+
-+BLUETOOTH BNEP LAYER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+P: Maxim Krasnyansky
-+M: maxk@qualcomm.com
-+S: Maintained
-+
-+BLUETOOTH CMTP LAYER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+S: Maintained
-+
-+BLUETOOTH HIDP LAYER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+S: Maintained
-+
-+BLUETOOTH HCI UART DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+P: Maxim Krasnyansky
-+M: maxk@qualcomm.com
-+S: Maintained
-+
-+BLUETOOTH HCI USB DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+P: Maxim Krasnyansky
-+M: maxk@qualcomm.com
-+S: Maintained
-+
-+BLUETOOTH HCI BCM203X DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+S: Maintained
-+
-+BLUETOOTH HCI BFUSB DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+S: Maintained
-+
-+BLUETOOTH HCI DTL1 DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+S: Maintained
-+
-+BLUETOOTH HCI BLUECARD DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+S: Maintained
-+
-+BLUETOOTH HCI BT3C DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+S: Maintained
-+
-+BLUETOOTH HCI BTUART DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+S: Maintained
-+
-+BLUETOOTH HCI VHCI DRIVER
-+P: Maxim Krasnyansky
-+M: maxk@qualcomm.com
- S: Maintained
-
- BONDING DRIVER
---- linux-2.4.21/Makefile~linux-mkdep
-+++ linux-2.4.21/Makefile
-@@ -14,10 +14,11 @@
- else echo sh; fi ; fi)
- TOPDIR := $(shell /bin/pwd)
-
-+PATH := /usr/local/arm/3.3/bin:$(PATH)
- HPATH = $(TOPDIR)/include
- FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net $(HPATH)/math-emu
-
--HOSTCC = gcc
-+HOSTCC = ccache gcc
- HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
-
- CROSS_COMPILE = arm-linux-
-@@ -28,7 +29,7 @@
-
- AS = $(CROSS_COMPILE)as
- LD = $(CROSS_COMPILE)ld
--CC = $(CROSS_COMPILE)gcc
-+CC = ccache $(CROSS_COMPILE)gcc
- CPP = $(CC) -E
- AR = $(CROSS_COMPILE)ar
- NM = $(CROSS_COMPILE)nm
-@@ -80,6 +81,7 @@
- # makefile but the arguement can be passed to make if needed.
- #
-
-+export INSTALL_MOD_PATH = /tftpboot/ramses2
- MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
- export MODLIB
-
-@@ -140,7 +142,6 @@
- DRIVERS-y += drivers/serial/serial.o \
- drivers/char/char.o \
- drivers/block/block.o \
-- drivers/misc/misc.o \
- drivers/net/net.o
- DRIVERS-$(CONFIG_AGP) += drivers/char/agp/agp.o
- DRIVERS-$(CONFIG_DRM_NEW) += drivers/char/drm/drm.o
-@@ -197,6 +198,7 @@
- DRIVERS-$(CONFIG_ISDN_BOOL) += drivers/isdn/vmlinux-obj.o
- DRIVERS-$(CONFIG_PLD) += drivers/pld/pld.o
- DRIVERS-$(CONFIG_ARCH_AT91RM9200) += drivers/at91/at91drv.o
-+DRIVERS-y += drivers/misc/misc.o
-
- DRIVERS := $(DRIVERS-y)
-
-@@ -416,7 +418,7 @@
- endif
- .PHONY: _modinst_post
- _modinst_post: _modinst_post_pcmcia
-- if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
-+# if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
-
- # Backwards compatibilty symlinks for people still using old versions
- # of pcmcia-cs with hard coded pathnames on insmod. Remove
-@@ -495,7 +497,7 @@
- ifdef CONFIG_MODVERSIONS
- $(MAKE) update-modverfile
- endif
-- scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
-+ $(foreach, dir, $(FINDHPATH), scripts/mkdep -- `find $(dir) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` >> .hdepend)
- scripts/mkdep -- init/*.c > .depend
-
- ifdef CONFIG_MODVERSIONS
-@@ -574,3 +576,14 @@
- . scripts/mkversion > .version ; \
- rpm -ta $(TOPDIR)/../$(KERNELPATH).tar.gz ; \
- rm $(TOPDIR)/../$(KERNELPATH).tar.gz
-+
-+
-+
-+#
-+# Burn Linux Image for ArmBoot using the bdi2000
-+#
-+burn burn_zImage:
-+ ../hwtester/burner.py arch/arm/boot/zImage 0x40000
-+
-+publish: arch/arm/boot/zImage
-+ cp arch/arm/boot/zImage /tftpboot/bdi/zImage.testing
---- linux-2.4.21/arch/arm/Makefile~arm-noshortloads
-+++ linux-2.4.21/arch/arm/Makefile
-@@ -55,8 +55,8 @@
- #tune-$(CONFIG_CPU_XSCALE) :=-mtune=xscale
- tune-$(CONFIG_CPU_XSCALE) :=-mtune=strongarm
-
--CFLAGS_BOOT :=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm
--CFLAGS +=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm
-+CFLAGS_BOOT :=$(apcs-y) $(arch-y) $(tune-y) -msoft-float -Uarm
-+CFLAGS +=$(apcs-y) $(arch-y) $(tune-y) -msoft-float -Uarm
- AFLAGS +=$(apcs-y) $(arch-y) -msoft-float
-
- ifeq ($(CONFIG_CPU_26),y)
-@@ -289,7 +289,7 @@
- arch/arm/kernel arch/arm/mm arch/arm/lib: dummy
- $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@)
-
--bzImage zImage zinstall Image xipImage bootpImage install: vmlinux
-+bzImage zImage zinstall Image xipImage bootpImage: vmlinux
- @$(MAKEBOOT) $@
-
- CLEAN_FILES += \
---- linux-2.4.21/arch/arm/config.in~pm
-+++ linux-2.4.21/arch/arm/config.in
-@@ -152,6 +152,7 @@
- dep_bool ' Intel DBPXA250 Development Platform' CONFIG_ARCH_LUBBOCK $CONFIG_ARCH_PXA
- dep_bool ' Accelent Xscale IDP' CONFIG_ARCH_PXA_IDP $CONFIG_ARCH_PXA
- dep_bool ' Intrinsyc CerfBoard' CONFIG_ARCH_PXA_CERF $CONFIG_ARCH_PXA
-+dep_bool ' M und N Ramses' CONFIG_ARCH_RAMSES $CONFIG_ARCH_PXA
- dep_bool ' Trizeps-II MT6N' CONFIG_ARCH_TRIZEPS2 $CONFIG_ARCH_PXA
-
- if [ "$CONFIG_ARCH_PXA_CERF" = "y" ]; then
-@@ -586,6 +587,7 @@
- tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
- tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
- dep_bool 'Power Management support (experimental)' CONFIG_PM $CONFIG_EXPERIMENTAL
-+dep_bool 'Advanced power management emulation support' CONFIG_APM $CONFIG_PM
- dep_tristate 'RISC OS personality' CONFIG_ARTHUR $CONFIG_CPU_32
- string 'Default kernel command string' CONFIG_CMDLINE ""
-
---- /dev/null
-+++ linux-2.4.21/arch/arm/def-configs/ramses
-@@ -0,0 +1,1177 @@
-+#
-+# Automatically generated by make menuconfig: don't edit
-+#
-+CONFIG_ARM=y
-+# CONFIG_EISA is not set
-+# CONFIG_SBUS is not set
-+# CONFIG_MCA is not set
-+CONFIG_UID16=y
-+CONFIG_RWSEM_GENERIC_SPINLOCK=y
-+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-+# CONFIG_GENERIC_BUST_SPINLOCK is not set
-+# CONFIG_GENERIC_ISA_DMA is not set
-+
-+#
-+# Code maturity level options
-+#
-+CONFIG_EXPERIMENTAL=y
-+# CONFIG_OBSOLETE is not set
-+
-+#
-+# Loadable module support
-+#
-+CONFIG_MODULES=y
-+# CONFIG_MODVERSIONS is not set
-+CONFIG_KMOD=y
-+
-+#
-+# System Type
-+#
-+# CONFIG_ARCH_ANAKIN is not set
-+# CONFIG_ARCH_ARCA5K is not set
-+# CONFIG_ARCH_CLPS7500 is not set
-+# CONFIG_ARCH_CLPS711X is not set
-+# CONFIG_ARCH_CO285 is not set
-+CONFIG_ARCH_PXA=y
-+# 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_OMAHA is not set
-+# CONFIG_ARCH_L7200 is not set
-+# CONFIG_ARCH_MX1ADS is not set
-+# CONFIG_ARCH_RPC is not set
-+# CONFIG_ARCH_RISCSTATION is not set
-+# CONFIG_ARCH_SA1100 is not set
-+# CONFIG_ARCH_SHARK is not set
-+# CONFIG_ARCH_AT91RM9200 is not set
-+
-+#
-+# Archimedes/A5000 Implementations
-+#
-+# CONFIG_ARCH_ARC is not set
-+# CONFIG_ARCH_A5K is not set
-+
-+#
-+# Footbridge Implementations
-+#
-+# CONFIG_ARCH_CATS is not set
-+# CONFIG_ARCH_PERSONAL_SERVER is not set
-+# CONFIG_ARCH_EBSA285_ADDIN is not set
-+# CONFIG_ARCH_EBSA285_HOST is not set
-+# CONFIG_ARCH_NETWINDER is not set
-+
-+#
-+# SA11x0 Implementations
-+#
-+# CONFIG_SA1100_ACCELENT is not set
-+# CONFIG_SA1100_ASSABET is not set
-+# CONFIG_ASSABET_NEPONSET is not set
-+# CONFIG_SA1100_ADSAGC is not set
-+# CONFIG_SA1100_ADSBITSY is not set
-+# CONFIG_SA1100_ADSBITSYPLUS is not set
-+# CONFIG_SA1100_BRUTUS is not set
-+# CONFIG_SA1100_CEP is not set
-+# CONFIG_SA1100_CERF is not set
-+# CONFIG_SA1100_H3100 is not set
-+# CONFIG_SA1100_H3600 is not set
-+# CONFIG_SA1100_H3800 is not set
-+# CONFIG_SA1100_H3XXX is not set
-+# CONFIG_H3600_SLEEVE is not set
-+# CONFIG_SA1100_EXTENEX1 is not set
-+# CONFIG_SA1100_FLEXANET is not set
-+# CONFIG_SA1100_FREEBIRD is not set
-+# CONFIG_SA1100_FRODO is not set
-+# CONFIG_SA1100_GRAPHICSCLIENT is not set
-+# CONFIG_SA1100_GRAPHICSMASTER is not set
-+# CONFIG_SA1100_HACKKIT is not set
-+# CONFIG_SA1100_BADGE4 is not set
-+# CONFIG_SA1100_JORNADA720 is not set
-+# CONFIG_SA1100_HUW_WEBPANEL is not set
-+# CONFIG_SA1100_ITSY is not set
-+# CONFIG_SA1100_LART is not set
-+# CONFIG_SA1100_NANOENGINE is not set
-+# CONFIG_SA1100_OMNIMETER is not set
-+# CONFIG_SA1100_PANGOLIN is not set
-+# CONFIG_SA1100_PLEB is not set
-+# CONFIG_SA1100_PT_SYSTEM3 is not set
-+# CONFIG_SA1100_SHANNON is not set
-+# CONFIG_SA1100_SHERMAN is not set
-+# CONFIG_SA1100_SIMPAD is not set
-+# CONFIG_SA1100_SIMPUTER is not set
-+# CONFIG_SA1100_PFS168 is not set
-+# CONFIG_SA1100_VICTOR is not set
-+# CONFIG_SA1100_XP860 is not set
-+# CONFIG_SA1100_YOPY is not set
-+# CONFIG_SA1100_USB is not set
-+# CONFIG_SA1100_USB_NETLINK is not set
-+# CONFIG_SA1100_USB_CHAR is not set
-+# CONFIG_SA1100_SSP is not set
-+
-+#
-+# AT91RM9200 Implementations
-+#
-+# CONFIG_ARCH_AT91RM9200DK is not set
-+
-+#
-+# Intel PXA250/210 Implementations
-+#
-+# CONFIG_ARCH_LUBBOCK is not set
-+# CONFIG_ARCH_PXA_IDP is not set
-+# CONFIG_ARCH_PXA_CERF is not set
-+CONFIG_ARCH_RAMSES=y
-+# CONFIG_ARCH_TRIZEPS2 is not set
-+CONFIG_PXA_USB=m
-+CONFIG_PXA_USB_NETLINK=m
-+CONFIG_PXA_USB_CHAR=m
-+
-+#
-+# CLPS711X/EP721X Implementations
-+#
-+# CONFIG_ARCH_AUTCPU12 is not set
-+# CONFIG_ARCH_CDB89712 is not set
-+# CONFIG_ARCH_CLEP7312 is not set
-+# CONFIG_ARCH_EDB7211 is not set
-+# CONFIG_ARCH_FORTUNET is not set
-+# CONFIG_ARCH_GUIDEA07 is not set
-+# CONFIG_ARCH_P720T is not set
-+# CONFIG_ARCH_EP7211 is not set
-+# CONFIG_ARCH_EP7212 is not set
-+# CONFIG_ARCH_ACORN is not set
-+# CONFIG_PLD is not set
-+# CONFIG_FOOTBRIDGE is not set
-+# CONFIG_FOOTBRIDGE_HOST is not set
-+# CONFIG_FOOTBRIDGE_ADDIN is not set
-+CONFIG_CPU_32=y
-+# CONFIG_CPU_26 is not set
-+# CONFIG_CPU_ARM610 is not set
-+# CONFIG_CPU_ARM710 is not set
-+# CONFIG_CPU_ARM720T is not set
-+# CONFIG_CPU_ARM920T is not set
-+# CONFIG_CPU_ARM922T is not set
-+# CONFIG_CPU_ARM926T is not set
-+# CONFIG_CPU_ARM1020 is not set
-+# CONFIG_CPU_ARM1020E is not set
-+# CONFIG_CPU_ARM1022 is not set
-+# CONFIG_CPU_ARM1026 is not set
-+# CONFIG_CPU_SA110 is not set
-+# CONFIG_CPU_SA1100 is not set
-+CONFIG_CPU_32v5=y
-+CONFIG_CPU_XSCALE=y
-+# CONFIG_XSCALE_CACHE_ERRATA is not set
-+# CONFIG_CPU_32v3 is not set
-+# CONFIG_CPU_32v4 is not set
-+# CONFIG_DISCONTIGMEM is not set
-+
-+#
-+# General setup
-+#
-+# CONFIG_PCI is not set
-+# CONFIG_ISA is not set
-+# CONFIG_ISA_DMA is not set
-+CONFIG_ZBOOT_ROM=y
-+CONFIG_ZBOOT_ROM_TEXT=00040000
-+CONFIG_ZBOOT_ROM_BSS=a00c0000
-+CONFIG_CPU_FREQ=y
-+CONFIG_HOTPLUG=y
-+
-+#
-+# PCMCIA/CardBus support
-+#
-+CONFIG_PCMCIA=y
-+# CONFIG_I82092 is not set
-+# CONFIG_I82365 is not set
-+# CONFIG_TCIC is not set
-+# CONFIG_PCMCIA_CLPS6700 is not set
-+# CONFIG_PCMCIA_SA1100 is not set
-+CONFIG_PCMCIA_PXA=y
-+
-+#
-+# MMC device drivers
-+#
-+CONFIG_MMC=m
-+CONFIG_MMC_PXA=m
-+CONFIG_MMC_BLOCK=m
-+CONFIG_MMC_PARTITIONS=y
-+CONFIG_NET=y
-+CONFIG_SYSVIPC=y
-+# CONFIG_BSD_PROCESS_ACCT is not set
-+CONFIG_SYSCTL=y
-+# CONFIG_XIP_KERNEL is not set
-+CONFIG_FPE_NWFPE=y
-+# CONFIG_FPE_NWFPE_XP is not set
-+# CONFIG_FPE_FASTFPE is not set
-+CONFIG_KCORE_ELF=y
-+# CONFIG_KCORE_AOUT is not set
-+# CONFIG_BINFMT_AOUT is not set
-+CONFIG_BINFMT_ELF=y
-+# CONFIG_BINFMT_MISC is not set
-+CONFIG_PM=y
-+CONFIG_APM=y
-+# CONFIG_ARTHUR is not set
-+CONFIG_CMDLINE="debug"
-+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 is not set
-+# CONFIG_MTD_CMDLINE_PARTS is not set
-+# CONFIG_MTD_AFS_PARTS is not set
-+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_MAP_BANK_WIDTH_1 is not set
-+# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
-+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 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_CFI_UTIL=y
-+# 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
-+# CONFIG_MTD_AMDSTD is not set
-+# CONFIG_MTD_SHARP is not set
-+# CONFIG_MTD_JEDEC 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_CDB89712 is not set
-+# CONFIG_MTD_SA1100 is not set
-+# CONFIG_MTD_DC21285 is not set
-+# CONFIG_MTD_IQ80310 is not set
-+# CONFIG_MTD_LUBBOCK is not set
-+CONFIG_MTD_RAMSES=y
-+# CONFIG_MTD_IXP425 is not set
-+# CONFIG_MTD_EPXA10DB is not set
-+# CONFIG_MTD_FORTUNET is not set
-+# CONFIG_MTD_AUTCPU12 is not set
-+# CONFIG_MTD_EDB7312 is not set
-+# CONFIG_MTD_H720X is not set
-+# CONFIG_MTD_IMPA7 is not set
-+# CONFIG_MTD_CEIVA is not set
-+# CONFIG_MTD_NOR_TOTO is not set
-+# CONFIG_MTD_PCI is not set
-+# CONFIG_MTD_PCMCIA 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
-+# CONFIG_MTD_DOC2000 is not set
-+# CONFIG_MTD_DOC2001 is not set
-+# CONFIG_MTD_DOC2001PLUS is not set
-+# CONFIG_MTD_DOCPROBE is not set
-+# CONFIG_MTD_DOCECC is not set
-+
-+#
-+# NAND Flash Device Drivers
-+#
-+# CONFIG_MTD_NAND is not set
-+# CONFIG_MTD_NAND_SPIA is not set
-+# CONFIG_MTD_NAND_TOTO is not set
-+# CONFIG_MTD_NAND_AUTCPU12 is not set
-+# CONFIG_MTD_NAND_EDB7312 is not set
-+# CONFIG_MTD_NAND_DISKONCHIP is not set
-+
-+#
-+# Plug and Play configuration
-+#
-+# CONFIG_PNP is not set
-+# CONFIG_ISAPNP is not set
-+
-+#
-+# Block devices
-+#
-+# CONFIG_BLK_DEV_FD is not set
-+# CONFIG_BLK_DEV_XD is not set
-+# CONFIG_PARIDE is not set
-+# CONFIG_BLK_CPQ_DA is not set
-+# CONFIG_BLK_CPQ_CISS_DA is not set
-+# CONFIG_CISS_SCSI_TAPE is not set
-+# CONFIG_BLK_DEV_DAC960 is not set
-+# CONFIG_BLK_DEV_UMEM is not set
-+CONFIG_BLK_DEV_LOOP=m
-+CONFIG_BLK_DEV_NBD=m
-+# CONFIG_BLK_DEV_RAM is not set
-+# CONFIG_BLK_DEV_INITRD is not set
-+CONFIG_BLK_STATS=y
-+
-+#
-+# Multi-device support (RAID and LVM)
-+#
-+# CONFIG_MD is not set
-+# CONFIG_BLK_DEV_MD is not set
-+# CONFIG_MD_LINEAR is not set
-+# CONFIG_MD_RAID0 is not set
-+# CONFIG_MD_RAID1 is not set
-+# CONFIG_MD_RAID5 is not set
-+# CONFIG_MD_MULTIPATH is not set
-+# CONFIG_BLK_DEV_LVM is not set
-+
-+#
-+# Networking options
-+#
-+CONFIG_PACKET=y
-+# CONFIG_PACKET_MMAP is not set
-+CONFIG_NETLINK_DEV=m
-+# CONFIG_NETFILTER is not set
-+# CONFIG_FILTER is not set
-+CONFIG_UNIX=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=m
-+CONFIG_NET_IPGRE=m
-+# CONFIG_ARPD is not set
-+# CONFIG_INET_ECN is not set
-+# CONFIG_SYN_COOKIES is not set
-+# CONFIG_IPV6 is not set
-+# CONFIG_KHTTPD is not set
-+# CONFIG_ATM is not set
-+CONFIG_VLAN_8021Q=m
-+# CONFIG_IPX is not set
-+# CONFIG_ATALK is not set
-+
-+#
-+# Appletalk devices
-+#
-+# CONFIG_DEV_APPLETALK is not set
-+# CONFIG_DECNET is not set
-+CONFIG_BRIDGE=m
-+# CONFIG_X25 is not set
-+# CONFIG_LAPB is not set
-+# CONFIG_LLC is not set
-+# CONFIG_NET_DIVERT is not set
-+# CONFIG_ECONET is not set
-+# CONFIG_WAN_ROUTER is not set
-+# CONFIG_NET_FASTROUTE 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
-+
-+#
-+# Network device support
-+#
-+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
-+# CONFIG_ETHERTAP is not set
-+
-+#
-+# Ethernet (10 or 100Mbit)
-+#
-+CONFIG_NET_ETHERNET=y
-+# CONFIG_ARM_AM79C961A is not set
-+# CONFIG_ARM_CIRRUS is not set
-+# CONFIG_SUNLANCE is not set
-+# CONFIG_SUNBMAC is not set
-+# CONFIG_SUNQE is not set
-+# CONFIG_SUNGEM is not set
-+# CONFIG_NET_VENDOR_3COM is not set
-+# CONFIG_LANCE is not set
-+CONFIG_NET_VENDOR_SMC=y
-+# CONFIG_WD80x3 is not set
-+# CONFIG_ULTRAMCA is not set
-+# CONFIG_ULTRA is not set
-+# CONFIG_ULTRA32 is not set
-+# CONFIG_SMC9194 is not set
-+CONFIG_SMC91X=y
-+# CONFIG_NET_VENDOR_RACAL is not set
-+# CONFIG_NET_ISA is not set
-+# CONFIG_NET_PCI 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_MYRI_SBUS 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
-+# CONFIG_FDDI is not set
-+# CONFIG_HIPPI is not set
-+# CONFIG_PLIP is not set
-+CONFIG_PPP=m
-+# CONFIG_PPP_MULTILINK is not set
-+# CONFIG_PPP_FILTER is not set
-+CONFIG_PPP_ASYNC=m
-+CONFIG_PPP_SYNC_TTY=m
-+CONFIG_PPP_DEFLATE=m
-+CONFIG_PPP_BSDCOMP=m
-+CONFIG_PPPOE=m
-+# CONFIG_SLIP is not set
-+
-+#
-+# Wireless LAN (non-hamradio)
-+#
-+CONFIG_NET_RADIO=y
-+# CONFIG_STRIP is not set
-+# CONFIG_WAVELAN is not set
-+# CONFIG_ARLAN is not set
-+# CONFIG_AIRONET4500 is not set
-+# CONFIG_AIRONET4500_NONCS is not set
-+# CONFIG_AIRONET4500_PROC is not set
-+CONFIG_HERMES=m
-+CONFIG_PCMCIA_HERMES=m
-+# CONFIG_AIRO_CS is not set
-+CONFIG_NET_WIRELESS=y
-+
-+#
-+# Token Ring devices
-+#
-+# CONFIG_TR is not set
-+# CONFIG_NET_FC 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=y
-+# CONFIG_PCMCIA_3C589 is not set
-+# CONFIG_PCMCIA_3C574 is not set
-+# CONFIG_PCMCIA_FMVJ18X is not set
-+# CONFIG_PCMCIA_PCNET is not set
-+# CONFIG_PCMCIA_AXNET is not set
-+# CONFIG_PCMCIA_NMCLAN is not set
-+# CONFIG_PCMCIA_SMC91C92 is not set
-+# CONFIG_PCMCIA_XIRC2PS is not set
-+# CONFIG_ARCNET_COM20020_CS is not set
-+# CONFIG_PCMCIA_IBMTR is not set
-+# CONFIG_NET_PCMCIA_RADIO is not set
-+
-+#
-+# Amateur Radio support
-+#
-+# CONFIG_HAMRADIO is not set
-+
-+#
-+# IrDA (infrared) support
-+#
-+CONFIG_IRDA=m
-+CONFIG_IRLAN=m
-+CONFIG_IRNET=m
-+CONFIG_IRCOMM=m
-+CONFIG_IRDA_ULTRA=y
-+CONFIG_IRDA_CACHE_LAST_LSAP=y
-+CONFIG_IRDA_FAST_RR=y
-+CONFIG_IRDA_DEBUG=y
-+
-+#
-+# Infrared-port device drivers
-+#
-+CONFIG_IRTTY_SIR=m
-+CONFIG_IRPORT_SIR=m
-+# CONFIG_DONGLE is not set
-+# CONFIG_USB_IRDA is not set
-+# CONFIG_NSC_FIR is not set
-+# CONFIG_WINBOND_FIR is not set
-+# CONFIG_TOSHIBA_OLD 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_PXA_FIR=m
-+
-+#
-+# ATA/ATAPI/MFM/RLL support
-+#
-+# CONFIG_IDE is not set
-+# CONFIG_BLK_DEV_IDE_MODES is not set
-+# CONFIG_BLK_DEV_HD is not set
-+
-+#
-+# SCSI support
-+#
-+CONFIG_SCSI=m
-+CONFIG_BLK_DEV_SD=m
-+CONFIG_SD_EXTRA_DEVS=4
-+# CONFIG_CHR_DEV_ST is not set
-+# CONFIG_CHR_DEV_OSST is not set
-+# CONFIG_BLK_DEV_SR is not set
-+# CONFIG_CHR_DEV_SG is not set
-+# CONFIG_SCSI_DEBUG_QUEUES is not set
-+# CONFIG_SCSI_MULTI_LUN is not set
-+# CONFIG_SCSI_CONSTANTS is not set
-+# CONFIG_SCSI_LOGGING is not set
-+
-+#
-+# SCSI low-level drivers
-+#
-+# CONFIG_SCSI_7000FASST is not set
-+# CONFIG_SCSI_ACARD is not set
-+# CONFIG_SCSI_AHA152X is not set
-+# CONFIG_SCSI_AHA1542 is not set
-+# CONFIG_SCSI_AHA1740 is not set
-+# CONFIG_SCSI_AACRAID is not set
-+# CONFIG_SCSI_AIC7XXX is not set
-+# CONFIG_SCSI_AIC79XX is not set
-+# CONFIG_SCSI_AIC7XXX_OLD is not set
-+# CONFIG_SCSI_DPT_I2O is not set
-+# CONFIG_SCSI_ADVANSYS is not set
-+# CONFIG_SCSI_IN2000 is not set
-+# CONFIG_SCSI_AM53C974 is not set
-+# CONFIG_SCSI_MEGARAID is not set
-+# CONFIG_SCSI_BUSLOGIC is not set
-+# CONFIG_SCSI_DMX3191D is not set
-+# CONFIG_SCSI_DTC3280 is not set
-+# CONFIG_SCSI_EATA is not set
-+# CONFIG_SCSI_EATA_DMA is not set
-+# CONFIG_SCSI_EATA_PIO is not set
-+# CONFIG_SCSI_FUTURE_DOMAIN is not set
-+# CONFIG_SCSI_GDTH is not set
-+# CONFIG_SCSI_GENERIC_NCR5380 is not set
-+# CONFIG_SCSI_INITIO is not set
-+# CONFIG_SCSI_INIA100 is not set
-+# CONFIG_SCSI_NCR53C406A is not set
-+# CONFIG_SCSI_NCR53C7xx is not set
-+# CONFIG_SCSI_PAS16 is not set
-+# CONFIG_SCSI_PCI2000 is not set
-+# CONFIG_SCSI_PCI2220I is not set
-+# CONFIG_SCSI_PSI240I is not set
-+# CONFIG_SCSI_QLOGIC_FAS is not set
-+# CONFIG_SCSI_SIM710 is not set
-+# CONFIG_SCSI_SYM53C416 is not set
-+# CONFIG_SCSI_T128 is not set
-+# CONFIG_SCSI_U14_34F is not set
-+# CONFIG_SCSI_NSP32 is not set
-+# CONFIG_SCSI_DEBUG is not set
-+
-+#
-+# PCMCIA SCSI adapter support
-+#
-+# CONFIG_SCSI_PCMCIA is not set
-+
-+#
-+# I2O device support
-+#
-+# CONFIG_I2O is not set
-+# CONFIG_I2O_BLOCK is not set
-+# CONFIG_I2O_LAN is not set
-+# CONFIG_I2O_SCSI is not set
-+# CONFIG_I2O_PROC is not set
-+
-+#
-+# ISDN subsystem
-+#
-+# CONFIG_ISDN is not set
-+
-+#
-+# Input core support
-+#
-+CONFIG_INPUT=y
-+CONFIG_INPUT_KEYBDEV=y
-+CONFIG_INPUT_RAMSES_KEYB=y
-+CONFIG_INPUT_RAMSES_WEDGE=y
-+# CONFIG_INPUT_MOUSEDEV is not set
-+# CONFIG_INPUT_JOYDEV is not set
-+CONFIG_INPUT_EVDEV=y
-+CONFIG_INPUT_UINPUT=m
-+# CONFIG_INPUT_MX1TS is not set
-+
-+#
-+# Character devices
-+#
-+CONFIG_VT=y
-+CONFIG_VT_CONSOLE=y
-+CONFIG_SERIAL=y
-+CONFIG_SERIAL_CONSOLE=y
-+# CONFIG_SERIAL_EXTENDED is not set
-+# CONFIG_SERIAL_NONSTANDARD is not set
-+
-+#
-+# Serial drivers
-+#
-+# CONFIG_SERIAL_ANAKIN is not set
-+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
-+# CONFIG_SERIAL_AMBA is not set
-+# CONFIG_SERIAL_AMBA_CONSOLE is not set
-+# CONFIG_SERIAL_CLPS711X is not set
-+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
-+# CONFIG_SERIAL_21285 is not set
-+# CONFIG_SERIAL_21285_OLD is not set
-+# CONFIG_SERIAL_21285_CONSOLE is not set
-+# CONFIG_SERIAL_UART00 is not set
-+# CONFIG_SERIAL_UART00_CONSOLE is not set
-+# CONFIG_SERIAL_SA1100 is not set
-+# CONFIG_SERIAL_SA1100_CONSOLE is not set
-+# CONFIG_SERIAL_OMAHA is not set
-+# CONFIG_SERIAL_OMAHA_CONSOLE is not set
-+# CONFIG_SERIAL_AT91 is not set
-+# CONFIG_SERIAL_AT91_CONSOLE is not set
-+# CONFIG_SERIAL_8250 is not set
-+# CONFIG_SERIAL_8250_CONSOLE is not set
-+# CONFIG_SERIAL_8250_EXTENDED is not set
-+# CONFIG_SERIAL_8250_MANY_PORTS is not set
-+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
-+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-+# CONFIG_SERIAL_8250_MULTIPORT is not set
-+# CONFIG_SERIAL_8250_HUB6 is not set
-+CONFIG_UNIX98_PTYS=y
-+CONFIG_UNIX98_PTY_COUNT=32
-+
-+#
-+# I2C support
-+#
-+CONFIG_I2C=y
-+# CONFIG_I2C_ALGOBIT is not set
-+# CONFIG_I2C_ALGOPCF is not set
-+CONFIG_I2C_PXA_ALGO=y
-+CONFIG_I2C_PXA_ADAP=y
-+CONFIG_I2C_CHARDEV=m
-+CONFIG_I2C_PROC=m
-+# CONFIG_I2C_DS1307 is not set
-+CONFIG_I2C_DS1337=y
-+
-+#
-+# L3 serial bus support
-+#
-+# CONFIG_L3 is not set
-+# CONFIG_L3_ALGOBIT is not set
-+# CONFIG_L3_BIT_SA1100_GPIO is not set
-+# CONFIG_L3_SA1111 is not set
-+# CONFIG_BIT_SA1100_GPIO is not set
-+
-+#
-+# Mice
-+#
-+# CONFIG_BUSMOUSE is not set
-+# CONFIG_MOUSE is not set
-+
-+#
-+# Joysticks
-+#
-+# CONFIG_INPUT_GAMEPORT is not set
-+# CONFIG_INPUT_NS558 is not set
-+# CONFIG_INPUT_LIGHTNING is not set
-+# CONFIG_INPUT_PCIGAME is not set
-+# CONFIG_INPUT_CS461X is not set
-+# CONFIG_INPUT_EMU10K1 is not set
-+# CONFIG_INPUT_SERIO is not set
-+# CONFIG_INPUT_SERPORT is not set
-+# CONFIG_INPUT_ANALOG is not set
-+# CONFIG_INPUT_A3D is not set
-+# CONFIG_INPUT_ADI is not set
-+# CONFIG_INPUT_COBRA is not set
-+# CONFIG_INPUT_GF2K is not set
-+# CONFIG_INPUT_GRIP is not set
-+# CONFIG_INPUT_INTERACT is not set
-+# CONFIG_INPUT_TMDC is not set
-+# CONFIG_INPUT_SIDEWINDER is not set
-+# CONFIG_INPUT_IFORCE_USB is not set
-+# CONFIG_INPUT_IFORCE_232 is not set
-+# CONFIG_INPUT_WARRIOR is not set
-+# CONFIG_INPUT_MAGELLAN is not set
-+# CONFIG_INPUT_SPACEORB is not set
-+# CONFIG_INPUT_SPACEBALL is not set
-+# CONFIG_INPUT_STINGER is not set
-+# CONFIG_INPUT_DB9 is not set
-+# CONFIG_INPUT_GAMECON is not set
-+# CONFIG_INPUT_TURBOGRAFX is not set
-+# CONFIG_QIC02_TAPE is not set
-+# CONFIG_IPMI_HANDLER is not set
-+# CONFIG_IPMI_PANIC_EVENT is not set
-+# CONFIG_IPMI_DEVICE_INTERFACE is not set
-+# CONFIG_IPMI_KCS is not set
-+# CONFIG_IPMI_WATCHDOG is not set
-+
-+#
-+# Watchdog Cards
-+#
-+# CONFIG_WATCHDOG is not set
-+# CONFIG_SCx200_GPIO is not set
-+# CONFIG_AMD_PM768 is not set
-+# CONFIG_NVRAM is not set
-+CONFIG_RTC=m
-+CONFIG_PXA_RTC=m
-+# 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_PCMCIA_SERIAL_CS=m
-+# CONFIG_SYNCLINK_CS is not set
-+
-+#
-+# Multimedia devices
-+#
-+CONFIG_VIDEO_DEV=m
-+
-+#
-+# Video For Linux
-+#
-+CONFIG_VIDEO_PROC_FS=y
-+# CONFIG_I2C_PARPORT is not set
-+# CONFIG_VIDEO_BT848 is not set
-+# CONFIG_VIDEO_PMS is not set
-+# CONFIG_VIDEO_CPIA is not set
-+# CONFIG_VIDEO_SAA5249 is not set
-+# CONFIG_TUNER_3036 is not set
-+# CONFIG_VIDEO_STRADIS is not set
-+# CONFIG_VIDEO_ZORAN is not set
-+# CONFIG_VIDEO_ZORAN_BUZ is not set
-+# CONFIG_VIDEO_ZORAN_DC10 is not set
-+# CONFIG_VIDEO_ZORAN_LML33 is not set
-+# CONFIG_VIDEO_ZR36120 is not set
-+# CONFIG_VIDEO_MEYE is not set
-+# CONFIG_VIDEO_CYBERPRO is not set
-+
-+#
-+# Radio Adapters
-+#
-+# CONFIG_RADIO_GEMTEK_PCI is not set
-+# CONFIG_RADIO_MAXIRADIO is not set
-+# CONFIG_RADIO_MAESTRO is not set
-+# CONFIG_RADIO_MIROPCM20 is not set
-+
-+#
-+# File systems
-+#
-+# CONFIG_QUOTA is not set
-+# CONFIG_AUTOFS_FS is not set
-+# CONFIG_AUTOFS4_FS is not set
-+# CONFIG_REISERFS_FS is not set
-+# CONFIG_REISERFS_CHECK is not set
-+# CONFIG_REISERFS_PROC_INFO is not set
-+# CONFIG_ADFS_FS is not set
-+# CONFIG_ADFS_FS_RW is not set
-+# CONFIG_AFFS_FS is not set
-+# CONFIG_HFS_FS is not set
-+# CONFIG_BEFS_FS is not set
-+# CONFIG_BEFS_DEBUG is not set
-+# CONFIG_BFS_FS is not set
-+# CONFIG_EXT3_FS is not set
-+# CONFIG_JBD is not set
-+# CONFIG_JBD_DEBUG is not set
-+CONFIG_FAT_FS=m
-+CONFIG_MSDOS_FS=m
-+# CONFIG_UMSDOS_FS is not set
-+CONFIG_VFAT_FS=m
-+# CONFIG_EFS_FS is not set
-+# CONFIG_JFFS_FS is not set
-+CONFIG_JFFS2_FS=y
-+CONFIG_JFFS2_FS_DEBUG=0
-+CONFIG_JFFS2_FS_WRITEBUFFER=y
-+CONFIG_JFFS2_ZLIB=y
-+CONFIG_JFFS2_RTIME=y
-+CONFIG_JFFS2_RUBIN=y
-+# CONFIG_JFFS2_LZO is not set
-+# CONFIG_JFFS2_LZARI is not set
-+# CONFIG_JFFS2_CMODE_NONE is not set
-+CONFIG_JFFS2_CMODE_PRIORITY=y
-+# CONFIG_JFFS2_CMODE_SIZE is not set
-+CONFIG_JFFS2_PROC=y
-+CONFIG_CRAMFS=m
-+# CONFIG_CRAMFS_LINEAR is not set
-+# CONFIG_CRAMFS_LINEAR_XIP is not set
-+# CONFIG_ROOT_CRAMFS_LINEAR is not set
-+CONFIG_TMPFS=y
-+CONFIG_RAMFS=y
-+# CONFIG_ISO9660_FS is not set
-+# CONFIG_JOLIET is not set
-+# CONFIG_ZISOFS is not set
-+# CONFIG_JFS_FS is not set
-+# CONFIG_JFS_DEBUG is not set
-+# CONFIG_JFS_STATISTICS is not set
-+# CONFIG_MINIX_FS is not set
-+# CONFIG_VXFS_FS is not set
-+# CONFIG_NTFS_FS is not set
-+# CONFIG_NTFS_RW is not set
-+# CONFIG_HPFS_FS is not set
-+CONFIG_PROC_FS=y
-+CONFIG_DEVFS_FS=y
-+CONFIG_DEVFS_MOUNT=y
-+# CONFIG_DEVFS_DEBUG is not set
-+# CONFIG_DEVPTS_FS is not set
-+# CONFIG_QNX4FS_FS is not set
-+# CONFIG_QNX4FS_RW is not set
-+# CONFIG_ROMFS_FS is not set
-+CONFIG_EXT2_FS=m
-+# CONFIG_SYSV_FS is not set
-+# CONFIG_UDF_FS is not set
-+# CONFIG_UDF_RW is not set
-+# CONFIG_UFS_FS is not set
-+# CONFIG_UFS_FS_WRITE is not set
-+
-+#
-+# Network File Systems
-+#
-+# CONFIG_CODA_FS is not set
-+# CONFIG_INTERMEZZO_FS is not set
-+CONFIG_NFS_FS=y
-+# CONFIG_NFS_V3 is not set
-+CONFIG_ROOT_NFS=y
-+# CONFIG_NFSD is not set
-+# CONFIG_NFSD_V3 is not set
-+# CONFIG_NFSD_TCP is not set
-+CONFIG_SUNRPC=y
-+CONFIG_LOCKD=y
-+# CONFIG_SMB_FS is not set
-+# CONFIG_NCP_FS is not set
-+# CONFIG_NCPFS_PACKET_SIGNING is not set
-+# CONFIG_NCPFS_IOCTL_LOCKING is not set
-+# CONFIG_NCPFS_STRONG is not set
-+# CONFIG_NCPFS_NFS_NS is not set
-+# CONFIG_NCPFS_OS2_NS is not set
-+# CONFIG_NCPFS_SMALLDOS is not set
-+# CONFIG_NCPFS_NLS is not set
-+# CONFIG_NCPFS_EXTRAS is not set
-+# CONFIG_ZISOFS_FS is not set
-+
-+#
-+# Partition Types
-+#
-+# CONFIG_PARTITION_ADVANCED is not set
-+CONFIG_MSDOS_PARTITION=y
-+# CONFIG_SMB_NLS is not set
-+CONFIG_NLS=y
-+
-+#
-+# Native Language Support
-+#
-+CONFIG_NLS_DEFAULT="iso8859-1"
-+CONFIG_NLS_CODEPAGE_437=m
-+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_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
-+
-+#
-+# Console drivers
-+#
-+CONFIG_PC_KEYMAP=y
-+# CONFIG_VGA_CONSOLE is not set
-+
-+#
-+# Frame-buffer support
-+#
-+CONFIG_FB=y
-+CONFIG_DUMMY_CONSOLE=y
-+# CONFIG_FB_ACORN is not set
-+# CONFIG_FB_ANAKIN is not set
-+# CONFIG_FB_CLPS711X is not set
-+# CONFIG_FB_SA1100 is not set
-+# CONFIG_FB_DBMX1 is not set
-+CONFIG_FB_PXA=y
-+# CONFIG_FB_PXA_8BPP is not set
-+CONFIG_FB_PXA_16BPP=y
-+# CONFIG_FB_CYBER2000 is not set
-+# CONFIG_FB_VIRTUAL is not set
-+CONFIG_FBCON_ADVANCED=y
-+# CONFIG_FBCON_MFB is not set
-+# CONFIG_FBCON_CFB2 is not set
-+# CONFIG_FBCON_CFB4 is not set
-+# CONFIG_FBCON_CFB8 is not set
-+CONFIG_FBCON_CFB16=y
-+# CONFIG_FBCON_CFB24 is not set
-+# CONFIG_FBCON_CFB32 is not set
-+# CONFIG_FBCON_AFB is not set
-+# CONFIG_FBCON_ILBM is not set
-+# CONFIG_FBCON_IPLAN2P2 is not set
-+# CONFIG_FBCON_IPLAN2P4 is not set
-+# CONFIG_FBCON_IPLAN2P8 is not set
-+# CONFIG_FBCON_MAC is not set
-+# CONFIG_FBCON_VGA_PLANES is not set
-+# CONFIG_FBCON_VGA is not set
-+# CONFIG_FBCON_HGA is not set
-+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
-+# CONFIG_FBCON_FONTS is not set
-+CONFIG_FONT_8x8=y
-+CONFIG_FONT_8x16=y
-+
-+#
-+# Sound
-+#
-+CONFIG_SOUND=y
-+# CONFIG_SOUND_ALI5455 is not set
-+# CONFIG_SOUND_BT878 is not set
-+# CONFIG_SOUND_CMPCI is not set
-+# CONFIG_SOUND_EMU10K1 is not set
-+# CONFIG_MIDI_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_FORTE is not set
-+# CONFIG_SOUND_ICH is not set
-+# CONFIG_SOUND_RME96XX 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_MIDI_VIA82CXXX is not set
-+# CONFIG_SOUND_OSS is not set
-+# CONFIG_SOUND_VIDC is not set
-+# CONFIG_SOUND_WAVEARTIST is not set
-+CONFIG_SOUND_PXA_AC97=y
-+# CONFIG_SOUND_TVMIXER is not set
-+
-+#
-+# Multimedia Capabilities Port drivers
-+#
-+CONFIG_MCP=y
-+# CONFIG_MCP_SA1100 is not set
-+# CONFIG_MCP_UCB1200 is not set
-+# CONFIG_MCP_UCB1200_AUDIO is not set
-+# CONFIG_MCP_UCB1200_TS is not set
-+CONFIG_MCP_UCB1400_TS=y
-+
-+#
-+# USB support
-+#
-+CONFIG_USB=m
-+# CONFIG_USB_DEBUG is not set
-+CONFIG_USB_DEVICEFS=y
-+# CONFIG_USB_BANDWIDTH is not set
-+# CONFIG_USB_EHCI_HCD is not set
-+# CONFIG_USB_UHCI is not set
-+# CONFIG_USB_UHCI_ALT is not set
-+# CONFIG_USB_OHCI is not set
-+# CONFIG_USB_OHCI_SA1111 is not set
-+CONFIG_USB_SL811HS_ALT=m
-+CONFIG_USB_AUDIO=m
-+CONFIG_USB_EMI26=m
-+CONFIG_USB_MIDI=m
-+CONFIG_USB_STORAGE=m
-+CONFIG_USB_STORAGE_DEBUG=y
-+CONFIG_USB_STORAGE_DATAFAB=y
-+CONFIG_USB_STORAGE_FREECOM=y
-+# CONFIG_USB_STORAGE_ISD200 is not set
-+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
-+# CONFIG_USB_ACM is not set
-+CONFIG_USB_PRINTER=m
-+CONFIG_USB_HID=m
-+CONFIG_USB_HIDINPUT=y
-+CONFIG_USB_HIDDEV=y
-+CONFIG_USB_KBD=m
-+# CONFIG_USB_MOUSE is not set
-+# CONFIG_USB_AIPTEK is not set
-+# CONFIG_USB_WACOM is not set
-+# CONFIG_USB_KBTAB is not set
-+# CONFIG_USB_POWERMATE is not set
-+CONFIG_USB_DC2XX=m
-+CONFIG_USB_MDC800=m
-+CONFIG_USB_SCANNER=m
-+CONFIG_USB_MICROTEK=m
-+CONFIG_USB_HPUSBSCSI=m
-+CONFIG_USB_IBMCAM=m
-+CONFIG_USB_KONICAWC=m
-+CONFIG_USB_OV511=m
-+CONFIG_USB_PWC=m
-+CONFIG_USB_SE401=m
-+CONFIG_USB_STV680=m
-+CONFIG_USB_VICAM=m
-+# CONFIG_USB_DSBR is not set
-+# CONFIG_USB_DABUSB is not set
-+# CONFIG_USB_PEGASUS is not set
-+# CONFIG_USB_RTL8150 is not set
-+# CONFIG_USB_KAWETH is not set
-+# CONFIG_USB_CATC is not set
-+# CONFIG_USB_CDCETHER is not set
-+# CONFIG_USB_USBNET is not set
-+# CONFIG_USB_USS720 is not set
-+
-+#
-+# USB Serial Converter support
-+#
-+CONFIG_USB_SERIAL=m
-+# CONFIG_USB_SERIAL_DEBUG is not set
-+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 is not set
-+# CONFIG_USB_SERIAL_VISOR is not set
-+# CONFIG_USB_SERIAL_IPAQ is not set
-+# CONFIG_USB_SERIAL_IR is not set
-+# CONFIG_USB_SERIAL_EDGEPORT is not set
-+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
-+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-+# CONFIG_USB_SERIAL_KEYSPAN is not set
-+# CONFIG_USB_SERIAL_MCT_U232 is not set
-+# CONFIG_USB_SERIAL_KLSI is not set
-+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
-+# CONFIG_USB_SERIAL_PL2303 is not set
-+# CONFIG_USB_SERIAL_CYBERJACK is not set
-+# CONFIG_USB_SERIAL_XIRCOM is not set
-+# CONFIG_USB_SERIAL_OMNINET is not set
-+# CONFIG_USB_RIO500 is not set
-+# CONFIG_USB_AUERSWALD is not set
-+# CONFIG_USB_TIGL is not set
-+# CONFIG_USB_BRLVGER is not set
-+# CONFIG_USB_LCD is not set
-+
-+#
-+# Bluetooth support
-+#
-+CONFIG_BLUEZ=m
-+CONFIG_BLUEZ_L2CAP=m
-+CONFIG_BLUEZ_SCO=m
-+CONFIG_BLUEZ_RFCOMM=m
-+CONFIG_BLUEZ_RFCOMM_TTY=y
-+CONFIG_BLUEZ_BNEP=m
-+CONFIG_BLUEZ_BNEP_MC_FILTER=y
-+CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
-+CONFIG_BLUEZ_HIDP=m
-+
-+#
-+# Bluetooth device drivers
-+#
-+CONFIG_BLUEZ_HCIUSB=m
-+CONFIG_BLUEZ_HCIUSB_SCO=y
-+CONFIG_BLUEZ_HCIUART=m
-+CONFIG_BLUEZ_HCIUART_H4=y
-+CONFIG_BLUEZ_HCIUART_BCSP=y
-+# CONFIG_BLUEZ_HCIUART_BCSP_TXCRC is not set
-+CONFIG_BLUEZ_HCIBFUSB=m
-+CONFIG_BLUEZ_HCIDTL1=m
-+CONFIG_BLUEZ_HCIBT3C=m
-+CONFIG_BLUEZ_HCIBLUECARD=m
-+CONFIG_BLUEZ_HCIBTUART=m
-+CONFIG_BLUEZ_HCIVHCI=m
-+
-+#
-+# Kernel hacking
-+#
-+CONFIG_FRAME_POINTER=y
-+# CONFIG_DEBUG_USER is not set
-+# CONFIG_DEBUG_INFO is not set
-+# CONFIG_NO_PGT_CACHE is not set
-+# CONFIG_DEBUG_KERNEL is not set
-+# 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 is not set
-+# CONFIG_DEBUG_DC21285_PORT is not set
-+# CONFIG_DEBUG_CLPS711X_UART2 is not set
-+
-+#
-+# Library routines
-+#
-+CONFIG_ZLIB_INFLATE=y
-+CONFIG_ZLIB_DEFLATE=y
-+# CONFIG_REED_SOLOMON is not set
-+CONFIG_FW_LOADER=m
---- linux-2.4.21/arch/arm/mach-pxa/Makefile~pm
-+++ linux-2.4.21/arch/arm/mach-pxa/Makefile
-@@ -14,8 +14,11 @@
- obj-n :=
- obj- :=
-
--export-objs := generic.o irq.o dma.o sa1111.o \
-- usb_ctl.o usb_recv.o usb_send.o
-+export-objs := apm.o generic.o irq.o dma.o sa1111.o \
-+ usb_ctl.o usb_recv.o usb_send.o pm.o
-+
-+
-+export-objs += ramses.o
-
- # Common support (must be linked before board specific support)
- obj-y += generic.o irq.o dma.o
-@@ -27,6 +30,7 @@
- obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
- obj-$(CONFIG_ARCH_PXA_CERF) += cerf.o
- obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
-+obj-$(CONFIG_ARCH_RAMSES) += ramses.o
- obj-$(CONFIG_ARCH_TRIZEPS2) += trizeps2.o
-
- # Support for blinky lights
-@@ -48,6 +52,7 @@
-
- # Misc features
- obj-$(CONFIG_PM) += pm.o sleep.o
-+obj-$(CONFIG_APM) += apm.o
- obj-$(CONFIG_CPU_FREQ) += cpu-pxa.o
-
- include $(TOPDIR)/Rules.make
---- /dev/null
-+++ linux-2.4.21/arch/arm/mach-pxa/apm.c
-@@ -0,0 +1,491 @@
-+/*
-+ * bios-less APM driver for ARM Linux
-+ * Jamey Hicks <jamey@crl.dec.com>
-+ * adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com)
-+ *
-+ * APM 1.2 Reference:
-+ * Intel Corporation, Microsoft Corporation. Advanced Power Management
-+ * (APM) BIOS Interface Specification, Revision 1.2, February 1996.
-+ *
-+ * [This document is available from Microsoft at:
-+ * http://www.microsoft.com/hwdev/busbios/amp_12.htm]
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/poll.h>
-+#include <linux/types.h>
-+#include <linux/stddef.h>
-+#include <linux/timer.h>
-+#include <linux/fcntl.h>
-+#include <linux/slab.h>
-+#include <linux/stat.h>
-+#include <linux/proc_fs.h>
-+#include <linux/miscdevice.h>
-+#include <linux/apm_bios.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/pm.h>
-+#include <linux/kernel.h>
-+#include <linux/smp_lock.h>
-+
-+#include <asm/system.h>
-+#include <asm/hardware.h>
-+
-+#ifdef CONFIG_SA1100_H3XXX
-+#include <asm/arch/h3600_hal.h>
-+#endif
-+
-+#include "pm-common.c"
-+
-+struct apm_bios_info apm_bios_info = {
-+ /* this driver simulates APM version 1.2 */
-+ version: 0x102,
-+ flags: APM_32_BIT_SUPPORT
-+};
-+
-+/*
-+ * The apm_bios device is one of the misc char devices.
-+ * This is its minor number.
-+ */
-+#define APM_MINOR_DEV 134
-+
-+/*
-+ * See Documentation/Config.help for the configuration options.
-+ *
-+ * Various options can be changed at boot time as follows:
-+ * (We allow underscores for compatibility with the modules code)
-+ * apm=on/off enable/disable APM
-+ * [no-]power[-_]off power off on shutdown
-+ */
-+
-+/*
-+ * Maximum number of events stored
-+ */
-+#define APM_MAX_EVENTS 10
-+
-+/*
-+ * The per-file APM data
-+ */
-+struct apm_user {
-+ int magic;
-+ struct apm_user * next;
-+ int suser: 1;
-+ int suspend_wait: 1;
-+ int suspend_result;
-+ int suspends_pending;
-+ int standbys_pending;
-+ int suspends_read;
-+ int standbys_read;
-+ int event_head;
-+ int event_tail;
-+ apm_event_t events[APM_MAX_EVENTS];
-+};
-+
-+/*
-+ * The magic number in apm_user
-+ */
-+#define APM_BIOS_MAGIC 0x4101
-+
-+/*
-+ * Local variables
-+ */
-+
-+#ifdef CONFIG_APM_RTC_IS_GMT
-+#define clock_cmos_diff 0
-+#define got_clock_diff 1
-+#endif
-+static int apm_disabled;
-+#ifdef CONFIG_SMP
-+static int power_off;
-+#else
-+static int power_off = 1;
-+#endif
-+static int exit_kapmd;
-+static int kapmd_running;
-+
-+static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
-+static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
-+static struct apm_user * user_list = NULL;
-+
-+static char driver_version[] = "1.13"; /* no spaces */
-+
-+typedef struct lookup_t {
-+ int key;
-+ char * msg;
-+} lookup_t;
-+
-+static const lookup_t error_table[] = {
-+/* N/A { APM_SUCCESS, "Operation succeeded" }, */
-+ { APM_DISABLED, "Power management disabled" },
-+ { APM_CONNECTED, "Real mode interface already connected" },
-+ { APM_NOT_CONNECTED, "Interface not connected" },
-+ { APM_16_CONNECTED, "16 bit interface already connected" },
-+/* N/A { APM_16_UNSUPPORTED, "16 bit interface not supported" }, */
-+ { APM_32_CONNECTED, "32 bit interface already connected" },
-+ { APM_32_UNSUPPORTED, "32 bit interface not supported" },
-+ { APM_BAD_DEVICE, "Unrecognized device ID" },
-+ { APM_BAD_PARAM, "Parameter out of range" },
-+ { APM_NOT_ENGAGED, "Interface not engaged" },
-+ { APM_BAD_FUNCTION, "Function not supported" },
-+ { APM_RESUME_DISABLED, "Resume timer disabled" },
-+ { APM_BAD_STATE, "Unable to enter requested state" },
-+/* N/A { APM_NO_EVENTS, "No events pending" }, */
-+ { APM_NO_ERROR, "BIOS did not set a return code" },
-+ { APM_NOT_PRESENT, "No APM present" }
-+};
-+#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t))
-+
-+static int (*apm_get_power_status)(u_char *ac_line_status,
-+ u_char *battery_status,
-+ u_char *battery_flag,
-+ u_char *battery_percentage,
-+ u_short *battery_life) = 0;
-+
-+void apm_register_get_power_status( int (*fn)(u_char *ac_line_status,
-+ u_char *battery_status,
-+ u_char *battery_flag,
-+ u_char *battery_percentage,
-+ u_short *battery_life))
-+{
-+ apm_get_power_status = fn;
-+}
-+
-+static int queue_empty(struct apm_user *as)
-+{
-+ return as->event_head == as->event_tail;
-+}
-+
-+static apm_event_t get_queued_event(struct apm_user *as)
-+{
-+ as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
-+ return as->events[as->event_tail];
-+}
-+
-+static int check_apm_user(struct apm_user *as, const char *func)
-+{
-+ if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
-+ printk(KERN_ERR "apm: %s passed bad filp\n", func);
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos)
-+{
-+ struct apm_user * as;
-+ int i;
-+ apm_event_t event;
-+ DECLARE_WAITQUEUE(wait, current);
-+
-+ as = fp->private_data;
-+ if (check_apm_user(as, "read"))
-+ return -EIO;
-+ if (count < sizeof(apm_event_t))
-+ return -EINVAL;
-+ if (queue_empty(as)) {
-+ if (fp->f_flags & O_NONBLOCK)
-+ return -EAGAIN;
-+ add_wait_queue(&apm_waitqueue, &wait);
-+ printk("do_read: waiting\n");
-+repeat:
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ if (queue_empty(as) && !signal_pending(current)) {
-+ schedule();
-+ goto repeat;
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&apm_waitqueue, &wait);
-+ }
-+ i = count;
-+ while ((i >= sizeof(event)) && !queue_empty(as)) {
-+ event = get_queued_event(as);
-+ printk(" do_read: event=%d\n", event);
-+ if (copy_to_user(buf, &event, sizeof(event))) {
-+ if (i < count)
-+ break;
-+ return -EFAULT;
-+ }
-+ switch (event) {
-+ case APM_SYS_SUSPEND:
-+ case APM_USER_SUSPEND:
-+ as->suspends_read++;
-+ break;
-+
-+ case APM_SYS_STANDBY:
-+ case APM_USER_STANDBY:
-+ as->standbys_read++;
-+ break;
-+ }
-+ buf += sizeof(event);
-+ i -= sizeof(event);
-+ }
-+ if (i < count)
-+ return count - i;
-+ if (signal_pending(current))
-+ return -ERESTARTSYS;
-+ return 0;
-+}
-+
-+static unsigned int do_poll(struct file *fp, poll_table * wait)
-+{
-+ struct apm_user * as;
-+
-+ as = fp->private_data;
-+ if (check_apm_user(as, "poll"))
-+ return 0;
-+ poll_wait(fp, &apm_waitqueue, wait);
-+ if (!queue_empty(as))
-+ return POLLIN | POLLRDNORM;
-+ return 0;
-+}
-+
-+static int do_ioctl(struct inode * inode, struct file *filp,
-+ u_int cmd, u_long arg)
-+{
-+ struct apm_user * as;
-+
-+ as = filp->private_data;
-+ if (check_apm_user(as, "ioctl"))
-+ return -EIO;
-+ if (!as->suser)
-+ return -EPERM;
-+ switch (cmd) {
-+ case APM_IOC_SUSPEND:
-+ pm_suggest_suspend();
-+ break;
-+ default:
-+ printk("//hs %x\n", cmd);
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+static int do_release(struct inode * inode, struct file * filp)
-+{
-+ struct apm_user * as;
-+
-+ as = filp->private_data;
-+ if (check_apm_user(as, "release"))
-+ return 0;
-+ filp->private_data = NULL;
-+ lock_kernel();
-+ unlock_kernel();
-+ kfree(as);
-+ return 0;
-+}
-+
-+static int do_open(struct inode * inode, struct file * filp)
-+{
-+ struct apm_user * as;
-+
-+ as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL);
-+ if (as == NULL) {
-+ printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
-+ sizeof(*as));
-+ return -ENOMEM;
-+ }
-+ as->magic = APM_BIOS_MAGIC;
-+ as->event_tail = as->event_head = 0;
-+ as->suspends_pending = as->standbys_pending = 0;
-+ as->suspends_read = as->standbys_read = 0;
-+ /*
-+ * XXX - this is a tiny bit broken, when we consider BSD
-+ * process accounting. If the device is opened by root, we
-+ * instantly flag that we used superuser privs. Who knows,
-+ * we might close the device immediately without doing a
-+ * privileged operation -- cevans
-+ */
-+ as->suser = capable(CAP_SYS_ADMIN);
-+ as->next = user_list;
-+ user_list = as;
-+ filp->private_data = as;
-+ return 0;
-+}
-+
-+static int apm_get_info(char *buf, char **start, off_t fpos, int length)
-+{
-+ char * p;
-+ unsigned short dx;
-+ unsigned short error;
-+ unsigned char ac_line_status = 0xff;
-+ unsigned char battery_status = 0xff;
-+ unsigned char battery_flag = 0xff;
-+ unsigned char percentage = 0xff;
-+ int time_units = -1;
-+ char *units = "?";
-+
-+ p = buf;
-+
-+ if ( (smp_num_cpus == 1) &&
-+ apm_get_power_status &&
-+ !(error = apm_get_power_status(&ac_line_status,
-+ &battery_status, &battery_flag, &percentage, &dx))) {
-+ if (apm_bios_info.version > 0x100) {
-+ if (dx != 0xffff) {
-+ units = (dx & 0x8000) ? "min" : "sec";
-+ time_units = dx & 0x7fff;
-+ }
-+ }
-+ }
-+ /* Arguments, with symbols from linux/apm_bios.h. Information is
-+ from the Get Power Status (0x0a) call unless otherwise noted.
-+
-+ 0) Linux driver version (this will change if format changes)
-+ 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2.
-+ 2) APM flags from APM Installation Check (0x00):
-+ bit 0: APM_16_BIT_SUPPORT
-+ bit 1: APM_32_BIT_SUPPORT
-+ bit 2: APM_IDLE_SLOWS_CLOCK
-+ bit 3: APM_BIOS_DISABLED
-+ bit 4: APM_BIOS_DISENGAGED
-+ 3) AC line status
-+ 0x00: Off-line
-+ 0x01: On-line
-+ 0x02: On backup power (BIOS >= 1.1 only)
-+ 0xff: Unknown
-+ 4) Battery status
-+ 0x00: High
-+ 0x01: Low
-+ 0x02: Critical
-+ 0x03: Charging
-+ 0x04: Selected battery not present (BIOS >= 1.2 only)
-+ 0xff: Unknown
-+ 5) Battery flag
-+ bit 0: High
-+ bit 1: Low
-+ bit 2: Critical
-+ bit 3: Charging
-+ bit 7: No system battery
-+ 0xff: Unknown
-+ 6) Remaining battery life (percentage of charge):
-+ 0-100: valid
-+ -1: Unknown
-+ 7) Remaining battery life (time units):
-+ Number of remaining minutes or seconds
-+ -1: Unknown
-+ 8) min = minutes; sec = seconds */
-+
-+ p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
-+ driver_version,
-+ (apm_bios_info.version >> 8) & 0xff,
-+ apm_bios_info.version & 0xff,
-+ apm_bios_info.flags,
-+ ac_line_status,
-+ battery_status,
-+ battery_flag,
-+ percentage,
-+ time_units,
-+ units);
-+
-+ return p - buf;
-+}
-+
-+#ifndef MODULE
-+static int __init apm_setup(char *str)
-+{
-+ int invert;
-+
-+printk("//hs apm_setup\n");
-+ while ((str != NULL) && (*str != '\0')) {
-+ if (strncmp(str, "off", 3) == 0)
-+ apm_disabled = 1;
-+ if (strncmp(str, "on", 2) == 0)
-+ apm_disabled = 0;
-+ invert = (strncmp(str, "no-", 3) == 0);
-+ if (invert)
-+ str += 3;
-+ if ((strncmp(str, "power-off", 9) == 0) ||
-+ (strncmp(str, "power_off", 9) == 0))
-+ power_off = !invert;
-+ str = strchr(str, ',');
-+ if (str != NULL)
-+ str += strspn(str, ", \t");
-+ }
-+ return 1;
-+}
-+
-+__setup("apm=", apm_setup);
-+#endif
-+
-+static struct file_operations apm_bios_fops = {
-+ owner: THIS_MODULE,
-+ read: do_read,
-+ poll: do_poll,
-+ ioctl: do_ioctl,
-+ open: do_open,
-+ release: do_release,
-+};
-+
-+static struct miscdevice apm_device = {
-+ APM_MINOR_DEV,
-+ "apm_bios",
-+ &apm_bios_fops
-+};
-+
-+#define APM_INIT_ERROR_RETURN return -1
-+
-+/*
-+ * Just start the APM thread. We do NOT want to do APM BIOS
-+ * calls from anything but the APM thread, if for no other reason
-+ * than the fact that we don't trust the APM BIOS. This way,
-+ * most common APM BIOS problems that lead to protection errors
-+ * etc will have at least some level of being contained...
-+ *
-+ * In short, if something bad happens, at least we have a choice
-+ * of just killing the apm thread..
-+ */
-+static int __init apm_init(void)
-+{
-+ if (apm_bios_info.version == 0) {
-+ printk(KERN_INFO "apm: BIOS not found.\n");
-+ APM_INIT_ERROR_RETURN;
-+ }
-+ printk(KERN_INFO
-+ "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
-+ ((apm_bios_info.version >> 8) & 0xff),
-+ (apm_bios_info.version & 0xff),
-+ apm_bios_info.flags,
-+ driver_version);
-+
-+ if (apm_disabled) {
-+ printk(KERN_NOTICE "apm: disabled on user request.\n");
-+ APM_INIT_ERROR_RETURN;
-+ }
-+
-+ if (PM_IS_ACTIVE()) {
-+ printk(KERN_NOTICE "apm: overridden by ACPI.\n");
-+ APM_INIT_ERROR_RETURN;
-+ }
-+ pm_active = 1;
-+
-+ create_proc_info_entry("apm", 0, NULL, apm_get_info);
-+
-+ misc_register(&apm_device);
-+
-+ return 0;
-+}
-+
-+module_init(apm_init);
-+
-+#ifdef MODULE
-+static void __exit apm_exit(void)
-+{
-+ misc_deregister(&apm_device);
-+ remove_proc_entry("apm", NULL);
-+ if (power_off)
-+ pm_power_off = NULL;
-+ exit_kapmd = 1;
-+ while (kapmd_running)
-+ schedule();
-+ pm_active = 0;
-+}
-+
-+module_exit(apm_exit);
-+
-+MODULE_AUTHOR("Jamey Hicks, pulling bits from original by Stephen Rothwell");
-+MODULE_DESCRIPTION("A minimal emulation of APM");
-+MODULE_PARM(power_off, "i");
-+MODULE_PARM_DESC(power_off, "Enable power off");
-+#endif
---- linux-2.4.21/arch/arm/mach-pxa/cpu-pxa.c~ramses-corevolt
-+++ linux-2.4.21/arch/arm/mach-pxa/cpu-pxa.c
-@@ -39,7 +39,7 @@
-
- #include <asm/hardware.h>
-
--#define DEBUGGING 1
-+#define DEBUGGING 0
-
- #if DEBUGGING
- static unsigned int freq_debug = DEBUGGING;
-@@ -52,6 +52,7 @@
- unsigned int khz;
- unsigned int cccr;
- unsigned int pxbus;
-+ unsigned int corevolt;
- } pxa_freqs_t;
-
- #define CCLKCFG_TURBO 0x1
-@@ -79,23 +80,23 @@
-
- static pxa_freqs_t pxa250_valid_freqs[] =
- {
-- {199100, 0x141, 99}, /* mem= 99, run=199, turbo=199, PXbus= 99 */
-- {298600, 0x1c1, 99}, /* mem= 99, run=199, turbo=298, PXbus= 99 */
-- {398100, 0x241, 99}, /* mem= 99, run=199, turbo=398, PXbus= 99 */
-+ {199100, 0x141, 99, 115}, /* mem= 99, run=199, turbo=199, PXbus= 99 */
-+ {298600, 0x1c1, 99, 125}, /* mem= 99, run=199, turbo=298, PXbus= 99 */
-+ {398100, 0x241, 99, 135}, /* mem= 99, run=199, turbo=398, PXbus= 99 */
- {0,0}
- };
-
- static pxa_freqs_t pxa255_valid_freqs[] =
- {
-- { 99000, 0x121, 50}, /* mem= 99, run= 99, turbo= 99, PXbus= 50 */
--OC( {118000, 0x122, 59},)/* mem=118, run=118, turbo=118, PXbus= 59 OC'd mem */
-- {199100, 0x141, 99}, /* mem= 99, run=199, turbo=199, PXbus= 99 */
--OC( {236000, 0x142,118},)/* mem=118, run=236, turbo=236, PXbus=118 OC'd mem */
-- {298600, 0x1c1, 99}, /* mem= 99, run=199, turbo=298, PXbus= 99 */
--OC( {354000, 0x1c2,118},)/* mem=118, run=236, turbo=354, PXbus=118 OC'd mem */
-- {398099, 0x241, 99}, /* mem= 99, run=199, turbo=398, PXbus= 99 */
-- {398100, 0x161,196}, /* mem= 99, run=398, turbo=398, PXbus=196 */
--OC( {471000, 0x162,236},)/* mem=118, run=471, turbo=471, PXbus=236 OC'd mem/core/bus */
-+ { 99000, 0x121, 50, 105}, /* mem= 99, run= 99, turbo= 99, PXbus= 50 */
-+OC( {118000, 0x122, 59, 115},)/* mem=118, run=118, turbo=118, PXbus= 59 OC'd mem */
-+ {199100, 0x141, 99, 115}, /* mem= 99, run=199, turbo=199, PXbus= 99 */
-+OC( {236000, 0x142,118, 125},)/* mem=118, run=236, turbo=236, PXbus=118 OC'd mem */
-+ {298600, 0x1c1, 99, 125}, /* mem= 99, run=199, turbo=298, PXbus= 99 */
-+OC( {354000, 0x1c2,118, 135},)/* mem=118, run=236, turbo=354, PXbus=118 OC'd mem */
-+ {398099, 0x241, 99, 135}, /* mem= 99, run=199, turbo=398, PXbus= 99 */
-+ {398100, 0x161,196, 135}, /* mem= 99, run=398, turbo=398, PXbus=196 */
-+OC( {471000, 0x162,236, 150},)/* mem=118, run=471, turbo=471, PXbus=236 OC'd mem/core/bus */
- {0,0}
- };
-
-@@ -109,7 +110,7 @@
- int i=0;
- while( pxa_valid_freqs[i].khz)
- {
-- if( pxa_valid_freqs[i].khz == khz)
-+ if (pxa_valid_freqs[i].khz == khz)
- return &pxa_valid_freqs[i];
- i++;
- }
-@@ -141,14 +142,17 @@
- void *ramstart = phys_to_virt(0xa0000000);
- pxa_freqs_t *freq_info;
-
-- if( ! supported) return;
-+ if (! supported) return;
-
- freq_info = pxa_get_freq_info( khz);
-
-- if( ! freq_info) return;
-+ if (! freq_info) return;
-+
-+ if (freq_info->corevolt > ramses_corevolt_shadow)
-+ ramses_set_corevolt(freq_info->corevolt);
-
- CCCR = freq_info->cccr;
-- if( freq_debug)
-+ if (freq_debug)
- printk(KERN_INFO "Changing CPU frequency to %d Mhz (PXbus=%dMhz).\n",
- khz/1000, freq_info->pxbus);
-
-@@ -184,6 +188,9 @@
- : "r" (&MDREFR), "r" (CCLKCFG_TURBO|CCLKCFG_FCS), "r" (ramstart)
- : "r4", "r5");
- local_irq_restore(flags);
-+
-+ if (freq_info->corevolt < ramses_corevolt_shadow)
-+ ramses_set_corevolt(freq_info->corevolt);
- }
-
- static int pxa_init_freqs( void)
-@@ -191,19 +198,19 @@
- int cpu_ver;
- asm("mrc%? p15, 0, %0, c0, c0" : "=r" (cpu_ver));
-
-- if( (cpu_ver & 0xf) <= PXA250_REV_A1)
-+ if ((cpu_ver & 0xf) <= PXA250_REV_A1)
- {
- return 0;
- }
-
-- if( (cpu_ver & 0xf) <= PXA250_REV_B2)
-+ if ((cpu_ver & 0xf) <= PXA250_REV_B2)
- {
-- if( freq_debug) printk(KERN_INFO "Using PXA250 frequency points.\n");
-+ if (freq_debug) printk(KERN_INFO "Using PXA250 frequency points.\n");
- pxa_valid_freqs = pxa250_valid_freqs;
- }
- else /* C0 and above */
- {
-- if( freq_debug) printk(KERN_INFO "Using PXA255 frequency points.\n");
-+ if (freq_debug) printk(KERN_INFO "Using PXA255 frequency points.\n");
- pxa_valid_freqs = pxa255_valid_freqs;
- }
-
-@@ -212,24 +219,23 @@
-
- static int __init pxa_clk_init(void)
- {
-- if( pxa_init_freqs())
-+ if (pxa_init_freqs())
- {
-- if( freq_debug) printk(KERN_INFO "Registering CPU frequency change support.\n");
-+ if (freq_debug) printk(KERN_INFO "Registering CPU frequency change support.\n");
- supported = 1;
-
- cpufreq_init( get_clk_frequency_khz(0), PXA25x_MIN_FREQ, PXA25x_MAX_FREQ);
-- cpufreq_setfunctions(pxa_validate_speed, pxa_setspeed);
- }
- else
- {
-- if( freq_debug) printk(KERN_INFO "Disabling CPU frequency change support.\n");
-+ if (freq_debug) printk(KERN_INFO "Disabling CPU frequency change support.\n");
- /* Note that we have to initialize the generic code in order to
- * release a lock (cpufreq_sem). Any registration for freq changes
- * (e.g. lcd driver) will get blocked otherwise.
- */
- cpufreq_init( 0, 0, 0);
-- cpufreq_setfunctions(pxa_validate_speed, pxa_setspeed);
- }
-+ cpufreq_setfunctions(pxa_validate_speed, pxa_setspeed);
-
- return 0;
- }
---- linux-2.4.21/arch/arm/mach-pxa/generic.c~pm
-+++ linux-2.4.21/arch/arm/mach-pxa/generic.c
-@@ -28,6 +28,11 @@
- #include <asm/pgtable.h>
- #include <asm/mach/map.h>
-
-+#ifdef CONFIG_PXA_RTC_HACK
-+#include <asm/setup.h>
-+#include <linux/bootmem.h>
-+#endif
-+
- #include "generic.h"
-
- /*
-@@ -139,4 +144,41 @@
- {
- iotable_init(standard_io_desc);
- get_clk_frequency_khz( 1);
-+#ifdef CONFIG_PXA_RTC_HACK
-+ pxa_rtc_hack_init();
-+#endif
-+}
-+
-+
-+
-+#ifdef CONFIG_PXA_RTC_HACK
-+unsigned long *save_RCNR = 0;
-+
-+void pxa_rtc_hack_init(void)
-+{
-+ /*
-+ This has to be here since I guess the bootmem API is the
-+ right choice to allocate the memory during boot
-+ place. And we are sure that timer iqr is not already
-+ running.
-+ - Christian Pellegin <chri@infis.univ.trieste.it>
-+ */
-+ unsigned long pxa_rtc_hack = 0;
-+
-+ pxa_rtc_hack = meminfo.bank[meminfo.nr_banks-1].start +
-+ meminfo.bank[meminfo.nr_banks-1].size -
-+ PAGE_SIZE;
-+ reserve_bootmem(pxa_rtc_hack, PAGE_SIZE);
-+ printk("Reserved %ld bytes at %lx for RTC hack\n",
-+ PAGE_SIZE, pxa_rtc_hack);
-+ save_RCNR = (unsigned long *) phys_to_virt(pxa_rtc_hack);
-+ if ( (save_RCNR[0] ^ save_RCNR[1]) == 0xffffffff ) {
-+ printk("Restoring saved RCNR value to %ld (from %lx)\n",
-+ save_RCNR[0], (unsigned long) save_RCNR);
-+ RCNR = save_RCNR[0];
-+ }
-+ else {
-+ printk("No valid saved RCNR value found at %lx\n", (unsigned long) save_RCNR);
-+ }
- }
-+#endif /* CONFIG_PXA_RTC_HACK */
---- linux-2.4.21/arch/arm/mach-pxa/generic.h~pm
-+++ linux-2.4.21/arch/arm/mach-pxa/generic.h
-@@ -17,3 +17,7 @@
- mi->bank[__nr].size = (__size), \
- mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27)
-
-+#ifdef CONFIG_PXA_RTC_HACK
-+void pxa_rtc_hack_init(void);
-+extern unsigned long *save_RCNR;
-+#endif
---- /dev/null
-+++ linux-2.4.21/arch/arm/mach-pxa/pm-common.c
-@@ -0,0 +1,285 @@
-+/*
-+ * SA1100 Power Management Routines
-+ *
-+ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License.
-+ *
-+ * History:
-+ *
-+ * 2001-02-06: Cliff Brake Initial code
-+ *
-+ * 2001-02-25: Sukjae Cho <sjcho@east.isi.edu> &
-+ * Chester Kuo <chester@linux.org.tw>
-+ * Save more value for the resume function! Support
-+ * Bitsy/Assabet/Freebird board
-+ *
-+ * 2001-08-29: Nicolas Pitre <nico@cam.org>
-+ * Cleaned up, pushed platform dependent stuff
-+ * in the platform specific files.
-+ *
-+ * 2002-05-27: Nicolas Pitre Killed sleep.h and the kmalloced save array.
-+ * Storage is local on the stack now.
-+ */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/pm.h>
-+#include <linux/slab.h>
-+#include <linux/sched.h>
-+#include <linux/interrupt.h>
-+#include <linux/sysctl.h>
-+#include <linux/errno.h>
-+#include <linux/cpufreq.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/memory.h>
-+#include <asm/system.h>
-+#include <asm/leds.h>
-+#include <asm/uaccess.h>
-+
-+
-+#ifdef CONFIG_IPAQ_HANDHELD
-+#include <asm/arch-sa1100/h3600_asic.h>
-+#endif
-+
-+#define __KERNEL_SYSCALLS__
-+#include <linux/unistd.h>
-+
-+
-+
-+static char pm_helper_path[128] = "/etc/apm/apmd_proxy";
-+extern int exec_usermodehelper(char *path, char **argv, char **envp);
-+int debug_pm = 0;
-+static int pm_helper_veto = 0;
-+
-+static int
-+run_sbin_pm_helper( pm_request_t action )
-+{
-+ int i;
-+ char *argv[3], *envp[8];
-+
-+ if (!pm_helper_path[0])
-+ return 2;
-+
-+ if ( action != PM_SUSPEND && action != PM_RESUME )
-+ return 1;
-+
-+ /* Be root */
-+ current->uid = current->gid = 0;
-+
-+ i = 0;
-+ argv[i++] = pm_helper_path;
-+ argv[i++] = (action == PM_RESUME ? "resume" : "suspend");
-+
-+ if (action == PM_RESUME)
-+ argv[i++]="suspend";
-+
-+ argv[i] = 0;
-+
-+ i = 0;
-+ /* minimal command environment */
-+ envp[i++] = "HOME=/";
-+ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-+ envp[i] = 0;
-+
-+ /* other stuff we want to pass to /sbin/pm_helper */
-+ return exec_usermodehelper (argv [0], argv, envp);
-+}
-+
-+/*
-+ * If pm_suggest_suspend_hook is non-NULL, it is called by pm_suggest_suspend.
-+ */
-+int (*pm_suggest_suspend_hook)(int state);
-+EXPORT_SYMBOL(pm_suggest_suspend_hook);
-+
-+/*
-+ * If pm_use_sbin_pm_helper is nonzero, then run_sbin_pm_helper is called before suspend and after resume
-+ */
-+int pm_use_sbin_pm_helper = 1;
-+EXPORT_SYMBOL(pm_use_sbin_pm_helper);
-+
-+/*
-+ * If sysctl_pm_do_suspend_hook is non-NULL, it is called by sysctl_pm_do_suspend.
-+ * If it returns a true value, then pm_suspend is not called.
-+ * Use this to hook in apmd, for now.
-+ */
-+int (*pm_sysctl_suspend_hook)(int state);
-+EXPORT_SYMBOL(pm_sysctl_suspend_hook);
-+
-+int pm_suspend(void);
-+
-+int pm_suggest_suspend(void)
-+{
-+ int retval;
-+
-+ if (pm_suggest_suspend_hook) {
-+ if (pm_suggest_suspend_hook(PM_SUSPEND))
-+ return 0;
-+ }
-+
-+ if (pm_use_sbin_pm_helper) {
-+ pid_t pid;
-+ int res;
-+ int status = 0;
-+ unsigned int old_fs;
-+
-+ pid = kernel_thread ((int (*) (void *)) run_sbin_pm_helper, (void *) PM_SUSPEND, 0 );
-+ if ( pid < 0 )
-+ return pid;
-+
-+ if (debug_pm)
-+ printk(KERN_CRIT "%s:%d got pid=%d\n", __FUNCTION__, __LINE__, pid);
-+
-+ old_fs = get_fs ();
-+ set_fs (get_ds ());
-+ res = waitpid(pid, &status, __WCLONE);
-+ set_fs (old_fs);
-+
-+ if ( pid != res ) {
-+ if (debug_pm)
-+ printk(KERN_CRIT ": waitpid returned %d (exit_code=%d); not suspending\n", res, status );
-+
-+ return -1;
-+ }
-+
-+ /*if ( WIFEXITED(status) && ( WIFEXITSTATUS(status) != 0 )) {*/
-+ if (( status & 0xff7f ) != 0 ) {
-+ if (pm_helper_veto) {
-+ if (debug_pm)
-+ printk(KERN_CRIT "%s: SUSPEND WAS CANCELLED BY pm_helper (exit status %d)\n", __FUNCTION__, status >> 8);
-+ return -1;
-+ } else {
-+ if (debug_pm)
-+ printk(KERN_CRIT "%s: pm_helper returned %d, but going ahead anyway\n", __FUNCTION__, status >> 8);
-+ }
-+ }
-+ }
-+
-+ if (debug_pm)
-+ printk(KERN_CRIT "%s: REALLY SUSPENDING NOW\n", __FUNCTION__ );
-+
-+ if (pm_sysctl_suspend_hook) {
-+ if (pm_sysctl_suspend_hook(PM_SUSPEND))
-+ return 0;
-+ }
-+
-+ retval = pm_suspend();
-+ if (retval) {
-+ if (debug_pm)
-+ printk(KERN_CRIT "pm_suspend returned %d\n", retval);
-+ return retval;
-+ }
-+
-+ if (pm_use_sbin_pm_helper) {
-+ pid_t pid;
-+
-+ if (debug_pm)
-+ printk(KERN_CRIT "%s: running pm_helper for wakeup\n", __FUNCTION__);
-+
-+ pid = kernel_thread ((int (*) (void *)) run_sbin_pm_helper, (void *) PM_RESUME, 0 );
-+ if ( pid < 0 )
-+ return pid;
-+
-+ if ( pid != waitpid ( pid, NULL, __WCLONE ))
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+EXPORT_SYMBOL(pm_suggest_suspend);
-+
-+
-+/*
-+ * Send us to sleep.
-+ */
-+int pm_suspend(void)
-+{
-+ int retval;
-+
-+ retval = pm_send_all(PM_SUSPEND, (void *)3);
-+ if ( retval )
-+ return retval;
-+
-+#ifdef CONFIG_IPAQ_HANDHELD
-+ retval = h3600_power_management(PM_SUSPEND);
-+ if (retval) {
-+ pm_send_all(PM_RESUME, (void *)0);
-+ return retval;
-+ }
-+#endif
-+
-+ retval = pm_do_suspend();
-+
-+#ifdef CONFIG_IPAQ_HANDHELD
-+ /* Allow the power management routines to override resuming */
-+ while ( h3600_power_management(PM_RESUME) )
-+ retval = pm_do_suspend();
-+#endif
-+
-+ pm_send_all(PM_RESUME, (void *)0);
-+
-+ return retval;
-+}
-+EXPORT_SYMBOL(pm_suspend);
-+
-+#ifdef CONFIG_SYSCTL
-+/*
-+ * ARGH! ACPI people defined CTL_ACPI in linux/acpi.h rather than
-+ * linux/sysctl.h.
-+ *
-+ * This means our interface here won't survive long - it needs a new
-+ * interface. Quick hack to get this working - use sysctl id 9999.
-+ */
-+#warning ACPI broke the kernel, this interface needs to be fixed up.
-+#define CTL_ACPI 9999
-+#define ACPI_S1_SLP_TYP 19
-+
-+/*
-+ * Send us to sleep.
-+ */
-+static int sysctl_pm_do_suspend(void)
-+{
-+ int retval;
-+
-+ retval = pm_send_all(PM_SUSPEND, (void *)3);
-+
-+ if (retval == 0) {
-+ retval = pm_do_suspend();
-+
-+ pm_send_all(PM_RESUME, (void *)0);
-+ }
-+
-+ return retval;
-+}
-+
-+static struct ctl_table pm_table[] =
-+{
-+ {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_do_suspend},
-+ {2, "helper", pm_helper_path, sizeof(pm_helper_path), 0644, NULL, (proc_handler *)&proc_dostring},
-+ {3, "debug", &debug_pm, sizeof(debug_pm), 0644, NULL, (proc_handler *)&proc_dointvec},
-+ {4, "helper_veto", &pm_helper_veto, sizeof(pm_helper_veto), 0644, NULL, (proc_handler *)&proc_dointvec},
-+ {0}
-+};
-+
-+static struct ctl_table pm_dir_table[] =
-+{
-+ {CTL_ACPI, "pm", NULL, 0, 0555, pm_table},
-+ {0}
-+};
-+
-+/*
-+ * Initialize power interface
-+ */
-+static int __init pm_init(void)
-+{
-+ register_sysctl_table(pm_dir_table, 1);
-+ return 0;
-+}
-+
-+__initcall(pm_init);
-+
-+#endif
-+
---- linux-2.4.21/arch/arm/mach-pxa/pm.c~pm
-+++ linux-2.4.21/arch/arm/mach-pxa/pm.c
-@@ -19,6 +19,7 @@
- #include <linux/interrupt.h>
- #include <linux/sysctl.h>
- #include <linux/errno.h>
-+#include <linux/module.h>
-
- #include <asm/hardware.h>
- #include <asm/memory.h>
-@@ -82,7 +83,7 @@
-
- /*
- * Temporary solution. This won't be necessary once
-- * we move pxa support into the serial/* driver
-+ * we move pxa support into the serial driver
- * Save the FF UART
- */
- SAVE(FFIER);
-@@ -176,7 +177,7 @@
-
- /*
- * Temporary solution. This won't be necessary once
-- * we move pxa support into the serial/* driver.
-+ * we move pxa support into the serial driver.
- * Restore the FF UART.
- */
- RESTORE(FFMCR);
-@@ -209,6 +210,12 @@
- return virt_to_phys(sp);
- }
-
-+#ifndef CONFIG_APM
-+/*
-+ * This code is only needed if we don't compile in APM support.
-+ * If we compile APM support in, then this code is in pm-common.c
-+ */
-+
- #ifdef CONFIG_SYSCTL
- /*
- * ARGH! ACPI people defined CTL_ACPI in linux/acpi.h rather than
-@@ -263,3 +270,6 @@
- __initcall(pm_init);
-
- #endif
-+#endif
-+
-+EXPORT_SYMBOL(pm_do_suspend);
---- linux-2.4.21/arch/arm/mach-pxa/pxa_usb.h~pxa-usb
-+++ linux-2.4.21/arch/arm/mach-pxa/pxa_usb.h
-@@ -39,6 +39,7 @@
- int pxa_usb_xmitter_avail( void );
- int pxa_usb_send(char *buf, int len, usb_callback_t callback);
- void sa110a_usb_send_reset(void);
-+void pxa_usb_send_reset(void);
-
- /* in usb_recev.c */
- int pxa_usb_recv(char *buf, int len, usb_callback_t callback);
---- /dev/null
-+++ linux-2.4.21/arch/arm/mach-pxa/ramses.c
-@@ -0,0 +1,844 @@
-+/*
-+ * linux/arch/arm/mach-pxa/ramses.c
-+ *
-+ * 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.
-+ *
-+ * Copyright (c) 2002,2003,2004 by M&N Logistik-Lösungen Online GmbH
-+ * written by Holger Schurig
-+ *
-+ * 2001-09-13: Cliff Brake <cbrake@accelent.com>
-+ * Initial code
-+ *
-+ * 2002-10-09: adaptions to ramses
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/interrupt.h>
-+#include <linux/sched.h>
-+#include <linux/ioport.h>
-+#include <linux/pm.h>
-+#include <linux/delay.h>
-+#ifdef CONFIG_APM
-+#include <linux/apm_bios.h>
-+#endif
-+#define USE_UCB
-+//#define PFI_LED
-+#define PFI_TURNOFF
-+
-+#include <asm/types.h>
-+#include <asm/setup.h>
-+#include <asm/memory.h>
-+#include <asm/mach-types.h>
-+#include <asm/hardware.h>
-+#include <asm/irq.h>
-+
-+#include <asm/mach/arch.h>
-+#include <asm/mach/map.h>
-+#include <asm/mach/irq.h>
-+#include <asm/arch/irq.h>
-+#include <asm/arch-pxa/pxa-regs.h>
-+
-+#ifdef USE_UCB
-+#include "../drivers/misc/ucb1x00.h"
-+#endif
-+
-+#include "generic.h"
-+
-+
-+/* shadow registers for write only registers */
-+u16 ramses_control_shadow =
-+ RAMSES_CONTROL_LED_BLUE_ +
-+ RAMSES_CONTROL_LED_ORANGE_ +
-+ RAMSES_CONTROL_SCANNER_WAKE_ +
-+ RAMSES_CONTROL_SCANNER_TRIG_;
-+
-+/* various flags the change the behavior of the kernel */
-+unsigned int ramses_flags =
-+ RAMSES_FLAGS_KEY_SCAN +
-+ RAMSES_FLAGS_KEY_SUSPEND +
-+ RAMSES_FLAGS_KEY_OFF;
-+
-+
-+/******************************************************************/
-+/* Corevoltage settings */
-+/******************************************************************/
-+
-+int ramses_corevolt_shadow = 150;
-+
-+void ramses_set_corevolt(int volt)
-+{
-+ int val = 0;
-+ switch (volt) {
-+ case 150:
-+ val = 5;
-+ break;
-+ case 135:
-+ val = 8;
-+ break;
-+ case 125:
-+ val = 10;
-+ break;
-+ case 115:
-+ val = 12;
-+ break;
-+ case 105:
-+ val = 14;
-+ break;
-+ }
-+ if (val) {
-+ ramses_corevolt_shadow = volt;
-+ RAMSES_COREVOLT = val;
-+ RAMSES_CPLD_PERIPH_PWR |= CORE_VAR_EN;
-+ }
-+}
-+
-+
-+/******************************************************************/
-+/* LCD stuff */
-+/******************************************************************/
-+
-+u16 ramses_lcd_type;
-+
-+void ramses_lcd_power_on(void)
-+{
-+ //printk("--> ramses_lcd_power_on\n");
-+
-+ /* 1. VCC */
-+ RAMSES_CPLD_LCD |= RAMSES_LCD_VCC;
-+
-+ /* 2. Signal */
-+
-+ /* 3. the PWM */
-+ CKEN |= (CKEN0_PWM0 | CKEN1_PWM1);
-+
-+ /* 4. nDISPOFF (done at backlight_on time) */
-+ RAMSES_CPLD_LCD |= RAMSES_LCD_DISPOFF;
-+}
-+
-+
-+void ramses_lcd_power_off(void)
-+{
-+ //printk("--> ramses_lcd_power_off\n");
-+ if (RAMSES_CPLD_LCD & RAMSES_LCD_DISPOFF) {
-+ //printk("--> turn bl off first\n");
-+ ramses_lcd_backlight_off();
-+ }
-+
-+ /* 1. nDISPOFF (just to be sure) */
-+ RAMSES_CPLD_LCD &= ~RAMSES_LCD_DISPOFF;
-+
-+ // for Torisan: wait until all has been sent out
-+ if (ramses_lcd_type == 2) {
-+ int i;
-+ for (i=0; i<33; i++)
-+ udelay(1500);
-+ }
-+
-+ /* 2. disable the PWM */
-+ set_GPIO_mode(GPIO16_PWM0 | GPIO_OUT);
-+ set_GPIO_mode(GPIO17_PWM1 | GPIO_OUT);
-+ CKEN &= ~(CKEN0_PWM0 | CKEN1_PWM1);
-+
-+ /* 3. SIGNAL */
-+
-+ /* 4. VCC */
-+ RAMSES_CPLD_LCD &= ~RAMSES_LCD_VCC;
-+}
-+
-+
-+void ramses_lcd_backlight_on(void)
-+{
-+ int i;
-+
-+ //printk("--> ramses_lcd_backlight_on\n");
-+ if ((ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT) != 0)
-+ return;
-+ //printk(" state: %d\n", ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT);
-+
-+ set_GPIO_mode(GPIO17_PWM1 | GPIO_OUT);
-+
-+ /* 4. nDISPOFF */
-+ RAMSES_CPLD_LCD |= RAMSES_LCD_DISPOFF;
-+
-+ /* Backlight can be turned on at any time */
-+ RAMSES_LCD_BLIGHT_ON();
-+
-+ for (i=0; i<33; i++)
-+ udelay(1500);
-+ set_GPIO_mode(GPIO16_PWM0_MD);
-+ set_GPIO_mode(GPIO17_PWM1_MD);
-+}
-+
-+
-+void ramses_lcd_backlight_off(void)
-+{
-+ int i;
-+
-+ //printk("--> ramses_lcd_backlight_off\n");
-+ if ((ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT) == 0)
-+ return;
-+ //printk(" state: %d\n", ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT);
-+
-+ set_GPIO_mode(GPIO17_PWM1 | GPIO_OUT);
-+ for (i=0; i<100; i++)
-+ udelay(1500);
-+
-+ /* Backlight can be turned off at any time */
-+ RAMSES_LCD_BLIGHT_OFF();
-+ udelay(1500);
-+
-+ /* 1. nDISPOFF */
-+ if (ramses_lcd_type != 2)
-+ RAMSES_CPLD_LCD &= ~RAMSES_LCD_DISPOFF;
-+
-+ //set_GPIO_mode(GPIO16_PWM0 | GPIO_IN);
-+ //set_GPIO_mode(GPIO17_PWM1 | GPIO_IN);
-+}
-+
-+
-+void ramses_lcd_set_brightness(int b)
-+{
-+ if (b > 255) b = 255;
-+ if (b < 0) b = 0;
-+ PWM_PWDUTY1 = 510-(b<<1);
-+}
-+
-+
-+int ramses_lcd_get_brightness(void)
-+{
-+ return 255-(PWM_PWDUTY1 >> 1);
-+}
-+
-+
-+void ramses_lcd_set_contrast(int c)
-+{
-+ if (c > 255) c = 255;
-+ if (c < 0) c = 0;
-+ PWM_PWDUTY0 = 542-c;
-+}
-+
-+
-+int ramses_lcd_get_contrast(void)
-+{
-+ return 542-PWM_PWDUTY0;
-+}
-+
-+
-+void ramses_lcd_set_intensity(int i)
-+{
-+ //printk("--> ramses_lcd_set_intensity(%d)\n", i);
-+ if (i) {
-+ ramses_lcd_backlight_on();
-+ } else {
-+ ramses_lcd_backlight_off();
-+ }
-+}
-+
-+
-+int ramses_lcd_get_intensity(void)
-+{
-+ return ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT;
-+}
-+
-+
-+
-+
-+
-+/******************************************************************/
-+/* HDQ communication */
-+/******************************************************************/
-+
-+#define GPIO_HDQ 2
-+
-+#define HDQ_LO GPCR(GPIO_HDQ) = GPIO_bit(GPIO_HDQ)
-+#define HDQ_HI GPSR(GPIO_HDQ) = GPIO_bit(GPIO_HDQ)
-+#define HDQ_GET (GPLR(GPIO_HDQ) & (1 << GPIO_HDQ))
-+
-+#define MAXLOOPS 800
-+#define MAXTRIES 3
-+
-+
-+static void hdq_break(void)
-+{
-+ HDQ_LO;
-+ set_GPIO_mode(GPIO_HDQ | GPIO_OUT);
-+ udelay(220);
-+ HDQ_HI;
-+ udelay(50);
-+}
-+
-+
-+/**
-+ * Send data on the 1-bit wire.
-+ *
-+ * LSB first. Depending on the bit, do the low phase short or
-+ * small. The used timings in usec's are made so that our send
-+ * stuff has exactly the timing that the BQ2050 battery sends
-+ * us back.
-+*/
-+static void hdq_put_data(unsigned char cmd)
-+{
-+ unsigned char mask = 1;
-+
-+ HDQ_HI;
-+ set_GPIO_mode(GPIO_HDQ | GPIO_OUT);
-+
-+ while (1) {
-+ HDQ_LO;
-+ udelay(cmd & mask ? 37 : 115);
-+ HDQ_HI;
-+ udelay(cmd & mask ? 163 : 85);
-+ if (mask == 0x80) break;
-+ mask = mask << 1;
-+ }
-+ set_GPIO_mode(GPIO_HDQ | GPIO_IN);
-+}
-+
-+
-+/**
-+ * Receive data on the 1-bit wire.
-+ *
-+ * Little state-machine with two states (yuck) that measures the time
-+ * in the low-state. If it exceeds some value, then the bit was a 0,
-+ * otherwise it's a 1.
-+*/
-+static int hdq_get_data(void)
-+{
-+ enum { ST_WAITLOW, ST_LOW };
-+
-+ int i;
-+ int lastlow = 0;
-+ int state = ST_WAITLOW;
-+ unsigned char mask = 1;
-+ unsigned char d = 0;
-+
-+ for (i=0; i<MAXLOOPS; i++) {
-+ if (state==ST_WAITLOW) {
-+ if (HDQ_GET == 0) {
-+ lastlow = i;
-+ state = ST_LOW;
-+ }
-+ } else
-+ if (state == ST_LOW) {
-+ if (HDQ_GET) {
-+ // 34 must be changed if the udelay(2) changes!
-+ if (i-lastlow < 34) {
-+ d = d | mask;
-+ }
-+ if (mask == 0x80) break;
-+ mask = mask << 1;
-+ state = ST_WAITLOW;
-+ }
-+ }
-+ udelay(2);
-+ }
-+ if (i==MAXLOOPS) {
-+ //printk("no respone after %d\n", i);
-+ return -1;
-+ } else {
-+ //printk("done after %d: %d %x\n", i, d, d);
-+ return d;
-+ }
-+}
-+
-+
-+static int hdq_get_reg_once(unsigned char reg)
-+{
-+ int d = -1;
-+ int i;
-+
-+ reg &= 0x7f;
-+
-+ for (i=0; i<MAXTRIES; i++) {
-+ hdq_break();
-+ hdq_put_data(reg);
-+ d = hdq_get_data();
-+ if (d != -1)
-+ break;
-+ //printk("hdq_get_reg_once try again: %d\n", i);
-+ }
-+
-+ return d;
-+}
-+
-+/**
-+ * The HDQ protocol communication is so bad that we can't really
-+ * be sure that we got something usable. So we call hdq_get_reg_once()
-+ * twice and compare if we got the same value twice. If not, we try
-+ * again. And again, and again ... up to MAXTRIES times.
-+ */
-+int ramses_hdq_get_reg(unsigned char reg)
-+{
-+ int i,d1,d2;
-+
-+ d1 = hdq_get_reg_once(reg);
-+ for (i=0; i<MAXTRIES; i++) {
-+ d2 = hdq_get_reg_once(reg);
-+ if (d1 == d2)
-+ return d2;
-+ d1 = d2;
-+ }
-+ printk("no response from battery\n");
-+ return -1;
-+}
-+
-+
-+
-+/******************************************************************/
-+/* Power Management */
-+/******************************************************************/
-+
-+#ifdef CONFIG_PM
-+static int
-+ramses_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
-+{
-+ static int old_shadow;
-+ static int old_ctrl0;
-+ static int old_ctrl1;
-+ static int old_perval0;
-+ static int old_perval1;
-+ static int old_duty0;
-+ static int old_duty1;
-+
-+ switch (req) {
-+ case PM_SUSPEND:
-+ old_shadow = ramses_control_shadow;
-+ old_ctrl0 = PWM_CTRL0;
-+ old_ctrl1 = PWM_CTRL1;
-+ old_perval0 = PWM_PERVAL0;
-+ old_perval1 = PWM_PERVAL1;
-+ old_duty0 = PWM_PWDUTY0;
-+ old_duty1 = PWM_PWDUTY1;
-+
-+ // RAMSES_LED_BLUE_OFF();
-+ // RAMSES_LED_ORANGE_OFF();
-+ RAMSES_UART_OFF();
-+ // RAMSES_SCANNER_OFF();
-+ // RAMSES_USB_BUS_OFF();
-+ // printk("shadow: %08x -> %08x\n", old_shadow, ramses_control_shadow);
-+
-+ RAMSES_CPLD_PERIPH_PWR &= ~PER_PWR_EN;
-+ break;
-+
-+ case PM_RESUME:
-+ RAMSES_CPLD_PERIPH_PWR |= PER_PWR_EN;
-+ ramses_control_shadow = old_shadow;
-+ PWM_CTRL0 = old_ctrl0;
-+ PWM_CTRL1 = old_ctrl1;
-+ PWM_PERVAL0 = old_perval0;
-+ PWM_PERVAL1 = old_perval1;
-+ PWM_PWDUTY0 = old_duty0;
-+ PWM_PWDUTY1 = old_duty1;
-+
-+ break;
-+ }
-+ return 0;
-+}
-+
-+#endif
-+
-+
-+
-+static void pf_interrupt(int irq, void *dummy, struct pt_regs *fp)
-+{
-+#ifdef PFI_LED
-+ RAMSES_LED_BLUE_ON();
-+ RAMSES_LED_ORANGE_ON();
-+#endif
-+#ifdef PFI_TURNOFF
-+ // Make sure we can't be turned on by setting low onto the CPLD's columns
-+ RAMSES_CPLD_KB_COL_LOW = 0;
-+ RAMSES_CPLD_KB_COL_HIGH = 0;
-+
-+ // turn power off
-+ RAMSES_POWER_OFF();
-+
-+ // wait until VCC fades
-+ while (1) { }
-+#endif
-+}
-+
-+
-+void ramses_shut_off(void)
-+{
-+ // Make sure we can't be turned on by setting low onto the CPLD's columns
-+ RAMSES_CPLD_KB_COL_LOW = 0;
-+ RAMSES_CPLD_KB_COL_HIGH = 0;
-+ //printk("--> ramses_shut_off calling ramses_lcd_backlight_off\n");
-+ ramses_lcd_backlight_off();
-+ //printk("--> ramses_shut_off calling ramses_lcd_power_off\n");
-+ ramses_lcd_power_off();
-+
-+ // turn power off
-+ RAMSES_POWER_OFF();
-+
-+ // wait until voltage fades
-+ while (1) {}
-+}
-+
-+
-+
-+
-+#ifdef CONFIG_APM
-+static int ramses_get_power_status(u_char *ac_line_status,
-+ u_char *battery_status,
-+ u_char *battery_flag,
-+ u_char *battery_percentage,
-+ u_short *battery_life)
-+{
-+#ifdef USE_UCB
-+ int adc3;
-+ struct ucb1x00 *ucb = ucb1x00_get();
-+
-+ ucb1x00_adc_enable(ucb);
-+ adc3 = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD3, 0);
-+ ucb1x00_adc_disable(ucb);
-+
-+ /*
-+ * when charged: 0..430
-+ * when discharging: 0..340
-+ */
-+
-+#define CHG_LO 165
-+#define CHG_HI 420
-+#define OFF_LO 60
-+#define OFF_HI 350
-+ if ((RAMSES_CPLD_MISC_STATUS & RAMSES_CHG_STS) == 0) {
-+ // in Docking-Station
-+ if (adc3 > CHG_HI) adc3 = CHG_HI;
-+ if (adc3 < CHG_LO) adc3 = CHG_LO;
-+ adc3 -= CHG_LO;
-+ *battery_percentage = adc3 * 100 / (CHG_HI-CHG_LO);
-+ *ac_line_status = 0x01;
-+ } else {
-+ // offline
-+ if (adc3 > OFF_HI) adc3 = OFF_HI;
-+ if (adc3 < OFF_LO) adc3 = OFF_LO;
-+ adc3 -= OFF_LO;
-+ *battery_percentage = adc3 * 100 / (OFF_HI-OFF_LO);
-+ *ac_line_status = 0x00;
-+ }
-+
-+ if (*battery_percentage > 100)
-+ *battery_percentage = 100;
-+
-+ if (*ac_line_status) {
-+ *battery_status = 3; // charging
-+ *battery_flag = 1<<3;
-+ } else
-+ if (*battery_percentage >= 30) {
-+ *battery_status = 0; // high
-+ *battery_flag = 1<<0;
-+ } else
-+ if (*battery_percentage >= 15) {
-+ *battery_status = 1; // low
-+ *battery_flag = 1<<1;
-+ } else {
-+ *battery_status = 2; // critical
-+ *battery_flag = 1<<2;
-+ }
-+
-+ // assume 5.5 hours operation, 330 minutes
-+ *battery_life = (*battery_percentage * 330 / 100) | 0x8000;
-+#endif
-+
-+
-+#ifdef USE_HDQ
-+#error HDQ
-+ // SAE is something like mAh * 10
-+ int sae, sael;
-+
-+ sael = ramses_hdq_get_reg(HDQ_SAEL);
-+ sae = ramses_hdq_get_reg(HDQ_SAEH);
-+
-+ if (sae == -1 || sael == -1) {
-+ //printk("ramses: could not read HDQ_SAE\n");
-+ *ac_line_status = 0xff;
-+ *battery_status = 0xff;
-+ *battery_flag = 0xff;
-+ *battery_percentage = 0xff;
-+ *battery_life = -1;
-+ return 0;
-+ }
-+
-+ sae = (sae << 16) + sael;
-+ if (sae > 27000) {
-+ printk("ramses: capped HDQ_SAE from %d to 27000\n", sae);
-+ sae = 27000;
-+ }
-+
-+ if (sae < 4000) {
-+ *battery_status = 2; // critical
-+ *battery_flag = 1<<2;
-+ } else
-+ if (sae < 10000) {
-+ *battery_status = 1; // low
-+ *battery_flag = 1<<1;
-+ } else {
-+ *battery_status = 0; // high
-+ *battery_flag = 1<<0;
-+ }
-+
-+ if ((RAMSES_CPLD_MISC_STATUS & RAMSES_CHG_STS) == 0) {
-+ *battery_status = 3; // charging
-+ *battery_flag = 1<<3;
-+ *ac_line_status = 0x01; // online
-+ } else {
-+ *ac_line_status = 0x00; // offline
-+ }
-+
-+ *battery_percentage = sae / 270;
-+ *battery_life = (sae / 56) | 0x8000;
-+#endif
-+
-+
-+#if !defined(USE_UCB) && !defined(USE_HDQ)
-+#error NONE
-+ *ac_line_status = 0xff;
-+ *battery_status = 0xff;
-+ *battery_flag = 0xff;
-+ *battery_percentage = 0xff;
-+ *battery_life = -1;
-+#endif
-+
-+ return 0;
-+}
-+#endif
-+
-+
-+
-+
-+/******************************************************************/
-+/* Initialisation */
-+/******************************************************************/
-+
-+static struct map_desc ramses_io_desc[] __initdata = {
-+ /* virtual physical length domain r w c b */
-+ { RAMSES_IDE_BASE, RAMSES_IDE_PHYS, RAMSES_IDE_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
-+ { RAMSES_ETH_BASE, RAMSES_ETH_PHYS, RAMSES_ETH_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
-+ { RAMSES_COREVOLT_BASE, RAMSES_COREVOLT_PHYS, RAMSES_COREVOLT_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
-+ { RAMSES_CPLD_BASE, RAMSES_CPLD_PHYS, RAMSES_CPLD_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
-+ { RAMSES_CONTROL_BASE, RAMSES_CONTROL_PHYS, RAMSES_CONTROL_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
-+ LAST_DESC
-+};
-+
-+
-+
-+
-+
-+/*
-+ * Uncompressing Linux...... done, booting the kernel.
-+ * Linux version 2.4.19-rmk4-pxa1-mn ...
-+ * CPU: Intel XScale-PXA250 revision 4
-+ * Machine: Ramses
-+ * fixup_ramses()
-+ */
-+
-+static void __init
-+fixup_ramses(struct machine_desc *desc, struct param_struct *params,
-+ char **cmdline, struct meminfo *mi)
-+{
-+ SET_BANK (0, 0xa0000000,128*1024*1024);
-+ mi->nr_banks = 1;
-+}
-+
-+
-+
-+
-+/*
-+ * fixup_ramses()
-+ * ramses_map_io()
-+ */
-+
-+static void __init ramses_map_io(void)
-+{
-+ u16 smc_eeprom_read(long ioaddr, u16 location);
-+
-+ pxa_map_io();
-+ iotable_init(ramses_io_desc);
-+
-+#ifdef IPAQ
-+ // set power managament stuff
-+ PGSR0 = GPSRx_SleepValue;
-+ PGSR1 = GPSRy_SleepValue;
-+ PGSR2 = GPSRz_SleepValue;
-+ PWER = PWER_GPIO0 | PWER_RTC;
-+ PFER = PWER_GPIO0 | PWER_RTC;
-+ PRER = 0;
-+#endif
-+
-+ ramses_lcd_type = smc_eeprom_read(RAMSES_ETH_BASE+0x300, RAMSES_LCD_TYPE_OFFSET);
-+ // here we could make a special case about ramses_lcd_type == 0xffff
-+ ramses_flags |= (ramses_lcd_type & RAMSES_FLAGS_LCD_FBTURN);
-+}
-+
-+
-+
-+
-+/*
-+ * ramses_map_io()
-+ * Memory clock: 99.53MHz (*27)
-+ * Run Mode clock: 199.07MHz (*2)
-+ * Turbo Mode clock: 398.13MHz (*2.0, active) * On node 0 totalpages: 16384
-+ * zone(0): 32768 pages.
-+ * zone(1): 0 pages.
-+ * zone(2): 0 pages.
-+ * Kernel command line: root=/dev/nfsroot ...
-+ * ramses_init_irq()
-+ */
-+
-+static void __init ramses_init_irq(void)
-+{
-+ set_GPIO_IRQ_edge(21, GPIO_FALLING_EDGE); // UCB 1400
-+
-+ RAMSES_SCANNER_OFF();
-+ RAMSES_GSM_OFF();
-+ RAMSES_GSM_RESET_OFF();
-+ RAMSES_GSM_BOOT_OFF();
-+ pxa_init_irq();
-+}
-+
-+
-+
-+
-+/*
-+ * ramses_init_irq()
-+ * Console: colour dummy device 80x30
-+ * serial_console_init
-+ * serial_console_setup
-+ * Calibrating delay loop... 397.31 BogoMIPS
-+ * Memory: 128MB = 128MB total
-+ * Memory: 127872KB available (1355K code, 272K data, 112K init)
-+ * Dentry cache hash table entries: 16384 (order: 5, 131072 bytes)
-+ * Inode cache hash table entries: 8192 (order: 4, 65536 bytes)
-+ * Mount-cache hash table entries: 2048 (order: 2, 16384 bytes)
-+ * Buffer-cache hash table entries: 8192 (order: 3, 32768 bytes)
-+ * Page-cache hash table entries: 32768 (order: 5, 131072 bytes)
-+ * POSIX conformance testing by UNIFIX
-+ * Linux NET4.0 for Linux 2.4
-+ * Based upon Swansea University Computer Society NET3.039
-+ * Initializing RT netlink socket
-+ * ramses_init()
-+ */
-+
-+static int __init ramses_init(void)
-+{
-+ unsigned int irq_gpio_pin;
-+
-+ // Set IRQ for Touchpanel (via UCB 1400)
-+ irq_gpio_pin = IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ);
-+ set_GPIO_IRQ_edge(irq_gpio_pin, TOUCH_PANEL_IRQ_EDGE);
-+
-+ // Set IRQ for Power Fail Interrupt
-+ set_GPIO_IRQ_edge(1, GPIO_FALLING_EDGE);
-+ request_irq(IRQ_GPIO(1), pf_interrupt, 0, "PWR FAIL", NULL);
-+
-+ // Setup IRQ edge for Ethernet
-+ //set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(27), GPIO_RISING_EDGE);
-+ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(ETHERNET_IRQ), ETHERNET_IRQ_EDGE);
-+
-+ // Configure PWMs for LCD
-+ PWM_CTRL0 = 0;
-+ PWM_PERVAL0 = 512;
-+ PWM_PWDUTY0 = 440;
-+ PWM_CTRL1 = 0;
-+ PWM_PERVAL1 = 512;
-+ PWM_PWDUTY1 = 450;
-+
-+ // Request Memory Regions of core components
-+ request_mem_region(RAMSES_CONTROL_BASE, RAMSES_CONTROL_SIZE, "Ramses Control");
-+ request_mem_region(RAMSES_CPLD_BASE, RAMSES_CPLD_SIZE, "Ramses CPLD");
-+ request_mem_region(RAMSES_COREVOLT_BASE, RAMSES_COREVOLT_SIZE, "Ramses Corevolt");
-+
-+#ifdef CONFIG_PM
-+#ifdef PM_DEBUG
-+ pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ramses_pm_callback, "ramses");
-+#else
-+ pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ramses_pm_callback);
-+#endif
-+ //TODO PWER (PXA255: 3-25)
-+ //TODO PRER (PXA255: 3-26)
-+ //TODO PFER (PXA255: 3-27)
-+ //TODO PSSR (PXA255: 3-29)
-+ //TODO PGSR0..PGSR2 (PXA255: 3-32)
-+#endif
-+
-+#ifdef CONFIG_APM
-+ apm_register_get_power_status(ramses_get_power_status);
-+#endif
-+
-+ PCFR = PCFR_OPDE | PCFR_FS | PCFR_FP; // PXA255: 3-24
-+
-+ pm_power_off = ramses_shut_off;
-+
-+ return 0;
-+}
-+
-+__initcall(ramses_init);
-+
-+
-+
-+/*
-+ * ramses_init()
-+ * Using PXA255 frequency points.
-+ * Registering CPU frequency change support.
-+ * CPU clock: 398.131 MHz (99.000-400.000 MHz)
-+ * Starting kswapd
-+ * devfs: v1.12a (20020514) Richard Gooch (rgooch@atnf.csiro.au)
-+ * devfs: boot_options: 0x1
-+ * pty: 256 Unix98 ptys configured
-+ * pxa & ti16c754b serial driver
-+ * tts/0 at irq 14 is a PXA UART
-+ * tts/1 at irq 13 is a PXA UART
-+ * tts/2 at irq 12 is a PXA UART
-+ * tts/3 at irq 45 is a TI16750
-+ * tts/4 at irq 46 is a TI16750
-+ * tts/5 at irq 47 is a TI16750
-+ * tts/6 at irq 48 is a TI16750
-+ * LAN91C111: You shouldn't use auto-probing with insmod!
-+ * SMSC LAN91C111 Driver (v2.2), (Linux Kernel 2.4 + Support for Odd Byte) ...
-+ * eth0: SMC91C11xFD(rev:1) at 0xf0100300 IRQ:26 MEMSIZE ...
-+ * ac97_codec: AC97 Audio codec, id: 0x5053:0x4304 (Philips UCB1400)
-+ * NET4: Linux TCP/IP 1.0 for NET4.0
-+ * IP Protocols: ICMP, UDP, TCP
-+ * IP: routing cache hash table of 512 buckets, 4Kbytes
-+ * TCP: Hash tables configured (established 4096 bind 4096)
-+ * IP-Config: ...
-+ * NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
-+ * NetWinder Floating Point Emulator V0.95 (c) 1998-1999 Rebel.com
-+ * Looking up port of RPC 100003/2 on 192.168.233.66
-+ * Looking up port of RPC 100005/1 on 192.168.233.66
-+ * VFS: Mounted root (nfs filesystem).
-+ * Mounted devfs on /dev
-+ * Freeing init memory: 68K
-+ * INIT: version 2.84 booting
-+ */
-+
-+
-+
-+MACHINE_START(RAMSES, "Ramses")
-+ MAINTAINER("M&N Logistik-Lösungen Online GmbH")
-+ BOOT_MEM(0xa0000000, 0x40000000, 0xfc000000)
-+ BOOT_PARAMS(0xa0000100)
-+ FIXUP(fixup_ramses)
-+ MAPIO(ramses_map_io)
-+ INITIRQ(ramses_init_irq)
-+MACHINE_END
-+
-+EXPORT_SYMBOL(ramses_lcd_type);
-+EXPORT_SYMBOL(ramses_lcd_power_on);
-+EXPORT_SYMBOL(ramses_lcd_power_off);
-+EXPORT_SYMBOL(ramses_lcd_backlight_on);
-+EXPORT_SYMBOL(ramses_lcd_backlight_off);
-+EXPORT_SYMBOL(ramses_lcd_set_intensity);
-+EXPORT_SYMBOL(ramses_lcd_set_brightness);
-+EXPORT_SYMBOL(ramses_lcd_set_contrast);
-+EXPORT_SYMBOL(ramses_lcd_get_intensity);
-+EXPORT_SYMBOL(ramses_lcd_get_brightness);
-+EXPORT_SYMBOL(ramses_lcd_get_contrast);
-+EXPORT_SYMBOL(ramses_hdq_get_reg);
-+EXPORT_SYMBOL(ramses_set_corevolt);
-+EXPORT_SYMBOL(ramses_corevolt_shadow);
---- linux-2.4.21/arch/arm/mach-pxa/usb-char.c~pxa-usb
-+++ linux-2.4.21/arch/arm/mach-pxa/usb-char.c
-@@ -211,7 +211,6 @@
- static void twiddle_descriptors( void )
- {
- desc_t * pDesc = pxa_usb_get_descriptor_ptr();
-- string_desc_t * pString;
-
- pDesc->b.ep1.wMaxPacketSize = make_word_c( RX_PACKET_SIZE );
- pDesc->b.ep1.bmAttributes = USB_EP_BULK;
-@@ -220,6 +219,7 @@
-
- if ( machine_is_extenex1() ) {
- #ifdef CONFIG_SA1100_EXTENEX1
-+ string_desc_t * pString;
- pDesc->dev.idVendor = make_word_c( 0xC9F );
- pDesc->dev.idProduct = 1;
- pDesc->dev.bcdDevice = make_word_c( 0x0001 );
---- linux-2.4.21/arch/arm/mach-pxa/usb-eth.c~pxa-usbeth
-+++ linux-2.4.21/arch/arm/mach-pxa/usb-eth.c
-@@ -52,6 +52,7 @@
-
- #define ETHERNET_VENDOR_ID 0x49f
- #define ETHERNET_PRODUCT_ID 0x505A
-+#define ETHERNET_DEVICE_ID 0x0200
- #define MAX_PACKET 32768
- #define MIN(a, b) (((a) < (b)) ? (a) : (b))
-
-@@ -329,6 +330,7 @@
- pd->b.ep2.wMaxPacketSize = make_word( usb_wsize );
- pd->dev.idVendor = ETHERNET_VENDOR_ID;
- pd->dev.idProduct = ETHERNET_PRODUCT_ID;
-+ pd->dev.bcdDevice = ETHERNET_DEVICE_ID;
- pstr = pxa_usb_kmalloc_string_descriptor( "PXA USB NIC" );
- if ( pstr ) {
- pxa_usb_set_string_descriptor( 1, pstr );
---- linux-2.4.21/drivers/bluetooth/Config.in~bluetooth
-+++ linux-2.4.21/drivers/bluetooth/Config.in
-@@ -7,8 +7,7 @@
-
- dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB
- if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then
-- bool ' SCO (voice) support' CONFIG_BLUEZ_USB_SCO
-- bool ' USB zero packet support' CONFIG_BLUEZ_USB_ZERO_PACKET
-+ bool ' SCO (voice) support' CONFIG_BLUEZ_HCIUSB_SCO
- fi
-
- dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ
-@@ -18,6 +17,8 @@
- dep_bool ' Transmit CRC with every BCSP packet' CONFIG_BLUEZ_HCIUART_BCSP_TXCRC $CONFIG_BLUEZ_HCIUART_BCSP
- fi
-
-+dep_tristate 'HCI BlueFRITZ! USB driver' CONFIG_BLUEZ_HCIBFUSB $CONFIG_BLUEZ $CONFIG_USB
-+
- dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
-
- dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ
---- linux-2.4.21/drivers/bluetooth/Makefile~bluetooth
-+++ linux-2.4.21/drivers/bluetooth/Makefile
-@@ -14,6 +14,8 @@
- uart-$(CONFIG_BLUEZ_HCIUART_H4) += hci_h4.o
- uart-$(CONFIG_BLUEZ_HCIUART_BCSP) += hci_bcsp.o
-
-+obj-$(CONFIG_BLUEZ_HCIBFUSB) += bfusb.o
-+
- obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o
- obj-$(CONFIG_BLUEZ_HCIBT3C) += bt3c_cs.o
- obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o
---- /dev/null
-+++ linux-2.4.21/drivers/bluetooth/Makefile.lib
-@@ -0,0 +1,2 @@
-+obj-$(CONFIG_BLUEZ_HCIBFUSB) += firmware_class.o
-+obj-$(CONFIG_BLUEZ_HCIBT3C) += firmware_class.o
---- /dev/null
-+++ linux-2.4.21/drivers/bluetooth/bfusb.c
-@@ -0,0 +1,782 @@
-+/*
-+ *
-+ * AVM BlueFRITZ! USB driver
-+ *
-+ * Copyright (C) 2003 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 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/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <linux/sched.h>
-+#include <linux/errno.h>
-+#include <linux/skbuff.h>
-+
-+#include <linux/firmware.h>
-+#include <linux/usb.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+#ifndef CONFIG_BLUEZ_HCIBFUSB_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define VERSION "1.1"
-+
-+static struct usb_device_id bfusb_table[] = {
-+ /* AVM BlueFRITZ! USB */
-+ { USB_DEVICE(0x057c, 0x2200) },
-+
-+ { } /* Terminating entry */
-+};
-+
-+MODULE_DEVICE_TABLE(usb, bfusb_table);
-+
-+
-+#define BFUSB_MAX_BLOCK_SIZE 256
-+
-+#define BFUSB_BLOCK_TIMEOUT (HZ * 3)
-+
-+#define BFUSB_TX_PROCESS 1
-+#define BFUSB_TX_WAKEUP 2
-+
-+#define BFUSB_MAX_BULK_TX 1
-+#define BFUSB_MAX_BULK_RX 1
-+
-+struct bfusb {
-+ struct hci_dev hdev;
-+
-+ unsigned long state;
-+
-+ struct usb_device *udev;
-+
-+ unsigned int bulk_in_ep;
-+ unsigned int bulk_out_ep;
-+ unsigned int bulk_pkt_size;
-+
-+ rwlock_t lock;
-+
-+ struct sk_buff_head transmit_q;
-+
-+ struct sk_buff *reassembly;
-+
-+ atomic_t pending_tx;
-+ struct sk_buff_head pending_q;
-+ struct sk_buff_head completed_q;
-+};
-+
-+struct bfusb_scb {
-+ struct urb *urb;
-+};
-+
-+static void bfusb_tx_complete(struct urb *urb);
-+static void bfusb_rx_complete(struct urb *urb);
-+
-+static struct urb *bfusb_get_completed(struct bfusb *bfusb)
-+{
-+ struct sk_buff *skb;
-+ struct urb *urb = NULL;
-+
-+ BT_DBG("bfusb %p", bfusb);
-+
-+ skb = skb_dequeue(&bfusb->completed_q);
-+ if (skb) {
-+ urb = ((struct bfusb_scb *) skb->cb)->urb;
-+ kfree_skb(skb);
-+ }
-+
-+ return urb;
-+}
-+
-+static inline void bfusb_unlink_urbs(struct bfusb *bfusb)
-+{
-+ struct sk_buff *skb;
-+ struct urb *urb;
-+
-+ BT_DBG("bfusb %p", bfusb);
-+
-+ while ((skb = skb_dequeue(&bfusb->pending_q))) {
-+ urb = ((struct bfusb_scb *) skb->cb)->urb;
-+ usb_unlink_urb(urb);
-+ skb_queue_tail(&bfusb->completed_q, skb);
-+ }
-+
-+ while ((urb = bfusb_get_completed(bfusb)))
-+ usb_free_urb(urb);
-+}
-+
-+
-+static int bfusb_send_bulk(struct bfusb *bfusb, struct sk_buff *skb)
-+{
-+ struct bfusb_scb *scb = (void *) skb->cb;
-+ struct urb *urb = bfusb_get_completed(bfusb);
-+ int err, pipe;
-+
-+ BT_DBG("bfusb %p skb %p len %d", bfusb, skb, skb->len);
-+
-+ if (!urb && !(urb = usb_alloc_urb(0)))
-+ return -ENOMEM;
-+
-+ pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
-+
-+ FILL_BULK_URB(urb, bfusb->udev, pipe, skb->data, skb->len,
-+ bfusb_tx_complete, skb);
-+
-+ urb->transfer_flags = USB_QUEUE_BULK;
-+
-+ scb->urb = urb;
-+
-+ skb_queue_tail(&bfusb->pending_q, skb);
-+
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s bulk tx submit failed urb %p err %d",
-+ bfusb->hdev.name, urb, err);
-+ skb_unlink(skb);
-+ usb_free_urb(urb);
-+ } else
-+ atomic_inc(&bfusb->pending_tx);
-+
-+ return err;
-+}
-+
-+static void bfusb_tx_wakeup(struct bfusb *bfusb)
-+{
-+ struct sk_buff *skb;
-+
-+ BT_DBG("bfusb %p", bfusb);
-+
-+ if (test_and_set_bit(BFUSB_TX_PROCESS, &bfusb->state)) {
-+ set_bit(BFUSB_TX_WAKEUP, &bfusb->state);
-+ return;
-+ }
-+
-+ do {
-+ clear_bit(BFUSB_TX_WAKEUP, &bfusb->state);
-+
-+ while ((atomic_read(&bfusb->pending_tx) < BFUSB_MAX_BULK_TX) &&
-+ (skb = skb_dequeue(&bfusb->transmit_q))) {
-+ if (bfusb_send_bulk(bfusb, skb) < 0) {
-+ skb_queue_head(&bfusb->transmit_q, skb);
-+ break;
-+ }
-+ }
-+
-+ } while (test_bit(BFUSB_TX_WAKEUP, &bfusb->state));
-+
-+ clear_bit(BFUSB_TX_PROCESS, &bfusb->state);
-+}
-+
-+static void bfusb_tx_complete(struct urb *urb)
-+{
-+ struct sk_buff *skb = (struct sk_buff *) urb->context;
-+ struct bfusb *bfusb = (struct bfusb *) skb->dev;
-+
-+ BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
-+
-+ atomic_dec(&bfusb->pending_tx);
-+
-+ if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags))
-+ return;
-+
-+ if (!urb->status)
-+ bfusb->hdev.stat.byte_tx += skb->len;
-+ else
-+ bfusb->hdev.stat.err_tx++;
-+
-+ read_lock(&bfusb->lock);
-+
-+ skb_unlink(skb);
-+ skb_queue_tail(&bfusb->completed_q, skb);
-+
-+ bfusb_tx_wakeup(bfusb);
-+
-+ read_unlock(&bfusb->lock);
-+}
-+
-+
-+static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb)
-+{
-+ struct bfusb_scb *scb;
-+ struct sk_buff *skb;
-+ int err, pipe, size = HCI_MAX_FRAME_SIZE + 32;
-+
-+ BT_DBG("bfusb %p urb %p", bfusb, urb);
-+
-+ if (!urb && !(urb = usb_alloc_urb(0)))
-+ return -ENOMEM;
-+
-+ if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) {
-+ usb_free_urb(urb);
-+ return -ENOMEM;
-+ }
-+
-+ skb->dev = (void *) bfusb;
-+
-+ scb = (struct bfusb_scb *) skb->cb;
-+ scb->urb = urb;
-+
-+ pipe = usb_rcvbulkpipe(bfusb->udev, bfusb->bulk_in_ep);
-+
-+ FILL_BULK_URB(urb, bfusb->udev, pipe, skb->data, size,
-+ bfusb_rx_complete, skb);
-+
-+ urb->transfer_flags = USB_QUEUE_BULK;
-+
-+ skb_queue_tail(&bfusb->pending_q, skb);
-+
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s bulk rx submit failed urb %p err %d",
-+ bfusb->hdev.name, urb, err);
-+ skb_unlink(skb);
-+ kfree_skb(skb);
-+ usb_free_urb(urb);
-+ }
-+
-+ return err;
-+}
-+
-+static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *data, int len)
-+{
-+ BT_DBG("bfusb %p hdr 0x%02x data %p len %d", bfusb, hdr, data, len);
-+
-+ if (hdr & 0x10) {
-+ BT_ERR("%s error in block", bfusb->hdev.name);
-+ if (bfusb->reassembly)
-+ kfree_skb(bfusb->reassembly);
-+ bfusb->reassembly = NULL;
-+ return -EIO;
-+ }
-+
-+ if (hdr & 0x04) {
-+ struct sk_buff *skb;
-+ unsigned char pkt_type;
-+ int pkt_len = 0;
-+
-+ if (bfusb->reassembly) {
-+ BT_ERR("%s unexpected start block", bfusb->hdev.name);
-+ kfree_skb(bfusb->reassembly);
-+ bfusb->reassembly = NULL;
-+ }
-+
-+ if (len < 1) {
-+ BT_ERR("%s no packet type found", bfusb->hdev.name);
-+ return -EPROTO;
-+ }
-+
-+ pkt_type = *data++; len--;
-+
-+ switch (pkt_type) {
-+ case HCI_EVENT_PKT:
-+ if (len >= HCI_EVENT_HDR_SIZE) {
-+ hci_event_hdr *hdr = (hci_event_hdr *) data;
-+ pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
-+ } else {
-+ BT_ERR("%s event block is too short", bfusb->hdev.name);
-+ return -EILSEQ;
-+ }
-+ break;
-+
-+ case HCI_ACLDATA_PKT:
-+ if (len >= HCI_ACL_HDR_SIZE) {
-+ hci_acl_hdr *hdr = (hci_acl_hdr *) data;
-+ pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen);
-+ } else {
-+ BT_ERR("%s data block is too short", bfusb->hdev.name);
-+ return -EILSEQ;
-+ }
-+ break;
-+
-+ case HCI_SCODATA_PKT:
-+ if (len >= HCI_SCO_HDR_SIZE) {
-+ hci_sco_hdr *hdr = (hci_sco_hdr *) data;
-+ pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen;
-+ } else {
-+ BT_ERR("%s audio block is too short", bfusb->hdev.name);
-+ return -EILSEQ;
-+ }
-+ break;
-+ }
-+
-+ skb = bluez_skb_alloc(pkt_len, GFP_ATOMIC);
-+ if (!skb) {
-+ BT_ERR("%s no memory for the packet", bfusb->hdev.name);
-+ return -ENOMEM;
-+ }
-+
-+ skb->dev = (void *) &bfusb->hdev;
-+ skb->pkt_type = pkt_type;
-+
-+ bfusb->reassembly = skb;
-+ } else {
-+ if (!bfusb->reassembly) {
-+ BT_ERR("%s unexpected continuation block", bfusb->hdev.name);
-+ return -EIO;
-+ }
-+ }
-+
-+ if (len > 0)
-+ memcpy(skb_put(bfusb->reassembly, len), data, len);
-+
-+ if (hdr & 0x08) {
-+ hci_recv_frame(bfusb->reassembly);
-+ bfusb->reassembly = NULL;
-+ }
-+
-+ return 0;
-+}
-+
-+static void bfusb_rx_complete(struct urb *urb)
-+{
-+ struct sk_buff *skb = (struct sk_buff *) urb->context;
-+ struct bfusb *bfusb = (struct bfusb *) skb->dev;
-+ unsigned char *buf = urb->transfer_buffer;
-+ int count = urb->actual_length;
-+ int err, hdr, len;
-+
-+ BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
-+
-+ read_lock(&bfusb->lock);
-+
-+ if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags))
-+ goto unlock;
-+
-+ if (urb->status || !count)
-+ goto resubmit;
-+
-+ bfusb->hdev.stat.byte_rx += count;
-+
-+ skb_put(skb, count);
-+
-+ while (count) {
-+ hdr = buf[0] | (buf[1] << 8);
-+
-+ if (hdr & 0x4000) {
-+ len = 0;
-+ count -= 2;
-+ buf += 2;
-+ } else {
-+ len = (buf[2] == 0) ? 256 : buf[2];
-+ count -= 3;
-+ buf += 3;
-+ }
-+
-+ if (count < len) {
-+ BT_ERR("%s block extends over URB buffer ranges",
-+ bfusb->hdev.name);
-+ }
-+
-+ if ((hdr & 0xe1) == 0xc1)
-+ bfusb_recv_block(bfusb, hdr, buf, len);
-+
-+ count -= len;
-+ buf += len;
-+ }
-+
-+ skb_unlink(skb);
-+ kfree_skb(skb);
-+
-+ bfusb_rx_submit(bfusb, urb);
-+
-+ read_unlock(&bfusb->lock);
-+
-+ return;
-+
-+resubmit:
-+ urb->dev = bfusb->udev;
-+
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s bulk resubmit failed urb %p err %d",
-+ bfusb->hdev.name, urb, err);
-+ }
-+
-+unlock:
-+ read_unlock(&bfusb->lock);
-+}
-+
-+
-+static int bfusb_open(struct hci_dev *hdev)
-+{
-+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
-+ unsigned long flags;
-+ int i, err;
-+
-+ BT_DBG("hdev %p bfusb %p", hdev, bfusb);
-+
-+ if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
-+ return 0;
-+
-+ MOD_INC_USE_COUNT;
-+
-+ write_lock_irqsave(&bfusb->lock, flags);
-+
-+ err = bfusb_rx_submit(bfusb, NULL);
-+ if (!err) {
-+ for (i = 1; i < BFUSB_MAX_BULK_RX; i++)
-+ bfusb_rx_submit(bfusb, NULL);
-+ } else {
-+ clear_bit(HCI_RUNNING, &hdev->flags);
-+ MOD_DEC_USE_COUNT;
-+ }
-+
-+ write_unlock_irqrestore(&bfusb->lock, flags);
-+
-+ return err;
-+}
-+
-+static int bfusb_flush(struct hci_dev *hdev)
-+{
-+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
-+
-+ BT_DBG("hdev %p bfusb %p", hdev, bfusb);
-+
-+ skb_queue_purge(&bfusb->transmit_q);
-+
-+ return 0;
-+}
-+
-+static int bfusb_close(struct hci_dev *hdev)
-+{
-+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
-+ unsigned long flags;
-+
-+ BT_DBG("hdev %p bfusb %p", hdev, bfusb);
-+
-+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
-+ return 0;
-+
-+ write_lock_irqsave(&bfusb->lock, flags);
-+
-+ bfusb_unlink_urbs(bfusb);
-+ bfusb_flush(hdev);
-+
-+ write_unlock_irqrestore(&bfusb->lock, flags);
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ return 0;
-+}
-+
-+static int bfusb_send_frame(struct sk_buff *skb)
-+{
-+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-+ struct bfusb *bfusb;
-+ struct sk_buff *nskb;
-+ unsigned char buf[3];
-+ int sent = 0, size, count;
-+
-+ BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, skb->pkt_type, skb->len);
-+
-+ if (!hdev) {
-+ BT_ERR("Frame for unknown HCI device (hdev=NULL)");
-+ return -ENODEV;
-+ }
-+
-+ if (!test_bit(HCI_RUNNING, &hdev->flags))
-+ return -EBUSY;
-+
-+ bfusb = (struct bfusb *) hdev->driver_data;
-+
-+ switch (skb->pkt_type) {
-+ case HCI_COMMAND_PKT:
-+ hdev->stat.cmd_tx++;
-+ break;
-+ case HCI_ACLDATA_PKT:
-+ hdev->stat.acl_tx++;
-+ break;
-+ case HCI_SCODATA_PKT:
-+ hdev->stat.sco_tx++;
-+ break;
-+ };
-+
-+ /* Prepend skb with frame type */
-+ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
-+
-+ count = skb->len;
-+
-+ /* Max HCI frame size seems to be 1511 + 1 */
-+ if (!(nskb = bluez_skb_alloc(count + 32, GFP_ATOMIC))) {
-+ BT_ERR("Can't allocate memory for new packet");
-+ return -ENOMEM;
-+ }
-+
-+ nskb->dev = (void *) bfusb;
-+
-+ while (count) {
-+ size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE);
-+
-+ buf[0] = 0xc1 | ((sent == 0) ? 0x04 : 0) | ((count == size) ? 0x08 : 0);
-+ buf[1] = 0x00;
-+ buf[2] = (size == BFUSB_MAX_BLOCK_SIZE) ? 0 : size;
-+
-+ memcpy(skb_put(nskb, 3), buf, 3);
-+ memcpy(skb_put(nskb, size), skb->data + sent, size);
-+
-+ sent += size;
-+ count -= size;
-+ }
-+
-+ /* Don't send frame with multiple size of bulk max packet */
-+ if ((nskb->len % bfusb->bulk_pkt_size) == 0) {
-+ buf[0] = 0xdd;
-+ buf[1] = 0x00;
-+ memcpy(skb_put(nskb, 2), buf, 2);
-+ }
-+
-+ read_lock(&bfusb->lock);
-+
-+ skb_queue_tail(&bfusb->transmit_q, nskb);
-+ bfusb_tx_wakeup(bfusb);
-+
-+ read_unlock(&bfusb->lock);
-+
-+ kfree_skb(skb);
-+
-+ return 0;
-+}
-+
-+static void bfusb_destruct(struct hci_dev *hdev)
-+{
-+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
-+
-+ BT_DBG("hdev %p bfusb %p", hdev, bfusb);
-+
-+ kfree(bfusb);
-+}
-+
-+static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
-+{
-+ return -ENOIOCTLCMD;
-+}
-+
-+
-+static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int count)
-+{
-+ unsigned char *buf;
-+ int err, pipe, len, size, sent = 0;
-+
-+ BT_DBG("bfusb %p udev %p firmware %p count %d", bfusb, bfusb->udev, firmware, count);
-+
-+ BT_INFO("BlueFRITZ! USB loading firmware");
-+
-+ if (usb_set_configuration(bfusb->udev, 1) < 0) {
-+ BT_ERR("Can't change to loading configuration");
-+ return -EBUSY;
-+ }
-+
-+ buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC);
-+ if (!buf) {
-+ BT_ERR("Can't allocate memory chunk for firmware");
-+ return -ENOMEM;
-+ }
-+
-+ pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
-+
-+ while (count) {
-+ size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE + 3);
-+
-+ memcpy(buf, firmware + sent, size);
-+
-+ err = usb_bulk_msg(bfusb->udev, pipe, buf, size,
-+ &len, BFUSB_BLOCK_TIMEOUT);
-+
-+ if (err || (len != size)) {
-+ BT_ERR("Error in firmware loading");
-+ goto error;
-+ }
-+
-+ sent += size;
-+ count -= size;
-+ }
-+
-+ if ((err = usb_bulk_msg(bfusb->udev, pipe, NULL, 0,
-+ &len, BFUSB_BLOCK_TIMEOUT)) < 0) {
-+ BT_ERR("Error in null packet request");
-+ goto error;
-+ }
-+
-+ if ((err = usb_set_configuration(bfusb->udev, 2)) < 0) {
-+ BT_ERR("Can't change to running configuration");
-+ goto error;
-+ }
-+
-+ BT_INFO("BlueFRITZ! USB device ready");
-+
-+ kfree(buf);
-+ return 0;
-+
-+error:
-+ kfree(buf);
-+
-+ pipe = usb_sndctrlpipe(bfusb->udev, 0);
-+
-+ usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
-+ 0, 0, 0, NULL, 0, BFUSB_BLOCK_TIMEOUT);
-+
-+ return err;
-+}
-+
-+static void *bfusb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
-+{
-+ const struct firmware *firmware;
-+ char device[16];
-+ struct usb_interface *iface;
-+ struct usb_interface_descriptor *iface_desc;
-+ struct usb_endpoint_descriptor *bulk_out_ep;
-+ struct usb_endpoint_descriptor *bulk_in_ep;
-+ struct hci_dev *hdev;
-+ struct bfusb *bfusb;
-+
-+ BT_DBG("udev %p ifnum %d id %p", udev, ifnum, id);
-+
-+ /* Check number of endpoints */
-+ iface = &udev->actconfig->interface[0];
-+ iface_desc = &iface->altsetting[0];
-+
-+ if (iface_desc->bNumEndpoints < 2)
-+ return NULL;
-+
-+ bulk_out_ep = &iface_desc->endpoint[0];
-+ bulk_in_ep = &iface_desc->endpoint[1];
-+
-+ if (!bulk_out_ep || !bulk_in_ep) {
-+ BT_ERR("Bulk endpoints not found");
-+ goto done;
-+ }
-+
-+ /* Initialize control structure and load firmware */
-+ if (!(bfusb = kmalloc(sizeof(struct bfusb), GFP_KERNEL))) {
-+ BT_ERR("Can't allocate memory for control structure");
-+ goto done;
-+ }
-+
-+ memset(bfusb, 0, sizeof(struct bfusb));
-+
-+ bfusb->udev = udev;
-+ bfusb->bulk_in_ep = bulk_in_ep->bEndpointAddress;
-+ bfusb->bulk_out_ep = bulk_out_ep->bEndpointAddress;
-+ bfusb->bulk_pkt_size = bulk_out_ep->wMaxPacketSize;
-+
-+ bfusb->lock = RW_LOCK_UNLOCKED;
-+
-+ bfusb->reassembly = NULL;
-+
-+ skb_queue_head_init(&bfusb->transmit_q);
-+ skb_queue_head_init(&bfusb->pending_q);
-+ skb_queue_head_init(&bfusb->completed_q);
-+
-+ snprintf(device, sizeof(device), "bfusb%3.3d%3.3d", udev->bus->busnum, udev->devnum);
-+
-+ if (request_firmware(&firmware, "bfubase.frm", device) < 0) {
-+ BT_ERR("Firmware request failed");
-+ goto error;
-+ }
-+
-+ if (bfusb_load_firmware(bfusb, firmware->data, firmware->size) < 0) {
-+ BT_ERR("Firmware loading failed");
-+ goto release;
-+ }
-+
-+ release_firmware(firmware);
-+
-+ /* Initialize and register HCI device */
-+ hdev = &bfusb->hdev;
-+
-+ hdev->type = HCI_USB;
-+ hdev->driver_data = bfusb;
-+
-+ hdev->open = bfusb_open;
-+ hdev->close = bfusb_close;
-+ hdev->flush = bfusb_flush;
-+ hdev->send = bfusb_send_frame;
-+ hdev->destruct = bfusb_destruct;
-+ hdev->ioctl = bfusb_ioctl;
-+
-+ if (hci_register_dev(hdev) < 0) {
-+ BT_ERR("Can't register HCI device");
-+ goto error;
-+ }
-+
-+ return bfusb;
-+
-+release:
-+ release_firmware(firmware);
-+
-+error:
-+ kfree(bfusb);
-+
-+done:
-+ return NULL;
-+}
-+
-+static void bfusb_disconnect(struct usb_device *udev, void *ptr)
-+{
-+ struct bfusb *bfusb = (struct bfusb *) ptr;
-+ struct hci_dev *hdev = &bfusb->hdev;
-+
-+ BT_DBG("udev %p ptr %p", udev, ptr);
-+
-+ if (!hdev)
-+ return;
-+
-+ bfusb_close(hdev);
-+
-+ if (hci_unregister_dev(hdev) < 0)
-+ BT_ERR("Can't unregister HCI device %s", hdev->name);
-+}
-+
-+static struct usb_driver bfusb_driver = {
-+ name: "bfusb",
-+ probe: bfusb_probe,
-+ disconnect: bfusb_disconnect,
-+ id_table: bfusb_table,
-+};
-+
-+static int __init bfusb_init(void)
-+{
-+ int err;
-+
-+ BT_INFO("BlueFRITZ! USB driver ver %s", VERSION);
-+ BT_INFO("Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org>");
-+
-+ if ((err = usb_register(&bfusb_driver)) < 0)
-+ BT_ERR("Failed to register BlueFRITZ! USB driver");
-+
-+ return err;
-+}
-+
-+static void __exit bfusb_cleanup(void)
-+{
-+ usb_deregister(&bfusb_driver);
-+}
-+
-+module_init(bfusb_init);
-+module_exit(bfusb_cleanup);
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION);
-+MODULE_LICENSE("GPL");
---- linux-2.4.21/drivers/bluetooth/bluecard_cs.c~bluetooth
-+++ linux-2.4.21/drivers/bluetooth/bluecard_cs.c
-@@ -803,6 +803,9 @@
- unsigned int iobase = info->link.io.BasePort1;
- struct hci_dev *hdev = &(info->hdev);
-
-+ if (info->link.state & DEV_CONFIG_PENDING)
-+ return -ENODEV;
-+
- bluecard_hci_close(hdev);
-
- clear_bit(CARD_READY, &(info->hw_state));
---- linux-2.4.21/drivers/bluetooth/bt3c_cs.c~bluetooth
-+++ linux-2.4.21/drivers/bluetooth/bt3c_cs.c
-@@ -24,8 +24,6 @@
- #include <linux/config.h>
- #include <linux/module.h>
-
--#define __KERNEL_SYSCALLS__
--
- #include <linux/kernel.h>
- #include <linux/kmod.h>
- #include <linux/init.h>
-@@ -48,6 +46,8 @@
- #include <asm/bitops.h>
- #include <asm/io.h>
-
-+#include <linux/firmware.h>
-+
- #include <pcmcia/version.h>
- #include <pcmcia/cs_types.h>
- #include <pcmcia/cs.h>
-@@ -485,78 +485,101 @@
-
-
-
--/* ======================== User mode firmware loader ======================== */
-+/* ======================== Card services HCI interaction ======================== */
-
-
--#define FW_LOADER "/sbin/bluefw"
--static int errno;
-+static int bt3c_load_firmware(bt3c_info_t *info, unsigned char *firmware, int count)
-+{
-+ char *ptr = (char *) firmware;
-+ char b[9];
-+ unsigned int iobase, size, addr, fcs, tmp;
-+ int i, err = 0;
-
-+ iobase = info->link.io.BasePort1;
-
--static int bt3c_fw_loader_exec(void *dev)
--{
-- char *argv[] = { FW_LOADER, "pccard", dev, NULL };
-- char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
-- int err;
-+ /* Reset */
-
-- err = exec_usermodehelper(FW_LOADER, argv, envp);
-- if (err)
-- printk(KERN_WARNING "bt3c_cs: Failed to exec \"%s pccard %s\".\n", FW_LOADER, (char *)dev);
-+ bt3c_io_write(iobase, 0x8040, 0x0404);
-+ bt3c_io_write(iobase, 0x8040, 0x0400);
-
-- return err;
--}
-+ udelay(1);
-
-+ bt3c_io_write(iobase, 0x8040, 0x0404);
-
--static int bt3c_firmware_load(bt3c_info_t *info)
--{
-- sigset_t tmpsig;
-- char dev[16];
-- pid_t pid;
-- int result;
-+ udelay(17);
-
-- /* Check if root fs is mounted */
-- if (!current->fs->root) {
-- printk(KERN_WARNING "bt3c_cs: Root filesystem is not mounted.\n");
-- return -EPERM;
-- }
-+ /* Load */
-
-- sprintf(dev, "%04x", info->link.io.BasePort1);
-+ while (count) {
-+ if (ptr[0] != 'S') {
-+ printk(KERN_WARNING "bt3c_cs: Bad address in firmware.\n");
-+ err = -EFAULT;
-+ goto error;
-+ }
-
-- pid = kernel_thread(bt3c_fw_loader_exec, (void *)dev, 0);
-- if (pid < 0) {
-- printk(KERN_WARNING "bt3c_cs: Forking of kernel thread failed (errno=%d).\n", -pid);
-- return pid;
-- }
-+ memset(b, 0, sizeof(b));
-+ memcpy(b, ptr + 2, 2);
-+ size = simple_strtol(b, NULL, 16);
-
-- /* Block signals, everything but SIGKILL/SIGSTOP */
-- spin_lock_irq(&current->sigmask_lock);
-- tmpsig = current->blocked;
-- siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
-- recalc_sigpending(current);
-- spin_unlock_irq(&current->sigmask_lock);
-+ memset(b, 0, sizeof(b));
-+ memcpy(b, ptr + 4, 8);
-+ addr = simple_strtol(b, NULL, 16);
-
-- result = waitpid(pid, NULL, __WCLONE);
-+ memset(b, 0, sizeof(b));
-+ memcpy(b, ptr + (size * 2) + 2, 2);
-+ fcs = simple_strtol(b, NULL, 16);
-
-- /* Allow signals again */
-- spin_lock_irq(&current->sigmask_lock);
-- current->blocked = tmpsig;
-- recalc_sigpending(current);
-- spin_unlock_irq(&current->sigmask_lock);
-+ memset(b, 0, sizeof(b));
-+ for (tmp = 0, i = 0; i < size; i++) {
-+ memcpy(b, ptr + (i * 2) + 2, 2);
-+ tmp += simple_strtol(b, NULL, 16);
-+ }
-
-- if (result != pid) {
-- printk(KERN_WARNING "bt3c_cs: Waiting for pid %d failed (errno=%d).\n", pid, -result);
-- return -result;
-+ if (((tmp + fcs) & 0xff) != 0xff) {
-+ printk(KERN_WARNING "bt3c_cs: Checksum error in firmware.\n");
-+ err = -EILSEQ;
-+ goto error;
-+ }
-+
-+ if (ptr[1] == '3') {
-+ bt3c_address(iobase, addr);
-+
-+ memset(b, 0, sizeof(b));
-+ for (i = 0; i < (size - 4) / 2; i++) {
-+ memcpy(b, ptr + (i * 4) + 12, 4);
-+ tmp = simple_strtol(b, NULL, 16);
-+ bt3c_put(iobase, tmp);
-+ }
-+ }
-+
-+ ptr += (size * 2) + 6;
-+ count -= (size * 2) + 6;
- }
-
-- return 0;
--}
-+ udelay(17);
-
-+ /* Boot */
-
-+ bt3c_address(iobase, 0x3000);
-+ outb(inb(iobase + CONTROL) | 0x40, iobase + CONTROL);
-
--/* ======================== Card services HCI interaction ======================== */
-+error:
-+ udelay(17);
-+
-+ /* Clear */
-+
-+ bt3c_io_write(iobase, 0x7006, 0x0000);
-+ bt3c_io_write(iobase, 0x7005, 0x0000);
-+ bt3c_io_write(iobase, 0x7001, 0x0000);
-+
-+ return err;
-+}
-
-
- int bt3c_open(bt3c_info_t *info)
- {
-+ const struct firmware *firmware;
-+ char device[16];
- struct hci_dev *hdev;
- int err;
-
-@@ -570,8 +593,22 @@
-
- /* Load firmware */
-
-- if ((err = bt3c_firmware_load(info)) < 0)
-+ snprintf(device, sizeof(device), "bt3c%4.4x", info->link.io.BasePort1);
-+
-+ err = request_firmware(&firmware, "BT3CPCC.bin", device);
-+ if (err < 0) {
-+ printk(KERN_WARNING "bt3c_cs: Firmware request failed.\n");
- return err;
-+ }
-+
-+ err = bt3c_load_firmware(info, firmware->data, firmware->size);
-+
-+ release_firmware(firmware);
-+
-+ if (err < 0) {
-+ printk(KERN_WARNING "bt3c_cs: Firmware loading failed.\n");
-+ return err;
-+ }
-
- /* Timeout before it is safe to send the first HCI packet */
-
-@@ -606,6 +643,9 @@
- {
- struct hci_dev *hdev = &(info->hdev);
-
-+ if (info->link.state & DEV_CONFIG_PENDING)
-+ return -ENODEV;
-+
- bt3c_hci_close(hdev);
-
- if (hci_unregister_dev(hdev) < 0)
---- linux-2.4.21/drivers/bluetooth/btuart_cs.c~bluetooth
-+++ linux-2.4.21/drivers/bluetooth/btuart_cs.c
-@@ -556,6 +556,9 @@
- unsigned int iobase = info->link.io.BasePort1;
- struct hci_dev *hdev = &(info->hdev);
-
-+ if (info->link.state & DEV_CONFIG_PENDING)
-+ return -ENODEV;
-+
- btuart_hci_close(hdev);
-
- spin_lock_irqsave(&(info->lock), flags);
---- linux-2.4.21/drivers/bluetooth/dtl1_cs.c~bluetooth
-+++ linux-2.4.21/drivers/bluetooth/dtl1_cs.c
-@@ -535,6 +535,9 @@
- unsigned int iobase = info->link.io.BasePort1;
- struct hci_dev *hdev = &(info->hdev);
-
-+ if (info->link.state & DEV_CONFIG_PENDING)
-+ return -ENODEV;
-+
- dtl1_hci_close(hdev);
-
- spin_lock_irqsave(&(info->lock), flags);
---- linux-2.4.21/drivers/bluetooth/hci_bcsp.c~bluetooth
-+++ linux-2.4.21/drivers/bluetooth/hci_bcsp.c
-@@ -34,7 +34,6 @@
- #include <linux/module.h>
-
- #include <linux/version.h>
--#include <linux/config.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/sched.h>
-@@ -635,7 +634,8 @@
- struct sk_buff *skb;
- unsigned long flags;
-
-- BT_ERR("Timeout, retransmitting %u pkts", bcsp->unack.qlen);
-+ BT_DBG("hu %p retransmitting %u pkts", hu, bcsp->unack.qlen);
-+
- spin_lock_irqsave(&bcsp->unack.lock, flags);
-
- while ((skb = __skb_dequeue_tail(&bcsp->unack)) != NULL) {
---- linux-2.4.21/drivers/bluetooth/hci_ldisc.c~bluetooth
-+++ linux-2.4.21/drivers/bluetooth/hci_ldisc.c
-@@ -33,7 +33,6 @@
- #include <linux/module.h>
-
- #include <linux/version.h>
--#include <linux/config.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/sched.h>
---- linux-2.4.21/drivers/bluetooth/hci_uart.h~bluetooth
-+++ linux-2.4.21/drivers/bluetooth/hci_uart.h
-@@ -35,11 +35,12 @@
- #define HCIUARTGETPROTO _IOR('U', 201, int)
-
- /* UART protocols */
--#define HCI_UART_MAX_PROTO 3
-+#define HCI_UART_MAX_PROTO 4
-
- #define HCI_UART_H4 0
- #define HCI_UART_BCSP 1
--#define HCI_UART_NCSP 2
-+#define HCI_UART_3WIRE 2
-+#define HCI_UART_H4DS 3
-
- #ifdef __KERNEL__
- struct hci_uart;
---- linux-2.4.21/drivers/bluetooth/hci_usb.c~bluetooth
-+++ linux-2.4.21/drivers/bluetooth/hci_usb.c
-@@ -30,7 +30,7 @@
- *
- * $Id: hci_usb.c,v 1.8 2002/07/18 17:23:09 maxk Exp $
- */
--#define VERSION "2.4"
-+#define VERSION "2.7"
-
- #include <linux/config.h>
- #include <linux/module.h>
-@@ -62,7 +62,7 @@
- #define BT_DMP( A... )
- #endif
-
--#ifndef CONFIG_BLUEZ_USB_ZERO_PACKET
-+#ifndef CONFIG_BLUEZ_HCIUSB_ZERO_PACKET
- #undef USB_ZERO_PACKET
- #define USB_ZERO_PACKET 0
- #endif
-@@ -73,20 +73,39 @@
- /* Generic Bluetooth USB device */
- { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) },
-
-- /* Ericsson with non-standard id */
-- { USB_DEVICE(0x0bdb, 0x1002) },
-+ /* AVM BlueFRITZ! USB v2.0 */
-+ { USB_DEVICE(0x057c, 0x3800) },
-
- /* Bluetooth Ultraport Module from IBM */
- { USB_DEVICE(0x04bf, 0x030a) },
-
-+ /* ALPS Modules with non-standard id */
-+ { USB_DEVICE(0x044e, 0x3001) },
-+ { USB_DEVICE(0x044e, 0x3002) },
-+
-+ /* Ericsson with non-standard id */
-+ { USB_DEVICE(0x0bdb, 0x1002) },
-+
- { } /* Terminating entry */
- };
-
- MODULE_DEVICE_TABLE (usb, bluetooth_ids);
-
--static struct usb_device_id ignore_ids[] = {
-+static struct usb_device_id blacklist_ids[] = {
- /* Broadcom BCM2033 without firmware */
-- { USB_DEVICE(0x0a5c, 0x2033) },
-+ { USB_DEVICE(0x0a5c, 0x2033), driver_info: HCI_IGNORE },
-+
-+ /* Broadcom BCM2035 */
-+ { USB_DEVICE(0x0a5c, 0x200a), driver_info: HCI_RESET },
-+
-+ /* ISSC Bluetooth Adapter v3.1 */
-+ { USB_DEVICE(0x1131, 0x1001), driver_info: HCI_RESET },
-+
-+ /* Digianswer device */
-+ { USB_DEVICE(0x08fd, 0x0001), driver_info: HCI_DIGIANSWER },
-+
-+ /* RTX Telecom based adapter with buggy SCO support */
-+ { USB_DEVICE(0x0400, 0x0807), driver_info: HCI_BROKEN_ISOC },
-
- { } /* Terminating entry */
- };
-@@ -133,6 +152,7 @@
- return _urb_dequeue(__completed_q(husb, type));
- }
-
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
- static void __fill_isoc_desc(struct urb *urb, int len, int mtu)
- {
- int offset = 0, i;
-@@ -152,6 +172,7 @@
- }
- urb->number_of_packets = i;
- }
-+#endif
-
- static int hci_usb_intr_rx_submit(struct hci_usb *husb)
- {
-@@ -229,7 +250,7 @@
- return err;
- }
-
--#ifdef CONFIG_BLUEZ_USB_SCO
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
- static int hci_usb_isoc_rx_submit(struct hci_usb *husb)
- {
- struct _urb *_urb;
-@@ -300,8 +321,10 @@
- for (i = 0; i < HCI_MAX_BULK_RX; i++)
- hci_usb_bulk_rx_submit(husb);
-
--#ifdef CONFIG_BLUEZ_USB_SCO
-- hci_usb_isoc_rx_submit(husb);
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+ if (husb->isoc_iface)
-+ for (i = 0; i < HCI_MAX_ISOC_RX; i++)
-+ hci_usb_isoc_rx_submit(husb);
- #endif
- } else {
- clear_bit(HCI_RUNNING, &hdev->flags);
-@@ -426,7 +449,7 @@
- } else
- dr = (void *) _urb->urb.setup_packet;
-
-- dr->bRequestType = HCI_CTRL_REQ;
-+ dr->bRequestType = husb->ctrl_req;
- dr->bRequest = 0;
- dr->wIndex = 0;
- dr->wValue = 0;
-@@ -467,7 +490,7 @@
- return __tx_submit(husb, _urb);
- }
-
--#ifdef CONFIG_BLUEZ_USB_SCO
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
- static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb)
- {
- struct _urb *_urb = __get_completed(husb, skb->pkt_type);
-@@ -518,10 +541,10 @@
- skb_queue_head(q, skb);
- }
-
--#ifdef CONFIG_BLUEZ_USB_SCO
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
- /* Process SCO queue */
- q = __transmit_q(husb, HCI_SCODATA_PKT);
-- if (!atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) &&
-+ if (atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) < HCI_MAX_ISOC_TX &&
- (skb = skb_dequeue(q))) {
- if (hci_usb_send_isoc(husb, skb) < 0)
- skb_queue_head(q, skb);
-@@ -577,7 +600,7 @@
- hdev->stat.acl_tx++;
- break;
-
--#ifdef CONFIG_BLUEZ_USB_SCO
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
- case HCI_SCODATA_PKT:
- hdev->stat.sco_tx++;
- break;
-@@ -627,7 +650,7 @@
- } else
- return -EILSEQ;
- break;
--#ifdef CONFIG_BLUEZ_USB_SCO
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
- case HCI_SCODATA_PKT:
- if (count >= HCI_SCO_HDR_SIZE) {
- hci_sco_hdr *h = data;
-@@ -638,7 +661,7 @@
- #endif
- }
- BT_DBG("new packet len %d", len);
--
-+
- skb = bluez_skb_alloc(len, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("%s no memory for the packet", husb->hdev.name);
-@@ -683,16 +706,16 @@
- BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb,
- _urb->type, urb->status, count, urb->transfer_flags);
-
-- if (!test_bit(HCI_RUNNING, &hdev->flags))
-- return;
--
- read_lock(&husb->completion_lock);
-
-+ if (!test_bit(HCI_RUNNING, &hdev->flags))
-+ goto unlock;
-+
- if (urb->status || !count)
- goto resubmit;
-
- if (_urb->type == HCI_SCODATA_PKT) {
--#ifdef CONFIG_BLUEZ_USB_SCO
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
- int i;
- for (i=0; i < urb->number_of_packets; i++) {
- BT_DBG("desc %d status %d offset %d len %d", i,
-@@ -724,6 +747,8 @@
- BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb,
- _urb->type, err);
- }
-+
-+unlock:
- read_unlock(&husb->completion_lock);
- }
-
-@@ -786,8 +811,14 @@
-
- iface = &udev->actconfig->interface[0];
-
-- /* Check our black list */
-- if (usb_match_id(udev, iface, ignore_ids))
-+ if (!id->driver_info) {
-+ const struct usb_device_id *match;
-+ match = usb_match_id(udev, iface, blacklist_ids);
-+ if (match)
-+ id = match;
-+ }
-+
-+ if (id->driver_info & HCI_IGNORE)
- return NULL;
-
- /* Check number of endpoints */
-@@ -827,9 +858,9 @@
- bulk_out_ep[i] = ep;
- break;
-
--#ifdef CONFIG_BLUEZ_USB_SCO
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
- case USB_ENDPOINT_XFER_ISOC:
-- if (ep->wMaxPacketSize < size)
-+ if (ep->wMaxPacketSize < size || a > 2)
- break;
- size = ep->wMaxPacketSize;
-
-@@ -853,8 +884,8 @@
- goto done;
- }
-
--#ifdef CONFIG_BLUEZ_USB_SCO
-- if (!isoc_in_ep[1] || !isoc_out_ep[1]) {
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+ if (id->driver_info & HCI_BROKEN_ISOC || !isoc_in_ep[1] || !isoc_out_ep[1]) {
- BT_DBG("Isoc endpoints not found");
- isoc_iface = NULL;
- }
-@@ -872,7 +903,12 @@
- husb->bulk_in_ep = bulk_in_ep[0];
- husb->intr_in_ep = intr_in_ep[0];
-
--#ifdef CONFIG_BLUEZ_USB_SCO
-+ if (id->driver_info & HCI_DIGIANSWER)
-+ husb->ctrl_req = HCI_DIGI_REQ;
-+ else
-+ husb->ctrl_req = HCI_CTRL_REQ;
-+
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
- if (isoc_iface) {
- BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts);
- if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) {
-@@ -906,6 +942,9 @@
- hdev->send = hci_usb_send_frame;
- hdev->destruct = hci_usb_destruct;
-
-+ if (id->driver_info & HCI_RESET)
-+ set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
-+
- if (hci_register_dev(hdev) < 0) {
- BT_ERR("Can't register HCI device");
- goto probe_error;
-@@ -968,6 +1007,6 @@
- module_init(hci_usb_init);
- module_exit(hci_usb_cleanup);
-
--MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
- MODULE_DESCRIPTION("BlueZ HCI USB driver ver " VERSION);
- MODULE_LICENSE("GPL");
---- linux-2.4.21/drivers/bluetooth/hci_usb.h~bluetooth
-+++ linux-2.4.21/drivers/bluetooth/hci_usb.h
-@@ -35,12 +35,21 @@
- #define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */
-
- #define HCI_CTRL_REQ 0x20
-+#define HCI_DIGI_REQ 0x40
-+
-+#define HCI_IGNORE 0x01
-+#define HCI_RESET 0x02
-+#define HCI_DIGIANSWER 0x04
-+#define HCI_BROKEN_ISOC 0x08
-
- #define HCI_MAX_IFACE_NUM 3
-
- #define HCI_MAX_BULK_TX 4
- #define HCI_MAX_BULK_RX 1
-
-+#define HCI_MAX_ISOC_RX 2
-+#define HCI_MAX_ISOC_TX 2
-+
- #define HCI_MAX_ISOC_FRAMES 10
-
- struct _urb_queue {
-@@ -119,6 +128,8 @@
- struct usb_endpoint_descriptor *isoc_out_ep;
- struct usb_endpoint_descriptor *isoc_in_ep;
-
-+ __u8 ctrl_req;
-+
- struct sk_buff_head transmit_q[4];
- struct sk_buff *reassembly[4]; // Reassembly buffers
-
---- linux-2.4.21/drivers/char/Config.in~i2c-ds1337
-+++ linux-2.4.21/drivers/char/Config.in
-@@ -164,6 +164,7 @@
-
- if [ "$CONFIG_I2C" != "n" ]; then
- dep_tristate ' DS1307 RTC' CONFIG_I2C_DS1307 $CONFIG_I2C
-+ dep_tristate ' DS1337 RTC' CONFIG_I2C_DS1337 $CONFIG_I2C
- fi
-
- source drivers/l3/Config.in
---- linux-2.4.21/drivers/char/Makefile~i2c-ds1337
-+++ linux-2.4.21/drivers/char/Makefile
-@@ -21,10 +21,11 @@
- # All of the (potential) objects that export symbols.
- # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
-
--export-objs := busmouse.o console.o keyboard.o sysrq.o \
-+export-objs := vt.o busmouse.o console.o keyboard.o sysrq.o \
- misc.o pty.o random.o selection.o serial.o \
- sonypi.o tty_io.o tty_ioctl.o generic_serial.o \
-- au1000_gpio.o hp_psaux.o nvram.o scx200.o
-+ au1000_gpio.o hp_psaux.o nvram.o scx200.o \
-+ input_keyb.o
-
- mod-subdirs := joystick ftape drm drm-4.0 pcmcia
-
-@@ -129,6 +130,11 @@
- ifeq ($(CONFIG_SA1100_CERF_CPLD),y)
- KEYBD += cerf_keyb.o
- endif
-+ ifeq ($(CONFIG_ARCH_RAMSES),y)
-+ KEYMAP = german.o
-+ KEYBD += input_keyb.o
-+ obj-m += sysctl.o
-+ endif
- ifeq ($(CONFIG_ARCH_FORTUNET),y)
- KEYMAP := defkeymap.o
- endif
-@@ -337,6 +343,7 @@
-
- # I2C char devices
- obj-$(CONFIG_I2C_DS1307) += ds1307.o
-+obj-$(CONFIG_I2C_DS1337) += ds1337.o
-
- subdir-$(CONFIG_MWAVE) += mwave
- ifeq ($(CONFIG_MWAVE),y)
-@@ -373,3 +380,6 @@
-
- qtronixmap.c: qtronixmap.map
- set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
-+
-+german.c: german.map
-+ set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
---- linux-2.4.21/drivers/char/console.c~keyb-module
-+++ linux-2.4.21/drivers/char/console.c
-@@ -150,7 +150,7 @@
- static int con_open(struct tty_struct *, struct file *);
- static void vc_init(unsigned int console, unsigned int rows,
- unsigned int cols, int do_clear);
--static void blank_screen(unsigned long dummy);
-+//static void blank_screen(unsigned long dummy);
- static void gotoxy(int currcons, int new_x, int new_y);
- static void save_cur(int currcons);
- static void reset_terminal(int currcons, int do_clear);
-@@ -158,7 +158,7 @@
- static void set_vesa_blanking(unsigned long arg);
- static void set_cursor(int currcons);
- static void hide_cursor(int currcons);
--static void unblank_screen_t(unsigned long dummy);
-+//static void unblank_screen_t(unsigned long dummy);
- static void console_callback(void *ignored);
-
- static int printable; /* Is console ready for printing? */
-@@ -167,7 +167,7 @@
- int console_blanked;
-
- static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
--static int blankinterval = 10*60*HZ;
-+//static int blankinterval = 10*60*HZ;
- static int vesa_off_interval;
-
- static struct tq_struct console_callback_tq = {
-@@ -209,9 +209,9 @@
- * Hook so that the power management routines can (un)blank
- * the console on our behalf.
- */
--int (*console_blank_hook)(int);
-+//int (*console_blank_hook)(int);
-
--static struct timer_list console_timer;
-+//static struct timer_list console_timer;
-
- /*
- * Low-Level Functions
-@@ -543,7 +543,7 @@
-
- static void set_cursor(int currcons)
- {
-- if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS)
-+ if (!IS_FG || vcmode == KD_GRAPHICS)
- return;
- if (deccm) {
- if (currcons == sel_cons)
-@@ -1287,7 +1287,7 @@
- update_attr(currcons);
- break;
- case 9: /* set blanking interval */
-- blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
-+ //blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
- poke_blanked_console();
- break;
- case 10: /* set bell frequency in Hz */
-@@ -2575,11 +2575,11 @@
- if (tty_register_driver(&console_driver))
- panic("Couldn't register console driver\n");
-
-- init_timer(&console_timer);
-- console_timer.function = blank_screen;
-- if (blankinterval) {
-- mod_timer(&console_timer, jiffies + blankinterval);
-- }
-+ //init_timer(&console_timer);
-+ //console_timer.function = blank_screen;
-+ //if (blankinterval) {
-+ // mod_timer(&console_timer, jiffies + blankinterval);
-+ //}
-
- /*
- * kmalloc is not running yet - we use the bootmem allocator.
-@@ -2744,11 +2744,12 @@
- */
- static void vesa_powerdown_screen(unsigned long dummy)
- {
-- console_timer.function = unblank_screen_t;
-+ //console_timer.function = unblank_screen_t;
-
- vesa_powerdown();
- }
-
-+#if 0
- static void timer_do_blank_screen(int entering_gfx, int from_timer_handler)
- {
- int currcons = fg_console;
-@@ -2797,12 +2798,14 @@
- if (vesa_blank_mode)
- sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1);
- }
-+#endif
-
- void do_blank_screen(int entering_gfx)
- {
-- timer_do_blank_screen(entering_gfx, 0);
-+ //timer_do_blank_screen(entering_gfx, 0);
- }
-
-+#if 0
- /*
- * This is a timer handler
- */
-@@ -2810,12 +2813,14 @@
- {
- unblank_screen();
- }
-+#endif
-
- /*
- * Called by timer as well as from vt_console_driver
- */
- void unblank_screen(void)
- {
-+#if 0
- int currcons;
-
- if (!console_blanked)
-@@ -2842,6 +2847,7 @@
- /* Low-level driver cannot restore -> do it ourselves */
- update_screen(fg_console);
- set_cursor(fg_console);
-+#endif
- }
-
- /*
-@@ -2849,11 +2855,12 @@
- */
- static void blank_screen(unsigned long dummy)
- {
-- timer_do_blank_screen(0, 1);
-+ //timer_do_blank_screen(0, 1);
- }
-
- void poke_blanked_console(void)
- {
-+#if 0
- del_timer(&console_timer);
- if (!vt_cons[fg_console] || vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
- return;
-@@ -2863,6 +2870,7 @@
- } else if (blankinterval) {
- mod_timer(&console_timer, jiffies + blankinterval);
- }
-+#endif
- }
-
- /*
-@@ -3088,7 +3096,7 @@
- unblank_screen();
- break;
- case PM_SUSPEND:
-- do_blank_screen(0);
-+ //do_blank_screen(0);
- break;
- }
- return 0;
-@@ -3106,7 +3114,8 @@
- EXPORT_SYMBOL(video_scan_lines);
- EXPORT_SYMBOL(vc_resize);
- EXPORT_SYMBOL(fg_console);
--EXPORT_SYMBOL(console_blank_hook);
-+//EXPORT_SYMBOL(console_blank_hook);
-+EXPORT_SYMBOL(console_driver);
- #ifdef CONFIG_VT
- EXPORT_SYMBOL(vt_cons);
- #endif
---- /dev/null
-+++ linux-2.4.21/drivers/char/ds1337.c
-@@ -0,0 +1,545 @@
-+/*
-+ * ds1337.c
-+ *
-+ * Device driver for Dallas Semiconductor's Real Time Controller DS1337.
-+ *
-+ * Copyright (C) 2003 M&N Logistik-Lösungen Online GmbH
-+ *
-+ * 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.
-+ *
-+ * Documentation for this Chip: http://pdfserv.maxim-ic.com/arpdf/DS1337.pdf
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/version.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/poll.h>
-+#include <linux/i2c.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/rtc.h>
-+#include <linux/string.h>
-+#include <linux/miscdevice.h>
-+#include <linux/proc_fs.h>
-+
-+#include "ds1337.h"
-+
-+//#define DEBUG 1
-+
-+#if DEBUG
-+static unsigned int rtc_debug = DEBUG;
-+#else
-+#define rtc_debug 0 /* gcc will remove all the debug code for us */
-+#endif
-+
-+static unsigned short slave_address = DS1337_I2C_SLAVE_ADDR;
-+struct i2c_driver ds1337_driver;
-+struct i2c_client *ds1337_i2c_client = 0;
-+static spinlock_t ds1337_rtc_lock = SPIN_LOCK_UNLOCKED;
-+
-+static unsigned short ignore[] = { I2C_CLIENT_END };
-+static unsigned short normal_addr[] = { DS1337_I2C_SLAVE_ADDR, I2C_CLIENT_END };
-+
-+static int ds1337_rtc_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
-+static int ds1337_rtc_noop(struct inode *inode, struct file *file);
-+
-+static int ds1337_probe(struct i2c_adapter *adap);
-+static int ds1337_detach(struct i2c_client *client);
-+static int ds1337_command(struct i2c_client *client, unsigned int cmd, void *arg);
-+
-+
-+static struct i2c_client_address_data addr_data = {
-+ .normal_i2c = normal_addr,
-+ .normal_i2c_range = ignore,
-+ .probe = ignore,
-+ .probe_range = ignore,
-+ .ignore = ignore,
-+ .ignore_range = ignore,
-+ .force = ignore,
-+};
-+
-+static struct file_operations rtc_fops = {
-+ .owner = THIS_MODULE,
-+ .ioctl = ds1337_rtc_ioctl,
-+ .open = ds1337_rtc_noop,
-+ .release = ds1337_rtc_noop,
-+};
-+
-+static struct miscdevice ds1337_rtc_miscdev = {
-+ RTC_MINOR,
-+ "rtc",
-+ &rtc_fops
-+};
-+
-+
-+struct i2c_driver ds1337_driver = {
-+ .name = "DS1337",
-+ .id = I2C_DRIVERID_DS1337,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = ds1337_probe,
-+ .detach_client = ds1337_detach,
-+ .command = ds1337_command
-+};
-+
-+#define DAT(x) ((unsigned int)((x)->data)) /* keep the control register info */
-+
-+
-+static int ds1337_readram(char *buf, int len)
-+{
-+ unsigned long flags;
-+ unsigned char ad[1] = { 0 };
-+ int ret;
-+ struct i2c_msg msgs[2] = {
-+ {ds1337_i2c_client->addr, 0, 1, ad},
-+ {ds1337_i2c_client->addr, I2C_M_RD, len, buf}
-+ };
-+
-+ spin_lock_irqsave(&ds1337_rtc_lock, flags);
-+ ret = i2c_transfer(ds1337_i2c_client->adapter, msgs, 2);
-+ spin_unlock_irqrestore(&ds1337_rtc_lock, flags);
-+
-+ return ret;
-+}
-+
-+
-+static void ds1337_setreg(struct i2c_client *c, unsigned char reg, unsigned char val)
-+{
-+ unsigned char buf[2];
-+ buf[0] = reg;
-+ buf[1] = val;
-+ i2c_master_send(c, (char *) buf, 2);
-+}
-+
-+static int ds1337_attach(struct i2c_adapter *adap, int addr,
-+ unsigned short flags, int kind)
-+{
-+ struct i2c_client *c;
-+ unsigned char buf[DS1337_MEM_SIZE], ad[1] = { 7 };
-+ struct i2c_msg msgs[2] = {
-+ {addr, 0, 1, ad},
-+ {addr, I2C_M_RD, 1, buf}
-+ };
-+ int ret;
-+
-+ if (rtc_debug>1)
-+ printk("%s(adap,%d,%d,%d)\n", __FUNCTION__, addr, flags, kind);
-+
-+ c = (struct i2c_client *) kmalloc(sizeof(*c), GFP_KERNEL);
-+ if (!c)
-+ return -ENOMEM;
-+
-+ strcpy(c->name, "DS1337");
-+ c->id = ds1337_driver.id;
-+ c->flags = 0;
-+ c->addr = addr;
-+ c->adapter = adap;
-+ c->driver = &ds1337_driver;
-+ c->data = NULL;
-+
-+ ret = i2c_transfer(c->adapter, msgs, 2);
-+
-+ if (ret == 2) {
-+ DAT(c) = buf[0];
-+ } else
-+ printk("ds1337_attach(): i2c_transfer() returned %d.\n", ret);
-+
-+ ds1337_i2c_client = c;
-+
-+ ds1337_readram(buf, DS1337_MEM_SIZE);
-+
-+ // set 24 hour mode
-+ ds1337_setreg(c, 0x2, buf[2] | DS1337_HOUR24);
-+ // INTCN sets INTB to alarm2 (disables SQW)
-+ ds1337_setreg(c, 0x5, buf[5] & 0x7f); // clear century
-+ ds1337_setreg(c, 0x7, 0x00); // clear Alarm 1 seconds
-+ ds1337_setreg(c, 0x8, 0x00); // clear Alarm 1 minutes
-+ ds1337_setreg(c, 0x9, 0x40); // clear Alarm 1 hours, 24 hour on
-+ ds1337_setreg(c, 0xA, 0x00); // clear Alarm 1 date
-+ ds1337_setreg(c, 0xB, 0x00); // clear Alarm 2 minutes
-+ ds1337_setreg(c, 0xC, 0x40); // clear Alarm 2 hours, 24 hour on
-+ ds1337_setreg(c, 0xD, 0x00); // clear Alarm 2 date
-+ ds1337_setreg(c, 0xe, 4); // nEOSC enabled
-+ ds1337_setreg(c, 0xf, 0); // clear OSF, A2F, A1F
-+
-+ return i2c_attach_client(c);
-+}
-+
-+
-+static int ds1337_probe(struct i2c_adapter *adap)
-+{
-+ if (rtc_debug>1)
-+ printk("%s()\n", __FUNCTION__);
-+
-+ return i2c_probe(adap, &addr_data, ds1337_attach);
-+}
-+
-+
-+static int ds1337_detach(struct i2c_client *client)
-+{
-+ if (rtc_debug>1)
-+ printk("%s()\n", __FUNCTION__);
-+
-+ i2c_detach_client(client);
-+
-+ return 0;
-+}
-+
-+
-+static void ds1337_convert_to_time(struct rtc_time *dt, char *buf)
-+{
-+ if (rtc_debug>1)
-+ printk("%s()\n", __FUNCTION__);
-+
-+ dt->tm_sec = BCD_TO_BIN(buf[0]);
-+ dt->tm_min = BCD_TO_BIN(buf[1]);
-+ dt->tm_hour = DS1337_HOURS_24(buf[2]);
-+
-+ dt->tm_mday = BCD_TO_BIN(buf[4]);
-+ /* dt->tm_mon is zero-based */
-+ dt->tm_mon = BCD_TO_BIN(buf[5]) - 1;
-+ /* year is 1900 + dt->tm_year */
-+ dt->tm_year = BCD_TO_BIN(buf[6]) + 100;
-+
-+ if (rtc_debug > 2) {
-+ printk("ds1337_get_datetime: year = %d\n", dt->tm_year);
-+ printk("ds1337_get_datetime: mon = %d\n", dt->tm_mon);
-+ printk("ds1337_get_datetime: mday = %d\n", dt->tm_mday);
-+ printk("ds1337_get_datetime: hour = %d\n", dt->tm_hour);
-+ printk("ds1337_get_datetime: min = %d\n", dt->tm_min);
-+ printk("ds1337_get_datetime: sec = %d\n", dt->tm_sec);
-+ }
-+}
-+
-+
-+static int ds1337_get_datetime(struct i2c_client *client,
-+ struct rtc_time *dt)
-+{
-+ unsigned char buf[7], addr[1] = { 0 };
-+ struct i2c_msg msgs[2] = {
-+ {client->addr, 0, 1, addr},
-+ {client->addr, I2C_M_RD, 7, buf}
-+ };
-+ int ret = -EIO;
-+
-+ if (rtc_debug)
-+ printk("%s()\n", __FUNCTION__);
-+
-+ memset(buf, 0, sizeof(buf));
-+
-+ ret = i2c_transfer(client->adapter, msgs, 2);
-+
-+ if (ret == 2) {
-+ ds1337_convert_to_time(dt, buf);
-+ ret = 0;
-+ } else
-+ printk("ds1337_get_datetime(), i2c_transfer() returned %d\n", ret);
-+
-+ return ret;
-+}
-+
-+
-+static int ds1337_set_datetime(struct i2c_client *client,
-+ struct rtc_time *dt, int datetoo)
-+{
-+ unsigned char buf[8];
-+ int ret, len = 4;
-+
-+ if (rtc_debug)
-+ printk("%s()\n", __FUNCTION__);
-+
-+ if (rtc_debug > 2) {
-+ printk("ds1337_set_datetime: tm_year = %d\n", dt->tm_year);
-+ printk("ds1337_set_datetime: tm_mon = %d\n", dt->tm_mon);
-+ printk("ds1337_set_datetime: tm_mday = %d\n", dt->tm_mday);
-+ printk("ds1337_set_datetime: tm_hour = %d\n", dt->tm_hour);
-+ printk("ds1337_set_datetime: tm_min = %d\n", dt->tm_min);
-+ printk("ds1337_set_datetime: tm_sec = %d\n", dt->tm_sec);
-+ }
-+
-+ buf[0] = 0; /* register address on DS1337 */
-+ buf[1] = (BIN_TO_BCD(dt->tm_sec));
-+ buf[2] = (BIN_TO_BCD(dt->tm_min));
-+ buf[3] = (BIN_TO_BCD(dt->tm_hour)) | DS1337_HOUR24;
-+
-+ if (datetoo) {
-+ len = 8;
-+ /* we skip buf[4] as we don't use day-of-week. */
-+ buf[5] = (BIN_TO_BCD(dt->tm_mday));
-+ buf[6] = (BIN_TO_BCD(dt->tm_mon + 1));
-+ /* The year only ranges from 0-99, we are being passed an offset from 1900,
-+ * and the chip calulates leap years based on 2000, thus we adjust by 100.
-+ */
-+ buf[7] = (BIN_TO_BCD(dt->tm_year - 100));
-+ }
-+ ret = i2c_master_send(client, (char *) buf, len);
-+ if (ret == len)
-+ ret = 0;
-+ else
-+ printk("ds1337_set_datetime(), i2c_master_send() returned %d\n",
-+ ret);
-+
-+
-+ return ret;
-+}
-+
-+
-+#if 0
-+static int ds1337_get_ctrl(struct i2c_client *client, unsigned char *ctrl)
-+{
-+ *ctrl = DAT(client);
-+
-+ if (rtc_debug)
-+ printk("%s():%d\n", __FUNCTION__, *ctrl);
-+
-+ return 0;
-+}
-+
-+
-+static int ds1337_set_ctrl(struct i2c_client *client, unsigned char *cinfo)
-+{
-+ unsigned char buf[2];
-+ int ret;
-+
-+ if (rtc_debug)
-+ printk("%s(%d)\n", __FUNCTION__, *cinfo);
-+
-+ buf[0] = 7; /* control register address on DS1337 */
-+ buf[1] = *cinfo;
-+ /* save the control reg info in the client data field so that get_ctrl
-+ * function doesn't have to do an I2C transfer to get it.
-+ */
-+ DAT(client) = buf[1];
-+
-+ ret = i2c_master_send(client, (char *) buf, 2);
-+
-+ return ret;
-+}
-+#endif
-+
-+
-+static int ds1337_command(struct i2c_client *client, unsigned int cmd,
-+ void *arg)
-+{
-+ if (rtc_debug)
-+ printk("%s(client,,%u,arg)\n", __FUNCTION__, cmd);
-+
-+ switch (cmd) {
-+ case DS1337_GETDATETIME:
-+ return ds1337_get_datetime(client, arg);
-+
-+ case DS1337_SETTIME:
-+ return ds1337_set_datetime(client, arg, 0);
-+
-+ case DS1337_SETDATETIME:
-+ return ds1337_set_datetime(client, arg, 1);
-+
-+ default:
-+ return -EINVAL;
-+ }
-+}
-+
-+
-+static int ds1337_rtc_noop(struct inode *inode, struct file *file)
-+{
-+ return 0;
-+}
-+
-+
-+static int ds1337_rtc_ioctl(struct inode *inode, struct file *file,
-+ unsigned int cmd, unsigned long arg)
-+{
-+ unsigned long flags;
-+ struct rtc_time wtime;
-+ int status = 0;
-+
-+ if (rtc_debug)
-+ printk("%s()\n", __FUNCTION__);
-+
-+ switch (cmd) {
-+ default:
-+ case RTC_UIE_ON: // mask ints from RTC updates
-+ case RTC_UIE_OFF:
-+ case RTC_PIE_ON: // allow periodic interrupts
-+ case RTC_PIE_OFF:
-+ case RTC_AIE_ON: // mask alarm int enable bit
-+ case RTC_AIE_OFF:
-+ case RTC_ALM_SET:
-+ /*
-+ * This expects a struct rtc_time. Writing 0xff means
-+ * "don't care" or "match all". Only the tm_hour,
-+ * tm_min and tm_sec are used.
-+ */
-+ case RTC_ALM_READ:
-+ // get_rtc_alm_time(&wtime);
-+ case RTC_IRQP_READ: // Read the periodic IRQ rate
-+ case RTC_IRQP_SET: // Set periodic IRQ rate
-+ case RTC_EPOCH_READ:
-+ // return put_user (epoch, (unsigned long *)arg);
-+ case RTC_EPOCH_SET:
-+ case RTC_WKALM_SET:
-+ case RTC_WKALM_RD:
-+ status = -EINVAL;
-+ break;
-+
-+ case RTC_RD_TIME:
-+ spin_lock_irqsave(&ds1337_rtc_lock, flags);
-+ ds1337_command(ds1337_i2c_client, DS1337_GETDATETIME, &wtime);
-+ spin_unlock_irqrestore(&ds1337_rtc_lock, flags);
-+
-+ if (copy_to_user((void *) arg, &wtime, sizeof(struct rtc_time)))
-+ status = -EFAULT;
-+ break;
-+
-+ case RTC_SET_TIME:
-+ if (!capable(CAP_SYS_TIME)) {
-+ status = -EACCES;
-+ break;
-+ }
-+
-+ if (copy_from_user
-+ (&wtime, (struct rtc_time *) arg, sizeof(struct rtc_time))) {
-+ status = -EFAULT;
-+ break;
-+ }
-+
-+ spin_lock_irqsave(&ds1337_rtc_lock, flags);
-+ ds1337_command(ds1337_i2c_client, DS1337_SETDATETIME, &wtime);
-+ spin_unlock_irqrestore(&ds1337_rtc_lock, flags);
-+ break;
-+ }
-+
-+ return status;
-+}
-+
-+
-+static char *ds1337_mon2str(unsigned int mon)
-+{
-+ char *mon2str[12] = {
-+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-+ };
-+ if (mon > 11)
-+ return "error";
-+ else
-+ return mon2str[mon];
-+}
-+
-+
-+static int ds1337_rtc_proc_output(char *buf)
-+{
-+#define CHECK(ctrl,bit) ((ctrl & bit) ? "yes" : "no")
-+
-+ unsigned char ram[DS1337_MEM_SIZE];
-+ int ret;
-+
-+ char *p = buf;
-+
-+ ret = ds1337_readram(ram, DS1337_MEM_SIZE);
-+ if (ret > 0) {
-+#ifdef DEBUG
-+ int i;
-+ char text[9];
-+#endif
-+ struct rtc_time dt;
-+
-+ p += sprintf(p, "DS1337 (i2c Serial Real Time Clock)\n");
-+
-+ ds1337_convert_to_time(&dt, ram);
-+ p += sprintf(p, "Date/Time: %02d-%s-%04d %02d:%02d:%02d\n",
-+ dt.tm_mday, ds1337_mon2str(dt.tm_mon),
-+ dt.tm_year + 1900, dt.tm_hour, dt.tm_min, dt.tm_sec);
-+
-+#ifdef DEBUG
-+ p += sprintf(p, "RAM dump:\n");
-+ text[8] = '\0';
-+ for (i = 0; i < DS1337_MEM_SIZE; i++) {
-+ if ((i % 8) == 0)
-+ p += sprintf(p, "%02X: ", i);
-+ p += sprintf(p, "%02X ", ram[i]);
-+
-+ if ((ram[i] < 32) || (ram[i] > 126))
-+ ram[i] = '.';
-+ text[i % 8] = ram[i];
-+ if ((i % 8) == 7)
-+ p += sprintf(p, "%s\n", text);
-+ }
-+ p += sprintf(p, "\n");
-+#endif
-+ } else {
-+ p += sprintf(p, "Failed to read RTC memory!\n");
-+ }
-+
-+ return p - buf;
-+}
-+
-+
-+static int ds1337_rtc_read_proc(char *page, char **start, off_t off,
-+ int count, int *eof, void *data)
-+{
-+ int len = ds1337_rtc_proc_output(page);
-+
-+ if (len <= off + count)
-+ *eof = 1;
-+ *start = page + off;
-+ len -= off;
-+ if (len > count)
-+ len = count;
-+ if (len < 0)
-+ len = 0;
-+ return len;
-+}
-+
-+
-+static __init int ds1337_init(void)
-+{
-+ int retval = 0;
-+
-+ if (rtc_debug>1)
-+ printk("%s()\n", __FUNCTION__);
-+
-+ if (slave_address != 0xffff) {
-+ normal_addr[0] = slave_address;
-+ }
-+
-+ if (normal_addr[0] == 0xffff) {
-+ printk(KERN_ERR
-+ "I2C: Invalid slave address for DS1337 RTC (%#x)\n",
-+ normal_addr[0]);
-+ return -EINVAL;
-+ }
-+
-+ retval = i2c_add_driver(&ds1337_driver);
-+
-+ if (retval == 0) {
-+ misc_register(&ds1337_rtc_miscdev);
-+ create_proc_read_entry(DS1337_PROC_NAME, 0, 0,
-+ ds1337_rtc_read_proc, NULL);
-+ printk("I2C: DS1337 RTC driver loaded\n");
-+ }
-+ return retval;
-+}
-+
-+
-+static __exit void ds1337_exit(void)
-+{
-+ if (rtc_debug>1)
-+ printk("%s()\n", __FUNCTION__);
-+
-+ remove_proc_entry(DS1337_PROC_NAME, NULL);
-+ misc_deregister(&ds1337_rtc_miscdev);
-+ i2c_del_driver(&ds1337_driver);
-+}
-+
-+
-+module_init(ds1337_init);
-+module_exit(ds1337_exit);
-+
-+MODULE_PARM(slave_address, "i");
-+MODULE_PARM_DESC(slave_address, "I2C slave address for DS1337 RTC");
-+
-+MODULE_AUTHOR("M&N Logistik-Lösungen Online GmbH");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ linux-2.4.21/drivers/char/ds1337.h
-@@ -0,0 +1,43 @@
-+/*
-+ * ds1337.h
-+ *
-+ * Copyright (C) 2003 M&N Logistik-Lösungen Online GmbH
-+ *
-+ * 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.
-+ *
-+ */
-+#ifndef DS1337_H
-+#define DS1337_H
-+
-+#define DS1337_I2C_SLAVE_ADDR 0x68
-+//#define DS1337_RAM_ADDR_START 0x10
-+//#define DS1337_RAM_ADDR_END 0x10
-+#define DS1337_MEM_SIZE 0x10
-+
-+#define DS1337_PROC_NAME "driver/ds1337"
-+
-+struct rtc_mem {
-+ unsigned int loc;
-+ unsigned int nr;
-+ unsigned char *data;
-+};
-+
-+#define DS1337_GETDATETIME 0
-+#define DS1337_SETTIME 1
-+#define DS1337_SETDATETIME 2
-+
-+#define DS1337_RATE_1HZ 0x00 /* Rate Select 1 Hz */
-+#define DS1337_RATE_4096HZ 0x01 /* Rate Select 4096 kHz */
-+#define DS1337_RATE_8192HZ 0x02 /* Rate Select 8192 kHz */
-+#define DS1337_RATE_32768HZ 0x03 /* Rate Select 32768 kHz */
-+
-+#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
-+#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
-+
-+#define DS1337_HOUR12 0x40
-+#define DS1337_HOUR24 0x00
-+#define DS1337_HOURS_24(val) BCD_TO_BIN((val & 0x3f))
-+
-+#endif
---- /dev/null
-+++ linux-2.4.21/drivers/char/german.map
-@@ -0,0 +1,528 @@
-+keymaps 0-2,4-6,8-10,12
-+keycode 1 = Escape Escape
-+ alt keycode 1 = Meta_Escape
-+ shift alt keycode 1 = Meta_Escape
-+keycode 2 = one exclam
-+ alt keycode 2 = Meta_one
-+ shift alt keycode 2 = Meta_exclam
-+keycode 3 = two quotedbl twosuperior nul
-+ alt keycode 3 = Meta_two
-+ shift alt keycode 3 = Meta_quotedbl
-+ control alt keycode 3 = Meta_nul
-+keycode 4 = three section threesuperior Escape
-+ alt keycode 4 = Meta_three
-+ control alt keycode 4 = Meta_Escape
-+keycode 5 = four dollar
-+ alt keycode 5 = Meta_four
-+ shift alt keycode 5 = Meta_dollar
-+keycode 6 = five percent
-+ alt keycode 6 = Meta_five
-+ shift alt keycode 6 = Meta_percent
-+keycode 7 = six ampersand
-+ control keycode 7 = Control_asciicircum
-+ alt keycode 7 = Meta_six
-+ shift alt keycode 7 = Meta_ampersand
-+keycode 8 = seven slash braceleft
-+ alt keycode 8 = Meta_seven
-+ shift alt keycode 8 = Meta_slash
-+ altgr alt keycode 8 = Meta_braceleft
-+keycode 9 = eight parenleft bracketleft
-+ alt keycode 9 = Meta_eight
-+ shift alt keycode 9 = Meta_parenleft
-+ altgr alt keycode 9 = Meta_bracketleft
-+keycode 10 = nine parenright bracketright
-+ altgr control keycode 10 = Control_bracketright
-+ alt keycode 10 = Meta_nine
-+ shift alt keycode 10 = Meta_parenright
-+ altgr alt keycode 10 = Meta_bracketright
-+keycode 11 = zero equal braceright
-+ alt keycode 11 = Meta_zero
-+ shift alt keycode 11 = Meta_equal
-+ altgr alt keycode 11 = Meta_braceright
-+keycode 12 = ssharp question backslash
-+ altgr control keycode 12 = Control_backslash
-+ shift alt keycode 12 = Meta_question
-+ altgr alt keycode 12 = Meta_backslash
-+keycode 13 = apostrophe grave
-+ alt keycode 13 = 0x08b4
-+ shift alt keycode 13 = Meta_grave
-+keycode 14 = BackSpace Delete
-+ alt keycode 14 = Meta_BackSpace
-+ shift alt keycode 14 = Meta_Delete
-+keycode 15 = Tab Tab
-+ alt keycode 15 = Meta_Tab
-+ shift alt keycode 15 = Meta_Tab
-+keycode 16 = +q +Q at Control_q Control_q Control_q Meta_q Meta_Q Meta_at Meta_Control_q
-+keycode 17 = w
-+keycode 18 = +e +E currency Control_e Control_e Control_e Meta_e Meta_E Meta_e Meta_Control_e
-+keycode 19 = r
-+keycode 20 = t
-+keycode 21 = z
-+keycode 22 = u
-+keycode 23 = i
-+keycode 24 = o
-+keycode 25 = p
-+keycode 26 = +udiaeresis +Udiaeresis
-+keycode 27 = plus asterisk asciitilde
-+ alt keycode 27 = Meta_plus
-+ shift alt keycode 27 = Meta_asterisk
-+keycode 28 = Return
-+ alt keycode 28 = Meta_Control_m
-+keycode 29 = Control
-+keycode 30 = a
-+keycode 31 = s
-+keycode 32 = d
-+keycode 33 = f
-+keycode 34 = g
-+keycode 35 = h
-+keycode 36 = j
-+keycode 37 = k
-+keycode 38 = l
-+keycode 39 = +odiaeresis +Odiaeresis
-+keycode 40 = +adiaeresis +Adiaeresis
-+keycode 41 = asciicircum degree Meta_asciicircum Control_asciicircum
-+ control alt keycode 41 = Meta_Control_asciicircum
-+keycode 42 = Shift
-+keycode 43 = numbersign apostrophe
-+ alt keycode 43 = Meta_numbersign
-+ shift alt keycode 43 = Meta_apostrophe
-+keycode 44 = y
-+keycode 45 = x
-+keycode 46 = c
-+keycode 47 = v
-+keycode 48 = b
-+keycode 49 = n
-+keycode 50 = +m +M mu Control_m Control_m Control_m Meta_m Meta_M Meta_m Meta_Control_m
-+keycode 51 = comma semicolon
-+ alt keycode 51 = Meta_comma
-+ shift alt keycode 51 = Meta_semicolon
-+keycode 52 = period colon
-+ alt keycode 52 = Meta_period
-+ shift alt keycode 52 = Meta_colon
-+keycode 53 = minus underscore Meta_minus
-+ shift control keycode 53 = Control_underscore
-+ alt keycode 53 = Meta_minus
-+ shift alt keycode 53 = Meta_underscore
-+keycode 54 = Shift
-+keycode 55 = KP_Multiply
-+ altgr keycode 55 = Hex_C
-+keycode 56 = Alt
-+keycode 57 = space space Meta_space nul
-+ alt keycode 57 = Meta_space
-+ shift alt keycode 57 = Meta_space
-+ control alt keycode 57 = Meta_nul
-+keycode 58 = Caps_Lock
-+keycode 59 = F1 F13 Console_13 F25
-+ altgr control keycode 59 = F1
-+ alt keycode 59 = Console_1
-+ control alt keycode 59 = Console_1
-+keycode 60 = F2 F14 Console_14 F26
-+ altgr control keycode 60 = F2
-+ alt keycode 60 = Console_2
-+ control alt keycode 60 = Console_2
-+keycode 61 = F3 F15 Console_15 F27
-+ altgr control keycode 61 = F3
-+ alt keycode 61 = Console_3
-+ control alt keycode 61 = Console_3
-+keycode 62 = F4 F16 Console_16 F28
-+ altgr control keycode 62 = F4
-+ alt keycode 62 = Console_4
-+ control alt keycode 62 = Console_4
-+keycode 63 = F5 F17 Console_17 F29
-+ altgr control keycode 63 = F5
-+ alt keycode 63 = Console_5
-+ control alt keycode 63 = Console_5
-+keycode 64 = F6 F18 Console_18 F30
-+ altgr control keycode 64 = F6
-+ alt keycode 64 = Console_6
-+ control alt keycode 64 = Console_6
-+keycode 65 = F7 F19 Console_19 F31
-+ altgr control keycode 65 = F7
-+ alt keycode 65 = Console_7
-+ control alt keycode 65 = Console_7
-+keycode 66 = F8 F20 Console_20 F32
-+ altgr control keycode 66 = F8
-+ alt keycode 66 = Console_8
-+ control alt keycode 66 = Console_8
-+keycode 67 = F9 F21 Console_21 F33
-+ altgr control keycode 67 = F9
-+ alt keycode 67 = Console_9
-+ control alt keycode 67 = Console_9
-+keycode 68 = F10 F22 Console_22 F34
-+ altgr control keycode 68 = F10
-+ alt keycode 68 = Console_10
-+ control alt keycode 68 = Console_10
-+keycode 69 = Num_Lock
-+ altgr keycode 69 = Hex_A
-+keycode 70 = Scroll_Lock Show_Memory Show_Registers Show_State
-+ alt keycode 70 = Scroll_Lock
-+keycode 71 = KP_7
-+ altgr keycode 71 = Hex_7
-+ alt keycode 71 = Ascii_7
-+keycode 72 = KP_8
-+ altgr keycode 72 = Hex_8
-+ alt keycode 72 = Ascii_8
-+keycode 73 = KP_9
-+ altgr keycode 73 = Hex_9
-+ alt keycode 73 = Ascii_9
-+keycode 74 = KP_Subtract
-+ altgr keycode 74 = Hex_D
-+keycode 75 = KP_4
-+ altgr keycode 75 = Hex_4
-+ alt keycode 75 = Ascii_4
-+keycode 76 = KP_5
-+ altgr keycode 76 = Hex_5
-+ alt keycode 76 = Ascii_5
-+keycode 77 = KP_6
-+ altgr keycode 77 = Hex_6
-+ alt keycode 77 = Ascii_6
-+keycode 78 = KP_Add
-+ altgr keycode 78 = Hex_E
-+keycode 79 = KP_1
-+ altgr keycode 79 = Hex_1
-+ alt keycode 79 = Ascii_1
-+keycode 80 = KP_2
-+ altgr keycode 80 = Hex_2
-+ alt keycode 80 = Ascii_2
-+keycode 81 = KP_3
-+ altgr keycode 81 = Hex_3
-+ alt keycode 81 = Ascii_3
-+keycode 82 = KP_0
-+ altgr keycode 82 = Hex_0
-+ alt keycode 82 = Ascii_0
-+keycode 83 = KP_Comma
-+ altgr control keycode 83 = Boot
-+ control alt keycode 83 = Boot
-+#keycode 84 = Last_Console
-+keycode 85 =
-+keycode 86 = less greater bar
-+ alt keycode 86 = Meta_less
-+ shift alt keycode 86 = Meta_greater
-+ altgr alt keycode 86 = Meta_bar
-+keycode 87 = F11 F23 Console_23 F35
-+ altgr control keycode 87 = F11
-+ alt keycode 87 = Console_11
-+ control alt keycode 87 = Console_11
-+keycode 88 = F12 F24 Console_24 F36
-+ altgr control keycode 88 = F12
-+ alt keycode 88 = Console_12
-+ control alt keycode 88 = Console_12
-+keycode 89 = slash question degree
-+ alt keycode 89 = Meta_slash
-+ shift alt keycode 89 = Meta_question
-+keycode 90 =
-+keycode 91 =
-+keycode 92 =
-+keycode 93 =
-+keycode 94 =
-+keycode 95 =
-+keycode 96 = KP_Enter
-+ altgr keycode 96 = Hex_F
-+keycode 97 = Control
-+keycode 98 = KP_Divide
-+ altgr keycode 98 = Hex_B
-+keycode 99 = Compose
-+keycode 100 = AltGr
-+ alt keycode 100 = Compose
-+keycode 101 = Break
-+keycode 102 = Find
-+keycode 103 = Up
-+ alt keycode 103 = KeyboardSignal
-+keycode 104 = Prior
-+ shift keycode 104 = Scroll_Backward
-+keycode 105 = Left
-+# alt keycode 105 = Decr_Console
-+keycode 106 = Right
-+# alt keycode 106 = Incr_Console
-+keycode 107 = Select
-+keycode 108 = Down
-+keycode 109 = Next
-+ shift keycode 109 = Scroll_Forward
-+keycode 110 = Insert
-+keycode 111 = Remove
-+ altgr control keycode 111 = Boot
-+ control alt keycode 111 = Boot
-+keycode 112 = Macro
-+ shift alt keycode 112 = VoidSymbol
-+ altgr alt keycode 112 = VoidSymbol
-+keycode 113 = F13
-+ shift alt keycode 113 = VoidSymbol
-+ altgr alt keycode 113 = VoidSymbol
-+keycode 114 = F14
-+ shift alt keycode 114 = VoidSymbol
-+ altgr alt keycode 114 = VoidSymbol
-+keycode 115 = Help
-+ shift alt keycode 115 = VoidSymbol
-+ altgr alt keycode 115 = VoidSymbol
-+keycode 116 = Do
-+ shift alt keycode 116 = VoidSymbol
-+ altgr alt keycode 116 = VoidSymbol
-+keycode 117 = F17
-+ shift alt keycode 117 = VoidSymbol
-+ altgr alt keycode 117 = VoidSymbol
-+keycode 118 = KP_MinPlus
-+ shift alt keycode 118 = VoidSymbol
-+ altgr alt keycode 118 = VoidSymbol
-+keycode 119 = Pause
-+keycode 120 =
-+keycode 121 =
-+keycode 122 =
-+keycode 123 =
-+keycode 124 =
-+#keycode 125 = Decr_Console
-+#keycode 126 = Incr_Console
-+keycode 127 = Compose
-+string F1 = "\033[[A"
-+string F2 = "\033[[B"
-+string F3 = "\033[[C"
-+string F4 = "\033[[D"
-+string F5 = "\033[[E"
-+string F6 = "\033[17~"
-+string F7 = "\033[18~"
-+string F8 = "\033[19~"
-+string F9 = "\033[20~"
-+string F10 = "\033[21~"
-+string F11 = "\033[23~"
-+string F12 = "\033[24~"
-+string F13 = "\033[25~"
-+string F14 = "\033[26~"
-+string F15 = "\033[28~"
-+string F16 = "\033[29~"
-+string F17 = "\033[31~"
-+string F18 = "\033[32~"
-+string F19 = "\033[33~"
-+string F20 = "\033[34~"
-+string Find = "\033[1~"
-+string Insert = "\033[2~"
-+string Remove = "\033[3~"
-+string Select = "\033[4~"
-+string Prior = "\033[5~"
-+string Next = "\033[6~"
-+string Macro = "\033[M"
-+string Pause = "\033[P"
-+compose '!' '!' to 'ˇ'
-+compose '"' 'A' to 'Ä'
-+compose '"' 'E' to 'Ë'
-+compose '"' 'I' to 'Ď'
-+compose '"' 'O' to 'Ö'
-+compose '"' 'U' to 'Ü'
-+compose '"' 'Y' to 'ľ'
-+compose '"' 'a' to 'ä'
-+compose '"' 'c' to '©'
-+compose '"' 'e' to 'ë'
-+compose '"' 'i' to 'ď'
-+compose '"' 'o' to 'ö'
-+compose '"' 'r' to '®'
-+compose '"' 'u' to 'ü'
-+compose '"' 'y' to '˙'
-+compose '(' 'c' to '©'
-+compose '(' 'r' to '®'
-+compose '+' '-' to '±'
-+compose ',' 'A' to 'ˇ'
-+compose ',' 'C' to 'Ç'
-+compose ',' 'E' to 'Ę'
-+compose ',' 'G' to '«'
-+compose ',' 'I' to 'Ç'
-+compose ',' 'K' to 'Ó'
-+compose ',' 'L' to '¦'
-+compose ',' 'N' to 'Ń'
-+compose ',' 'R' to 'Ł'
-+compose ',' 'S' to 'Ş'
-+compose ',' 'T' to 'Ţ'
-+compose ',' 'U' to 'Ů'
-+compose ',' 'a' to '±'
-+compose ',' 'c' to 'ç'
-+compose ',' 'e' to 'ę'
-+compose ',' 'g' to '»'
-+compose ',' 'i' to 'ç'
-+compose ',' 'k' to 'ó'
-+compose ',' 'l' to '¶'
-+compose ',' 'n' to 'ń'
-+compose ',' 'r' to 'ł'
-+compose ',' 's' to 'ş'
-+compose ',' 't' to 'ţ'
-+compose ',' 'u' to 'ů'
-+compose '-' ':' to '÷'
-+compose '-' 'A' to 'Ş'
-+compose '-' 'C' to '˘'
-+compose '-' 'D' to 'Đ'
-+compose '-' 'E' to '¤'
-+compose '-' 'H' to 'ˇ'
-+compose '-' 'L' to 'Ł'
-+compose '-' 'O' to 'ş'
-+compose '-' 'T' to '¬'
-+compose '-' 'Y' to 'Ą'
-+compose '-' 'a' to 'Ş'
-+compose '-' 'c' to '˘'
-+compose '-' 'd' to 'đ'
-+compose '-' 'e' to '¤'
-+compose '-' 'h' to '±'
-+compose '-' 'l' to 'Ł'
-+compose '-' 'l' to 'Ą'
-+compose '-' 'l' to 'ł'
-+compose '-' 'o' to 'ş'
-+compose '-' 't' to 'Ľ'
-+compose '.' '.' to '·'
-+compose '.' 'C' to 'Ĺ'
-+compose '.' 'C' to 'Ő'
-+compose '.' 'E' to 'Ě'
-+compose '.' 'I' to '©'
-+compose '.' 'Z' to 'Ż'
-+compose '.' 'c' to 'ĺ'
-+compose '.' 'c' to 'ő'
-+compose '.' 'e' to 'ě'
-+compose '.' 'i' to 'ą'
-+compose '.' 'z' to 'ż'
-+compose '/' 'D' to 'Đ'
-+compose '/' 'L' to 'Ł'
-+compose '/' 'O' to 'Ř'
-+compose '/' 'T' to '¬'
-+compose '/' 'c' to '˘'
-+compose '/' 'd' to 'đ'
-+compose '/' 'l' to 'ł'
-+compose '/' 'o' to 'ř'
-+compose '/' 't' to 'Ľ'
-+compose '0' 'A' to 'Ĺ'
-+compose '0' 'U' to 'Ů'
-+compose '0' 'a' to 'ĺ'
-+compose '0' 'u' to 'ů'
-+compose '1' '2' to '˝'
-+compose '1' '4' to 'Ľ'
-+compose '3' '4' to 'ľ'
-+compose ':' '-' to '÷'
-+compose ':' 'A' to 'Ä'
-+compose ':' 'E' to 'Ë'
-+compose ':' 'O' to 'Ö'
-+compose ':' 'U' to 'Ü'
-+compose ':' 'a' to 'ä'
-+compose ':' 'e' to 'ë'
-+compose ':' 'o' to 'ö'
-+compose ':' 'u' to 'ü'
-+compose '<' '<' to '«'
-+compose '>' '>' to '»'
-+compose '?' '?' to 'ż'
-+compose 'A' 'A' to 'Ĺ'
-+compose 'A' 'E' to 'Ć'
-+compose 'I' 'J' to 'ľ'
-+compose 'L' '=' to 'Ł'
-+compose 'N' 'G' to '˝'
-+compose 'N' 'H' to 'Ń'
-+compose 'N' 'N' to 'Ń'
-+compose 'N' 'Y' to 'Ń'
-+compose 'N' 'h' to 'Ń'
-+compose 'N' 'n' to 'Ń'
-+compose 'N' 'y' to 'Ń'
-+compose 'O' 'A' to 'Ĺ'
-+compose 'O' 'E' to 'Ľ'
-+compose 'O' 'e' to 'Ľ'
-+compose 'T' 'H' to 'Ţ'
-+compose 'U' 'U' to 'Ů'
-+compose 'Y' '=' to 'Ą'
-+compose '\'' 'A' to 'Á'
-+compose '\'' 'C' to 'Ć'
-+compose '\'' 'E' to 'É'
-+compose '\'' 'I' to 'Í'
-+compose '\'' 'L' to 'Ĺ'
-+compose '\'' 'N' to 'Ń'
-+compose '\'' 'O' to 'Ó'
-+compose '\'' 'R' to 'Ŕ'
-+compose '\'' 'S' to '¦'
-+compose '\'' 'U' to 'Ú'
-+compose '\'' 'Y' to 'Ý'
-+compose '\'' 'Z' to '¬'
-+compose '\'' 'a' to 'á'
-+compose '\'' 'c' to 'ć'
-+compose '\'' 'e' to 'é'
-+compose '\'' 'i' to 'í'
-+compose '\'' 'l' to 'ĺ'
-+compose '\'' 'n' to 'ń'
-+compose '\'' 'o' to 'ó'
-+compose '\'' 'r' to 'ŕ'
-+compose '\'' 's' to '¶'
-+compose '\'' 'u' to 'ú'
-+compose '\'' 'y' to 'ý'
-+compose '\'' 'z' to 'Ľ'
-+compose '^' '!' to 'ˇ'
-+compose '^' '*' to '×'
-+compose '^' '.' to '·'
-+compose '^' '/' to '÷'
-+compose '^' '1' to 'ą'
-+compose '^' '2' to '˛'
-+compose '^' '3' to 'ł'
-+compose '^' ':' to '÷'
-+compose '^' '?' to 'ż'
-+compose '^' 'A' to 'Â'
-+compose '^' 'C' to 'Ç'
-+compose '^' 'D' to 'Đ'
-+compose '^' 'E' to 'Ę'
-+compose '^' 'G' to 'Ô'
-+compose '^' 'H' to '¦'
-+compose '^' 'I' to 'Î'
-+compose '^' 'J' to '¬'
-+compose '^' 'L' to 'Ą'
-+compose '^' 'N' to 'Ń'
-+compose '^' 'R' to 'Ř'
-+compose '^' 'S' to '¦'
-+compose '^' 'T' to '«'
-+compose '^' 'U' to 'Ű'
-+compose '^' 'Z' to '´'
-+compose '^' 'a' to 'â'
-+compose '^' 'c' to 'ç'
-+compose '^' 'd' to 'đ'
-+compose '^' 'e' to 'ę'
-+compose '^' 'g' to 'ř'
-+compose '^' 'h' to '¶'
-+compose '^' 'i' to 'î'
-+compose '^' 'j' to 'Ľ'
-+compose '^' 'l' to 'µ'
-+compose '^' 'n' to 'ń'
-+compose '^' 'o' to 'ô'
-+compose '^' 'r' to 'ř'
-+compose '^' 's' to '¨'
-+compose '^' 't' to '»'
-+compose '^' 'u' to 'ű'
-+compose '^' 'x' to '×'
-+compose '^' 'z' to '¸'
-+compose '`' 'A' to 'Ŕ'
-+compose '`' 'E' to 'Č'
-+compose '`' 'I' to 'Ě'
-+compose '`' 'O' to 'Ň'
-+compose '`' 'U' to 'Ů'
-+compose '`' 'a' to 'ŕ'
-+compose '`' 'e' to 'č'
-+compose '`' 'i' to 'ě'
-+compose '`' 'o' to 'ň'
-+compose '`' 'u' to 'ů'
-+compose 'a' 'a' to 'ĺ'
-+compose 'a' 'e' to 'ć'
-+compose 'c' '/' to '˘'
-+compose 'c' '=' to '˘'
-+compose 'e' '=' to '¤'
-+compose 'i' 'j' to '˙'
-+compose 'm' 'u' to 'µ'
-+compose 'n' 'g' to 'ż'
-+compose 'n' 'h' to 'ń'
-+compose 'n' 'n' to 'ń'
-+compose 'o' 'a' to 'ĺ'
-+compose 'o' 'e' to '˝'
-+compose 's' 's' to 'ß'
-+compose 's' 'z' to 'ß'
-+compose 't' 'h' to 'ţ'
-+compose 'u' 'u' to 'ů'
-+compose 'v' 'S' to '¦'
-+compose 'v' 'Z' to '´'
-+compose 'v' 's' to '¨'
-+compose 'v' 'z' to '¸'
-+compose 'x' 'x' to '×'
-+compose '~' 'A' to 'Ă'
-+compose '~' 'G' to '«'
-+compose '~' 'I' to 'Ą'
-+compose '~' 'N' to 'Ń'
-+compose '~' 'O' to 'Ő'
-+compose '~' 'U' to 'Ý'
-+compose '~' 'a' to 'ă'
-+compose '~' 'g' to '»'
-+compose '~' 'i' to 'µ'
-+compose '~' 'n' to 'ń'
-+compose '~' 'o' to 'ő'
-+compose '~' 'u' to 'ý'
---- /dev/null
-+++ linux-2.4.21/drivers/char/input_keyb.c
-@@ -0,0 +1,167 @@
-+/*
-+ * linux/drivers/char/input_keyb.c by Russ Dill <Russ.Dill@asu.edu>
-+ * taken from pc_keyb.c
-+ *
-+ * This code grabs keypresses from the input layer and makes them
-+ * available to the console.
-+ *
-+ * 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 <asm/uaccess.h>
-+#include <asm/keyboard.h>
-+
-+/* Simple translation table for the SysRq keys */
-+
-+unsigned char input_sysrq_xlate[128] =
-+ "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
-+ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
-+ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
-+ "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
-+ "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */
-+ "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
-+ "\r\000/"; /* 0x60 - 0x6f */
-+
-+/*
-+ * Translation of escaped scancodes to keycodes.
-+ * This is now user-settable.
-+ * The keycodes 1-88,96-111,119 are fairly standard, and
-+ * should probably not be changed - changing might confuse X.
-+ * X also interprets scancode 0x5d (KEY_Begin).
-+ *
-+ * For 1-88 keycode equals scancode.
-+ */
-+
-+#define E0_KPENTER 96
-+#define E0_RCTRL 97
-+#define E0_KPSLASH 98
-+#define E0_PRSCR 99
-+#define E0_RALT 100
-+#define E0_BREAK 101 /* (control-pause) */
-+#define E0_HOME 102
-+#define E0_UP 103
-+#define E0_PGUP 104
-+#define E0_LEFT 105
-+#define E0_RIGHT 106
-+#define E0_END 107
-+#define E0_DOWN 108
-+#define E0_PGDN 109
-+#define E0_INS 110
-+#define E0_DEL 111
-+
-+#define E1_PAUSE 119
-+
-+/*
-+ * New microsoft keyboard is rumoured to have
-+ * e0 5b (left window button), e0 5c (right window button),
-+ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
-+ * [or: Windows_L, Windows_R, TaskMan]
-+ */
-+#define E0_MSLW 125
-+
-+static unsigned char e0_keys[128] = {
-+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */
-+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */
-+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */
-+ 0, 0, 0, 0, 0, E0_RCTRL, 0, 0, /* 0x18-0x1f */
-+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */
-+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */
-+ 0, 0, 0, 0, 0, 0, 0, E0_PRSCR, /* 0x30-0x37 */
-+ E0_RALT, 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f */
-+ 0, 0, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */
-+ E0_UP, E0_PGUP, 0, E0_LEFT, 0, E0_RIGHT, 0, E0_END, /* 0x48-0x4f */
-+ E0_DOWN, E0_PGDN, 0, 0, 0, 0, 0, 0, /* 0x50-0x57 */
-+ 0, 0, 0, E0_MSLW, 0, 0, 0, 0, /* 0x58-0x5f */
-+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
-+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68-0x6f */
-+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */
-+ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */
-+};
-+
-+int input_setkeycode(unsigned int scancode, unsigned int keycode)
-+{
-+ if (scancode > 255 || keycode > 127) return -EINVAL;
-+ e0_keys[scancode - 128] = keycode;
-+ return 0;
-+}
-+
-+int input_getkeycode(unsigned int scancode)
-+{
-+ return scancode > 255 ? -EINVAL : e0_keys[scancode - 128];
-+}
-+
-+#define KBD_REPORT_UNKN
-+int input_translate(unsigned char scancode, unsigned char *keycode,
-+ char raw_mode)
-+{
-+ static int prev_scancode;
-+
-+ /* special prefix scancodes.. */
-+ if (scancode == 0xe0 || scancode == 0xe1) {
-+ prev_scancode = scancode;
-+ return 0;
-+ }
-+ if (prev_scancode) {
-+ /*
-+ * usually it will be 0xe0, but a Pause key generates
-+ * e1 1d 45 e1 9d c5 when pressed, and nothing when released
-+ */
-+ if (prev_scancode != 0xe0) {
-+ if (prev_scancode == 0xe1 && scancode == 0x1d) {
-+ prev_scancode = 0x100;
-+ return 0;
-+ } else if (prev_scancode == 0x100 && scancode == 0x45) {
-+ *keycode = E1_PAUSE;
-+ prev_scancode = 0;
-+ } else {
-+#ifdef KBD_REPORT_UNKN
-+ if (!raw_mode)
-+ printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
-+#endif
-+ prev_scancode = 0;
-+ return 0;
-+ }
-+ } else {
-+ prev_scancode = 0;
-+
-+ if (e0_keys[scancode])
-+ *keycode = e0_keys[scancode];
-+ else {
-+#ifdef KBD_REPORT_UNKN
-+ if (!raw_mode)
-+ printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
-+ scancode);
-+#endif
-+ return 0;
-+ }
-+ }
-+ } else
-+ *keycode = scancode;
-+ return 1;
-+}
-+
-+char input_unexpected_up(unsigned char keycode)
-+{
-+ return 0200;
-+}
-+
-+/* Allow for loadable keyboard drivers */
-+EXPORT_SYMBOL(input_setkeycode);
-+EXPORT_SYMBOL(input_unexpected_up);
-+EXPORT_SYMBOL(input_translate);
-+EXPORT_SYMBOL(input_sysrq_xlate);
-+EXPORT_SYMBOL(input_getkeycode);
-+EXPORT_SYMBOL(k_setkeycode);
-+EXPORT_SYMBOL(k_unexpected_up);
-+EXPORT_SYMBOL(k_translate);
-+EXPORT_SYMBOL(k_getkeycode);
-+#ifdef CONFIG_MAGIC_SYSRQ
-+EXPORT_SYMBOL(k_sysrq_key);
-+EXPORT_SYMBOL(k_sysrq_xlate);
-+#endif
---- linux-2.4.21/drivers/char/keyboard.c~wedge
-+++ linux-2.4.21/drivers/char/keyboard.c
-@@ -77,6 +77,7 @@
- void (*kbd_ledfunc)(unsigned int led);
- EXPORT_SYMBOL(handle_scancode);
- EXPORT_SYMBOL(kbd_ledfunc);
-+EXPORT_SYMBOL(key_maps);
- EXPORT_SYMBOL(kbd_refresh_leds);
-
- extern void ctrl_alt_del(void);
---- linux-2.4.21/drivers/char/serial.c~ramses-serial
-+++ linux-2.4.21/drivers/char/serial.c
-@@ -1,138 +1,8 @@
--/*
-- * linux/drivers/char/serial.c
-- *
-- * Copyright (C) 1991, 1992 Linus Torvalds
-- * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997,
-- * 1998, 1999 Theodore Ts'o
-- *
-- * Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now
-- * much more extensible to support other serial cards based on the
-- * 16450/16550A UART's. Added support for the AST FourPort and the
-- * Accent Async board.
-- *
-- * set_serial_info fixed to set the flags, custom divisor, and uart
-- * type fields. Fix suggested by Michael K. Johnson 12/12/92.
-- *
-- * 11/95: TIOCMIWAIT, TIOCGICOUNT by Angelo Haritsis <ah@doc.ic.ac.uk>
-- *
-- * 03/96: Modularised by Angelo Haritsis <ah@doc.ic.ac.uk>
-- *
-- * rs_set_termios fixed to look also for changes of the input
-- * flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK.
-- * Bernd Anhäupl 05/17/96.
-- *
-- * 1/97: Extended dumb serial ports are a config option now.
-- * Saves 4k. Michael A. Griffith <grif@acm.org>
-- *
-- * 8/97: Fix bug in rs_set_termios with RTS
-- * Stanislav V. Voronyi <stas@uanet.kharkov.ua>
-- *
-- * 3/98: Change the IRQ detection, use of probe_irq_o*(),
-- * suppress TIOCSERGWILD and TIOCSERSWILD
-- * Etienne Lorrain <etienne.lorrain@ibm.net>
-- *
-- * 4/98: Added changes to support the ARM architecture proposed by
-- * Russell King
-- *
-- * 5/99: Updated to include support for the XR16C850 and ST16C654
-- * uarts. Stuart MacDonald <stuartm@connecttech.com>
-- *
-- * 8/99: Generalized PCI support added. Theodore Ts'o
-- *
-- * 3/00: Rid circular buffer of redundant xmit_cnt. Fix a
-- * few races on freeing buffers too.
-- * Alan Modra <alan@linuxcare.com>
-- *
-- * 5/00: Support for the RSA-DV II/S card added.
-- * Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
-- *
-- * 6/00: Remove old-style timer, use timer_list
-- * Andrew Morton <andrewm@uow.edu.au>
-- *
-- * 7/00: Support Timedia/Sunix/Exsys PCI cards
-- *
-- * 7/00: fix some returns on failure not using MOD_DEC_USE_COUNT.
-- * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-- *
-- * 10/00: add in optional software flow control for serial console.
-- * Kanoj Sarcar <kanoj@sgi.com> (Modified by Theodore Ts'o)
-- *
-- * 02/02: Fix for AMD Elan bug in transmit irq routine, by
-- * Christer Weinigel <wingel@hog.ctrl-c.liu.se>,
-- * Robert Schwebel <robert@schwebel.de>,
-- * Juergen Beisert <jbeisert@eurodsn.de>,
-- * Theodore Ts'o <tytso@mit.edu>
-- */
--
--static char *serial_version = "5.05c";
--static char *serial_revdate = "2001-07-08";
--
--/*
-- * Serial driver configuration section. Here are the various options:
-- *
-- * CONFIG_HUB6
-- * Enables support for the venerable Bell Technologies
-- * HUB6 card.
-- *
-- * CONFIG_SERIAL_MANY_PORTS
-- * Enables support for ports beyond the standard, stupid
-- * COM 1/2/3/4.
-- *
-- * CONFIG_SERIAL_MULTIPORT
-- * Enables support for special multiport board support.
-- *
-- * CONFIG_SERIAL_SHARE_IRQ
-- * Enables support for multiple serial ports on one IRQ
-- *
-- * CONFIG_SERIAL_DETECT_IRQ
-- * Enable the autodetection of IRQ on standart ports
-- *
-- * SERIAL_PARANOIA_CHECK
-- * Check the magic number for the async_structure where
-- * ever possible.
-- *
-- * CONFIG_SERIAL_ACPI
-- * Enable support for serial console port and serial
-- * debug port as defined by the SPCR and DBGP tables in
-- * ACPI 2.0.
-- */
-+#undef DEBUG
-
- #include <linux/config.h>
- #include <linux/version.h>
-
--#undef SERIAL_PARANOIA_CHECK
--#define CONFIG_SERIAL_NOPAUSE_IO
--#define SERIAL_DO_RESTART
--
--#if 0
--/* These defines are normally controlled by the autoconf.h */
--#define CONFIG_SERIAL_MANY_PORTS
--#define CONFIG_SERIAL_SHARE_IRQ
--#define CONFIG_SERIAL_DETECT_IRQ
--#define CONFIG_SERIAL_MULTIPORT
--#define CONFIG_HUB6
--#endif
--
--#ifdef CONFIG_PCI
--#define ENABLE_SERIAL_PCI
--#ifndef CONFIG_SERIAL_SHARE_IRQ
--#define CONFIG_SERIAL_SHARE_IRQ
--#endif
--#ifndef CONFIG_SERIAL_MANY_PORTS
--#define CONFIG_SERIAL_MANY_PORTS
--#endif
--#endif
--
--#ifdef CONFIG_SERIAL_ACPI
--#define ENABLE_SERIAL_ACPI
--#endif
--
--#if defined(CONFIG_ISAPNP)|| (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE))
--#ifndef ENABLE_SERIAL_PNP
--#define ENABLE_SERIAL_PNP
--#endif
--#endif
--
- #ifdef CONFIG_ARCH_PXA
- #define pxa_port(x) ((x) == PORT_PXA)
- #define pxa_buggy_port(x) ({ \
-@@ -149,39 +19,16 @@
- #undef SERIAL_DEBUG_OPEN
- #undef SERIAL_DEBUG_FLOW
- #undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
--#undef SERIAL_DEBUG_PCI
--#undef SERIAL_DEBUG_AUTOCONF
-
- /* Sanity checks */
-
--#ifdef CONFIG_SERIAL_MULTIPORT
--#ifndef CONFIG_SERIAL_SHARE_IRQ
--#define CONFIG_SERIAL_SHARE_IRQ
--#endif
--#endif
--
--#ifdef CONFIG_HUB6
--#ifndef CONFIG_SERIAL_MANY_PORTS
--#define CONFIG_SERIAL_MANY_PORTS
--#endif
--#ifndef CONFIG_SERIAL_SHARE_IRQ
--#define CONFIG_SERIAL_SHARE_IRQ
--#endif
--#endif
--
- #ifdef MODULE
- #undef CONFIG_SERIAL_CONSOLE
- #endif
-
--#define CONFIG_SERIAL_RSA
--
- #define RS_STROBE_TIME (10*HZ)
- #define RS_ISR_PASS_LIMIT 256
-
--#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
--#define SERIAL_INLINE
--#endif
--
- /*
- * End of serial driver configuration section.
- */
-@@ -213,53 +60,51 @@
- #include <linux/ioport.h>
- #include <linux/mm.h>
- #include <linux/slab.h>
--#if (LINUX_VERSION_CODE >= 131343)
- #include <linux/init.h>
--#endif
--#if (LINUX_VERSION_CODE >= 131336)
- #include <asm/uaccess.h>
--#endif
- #include <linux/delay.h>
- #ifdef CONFIG_SERIAL_CONSOLE
- #include <linux/console.h>
- #endif
--#ifdef ENABLE_SERIAL_PCI
--#include <linux/pci.h>
--#endif
--#ifdef ENABLE_SERIAL_PNP
--#include <linux/isapnp.h>
--#endif
- #ifdef CONFIG_MAGIC_SYSRQ
- #include <linux/sysrq.h>
- #endif
-
--/*
-- * All of the compatibilty code so we can compile serial.c against
-- * older kernels is hidden in serial_compat.h
-- */
--#if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */
--#include "serial_compat.h"
--#endif
--
- #include <asm/system.h>
- #include <asm/io.h>
- #include <asm/irq.h>
- #include <asm/bitops.h>
-
--#if defined(CONFIG_MAC_SERIAL)
--#define SERIAL_DEV_OFFSET ((_machine == _MACH_prep || _machine == _MACH_chrp) ? 0 : 2)
--#else
--#define SERIAL_DEV_OFFSET 0
--#endif
-+#define _INLINE_
-
--#ifdef SERIAL_INLINE
--#define _INLINE_ inline
-+/*
-+ * The TI16754 has 4 UARTS. They are selected with nCS3 and some
-+ * address bits:
-+ *
-+ * 12 8 4
-+ * nA8, nCS[3] for MN_UART_1, address mask 1110 1110 0000 0000 = 0xEE00
-+ * nA9, nCS[3] for MN_UART_1, address mask 1110 1101 0000 0000 = 0xED00
-+ * nA10, nCS[3] for MN_UART_1, address mask 1110 1011 0000 0000 = 0xEB00
-+ * nA11, nCS[3] for MN_UART_1, address mask 1110 0111 0000 0000 = 0xE700
-+ */
-+#define RAMSES_UARTA_PHYS (PXA_CS3_PHYS+0xEE00)
-+#define RAMSES_UARTB_PHYS (PXA_CS3_PHYS+0xED00)
-+#define RAMSES_UARTC_PHYS (PXA_CS3_PHYS+0xEB00)
-+#define RAMSES_UARTD_PHYS (PXA_CS3_PHYS+0xE700)
-+static void *ramses_uarta; // address cookie for UART A
-+static void *ramses_uartb; // address cookie for UART B
-+static void *ramses_uartc; // address cookie for UART C/Scanner
-+static void *ramses_uartd; // address cookie for UART D
-+static int ramses_stay_on = 0;
-+
-+#ifdef DEBUG
-+#define DPRINTK(fmt,args...) printk("//HS " fmt, ## args)
-+static int show_io = 1;
- #else
--#define _INLINE_
-+#define DPRINTK(fmt,args...)
-+static int show_io = 0;
- #endif
-
--static char *serial_name = "Serial driver";
--
- static DECLARE_TASK_QUEUE(tq_serial);
-
- static struct tty_driver serial_driver, callout_driver;
-@@ -282,9 +127,6 @@
- */
-
- static struct async_struct *IRQ_ports[NR_IRQS];
--#ifdef CONFIG_SERIAL_MULTIPORT
--static struct rs_multiport_struct rs_multiport[NR_IRQS];
--#endif
- static int IRQ_timeout[NR_IRQS];
- #ifdef CONFIG_SERIAL_CONSOLE
- static struct console sercons;
-@@ -294,8 +136,6 @@
- static unsigned long break_pressed; /* break, really ... */
- #endif
-
--static unsigned detect_uart_irq (struct serial_state * state);
--static void autoconfig(struct serial_state * state);
- static void change_speed(struct async_struct *info, struct termios *old);
- static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-
-@@ -325,46 +165,86 @@
- { 0, 0}
- };
-
--#if defined(CONFIG_SERIAL_RSA) && defined(MODULE)
--
--#define PORT_RSA_MAX 4
--static int probe_rsa[PORT_RSA_MAX];
--static int force_rsa[PORT_RSA_MAX];
--
--MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
--MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
--MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
--MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA");
--#endif /* CONFIG_SERIAL_RSA */
--
--struct serial_state rs_table[RS_TABLE_SIZE] = {
-- SERIAL_PORT_DFNS /* Defined in serial.h */
-+static struct serial_state rs_table[] = {
-+ {
-+ type: PORT_PXA,
-+ xmit_fifo_size: 32,
-+ baud_base: 921600,
-+ iomem_base: (void *)&FFUART,
-+ iomem_reg_shift: 2,
-+ io_type: SERIAL_IO_MEM32,
-+ irq: IRQ_FFUART,
-+ flags: ASYNC_SKIP_TEST,
-+ }, {
-+ type: PORT_PXA,
-+ xmit_fifo_size: 32,
-+ baud_base: 921600,
-+ iomem_base: (void *)&BTUART,
-+ iomem_reg_shift: 2,
-+ io_type: SERIAL_IO_MEM32,
-+ irq: IRQ_BTUART,
-+ flags: ASYNC_SKIP_TEST,
-+ }, {
-+ type: PORT_PXA,
-+ xmit_fifo_size: 32,
-+ baud_base: 921600,
-+ iomem_base: (void *)&STUART,
-+ iomem_reg_shift: 2,
-+ io_type: SERIAL_IO_MEM32,
-+ irq: IRQ_STUART,
-+ flags: ASYNC_SKIP_TEST,
-+ }, {
-+ type: PORT_16750,
-+ xmit_fifo_size: 64,
-+ baud_base: 115200*2,
-+ iomem_base: (void *)0,
-+ iomem_reg_shift: 2,
-+ io_type: SERIAL_IO_MEM,
-+ irq: IRQ_GPIO(7),
-+ flags: ASYNC_SKIP_TEST,
-+ }, {
-+ type: PORT_16750,
-+ xmit_fifo_size: 64,
-+ baud_base: 115200*2,
-+ iomem_base: (void *)0,
-+ iomem_reg_shift: 2,
-+ io_type: SERIAL_IO_MEM,
-+ irq: IRQ_GPIO(24),
-+ flags: ASYNC_SKIP_TEST,
-+ }, {
-+ type: PORT_16750,
-+ xmit_fifo_size: 64,
-+ baud_base: 115200*2,
-+ iomem_base: (void *)0,
-+ iomem_reg_shift: 2,
-+ io_type: SERIAL_IO_MEM,
-+ irq: IRQ_GPIO(25),
-+ flags: ASYNC_SKIP_TEST,
-+ }, {
-+ type: PORT_16750,
-+ xmit_fifo_size: 64,
-+ baud_base: 115200*2,
-+ iomem_base: (void *)0,
-+ iomem_reg_shift: 2,
-+ io_type: SERIAL_IO_MEM,
-+ irq: IRQ_GPIO(26),
-+ flags: ASYNC_SKIP_TEST,
-+ }, {
-+ type: PORT_UNKNOWN,
-+ baud_base: 115200,
-+ }, {
-+ type: PORT_UNKNOWN,
-+ baud_base: 115200,
-+ }, {
-+ type: PORT_UNKNOWN,
-+ baud_base: 115200,
-+ }, {
-+ type: PORT_UNKNOWN,
-+ baud_base: 115200,
-+ }
- };
-
- #define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state))
--int serial_nr_ports = NR_PORTS;
--
--#if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP))
--#define NR_PCI_BOARDS 8
--
--static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS];
--
--#ifndef IS_PCI_REGION_IOPORT
--#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
-- IORESOURCE_IO)
--#endif
--#ifndef IS_PCI_REGION_IOMEM
--#define IS_PCI_REGION_IOMEM(dev, r) (pci_resource_flags((dev), (r)) & \
-- IORESOURCE_MEM)
--#endif
--#ifndef PCI_IRQ_RESOURCE
--#define PCI_IRQ_RESOURCE(dev, r) ((dev)->irq_resource[r].start)
--#endif
--#ifndef pci_get_subvendor
--#define pci_get_subvendor(dev) ((dev)->subsystem_vendor)
--#define pci_get_subdevice(dev) ((dev)->subsystem_device)
--#endif
--#endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */
-
- #ifndef PREPARE_FUNC
- #define PREPARE_FUNC(dev) (dev->prepare)
-@@ -403,39 +283,21 @@
- #endif
-
-
--static inline int serial_paranoia_check(struct async_struct *info,
-- kdev_t device, const char *routine)
--{
--#ifdef SERIAL_PARANOIA_CHECK
-- static const char *badmagic =
-- "Warning: bad magic number for serial struct (%s) in %s\n";
-- static const char *badinfo =
-- "Warning: null async_struct for (%s) in %s\n";
--
-- if (!info) {
-- printk(badinfo, kdevname(device), routine);
-- return 1;
-- }
-- if (info->magic != SERIAL_MAGIC) {
-- printk(badmagic, kdevname(device), routine);
-- return 1;
-- }
--#endif
-- return 0;
--}
--
- static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset)
- {
-+ unsigned int value;
- switch (info->io_type) {
--#ifdef CONFIG_HUB6
-- case SERIAL_IO_HUB6:
-- outb(info->hub6 - 1 + offset, info->port);
-- return inb(info->port+1);
--#endif
- case SERIAL_IO_MEM:
-- return readb((unsigned long) info->iomem_base +
-+ value = readb((unsigned long) info->iomem_base +
- (offset<<info->iomem_reg_shift));
-+ udelay(10);
-+ if (show_io) printk("in %02x = %02x\n", offset, value);
-+ return value;
- case SERIAL_IO_MEM32:
-+ value = readl((unsigned long) info->iomem_base +
-+ (offset<<info->iomem_reg_shift));
-+ if (show_io) printk("in %02x = %02x\n", offset, value);
-+ return value;
- return readl((unsigned long) info->iomem_base +
- (offset<<info->iomem_reg_shift));
- default:
-@@ -447,17 +309,14 @@
- int value)
- {
- switch (info->io_type) {
--#ifdef CONFIG_HUB6
-- case SERIAL_IO_HUB6:
-- outb(info->hub6 - 1 + offset, info->port);
-- outb(value, info->port+1);
-- break;
--#endif
- case SERIAL_IO_MEM:
-+ if (show_io) printk("out %02x, %02x\n", offset, value);
- writeb(value, (unsigned long) info->iomem_base +
- (offset<<info->iomem_reg_shift));
-+ udelay(10);
- break;
- case SERIAL_IO_MEM32:
-+ if (show_io) printk("out %02x, %02x\n", offset, value);
- writel(value, (unsigned long) info->iomem_base +
- (offset<<info->iomem_reg_shift));
- break;
-@@ -509,9 +368,6 @@
- struct async_struct *info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
-
-- if (serial_paranoia_check(info, tty->device, "rs_stop"))
-- return;
--
- save_flags(flags); cli();
- if (info->IER & UART_IER_THRI) {
- info->IER &= ~UART_IER_THRI;
-@@ -529,9 +385,6 @@
- struct async_struct *info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
-
-- if (serial_paranoia_check(info, tty->device, "rs_start"))
-- return;
--
- save_flags(flags); cli();
- if (info->xmit.head != info->xmit.tail
- && info->xmit.buf
-@@ -689,11 +542,7 @@
- #endif
- *status = serial_inp(info, UART_LSR);
- } while ((*status & UART_LSR_DR) && (max_count-- > 0));
--#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
- tty_flip_buffer_push(tty);
--#else
-- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
--#endif
- }
-
- static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
-@@ -758,11 +607,6 @@
- icount->dsr++;
- if (status & UART_MSR_DDCD) {
- icount->dcd++;
--#ifdef CONFIG_HARD_PPS
-- if ((info->flags & ASYNC_HARDPPS_CD) &&
-- (status & UART_MSR_DCD))
-- hardpps();
--#endif
- }
- if (status & UART_MSR_DCTS)
- icount->cts++;
-@@ -810,120 +654,23 @@
- }
- }
-
--#ifdef CONFIG_SERIAL_SHARE_IRQ
--/*
-- * This is the serial driver's generic interrupt routine
-- */
--static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
--{
-- int status, iir;
-- struct async_struct * info;
-- int pass_counter = 0;
-- struct async_struct *end_mark = 0;
--#ifdef CONFIG_SERIAL_MULTIPORT
-- int first_multi = 0;
-- struct rs_multiport_struct *multi;
--#endif
--
--#ifdef SERIAL_DEBUG_INTR
-- printk("rs_interrupt(%d)...", irq);
--#endif
--
-- info = IRQ_ports[irq];
-- if (!info)
-- return;
--
--#ifdef CONFIG_SERIAL_MULTIPORT
-- multi = &rs_multiport[irq];
-- if (multi->port_monitor)
-- first_multi = inb(multi->port_monitor);
--#endif
--
-- do {
-- if (!info->tty ||
-- ((iir=serial_in(info, UART_IIR)) & UART_IIR_NO_INT)) {
-- if (!end_mark)
-- end_mark = info;
-- goto next;
-- }
--#ifdef SERIAL_DEBUG_INTR
-- printk("IIR = %x...", serial_in(info, UART_IIR));
--#endif
-- end_mark = 0;
--
-- info->last_active = jiffies;
--
-- status = serial_inp(info, UART_LSR);
--#ifdef SERIAL_DEBUG_INTR
-- printk("status = %x...", status);
--#endif
-- if (status & UART_LSR_DR)
-- receive_chars(info, &status, regs);
-- check_modem_status(info);
--#ifdef CONFIG_MELAN
-- if ((status & UART_LSR_THRE) ||
-- /* for buggy ELAN processors */
-- ((iir & UART_IIR_ID) == UART_IIR_THRI))
-- transmit_chars(info, 0);
--#else
-- if (status & UART_LSR_THRE)
-- transmit_chars(info, 0);
--#endif
--
-- next:
-- info = info->next_port;
-- if (!info) {
-- info = IRQ_ports[irq];
-- if (pass_counter++ > RS_ISR_PASS_LIMIT) {
--#if 0
-- printk("rs loop break\n");
--#endif
-- break; /* Prevent infinite loops */
-- }
-- continue;
-- }
-- } while (end_mark != info);
--#ifdef CONFIG_SERIAL_MULTIPORT
-- if (multi->port_monitor)
-- printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n",
-- info->state->irq, first_multi,
-- inb(multi->port_monitor));
--#endif
--#ifdef SERIAL_DEBUG_INTR
-- printk("end.\n");
--#endif
--}
--#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ */
--
-
- /*
- * This is the serial driver's interrupt routine for a single port
- */
- static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
- {
-- int status, iir;
-+ int status;
- int pass_counter = 0;
- struct async_struct * info;
--#ifdef CONFIG_SERIAL_MULTIPORT
-- int first_multi = 0;
-- struct rs_multiport_struct *multi;
--#endif
-
- #ifdef SERIAL_DEBUG_INTR
- printk("rs_interrupt_single(%d)...", irq);
- #endif
--
- info = IRQ_ports[irq];
- if (!info || !info->tty)
- return;
-
--#ifdef CONFIG_SERIAL_MULTIPORT
-- multi = &rs_multiport[irq];
-- if (multi->port_monitor)
-- first_multi = inb(multi->port_monitor);
--#endif
--
-- iir = serial_in(info, UART_IIR);
- do {
- status = serial_inp(info, UART_LSR);
- #ifdef SERIAL_DEBUG_INTR
-@@ -932,120 +679,23 @@
- if (status & UART_LSR_DR)
- receive_chars(info, &status, regs);
- check_modem_status(info);
-- if ((status & UART_LSR_THRE) ||
-- /* For buggy ELAN processors */
-- ((iir & UART_IIR_ID) == UART_IIR_THRI))
-+ if (status & UART_LSR_THRE)
- transmit_chars(info, 0);
- if (pass_counter++ > RS_ISR_PASS_LIMIT) {
--#if SERIAL_DEBUG_INTR
-+#if 0
- printk("rs_single loop break.\n");
- #endif
- break;
- }
-- iir = serial_in(info, UART_IIR);
--#ifdef SERIAL_DEBUG_INTR
-- printk("IIR = %x...", iir);
--#endif
-- } while ((iir & UART_IIR_NO_INT) == 0);
-- info->last_active = jiffies;
--#ifdef CONFIG_SERIAL_MULTIPORT
-- if (multi->port_monitor)
-- printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n",
-- info->state->irq, first_multi,
-- inb(multi->port_monitor));
--#endif
--#ifdef SERIAL_DEBUG_INTR
-- printk("end.\n");
--#endif
--}
--
--#ifdef CONFIG_SERIAL_MULTIPORT
--/*
-- * This is the serial driver's for multiport boards
-- */
--static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
--{
-- int status;
-- struct async_struct * info;
-- int pass_counter = 0;
-- int first_multi= 0;
-- struct rs_multiport_struct *multi;
--
- #ifdef SERIAL_DEBUG_INTR
-- printk("rs_interrupt_multi(%d)...", irq);
-+ printk("IIR = %x...", serial_in(info, UART_IIR));
- #endif
--
-- info = IRQ_ports[irq];
-- if (!info)
-- return;
-- multi = &rs_multiport[irq];
-- if (!multi->port1) {
-- /* Should never happen */
-- printk("rs_interrupt_multi: NULL port1!\n");
-- return;
-- }
-- if (multi->port_monitor)
-- first_multi = inb(multi->port_monitor);
--
-- while (1) {
-- if (!info->tty ||
-- (serial_in(info, UART_IIR) & UART_IIR_NO_INT))
-- goto next;
--
-+ } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
- info->last_active = jiffies;
--
-- status = serial_inp(info, UART_LSR);
--#ifdef SERIAL_DEBUG_INTR
-- printk("status = %x...", status);
--#endif
-- if (status & UART_LSR_DR)
-- receive_chars(info, &status, regs);
-- check_modem_status(info);
-- if (status & UART_LSR_THRE)
-- transmit_chars(info, 0);
--
-- next:
-- info = info->next_port;
-- if (info)
-- continue;
--
-- info = IRQ_ports[irq];
-- /*
-- * The user was a bonehead, and misconfigured their
-- * multiport info. Rather than lock up the kernel
-- * in an infinite loop, if we loop too many times,
-- * print a message and break out of the loop.
-- */
-- if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-- printk("Misconfigured multiport serial info "
-- "for irq %d. Breaking out irq loop\n", irq);
-- break;
-- }
-- if (multi->port_monitor)
-- printk("rs port monitor irq %d: 0x%x, 0x%x\n",
-- info->state->irq, first_multi,
-- inb(multi->port_monitor));
-- if ((inb(multi->port1) & multi->mask1) != multi->match1)
-- continue;
-- if (!multi->port2)
-- break;
-- if ((inb(multi->port2) & multi->mask2) != multi->match2)
-- continue;
-- if (!multi->port3)
-- break;
-- if ((inb(multi->port3) & multi->mask3) != multi->match3)
-- continue;
-- if (!multi->port4)
-- break;
-- if ((inb(multi->port4) & multi->mask4) != multi->match4)
-- continue;
-- break;
-- }
- #ifdef SERIAL_DEBUG_INTR
- printk("end.\n");
- #endif
- }
--#endif
-
- /*
- * -------------------------------------------------------------------
-@@ -1107,22 +757,6 @@
- if (!info)
- continue;
- save_flags(flags); cli();
--#ifdef CONFIG_SERIAL_SHARE_IRQ
-- if (info->next_port) {
-- do {
-- serial_out(info, UART_IER, 0);
-- info->IER |= UART_IER_THRI;
-- serial_out(info, UART_IER, info->IER);
-- info = info->next_port;
-- } while (info);
--#ifdef CONFIG_SERIAL_MULTIPORT
-- if (rs_multiport[i].port1)
-- rs_interrupt_multi(i, NULL, NULL);
-- else
--#endif
-- rs_interrupt(i, NULL, NULL);
-- } else
--#endif /* CONFIG_SERIAL_SHARE_IRQ */
- rs_interrupt_single(i, NULL, NULL);
- restore_flags(flags);
- }
-@@ -1132,11 +766,7 @@
-
- if (IRQ_ports[0]) {
- save_flags(flags); cli();
--#ifdef CONFIG_SERIAL_SHARE_IRQ
-- rs_interrupt(0, NULL, NULL);
--#else
- rs_interrupt_single(0, NULL, NULL);
--#endif
- restore_flags(flags);
-
- mod_timer(&serial_timer, jiffies + IRQ_timeout[0]);
-@@ -1177,50 +807,6 @@
- IRQ_timeout[irq] = (timeout > 3) ? timeout-2 : 1;
- }
-
--#ifdef CONFIG_SERIAL_RSA
--/* Attempts to turn on the RSA FIFO. Returns zero on failure */
--static int enable_rsa(struct async_struct *info)
--{
-- unsigned char mode;
-- int result;
-- unsigned long flags;
--
-- save_flags(flags); cli();
-- mode = serial_inp(info, UART_RSA_MSR);
-- result = mode & UART_RSA_MSR_FIFO;
--
-- if (!result) {
-- serial_outp(info, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
-- mode = serial_inp(info, UART_RSA_MSR);
-- result = mode & UART_RSA_MSR_FIFO;
-- }
--
-- restore_flags(flags);
-- return result;
--}
--
--/* Attempts to turn off the RSA FIFO. Returns zero on failure */
--static int disable_rsa(struct async_struct *info)
--{
-- unsigned char mode;
-- int result;
-- unsigned long flags;
--
-- save_flags(flags); cli();
-- mode = serial_inp(info, UART_RSA_MSR);
-- result = !(mode & UART_RSA_MSR_FIFO);
--
-- if (!result) {
-- serial_outp(info, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
-- mode = serial_inp(info, UART_RSA_MSR);
-- result = !(mode & UART_RSA_MSR_FIFO);
-- }
--
-- restore_flags(flags);
-- return result;
--}
--#endif /* CONFIG_SERIAL_RSA */
--
- static int startup(struct async_struct * info)
- {
- unsigned long flags;
-@@ -1228,9 +814,6 @@
- void (*handler)(int, void *, struct pt_regs *);
- struct serial_state *state= info->state;
- unsigned long page;
--#ifdef CONFIG_SERIAL_MANY_PORTS
-- unsigned short ICP;
--#endif
-
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
-@@ -1258,6 +841,22 @@
- printk("starting up ttys%d (irq %d)...", info->line, state->irq);
- #endif
-
-+ // Special handling to give power to devices
-+ switch (info->line) {
-+ case 3:
-+ //printk("gsm on\n");
-+ RAMSES_GSM_ON();
-+ break;
-+ case 4:
-+ //printk("uart on\n");
-+ RAMSES_UART_ON();
-+ break;
-+ case 5:
-+ //printk("scanner on\n");
-+ RAMSES_SCANNER_ON();
-+ break;
-+ }
-+
- if (uart_config[state->type].flags & UART_STARTECH) {
- /* Wake up UART */
- serial_outp(info, UART_LCR, 0xBF);
-@@ -1305,25 +904,12 @@
- serial_outp(info, UART_LCR, 0);
- }
-
--#ifdef CONFIG_SERIAL_RSA
-- /*
-- * If this is an RSA port, see if we can kick it up to the
-- * higher speed clock.
-- */
-- if (state->type == PORT_RSA) {
-- if (state->baud_base != SERIAL_RSA_BAUD_BASE &&
-- enable_rsa(info))
-- state->baud_base = SERIAL_RSA_BAUD_BASE;
-- if (state->baud_base == SERIAL_RSA_BAUD_BASE)
-- serial_outp(info, UART_RSA_FRR, 0);
-- }
--#endif
--
- #ifdef CONFIG_ARCH_PXA
- if (state->type == PORT_PXA) {
- switch ((long)state->iomem_base) {
- case (long)&FFUART: CKEN |= CKEN6_FFUART; break;
- case (long)&BTUART: CKEN |= CKEN7_BTUART; break;
-+ //HS TODO: cerf keeps the clock on
- case (long)&STUART: CKEN |= CKEN5_STUART; break;
- }
- }
-@@ -1344,6 +930,7 @@
- /*
- * Clear the interrupt registers.
- */
-+ (void) serial_inp(info, UART_IIR);
- (void) serial_inp(info, UART_LSR);
- (void) serial_inp(info, UART_RX);
- (void) serial_inp(info, UART_IIR);
-@@ -1371,18 +958,8 @@
- if (state->irq && (!IRQ_ports[state->irq] ||
- !IRQ_ports[state->irq]->next_port)) {
- if (IRQ_ports[state->irq]) {
--#ifdef CONFIG_SERIAL_SHARE_IRQ
-- free_irq(state->irq, &IRQ_ports[state->irq]);
--#ifdef CONFIG_SERIAL_MULTIPORT
-- if (rs_multiport[state->irq].port1)
-- handler = rs_interrupt_multi;
-- else
--#endif
-- handler = rs_interrupt;
--#else
- retval = -EBUSY;
- goto errout;
--#endif /* CONFIG_SERIAL_SHARE_IRQ */
- } else
- handler = rs_interrupt_single;
-
-@@ -1417,12 +994,6 @@
- info->MCR = 0;
- if (info->tty->termios->c_cflag & CBAUD)
- info->MCR = UART_MCR_DTR | UART_MCR_RTS;
--#ifdef CONFIG_SERIAL_MANY_PORTS
-- if (info->flags & ASYNC_FOURPORT) {
-- if (state->irq == 0)
-- info->MCR |= UART_MCR_OUT1;
-- } else
--#endif
- {
- if (state->irq != 0)
- info->MCR |= UART_MCR_OUT2;
-@@ -1437,18 +1008,9 @@
- */
- info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
- if (pxa_port(state->type))
-- info->IER |= UART_IER_UUE | UART_IER_RTOIE;
-+ info->IER |= UART_IER_UUE | UART_IER_RTOIE; //HS TODO: UART_IER_THRI for PXA uarts?
- serial_outp(info, UART_IER, info->IER); /* enable interrupts */
-
--#ifdef CONFIG_SERIAL_MANY_PORTS
-- if (info->flags & ASYNC_FOURPORT) {
-- /* Enable interrupts on the AST Fourport board */
-- ICP = (info->port & 0xFE0) | 0x01F;
-- outb_p(0x80, ICP);
-- (void) inb_p(ICP);
-- }
--#endif
--
- /*
- * And clear the interrupt registers again for luck.
- */
-@@ -1469,7 +1031,6 @@
- /*
- * Set up the tty->alt_speed kludge
- */
--#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
- if (info->tty) {
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- info->tty->alt_speed = 57600;
-@@ -1480,7 +1041,6 @@
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
- info->tty->alt_speed = 460800;
- }
--#endif
-
- /*
- * and set the speed of the serial port
-@@ -1516,6 +1076,30 @@
- state->irq);
- #endif
-
-+ switch (info->line) {
-+ case 3:
-+ if (ramses_stay_on & RAMSES_CONTROL_GSM_PWR) {
-+ //printk("gsm on\n");
-+ RAMSES_GSM_OFF();
-+ }
-+ //else printk("gsm stays on\n");
-+ break;
-+ case 4:
-+ if (ramses_stay_on & RAMSES_CONTROL_UART_PWR) {
-+ //printk("uart off\n");
-+ RAMSES_UART_OFF();
-+ }
-+ //else printk("uart stays on\n");
-+ break;
-+ case 5:
-+ if (ramses_stay_on & RAMSES_CONTROL_SCANNER_PWR) {
-+ //printk("scanner off\n");
-+ RAMSES_SCANNER_OFF();
-+ }
-+ //else printk("scanner on\n");
-+ break;
-+ }
-+
- save_flags(flags); cli(); /* Disable interrupts */
-
- /*
-@@ -1561,13 +1145,6 @@
-
- info->IER = 0;
- serial_outp(info, UART_IER, 0x00); /* disable all intrs */
--#ifdef CONFIG_SERIAL_MANY_PORTS
-- if (info->flags & ASYNC_FOURPORT) {
-- /* reset interrupts on the AST Fourport board */
-- (void) inb((info->port & 0xFE0) | 0x01F);
-- info->MCR |= UART_MCR_OUT1;
-- } else
--#endif
- info->MCR &= ~UART_MCR_OUT2;
- if (pxa_buggy_port(state->type))
- info->MCR ^= UART_MCR_OUT2;
-@@ -1586,16 +1163,6 @@
- UART_FCR_CLEAR_XMIT));
- serial_outp(info, UART_FCR, 0);
-
--#ifdef CONFIG_SERIAL_RSA
-- /*
-- * Reset the RSA board back to 115kbps compat mode.
-- */
-- if ((state->type == PORT_RSA) &&
-- (state->baud_base == SERIAL_RSA_BAUD_BASE &&
-- disable_rsa(info)))
-- state->baud_base = SERIAL_RSA_BAUD_BASE_LO;
--#endif
--
- #ifdef CONFIG_ARCH_PXA
- if (state->type == PORT_PXA
- #ifdef CONFIG_SERIAL_CONSOLE
-@@ -1634,37 +1201,6 @@
- restore_flags(flags);
- }
-
--#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
--static int baud_table[] = {
-- 0, 50, 75, 110, 134, 150, 200, 300,
-- 600, 1200, 1800, 2400, 4800, 9600, 19200,
-- 38400, 57600, 115200, 230400, 460800, 0 };
--
--static int tty_get_baud_rate(struct tty_struct *tty)
--{
-- struct async_struct * info = (struct async_struct *)tty->driver_data;
-- unsigned int cflag, i;
--
-- cflag = tty->termios->c_cflag;
--
-- i = cflag & CBAUD;
-- if (i & CBAUDEX) {
-- i &= ~CBAUDEX;
-- if (i < 1 || i > 2)
-- tty->termios->c_cflag &= ~CBAUDEX;
-- else
-- i += 15;
-- }
-- if (i == 15) {
-- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-- i += 1;
-- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-- i += 2;
-- }
-- return baud_table[i];
--}
--#endif
--
- /*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
-@@ -1711,12 +1247,6 @@
- baud = tty_get_baud_rate(info->tty);
- if (!baud)
- baud = 9600; /* B0 transition handled in rs_set_termios */
--#ifdef CONFIG_SERIAL_RSA
-- if ((info->state->type == PORT_RSA) &&
-- (info->state->baud_base != SERIAL_RSA_BAUD_BASE) &&
-- enable_rsa(info))
-- info->state->baud_base = SERIAL_RSA_BAUD_BASE;
--#endif
- baud_base = info->state->baud_base;
- if (info->state->type == PORT_16C950) {
- if (baud <= baud_base)
-@@ -1778,10 +1308,6 @@
- if (uart_config[info->state->type].flags & UART_USE_FIFO) {
- if ((info->state->baud_base / quot) < 2400)
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
--#ifdef CONFIG_SERIAL_RSA
-- else if (info->state->type == PORT_RSA)
-- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
--#endif
- else
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
- }
-@@ -1864,9 +1390,6 @@
- struct async_struct *info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
-
-- if (serial_paranoia_check(info, tty->device, "rs_put_char"))
-- return;
--
- if (!tty || !info->xmit.buf)
- return;
-
-@@ -1888,9 +1411,6 @@
- struct async_struct *info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
-
-- if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
-- return;
--
- if (info->xmit.head == info->xmit.tail
- || tty->stopped
- || tty->hw_stopped
-@@ -1900,8 +1420,6 @@
- save_flags(flags); cli();
- info->IER |= UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
-- if (pxa_buggy_port(info->state->type))
-- rs_interrupt_single(info->state->irq, NULL, NULL);
- restore_flags(flags);
- }
-
-@@ -1912,9 +1430,6 @@
- struct async_struct *info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
-
-- if (serial_paranoia_check(info, tty->device, "rs_write"))
-- return 0;
--
- if (!tty || !info->xmit.buf || !tmp_buf)
- return 0;
-
-@@ -1978,11 +1493,6 @@
- && !(info->IER & UART_IER_THRI)) {
- info->IER |= UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
-- if (pxa_buggy_port(info->state->type)) {
-- save_flags(flags); cli();
-- rs_interrupt_single(info->state->irq, NULL, NULL);
-- restore_flags(flags);
-- }
- }
- return ret;
- }
-@@ -1991,8 +1501,6 @@
- {
- struct async_struct *info = (struct async_struct *)tty->driver_data;
-
-- if (serial_paranoia_check(info, tty->device, "rs_write_room"))
-- return 0;
- return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
- }
-
-@@ -2000,8 +1508,6 @@
- {
- struct async_struct *info = (struct async_struct *)tty->driver_data;
-
-- if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
-- return 0;
- return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
- }
-
-@@ -2010,8 +1516,6 @@
- struct async_struct *info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
-
-- if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
-- return;
- save_flags(flags); cli();
- info->xmit.head = info->xmit.tail = 0;
- restore_flags(flags);
-@@ -2032,16 +1536,11 @@
- {
- struct async_struct *info = (struct async_struct *)tty->driver_data;
-
-- if (serial_paranoia_check(info, tty->device, "rs_send_char"))
-- return;
--
- info->x_char = ch;
- if (ch) {
- /* Make sure transmit interrupts are on */
- info->IER |= UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
-- if (pxa_buggy_port(info->state->type))
-- rs_interrupt_single(info->state->irq, NULL, NULL);
- }
- }
-
-@@ -2064,9 +1563,6 @@
- tty->ldisc.chars_in_buffer(tty));
- #endif
-
-- if (serial_paranoia_check(info, tty->device, "rs_throttle"))
-- return;
--
- if (I_IXOFF(tty))
- rs_send_xchar(tty, STOP_CHAR(tty));
-
-@@ -2089,9 +1585,6 @@
- tty->ldisc.chars_in_buffer(tty));
- #endif
-
-- if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
-- return;
--
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
-@@ -2134,7 +1627,6 @@
- tmp.close_delay = state->close_delay;
- tmp.closing_wait = state->closing_wait;
- tmp.custom_divisor = state->custom_divisor;
-- tmp.hub6 = state->hub6;
- tmp.io_type = state->io_type;
- if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
- return -EFAULT;
-@@ -2160,8 +1652,7 @@
- new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
-
- change_irq = new_serial.irq != state->irq;
-- change_port = (new_port != ((int) state->port)) ||
-- (new_serial.hub6 != state->hub6);
-+ change_port = (new_port != ((int) state->port));
-
- if (!capable(CAP_SYS_ADMIN)) {
- if (change_irq || change_port ||
-@@ -2198,7 +1689,6 @@
- if (new_serial.type) {
- for (i = 0 ; i < NR_PORTS; i++)
- if ((state != &rs_table[i]) &&
-- (rs_table[i].io_type == SERIAL_IO_PORT) &&
- (rs_table[i].port == new_port) &&
- rs_table[i].type)
- return -EADDRINUSE;
-@@ -2220,18 +1710,11 @@
- state->custom_divisor = new_serial.custom_divisor;
- state->close_delay = new_serial.close_delay * HZ/100;
- state->closing_wait = new_serial.closing_wait * HZ/100;
--#if (LINUX_VERSION_CODE > 0x20100)
- info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
--#endif
- info->xmit_fifo_size = state->xmit_fifo_size =
- new_serial.xmit_fifo_size;
-
- if ((state->type != PORT_UNKNOWN) && state->port) {
--#ifdef CONFIG_SERIAL_RSA
-- if (old_state.type == PORT_RSA)
-- release_region(state->port + UART_RSA_BASE, 16);
-- else
--#endif
- release_region(state->port,8);
- }
- state->type = new_serial.type;
-@@ -2243,31 +1726,19 @@
- shutdown(info);
- state->irq = new_serial.irq;
- info->port = state->port = new_port;
-- info->hub6 = state->hub6 = new_serial.hub6;
-- if (info->hub6)
-- info->io_type = state->io_type = SERIAL_IO_HUB6;
-- else if (info->io_type == SERIAL_IO_HUB6)
-- info->io_type = state->io_type = SERIAL_IO_PORT;
- }
- if ((state->type != PORT_UNKNOWN) && state->port) {
--#ifdef CONFIG_SERIAL_RSA
-- if (state->type == PORT_RSA)
-- request_region(state->port + UART_RSA_BASE,
-- 16, "serial_rsa(set)");
-- else
--#endif
- request_region(state->port,8,"serial(set)");
- }
-
-
- check_and_exit:
-- if ((!state->port && !state->iomem_base) || !state->type)
-+ if (!state->port || !state->type)
- return 0;
- if (info->flags & ASYNC_INITIALIZED) {
- if (((old_state.flags & ASYNC_SPD_MASK) !=
- (state->flags & ASYNC_SPD_MASK)) ||
- (old_state.custom_divisor != state->custom_divisor)) {
--#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
- if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- info->tty->alt_speed = 57600;
- if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-@@ -2276,7 +1747,6 @@
- info->tty->alt_speed = 230400;
- if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
- info->tty->alt_speed = 460800;
--#endif
- change_speed(info, 0);
- }
- } else
-@@ -2414,60 +1884,14 @@
- return 0;
- }
-
--static int do_autoconfig(struct async_struct * info)
--{
-- int irq, retval;
--
-- if (!capable(CAP_SYS_ADMIN))
-- return -EPERM;
--
-- if (info->state->count > 1)
-- return -EBUSY;
--
-- shutdown(info);
--
-- autoconfig(info->state);
-- if ((info->state->flags & ASYNC_AUTO_IRQ) &&
-- (info->state->port != 0 || info->state->iomem_base != 0) &&
-- (info->state->type != PORT_UNKNOWN)) {
-- irq = detect_uart_irq(info->state);
-- if (irq > 0)
-- info->state->irq = irq;
-- }
--
-- retval = startup(info);
-- if (retval)
-- return retval;
-- return 0;
--}
--
- /*
- * rs_break() --- routine which turns the break handling on or off
- */
--#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
--static void send_break( struct async_struct * info, int duration)
--{
-- if (!CONFIGURED_SERIAL_PORT(info))
-- return;
-- current->state = TASK_INTERRUPTIBLE;
-- current->timeout = jiffies + duration;
-- cli();
-- info->LCR |= UART_LCR_SBC;
-- serial_out(info, UART_LCR, info->LCR);
-- schedule();
-- info->LCR &= ~UART_LCR_SBC;
-- serial_out(info, UART_LCR, info->LCR);
-- sti();
--}
--#else
- static void rs_break(struct tty_struct *tty, int break_state)
- {
- struct async_struct * info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
-
-- if (serial_paranoia_check(info, tty->device, "rs_break"))
-- return;
--
- if (!CONFIGURED_SERIAL_PORT(info))
- return;
- save_flags(flags); cli();
-@@ -2478,121 +1902,6 @@
- serial_out(info, UART_LCR, info->LCR);
- restore_flags(flags);
- }
--#endif
--
--#ifdef CONFIG_SERIAL_MULTIPORT
--static int get_multiport_struct(struct async_struct * info,
-- struct serial_multiport_struct *retinfo)
--{
-- struct serial_multiport_struct ret;
-- struct rs_multiport_struct *multi;
--
-- multi = &rs_multiport[info->state->irq];
--
-- ret.port_monitor = multi->port_monitor;
--
-- ret.port1 = multi->port1;
-- ret.mask1 = multi->mask1;
-- ret.match1 = multi->match1;
--
-- ret.port2 = multi->port2;
-- ret.mask2 = multi->mask2;
-- ret.match2 = multi->match2;
--
-- ret.port3 = multi->port3;
-- ret.mask3 = multi->mask3;
-- ret.match3 = multi->match3;
--
-- ret.port4 = multi->port4;
-- ret.mask4 = multi->mask4;
-- ret.match4 = multi->match4;
--
-- ret.irq = info->state->irq;
--
-- if (copy_to_user(retinfo,&ret,sizeof(*retinfo)))
-- return -EFAULT;
-- return 0;
--}
--
--static int set_multiport_struct(struct async_struct * info,
-- struct serial_multiport_struct *in_multi)
--{
-- struct serial_multiport_struct new_multi;
-- struct rs_multiport_struct *multi;
-- struct serial_state *state;
-- int was_multi, now_multi;
-- int retval;
-- void (*handler)(int, void *, struct pt_regs *);
--
-- if (!capable(CAP_SYS_ADMIN))
-- return -EPERM;
-- state = info->state;
--
-- if (copy_from_user(&new_multi, in_multi,
-- sizeof(struct serial_multiport_struct)))
-- return -EFAULT;
--
-- if (new_multi.irq != state->irq || state->irq == 0 ||
-- !IRQ_ports[state->irq])
-- return -EINVAL;
--
-- multi = &rs_multiport[state->irq];
-- was_multi = (multi->port1 != 0);
--
-- multi->port_monitor = new_multi.port_monitor;
--
-- if (multi->port1)
-- release_region(multi->port1,1);
-- multi->port1 = new_multi.port1;
-- multi->mask1 = new_multi.mask1;
-- multi->match1 = new_multi.match1;
-- if (multi->port1)
-- request_region(multi->port1,1,"serial(multiport1)");
--
-- if (multi->port2)
-- release_region(multi->port2,1);
-- multi->port2 = new_multi.port2;
-- multi->mask2 = new_multi.mask2;
-- multi->match2 = new_multi.match2;
-- if (multi->port2)
-- request_region(multi->port2,1,"serial(multiport2)");
--
-- if (multi->port3)
-- release_region(multi->port3,1);
-- multi->port3 = new_multi.port3;
-- multi->mask3 = new_multi.mask3;
-- multi->match3 = new_multi.match3;
-- if (multi->port3)
-- request_region(multi->port3,1,"serial(multiport3)");
--
-- if (multi->port4)
-- release_region(multi->port4,1);
-- multi->port4 = new_multi.port4;
-- multi->mask4 = new_multi.mask4;
-- multi->match4 = new_multi.match4;
-- if (multi->port4)
-- request_region(multi->port4,1,"serial(multiport4)");
--
-- now_multi = (multi->port1 != 0);
--
-- if (IRQ_ports[state->irq]->next_port &&
-- (was_multi != now_multi)) {
-- free_irq(state->irq, &IRQ_ports[state->irq]);
-- if (now_multi)
-- handler = rs_interrupt_multi;
-- else
-- handler = rs_interrupt;
--
-- retval = request_irq(state->irq, handler, SA_SHIRQ,
-- "serial", &IRQ_ports[state->irq]);
-- if (retval) {
-- printk("Couldn't reallocate serial interrupt "
-- "driver!!\n");
-- }
-- }
-- return 0;
--}
--#endif
-
- static int rs_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg)
-@@ -2601,12 +1910,6 @@
- struct async_icount cprev, cnow; /* kernel counter temps */
- struct serial_icounter_struct icount;
- unsigned long flags;
--#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
-- int retval, tmp;
--#endif
--
-- if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
-- return -ENODEV;
-
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
-@@ -2616,45 +1919,6 @@
- }
-
- switch (cmd) {
--#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
-- case TCSBRK: /* SVID version: non-zero arg --> no break */
-- retval = tty_check_change(tty);
-- if (retval)
-- return retval;
-- tty_wait_until_sent(tty, 0);
-- if (signal_pending(current))
-- return -EINTR;
-- if (!arg) {
-- send_break(info, HZ/4); /* 1/4 second */
-- if (signal_pending(current))
-- return -EINTR;
-- }
-- return 0;
-- case TCSBRKP: /* support for POSIX tcsendbreak() */
-- retval = tty_check_change(tty);
-- if (retval)
-- return retval;
-- tty_wait_until_sent(tty, 0);
-- if (signal_pending(current))
-- return -EINTR;
-- send_break(info, arg ? arg*(HZ/10) : HZ/4);
-- if (signal_pending(current))
-- return -EINTR;
-- return 0;
-- case TIOCGSOFTCAR:
-- tmp = C_CLOCAL(tty) ? 1 : 0;
-- if (copy_to_user((void *)arg, &tmp, sizeof(int)))
-- return -EFAULT;
-- return 0;
-- case TIOCSSOFTCAR:
-- if (copy_from_user(&tmp, (void *)arg, sizeof(int)))
-- return -EFAULT;
--
-- tty->termios->c_cflag =
-- ((tty->termios->c_cflag & ~CLOCAL) |
-- (tmp ? CLOCAL : 0));
-- return 0;
--#endif
- case TIOCMGET:
- return get_modem_info(info, (unsigned int *) arg);
- case TIOCMBIS:
-@@ -2667,9 +1931,6 @@
- case TIOCSSERIAL:
- return set_serial_info(info,
- (struct serial_struct *) arg);
-- case TIOCSERCONFIG:
-- return do_autoconfig(info);
--
- case TIOCSERGETLSR: /* Get line status register */
- return get_lsr_info(info, (unsigned int *) arg);
-
-@@ -2679,15 +1940,6 @@
- return -EFAULT;
- return 0;
-
--#ifdef CONFIG_SERIAL_MULTIPORT
-- case TIOCSERGETMULTI:
-- return get_multiport_struct(info,
-- (struct serial_multiport_struct *) arg);
-- case TIOCSERSETMULTI:
-- return set_multiport_struct(info,
-- (struct serial_multiport_struct *) arg);
--#endif
--
- /*
- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
- * - mask passed in arg for lines of interest
-@@ -2754,6 +2006,39 @@
- printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
- return 0;
-
-+ case TIOCSERSETMULTI:
-+ switch (arg) {
-+
-+ // switch devices on
-+ case 2: RAMSES_LCD_BLIGHT_ON(); break;
-+ case 3: RAMSES_GSM_ON(); break;
-+ case 4: RAMSES_UART_ON(); break;
-+ case 5: RAMSES_SCANNER_ON(); break;
-+ case 7: RAMSES_SCANNER_WAKE_ON(); break;
-+ case 8: RAMSES_SCANNER_TRIG_ON(); break;
-+ case 9: RAMSES_GSM_RESET_ON(); break;
-+
-+ // switch devices off
-+ case 12: RAMSES_LCD_BLIGHT_OFF(); break;
-+ case 13: RAMSES_GSM_OFF(); break;
-+ case 14: RAMSES_UART_OFF(); break;
-+ case 15: RAMSES_SCANNER_OFF(); break;
-+ case 17: RAMSES_SCANNER_WAKE_OFF(); break;
-+ case 18: RAMSES_SCANNER_TRIG_OFF(); break;
-+ case 19: RAMSES_GSM_RESET_OFF(); break;
-+
-+ // disable automatic poweroff on file-handle close
-+ case 23: ramses_stay_on |= RAMSES_CONTROL_GSM_PWR; break;
-+ case 24: ramses_stay_on |= RAMSES_CONTROL_UART_PWR; break;
-+ case 25: ramses_stay_on |= RAMSES_CONTROL_SCANNER_PWR; break;
-+
-+ // enable automatic poweroff on file-handle close
-+ case 33: ramses_stay_on &= ~RAMSES_CONTROL_GSM_PWR; break;
-+ case 34: ramses_stay_on &= ~RAMSES_CONTROL_UART_PWR; break;
-+ case 35: ramses_stay_on &= ~RAMSES_CONTROL_SCANNER_PWR; break;
-+ }
-+ return 0;
-+
- default:
- return -ENOIOCTLCMD;
- }
-@@ -2801,18 +2086,6 @@
- tty->hw_stopped = 0;
- rs_start(tty);
- }
--
--#if 0
-- /*
-- * No need to wake up processes in open wait, since they
-- * sample the CLOCAL flag once, and don't recheck it.
-- * XXX It's not clear whether the current behavior is correct
-- * or not. Hence, this may change.....
-- */
-- if (!(old_termios->c_cflag & CLOCAL) &&
-- (tty->termios->c_cflag & CLOCAL))
-- wake_up_interruptible(&info->open_wait);
--#endif
- }
-
- /*
-@@ -2831,9 +2104,6 @@
- struct serial_state *state;
- unsigned long flags;
-
-- if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
-- return;
--
- state = info->state;
-
- save_flags(flags); cli();
-@@ -2933,10 +2203,7 @@
- {
- struct async_struct * info = (struct async_struct *)tty->driver_data;
- unsigned long orig_jiffies, char_time;
-- int lsr;
--
-- if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
-- return;
-+ int lsr, old_show_io;
-
- if (info->state->type == PORT_UNKNOWN)
- return;
-@@ -2974,9 +2241,11 @@
- printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
- printk("jiff=%lu...", jiffies);
- #endif
-+ old_show_io = show_io;
-+ show_io = 0;
- while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) {
- #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-- printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
-+ printk("lsr = %02x (jiff=%lu)...", lsr, jiffies);
- #endif
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(char_time);
-@@ -2986,8 +2255,9 @@
- break;
- }
- #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-- printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
-+ printk("lsr = %02x (jiff=%lu)...done\n", lsr, jiffies);
- #endif
-+ show_io = old_show_io;
- }
-
- /*
-@@ -2998,9 +2268,6 @@
- struct async_struct * info = (struct async_struct *)tty->driver_data;
- struct serial_state *state = info->state;
-
-- if (serial_paranoia_check(info, tty->device, "rs_hangup"))
-- return;
--
- state = info->state;
-
- rs_flush_buffer(tty);
-@@ -3036,12 +2303,8 @@
- (info->flags & ASYNC_CLOSING)) {
- if (info->flags & ASYNC_CLOSING)
- interruptible_sleep_on(&info->close_wait);
--#ifdef SERIAL_DO_RESTART
- return ((info->flags & ASYNC_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
--#else
-- return -EAGAIN;
--#endif
- }
-
- /*
-@@ -3114,14 +2377,10 @@
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(info->flags & ASYNC_INITIALIZED)) {
--#ifdef SERIAL_DO_RESTART
- if (info->flags & ASYNC_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
--#else
-- retval = -EAGAIN;
--#endif
- break;
- }
- if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-@@ -3223,16 +2482,12 @@
- }
- tty->driver_data = info;
- info->tty = tty;
-- if (serial_paranoia_check(info, tty->device, "rs_open"))
-- return -ENODEV;
-
- #ifdef SERIAL_DEBUG_OPEN
- printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
- info->state->count);
- #endif
--#if (LINUX_VERSION_CODE > 0x20100)
- info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
--#endif
-
- /*
- * This relies on lock_kernel() stuff so wants tidying for 2.5
-@@ -3254,12 +2509,8 @@
- (info->flags & ASYNC_CLOSING)) {
- if (info->flags & ASYNC_CLOSING)
- interruptible_sleep_on(&info->close_wait);
--#ifdef SERIAL_DO_RESTART
- return ((info->flags & ASYNC_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
--#else
-- return -EAGAIN;
--#endif
- }
-
- /*
-@@ -3313,17 +2564,14 @@
- int ret;
- unsigned long flags;
-
-- /*
-- * Return zero characters for ports not claimed by driver.
-- */
-- if (state->type == PORT_UNKNOWN) {
-- return 0; /* ignore unused ports */
-- }
--
- ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d",
- state->line, uart_config[state->type].name,
-- (state->port ? state->port : (long)state->iomem_base),
-- state->irq);
-+ state->port, state->irq);
-+
-+ if (!state->port || (state->type == PORT_UNKNOWN)) {
-+ ret += sprintf(buf+ret, "\n");
-+ return ret;
-+ }
-
- /*
- * Figure out the current RS-232 lines
-@@ -3334,7 +2582,6 @@
- info->magic = SERIAL_MAGIC;
- info->port = state->port;
- info->flags = state->flags;
-- info->hub6 = state->hub6;
- info->io_type = state->io_type;
- info->iomem_base = state->iomem_base;
- info->iomem_reg_shift = state->iomem_reg_shift;
-@@ -3389,13 +2636,13 @@
- }
-
- static int rs_read_proc(char *page, char **start, off_t off, int count,
-- int *eof, void *data)
-+ int *eof, void *data)
- {
- int i, len = 0, l;
- off_t begin = 0;
-
-- len += sprintf(page, "serinfo:1.0 driver:%s%s revision:%s\n",
-- serial_version, LOCAL_VERSTRING, serial_revdate);
-+ len += sprintf(page, "serial: %s\n",
-+ LOCAL_VERSTRING);
- for (i = 0; i < NR_PORTS && len < 4000; i++) {
- l = line_info(page + len, &rs_table[i]);
- len += l;
-@@ -3423,125 +2670,212 @@
- */
-
- /*
-- * This routine prints out the appropriate serial driver version
-- * number, and identifies which options were configured into this
-- * driver.
-+ * The serial driver boot-time initialization code!
- */
--static char serial_options[] __initdata =
--#ifdef CONFIG_HUB6
-- " HUB-6"
--#define SERIAL_OPT
--#endif
--#ifdef CONFIG_SERIAL_MANY_PORTS
-- " MANY_PORTS"
--#define SERIAL_OPT
--#endif
--#ifdef CONFIG_SERIAL_MULTIPORT
-- " MULTIPORT"
--#define SERIAL_OPT
--#endif
--#ifdef CONFIG_SERIAL_SHARE_IRQ
-- " SHARE_IRQ"
--#define SERIAL_OPT
--#endif
--#ifdef CONFIG_SERIAL_DETECT_IRQ
-- " DETECT_IRQ"
--#define SERIAL_OPT
--#endif
--#ifdef ENABLE_SERIAL_PCI
-- " SERIAL_PCI"
--#define SERIAL_OPT
--#endif
--#ifdef ENABLE_SERIAL_PNP
-- " ISAPNP"
--#define SERIAL_OPT
-+static int __init rs_init(void)
-+{
-+ int i;
-+ struct serial_state * state;
-+
-+ printk("pxa & ti16c754b serial driver\n");
-+ set_GPIO_IRQ_edge(7, GPIO_RISING_EDGE);
-+ set_GPIO_IRQ_edge(24, GPIO_RISING_EDGE);
-+ set_GPIO_IRQ_edge(25, GPIO_RISING_EDGE);
-+ set_GPIO_IRQ_edge(26, GPIO_RISING_EDGE);
-+
-+ if (!request_mem_region(RAMSES_UARTA_PHYS, 16*4, "Ramses UART A"))
-+ printk(KERN_ERR "unable to reserve region\n");
-+ else {
-+ ramses_uarta = ioremap_nocache(RAMSES_UARTA_PHYS, 16*4);
-+ if (!ramses_uarta)
-+ printk(KERN_ERR "unable to map region\n");
-+ else {
-+ //printk("ramses_uarta cookie is: %08x\n", (unsigned int) ramses_uarta);
-+ rs_table[3].iomem_base = ramses_uarta;
-+ }
-+ }
-+ if (!request_mem_region(RAMSES_UARTB_PHYS, 16*4, "Ramses UART B"))
-+ printk(KERN_ERR "unable to reserve region\n");
-+ else {
-+ ramses_uartb = ioremap_nocache(RAMSES_UARTB_PHYS, 16*4);
-+ if (!ramses_uartb)
-+ printk(KERN_ERR "unable to map region\n");
-+ else {
-+ //printk("ramses_uartb cookie is: %08x\n", (unsigned int) ramses_uartb);
-+ rs_table[4].iomem_base = ramses_uartb;
-+ }
-+ }
-+ if (!request_mem_region(RAMSES_UARTC_PHYS, 16*4, "Ramses UART C"))
-+ printk(KERN_ERR "unable to reserve region\n");
-+ else {
-+ ramses_uartc = ioremap_nocache(RAMSES_UARTC_PHYS, 16*4);
-+ if (!ramses_uartc)
-+ printk(KERN_ERR "unable to map region\n");
-+ else {
-+ //printk("ramses_uartc cookie is: %08x\n", (unsigned int) ramses_uartc);
-+ rs_table[5].iomem_base = ramses_uartc;
-+ }
-+ }
-+ if (!request_mem_region(RAMSES_UARTD_PHYS, 16*4, "Ramses UART D"))
-+ printk(KERN_ERR "unable to reserve region\n");
-+ else {
-+ ramses_uartd = ioremap_nocache(RAMSES_UARTD_PHYS, 16*4);
-+ if (!ramses_uartd)
-+ printk(KERN_ERR "unable to map region\n");
-+ else {
-+ //printk("ramses_uartd cookie is: %08x\n", (unsigned int) ramses_uartd);
-+ rs_table[6].iomem_base = ramses_uartd;
-+ }
-+ }
-+ init_bh(SERIAL_BH, do_serial_bh);
-+ init_timer(&serial_timer);
-+ serial_timer.function = rs_timer;
-+ mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
-+
-+ for (i = 0; i < NR_IRQS; i++) {
-+ IRQ_ports[i] = 0;
-+ IRQ_timeout[i] = 0;
-+ }
-+#ifdef CONFIG_SERIAL_CONSOLE
-+ /*
-+ * The interrupt of the serial console port
-+ * can't be shared.
-+ */
-+ if (sercons.flags & CON_CONSDEV) {
-+ for(i = 0; i < NR_PORTS; i++)
-+ if (i != sercons.index &&
-+ rs_table[i].irq == rs_table[sercons.index].irq)
-+ rs_table[i].irq = 0;
-+ }
- #endif
--#ifdef ENABLE_SERIAL_ACPI
-- " SERIAL_ACPI"
--#define SERIAL_OPT
-+ /* Initialize the tty_driver structure */
-+
-+ memset(&serial_driver, 0, sizeof(struct tty_driver));
-+ serial_driver.magic = TTY_DRIVER_MAGIC;
-+ serial_driver.driver_name = "serial";
-+#if defined(CONFIG_DEVFS_FS)
-+ serial_driver.name = "tts/%d";
-+#else
-+ serial_driver.name = "ttyS";
- #endif
--#ifdef SERIAL_OPT
-- " enabled\n";
-+ serial_driver.major = TTY_MAJOR;
-+ serial_driver.minor_start = 64;
-+ serial_driver.name_base = 0;
-+ serial_driver.num = NR_PORTS;
-+ serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
-+ serial_driver.subtype = SERIAL_TYPE_NORMAL;
-+ serial_driver.init_termios = tty_std_termios;
-+ serial_driver.init_termios.c_cflag =
-+ B115200 | CS8 | CREAD | HUPCL | CLOCAL;
-+ serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
-+ serial_driver.refcount = &serial_refcount;
-+ serial_driver.table = serial_table;
-+ serial_driver.termios = serial_termios;
-+ serial_driver.termios_locked = serial_termios_locked;
-+
-+ serial_driver.open = rs_open;
-+ serial_driver.close = rs_close;
-+ serial_driver.write = rs_write;
-+ serial_driver.put_char = rs_put_char;
-+ serial_driver.flush_chars = rs_flush_chars;
-+ serial_driver.write_room = rs_write_room;
-+ serial_driver.chars_in_buffer = rs_chars_in_buffer;
-+ serial_driver.flush_buffer = rs_flush_buffer;
-+ serial_driver.ioctl = rs_ioctl;
-+ serial_driver.throttle = rs_throttle;
-+ serial_driver.unthrottle = rs_unthrottle;
-+ serial_driver.set_termios = rs_set_termios;
-+ serial_driver.stop = rs_stop;
-+ serial_driver.start = rs_start;
-+ serial_driver.hangup = rs_hangup;
-+ serial_driver.break_ctl = rs_break;
-+ serial_driver.send_xchar = rs_send_xchar;
-+ serial_driver.wait_until_sent = rs_wait_until_sent;
-+ serial_driver.read_proc = rs_read_proc;
-+
-+ /*
-+ * The callout device is just like normal device except for
-+ * major number and the subtype code.
-+ */
-+ callout_driver = serial_driver;
-+#if defined(CONFIG_DEVFS_FS)
-+ callout_driver.name = "cua/%d";
- #else
-- " no serial options enabled\n";
-+ callout_driver.name = "cua";
- #endif
--#undef SERIAL_OPT
-+ callout_driver.major = TTYAUX_MAJOR;
-+ callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-+ callout_driver.read_proc = 0;
-+ callout_driver.proc_entry = 0;
-
--static _INLINE_ void show_serial_version(void)
--{
-- printk(KERN_INFO "%s version %s%s (%s) with%s", serial_name,
-- serial_version, LOCAL_VERSTRING, serial_revdate,
-- serial_options);
-+ if (tty_register_driver(&serial_driver))
-+ panic("Couldn't register serial driver\n");
-+ if (tty_register_driver(&callout_driver))
-+ panic("Couldn't register callout driver\n");
-+
-+ for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
-+ state->magic = SSTATE_MAGIC;
-+ state->line = i;
-+ state->custom_divisor = 0;
-+ state->close_delay = 5*HZ/10;
-+ state->closing_wait = 30*HZ;
-+ state->callout_termios = callout_driver.init_termios;
-+ state->normal_termios = serial_driver.init_termios;
-+ state->icount.cts = state->icount.dsr =
-+ state->icount.rng = state->icount.dcd = 0;
-+ state->icount.rx = state->icount.tx = 0;
-+ state->icount.frame = state->icount.parity = 0;
-+ state->icount.overrun = state->icount.brk = 0;
-+ state->irq = irq_cannonicalize(state->irq);
-+ if (state->port && check_region(state->port,8)) {
-+ state->type = PORT_UNKNOWN;
-+ continue;
-+ }
-+ }
-+ for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
-+ if (state->type == PORT_UNKNOWN)
-+ continue;
-+ printk(KERN_INFO"tts/%d at irq %d is a %s\n",
-+ state->line,
-+ state->irq,
-+ uart_config[state->type].name);
-+ tty_register_devfs(&serial_driver, 0,
-+ serial_driver.minor_start + state->line);
-+ tty_register_devfs(&callout_driver, 0,
-+ callout_driver.minor_start + state->line);
-+ }
-+ return 0;
- }
-
- /*
-- * This routine detect the IRQ of a serial port by clearing OUT2 when
-- * no UART interrupt are requested (IER = 0) (*GPL*). This seems to work at
-- * each time, as long as no other device permanently request the IRQ.
-- * If no IRQ is detected, or multiple IRQ appear, this function returns 0.
-- * The variable "state" and the field "state->port" should not be null.
-+ * This is for use by architectures that know their serial console
-+ * attributes only at run time. Not to be invoked after rs_init().
- */
--static unsigned detect_uart_irq (struct serial_state * state)
-+int __init early_serial_setup(struct serial_struct *req)
- {
-- int irq;
-- unsigned long irqs;
-- unsigned char save_mcr, save_ier;
-- struct async_struct scr_info; /* serial_{in,out} because HUB6 */
--
--#ifdef CONFIG_SERIAL_MANY_PORTS
-- unsigned char save_ICP=0; /* no warning */
-- unsigned short ICP=0;
--
-- if (state->flags & ASYNC_FOURPORT) {
-- ICP = (state->port & 0xFE0) | 0x01F;
-- save_ICP = inb_p(ICP);
-- outb_p(0x80, ICP);
-- (void) inb_p(ICP);
-- }
--#endif
-- scr_info.magic = SERIAL_MAGIC;
-- scr_info.state = state;
-- scr_info.port = state->port;
-- scr_info.flags = state->flags;
--#ifdef CONFIG_HUB6
-- scr_info.hub6 = state->hub6;
--#endif
-- scr_info.io_type = state->io_type;
-- scr_info.iomem_base = state->iomem_base;
-- scr_info.iomem_reg_shift = state->iomem_reg_shift;
-+ int i = req->line;
-
-- /* forget possible initially masked and pending IRQ */
-- probe_irq_off(probe_irq_on());
-- save_mcr = serial_inp(&scr_info, UART_MCR);
-- save_ier = serial_inp(&scr_info, UART_IER);
-- serial_outp(&scr_info, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
--
-- irqs = probe_irq_on();
-- serial_outp(&scr_info, UART_MCR, 0);
-- udelay (10);
-- if (state->flags & ASYNC_FOURPORT) {
-- serial_outp(&scr_info, UART_MCR,
-- UART_MCR_DTR | UART_MCR_RTS);
-- } else {
-- serial_outp(&scr_info, UART_MCR,
-- UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
-- }
-- serial_outp(&scr_info, UART_IER, 0x0f); /* enable all intrs */
-- (void)serial_inp(&scr_info, UART_LSR);
-- (void)serial_inp(&scr_info, UART_RX);
-- (void)serial_inp(&scr_info, UART_IIR);
-- (void)serial_inp(&scr_info, UART_MSR);
-- serial_outp(&scr_info, UART_TX, 0xFF);
-- udelay (20);
-- irq = probe_irq_off(irqs);
-+ printk("%s\n", __FUNCTION__);
-
-- serial_outp(&scr_info, UART_MCR, save_mcr);
-- serial_outp(&scr_info, UART_IER, save_ier);
--#ifdef CONFIG_SERIAL_MANY_PORTS
-- if (state->flags & ASYNC_FOURPORT)
-- outb_p(save_ICP, ICP);
--#endif
-- return (irq > 0)? irq : 0;
-+ if (i >= NR_IRQS)
-+ return(-ENOENT);
-+ rs_table[i].magic = 0;
-+ rs_table[i].baud_base = req->baud_base;
-+ rs_table[i].port = req->port;
-+ if (HIGH_BITS_OFFSET)
-+ rs_table[i].port += (unsigned long) req->port_high <<
-+ HIGH_BITS_OFFSET;
-+ rs_table[i].irq = req->irq;
-+ rs_table[i].flags = req->flags;
-+ rs_table[i].close_delay = req->close_delay;
-+ rs_table[i].io_type = req->io_type;
-+ rs_table[i].iomem_base = req->iomem_base;
-+ rs_table[i].iomem_reg_shift = req->iomem_reg_shift;
-+ rs_table[i].type = req->type;
-+ rs_table[i].xmit_fifo_size = req->xmit_fifo_size;
-+ rs_table[i].custom_divisor = req->custom_divisor;
-+ rs_table[i].closing_wait = req->closing_wait;
-+ return(0);
- }
-
- /*
-@@ -3894,1762 +3228,10 @@
- restore_flags(flags);
- }
-
--int register_serial(struct serial_struct *req);
--void unregister_serial(int line);
--
--#if (LINUX_VERSION_CODE > 0x20100)
--EXPORT_SYMBOL(register_serial);
--EXPORT_SYMBOL(unregister_serial);
--#else
--static struct symbol_table serial_syms = {
--#include <linux/symtab_begin.h>
-- X(register_serial),
-- X(unregister_serial),
--#include <linux/symtab_end.h>
--};
--#endif
--
--
--#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
--
--static void __devinit printk_pnp_dev_id(unsigned short vendor,
-- unsigned short device)
--{
-- printk("%c%c%c%x%x%x%x",
-- 'A' + ((vendor >> 2) & 0x3f) - 1,
-- 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
-- 'A' + ((vendor >> 8) & 0x1f) - 1,
-- (device >> 4) & 0x0f,
-- device & 0x0f,
-- (device >> 12) & 0x0f,
-- (device >> 8) & 0x0f);
--}
--
--static _INLINE_ int get_pci_port(struct pci_dev *dev,
-- struct pci_board *board,
-- struct serial_struct *req,
-- int idx)
--{
-- unsigned long port;
-- int base_idx;
-- int max_port;
-- int offset;
--
-- base_idx = SPCI_FL_GET_BASE(board->flags);
-- if (board->flags & SPCI_FL_BASE_TABLE)
-- base_idx += idx;
--
-- if (board->flags & SPCI_FL_REGION_SZ_CAP) {
-- max_port = pci_resource_len(dev, base_idx) / 8;
-- if (idx >= max_port)
-- return 1;
-- }
--
-- offset = board->first_uart_offset;
--
-- /* Timedia/SUNIX uses a mixture of BARs and offsets */
-- /* Ugh, this is ugly as all hell --- TYT */
-- if(dev->vendor == PCI_VENDOR_ID_TIMEDIA ) /* 0x1409 */
-- switch(idx) {
-- case 0: base_idx=0;
-- break;
-- case 1: base_idx=0; offset=8;
-- break;
-- case 2: base_idx=1;
-- break;
-- case 3: base_idx=1; offset=8;
-- break;
-- case 4: /* BAR 2*/
-- case 5: /* BAR 3 */
-- case 6: /* BAR 4*/
-- case 7: base_idx=idx-2; /* BAR 5*/
-- }
--
-- /* Some Titan cards are also a little weird */
-- if (dev->vendor == PCI_VENDOR_ID_TITAN &&
-- (dev->device == PCI_DEVICE_ID_TITAN_400L ||
-- dev->device == PCI_DEVICE_ID_TITAN_800L)) {
-- switch (idx) {
-- case 0: base_idx = 1;
-- break;
-- case 1: base_idx = 2;
-- break;
-- default:
-- base_idx = 4;
-- offset = 8 * (idx - 2);
-- }
--
-- }
--
-- /* HP's Diva chip puts the 4th/5th serial port further out, and
-- * some serial ports are supposed to be hidden on certain models.
-- */
-- if (dev->vendor == PCI_VENDOR_ID_HP &&
-- dev->device == PCI_DEVICE_ID_HP_SAS) {
-- switch (dev->subsystem_device) {
-- case 0x104B: /* Maestro */
-- if (idx == 3) idx++;
-- break;
-- case 0x1282: /* Everest / Longs Peak */
-- if (idx > 0) idx++;
-- if (idx > 2) idx++;
-- break;
-- }
-- if (idx > 2) {
-- offset = 0x18;
-- }
-- }
--
-- port = pci_resource_start(dev, base_idx) + offset;
--
-- if ((board->flags & SPCI_FL_BASE_TABLE) == 0)
-- port += idx * (board->uart_offset ? board->uart_offset : 8);
--
-- if (IS_PCI_REGION_IOPORT(dev, base_idx)) {
-- req->port = port;
-- if (HIGH_BITS_OFFSET)
-- req->port_high = port >> HIGH_BITS_OFFSET;
-- else
-- req->port_high = 0;
-- return 0;
-- }
-- req->io_type = SERIAL_IO_MEM;
-- req->iomem_base = ioremap(port, board->uart_offset);
-- req->iomem_reg_shift = board->reg_shift;
-- req->port = 0;
-- return 0;
--}
--
--static _INLINE_ int get_pci_irq(struct pci_dev *dev,
-- struct pci_board *board,
-- int idx)
--{
-- int base_idx;
--
-- if ((board->flags & SPCI_FL_IRQRESOURCE) == 0)
-- return dev->irq;
--
-- base_idx = SPCI_FL_GET_IRQBASE(board->flags);
-- if (board->flags & SPCI_FL_IRQ_TABLE)
-- base_idx += idx;
--
-- return PCI_IRQ_RESOURCE(dev, base_idx);
--}
--
--/*
-- * Common enabler code shared by both PCI and ISAPNP probes
-- */
--static void __devinit start_pci_pnp_board(struct pci_dev *dev,
-- struct pci_board *board)
--{
-- int k, line;
-- struct serial_struct serial_req;
-- int base_baud;
--
-- if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
-- printk("serial: PNP device '");
-- printk_pnp_dev_id(dev->vendor, dev->device);
-- printk("' prepare failed\n");
-- return;
-- }
--
-- if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
-- printk("serial: PNP device '");
-- printk_pnp_dev_id(dev->vendor, dev->device);
-- printk("' activate failed\n");
-- return;
-- }
--
-- /*
-- * Run the initialization function, if any
-- */
-- if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0))
-- return;
--
-- /*
-- * Register the serial board in the array if we need to
-- * shutdown the board on a module unload or card removal
-- */
-- if (DEACTIVATE_FUNC(dev) || board->init_fn) {
-- for (k=0; k < NR_PCI_BOARDS; k++)
-- if (serial_pci_board[k].dev == 0)
-- break;
-- if (k >= NR_PCI_BOARDS)
-- return;
-- serial_pci_board[k].board = *board;
-- serial_pci_board[k].dev = dev;
-- }
--
-- base_baud = board->base_baud;
-- if (!base_baud)
-- base_baud = BASE_BAUD;
-- memset(&serial_req, 0, sizeof(serial_req));
--
-- for (k=0; k < board->num_ports; k++) {
-- serial_req.irq = get_pci_irq(dev, board, k);
-- if (get_pci_port(dev, board, &serial_req, k))
-- break;
-- serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE;
--#ifdef SERIAL_DEBUG_PCI
-- printk("Setup PCI/PNP port: port %x, irq %d, type %d\n",
-- serial_req.port, serial_req.irq, serial_req.io_type);
--#endif
-- line = register_serial(&serial_req);
-- if (line < 0)
-- break;
-- rs_table[line].baud_base = base_baud;
-- rs_table[line].dev = dev;
-- }
--}
--#endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */
--
--#ifdef ENABLE_SERIAL_PCI
--/*
-- * Some PCI serial cards using the PLX 9050 PCI interface chip require
-- * that the card interrupt be explicitly enabled or disabled. This
-- * seems to be mainly needed on card using the PLX which also use I/O
-- * mapped memory.
-- */
--static int __devinit
--pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
--{
-- u8 data, *p, irq_config;
-- int pci_config;
--
-- irq_config = 0x41;
-- pci_config = PCI_COMMAND_MEMORY;
-- if (dev->vendor == PCI_VENDOR_ID_PANACOM)
-- irq_config = 0x43;
-- if ((dev->vendor == PCI_VENDOR_ID_PLX) &&
-- (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) {
-- /*
-- * As the megawolf cards have the int pins active
-- * high, and have 2 UART chips, both ints must be
-- * enabled on the 9050. Also, the UARTS are set in
-- * 16450 mode by default, so we have to enable the
-- * 16C950 'enhanced' mode so that we can use the deep
-- * FIFOs
-- */
-- irq_config = 0x5b;
-- pci_config = PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
-- }
--
-- pci_read_config_byte(dev, PCI_COMMAND, &data);
--
-- if (enable)
-- pci_write_config_byte(dev, PCI_COMMAND,
-- data | pci_config);
--
-- /* enable/disable interrupts */
-- p = ioremap(pci_resource_start(dev, 0), 0x80);
-- writel(enable ? irq_config : 0x00, (unsigned long)p + 0x4c);
-- iounmap(p);
-
-- if (!enable)
-- pci_write_config_byte(dev, PCI_COMMAND,
-- data & ~pci_config);
-- return 0;
--}
-
-
- /*
-- * SIIG serial cards have an PCI interface chip which also controls
-- * the UART clocking frequency. Each UART can be clocked independently
-- * (except cards equiped with 4 UARTs) and initial clocking settings
-- * are stored in the EEPROM chip. It can cause problems because this
-- * version of serial driver doesn't support differently clocked UART's
-- * on single PCI card. To prevent this, initialization functions set
-- * high frequency clocking for all UART's on given card. It is safe (I
-- * hope) because it doesn't touch EEPROM settings to prevent conflicts
-- * with other OSes (like M$ DOS).
-- *
-- * SIIG support added by Andrey Panin <pazke@mail.tp.ru>, 10/1999
-- *
-- * There is two family of SIIG serial cards with different PCI
-- * interface chip and different configuration methods:
-- * - 10x cards have control registers in IO and/or memory space;
-- * - 20x cards have control registers in standard PCI configuration space.
-- *
-- * SIIG initialization functions exported for use by parport_serial.c module.
-- */
--
--#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
--#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
--
--int __devinit
--pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
--{
-- u16 data, *p;
--
-- if (!enable) return 0;
--
-- p = ioremap(pci_resource_start(dev, 0), 0x80);
--
-- switch (dev->device & 0xfff8) {
-- case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */
-- data = 0xffdf;
-- break;
-- case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */
-- data = 0xf7ff;
-- break;
-- default: /* 1S1P, 4S */
-- data = 0xfffb;
-- break;
-- }
--
-- writew(readw((unsigned long) p + 0x28) & data, (unsigned long) p + 0x28);
-- iounmap(p);
-- return 0;
--}
--EXPORT_SYMBOL(pci_siig10x_fn);
--
--#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
--#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
--
--int __devinit
--pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
--{
-- u8 data;
--
-- if (!enable) return 0;
--
-- /* Change clock frequency for the first UART. */
-- pci_read_config_byte(dev, 0x6f, &data);
-- pci_write_config_byte(dev, 0x6f, data & 0xef);
--
-- /* If this card has 2 UART, we have to do the same with second UART. */
-- if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) ||
-- ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) {
-- pci_read_config_byte(dev, 0x73, &data);
-- pci_write_config_byte(dev, 0x73, data & 0xef);
-- }
-- return 0;
--}
--EXPORT_SYMBOL(pci_siig20x_fn);
--
--/* Added for EKF Intel i960 serial boards */
--static int __devinit
--pci_inteli960ni_fn(struct pci_dev *dev,
-- struct pci_board *board,
-- int enable)
--{
-- unsigned long oldval;
--
-- if (!(pci_get_subdevice(dev) & 0x1000))
-- return(-1);
--
-- if (!enable) /* is there something to deinit? */
-- return(0);
--
--#ifdef SERIAL_DEBUG_PCI
-- printk(KERN_DEBUG " Subsystem ID %lx (intel 960)\n",
-- (unsigned long) board->subdevice);
--#endif
-- /* is firmware started? */
-- pci_read_config_dword(dev, 0x44, (void*) &oldval);
-- if (oldval == 0x00001000L) { /* RESET value */
-- printk(KERN_DEBUG "Local i960 firmware missing");
-- return(-1);
-- }
-- return(0);
--}
--
--/*
-- * Timedia has an explosion of boards, and to avoid the PCI table from
-- * growing *huge*, we use this function to collapse some 70 entries
-- * in the PCI table into one, for sanity's and compactness's sake.
-- */
--static unsigned short timedia_single_port[] = {
-- 0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0 };
--static unsigned short timedia_dual_port[] = {
-- 0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085,
-- 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079,
-- 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079,
-- 0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079,
-- 0xD079, 0 };
--static unsigned short timedia_quad_port[] = {
-- 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157,
-- 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159,
-- 0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056,
-- 0xB157, 0 };
--static unsigned short timedia_eight_port[] = {
-- 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166,
-- 0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0 };
--static struct timedia_struct {
-- int num;
-- unsigned short *ids;
--} timedia_data[] = {
-- { 1, timedia_single_port },
-- { 2, timedia_dual_port },
-- { 4, timedia_quad_port },
-- { 8, timedia_eight_port },
-- { 0, 0 }
--};
--
--static int __devinit
--pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
--{
-- int i, j;
-- unsigned short *ids;
--
-- if (!enable)
-- return 0;
--
-- for (i=0; timedia_data[i].num; i++) {
-- ids = timedia_data[i].ids;
-- for (j=0; ids[j]; j++) {
-- if (pci_get_subdevice(dev) == ids[j]) {
-- board->num_ports = timedia_data[i].num;
-- return 0;
-- }
-- }
-- }
-- return 0;
--}
--
--/*
-- * HP's Remote Management Console. The Diva chip came in several
-- * different versions. N-class, L2000 and A500 have two Diva chips, each
-- * with 3 UARTs (the third UART on the second chip is unused). Superdome
-- * and Keystone have one Diva chip with 3 UARTs. Some later machines have
-- * one Diva chip, but it has been expanded to 5 UARTs.
-- */
--static int __devinit
--pci_hp_diva(struct pci_dev *dev, struct pci_board *board, int enable)
--{
-- if (!enable)
-- return 0;
--
-- switch (dev->subsystem_device) {
-- case 0x1049: /* Prelude Diva 1 */
-- case 0x1223: /* Superdome */
-- case 0x1226: /* Keystone */
-- case 0x1282: /* Everest / Longs Peak */
-- board->num_ports = 3;
-- break;
-- case 0x104A: /* Prelude Diva 2 */
-- board->num_ports = 2;
-- break;
-- case 0x104B: /* Maestro */
-- board->num_ports = 4;
-- break;
-- case 0x1227: /* Powerbar */
-- board->num_ports = 1;
-- break;
-- }
--
-- return 0;
--}
--
--static int __devinit
--pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable)
--{
-- __set_current_state(TASK_UNINTERRUPTIBLE);
-- schedule_timeout(HZ/10);
-- return 0;
--}
--
--/*
-- * This is the configuration table for all of the PCI serial boards
-- * which we support. It is directly indexed by the pci_board_num_t enum
-- * value, which is encoded in the pci_device_id PCI probe table's
-- * driver_data member.
-- */
--enum pci_board_num_t {
-- pbn_b0_1_115200,
-- pbn_default = 0,
--
-- pbn_b0_2_115200,
-- pbn_b0_4_115200,
--
-- pbn_b0_1_921600,
-- pbn_b0_2_921600,
-- pbn_b0_4_921600,
--
-- pbn_b0_bt_1_115200,
-- pbn_b0_bt_2_115200,
-- pbn_b0_bt_1_460800,
-- pbn_b0_bt_2_460800,
-- pbn_b0_bt_2_921600,
--
-- pbn_b1_1_115200,
-- pbn_b1_2_115200,
-- pbn_b1_4_115200,
-- pbn_b1_8_115200,
--
-- pbn_b1_2_921600,
-- pbn_b1_4_921600,
-- pbn_b1_8_921600,
--
-- pbn_b1_2_1382400,
-- pbn_b1_4_1382400,
-- pbn_b1_8_1382400,
--
-- pbn_b2_1_115200,
-- pbn_b2_8_115200,
-- pbn_b2_4_460800,
-- pbn_b2_8_460800,
-- pbn_b2_16_460800,
-- pbn_b2_4_921600,
-- pbn_b2_8_921600,
--
-- pbn_b2_bt_1_115200,
-- pbn_b2_bt_2_115200,
-- pbn_b2_bt_4_115200,
-- pbn_b2_bt_2_921600,
--
-- pbn_panacom,
-- pbn_panacom2,
-- pbn_panacom4,
-- pbn_plx_romulus,
-- pbn_oxsemi,
-- pbn_timedia,
-- pbn_intel_i960,
-- pbn_sgi_ioc3,
-- pbn_hp_diva,
--#ifdef CONFIG_DDB5074
-- pbn_nec_nile4,
--#endif
--#if 0
-- pbn_dci_pccom8,
--#endif
-- pbn_xircom_combo,
--
-- pbn_siig10x_0,
-- pbn_siig10x_1,
-- pbn_siig10x_2,
-- pbn_siig10x_4,
-- pbn_siig20x_0,
-- pbn_siig20x_2,
-- pbn_siig20x_4,
--
-- pbn_computone_4,
-- pbn_computone_6,
-- pbn_computone_8,
--};
--
--static struct pci_board pci_boards[] __devinitdata = {
-- /*
-- * PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
-- * Offset to get to next UART's registers,
-- * Register shift to use for memory-mapped I/O,
-- * Initialization function, first UART offset
-- */
--
-- /* Generic serial board, pbn_b0_1_115200, pbn_default */
-- { SPCI_FL_BASE0, 1, 115200 }, /* pbn_b0_1_115200,
-- pbn_default */
--
-- { SPCI_FL_BASE0, 2, 115200 }, /* pbn_b0_2_115200 */
-- { SPCI_FL_BASE0, 4, 115200 }, /* pbn_b0_4_115200 */
--
-- { SPCI_FL_BASE0, 1, 921600 }, /* pbn_b0_1_921600 */
-- { SPCI_FL_BASE0, 2, 921600 }, /* pbn_b0_2_921600 */
-- { SPCI_FL_BASE0, 4, 921600 }, /* pbn_b0_4_921600 */
--
-- { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */
-- { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */
-- { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */
-- { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */
-- { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b0_bt_2_921600 */
--
-- { SPCI_FL_BASE1, 1, 115200 }, /* pbn_b1_1_115200 */
-- { SPCI_FL_BASE1, 2, 115200 }, /* pbn_b1_2_115200 */
-- { SPCI_FL_BASE1, 4, 115200 }, /* pbn_b1_4_115200 */
-- { SPCI_FL_BASE1, 8, 115200 }, /* pbn_b1_8_115200 */
--
-- { SPCI_FL_BASE1, 2, 921600 }, /* pbn_b1_2_921600 */
-- { SPCI_FL_BASE1, 4, 921600 }, /* pbn_b1_4_921600 */
-- { SPCI_FL_BASE1, 8, 921600 }, /* pbn_b1_8_921600 */
--
-- { SPCI_FL_BASE1, 2, 1382400 }, /* pbn_b1_2_1382400 */
-- { SPCI_FL_BASE1, 4, 1382400 }, /* pbn_b1_4_1382400 */
-- { SPCI_FL_BASE1, 8, 1382400 }, /* pbn_b1_8_1382400 */
--
-- { SPCI_FL_BASE2, 1, 115200 }, /* pbn_b2_1_115200 */
-- { SPCI_FL_BASE2, 8, 115200 }, /* pbn_b2_8_115200 */
-- { SPCI_FL_BASE2, 4, 460800 }, /* pbn_b2_4_460800 */
-- { SPCI_FL_BASE2, 8, 460800 }, /* pbn_b2_8_460800 */
-- { SPCI_FL_BASE2, 16, 460800 }, /* pbn_b2_16_460800 */
-- { SPCI_FL_BASE2, 4, 921600 }, /* pbn_b2_4_921600 */
-- { SPCI_FL_BASE2, 8, 921600 }, /* pbn_b2_8_921600 */
--
-- { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b2_bt_1_115200 */
-- { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b2_bt_2_115200 */
-- { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, /* pbn_b2_bt_4_115200 */
-- { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b2_bt_2_921600 */
--
-- { SPCI_FL_BASE2, 2, 921600, /* IOMEM */ /* pbn_panacom */
-- 0x400, 7, pci_plx9050_fn },
-- { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_panacom2 */
-- 0x400, 7, pci_plx9050_fn },
-- { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_panacom4 */
-- 0x400, 7, pci_plx9050_fn },
-- { SPCI_FL_BASE2, 4, 921600, /* pbn_plx_romulus */
-- 0x20, 2, pci_plx9050_fn, 0x03 },
-- /* This board uses the size of PCI Base region 0 to
-- * signal now many ports are available */
-- { SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, /* pbn_oxsemi */
-- { SPCI_FL_BASE_TABLE, 1, 921600, /* pbn_timedia */
-- 0, 0, pci_timedia_fn },
-- /* EKF addition for i960 Boards form EKF with serial port */
-- { SPCI_FL_BASE0, 32, 921600, /* max 256 ports */ /* pbn_intel_i960 */
-- 8<<2, 2, pci_inteli960ni_fn, 0x10000},
-- { SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE, /* pbn_sgi_ioc3 */
-- 1, 458333, 0, 0, 0, 0x20178 },
-- { SPCI_FL_BASE0, 5, 115200, 8, 0, pci_hp_diva, 0}, /* pbn_hp_diva */
--#ifdef CONFIG_DDB5074
-- /*
-- * NEC Vrc-5074 (Nile 4) builtin UART.
-- * Conditionally compiled in since this is a motherboard device.
-- */
-- { SPCI_FL_BASE0, 1, 520833, /* pbn_nec_nile4 */
-- 64, 3, NULL, 0x300 },
--#endif
--#if 0 /* PCI_DEVICE_ID_DCI_PCCOM8 ? */ /* pbn_dci_pccom8 */
-- { SPCI_FL_BASE3, 8, 115200, 8 },
--#endif
-- { SPCI_FL_BASE0, 1, 115200, /* pbn_xircom_combo */
-- 0, 0, pci_xircom_fn },
--
-- { SPCI_FL_BASE2, 1, 460800, /* pbn_siig10x_0 */
-- 0, 0, pci_siig10x_fn },
-- { SPCI_FL_BASE2, 1, 921600, /* pbn_siig10x_1 */
-- 0, 0, pci_siig10x_fn },
-- { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_siig10x_2 */
-- 0, 0, pci_siig10x_fn },
-- { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_siig10x_4 */
-- 0, 0, pci_siig10x_fn },
-- { SPCI_FL_BASE0, 1, 921600, /* pbn_siix20x_0 */
-- 0, 0, pci_siig20x_fn },
-- { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_siix20x_2 */
-- 0, 0, pci_siig20x_fn },
-- { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_siix20x_4 */
-- 0, 0, pci_siig20x_fn },
--
-- { SPCI_FL_BASE0, 4, 921600, /* IOMEM */ /* pbn_computone_4 */
-- 0x40, 2, NULL, 0x200 },
-- { SPCI_FL_BASE0, 6, 921600, /* IOMEM */ /* pbn_computone_6 */
-- 0x40, 2, NULL, 0x200 },
-- { SPCI_FL_BASE0, 8, 921600, /* IOMEM */ /* pbn_computone_8 */
-- 0x40, 2, NULL, 0x200 },
--};
--
--/*
-- * Given a complete unknown PCI device, try to use some heuristics to
-- * guess what the configuration might be, based on the pitiful PCI
-- * serial specs. Returns 0 on success, 1 on failure.
-- */
--static int __devinit serial_pci_guess_board(struct pci_dev *dev,
-- struct pci_board *board)
--{
-- int num_iomem = 0, num_port = 0, first_port = -1;
-- int i;
--
-- /*
-- * If it is not a communications device or the programming
-- * interface is greater than 6, give up.
-- *
-- * (Should we try to make guesses for multiport serial devices
-- * later?)
-- */
-- if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
-- ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
-- (dev->class & 0xff) > 6)
-- return 1;
--
-- for (i=0; i < 6; i++) {
-- if (IS_PCI_REGION_IOPORT(dev, i)) {
-- num_port++;
-- if (first_port == -1)
-- first_port = i;
-- }
-- if (IS_PCI_REGION_IOMEM(dev, i))
-- num_iomem++;
-- }
--
-- /*
-- * If there is exactly one port of 8 bytes, use it.
-- */
-- if (num_port == 1 && pci_resource_len(dev, first_port) == 8) {
-- board->flags = first_port;
-- return 0;
-- }
--
-- /*
-- * If there is 1 or 0 iomem regions, and exactly one port, use
-- * it.
-- */
-- if (num_iomem <= 1 && num_port == 1) {
-- board->flags = first_port;
-- return 0;
-- }
-- return 1;
--}
--
--static int __devinit serial_init_one(struct pci_dev *dev,
-- const struct pci_device_id *ent)
--{
-- struct pci_board *board, tmp;
-- int rc;
--
-- board = &pci_boards[ent->driver_data];
--
-- rc = pci_enable_device(dev);
-- if (rc) return rc;
--
-- if (ent->driver_data == pbn_default &&
-- serial_pci_guess_board(dev, board))
-- return -ENODEV;
-- else if (serial_pci_guess_board(dev, &tmp) == 0) {
-- printk(KERN_INFO "Redundant entry in serial pci_table. "
-- "Please send the output of\n"
-- "lspci -vv, this message (%04x,%04x,%04x,%04x)\n"
-- "and the manufacturer and name of "
-- "serial board or modem board\n"
-- "to serial-pci-info@lists.sourceforge.net.\n",
-- dev->vendor, dev->device,
-- pci_get_subvendor(dev), pci_get_subdevice(dev));
-- }
--
-- start_pci_pnp_board(dev, board);
--
-- return 0;
--}
--
--static void __devexit serial_remove_one(struct pci_dev *dev)
--{
-- int i;
--
-- /*
-- * Iterate through all of the ports finding those that belong
-- * to this PCI device.
-- */
-- for(i = 0; i < NR_PORTS; i++) {
-- if (rs_table[i].dev != dev)
-- continue;
-- unregister_serial(i);
-- rs_table[i].dev = 0;
-- }
-- /*
-- * Now execute any board-specific shutdown procedure
-- */
-- for (i=0; i < NR_PCI_BOARDS; i++) {
-- struct pci_board_inst *brd = &serial_pci_board[i];
--
-- if (serial_pci_board[i].dev != dev)
-- continue;
-- if (brd->board.init_fn)
-- (brd->board.init_fn)(brd->dev, &brd->board, 0);
-- if (DEACTIVATE_FUNC(brd->dev))
-- (DEACTIVATE_FUNC(brd->dev))(brd->dev);
-- serial_pci_board[i].dev = 0;
-- }
--}
--
--
--static struct pci_device_id serial_pci_tbl[] __devinitdata = {
-- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
-- PCI_SUBVENDOR_ID_CONNECT_TECH,
-- PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
-- pbn_b1_8_1382400 },
-- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
-- PCI_SUBVENDOR_ID_CONNECT_TECH,
-- PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
-- pbn_b1_4_1382400 },
-- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
-- PCI_SUBVENDOR_ID_CONNECT_TECH,
-- PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
-- pbn_b1_2_1382400 },
-- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-- PCI_SUBVENDOR_ID_CONNECT_TECH,
-- PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
-- pbn_b1_8_1382400 },
-- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-- PCI_SUBVENDOR_ID_CONNECT_TECH,
-- PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
-- pbn_b1_4_1382400 },
-- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-- PCI_SUBVENDOR_ID_CONNECT_TECH,
-- PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
-- pbn_b1_2_1382400 },
-- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-- PCI_SUBVENDOR_ID_CONNECT_TECH,
-- PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0,
-- pbn_b1_8_921600 },
-- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-- PCI_SUBVENDOR_ID_CONNECT_TECH,
-- PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0,
-- pbn_b1_8_921600 },
-- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-- PCI_SUBVENDOR_ID_CONNECT_TECH,
-- PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0,
-- pbn_b1_4_921600 },
-- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-- PCI_SUBVENDOR_ID_CONNECT_TECH,
-- PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0,
-- pbn_b1_4_921600 },
-- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-- PCI_SUBVENDOR_ID_CONNECT_TECH,
-- PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0,
-- pbn_b1_2_921600 },
-- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-- PCI_SUBVENDOR_ID_CONNECT_TECH,
-- PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0,
-- pbn_b1_8_921600 },
-- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-- PCI_SUBVENDOR_ID_CONNECT_TECH,
-- PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0,
-- pbn_b1_8_921600 },
-- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-- PCI_SUBVENDOR_ID_CONNECT_TECH,
-- PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0,
-- pbn_b1_4_921600 },
--
-- { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b2_bt_1_115200 },
-- { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b2_bt_2_115200 },
-- { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b2_bt_4_115200 },
-- { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b2_bt_2_115200 },
-- { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b2_bt_4_115200 },
-- { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b2_8_115200 },
--
-- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b2_bt_2_115200 },
-- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b2_bt_2_921600 },
-- /* VScom SPCOM800, from sl@s.pl */
-- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b2_8_921600 },
-- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b2_4_921600 },
-- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-- PCI_SUBVENDOR_ID_KEYSPAN,
-- PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
-- pbn_panacom },
-- { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_panacom4 },
-- { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_panacom2 },
-- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-- PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-- PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0,
-- pbn_b2_4_460800 },
-- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-- PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-- PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0,
-- pbn_b2_8_460800 },
-- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-- PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-- PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0,
-- pbn_b2_16_460800 },
-- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-- PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-- PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0,
-- pbn_b2_16_460800 },
-- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-- PCI_SUBVENDOR_ID_CHASE_PCIRAS,
-- PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0,
-- pbn_b2_4_460800 },
-- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-- PCI_SUBVENDOR_ID_CHASE_PCIRAS,
-- PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0,
-- pbn_b2_8_460800 },
-- /* Megawolf Romulus PCI Serial Card, from Mike Hudson */
-- /* (Exoray@isys.ca) */
-- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
-- 0x10b5, 0x106a, 0, 0,
-- pbn_plx_romulus },
-- { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b1_4_115200 },
-- { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b1_2_115200 },
-- { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b1_8_115200 },
-- { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b1_8_115200 },
-- { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
-- PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 0,
-- pbn_b0_4_921600 },
-- { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b0_4_115200 },
-- { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b0_bt_2_921600 },
--
-- /* Digitan DS560-558, from jimd@esoft.com */
-- { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b1_1_115200 },
--
-- /* 3Com US Robotics 56k Voice Internal PCI model 5610 */
-- { PCI_VENDOR_ID_USR, 0x1008,
-- PCI_ANY_ID, PCI_ANY_ID, },
--
-- /* Titan Electronic cards */
-- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b0_1_921600 },
-- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b0_2_921600 },
-- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b0_4_921600 },
-- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b0_4_921600 },
-- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L,
-- PCI_ANY_ID, PCI_ANY_ID,
-- SPCI_FL_BASE1, 1, 921600 },
-- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L,
-- PCI_ANY_ID, PCI_ANY_ID,
-- SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 },
-- /* The 400L and 800L have a custom hack in get_pci_port */
-- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L,
-- PCI_ANY_ID, PCI_ANY_ID,
-- SPCI_FL_BASE_TABLE, 4, 921600 },
-- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L,
-- PCI_ANY_ID, PCI_ANY_ID,
-- SPCI_FL_BASE_TABLE, 8, 921600 },
--
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig10x_0 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig10x_0 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig10x_0 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig10x_2 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig10x_2 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig10x_2 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig10x_4 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig10x_4 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig10x_4 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig20x_0 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig20x_0 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig20x_0 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig20x_2 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig20x_2 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig20x_2 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig20x_4 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig20x_4 },
-- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_siig20x_4 },
--
-- /* Computone devices submitted by Doug McNash dmcnash@computone.com */
-- { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
-- PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
-- 0, 0, pbn_computone_4 },
-- { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
-- PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
-- 0, 0, pbn_computone_8 },
-- { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
-- PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
-- 0, 0, pbn_computone_6 },
--
-- { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi },
-- { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
-- PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0, pbn_timedia },
--
-- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b0_bt_2_115200 },
-- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b0_bt_2_115200 },
-- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b0_bt_2_115200 },
-- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b0_bt_2_460800 },
-- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b0_bt_2_460800 },
-- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b0_bt_2_460800 },
-- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b0_bt_1_115200 },
-- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b0_bt_1_460800 },
--
-- /* RAStel 2 port modem, gerg@moreton.com.au */
-- { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b2_bt_2_115200 },
--
-- /* EKF addition for i960 Boards form EKF with serial port */
-- { PCI_VENDOR_ID_INTEL, 0x1960,
-- 0xE4BF, PCI_ANY_ID, 0, 0,
-- pbn_intel_i960 },
--
-- /* Xircom Cardbus/Ethernet combos */
-- { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_xircom_combo },
--
-- /*
-- * Untested PCI modems, sent in from various folks...
-- */
--
-- /* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de> */
-- { PCI_VENDOR_ID_ROCKWELL, 0x1004,
-- 0x1048, 0x1500, 0, 0,
-- pbn_b1_1_115200 },
--
-- { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
-- 0xFF00, 0, 0, 0,
-- pbn_sgi_ioc3 },
--
-- /* HP Diva card */
-- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_SAS,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_hp_diva },
-- { PCI_VENDOR_ID_HP, 0x1290,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_b2_1_115200 },
--
--#ifdef CONFIG_DDB5074
-- /*
-- * NEC Vrc-5074 (Nile 4) builtin UART.
-- * Conditionally compiled in since this is a motherboard device.
-- */
-- { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_nec_nile4 },
--#endif
--
--#if 0 /* PCI_DEVICE_ID_DCI_PCCOM8 ? */
-- { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
-- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-- pbn_dci_pccom8 },
--#endif
--
-- { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
-- PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, },
-- { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
-- PCI_CLASS_COMMUNICATION_MODEM << 8, 0xffff00, },
-- { 0, }
--};
--
--MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
--
--static struct pci_driver serial_pci_driver = {
-- name: "serial",
-- probe: serial_init_one,
-- remove: __devexit_p(serial_remove_one),
-- id_table: serial_pci_tbl,
--};
--
--
--/*
-- * Query PCI space for known serial boards
-- * If found, add them to the PCI device space in rs_table[]
-- *
-- * Accept a maximum of eight boards
-- *
-- */
--static void __devinit probe_serial_pci(void)
--{
--#ifdef SERIAL_DEBUG_PCI
-- printk(KERN_DEBUG "Entered probe_serial_pci()\n");
--#endif
--
-- /* Register call PCI serial devices. Null out
-- * the driver name upon failure, as a signal
-- * not to attempt to unregister the driver later
-- */
-- if (pci_module_init (&serial_pci_driver) != 0)
-- serial_pci_driver.name = "";
--
--#ifdef SERIAL_DEBUG_PCI
-- printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
--#endif
-- return;
--}
--
--#endif /* ENABLE_SERIAL_PCI */
--
--#ifdef ENABLE_SERIAL_PNP
--
--struct pnp_board {
-- unsigned short vendor;
-- unsigned short device;
--};
--
--static struct pnp_board pnp_devices[] __devinitdata = {
-- /* Archtek America Corp. */
-- /* Archtek SmartLink Modem 3334BT Plug & Play */
-- { ISAPNP_VENDOR('A', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
-- /* Anchor Datacomm BV */
-- /* SXPro 144 External Data Fax Modem Plug & Play */
-- { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0001) },
-- /* SXPro 288 External Data Fax Modem Plug & Play */
-- { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0002) },
-- /* Rockwell 56K ACF II Fax+Data+Voice Modem */
-- { ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021) },
-- /* AZT3005 PnP SOUND DEVICE */
-- { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001) },
-- /* Best Data Products Inc. Smart One 336F PnP Modem */
-- { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) },
-- /* Boca Research */
-- /* Boca Complete Ofc Communicator 14.4 Data-FAX */
-- { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) },
-- /* Boca Research 33,600 ACF Modem */
-- { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400) },
-- /* Boca 33.6 Kbps Internal FD34FSVD */
-- { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x3400) },
-- /* Boca 33.6 Kbps Internal FD34FSVD */
-- { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) },
-- /* Best Data Products Inc. Smart One 336F PnP Modem */
-- { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) },
-- /* Computer Peripherals Inc */
-- /* EuroViVa CommCenter-33.6 SP PnP */
-- { ISAPNP_VENDOR('C', 'P', 'I'), ISAPNP_DEVICE(0x4050) },
-- /* Creative Labs */
-- /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
-- { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3001) },
-- /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
-- { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3011) },
-- /* Creative */
-- /* Creative Modem Blaster Flash56 DI5601-1 */
-- { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032) },
-- /* Creative Modem Blaster V.90 DI5660 */
-- { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001) },
-- /* FUJITSU */
-- /* Fujitsu 33600 PnP-I2 R Plug & Play */
-- { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0202) },
-- /* Fujitsu FMV-FX431 Plug & Play */
-- { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0205) },
-- /* Fujitsu 33600 PnP-I4 R Plug & Play */
-- { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0206) },
-- /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
-- { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0209) },
-- /* Archtek America Corp. */
-- /* Archtek SmartLink Modem 3334BT Plug & Play */
-- { ISAPNP_VENDOR('G', 'V', 'C'), ISAPNP_DEVICE(0x000F) },
-- /* Hayes */
-- /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
-- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x0001) },
-- /* Hayes Optima 336 V.34 + FAX + Voice PnP */
-- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000C) },
-- /* Hayes Optima 336B V.34 + FAX + Voice PnP */
-- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000D) },
-- /* Hayes Accura 56K Ext Fax Modem PnP */
-- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5670) },
-- /* Hayes Accura 56K Ext Fax Modem PnP */
-- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5674) },
-- /* Hayes Accura 56K Fax Modem PnP */
-- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5675) },
-- /* Hayes 288, V.34 + FAX */
-- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF000) },
-- /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
-- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF001) },
-- /* IBM */
-- /* IBM Thinkpad 701 Internal Modem Voice */
-- { ISAPNP_VENDOR('I', 'B', 'M'), ISAPNP_DEVICE(0x0033) },
-- /* Intertex */
-- /* Intertex 28k8 33k6 Voice EXT PnP */
-- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC801) },
-- /* Intertex 33k6 56k Voice EXT PnP */
-- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC901) },
-- /* Intertex 28k8 33k6 Voice SP EXT PnP */
-- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD801) },
-- /* Intertex 33k6 56k Voice SP EXT PnP */
-- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD901) },
-- /* Intertex 28k8 33k6 Voice SP INT PnP */
-- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF401) },
-- /* Intertex 28k8 33k6 Voice SP EXT PnP */
-- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF801) },
-- /* Intertex 33k6 56k Voice SP EXT PnP */
-- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF901) },
-- /* Kortex International */
-- /* KORTEX 28800 Externe PnP */
-- { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0x4522) },
-- /* KXPro 33.6 Vocal ASVD PnP */
-- { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0xF661) },
-- /* Lasat */
-- /* LASAT Internet 33600 PnP */
-- { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4040) },
-- /* Lasat Safire 560 PnP */
-- { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4540) },
-- /* Lasat Safire 336 PnP */
-- { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x5440) },
-- /* Microcom, Inc. */
-- /* Microcom TravelPorte FAST V.34 Plug & Play */
-- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x281) },
-- /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
-- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0336) },
-- /* Microcom DeskPorte FAST EP 28.8 Plug & Play */
-- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0339) },
-- /* Microcom DeskPorte 28.8P Plug & Play */
-- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0342) },
-- /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
-- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0500) },
-- /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
-- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0501) },
-- /* Microcom DeskPorte 28.8S Internal Plug & Play */
-- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0502) },
-- /* Motorola */
-- /* Motorola BitSURFR Plug & Play */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1105) },
-- /* Motorola TA210 Plug & Play */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1111) },
-- /* Motorola HMTA 200 (ISDN) Plug & Play */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1114) },
-- /* Motorola BitSURFR Plug & Play */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1115) },
-- /* Motorola Lifestyle 28.8 Internal */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1190) },
-- /* Motorola V.3400 Plug & Play */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1501) },
-- /* Motorola Lifestyle 28.8 V.34 Plug & Play */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1502) },
-- /* Motorola Power 28.8 V.34 Plug & Play */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1505) },
-- /* Motorola ModemSURFR External 28.8 Plug & Play */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1509) },
-- /* Motorola Premier 33.6 Desktop Plug & Play */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150A) },
-- /* Motorola VoiceSURFR 56K External PnP */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150F) },
-- /* Motorola ModemSURFR 56K External PnP */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1510) },
-- /* Motorola ModemSURFR 56K Internal PnP */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1550) },
-- /* Motorola ModemSURFR Internal 28.8 Plug & Play */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1560) },
-- /* Motorola Premier 33.6 Internal Plug & Play */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1580) },
-- /* Motorola OnlineSURFR 28.8 Internal Plug & Play */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15B0) },
-- /* Motorola VoiceSURFR 56K Internal PnP */
-- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0) },
-- /* Com 1 */
-- /* Deskline K56 Phone System PnP */
-- { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00A1) },
-- /* PC Rider K56 Phone System PnP */
-- { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00F2) },
-- /* Pace 56 Voice Internal Plug & Play Modem */
-- { ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430) },
-- /* Generic */
-- /* Generic standard PC COM port */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500) },
-- /* Generic 16550A-compatible COM port */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501) },
-- /* Compaq 14400 Modem */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000) },
-- /* Compaq 2400/9600 Modem */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001) },
-- /* Dial-Up Networking Serial Cable between 2 PCs */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC031) },
-- /* Dial-Up Networking Parallel Cable between 2 PCs */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC032) },
-- /* Standard 9600 bps Modem */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC100) },
-- /* Standard 14400 bps Modem */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC101) },
-- /* Standard 28800 bps Modem*/
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC102) },
-- /* Standard Modem*/
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC103) },
-- /* Standard 9600 bps Modem*/
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC104) },
-- /* Standard 14400 bps Modem*/
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC105) },
-- /* Standard 28800 bps Modem*/
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC106) },
-- /* Standard Modem */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC107) },
-- /* Standard 9600 bps Modem */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC108) },
-- /* Standard 14400 bps Modem */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC109) },
-- /* Standard 28800 bps Modem */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10A) },
-- /* Standard Modem */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10B) },
-- /* Standard 9600 bps Modem */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10C) },
-- /* Standard 14400 bps Modem */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10D) },
-- /* Standard 28800 bps Modem */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10E) },
-- /* Standard Modem */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10F) },
-- /* Standard PCMCIA Card Modem */
-- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x2000) },
-- /* Rockwell */
-- /* Modular Technology */
-- /* Rockwell 33.6 DPF Internal PnP */
-- /* Modular Technology 33.6 Internal PnP */
-- { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0030) },
-- /* Kortex International */
-- /* KORTEX 14400 Externe PnP */
-- { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0100) },
-- /* Viking Components, Inc */
-- /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
-- { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x4920) },
-- /* Rockwell */
-- /* British Telecom */
-- /* Modular Technology */
-- /* Rockwell 33.6 DPF External PnP */
-- /* BT Prologue 33.6 External PnP */
-- /* Modular Technology 33.6 External PnP */
-- { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x00A0) },
-- /* Viking 56K FAX INT */
-- { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262) },
-- /* SupraExpress 28.8 Data/Fax PnP modem */
-- { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310) },
-- /* SupraExpress 33.6 Data/Fax PnP modem */
-- { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1421) },
-- /* SupraExpress 33.6 Data/Fax PnP modem */
-- { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1590) },
-- /* SupraExpress 33.6 Data/Fax PnP modem */
-- { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1760) },
-- /* Phoebe Micro */
-- /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
-- { ISAPNP_VENDOR('T', 'E', 'X'), ISAPNP_DEVICE(0x0011) },
-- /* Archtek America Corp. */
-- /* Archtek SmartLink Modem 3334BT Plug & Play */
-- { ISAPNP_VENDOR('U', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
-- /* 3Com Corp. */
-- /* Gateway Telepath IIvi 33.6 */
-- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0000) },
-- /* Sportster Vi 14.4 PnP FAX Voicemail */
-- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0004) },
-- /* U.S. Robotics 33.6K Voice INT PnP */
-- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006) },
-- /* U.S. Robotics 33.6K Voice EXT PnP */
-- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0007) },
-- /* U.S. Robotics 33.6K Voice INT PnP */
-- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2002) },
-- /* U.S. Robotics 56K Voice INT PnP */
-- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2070) },
-- /* U.S. Robotics 56K Voice EXT PnP */
-- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2080) },
-- /* U.S. Robotics 56K FAX INT */
-- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031) },
-- /* U.S. Robotics 56K Voice INT PnP */
-- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3070) },
-- /* U.S. Robotics 56K Voice EXT PnP */
-- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3080) },
-- /* U.S. Robotics 56K Voice INT PnP */
-- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3090) },
-- /* U.S. Robotics 56K Message */
-- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9100) },
-- /* U.S. Robotics 56K FAX EXT PnP*/
-- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9160) },
-- /* U.S. Robotics 56K FAX INT PnP*/
-- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9170) },
-- /* U.S. Robotics 56K Voice EXT PnP*/
-- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9180) },
-- /* U.S. Robotics 56K Voice INT PnP*/
-- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9190) },
-- { 0, }
--};
--
--static inline void avoid_irq_share(struct pci_dev *dev)
--{
-- int i, map = 0x1FF8;
-- struct serial_state *state = rs_table;
-- struct isapnp_irq *irq;
-- struct isapnp_resources *res = dev->sysdata;
--
-- for (i = 0; i < NR_PORTS; i++) {
-- if (state->type != PORT_UNKNOWN)
-- clear_bit(state->irq, &map);
-- state++;
-- }
--
-- for ( ; res; res = res->alt)
-- for(irq = res->irq; irq; irq = irq->next)
-- irq->map = map;
--}
--
--static char *modem_names[] __devinitdata = {
-- "MODEM", "Modem", "modem", "FAX", "Fax", "fax",
-- "56K", "56k", "K56", "33.6", "28.8", "14.4",
-- "33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
-- "33600", "28800", "14400", "V.90", "V.34", "V.32", 0
--};
--
--static int __devinit check_name(char *name)
--{
-- char **tmp = modem_names;
--
-- while (*tmp) {
-- if (strstr(name, *tmp))
-- return 1;
-- tmp++;
-- }
-- return 0;
--}
--
--static inline int check_compatible_id(struct pci_dev *dev)
--{
-- int i;
-- for (i = 0; i < DEVICE_COUNT_COMPATIBLE; i++)
-- if ((dev->vendor_compatible[i] ==
-- ISAPNP_VENDOR('P', 'N', 'P')) &&
-- (swab16(dev->device_compatible[i]) >= 0xc000) &&
-- (swab16(dev->device_compatible[i]) <= 0xdfff))
-- return 0;
-- return 1;
--}
--
--/*
-- * Given a complete unknown ISA PnP device, try to use some heuristics to
-- * detect modems. Currently use such heuristic set:
-- * - dev->name or dev->bus->name must contain "modem" substring;
-- * - device must have only one IO region (8 byte long) with base adress
-- * 0x2e8, 0x3e8, 0x2f8 or 0x3f8.
-- *
-- * Such detection looks very ugly, but can detect at least some of numerous
-- * ISA PnP modems, alternatively we must hardcode all modems in pnp_devices[]
-- * table.
-- */
--static int _INLINE_ serial_pnp_guess_board(struct pci_dev *dev,
-- struct pci_board *board)
--{
-- struct isapnp_resources *res = (struct isapnp_resources *)dev->sysdata;
-- struct isapnp_resources *resa;
--
-- if (!(check_name(dev->name) || check_name(dev->bus->name)) &&
-- !(check_compatible_id(dev)))
-- return 1;
--
-- if (!res || res->next)
-- return 1;
--
-- for (resa = res->alt; resa; resa = resa->alt) {
-- struct isapnp_port *port;
-- for (port = res->port; port; port = port->next)
-- if ((port->size == 8) &&
-- ((port->min == 0x2f8) ||
-- (port->min == 0x3f8) ||
-- (port->min == 0x2e8) ||
-- (port->min == 0x3e8)))
-- return 0;
-- }
--
-- return 1;
--}
--
--static void __devinit probe_serial_pnp(void)
--{
-- struct pci_dev *dev = NULL;
-- struct pnp_board *pnp_board;
-- struct pci_board board;
--
--#ifdef SERIAL_DEBUG_PNP
-- printk("Entered probe_serial_pnp()\n");
--#endif
-- if (!isapnp_present()) {
--#ifdef SERIAL_DEBUG_PNP
-- printk("Leaving probe_serial_pnp() (no isapnp)\n");
--#endif
-- return;
-- }
--
-- isapnp_for_each_dev(dev) {
-- if (dev->active)
-- continue;
--
-- memset(&board, 0, sizeof(board));
-- board.flags = SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT;
-- board.num_ports = 1;
-- board.base_baud = 115200;
--
-- for (pnp_board = pnp_devices; pnp_board->vendor; pnp_board++)
-- if ((dev->vendor == pnp_board->vendor) &&
-- (dev->device == pnp_board->device))
-- break;
--
-- if (pnp_board->vendor) {
-- /* Special case that's more efficient to hardcode */
-- if ((pnp_board->vendor == ISAPNP_VENDOR('A', 'K', 'Y') &&
-- pnp_board->device == ISAPNP_DEVICE(0x1021)))
-- board.flags |= SPCI_FL_NO_SHIRQ;
-- } else {
-- if (serial_pnp_guess_board(dev, &board))
-- continue;
-- }
--
-- if (board.flags & SPCI_FL_NO_SHIRQ)
-- avoid_irq_share(dev);
-- start_pci_pnp_board(dev, &board);
-- }
--
--#ifdef SERIAL_DEBUG_PNP
-- printk("Leaving probe_serial_pnp() (probe finished)\n");
--#endif
-- return;
--}
--
--#endif /* ENABLE_SERIAL_PNP */
--
--/*
-- * The serial driver boot-time initialization code!
-- */
--static int __init rs_init(void)
--{
-- int i;
-- struct serial_state * state;
--
-- init_bh(SERIAL_BH, do_serial_bh);
-- init_timer(&serial_timer);
-- serial_timer.function = rs_timer;
-- mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
--
-- for (i = 0; i < NR_IRQS; i++) {
-- IRQ_ports[i] = 0;
-- IRQ_timeout[i] = 0;
--#ifdef CONFIG_SERIAL_MULTIPORT
-- memset(&rs_multiport[i], 0,
-- sizeof(struct rs_multiport_struct));
--#endif
-- }
--#ifdef CONFIG_SERIAL_CONSOLE
-- /*
-- * The interrupt of the serial console port
-- * can't be shared.
-- */
-- if (sercons.flags & CON_CONSDEV) {
-- for(i = 0; i < NR_PORTS; i++)
-- if (i != sercons.index &&
-- rs_table[i].irq == rs_table[sercons.index].irq)
-- rs_table[i].irq = 0;
-- }
--#endif
-- show_serial_version();
--
-- /* Initialize the tty_driver structure */
--
-- memset(&serial_driver, 0, sizeof(struct tty_driver));
-- serial_driver.magic = TTY_DRIVER_MAGIC;
--#if (LINUX_VERSION_CODE > 0x20100)
-- serial_driver.driver_name = "serial";
--#endif
--#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
-- serial_driver.name = "tts/%d";
--#else
-- serial_driver.name = "ttyS";
--#endif
-- serial_driver.major = TTY_MAJOR;
-- serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET;
-- serial_driver.name_base = SERIAL_DEV_OFFSET;
-- serial_driver.num = NR_PORTS;
-- serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
-- serial_driver.subtype = SERIAL_TYPE_NORMAL;
-- serial_driver.init_termios = tty_std_termios;
-- serial_driver.init_termios.c_cflag =
-- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-- serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
-- serial_driver.refcount = &serial_refcount;
-- serial_driver.table = serial_table;
-- serial_driver.termios = serial_termios;
-- serial_driver.termios_locked = serial_termios_locked;
--
-- serial_driver.open = rs_open;
-- serial_driver.close = rs_close;
-- serial_driver.write = rs_write;
-- serial_driver.put_char = rs_put_char;
-- serial_driver.flush_chars = rs_flush_chars;
-- serial_driver.write_room = rs_write_room;
-- serial_driver.chars_in_buffer = rs_chars_in_buffer;
-- serial_driver.flush_buffer = rs_flush_buffer;
-- serial_driver.ioctl = rs_ioctl;
-- serial_driver.throttle = rs_throttle;
-- serial_driver.unthrottle = rs_unthrottle;
-- serial_driver.set_termios = rs_set_termios;
-- serial_driver.stop = rs_stop;
-- serial_driver.start = rs_start;
-- serial_driver.hangup = rs_hangup;
--#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
-- serial_driver.break_ctl = rs_break;
--#endif
--#if (LINUX_VERSION_CODE >= 131343)
-- serial_driver.send_xchar = rs_send_xchar;
-- serial_driver.wait_until_sent = rs_wait_until_sent;
-- serial_driver.read_proc = rs_read_proc;
--#endif
--
-- /*
-- * The callout device is just like normal device except for
-- * major number and the subtype code.
-- */
-- callout_driver = serial_driver;
--#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
-- callout_driver.name = "cua/%d";
--#else
-- callout_driver.name = "cua";
--#endif
-- callout_driver.major = TTYAUX_MAJOR;
-- callout_driver.subtype = SERIAL_TYPE_CALLOUT;
--#if (LINUX_VERSION_CODE >= 131343)
-- callout_driver.read_proc = 0;
-- callout_driver.proc_entry = 0;
--#endif
--
-- if (tty_register_driver(&serial_driver))
-- panic("Couldn't register serial driver\n");
-- if (tty_register_driver(&callout_driver))
-- panic("Couldn't register callout driver\n");
--
-- for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
-- state->magic = SSTATE_MAGIC;
-- state->line = i;
-- state->custom_divisor = 0;
-- state->close_delay = 5*HZ/10;
-- state->closing_wait = 30*HZ;
-- state->callout_termios = callout_driver.init_termios;
-- state->normal_termios = serial_driver.init_termios;
-- state->icount.cts = state->icount.dsr =
-- state->icount.rng = state->icount.dcd = 0;
-- state->icount.rx = state->icount.tx = 0;
-- state->icount.frame = state->icount.parity = 0;
-- state->icount.overrun = state->icount.brk = 0;
-- state->irq = irq_cannonicalize(state->irq);
-- if (state->hub6)
-- state->io_type = SERIAL_IO_HUB6;
-- if (state->port && check_region(state->port,8)) {
-- state->type = PORT_UNKNOWN;
-- continue;
-- }
--#ifdef CONFIG_MCA
-- if ((state->flags & ASYNC_BOOT_ONLYMCA) && !MCA_bus)
-- continue;
--#endif
-- if (state->flags & ASYNC_BOOT_AUTOCONF) {
-- state->type = PORT_UNKNOWN;
-- autoconfig(state);
-- }
-- }
-- for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
-- if (state->type == PORT_UNKNOWN)
-- continue;
-- if ( (state->flags & ASYNC_BOOT_AUTOCONF)
-- && (state->flags & ASYNC_AUTO_IRQ)
-- && (state->port != 0 || state->iomem_base != 0))
-- state->irq = detect_uart_irq(state);
-- if (state->io_type == SERIAL_IO_MEM) {
-- printk(KERN_INFO"ttyS%02d%s at 0x%p (irq = %d) is a %s\n",
-- state->line + SERIAL_DEV_OFFSET,
-- (state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
-- state->iomem_base, state->irq,
-- uart_config[state->type].name);
-- }
-- else {
-- printk(KERN_INFO "ttyS%02d%s at 0x%04lx (irq = %d) is a %s\n",
-- state->line + SERIAL_DEV_OFFSET,
-- (state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
-- state->port, state->irq,
-- uart_config[state->type].name);
-- }
-- tty_register_devfs(&serial_driver, 0,
-- serial_driver.minor_start + state->line);
-- tty_register_devfs(&callout_driver, 0,
-- callout_driver.minor_start + state->line);
-- }
--#ifdef ENABLE_SERIAL_PCI
-- probe_serial_pci();
--#endif
--#ifdef ENABLE_SERIAL_PNP
-- probe_serial_pnp();
--#endif
-- return 0;
--}
--
--/*
-- * This is for use by architectures that know their serial console
-- * attributes only at run time. Not to be invoked after rs_init().
-- */
--int __init early_serial_setup(struct serial_struct *req)
--{
-- int i = req->line;
--
-- if (i >= NR_IRQS)
-- return(-ENOENT);
-- rs_table[i].magic = 0;
-- rs_table[i].baud_base = req->baud_base;
-- rs_table[i].port = req->port;
-- if (HIGH_BITS_OFFSET)
-- rs_table[i].port += (unsigned long) req->port_high <<
-- HIGH_BITS_OFFSET;
-- rs_table[i].irq = req->irq;
-- rs_table[i].flags = req->flags;
-- rs_table[i].close_delay = req->close_delay;
-- rs_table[i].io_type = req->io_type;
-- rs_table[i].hub6 = req->hub6;
-- rs_table[i].iomem_base = req->iomem_base;
-- rs_table[i].iomem_reg_shift = req->iomem_reg_shift;
-- rs_table[i].type = req->type;
-- rs_table[i].xmit_fifo_size = req->xmit_fifo_size;
-- rs_table[i].custom_divisor = req->custom_divisor;
-- rs_table[i].closing_wait = req->closing_wait;
-- return(0);
--}
--
--/*
- * register_serial and unregister_serial allows for 16x50 serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-@@ -5734,11 +3316,8 @@
- }
- restore_flags(flags);
-
-- if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state))
-- state->irq = detect_uart_irq(state);
--
- printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n",
-- state->line + SERIAL_DEV_OFFSET,
-+ state->line,
- state->iomem_base ? "iomem" : "port",
- state->iomem_base ? (unsigned long)state->iomem_base :
- state->port, state->irq, uart_config[state->type].name);
-@@ -5746,7 +3325,7 @@
- serial_driver.minor_start + state->line);
- tty_register_devfs(&callout_driver, 0,
- callout_driver.minor_start + state->line);
-- return state->line + SERIAL_DEV_OFFSET;
-+ return state->line;
- }
-
- /**
-@@ -5785,7 +3364,6 @@
- int i;
- struct async_struct *info;
-
-- /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
- del_timer_sync(&serial_timer);
- save_flags(flags); cli();
- remove_bh(SERIAL_BH);
-@@ -5803,41 +3381,31 @@
- kfree(info);
- }
- if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) {
--#ifdef CONFIG_SERIAL_RSA
-- if (rs_table[i].type == PORT_RSA)
-- release_region(rs_table[i].port +
-- UART_RSA_BASE, 16);
-- else
--#endif
- release_region(rs_table[i].port, 8);
- }
--#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
-- if (rs_table[i].iomem_base)
-- iounmap(rs_table[i].iomem_base);
--#endif
-- }
--#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
-- for (i=0; i < NR_PCI_BOARDS; i++) {
-- struct pci_board_inst *brd = &serial_pci_board[i];
--
-- if (serial_pci_board[i].dev == 0)
-- continue;
-- if (brd->board.init_fn)
-- (brd->board.init_fn)(brd->dev, &brd->board, 0);
-- if (DEACTIVATE_FUNC(brd->dev))
-- (DEACTIVATE_FUNC(brd->dev))(brd->dev);
- }
--#endif
- if (tmp_buf) {
- unsigned long pg = (unsigned long) tmp_buf;
- tmp_buf = NULL;
- free_page(pg);
- }
-
--#ifdef ENABLE_SERIAL_PCI
-- if (serial_pci_driver.name[0])
-- pci_unregister_driver (&serial_pci_driver);
--#endif
-+ if (ramses_uarta) {
-+ iounmap(ramses_uarta);
-+ release_mem_region(RAMSES_UARTA_PHYS, 16*4);
-+ }
-+ if (ramses_uartb) {
-+ iounmap(ramses_uartb);
-+ release_mem_region(RAMSES_UARTB_PHYS, 16*4);
-+ }
-+ if (ramses_uartc) {
-+ iounmap(ramses_uartc);
-+ release_mem_region(RAMSES_UARTC_PHYS, 16*4);
-+ }
-+ if (ramses_uartd) {
-+ iounmap(ramses_uartd);
-+ release_mem_region(RAMSES_UARTD_PHYS, 16*4);
-+ }
- }
-
- module_init(rs_init);
-@@ -5946,7 +3514,7 @@
- static struct async_struct *info;
- struct serial_state *state;
- unsigned cval;
-- int baud = 9600;
-+ int baud = 115200;
- int bits = 8;
- int parity = 'n';
- int doflow = 0;
-@@ -5954,6 +3522,8 @@
- int quot = 0;
- char *s;
-
-+ printk("%s\n", __FUNCTION__);
-+
- if (options) {
- baud = simple_strtoul(options, NULL, 10);
- s = options;
-@@ -6028,19 +3598,12 @@
- info->state = state;
- info->port = state->port;
- info->flags = state->flags;
--#ifdef CONFIG_HUB6
-- info->hub6 = state->hub6;
--#endif
- info->io_type = state->io_type;
- info->iomem_base = state->iomem_base;
- info->iomem_reg_shift = state->iomem_reg_shift;
- quot = state->baud_base / baud;
- cval = cflag & (CSIZE | CSTOPB);
--#if defined(__powerpc__) || defined(__alpha__)
-- cval >>= 8;
--#else /* !__powerpc__ && !__alpha__ */
- cval >>= 4;
--#endif /* !__powerpc__ && !__alpha__ */
- if (cflag & PARENB)
- cval |= UART_LCR_PARITY;
- if (!(cflag & PARODD))
-@@ -6082,10 +3645,15 @@
- */
- void __init serial_console_init(void)
- {
-+ printk("%s\n", __FUNCTION__);
-+
- register_console(&sercons);
- }
- #endif
-
-+EXPORT_SYMBOL(register_serial);
-+EXPORT_SYMBOL(unregister_serial);
-+
- /*
- Local variables:
- compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i586 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c"
---- /dev/null
-+++ linux-2.4.21/drivers/char/sysctl.c
-@@ -0,0 +1,948 @@
-+/*
-+ * /proc/sys-board - Interface to the 16 bit latch and other
-+ * ramses-related hardware settings
-+ *
-+ * (C) 2002,2003 by M&N Logistik-Lösungen Online GmbH
-+ * written by H.Schurig
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/sysctl.h>
-+#include <linux/crc32.h>
-+#include <linux/delay.h>
-+#include <linux/pm.h>
-+
-+#include <asm/io.h>
-+#include <asm/arch/ramses.h>
-+#include <asm/uaccess.h>
-+
-+#include "../drivers/misc/ucb1x00.h"
-+
-+//#define DEBUG
-+//define CPLD_LED 1
-+//define POTI 1
-+
-+/*
-+ * This is the number for the "board" entry in /proc/sys:
-+ */
-+#define RAMSES_SYSCTL 1312
-+
-+/*
-+ * These are the numbers for the entries in /etc/sys/board
-+ */
-+enum {
-+ CTL_NAME=991,
-+ CTL_CPLD_VERSION,
-+ CTL_BOOTLOADER_CRC,
-+ CTL_LINUX_CRC,
-+ CTL_LED_BLUE,
-+ CTL_LED_ORANGE,
-+ CTL_UART,
-+ CTL_MMC,
-+ CTL_POWEROFF,
-+ CTL_GSM_POWER,
-+ CTL_GSM_RESET,
-+ CTL_SCANNER_POWER,
-+ CTL_SCANNER_WAKE,
-+ CTL_SCANNER_TRIG,
-+ CTL_SCANNER_BEAM,
-+ CTL_KEY_SCAN,
-+ CTL_KEY_SUSPEND,
-+ CTL_KEY_OFF,
-+ CTL_USBBUS_POWER,
-+ CTL_USBCHIP_POWER,
-+#ifdef CPLD_LED
-+ CTL_LED_CPLD,
-+ CTL_LED_CPLD_RED,
-+#endif
-+ CTL_LCD_VCC,
-+ CTL_LCD_DISPOFF,
-+ CTL_LCD_BLIGHT,
-+#ifdef DEBUG
-+ CTL_LCD_PWM0,
-+ CTL_LCD_PWM1,
-+#endif
-+ CTL_LCD_BRIGHTNESS,
-+ CTL_LCD_CONTRAST,
-+ CTL_LCD_FBTURN,
-+ CTL_LCD_TYPE,
-+ CTL_CONTROL_SHADOW,
-+ CTL_COREVOLT,
-+#ifdef POTI
-+ CTL_LCD_POTI_NINC,
-+ CTL_LCD_POTI_NCS,
-+ CTL_LCD_POTI_UP,
-+#endif
-+#ifdef CONFIG_MCP_UCB1400_TS
-+ CTL_ADC0,
-+ CTL_ADC1,
-+ CTL_ADC2,
-+ CTL_ADC3,
-+#else
-+#error NO UCB
-+#endif
-+ CTL_CHG_STS,
-+ CTL_WALL_IN,
-+ CTL_BATT_TMP,
-+ CTL_BATT_LMD,
-+ CTL_BATT_VSB,
-+ CTL_BATT_RCAC,
-+ CTL_BATT_CACT,
-+ CTL_BATT_SAE,
-+ CTL_BATT_DCR,
-+};
-+
-+static const char ramses_board_name[] = "ramses";
-+static int dummy_int = 0;
-+static char dummy_str[80];
-+
-+
-+
-+/******************************************************************/
-+/* ADC communication */
-+/******************************************************************/
-+
-+
-+#ifdef CONFIG_MCP_UCB1400_TS
-+static int adc_get(int channel)
-+{
-+ int val;
-+ struct ucb1x00 *ucb = ucb1x00_get();
-+
-+ ucb1x00_adc_enable(ucb);
-+ val = ucb1x00_adc_read(ucb, channel, 0);
-+ ucb1x00_adc_disable(ucb);
-+
-+ return val;
-+}
-+#endif
-+
-+
-+
-+static int
-+ramses_sysctl_handler(ctl_table * ctl, int write, struct file *filp,
-+ void *buffer, size_t * lenp)
-+{
-+ int *valp = ctl->data;
-+ int val;
-+ int ret;
-+ unsigned crc;
-+ void *flash;
-+
-+#ifdef DEBUG
-+ printk("ramses_control_shadow: %04x\n", ramses_control_shadow);
-+#endif
-+
-+ // Update parameters from the real registers
-+ switch (ctl->ctl_name) {
-+ case CTL_CPLD_VERSION:
-+ sprintf(dummy_str,"20%02ld-%02ld-%02ld.%ld\n",
-+ RAMSES_CPLD_YEAR & 0xff,
-+ RAMSES_CPLD_MONTH & 0xff,
-+ RAMSES_CPLD_DAY & 0xff,
-+ RAMSES_CPLD_REV & 0xff);
-+ return proc_dostring(ctl,write,filp,buffer,lenp);
-+
-+ case CTL_BOOTLOADER_CRC:
-+ flash = ioremap_nocache(RAMSES_FLASH_PHYS, 0x40000);
-+ crc = ether_crc_le(0x40000, flash);
-+ iounmap(flash);
-+ sprintf(dummy_str,"%08x", crc);
-+ return proc_dostring(ctl,write,filp,buffer,lenp);
-+
-+ case CTL_LINUX_CRC:
-+ flash = ioremap_nocache(RAMSES_FLASH_PHYS+0x40000, 3*0x40000);
-+ crc = ether_crc_le(3*0x40000, flash);
-+ iounmap(flash);
-+ sprintf(dummy_str,"%08x", crc);
-+ return proc_dostring(ctl,write,filp,buffer,lenp);
-+
-+ case CTL_LED_BLUE:
-+ *valp = (ramses_control_shadow & RAMSES_CONTROL_LED_BLUE_) == 0;
-+ break;
-+ case CTL_LED_ORANGE:
-+ *valp = (ramses_control_shadow & RAMSES_CONTROL_LED_ORANGE_) == 0;
-+ break;
-+ case CTL_UART:
-+ *valp = (ramses_control_shadow & RAMSES_CONTROL_UART_PWR) != 0;
-+ break;
-+ case CTL_MMC:
-+ *valp = (ramses_control_shadow & RAMSES_CONTROL_MMC_PWR) != 0;
-+ break;
-+ case CTL_POWEROFF:
-+ *valp = 0;
-+ break;
-+ case CTL_GSM_POWER:
-+ *valp = (ramses_control_shadow & RAMSES_CONTROL_GSM_PWR) != 0;
-+ break;
-+ case CTL_GSM_RESET:
-+ *valp = (ramses_control_shadow & RAMSES_CONTROL_GSM_RESET) != 0;
-+ break;
-+
-+ case CTL_SCANNER_POWER:
-+ *valp = (ramses_control_shadow & RAMSES_CONTROL_SCANNER_PWR) != 0;
-+ break;
-+ case CTL_SCANNER_WAKE:
-+ *valp = (ramses_control_shadow & RAMSES_CONTROL_SCANNER_WAKE_) == 0;
-+ break;
-+ case CTL_SCANNER_TRIG:
-+ *valp = (ramses_control_shadow & RAMSES_CONTROL_SCANNER_TRIG_) == 0;
-+ break;
-+ case CTL_SCANNER_BEAM:
-+ *valp = ramses_flags & RAMSES_FLAGS_SCANNER_BEAM;
-+ break;
-+
-+ case CTL_KEY_SCAN:
-+ *valp = (ramses_flags & RAMSES_FLAGS_KEY_SCAN) != 0;
-+ break;
-+ case CTL_KEY_SUSPEND:
-+ *valp = (ramses_flags & RAMSES_FLAGS_KEY_SUSPEND) != 0;
-+ break;
-+ case CTL_KEY_OFF:
-+ *valp = (ramses_flags & RAMSES_FLAGS_KEY_OFF) != 0;
-+ break;
-+
-+ case CTL_USBBUS_POWER:
-+ *valp = (ramses_control_shadow & RAMSES_CONTROL_USB) != 0;
-+ break;
-+ case CTL_USBCHIP_POWER:
-+ *valp = (RAMSES_CPLD_PERIPH_PWR & USB_HOST_PWR_EN) != 0;
-+ break;
-+#ifdef CPLD_LED
-+ case CTL_LED_CPLD:
-+ *valp = (RAMSES_CPLD_LED_CONTROL & CPLD_LED1) == 0;
-+ break;
-+ case CTL_LED_CPLD_RED:
-+ *valp = (RAMSES_CPLD_LED_CONTROL & CPLD_LED2) == 0;
-+ break;
-+#endif
-+ case CTL_LCD_BLIGHT:
-+ *valp = (ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT) != 0;
-+ break;
-+ case CTL_LCD_VCC:
-+ *valp = (RAMSES_CPLD_LCD & RAMSES_LCD_VCC) != 0;
-+ break;
-+ case CTL_LCD_DISPOFF:
-+ *valp = (RAMSES_CPLD_LCD & RAMSES_LCD_DISPOFF) != 0;
-+ break;
-+#ifdef DEBUG
-+ case CTL_LCD_PWM0:
-+ *valp = PWM_PWDUTY0;
-+ break;
-+ case CTL_LCD_PWM1:
-+#ifdef OLDCODE
-+ *valp = ramses_lcd_pwm1_shadow;
-+#else
-+ *valp = PWM_PWDUTY1;
-+#endif
-+ break;
-+#endif
-+ case CTL_LCD_BRIGHTNESS:
-+ *valp = ramses_lcd_get_brightness();
-+ break;
-+ case CTL_LCD_CONTRAST:
-+ *valp = ramses_lcd_get_contrast();
-+ break;
-+ case CTL_LCD_FBTURN:
-+ *valp = (ramses_flags & RAMSES_FLAGS_LCD_FBTURN) != 0;
-+ break;
-+ case CTL_LCD_TYPE:
-+ *valp = ramses_lcd_type;
-+ break;
-+
-+ case CTL_CONTROL_SHADOW:
-+ sprintf(dummy_str,"%04x", ramses_control_shadow);
-+ return proc_dostring(ctl,write,filp,buffer,lenp);
-+
-+ case CTL_COREVOLT:
-+ *valp = ramses_corevolt_shadow;
-+ break;
-+
-+#ifdef POTI
-+ case CTL_LCD_POTI_NINC:
-+ *valp = (RAMSES_CPLD_LCD & RAMSES_LCD_PINC) != 0;
-+ break;
-+ case CTL_LCD_POTI_NCS:
-+ *valp = (RAMSES_CPLD_LCD & RAMSES_LCD_PCS) != 0;
-+ break;
-+ case CTL_LCD_POTI_UP:
-+ *valp = (RAMSES_CPLD_LCD & RAMSES_LCD_PUP) != 0;
-+ break;
-+#endif
-+
-+#ifdef CONFIG_MCP_UCB1400_TS
-+ case CTL_ADC0:
-+ *valp = adc_get(UCB_ADC_INP_AD0);
-+ break;
-+ case CTL_ADC1:
-+ *valp = adc_get(UCB_ADC_INP_AD1);
-+ break;
-+ case CTL_ADC2:
-+ *valp = adc_get(UCB_ADC_INP_AD2);
-+ break;
-+ case CTL_ADC3:
-+ *valp = adc_get(UCB_ADC_INP_AD3);
-+ break;
-+#endif
-+
-+ case CTL_CHG_STS:
-+ *valp = (RAMSES_CPLD_MISC_STATUS & RAMSES_CHG_STS) == 0;
-+ break;
-+ case CTL_WALL_IN:
-+ *valp = (RAMSES_CPLD_MISC_STATUS & RAMSES_WALL_IN) != 0;
-+ break;
-+
-+ case CTL_BATT_TMP:
-+ *valp = ramses_hdq_get_reg(HDQ_TMP) >> 4;
-+ break;
-+ case CTL_BATT_LMD:
-+ *valp = ramses_hdq_get_reg(HDQ_LMD);
-+ break;
-+ case CTL_BATT_VSB:
-+ *valp = ramses_hdq_get_reg(HDQ_VSB);
-+ break;
-+ case CTL_BATT_RCAC:
-+ *valp = ramses_hdq_get_reg(HDQ_RCAC) & 0x7f;
-+ break;
-+ case CTL_BATT_CACT:
-+ *valp = ramses_hdq_get_reg(HDQ_CACT);
-+ break;
-+ case CTL_BATT_SAE:
-+ *valp = ramses_hdq_get_reg(HDQ_SAEH) << 8 | ramses_hdq_get_reg(HDQ_SAEL);
-+ break;
-+ case CTL_BATT_DCR:
-+ *valp = ramses_hdq_get_reg(HDQ_DCR);
-+ break;
-+
-+ default:
-+ // Just ignore unsupported parameters
-+ break;
-+ }
-+
-+ // Save old state
-+ val = *valp;
-+
-+ // Perform the generic integer operation
-+ if ((ret = proc_dointvec(ctl, write, filp, buffer, lenp)) != 0)
-+ return (ret);
-+
-+ // Write changes out to the registers
-+ if (write && *valp != val) {
-+
-+ val = *valp;
-+ switch (ctl->ctl_name) {
-+
-+ case CTL_LED_BLUE:
-+ if (val)
-+ RAMSES_LED_BLUE_ON()
-+ else
-+ RAMSES_LED_BLUE_OFF();
-+ break;
-+
-+ case CTL_LED_ORANGE:
-+ if (val)
-+ RAMSES_LED_ORANGE_ON()
-+ else
-+ RAMSES_LED_ORANGE_OFF();
-+ break;
-+
-+ case CTL_UART:
-+ if (val)
-+ RAMSES_UART_ON()
-+ else
-+ RAMSES_UART_OFF();
-+ break;
-+
-+ case CTL_MMC:
-+ if (val)
-+ RAMSES_MMC_ON()
-+ else
-+ RAMSES_MMC_OFF();
-+ break;
-+
-+ case CTL_POWEROFF:
-+ if (val)
-+ pm_power_off();
-+ break;
-+
-+ case CTL_GSM_POWER:
-+ if (val)
-+ RAMSES_GSM_ON()
-+ else
-+ RAMSES_GSM_OFF();
-+ break;
-+
-+ case CTL_GSM_RESET:
-+ if (val)
-+ RAMSES_GSM_RESET_ON()
-+ else
-+ RAMSES_GSM_RESET_OFF();
-+ break;
-+
-+ case CTL_SCANNER_POWER:
-+ if (val)
-+ RAMSES_SCANNER_ON()
-+ else
-+ RAMSES_SCANNER_OFF();
-+ break;
-+
-+ case CTL_SCANNER_WAKE:
-+ if (val)
-+ RAMSES_SCANNER_WAKE_ON()
-+ else
-+ RAMSES_SCANNER_WAKE_OFF();
-+ break;
-+
-+ case CTL_SCANNER_TRIG:
-+ if (val)
-+ RAMSES_SCANNER_TRIG_ON()
-+ else
-+ RAMSES_SCANNER_TRIG_OFF();
-+ break;
-+
-+ case CTL_SCANNER_BEAM:
-+ if (val)
-+ ramses_flags |= RAMSES_FLAGS_SCANNER_BEAM;
-+ else
-+ ramses_flags &= ~RAMSES_FLAGS_SCANNER_BEAM;
-+ break;
-+
-+ case CTL_KEY_SCAN:
-+ if (val)
-+ ramses_flags |= RAMSES_FLAGS_KEY_SCAN;
-+ else
-+ ramses_flags &= ~RAMSES_FLAGS_KEY_SCAN;
-+ break;
-+
-+ case CTL_KEY_SUSPEND:
-+ if (val)
-+ ramses_flags |= RAMSES_FLAGS_KEY_SUSPEND;
-+ else
-+ ramses_flags &= ~RAMSES_FLAGS_KEY_SUSPEND;
-+ break;
-+
-+ case CTL_KEY_OFF:
-+ if (val)
-+ ramses_flags |= RAMSES_FLAGS_KEY_OFF;
-+ else
-+ ramses_flags &= ~RAMSES_FLAGS_KEY_OFF;
-+ break;
-+
-+ case CTL_USBBUS_POWER:
-+ if (val)
-+ RAMSES_USB_BUS_ON()
-+ else
-+ RAMSES_USB_BUS_OFF();
-+ break;
-+
-+ case CTL_USBCHIP_POWER:
-+ if (val)
-+ RAMSES_CPLD_PERIPH_PWR |= USB_HOST_PWR_EN;
-+ else
-+ RAMSES_CPLD_PERIPH_PWR &= ~USB_HOST_PWR_EN;
-+ break;
-+
-+#ifdef CPLD_LED
-+ case CTL_LED_CPLD:
-+ if (val)
-+ RAMSES_CPLD_LED_CONTROL &= ~CPLD_LED1;
-+ else
-+ RAMSES_CPLD_LED_CONTROL |= CPLD_LED1;
-+ break;
-+
-+ case CTL_LED_CPLD_RED:
-+ if (val)
-+ RAMSES_CPLD_LED_CONTROL &= ~CPLD_LED2;
-+ else
-+ RAMSES_CPLD_LED_CONTROL |= CPLD_LED2;
-+ break;
-+#endif
-+
-+ case CTL_LCD_BLIGHT:
-+ if (val)
-+ ramses_lcd_backlight_on();
-+ else
-+ ramses_lcd_backlight_off();
-+ break;
-+
-+ case CTL_LCD_VCC:
-+ if (val)
-+ RAMSES_CPLD_LCD |= RAMSES_LCD_VCC;
-+ else
-+ RAMSES_CPLD_LCD &= ~RAMSES_LCD_VCC;
-+ break;
-+
-+ case CTL_LCD_DISPOFF:
-+ if (val)
-+ RAMSES_CPLD_LCD |= RAMSES_LCD_DISPOFF;
-+ else
-+ RAMSES_CPLD_LCD &= ~RAMSES_LCD_DISPOFF;
-+ break;
-+
-+#ifdef DEBUG
-+ case CTL_LCD_PWM0:
-+ PWM_PWDUTY0 = val;
-+ break;
-+
-+ case CTL_LCD_PWM1:
-+#ifdef OLDCODE
-+ ramses_lcd_set_pwm1(val);
-+#else
-+ PWM_PWDUTY1 = val;
-+#endif
-+ break;
-+#endif
-+
-+ case CTL_LCD_BRIGHTNESS:
-+ ramses_lcd_set_brightness(val);
-+ break;
-+
-+ case CTL_LCD_CONTRAST:
-+ ramses_lcd_set_contrast(val);
-+ break;
-+
-+ case CTL_LCD_FBTURN:
-+ if (val)
-+ ramses_flags |= RAMSES_FLAGS_LCD_FBTURN;
-+ else
-+ ramses_flags &= ~RAMSES_FLAGS_LCD_FBTURN;
-+ break;
-+
-+ case CTL_COREVOLT:
-+ ramses_set_corevolt(val);
-+ break;
-+
-+#ifdef POTI
-+ case CTL_LCD_POTI_NCS:
-+ if (val)
-+ RAMSES_CPLD_LCD |= RAMSES_LCD_PCS;
-+ else
-+ RAMSES_CPLD_LCD &= ~RAMSES_LCD_PCS;
-+ break;
-+ case CTL_LCD_POTI_NINC:
-+ if (val)
-+ RAMSES_CPLD_LCD |= RAMSES_LCD_PINC;
-+ else
-+ RAMSES_CPLD_LCD &= ~RAMSES_LCD_PINC;
-+ break;
-+ case CTL_LCD_POTI_UP:
-+ if (val)
-+ RAMSES_CPLD_LCD |= RAMSES_LCD_PUP;
-+ else
-+ RAMSES_CPLD_LCD &= ~RAMSES_LCD_PUP;
-+ break;
-+#endif
-+
-+ default:
-+ // Just ignore unsupported parameters
-+ break;
-+ }
-+ }
-+
-+#ifdef DEBUG
-+ printk("ramses_control_shadow new: %04x\n", ramses_control_shadow);
-+#endif
-+ return ret;
-+}
-+
-+
-+
-+static ctl_table ramses_table[] = {
-+ {
-+ procname: "sys_name",
-+ ctl_name: CTL_NAME,
-+ data: &ramses_board_name,
-+ maxlen: sizeof(ramses_board_name),
-+ proc_handler: &proc_dostring,
-+ mode: 0444, // read-only
-+ }, {
-+ procname: "sys_cpldver",
-+ ctl_name: CTL_CPLD_VERSION,
-+ data: &dummy_str,
-+ maxlen: sizeof(dummy_str),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444, // read-only
-+ }, {
-+ procname: "sys_bootcrc",
-+ ctl_name: CTL_BOOTLOADER_CRC,
-+ data: &dummy_str,
-+ maxlen: sizeof(dummy_str),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444, // read-only
-+ }, {
-+ procname: "sys_linuxcrc",
-+ ctl_name: CTL_LINUX_CRC,
-+ data: &dummy_str,
-+ maxlen: sizeof(dummy_str),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444, // read-only
-+ }, {
-+ procname: "led_blue",
-+ ctl_name: CTL_LED_BLUE,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "led_orange",
-+ ctl_name: CTL_LED_ORANGE,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "pwr_uart",
-+ ctl_name: CTL_UART,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "pwr_mmc",
-+ ctl_name: CTL_MMC,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "pwr_off",
-+ ctl_name: CTL_POWEROFF,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "gsm_power",
-+ ctl_name: CTL_GSM_POWER,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "gsm_reset",
-+ ctl_name: CTL_GSM_RESET,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "scanner_power",
-+ ctl_name: CTL_SCANNER_POWER,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "scanner_wake",
-+ ctl_name: CTL_SCANNER_WAKE,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "scanner_trig",
-+ ctl_name: CTL_SCANNER_TRIG,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "scanner_beam",
-+ ctl_name: CTL_SCANNER_BEAM,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "key_scan",
-+ ctl_name: CTL_KEY_SCAN,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "key_suspend",
-+ ctl_name: CTL_KEY_SUSPEND,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "key_off",
-+ ctl_name: CTL_KEY_OFF,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "usb_bus_power",
-+ ctl_name: CTL_USBBUS_POWER,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "usb_chip_power",
-+ ctl_name: CTL_USBCHIP_POWER,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ },
-+#if LED_CPLD
-+ {
-+ procname: "led_cpld",
-+ ctl_name: CTL_LED_CPLD,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "led_cpld_red",
-+ ctl_name: CTL_LED_CPLD_RED,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ },
-+#endif
-+ {
-+ procname: "lcd_backlight",
-+ ctl_name: CTL_LCD_BLIGHT,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "lcd_vcc",
-+ ctl_name: CTL_LCD_VCC,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "lcd_dispoff",
-+ ctl_name: CTL_LCD_DISPOFF,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "lcd_brightness",
-+ ctl_name: CTL_LCD_BRIGHTNESS,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "lcd_contrast",
-+ ctl_name: CTL_LCD_CONTRAST,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "lcd_fbturn",
-+ ctl_name: CTL_LCD_FBTURN,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "lcd_type",
-+ ctl_name: CTL_LCD_TYPE,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444,
-+ },
-+#ifdef POTI
-+ {
-+ procname: "lcd_poti_ncs",
-+ ctl_name: CTL_LCD_POTI_NCS,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "lcd_poti_ninc",
-+ ctl_name: CTL_LCD_POTI_NINC,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "lcd_poti_up",
-+ ctl_name: CTL_LCD_POTI_UP,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ },
-+#endif
-+#ifdef DEBUG
-+ {
-+ procname: "lcd_pwm0",
-+ ctl_name: CTL_LCD_PWM0,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ }, {
-+ procname: "lcd_pwm1",
-+ ctl_name: CTL_LCD_PWM1,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ },
-+#endif
-+ {
-+ procname: "sys_shadowreg",
-+ ctl_name: CTL_CONTROL_SHADOW,
-+ data: &dummy_str,
-+ maxlen: sizeof(dummy_str),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444,
-+ },
-+ {
-+ procname: "pwr_corevolt",
-+ ctl_name: CTL_COREVOLT,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0664,
-+ },
-+#ifdef CONFIG_MCP_UCB1400_TS
-+ {
-+ procname: "adc0_vcc",
-+ ctl_name: CTL_ADC0,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444,
-+ }, {
-+ procname: "adc1_ntc",
-+ ctl_name: CTL_ADC1,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444,
-+ }, {
-+ procname: "adc2_goldcap",
-+ ctl_name: CTL_ADC2,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444,
-+ }, {
-+ procname: "adc3_batt",
-+ ctl_name: CTL_ADC3,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444,
-+ },
-+#else
-+#error No UCB
-+#endif
-+ {
-+ procname: "pwr_wall_in",
-+ ctl_name: CTL_WALL_IN,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444,
-+ }, {
-+ procname: "batt_charge",
-+ ctl_name: CTL_CHG_STS,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444,
-+ }, {
-+ procname: "batt_temp",
-+ ctl_name: CTL_BATT_TMP,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444,
-+ }, {
-+ procname: "batt_lmd",
-+ ctl_name: CTL_BATT_LMD,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444,
-+ }, {
-+ procname: "batt_vsb",
-+ ctl_name: CTL_BATT_VSB,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444,
-+ }, {
-+ procname: "batt_rcac",
-+ ctl_name: CTL_BATT_RCAC,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444,
-+ }, {
-+ procname: "batt_cact",
-+ ctl_name: CTL_BATT_CACT,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444,
-+ }, {
-+ procname: "batt_sae",
-+ ctl_name: CTL_BATT_SAE,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444,
-+ }, {
-+ procname: "batt_dcr",
-+ ctl_name: CTL_BATT_DCR,
-+ data: &dummy_int,
-+ maxlen: sizeof(int),
-+ proc_handler: &ramses_sysctl_handler,
-+ mode: 0444,
-+ },
-+
-+ {0}
-+ };
-+
-+static ctl_table ramses_root_table[] = {
-+ {RAMSES_SYSCTL, "board", NULL, 0, 0555, ramses_table},
-+ {0}
-+ };
-+
-+
-+static struct ctl_table_header *ramses_table_header;
-+
-+
-+static int __init ramses_sysctl_init(void)
-+{
-+ ramses_table_header = register_sysctl_table(ramses_root_table, 0);
-+ if (!ramses_table_header)
-+ return -ENOMEM;
-+ return 0;
-+}
-+
-+static void __exit ramses_sysctl_exit(void)
-+{
-+ unregister_sysctl_table(ramses_table_header);
-+}
-+
-+
-+module_init(ramses_sysctl_init);
-+module_exit(ramses_sysctl_exit);
-+
-+MODULE_AUTHOR("Holger Schurig <h.schurig@mn-logistik.de>");
-+MODULE_DESCRIPTION("Implements /proc/sys/board");
-+MODULE_LICENSE("GPL");
---- linux-2.4.21/drivers/char/vt.c~linux-vtcomparison
-+++ linux-2.4.21/drivers/char/vt.c
-@@ -163,7 +163,9 @@
-
- if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
- return -EFAULT;
-- if (i >= NR_KEYS || s >= MAX_NR_KEYMAPS)
-+ if (i >= NR_KEYS)
-+ return -EINVAL;
-+ if (s >= MAX_NR_KEYMAPS)
- return -EINVAL;
-
- switch (cmd) {
---- linux-2.4.21/drivers/input/Config.in~keyb-input
-+++ linux-2.4.21/drivers/input/Config.in
-@@ -7,6 +7,8 @@
-
- tristate 'Input core support' CONFIG_INPUT
- dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT
-+dep_tristate ' Ramses keyboard' CONFIG_INPUT_RAMSES_KEYB $CONFIG_INPUT_KEYBDEV $CONFIG_ARCH_RAMSES
-+dep_tristate ' Ramses wedge' CONFIG_INPUT_RAMSES_WEDGE $CONFIG_INPUT_RAMSES_KEYB
- dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT
- if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
- int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
-@@ -14,6 +16,7 @@
- fi
- dep_tristate ' Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_INPUT
- dep_tristate ' Event interface support' CONFIG_INPUT_EVDEV $CONFIG_INPUT
-+dep_tristate ' User level driver support' CONFIG_INPUT_UINPUT $CONFIG_INPUT
- dep_tristate ' MX1 touchscreen support' CONFIG_INPUT_MX1TS $CONFIG_INPUT_MOUSEDEV $CONFIG_ARCH_MX1ADS
-
- endmenu
---- linux-2.4.21/drivers/input/Makefile~bluetooth
-+++ linux-2.4.21/drivers/input/Makefile
-@@ -8,7 +8,7 @@
-
- # Objects that export symbols.
-
--export-objs := input.o
-+export-objs := input.o ramses_keyb.o
-
- # Object file lists.
-
-@@ -21,10 +21,13 @@
-
- obj-$(CONFIG_INPUT) += input.o
- obj-$(CONFIG_INPUT_KEYBDEV) += keybdev.o
-+obj-$(CONFIG_INPUT_RAMSES_KEYB) += ramses_keyb.o
- obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
- obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
- obj-$(CONFIG_INPUT_EVDEV) += evdev.o
-+obj-$(CONFIG_INPUT_UINPUT) += uinput.o
- obj-$(CONFIG_INPUT_MX1TS) += mx1ts.o
-+obj-$(CONFIG_INPUT_RAMSES_WEDGE) += wedge.o
-
- # The global Rules.make.
-
---- linux-2.4.21/drivers/input/keybdev.c~bluetooth
-+++ linux-2.4.21/drivers/input/keybdev.c
-@@ -154,16 +154,18 @@
-
- static struct input_handler keybdev_handler;
-
-+static unsigned int ledstate = 0xff;
-+
- void keybdev_ledfunc(unsigned int led)
- {
- struct input_handle *handle;
-
-- for (handle = keybdev_handler.handle; handle; handle = handle->hnext) {
-+ ledstate = led;
-
-+ for (handle = keybdev_handler.handle; handle; handle = handle->hnext) {
- input_event(handle->dev, EV_LED, LED_SCROLLL, !!(led & 0x01));
- input_event(handle->dev, EV_LED, LED_NUML, !!(led & 0x02));
- input_event(handle->dev, EV_LED, LED_CAPSL, !!(led & 0x04));
--
- }
- }
-
-@@ -203,6 +205,12 @@
- // printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number);
- kbd_refresh_leds();
-
-+ if (ledstate != 0xff) {
-+ input_event(dev, EV_LED, LED_SCROLLL, !!(ledstate & 0x01));
-+ input_event(dev, EV_LED, LED_NUML, !!(ledstate & 0x02));
-+ input_event(dev, EV_LED, LED_CAPSL, !!(ledstate & 0x04));
-+ }
-+
- return handle;
- }
-
---- /dev/null
-+++ linux-2.4.21/drivers/input/ramses_cellmap.h
-@@ -0,0 +1,34 @@
-+static int ramses_cellmap[][8] = {
-+ { KEY_A, KEY_B, KEY_C, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 0
-+ { KEY_D, KEY_E, KEY_F, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 1
-+ { KEY_G, KEY_H, KEY_I, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 2
-+ { KEY_J, KEY_K, KEY_L, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 3
-+ { KEY_M, KEY_N, KEY_O, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 4
-+ { KEY_P, KEY_Q, KEY_R, KEY_S, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 5
-+ { KEY_T, KEY_U, KEY_V, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 6
-+ { KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 7
-+ { KEY_AE, KEY_OE, KEY_UE, KEY_SZ, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 8
-+ { KEY_sA, KEY_sB, KEY_sC, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 9
-+ { KEY_sD, KEY_sE, KEY_sF, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 10
-+ { KEY_sG, KEY_sH, KEY_sI, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 11
-+ { KEY_sJ, KEY_sK, KEY_sL, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 12
-+ { KEY_sM, KEY_sN, KEY_sO, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 13
-+ { KEY_sP, KEY_sQ, KEY_sR, KEY_sS, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 14
-+ { KEY_sT, KEY_sU, KEY_sV, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 15
-+ { KEY_sW, KEY_sX, KEY_sY, KEY_sZ, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 16
-+ { KEY_sAE, KEY_sOE, KEY_sUE, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 17
-+ { KEY_COLON, KEY_FSLASH,KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 18
-+ { KEY_SEMI, KEY_BSLASH,KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 19
-+ { KEY_COMMA, KEY_STAR, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 20
-+ { KEY_UNDERL,KEY_EQUAL, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 21
-+ { KEY_PLUS, KEY_MINUS, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 22
-+ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 24
-+ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 24
-+ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 25
-+ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 26
-+ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 27
-+ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 28
-+ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 29
-+ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 30
-+ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 31
-+};
---- /dev/null
-+++ linux-2.4.21/drivers/input/ramses_keyb.c
-@@ -0,0 +1,596 @@
-+/*
-+ * Keyboard driver using input layer
-+ *
-+ * (C) 2002,2003 by M&N Logistik-Lösungen Online GmbH
-+ * written by H.Schurig
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/input.h>
-+#include <linux/delay.h>
-+
-+#include <asm/keyboard.h>
-+#include <asm/irq.h>
-+#include <linux/keyboard.h>
-+
-+// Debug
-+//#define DEBUG
-+//#define DEBUG_DUMP_KEYSTATE
-+#ifdef DEBUG
-+# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
-+# define PRINTK(fmt, args...) printk(fmt, ## args)
-+#else
-+# define DPRINTK(fmt, args...)
-+# define PRINTK(fmt, args...)
-+#endif
-+
-+
-+/*
-+ * Timeouts
-+ */
-+#define SCANINTERVAL HZ/10
-+#define TRIGOFFINTERVAL HZ*2
-+#define CELLINTERVAL HZ+HZ/2
-+#define MAPINTERVAL 15*HZ
-+#define SUSPEND_COUNTER 40
-+#define SUSPEND_LED_COUNTER 8
-+#define SUSPEND_NOW 0xffff
-+#define KEYBD_MATRIX_SETTLING_TIME_US 100
-+
-+
-+/*
-+ * macros for matrix keyboard driver
-+ */
-+#define KEYBD_MATRIX_NUMBER_INPUTS 7
-+#define KEYBD_MATRIX_NUMBER_OUTPUTS 14
-+
-+#define KEYBD_MATRIX_SET_OUTPUTS(outputs) \
-+{\
-+ RAMSES_CPLD_KB_COL_LOW = outputs;\
-+ RAMSES_CPLD_KB_COL_HIGH = outputs >> 7;\
-+}
-+
-+#define KEYBD_MATRIX_GET_INPUTS(inputs) \
-+{\
-+ inputs = (RAMSES_CPLD_KB_ROW & 0x7f);\
-+}
-+
-+
-+// External functions (are they in some #include file?)
-+extern int input_setkeycode(unsigned int scancode, unsigned int keycode);
-+extern int input_getkeycode(unsigned int scancode);
-+extern int input_translate(unsigned char scancode, unsigned char *keycode,
-+ char raw_mode);
-+extern char input_unexpected_up(unsigned char keycode);
-+extern unsigned char input_sysrq_xlate[];
-+extern int pm_suggest_suspend(void);
-+
-+// Keyboard-Related definitions
-+#define KEYBD_MATRIX_INPUT_MASK ((1 << KEYBD_MATRIX_NUMBER_INPUTS)-1)
-+#define KEYBD_MATRIX_OUTPUT_MASK ((1 << KEYBD_MATRIX_NUMBER_OUTPUTS)-1)
-+
-+#include "ramses_scancodes.h"
-+#include "ramses_keymap.h"
-+#include "ramses_cellmap.h"
-+
-+
-+static char *kbd_name = "Keyboard";
-+struct input_dev ramses_kbd_dev;
-+static struct timer_list reenable_timer;
-+static struct timer_list trigoff_timer;
-+static struct tq_struct tq_suspend;
-+static __u16 keystate_cur[KEYBD_MATRIX_NUMBER_OUTPUTS];
-+static __u16 keystate_prev[KEYBD_MATRIX_NUMBER_OUTPUTS];
-+static __u16 keystate_keep[KEYBD_MATRIX_NUMBER_OUTPUTS]; // used for auto-repeat
-+static struct timer_list cell_timer;
-+static int curr_map = MAP_NORMAL;
-+static int cell_key = -1;
-+static int cell_sel = -1;
-+static struct pm_dev *pm_keyb;
-+static int suspend_counter = 0;
-+
-+
-+void ramses_key(int keycode)
-+{
-+ DPRINTK("keycode: %d 0x%x\n", keycode, keycode);
-+ if (KVAL(keycode)) {
-+ switch (KMOD(keycode)) {
-+ case KM_SHIFT:
-+ DPRINTK("shift\n");
-+ input_report_key(&ramses_kbd_dev, KEY_LEFTSHIFT, 1);
-+ break;
-+ case KM_CTRL:
-+ DPRINTK("ctrl\n");
-+ input_report_key(&ramses_kbd_dev, KEY_LEFTCTRL, 1);
-+ break;
-+ case KM_ALT:
-+ DPRINTK("alt\n");
-+ input_report_key(&ramses_kbd_dev, KEY_LEFTALT, 1);
-+ break;
-+ case KM_ALTGR:
-+ DPRINTK("altgr\n");
-+ input_report_key(&ramses_kbd_dev, KEY_RIGHTALT, 1);
-+ break;
-+ case KM_ALTCTRL:
-+ DPRINTK("alt+ctrl\n");
-+ input_report_key(&ramses_kbd_dev, KEY_LEFTALT, 1);
-+ input_report_key(&ramses_kbd_dev, KEY_LEFTCTRL, 1);
-+ break;
-+ }
-+
-+ DPRINTK("report: %d 0x%x\n", KVAL(keycode), KVAL(keycode));
-+ input_report_key(&ramses_kbd_dev, KVAL(keycode), 1);
-+ input_report_key(&ramses_kbd_dev, KVAL(keycode), 0);
-+
-+ switch (KMOD(keycode)) {
-+ case KM_SHIFT:
-+ input_report_key(&ramses_kbd_dev, KEY_LEFTSHIFT, 0);
-+ break;
-+ case KM_CTRL:
-+ input_report_key(&ramses_kbd_dev, KEY_LEFTCTRL, 0);
-+ break;
-+ case KM_ALT:
-+ input_report_key(&ramses_kbd_dev, KEY_LEFTALT, 0);
-+ break;
-+ case KM_ALTGR:
-+ input_report_key(&ramses_kbd_dev, KEY_RIGHTALT, 0);
-+ break;
-+ case KM_ALTCTRL:
-+ input_report_key(&ramses_kbd_dev, KEY_LEFTALT, 0);
-+ input_report_key(&ramses_kbd_dev, KEY_LEFTCTRL, 0);
-+ break;
-+ }
-+ }
-+}
-+
-+static void kbd_cell_timer(unsigned long keepmap)
-+{
-+ int keycode;
-+
-+ if (cell_sel != -1) {
-+ keycode = ramses_cellmap[cell_key][cell_sel];
-+ //DPRINTK("key: %d sel: %d keycode: %d 0x%x\n", cell_key, cell_sel, keycode, keycode);
-+ ramses_key(keycode);
-+ cell_sel = -1;
-+ }
-+
-+ if (!keepmap && curr_map!=MAP_NORMAL) {
-+ DPRINTK("normal map because of %ld\n", keepmap);
-+ curr_map = MAP_NORMAL;
-+ RAMSES_LED_BLUE_OFF();
-+ RAMSES_LED_ORANGE_OFF();
-+ }
-+}
-+
-+static void kbd_setleds(void)
-+{
-+ if (suspend_counter >= SUSPEND_LED_COUNTER) {
-+ if (suspend_counter & 4) {
-+ RAMSES_LED_ORANGE_OFF();
-+ RAMSES_LED_BLUE_ON();
-+ } else {
-+ RAMSES_LED_ORANGE_ON();
-+ RAMSES_LED_BLUE_OFF();
-+ }
-+ return;
-+ }
-+
-+ switch (curr_map) {
-+ case MAP_NORMAL:
-+ RAMSES_LED_BLUE_OFF();
-+ RAMSES_LED_ORANGE_OFF();
-+ return;
-+
-+ case MAP_BLUE:
-+ RAMSES_LED_BLUE_ON();
-+ RAMSES_LED_ORANGE_OFF();
-+ return;
-+
-+ case MAP_ORANGE:
-+ RAMSES_LED_BLUE_OFF();
-+ RAMSES_LED_ORANGE_ON();
-+ return;
-+
-+ case MAP_CAPS:
-+ RAMSES_LED_BLUE_ON();
-+ RAMSES_LED_ORANGE_ON();
-+ return;
-+ }
-+ DPRINTK("unknown map\n");
-+}
-+
-+
-+static void kbd_start_scanner(void)
-+{
-+ RAMSES_SCANNER_TRIG_OFF();
-+ RAMSES_SCANNER_WAKE_OFF();
-+ RAMSES_SCANNER_TRIG_ON();
-+ mod_timer(&trigoff_timer, jiffies + TRIGOFFINTERVAL);
-+}
-+
-+static void kbd_stop_scanner(unsigned long dummy)
-+{
-+ RAMSES_SCANNER_TRIG_OFF();
-+}
-+
-+static int kbd_dokeycode(unsigned char scancode, int down)
-+{
-+ int i,keycode;
-+
-+ //DPRINTK("calling with (%d,%x,%d)\n", scancode, scancode, down);
-+ if (scancode >= MAX_SCANCODES) {
-+ printk("%s: scancode too big for table\n", __FUNCTION__);
-+ return 0;
-+ }
-+
-+ keycode = ramses_keymap[scancode][curr_map];
-+
-+
-+ if (keycode==KEY_SCAN) {
-+ if ((ramses_flags & RAMSES_FLAGS_KEY_SCAN) == 0)
-+ return 0;
-+
-+ DPRINTK("scan btn\n");
-+ if (down) {
-+ if (ramses_flags & RAMSES_FLAGS_SCANNER_BEAM) {
-+ // just turn on laser beam
-+ RAMSES_SCANNER_WAKE_ON();
-+ } else {
-+ kbd_start_scanner();
-+ }
-+ } else {
-+ if (ramses_flags & RAMSES_FLAGS_SCANNER_BEAM) {
-+ kbd_start_scanner();
-+ } else {
-+ kbd_stop_scanner(0);
-+ }
-+ }
-+ return 0;
-+ }
-+
-+
-+ if (keycode==KEY_SUSP) {
-+ if ((ramses_flags & RAMSES_FLAGS_KEY_SUSPEND) == 0)
-+ return 0;
-+
-+ if (down) {
-+ suspend_counter++;
-+ if (suspend_counter >= SUSPEND_COUNTER) {
-+ suspend_counter = SUSPEND_NOW;
-+ }
-+ } else {
-+ if (suspend_counter == SUSPEND_NOW) {
-+ curr_map = MAP_NORMAL;
-+ schedule_task(&tq_suspend);
-+ }
-+ suspend_counter = 0;
-+ }
-+ return down;
-+ }
-+
-+
-+ if (keycode==KEY_OFF) {
-+ if (down || ((ramses_flags & RAMSES_FLAGS_KEY_OFF) == 0))
-+ return 0;
-+ curr_map = MAP_NORMAL;
-+ ramses_shut_off();
-+ return 0;
-+ }
-+
-+
-+ if (!down)
-+ return 0;
-+
-+
-+ DPRINTK("curr_map %d scancode %d keycode %d 0x%x typ %d\n", curr_map, scancode, keycode, keycode, KMOD(keycode));
-+
-+
-+ // Cell-Phone keyboard handling
-+ if (KMOD(keycode)==KM_CELL) {
-+ //DPRINTK("cell phone key %d\n", KVAL(keycode));
-+
-+ // did we press a different cell-phone key as last time?
-+ if (KVAL(keycode)!=cell_key)
-+ kbd_cell_timer(1);
-+
-+ cell_key = KVAL(keycode); // store current cell-phone key
-+ cell_sel++; // increase current sub-key
-+ if (ramses_cellmap[cell_key][cell_sel]==0) // if at end of sub-key list, back off
-+ cell_sel = 0;
-+ //DPRINTK("cell_key: %d cell_sel: %d\n", cell_key, cell_sel);
-+ // auto-emit via kbd_cell_timer
-+ mod_timer(&cell_timer, jiffies + CELLINTERVAL);
-+ return 0; // do not revert to keys_normal
-+ }
-+
-+
-+ // if we pressed any other key then a cell-phone key, we look if the
-+ // current half-pressed cell-phone key should be emitted
-+ kbd_cell_timer(1);
-+
-+
-+ switch(keycode) {
-+
-+ // Keymap handling
-+
-+ case KEY_NORM:
-+ DPRINTK("norm key map\n");
-+ curr_map = MAP_NORMAL;
-+ return 0;
-+
-+ case KEY_BLUE:
-+ //DPRINTK("blue key map\n");
-+ curr_map = MAP_BLUE;
-+ mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap
-+ return 0;
-+
-+ case KEY_ORNG:
-+ //DPRINTK("orange key map\n");
-+ curr_map = MAP_ORANGE;
-+ mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap
-+ return 0;
-+
-+ case KEY_CAPS:
-+ DPRINTK("caps key map\n");
-+ curr_map = MAP_CAPS;
-+ mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap
-+ return 0;
-+
-+ case KEY_BRIP:
-+ i = ramses_lcd_get_brightness()-6;
-+ ramses_lcd_set_brightness(i);
-+ mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap
-+ return 0;
-+
-+ case KEY_BRIM:
-+ i = ramses_lcd_get_brightness()+6;
-+ ramses_lcd_set_brightness(i);
-+ mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap
-+ return 0;
-+
-+ case KEY_CTRM:
-+ i = ramses_lcd_get_contrast()+3;
-+ ramses_lcd_set_contrast(i);
-+ mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap
-+ return 0;
-+
-+ case KEY_CTRP:
-+ i = ramses_lcd_get_contrast()-3;
-+ ramses_lcd_set_contrast(i);
-+ mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap
-+ return 0;
-+ }
-+
-+ // normal keys
-+
-+ ramses_key(keycode);
-+
-+ if (curr_map!=MAP_NORMAL)
-+ DPRINTK("back to normal map\n");
-+ curr_map = MAP_NORMAL;
-+ RAMSES_LED_BLUE_OFF();
-+ RAMSES_LED_ORANGE_OFF();
-+ return 0;
-+}
-+
-+
-+/**
-+ * @param rescan 0 if we look for pressed keys, 1 if we look for released keys
-+ *
-+ * This routine get's called from the ISR (then rescan is always 0) or from
-+ * the reenable_timer function (then rescan is 1).
-+ */
-+static void kbd_scan_keyboard(unsigned long rescan)
-+{
-+ int i,n;
-+ int cols;
-+ unsigned char code;
-+ __u16 keystate_xor[KEYBD_MATRIX_NUMBER_OUTPUTS];
-+
-+
-+ // Find out if a key (or more) was pressed down. It's possible that
-+ // because of spikes we got an interrupt, but when the IRQ service
-+ // routine fired there is currently no detectable key. If this is
-+ // true, then delay some times and re-try, but not too often.
-+
-+ cols = 0;
-+ for(n=0; n<10; n++) {
-+ for (i = 0; i < KEYBD_MATRIX_NUMBER_OUTPUTS; i++) {
-+ KEYBD_MATRIX_SET_OUTPUTS( 1 << i );
-+ udelay(KEYBD_MATRIX_SETTLING_TIME_US);
-+ KEYBD_MATRIX_GET_INPUTS(keystate_cur[i]);
-+ if (keystate_cur[i])
-+ cols++;
-+ }
-+ if (cols || rescan)
-+ break;
-+ udelay(KEYBD_MATRIX_SETTLING_TIME_US*50);
-+ }
-+
-+ // if rescan is true, we are in the process of turning on the IRQ.
-+ // Ignore any spurious IRQ. However, if we got an IRQ but could not
-+ // detect any key, we note this on the console, clear the keystate
-+ // completely and make sure the IRQ gets re-enabled via the timer
-+ // shortly.
-+
-+ if (!cols && !rescan) {
-+ printk("%s: spurious kbd int\n", __FUNCTION__);
-+ for (i = 0; i < KEYBD_MATRIX_NUMBER_OUTPUTS; i++) {
-+ keystate_cur[i] = 0;
-+ keystate_prev[i] = 0;
-+ }
-+ mod_timer(&reenable_timer, jiffies + SCANINTERVAL);
-+ return;
-+ }
-+
-+ pm_access(pm_keyb);
-+
-+ // Okay, all went well. We now keystate_cur[] may contain the rows
-+ // where we had keypresses, e.g.
-+ // 0 0 0 2 0 0 0 0 0 0 0 0 0 0
-+ // We would see this if DEBUG_DUMP_KEYSTATE is on:
-+
-+#ifdef DEBUG_DUMP_KEYSTATE
-+ cols = 0;
-+ for (i = 0; i < KEYBD_MATRIX_NUMBER_OUTPUTS; i++) {
-+ printk("%d-%d ",keystate_cur[i], keystate_keep[i]);
-+ }
-+ printk("\n");
-+#endif
-+
-+ cols = 0;
-+ for (i = 0; i < KEYBD_MATRIX_NUMBER_OUTPUTS; i++) {
-+
-+ // detect which key has changes doing an XOR of old state with new state
-+ keystate_xor[i] = keystate_prev[i] ^ keystate_cur[i];
-+ //printk("%d: prev %d cur %d xor %d keep %d\n", i, keystate_prev[i], keystate_cur[i], keystate_xor[i], keystate_keep[i]);
-+
-+ // some key changed, find out which one and do the scancode handling
-+ if (keystate_xor[i] || keystate_keep[i]) {
-+ for (n = 0; n < KEYBD_MATRIX_NUMBER_INPUTS; n++)
-+ {
-+ if ( (keystate_keep[i] & keystate_cur[i]) ||
-+ (keystate_xor[i] & (1 << n)) )
-+ {
-+ int res;
-+ code = n * KEYBD_MATRIX_NUMBER_OUTPUTS + i + 1;
-+ res = kbd_dokeycode(code, keystate_cur[i] & (1 << n) ? 1 : 0);
-+ kbd_setleds();
-+ if (res) {
-+ keystate_keep[i] = 1 << n;
-+ goto out;
-+ }
-+ }
-+ }
-+ }
-+out:
-+ keystate_prev[i] = keystate_cur[i];
-+ }
-+
-+
-+ // fire reenable time if we are in the ISR
-+ if (!rescan)
-+ mod_timer(&reenable_timer, jiffies + SCANINTERVAL);
-+}
-+
-+
-+
-+static void kbd_reenable_timer(unsigned long dummy)
-+{
-+ // re-scan the keyboard (to detect released keys)
-+ kbd_scan_keyboard(1);
-+
-+ // re-enable interrupts from the CPLD
-+ KEYBD_MATRIX_SET_OUTPUTS( KEYBD_MATRIX_OUTPUT_MASK );
-+}
-+
-+
-+
-+
-+
-+/**
-+ * Referenced by request_irq()
-+ */
-+static void kbd_interrupt(int irq, void *dummy, struct pt_regs *fp)
-+{
-+ kbd_scan_keyboard(0);
-+}
-+
-+static void ramseskbd_suspend(void *data)
-+{
-+ pm_suggest_suspend();
-+}
-+
-+
-+static int __init ramseskbd_init(void)
-+{
-+ int irq_gpio_pin;
-+
-+ // Activate the normal pc-keycodes for the input-layer-keyboard
-+ k_setkeycode = input_setkeycode;
-+ k_getkeycode = input_getkeycode;
-+ k_translate = input_translate;
-+ k_unexpected_up = input_unexpected_up;
-+#ifdef CONFIG_MAGIC_SYSRQ
-+ k_sysrq_key = 0x54;
-+ k_sysrq_xlate = input_sysrq_xlate;
-+#endif
-+
-+ // In linux-2.5.x we can do
-+ // init_input_dev(&ramses_kbd_dev);
-+ // but here we don't have this on linux-2.4, so we fill it with zeros:
-+ memset(&ramses_kbd_dev, 0, sizeof(ramses_kbd_dev));
-+ ramses_kbd_dev.name = kbd_name;
-+
-+ // which events we can produce (only keypresses):
-+ ramses_kbd_dev.evbit[0] = BIT(EV_KEY);
-+
-+ // which keypresses we can produce (all):
-+ memset(&ramses_kbd_dev.keybit, 0xff, sizeof(ramses_kbd_dev.keybit));
-+
-+ // We set the 14 output columns to 0. This stops the CPLD to
-+ // generate an IRQ before we finished our setup
-+ KEYBD_MATRIX_SET_OUTPUTS(0);
-+
-+ // Turn all LEDs off, meaning that we have the normal keymap active
-+ RAMSES_LED_BLUE_OFF();
-+ RAMSES_LED_ORANGE_OFF();
-+ // TODO: used leds.c?
-+
-+ // Now we make sure that the GPIO for our IRQ is programmed correctly
-+ irq_gpio_pin = IRQ_TO_GPIO_2_80(RAMSES_KEYBOARD_IRQ);
-+ GPDR(irq_gpio_pin) &= ~GPIO_bit(irq_gpio_pin);
-+ set_GPIO_IRQ_edge(irq_gpio_pin, RAMSES_KEYBOARD_IRQ_EDGE);
-+ request_irq(RAMSES_KEYBOARD_IRQ, kbd_interrupt, 0, kbd_name, NULL);
-+
-+ // Initialize timer to re-enable IRQs. That's our method of keyboard de-prelling
-+ init_timer(&reenable_timer);
-+ reenable_timer.function = kbd_reenable_timer;
-+
-+ init_timer(&trigoff_timer);
-+ trigoff_timer.function = kbd_stop_scanner;
-+
-+ // Initialize to escape the blue mode, so we emit the current cell-phone key
-+ init_timer(&cell_timer);
-+ cell_timer.function = kbd_cell_timer;
-+
-+ tq_suspend.routine = ramseskbd_suspend;
-+
-+ // Register with Power-Management
-+#ifdef PM_DEBUG
-+ pm_keyb = pm_register(PM_SYS_DEV, PM_SYS_KBC+1, NULL, "ramses_keyb");
-+#else
-+ pm_keyb = pm_register(PM_SYS_DEV, PM_SYS_KBC+1, NULL);
-+#endif
-+
-+ // Register our keyboard
-+ input_register_device(&ramses_kbd_dev);
-+
-+ // We set the 14 output columns to 1. This allows the CPLD to
-+ // generate an IRQ when one of the rows goes high
-+ KEYBD_MATRIX_SET_OUTPUTS(KEYBD_MATRIX_OUTPUT_MASK);
-+
-+ return 0;
-+}
-+
-+
-+static void __exit ramseskbd_exit(void)
-+{
-+ // make IRQs impossible, return the IRQ and unregister us
-+ KEYBD_MATRIX_SET_OUTPUTS(0);
-+ free_irq(RAMSES_KEYBOARD_IRQ, NULL);
-+ pm_unregister(pm_keyb);
-+ input_unregister_device(&ramses_kbd_dev);
-+}
-+
-+
-+module_init(ramseskbd_init);
-+module_exit(ramseskbd_exit);
-+
-+MODULE_AUTHOR("Holger Schurig <h.schurig@mn-logistik.de>");
-+MODULE_DESCRIPTION("Ramses keyboard driver");
-+MODULE_LICENSE("GPL");
-+EXPORT_SYMBOL(ramses_key);
-+EXPORT_SYMBOL(ramses_kbd_dev);
---- /dev/null
-+++ linux-2.4.21/drivers/input/ramses_keymap.h
-@@ -0,0 +1,68 @@
-+// Normal Map
-+static int ramses_keymap[][6] = {
-+/* Normal Blue Orange Caps Spare Spare */
-+/* 0 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 1 */ {KEY_SUSP, KEY_SUSP, KEY_SUSP, KEY_OFF, KEY_SUSP, KEY_SUSP },
-+/* 2 */ {KEY_UP, KEY_UP, KEY_PGUP, KEY_UP, KEY_noop, KEY_noop },
-+/* 3 */ {KEY_1, KEY_SPACE, KEY_BRIM, KEY_SPACE, KEY_noop, KEY_noop },
-+/* 4 */ {KEY_4, KEY_ghi , KEY_CTRM, KEY_GHI , KEY_noop, KEY_noop },
-+/* 5 */ {KEY_7, KEY_pqrs, KEY_cel7, KEY_PQRS, KEY_noop, KEY_noop },
-+/* 6 */ {KEY_DOT, KEY_uml, KEY_celP, KEY_UML, KEY_noop, KEY_noop },
-+/* 7 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 8 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 9 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 10 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 11 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 12 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 13 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 14 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 15 */ {KEY_ENTER, KEY_ENTER, KEY_ENTER, KEY_ENTER, KEY_ENTER, KEY_ENTER},
-+/* 16 */ {KEY_DOWN, KEY_DOWN, KEY_PGDN, KEY_DOWN, KEY_noop, KEY_noop },
-+/* 17 */ {KEY_2, KEY_abc , KEY_BRIP, KEY_ABC , KEY_noop, KEY_noop },
-+/* 18 */ {KEY_5, KEY_jkl , KEY_CTRP, KEY_JKL, KEY_noop, KEY_noop },
-+/* 19 */ {KEY_8, KEY_tuv , KEY_cel8, KEY_TUV, KEY_noop, KEY_noop },
-+
-+/* Normal Blue Orange Caps Spare Spare */
-+/* 20 */ {KEY_0, KEY_TAB, KEY_cel0, KEY_BTAB, KEY_noop, KEY_noop },
-+/* 21 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 22 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 23 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 24 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 25 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 26 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 27 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 28 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 29 */ {KEY_ESC, KEY_ESC, KEY_ESC, KEY_ESC, KEY_ESC, KEY_ESC },
-+/* 30 */ {KEY_RIGHT, KEY_RIGHT, KEY_END, KEY_C2, KEY_noop, KEY_noop },
-+/* 31 */ {KEY_3, KEY_def, KEY_FXIT, KEY_DEF, KEY_noop, KEY_noop },
-+/* 32 */ {KEY_6, KEY_mno , KEY_FRST, KEY_MNO, KEY_noop, KEY_noop },
-+/* 33 */ {KEY_9, KEY_wxyz, KEY_cel9, KEY_WXYZ, KEY_noop, KEY_noop },
-+/* 34 */ {KEY_BACKSPACE,KEY_ATSIGN,KEY_BAR, KEY_noop, KEY_noop, KEY_noop },
-+/* 35 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 36 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 37 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 38 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 39 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+
-+/* Normal Blue Orange Caps Spare Spare */
-+/* 40 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 41 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 42 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 43 */ {KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN },
-+/* 44 */ {KEY_LEFT, KEY_LEFT, KEY_HOME, KEY_C1, KEY_noop, KEY_noop },
-+/* 45 */ {KEY_OFF, KEY_OFF, KEY_OFF, KEY_OFF, KEY_OFF, KEY_OFF },
-+/* 46 */ {KEY_F1, KEY_F4, KEY_F7, KEY_F10, KEY_noop, KEY_noop },
-+/* 47 */ {KEY_F2, KEY_F5, KEY_F8, KEY_F11, KEY_noop, KEY_noop },
-+/* 48 */ {KEY_F3, KEY_F6, KEY_F9, KEY_F12, KEY_noop, KEY_noop },
-+/* 49 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 50 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 51 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 52 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 53 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 54 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 55 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 56 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
-+/* 57 */ {KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN },
-+/* 58 */ {KEY_BLUE, KEY_NORM, KEY_CAPS, KEY_NORM, KEY_NORM, KEY_NORM },
-+/* 59 */ {KEY_ORNG, KEY_CAPS, KEY_NORM, KEY_NORM, KEY_NORM, KEY_NORM },
-+};
---- /dev/null
-+++ linux-2.4.21/drivers/input/ramses_scancodes.h
-@@ -0,0 +1,134 @@
-+#ifndef _RAMSES_SCANCODES_H
-+#define _RAMSES_SCANCODES_H
-+
-+#define KMOD(a) (a & 0xff00)
-+#undef KVAL
-+#define KVAL(a) (a & 0x00ff)
-+
-+// which modifiers to send before/after
-+#define KM_SPECIAL 0x300
-+#define KM_CELL 0x400
-+#define KM_SHIFT 0x500
-+#define KM_ALT 0x600
-+#define KM_CTRL 0x700
-+#define KM_ALTGR 0x800
-+#define KM_ALTCTRL 0x900
-+
-+// or special keys
-+#define KEY_noop KM_SPECIAL + 0
-+#define KEY_OFF KM_SPECIAL + 1
-+#define KEY_SUSP KM_SPECIAL + 2
-+#define KEY_SCAN KM_SPECIAL + 3
-+#define KEY_CTRM KM_SPECIAL + 4
-+#define KEY_CTRP KM_SPECIAL + 5
-+#define KEY_BRIM KM_SPECIAL + 6
-+#define KEY_BRIP KM_SPECIAL + 7
-+
-+#define KEY_NORM KM_SPECIAL + 10
-+#define KEY_BLUE KM_SPECIAL + 11
-+#define KEY_ORNG KM_SPECIAL + 12
-+#define KEY_CAPS KM_SPECIAL + 13
-+
-+
-+// our cell-phone like keys
-+#define KEY_abc KM_CELL + 0
-+#define KEY_def KM_CELL + 1
-+#define KEY_ghi KM_CELL + 2
-+#define KEY_jkl KM_CELL + 3
-+#define KEY_mno KM_CELL + 4
-+#define KEY_pqrs KM_CELL + 5
-+#define KEY_tuv KM_CELL + 6
-+#define KEY_wxyz KM_CELL + 7
-+#define KEY_uml KM_CELL + 8
-+#define KEY_ABC KM_CELL + 9
-+#define KEY_DEF KM_CELL + 10
-+#define KEY_GHI KM_CELL + 11
-+#define KEY_JKL KM_CELL + 12
-+#define KEY_MNO KM_CELL + 13
-+#define KEY_PQRS KM_CELL + 14
-+#define KEY_TUV KM_CELL + 15
-+#define KEY_WXYZ KM_CELL + 16
-+#define KEY_UML KM_CELL + 17
-+#define KEY_cel7 KM_CELL + 18
-+#define KEY_cel8 KM_CELL + 19
-+#define KEY_cel9 KM_CELL + 20
-+#define KEY_celP KM_CELL + 21
-+#define KEY_cel0 KM_CELL + 22
-+
-+// Shift-Keys
-+#define KEY_sA KM_SHIFT + KEY_A
-+#define KEY_sB KM_SHIFT + KEY_B
-+#define KEY_sC KM_SHIFT + KEY_C
-+#define KEY_sD KM_SHIFT + KEY_D
-+#define KEY_sE KM_SHIFT + KEY_E
-+#define KEY_sF KM_SHIFT + KEY_F
-+#define KEY_sG KM_SHIFT + KEY_G
-+#define KEY_sH KM_SHIFT + KEY_H
-+#define KEY_sI KM_SHIFT + KEY_I
-+#define KEY_sJ KM_SHIFT + KEY_J
-+#define KEY_sK KM_SHIFT + KEY_K
-+#define KEY_sL KM_SHIFT + KEY_L
-+#define KEY_sM KM_SHIFT + KEY_M
-+#define KEY_sN KM_SHIFT + KEY_N
-+#define KEY_sO KM_SHIFT + KEY_O
-+#define KEY_sP KM_SHIFT + KEY_P
-+#define KEY_sQ KM_SHIFT + KEY_Q
-+#define KEY_sR KM_SHIFT + KEY_R
-+#define KEY_sS KM_SHIFT + KEY_S
-+#define KEY_sT KM_SHIFT + KEY_T
-+#define KEY_sU KM_SHIFT + KEY_U
-+#define KEY_sV KM_SHIFT + KEY_V
-+#define KEY_sW KM_SHIFT + KEY_W
-+#define KEY_sX KM_SHIFT + KEY_X
-+#define KEY_sY KM_SHIFT + KEY_Y
-+#define KEY_sZ KM_SHIFT + KEY_Z
-+
-+// Umlaute
-+#define KEY_sAE KM_SHIFT + 40
-+#define KEY_sOE KM_SHIFT + 39
-+#define KEY_sUE KM_SHIFT + 26
-+#define KEY_AE 40
-+#define KEY_OE 39
-+#define KEY_UE 26
-+#define KEY_SZ 12
-+
-+// AS400-Keys
-+#define KEY_FRST KM_ALT + KEY_R
-+#define KEY_FXIT KM_ALT + KEY_X
-+
-+// Console-Switch
-+#define KEY_C1 KM_ALTCTRL + KEY_F1
-+#define KEY_C2 KM_ALTCTRL + KEY_F2
-+
-+// additional keys from the german keyboard
-+#undef KEY_MINUS
-+#undef KEY_EQUAL
-+#undef KEY_Y
-+#undef KEY_Z
-+#define KEY_Y 44
-+#define KEY_Z 21
-+#define KEY_STAR 55
-+#define KEY_COLON KM_SHIFT + 52
-+#define KEY_UNDERL KM_SHIFT + 53
-+#define KEY_ATSIGN KM_ALTGR + 16
-+#define KEY_BAR KM_ALTGR + 86
-+#define KEY_EQUAL KM_SHIFT + 11
-+#define KEY_SEMI KM_SHIFT + 51
-+#define KEY_BSLASH KM_ALTGR + 12
-+#define KEY_FSLASH KM_SHIFT + KEY_7
-+#define KEY_MINUS 53
-+#define KEY_PLUS 27
-+#define KEY_GAENSE KM_SHIFT + 3
-+#define KEY_PARA KM_SHIFT + 4
-+#define KEY_HASH 43
-+#define KEY_PGUP KEY_PAGEUP
-+#define KEY_PGDN KEY_PAGEDOWN
-+#define KEY_BTAB KM_SHIFT + KEY_TAB
-+
-+#define MAP_NORMAL 0
-+#define MAP_BLUE 1
-+#define MAP_ORANGE 2
-+#define MAP_CAPS 3
-+#define MAX_SCANCODES 100
-+
-+#endif
---- /dev/null
-+++ linux-2.4.21/drivers/input/uinput.c
-@@ -0,0 +1,428 @@
-+/*
-+ * User level driver support for input subsystem
-+ *
-+ * Heavily based on evdev.c by Vojtech Pavlik
-+ *
-+ * This program is free software; 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: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
-+ *
-+ * Changes/Revisions:
-+ * 0.1 20/06/2002
-+ * - first public version
-+ */
-+
-+#include <linux/poll.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/input.h>
-+#include <linux/smp_lock.h>
-+#include <linux/fs.h>
-+#include <linux/miscdevice.h>
-+#include <linux/uinput.h>
-+
-+static int uinput_dev_open(struct input_dev *dev)
-+{
-+ return 0;
-+}
-+
-+static void uinput_dev_close(struct input_dev *dev)
-+{
-+}
-+
-+static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-+{
-+ struct uinput_device *udev;
-+
-+ udev = (struct uinput_device *)dev->private;
-+
-+ udev->buff[udev->head].type = type;
-+ udev->buff[udev->head].code = code;
-+ udev->buff[udev->head].value = value;
-+ do_gettimeofday(&udev->buff[udev->head].time);
-+ udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE;
-+
-+ wake_up_interruptible(&udev->waitq);
-+
-+ return 0;
-+}
-+
-+static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect)
-+{
-+ return 0;
-+}
-+
-+static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
-+{
-+ return 0;
-+}
-+
-+static int uinput_create_device(struct uinput_device *udev)
-+{
-+ if (!udev->dev->name) {
-+ printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
-+ return -EINVAL;
-+ }
-+
-+ udev->dev->open = uinput_dev_open;
-+ udev->dev->close = uinput_dev_close;
-+ udev->dev->event = uinput_dev_event;
-+ udev->dev->upload_effect = uinput_dev_upload_effect;
-+ udev->dev->erase_effect = uinput_dev_erase_effect;
-+ udev->dev->private = udev;
-+
-+ init_waitqueue_head(&(udev->waitq));
-+
-+ input_register_device(udev->dev);
-+
-+ set_bit(UIST_CREATED, &(udev->state));
-+
-+ return 0;
-+}
-+
-+static int uinput_destroy_device(struct uinput_device *udev)
-+{
-+ if (!test_bit(UIST_CREATED, &(udev->state))) {
-+ printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME);
-+ return -EINVAL;
-+ }
-+
-+ input_unregister_device(udev->dev);
-+
-+ clear_bit(UIST_CREATED, &(udev->state));
-+
-+ return 0;
-+}
-+
-+static int uinput_open(struct inode *inode, struct file *file)
-+{
-+ struct uinput_device *newdev;
-+ struct input_dev *newinput;
-+
-+ newdev = kmalloc(sizeof(struct uinput_device), GFP_KERNEL);
-+ if (!newdev)
-+ goto error;
-+ memset(newdev, 0, sizeof(struct uinput_device));
-+
-+ newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL);
-+ if (!newinput)
-+ goto cleanup;
-+ memset(newinput, 0, sizeof(struct input_dev));
-+
-+ newdev->dev = newinput;
-+
-+ file->private_data = newdev;
-+
-+ return 0;
-+cleanup:
-+ kfree(newdev);
-+error:
-+ return -ENOMEM;
-+}
-+
-+static int uinput_validate_absbits(struct input_dev *dev)
-+{
-+ unsigned int cnt;
-+ int retval = 0;
-+
-+ for (cnt = 0; cnt < ABS_MAX; cnt++) {
-+ if (!test_bit(cnt, dev->absbit))
-+ continue;
-+
-+ if (/*!dev->absmin[cnt] || !dev->absmax[cnt] || */
-+ (dev->absmax[cnt] <= dev->absmin[cnt])) {
-+ printk(KERN_DEBUG
-+ "%s: invalid abs[%02x] min:%d max:%d\n",
-+ UINPUT_NAME, cnt,
-+ dev->absmin[cnt], dev->absmax[cnt]);
-+ retval = -EINVAL;
-+ break;
-+ }
-+
-+ if ((dev->absflat[cnt] < dev->absmin[cnt]) ||
-+ (dev->absflat[cnt] > dev->absmax[cnt])) {
-+ printk(KERN_DEBUG
-+ "%s: absflat[%02x] out of range: %d "
-+ "(min:%d/max:%d)\n",
-+ UINPUT_NAME, cnt, dev->absflat[cnt],
-+ dev->absmin[cnt], dev->absmax[cnt]);
-+ retval = -EINVAL;
-+ break;
-+ }
-+ }
-+ return retval;
-+}
-+
-+static int uinput_alloc_device(struct file *file, const char *buffer, size_t count)
-+{
-+ struct uinput_user_dev *user_dev;
-+ struct input_dev *dev;
-+ struct uinput_device *udev;
-+ int size,
-+ retval;
-+
-+ retval = count;
-+
-+ udev = (struct uinput_device *)file->private_data;
-+ dev = udev->dev;
-+
-+ user_dev = kmalloc(sizeof(*user_dev), GFP_KERNEL);
-+ if (!user_dev) {
-+ retval = -ENOMEM;
-+ goto exit;
-+ }
-+
-+ if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) {
-+ retval = -EFAULT;
-+ goto exit;
-+ }
-+
-+ if (NULL != dev->name)
-+ kfree(dev->name);
-+
-+ size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1;
-+ dev->name = kmalloc(size, GFP_KERNEL);
-+ if (!dev->name) {
-+ retval = -ENOMEM;
-+ goto exit;
-+ }
-+
-+ strncpy(dev->name, user_dev->name, size);
-+ dev->idbus = user_dev->idbus;
-+ dev->idvendor = user_dev->idvendor;
-+ dev->idproduct = user_dev->idproduct;
-+ dev->idversion = user_dev->idversion;
-+ dev->ff_effects_max = user_dev->ff_effects_max;
-+
-+ size = sizeof(int) * (ABS_MAX + 1);
-+ memcpy(dev->absmax, user_dev->absmax, size);
-+ memcpy(dev->absmin, user_dev->absmin, size);
-+ memcpy(dev->absfuzz, user_dev->absfuzz, size);
-+ memcpy(dev->absflat, user_dev->absflat, size);
-+
-+ /* check if absmin/absmax/absfuzz/absflat are filled as
-+ * told in Documentation/input/input-programming.txt */
-+ if (test_bit(EV_ABS, dev->evbit)) {
-+ retval = uinput_validate_absbits(dev);
-+ if (retval < 0)
-+ kfree(dev->name);
-+ }
-+
-+exit:
-+ kfree(user_dev);
-+ return retval;
-+}
-+
-+static ssize_t uinput_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
-+{
-+ struct uinput_device *udev = file->private_data;
-+
-+ if (test_bit(UIST_CREATED, &(udev->state))) {
-+ struct input_event ev;
-+
-+ if (copy_from_user(&ev, buffer, sizeof(struct input_event)))
-+ return -EFAULT;
-+ input_event(udev->dev, ev.type, ev.code, ev.value);
-+ }
-+ else
-+ count = uinput_alloc_device(file, buffer, count);
-+
-+ return count;
-+}
-+
-+static ssize_t uinput_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
-+{
-+ struct uinput_device *udev = file->private_data;
-+ int retval = 0;
-+
-+ if (!test_bit(UIST_CREATED, &(udev->state)))
-+ return -ENODEV;
-+
-+ if ((udev->head == udev->tail) && (file->f_flags & O_NONBLOCK))
-+ return -EAGAIN;
-+
-+ retval = wait_event_interruptible(udev->waitq,
-+ (udev->head != udev->tail) ||
-+ !test_bit(UIST_CREATED, &(udev->state)));
-+
-+ if (retval)
-+ return retval;
-+
-+ if (!test_bit(UIST_CREATED, &(udev->state)))
-+ return -ENODEV;
-+
-+ while ((udev->head != udev->tail) &&
-+ (retval + sizeof(struct input_event) <= count)) {
-+ if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]),
-+ sizeof(struct input_event))) return -EFAULT;
-+ udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE;
-+ retval += sizeof(struct input_event);
-+ }
-+
-+ return retval;
-+}
-+
-+static unsigned int uinput_poll(struct file *file, poll_table *wait)
-+{
-+ struct uinput_device *udev = file->private_data;
-+
-+ poll_wait(file, &udev->waitq, wait);
-+
-+ if (udev->head != udev->tail)
-+ return POLLIN | POLLRDNORM;
-+
-+ return 0;
-+}
-+
-+static int uinput_burn_device(struct uinput_device *udev)
-+{
-+ if (test_bit(UIST_CREATED, &(udev->state)))
-+ uinput_destroy_device(udev);
-+
-+ kfree(udev->dev);
-+ kfree(udev);
-+
-+ return 0;
-+}
-+
-+static int uinput_close(struct inode *inode, struct file *file)
-+{
-+ return uinput_burn_device((struct uinput_device *)file->private_data);
-+}
-+
-+static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+ int retval = 0;
-+ struct uinput_device *udev;
-+
-+ udev = (struct uinput_device *)file->private_data;
-+
-+ /* device attributes can not be changed after the device is created */
-+ if (cmd >= UI_SET_EVBIT && test_bit(UIST_CREATED, &(udev->state)))
-+ return -EINVAL;
-+
-+ switch (cmd) {
-+ case UI_DEV_CREATE:
-+ retval = uinput_create_device(udev);
-+ break;
-+
-+ case UI_DEV_DESTROY:
-+ retval = uinput_destroy_device(udev);
-+ break;
-+
-+ case UI_SET_EVBIT:
-+ if (arg > EV_MAX) {
-+ retval = -EINVAL;
-+ break;
-+ }
-+ set_bit(arg, udev->dev->evbit);
-+ break;
-+
-+ case UI_SET_KEYBIT:
-+ if (arg > KEY_MAX) {
-+ retval = -EINVAL;
-+ break;
-+ }
-+ set_bit(arg, udev->dev->keybit);
-+ break;
-+
-+ case UI_SET_RELBIT:
-+ if (arg > REL_MAX) {
-+ retval = -EINVAL;
-+ break;
-+ }
-+ set_bit(arg, udev->dev->relbit);
-+ break;
-+
-+ case UI_SET_ABSBIT:
-+ if (arg > ABS_MAX) {
-+ retval = -EINVAL;
-+ break;
-+ }
-+ set_bit(arg, udev->dev->absbit);
-+ break;
-+
-+ case UI_SET_MSCBIT:
-+ if (arg > MSC_MAX) {
-+ retval = -EINVAL;
-+ break;
-+ }
-+ set_bit(arg, udev->dev->mscbit);
-+ break;
-+
-+ case UI_SET_LEDBIT:
-+ if (arg > LED_MAX) {
-+ retval = -EINVAL;
-+ break;
-+ }
-+ set_bit(arg, udev->dev->ledbit);
-+ break;
-+
-+ case UI_SET_SNDBIT:
-+ if (arg > SND_MAX) {
-+ retval = -EINVAL;
-+ break;
-+ }
-+ set_bit(arg, udev->dev->sndbit);
-+ break;
-+
-+ case UI_SET_FFBIT:
-+ if (arg > FF_MAX) {
-+ retval = -EINVAL;
-+ break;
-+ }
-+ set_bit(arg, udev->dev->ffbit);
-+ break;
-+
-+ default:
-+ retval = -EFAULT;
-+ }
-+ return retval;
-+}
-+
-+struct file_operations uinput_fops = {
-+ owner: THIS_MODULE,
-+ open: uinput_open,
-+ release: uinput_close,
-+ read: uinput_read,
-+ write: uinput_write,
-+ poll: uinput_poll,
-+ ioctl: uinput_ioctl,
-+};
-+
-+static struct miscdevice uinput_misc = {
-+ fops: &uinput_fops,
-+ minor: UINPUT_MINOR,
-+ name: UINPUT_NAME,
-+};
-+
-+static int __init uinput_init(void)
-+{
-+ return misc_register(&uinput_misc);
-+}
-+
-+static void __exit uinput_exit(void)
-+{
-+ misc_deregister(&uinput_misc);
-+}
-+
-+MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
-+MODULE_DESCRIPTION("User level driver support for input subsystem");
-+MODULE_LICENSE("GPL");
-+
-+module_init(uinput_init);
-+module_exit(uinput_exit);
-+
---- /dev/null
-+++ linux-2.4.21/drivers/input/wedge.c
-@@ -0,0 +1,241 @@
-+/*
-+ * Virtual keyboard wedge using input layer
-+ *
-+ * (C) 2002,2003 by M&N Logistik-Lösungen Online GmbH
-+ * written by H.Schurig
-+ *
-+ * Creates a misc char device /dev/misc/wedge. Any output to this
-+ * device will be translated (via a german keyboard map) into scancodes
-+ * and re-submitted into the keyboard channel. Any console, X-Windows
-+ * or Qt/Embedded application will be able to receive this info.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/miscdevice.h>
-+#include <linux/input.h>
-+
-+#include <linux/types.h>
-+#include <linux/keyboard.h>
-+#include <linux/kd.h>
-+
-+#include <asm/uaccess.h>
-+
-+
-+// Debug
-+//#define DEBUG 1
-+#ifdef DEBUG
-+# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
-+# define PRINTK(fmt, args...) printk(fmt, ## args)
-+#else
-+# define DPRINTK(fmt, args...)
-+# define PRINTK(fmt, args...)
-+#endif
-+
-+
-+// Defines
-+#define KBD_STUFF_MAX_BYTES 512
-+
-+// Für den IOCTL
-+#define WEDGE_RAWKEY_DOWN _IOW('w', 0x72, unsigned long)
-+#define WEDGE_RAWKEY_UP _IOW('w', 0x73, unsigned long)
-+#define WEDGE_TS_ABS_X _IOW('w', 0x74, unsigned long)
-+#define WEDGE_TS_ABS_Y _IOW('w', 0x75, unsigned long)
-+#define WEDGE_TS_ABS_PRESSURE _IOW('w', 0x76, unsigned long)
-+
-+// Externs
-+#define MAX_NR_KEYMAPS 256
-+extern void ramses_key(int keycode);
-+extern unsigned short *key_maps[MAX_NR_KEYMAPS];
-+extern struct input_dev ramses_kbd_dev;
-+extern void ucb1x00_ts_evt_add(void *, u16 pressure, u16 x, u16 y);
-+
-+// for special keys
-+struct wedge_lookup_t {
-+ u_short c;
-+ u_short keysym;
-+};
-+
-+struct wedge_lookup_t wedge_lookup[] = {
-+ { 0x0a, 0x001c, },
-+ { 0x2f, 0x0508, },
-+};
-+
-+
-+
-+
-+static void *outbuf;
-+
-+static int wedge_open(struct inode *inode, struct file *filp)
-+{
-+ int ret;
-+
-+ ret = -ENXIO;
-+ outbuf = kmalloc(KBD_STUFF_MAX_BYTES, GFP_KERNEL);
-+ if (!outbuf)
-+ goto out;
-+
-+ ret = 0;
-+
-+out:
-+ if (ret) {
-+ kfree(outbuf);
-+ }
-+ return ret;
-+}
-+
-+
-+static int wedge_close(struct inode *inode, struct file *filp)
-+{
-+ kfree(outbuf);
-+ return 0;
-+}
-+
-+
-+static int wedge_search_map(u_short map[], int c)
-+{
-+ int i;
-+
-+ for (i=0; i<NR_KEYS; i++) {
-+ if (map[i] == (c | 0xf000))
-+ return i;
-+ if (map[i] == (c | 0xfb00))
-+ return i;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+static void wedge_handle_char(int c)
-+{
-+ int i;
-+ unsigned int maps;
-+ u_short *map;
-+
-+ DPRINTK("wedge_handle_char(0x%0x)\n", c);
-+
-+ for (i=0; i < sizeof(wedge_lookup)/sizeof(wedge_lookup[0]); i++) {
-+ if (wedge_lookup[i].c == c) {
-+ ramses_key(wedge_lookup[i].keysym);
-+ return;
-+ }
-+ }
-+
-+
-+ i = 0;
-+ for (maps=0; maps<MAX_NR_KEYMAPS; maps++) {
-+ map = key_maps[maps];
-+ if (!map)
-+ continue;
-+ if ((i = wedge_search_map(map, c))) {
-+ switch(maps) {
-+ case 0:
-+ break;
-+ case 1:
-+ i |= 0x500; // KT_SHIFT from ramses_scancodes.h
-+ break;
-+ case 2:
-+ i |= 0x800; // KT_ALTGR from ramses_scancodes.h
-+ break;
-+ case 4:
-+ i |= 0x700; // KT_CTRL from ramses_scancodes.h
-+ break;
-+ default:
-+ DPRINTK("unknown map for char %d %d\n", c, maps);
-+ }
-+ DPRINTK("ramses_key(0x%x)\n", i);
-+ ramses_key(i);
-+ return;
-+ }
-+ }
-+
-+ DPRINTK("entry for char %02x missing\n", c);
-+}
-+
-+
-+
-+static ssize_t wedge_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
-+{
-+ const char *p = buf;
-+ char c;
-+
-+ //DPRINTK("count=%d\n", count);
-+ while (count) {
-+ if (copy_from_user(&c, p, sizeof(c)))
-+ return -EFAULT;
-+
-+ p++;
-+ count--;
-+
-+ wedge_handle_char( (int)c & 0xff);
-+
-+ }
-+ return p - buf;
-+}
-+
-+
-+int wedge_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+ static u16 x;
-+ static u16 y;
-+ static u16 p;
-+
-+ switch (cmd) {
-+ case WEDGE_RAWKEY_DOWN:
-+ DPRINTK("send down raw key\n");
-+ input_report_key(&ramses_kbd_dev, arg, 1);
-+ return 0;
-+ case WEDGE_RAWKEY_UP:
-+ DPRINTK("send up raw key\n");
-+ input_report_key(&ramses_kbd_dev, arg, 0);
-+ return 0;
-+ case WEDGE_TS_ABS_X:
-+ x = arg;
-+ return 0;
-+ case WEDGE_TS_ABS_Y:
-+ y = arg;
-+ return 0;
-+ case WEDGE_TS_ABS_PRESSURE:
-+ p = arg;
-+ ucb1x00_ts_evt_add(NULL, arg, y, x);
-+ return 0;
-+ }
-+ return -EINVAL;
-+}
-+
-+
-+static struct file_operations wedge_fops = {
-+ owner: THIS_MODULE,
-+ write: wedge_write,
-+ open: wedge_open,
-+ release: wedge_close,
-+ ioctl: wedge_ioctl,
-+};
-+
-+
-+static struct miscdevice wedge_miscdev = {
-+ minor: MISC_DYNAMIC_MINOR,
-+ name: "wedge",
-+ fops: &wedge_fops,
-+};
-+
-+static int __init wedge_init(void)
-+{
-+ int ret;
-+ ret = misc_register(&wedge_miscdev);
-+ DPRINTK("major,minor is 10,%d\n", wedge_miscdev.minor);
-+ return ret;
-+}
-+
-+static void __exit wedge_exit(void)
-+{
-+ misc_deregister(&wedge_miscdev);
-+}
-+
-+module_init(wedge_init);
-+module_exit(wedge_exit);
-+
-+MODULE_DESCRIPTION("virtual keyboard wedge");
-+MODULE_LICENSE("GPL");
---- linux-2.4.21/drivers/isdn/avmb1/capidrv.c~bluetooth
-+++ linux-2.4.21/drivers/isdn/avmb1/capidrv.c
-@@ -523,13 +523,25 @@
-
- static void send_message(capidrv_contr * card, _cmsg * cmsg)
- {
-- struct sk_buff *skb;
-- size_t len;
-+ struct sk_buff *skb;
-+ size_t len;
-+ u16 err;
-+
- capi_cmsg2message(cmsg, cmsg->buf);
- len = CAPIMSG_LEN(cmsg->buf);
- skb = alloc_skb(len, GFP_ATOMIC);
-+ if(!skb) {
-+ printk(KERN_ERR "no skb len(%d) memory\n", len);
-+ return;
-+ }
- memcpy(skb_put(skb, len), cmsg->buf, len);
-- (*capifuncs->capi_put_message) (global.appid, skb);
-+ err = (*capifuncs->capi_put_message) (global.appid, skb);
-+ if (err) {
-+ printk(KERN_WARNING "%s: capi_put_message error: %04x\n",
-+ __FUNCTION__, err);
-+ kfree_skb(skb);
-+ return;
-+ }
- global.nsentctlpkt++;
- }
-
-@@ -2188,10 +2200,10 @@
- free_ncci(card, card->bchans[card->nbchan-1].nccip);
- if (card->bchans[card->nbchan-1].plcip)
- free_plci(card, card->bchans[card->nbchan-1].plcip);
-- if (card->plci_list)
-- printk(KERN_ERR "capidrv: bug in free_plci()\n");
- card->nbchan--;
- }
-+ if (card->plci_list)
-+ printk(KERN_ERR "capidrv: bug in free_plci()\n");
- kfree(card->bchans);
- card->bchans = 0;
-
---- linux-2.4.21/drivers/isdn/avmb1/kcapi.c~bluetooth
-+++ linux-2.4.21/drivers/isdn/avmb1/kcapi.c
-@@ -546,7 +546,13 @@
- static void notify_up(__u32 contr)
- {
- struct capi_interface_user *p;
-+ __u16 appl;
-
-+ for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
-+ if (!VALID_APPLID(appl)) continue;
-+ if (APPL(appl)->releasing) continue;
-+ CARD(contr)->driver->register_appl(CARD(contr), appl, &APPL(appl)->rparam);
-+ }
- printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
- spin_lock(&capi_users_lock);
- for (p = capi_users; p; p = p->next) {
-@@ -714,12 +720,16 @@
- nextpp = &(*pp)->next;
- }
- }
-- APPL(appl)->releasing--;
-- if (APPL(appl)->releasing <= 0) {
-- APPL(appl)->signal = 0;
-- APPL_MARK_FREE(appl);
-- printk(KERN_INFO "kcapi: appl %d down\n", appl);
-- }
-+ if (APPL(appl)->releasing) { /* only release if the application was marked for release */
-+ printk(KERN_DEBUG "kcapi: appl %d releasing(%d)\n", appl, APPL(appl)->releasing);
-+ APPL(appl)->releasing--;
-+ if (APPL(appl)->releasing <= 0) {
-+ APPL(appl)->signal = 0;
-+ APPL_MARK_FREE(appl);
-+ printk(KERN_INFO "kcapi: appl %d down\n", appl);
-+ }
-+ } else
-+ printk(KERN_WARNING "kcapi: appl %d card%d released without request\n", appl, card->cnr);
- }
- /*
- * ncci management
-@@ -872,16 +882,7 @@
-
- static void controllercb_ready(struct capi_ctr * card)
- {
-- __u16 appl;
--
- card->cardstate = CARD_RUNNING;
--
-- for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
-- if (!VALID_APPLID(appl)) continue;
-- if (APPL(appl)->releasing) continue;
-- card->driver->register_appl(card, appl, &APPL(appl)->rparam);
-- }
--
- printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n",
- CARDNR(card), card->name);
-
---- linux-2.4.21/drivers/misc/Makefile~wedge
-+++ linux-2.4.21/drivers/misc/Makefile
-@@ -12,7 +12,7 @@
- O_TARGET := misc.o
-
- export-objs := mcp-core.o mcp-sa1100.o mcp-pxa.o \
-- ucb1x00-core.o
-+ ucb1x00-core.o ucb1x00-ts.o
-
- obj-$(CONFIG_MCP_SA1100) += mcp-core.o mcp-sa1100.o
- obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o
---- linux-2.4.21/drivers/misc/mcp-pxa.c~ucb1x00
-+++ linux-2.4.21/drivers/misc/mcp-pxa.c
-@@ -31,6 +31,11 @@
- return (struct mcp *)codec;
- }
-
-+void mcp_put(void)
-+{
-+ pxa_ac97_put();
-+}
-+
- void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val)
- {
- struct ac97_codec *codec = (struct ac97_codec *)mcp;
-@@ -55,3 +60,7 @@
- void mcp_disable(struct mcp *mcp)
- {
- }
-+
-+MODULE_AUTHOR("Jeff Sutherland <jeffs@accelent.com>");
-+MODULE_DESCRIPTION("PXA mcp low level support");
-+MODULE_LICENSE("GPL");
---- linux-2.4.21/drivers/misc/mcp.h~ucb1x00
-+++ linux-2.4.21/drivers/misc/mcp.h
-@@ -43,6 +43,7 @@
-
- /* noddy implementation alert! */
- struct mcp *mcp_get(void);
-+void mcp_put(void);
- int mcp_register(struct mcp *);
-
- #define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate)
---- linux-2.4.21/drivers/misc/ucb1x00-core.c~pm
-+++ linux-2.4.21/drivers/misc/ucb1x00-core.c
-@@ -25,6 +25,7 @@
- #include <linux/pm.h>
- #include <linux/tqueue.h>
- #include <linux/config.h>
-+#include <linux/delay.h>
-
- #include <asm/irq.h>
- #include <asm/mach-types.h>
-@@ -181,8 +182,9 @@
- if (val & UCB_ADC_DAT_VAL)
- break;
- /* yield to other processes */
-- set_current_state(TASK_INTERRUPTIBLE);
-- schedule_timeout(1);
-+ //HS set_current_state(TASK_INTERRUPTIBLE);
-+ //HS schedule_timeout(1);
-+ udelay(200);
- }
-
- return UCB_ADC_DAT(val);
-@@ -209,7 +211,8 @@
- struct ucb1x00 *ucb = (struct ucb1x00 *)dev->data;
- unsigned int isr;
-
-- if (rqst == PM_RESUME) {
-+ switch (rqst) {
-+ case PM_RESUME:
- ucb1x00_enable(ucb);
- isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS);
- ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr);
-@@ -521,7 +524,9 @@
- */
- static int __init ucb1x00_configure(struct ucb1x00 *ucb)
- {
-+#ifndef CONFIG_ARCH_RAMSES
- unsigned int irq_gpio_pin = 0;
-+#endif
- int irq, default_irq = NO_IRQ;
-
- #ifdef CONFIG_ARCH_SA1100
-@@ -611,12 +616,14 @@
- /*
- * Eventually, this will disappear.
- */
-+#ifndef CONFIG_ARCH_RAMSES
- if (irq_gpio_pin)
- #ifdef CONFIG_ARCH_PXA_IDP
- set_GPIO_IRQ_edge(irq_gpio_pin, GPIO_FALLING_EDGE);
- #else
- set_GPIO_IRQ_edge(irq_gpio_pin, GPIO_RISING_EDGE);
- #endif
-+#endif
- irq = ucb1x00_detect_irq(ucb);
- if (irq != NO_IRQ) {
- if (default_irq != NO_IRQ && irq != default_irq)
---- linux-2.4.21/drivers/misc/ucb1x00-ts.c~ramses-ucb1x00-dejitter
-+++ linux-2.4.21/drivers/misc/ucb1x00-ts.c
-@@ -29,6 +29,7 @@
-
- #include <asm/dma.h>
- #include <asm/semaphore.h>
-+#include <asm/hardware.h>
-
- #include "ucb1x00.h"
-
-@@ -97,7 +98,7 @@
- };
-
- static struct ucb1x00_ts ucbts;
--static int adcsync = UCB_NOSYNC;
-+static int adcsync = UCB_SYNC;
-
- static int ucb1x00_ts_startup(struct ucb1x00_ts *ts);
- static void ucb1x00_ts_shutdown(struct ucb1x00_ts *ts);
-@@ -116,8 +117,14 @@
- next_head = (ts->evt_head + 1) & (NR_EVENTS - 1);
- if (next_head != ts->evt_tail) {
- ts->events[ts->evt_head].pressure = pressure;
-+#if 0
- ts->events[ts->evt_head].x = x;
- ts->events[ts->evt_head].y = y;
-+#else
-+ // rotate by -90
-+ ts->events[ts->evt_head].x = y;
-+ ts->events[ts->evt_head].y = x;
-+#endif
- do_gettimeofday(&ts->events[ts->evt_head].stamp);
- ts->evt_head = next_head;
-
-@@ -256,11 +263,11 @@
-
- #define ucb1x00_ts_evt_clear(ts) do { } while (0)
-
--static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y)
-+void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y)
- {
-- input_report_abs(&ts->idev, ABS_X, x);
-- input_report_abs(&ts->idev, ABS_Y, y);
-- input_report_abs(&ts->idev, ABS_PRESSURE, pressure);
-+ input_report_abs(&ucbts.idev, ABS_X, y);
-+ input_report_abs(&ucbts.idev, ABS_Y, x);
-+ input_report_abs(&ucbts.idev, ABS_PRESSURE, pressure);
- }
-
- static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
-@@ -335,7 +342,7 @@
- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-
-- return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
-+ return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSMY, ts->adcsync);
- }
-
- /*
-@@ -346,19 +353,15 @@
- */
- static inline unsigned int ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts)
- {
-- ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-- UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
-- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-- ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-- UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
-- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-+ unsigned int res;
- ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
- UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
- UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
-
-- udelay(55);
-+ udelay(600);
-
-- return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
-+ res = ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSMY, ts->adcsync);
-+ return res;
- }
-
- /*
-@@ -369,19 +372,15 @@
- */
- static inline unsigned int ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts)
- {
-+ unsigned int res;
- ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
-- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-- ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
-- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-- ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
-+ UCB_TS_CR_TSPY_GND | UCB_TS_CR_TSMY_POW |
- UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
-
-- udelay(55);
-+ udelay(300);
-
-- return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync);
-+ res = ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync);
-+ return res;
- }
-
- /*
-@@ -430,8 +429,9 @@
- * We could run as a real-time thread. However, thus far
- * this doesn't seem to be necessary.
- */
--// tsk->policy = SCHED_FIFO;
--// tsk->rt_priority = 1;
-+//HS
-+ tsk->policy = SCHED_FIFO;
-+ tsk->rt_priority = 1;
-
- /* only want to receive SIGKILL */
- spin_lock_irq(&tsk->sigmask_lock);
-@@ -451,8 +451,8 @@
- ucb1x00_adc_enable(ts->ucb);
-
- x = ucb1x00_ts_read_xpos(ts);
-- y = ucb1x00_ts_read_ypos(ts);
- p = ucb1x00_ts_read_pressure(ts);
-+ y = ucb1x00_ts_read_ypos(ts);
-
- /*
- * Switch back to interrupt mode.
-@@ -461,7 +461,7 @@
- ucb1x00_adc_disable(ts->ucb);
-
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-- schedule_timeout(HZ / 100);
-+ schedule_timeout(HZ / 200);
- if (signal_pending(tsk))
- break;
-
-@@ -504,7 +504,7 @@
- }
-
- set_task_state(tsk, TASK_INTERRUPTIBLE);
-- schedule_timeout(HZ / 100);
-+ schedule_timeout(HZ / 200);
- }
-
- if (signal_pending(tsk))
-@@ -655,8 +655,8 @@
- char *p;
-
- while ((p = strsep(&str, ",")) != NULL) {
-- if (strcmp(p, "sync") == 0)
-- adcsync = UCB_SYNC;
-+ if (strcmp(p, "nosync") == 0)
-+ adcsync = UCB_NOSYNC;
- }
-
- return 1;
-@@ -674,6 +674,7 @@
- module_init(ucb1x00_ts_init);
- module_exit(ucb1x00_ts_exit);
-
-+EXPORT_SYMBOL(ucb1x00_ts_evt_add);
- MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
- MODULE_DESCRIPTION("UCB1x00 touchscreen driver");
- MODULE_LICENSE("GPL");
---- linux-2.4.21/drivers/mtd/Config.in~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/Config.in
-@@ -1,5 +1,5 @@
-
--# $Id: Config.in,v 1.74 2002/04/23 13:52:14 mag Exp $
-+# $Id: Config.in,v 1.78 2004/08/09 18:46:03 dmarlin Exp $
-
- mainmenu_option next_comment
- comment 'Memory Technology Devices (MTD)'
-@@ -11,10 +11,16 @@
- if [ "$CONFIG_MTD_DEBUG" = "y" ]; then
- int ' Debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_MTD_DEBUG_VERBOSE 0
- fi
-- dep_tristate ' MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD
-+ bool ' MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD
- dep_tristate ' MTD concatenating support' CONFIG_MTD_CONCAT $CONFIG_MTD
- dep_tristate ' RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS
-- dep_tristate ' Command line partition table parsing' CONFIG_MTD_CMDLINE_PARTS $CONFIG_MTD_PARTITIONS
-+ if [ "$CONFIG_MTD_REDBOOT_PARTS" = "y" -o "$CONFIG_MTD_REDBOOT_PARTS" = "m" ]; then
-+ bool ' Include unallocated flash space' CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
-+ bool ' Force read-only for RedBoot system images' CONFIG_MTD_REDBOOT_PARTS_READONLY
-+ fi
-+ if [ "$CONFIG_MTD_PARTITIONS" = "y" ]; then
-+ bool ' Command line partition table parsing' CONFIG_MTD_CMDLINE_PARTS
-+ fi
- if [ "$CONFIG_ARM" = "y" ]; then
- dep_tristate ' ARM Firmware Suite partition parsing' CONFIG_MTD_AFS_PARTS $CONFIG_MTD_PARTITIONS
- fi
-@@ -30,6 +36,7 @@
- if [ "$CONFIG_NFTL" = "y" -o "$CONFIG_NFTL" = "m" ]; then
- bool ' Write support for NFTL (BETA)' CONFIG_NFTL_RW
- fi
-+ dep_tristate ' INFTL (Inverse NAND Flash Translation Layer) support' CONFIG_INFTL $CONFIG_MTD
-
- source drivers/mtd/chips/Config.in
-
---- linux-2.4.21/drivers/mtd/Makefile~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/Makefile
-@@ -1,66 +1,54 @@
- #
--# Makefile for the memory technology device drivers.
--#
--# Note! Dependencies are done automagically by 'make dep', which also
--# removes any old dependencies. DON'T put your own dependencies here
--# unless it's something special (ie not a .c file).
--#
--# Note 2! The CFLAGS definitions are now inherited from the
--# parent makes..
--#
--# $Id: Makefile,v 1.65 2002/03/22 07:10:34 dwmw2 Exp $
--
--
--obj-y += chips/chipslink.o maps/mapslink.o \
-- devices/devlink.o nand/nandlink.o
--obj-m :=
--obj-n :=
--obj- :=
--
--O_TARGET := mtdlink.o
--
--export-objs := mtdcore.o mtdpart.o redboot.o cmdlinepart.o afs.o mtdconcat.o
--list-multi := nftl.o
--
--mod-subdirs :=
--subdir-y := chips maps devices nand
--subdir-m := $(subdir-y)
--
--# *** BIG UGLY NOTE ***
--#
--# The shiny new inter_module_xxx has introduced yet another ugly link
--# order dependency, which I'd previously taken great care to avoid.
--# We now have to ensure that the chip drivers are initialised before the
--# map drivers, and that the doc200[01] drivers are initialised before
--# docprobe.
--#
--# We'll hopefully merge the doc200[01] drivers and docprobe back into
--# a single driver some time soon, but the CFI drivers are going to have
--# to stay like that.
--#
--# Urgh.
-+# linux/drivers/Makefile.24
-+# Makefile for obsolete kernels.
- #
--# dwmw2 21/11/0
-+# $Id: Makefile.24,v 1.3 2004/08/11 14:45:53 dmarlin Exp $
-
- # Core functionality.
--obj-$(CONFIG_MTD) += mtdcore.o
-+mtd-y := mtdcore.o
-+mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
-+obj-$(CONFIG_MTD) += $(mtd-y)
-+
- obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
--obj-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
- obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
- obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
- obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
-
- # 'Users' - code which presents functionality to userspace.
- obj-$(CONFIG_MTD_CHAR) += mtdchar.o
--obj-$(CONFIG_MTD_BLOCK) += mtdblock.o
--obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o
--obj-$(CONFIG_FTL) += ftl.o
--obj-$(CONFIG_NFTL) += nftl.o
-+obj-$(CONFIG_MTD_BLOCK) += mtdblock.o mtd_blkdevs-24.o
-+obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o mtd_blkdevs-24.o
-+obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs-24.o
-+obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs-24.o
-+obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs-24.o
-
- nftl-objs := nftlcore.o nftlmount.o
-+inftl-objs := inftlcore.o inftlmount.o
-+
-+export-objs := mtdcore.o mtdpart.o redboot.o cmdlinepart.o afs.o \
-+ mtdconcat.o mtd_blkdevs-24.o
-+
-+mtd_blkdevs-objs := mtd_blkdevs-24.o
-+
-+obj-y += chips/chipslink.o maps/mapslink.o \
-+ devices/devlink.o nand/nandlink.o
-+
-+O_TARGET := mtdlink.o
-+
-+list-multi := nftl.o inftl.o mtd_blkdevs-24.o
-+
-+mod-subdirs :=
-+subdir-y := chips maps devices nand
-+subdir-m := $(subdir-y)
-
- include $(TOPDIR)/Rules.make
-
- nftl.o: $(nftl-objs)
- $(LD) -r -o $@ $(nftl-objs)
-
-+inftl.o: $(inftl-objs)
-+ $(LD) -r -o $@ $(inftl-objs)
-+
-+mtd_blkdevs.o: $(mtd_blkdevs-objs)
-+ $(LD) -r -o $@ $(mtd_blkdevs-objs)
-+
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/Makefile.common
-@@ -0,0 +1,27 @@
-+#
-+# Makefile for the memory technology device drivers.
-+#
-+# $Id: Makefile.common,v 1.5 2004/08/10 20:51:49 dwmw2 Exp $
-+
-+# Core functionality.
-+mtd-y := mtdcore.o
-+mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
-+obj-$(CONFIG_MTD) += $(mtd-y)
-+
-+obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
-+obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
-+obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
-+obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
-+
-+# 'Users' - code which presents functionality to userspace.
-+obj-$(CONFIG_MTD_CHAR) += mtdchar.o
-+obj-$(CONFIG_MTD_BLOCK) += mtdblock.o mtd_blkdevs.o
-+obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o mtd_blkdevs.o
-+obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.o
-+obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o
-+obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o
-+
-+nftl-objs := nftlcore.o nftlmount.o
-+inftl-objs := inftlcore.o inftlmount.o
-+
-+obj-y += chips/ maps/ devices/ nand/
---- linux-2.4.21/drivers/mtd/afs.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/afs.c
-@@ -21,7 +21,7 @@
- This is access code for flashes using ARM's flash partitioning
- standards.
-
-- $Id: afs.c,v 1.8 2002/05/04 08:49:09 rmk Exp $
-+ $Id: afs.c,v 1.13 2004/02/27 22:09:59 rmk Exp $
-
- ======================================================================*/
-
-@@ -57,6 +57,17 @@
- u32 checksum; /* Image checksum (inc. this struct) */
- };
-
-+static u32 word_sum(void *words, int num)
-+{
-+ u32 *p = words;
-+ u32 sum = 0;
-+
-+ while (num--)
-+ sum += *p++;
-+
-+ return sum;
-+}
-+
- static int
- afs_read_footer(struct mtd_info *mtd, u_int *img_start, u_int *iis_start,
- u_int off, u_int mask)
-@@ -76,17 +87,25 @@
- return ret;
- }
-
-+ ret = 1;
-+
- /*
- * Does it contain the magic number?
- */
- if (fs.signature != 0xa0ffff9f)
-- ret = 1;
-+ ret = 0;
-+
-+ /*
-+ * Check the checksum.
-+ */
-+ if (word_sum(&fs, sizeof(fs) / sizeof(u32)) != 0xffffffff)
-+ ret = 0;
-
- /*
- * Don't touch the SIB.
- */
- if (fs.type == 2)
-- ret = 1;
-+ ret = 0;
-
- *iis_start = fs.image_info_base & mask;
- *img_start = fs.image_start & mask;
-@@ -96,14 +115,14 @@
- * be located after the footer structure.
- */
- if (*iis_start >= ptr)
-- ret = 1;
-+ ret = 0;
-
- /*
- * Check the start of this image. The image
- * data can not be located after this block.
- */
- if (*img_start > off)
-- ret = 1;
-+ ret = 0;
-
- return ret;
- }
-@@ -112,20 +131,41 @@
- afs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr)
- {
- size_t sz;
-- int ret;
-+ int ret, i;
-
- memset(iis, 0, sizeof(*iis));
- ret = mtd->read(mtd, ptr, sizeof(*iis), &sz, (u_char *) iis);
-- if (ret >= 0 && sz != sizeof(*iis))
-- ret = -EINVAL;
- if (ret < 0)
-+ goto failed;
-+
-+ if (sz != sizeof(*iis)) {
-+ ret = -EINVAL;
-+ goto failed;
-+ }
-+
-+ ret = 0;
-+
-+ /*
-+ * Validate the name - it must be NUL terminated.
-+ */
-+ for (i = 0; i < sizeof(iis->name); i++)
-+ if (iis->name[i] == '\0')
-+ break;
-+
-+ if (i < sizeof(iis->name))
-+ ret = 1;
-+
-+ return ret;
-+
-+ failed:
- printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
- ptr, ret);
--
- return ret;
- }
-
--int parse_afs_partitions(struct mtd_info *mtd, struct mtd_partition **pparts)
-+static int parse_afs_partitions(struct mtd_info *mtd,
-+ struct mtd_partition **pparts,
-+ unsigned long origin)
- {
- struct mtd_partition *parts;
- u_int mask, off, idx, sz;
-@@ -150,12 +190,14 @@
- ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
- if (ret < 0)
- break;
-- if (ret == 1)
-+ if (ret == 0)
- continue;
-
- ret = afs_read_iis(mtd, &iis, iis_ptr);
- if (ret < 0)
- break;
-+ if (ret == 0)
-+ continue;
-
- sz += sizeof(struct mtd_partition);
- sz += strlen(iis.name) + 1;
-@@ -183,13 +225,15 @@
- ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
- if (ret < 0)
- break;
-- if (ret == 1)
-+ if (ret == 0)
- continue;
-
- /* Read the image info block */
- ret = afs_read_iis(mtd, &iis, iis_ptr);
- if (ret < 0)
- break;
-+ if (ret == 0)
-+ continue;
-
- strcpy(str, iis.name);
- size = mtd->erasesize + off - img_ptr;
-@@ -227,7 +271,25 @@
- return idx ? idx : ret;
- }
-
--EXPORT_SYMBOL(parse_afs_partitions);
-+static struct mtd_part_parser afs_parser = {
-+ .owner = THIS_MODULE,
-+ .parse_fn = parse_afs_partitions,
-+ .name = "afs",
-+};
-+
-+static int __init afs_parser_init(void)
-+{
-+ return register_mtd_parser(&afs_parser);
-+}
-+
-+static void __exit afs_parser_exit(void)
-+{
-+ deregister_mtd_parser(&afs_parser);
-+}
-+
-+module_init(afs_parser_init);
-+module_exit(afs_parser_exit);
-+
-
- MODULE_AUTHOR("ARM Ltd");
- MODULE_DESCRIPTION("ARM Firmware Suite partition parser");
---- linux-2.4.21/drivers/mtd/chips/Config.in~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/chips/Config.in
-@@ -1,6 +1,6 @@
- # drivers/mtd/chips/Config.in
-
--# $Id: Config.in,v 1.16 2002/09/03 13:30:43 joern Exp $
-+# $Id: Config.in,v 1.20 2004/08/09 18:46:03 dmarlin Exp $
-
- mainmenu_option next_comment
-
-@@ -18,6 +18,7 @@
- define_bool CONFIG_MTD_GEN_PROBE n
- fi
- fi
-+
- if [ "$CONFIG_MTD_GEN_PROBE" = "y" -o "$CONFIG_MTD_GEN_PROBE" = "m" ]; then
- bool ' Flash chip driver advanced configuration options' CONFIG_MTD_CFI_ADV_OPTIONS
- if [ "$CONFIG_MTD_CFI_ADV_OPTIONS" = "y" ]; then
-@@ -27,11 +28,13 @@
- LITTLE_ENDIAN_BYTE CONFIG_MTD_CFI_LE_BYTE_SWAP" NO
- bool ' Specific CFI Flash geometry selection' CONFIG_MTD_CFI_GEOMETRY
- if [ "$CONFIG_MTD_CFI_GEOMETRY" = "y" ]; then
-- bool ' Support 8-bit buswidth' CONFIG_MTD_CFI_B1
-- bool ' Support 16-bit buswidth' CONFIG_MTD_CFI_B2
-- bool ' Support 32-bit buswidth' CONFIG_MTD_CFI_B4
-- bool ' Support 64-bit buswidth' CONFIG_MTD_CFI_B8
-- if [ "$CONFIG_MTD_CFI_B1" = "y" ]; then
-+ bool ' Support 8-bit buswidth' CONFIG_MTD_MAP_BANK_WIDTH_1
-+ bool ' Support 16-bit buswidth' CONFIG_MTD_MAP_BANK_WIDTH_2
-+ bool ' Support 32-bit buswidth' CONFIG_MTD_MAP_BANK_WIDTH_4
-+ bool ' Support 64-bit buswidth' CONFIG_MTD_MAP_BANK_WIDTH_8
-+ bool ' Support 128-bit buswidth' CONFIG_MTD_MAP_BANK_WIDTH_16
-+ bool ' Support 256-bit buswidth' CONFIG_MTD_MAP_BANK_WIDTH_32
-+ if [ "$CONFIG_MTD_MAP_BANK_WIDTH_1" = "y" ]; then
- define_bool CONFIG_MTD_CFI_I1 y
- else
- bool ' Support 1-chip flash interleave' CONFIG_MTD_CFI_I1
-@@ -46,6 +49,20 @@
- dep_tristate ' Support for AMD/Fujitsu flash chips' CONFIG_MTD_CFI_AMDSTD $CONFIG_MTD_GEN_PROBE
- dep_tristate ' Support for ST (Advanced Architecture) flash chips' CONFIG_MTD_CFI_STAA $CONFIG_MTD_GEN_PROBE
-
-+if [ "$CONFIG_MTD_CFI_INTELEXT" = "y" \
-+ -o "$CONFIG_MTD_CFI_AMDSTD" = "y" \
-+ -o "$CONFIG_MTD_CFI_STAA" = "y" ]; then
-+ define_bool CONFIG_MTD_CFI_UTIL y
-+else
-+ if [ "$CONFIG_MTD_CFI_INTELEXT" = "m" \
-+ -o "$CONFIG_MTD_CFI_AMDSTD" = "m" \
-+ -o "$CONFIG_MTD_CFI_STAA" = "m" ]; then
-+ define_bool CONFIG_MTD_CFI_UTIL m
-+ else
-+ define_bool CONFIG_MTD_CFI_UTIL n
-+ fi
-+fi
-+
- dep_tristate ' Support for RAM chips in bus mapping' CONFIG_MTD_RAM $CONFIG_MTD
- dep_tristate ' Support for ROM chips in bus mapping' CONFIG_MTD_ROM $CONFIG_MTD
- dep_tristate ' Support for absent chips in bus mapping' CONFIG_MTD_ABSENT $CONFIG_MTD
---- linux-2.4.21/drivers/mtd/chips/Makefile~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/chips/Makefile
-@@ -1,31 +1,12 @@
- #
--# linux/drivers/chips/Makefile
-+# linux/drivers/chips/Makefile.24
-+# Makefile for obsolete kernels.
- #
--# $Id: Makefile,v 1.8 2002/01/10 20:27:40 eric Exp $
-+# $Id: Makefile.24,v 1.1 2004/07/12 16:08:16 dwmw2 Exp $
-
- O_TARGET := chipslink.o
-+export-objs := chipreg.o gen_probe.o cfi_util.o
-
--export-objs := chipreg.o gen_probe.o
--
--# *** BIG UGLY NOTE ***
--#
--# The removal of get_module_symbol() and replacement with
--# inter_module_register() et al has introduced a link order dependency
--# here where previously there was none. We now have to ensure that
--# the CFI command set drivers are linked before cfi_probe.o
--
--obj-$(CONFIG_MTD) += chipreg.o
--obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o
--obj-$(CONFIG_MTD_CFI) += cfi_probe.o
--obj-$(CONFIG_MTD_CFI_STAA) += cfi_cmdset_0020.o
--obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o
--obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o
--obj-$(CONFIG_MTD_GEN_PROBE) += gen_probe.o
--obj-$(CONFIG_MTD_JEDEC) += jedec.o
--obj-$(CONFIG_MTD_JEDECPROBE) += jedec_probe.o
--obj-$(CONFIG_MTD_RAM) += map_ram.o
--obj-$(CONFIG_MTD_ROM) += map_rom.o
--obj-$(CONFIG_MTD_SHARP) += sharp.o
--obj-$(CONFIG_MTD_ABSENT) += map_absent.o
-+include Makefile.common
-
- include $(TOPDIR)/Rules.make
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/chips/Makefile.common
-@@ -0,0 +1,26 @@
-+#
-+# linux/drivers/chips/Makefile
-+#
-+# $Id: Makefile.common,v 1.4 2004/07/12 16:07:30 dwmw2 Exp $
-+
-+# *** BIG UGLY NOTE ***
-+#
-+# The removal of get_module_symbol() and replacement with
-+# inter_module_register() et al has introduced a link order dependency
-+# here where previously there was none. We now have to ensure that
-+# the CFI command set drivers are linked before gen_probe.o
-+
-+obj-$(CONFIG_MTD) += chipreg.o
-+obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o
-+obj-$(CONFIG_MTD_CFI) += cfi_probe.o
-+obj-$(CONFIG_MTD_CFI_UTIL) += cfi_util.o
-+obj-$(CONFIG_MTD_CFI_STAA) += cfi_cmdset_0020.o
-+obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o
-+obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o
-+obj-$(CONFIG_MTD_GEN_PROBE) += gen_probe.o
-+obj-$(CONFIG_MTD_JEDEC) += jedec.o
-+obj-$(CONFIG_MTD_JEDECPROBE) += jedec_probe.o
-+obj-$(CONFIG_MTD_RAM) += map_ram.o
-+obj-$(CONFIG_MTD_ROM) += map_rom.o
-+obj-$(CONFIG_MTD_SHARP) += sharp.o
-+obj-$(CONFIG_MTD_ABSENT) += map_absent.o
---- linux-2.4.21/drivers/mtd/chips/amd_flash.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/chips/amd_flash.c
-@@ -3,7 +3,7 @@
- *
- * Author: Jonas Holmberg <jonas.holmberg@axis.com>
- *
-- * $Id: amd_flash.c,v 1.19 2003/01/24 13:30:11 dwmw2 Exp $
-+ * $Id: amd_flash.c,v 1.27 2005/02/04 07:43:09 jonashg Exp $
- *
- * Copyright (c) 2001 Axis Communications AB
- *
-@@ -19,6 +19,7 @@
- #include <linux/slab.h>
- #include <linux/delay.h>
- #include <linux/interrupt.h>
-+#include <linux/init.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/flashchip.h>
-@@ -66,7 +67,6 @@
- #define AM29LV160DT 0x22C4
- #define AM29LV160DB 0x2249
- #define AM29BDS323D 0x22D1
--#define AM29BDS643D 0x227E
-
- /* Atmel */
- #define AT49xV16x 0x00C0
-@@ -125,10 +125,10 @@
-
-
- static struct mtd_chip_driver amd_flash_chipdrv = {
-- probe: amd_flash_probe,
-- destroy: amd_flash_destroy,
-- name: "amd_flash",
-- module: THIS_MODULE
-+ .probe = amd_flash_probe,
-+ .destroy = amd_flash_destroy,
-+ .name = "amd_flash",
-+ .module = THIS_MODULE
- };
-
-
-@@ -140,11 +140,11 @@
- static inline __u32 wide_read(struct map_info *map, __u32 addr)
- {
- if (map->buswidth == 1) {
-- return map->read8(map, addr);
-+ return map_read8(map, addr);
- } else if (map->buswidth == 2) {
-- return map->read16(map, addr);
-+ return map_read16(map, addr);
- } else if (map->buswidth == 4) {
-- return map->read32(map, addr);
-+ return map_read32(map, addr);
- }
-
- return 0;
-@@ -153,11 +153,11 @@
- static inline void wide_write(struct map_info *map, __u32 val, __u32 addr)
- {
- if (map->buswidth == 1) {
-- map->write8(map, val, addr);
-+ map_write8(map, val, addr);
- } else if (map->buswidth == 2) {
-- map->write16(map, val, addr);
-+ map_write16(map, val, addr);
- } else if (map->buswidth == 4) {
-- map->write32(map, val, addr);
-+ map_write32(map, val, addr);
- }
- }
-
-@@ -424,231 +424,217 @@
-
- static struct mtd_info *amd_flash_probe(struct map_info *map)
- {
-- /* Keep this table on the stack so that it gets deallocated after the
-- * probe is done.
-- */
-- const struct amd_flash_info table[] = {
-+ static const struct amd_flash_info table[] = {
- {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV160DT,
-- name: "AMD AM29LV160DT",
-- size: 0x00200000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 31 },
-- { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 }
-- }
-- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV160DB,
-- name: "AMD AM29LV160DB",
-- size: 0x00200000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 },
-- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x010000, erasesize: 0x10000, numblocks: 31 }
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV160DT,
-+ .name = "AMD AM29LV160DT",
-+ .size = 0x00200000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-+ { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
-- mfr_id: MANUFACTURER_TOSHIBA,
-- dev_id: TC58FVT160,
-- name: "Toshiba TC58FVT160",
-- size: 0x00200000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 31 },
-- { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 }
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV160DB,
-+ .name = "AMD AM29LV160DB",
-+ .size = 0x00200000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
-+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV160TE,
-- name: "Fujitsu MBM29LV160TE",
-- size: 0x00200000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 31 },
-- { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 }
-+ .mfr_id = MANUFACTURER_TOSHIBA,
-+ .dev_id = TC58FVT160,
-+ .name = "Toshiba TC58FVT160",
-+ .size = 0x00200000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-+ { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
-- mfr_id: MANUFACTURER_TOSHIBA,
-- dev_id: TC58FVB160,
-- name: "Toshiba TC58FVB160",
-- size: 0x00200000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 },
-- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x010000, erasesize: 0x10000, numblocks: 31 }
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV160TE,
-+ .name = "Fujitsu MBM29LV160TE",
-+ .size = 0x00200000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-+ { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV160BE,
-- name: "Fujitsu MBM29LV160BE",
-- size: 0x00200000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 },
-- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x010000, erasesize: 0x10000, numblocks: 31 }
-+ .mfr_id = MANUFACTURER_TOSHIBA,
-+ .dev_id = TC58FVB160,
-+ .name = "Toshiba TC58FVB160",
-+ .size = 0x00200000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
-+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV800BB,
-- name: "AMD AM29LV800BB",
-- size: 0x00100000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 },
-- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x010000, erasesize: 0x10000, numblocks: 15 }
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV160BE,
-+ .name = "Fujitsu MBM29LV160BE",
-+ .size = 0x00200000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
-+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F800BB,
-- name: "AMD AM29F800BB",
-- size: 0x00100000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 },
-- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x010000, erasesize: 0x10000, numblocks: 15 }
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV800BB,
-+ .name = "AMD AM29LV800BB",
-+ .size = 0x00100000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
-+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV800BT,
-- name: "AMD AM29LV800BT",
-- size: 0x00100000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 15 },
-- { offset: 0x0F0000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x0F8000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x0FC000, erasesize: 0x04000, numblocks: 1 }
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F800BB,
-+ .name = "AMD AM29F800BB",
-+ .size = 0x00100000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
-+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F800BT,
-- name: "AMD AM29F800BT",
-- size: 0x00100000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 15 },
-- { offset: 0x0F0000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x0F8000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x0FC000, erasesize: 0x04000, numblocks: 1 }
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV800BT,
-+ .name = "AMD AM29LV800BT",
-+ .size = 0x00100000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-+ { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV800BB,
-- name: "AMD AM29LV800BB",
-- size: 0x00100000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 15 },
-- { offset: 0x0F0000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x0F8000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x0FC000, erasesize: 0x04000, numblocks: 1 }
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F800BT,
-+ .name = "AMD AM29F800BT",
-+ .size = 0x00100000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-+ { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV800BB,
-- name: "Fujitsu MBM29LV800BB",
-- size: 0x00100000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 },
-- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x010000, erasesize: 0x10000, numblocks: 15 }
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV800BB,
-+ .name = "AMD AM29LV800BB",
-+ .size = 0x00100000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-+ { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
-- mfr_id: MANUFACTURER_ST,
-- dev_id: M29W800T,
-- name: "ST M29W800T",
-- size: 0x00100000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 15 },
-- { offset: 0x0F0000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x0F8000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x0FC000, erasesize: 0x04000, numblocks: 1 }
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV800BB,
-+ .name = "Fujitsu MBM29LV800BB",
-+ .size = 0x00100000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
-+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
- }
- }, {
-- mfr_id: MANUFACTURER_ST,
-- dev_id: M29W160DT,
-- name: "ST M29W160DT",
-- size: 0x00200000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 31 },
-- { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 }
-+ .mfr_id = MANUFACTURER_ST,
-+ .dev_id = M29W800T,
-+ .name = "ST M29W800T",
-+ .size = 0x00100000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-+ { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
-- mfr_id: MANUFACTURER_ST,
-- dev_id: M29W160DB,
-- name: "ST M29W160DB",
-- size: 0x00200000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 },
-- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x010000, erasesize: 0x10000, numblocks: 31 }
-+ .mfr_id = MANUFACTURER_ST,
-+ .dev_id = M29W160DT,
-+ .name = "ST M29W160DT",
-+ .size = 0x00200000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-+ { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29BDS323D,
-- name: "AMD AM29BDS323D",
-- size: 0x00400000,
-- numeraseregions: 3,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 48 },
-- { offset: 0x300000, erasesize: 0x10000, numblocks: 15 },
-- { offset: 0x3f0000, erasesize: 0x02000, numblocks: 8 },
-+ .mfr_id = MANUFACTURER_ST,
-+ .dev_id = M29W160DB,
-+ .name = "ST M29W160DB",
-+ .size = 0x00200000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
-+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29BDS643D,
-- name: "AMD AM29BDS643D",
-- size: 0x00800000,
-- numeraseregions: 3,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 96 },
-- { offset: 0x600000, erasesize: 0x10000, numblocks: 31 },
-- { offset: 0x7f0000, erasesize: 0x02000, numblocks: 8 },
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29BDS323D,
-+ .name = "AMD AM29BDS323D",
-+ .size = 0x00400000,
-+ .numeraseregions = 3,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 48 },
-+ { .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 },
-+ { .offset = 0x3f0000, .erasesize = 0x02000, .numblocks = 8 },
- }
- }, {
-- mfr_id: MANUFACTURER_ATMEL,
-- dev_id: AT49xV16x,
-- name: "Atmel AT49xV16x",
-- size: 0x00200000,
-- numeraseregions: 2,
-- regions: {
-- { offset: 0x000000, erasesize: 0x02000, numblocks: 8 },
-- { offset: 0x010000, erasesize: 0x10000, numblocks: 31 }
-+ .mfr_id = MANUFACTURER_ATMEL,
-+ .dev_id = AT49xV16x,
-+ .name = "Atmel AT49xV16x",
-+ .size = 0x00200000,
-+ .numeraseregions = 2,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x02000, .numblocks = 8 },
-+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
- }
- }, {
-- mfr_id: MANUFACTURER_ATMEL,
-- dev_id: AT49xV16xT,
-- name: "Atmel AT49xV16xT",
-- size: 0x00200000,
-- numeraseregions: 2,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 31 },
-- { offset: 0x1F0000, erasesize: 0x02000, numblocks: 8 }
-+ .mfr_id = MANUFACTURER_ATMEL,
-+ .dev_id = AT49xV16xT,
-+ .name = "Atmel AT49xV16xT",
-+ .size = 0x00200000,
-+ .numeraseregions = 2,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-+ { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks = 8 }
- }
- }
- };
-@@ -720,7 +706,7 @@
- "memory for MTD erase region info\n", map->name);
- kfree(mtd);
- map->fldrv_priv = NULL;
-- return 0;
-+ return NULL;
- }
-
- reg_idx = 0;
-@@ -782,8 +768,8 @@
- map->fldrv_priv = private;
-
- map->fldrv = &amd_flash_chipdrv;
-- MOD_INC_USE_COUNT;
-
-+ __module_get(THIS_MODULE);
- return mtd;
- }
-
-@@ -822,7 +808,7 @@
-
- chip->state = FL_READY;
-
-- map->copy_from(map, buf, adr, len);
-+ map_copy_from(map, buf, adr, len);
-
- wake_up(&chip->wq);
- spin_unlock_bh(chip->mutex);
-@@ -984,7 +970,7 @@
- u_char tmp_buf[4];
- __u32 datum;
-
-- map->copy_from(map, tmp_buf,
-+ map_copy_from(map, tmp_buf,
- bus_ofs + private->chips[chipnum].start,
- map->buswidth);
- while (len && i < map->buswidth)
-@@ -1057,7 +1043,7 @@
- u_char tmp_buf[2];
- __u32 datum;
-
-- map->copy_from(map, tmp_buf,
-+ map_copy_from(map, tmp_buf,
- ofs + private->chips[chipnum].start,
- map->buswidth);
- while (len--) {
-@@ -1124,7 +1110,7 @@
- timeo = jiffies + (HZ * 20);
-
- spin_unlock_bh(chip->mutex);
-- schedule_timeout(HZ);
-+ msleep(1000);
- spin_lock_bh(chip->mutex);
-
- while (flash_is_busy(map, adr, private->interleave)) {
-@@ -1178,7 +1164,7 @@
- __u8 verify;
-
- for (address = adr; address < (adr + size); address++) {
-- if ((verify = map->read8(map, address)) != 0xFF) {
-+ if ((verify = map_read8(map, address)) != 0xFF) {
- error = 1;
- break;
- }
-@@ -1309,9 +1295,7 @@
- }
-
- instr->state = MTD_ERASE_DONE;
-- if (instr->callback) {
-- instr->callback(instr);
-- }
-+ mtd_erase_callback(instr);
-
- return 0;
- }
---- linux-2.4.21/drivers/mtd/chips/cfi_cmdset_0001.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/chips/cfi_cmdset_0001.c
-@@ -4,7 +4,7 @@
- *
- * (C) 2000 Red Hat. GPL'd
- *
-- * $Id: cfi_cmdset_0001.c,v 1.114 2003/03/18 12:28:40 dwmw2 Exp $
-+ * $Id: cfi_cmdset_0001.c,v 1.168 2005/02/17 20:34:59 nico Exp $
- *
- *
- * 10/10/2000 Nicolas Pitre <nico@cam.org>
-@@ -21,6 +21,7 @@
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <asm/byteorder.h>
-
-@@ -28,21 +29,39 @@
- #include <linux/slab.h>
- #include <linux/delay.h>
- #include <linux/interrupt.h>
-+#include <linux/mtd/xip.h>
- #include <linux/mtd/map.h>
--#include <linux/mtd/cfi.h>
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/compatmac.h>
-+#include <linux/mtd/cfi.h>
-
--// debugging, turns off buffer write mode #define FORCE_WORD_WRITE
-+/* #define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE */
-+/* #define CMDSET0001_DISABLE_WRITE_SUSPEND */
-+
-+// debugging, turns off buffer write mode if set to 1
-+#define FORCE_WORD_WRITE 0
-+
-+#define MANUFACTURER_INTEL 0x0089
-+#define I82802AB 0x00ad
-+#define I82802AC 0x00ac
-+#define MANUFACTURER_ST 0x0020
-+#define M50LPW080 0x002F
-
- static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
--static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
--static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
- static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
- static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
- static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
- static void cfi_intelext_sync (struct mtd_info *);
- static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
- static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
-+static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-+static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-+static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-+static int cfi_intelext_lock_user_prot_reg (struct mtd_info *, loff_t, size_t);
-+static int cfi_intelext_get_fact_prot_info (struct mtd_info *,
-+ struct otp_info *, size_t);
-+static int cfi_intelext_get_user_prot_info (struct mtd_info *,
-+ struct otp_info *, size_t);
- static int cfi_intelext_suspend (struct mtd_info *);
- static void cfi_intelext_resume (struct mtd_info *);
-
-@@ -50,18 +69,29 @@
-
- struct mtd_info *cfi_cmdset_0001(struct map_info *, int);
-
--static struct mtd_info *cfi_intelext_setup (struct map_info *);
-+static struct mtd_info *cfi_intelext_setup (struct mtd_info *);
-+static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **);
-
--static int do_point (struct mtd_info *mtd, loff_t from, size_t len,
-+static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf);
--static void do_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
-+static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
- size_t len);
-
-+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
-+static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr);
-+#include "fwh_lock.h"
-+
-+
-+
-+/*
-+ * *********** SETUP AND PROBE BITS ***********
-+ */
-+
- static struct mtd_chip_driver cfi_intelext_chipdrv = {
-- probe: NULL, /* Not usable directly */
-- destroy: cfi_intelext_destroy,
-- name: "cfi_cmdset_0001",
-- module: THIS_MODULE
-+ .probe = NULL, /* Not usable directly */
-+ .destroy = cfi_intelext_destroy,
-+ .name = "cfi_cmdset_0001",
-+ .module = THIS_MODULE
- };
-
- /* #define DEBUG_LOCK_BITS */
-@@ -81,7 +111,8 @@
- printk(" - Protection Bits: %s\n", extp->FeatureSupport&64?"supported":"unsupported");
- printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported");
- printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported");
-- for (i=9; i<32; i++) {
-+ printk(" - Simultaneous operations: %s\n", extp->FeatureSupport&512?"supported":"unsupported");
-+ for (i=10; i<32; i++) {
- if (extp->FeatureSupport & (1<<i))
- printk(" - Unknown Bit %X: supported\n", i);
- }
-@@ -102,13 +133,171 @@
- }
-
- printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n",
-- extp->VccOptimal >> 8, extp->VccOptimal & 0xf);
-+ extp->VccOptimal >> 4, extp->VccOptimal & 0xf);
- if (extp->VppOptimal)
- printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n",
-- extp->VppOptimal >> 8, extp->VppOptimal & 0xf);
-+ extp->VppOptimal >> 4, extp->VppOptimal & 0xf);
- }
- #endif
-
-+#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
-+/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
-+static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)
-+{
-+ struct map_info *map = mtd->priv;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
-+
-+ printk(KERN_WARNING "cfi_cmdset_0001: Suspend "
-+ "erase on write disabled.\n");
-+ extp->SuspendCmdSupport &= ~1;
-+}
-+#endif
-+
-+#ifdef CMDSET0001_DISABLE_WRITE_SUSPEND
-+static void fixup_no_write_suspend(struct mtd_info *mtd, void* param)
-+{
-+ struct map_info *map = mtd->priv;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
-+
-+ if (cfip && (cfip->FeatureSupport&4)) {
-+ cfip->FeatureSupport &= ~4;
-+ printk(KERN_WARNING "cfi_cmdset_0001: write suspend disabled\n");
-+ }
-+}
-+#endif
-+
-+static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param)
-+{
-+ struct map_info *map = mtd->priv;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+
-+ cfi->cfiq->BufWriteTimeoutTyp = 0; /* Not supported */
-+ cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */
-+}
-+
-+static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param)
-+{
-+ struct map_info *map = mtd->priv;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+
-+ /* Note this is done after the region info is endian swapped */
-+ cfi->cfiq->EraseRegionInfo[1] =
-+ (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e;
-+};
-+
-+static void fixup_use_point(struct mtd_info *mtd, void *param)
-+{
-+ struct map_info *map = mtd->priv;
-+ if (!mtd->point && map_is_linear(map)) {
-+ mtd->point = cfi_intelext_point;
-+ mtd->unpoint = cfi_intelext_unpoint;
-+ }
-+}
-+
-+static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
-+{
-+ struct map_info *map = mtd->priv;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ if (cfi->cfiq->BufWriteTimeoutTyp) {
-+ printk(KERN_INFO "Using buffer write method\n" );
-+ mtd->write = cfi_intelext_write_buffers;
-+ }
-+}
-+
-+static struct cfi_fixup cfi_fixup_table[] = {
-+#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
-+ { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
-+#endif
-+#ifdef CMDSET0001_DISABLE_WRITE_SUSPEND
-+ { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend, NULL },
-+#endif
-+#if !FORCE_WORD_WRITE
-+ { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL },
-+#endif
-+ { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
-+ { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
-+ { 0, 0, NULL, NULL }
-+};
-+
-+static struct cfi_fixup jedec_fixup_table[] = {
-+ { MANUFACTURER_INTEL, I82802AB, fixup_use_fwh_lock, NULL, },
-+ { MANUFACTURER_INTEL, I82802AC, fixup_use_fwh_lock, NULL, },
-+ { MANUFACTURER_ST, M50LPW080, fixup_use_fwh_lock, NULL, },
-+ { 0, 0, NULL, NULL }
-+};
-+static struct cfi_fixup fixup_table[] = {
-+ /* The CFI vendor ids and the JEDEC vendor IDs appear
-+ * to be common. It is like the devices id's are as
-+ * well. This table is to pick all cases where
-+ * we know that is the case.
-+ */
-+ { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point, NULL },
-+ { 0, 0, NULL, NULL }
-+};
-+
-+static inline struct cfi_pri_intelext *
-+read_pri_intelext(struct map_info *map, __u16 adr)
-+{
-+ struct cfi_pri_intelext *extp;
-+ unsigned int extp_size = sizeof(*extp);
-+
-+ again:
-+ extp = (struct cfi_pri_intelext *)cfi_read_pri(map, adr, extp_size, "Intel/Sharp");
-+ if (!extp)
-+ return NULL;
-+
-+ /* Do some byteswapping if necessary */
-+ extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
-+ extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
-+ extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
-+
-+ if (extp->MajorVersion == '1' && extp->MinorVersion == '3') {
-+ unsigned int extra_size = 0;
-+ int nb_parts, i;
-+
-+ /* Protection Register info */
-+ extra_size += (extp->NumProtectionFields - 1) *
-+ sizeof(struct cfi_intelext_otpinfo);
-+
-+ /* Burst Read info */
-+ extra_size += 6;
-+
-+ /* Number of hardware-partitions */
-+ extra_size += 1;
-+ if (extp_size < sizeof(*extp) + extra_size)
-+ goto need_more;
-+ nb_parts = extp->extra[extra_size - 1];
-+
-+ for (i = 0; i < nb_parts; i++) {
-+ struct cfi_intelext_regioninfo *rinfo;
-+ rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[extra_size];
-+ extra_size += sizeof(*rinfo);
-+ if (extp_size < sizeof(*extp) + extra_size)
-+ goto need_more;
-+ rinfo->NumIdentPartitions=le16_to_cpu(rinfo->NumIdentPartitions);
-+ extra_size += (rinfo->NumBlockTypes - 1)
-+ * sizeof(struct cfi_intelext_blockinfo);
-+ }
-+
-+ if (extp_size < sizeof(*extp) + extra_size) {
-+ need_more:
-+ extp_size = sizeof(*extp) + extra_size;
-+ kfree(extp);
-+ if (extp_size > 4096) {
-+ printk(KERN_ERR
-+ "%s: cfi_pri_intelext is too fat\n",
-+ __FUNCTION__);
-+ return NULL;
-+ }
-+ goto again;
-+ }
-+ }
-+
-+ return extp;
-+}
-+
- /* This routine is made available to other mtd code via
- * inter_module_register. It must only be accessed through
- * inter_module_get which will bump the use count of this module. The
-@@ -119,8 +308,29 @@
- struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
- {
- struct cfi_private *cfi = map->fldrv_priv;
-+ struct mtd_info *mtd;
- int i;
-- __u32 base = cfi->chips[0].start;
-+
-+ mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
-+ if (!mtd) {
-+ printk(KERN_ERR "Failed to allocate memory for MTD device\n");
-+ return NULL;
-+ }
-+ memset(mtd, 0, sizeof(*mtd));
-+ mtd->priv = map;
-+ mtd->type = MTD_NORFLASH;
-+
-+ /* Fill in the default mtd operations */
-+ mtd->erase = cfi_intelext_erase_varsize;
-+ mtd->read = cfi_intelext_read;
-+ mtd->write = cfi_intelext_write_words;
-+ mtd->sync = cfi_intelext_sync;
-+ mtd->lock = cfi_intelext_lock;
-+ mtd->unlock = cfi_intelext_unlock;
-+ mtd->suspend = cfi_intelext_suspend;
-+ mtd->resume = cfi_intelext_resume;
-+ mtd->flags = MTD_CAP_NORFLASH;
-+ mtd->name = map->name;
-
- if (cfi->cfi_mode == CFI_MODE_CFI) {
- /*
-@@ -130,40 +340,17 @@
- */
- __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
- struct cfi_pri_intelext *extp;
-- int ofs_factor = cfi->interleave * cfi->device_type;
--
-- //printk(" Intel/Sharp Extended Query Table at 0x%4.4X\n", adr);
-- if (!adr)
-- return NULL;
-
-- /* Switch it into Query Mode */
-- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
--
-- extp = kmalloc(sizeof(*extp), GFP_KERNEL);
-+ extp = read_pri_intelext(map, adr);
- if (!extp) {
-- printk(KERN_ERR "Failed to allocate memory\n");
-+ kfree(mtd);
- return NULL;
- }
-
-- /* Read in the Extended Query Table */
-- for (i=0; i<sizeof(*extp); i++) {
-- ((unsigned char *)extp)[i] =
-- cfi_read_query(map, (base+((adr+i)*ofs_factor)));
-- }
--
-- if (extp->MajorVersion != '1' ||
-- (extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
-- printk(KERN_WARNING " Unknown IntelExt Extended Query "
-- "version %c.%c.\n", extp->MajorVersion,
-- extp->MinorVersion);
-- kfree(extp);
-- return NULL;
-- }
-+ /* Install our own private info structure */
-+ cfi->cmdset_priv = extp;
-
-- /* Do some byteswapping if necessary */
-- extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
-- extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
-- extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
-+ cfi_fixup(mtd, cfi_fixup_table);
-
- #ifdef DEBUG_CFI_FEATURES
- /* Tell the user about it in lots of lovely detail */
-@@ -171,19 +358,15 @@
- #endif
-
- if(extp->SuspendCmdSupport & 1) {
--//#define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
--#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
--/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
-- printk(KERN_WARNING "cfi_cmdset_0001: Suspend "
-- "erase on write disabled.\n");
-- extp->SuspendCmdSupport &= ~1;
--#else
- printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n");
--#endif
- }
-- /* Install our own private info structure */
-- cfi->cmdset_priv = extp;
- }
-+ else if (cfi->cfi_mode == CFI_MODE_JEDEC) {
-+ /* Apply jedec specific fixups */
-+ cfi_fixup(mtd, jedec_fixup_table);
-+ }
-+ /* Apply generic fixups */
-+ cfi_fixup(mtd, fixup_table);
-
- for (i=0; i< cfi->numchips; i++) {
- cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
-@@ -194,30 +377,19 @@
-
- map->fldrv = &cfi_intelext_chipdrv;
-
-- /* Make sure it's in read mode */
-- cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
-- return cfi_intelext_setup(map);
-+ return cfi_intelext_setup(mtd);
- }
-
--static struct mtd_info *cfi_intelext_setup(struct map_info *map)
-+static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
- {
-+ struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
-- struct mtd_info *mtd;
- unsigned long offset = 0;
- int i,j;
- unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
-
-- mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
- //printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips);
-
-- if (!mtd) {
-- printk(KERN_ERR "Failed to allocate memory for MTD device\n");
-- goto setup_err;
-- }
--
-- memset(mtd, 0, sizeof(*mtd));
-- mtd->priv = map;
-- mtd->type = MTD_NORFLASH;
- mtd->size = devsize * cfi->numchips;
-
- mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
-@@ -257,37 +429,21 @@
- mtd->eraseregions[i].numblocks);
- }
-
-- /* Also select the correct geometry setup too */
-- mtd->erase = cfi_intelext_erase_varsize;
-- mtd->read = cfi_intelext_read;
-+#ifdef CONFIG_MTD_OTP
-+ mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
-+ mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
-+ mtd->write_user_prot_reg = cfi_intelext_write_user_prot_reg;
-+ mtd->lock_user_prot_reg = cfi_intelext_lock_user_prot_reg;
-+ mtd->get_fact_prot_info = cfi_intelext_get_fact_prot_info;
-+ mtd->get_user_prot_info = cfi_intelext_get_user_prot_info;
-+#endif
-
-- if(map->point && map->unpoint){
-- mtd->point = do_point;
-- mtd->unpoint = do_unpoint;
-- }
-+ /* This function has the potential to distort the reality
-+ a bit and therefore should be called last. */
-+ if (cfi_intelext_partition_fixup(mtd, &cfi) != 0)
-+ goto setup_err;
-
--#ifndef FORCE_WORD_WRITE
-- if ( cfi->cfiq->BufWriteTimeoutTyp ) {
-- printk("Using buffer write method\n" );
-- mtd->write = cfi_intelext_write_buffers;
-- } else {
--#else
-- {
--#endif
-- printk("Using word write method\n" );
-- mtd->write = cfi_intelext_write_words;
-- }
-- mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
-- mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
-- mtd->sync = cfi_intelext_sync;
-- mtd->lock = cfi_intelext_lock;
-- mtd->unlock = cfi_intelext_unlock;
-- mtd->suspend = cfi_intelext_suspend;
-- mtd->resume = cfi_intelext_resume;
-- mtd->flags = MTD_CAP_NORFLASH;
-- map->fldrv = &cfi_intelext_chipdrv;
-- MOD_INC_USE_COUNT;
-- mtd->name = map->name;
-+ __module_get(THIS_MODULE);
- return mtd;
-
- setup_err:
-@@ -297,82 +453,584 @@
- kfree(mtd);
- }
- kfree(cfi->cmdset_priv);
-- kfree(cfi->cfiq);
- return NULL;
- }
-
--static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
-+static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
-+ struct cfi_private **pcfi)
- {
-- cfi_word status, status_OK;
-- unsigned long timeo;
-- DECLARE_WAITQUEUE(wait, current);
-- unsigned long cmd_addr;
-- struct cfi_private *cfi = map->fldrv_priv;
-+ struct map_info *map = mtd->priv;
-+ struct cfi_private *cfi = *pcfi;
-+ struct cfi_pri_intelext *extp = cfi->cmdset_priv;
-
-- adr += chip->start;
-+ /*
-+ * Probing of multi-partition flash ships.
-+ *
-+ * To support multiple partitions when available, we simply arrange
-+ * for each of them to have their own flchip structure even if they
-+ * are on the same physical chip. This means completely recreating
-+ * a new cfi_private structure right here which is a blatent code
-+ * layering violation, but this is still the least intrusive
-+ * arrangement at this point. This can be rearranged in the future
-+ * if someone feels motivated enough. --nico
-+ */
-+ if (extp && extp->MajorVersion == '1' && extp->MinorVersion == '3'
-+ && extp->FeatureSupport & (1 << 9)) {
-+ struct cfi_private *newcfi;
-+ struct flchip *chip;
-+ struct flchip_shared *shared;
-+ int offs, numregions, numparts, partshift, numvirtchips, i, j;
-
-- /* Ensure cmd read/writes are aligned. */
-- cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1);
-+ /* Protection Register info */
-+ offs = (extp->NumProtectionFields - 1) *
-+ sizeof(struct cfi_intelext_otpinfo);
-
-- /* Let's determine this according to the interleave only once */
-- status_OK = CMD(0x80);
-+ /* Burst Read info */
-+ offs += 6;
-
-+ /* Number of partition regions */
-+ numregions = extp->extra[offs];
-+ offs += 1;
-+
-+ /* Number of hardware partitions */
-+ numparts = 0;
-+ for (i = 0; i < numregions; i++) {
-+ struct cfi_intelext_regioninfo *rinfo;
-+ rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[offs];
-+ numparts += rinfo->NumIdentPartitions;
-+ offs += sizeof(*rinfo)
-+ + (rinfo->NumBlockTypes - 1) *
-+ sizeof(struct cfi_intelext_blockinfo);
-+ }
-+
-+ /*
-+ * All functions below currently rely on all chips having
-+ * the same geometry so we'll just assume that all hardware
-+ * partitions are of the same size too.
-+ */
-+ partshift = cfi->chipshift - __ffs(numparts);
-+
-+ if ((1 << partshift) < mtd->erasesize) {
-+ printk( KERN_ERR
-+ "%s: bad number of hw partitions (%d)\n",
-+ __FUNCTION__, numparts);
-+ return -EINVAL;
-+ }
-+
-+ numvirtchips = cfi->numchips * numparts;
-+ newcfi = kmalloc(sizeof(struct cfi_private) + numvirtchips * sizeof(struct flchip), GFP_KERNEL);
-+ if (!newcfi)
-+ return -ENOMEM;
-+ shared = kmalloc(sizeof(struct flchip_shared) * cfi->numchips, GFP_KERNEL);
-+ if (!shared) {
-+ kfree(newcfi);
-+ return -ENOMEM;
-+ }
-+ memcpy(newcfi, cfi, sizeof(struct cfi_private));
-+ newcfi->numchips = numvirtchips;
-+ newcfi->chipshift = partshift;
-+
-+ chip = &newcfi->chips[0];
-+ for (i = 0; i < cfi->numchips; i++) {
-+ shared[i].writing = shared[i].erasing = NULL;
-+ spin_lock_init(&shared[i].lock);
-+ for (j = 0; j < numparts; j++) {
-+ *chip = cfi->chips[i];
-+ chip->start += j << partshift;
-+ chip->priv = &shared[i];
-+ /* those should be reset too since
-+ they create memory references. */
-+ init_waitqueue_head(&chip->wq);
-+ spin_lock_init(&chip->_spinlock);
-+ chip->mutex = &chip->_spinlock;
-+ chip++;
-+ }
-+ }
-+
-+ printk(KERN_DEBUG "%s: %d set(s) of %d interleaved chips "
-+ "--> %d partitions of %d KiB\n",
-+ map->name, cfi->numchips, cfi->interleave,
-+ newcfi->numchips, 1<<(newcfi->chipshift-10));
-+
-+ map->fldrv_priv = newcfi;
-+ *pcfi = newcfi;
-+ kfree(cfi);
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * *********** CHIP ACCESS FUNCTIONS ***********
-+ */
-+
-+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ map_word status, status_OK = CMD(0x80), status_PWS = CMD(0x01);
-+ unsigned long timeo;
-+ struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
-+
-+ resettime:
- timeo = jiffies + HZ;
- retry:
-+ if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE)) {
-+ /*
-+ * OK. We have possibility for contension on the write/erase
-+ * operations which are global to the real chip and not per
-+ * partition. So let's fight it over in the partition which
-+ * currently has authority on the operation.
-+ *
-+ * The rules are as follows:
-+ *
-+ * - any write operation must own shared->writing.
-+ *
-+ * - any erase operation must own _both_ shared->writing and
-+ * shared->erasing.
-+ *
-+ * - contension arbitration is handled in the owner's context.
-+ *
-+ * The 'shared' struct can be read when its lock is taken.
-+ * However any writes to it can only be made when the current
-+ * owner's lock is also held.
-+ */
-+ struct flchip_shared *shared = chip->priv;
-+ struct flchip *contender;
-+ spin_lock(&shared->lock);
-+ contender = shared->writing;
-+ if (contender && contender != chip) {
-+ /*
-+ * The engine to perform desired operation on this
-+ * partition is already in use by someone else.
-+ * Let's fight over it in the context of the chip
-+ * currently using it. If it is possible to suspend,
-+ * that other partition will do just that, otherwise
-+ * it'll happily send us to sleep. In any case, when
-+ * get_chip returns success we're clear to go ahead.
-+ */
-+ int ret = spin_trylock(contender->mutex);
-+ spin_unlock(&shared->lock);
-+ if (!ret)
-+ goto retry;
-+ spin_unlock(chip->mutex);
-+ ret = get_chip(map, contender, contender->start, mode);
- spin_lock(chip->mutex);
-+ if (ret) {
-+ spin_unlock(contender->mutex);
-+ return ret;
-+ }
-+ timeo = jiffies + HZ;
-+ spin_lock(&shared->lock);
-+ }
-+
-+ /* We now own it */
-+ shared->writing = chip;
-+ if (mode == FL_ERASING)
-+ shared->erasing = chip;
-+ if (contender && contender != chip)
-+ spin_unlock(contender->mutex);
-+ spin_unlock(&shared->lock);
-+ }
-
-- /* Check that the chip's ready to talk to us.
-- * If it's in FL_ERASING state, suspend it and make it talk now.
-- */
- switch (chip->state) {
-
-- case FL_READY:
-- case FL_POINT:
-+ case FL_STATUS:
-+ for (;;) {
-+ status = map_read(map, adr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
-+ /* At this point we're fine with write operations
-+ in other partitions as they don't conflict. */
-+ if (chip->priv && map_word_andequal(map, status, status_PWS, status_PWS))
-+ break;
-+
-+ if (time_after(jiffies, timeo)) {
-+ printk(KERN_ERR "Waiting for chip to be ready timed out. Status %lx\n",
-+ status.x[0]);
-+ return -EIO;
-+ }
-+ spin_unlock(chip->mutex);
-+ cfi_udelay(1);
-+ spin_lock(chip->mutex);
-+ /* Someone else might have been playing with it. */
-+ goto retry;
-+ }
-+
-+ case FL_READY:
- case FL_CFI_QUERY:
- case FL_JEDEC_QUERY:
-- cfi_write(map, CMD(0x70), cmd_addr);
-- chip->state = FL_STATUS;
-+ return 0;
-
-- case FL_STATUS:
-- status = cfi_read(map, cmd_addr);
-- if ((status & status_OK) == status_OK) {
-- cfi_write(map, CMD(0xff), cmd_addr);
-- chip->state = FL_READY;
-+ case FL_ERASING:
-+ if (!cfip ||
-+ !(cfip->FeatureSupport & 2) ||
-+ !(mode == FL_READY || mode == FL_POINT ||
-+ (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1))))
-+ goto sleep;
-+
-+
-+ /* Erase suspend */
-+ map_write(map, CMD(0xB0), adr);
-+
-+ /* If the flash has finished erasing, then 'erase suspend'
-+ * appears to make some (28F320) flash devices switch to
-+ * 'read' mode. Make sure that we switch to 'read status'
-+ * mode so we get the right data. --rmk
-+ */
-+ map_write(map, CMD(0x70), adr);
-+ chip->oldstate = FL_ERASING;
-+ chip->state = FL_ERASE_SUSPENDING;
-+ chip->erase_suspended = 1;
-+ for (;;) {
-+ status = map_read(map, adr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-- }
-
-- /* Urgh. Chip not yet ready to talk to us. */
- if (time_after(jiffies, timeo)) {
-- spin_unlock(chip->mutex);
-- printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %llx\n", (__u64)status);
-+ /* Urgh. Resume and pretend we weren't here. */
-+ map_write(map, CMD(0xd0), adr);
-+ /* Make sure we're in 'read status' mode if it had finished */
-+ map_write(map, CMD(0x70), adr);
-+ chip->state = FL_ERASING;
-+ chip->oldstate = FL_READY;
-+ printk(KERN_ERR "Chip not ready after erase "
-+ "suspended: status = 0x%lx\n", status.x[0]);
- return -EIO;
- }
-
-- /* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
- cfi_udelay(1);
-- goto retry;
-+ spin_lock(chip->mutex);
-+ /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
-+ So we can just loop here. */
-+ }
-+ chip->state = FL_STATUS;
-+ return 0;
-+
-+ case FL_XIP_WHILE_ERASING:
-+ if (mode != FL_READY && mode != FL_POINT &&
-+ (mode != FL_WRITING || !cfip || !(cfip->SuspendCmdSupport&1)))
-+ goto sleep;
-+ chip->oldstate = chip->state;
-+ chip->state = FL_READY;
-+ return 0;
-+
-+ case FL_POINT:
-+ /* Only if there's no operation suspended... */
-+ if (mode == FL_READY && chip->oldstate == FL_READY)
-+ return 0;
-
- default:
-- /* Stick ourselves on a wait queue to be woken when
-- someone changes the status */
-+ sleep:
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
- spin_unlock(chip->mutex);
- schedule();
- remove_wait_queue(&chip->wq, &wait);
-- timeo = jiffies + HZ;
-- goto retry;
-+ spin_lock(chip->mutex);
-+ goto resettime;
-+ }
-+}
-+
-+static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+
-+ if (chip->priv) {
-+ struct flchip_shared *shared = chip->priv;
-+ spin_lock(&shared->lock);
-+ if (shared->writing == chip && chip->oldstate == FL_READY) {
-+ /* We own the ability to write, but we're done */
-+ shared->writing = shared->erasing;
-+ if (shared->writing && shared->writing != chip) {
-+ /* give back ownership to who we loaned it from */
-+ struct flchip *loaner = shared->writing;
-+ spin_lock(loaner->mutex);
-+ spin_unlock(&shared->lock);
-+ spin_unlock(chip->mutex);
-+ put_chip(map, loaner, loaner->start);
-+ spin_lock(chip->mutex);
-+ spin_unlock(loaner->mutex);
-+ wake_up(&chip->wq);
-+ return;
-+ }
-+ shared->erasing = NULL;
-+ shared->writing = NULL;
-+ } else if (shared->erasing == chip && shared->writing != chip) {
-+ /*
-+ * We own the ability to erase without the ability
-+ * to write, which means the erase was suspended
-+ * and some other partition is currently writing.
-+ * Don't let the switch below mess things up since
-+ * we don't have ownership to resume anything.
-+ */
-+ spin_unlock(&shared->lock);
-+ wake_up(&chip->wq);
-+ return;
-+ }
-+ spin_unlock(&shared->lock);
-+ }
-+
-+ switch(chip->oldstate) {
-+ case FL_ERASING:
-+ chip->state = chip->oldstate;
-+ /* What if one interleaved chip has finished and the
-+ other hasn't? The old code would leave the finished
-+ one in READY mode. That's bad, and caused -EROFS
-+ errors to be returned from do_erase_oneblock because
-+ that's the only bit it checked for at the time.
-+ As the state machine appears to explicitly allow
-+ sending the 0x70 (Read Status) command to an erasing
-+ chip and expecting it to be ignored, that's what we
-+ do. */
-+ map_write(map, CMD(0xd0), adr);
-+ map_write(map, CMD(0x70), adr);
-+ chip->oldstate = FL_READY;
-+ chip->state = FL_ERASING;
-+ break;
-+
-+ case FL_XIP_WHILE_ERASING:
-+ chip->state = chip->oldstate;
-+ chip->oldstate = FL_READY;
-+ break;
-+
-+ case FL_READY:
-+ case FL_STATUS:
-+ case FL_JEDEC_QUERY:
-+ /* We should really make set_vpp() count, rather than doing this */
-+ DISABLE_VPP(map);
-+ break;
-+ default:
-+ printk(KERN_ERR "put_chip() called with oldstate %d!!\n", chip->oldstate);
-+ }
-+ wake_up(&chip->wq);
-+}
-+
-+#ifdef CONFIG_MTD_XIP
-+
-+/*
-+ * No interrupt what so ever can be serviced while the flash isn't in array
-+ * mode. This is ensured by the xip_disable() and xip_enable() functions
-+ * enclosing any code path where the flash is known not to be in array mode.
-+ * And within a XIP disabled code path, only functions marked with __xipram
-+ * may be called and nothing else (it's a good thing to inspect generated
-+ * assembly to make sure inline functions were actually inlined and that gcc
-+ * didn't emit calls to its own support functions). Also configuring MTD CFI
-+ * support to a single buswidth and a single interleave is also recommended.
-+ * Note that not only IRQs are disabled but the preemption count is also
-+ * increased to prevent other locking primitives (namely spin_unlock) from
-+ * decrementing the preempt count to zero and scheduling the CPU away while
-+ * not in array mode.
-+ */
-+
-+static void xip_disable(struct map_info *map, struct flchip *chip,
-+ unsigned long adr)
-+{
-+ /* TODO: chips with no XIP use should ignore and return */
-+ (void) map_read(map, adr); /* ensure mmu mapping is up to date */
-+ preempt_disable();
-+ local_irq_disable();
-+}
-+
-+static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
-+ unsigned long adr)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ if (chip->state != FL_POINT && chip->state != FL_READY) {
-+ map_write(map, CMD(0xff), adr);
-+ chip->state = FL_READY;
- }
-+ (void) map_read(map, adr);
-+ asm volatile (".rep 8; nop; .endr"); /* fill instruction prefetch */
-+ local_irq_enable();
-+ preempt_enable();
-+}
-+
-+/*
-+ * When a delay is required for the flash operation to complete, the
-+ * xip_udelay() function is polling for both the given timeout and pending
-+ * (but still masked) hardware interrupts. Whenever there is an interrupt
-+ * pending then the flash erase or write operation is suspended, array mode
-+ * restored and interrupts unmasked. Task scheduling might also happen at that
-+ * point. The CPU eventually returns from the interrupt or the call to
-+ * schedule() and the suspended flash operation is resumed for the remaining
-+ * of the delay period.
-+ *
-+ * Warning: this function _will_ fool interrupt latency tracing tools.
-+ */
-+
-+static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
-+ unsigned long adr, int usec)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
-+ map_word status, OK = CMD(0x80);
-+ unsigned long suspended, start = xip_currtime();
-+ flstate_t oldstate, newstate;
-+
-+ do {
-+ cpu_relax();
-+ if (xip_irqpending() && cfip &&
-+ ((chip->state == FL_ERASING && (cfip->FeatureSupport&2)) ||
-+ (chip->state == FL_WRITING && (cfip->FeatureSupport&4))) &&
-+ (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) {
-+ /*
-+ * Let's suspend the erase or write operation when
-+ * supported. Note that we currently don't try to
-+ * suspend interleaved chips if there is already
-+ * another operation suspended (imagine what happens
-+ * when one chip was already done with the current
-+ * operation while another chip suspended it, then
-+ * we resume the whole thing at once). Yes, it
-+ * can happen!
-+ */
-+ map_write(map, CMD(0xb0), adr);
-+ map_write(map, CMD(0x70), adr);
-+ usec -= xip_elapsed_since(start);
-+ suspended = xip_currtime();
-+ do {
-+ if (xip_elapsed_since(suspended) > 100000) {
-+ /*
-+ * The chip doesn't want to suspend
-+ * after waiting for 100 msecs.
-+ * This is a critical error but there
-+ * is not much we can do here.
-+ */
-+ return;
-+ }
-+ status = map_read(map, adr);
-+ } while (!map_word_andequal(map, status, OK, OK));
-+
-+ /* Suspend succeeded */
-+ oldstate = chip->state;
-+ if (oldstate == FL_ERASING) {
-+ if (!map_word_bitsset(map, status, CMD(0x40)))
-+ break;
-+ newstate = FL_XIP_WHILE_ERASING;
-+ chip->erase_suspended = 1;
-+ } else {
-+ if (!map_word_bitsset(map, status, CMD(0x04)))
-+ break;
-+ newstate = FL_XIP_WHILE_WRITING;
-+ chip->write_suspended = 1;
-+ }
-+ chip->state = newstate;
-+ map_write(map, CMD(0xff), adr);
-+ (void) map_read(map, adr);
-+ asm volatile (".rep 8; nop; .endr");
-+ local_irq_enable();
-+ preempt_enable();
-+ asm volatile (".rep 8; nop; .endr");
-+ cond_resched();
-+
-+ /*
-+ * We're back. However someone else might have
-+ * decided to go write to the chip if we are in
-+ * a suspended erase state. If so let's wait
-+ * until it's done.
-+ */
-+ preempt_disable();
-+ while (chip->state != newstate) {
-+ DECLARE_WAITQUEUE(wait, current);
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ add_wait_queue(&chip->wq, &wait);
-+ preempt_enable();
-+ schedule();
-+ remove_wait_queue(&chip->wq, &wait);
-+ preempt_disable();
-+ }
-+ /* Disallow XIP again */
-+ local_irq_disable();
-+
-+ /* Resume the write or erase operation */
-+ map_write(map, CMD(0xd0), adr);
-+ map_write(map, CMD(0x70), adr);
-+ chip->state = oldstate;
-+ start = xip_currtime();
-+ } else if (usec >= 1000000/HZ) {
-+ /*
-+ * Try to save on CPU power when waiting delay
-+ * is at least a system timer tick period.
-+ * No need to be extremely accurate here.
-+ */
-+ xip_cpu_idle();
-+ }
-+ status = map_read(map, adr);
-+ } while (!map_word_andequal(map, status, OK, OK)
-+ && xip_elapsed_since(start) < usec);
-+}
-+
-+#define UDELAY(map, chip, adr, usec) xip_udelay(map, chip, adr, usec)
-+
-+/*
-+ * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
-+ * the flash is actively programming or erasing since we have to poll for
-+ * the operation to complete anyway. We can't do that in a generic way with
-+ * a XIP setup so do it before the actual flash operation in this case.
-+ */
-+#undef INVALIDATE_CACHED_RANGE
-+#define INVALIDATE_CACHED_RANGE(x...)
-+#define XIP_INVAL_CACHED_RANGE(map, from, size) \
-+ do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0)
-+
-+/*
-+ * Extra notes:
-+ *
-+ * Activating this XIP support changes the way the code works a bit. For
-+ * example the code to suspend the current process when concurrent access
-+ * happens is never executed because xip_udelay() will always return with the
-+ * same chip state as it was entered with. This is why there is no care for
-+ * the presence of add_wait_queue() or schedule() calls from within a couple
-+ * xip_disable()'d areas of code, like in do_erase_oneblock for example.
-+ * The queueing and scheduling are always happening within xip_udelay().
-+ *
-+ * Similarly, get_chip() and put_chip() just happen to always be executed
-+ * with chip->state set to FL_READY (or FL_XIP_WHILE_*) where flash state
-+ * is in array mode, therefore never executing many cases therein and not
-+ * causing any problem with XIP.
-+ */
-+
-+#else
-+
-+#define xip_disable(map, chip, adr)
-+#define xip_enable(map, chip, adr)
-+
-+#define UDELAY(map, chip, adr, usec) cfi_udelay(usec)
-+
-+#define XIP_INVAL_CACHED_RANGE(x...)
-+
-+#endif
-+
-+static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
-+{
-+ unsigned long cmd_addr;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ int ret = 0;
-+
-+ adr += chip->start;
-+
-+ /* Ensure cmd read/writes are aligned. */
-+ cmd_addr = adr & ~(map_bankwidth(map)-1);
-+
-+ spin_lock(chip->mutex);
-+
-+ ret = get_chip(map, chip, cmd_addr, FL_POINT);
-+
-+ if (!ret) {
-+ if (chip->state != FL_POINT && chip->state != FL_READY)
-+ map_write(map, CMD(0xff), cmd_addr);
-
- chip->state = FL_POINT;
- chip->ref_point_counter++;
-+ }
- spin_unlock(chip->mutex);
-- return 0;
-+
-+ return ret;
- }
--static int do_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
-+
-+static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
- {
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
-@@ -380,12 +1038,10 @@
- int chipnum;
- int ret = 0;
-
-- if (from + len > mtd->size)
-+ if (!map->virt || (from + len > mtd->size))
- return -EINVAL;
-
-- *mtdbuf = map->point(map, from, len);
-- if(*mtdbuf == NULL)
-- return -EINVAL; /* can not point this region */
-+ *mtdbuf = (void *)map->virt + from;
- *retlen = 0;
-
- /* Now lock the chip(s) to POINT state */
-@@ -418,14 +1074,13 @@
- return 0;
- }
-
--static void do_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
-+static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
- {
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
- unsigned long ofs;
- int chipnum;
-
-- map->unpoint(map, addr, from, len);
- /* Now unlock the chip(s) POINT state */
-
- /* ofs: offset within the first chip that the first read should start */
-@@ -446,13 +1101,14 @@
- thislen = len;
-
- spin_lock(chip->mutex);
-- if(chip->state == FL_POINT){
-+ if (chip->state == FL_POINT) {
- chip->ref_point_counter--;
- if(chip->ref_point_counter == 0)
- chip->state = FL_READY;
- } else
-- printk("Warning: unpoint called on non pointed region\n"); /* Should this give an error? */
-- wake_up(&chip->wq);
-+ printk(KERN_ERR "Warning: unpoint called on non pointed region\n"); /* Should this give an error? */
-+
-+ put_chip(map, chip, chip->start);
- spin_unlock(chip->mutex);
-
- len -= thislen;
-@@ -463,136 +1119,32 @@
-
- static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
- {
-- cfi_word status, status_OK;
-- unsigned long timeo;
-- DECLARE_WAITQUEUE(wait, current);
-- int suspended = 0;
- unsigned long cmd_addr;
- struct cfi_private *cfi = map->fldrv_priv;
-+ int ret;
-
- adr += chip->start;
-
- /* Ensure cmd read/writes are aligned. */
-- cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1);
--
-- /* Let's determine this according to the interleave only once */
-- status_OK = CMD(0x80);
-+ cmd_addr = adr & ~(map_bankwidth(map)-1);
-
-- timeo = jiffies + HZ;
-- retry:
- spin_lock(chip->mutex);
--
-- /* Check that the chip's ready to talk to us.
-- * If it's in FL_ERASING state, suspend it and make it talk now.
-- */
-- switch (chip->state) {
-- case FL_ERASING:
-- if (!cfi->cmdset_priv ||
-- !(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2))
-- goto sleep; /* We don't support erase suspend */
--
-- cfi_write (map, CMD(0xb0), cmd_addr);
-- /* If the flash has finished erasing, then 'erase suspend'
-- * appears to make some (28F320) flash devices switch to
-- * 'read' mode. Make sure that we switch to 'read status'
-- * mode so we get the right data. --rmk
-- */
-- cfi_write(map, CMD(0x70), cmd_addr);
-- chip->oldstate = FL_ERASING;
-- chip->state = FL_ERASE_SUSPENDING;
-- // printk("Erase suspending at 0x%lx\n", cmd_addr);
-- for (;;) {
-- status = cfi_read(map, cmd_addr);
-- if ((status & status_OK) == status_OK)
-- break;
--
-- if (time_after(jiffies, timeo)) {
-- /* Urgh */
-- cfi_write(map, CMD(0xd0), cmd_addr);
-- /* make sure we're in 'read status' mode */
-- cfi_write(map, CMD(0x70), cmd_addr);
-- chip->state = FL_ERASING;
-- spin_unlock(chip->mutex);
-- printk(KERN_ERR "Chip not ready after erase "
-- "suspended: status = 0x%llx\n", (__u64)status);
-- return -EIO;
-- }
--
-+ ret = get_chip(map, chip, cmd_addr, FL_READY);
-+ if (ret) {
- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-- spin_lock(chip->mutex);
-+ return ret;
- }
-
-- suspended = 1;
-- cfi_write(map, CMD(0xff), cmd_addr);
-- chip->state = FL_READY;
-- break;
--
--#if 0
-- case FL_WRITING:
-- /* Not quite yet */
--#endif
--
-- case FL_READY:
-- case FL_POINT:
-- break;
--
-- case FL_CFI_QUERY:
-- case FL_JEDEC_QUERY:
-- cfi_write(map, CMD(0x70), cmd_addr);
-- chip->state = FL_STATUS;
-+ if (chip->state != FL_POINT && chip->state != FL_READY) {
-+ map_write(map, CMD(0xff), cmd_addr);
-
-- case FL_STATUS:
-- status = cfi_read(map, cmd_addr);
-- if ((status & status_OK) == status_OK) {
-- cfi_write(map, CMD(0xff), cmd_addr);
- chip->state = FL_READY;
-- break;
- }
-
-- /* Urgh. Chip not yet ready to talk to us. */
-- if (time_after(jiffies, timeo)) {
-- spin_unlock(chip->mutex);
-- printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %llx\n", (__u64)status);
-- return -EIO;
-- }
--
-- /* Latency issues. Drop the lock, wait a while and retry */
-- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-- goto retry;
--
-- default:
-- sleep:
-- /* Stick ourselves on a wait queue to be woken when
-- someone changes the status */
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-- spin_unlock(chip->mutex);
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
-- timeo = jiffies + HZ;
-- goto retry;
-- }
--
-- map->copy_from(map, buf, adr, len);
-+ map_copy_from(map, buf, adr, len);
-
-- if (suspended) {
-- chip->state = chip->oldstate;
-- /* What if one interleaved chip has finished and the
-- other hasn't? The old code would leave the finished
-- one in READY mode. That's bad, and caused -EROFS
-- errors to be returned from do_erase_oneblock because
-- that's the only bit it checked for at the time.
-- As the state machine appears to explicitly allow
-- sending the 0x70 (Read Status) command to an erasing
-- chip and expecting it to be ignored, that's what we
-- do. */
-- cfi_write(map, CMD(0xd0), cmd_addr);
-- cfi_write(map, CMD(0x70), cmd_addr);
-- }
-+ put_chip(map, chip, cmd_addr);
-
-- wake_up(&chip->wq);
- spin_unlock(chip->mutex);
- return 0;
- }
-@@ -636,232 +1188,50 @@
- return ret;
- }
-
--static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz)
--{
-- struct map_info *map = mtd->priv;
-- struct cfi_private *cfi = map->fldrv_priv;
-- struct cfi_pri_intelext *extp=cfi->cmdset_priv;
-- int ofs_factor = cfi->interleave * cfi->device_type;
-- int count=len;
-- struct flchip *chip;
-- int chip_num,offst;
-- unsigned long timeo;
-- DECLARE_WAITQUEUE(wait, current);
--
-- chip=0;
-- /* Calculate which chip & protection register offset we need */
-- chip_num=((unsigned int)from/reg_sz);
-- offst=from-(reg_sz*chip_num)+base_offst;
--
-- while(count){
--
-- if(chip_num>=cfi->numchips)
-- goto out;
--
-- /* Make sure that the chip is in the right state */
--
-- timeo = jiffies + HZ;
-- chip=&cfi->chips[chip_num];
-- retry:
-- spin_lock(chip->mutex);
--
-- switch (chip->state) {
-- case FL_READY:
-- case FL_STATUS:
-- case FL_CFI_QUERY:
-- case FL_JEDEC_QUERY:
-- break;
--
-- default:
-- /* Stick ourselves on a wait queue to be woken when
-- someone changes the status */
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-- spin_unlock(chip->mutex);
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
-- timeo = jiffies + HZ;
-- goto retry;
-- }
--
-- /* Now read the data required from this flash */
--
-- cfi_send_gen_cmd(0x90, 0x55,chip->start, map, cfi, cfi->device_type, NULL);
-- while(count && ((offst-base_offst)<reg_sz)){
-- *buf=map->read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst));
-- buf++;
-- offst++;
-- count--;
-- }
--
-- chip->state=FL_CFI_QUERY;
-- spin_unlock(chip->mutex);
-- /* Move on to the next chip */
-- chip_num++;
-- offst=base_offst;
--
-- }
--
-- out:
-- wake_up(&chip->wq);
-- return len-count;
--}
--
--static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
--{
-- struct map_info *map = mtd->priv;
-- struct cfi_private *cfi = map->fldrv_priv;
-- struct cfi_pri_intelext *extp=cfi->cmdset_priv;
-- int base_offst,reg_sz;
--
-- /* Check that we actually have some protection registers */
-- if(!(extp->FeatureSupport&64)){
-- printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
-- return 0;
-- }
--
-- base_offst=(1<<extp->FactProtRegSize);
-- reg_sz=(1<<extp->UserProtRegSize);
--
-- return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
--}
--
--static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
--{
-- struct map_info *map = mtd->priv;
-- struct cfi_private *cfi = map->fldrv_priv;
-- struct cfi_pri_intelext *extp=cfi->cmdset_priv;
-- int base_offst,reg_sz;
--
-- /* Check that we actually have some protection registers */
-- if(!(extp->FeatureSupport&64)){
-- printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
-- return 0;
-- }
--
-- base_offst=0;
-- reg_sz=(1<<extp->FactProtRegSize);
--
-- return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
--}
--
--
--static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum)
-+static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
-+ unsigned long adr, map_word datum, int mode)
- {
- struct cfi_private *cfi = map->fldrv_priv;
-- struct cfi_pri_intelext *extp = cfi->cmdset_priv;
-- cfi_word status, status_OK;
-+ map_word status, status_OK, write_cmd;
- unsigned long timeo;
-- DECLARE_WAITQUEUE(wait, current);
-- int z, suspended=0, ret=0;
-+ int z, ret=0;
-
- adr += chip->start;
-
- /* Let's determine this according to the interleave only once */
- status_OK = CMD(0x80);
--
-- timeo = jiffies + HZ;
-- retry:
-- spin_lock(chip->mutex);
--
-- /* Check that the chip's ready to talk to us.
-- * Later, we can actually think about interrupting it
-- * if it's in FL_ERASING state.
-- * Not just yet, though.
-- */
-- switch (chip->state) {
-- case FL_READY:
-- break;
--
-- case FL_CFI_QUERY:
-- case FL_JEDEC_QUERY:
-- cfi_write(map, CMD(0x70), adr);
-- chip->state = FL_STATUS;
--
-- case FL_STATUS:
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-- break;
--
-- /* Urgh. Chip not yet ready to talk to us. */
-- if (time_after(jiffies, timeo)) {
-- spin_unlock(chip->mutex);
-- printk(KERN_ERR "waiting for chip to be ready timed out in read\n");
-- return -EIO;
-- }
--
-- /* Latency issues. Drop the lock, wait a while and retry */
-- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-- goto retry;
--
-- case FL_ERASING:
-- if (!extp ||
-- !((extp->FeatureSupport & 2) && (extp->SuspendCmdSupport & 1)))
-- goto sleep; /* We don't support erase suspend */
--
-- cfi_write (map, CMD(0xb0), adr);
--
-- /* If the flash has finished erasing, then 'erase suspend'
-- * appears to make some (28F320) flash devices switch to
-- * 'read' mode. Make sure that we switch to 'read status'
-- * mode so we get the right data. --rmk
-- */
-- cfi_write(map, CMD(0x70), adr);
-- chip->oldstate = FL_ERASING;
-- chip->state = FL_ERASE_SUSPENDING;
-- for (;;) {
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-- break;
--
-- if (time_after(jiffies, timeo)) {
-- /* Urgh */
-- cfi_write(map, CMD(0xd0), adr);
-- /* make sure we're in 'read status' mode */
-- cfi_write(map, CMD(0x70), adr);
-- chip->state = FL_ERASING;
-- spin_unlock(chip->mutex);
-- printk(KERN_ERR "Chip not ready after erase "
-- "suspended: status = 0x%x\n", status);
-- return -EIO;
-+ switch (mode) {
-+ case FL_WRITING: write_cmd = CMD(0x40); break;
-+ case FL_OTP_WRITE: write_cmd = CMD(0xc0); break;
-+ default: return -EINVAL;
- }
-
-- spin_unlock(chip->mutex);
-- cfi_udelay(1);
- spin_lock(chip->mutex);
-- }
-- suspended = 1;
-- chip->state = FL_STATUS;
-- break;
--
-- default:
-- sleep:
-- /* Stick ourselves on a wait queue to be woken when
-- someone changes the status */
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-+ ret = get_chip(map, chip, adr, mode);
-+ if (ret) {
- spin_unlock(chip->mutex);
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
-- timeo = jiffies + HZ;
-- goto retry;
-+ return ret;
- }
-
-+ XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
- ENABLE_VPP(map);
-- cfi_write(map, CMD(0x40), adr);
-- cfi_write(map, datum, adr);
-- chip->state = FL_WRITING;
-+ xip_disable(map, chip, adr);
-+ map_write(map, write_cmd, adr);
-+ map_write(map, datum, adr);
-+ chip->state = mode;
-
- spin_unlock(chip->mutex);
-- cfi_udelay(chip->word_write_time);
-+ INVALIDATE_CACHED_RANGE(map, adr, map_bankwidth(map));
-+ UDELAY(map, chip, adr, chip->word_write_time);
- spin_lock(chip->mutex);
-
- timeo = jiffies + (HZ/2);
- z = 0;
- for (;;) {
-- if (chip->state != FL_WRITING) {
-+ if (chip->state != mode) {
- /* Someone's suspended the write. Sleep */
-+ DECLARE_WAITQUEUE(wait, current);
-+
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
- spin_unlock(chip->mutex);
-@@ -872,14 +1242,14 @@
- continue;
- }
-
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-+ status = map_read(map, adr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- /* OK Still waiting */
- if (time_after(jiffies, timeo)) {
- chip->state = FL_STATUS;
-- DISABLE_VPP(map);
-+ xip_enable(map, chip, adr);
- printk(KERN_ERR "waiting for chip to be ready timed out in word write\n");
- ret = -EIO;
- goto out;
-@@ -888,7 +1258,7 @@
- /* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
- z++;
-- cfi_udelay(1);
-+ UDELAY(map, chip, adr, 1);
- spin_lock(chip->mutex);
- }
- if (!z) {
-@@ -901,34 +1271,20 @@
-
- /* Done and happy. */
- chip->state = FL_STATUS;
-+
- /* check for lock bit */
-- if (status & CMD(0x02)) {
-+ if (map_word_bitsset(map, status, CMD(0x02))) {
- /* clear status */
-- cfi_write(map, CMD(0x50), adr);
-+ map_write(map, CMD(0x50), adr);
- /* put back into read status register mode */
-- cfi_write(map, CMD(0x70), adr);
-+ map_write(map, CMD(0x70), adr);
- ret = -EROFS;
-- goto out;
- }
-- out:
-- if (suspended) {
-- chip->state = chip->oldstate;
-- /* What if one interleaved chip has finished and the
-- other hasn't? The old code would leave the finished
-- one in READY mode. That's bad, and caused -EROFS
-- errors to be returned from do_erase_oneblock because
-- that's the only bit it checked for at the time.
-- As the state machine appears to explicitly allow
-- sending the 0x70 (Read Status) command to an erasing
-- chip and expecting it to be ignored, that's what we
-- do. */
-- cfi_write(map, CMD(0xd0), adr);
-- cfi_write(map, CMD(0x70), adr);
-- } else
-- DISABLE_VPP(map); /* must not clear the VPP if there is a suspended erase to be resumed */
-
-- wake_up(&chip->wq);
-+ xip_enable(map, chip, adr);
-+ out: put_chip(map, chip, adr);
- spin_unlock(chip->mutex);
-+
- return ret;
- }
-
-@@ -949,35 +1305,22 @@
- ofs = to - (chipnum << cfi->chipshift);
-
- /* If it's not bus-aligned, do the first byte write */
-- if (ofs & (CFIDEV_BUSWIDTH-1)) {
-- unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);
-+ if (ofs & (map_bankwidth(map)-1)) {
-+ unsigned long bus_ofs = ofs & ~(map_bankwidth(map)-1);
- int gap = ofs - bus_ofs;
-- int i = 0, n = 0;
-- u_char tmp_buf[8];
-- cfi_word datum;
--
-- while (gap--)
-- tmp_buf[i++] = 0xff;
-- while (len && i < CFIDEV_BUSWIDTH)
-- tmp_buf[i++] = buf[n++], len--;
-- while (i < CFIDEV_BUSWIDTH)
-- tmp_buf[i++] = 0xff;
-+ int n;
-+ map_word datum;
-
-- if (cfi_buswidth_is_2()) {
-- datum = *(__u16*)tmp_buf;
-- } else if (cfi_buswidth_is_4()) {
-- datum = *(__u32*)tmp_buf;
-- } else if (cfi_buswidth_is_8()) {
-- datum = *(__u64*)tmp_buf;
-- } else {
-- return -EINVAL; /* should never happen, but be safe */
-- }
-+ n = min_t(int, len, map_bankwidth(map)-gap);
-+ datum = map_word_ff(map);
-+ datum = map_word_load_partial(map, datum, buf, gap, n);
-
- ret = do_write_oneword(map, &cfi->chips[chipnum],
-- bus_ofs, datum);
-+ bus_ofs, datum, FL_WRITING);
- if (ret)
- return ret;
-
-+ len -= n;
- ofs += n;
- buf += n;
- (*retlen) += n;
-@@ -990,30 +1333,18 @@
- }
- }
-
-- while(len >= CFIDEV_BUSWIDTH) {
-- cfi_word datum;
--
-- if (cfi_buswidth_is_1()) {
-- datum = *(__u8*)buf;
-- } else if (cfi_buswidth_is_2()) {
-- datum = *(__u16*)buf;
-- } else if (cfi_buswidth_is_4()) {
-- datum = *(__u32*)buf;
-- } else if (cfi_buswidth_is_8()) {
-- datum = *(__u64*)buf;
-- } else {
-- return -EINVAL;
-- }
-+ while(len >= map_bankwidth(map)) {
-+ map_word datum = map_word_load(map, buf);
-
- ret = do_write_oneword(map, &cfi->chips[chipnum],
-- ofs, datum);
-+ ofs, datum, FL_WRITING);
- if (ret)
- return ret;
-
-- ofs += CFIDEV_BUSWIDTH;
-- buf += CFIDEV_BUSWIDTH;
-- (*retlen) += CFIDEV_BUSWIDTH;
-- len -= CFIDEV_BUSWIDTH;
-+ ofs += map_bankwidth(map);
-+ buf += map_bankwidth(map);
-+ (*retlen) += map_bankwidth(map);
-+ len -= map_bankwidth(map);
-
- if (ofs >> cfi->chipshift) {
- chipnum ++;
-@@ -1023,203 +1354,126 @@
- }
- }
-
-- if (len & (CFIDEV_BUSWIDTH-1)) {
-- int i = 0, n = 0;
-- u_char tmp_buf[8];
-- cfi_word datum;
--
-- while (len--)
-- tmp_buf[i++] = buf[n++];
-- while (i < CFIDEV_BUSWIDTH)
-- tmp_buf[i++] = 0xff;
-+ if (len & (map_bankwidth(map)-1)) {
-+ map_word datum;
-
-- if (cfi_buswidth_is_2()) {
-- datum = *(__u16*)tmp_buf;
-- } else if (cfi_buswidth_is_4()) {
-- datum = *(__u32*)tmp_buf;
-- } else if (cfi_buswidth_is_8()) {
-- datum = *(__u64*)tmp_buf;
-- } else {
-- return -EINVAL; /* should never happen, but be safe */
-- }
-+ datum = map_word_ff(map);
-+ datum = map_word_load_partial(map, datum, buf, 0, len);
-
- ret = do_write_oneword(map, &cfi->chips[chipnum],
-- ofs, datum);
-+ ofs, datum, FL_WRITING);
- if (ret)
- return ret;
-
-- (*retlen) += n;
-+ (*retlen) += len;
- }
-
- return 0;
- }
-
-
--static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
-+static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
- unsigned long adr, const u_char *buf, int len)
- {
- struct cfi_private *cfi = map->fldrv_priv;
-- struct cfi_pri_intelext *extp = cfi->cmdset_priv;
-- cfi_word status, status_OK;
-+ map_word status, status_OK;
- unsigned long cmd_adr, timeo;
-- DECLARE_WAITQUEUE(wait, current);
-- int wbufsize, z, suspended=0, ret=0;
-+ int wbufsize, z, ret=0, bytes, words;
-
-- wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
-+ wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
- adr += chip->start;
- cmd_adr = adr & ~(wbufsize-1);
-
- /* Let's determine this according to the interleave only once */
- status_OK = CMD(0x80);
-
-- timeo = jiffies + HZ;
-- retry:
- spin_lock(chip->mutex);
--
-- /* Check that the chip's ready to talk to us.
-- * Later, we can actually think about interrupting it
-- * if it's in FL_ERASING state.
-- * Not just yet, though.
-- */
-- switch (chip->state) {
-- case FL_READY:
-- case FL_CFI_QUERY:
-- case FL_JEDEC_QUERY:
-- cfi_write(map, CMD(0x70), cmd_adr);
-- chip->state = FL_STATUS;
--
-- case FL_STATUS:
-- status = cfi_read(map, cmd_adr);
-- if ((status & status_OK) == status_OK)
-- break;
-- /* Urgh. Chip not yet ready to talk to us. */
-- if (time_after(jiffies, timeo)) {
-- spin_unlock(chip->mutex);
-- printk(KERN_ERR "waiting for chip to be ready timed out in buffer write\n");
-- return -EIO;
-- }
--
-- /* Latency issues. Drop the lock, wait a while and retry */
-- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-- goto retry;
--
-- case FL_ERASING:
-- if (!extp ||
-- !((extp->FeatureSupport & 2) && (extp->SuspendCmdSupport & 1)))
-- goto sleep; /* We don't support erase suspend */
--
-- cfi_write (map, CMD(0xb0), adr);
--
-- /* If the flash has finished erasing, then 'erase suspend'
-- * appears to make some (28F320) flash devices switch to
-- * 'read' mode. Make sure that we switch to 'read status'
-- * mode so we get the right data. --rmk
-- */
-- cfi_write(map, CMD(0x70), adr);
-- chip->oldstate = FL_ERASING;
-- chip->state = FL_ERASE_SUSPENDING;
-- for (;;) {
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-- break;
--
-- if (time_after(jiffies, timeo)) {
-- /* Urgh */
-- cfi_write(map, CMD(0xd0), adr);
-- /* make sure we're in 'read status' mode */
-- cfi_write(map, CMD(0x70), adr);
-- chip->state = FL_ERASING;
-+ ret = get_chip(map, chip, cmd_adr, FL_WRITING);
-+ if (ret) {
- spin_unlock(chip->mutex);
-- printk(KERN_ERR "Chip not ready after erase "
-- "suspended: status = 0x%x\n", status);
-- return -EIO;
-+ return ret;
- }
-
-- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-- spin_lock(chip->mutex);
-- }
-- suspended = 1;
-- chip->state = FL_STATUS;
-- break;
-+ XIP_INVAL_CACHED_RANGE(map, adr, len);
-+ ENABLE_VPP(map);
-+ xip_disable(map, chip, cmd_adr);
-
-- default:
-- sleep:
-- /* Stick ourselves on a wait queue to be woken when
-- someone changes the status */
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-- spin_unlock(chip->mutex);
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
-- timeo = jiffies + HZ;
-- goto retry;
-- }
-- /* We know we're now in FL_STATUS mode, and 'status' is current */
- /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set
- [...], the device will not accept any more Write to Buffer commands".
- So we must check here and reset those bits if they're set. Otherwise
- we're just pissing in the wind */
-- if (status & CMD(0x30)) {
-- printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %x). Clearing.\n", status);
-- cfi_write(map, CMD(0x50), cmd_adr);
-- cfi_write(map, CMD(0x70), cmd_adr);
-+ if (chip->state != FL_STATUS)
-+ map_write(map, CMD(0x70), cmd_adr);
-+ status = map_read(map, cmd_adr);
-+ if (map_word_bitsset(map, status, CMD(0x30))) {
-+ xip_enable(map, chip, cmd_adr);
-+ printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %lx). Clearing.\n", status.x[0]);
-+ xip_disable(map, chip, cmd_adr);
-+ map_write(map, CMD(0x50), cmd_adr);
-+ map_write(map, CMD(0x70), cmd_adr);
- }
-- ENABLE_VPP(map);
-+
- chip->state = FL_WRITING_TO_BUFFER;
-
- z = 0;
- for (;;) {
-- cfi_write(map, CMD(0xe8), cmd_adr);
-+ map_write(map, CMD(0xe8), cmd_adr);
-
-- status = cfi_read(map, cmd_adr);
-- if ((status & status_OK) == status_OK)
-+ status = map_read(map, cmd_adr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-+ UDELAY(map, chip, cmd_adr, 1);
- spin_lock(chip->mutex);
-
- if (++z > 20) {
- /* Argh. Not ready for write to buffer */
-- cfi_write(map, CMD(0x70), cmd_adr);
-+ map_word Xstatus;
-+ map_write(map, CMD(0x70), cmd_adr);
- chip->state = FL_STATUS;
-- DISABLE_VPP(map);
-- printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %llx, status = %llx\n", (__u64)status, (__u64)cfi_read(map, cmd_adr));
-+ Xstatus = map_read(map, cmd_adr);
- /* Odd. Clear status bits */
-- cfi_write(map, CMD(0x50), cmd_adr);
-- cfi_write(map, CMD(0x70), cmd_adr);
-+ map_write(map, CMD(0x50), cmd_adr);
-+ map_write(map, CMD(0x70), cmd_adr);
-+ xip_enable(map, chip, cmd_adr);
-+ printk(KERN_ERR "Chip not ready for buffer write. status = %lx, Xstatus = %lx\n",
-+ status.x[0], Xstatus.x[0]);
- ret = -EIO;
- goto out;
- }
- }
-
- /* Write length of data to come */
-- cfi_write(map, CMD(len/CFIDEV_BUSWIDTH-1), cmd_adr );
-+ bytes = len & (map_bankwidth(map)-1);
-+ words = len / map_bankwidth(map);
-+ map_write(map, CMD(words - !bytes), cmd_adr );
-
- /* Write data */
-- for (z = 0; z < len; z += CFIDEV_BUSWIDTH) {
-- if (cfi_buswidth_is_1()) {
-- map->write8 (map, *((__u8*)buf)++, adr+z);
-- } else if (cfi_buswidth_is_2()) {
-- map->write16 (map, *((__u16*)buf)++, adr+z);
-- } else if (cfi_buswidth_is_4()) {
-- map->write32 (map, *((__u32*)buf)++, adr+z);
-- } else if (cfi_buswidth_is_8()) {
-- map->write64 (map, *((__u64*)buf)++, adr+z);
-- } else {
-- DISABLE_VPP(map);
-- ret = -EINVAL;
-- goto out;
-+ z = 0;
-+ while(z < words * map_bankwidth(map)) {
-+ map_word datum = map_word_load(map, buf);
-+ map_write(map, datum, adr+z);
-+
-+ z += map_bankwidth(map);
-+ buf += map_bankwidth(map);
- }
-+
-+ if (bytes) {
-+ map_word datum;
-+
-+ datum = map_word_ff(map);
-+ datum = map_word_load_partial(map, datum, buf, 0, bytes);
-+ map_write(map, datum, adr+z);
- }
-+
- /* GO GO GO */
-- cfi_write(map, CMD(0xd0), cmd_adr);
-+ map_write(map, CMD(0xd0), cmd_adr);
- chip->state = FL_WRITING;
-
- spin_unlock(chip->mutex);
-- cfi_udelay(chip->buffer_write_time);
-+ INVALIDATE_CACHED_RANGE(map, adr, len);
-+ UDELAY(map, chip, cmd_adr, chip->buffer_write_time);
- spin_lock(chip->mutex);
-
- timeo = jiffies + (HZ/2);
-@@ -1227,6 +1481,7 @@
- for (;;) {
- if (chip->state != FL_WRITING) {
- /* Someone's suspended the write. Sleep */
-+ DECLARE_WAITQUEUE(wait, current);
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
- spin_unlock(chip->mutex);
-@@ -1237,14 +1492,14 @@
- continue;
- }
-
-- status = cfi_read(map, cmd_adr);
-- if ((status & status_OK) == status_OK)
-+ status = map_read(map, cmd_adr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- /* OK Still waiting */
- if (time_after(jiffies, timeo)) {
- chip->state = FL_STATUS;
-- DISABLE_VPP(map);
-+ xip_enable(map, chip, cmd_adr);
- printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n");
- ret = -EIO;
- goto out;
-@@ -1252,7 +1507,7 @@
-
- /* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-+ UDELAY(map, chip, cmd_adr, 1);
- z++;
- spin_lock(chip->mutex);
- }
-@@ -1266,33 +1521,18 @@
-
- /* Done and happy. */
- chip->state = FL_STATUS;
-+
- /* check for lock bit */
-- if (status & CMD(0x02)) {
-+ if (map_word_bitsset(map, status, CMD(0x02))) {
- /* clear status */
-- cfi_write(map, CMD(0x50), cmd_adr);
-+ map_write(map, CMD(0x50), cmd_adr);
- /* put back into read status register mode */
-- cfi_write(map, CMD(0x70), adr);
-+ map_write(map, CMD(0x70), adr);
- ret = -EROFS;
-- goto out;
- }
-- out:
-- if (suspended) {
-- chip->state = chip->oldstate;
-- /* What if one interleaved chip has finished and the
-- other hasn't? The old code would leave the finished
-- one in READY mode. That's bad, and caused -EROFS
-- errors to be returned from do_erase_oneblock because
-- that's the only bit it checked for at the time.
-- As the state machine appears to explicitly allow
-- sending the 0x70 (Read Status) command to an erasing
-- chip and expecting it to be ignored, that's what we
-- do. */
-- cfi_write(map, CMD(0xd0), adr);
-- cfi_write(map, CMD(0x70), adr);
-- } else
-- DISABLE_VPP(map); /* must not clear the VPP if there is a suspended erase to be resumed */
-
-- wake_up(&chip->wq);
-+ xip_enable(map, chip, cmd_adr);
-+ out: put_chip(map, chip, cmd_adr);
- spin_unlock(chip->mutex);
- return ret;
- }
-@@ -1302,7 +1542,7 @@
- {
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
-- int wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
-+ int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
- int ret = 0;
- int chipnum;
- unsigned long ofs;
-@@ -1315,8 +1555,8 @@
- ofs = to - (chipnum << cfi->chipshift);
-
- /* If it's not bus-aligned, do the first word write */
-- if (ofs & (CFIDEV_BUSWIDTH-1)) {
-- size_t local_len = (-ofs)&(CFIDEV_BUSWIDTH-1);
-+ if (ofs & (map_bankwidth(map)-1)) {
-+ size_t local_len = (-ofs)&(map_bankwidth(map)-1);
- if (local_len > len)
- local_len = len;
- ret = cfi_intelext_write_words(mtd, to, local_len,
-@@ -1335,13 +1575,12 @@
- }
- }
-
-- /* Write buffer is worth it only if more than one word to write... */
-- while(len > CFIDEV_BUSWIDTH) {
-+ while(len) {
- /* We must not cross write block boundaries */
- int size = wbufsize - (ofs & (wbufsize-1));
-
- if (size > len)
-- size = len & ~(CFIDEV_BUSWIDTH-1);
-+ size = len;
- ret = do_write_buffer(map, &cfi->chips[chipnum],
- ofs, buf, size);
- if (ret)
-@@ -1359,116 +1598,14 @@
- return 0;
- }
- }
--
-- /* ... and write the remaining bytes */
-- if (len > 0) {
-- size_t local_retlen;
-- ret = cfi_intelext_write_words(mtd, ofs + (chipnum << cfi->chipshift),
-- len, &local_retlen, buf);
-- if (ret)
-- return ret;
-- (*retlen) += local_retlen;
-- }
--
- return 0;
- }
-
--typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip,
-- unsigned long adr, void *thunk);
--
--static int cfi_intelext_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
-- loff_t ofs, size_t len, void *thunk)
--{
-- struct map_info *map = mtd->priv;
-- struct cfi_private *cfi = map->fldrv_priv;
-- unsigned long adr;
-- int chipnum, ret = 0;
-- int i, first;
-- struct mtd_erase_region_info *regions = mtd->eraseregions;
--
-- if (ofs > mtd->size)
-- return -EINVAL;
--
-- if ((len + ofs) > mtd->size)
-- return -EINVAL;
--
-- /* Check that both start and end of the requested erase are
-- * aligned with the erasesize at the appropriate addresses.
-- */
--
-- i = 0;
--
-- /* Skip all erase regions which are ended before the start of
-- the requested erase. Actually, to save on the calculations,
-- we skip to the first erase region which starts after the
-- start of the requested erase, and then go back one.
-- */
--
-- while (i < mtd->numeraseregions && ofs >= regions[i].offset)
-- i++;
-- i--;
--
-- /* OK, now i is pointing at the erase region in which this
-- erase request starts. Check the start of the requested
-- erase range is aligned with the erase size which is in
-- effect here.
-- */
--
-- if (ofs & (regions[i].erasesize-1))
-- return -EINVAL;
--
-- /* Remember the erase region we start on */
-- first = i;
--
-- /* Next, check that the end of the requested erase is aligned
-- * with the erase region at that address.
-- */
--
-- while (i<mtd->numeraseregions && (ofs + len) >= regions[i].offset)
-- i++;
--
-- /* As before, drop back one to point at the region in which
-- the address actually falls
-- */
-- i--;
--
-- if ((ofs + len) & (regions[i].erasesize-1))
-- return -EINVAL;
--
-- chipnum = ofs >> cfi->chipshift;
-- adr = ofs - (chipnum << cfi->chipshift);
--
-- i=first;
--
-- while(len) {
-- ret = (*frob)(map, &cfi->chips[chipnum], adr, thunk);
--
-- if (ret)
-- return ret;
--
-- adr += regions[i].erasesize;
-- len -= regions[i].erasesize;
--
-- if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
-- i++;
--
-- if (adr >> cfi->chipshift) {
-- adr = 0;
-- chipnum++;
--
-- if (chipnum >= cfi->numchips)
-- break;
-- }
-- }
--
-- return 0;
--}
--
--
--static int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
-+static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
-+ unsigned long adr, int len, void *thunk)
- {
- struct cfi_private *cfi = map->fldrv_priv;
-- cfi_word status, status_OK;
-+ map_word status, status_OK;
- unsigned long timeo;
- int retries = 3;
- DECLARE_WAITQUEUE(wait, current);
-@@ -1479,60 +1616,30 @@
- /* Let's determine this according to the interleave only once */
- status_OK = CMD(0x80);
-
-- timeo = jiffies + HZ;
--retry:
-+ retry:
- spin_lock(chip->mutex);
--
-- /* Check that the chip's ready to talk to us. */
-- switch (chip->state) {
-- case FL_CFI_QUERY:
-- case FL_JEDEC_QUERY:
-- case FL_READY:
-- cfi_write(map, CMD(0x70), adr);
-- chip->state = FL_STATUS;
--
-- case FL_STATUS:
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-- break;
--
-- /* Urgh. Chip not yet ready to talk to us. */
-- if (time_after(jiffies, timeo)) {
-- spin_unlock(chip->mutex);
-- printk(KERN_ERR "waiting for chip to be ready timed out in erase\n");
-- return -EIO;
-- }
--
-- /* Latency issues. Drop the lock, wait a while and retry */
-- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-- goto retry;
--
-- default:
-- /* Stick ourselves on a wait queue to be woken when
-- someone changes the status */
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-+ ret = get_chip(map, chip, adr, FL_ERASING);
-+ if (ret) {
- spin_unlock(chip->mutex);
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
-- timeo = jiffies + HZ;
-- goto retry;
-+ return ret;
- }
-
-+ XIP_INVAL_CACHED_RANGE(map, adr, len);
- ENABLE_VPP(map);
-+ xip_disable(map, chip, adr);
-+
- /* Clear the status register first */
-- cfi_write(map, CMD(0x50), adr);
-+ map_write(map, CMD(0x50), adr);
-
- /* Now erase */
-- cfi_write(map, CMD(0x20), adr);
-- cfi_write(map, CMD(0xD0), adr);
-+ map_write(map, CMD(0x20), adr);
-+ map_write(map, CMD(0xD0), adr);
- chip->state = FL_ERASING;
-- chip->oldstate = 0;
-+ chip->erase_suspended = 0;
-
- spin_unlock(chip->mutex);
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- schedule_timeout((chip->erase_time*HZ)/(2*1000));
-+ INVALIDATE_CACHED_RANGE(map, adr, len);
-+ UDELAY(map, chip, adr, chip->erase_time*1000/2);
- spin_lock(chip->mutex);
-
- /* FIXME. Use a timer to check this, and return immediately. */
-@@ -1550,84 +1657,92 @@
- spin_lock(chip->mutex);
- continue;
- }
-- if (chip->oldstate) {
-+ if (chip->erase_suspended) {
- /* This erase was suspended and resumed.
- Adjust the timeout */
- timeo = jiffies + (HZ*20); /* FIXME */
-- chip->oldstate = 0;
-+ chip->erase_suspended = 0;
- }
-
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-+ status = map_read(map, adr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- /* OK Still waiting */
- if (time_after(jiffies, timeo)) {
-- cfi_write(map, CMD(0x70), adr);
-+ map_word Xstatus;
-+ map_write(map, CMD(0x70), adr);
- chip->state = FL_STATUS;
-- printk(KERN_ERR "waiting for erase at %08lx to complete timed out. Xstatus = %llx, status = %llx.\n",
-- adr, (__u64)status, (__u64)cfi_read(map, adr));
-+ Xstatus = map_read(map, adr);
- /* Clear status bits */
-- cfi_write(map, CMD(0x50), adr);
-- cfi_write(map, CMD(0x70), adr);
-- DISABLE_VPP(map);
-- spin_unlock(chip->mutex);
-- return -EIO;
-+ map_write(map, CMD(0x50), adr);
-+ map_write(map, CMD(0x70), adr);
-+ xip_enable(map, chip, adr);
-+ printk(KERN_ERR "waiting for erase at %08lx to complete timed out. status = %lx, Xstatus = %lx.\n",
-+ adr, status.x[0], Xstatus.x[0]);
-+ ret = -EIO;
-+ goto out;
- }
-
- /* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- schedule_timeout(1);
-+ UDELAY(map, chip, adr, 1000000/HZ);
- spin_lock(chip->mutex);
- }
-
-- DISABLE_VPP(map);
-- ret = 0;
--
- /* We've broken this before. It doesn't hurt to be safe */
-- cfi_write(map, CMD(0x70), adr);
-+ map_write(map, CMD(0x70), adr);
- chip->state = FL_STATUS;
-- status = cfi_read(map, adr);
-+ status = map_read(map, adr);
-
- /* check for lock bit */
-- if (status & CMD(0x3a)) {
-- unsigned char chipstatus = status;
-- if (status != CMD(status & 0xff)) {
-- int i;
-- for (i = 1; i<CFIDEV_INTERLEAVE; i++) {
-- chipstatus |= status >> (cfi->device_type * 8);
-+ if (map_word_bitsset(map, status, CMD(0x3a))) {
-+ unsigned char chipstatus;
-+
-+ /* Reset the error bits */
-+ map_write(map, CMD(0x50), adr);
-+ map_write(map, CMD(0x70), adr);
-+ xip_enable(map, chip, adr);
-+
-+ chipstatus = status.x[0];
-+ if (!map_word_equal(map, status, CMD(chipstatus))) {
-+ int i, w;
-+ for (w=0; w<map_words(map); w++) {
-+ for (i = 0; i<cfi_interleave(cfi); i++) {
-+ chipstatus |= status.x[w] >> (cfi->device_type * 8);
- }
-- printk(KERN_WARNING "Status is not identical for all chips: 0x%llx. Merging to give 0x%02x\n", (__u64)status, chipstatus);
- }
-- /* Reset the error bits */
-- cfi_write(map, CMD(0x50), adr);
-- cfi_write(map, CMD(0x70), adr);
-+ printk(KERN_WARNING "Status is not identical for all chips: 0x%lx. Merging to give 0x%02x\n",
-+ status.x[0], chipstatus);
-+ }
-
- if ((chipstatus & 0x30) == 0x30) {
-- printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%llx\n", (__u64)status);
-+ printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus);
- ret = -EIO;
- } else if (chipstatus & 0x02) {
- /* Protection bit set */
- ret = -EROFS;
- } else if (chipstatus & 0x8) {
- /* Voltage */
-- printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%llx\n", (__u64)status);
-+ printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", chipstatus);
- ret = -EIO;
- } else if (chipstatus & 0x20) {
- if (retries--) {
-- printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%llx. Retrying...\n", adr, (__u64)status);
-+ printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, chipstatus);
- timeo = jiffies + HZ;
-- chip->state = FL_STATUS;
-+ put_chip(map, chip, adr);
- spin_unlock(chip->mutex);
- goto retry;
- }
-- printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%llx\n", adr, (__u64)status);
-+ printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, chipstatus);
- ret = -EIO;
- }
-+ } else {
-+ xip_enable(map, chip, adr);
-+ ret = 0;
- }
-
-- wake_up(&chip->wq);
-+ out: put_chip(map, chip, adr);
- spin_unlock(chip->mutex);
- return ret;
- }
-@@ -1640,13 +1755,12 @@
- ofs = instr->addr;
- len = instr->len;
-
-- ret = cfi_intelext_varsize_frob(mtd, do_erase_oneblock, ofs, len, 0);
-+ ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL);
- if (ret)
- return ret;
-
- instr->state = MTD_ERASE_DONE;
-- if (instr->callback)
-- instr->callback(instr);
-+ mtd_erase_callback(instr);
-
- return 0;
- }
-@@ -1658,39 +1772,22 @@
- int i;
- struct flchip *chip;
- int ret = 0;
-- DECLARE_WAITQUEUE(wait, current);
-
- for (i=0; !ret && i<cfi->numchips; i++) {
- chip = &cfi->chips[i];
-
-- retry:
- spin_lock(chip->mutex);
-+ ret = get_chip(map, chip, chip->start, FL_SYNCING);
-
-- switch(chip->state) {
-- case FL_READY:
-- case FL_STATUS:
-- case FL_CFI_QUERY:
-- case FL_JEDEC_QUERY:
-+ if (!ret) {
- chip->oldstate = chip->state;
- chip->state = FL_SYNCING;
- /* No need to wake_up() on this state change -
- * as the whole point is that nobody can do anything
- * with the chip now anyway.
- */
-- case FL_SYNCING:
-- spin_unlock(chip->mutex);
-- break;
--
-- default:
-- /* Not an idle state */
-- add_wait_queue(&chip->wq, &wait);
--
-- spin_unlock(chip->mutex);
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
--
-- goto retry;
- }
-+ spin_unlock(chip->mutex);
- }
-
- /* Unlock the chips again */
-@@ -1709,16 +1806,21 @@
- }
-
- #ifdef DEBUG_LOCK_BITS
--static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
-+static int __xipram do_printlockstatus_oneblock(struct map_info *map,
-+ struct flchip *chip,
-+ unsigned long adr,
-+ int len, void *thunk)
- {
- struct cfi_private *cfi = map->fldrv_priv;
-- int ofs_factor = cfi->interleave * cfi->device_type;
-+ int status, ofs_factor = cfi->interleave * cfi->device_type;
-
-+ xip_disable(map, chip, adr+(2*ofs_factor));
- cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
-+ chip->state = FL_JEDEC_QUERY;
-+ status = cfi_read_query(map, adr+(2*ofs_factor));
-+ xip_enable(map, chip, 0);
- printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
-- adr, cfi_read_query(map, adr+(2*ofs_factor)));
-- cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
--
-+ adr, status);
- return 0;
- }
- #endif
-@@ -1726,73 +1828,41 @@
- #define DO_XXLOCK_ONEBLOCK_LOCK ((void *) 1)
- #define DO_XXLOCK_ONEBLOCK_UNLOCK ((void *) 2)
-
--static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
-+static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip,
-+ unsigned long adr, int len, void *thunk)
- {
- struct cfi_private *cfi = map->fldrv_priv;
-- cfi_word status, status_OK;
-+ map_word status, status_OK;
- unsigned long timeo = jiffies + HZ;
-- DECLARE_WAITQUEUE(wait, current);
-+ int ret;
-
- adr += chip->start;
-
- /* Let's determine this according to the interleave only once */
- status_OK = CMD(0x80);
-
-- timeo = jiffies + HZ;
--retry:
- spin_lock(chip->mutex);
--
-- /* Check that the chip's ready to talk to us. */
-- switch (chip->state) {
-- case FL_CFI_QUERY:
-- case FL_JEDEC_QUERY:
-- case FL_READY:
-- cfi_write(map, CMD(0x70), adr);
-- chip->state = FL_STATUS;
--
-- case FL_STATUS:
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-- break;
--
-- /* Urgh. Chip not yet ready to talk to us. */
-- if (time_after(jiffies, timeo)) {
-- spin_unlock(chip->mutex);
-- printk(KERN_ERR "%s: waiting for chip to be ready timed out\n", __FUNCTION__);
-- return -EIO;
-- }
--
-- /* Latency issues. Drop the lock, wait a while and retry */
-- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-- goto retry;
--
-- default:
-- /* Stick ourselves on a wait queue to be woken when
-- someone changes the status */
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-+ ret = get_chip(map, chip, adr, FL_LOCKING);
-+ if (ret) {
- spin_unlock(chip->mutex);
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
-- timeo = jiffies + HZ;
-- goto retry;
-+ return ret;
- }
-
- ENABLE_VPP(map);
-- cfi_write(map, CMD(0x60), adr);
-+ xip_disable(map, chip, adr);
-
-+ map_write(map, CMD(0x60), adr);
- if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) {
-- cfi_write(map, CMD(0x01), adr);
-+ map_write(map, CMD(0x01), adr);
- chip->state = FL_LOCKING;
- } else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) {
-- cfi_write(map, CMD(0xD0), adr);
-+ map_write(map, CMD(0xD0), adr);
- chip->state = FL_UNLOCKING;
- } else
- BUG();
-
- spin_unlock(chip->mutex);
-- schedule_timeout(HZ);
-+ UDELAY(map, chip, adr, 1000000/HZ);
- spin_lock(chip->mutex);
-
- /* FIXME. Use a timer to check this, and return immediately. */
-@@ -1801,30 +1871,34 @@
- timeo = jiffies + (HZ*20);
- for (;;) {
-
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-+ status = map_read(map, adr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- /* OK Still waiting */
- if (time_after(jiffies, timeo)) {
-- cfi_write(map, CMD(0x70), adr);
-+ map_word Xstatus;
-+ map_write(map, CMD(0x70), adr);
- chip->state = FL_STATUS;
-- printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %llx, status = %llx.\n", (__u64)status, (__u64)cfi_read(map, adr));
-- DISABLE_VPP(map);
-+ Xstatus = map_read(map, adr);
-+ xip_enable(map, chip, adr);
-+ printk(KERN_ERR "waiting for unlock to complete timed out. status = %lx, Xstatus = %lx.\n",
-+ status.x[0], Xstatus.x[0]);
-+ put_chip(map, chip, adr);
- spin_unlock(chip->mutex);
- return -EIO;
- }
-
- /* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-+ UDELAY(map, chip, adr, 1);
- spin_lock(chip->mutex);
- }
-
- /* Done and happy. */
- chip->state = FL_STATUS;
-- DISABLE_VPP(map);
-- wake_up(&chip->wq);
-+ xip_enable(map, chip, adr);
-+ put_chip(map, chip, adr);
- spin_unlock(chip->mutex);
- return 0;
- }
-@@ -1836,17 +1910,17 @@
- #ifdef DEBUG_LOCK_BITS
- printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
- __FUNCTION__, ofs, len);
-- cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
-+ cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
- ofs, len, 0);
- #endif
-
-- ret = cfi_intelext_varsize_frob(mtd, do_xxlock_oneblock,
-+ ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
- ofs, len, DO_XXLOCK_ONEBLOCK_LOCK);
-
- #ifdef DEBUG_LOCK_BITS
-- printk(KERN_DEBUG __FUNCTION__
-- "%s: lock status after, ret=%d\n", __FUNCTION__, ret);
-- cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
-+ printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
-+ __FUNCTION__, ret);
-+ cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
- ofs, len, 0);
- #endif
-
-@@ -1860,22 +1934,281 @@
- #ifdef DEBUG_LOCK_BITS
- printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
- __FUNCTION__, ofs, len);
-- cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
-+ cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
- ofs, len, 0);
- #endif
-
-- ret = cfi_intelext_varsize_frob(mtd, do_xxlock_oneblock,
-+ ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
- ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK);
-
- #ifdef DEBUG_LOCK_BITS
-- printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __FUNCTION__, ret);
-- cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
-+ printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
-+ __FUNCTION__, ret);
-+ cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
- ofs, len, 0);
- #endif
-
- return ret;
- }
-
-+#ifdef CONFIG_MTD_OTP
-+
-+typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip,
-+ u_long data_offset, u_char *buf, u_int size,
-+ u_long prot_offset, u_int groupno, u_int groupsize);
-+
-+static int __xipram
-+do_otp_read(struct map_info *map, struct flchip *chip, u_long offset,
-+ u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ int ret;
-+
-+ spin_lock(chip->mutex);
-+ ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
-+ if (ret) {
-+ spin_unlock(chip->mutex);
-+ return ret;
-+ }
-+
-+ /* let's ensure we're not reading back cached data from array mode */
-+ if (map->inval_cache)
-+ map->inval_cache(map, chip->start + offset, size);
-+
-+ xip_disable(map, chip, chip->start);
-+ if (chip->state != FL_JEDEC_QUERY) {
-+ map_write(map, CMD(0x90), chip->start);
-+ chip->state = FL_JEDEC_QUERY;
-+ }
-+ map_copy_from(map, buf, chip->start + offset, size);
-+ xip_enable(map, chip, chip->start);
-+
-+ /* then ensure we don't keep OTP data in the cache */
-+ if (map->inval_cache)
-+ map->inval_cache(map, chip->start + offset, size);
-+
-+ put_chip(map, chip, chip->start);
-+ spin_unlock(chip->mutex);
-+ return 0;
-+}
-+
-+static int
-+do_otp_write(struct map_info *map, struct flchip *chip, u_long offset,
-+ u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
-+{
-+ int ret;
-+
-+ while (size) {
-+ unsigned long bus_ofs = offset & ~(map_bankwidth(map)-1);
-+ int gap = offset - bus_ofs;
-+ int n = min_t(int, size, map_bankwidth(map)-gap);
-+ map_word datum = map_word_ff(map);
-+
-+ datum = map_word_load_partial(map, datum, buf, gap, n);
-+ ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE);
-+ if (ret)
-+ return ret;
-+
-+ offset += n;
-+ buf += n;
-+ size -= n;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+do_otp_lock(struct map_info *map, struct flchip *chip, u_long offset,
-+ u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ map_word datum;
-+
-+ /* make sure area matches group boundaries */
-+ if (size != grpsz)
-+ return -EXDEV;
-+
-+ datum = map_word_ff(map);
-+ datum = map_word_clr(map, datum, CMD(1 << grpno));
-+ return do_write_oneword(map, chip, prot, datum, FL_OTP_WRITE);
-+}
-+
-+static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t *retlen, u_char *buf,
-+ otp_op_t action, int user_regs)
-+{
-+ struct map_info *map = mtd->priv;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ struct cfi_pri_intelext *extp = cfi->cmdset_priv;
-+ struct flchip *chip;
-+ struct cfi_intelext_otpinfo *otp;
-+ u_long devsize, reg_prot_offset, data_offset;
-+ u_int chip_num, chip_step, field, reg_fact_size, reg_user_size;
-+ u_int groups, groupno, groupsize, reg_fact_groups, reg_user_groups;
-+ int ret;
-+
-+ *retlen = 0;
-+
-+ /* Check that we actually have some OTP registers */
-+ if (!extp || !(extp->FeatureSupport & 64) || !extp->NumProtectionFields)
-+ return -ENODATA;
-+
-+ /* we need real chips here not virtual ones */
-+ devsize = (1 << cfi->cfiq->DevSize) * cfi->interleave;
-+ chip_step = devsize >> cfi->chipshift;
-+
-+ for (chip_num = 0; chip_num < cfi->numchips; chip_num += chip_step) {
-+ chip = &cfi->chips[chip_num];
-+ otp = (struct cfi_intelext_otpinfo *)&extp->extra[0];
-+
-+ /* first OTP region */
-+ field = 0;
-+ reg_prot_offset = extp->ProtRegAddr;
-+ reg_fact_groups = 1;
-+ reg_fact_size = 1 << extp->FactProtRegSize;
-+ reg_user_groups = 1;
-+ reg_user_size = 1 << extp->UserProtRegSize;
-+
-+ while (len > 0) {
-+ /* flash geometry fixup */
-+ data_offset = reg_prot_offset + 1;
-+ data_offset *= cfi->interleave * cfi->device_type;
-+ reg_prot_offset *= cfi->interleave * cfi->device_type;
-+ reg_fact_size *= cfi->interleave;
-+ reg_user_size *= cfi->interleave;
-+
-+ if (user_regs) {
-+ groups = reg_user_groups;
-+ groupsize = reg_user_size;
-+ /* skip over factory reg area */
-+ groupno = reg_fact_groups;
-+ data_offset += reg_fact_groups * reg_fact_size;
-+ } else {
-+ groups = reg_fact_groups;
-+ groupsize = reg_fact_size;
-+ groupno = 0;
-+ }
-+
-+ while (len > 0 && groups > 0) {
-+ if (!action) {
-+ /*
-+ * Special case: if action is NULL
-+ * we fill buf with otp_info records.
-+ */
-+ struct otp_info *otpinfo;
-+ map_word lockword;
-+ len -= sizeof(struct otp_info);
-+ if (len <= 0)
-+ return -ENOSPC;
-+ ret = do_otp_read(map, chip,
-+ reg_prot_offset,
-+ (u_char *)&lockword,
-+ map_bankwidth(map),
-+ 0, 0, 0);
-+ if (ret)
-+ return ret;
-+ otpinfo = (struct otp_info *)buf;
-+ otpinfo->start = from;
-+ otpinfo->length = groupsize;
-+ otpinfo->locked =
-+ !map_word_bitsset(map, lockword,
-+ CMD(1 << groupno));
-+ from += groupsize;
-+ buf += sizeof(*otpinfo);
-+ *retlen += sizeof(*otpinfo);
-+ } else if (from >= groupsize) {
-+ from -= groupsize;
-+ data_offset += groupsize;
-+ } else {
-+ int size = groupsize;
-+ data_offset += from;
-+ size -= from;
-+ from = 0;
-+ if (size > len)
-+ size = len;
-+ ret = action(map, chip, data_offset,
-+ buf, size, reg_prot_offset,
-+ groupno, groupsize);
-+ if (ret < 0)
-+ return ret;
-+ buf += size;
-+ len -= size;
-+ *retlen += size;
-+ data_offset += size;
-+ }
-+ groupno++;
-+ groups--;
-+ }
-+
-+ /* next OTP region */
-+ if (++field == extp->NumProtectionFields)
-+ break;
-+ reg_prot_offset = otp->ProtRegAddr;
-+ reg_fact_groups = otp->FactGroups;
-+ reg_fact_size = 1 << otp->FactProtRegSize;
-+ reg_user_groups = otp->UserGroups;
-+ reg_user_size = 1 << otp->UserProtRegSize;
-+ otp++;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int cfi_intelext_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
-+ size_t len, size_t *retlen,
-+ u_char *buf)
-+{
-+ return cfi_intelext_otp_walk(mtd, from, len, retlen,
-+ buf, do_otp_read, 0);
-+}
-+
-+static int cfi_intelext_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
-+ size_t len, size_t *retlen,
-+ u_char *buf)
-+{
-+ return cfi_intelext_otp_walk(mtd, from, len, retlen,
-+ buf, do_otp_read, 1);
-+}
-+
-+static int cfi_intelext_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
-+ size_t len, size_t *retlen,
-+ u_char *buf)
-+{
-+ return cfi_intelext_otp_walk(mtd, from, len, retlen,
-+ buf, do_otp_write, 1);
-+}
-+
-+static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd,
-+ loff_t from, size_t len)
-+{
-+ size_t retlen;
-+ return cfi_intelext_otp_walk(mtd, from, len, &retlen,
-+ NULL, do_otp_lock, 1);
-+}
-+
-+static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd,
-+ struct otp_info *buf, size_t len)
-+{
-+ size_t retlen;
-+ int ret;
-+
-+ ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0);
-+ return ret ? : retlen;
-+}
-+
-+static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd,
-+ struct otp_info *buf, size_t len)
-+{
-+ size_t retlen;
-+ int ret;
-+
-+ ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1);
-+ return ret ? : retlen;
-+}
-+
-+#endif
-+
- static int cfi_intelext_suspend(struct mtd_info *mtd)
- {
- struct map_info *map = mtd->priv;
-@@ -1889,22 +2222,32 @@
-
- spin_lock(chip->mutex);
-
-- switch(chip->state) {
-+ switch (chip->state) {
- case FL_READY:
- case FL_STATUS:
- case FL_CFI_QUERY:
- case FL_JEDEC_QUERY:
-+ if (chip->oldstate == FL_READY) {
- chip->oldstate = chip->state;
- chip->state = FL_PM_SUSPENDED;
- /* No need to wake_up() on this state change -
- * as the whole point is that nobody can do anything
- * with the chip now anyway.
- */
-- case FL_PM_SUSPENDED:
-+ } else {
-+ /* There seems to be an operation pending. We must wait for it. */
-+ printk(KERN_NOTICE "Flash device refused suspend due to pending operation (oldstate %d)\n", chip->oldstate);
-+ ret = -EAGAIN;
-+ }
- break;
--
- default:
-+ /* Should we actually wait? Once upon a time these routines weren't
-+ allowed to. Or should we return -EAGAIN, because the upper layers
-+ ought to have already shut down anything which was using the device
-+ anyway? The latter for now. */
-+ printk(KERN_NOTICE "Flash device refused suspend due to active operation (state %d)\n", chip->oldstate);
- ret = -EAGAIN;
-+ case FL_PM_SUSPENDED:
- break;
- }
- spin_unlock(chip->mutex);
-@@ -1923,6 +2266,7 @@
- because we're returning failure, and it didn't
- get power cycled */
- chip->state = chip->oldstate;
-+ chip->oldstate = FL_READY;
- wake_up(&chip->wq);
- }
- spin_unlock(chip->mutex);
-@@ -1947,8 +2291,8 @@
-
- /* Go to known state. Chip may have been power cycled */
- if (chip->state == FL_PM_SUSPENDED) {
-- cfi_write(map, CMD(0xFF), 0);
-- chip->state = FL_READY;
-+ map_write(map, CMD(0xFF), cfi->chips[i].start);
-+ chip->oldstate = chip->state = FL_READY;
- wake_up(&chip->wq);
- }
-
-@@ -1962,6 +2306,7 @@
- struct cfi_private *cfi = map->fldrv_priv;
- kfree(cfi->cmdset_priv);
- kfree(cfi->cfiq);
-+ kfree(cfi->chips[0].priv);
- kfree(cfi);
- kfree(mtd->eraseregions);
- }
-@@ -1969,7 +2314,7 @@
- static char im_name_1[]="cfi_cmdset_0001";
- static char im_name_3[]="cfi_cmdset_0003";
-
--int __init cfi_intelext_init(void)
-+static int __init cfi_intelext_init(void)
- {
- inter_module_register(im_name_1, THIS_MODULE, &cfi_cmdset_0001);
- inter_module_register(im_name_3, THIS_MODULE, &cfi_cmdset_0001);
---- linux-2.4.21/drivers/mtd/chips/cfi_cmdset_0002.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/chips/cfi_cmdset_0002.c
-@@ -3,19 +3,26 @@
- * AMD & Fujitsu Standard Vendor Command Set (ID 0x0002)
- *
- * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp>
-+ * Copyright (C) 2004 Arcom Control Systems Ltd <linux@arcom.com>
- *
- * 2_by_8 routines added by Simon Munton
- *
-+ * 4_by_16 work by Carolyn J. Smith
-+ *
-+ * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
-+ *
- * This code is GPL
- *
-- * $Id: cfi_cmdset_0002.c,v 1.62 2003/01/24 23:30:13 dwmw2 Exp $
-+ * $Id: cfi_cmdset_0002.c,v 1.114 2004/12/11 15:43:53 dedekind Exp $
- *
- */
-
-+#include <linux/config.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <asm/byteorder.h>
-
-@@ -23,15 +30,24 @@
- #include <linux/slab.h>
- #include <linux/delay.h>
- #include <linux/interrupt.h>
-+#include <linux/mtd/compatmac.h>
- #include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/cfi.h>
-
- #define AMD_BOOTLOC_BUG
-+#define FORCE_WORD_WRITE 0
-+
-+#define MAX_WORD_RETRIES 3
-+
-+#define MANUFACTURER_AMD 0x0001
-+#define MANUFACTURER_SST 0x00BF
-+#define SST49LF004B 0x0060
-
- static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
--static int cfi_amdstd_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
-+static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
-+static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
- static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *);
--static int cfi_amdstd_erase_onesize(struct mtd_info *, struct erase_info *);
- static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *);
- static void cfi_amdstd_sync (struct mtd_info *);
- static int cfi_amdstd_suspend (struct mtd_info *);
-@@ -41,59 +57,213 @@
- static void cfi_amdstd_destroy(struct mtd_info *);
-
- struct mtd_info *cfi_cmdset_0002(struct map_info *, int);
--static struct mtd_info *cfi_amdstd_setup (struct map_info *);
-+static struct mtd_info *cfi_amdstd_setup (struct mtd_info *);
-
-+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
-+static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr);
-+#include "fwh_lock.h"
-
- static struct mtd_chip_driver cfi_amdstd_chipdrv = {
-- probe: NULL, /* Not usable directly */
-- destroy: cfi_amdstd_destroy,
-- name: "cfi_cmdset_0002",
-- module: THIS_MODULE
-+ .probe = NULL, /* Not usable directly */
-+ .destroy = cfi_amdstd_destroy,
-+ .name = "cfi_cmdset_0002",
-+ .module = THIS_MODULE
- };
-
--struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
-+
-+/* #define DEBUG_CFI_FEATURES */
-+
-+
-+#ifdef DEBUG_CFI_FEATURES
-+static void cfi_tell_features(struct cfi_pri_amdstd *extp)
- {
-- struct cfi_private *cfi = map->fldrv_priv;
-- unsigned char bootloc;
-- int ofs_factor = cfi->interleave * cfi->device_type;
-- int i;
-- __u8 major, minor;
-- __u32 base = cfi->chips[0].start;
-+ const char* erase_suspend[3] = {
-+ "Not supported", "Read only", "Read/write"
-+ };
-+ const char* top_bottom[6] = {
-+ "No WP", "8x8KiB sectors at top & bottom, no WP",
-+ "Bottom boot", "Top boot",
-+ "Uniform, Bottom WP", "Uniform, Top WP"
-+ };
-
-- if (cfi->cfi_mode==CFI_MODE_CFI){
-- __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
-+ printk(" Silicon revision: %d\n", extp->SiliconRevision >> 1);
-+ printk(" Address sensitive unlock: %s\n",
-+ (extp->SiliconRevision & 1) ? "Not required" : "Required");
-
-- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-+ if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend))
-+ printk(" Erase Suspend: %s\n", erase_suspend[extp->EraseSuspend]);
-+ else
-+ printk(" Erase Suspend: Unknown value %d\n", extp->EraseSuspend);
-
-- major = cfi_read_query(map, base + (adr+3)*ofs_factor);
-- minor = cfi_read_query(map, base + (adr+4)*ofs_factor);
-+ if (extp->BlkProt == 0)
-+ printk(" Block protection: Not supported\n");
-+ else
-+ printk(" Block protection: %d sectors per group\n", extp->BlkProt);
-
-- printk(KERN_NOTICE " Amd/Fujitsu Extended Query Table v%c.%c at 0x%4.4X\n",
-- major, minor, adr);
-- cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL);
-
-- cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
-- cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
-- cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
-- cfi->mfr = cfi_read_query(map, base);
-- cfi->id = cfi_read_query(map, base + ofs_factor);
-+ printk(" Temporary block unprotect: %s\n",
-+ extp->TmpBlkUnprotect ? "Supported" : "Not supported");
-+ printk(" Block protect/unprotect scheme: %d\n", extp->BlkProtUnprot);
-+ printk(" Number of simultaneous operations: %d\n", extp->SimultaneousOps);
-+ printk(" Burst mode: %s\n",
-+ extp->BurstMode ? "Supported" : "Not supported");
-+ if (extp->PageMode == 0)
-+ printk(" Page mode: Not supported\n");
-+ else
-+ printk(" Page mode: %d word page\n", extp->PageMode << 2);
-+
-+ printk(" Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n",
-+ extp->VppMin >> 4, extp->VppMin & 0xf);
-+ printk(" Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n",
-+ extp->VppMax >> 4, extp->VppMax & 0xf);
-+
-+ if (extp->TopBottom < ARRAY_SIZE(top_bottom))
-+ printk(" Top/Bottom Boot Block: %s\n", top_bottom[extp->TopBottom]);
-+ else
-+ printk(" Top/Bottom Boot Block: Unknown value %d\n", extp->TopBottom);
-+}
-+#endif
-
-- /* Wheee. Bring me the head of someone at AMD. */
- #ifdef AMD_BOOTLOC_BUG
-+/* Wheee. Bring me the head of someone at AMD. */
-+static void fixup_amd_bootblock(struct mtd_info *mtd, void* param)
-+{
-+ struct map_info *map = mtd->priv;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
-+ __u8 major = extp->MajorVersion;
-+ __u8 minor = extp->MinorVersion;
-+
- if (((major << 8) | minor) < 0x3131) {
- /* CFI version 1.0 => don't trust bootloc */
- if (cfi->id & 0x80) {
- printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id);
-- bootloc = 3; /* top boot */
-+ extp->TopBottom = 3; /* top boot */
- } else {
-- bootloc = 2; /* bottom boot */
-+ extp->TopBottom = 2; /* bottom boot */
- }
-- } else
-+ }
-+}
- #endif
-- {
-- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-- bootloc = cfi_read_query(map, base + (adr+15)*ofs_factor);
-+
-+static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
-+{
-+ struct map_info *map = mtd->priv;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ if (cfi->cfiq->BufWriteTimeoutTyp) {
-+ DEBUG(MTD_DEBUG_LEVEL1, "Using buffer write method\n" );
-+ mtd->write = cfi_amdstd_write_buffers;
-+ }
-+}
-+
-+static void fixup_use_secsi(struct mtd_info *mtd, void *param)
-+{
-+ /* Setup for chips with a secsi area */
-+ mtd->read_user_prot_reg = cfi_amdstd_secsi_read;
-+ mtd->read_fact_prot_reg = cfi_amdstd_secsi_read;
-+}
-+
-+static void fixup_use_erase_chip(struct mtd_info *mtd, void *param)
-+{
-+ struct map_info *map = mtd->priv;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ if ((cfi->cfiq->NumEraseRegions == 1) &&
-+ ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) {
-+ mtd->erase = cfi_amdstd_erase_chip;
-+ }
-+
-+}
-+
-+static struct cfi_fixup cfi_fixup_table[] = {
-+#ifdef AMD_BOOTLOC_BUG
-+ { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL },
-+#endif
-+ { CFI_MFR_AMD, 0x0050, fixup_use_secsi, NULL, },
-+ { CFI_MFR_AMD, 0x0053, fixup_use_secsi, NULL, },
-+ { CFI_MFR_AMD, 0x0055, fixup_use_secsi, NULL, },
-+ { CFI_MFR_AMD, 0x0056, fixup_use_secsi, NULL, },
-+ { CFI_MFR_AMD, 0x005C, fixup_use_secsi, NULL, },
-+ { CFI_MFR_AMD, 0x005F, fixup_use_secsi, NULL, },
-+#if !FORCE_WORD_WRITE
-+ { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, },
-+#endif
-+ { 0, 0, NULL, NULL }
-+};
-+static struct cfi_fixup jedec_fixup_table[] = {
-+ { MANUFACTURER_SST, SST49LF004B, fixup_use_fwh_lock, NULL, },
-+ { 0, 0, NULL, NULL }
-+};
-+
-+static struct cfi_fixup fixup_table[] = {
-+ /* The CFI vendor ids and the JEDEC vendor IDs appear
-+ * to be common. It is like the devices id's are as
-+ * well. This table is to pick all cases where
-+ * we know that is the case.
-+ */
-+ { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip, NULL },
-+ { 0, 0, NULL, NULL }
-+};
-+
-+
-+struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ struct mtd_info *mtd;
-+ int i;
-+
-+ mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
-+ if (!mtd) {
-+ printk(KERN_WARNING "Failed to allocate memory for MTD device\n");
-+ return NULL;
-+ }
-+ memset(mtd, 0, sizeof(*mtd));
-+ mtd->priv = map;
-+ mtd->type = MTD_NORFLASH;
-+
-+ /* Fill in the default mtd operations */
-+ mtd->erase = cfi_amdstd_erase_varsize;
-+ mtd->write = cfi_amdstd_write_words;
-+ mtd->read = cfi_amdstd_read;
-+ mtd->sync = cfi_amdstd_sync;
-+ mtd->suspend = cfi_amdstd_suspend;
-+ mtd->resume = cfi_amdstd_resume;
-+ mtd->flags = MTD_CAP_NORFLASH;
-+ mtd->name = map->name;
-+
-+ if (cfi->cfi_mode==CFI_MODE_CFI){
-+ unsigned char bootloc;
-+ /*
-+ * It's a real CFI chip, not one for which the probe
-+ * routine faked a CFI structure. So we read the feature
-+ * table from it.
-+ */
-+ __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
-+ struct cfi_pri_amdstd *extp;
-+
-+ extp = (struct cfi_pri_amdstd*)cfi_read_pri(map, adr, sizeof(*extp), "Amd/Fujitsu");
-+ if (!extp) {
-+ kfree(mtd);
-+ return NULL;
-+ }
-+
-+ /* Install our own private info structure */
-+ cfi->cmdset_priv = extp;
-+
-+ /* Apply cfi device specific fixups */
-+ cfi_fixup(mtd, cfi_fixup_table);
-+
-+#ifdef DEBUG_CFI_FEATURES
-+ /* Tell the user about it in lots of lovely detail */
-+ cfi_tell_features(extp);
-+#endif
-+
-+ bootloc = extp->TopBottom;
-+ if ((bootloc != 2) && (bootloc != 3)) {
-+ printk(KERN_WARNING "%s: CFI does not contain boot "
-+ "bank location. Assuming top.\n", map->name);
-+ bootloc = 2;
- }
-+
- if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) {
- printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name);
-
-@@ -106,29 +276,28 @@
- cfi->cfiq->EraseRegionInfo[j] = swap;
- }
- }
-- switch (cfi->device_type) {
-- case CFI_DEVICETYPE_X8:
-+ /* Set the default CFI lock/unlock addresses */
- cfi->addr_unlock1 = 0x555;
- cfi->addr_unlock2 = 0x2aa;
-- break;
-- case CFI_DEVICETYPE_X16:
-+ /* Modify the unlock address if we are in compatibility mode */
-+ if ( /* x16 in x8 mode */
-+ ((cfi->device_type == CFI_DEVICETYPE_X8) &&
-+ (cfi->cfiq->InterfaceDesc == 2)) ||
-+ /* x32 in x16 mode */
-+ ((cfi->device_type == CFI_DEVICETYPE_X16) &&
-+ (cfi->cfiq->InterfaceDesc == 4)))
-+ {
- cfi->addr_unlock1 = 0xaaa;
-- if (map->buswidth == cfi->interleave) {
-- /* X16 chip(s) in X8 mode */
- cfi->addr_unlock2 = 0x555;
-- } else {
-- cfi->addr_unlock2 = 0x554;
-- }
-- break;
-- case CFI_DEVICETYPE_X32:
-- cfi->addr_unlock1 = 0x1555;
-- cfi->addr_unlock2 = 0xaaa;
-- break;
-- default:
-- printk(KERN_NOTICE "Eep. Unknown cfi_cmdset_0002 device type %d\n", cfi->device_type);
-- return NULL;
- }
-+
- } /* CFI mode */
-+ else if (cfi->cfi_mode == CFI_MODE_JEDEC) {
-+ /* Apply jedec specific fixups */
-+ cfi_fixup(mtd, jedec_fixup_table);
-+ }
-+ /* Apply generic fixups */
-+ cfi_fixup(mtd, fixup_table);
-
- for (i=0; i< cfi->numchips; i++) {
- cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
-@@ -138,40 +307,26 @@
-
- map->fldrv = &cfi_amdstd_chipdrv;
-
-- cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL);
-- return cfi_amdstd_setup(map);
-+ return cfi_amdstd_setup(mtd);
- }
-
--static struct mtd_info *cfi_amdstd_setup(struct map_info *map)
-+
-+static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
- {
-+ struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
-- struct mtd_info *mtd;
- unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
-+ unsigned long offset = 0;
-+ int i,j;
-
-- mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
- printk(KERN_NOTICE "number of %s chips: %d\n",
- (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips);
--
-- if (!mtd) {
-- printk(KERN_WARNING "Failed to allocate memory for MTD device\n");
-- goto setup_err;
-- }
--
-- memset(mtd, 0, sizeof(*mtd));
-- mtd->priv = map;
-- mtd->type = MTD_NORFLASH;
-- /* Also select the correct geometry setup too */
-+ /* Select the correct geometry setup */
- mtd->size = devsize * cfi->numchips;
-
-- if (cfi->cfiq->NumEraseRegions == 1) {
-- /* No need to muck about with multiple erase sizes */
-- mtd->erasesize = ((cfi->cfiq->EraseRegionInfo[0] >> 8) & ~0xff) * cfi->interleave;
-- } else {
-- unsigned long offset = 0;
-- int i,j;
--
- mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
-- mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL);
-+ mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
-+ * mtd->numeraseregions, GFP_KERNEL);
- if (!mtd->eraseregions) {
- printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n");
- goto setup_err;
-@@ -206,67 +361,12 @@
- mtd->eraseregions[i].numblocks);
- }
- #endif
-- }
--
-- switch (CFIDEV_BUSWIDTH)
-- {
-- case 1:
-- case 2:
-- case 4:
--#if 1
-- if (mtd->numeraseregions > 1)
-- mtd->erase = cfi_amdstd_erase_varsize;
-- else
--#endif
-- if (((cfi->cfiq->EraseRegionInfo[0] & 0xffff) + 1) == 1)
-- mtd->erase = cfi_amdstd_erase_chip;
-- else
-- mtd->erase = cfi_amdstd_erase_onesize;
-- mtd->read = cfi_amdstd_read;
-- mtd->write = cfi_amdstd_write;
-- break;
--
-- default:
-- printk(KERN_WARNING "Unsupported buswidth\n");
-- goto setup_err;
-- break;
-- }
-- if (cfi->fast_prog) {
-- /* In cfi_amdstd_write() we frob the protection stuff
-- without paying any attention to the state machine.
-- This upsets in-progress erases. So we turn this flag
-- off for now till the code gets fixed. */
-- printk(KERN_NOTICE "cfi_cmdset_0002: Disabling fast programming due to code brokenness.\n");
-- cfi->fast_prog = 0;
-- }
--
--
-- /* does this chip have a secsi area? */
-- if(cfi->mfr==1){
--
-- switch(cfi->id){
-- case 0x50:
-- case 0x53:
-- case 0x55:
-- case 0x56:
-- case 0x5C:
-- case 0x5F:
-- /* Yes */
-- mtd->read_user_prot_reg = cfi_amdstd_secsi_read;
-- mtd->read_fact_prot_reg = cfi_amdstd_secsi_read;
-- default:
-- ;
-- }
-- }
-
-+ /* FIXME: erase-suspend-program is broken. See
-+ http://lists.infradead.org/pipermail/linux-mtd/2003-December/009001.html */
-+ printk(KERN_NOTICE "cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.\n");
-
-- mtd->sync = cfi_amdstd_sync;
-- mtd->suspend = cfi_amdstd_suspend;
-- mtd->resume = cfi_amdstd_resume;
-- mtd->flags = MTD_CAP_NORFLASH;
-- map->fldrv = &cfi_amdstd_chipdrv;
-- mtd->name = map->name;
-- MOD_INC_USE_COUNT;
-+ __module_get(THIS_MODULE);
- return mtd;
-
- setup_err:
-@@ -280,46 +380,182 @@
- return NULL;
- }
-
--static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
-+/*
-+ * Return true if the chip is ready.
-+ *
-+ * Ready is one of: read mode, query mode, erase-suspend-read mode (in any
-+ * non-suspended sector) and is indicated by no toggle bits toggling.
-+ *
-+ * Note that anything more complicated than checking if no bits are toggling
-+ * (including checking DQ5 for an error status) is tricky to get working
-+ * correctly and is therefore not done (particulary with interleaved chips
-+ * as each chip must be checked independantly of the others).
-+ */
-+static int chip_ready(struct map_info *map, unsigned long addr)
-+{
-+ map_word d, t;
-+
-+ d = map_read(map, addr);
-+ t = map_read(map, addr);
-+
-+ return map_word_equal(map, d, t);
-+}
-+
-+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
- {
- DECLARE_WAITQUEUE(wait, current);
-- unsigned long timeo = jiffies + HZ;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ unsigned long timeo;
-+ struct cfi_pri_amdstd *cfip = (struct cfi_pri_amdstd *)cfi->cmdset_priv;
-
-+ resettime:
-+ timeo = jiffies + HZ;
- retry:
-+ switch (chip->state) {
-+
-+ case FL_STATUS:
-+ for (;;) {
-+ if (chip_ready(map, adr))
-+ break;
-+
-+ if (time_after(jiffies, timeo)) {
-+ printk(KERN_ERR "Waiting for chip to be ready timed out.\n");
-+ cfi_spin_unlock(chip->mutex);
-+ return -EIO;
-+ }
-+ cfi_spin_unlock(chip->mutex);
-+ cfi_udelay(1);
- cfi_spin_lock(chip->mutex);
-+ /* Someone else might have been playing with it. */
-+ goto retry;
-+ }
-
-- if (chip->state != FL_READY){
--#if 0
-- printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state);
--#endif
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-+ case FL_READY:
-+ case FL_CFI_QUERY:
-+ case FL_JEDEC_QUERY:
-+ return 0;
-+
-+ case FL_ERASING:
-+ if (mode == FL_WRITING) /* FIXME: Erase-suspend-program appears broken. */
-+ goto sleep;
-+
-+ if (!(mode == FL_READY || mode == FL_POINT
-+ || !cfip
-+ || (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))
-+ || (mode == FL_WRITING && (cfip->EraseSuspend & 0x1))))
-+ goto sleep;
-+
-+ /* We could check to see if we're trying to access the sector
-+ * that is currently being erased. However, no user will try
-+ * anything like that so we just wait for the timeout. */
-+
-+ /* Erase suspend */
-+ /* It's harmless to issue the Erase-Suspend and Erase-Resume
-+ * commands when the erase algorithm isn't in progress. */
-+ map_write(map, CMD(0xB0), chip->in_progress_block_addr);
-+ chip->oldstate = FL_ERASING;
-+ chip->state = FL_ERASE_SUSPENDING;
-+ chip->erase_suspended = 1;
-+ for (;;) {
-+ if (chip_ready(map, adr))
-+ break;
-+
-+ if (time_after(jiffies, timeo)) {
-+ /* Should have suspended the erase by now.
-+ * Send an Erase-Resume command as either
-+ * there was an error (so leave the erase
-+ * routine to recover from it) or we trying to
-+ * use the erase-in-progress sector. */
-+ map_write(map, CMD(0x30), chip->in_progress_block_addr);
-+ chip->state = FL_ERASING;
-+ chip->oldstate = FL_READY;
-+ printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__);
-+ return -EIO;
-+ }
-
- cfi_spin_unlock(chip->mutex);
-+ cfi_udelay(1);
-+ cfi_spin_lock(chip->mutex);
-+ /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
-+ So we can just loop here. */
-+ }
-+ chip->state = FL_READY;
-+ return 0;
-
-+ case FL_POINT:
-+ /* Only if there's no operation suspended... */
-+ if (mode == FL_READY && chip->oldstate == FL_READY)
-+ return 0;
-+
-+ default:
-+ sleep:
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ add_wait_queue(&chip->wq, &wait);
-+ cfi_spin_unlock(chip->mutex);
- schedule();
- remove_wait_queue(&chip->wq, &wait);
--#if 0
-- if(signal_pending(current))
-- return -EINTR;
--#endif
-- timeo = jiffies + HZ;
-+ cfi_spin_lock(chip->mutex);
-+ goto resettime;
-+ }
-+}
-
-- goto retry;
-+
-+static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+
-+ switch(chip->oldstate) {
-+ case FL_ERASING:
-+ chip->state = chip->oldstate;
-+ map_write(map, CMD(0x30), chip->in_progress_block_addr);
-+ chip->oldstate = FL_READY;
-+ chip->state = FL_ERASING;
-+ break;
-+
-+ case FL_READY:
-+ case FL_STATUS:
-+ /* We should really make set_vpp() count, rather than doing this */
-+ DISABLE_VPP(map);
-+ break;
-+ default:
-+ printk(KERN_ERR "MTD: put_chip() called with oldstate %d!!\n", chip->oldstate);
- }
-+ wake_up(&chip->wq);
-+}
-+
-+
-+static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
-+{
-+ unsigned long cmd_addr;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ int ret;
-
- adr += chip->start;
-
-+ /* Ensure cmd read/writes are aligned. */
-+ cmd_addr = adr & ~(map_bankwidth(map)-1);
-+
-+ cfi_spin_lock(chip->mutex);
-+ ret = get_chip(map, chip, cmd_addr, FL_READY);
-+ if (ret) {
-+ cfi_spin_unlock(chip->mutex);
-+ return ret;
-+ }
-+
-+ if (chip->state != FL_POINT && chip->state != FL_READY) {
-+ map_write(map, CMD(0xf0), cmd_addr);
- chip->state = FL_READY;
-+ }
-
-- map->copy_from(map, buf, adr, len);
-+ map_copy_from(map, buf, adr, len);
-
-- wake_up(&chip->wq);
-- cfi_spin_unlock(chip->mutex);
-+ put_chip(map, chip, cmd_addr);
-
-+ cfi_spin_unlock(chip->mutex);
- return 0;
- }
-
-+
- static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
- {
- struct map_info *map = mtd->priv;
-@@ -361,6 +597,7 @@
- return ret;
- }
-
-+
- static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
- {
- DECLARE_WAITQUEUE(wait, current);
-@@ -398,7 +635,7 @@
- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-
-- map->copy_from(map, buf, adr, len);
-+ map_copy_from(map, buf, adr, len);
-
- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
-@@ -454,125 +691,118 @@
- return ret;
- }
-
--static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum, int fast)
-+
-+static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
- {
-- unsigned long timeo = jiffies + HZ;
-- unsigned int oldstatus, status;
-- unsigned int dq6, dq5;
- struct cfi_private *cfi = map->fldrv_priv;
-- DECLARE_WAITQUEUE(wait, current);
-+ unsigned long timeo = jiffies + HZ;
-+ /*
-+ * We use a 1ms + 1 jiffies generic timeout for writes (most devices
-+ * have a max write time of a few hundreds usec). However, we should
-+ * use the maximum timeout value given by the chip at probe time
-+ * instead. Unfortunately, struct flchip does have a field for
-+ * maximum timeout, only for typical which can be far too short
-+ * depending of the conditions. The ' + 1' is to avoid having a
-+ * timeout of 0 jiffies if HZ is smaller than 1000.
-+ */
-+ unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
- int ret = 0;
-+ map_word oldd;
-+ int retry_cnt = 0;
-
-- retry:
-- cfi_spin_lock(chip->mutex);
--
-- if (chip->state != FL_READY) {
--#if 0
-- printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", chip->state);
--#endif
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-+ adr += chip->start;
-
-+ cfi_spin_lock(chip->mutex);
-+ ret = get_chip(map, chip, adr, FL_WRITING);
-+ if (ret) {
- cfi_spin_unlock(chip->mutex);
--
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
--#if 0
-- printk(KERN_DEBUG "Wake up to write:\n");
-- if(signal_pending(current))
-- return -EINTR;
--#endif
-- timeo = jiffies + HZ;
--
-- goto retry;
-+ return ret;
- }
-
-- chip->state = FL_WRITING;
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
-+ __func__, adr, datum.x[0] );
-
-- adr += chip->start;
-- ENABLE_VPP(map);
-- if (fast) { /* Unlock bypass */
-- cfi_send_gen_cmd(0xA0, 0, chip->start, map, cfi, cfi->device_type, NULL);
-- }
-- else {
-- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-+ /*
-+ * Check for a NOP for the case when the datum to write is already
-+ * present - it saves time and works around buggy chips that corrupt
-+ * data at other locations when 0xff is written to a location that
-+ * already contains 0xff.
-+ */
-+ oldd = map_read(map, adr);
-+ if (map_word_equal(map, oldd, datum)) {
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): NOP\n",
-+ __func__);
-+ goto op_done;
- }
-
-- cfi_write(map, datum, adr);
-+ ENABLE_VPP(map);
-+ retry:
-+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-+ map_write(map, datum, adr);
-+ chip->state = FL_WRITING;
-
- cfi_spin_unlock(chip->mutex);
- cfi_udelay(chip->word_write_time);
- cfi_spin_lock(chip->mutex);
-
-- /* Polling toggle bits instead of reading back many times
-- This ensures that write operation is really completed,
-- or tells us why it failed. */
-- dq6 = CMD(1<<6);
-- dq5 = CMD(1<<5);
-- timeo = jiffies + (HZ/1000); /* setting timeout to 1ms for now */
--
-- oldstatus = cfi_read(map, adr);
-- status = cfi_read(map, adr);
--
-- while( (status & dq6) != (oldstatus & dq6) &&
-- (status & dq5) != dq5 &&
-- !time_after(jiffies, timeo) ) {
-+ /* See comment above for timeout value. */
-+ timeo = jiffies + uWriteTimeout;
-+ for (;;) {
-+ if (chip->state != FL_WRITING) {
-+ /* Someone's suspended the write. Sleep */
-+ DECLARE_WAITQUEUE(wait, current);
-
-- if (need_resched()) {
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ add_wait_queue(&chip->wq, &wait);
- cfi_spin_unlock(chip->mutex);
-- yield();
-+ schedule();
-+ remove_wait_queue(&chip->wq, &wait);
-+ timeo = jiffies + (HZ / 2); /* FIXME */
- cfi_spin_lock(chip->mutex);
-- } else
-- udelay(1);
--
-- oldstatus = cfi_read( map, adr );
-- status = cfi_read( map, adr );
-+ continue;
- }
-
-- if( (status & dq6) != (oldstatus & dq6) ) {
-- /* The erasing didn't stop?? */
-- if( (status & dq5) == dq5 ) {
-- /* When DQ5 raises, we must check once again
-- if DQ6 is toggling. If not, the erase has been
-- completed OK. If not, reset chip. */
-- oldstatus = cfi_read(map, adr);
-- status = cfi_read(map, adr);
-+ if (chip_ready(map, adr))
-+ goto op_done;
-
-- if ( (oldstatus & 0x00FF) == (status & 0x00FF) ) {
-- printk(KERN_WARNING "Warning: DQ5 raised while program operation was in progress, however operation completed OK\n" );
-- } else {
-- /* DQ5 is active so we can do a reset and stop the erase */
-- cfi_write(map, CMD(0xF0), chip->start);
-- printk(KERN_WARNING "Internal flash device timeout occurred or write operation was performed while flash was programming.\n" );
-- }
-- } else {
-- printk(KERN_WARNING "Waiting for write to complete timed out in do_write_oneword.");
-+ if (time_after(jiffies, timeo))
-+ break;
-
-- chip->state = FL_READY;
-- wake_up(&chip->wq);
-+ /* Latency issues. Drop the lock, wait a while and retry */
- cfi_spin_unlock(chip->mutex);
-- DISABLE_VPP(map);
-- ret = -EIO;
-- }
-+ cfi_udelay(1);
-+ cfi_spin_lock(chip->mutex);
- }
-
-- DISABLE_VPP(map);
-+ printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
-+
-+ /* reset on all failures. */
-+ map_write( map, CMD(0xF0), chip->start );
-+ /* FIXME - should have reset delay before continuing */
-+ if (++retry_cnt <= MAX_WORD_RETRIES)
-+ goto retry;
-+
-+ ret = -EIO;
-+ op_done:
- chip->state = FL_READY;
-- wake_up(&chip->wq);
-+ put_chip(map, chip, adr);
- cfi_spin_unlock(chip->mutex);
-
- return ret;
- }
-
--static int cfi_amdstd_write (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf)
-+
-+static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t *retlen, const u_char *buf)
- {
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
- int ret = 0;
- int chipnum;
- unsigned long ofs, chipstart;
-+ DECLARE_WAITQUEUE(wait, current);
-
- *retlen = 0;
- if (!len)
-@@ -583,33 +813,52 @@
- chipstart = cfi->chips[chipnum].start;
-
- /* If it's not bus-aligned, do the first byte write */
-- if (ofs & (CFIDEV_BUSWIDTH-1)) {
-- unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);
-+ if (ofs & (map_bankwidth(map)-1)) {
-+ unsigned long bus_ofs = ofs & ~(map_bankwidth(map)-1);
- int i = ofs - bus_ofs;
- int n = 0;
-- u_char tmp_buf[4];
-- __u32 datum;
-+ map_word tmp_buf;
-
-- map->copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
-- while (len && i < CFIDEV_BUSWIDTH)
-- tmp_buf[i++] = buf[n++], len--;
-+ retry:
-+ cfi_spin_lock(cfi->chips[chipnum].mutex);
-
-- if (cfi_buswidth_is_2()) {
-- datum = *(__u16*)tmp_buf;
-- } else if (cfi_buswidth_is_4()) {
-- datum = *(__u32*)tmp_buf;
-- } else {
-- return -EINVAL; /* should never happen, but be safe */
-+ if (cfi->chips[chipnum].state != FL_READY) {
-+#if 0
-+ printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state);
-+#endif
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ add_wait_queue(&cfi->chips[chipnum].wq, &wait);
-+
-+ cfi_spin_unlock(cfi->chips[chipnum].mutex);
-+
-+ schedule();
-+ remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
-+#if 0
-+ if(signal_pending(current))
-+ return -EINTR;
-+#endif
-+ goto retry;
- }
-
-+ /* Load 'tmp_buf' with old contents of flash */
-+ tmp_buf = map_read(map, bus_ofs+chipstart);
-+
-+ cfi_spin_unlock(cfi->chips[chipnum].mutex);
-+
-+ /* Number of bytes to copy from buffer */
-+ n = min_t(int, len, map_bankwidth(map)-i);
-+
-+ tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n);
-+
- ret = do_write_oneword(map, &cfi->chips[chipnum],
-- bus_ofs, datum, 0);
-+ bus_ofs, tmp_buf);
- if (ret)
- return ret;
-
- ofs += n;
- buf += n;
- (*retlen) += n;
-+ len -= n;
-
- if (ofs >> cfi->chipshift) {
- chipnum ++;
-@@ -619,505 +868,457 @@
- }
- }
-
-- if (cfi->fast_prog) {
-- /* Go into unlock bypass mode */
-- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- }
--
- /* We are now aligned, write as much as possible */
-- while(len >= CFIDEV_BUSWIDTH) {
-- __u32 datum;
-+ while(len >= map_bankwidth(map)) {
-+ map_word datum;
-+
-+ datum = map_word_load(map, buf);
-
-- if (cfi_buswidth_is_1()) {
-- datum = *(__u8*)buf;
-- } else if (cfi_buswidth_is_2()) {
-- datum = *(__u16*)buf;
-- } else if (cfi_buswidth_is_4()) {
-- datum = *(__u32*)buf;
-- } else {
-- return -EINVAL;
-- }
- ret = do_write_oneword(map, &cfi->chips[chipnum],
-- ofs, datum, cfi->fast_prog);
-- if (ret) {
-- if (cfi->fast_prog){
-- /* Get out of unlock bypass mode */
-- cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
-- cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
-- }
-+ ofs, datum);
-+ if (ret)
- return ret;
-- }
-
-- ofs += CFIDEV_BUSWIDTH;
-- buf += CFIDEV_BUSWIDTH;
-- (*retlen) += CFIDEV_BUSWIDTH;
-- len -= CFIDEV_BUSWIDTH;
-+ ofs += map_bankwidth(map);
-+ buf += map_bankwidth(map);
-+ (*retlen) += map_bankwidth(map);
-+ len -= map_bankwidth(map);
-
- if (ofs >> cfi->chipshift) {
-- if (cfi->fast_prog){
-- /* Get out of unlock bypass mode */
-- cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
-- cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
-- }
--
- chipnum ++;
- ofs = 0;
- if (chipnum == cfi->numchips)
- return 0;
- chipstart = cfi->chips[chipnum].start;
-- if (cfi->fast_prog){
-- /* Go into unlock bypass mode for next set of chips */
-- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- }
- }
- }
-
-- if (cfi->fast_prog){
-- /* Get out of unlock bypass mode */
-- cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
-- cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
-- }
--
- /* Write the trailing bytes if any */
-- if (len & (CFIDEV_BUSWIDTH-1)) {
-- int i = 0, n = 0;
-- u_char tmp_buf[4];
-- __u32 datum;
-+ if (len & (map_bankwidth(map)-1)) {
-+ map_word tmp_buf;
-
-- map->copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
-- while (len--)
-- tmp_buf[i++] = buf[n++];
-+ retry1:
-+ cfi_spin_lock(cfi->chips[chipnum].mutex);
-
-- if (cfi_buswidth_is_2()) {
-- datum = *(__u16*)tmp_buf;
-- } else if (cfi_buswidth_is_4()) {
-- datum = *(__u32*)tmp_buf;
-- } else {
-- return -EINVAL; /* should never happen, but be safe */
-+ if (cfi->chips[chipnum].state != FL_READY) {
-+#if 0
-+ printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state);
-+#endif
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ add_wait_queue(&cfi->chips[chipnum].wq, &wait);
-+
-+ cfi_spin_unlock(cfi->chips[chipnum].mutex);
-+
-+ schedule();
-+ remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
-+#if 0
-+ if(signal_pending(current))
-+ return -EINTR;
-+#endif
-+ goto retry1;
- }
-
-+ tmp_buf = map_read(map, ofs + chipstart);
-+
-+ cfi_spin_unlock(cfi->chips[chipnum].mutex);
-+
-+ tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);
-+
- ret = do_write_oneword(map, &cfi->chips[chipnum],
-- ofs, datum, 0);
-+ ofs, tmp_buf);
- if (ret)
- return ret;
-
-- (*retlen) += n;
-+ (*retlen) += len;
- }
-
- return 0;
- }
-
--static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
-+
-+/*
-+ * FIXME: interleaved mode not tested, and probably not supported!
-+ */
-+static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
-+ unsigned long adr, const u_char *buf, int len)
- {
-- unsigned int oldstatus, status;
-- unsigned int dq6, dq5;
-- unsigned long timeo = jiffies + HZ;
-- unsigned int adr;
- struct cfi_private *cfi = map->fldrv_priv;
-- DECLARE_WAITQUEUE(wait, current);
-+ unsigned long timeo = jiffies + HZ;
-+ /* see comments in do_write_oneword() regarding uWriteTimeo. */
-+ unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
-+ int ret = -EIO;
-+ unsigned long cmd_adr;
-+ int z, words;
-+ map_word datum;
-+
-+ adr += chip->start;
-+ cmd_adr = adr;
-
-- retry:
- cfi_spin_lock(chip->mutex);
-+ ret = get_chip(map, chip, adr, FL_WRITING);
-+ if (ret) {
-+ cfi_spin_unlock(chip->mutex);
-+ return ret;
-+ }
-
-- if (chip->state != FL_READY){
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-+ datum = map_word_load(map, buf);
-
-- cfi_spin_unlock(chip->mutex);
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
-+ __func__, adr, datum.x[0] );
-
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
--#if 0
-- if(signal_pending(current))
-- return -EINTR;
--#endif
-- timeo = jiffies + HZ;
-+ ENABLE_VPP(map);
-+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
-+ //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-
-- goto retry;
-- }
-+ /* Write Buffer Load */
-+ map_write(map, CMD(0x25), cmd_adr);
-
-- chip->state = FL_ERASING;
-+ chip->state = FL_WRITING_TO_BUFFER;
-
-- /* Handle devices with one erase region, that only implement
-- * the chip erase command.
-- */
-- ENABLE_VPP(map);
-- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- timeo = jiffies + (HZ*20);
-- adr = cfi->addr_unlock1;
-+ /* Write length of data to come */
-+ words = len / map_bankwidth(map);
-+ map_write(map, CMD(words - 1), cmd_adr);
-+ /* Write data */
-+ z = 0;
-+ while(z < words * map_bankwidth(map)) {
-+ datum = map_word_load(map, buf);
-+ map_write(map, datum, adr + z);
-
-- /* Wait for the end of programing/erasure by using the toggle method.
-- * As long as there is a programming procedure going on, bit 6 of the last
-- * written byte is toggling it's state with each consectuve read.
-- * The toggling stops as soon as the procedure is completed.
-- *
-- * If the process has gone on for too long on the chip bit 5 gets.
-- * After bit5 is set you can kill the operation by sending a reset
-- * command to the chip.
-- */
-- dq6 = CMD(1<<6);
-- dq5 = CMD(1<<5);
-+ z += map_bankwidth(map);
-+ buf += map_bankwidth(map);
-+ }
-+ z -= map_bankwidth(map);
-
-- oldstatus = cfi_read(map, adr);
-- status = cfi_read(map, adr);
-- while( ((status & dq6) != (oldstatus & dq6)) &&
-- ((status & dq5) != dq5) &&
-- !time_after(jiffies, timeo)) {
-- int wait_reps;
-+ adr += z;
-+
-+ /* Write Buffer Program Confirm: GO GO GO */
-+ map_write(map, CMD(0x29), cmd_adr);
-+ chip->state = FL_WRITING;
-
-- /* an initial short sleep */
- cfi_spin_unlock(chip->mutex);
-- schedule_timeout(HZ/100);
-+ cfi_udelay(chip->buffer_write_time);
- cfi_spin_lock(chip->mutex);
-
-- if (chip->state != FL_ERASING) {
-- /* Someone's suspended the erase. Sleep */
-+ timeo = jiffies + uWriteTimeout;
-+
-+ for (;;) {
-+ if (chip->state != FL_WRITING) {
-+ /* Someone's suspended the write. Sleep */
-+ DECLARE_WAITQUEUE(wait, current);
-+
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
--
- cfi_spin_unlock(chip->mutex);
-- printk("erase suspended. Sleeping\n");
--
- schedule();
- remove_wait_queue(&chip->wq, &wait);
--#if 0
-- if (signal_pending(current))
-- return -EINTR;
--#endif
-- timeo = jiffies + (HZ*2); /* FIXME */
-+ timeo = jiffies + (HZ / 2); /* FIXME */
- cfi_spin_lock(chip->mutex);
- continue;
- }
-
-- /* Busy wait for 1/10 of a milisecond */
-- for(wait_reps = 0;
-- (wait_reps < 100) &&
-- ((status & dq6) != (oldstatus & dq6)) &&
-- ((status & dq5) != dq5);
-- wait_reps++) {
-+ if (chip_ready(map, adr))
-+ goto op_done;
-+
-+ if( time_after(jiffies, timeo))
-+ break;
-
- /* Latency issues. Drop the lock, wait a while and retry */
- cfi_spin_unlock(chip->mutex);
--
- cfi_udelay(1);
--
- cfi_spin_lock(chip->mutex);
-- oldstatus = cfi_read(map, adr);
-- status = cfi_read(map, adr);
- }
-- oldstatus = cfi_read(map, adr);
-- status = cfi_read(map, adr);
-- }
-- if ((status & dq6) != (oldstatus & dq6)) {
-- /* The erasing didn't stop?? */
-- if ((status & dq5) == dq5) {
-- /* dq5 is active so we can do a reset and stop the erase */
-- cfi_write(map, CMD(0xF0), chip->start);
-- }
-- chip->state = FL_READY;
-- wake_up(&chip->wq);
-- cfi_spin_unlock(chip->mutex);
-- printk("waiting for erase to complete timed out.");
-- DISABLE_VPP(map);
-- return -EIO;
-- }
-- DISABLE_VPP(map);
-+
-+ printk(KERN_WARNING "MTD %s(): software timeout\n",
-+ __func__ );
-+
-+ /* reset on all failures. */
-+ map_write( map, CMD(0xF0), chip->start );
-+ /* FIXME - should have reset delay before continuing */
-+
-+ ret = -EIO;
-+ op_done:
- chip->state = FL_READY;
-- wake_up(&chip->wq);
-+ put_chip(map, chip, adr);
- cfi_spin_unlock(chip->mutex);
-
-- return 0;
-+ return ret;
- }
-
--static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
-+
-+static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t *retlen, const u_char *buf)
- {
-- unsigned int oldstatus, status;
-- unsigned int dq6, dq5;
-- unsigned long timeo = jiffies + HZ;
-+ struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
-- DECLARE_WAITQUEUE(wait, current);
-+ int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
-+ int ret = 0;
-+ int chipnum;
-+ unsigned long ofs;
-
-- retry:
-- cfi_spin_lock(chip->mutex);
-+ *retlen = 0;
-+ if (!len)
-+ return 0;
-
-- if (chip->state != FL_READY){
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-+ chipnum = to >> cfi->chipshift;
-+ ofs = to - (chipnum << cfi->chipshift);
-
-- cfi_spin_unlock(chip->mutex);
-+ /* If it's not bus-aligned, do the first word write */
-+ if (ofs & (map_bankwidth(map)-1)) {
-+ size_t local_len = (-ofs)&(map_bankwidth(map)-1);
-+ if (local_len > len)
-+ local_len = len;
-+ ret = cfi_amdstd_write_words(mtd, ofs + (chipnum<<cfi->chipshift),
-+ local_len, retlen, buf);
-+ if (ret)
-+ return ret;
-+ ofs += local_len;
-+ buf += local_len;
-+ len -= local_len;
-
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
--#if 0
-- if(signal_pending(current))
-- return -EINTR;
--#endif
-- timeo = jiffies + HZ;
-+ if (ofs >> cfi->chipshift) {
-+ chipnum ++;
-+ ofs = 0;
-+ if (chipnum == cfi->numchips)
-+ return 0;
-+ }
-+ }
-
-- goto retry;
-+ /* Write buffer is worth it only if more than one word to write... */
-+ while (len >= map_bankwidth(map) * 2) {
-+ /* We must not cross write block boundaries */
-+ int size = wbufsize - (ofs & (wbufsize-1));
-+
-+ if (size > len)
-+ size = len;
-+ if (size % map_bankwidth(map))
-+ size -= size % map_bankwidth(map);
-+
-+ ret = do_write_buffer(map, &cfi->chips[chipnum],
-+ ofs, buf, size);
-+ if (ret)
-+ return ret;
-+
-+ ofs += size;
-+ buf += size;
-+ (*retlen) += size;
-+ len -= size;
-+
-+ if (ofs >> cfi->chipshift) {
-+ chipnum ++;
-+ ofs = 0;
-+ if (chipnum == cfi->numchips)
-+ return 0;
-+ }
- }
-
-- chip->state = FL_ERASING;
-+ if (len) {
-+ size_t retlen_dregs = 0;
-
-- adr += chip->start;
-- ENABLE_VPP(map);
-- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_write(map, CMD(0x30), adr);
-+ ret = cfi_amdstd_write_words(mtd, ofs + (chipnum<<cfi->chipshift),
-+ len, &retlen_dregs, buf);
-
-- timeo = jiffies + (HZ*20);
-+ *retlen += retlen_dregs;
-+ return ret;
-+ }
-
-- /* Wait for the end of programing/erasure by using the toggle method.
-- * As long as there is a programming procedure going on, bit 6 of the last
-- * written byte is toggling it's state with each consectuve read.
-- * The toggling stops as soon as the procedure is completed.
-- *
-- * If the process has gone on for too long on the chip bit 5 gets.
-- * After bit5 is set you can kill the operation by sending a reset
-- * command to the chip.
-+ return 0;
-+}
-+
-+
-+/*
-+ * Handle devices with one erase region, that only implement
-+ * the chip erase command.
- */
-- dq6 = CMD(1<<6);
-- dq5 = CMD(1<<5);
-+static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ unsigned long timeo = jiffies + HZ;
-+ unsigned long int adr;
-+ DECLARE_WAITQUEUE(wait, current);
-+ int ret = 0;
-
-- oldstatus = cfi_read(map, adr);
-- status = cfi_read(map, adr);
-- while( ((status & dq6) != (oldstatus & dq6)) &&
-- ((status & dq5) != dq5) &&
-- !time_after(jiffies, timeo)) {
-- int wait_reps;
-+ adr = cfi->addr_unlock1;
-
-- /* an initial short sleep */
-+ cfi_spin_lock(chip->mutex);
-+ ret = get_chip(map, chip, adr, FL_WRITING);
-+ if (ret) {
- cfi_spin_unlock(chip->mutex);
-- schedule_timeout(HZ/100);
-+ return ret;
-+ }
-+
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
-+ __func__, chip->start );
-+
-+ ENABLE_VPP(map);
-+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-+
-+ chip->state = FL_ERASING;
-+ chip->erase_suspended = 0;
-+ chip->in_progress_block_addr = adr;
-+
-+ cfi_spin_unlock(chip->mutex);
-+ msleep(chip->erase_time/2);
- cfi_spin_lock(chip->mutex);
-
-+ timeo = jiffies + (HZ*20);
-+
-+ for (;;) {
- if (chip->state != FL_ERASING) {
- /* Someone's suspended the erase. Sleep */
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
--
- cfi_spin_unlock(chip->mutex);
-- printk(KERN_DEBUG "erase suspended. Sleeping\n");
--
- schedule();
- remove_wait_queue(&chip->wq, &wait);
--#if 0
-- if (signal_pending(current))
-- return -EINTR;
--#endif
-- timeo = jiffies + (HZ*2); /* FIXME */
- cfi_spin_lock(chip->mutex);
- continue;
- }
-+ if (chip->erase_suspended) {
-+ /* This erase was suspended and resumed.
-+ Adjust the timeout */
-+ timeo = jiffies + (HZ*20); /* FIXME */
-+ chip->erase_suspended = 0;
-+ }
-
-- /* Busy wait for 1/10 of a milisecond */
-- for(wait_reps = 0;
-- (wait_reps < 100) &&
-- ((status & dq6) != (oldstatus & dq6)) &&
-- ((status & dq5) != dq5);
-- wait_reps++) {
-+ if (chip_ready(map, adr))
-+ goto op_done;
-+
-+ if (time_after(jiffies, timeo))
-+ break;
-
- /* Latency issues. Drop the lock, wait a while and retry */
- cfi_spin_unlock(chip->mutex);
--
-- cfi_udelay(1);
--
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ schedule_timeout(1);
- cfi_spin_lock(chip->mutex);
-- oldstatus = cfi_read(map, adr);
-- status = cfi_read(map, adr);
- }
-- oldstatus = cfi_read(map, adr);
-- status = cfi_read(map, adr);
-- }
-- if( (status & dq6) != (oldstatus & dq6) )
-- {
-- /* The erasing didn't stop?? */
-- if( ( status & dq5 ) == dq5 )
-- {
-- /* When DQ5 raises, we must check once again if DQ6 is toggling.
-- If not, the erase has been completed OK. If not, reset chip. */
-- oldstatus = cfi_read( map, adr );
-- status = cfi_read( map, adr );
-
-- if( ( oldstatus & 0x00FF ) == ( status & 0x00FF ) )
-- {
-- printk( "Warning: DQ5 raised while erase operation was in progress, but erase completed OK\n" );
-- }
-- else
-- {
-- /* DQ5 is active so we can do a reset and stop the erase */
-- cfi_write(map, CMD(0xF0), chip->start);
-- printk( KERN_WARNING "Internal flash device timeout occured or write operation was performed while flash was erasing\n" );
-- }
-- }
-- else
-- {
-- printk( "Waiting for erase to complete timed out in do_erase_oneblock.");
-+ printk(KERN_WARNING "MTD %s(): software timeout\n",
-+ __func__ );
-
-- chip->state = FL_READY;
-- wake_up(&chip->wq);
-- cfi_spin_unlock(chip->mutex);
-- DISABLE_VPP(map);
-- return -EIO;
-- }
-- }
-+ /* reset on all failures. */
-+ map_write( map, CMD(0xF0), chip->start );
-+ /* FIXME - should have reset delay before continuing */
-
-- DISABLE_VPP(map);
-+ ret = -EIO;
-+ op_done:
- chip->state = FL_READY;
-- wake_up(&chip->wq);
-+ put_chip(map, chip, adr);
- cfi_spin_unlock(chip->mutex);
-- return 0;
-+
-+ return ret;
- }
-
--static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
-+
-+static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk)
- {
-- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
-- unsigned long adr, len;
-- int chipnum, ret = 0;
-- int i, first;
-- struct mtd_erase_region_info *regions = mtd->eraseregions;
--
-- if (instr->addr > mtd->size)
-- return -EINVAL;
--
-- if ((instr->len + instr->addr) > mtd->size)
-- return -EINVAL;
--
-- /* Check that both start and end of the requested erase are
-- * aligned with the erasesize at the appropriate addresses.
-- */
-+ unsigned long timeo = jiffies + HZ;
-+ DECLARE_WAITQUEUE(wait, current);
-+ int ret = 0;
-
-- i = 0;
-+ adr += chip->start;
-
-- /* Skip all erase regions which are ended before the start of
-- the requested erase. Actually, to save on the calculations,
-- we skip to the first erase region which starts after the
-- start of the requested erase, and then go back one.
-- */
-+ cfi_spin_lock(chip->mutex);
-+ ret = get_chip(map, chip, adr, FL_ERASING);
-+ if (ret) {
-+ cfi_spin_unlock(chip->mutex);
-+ return ret;
-+ }
-
-- while (i < mtd->numeraseregions && instr->addr >= regions[i].offset)
-- i++;
-- i--;
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
-+ __func__, adr );
-
-- /* OK, now i is pointing at the erase region in which this
-- erase request starts. Check the start of the requested
-- erase range is aligned with the erase size which is in
-- effect here.
-- */
-+ ENABLE_VPP(map);
-+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
-+ map_write(map, CMD(0x30), adr);
-
-- if (instr->addr & (regions[i].erasesize-1))
-- return -EINVAL;
-+ chip->state = FL_ERASING;
-+ chip->erase_suspended = 0;
-+ chip->in_progress_block_addr = adr;
-
-- /* Remember the erase region we start on */
-- first = i;
-+ cfi_spin_unlock(chip->mutex);
-+ msleep(chip->erase_time/2);
-+ cfi_spin_lock(chip->mutex);
-
-- /* Next, check that the end of the requested erase is aligned
-- * with the erase region at that address.
-- */
-+ timeo = jiffies + (HZ*20);
-
-- while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset)
-- i++;
-+ for (;;) {
-+ if (chip->state != FL_ERASING) {
-+ /* Someone's suspended the erase. Sleep */
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ add_wait_queue(&chip->wq, &wait);
-+ cfi_spin_unlock(chip->mutex);
-+ schedule();
-+ remove_wait_queue(&chip->wq, &wait);
-+ cfi_spin_lock(chip->mutex);
-+ continue;
-+ }
-+ if (chip->erase_suspended) {
-+ /* This erase was suspended and resumed.
-+ Adjust the timeout */
-+ timeo = jiffies + (HZ*20); /* FIXME */
-+ chip->erase_suspended = 0;
-+ }
-
-- /* As before, drop back one to point at the region in which
-- the address actually falls
-- */
-- i--;
-+ if (chip_ready(map, adr))
-+ goto op_done;
-
-- if ((instr->addr + instr->len) & (regions[i].erasesize-1))
-- return -EINVAL;
-+ if (time_after(jiffies, timeo))
-+ break;
-
-- chipnum = instr->addr >> cfi->chipshift;
-- adr = instr->addr - (chipnum << cfi->chipshift);
-- len = instr->len;
-+ /* Latency issues. Drop the lock, wait a while and retry */
-+ cfi_spin_unlock(chip->mutex);
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ schedule_timeout(1);
-+ cfi_spin_lock(chip->mutex);
-+ }
-
-- i=first;
-+ printk(KERN_WARNING "MTD %s(): software timeout\n",
-+ __func__ );
-
-- while(len) {
-- ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
-+ /* reset on all failures. */
-+ map_write( map, CMD(0xF0), chip->start );
-+ /* FIXME - should have reset delay before continuing */
-
-- if (ret)
-+ ret = -EIO;
-+ op_done:
-+ chip->state = FL_READY;
-+ put_chip(map, chip, adr);
-+ cfi_spin_unlock(chip->mutex);
- return ret;
--
-- adr += regions[i].erasesize;
-- len -= regions[i].erasesize;
--
-- if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
-- i++;
--
-- if (adr >> cfi->chipshift) {
-- adr = 0;
-- chipnum++;
--
-- if (chipnum >= cfi->numchips)
-- break;
-- }
-- }
--
-- instr->state = MTD_ERASE_DONE;
-- if (instr->callback)
-- instr->callback(instr);
--
-- return 0;
- }
-
--static int cfi_amdstd_erase_onesize(struct mtd_info *mtd, struct erase_info *instr)
--{
-- struct map_info *map = mtd->priv;
-- struct cfi_private *cfi = map->fldrv_priv;
-- unsigned long adr, len;
-- int chipnum, ret = 0;
-
-- if (instr->addr & (mtd->erasesize - 1))
-- return -EINVAL;
--
-- if (instr->len & (mtd->erasesize -1))
-- return -EINVAL;
--
-- if ((instr->len + instr->addr) > mtd->size)
-- return -EINVAL;
-+int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
-+{
-+ unsigned long ofs, len;
-+ int ret;
-
-- chipnum = instr->addr >> cfi->chipshift;
-- adr = instr->addr - (chipnum << cfi->chipshift);
-+ ofs = instr->addr;
- len = instr->len;
-
-- while(len) {
-- ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
--
-+ ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL);
- if (ret)
- return ret;
-
-- adr += mtd->erasesize;
-- len -= mtd->erasesize;
--
-- if (adr >> cfi->chipshift) {
-- adr = 0;
-- chipnum++;
--
-- if (chipnum >= cfi->numchips)
-- break;
-- }
-- }
--
- instr->state = MTD_ERASE_DONE;
-- if (instr->callback)
-- instr->callback(instr);
-+ mtd_erase_callback(instr);
-
- return 0;
- }
-
-+
- static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr)
- {
- struct map_info *map = mtd->priv;
-@@ -1135,12 +1336,12 @@
- return ret;
-
- instr->state = MTD_ERASE_DONE;
-- if (instr->callback)
-- instr->callback(instr);
-+ mtd_erase_callback(instr);
-
- return 0;
- }
-
-+
- static void cfi_amdstd_sync (struct mtd_info *mtd)
- {
- struct map_info *map = mtd->priv;
-@@ -1254,6 +1455,7 @@
- return ret;
- }
-
-+
- static void cfi_amdstd_resume(struct mtd_info *mtd)
- {
- struct map_info *map = mtd->priv;
-@@ -1269,7 +1471,7 @@
-
- if (chip->state == FL_PM_SUSPENDED) {
- chip->state = FL_READY;
-- cfi_write(map, CMD(0xF0), chip->start);
-+ map_write(map, CMD(0xF0), chip->start);
- wake_up(&chip->wq);
- }
- else
-@@ -1291,21 +1493,23 @@
-
- static char im_name[]="cfi_cmdset_0002";
-
--int __init cfi_amdstd_init(void)
-+
-+static int __init cfi_amdstd_init(void)
- {
- inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0002);
- return 0;
- }
-
-+
- static void __exit cfi_amdstd_exit(void)
- {
- inter_module_unregister(im_name);
- }
-
-+
- module_init(cfi_amdstd_init);
- module_exit(cfi_amdstd_exit);
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al.");
- MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips");
--
---- linux-2.4.21/drivers/mtd/chips/cfi_cmdset_0020.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/chips/cfi_cmdset_0020.c
-@@ -4,6 +4,7 @@
- *
- * (C) 2000 Red Hat. GPL'd
- *
-+ * $Id: cfi_cmdset_0020.c,v 1.17 2004/11/20 12:49:04 dwmw2 Exp $
- *
- * 10/10/2000 Nicolas Pitre <nico@cam.org>
- * - completely revamped method functions so they are aware and
-@@ -17,10 +18,12 @@
- * - added a writev function
- */
-
-+#include <linux/version.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <asm/byteorder.h>
-
-@@ -30,12 +33,13 @@
- #include <linux/interrupt.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/cfi.h>
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/compatmac.h>
-
-
- static int cfi_staa_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
- static int cfi_staa_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
--static int cfi_staa_writev(struct mtd_info *mtd, const struct iovec *vecs,
-+static int cfi_staa_writev(struct mtd_info *mtd, const struct kvec *vecs,
- unsigned long count, loff_t to, size_t *retlen);
- static int cfi_staa_erase_varsize(struct mtd_info *, struct erase_info *);
- static void cfi_staa_sync (struct mtd_info *);
-@@ -51,10 +55,10 @@
- static struct mtd_info *cfi_staa_setup (struct map_info *);
-
- static struct mtd_chip_driver cfi_staa_chipdrv = {
-- probe: NULL, /* Not usable directly */
-- destroy: cfi_staa_destroy,
-- name: "cfi_cmdset_0020",
-- module: THIS_MODULE
-+ .probe = NULL, /* Not usable directly */
-+ .destroy = cfi_staa_destroy,
-+ .name = "cfi_cmdset_0020",
-+ .module = THIS_MODULE
- };
-
- /* #define DEBUG_LOCK_BITS */
-@@ -113,7 +117,6 @@
- {
- struct cfi_private *cfi = map->fldrv_priv;
- int i;
-- __u32 base = cfi->chips[0].start;
-
- if (cfi->cfi_mode) {
- /*
-@@ -123,35 +126,10 @@
- */
- __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
- struct cfi_pri_intelext *extp;
-- int ofs_factor = cfi->interleave * cfi->device_type;
--
-- printk(" ST Microelectronics Extended Query Table at 0x%4.4X\n", adr);
-- if (!adr)
-- return NULL;
--
-- /* Switch it into Query Mode */
-- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
--
-- extp = kmalloc(sizeof(*extp), GFP_KERNEL);
-- if (!extp) {
-- printk(KERN_ERR "Failed to allocate memory\n");
-- return NULL;
-- }
-
-- /* Read in the Extended Query Table */
-- for (i=0; i<sizeof(*extp); i++) {
-- ((unsigned char *)extp)[i] =
-- cfi_read_query(map, (base+((adr+i)*ofs_factor)));
-- }
--
-- if (extp->MajorVersion != '1' ||
-- (extp->MinorVersion < '0' || extp->MinorVersion > '2')) {
-- printk(KERN_WARNING " Unknown staa Extended Query "
-- "version %c.%c.\n", extp->MajorVersion,
-- extp->MinorVersion);
-- kfree(extp);
-+ extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "ST Microelectronics");
-+ if (!extp)
- return NULL;
-- }
-
- /* Do some byteswapping if necessary */
- extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport);
-@@ -172,11 +150,6 @@
- cfi->chips[i].erase_time = 1024;
- }
-
-- map->fldrv = &cfi_staa_chipdrv;
-- MOD_INC_USE_COUNT;
--
-- /* Make sure it's in read mode */
-- cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
- return cfi_staa_setup(map);
- }
-
-@@ -208,6 +181,7 @@
- if (!mtd->eraseregions) {
- printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");
- kfree(cfi->cmdset_priv);
-+ kfree(mtd);
- return NULL;
- }
-
-@@ -232,6 +206,7 @@
- printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
- kfree(mtd->eraseregions);
- kfree(cfi->cmdset_priv);
-+ kfree(mtd);
- return NULL;
- }
-
-@@ -256,7 +231,7 @@
- mtd->flags |= MTD_ECC; /* FIXME: Not all STMicro flashes have this */
- mtd->eccsize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
- map->fldrv = &cfi_staa_chipdrv;
-- MOD_INC_USE_COUNT;
-+ __module_get(THIS_MODULE);
- mtd->name = map->name;
- return mtd;
- }
-@@ -264,7 +239,7 @@
-
- static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
- {
-- __u32 status, status_OK;
-+ map_word status, status_OK;
- unsigned long timeo;
- DECLARE_WAITQUEUE(wait, current);
- int suspended = 0;
-@@ -274,7 +249,7 @@
- adr += chip->start;
-
- /* Ensure cmd read/writes are aligned. */
-- cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1);
-+ cmd_addr = adr & ~(map_bankwidth(map)-1);
-
- /* Let's determine this according to the interleave only once */
- status_OK = CMD(0x80);
-@@ -288,33 +263,33 @@
- */
- switch (chip->state) {
- case FL_ERASING:
-- if (!((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)
-+ if (!(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2))
- goto sleep; /* We don't support erase suspend */
-
-- cfi_write (map, CMD(0xb0), cmd_addr);
-+ map_write (map, CMD(0xb0), cmd_addr);
- /* If the flash has finished erasing, then 'erase suspend'
- * appears to make some (28F320) flash devices switch to
- * 'read' mode. Make sure that we switch to 'read status'
- * mode so we get the right data. --rmk
- */
-- cfi_write(map, CMD(0x70), cmd_addr);
-+ map_write(map, CMD(0x70), cmd_addr);
- chip->oldstate = FL_ERASING;
- chip->state = FL_ERASE_SUSPENDING;
- // printk("Erase suspending at 0x%lx\n", cmd_addr);
- for (;;) {
-- status = cfi_read(map, cmd_addr);
-- if ((status & status_OK) == status_OK)
-+ status = map_read(map, cmd_addr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- if (time_after(jiffies, timeo)) {
- /* Urgh */
-- cfi_write(map, CMD(0xd0), cmd_addr);
-+ map_write(map, CMD(0xd0), cmd_addr);
- /* make sure we're in 'read status' mode */
-- cfi_write(map, CMD(0x70), cmd_addr);
-+ map_write(map, CMD(0x70), cmd_addr);
- chip->state = FL_ERASING;
- spin_unlock_bh(chip->mutex);
- printk(KERN_ERR "Chip not ready after erase "
-- "suspended: status = 0x%x\n", status);
-+ "suspended: status = 0x%lx\n", status.x[0]);
- return -EIO;
- }
-
-@@ -324,7 +299,7 @@
- }
-
- suspended = 1;
-- cfi_write(map, CMD(0xff), cmd_addr);
-+ map_write(map, CMD(0xff), cmd_addr);
- chip->state = FL_READY;
- break;
-
-@@ -338,13 +313,13 @@
-
- case FL_CFI_QUERY:
- case FL_JEDEC_QUERY:
-- cfi_write(map, CMD(0x70), cmd_addr);
-+ map_write(map, CMD(0x70), cmd_addr);
- chip->state = FL_STATUS;
-
- case FL_STATUS:
-- status = cfi_read(map, cmd_addr);
-- if ((status & status_OK) == status_OK) {
-- cfi_write(map, CMD(0xff), cmd_addr);
-+ status = map_read(map, cmd_addr);
-+ if (map_word_andequal(map, status, status_OK, status_OK)) {
-+ map_write(map, CMD(0xff), cmd_addr);
- chip->state = FL_READY;
- break;
- }
-@@ -352,7 +327,7 @@
- /* Urgh. Chip not yet ready to talk to us. */
- if (time_after(jiffies, timeo)) {
- spin_unlock_bh(chip->mutex);
-- printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %x\n", status);
-+ printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %lx\n", status.x[0]);
- return -EIO;
- }
-
-@@ -374,7 +349,7 @@
- goto retry;
- }
-
-- map->copy_from(map, buf, adr, len);
-+ map_copy_from(map, buf, adr, len);
-
- if (suspended) {
- chip->state = chip->oldstate;
-@@ -387,8 +362,8 @@
- sending the 0x70 (Read Status) command to an erasing
- chip and expecting it to be ignored, that's what we
- do. */
-- cfi_write(map, CMD(0xd0), cmd_addr);
-- cfi_write(map, CMD(0x70), cmd_addr);
-+ map_write(map, CMD(0xd0), cmd_addr);
-+ map_write(map, CMD(0x70), cmd_addr);
- }
-
- wake_up(&chip->wq);
-@@ -439,16 +414,16 @@
- unsigned long adr, const u_char *buf, int len)
- {
- struct cfi_private *cfi = map->fldrv_priv;
-- __u32 status, status_OK;
-+ map_word status, status_OK;
- unsigned long cmd_adr, timeo;
- DECLARE_WAITQUEUE(wait, current);
- int wbufsize, z;
-
- /* M58LW064A requires bus alignment for buffer wriets -- saw */
-- if (adr & (CFIDEV_BUSWIDTH-1))
-+ if (adr & (map_bankwidth(map)-1))
- return -EINVAL;
-
-- wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
-+ wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
- adr += chip->start;
- cmd_adr = adr & ~(wbufsize-1);
-
-@@ -474,21 +449,21 @@
-
- case FL_CFI_QUERY:
- case FL_JEDEC_QUERY:
-- cfi_write(map, CMD(0x70), cmd_adr);
-+ map_write(map, CMD(0x70), cmd_adr);
- chip->state = FL_STATUS;
- #ifdef DEBUG_CFI_FEATURES
-- printk("%s: 1 status[%x]\n", __FUNCTION__, cfi_read(map, cmd_adr));
-+ printk("%s: 1 status[%x]\n", __FUNCTION__, map_read(map, cmd_adr));
- #endif
-
- case FL_STATUS:
-- status = cfi_read(map, cmd_adr);
-- if ((status & status_OK) == status_OK)
-+ status = map_read(map, cmd_adr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
- /* Urgh. Chip not yet ready to talk to us. */
- if (time_after(jiffies, timeo)) {
- spin_unlock_bh(chip->mutex);
-- printk(KERN_ERR "waiting for chip to be ready timed out in buffer write Xstatus = %x, status = %x\n",
-- status, cfi_read(map, cmd_adr));
-+ printk(KERN_ERR "waiting for chip to be ready timed out in buffer write Xstatus = %lx, status = %lx\n",
-+ status.x[0], map_read(map, cmd_adr).x[0]);
- return -EIO;
- }
-
-@@ -510,13 +485,13 @@
- }
-
- ENABLE_VPP(map);
-- cfi_write(map, CMD(0xe8), cmd_adr);
-+ map_write(map, CMD(0xe8), cmd_adr);
- chip->state = FL_WRITING_TO_BUFFER;
-
- z = 0;
- for (;;) {
-- status = cfi_read(map, cmd_adr);
-- if ((status & status_OK) == status_OK)
-+ status = map_read(map, cmd_adr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- spin_unlock_bh(chip->mutex);
-@@ -526,32 +501,26 @@
- if (++z > 100) {
- /* Argh. Not ready for write to buffer */
- DISABLE_VPP(map);
-- cfi_write(map, CMD(0x70), cmd_adr);
-+ map_write(map, CMD(0x70), cmd_adr);
- chip->state = FL_STATUS;
- spin_unlock_bh(chip->mutex);
-- printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %x\n", status);
-+ printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %lx\n", status.x[0]);
- return -EIO;
- }
- }
-
- /* Write length of data to come */
-- cfi_write(map, CMD(len/CFIDEV_BUSWIDTH-1), cmd_adr );
-+ map_write(map, CMD(len/map_bankwidth(map)-1), cmd_adr );
-
- /* Write data */
-- for (z = 0; z < len; z += CFIDEV_BUSWIDTH) {
-- if (cfi_buswidth_is_1()) {
-- map->write8 (map, *((__u8*)buf)++, adr+z);
-- } else if (cfi_buswidth_is_2()) {
-- map->write16 (map, *((__u16*)buf)++, adr+z);
-- } else if (cfi_buswidth_is_4()) {
-- map->write32 (map, *((__u32*)buf)++, adr+z);
-- } else {
-- DISABLE_VPP(map);
-- return -EINVAL;
-- }
-+ for (z = 0; z < len;
-+ z += map_bankwidth(map), buf += map_bankwidth(map)) {
-+ map_word d;
-+ d = map_word_load(map, buf);
-+ map_write(map, d, adr+z);
- }
- /* GO GO GO */
-- cfi_write(map, CMD(0xd0), cmd_adr);
-+ map_write(map, CMD(0xd0), cmd_adr);
- chip->state = FL_WRITING;
-
- spin_unlock_bh(chip->mutex);
-@@ -573,16 +542,16 @@
- continue;
- }
-
-- status = cfi_read(map, cmd_adr);
-- if ((status & status_OK) == status_OK)
-+ status = map_read(map, cmd_adr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- /* OK Still waiting */
- if (time_after(jiffies, timeo)) {
- /* clear status */
-- cfi_write(map, CMD(0x50), cmd_adr);
-+ map_write(map, CMD(0x50), cmd_adr);
- /* put back into read status register mode */
-- cfi_write(map, CMD(0x70), adr);
-+ map_write(map, CMD(0x70), adr);
- chip->state = FL_STATUS;
- DISABLE_VPP(map);
- spin_unlock_bh(chip->mutex);
-@@ -609,18 +578,17 @@
- chip->state = FL_STATUS;
-
- /* check for errors: 'lock bit', 'VPP', 'dead cell'/'unerased cell' or 'incorrect cmd' -- saw */
-- if ((status & CMD(0x02)) || (status & CMD(0x08)) ||
-- (status & CMD(0x10)) || (status & CMD(0x20))) {
-+ if (map_word_bitsset(map, status, CMD(0x3a))) {
- #ifdef DEBUG_CFI_FEATURES
-- printk("%s: 2 status[%x]\n", __FUNCTION__, status);
-+ printk("%s: 2 status[%lx]\n", __FUNCTION__, status.x[0]);
- #endif
- /* clear status */
-- cfi_write(map, CMD(0x50), cmd_adr);
-+ map_write(map, CMD(0x50), cmd_adr);
- /* put back into read status register mode */
-- cfi_write(map, CMD(0x70), adr);
-+ map_write(map, CMD(0x70), adr);
- wake_up(&chip->wq);
- spin_unlock_bh(chip->mutex);
-- return (status & CMD(0x02)) ? -EROFS : -EIO;
-+ return map_word_bitsset(map, status, CMD(0x02)) ? -EROFS : -EIO;
- }
- wake_up(&chip->wq);
- spin_unlock_bh(chip->mutex);
-@@ -633,7 +601,7 @@
- {
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
-- int wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
-+ int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
- int ret = 0;
- int chipnum;
- unsigned long ofs;
-@@ -646,7 +614,7 @@
- ofs = to - (chipnum << cfi->chipshift);
-
- #ifdef DEBUG_CFI_FEATURES
-- printk("%s: CFIDEV_BUSWIDTH[%x]\n", __FUNCTION__, CFIDEV_BUSWIDTH);
-+ printk("%s: map_bankwidth(map)[%x]\n", __FUNCTION__, map_bankwidth(map));
- printk("%s: chipnum[%x] wbufsize[%x]\n", __FUNCTION__, chipnum, wbufsize);
- printk("%s: ofs[%x] len[%x]\n", __FUNCTION__, ofs, len);
- #endif
-@@ -689,7 +657,7 @@
- #define ECCBUF_DIV(x) ((x) & ~(ECCBUF_SIZE - 1))
- #define ECCBUF_MOD(x) ((x) & (ECCBUF_SIZE - 1))
- static int
--cfi_staa_writev(struct mtd_info *mtd, const struct iovec *vecs,
-+cfi_staa_writev(struct mtd_info *mtd, const struct kvec *vecs,
- unsigned long count, loff_t to, size_t *retlen)
- {
- unsigned long i;
-@@ -758,7 +726,7 @@
- static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
- {
- struct cfi_private *cfi = map->fldrv_priv;
-- __u32 status, status_OK;
-+ map_word status, status_OK;
- unsigned long timeo;
- int retries = 3;
- DECLARE_WAITQUEUE(wait, current);
-@@ -778,12 +746,12 @@
- case FL_CFI_QUERY:
- case FL_JEDEC_QUERY:
- case FL_READY:
-- cfi_write(map, CMD(0x70), adr);
-+ map_write(map, CMD(0x70), adr);
- chip->state = FL_STATUS;
-
- case FL_STATUS:
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-+ status = map_read(map, adr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- /* Urgh. Chip not yet ready to talk to us. */
-@@ -812,15 +780,15 @@
-
- ENABLE_VPP(map);
- /* Clear the status register first */
-- cfi_write(map, CMD(0x50), adr);
-+ map_write(map, CMD(0x50), adr);
-
- /* Now erase */
-- cfi_write(map, CMD(0x20), adr);
-- cfi_write(map, CMD(0xD0), adr);
-+ map_write(map, CMD(0x20), adr);
-+ map_write(map, CMD(0xD0), adr);
- chip->state = FL_ERASING;
-
- spin_unlock_bh(chip->mutex);
-- schedule_timeout(HZ);
-+ msleep(1000);
- spin_lock_bh(chip->mutex);
-
- /* FIXME. Use a timer to check this, and return immediately. */
-@@ -840,15 +808,15 @@
- continue;
- }
-
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-+ status = map_read(map, adr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- /* OK Still waiting */
- if (time_after(jiffies, timeo)) {
-- cfi_write(map, CMD(0x70), adr);
-+ map_write(map, CMD(0x70), adr);
- chip->state = FL_STATUS;
-- printk(KERN_ERR "waiting for erase to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
-+ printk(KERN_ERR "waiting for erase to complete timed out. Xstatus = %lx, status = %lx.\n", status.x[0], map_read(map, adr).x[0]);
- DISABLE_VPP(map);
- spin_unlock_bh(chip->mutex);
- return -EIO;
-@@ -864,43 +832,46 @@
- ret = 0;
-
- /* We've broken this before. It doesn't hurt to be safe */
-- cfi_write(map, CMD(0x70), adr);
-+ map_write(map, CMD(0x70), adr);
- chip->state = FL_STATUS;
-- status = cfi_read(map, adr);
-+ status = map_read(map, adr);
-
- /* check for lock bit */
-- if (status & CMD(0x3a)) {
-- unsigned char chipstatus = status;
-- if (status != CMD(status & 0xff)) {
-- int i;
-- for (i = 1; i<CFIDEV_INTERLEAVE; i++) {
-- chipstatus |= status >> (cfi->device_type * 8);
-+ if (map_word_bitsset(map, status, CMD(0x3a))) {
-+ unsigned char chipstatus = status.x[0];
-+ if (!map_word_equal(map, status, CMD(chipstatus))) {
-+ int i, w;
-+ for (w=0; w<map_words(map); w++) {
-+ for (i = 0; i<cfi_interleave(cfi); i++) {
-+ chipstatus |= status.x[w] >> (cfi->device_type * 8);
- }
-- printk(KERN_WARNING "Status is not identical for all chips: 0x%x. Merging to give 0x%02x\n", status, chipstatus);
-+ }
-+ printk(KERN_WARNING "Status is not identical for all chips: 0x%lx. Merging to give 0x%02x\n",
-+ status.x[0], chipstatus);
- }
- /* Reset the error bits */
-- cfi_write(map, CMD(0x50), adr);
-- cfi_write(map, CMD(0x70), adr);
-+ map_write(map, CMD(0x50), adr);
-+ map_write(map, CMD(0x70), adr);
-
- if ((chipstatus & 0x30) == 0x30) {
-- printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", status);
-+ printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus);
- ret = -EIO;
- } else if (chipstatus & 0x02) {
- /* Protection bit set */
- ret = -EROFS;
- } else if (chipstatus & 0x8) {
- /* Voltage */
-- printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", status);
-+ printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", chipstatus);
- ret = -EIO;
- } else if (chipstatus & 0x20) {
- if (retries--) {
-- printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, status);
-+ printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, chipstatus);
- timeo = jiffies + HZ;
- chip->state = FL_STATUS;
- spin_unlock_bh(chip->mutex);
- goto retry;
- }
-- printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, status);
-+ printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, chipstatus);
- ret = -EIO;
- }
- }
-@@ -995,8 +966,7 @@
- }
-
- instr->state = MTD_ERASE_DONE;
-- if (instr->callback)
-- instr->callback(instr);
-+ mtd_erase_callback(instr);
-
- return 0;
- }
-@@ -1061,7 +1031,7 @@
- static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
- {
- struct cfi_private *cfi = map->fldrv_priv;
-- __u32 status, status_OK;
-+ map_word status, status_OK;
- unsigned long timeo = jiffies + HZ;
- DECLARE_WAITQUEUE(wait, current);
-
-@@ -1079,12 +1049,12 @@
- case FL_CFI_QUERY:
- case FL_JEDEC_QUERY:
- case FL_READY:
-- cfi_write(map, CMD(0x70), adr);
-+ map_write(map, CMD(0x70), adr);
- chip->state = FL_STATUS;
-
- case FL_STATUS:
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-+ status = map_read(map, adr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- /* Urgh. Chip not yet ready to talk to us. */
-@@ -1112,12 +1082,12 @@
- }
-
- ENABLE_VPP(map);
-- cfi_write(map, CMD(0x60), adr);
-- cfi_write(map, CMD(0x01), adr);
-+ map_write(map, CMD(0x60), adr);
-+ map_write(map, CMD(0x01), adr);
- chip->state = FL_LOCKING;
-
- spin_unlock_bh(chip->mutex);
-- schedule_timeout(HZ);
-+ msleep(1000);
- spin_lock_bh(chip->mutex);
-
- /* FIXME. Use a timer to check this, and return immediately. */
-@@ -1126,15 +1096,15 @@
- timeo = jiffies + (HZ*2);
- for (;;) {
-
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-+ status = map_read(map, adr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- /* OK Still waiting */
- if (time_after(jiffies, timeo)) {
-- cfi_write(map, CMD(0x70), adr);
-+ map_write(map, CMD(0x70), adr);
- chip->state = FL_STATUS;
-- printk(KERN_ERR "waiting for lock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
-+ printk(KERN_ERR "waiting for lock to complete timed out. Xstatus = %lx, status = %lx.\n", status.x[0], map_read(map, adr).x[0]);
- DISABLE_VPP(map);
- spin_unlock_bh(chip->mutex);
- return -EIO;
-@@ -1210,7 +1180,7 @@
- static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
- {
- struct cfi_private *cfi = map->fldrv_priv;
-- __u32 status, status_OK;
-+ map_word status, status_OK;
- unsigned long timeo = jiffies + HZ;
- DECLARE_WAITQUEUE(wait, current);
-
-@@ -1228,12 +1198,12 @@
- case FL_CFI_QUERY:
- case FL_JEDEC_QUERY:
- case FL_READY:
-- cfi_write(map, CMD(0x70), adr);
-+ map_write(map, CMD(0x70), adr);
- chip->state = FL_STATUS;
-
- case FL_STATUS:
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-+ status = map_read(map, adr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- /* Urgh. Chip not yet ready to talk to us. */
-@@ -1261,12 +1231,12 @@
- }
-
- ENABLE_VPP(map);
-- cfi_write(map, CMD(0x60), adr);
-- cfi_write(map, CMD(0xD0), adr);
-+ map_write(map, CMD(0x60), adr);
-+ map_write(map, CMD(0xD0), adr);
- chip->state = FL_UNLOCKING;
-
- spin_unlock_bh(chip->mutex);
-- schedule_timeout(HZ);
-+ msleep(1000);
- spin_lock_bh(chip->mutex);
-
- /* FIXME. Use a timer to check this, and return immediately. */
-@@ -1275,15 +1245,15 @@
- timeo = jiffies + (HZ*2);
- for (;;) {
-
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-+ status = map_read(map, adr);
-+ if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- /* OK Still waiting */
- if (time_after(jiffies, timeo)) {
-- cfi_write(map, CMD(0x70), adr);
-+ map_write(map, CMD(0x70), adr);
- chip->state = FL_STATUS;
-- printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
-+ printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %lx, status = %lx.\n", status.x[0], map_read(map, adr).x[0]);
- DISABLE_VPP(map);
- spin_unlock_bh(chip->mutex);
- return -EIO;
-@@ -1412,7 +1382,7 @@
-
- /* Go to known state. Chip may have been power cycled */
- if (chip->state == FL_PM_SUSPENDED) {
-- cfi_write(map, CMD(0xFF), 0);
-+ map_write(map, CMD(0xFF), 0);
- chip->state = FL_READY;
- wake_up(&chip->wq);
- }
-@@ -1429,23 +1399,20 @@
- kfree(cfi);
- }
-
--#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
--#define cfi_staa_init init_module
--#define cfi_staa_exit cleanup_module
--#endif
--
- static char im_name[]="cfi_cmdset_0020";
-
--mod_init_t cfi_staa_init(void)
-+static int __init cfi_staa_init(void)
- {
- inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0020);
- return 0;
- }
-
--mod_exit_t cfi_staa_exit(void)
-+static void __exit cfi_staa_exit(void)
- {
- inter_module_unregister(im_name);
- }
-
- module_init(cfi_staa_init);
- module_exit(cfi_staa_exit);
-+
-+MODULE_LICENSE("GPL");
---- linux-2.4.21/drivers/mtd/chips/cfi_probe.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/chips/cfi_probe.c
-@@ -1,19 +1,21 @@
- /*
- Common Flash Interface probe code.
- (C) 2000 Red Hat. GPL'd.
-- $Id: cfi_probe.c,v 1.69 2002/05/11 22:13:03 dwmw2 Exp $
-+ $Id: cfi_probe.c,v 1.83 2004/11/16 18:19:02 nico Exp $
- */
-
- #include <linux/config.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <asm/byteorder.h>
- #include <linux/errno.h>
- #include <linux/slab.h>
- #include <linux/interrupt.h>
-
-+#include <linux/mtd/xip.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/cfi.h>
- #include <linux/mtd/gen_probe.h>
-@@ -25,30 +27,80 @@
- #endif
-
- static int cfi_probe_chip(struct map_info *map, __u32 base,
-- struct flchip *chips, struct cfi_private *cfi);
-+ unsigned long *chip_map, struct cfi_private *cfi);
- static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi);
-
- struct mtd_info *cfi_probe(struct map_info *map);
-
-+#ifdef CONFIG_MTD_XIP
-+
-+/* only needed for short periods, so this is rather simple */
-+#define xip_disable() local_irq_disable()
-+
-+#define xip_allowed(base, map) \
-+do { \
-+ (void) map_read(map, base); \
-+ asm volatile (".rep 8; nop; .endr"); \
-+ local_irq_enable(); \
-+} while (0)
-+
-+#define xip_enable(base, map, cfi) \
-+do { \
-+ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \
-+ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); \
-+ xip_allowed(base, map); \
-+} while (0)
-+
-+#define xip_disable_qry(base, map, cfi) \
-+do { \
-+ xip_disable(); \
-+ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \
-+ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); \
-+ cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); \
-+} while (0)
-+
-+#else
-+
-+#define xip_disable() do { } while (0)
-+#define xip_allowed(base, map) do { } while (0)
-+#define xip_enable(base, map, cfi) do { } while (0)
-+#define xip_disable_qry(base, map, cfi) do { } while (0)
-+
-+#endif
-+
- /* check for QRY.
- in: interleave,type,mode
- ret: table index, <0 for error
- */
--static inline int qry_present(struct map_info *map, __u32 base,
-+static int __xipram qry_present(struct map_info *map, __u32 base,
- struct cfi_private *cfi)
- {
- int osf = cfi->interleave * cfi->device_type; // scale factor
-+ map_word val[3];
-+ map_word qry[3];
-
-- if (cfi_read(map,base+osf*0x10)==cfi_build_cmd('Q',map,cfi) &&
-- cfi_read(map,base+osf*0x11)==cfi_build_cmd('R',map,cfi) &&
-- cfi_read(map,base+osf*0x12)==cfi_build_cmd('Y',map,cfi))
-- return 1; // ok !
-+ qry[0] = cfi_build_cmd('Q', map, cfi);
-+ qry[1] = cfi_build_cmd('R', map, cfi);
-+ qry[2] = cfi_build_cmd('Y', map, cfi);
-
-- return 0; // nothing found
-+ val[0] = map_read(map, base + osf*0x10);
-+ val[1] = map_read(map, base + osf*0x11);
-+ val[2] = map_read(map, base + osf*0x12);
-+
-+ if (!map_word_equal(map, qry[0], val[0]))
-+ return 0;
-+
-+ if (!map_word_equal(map, qry[1], val[1]))
-+ return 0;
-+
-+ if (!map_word_equal(map, qry[2], val[2]))
-+ return 0;
-+
-+ return 1; // "QRY" found
- }
-
--static int cfi_probe_chip(struct map_info *map, __u32 base,
-- struct flchip *chips, struct cfi_private *cfi)
-+static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
-+ unsigned long *chip_map, struct cfi_private *cfi)
- {
- int i;
-
-@@ -64,15 +116,16 @@
- (unsigned long)base + 0x55, map->size -1);
- return 0;
- }
-- cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
-
-- /* some devices don't respond to 0xF0, so send 0xFF to be sure */
-+ xip_disable();
-+ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
--
- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-
-- if (!qry_present(map,base,cfi))
-+ if (!qry_present(map,base,cfi)) {
-+ xip_enable(base, map, cfi);
- return 0;
-+ }
-
- if (!cfi->numchips) {
- /* This is the first time we're called. Set up the CFI
-@@ -81,20 +134,26 @@
- }
-
- /* Check each previous chip to see if it's an alias */
-- for (i=0; i<cfi->numchips; i++) {
-+ for (i=0; i < (base >> cfi->chipshift); i++) {
-+ unsigned long start;
-+ if(!test_bit(i, chip_map)) {
-+ /* Skip location; no valid chip at this address */
-+ continue;
-+ }
-+ start = i << cfi->chipshift;
- /* This chip should be in read mode if it's one
- we've already touched. */
-- if (qry_present(map,chips[i].start,cfi)) {
-+ if (qry_present(map, start, cfi)) {
- /* Eep. This chip also had the QRY marker.
- * Is it an alias for the new one? */
-- cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL);
-- /* some devices don't respond to 0xF0, so send 0xFF to be sure */
-- cfi_send_gen_cmd(0xFF, 0, chips[i].start, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL);
-
- /* If the QRY marker goes away, it's an alias */
-- if (!qry_present(map, chips[i].start, cfi)) {
-+ if (!qry_present(map, start, cfi)) {
-+ xip_allowed(base, map);
- printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
-- map->name, base, chips[i].start);
-+ map->name, base, start);
- return 0;
- }
- /* Yes, it's actually got QRY for data. Most
-@@ -102,11 +161,12 @@
- * too and if it's the same, assume it's an alias. */
- /* FIXME: Use other modes to do a proper check */
- cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
-- /* some devices don't respond to 0xF0, so send 0xFF to be sure */
-- cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL);
-+
- if (qry_present(map, base, cfi)) {
-+ xip_allowed(base, map);
- printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
-- map->name, base, chips[i].start);
-+ map->name, base, start);
- return 0;
- }
- }
-@@ -114,30 +174,22 @@
-
- /* OK, if we got to here, then none of the previous chips appear to
- be aliases for the current one. */
-- if (cfi->numchips == MAX_CFI_CHIPS) {
-- printk(KERN_WARNING"%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS);
-- /* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */
-- return -1;
-- }
-- chips[cfi->numchips].start = base;
-- chips[cfi->numchips].state = FL_READY;
-+ set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */
- cfi->numchips++;
-
- /* Put it back into Read Mode */
- cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
--
-- /* some devices don't respond to 0xF0, so send 0xFF to be sure */
- cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
-+ xip_allowed(base, map);
-
--
-- printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n",
-+ printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
- map->name, cfi->interleave, cfi->device_type*8, base,
-- map->buswidth*8);
-+ map->bankwidth*8);
-
- return 1;
- }
-
--static int cfi_chip_setup(struct map_info *map,
-+static int __xipram cfi_chip_setup(struct map_info *map,
- struct cfi_private *cfi)
- {
- int ofs_factor = cfi->interleave*cfi->device_type;
-@@ -145,6 +197,7 @@
- int num_erase_regions = cfi_read_query(map, base + (0x10 + 28)*ofs_factor);
- int i;
-
-+ xip_enable(base, map, cfi);
- #ifdef DEBUG_CFI
- printk("Number of erase regions: %d\n", num_erase_regions);
- #endif
-@@ -160,12 +213,31 @@
- memset(cfi->cfiq,0,sizeof(struct cfi_ident));
-
- cfi->cfi_mode = CFI_MODE_CFI;
-- cfi->fast_prog=1; /* CFI supports fast programming */
-
- /* Read the CFI info structure */
-- for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) {
-+ xip_disable_qry(base, map, cfi);
-+ for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++)
- ((unsigned char *)cfi->cfiq)[i] = cfi_read_query(map,base + (0x10 + i)*ofs_factor);
-- }
-+
-+ /* Note we put the device back into Read Mode BEFORE going into Auto
-+ * Select Mode, as some devices support nesting of modes, others
-+ * don't. This way should always work.
-+ * On cmdset 0001 the writes of 0xaa and 0x55 are not needed, and
-+ * so should be treated as nops or illegal (and so put the device
-+ * back into Read Mode, which is a nop in this case).
-+ */
-+ cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
-+ cfi->mfr = cfi_read_query(map, base);
-+ cfi->id = cfi_read_query(map, base + ofs_factor);
-+
-+ /* Put it back into Read Mode */
-+ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
-+ /* ... even if it's an Intel chip */
-+ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
-+ xip_allowed(base, map);
-
- /* Do any necessary byteswapping */
- cfi->cfiq->P_ID = le16_to_cpu(cfi->cfiq->P_ID);
-@@ -176,20 +248,6 @@
- cfi->cfiq->InterfaceDesc = le16_to_cpu(cfi->cfiq->InterfaceDesc);
- cfi->cfiq->MaxBufWriteSize = le16_to_cpu(cfi->cfiq->MaxBufWriteSize);
-
-- /*
-- * ST screwed up the CFI interface for buffer writes on their parts,
-- * so this needs to be fixed up by hand here.
-- *
-- * A possible enhancment is that instead of just reverting back
-- * to word write (as this does), we could use the ST specific double
-- * word write instead.
-- */
--
-- if (cfi_read_query(map,base) == 0x20){
-- cfi->cfiq->BufWriteTimeoutTyp = 0;
-- cfi->cfiq->BufWriteTimeoutMax = 0;
-- }
--
- #ifdef DEBUG_CFI
- /* Dump the information therein */
- print_cfi_ident(cfi->cfiq);
-@@ -204,11 +262,10 @@
- (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1);
- #endif
- }
-- /* Put it back into Read Mode */
-- cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
-
-- /* some devices don't respond to 0xF0, so send 0xFF to be sure */
-- cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
-+ printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
-+ map->name, cfi->interleave, cfi->device_type*8, base,
-+ map->bankwidth*8);
-
- return 1;
- }
-@@ -232,12 +289,27 @@
- case P_ID_AMD_EXT:
- return "AMD/Fujitsu Extended";
-
-+ case P_ID_WINBOND:
-+ return "Winbond Standard";
-+
-+ case P_ID_ST_ADV:
-+ return "ST Advanced";
-+
- case P_ID_MITSUBISHI_STD:
- return "Mitsubishi Standard";
-
- case P_ID_MITSUBISHI_EXT:
- return "Mitsubishi Extended";
-
-+ case P_ID_SST_PAGE:
-+ return "SST Page Write";
-+
-+ case P_ID_INTEL_PERFORMANCE:
-+ return "Intel Performance Code";
-+
-+ case P_ID_INTEL_DATA:
-+ return "Intel Data";
-+
- case P_ID_RESERVED:
- return "Not Allowed / Reserved for Future Use";
-
-@@ -268,11 +340,11 @@
- printk("No Alternate Algorithm Table\n");
-
-
-- printk("Vcc Minimum: %x.%x V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf);
-- printk("Vcc Maximum: %x.%x V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf);
-+ printk("Vcc Minimum: %2d.%d V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf);
-+ printk("Vcc Maximum: %2d.%d V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf);
- if (cfip->VppMin) {
-- printk("Vpp Minimum: %x.%x V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf);
-- printk("Vpp Maximum: %x.%x V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf);
-+ printk("Vpp Minimum: %2d.%d V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf);
-+ printk("Vpp Maximum: %2d.%d V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf);
- }
- else
- printk("No Vpp line\n");
-@@ -315,6 +387,10 @@
- printk(" - x32-only asynchronous interface\n");
- break;
-
-+ case 4:
-+ printk(" - supports x16 and x32 via Word# with asynchronous interface\n");
-+ break;
-+
- case 65535:
- printk(" - Not Allowed / Reserved\n");
- break;
-@@ -331,8 +407,8 @@
- #endif /* DEBUG_CFI */
-
- static struct chip_probe cfi_chip_probe = {
-- name: "CFI",
-- probe_chip: cfi_probe_chip
-+ .name = "CFI",
-+ .probe_chip = cfi_probe_chip
- };
-
- struct mtd_info *cfi_probe(struct map_info *map)
-@@ -345,9 +421,9 @@
- }
-
- static struct mtd_chip_driver cfi_chipdrv = {
-- probe: cfi_probe,
-- name: "cfi_probe",
-- module: THIS_MODULE
-+ .probe = cfi_probe,
-+ .name = "cfi_probe",
-+ .module = THIS_MODULE
- };
-
- int __init cfi_probe_init(void)
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/chips/cfi_util.c
-@@ -0,0 +1,196 @@
-+/*
-+ * Common Flash Interface support:
-+ * Generic utility functions not dependant on command set
-+ *
-+ * Copyright (C) 2002 Red Hat
-+ * Copyright (C) 2003 STMicroelectronics Limited
-+ *
-+ * This code is covered by the GPL.
-+ *
-+ * $Id: cfi_util.c,v 1.8 2004/12/14 19:55:56 nico Exp $
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <asm/io.h>
-+#include <asm/byteorder.h>
-+
-+#include <linux/errno.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
-+#include <linux/interrupt.h>
-+#include <linux/mtd/xip.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/cfi.h>
-+#include <linux/mtd/compatmac.h>
-+
-+struct cfi_extquery *
-+__xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ __u32 base = 0; // cfi->chips[0].start;
-+ int ofs_factor = cfi->interleave * cfi->device_type;
-+ int i;
-+ struct cfi_extquery *extp = NULL;
-+
-+ printk(" %s Extended Query Table at 0x%4.4X\n", name, adr);
-+ if (!adr)
-+ goto out;
-+
-+ extp = kmalloc(size, GFP_KERNEL);
-+ if (!extp) {
-+ printk(KERN_ERR "Failed to allocate memory\n");
-+ goto out;
-+ }
-+
-+#ifdef CONFIG_MTD_XIP
-+ local_irq_disable();
-+#endif
-+
-+ /* Switch it into Query Mode */
-+ cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-+
-+ /* Read in the Extended Query Table */
-+ for (i=0; i<size; i++) {
-+ ((unsigned char *)extp)[i] =
-+ cfi_read_query(map, base+((adr+i)*ofs_factor));
-+ }
-+
-+ /* Make sure it returns to read mode */
-+ cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0xff, 0, base, map, cfi, cfi->device_type, NULL);
-+
-+#ifdef CONFIG_MTD_XIP
-+ (void) map_read(map, base);
-+ asm volatile (".rep 8; nop; .endr");
-+ local_irq_enable();
-+#endif
-+
-+ if (extp->MajorVersion != '1' ||
-+ (extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
-+ printk(KERN_WARNING " Unknown %s Extended Query "
-+ "version %c.%c.\n", name, extp->MajorVersion,
-+ extp->MinorVersion);
-+ kfree(extp);
-+ extp = NULL;
-+ }
-+
-+ out: return extp;
-+}
-+
-+EXPORT_SYMBOL(cfi_read_pri);
-+
-+void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup *fixups)
-+{
-+ struct map_info *map = mtd->priv;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ struct cfi_fixup *f;
-+
-+ for (f=fixups; f->fixup; f++) {
-+ if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) &&
-+ ((f->id == CFI_ID_ANY) || (f->id == cfi->id))) {
-+ f->fixup(mtd, f->param);
-+ }
-+ }
-+}
-+
-+EXPORT_SYMBOL(cfi_fixup);
-+
-+int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
-+ loff_t ofs, size_t len, void *thunk)
-+{
-+ struct map_info *map = mtd->priv;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ unsigned long adr;
-+ int chipnum, ret = 0;
-+ int i, first;
-+ struct mtd_erase_region_info *regions = mtd->eraseregions;
-+
-+ if (ofs > mtd->size)
-+ return -EINVAL;
-+
-+ if ((len + ofs) > mtd->size)
-+ return -EINVAL;
-+
-+ /* Check that both start and end of the requested erase are
-+ * aligned with the erasesize at the appropriate addresses.
-+ */
-+
-+ i = 0;
-+
-+ /* Skip all erase regions which are ended before the start of
-+ the requested erase. Actually, to save on the calculations,
-+ we skip to the first erase region which starts after the
-+ start of the requested erase, and then go back one.
-+ */
-+
-+ while (i < mtd->numeraseregions && ofs >= regions[i].offset)
-+ i++;
-+ i--;
-+
-+ /* OK, now i is pointing at the erase region in which this
-+ erase request starts. Check the start of the requested
-+ erase range is aligned with the erase size which is in
-+ effect here.
-+ */
-+
-+ if (ofs & (regions[i].erasesize-1))
-+ return -EINVAL;
-+
-+ /* Remember the erase region we start on */
-+ first = i;
-+
-+ /* Next, check that the end of the requested erase is aligned
-+ * with the erase region at that address.
-+ */
-+
-+ while (i<mtd->numeraseregions && (ofs + len) >= regions[i].offset)
-+ i++;
-+
-+ /* As before, drop back one to point at the region in which
-+ the address actually falls
-+ */
-+ i--;
-+
-+ if ((ofs + len) & (regions[i].erasesize-1))
-+ return -EINVAL;
-+
-+ chipnum = ofs >> cfi->chipshift;
-+ adr = ofs - (chipnum << cfi->chipshift);
-+
-+ i=first;
-+
-+ while(len) {
-+ int size = regions[i].erasesize;
-+
-+ ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk);
-+
-+ if (ret)
-+ return ret;
-+
-+ adr += size;
-+ ofs += size;
-+ len -= size;
-+
-+ if (ofs == regions[i].offset + size * regions[i].numblocks)
-+ i++;
-+
-+ if (adr >> cfi->chipshift) {
-+ adr = 0;
-+ chipnum++;
-+
-+ if (chipnum >= cfi->numchips)
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+EXPORT_SYMBOL(cfi_varsize_frob);
-+
-+MODULE_LICENSE("GPL");
---- linux-2.4.21/drivers/mtd/chips/chipreg.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/chips/chipreg.c
-@@ -1,5 +1,5 @@
- /*
-- * $Id: chipreg.c,v 1.13 2002/02/21 08:26:58 dwmw2 Exp $
-+ * $Id: chipreg.c,v 1.18 2005/01/12 22:34:34 gleixner Exp $
- *
- * Registration for chip drivers
- *
-@@ -7,12 +7,15 @@
-
- #include <linux/kernel.h>
- #include <linux/config.h>
-+#include <linux/module.h>
- #include <linux/kmod.h>
- #include <linux/spinlock.h>
--#include <linux/mtd/compatmac.h>
-+#include <linux/slab.h>
- #include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/compatmac.h>
-
--spinlock_t chip_drvs_lock = SPIN_LOCK_UNLOCKED;
-+static DEFINE_SPINLOCK(chip_drvs_lock);
- static LIST_HEAD(chip_drvs_list);
-
- void register_mtd_chip_driver(struct mtd_chip_driver *drv)
-@@ -44,10 +47,8 @@
- break;
- }
- }
-- if (ret && !try_inc_mod_count(ret->module)) {
-- /* Eep. Failed. */
-+ if (ret && !try_module_get(ret->module))
- ret = NULL;
-- }
-
- spin_unlock(&chip_drvs_lock);
-
-@@ -64,32 +65,46 @@
-
- drv = get_mtd_chip_driver(name);
-
-- if (!drv && !request_module(name))
-+ if (!drv && !request_module("%s", name))
- drv = get_mtd_chip_driver(name);
-
- if (!drv)
- return NULL;
-
- ret = drv->probe(map);
--#ifdef CONFIG_MODULES
-+
- /* We decrease the use count here. It may have been a
- probe-only module, which is no longer required from this
- point, having given us a handle on (and increased the use
- count of) the actual driver code.
- */
-- if(drv->module)
-- __MOD_DEC_USE_COUNT(drv->module);
--#endif
-+ module_put(drv->module);
-
- if (ret)
- return ret;
-
- return NULL;
- }
-+/*
-+ * Destroy an MTD device which was created for a map device.
-+ * Make sure the MTD device is already unregistered before calling this
-+ */
-+void map_destroy(struct mtd_info *mtd)
-+{
-+ struct map_info *map = mtd->priv;
-+
-+ if (map->fldrv->destroy)
-+ map->fldrv->destroy(mtd);
-+
-+ module_put(map->fldrv->module);
-+
-+ kfree(mtd);
-+}
-
- EXPORT_SYMBOL(register_mtd_chip_driver);
- EXPORT_SYMBOL(unregister_mtd_chip_driver);
- EXPORT_SYMBOL(do_map_probe);
-+EXPORT_SYMBOL(map_destroy);
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/chips/fwh_lock.h
-@@ -0,0 +1,107 @@
-+#ifndef FWH_LOCK_H
-+#define FWH_LOCK_H
-+
-+
-+enum fwh_lock_state {
-+ FWH_UNLOCKED = 0,
-+ FWH_DENY_WRITE = 1,
-+ FWH_IMMUTABLE = 2,
-+ FWH_DENY_READ = 4,
-+};
-+
-+struct fwh_xxlock_thunk {
-+ enum fwh_lock_state val;
-+ flstate_t state;
-+};
-+
-+
-+#define FWH_XXLOCK_ONEBLOCK_LOCK ((struct fwh_xxlock_thunk){ FWH_DENY_WRITE, FL_LOCKING})
-+#define FWH_XXLOCK_ONEBLOCK_UNLOCK ((struct fwh_xxlock_thunk){ FWH_UNLOCKED, FL_UNLOCKING})
-+
-+/*
-+ * This locking/unlock is specific to firmware hub parts. Only one
-+ * is known that supports the Intel command set. Firmware
-+ * hub parts cannot be interleaved as they are on the LPC bus
-+ * so this code has not been tested with interleaved chips,
-+ * and will likely fail in that context.
-+ */
-+static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip,
-+ unsigned long adr, int len, void *thunk)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ struct fwh_xxlock_thunk *xxlt = (struct fwh_xxlock_thunk *)thunk;
-+ int ret;
-+
-+ /* Refuse the operation if the we cannot look behind the chip */
-+ if (chip->start < 0x400000) {
-+ DEBUG( MTD_DEBUG_LEVEL3,
-+ "MTD %s(): chip->start: %lx wanted >= 0x400000\n",
-+ __func__, chip->start );
-+ return -EIO;
-+ }
-+ /*
-+ * lock block registers:
-+ * - on 64k boundariesand
-+ * - bit 1 set high
-+ * - block lock registers are 4MiB lower - overflow subtract (danger)
-+ *
-+ * The address manipulation is first done on the logical address
-+ * which is 0 at the start of the chip, and then the offset of
-+ * the individual chip is addted to it. Any other order a weird
-+ * map offset could cause problems.
-+ */
-+ adr = (adr & ~0xffffUL) | 0x2;
-+ adr += chip->start - 0x400000;
-+
-+ /*
-+ * This is easy because these are writes to registers and not writes
-+ * to flash memory - that means that we don't have to check status
-+ * and timeout.
-+ */
-+ cfi_spin_lock(chip->mutex);
-+ ret = get_chip(map, chip, adr, FL_LOCKING);
-+ if (ret) {
-+ cfi_spin_unlock(chip->mutex);
-+ return ret;
-+ }
-+
-+ chip->state = xxlt->state;
-+ map_write(map, CMD(xxlt->val), adr);
-+
-+ /* Done and happy. */
-+ chip->state = FL_READY;
-+ put_chip(map, chip, adr);
-+ cfi_spin_unlock(chip->mutex);
-+ return 0;
-+}
-+
-+
-+static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len)
-+{
-+ int ret;
-+
-+ ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len,
-+ (void *)&FWH_XXLOCK_ONEBLOCK_LOCK);
-+
-+ return ret;
-+}
-+
-+
-+static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len)
-+{
-+ int ret;
-+
-+ ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len,
-+ (void *)&FWH_XXLOCK_ONEBLOCK_UNLOCK);
-+
-+ return ret;
-+}
-+
-+static void fixup_use_fwh_lock(struct mtd_info *mtd, void *param)
-+{
-+ printk(KERN_NOTICE "using fwh lock/unlock method\n");
-+ /* Setup for the chips with the fwh lock method */
-+ mtd->lock = fwh_lock_varsize;
-+ mtd->unlock = fwh_unlock_varsize;
-+}
-+#endif /* FWH_LOCK_H */
---- linux-2.4.21/drivers/mtd/chips/gen_probe.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/chips/gen_probe.c
-@@ -1,11 +1,13 @@
- /*
- * Routines common to all CFI-type probes.
-- * (C) 2001, 2001 Red Hat, Inc.
-+ * (C) 2001-2003 Red Hat, Inc.
- * GPL'd
-- * $Id: gen_probe.c,v 1.9 2002/09/05 05:15:32 acurtis Exp $
-+ * $Id: gen_probe.c,v 1.22 2005/01/24 23:49:50 rmk Exp $
- */
-
- #include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/cfi.h>
-@@ -48,13 +50,13 @@
- EXPORT_SYMBOL(mtd_do_chip_probe);
-
-
--struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)
-+static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)
- {
-- unsigned long base=0;
- struct cfi_private cfi;
- struct cfi_private *retcfi;
-- struct flchip chip[MAX_CFI_CHIPS];
-- int i;
-+ unsigned long *chip_map;
-+ int i, j, mapsize;
-+ int max_chips;
-
- memset(&cfi, 0, sizeof(cfi));
-
-@@ -62,7 +64,7 @@
- interleave and device type, etc. */
- if (!genprobe_new_chip(map, cp, &cfi)) {
- /* The probe didn't like it */
-- printk(KERN_WARNING "%s: Found no %s device at location zero\n",
-+ printk(KERN_DEBUG "%s: Found no %s device at location zero\n",
- cp->name, map->name);
- return NULL;
- }
-@@ -77,46 +79,47 @@
- return NULL;
- }
- #endif
-- chip[0].start = 0;
-- chip[0].state = FL_READY;
- cfi.chipshift = cfi.cfiq->DevSize;
-
-- switch(cfi.interleave) {
--#ifdef CFIDEV_INTERLEAVE_1
-- case 1:
-- break;
--#endif
--#ifdef CFIDEV_INTERLEAVE_2
-- case 2:
-+ if (cfi_interleave_is_1(&cfi)) {
-+ ;
-+ } else if (cfi_interleave_is_2(&cfi)) {
- cfi.chipshift++;
-- break;
--#endif
--#ifdef CFIDEV_INTERLEAVE_4
-- case 4:
-- cfi.chipshift+=2;
-- break;
--#endif
-- default:
-+ } else if (cfi_interleave_is_4((&cfi))) {
-+ cfi.chipshift += 2;
-+ } else if (cfi_interleave_is_8(&cfi)) {
-+ cfi.chipshift += 3;
-+ } else {
- BUG();
- }
-
- cfi.numchips = 1;
-
- /*
-+ * Allocate memory for bitmap of valid chips.
-+ * Align bitmap storage size to full byte.
-+ */
-+ max_chips = map->size >> cfi.chipshift;
-+ mapsize = (max_chips / 8) + ((max_chips % 8) ? 1 : 0);
-+ chip_map = kmalloc(mapsize, GFP_KERNEL);
-+ if (!chip_map) {
-+ printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name);
-+ kfree(cfi.cfiq);
-+ return NULL;
-+ }
-+ memset (chip_map, 0, mapsize);
-+
-+ set_bit(0, chip_map); /* Mark first chip valid */
-+
-+ /*
- * Now probe for other chips, checking sensibly for aliases while
- * we're at it. The new_chip probe above should have let the first
- * chip in read mode.
-- *
-- * NOTE: Here, we're checking if there is room for another chip
-- * the same size within the mapping. Therefore,
-- * base + chipsize <= map->size is the correct thing to do,
-- * because, base + chipsize would be the _first_ byte of the
-- * next chip, not the one we're currently pondering.
- */
-
-- for (base = (1<<cfi.chipshift); base + (1<<cfi.chipshift) <= map->size;
-- base += (1<<cfi.chipshift))
-- cp->probe_chip(map, base, &chip[0], &cfi);
-+ for (i = 1; i < max_chips; i++) {
-+ cp->probe_chip(map, i << cfi.chipshift, chip_map, &cfi);
-+ }
-
- /*
- * Now allocate the space for the structures we need to return to
-@@ -128,19 +131,26 @@
- if (!retcfi) {
- printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name);
- kfree(cfi.cfiq);
-+ kfree(chip_map);
- return NULL;
- }
-
- memcpy(retcfi, &cfi, sizeof(cfi));
-- memcpy(&retcfi->chips[0], chip, sizeof(struct flchip) * cfi.numchips);
-+ memset(&retcfi->chips[0], 0, sizeof(struct flchip) * cfi.numchips);
-
-- /* Fix up the stuff that breaks when you move it */
-- for (i=0; i< retcfi->numchips; i++) {
-- init_waitqueue_head(&retcfi->chips[i].wq);
-- spin_lock_init(&retcfi->chips[i]._spinlock);
-- retcfi->chips[i].mutex = &retcfi->chips[i]._spinlock;
-+ for (i = 0, j = 0; (j < cfi.numchips) && (i < max_chips); i++) {
-+ if(test_bit(i, chip_map)) {
-+ struct flchip *pchip = &retcfi->chips[j++];
-+
-+ pchip->start = (i << cfi.chipshift);
-+ pchip->state = FL_READY;
-+ init_waitqueue_head(&pchip->wq);
-+ spin_lock_init(&pchip->_spinlock);
-+ pchip->mutex = &pchip->_spinlock;
-+ }
- }
-
-+ kfree(chip_map);
- return retcfi;
- }
-
-@@ -148,135 +158,36 @@
- static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
- struct cfi_private *cfi)
- {
-- switch (map->buswidth) {
--#ifdef CFIDEV_BUSWIDTH_1
-- case CFIDEV_BUSWIDTH_1:
-- cfi->interleave = CFIDEV_INTERLEAVE_1;
--
-- cfi->device_type = CFI_DEVICETYPE_X8;
-- if (cp->probe_chip(map, 0, NULL, cfi))
-- return 1;
--
-- cfi->device_type = CFI_DEVICETYPE_X16;
-- if (cp->probe_chip(map, 0, NULL, cfi))
-- return 1;
-- break;
--#endif /* CFIDEV_BUSWITDH_1 */
--
--#ifdef CFIDEV_BUSWIDTH_2
-- case CFIDEV_BUSWIDTH_2:
--#ifdef CFIDEV_INTERLEAVE_1
-- cfi->interleave = CFIDEV_INTERLEAVE_1;
--
-- cfi->device_type = CFI_DEVICETYPE_X16;
-- if (cp->probe_chip(map, 0, NULL, cfi))
-- return 1;
--#endif /* CFIDEV_INTERLEAVE_1 */
--#ifdef CFIDEV_INTERLEAVE_2
-- cfi->interleave = CFIDEV_INTERLEAVE_2;
--
-- cfi->device_type = CFI_DEVICETYPE_X8;
-- if (cp->probe_chip(map, 0, NULL, cfi))
-- return 1;
--
-- cfi->device_type = CFI_DEVICETYPE_X16;
-- if (cp->probe_chip(map, 0, NULL, cfi))
-- return 1;
--#endif /* CFIDEV_INTERLEAVE_2 */
-- break;
--#endif /* CFIDEV_BUSWIDTH_2 */
--
--#ifdef CFIDEV_BUSWIDTH_4
-- case CFIDEV_BUSWIDTH_4:
--#if defined(CFIDEV_INTERLEAVE_1) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
-- cfi->interleave = CFIDEV_INTERLEAVE_1;
--
-- cfi->device_type = CFI_DEVICETYPE_X32;
-- if (cp->probe_chip(map, 0, NULL, cfi))
-- return 1;
--#endif /* CFIDEV_INTERLEAVE_1 */
--#ifdef CFIDEV_INTERLEAVE_2
-- cfi->interleave = CFIDEV_INTERLEAVE_2;
--
--#ifdef SOMEONE_ACTUALLY_MAKES_THESE
-- cfi->device_type = CFI_DEVICETYPE_X32;
-- if (cp->probe_chip(map, 0, NULL, cfi))
-- return 1;
--#endif
-- cfi->device_type = CFI_DEVICETYPE_X16;
-- if (cp->probe_chip(map, 0, NULL, cfi))
-- return 1;
--
-- cfi->device_type = CFI_DEVICETYPE_X8;
-- if (cp->probe_chip(map, 0, NULL, cfi))
-- return 1;
--#endif /* CFIDEV_INTERLEAVE_2 */
--#ifdef CFIDEV_INTERLEAVE_4
-- cfi->interleave = CFIDEV_INTERLEAVE_4;
--
--#ifdef SOMEONE_ACTUALLY_MAKES_THESE
-- cfi->device_type = CFI_DEVICETYPE_X32;
-- if (cp->probe_chip(map, 0, NULL, cfi))
-- return 1;
--#endif
-- cfi->device_type = CFI_DEVICETYPE_X16;
-- if (cp->probe_chip(map, 0, NULL, cfi))
-- return 1;
-+ int min_chips = (map_bankwidth(map)/4?:1); /* At most 4-bytes wide. */
-+ int max_chips = map_bankwidth(map); /* And minimum 1 */
-+ int nr_chips, type;
-
-- cfi->device_type = CFI_DEVICETYPE_X8;
-- if (cp->probe_chip(map, 0, NULL, cfi))
-- return 1;
--#endif /* CFIDEV_INTERLEAVE_4 */
-- break;
--#endif /* CFIDEV_BUSWIDTH_4 */
-+ for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) {
-
--#ifdef CFIDEV_BUSWIDTH_8
-- case CFIDEV_BUSWIDTH_8:
--#if defined(CFIDEV_INTERLEAVE_2) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
-- cfi->interleave = CFIDEV_INTERLEAVE_2;
-+ if (!cfi_interleave_supported(nr_chips))
-+ continue;
-
-- cfi->device_type = CFI_DEVICETYPE_X32;
-- if (cp->probe_chip(map, 0, NULL, cfi))
-- return 1;
--#endif /* CFIDEV_INTERLEAVE_2 */
--#ifdef CFIDEV_INTERLEAVE_4
-- cfi->interleave = CFIDEV_INTERLEAVE_4;
-+ cfi->interleave = nr_chips;
-
--#ifdef SOMEONE_ACTUALLY_MAKES_THESE
-- cfi->device_type = CFI_DEVICETYPE_X32;
-- if (cp->probe_chip(map, 0, NULL, cfi))
-- return 1;
--#endif
-- cfi->device_type = CFI_DEVICETYPE_X16;
-- if (cp->probe_chip(map, 0, NULL, cfi))
-- return 1;
--#endif /* CFIDEV_INTERLEAVE_4 */
--#ifdef CFIDEV_INTERLEAVE_8
-- cfi->interleave = CFIDEV_INTERLEAVE_8;
-+ /* Minimum device size. Don't look for one 8-bit device
-+ in a 16-bit bus, etc. */
-+ type = map_bankwidth(map) / nr_chips;
-
-- cfi->device_type = CFI_DEVICETYPE_X16;
-- if (cp->probe_chip(map, 0, NULL, cfi))
-- return 1;
-+ for (; type <= CFI_DEVICETYPE_X32; type<<=1) {
-+ cfi->device_type = type;
-
-- cfi->device_type = CFI_DEVICETYPE_X8;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
--#endif /* CFIDEV_INTERLEAVE_8 */
-- break;
--#endif /* CFIDEV_BUSWIDTH_8 */
--
-- default:
-- printk(KERN_WARNING "genprobe_new_chip called with unsupported buswidth %d\n", map->buswidth);
-- return 0;
-+ }
- }
- return 0;
- }
-
--
- typedef struct mtd_info *cfi_cmdset_fn_t(struct map_info *, int);
-
- extern cfi_cmdset_fn_t cfi_cmdset_0001;
- extern cfi_cmdset_fn_t cfi_cmdset_0002;
-+extern cfi_cmdset_fn_t cfi_cmdset_0020;
-
- static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map,
- int primary)
---- linux-2.4.21/drivers/mtd/chips/jedec.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/chips/jedec.c
-@@ -11,10 +11,16 @@
- * not going to guess how to send commands to them, plus I expect they will
- * all speak CFI..
- *
-- * $Id: jedec.c,v 1.14 2002/06/27 02:19:12 dwmw2 Exp $
-+ * $Id: jedec.c,v 1.22 2005/01/05 18:05:11 dwmw2 Exp $
- */
-
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
- #include <linux/mtd/jedec.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/compatmac.h>
-
- static struct mtd_info *jedec_probe(struct map_info *);
- static int jedec_probe8(struct map_info *map,unsigned long base,
-@@ -33,14 +39,51 @@
-
- /* Listing of parts and sizes. We need this table to learn the sector
- size of the chip and the total length */
--static const struct JEDECTable JEDEC_table[] =
-- {{0x013D,"AMD Am29F017D",2*1024*1024,64*1024,MTD_CAP_NORFLASH},
-- {0x01AD,"AMD Am29F016",2*1024*1024,64*1024,MTD_CAP_NORFLASH},
-- {0x01D5,"AMD Am29F080",1*1024*1024,64*1024,MTD_CAP_NORFLASH},
-- {0x01A4,"AMD Am29F040",512*1024,64*1024,MTD_CAP_NORFLASH},
-- {0x20E3,"AMD Am29W040B",512*1024,64*1024,MTD_CAP_NORFLASH},
-- {0xC2AD,"Macronix MX29F016",2*1024*1024,64*1024,MTD_CAP_NORFLASH},
-- {}};
-+static const struct JEDECTable JEDEC_table[] = {
-+ {
-+ .jedec = 0x013D,
-+ .name = "AMD Am29F017D",
-+ .size = 2*1024*1024,
-+ .sectorsize = 64*1024,
-+ .capabilities = MTD_CAP_NORFLASH
-+ },
-+ {
-+ .jedec = 0x01AD,
-+ .name = "AMD Am29F016",
-+ .size = 2*1024*1024,
-+ .sectorsize = 64*1024,
-+ .capabilities = MTD_CAP_NORFLASH
-+ },
-+ {
-+ .jedec = 0x01D5,
-+ .name = "AMD Am29F080",
-+ .size = 1*1024*1024,
-+ .sectorsize = 64*1024,
-+ .capabilities = MTD_CAP_NORFLASH
-+ },
-+ {
-+ .jedec = 0x01A4,
-+ .name = "AMD Am29F040",
-+ .size = 512*1024,
-+ .sectorsize = 64*1024,
-+ .capabilities = MTD_CAP_NORFLASH
-+ },
-+ {
-+ .jedec = 0x20E3,
-+ .name = "AMD Am29W040B",
-+ .size = 512*1024,
-+ .sectorsize = 64*1024,
-+ .capabilities = MTD_CAP_NORFLASH
-+ },
-+ {
-+ .jedec = 0xC2AD,
-+ .name = "Macronix MX29F016",
-+ .size = 2*1024*1024,
-+ .sectorsize = 64*1024,
-+ .capabilities = MTD_CAP_NORFLASH
-+ },
-+ { .jedec = 0x0 }
-+};
-
- static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id);
- static void jedec_sync(struct mtd_info *mtd) {};
-@@ -54,9 +97,9 @@
-
-
- static struct mtd_chip_driver jedec_chipdrv = {
-- probe: jedec_probe,
-- name: "jedec",
-- module: THIS_MODULE
-+ .probe = jedec_probe,
-+ .name = "jedec",
-+ .module = THIS_MODULE
- };
-
- /* Probe entry point */
-@@ -85,7 +128,7 @@
- {
- printk("mtd: Increase MAX_JEDEC_CHIPS, too many banks.\n");
- kfree(MTD);
-- return 0;
-+ return NULL;
- }
-
- for (Base = 0; Base < map->size; Base += my_bank_size)
-@@ -98,7 +141,7 @@
- if (jedec_probe8(map,Base,priv) == 0) {
- printk("did recognize jedec chip\n");
- kfree(MTD);
-- return 0;
-+ return NULL;
- }
- }
- if (map->buswidth == 2)
-@@ -124,15 +167,14 @@
- {
- printk("mtd: Failed. Device has incompatible mixed sector sizes\n");
- kfree(MTD);
-- return 0;
-+ return NULL;
- }
- }
-
- /* Generate a part name that includes the number of different chips and
- other configuration information */
- count = 1;
-- strncpy(Part,map->name,sizeof(Part)-10);
-- Part[sizeof(Part)-11] = 0;
-+ strlcpy(Part,map->name,sizeof(Part)-10);
- strcat(Part," ");
- Uniq = 0;
- for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-@@ -151,7 +193,7 @@
- {
- printk("mtd: Internal Error, JEDEC not set\n");
- kfree(MTD);
-- return 0;
-+ return NULL;
- }
-
- if (Uniq != 0)
-@@ -179,7 +221,7 @@
- if (!priv->size) {
- printk("priv->size is zero\n");
- kfree(MTD);
-- return 0;
-+ return NULL;
- }
- if (priv->size/my_bank_size) {
- if (priv->size/my_bank_size == 1) {
-@@ -198,7 +240,7 @@
- {
- printk("mtd: Failed. Cannot handle unsymmetric banking\n");
- kfree(MTD);
-- return 0;
-+ return NULL;
- }
- }
- }
-@@ -209,8 +251,7 @@
- // printk("Part: '%s'\n",Part);
-
- memset(MTD,0,sizeof(*MTD));
-- // strncpy(MTD->name,Part,sizeof(MTD->name));
-- // MTD->name[sizeof(MTD->name)-1] = 0;
-+ // strlcpy(MTD->name,Part,sizeof(MTD->name));
- MTD->name = map->name;
- MTD->type = MTD_NORFLASH;
- MTD->flags = MTD_CAP_NORFLASH;
-@@ -229,7 +270,7 @@
- MTD->priv = map;
- map->fldrv_priv = priv;
- map->fldrv = &jedec_chipdrv;
-- MOD_INC_USE_COUNT;
-+ __module_get(THIS_MODULE);
- return MTD;
- }
-
-@@ -344,15 +385,15 @@
- for (I = 0; JEDEC_table[I].jedec != 0; I++)
- if (JEDEC_table[I].jedec == Id)
- return JEDEC_table + I;
-- return 0;
-+ return NULL;
- }
-
- // Look for flash using an 8 bit bus interface
- static int jedec_probe8(struct map_info *map,unsigned long base,
- struct jedec_private *priv)
- {
-- #define flread(x) map->read8(map,base+x)
-- #define flwrite(v,x) map->write8(map,v,base+x)
-+ #define flread(x) map_read8(map,base+x)
-+ #define flwrite(v,x) map_write8(map,v,base+x)
-
- const unsigned long AutoSel1 = 0xAA;
- const unsigned long AutoSel2 = 0x55;
-@@ -411,8 +452,8 @@
- static int jedec_probe32(struct map_info *map,unsigned long base,
- struct jedec_private *priv)
- {
-- #define flread(x) map->read32(map,base+((x)<<2))
-- #define flwrite(v,x) map->write32(map,v,base+((x)<<2))
-+ #define flread(x) map_read32(map,base+((x)<<2))
-+ #define flwrite(v,x) map_write32(map,v,base+((x)<<2))
-
- const unsigned long AutoSel1 = 0xAAAAAAAA;
- const unsigned long AutoSel2 = 0x55555555;
-@@ -488,9 +529,9 @@
- static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
- {
-- struct map_info *map = (struct map_info *)mtd->priv;
-+ struct map_info *map = mtd->priv;
-
-- map->copy_from(map, buf, from, len);
-+ map_copy_from(map, buf, from, len);
- *retlen = len;
- return 0;
- }
-@@ -500,8 +541,8 @@
- static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
- {
-- struct map_info *map = (struct map_info *)mtd->priv;
-- struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv;
-+ struct map_info *map = mtd->priv;
-+ struct jedec_private *priv = map->fldrv_priv;
-
- *retlen = 0;
- while (len > 0)
-@@ -514,7 +555,7 @@
- get = priv->bank_fill[0] - offset;
-
- bank /= priv->bank_fill[0];
-- map->copy_from(map,buf + *retlen,bank*my_bank_size + offset,get);
-+ map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get);
-
- len -= get;
- *retlen += get;
-@@ -545,15 +586,15 @@
- static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
- {
- // Does IO to the currently selected chip
-- #define flread(x) map->read8(map,chip->base+((x)<<chip->addrshift))
-- #define flwrite(v,x) map->write8(map,v,chip->base+((x)<<chip->addrshift))
-+ #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift))
-+ #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift))
-
- unsigned long Time = 0;
- unsigned long NoTime = 0;
- unsigned long start = instr->addr, len = instr->len;
- unsigned int I;
-- struct map_info *map = (struct map_info *)mtd->priv;
-- struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv;
-+ struct map_info *map = mtd->priv;
-+ struct jedec_private *priv = map->fldrv_priv;
-
- // Verify the arguments..
- if (start + len > mtd->size ||
-@@ -608,7 +649,7 @@
-
- /* Poll the flash for erasure completion, specs say this can take as long
- as 480 seconds to do all the sectors (for a 2 meg flash).
-- Erasure time is dependant on chip age, temp and wear.. */
-+ Erasure time is dependent on chip age, temp and wear.. */
-
- /* This being a generic routine assumes a 32 bit bus. It does read32s
- and bundles interleved chips into the same grouping. This will work
-@@ -651,19 +692,19 @@
- or this is not really flash ;> */
- switch (map->buswidth) {
- case 1:
-- Last[0] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-- Last[1] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-- Last[2] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[0] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[1] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[2] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- case 2:
-- Last[0] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-- Last[1] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-- Last[2] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[0] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[1] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[2] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- case 3:
-- Last[0] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-- Last[1] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-- Last[2] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[0] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[1] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[2] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- }
- Count = 3;
-@@ -699,13 +740,13 @@
-
- switch (map->buswidth) {
- case 1:
-- Last[Count % 4] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[Count % 4] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- case 2:
-- Last[Count % 4] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[Count % 4] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- case 4:
-- Last[Count % 4] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[Count % 4] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- }
- Count++;
-@@ -739,8 +780,7 @@
-
- //printk("done\n");
- instr->state = MTD_ERASE_DONE;
-- if (instr->callback)
-- instr->callback(instr);
-+ mtd_erase_callback(instr);
- return 0;
-
- #undef flread
-@@ -755,13 +795,13 @@
- size_t *retlen, const u_char *buf)
- {
- /* Does IO to the currently selected chip. It takes the bank addressing
-- base (which is divisable by the chip size) adds the necesary lower bits
-- of addrshift (interleve index) and then adds the control register index. */
-- #define flread(x) map->read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-- #define flwrite(v,x) map->write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-+ base (which is divisible by the chip size) adds the necessary lower bits
-+ of addrshift (interleave index) and then adds the control register index. */
-+ #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-+ #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-
-- struct map_info *map = (struct map_info *)mtd->priv;
-- struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv;
-+ struct map_info *map = mtd->priv;
-+ struct jedec_private *priv = map->fldrv_priv;
- unsigned long base;
- unsigned long off;
- size_t save_len = len;
-@@ -794,7 +834,7 @@
- // Loop over this page
- for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++)
- {
-- unsigned char oldbyte = map->read8(map,base+off);
-+ unsigned char oldbyte = map_read8(map,base+off);
- unsigned char Last[4];
- unsigned long Count = 0;
-
-@@ -809,10 +849,10 @@
- flwrite(0xAA,0x555);
- flwrite(0x55,0x2AA);
- flwrite(0xA0,0x555);
-- map->write8(map,*buf,base + off);
-- Last[0] = map->read8(map,base + off);
-- Last[1] = map->read8(map,base + off);
-- Last[2] = map->read8(map,base + off);
-+ map_write8(map,*buf,base + off);
-+ Last[0] = map_read8(map,base + off);
-+ Last[1] = map_read8(map,base + off);
-+ Last[2] = map_read8(map,base + off);
-
- /* Wait for the flash to finish the operation. We store the last 4
- status bytes that have been retrieved so we can determine why
-@@ -820,7 +860,7 @@
- failure */
- for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] &&
- Count < 10000; Count++)
-- Last[Count % 4] = map->read8(map,base + off);
-+ Last[Count % 4] = map_read8(map,base + off);
- if (Last[(Count - 1) % 4] != *buf)
- {
- jedec_flash_failed(Last[(Count - 3) % 4]);
---- linux-2.4.21/drivers/mtd/chips/jedec_probe.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/chips/jedec_probe.c
-@@ -1,13 +1,16 @@
- /*
- Common Flash Interface probe code.
- (C) 2000 Red Hat. GPL'd.
-- $Id: jedec_probe.c,v 1.19 2002/11/12 13:12:10 dwmw2 Exp $
-+ $Id: jedec_probe.c,v 1.63 2005/02/14 16:30:32 bjd Exp $
- See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
- for the standard this probe goes back to.
-+
-+ Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
- */
-
- #include <linux/config.h>
- #include <linux/module.h>
-+#include <linux/init.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <asm/io.h>
-@@ -15,7 +18,9 @@
- #include <linux/errno.h>
- #include <linux/slab.h>
- #include <linux/interrupt.h>
-+#include <linux/init.h>
-
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/cfi.h>
- #include <linux/mtd/gen_probe.h>
-@@ -24,26 +29,35 @@
- #define MANUFACTURER_AMD 0x0001
- #define MANUFACTURER_ATMEL 0x001f
- #define MANUFACTURER_FUJITSU 0x0004
-+#define MANUFACTURER_HYUNDAI 0x00AD
- #define MANUFACTURER_INTEL 0x0089
- #define MANUFACTURER_MACRONIX 0x00C2
--#define MANUFACTURER_ST 0x0020
-+#define MANUFACTURER_PMC 0x009D
- #define MANUFACTURER_SST 0x00BF
-+#define MANUFACTURER_ST 0x0020
- #define MANUFACTURER_TOSHIBA 0x0098
-+#define MANUFACTURER_WINBOND 0x00da
-
-
- /* AMD */
-+#define AM29DL800BB 0x22C8
-+#define AM29DL800BT 0x224A
-+
- #define AM29F800BB 0x2258
- #define AM29F800BT 0x22D6
-+#define AM29LV400BB 0x22BA
-+#define AM29LV400BT 0x22B9
- #define AM29LV800BB 0x225B
- #define AM29LV800BT 0x22DA
- #define AM29LV160DT 0x22C4
- #define AM29LV160DB 0x2249
- #define AM29F017D 0x003D
--#define AM29F016 0x00AD
-+#define AM29F016D 0x00AD
- #define AM29F080 0x00D5
- #define AM29F040 0x00A4
- #define AM29LV040B 0x004F
- #define AM29F032B 0x0041
-+#define AM29F002T 0x00B0
-
- /* Atmel */
- #define AT49BV512 0x0003
-@@ -54,6 +68,7 @@
- #define AT49BV32XT 0x00C9
-
- /* Fujitsu */
-+#define MBM29F040C 0x00A4
- #define MBM29LV650UE 0x22D7
- #define MBM29LV320TE 0x22F6
- #define MBM29LV320BE 0x22F9
-@@ -61,6 +76,11 @@
- #define MBM29LV160BE 0x2249
- #define MBM29LV800BA 0x225B
- #define MBM29LV800TA 0x22DA
-+#define MBM29LV400TC 0x22B9
-+#define MBM29LV400BC 0x22BA
-+
-+/* Hyundai */
-+#define HY29F002T 0x00B0
-
- /* Intel */
- #define I28F004B3T 0x00d4
-@@ -87,29 +107,46 @@
- #define I82802AC 0x00ac
-
- /* Macronix */
-+#define MX29LV040C 0x004F
- #define MX29LV160T 0x22C4
- #define MX29LV160B 0x2249
- #define MX29F016 0x00AD
-+#define MX29F002T 0x00B0
- #define MX29F004T 0x0045
- #define MX29F004B 0x0046
-
-+/* PMC */
-+#define PM49FL002 0x006D
-+#define PM49FL004 0x006E
-+#define PM49FL008 0x006A
-+
- /* ST - www.st.com */
--#define M29W800T 0x00D7
-+#define M29W800DT 0x00D7
-+#define M29W800DB 0x005B
- #define M29W160DT 0x22C4
- #define M29W160DB 0x2249
- #define M29W040B 0x00E3
-+#define M50FW040 0x002C
-+#define M50FW080 0x002D
-+#define M50FW016 0x002E
-+#define M50LPW080 0x002F
-
- /* SST */
-+#define SST29EE020 0x0010
-+#define SST29LE020 0x0012
- #define SST29EE512 0x005d
- #define SST29LE512 0x003d
- #define SST39LF800 0x2781
- #define SST39LF160 0x2782
-+#define SST39VF1601 0x234b
- #define SST39LF512 0x00D4
- #define SST39LF010 0x00D5
- #define SST39LF020 0x00D6
- #define SST39LF040 0x00D7
- #define SST39SF010A 0x00B5
- #define SST39SF020A 0x00B6
-+#define SST49LF004B 0x0060
-+#define SST49LF008A 0x005a
- #define SST49LF030A 0x001C
- #define SST49LF040A 0x0051
- #define SST49LF080A 0x005B
-@@ -122,16 +159,93 @@
- #define TC58FVT641 0x0093
- #define TC58FVB641 0x0095
-
-+/* Winbond */
-+#define W49V002A 0x00b0
-+
-+
-+/*
-+ * Unlock address sets for AMD command sets.
-+ * Intel command sets use the MTD_UADDR_UNNECESSARY.
-+ * Each identifier, except MTD_UADDR_UNNECESSARY, and
-+ * MTD_UADDR_NO_SUPPORT must be defined below in unlock_addrs[].
-+ * MTD_UADDR_NOT_SUPPORTED must be 0 so that structure
-+ * initialization need not require initializing all of the
-+ * unlock addresses for all bit widths.
-+ */
-+enum uaddr {
-+ MTD_UADDR_NOT_SUPPORTED = 0, /* data width not supported */
-+ MTD_UADDR_0x0555_0x02AA,
-+ MTD_UADDR_0x0555_0x0AAA,
-+ MTD_UADDR_0x5555_0x2AAA,
-+ MTD_UADDR_0x0AAA_0x0555,
-+ MTD_UADDR_DONT_CARE, /* Requires an arbitrary address */
-+ MTD_UADDR_UNNECESSARY, /* Does not require any address */
-+};
-+
-+
-+struct unlock_addr {
-+ u32 addr1;
-+ u32 addr2;
-+};
-+
-+
-+/*
-+ * I don't like the fact that the first entry in unlock_addrs[]
-+ * exists, but is for MTD_UADDR_NOT_SUPPORTED - and, therefore,
-+ * should not be used. The problem is that structures with
-+ * initializers have extra fields initialized to 0. It is _very_
-+ * desireable to have the unlock address entries for unsupported
-+ * data widths automatically initialized - that means that
-+ * MTD_UADDR_NOT_SUPPORTED must be 0 and the first entry here
-+ * must go unused.
-+ */
-+static const struct unlock_addr unlock_addrs[] = {
-+ [MTD_UADDR_NOT_SUPPORTED] = {
-+ .addr1 = 0xffff,
-+ .addr2 = 0xffff
-+ },
-+
-+ [MTD_UADDR_0x0555_0x02AA] = {
-+ .addr1 = 0x0555,
-+ .addr2 = 0x02aa
-+ },
-+
-+ [MTD_UADDR_0x0555_0x0AAA] = {
-+ .addr1 = 0x0555,
-+ .addr2 = 0x0aaa
-+ },
-+
-+ [MTD_UADDR_0x5555_0x2AAA] = {
-+ .addr1 = 0x5555,
-+ .addr2 = 0x2aaa
-+ },
-+
-+ [MTD_UADDR_0x0AAA_0x0555] = {
-+ .addr1 = 0x0AAA,
-+ .addr2 = 0x0555
-+ },
-+
-+ [MTD_UADDR_DONT_CARE] = {
-+ .addr1 = 0x0000, /* Doesn't matter which address */
-+ .addr2 = 0x0000 /* is used - must be last entry */
-+ },
-+
-+ [MTD_UADDR_UNNECESSARY] = {
-+ .addr1 = 0x0000,
-+ .addr2 = 0x0000
-+ }
-+};
-+
-
- struct amd_flash_info {
- const __u16 mfr_id;
- const __u16 dev_id;
- const char *name;
- const int DevSize;
-- const int InterfaceDesc;
- const int NumEraseRegions;
- const int CmdSet;
-- const ulong regions[4];
-+ const __u8 uaddr[4]; /* unlock addrs for 8, 16, 32, 64 */
-+ const ulong regions[6];
- };
-
- #define ERASEINFO(size,blocks) (size<<8)|(blocks-1)
-@@ -145,760 +259,1434 @@
- #define SIZE_4MiB 22
- #define SIZE_8MiB 23
-
-+
-+/*
-+ * Please keep this list ordered by manufacturer!
-+ * Fortunately, the list isn't searched often and so a
-+ * slow, linear search isn't so bad.
-+ */
- static const struct amd_flash_info jedec_table[] = {
- {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F032B,
-- name: "AMD AM29F032B",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,64)
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F032B,
-+ .name = "AMD AM29F032B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,64)
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV160DT,
-- name: "AMD AM29LV160DT",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,31),
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV160DT,
-+ .name = "AMD AM29LV160DT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,31),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV160DB,
-- name: "AMD AM29LV160DB",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV160DB,
-+ .name = "AMD AM29LV160DB",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x10000,31)
- }
- }, {
-- mfr_id: MANUFACTURER_TOSHIBA,
-- dev_id: TC58FVT160,
-- name: "Toshiba TC58FVT160",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,31),
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV400BB,
-+ .name = "AMD AM29LV400BB",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x10000,7)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV400BT,
-+ .name = "AMD AM29LV400BT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,7),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_TOSHIBA,
-- dev_id: TC58FVB160,
-- name: "Toshiba TC58FVB160",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV800BB,
-+ .name = "AMD AM29LV800BB",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x08000,1),
-- ERASEINFO(0x10000,31)
-+ ERASEINFO(0x10000,15),
- }
- }, {
-- mfr_id: MANUFACTURER_TOSHIBA,
-- dev_id: TC58FVB321,
-- name: "Toshiba TC58FVB321",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x02000,8),
-- ERASEINFO(0x10000,63)
-+/* add DL */
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29DL800BB,
-+ .name = "AMD AM29DL800BB",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 6,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x02000,4),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x04000,1),
-+ ERASEINFO(0x10000,14)
- }
- }, {
-- mfr_id: MANUFACTURER_TOSHIBA,
-- dev_id: TC58FVT321,
-- name: "Toshiba TC58FVT321",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x10000,63),
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29DL800BT,
-+ .name = "AMD AM29DL800BT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 6,
-+ .regions = {
-+ ERASEINFO(0x10000,14),
-+ ERASEINFO(0x04000,1),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x02000,4),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x04000,1)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F800BB,
-+ .name = "AMD AM29F800BB",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x10000,15),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV800BT,
-+ .name = "AMD AM29LV800BT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,15),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x04000,1)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F800BT,
-+ .name = "AMD AM29F800BT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,15),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x04000,1)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F017D,
-+ .name = "AMD AM29F017D",
-+ .uaddr = {
-+ [0] = MTD_UADDR_DONT_CARE /* x8 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,32),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F016D,
-+ .name = "AMD AM29F016D",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,32),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F080,
-+ .name = "AMD AM29F080",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,16),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F040,
-+ .name = "AMD AM29F040",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,8),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV040B,
-+ .name = "AMD AM29LV040B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,8),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F002T,
-+ .name = "AMD AM29F002T",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_256KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,3),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x04000,1),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_ATMEL,
-+ .dev_id = AT49BV512,
-+ .name = "Atmel AT49BV512",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_64KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,1)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_ATMEL,
-+ .dev_id = AT29LV512,
-+ .name = "Atmel AT29LV512",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_64KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x80,256),
-+ ERASEINFO(0x80,256)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_ATMEL,
-+ .dev_id = AT49BV16X,
-+ .name = "Atmel AT49BV16X",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x02000,8),
-+ ERASEINFO(0x10000,31)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_ATMEL,
-+ .dev_id = AT49BV16XT,
-+ .name = "Atmel AT49BV16XT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x10000,31),
- ERASEINFO(0x02000,8)
- }
- }, {
-- mfr_id: MANUFACTURER_TOSHIBA,
-- dev_id: TC58FVB641,
-- name: "Toshiba TC58FVB641",
-- DevSize: SIZE_8MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x02000,8),
-- ERASEINFO(0x10000,127)
-+ .mfr_id = MANUFACTURER_ATMEL,
-+ .dev_id = AT49BV32X,
-+ .name = "Atmel AT49BV32X",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x02000,8),
-+ ERASEINFO(0x10000,63)
- }
- }, {
-- mfr_id: MANUFACTURER_TOSHIBA,
-- dev_id: TC58FVT641,
-- name: "Toshiba TC58FVT641",
-- DevSize: SIZE_8MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x10000,127),
-+ .mfr_id = MANUFACTURER_ATMEL,
-+ .dev_id = AT49BV32XT,
-+ .name = "Atmel AT49BV32XT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x10000,63),
- ERASEINFO(0x02000,8)
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV650UE,
-- name: "Fujitsu MBM29LV650UE",
-- DevSize: SIZE_8MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,128)
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29F040C,
-+ .name = "Fujitsu MBM29F040C",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,8)
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV320TE,
-- name: "Fujitsu MBM29LV320TE",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x10000,63),
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV650UE,
-+ .name = "Fujitsu MBM29LV650UE",
-+ .uaddr = {
-+ [0] = MTD_UADDR_DONT_CARE /* x16 */
-+ },
-+ .DevSize = SIZE_8MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,128)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV320TE,
-+ .name = "Fujitsu MBM29LV320TE",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x10000,63),
- ERASEINFO(0x02000,8)
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV320BE,
-- name: "Fujitsu MBM29LV320BE",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x02000,8),
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV320BE,
-+ .name = "Fujitsu MBM29LV320BE",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x02000,8),
- ERASEINFO(0x10000,63)
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV160TE,
-- name: "Fujitsu MBM29LV160TE",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,31),
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV160TE,
-+ .name = "Fujitsu MBM29LV160TE",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,31),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV160BE,
-- name: "Fujitsu MBM29LV160BE",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV160BE,
-+ .name = "Fujitsu MBM29LV160BE",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x10000,31)
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV800BA,
-- name: "Fujitsu MBM29LV800BA",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV800BA,
-+ .name = "Fujitsu MBM29LV800BA",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x10000,15)
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV800TA,
-- name: "Fujitsu MBM29LV800TA",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,15),
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV800TA,
-+ .name = "Fujitsu MBM29LV800TA",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,15),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV800BB,
-- name: "AMD AM29LV800BB",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-- ERASEINFO(0x02000,2),
-- ERASEINFO(0x08000,1),
-- ERASEINFO(0x10000,15),
-- }
-- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F800BB,
-- name: "AMD AM29F800BB",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV400BC,
-+ .name = "Fujitsu MBM29LV400BC",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x08000,1),
-- ERASEINFO(0x10000,15),
-- }
-- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV800BT,
-- name: "AMD AM29LV800BT",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,15),
-- ERASEINFO(0x08000,1),
-- ERASEINFO(0x02000,2),
-- ERASEINFO(0x04000,1)
-+ ERASEINFO(0x10000,7)
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F800BT,
-- name: "AMD AM29F800BT",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,15),
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV400TC,
-+ .name = "Fujitsu MBM29LV400TC",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,7),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV800BB,
-- name: "AMD AM29LV800BB",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,15),
-+ .mfr_id = MANUFACTURER_HYUNDAI,
-+ .dev_id = HY29F002T,
-+ .name = "Hyundai HY29F002T",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_256KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,3),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
-- ERASEINFO(0x04000,1)
-+ ERASEINFO(0x04000,1),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F004B3B,
-- name: "Intel 28F004B3B",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F004B3B,
-+ .name = "Intel 28F004B3B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x02000, 8),
- ERASEINFO(0x10000, 7),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F004B3T,
-- name: "Intel 28F004B3T",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F004B3T,
-+ .name = "Intel 28F004B3T",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x10000, 7),
- ERASEINFO(0x02000, 8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F400B3B,
-- name: "Intel 28F400B3B",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F400B3B,
-+ .name = "Intel 28F400B3B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x02000, 8),
- ERASEINFO(0x10000, 7),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F400B3T,
-- name: "Intel 28F400B3T",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F400B3T,
-+ .name = "Intel 28F400B3T",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x10000, 7),
- ERASEINFO(0x02000, 8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F008B3B,
-- name: "Intel 28F008B3B",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F008B3B,
-+ .name = "Intel 28F008B3B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x02000, 8),
- ERASEINFO(0x10000, 15),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F008B3T,
-- name: "Intel 28F008B3T",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F008B3T,
-+ .name = "Intel 28F008B3T",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x10000, 15),
- ERASEINFO(0x02000, 8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F008S5,
-- name: "Intel 28F008S5",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_INTEL_EXT,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,16),
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F008S5,
-+ .name = "Intel 28F008S5",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_INTEL_EXT,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,16),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F016S5,
-- name: "Intel 28F016S5",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_INTEL_EXT,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,32),
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F016S5,
-+ .name = "Intel 28F016S5",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_INTEL_EXT,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,32),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F008SA,
-- name: "Intel 28F008SA",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 1,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F008SA,
-+ .name = "Intel 28F008SA",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
- ERASEINFO(0x10000, 16),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F800B3B,
-- name: "Intel 28F800B3B",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F800B3B,
-+ .name = "Intel 28F800B3B",
-+ .uaddr = {
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x02000, 8),
- ERASEINFO(0x10000, 15),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F800B3T,
-- name: "Intel 28F800B3T",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F800B3T,
-+ .name = "Intel 28F800B3T",
-+ .uaddr = {
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x10000, 15),
- ERASEINFO(0x02000, 8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F016B3B,
-- name: "Intel 28F016B3B",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F016B3B,
-+ .name = "Intel 28F016B3B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x02000, 8),
- ERASEINFO(0x10000, 31),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F016S3,
-- name: "Intel I28F016S3",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 1,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F016S3,
-+ .name = "Intel I28F016S3",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
- ERASEINFO(0x10000, 32),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F016B3T,
-- name: "Intel 28F016B3T",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F016B3T,
-+ .name = "Intel 28F016B3T",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x10000, 31),
- ERASEINFO(0x02000, 8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F160B3B,
-- name: "Intel 28F160B3B",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F160B3B,
-+ .name = "Intel 28F160B3B",
-+ .uaddr = {
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x02000, 8),
- ERASEINFO(0x10000, 31),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F160B3T,
-- name: "Intel 28F160B3T",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F160B3T,
-+ .name = "Intel 28F160B3T",
-+ .uaddr = {
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x10000, 31),
- ERASEINFO(0x02000, 8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F320B3B,
-- name: "Intel 28F320B3B",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F320B3B,
-+ .name = "Intel 28F320B3B",
-+ .uaddr = {
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x02000, 8),
- ERASEINFO(0x10000, 63),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F320B3T,
-- name: "Intel 28F320B3T",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F320B3T,
-+ .name = "Intel 28F320B3T",
-+ .uaddr = {
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x10000, 63),
- ERASEINFO(0x02000, 8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F640B3B,
-- name: "Intel 28F640B3B",
-- DevSize: SIZE_8MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F640B3B,
-+ .name = "Intel 28F640B3B",
-+ .uaddr = {
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_8MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x02000, 8),
- ERASEINFO(0x10000, 127),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F640B3T,
-- name: "Intel 28F640B3T",
-- DevSize: SIZE_8MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F640B3T,
-+ .name = "Intel 28F640B3T",
-+ .uaddr = {
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_8MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x10000, 127),
- ERASEINFO(0x02000, 8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I82802AB,
-- name: "Intel 82802AB",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_INTEL_EXT,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,8),
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I82802AB,
-+ .name = "Intel 82802AB",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_INTEL_EXT,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I82802AC,
-- name: "Intel 82802AC",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_INTEL_EXT,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,16),
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I82802AC,
-+ .name = "Intel 82802AC",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_INTEL_EXT,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,16),
- }
- }, {
-- mfr_id: MANUFACTURER_ST,
-- dev_id: M29W800T,
-- name: "ST M29W800T",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,15),
-+ .mfr_id = MANUFACTURER_MACRONIX,
-+ .dev_id = MX29LV040C,
-+ .name = "Macronix MX29LV040C",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,8),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_MACRONIX,
-+ .dev_id = MX29LV160T,
-+ .name = "MXIC MX29LV160T",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,31),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_ST,
-- dev_id: M29W160DT,
-- name: "ST M29W160DT",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,31),
-+ .mfr_id = MANUFACTURER_MACRONIX,
-+ .dev_id = MX29LV160B,
-+ .name = "MXIC MX29LV160B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x10000,31)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_MACRONIX,
-+ .dev_id = MX29F016,
-+ .name = "Macronix MX29F016",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,32),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_MACRONIX,
-+ .dev_id = MX29F004T,
-+ .name = "Macronix MX29F004T",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,7),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
-- ERASEINFO(0x04000,1)
-+ ERASEINFO(0x04000,1),
- }
- }, {
-- mfr_id: MANUFACTURER_ST,
-- dev_id: M29W160DB,
-- name: "ST M29W160DB",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-+ .mfr_id = MANUFACTURER_MACRONIX,
-+ .dev_id = MX29F004B,
-+ .name = "Macronix MX29F004B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x08000,1),
-- ERASEINFO(0x10000,31)
-+ ERASEINFO(0x10000,7),
- }
- }, {
-- mfr_id: MANUFACTURER_ATMEL,
-- dev_id: AT49BV512,
-- name: "Atmel AT49BV512",
-- DevSize: SIZE_64KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,1)
-+ .mfr_id = MANUFACTURER_MACRONIX,
-+ .dev_id = MX29F002T,
-+ .name = "Macronix MX29F002T",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_256KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,3),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x04000,1),
- }
- }, {
-- mfr_id: MANUFACTURER_ATMEL,
-- dev_id: AT29LV512,
-- name: "Atmel AT29LV512",
-- DevSize: SIZE_64KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {
-- ERASEINFO(0x80,256),
-- ERASEINFO(0x80,256)
-+ .mfr_id = MANUFACTURER_PMC,
-+ .dev_id = PM49FL002,
-+ .name = "PMC Pm49FL002",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_256KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO( 0x01000, 64 )
- }
- }, {
-- mfr_id: MANUFACTURER_ATMEL,
-- dev_id: AT49BV16X,
-- name: "Atmel AT49BV16X",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x02000,8),
-- ERASEINFO(0x10000,31)
-+ .mfr_id = MANUFACTURER_PMC,
-+ .dev_id = PM49FL004,
-+ .name = "PMC Pm49FL004",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO( 0x01000, 128 )
- }
- }, {
-- mfr_id: MANUFACTURER_ATMEL,
-- dev_id: AT49BV16XT,
-- name: "Atmel AT49BV16XT",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x10000,31),
-- ERASEINFO(0x02000,8)
-+ .mfr_id = MANUFACTURER_PMC,
-+ .dev_id = PM49FL008,
-+ .name = "PMC Pm49FL008",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO( 0x01000, 256 )
- }
- }, {
-- mfr_id: MANUFACTURER_ATMEL,
-- dev_id: AT49BV32X,
-- name: "Atmel AT49BV32X",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x02000,8),
-- ERASEINFO(0x10000,63)
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST39LF512,
-+ .name = "SST 39LF512",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_64KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,16),
- }
- }, {
-- mfr_id: MANUFACTURER_ATMEL,
-- dev_id: AT49BV32XT,
-- name: "Atmel AT49BV32XT",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x10000,63),
-- ERASEINFO(0x02000,8)
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST39LF010,
-+ .name = "SST 39LF010",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_128KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,32),
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F017D,
-- name: "AMD AM29F017D",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,32),
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST29EE020,
-+ .name = "SST 29EE020",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_256KiB,
-+ .CmdSet = P_ID_SST_PAGE,
-+ .NumEraseRegions= 1,
-+ regions: {ERASEINFO(0x01000,64),
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F016,
-- name: "AMD AM29F016",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,32),
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST29LE020,
-+ .name = "SST 29LE020",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_256KiB,
-+ .CmdSet = P_ID_SST_PAGE,
-+ .NumEraseRegions= 1,
-+ regions: {ERASEINFO(0x01000,64),
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F080,
-- name: "AMD AM29F080",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,16),
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST39LF020,
-+ .name = "SST 39LF020",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_256KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,64),
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F040,
-- name: "AMD AM29F040",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,8),
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST39LF040,
-+ .name = "SST 39LF040",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,128),
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV040B,
-- name: "AMD AM29LV040B",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,8),
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST39SF010A,
-+ .name = "SST 39SF010A",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_128KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,32),
- }
- }, {
-- mfr_id: MANUFACTURER_ST,
-- dev_id: M29W040B,
-- name: "ST M29W040B",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,8),
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST39SF020A,
-+ .name = "SST 39SF020A",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_256KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,64),
- }
- }, {
-- mfr_id: MANUFACTURER_MACRONIX,
-- dev_id: MX29LV160T,
-- name: "MXIC MX29LV160T",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,31),
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST49LF004B,
-+ .name = "SST 49LF004B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,128),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST49LF008A,
-+ .name = "SST 49LF008A",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,256),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST49LF030A,
-+ .name = "SST 49LF030A",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,96),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST49LF040A,
-+ .name = "SST 49LF040A",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,128),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST49LF080A,
-+ .name = "SST 49LF080A",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,256),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_SST, /* should be CFI */
-+ .dev_id = SST39LF160,
-+ .name = "SST 39LF160",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */
-+ [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x1000,256),
-+ ERASEINFO(0x1000,256)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_SST, /* should be CFI */
-+ .dev_id = SST39VF1601,
-+ .name = "SST 39VF1601",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */
-+ [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x1000,256),
-+ ERASEINFO(0x1000,256)
-+ }
-+
-+ }, {
-+ .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */
-+ .dev_id = M29W800DT,
-+ .name = "ST M29W800DT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */
-+ [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,15),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_MACRONIX,
-- dev_id: MX29LV160B,
-- name: "MXIC MX29LV160B",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-+ .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */
-+ .dev_id = M29W800DB,
-+ .name = "ST M29W800DB",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */
-+ [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x08000,1),
-- ERASEINFO(0x10000,31)
-- }
-- }, {
-- mfr_id: MANUFACTURER_MACRONIX,
-- dev_id: MX29F016,
-- name: "Macronix MX29F016",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,32),
-+ ERASEINFO(0x10000,15)
- }
- }, {
-- mfr_id: MANUFACTURER_MACRONIX,
-- dev_id: MX29F004T,
-- name: "Macronix MX29F004T",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,7),
-+ .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */
-+ .dev_id = M29W160DT,
-+ .name = "ST M29W160DT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,31),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
-- ERASEINFO(0x04000,1),
-+ ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_MACRONIX,
-- dev_id: MX29F004B,
-- name: "Macronix MX29F004B",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-+ .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */
-+ .dev_id = M29W160DB,
-+ .name = "ST M29W160DB",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x08000,1),
-- ERASEINFO(0x10000,7),
-+ ERASEINFO(0x10000,31)
- }
- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST39LF512,
-- name: "SST 39LF512",
-- DevSize: SIZE_64KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,16),
-+ .mfr_id = MANUFACTURER_ST,
-+ .dev_id = M29W040B,
-+ .name = "ST M29W040B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,8),
- }
- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST39LF010,
-- name: "SST 39LF010",
-- DevSize: SIZE_128KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,32),
-+ .mfr_id = MANUFACTURER_ST,
-+ .dev_id = M50FW040,
-+ .name = "ST M50FW040",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_INTEL_EXT,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,8),
- }
- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST39LF020,
-- name: "SST 39LF020",
-- DevSize: SIZE_256KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,64),
-+ .mfr_id = MANUFACTURER_ST,
-+ .dev_id = M50FW080,
-+ .name = "ST M50FW080",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_INTEL_EXT,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,16),
- }
- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST39LF040,
-- name: "SST 39LF040",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,128),
-+ .mfr_id = MANUFACTURER_ST,
-+ .dev_id = M50FW016,
-+ .name = "ST M50FW016",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_INTEL_EXT,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,32),
- }
- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST39SF010A,
-- name: "SST 39SF010A",
-- DevSize: SIZE_128KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,32),
-+ .mfr_id = MANUFACTURER_ST,
-+ .dev_id = M50LPW080,
-+ .name = "ST M50LPW080",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_INTEL_EXT,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,16),
- }
- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST39SF020A,
-- name: "SST 39SF020A",
-- DevSize: SIZE_256KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,64),
-+ .mfr_id = MANUFACTURER_TOSHIBA,
-+ .dev_id = TC58FVT160,
-+ .name = "Toshiba TC58FVT160",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,31),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST49LF030A,
-- name: "SST 49LF030A",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,96),
-+ .mfr_id = MANUFACTURER_TOSHIBA,
-+ .dev_id = TC58FVB160,
-+ .name = "Toshiba TC58FVB160",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x10000,31)
- }
- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST49LF040A,
-- name: "SST 49LF040A",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,128),
-+ .mfr_id = MANUFACTURER_TOSHIBA,
-+ .dev_id = TC58FVB321,
-+ .name = "Toshiba TC58FVB321",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x02000,8),
-+ ERASEINFO(0x10000,63)
- }
- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST49LF080A,
-- name: "SST 49LF080A",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,256),
-+ .mfr_id = MANUFACTURER_TOSHIBA,
-+ .dev_id = TC58FVT321,
-+ .name = "Toshiba TC58FVT321",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x10000,63),
-+ ERASEINFO(0x02000,8)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_TOSHIBA,
-+ .dev_id = TC58FVB641,
-+ .name = "Toshiba TC58FVB641",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_8MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x02000,8),
-+ ERASEINFO(0x10000,127)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_TOSHIBA,
-+ .dev_id = TC58FVT641,
-+ .name = "Toshiba TC58FVT641",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_8MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x10000,127),
-+ ERASEINFO(0x02000,8)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_WINBOND,
-+ .dev_id = W49V002A,
-+ .name = "Winbond W49V002A",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_256KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000, 3),
-+ ERASEINFO(0x08000, 1),
-+ ERASEINFO(0x02000, 2),
-+ ERASEINFO(0x04000, 1),
- }
- }
- };
-@@ -907,48 +1695,94 @@
- static int cfi_jedec_setup(struct cfi_private *p_cfi, int index);
-
- static int jedec_probe_chip(struct map_info *map, __u32 base,
-- struct flchip *chips, struct cfi_private *cfi);
-+ unsigned long *chip_map, struct cfi_private *cfi);
-
--struct mtd_info *jedec_probe(struct map_info *map);
-+static struct mtd_info *jedec_probe(struct map_info *map);
-
- static inline u32 jedec_read_mfr(struct map_info *map, __u32 base,
- struct cfi_private *cfi)
- {
-- u32 result, mask;
-+ map_word result;
-+ unsigned long mask;
-+ u32 ofs = cfi_build_cmd_addr(0, cfi_interleave(cfi), cfi->device_type);
- mask = (1 << (cfi->device_type * 8)) -1;
-- result = cfi_read(map, base);
-- result &= mask;
-- return result;
-+ result = map_read(map, base + ofs);
-+ return result.x[0] & mask;
- }
-
- static inline u32 jedec_read_id(struct map_info *map, __u32 base,
- struct cfi_private *cfi)
- {
-- int osf;
-- u32 result, mask;
-- osf = cfi->interleave *cfi->device_type;
-+ map_word result;
-+ unsigned long mask;
-+ u32 ofs = cfi_build_cmd_addr(1, cfi_interleave(cfi), cfi->device_type);
- mask = (1 << (cfi->device_type * 8)) -1;
-- result = cfi_read(map, base + osf);
-- result &= mask;
-- return result;
-+ result = map_read(map, base + ofs);
-+ return result.x[0] & mask;
- }
-
- static inline void jedec_reset(u32 base, struct map_info *map,
- struct cfi_private *cfi)
- {
- /* Reset */
-- cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
-+
-+ /* after checking the datasheets for SST, MACRONIX and ATMEL
-+ * (oh and incidentaly the jedec spec - 3.5.3.3) the reset
-+ * sequence is *supposed* to be 0xaa at 0x5555, 0x55 at
-+ * 0x2aaa, 0xF0 at 0x5555 this will not affect the AMD chips
-+ * as they will ignore the writes and dont care what address
-+ * the F0 is written to */
-+ if(cfi->addr_unlock1) {
-+ DEBUG( MTD_DEBUG_LEVEL3,
-+ "reset unlock called %x %x \n",
-+ cfi->addr_unlock1,cfi->addr_unlock2);
-+ cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL);
-+ }
-+
-+ cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
- /* Some misdesigned intel chips do not respond for 0xF0 for a reset,
- * so ensure we're in read mode. Send both the Intel and the AMD command
- * for this. Intel uses 0xff for this, AMD uses 0xff for NOP, so
- * this should be safe.
- */
- cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
-+ /* FIXME - should have reset delay before continuing */
-+}
-+
-+
-+static inline __u8 finfo_uaddr(const struct amd_flash_info *finfo, int device_type)
-+{
-+ int uaddr_idx;
-+ __u8 uaddr = MTD_UADDR_NOT_SUPPORTED;
-+
-+ switch ( device_type ) {
-+ case CFI_DEVICETYPE_X8: uaddr_idx = 0; break;
-+ case CFI_DEVICETYPE_X16: uaddr_idx = 1; break;
-+ case CFI_DEVICETYPE_X32: uaddr_idx = 2; break;
-+ default:
-+ printk(KERN_NOTICE "MTD: %s(): unknown device_type %d\n",
-+ __func__, device_type);
-+ goto uaddr_done;
-+ }
-+
-+ uaddr = finfo->uaddr[uaddr_idx];
-
-+ if (uaddr != MTD_UADDR_NOT_SUPPORTED ) {
-+ /* ASSERT("The unlock addresses for non-8-bit mode
-+ are bollocks. We don't really need an array."); */
-+ uaddr = finfo->uaddr[0];
-+ }
-+
-+ uaddr_done:
-+ return uaddr;
- }
-+
-+
- static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
- {
- int i,num_erase_regions;
-+ __u8 uaddr;
-
- printk("Found: %s\n",jedec_table[index].name);
-
-@@ -970,42 +1804,174 @@
- for (i=0; i<num_erase_regions; i++){
- p_cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i];
- }
-- p_cfi->cmdset_priv = 0;
-+ p_cfi->cmdset_priv = NULL;
-+
-+ /* This may be redundant for some cases, but it doesn't hurt */
-+ p_cfi->mfr = jedec_table[index].mfr_id;
-+ p_cfi->id = jedec_table[index].dev_id;
-+
-+ uaddr = finfo_uaddr(&jedec_table[index], p_cfi->device_type);
-+ if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) {
-+ kfree( p_cfi->cfiq );
-+ return 0;
-+ }
-+
-+ p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1;
-+ p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2;
-+
- return 1; /* ok */
- }
-
--static int jedec_probe_chip(struct map_info *map, __u32 base,
-- struct flchip *chips, struct cfi_private *cfi)
-+
-+/*
-+ * There is a BIG problem properly ID'ing the JEDEC devic and guaranteeing
-+ * the mapped address, unlock addresses, and proper chip ID. This function
-+ * attempts to minimize errors. It is doubtfull that this probe will ever
-+ * be perfect - consequently there should be some module parameters that
-+ * could be manually specified to force the chip info.
-+ */
-+static inline int jedec_match( __u32 base,
-+ struct map_info *map,
-+ struct cfi_private *cfi,
-+ const struct amd_flash_info *finfo )
- {
-- int i;
-- int unlockpass = 0;
-+ int rc = 0; /* failure until all tests pass */
-+ u32 mfr, id;
-+ __u8 uaddr;
-
-- if (!cfi->numchips) {
-+ /*
-+ * The IDs must match. For X16 and X32 devices operating in
-+ * a lower width ( X8 or X16 ), the device ID's are usually just
-+ * the lower byte(s) of the larger device ID for wider mode. If
-+ * a part is found that doesn't fit this assumption (device id for
-+ * smaller width mode is completely unrealated to full-width mode)
-+ * then the jedec_table[] will have to be augmented with the IDs
-+ * for different widths.
-+ */
- switch (cfi->device_type) {
- case CFI_DEVICETYPE_X8:
-- cfi->addr_unlock1 = 0x555;
-- cfi->addr_unlock2 = 0x2aa;
-+ mfr = (__u8)finfo->mfr_id;
-+ id = (__u8)finfo->dev_id;
-+
-+ /* bjd: it seems that if we do this, we can end up
-+ * detecting 16bit flashes as an 8bit device, even though
-+ * there aren't.
-+ */
-+ if (finfo->dev_id > 0xff) {
-+ DEBUG( MTD_DEBUG_LEVEL3, "%s(): ID is not 8bit\n",
-+ __func__);
-+ goto match_done;
-+ }
- break;
- case CFI_DEVICETYPE_X16:
-- cfi->addr_unlock1 = 0xaaa;
-- if (map->buswidth == cfi->interleave) {
-- /* X16 chip(s) in X8 mode */
-- cfi->addr_unlock2 = 0x555;
-- } else {
-- cfi->addr_unlock2 = 0x554;
-- }
-+ mfr = (__u16)finfo->mfr_id;
-+ id = (__u16)finfo->dev_id;
- break;
- case CFI_DEVICETYPE_X32:
-- cfi->addr_unlock1 = 0x1555;
-- cfi->addr_unlock2 = 0xaaa;
-+ mfr = (__u16)finfo->mfr_id;
-+ id = (__u32)finfo->dev_id;
- break;
- default:
-- printk(KERN_NOTICE "Eep. Unknown jedec_probe device type %d\n", cfi->device_type);
-- return 0;
-+ printk(KERN_WARNING
-+ "MTD %s(): Unsupported device type %d\n",
-+ __func__, cfi->device_type);
-+ goto match_done;
- }
-+ if ( cfi->mfr != mfr || cfi->id != id ) {
-+ goto match_done;
-+ }
-+
-+ /* the part size must fit in the memory window */
-+ DEBUG( MTD_DEBUG_LEVEL3,
-+ "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n",
-+ __func__, base, 1 << finfo->DevSize, base + (1 << finfo->DevSize) );
-+ if ( base + cfi_interleave(cfi) * ( 1 << finfo->DevSize ) > map->size ) {
-+ DEBUG( MTD_DEBUG_LEVEL3,
-+ "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n",
-+ __func__, finfo->mfr_id, finfo->dev_id,
-+ 1 << finfo->DevSize );
-+ goto match_done;
-+ }
-+
-+ uaddr = finfo_uaddr(finfo, cfi->device_type);
-+ if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) {
-+ goto match_done;
-+ }
-+
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n",
-+ __func__, cfi->addr_unlock1, cfi->addr_unlock2 );
-+ if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr
-+ && ( unlock_addrs[uaddr].addr1 != cfi->addr_unlock1 ||
-+ unlock_addrs[uaddr].addr2 != cfi->addr_unlock2 ) ) {
-+ DEBUG( MTD_DEBUG_LEVEL3,
-+ "MTD %s(): 0x%.4x 0x%.4x did not match\n",
-+ __func__,
-+ unlock_addrs[uaddr].addr1,
-+ unlock_addrs[uaddr].addr2);
-+ goto match_done;
-+ }
-+
-+ /*
-+ * Make sure the ID's dissappear when the device is taken out of
-+ * ID mode. The only time this should fail when it should succeed
-+ * is when the ID's are written as data to the same
-+ * addresses. For this rare and unfortunate case the chip
-+ * cannot be probed correctly.
-+ * FIXME - write a driver that takes all of the chip info as
-+ * module parameters, doesn't probe but forces a load.
-+ */
-+ DEBUG( MTD_DEBUG_LEVEL3,
-+ "MTD %s(): check ID's disappear when not in ID mode\n",
-+ __func__ );
-+ jedec_reset( base, map, cfi );
-+ mfr = jedec_read_mfr( map, base, cfi );
-+ id = jedec_read_id( map, base, cfi );
-+ if ( mfr == cfi->mfr && id == cfi->id ) {
-+ DEBUG( MTD_DEBUG_LEVEL3,
-+ "MTD %s(): ID 0x%.2x:0x%.2x did not change after reset:\n"
-+ "You might need to manually specify JEDEC parameters.\n",
-+ __func__, cfi->mfr, cfi->id );
-+ goto match_done;
-+ }
-+
-+ /* all tests passed - mark as success */
-+ rc = 1;
-+
-+ /*
-+ * Put the device back in ID mode - only need to do this if we
-+ * were truly frobbing a real device.
-+ */
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ );
-+ if(cfi->addr_unlock1) {
-+ cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL);
- }
-+ cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
-+ /* FIXME - should have a delay before continuing */
-+
-+ match_done:
-+ return rc;
-+}
-+
-+
-+static int jedec_probe_chip(struct map_info *map, __u32 base,
-+ unsigned long *chip_map, struct cfi_private *cfi)
-+{
-+ int i;
-+ enum uaddr uaddr_idx = MTD_UADDR_NOT_SUPPORTED;
-+ u32 probe_offset1, probe_offset2;
-
- retry:
-+ if (!cfi->numchips) {
-+ uaddr_idx++;
-+
-+ if (MTD_UADDR_UNNECESSARY == uaddr_idx)
-+ return 0;
-+
-+ cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1;
-+ cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2;
-+ }
-+
- /* Make certain we aren't probing past the end of map */
- if (base >= map->size) {
- printk(KERN_NOTICE
-@@ -1014,19 +1980,19 @@
- return 0;
-
- }
-- if ((base + cfi->addr_unlock1) >= map->size) {
-- printk(KERN_NOTICE
-- "Probe at addr_unlock1(0x%08x + 0x%08x) past the end of the map(0x%08lx)\n",
-- base, cfi->addr_unlock1, map->size -1);
--
-- return 0;
-- }
-- if ((base + cfi->addr_unlock2) >= map->size) {
-- printk(KERN_NOTICE
-- "Probe at addr_unlock2(0x%08x + 0x%08x) past the end of the map(0x%08lx)\n",
-- base, cfi->addr_unlock2, map->size -1);
-- return 0;
--
-+ /* Ensure the unlock addresses we try stay inside the map */
-+ probe_offset1 = cfi_build_cmd_addr(
-+ cfi->addr_unlock1,
-+ cfi_interleave(cfi),
-+ cfi->device_type);
-+ probe_offset2 = cfi_build_cmd_addr(
-+ cfi->addr_unlock1,
-+ cfi_interleave(cfi),
-+ cfi->device_type);
-+ if ( ((base + probe_offset1 + map_bankwidth(map)) >= map->size) ||
-+ ((base + probe_offset2 + map_bankwidth(map)) >= map->size))
-+ {
-+ goto retry;
- }
-
- /* Reset */
-@@ -1034,10 +2000,11 @@
-
- /* Autoselect Mode */
- if(cfi->addr_unlock1) {
-- cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
-+ cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL);
- }
-- cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
-+ cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
-+ /* FIXME - should have a delay before continuing */
-
- if (!cfi->numchips) {
- /* This is the first time we're called. Set up the CFI
-@@ -1045,26 +2012,21 @@
-
- cfi->mfr = jedec_read_mfr(map, base, cfi);
- cfi->id = jedec_read_id(map, base, cfi);
-- printk(KERN_INFO "Search for id:(%02x %02x) interleave(%d) type(%d)\n",
-- cfi->mfr, cfi->id, cfi->interleave, cfi->device_type);
-+ DEBUG(MTD_DEBUG_LEVEL3,
-+ "Search for id:(%02x %02x) interleave(%d) type(%d)\n",
-+ cfi->mfr, cfi->id, cfi_interleave(cfi), cfi->device_type);
- for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) {
-- if (cfi->mfr == jedec_table[i].mfr_id &&
-- cfi->id == jedec_table[i].dev_id) {
-+ if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) {
-+ DEBUG( MTD_DEBUG_LEVEL3,
-+ "MTD %s(): matched device 0x%x,0x%x unlock_addrs: 0x%.4x 0x%.4x\n",
-+ __func__, cfi->mfr, cfi->id,
-+ cfi->addr_unlock1, cfi->addr_unlock2 );
- if (!cfi_jedec_setup(cfi, i))
- return 0;
- goto ok_out;
- }
- }
-- switch(unlockpass++) {
-- case 0:
-- cfi->addr_unlock1 |= cfi->addr_unlock1 << 4;
-- cfi->addr_unlock2 |= cfi->addr_unlock2 << 4;
-- goto retry;
-- case 1:
-- cfi->addr_unlock1 = cfi->addr_unlock2 = 0;
- goto retry;
-- }
-- return 0;
- } else {
- __u16 mfr;
- __u16 id;
-@@ -1081,21 +2043,24 @@
- }
- }
-
-- /* Check each previous chip to see if it's an alias */
-- for (i=0; i<cfi->numchips; i++) {
-- /* This chip should be in read mode if it's one
-- we've already touched. */
-- if (jedec_read_mfr(map, chips[i].start, cfi) == cfi->mfr &&
-- jedec_read_id(map, chips[i].start, cfi) == cfi->id) {
-+ /* Check each previous chip locations to see if it's an alias */
-+ for (i=0; i < (base >> cfi->chipshift); i++) {
-+ unsigned long start;
-+ if(!test_bit(i, chip_map)) {
-+ continue; /* Skip location; no valid chip at this address */
-+ }
-+ start = i << cfi->chipshift;
-+ if (jedec_read_mfr(map, start, cfi) == cfi->mfr &&
-+ jedec_read_id(map, start, cfi) == cfi->id) {
- /* Eep. This chip also looks like it's in autoselect mode.
- Is it an alias for the new one? */
-- jedec_reset(chips[i].start, map, cfi);
-+ jedec_reset(start, map, cfi);
-
- /* If the device IDs go away, it's an alias */
- if (jedec_read_mfr(map, base, cfi) != cfi->mfr ||
- jedec_read_id(map, base, cfi) != cfi->id) {
- printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
-- map->name, base, chips[i].start);
-+ map->name, base, start);
- return 0;
- }
-
-@@ -1107,7 +2072,7 @@
- if (jedec_read_mfr(map, base, cfi) == cfi->mfr &&
- jedec_read_id(map, base, cfi) == cfi->id) {
- printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
-- map->name, base, chips[i].start);
-+ map->name, base, start);
- return 0;
- }
- }
-@@ -1115,32 +2080,26 @@
-
- /* OK, if we got to here, then none of the previous chips appear to
- be aliases for the current one. */
-- if (cfi->numchips == MAX_CFI_CHIPS) {
-- printk(KERN_WARNING"%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS);
-- /* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */
-- return -1;
-- }
-- chips[cfi->numchips].start = base;
-- chips[cfi->numchips].state = FL_READY;
-+ set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */
- cfi->numchips++;
-
- ok_out:
- /* Put it back into Read Mode */
- jedec_reset(base, map, cfi);
-
-- printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n",
-- map->name, cfi->interleave, cfi->device_type*8, base,
-- map->buswidth*8);
-+ printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
-+ map->name, cfi_interleave(cfi), cfi->device_type*8, base,
-+ map->bankwidth*8);
-
- return 1;
- }
-
- static struct chip_probe jedec_chip_probe = {
-- name: "JEDEC",
-- probe_chip: jedec_probe_chip
-+ .name = "JEDEC",
-+ .probe_chip = jedec_probe_chip
- };
-
--struct mtd_info *jedec_probe(struct map_info *map)
-+static struct mtd_info *jedec_probe(struct map_info *map)
- {
- /*
- * Just use the generic probe stuff to call our CFI-specific
-@@ -1150,12 +2109,12 @@
- }
-
- static struct mtd_chip_driver jedec_chipdrv = {
-- probe: jedec_probe,
-- name: "jedec_probe",
-- module: THIS_MODULE
-+ .probe = jedec_probe,
-+ .name = "jedec_probe",
-+ .module = THIS_MODULE
- };
-
--int __init jedec_probe_init(void)
-+static int __init jedec_probe_init(void)
- {
- register_mtd_chip_driver(&jedec_chipdrv);
- return 0;
---- linux-2.4.21/drivers/mtd/chips/map_absent.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/chips/map_absent.c
-@@ -1,7 +1,7 @@
- /*
- * Common code to handle absent "placeholder" devices
- * Copyright 2001 Resilience Corporation <ebrower@resilience.com>
-- * $Id: map_absent.c,v 1.2 2001/10/02 15:05:12 dwmw2 Exp $
-+ * $Id: map_absent.c,v 1.5 2004/11/16 18:29:00 dwmw2 Exp $
- *
- * This map driver is used to allocate "placeholder" MTD
- * devices on systems that have socketed/removable media.
-@@ -23,9 +23,10 @@
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/slab.h>
--
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
--
-+#include <linux/mtd/compatmac.h>
-
- static int map_absent_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
- static int map_absent_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
-@@ -36,10 +37,10 @@
-
-
- static struct mtd_chip_driver map_absent_chipdrv = {
-- probe: map_absent_probe,
-- destroy: map_absent_destroy,
-- name: "map_absent",
-- module: THIS_MODULE
-+ .probe = map_absent_probe,
-+ .destroy = map_absent_destroy,
-+ .name = "map_absent",
-+ .module = THIS_MODULE
- };
-
- static struct mtd_info *map_absent_probe(struct map_info *map)
-@@ -65,7 +66,7 @@
- mtd->flags = 0;
- mtd->erasesize = PAGE_SIZE;
-
-- MOD_INC_USE_COUNT;
-+ __module_get(THIS_MODULE);
- return mtd;
- }
-
-@@ -97,7 +98,7 @@
- /* nop */
- }
-
--int __init map_absent_init(void)
-+static int __init map_absent_init(void)
- {
- register_mtd_chip_driver(&map_absent_chipdrv);
- return 0;
---- linux-2.4.21/drivers/mtd/chips/map_ram.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/chips/map_ram.c
-@@ -1,7 +1,7 @@
- /*
- * Common code to handle map devices which are simple RAM
- * (C) 2000 Red Hat. GPL'd.
-- * $Id: map_ram.c,v 1.14 2001/10/02 15:05:12 dwmw2 Exp $
-+ * $Id: map_ram.c,v 1.22 2005/01/05 18:05:12 dwmw2 Exp $
- */
-
- #include <linux/module.h>
-@@ -11,8 +11,10 @@
- #include <asm/byteorder.h>
- #include <linux/errno.h>
- #include <linux/slab.h>
--
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-+#include <linux/mtd/compatmac.h>
-
-
- static int mapram_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-@@ -23,9 +25,9 @@
-
-
- static struct mtd_chip_driver mapram_chipdrv = {
-- probe: map_ram_probe,
-- name: "map_ram",
-- module: THIS_MODULE
-+ .probe = map_ram_probe,
-+ .name = "map_ram",
-+ .module = THIS_MODULE
- };
-
- static struct mtd_info *map_ram_probe(struct map_info *map)
-@@ -34,21 +36,21 @@
-
- /* Check the first byte is RAM */
- #if 0
-- map->write8(map, 0x55, 0);
-- if (map->read8(map, 0) != 0x55)
-+ map_write8(map, 0x55, 0);
-+ if (map_read8(map, 0) != 0x55)
- return NULL;
-
-- map->write8(map, 0xAA, 0);
-- if (map->read8(map, 0) != 0xAA)
-+ map_write8(map, 0xAA, 0);
-+ if (map_read8(map, 0) != 0xAA)
- return NULL;
-
- /* Check the last byte is RAM */
-- map->write8(map, 0x55, map->size-1);
-- if (map->read8(map, map->size-1) != 0x55)
-+ map_write8(map, 0x55, map->size-1);
-+ if (map_read8(map, map->size-1) != 0x55)
- return NULL;
-
-- map->write8(map, 0xAA, map->size-1);
-- if (map->read8(map, map->size-1) != 0xAA)
-+ map_write8(map, 0xAA, map->size-1);
-+ if (map_read8(map, map->size-1) != 0xAA)
- return NULL;
- #endif
- /* OK. It seems to be RAM. */
-@@ -74,25 +76,25 @@
- while(mtd->size & (mtd->erasesize - 1))
- mtd->erasesize >>= 1;
-
-- MOD_INC_USE_COUNT;
-+ __module_get(THIS_MODULE);
- return mtd;
- }
-
-
- static int mapram_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
- {
-- struct map_info *map = (struct map_info *)mtd->priv;
-+ struct map_info *map = mtd->priv;
-
-- map->copy_from(map, buf, from, len);
-+ map_copy_from(map, buf, from, len);
- *retlen = len;
- return 0;
- }
-
- static int mapram_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
- {
-- struct map_info *map = (struct map_info *)mtd->priv;
-+ struct map_info *map = mtd->priv;
-
-- map->copy_to(map, to, buf, len);
-+ map_copy_to(map, to, buf, len);
- *retlen = len;
- return 0;
- }
-@@ -101,14 +103,18 @@
- {
- /* Yeah, it's inefficient. Who cares? It's faster than a _real_
- flash erase. */
-- struct map_info *map = (struct map_info *)mtd->priv;
-+ struct map_info *map = mtd->priv;
-+ map_word allff;
- unsigned long i;
-
-- for (i=0; i<instr->len; i++)
-- map->write8(map, 0xFF, instr->addr + i);
-+ allff = map_word_ff(map);
-
-- if (instr->callback)
-- instr->callback(instr);
-+ for (i=0; i<instr->len; i += map_bankwidth(map))
-+ map_write(map, allff, instr->addr + i);
-+
-+ instr->state = MTD_ERASE_DONE;
-+
-+ mtd_erase_callback(instr);
-
- return 0;
- }
-@@ -118,7 +124,7 @@
- /* Nothing to see here */
- }
-
--int __init map_ram_init(void)
-+static int __init map_ram_init(void)
- {
- register_mtd_chip_driver(&mapram_chipdrv);
- return 0;
---- linux-2.4.21/drivers/mtd/chips/map_rom.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/chips/map_rom.c
-@@ -1,10 +1,9 @@
- /*
- * Common code to handle map devices which are simple ROM
- * (C) 2000 Red Hat. GPL'd.
-- * $Id: map_rom.c,v 1.17 2001/10/02 15:05:12 dwmw2 Exp $
-+ * $Id: map_rom.c,v 1.23 2005/01/05 18:05:12 dwmw2 Exp $
- */
-
--#include <linux/version.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-@@ -12,21 +11,23 @@
- #include <asm/byteorder.h>
- #include <linux/errno.h>
- #include <linux/slab.h>
--
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-+#include <linux/mtd/compatmac.h>
-
- static int maprom_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
- static int maprom_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
- static void maprom_nop (struct mtd_info *);
--struct mtd_info *map_rom_probe(struct map_info *map);
-+static struct mtd_info *map_rom_probe(struct map_info *map);
-
- static struct mtd_chip_driver maprom_chipdrv = {
-- probe: map_rom_probe,
-- name: "map_rom",
-- module: THIS_MODULE
-+ .probe = map_rom_probe,
-+ .name = "map_rom",
-+ .module = THIS_MODULE
- };
-
--struct mtd_info *map_rom_probe(struct map_info *map)
-+static struct mtd_info *map_rom_probe(struct map_info *map)
- {
- struct mtd_info *mtd;
-
-@@ -49,16 +50,16 @@
- while(mtd->size & (mtd->erasesize - 1))
- mtd->erasesize >>= 1;
-
-- MOD_INC_USE_COUNT;
-+ __module_get(THIS_MODULE);
- return mtd;
- }
-
-
- static int maprom_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
- {
-- struct map_info *map = (struct map_info *)mtd->priv;
-+ struct map_info *map = mtd->priv;
-
-- map->copy_from(map, buf, from, len);
-+ map_copy_from(map, buf, from, len);
- *retlen = len;
- return 0;
- }
-@@ -74,7 +75,7 @@
- return -EIO;
- }
-
--int __init map_rom_init(void)
-+static int __init map_rom_init(void)
- {
- register_mtd_chip_driver(&maprom_chipdrv);
- return 0;
---- linux-2.4.21/drivers/mtd/chips/sharp.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/chips/sharp.c
-@@ -4,7 +4,7 @@
- * Copyright 2000,2001 David A. Schleef <ds@schleef.org>
- * 2000,2001 Lineo, Inc.
- *
-- * $Id: sharp.c,v 1.8 2002/05/17 08:59:19 dwmw2 Exp $
-+ * $Id: sharp.c,v 1.14 2004/08/09 13:19:43 dwmw2 Exp $
- *
- * Devices supported:
- * LH28F016SCT Symmetrical block flash memory, 2Mx8
-@@ -22,14 +22,15 @@
-
- #include <linux/kernel.h>
- #include <linux/module.h>
--#include <linux/version.h>
- #include <linux/types.h>
- #include <linux/sched.h>
- #include <linux/errno.h>
- #include <linux/interrupt.h>
- #include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/cfi.h>
- #include <linux/delay.h>
-+#include <linux/init.h>
-
- #define CMD_RESET 0xffffffff
- #define CMD_READ_ID 0x90909090
-@@ -98,10 +99,10 @@
- static void sharp_destroy(struct mtd_info *mtd);
-
- static struct mtd_chip_driver sharp_chipdrv = {
-- probe: sharp_probe,
-- destroy: sharp_destroy,
-- name: "sharp",
-- module: THIS_MODULE
-+ .probe = sharp_probe,
-+ .destroy = sharp_destroy,
-+ .name = "sharp",
-+ .module = THIS_MODULE
- };
-
-
-@@ -116,8 +117,10 @@
- return NULL;
-
- sharp = kmalloc(sizeof(*sharp), GFP_KERNEL);
-- if(!sharp)
-+ if(!sharp) {
-+ kfree(mtd);
- return NULL;
-+ }
-
- memset(mtd, 0, sizeof(*mtd));
-
-@@ -152,7 +155,7 @@
- map->fldrv = &sharp_chipdrv;
- map->fldrv_priv = sharp;
-
-- MOD_INC_USE_COUNT;
-+ __module_get(THIS_MODULE);
- return mtd;
- }
-
-@@ -163,12 +166,12 @@
- u32 read0, read4;
- int width = 4;
-
-- tmp = map->read32(map, base+0);
-+ tmp = map_read32(map, base+0);
-
-- map->write32(map, CMD_READ_ID, base+0);
-+ map_write32(map, CMD_READ_ID, base+0);
-
-- read0=map->read32(map, base+0);
-- read4=map->read32(map, base+4);
-+ read0=map_read32(map, base+0);
-+ read4=map_read32(map, base+4);
- if(read0 == 0x89898989){
- printk("Looks like sharp flash\n");
- switch(read4){
-@@ -196,10 +199,10 @@
- printk("Sort-of looks like sharp flash, 0x%08x 0x%08x\n",
- read0,read4);
- }
-- }else if((map->read32(map, base+0) == CMD_READ_ID)){
-+ }else if((map_read32(map, base+0) == CMD_READ_ID)){
- /* RAM, probably */
- printk("Looks like RAM\n");
-- map->write32(map, tmp, base+0);
-+ map_write32(map, tmp, base+0);
- }else{
- printk("Doesn't look like sharp flash, 0x%08x 0x%08x\n",
- read0,read4);
-@@ -221,10 +224,10 @@
-
- switch(chip->state){
- case FL_READY:
-- map->write32(map,CMD_READ_STATUS,adr);
-+ map_write32(map,CMD_READ_STATUS,adr);
- chip->state = FL_STATUS;
- case FL_STATUS:
-- status = map->read32(map,adr);
-+ status = map_read32(map,adr);
- //printk("status=%08x\n",status);
-
- udelay(100);
-@@ -252,7 +255,7 @@
- goto retry;
- }
-
-- map->write32(map,CMD_RESET, adr);
-+ map_write32(map,CMD_RESET, adr);
-
- chip->state = FL_READY;
-
-@@ -293,7 +296,7 @@
- if(ret<0)
- break;
-
-- map->copy_from(map,buf,ofs,thislen);
-+ map_copy_from(map,buf,ofs,thislen);
-
- sharp_release(&sharp->chips[chipnum]);
-
-@@ -354,17 +357,17 @@
- ret = sharp_wait(map,chip);
-
- for(try=0;try<10;try++){
-- map->write32(map,CMD_BYTE_WRITE,adr);
-+ map_write32(map,CMD_BYTE_WRITE,adr);
- /* cpu_to_le32 -> hack to fix the writel be->le conversion */
-- map->write32(map,cpu_to_le32(datum),adr);
-+ map_write32(map,cpu_to_le32(datum),adr);
-
- chip->state = FL_WRITING;
-
- timeo = jiffies + (HZ/2);
-
-- map->write32(map,CMD_READ_STATUS,adr);
-+ map_write32(map,CMD_READ_STATUS,adr);
- for(i=0;i<100;i++){
-- status = map->read32(map,adr);
-+ status = map_read32(map,adr);
- if((status & SR_READY)==SR_READY)
- break;
- }
-@@ -377,9 +380,9 @@
-
- printk("sharp: error writing byte at addr=%08lx status=%08x\n",adr,status);
-
-- map->write32(map,CMD_CLEAR_STATUS,adr);
-+ map_write32(map,CMD_CLEAR_STATUS,adr);
- }
-- map->write32(map,CMD_RESET,adr);
-+ map_write32(map,CMD_RESET,adr);
- chip->state = FL_READY;
-
- wake_up(&chip->wq);
-@@ -422,8 +425,7 @@
- }
-
- instr->state = MTD_ERASE_DONE;
-- if(instr->callback)
-- instr->callback(instr);
-+ mtd_erase_callback(instr);
-
- return 0;
- }
-@@ -432,18 +434,18 @@
- unsigned long adr)
- {
- int ret;
-- int timeo;
-+ unsigned long timeo;
- int status;
- DECLARE_WAITQUEUE(wait, current);
-
-- map->write32(map,CMD_READ_STATUS,adr);
-- status = map->read32(map,adr);
-+ map_write32(map,CMD_READ_STATUS,adr);
-+ status = map_read32(map,adr);
-
- timeo = jiffies + HZ;
-
- while(time_before(jiffies, timeo)){
-- map->write32(map,CMD_READ_STATUS,adr);
-- status = map->read32(map,adr);
-+ map_write32(map,CMD_READ_STATUS,adr);
-+ status = map_read32(map,adr);
- if((status & SR_READY)==SR_READY){
- ret = 0;
- goto out;
-@@ -485,26 +487,26 @@
- sharp_unlock_oneblock(map,chip,adr);
- #endif
-
-- map->write32(map,CMD_BLOCK_ERASE_1,adr);
-- map->write32(map,CMD_BLOCK_ERASE_2,adr);
-+ map_write32(map,CMD_BLOCK_ERASE_1,adr);
-+ map_write32(map,CMD_BLOCK_ERASE_2,adr);
-
- chip->state = FL_ERASING;
-
- ret = sharp_do_wait_for_ready(map,chip,adr);
- if(ret<0)return ret;
-
-- map->write32(map,CMD_READ_STATUS,adr);
-- status = map->read32(map,adr);
-+ map_write32(map,CMD_READ_STATUS,adr);
-+ status = map_read32(map,adr);
-
- if(!(status&SR_ERRORS)){
-- map->write32(map,CMD_RESET,adr);
-+ map_write32(map,CMD_RESET,adr);
- chip->state = FL_READY;
- //spin_unlock_bh(chip->mutex);
- return 0;
- }
-
- printk("sharp: error erasing block at addr=%08lx status=%08x\n",adr,status);
-- map->write32(map,CMD_CLEAR_STATUS,adr);
-+ map_write32(map,CMD_CLEAR_STATUS,adr);
-
- //spin_unlock_bh(chip->mutex);
-
-@@ -518,17 +520,17 @@
- int i;
- int status;
-
-- map->write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr);
-- map->write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr);
-+ map_write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr);
-+ map_write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr);
-
- udelay(100);
-
-- status = map->read32(map,adr);
-+ status = map_read32(map,adr);
- printk("status=%08x\n",status);
-
- for(i=0;i<1000;i++){
-- //map->write32(map,CMD_READ_STATUS,adr);
-- status = map->read32(map,adr);
-+ //map_write32(map,CMD_READ_STATUS,adr);
-+ status = map_read32(map,adr);
- if((status & SR_READY)==SR_READY)
- break;
- udelay(100);
-@@ -538,13 +540,13 @@
- }
-
- if(!(status&SR_ERRORS)){
-- map->write32(map,CMD_RESET,adr);
-+ map_write32(map,CMD_RESET,adr);
- chip->state = FL_READY;
- return;
- }
-
- printk("sharp: error unlocking block at addr=%08lx status=%08x\n",adr,status);
-- map->write32(map,CMD_CLEAR_STATUS,adr);
-+ map_write32(map,CMD_CLEAR_STATUS,adr);
- }
- #endif
-
---- linux-2.4.21/drivers/mtd/cmdlinepart.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/cmdlinepart.c
-@@ -1,5 +1,5 @@
- /*
-- * $Id: cmdlinepart.c,v 1.6 2002/11/16 01:37:39 dneuer Exp $
-+ * $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
- *
- * Read flash partition table from command line
- *
-@@ -10,7 +10,7 @@
- * mtdparts=<mtddef>[;<mtddef]
- * <mtddef> := <mtd-id>:<partdef>[,<partdef>]
- * <partdef> := <size>[@offset][<name>][ro]
-- * <mtd-id> := unique id used in mapping driver/device
-+ * <mtd-id> := unique name used in mapping driver/device (mtd->name)
- * <size> := standard linux memsize OR "-" to denote all remaining space
- * <name> := '(' NAME ')'
- *
-@@ -28,7 +28,6 @@
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
--#include <asm/setup.h>
- #include <linux/bootmem.h>
-
- /* error message prefix */
-@@ -95,7 +94,7 @@
- if (size < PAGE_SIZE)
- {
- printk(KERN_ERR ERRP "partition size too small (%lx)\n", size);
-- return 0;
-+ return NULL;
- }
- }
-
-@@ -122,7 +121,7 @@
- if ((p = strchr(name, delim)) == 0)
- {
- printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim);
-- return 0;
-+ return NULL;
- }
- name_len = p - name;
- s = p + 1;
-@@ -149,12 +148,12 @@
- if (size == SIZE_REMAINING)
- {
- printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n");
-- return 0;
-+ return NULL;
- }
- /* more partitions follow, parse them */
- if ((parts = newpart(s + 1, &s, num_parts,
- this_part + 1, &extra_mem, extra_mem_size)) == 0)
-- return 0;
-+ return NULL;
- }
- else
- { /* this is the last partition: allocate space for all */
-@@ -167,7 +166,7 @@
- if (!parts)
- {
- printk(KERN_ERR ERRP "out of memory\n");
-- return 0;
-+ return NULL;
- }
- memset(parts, 0, alloc_size);
- extra_mem = (unsigned char *)(parts + *num_parts);
-@@ -178,8 +177,7 @@
- parts[this_part].mask_flags = mask_flags;
- if (name)
- {
-- strncpy(extra_mem, name, name_len);
-- extra_mem[name_len] = 0;
-+ strlcpy(extra_mem, name, name_len + 1);
- }
- else
- {
-@@ -258,8 +256,7 @@
- this_mtd->parts = parts;
- this_mtd->num_parts = num_parts;
- this_mtd->mtd_id = (char*)(this_mtd + 1);
-- strncpy(this_mtd->mtd_id, mtd_id, mtd_id_len);
-- this_mtd->mtd_id[mtd_id_len] = 0;
-+ strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1);
-
- /* link into chain */
- this_mtd->next = partitions;
-@@ -291,13 +288,14 @@
- * information. It returns partitions for the requested mtd device, or
- * the first one in the chain if a NULL mtd_id is passed in.
- */
--int parse_cmdline_partitions(struct mtd_info *master,
-+static int parse_cmdline_partitions(struct mtd_info *master,
- struct mtd_partition **pparts,
-- const char *mtd_id)
-+ unsigned long origin)
- {
- unsigned long offset;
- int i;
- struct cmdline_mtd_partition *part;
-+ char *mtd_id = master->name;
-
- if(!cmdline)
- return -EINVAL;
-@@ -340,8 +338,10 @@
- * This is the handler for our kernel parameter, called from
- * main.c::checksetup(). Note that we can not yet kmalloc() anything,
- * so we only save the commandline for later processing.
-+ *
-+ * This function needs to be visible for bootloaders.
- */
--static int __init mtdpart_setup(char *s)
-+int mtdpart_setup(char *s)
- {
- cmdline = s;
- return 1;
-@@ -349,7 +349,18 @@
-
- __setup("mtdparts=", mtdpart_setup);
-
--EXPORT_SYMBOL(parse_cmdline_partitions);
-+static struct mtd_part_parser cmdline_parser = {
-+ .owner = THIS_MODULE,
-+ .parse_fn = parse_cmdline_partitions,
-+ .name = "cmdlinepart",
-+};
-+
-+static int __init cmdline_parser_init(void)
-+{
-+ return register_mtd_parser(&cmdline_parser);
-+}
-+
-+module_init(cmdline_parser_init);
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
---- linux-2.4.21/drivers/mtd/devices/Config.in~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/devices/Config.in
-@@ -1,6 +1,6 @@
--# drivers/mtd/maps/Config.in
-+# drivers/mtd/devices/Config.in
-
--# $Id: Config.in,v 1.8 2003/01/24 23:25:14 dwmw2 Exp $
-+# $Id: Config.in,v 1.15 2004/10/01 21:47:13 gleixner Exp $
-
- mainmenu_option next_comment
-
-@@ -10,22 +10,13 @@
- bool ' PMC551 256M DRAM Bugfix' CONFIG_MTD_PMC551_BUGFIX
- bool ' PMC551 Debugging' CONFIG_MTD_PMC551_DEBUG
- fi
--if [ "$CONFIG_DECSTATION" = "y" ]; then
-+if [ "$CONFIG_MACH__DECSTATION" = "y" ]; then
- dep_tristate ' DEC MS02-NV NVRAM module support' CONFIG_MTD_MS02NV $CONFIG_MTD
- fi
- dep_tristate ' Uncached system RAM' CONFIG_MTD_SLRAM $CONFIG_MTD
- if [ "$CONFIG_SA1100_LART" = "y" ]; then
- dep_tristate ' 28F160xx flash driver for LART' CONFIG_MTD_LART $CONFIG_MTD
- fi
--if [ "$CONFIG_ARCH_MX1ADS" = "y" ]; then
-- dep_tristate ' SyncFlash driver for MX1ADS' CONFIG_MTD_SYNCFLASH $CONFIG_MTD
--fi
--if [ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then
-- dep_tristate ' AT91RM9200 DataFlash support' CONFIG_MTD_AT91_DATAFLASH $CONFIG_MTD
-- if [ "$CONFIG_MTD_AT91_DATAFLASH" = "y" -o "$CONFIG_MTD_AT91_DATAFLASH" = "m" ]; then
-- bool ' Enable DataFlash card? ' CONFIG_MTD_AT91_DATAFLASH_CARD
-- fi
--fi
- dep_tristate ' Test driver using RAM' CONFIG_MTD_MTDRAM $CONFIG_MTD
- if [ "$CONFIG_MTD_MTDRAM" = "y" -o "$CONFIG_MTD_MTDRAM" = "m" ]; then
- int 'MTDRAM device size in KiB' CONFIG_MTDRAM_TOTAL_SIZE 4096
-@@ -37,19 +28,29 @@
- dep_tristate ' MTD emulation using block device' CONFIG_MTD_BLKMTD $CONFIG_MTD
-
- comment 'Disk-On-Chip Device Drivers'
-- dep_tristate ' M-Systems Disk-On-Chip 1000' CONFIG_MTD_DOC1000 $CONFIG_MTD
-- dep_tristate ' M-Systems Disk-On-Chip 2000 and Millennium' CONFIG_MTD_DOC2000 $CONFIG_MTD
-- dep_tristate ' M-Systems Disk-On-Chip Millennium-only alternative driver (see help)' CONFIG_MTD_DOC2001 $CONFIG_MTD
-- if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" ]; then
-+ dep_tristate ' M-Systems Disk-On-Chip 2000 and Millennium (DEPRECATED)' CONFIG_MTD_DOC2000 $CONFIG_MTD
-+ dep_tristate ' M-Systems Disk-On-Chip Millennium-only alternative driver (DEPRECATED)' CONFIG_MTD_DOC2001 $CONFIG_MTD
-+ dep_tristate ' M-Systems Disk-On-Chip Millennium Plus driver (see help)' CONFIG_MTD_DOC2001PLUS $CONFIG_MTD
-+ if [ "$CONFIG_MTD_DOC2001PLUS" = "y" -o "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" ]; then
- define_bool CONFIG_MTD_DOCPROBE y
- else
-- if [ "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" ]; then
-+ if [ "$CONFIG_MTD_DOC2001PLUS" = "m" -o "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" ]; then
- define_bool CONFIG_MTD_DOCPROBE m
- else
- define_bool CONFIG_MTD_DOCPROBE n
- fi
- fi
-
-+ if [ "$CONFIG_MTD_DOCPROBE" = "y" ]; then
-+ define_bool CONFIG_MTD_DOCECC y
-+ else
-+ if [ "$CONFIG_MTD_DOCPROBE" = "m" ]; then
-+ define_bool CONFIG_MTD_DOCECC m
-+ else
-+ define_bool CONFIG_MTD_DOCECC n
-+ fi
-+ fi
-+
- if [ "$CONFIG_MTD_DOCPROBE" = "y" -o "$CONFIG_MTD_DOCPROBE" = "m" ]; then
- bool ' Advanced detection options for DiskOnChip' CONFIG_MTD_DOCPROBE_ADVANCED
- if [ "$CONFIG_MTD_DOCPROBE_ADVANCED" = "n" ]; then
---- linux-2.4.21/drivers/mtd/devices/Makefile~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/devices/Makefile
-@@ -1,27 +1,23 @@
- #
--# linux/drivers/devices/Makefile
-+# linux/drivers/maps/Makefile.24
-+# Makefile for obsolete kernels
- #
--# $Id: Makefile,v 1.4 2001/06/26 21:10:05 spse Exp $
-+# $Id: Makefile.24,v 1.2 2004/08/09 18:46:04 dmarlin Exp $
-
- O_TARGET := devlink.o
-+export-objs := docecc.o
-
--# *** BIG UGLY NOTE ***
--#
--# The removal of get_module_symbol() and replacement with
--# inter_module_register() et al has introduced a link order dependency
--# here where previously there was none. We now have to ensure that
--# doc200[01].o are linked before docprobe.o
--
--obj-$(CONFIG_MTD_DOC1000) += doc1000.o
- obj-$(CONFIG_MTD_DOC2000) += doc2000.o
- obj-$(CONFIG_MTD_DOC2001) += doc2001.o
--obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o docecc.o
-+obj-$(CONFIG_MTD_DOC2001PLUS) += doc2001plus.o
-+obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o
-+obj-$(CONFIG_MTD_DOCECC) += docecc.o
- obj-$(CONFIG_MTD_SLRAM) += slram.o
-+obj-$(CONFIG_MTD_PHRAM) += phram.o
- obj-$(CONFIG_MTD_PMC551) += pmc551.o
- obj-$(CONFIG_MTD_MS02NV) += ms02-nv.o
- obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
- obj-$(CONFIG_MTD_LART) += lart.o
--obj-$(CONFIG_MTD_SYNCFLASH) += syncflash.o
--obj-$(CONFIG_MTD_BLKMTD) += blkmtd.o
-+obj-$(CONFIG_MTD_BLKMTD) += blkmtd-24.o
-
- include $(TOPDIR)/Rules.make
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/devices/Makefile.common
-@@ -0,0 +1,25 @@
-+#
-+# linux/drivers/devices/Makefile
-+#
-+# $Id: Makefile.common,v 1.7 2004/12/22 17:51:15 joern Exp $
-+
-+# *** BIG UGLY NOTE ***
-+#
-+# The removal of get_module_symbol() and replacement with
-+# inter_module_register() et al has introduced a link order dependency
-+# here where previously there was none. We now have to ensure that
-+# doc200[01].o are linked before docprobe.o
-+
-+obj-$(CONFIG_MTD_DOC2000) += doc2000.o
-+obj-$(CONFIG_MTD_DOC2001) += doc2001.o
-+obj-$(CONFIG_MTD_DOC2001PLUS) += doc2001plus.o
-+obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o
-+obj-$(CONFIG_MTD_DOCECC) += docecc.o
-+obj-$(CONFIG_MTD_SLRAM) += slram.o
-+obj-$(CONFIG_MTD_PHRAM) += phram.o
-+obj-$(CONFIG_MTD_PMC551) += pmc551.o
-+obj-$(CONFIG_MTD_MS02NV) += ms02-nv.o
-+obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
-+obj-$(CONFIG_MTD_LART) += lart.o
-+obj-$(CONFIG_MTD_BLKMTD) += blkmtd.o
-+obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/devices/blkmtd-24.c
-@@ -0,0 +1,1056 @@
-+/*
-+ * $Id: blkmtd-24.c,v 1.23 2004/08/09 18:49:42 dmarlin Exp $
-+ *
-+ * blkmtd.c - use a block device as a fake MTD
-+ *
-+ * Author: Simon Evans <spse@secret.org.uk>
-+ *
-+ * Copyright (C) 2001,2002 Simon Evans
-+ *
-+ * Licence: GPL
-+ *
-+ * How it works:
-+ * The driver uses raw/io to read/write the device and the page
-+ * cache to cache access. Writes update the page cache with the
-+ * new data and mark it dirty and add the page into a kiobuf.
-+ * When the kiobuf becomes full or the next extry is to an earlier
-+ * block in the kiobuf then it is flushed to disk. This allows
-+ * writes to remained ordered and gives a small and simple outgoing
-+ * write cache.
-+ *
-+ * It can be loaded Read-Only to prevent erases and writes to the
-+ * medium.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/fs.h>
-+#include <linux/blkdev.h>
-+#include <linux/iobuf.h>
-+#include <linux/slab.h>
-+#include <linux/pagemap.h>
-+#include <linux/list.h>
-+#include <linux/mtd/mtd.h>
-+
-+#ifdef CONFIG_MTD_DEBUG
-+#ifdef CONFIG_PROC_FS
-+# include <linux/proc_fs.h>
-+# define BLKMTD_PROC_DEBUG
-+ static struct proc_dir_entry *blkmtd_proc;
-+#endif
-+#endif
-+
-+
-+#define err(format, arg...) printk(KERN_ERR "blkmtd: " format "\n" , ## arg)
-+#define info(format, arg...) printk(KERN_INFO "blkmtd: " format "\n" , ## arg)
-+#define warn(format, arg...) printk(KERN_WARNING "blkmtd: " format "\n" , ## arg)
-+#define crit(format, arg...) printk(KERN_CRIT "blkmtd: " format "\n" , ## arg)
-+
-+
-+/* Default erase size in KiB, always make it a multiple of PAGE_SIZE */
-+#define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10) /* 128KiB */
-+#define VERSION "1.10"
-+
-+/* Info for the block device */
-+struct blkmtd_dev {
-+ struct list_head list;
-+ struct block_device *binding;
-+ struct mtd_info mtd_info;
-+ struct kiobuf *rd_buf, *wr_buf;
-+ long iobuf_locks;
-+ struct semaphore wrbuf_mutex;
-+};
-+
-+
-+/* Static info about the MTD, used in cleanup_module */
-+static LIST_HEAD(blkmtd_device_list);
-+
-+
-+static void blkmtd_sync(struct mtd_info *mtd);
-+
-+#define MAX_DEVICES 4
-+
-+/* Module parameters passed by insmod/modprobe */
-+char *device[MAX_DEVICES]; /* the block device to use */
-+int erasesz[MAX_DEVICES]; /* optional default erase size */
-+int ro[MAX_DEVICES]; /* optional read only flag */
-+int sync;
-+
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
-+MODULE_DESCRIPTION("Emulate an MTD using a block device");
-+MODULE_PARM(device, "1-4s");
-+MODULE_PARM_DESC(device, "block device to use");
-+MODULE_PARM(erasesz, "1-4i");
-+MODULE_PARM_DESC(erasesz, "optional erase size to use in KiB. eg 4=4KiB.");
-+MODULE_PARM(ro, "1-4i");
-+MODULE_PARM_DESC(ro, "1=Read only, writes and erases cause errors");
-+MODULE_PARM(sync, "i");
-+MODULE_PARM_DESC(sync, "1=Synchronous writes");
-+
-+
-+/**
-+ * read_pages - read in pages via the page cache
-+ * @dev: device to read from
-+ * @pagenrs: list of page numbers wanted
-+ * @pagelst: storage for struce page * pointers
-+ * @pages: count of pages wanted
-+ *
-+ * Read pages, getting them from the page cache if available
-+ * else reading them in from disk if not. pagelst must be preallocated
-+ * to hold the page count.
-+ */
-+static int read_pages(struct blkmtd_dev *dev, int pagenrs[], struct page **pagelst, int pages)
-+{
-+ kdev_t kdev;
-+ struct page *page;
-+ int cnt = 0;
-+ struct kiobuf *iobuf;
-+ int err = 0;
-+
-+ if(!dev) {
-+ err("read_pages: PANIC dev == NULL");
-+ return -EIO;
-+ }
-+ kdev = to_kdev_t(dev->binding->bd_dev);
-+
-+ DEBUG(2, "read_pages: reading %d pages\n", pages);
-+ if(test_and_set_bit(0, &dev->iobuf_locks)) {
-+ err = alloc_kiovec(1, &iobuf);
-+ if (err) {
-+ crit("cant allocate kiobuf");
-+ return -ENOMEM;
-+ }
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-+ iobuf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);
-+ if(iobuf->blocks == NULL) {
-+ crit("cant allocate iobuf blocks");
-+ free_kiovec(1, &iobuf);
-+ return -ENOMEM;
-+ }
-+#endif
-+ } else {
-+ iobuf = dev->rd_buf;
-+ }
-+
-+ iobuf->nr_pages = 0;
-+ iobuf->length = 0;
-+ iobuf->offset = 0;
-+ iobuf->locked = 1;
-+
-+ for(cnt = 0; cnt < pages; cnt++) {
-+ page = grab_cache_page(dev->binding->bd_inode->i_mapping, pagenrs[cnt]);
-+ pagelst[cnt] = page;
-+ if(!Page_Uptodate(page)) {
-+ iobuf->blocks[iobuf->nr_pages] = pagenrs[cnt];
-+ iobuf->maplist[iobuf->nr_pages++] = page;
-+ }
-+ }
-+
-+ if(iobuf->nr_pages) {
-+ iobuf->length = iobuf->nr_pages << PAGE_SHIFT;
-+ err = brw_kiovec(READ, 1, &iobuf, kdev, iobuf->blocks, PAGE_SIZE);
-+ DEBUG(3, "blkmtd: read_pages: finished, err = %d\n", err);
-+ if(err < 0) {
-+ while(pages--) {
-+ ClearPageUptodate(pagelst[pages]);
-+ unlock_page(pagelst[pages]);
-+ page_cache_release(pagelst[pages]);
-+ }
-+ } else {
-+ while(iobuf->nr_pages--) {
-+ SetPageUptodate(iobuf->maplist[iobuf->nr_pages]);
-+ }
-+ err = 0;
-+ }
-+ }
-+
-+
-+ if(iobuf != dev->rd_buf) {
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-+ kfree(iobuf->blocks);
-+#endif
-+ free_kiovec(1, &iobuf);
-+ } else {
-+ clear_bit(0, &dev->iobuf_locks);
-+ }
-+ DEBUG(2, "read_pages: done, err = %d\n", err);
-+ return err;
-+}
-+
-+
-+/**
-+ * commit_pages - commit pages in the writeout kiobuf to disk
-+ * @dev: device to write to
-+ *
-+ * If the current dev has pages in the dev->wr_buf kiobuf,
-+ * they are written to disk using brw_kiovec()
-+ */
-+static int commit_pages(struct blkmtd_dev *dev)
-+{
-+ struct kiobuf *iobuf = dev->wr_buf;
-+ kdev_t kdev = to_kdev_t(dev->binding->bd_dev);
-+ int err = 0;
-+
-+ iobuf->length = iobuf->nr_pages << PAGE_SHIFT;
-+ iobuf->locked = 1;
-+ if(iobuf->length) {
-+ int i;
-+ DEBUG(2, "blkmtd: commit_pages: nrpages = %d\n", iobuf->nr_pages);
-+ /* Check all the pages are dirty and lock them */
-+ for(i = 0; i < iobuf->nr_pages; i++) {
-+ struct page *page = iobuf->maplist[i];
-+ BUG_ON(!PageDirty(page));
-+ lock_page(page);
-+ }
-+ err = brw_kiovec(WRITE, 1, &iobuf, kdev, iobuf->blocks, PAGE_SIZE);
-+ DEBUG(3, "commit_write: committed %d pages err = %d\n", iobuf->nr_pages, err);
-+ while(iobuf->nr_pages) {
-+ struct page *page = iobuf->maplist[--iobuf->nr_pages];
-+ ClearPageDirty(page);
-+ SetPageUptodate(page);
-+ unlock_page(page);
-+ page_cache_release(page);
-+ }
-+ }
-+
-+ DEBUG(2, "blkmtd: sync: end, err = %d\n", err);
-+ iobuf->offset = 0;
-+ iobuf->nr_pages = 0;
-+ iobuf->length = 0;
-+ return err;
-+}
-+
-+
-+/**
-+ * write_pages - write block of data to device via the page cache
-+ * @dev: device to write to
-+ * @buf: data source or NULL if erase (output is set to 0xff)
-+ * @to: offset into output device
-+ * @len: amount to data to write
-+ * @retlen: amount of data written
-+ *
-+ * Grab pages from the page cache and fill them with the source data.
-+ * Non page aligned start and end result in a readin of the page and
-+ * part of the page being modified. Pages are added to the wr_buf kiobuf
-+ * until this becomes full or the next page written to has a lower pagenr
-+ * then the current max pagenr in the kiobuf.
-+ */
-+static int write_pages(struct blkmtd_dev *dev, const u_char *buf, loff_t to,
-+ size_t len, int *retlen)
-+{
-+ int pagenr, offset;
-+ size_t start_len = 0, end_len;
-+ int pagecnt = 0;
-+ struct kiobuf *iobuf = dev->wr_buf;
-+ int err = 0;
-+ struct page *pagelst[2];
-+ int pagenrs[2];
-+ int readpages = 0;
-+ int ignorepage = -1;
-+
-+ pagenr = to >> PAGE_SHIFT;
-+ offset = to & ~PAGE_MASK;
-+
-+ DEBUG(2, "blkmtd: write_pages: buf = %p to = %ld len = %zd pagenr = %d offset = %d\n",
-+ buf, (long)to, len, pagenr, offset);
-+
-+ *retlen = 0;
-+ /* see if we have to do a partial write at the start */
-+ if(offset) {
-+ start_len = ((offset + len) > PAGE_SIZE) ? PAGE_SIZE - offset : len;
-+ len -= start_len;
-+ }
-+
-+ /* calculate the length of the other two regions */
-+ end_len = len & ~PAGE_MASK;
-+ len -= end_len;
-+
-+ if(start_len) {
-+ pagenrs[0] = pagenr;
-+ readpages++;
-+ pagecnt++;
-+ }
-+ if(len)
-+ pagecnt += len >> PAGE_SHIFT;
-+ if(end_len) {
-+ pagenrs[readpages] = pagenr + pagecnt;
-+ readpages++;
-+ pagecnt++;
-+ }
-+
-+ DEBUG(3, "blkmtd: write: start_len = %zd len = %zd end_len = %zd pagecnt = %d\n",
-+ start_len, len, end_len, pagecnt);
-+
-+ down(&dev->wrbuf_mutex);
-+
-+ if(iobuf->nr_pages && ((pagenr <= iobuf->blocks[iobuf->nr_pages-1])
-+ || (iobuf->nr_pages + pagecnt) >= KIO_STATIC_PAGES)) {
-+
-+ if((pagenr == iobuf->blocks[iobuf->nr_pages-1])
-+ && ((iobuf->nr_pages + pagecnt) < KIO_STATIC_PAGES)) {
-+ iobuf->nr_pages--;
-+ ignorepage = pagenr;
-+ } else {
-+ DEBUG(3, "blkmtd: doing writeout pagenr = %d max_pagenr = %ld pagecnt = %d idx = %d\n",
-+ pagenr, iobuf->blocks[iobuf->nr_pages-1],
-+ pagecnt, iobuf->nr_pages);
-+ commit_pages(dev);
-+ }
-+ }
-+
-+ if(readpages) {
-+ err = read_pages(dev, pagenrs, pagelst, readpages);
-+ if(err < 0)
-+ goto readin_err;
-+ }
-+
-+ if(start_len) {
-+ /* do partial start region */
-+ struct page *page;
-+
-+ DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %zd offset = %d\n",
-+ pagenr, start_len, offset);
-+ page = pagelst[0];
-+ BUG_ON(!buf);
-+ if(PageDirty(page) && pagenr != ignorepage) {
-+ err("to = %lld start_len = %zd len = %zd end_len = %zd pagenr = %d ignorepage = %d\n",
-+ to, start_len, len, end_len, pagenr, ignorepage);
-+ BUG();
-+ }
-+ memcpy(page_address(page)+offset, buf, start_len);
-+ SetPageDirty(page);
-+ SetPageUptodate(page);
-+ unlock_page(page);
-+ buf += start_len;
-+ *retlen = start_len;
-+ err = 0;
-+ iobuf->blocks[iobuf->nr_pages] = pagenr++;
-+ iobuf->maplist[iobuf->nr_pages] = page;
-+ iobuf->nr_pages++;
-+ }
-+
-+ /* Now do the main loop to a page aligned, n page sized output */
-+ if(len) {
-+ int pagesc = len >> PAGE_SHIFT;
-+ DEBUG(3, "blkmtd: write: whole pages start = %d, count = %d\n",
-+ pagenr, pagesc);
-+ while(pagesc) {
-+ struct page *page;
-+
-+ /* see if page is in the page cache */
-+ DEBUG(3, "blkmtd: write: grabbing page %d from page cache\n", pagenr);
-+ page = grab_cache_page(dev->binding->bd_inode->i_mapping, pagenr);
-+ if(PageDirty(page) && pagenr != ignorepage) {
-+ BUG();
-+ }
-+ if(!page) {
-+ warn("write: cant grab cache page %d", pagenr);
-+ err = -ENOMEM;
-+ goto write_err;
-+ }
-+ if(!buf) {
-+ memset(page_address(page), 0xff, PAGE_SIZE);
-+ } else {
-+ memcpy(page_address(page), buf, PAGE_SIZE);
-+ buf += PAGE_SIZE;
-+ }
-+ iobuf->blocks[iobuf->nr_pages] = pagenr++;
-+ iobuf->maplist[iobuf->nr_pages] = page;
-+ iobuf->nr_pages++;
-+ SetPageDirty(page);
-+ SetPageUptodate(page);
-+ unlock_page(page);
-+ pagesc--;
-+ *retlen += PAGE_SIZE;
-+ }
-+ }
-+
-+ if(end_len) {
-+ /* do the third region */
-+ struct page *page;
-+ DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %zd\n",
-+ pagenr, end_len);
-+ page = pagelst[readpages-1];
-+ BUG_ON(!buf);
-+ if(PageDirty(page) && pagenr != ignorepage) {
-+ err("to = %lld start_len = %zd len = %zd end_len = %zd pagenr = %d ignorepage = %d\n",
-+ to, start_len, len, end_len, pagenr, ignorepage);
-+ BUG();
-+ }
-+ memcpy(page_address(page), buf, end_len);
-+ SetPageDirty(page);
-+ SetPageUptodate(page);
-+ unlock_page(page);
-+ DEBUG(3, "blkmtd: write: writing out partial end\n");
-+ *retlen += end_len;
-+ err = 0;
-+ iobuf->blocks[iobuf->nr_pages] = pagenr;
-+ iobuf->maplist[iobuf->nr_pages] = page;
-+ iobuf->nr_pages++;
-+ }
-+
-+ DEBUG(2, "blkmtd: write: end, retlen = %zd, err = %d\n", *retlen, err);
-+
-+ if(sync) {
-+write_err:
-+ commit_pages(dev);
-+ }
-+
-+readin_err:
-+ up(&dev->wrbuf_mutex);
-+ return err;
-+}
-+
-+
-+/* erase a specified part of the device */
-+static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
-+{
-+ struct blkmtd_dev *dev = mtd->priv;
-+ struct mtd_erase_region_info *einfo = mtd->eraseregions;
-+ int numregions = mtd->numeraseregions;
-+ size_t from;
-+ u_long len;
-+ int err = -EIO;
-+ size_t retlen;
-+
-+ /* check readonly */
-+ if(!dev->wr_buf) {
-+ err("error: mtd%d trying to erase readonly device %s",
-+ mtd->index, mtd->name);
-+ instr->state = MTD_ERASE_FAILED;
-+ goto erase_callback;
-+ }
-+
-+ instr->state = MTD_ERASING;
-+ from = instr->addr;
-+ len = instr->len;
-+
-+ /* check erase region has valid start and length */
-+ DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%zx len = 0x%lx\n",
-+ bdevname(dev->binding->bd_dev), from, len);
-+ while(numregions) {
-+ DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n",
-+ einfo->offset, einfo->erasesize, einfo->numblocks);
-+ if(from >= einfo->offset
-+ && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) {
-+ if(len == einfo->erasesize
-+ && ( (from - einfo->offset) % einfo->erasesize == 0))
-+ break;
-+ }
-+ numregions--;
-+ einfo++;
-+ }
-+
-+ if(!numregions) {
-+ /* Not a valid erase block */
-+ err("erase: invalid erase request 0x%lX @ 0x%08zX", len, from);
-+ instr->state = MTD_ERASE_FAILED;
-+ err = -EIO;
-+ }
-+
-+ if(instr->state != MTD_ERASE_FAILED) {
-+ /* do the erase */
-+ DEBUG(3, "Doing erase from = %zd len = %ld\n", from, len);
-+ err = write_pages(dev, NULL, from, len, &retlen);
-+ if(err < 0) {
-+ err("erase failed err = %d", err);
-+ instr->state = MTD_ERASE_FAILED;
-+ } else {
-+ instr->state = MTD_ERASE_DONE;
-+ err = 0;
-+ }
-+ }
-+
-+ DEBUG(3, "blkmtd: erase: checking callback\n");
-+ erase_callback:
-+ mtd_erase_callback(instr);
-+ DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err);
-+ return err;
-+}
-+
-+
-+/* read a range of the data via the page cache */
-+static int blkmtd_read(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t *retlen, u_char *buf)
-+{
-+ struct blkmtd_dev *dev = mtd->priv;
-+ int err = 0;
-+ int offset;
-+ int pagenr, pages;
-+ struct page **pagelst;
-+ int *pagenrs;
-+ int i;
-+
-+ *retlen = 0;
-+
-+ DEBUG(2, "blkmtd: read: dev = `%s' from = %lld len = %zd buf = %p\n",
-+ bdevname(dev->binding->bd_dev), from, len, buf);
-+
-+ pagenr = from >> PAGE_SHIFT;
-+ offset = from - (pagenr << PAGE_SHIFT);
-+
-+ pages = (offset+len+PAGE_SIZE-1) >> PAGE_SHIFT;
-+ DEBUG(3, "blkmtd: read: pagenr = %d offset = %d, pages = %d\n",
-+ pagenr, offset, pages);
-+
-+ pagelst = kmalloc(sizeof(struct page *) * pages, GFP_KERNEL);
-+ if(!pagelst)
-+ return -ENOMEM;
-+ pagenrs = kmalloc(sizeof(int) * pages, GFP_KERNEL);
-+ if(!pagenrs) {
-+ kfree(pagelst);
-+ return -ENOMEM;
-+ }
-+ for(i = 0; i < pages; i++)
-+ pagenrs[i] = pagenr+i;
-+
-+ err = read_pages(dev, pagenrs, pagelst, pages);
-+ if(err)
-+ goto readerr;
-+
-+ pagenr = 0;
-+ while(pages) {
-+ struct page *page;
-+ int cpylen;
-+
-+ DEBUG(3, "blkmtd: read: looking for page: %d\n", pagenr);
-+ page = pagelst[pagenr];
-+
-+ cpylen = (PAGE_SIZE > len) ? len : PAGE_SIZE;
-+ if(offset+cpylen > PAGE_SIZE)
-+ cpylen = PAGE_SIZE-offset;
-+
-+ memcpy(buf + *retlen, page_address(page) + offset, cpylen);
-+ offset = 0;
-+ len -= cpylen;
-+ *retlen += cpylen;
-+ pagenr++;
-+ pages--;
-+ unlock_page(page);
-+ if(!PageDirty(page))
-+ page_cache_release(page);
-+ }
-+
-+ readerr:
-+ kfree(pagelst);
-+ kfree(pagenrs);
-+ DEBUG(2, "blkmtd: end read: retlen = %zd, err = %d\n", *retlen, err);
-+ return err;
-+}
-+
-+
-+/* write data to the underlying device */
-+static int blkmtd_write(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t *retlen, const u_char *buf)
-+{
-+ struct blkmtd_dev *dev = mtd->priv;
-+ int err;
-+
-+ *retlen = 0;
-+ if(!len)
-+ return 0;
-+
-+ DEBUG(2, "blkmtd: write: dev = `%s' to = %lld len = %zd buf = %p\n",
-+ bdevname(dev->binding->bd_dev), to, len, buf);
-+
-+ /* handle readonly and out of range numbers */
-+
-+ if(!dev->wr_buf) {
-+ err("error: trying to write to a readonly device %s", mtd->name);
-+ return -EROFS;
-+ }
-+
-+ if(to >= mtd->size) {
-+ return -ENOSPC;
-+ }
-+
-+ if(to + len > mtd->size) {
-+ len = (mtd->size - to);
-+ }
-+
-+ err = write_pages(dev, buf, to, len, retlen);
-+ if(err < 0)
-+ *retlen = 0;
-+ else
-+ err = 0;
-+ DEBUG(2, "blkmtd: write: end, err = %d\n", err);
-+ return err;
-+}
-+
-+
-+/* sync the device - wait until the write queue is empty */
-+static void blkmtd_sync(struct mtd_info *mtd)
-+{
-+ struct blkmtd_dev *dev = mtd->priv;
-+ struct kiobuf *iobuf = dev->wr_buf;
-+
-+ DEBUG(2, "blkmtd: sync: called\n");
-+ if(iobuf == NULL)
-+ return;
-+
-+ DEBUG(3, "blkmtd: kiovec: length = %d nr_pages = %d\n",
-+ iobuf->length, iobuf->nr_pages);
-+ down(&dev->wrbuf_mutex);
-+ if(iobuf->nr_pages)
-+ commit_pages(dev);
-+ up(&dev->wrbuf_mutex);
-+}
-+
-+
-+#ifdef BLKMTD_PROC_DEBUG
-+/* procfs stuff */
-+static int blkmtd_proc_read(char *page, char **start, off_t off,
-+ int count, int *eof, void *data)
-+{
-+ int len;
-+ struct list_head *temp1, *temp2;
-+
-+ MOD_INC_USE_COUNT;
-+
-+ /* Count the size of the page lists */
-+
-+ len = sprintf(page, "dev\twr_idx\tmax_idx\tnrpages\tclean\tdirty\tlocked\tlru\n");
-+ list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
-+ struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
-+ list);
-+ struct list_head *temp;
-+ struct page *pagei;
-+
-+ int clean = 0, dirty = 0, locked = 0, lru = 0;
-+ /* Count the size of the page lists */
-+ list_for_each(temp, &dev->binding->bd_inode->i_mapping->clean_pages) {
-+ pagei = list_entry(temp, struct page, list);
-+ clean++;
-+ if(PageLocked(pagei))
-+ locked++;
-+ if(PageDirty(pagei))
-+ dirty++;
-+ if(PageLRU(pagei))
-+ lru++;
-+ }
-+ list_for_each(temp, &dev->binding->bd_inode->i_mapping->dirty_pages) {
-+ pagei = list_entry(temp, struct page, list);
-+ if(PageLocked(pagei))
-+ locked++;
-+ if(PageDirty(pagei))
-+ dirty++;
-+ if(PageLRU(pagei))
-+ lru++;
-+ }
-+ list_for_each(temp, &dev->binding->bd_inode->i_mapping->locked_pages) {
-+ pagei = list_entry(temp, struct page, list);
-+ if(PageLocked(pagei))
-+ locked++;
-+ if(PageDirty(pagei))
-+ dirty++;
-+ if(PageLRU(pagei))
-+ lru++;
-+ }
-+
-+ len += sprintf(page+len, "mtd%d:\t%ld\t%d\t%ld\t%d\t%d\t%d\t%d\n",
-+ dev->mtd_info.index,
-+ (dev->wr_buf && dev->wr_buf->nr_pages) ?
-+ dev->wr_buf->blocks[dev->wr_buf->nr_pages-1] : 0,
-+ (dev->wr_buf) ? dev->wr_buf->nr_pages : 0,
-+ dev->binding->bd_inode->i_mapping->nrpages,
-+ clean, dirty, locked, lru);
-+ }
-+
-+ if(len <= count)
-+ *eof = 1;
-+
-+ MOD_DEC_USE_COUNT;
-+ return len;
-+}
-+#endif
-+
-+
-+static void free_device(struct blkmtd_dev *dev)
-+{
-+ DEBUG(2, "blkmtd: free_device() dev = %p\n", dev);
-+ if(dev) {
-+ del_mtd_device(&dev->mtd_info);
-+ info("mtd%d: [%s] removed", dev->mtd_info.index,
-+ dev->mtd_info.name + strlen("blkmtd: "));
-+ if(dev->mtd_info.eraseregions)
-+ kfree(dev->mtd_info.eraseregions);
-+ if(dev->mtd_info.name)
-+ kfree(dev->mtd_info.name);
-+
-+ if(dev->rd_buf) {
-+ dev->rd_buf->locked = 0;
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-+ if(dev->rd_buf->blocks)
-+ kfree(dev->rd_buf->blocks);
-+#endif
-+ free_kiovec(1, &dev->rd_buf);
-+ }
-+ if(dev->wr_buf) {
-+ dev->wr_buf->locked = 0;
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-+ if(dev->wr_buf->blocks)
-+ kfree(dev->rw_buf->blocks);
-+#endif
-+ free_kiovec(1, &dev->wr_buf);
-+ }
-+
-+ if(dev->binding) {
-+ kdev_t kdev = to_kdev_t(dev->binding->bd_dev);
-+ invalidate_inode_pages(dev->binding->bd_inode);
-+ set_blocksize(kdev, 1 << 10);
-+ blkdev_put(dev->binding, BDEV_RAW);
-+ }
-+ kfree(dev);
-+ }
-+}
-+
-+
-+/* For a given size and initial erase size, calculate the number
-+ * and size of each erase region. Goes round the loop twice,
-+ * once to find out how many regions, then allocates space,
-+ * then round the loop again to fill it in.
-+ */
-+static struct mtd_erase_region_info *calc_erase_regions(
-+ size_t erase_size, size_t total_size, int *regions)
-+{
-+ struct mtd_erase_region_info *info = NULL;
-+
-+ DEBUG(2, "calc_erase_regions, es = %zd size = %zd regions = %d\n",
-+ erase_size, total_size, *regions);
-+ /* Make any user specified erasesize be a power of 2
-+ and at least PAGE_SIZE */
-+ if(erase_size) {
-+ int es = erase_size;
-+ erase_size = 1;
-+ while(es != 1) {
-+ es >>= 1;
-+ erase_size <<= 1;
-+ }
-+ if(erase_size < PAGE_SIZE)
-+ erase_size = PAGE_SIZE;
-+ } else {
-+ erase_size = CONFIG_MTD_BLKDEV_ERASESIZE;
-+ }
-+
-+ *regions = 0;
-+
-+ do {
-+ int tot_size = total_size;
-+ int er_size = erase_size;
-+ int count = 0, offset = 0, regcnt = 0;
-+
-+ while(tot_size) {
-+ count = tot_size / er_size;
-+ if(count) {
-+ tot_size = tot_size % er_size;
-+ if(info) {
-+ DEBUG(2, "adding to erase info off=%d er=%d cnt=%d\n",
-+ offset, er_size, count);
-+ (info+regcnt)->offset = offset;
-+ (info+regcnt)->erasesize = er_size;
-+ (info+regcnt)->numblocks = count;
-+ (*regions)++;
-+ }
-+ regcnt++;
-+ offset += (count * er_size);
-+ }
-+ while(er_size > tot_size)
-+ er_size >>= 1;
-+ }
-+ if(info == NULL) {
-+ info = kmalloc(regcnt * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
-+ if(!info)
-+ break;
-+ }
-+ } while(!(*regions));
-+ DEBUG(2, "calc_erase_regions done, es = %zd size = %zd regions = %d\n",
-+ erase_size, total_size, *regions);
-+ return info;
-+}
-+
-+
-+extern kdev_t name_to_kdev_t(char *line) __init;
-+
-+
-+static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size)
-+{
-+ int maj, min;
-+ kdev_t kdev;
-+ int mode;
-+ struct blkmtd_dev *dev;
-+
-+#ifdef MODULE
-+ struct file *file = NULL;
-+ struct inode *inode;
-+#endif
-+
-+ if(!devname)
-+ return NULL;
-+
-+ /* Get a handle on the device */
-+ mode = (readonly) ? O_RDONLY : O_RDWR;
-+
-+#ifdef MODULE
-+
-+ file = filp_open(devname, mode, 0);
-+ if(IS_ERR(file)) {
-+ err("error: cant open device %s", devname);
-+ DEBUG(2, "blkmtd: filp_open returned %ld\n", PTR_ERR(file));
-+ return NULL;
-+ }
-+
-+ /* determine is this is a block device and
-+ * if so get its major and minor numbers
-+ */
-+ inode = file->f_dentry->d_inode;
-+ if(!S_ISBLK(inode->i_mode)) {
-+ err("%s not a block device", devname);
-+ filp_close(file, NULL);
-+ return NULL;
-+ }
-+ kdev = inode->i_rdev;
-+ filp_close(file, NULL);
-+#else
-+ kdev = name_to_kdev_t(devname);
-+#endif /* MODULE */
-+
-+ if(!kdev) {
-+ err("bad block device: `%s'", devname);
-+ return NULL;
-+ }
-+
-+ maj = MAJOR(kdev);
-+ min = MINOR(kdev);
-+ DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n",
-+ maj, min);
-+
-+ if(maj == MTD_BLOCK_MAJOR) {
-+ err("attempting to use an MTD device as a block device");
-+ return NULL;
-+ }
-+
-+ DEBUG(1, "blkmtd: devname = %s\n", bdevname(kdev));
-+
-+ dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL);
-+ if(dev == NULL)
-+ return NULL;
-+
-+ memset(dev, 0, sizeof(struct blkmtd_dev));
-+ if(alloc_kiovec(1, &dev->rd_buf)) {
-+ err("cant allocate read iobuf");
-+ goto devinit_err;
-+ }
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-+ dev->rd_buf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);
-+ if(dev->rd_buf->blocks == NULL) {
-+ crit("cant allocate rd_buf blocks");
-+ goto devinit_err;
-+ }
-+#endif
-+
-+ if(!readonly) {
-+ if(alloc_kiovec(1, &dev->wr_buf)) {
-+ err("cant allocate kiobuf - readonly enabled");
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-+ } else {
-+ dev->wr_buf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);
-+ if(dev->wr_buf->blocks == NULL) {
-+ crit("cant allocate wr_buf blocks - readonly enabled");
-+ free_kiovec(1, &iobuf);
-+ }
-+#endif
-+ }
-+ if(dev->wr_buf)
-+ init_MUTEX(&dev->wrbuf_mutex);
-+ }
-+
-+ /* get the block device */
-+ dev->binding = bdget(kdev_t_to_nr(MKDEV(maj, min)));
-+ if(blkdev_get(dev->binding, mode, 0, BDEV_RAW))
-+ goto devinit_err;
-+
-+ if(set_blocksize(kdev, PAGE_SIZE)) {
-+ err("cant set block size to PAGE_SIZE on %s", bdevname(kdev));
-+ goto devinit_err;
-+ }
-+
-+ dev->mtd_info.size = dev->binding->bd_inode->i_size & PAGE_MASK;
-+
-+ /* Setup the MTD structure */
-+ /* make the name contain the block device in */
-+ dev->mtd_info.name = kmalloc(sizeof("blkmtd: ") + strlen(devname), GFP_KERNEL);
-+ if(dev->mtd_info.name == NULL)
-+ goto devinit_err;
-+
-+ sprintf(dev->mtd_info.name, "blkmtd: %s", devname);
-+ dev->mtd_info.eraseregions = calc_erase_regions(erase_size, dev->mtd_info.size,
-+ &dev->mtd_info.numeraseregions);
-+ if(dev->mtd_info.eraseregions == NULL)
-+ goto devinit_err;
-+
-+ dev->mtd_info.erasesize = dev->mtd_info.eraseregions->erasesize;
-+ DEBUG(1, "blkmtd: init: found %d erase regions\n",
-+ dev->mtd_info.numeraseregions);
-+
-+ if(readonly) {
-+ dev->mtd_info.type = MTD_ROM;
-+ dev->mtd_info.flags = MTD_CAP_ROM;
-+ } else {
-+ dev->mtd_info.type = MTD_RAM;
-+ dev->mtd_info.flags = MTD_CAP_RAM;
-+ }
-+ dev->mtd_info.erase = blkmtd_erase;
-+ dev->mtd_info.read = blkmtd_read;
-+ dev->mtd_info.write = blkmtd_write;
-+ dev->mtd_info.sync = blkmtd_sync;
-+ dev->mtd_info.point = 0;
-+ dev->mtd_info.unpoint = 0;
-+ dev->mtd_info.priv = dev;
-+ dev->mtd_info.owner = THIS_MODULE;
-+
-+ list_add(&dev->list, &blkmtd_device_list);
-+ if (add_mtd_device(&dev->mtd_info)) {
-+ /* Device didnt get added, so free the entry */
-+ list_del(&dev->list);
-+ free_device(dev);
-+ return NULL;
-+ } else {
-+ info("mtd%d: [%s] erase_size = %dKiB %s",
-+ dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "),
-+ dev->mtd_info.erasesize >> 10,
-+ (dev->wr_buf) ? "" : "(read-only)");
-+ }
-+
-+ return dev;
-+
-+ devinit_err:
-+ free_device(dev);
-+ return NULL;
-+}
-+
-+
-+/* Cleanup and exit - sync the device and kill of the kernel thread */
-+static void __devexit cleanup_blkmtd(void)
-+{
-+ struct list_head *temp1, *temp2;
-+#ifdef BLKMTD_PROC_DEBUG
-+ if(blkmtd_proc) {
-+ remove_proc_entry("blkmtd_debug", NULL);
-+ }
-+#endif
-+
-+ /* Remove the MTD devices */
-+ list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
-+ struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
-+ list);
-+ blkmtd_sync(&dev->mtd_info);
-+ free_device(dev);
-+ }
-+}
-+
-+#ifndef MODULE
-+
-+/* Handle kernel boot params */
-+
-+
-+static int __init param_blkmtd_device(char *str)
-+{
-+ int i;
-+
-+ for(i = 0; i < MAX_DEVICES; i++) {
-+ device[i] = str;
-+ DEBUG(2, "blkmtd: device setup: %d = %s\n", i, device[i]);
-+ strsep(&str, ",");
-+ }
-+ return 1;
-+}
-+
-+
-+static int __init param_blkmtd_erasesz(char *str)
-+{
-+ int i;
-+ for(i = 0; i < MAX_DEVICES; i++) {
-+ char *val = strsep(&str, ",");
-+ if(val)
-+ erasesz[i] = simple_strtoul(val, NULL, 0);
-+ DEBUG(2, "blkmtd: erasesz setup: %d = %d\n", i, erasesz[i]);
-+ }
-+
-+ return 1;
-+}
-+
-+
-+static int __init param_blkmtd_ro(char *str)
-+{
-+ int i;
-+ for(i = 0; i < MAX_DEVICES; i++) {
-+ char *val = strsep(&str, ",");
-+ if(val)
-+ ro[i] = simple_strtoul(val, NULL, 0);
-+ DEBUG(2, "blkmtd: ro setup: %d = %d\n", i, ro[i]);
-+ }
-+
-+ return 1;
-+}
-+
-+
-+static int __init param_blkmtd_sync(char *str)
-+{
-+ if(str[0] == '1')
-+ sync = 1;
-+ return 1;
-+}
-+
-+__setup("blkmtd_device=", param_blkmtd_device);
-+__setup("blkmtd_erasesz=", param_blkmtd_erasesz);
-+__setup("blkmtd_ro=", param_blkmtd_ro);
-+__setup("blkmtd_sync=", param_blkmtd_sync);
-+
-+#endif
-+
-+
-+/* Startup */
-+static int __init init_blkmtd(void)
-+{
-+ int i;
-+
-+ /* Check args - device[0] is the bare minimum*/
-+ if(!device[0]) {
-+ err("error: missing `device' name\n");
-+ return -EINVAL;
-+ }
-+
-+ for(i = 0; i < MAX_DEVICES; i++)
-+ add_device(device[i], ro[i], erasesz[i] << 10);
-+
-+ if(list_empty(&blkmtd_device_list))
-+ goto init_err;
-+
-+ info("version " VERSION);
-+
-+#ifdef BLKMTD_PROC_DEBUG
-+ /* create proc entry */
-+ DEBUG(2, "Creating /proc/blkmtd_debug\n");
-+ blkmtd_proc = create_proc_read_entry("blkmtd_debug", 0444,
-+ NULL, blkmtd_proc_read, NULL);
-+ if(blkmtd_proc == NULL) {
-+ err("Cant create /proc/blkmtd_debug");
-+ } else {
-+ blkmtd_proc->owner = THIS_MODULE;
-+ }
-+#endif
-+
-+ if(!list_empty(&blkmtd_device_list))
-+ /* Everything is ok if we got here */
-+ return 0;
-+
-+ init_err:
-+ return -EINVAL;
-+}
-+
-+module_init(init_blkmtd);
-+module_exit(cleanup_blkmtd);
---- linux-2.4.21/drivers/mtd/devices/blkmtd.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/devices/blkmtd.c
-@@ -1,5 +1,5 @@
- /*
-- * $Id: blkmtd.c,v 1.17 2003/01/24 13:00:24 dwmw2 Exp $
-+ * $Id: blkmtd.c,v 1.24 2004/11/16 18:29:01 dwmw2 Exp $
- *
- * blkmtd.c - use a block device as a fake MTD
- *
-@@ -12,11 +12,8 @@
- * How it works:
- * The driver uses raw/io to read/write the device and the page
- * cache to cache access. Writes update the page cache with the
-- * new data and mark it dirty and add the page into a kiobuf.
-- * When the kiobuf becomes full or the next extry is to an earlier
-- * block in the kiobuf then it is flushed to disk. This allows
-- * writes to remained ordered and gives a small and simple outgoing
-- * write cache.
-+ * new data and mark it dirty and add the page into a BIO which
-+ * is then written out.
- *
- * It can be loaded Read-Only to prevent erases and writes to the
- * medium.
-@@ -27,20 +24,12 @@
- #include <linux/module.h>
- #include <linux/fs.h>
- #include <linux/blkdev.h>
--#include <linux/iobuf.h>
--#include <linux/slab.h>
-+#include <linux/bio.h>
- #include <linux/pagemap.h>
- #include <linux/list.h>
-+#include <linux/init.h>
- #include <linux/mtd/mtd.h>
-
--#ifdef CONFIG_MTD_DEBUG
--#ifdef CONFIG_PROC_FS
--# include <linux/proc_fs.h>
--# define BLKMTD_PROC_DEBUG
-- static struct proc_dir_entry *blkmtd_proc;
--#endif
--#endif
--
-
- #define err(format, arg...) printk(KERN_ERR "blkmtd: " format "\n" , ## arg)
- #define info(format, arg...) printk(KERN_INFO "blkmtd: " format "\n" , ## arg)
-@@ -48,17 +37,15 @@
- #define crit(format, arg...) printk(KERN_CRIT "blkmtd: " format "\n" , ## arg)
-
-
--/* Default erase size in KiB, always make it a multiple of PAGE_SIZE */
-+/* Default erase size in K, always make it a multiple of PAGE_SIZE */
- #define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10) /* 128KiB */
--#define VERSION "1.10"
-+#define VERSION "$Revision: 1.24 $"
-
- /* Info for the block device */
- struct blkmtd_dev {
- struct list_head list;
-- struct block_device *binding;
-+ struct block_device *blkdev;
- struct mtd_info mtd_info;
-- struct kiobuf *rd_buf, *wr_buf;
-- long iobuf_locks;
- struct semaphore wrbuf_mutex;
- };
-
-@@ -72,10 +59,10 @@
- #define MAX_DEVICES 4
-
- /* Module parameters passed by insmod/modprobe */
--char *device[MAX_DEVICES]; /* the block device to use */
--int erasesz[MAX_DEVICES]; /* optional default erase size */
--int ro[MAX_DEVICES]; /* optional read only flag */
--int sync;
-+static char *device[MAX_DEVICES]; /* the block device to use */
-+static int erasesz[MAX_DEVICES]; /* optional default erase size */
-+static int ro[MAX_DEVICES]; /* optional read only flag */
-+static int sync;
-
-
- MODULE_LICENSE("GPL");
-@@ -91,136 +78,145 @@
- MODULE_PARM_DESC(sync, "1=Synchronous writes");
-
-
--/**
-- * read_pages - read in pages via the page cache
-- * @dev: device to read from
-- * @pagenrs: list of page numbers wanted
-- * @pagelst: storage for struce page * pointers
-- * @pages: count of pages wanted
-- *
-- * Read pages, getting them from the page cache if available
-- * else reading them in from disk if not. pagelst must be preallocated
-- * to hold the page count.
-- */
--static int read_pages(struct blkmtd_dev *dev, int pagenrs[], struct page **pagelst, int pages)
-+/* completion handler for BIO reads */
-+static int bi_read_complete(struct bio *bio, unsigned int bytes_done, int error)
- {
-- kdev_t kdev;
-- struct page *page;
-- int cnt = 0;
-- struct kiobuf *iobuf;
-- int err = 0;
-+ if (bio->bi_size)
-+ return 1;
-
-- if(!dev) {
-- err("read_pages: PANIC dev == NULL");
-- return -EIO;
-- }
-- kdev = to_kdev_t(dev->binding->bd_dev);
-+ complete((struct completion*)bio->bi_private);
-+ return 0;
-+}
-
-- DEBUG(2, "read_pages: reading %d pages\n", pages);
-- if(test_and_set_bit(0, &dev->iobuf_locks)) {
-- err = alloc_kiovec(1, &iobuf);
-- if (err) {
-- crit("cant allocate kiobuf");
-- return -ENOMEM;
-- }
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-- iobuf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);
-- if(iobuf->blocks == NULL) {
-- crit("cant allocate iobuf blocks");
-- free_kiovec(1, &iobuf);
-- return -ENOMEM;
-- }
--#endif
-+
-+/* completion handler for BIO writes */
-+static int bi_write_complete(struct bio *bio, unsigned int bytes_done, int error)
-+{
-+ const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
-+ struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
-+
-+ if (bio->bi_size)
-+ return 1;
-+
-+ if(!uptodate)
-+ err("bi_write_complete: not uptodate\n");
-+
-+ do {
-+ struct page *page = bvec->bv_page;
-+ DEBUG(3, "Cleaning up page %ld\n", page->index);
-+ if (--bvec >= bio->bi_io_vec)
-+ prefetchw(&bvec->bv_page->flags);
-+
-+ if (uptodate) {
-+ SetPageUptodate(page);
- } else {
-- iobuf = dev->rd_buf;
-+ ClearPageUptodate(page);
-+ SetPageError(page);
- }
-+ ClearPageDirty(page);
-+ unlock_page(page);
-+ page_cache_release(page);
-+ } while (bvec >= bio->bi_io_vec);
-
-- iobuf->nr_pages = 0;
-- iobuf->length = 0;
-- iobuf->offset = 0;
-- iobuf->locked = 1;
-+ complete((struct completion*)bio->bi_private);
-+ return 0;
-+}
-
-- for(cnt = 0; cnt < pages; cnt++) {
-- page = grab_cache_page(dev->binding->bd_inode->i_mapping, pagenrs[cnt]);
-- pagelst[cnt] = page;
-- if(!PageUptodate(page)) {
-- iobuf->blocks[iobuf->nr_pages] = pagenrs[cnt];
-- iobuf->maplist[iobuf->nr_pages++] = page;
-- }
-- }
-
-- if(iobuf->nr_pages) {
-- iobuf->length = iobuf->nr_pages << PAGE_SHIFT;
-- err = brw_kiovec(READ, 1, &iobuf, kdev, iobuf->blocks, PAGE_SIZE);
-- DEBUG(3, "blkmtd: read_pages: finished, err = %d\n", err);
-- if(err < 0) {
-- while(pages--) {
-- ClearPageUptodate(pagelst[pages]);
-- unlock_page(pagelst[pages]);
-- page_cache_release(pagelst[pages]);
-- }
-- } else {
-- while(iobuf->nr_pages--) {
-- SetPageUptodate(iobuf->maplist[iobuf->nr_pages]);
-+/* read one page from the block device */
-+static int blkmtd_readpage(struct blkmtd_dev *dev, struct page *page)
-+{
-+ struct bio *bio;
-+ struct completion event;
-+ int err = -ENOMEM;
-+
-+ if(PageUptodate(page)) {
-+ DEBUG(2, "blkmtd: readpage page %ld is already upto date\n", page->index);
-+ unlock_page(page);
-+ return 0;
- }
-- err = 0;
-+
-+ ClearPageUptodate(page);
-+ ClearPageError(page);
-+
-+ bio = bio_alloc(GFP_KERNEL, 1);
-+ if(bio) {
-+ init_completion(&event);
-+ bio->bi_bdev = dev->blkdev;
-+ bio->bi_sector = page->index << (PAGE_SHIFT-9);
-+ bio->bi_private = &event;
-+ bio->bi_end_io = bi_read_complete;
-+ if(bio_add_page(bio, page, PAGE_SIZE, 0) == PAGE_SIZE) {
-+ submit_bio(READ_SYNC, bio);
-+ wait_for_completion(&event);
-+ err = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : -EIO;
-+ bio_put(bio);
- }
- }
-
-+ if(err)
-+ SetPageError(page);
-+ else
-+ SetPageUptodate(page);
-+ flush_dcache_page(page);
-+ unlock_page(page);
-+ return err;
-+}
-
-- if(iobuf != dev->rd_buf) {
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-- kfree(iobuf->blocks);
--#endif
-- free_kiovec(1, &iobuf);
-- } else {
-- clear_bit(0, &dev->iobuf_locks);
-+
-+/* write out the current BIO and wait for it to finish */
-+static int blkmtd_write_out(struct bio *bio)
-+{
-+ struct completion event;
-+ int err;
-+
-+ if(!bio->bi_vcnt) {
-+ bio_put(bio);
-+ return 0;
- }
-- DEBUG(2, "read_pages: done, err = %d\n", err);
-+
-+ init_completion(&event);
-+ bio->bi_private = &event;
-+ bio->bi_end_io = bi_write_complete;
-+ submit_bio(WRITE_SYNC, bio);
-+ wait_for_completion(&event);
-+ DEBUG(3, "submit_bio completed, bi_vcnt = %d\n", bio->bi_vcnt);
-+ err = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : -EIO;
-+ bio_put(bio);
- return err;
- }
-
-
- /**
-- * commit_pages - commit pages in the writeout kiobuf to disk
-- * @dev: device to write to
-+ * blkmtd_add_page - add a page to the current BIO
-+ * @bio: bio to add to (NULL to alloc initial bio)
-+ * @blkdev: block device
-+ * @page: page to add
-+ * @pagecnt: pages left to add
- *
-- * If the current dev has pages in the dev->wr_buf kiobuf,
-- * they are written to disk using brw_kiovec()
-+ * Adds a page to the current bio, allocating it if necessary. If it cannot be
-+ * added, the current bio is written out and a new one is allocated. Returns
-+ * the new bio to add or NULL on error
- */
--static int commit_pages(struct blkmtd_dev *dev)
-+static struct bio *blkmtd_add_page(struct bio *bio, struct block_device *blkdev,
-+ struct page *page, int pagecnt)
- {
-- struct kiobuf *iobuf = dev->wr_buf;
-- kdev_t kdev = to_kdev_t(dev->binding->bd_dev);
-- int err = 0;
-
-- iobuf->length = iobuf->nr_pages << PAGE_SHIFT;
-- iobuf->locked = 1;
-- if(iobuf->length) {
-- int i;
-- DEBUG(2, "blkmtd: commit_pages: nrpages = %d\n", iobuf->nr_pages);
-- /* Check all the pages are dirty and lock them */
-- for(i = 0; i < iobuf->nr_pages; i++) {
-- struct page *page = iobuf->maplist[i];
-- BUG_ON(!PageDirty(page));
-- lock_page(page);
-- }
-- err = brw_kiovec(WRITE, 1, &iobuf, kdev, iobuf->blocks, PAGE_SIZE);
-- DEBUG(3, "commit_write: committed %d pages err = %d\n", iobuf->nr_pages, err);
-- while(iobuf->nr_pages) {
-- struct page *page = iobuf->maplist[--iobuf->nr_pages];
-- ClearPageDirty(page);
-- SetPageUptodate(page);
-- unlock_page(page);
-- page_cache_release(page);
-- }
-+ retry:
-+ if(!bio) {
-+ bio = bio_alloc(GFP_KERNEL, pagecnt);
-+ if(!bio)
-+ return NULL;
-+ bio->bi_sector = page->index << (PAGE_SHIFT-9);
-+ bio->bi_bdev = blkdev;
- }
-
-- DEBUG(2, "blkmtd: sync: end, err = %d\n", err);
-- iobuf->offset = 0;
-- iobuf->nr_pages = 0;
-- iobuf->length = 0;
-- return err;
-+ if(bio_add_page(bio, page, PAGE_SIZE, 0) != PAGE_SIZE) {
-+ blkmtd_write_out(bio);
-+ bio = NULL;
-+ goto retry;
-+ }
-+ return bio;
- }
-
-
-@@ -234,30 +230,25 @@
- *
- * Grab pages from the page cache and fill them with the source data.
- * Non page aligned start and end result in a readin of the page and
-- * part of the page being modified. Pages are added to the wr_buf kiobuf
-- * until this becomes full or the next page written to has a lower pagenr
-- * then the current max pagenr in the kiobuf.
-+ * part of the page being modified. Pages are added to the bio and then written
-+ * out.
- */
- static int write_pages(struct blkmtd_dev *dev, const u_char *buf, loff_t to,
-- size_t len, int *retlen)
-+ size_t len, size_t *retlen)
- {
- int pagenr, offset;
- size_t start_len = 0, end_len;
- int pagecnt = 0;
-- struct kiobuf *iobuf = dev->wr_buf;
- int err = 0;
-- struct page *pagelst[2];
-- int pagenrs[2];
-- int readpages = 0;
-- int ignorepage = -1;
-+ struct bio *bio = NULL;
-+ size_t thislen = 0;
-
- pagenr = to >> PAGE_SHIFT;
- offset = to & ~PAGE_MASK;
-
-- DEBUG(2, "blkmtd: write_pages: buf = %p to = %ld len = %d pagenr = %d offset = %d\n",
-+ DEBUG(2, "blkmtd: write_pages: buf = %p to = %ld len = %zd pagenr = %d offset = %d\n",
- buf, (long)to, len, pagenr, offset);
-
-- *retlen = 0;
- /* see if we have to do a partial write at the start */
- if(offset) {
- start_len = ((offset + len) > PAGE_SIZE) ? PAGE_SIZE - offset : len;
-@@ -268,68 +259,48 @@
- end_len = len & ~PAGE_MASK;
- len -= end_len;
-
-- if(start_len) {
-- pagenrs[0] = pagenr;
-- readpages++;
-+ if(start_len)
- pagecnt++;
-- }
-+
- if(len)
- pagecnt += len >> PAGE_SHIFT;
-- if(end_len) {
-- pagenrs[readpages] = pagenr + pagecnt;
-- readpages++;
-- pagecnt++;
-- }
-
-- DEBUG(3, "blkmtd: write: start_len = %d len = %d end_len = %d pagecnt = %d\n",
-- start_len, len, end_len, pagecnt);
-+ if(end_len)
-+ pagecnt++;
-
- down(&dev->wrbuf_mutex);
-
-- if(iobuf->nr_pages && ((pagenr <= iobuf->blocks[iobuf->nr_pages-1])
-- || (iobuf->nr_pages + pagecnt) >= KIO_STATIC_PAGES)) {
--
-- if((pagenr == iobuf->blocks[iobuf->nr_pages-1])
-- && ((iobuf->nr_pages + pagecnt) < KIO_STATIC_PAGES)) {
-- iobuf->nr_pages--;
-- ignorepage = pagenr;
-- } else {
-- DEBUG(3, "blkmtd: doing writeout pagenr = %d max_pagenr = %ld pagecnt = %d idx = %d\n",
-- pagenr, iobuf->blocks[iobuf->nr_pages-1],
-- pagecnt, iobuf->nr_pages);
-- commit_pages(dev);
-- }
-- }
--
-- if(readpages) {
-- err = read_pages(dev, pagenrs, pagelst, readpages);
-- if(err < 0)
-- goto readin_err;
-- }
-+ DEBUG(3, "blkmtd: write: start_len = %zd len = %zd end_len = %zd pagecnt = %d\n",
-+ start_len, len, end_len, pagecnt);
-
- if(start_len) {
- /* do partial start region */
- struct page *page;
-
-- DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %d offset = %d\n",
-+ DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %zd offset = %d\n",
- pagenr, start_len, offset);
-- page = pagelst[0];
-+
- BUG_ON(!buf);
-- if(PageDirty(page) && pagenr != ignorepage) {
-- err("to = %lld start_len = %d len = %d end_len = %d pagenr = %d ignorepage = %d\n",
-- to, start_len, len, end_len, pagenr, ignorepage);
-+ page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev);
-+ lock_page(page);
-+ if(PageDirty(page)) {
-+ err("to = %lld start_len = %zd len = %zd end_len = %zd pagenr = %d\n",
-+ to, start_len, len, end_len, pagenr);
- BUG();
- }
- memcpy(page_address(page)+offset, buf, start_len);
- SetPageDirty(page);
- SetPageUptodate(page);
-- unlock_page(page);
- buf += start_len;
-- *retlen = start_len;
-- err = 0;
-- iobuf->blocks[iobuf->nr_pages] = pagenr++;
-- iobuf->maplist[iobuf->nr_pages] = page;
-- iobuf->nr_pages++;
-+ thislen = start_len;
-+ bio = blkmtd_add_page(bio, dev->blkdev, page, pagecnt);
-+ if(!bio) {
-+ err = -ENOMEM;
-+ err("bio_add_page failed\n");
-+ goto write_err;
-+ }
-+ pagecnt--;
-+ pagenr++;
- }
-
- /* Now do the main loop to a page aligned, n page sized output */
-@@ -342,12 +313,12 @@
-
- /* see if page is in the page cache */
- DEBUG(3, "blkmtd: write: grabbing page %d from page cache\n", pagenr);
-- page = grab_cache_page(dev->binding->bd_inode->i_mapping, pagenr);
-- if(PageDirty(page) && pagenr != ignorepage) {
-+ page = grab_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr);
-+ if(PageDirty(page)) {
- BUG();
- }
- if(!page) {
-- warn("write: cant grab cache page %d", pagenr);
-+ warn("write: cannot grab cache page %d", pagenr);
- err = -ENOMEM;
- goto write_err;
- }
-@@ -357,50 +328,58 @@
- memcpy(page_address(page), buf, PAGE_SIZE);
- buf += PAGE_SIZE;
- }
-- iobuf->blocks[iobuf->nr_pages] = pagenr++;
-- iobuf->maplist[iobuf->nr_pages] = page;
-- iobuf->nr_pages++;
-+ bio = blkmtd_add_page(bio, dev->blkdev, page, pagecnt);
-+ if(!bio) {
-+ err = -ENOMEM;
-+ err("bio_add_page failed\n");
-+ goto write_err;
-+ }
-+ pagenr++;
-+ pagecnt--;
- SetPageDirty(page);
- SetPageUptodate(page);
-- unlock_page(page);
- pagesc--;
-- *retlen += PAGE_SIZE;
-+ thislen += PAGE_SIZE;
- }
- }
-
- if(end_len) {
- /* do the third region */
- struct page *page;
-- DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %d\n",
-+ DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %zd\n",
- pagenr, end_len);
-- page = pagelst[readpages-1];
- BUG_ON(!buf);
-- if(PageDirty(page) && pagenr != ignorepage) {
-- err("to = %lld start_len = %d len = %d end_len = %d pagenr = %d ignorepage = %d\n",
-- to, start_len, len, end_len, pagenr, ignorepage);
-+ page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev);
-+ lock_page(page);
-+ if(PageDirty(page)) {
-+ err("to = %lld start_len = %zd len = %zd end_len = %zd pagenr = %d\n",
-+ to, start_len, len, end_len, pagenr);
- BUG();
- }
- memcpy(page_address(page), buf, end_len);
- SetPageDirty(page);
- SetPageUptodate(page);
-- unlock_page(page);
- DEBUG(3, "blkmtd: write: writing out partial end\n");
-- *retlen += end_len;
-- err = 0;
-- iobuf->blocks[iobuf->nr_pages] = pagenr;
-- iobuf->maplist[iobuf->nr_pages] = page;
-- iobuf->nr_pages++;
-+ thislen += end_len;
-+ bio = blkmtd_add_page(bio, dev->blkdev, page, pagecnt);
-+ if(!bio) {
-+ err = -ENOMEM;
-+ err("bio_add_page failed\n");
-+ goto write_err;
- }
--
-- DEBUG(2, "blkmtd: write: end, retlen = %d, err = %d\n", *retlen, err);
--
-- if(sync) {
--write_err:
-- commit_pages(dev);
-+ pagenr++;
- }
-
--readin_err:
-+ DEBUG(3, "blkmtd: write: got %d vectors to write\n", bio->bi_vcnt);
-+ write_err:
-+ if(bio)
-+ blkmtd_write_out(bio);
-+
-+ DEBUG(2, "blkmtd: write: end, retlen = %zd, err = %d\n", *retlen, err);
- up(&dev->wrbuf_mutex);
-+
-+ if(retlen)
-+ *retlen = thislen;
- return err;
- }
-
-@@ -414,23 +393,15 @@
- size_t from;
- u_long len;
- int err = -EIO;
-- int retlen;
--
-- /* check readonly */
-- if(!dev->wr_buf) {
-- err("error: mtd%d trying to erase readonly device %s",
-- mtd->index, mtd->name);
-- instr->state = MTD_ERASE_FAILED;
-- goto erase_callback;
-- }
-+ size_t retlen;
-
- instr->state = MTD_ERASING;
- from = instr->addr;
- len = instr->len;
-
- /* check erase region has valid start and length */
-- DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%x len = 0x%lx\n",
-- bdevname(dev->binding->bd_dev), from, len);
-+ DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%zx len = 0x%lx\n",
-+ mtd->name+9, from, len);
- while(numregions) {
- DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n",
- einfo->offset, einfo->erasesize, einfo->numblocks);
-@@ -446,29 +417,25 @@
-
- if(!numregions) {
- /* Not a valid erase block */
-- err("erase: invalid erase request 0x%lX @ 0x%08X", len, from);
-+ err("erase: invalid erase request 0x%lX @ 0x%08zX", len, from);
- instr->state = MTD_ERASE_FAILED;
- err = -EIO;
- }
-
- if(instr->state != MTD_ERASE_FAILED) {
- /* do the erase */
-- DEBUG(3, "Doing erase from = %d len = %ld\n", from, len);
-+ DEBUG(3, "Doing erase from = %zd len = %ld\n", from, len);
- err = write_pages(dev, NULL, from, len, &retlen);
-- if(err < 0) {
-+ if(err || retlen != len) {
- err("erase failed err = %d", err);
- instr->state = MTD_ERASE_FAILED;
- } else {
- instr->state = MTD_ERASE_DONE;
-- err = 0;
- }
- }
-
- DEBUG(3, "blkmtd: erase: checking callback\n");
-- erase_callback:
-- if (instr->callback) {
-- (*(instr->callback))(instr);
-- }
-+ mtd_erase_callback(instr);
- DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err);
- return err;
- }
-@@ -482,14 +449,15 @@
- int err = 0;
- int offset;
- int pagenr, pages;
-- struct page **pagelst;
-- int *pagenrs;
-- int i;
-+ size_t thislen = 0;
-
-- *retlen = 0;
-+ DEBUG(2, "blkmtd: read: dev = `%s' from = %lld len = %zd buf = %p\n",
-+ mtd->name+9, from, len, buf);
-
-- DEBUG(2, "blkmtd: read: dev = `%s' from = %ld len = %d buf = %p\n",
-- bdevname(dev->binding->bd_dev), (long int)from, len, buf);
-+ if(from > mtd->size)
-+ return -EINVAL;
-+ if(from + len > mtd->size)
-+ len = mtd->size - from;
-
- pagenr = from >> PAGE_SHIFT;
- offset = from - (pagenr << PAGE_SHIFT);
-@@ -498,48 +466,35 @@
- DEBUG(3, "blkmtd: read: pagenr = %d offset = %d, pages = %d\n",
- pagenr, offset, pages);
-
-- pagelst = kmalloc(sizeof(struct page *) * pages, GFP_KERNEL);
-- if(!pagelst)
-- return -ENOMEM;
-- pagenrs = kmalloc(sizeof(int) * pages, GFP_KERNEL);
-- if(!pagenrs) {
-- kfree(pagelst);
-- return -ENOMEM;
-- }
-- for(i = 0; i < pages; i++)
-- pagenrs[i] = pagenr+i;
--
-- err = read_pages(dev, pagenrs, pagelst, pages);
-- if(err)
-- goto readerr;
--
-- pagenr = 0;
- while(pages) {
- struct page *page;
- int cpylen;
-
- DEBUG(3, "blkmtd: read: looking for page: %d\n", pagenr);
-- page = pagelst[pagenr];
-+ page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev);
-+ if(IS_ERR(page)) {
-+ err = -EIO;
-+ goto readerr;
-+ }
-
- cpylen = (PAGE_SIZE > len) ? len : PAGE_SIZE;
- if(offset+cpylen > PAGE_SIZE)
- cpylen = PAGE_SIZE-offset;
-
-- memcpy(buf + *retlen, page_address(page) + offset, cpylen);
-+ memcpy(buf + thislen, page_address(page) + offset, cpylen);
- offset = 0;
- len -= cpylen;
-- *retlen += cpylen;
-+ thislen += cpylen;
- pagenr++;
- pages--;
-- unlock_page(page);
- if(!PageDirty(page))
- page_cache_release(page);
- }
-
- readerr:
-- kfree(pagelst);
-- kfree(pagenrs);
-- DEBUG(2, "blkmtd: end read: retlen = %d, err = %d\n", *retlen, err);
-+ if(retlen)
-+ *retlen = thislen;
-+ DEBUG(2, "blkmtd: end read: retlen = %zd, err = %d\n", thislen, err);
- return err;
- }
-
-@@ -551,32 +506,22 @@
- struct blkmtd_dev *dev = mtd->priv;
- int err;
-
-- *retlen = 0;
- if(!len)
- return 0;
-
-- DEBUG(2, "blkmtd: write: dev = `%s' to = %ld len = %d buf = %p\n",
-- bdevname(dev->binding->bd_dev), (long int)to, len, buf);
--
-- /* handle readonly and out of range numbers */
--
-- if(!dev->wr_buf) {
-- err("error: trying to write to a readonly device %s", mtd->name);
-- return -EROFS;
-- }
-+ DEBUG(2, "blkmtd: write: dev = `%s' to = %lld len = %zd buf = %p\n",
-+ mtd->name+9, to, len, buf);
-
- if(to >= mtd->size) {
- return -ENOSPC;
- }
-
- if(to + len > mtd->size) {
-- len = (mtd->size - to);
-+ len = mtd->size - to;
- }
-
- err = write_pages(dev, buf, to, len, retlen);
-- if(err < 0)
-- *retlen = 0;
-- else
-+ if(err > 0)
- err = 0;
- DEBUG(2, "blkmtd: write: end, err = %d\n", err);
- return err;
-@@ -586,124 +531,22 @@
- /* sync the device - wait until the write queue is empty */
- static void blkmtd_sync(struct mtd_info *mtd)
- {
-- struct blkmtd_dev *dev = mtd->priv;
-- struct kiobuf *iobuf = dev->wr_buf;
--
-- DEBUG(2, "blkmtd: sync: called\n");
-- if(iobuf == NULL)
-- return;
--
-- DEBUG(3, "blkmtd: kiovec: length = %d nr_pages = %d\n",
-- iobuf->length, iobuf->nr_pages);
-- down(&dev->wrbuf_mutex);
-- if(iobuf->nr_pages)
-- commit_pages(dev);
-- up(&dev->wrbuf_mutex);
--}
--
--
--#ifdef BLKMTD_PROC_DEBUG
--/* procfs stuff */
--static int blkmtd_proc_read(char *page, char **start, off_t off,
-- int count, int *eof, void *data)
--{
-- int len;
-- struct list_head *temp1, *temp2;
--
-- MOD_INC_USE_COUNT;
--
-- /* Count the size of the page lists */
--
-- len = sprintf(page, "dev\twr_idx\tmax_idx\tnrpages\tclean\tdirty\tlocked\tlru\n");
-- list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
-- struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
-- list);
-- struct list_head *temp;
-- struct page *pagei;
--
-- int clean = 0, dirty = 0, locked = 0, lru = 0;
-- /* Count the size of the page lists */
-- list_for_each(temp, &dev->binding->bd_inode->i_mapping->clean_pages) {
-- pagei = list_entry(temp, struct page, list);
-- clean++;
-- if(PageLocked(pagei))
-- locked++;
-- if(PageDirty(pagei))
-- dirty++;
-- if(PageLRU(pagei))
-- lru++;
-- }
-- list_for_each(temp, &dev->binding->bd_inode->i_mapping->dirty_pages) {
-- pagei = list_entry(temp, struct page, list);
-- if(PageLocked(pagei))
-- locked++;
-- if(PageDirty(pagei))
-- dirty++;
-- if(PageLRU(pagei))
-- lru++;
-- }
-- list_for_each(temp, &dev->binding->bd_inode->i_mapping->locked_pages) {
-- pagei = list_entry(temp, struct page, list);
-- if(PageLocked(pagei))
-- locked++;
-- if(PageDirty(pagei))
-- dirty++;
-- if(PageLRU(pagei))
-- lru++;
-- }
--
-- len += sprintf(page+len, "mtd%d:\t%ld\t%d\t%ld\t%d\t%d\t%d\t%d\n",
-- dev->mtd_info.index,
-- (dev->wr_buf && dev->wr_buf->nr_pages) ?
-- dev->wr_buf->blocks[dev->wr_buf->nr_pages-1] : 0,
-- (dev->wr_buf) ? dev->wr_buf->nr_pages : 0,
-- dev->binding->bd_inode->i_mapping->nrpages,
-- clean, dirty, locked, lru);
-- }
--
-- if(len <= count)
-- *eof = 1;
--
-- MOD_DEC_USE_COUNT;
-- return len;
-+ /* Currently all writes are synchronous */
- }
--#endif
-
-
- static void free_device(struct blkmtd_dev *dev)
- {
- DEBUG(2, "blkmtd: free_device() dev = %p\n", dev);
- if(dev) {
-- del_mtd_device(&dev->mtd_info);
-- info("mtd%d: [%s] removed", dev->mtd_info.index,
-- dev->mtd_info.name + strlen("blkmtd: "));
- if(dev->mtd_info.eraseregions)
- kfree(dev->mtd_info.eraseregions);
- if(dev->mtd_info.name)
- kfree(dev->mtd_info.name);
-
-- if(dev->rd_buf) {
-- dev->rd_buf->locked = 0;
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-- if(dev->rd_buf->blocks)
-- kfree(dev->rd_buf->blocks);
--#endif
-- free_kiovec(1, &dev->rd_buf);
-- }
-- if(dev->wr_buf) {
-- dev->wr_buf->locked = 0;
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-- if(dev->wr_buf->blocks)
-- kfree(dev->rw_buf->blocks);
--#endif
-- free_kiovec(1, &dev->wr_buf);
-- }
--
-- if(dev->binding) {
-- kdev_t kdev = to_kdev_t(dev->binding->bd_dev);
-- invalidate_inode_pages(dev->binding->bd_inode);
-- set_blocksize(kdev, 1 << 10);
-- blkdev_put(dev->binding, BDEV_RAW);
-+ if(dev->blkdev) {
-+ invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping);
-+ close_bdev_excl(dev->blkdev);
- }
- kfree(dev);
- }
-@@ -720,7 +563,7 @@
- {
- struct mtd_erase_region_info *info = NULL;
-
-- DEBUG(2, "calc_erase_regions, es = %d size = %d regions = %d\n",
-+ DEBUG(2, "calc_erase_regions, es = %zd size = %zd regions = %d\n",
- erase_size, total_size, *regions);
- /* Make any user specified erasesize be a power of 2
- and at least PAGE_SIZE */
-@@ -768,119 +611,62 @@
- break;
- }
- } while(!(*regions));
-- DEBUG(2, "calc_erase_regions done, es = %d size = %d regions = %d\n",
-+ DEBUG(2, "calc_erase_regions done, es = %zd size = %zd regions = %d\n",
- erase_size, total_size, *regions);
- return info;
- }
-
-
--extern kdev_t name_to_kdev_t(char *line) __init;
--
-+extern dev_t __init name_to_dev_t(const char *line);
-
- static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size)
- {
-- int maj, min;
-- kdev_t kdev;
-+ struct block_device *bdev;
- int mode;
- struct blkmtd_dev *dev;
-
--#ifdef MODULE
-- struct file *file = NULL;
-- struct inode *inode;
--#endif
--
- if(!devname)
- return NULL;
-
- /* Get a handle on the device */
-- mode = (readonly) ? O_RDONLY : O_RDWR;
-
--#ifdef MODULE
-
-- file = filp_open(devname, mode, 0);
-- if(IS_ERR(file)) {
-- err("error: cant open device %s", devname);
-- DEBUG(2, "blkmtd: filp_open returned %ld\n", PTR_ERR(file));
-- return NULL;
-- }
--
-- /* determine is this is a block device and
-- * if so get its major and minor numbers
-- */
-- inode = file->f_dentry->d_inode;
-- if(!S_ISBLK(inode->i_mode)) {
-- err("%s not a block device", devname);
-- filp_close(file, NULL);
-- return NULL;
-- }
-- kdev = inode->i_rdev;
-- filp_close(file, NULL);
-+#ifdef MODULE
-+ mode = (readonly) ? O_RDONLY : O_RDWR;
-+ bdev = open_bdev_excl(devname, mode, NULL);
- #else
-- kdev = name_to_kdev_t(devname);
--#endif /* MODULE */
--
-- if(!kdev) {
-- err("bad block device: `%s'", devname);
-+ mode = (readonly) ? FMODE_READ : FMODE_WRITE;
-+ bdev = open_by_devnum(name_to_dev_t(devname), mode);
-+#endif
-+ if(IS_ERR(bdev)) {
-+ err("error: cannot open device %s", devname);
-+ DEBUG(2, "blkmtd: opening bdev returned %ld\n", PTR_ERR(bdev));
- return NULL;
- }
-
-- maj = MAJOR(kdev);
-- min = MINOR(kdev);
- DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n",
-- maj, min);
-+ MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
-
-- if(maj == MTD_BLOCK_MAJOR) {
-+ if(MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
- err("attempting to use an MTD device as a block device");
-+ blkdev_put(bdev);
- return NULL;
- }
-
-- DEBUG(1, "blkmtd: devname = %s\n", bdevname(kdev));
--
- dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL);
-- if(dev == NULL)
-+ if(dev == NULL) {
-+ blkdev_put(bdev);
- return NULL;
--
-- memset(dev, 0, sizeof(struct blkmtd_dev));
-- if(alloc_kiovec(1, &dev->rd_buf)) {
-- err("cant allocate read iobuf");
-- goto devinit_err;
- }
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-- dev->rd_buf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);
-- if(dev->rd_buf->blocks == NULL) {
-- crit("cant allocate rd_buf blocks");
-- goto devinit_err;
-- }
--#endif
-
-+ memset(dev, 0, sizeof(struct blkmtd_dev));
-+ dev->blkdev = bdev;
-+ atomic_set(&(dev->blkdev->bd_inode->i_mapping->truncate_count), 0);
- if(!readonly) {
-- if(alloc_kiovec(1, &dev->wr_buf)) {
-- err("cant allocate kiobuf - readonly enabled");
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-- } else {
-- dev->wr_buf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);
-- if(dev->wr_buf->blocks == NULL) {
-- crit("cant allocate wr_buf blocks - readonly enabled");
-- free_kiovec(1, &iobuf);
-- }
--#endif
-- }
-- if(dev->wr_buf)
- init_MUTEX(&dev->wrbuf_mutex);
- }
-
-- /* get the block device */
-- dev->binding = bdget(kdev_t_to_nr(MKDEV(maj, min)));
-- if(blkdev_get(dev->binding, mode, 0, BDEV_RAW))
-- goto devinit_err;
--
-- if(set_blocksize(kdev, PAGE_SIZE)) {
-- err("cant set block size to PAGE_SIZE on %s", bdevname(kdev));
-- goto devinit_err;
-- }
--
-- dev->mtd_info.size = dev->binding->bd_inode->i_size & PAGE_MASK;
-+ dev->mtd_info.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
-
- /* Setup the MTD structure */
- /* make the name contain the block device in */
-@@ -904,27 +690,26 @@
- } else {
- dev->mtd_info.type = MTD_RAM;
- dev->mtd_info.flags = MTD_CAP_RAM;
-- }
- dev->mtd_info.erase = blkmtd_erase;
-- dev->mtd_info.read = blkmtd_read;
- dev->mtd_info.write = blkmtd_write;
-+ dev->mtd_info.writev = default_mtd_writev;
- dev->mtd_info.sync = blkmtd_sync;
-- dev->mtd_info.point = 0;
-- dev->mtd_info.unpoint = 0;
-+ }
-+ dev->mtd_info.read = blkmtd_read;
-+ dev->mtd_info.readv = default_mtd_readv;
- dev->mtd_info.priv = dev;
-- dev->mtd_info.module = THIS_MODULE;
-+ dev->mtd_info.owner = THIS_MODULE;
-
- list_add(&dev->list, &blkmtd_device_list);
- if (add_mtd_device(&dev->mtd_info)) {
- /* Device didnt get added, so free the entry */
- list_del(&dev->list);
-- free_device(dev);
-- return NULL;
-+ goto devinit_err;
- } else {
- info("mtd%d: [%s] erase_size = %dKiB %s",
- dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "),
- dev->mtd_info.erasesize >> 10,
-- (dev->wr_buf) ? "" : "(read-only)");
-+ readonly ? "(read-only)" : "");
- }
-
- return dev;
-@@ -939,17 +724,16 @@
- static void __devexit cleanup_blkmtd(void)
- {
- struct list_head *temp1, *temp2;
--#ifdef BLKMTD_PROC_DEBUG
-- if(blkmtd_proc) {
-- remove_proc_entry("blkmtd_debug", NULL);
-- }
--#endif
-
- /* Remove the MTD devices */
- list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
- struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
- list);
- blkmtd_sync(&dev->mtd_info);
-+ del_mtd_device(&dev->mtd_info);
-+ info("mtd%d: [%s] removed", dev->mtd_info.index,
-+ dev->mtd_info.name + strlen("blkmtd: "));
-+ list_del(&dev->list);
- free_device(dev);
- }
- }
-@@ -1020,6 +804,7 @@
- {
- int i;
-
-+ info("version " VERSION);
- /* Check args - device[0] is the bare minimum*/
- if(!device[0]) {
- err("error: missing `device' name\n");
-@@ -1030,28 +815,9 @@
- add_device(device[i], ro[i], erasesz[i] << 10);
-
- if(list_empty(&blkmtd_device_list))
-- goto init_err;
--
-- info("version " VERSION);
--
--#ifdef BLKMTD_PROC_DEBUG
-- /* create proc entry */
-- DEBUG(2, "Creating /proc/blkmtd_debug\n");
-- blkmtd_proc = create_proc_read_entry("blkmtd_debug", 0444,
-- NULL, blkmtd_proc_read, NULL);
-- if(blkmtd_proc == NULL) {
-- err("Cant create /proc/blkmtd_debug");
-- } else {
-- blkmtd_proc->owner = THIS_MODULE;
-- }
--#endif
-+ return -EINVAL;
-
-- if(!list_empty(&blkmtd_device_list))
-- /* Everything is ok if we got here */
- return 0;
--
-- init_err:
-- return -EINVAL;
- }
-
- module_init(init_blkmtd);
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/devices/block2mtd.c
-@@ -0,0 +1,494 @@
-+/*
-+ * $Id: block2mtd.c,v 1.25 2005/03/07 20:29:05 joern Exp $
-+ *
-+ * block2mtd.c - create an mtd from a block device
-+ *
-+ * Copyright (C) 2001,2002 Simon Evans <spse@secret.org.uk>
-+ * Copyright (C) 2004,2005 Jörn Engel <joern@wh.fh-wedel.de>
-+ *
-+ * Licence: GPL
-+ */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/fs.h>
-+#include <linux/blkdev.h>
-+#include <linux/bio.h>
-+#include <linux/pagemap.h>
-+#include <linux/list.h>
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/buffer_head.h>
-+
-+#define VERSION "$Revision: 1.25 $"
-+
-+
-+#define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args)
-+#define INFO(fmt, args...) printk(KERN_INFO "block2mtd: " fmt "\n" , ## args)
-+
-+
-+/* Info for the block device */
-+struct block2mtd_dev {
-+ struct list_head list;
-+ struct block_device *blkdev;
-+ struct mtd_info mtd;
-+ struct semaphore write_mutex;
-+};
-+
-+
-+/* Static info about the MTD, used in cleanup_module */
-+static LIST_HEAD(blkmtd_device_list);
-+
-+
-+#define PAGE_READAHEAD 64
-+void cache_readahead(struct address_space *mapping, int index)
-+{
-+ filler_t *filler = (filler_t*)mapping->a_ops->readpage;
-+ int i, pagei;
-+ unsigned ret = 0;
-+ unsigned long end_index;
-+ struct page *page;
-+ LIST_HEAD(page_pool);
-+ struct inode *inode = mapping->host;
-+ loff_t isize = i_size_read(inode);
-+
-+ if (!isize) {
-+ printk(KERN_INFO "iSize=0 in cache_readahead\n");
-+ return;
-+ }
-+
-+ end_index = ((isize - 1) >> PAGE_CACHE_SHIFT);
-+
-+ spin_lock_irq(&mapping->tree_lock);
-+ for (i = 0; i < PAGE_READAHEAD; i++) {
-+ pagei = index + i;
-+ if (pagei > end_index) {
-+ printk(KERN_INFO "Overrun end of disk in cache readahead\n");
-+ break;
-+ }
-+ page = radix_tree_lookup(&mapping->page_tree, pagei);
-+ if (page && (!i))
-+ break;
-+ if (page)
-+ continue;
-+ spin_unlock_irq(&mapping->tree_lock);
-+ page = page_cache_alloc_cold(mapping);
-+ spin_lock_irq(&mapping->tree_lock);
-+ if (!page)
-+ break;
-+ page->index = pagei;
-+ list_add(&page->lru, &page_pool);
-+ ret++;
-+ }
-+ spin_unlock_irq(&mapping->tree_lock);
-+ if (ret)
-+ read_cache_pages(mapping, &page_pool, filler, NULL);
-+}
-+
-+
-+static struct page* page_readahead(struct address_space *mapping, int index)
-+{
-+ filler_t *filler = (filler_t*)mapping->a_ops->readpage;
-+ cache_readahead(mapping, index);
-+ return read_cache_page(mapping, index, filler, NULL);
-+}
-+
-+
-+/* erase a specified part of the device */
-+static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
-+{
-+ struct address_space *mapping = dev->blkdev->bd_inode->i_mapping;
-+ struct page *page;
-+ int index = to >> PAGE_SHIFT; // page index
-+ int pages = len >> PAGE_SHIFT;
-+ u_long *p;
-+ u_long *max;
-+
-+ while (pages) {
-+ page = page_readahead(mapping, index);
-+ if (!page)
-+ return -ENOMEM;
-+ if (IS_ERR(page))
-+ return PTR_ERR(page);
-+
-+ max = (u_long*)page_address(page) + PAGE_SIZE;
-+ for (p=(u_long*)page_address(page); p<max; p++)
-+ if (*p != -1UL) {
-+ lock_page(page);
-+ memset(page_address(page), 0xff, PAGE_SIZE);
-+ set_page_dirty(page);
-+ unlock_page(page);
-+ break;
-+ }
-+
-+ page_cache_release(page);
-+ pages--;
-+ index++;
-+ }
-+ return 0;
-+}
-+static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
-+{
-+ struct block2mtd_dev *dev = mtd->priv;
-+ size_t from = instr->addr;
-+ size_t len = instr->len;
-+ int err;
-+
-+ instr->state = MTD_ERASING;
-+ down(&dev->write_mutex);
-+ err = _block2mtd_erase(dev, from, len);
-+ up(&dev->write_mutex);
-+ if (err) {
-+ ERROR("erase failed err = %d", err);
-+ instr->state = MTD_ERASE_FAILED;
-+ } else
-+ instr->state = MTD_ERASE_DONE;
-+
-+ instr->state = MTD_ERASE_DONE;
-+ mtd_erase_callback(instr);
-+ return err;
-+}
-+
-+
-+static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t *retlen, u_char *buf)
-+{
-+ struct block2mtd_dev *dev = mtd->priv;
-+ struct page *page;
-+ int index = from >> PAGE_SHIFT;
-+ int offset = from & (PAGE_SIZE-1);
-+ int cpylen;
-+
-+ if (from > mtd->size)
-+ return -EINVAL;
-+ if (from + len > mtd->size)
-+ len = mtd->size - from;
-+
-+ if (retlen)
-+ *retlen = 0;
-+
-+ while (len) {
-+ if ((offset + len) > PAGE_SIZE)
-+ cpylen = PAGE_SIZE - offset; // multiple pages
-+ else
-+ cpylen = len; // this page
-+ len = len - cpylen;
-+
-+ // Get page
-+ page = page_readahead(dev->blkdev->bd_inode->i_mapping, index);
-+ if (!page)
-+ return -ENOMEM;
-+ if (IS_ERR(page))
-+ return PTR_ERR(page);
-+
-+ memcpy(buf, page_address(page) + offset, cpylen);
-+ page_cache_release(page);
-+
-+ if (retlen)
-+ *retlen += cpylen;
-+ buf += cpylen;
-+ offset = 0;
-+ index++;
-+ }
-+ return 0;
-+}
-+
-+
-+/* write data to the underlying device */
-+static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
-+ loff_t to, size_t len, size_t *retlen)
-+{
-+ struct page *page;
-+ struct address_space *mapping = dev->blkdev->bd_inode->i_mapping;
-+ int index = to >> PAGE_SHIFT; // page index
-+ int offset = to & ~PAGE_MASK; // page offset
-+ int cpylen;
-+
-+ if (retlen)
-+ *retlen = 0;
-+ while (len) {
-+ if ((offset+len) > PAGE_SIZE)
-+ cpylen = PAGE_SIZE - offset; // multiple pages
-+ else
-+ cpylen = len; // this page
-+ len = len - cpylen;
-+
-+ // Get page
-+ page = page_readahead(mapping, index);
-+ if (!page)
-+ return -ENOMEM;
-+ if (IS_ERR(page))
-+ return PTR_ERR(page);
-+
-+ if (memcmp(page_address(page)+offset, buf, cpylen)) {
-+ lock_page(page);
-+ memcpy(page_address(page) + offset, buf, cpylen);
-+ set_page_dirty(page);
-+ unlock_page(page);
-+ }
-+ page_cache_release(page);
-+
-+ if (retlen)
-+ *retlen += cpylen;
-+
-+ buf += cpylen;
-+ offset = 0;
-+ index++;
-+ }
-+ return 0;
-+}
-+static int block2mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t *retlen, const u_char *buf)
-+{
-+ struct block2mtd_dev *dev = mtd->priv;
-+ int err;
-+
-+ if (!len)
-+ return 0;
-+ if (to >= mtd->size)
-+ return -ENOSPC;
-+ if (to + len > mtd->size)
-+ len = mtd->size - to;
-+
-+ down(&dev->write_mutex);
-+ err = _block2mtd_write(dev, buf, to, len, retlen);
-+ up(&dev->write_mutex);
-+ if (err > 0)
-+ err = 0;
-+ return err;
-+}
-+
-+
-+/* sync the device - wait until the write queue is empty */
-+static void block2mtd_sync(struct mtd_info *mtd)
-+{
-+ struct block2mtd_dev *dev = mtd->priv;
-+ sync_blockdev(dev->blkdev);
-+ return;
-+}
-+
-+
-+static void block2mtd_free_device(struct block2mtd_dev *dev)
-+{
-+ if (!dev)
-+ return;
-+
-+ kfree(dev->mtd.name);
-+
-+ if (dev->blkdev) {
-+ invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping);
-+ close_bdev_excl(dev->blkdev);
-+ }
-+
-+ kfree(dev);
-+}
-+
-+
-+/* FIXME: ensure that mtd->size % erase_size == 0 */
-+static struct block2mtd_dev *add_device(char *devname, int erase_size)
-+{
-+ struct block_device *bdev;
-+ struct block2mtd_dev *dev;
-+
-+ if (!devname)
-+ return NULL;
-+
-+ dev = kmalloc(sizeof(struct block2mtd_dev), GFP_KERNEL);
-+ if (!dev)
-+ return NULL;
-+ memset(dev, 0, sizeof(*dev));
-+
-+ /* Get a handle on the device */
-+ bdev = open_bdev_excl(devname, O_RDWR, NULL);
-+ if (IS_ERR(bdev)) {
-+ ERROR("error: cannot open device %s", devname);
-+ goto devinit_err;
-+ }
-+ dev->blkdev = bdev;
-+
-+ if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
-+ ERROR("attempting to use an MTD device as a block device");
-+ goto devinit_err;
-+ }
-+
-+ atomic_set(&bdev->bd_inode->i_mapping->truncate_count, 0);
-+ init_MUTEX(&dev->write_mutex);
-+
-+ /* Setup the MTD structure */
-+ /* make the name contain the block device in */
-+ dev->mtd.name = kmalloc(sizeof("block2mtd: ") + strlen(devname),
-+ GFP_KERNEL);
-+ if (!dev->mtd.name)
-+ goto devinit_err;
-+
-+ sprintf(dev->mtd.name, "block2mtd: %s", devname);
-+
-+ dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
-+ dev->mtd.erasesize = erase_size;
-+ dev->mtd.type = MTD_RAM;
-+ dev->mtd.flags = MTD_CAP_RAM;
-+ dev->mtd.erase = block2mtd_erase;
-+ dev->mtd.write = block2mtd_write;
-+ dev->mtd.writev = default_mtd_writev;
-+ dev->mtd.sync = block2mtd_sync;
-+ dev->mtd.read = block2mtd_read;
-+ dev->mtd.readv = default_mtd_readv;
-+ dev->mtd.priv = dev;
-+ dev->mtd.owner = THIS_MODULE;
-+
-+ if (add_mtd_device(&dev->mtd)) {
-+ /* Device didnt get added, so free the entry */
-+ goto devinit_err;
-+ }
-+ list_add(&dev->list, &blkmtd_device_list);
-+ INFO("mtd%d: [%s] erase_size = %dKiB [%d]", dev->mtd.index,
-+ dev->mtd.name + strlen("blkmtd: "),
-+ dev->mtd.erasesize >> 10, dev->mtd.erasesize);
-+ return dev;
-+
-+devinit_err:
-+ block2mtd_free_device(dev);
-+ return NULL;
-+}
-+
-+
-+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;
-+ /* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */
-+ if ((*endp)[1] == 'i')
-+ (*endp) += 2;
-+ }
-+ return result;
-+}
-+
-+
-+static int parse_num32(u32 *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 limit)
-+{
-+ size_t len;
-+ char *name;
-+
-+ len = strlen(token) + 1;
-+ if (len > limit)
-+ return -ENOSPC;
-+
-+ name = kmalloc(len, GFP_KERNEL);
-+ if (!name)
-+ return -ENOMEM;
-+
-+ strcpy(name, token);
-+
-+ *pname = name;
-+ return 0;
-+}
-+
-+
-+static inline void kill_final_newline(char *str)
-+{
-+ char *newline = strrchr(str, '\n');
-+ if (newline && !newline[1])
-+ *newline = 0;
-+}
-+
-+
-+#define parse_err(fmt, args...) do { \
-+ ERROR("block2mtd: " fmt "\n", ## args); \
-+ return 0; \
-+} while (0)
-+
-+static int block2mtd_setup(const char *val, struct kernel_param *kp)
-+{
-+ char buf[80+12], *str=buf; /* 80 for device, 12 for erase size */
-+ char *token[2];
-+ char *name;
-+ size_t erase_size = PAGE_SIZE;
-+ int i, ret;
-+
-+ if (strnlen(val, sizeof(buf)) >= sizeof(buf))
-+ parse_err("parameter too long");
-+
-+ strcpy(str, val);
-+ kill_final_newline(str);
-+
-+ for (i=0; i<2; i++)
-+ token[i] = strsep(&str, ",");
-+
-+ if (str)
-+ parse_err("too many arguments");
-+
-+ if (!token[0])
-+ parse_err("no argument");
-+
-+ ret = parse_name(&name, token[0], 80);
-+ if (ret == -ENOMEM)
-+ parse_err("out of memory");
-+ if (ret == -ENOSPC)
-+ parse_err("name too long");
-+ if (ret)
-+ return 0;
-+
-+ if (token[1]) {
-+ ret = parse_num32(&erase_size, token[1]);
-+ if (ret)
-+ parse_err("illegal erase size");
-+ }
-+
-+ add_device(name, erase_size);
-+
-+ return 0;
-+}
-+
-+
-+module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200);
-+MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>]\"");
-+
-+static int __init block2mtd_init(void)
-+{
-+ INFO("version " VERSION);
-+ return 0;
-+}
-+
-+
-+static void __devexit block2mtd_exit(void)
-+{
-+ struct list_head *pos, *next;
-+
-+ /* Remove the MTD devices */
-+ list_for_each_safe(pos, next, &blkmtd_device_list) {
-+ struct block2mtd_dev *dev = list_entry(pos, typeof(*dev), list);
-+ block2mtd_sync(&dev->mtd);
-+ del_mtd_device(&dev->mtd);
-+ INFO("mtd%d: [%s] removed", dev->mtd.index,
-+ dev->mtd.name + strlen("blkmtd: "));
-+ list_del(&dev->list);
-+ block2mtd_free_device(dev);
-+ }
-+}
-+
-+
-+module_init(block2mtd_init);
-+module_exit(block2mtd_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk> and others");
-+MODULE_DESCRIPTION("Emulate an MTD using a block device");
---- linux-2.4.21/drivers/mtd/devices/doc2000.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/devices/doc2000.c
-@@ -4,7 +4,7 @@
- * (c) 1999 Machine Vision Holdings, Inc.
- * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
- *
-- * $Id: doc2000.c,v 1.50 2002/12/10 15:05:42 gleixner Exp $
-+ * $Id: doc2000.c,v 1.66 2005/01/05 18:05:12 dwmw2 Exp $
- */
-
- #include <linux/kernel.h>
-@@ -19,12 +19,14 @@
- #include <linux/sched.h>
- #include <linux/init.h>
- #include <linux/types.h>
-+#include <linux/bitops.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
- #include <linux/mtd/doc2000.h>
-
- #define DOC_SUPPORT_2000
-+#define DOC_SUPPORT_2000TSOP
- #define DOC_SUPPORT_MILLENNIUM
-
- #ifdef DOC_SUPPORT_2000
-@@ -33,7 +35,7 @@
- #define DoC_is_2000(doc) (0)
- #endif
-
--#ifdef DOC_SUPPORT_MILLENNIUM
-+#if defined(DOC_SUPPORT_2000TSOP) || defined(DOC_SUPPORT_MILLENNIUM)
- #define DoC_is_Millennium(doc) (doc->ChipID == DOC_ChipID_DocMil)
- #else
- #define DoC_is_Millennium(doc) (0)
-@@ -53,9 +55,12 @@
- static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf);
- static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-- size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel);
-+ size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
- static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-- size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
-+ size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
-+static int doc_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 doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
- size_t *retlen, u_char *buf);
- static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
-@@ -84,7 +89,7 @@
- /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
- static int _DoC_WaitReady(struct DiskOnChip *doc)
- {
-- unsigned long docptr = doc->virtadr;
-+ void __iomem *docptr = doc->virtadr;
- unsigned long timeo = jiffies + (HZ * 10);
-
- DEBUG(MTD_DEBUG_LEVEL3,
-@@ -92,6 +97,10 @@
-
- /* Out-of-line routine to wait for chip response */
- while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
-+ /* issue 2 read from NOP register after reading from CDSNControl register
-+ see Software Requirement 11.4 item 2. */
-+ DoC_Delay(doc, 2);
-+
- if (time_after(jiffies, timeo)) {
- DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
- return -EIO;
-@@ -105,7 +114,8 @@
-
- static inline int DoC_WaitReady(struct DiskOnChip *doc)
- {
-- unsigned long docptr = doc->virtadr;
-+ void __iomem *docptr = doc->virtadr;
-+
- /* This is inline, to optimise the common case, where it's ready instantly */
- int ret = 0;
-
-@@ -131,7 +141,7 @@
- static inline int DoC_Command(struct DiskOnChip *doc, unsigned char command,
- unsigned char xtraflags)
- {
-- unsigned long docptr = doc->virtadr;
-+ void __iomem *docptr = doc->virtadr;
-
- if (DoC_is_2000(doc))
- xtraflags |= CDSN_CTRL_FLASH_IO;
-@@ -145,6 +155,8 @@
-
- /* Send the command */
- WriteDOC_(command, docptr, doc->ioreg);
-+ if (DoC_is_Millennium(doc))
-+ WriteDOC(command, docptr, WritePipeTerm);
-
- /* Lower the CLE line */
- WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
-@@ -161,10 +173,8 @@
- static int DoC_Address(struct DiskOnChip *doc, int numbytes, unsigned long ofs,
- unsigned char xtraflags1, unsigned char xtraflags2)
- {
-- unsigned long docptr;
- int i;
--
-- docptr = doc->virtadr;
-+ void __iomem *docptr = doc->virtadr;
-
- if (DoC_is_2000(doc))
- xtraflags1 |= CDSN_CTRL_FLASH_IO;
-@@ -206,6 +216,9 @@
- }
- }
-
-+ if (DoC_is_Millennium(doc))
-+ WriteDOC(ofs & 0xff, docptr, WritePipeTerm);
-+
- DoC_Delay(doc, 2); /* Needed for some slow flash chips. mf. */
-
- /* FIXME: The SlowIO's for millennium could be replaced by
-@@ -226,11 +239,9 @@
- {
- volatile int dummy;
- int modulus = 0xffff;
-- unsigned long docptr;
-+ void __iomem *docptr = doc->virtadr;
- int i;
-
-- docptr = doc->virtadr;
--
- if (len <= 0)
- return;
-
-@@ -257,11 +268,9 @@
- /* Write a buffer to DoC, taking care of Millennium odditys */
- static void DoC_WriteBuf(struct DiskOnChip *doc, const u_char * buf, int len)
- {
-- unsigned long docptr;
-+ void __iomem *docptr = doc->virtadr;
- int i;
-
-- docptr = doc->virtadr;
--
- if (len <= 0)
- return;
-
-@@ -278,7 +287,7 @@
-
- static inline int DoC_SelectChip(struct DiskOnChip *doc, int chip)
- {
-- unsigned long docptr = doc->virtadr;
-+ void __iomem *docptr = doc->virtadr;
-
- /* Software requirement 11.4.4 before writing DeviceSelect */
- /* Deassert the CE line to eliminate glitches on the FCE# outputs */
-@@ -302,7 +311,7 @@
-
- static inline int DoC_SelectFloor(struct DiskOnChip *doc, int floor)
- {
-- unsigned long docptr = doc->virtadr;
-+ void __iomem *docptr = doc->virtadr;
-
- /* Select the floor (bank) of chips required */
- WriteDOC(floor, docptr, FloorSelect);
-@@ -344,15 +353,25 @@
-
- /* Read the manufacturer and device id codes from the device */
-
-- /* CDSN Slow IO register see Software Requirement 11.4 item 5. */
-+ if (DoC_is_Millennium(doc)) {
-+ DoC_Delay(doc, 2);
-+ dummy = ReadDOC(doc->virtadr, ReadPipeInit);
-+ mfr = ReadDOC(doc->virtadr, LastDataRead);
-+
-+ DoC_Delay(doc, 2);
-+ dummy = ReadDOC(doc->virtadr, ReadPipeInit);
-+ id = ReadDOC(doc->virtadr, LastDataRead);
-+ } else {
-+ /* CDSN Slow IO register see Software Req 11.4 item 5. */
- dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
- DoC_Delay(doc, 2);
- mfr = ReadDOC_(doc->virtadr, doc->ioreg);
-
-- /* CDSN Slow IO register see Software Requirement 11.4 item 5. */
-+ /* CDSN Slow IO register see Software Req 11.4 item 5. */
- dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
- DoC_Delay(doc, 2);
- id = ReadDOC_(doc->virtadr, doc->ioreg);
-+ }
-
- /* No response - return failure */
- if (mfr == 0xff || mfr == 0)
-@@ -387,10 +406,9 @@
- doc->mfr = mfr;
- doc->id = id;
- doc->chipshift =
-- nand_flash_ids[i].chipshift;
-- doc->page256 = nand_flash_ids[i].page256;
-- doc->pageadrlen =
-- nand_flash_ids[i].chipshift > 25 ? 3 : 2;
-+ ffs((nand_flash_ids[i].chipsize << 20)) - 1;
-+ doc->page256 = (nand_flash_ids[i].pagesize == 256) ? 1 : 0;
-+ doc->pageadrlen = doc->chipshift > 25 ? 3 : 2;
- doc->erasesize =
- nand_flash_ids[i].erasesize;
- return 1;
-@@ -410,20 +428,16 @@
-
- /* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
-
--static void DoC_ScanChips(struct DiskOnChip *this)
-+static void DoC_ScanChips(struct DiskOnChip *this, int maxchips)
- {
- int floor, chip;
- int numchips[MAX_FLOORS];
-- int maxchips = MAX_CHIPS;
- int ret = 1;
-
- this->numchips = 0;
- this->mfr = 0;
- this->id = 0;
-
-- if (DoC_is_Millennium(this))
-- maxchips = MAX_CHIPS_MIL;
--
- /* For each floor, find the number of valid chips it contains */
- for (floor = 0; floor < MAX_FLOORS; floor++) {
- ret = 1;
-@@ -513,39 +527,54 @@
- */
- static void DoC2k_init(struct mtd_info *mtd)
- {
-- struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
-+ struct DiskOnChip *this = mtd->priv;
- struct DiskOnChip *old = NULL;
-+ int maxchips;
-
- /* We must avoid being called twice for the same device. */
-
- if (doc2klist)
-- old = (struct DiskOnChip *) doc2klist->priv;
-+ old = doc2klist->priv;
-
- while (old) {
- if (DoC2k_is_alias(old, this)) {
- printk(KERN_NOTICE
- "Ignoring DiskOnChip 2000 at 0x%lX - already configured\n",
- this->physadr);
-- iounmap((void *) this->virtadr);
-+ iounmap(this->virtadr);
- kfree(mtd);
- return;
- }
- if (old->nextdoc)
-- old = (struct DiskOnChip *) old->nextdoc->priv;
-+ old = old->nextdoc->priv;
- else
- old = NULL;
- }
-
-
- switch (this->ChipID) {
-+ case DOC_ChipID_Doc2kTSOP:
-+ mtd->name = "DiskOnChip 2000 TSOP";
-+ this->ioreg = DoC_Mil_CDSN_IO;
-+ /* Pretend it's a Millennium */
-+ this->ChipID = DOC_ChipID_DocMil;
-+ maxchips = MAX_CHIPS;
-+ break;
- case DOC_ChipID_Doc2k:
- mtd->name = "DiskOnChip 2000";
- this->ioreg = DoC_2k_CDSN_IO;
-+ maxchips = MAX_CHIPS;
- break;
- case DOC_ChipID_DocMil:
- mtd->name = "DiskOnChip Millennium";
- this->ioreg = DoC_Mil_CDSN_IO;
-+ maxchips = MAX_CHIPS_MIL;
- break;
-+ default:
-+ printk("Unknown ChipID 0x%02x\n", this->ChipID);
-+ kfree(mtd);
-+ iounmap(this->virtadr);
-+ return;
- }
-
- printk(KERN_NOTICE "%s found at address 0x%lX\n", mtd->name,
-@@ -553,11 +582,12 @@
-
- mtd->type = MTD_NANDFLASH;
- mtd->flags = MTD_CAP_NANDFLASH;
-+ mtd->ecctype = MTD_ECC_RS_DiskOnChip;
- mtd->size = 0;
- mtd->erasesize = 0;
- mtd->oobblock = 512;
- mtd->oobsize = 16;
-- mtd->module = THIS_MODULE;
-+ mtd->owner = THIS_MODULE;
- mtd->erase = doc_erase;
- mtd->point = NULL;
- mtd->unpoint = NULL;
-@@ -565,6 +595,7 @@
- mtd->write = doc_write;
- mtd->read_ecc = doc_read_ecc;
- mtd->write_ecc = doc_write_ecc;
-+ mtd->writev_ecc = doc_writev_ecc;
- mtd->read_oob = doc_read_oob;
- mtd->write_oob = doc_write_oob;
- mtd->sync = NULL;
-@@ -577,11 +608,11 @@
- init_MUTEX(&this->lock);
-
- /* Ident all the chips present. */
-- DoC_ScanChips(this);
-+ DoC_ScanChips(this, maxchips);
-
- if (!this->totlen) {
- kfree(mtd);
-- iounmap((void *) this->virtadr);
-+ iounmap(this->virtadr);
- } else {
- this->nextdoc = doc2klist;
- doc2klist = mtd;
-@@ -596,20 +627,19 @@
- size_t * retlen, u_char * buf)
- {
- /* Just a special case of doc_read_ecc */
-- return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
-+ return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
- }
-
- static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-- size_t * retlen, u_char * buf, u_char * eccbuf, int oobsel)
-+ size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel)
- {
-- struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
-- unsigned long docptr;
-+ struct DiskOnChip *this = mtd->priv;
-+ void __iomem *docptr = this->virtadr;
- struct Nand *mychip;
- unsigned char syndrome[6];
- volatile char dummy;
- int i, len256 = 0, ret=0;
--
-- docptr = this->virtadr;
-+ size_t left = len;
-
- /* Don't allow read past end of device */
- if (from >= this->totlen)
-@@ -617,6 +647,10 @@
-
- down(&this->lock);
-
-+ *retlen = 0;
-+ while (left) {
-+ len = left;
-+
- /* Don't allow a single read to cross a 512-byte block boundary */
- if (from + len > ((from | 0x1ff) + 1))
- len = ((from | 0x1ff) + 1) - from;
-@@ -673,7 +707,7 @@
- DoC_ReadBuf(this, &buf[len256], len - len256);
-
- /* Let the caller know we completed it */
-- *retlen = len;
-+ *retlen += len;
-
- if (eccbuf) {
- /* Read the ECC data through the DiskOnChip ECC logic */
-@@ -730,11 +764,16 @@
-
- /* according to 11.4.1, we need to wait for the busy line
- * drop if we read to the end of the page. */
-- if(0 == ((from + *retlen) & 0x1ff))
-+ if(0 == ((from + len) & 0x1ff))
- {
- DoC_WaitReady(this);
- }
-
-+ from += len;
-+ left -= len;
-+ buf += len;
-+ }
-+
- up(&this->lock);
-
- return ret;
-@@ -744,21 +783,21 @@
- size_t * retlen, const u_char * buf)
- {
- char eccbuf[6];
-- return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
-+ return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
- }
-
- static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
- size_t * retlen, const u_char * buf,
-- u_char * eccbuf, int oobsel)
-+ u_char * eccbuf, struct nand_oobinfo *oobsel)
- {
-- struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
-+ struct DiskOnChip *this = mtd->priv;
- int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
-- unsigned long docptr;
-+ void __iomem *docptr = this->virtadr;
- volatile char dummy;
- int len256 = 0;
- struct Nand *mychip;
--
-- docptr = this->virtadr;
-+ size_t left = len;
-+ int status;
-
- /* Don't allow write past end of device */
- if (to >= this->totlen)
-@@ -766,15 +805,21 @@
-
- down(&this->lock);
-
-+ *retlen = 0;
-+ while (left) {
-+ len = left;
-+
- /* Don't allow a single write to cross a 512-byte block boundary */
- if (to + len > ((to | 0x1ff) + 1))
- len = ((to | 0x1ff) + 1) - to;
-
- /* The ECC will not be calculated correctly if less than 512 is written */
-+/* DBB-
- if (len != 0x200 && eccbuf)
- printk(KERN_WARNING
- "ECC needs a full sector write (adr: %lx size %lx)\n",
- (long) to, (long) len);
-+ -DBB */
-
- /* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
-
-@@ -853,6 +898,9 @@
- WriteDOC_(0, docptr, this->ioreg);
- }
-
-+ WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr,
-+ CDSNControl);
-+
- /* Read the ECC data through the DiskOnChip ECC logic */
- for (di = 0; di < 6; di++) {
- eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
-@@ -874,10 +922,16 @@
- DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
- /* There's an implicit DoC_WaitReady() in DoC_Command */
-
-+ if (DoC_is_Millennium(this)) {
-+ ReadDOC(docptr, ReadPipeInit);
-+ status = ReadDOC(docptr, LastDataRead);
-+ } else {
- dummy = ReadDOC(docptr, CDSNSlowIO);
- DoC_Delay(this, 2);
-+ status = ReadDOC_(docptr, this->ioreg);
-+ }
-
-- if (ReadDOC_(docptr, this->ioreg) & 1) {
-+ if (status & 1) {
- printk(KERN_ERR "Error programming flash\n");
- /* Error in programming */
- *retlen = 0;
-@@ -886,7 +940,7 @@
- }
-
- /* Let the caller know we completed it */
-- *retlen = len;
-+ *retlen += len;
-
- if (eccbuf) {
- unsigned char x[8];
-@@ -901,25 +955,90 @@
- x[7]=0x55;
-
- ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x);
-+ if (ret) {
- up(&this->lock);
- return ret;
- }
-+ }
-+
-+ to += len;
-+ left -= len;
-+ buf += len;
-+ }
-+
- up(&this->lock);
- return 0;
- }
-
-+static int doc_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 char static_buf[512];
-+ static DECLARE_MUTEX(writev_buf_sem);
-+
-+ size_t totretlen = 0;
-+ size_t thisvecofs = 0;
-+ int ret= 0;
-+
-+ down(&writev_buf_sem);
-+
-+ while(count) {
-+ size_t thislen, thisretlen;
-+ unsigned char *buf;
-+
-+ buf = vecs->iov_base + thisvecofs;
-+ thislen = vecs->iov_len - thisvecofs;
-+
-+
-+ if (thislen >= 512) {
-+ thislen = thislen & ~(512-1);
-+ thisvecofs += thislen;
-+ } else {
-+ /* Not enough to fill a page. Copy into buf */
-+ memcpy(static_buf, buf, thislen);
-+ buf = &static_buf[thislen];
-+
-+ while(count && thislen < 512) {
-+ vecs++;
-+ count--;
-+ thisvecofs = min((512-thislen), vecs->iov_len);
-+ memcpy(buf, vecs->iov_base, thisvecofs);
-+ thislen += thisvecofs;
-+ buf += thisvecofs;
-+ }
-+ buf = static_buf;
-+ }
-+ if (count && thisvecofs == vecs->iov_len) {
-+ thisvecofs = 0;
-+ vecs++;
-+ count--;
-+ }
-+ ret = doc_write_ecc(mtd, to, thislen, &thisretlen, buf, eccbuf, oobsel);
-+
-+ totretlen += thisretlen;
-+
-+ if (ret || thisretlen != thislen)
-+ break;
-+
-+ to += thislen;
-+ }
-+
-+ up(&writev_buf_sem);
-+ *retlen = totretlen;
-+ return ret;
-+}
-+
-+
- static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
- size_t * retlen, u_char * buf)
- {
-- struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
-+ struct DiskOnChip *this = mtd->priv;
- int len256 = 0, ret;
-- unsigned long docptr;
- struct Nand *mychip;
-
- down(&this->lock);
-
-- docptr = this->virtadr;
--
- mychip = &this->chips[ofs >> this->chipshift];
-
- if (this->curfloor != mychip->floor) {
-@@ -972,11 +1091,12 @@
- static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len,
- size_t * retlen, const u_char * buf)
- {
-- struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
-+ struct DiskOnChip *this = mtd->priv;
- int len256 = 0;
-- unsigned long docptr = this->virtadr;
-+ void __iomem *docptr = this->virtadr;
- struct Nand *mychip = &this->chips[ofs >> this->chipshift];
- volatile int dummy;
-+ int status;
-
- // printk("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",(long)ofs, len,
- // buf[0], buf[1], buf[2], buf[3], buf[8], buf[9], buf[14],buf[15]);
-@@ -1025,10 +1145,16 @@
- DoC_Command(this, NAND_CMD_STATUS, 0);
- /* DoC_WaitReady() is implicit in DoC_Command */
-
-+ if (DoC_is_Millennium(this)) {
-+ ReadDOC(docptr, ReadPipeInit);
-+ status = ReadDOC(docptr, LastDataRead);
-+ } else {
- dummy = ReadDOC(docptr, CDSNSlowIO);
- DoC_Delay(this, 2);
-+ status = ReadDOC_(docptr, this->ioreg);
-+ }
-
-- if (ReadDOC_(docptr, this->ioreg) & 1) {
-+ if (status & 1) {
- printk(KERN_ERR "Error programming oob data\n");
- /* There was an error */
- *retlen = 0;
-@@ -1044,10 +1170,16 @@
- DoC_Command(this, NAND_CMD_STATUS, 0);
- /* DoC_WaitReady() is implicit in DoC_Command */
-
-+ if (DoC_is_Millennium(this)) {
-+ ReadDOC(docptr, ReadPipeInit);
-+ status = ReadDOC(docptr, LastDataRead);
-+ } else {
- dummy = ReadDOC(docptr, CDSNSlowIO);
- DoC_Delay(this, 2);
-+ status = ReadDOC_(docptr, this->ioreg);
-+ }
-
-- if (ReadDOC_(docptr, this->ioreg) & 1) {
-+ if (status & 1) {
- printk(KERN_ERR "Error programming oob data\n");
- /* There was an error */
- *retlen = 0;
-@@ -1062,7 +1194,7 @@
- static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
- size_t * retlen, const u_char * buf)
- {
-- struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
-+ struct DiskOnChip *this = mtd->priv;
- int ret;
-
- down(&this->lock);
-@@ -1074,12 +1206,13 @@
-
- static int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
- {
-- struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
-+ struct DiskOnChip *this = mtd->priv;
- __u32 ofs = instr->addr;
- __u32 len = instr->len;
- volatile int dummy;
-- unsigned long docptr;
-+ void __iomem *docptr = this->virtadr;
- struct Nand *mychip;
-+ int status;
-
- down(&this->lock);
-
-@@ -1090,8 +1223,6 @@
-
- instr->state = MTD_ERASING;
-
-- docptr = this->virtadr;
--
- /* FIXME: Do this in the background. Use timers or schedule_task() */
- while(len) {
- mychip = &this->chips[ofs >> this->chipshift];
-@@ -1111,10 +1242,16 @@
-
- DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
-
-+ if (DoC_is_Millennium(this)) {
-+ ReadDOC(docptr, ReadPipeInit);
-+ status = ReadDOC(docptr, LastDataRead);
-+ } else {
- dummy = ReadDOC(docptr, CDSNSlowIO);
- DoC_Delay(this, 2);
-+ status = ReadDOC_(docptr, this->ioreg);
-+ }
-
-- if (ReadDOC_(docptr, this->ioreg) & 1) {
-+ if (status & 1) {
- printk(KERN_ERR "Error erasing at 0x%x\n", ofs);
- /* There was an error */
- instr->state = MTD_ERASE_FAILED;
-@@ -1126,8 +1263,7 @@
- instr->state = MTD_ERASE_DONE;
-
- callback:
-- if (instr->callback)
-- instr->callback(instr);
-+ mtd_erase_callback(instr);
-
- up(&this->lock);
- return 0;
-@@ -1140,7 +1276,7 @@
- *
- ****************************************************************************/
-
--int __init init_doc2000(void)
-+static int __init init_doc2000(void)
- {
- inter_module_register(im_name, THIS_MODULE, &DoC2k_init);
- return 0;
-@@ -1152,12 +1288,12 @@
- struct DiskOnChip *this;
-
- while ((mtd = doc2klist)) {
-- this = (struct DiskOnChip *) mtd->priv;
-+ this = mtd->priv;
- doc2klist = this->nextdoc;
-
- del_mtd_device(mtd);
-
-- iounmap((void *) this->virtadr);
-+ iounmap(this->virtadr);
- kfree(this->chips);
- kfree(mtd);
- }
---- linux-2.4.21/drivers/mtd/devices/doc2001.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/devices/doc2001.c
-@@ -4,7 +4,7 @@
- * (c) 1999 Machine Vision Holdings, Inc.
- * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
- *
-- * $Id: doc2001.c,v 1.38 2002/12/10 15:05:42 gleixner Exp $
-+ * $Id: doc2001.c,v 1.48 2005/01/05 18:05:12 dwmw2 Exp $
- */
-
- #include <linux/kernel.h>
-@@ -19,6 +19,7 @@
- #include <linux/sched.h>
- #include <linux/init.h>
- #include <linux/types.h>
-+#include <linux/bitops.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
-@@ -37,9 +38,11 @@
- static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf);
- static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-- size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel);
-+ size_t *retlen, u_char *buf, u_char *eccbuf,
-+ struct nand_oobinfo *oobsel);
- static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-- size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
-+ size_t *retlen, const u_char *buf, u_char *eccbuf,
-+ struct nand_oobinfo *oobsel);
- static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
- size_t *retlen, u_char *buf);
- static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
-@@ -49,7 +52,7 @@
- static struct mtd_info *docmillist = NULL;
-
- /* Perform the required delay cycles by reading from the NOP register */
--static void DoC_Delay(unsigned long docptr, unsigned short cycles)
-+static void DoC_Delay(void __iomem * docptr, unsigned short cycles)
- {
- volatile char dummy;
- int i;
-@@ -59,7 +62,7 @@
- }
-
- /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
--static int _DoC_WaitReady(unsigned long docptr)
-+static int _DoC_WaitReady(void __iomem * docptr)
- {
- unsigned short c = 0xffff;
-
-@@ -76,7 +79,7 @@
- return (c == 0);
- }
-
--static inline int DoC_WaitReady(unsigned long docptr)
-+static inline int DoC_WaitReady(void __iomem * docptr)
- {
- /* This is inline, to optimise the common case, where it's ready instantly */
- int ret = 0;
-@@ -100,7 +103,7 @@
- with the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
- required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
-
--static inline void DoC_Command(unsigned long docptr, unsigned char command,
-+static inline void DoC_Command(void __iomem * docptr, unsigned char command,
- unsigned char xtraflags)
- {
- /* Assert the CLE (Command Latch Enable) line to the flash chip */
-@@ -120,7 +123,7 @@
- with the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
- required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
-
--static inline void DoC_Address(unsigned long docptr, int numbytes, unsigned long ofs,
-+static inline void DoC_Address(void __iomem * docptr, int numbytes, unsigned long ofs,
- unsigned char xtraflags1, unsigned char xtraflags2)
- {
- /* Assert the ALE (Address Latch Enable) line to the flash chip */
-@@ -158,7 +161,7 @@
- }
-
- /* DoC_SelectChip: Select a given flash chip within the current floor */
--static int DoC_SelectChip(unsigned long docptr, int chip)
-+static int DoC_SelectChip(void __iomem * docptr, int chip)
- {
- /* Select the individual flash chip requested */
- WriteDOC(chip, docptr, CDSNDeviceSelect);
-@@ -169,7 +172,7 @@
- }
-
- /* DoC_SelectFloor: Select a given floor (bank of flash chips) */
--static int DoC_SelectFloor(unsigned long docptr, int floor)
-+static int DoC_SelectFloor(void __iomem * docptr, int floor)
- {
- /* Select the floor (bank) of chips required */
- WriteDOC(floor, docptr, FloorSelect);
-@@ -226,7 +229,7 @@
- mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name);
- doc->mfr = mfr;
- doc->id = id;
-- doc->chipshift = nand_flash_ids[i].chipshift;
-+ doc->chipshift = ffs((nand_flash_ids[i].chipsize << 20)) - 1;
- break;
- }
- }
-@@ -332,23 +335,23 @@
- */
- static void DoCMil_init(struct mtd_info *mtd)
- {
-- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-+ struct DiskOnChip *this = mtd->priv;
- struct DiskOnChip *old = NULL;
-
- /* We must avoid being called twice for the same device. */
- if (docmillist)
-- old = (struct DiskOnChip *)docmillist->priv;
-+ old = docmillist->priv;
-
- while (old) {
- if (DoCMil_is_alias(this, old)) {
- printk(KERN_NOTICE "Ignoring DiskOnChip Millennium at "
- "0x%lX - already configured\n", this->physadr);
-- iounmap((void *)this->virtadr);
-+ iounmap(this->virtadr);
- kfree(mtd);
- return;
- }
- if (old->nextdoc)
-- old = (struct DiskOnChip *)old->nextdoc->priv;
-+ old = old->nextdoc->priv;
- else
- old = NULL;
- }
-@@ -359,14 +362,15 @@
-
- mtd->type = MTD_NANDFLASH;
- mtd->flags = MTD_CAP_NANDFLASH;
-+ mtd->ecctype = MTD_ECC_RS_DiskOnChip;
- mtd->size = 0;
-
-- /* FIXME: erase size is not always 8kB */
-+ /* FIXME: erase size is not always 8KiB */
- mtd->erasesize = 0x2000;
-
- mtd->oobblock = 512;
- mtd->oobsize = 16;
-- mtd->module = THIS_MODULE;
-+ mtd->owner = THIS_MODULE;
- mtd->erase = doc_erase;
- mtd->point = NULL;
- mtd->unpoint = NULL;
-@@ -388,7 +392,7 @@
-
- if (!this->totlen) {
- kfree(mtd);
-- iounmap((void *)this->virtadr);
-+ iounmap(this->virtadr);
- } else {
- this->nextdoc = docmillist;
- docmillist = mtd;
-@@ -402,17 +406,18 @@
- size_t *retlen, u_char *buf)
- {
- /* Just a special case of doc_read_ecc */
-- return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
-+ return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
- }
-
- static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-- size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel)
-+ size_t *retlen, u_char *buf, u_char *eccbuf,
-+ struct nand_oobinfo *oobsel)
- {
- int i, ret;
- volatile char dummy;
- unsigned char syndrome[6];
-- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-- unsigned long docptr = this->virtadr;
-+ struct DiskOnChip *this = mtd->priv;
-+ void __iomem *docptr = this->virtadr;
- struct Nand *mychip = &this->chips[from >> (this->chipshift)];
-
- /* Don't allow read past end of device */
-@@ -528,16 +533,17 @@
- size_t *retlen, const u_char *buf)
- {
- char eccbuf[6];
-- return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
-+ return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
- }
-
- static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-- size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel)
-+ size_t *retlen, const u_char *buf, u_char *eccbuf,
-+ struct nand_oobinfo *oobsel)
- {
- int i,ret = 0;
- volatile char dummy;
-- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-- unsigned long docptr = this->virtadr;
-+ struct DiskOnChip *this = mtd->priv;
-+ void __iomem *docptr = this->virtadr;
- struct Nand *mychip = &this->chips[to >> (this->chipshift)];
-
- /* Don't allow write past end of device */
-@@ -671,8 +677,8 @@
- int i;
- #endif
- volatile char dummy;
-- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-- unsigned long docptr = this->virtadr;
-+ struct DiskOnChip *this = mtd->priv;
-+ void __iomem *docptr = this->virtadr;
- struct Nand *mychip = &this->chips[ofs >> this->chipshift];
-
- /* Find the chip which is to be used and select it */
-@@ -723,8 +729,8 @@
- #endif
- volatile char dummy;
- int ret = 0;
-- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-- unsigned long docptr = this->virtadr;
-+ struct DiskOnChip *this = mtd->priv;
-+ void __iomem *docptr = this->virtadr;
- struct Nand *mychip = &this->chips[ofs >> this->chipshift];
-
- /* Find the chip which is to be used and select it */
-@@ -790,10 +796,10 @@
- int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
- {
- volatile char dummy;
-- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-+ struct DiskOnChip *this = mtd->priv;
- __u32 ofs = instr->addr;
- __u32 len = instr->len;
-- unsigned long docptr = this->virtadr;
-+ void __iomem *docptr = this->virtadr;
- struct Nand *mychip = &this->chips[ofs >> this->chipshift];
-
- if (len != mtd->erasesize)
-@@ -839,8 +845,7 @@
- instr->state = MTD_ERASE_DONE;
- dummy = ReadDOC(docptr, LastDataRead);
-
-- if (instr->callback)
-- instr->callback(instr);
-+ mtd_erase_callback(instr);
-
- return 0;
- }
-@@ -851,7 +856,7 @@
- *
- ****************************************************************************/
-
--int __init init_doc2001(void)
-+static int __init init_doc2001(void)
- {
- inter_module_register(im_name, THIS_MODULE, &DoCMil_init);
- return 0;
-@@ -863,12 +868,12 @@
- struct DiskOnChip *this;
-
- while ((mtd=docmillist)) {
-- this = (struct DiskOnChip *)mtd->priv;
-+ this = mtd->priv;
- docmillist = this->nextdoc;
-
- del_mtd_device(mtd);
-
-- iounmap((void *)this->virtadr);
-+ iounmap(this->virtadr);
- kfree(this->chips);
- kfree(mtd);
- }
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/devices/doc2001plus.c
-@@ -0,0 +1,1154 @@
-+/*
-+ * Linux driver for Disk-On-Chip Millennium Plus
-+ *
-+ * (c) 2002-2003 Greg Ungerer <gerg@snapgear.com>
-+ * (c) 2002-2003 SnapGear Inc
-+ * (c) 1999 Machine Vision Holdings, Inc.
-+ * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * $Id: doc2001plus.c,v 1.13 2005/01/05 18:05:12 dwmw2 Exp $
-+ *
-+ * Released under GPL
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <asm/errno.h>
-+#include <asm/io.h>
-+#include <asm/uaccess.h>
-+#include <linux/miscdevice.h>
-+#include <linux/pci.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <linux/sched.h>
-+#include <linux/init.h>
-+#include <linux/types.h>
-+#include <linux/bitops.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/doc2000.h>
-+
-+/* #define ECC_DEBUG */
-+
-+/* I have no idea why some DoC chips can not use memcop_form|to_io().
-+ * This may be due to the different revisions of the ASIC controller built-in or
-+ * simplily a QA/Bug issue. Who knows ?? If you have trouble, please uncomment
-+ * this:*/
-+#undef USE_MEMCPY
-+
-+static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t *retlen, u_char *buf);
-+static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t *retlen, const u_char *buf);
-+static int doc_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 doc_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 doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
-+ size_t *retlen, u_char *buf);
-+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
-+ size_t *retlen, const u_char *buf);
-+static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
-+
-+static struct mtd_info *docmilpluslist = NULL;
-+
-+
-+/* Perform the required delay cycles by writing to the NOP register */
-+static void DoC_Delay(void __iomem * docptr, int cycles)
-+{
-+ int i;
-+
-+ for (i = 0; (i < cycles); i++)
-+ WriteDOC(0, docptr, Mplus_NOP);
-+}
-+
-+#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(void __iomem * docptr)
-+{
-+ unsigned int c = 0xffff;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3,
-+ "_DoC_WaitReady called for out-of-line wait\n");
-+
-+ /* Out-of-line routine to wait for chip response */
-+ while (((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) && --c)
-+ ;
-+
-+ if (c == 0)
-+ DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
-+
-+ return (c == 0);
-+}
-+
-+static inline int DoC_WaitReady(void __iomem * docptr)
-+{
-+ /* This is inline, to optimise the common case, where it's ready instantly */
-+ int ret = 0;
-+
-+ /* read form NOP register should be issued prior to the read from CDSNControl
-+ see Software Requirement 11.4 item 2. */
-+ DoC_Delay(docptr, 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(docptr);
-+
-+ return ret;
-+}
-+
-+/* For some reason the Millennium Plus seems to occassionally put itself
-+ * into reset mode. For me this happens randomly, with no pattern that I
-+ * can detect. M-systems suggest always check this on any block level
-+ * operation and setting to normal mode if in reset mode.
-+ */
-+static inline void DoC_CheckASIC(void __iomem * docptr)
-+{
-+ /* Make sure the DoC is in normal mode */
-+ if ((ReadDOC(docptr, Mplus_DOCControl) & DOC_MODE_NORMAL) == 0) {
-+ WriteDOC((DOC_MODE_NORMAL | DOC_MODE_MDWREN), docptr, Mplus_DOCControl);
-+ WriteDOC(~(DOC_MODE_NORMAL | DOC_MODE_MDWREN), docptr, Mplus_CtrlConfirm);
-+ }
-+}
-+
-+/* DoC_Command: Send a flash command to the flash chip through the Flash
-+ * command register. Need 2 Write Pipeline Terminates to complete send.
-+ */
-+static inline void DoC_Command(void __iomem * docptr, unsigned char command,
-+ unsigned char xtraflags)
-+{
-+ WriteDOC(command, docptr, Mplus_FlashCmd);
-+ WriteDOC(command, docptr, Mplus_WritePipeTerm);
-+ WriteDOC(command, docptr, Mplus_WritePipeTerm);
-+}
-+
-+/* DoC_Address: Set the current address for the flash chip through the Flash
-+ * Address register. Need 2 Write Pipeline Terminates to complete send.
-+ */
-+static inline void DoC_Address(struct DiskOnChip *doc, int numbytes,
-+ unsigned long ofs, unsigned char xtraflags1,
-+ unsigned char xtraflags2)
-+{
-+ void __iomem * docptr = doc->virtadr;
-+
-+ /* Allow for possible Mill Plus internal flash interleaving */
-+ ofs >>= doc->interleave;
-+
-+ switch (numbytes) {
-+ case 1:
-+ /* Send single byte, bits 0-7. */
-+ WriteDOC(ofs & 0xff, docptr, Mplus_FlashAddress);
-+ break;
-+ case 2:
-+ /* Send bits 9-16 followed by 17-23 */
-+ WriteDOC((ofs >> 9) & 0xff, docptr, Mplus_FlashAddress);
-+ WriteDOC((ofs >> 17) & 0xff, docptr, Mplus_FlashAddress);
-+ break;
-+ case 3:
-+ /* Send 0-7, 9-16, then 17-23 */
-+ WriteDOC(ofs & 0xff, docptr, Mplus_FlashAddress);
-+ WriteDOC((ofs >> 9) & 0xff, docptr, Mplus_FlashAddress);
-+ WriteDOC((ofs >> 17) & 0xff, docptr, Mplus_FlashAddress);
-+ break;
-+ default:
-+ return;
-+ }
-+
-+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
-+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
-+}
-+
-+/* DoC_SelectChip: Select a given flash chip within the current floor */
-+static int DoC_SelectChip(void __iomem * docptr, int chip)
-+{
-+ /* No choice for flash chip on Millennium Plus */
-+ return 0;
-+}
-+
-+/* DoC_SelectFloor: Select a given floor (bank of flash chips) */
-+static int DoC_SelectFloor(void __iomem * docptr, int floor)
-+{
-+ WriteDOC((floor & 0x3), docptr, Mplus_DeviceSelect);
-+ return 0;
-+}
-+
-+/*
-+ * Translate the given offset into the appropriate command and offset.
-+ * This does the mapping using the 16bit interleave layout defined by
-+ * M-Systems, and looks like this for a sector pair:
-+ * +-----------+-------+-------+-------+--------------+---------+-----------+
-+ * | 0 --- 511 |512-517|518-519|520-521| 522 --- 1033 |1034-1039|1040 - 1055|
-+ * +-----------+-------+-------+-------+--------------+---------+-----------+
-+ * | Data 0 | ECC 0 |Flags0 |Flags1 | Data 1 |ECC 1 | OOB 1 + 2 |
-+ * +-----------+-------+-------+-------+--------------+---------+-----------+
-+ */
-+/* FIXME: This lives in INFTL not here. Other users of flash devices
-+ may not want it */
-+static unsigned int DoC_GetDataOffset(struct mtd_info *mtd, loff_t *from)
-+{
-+ struct DiskOnChip *this = mtd->priv;
-+
-+ if (this->interleave) {
-+ unsigned int ofs = *from & 0x3ff;
-+ unsigned int cmd;
-+
-+ if (ofs < 512) {
-+ cmd = NAND_CMD_READ0;
-+ ofs &= 0x1ff;
-+ } else if (ofs < 1014) {
-+ cmd = NAND_CMD_READ1;
-+ ofs = (ofs & 0x1ff) + 10;
-+ } else {
-+ cmd = NAND_CMD_READOOB;
-+ ofs = ofs - 1014;
-+ }
-+
-+ *from = (*from & ~0x3ff) | ofs;
-+ return cmd;
-+ } else {
-+ /* No interleave */
-+ if ((*from) & 0x100)
-+ return NAND_CMD_READ1;
-+ return NAND_CMD_READ0;
-+ }
-+}
-+
-+static unsigned int DoC_GetECCOffset(struct mtd_info *mtd, loff_t *from)
-+{
-+ unsigned int ofs, cmd;
-+
-+ if (*from & 0x200) {
-+ cmd = NAND_CMD_READOOB;
-+ ofs = 10 + (*from & 0xf);
-+ } else {
-+ cmd = NAND_CMD_READ1;
-+ ofs = (*from & 0xf);
-+ }
-+
-+ *from = (*from & ~0x3ff) | ofs;
-+ return cmd;
-+}
-+
-+static unsigned int DoC_GetFlagsOffset(struct mtd_info *mtd, loff_t *from)
-+{
-+ unsigned int ofs, cmd;
-+
-+ cmd = NAND_CMD_READ1;
-+ ofs = (*from & 0x200) ? 8 : 6;
-+ *from = (*from & ~0x3ff) | ofs;
-+ return cmd;
-+}
-+
-+static unsigned int DoC_GetHdrOffset(struct mtd_info *mtd, loff_t *from)
-+{
-+ unsigned int ofs, cmd;
-+
-+ cmd = NAND_CMD_READOOB;
-+ ofs = (*from & 0x200) ? 24 : 16;
-+ *from = (*from & ~0x3ff) | ofs;
-+ return cmd;
-+}
-+
-+static inline void MemReadDOC(void __iomem * docptr, unsigned char *buf, int len)
-+{
-+#ifndef USE_MEMCPY
-+ int i;
-+ for (i = 0; i < len; i++)
-+ buf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
-+#else
-+ memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len);
-+#endif
-+}
-+
-+static inline void MemWriteDOC(void __iomem * docptr, unsigned char *buf, int len)
-+{
-+#ifndef USE_MEMCPY
-+ int i;
-+ for (i = 0; i < len; i++)
-+ WriteDOC(buf[i], docptr, Mil_CDSN_IO + i);
-+#else
-+ memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len);
-+#endif
-+}
-+
-+/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */
-+static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
-+{
-+ int mfr, id, i, j;
-+ volatile char dummy;
-+ void __iomem * docptr = doc->virtadr;
-+
-+ /* Page in the required floor/chip */
-+ DoC_SelectFloor(docptr, floor);
-+ DoC_SelectChip(docptr, chip);
-+
-+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
-+ WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect);
-+
-+ /* Reset the chip, see Software Requirement 11.4 item 1. */
-+ DoC_Command(docptr, NAND_CMD_RESET, 0);
-+ DoC_WaitReady(docptr);
-+
-+ /* Read the NAND chip ID: 1. Send ReadID command */
-+ DoC_Command(docptr, NAND_CMD_READID, 0);
-+
-+ /* Read the NAND chip ID: 2. Send address byte zero */
-+ DoC_Address(doc, 1, 0x00, 0, 0x00);
-+
-+ WriteDOC(0, docptr, Mplus_FlashControl);
-+ DoC_WaitReady(docptr);
-+
-+ /* Read the manufacturer and device id codes of the flash device through
-+ CDSN IO register see Software Requirement 11.4 item 5.*/
-+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
-+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
-+
-+ mfr = ReadDOC(docptr, Mil_CDSN_IO);
-+ if (doc->interleave)
-+ dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
-+
-+ id = ReadDOC(docptr, Mil_CDSN_IO);
-+ if (doc->interleave)
-+ dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
-+
-+ dummy = ReadDOC(docptr, Mplus_LastDataRead);
-+ dummy = ReadDOC(docptr, Mplus_LastDataRead);
-+
-+ /* Disable flash internally */
-+ WriteDOC(0, docptr, Mplus_FlashSelect);
-+
-+ /* No response - return failure */
-+ if (mfr == 0xff || mfr == 0)
-+ return 0;
-+
-+ for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-+ if (id == nand_flash_ids[i].id) {
-+ /* Try to identify manufacturer */
-+ for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
-+ if (nand_manuf_ids[j].id == mfr)
-+ break;
-+ }
-+ printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, "
-+ "Chip ID: %2.2X (%s:%s)\n", mfr, id,
-+ nand_manuf_ids[j].name, nand_flash_ids[i].name);
-+ doc->mfr = mfr;
-+ doc->id = id;
-+ doc->chipshift = ffs((nand_flash_ids[i].chipsize << 20)) - 1;
-+ doc->erasesize = nand_flash_ids[i].erasesize << doc->interleave;
-+ break;
-+ }
-+ }
-+
-+ if (nand_flash_ids[i].name == NULL)
-+ return 0;
-+ return 1;
-+}
-+
-+/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
-+static void DoC_ScanChips(struct DiskOnChip *this)
-+{
-+ int floor, chip;
-+ int numchips[MAX_FLOORS_MPLUS];
-+ int ret;
-+
-+ this->numchips = 0;
-+ this->mfr = 0;
-+ this->id = 0;
-+
-+ /* Work out the intended interleave setting */
-+ this->interleave = 0;
-+ if (this->ChipID == DOC_ChipID_DocMilPlus32)
-+ this->interleave = 1;
-+
-+ /* Check the ASIC agrees */
-+ if ( (this->interleave << 2) !=
-+ (ReadDOC(this->virtadr, Mplus_Configuration) & 4)) {
-+ u_char conf = ReadDOC(this->virtadr, Mplus_Configuration);
-+ printk(KERN_NOTICE "Setting DiskOnChip Millennium Plus interleave to %s\n",
-+ this->interleave?"on (16-bit)":"off (8-bit)");
-+ conf ^= 4;
-+ WriteDOC(conf, this->virtadr, Mplus_Configuration);
-+ }
-+
-+ /* For each floor, find the number of valid chips it contains */
-+ for (floor = 0,ret = 1; floor < MAX_FLOORS_MPLUS; floor++) {
-+ numchips[floor] = 0;
-+ for (chip = 0; chip < MAX_CHIPS_MPLUS && ret != 0; chip++) {
-+ ret = DoC_IdentChip(this, floor, chip);
-+ if (ret) {
-+ numchips[floor]++;
-+ this->numchips++;
-+ }
-+ }
-+ }
-+ /* If there are none at all that we recognise, bail */
-+ if (!this->numchips) {
-+ printk("No flash chips recognised.\n");
-+ return;
-+ }
-+
-+ /* Allocate an array to hold the information for each chip */
-+ this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL);
-+ if (!this->chips){
-+ printk("MTD: No memory for allocating chip info structures\n");
-+ return;
-+ }
-+
-+ /* Fill out the chip array with {floor, chipno} for each
-+ * detected chip in the device. */
-+ for (floor = 0, ret = 0; floor < MAX_FLOORS_MPLUS; floor++) {
-+ for (chip = 0 ; chip < numchips[floor] ; chip++) {
-+ this->chips[ret].floor = floor;
-+ this->chips[ret].chip = chip;
-+ this->chips[ret].curadr = 0;
-+ this->chips[ret].curmode = 0x50;
-+ ret++;
-+ }
-+ }
-+
-+ /* Calculate and print the total size of the device */
-+ this->totlen = this->numchips * (1 << this->chipshift);
-+ printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld MiB\n",
-+ this->numchips ,this->totlen >> 20);
-+}
-+
-+static int DoCMilPlus_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
-+{
-+ int tmp1, tmp2, retval;
-+
-+ if (doc1->physadr == doc2->physadr)
-+ return 1;
-+
-+ /* Use the alias resolution register which was set aside for this
-+ * purpose. If it's value is the same on both chips, they might
-+ * be the same chip, and we write to one and check for a change in
-+ * the other. It's unclear if this register is usuable in the
-+ * DoC 2000 (it's in the Millennium docs), but it seems to work. */
-+ tmp1 = ReadDOC(doc1->virtadr, Mplus_AliasResolution);
-+ tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution);
-+ if (tmp1 != tmp2)
-+ return 0;
-+
-+ WriteDOC((tmp1+1) % 0xff, doc1->virtadr, Mplus_AliasResolution);
-+ tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution);
-+ if (tmp2 == (tmp1+1) % 0xff)
-+ retval = 1;
-+ else
-+ retval = 0;
-+
-+ /* Restore register contents. May not be necessary, but do it just to
-+ * be safe. */
-+ WriteDOC(tmp1, doc1->virtadr, Mplus_AliasResolution);
-+
-+ return retval;
-+}
-+
-+static const char im_name[] = "DoCMilPlus_init";
-+
-+/* This routine is made available to other mtd code via
-+ * inter_module_register. It must only be accessed through
-+ * inter_module_get which will bump the use count of this module. The
-+ * addresses passed back in mtd are valid as long as the use count of
-+ * this module is non-zero, i.e. between inter_module_get and
-+ * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
-+ */
-+static void DoCMilPlus_init(struct mtd_info *mtd)
-+{
-+ struct DiskOnChip *this = mtd->priv;
-+ struct DiskOnChip *old = NULL;
-+
-+ /* We must avoid being called twice for the same device. */
-+ if (docmilpluslist)
-+ old = docmilpluslist->priv;
-+
-+ while (old) {
-+ if (DoCMilPlus_is_alias(this, old)) {
-+ printk(KERN_NOTICE "Ignoring DiskOnChip Millennium "
-+ "Plus at 0x%lX - already configured\n",
-+ this->physadr);
-+ iounmap(this->virtadr);
-+ kfree(mtd);
-+ return;
-+ }
-+ if (old->nextdoc)
-+ old = old->nextdoc->priv;
-+ else
-+ old = NULL;
-+ }
-+
-+ mtd->name = "DiskOnChip Millennium Plus";
-+ printk(KERN_NOTICE "DiskOnChip Millennium Plus found at "
-+ "address 0x%lX\n", this->physadr);
-+
-+ mtd->type = MTD_NANDFLASH;
-+ mtd->flags = MTD_CAP_NANDFLASH;
-+ mtd->ecctype = MTD_ECC_RS_DiskOnChip;
-+ mtd->size = 0;
-+
-+ mtd->erasesize = 0;
-+ mtd->oobblock = 512;
-+ mtd->oobsize = 16;
-+ mtd->owner = THIS_MODULE;
-+ mtd->erase = doc_erase;
-+ mtd->point = NULL;
-+ mtd->unpoint = NULL;
-+ mtd->read = doc_read;
-+ mtd->write = doc_write;
-+ mtd->read_ecc = doc_read_ecc;
-+ mtd->write_ecc = doc_write_ecc;
-+ mtd->read_oob = doc_read_oob;
-+ mtd->write_oob = doc_write_oob;
-+ mtd->sync = NULL;
-+
-+ this->totlen = 0;
-+ this->numchips = 0;
-+ this->curfloor = -1;
-+ this->curchip = -1;
-+
-+ /* Ident all the chips present. */
-+ DoC_ScanChips(this);
-+
-+ if (!this->totlen) {
-+ kfree(mtd);
-+ iounmap(this->virtadr);
-+ } else {
-+ this->nextdoc = docmilpluslist;
-+ docmilpluslist = mtd;
-+ mtd->size = this->totlen;
-+ mtd->erasesize = this->erasesize;
-+ add_mtd_device(mtd);
-+ return;
-+ }
-+}
-+
-+#if 0
-+static int doc_dumpblk(struct mtd_info *mtd, loff_t from)
-+{
-+ int i;
-+ loff_t fofs;
-+ struct DiskOnChip *this = mtd->priv;
-+ void __iomem * docptr = this->virtadr;
-+ struct Nand *mychip = &this->chips[from >> (this->chipshift)];
-+ unsigned char *bp, buf[1056];
-+ char c[32];
-+
-+ from &= ~0x3ff;
-+
-+ /* Don't allow read past end of device */
-+ if (from >= this->totlen)
-+ return -EINVAL;
-+
-+ DoC_CheckASIC(docptr);
-+
-+ /* Find the chip which is to be used and select it */
-+ if (this->curfloor != mychip->floor) {
-+ DoC_SelectFloor(docptr, mychip->floor);
-+ DoC_SelectChip(docptr, mychip->chip);
-+ } else if (this->curchip != mychip->chip) {
-+ DoC_SelectChip(docptr, mychip->chip);
-+ }
-+ this->curfloor = mychip->floor;
-+ this->curchip = mychip->chip;
-+
-+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
-+ WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect);
-+
-+ /* Reset the chip, see Software Requirement 11.4 item 1. */
-+ DoC_Command(docptr, NAND_CMD_RESET, 0);
-+ DoC_WaitReady(docptr);
-+
-+ fofs = from;
-+ DoC_Command(docptr, DoC_GetDataOffset(mtd, &fofs), 0);
-+ DoC_Address(this, 3, fofs, 0, 0x00);
-+ WriteDOC(0, docptr, Mplus_FlashControl);
-+ DoC_WaitReady(docptr);
-+
-+ /* disable the ECC engine */
-+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-+
-+ ReadDOC(docptr, Mplus_ReadPipeInit);
-+ ReadDOC(docptr, Mplus_ReadPipeInit);
-+
-+ /* Read the data via the internal pipeline through CDSN IO
-+ register, see Pipelined Read Operations 11.3 */
-+ MemReadDOC(docptr, buf, 1054);
-+ buf[1054] = ReadDOC(docptr, Mplus_LastDataRead);
-+ buf[1055] = ReadDOC(docptr, Mplus_LastDataRead);
-+
-+ memset(&c[0], 0, sizeof(c));
-+ printk("DUMP OFFSET=%x:\n", (int)from);
-+
-+ for (i = 0, bp = &buf[0]; (i < 1056); i++) {
-+ if ((i % 16) == 0)
-+ printk("%08x: ", i);
-+ printk(" %02x", *bp);
-+ c[(i & 0xf)] = ((*bp >= 0x20) && (*bp <= 0x7f)) ? *bp : '.';
-+ bp++;
-+ if (((i + 1) % 16) == 0)
-+ printk(" %s\n", c);
-+ }
-+ printk("\n");
-+
-+ /* Disable flash internally */
-+ WriteDOC(0, docptr, Mplus_FlashSelect);
-+
-+ return 0;
-+}
-+#endif
-+
-+static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t *retlen, u_char *buf)
-+{
-+ /* Just a special case of doc_read_ecc */
-+ return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
-+}
-+
-+static int doc_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)
-+{
-+ int ret, i;
-+ volatile char dummy;
-+ loff_t fofs;
-+ unsigned char syndrome[6];
-+ struct DiskOnChip *this = mtd->priv;
-+ void __iomem * docptr = this->virtadr;
-+ struct Nand *mychip = &this->chips[from >> (this->chipshift)];
-+
-+ /* Don't allow read past end of device */
-+ if (from >= this->totlen)
-+ return -EINVAL;
-+
-+ /* Don't allow a single read to cross a 512-byte block boundary */
-+ if (from + len > ((from | 0x1ff) + 1))
-+ len = ((from | 0x1ff) + 1) - from;
-+
-+ DoC_CheckASIC(docptr);
-+
-+ /* Find the chip which is to be used and select it */
-+ if (this->curfloor != mychip->floor) {
-+ DoC_SelectFloor(docptr, mychip->floor);
-+ DoC_SelectChip(docptr, mychip->chip);
-+ } else if (this->curchip != mychip->chip) {
-+ DoC_SelectChip(docptr, mychip->chip);
-+ }
-+ this->curfloor = mychip->floor;
-+ this->curchip = mychip->chip;
-+
-+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
-+ WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect);
-+
-+ /* Reset the chip, see Software Requirement 11.4 item 1. */
-+ DoC_Command(docptr, NAND_CMD_RESET, 0);
-+ DoC_WaitReady(docptr);
-+
-+ fofs = from;
-+ DoC_Command(docptr, DoC_GetDataOffset(mtd, &fofs), 0);
-+ DoC_Address(this, 3, fofs, 0, 0x00);
-+ WriteDOC(0, docptr, Mplus_FlashControl);
-+ DoC_WaitReady(docptr);
-+
-+ if (eccbuf) {
-+ /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
-+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-+ WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
-+ } else {
-+ /* disable the ECC engine */
-+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-+ }
-+
-+ /* Let the caller know we completed it */
-+ *retlen = len;
-+ ret = 0;
-+
-+ ReadDOC(docptr, Mplus_ReadPipeInit);
-+ ReadDOC(docptr, Mplus_ReadPipeInit);
-+
-+ if (eccbuf) {
-+ /* Read the data via the internal pipeline through CDSN IO
-+ register, see Pipelined Read Operations 11.3 */
-+ MemReadDOC(docptr, buf, len);
-+
-+ /* Read the ECC data following raw data */
-+ MemReadDOC(docptr, eccbuf, 4);
-+ eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead);
-+ eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead);
-+
-+ /* Flush the pipeline */
-+ dummy = ReadDOC(docptr, Mplus_ECCConf);
-+ dummy = ReadDOC(docptr, Mplus_ECCConf);
-+
-+ /* Check the ECC Status */
-+ if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) {
-+ int nb_errors;
-+ /* There was an ECC error */
-+#ifdef ECC_DEBUG
-+ printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
-+#endif
-+ /* Read the ECC syndrom through the DiskOnChip ECC logic.
-+ These syndrome will be all ZERO when there is no error */
-+ for (i = 0; i < 6; i++)
-+ syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
-+
-+ nb_errors = doc_decode_ecc(buf, syndrome);
-+#ifdef ECC_DEBUG
-+ printk("ECC Errors corrected: %x\n", nb_errors);
-+#endif
-+ if (nb_errors < 0) {
-+ /* We return error, but have actually done the read. Not that
-+ this can be told to user-space, via sys_read(), but at least
-+ MTD-aware stuff can know about it by checking *retlen */
-+#ifdef ECC_DEBUG
-+ printk("%s(%d): Millennium Plus ECC error (from=0x%x:\n",
-+ __FILE__, __LINE__, (int)from);
-+ printk(" syndrome= %02x:%02x:%02x:%02x:%02x:"
-+ "%02x\n",
-+ syndrome[0], syndrome[1], syndrome[2],
-+ syndrome[3], syndrome[4], syndrome[5]);
-+ printk(" eccbuf= %02x:%02x:%02x:%02x:%02x:"
-+ "%02x\n",
-+ eccbuf[0], eccbuf[1], eccbuf[2],
-+ eccbuf[3], eccbuf[4], eccbuf[5]);
-+#endif
-+ ret = -EIO;
-+ }
-+ }
-+
-+#ifdef PSYCHO_DEBUG
-+ printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-+ (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
-+ eccbuf[4], eccbuf[5]);
-+#endif
-+
-+ /* disable the ECC engine */
-+ WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf);
-+ } else {
-+ /* Read the data via the internal pipeline through CDSN IO
-+ register, see Pipelined Read Operations 11.3 */
-+ MemReadDOC(docptr, buf, len-2);
-+ buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead);
-+ buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead);
-+ }
-+
-+ /* Disable flash internally */
-+ WriteDOC(0, docptr, Mplus_FlashSelect);
-+
-+ return ret;
-+}
-+
-+static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t *retlen, const u_char *buf)
-+{
-+ char eccbuf[6];
-+ return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
-+}
-+
-+static int doc_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 i, before, ret = 0;
-+ loff_t fto;
-+ volatile char dummy;
-+ struct DiskOnChip *this = mtd->priv;
-+ void __iomem * docptr = this->virtadr;
-+ struct Nand *mychip = &this->chips[to >> (this->chipshift)];
-+
-+ /* Don't allow write past end of device */
-+ if (to >= this->totlen)
-+ return -EINVAL;
-+
-+ /* Don't allow writes which aren't exactly one block (512 bytes) */
-+ if ((to & 0x1ff) || (len != 0x200))
-+ return -EINVAL;
-+
-+ /* Determine position of OOB flags, before or after data */
-+ before = (this->interleave && (to & 0x200));
-+
-+ DoC_CheckASIC(docptr);
-+
-+ /* Find the chip which is to be used and select it */
-+ if (this->curfloor != mychip->floor) {
-+ DoC_SelectFloor(docptr, mychip->floor);
-+ DoC_SelectChip(docptr, mychip->chip);
-+ } else if (this->curchip != mychip->chip) {
-+ DoC_SelectChip(docptr, mychip->chip);
-+ }
-+ this->curfloor = mychip->floor;
-+ this->curchip = mychip->chip;
-+
-+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
-+ WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect);
-+
-+ /* Reset the chip, see Software Requirement 11.4 item 1. */
-+ DoC_Command(docptr, NAND_CMD_RESET, 0);
-+ DoC_WaitReady(docptr);
-+
-+ /* Set device to appropriate plane of flash */
-+ fto = to;
-+ WriteDOC(DoC_GetDataOffset(mtd, &fto), docptr, Mplus_FlashCmd);
-+
-+ /* On interleaved devices the flags for 2nd half 512 are before data */
-+ if (eccbuf && before)
-+ fto -= 2;
-+
-+ /* issue the Serial Data In command to initial the Page Program process */
-+ DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
-+ DoC_Address(this, 3, fto, 0x00, 0x00);
-+
-+ /* Disable the ECC engine */
-+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-+
-+ if (eccbuf) {
-+ if (before) {
-+ /* Write the block status BLOCK_USED (0x5555) */
-+ WriteDOC(0x55, docptr, Mil_CDSN_IO);
-+ WriteDOC(0x55, docptr, Mil_CDSN_IO);
-+ }
-+
-+ /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
-+ WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
-+ }
-+
-+ MemWriteDOC(docptr, (unsigned char *) buf, len);
-+
-+ if (eccbuf) {
-+ /* Write ECC data to flash, the ECC info is generated by
-+ the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */
-+ DoC_Delay(docptr, 3);
-+
-+ /* Read the ECC data through the DiskOnChip ECC logic */
-+ for (i = 0; i < 6; i++)
-+ eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
-+
-+ /* disable the ECC engine */
-+ WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
-+
-+ /* Write the ECC data to flash */
-+ MemWriteDOC(docptr, eccbuf, 6);
-+
-+ if (!before) {
-+ /* Write the block status BLOCK_USED (0x5555) */
-+ WriteDOC(0x55, docptr, Mil_CDSN_IO+6);
-+ WriteDOC(0x55, docptr, Mil_CDSN_IO+7);
-+ }
-+
-+#ifdef PSYCHO_DEBUG
-+ printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-+ (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
-+ eccbuf[4], eccbuf[5]);
-+#endif
-+ }
-+
-+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
-+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
-+
-+ /* Commit the Page Program command and wait for ready
-+ see Software Requirement 11.4 item 1.*/
-+ DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00);
-+ DoC_WaitReady(docptr);
-+
-+ /* Read the status of the flash device through CDSN IO register
-+ see Software Requirement 11.4 item 5.*/
-+ DoC_Command(docptr, NAND_CMD_STATUS, 0);
-+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
-+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
-+ DoC_Delay(docptr, 2);
-+ if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) {
-+ printk("MTD: Error 0x%x programming at 0x%x\n", dummy, (int)to);
-+ /* Error in programming
-+ FIXME: implement Bad Block Replacement (in nftl.c ??) */
-+ *retlen = 0;
-+ ret = -EIO;
-+ }
-+ dummy = ReadDOC(docptr, Mplus_LastDataRead);
-+
-+ /* Disable flash internally */
-+ WriteDOC(0, docptr, Mplus_FlashSelect);
-+
-+ /* Let the caller know we completed it */
-+ *retlen = len;
-+
-+ return ret;
-+}
-+
-+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
-+ size_t *retlen, u_char *buf)
-+{
-+ loff_t fofs, base;
-+ struct DiskOnChip *this = mtd->priv;
-+ void __iomem * docptr = this->virtadr;
-+ struct Nand *mychip = &this->chips[ofs >> this->chipshift];
-+ size_t i, size, got, want;
-+
-+ DoC_CheckASIC(docptr);
-+
-+ /* Find the chip which is to be used and select it */
-+ if (this->curfloor != mychip->floor) {
-+ DoC_SelectFloor(docptr, mychip->floor);
-+ DoC_SelectChip(docptr, mychip->chip);
-+ } else if (this->curchip != mychip->chip) {
-+ DoC_SelectChip(docptr, mychip->chip);
-+ }
-+ this->curfloor = mychip->floor;
-+ this->curchip = mychip->chip;
-+
-+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
-+ WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect);
-+
-+ /* disable the ECC engine */
-+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-+ DoC_WaitReady(docptr);
-+
-+ /* Maximum of 16 bytes in the OOB region, so limit read to that */
-+ if (len > 16)
-+ len = 16;
-+ got = 0;
-+ want = len;
-+
-+ for (i = 0; ((i < 3) && (want > 0)); i++) {
-+ /* Figure out which region we are accessing... */
-+ fofs = ofs;
-+ base = ofs & 0xf;
-+ if (!this->interleave) {
-+ DoC_Command(docptr, NAND_CMD_READOOB, 0);
-+ size = 16 - base;
-+ } else if (base < 6) {
-+ DoC_Command(docptr, DoC_GetECCOffset(mtd, &fofs), 0);
-+ size = 6 - base;
-+ } else if (base < 8) {
-+ DoC_Command(docptr, DoC_GetFlagsOffset(mtd, &fofs), 0);
-+ size = 8 - base;
-+ } else {
-+ DoC_Command(docptr, DoC_GetHdrOffset(mtd, &fofs), 0);
-+ size = 16 - base;
-+ }
-+ if (size > want)
-+ size = want;
-+
-+ /* Issue read command */
-+ DoC_Address(this, 3, fofs, 0, 0x00);
-+ WriteDOC(0, docptr, Mplus_FlashControl);
-+ DoC_WaitReady(docptr);
-+
-+ ReadDOC(docptr, Mplus_ReadPipeInit);
-+ ReadDOC(docptr, Mplus_ReadPipeInit);
-+ MemReadDOC(docptr, &buf[got], size - 2);
-+ buf[got + size - 2] = ReadDOC(docptr, Mplus_LastDataRead);
-+ buf[got + size - 1] = ReadDOC(docptr, Mplus_LastDataRead);
-+
-+ ofs += size;
-+ got += size;
-+ want -= size;
-+ }
-+
-+ /* Disable flash internally */
-+ WriteDOC(0, docptr, Mplus_FlashSelect);
-+
-+ *retlen = len;
-+ return 0;
-+}
-+
-+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
-+ size_t *retlen, const u_char *buf)
-+{
-+ volatile char dummy;
-+ loff_t fofs, base;
-+ struct DiskOnChip *this = mtd->priv;
-+ void __iomem * docptr = this->virtadr;
-+ struct Nand *mychip = &this->chips[ofs >> this->chipshift];
-+ size_t i, size, got, want;
-+ int ret = 0;
-+
-+ DoC_CheckASIC(docptr);
-+
-+ /* Find the chip which is to be used and select it */
-+ if (this->curfloor != mychip->floor) {
-+ DoC_SelectFloor(docptr, mychip->floor);
-+ DoC_SelectChip(docptr, mychip->chip);
-+ } else if (this->curchip != mychip->chip) {
-+ DoC_SelectChip(docptr, mychip->chip);
-+ }
-+ this->curfloor = mychip->floor;
-+ this->curchip = mychip->chip;
-+
-+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
-+ WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect);
-+
-+
-+ /* Maximum of 16 bytes in the OOB region, so limit write to that */
-+ if (len > 16)
-+ len = 16;
-+ got = 0;
-+ want = len;
-+
-+ for (i = 0; ((i < 3) && (want > 0)); i++) {
-+ /* Reset the chip, see Software Requirement 11.4 item 1. */
-+ DoC_Command(docptr, NAND_CMD_RESET, 0);
-+ DoC_WaitReady(docptr);
-+
-+ /* Figure out which region we are accessing... */
-+ fofs = ofs;
-+ base = ofs & 0x0f;
-+ if (!this->interleave) {
-+ WriteDOC(NAND_CMD_READOOB, docptr, Mplus_FlashCmd);
-+ size = 16 - base;
-+ } else if (base < 6) {
-+ WriteDOC(DoC_GetECCOffset(mtd, &fofs), docptr, Mplus_FlashCmd);
-+ size = 6 - base;
-+ } else if (base < 8) {
-+ WriteDOC(DoC_GetFlagsOffset(mtd, &fofs), docptr, Mplus_FlashCmd);
-+ size = 8 - base;
-+ } else {
-+ WriteDOC(DoC_GetHdrOffset(mtd, &fofs), docptr, Mplus_FlashCmd);
-+ size = 16 - base;
-+ }
-+ if (size > want)
-+ size = want;
-+
-+ /* Issue the Serial Data In command to initial the Page Program process */
-+ DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
-+ DoC_Address(this, 3, fofs, 0, 0x00);
-+
-+ /* Disable the ECC engine */
-+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-+
-+ /* Write the data via the internal pipeline through CDSN IO
-+ register, see Pipelined Write Operations 11.2 */
-+ MemWriteDOC(docptr, (unsigned char *) &buf[got], size);
-+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
-+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
-+
-+ /* Commit the Page Program command and wait for ready
-+ see Software Requirement 11.4 item 1.*/
-+ DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00);
-+ DoC_WaitReady(docptr);
-+
-+ /* Read the status of the flash device through CDSN IO register
-+ see Software Requirement 11.4 item 5.*/
-+ DoC_Command(docptr, NAND_CMD_STATUS, 0x00);
-+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
-+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
-+ DoC_Delay(docptr, 2);
-+ if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) {
-+ printk("MTD: Error 0x%x programming oob at 0x%x\n",
-+ dummy, (int)ofs);
-+ /* FIXME: implement Bad Block Replacement */
-+ *retlen = 0;
-+ ret = -EIO;
-+ }
-+ dummy = ReadDOC(docptr, Mplus_LastDataRead);
-+
-+ ofs += size;
-+ got += size;
-+ want -= size;
-+ }
-+
-+ /* Disable flash internally */
-+ WriteDOC(0, docptr, Mplus_FlashSelect);
-+
-+ *retlen = len;
-+ return ret;
-+}
-+
-+int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
-+{
-+ volatile char dummy;
-+ struct DiskOnChip *this = mtd->priv;
-+ __u32 ofs = instr->addr;
-+ __u32 len = instr->len;
-+ void __iomem * docptr = this->virtadr;
-+ struct Nand *mychip = &this->chips[ofs >> this->chipshift];
-+
-+ DoC_CheckASIC(docptr);
-+
-+ if (len != mtd->erasesize)
-+ printk(KERN_WARNING "MTD: Erase not right size (%x != %x)n",
-+ len, mtd->erasesize);
-+
-+ /* Find the chip which is to be used and select it */
-+ if (this->curfloor != mychip->floor) {
-+ DoC_SelectFloor(docptr, mychip->floor);
-+ DoC_SelectChip(docptr, mychip->chip);
-+ } else if (this->curchip != mychip->chip) {
-+ DoC_SelectChip(docptr, mychip->chip);
-+ }
-+ this->curfloor = mychip->floor;
-+ this->curchip = mychip->chip;
-+
-+ instr->state = MTD_ERASE_PENDING;
-+
-+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
-+ WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect);
-+
-+ DoC_Command(docptr, NAND_CMD_RESET, 0x00);
-+ DoC_WaitReady(docptr);
-+
-+ DoC_Command(docptr, NAND_CMD_ERASE1, 0);
-+ DoC_Address(this, 2, ofs, 0, 0x00);
-+ DoC_Command(docptr, NAND_CMD_ERASE2, 0);
-+ DoC_WaitReady(docptr);
-+ instr->state = MTD_ERASING;
-+
-+ /* Read the status of the flash device through CDSN IO register
-+ see Software Requirement 11.4 item 5. */
-+ DoC_Command(docptr, NAND_CMD_STATUS, 0);
-+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
-+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
-+ if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) {
-+ printk("MTD: Error 0x%x erasing at 0x%x\n", dummy, ofs);
-+ /* FIXME: implement Bad Block Replacement (in nftl.c ??) */
-+ instr->state = MTD_ERASE_FAILED;
-+ } else {
-+ instr->state = MTD_ERASE_DONE;
-+ }
-+ dummy = ReadDOC(docptr, Mplus_LastDataRead);
-+
-+ /* Disable flash internally */
-+ WriteDOC(0, docptr, Mplus_FlashSelect);
-+
-+ mtd_erase_callback(instr);
-+
-+ return 0;
-+}
-+
-+/****************************************************************************
-+ *
-+ * Module stuff
-+ *
-+ ****************************************************************************/
-+
-+static int __init init_doc2001plus(void)
-+{
-+ inter_module_register(im_name, THIS_MODULE, &DoCMilPlus_init);
-+ return 0;
-+}
-+
-+static void __exit cleanup_doc2001plus(void)
-+{
-+ struct mtd_info *mtd;
-+ struct DiskOnChip *this;
-+
-+ while ((mtd=docmilpluslist)) {
-+ this = mtd->priv;
-+ docmilpluslist = this->nextdoc;
-+
-+ del_mtd_device(mtd);
-+
-+ iounmap(this->virtadr);
-+ kfree(this->chips);
-+ kfree(mtd);
-+ }
-+ inter_module_unregister(im_name);
-+}
-+
-+module_exit(cleanup_doc2001plus);
-+module_init(init_doc2001plus);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com> et al.");
-+MODULE_DESCRIPTION("Driver for DiskOnChip Millennium Plus");
---- linux-2.4.21/drivers/mtd/devices/docecc.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/devices/docecc.c
-@@ -7,7 +7,7 @@
- * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
- * Copyright (C) 2000 Netgem S.A.
- *
-- * $Id: docecc.c,v 1.4 2001/10/02 15:05:13 dwmw2 Exp $
-+ * $Id: docecc.c,v 1.5 2003/05/21 15:15:06 dwmw2 Exp $
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
-@@ -519,6 +519,8 @@
- return nb_errors;
- }
-
-+EXPORT_SYMBOL_GPL(doc_decode_ecc);
-+
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Fabrice Bellard <fabrice.bellard@netgem.com>");
- MODULE_DESCRIPTION("ECC code for correcting errors detected by DiskOnChip 2000 and Millennium ECC hardware");
---- linux-2.4.21/drivers/mtd/devices/docprobe.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/devices/docprobe.c
-@@ -4,7 +4,7 @@
- /* (C) 1999 Machine Vision Holdings, Inc. */
- /* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> */
-
--/* $Id: docprobe.c,v 1.33 2003/01/24 14:02:47 dwmw2 Exp $ */
-+/* $Id: docprobe.c,v 1.44 2005/01/05 12:40:36 dwmw2 Exp $ */
-
-
-
-@@ -31,14 +31,12 @@
- /* DOC_SINGLE_DRIVER:
- Millennium driver has been merged into DOC2000 driver.
-
-- The newly-merged driver doesn't appear to work for writing. It's the
-- same with the DiskOnChip 2000 and the Millennium. If you have a
-- Millennium and you want write support to work, remove the definition
-- of DOC_SINGLE_DRIVER below to use the old doc2001-specific driver.
--
-- Otherwise, it's left on in the hope that it'll annoy someone with
-- a Millennium enough that they go through and work out what the
-- difference is :)
-+ The old Millennium-only driver has been retained just in case there
-+ are problems with the new code. If the combined driver doesn't work
-+ for you, you can try the old one by undefining DOC_SINGLE_DRIVER
-+ below and also enabling it in your configuration. If this fixes the
-+ problems, please send a report to the MTD mailing list at
-+ <linux-mtd@lists.infradead.org>.
- */
- #define DOC_SINGLE_DRIVER
-
-@@ -47,18 +45,15 @@
- #include <linux/module.h>
- #include <asm/errno.h>
- #include <asm/io.h>
--#include <asm/uaccess.h>
--#include <linux/miscdevice.h>
--#include <linux/pci.h>
- #include <linux/delay.h>
- #include <linux/slab.h>
--#include <linux/sched.h>
- #include <linux/init.h>
- #include <linux/types.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
- #include <linux/mtd/doc2000.h>
-+#include <linux/mtd/compatmac.h>
-
- /* Where to look for the devices? */
- #ifndef CONFIG_MTD_DOCPROBE_ADDRESS
-@@ -95,14 +90,14 @@
- ##else
- #warning Unknown architecture for DiskOnChip. No default probe locations defined
- #endif
-- 0 };
-+ 0xffffffff };
-
- /* doccheck: Probe a given memory window to see if there's a DiskOnChip present */
-
--static inline int __init doccheck(unsigned long potential, unsigned long physadr)
-+static inline int __init doccheck(void __iomem *potential, unsigned long physadr)
- {
-- unsigned long window=potential;
-- unsigned char tmp, ChipID;
-+ void __iomem *window=potential;
-+ unsigned char tmp, tmpb, tmpc, ChipID;
- #ifndef DOC_PASSIVE_PROBE
- unsigned char tmp2;
- #endif
-@@ -140,26 +135,80 @@
- window, DOCControl);
- #endif /* !DOC_PASSIVE_PROBE */
-
-+ /* We need to read the ChipID register four times. For some
-+ newer DiskOnChip 2000 units, the first three reads will
-+ return the DiskOnChip Millennium ident. Don't ask. */
- ChipID = ReadDOC(window, ChipID);
-
- switch (ChipID) {
- case DOC_ChipID_Doc2k:
- /* Check the TOGGLE bit in the ECC register */
- tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
-- if ((ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT) != tmp)
-+ tmpb = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
-+ tmpc = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
-+ if (tmp != tmpb && tmp == tmpc)
- return ChipID;
- break;
-
- case DOC_ChipID_DocMil:
-+ /* Check for the new 2000 with Millennium ASIC */
-+ ReadDOC(window, ChipID);
-+ ReadDOC(window, ChipID);
-+ if (ReadDOC(window, ChipID) != DOC_ChipID_DocMil)
-+ ChipID = DOC_ChipID_Doc2kTSOP;
-+
- /* Check the TOGGLE bit in the ECC register */
- tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
-- if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp)
-+ tmpb = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
-+ tmpc = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
-+ if (tmp != tmpb && tmp == tmpc)
- return ChipID;
- break;
-
-+ case DOC_ChipID_DocMilPlus16:
-+ case DOC_ChipID_DocMilPlus32:
-+ case 0:
-+ /* Possible Millennium+, need to do more checks */
-+#ifndef DOC_PASSIVE_PROBE
-+ /* Possibly release from power down mode */
-+ for (tmp = 0; (tmp < 4); tmp++)
-+ ReadDOC(window, Mplus_Power);
-+
-+ /* Reset the DiskOnChip ASIC */
-+ tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
-+ DOC_MODE_BDECT;
-+ WriteDOC(tmp, window, Mplus_DOCControl);
-+ WriteDOC(~tmp, window, Mplus_CtrlConfirm);
-+
-+ mdelay(1);
-+ /* Enable the DiskOnChip ASIC */
-+ tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
-+ DOC_MODE_BDECT;
-+ WriteDOC(tmp, window, Mplus_DOCControl);
-+ WriteDOC(~tmp, window, Mplus_CtrlConfirm);
-+ mdelay(1);
-+#endif /* !DOC_PASSIVE_PROBE */
-+
-+ ChipID = ReadDOC(window, ChipID);
-+
-+ switch (ChipID) {
-+ case DOC_ChipID_DocMilPlus16:
-+ case DOC_ChipID_DocMilPlus32:
-+ /* Check the TOGGLE bit in the toggle register */
-+ tmp = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
-+ tmpb = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
-+ tmpc = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
-+ if (tmp != tmpb && tmp == tmpc)
-+ return ChipID;
- default:
--#ifndef CONFIG_MTD_DOCPROBE_55AA
-- printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
-+ break;
-+ }
-+ /* FALL TRHU */
-+
-+ default:
-+
-+#ifdef CONFIG_MTD_DOCPROBE_55AA
-+ printk(KERN_DEBUG "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
- ChipID, physadr);
- #endif
- #ifndef DOC_PASSIVE_PROBE
-@@ -184,7 +233,7 @@
-
- static void __init DoC_Probe(unsigned long physadr)
- {
-- unsigned long docptr;
-+ void __iomem *docptr;
- struct DiskOnChip *this;
- struct mtd_info *mtd;
- int ChipID;
-@@ -194,18 +243,24 @@
- char *im_modname = NULL;
- void (*initroutine)(struct mtd_info *) = NULL;
-
-- docptr = (unsigned long)ioremap(physadr, DOC_IOREMAP_LEN);
-+ docptr = ioremap(physadr, DOC_IOREMAP_LEN);
-
- if (!docptr)
- return;
-
- if ((ChipID = doccheck(docptr, physadr))) {
-+ if (ChipID == DOC_ChipID_Doc2kTSOP) {
-+ /* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */
-+ printk(KERN_NOTICE "Refusing to drive DiskOnChip 2000 TSOP until Bad Block Table is correctly supported by INFTL\n");
-+ iounmap(docptr);
-+ return;
-+ }
- docfound = 1;
- mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL);
-
- if (!mtd) {
- printk(KERN_WARNING "Cannot allocate memory for data structures. Dropping.\n");
-- iounmap((void *)docptr);
-+ iounmap(docptr);
- return;
- }
-
-@@ -221,6 +276,12 @@
- sprintf(namebuf, "with ChipID %2.2X", ChipID);
-
- switch(ChipID) {
-+ case DOC_ChipID_Doc2kTSOP:
-+ name="2000 TSOP";
-+ im_funcname = "DoC2k_init";
-+ im_modname = "doc2000";
-+ break;
-+
- case DOC_ChipID_Doc2k:
- name="2000";
- im_funcname = "DoC2k_init";
-@@ -237,6 +298,13 @@
- im_modname = "doc2001";
- #endif /* DOC_SINGLE_DRIVER */
- break;
-+
-+ case DOC_ChipID_DocMilPlus16:
-+ case DOC_ChipID_DocMilPlus32:
-+ name="MillenniumPlus";
-+ im_funcname = "DoCMilPlus_init";
-+ im_modname = "doc2001plus";
-+ break;
- }
-
- if (im_funcname)
-@@ -248,8 +316,9 @@
- return;
- }
- printk(KERN_NOTICE "Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr);
-+ kfree(mtd);
- }
-- iounmap((void *)docptr);
-+ iounmap(docptr);
- }
-
-
-@@ -259,7 +328,7 @@
- *
- ****************************************************************************/
-
--int __init init_doc(void)
-+static int __init init_doc(void)
- {
- int i;
-
-@@ -267,7 +336,7 @@
- printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
- DoC_Probe(doc_config_location);
- } else {
-- for (i=0; doc_locations[i]; i++) {
-+ for (i=0; (doc_locations[i] != 0xffffffff); i++) {
- DoC_Probe(doc_locations[i]);
- }
- }
-@@ -275,11 +344,7 @@
- found, so the user knows we at least tried. */
- if (!docfound)
- printk(KERN_INFO "No recognised DiskOnChip devices found\n");
-- /* So it looks like we've been used and we get unloaded */
-- MOD_INC_USE_COUNT;
-- MOD_DEC_USE_COUNT;
-- return 0;
--
-+ return -EAGAIN;
- }
-
- module_init(init_doc);
---- linux-2.4.21/drivers/mtd/devices/lart.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/devices/lart.c
-@@ -2,7 +2,7 @@
- /*
- * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART.
- *
-- * $Id: lart.c,v 1.2 2001/10/02 15:05:13 dwmw2 Exp $
-+ * $Id: lart.c,v 1.7 2004/08/09 13:19:44 dwmw2 Exp $
- *
- * Author: Abraham vd Merwe <abraham@2d3d.co.za>
- *
-@@ -42,7 +42,7 @@
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/types.h>
--#include <linux/version.h>
-+#include <linux/init.h>
- #include <linux/errno.h>
- #include <linux/mtd/mtd.h>
- #ifdef HAVE_PARTITIONS
-@@ -433,7 +433,7 @@
- }
-
- instr->state = MTD_ERASE_DONE;
-- if (instr->callback) instr->callback (instr);
-+ mtd_erase_callback(instr);
-
- return (0);
- }
-@@ -584,45 +584,40 @@
-
- static struct mtd_info mtd;
-
--static struct mtd_erase_region_info erase_regions[] =
--{
-+static struct mtd_erase_region_info erase_regions[] = {
- /* parameter blocks */
- {
-- offset: 0x00000000,
-- erasesize: FLASH_BLOCKSIZE_PARAM,
-- numblocks: FLASH_NUMBLOCKS_16m_PARAM
-+ .offset = 0x00000000,
-+ .erasesize = FLASH_BLOCKSIZE_PARAM,
-+ .numblocks = FLASH_NUMBLOCKS_16m_PARAM,
- },
- /* main blocks */
- {
-- offset: FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM,
-- erasesize: FLASH_BLOCKSIZE_MAIN,
-- numblocks: FLASH_NUMBLOCKS_16m_MAIN
-+ .offset = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM,
-+ .erasesize = FLASH_BLOCKSIZE_MAIN,
-+ .numblocks = FLASH_NUMBLOCKS_16m_MAIN,
- }
- };
-
- #ifdef HAVE_PARTITIONS
--static struct mtd_partition lart_partitions[] =
--{
-+static struct mtd_partition lart_partitions[] = {
- /* blob */
- {
-- name: "blob",
-- offset: BLOB_START,
-- size: BLOB_LEN,
-- mask_flags: 0
-+ .name = "blob",
-+ .offset = BLOB_START,
-+ .size = BLOB_LEN,
- },
- /* kernel */
- {
-- name: "kernel",
-- offset: KERNEL_START, /* MTDPART_OFS_APPEND */
-- size: KERNEL_LEN,
-- mask_flags: 0
-+ .name = "kernel",
-+ .offset = KERNEL_START, /* MTDPART_OFS_APPEND */
-+ .size = KERNEL_LEN,
- },
- /* initial ramdisk / file system */
- {
-- name: "file system",
-- offset: INITRD_START, /* MTDPART_OFS_APPEND */
-- size: INITRD_LEN, /* MTDPART_SIZ_FULL */
-- mask_flags: 0
-+ .name = "file system",
-+ .offset = INITRD_START, /* MTDPART_OFS_APPEND */
-+ .size = INITRD_LEN, /* MTDPART_SIZ_FULL */
- }
- };
- #endif
-@@ -646,10 +641,10 @@
- mtd.erasesize = FLASH_BLOCKSIZE_MAIN;
- mtd.numeraseregions = NB_OF (erase_regions);
- mtd.eraseregions = erase_regions;
-- mtd.module = THIS_MODULE;
- mtd.erase = flash_erase;
- mtd.read = flash_read;
- mtd.write = flash_write;
-+ mtd.owner = THIS_MODULE;
-
- #ifdef LART_DEBUG
- printk (KERN_DEBUG
---- linux-2.4.21/drivers/mtd/devices/ms02-nv.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/devices/ms02-nv.c
-@@ -6,7 +6,7 @@
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
-- * $Id: ms02-nv.c,v 1.2 2003/01/24 14:05:17 dwmw2 Exp $
-+ * $Id: ms02-nv.c,v 1.8 2005/01/05 18:05:12 dwmw2 Exp $
- */
-
- #include <linux/init.h>
-@@ -31,16 +31,16 @@
- static char version[] __initdata =
- "ms02-nv.c: v.1.0.0 13 Aug 2001 Maciej W. Rozycki.\n";
-
--MODULE_AUTHOR("Maciej W. Rozycki <macro@ds2.pg.gda.pl>");
-+MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
- MODULE_DESCRIPTION("DEC MS02-NV NVRAM module driver");
- MODULE_LICENSE("GPL");
-
-
- /*
- * Addresses we probe for an MS02-NV at. Modules may be located
-- * at any 8MB boundary within a 0MB up to 112MB range or at any 32MB
-- * boundary within a 0MB up to 448MB range. We don't support a module
-- * at 0MB, though.
-+ * at any 8MiB boundary within a 0MiB up to 112MiB range or at any 32MiB
-+ * boundary within a 0MiB up to 448MiB range. We don't support a module
-+ * at 0MiB, though.
- */
- static ulong ms02nv_addrs[] __initdata = {
- 0x07000000, 0x06800000, 0x06000000, 0x05800000, 0x05000000,
-@@ -59,7 +59,7 @@
- static int ms02nv_read(struct mtd_info *mtd, loff_t from,
- size_t len, size_t *retlen, u_char *buf)
- {
-- struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv;
-+ struct ms02nv_private *mp = mtd->priv;
-
- if (from + len > mtd->size)
- return -EINVAL;
-@@ -73,7 +73,7 @@
- static int ms02nv_write(struct mtd_info *mtd, loff_t to,
- size_t len, size_t *retlen, const u_char *buf)
- {
-- struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv;
-+ struct ms02nv_private *mp = mtd->priv;
-
- if (to + len > mtd->size)
- return -EINVAL;
-@@ -130,7 +130,7 @@
-
- int ret = -ENODEV;
-
-- /* The module decodes 8MB of address space. */
-+ /* The module decodes 8MiB of address space. */
- mod_res = kmalloc(sizeof(*mod_res), GFP_KERNEL);
- if (!mod_res)
- return -ENOMEM;
-@@ -222,7 +222,7 @@
- mtd->flags = MTD_CAP_RAM | MTD_XIP;
- mtd->size = fixsize;
- mtd->name = (char *)ms02nv_name;
-- mtd->module = THIS_MODULE;
-+ mtd->owner = THIS_MODULE;
- mtd->read = ms02nv_read;
- mtd->write = ms02nv_write;
-
-@@ -233,7 +233,7 @@
- goto err_out_csr_res;
- }
-
-- printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMB.\n",
-+ printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMiB.\n",
- mtd->index, ms02nv_name, addr, size >> 20);
-
- mp->next = root_ms02nv_mtd;
-@@ -265,7 +265,7 @@
- static void __exit ms02nv_remove_one(void)
- {
- struct mtd_info *mtd = root_ms02nv_mtd;
-- struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv;
-+ struct ms02nv_private *mp = mtd->priv;
-
- root_ms02nv_mtd = mp->next;
-
-@@ -293,12 +293,12 @@
-
- switch (mips_machtype) {
- case MACH_DS5000_200:
-- csr = (volatile u32 *)KN02_CSR_ADDR;
-+ csr = (volatile u32 *)KN02_CSR_BASE;
- if (*csr & KN02_CSR_BNK32M)
- stride = 2;
- break;
- case MACH_DS5000_2X0:
-- case MACH_DS5000:
-+ case MACH_DS5900:
- csr = (volatile u32 *)KN03_MCR_BASE;
- if (*csr & KN03_MCR_BNK32M)
- stride = 2;
---- linux-2.4.21/drivers/mtd/devices/ms02-nv.h~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/devices/ms02-nv.h
-@@ -1,32 +1,96 @@
- /*
-- * Copyright (c) 2001 Maciej W. Rozycki
-+ * Copyright (c) 2001, 2003 Maciej W. Rozycki
-+ *
-+ * DEC MS02-NV (54-20948-01) battery backed-up NVRAM module for
-+ * DECstation/DECsystem 5000/2x0 and DECsystem 5900 and 5900/260
-+ * systems.
- *
- * This program is free software; 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.
-+ *
-+ * $Id: ms02-nv.h,v 1.3 2003/08/19 09:25:36 dwmw2 Exp $
- */
-
- #include <linux/ioport.h>
- #include <linux/mtd/mtd.h>
-
-+/*
-+ * Addresses are decoded as follows:
-+ *
-+ * 0x000000 - 0x3fffff SRAM
-+ * 0x400000 - 0x7fffff CSR
-+ *
-+ * Within the SRAM area the following ranges are forced by the system
-+ * firmware:
-+ *
-+ * 0x000000 - 0x0003ff diagnostic area, destroyed upon a reboot
-+ * 0x000400 - ENDofRAM storage area, available to operating systems
-+ *
-+ * but we can't really use the available area right from 0x000400 as
-+ * the first word is used by the firmware as a status flag passed
-+ * from an operating system. If anything but the valid data magic
-+ * ID value is found, the firmware considers the SRAM clean, i.e.
-+ * containing no valid data, and disables the battery resulting in
-+ * data being erased as soon as power is switched off. So the choice
-+ * for the start address of the user-available is 0x001000 which is
-+ * nicely page aligned. The area between 0x000404 and 0x000fff may
-+ * be used by the driver for own needs.
-+ *
-+ * The diagnostic area defines two status words to be read by an
-+ * operating system, a magic ID to distinguish a MS02-NV board from
-+ * anything else and a status information providing results of tests
-+ * as well as the size of SRAM available, which can be 1MiB or 2MiB
-+ * (that's what the firmware handles; no idea if 2MiB modules ever
-+ * existed).
-+ *
-+ * The firmware only handles the MS02-NV board if installed in the
-+ * last (15th) slot, so for any other location the status information
-+ * stored in the SRAM cannot be relied upon. But from the hardware
-+ * point of view there is no problem using up to 14 such boards in a
-+ * system -- only the 1st slot needs to be filled with a DRAM module.
-+ * The MS02-NV board is ECC-protected, like other MS02 memory boards.
-+ *
-+ * The state of the battery as provided by the CSR is reflected on
-+ * the two onboard LEDs. When facing the battery side of the board,
-+ * with the LEDs at the top left and the battery at the bottom right
-+ * (i.e. looking from the back side of the system box), their meaning
-+ * is as follows (the system has to be powered on):
-+ *
-+ * left LED battery disable status: lit = enabled
-+ * right LED battery condition status: lit = OK
-+ */
-+
- /* MS02-NV iomem register offsets. */
- #define MS02NV_CSR 0x400000 /* control & status register */
-
-+/* MS02-NV CSR status bits. */
-+#define MS02NV_CSR_BATT_OK 0x01 /* battery OK */
-+#define MS02NV_CSR_BATT_OFF 0x02 /* battery disabled */
-+
-+
- /* MS02-NV memory offsets. */
- #define MS02NV_DIAG 0x0003f8 /* diagnostic status */
- #define MS02NV_MAGIC 0x0003fc /* MS02-NV magic ID */
--#define MS02NV_RAM 0x000400 /* general-purpose RAM start */
-+#define MS02NV_VALID 0x000400 /* valid data magic ID */
-+#define MS02NV_RAM 0x001000 /* user-exposed RAM start */
-
--/* MS02-NV diagnostic status constants. */
--#define MS02NV_DIAG_SIZE_MASK 0xf0 /* RAM size mask */
--#define MS02NV_DIAG_SIZE_SHIFT 0x10 /* RAM size shift (left) */
-+/* MS02-NV diagnostic status bits. */
-+#define MS02NV_DIAG_TEST 0x01 /* SRAM test done (?) */
-+#define MS02NV_DIAG_RO 0x02 /* SRAM r/o test done */
-+#define MS02NV_DIAG_RW 0x04 /* SRAM r/w test done */
-+#define MS02NV_DIAG_FAIL 0x08 /* SRAM test failed */
-+#define MS02NV_DIAG_SIZE_MASK 0xf0 /* SRAM size mask */
-+#define MS02NV_DIAG_SIZE_SHIFT 0x10 /* SRAM size shift (left) */
-
- /* MS02-NV general constants. */
- #define MS02NV_ID 0x03021966 /* MS02-NV magic ID value */
-+#define MS02NV_VALID_ID 0xbd100248 /* valid data magic ID value */
- #define MS02NV_SLOT_SIZE 0x800000 /* size of the address space
- decoded by the module */
-
-+
- typedef volatile u32 ms02nv_uint;
-
- struct ms02nv_private {
---- linux-2.4.21/drivers/mtd/devices/mtdram.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/devices/mtdram.c
-@@ -1,6 +1,6 @@
- /*
- * mtdram - a test mtd device
-- * $Id: mtdram.c,v 1.29 2002/10/21 13:40:06 jocke Exp $
-+ * $Id: mtdram.c,v 1.35 2005/01/05 18:05:12 dwmw2 Exp $
- * Author: Alexander Larsson <alex@cendio.se>
- *
- * Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
-@@ -13,6 +13,8 @@
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <linux/ioport.h>
-+#include <linux/vmalloc.h>
-+#include <linux/init.h>
- #include <linux/mtd/compatmac.h>
- #include <linux/mtd/mtd.h>
-
-@@ -55,9 +57,8 @@
- memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
-
- instr->state = MTD_ERASE_DONE;
-+ mtd_erase_callback(instr);
-
-- if (instr->callback)
-- (*(instr->callback))(instr);
- return 0;
- }
-
-@@ -136,7 +137,7 @@
- mtd->erasesize = MTDRAM_ERASE_SIZE;
- mtd->priv = mapped_address;
-
-- mtd->module = THIS_MODULE;
-+ mtd->owner = THIS_MODULE;
- mtd->erase = ram_erase;
- mtd->point = ram_point;
- mtd->unpoint = ram_unpoint;
-@@ -152,12 +153,12 @@
-
- #if CONFIG_MTDRAM_TOTAL_SIZE > 0
- #if CONFIG_MTDRAM_ABS_POS > 0
--int __init init_mtdram(void)
-+static int __init init_mtdram(void)
- {
- void *addr;
- int err;
- /* Allocate some memory */
-- mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-+ mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
- if (!mtd_info)
- return -ENOMEM;
-
-@@ -185,12 +186,12 @@
-
- #else /* CONFIG_MTDRAM_ABS_POS > 0 */
-
--int __init init_mtdram(void)
-+static int __init init_mtdram(void)
- {
- void *addr;
- int err;
- /* Allocate some memory */
-- mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-+ mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
- if (!mtd_info)
- return -ENOMEM;
-
-@@ -219,7 +220,7 @@
-
- #else /* CONFIG_MTDRAM_TOTAL_SIZE > 0 */
-
--int __init init_mtdram(void)
-+static int __init init_mtdram(void)
- {
- return 0;
- }
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/devices/phram.c
-@@ -0,0 +1,299 @@
-+/**
-+ * $Id: phram.c,v 1.14 2005/03/07 21:43:38 joern Exp $
-+ *
-+ * Copyright (c) ???? Jochen Schäuble <psionic@psionic.de>
-+ * Copyright (c) 2003-2004 Jörn Engel <joern@wh.fh-wedel.de>
-+ *
-+ * 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 "ki", "Mi" or "Gi", the numbers will be interpreted as kilo, mega or
-+ * gigabytes.
-+ *
-+ * Example:
-+ * phram=swap,64Mi,128Mi phram=test,900Mi,1Mi
-+ */
-+#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 mtd_info mtd;
-+ struct list_head list;
-+};
-+
-+static LIST_HEAD(phram_list);
-+
-+
-+static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
-+{
-+ u_char *start = 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;
-+}
-+
-+static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t *retlen, u_char **mtdbuf)
-+{
-+ u_char *start = mtd->priv;
-+
-+ if (from + len > mtd->size)
-+ return -EINVAL;
-+
-+ *mtdbuf = start + from;
-+ *retlen = len;
-+ return 0;
-+}
-+
-+static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from,
-+ size_t len)
-+{
-+}
-+
-+static int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t *retlen, u_char *buf)
-+{
-+ u_char *start = mtd->priv;
-+
-+ if (from >= mtd->size)
-+ return -EINVAL;
-+
-+ if (len > mtd->size - from)
-+ len = mtd->size - from;
-+
-+ memcpy(buf, start + from, len);
-+
-+ *retlen = len;
-+ return 0;
-+}
-+
-+static int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t *retlen, const u_char *buf)
-+{
-+ u_char *start = mtd->priv;
-+
-+ if (to >= mtd->size)
-+ return -EINVAL;
-+
-+ if (len > mtd->size - to)
-+ len = mtd->size - to;
-+
-+ memcpy(start + to, buf, len);
-+
-+ *retlen = len;
-+ return 0;
-+}
-+
-+
-+
-+static void unregister_devices(void)
-+{
-+ struct phram_mtd_list *this, *safe;
-+
-+ list_for_each_entry_safe(this, safe, &phram_list, list) {
-+ del_mtd_device(&this->mtd);
-+ iounmap(this->mtd.priv);
-+ 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;
-+
-+ memset(new, 0, sizeof(*new));
-+
-+ ret = -EIO;
-+ new->mtd.priv = ioremap(start, len);
-+ if (!new->mtd.priv) {
-+ ERROR("ioremap failed\n");
-+ goto out1;
-+ }
-+
-+
-+ new->mtd.name = name;
-+ new->mtd.size = len;
-+ new->mtd.flags = MTD_CAP_RAM | MTD_ERASEABLE | MTD_VOLATILE;
-+ new->mtd.erase = phram_erase;
-+ new->mtd.point = phram_point;
-+ new->mtd.unpoint = phram_unpoint;
-+ new->mtd.read = phram_read;
-+ new->mtd.write = phram_write;
-+ new->mtd.owner = THIS_MODULE;
-+ new->mtd.type = MTD_RAM;
-+ new->mtd.erasesize = PAGE_SIZE;
-+
-+ ret = -EAGAIN;
-+ if (add_mtd_device(&new->mtd)) {
-+ ERROR("Failed to register new device\n");
-+ goto out2;
-+ }
-+
-+ list_add_tail(&new->list, &phram_list);
-+ return 0;
-+
-+out2:
-+ iounmap(new->mtd.priv);
-+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;
-+ /* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */
-+ if ((*endp)[1] == 'i')
-+ (*endp) += 2;
-+ }
-+ 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;
-+}
-+
-+
-+static inline void kill_final_newline(char *str)
-+{
-+ char *newline = strrchr(str, '\n');
-+ if (newline && !newline[1])
-+ *newline = 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(buf)) >= sizeof(buf))
-+ parse_err("parameter too long\n");
-+
-+ strcpy(str, val);
-+ kill_final_newline(str);
-+
-+ 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>\"");
-+
-+
-+static int __init init_phram(void)
-+{
-+ 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");
---- linux-2.4.21/drivers/mtd/devices/pmc551.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/devices/pmc551.c
-@@ -1,5 +1,5 @@
- /*
-- * $Id: pmc551.c,v 1.22 2003/01/24 13:34:30 dwmw2 Exp $
-+ * $Id: pmc551.c,v 1.30 2005/01/05 18:05:13 dwmw2 Exp $
- *
- * PMC551 PCI Mezzanine Ram Device
- *
-@@ -82,6 +82,7 @@
- * * Comb the init routine. It's still a bit cludgy on a few things.
- */
-
-+#include <linux/version.h>
- #include <linux/config.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
-@@ -108,17 +109,11 @@
- #include <linux/mtd/pmc551.h>
- #include <linux/mtd/compatmac.h>
-
--#if LINUX_VERSION_CODE > 0x20300
--#define PCI_BASE_ADDRESS(dev) (dev->resource[0].start)
--#else
--#define PCI_BASE_ADDRESS(dev) (dev->base_address[0])
--#endif
--
- static struct mtd_info *pmc551list;
-
- static int pmc551_erase (struct mtd_info *mtd, struct erase_info *instr)
- {
-- struct mypriv *priv = (struct mypriv *)mtd->priv;
-+ struct mypriv *priv = mtd->priv;
- u32 soff_hi, soff_lo; /* start address offset hi/lo */
- u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
- unsigned long end;
-@@ -174,16 +169,14 @@
- printk(KERN_DEBUG "pmc551_erase() done\n");
- #endif
-
-- if (instr->callback) {
-- (*(instr->callback))(instr);
-- }
-+ mtd_erase_callback(instr);
- return 0;
- }
-
-
- static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
- {
-- struct mypriv *priv = (struct mypriv *)mtd->priv;
-+ struct mypriv *priv = mtd->priv;
- u32 soff_hi;
- u32 soff_lo;
-
-@@ -224,7 +217,7 @@
-
- static int pmc551_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
- {
-- struct mypriv *priv = (struct mypriv *)mtd->priv;
-+ struct mypriv *priv = mtd->priv;
- u32 soff_hi, soff_lo; /* start address offset hi/lo */
- u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
- unsigned long end;
-@@ -286,7 +279,7 @@
-
- static int pmc551_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
- {
-- struct mypriv *priv = (struct mypriv *)mtd->priv;
-+ struct mypriv *priv = mtd->priv;
- u32 soff_hi, soff_lo; /* start address offset hi/lo */
- u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
- unsigned long end;
-@@ -563,7 +556,7 @@
- (size<1024)?size:(size<1048576)?size>>10:size>>20,
- (size<1024)?'B':(size<1048576)?'K':'M',
- size, ((dcmd&(0x1<<3)) == 0)?"non-":"",
-- PCI_BASE_ADDRESS(dev)&PCI_BASE_ADDRESS_MEM_MASK );
-+ (dev->resource[0].start)&PCI_BASE_ADDRESS_MEM_MASK );
-
- /*
- * Check to see the state of the memory
-@@ -655,7 +648,7 @@
- /*
- * PMC551 Card Initialization
- */
--int __init init_pmc551(void)
-+static int __init init_pmc551(void)
- {
- struct pci_dev *PCI_Device = NULL;
- struct mypriv *priv;
-@@ -681,11 +674,6 @@
-
- printk(KERN_INFO PMC551_VERSION);
-
-- if(!pci_present()) {
-- printk(KERN_NOTICE "pmc551: PCI not enabled.\n");
-- return -ENODEV;
-- }
--
- /*
- * PCU-bus chipset probe.
- */
-@@ -698,7 +686,7 @@
- }
-
- printk(KERN_NOTICE "pmc551: Found PCI V370PDC at 0x%lX\n",
-- PCI_BASE_ADDRESS(PCI_Device));
-+ PCI_Device->resource[0].start);
-
- /*
- * The PMC551 device acts VERY weird if you don't init it
-@@ -752,7 +740,7 @@
- printk(KERN_NOTICE "pmc551: Using specified aperture size %dM\n", asize>>20);
- priv->asize = asize;
- }
-- priv->start = ioremap((PCI_BASE_ADDRESS(PCI_Device)
-+ priv->start = ioremap(((PCI_Device->resource[0].start)
- & PCI_BASE_ADDRESS_MEM_MASK),
- priv->asize);
-
-@@ -787,10 +775,10 @@
- mtd->write = pmc551_write;
- mtd->point = pmc551_point;
- mtd->unpoint = pmc551_unpoint;
-- mtd->module = THIS_MODULE;
- mtd->type = MTD_RAM;
- mtd->name = "PMC551 RAM board";
- mtd->erasesize = 0x10000;
-+ mtd->owner = THIS_MODULE;
-
- if (add_mtd_device(mtd)) {
- printk(KERN_NOTICE "pmc551: Failed to register new device\n");
-@@ -832,7 +820,7 @@
- struct mypriv *priv;
-
- while((mtd=pmc551list)) {
-- priv = (struct mypriv *)mtd->priv;
-+ priv = mtd->priv;
- pmc551list = priv->nextpmc551;
-
- if(priv->start) {
---- linux-2.4.21/drivers/mtd/devices/slram.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/devices/slram.c
-@@ -1,6 +1,6 @@
- /*======================================================================
-
-- $Id: slram.c,v 1.28 2003/01/24 13:35:34 dwmw2 Exp $
-+ $Id: slram.c,v 1.34 2005/01/06 21:16:42 jwboyer Exp $
-
- This driver provides a method to access memory not used by the kernel
- itself (i.e. if the kernel commandline mem=xxx is used). To actually
-@@ -50,6 +50,7 @@
- #include <linux/mtd/mtd.h>
-
- #define SLRAM_MAX_DEVICES_PARAMS 6 /* 3 parameters / device */
-+#define SLRAM_BLK_SZ 0x4000
-
- #define T(fmt, args...) printk(KERN_DEBUG fmt, ## args)
- #define E(fmt, args...) printk(KERN_NOTICE fmt, ## args)
-@@ -75,13 +76,13 @@
-
- static slram_mtd_list_t *slram_mtdlist = NULL;
-
--int slram_erase(struct mtd_info *, struct erase_info *);
--int slram_point(struct mtd_info *, loff_t, size_t, size_t *, u_char **);
--void slram_unpoint(struct mtd_info *, u_char *, loff_t, size_t);
--int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
--int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
-+static int slram_erase(struct mtd_info *, struct erase_info *);
-+static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, u_char **);
-+static void slram_unpoint(struct mtd_info *, u_char *, loff_t, size_t);
-+static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-+static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
-
--int slram_erase(struct mtd_info *mtd, struct erase_info *instr)
-+static int slram_erase(struct mtd_info *mtd, struct erase_info *instr)
- {
- slram_priv_t *priv = mtd->priv;
-
-@@ -98,34 +99,38 @@
-
- instr->state = MTD_ERASE_DONE;
-
-- if (instr->callback) {
-- (*(instr->callback))(instr);
-- }
-- else {
-- kfree(instr);
-- }
-+ mtd_erase_callback(instr);
-
- return(0);
- }
-
--int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
-+static int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf)
- {
-- slram_priv_t *priv = (slram_priv_t *)mtd->priv;
-+ slram_priv_t *priv = mtd->priv;
-+
-+ if (from + len > mtd->size)
-+ return -EINVAL;
-
- *mtdbuf = priv->start + from;
- *retlen = len;
- return(0);
- }
-
--void slram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
-+static void slram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
- {
- }
-
--int slram_read(struct mtd_info *mtd, loff_t from, size_t len,
-+static int slram_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
- {
-- slram_priv_t *priv = (slram_priv_t *)mtd->priv;
-+ slram_priv_t *priv = mtd->priv;
-+
-+ if (from > mtd->size)
-+ return -EINVAL;
-+
-+ if (from + len > mtd->size)
-+ len = mtd->size - from;
-
- memcpy(buf, priv->start + from, len);
-
-@@ -133,10 +138,13 @@
- return(0);
- }
-
--int slram_write(struct mtd_info *mtd, loff_t to, size_t len,
-+static int slram_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
- {
-- slram_priv_t *priv = (slram_priv_t *)mtd->priv;
-+ slram_priv_t *priv = mtd->priv;
-+
-+ if (to + len > mtd->size)
-+ return -EINVAL;
-
- memcpy(priv->start + to, buf, len);
-
-@@ -146,7 +154,7 @@
-
- /*====================================================================*/
-
--int register_device(char *name, unsigned long start, unsigned long length)
-+static int register_device(char *name, unsigned long start, unsigned long length)
- {
- slram_mtd_list_t **curmtd;
-
-@@ -166,7 +174,7 @@
- if ((*curmtd)->mtdinfo) {
- memset((char *)(*curmtd)->mtdinfo, 0, sizeof(struct mtd_info));
- (*curmtd)->mtdinfo->priv =
-- (void *)kmalloc(sizeof(slram_priv_t), GFP_KERNEL);
-+ kmalloc(sizeof(slram_priv_t), GFP_KERNEL);
-
- if (!(*curmtd)->mtdinfo->priv) {
- kfree((*curmtd)->mtdinfo);
-@@ -193,15 +201,15 @@
- (*curmtd)->mtdinfo->name = name;
- (*curmtd)->mtdinfo->size = length;
- (*curmtd)->mtdinfo->flags = MTD_CLEAR_BITS | MTD_SET_BITS |
-- MTD_WRITEB_WRITEABLE | MTD_VOLATILE;
-+ MTD_WRITEB_WRITEABLE | MTD_VOLATILE | MTD_CAP_RAM;
- (*curmtd)->mtdinfo->erase = slram_erase;
- (*curmtd)->mtdinfo->point = slram_point;
- (*curmtd)->mtdinfo->unpoint = slram_unpoint;
- (*curmtd)->mtdinfo->read = slram_read;
- (*curmtd)->mtdinfo->write = slram_write;
-- (*curmtd)->mtdinfo->module = THIS_MODULE;
-+ (*curmtd)->mtdinfo->owner = THIS_MODULE;
- (*curmtd)->mtdinfo->type = MTD_RAM;
-- (*curmtd)->mtdinfo->erasesize = 0x0;
-+ (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ;
-
- if (add_mtd_device((*curmtd)->mtdinfo)) {
- E("slram: Failed to register new device\n");
-@@ -218,7 +226,7 @@
- return(0);
- }
-
--void unregister_devices(void)
-+static void unregister_devices(void)
- {
- slram_mtd_list_t *nextitem;
-
-@@ -233,7 +241,7 @@
- }
- }
-
--unsigned long handle_unit(unsigned long value, char *unit)
-+static unsigned long handle_unit(unsigned long value, char *unit)
- {
- if ((*unit == 'M') || (*unit == 'm')) {
- return(value * 1024 * 1024);
-@@ -243,7 +251,7 @@
- return(value);
- }
-
--int parse_cmdline(char *devname, char *szstart, char *szlength)
-+static int parse_cmdline(char *devname, char *szstart, char *szlength)
- {
- char *buffer;
- unsigned long devstart;
-@@ -266,7 +274,7 @@
- }
- T("slram: devname=%s, devstart=0x%lx, devlength=0x%lx\n",
- devname, devstart, devlength);
-- if ((devstart < 0) || (devlength < 0)) {
-+ if ((devstart < 0) || (devlength < 0) || (devlength % SLRAM_BLK_SZ != 0)) {
- E("slram: Illegal start / length parameter.\n");
- return(-EINVAL);
- }
-@@ -290,7 +298,7 @@
-
- #endif
-
--int init_slram(void)
-+static int init_slram(void)
- {
- char *devname;
- int i;
---- linux-2.4.21/drivers/mtd/ftl.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/ftl.c
-@@ -1,5 +1,5 @@
- /* This version ported to the Linux-MTD system by dwmw2@infradead.org
-- * $Id: ftl.c,v 1.45 2003/01/24 23:31:27 dwmw2 Exp $
-+ * $Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $
- *
- * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
-@@ -55,8 +55,8 @@
- contact M-Systems (http://www.m-sys.com) directly.
-
- ======================================================================*/
-+#include <linux/mtd/blktrans.h>
- #include <linux/module.h>
--#include <linux/mtd/compatmac.h>
- #include <linux/mtd/mtd.h>
- /*#define PSYCHO_DEBUG */
-
-@@ -68,43 +68,13 @@
- #include <linux/timer.h>
- #include <linux/major.h>
- #include <linux/fs.h>
--#include <linux/ioctl.h>
-+#include <linux/init.h>
- #include <linux/hdreg.h>
--
--#if (LINUX_VERSION_CODE >= 0x20100)
- #include <linux/vmalloc.h>
--#endif
--#if (LINUX_VERSION_CODE >= 0x20303)
- #include <linux/blkpg.h>
--#endif
-+#include <asm/uaccess.h>
-
- #include <linux/mtd/ftl.h>
--/*====================================================================*/
--/* Stuff which really ought to be in compatmac.h */
--
--#if (LINUX_VERSION_CODE < 0x20328)
--#define register_disk(dev, drive, minors, ops, size) \
-- do { (dev)->part[(drive)*(minors)].nr_sects = size; \
-- if (size == 0) (dev)->part[(drive)*(minors)].start_sect = -1; \
-- resetup_one_dev(dev, drive); } while (0)
--#endif
--
--#if (LINUX_VERSION_CODE < 0x20320)
--#define BLK_DEFAULT_QUEUE(n) blk_dev[n].request_fn
--#define blk_init_queue(q, req) q = (req)
--#define blk_cleanup_queue(q) q = NULL
--#define request_arg_t void
--#else
--#define request_arg_t request_queue_t *q
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
--#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
--#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
--#else
--#define BLK_INC_USE_COUNT do {} while(0)
--#define BLK_DEC_USE_COUNT do {} while(0)
--#endif
-
- /*====================================================================*/
-
-@@ -119,19 +89,6 @@
- #define FTL_MAJOR 44
- #endif
-
--/* Funky stuff for setting up a block device */
--#define MAJOR_NR FTL_MAJOR
--#define DEVICE_NAME "ftl"
--#define DEVICE_REQUEST do_ftl_request
--#define DEVICE_ON(device)
--#define DEVICE_OFF(device)
--
--#define DEVICE_NR(minor) ((minor)>>5)
--#define REGION_NR(minor) (((minor)>>3)&3)
--#define PART_NR(minor) ((minor)&7)
--#define MINOR_NR(dev,reg,part) (((dev)<<5)+((reg)<<3)+(part))
--
--#include <linux/blk.h>
-
- /*====================================================================*/
-
-@@ -142,8 +99,7 @@
- #define MAX_REGION 4
-
- /* Maximum number of partitions in an FTL region */
--#define PART_BITS 3
--#define MAX_PART 8
-+#define PART_BITS 4
-
- /* Maximum number of outstanding erase requests per socket */
- #define MAX_ERASE 8
-@@ -154,7 +110,7 @@
-
- /* Each memory region corresponds to a minor device */
- typedef struct partition_t {
-- struct mtd_info *mtd;
-+ struct mtd_blktrans_dev mbd;
- u_int32_t state;
- u_int32_t *VirtualBlockMap;
- u_int32_t *VirtualPageMap;
-@@ -179,21 +135,10 @@
- region_info_t region;
- memory_handle_t handle;
- #endif
-- atomic_t open;
- } partition_t;
-
--partition_t *myparts[MAX_MTD_DEVICES];
--
--static void ftl_notify_add(struct mtd_info *mtd);
--static void ftl_notify_remove(struct mtd_info *mtd);
--
- void ftl_freepart(partition_t *part);
-
--static struct mtd_notifier ftl_notifier = {
-- add: ftl_notify_add,
-- remove: ftl_notify_remove,
--};
--
- /* Partition state flags */
- #define FTL_FORMATTED 0x01
-
-@@ -204,51 +149,11 @@
- #define XFER_PREPARED 0x03
- #define XFER_FAILED 0x04
-
--static struct hd_struct ftl_hd[MINOR_NR(MAX_DEV, 0, 0)];
--static int ftl_sizes[MINOR_NR(MAX_DEV, 0, 0)];
--static int ftl_blocksizes[MINOR_NR(MAX_DEV, 0, 0)];
--
--static struct gendisk ftl_gendisk = {
-- major: FTL_MAJOR,
-- major_name: "ftl",
-- minor_shift: PART_BITS,
-- max_p: MAX_PART,
--#if (LINUX_VERSION_CODE < 0x20328)
-- max_nr: MAX_DEV*MAX_PART,
--#endif
-- part: ftl_hd,
-- sizes: ftl_sizes,
--};
--
- /*====================================================================*/
-
--static int ftl_ioctl(struct inode *inode, struct file *file,
-- u_int cmd, u_long arg);
--static int ftl_open(struct inode *inode, struct file *file);
--static release_t ftl_close(struct inode *inode, struct file *file);
--static int ftl_reread_partitions(int minor);
-
- static void ftl_erase_callback(struct erase_info *done);
-
--#if LINUX_VERSION_CODE < 0x20326
--static struct file_operations ftl_blk_fops = {
-- open: ftl_open,
-- release: ftl_close,
-- ioctl: ftl_ioctl,
-- read: block_read,
-- write: block_write,
-- fsync: block_fsync
--};
--#else
--static struct block_device_operations ftl_blk_fops = {
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
-- owner: THIS_MODULE,
--#endif
-- open: ftl_open,
-- release: ftl_close,
-- ioctl: ftl_ioctl,
--};
--#endif
-
- /*======================================================================
-
-@@ -262,19 +167,20 @@
- {
- erase_unit_header_t header;
- loff_t offset, max_offset;
-- int ret;
-+ size_t ret;
-+ int err;
- part->header.FormattedSize = 0;
-- max_offset = (0x100000<part->mtd->size)?0x100000:part->mtd->size;
-+ max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size;
- /* Search first megabyte for a valid FTL header */
- for (offset = 0;
- (offset + sizeof(header)) < max_offset;
-- offset += part->mtd->erasesize ? : 0x2000) {
-+ offset += part->mbd.mtd->erasesize ? : 0x2000) {
-
-- ret = part->mtd->read(part->mtd, offset, sizeof(header), &ret,
-+ err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret,
- (unsigned char *)&header);
-
-- if (ret)
-- return ret;
-+ if (err)
-+ return err;
-
- if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
- }
-@@ -283,15 +189,15 @@
- printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
- return -ENOENT;
- }
-- if ((le16_to_cpu(header.NumEraseUnits) > 65536) || header.BlockSize != 9 ||
-+ if (header.BlockSize != 9 ||
- (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
- (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) {
- printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
- return -1;
- }
-- if ((1 << header.EraseUnitSize) != part->mtd->erasesize) {
-+ if ((1 << header.EraseUnitSize) != part->mbd.mtd->erasesize) {
- printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
-- 1 << header.EraseUnitSize,part->mtd->erasesize);
-+ 1 << header.EraseUnitSize,part->mbd.mtd->erasesize);
- return -1;
- }
- part->header = header;
-@@ -326,7 +232,7 @@
- for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
- offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
- << part->header.EraseUnitSize);
-- ret = part->mtd->read(part->mtd, offset, sizeof(header), &retval,
-+ ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval,
- (unsigned char *)&header);
-
- if (ret)
-@@ -391,7 +297,7 @@
- part->EUNInfo[i].Deleted = 0;
- offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
-
-- ret = part->mtd->read(part->mtd, offset,
-+ ret = part->mbd.mtd->read(part->mbd.mtd, offset,
- part->BlocksPerUnit * sizeof(u_int32_t), &retval,
- (unsigned char *)part->bam_cache);
-
-@@ -451,12 +357,13 @@
- if (!erase)
- return -ENOMEM;
-
-+ erase->mtd = part->mbd.mtd;
- erase->callback = ftl_erase_callback;
- erase->addr = xfer->Offset;
- erase->len = 1 << part->header.EraseUnitSize;
- erase->priv = (u_long)part;
-
-- ret = part->mtd->erase(part->mtd, erase);
-+ ret = part->mbd.mtd->erase(part->mbd.mtd, erase);
-
- if (!ret)
- xfer->EraseCount++;
-@@ -523,7 +430,7 @@
- header.LogicalEUN = cpu_to_le16(0xffff);
- header.EraseCount = cpu_to_le32(xfer->EraseCount);
-
-- ret = part->mtd->write(part->mtd, xfer->Offset, sizeof(header),
-+ ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset, sizeof(header),
- &retlen, (u_char *)&header);
-
- if (ret) {
-@@ -539,7 +446,7 @@
-
- for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
-
-- ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t),
-+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
- &retlen, (u_char *)&ctl);
-
- if (ret)
-@@ -586,7 +493,7 @@
-
- offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
-
-- ret = part->mtd->read(part->mtd, offset,
-+ ret = part->mbd.mtd->read(part->mbd.mtd, offset,
- part->BlocksPerUnit * sizeof(u_int32_t),
- &retlen, (u_char *) (part->bam_cache));
-
-@@ -604,7 +511,7 @@
- offset = xfer->Offset + 20; /* Bad! */
- unit = cpu_to_le16(0x7fff);
-
-- ret = part->mtd->write(part->mtd, offset, sizeof(u_int16_t),
-+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t),
- &retlen, (u_char *) &unit);
-
- if (ret) {
-@@ -624,7 +531,7 @@
- break;
- case BLOCK_DATA:
- case BLOCK_REPLACEMENT:
-- ret = part->mtd->read(part->mtd, src, SECTOR_SIZE,
-+ ret = part->mbd.mtd->read(part->mbd.mtd, src, SECTOR_SIZE,
- &retlen, (u_char *) buf);
- if (ret) {
- printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
-@@ -632,7 +539,7 @@
- }
-
-
-- ret = part->mtd->write(part->mtd, dest, SECTOR_SIZE,
-+ ret = part->mbd.mtd->write(part->mbd.mtd, dest, SECTOR_SIZE,
- &retlen, (u_char *) buf);
- if (ret) {
- printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
-@@ -651,7 +558,7 @@
- }
-
- /* Write the BAM to the transfer unit */
-- ret = part->mtd->write(part->mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
-+ ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
- part->BlocksPerUnit * sizeof(int32_t), &retlen,
- (u_char *)part->bam_cache);
- if (ret) {
-@@ -661,7 +568,7 @@
-
-
- /* All clear? Then update the LogicalEUN again */
-- ret = part->mtd->write(part->mtd, xfer->Offset + 20, sizeof(u_int16_t),
-+ ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t),
- &retlen, (u_char *)&srcunitswap);
-
- if (ret) {
-@@ -749,8 +656,8 @@
- if (queued) {
- DEBUG(1, "ftl_cs: waiting for transfer "
- "unit to be prepared...\n");
-- if (part->mtd->sync)
-- part->mtd->sync(part->mtd);
-+ if (part->mbd.mtd->sync)
-+ part->mbd.mtd->sync(part->mbd.mtd);
- } else {
- static int ne = 0;
- if (++ne < 5)
-@@ -848,7 +755,7 @@
- /* Invalidate cache */
- part->bam_index = 0xffff;
-
-- ret = part->mtd->read(part->mtd,
-+ ret = part->mbd.mtd->read(part->mbd.mtd,
- part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
- part->BlocksPerUnit * sizeof(u_int32_t),
- &retlen, (u_char *) (part->bam_cache));
-@@ -877,78 +784,6 @@
-
- } /* find_free */
-
--/*======================================================================
--
-- This gets a memory handle for the region corresponding to the
-- minor device number.
--
--======================================================================*/
--
--static int ftl_open(struct inode *inode, struct file *file)
--{
-- int minor = MINOR(inode->i_rdev);
-- partition_t *partition;
--
-- if (minor>>4 >= MAX_MTD_DEVICES)
-- return -ENODEV;
--
-- partition = myparts[minor>>4];
--
-- if (!partition)
-- return -ENODEV;
--
-- if (partition->state != FTL_FORMATTED)
-- return -ENXIO;
--
-- if (ftl_gendisk.part[minor].nr_sects == 0)
-- return -ENXIO;
--
-- BLK_INC_USE_COUNT;
--
-- if (!get_mtd_device(partition->mtd, -1)) {
-- BLK_DEC_USE_COUNT;
-- return -ENXIO;
-- }
--
-- if ((file->f_mode & 2) && !(partition->mtd->flags & MTD_CLEAR_BITS) ) {
-- put_mtd_device(partition->mtd);
-- BLK_DEC_USE_COUNT;
-- return -EROFS;
-- }
--
-- DEBUG(0, "ftl_cs: ftl_open(%d)\n", minor);
--
-- atomic_inc(&partition->open);
--
-- return 0;
--}
--
--/*====================================================================*/
--
--static release_t ftl_close(struct inode *inode, struct file *file)
--{
-- int minor = MINOR(inode->i_rdev);
-- partition_t *part = myparts[minor >> 4];
-- int i;
--
-- DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor);
--
-- /* Wait for any pending erase operations to complete */
-- if (part->mtd->sync)
-- part->mtd->sync(part->mtd);
--
-- for (i = 0; i < part->header.NumTransferUnits; i++) {
-- if (part->XferInfo[i].state == XFER_ERASED)
-- prepare_xfer(part, i);
-- }
--
-- atomic_dec(&part->open);
--
-- put_mtd_device(part->mtd);
-- BLK_DEC_USE_COUNT;
-- release_return(0);
--} /* ftl_close */
--
-
- /*======================================================================
-
-@@ -983,7 +818,7 @@
- else {
- offset = (part->EUNInfo[log_addr / bsize].Offset
- + (log_addr % bsize));
-- ret = part->mtd->read(part->mtd, offset, SECTOR_SIZE,
-+ ret = part->mbd.mtd->read(part->mbd.mtd, offset, SECTOR_SIZE,
- &retlen, (u_char *) buffer);
-
- if (ret) {
-@@ -1022,7 +857,7 @@
- le32_to_cpu(part->header.BAMOffset));
-
- #ifdef PSYCHO_DEBUG
-- ret = part->mtd->read(part->mtd, offset, sizeof(u_int32_t),
-+ ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t),
- &retlen, (u_char *)&old_addr);
- if (ret) {
- printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
-@@ -1059,7 +894,7 @@
- #endif
- part->bam_cache[blk] = le_virt_addr;
- }
-- ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t),
-+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
- &retlen, (u_char *)&le_virt_addr);
-
- if (ret) {
-@@ -1119,13 +954,13 @@
- part->EUNInfo[part->bam_index].Deleted++;
- offset = (part->EUNInfo[part->bam_index].Offset +
- blk * SECTOR_SIZE);
-- ret = part->mtd->write(part->mtd, offset, SECTOR_SIZE, &retlen,
-+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
- buffer);
-
- if (ret) {
- printk(KERN_NOTICE "ftl_cs: block write failed!\n");
- printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, virt_addr"
-- " = 0x%x, Offset = 0x%x\n", log_addr, virt_addr,
-+ " = 0x%x, Offset = 0x%zx\n", log_addr, virt_addr,
- offset);
- return -EIO;
- }
-@@ -1151,164 +986,32 @@
- return 0;
- } /* ftl_write */
-
--/*======================================================================
--
-- IOCTL calls for getting device parameters.
--
--======================================================================*/
--
--static int ftl_ioctl(struct inode *inode, struct file *file,
-- u_int cmd, u_long arg)
-+static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
- {
-- struct hd_geometry *geo = (struct hd_geometry *)arg;
-- int ret = 0, minor = MINOR(inode->i_rdev);
-- partition_t *part= myparts[minor >> 4];
-+ partition_t *part = (void *)dev;
- u_long sect;
-
-- if (!part)
-- return -ENODEV; /* How? */
--
-- switch (cmd) {
-- case HDIO_GETGEO:
-- ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(*geo));
-- if (ret) return ret;
-- /* Sort of arbitrary: round size down to 4K boundary */
-+ /* Sort of arbitrary: round size down to 4KiB boundary */
- sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
-- put_user(1, (char *)&geo->heads);
-- put_user(8, (char *)&geo->sectors);
-- put_user((sect>>3), (short *)&geo->cylinders);
-- put_user(ftl_hd[minor].start_sect, (u_long *)&geo->start);
-- break;
-- case BLKGETSIZE:
-- ret = put_user(ftl_hd[minor].nr_sects, (unsigned long *)arg);
-- break;
--#ifdef BLKGETSIZE64
-- case BLKGETSIZE64:
-- ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg);
-- break;
--#endif
-- case BLKRRPART:
-- ret = ftl_reread_partitions(minor);
-- break;
--#if (LINUX_VERSION_CODE < 0x20303)
-- case BLKFLSBUF:
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
--#endif
-- fsync_dev(inode->i_rdev);
-- invalidate_buffers(inode->i_rdev);
-- break;
-- RO_IOCTLS(inode->i_rdev, arg);
--#else
-- case BLKROSET:
-- case BLKROGET:
-- case BLKFLSBUF:
-- ret = blk_ioctl(inode->i_rdev, cmd, arg);
-- break;
--#endif
-- default:
-- ret = -EINVAL;
-- }
--
-- return ret;
--} /* ftl_ioctl */
--
--/*======================================================================
--
-- Handler for block device requests
-
--======================================================================*/
--
--static int ftl_reread_partitions(int minor)
--{
-- partition_t *part = myparts[minor >> 4];
-- int i, whole;
--
-- DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor);
-- if ((atomic_read(&part->open) > 1)) {
-- return -EBUSY;
-- }
-- whole = minor & ~(MAX_PART-1);
--
-- i = MAX_PART - 1;
-- while (i-- > 0) {
-- if (ftl_hd[whole+i].nr_sects > 0) {
-- kdev_t rdev = MKDEV(FTL_MAJOR, whole+i);
--
-- invalidate_device(rdev, 1);
-- }
-- ftl_hd[whole+i].start_sect = 0;
-- ftl_hd[whole+i].nr_sects = 0;
-- }
--
-- scan_header(part);
--
-- register_disk(&ftl_gendisk, whole >> PART_BITS, MAX_PART,
-- &ftl_blk_fops, le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE);
-+ geo->heads = 1;
-+ geo->sectors = 8;
-+ geo->cylinders = sect >> 3;
-
--#ifdef PCMCIA_DEBUG
-- for (i = 0; i < MAX_PART; i++) {
-- if (ftl_hd[whole+i].nr_sects > 0)
-- printk(KERN_INFO " %d: start %ld size %ld\n", i,
-- ftl_hd[whole+i].start_sect,
-- ftl_hd[whole+i].nr_sects);
-- }
--#endif
- return 0;
- }
-
--/*======================================================================
--
-- Handler for block device requests
--
--======================================================================*/
--
--static void do_ftl_request(request_arg_t)
-+static int ftl_readsect(struct mtd_blktrans_dev *dev,
-+ unsigned long block, char *buf)
- {
-- int ret, minor;
-- partition_t *part;
--
-- do {
-- // sti();
-- INIT_REQUEST;
--
-- minor = MINOR(CURRENT->rq_dev);
--
-- part = myparts[minor >> 4];
-- if (part) {
-- ret = 0;
--
-- switch (CURRENT->cmd) {
-- case READ:
-- ret = ftl_read(part, CURRENT->buffer,
-- CURRENT->sector+ftl_hd[minor].start_sect,
-- CURRENT->current_nr_sectors);
-- if (ret) printk("ftl_read returned %d\n", ret);
-- break;
--
-- case WRITE:
-- ret = ftl_write(part, CURRENT->buffer,
-- CURRENT->sector+ftl_hd[minor].start_sect,
-- CURRENT->current_nr_sectors);
-- if (ret) printk("ftl_write returned %d\n", ret);
-- break;
--
-- default:
-- panic("ftl_cs: unknown block command!\n");
--
-- }
-- } else {
-- ret = 1;
-- printk("NULL part in ftl_request\n");
-- }
--
-- if (!ret) {
-- CURRENT->sector += CURRENT->current_nr_sectors;
-- }
-+ return ftl_read((void *)dev, buf, block, 1);
-+}
-
-- end_request((ret == 0) ? 1 : 0);
-- } while (1);
--} /* do_ftl_request */
-+static int ftl_writesect(struct mtd_blktrans_dev *dev,
-+ unsigned long block, char *buf)
-+{
-+ return ftl_write((void *)dev, buf, block, 1);
-+}
-
- /*====================================================================*/
-
-@@ -1337,19 +1040,9 @@
-
- } /* ftl_freepart */
-
--static void ftl_notify_add(struct mtd_info *mtd)
-+static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
- {
- partition_t *partition;
-- int device;
--
-- for (device=0; device < MAX_MTD_DEVICES && myparts[device]; device++)
-- ;
--
-- if (device == MAX_MTD_DEVICES) {
-- printk(KERN_NOTICE "Maximum number of FTL partitions reached\n"
-- "Not scanning <%s>\n", mtd->name);
-- return;
-- }
-
- partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
-
-@@ -1361,92 +1054,57 @@
-
- memset(partition, 0, sizeof(partition_t));
-
-- partition->mtd = mtd;
-+ partition->mbd.mtd = mtd;
-
- if ((scan_header(partition) == 0) &&
- (build_maps(partition) == 0)) {
-
- partition->state = FTL_FORMATTED;
-- atomic_set(&partition->open, 0);
-- myparts[device] = partition;
-- ftl_reread_partitions(device << 4);
- #ifdef PCMCIA_DEBUG
-- printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n",
-+ printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
- le32_to_cpu(partition->header.FormattedSize) >> 10);
- #endif
-- } else
-+ partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
-+ partition->mbd.blksize = SECTOR_SIZE;
-+ partition->mbd.tr = tr;
-+ partition->mbd.devnum = -1;
-+ if (!add_mtd_blktrans_dev((void *)partition))
-+ return;
-+ }
-+
-+ ftl_freepart(partition);
- kfree(partition);
- }
-
--static void ftl_notify_remove(struct mtd_info *mtd)
-+static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
- {
-- int i,j;
--
-- /* Q: What happens if you try to remove a device which has
-- * a currently-open FTL partition on it?
-- *
-- * A: You don't. The ftl_open routine is responsible for
-- * increasing the use count of the driver module which
-- * it uses.
-- */
--
-- /* That's the theory, anyway :) */
--
-- for (i=0; i< MAX_MTD_DEVICES; i++)
-- if (myparts[i] && myparts[i]->mtd == mtd) {
--
-- if (myparts[i]->state == FTL_FORMATTED)
-- ftl_freepart(myparts[i]);
--
-- myparts[i]->state = 0;
-- for (j=0; j<16; j++) {
-- ftl_gendisk.part[j].nr_sects=0;
-- ftl_gendisk.part[j].start_sect=0;
-- }
-- kfree(myparts[i]);
-- myparts[i] = NULL;
-- }
-+ del_mtd_blktrans_dev(dev);
-+ ftl_freepart((partition_t *)dev);
-+ kfree(dev);
- }
-
-+struct mtd_blktrans_ops ftl_tr = {
-+ .name = "ftl",
-+ .major = FTL_MAJOR,
-+ .part_bits = PART_BITS,
-+ .readsect = ftl_readsect,
-+ .writesect = ftl_writesect,
-+ .getgeo = ftl_getgeo,
-+ .add_mtd = ftl_add_mtd,
-+ .remove_dev = ftl_remove_dev,
-+ .owner = THIS_MODULE,
-+};
-+
- int init_ftl(void)
- {
-- int i;
--
-- memset(myparts, 0, sizeof(myparts));
--
-- DEBUG(0, "$Id: ftl.c,v 1.45 2003/01/24 23:31:27 dwmw2 Exp $\n");
--
-- if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) {
-- printk(KERN_NOTICE "ftl_cs: unable to grab major "
-- "device number!\n");
-- return -EAGAIN;
-- }
--
-- for (i = 0; i < MINOR_NR(MAX_DEV, 0, 0); i++)
-- ftl_blocksizes[i] = 1024;
-- for (i = 0; i < MAX_DEV*MAX_PART; i++) {
-- ftl_hd[i].nr_sects = 0;
-- ftl_hd[i].start_sect = 0;
-- }
-- blksize_size[FTL_MAJOR] = ftl_blocksizes;
-- ftl_gendisk.major = FTL_MAJOR;
-- blk_init_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR), &do_ftl_request);
-- add_gendisk(&ftl_gendisk);
--
-- register_mtd_user(&ftl_notifier);
-+ DEBUG(0, "$Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $\n");
-
-- return 0;
-+ return register_mtd_blktrans(&ftl_tr);
- }
-
- static void __exit cleanup_ftl(void)
- {
-- unregister_mtd_user(&ftl_notifier);
--
-- unregister_blkdev(FTL_MAJOR, "ftl");
-- blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR));
-- blksize_size[FTL_MAJOR] = NULL;
--
-- del_gendisk(&ftl_gendisk);
-+ deregister_mtd_blktrans(&ftl_tr);
- }
-
- module_init(init_ftl);
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/inftlcore.c
-@@ -0,0 +1,912 @@
-+/*
-+ * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL)
-+ *
-+ * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
-+ *
-+ * Based heavily on the nftlcore.c code which is:
-+ * (c) 1999 Machine Vision Holdings, Inc.
-+ * Author: David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * $Id: inftlcore.c,v 1.18 2004/11/16 18:28:59 dwmw2 Exp $
-+ *
-+ * This program is free software; 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/kernel.h>
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <linux/sched.h>
-+#include <linux/init.h>
-+#include <linux/kmod.h>
-+#include <linux/hdreg.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nftl.h>
-+#include <linux/mtd/inftl.h>
-+#include <asm/uaccess.h>
-+#include <asm/errno.h>
-+#include <asm/io.h>
-+
-+/*
-+ * Maximum number of loops while examining next block, to have a
-+ * chance to detect consistency problems (they should never happen
-+ * because of the checks done in the mounting.
-+ */
-+#define MAX_LOOPS 10000
-+
-+extern void INFTL_dumptables(struct INFTLrecord *inftl);
-+extern void INFTL_dumpVUchains(struct INFTLrecord *inftl);
-+
-+static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
-+{
-+ struct INFTLrecord *inftl;
-+ unsigned long temp;
-+
-+ if (mtd->type != MTD_NANDFLASH)
-+ return;
-+ /* OK, this is moderately ugly. But probably safe. Alternatives? */
-+ if (memcmp(mtd->name, "DiskOnChip", 10))
-+ return;
-+
-+ if (!mtd->block_isbad) {
-+ printk(KERN_ERR
-+"INFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
-+"Please use the new diskonchip driver under the NAND subsystem.\n");
-+ return;
-+ }
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name);
-+
-+ inftl = kmalloc(sizeof(*inftl), GFP_KERNEL);
-+
-+ if (!inftl) {
-+ printk(KERN_WARNING "INFTL: Out of memory for data structures\n");
-+ return;
-+ }
-+ memset(inftl, 0, sizeof(*inftl));
-+
-+ inftl->mbd.mtd = mtd;
-+ inftl->mbd.devnum = -1;
-+ inftl->mbd.blksize = 512;
-+ inftl->mbd.tr = tr;
-+ memcpy(&inftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo));
-+ inftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY;
-+
-+ if (INFTL_mount(inftl) < 0) {
-+ printk(KERN_WARNING "INFTL: could not mount device\n");
-+ kfree(inftl);
-+ return;
-+ }
-+
-+ /* OK, it's a new one. Set up all the data structures. */
-+
-+ /* Calculate geometry */
-+ inftl->cylinders = 1024;
-+ inftl->heads = 16;
-+
-+ temp = inftl->cylinders * inftl->heads;
-+ inftl->sectors = inftl->mbd.size / temp;
-+ if (inftl->mbd.size % temp) {
-+ inftl->sectors++;
-+ temp = inftl->cylinders * inftl->sectors;
-+ inftl->heads = inftl->mbd.size / temp;
-+
-+ if (inftl->mbd.size % temp) {
-+ inftl->heads++;
-+ temp = inftl->heads * inftl->sectors;
-+ inftl->cylinders = inftl->mbd.size / temp;
-+ }
-+ }
-+
-+ if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) {
-+ /*
-+ Oh no we don't have
-+ mbd.size == heads * cylinders * sectors
-+ */
-+ printk(KERN_WARNING "INFTL: cannot calculate a geometry to "
-+ "match size of 0x%lx.\n", inftl->mbd.size);
-+ printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d "
-+ "(== 0x%lx sects)\n",
-+ inftl->cylinders, inftl->heads , inftl->sectors,
-+ (long)inftl->cylinders * (long)inftl->heads *
-+ (long)inftl->sectors );
-+ }
-+
-+ if (add_mtd_blktrans_dev(&inftl->mbd)) {
-+ if (inftl->PUtable)
-+ kfree(inftl->PUtable);
-+ if (inftl->VUtable)
-+ kfree(inftl->VUtable);
-+ kfree(inftl);
-+ return;
-+ }
-+#ifdef PSYCHO_DEBUG
-+ printk(KERN_INFO "INFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a');
-+#endif
-+ return;
-+}
-+
-+static void inftl_remove_dev(struct mtd_blktrans_dev *dev)
-+{
-+ struct INFTLrecord *inftl = (void *)dev;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: remove_dev (i=%d)\n", dev->devnum);
-+
-+ del_mtd_blktrans_dev(dev);
-+
-+ if (inftl->PUtable)
-+ kfree(inftl->PUtable);
-+ if (inftl->VUtable)
-+ kfree(inftl->VUtable);
-+ kfree(inftl);
-+}
-+
-+/*
-+ * Actual INFTL access routines.
-+ */
-+
-+/*
-+ * INFTL_findfreeblock: Find a free Erase Unit on the INFTL partition.
-+ * This function is used when the give Virtual Unit Chain.
-+ */
-+static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate)
-+{
-+ u16 pot = inftl->LastFreeEUN;
-+ int silly = inftl->nb_blocks;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findfreeblock(inftl=%p,"
-+ "desperate=%d)\n", inftl, desperate);
-+
-+ /*
-+ * Normally, we force a fold to happen before we run out of free
-+ * blocks completely.
-+ */
-+ if (!desperate && inftl->numfreeEUNs < 2) {
-+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: there are too few free "
-+ "EUNs (%d)\n", inftl->numfreeEUNs);
-+ return 0xffff;
-+ }
-+
-+ /* Scan for a free block */
-+ do {
-+ if (inftl->PUtable[pot] == BLOCK_FREE) {
-+ inftl->LastFreeEUN = pot;
-+ return pot;
-+ }
-+
-+ if (++pot > inftl->lastEUN)
-+ pot = 0;
-+
-+ if (!silly--) {
-+ printk(KERN_WARNING "INFTL: no free blocks found! "
-+ "EUN range = %d - %d\n", 0, inftl->LastFreeEUN);
-+ return BLOCK_NIL;
-+ }
-+ } while (pot != inftl->LastFreeEUN);
-+
-+ return BLOCK_NIL;
-+}
-+
-+static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned pendingblock)
-+{
-+ u16 BlockMap[MAX_SECTORS_PER_UNIT];
-+ unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];
-+ unsigned int thisEUN, prevEUN, status;
-+ int block, silly;
-+ unsigned int targetEUN;
-+ struct inftl_oob oob;
-+ size_t retlen;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d,"
-+ "pending=%d)\n", inftl, thisVUC, pendingblock);
-+
-+ memset(BlockMap, 0xff, sizeof(BlockMap));
-+ memset(BlockDeleted, 0, sizeof(BlockDeleted));
-+
-+ thisEUN = targetEUN = inftl->VUtable[thisVUC];
-+
-+ if (thisEUN == BLOCK_NIL) {
-+ printk(KERN_WARNING "INFTL: trying to fold non-existent "
-+ "Virtual Unit Chain %d!\n", thisVUC);
-+ return BLOCK_NIL;
-+ }
-+
-+ /*
-+ * Scan to find the Erase Unit which holds the actual data for each
-+ * 512-byte block within the Chain.
-+ */
-+ silly = MAX_LOOPS;
-+ while (thisEUN < inftl->nb_blocks) {
-+ for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) {
-+ if ((BlockMap[block] != 0xffff) || BlockDeleted[block])
-+ continue;
-+
-+ if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize)
-+ + (block * SECTORSIZE), 16 , &retlen,
-+ (char *)&oob) < 0)
-+ status = SECTOR_IGNORE;
-+ else
-+ status = oob.b.Status | oob.b.Status1;
-+
-+ switch(status) {
-+ case SECTOR_FREE:
-+ case SECTOR_IGNORE:
-+ break;
-+ case SECTOR_USED:
-+ BlockMap[block] = thisEUN;
-+ continue;
-+ case SECTOR_DELETED:
-+ BlockDeleted[block] = 1;
-+ continue;
-+ default:
-+ printk(KERN_WARNING "INFTL: unknown status "
-+ "for block %d in EUN %d: %x\n",
-+ block, thisEUN, status);
-+ break;
-+ }
-+ }
-+
-+ if (!silly--) {
-+ printk(KERN_WARNING "INFTL: infinite loop in Virtual "
-+ "Unit Chain 0x%x\n", thisVUC);
-+ return BLOCK_NIL;
-+ }
-+
-+ thisEUN = inftl->PUtable[thisEUN];
-+ }
-+
-+ /*
-+ * OK. We now know the location of every block in the Virtual Unit
-+ * Chain, and the Erase Unit into which we are supposed to be copying.
-+ * Go for it.
-+ */
-+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: folding chain %d into unit %d\n",
-+ thisVUC, targetEUN);
-+
-+ for (block = 0; block < inftl->EraseSize/SECTORSIZE ; block++) {
-+ unsigned char movebuf[SECTORSIZE];
-+ int ret;
-+
-+ /*
-+ * If it's in the target EUN already, or if it's pending write,
-+ * do nothing.
-+ */
-+ if (BlockMap[block] == targetEUN || (pendingblock ==
-+ (thisVUC * (inftl->EraseSize / SECTORSIZE) + block))) {
-+ continue;
-+ }
-+
-+ /*
-+ * Copy only in non free block (free blocks can only
-+ * happen in case of media errors or deleted blocks).
-+ */
-+ if (BlockMap[block] == BLOCK_NIL)
-+ continue;
-+
-+ ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
-+ BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE,
-+ &retlen, movebuf);
-+ if (ret < 0) {
-+ ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
-+ BlockMap[block]) + (block * SECTORSIZE),
-+ SECTORSIZE, &retlen, movebuf);
-+ if (ret != -EIO)
-+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
-+ "away on retry?\n");
-+ }
-+ memset(&oob, 0xff, sizeof(struct inftl_oob));
-+ oob.b.Status = oob.b.Status1 = SECTOR_USED;
-+ MTD_WRITEECC(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
-+ (block * SECTORSIZE), SECTORSIZE, &retlen,
-+ movebuf, (char *)&oob, &inftl->oobinfo);
-+ }
-+
-+ /*
-+ * Newest unit in chain now contains data from _all_ older units.
-+ * So go through and erase each unit in chain, oldest first. (This
-+ * is important, by doing oldest first if we crash/reboot then it
-+ * it is relatively simple to clean up the mess).
-+ */
-+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: want to erase virtual chain %d\n",
-+ thisVUC);
-+
-+ for (;;) {
-+ /* Find oldest unit in chain. */
-+ thisEUN = inftl->VUtable[thisVUC];
-+ prevEUN = BLOCK_NIL;
-+ while (inftl->PUtable[thisEUN] != BLOCK_NIL) {
-+ prevEUN = thisEUN;
-+ thisEUN = inftl->PUtable[thisEUN];
-+ }
-+
-+ /* Check if we are all done */
-+ if (thisEUN == targetEUN)
-+ break;
-+
-+ if (INFTL_formatblock(inftl, thisEUN) < 0) {
-+ /*
-+ * Could not erase : mark block as reserved.
-+ */
-+ inftl->PUtable[thisEUN] = BLOCK_RESERVED;
-+ } else {
-+ /* Correctly erased : mark it as free */
-+ inftl->PUtable[thisEUN] = BLOCK_FREE;
-+ inftl->PUtable[prevEUN] = BLOCK_NIL;
-+ inftl->numfreeEUNs++;
-+ }
-+ }
-+
-+ return targetEUN;
-+}
-+
-+static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock)
-+{
-+ /*
-+ * This is the part that needs some cleverness applied.
-+ * For now, I'm doing the minimum applicable to actually
-+ * get the thing to work.
-+ * Wear-levelling and other clever stuff needs to be implemented
-+ * and we also need to do some assessment of the results when
-+ * the system loses power half-way through the routine.
-+ */
-+ u16 LongestChain = 0;
-+ u16 ChainLength = 0, thislen;
-+ u16 chain, EUN;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_makefreeblock(inftl=%p,"
-+ "pending=%d)\n", inftl, pendingblock);
-+
-+ for (chain = 0; chain < inftl->nb_blocks; chain++) {
-+ EUN = inftl->VUtable[chain];
-+ thislen = 0;
-+
-+ while (EUN <= inftl->lastEUN) {
-+ thislen++;
-+ EUN = inftl->PUtable[EUN];
-+ if (thislen > 0xff00) {
-+ printk(KERN_WARNING "INFTL: endless loop in "
-+ "Virtual Chain %d: Unit %x\n",
-+ chain, EUN);
-+ /*
-+ * Actually, don't return failure.
-+ * Just ignore this chain and get on with it.
-+ */
-+ thislen = 0;
-+ break;
-+ }
-+ }
-+
-+ if (thislen > ChainLength) {
-+ ChainLength = thislen;
-+ LongestChain = chain;
-+ }
-+ }
-+
-+ if (ChainLength < 2) {
-+ printk(KERN_WARNING "INFTL: no Virtual Unit Chains available "
-+ "for folding. Failing request\n");
-+ return BLOCK_NIL;
-+ }
-+
-+ return INFTL_foldchain(inftl, LongestChain, pendingblock);
-+}
-+
-+static int nrbits(unsigned int val, int bitcount)
-+{
-+ int i, total = 0;
-+
-+ for (i = 0; (i < bitcount); i++)
-+ total += (((0x1 << i) & val) ? 1 : 0);
-+ return total;
-+}
-+
-+/*
-+ * INFTL_findwriteunit: Return the unit number into which we can write
-+ * for this block. Make it available if it isn't already.
-+ */
-+static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
-+{
-+ unsigned int thisVUC = block / (inftl->EraseSize / SECTORSIZE);
-+ unsigned int thisEUN, writeEUN, prev_block, status;
-+ unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize -1);
-+ struct inftl_oob oob;
-+ struct inftl_bci bci;
-+ unsigned char anac, nacs, parity;
-+ size_t retlen;
-+ int silly, silly2 = 3;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findwriteunit(inftl=%p,"
-+ "block=%d)\n", inftl, block);
-+
-+ do {
-+ /*
-+ * Scan the media to find a unit in the VUC which has
-+ * a free space for the block in question.
-+ */
-+ writeEUN = BLOCK_NIL;
-+ thisEUN = inftl->VUtable[thisVUC];
-+ silly = MAX_LOOPS;
-+
-+ while (thisEUN <= inftl->lastEUN) {
-+ MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
-+ blockofs, 8, &retlen, (char *)&bci);
-+
-+ status = bci.Status | bci.Status1;
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in "
-+ "EUN %d is %x\n", block , writeEUN, status);
-+
-+ switch(status) {
-+ case SECTOR_FREE:
-+ writeEUN = thisEUN;
-+ break;
-+ case SECTOR_DELETED:
-+ case SECTOR_USED:
-+ /* Can't go any further */
-+ goto hitused;
-+ case SECTOR_IGNORE:
-+ break;
-+ default:
-+ /*
-+ * Invalid block. Don't use it any more.
-+ * Must implement.
-+ */
-+ break;
-+ }
-+
-+ if (!silly--) {
-+ printk(KERN_WARNING "INFTL: infinite loop in "
-+ "Virtual Unit Chain 0x%x\n", thisVUC);
-+ return 0xffff;
-+ }
-+
-+ /* Skip to next block in chain */
-+ thisEUN = inftl->PUtable[thisEUN];
-+ }
-+
-+hitused:
-+ if (writeEUN != BLOCK_NIL)
-+ return writeEUN;
-+
-+
-+ /*
-+ * OK. We didn't find one in the existing chain, or there
-+ * is no existing chain. Allocate a new one.
-+ */
-+ writeEUN = INFTL_findfreeblock(inftl, 0);
-+
-+ if (writeEUN == BLOCK_NIL) {
-+ /*
-+ * That didn't work - there were no free blocks just
-+ * waiting to be picked up. We're going to have to fold
-+ * a chain to make room.
-+ */
-+ thisEUN = INFTL_makefreeblock(inftl, 0xffff);
-+
-+ /*
-+ * Hopefully we free something, lets try again.
-+ * This time we are desperate...
-+ */
-+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: using desperate==1 "
-+ "to find free EUN to accommodate write to "
-+ "VUC %d\n", thisVUC);
-+ writeEUN = INFTL_findfreeblock(inftl, 1);
-+ if (writeEUN == BLOCK_NIL) {
-+ /*
-+ * Ouch. This should never happen - we should
-+ * always be able to make some room somehow.
-+ * If we get here, we've allocated more storage
-+ * space than actual media, or our makefreeblock
-+ * routine is missing something.
-+ */
-+ printk(KERN_WARNING "INFTL: cannot make free "
-+ "space.\n");
-+#ifdef DEBUG
-+ INFTL_dumptables(inftl);
-+ INFTL_dumpVUchains(inftl);
-+#endif
-+ return BLOCK_NIL;
-+ }
-+ }
-+
-+ /*
-+ * Insert new block into virtual chain. Firstly update the
-+ * block headers in flash...
-+ */
-+ anac = 0;
-+ nacs = 0;
-+ thisEUN = inftl->VUtable[thisVUC];
-+ if (thisEUN != BLOCK_NIL) {
-+ MTD_READOOB(inftl->mbd.mtd, thisEUN * inftl->EraseSize
-+ + 8, 8, &retlen, (char *)&oob.u);
-+ anac = oob.u.a.ANAC + 1;
-+ nacs = oob.u.a.NACs + 1;
-+ }
-+
-+ prev_block = inftl->VUtable[thisVUC];
-+ if (prev_block < inftl->nb_blocks)
-+ prev_block -= inftl->firstEUN;
-+
-+ parity = (nrbits(thisVUC, 16) & 0x1) ? 0x1 : 0;
-+ parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0;
-+ parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0;
-+ parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0;
-+
-+ oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC);
-+ oob.u.a.prevUnitNo = cpu_to_le16(prev_block);
-+ oob.u.a.ANAC = anac;
-+ oob.u.a.NACs = nacs;
-+ oob.u.a.parityPerField = parity;
-+ oob.u.a.discarded = 0xaa;
-+
-+ MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + 8, 8,
-+ &retlen, (char *)&oob.u);
-+
-+ /* Also back up header... */
-+ oob.u.b.virtualUnitNo = cpu_to_le16(thisVUC);
-+ oob.u.b.prevUnitNo = cpu_to_le16(prev_block);
-+ oob.u.b.ANAC = anac;
-+ oob.u.b.NACs = nacs;
-+ oob.u.b.parityPerField = parity;
-+ oob.u.b.discarded = 0xaa;
-+
-+ MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize +
-+ SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u);
-+
-+ inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC];
-+ inftl->VUtable[thisVUC] = writeEUN;
-+
-+ inftl->numfreeEUNs--;
-+ return writeEUN;
-+
-+ } while (silly2--);
-+
-+ printk(KERN_WARNING "INFTL: error folding to make room for Virtual "
-+ "Unit Chain 0x%x\n", thisVUC);
-+ return 0xffff;
-+}
-+
-+/*
-+ * Given a Virtual Unit Chain, see if it can be deleted, and if so do it.
-+ */
-+static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
-+{
-+ unsigned char BlockUsed[MAX_SECTORS_PER_UNIT];
-+ unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];
-+ unsigned int thisEUN, status;
-+ int block, silly;
-+ struct inftl_bci bci;
-+ size_t retlen;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_trydeletechain(inftl=%p,"
-+ "thisVUC=%d)\n", inftl, thisVUC);
-+
-+ memset(BlockUsed, 0, sizeof(BlockUsed));
-+ memset(BlockDeleted, 0, sizeof(BlockDeleted));
-+
-+ thisEUN = inftl->VUtable[thisVUC];
-+ if (thisEUN == BLOCK_NIL) {
-+ printk(KERN_WARNING "INFTL: trying to delete non-existent "
-+ "Virtual Unit Chain %d!\n", thisVUC);
-+ return;
-+ }
-+
-+ /*
-+ * Scan through the Erase Units to determine whether any data is in
-+ * each of the 512-byte blocks within the Chain.
-+ */
-+ silly = MAX_LOOPS;
-+ while (thisEUN < inftl->nb_blocks) {
-+ for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++) {
-+ if (BlockUsed[block] || BlockDeleted[block])
-+ continue;
-+
-+ if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize)
-+ + (block * SECTORSIZE), 8 , &retlen,
-+ (char *)&bci) < 0)
-+ status = SECTOR_IGNORE;
-+ else
-+ status = bci.Status | bci.Status1;
-+
-+ switch(status) {
-+ case SECTOR_FREE:
-+ case SECTOR_IGNORE:
-+ break;
-+ case SECTOR_USED:
-+ BlockUsed[block] = 1;
-+ continue;
-+ case SECTOR_DELETED:
-+ BlockDeleted[block] = 1;
-+ continue;
-+ default:
-+ printk(KERN_WARNING "INFTL: unknown status "
-+ "for block %d in EUN %d: 0x%x\n",
-+ block, thisEUN, status);
-+ }
-+ }
-+
-+ if (!silly--) {
-+ printk(KERN_WARNING "INFTL: infinite loop in Virtual "
-+ "Unit Chain 0x%x\n", thisVUC);
-+ return;
-+ }
-+
-+ thisEUN = inftl->PUtable[thisEUN];
-+ }
-+
-+ for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++)
-+ if (BlockUsed[block])
-+ return;
-+
-+ /*
-+ * For each block in the chain free it and make it available
-+ * for future use. Erase from the oldest unit first.
-+ */
-+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: deleting empty VUC %d\n", thisVUC);
-+
-+ for (;;) {
-+ u16 *prevEUN = &inftl->VUtable[thisVUC];
-+ thisEUN = *prevEUN;
-+
-+ /* If the chain is all gone already, we're done */
-+ if (thisEUN == BLOCK_NIL) {
-+ DEBUG(MTD_DEBUG_LEVEL2, "INFTL: Empty VUC %d for deletion was already absent\n", thisEUN);
-+ return;
-+ }
-+
-+ /* Find oldest unit in chain. */
-+ while (inftl->PUtable[thisEUN] != BLOCK_NIL) {
-+ BUG_ON(thisEUN >= inftl->nb_blocks);
-+
-+ prevEUN = &inftl->PUtable[thisEUN];
-+ thisEUN = *prevEUN;
-+ }
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n",
-+ thisEUN, thisVUC);
-+
-+ if (INFTL_formatblock(inftl, thisEUN) < 0) {
-+ /*
-+ * Could not erase : mark block as reserved.
-+ */
-+ inftl->PUtable[thisEUN] = BLOCK_RESERVED;
-+ } else {
-+ /* Correctly erased : mark it as free */
-+ inftl->PUtable[thisEUN] = BLOCK_FREE;
-+ inftl->numfreeEUNs++;
-+ }
-+
-+ /* Now sort out whatever was pointing to it... */
-+ *prevEUN = BLOCK_NIL;
-+
-+ /* Ideally we'd actually be responsive to new
-+ requests while we're doing this -- if there's
-+ free space why should others be made to wait? */
-+ cond_resched();
-+ }
-+
-+ inftl->VUtable[thisVUC] = BLOCK_NIL;
-+}
-+
-+static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block)
-+{
-+ unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
-+ unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
-+ unsigned int status;
-+ int silly = MAX_LOOPS;
-+ size_t retlen;
-+ struct inftl_bci bci;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_deleteblock(inftl=%p,"
-+ "block=%d)\n", inftl, block);
-+
-+ while (thisEUN < inftl->nb_blocks) {
-+ if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
-+ blockofs, 8, &retlen, (char *)&bci) < 0)
-+ status = SECTOR_IGNORE;
-+ else
-+ status = bci.Status | bci.Status1;
-+
-+ switch (status) {
-+ case SECTOR_FREE:
-+ case SECTOR_IGNORE:
-+ break;
-+ case SECTOR_DELETED:
-+ thisEUN = BLOCK_NIL;
-+ goto foundit;
-+ case SECTOR_USED:
-+ goto foundit;
-+ default:
-+ printk(KERN_WARNING "INFTL: unknown status for "
-+ "block %d in EUN %d: 0x%x\n",
-+ block, thisEUN, status);
-+ break;
-+ }
-+
-+ if (!silly--) {
-+ printk(KERN_WARNING "INFTL: infinite loop in Virtual "
-+ "Unit Chain 0x%x\n",
-+ block / (inftl->EraseSize / SECTORSIZE));
-+ return 1;
-+ }
-+ thisEUN = inftl->PUtable[thisEUN];
-+ }
-+
-+foundit:
-+ if (thisEUN != BLOCK_NIL) {
-+ loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
-+
-+ if (MTD_READOOB(inftl->mbd.mtd, ptr, 8, &retlen, (char *)&bci) < 0)
-+ return -EIO;
-+ bci.Status = bci.Status1 = SECTOR_DELETED;
-+ if (MTD_WRITEOOB(inftl->mbd.mtd, ptr, 8, &retlen, (char *)&bci) < 0)
-+ return -EIO;
-+ INFTL_trydeletechain(inftl, block / (inftl->EraseSize / SECTORSIZE));
-+ }
-+ return 0;
-+}
-+
-+static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
-+ char *buffer)
-+{
-+ struct INFTLrecord *inftl = (void *)mbd;
-+ unsigned int writeEUN;
-+ unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
-+ size_t retlen;
-+ struct inftl_oob oob;
-+ char *p, *pend;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=%p,block=%ld,"
-+ "buffer=%p)\n", inftl, block, buffer);
-+
-+ /* Is block all zero? */
-+ pend = buffer + SECTORSIZE;
-+ for (p = buffer; p < pend && !*p; p++)
-+ ;
-+
-+ if (p < pend) {
-+ writeEUN = INFTL_findwriteunit(inftl, block);
-+
-+ if (writeEUN == BLOCK_NIL) {
-+ printk(KERN_WARNING "inftl_writeblock(): cannot find "
-+ "block to write to\n");
-+ /*
-+ * If we _still_ haven't got a block to use,
-+ * we're screwed.
-+ */
-+ return 1;
-+ }
-+
-+ memset(&oob, 0xff, sizeof(struct inftl_oob));
-+ oob.b.Status = oob.b.Status1 = SECTOR_USED;
-+ MTD_WRITEECC(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
-+ blockofs, SECTORSIZE, &retlen, (char *)buffer,
-+ (char *)&oob, &inftl->oobinfo);
-+ /*
-+ * need to write SECTOR_USED flags since they are not written
-+ * in mtd_writeecc
-+ */
-+ } else {
-+ INFTL_deleteblock(inftl, block);
-+ }
-+
-+ return 0;
-+}
-+
-+static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
-+ char *buffer)
-+{
-+ struct INFTLrecord *inftl = (void *)mbd;
-+ unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
-+ unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
-+ unsigned int status;
-+ int silly = MAX_LOOPS;
-+ struct inftl_bci bci;
-+ size_t retlen;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld,"
-+ "buffer=%p)\n", inftl, block, buffer);
-+
-+ while (thisEUN < inftl->nb_blocks) {
-+ if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
-+ blockofs, 8, &retlen, (char *)&bci) < 0)
-+ status = SECTOR_IGNORE;
-+ else
-+ status = bci.Status | bci.Status1;
-+
-+ switch (status) {
-+ case SECTOR_DELETED:
-+ thisEUN = BLOCK_NIL;
-+ goto foundit;
-+ case SECTOR_USED:
-+ goto foundit;
-+ case SECTOR_FREE:
-+ case SECTOR_IGNORE:
-+ break;
-+ default:
-+ printk(KERN_WARNING "INFTL: unknown status for "
-+ "block %ld in EUN %d: 0x%04x\n",
-+ block, thisEUN, status);
-+ break;
-+ }
-+
-+ if (!silly--) {
-+ printk(KERN_WARNING "INFTL: infinite loop in "
-+ "Virtual Unit Chain 0x%lx\n",
-+ block / (inftl->EraseSize / SECTORSIZE));
-+ return 1;
-+ }
-+
-+ thisEUN = inftl->PUtable[thisEUN];
-+ }
-+
-+foundit:
-+ if (thisEUN == BLOCK_NIL) {
-+ /* The requested block is not on the media, return all 0x00 */
-+ memset(buffer, 0, SECTORSIZE);
-+ } else {
-+ size_t retlen;
-+ loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
-+ if (MTD_READ(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen,
-+ buffer))
-+ return -EIO;
-+ }
-+ return 0;
-+}
-+
-+static int inftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
-+{
-+ struct INFTLrecord *inftl = (void *)dev;
-+
-+ geo->heads = inftl->heads;
-+ geo->sectors = inftl->sectors;
-+ geo->cylinders = inftl->cylinders;
-+
-+ return 0;
-+}
-+
-+static struct mtd_blktrans_ops inftl_tr = {
-+ .name = "inftl",
-+ .major = INFTL_MAJOR,
-+ .part_bits = INFTL_PARTN_BITS,
-+ .getgeo = inftl_getgeo,
-+ .readsect = inftl_readblock,
-+ .writesect = inftl_writeblock,
-+ .add_mtd = inftl_add_mtd,
-+ .remove_dev = inftl_remove_dev,
-+ .owner = THIS_MODULE,
-+};
-+
-+extern char inftlmountrev[];
-+
-+static int __init init_inftl(void)
-+{
-+ printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.18 $, "
-+ "inftlmount.c %s\n", inftlmountrev);
-+
-+ return register_mtd_blktrans(&inftl_tr);
-+}
-+
-+static void __exit cleanup_inftl(void)
-+{
-+ deregister_mtd_blktrans(&inftl_tr);
-+}
-+
-+module_init(init_inftl);
-+module_exit(cleanup_inftl);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>, David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
-+MODULE_DESCRIPTION("Support code for Inverse Flash Translation Layer, used on M-Systems DiskOnChip 2000, Millennium and Millennium Plus");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/inftlmount.c
-@@ -0,0 +1,804 @@
-+/*
-+ * inftlmount.c -- INFTL mount code with extensive checks.
-+ *
-+ * Author: Greg Ungerer (gerg@snapgear.com)
-+ * (C) Copyright 2002-2003, Greg Ungerer (gerg@snapgear.com)
-+ *
-+ * Based heavily on the nftlmount.c code which is:
-+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
-+ * Copyright (C) 2000 Netgem S.A.
-+ *
-+ * $Id: inftlmount.c,v 1.16 2004/11/22 13:50:53 kalev Exp $
-+ *
-+ * This program is free software; 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/module.h>
-+#include <asm/errno.h>
-+#include <asm/io.h>
-+#include <asm/uaccess.h>
-+#include <linux/miscdevice.h>
-+#include <linux/pci.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <linux/sched.h>
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nftl.h>
-+#include <linux/mtd/inftl.h>
-+#include <linux/mtd/compatmac.h>
-+
-+char inftlmountrev[]="$Revision: 1.16 $";
-+
-+/*
-+ * find_boot_record: Find the INFTL Media Header and its Spare copy which
-+ * contains the various device information of the INFTL partition and
-+ * Bad Unit Table. Update the PUtable[] table according to the Bad
-+ * Unit Table. PUtable[] is used for management of Erase Unit in
-+ * other routines in inftlcore.c and inftlmount.c.
-+ */
-+static int find_boot_record(struct INFTLrecord *inftl)
-+{
-+ struct inftl_unittail h1;
-+ //struct inftl_oob oob;
-+ unsigned int i, block;
-+ u8 buf[SECTORSIZE];
-+ struct INFTLMediaHeader *mh = &inftl->MediaHdr;
-+ struct INFTLPartition *ip;
-+ size_t retlen;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: find_boot_record(inftl=%p)\n", inftl);
-+
-+ /*
-+ * Assume logical EraseSize == physical erasesize for starting the
-+ * scan. We'll sort it out later if we find a MediaHeader which says
-+ * otherwise.
-+ */
-+ inftl->EraseSize = inftl->mbd.mtd->erasesize;
-+ inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;
-+
-+ inftl->MediaUnit = BLOCK_NIL;
-+
-+ /* Search for a valid boot record */
-+ for (block = 0; block < inftl->nb_blocks; block++) {
-+ int ret;
-+
-+ /*
-+ * Check for BNAND header first. Then whinge if it's found
-+ * but later checks fail.
-+ */
-+ ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize,
-+ SECTORSIZE, &retlen, buf);
-+ /* We ignore ret in case the ECC of the MediaHeader is invalid
-+ (which is apparently acceptable) */
-+ if (retlen != SECTORSIZE) {
-+ static int warncount = 5;
-+
-+ if (warncount) {
-+ printk(KERN_WARNING "INFTL: block read at 0x%x "
-+ "of mtd%d failed: %d\n",
-+ block * inftl->EraseSize,
-+ inftl->mbd.mtd->index, ret);
-+ if (!--warncount)
-+ printk(KERN_WARNING "INFTL: further "
-+ "failures for this block will "
-+ "not be printed\n");
-+ }
-+ continue;
-+ }
-+
-+ if (retlen < 6 || memcmp(buf, "BNAND", 6)) {
-+ /* BNAND\0 not found. Continue */
-+ continue;
-+ }
-+
-+ /* To be safer with BIOS, also use erase mark as discriminant */
-+ if ((ret = MTD_READOOB(inftl->mbd.mtd, block * inftl->EraseSize +
-+ SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0)) {
-+ printk(KERN_WARNING "INFTL: ANAND header found at "
-+ "0x%x in mtd%d, but OOB data read failed "
-+ "(err %d)\n", block * inftl->EraseSize,
-+ inftl->mbd.mtd->index, ret);
-+ continue;
-+ }
-+
-+
-+ /*
-+ * This is the first we've seen.
-+ * Copy the media header structure into place.
-+ */
-+ memcpy(mh, buf, sizeof(struct INFTLMediaHeader));
-+
-+ /* Read the spare media header at offset 4096 */
-+ MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize + 4096,
-+ SECTORSIZE, &retlen, buf);
-+ if (retlen != SECTORSIZE) {
-+ printk(KERN_WARNING "INFTL: Unable to read spare "
-+ "Media Header\n");
-+ return -1;
-+ }
-+ /* Check if this one is the same as the first one we found. */
-+ if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) {
-+ printk(KERN_WARNING "INFTL: Primary and spare Media "
-+ "Headers disagree.\n");
-+ return -1;
-+ }
-+
-+ 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("INFTL: Media Header ->\n"
-+ " bootRecordID = %s\n"
-+ " NoOfBootImageBlocks = %d\n"
-+ " NoOfBinaryPartitions = %d\n"
-+ " NoOfBDTLPartitions = %d\n"
-+ " BlockMultiplerBits = %d\n"
-+ " FormatFlgs = %d\n"
-+ " OsakVersion = 0x%x\n"
-+ " PercentUsed = %d\n",
-+ mh->bootRecordID, mh->NoOfBootImageBlocks,
-+ mh->NoOfBinaryPartitions,
-+ mh->NoOfBDTLPartitions,
-+ mh->BlockMultiplierBits, mh->FormatFlags,
-+ mh->OsakVersion, mh->PercentUsed);
-+ }
-+#endif
-+
-+ if (mh->NoOfBDTLPartitions == 0) {
-+ printk(KERN_WARNING "INFTL: Media Header sanity check "
-+ "failed: NoOfBDTLPartitions (%d) == 0, "
-+ "must be at least 1\n", mh->NoOfBDTLPartitions);
-+ return -1;
-+ }
-+
-+ if ((mh->NoOfBDTLPartitions + mh->NoOfBinaryPartitions) > 4) {
-+ printk(KERN_WARNING "INFTL: Media Header sanity check "
-+ "failed: Total Partitions (%d) > 4, "
-+ "BDTL=%d Binary=%d\n", mh->NoOfBDTLPartitions +
-+ mh->NoOfBinaryPartitions,
-+ mh->NoOfBDTLPartitions,
-+ mh->NoOfBinaryPartitions);
-+ return -1;
-+ }
-+
-+ if (mh->BlockMultiplierBits > 1) {
-+ printk(KERN_WARNING "INFTL: sorry, we don't support "
-+ "UnitSizeFactor 0x%02x\n",
-+ mh->BlockMultiplierBits);
-+ return -1;
-+ } else if (mh->BlockMultiplierBits == 1) {
-+ printk(KERN_WARNING "INFTL: support for INFTL with "
-+ "UnitSizeFactor 0x%02x is experimental\n",
-+ mh->BlockMultiplierBits);
-+ inftl->EraseSize = inftl->mbd.mtd->erasesize <<
-+ mh->BlockMultiplierBits;
-+ inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;
-+ block >>= mh->BlockMultiplierBits;
-+ }
-+
-+ /* 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(" 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 (ip->Reserved0 != ip->firstUnit) {
-+ struct erase_info *instr = &inftl->instr;
-+
-+ instr->mtd = inftl->mbd.mtd;
-+
-+ /*
-+ * Most likely this is using the
-+ * undocumented qiuck mount feature.
-+ * We don't support that, we will need
-+ * to erase the hidden block for full
-+ * compatibility.
-+ */
-+ instr->addr = ip->Reserved0 * inftl->EraseSize;
-+ instr->len = inftl->EraseSize;
-+ MTD_ERASE(inftl->mbd.mtd, instr);
-+ }
-+ if ((ip->lastUnit - ip->firstUnit + 1) < ip->virtualUnits) {
-+ printk(KERN_WARNING "INFTL: Media Header "
-+ "Partition %d sanity check failed\n"
-+ " firstUnit %d : lastUnit %d > "
-+ "virtualUnits %d\n", i, ip->lastUnit,
-+ ip->firstUnit, ip->Reserved0);
-+ return -1;
-+ }
-+ if (ip->Reserved1 != 0) {
-+ printk(KERN_WARNING "INFTL: Media Header "
-+ "Partition %d sanity check failed: "
-+ "Reserved1 %d != 0\n",
-+ i, ip->Reserved1);
-+ return -1;
-+ }
-+
-+ if (ip->flags & INFTL_BDTL)
-+ break;
-+ }
-+
-+ if (i >= 4) {
-+ printk(KERN_WARNING "INFTL: Media Header Partition "
-+ "sanity check failed:\n No partition "
-+ "marked as Disk Partition\n");
-+ return -1;
-+ }
-+
-+ inftl->nb_boot_blocks = ip->firstUnit;
-+ inftl->numvunits = ip->virtualUnits;
-+ if (inftl->numvunits > (inftl->nb_blocks -
-+ inftl->nb_boot_blocks - 2)) {
-+ printk(KERN_WARNING "INFTL: Media Header sanity check "
-+ "failed:\n numvunits (%d) > nb_blocks "
-+ "(%d) - nb_boot_blocks(%d) - 2\n",
-+ inftl->numvunits, inftl->nb_blocks,
-+ inftl->nb_boot_blocks);
-+ return -1;
-+ }
-+
-+ inftl->mbd.size = inftl->numvunits *
-+ (inftl->EraseSize / SECTORSIZE);
-+
-+ /*
-+ * Block count is set to last used EUN (we won't need to keep
-+ * any meta-data past that point).
-+ */
-+ inftl->firstEUN = ip->firstUnit;
-+ inftl->lastEUN = ip->lastUnit;
-+ inftl->nb_blocks = ip->lastUnit + 1;
-+
-+ /* Memory alloc */
-+ inftl->PUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL);
-+ if (!inftl->PUtable) {
-+ printk(KERN_WARNING "INFTL: allocation of PUtable "
-+ "failed (%zd bytes)\n",
-+ inftl->nb_blocks * sizeof(u16));
-+ return -ENOMEM;
-+ }
-+
-+ inftl->VUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL);
-+ if (!inftl->VUtable) {
-+ kfree(inftl->PUtable);
-+ printk(KERN_WARNING "INFTL: allocation of VUtable "
-+ "failed (%zd bytes)\n",
-+ inftl->nb_blocks * sizeof(u16));
-+ return -ENOMEM;
-+ }
-+
-+ /* Mark the blocks before INFTL MediaHeader as reserved */
-+ for (i = 0; i < inftl->nb_boot_blocks; i++)
-+ inftl->PUtable[i] = BLOCK_RESERVED;
-+ /* Mark all remaining blocks as potentially containing data */
-+ for (; i < inftl->nb_blocks; i++)
-+ inftl->PUtable[i] = BLOCK_NOTEXPLORED;
-+
-+ /* Mark this boot record (NFTL MediaHeader) block as reserved */
-+ inftl->PUtable[block] = BLOCK_RESERVED;
-+
-+ /* Read Bad Erase Unit Table and modify PUtable[] accordingly */
-+ for (i = 0; i < inftl->nb_blocks; i++) {
-+ int physblock;
-+ /* If any of the physical eraseblocks are bad, don't
-+ use the unit. */
-+ for (physblock = 0; physblock < inftl->EraseSize; physblock += inftl->mbd.mtd->erasesize) {
-+ if (inftl->mbd.mtd->block_isbad(inftl->mbd.mtd, i * inftl->EraseSize + physblock))
-+ inftl->PUtable[i] = BLOCK_RESERVED;
-+ }
-+ }
-+
-+ inftl->MediaUnit = block;
-+ return 0;
-+ }
-+
-+ /* Not found. */
-+ return -1;
-+}
-+
-+static int memcmpb(void *a, int c, int n)
-+{
-+ int i;
-+ for (i = 0; i < n; i++) {
-+ if (c != ((unsigned char *)a)[i])
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+/*
-+ * check_free_sector: check if a free sector is actually FREE,
-+ * i.e. All 0xff in data and oob area.
-+ */
-+static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
-+ int len, int check_oob)
-+{
-+ u8 buf[SECTORSIZE + inftl->mbd.mtd->oobsize];
-+ size_t retlen;
-+ int i;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=%p,"
-+ "address=0x%x,len=%d,check_oob=%d)\n", inftl,
-+ address, len, check_oob);
-+
-+ for (i = 0; i < len; i += SECTORSIZE) {
-+ if (MTD_READECC(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &inftl->oobinfo) < 0)
-+ return -1;
-+ if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
-+ return -1;
-+
-+ if (check_oob) {
-+ if (memcmpb(buf + SECTORSIZE, 0xff, inftl->mbd.mtd->oobsize) != 0)
-+ return -1;
-+ }
-+ address += SECTORSIZE;
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * INFTL_format: format a Erase Unit by erasing ALL Erase Zones in the Erase
-+ * Unit and Update INFTL metadata. Each erase operation is
-+ * checked with check_free_sectors.
-+ *
-+ * Return: 0 when succeed, -1 on error.
-+ *
-+ * ToDo: 1. Is it neceressary to check_free_sector after erasing ??
-+ */
-+int INFTL_formatblock(struct INFTLrecord *inftl, int block)
-+{
-+ size_t retlen;
-+ struct inftl_unittail uci;
-+ struct erase_info *instr = &inftl->instr;
-+ int physblock;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=%p,"
-+ "block=%d)\n", inftl, block);
-+
-+ memset(instr, 0, sizeof(struct erase_info));
-+
-+ /* FIXME: Shouldn't we be setting the 'discarded' flag to zero
-+ _first_? */
-+
-+ /* Use async erase interface, test return code */
-+ instr->mtd = inftl->mbd.mtd;
-+ instr->addr = block * inftl->EraseSize;
-+ instr->len = inftl->mbd.mtd->erasesize;
-+ /* Erase one physical eraseblock at a time, even though the NAND api
-+ allows us to group them. This way we if we have a failure, we can
-+ mark only the failed block in the bbt. */
-+ for (physblock = 0; physblock < inftl->EraseSize; physblock += instr->len, instr->addr += instr->len) {
-+ MTD_ERASE(inftl->mbd.mtd, instr);
-+
-+ if (instr->state == MTD_ERASE_FAILED) {
-+ printk(KERN_WARNING "INFTL: error while formatting block %d\n",
-+ block);
-+ goto fail;
-+ }
-+
-+ /*
-+ * Check the "freeness" of Erase Unit before updating metadata.
-+ * FixMe: is this check really necessary? Since we have check the
-+ * return code after the erase operation.
-+ */
-+ if (check_free_sectors(inftl, instr->addr, instr->len, 1) != 0)
-+ goto fail;
-+ }
-+
-+ uci.EraseMark = cpu_to_le16(ERASE_MARK);
-+ uci.EraseMark1 = cpu_to_le16(ERASE_MARK);
-+ uci.Reserved[0] = 0;
-+ uci.Reserved[1] = 0;
-+ uci.Reserved[2] = 0;
-+ uci.Reserved[3] = 0;
-+ instr->addr = block * inftl->EraseSize + SECTORSIZE * 2;
-+ if (MTD_WRITEOOB(inftl->mbd.mtd, instr->addr +
-+ 8, 8, &retlen, (char *)&uci) < 0)
-+ goto fail;
-+ return 0;
-+fail:
-+ /* could not format, update the bad block table (caller is responsible
-+ for setting the PUtable to BLOCK_RESERVED on failure) */
-+ inftl->mbd.mtd->block_markbad(inftl->mbd.mtd, instr->addr);
-+ return -1;
-+}
-+
-+/*
-+ * format_chain: Format an invalid Virtual Unit chain. It frees all the Erase
-+ * Units in a Virtual Unit Chain, i.e. all the units are disconnected.
-+ *
-+ * Since the chain is invalid then we will have to erase it from its
-+ * head (normally for INFTL we go from the oldest). But if it has a
-+ * loop then there is no oldest...
-+ */
-+static void format_chain(struct INFTLrecord *inftl, unsigned int first_block)
-+{
-+ unsigned int block = first_block, block1;
-+
-+ printk(KERN_WARNING "INFTL: formatting chain at block %d\n",
-+ first_block);
-+
-+ for (;;) {
-+ block1 = inftl->PUtable[block];
-+
-+ printk(KERN_WARNING "INFTL: formatting block %d\n", block);
-+ if (INFTL_formatblock(inftl, block) < 0) {
-+ /*
-+ * Cannot format !!!! Mark it as Bad Unit,
-+ */
-+ inftl->PUtable[block] = BLOCK_RESERVED;
-+ } else {
-+ inftl->PUtable[block] = BLOCK_FREE;
-+ }
-+
-+ /* Goto next block on the chain */
-+ block = block1;
-+
-+ if (block == BLOCK_NIL || block >= inftl->lastEUN)
-+ break;
-+ }
-+}
-+
-+void INFTL_dumptables(struct INFTLrecord *s)
-+{
-+ int i;
-+
-+ printk("-------------------------------------------"
-+ "----------------------------------\n");
-+
-+ printk("VUtable[%d] ->", s->nb_blocks);
-+ for (i = 0; i < s->nb_blocks; i++) {
-+ if ((i % 8) == 0)
-+ printk("\n%04x: ", i);
-+ printk("%04x ", s->VUtable[i]);
-+ }
-+
-+ printk("\n-------------------------------------------"
-+ "----------------------------------\n");
-+
-+ printk("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks);
-+ for (i = 0; i <= s->lastEUN; i++) {
-+ if ((i % 8) == 0)
-+ printk("\n%04x: ", i);
-+ printk("%04x ", s->PUtable[i]);
-+ }
-+
-+ printk("\n-------------------------------------------"
-+ "----------------------------------\n");
-+
-+ printk("INFTL ->\n"
-+ " EraseSize = %d\n"
-+ " h/s/c = %d/%d/%d\n"
-+ " numvunits = %d\n"
-+ " firstEUN = %d\n"
-+ " lastEUN = %d\n"
-+ " numfreeEUNs = %d\n"
-+ " LastFreeEUN = %d\n"
-+ " nb_blocks = %d\n"
-+ " nb_boot_blocks = %d",
-+ s->EraseSize, s->heads, s->sectors, s->cylinders,
-+ s->numvunits, s->firstEUN, s->lastEUN, s->numfreeEUNs,
-+ s->LastFreeEUN, s->nb_blocks, s->nb_boot_blocks);
-+
-+ printk("\n-------------------------------------------"
-+ "----------------------------------\n");
-+}
-+
-+void INFTL_dumpVUchains(struct INFTLrecord *s)
-+{
-+ int logical, block, i;
-+
-+ printk("-------------------------------------------"
-+ "----------------------------------\n");
-+
-+ printk("INFTL Virtual Unit Chains:\n");
-+ for (logical = 0; logical < s->nb_blocks; logical++) {
-+ block = s->VUtable[logical];
-+ if (block > s->nb_blocks)
-+ continue;
-+ printk(" LOGICAL %d --> %d ", logical, block);
-+ for (i = 0; i < s->nb_blocks; i++) {
-+ if (s->PUtable[block] == BLOCK_NIL)
-+ break;
-+ block = s->PUtable[block];
-+ printk("%d ", block);
-+ }
-+ printk("\n");
-+ }
-+
-+ printk("-------------------------------------------"
-+ "----------------------------------\n");
-+}
-+
-+int INFTL_mount(struct INFTLrecord *s)
-+{
-+ unsigned int block, first_block, prev_block, last_block;
-+ unsigned int first_logical_block, logical_block, erase_mark;
-+ int chain_length, do_format_chain;
-+ struct inftl_unithead1 h0;
-+ struct inftl_unittail h1;
-+ size_t retlen;
-+ int i;
-+ u8 *ANACtable, ANAC;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_mount(inftl=%p)\n", s);
-+
-+ /* Search for INFTL MediaHeader and Spare INFTL Media Header */
-+ if (find_boot_record(s) < 0) {
-+ printk(KERN_WARNING "INFTL: could not find valid boot record?\n");
-+ return -1;
-+ }
-+
-+ /* Init the logical to physical table */
-+ for (i = 0; i < s->nb_blocks; i++)
-+ s->VUtable[i] = BLOCK_NIL;
-+
-+ logical_block = block = BLOCK_NIL;
-+
-+ /* Temporary buffer to store ANAC numbers. */
-+ ANACtable = kmalloc(s->nb_blocks * sizeof(u8), GFP_KERNEL);
-+ memset(ANACtable, 0, s->nb_blocks);
-+
-+ /*
-+ * First pass is to explore each physical unit, and construct the
-+ * virtual chains that exist (newest physical unit goes into VUtable).
-+ * Any block that is in any way invalid will be left in the
-+ * NOTEXPLORED state. Then at the end we will try to format it and
-+ * mark it as free.
-+ */
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 1, explore each unit\n");
-+ for (first_block = s->firstEUN; first_block <= s->lastEUN; first_block++) {
-+ if (s->PUtable[first_block] != BLOCK_NOTEXPLORED)
-+ continue;
-+
-+ do_format_chain = 0;
-+ first_logical_block = BLOCK_NIL;
-+ last_block = BLOCK_NIL;
-+ block = first_block;
-+
-+ for (chain_length = 0; ; chain_length++) {
-+
-+ if ((chain_length == 0) &&
-+ (s->PUtable[block] != BLOCK_NOTEXPLORED)) {
-+ /* Nothing to do here, onto next block */
-+ break;
-+ }
-+
-+ if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8,
-+ 8, &retlen, (char *)&h0) < 0 ||
-+ MTD_READOOB(s->mbd.mtd, block * s->EraseSize +
-+ 2 * SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0) {
-+ /* Should never happen? */
-+ do_format_chain++;
-+ break;
-+ }
-+
-+ logical_block = le16_to_cpu(h0.virtualUnitNo);
-+ prev_block = le16_to_cpu(h0.prevUnitNo);
-+ erase_mark = le16_to_cpu((h1.EraseMark | h1.EraseMark1));
-+ ANACtable[block] = h0.ANAC;
-+
-+ /* Previous block is relative to start of Partition */
-+ if (prev_block < s->nb_blocks)
-+ prev_block += s->firstEUN;
-+
-+ /* Already explored partial chain? */
-+ if (s->PUtable[block] != BLOCK_NOTEXPLORED) {
-+ /* Check if chain for this logical */
-+ if (logical_block == first_logical_block) {
-+ if (last_block != BLOCK_NIL)
-+ s->PUtable[last_block] = block;
-+ }
-+ break;
-+ }
-+
-+ /* Check for invalid block */
-+ if (erase_mark != ERASE_MARK) {
-+ printk(KERN_WARNING "INFTL: corrupt block %d "
-+ "in chain %d, chain length %d, erase "
-+ "mark 0x%x?\n", block, first_block,
-+ chain_length, erase_mark);
-+ /*
-+ * Assume end of chain, probably incomplete
-+ * fold/erase...
-+ */
-+ if (chain_length == 0)
-+ do_format_chain++;
-+ break;
-+ }
-+
-+ /* Check for it being free already then... */
-+ if ((logical_block == BLOCK_FREE) ||
-+ (logical_block == BLOCK_NIL)) {
-+ s->PUtable[block] = BLOCK_FREE;
-+ break;
-+ }
-+
-+ /* Sanity checks on block numbers */
-+ if ((logical_block >= s->nb_blocks) ||
-+ ((prev_block >= s->nb_blocks) &&
-+ (prev_block != BLOCK_NIL))) {
-+ if (chain_length > 0) {
-+ printk(KERN_WARNING "INFTL: corrupt "
-+ "block %d in chain %d?\n",
-+ block, first_block);
-+ do_format_chain++;
-+ }
-+ break;
-+ }
-+
-+ if (first_logical_block == BLOCK_NIL) {
-+ first_logical_block = logical_block;
-+ } else {
-+ if (first_logical_block != logical_block) {
-+ /* Normal for folded chain... */
-+ break;
-+ }
-+ }
-+
-+ /*
-+ * Current block is valid, so if we followed a virtual
-+ * chain to get here then we can set the previous
-+ * block pointer in our PUtable now. Then move onto
-+ * the previous block in the chain.
-+ */
-+ s->PUtable[block] = BLOCK_NIL;
-+ if (last_block != BLOCK_NIL)
-+ s->PUtable[last_block] = block;
-+ last_block = block;
-+ block = prev_block;
-+
-+ /* Check for end of chain */
-+ if (block == BLOCK_NIL)
-+ break;
-+
-+ /* Validate next block before following it... */
-+ if (block > s->lastEUN) {
-+ printk(KERN_WARNING "INFTL: invalid previous "
-+ "block %d in chain %d?\n", block,
-+ first_block);
-+ do_format_chain++;
-+ break;
-+ }
-+ }
-+
-+ if (do_format_chain) {
-+ format_chain(s, first_block);
-+ continue;
-+ }
-+
-+ /*
-+ * Looks like a valid chain then. It may not really be the
-+ * newest block in the chain, but it is the newest we have
-+ * found so far. We might update it in later iterations of
-+ * this loop if we find something newer.
-+ */
-+ s->VUtable[first_logical_block] = first_block;
-+ logical_block = BLOCK_NIL;
-+ }
-+
-+#ifdef CONFIG_MTD_DEBUG_VERBOSE
-+ if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
-+ INFTL_dumptables(s);
-+#endif
-+
-+ /*
-+ * Second pass, check for infinite loops in chains. These are
-+ * possible because we don't update the previous pointers when
-+ * we fold chains. No big deal, just fix them up in PUtable.
-+ */
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 2, validate virtual chains\n");
-+ for (logical_block = 0; logical_block < s->numvunits; logical_block++) {
-+ block = s->VUtable[logical_block];
-+ last_block = BLOCK_NIL;
-+
-+ /* Check for free/reserved/nil */
-+ if (block >= BLOCK_RESERVED)
-+ continue;
-+
-+ ANAC = ANACtable[block];
-+ for (i = 0; i < s->numvunits; i++) {
-+ if (s->PUtable[block] == BLOCK_NIL)
-+ break;
-+ if (s->PUtable[block] > s->lastEUN) {
-+ printk(KERN_WARNING "INFTL: invalid prev %d, "
-+ "in virtual chain %d\n",
-+ s->PUtable[block], logical_block);
-+ s->PUtable[block] = BLOCK_NIL;
-+
-+ }
-+ if (ANACtable[block] != ANAC) {
-+ /*
-+ * Chain must point back to itself. This is ok,
-+ * but we will need adjust the tables with this
-+ * newest block and oldest block.
-+ */
-+ s->VUtable[logical_block] = block;
-+ s->PUtable[last_block] = BLOCK_NIL;
-+ break;
-+ }
-+
-+ ANAC--;
-+ last_block = block;
-+ block = s->PUtable[block];
-+ }
-+
-+ if (i >= s->nb_blocks) {
-+ /*
-+ * Uhoo, infinite chain with valid ANACS!
-+ * Format whole chain...
-+ */
-+ format_chain(s, first_block);
-+ }
-+ }
-+
-+#ifdef CONFIG_MTD_DEBUG_VERBOSE
-+ if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
-+ INFTL_dumptables(s);
-+ if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
-+ INFTL_dumpVUchains(s);
-+#endif
-+
-+ /*
-+ * Third pass, format unreferenced blocks and init free block count.
-+ */
-+ s->numfreeEUNs = 0;
-+ s->LastFreeEUN = BLOCK_NIL;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 3, format unused blocks\n");
-+ for (block = s->firstEUN; block <= s->lastEUN; block++) {
-+ if (s->PUtable[block] == BLOCK_NOTEXPLORED) {
-+ printk("INFTL: unreferenced block %d, formatting it\n",
-+ block);
-+ if (INFTL_formatblock(s, block) < 0)
-+ s->PUtable[block] = BLOCK_RESERVED;
-+ else
-+ s->PUtable[block] = BLOCK_FREE;
-+ }
-+ if (s->PUtable[block] == BLOCK_FREE) {
-+ s->numfreeEUNs++;
-+ if (s->LastFreeEUN == BLOCK_NIL)
-+ s->LastFreeEUN = block;
-+ }
-+ }
-+
-+ kfree(ANACtable);
-+ return 0;
-+}
---- linux-2.4.21/drivers/mtd/maps/Config.in~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/Config.in
-@@ -1,16 +1,18 @@
- # drivers/mtd/maps/Config.in
-
--# $Id: Config.in,v 1.43 2003/01/24 14:26:38 dwmw2 Exp $
-+# $Id: Config.in,v 1.72 2005/02/27 21:50:21 ppopov Exp $
-
- mainmenu_option next_comment
-
- comment 'Mapping drivers for chip access'
-
--dep_tristate ' CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_GEN_PROBE
--if [ "$CONFIG_MTD_PHYSMAP" = "y" -o "$CONFIG_MTD_PHYSMAP" = "m" ]; then
-+bool ' Support for non-linear mappings of flash chips' CONFIG_MTD_COMPLEX_MAPPINGS
-+
-+bool ' CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_GEN_PROBE
-+if [ "$CONFIG_MTD_PHYSMAP" = "y" ]; then
- hex ' Physical start address of flash mapping' CONFIG_MTD_PHYSMAP_START 0x8000000
- hex ' Physical length of flash mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000
-- int ' Bus width in octets' CONFIG_MTD_PHYSMAP_BUSWIDTH 2
-+ int ' Bank width in octets' CONFIG_MTD_PHYSMAP_BANKWIDTH 2
- fi
-
- if [ "$CONFIG_SPARC" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
-@@ -21,41 +23,58 @@
- dep_tristate ' CFI Flash device mapped on Photron PNC-2000' CONFIG_MTD_PNC2000 $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS
- dep_tristate ' CFI Flash device mapped on AMD SC520 CDP' CONFIG_MTD_SC520CDP $CONFIG_MTD_CFI
- dep_tristate ' CFI Flash device mapped on AMD NetSc520' CONFIG_MTD_NETSC520 $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS
-- dep_tristate ' CFI Flash device mapped on Arcom SBC-GXx boards' CONFIG_MTD_SBC_GXX $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS
-- dep_tristate ' CFI Flash device mapped on Arcom ELAN-104NC' CONFIG_MTD_ELAN_104NC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS
-+ dep_tristate ' CFI Flash device mapped on Arcom SBC-GXx boards' CONFIG_MTD_SBC_GXX $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS $CONFIG_MTD_COMPLEX_MAPPINGS
-+ dep_tristate ' CFI Flash device mapped on Arcom ELAN-104NC' CONFIG_MTD_ELAN_104NC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS $CONFIG_MTD_COMPLEX_MAPPINGS
- dep_tristate ' CFI Flash device mapped on DIL/Net PC' CONFIG_MTD_DILNETPC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS $CONFIG_MTD_CONCAT
- if [ "$CONFIG_MTD_DILNETPC" = "y" -o "$CONFIG_MTD_DILNETPC" = "m" ]; then
- hex ' Size of boot partition' CONFIG_MTD_DILNETPC_BOOTSIZE 0x80000
- fi
-- dep_tristate ' JEDEC Flash device mapped on Mixcom piggyback card' CONFIG_MTD_MIXMEM $CONFIG_MTD_JEDEC
-- dep_tristate ' JEDEC Flash device mapped on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC
-- dep_tristate ' JEDEC Flash device mapped on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC
-+ dep_tristate ' JEDEC Flash device mapped on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC $CONFIG_MTD_COMPLEX_MAPPINGS
-+ dep_tristate ' JEDEC Flash device mapped on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC $CONFIG_MTD_COMPLEX_MAPPINGS
- dep_tristate ' Flash device mapped with DOCCS on NatSemi SCx200' CONFIG_MTD_SCx200_DOCFLASH $CONFIG_MTD_CFI
- dep_tristate ' BIOS flash chip on Intel L440GX boards' CONFIG_MTD_L440GX $CONFIG_MTD_JEDECPROBE
- dep_tristate ' ROM connected to AMD76X southbridge' CONFIG_MTD_AMD76XROM $CONFIG_MTD_GEN_PROBE
-- dep_tristate ' ROM connected to Intel Hub Controller 2' CONFIG_MTD_ICH2ROM $CONFIG_MTD_JEDECPROBE
-+ dep_tristate ' ROM connected to Intel Hub Controller 2/3/4/5' CONFIG_MTD_ICHXROM $CONFIG_MTD_JEDECPROBE
- dep_tristate ' CFI Flash device mapped on SnapGear/SecureEdge' CONFIG_MTD_NETtel $CONFIG_MTD_PARTITIONS
- dep_tristate ' BIOS flash chip on Intel SCB2 boards' CONFIG_MTD_SCB2_FLASH $CONFIG_MTD_GEN_PROBE
- fi
-
--if [ "$CONFIG_PPC" = "y" ]; then
-- dep_tristate ' CFI Flash device mapped on TQM8XXL' CONFIG_MTD_TQM8XXL $CONFIG_MTD_CFI $CONFIG_TQM8xxL
-+if [ "$CONFIG_PPC32" = "y" ]; then
-+ if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "y" ]; then
-+ dep_tristate ' Flash device on SBC8240' CONFIG_MTD_SBC8240 $CONFIG_MTD_JEDECPROBE
-+ fi
-+ if [ "$CONFIG_8xx" = "y" ]; then
-+ if [ "$CONFIG_TQM8xxL" = "y" ]; then
-+ dep_tristate ' CFI Flash device mapped on TQM8XXL' CONFIG_MTD_TQM8XXL $CONFIG_MTD_CFI
-+ fi
-+ if [ "$CONFIG_RPXLITE" = "y" -o "$CONFIG_RPXCLASSIC" = "y" ]; then
- dep_tristate ' CFI Flash device mapped on RPX Lite or CLLF' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI
-+ fi
-+ if [ "$CONFIG_MBX" = "y" ]; then
- dep_tristate ' System flash on MBX860 board' CONFIG_MTD_MBX860 $CONFIG_MTD_CFI
-+ fi
-+ if [ "$CONFIG_DBOX2" = "y" ]; then
- dep_tristate ' CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI
-+ fi
- dep_tristate ' CFI Flash device mapping on FlagaDM' CONFIG_MTD_CFI_FLAGADM $CONFIG_MTD_CFI
-- dep_tristate ' CFI Flash device mapped on IBM Redwood-4/5' CONFIG_MTD_REDWOOD $CONFIG_MTD_CFI
-+ fi
-+ if [ "$CONFIG_4xx" = "y" ]; then
-+ if [ "$CONFIG_40x" = "y" ]; then
-+ if [ "$CONFIG_REDWOOD_4" = "y" -o "$CONFIG_REDWOOD_5" = "y" -o "$CONFIG_REDWOOD_6" = "y" ]; then
-+ dep_tristate ' CFI Flash device mapped on IBM Redwood' CONFIG_MTD_REDWOOD $CONFIG_MTD_CFI
-+ fi
-+ dep_tristate ' CFI Flash device mapped on IBM Beech' CONFIG_MTD_BEECH $CONFIG_MTD_CFI $CONFIG_BEECH
-+ dep_tristate ' CFI Flash device mapped on IBM Arctic' CONFIG_MTD_ARCTIC $CONFIG_MTD_CFI $CONFIG_ARCTIC2
-+ dep_tristate ' Flash device mapped on IBM Walnut' CONFIG_MTD_WALNUT $CONFIG_MTD_JEDECPROBE $CONFIG_WALNUT
-+ fi
-+ if [ "$CONFIG_440" = "y" ]; then
-+ dep_tristate ' Flash devices mapped on IBM Ebony' CONFIG_MTD_EBONY $CONFIG_MTD_JEDECPROBE $CONFIG_EBONY
-+ fi
-+ fi
- fi
-
--if [ "$CONFIG_MIPS" = "y" ]; then
-- dep_tristate ' Pb1000 MTD support' CONFIG_MTD_PB1000 $CONFIG_MIPS_PB1000
-- dep_tristate ' Pb1500 MTD support' CONFIG_MTD_PB1500 $CONFIG_MIPS_PB1500
-- dep_tristate ' Pb1100 MTD support' CONFIG_MTD_PB1100 $CONFIG_MIPS_PB1100
-- if [ "$CONFIG_MTD_PB1500" = "y" -o "$CONFIG_MTD_PB1500" = "m" \
-- -o "$CONFIG_MTD_PB1100" = "y" -o "$CONFIG_MTD_PB1100" = "m" ]; then
-- bool ' Pb[15]00 boot flash device' CONFIG_MTD_PB1500_BOOT
-- bool ' Pb[15]00 user flash device (2nd 32MiB bank)' CONFIG_MTD_PB1500_USER
-- fi
-+if [ "$CONFIG_MIPS" = "y" -o "$CONFIG_MIPS64" = "y" ]; then
-+ dep_tristate ' AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support' CONFIG_MTD_ALCHEMY $CONFIG_SOC_AU1X00
- dep_tristate ' Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board' CONFIG_MTD_CSTM_MIPS_IXX $CONFIG_MTD_CFI $CONFIG_MTD_JEDEC $CONFIG_MTD_PARTITIONS
- if [ "$CONFIG_MTD_CSTM_MIPS_IXX" = "y" -o "$CONFIG_MTD_CSTM_MIPS_IXX" = "m" ]; then
- hex ' Physical start address of flash mapping' CONFIG_MTD_CSTM_MIPS_IXX_START 0x8000000
-@@ -63,7 +82,7 @@
- int ' Bus width in octets' CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH 2
- fi
- dep_tristate ' Momenco Ocelot boot flash device' CONFIG_MTD_OCELOT $CONFIG_MOMENCO_OCELOT
-- dep_tristate ' LASAT flash device' CONFIG_MTD_LASAT $CONFIG_MTD_CFI $CONFIG_LASAT
-+ dep_tristate ' LASAT flash device' CONFIG_MTD_LASAT $CONFIG_LASAT
- fi
-
- if [ "$CONFIG_SUPERH" = "y" ]; then
-@@ -75,22 +94,25 @@
- fi
-
- if [ "$CONFIG_ARM" = "y" ]; then
-- dep_tristate ' CFI Flash device mapped on Lubbock board' CONFIG_MTD_LUBBOCK $CONFIG_MTD_CFI $CONFIG_ARCH_LUBBOCK $CONFIG_MTD_PARTITIONS
-- dep_tristate ' CFI Flash device mapped on Nora' CONFIG_MTD_NORA $CONFIG_MTD_CFI
- dep_tristate ' CFI Flash device mapped on ARM Integrator/P720T' CONFIG_MTD_ARM_INTEGRATOR $CONFIG_MTD_CFI
- dep_tristate ' Cirrus CDB89712 evaluation board mappings' CONFIG_MTD_CDB89712 $CONFIG_MTD_CFI $CONFIG_ARCH_CDB89712
- dep_tristate ' CFI Flash device mapped on StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS
-- dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE
-+ dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE $CONFIG_MTD_COMPLEX_MAPPINGS
- dep_tristate ' CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_ARCH_IQ80310
-- dep_tristate ' CFI Flash device mapped on the FortuNet board' CONFIG_MTD_FORTUNET $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_FORTUNET
-- dep_tristate ' CFI Flash device mapped on Epxa' CONFIG_MTD_EPXA $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT
-+ dep_tristate ' CFI Flash device mapped on the XScale Lubbock board' CONFIG_MTD_LUBBOCK $CONFIG_MTD_CFI $CONFIG_ARCH_LUBBOCK
-+ dep_tristate ' CFI Flash device mapped on Ramses board' CONFIG_MTD_RAMSES $CONFIG_MTD_CFI $CONFIG_ARCH_RAMSES $CONFIG_MTD_PARTITIONS
-+ dep_tristate ' CFI Flash device mapped on XScale IXP425 systems' CONFIG_MTD_IXP425 $CONFIG_MTD_CFI $CONFIG_MTD_COMPLEX_MAPPINGS
-+ dep_tristate ' CFI Flash device mapped on Epxa10db' CONFIG_MTD_EPXA10DB $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT
-+ dep_tristate ' CFI Flash device mapped on the FortuNet board' CONFIG_MTD_FORTUNET $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_SA1100_FORTUNET
- dep_tristate ' NV-RAM mapping AUTCPU12 board' CONFIG_MTD_AUTCPU12 $CONFIG_ARCH_AUTCPU12
-- dep_tristate ' CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_ARCH_EDB7212 $CONFIG_MTD_CFI
-+ dep_tristate ' CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_MTD_CFI
-+ dep_tristate ' CFI Flash device mapped on Hynix evaluation boards' CONFIG_MTD_H720X $CONFIG_MTD_CFI
- dep_tristate ' JEDEC Flash device mapped on impA7' CONFIG_MTD_IMPA7 $CONFIG_MTD_JEDECPROBE
- dep_tristate ' JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame' CONFIG_MTD_CEIVA $CONFIG_MTD_JEDECPROBE $CONFIG_ARCH_CEIVA
-+ dep_tristate ' NOR Flash device on TOTO board' CONFIG_MTD_NOR_TOTO $CONFIG_MTD $CONFIG_OMAP_TOTO
- fi
- if [ "$CONFIG_ALPHA" = "y" ]; then
-- dep_tristate ' Flash chip mapping on TSUNAMI' CONFIG_MTD_TSUNAMI $CONFIG_MTD_GENPROBE
-+ dep_tristate ' Flash chip mapping on TSUNAMI' CONFIG_MTD_TSUNAMI $CONFIG_MTD_GENPROBE $CONFIG_MTD_COMPLEX_MAPPINGS
- fi
-
- if [ "$CONFIG_UCLINUX" = "y" ]; then
-@@ -98,7 +120,7 @@
- fi
-
- # This needs CFI or JEDEC, depending on the cards found.
--dep_tristate ' PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI
--dep_tristate ' PCMCIA MTD driver' CONFIG_MTD_PCMCIA $CONFIG_MTD $CONFIG_PCMCIA
-+dep_tristate ' PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI $CONFIG_MTD_COMPLEX_MAPPINGS
-+dep_tristate ' PCMCIA MTD driver' CONFIG_MTD_PCMCIA $CONFIG_MTD $CONFIG_PCMCIA $CONFIG_MTD_COMPLEX_MAPPINGS
-
- endmenu
---- linux-2.4.21/drivers/mtd/maps/Makefile~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/Makefile
-@@ -1,67 +1,11 @@
- #
--# linux/drivers/maps/Makefile
-+# linux/drivers/maps/Makefile.24
-+# Makefile for obsolete kernels
- #
--# $Id: Makefile,v 1.37 2003/01/24 14:26:38 dwmw2 Exp $
-+# $Id: Makefile.24,v 1.1 2004/07/12 16:08:16 dwmw2 Exp $
-
- O_TARGET := mapslink.o
-+export-objs := map_funcs.o
-
--# Chip mappings
--obj-$(CONFIG_MTD_CDB89712) += cdb89712.o
--obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o
--obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
--obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
--obj-$(CONFIG_MTD_DC21285) += dc21285.o
--obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o
--obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o
--obj-$(CONFIG_MTD_EPXA) += epxa-flash.o
--obj-$(CONFIG_MTD_IQ80310) += iq80310.o
--obj-$(CONFIG_MTD_LUBBOCK) += lubbock.o
--obj-$(CONFIG_MTD_PXA_CERF) += pxa_cerf.o
--obj-$(CONFIG_MTD_TRIZEPS2) += trizeps2.o
--obj-$(CONFIG_MTD_L440GX) += l440gx.o
--obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o
--obj-$(CONFIG_MTD_ICH2ROM) += ich2rom.o
--obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o
--obj-$(CONFIG_MTD_MBX860) += mbx860.o
--obj-$(CONFIG_MTD_NORA) += nora.o
--obj-$(CONFIG_MTD_CEIVA) += ceiva.o
--obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o
--ifneq ($(CONFIG_MTD_PHYSMAP),n)
-- ifeq ($(CONFIG_MTD_PHYSMAP_BUSWIDTH),8)
-- obj-$(CONFIG_MTD_PHYSMAP) += physmap64.o
-- else
-- obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
-- endif
--endif
--obj-$(CONFIG_MTD_PNC2000) += pnc2000.o
--obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
--obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
--obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o
--obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
--ifeq ($(CONFIG_ASSABET_NEPONSET),y)
-- obj-$(CONFIG_MTD_SA1100) += neponset-flash.o
--endif
--obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o
--obj-$(CONFIG_MTD_SC520CDP) += sc520cdp.o
--obj-$(CONFIG_MTD_NETSC520) += netsc520.o
--obj-$(CONFIG_MTD_SUN_UFLASH) += sun_uflash.o
--obj-$(CONFIG_MTD_VMAX) += vmax301.o
--obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
--obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o
--obj-$(CONFIG_MTD_OCELOT) += ocelot.o
--obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
--obj-$(CONFIG_MTD_PCI) += pci.o
--obj-$(CONFIG_MTD_PB1000) += pb1xxx-flash.o
--obj-$(CONFIG_MTD_PB1100) += pb1xxx-flash.o
--obj-$(CONFIG_MTD_PB1500) += pb1xxx-flash.o
--obj-$(CONFIG_MTD_LASAT) += lasat.o
--obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o
--obj-$(CONFIG_MTD_EDB7312) += edb7312.o
--obj-$(CONFIG_MTD_IMPA7) += impa7.o
--obj-$(CONFIG_MTD_FORTUNET) += fortunet.o
--obj-$(CONFIG_MTD_REDWOOD) += redwood.o
--obj-$(CONFIG_MTD_UCLINUX) += uclinux.o
--obj-$(CONFIG_MTD_NETtel) += nettel.o
--obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o
--
-+include Makefile.common
- include $(TOPDIR)/Rules.make
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/Makefile.common
-@@ -0,0 +1,73 @@
-+#
-+# linux/drivers/maps/Makefile
-+#
-+# $Id: Makefile.common,v 1.27 2005/03/07 23:15:48 joern Exp $
-+
-+ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y)
-+obj-$(CONFIG_MTD) += map_funcs.o
-+endif
-+
-+# Chip mappings
-+obj-$(CONFIG_MTD_CDB89712) += cdb89712.o
-+obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o
-+obj-$(CONFIG_MTD_BAST) += bast-flash.o
-+obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
-+obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
-+obj-$(CONFIG_MTD_DC21285) += dc21285.o
-+obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o
-+obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o
-+obj-$(CONFIG_MTD_IQ80310) += iq80310.o
-+obj-$(CONFIG_MTD_L440GX) += l440gx.o
-+obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o
-+obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o
-+obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o
-+obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o
-+obj-$(CONFIG_MTD_RAMSES) += ramses.o
-+obj-$(CONFIG_MTD_MBX860) += mbx860.o
-+obj-$(CONFIG_MTD_CEIVA) += ceiva.o
-+obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o
-+obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
-+obj-$(CONFIG_MTD_MULTI_PHYSMAP) += mphysmap.o
-+obj-$(CONFIG_MTD_PNC2000) += pnc2000.o
-+obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
-+obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
-+obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o
-+obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
-+obj-$(CONFIG_MTD_IPAQ) += ipaq-flash.o
-+obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o
-+obj-$(CONFIG_MTD_SC520CDP) += sc520cdp.o
-+obj-$(CONFIG_MTD_NETSC520) += netsc520.o
-+obj-$(CONFIG_MTD_TS5500) += ts5500_flash.o
-+obj-$(CONFIG_MTD_SUN_UFLASH) += sun_uflash.o
-+obj-$(CONFIG_MTD_VMAX) += vmax301.o
-+obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
-+obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o
-+obj-$(CONFIG_MTD_OCELOT) += ocelot.o
-+obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
-+obj-$(CONFIG_MTD_PCI) += pci.o
-+obj-$(CONFIG_MTD_ALCHEMY) += alchemy-flash.o
-+obj-$(CONFIG_MTD_LASAT) += lasat.o
-+obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o
-+obj-$(CONFIG_MTD_EDB7312) += edb7312.o
-+obj-$(CONFIG_MTD_IMPA7) += impa7.o
-+obj-$(CONFIG_MTD_FORTUNET) += fortunet.o
-+obj-$(CONFIG_MTD_REDWOOD) += redwood.o
-+obj-$(CONFIG_MTD_CHESTNUT) += chestnut.o
-+obj-$(CONFIG_MTD_UCLINUX) += uclinux.o
-+obj-$(CONFIG_MTD_NETtel) += nettel.o
-+obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o
-+obj-$(CONFIG_MTD_EBONY) += ebony.o
-+obj-$(CONFIG_MTD_OCOTEA) += ocotea.o
-+obj-$(CONFIG_MTD_BEECH) += beech-mtd.o
-+obj-$(CONFIG_MTD_ARCTIC) += arctic-mtd.o
-+obj-$(CONFIG_MTD_WALNUT) += walnut.o
-+obj-$(CONFIG_MTD_H720X) += h720x-flash.o
-+obj-$(CONFIG_MTD_SBC8240) += sbc8240.o
-+obj-$(CONFIG_MTD_NOR_TOTO) += omap-toto-flash.o
-+obj-$(CONFIG_MTD_MPC1211) += mpc1211.o
-+obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o
-+obj-$(CONFIG_MTD_IXP2000) += ixp2000.o
-+obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o
-+obj-$(CONFIG_MTD_DMV182) += dmv182.o
-+obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o
-+obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o
---- linux-2.4.21/drivers/mtd/maps/amd76xrom.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/amd76xrom.c
-@@ -2,133 +2,138 @@
- * amd76xrom.c
- *
- * Normal mappings of chips in physical memory
-- * $Id: amd76xrom.c,v 1.1 2002/10/18 22:45:48 eric Exp $
-+ * $Id: amd76xrom.c,v 1.19 2004/11/28 09:40:39 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/mtd/cfi.h>
-+#include <linux/mtd/flashchip.h>
- #include <linux/config.h>
- #include <linux/pci.h>
- #include <linux/pci_ids.h>
-+#include <linux/list.h>
-+
-+
-+#define xstr(s) str(s)
-+#define str(s) #s
-+#define MOD_NAME xstr(KBUILD_BASENAME)
-+
-+#define ADDRESS_NAME_LEN 18
-+
-+#define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */
-
-+struct amd76xrom_window {
-+ void __iomem *virt;
-+ unsigned long phys;
-+ unsigned long size;
-+ struct list_head maps;
-+ struct resource rsrc;
-+ struct pci_dev *pdev;
-+};
-
- struct amd76xrom_map_info {
-+ struct list_head list;
- struct map_info map;
- struct mtd_info *mtd;
-- unsigned long window_addr;
-- u32 window_start, window_size;
-- struct pci_dev *pdev;
-+ struct resource rsrc;
-+ char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
- };
-
--static __u8 amd76xrom_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--static __u16 amd76xrom_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--static __u32 amd76xrom_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--static void amd76xrom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
-+static struct amd76xrom_window amd76xrom_window = {
-+ .maps = LIST_HEAD_INIT(amd76xrom_window.maps),
-+};
-
--static void amd76xrom_write8(struct map_info *map, __u8 d, unsigned long adr)
-+static void amd76xrom_cleanup(struct amd76xrom_window *window)
- {
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
-+ struct amd76xrom_map_info *map, *scratch;
-+ u8 byte;
-
--static void amd76xrom_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
-+ if (window->pdev) {
-+ /* Disable writes through the rom window */
-+ pci_read_config_byte(window->pdev, 0x40, &byte);
-+ pci_write_config_byte(window->pdev, 0x40, byte & ~1);
-+ }
-
--static void amd76xrom_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
-+ /* Free all of the mtd devices */
-+ list_for_each_entry_safe(map, scratch, &window->maps, list) {
-+ if (map->rsrc.parent) {
-+ release_resource(&map->rsrc);
-+ }
-+ del_mtd_device(map->mtd);
-+ map_destroy(map->mtd);
-+ list_del(&map->list);
-+ kfree(map);
-+ }
-+ if (window->rsrc.parent)
-+ release_resource(&window->rsrc);
-
--static void amd76xrom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
-+ if (window->virt) {
-+ iounmap(window->virt);
-+ window->virt = NULL;
-+ window->phys = 0;
-+ window->size = 0;
-+ window->pdev = NULL;
-+ }
- }
-
--static struct amd76xrom_map_info amd76xrom_map = {
-- map: {
-- name: "AMD76X rom",
-- size: 0,
-- buswidth: 1,
-- read8: amd76xrom_read8,
-- read16: amd76xrom_read16,
-- read32: amd76xrom_read32,
-- copy_from: amd76xrom_copy_from,
-- write8: amd76xrom_write8,
-- write16: amd76xrom_write16,
-- write32: amd76xrom_write32,
-- copy_to: amd76xrom_copy_to,
-- /* The standard rom socket is for single power supply chips
-- * that don't have an extra vpp.
-- */
-- },
-- mtd: 0,
-- window_addr: 0,
--};
-
- static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
- const struct pci_device_id *ent)
- {
-- struct rom_window {
-- u32 start;
-- u32 size;
-- u8 segen_bits;
-- };
-- static struct rom_window rom_window[] = {
-- { 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), },
-- { 0xffc00000, 4*1024*1024, (1<<7), },
-- { 0xffff0000, 64*1024, 0 },
-- { 0 , 0, 0 },
-- };
-- static const u32 rom_probe_sizes[] = {
-- 5*1024*1024, 4*1024*1024, 2*1024*1024, 1024*1024, 512*1024,
-- 256*1024, 128*1024, 64*1024, 0};
-- static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", 0 };
-+ static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
- u8 byte;
-- struct amd76xrom_map_info *info = &amd76xrom_map;
-- struct rom_window *window;
-- int i;
-- u32 rom_size;
-+ struct amd76xrom_window *window = &amd76xrom_window;
-+ struct amd76xrom_map_info *map = NULL;
-+ unsigned long map_top;
-
-- window = &rom_window[0];
--#if 0
-- while(window->size) {
-- if (request_mem_region(window->start, window->size, "amd76xrom")) {
-- break;
-+ /* Remember the pci dev I find the window in */
-+ window->pdev = pdev;
-+
-+ /* Assume the rom window is properly setup, and find it's size */
-+ pci_read_config_byte(pdev, 0x43, &byte);
-+ if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6))) {
-+ window->phys = 0xffb00000; /* 5MiB */
- }
-- window++;
-+ else if ((byte & (1<<7)) == (1<<7)) {
-+ window->phys = 0xffc00000; /* 4MiB */
- }
-- if (!window->size) {
-- printk(KERN_ERR "amd76xrom: cannot reserve rom window\n");
-- goto err_out_none;
-+ else {
-+ window->phys = 0xffff0000; /* 64KiB */
-+ }
-+ window->size = 0xffffffffUL - window->phys + 1UL;
-+
-+ /*
-+ * Try to reserve the window mem region. If this fails then
-+ * it is likely due to a fragment of the window being
-+ * "reseved" by the BIOS. In the case that the
-+ * request_mem_region() fails then once the rom size is
-+ * discovered we will try to reserve the unreserved fragment.
-+ */
-+ window->rsrc.name = MOD_NAME;
-+ window->rsrc.start = window->phys;
-+ window->rsrc.end = window->phys + window->size - 1;
-+ window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-+ if (request_resource(&iomem_resource, &window->rsrc)) {
-+ window->rsrc.parent = NULL;
-+ printk(KERN_ERR MOD_NAME
-+ " %s(): Unable to register resource"
-+ " 0x%.08lx-0x%.08lx - kernel bug?\n",
-+ __func__,
-+ window->rsrc.start, window->rsrc.end);
- }
--#endif
-+
-+#if 0
-
- /* Enable the selected rom window */
- pci_read_config_byte(pdev, 0x43, &byte);
-- pci_write_config_byte(pdev, 0x43, byte | window->segen_bits);
-+ pci_write_config_byte(pdev, 0x43, byte | rwindow->segen_bits);
-+#endif
-
- /* Enable writes through the rom window */
- pci_read_config_byte(pdev, 0x40, &byte);
-@@ -136,78 +141,149 @@
-
- /* FIXME handle registers 0x80 - 0x8C the bios region locks */
-
-- printk(KERN_NOTICE "amd76xrom window : %x at %x\n",
-- window->size, window->start);
- /* For write accesses caches are useless */
-- info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size);
-+ window->virt = ioremap_nocache(window->phys, window->size);
-+ if (!window->virt) {
-+ printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
-+ window->phys, window->size);
-+ goto out;
-+ }
-
-- if (!info->window_addr) {
-- printk(KERN_ERR "Failed to ioremap\n");
-- goto err_out_free_mmio_region;
-+ /* Get the first address to look for an rom chip at */
-+ map_top = window->phys;
-+#if 1
-+ /* The probe sequence run over the firmware hub lock
-+ * registers sets them to 0x7 (no access).
-+ * Probe at most the last 4M of the address space.
-+ */
-+ if (map_top < 0xffc00000) {
-+ map_top = 0xffc00000;
- }
-- info->mtd = 0;
-- for(i = 0; (rom_size = rom_probe_sizes[i]); i++) {
-- char **chip_type;
-- if (rom_size > window->size) {
-+#endif
-+ /* Loop through and look for rom chips */
-+ while((map_top - 1) < 0xffffffffUL) {
-+ struct cfi_private *cfi;
-+ unsigned long offset;
-+ int i;
-+
-+ if (!map) {
-+ map = kmalloc(sizeof(*map), GFP_KERNEL);
-+ }
-+ if (!map) {
-+ printk(KERN_ERR MOD_NAME ": kmalloc failed");
-+ goto out;
-+ }
-+ memset(map, 0, sizeof(*map));
-+ INIT_LIST_HEAD(&map->list);
-+ map->map.name = map->map_name;
-+ map->map.phys = map_top;
-+ offset = map_top - window->phys;
-+ map->map.virt = (void __iomem *)
-+ (((unsigned long)(window->virt)) + offset);
-+ map->map.size = 0xffffffffUL - map_top + 1UL;
-+ /* Set the name of the map to the address I am trying */
-+ sprintf(map->map_name, "%s @%08lx",
-+ MOD_NAME, map->map.phys);
-+
-+ /* There is no generic VPP support */
-+ for(map->map.bankwidth = 32; map->map.bankwidth;
-+ map->map.bankwidth >>= 1)
-+ {
-+ char **probe_type;
-+ /* Skip bankwidths that are not supported */
-+ if (!map_bankwidth_supported(map->map.bankwidth))
- continue;
-+
-+ /* Setup the map methods */
-+ simple_map_init(&map->map);
-+
-+ /* Try all of the probe methods */
-+ probe_type = rom_probe_types;
-+ for(; *probe_type; probe_type++) {
-+ map->mtd = do_map_probe(*probe_type, &map->map);
-+ if (map->mtd)
-+ goto found;
- }
-- info->map.map_priv_1 =
-- info->window_addr + window->size - rom_size;
-- info->map.size = rom_size;
-- chip_type = rom_probe_types;
-- for(; !info->mtd && *chip_type; chip_type++) {
-- info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map);
- }
-- if (info->mtd) {
-- break;
-+ map_top += ROM_PROBE_STEP_SIZE;
-+ continue;
-+ found:
-+ /* Trim the size if we are larger than the map */
-+ if (map->mtd->size > map->map.size) {
-+ printk(KERN_WARNING MOD_NAME
-+ " rom(%u) larger than window(%lu). fixing...\n",
-+ map->mtd->size, map->map.size);
-+ map->mtd->size = map->map.size;
-+ }
-+ if (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.
-+ */
-+ map->rsrc.name = map->map_name;
-+ map->rsrc.start = map->map.phys;
-+ map->rsrc.end = map->map.phys + map->mtd->size - 1;
-+ map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-+ if (request_resource(&window->rsrc, &map->rsrc)) {
-+ printk(KERN_ERR MOD_NAME
-+ ": cannot reserve MTD resource\n");
-+ map->rsrc.parent = NULL;
- }
- }
-- if (!info->mtd) {
-- goto err_out_iounmap;
-+
-+ /* Make the whole region visible in the map */
-+ map->map.virt = window->virt;
-+ map->map.phys = window->phys;
-+ cfi = map->map.fldrv_priv;
-+ for(i = 0; i < cfi->numchips; i++) {
-+ cfi->chips[i].start += offset;
- }
-- printk(KERN_NOTICE "amd76xrom chip at offset: %x\n",
-- window->size - rom_size);
-
-- info->mtd->module = THIS_MODULE;
-- add_mtd_device(info->mtd);
-- info->window_start = window->start;
-- info->window_size = window->size;
-- return 0;
-+ /* Now that the mtd devices is complete claim and export it */
-+ map->mtd->owner = THIS_MODULE;
-+ if (add_mtd_device(map->mtd)) {
-+ map_destroy(map->mtd);
-+ map->mtd = NULL;
-+ goto out;
-+ }
-
--err_out_iounmap:
-- iounmap((void *)(info->window_addr));
--err_out_free_mmio_region:
-- release_mem_region(window->start, window->size);
--err_out_none:
-+
-+ /* Calculate the new value of map_top */
-+ map_top += map->mtd->size;
-+
-+ /* File away the map structure */
-+ list_add(&map->list, &window->maps);
-+ map = NULL;
-+ }
-+
-+ out:
-+ /* Free any left over map structures */
-+ if (map) {
-+ kfree(map);
-+ }
-+ /* See if I have any map structures */
-+ if (list_empty(&window->maps)) {
-+ amd76xrom_cleanup(window);
- return -ENODEV;
-+ }
-+ return 0;
- }
-
-
- static void __devexit amd76xrom_remove_one (struct pci_dev *pdev)
- {
-- struct amd76xrom_map_info *info = &amd76xrom_map;
-- u8 byte;
--
-- del_mtd_device(info->mtd);
-- map_destroy(info->mtd);
-- info->mtd = 0;
-- info->map.map_priv_1 = 0;
--
-- iounmap((void *)(info->window_addr));
-- info->window_addr = 0;
--
-- /* Disable writes through the rom window */
-- pci_read_config_byte(pdev, 0x40, &byte);
-- pci_write_config_byte(pdev, 0x40, byte & ~1);
-+ struct amd76xrom_window *window = &amd76xrom_window;
-
-- release_mem_region(info->window_start, info->window_size);
-+ amd76xrom_cleanup(window);
- }
-
--static struct pci_device_id amd76xrom_pci_tbl[] __devinitdata = {
-+static struct pci_device_id amd76xrom_pci_tbl[] = {
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,
- PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440,
- PCI_ANY_ID, PCI_ANY_ID, },
-+ { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */
- { 0, }
- };
-
-@@ -215,26 +291,25 @@
-
- #if 0
- static struct pci_driver amd76xrom_driver = {
-- name: "amd76xrom",
-- id_table: amd76xrom_pci_tbl,
-- probe: amd76xrom_init_one,
-- remove: amd76xrom_remove_one,
-+ .name = MOD_NAME,
-+ .id_table = amd76xrom_pci_tbl,
-+ .probe = amd76xrom_init_one,
-+ .remove = amd76xrom_remove_one,
- };
- #endif
-
--int __init init_amd76xrom(void)
-+static int __init init_amd76xrom(void)
- {
- struct pci_dev *pdev;
- struct pci_device_id *id;
-- pdev = 0;
-+ pdev = NULL;
- for(id = amd76xrom_pci_tbl; id->vendor; id++) {
-- pdev = pci_find_device(id->vendor, id->device, 0);
-+ pdev = pci_find_device(id->vendor, id->device, NULL);
- if (pdev) {
- break;
- }
- }
- if (pdev) {
-- amd76xrom_map.pdev = pdev;
- return amd76xrom_init_one(pdev, &amd76xrom_pci_tbl[0]);
- }
- return -ENXIO;
-@@ -245,7 +320,7 @@
-
- static void __exit cleanup_amd76xrom(void)
- {
-- amd76xrom_remove_one(amd76xrom_map.pdev);
-+ amd76xrom_remove_one(amd76xrom_window.pdev);
- }
-
- module_init(init_amd76xrom);
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/arctic-mtd.c
-@@ -0,0 +1,135 @@
-+/*
-+ * $Id: arctic-mtd.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $
-+ *
-+ * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for
-+ * IBM 405LP Arctic boards.
-+ *
-+ * This program is free software; 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
-+ *
-+ * Copyright (C) 2002, International Business Machines Corporation
-+ * All Rights Reserved.
-+ *
-+ * Bishop Brock
-+ * IBM Research, Austin Center for Low-Power Computing
-+ * bcbrock@us.ibm.com
-+ * March 2002
-+ *
-+ * modified for Arctic by,
-+ * David Gibson
-+ * IBM OzLabs, Canberra, Australia
-+ * <arctic@gibson.dropbear.id.au>
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/io.h>
-+#include <asm/ibm4xx.h>
-+
-+/*
-+ * 0 : 0xFE00 0000 - 0xFEFF FFFF : Filesystem 1 (16MiB)
-+ * 1 : 0xFF00 0000 - 0xFF4F FFFF : kernel (5.12MiB)
-+ * 2 : 0xFF50 0000 - 0xFFF5 FFFF : Filesystem 2 (10.624MiB) (if non-XIP)
-+ * 3 : 0xFFF6 0000 - 0xFFFF FFFF : PIBS Firmware (640KiB)
-+ */
-+
-+#define FFS1_SIZE 0x01000000 /* 16MiB */
-+#define KERNEL_SIZE 0x00500000 /* 5.12MiB */
-+#define FFS2_SIZE 0x00a60000 /* 10.624MiB */
-+#define FIRMWARE_SIZE 0x000a0000 /* 640KiB */
-+
-+
-+#define NAME "Arctic Linux Flash"
-+#define PADDR SUBZERO_BOOTFLASH_PADDR
-+#define BUSWIDTH 2
-+#define SIZE SUBZERO_BOOTFLASH_SIZE
-+#define PARTITIONS 4
-+
-+/* Flash memories on these boards are memory resources, accessed big-endian. */
-+
-+{
-+ /* do nothing for now */
-+}
-+
-+static struct map_info arctic_mtd_map = {
-+ .name = NAME,
-+ .size = SIZE,
-+ .bankwidth = BUSWIDTH,
-+ .phys = PADDR,
-+};
-+
-+static struct mtd_info *arctic_mtd;
-+
-+static struct mtd_partition arctic_partitions[PARTITIONS] = {
-+ { .name = "Filesystem",
-+ .size = FFS1_SIZE,
-+ .offset = 0,},
-+ { .name = "Kernel",
-+ .size = KERNEL_SIZE,
-+ .offset = FFS1_SIZE,},
-+ { .name = "Filesystem",
-+ .size = FFS2_SIZE,
-+ .offset = FFS1_SIZE + KERNEL_SIZE,},
-+ { .name = "Firmware",
-+ .size = FIRMWARE_SIZE,
-+ .offset = SUBZERO_BOOTFLASH_SIZE - FIRMWARE_SIZE,},
-+};
-+
-+static int __init
-+init_arctic_mtd(void)
-+{
-+ printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
-+
-+ arctic_mtd_map.virt = ioremap(PADDR, SIZE);
-+
-+ if (!arctic_mtd_map.virt) {
-+ printk("%s: failed to ioremap 0x%x\n", NAME, PADDR);
-+ return -EIO;
-+ }
-+ simple_map_init(&arctic_mtd_map);
-+
-+ printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
-+ arctic_mtd = do_map_probe("cfi_probe", &arctic_mtd_map);
-+
-+ if (!arctic_mtd)
-+ return -ENXIO;
-+
-+ arctic_mtd->owner = THIS_MODULE;
-+
-+ return add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS);
-+}
-+
-+static void __exit
-+cleanup_arctic_mtd(void)
-+{
-+ if (arctic_mtd) {
-+ del_mtd_partitions(arctic_mtd);
-+ map_destroy(arctic_mtd);
-+ iounmap((void *) arctic_mtd_map.virt);
-+ }
-+}
-+
-+module_init(init_arctic_mtd);
-+module_exit(cleanup_arctic_mtd);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("David Gibson <arctic@gibson.dropbear.id.au>");
-+MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Arctic boards");
---- linux-2.4.21/drivers/mtd/maps/autcpu12-nvram.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/autcpu12-nvram.c
-@@ -2,7 +2,7 @@
- * NV-RAM memory access on autcpu12
- * (C) 2002 Thomas Gleixner (gleixner@autronix.de)
- *
-- * $Id: autcpu12-nvram.c,v 1.1 2002/02/22 09:30:24 gleixner Exp $
-+ * $Id: autcpu12-nvram.c,v 1.8 2004/11/04 13:24:14 gleixner Exp $
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
-@@ -24,6 +24,7 @@
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/ioport.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <asm/sizes.h>
- #include <asm/hardware.h>
-@@ -32,80 +33,27 @@
- #include <linux/mtd/map.h>
- #include <linux/mtd/partitions.h>
-
--__u8 autcpu12_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 autcpu12_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 autcpu12_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void autcpu12_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void autcpu12_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void autcpu12_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void autcpu12_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void autcpu12_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- while(len) {
-- __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to);
-- from++;
-- to++;
-- len--;
-- }
--}
-
- static struct mtd_info *sram_mtd;
-
- struct map_info autcpu12_sram_map = {
-- name: "SRAM",
-- size: 32768,
-- buswidth: 8,
-- read8: autcpu12_read8,
-- read16: autcpu12_read16,
-- read32: autcpu12_read32,
-- copy_from: autcpu12_copy_from,
-- write8: autcpu12_write8,
-- write16: autcpu12_write16,
-- write32: autcpu12_write32,
-- copy_to: autcpu12_copy_to
-+ .name = "SRAM",
-+ .size = 32768,
-+ .bankwidth = 4,
-+ .phys = 0x12000000,
- };
-
- static int __init init_autcpu12_sram (void)
- {
- int err, save0, save1;
-
-- autcpu12_sram_map.map_priv_1 = (unsigned long)ioremap(0x12000000, SZ_128K);
-- if (!autcpu12_sram_map.map_priv_1) {
-+ autcpu12_sram_map.virt = ioremap(0x12000000, SZ_128K);
-+ if (!autcpu12_sram_map.virt) {
- printk("Failed to ioremap autcpu12 NV-RAM space\n");
- err = -EIO;
- goto out;
- }
-+ simple_map_init(&autcpu_sram_map);
-
- /*
- * Check for 32K/128K
-@@ -115,20 +63,20 @@
- * Read and check result on ofs 0x0
- * Restore contents
- */
-- save0 = autcpu12_read32(&autcpu12_sram_map,0);
-- save1 = autcpu12_read32(&autcpu12_sram_map,0x10000);
-- autcpu12_write32(&autcpu12_sram_map,~save0,0x10000);
-+ save0 = map_read32(&autcpu12_sram_map,0);
-+ save1 = map_read32(&autcpu12_sram_map,0x10000);
-+ map_write32(&autcpu12_sram_map,~save0,0x10000);
- /* if we find this pattern on 0x0, we have 32K size
- * restore contents and exit
- */
-- if ( autcpu12_read32(&autcpu12_sram_map,0) != save0) {
-- autcpu12_write32(&autcpu12_sram_map,save0,0x0);
-+ if ( map_read32(&autcpu12_sram_map,0) != save0) {
-+ map_write32(&autcpu12_sram_map,save0,0x0);
- goto map;
- }
- /* We have a 128K found, restore 0x10000 and set size
- * to 128K
- */
-- autcpu12_write32(&autcpu12_sram_map,save1,0x10000);
-+ map_write32(&autcpu12_sram_map,save1,0x10000);
- autcpu12_sram_map.size = SZ_128K;
-
- map:
-@@ -139,7 +87,7 @@
- goto out_ioremap;
- }
-
-- sram_mtd->module = THIS_MODULE;
-+ sram_mtd->owner = THIS_MODULE;
- sram_mtd->erasesize = 16;
-
- if (add_mtd_device(sram_mtd)) {
-@@ -148,7 +96,7 @@
- goto out_probe;
- }
-
-- printk("NV-RAM device size %ldK registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K);
-+ printk("NV-RAM device size %ldKiB registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K);
-
- return 0;
-
-@@ -157,7 +105,7 @@
- sram_mtd = 0;
-
- out_ioremap:
-- iounmap((void *)autcpu12_sram_map.map_priv_1);
-+ iounmap((void *)autcpu12_sram_map.virt);
- out:
- return err;
- }
-@@ -167,7 +115,7 @@
- if (sram_mtd) {
- del_mtd_device(sram_mtd);
- map_destroy(sram_mtd);
-- iounmap((void *)autcpu12_sram_map.map_priv_1);
-+ iounmap((void *)autcpu12_sram_map.virt);
- }
- }
-
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/bast-flash.c
-@@ -0,0 +1,230 @@
-+/* linux/drivers/mtd/maps/bast_flash.c
-+ *
-+ * Copyright (c) 2004-2005 Simtec Electronics
-+ * Ben Dooks <ben@simtec.co.uk>
-+ *
-+ * Simtec Bast (EB2410ITX) NOR MTD Mapping driver
-+ *
-+ * Changelog:
-+ * 20-Sep-2004 BJD Initial version
-+ * 17-Jan-2005 BJD Add whole device if no partitions found
-+ *
-+ * $Id: bast-flash.c,v 1.2 2005/01/18 11:13:47 bjd Exp $
-+ *
-+ * This program is free software; 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/module.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/ioport.h>
-+#include <linux/device.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/io.h>
-+#include <asm/mach-types.h>
-+#include <asm/mach/flash.h>
-+
-+#include <asm/arch/map.h>
-+#include <asm/arch/bast-map.h>
-+#include <asm/arch/bast-cpld.h>
-+
-+#ifdef CONFIG_MTD_BAST_MAXSIZE
-+#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * SZ_1M)
-+#else
-+#define AREA_MAXSIZE (32 * SZ_1M)
-+#endif
-+
-+#define PFX "bast-flash: "
-+
-+struct bast_flash_info {
-+ struct mtd_info *mtd;
-+ struct map_info map;
-+ struct mtd_partition *partitions;
-+ struct resource *area;
-+};
-+
-+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-+
-+static struct bast_flash_info *to_bast_info(struct device *dev)
-+{
-+ return (struct bast_flash_info *)dev_get_drvdata(dev);
-+}
-+
-+static void bast_flash_setrw(int to)
-+{
-+ unsigned int val;
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+ val = __raw_readb(BAST_VA_CTRL3);
-+
-+ if (to)
-+ val |= BAST_CPLD_CTRL3_ROMWEN;
-+ else
-+ val &= ~BAST_CPLD_CTRL3_ROMWEN;
-+
-+ pr_debug("new cpld ctrl3=%02x\n", val);
-+
-+ __raw_writeb(val, BAST_VA_CTRL3);
-+ local_irq_restore(flags);
-+}
-+
-+static int bast_flash_remove(struct device *dev)
-+{
-+ struct bast_flash_info *info = to_bast_info(dev);
-+
-+ dev_set_drvdata(dev, NULL);
-+
-+ if (info == NULL)
-+ return 0;
-+
-+ if (info->map.virt != NULL)
-+ iounmap(info->map.virt);
-+
-+ if (info->mtd) {
-+ del_mtd_partitions(info->mtd);
-+ map_destroy(info->mtd);
-+ }
-+
-+ if (info->partitions)
-+ kfree(info->partitions);
-+
-+ if (info->area) {
-+ release_resource(info->area);
-+ kfree(info->area);
-+ }
-+
-+ kfree(info);
-+
-+ return 0;
-+}
-+
-+static int bast_flash_probe(struct device *dev)
-+{
-+ struct platform_device *pdev = to_platform_device(dev);
-+ struct bast_flash_info *info;
-+ struct resource *res;
-+ int err = 0;
-+
-+ info = kmalloc(sizeof(*info), GFP_KERNEL);
-+ if (info == NULL) {
-+ printk(KERN_ERR PFX "no memory for flash info\n");
-+ err = -ENOMEM;
-+ goto exit_error;
-+ }
-+
-+ memzero(info, sizeof(*info));
-+ dev_set_drvdata(dev, info);
-+
-+ res = pdev->resource; /* assume that the flash has one resource */
-+
-+ info->map.phys = res->start;
-+ info->map.size = res->end - res->start + 1;
-+ info->map.name = dev->bus_id;
-+ info->map.bankwidth = 2;
-+
-+ if (info->map.size > AREA_MAXSIZE)
-+ info->map.size = AREA_MAXSIZE;
-+
-+ pr_debug("%s: area %08lx, size %ld\n", __FUNCTION__,
-+ info->map.phys, info->map.size);
-+
-+ info->area = request_mem_region(res->start, info->map.size,
-+ pdev->name);
-+ if (info->area == NULL) {
-+ printk(KERN_ERR PFX "cannot reserve flash memory region\n");
-+ err = -ENOENT;
-+ goto exit_error;
-+ }
-+
-+ info->map.virt = ioremap(res->start, info->map.size);
-+ pr_debug("%s: virt at %08x\n", __FUNCTION__, (int)info->map.virt);
-+
-+ if (info->map.virt == 0) {
-+ printk(KERN_ERR PFX "failed to ioremap() region\n");
-+ err = -EIO;
-+ goto exit_error;
-+ }
-+
-+ simple_map_init(&info->map);
-+
-+ /* enable the write to the flash area */
-+
-+ bast_flash_setrw(1);
-+
-+ /* probe for the device(s) */
-+
-+ info->mtd = do_map_probe("jedec_probe", &info->map);
-+ if (info->mtd == NULL)
-+ info->mtd = do_map_probe("cfi_probe", &info->map);
-+
-+ if (info->mtd == NULL) {
-+ printk(KERN_ERR PFX "map_probe() failed\n");
-+ err = -ENXIO;
-+ goto exit_error;
-+ }
-+
-+ /* mark ourselves as the owner */
-+ info->mtd->owner = THIS_MODULE;
-+
-+ err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0);
-+ if (err > 0) {
-+ err = add_mtd_partitions(info->mtd, info->partitions, err);
-+ if (err)
-+ printk(KERN_ERR PFX "cannot add/parse partitions\n");
-+ } else {
-+ err = add_mtd_device(info->mtd);
-+ }
-+
-+ if (err == 0)
-+ return 0;
-+
-+ /* fall through to exit error */
-+
-+ exit_error:
-+ bast_flash_remove(dev);
-+ return err;
-+}
-+
-+static struct device_driver bast_flash_driver = {
-+ .name = "bast-nor",
-+ .bus = &platform_bus_type,
-+ .probe = bast_flash_probe,
-+ .remove = bast_flash_remove,
-+};
-+
-+static int __init bast_flash_init(void)
-+{
-+ printk("BAST NOR-Flash Driver, (c) 2004 Simtec Electronics\n");
-+ return driver_register(&bast_flash_driver);
-+}
-+
-+static void __exit bast_flash_exit(void)
-+{
-+ driver_unregister(&bast_flash_driver);
-+}
-+
-+module_init(bast_flash_init);
-+module_exit(bast_flash_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-+MODULE_DESCRIPTION("BAST MTD Map driver");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/beech-mtd.c
-@@ -0,0 +1,112 @@
-+/*
-+ * $Id: beech-mtd.c,v 1.10 2004/11/04 13:24:14 gleixner Exp $
-+ *
-+ * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for
-+ * IBM 405LP Beech boards.
-+ *
-+ * This program is free software; 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
-+ *
-+ * Copyright (C) 2002, International Business Machines Corporation
-+ * All Rights Reserved.
-+ *
-+ * Bishop Brock
-+ * IBM Research, Austin Center for Low-Power Computing
-+ * bcbrock@us.ibm.com
-+ * March 2002
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/io.h>
-+#include <asm/ibm4xx.h>
-+
-+#define NAME "Beech Linux Flash"
-+#define PADDR BEECH_BIGFLASH_PADDR
-+#define SIZE BEECH_BIGFLASH_SIZE
-+#define BUSWIDTH 1
-+
-+/* Flash memories on these boards are memory resources, accessed big-endian. */
-+
-+
-+static struct map_info beech_mtd_map = {
-+ .name = NAME,
-+ .size = SIZE,
-+ .bankwidth = BUSWIDTH,
-+ .phys = PADDR
-+};
-+
-+static struct mtd_info *beech_mtd;
-+
-+static struct mtd_partition beech_partitions[2] = {
-+ {
-+ .name = "Linux Kernel",
-+ .size = BEECH_KERNEL_SIZE,
-+ .offset = BEECH_KERNEL_OFFSET
-+ }, {
-+ .name = "Free Area",
-+ .size = BEECH_FREE_AREA_SIZE,
-+ .offset = BEECH_FREE_AREA_OFFSET
-+ }
-+};
-+
-+static int __init
-+init_beech_mtd(void)
-+{
-+ printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
-+
-+ beech_mtd_map.virt = ioremap(PADDR, SIZE);
-+
-+ if (!beech_mtd_map.virt) {
-+ printk("%s: failed to ioremap 0x%x\n", NAME, PADDR);
-+ return -EIO;
-+ }
-+
-+ simple_map_init(&beech_mtd_map);
-+
-+ printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
-+ beech_mtd = do_map_probe("cfi_probe", &beech_mtd_map);
-+
-+ if (!beech_mtd)
-+ return -ENXIO;
-+
-+ beech_mtd->owner = THIS_MODULE;
-+
-+ return add_mtd_partitions(beech_mtd, beech_partitions, 2);
-+}
-+
-+static void __exit
-+cleanup_beech_mtd(void)
-+{
-+ if (beech_mtd) {
-+ del_mtd_partitions(beech_mtd);
-+ map_destroy(beech_mtd);
-+ iounmap((void *) beech_mtd_map.virt);
-+ }
-+}
-+
-+module_init(init_beech_mtd);
-+module_exit(cleanup_beech_mtd);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Bishop Brock <bcbrock@us.ibm.com>");
-+MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Beech boards");
---- linux-2.4.21/drivers/mtd/maps/cdb89712.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/cdb89712.c
-@@ -1,13 +1,14 @@
- /*
- * Flash on Cirrus CDB89712
- *
-- * $Id: cdb89712.c,v 1.3 2001/10/02 15:14:43 rmk Exp $
-+ * $Id: cdb89712.c,v 1.10 2004/11/04 13:24:14 gleixner Exp $
- */
-
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/ioport.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <asm/arch/hardware.h>
- #include <linux/mtd/mtd.h>
-@@ -16,77 +17,21 @@
-
-
-
--__u8 cdb89712_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 cdb89712_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 cdb89712_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void cdb89712_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void cdb89712_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void cdb89712_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void cdb89712_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- // printk ("cdb89712_copy_from: 0x%x@0x%x -> 0x%x\n", len, from, to);
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void cdb89712_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- while(len) {
-- __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to);
-- from++;
-- to++;
-- len--;
-- }
--}
--
-
- static struct mtd_info *flash_mtd;
-
- struct map_info cdb89712_flash_map = {
-- name: "flash",
-- size: FLASH_SIZE,
-- buswidth: FLASH_WIDTH,
-- read8: cdb89712_read8,
-- read16: cdb89712_read16,
-- read32: cdb89712_read32,
-- copy_from: cdb89712_copy_from,
-- write8: cdb89712_write8,
-- write16: cdb89712_write16,
-- write32: cdb89712_write32,
-- copy_to: cdb89712_copy_to
-+ .name = "flash",
-+ .size = FLASH_SIZE,
-+ .bankwidth = FLASH_WIDTH,
-+ .phys = FLASH_START,
- };
-
- struct resource cdb89712_flash_resource = {
-- name: "Flash",
-- start: FLASH_START,
-- end: FLASH_START + FLASH_SIZE - 1,
-- flags: IORESOURCE_IO | IORESOURCE_BUSY,
-+ .name = "Flash",
-+ .start = FLASH_START,
-+ .end = FLASH_START + FLASH_SIZE - 1,
-+ .flags = IORESOURCE_IO | IORESOURCE_BUSY,
- };
-
- static int __init init_cdb89712_flash (void)
-@@ -99,13 +44,13 @@
- goto out;
- }
-
-- cdb89712_flash_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
-- if (!cdb89712_flash_map.map_priv_1) {
-+ cdb89712_flash_map.virt = ioremap(FLASH_START, FLASH_SIZE);
-+ if (!cdb89712_flash_map.virt) {
- printk(KERN_NOTICE "Failed to ioremap Cdb89712 FLASH space\n");
- err = -EIO;
- goto out_resource;
- }
--
-+ simple_map_init(&cdb89712_flash_map);
- flash_mtd = do_map_probe("cfi_probe", &cdb89712_flash_map);
- if (!flash_mtd) {
- flash_mtd = do_map_probe("map_rom", &cdb89712_flash_map);
-@@ -118,7 +63,7 @@
- goto out_ioremap;
- }
-
-- flash_mtd->module = THIS_MODULE;
-+ flash_mtd->owner = THIS_MODULE;
-
- if (add_mtd_device(flash_mtd)) {
- printk("FLASH device addition failed\n");
-@@ -132,7 +77,7 @@
- map_destroy(flash_mtd);
- flash_mtd = 0;
- out_ioremap:
-- iounmap((void *)cdb89712_flash_map.map_priv_1);
-+ iounmap((void *)cdb89712_flash_map.virt);
- out_resource:
- release_resource (&cdb89712_flash_resource);
- out:
-@@ -146,24 +91,17 @@
- static struct mtd_info *sram_mtd;
-
- struct map_info cdb89712_sram_map = {
-- name: "SRAM",
-- size: SRAM_SIZE,
-- buswidth: SRAM_WIDTH,
-- read8: cdb89712_read8,
-- read16: cdb89712_read16,
-- read32: cdb89712_read32,
-- copy_from: cdb89712_copy_from,
-- write8: cdb89712_write8,
-- write16: cdb89712_write16,
-- write32: cdb89712_write32,
-- copy_to: cdb89712_copy_to
-+ .name = "SRAM",
-+ .size = SRAM_SIZE,
-+ .bankwidth = SRAM_WIDTH,
-+ .phys = SRAM_START,
- };
-
- struct resource cdb89712_sram_resource = {
-- name: "SRAM",
-- start: SRAM_START,
-- end: SRAM_START + SRAM_SIZE - 1,
-- flags: IORESOURCE_IO | IORESOURCE_BUSY,
-+ .name = "SRAM",
-+ .start = SRAM_START,
-+ .end = SRAM_START + SRAM_SIZE - 1,
-+ .flags = IORESOURCE_IO | IORESOURCE_BUSY,
- };
-
- static int __init init_cdb89712_sram (void)
-@@ -176,13 +114,13 @@
- goto out;
- }
-
-- cdb89712_sram_map.map_priv_1 = (unsigned long)ioremap(SRAM_START, SRAM_SIZE);
-- if (!cdb89712_sram_map.map_priv_1) {
-+ cdb89712_sram_map.virt = ioremap(SRAM_START, SRAM_SIZE);
-+ if (!cdb89712_sram_map.virt) {
- printk(KERN_NOTICE "Failed to ioremap Cdb89712 SRAM space\n");
- err = -EIO;
- goto out_resource;
- }
--
-+ simple_map_init(&cdb89712_sram_map);
- sram_mtd = do_map_probe("map_ram", &cdb89712_sram_map);
- if (!sram_mtd) {
- printk("SRAM probe failed\n");
-@@ -190,7 +128,7 @@
- goto out_ioremap;
- }
-
-- sram_mtd->module = THIS_MODULE;
-+ sram_mtd->owner = THIS_MODULE;
- sram_mtd->erasesize = 16;
-
- if (add_mtd_device(sram_mtd)) {
-@@ -205,7 +143,7 @@
- map_destroy(sram_mtd);
- sram_mtd = 0;
- out_ioremap:
-- iounmap((void *)cdb89712_sram_map.map_priv_1);
-+ iounmap((void *)cdb89712_sram_map.virt);
- out_resource:
- release_resource (&cdb89712_sram_resource);
- out:
-@@ -221,20 +159,17 @@
- static struct mtd_info *bootrom_mtd;
-
- struct map_info cdb89712_bootrom_map = {
-- name: "BootROM",
-- size: BOOTROM_SIZE,
-- buswidth: BOOTROM_WIDTH,
-- read8: cdb89712_read8,
-- read16: cdb89712_read16,
-- read32: cdb89712_read32,
-- copy_from: cdb89712_copy_from,
-+ .name = "BootROM",
-+ .size = BOOTROM_SIZE,
-+ .bankwidth = BOOTROM_WIDTH,
-+ .phys = BOOTROM_START,
- };
-
- struct resource cdb89712_bootrom_resource = {
-- name: "BootROM",
-- start: BOOTROM_START,
-- end: BOOTROM_START + BOOTROM_SIZE - 1,
-- flags: IORESOURCE_IO | IORESOURCE_BUSY,
-+ .name = "BootROM",
-+ .start = BOOTROM_START,
-+ .end = BOOTROM_START + BOOTROM_SIZE - 1,
-+ .flags = IORESOURCE_IO | IORESOURCE_BUSY,
- };
-
- static int __init init_cdb89712_bootrom (void)
-@@ -247,13 +182,13 @@
- goto out;
- }
-
-- cdb89712_bootrom_map.map_priv_1 = (unsigned long)ioremap(BOOTROM_START, BOOTROM_SIZE);
-- if (!cdb89712_bootrom_map.map_priv_1) {
-+ cdb89712_bootrom_map.virt = ioremap(BOOTROM_START, BOOTROM_SIZE);
-+ if (!cdb89712_bootrom_map.virt) {
- printk(KERN_NOTICE "Failed to ioremap Cdb89712 BootROM space\n");
- err = -EIO;
- goto out_resource;
- }
--
-+ simple_map_init(&cdb89712_bootrom_map);
- bootrom_mtd = do_map_probe("map_rom", &cdb89712_bootrom_map);
- if (!bootrom_mtd) {
- printk("BootROM probe failed\n");
-@@ -261,7 +196,7 @@
- goto out_ioremap;
- }
-
-- bootrom_mtd->module = THIS_MODULE;
-+ bootrom_mtd->owner = THIS_MODULE;
- bootrom_mtd->erasesize = 0x10000;
-
- if (add_mtd_device(bootrom_mtd)) {
-@@ -276,7 +211,7 @@
- map_destroy(bootrom_mtd);
- bootrom_mtd = 0;
- out_ioremap:
-- iounmap((void *)cdb89712_bootrom_map.map_priv_1);
-+ iounmap((void *)cdb89712_bootrom_map.virt);
- out_resource:
- release_resource (&cdb89712_bootrom_resource);
- out:
-@@ -306,21 +241,21 @@
- if (sram_mtd) {
- del_mtd_device(sram_mtd);
- map_destroy(sram_mtd);
-- iounmap((void *)cdb89712_sram_map.map_priv_1);
-+ iounmap((void *)cdb89712_sram_map.virt);
- release_resource (&cdb89712_sram_resource);
- }
-
- if (flash_mtd) {
- del_mtd_device(flash_mtd);
- map_destroy(flash_mtd);
-- iounmap((void *)cdb89712_flash_map.map_priv_1);
-+ iounmap((void *)cdb89712_flash_map.virt);
- release_resource (&cdb89712_flash_resource);
- }
-
- if (bootrom_mtd) {
- del_mtd_device(bootrom_mtd);
- map_destroy(bootrom_mtd);
-- iounmap((void *)cdb89712_bootrom_map.map_priv_1);
-+ iounmap((void *)cdb89712_bootrom_map.virt);
- release_resource (&cdb89712_bootrom_resource);
- }
- }
---- linux-2.4.21/drivers/mtd/maps/ceiva.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/ceiva.c
-@@ -11,7 +11,7 @@
- *
- * (C) 2000 Nicolas Pitre <nico@cam.org>
- *
-- * $Id: ceiva.c,v 1.2 2002/10/14 12:50:22 rmk Exp $
-+ * $Id: ceiva.c,v 1.11 2004/09/16 23:27:12 gleixner Exp $
- */
-
- #include <linux/config.h>
-@@ -19,6 +19,7 @@
- #include <linux/types.h>
- #include <linux/ioport.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -31,62 +32,10 @@
- #include <asm/sizes.h>
-
- /*
-- * This isnt complete yet, so...
-+ * This isn't complete yet, so...
- */
- #define CONFIG_MTD_CEIVA_STATICMAP
-
--static __u8 clps_read8(struct map_info *map, unsigned long ofs)
--{
-- return readb(map->map_priv_1 + ofs);
--}
--
--static __u16 clps_read16(struct map_info *map, unsigned long ofs)
--{
-- return readw(map->map_priv_1 + ofs);
--}
--
--static __u32 clps_read32(struct map_info *map, unsigned long ofs)
--{
-- return readl(map->map_priv_1 + ofs);
--}
--
--static void clps_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy(to, (void *)(map->map_priv_1 + from), len);
--}
--
--static void clps_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- writeb(d, map->map_priv_1 + adr);
--}
--
--static void clps_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- writew(d, map->map_priv_1 + adr);
--}
--
--static void clps_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- writel(d, map->map_priv_1 + adr);
--}
--
--static void clps_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy((void *)(map->map_priv_1 + to), from, len);
--}
--
--static struct map_info clps_map __initdata = {
-- name: "clps flash",
-- read8: clps_read8,
-- read16: clps_read16,
-- read32: clps_read32,
-- copy_from: clps_copy_from,
-- write8: clps_write8,
-- write16: clps_write16,
-- write32: clps_write32,
-- copy_to: clps_copy_to,
--};
--
- #ifdef CONFIG_MTD_CEIVA_STATICMAP
- /*
- * See include/linux/mtd/partitions.h for definition of the mtd_partition
-@@ -115,23 +64,23 @@
-
- static struct mtd_partition ceiva_partitions[] = {
- {
-- name: "Ceiva BOOT partition",
-- size: BOOT_PARTITION_SIZE_KiB*1024,
-- offset: 0,
-+ .name = "Ceiva BOOT partition",
-+ .size = BOOT_PARTITION_SIZE_KiB*1024,
-+ .offset = 0,
-
- },{
-- name: "Ceiva parameters partition",
-- size: PARAMS_PARTITION_SIZE_KiB*1024,
-- offset: (16 + 8) * 1024,
-+ .name = "Ceiva parameters partition",
-+ .size = PARAMS_PARTITION_SIZE_KiB*1024,
-+ .offset = (16 + 8) * 1024,
- },{
-- name: "Ceiva kernel partition",
-- size: (KERNEL_PARTITION_SIZE_KiB)*1024,
-- offset: 0x20000,
-+ .name = "Ceiva kernel partition",
-+ .size = (KERNEL_PARTITION_SIZE_KiB)*1024,
-+ .offset = 0x20000,
-
- },{
-- name: "Ceiva root filesystem partition",
-- offset: MTDPART_OFS_APPEND,
-- size: (ROOT_PARTITION_SIZE_KiB)*1024,
-+ .name = "Ceiva root filesystem partition",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = (ROOT_PARTITION_SIZE_KiB)*1024,
- }
- };
- #endif
-@@ -176,7 +125,7 @@
- maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
- if (!maps)
- return -ENOMEM;
--
-+ memset(maps, 0, sizeof(struct map_info) * nr);
- /*
- * Claim and then map the memory regions.
- */
-@@ -191,7 +140,9 @@
- }
-
- clps[i].map = maps + i;
-- memcpy(clps[i].map, &clps_map, sizeof(struct map_info));
-+
-+ clps[i].map->name = "clps flash";
-+ clps[i].map->phys = clps[i].base;
-
- clps[i].vbase = ioremap(clps[i].base, clps[i].size);
- if (!clps[i].vbase) {
-@@ -199,16 +150,18 @@
- break;
- }
-
-- clps[i].map->map_priv_1 = (unsigned long)clps[i].vbase;
-- clps[i].map->buswidth = clps[i].width;
-+ clps[i].map->virt = (void __iomem *)clps[i].vbase;
-+ clps[i].map->bankwidth = clps[i].width;
- clps[i].map->size = clps[i].size;
-
-+ simple_map_init(&clps[i].map);
-+
- clps[i].mtd = do_map_probe("jedec_probe", clps[i].map);
- if (clps[i].mtd == NULL) {
- ret = -ENXIO;
- break;
- }
-- clps[i].mtd->module = THIS_MODULE;
-+ clps[i].mtd->owner = THIS_MODULE;
- subdev[i] = clps[i].mtd;
-
- printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, "
-@@ -318,10 +271,8 @@
- return nr;
- }
-
--extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
--extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
--
- static struct mtd_partition *parsed_parts;
-+static const char *probes[] = { "cmdlinepart", "RedBoot", NULL };
-
- static void __init clps_locate_partitions(struct mtd_info *mtd)
- {
-@@ -331,20 +282,11 @@
- /*
- * Partition selection stuff.
- */
--#ifdef CONFIG_MTD_CMDLINE_PARTS
-- nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "clps");
-+ nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0);
- if (nr_parts > 0) {
- part_type = "command line";
- break;
- }
--#endif
--#ifdef CONFIG_MTD_REDBOOT_PARTS
-- nr_parts = parse_redboot_partitions(mtd, &parsed_parts);
-- if (nr_parts > 0) {
-- part_type = "RedBoot";
-- break;
-- }
--#endif
- #ifdef CONFIG_MTD_CEIVA_STATICMAP
- nr_parts = clps_static_partitions(&parsed_parts);
- if (nr_parts > 0) {
---- linux-2.4.21/drivers/mtd/maps/cfi_flagadm.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/cfi_flagadm.c
-@@ -1,7 +1,7 @@
- /*
- * Copyright © 2001 Flaga hf. Medical Devices, Kári Davíđsson <kd@flaga.is>
- *
-- * $Id: cfi_flagadm.c,v 1.7 2001/10/02 15:05:13 dwmw2 Exp $
-+ * $Id: cfi_flagadm.c,v 1.14 2004/11/04 13:24:14 gleixner Exp $
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
-@@ -27,6 +27,7 @@
- #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>
-@@ -55,83 +56,33 @@
- #define FLASH_PARTITION3_ADDR 0x00240000
- #define FLASH_PARTITION3_SIZE 0x001C0000
-
--__u8 flagadm_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 flagadm_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 flagadm_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void flagadm_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void flagadm_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void flagadm_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void flagadm_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void flagadm_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
-
- struct map_info flagadm_map = {
-- name: "FlagaDM flash device",
-- size: FLASH_SIZE,
-- buswidth: 2,
-- read8: flagadm_read8,
-- read16: flagadm_read16,
-- read32: flagadm_read32,
-- copy_from: flagadm_copy_from,
-- write8: flagadm_write8,
-- write16: flagadm_write16,
-- write32: flagadm_write32,
-- copy_to: flagadm_copy_to
-+ .name = "FlagaDM flash device",
-+ .size = FLASH_SIZE,
-+ .bankwidth = 2,
- };
-
- struct mtd_partition flagadm_parts[] = {
- {
-- name : "Bootloader",
-- offset : FLASH_PARTITION0_ADDR,
-- size : FLASH_PARTITION0_SIZE
-+ .name = "Bootloader",
-+ .offset = FLASH_PARTITION0_ADDR,
-+ .size = FLASH_PARTITION0_SIZE
- },
- {
-- name : "Kernel image",
-- offset : FLASH_PARTITION1_ADDR,
-- size : FLASH_PARTITION1_SIZE
-+ .name = "Kernel image",
-+ .offset = FLASH_PARTITION1_ADDR,
-+ .size = FLASH_PARTITION1_SIZE
- },
- {
-- name : "Initial ramdisk image",
-- offset : FLASH_PARTITION2_ADDR,
-- size : FLASH_PARTITION2_SIZE
-+ .name = "Initial ramdisk image",
-+ .offset = FLASH_PARTITION2_ADDR,
-+ .size = FLASH_PARTITION2_SIZE
- },
- {
-- name : "Persistant storage",
-- offset : FLASH_PARTITION3_ADDR,
-- size : FLASH_PARTITION3_SIZE
-+ .name = "Persistant storage",
-+ .offset = FLASH_PARTITION3_ADDR,
-+ .size = FLASH_PARTITION3_SIZE
- }
- };
-
-@@ -144,22 +95,26 @@
- printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n",
- FLASH_SIZE, FLASH_PHYS_ADDR);
-
-- flagadm_map.map_priv_1 = (unsigned long)ioremap(FLASH_PHYS_ADDR,
-+ flagadm_map.phys = FLASH_PHYS_ADDR;
-+ flagadm_map.virt = ioremap(FLASH_PHYS_ADDR,
- FLASH_SIZE);
-
-- if (!flagadm_map.map_priv_1) {
-+ if (!flagadm_map.virt) {
- printk("Failed to ioremap\n");
- return -EIO;
- }
-+
-+ simple_map_init(&flagadm_map);
-+
- mymtd = do_map_probe("cfi_probe", &flagadm_map);
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
- add_mtd_partitions(mymtd, flagadm_parts, PARTITION_COUNT);
- printk(KERN_NOTICE "FlagaDM flash device initialized\n");
- return 0;
- }
-
-- iounmap((void *)flagadm_map.map_priv_1);
-+ iounmap((void *)flagadm_map.virt);
- return -ENXIO;
- }
-
-@@ -169,9 +124,9 @@
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- }
-- if (flagadm_map.map_priv_1) {
-- iounmap((void *)flagadm_map.map_priv_1);
-- flagadm_map.map_priv_1 = 0;
-+ if (flagadm_map.virt) {
-+ iounmap((void *)flagadm_map.virt);
-+ flagadm_map.virt = 0;
- }
- }
-
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/chestnut.c
-@@ -0,0 +1,91 @@
-+/*
-+ * drivers/mtd/maps/chestnut.c
-+ *
-+ * $Id: chestnut.c,v 1.1 2005/01/05 16:59:50 dwmw2 Exp $
-+ *
-+ * Flash map driver for IBM Chestnut (750FXGX Eval)
-+ *
-+ * Chose not to enable 8 bit flash as it contains the firmware and board
-+ * info. Thus only the 32bit flash is supported.
-+ *
-+ * Author: <source@mvista.com>
-+ *
-+ * 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/module.h>
-+#include <linux/init.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <asm/io.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <platforms/chestnut.h>
-+
-+static struct map_info chestnut32_map = {
-+ .name = "User FS",
-+ .size = CHESTNUT_32BIT_SIZE,
-+ .bankwidth = 4,
-+ .phys = CHESTNUT_32BIT_BASE,
-+};
-+
-+static struct mtd_partition chestnut32_partitions[] = {
-+ {
-+ .name = "User FS",
-+ .offset = 0,
-+ .size = CHESTNUT_32BIT_SIZE,
-+ }
-+};
-+
-+static struct mtd_info *flash32;
-+
-+int __init init_chestnut(void)
-+{
-+ /* 32-bit FLASH */
-+
-+ chestnut32_map.virt = ioremap(chestnut32_map.phys, chestnut32_map.size);
-+
-+ if (!chestnut32_map.virt) {
-+ printk(KERN_NOTICE "Failed to ioremap 32-bit flash\n");
-+ return -EIO;
-+ }
-+
-+ simple_map_init(&chestnut32_map);
-+
-+ flash32 = do_map_probe("cfi_probe", &chestnut32_map);
-+ if (flash32) {
-+ flash32->owner = THIS_MODULE;
-+ add_mtd_partitions(flash32, chestnut32_partitions,
-+ ARRAY_SIZE(chestnut32_partitions));
-+ } else {
-+ printk(KERN_NOTICE "map probe failed for 32-bit flash\n");
-+ return -ENXIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static void __exit
-+cleanup_chestnut(void)
-+{
-+ if (flash32) {
-+ del_mtd_partitions(flash32);
-+ map_destroy(flash32);
-+ }
-+
-+ if (chestnut32_map.virt) {
-+ iounmap((void *)chestnut32_map.virt);
-+ chestnut32_map.virt = 0;
-+ }
-+}
-+
-+module_init(init_chestnut);
-+module_exit(cleanup_chestnut);
-+
-+MODULE_DESCRIPTION("MTD map and partitions for IBM Chestnut (750fxgx Eval)");
-+MODULE_AUTHOR("<source@mvista.com>");
-+MODULE_LICENSE("GPL");
---- linux-2.4.21/drivers/mtd/maps/cstm_mips_ixx.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/cstm_mips_ixx.c
-@@ -1,5 +1,5 @@
- /*
-- * $Id: cstm_mips_ixx.c,v 1.5 2001/10/02 15:05:14 dwmw2 Exp $
-+ * $Id: cstm_mips_ixx.c,v 1.13 2005/01/12 22:34:35 gleixner Exp $
- *
- * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions.
- * Config with both CFI and JEDEC device support.
-@@ -33,55 +33,13 @@
- #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/mtd/partitions.h>
- #include <linux/config.h>
--
--#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
- #include <linux/delay.h>
--#endif
--
--__u8 cstm_mips_ixx_read8(struct map_info *map, unsigned long ofs)
--{
-- return *(__u8 *)(map->map_priv_1 + ofs);
--}
--
--__u16 cstm_mips_ixx_read16(struct map_info *map, unsigned long ofs)
--{
-- return *(__u16 *)(map->map_priv_1 + ofs);
--}
--
--__u32 cstm_mips_ixx_read32(struct map_info *map, unsigned long ofs)
--{
-- return *(__u32 *)(map->map_priv_1 + ofs);
--}
--
--void cstm_mips_ixx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void cstm_mips_ixx_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- *(__u8 *)(map->map_priv_1 + adr) = d;
--}
--
--void cstm_mips_ixx_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- *(__u16 *)(map->map_priv_1 + adr) = d;
--}
--
--void cstm_mips_ixx_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- *(__u32 *)(map->map_priv_1 + adr) = d;
--}
--
--void cstm_mips_ixx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
-
- #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
- #define CC_GCR 0xB4013818
-@@ -97,10 +55,17 @@
- #define CC_GPAICR 0xB4013804
- #endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
-
-+#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
- void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp)
- {
-+ static DEFINE_SPINLOCK(vpp_lock);
-+ static int vpp_count = 0;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&vpp_lock, flags);
-+
- if (vpp) {
--#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-+ if (!vpp_count++) {
- __u16 data;
- __u8 data1;
- static u8 first = 1;
-@@ -116,10 +81,9 @@
- enabling vpp after powerup */
- udelay(40);
- }
--#endif /* CONFIG_MIPS_ITE8172 */
- }
-- else {
--#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-+ } else {
-+ if (!--vpp_count) {
- __u16 data;
-
- // Set GPIO port B pin3 to high
-@@ -127,26 +91,11 @@
- data = (data & 0xff3f) | 0x0040;
- *(__u16 *)CC_GPBCR = data;
- *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) & 0xf7;
--#endif /* CONFIG_MIPS_ITE8172 */
- }
-+ }
-+ spin_unlock_irqrestore(&vpp_lock, flags);
- }
--
--const struct map_info basic_cstm_mips_ixx_map = {
-- NULL,
-- 0,
-- 0,
-- cstm_mips_ixx_read8,
-- cstm_mips_ixx_read16,
-- cstm_mips_ixx_read32,
-- cstm_mips_ixx_copy_from,
-- cstm_mips_ixx_write8,
-- cstm_mips_ixx_write16,
-- cstm_mips_ixx_write32,
-- cstm_mips_ixx_copy_to,
-- cstm_mips_ixx_set_vpp,
-- 0,
-- 0
--};
-+#endif
-
- /* board and partition description */
-
-@@ -155,7 +104,7 @@
- char *name;
- unsigned long window_addr;
- unsigned long window_size;
-- int buswidth;
-+ int bankwidth;
- int num_partitions;
- };
-
-@@ -167,7 +116,7 @@
- "big flash", // name
- 0x08000000, // window_addr
- 0x02000000, // window_size
-- 4, // buswidth
-+ 4, // bankwidth
- 1, // num_partitions
- }
-
-@@ -175,9 +124,9 @@
- static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = {
- { // 28F128J3A in 2x16 configuration
- {
-- name: "main partition ",
-- size: 0x02000000, // 128 x 2 x 128k byte sectors
-- offset: 0,
-+ .name = "main partition ",
-+ .size = 0x02000000, // 128 x 2 x 128k byte sectors
-+ .offset = 0,
- },
- },
- };
-@@ -189,7 +138,7 @@
- "MTD flash", // name
- CONFIG_MTD_CSTM_MIPS_IXX_START, // window_addr
- CONFIG_MTD_CSTM_MIPS_IXX_LEN, // window_size
-- CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH, // buswidth
-+ CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH, // bankwidth
- 1, // num_partitions
- },
-
-@@ -197,9 +146,9 @@
- static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = {
- {
- {
-- name: "main partition",
-- size: CONFIG_MTD_CSTM_MIPS_IXX_LEN,
-- offset: 0,
-+ .name = "main partition",
-+ .size = CONFIG_MTD_CSTM_MIPS_IXX_LEN,
-+ .offset = 0,
- },
- },
- };
-@@ -216,17 +165,24 @@
-
- /* Initialize mapping */
- for (i=0;i<PHYSMAP_NUMBER;i++) {
-- printk(KERN_NOTICE "cstm_mips_ixx flash device: %lx at %lx\n", cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr);
-- memcpy((char *)&cstm_mips_ixx_map[i],(char *)&basic_cstm_mips_ixx_map,sizeof(struct map_info));
-- cstm_mips_ixx_map[i].map_priv_1 = (unsigned long)ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size);
-- if (!cstm_mips_ixx_map[i].map_priv_1) {
-+ printk(KERN_NOTICE "cstm_mips_ixx flash device: 0x%lx at 0x%lx\n",
-+ cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr);
-+
-+
-+ cstm_mips_ixx_map[i].phys = cstm_mips_ixx_board_desc[i].window_addr;
-+ cstm_mips_ixx_map[i].virt = ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size);
-+ if (!cstm_mips_ixx_map[i].virt) {
- printk(KERN_WARNING "Failed to ioremap\n");
- return -EIO;
- }
- cstm_mips_ixx_map[i].name = cstm_mips_ixx_board_desc[i].name;
- cstm_mips_ixx_map[i].size = cstm_mips_ixx_board_desc[i].window_size;
-- cstm_mips_ixx_map[i].buswidth = cstm_mips_ixx_board_desc[i].buswidth;
-- //printk(KERN_NOTICE "cstm_mips_ixx: ioremap is %x\n",(unsigned int)(cstm_mips_ixx_map[i].map_priv_1));
-+ cstm_mips_ixx_map[i].bankwidth = cstm_mips_ixx_board_desc[i].bankwidth;
-+#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-+ cstm_mips_ixx_map[i].set_vpp = cstm_mips_ixx_set_vpp;
-+#endif
-+ simple_map_init(&cstm_mips_ixx_map[i]);
-+ //printk(KERN_NOTICE "cstm_mips_ixx: ioremap is %x\n",(unsigned int)(cstm_mips_ixx_map[i].virt));
- }
-
- #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-@@ -244,7 +200,7 @@
- printk(KERN_NOTICE "cstm_mips_ixx %d jedec: mymtd is %x\n",i,(unsigned int)mymtd);
- }
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
- cstm_mips_ixx_map[i].map_priv_2 = (unsigned long)mymtd;
- add_mtd_partitions(mymtd, parts, cstm_mips_ixx_board_desc[i].num_partitions);
-@@ -266,9 +222,9 @@
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- }
-- if (cstm_mips_ixx_map[i].map_priv_1) {
-- iounmap((void *)cstm_mips_ixx_map[i].map_priv_1);
-- cstm_mips_ixx_map[i].map_priv_1 = 0;
-+ if (cstm_mips_ixx_map[i].virt) {
-+ iounmap((void *)cstm_mips_ixx_map[i].virt);
-+ cstm_mips_ixx_map[i].virt = 0;
- }
- }
- }
---- linux-2.4.21/drivers/mtd/maps/dbox2-flash.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/dbox2-flash.c
-@@ -1,37 +1,61 @@
- /*
-- * $Id: dbox2-flash.c,v 1.4 2001/10/02 15:05:14 dwmw2 Exp $
-+ * $Id: dbox2-flash.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $
- *
-- * Nokia / Sagem D-Box 2 flash driver
-+ * D-Box 2 flash driver
- */
-
- #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/mtd/partitions.h>
- #include <linux/config.h>
-+#include <linux/errno.h>
-
- /* partition_info gives details on the logical partitions that the split the
- * single flash device into. If the size if zero we use up to the end of the
- * device. */
--static struct mtd_partition partition_info[]= {{name: "BR bootloader", // raw
-- size: 128 * 1024,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE},
-- {name: "PPC bootloader", // flfs
-- size: 128 * 1024,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: 0},
-- {name: "Kernel", // idxfs
-- size: 768 * 1024,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: 0},
-- {name: "System", // jffs
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: 0}};
-+static struct mtd_partition partition_info[]= {
-+ {
-+ .name = "BR bootloader",
-+ .size = 128 * 1024,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE
-+ },
-+ {
-+ .name = "FLFS (U-Boot)",
-+ .size = 128 * 1024,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = 0
-+ },
-+ {
-+ .name = "Root (SquashFS)",
-+ .size = 7040 * 1024,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = 0
-+ },
-+ {
-+ .name = "var (JFFS2)",
-+ .size = 896 * 1024,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = 0
-+ },
-+ {
-+ .name = "Flash without bootloader",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = 128 * 1024,
-+ .mask_flags = 0
-+ },
-+ {
-+ .name = "Complete Flash",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE
-+ }
-+};
-
- #define NUM_PARTITIONS (sizeof(partition_info) / sizeof(partition_info[0]))
-
-@@ -40,84 +64,36 @@
-
- static struct mtd_info *mymtd;
-
--__u8 dbox2_flash_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 dbox2_flash_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 dbox2_flash_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void dbox2_flash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void dbox2_flash_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void dbox2_flash_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void dbox2_flash_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void dbox2_flash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
-
- struct map_info dbox2_flash_map = {
-- name: "D-Box 2 flash memory",
-- size: WINDOW_SIZE,
-- buswidth: 4,
-- read8: dbox2_flash_read8,
-- read16: dbox2_flash_read16,
-- read32: dbox2_flash_read32,
-- copy_from: dbox2_flash_copy_from,
-- write8: dbox2_flash_write8,
-- write16: dbox2_flash_write16,
-- write32: dbox2_flash_write32,
-- copy_to: dbox2_flash_copy_to
-+ .name = "D-Box 2 flash memory",
-+ .size = WINDOW_SIZE,
-+ .bankwidth = 4,
-+ .phys = WINDOW_ADDR,
- };
-
- int __init init_dbox2_flash(void)
- {
- printk(KERN_NOTICE "D-Box 2 flash driver (size->0x%X mem->0x%X)\n", WINDOW_SIZE, WINDOW_ADDR);
-- dbox2_flash_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+ dbox2_flash_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
-
-- if (!dbox2_flash_map.map_priv_1) {
-+ if (!dbox2_flash_map.virt) {
- printk("Failed to ioremap\n");
- return -EIO;
- }
-+ simple_map_init(&dbox2_flash_map);
-
- // Probe for dual Intel 28F320 or dual AMD
- mymtd = do_map_probe("cfi_probe", &dbox2_flash_map);
- if (!mymtd) {
- // Probe for single Intel 28F640
-- dbox2_flash_map.buswidth = 2;
-+ dbox2_flash_map.bankwidth = 2;
-
- mymtd = do_map_probe("cfi_probe", &dbox2_flash_map);
- }
-
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
- /* Create MTD devices for each partition. */
- add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
-@@ -125,7 +101,7 @@
- return 0;
- }
-
-- iounmap((void *)dbox2_flash_map.map_priv_1);
-+ iounmap((void *)dbox2_flash_map.virt);
- return -ENXIO;
- }
-
-@@ -135,9 +111,9 @@
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- }
-- if (dbox2_flash_map.map_priv_1) {
-- iounmap((void *)dbox2_flash_map.map_priv_1);
-- dbox2_flash_map.map_priv_1 = 0;
-+ if (dbox2_flash_map.virt) {
-+ iounmap((void *)dbox2_flash_map.virt);
-+ dbox2_flash_map.virt = 0;
- }
- }
-
-@@ -146,5 +122,5 @@
-
-
- MODULE_LICENSE("GPL");
--MODULE_AUTHOR("Kári Davíđsson <kd@flaga.is>");
--MODULE_DESCRIPTION("MTD map driver for Nokia/Sagem D-Box 2 board");
-+MODULE_AUTHOR("Kári Davíđsson <kd@flaga.is>, Bastian Blank <waldi@tuxbox.org>, Alexander Wild <wild@te-elektronik.com>");
-+MODULE_DESCRIPTION("MTD map driver for D-Box 2 board");
---- linux-2.4.21/drivers/mtd/maps/dc21285.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/dc21285.c
-@@ -5,12 +5,14 @@
- *
- * This code is GPL
- *
-- * $Id: dc21285.c,v 1.9 2002/10/14 12:22:10 rmk Exp $
-+ * $Id: dc21285.c,v 1.22 2004/11/01 13:39:21 rmk Exp $
- */
- #include <linux/config.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -18,143 +20,199 @@
-
- #include <asm/io.h>
- #include <asm/hardware/dec21285.h>
-+#include <asm/mach-types.h>
-
-
--static struct mtd_info *mymtd;
-+static struct mtd_info *dc21285_mtd;
-
--__u8 dc21285_read8(struct map_info *map, unsigned long ofs)
-+#ifdef CONFIG_ARCH_NETWINDER
-+/*
-+ * This is really ugly, but it seams to be the only
-+ * realiable way to do it, as the cpld state machine
-+ * is unpredictible. So we have a 25us penalty per
-+ * write access.
-+ */
-+static void nw_en_write(void)
- {
-- return *(__u8*)(map->map_priv_1 + ofs);
-+ extern spinlock_t gpio_lock;
-+ unsigned long flags;
-+
-+ /*
-+ * we want to write a bit pattern XXX1 to Xilinx to enable
-+ * the write gate, which will be open for about the next 2ms.
-+ */
-+ spin_lock_irqsave(&gpio_lock, flags);
-+ cpld_modify(1, 1);
-+ spin_unlock_irqrestore(&gpio_lock, flags);
-+
-+ /*
-+ * let the ISA bus to catch on...
-+ */
-+ udelay(25);
- }
-+#else
-+#define nw_en_write() do { } while (0)
-+#endif
-
--__u16 dc21285_read16(struct map_info *map, unsigned long ofs)
-+static map_word dc21285_read8(struct map_info *map, unsigned long ofs)
- {
-- return *(__u16*)(map->map_priv_1 + ofs);
-+ map_word val;
-+ val.x[0] = *(uint8_t*)(map->virt + ofs);
-+ return val;
- }
-
--__u32 dc21285_read32(struct map_info *map, unsigned long ofs)
-+static map_word dc21285_read16(struct map_info *map, unsigned long ofs)
- {
-- return *(__u32*)(map->map_priv_1 + ofs);
-+ map_word val;
-+ val.x[0] = *(uint16_t*)(map->virt + ofs);
-+ return val;
- }
-
--void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-+static map_word dc21285_read32(struct map_info *map, unsigned long ofs)
- {
-- memcpy(to, (void*)(map->map_priv_1 + from), len);
-+ map_word val;
-+ val.x[0] = *(uint32_t*)(map->virt + ofs);
-+ return val;
- }
-
--void dc21285_write8(struct map_info *map, __u8 d, unsigned long adr)
-+static void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
- {
-+ memcpy(to, (void*)(map->virt + from), len);
-+}
-+
-+static void dc21285_write8(struct map_info *map, const map_word d, unsigned long adr)
-+{
-+ if (machine_is_netwinder())
-+ nw_en_write();
- *CSR_ROMWRITEREG = adr & 3;
- adr &= ~3;
-- *(__u8*)(map->map_priv_1 + adr) = d;
-+ *(uint8_t*)(map->virt + adr) = d.x[0];
- }
-
--void dc21285_write16(struct map_info *map, __u16 d, unsigned long adr)
-+static void dc21285_write16(struct map_info *map, const map_word d, unsigned long adr)
- {
-+ if (machine_is_netwinder())
-+ nw_en_write();
- *CSR_ROMWRITEREG = adr & 3;
- adr &= ~3;
-- *(__u16*)(map->map_priv_1 + adr) = d;
-+ *(uint16_t*)(map->virt + adr) = d.x[0];
- }
-
--void dc21285_write32(struct map_info *map, __u32 d, unsigned long adr)
-+static void dc21285_write32(struct map_info *map, const map_word d, unsigned long adr)
- {
-- *(__u32*)(map->map_priv_1 + adr) = d;
-+ if (machine_is_netwinder())
-+ nw_en_write();
-+ *(uint32_t*)(map->virt + adr) = d.x[0];
- }
-
--void dc21285_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-+static void dc21285_copy_to_32(struct map_info *map, unsigned long to, const void *from, ssize_t len)
- {
-- switch (map->buswidth) {
-- case 4:
- while (len > 0) {
-- __u32 d = *((__u32*)from)++;
-+ map_word d;
-+ d.x[0] = *((uint32_t*)from)++;
- dc21285_write32(map, d, to);
- to += 4;
- len -= 4;
- }
-- break;
-- case 2:
-+}
-+
-+static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-+{
- while (len > 0) {
-- __u16 d = *((__u16*)from)++;
-+ map_word d;
-+ d.x[0] = *((uint16_t*)from)++;
- dc21285_write16(map, d, to);
- to += 2;
- len -= 2;
- }
-- break;
-- case 1:
-- while (len > 0) {
-- __u8 d = *((__u8*)from)++;
-+}
-+
-+static void dc21285_copy_to_8(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-+{
-+ map_word d;
-+ d.x[0] = *((uint8_t*)from)++;
- dc21285_write8(map, d, to);
- to++;
- len--;
-- }
-- break;
-- }
- }
-
--struct map_info dc21285_map = {
-- name: "DC21285 flash",
-- size: 16*1024*1024,
-- read8: dc21285_read8,
-- read16: dc21285_read16,
-- read32: dc21285_read32,
-- copy_from: dc21285_copy_from,
-- write8: dc21285_write8,
-- write16: dc21285_write16,
-- write32: dc21285_write32,
-- copy_to: dc21285_copy_to
-+static struct map_info dc21285_map = {
-+ .name = "DC21285 flash",
-+ .phys = NO_XIP,
-+ .size = 16*1024*1024,
-+ .copy_from = dc21285_copy_from,
- };
-
-
- /* Partition stuff */
-+#ifdef CONFIG_MTD_PARTITIONS
- static struct mtd_partition *dc21285_parts;
-+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-+#endif
-
--extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **);
--
--int __init init_dc21285(void)
-+static int __init init_dc21285(void)
- {
-- /* Determine buswidth */
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+ int nrparts;
-+#endif
-+
-+ /* Determine bankwidth */
- switch (*CSR_SA110_CNTL & (3<<14)) {
- case SA110_CNTL_ROMWIDTH_8:
-- dc21285_map.buswidth = 1;
-+ dc21285_map.bankwidth = 1;
-+ dc21285_map.read = dc21285_read8;
-+ dc21285_map.write = dc21285_write8;
-+ dc21285_map.copy_to = dc21285_copy_to_8;
- break;
- case SA110_CNTL_ROMWIDTH_16:
-- dc21285_map.buswidth = 2;
-+ dc21285_map.bankwidth = 2;
-+ dc21285_map.read = dc21285_read16;
-+ dc21285_map.write = dc21285_write16;
-+ dc21285_map.copy_to = dc21285_copy_to_16;
- break;
- case SA110_CNTL_ROMWIDTH_32:
-- dc21285_map.buswidth = 4;
-+ dc21285_map.bankwidth = 4;
-+ dc21285_map.read = dc21285_read32;
-+ dc21285_map.write = dc21285_write32;
-+ dc21285_map.copy_to = dc21285_copy_to_32;
- break;
- default:
-- printk (KERN_ERR "DC21285 flash: undefined buswidth\n");
-+ printk (KERN_ERR "DC21285 flash: undefined bankwidth\n");
- return -ENXIO;
- }
-- printk (KERN_NOTICE "DC21285 flash support (%d-bit buswidth)\n",
-- dc21285_map.buswidth*8);
-+ printk (KERN_NOTICE "DC21285 flash support (%d-bit bankwidth)\n",
-+ dc21285_map.bankwidth*8);
-
- /* Let's map the flash area */
-- dc21285_map.map_priv_1 = (unsigned long)ioremap(DC21285_FLASH, 16*1024*1024);
-- if (!dc21285_map.map_priv_1) {
-+ dc21285_map.virt = ioremap(DC21285_FLASH, 16*1024*1024);
-+ if (!dc21285_map.virt) {
- printk("Failed to ioremap\n");
- return -EIO;
- }
-
-- mymtd = do_map_probe("cfi_probe", &dc21285_map);
-- if (mymtd) {
-- int nrparts = 0;
-+ if (machine_is_ebsa285()) {
-+ dc21285_mtd = do_map_probe("cfi_probe", &dc21285_map);
-+ } else {
-+ dc21285_mtd = do_map_probe("jedec_probe", &dc21285_map);
-+ }
-
-- mymtd->module = THIS_MODULE;
-+ if (!dc21285_mtd) {
-+ iounmap(dc21285_map.virt);
-+ return -ENXIO;
-+ }
-
-- /* partition fixup */
-+ dc21285_mtd->owner = THIS_MODULE;
-
--#ifdef CONFIG_MTD_REDBOOT_PARTS
-- nrparts = parse_redboot_partitions(mymtd, &dc21285_parts);
-+#ifdef CONFIG_MTD_PARTITIONS
-+ nrparts = parse_mtd_partitions(dc21285_mtd, probes, &dc21285_parts, 0);
-+ if (nrparts > 0)
-+ add_mtd_partitions(dc21285_mtd, dc21285_parts, nrparts);
-+ else
- #endif
-- if (nrparts > 0) {
-- add_mtd_partitions(mymtd, dc21285_parts, nrparts);
-- } else if (nrparts == 0) {
-- printk(KERN_NOTICE "RedBoot partition table failed\n");
-- add_mtd_device(mymtd);
-- }
-+ add_mtd_device(dc21285_mtd);
-
-+ if(machine_is_ebsa285()) {
- /*
- * Flash timing is determined with bits 19-16 of the
- * CSR_SA110_CNTL. The value is the number of wait cycles, or
-@@ -167,27 +225,23 @@
- *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20));
- /* tristate time */
- *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
--
-- return 0;
- }
-
-- iounmap((void *)dc21285_map.map_priv_1);
-- return -ENXIO;
-+ return 0;
- }
-
- static void __exit cleanup_dc21285(void)
- {
-- if (mymtd) {
-- del_mtd_device(mymtd);
-- map_destroy(mymtd);
-- mymtd = NULL;
-- }
-- if (dc21285_map.map_priv_1) {
-- iounmap((void *)dc21285_map.map_priv_1);
-- dc21285_map.map_priv_1 = 0;
-- }
-- if(dc21285_parts)
-+#ifdef CONFIG_MTD_PARTITIONS
-+ if (dc21285_parts) {
-+ del_mtd_partitions(dc21285_mtd);
- kfree(dc21285_parts);
-+ } else
-+#endif
-+ del_mtd_device(dc21285_mtd);
-+
-+ map_destroy(dc21285_mtd);
-+ iounmap(dc21285_map.virt);
- }
-
- module_init(init_dc21285);
---- linux-2.4.21/drivers/mtd/maps/dilnetpc.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/dilnetpc.c
-@@ -14,7 +14,7 @@
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- *
-- * $Id: dilnetpc.c,v 1.8 2002/03/12 13:07:26 rkaiser Exp $
-+ * $Id: dilnetpc.c,v 1.18 2005/01/12 22:34:35 gleixner Exp $
- *
- * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems
- * featuring the AMD Elan SC410 processor. There are two variants of this
-@@ -29,6 +29,7 @@
- #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>
-@@ -36,7 +37,7 @@
- #include <linux/mtd/concat.h>
-
- /*
--** The DIL/NetPC keeps it's BIOS in two distinct flash blocks.
-+** The DIL/NetPC keeps its BIOS in two distinct flash blocks.
- ** Destroying any of these blocks transforms the DNPC into
- ** a paperweight (albeit not a very useful one, considering
- ** it only weighs a few grams).
-@@ -189,45 +190,6 @@
- }
-
-
--static __u8 dnpc_read8(struct map_info *map, unsigned long ofs)
--{
-- return readb(map->map_priv_1 + ofs);
--}
--
--static __u16 dnpc_read16(struct map_info *map, unsigned long ofs)
--{
-- return readw(map->map_priv_1 + ofs);
--}
--
--static __u32 dnpc_read32(struct map_info *map, unsigned long ofs)
--{
-- return readl(map->map_priv_1 + ofs);
--}
--
--static void dnpc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
--}
--
--static void dnpc_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- writeb(d, map->map_priv_1 + adr);
--}
--
--static void dnpc_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- writew(d, map->map_priv_1 + adr);
--}
--
--static void dnpc_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- writel(d, map->map_priv_1 + adr);
--}
--
--static void dnpc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio((void *)(map->map_priv_1 + to), from, len);
--}
-
- /*
- ************************************************************
-@@ -235,7 +197,7 @@
- ************************************************************
- */
-
--static spinlock_t dnpc_spin = SPIN_LOCK_UNLOCKED;
-+static DEFINE_SPINLOCK(dnpc_spin);
- static int vpp_counter = 0;
- /*
- ** This is what has to be done for the DNP board ..
-@@ -288,19 +250,11 @@
- #define WINDOW_ADDR FLASH_BASE
-
- static struct map_info dnpc_map = {
-- name: "ADNP Flash Bank",
-- size: ADNP_WINDOW_SIZE,
-- buswidth: 1,
-- read8: dnpc_read8,
-- read16: dnpc_read16,
-- read32: dnpc_read32,
-- copy_from: dnpc_copy_from,
-- write8: dnpc_write8,
-- write16: dnpc_write16,
-- write32: dnpc_write32,
-- copy_to: dnpc_copy_to,
-- set_vpp: adnp_set_vpp,
-- map_priv_2: WINDOW_ADDR
-+ .name = "ADNP Flash Bank",
-+ .size = ADNP_WINDOW_SIZE,
-+ .bankwidth = 1,
-+ .set_vpp = adnp_set_vpp,
-+ .phys = WINDOW_ADDR
- };
-
- /*
-@@ -316,29 +270,29 @@
- static struct mtd_partition partition_info[]=
- {
- {
-- name: "ADNP boot",
-- offset: 0,
-- size: 0xf0000,
-+ .name = "ADNP boot",
-+ .offset = 0,
-+ .size = 0xf0000,
- },
- {
-- name: "ADNP system BIOS",
-- offset: MTDPART_OFS_NXTBLK,
-- size: 0x10000,
-+ .name = "ADNP system BIOS",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = 0x10000,
- #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
-- mask_flags: MTD_WRITEABLE,
-+ .mask_flags = MTD_WRITEABLE,
- #endif
- },
- {
-- name: "ADNP file system",
-- offset: MTDPART_OFS_NXTBLK,
-- size: 0x2f0000,
-+ .name = "ADNP file system",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = 0x2f0000,
- },
- {
-- name: "ADNP system BIOS entry",
-- offset: MTDPART_OFS_NXTBLK,
-- size: MTDPART_SIZ_FULL,
-+ .name = "ADNP system BIOS entry",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = MTDPART_SIZ_FULL,
- #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
-- mask_flags: MTD_WRITEABLE,
-+ .mask_flags = MTD_WRITEABLE,
- #endif
- },
- };
-@@ -369,21 +323,21 @@
- static struct mtd_partition higlvl_partition_info[]=
- {
- {
-- name: "ADNP boot block",
-- offset: 0,
-- size: CONFIG_MTD_DILNETPC_BOOTSIZE,
-+ .name = "ADNP boot block",
-+ .offset = 0,
-+ .size = CONFIG_MTD_DILNETPC_BOOTSIZE,
- },
- {
-- name: "ADNP file system space",
-- offset: MTDPART_OFS_NXTBLK,
-- size: ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000,
-+ .name = "ADNP file system space",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000,
- },
- {
-- name: "ADNP system BIOS + BIOS Entry",
-- offset: MTDPART_OFS_NXTBLK,
-- size: MTDPART_SIZ_FULL,
-+ .name = "ADNP system BIOS + BIOS Entry",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = MTDPART_SIZ_FULL,
- #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
-- mask_flags: MTD_WRITEABLE,
-+ .mask_flags = MTD_WRITEABLE,
- #endif
- },
- };
-@@ -447,18 +401,19 @@
- }
-
- printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n",
-- is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.map_priv_2);
-+ is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys);
-
-- dnpc_map.map_priv_1 = (unsigned long)ioremap_nocache(dnpc_map.map_priv_2, dnpc_map.size);
-+ dnpc_map.virt = ioremap_nocache(dnpc_map.phys, dnpc_map.size);
-
-- dnpc_map_flash(dnpc_map.map_priv_2, dnpc_map.size);
-+ dnpc_map_flash(dnpc_map.phys, dnpc_map.size);
-
-- if (!dnpc_map.map_priv_1) {
-+ if (!dnpc_map.virt) {
- printk("Failed to ioremap_nocache\n");
- return -EIO;
- }
-+ simple_map_init(&dnpc_map);
-
-- printk("FLASH virtual address: 0x%lx\n", dnpc_map.map_priv_1);
-+ printk("FLASH virtual address: 0x%p\n", dnpc_map.virt);
-
- mymtd = do_map_probe("jedec_probe", &dnpc_map);
-
-@@ -475,11 +430,11 @@
- mymtd->erasesize = 0x10000;
-
- if (!mymtd) {
-- iounmap((void *)dnpc_map.map_priv_1);
-+ iounmap(dnpc_map.virt);
- return -ENXIO;
- }
-
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
- /*
- ** Supply pointers to lowlvl_parts[] array to add_mtd_partitions()
-@@ -525,10 +480,10 @@
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- }
-- if (dnpc_map.map_priv_1) {
-- iounmap((void *)dnpc_map.map_priv_1);
-+ if (dnpc_map.virt) {
-+ iounmap(dnpc_map.virt);
- dnpc_unmap_flash();
-- dnpc_map.map_priv_1 = 0;
-+ dnpc_map.virt = NULL;
- }
- }
-
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/dmv182.c
-@@ -0,0 +1,149 @@
-+
-+/*
-+ * drivers/mtd/maps/svme182.c
-+ *
-+ * Flash map driver for the Dy4 SVME182 board
-+ *
-+ * $Id: dmv182.c,v 1.5 2004/11/04 13:24:14 gleixner Exp $
-+ *
-+ * Copyright 2003-2004, TimeSys Corporation
-+ *
-+ * Based on the SVME181 flash map, by Tom Nelson, Dot4, Inc. for TimeSys Corp.
-+ *
-+ * This program is free software; 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/module.h>
-+#include <linux/init.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <asm/io.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/errno.h>
-+
-+/*
-+ * This driver currently handles only the 16MiB user flash bank 1 on the
-+ * board. It does not provide access to bank 0 (contains the Dy4 FFW), bank 2
-+ * (VxWorks boot), or the optional 48MiB expansion flash.
-+ *
-+ * scott.wood@timesys.com: On the newer boards with 128MiB flash, it
-+ * now supports the first 96MiB (the boot flash bank containing FFW
-+ * is excluded). The VxWorks loader is in partition 1.
-+ */
-+
-+#define FLASH_BASE_ADDR 0xf0000000
-+#define FLASH_BANK_SIZE (128*1024*1024)
-+
-+MODULE_AUTHOR("Scott Wood, TimeSys Corporation <scott.wood@timesys.com>");
-+MODULE_DESCRIPTION("User-programmable flash device on the Dy4 SVME182 board");
-+MODULE_LICENSE("GPL");
-+
-+static struct map_info svme182_map = {
-+ .name = "Dy4 SVME182",
-+ .bankwidth = 32,
-+ .size = 128 * 1024 * 1024
-+};
-+
-+#define BOOTIMAGE_PART_SIZE ((6*1024*1024)-RESERVED_PART_SIZE)
-+
-+// Allow 6MiB for the kernel
-+#define NEW_BOOTIMAGE_PART_SIZE (6 * 1024 * 1024)
-+// Allow 1MiB for the bootloader
-+#define NEW_BOOTLOADER_PART_SIZE (1024 * 1024)
-+// Use the remaining 9MiB at the end of flash for the RFS
-+#define NEW_RFS_PART_SIZE (0x01000000 - NEW_BOOTLOADER_PART_SIZE - \
-+ NEW_BOOTIMAGE_PART_SIZE)
-+
-+static struct mtd_partition svme182_partitions[] = {
-+ // The Lower PABS is only 128KiB, but the partition code doesn't
-+ // like partitions that don't end on the largest erase block
-+ // size of the device, even if all of the erase blocks in the
-+ // partition are small ones. The hardware should prevent
-+ // writes to the actual PABS areas.
-+ {
-+ name: "Lower PABS and CPU 0 bootloader or kernel",
-+ size: 6*1024*1024,
-+ offset: 0,
-+ },
-+ {
-+ name: "Root Filesystem",
-+ size: 10*1024*1024,
-+ offset: MTDPART_OFS_NXTBLK
-+ },
-+ {
-+ name: "CPU1 Bootloader",
-+ size: 1024*1024,
-+ offset: MTDPART_OFS_NXTBLK,
-+ },
-+ {
-+ name: "Extra",
-+ size: 110*1024*1024,
-+ offset: MTDPART_OFS_NXTBLK
-+ },
-+ {
-+ name: "Foundation Firmware and Upper PABS",
-+ size: 1024*1024,
-+ offset: MTDPART_OFS_NXTBLK,
-+ mask_flags: MTD_WRITEABLE // read-only
-+ }
-+};
-+
-+static struct mtd_info *this_mtd;
-+
-+static int __init init_svme182(void)
-+{
-+ struct mtd_partition *partitions;
-+ int num_parts = sizeof(svme182_partitions) / sizeof(struct mtd_partition);
-+
-+ partitions = svme182_partitions;
-+
-+ svme182_map.virt = ioremap(FLASH_BASE_ADDR, svme182_map.size);
-+
-+ if (svme182_map.virt == 0) {
-+ printk("Failed to ioremap FLASH memory area.\n");
-+ return -EIO;
-+ }
-+
-+ simple_map_init(&svme182_map);
-+
-+ this_mtd = do_map_probe("cfi_probe", &svme182_map);
-+ if (!this_mtd)
-+ {
-+ iounmap((void *)svme182_map.virt);
-+ return -ENXIO;
-+ }
-+
-+ printk(KERN_NOTICE "SVME182 flash device: %dMiB at 0x%08x\n",
-+ this_mtd->size >> 20, FLASH_BASE_ADDR);
-+
-+ this_mtd->owner = THIS_MODULE;
-+ add_mtd_partitions(this_mtd, partitions, num_parts);
-+
-+ return 0;
-+}
-+
-+static void __exit cleanup_svme182(void)
-+{
-+ if (this_mtd)
-+ {
-+ del_mtd_partitions(this_mtd);
-+ map_destroy(this_mtd);
-+ }
-+
-+ if (svme182_map.virt)
-+ {
-+ iounmap((void *)svme182_map.virt);
-+ svme182_map.virt = 0;
-+ }
-+
-+ return;
-+}
-+
-+module_init(init_svme182);
-+module_exit(cleanup_svme182);
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/ebony.c
-@@ -0,0 +1,163 @@
-+/*
-+ * $Id: ebony.c,v 1.15 2004/12/09 18:39:54 holindho Exp $
-+ *
-+ * Mapping for Ebony user flash
-+ *
-+ * Matt Porter <mporter@kernel.crashing.org>
-+ *
-+ * Copyright 2002-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 as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <asm/io.h>
-+#include <asm/ibm44x.h>
-+#include <platforms/4xx/ebony.h>
-+
-+static struct mtd_info *flash;
-+
-+static struct map_info ebony_small_map = {
-+ .name = "Ebony small flash",
-+ .size = EBONY_SMALL_FLASH_SIZE,
-+ .bankwidth = 1,
-+};
-+
-+static struct map_info ebony_large_map = {
-+ .name = "Ebony large flash",
-+ .size = EBONY_LARGE_FLASH_SIZE,
-+ .bankwidth = 1,
-+};
-+
-+static struct mtd_partition ebony_small_partitions[] = {
-+ {
-+ .name = "OpenBIOS",
-+ .offset = 0x0,
-+ .size = 0x80000,
-+ }
-+};
-+
-+static struct mtd_partition ebony_large_partitions[] = {
-+ {
-+ .name = "fs",
-+ .offset = 0,
-+ .size = 0x380000,
-+ },
-+ {
-+ .name = "firmware",
-+ .offset = 0x380000,
-+ .size = 0x80000,
-+ }
-+};
-+
-+int __init init_ebony(void)
-+{
-+ u8 fpga0_reg;
-+ u8 __iomem *fpga0_adr;
-+ unsigned long long small_flash_base, large_flash_base;
-+
-+ fpga0_adr = ioremap64(EBONY_FPGA_ADDR, 16);
-+ if (!fpga0_adr)
-+ return -ENOMEM;
-+
-+ fpga0_reg = readb(fpga0_adr);
-+ iounmap(fpga0_adr);
-+
-+ if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
-+ !EBONY_FLASH_SEL(fpga0_reg))
-+ small_flash_base = EBONY_SMALL_FLASH_HIGH2;
-+ else if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
-+ EBONY_FLASH_SEL(fpga0_reg))
-+ small_flash_base = EBONY_SMALL_FLASH_HIGH1;
-+ else if (!EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
-+ !EBONY_FLASH_SEL(fpga0_reg))
-+ small_flash_base = EBONY_SMALL_FLASH_LOW2;
-+ else
-+ small_flash_base = EBONY_SMALL_FLASH_LOW1;
-+
-+ if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
-+ !EBONY_ONBRD_FLASH_EN(fpga0_reg))
-+ large_flash_base = EBONY_LARGE_FLASH_LOW;
-+ else
-+ large_flash_base = EBONY_LARGE_FLASH_HIGH;
-+
-+ ebony_small_map.phys = small_flash_base;
-+ ebony_small_map.virt = ioremap64(small_flash_base,
-+ ebony_small_map.size);
-+
-+ if (!ebony_small_map.virt) {
-+ printk("Failed to ioremap flash\n");
-+ return -EIO;
-+ }
-+
-+ simple_map_init(&ebony_small_map);
-+
-+ flash = do_map_probe("jedec_probe", &ebony_small_map);
-+ if (flash) {
-+ flash->owner = THIS_MODULE;
-+ add_mtd_partitions(flash, ebony_small_partitions,
-+ ARRAY_SIZE(ebony_small_partitions));
-+ } else {
-+ printk("map probe failed for flash\n");
-+ return -ENXIO;
-+ }
-+
-+ ebony_large_map.phys = large_flash_base;
-+ ebony_large_map.virt = ioremap64(large_flash_base,
-+ ebony_large_map.size);
-+
-+ if (!ebony_large_map.virt) {
-+ printk("Failed to ioremap flash\n");
-+ return -EIO;
-+ }
-+
-+ simple_map_init(&ebony_large_map);
-+
-+ flash = do_map_probe("jedec_probe", &ebony_large_map);
-+ if (flash) {
-+ flash->owner = THIS_MODULE;
-+ add_mtd_partitions(flash, ebony_large_partitions,
-+ ARRAY_SIZE(ebony_large_partitions));
-+ } else {
-+ printk("map probe failed for flash\n");
-+ return -ENXIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static void __exit cleanup_ebony(void)
-+{
-+ if (flash) {
-+ del_mtd_partitions(flash);
-+ map_destroy(flash);
-+ }
-+
-+ if (ebony_small_map.virt) {
-+ iounmap(ebony_small_map.virt);
-+ ebony_small_map.virt = NULL;
-+ }
-+
-+ if (ebony_large_map.virt) {
-+ iounmap(ebony_large_map.virt);
-+ ebony_large_map.virt = NULL;
-+ }
-+}
-+
-+module_init(init_ebony);
-+module_exit(cleanup_ebony);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>");
-+MODULE_DESCRIPTION("MTD map and partitions for IBM 440GP Ebony boards");
---- linux-2.4.21/drivers/mtd/maps/edb7312.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/edb7312.c
-@@ -1,5 +1,5 @@
- /*
-- * $Id: edb7312.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $
-+ * $Id: edb7312.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $
- *
- * Handle mapping of the NOR flash on Cogent EDB7312 boards
- *
-@@ -13,6 +13,7 @@
- #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>
-@@ -27,69 +28,19 @@
- #define BUSWIDTH 2
- #define FLASH_BLOCKSIZE_MAIN 0x20000
- #define FLASH_NUMBLOCKS_MAIN 128
--/* can be "cfi_probe", "jedec_probe", "map_rom", 0 }; */
--#define PROBETYPES { "cfi_probe", 0 }
-+/* can be "cfi_probe", "jedec_probe", "map_rom", NULL }; */
-+#define PROBETYPES { "cfi_probe", NULL }
-
- #define MSG_PREFIX "EDB7312-NOR:" /* prefix for our printk()'s */
- #define MTDID "edb7312-nor" /* for mtdparts= partitioning */
-
- static struct mtd_info *mymtd;
-
--__u8 edb7312nor_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 edb7312nor_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 edb7312nor_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void edb7312nor_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void edb7312nor_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void edb7312nor_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void edb7312nor_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void edb7312nor_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
--
- struct map_info edb7312nor_map = {
-- name: "NOR flash on EDB7312",
-- size: WINDOW_SIZE,
-- buswidth: BUSWIDTH,
-- read8: edb7312nor_read8,
-- read16: edb7312nor_read16,
-- read32: edb7312nor_read32,
-- copy_from: edb7312nor_copy_from,
-- write8: edb7312nor_write8,
-- write16: edb7312nor_write16,
-- write32: edb7312nor_write32,
-- copy_to: edb7312nor_copy_to
-+ .name = "NOR flash on EDB7312",
-+ .size = WINDOW_SIZE,
-+ .bankwidth = BUSWIDTH,
-+ .phys = WINDOW_ADDR,
- };
-
- #ifdef CONFIG_MTD_PARTITIONS
-@@ -100,29 +51,23 @@
- static struct mtd_partition static_partitions[3] =
- {
- {
-- name: "ARMboot",
-- size: 0x40000,
-- offset: 0
-+ .name = "ARMboot",
-+ .size = 0x40000,
-+ .offset = 0
- },
- {
-- name: "Kernel",
-- size: 0x200000,
-- offset: 0x40000
-+ .name = "Kernel",
-+ .size = 0x200000,
-+ .offset = 0x40000
- },
- {
-- name: "RootFS",
-- size: 0xDC0000,
-- offset: 0x240000
-+ .name = "RootFS",
-+ .size = 0xDC0000,
-+ .offset = 0x240000
- },
- };
-
--#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
--
--#ifdef CONFIG_MTD_CMDLINE_PARTS
--int parse_cmdline_partitions(struct mtd_info *master,
-- struct mtd_partition **pparts,
-- const char *mtd_id);
--#endif
-+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-
- #endif
-
-@@ -137,32 +82,32 @@
-
- printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n",
- WINDOW_SIZE, WINDOW_ADDR);
-- edb7312nor_map.map_priv_1 = (unsigned long)
-- ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+ edb7312nor_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
-
-- if (!edb7312nor_map.map_priv_1) {
-+ if (!edb7312nor_map.virt) {
- printk(MSG_PREFIX "failed to ioremap\n");
- return -EIO;
- }
-
-+ simple_map_init(&edb7312nor_map);
-+
- mymtd = 0;
- type = rom_probe_types;
- for(; !mymtd && *type; type++) {
- mymtd = do_map_probe(*type, &edb7312nor_map);
- }
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
- #ifdef CONFIG_MTD_PARTITIONS
--#ifdef CONFIG_MTD_CMDLINE_PARTS
-- mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, MTDID);
-+ mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, MTDID);
- if (mtd_parts_nb > 0)
-- part_type = "command line";
--#endif
-+ part_type = "detected";
-+
- if (mtd_parts_nb == 0)
- {
- mtd_parts = static_partitions;
-- mtd_parts_nb = NB_OF(static_partitions);
-+ mtd_parts_nb = ARRAY_SIZE(static_partitions);
- part_type = "static";
- }
- #endif
-@@ -178,7 +123,7 @@
- return 0;
- }
-
-- iounmap((void *)edb7312nor_map.map_priv_1);
-+ iounmap((void *)edb7312nor_map.virt);
- return -ENXIO;
- }
-
-@@ -188,9 +133,9 @@
- del_mtd_device(mymtd);
- map_destroy(mymtd);
- }
-- if (edb7312nor_map.map_priv_1) {
-- iounmap((void *)edb7312nor_map.map_priv_1);
-- edb7312nor_map.map_priv_1 = 0;
-+ if (edb7312nor_map.virt) {
-+ iounmap((void *)edb7312nor_map.virt);
-+ edb7312nor_map.virt = 0;
- }
- }
-
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/epxa10db-flash.c
-@@ -0,0 +1,176 @@
-+/*
-+ * Flash memory access on EPXA based devices
-+ *
-+ * (C) 2000 Nicolas Pitre <nico@cam.org>
-+ * Copyright (C) 2001 Altera Corporation
-+ * Copyright (C) 2001 Red Hat, Inc.
-+ *
-+ * $Id: epxa10db-flash.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $
-+ *
-+ * This program is free software; 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/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/mtd/partitions.h>
-+
-+#include <asm/hardware.h>
-+#ifdef CONFIG_EPXA10DB
-+#define BOARD_NAME "EPXA10DB"
-+#else
-+#define BOARD_NAME "EPXA1DB"
-+#endif
-+
-+static int nr_parts = 0;
-+static struct mtd_partition *parts;
-+
-+static struct mtd_info *mymtd;
-+
-+static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts);
-+
-+
-+static struct map_info epxa_map = {
-+ .name = "EPXA flash",
-+ .size = FLASH_SIZE,
-+ .bankwidth = 2,
-+ .phys = FLASH_START,
-+};
-+
-+static const char *probes[] = { "RedBoot", "afs", NULL };
-+
-+static int __init epxa_mtd_init(void)
-+{
-+ int i;
-+
-+ printk(KERN_NOTICE "%s flash device: 0x%x at 0x%x\n", BOARD_NAME, FLASH_SIZE, FLASH_START);
-+
-+ epxa_map.virt = ioremap(FLASH_START, FLASH_SIZE);
-+ if (!epxa_map.virt) {
-+ printk("Failed to ioremap %s flash\n",BOARD_NAME);
-+ return -EIO;
-+ }
-+ simple_map_init(&epxa_map);
-+
-+ mymtd = do_map_probe("cfi_probe", &epxa_map);
-+ if (!mymtd) {
-+ iounmap((void *)epxa_map.virt);
-+ return -ENXIO;
-+ }
-+
-+ mymtd->owner = THIS_MODULE;
-+
-+ /* Unlock the flash device. */
-+ if(mymtd->unlock){
-+ for (i=0; i<mymtd->numeraseregions;i++){
-+ int j;
-+ for(j=0;j<mymtd->eraseregions[i].numblocks;j++){
-+ mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,mymtd->eraseregions[i].erasesize);
-+ }
-+ }
-+ }
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+ nr_parts = parse_mtd_partitions(mymtd, probes, &parts, 0);
-+
-+ if (nr_parts > 0) {
-+ add_mtd_partitions(mymtd, parts, nr_parts);
-+ return 0;
-+ }
-+#endif
-+ /* No recognised partitioning schemes found - use defaults */
-+ nr_parts = epxa_default_partitions(mymtd, &parts);
-+ if (nr_parts > 0) {
-+ add_mtd_partitions(mymtd, parts, nr_parts);
-+ return 0;
-+ }
-+
-+ /* If all else fails... */
-+ add_mtd_device(mymtd);
-+ return 0;
-+}
-+
-+static void __exit epxa_mtd_cleanup(void)
-+{
-+ if (mymtd) {
-+ if (nr_parts)
-+ del_mtd_partitions(mymtd);
-+ else
-+ del_mtd_device(mymtd);
-+ map_destroy(mymtd);
-+ }
-+ if (epxa_map.virt) {
-+ iounmap((void *)epxa_map.virt);
-+ epxa_map.virt = 0;
-+ }
-+}
-+
-+
-+/*
-+ * This will do for now, once we decide which bootldr we're finally
-+ * going to use then we'll remove this function and do it properly
-+ *
-+ * Partions are currently (as offsets from base of flash):
-+ * 0x00000000 - 0x003FFFFF - bootloader (!)
-+ * 0x00400000 - 0x00FFFFFF - Flashdisk
-+ */
-+
-+static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts)
-+{
-+ struct mtd_partition *parts;
-+ int ret, i;
-+ int npartitions = 0;
-+ char *names;
-+ const char *name = "jffs";
-+
-+ printk("Using default partitions for %s\n",BOARD_NAME);
-+ npartitions=1;
-+ parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL);
-+ memzero(parts,npartitions*sizeof(*parts)+strlen(name));
-+ if (!parts) {
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+ i=0;
-+ names = (char *)&parts[npartitions];
-+ parts[i].name = names;
-+ names += strlen(name) + 1;
-+ strcpy(parts[i].name, name);
-+
-+#ifdef CONFIG_EPXA10DB
-+ parts[i].size = FLASH_SIZE-0x00400000;
-+ parts[i].offset = 0x00400000;
-+#else
-+ parts[i].size = FLASH_SIZE-0x00180000;
-+ parts[i].offset = 0x00180000;
-+#endif
-+
-+ out:
-+ *pparts = parts;
-+ return npartitions;
-+}
-+
-+
-+module_init(epxa_mtd_init);
-+module_exit(epxa_mtd_cleanup);
-+
-+MODULE_AUTHOR("Clive Davies");
-+MODULE_DESCRIPTION("Altera epxa mtd flash map");
-+MODULE_LICENSE("GPL");
---- linux-2.4.21/drivers/mtd/maps/fortunet.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/fortunet.c
-@@ -1,11 +1,12 @@
- /* fortunet.c memory map
- *
-- * $Id: fortunet.c,v 1.2 2002/10/14 12:50:22 rmk Exp $
-+ * $Id: fortunet.c,v 1.9 2004/11/04 13:24:14 gleixner 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>
-@@ -23,8 +24,8 @@
-
- struct map_region
- {
-- int window_addr_phyical;
-- int altbuswidth;
-+ int window_addr_physical;
-+ int altbankwidth;
- struct map_info map_info;
- struct mtd_info *mymtd;
- struct mtd_partition parts[MAX_NUM_PARTITIONS];
-@@ -37,57 +38,10 @@
- static int map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0};
-
-
--__u8 fortunet_read8(struct map_info *map, unsigned long ofs)
--{
-- return *(__u8 *)(map->map_priv_1 + ofs);
--}
--
--__u16 fortunet_read16(struct map_info *map, unsigned long ofs)
--{
-- return *(__u16 *)(map->map_priv_1 + ofs);
--}
--
--__u32 fortunet_read32(struct map_info *map, unsigned long ofs)
--{
-- return *(__u32 *)(map->map_priv_1 + ofs);
--}
--
--void fortunet_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy(to, (void *)(map->map_priv_1 + from), len);
--}
--
--void fortunet_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- *(__u8 *)(map->map_priv_1 + adr) = d;
--}
--
--void fortunet_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- *(__u16 *)(map->map_priv_1 + adr) = d;
--}
--
--void fortunet_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- *(__u32 *)(map->map_priv_1 + adr) = d;
--}
--
--void fortunet_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy((void *)(map->map_priv_1 + to), from, len);
--}
-
- struct map_info default_map = {
-- size: DEF_WINDOW_SIZE,
-- buswidth: 4,
-- read8: fortunet_read8,
-- read16: fortunet_read16,
-- read32: fortunet_read32,
-- copy_from: fortunet_copy_from,
-- write8: fortunet_write8,
-- write16: fortunet_write16,
-- write32: fortunet_write32,
-- copy_to: fortunet_copy_to
-+ .size = DEF_WINDOW_SIZE,
-+ .bankwidth = 4,
- };
-
- static char * __init get_string_option(char *dest,int dest_size,char *sor)
-@@ -147,8 +101,8 @@
- get_options (get_string_option(string,sizeof(string),line),6,params);
- if(params[0]<1)
- {
-- printk(MTD_FORTUNET_PK "Bad paramters for MTD Region "
-- " name,region-number[,base,size,buswidth,altbuswidth]\n");
-+ printk(MTD_FORTUNET_PK "Bad parameters for MTD Region "
-+ " name,region-number[,base,size,bankwidth,altbankwidth]\n");
- return 1;
- }
- if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
-@@ -161,14 +115,14 @@
- memcpy(&map_regions[params[1]].map_info,
- &default_map,sizeof(map_regions[params[1]].map_info));
- map_regions_set[params[1]] = 1;
-- map_regions[params[1]].window_addr_phyical = DEF_WINDOW_ADDR_PHY;
-- map_regions[params[1]].altbuswidth = 2;
-+ map_regions[params[1]].window_addr_physical = DEF_WINDOW_ADDR_PHY;
-+ map_regions[params[1]].altbankwidth = 2;
- map_regions[params[1]].mymtd = NULL;
- map_regions[params[1]].map_info.name = map_regions[params[1]].map_name;
- strcpy(map_regions[params[1]].map_info.name,string);
- if(params[0]>1)
- {
-- map_regions[params[1]].window_addr_phyical = params[2];
-+ map_regions[params[1]].window_addr_physical = params[2];
- }
- if(params[0]>2)
- {
-@@ -176,23 +130,23 @@
- }
- if(params[0]>3)
- {
-- map_regions[params[1]].map_info.buswidth = params[4];
-+ map_regions[params[1]].map_info.bankwidth = params[4];
- }
- if(params[0]>4)
- {
-- map_regions[params[1]].altbuswidth = params[5];
-+ map_regions[params[1]].altbankwidth = params[5];
- }
- return 1;
- }
-
--static int __init MTD_New_Partion(char *line)
-+static int __init MTD_New_Partition(char *line)
- {
- char string[MAX_NAME_SIZE];
- int params[4];
- get_options (get_string_option(string,sizeof(string),line),4,params);
- if(params[0]<3)
- {
-- printk(MTD_FORTUNET_PK "Bad paramters for MTD Partion "
-+ printk(MTD_FORTUNET_PK "Bad parameters for MTD Partition "
- " name,region-number,size,offset\n");
- return 1;
- }
-@@ -204,7 +158,7 @@
- }
- if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS)
- {
-- printk(MTD_FORTUNET_PK "Out of space for partion in this region\n");
-+ printk(MTD_FORTUNET_PK "Out of space for partition in this region\n");
- return 1;
- }
- map_regions[params[1]].parts[map_regions_parts[params[1]]].name =
-@@ -220,7 +174,10 @@
- }
-
- __setup("MTD_Region=", MTD_New_Region);
--__setup("MTD_Partion=", MTD_New_Partion);
-+__setup("MTD_Partition=", MTD_New_Partition);
-+
-+/* Backwards-spelling-compatibility */
-+__setup("MTD_Partion=", MTD_New_Partition);
-
- int __init init_fortunet(void)
- {
-@@ -229,14 +186,14 @@
- {
- if(map_regions_parts[ix]&&(!map_regions_set[ix]))
- {
-- printk(MTD_FORTUNET_PK "Region %d is not setup (Seting to default)\n",
-+ printk(MTD_FORTUNET_PK "Region %d is not setup (Setting to default)\n",
- ix);
- memset(&map_regions[ix],0,sizeof(map_regions[ix]));
- memcpy(&map_regions[ix].map_info,&default_map,
- sizeof(map_regions[ix].map_info));
- map_regions_set[ix] = 1;
-- map_regions[ix].window_addr_phyical = DEF_WINDOW_ADDR_PHY;
-- map_regions[ix].altbuswidth = 2;
-+ map_regions[ix].window_addr_physical = DEF_WINDOW_ADDR_PHY;
-+ map_regions[ix].altbankwidth = 2;
- map_regions[ix].mymtd = NULL;
- map_regions[ix].map_info.name = map_regions[ix].map_name;
- strcpy(map_regions[ix].map_info.name,"FORTUNET");
-@@ -244,38 +201,43 @@
- if(map_regions_set[ix])
- {
- iy++;
-- printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at phyicaly "
-+ printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at physically "
- " address %x size %x\n",
- map_regions[ix].map_info.name,
-- map_regions[ix].window_addr_phyical,
-+ map_regions[ix].window_addr_physical,
- map_regions[ix].map_info.size);
-- map_regions[ix].map_info.map_priv_1 =
-- (int)ioremap_nocache(
-- map_regions[ix].window_addr_phyical,
-+
-+ map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical,
-+
-+ map_regions[ix].map_info.virt =
-+ ioremap_nocache(
-+ map_regions[ix].window_addr_physical,
- map_regions[ix].map_info.size);
-- if(!map_regions[ix].map_info.map_priv_1)
-+ if(!map_regions[ix].map_info.virt)
- {
- printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
- map_regions[ix].map_info.name);
- return -ENXIO;
- }
-- printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is veritualy at: %x\n",
-+ simple_map_init(&map_regions[ix].map_info);
-+
-+ printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is virtually at: %x\n",
- map_regions[ix].map_info.name,
-- map_regions[ix].map_info.map_priv_1);
-+ map_regions[ix].map_info.virt);
- map_regions[ix].mymtd = do_map_probe("cfi_probe",
- &map_regions[ix].map_info);
- if((!map_regions[ix].mymtd)&&(
-- map_regions[ix].altbuswidth!=map_regions[ix].map_info.buswidth))
-+ map_regions[ix].altbankwidth!=map_regions[ix].map_info.bankwidth))
- {
-- printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternet buswidth "
-+ printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternate bankwidth "
- "for %s flash.\n",
- map_regions[ix].map_info.name);
-- map_regions[ix].map_info.buswidth =
-- map_regions[ix].altbuswidth;
-+ map_regions[ix].map_info.bankwidth =
-+ map_regions[ix].altbankwidth;
- map_regions[ix].mymtd = do_map_probe("cfi_probe",
- &map_regions[ix].map_info);
- }
-- map_regions[ix].mymtd->module = THIS_MODULE;
-+ map_regions[ix].mymtd->owner = THIS_MODULE;
- add_mtd_partitions(map_regions[ix].mymtd,
- map_regions[ix].parts,map_regions_parts[ix]);
- }
-@@ -297,7 +259,7 @@
- del_mtd_partitions( map_regions[ix].mymtd );
- map_destroy( map_regions[ix].mymtd );
- }
-- iounmap((void *)map_regions[ix].map_info.map_priv_1);
-+ iounmap((void *)map_regions[ix].map_info.virt);
- }
- }
- }
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/h720x-flash.c
-@@ -0,0 +1,144 @@
-+/*
-+ * Flash memory access on Hynix GMS30C7201/HMS30C7202 based
-+ * evaluation boards
-+ *
-+ * $Id: h720x-flash.c,v 1.11 2004/11/04 13:24:14 gleixner Exp $
-+ *
-+ * (C) 2002 Jungjun Kim <jungjun.kim@hynix.com>
-+ * 2003 Thomas Gleixner <tglx@linutronix.de>
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/slab.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/hardware.h>
-+#include <asm/io.h>
-+
-+static struct mtd_info *mymtd;
-+
-+static struct map_info h720x_map = {
-+ .name = "H720X",
-+ .bankwidth = 4,
-+ .size = FLASH_SIZE,
-+ .phys = FLASH_PHYS,
-+};
-+
-+static struct mtd_partition h720x_partitions[] = {
-+ {
-+ .name = "ArMon",
-+ .size = 0x00080000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE
-+ },{
-+ .name = "Env",
-+ .size = 0x00040000,
-+ .offset = 0x00080000,
-+ .mask_flags = MTD_WRITEABLE
-+ },{
-+ .name = "Kernel",
-+ .size = 0x00180000,
-+ .offset = 0x000c0000,
-+ .mask_flags = MTD_WRITEABLE
-+ },{
-+ .name = "Ramdisk",
-+ .size = 0x00400000,
-+ .offset = 0x00240000,
-+ .mask_flags = MTD_WRITEABLE
-+ },{
-+ .name = "jffs2",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND
-+ }
-+};
-+
-+#define NUM_PARTITIONS (sizeof(h720x_partitions)/sizeof(h720x_partitions[0]))
-+
-+static int nr_mtd_parts;
-+static struct mtd_partition *mtd_parts;
-+static const char *probes[] = { "cmdlinepart", NULL };
-+
-+/*
-+ * Initialize FLASH support
-+ */
-+int __init h720x_mtd_init(void)
-+{
-+
-+ char *part_type = NULL;
-+
-+ h720x_map.virt = ioremap(FLASH_PHYS, FLASH_SIZE);
-+
-+ if (!h720x_map.virt) {
-+ printk(KERN_ERR "H720x-MTD: ioremap failed\n");
-+ return -EIO;
-+ }
-+
-+ simple_map_init(&h720x_map);
-+
-+ // Probe for flash bankwidth 4
-+ printk (KERN_INFO "H720x-MTD probing 32bit FLASH\n");
-+ mymtd = do_map_probe("cfi_probe", &h720x_map);
-+ if (!mymtd) {
-+ printk (KERN_INFO "H720x-MTD probing 16bit FLASH\n");
-+ // Probe for bankwidth 2
-+ h720x_map.bankwidth = 2;
-+ mymtd = do_map_probe("cfi_probe", &h720x_map);
-+ }
-+
-+ if (mymtd) {
-+ mymtd->owner = THIS_MODULE;
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+ nr_mtd_parts = parse_mtd_partitions(mymtd, probes, &mtd_parts, 0);
-+ if (nr_mtd_parts > 0)
-+ part_type = "command line";
-+#endif
-+ if (nr_mtd_parts <= 0) {
-+ mtd_parts = h720x_partitions;
-+ nr_mtd_parts = NUM_PARTITIONS;
-+ part_type = "builtin";
-+ }
-+ printk(KERN_INFO "Using %s partition table\n", part_type);
-+ add_mtd_partitions(mymtd, mtd_parts, nr_mtd_parts);
-+ return 0;
-+ }
-+
-+ iounmap((void *)h720x_map.virt);
-+ return -ENXIO;
-+}
-+
-+/*
-+ * Cleanup
-+ */
-+static void __exit h720x_mtd_cleanup(void)
-+{
-+
-+ if (mymtd) {
-+ del_mtd_partitions(mymtd);
-+ map_destroy(mymtd);
-+ }
-+
-+ /* Free partition info, if commandline partition was used */
-+ if (mtd_parts && (mtd_parts != h720x_partitions))
-+ kfree (mtd_parts);
-+
-+ if (h720x_map.virt) {
-+ iounmap((void *)h720x_map.virt);
-+ h720x_map.virt = 0;
-+ }
-+}
-+
-+
-+module_init(h720x_mtd_init);
-+module_exit(h720x_mtd_cleanup);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
-+MODULE_DESCRIPTION("MTD map driver for Hynix evaluation boards");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/ichxrom.c
-@@ -0,0 +1,383 @@
-+/*
-+ * ichxrom.c
-+ *
-+ * Normal mappings of chips in physical memory
-+ * $Id: ichxrom.c,v 1.16 2004/11/28 09:40:39 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/mtd/cfi.h>
-+#include <linux/mtd/flashchip.h>
-+#include <linux/config.h>
-+#include <linux/pci.h>
-+#include <linux/pci_ids.h>
-+#include <linux/list.h>
-+
-+#define xstr(s) str(s)
-+#define str(s) #s
-+#define MOD_NAME xstr(KBUILD_BASENAME)
-+
-+#define ADDRESS_NAME_LEN 18
-+
-+#define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */
-+
-+#define BIOS_CNTL 0x4e
-+#define FWH_DEC_EN1 0xE3
-+#define FWH_DEC_EN2 0xF0
-+#define FWH_SEL1 0xE8
-+#define FWH_SEL2 0xEE
-+
-+struct ichxrom_window {
-+ void __iomem* virt;
-+ unsigned long phys;
-+ unsigned long size;
-+ struct list_head maps;
-+ struct resource rsrc;
-+ struct pci_dev *pdev;
-+};
-+
-+struct ichxrom_map_info {
-+ struct list_head list;
-+ struct map_info map;
-+ struct mtd_info *mtd;
-+ struct resource rsrc;
-+ char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
-+};
-+
-+static struct ichxrom_window ichxrom_window = {
-+ .maps = LIST_HEAD_INIT(ichxrom_window.maps),
-+};
-+
-+static void ichxrom_cleanup(struct ichxrom_window *window)
-+{
-+ struct ichxrom_map_info *map, *scratch;
-+ u16 word;
-+
-+ /* Disable writes through the rom window */
-+ pci_read_config_word(window->pdev, BIOS_CNTL, &word);
-+ pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
-+
-+ /* Free all of the mtd devices */
-+ list_for_each_entry_safe(map, scratch, &window->maps, list) {
-+ if (map->rsrc.parent)
-+ release_resource(&map->rsrc);
-+ del_mtd_device(map->mtd);
-+ map_destroy(map->mtd);
-+ list_del(&map->list);
-+ kfree(map);
-+ }
-+ if (window->rsrc.parent)
-+ release_resource(&window->rsrc);
-+ if (window->virt) {
-+ iounmap(window->virt);
-+ window->virt = NULL;
-+ window->phys = 0;
-+ window->size = 0;
-+ window->pdev = NULL;
-+ }
-+}
-+
-+
-+static int __devinit ichxrom_init_one (struct pci_dev *pdev,
-+ const struct pci_device_id *ent)
-+{
-+ static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
-+ struct ichxrom_window *window = &ichxrom_window;
-+ struct ichxrom_map_info *map = NULL;
-+ unsigned long map_top;
-+ u8 byte;
-+ u16 word;
-+
-+ /* 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.
-+ */
-+ window->pdev = pdev;
-+
-+ /* Find a region continuous to the end of the ROM window */
-+ window->phys = 0;
-+ pci_read_config_byte(pdev, FWH_DEC_EN1, &byte);
-+ if (byte == 0xff) {
-+ window->phys = 0xffc00000;
-+ pci_read_config_byte(pdev, FWH_DEC_EN2, &byte);
-+ if ((byte & 0x0f) == 0x0f) {
-+ window->phys = 0xff400000;
-+ }
-+ else if ((byte & 0x0e) == 0x0e) {
-+ window->phys = 0xff500000;
-+ }
-+ else if ((byte & 0x0c) == 0x0c) {
-+ window->phys = 0xff600000;
-+ }
-+ else if ((byte & 0x08) == 0x08) {
-+ window->phys = 0xff700000;
-+ }
-+ }
-+ else if ((byte & 0xfe) == 0xfe) {
-+ window->phys = 0xffc80000;
-+ }
-+ else if ((byte & 0xfc) == 0xfc) {
-+ window->phys = 0xffd00000;
-+ }
-+ else if ((byte & 0xf8) == 0xf8) {
-+ window->phys = 0xffd80000;
-+ }
-+ else if ((byte & 0xf0) == 0xf0) {
-+ window->phys = 0xffe00000;
-+ }
-+ else if ((byte & 0xe0) == 0xe0) {
-+ window->phys = 0xffe80000;
-+ }
-+ else if ((byte & 0xc0) == 0xc0) {
-+ window->phys = 0xfff00000;
-+ }
-+ else if ((byte & 0x80) == 0x80) {
-+ window->phys = 0xfff80000;
-+ }
-+
-+ if (window->phys == 0) {
-+ printk(KERN_ERR MOD_NAME ": Rom window is closed\n");
-+ goto out;
-+ }
-+ window->phys -= 0x400000UL;
-+ window->size = (0xffffffffUL - window->phys) + 1UL;
-+
-+ /* 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 out;
-+ }
-+ pci_write_config_word(pdev, BIOS_CNTL, word | 1);
-+
-+ /*
-+ * Try to reserve the window mem region. If this fails then
-+ * it is likely due to the window being "reseved" by the BIOS.
-+ */
-+ window->rsrc.name = MOD_NAME;
-+ window->rsrc.start = window->phys;
-+ window->rsrc.end = window->phys + window->size - 1;
-+ window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-+ if (request_resource(&iomem_resource, &window->rsrc)) {
-+ window->rsrc.parent = NULL;
-+ printk(KERN_DEBUG MOD_NAME
-+ ": %s(): Unable to register resource"
-+ " 0x%.08lx-0x%.08lx - kernel bug?\n",
-+ __func__,
-+ window->rsrc.start, window->rsrc.end);
-+ }
-+
-+ /* Map the firmware hub into my address space. */
-+ window->virt = ioremap_nocache(window->phys, window->size);
-+ if (!window->virt) {
-+ printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
-+ window->phys, window->size);
-+ goto out;
-+ }
-+
-+ /* Get the first address to look for an rom chip at */
-+ map_top = window->phys;
-+ if ((window->phys & 0x3fffff) != 0) {
-+ map_top = window->phys + 0x400000;
-+ }
-+#if 1
-+ /* The probe sequence run over the firmware hub lock
-+ * registers sets them to 0x7 (no access).
-+ * Probe at most the last 4M of the address space.
-+ */
-+ if (map_top < 0xffc00000) {
-+ map_top = 0xffc00000;
-+ }
-+#endif
-+ /* Loop through and look for rom chips */
-+ while((map_top - 1) < 0xffffffffUL) {
-+ struct cfi_private *cfi;
-+ unsigned long offset;
-+ int i;
-+
-+ if (!map) {
-+ map = kmalloc(sizeof(*map), GFP_KERNEL);
-+ }
-+ if (!map) {
-+ printk(KERN_ERR MOD_NAME ": kmalloc failed");
-+ goto out;
-+ }
-+ memset(map, 0, sizeof(*map));
-+ INIT_LIST_HEAD(&map->list);
-+ map->map.name = map->map_name;
-+ map->map.phys = map_top;
-+ offset = map_top - window->phys;
-+ map->map.virt = (void __iomem *)
-+ (((unsigned long)(window->virt)) + offset);
-+ map->map.size = 0xffffffffUL - map_top + 1UL;
-+ /* Set the name of the map to the address I am trying */
-+ sprintf(map->map_name, "%s @%08lx",
-+ MOD_NAME, map->map.phys);
-+
-+ /* Firmware hubs only use vpp when being programmed
-+ * in a factory setting. So in-place programming
-+ * needs to use a different method.
-+ */
-+ for(map->map.bankwidth = 32; map->map.bankwidth;
-+ map->map.bankwidth >>= 1)
-+ {
-+ char **probe_type;
-+ /* Skip bankwidths that are not supported */
-+ if (!map_bankwidth_supported(map->map.bankwidth))
-+ continue;
-+
-+ /* Setup the map methods */
-+ simple_map_init(&map->map);
-+
-+ /* Try all of the probe methods */
-+ probe_type = rom_probe_types;
-+ for(; *probe_type; probe_type++) {
-+ map->mtd = do_map_probe(*probe_type, &map->map);
-+ if (map->mtd)
-+ goto found;
-+ }
-+ }
-+ map_top += ROM_PROBE_STEP_SIZE;
-+ continue;
-+ found:
-+ /* Trim the size if we are larger than the map */
-+ if (map->mtd->size > map->map.size) {
-+ printk(KERN_WARNING MOD_NAME
-+ " rom(%u) larger than window(%lu). fixing...\n",
-+ map->mtd->size, map->map.size);
-+ map->mtd->size = map->map.size;
-+ }
-+ if (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.
-+ */
-+ map->rsrc.name = map->map_name;
-+ map->rsrc.start = map->map.phys;
-+ map->rsrc.end = map->map.phys + map->mtd->size - 1;
-+ map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-+ if (request_resource(&window->rsrc, &map->rsrc)) {
-+ printk(KERN_ERR MOD_NAME
-+ ": cannot reserve MTD resource\n");
-+ map->rsrc.parent = NULL;
-+ }
-+ }
-+
-+ /* Make the whole region visible in the map */
-+ map->map.virt = window->virt;
-+ map->map.phys = window->phys;
-+ cfi = map->map.fldrv_priv;
-+ for(i = 0; i < cfi->numchips; i++) {
-+ cfi->chips[i].start += offset;
-+ }
-+
-+ /* Now that the mtd devices is complete claim and export it */
-+ map->mtd->owner = THIS_MODULE;
-+ if (add_mtd_device(map->mtd)) {
-+ map_destroy(map->mtd);
-+ map->mtd = NULL;
-+ goto out;
-+ }
-+
-+
-+ /* Calculate the new value of map_top */
-+ map_top += map->mtd->size;
-+
-+ /* File away the map structure */
-+ list_add(&map->list, &window->maps);
-+ map = NULL;
-+ }
-+
-+ out:
-+ /* Free any left over map structures */
-+ if (map) {
-+ kfree(map);
-+ }
-+ /* See if I have any map structures */
-+ if (list_empty(&window->maps)) {
-+ ichxrom_cleanup(window);
-+ return -ENODEV;
-+ }
-+ return 0;
-+}
-+
-+
-+static void __devexit ichxrom_remove_one (struct pci_dev *pdev)
-+{
-+ struct ichxrom_window *window = &ichxrom_window;
-+ ichxrom_cleanup(window);
-+}
-+
-+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 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) {
-+ 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(ichxrom_window.pdev);
-+}
-+
-+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");
---- linux-2.4.21/drivers/mtd/maps/impa7.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/impa7.c
-@@ -1,5 +1,5 @@
- /*
-- * $Id: impa7.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $
-+ * $Id: impa7.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $
- *
- * Handle mapping of the NOR flash on implementa A7 boards
- *
-@@ -13,6 +13,7 @@
- #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>
-@@ -29,83 +30,25 @@
- #define NUM_FLASHBANKS 2
- #define BUSWIDTH 4
-
--/* can be { "cfi_probe", "jedec_probe", "map_rom", 0 }; */
--#define PROBETYPES { "jedec_probe", 0 }
-+/* can be { "cfi_probe", "jedec_probe", "map_rom", NULL } */
-+#define PROBETYPES { "jedec_probe", NULL }
-
- #define MSG_PREFIX "impA7:" /* prefix for our printk()'s */
- #define MTDID "impa7-%d" /* for mtdparts= partitioning */
-
--static struct mtd_info *impa7_mtd[NUM_FLASHBANKS] = { 0 };
--
--__u8 impa7_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 impa7_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 impa7_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void impa7_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void impa7_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void impa7_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void impa7_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
-+static struct mtd_info *impa7_mtd[NUM_FLASHBANKS];
-
--void impa7_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
-
- static struct map_info impa7_map[NUM_FLASHBANKS] = {
- {
-- name: "impA7 NOR Flash Bank #0",
-- size: WINDOW_SIZE0,
-- buswidth: BUSWIDTH,
-- read8: impa7_read8,
-- read16: impa7_read16,
-- read32: impa7_read32,
-- copy_from: impa7_copy_from,
-- write8: impa7_write8,
-- write16: impa7_write16,
-- write32: impa7_write32,
-- copy_to: impa7_copy_to
-+ .name = "impA7 NOR Flash Bank #0",
-+ .size = WINDOW_SIZE0,
-+ .bankwidth = BUSWIDTH,
- },
- {
-- name: "impA7 NOR Flash Bank #1",
-- size: WINDOW_SIZE1,
-- buswidth: BUSWIDTH,
-- read8: impa7_read8,
-- read16: impa7_read16,
-- read32: impa7_read32,
-- copy_from: impa7_copy_from,
-- write8: impa7_write8,
-- write16: impa7_write16,
-- write32: impa7_write32,
-- copy_to: impa7_copy_to
-+ .name = "impA7 NOR Flash Bank #1",
-+ .size = WINDOW_SIZE1,
-+ .bankwidth = BUSWIDTH,
- },
- };
-
-@@ -117,24 +60,18 @@
- static struct mtd_partition static_partitions[] =
- {
- {
-- name: "FileSystem",
-- size: 0x800000,
-- offset: 0x00000000
-+ .name = "FileSystem",
-+ .size = 0x800000,
-+ .offset = 0x00000000
- },
- };
-
--#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
--
--#ifdef CONFIG_MTD_CMDLINE_PARTS
--int parse_cmdline_partitions(struct mtd_info *master,
-- struct mtd_partition **pparts,
-- const char *mtd_id);
--#endif
-+static int mtd_parts_nb[NUM_FLASHBANKS];
-+static struct mtd_partition *mtd_parts[NUM_FLASHBANKS];
-
- #endif
-
--static int mtd_parts_nb = 0;
--static struct mtd_partition *mtd_parts = 0;
-+static const char *probes[] = { "cmdlinepart", NULL };
-
- int __init init_impa7(void)
- {
-@@ -146,20 +83,20 @@
- { WINDOW_ADDR0, WINDOW_SIZE0 },
- { WINDOW_ADDR1, WINDOW_SIZE1 },
- };
-- char mtdid[10];
- int devicesfound = 0;
-
- for(i=0; i<NUM_FLASHBANKS; i++)
- {
- printk(KERN_NOTICE MSG_PREFIX "probing 0x%08lx at 0x%08lx\n",
- pt[i].size, pt[i].addr);
-- impa7_map[i].map_priv_1 = (unsigned long)
-- ioremap(pt[i].addr, pt[i].size);
-
-- if (!impa7_map[i].map_priv_1) {
-+ impa7_map[i].phys = pt[i].addr;
-+ impa7_map[i].virt = ioremap(pt[i].addr, pt[i].size);
-+ if (!impa7_map[i].virt) {
- printk(MSG_PREFIX "failed to ioremap\n");
- return -EIO;
- }
-+ simple_map_init(&impa7_map[i]);
-
- impa7_mtd[i] = 0;
- type = rom_probe_types;
-@@ -167,43 +104,34 @@
- impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]);
- }
-
-- if (impa7_mtd[i])
-- {
-- impa7_mtd[i]->module = THIS_MODULE;
-- add_mtd_device(impa7_mtd[i]);
-+ if (impa7_mtd[i]) {
-+ impa7_mtd[i]->owner = THIS_MODULE;
- devicesfound++;
- #ifdef CONFIG_MTD_PARTITIONS
--#ifdef CONFIG_MTD_CMDLINE_PARTS
-- sprintf(mtdid, MTDID, i);
-- mtd_parts_nb = parse_cmdline_partitions(impa7_mtd[i],
-- &mtd_parts,
-- mtdid);
-- if (mtd_parts_nb > 0)
-+ mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i],
-+ probes,
-+ &mtd_parts[i],
-+ 0);
-+ if (mtd_parts_nb[i] > 0) {
- part_type = "command line";
--#endif
-- if (mtd_parts_nb <= 0)
-- {
-- mtd_parts = static_partitions;
-- mtd_parts_nb = NB_OF(static_partitions);
-+ } else {
-+ mtd_parts[i] = static_partitions;
-+ mtd_parts_nb[i] = ARRAY_SIZE(static_partitions);
- part_type = "static";
- }
-- if (mtd_parts_nb <= 0)
-- {
-- printk(KERN_NOTICE MSG_PREFIX
-- "no partition info available\n");
-- }
-- else
-- {
-+
- printk(KERN_NOTICE MSG_PREFIX
- "using %s partition definition\n",
- part_type);
- add_mtd_partitions(impa7_mtd[i],
-- mtd_parts, mtd_parts_nb);
-- }
-+ mtd_parts[i], mtd_parts_nb[i]);
-+#else
-+ add_mtd_device(impa7_mtd[i]);
-+
- #endif
- }
- else
-- iounmap((void *)impa7_map[i].map_priv_1);
-+ iounmap((void *)impa7_map[i].virt);
- }
- return devicesfound == 0 ? -ENXIO : 0;
- }
-@@ -211,17 +139,16 @@
- static void __exit cleanup_impa7(void)
- {
- int i;
-- for (i=0; i<NUM_FLASHBANKS; i++)
-- {
-- if (impa7_mtd[i])
-- {
-+ for (i=0; i<NUM_FLASHBANKS; i++) {
-+ if (impa7_mtd[i]) {
-+#ifdef CONFIG_MTD_PARTITIONS
-+ del_mtd_partitions(impa7_mtd[i]);
-+#else
- del_mtd_device(impa7_mtd[i]);
-+#endif
- map_destroy(impa7_mtd[i]);
-- }
-- if (impa7_map[i].map_priv_1)
-- {
-- iounmap((void *)impa7_map[i].map_priv_1);
-- impa7_map[i].map_priv_1 = 0;
-+ iounmap((void *)impa7_map[i].virt);
-+ impa7_map[i].virt = 0;
- }
- }
- }
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/integrator-flash-v24.c
-@@ -0,0 +1,258 @@
-+/*======================================================================
-+
-+ drivers/mtd/maps/armflash.c: ARM Flash Layout/Partitioning
-+
-+ Copyright (C) 2000 ARM Limited
-+
-+ This program is free software; 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
-+
-+ This is access code for flashes using ARM's flash partitioning
-+ standards.
-+
-+ $Id: integrator-flash-v24.c,v 1.14 2004/09/16 23:27:13 gleixner Exp $
-+
-+======================================================================*/
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/ioport.h>
-+#include <linux/init.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/io.h>
-+#include <asm/system.h>
-+
-+// board specific stuff - sorry, it should be in arch/arm/mach-*.
-+#ifdef CONFIG_ARCH_INTEGRATOR
-+
-+#define FLASH_BASE INTEGRATOR_FLASH_BASE
-+#define FLASH_SIZE INTEGRATOR_FLASH_SIZE
-+
-+#define FLASH_PART_SIZE 0x400000
-+
-+#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
-+#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
-+#define EBI_CSR1 (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_CSR1_OFFSET)
-+#define EBI_LOCK (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_LOCK_OFFSET)
-+
-+/*
-+ * Initialise the flash access systems:
-+ * - Disable VPP
-+ * - Assert WP
-+ * - Set write enable bit in EBI reg
-+ */
-+static void armflash_flash_init(void)
-+{
-+ unsigned int tmp;
-+
-+ __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
-+
-+ tmp = __raw_readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE;
-+ __raw_writel(tmp, EBI_CSR1);
-+
-+ if (!(__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) {
-+ __raw_writel(0xa05f, EBI_LOCK);
-+ __raw_writel(tmp, EBI_CSR1);
-+ __raw_writel(0, EBI_LOCK);
-+ }
-+}
-+
-+/*
-+ * Shutdown the flash access systems:
-+ * - Disable VPP
-+ * - Assert WP
-+ * - Clear write enable bit in EBI reg
-+ */
-+static void armflash_flash_exit(void)
-+{
-+ unsigned int tmp;
-+
-+ __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
-+
-+ /*
-+ * Clear the write enable bit in system controller EBI register.
-+ */
-+ tmp = __raw_readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE;
-+ __raw_writel(tmp, EBI_CSR1);
-+
-+ if (__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) {
-+ __raw_writel(0xa05f, EBI_LOCK);
-+ __raw_writel(tmp, EBI_CSR1);
-+ __raw_writel(0, EBI_LOCK);
-+ }
-+}
-+
-+static void armflash_flash_wp(int on)
-+{
-+ unsigned int reg;
-+
-+ if (on)
-+ reg = SC_CTRLC;
-+ else
-+ reg = SC_CTRLS;
-+
-+ __raw_writel(INTEGRATOR_SC_CTRL_nFLWP, reg);
-+}
-+
-+static void armflash_set_vpp(struct map_info *map, int on)
-+{
-+ unsigned int reg;
-+
-+ if (on)
-+ reg = SC_CTRLS;
-+ else
-+ reg = SC_CTRLC;
-+
-+ __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg);
-+}
-+#endif
-+
-+#ifdef CONFIG_ARCH_P720T
-+
-+#define FLASH_BASE (0x04000000)
-+#define FLASH_SIZE (64*1024*1024)
-+
-+#define FLASH_PART_SIZE (4*1024*1024)
-+#define FLASH_BLOCK_SIZE (128*1024)
-+
-+static void armflash_flash_init(void)
-+{
-+}
-+
-+static void armflash_flash_exit(void)
-+{
-+}
-+
-+static void armflash_flash_wp(int on)
-+{
-+}
-+
-+static void armflash_set_vpp(struct map_info *map, int on)
-+{
-+}
-+#endif
-+
-+
-+static struct map_info armflash_map =
-+{
-+ .name = "AFS",
-+ .set_vpp = armflash_set_vpp,
-+ .phys = FLASH_BASE,
-+};
-+
-+static struct mtd_info *mtd;
-+static struct mtd_partition *parts;
-+static const char *probes[] = { "RedBoot", "afs", NULL };
-+
-+static int __init armflash_cfi_init(void *base, u_int size)
-+{
-+ int ret;
-+
-+ armflash_flash_init();
-+ armflash_flash_wp(1);
-+
-+ /*
-+ * look for CFI based flash parts fitted to this board
-+ */
-+ armflash_map.size = size;
-+ armflash_map.bankwidth = 4;
-+ armflash_map.virt = (void __iomem *) base;
-+
-+ simple_map_init(&armflash_map);
-+
-+ /*
-+ * Also, the CFI layer automatically works out what size
-+ * of chips we have, and does the necessary identification
-+ * for us automatically.
-+ */
-+ mtd = do_map_probe("cfi_probe", &armflash_map);
-+ if (!mtd)
-+ return -ENXIO;
-+
-+ mtd->owner = THIS_MODULE;
-+
-+ ret = parse_mtd_partitions(mtd, probes, &parts, (void *)0);
-+ if (ret > 0) {
-+ ret = add_mtd_partitions(mtd, parts, ret);
-+ if (ret)
-+ printk(KERN_ERR "mtd partition registration "
-+ "failed: %d\n", ret);
-+ }
-+
-+ /*
-+ * If we got an error, free all resources.
-+ */
-+ if (ret < 0) {
-+ del_mtd_partitions(mtd);
-+ map_destroy(mtd);
-+ }
-+
-+ return ret;
-+}
-+
-+static void armflash_cfi_exit(void)
-+{
-+ if (mtd) {
-+ del_mtd_partitions(mtd);
-+ map_destroy(mtd);
-+ }
-+ if (parts)
-+ kfree(parts);
-+}
-+
-+static int __init armflash_init(void)
-+{
-+ int err = -EBUSY;
-+ void *base;
-+
-+ if (request_mem_region(FLASH_BASE, FLASH_SIZE, "flash") == NULL)
-+ goto out;
-+
-+ base = ioremap(FLASH_BASE, FLASH_SIZE);
-+ err = -ENOMEM;
-+ if (base == NULL)
-+ goto release;
-+
-+ err = armflash_cfi_init(base, FLASH_SIZE);
-+ if (err) {
-+ iounmap(base);
-+release:
-+ release_mem_region(FLASH_BASE, FLASH_SIZE);
-+ }
-+out:
-+ return err;
-+}
-+
-+static void __exit armflash_exit(void)
-+{
-+ armflash_cfi_exit();
-+ iounmap((void *)armflash_map.virt);
-+ release_mem_region(FLASH_BASE, FLASH_SIZE);
-+ armflash_flash_exit();
-+}
-+
-+module_init(armflash_init);
-+module_exit(armflash_exit);
-+
-+MODULE_AUTHOR("ARM Ltd");
-+MODULE_DESCRIPTION("ARM Integrator CFI map driver");
-+MODULE_LICENSE("GPL");
---- linux-2.4.21/drivers/mtd/maps/integrator-flash.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/integrator-flash.c
-@@ -1,8 +1,9 @@
- /*======================================================================
-
-- drivers/mtd/maps/armflash.c: ARM Flash Layout/Partitioning
-+ drivers/mtd/maps/integrator-flash.c: ARM Integrator flash map driver
-
- Copyright (C) 2000 ARM Limited
-+ Copyright (C) 2003 Deep Blue Solutions Ltd.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
-@@ -21,7 +22,7 @@
- This is access code for flashes using ARM's flash partitioning
- standards.
-
-- $Id: integrator-flash.c,v 1.7 2001/11/01 20:55:47 rmk Exp $
-+ $Id: integrator-flash.c,v 1.18 2004/11/01 13:26:15 rmk Exp $
-
- ======================================================================*/
-
-@@ -31,268 +32,181 @@
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/ioport.h>
-+#include <linux/device.h>
- #include <linux/init.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/partitions.h>
-
-+#include <asm/mach/flash.h>
- #include <asm/hardware.h>
- #include <asm/io.h>
- #include <asm/system.h>
-
--extern int parse_afs_partitions(struct mtd_info *, struct mtd_partition **);
--
--// board specific stuff - sorry, it should be in arch/arm/mach-*.
--#ifdef CONFIG_ARCH_INTEGRATOR
--
--#define FLASH_BASE INTEGRATOR_FLASH_BASE
--#define FLASH_SIZE INTEGRATOR_FLASH_SIZE
--
--#define FLASH_PART_SIZE 0x400000
--
--#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
--#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
--#define EBI_CSR1 (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_CSR1_OFFSET)
--#define EBI_LOCK (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_LOCK_OFFSET)
--
--/*
-- * Initialise the flash access systems:
-- * - Disable VPP
-- * - Assert WP
-- * - Set write enable bit in EBI reg
-- */
--static void armflash_flash_init(void)
--{
-- unsigned int tmp;
--
-- __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
--
-- tmp = __raw_readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE;
-- __raw_writel(tmp, EBI_CSR1);
--
-- if (!(__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) {
-- __raw_writel(0xa05f, EBI_LOCK);
-- __raw_writel(tmp, EBI_CSR1);
-- __raw_writel(0, EBI_LOCK);
-- }
--}
--
--/*
-- * Shutdown the flash access systems:
-- * - Disable VPP
-- * - Assert WP
-- * - Clear write enable bit in EBI reg
-- */
--static void armflash_flash_exit(void)
--{
-- unsigned int tmp;
--
-- __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
--
-- /*
-- * Clear the write enable bit in system controller EBI register.
-- */
-- tmp = __raw_readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE;
-- __raw_writel(tmp, EBI_CSR1);
--
-- if (__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) {
-- __raw_writel(0xa05f, EBI_LOCK);
-- __raw_writel(tmp, EBI_CSR1);
-- __raw_writel(0, EBI_LOCK);
-- }
--}
--
--static void armflash_flash_wp(int on)
--{
-- unsigned int reg;
--
-- if (on)
-- reg = SC_CTRLC;
-- else
-- reg = SC_CTRLS;
--
-- __raw_writel(INTEGRATOR_SC_CTRL_nFLWP, reg);
--}
--
--static void armflash_set_vpp(struct map_info *map, int on)
--{
-- unsigned int reg;
--
-- if (on)
-- reg = SC_CTRLS;
-- else
-- reg = SC_CTRLC;
--
-- __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg);
--}
--#endif
--
- #ifdef CONFIG_ARCH_P720T
--
- #define FLASH_BASE (0x04000000)
- #define FLASH_SIZE (64*1024*1024)
--
--#define FLASH_PART_SIZE (4*1024*1024)
--#define FLASH_BLOCK_SIZE (128*1024)
--
--static void armflash_flash_init(void)
--{
--}
--
--static void armflash_flash_exit(void)
--{
--}
--
--static void armflash_flash_wp(int on)
--{
--}
--
--static void armflash_set_vpp(struct map_info *map, int on)
--{
--}
- #endif
-
--static __u8 armflash_read8(struct map_info *map, unsigned long ofs)
--{
-- return readb(ofs + map->map_priv_2);
--}
--
--static __u16 armflash_read16(struct map_info *map, unsigned long ofs)
--{
-- return readw(ofs + map->map_priv_2);
--}
--
--static __u32 armflash_read32(struct map_info *map, unsigned long ofs)
--{
-- return readl(ofs + map->map_priv_2);
--}
-+struct armflash_info {
-+ struct flash_platform_data *plat;
-+ struct resource *res;
-+ struct mtd_partition *parts;
-+ struct mtd_info *mtd;
-+ struct map_info map;
-+};
-
--static void armflash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-+static void armflash_set_vpp(struct map_info *map, int on)
- {
-- memcpy(to, (void *) (from + map->map_priv_2), len);
--}
-+ struct armflash_info *info = container_of(map, struct armflash_info, map);
-
--static void armflash_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- writeb(d, adr + map->map_priv_2);
-+ if (info->plat && info->plat->set_vpp)
-+ info->plat->set_vpp(on);
- }
-
--static void armflash_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- writew(d, adr + map->map_priv_2);
--}
-+static const char *probes[] = { "cmdlinepart", "RedBoot", "afs", NULL };
-
--static void armflash_write32(struct map_info *map, __u32 d, unsigned long adr)
-+static int armflash_probe(struct device *_dev)
- {
-- writel(d, adr + map->map_priv_2);
--}
-+ struct platform_device *dev = to_platform_device(_dev);
-+ struct flash_platform_data *plat = dev->dev.platform_data;
-+ struct resource *res = dev->resource;
-+ unsigned int size = res->end - res->start + 1;
-+ struct armflash_info *info;
-+ int err;
-+ void __iomem *base;
-
--static void armflash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy((void *) (to + map->map_priv_2), from, len);
--}
-+ info = kmalloc(sizeof(struct armflash_info), GFP_KERNEL);
-+ if (!info) {
-+ err = -ENOMEM;
-+ goto out;
-+ }
-
--static struct map_info armflash_map =
--{
-- name: "AFS",
-- read8: armflash_read8,
-- read16: armflash_read16,
-- read32: armflash_read32,
-- copy_from: armflash_copy_from,
-- write8: armflash_write8,
-- write16: armflash_write16,
-- write32: armflash_write32,
-- copy_to: armflash_copy_to,
-- set_vpp: armflash_set_vpp,
--};
-+ memset(info, 0, sizeof(struct armflash_info));
-
--static struct mtd_info *mtd;
--static struct mtd_partition *parts;
-+ info->plat = plat;
-+ if (plat && plat->init) {
-+ err = plat->init();
-+ if (err)
-+ goto no_resource;
-+ }
-
--static int __init armflash_cfi_init(void *base, u_int size)
--{
-- int ret;
-+ info->res = request_mem_region(res->start, size, "armflash");
-+ if (!info->res) {
-+ err = -EBUSY;
-+ goto no_resource;
-+ }
-
-- armflash_flash_init();
-- armflash_flash_wp(1);
-+ base = ioremap(res->start, size);
-+ if (!base) {
-+ err = -ENOMEM;
-+ goto no_mem;
-+ }
-
- /*
- * look for CFI based flash parts fitted to this board
- */
-- armflash_map.size = size;
-- armflash_map.buswidth = 4;
-- armflash_map.map_priv_2 = (unsigned long) base;
-+ info->map.size = size;
-+ info->map.bankwidth = plat->width;
-+ info->map.phys = res->start;
-+ info->map.virt = base;
-+ info->map.name = dev->dev.bus_id;
-+ info->map.set_vpp = armflash_set_vpp;
-+
-+ simple_map_init(&info->map);
-
- /*
- * Also, the CFI layer automatically works out what size
- * of chips we have, and does the necessary identification
- * for us automatically.
- */
-- mtd = do_map_probe("cfi_probe", &armflash_map);
-- if (!mtd)
-- return -ENXIO;
-+ info->mtd = do_map_probe(plat->map_name, &info->map);
-+ if (!info->mtd) {
-+ err = -ENXIO;
-+ goto no_device;
-+ }
-
-- mtd->module = THIS_MODULE;
-+ info->mtd->owner = THIS_MODULE;
-
-- ret = parse_afs_partitions(mtd, &parts);
-- if (ret > 0) {
-- ret = add_mtd_partitions(mtd, parts, ret);
-- if (ret)
-- printk(KERN_ERR "mtd partition registration "
-- "failed: %d\n", ret);
-+ err = parse_mtd_partitions(info->mtd, probes, &info->parts, 0);
-+ if (err > 0) {
-+ err = add_mtd_partitions(info->mtd, info->parts, err);
-+ if (err)
-+ printk(KERN_ERR
-+ "mtd partition registration failed: %d\n", err);
- }
-
-+ if (err == 0)
-+ dev_set_drvdata(&dev->dev, info);
-+
- /*
- * If we got an error, free all resources.
- */
-- if (ret < 0) {
-- del_mtd_partitions(mtd);
-- map_destroy(mtd);
-+ if (err < 0) {
-+ if (info->mtd) {
-+ del_mtd_partitions(info->mtd);
-+ map_destroy(info->mtd);
- }
-+ if (info->parts)
-+ kfree(info->parts);
-
-- return ret;
--}
--
--static void armflash_cfi_exit(void)
--{
-- if (mtd) {
-- del_mtd_partitions(mtd);
-- map_destroy(mtd);
-+ no_device:
-+ iounmap(base);
-+ no_mem:
-+ release_mem_region(res->start, size);
-+ no_resource:
-+ if (plat && plat->exit)
-+ plat->exit();
-+ kfree(info);
- }
-- if (parts)
-- kfree(parts);
-+ out:
-+ return err;
- }
-
--static int __init armflash_init(void)
-+static int armflash_remove(struct device *_dev)
- {
-- int err = -EBUSY;
-- void *base;
-+ struct platform_device *dev = to_platform_device(_dev);
-+ struct armflash_info *info = dev_get_drvdata(&dev->dev);
-
-- if (request_mem_region(FLASH_BASE, FLASH_SIZE, "flash") == NULL)
-- goto out;
-+ dev_set_drvdata(&dev->dev, NULL);
-
-- base = ioremap(FLASH_BASE, FLASH_SIZE);
-- err = -ENOMEM;
-- if (base == NULL)
-- goto release;
-+ if (info) {
-+ if (info->mtd) {
-+ del_mtd_partitions(info->mtd);
-+ map_destroy(info->mtd);
-+ }
-+ if (info->parts)
-+ kfree(info->parts);
-
-- err = armflash_cfi_init(base, FLASH_SIZE);
-- if (err) {
-- iounmap(base);
--release:
-- release_mem_region(FLASH_BASE, FLASH_SIZE);
-+ iounmap(info->map.virt);
-+ release_resource(info->res);
-+ kfree(info->res);
-+
-+ if (info->plat && info->plat->exit)
-+ info->plat->exit();
-+
-+ kfree(info);
- }
--out:
-- return err;
-+
-+ return 0;
-+}
-+
-+static struct device_driver armflash_driver = {
-+ .name = "armflash",
-+ .bus = &platform_bus_type,
-+ .probe = armflash_probe,
-+ .remove = armflash_remove,
-+};
-+
-+static int __init armflash_init(void)
-+{
-+ return driver_register(&armflash_driver);
- }
-
- static void __exit armflash_exit(void)
- {
-- armflash_cfi_exit();
-- iounmap((void *)armflash_map.map_priv_2);
-- release_mem_region(FLASH_BASE, FLASH_SIZE);
-- armflash_flash_exit();
-+ driver_unregister(&armflash_driver);
- }
-
- module_init(armflash_init);
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/ipaq-flash.c
-@@ -0,0 +1,464 @@
-+/*
-+ * Flash memory access on iPAQ Handhelds (either SA1100 or PXA250 based)
-+ *
-+ * (C) 2000 Nicolas Pitre <nico@cam.org>
-+ * (C) 2002 Hewlett-Packard Company <jamey.hicks@hp.com>
-+ * (C) 2003 Christian Pellegrin <chri@ascensit.com>, <chri@infis.univ.ts.it>: concatenation of multiple flashes
-+ *
-+ * $Id: ipaq-flash.c,v 1.4 2005/01/12 22:34:35 gleixner Exp $
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/spinlock.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <asm/page.h>
-+#include <asm/mach-types.h>
-+#include <asm/system.h>
-+#include <asm/errno.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#ifdef CONFIG_MTD_CONCAT
-+#include <linux/mtd/concat.h>
-+#endif
-+
-+#include <asm/hardware.h>
-+#include <asm/arch-sa1100/h3600.h>
-+#include <asm/io.h>
-+
-+
-+#ifndef CONFIG_IPAQ_HANDHELD
-+#error This is for iPAQ Handhelds only
-+#endif
-+#ifdef CONFIG_SA1100_JORNADA56X
-+
-+static void jornada56x_set_vpp(struct map_info *map, int vpp)
-+{
-+ if (vpp)
-+ GPSR = GPIO_GPIO26;
-+ else
-+ GPCR = GPIO_GPIO26;
-+ GPDR |= GPIO_GPIO26;
-+}
-+
-+#endif
-+
-+#ifdef CONFIG_SA1100_JORNADA720
-+
-+static void jornada720_set_vpp(struct map_info *map, int vpp)
-+{
-+ if (vpp)
-+ PPSR |= 0x80;
-+ else
-+ PPSR &= ~0x80;
-+ PPDR |= 0x80;
-+}
-+
-+#endif
-+
-+#define MAX_IPAQ_CS 2 /* Number of CS we are going to test */
-+
-+#define IPAQ_MAP_INIT(X) \
-+ { \
-+ name: "IPAQ flash " X, \
-+ }
-+
-+
-+static struct map_info ipaq_map[MAX_IPAQ_CS] = {
-+ IPAQ_MAP_INIT("bank 1"),
-+ IPAQ_MAP_INIT("bank 2")
-+};
-+
-+static struct mtd_info *my_sub_mtd[MAX_IPAQ_CS] = {
-+ NULL,
-+ NULL
-+};
-+
-+/*
-+ * Here are partition information for all known IPAQ-based devices.
-+ * See include/linux/mtd/partitions.h for definition of the mtd_partition
-+ * structure.
-+ *
-+ * The *_max_flash_size is the maximum possible mapped flash size which
-+ * is not necessarily the actual flash size. It must be no more than
-+ * the value specified in the "struct map_desc *_io_desc" mapping
-+ * definition for the corresponding machine.
-+ *
-+ * Please keep these in alphabetical order, and formatted as per existing
-+ * entries. Thanks.
-+ */
-+
-+#ifdef CONFIG_IPAQ_HANDHELD
-+static unsigned long h3xxx_max_flash_size = 0x04000000;
-+static struct mtd_partition h3xxx_partitions[] = {
-+ {
-+ name: "H3XXX boot firmware",
-+#ifndef CONFIG_LAB
-+ size: 0x00040000,
-+#else
-+ size: 0x00080000,
-+#endif
-+ offset: 0,
-+#ifndef CONFIG_LAB
-+ mask_flags: MTD_WRITEABLE, /* force read-only */
-+#endif
-+ },
-+ {
-+ name: "H3XXX root jffs2",
-+#ifndef CONFIG_LAB
-+ size: 0x2000000 - 2*0x40000, /* Warning, this is fixed later */
-+ offset: 0x00040000,
-+#else
-+ size: 0x2000000 - 0x40000 - 0x80000, /* Warning, this is fixed later */
-+ offset: 0x00080000,
-+#endif
-+ },
-+ {
-+ name: "asset",
-+ size: 0x40000,
-+ offset: 0x2000000 - 0x40000, /* Warning, this is fixed later */
-+ mask_flags: MTD_WRITEABLE, /* force read-only */
-+ }
-+};
-+
-+#ifndef CONFIG_MTD_CONCAT
-+static struct mtd_partition h3xxx_partitions_bank2[] = {
-+ /* this is used only on 2 CS machines when concat is not present */
-+ {
-+ name: "second H3XXX root jffs2",
-+ size: 0x1000000 - 0x40000, /* Warning, this is fixed later */
-+ offset: 0x00000000,
-+ },
-+ {
-+ name: "second asset",
-+ size: 0x40000,
-+ offset: 0x1000000 - 0x40000, /* Warning, this is fixed later */
-+ mask_flags: MTD_WRITEABLE, /* force read-only */
-+ }
-+};
-+#endif
-+
-+static DEFINE_SPINLOCK(ipaq_vpp_lock);
-+
-+static void h3xxx_set_vpp(struct map_info *map, int vpp)
-+{
-+ static int nest = 0;
-+
-+ spin_lock(&ipaq_vpp_lock);
-+ if (vpp)
-+ nest++;
-+ else
-+ nest--;
-+ if (nest)
-+ assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, 1);
-+ else
-+ assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, 0);
-+ spin_unlock(&ipaq_vpp_lock);
-+}
-+
-+#endif
-+
-+#if defined(CONFIG_SA1100_JORNADA56X) || defined(CONFIG_SA1100_JORNADA720)
-+static unsigned long jornada_max_flash_size = 0x02000000;
-+static struct mtd_partition jornada_partitions[] = {
-+ {
-+ name: "Jornada boot firmware",
-+ size: 0x00040000,
-+ offset: 0,
-+ mask_flags: MTD_WRITEABLE, /* force read-only */
-+ }, {
-+ name: "Jornada root jffs2",
-+ size: MTDPART_SIZ_FULL,
-+ offset: 0x00040000,
-+ }
-+};
-+#endif
-+
-+
-+static struct mtd_partition *parsed_parts;
-+static struct mtd_info *mymtd;
-+
-+static unsigned long cs_phys[] = {
-+#ifdef CONFIG_ARCH_SA1100
-+ SA1100_CS0_PHYS,
-+ SA1100_CS1_PHYS,
-+ SA1100_CS2_PHYS,
-+ SA1100_CS3_PHYS,
-+ SA1100_CS4_PHYS,
-+ SA1100_CS5_PHYS,
-+#else
-+ PXA_CS0_PHYS,
-+ PXA_CS1_PHYS,
-+ PXA_CS2_PHYS,
-+ PXA_CS3_PHYS,
-+ PXA_CS4_PHYS,
-+ PXA_CS5_PHYS,
-+#endif
-+};
-+
-+static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
-+
-+static int __init h1900_special_case(void);
-+
-+int __init ipaq_mtd_init(void)
-+{
-+ struct mtd_partition *parts = NULL;
-+ int nb_parts = 0;
-+ int parsed_nr_parts = 0;
-+ const char *part_type;
-+ int i; /* used when we have >1 flash chips */
-+ unsigned long tot_flashsize = 0; /* used when we have >1 flash chips */
-+
-+ /* Default flash bankwidth */
-+ // ipaq_map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
-+
-+ if (machine_is_h1900())
-+ {
-+ /* For our intents, the h1900 is not a real iPAQ, so we special-case it. */
-+ return h1900_special_case();
-+ }
-+
-+ if (machine_is_h3100() || machine_is_h1900())
-+ for(i=0; i<MAX_IPAQ_CS; i++)
-+ ipaq_map[i].bankwidth = 2;
-+ else
-+ for(i=0; i<MAX_IPAQ_CS; i++)
-+ ipaq_map[i].bankwidth = 4;
-+
-+ /*
-+ * Static partition definition selection
-+ */
-+ part_type = "static";
-+
-+ simple_map_init(&ipaq_map[0]);
-+ simple_map_init(&ipaq_map[1]);
-+
-+#ifdef CONFIG_IPAQ_HANDHELD
-+ if (machine_is_ipaq()) {
-+ parts = h3xxx_partitions;
-+ nb_parts = ARRAY_SIZE(h3xxx_partitions);
-+ for(i=0; i<MAX_IPAQ_CS; i++) {
-+ ipaq_map[i].size = h3xxx_max_flash_size;
-+ ipaq_map[i].set_vpp = h3xxx_set_vpp;
-+ ipaq_map[i].phys = cs_phys[i];
-+ ipaq_map[i].virt = __ioremap(cs_phys[i], 0x04000000, 0, 1);
-+ if (machine_is_h3100 () || machine_is_h1900())
-+ ipaq_map[i].bankwidth = 2;
-+ }
-+ if (machine_is_h3600()) {
-+ /* No asset partition here */
-+ h3xxx_partitions[1].size += 0x40000;
-+ nb_parts--;
-+ }
-+ }
-+#endif
-+#ifdef CONFIG_ARCH_H5400
-+ if (machine_is_h5400()) {
-+ ipaq_map[0].size = 0x02000000;
-+ ipaq_map[1].size = 0x02000000;
-+ ipaq_map[1].phys = 0x02000000;
-+ ipaq_map[1].virt = ipaq_map[0].virt + 0x02000000;
-+ }
-+#endif
-+#ifdef CONFIG_ARCH_H1900
-+ if (machine_is_h1900()) {
-+ ipaq_map[0].size = 0x00400000;
-+ ipaq_map[1].size = 0x02000000;
-+ ipaq_map[1].phys = 0x00080000;
-+ ipaq_map[1].virt = ipaq_map[0].virt + 0x00080000;
-+ }
-+#endif
-+
-+#ifdef CONFIG_SA1100_JORNADA56X
-+ if (machine_is_jornada56x()) {
-+ parts = jornada_partitions;
-+ nb_parts = ARRAY_SIZE(jornada_partitions);
-+ ipaq_map[0].size = jornada_max_flash_size;
-+ ipaq_map[0].set_vpp = jornada56x_set_vpp;
-+ ipaq_map[0].virt = (__u32)__ioremap(0x0, 0x04000000, 0, 1);
-+ }
-+#endif
-+#ifdef CONFIG_SA1100_JORNADA720
-+ if (machine_is_jornada720()) {
-+ parts = jornada_partitions;
-+ nb_parts = ARRAY_SIZE(jornada_partitions);
-+ ipaq_map[0].size = jornada_max_flash_size;
-+ ipaq_map[0].set_vpp = jornada720_set_vpp;
-+ }
-+#endif
-+
-+
-+ if (machine_is_ipaq()) { /* for iPAQs only */
-+ for(i=0; i<MAX_IPAQ_CS; i++) {
-+ printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with CFI.\n", ipaq_map[i].bankwidth*8, ipaq_map[i].virt);
-+ my_sub_mtd[i] = do_map_probe("cfi_probe", &ipaq_map[i]);
-+ if (!my_sub_mtd[i]) {
-+ printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[i].bankwidth*8, ipaq_map[i].virt);
-+ my_sub_mtd[i] = do_map_probe("jedec_probe", &ipaq_map[i]);
-+ }
-+ if (!my_sub_mtd[i]) {
-+ printk(KERN_NOTICE "iPAQ flash: failed to find flash.\n");
-+ if (i)
-+ break;
-+ else
-+ return -ENXIO;
-+ } else
-+ printk(KERN_NOTICE "iPAQ flash: found %d bytes\n", my_sub_mtd[i]->size);
-+
-+ /* do we really need this debugging? --joshua 20030703 */
-+ // printk("my_sub_mtd[%d]=%p\n", i, my_sub_mtd[i]);
-+ my_sub_mtd[i]->owner = THIS_MODULE;
-+ tot_flashsize += my_sub_mtd[i]->size;
-+ }
-+#ifdef CONFIG_MTD_CONCAT
-+ /* fix the asset location */
-+# ifdef CONFIG_LAB
-+ h3xxx_partitions[1].size = tot_flashsize - 0x40000 - 0x80000 /* extra big boot block */;
-+# else
-+ h3xxx_partitions[1].size = tot_flashsize - 2 * 0x40000;
-+# endif
-+ h3xxx_partitions[2].offset = tot_flashsize - 0x40000;
-+ /* and concat the devices */
-+ mymtd = mtd_concat_create(&my_sub_mtd[0], i,
-+ "ipaq");
-+ if (!mymtd) {
-+ printk("Cannot create iPAQ concat device\n");
-+ return -ENXIO;
-+ }
-+#else
-+ mymtd = my_sub_mtd[0];
-+
-+ /*
-+ *In the very near future, command line partition parsing
-+ * will use the device name as 'mtd-id' instead of a value
-+ * passed to the parse_cmdline_partitions() routine. Since
-+ * the bootldr says 'ipaq', make sure it continues to work.
-+ */
-+ mymtd->name = "ipaq";
-+
-+ if ((machine_is_h3600())) {
-+# ifdef CONFIG_LAB
-+ h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x80000;
-+# else
-+ h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x40000;
-+# endif
-+ nb_parts = 2;
-+ } else {
-+# ifdef CONFIG_LAB
-+ h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x40000 - 0x80000; /* extra big boot block */
-+# else
-+ h3xxx_partitions[1].size = my_sub_mtd[0]->size - 2*0x40000;
-+# endif
-+ h3xxx_partitions[2].offset = my_sub_mtd[0]->size - 0x40000;
-+ }
-+
-+ if (my_sub_mtd[1]) {
-+# ifdef CONFIG_LAB
-+ h3xxx_partitions_bank2[0].size = my_sub_mtd[1]->size - 0x80000;
-+# else
-+ h3xxx_partitions_bank2[0].size = my_sub_mtd[1]->size - 0x40000;
-+# endif
-+ h3xxx_partitions_bank2[1].offset = my_sub_mtd[1]->size - 0x40000;
-+ }
-+#endif
-+ }
-+ else {
-+ /*
-+ * Now let's probe for the actual flash. Do it here since
-+ * specific machine settings might have been set above.
-+ */
-+ printk(KERN_NOTICE "IPAQ flash: probing %d-bit flash bus, window=%lx\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt);
-+ mymtd = do_map_probe("cfi_probe", &ipaq_map[0]);
-+ if (!mymtd)
-+ return -ENXIO;
-+ mymtd->owner = THIS_MODULE;
-+ }
-+
-+
-+ /*
-+ * Dynamic partition selection stuff (might override the static ones)
-+ */
-+
-+ i = parse_mtd_partitions(mymtd, part_probes, &parsed_parts, 0);
-+
-+ if (i > 0) {
-+ nb_parts = parsed_nr_parts = i;
-+ parts = parsed_parts;
-+ part_type = "dynamic";
-+ }
-+
-+ if (!parts) {
-+ printk(KERN_NOTICE "IPAQ flash: no partition info available, registering whole flash at once\n");
-+ add_mtd_device(mymtd);
-+#ifndef CONFIG_MTD_CONCAT
-+ if (my_sub_mtd[1])
-+ add_mtd_device(my_sub_mtd[1]);
-+#endif
-+ } else {
-+ printk(KERN_NOTICE "Using %s partition definition\n", part_type);
-+ add_mtd_partitions(mymtd, parts, nb_parts);
-+#ifndef CONFIG_MTD_CONCAT
-+ if (my_sub_mtd[1])
-+ add_mtd_partitions(my_sub_mtd[1], h3xxx_partitions_bank2, ARRAY_SIZE(h3xxx_partitions_bank2));
-+#endif
-+ }
-+
-+ return 0;
-+}
-+
-+static void __exit ipaq_mtd_cleanup(void)
-+{
-+ int i;
-+
-+ if (mymtd) {
-+ del_mtd_partitions(mymtd);
-+#ifndef CONFIG_MTD_CONCAT
-+ if (my_sub_mtd[1])
-+ del_mtd_partitions(my_sub_mtd[1]);
-+#endif
-+ map_destroy(mymtd);
-+#ifdef CONFIG_MTD_CONCAT
-+ for(i=0; i<MAX_IPAQ_CS; i++)
-+#else
-+ for(i=1; i<MAX_IPAQ_CS; i++)
-+#endif
-+ {
-+ if (my_sub_mtd[i])
-+ map_destroy(my_sub_mtd[i]);
-+ }
-+ if (parsed_parts)
-+ kfree(parsed_parts);
-+ }
-+}
-+
-+static int __init h1900_special_case(void)
-+{
-+ /* The iPAQ h1900 is a special case - it has weird ROM. */
-+ simple_map_init(&ipaq_map[0]);
-+ ipaq_map[0].size = 0x80000;
-+ ipaq_map[0].set_vpp = h3xxx_set_vpp;
-+ ipaq_map[0].phys = 0x0;
-+ ipaq_map[0].virt = __ioremap(0x0, 0x04000000, 0, 1);
-+ ipaq_map[0].bankwidth = 2;
-+
-+ printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt);
-+ mymtd = do_map_probe("jedec_probe", &ipaq_map[0]);
-+ if (!mymtd)
-+ return -ENODEV;
-+ add_mtd_device(mymtd);
-+ printk(KERN_NOTICE "iPAQ flash: registered h1910 flash\n");
-+
-+ return 0;
-+}
-+
-+module_init(ipaq_mtd_init);
-+module_exit(ipaq_mtd_cleanup);
-+
-+MODULE_AUTHOR("Jamey Hicks");
-+MODULE_DESCRIPTION("IPAQ CFI map driver");
-+MODULE_LICENSE("MIT");
---- linux-2.4.21/drivers/mtd/maps/iq80310.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/iq80310.c
-@@ -1,5 +1,5 @@
- /*
-- * $Id: iq80310.c,v 1.9 2002/01/01 22:45:02 rmk Exp $
-+ * $Id: iq80310.c,v 1.20 2004/11/04 13:24:15 gleixner Exp $
- *
- * Mapping for the Intel XScale IQ80310 evaluation board
- *
-@@ -14,6 +14,8 @@
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -26,127 +28,72 @@
-
- static struct mtd_info *mymtd;
-
--static __u8 iq80310_read8(struct map_info *map, unsigned long ofs)
--{
-- return *(__u8 *)(map->map_priv_1 + ofs);
--}
--
--static __u16 iq80310_read16(struct map_info *map, unsigned long ofs)
--{
-- return *(__u16 *)(map->map_priv_1 + ofs);
--}
--
--static __u32 iq80310_read32(struct map_info *map, unsigned long ofs)
--{
-- return *(__u32 *)(map->map_priv_1 + ofs);
--}
--
--static void iq80310_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy(to, (void *)(map->map_priv_1 + from), len);
--}
--
--static void iq80310_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- *(__u8 *)(map->map_priv_1 + adr) = d;
--}
--
--static void iq80310_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- *(__u16 *)(map->map_priv_1 + adr) = d;
--}
--
--static void iq80310_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- *(__u32 *)(map->map_priv_1 + adr) = d;
--}
--
--static void iq80310_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy((void *)(map->map_priv_1 + to), from, len);
--}
--
- static struct map_info iq80310_map = {
-- name: "IQ80310 flash",
-- size: WINDOW_SIZE,
-- buswidth: BUSWIDTH,
-- read8: iq80310_read8,
-- read16: iq80310_read16,
-- read32: iq80310_read32,
-- copy_from: iq80310_copy_from,
-- write8: iq80310_write8,
-- write16: iq80310_write16,
-- write32: iq80310_write32,
-- copy_to: iq80310_copy_to
-+ .name = "IQ80310 flash",
-+ .size = WINDOW_SIZE,
-+ .bankwidth = BUSWIDTH,
-+ .phys = WINDOW_ADDR
- };
-
- static struct mtd_partition iq80310_partitions[4] = {
- {
-- name: "Firmware",
-- size: 0x00080000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE /* force read-only */
-+ .name = "Firmware",
-+ .size = 0x00080000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
- },{
-- name: "Kernel",
-- size: 0x000a0000,
-- offset: 0x00080000,
-+ .name = "Kernel",
-+ .size = 0x000a0000,
-+ .offset = 0x00080000,
- },{
-- name: "Filesystem",
-- size: 0x00600000,
-- offset: 0x00120000
-+ .name = "Filesystem",
-+ .size = 0x00600000,
-+ .offset = 0x00120000
- },{
-- name: "RedBoot",
-- size: 0x000e0000,
-- offset: 0x00720000,
-- mask_flags: MTD_WRITEABLE
-+ .name = "RedBoot",
-+ .size = 0x000e0000,
-+ .offset = 0x00720000,
-+ .mask_flags = MTD_WRITEABLE
- }
- };
-
--#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
--
- static struct mtd_info *mymtd;
- static struct mtd_partition *parsed_parts;
--
--extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
-+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-
- static int __init init_iq80310(void)
- {
- struct mtd_partition *parts;
- int nb_parts = 0;
- int parsed_nr_parts = 0;
-- char *part_type = "static";
-+ int ret;
-
-- iq80310_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-- if (!iq80310_map.map_priv_1) {
-+ iq80310_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+ if (!iq80310_map.virt) {
- printk("Failed to ioremap\n");
- return -EIO;
- }
-+ simple_map_init(&iq80310_map);
-+
- mymtd = do_map_probe("cfi_probe", &iq80310_map);
- if (!mymtd) {
-- iounmap((void *)iq80310_map.map_priv_1);
-+ iounmap((void *)iq80310_map.virt);
- return -ENXIO;
- }
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
--#ifdef CONFIG_MTD_REDBOOT_PARTS
-- if (parsed_nr_parts == 0) {
-- int ret = parse_redboot_partitions(mymtd, &parsed_parts);
-+ ret = parse_mtd_partitions(mymtd, probes, &parsed_parts, 0);
-
-- if (ret > 0) {
-- part_type = "RedBoot";
-+ if (ret > 0)
- parsed_nr_parts = ret;
-- }
-- }
--#endif
-
- if (parsed_nr_parts > 0) {
- parts = parsed_parts;
- nb_parts = parsed_nr_parts;
- } else {
- parts = iq80310_partitions;
-- nb_parts = NB_OF(iq80310_partitions);
-+ nb_parts = ARRAY_SIZE(iq80310_partitions);
- }
-- printk(KERN_NOTICE "Using %s partition definition\n", part_type);
- add_mtd_partitions(mymtd, parts, nb_parts);
- return 0;
- }
-@@ -159,8 +106,8 @@
- if (parsed_parts)
- kfree(parsed_parts);
- }
-- if (iq80310_map.map_priv_1)
-- iounmap((void *)iq80310_map.map_priv_1);
-+ if (iq80310_map.virt)
-+ iounmap((void *)iq80310_map.virt);
- }
-
- module_init(init_iq80310);
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/ixp2000.c
-@@ -0,0 +1,280 @@
-+/*
-+ * $Id: ixp2000.c,v 1.5 2004/11/16 17:15:48 dsaxena Exp $
-+ *
-+ * drivers/mtd/maps/ixp2000.c
-+ *
-+ * Mapping for the Intel XScale IXP2000 based systems
-+ *
-+ * Copyright (C) 2002 Intel Corp.
-+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
-+ *
-+ * Original Author: Naeem M Afzal <naeem.m.afzal@intel.com>
-+ * Maintainer: Deepak Saxena <dsaxena@plexity.net>
-+ *
-+ * 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/module.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/ioport.h>
-+#include <linux/device.h>
-+
-+#include <asm/io.h>
-+#include <asm/hardware.h>
-+#include <asm/mach-types.h>
-+#include <asm/mach/flash.h>
-+
-+#include <linux/reboot.h>
-+
-+struct ixp2000_flash_info {
-+ struct mtd_info *mtd;
-+ struct map_info map;
-+ struct mtd_partition *partitions;
-+ struct resource *res;
-+ int nr_banks;
-+};
-+
-+static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs)
-+{
-+ unsigned long (*set_bank)(unsigned long) =
-+ (unsigned long(*)(unsigned long))map->map_priv_2;
-+
-+ return (set_bank ? set_bank(ofs) : ofs);
-+}
-+
-+#ifdef __ARMEB__
-+/*
-+ * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which
-+ * causes the lower address bits to be XORed with 0x11 on 8 bit accesses
-+ * and XORed with 0x10 on 16 bit accesses. See the spec update, erratum 44.
-+ */
-+static int erratum44_workaround = 0;
-+
-+static inline unsigned long address_fix8_write(unsigned long addr)
-+{
-+ if (erratum44_workaround) {
-+ return (addr ^ 3);
-+ }
-+ return addr;
-+}
-+#else
-+
-+#define address_fix8_write(x) (x)
-+#endif
-+
-+static map_word ixp2000_flash_read8(struct map_info *map, unsigned long ofs)
-+{
-+ map_word val;
-+
-+ val.x[0] = *((u8 *)(map->map_priv_1 + flash_bank_setup(map, ofs)));
-+ return val;
-+}
-+
-+/*
-+ * We can't use the standard memcpy due to the broken SlowPort
-+ * address translation on rev A0 and A1 silicon and the fact that
-+ * we have banked flash.
-+ */
-+static void ixp2000_flash_copy_from(struct map_info *map, void *to,
-+ unsigned long from, ssize_t len)
-+{
-+ from = flash_bank_setup(map, from);
-+ while(len--)
-+ *(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++);
-+}
-+
-+static void ixp2000_flash_write8(struct map_info *map, map_word d, unsigned long ofs)
-+{
-+ *(__u8 *) (address_fix8_write(map->map_priv_1 +
-+ flash_bank_setup(map, ofs))) = d.x[0];
-+}
-+
-+static void ixp2000_flash_copy_to(struct map_info *map, unsigned long to,
-+ const void *from, ssize_t len)
-+{
-+ to = flash_bank_setup(map, to);
-+ while(len--) {
-+ unsigned long tmp = address_fix8_write(map->map_priv_1 + to++);
-+ *(__u8 *)(tmp) = *(__u8 *)(from++);
-+ }
-+}
-+
-+
-+static int ixp2000_flash_remove(struct device *_dev)
-+{
-+ struct platform_device *dev = to_platform_device(_dev);
-+ struct flash_platform_data *plat = dev->dev.platform_data;
-+ struct ixp2000_flash_info *info = dev_get_drvdata(&dev->dev);
-+
-+ dev_set_drvdata(&dev->dev, NULL);
-+
-+ if(!info)
-+ return 0;
-+
-+ if (info->mtd) {
-+ del_mtd_partitions(info->mtd);
-+ map_destroy(info->mtd);
-+ }
-+ if (info->map.map_priv_1)
-+ iounmap((void *) info->map.map_priv_1);
-+
-+ if (info->partitions) {
-+ kfree(info->partitions); }
-+
-+ if (info->res) {
-+ release_resource(info->res);
-+ kfree(info->res);
-+ }
-+
-+ if (plat->exit)
-+ plat->exit();
-+
-+ return 0;
-+}
-+
-+
-+static int ixp2000_flash_probe(struct device *_dev)
-+{
-+ static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-+ struct platform_device *dev = to_platform_device(_dev);
-+ struct ixp2000_flash_data *ixp_data = dev->dev.platform_data;
-+ struct flash_platform_data *plat;
-+ struct ixp2000_flash_info *info;
-+ unsigned long window_size;
-+ int err = -1;
-+
-+ if (!ixp_data)
-+ return -ENODEV;
-+
-+ plat = ixp_data->platform_data;
-+ if (!plat)
-+ return -ENODEV;
-+
-+ window_size = dev->resource->end - dev->resource->start + 1;
-+ dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n",
-+ ixp_data->nr_banks, ((u32)window_size >> 20));
-+
-+ if (plat->width != 1) {
-+ dev_err(_dev, "IXP2000 MTD map only supports 8-bit mode, asking for %d\n",
-+ plat->width * 8);
-+ return -EIO;
-+ }
-+
-+ info = kmalloc(sizeof(struct ixp2000_flash_info), GFP_KERNEL);
-+ if(!info) {
-+ err = -ENOMEM;
-+ goto Error;
-+ }
-+ memzero(info, sizeof(struct ixp2000_flash_info));
-+
-+ dev_set_drvdata(&dev->dev, info);
-+
-+ /*
-+ * Tell the MTD layer we're not 1:1 mapped so that it does
-+ * not attempt to do a direct access on us.
-+ */
-+ info->map.phys = NO_XIP;
-+
-+ info->nr_banks = ixp_data->nr_banks;
-+ info->map.size = ixp_data->nr_banks * window_size;
-+ info->map.bankwidth = 1;
-+
-+ /*
-+ * map_priv_2 is used to store a ptr to to the bank_setup routine
-+ */
-+ info->map.map_priv_2 = (void __iomem *) ixp_data->bank_setup;
-+
-+ info->map.name = dev->dev.bus_id;
-+ info->map.read = ixp2000_flash_read8;
-+ info->map.write = ixp2000_flash_write8;
-+ info->map.copy_from = ixp2000_flash_copy_from;
-+ info->map.copy_to = ixp2000_flash_copy_to;
-+
-+ info->res = request_mem_region(dev->resource->start,
-+ dev->resource->end - dev->resource->start + 1,
-+ dev->dev.bus_id);
-+ if (!info->res) {
-+ dev_err(_dev, "Could not reserve memory region\n");
-+ err = -ENOMEM;
-+ goto Error;
-+ }
-+
-+ info->map.map_priv_1 = ioremap(dev->resource->start,
-+ dev->resource->end - dev->resource->start + 1);
-+ if (!info->map.map_priv_1) {
-+ dev_err(_dev, "Failed to ioremap flash region\n");
-+ err = -EIO;
-+ goto Error;
-+ }
-+
-+ /*
-+ * Setup read mode for FLASH
-+ */
-+ *IXP2000_SLOWPORT_FRM = 1;
-+
-+#if defined(__ARMEB__)
-+ /*
-+ * Enable erratum 44 workaround for NPUs with broken slowport
-+ */
-+
-+ erratum44_workaround = ixp2000_has_broken_slowport();
-+ dev_info(_dev, "Erratum 44 workaround %s\n",
-+ erratum44_workaround ? "enabled" : "disabled");
-+#endif
-+
-+ info->mtd = do_map_probe(plat->map_name, &info->map);
-+ if (!info->mtd) {
-+ dev_err(_dev, "map_probe failed\n");
-+ err = -ENXIO;
-+ goto Error;
-+ }
-+ info->mtd->owner = THIS_MODULE;
-+
-+ err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0);
-+ if (err > 0) {
-+ err = add_mtd_partitions(info->mtd, info->partitions, err);
-+ if(err)
-+ dev_err(_dev, "Could not parse partitions\n");
-+ }
-+
-+ if (err)
-+ goto Error;
-+
-+ return 0;
-+
-+Error:
-+ ixp2000_flash_remove(_dev);
-+ return err;
-+}
-+
-+static struct device_driver ixp2000_flash_driver = {
-+ .name = "IXP2000-Flash",
-+ .bus = &platform_bus_type,
-+ .probe = &ixp2000_flash_probe,
-+ .remove = &ixp2000_flash_remove
-+};
-+
-+static int __init ixp2000_flash_init(void)
-+{
-+ return driver_register(&ixp2000_flash_driver);
-+}
-+
-+static void __exit ixp2000_flash_exit(void)
-+{
-+ driver_unregister(&ixp2000_flash_driver);
-+}
-+
-+module_init(ixp2000_flash_init);
-+module_exit(ixp2000_flash_exit);
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
-+
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/ixp4xx.c
-@@ -0,0 +1,259 @@
-+/*
-+ * $Id: ixp4xx.c,v 1.7 2004/11/04 13:24:15 gleixner Exp $
-+ *
-+ * drivers/mtd/maps/ixp4xx.c
-+ *
-+ * MTD Map file for IXP4XX based systems. Please do not make per-board
-+ * changes in here. If your board needs special setup, do it in your
-+ * platform level code in arch/arm/mach-ixp4xx/board-setup.c
-+ *
-+ * Original Author: Intel Corporation
-+ * Maintainer: Deepak Saxena <dsaxena@mvista.com>
-+ *
-+ * Copyright (C) 2002 Intel Corporation
-+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/ioport.h>
-+#include <linux/device.h>
-+#include <asm/io.h>
-+#include <asm/mach-types.h>
-+#include <asm/mach/flash.h>
-+
-+#include <linux/reboot.h>
-+
-+#ifndef __ARMEB__
-+#define BYTE0(h) ((h) & 0xFF)
-+#define BYTE1(h) (((h) >> 8) & 0xFF)
-+#else
-+#define BYTE0(h) (((h) >> 8) & 0xFF)
-+#define BYTE1(h) ((h) & 0xFF)
-+#endif
-+
-+static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs)
-+{
-+ map_word val;
-+ val.x[0] = *(__u16 *) (map->map_priv_1 + ofs);
-+ return val;
-+}
-+
-+/*
-+ * The IXP4xx expansion bus only allows 16-bit wide acceses
-+ * when attached to a 16-bit wide device (such as the 28F128J3A),
-+ * so we can't just memcpy_fromio().
-+ */
-+static void ixp4xx_copy_from(struct map_info *map, void *to,
-+ unsigned long from, ssize_t len)
-+{
-+ int i;
-+ u8 *dest = (u8 *) to;
-+ u16 *src = (u16 *) (map->map_priv_1 + from);
-+ u16 data;
-+
-+ for (i = 0; i < (len / 2); i++) {
-+ data = src[i];
-+ dest[i * 2] = BYTE0(data);
-+ dest[i * 2 + 1] = BYTE1(data);
-+ }
-+
-+ if (len & 1)
-+ dest[len - 1] = BYTE0(src[i]);
-+}
-+
-+/*
-+ * Unaligned writes are ignored, causing the 8-bit
-+ * probe to fail and proceed to the 16-bit probe (which succeeds).
-+ */
-+static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr)
-+{
-+ if (!(adr & 1))
-+ *(__u16 *) (map->map_priv_1 + adr) = d.x[0];
-+}
-+
-+/*
-+ * Fast write16 function without the probing check above
-+ */
-+static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr)
-+{
-+ *(__u16 *) (map->map_priv_1 + adr) = d.x[0];
-+}
-+
-+struct ixp4xx_flash_info {
-+ struct mtd_info *mtd;
-+ struct map_info map;
-+ struct mtd_partition *partitions;
-+ struct resource *res;
-+};
-+
-+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-+
-+static int ixp4xx_flash_remove(struct device *_dev)
-+{
-+ struct platform_device *dev = to_platform_device(_dev);
-+ struct flash_platform_data *plat = dev->dev.platform_data;
-+ struct ixp4xx_flash_info *info = dev_get_drvdata(&dev->dev);
-+ map_word d;
-+
-+ dev_set_drvdata(&dev->dev, NULL);
-+
-+ if(!info)
-+ return 0;
-+
-+ /*
-+ * This is required for a soft reboot to work.
-+ */
-+ d.x[0] = 0xff;
-+ ixp4xx_write16(&info->map, d, 0x55 * 0x2);
-+
-+ if (info->mtd) {
-+ del_mtd_partitions(info->mtd);
-+ map_destroy(info->mtd);
-+ }
-+ if (info->map.map_priv_1)
-+ iounmap((void *) info->map.map_priv_1);
-+
-+ if (info->partitions)
-+ kfree(info->partitions);
-+
-+ if (info->res) {
-+ release_resource(info->res);
-+ kfree(info->res);
-+ }
-+
-+ if (plat->exit)
-+ plat->exit();
-+
-+ /* Disable flash write */
-+ *IXP4XX_EXP_CS0 &= ~IXP4XX_FLASH_WRITABLE;
-+
-+ return 0;
-+}
-+
-+static int ixp4xx_flash_probe(struct device *_dev)
-+{
-+ struct platform_device *dev = to_platform_device(_dev);
-+ struct flash_platform_data *plat = dev->dev.platform_data;
-+ struct ixp4xx_flash_info *info;
-+ int err = -1;
-+
-+ if (!plat)
-+ return -ENODEV;
-+
-+ if (plat->init) {
-+ err = plat->init();
-+ if (err)
-+ return err;
-+ }
-+
-+ info = kmalloc(sizeof(struct ixp4xx_flash_info), GFP_KERNEL);
-+ if(!info) {
-+ err = -ENOMEM;
-+ goto Error;
-+ }
-+ memzero(info, sizeof(struct ixp4xx_flash_info));
-+
-+ dev_set_drvdata(&dev->dev, info);
-+
-+ /*
-+ * Enable flash write
-+ * TODO: Move this out to board specific code
-+ */
-+ *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
-+
-+ /*
-+ * Tell the MTD layer we're not 1:1 mapped so that it does
-+ * not attempt to do a direct access on us.
-+ */
-+ info->map.phys = NO_XIP;
-+ info->map.size = dev->resource->end - dev->resource->start + 1;
-+
-+ /*
-+ * We only support 16-bit accesses for now. If and when
-+ * any board use 8-bit access, we'll fixup the driver to
-+ * handle that.
-+ */
-+ info->map.bankwidth = 2;
-+ info->map.name = dev->dev.bus_id;
-+ info->map.read = ixp4xx_read16,
-+ info->map.write = ixp4xx_probe_write16,
-+ info->map.copy_from = ixp4xx_copy_from,
-+
-+ info->res = request_mem_region(dev->resource->start,
-+ dev->resource->end - dev->resource->start + 1,
-+ "IXP4XXFlash");
-+ if (!info->res) {
-+ printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n");
-+ err = -ENOMEM;
-+ goto Error;
-+ }
-+
-+ info->map.map_priv_1 = ioremap(dev->resource->start,
-+ dev->resource->end - dev->resource->start + 1);
-+ if (!info->map.map_priv_1) {
-+ printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n");
-+ err = -EIO;
-+ goto Error;
-+ }
-+
-+ info->mtd = do_map_probe(plat->map_name, &info->map);
-+ if (!info->mtd) {
-+ printk(KERN_ERR "IXP4XXFlash: map_probe failed\n");
-+ err = -ENXIO;
-+ goto Error;
-+ }
-+ info->mtd->owner = THIS_MODULE;
-+
-+ /* Use the fast version */
-+ info->map.write = ixp4xx_write16,
-+
-+ err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0);
-+ if (err > 0) {
-+ err = add_mtd_partitions(info->mtd, info->partitions, err);
-+ if(err)
-+ printk(KERN_ERR "Could not parse partitions\n");
-+ }
-+
-+ if (err)
-+ goto Error;
-+
-+ return 0;
-+
-+Error:
-+ ixp4xx_flash_remove(_dev);
-+ return err;
-+}
-+
-+static struct device_driver ixp4xx_flash_driver = {
-+ .name = "IXP4XX-Flash",
-+ .bus = &platform_bus_type,
-+ .probe = ixp4xx_flash_probe,
-+ .remove = ixp4xx_flash_remove,
-+};
-+
-+static int __init ixp4xx_flash_init(void)
-+{
-+ return driver_register(&ixp4xx_flash_driver);
-+}
-+
-+static void __exit ixp4xx_flash_exit(void)
-+{
-+ driver_unregister(&ixp4xx_flash_driver);
-+}
-+
-+
-+module_init(ixp4xx_flash_init);
-+module_exit(ixp4xx_flash_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems")
-+MODULE_AUTHOR("Deepak Saxena");
-+
---- linux-2.4.21/drivers/mtd/maps/l440gx.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/l440gx.c
-@@ -1,5 +1,5 @@
- /*
-- * $Id: l440gx.c,v 1.8 2002/01/10 20:27:40 eric Exp $
-+ * $Id: l440gx.c,v 1.17 2004/11/28 09:40:39 dwmw2 Exp $
- *
- * BIOS Flash chip on Intel 440GX board.
- *
-@@ -9,6 +9,7 @@
- #include <linux/module.h>
- #include <linux/pci.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -27,51 +28,9 @@
-
- static struct mtd_info *mymtd;
-
--__u8 l440gx_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 l440gx_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 l440gx_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void l440gx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void l440gx_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void l440gx_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void l440gx_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void l440gx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
-
- /* Is this really the vpp port? */
--void l440gx_set_vpp(struct map_info *map, int vpp)
-+static void l440gx_set_vpp(struct map_info *map, int vpp)
- {
- unsigned long l;
-
-@@ -84,23 +43,16 @@
- outl(l, VPP_PORT);
- }
-
--struct map_info l440gx_map = {
-- name: "L440GX BIOS",
-- size: WINDOW_SIZE,
-- buswidth: BUSWIDTH,
-- read8: l440gx_read8,
-- read16: l440gx_read16,
-- read32: l440gx_read32,
-- copy_from: l440gx_copy_from,
-- write8: l440gx_write8,
-- write16: l440gx_write16,
-- write32: l440gx_write32,
-- copy_to: l440gx_copy_to,
-+static struct map_info l440gx_map = {
-+ .name = "L440GX BIOS",
-+ .size = WINDOW_SIZE,
-+ .bankwidth = BUSWIDTH,
-+ .phys = WINDOW_ADDR,
- #if 0
- /* FIXME verify that this is the
- * appripriate code for vpp enable/disable
- */
-- set_vpp: l440gx_set_vpp
-+ .set_vpp = l440gx_set_vpp
- #endif
- };
-
-@@ -113,7 +65,6 @@
- dev = pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82371AB_0, NULL);
-
--
- pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
-
-@@ -122,15 +73,14 @@
- return -ENODEV;
- }
-
-+ l440gx_map.virt = ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
-
-- l440gx_map.map_priv_1 = (unsigned long)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
--
-- if (!l440gx_map.map_priv_1) {
-+ if (!l440gx_map.virt) {
- printk(KERN_WARNING "Failed to ioremap L440GX flash region\n");
- return -ENOMEM;
- }
--
-- printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.map_priv_1);
-+ simple_map_init(&l440gx_map);
-+ printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.virt);
-
- /* Setup the pm iobase resource
- * This code should move into some kind of generic bridge
-@@ -153,7 +103,7 @@
- /* Allocate the resource region */
- if (pci_assign_resource(pm_dev, PIIXE_IOBASE_RESOURCE) != 0) {
- printk(KERN_WARNING "Could not allocate pm iobase resource\n");
-- iounmap((void *)l440gx_map.map_priv_1);
-+ iounmap(l440gx_map.virt);
- return -ENXIO;
- }
- }
-@@ -181,13 +131,13 @@
- mymtd = do_map_probe("map_rom", &l440gx_map);
- }
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
- add_mtd_device(mymtd);
- return 0;
- }
-
-- iounmap((void *)l440gx_map.map_priv_1);
-+ iounmap(l440gx_map.virt);
- return -ENXIO;
- }
-
-@@ -196,7 +146,7 @@
- del_mtd_device(mymtd);
- map_destroy(mymtd);
-
-- iounmap((void *)l440gx_map.map_priv_1);
-+ iounmap(l440gx_map.virt);
- }
-
- module_init(init_l440gx);
---- linux-2.4.21/drivers/mtd/maps/lasat.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/lasat.c
-@@ -1,111 +1,73 @@
- /*
-- * Flash device on lasat 100 and 200 boards
-+ * Flash device on Lasat 100 and 200 boards
- *
-- * Presumably (C) 2002 Brian Murphy <brian@murphy.dk> or whoever he
-- * works for.
-+ * (C) 2002 Brian Murphy <brian@murphy.dk>
- *
- * 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.
- *
-- * $Id: lasat.c,v 1.1 2003/01/24 14:26:38 dwmw2 Exp $
-+ * $Id: lasat.c,v 1.9 2004/11/04 13:24:15 gleixner 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/mtd/partitions.h>
- #include <linux/config.h>
- #include <asm/lasat/lasat.h>
--#include <asm/lasat/lasat_mtd.h>
--
--static struct mtd_info *mymtd;
--
--static __u8 sp_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--static __u16 sp_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--static __u32 sp_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--static void sp_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--static void sp_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
-
--static void sp_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
-+static struct mtd_info *lasat_mtd;
-
--static void sp_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
-+static struct mtd_partition partition_info[LASAT_MTD_LAST];
-+static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Filesystem", "Config"};
-
--static void sp_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-+static void lasat_set_vpp(struct map_info *map, int vpp)
- {
-- memcpy_toio(map->map_priv_1 + to, from, len);
-+ if (vpp)
-+ *lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit;
-+ else
-+ *lasat_misc->flash_wp_reg &= ~(1 << lasat_misc->flash_wp_bit);
- }
-
--static struct map_info sp_map = {
-- .name = "SP flash",
-- .buswidth = 4,
-- .read8 = sp_read8,
-- .read16 = sp_read16,
-- .read32 = sp_read32,
-- .copy_from = sp_copy_from,
-- .write8 = sp_write8,
-- .write16 = sp_write16,
-- .write32 = sp_write32,
-- .copy_to = sp_copy_to
-+static struct map_info lasat_map = {
-+ .name = "LASAT flash",
-+ .bankwidth = 4,
-+ .set_vpp = lasat_set_vpp
- };
-
--static struct mtd_partition partition_info[LASAT_MTD_LAST];
--static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Filesystem", "Config"};
--
--static int __init init_sp(void)
-+static int __init init_lasat(void)
- {
- int i;
-- /* this does not play well with the old flash code which
-- * protects and uprotects the flash when necessary */
-+ /* since we use AMD chips and set_vpp is not implimented
-+ * for these (yet) we still have to permanently enable flash write */
- printk(KERN_NOTICE "Unprotecting flash\n");
-- *lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit;
-+ ENABLE_VPP((&lasat_map));
-
-- sp_map.map_priv_1 = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER);
-- sp_map.size = lasat_board_info.li_flash_size;
-+ lasat_map.phys = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER);
-+ lasat_map.virt = ioremap_nocache(
-+ lasat_map.phys, lasat_board_info.li_flash_size);
-+ lasat_map.size = lasat_board_info.li_flash_size;
-
-- printk(KERN_NOTICE "sp flash device: %lx at %lx\n",
-- sp_map.size, sp_map.map_priv_1);
-+ simple_map_init(&lasat_map);
-
- for (i=0; i < LASAT_MTD_LAST; i++)
- partition_info[i].name = lasat_mtd_partnames[i];
-
-- mymtd = do_map_probe("cfi_probe", &sp_map);
-- if (mymtd) {
-+ lasat_mtd = do_map_probe("cfi_probe", &lasat_map);
-+
-+ if (!lasat_mtd)
-+ lasat_mtd = do_map_probe("jedec_probe", &lasat_map);
-+
-+ if (lasat_mtd) {
- u32 size, offset = 0;
-
-- mymtd->module = THIS_MODULE;
-+ lasat_mtd->owner = THIS_MODULE;
-
- for (i=0; i < LASAT_MTD_LAST; i++) {
- size = lasat_flash_partition_size(i);
-@@ -114,26 +76,26 @@
- offset += size;
- }
-
-- add_mtd_partitions( mymtd, partition_info, LASAT_MTD_LAST );
-+ add_mtd_partitions( lasat_mtd, partition_info, LASAT_MTD_LAST );
- return 0;
- }
-
- return -ENXIO;
- }
-
--static void __exit cleanup_sp(void)
-+static void __exit cleanup_lasat(void)
- {
-- if (mymtd) {
-- del_mtd_partitions(mymtd);
-- map_destroy(mymtd);
-+ if (lasat_mtd) {
-+ del_mtd_partitions(lasat_mtd);
-+ map_destroy(lasat_mtd);
- }
-- if (sp_map.map_priv_1) {
-- sp_map.map_priv_1 = 0;
-+ if (lasat_map.virt) {
-+ lasat_map.virt = 0;
- }
- }
-
--module_init(init_sp);
--module_exit(cleanup_sp);
-+module_init(init_lasat);
-+module_exit(cleanup_lasat);
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Brian Murphy <brian@murphy.dk>");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/lubbock-flash.c
-@@ -0,0 +1,168 @@
-+/*
-+ * $Id: lubbock-flash.c,v 1.19 2004/11/04 13:24:15 gleixner Exp $
-+ *
-+ * Map driver for the Lubbock developer platform.
-+ *
-+ * Author: Nicolas Pitre
-+ * Copyright: (C) 2001 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/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/io.h>
-+#include <asm/hardware.h>
-+#include <asm/arch/pxa-regs.h>
-+#include <asm/arch/lubbock.h>
-+
-+
-+#define ROM_ADDR 0x00000000
-+#define FLASH_ADDR 0x04000000
-+
-+#define WINDOW_SIZE 64*1024*1024
-+
-+static void lubbock_map_inval_cache(struct map_info *map, unsigned long from, ssize_t len)
-+{
-+ consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE);
-+}
-+
-+static struct map_info lubbock_maps[2] = { {
-+ .size = WINDOW_SIZE,
-+ .phys = 0x00000000,
-+ .inval_cache = lubbock_map_inval_cache,
-+}, {
-+ .size = WINDOW_SIZE,
-+ .phys = 0x04000000,
-+ .inval_cache = lubbock_map_inval_cache,
-+} };
-+
-+static struct mtd_partition lubbock_partitions[] = {
-+ {
-+ .name = "Bootloader",
-+ .size = 0x00040000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
-+ },{
-+ .name = "Kernel",
-+ .size = 0x00100000,
-+ .offset = 0x00040000,
-+ },{
-+ .name = "Filesystem",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = 0x00140000
-+ }
-+};
-+
-+static struct mtd_info *mymtds[2];
-+static struct mtd_partition *parsed_parts[2];
-+static int nr_parsed_parts[2];
-+
-+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-+
-+static int __init init_lubbock(void)
-+{
-+ int flashboot = (LUB_CONF_SWITCHES & 1);
-+ int ret = 0, i;
-+
-+ lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth =
-+ (BOOT_DEF & 1) ? 2 : 4;
-+
-+ /* Compensate for the nROMBT switch which swaps the flash banks */
-+ printk(KERN_NOTICE "Lubbock configured to boot from %s (bank %d)\n",
-+ flashboot?"Flash":"ROM", flashboot);
-+
-+ lubbock_maps[flashboot^1].name = "Lubbock Application Flash";
-+ lubbock_maps[flashboot].name = "Lubbock Boot ROM";
-+
-+ for (i = 0; i < 2; i++) {
-+ lubbock_maps[i].virt = ioremap(lubbock_maps[i].phys, WINDOW_SIZE);
-+ if (!lubbock_maps[i].virt) {
-+ printk(KERN_WARNING "Failed to ioremap %s\n", lubbock_maps[i].name);
-+ if (!ret)
-+ ret = -ENOMEM;
-+ continue;
-+ }
-+ lubbock_maps[i].cached = ioremap_cached(lubbock_maps[i].phys, WINDOW_SIZE);
-+ if (!lubbock_maps[i].cached)
-+ printk(KERN_WARNING "Failed to ioremap cached %s\n", lubbock_maps[i].name);
-+ simple_map_init(&lubbock_maps[i]);
-+
-+ printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)\n",
-+ lubbock_maps[i].name, lubbock_maps[i].phys,
-+ lubbock_maps[i].bankwidth * 8);
-+
-+ mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]);
-+
-+ if (!mymtds[i]) {
-+ iounmap((void *)lubbock_maps[i].virt);
-+ if (lubbock_maps[i].cached)
-+ iounmap(lubbock_maps[i].cached);
-+ if (!ret)
-+ ret = -EIO;
-+ continue;
-+ }
-+ mymtds[i]->owner = THIS_MODULE;
-+
-+ ret = parse_mtd_partitions(mymtds[i], probes,
-+ &parsed_parts[i], 0);
-+
-+ if (ret > 0)
-+ nr_parsed_parts[i] = ret;
-+ }
-+
-+ if (!mymtds[0] && !mymtds[1])
-+ return ret;
-+
-+ for (i = 0; i < 2; i++) {
-+ if (!mymtds[i]) {
-+ printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name);
-+ } else if (nr_parsed_parts[i]) {
-+ add_mtd_partitions(mymtds[i], parsed_parts[i], nr_parsed_parts[i]);
-+ } else if (!i) {
-+ printk("Using static partitions on %s\n", lubbock_maps[i].name);
-+ add_mtd_partitions(mymtds[i], lubbock_partitions, ARRAY_SIZE(lubbock_partitions));
-+ } else {
-+ printk("Registering %s as whole device\n", lubbock_maps[i].name);
-+ add_mtd_device(mymtds[i]);
-+ }
-+ }
-+ return 0;
-+}
-+
-+static void __exit cleanup_lubbock(void)
-+{
-+ int i;
-+ for (i = 0; i < 2; i++) {
-+ if (!mymtds[i])
-+ continue;
-+
-+ if (nr_parsed_parts[i] || !i)
-+ del_mtd_partitions(mymtds[i]);
-+ else
-+ del_mtd_device(mymtds[i]);
-+
-+ map_destroy(mymtds[i]);
-+ iounmap((void *)lubbock_maps[i].virt);
-+ if (lubbock_maps[i].cached)
-+ iounmap(lubbock_maps[i].cached);
-+
-+ if (parsed_parts[i])
-+ kfree(parsed_parts[i]);
-+ }
-+}
-+
-+module_init(init_lubbock);
-+module_exit(cleanup_lubbock);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
-+MODULE_DESCRIPTION("MTD map driver for Intel Lubbock");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/map_funcs.c
-@@ -0,0 +1,44 @@
-+/*
-+ * $Id: map_funcs.c,v 1.9 2004/07/13 22:33:15 dwmw2 Exp $
-+ *
-+ * Out-of-line map I/O functions for simple maps when CONFIG_COMPLEX_MAPPINGS
-+ * is enabled.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+
-+#include <linux/mtd/map.h>
-+
-+static map_word simple_map_read(struct map_info *map, unsigned long ofs)
-+{
-+ return inline_map_read(map, ofs);
-+}
-+
-+static void simple_map_write(struct map_info *map, const map_word datum, unsigned long ofs)
-+{
-+ inline_map_write(map, datum, ofs);
-+}
-+
-+static void simple_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-+{
-+ inline_map_copy_from(map, to, from, len);
-+}
-+
-+static void simple_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-+{
-+ inline_map_copy_to(map, to, from, len);
-+}
-+
-+void simple_map_init(struct map_info *map)
-+{
-+ BUG_ON(!map_bankwidth_supported(map->bankwidth));
-+
-+ map->read = simple_map_read;
-+ map->write = simple_map_write;
-+ map->copy_from = simple_map_copy_from;
-+ map->copy_to = simple_map_copy_to;
-+}
-+
-+EXPORT_SYMBOL(simple_map_init);
-+MODULE_LICENSE("GPL");
---- linux-2.4.21/drivers/mtd/maps/mbx860.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/mbx860.c
-@@ -1,5 +1,5 @@
- /*
-- * $Id: mbx860.c,v 1.1 2001/11/18 19:43:09 dwmw2 Exp $
-+ * $Id: mbx860.c,v 1.8 2004/11/04 13:24:15 gleixner Exp $
- *
- * Handle mapping of the flash on MBX860 boards
- *
-@@ -15,6 +15,7 @@
- #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>
-@@ -36,91 +37,46 @@
- * single flash device into. If the size if zero we use up to the end of the
- * device. */
- static struct mtd_partition partition_info[]={
-- { name: "MBX flash BOOT partition",
-- offset: 0,
-- size: BOOT_PARTITION_SIZE_KiB*1024 },
-- { name: "MBX flash DATA partition",
-- offset: BOOT_PARTITION_SIZE_KiB*1024,
-- size: (KERNEL_PARTITION_SIZE_KiB)*1024 },
-- { name: "MBX flash APPLICATION partition",
-- offset: (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 }
-+ { .name = "MBX flash BOOT partition",
-+ .offset = 0,
-+ .size = BOOT_PARTITION_SIZE_KiB*1024 },
-+ { .name = "MBX flash DATA partition",
-+ .offset = BOOT_PARTITION_SIZE_KiB*1024,
-+ .size = (KERNEL_PARTITION_SIZE_KiB)*1024 },
-+ { .name = "MBX flash APPLICATION partition",
-+ .offset = (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 }
- };
-
-
- static struct mtd_info *mymtd;
-
--__u8 mbx_read8(struct map_info *map, unsigned long ofs)
--{
-- return readb(map->map_priv_1 + ofs);
--}
--
--__u16 mbx_read16(struct map_info *map, unsigned long ofs)
--{
-- return readw(map->map_priv_1 + ofs);
--}
--
--__u32 mbx_read32(struct map_info *map, unsigned long ofs)
--{
-- return readl(map->map_priv_1 + ofs);
--}
--
--void mbx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
--}
--
--void mbx_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- writeb(d, map->map_priv_1 + adr);
--}
--
--void mbx_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- writew(d, map->map_priv_1 + adr);
--}
--
--void mbx_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- writel(d, map->map_priv_1 + adr);
--}
--
--void mbx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio((void *)(map->map_priv_1 + to), from, len);
--}
--
- struct map_info mbx_map = {
-- name: "MBX flash",
-- size: WINDOW_SIZE,
-- buswidth: 4,
-- read8: mbx_read8,
-- read16: mbx_read16,
-- read32: mbx_read32,
-- copy_from: mbx_copy_from,
-- write8: mbx_write8,
-- write16: mbx_write16,
-- write32: mbx_write32,
-- copy_to: mbx_copy_to
-+ .name = "MBX flash",
-+ .size = WINDOW_SIZE,
-+ .phys = WINDOW_ADDR,
-+ .bankwidth = 4,
- };
-
- int __init init_mbx(void)
- {
-- printk(KERN_NOTICE "Motorola MBX flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR);
-- mbx_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
-+ printk(KERN_NOTICE "Motorola MBX flash device: 0x%x at 0x%x\n", WINDOW_SIZE*4, WINDOW_ADDR);
-+ mbx_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
-
-- if (!mbx_map.map_priv_1) {
-+ if (!mbx_map.virt) {
- printk("Failed to ioremap\n");
- return -EIO;
- }
-+ simple_map_init(&mbx_map);
-+
- mymtd = do_map_probe("jedec_probe", &mbx_map);
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
- add_mtd_device(mymtd);
- add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
- return 0;
- }
-
-- iounmap((void *)mbx_map.map_priv_1);
-+ iounmap((void *)mbx_map.virt);
- return -ENXIO;
- }
-
-@@ -130,9 +86,9 @@
- del_mtd_device(mymtd);
- map_destroy(mymtd);
- }
-- if (mbx_map.map_priv_1) {
-- iounmap((void *)mbx_map.map_priv_1);
-- mbx_map.map_priv_1 = 0;
-+ if (mbx_map.virt) {
-+ iounmap((void *)mbx_map.virt);
-+ mbx_map.virt = 0;
- }
- }
-
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/mpc1211.c
-@@ -0,0 +1,81 @@
-+/*
-+ * Flash on MPC-1211
-+ *
-+ * $Id: mpc1211.c,v 1.4 2004/09/16 23:27:13 gleixner Exp $
-+ *
-+ * (C) 2002 Interface, Saito.K & Jeanne
-+ *
-+ * GPL'd
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <asm/io.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/config.h>
-+
-+static struct mtd_info *flash_mtd;
-+static struct mtd_partition *parsed_parts;
-+
-+struct map_info mpc1211_flash_map = {
-+ .name = "MPC-1211 FLASH",
-+ .size = 0x80000,
-+ .bankwidth = 1,
-+};
-+
-+static struct mtd_partition mpc1211_partitions[] = {
-+ {
-+ .name = "IPL & ETH-BOOT",
-+ .offset = 0x00000000,
-+ .size = 0x10000,
-+ },
-+ {
-+ .name = "Flash FS",
-+ .offset = 0x00010000,
-+ .size = MTDPART_SIZ_FULL,
-+ }
-+};
-+
-+static int __init init_mpc1211_maps(void)
-+{
-+ int nr_parts;
-+
-+ mpc1211_flash_map.phys = 0;
-+ mpc1211_flash_map.virt = (void __iomem *)P2SEGADDR(0);
-+
-+ simple_map_init(&mpc1211_flash_map);
-+
-+ printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n");
-+ flash_mtd = do_map_probe("jedec_probe", &mpc1211_flash_map);
-+ if (!flash_mtd) {
-+ printk(KERN_NOTICE "Flash chips not detected at either possible location.\n");
-+ return -ENXIO;
-+ }
-+ printk(KERN_NOTICE "MPC-1211: Flash at 0x%08lx\n", mpc1211_flash_map.virt & 0x1fffffff);
-+ flash_mtd->module = THIS_MODULE;
-+
-+ parsed_parts = mpc1211_partitions;
-+ nr_parts = ARRAY_SIZE(mpc1211_partitions);
-+
-+ add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
-+ return 0;
-+}
-+
-+static void __exit cleanup_mpc1211_maps(void)
-+{
-+ if (parsed_parts)
-+ del_mtd_partitions(flash_mtd);
-+ else
-+ del_mtd_device(flash_mtd);
-+ map_destroy(flash_mtd);
-+}
-+
-+module_init(init_mpc1211_maps);
-+module_exit(cleanup_mpc1211_maps);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Saito.K & Jeanne <ksaito@interface.co.jp>");
-+MODULE_DESCRIPTION("MTD map driver for MPC-1211 boards. Interface");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/mphysmap.c
-@@ -0,0 +1,282 @@
-+/*
-+ * $Id: mphysmap.c,v 1.2 2005/03/07 23:15:48 joern Exp $
-+ *
-+ * Several mappings of NOR chips
-+ *
-+ * Copyright (c) 2001-2005 Jörn Engel <joern@wh.fh-wedelde>
-+ */
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
-+
-+
-+#define NO_DEVICES 8
-+struct map_info maps[NO_DEVICES] = {
-+#if CONFIG_MTD_MULTI_PHYSMAP_1_WIDTH
-+ {
-+ .name = CONFIG_MTD_MULTI_PHYSMAP_1_NAME,
-+ .phys = CONFIG_MTD_MULTI_PHYSMAP_1_START,
-+ .size = CONFIG_MTD_MULTI_PHYSMAP_1_LEN,
-+ .bankwidth = CONFIG_MTD_MULTI_PHYSMAP_1_WIDTH,
-+ },
-+#endif
-+#if CONFIG_MTD_MULTI_PHYSMAP_2_WIDTH
-+ {
-+ .name = CONFIG_MTD_MULTI_PHYSMAP_2_NAME,
-+ .phys = CONFIG_MTD_MULTI_PHYSMAP_2_START,
-+ .size = CONFIG_MTD_MULTI_PHYSMAP_2_LEN,
-+ .bankwidth = CONFIG_MTD_MULTI_PHYSMAP_2_WIDTH,
-+ },
-+#endif
-+#if CONFIG_MTD_MULTI_PHYSMAP_3_WIDTH
-+ {
-+ .name = CONFIG_MTD_MULTI_PHYSMAP_3_NAME,
-+ .phys = CONFIG_MTD_MULTI_PHYSMAP_3_START,
-+ .size = CONFIG_MTD_MULTI_PHYSMAP_3_LEN,
-+ .bankwidth = CONFIG_MTD_MULTI_PHYSMAP_3_WIDTH,
-+ },
-+#endif
-+#if CONFIG_MTD_MULTI_PHYSMAP_4_WIDTH
-+ {
-+ .name = CONFIG_MTD_MULTI_PHYSMAP_4_NAME,
-+ .phys = CONFIG_MTD_MULTI_PHYSMAP_4_START,
-+ .size = CONFIG_MTD_MULTI_PHYSMAP_4_LEN,
-+ .bankwidth = CONFIG_MTD_MULTI_PHYSMAP_4_WIDTH,
-+ },
-+#endif
-+ {
-+ .name = NULL,
-+ },
-+};
-+DECLARE_MUTEX(map_mutex);
-+
-+
-+static int map_one(struct map_info *map)
-+{
-+ struct mtd_info *mtd;
-+
-+ map->virt = ioremap(map->phys, map->size);
-+ if (!map->virt)
-+ return -EIO;
-+
-+ simple_map_init(map);
-+
-+ mtd = do_map_probe("cfi_probe", map);
-+ if (!mtd) {
-+ iounmap(map->virt);
-+ return -ENXIO;
-+ }
-+
-+ map->map_priv_1 = (unsigned long)mtd;
-+ mtd->owner = THIS_MODULE;
-+ /* TODO: partitioning */
-+ return add_mtd_device(mtd);
-+}
-+
-+
-+static void unmap_one(struct map_info *map)
-+{
-+ struct mtd_info *mtd = (struct mtd_info*)map->map_priv_1;
-+
-+ if (map->map_priv_2)
-+ kfree(map->name);
-+
-+ if (!map->virt)
-+ return;
-+
-+ BUG_ON(!mtd);
-+ BUG_ON(map->map_priv_2 > 1);
-+
-+ del_mtd_device(mtd);
-+ map_destroy(mtd);
-+ iounmap(map->virt);
-+
-+ map->map_priv_1 = 0;
-+ map->map_priv_2 = 0;
-+ map->virt = NULL;
-+}
-+
-+
-+static struct map_info *next_free_map(void)
-+{
-+ int i;
-+ for (i=0; i<NO_DEVICES; i++) {
-+ struct map_info *map = &maps[i];
-+ if (!map->virt)
-+ return map;
-+ }
-+ return NULL;
-+}
-+
-+
-+static int add_one_map(const char *name, unsigned long start,
-+ unsigned long len, int width)
-+{
-+ struct map_info *map = next_free_map();
-+ if (!map)
-+ return -ENOSPC;
-+
-+ map->name = kmalloc(strlen(name)+1, GFP_KERNEL);
-+ if (!name)
-+ return -ENOMEM;
-+
-+ strcpy(map->name, name);
-+ map->phys = start;
-+ map->size = len;
-+ map->bankwidth = width;
-+ map->map_priv_2 = 1; /* marker to free map->name */
-+
-+ return map_one(map);
-+}
-+
-+
-+static int parse_ulong(unsigned long *num, const char *token)
-+{
-+ char *endp;
-+ unsigned long n;
-+
-+ n = ustrtoul(token, &endp, 0);
-+ if (*endp)
-+ return -EINVAL;
-+
-+ *num = n;
-+ return 0;
-+}
-+
-+
-+static int parse_uint(unsigned int *num, const char *token)
-+{
-+ char *endp;
-+ unsigned long n;
-+
-+ n = ustrtoul(token, &endp, 0);
-+ if (*endp)
-+ return -EINVAL;
-+ if ((int)n != n)
-+ return -EINVAL;
-+
-+ *num = n;
-+ return 0;
-+}
-+
-+
-+static int parse_name(char **pname, const char *token, int limit)
-+{
-+ size_t len;
-+ char *name;
-+
-+ len = strlen(token) + 1;
-+ if (len > limit)
-+ return -ENOSPC;
-+
-+ name = kmalloc(len, GFP_KERNEL);
-+ if (!name)
-+ return -ENOMEM;
-+
-+ memcpy(name, token, len);
-+
-+ *pname = name;
-+ return 0;
-+}
-+
-+
-+static inline void kill_final_newline(char *str)
-+{
-+ char *newline = strrchr(str, '\n');
-+ if (newline && !newline[1])
-+ *newline = 0;
-+}
-+
-+
-+#define parse_err(fmt, args...) do { \
-+ printk(KERN_ERR fmt "\n", ## args); \
-+ return 0; \
-+} while(0)
-+
-+/* mphysmap=name,start,len,width */
-+static int mphysmap_setup(const char *val, struct kernel_param *kp)
-+{
-+ char buf[64+14+14+14], *str = buf;
-+ char *token[4];
-+ char *name;
-+ unsigned long start;
-+ unsigned long len;
-+ unsigned int width;
-+ int i, ret;
-+
-+ if (strnlen(val, sizeof(buf)) >= sizeof(buf))
-+ parse_err("parameter too long");
-+
-+ strcpy(str, val);
-+ kill_final_newline(str);
-+
-+ for (i=0; i<4; i++)
-+ token[i] = strsep(&str, ",");
-+
-+ if (str)
-+ parse_err("too many arguments");
-+ if (!token[3])
-+ parse_err("not enough arguments");
-+
-+ ret = parse_name(&name, token[0], 64);
-+ if (ret == -ENOMEM)
-+ parse_err("out of memory");
-+ if (ret == -ENOSPC)
-+ parse_err("name too long");
-+ if (ret)
-+ parse_err("illegal name: %d", ret);
-+
-+ ret = parse_ulong(&start, token[1]);
-+ if (ret)
-+ parse_err("illegal start address");
-+
-+ ret = parse_ulong(&len, token[2]);
-+ if (ret)
-+ parse_err("illegal length");
-+
-+ ret = parse_uint(&width, token[3]);
-+ if (ret)
-+ parse_err("illegal bus width");
-+
-+ down(&map_mutex);
-+ ret = add_one_map(name, start, len, width);
-+ up(&map_mutex);
-+ if (ret == -ENOSPC)
-+ parse_err("no free space for new map");
-+ if (ret)
-+ parse_err("error while mapping: %d", ret);
-+
-+ return 0;
-+}
-+
-+
-+static int __init mphysmap_init(void)
-+{
-+ int i;
-+ down(&map_mutex);
-+ for (i=0; i<NO_DEVICES; i++)
-+ map_one(&maps[i]);
-+ up(&map_mutex);
-+ return 0;
-+}
-+
-+
-+static void __exit mphysmap_exit(void)
-+{
-+ int i;
-+ down(&map_mutex);
-+ for (i=0; i<NO_DEVICES; i++)
-+ unmap_one(&maps[i]);
-+ up(&map_mutex);
-+}
-+
-+
-+__module_param_call("", mphysmap, mphysmap_setup, NULL, NULL, 0600);
-+
-+module_init(mphysmap_init);
-+module_exit(mphysmap_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Jörn Engel <joern@wh.fh-wedelde>");
-+MODULE_DESCRIPTION("Generic configurable extensible MTD map driver");
---- linux-2.4.21/drivers/mtd/maps/netsc520.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/netsc520.c
-@@ -3,7 +3,7 @@
- * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com)
- * based on sc520cdp.c by Sysgo Real-Time Solutions GmbH
- *
-- * $Id: netsc520.c,v 1.5 2001/10/02 15:05:14 dwmw2 Exp $
-+ * $Id: netsc520.c,v 1.13 2004/11/28 09:40:40 dwmw2 Exp $
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
-@@ -27,6 +27,7 @@
- #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>
-@@ -50,95 +51,41 @@
- ** recoverable afterwards.
- */
-
--static __u8 netsc520_read8(struct map_info *map, unsigned long ofs)
--{
-- return readb(map->map_priv_1 + ofs);
--}
--
--static __u16 netsc520_read16(struct map_info *map, unsigned long ofs)
--{
-- return readw(map->map_priv_1 + ofs);
--}
--
--static __u32 netsc520_read32(struct map_info *map, unsigned long ofs)
--{
-- return readl(map->map_priv_1 + ofs);
--}
--
--static void netsc520_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
--}
--
--static void netsc520_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- writeb(d, map->map_priv_1 + adr);
--}
--
--static void netsc520_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- writew(d, map->map_priv_1 + adr);
--}
--
--static void netsc520_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- writel(d, map->map_priv_1 + adr);
--}
--
--static void netsc520_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio((void *)(map->map_priv_1 + to), from, len);
--}
--
- /* partition_info gives details on the logical partitions that the split the
- * single flash device into. If the size if zero we use up to the end of the
- * device. */
- static struct mtd_partition partition_info[]={
- {
-- name: "NetSc520 boot kernel",
-- offset: 0,
-- size: 0xc0000
-+ .name = "NetSc520 boot kernel",
-+ .offset = 0,
-+ .size = 0xc0000
- },
- {
-- name: "NetSc520 Low BIOS",
-- offset: 0xc0000,
-- size: 0x40000
-+ .name = "NetSc520 Low BIOS",
-+ .offset = 0xc0000,
-+ .size = 0x40000
- },
- {
-- name: "NetSc520 file system",
-- offset: 0x100000,
-- size: 0xe80000
-+ .name = "NetSc520 file system",
-+ .offset = 0x100000,
-+ .size = 0xe80000
- },
- {
-- name: "NetSc520 High BIOS",
-- offset: 0xf80000,
-- size: 0x80000
-+ .name = "NetSc520 High BIOS",
-+ .offset = 0xf80000,
-+ .size = 0x80000
- },
- };
- #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
-
--/*
-- * If no idea what is going on here. This is taken from the FlashFX stuff.
-- */
--#define ROMCS 1
--
--
- #define WINDOW_SIZE 0x00100000
- #define WINDOW_ADDR 0x00200000
-
- static struct map_info netsc520_map = {
-- name: "netsc520 Flash Bank",
-- size: WINDOW_SIZE,
-- buswidth: 4,
-- read8: netsc520_read8,
-- read16: netsc520_read16,
-- read32: netsc520_read32,
-- copy_from: netsc520_copy_from,
-- write8: netsc520_write8,
-- write16: netsc520_write16,
-- write32: netsc520_write32,
-- copy_to: netsc520_copy_to,
-- map_priv_2: WINDOW_ADDR
-+ .name = "netsc520 Flash Bank",
-+ .size = WINDOW_SIZE,
-+ .bankwidth = 4,
-+ .phys = WINDOW_ADDR,
- };
-
- #define NUM_FLASH_BANKS (sizeof(netsc520_map)/sizeof(struct map_info))
-@@ -147,13 +94,16 @@
-
- static int __init init_netsc520(void)
- {
-- printk(KERN_NOTICE "NetSc520 flash device: %lx at %lx\n", netsc520_map.size, netsc520_map.map_priv_2);
-- netsc520_map.map_priv_1 = (unsigned long)ioremap_nocache(netsc520_map.map_priv_2, netsc520_map.size);
-+ printk(KERN_NOTICE "NetSc520 flash device: 0x%lx at 0x%lx\n", netsc520_map.size, netsc520_map.phys);
-+ netsc520_map.virt = ioremap_nocache(netsc520_map.phys, netsc520_map.size);
-
-- if (!netsc520_map.map_priv_1) {
-+ if (!netsc520_map.virt) {
- printk("Failed to ioremap_nocache\n");
- return -EIO;
- }
-+
-+ simple_map_init(&netsc520_map);
-+
- mymtd = do_map_probe("cfi_probe", &netsc520_map);
- if(!mymtd)
- mymtd = do_map_probe("map_ram", &netsc520_map);
-@@ -161,11 +111,11 @@
- mymtd = do_map_probe("map_rom", &netsc520_map);
-
- if (!mymtd) {
-- iounmap((void *)netsc520_map.map_priv_1);
-+ iounmap(netsc520_map.virt);
- return -ENXIO;
- }
-
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
- add_mtd_partitions( mymtd, partition_info, NUM_PARTITIONS );
- return 0;
- }
-@@ -176,9 +126,9 @@
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- }
-- if (netsc520_map.map_priv_1) {
-- iounmap((void *)netsc520_map.map_priv_1);
-- netsc520_map.map_priv_1 = 0;
-+ if (netsc520_map.virt) {
-+ iounmap(netsc520_map.virt);
-+ netsc520_map.virt = NULL;
- }
- }
-
---- linux-2.4.21/drivers/mtd/maps/nettel.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/nettel.c
-@@ -6,7 +6,7 @@
- * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com)
- * (C) Copyright 2001-2002, SnapGear (www.snapgear.com)
- *
-- * $Id: nettel.c,v 1.1 2002/08/08 06:30:13 gerg Exp $
-+ * $Id: nettel.c,v 1.10 2005/01/05 17:11:29 dwmw2 Exp $
- */
-
- /****************************************************************************/
-@@ -59,128 +59,72 @@
-
- /****************************************************************************/
-
--static __u8 nettel_read8(struct map_info *map, unsigned long ofs)
--{
-- return(readb(map->map_priv_1 + ofs));
--}
--
--static __u16 nettel_read16(struct map_info *map, unsigned long ofs)
--{
-- return(readw(map->map_priv_1 + ofs));
--}
--
--static __u32 nettel_read32(struct map_info *map, unsigned long ofs)
--{
-- return(readl(map->map_priv_1 + ofs));
--}
--
--static void nettel_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--static void nettel_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- writeb(d, map->map_priv_1 + adr);
--}
--
--static void nettel_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- writew(d, map->map_priv_1 + adr);
--}
--
--static void nettel_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- writel(d, map->map_priv_1 + adr);
--}
--
--static void nettel_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
--
- /****************************************************************************/
-
- #ifdef CONFIG_MTD_CFI_INTELEXT
- static struct map_info nettel_intel_map = {
-- name: "SnapGear Intel",
-- size: 0,
-- buswidth: INTEL_BUSWIDTH,
-- read8: nettel_read8,
-- read16: nettel_read16,
-- read32: nettel_read32,
-- copy_from: nettel_copy_from,
-- write8: nettel_write8,
-- write16: nettel_write16,
-- write32: nettel_write32,
-- copy_to: nettel_copy_to
-+ .name = "SnapGear Intel",
-+ .size = 0,
-+ .bankwidth = INTEL_BUSWIDTH,
- };
-
- static struct mtd_partition nettel_intel_partitions[] = {
- {
-- name: "SnapGear kernel",
-- offset: 0,
-- size: 0x000e0000
-+ .name = "SnapGear kernel",
-+ .offset = 0,
-+ .size = 0x000e0000
- },
- {
-- name: "SnapGear filesystem",
-- offset: 0x00100000,
-+ .name = "SnapGear filesystem",
-+ .offset = 0x00100000,
- },
- {
-- name: "SnapGear config",
-- offset: 0x000e0000,
-- size: 0x00020000
-+ .name = "SnapGear config",
-+ .offset = 0x000e0000,
-+ .size = 0x00020000
- },
- {
-- name: "SnapGear Intel",
-- offset: 0
-+ .name = "SnapGear Intel",
-+ .offset = 0
- },
- {
-- name: "SnapGear BIOS Config",
-- offset: 0x007e0000,
-- size: 0x00020000
-+ .name = "SnapGear BIOS Config",
-+ .offset = 0x007e0000,
-+ .size = 0x00020000
- },
- {
-- name: "SnapGear BIOS",
-- offset: 0x007e0000,
-- size: 0x00020000
-+ .name = "SnapGear BIOS",
-+ .offset = 0x007e0000,
-+ .size = 0x00020000
- },
- };
- #endif
-
- static struct map_info nettel_amd_map = {
-- name: "SnapGear AMD",
-- size: AMD_WINDOW_MAXSIZE,
-- buswidth: AMD_BUSWIDTH,
-- read8: nettel_read8,
-- read16: nettel_read16,
-- read32: nettel_read32,
-- copy_from: nettel_copy_from,
-- write8: nettel_write8,
-- write16: nettel_write16,
-- write32: nettel_write32,
-- copy_to: nettel_copy_to
-+ .name = "SnapGear AMD",
-+ .size = AMD_WINDOW_MAXSIZE,
-+ .bankwidth = AMD_BUSWIDTH,
- };
-
- static struct mtd_partition nettel_amd_partitions[] = {
- {
-- name: "SnapGear BIOS config",
-- offset: 0x000e0000,
-- size: 0x00010000
-+ .name = "SnapGear BIOS config",
-+ .offset = 0x000e0000,
-+ .size = 0x00010000
- },
- {
-- name: "SnapGear BIOS",
-- offset: 0x000f0000,
-- size: 0x00010000
-+ .name = "SnapGear BIOS",
-+ .offset = 0x000f0000,
-+ .size = 0x00010000
- },
- {
-- name: "SnapGear AMD",
-- offset: 0
-+ .name = "SnapGear AMD",
-+ .offset = 0
- },
- {
-- name: "SnapGear high BIOS",
-- offset: 0x001f0000,
-- size: 0x00010000
-+ .name = "SnapGear high BIOS",
-+ .offset = 0x001f0000,
-+ .size = 0x00010000
- }
- };
-
-@@ -236,7 +180,7 @@
- if (mtd) {
- nettel_erase.mtd = mtd;
- nettel_erase.callback = nettel_erasecallback;
-- nettel_erase.callback = 0;
-+ nettel_erase.callback = NULL;
- nettel_erase.addr = 0;
- nettel_erase.len = mtd->size;
- nettel_erase.priv = (u_long) &wait_q;
-@@ -328,18 +272,19 @@
- *amdpar = SC520_PAR(SC520_PAR_BOOTCS, amdaddr, maxsize);
- __asm__ ("wbinvd");
-
-- nettel_amd_map.map_priv_1 = (unsigned long)
-- ioremap_nocache(amdaddr, maxsize);
-- if (!nettel_amd_map.map_priv_1) {
-+ nettel_amd_map.phys = amdaddr;
-+ nettel_amd_map.virt = ioremap_nocache(amdaddr, maxsize);
-+ if (!nettel_amd_map.virt) {
- printk("SNAPGEAR: failed to ioremap() BOOTCS\n");
- return(-EIO);
- }
-+ simple_map_init(&nettel_amd_map);
-
- if ((amd_mtd = do_map_probe("jedec_probe", &nettel_amd_map))) {
- printk(KERN_NOTICE "SNAPGEAR: AMD flash device size = %dK\n",
- amd_mtd->size>>10);
-
-- amd_mtd->module = THIS_MODULE;
-+ amd_mtd->owner = THIS_MODULE;
-
- /* The high BIOS partition is only present for 2MB units */
- num_amd_partitions = NUM_AMD_PARTITIONS;
-@@ -387,8 +332,8 @@
-
- /* Destroy useless AMD MTD mapping */
- amd_mtd = NULL;
-- iounmap((void *) nettel_amd_map.map_priv_1);
-- nettel_amd_map.map_priv_1 = (unsigned long) NULL;
-+ iounmap(nettel_amd_map.virt);
-+ nettel_amd_map.virt = NULL;
- #else
- /* Only AMD flash supported */
- return(-ENXIO);
-@@ -411,16 +356,17 @@
-
- /* Probe for the the size of the first Intel flash */
- nettel_intel_map.size = maxsize;
-- nettel_intel_map.map_priv_1 = (unsigned long)
-- ioremap_nocache(intel0addr, maxsize);
-- if (!nettel_intel_map.map_priv_1) {
-+ nettel_intel_map.phys = intel0addr;
-+ nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
-+ if (!nettel_intel_map.virt) {
- printk("SNAPGEAR: failed to ioremap() ROMCS1\n");
- return(-EIO);
- }
-+ simple_map_init(&nettel_intel_map);
-
- intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
-- if (! intel_mtd) {
-- iounmap((void *) nettel_intel_map.map_priv_1);
-+ if (!intel_mtd) {
-+ iounmap(nettel_intel_map.virt);
- return(-ENXIO);
- }
-
-@@ -441,19 +387,18 @@
- /* Delete the old map and probe again to do both chips */
- map_destroy(intel_mtd);
- intel_mtd = NULL;
-- iounmap((void *) nettel_intel_map.map_priv_1);
-+ iounmap(nettel_intel_map.virt);
-
- nettel_intel_map.size = maxsize;
-- nettel_intel_map.map_priv_1 = (unsigned long)
-- ioremap_nocache(intel0addr, maxsize);
-- if (!nettel_intel_map.map_priv_1) {
-+ nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
-+ if (!nettel_intel_map.virt) {
- printk("SNAPGEAR: failed to ioremap() ROMCS1/2\n");
- return(-EIO);
- }
-
- intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
- if (! intel_mtd) {
-- iounmap((void *) nettel_intel_map.map_priv_1);
-+ iounmap((void *) nettel_intel_map.virt);
- return(-ENXIO);
- }
-
-@@ -468,7 +413,7 @@
- printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %dK\n",
- (intel_mtd->size >> 10));
-
-- intel_mtd->module = THIS_MODULE;
-+ intel_mtd->owner = THIS_MODULE;
-
- #ifndef CONFIG_BLK_DEV_INITRD
- ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1);
-@@ -523,18 +468,18 @@
- del_mtd_partitions(amd_mtd);
- map_destroy(amd_mtd);
- }
-- if (nettel_amd_map.map_priv_1) {
-- iounmap((void *)nettel_amd_map.map_priv_1);
-- nettel_amd_map.map_priv_1 = 0;
-+ if (nettel_amd_map.virt) {
-+ iounmap(nettel_amd_map.virt);
-+ nettel_amd_map.virt = NULL;
- }
- #ifdef CONFIG_MTD_CFI_INTELEXT
- if (intel_mtd) {
- del_mtd_partitions(intel_mtd);
- map_destroy(intel_mtd);
- }
-- if (nettel_intel_map.map_priv_1) {
-- iounmap((void *)nettel_intel_map.map_priv_1);
-- nettel_intel_map.map_priv_1 = 0;
-+ if (nettel_intel_map.virt) {
-+ iounmap(nettel_intel_map.virt);
-+ nettel_intel_map.virt = 0;
- }
- #endif
- }
---- linux-2.4.21/drivers/mtd/maps/ocelot.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/ocelot.c
-@@ -1,5 +1,5 @@
- /*
-- * $Id: ocelot.c,v 1.6 2001/10/02 15:05:14 dwmw2 Exp $
-+ * $Id: ocelot.c,v 1.16 2005/01/05 18:05:13 dwmw2 Exp $
- *
- * Flash on Momenco Ocelot
- */
-@@ -7,6 +7,7 @@
- #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>
-@@ -20,47 +21,23 @@
- #define NVRAM_WINDOW_SIZE 0x00007FF0
- #define NVRAM_BUSWIDTH 1
-
--extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
--
- static unsigned int cacheflush = 0;
-
- static struct mtd_info *flash_mtd;
- static struct mtd_info *nvram_mtd;
-
--__u8 ocelot_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--void ocelot_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- cacheflush = 1;
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void ocelot_copy_from_cache(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- if (cacheflush) {
-- dma_cache_inv(map->map_priv_2, map->size);
-- cacheflush = 0;
-- }
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void ocelot_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-+static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
- {
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
-+ struct map_info *map = mtd->priv;
-+ size_t done = 0;
-
--void ocelot_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
- /* If we use memcpy, it does word-wide writes. Even though we told the
- GT64120A that it's an 8-bit wide region, word-wide writes don't work.
- We end up just writing the first byte of the four to all four bytes.
- So we have this loop instead */
-+ *retlen = len;
- while(len) {
-- __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to);
-+ __raw_writeb(*(unsigned char *) from, map->virt + to);
- from++;
- to++;
- len--;
-@@ -70,24 +47,21 @@
- static struct mtd_partition *parsed_parts;
-
- struct map_info ocelot_flash_map = {
-- name: "Ocelot boot flash",
-- size: FLASH_WINDOW_SIZE,
-- buswidth: FLASH_BUSWIDTH,
-- read8: ocelot_read8,
-- copy_from: ocelot_copy_from_cache,
-- write8: ocelot_write8,
-+ .name = "Ocelot boot flash",
-+ .size = FLASH_WINDOW_SIZE,
-+ .bankwidth = FLASH_BUSWIDTH,
-+ .phys = FLASH_WINDOW_ADDR,
- };
-
- struct map_info ocelot_nvram_map = {
-- name: "Ocelot NVRAM",
-- size: NVRAM_WINDOW_SIZE,
-- buswidth: NVRAM_BUSWIDTH,
-- read8: ocelot_read8,
-- copy_from: ocelot_copy_from,
-- write8: ocelot_write8,
-- copy_to: ocelot_copy_to
-+ .name = "Ocelot NVRAM",
-+ .size = NVRAM_WINDOW_SIZE,
-+ .bankwidth = NVRAM_BUSWIDTH,
-+ .phys = NVRAM_WINDOW_ADDR,
- };
-
-+static const char *probes[] = { "RedBoot", NULL };
-+
- static int __init init_ocelot_maps(void)
- {
- void *pld;
-@@ -107,12 +81,13 @@
- iounmap(pld);
-
- /* Now ioremap the NVRAM space */
-- ocelot_nvram_map.map_priv_1 = (unsigned long)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE);
-- if (!ocelot_nvram_map.map_priv_1) {
-+ ocelot_nvram_map.virt = ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE);
-+ if (!ocelot_nvram_map.virt) {
- printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n");
- return -EIO;
- }
-- // ocelot_nvram_map.map_priv_2 = ocelot_nvram_map.map_priv_1;
-+
-+ simple_map_init(&ocelot_nvram_map);
-
- /* And do the RAM probe on it to get an MTD device */
- nvram_mtd = do_map_probe("map_ram", &ocelot_nvram_map);
-@@ -120,22 +95,21 @@
- printk("NVRAM probe failed\n");
- goto fail_1;
- }
-- nvram_mtd->module = THIS_MODULE;
-+ nvram_mtd->owner = THIS_MODULE;
- nvram_mtd->erasesize = 16;
-+ /* Override the write() method */
-+ nvram_mtd->write = ocelot_ram_write;
-
- /* Now map the flash space */
-- ocelot_flash_map.map_priv_1 = (unsigned long)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE);
-- if (!ocelot_flash_map.map_priv_1) {
-+ ocelot_flash_map.virt = ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE);
-+ if (!ocelot_flash_map.virt) {
- printk(KERN_NOTICE "Failed to ioremap Ocelot flash space\n");
- goto fail_2;
- }
- /* Now the cached version */
-- ocelot_flash_map.map_priv_2 = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0);
-+ ocelot_flash_map.cached = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0);
-
-- if (!ocelot_flash_map.map_priv_2) {
-- /* Doesn't matter if it failed. Just use the uncached version */
-- ocelot_flash_map.map_priv_2 = ocelot_flash_map.map_priv_1;
-- }
-+ simple_map_init(&ocelot_flash_map);
-
- /* Only probe for flash if the write jumper is present */
- if (brd_status & 0x40) {
-@@ -155,10 +129,10 @@
-
- add_mtd_device(nvram_mtd);
-
-- flash_mtd->module = THIS_MODULE;
-- nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts);
-+ flash_mtd->owner = THIS_MODULE;
-+ nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0);
-
-- if (nr_parts)
-+ if (nr_parts > 0)
- add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
- else
- add_mtd_device(flash_mtd);
-@@ -166,14 +140,13 @@
- return 0;
-
- fail3:
-- iounmap((void *)ocelot_flash_map.map_priv_1);
-- if (ocelot_flash_map.map_priv_2 &&
-- ocelot_flash_map.map_priv_2 != ocelot_flash_map.map_priv_1)
-- iounmap((void *)ocelot_flash_map.map_priv_2);
-+ iounmap((void *)ocelot_flash_map.virt);
-+ if (ocelot_flash_map.cached)
-+ iounmap((void *)ocelot_flash_map.cached);
- fail_2:
- map_destroy(nvram_mtd);
- fail_1:
-- iounmap((void *)ocelot_nvram_map.map_priv_1);
-+ iounmap((void *)ocelot_nvram_map.virt);
-
- return -ENXIO;
- }
-@@ -182,16 +155,16 @@
- {
- del_mtd_device(nvram_mtd);
- map_destroy(nvram_mtd);
-- iounmap((void *)ocelot_nvram_map.map_priv_1);
-+ iounmap((void *)ocelot_nvram_map.virt);
-
- if (parsed_parts)
- del_mtd_partitions(flash_mtd);
- else
- del_mtd_device(flash_mtd);
- map_destroy(flash_mtd);
-- iounmap((void *)ocelot_flash_map.map_priv_1);
-- if (ocelot_flash_map.map_priv_2 != ocelot_flash_map.map_priv_1)
-- iounmap((void *)ocelot_flash_map.map_priv_2);
-+ iounmap((void *)ocelot_flash_map.virt);
-+ if (ocelot_flash_map.cached)
-+ iounmap((void *)ocelot_flash_map.cached);
- }
-
- module_init(init_ocelot_maps);
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/ocotea.c
-@@ -0,0 +1,154 @@
-+/*
-+ * Mapping for Ocotea user flash
-+ *
-+ * Matt Porter <mporter@kernel.crashing.org>
-+ *
-+ * Copyright 2002-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 as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <asm/io.h>
-+#include <asm/ibm44x.h>
-+#include <platforms/4xx/ocotea.h>
-+
-+static struct mtd_info *flash;
-+
-+static struct map_info ocotea_small_map = {
-+ .name = "Ocotea small flash",
-+ .size = OCOTEA_SMALL_FLASH_SIZE,
-+ .buswidth = 1,
-+};
-+
-+static struct map_info ocotea_large_map = {
-+ .name = "Ocotea large flash",
-+ .size = OCOTEA_LARGE_FLASH_SIZE,
-+ .buswidth = 1,
-+};
-+
-+static struct mtd_partition ocotea_small_partitions[] = {
-+ {
-+ .name = "pibs",
-+ .offset = 0x0,
-+ .size = 0x100000,
-+ }
-+};
-+
-+static struct mtd_partition ocotea_large_partitions[] = {
-+ {
-+ .name = "fs",
-+ .offset = 0,
-+ .size = 0x300000,
-+ },
-+ {
-+ .name = "firmware",
-+ .offset = 0x300000,
-+ .size = 0x100000,
-+ }
-+};
-+
-+#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
-+
-+int __init init_ocotea(void)
-+{
-+ u8 fpga0_reg;
-+ u8 *fpga0_adr;
-+ unsigned long long small_flash_base, large_flash_base;
-+
-+ fpga0_adr = ioremap64(OCOTEA_FPGA_ADDR, 16);
-+ if (!fpga0_adr)
-+ return -ENOMEM;
-+
-+ fpga0_reg = readb((unsigned long)fpga0_adr);
-+ iounmap(fpga0_adr);
-+
-+ if (OCOTEA_BOOT_LARGE_FLASH(fpga0_reg)) {
-+ small_flash_base = OCOTEA_SMALL_FLASH_HIGH;
-+ large_flash_base = OCOTEA_LARGE_FLASH_LOW;
-+ }
-+ else {
-+ small_flash_base = OCOTEA_SMALL_FLASH_LOW;
-+ large_flash_base = OCOTEA_LARGE_FLASH_HIGH;
-+ }
-+
-+ ocotea_small_map.phys = small_flash_base;
-+ ocotea_small_map.virt = ioremap64(small_flash_base,
-+ ocotea_small_map.size);
-+
-+ if (!ocotea_small_map.virt) {
-+ printk("Failed to ioremap flash\n");
-+ return -EIO;
-+ }
-+
-+ simple_map_init(&ocotea_small_map);
-+
-+ flash = do_map_probe("map_rom", &ocotea_small_map);
-+ if (flash) {
-+ flash->owner = THIS_MODULE;
-+ add_mtd_partitions(flash, ocotea_small_partitions,
-+ NB_OF(ocotea_small_partitions));
-+ } else {
-+ printk("map probe failed for flash\n");
-+ return -ENXIO;
-+ }
-+
-+ ocotea_large_map.phys = large_flash_base;
-+ ocotea_large_map.virt = ioremap64(large_flash_base,
-+ ocotea_large_map.size);
-+
-+ if (!ocotea_large_map.virt) {
-+ printk("Failed to ioremap flash\n");
-+ return -EIO;
-+ }
-+
-+ simple_map_init(&ocotea_large_map);
-+
-+ flash = do_map_probe("cfi_probe", &ocotea_large_map);
-+ if (flash) {
-+ flash->owner = THIS_MODULE;
-+ add_mtd_partitions(flash, ocotea_large_partitions,
-+ NB_OF(ocotea_large_partitions));
-+ } else {
-+ printk("map probe failed for flash\n");
-+ return -ENXIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static void __exit cleanup_ocotea(void)
-+{
-+ if (flash) {
-+ del_mtd_partitions(flash);
-+ map_destroy(flash);
-+ }
-+
-+ if (ocotea_small_map.virt) {
-+ iounmap((void *)ocotea_small_map.virt);
-+ ocotea_small_map.virt = 0;
-+ }
-+
-+ if (ocotea_large_map.virt) {
-+ iounmap((void *)ocotea_large_map.virt);
-+ ocotea_large_map.virt = 0;
-+ }
-+}
-+
-+module_init(init_ocotea);
-+module_exit(cleanup_ocotea);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>");
-+MODULE_DESCRIPTION("MTD map and partitions for IBM 440GX Ocotea boards");
---- linux-2.4.21/drivers/mtd/maps/octagon-5066.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/octagon-5066.c
-@@ -1,4 +1,4 @@
--// $Id: octagon-5066.c,v 1.20 2003/01/07 17:21:55 dwmw2 Exp $
-+// $Id: octagon-5066.c,v 1.27 2005/01/12 22:34:35 gleixner Exp $
- /* ######################################################################
-
- Octagon 5066 MTD Driver.
-@@ -31,6 +31,7 @@
- #include <asm/io.h>
-
- #include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
-
- #define WINDOW_START 0xe8000
- #define WINDOW_LENGTH 0x8000
-@@ -40,7 +41,7 @@
-
- static volatile char page_n_dev = 0;
- static unsigned long iomapadr;
--static spinlock_t oct5066_spin = SPIN_LOCK_UNLOCKED;
-+static DEFINE_SPINLOCK(oct5066_spin);
-
- /*
- * We use map_priv_1 to identify which device we are.
-@@ -61,32 +62,12 @@
- }
-
-
--static __u8 oct5066_read8(struct map_info *map, unsigned long ofs)
--{
-- __u8 ret;
-- spin_lock(&oct5066_spin);
-- oct5066_page(map, ofs);
-- ret = readb(iomapadr + (ofs & WINDOW_MASK));
-- spin_unlock(&oct5066_spin);
-- return ret;
--}
--
--static __u16 oct5066_read16(struct map_info *map, unsigned long ofs)
--{
-- __u16 ret;
-- spin_lock(&oct5066_spin);
-- oct5066_page(map, ofs);
-- ret = readw(iomapadr + (ofs & WINDOW_MASK));
-- spin_unlock(&oct5066_spin);
-- return ret;
--}
--
--static __u32 oct5066_read32(struct map_info *map, unsigned long ofs)
-+static map_word oct5066_read8(struct map_info *map, unsigned long ofs)
- {
-- __u32 ret;
-+ map_word ret;
- spin_lock(&oct5066_spin);
- oct5066_page(map, ofs);
-- ret = readl(iomapadr + (ofs & WINDOW_MASK));
-+ ret.x[0] = readb(iomapadr + (ofs & WINDOW_MASK));
- spin_unlock(&oct5066_spin);
- return ret;
- }
-@@ -108,27 +89,11 @@
- }
- }
-
--static void oct5066_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- spin_lock(&oct5066_spin);
-- oct5066_page(map, adr);
-- writeb(d, iomapadr + (adr & WINDOW_MASK));
-- spin_unlock(&oct5066_spin);
--}
--
--static void oct5066_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- spin_lock(&oct5066_spin);
-- oct5066_page(map, adr);
-- writew(d, iomapadr + (adr & WINDOW_MASK));
-- spin_unlock(&oct5066_spin);
--}
--
--static void oct5066_write32(struct map_info *map, __u32 d, unsigned long adr)
-+static void oct5066_write8(struct map_info *map, map_word d, unsigned long adr)
- {
- spin_lock(&oct5066_spin);
- oct5066_page(map, adr);
-- writel(d, iomapadr + (adr & WINDOW_MASK));
-+ writeb(d.x[0], iomapadr + (adr & WINDOW_MASK));
- spin_unlock(&oct5066_spin);
- }
-
-@@ -151,32 +116,26 @@
-
- static struct map_info oct5066_map[2] = {
- {
-- name: "Octagon 5066 Socket",
-- size: 512 * 1024,
-- buswidth: 1,
-- read8: oct5066_read8,
-- read16: oct5066_read16,
-- read32: oct5066_read32,
-- copy_from: oct5066_copy_from,
-- write8: oct5066_write8,
-- write16: oct5066_write16,
-- write32: oct5066_write32,
-- copy_to: oct5066_copy_to,
-- map_priv_1: 1<<6
-+ .name = "Octagon 5066 Socket",
-+ .phys = NO_XIP,
-+ .size = 512 * 1024,
-+ .bankwidth = 1,
-+ .read = oct5066_read8,
-+ .copy_from = oct5066_copy_from,
-+ .write = oct5066_write8,
-+ .copy_to = oct5066_copy_to,
-+ .map_priv_1 = 1<<6
- },
- {
-- name: "Octagon 5066 Internal Flash",
-- size: 2 * 1024 * 1024,
-- buswidth: 1,
-- read8: oct5066_read8,
-- read16: oct5066_read16,
-- read32: oct5066_read32,
-- copy_from: oct5066_copy_from,
-- write8: oct5066_write8,
-- write16: oct5066_write16,
-- write32: oct5066_write32,
-- copy_to: oct5066_copy_to,
-- map_priv_1: 2<<6
-+ .name = "Octagon 5066 Internal Flash",
-+ .phys = NO_XIP,
-+ .size = 2 * 1024 * 1024,
-+ .bankwidth = 1,
-+ .read = oct5066_read8,
-+ .copy_from = oct5066_copy_from,
-+ .write = oct5066_write8,
-+ .copy_to = oct5066_copy_to,
-+ .map_priv_1 = 2<<6
- }
- };
-
-@@ -262,7 +221,7 @@
- if (!oct5066_mtd[i])
- oct5066_mtd[i] = do_map_probe("map_rom", &oct5066_map[i]);
- if (oct5066_mtd[i]) {
-- oct5066_mtd[i]->module = THIS_MODULE;
-+ oct5066_mtd[i]->owner = THIS_MODULE;
- add_mtd_device(oct5066_mtd[i]);
- }
- }
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/omap-toto-flash.c
-@@ -0,0 +1,137 @@
-+/*
-+ * NOR Flash memory access on TI Toto board
-+ *
-+ * jzhang@ti.com (C) 2003 Texas Instruments.
-+ *
-+ * (C) 2002 MontVista Software, Inc.
-+ *
-+ * $Id: omap-toto-flash.c,v 1.3 2004/09/16 23:27:13 gleixner Exp $
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+
-+#include <linux/errno.h>
-+#include <linux/init.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/io.h>
-+
-+
-+#ifndef CONFIG_ARCH_OMAP
-+#error This is for OMAP architecture only
-+#endif
-+
-+//these lines need be moved to a hardware header file
-+#define OMAP_TOTO_FLASH_BASE 0xd8000000
-+#define OMAP_TOTO_FLASH_SIZE 0x80000
-+
-+static struct map_info omap_toto_map_flash = {
-+ .name = "OMAP Toto flash",
-+ .bankwidth = 2,
-+ .virt = (void __iomem *)OMAP_TOTO_FLASH_BASE,
-+};
-+
-+
-+static struct mtd_partition toto_flash_partitions[] = {
-+ {
-+ .name = "BootLoader",
-+ .size = 0x00040000, /* hopefully u-boot will stay 128k + 128*/
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
-+ }, {
-+ .name = "ReservedSpace",
-+ .size = 0x00030000,
-+ .offset = MTDPART_OFS_APPEND,
-+ //mask_flags: MTD_WRITEABLE, /* force read-only */
-+ }, {
-+ .name = "EnvArea", /* bottom 64KiB for env vars */
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
-+ }
-+};
-+
-+static struct mtd_partition *parsed_parts;
-+
-+static struct mtd_info *flash_mtd;
-+
-+static int __init init_flash (void)
-+{
-+
-+ struct mtd_partition *parts;
-+ int nb_parts = 0;
-+ int parsed_nr_parts = 0;
-+ const char *part_type;
-+
-+ /*
-+ * Static partition definition selection
-+ */
-+ part_type = "static";
-+
-+ parts = toto_flash_partitions;
-+ nb_parts = ARRAY_SIZE(toto_flash_partitions);
-+ omap_toto_map_flash.size = OMAP_TOTO_FLASH_SIZE;
-+ omap_toto_map_flash.phys = virt_to_phys(OMAP_TOTO_FLASH_BASE);
-+
-+ simple_map_init(&omap_toto_map_flash);
-+ /*
-+ * Now let's probe for the actual flash. Do it here since
-+ * specific machine settings might have been set above.
-+ */
-+ printk(KERN_NOTICE "OMAP toto flash: probing %d-bit flash bus\n",
-+ omap_toto_map_flash.bankwidth*8);
-+ flash_mtd = do_map_probe("jedec_probe", &omap_toto_map_flash);
-+ if (!flash_mtd)
-+ return -ENXIO;
-+
-+ if (parsed_nr_parts > 0) {
-+ parts = parsed_parts;
-+ nb_parts = parsed_nr_parts;
-+ }
-+
-+ if (nb_parts == 0) {
-+ printk(KERN_NOTICE "OMAP toto flash: no partition info available,"
-+ "registering whole flash at once\n");
-+ if (add_mtd_device(flash_mtd)){
-+ return -ENXIO;
-+ }
-+ } else {
-+ printk(KERN_NOTICE "Using %s partition definition\n",
-+ part_type);
-+ return add_mtd_partitions(flash_mtd, parts, nb_parts);
-+ }
-+ return 0;
-+}
-+
-+int __init omap_toto_mtd_init(void)
-+{
-+ int status;
-+
-+ if (status = init_flash()) {
-+ printk(KERN_ERR "OMAP Toto Flash: unable to init map for toto flash\n");
-+ }
-+ return status;
-+}
-+
-+static void __exit omap_toto_mtd_cleanup(void)
-+{
-+ if (flash_mtd) {
-+ del_mtd_partitions(flash_mtd);
-+ map_destroy(flash_mtd);
-+ if (parsed_parts)
-+ kfree(parsed_parts);
-+ }
-+}
-+
-+module_init(omap_toto_mtd_init);
-+module_exit(omap_toto_mtd_cleanup);
-+
-+MODULE_AUTHOR("Jian Zhang");
-+MODULE_DESCRIPTION("OMAP Toto board map driver");
-+MODULE_LICENSE("GPL");
---- linux-2.4.21/drivers/mtd/maps/pci.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/pci.c
-@@ -7,7 +7,7 @@
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
-- * $Id: pci.c,v 1.2 2003/01/24 13:11:43 dwmw2 Exp $
-+ * $Id: pci.c,v 1.9 2004/11/28 09:40:40 dwmw2 Exp $
- *
- * Generic PCI memory map driver. We support the following boards:
- * - Intel IQ80310 ATU.
-@@ -33,12 +33,80 @@
-
- struct map_pci_info {
- struct map_info map;
-- void *base;
-+ void __iomem *base;
- void (*exit)(struct pci_dev *dev, struct map_pci_info *map);
- unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs);
- struct pci_dev *dev;
- };
-
-+static map_word mtd_pci_read8(struct map_info *_map, unsigned long ofs)
-+{
-+ struct map_pci_info *map = (struct map_pci_info *)_map;
-+ map_word val;
-+ val.x[0]= readb(map->base + map->translate(map, ofs));
-+// printk("read8 : %08lx => %02x\n", ofs, val.x[0]);
-+ return val;
-+}
-+
-+#if 0
-+static map_word mtd_pci_read16(struct map_info *_map, unsigned long ofs)
-+{
-+ struct map_pci_info *map = (struct map_pci_info *)_map;
-+ map_word val;
-+ val.x[0] = readw(map->base + map->translate(map, ofs));
-+// printk("read16: %08lx => %04x\n", ofs, val.x[0]);
-+ return val;
-+}
-+#endif
-+static map_word mtd_pci_read32(struct map_info *_map, unsigned long ofs)
-+{
-+ struct map_pci_info *map = (struct map_pci_info *)_map;
-+ map_word val;
-+ val.x[0] = readl(map->base + map->translate(map, ofs));
-+// printk("read32: %08lx => %08x\n", ofs, val.x[0]);
-+ return val;
-+}
-+
-+static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len)
-+{
-+ struct map_pci_info *map = (struct map_pci_info *)_map;
-+ memcpy_fromio(to, map->base + map->translate(map, from), len);
-+}
-+
-+static void mtd_pci_write8(struct map_info *_map, map_word val, unsigned long ofs)
-+{
-+ struct map_pci_info *map = (struct map_pci_info *)_map;
-+// printk("write8 : %08lx <= %02x\n", ofs, val.x[0]);
-+ writeb(val.x[0], map->base + map->translate(map, ofs));
-+}
-+
-+#if 0
-+static void mtd_pci_write16(struct map_info *_map, map_word val, unsigned long ofs)
-+{
-+ struct map_pci_info *map = (struct map_pci_info *)_map;
-+// printk("write16: %08lx <= %04x\n", ofs, val.x[0]);
-+ writew(val.x[0], map->base + map->translate(map, ofs));
-+}
-+#endif
-+static void mtd_pci_write32(struct map_info *_map, map_word val, unsigned long ofs)
-+{
-+ struct map_pci_info *map = (struct map_pci_info *)_map;
-+// printk("write32: %08lx <= %08x\n", ofs, val.x[0]);
-+ writel(val.x[0], map->base + map->translate(map, ofs));
-+}
-+
-+static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len)
-+{
-+ struct map_pci_info *map = (struct map_pci_info *)_map;
-+ memcpy_toio(map->base + map->translate(map, to), from, len);
-+}
-+
-+static struct map_info mtd_pci_map = {
-+ .phys = NO_XIP,
-+ .copy_from = mtd_pci_copyfrom,
-+ .copy_to = mtd_pci_copyto,
-+};
-+
- /*
- * Intel IOP80310 Flash driver
- */
-@@ -48,7 +116,10 @@
- {
- u32 win_base;
-
-- map->map.buswidth = 1;
-+ map->map.bankwidth = 1;
-+ map->map.read = mtd_pci_read8,
-+ map->map.write = mtd_pci_write8,
-+
- map->map.size = 0x00800000;
- map->base = ioremap_nocache(pci_resource_start(dev, 0),
- pci_resource_len(dev, 0));
-@@ -72,7 +143,7 @@
- intel_iq80310_exit(struct pci_dev *dev, struct map_pci_info *map)
- {
- if (map->base)
-- iounmap((void *)map->base);
-+ iounmap(map->base);
- pci_write_config_dword(dev, 0x44, map->map.map_priv_2);
- }
-
-@@ -98,10 +169,10 @@
- }
-
- static struct mtd_pci_info intel_iq80310_info = {
-- init: intel_iq80310_init,
-- exit: intel_iq80310_exit,
-- translate: intel_iq80310_translate,
-- map_name: "cfi_probe",
-+ .init = intel_iq80310_init,
-+ .exit = intel_iq80310_exit,
-+ .translate = intel_iq80310_translate,
-+ .map_name = "cfi_probe",
- };
-
- /*
-@@ -140,14 +211,16 @@
- pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val);
- val |= PCI_ROM_ADDRESS_ENABLE;
- pci_write_config_dword(dev, PCI_ROM_ADDRESS, val);
-- printk("%s: enabling expansion ROM\n", dev->slot_name);
-+ printk("%s: enabling expansion ROM\n", pci_name(dev));
- }
- }
-
- if (!len || !base)
- return -ENXIO;
-
-- map->map.buswidth = 4;
-+ map->map.bankwidth = 4;
-+ map->map.read = mtd_pci_read32,
-+ map->map.write = mtd_pci_write32,
- map->map.size = len;
- map->base = ioremap_nocache(base, len);
-
-@@ -163,7 +236,7 @@
- u32 val;
-
- if (map->base)
-- iounmap((void *)map->base);
-+ iounmap(map->base);
-
- /*
- * We need to undo the PCI BAR2/PCI ROM BAR address alteration.
-@@ -181,34 +254,32 @@
- }
-
- static struct mtd_pci_info intel_dc21285_info = {
-- init: intel_dc21285_init,
-- exit: intel_dc21285_exit,
-- translate: intel_dc21285_translate,
-- map_name: "jedec_probe",
-+ .init = intel_dc21285_init,
-+ .exit = intel_dc21285_exit,
-+ .translate = intel_dc21285_translate,
-+ .map_name = "jedec_probe",
- };
-
- /*
- * PCI device ID table
- */
-
--static struct pci_device_id mtd_pci_ids[] __devinitdata = {
-+static struct pci_device_id mtd_pci_ids[] = {
- {
-- vendor: PCI_VENDOR_ID_INTEL,
-- device: 0x530d,
-- subvendor: PCI_ANY_ID,
-- subdevice: PCI_ANY_ID,
-- class: PCI_CLASS_MEMORY_OTHER << 8,
-- class_mask: 0xffff00,
-- driver_data: (unsigned long)&intel_iq80310_info,
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = 0x530d,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .class = PCI_CLASS_MEMORY_OTHER << 8,
-+ .class_mask = 0xffff00,
-+ .driver_data = (unsigned long)&intel_iq80310_info,
- },
- {
-- vendor: PCI_VENDOR_ID_DEC,
-- device: PCI_DEVICE_ID_DEC_21285,
-- subvendor: 0, /* DC21285 defaults to 0 on reset */
-- subdevice: 0, /* DC21285 defaults to 0 on reset */
-- class: 0,
-- class_mask: 0,
-- driver_data: (unsigned long)&intel_dc21285_info,
-+ .vendor = PCI_VENDOR_ID_DEC,
-+ .device = PCI_DEVICE_ID_DEC_21285,
-+ .subvendor = 0, /* DC21285 defaults to 0 on reset */
-+ .subdevice = 0, /* DC21285 defaults to 0 on reset */
-+ .driver_data = (unsigned long)&intel_dc21285_info,
- },
- { 0, }
- };
-@@ -217,74 +288,6 @@
- * Generic code follows.
- */
-
--static u8 mtd_pci_read8(struct map_info *_map, unsigned long ofs)
--{
-- struct map_pci_info *map = (struct map_pci_info *)_map;
-- u8 val = readb(map->base + map->translate(map, ofs));
--// printk("read8 : %08lx => %02x\n", ofs, val);
-- return val;
--}
--
--static u16 mtd_pci_read16(struct map_info *_map, unsigned long ofs)
--{
-- struct map_pci_info *map = (struct map_pci_info *)_map;
-- u16 val = readw(map->base + map->translate(map, ofs));
--// printk("read16: %08lx => %04x\n", ofs, val);
-- return val;
--}
--
--static u32 mtd_pci_read32(struct map_info *_map, unsigned long ofs)
--{
-- struct map_pci_info *map = (struct map_pci_info *)_map;
-- u32 val = readl(map->base + map->translate(map, ofs));
--// printk("read32: %08lx => %08x\n", ofs, val);
-- return val;
--}
--
--static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len)
--{
-- struct map_pci_info *map = (struct map_pci_info *)_map;
-- memcpy_fromio(to, map->base + map->translate(map, from), len);
--}
--
--static void mtd_pci_write8(struct map_info *_map, u8 val, unsigned long ofs)
--{
-- struct map_pci_info *map = (struct map_pci_info *)_map;
--// printk("write8 : %08lx <= %02x\n", ofs, val);
-- writeb(val, map->base + map->translate(map, ofs));
--}
--
--static void mtd_pci_write16(struct map_info *_map, u16 val, unsigned long ofs)
--{
-- struct map_pci_info *map = (struct map_pci_info *)_map;
--// printk("write16: %08lx <= %04x\n", ofs, val);
-- writew(val, map->base + map->translate(map, ofs));
--}
--
--static void mtd_pci_write32(struct map_info *_map, u32 val, unsigned long ofs)
--{
-- struct map_pci_info *map = (struct map_pci_info *)_map;
--// printk("write32: %08lx <= %08x\n", ofs, val);
-- writel(val, map->base + map->translate(map, ofs));
--}
--
--static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len)
--{
-- struct map_pci_info *map = (struct map_pci_info *)_map;
-- memcpy_toio(map->base + map->translate(map, to), from, len);
--}
--
--static struct map_info mtd_pci_map = {
-- read8: mtd_pci_read8,
-- read16: mtd_pci_read16,
-- read32: mtd_pci_read32,
-- copy_from: mtd_pci_copyfrom,
-- write8: mtd_pci_write8,
-- write16: mtd_pci_write16,
-- write32: mtd_pci_write32,
-- copy_to: mtd_pci_copyto,
--};
--
- static int __devinit
- mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
- {
-@@ -307,7 +310,7 @@
- goto release;
-
- map->map = mtd_pci_map;
-- map->map.name = dev->slot_name;
-+ map->map.name = pci_name(dev);
- map->dev = dev;
- map->exit = info->exit;
- map->translate = info->translate;
-@@ -322,7 +325,7 @@
- if (!mtd)
- goto release;
-
-- mtd->module = THIS_MODULE;
-+ mtd->owner = THIS_MODULE;
- add_mtd_device(mtd);
-
- pci_set_drvdata(dev, mtd);
-@@ -359,10 +362,10 @@
- }
-
- static struct pci_driver mtd_pci_driver = {
-- name: "MTD PCI",
-- probe: mtd_pci_probe,
-- remove: __devexit_p(mtd_pci_remove),
-- id_table: mtd_pci_ids,
-+ .name = "MTD PCI",
-+ .probe = mtd_pci_probe,
-+ .remove = __devexit_p(mtd_pci_remove),
-+ .id_table = mtd_pci_ids,
- };
-
- static int __init mtd_pci_maps_init(void)
---- linux-2.4.21/drivers/mtd/maps/pcmciamtd.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/pcmciamtd.c
-@@ -1,5 +1,5 @@
- /*
-- * $Id: pcmciamtd.c,v 1.39 2003/01/06 17:51:38 spse Exp $
-+ * $Id: pcmciamtd.c,v 1.51 2004/07/12 22:38:29 dwmw2 Exp $
- *
- * pcmciamtd.c - MTD driver for PCMCIA flash memory cards
- *
-@@ -14,6 +14,7 @@
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <linux/timer.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <asm/system.h>
-
-@@ -24,6 +25,7 @@
- #include <pcmcia/ds.h>
-
- #include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
-
- #ifdef CONFIG_MTD_DEBUG
- static int debug = CONFIG_MTD_DEBUG_VERBOSE;
-@@ -47,7 +49,7 @@
-
-
- #define DRIVER_DESC "PCMCIA Flash memory card driver"
--#define DRIVER_VERSION "$Revision: 1.39 $"
-+#define DRIVER_VERSION "$Revision: 1.51 $"
-
- /* Size of the PCMCIA address space: 26 bits = 64 MB */
- #define MAX_PCMCIA_ADDR 0x4000000
-@@ -71,7 +73,7 @@
- /* Module parameters */
-
- /* 2 = do 16-bit transfers, 1 = do 8-bit transfers */
--static int buswidth = 2;
-+static int bankwidth = 2;
-
- /* Speed of memory accesses, in ns */
- static int mem_speed;
-@@ -91,12 +93,12 @@
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
- MODULE_DESCRIPTION(DRIVER_DESC);
--MODULE_PARM(buswidth, "i");
--MODULE_PARM_DESC(buswidth, "Set buswidth (1=8 bit, 2=16 bit, default=2)");
-+MODULE_PARM(bankwidth, "i");
-+MODULE_PARM_DESC(bankwidth, "Set bankwidth (1=8 bit, 2=16 bit, default=2)");
- MODULE_PARM(mem_speed, "i");
- MODULE_PARM_DESC(mem_speed, "Set memory access speed in ns");
- MODULE_PARM(force_size, "i");
--MODULE_PARM_DESC(force_size, "Force size of card in MB (1-64)");
-+MODULE_PARM_DESC(force_size, "Force size of card in MiB (1-64)");
- MODULE_PARM(setvpp, "i");
- MODULE_PARM_DESC(setvpp, "Set Vpp (0=Never, 1=On writes, 2=Always on, default=0)");
- MODULE_PARM(vpp, "i");
-@@ -105,16 +107,7 @@
- MODULE_PARM_DESC(mem_type, "Set Memory type (0=Flash, 1=RAM, 2=ROM, default=0)");
-
-
--
--static inline void cs_error(client_handle_t handle, int func, int ret)
--{
-- error_info_t err = { func, ret };
-- CardServices(ReportError, handle, &err);
--}
--
--
- /* read/write{8,16} copy_{from,to} routines with window remapping to access whole card */
--
- static caddr_t remap_window(struct map_info *map, unsigned long to)
- {
- struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
-@@ -132,7 +125,7 @@
- DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x",
- dev->offset, mrq.CardOffset);
- mrq.Page = 0;
-- if( (ret = CardServices(MapMemPage, win, &mrq)) != CS_SUCCESS) {
-+ if( (ret = pcmcia_map_mem_page(win, &mrq)) != CS_SUCCESS) {
- cs_error(dev->link.handle, MapMemPage, ret);
- return NULL;
- }
-@@ -142,32 +135,32 @@
- }
-
-
--static u8 pcmcia_read8_remap(struct map_info *map, unsigned long ofs)
-+static map_word pcmcia_read8_remap(struct map_info *map, unsigned long ofs)
- {
- caddr_t addr;
-- u8 d;
-+ map_word d = {{0}};
-
- addr = remap_window(map, ofs);
- if(!addr)
-- return 0;
-+ return d;
-
-- d = readb(addr);
-- DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, addr, d);
-+ d.x[0] = readb(addr);
-+ DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, addr, d.x[0]);
- return d;
- }
-
-
--static u16 pcmcia_read16_remap(struct map_info *map, unsigned long ofs)
-+static map_word pcmcia_read16_remap(struct map_info *map, unsigned long ofs)
- {
- caddr_t addr;
-- u16 d;
-+ map_word d = {{0}};
-
- addr = remap_window(map, ofs);
- if(!addr)
-- return 0;
-+ return d;
-
-- d = readw(addr);
-- DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, addr, d);
-+ d.x[0] = readw(addr);
-+ DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, addr, d.x[0]);
- return d;
- }
-
-@@ -198,26 +191,26 @@
- }
-
-
--static void pcmcia_write8_remap(struct map_info *map, u8 d, unsigned long adr)
-+static void pcmcia_write8_remap(struct map_info *map, map_word d, unsigned long adr)
- {
- caddr_t addr = remap_window(map, adr);
-
- if(!addr)
- return;
-
-- DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02x", adr, addr, d);
-- writeb(d, addr);
-+ DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02x", adr, addr, d.x[0]);
-+ writeb(d.x[0], addr);
- }
-
-
--static void pcmcia_write16_remap(struct map_info *map, u16 d, unsigned long adr)
-+static void pcmcia_write16_remap(struct map_info *map, map_word d, unsigned long adr)
- {
- caddr_t addr = remap_window(map, adr);
- if(!addr)
- return;
-
-- DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04x", adr, addr, d);
-- writew(d, addr);
-+ DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04x", adr, addr, d.x[0]);
-+ writew(d.x[0], addr);
- }
-
-
-@@ -251,30 +244,30 @@
-
- #define DEV_REMOVED(x) (!(*(u_int *)x->map_priv_1 & DEV_PRESENT))
-
--static u8 pcmcia_read8(struct map_info *map, unsigned long ofs)
-+static map_word pcmcia_read8(struct map_info *map, unsigned long ofs)
- {
- caddr_t win_base = (caddr_t)map->map_priv_2;
-- u8 d;
-+ map_word d = {{0}};
-
- if(DEV_REMOVED(map))
-- return 0;
-+ return d;
-
-- d = readb(win_base + ofs);
-- DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, win_base + ofs, d);
-+ d.x[0] = readb(win_base + ofs);
-+ DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, win_base + ofs, d.x[0]);
- return d;
- }
-
-
--static u16 pcmcia_read16(struct map_info *map, unsigned long ofs)
-+static map_word pcmcia_read16(struct map_info *map, unsigned long ofs)
- {
- caddr_t win_base = (caddr_t)map->map_priv_2;
-- u16 d;
-+ map_word d = {{0}};
-
- if(DEV_REMOVED(map))
-- return 0;
-+ return d;
-
-- d = readw(win_base + ofs);
-- DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, win_base + ofs, d);
-+ d.x[0] = readw(win_base + ofs);
-+ DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, win_base + ofs, d.x[0]);
- return d;
- }
-
-@@ -339,7 +332,7 @@
- mod.Vpp1 = mod.Vpp2 = on ? dev->vpp : 0;
-
- DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp);
-- ret = CardServices(ModifyConfiguration, link->handle, &mod);
-+ ret = pcmcia_modify_configuration(link->handle, &mod);
- if(ret != CS_SUCCESS) {
- cs_error(link->handle, ModifyConfiguration, ret);
- }
-@@ -351,9 +344,8 @@
- * still open, this will be postponed until it is closed.
- */
-
--static void pcmciamtd_release(u_long arg)
-+static void pcmciamtd_release(dev_link_t *link)
- {
-- dev_link_t *link = (dev_link_t *)arg;
- struct pcmciamtd_dev *dev = link->priv;
-
- DEBUG(3, "link = 0x%p", link);
-@@ -363,9 +355,9 @@
- iounmap(dev->win_base);
- dev->win_base = NULL;
- }
-- CardServices(ReleaseWindow, link->win);
-+ pcmcia_release_window(link->win);
- }
-- CardServices(ReleaseConfiguration, link->handle);
-+ pcmcia_release_configuration(link->handle);
- link->state &= ~DEV_CONFIG;
- }
-
-@@ -383,14 +375,14 @@
- tuple.TupleOffset = 0;
- tuple.DesiredTuple = RETURN_FIRST_TUPLE;
-
-- rc = CardServices(GetFirstTuple, link->handle, &tuple);
-+ rc = pcmcia_get_first_tuple(link->handle, &tuple);
- while(rc == CS_SUCCESS) {
-- rc = CardServices(GetTupleData, link->handle, &tuple);
-+ rc = pcmcia_get_tuple_data(link->handle, &tuple);
- if(rc != CS_SUCCESS) {
- cs_error(link->handle, GetTupleData, rc);
- break;
- }
-- rc = CardServices(ParseTuple, link->handle, &tuple, &parse);
-+ rc = pcmcia_parse_tuple(link->handle, &tuple, &parse);
- if(rc != CS_SUCCESS) {
- cs_error(link->handle, ParseTuple, rc);
- break;
-@@ -447,9 +439,9 @@
- case CISTPL_DEVICE_GEO: {
- cistpl_device_geo_t *t = &parse.device_geo;
- int i;
-- dev->pcmcia_map.buswidth = t->geo[0].buswidth;
-+ dev->pcmcia_map.bankwidth = t->geo[0].buswidth;
- for(i = 0; i < t->ngeo; i++) {
-- DEBUG(2, "region: %d buswidth = %u", i, t->geo[i].buswidth);
-+ DEBUG(2, "region: %d bankwidth = %u", i, t->geo[i].buswidth);
- DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block);
- DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block);
- DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block);
-@@ -463,22 +455,22 @@
- DEBUG(2, "Unknown tuple code %d", tuple.TupleCode);
- }
-
-- rc = CardServices(GetNextTuple, link->handle, &tuple, &parse);
-+ rc = pcmcia_get_next_tuple(link->handle, &tuple);
- }
- if(!dev->pcmcia_map.size)
- dev->pcmcia_map.size = MAX_PCMCIA_ADDR;
-
-- if(!dev->pcmcia_map.buswidth)
-- dev->pcmcia_map.buswidth = 2;
-+ if(!dev->pcmcia_map.bankwidth)
-+ dev->pcmcia_map.bankwidth = 2;
-
- if(force_size) {
- dev->pcmcia_map.size = force_size << 20;
- DEBUG(2, "size forced to %dM", force_size);
- }
-
-- if(buswidth) {
-- dev->pcmcia_map.buswidth = buswidth;
-- DEBUG(2, "buswidth forced to %d", buswidth);
-+ if(bankwidth) {
-+ dev->pcmcia_map.bankwidth = bankwidth;
-+ DEBUG(2, "bankwidth forced to %d", bankwidth);
- }
-
- dev->pcmcia_map.name = dev->mtd_name;
-@@ -488,7 +480,7 @@
- }
-
- DEBUG(1, "Device: Size: %lu Width:%d Name: %s",
-- dev->pcmcia_map.size, dev->pcmcia_map.buswidth << 3, dev->mtd_name);
-+ dev->pcmcia_map.size, dev->pcmcia_map.bankwidth << 3, dev->mtd_name);
- }
-
-
-@@ -497,8 +489,8 @@
- * MTD device available to the system.
- */
-
--#define CS_CHECK(fn, args...) \
--while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
-+#define CS_CHECK(fn, ret) \
-+do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
-
- static void pcmciamtd_config(dev_link_t *link)
- {
-@@ -520,7 +512,7 @@
- link->state |= DEV_CONFIG;
-
- DEBUG(2, "Validating CIS");
-- ret = CardServices(ValidateCIS, link->handle, &cisinfo);
-+ ret = pcmcia_validate_cis(link->handle, &cisinfo);
- if(ret != CS_SUCCESS) {
- cs_error(link->handle, GetTupleData, ret);
- } else {
-@@ -529,21 +521,25 @@
-
- card_settings(dev, link, &new_name);
-
-- dev->pcmcia_map.read8 = pcmcia_read8_remap;
-- dev->pcmcia_map.read16 = pcmcia_read16_remap;
-+ dev->pcmcia_map.phys = NO_XIP;
- dev->pcmcia_map.copy_from = pcmcia_copy_from_remap;
-- dev->pcmcia_map.write8 = pcmcia_write8_remap;
-- dev->pcmcia_map.write16 = pcmcia_write16_remap;
- dev->pcmcia_map.copy_to = pcmcia_copy_to_remap;
-+ if (dev->pcmcia_map.bankwidth == 1) {
-+ dev->pcmcia_map.read = pcmcia_read8_remap;
-+ dev->pcmcia_map.write = pcmcia_write8_remap;
-+ } else {
-+ dev->pcmcia_map.read = pcmcia_read16_remap;
-+ dev->pcmcia_map.write = pcmcia_write16_remap;
-+ }
- if(setvpp == 1)
- dev->pcmcia_map.set_vpp = pcmciamtd_set_vpp;
-
- /* Request a memory window for PCMCIA. Some architeures can map windows upto the maximum
-- that PCMCIA can support (64Mb) - this is ideal and we aim for a window the size of the
-+ that PCMCIA can support (64MiB) - this is ideal and we aim for a window the size of the
- whole card - otherwise we try smaller windows until we succeed */
-
- req.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE;
-- req.Attributes |= (dev->pcmcia_map.buswidth == 1) ? WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16;
-+ req.Attributes |= (dev->pcmcia_map.bankwidth == 1) ? WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16;
- req.Base = 0;
- req.AccessSpeed = mem_speed;
- link->win = (window_handle_t)link->handle;
-@@ -552,15 +548,14 @@
-
- do {
- int ret;
-- DEBUG(2, "requesting window with size = %dKB memspeed = %d",
-+ DEBUG(2, "requesting window with size = %dKiB memspeed = %d",
- req.Size >> 10, req.AccessSpeed);
-- link->win = (window_handle_t)link->handle;
-- ret = CardServices(RequestWindow, &link->win, &req);
-+ ret = pcmcia_request_window(&link->handle, &req, &link->win);
- DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size);
- if(ret) {
- req.Size >>= 1;
- } else {
-- DEBUG(2, "Got window of size %dKB", req.Size >> 10);
-+ DEBUG(2, "Got window of size %dKiB", req.Size >> 10);
- dev->win_size = req.Size;
- break;
- }
-@@ -570,19 +565,19 @@
-
- if(!dev->win_size) {
- err("Cant allocate memory window");
-- pcmciamtd_release((u_long)link);
-+ pcmciamtd_release(link);
- return;
- }
-- DEBUG(1, "Allocated a window of %dKB", dev->win_size >> 10);
-+ DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10);
-
- /* Get write protect status */
-- CS_CHECK(GetStatus, link->handle, &status);
-+ CS_CHECK(GetStatus, pcmcia_get_status(link->handle, &status));
- DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx",
- status.CardState, (unsigned long)link->win);
- dev->win_base = ioremap(req.Base, req.Size);
- if(!dev->win_base) {
- err("ioremap(%lu, %u) failed", req.Base, req.Size);
-- pcmciamtd_release((u_long)link);
-+ pcmciamtd_release(link);
- return;
- }
- DEBUG(1, "mapped window dev = %p req.base = 0x%lx base = %p size = 0x%x",
-@@ -593,7 +588,7 @@
- dev->pcmcia_map.map_priv_2 = (unsigned long)link->win;
-
- DEBUG(2, "Getting configuration");
-- CS_CHECK(GetConfigurationInfo, link->handle, &t);
-+ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link->handle, &t));
- DEBUG(2, "Vcc = %d Vpp1 = %d Vpp2 = %d", t.Vcc, t.Vpp1, t.Vpp2);
- dev->vpp = (vpp) ? vpp : t.Vpp1;
- link->conf.Attributes = 0;
-@@ -615,7 +610,7 @@
- link->conf.ConfigIndex = 0;
- link->conf.Present = t.Present;
- DEBUG(2, "Setting Configuration");
-- ret = CardServices(RequestConfiguration, link->handle, &link->conf);
-+ ret = pcmcia_request_configuration(link->handle, &link->conf);
- if(ret != CS_SUCCESS) {
- cs_error(link->handle, RequestConfiguration, ret);
- }
-@@ -637,26 +632,26 @@
-
- if(!mtd) {
- DEBUG(1, "Cant find an MTD");
-- pcmciamtd_release((u_long)link);
-+ pcmciamtd_release(link);
- return;
- }
-
- dev->mtd_info = mtd;
-- mtd->module = THIS_MODULE;
-+ mtd->owner = THIS_MODULE;
-
- if(new_name) {
- int size = 0;
- char unit = ' ';
- /* Since we are using a default name, make it better by adding in the
- size */
-- if(mtd->size < 1048576) { /* <1MB in size, show size in K */
-+ if(mtd->size < 1048576) { /* <1MiB in size, show size in KiB */
- size = mtd->size >> 10;
- unit = 'K';
- } else {
- size = mtd->size >> 20;
- unit = 'M';
- }
-- snprintf(dev->mtd_name, sizeof(dev->mtd_name), "%d%cB %s", size, unit, "PCMCIA Memory card");
-+ snprintf(dev->mtd_name, sizeof(dev->mtd_name), "%d%ciB %s", size, unit, "PCMCIA Memory card");
- }
-
- /* If the memory found is fits completely into the mapped PCMCIA window,
-@@ -665,11 +660,14 @@
- DEBUG(1, "Using non remapping memory functions");
- dev->pcmcia_map.map_priv_1 = (unsigned long)&(dev->link.state);
- dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base;
-- dev->pcmcia_map.read8 = pcmcia_read8;
-- dev->pcmcia_map.read16 = pcmcia_read16;
-+ if (dev->pcmcia_map.bankwidth == 1) {
-+ dev->pcmcia_map.read = pcmcia_read8;
-+ dev->pcmcia_map.write = pcmcia_write8;
-+ } else {
-+ dev->pcmcia_map.read = pcmcia_read16;
-+ dev->pcmcia_map.write = pcmcia_write16;
-+ }
- dev->pcmcia_map.copy_from = pcmcia_copy_from;
-- dev->pcmcia_map.write8 = pcmcia_write8;
-- dev->pcmcia_map.write16 = pcmcia_write16;
- dev->pcmcia_map.copy_to = pcmcia_copy_to;
- }
-
-@@ -677,7 +675,7 @@
- map_destroy(mtd);
- dev->mtd_info = NULL;
- err("Couldnt register MTD device");
-- pcmciamtd_release((u_long)link);
-+ pcmciamtd_release(link);
- return;
- }
- snprintf(dev->node.dev_name, sizeof(dev->node.dev_name), "mtd%d", mtd->index);
-@@ -689,7 +687,7 @@
- cs_failed:
- cs_error(link->handle, last_fn, last_ret);
- err("CS Error, exiting");
-- pcmciamtd_release((u_long)link);
-+ pcmciamtd_release(link);
- return;
- }
-
-@@ -716,7 +714,7 @@
- del_mtd_device(dev->mtd_info);
- info("mtd%d: Removed", dev->mtd_info->index);
- }
-- mod_timer(&link->release, jiffies + HZ/20);
-+ pcmciamtd_release(link);
- }
- break;
- case CS_EVENT_CARD_INSERTION:
-@@ -757,16 +755,14 @@
- {
- DEBUG(3, "link=0x%p", link);
-
-- del_timer(&link->release);
--
- if(link->state & DEV_CONFIG) {
-- pcmciamtd_release((u_long)link);
-+ pcmciamtd_release(link);
- }
-
- if (link->handle) {
- int ret;
- DEBUG(2, "Deregistering with card services");
-- ret = CardServices(DeregisterClient, link->handle);
-+ ret = pcmcia_deregister_client(link->handle);
- if (ret != CS_SUCCESS)
- cs_error(link->handle, DeregisterClient, ret);
- }
-@@ -796,10 +792,6 @@
- link = &dev->link;
- link->priv = dev;
-
-- init_timer(&link->release);
-- link->release.function = &pcmciamtd_release;
-- link->release.data = (u_long)link;
--
- link->conf.Attributes = 0;
- link->conf.IntType = INT_MEMORY;
-
-@@ -817,7 +809,7 @@
- client_reg.Version = 0x0210;
- client_reg.event_callback_args.client_data = link;
- DEBUG(2, "Calling RegisterClient");
-- ret = CardServices(RegisterClient, &link->handle, &client_reg);
-+ ret = pcmcia_register_client(&link->handle, &client_reg);
- if (ret != 0) {
- cs_error(link->handle, RegisterClient, ret);
- pcmciamtd_detach(link);
-@@ -828,20 +820,23 @@
- }
-
-
-+static struct pcmcia_driver pcmciamtd_driver = {
-+ .drv = {
-+ .name = "pcmciamtd"
-+ },
-+ .attach = pcmciamtd_attach,
-+ .detach = pcmciamtd_detach,
-+ .owner = THIS_MODULE
-+};
-+
-+
- static int __init init_pcmciamtd(void)
- {
-- servinfo_t serv;
--
- info(DRIVER_DESC " " DRIVER_VERSION);
-- CardServices(GetCardServicesInfo, &serv);
-- if (serv.Revision != CS_RELEASE_CODE) {
-- err("Card Services release does not match!");
-- return -1;
-- }
-
-- if(buswidth && buswidth != 1 && buswidth != 2) {
-- info("bad buswidth (%d), using default", buswidth);
-- buswidth = 2;
-+ if(bankwidth && bankwidth != 1 && bankwidth != 2) {
-+ info("bad bankwidth (%d), using default", bankwidth);
-+ bankwidth = 2;
- }
- if(force_size && (force_size < 1 || force_size > 64)) {
- info("bad force_size (%d), using default", force_size);
-@@ -851,15 +846,14 @@
- info("bad mem_type (%d), using default", mem_type);
- mem_type = 0;
- }
-- register_pccard_driver(&dev_info, &pcmciamtd_attach, &pcmciamtd_detach);
-- return 0;
-+ return pcmcia_register_driver(&pcmciamtd_driver);
- }
-
-
- static void __exit exit_pcmciamtd(void)
- {
- DEBUG(1, DRIVER_DESC " unloading");
-- unregister_pccard_driver(&dev_info);
-+ pcmcia_unregister_driver(&pcmciamtd_driver);
-
- while(dev_list) {
- dev_link_t *link = dev_list;
---- linux-2.4.21/drivers/mtd/maps/physmap.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/physmap.c
-@@ -1,179 +1,119 @@
- /*
-- * $Id: physmap.c,v 1.21 2002/09/05 05:12:54 acurtis Exp $
-+ * $Id: physmap.c,v 1.37 2004/11/28 09:40:40 dwmw2 Exp $
- *
- * Normal mappings of chips in physical memory
-+ *
-+ * Copyright (C) 2003 MontaVista Software Inc.
-+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
-+ *
-+ * 031022 - [jsun] add run-time configure and partition setup
- */
-
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
- #include <linux/config.h>
--
--#ifdef CONFIG_MTD_PARTITIONS
- #include <linux/mtd/partitions.h>
--#endif
--
--#define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START
--#define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN
--#define BUSWIDTH CONFIG_MTD_PHYSMAP_BUSWIDTH
-
- static struct mtd_info *mymtd;
-
--__u8 physmap_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 physmap_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 physmap_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void physmap_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void physmap_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void physmap_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
--
- struct map_info physmap_map = {
-- name: "Physically mapped flash",
-- size: WINDOW_SIZE,
-- buswidth: BUSWIDTH,
-- read8: physmap_read8,
-- read16: physmap_read16,
-- read32: physmap_read32,
-- copy_from: physmap_copy_from,
-- write8: physmap_write8,
-- write16: physmap_write16,
-- write32: physmap_write32,
-- copy_to: physmap_copy_to
-+ .name = "phys_mapped_flash",
-+ .phys = CONFIG_MTD_PHYSMAP_START,
-+ .size = CONFIG_MTD_PHYSMAP_LEN,
-+ .bankwidth = CONFIG_MTD_PHYSMAP_BANKWIDTH,
- };
-
- #ifdef CONFIG_MTD_PARTITIONS
--#ifdef CONFIG_MTD_CMDLINE_PARTS
--static struct mtd_partition *mtd_parts = 0;
--static int mtd_parts_nb = 0;
--#else
--static struct mtd_partition physmap_partitions[] = {
--/* Put your own partition definitions here */
--#if 0
-- {
-- name: "bootROM",
-- size: 0x80000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "zImage",
-- size: 0x100000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "ramdisk.gz",
-- size: 0x300000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "User FS",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-- }
--#endif
--};
-+static struct mtd_partition *mtd_parts;
-+static int mtd_parts_nb;
-
--#define NUM_PARTITIONS (sizeof(physmap_partitions)/sizeof(struct mtd_partition))
-+static int num_physmap_partitions;
-+static struct mtd_partition *physmap_partitions;
-
--#endif
--#endif
-+static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL};
-
--int __init init_physmap(void)
-+void physmap_set_partitions(struct mtd_partition *parts, int num_parts)
- {
-- static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 };
-+ physmap_partitions=parts;
-+ num_physmap_partitions=num_parts;
-+}
-+#endif /* CONFIG_MTD_PARTITIONS */
-+
-+static int __init init_physmap(void)
-+{
-+ static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
- const char **type;
-
-- printk(KERN_NOTICE "physmap flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
-- physmap_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+ printk(KERN_NOTICE "physmap flash device: %lx at %lx\n", physmap_map.size, physmap_map.phys);
-+ physmap_map.virt = ioremap(physmap_map.phys, physmap_map.size);
-
-- if (!physmap_map.map_priv_1) {
-+ if (!physmap_map.virt) {
- printk("Failed to ioremap\n");
- return -EIO;
- }
-
-- mymtd = 0;
-+ simple_map_init(&physmap_map);
-+
-+ mymtd = NULL;
- type = rom_probe_types;
- for(; !mymtd && *type; type++) {
- mymtd = do_map_probe(*type, &physmap_map);
- }
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
-- add_mtd_device(mymtd);
- #ifdef CONFIG_MTD_PARTITIONS
--#ifdef CONFIG_MTD_CMDLINE_PARTS
-- mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts,
-- "phys");
-+ mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes,
-+ &mtd_parts, 0);
-+
- if (mtd_parts_nb > 0)
- {
-- printk(KERN_NOTICE
-- "Using command line partition definition\n");
- add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb);
-+ return 0;
- }
--#else
-- if (NUM_PARTITIONS != 0)
-+
-+ if (num_physmap_partitions != 0)
- {
- printk(KERN_NOTICE
- "Using physmap partition definition\n");
-- add_mtd_partitions (mymtd, physmap_partitions, NUM_PARTITIONS);
-+ add_mtd_partitions (mymtd, physmap_partitions, num_physmap_partitions);
-+ return 0;
- }
-
- #endif
--#endif
-+ add_mtd_device(mymtd);
-+
- return 0;
- }
-
-- iounmap((void *)physmap_map.map_priv_1);
-+ iounmap(physmap_map.virt);
- return -ENXIO;
- }
-
- static void __exit cleanup_physmap(void)
- {
-- if (mymtd) {
-+#ifdef CONFIG_MTD_PARTITIONS
-+ if (mtd_parts_nb) {
-+ del_mtd_partitions(mymtd);
-+ kfree(mtd_parts);
-+ } else if (num_physmap_partitions) {
-+ del_mtd_partitions(mymtd);
-+ } else {
- del_mtd_device(mymtd);
-- map_destroy(mymtd);
-- }
-- if (physmap_map.map_priv_1) {
-- iounmap((void *)physmap_map.map_priv_1);
-- physmap_map.map_priv_1 = 0;
- }
-+#else
-+ del_mtd_device(mymtd);
-+#endif
-+ map_destroy(mymtd);
-+
-+ iounmap(physmap_map.virt);
-+ physmap_map.virt = NULL;
- }
-
- module_init(init_physmap);
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/plat-ram.c
-@@ -0,0 +1,286 @@
-+/* drivers/mtd/maps/plat-ram.c
-+ *
-+ * (c) 2004-2005 Simtec Electronics
-+ * http://www.simtec.co.uk/products/SWLINUX/
-+ * Ben Dooks <ben@simtec.co.uk>
-+ *
-+ * Generic platfrom device based RAM map
-+ *
-+ * $Id: plat-ram.c,v 1.1 2005/01/24 00:37:02 bjd Exp $
-+ *
-+ * This program is free software; 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
-+*/
-+
-+#define DEBUG
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/ioport.h>
-+#include <linux/device.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/mtd/plat-ram.h>
-+
-+#include <asm/io.h>
-+
-+/* private structure for each mtd platform ram device created */
-+
-+struct platram_info {
-+ struct device *dev;
-+ struct mtd_info *mtd;
-+ struct map_info map;
-+ struct mtd_partition *partitions;
-+ struct resource *area;
-+ struct platdata_mtd_ram *pdata;
-+};
-+
-+/* to_platram_info()
-+ *
-+ * device private data to struct platram_info conversion
-+*/
-+
-+static inline struct platram_info *to_platram_info(struct device *dev)
-+{
-+ return (struct platram_info *)dev_get_drvdata(dev);
-+}
-+
-+/* platram_setrw
-+ *
-+ * call the platform device's set rw/ro control
-+ *
-+ * to = 0 => read-only
-+ * = 1 => read-write
-+*/
-+
-+static inline void platram_setrw(struct platram_info *info, int to)
-+{
-+ if (info->pdata == NULL)
-+ return;
-+
-+ if (info->pdata->set_rw != NULL)
-+ (info->pdata->set_rw)(info->dev, to);
-+}
-+
-+/* platram_remove
-+ *
-+ * called to remove the device from the driver's control
-+*/
-+
-+static int platram_remove(struct device *dev)
-+{
-+ struct platram_info *info = to_platram_info(dev);
-+
-+ dev_set_drvdata(dev, NULL);
-+
-+ dev_dbg(dev, "removing device\n");
-+
-+ if (info == NULL)
-+ return 0;
-+
-+ if (info->mtd) {
-+#ifdef CONFIG_MTD_PARTITIONS
-+ if (info->partitions) {
-+ del_mtd_partitions(info->mtd);
-+ kfree(info->partitions);
-+ }
-+#endif
-+ del_mtd_device(info->mtd);
-+ map_destroy(info->mtd);
-+ }
-+
-+ /* ensure ram is left read-only */
-+
-+ platram_setrw(info, PLATRAM_RO);
-+
-+ /* release resources */
-+
-+ if (info->area) {
-+ release_resource(info->area);
-+ kfree(info->area);
-+ }
-+
-+ if (info->map.virt != NULL)
-+ iounmap(info->map.virt);
-+
-+ kfree(info);
-+
-+ return 0;
-+}
-+
-+/* platram_probe
-+ *
-+ * called from device drive system when a device matching our
-+ * driver is found.
-+*/
-+
-+static int platram_probe(struct device *dev)
-+{
-+ struct platform_device *pd = to_platform_device(dev);
-+ struct platdata_mtd_ram *pdata;
-+ struct platram_info *info;
-+ struct resource *res;
-+ int err = 0;
-+
-+ dev_dbg(dev, "probe entered\n");
-+
-+ if (dev->platform_data == NULL) {
-+ dev_err(dev, "no platform data supplied\n");
-+ err = -ENOENT;
-+ goto exit_error;
-+ }
-+
-+ pdata = dev->platform_data;
-+
-+ info = kmalloc(sizeof(*info), GFP_KERNEL);
-+ if (info == NULL) {
-+ dev_err(dev, "no memory for flash info\n");
-+ err = -ENOMEM;
-+ goto exit_error;
-+ }
-+
-+ memzero(info, sizeof(*info));
-+ dev_set_drvdata(dev, info);
-+
-+ info->dev = dev;
-+ info->pdata = pdata;
-+
-+ /* get the resource for the memory mapping */
-+
-+ res = platform_get_resource(pd, IORESOURCE_MEM, 0);
-+
-+ if (res == NULL) {
-+ dev_err(dev, "no memory resource specified\n");
-+ err = -ENOENT;
-+ goto exit_free;
-+ }
-+
-+ dev_dbg(dev, "got platform resource %p (0x%lx)\n", res, res->start);
-+
-+ /* setup map parameters */
-+
-+ info->map.phys = res->start;
-+ info->map.size = (res->end - res->start) + 1;
-+ info->map.name = pdata->mapname != NULL ? pdata->mapname : pd->name;
-+ info->map.bankwidth = pdata->bankwidth;
-+
-+ /* register our usage of the memory area */
-+
-+ info->area = request_mem_region(res->start, info->map.size, pd->name);
-+ if (info->area == NULL) {
-+ dev_err(dev, "failed to request memory region\n");
-+ err = -EIO;
-+ goto exit_free;
-+ }
-+
-+ /* remap the memory area */
-+
-+ info->map.virt = ioremap(res->start, info->map.size);
-+ dev_dbg(dev, "virt %p, %d bytes\n", info->map.virt, info->map.size);
-+
-+ if (info->map.virt == NULL) {
-+ dev_err(dev, "failed to ioremap() region\n");
-+ err = -EIO;
-+ goto exit_free;
-+ }
-+
-+ {
-+ unsigned int *p = (unsigned int *)info->map.virt;
-+ printk("%08x %08x %08x %08x\n",
-+ readl(p), readl(p+1), readl(p+2), readl(p+3));
-+ }
-+
-+ simple_map_init(&info->map);
-+
-+ dev_dbg(dev, "initialised map, probing for mtd\n");
-+
-+ /* probe for the right mtd map driver */
-+
-+ info->mtd = do_map_probe("map_ram" , &info->map);
-+ if (info->mtd == NULL) {
-+ dev_err(dev, "failed to probe for map_ram\n");
-+ err = -ENOMEM;
-+ goto exit_free;
-+ }
-+
-+ info->mtd->owner = THIS_MODULE;
-+
-+ platram_setrw(info, PLATRAM_RW);
-+
-+ /* check to see if there are any available partitions, or wether
-+ * to add this device whole */
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+ if (pdata->nr_partitions > 0) {
-+ const char **probes = { NULL };
-+
-+ if (pdata->probes)
-+ probes = (const char **)pdata->probes;
-+
-+ err = parse_mtd_partitions(info->mtd, probes,
-+ &info->partitions, 0);
-+ if (err > 0) {
-+ err = add_mtd_partitions(info->mtd, info->partitions,
-+ err);
-+ }
-+ }
-+#endif /* CONFIG_MTD_PARTITIONS */
-+
-+ if (add_mtd_device(info->mtd)) {
-+ dev_err(dev, "add_mtd_device() failed\n");
-+ err = -ENOMEM;
-+ }
-+
-+ dev_info(dev, "registered mtd device\n");
-+ return err;
-+
-+ exit_free:
-+ platram_remove(dev);
-+ exit_error:
-+ return err;
-+}
-+
-+/* device driver info */
-+
-+static struct device_driver platram_driver = {
-+ .name = "mtd-ram",
-+ .bus = &platform_bus_type,
-+ .probe = platram_probe,
-+ .remove = platram_remove,
-+};
-+
-+/* module init/exit */
-+
-+static int __init platram_init(void)
-+{
-+ printk("Generic platform RAM MTD, (c) 2004 Simtec Electronics\n");
-+ return driver_register(&platram_driver);
-+}
-+
-+static void __exit platram_exit(void)
-+{
-+ driver_unregister(&platram_driver);
-+}
-+
-+module_init(platram_init);
-+module_exit(platram_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-+MODULE_DESCRIPTION("MTD platform RAM map driver");
---- linux-2.4.21/drivers/mtd/maps/pnc2000.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/pnc2000.c
-@@ -5,12 +5,13 @@
- *
- * This code is GPL
- *
-- * $Id: pnc2000.c,v 1.10 2001/10/02 15:05:14 dwmw2 Exp $
-+ * $Id: pnc2000.c,v 1.17 2004/11/16 18:29:02 dwmw2 Exp $
- */
-
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -24,58 +25,13 @@
- * MAP DRIVER STUFF
- */
-
--__u8 pnc_read8(struct map_info *map, unsigned long ofs)
--{
-- return *(__u8 *)(WINDOW_ADDR + ofs);
--}
--
--__u16 pnc_read16(struct map_info *map, unsigned long ofs)
--{
-- return *(__u16 *)(WINDOW_ADDR + ofs);
--}
--
--__u32 pnc_read32(struct map_info *map, unsigned long ofs)
--{
-- return *(volatile unsigned int *)(WINDOW_ADDR + ofs);
--}
--
--void pnc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy(to, (void *)(WINDOW_ADDR + from), len);
--}
--
--void pnc_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- *(__u8 *)(WINDOW_ADDR + adr) = d;
--}
--
--void pnc_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- *(__u16 *)(WINDOW_ADDR + adr) = d;
--}
--
--void pnc_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- *(__u32 *)(WINDOW_ADDR + adr) = d;
--}
--
--void pnc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy((void *)(WINDOW_ADDR + to), from, len);
--}
-
--struct map_info pnc_map = {
-- name: "PNC-2000",
-- size: WINDOW_SIZE,
-- buswidth: 4,
-- read8: pnc_read8,
-- read16: pnc_read16,
-- read32: pnc_read32,
-- copy_from: pnc_copy_from,
-- write8: pnc_write8,
-- write16: pnc_write16,
-- write32: pnc_write32,
-- copy_to: pnc_copy_to
-+static struct map_info pnc_map = {
-+ .name = "PNC-2000",
-+ .size = WINDOW_SIZE,
-+ .bankwidth = 4,
-+ .phys = 0xFFFFFFFF,
-+ .virt = (void __iomem *)WINDOW_ADDR,
- };
-
-
-@@ -84,19 +40,19 @@
- */
- static struct mtd_partition pnc_partitions[3] = {
- {
-- name: "PNC-2000 boot firmware",
-- size: 0x20000,
-- offset: 0
-+ .name = "PNC-2000 boot firmware",
-+ .size = 0x20000,
-+ .offset = 0
- },
- {
-- name: "PNC-2000 kernel",
-- size: 0x1a0000,
-- offset: 0x20000
-+ .name = "PNC-2000 kernel",
-+ .size = 0x1a0000,
-+ .offset = 0x20000
- },
- {
-- name: "PNC-2000 filesystem",
-- size: 0x240000,
-- offset: 0x1c0000
-+ .name = "PNC-2000 filesystem",
-+ .size = 0x240000,
-+ .offset = 0x1c0000
- }
- };
-
-@@ -106,13 +62,15 @@
- */
- static struct mtd_info *mymtd;
-
--int __init init_pnc2000(void)
-+static int __init init_pnc2000(void)
- {
- printk(KERN_NOTICE "Photron PNC-2000 flash mapping: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
-
-+ simple_map_init(&pnc_map);
-+
- mymtd = do_map_probe("cfi_probe", &pnc_map);
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
- return add_mtd_partitions(mymtd, pnc_partitions, 3);
- }
-
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/ramses.c
-@@ -0,0 +1,124 @@
-+/*
-+ * Map driver for the Ramses developer platform.
-+ *
-+ * 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/types.h>
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/errno.h>
-+#include <linux/init.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/io.h>
-+
-+#define WINDOW_ADDR 0
-+#define WINDOW_SIZE 32*1024*1024
-+
-+static struct map_info ramses_map_flash = {
-+ .name = "Flash",
-+ .phys = WINDOW_ADDR,
-+ .size = WINDOW_SIZE,
-+ .bankwidth = 4,
-+};
-+
-+static struct mtd_partition ramses_flash_partitions[] = {
-+ {
-+ name: "Bootloader",
-+ size: 0x00040000,
-+ offset: 0,
-+ },{
-+ name: "Kernel",
-+ size: 0x00100000,
-+ offset: 0x00040000,
-+ },{
-+ name: "Filesystem",
-+ size: MTDPART_SIZ_FULL,
-+ offset: 0x00140000
-+ }
-+};
-+
-+static struct mtd_partition *parsed_parts;
-+
-+static struct mtd_info *flash_mtd;
-+static int __init init_ramses(void)
-+{
-+ struct mtd_partition *parts;
-+ int nb_parts = 0;
-+ int parsed_nr_parts = 0;
-+ const char *part_type;
-+
-+ /*
-+ * Static partition definition selection
-+ */
-+ part_type = "static";
-+ parts = ramses_flash_partitions;
-+ nb_parts = ARRAY_SIZE(ramses_flash_partitions);
-+
-+ simple_map_init(&ramses_map_flash);
-+
-+ printk( "Probing flash at physical address 0x%08x (%d-bit buswidth)\n",
-+ WINDOW_ADDR, ramses_map_flash.bankwidth * 8 );
-+#ifdef CONFIG_ARCH_RAMSES
-+ FLASH_WRITE_PROTECT_DISABLE();
-+#endif
-+
-+
-+ ramses_map_flash.virt = __ioremap(WINDOW_ADDR, WINDOW_SIZE, 0);
-+ if (!ramses_map_flash.virt) {
-+ printk("Failed to ioremap\n");
-+ return -EIO;
-+ }
-+ flash_mtd = do_map_probe("cfi_probe", &ramses_map_flash);
-+
-+ if (!flash_mtd) {
-+ iounmap((void *)ramses_map_flash.virt);
-+ return -ENXIO;
-+ }
-+
-+ if (parsed_nr_parts > 0) {
-+ parts = parsed_parts;
-+ nb_parts = parsed_nr_parts;
-+ }
-+
-+ if (nb_parts == 0) {
-+ printk(KERN_NOTICE "Ramses flash: no partition info available,"
-+ "registering whole flash at once\n");
-+ if (add_mtd_device(flash_mtd)){
-+ return -ENXIO;
-+ }
-+ } else {
-+ printk(KERN_NOTICE "Using %s partition definition\n",
-+ part_type);
-+ return add_mtd_partitions(flash_mtd, parts, nb_parts);
-+ }
-+ return 0;
-+}
-+
-+static void __exit cleanup_ramses(void)
-+{
-+ if (flash_mtd) {
-+ del_mtd_partitions(flash_mtd);
-+ map_destroy(flash_mtd);
-+ if (parsed_parts)
-+ kfree(parsed_parts);
-+ }
-+ if (ramses_map_flash.virt)
-+ iounmap(ramses_map_flash.virt);
-+#ifdef CONFIG_ARCH_RAMSES
-+ FLASH_WRITE_PROTECT_ENABLE();
-+#endif
-+ return;
-+}
-+
-+module_init(init_ramses);
-+module_exit(cleanup_ramses);
---- linux-2.4.21/drivers/mtd/maps/redwood.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/redwood.c
-@@ -1,38 +1,23 @@
- /*
-- * $Id:
-- *
-- * redwood.c - mapper for IBM Redwood-4/5 board.
-- *
-- * Copyright 2001 MontaVista Softare 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.
-+ * $Id: redwood.c,v 1.10 2004/11/04 13:24:15 gleixner Exp $
- *
-- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
-- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 OF
-- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ * drivers/mtd/maps/redwood.c
- *
-- * You 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.
-+ * FLASH map for the IBM Redwood 4/5/6 boards.
- *
-- * History: 12/17/2001 - Armin
-- * migrated to use do_map_probe
-+ * Author: MontaVista Software, Inc. <source@mvista.com>
- *
-+ * 2001-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/config.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -40,96 +25,102 @@
-
- #include <asm/io.h>
-
-+#if !defined (CONFIG_REDWOOD_6)
-+
- #define WINDOW_ADDR 0xffc00000
- #define WINDOW_SIZE 0x00400000
-
--__u8 redwood_flash_read8(struct map_info *map, unsigned long ofs)
--{
-- return *(__u8 *)(map->map_priv_1 + ofs);
--}
--
--__u16 redwood_flash_read16(struct map_info *map, unsigned long ofs)
--{
-- return *(__u16 *)(map->map_priv_1 + ofs);
--}
--
--__u32 redwood_flash_read32(struct map_info *map, unsigned long ofs)
--{
-- return *(volatile unsigned int *)(map->map_priv_1 + ofs);
--}
--
--void redwood_flash_copy_from(struct map_info *map, void *to,
-- unsigned long from, ssize_t len)
--{
-- memcpy(to, (void *)(map->map_priv_1 + from), len);
--}
--
--void redwood_flash_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- *(__u8 *)(map->map_priv_1 + adr) = d;
--}
--
--void redwood_flash_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- *(__u16 *)(map->map_priv_1 + adr) = d;
--}
--
--void redwood_flash_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- *(__u32 *)(map->map_priv_1 + adr) = d;
--}
--
--void redwood_flash_copy_to(struct map_info *map, unsigned long to,
-- const void *from, ssize_t len)
--{
-- memcpy((void *)(map->map_priv_1 + to), from, len);
--}
-+#define RW_PART0_OF 0
-+#define RW_PART0_SZ 0x10000
-+#define RW_PART1_OF RW_PART0_SZ
-+#define RW_PART1_SZ 0x200000 - 0x10000
-+#define RW_PART2_OF 0x200000
-+#define RW_PART2_SZ 0x10000
-+#define RW_PART3_OF 0x210000
-+#define RW_PART3_SZ 0x200000 - (0x10000 + 0x20000)
-+#define RW_PART4_OF 0x3e0000
-+#define RW_PART4_SZ 0x20000
-
--struct map_info redwood_flash_map = {
-- name: "IBM Redwood",
-- size: WINDOW_SIZE,
-- buswidth: 2,
-- read8: redwood_flash_read8,
-- read16: redwood_flash_read16,
-- read32: redwood_flash_read32,
-- copy_from: redwood_flash_copy_from,
-- write8: redwood_flash_write8,
-- write16: redwood_flash_write16,
-- write32: redwood_flash_write32,
-- copy_to: redwood_flash_copy_to
-+static struct mtd_partition redwood_flash_partitions[] = {
-+ {
-+ .name = "Redwood OpenBIOS Vital Product Data",
-+ .offset = RW_PART0_OF,
-+ .size = RW_PART0_SZ,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
-+ },
-+ {
-+ .name = "Redwood kernel",
-+ .offset = RW_PART1_OF,
-+ .size = RW_PART1_SZ
-+ },
-+ {
-+ .name = "Redwood OpenBIOS non-volatile storage",
-+ .offset = RW_PART2_OF,
-+ .size = RW_PART2_SZ,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
-+ },
-+ {
-+ .name = "Redwood filesystem",
-+ .offset = RW_PART3_OF,
-+ .size = RW_PART3_SZ
-+ },
-+ {
-+ .name = "Redwood OpenBIOS",
-+ .offset = RW_PART4_OF,
-+ .size = RW_PART4_SZ,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
-+ }
- };
-
-+#else /* CONFIG_REDWOOD_6 */
-+/* FIXME: the window is bigger - armin */
-+#define WINDOW_ADDR 0xff800000
-+#define WINDOW_SIZE 0x00800000
-+
-+#define RW_PART0_OF 0
-+#define RW_PART0_SZ 0x400000 /* 4 MiB data */
-+#define RW_PART1_OF RW_PART0_OF + RW_PART0_SZ
-+#define RW_PART1_SZ 0x10000 /* 64K VPD */
-+#define RW_PART2_OF RW_PART1_OF + RW_PART1_SZ
-+#define RW_PART2_SZ 0x400000 - (0x10000 + 0x20000)
-+#define RW_PART3_OF RW_PART2_OF + RW_PART2_SZ
-+#define RW_PART3_SZ 0x20000
-
- static struct mtd_partition redwood_flash_partitions[] = {
- {
-- name: "Redwood OpenBIOS Vital Product Data",
-- offset: 0,
-- size: 0x10000,
-- mask_flags: MTD_WRITEABLE /* force read-only */
-- },
-- {
-- name: "Redwood kernel",
-- offset: 0x10000,
-- size: 0x200000 - 0x10000
-+ .name = "Redwood filesystem",
-+ .offset = RW_PART0_OF,
-+ .size = RW_PART0_SZ
- },
- {
-- name: "Redwood OpenBIOS non-volatile storage",
-- offset: 0x200000,
-- size: 0x10000,
-- mask_flags: MTD_WRITEABLE /* force read-only */
-+ .name = "Redwood OpenBIOS Vital Product Data",
-+ .offset = RW_PART1_OF,
-+ .size = RW_PART1_SZ,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
- },
- {
-- name: "Redwood filesystem",
-- offset: 0x210000,
-- size: 0x200000 - (0x10000 + 0x20000)
-+ .name = "Redwood kernel",
-+ .offset = RW_PART2_OF,
-+ .size = RW_PART2_SZ
- },
- {
-- name: "Redwood OpenBIOS",
-- offset: 0x3e0000,
-- size: 0x20000,
-- mask_flags: MTD_WRITEABLE /* force read-only */
-+ .name = "Redwood OpenBIOS",
-+ .offset = RW_PART3_OF,
-+ .size = RW_PART3_SZ,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
- }
- };
-+
-+#endif /* CONFIG_REDWOOD_6 */
-+
-+struct map_info redwood_flash_map = {
-+ .name = "IBM Redwood",
-+ .size = WINDOW_SIZE,
-+ .bankwidth = 2,
-+ .phys = WINDOW_ADDR,
-+};
-+
-+
- #define NUM_REDWOOD_FLASH_PARTITIONS \
- (sizeof(redwood_flash_partitions)/sizeof(redwood_flash_partitions[0]))
-
-@@ -140,18 +131,18 @@
- printk(KERN_NOTICE "redwood: flash mapping: %x at %x\n",
- WINDOW_SIZE, WINDOW_ADDR);
-
-- redwood_flash_map.map_priv_1 =
-- (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+ redwood_flash_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
-
-- if (!redwood_flash_map.map_priv_1) {
-+ if (!redwood_flash_map.virt) {
- printk("init_redwood_flash: failed to ioremap\n");
- return -EIO;
- }
-+ simple_map_init(&redwood_flash_map);
-
- redwood_mtd = do_map_probe("cfi_probe",&redwood_flash_map);
-
- if (redwood_mtd) {
-- redwood_mtd->module = THIS_MODULE;
-+ redwood_mtd->owner = THIS_MODULE;
- return add_mtd_partitions(redwood_mtd,
- redwood_flash_partitions,
- NUM_REDWOOD_FLASH_PARTITIONS);
-@@ -164,10 +155,15 @@
- {
- if (redwood_mtd) {
- del_mtd_partitions(redwood_mtd);
-- iounmap((void *)redwood_flash_map.map_priv_1);
-+ /* moved iounmap after map_destroy - armin */
- map_destroy(redwood_mtd);
-+ iounmap((void *)redwood_flash_map.virt);
- }
- }
-
- module_init(init_redwood_flash);
- module_exit(cleanup_redwood_flash);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("MontaVista Software <source@mvista.com>");
-+MODULE_DESCRIPTION("MTD map driver for the IBM Redwood reference boards");
---- linux-2.4.21/drivers/mtd/maps/rpxlite.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/rpxlite.c
-@@ -1,5 +1,5 @@
- /*
-- * $Id: rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp $
-+ * $Id: rpxlite.c,v 1.22 2004/11/04 13:24:15 gleixner Exp $
- *
- * Handle mapping of the flash on the RPX Lite and CLLF boards
- */
-@@ -7,6 +7,7 @@
- #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>
-@@ -17,80 +18,31 @@
-
- static struct mtd_info *mymtd;
-
--__u8 rpxlite_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 rpxlite_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 rpxlite_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void rpxlite_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
--}
--
--void rpxlite_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void rpxlite_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void rpxlite_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void rpxlite_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio((void *)(map->map_priv_1 + to), from, len);
--}
--
--struct map_info rpxlite_map = {
-- name: "RPX",
-- size: WINDOW_SIZE,
-- buswidth: 4,
-- read8: rpxlite_read8,
-- read16: rpxlite_read16,
-- read32: rpxlite_read32,
-- copy_from: rpxlite_copy_from,
-- write8: rpxlite_write8,
-- write16: rpxlite_write16,
-- write32: rpxlite_write32,
-- copy_to: rpxlite_copy_to
-+static struct map_info rpxlite_map = {
-+ .name = "RPX",
-+ .size = WINDOW_SIZE,
-+ .bankwidth = 4,
-+ .phys = WINDOW_ADDR,
- };
-
- int __init init_rpxlite(void)
- {
- printk(KERN_NOTICE "RPX Lite or CLLF flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR);
-- rpxlite_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
-+ rpxlite_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
-
-- if (!rpxlite_map.map_priv_1) {
-+ if (!rpxlite_map.virt) {
- printk("Failed to ioremap\n");
- return -EIO;
- }
-+ simple_map_init(&rpxlite_map);
- mymtd = do_map_probe("cfi_probe", &rpxlite_map);
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
- add_mtd_device(mymtd);
- return 0;
- }
-
-- iounmap((void *)rpxlite_map.map_priv_1);
-+ iounmap((void *)rpxlite_map.virt);
- return -ENXIO;
- }
-
-@@ -100,9 +52,9 @@
- del_mtd_device(mymtd);
- map_destroy(mymtd);
- }
-- if (rpxlite_map.map_priv_1) {
-- iounmap((void *)rpxlite_map.map_priv_1);
-- rpxlite_map.map_priv_1 = 0;
-+ if (rpxlite_map.virt) {
-+ iounmap((void *)rpxlite_map.virt);
-+ rpxlite_map.virt = 0;
- }
- }
-
---- linux-2.4.21/drivers/mtd/maps/sa1100-flash.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/sa1100-flash.c
-@@ -3,7 +3,7 @@
- *
- * (C) 2000 Nicolas Pitre <nico@cam.org>
- *
-- * $Id: sa1100-flash.c,v 1.29 2002/09/06 14:36:19 abz Exp $
-+ * $Id: sa1100-flash.c,v 1.47 2004/11/01 13:44:36 rmk Exp $
- */
-
- #include <linux/config.h>
-@@ -11,330 +11,212 @@
- #include <linux/types.h>
- #include <linux/ioport.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/slab.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/partitions.h>
-+#include <linux/mtd/concat.h>
-
- #include <asm/hardware.h>
-+#include <asm/mach-types.h>
- #include <asm/io.h>
-+#include <asm/sizes.h>
-
-+#include <asm/arch/h3600.h>
-
- #ifndef CONFIG_ARCH_SA1100
- #error This is for SA1100 architecture only
- #endif
-
-+/*
-+ * This isnt complete yet, so...
-+ */
-+#define CONFIG_MTD_SA1100_STATICMAP 1
-
--#define WINDOW_ADDR 0xe8000000
--
--static __u8 sa1100_read8(struct map_info *map, unsigned long ofs)
--{
-- return readb(map->map_priv_1 + ofs);
--}
--
--static __u16 sa1100_read16(struct map_info *map, unsigned long ofs)
--{
-- return readw(map->map_priv_1 + ofs);
--}
--
--static __u32 sa1100_read32(struct map_info *map, unsigned long ofs)
--{
-- return readl(map->map_priv_1 + ofs);
--}
--
--static void sa1100_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy(to, (void *)(map->map_priv_1 + from), len);
--}
--
--static void sa1100_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- writeb(d, map->map_priv_1 + adr);
--}
--
--static void sa1100_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- writew(d, map->map_priv_1 + adr);
--}
--
--static void sa1100_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- writel(d, map->map_priv_1 + adr);
--}
--
--static void sa1100_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy((void *)(map->map_priv_1 + to), from, len);
--}
--
--static struct map_info sa1100_map = {
-- name: "SA1100 flash",
-- read8: sa1100_read8,
-- read16: sa1100_read16,
-- read32: sa1100_read32,
-- copy_from: sa1100_copy_from,
-- write8: sa1100_write8,
-- write16: sa1100_write16,
-- write32: sa1100_write32,
-- copy_to: sa1100_copy_to,
--
-- map_priv_1: WINDOW_ADDR,
-- map_priv_2: -1,
--};
--
--
-+#ifdef CONFIG_MTD_SA1100_STATICMAP
- /*
- * Here are partition information for all known SA1100-based devices.
- * See include/linux/mtd/partitions.h for definition of the mtd_partition
- * structure.
- *
-- * The *_max_flash_size is the maximum possible mapped flash size which
-- * is not necessarily the actual flash size. It must be no more than
-- * the value specified in the "struct map_desc *_io_desc" mapping
-- * definition for the corresponding machine.
-+ * Please note:
-+ * 1. We no longer support static flash mappings via the machine io_desc
-+ * structure.
-+ * 2. The flash size given should be the largest flash size that can
-+ * be accommodated.
-+ *
-+ * The MTD layer will detect flash chip aliasing and reduce the size of
-+ * the map accordingly.
- *
- * Please keep these in alphabetical order, and formatted as per existing
- * entries. Thanks.
- */
-
--#ifdef CONFIG_SA1100_ADSAGC
--#define ADSAGC_FLASH_SIZE 0x02000000
--static struct mtd_partition adsagc_partitions[] = {
-- {
-- name: "bootROM",
-- size: 0x80000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "zImage",
-- size: 0x100000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "ramdisk.gz",
-- size: 0x300000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "User FS",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-- }
--};
--#endif
--
- #ifdef CONFIG_SA1100_ADSBITSY
--#define ADSBITSY_FLASH_SIZE 0x02000000
- static struct mtd_partition adsbitsy_partitions[] = {
- {
-- name: "bootROM",
-- size: 0x80000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "zImage",
-- size: 0x100000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "ramdisk.gz",
-- size: 0x300000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "User FS",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-- }
--};
--#endif
--
--#ifdef CONFIG_SA1100_ADSBITSYPLUS
--#define ADSBITSYPLUS_FLASH_SIZE 0x02000000
--static struct mtd_partition adsbitsyplus_partitions[] = {
-- {
-- name: "bootROM",
-- size: 0x80000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "bootROM",
-+ .size = 0x80000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "zImage",
-- size: 0x100000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "zImage",
-+ .size = 0x100000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "ramdisk.gz",
-- size: 0x300000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "ramdisk.gz",
-+ .size = 0x300000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "User FS",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "User FS",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_ASSABET
- /* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */
--#define ASSABET4_FLASH_SIZE 0x00400000
- static struct mtd_partition assabet4_partitions[] = {
- {
-- name: "bootloader",
-- size: 0x00020000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE,
-+ .name = "bootloader",
-+ .size = 0x00020000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE,
- }, {
-- name: "bootloader params",
-- size: 0x00020000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-+ .name = "bootloader params",
-+ .size = 0x00020000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
- }, {
-- name: "jffs",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "jffs",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
-
- /* Phase 5 Assabet has two 28F128J3A flash parts in bank 0: */
--#define ASSABET5_FLASH_SIZE 0x02000000
- static struct mtd_partition assabet5_partitions[] = {
- {
-- name: "bootloader",
-- size: 0x00040000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE,
-+ .name = "bootloader",
-+ .size = 0x00040000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE,
- }, {
-- name: "bootloader params",
-- size: 0x00040000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-+ .name = "bootloader params",
-+ .size = 0x00040000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
- }, {
-- name: "jffs",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "jffs",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
-
--#define ASSABET_FLASH_SIZE ASSABET5_FLASH_SIZE
- #define assabet_partitions assabet5_partitions
- #endif
-
- #ifdef CONFIG_SA1100_BADGE4
--
- /*
-- * 1 x Intel 28F320C3BA100 Advanced+ Boot Block Flash (32 Mi bit)
-+ * 1 x Intel 28F320C3 Advanced+ Boot Block Flash (32 Mi bit)
- * Eight 4 KiW Parameter Bottom Blocks (64 KiB)
- * Sixty-three 32 KiW Main Blocks (4032 Ki b)
-+ *
-+ * <or>
-+ *
-+ * 1 x Intel 28F640C3 Advanced+ Boot Block Flash (64 Mi bit)
-+ * Eight 4 KiW Parameter Bottom Blocks (64 KiB)
-+ * One-hundred-twenty-seven 32 KiW Main Blocks (8128 Ki b)
- */
--#define BADGE4_FLASH_SIZE 0x00400000
- static struct mtd_partition badge4_partitions[] = {
- {
-- name: "BLOB boot loader",
-- offset: 0,
-- size: 0x0000A000
-- }, {
-- name: "params",
-- offset: MTDPART_OFS_APPEND,
-- size: 0x00006000
-+ .name = "BLOB boot loader",
-+ .offset = 0,
-+ .size = 0x0000A000
- }, {
-- name: "kernel",
-- offset: MTDPART_OFS_APPEND,
-- size: 0x00100000
-+ .name = "params",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = 0x00006000
- }, {
-- name: "root",
-- offset: MTDPART_OFS_APPEND,
-- size: MTDPART_SIZ_FULL
-+ .name = "root",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = MTDPART_SIZ_FULL
- }
- };
--
- #endif
-
-
- #ifdef CONFIG_SA1100_CERF
- #ifdef CONFIG_SA1100_CERF_FLASH_32MB
--#define CERF_FLASH_SIZE 0x02000000
--static struct mtd_partition cerf_partitions[] = {
-- {
-- name: "firmware",
-- size: 0x00040000,
-- offset: 0,
-- }, {
-- name: "params",
-- size: 0x00040000,
-- offset: 0x00040000,
-- }, {
-- name: "kernel",
-- size: 0x00100000,
-- offset: 0x00080000,
-- }, {
-- name: "rootdisk",
-- size: 0x01E80000,
-- offset: 0x00180000,
-- }
--};
-+# define CERF_FLASH_SIZE 0x02000000
- #elif defined CONFIG_SA1100_CERF_FLASH_16MB
--#define CERF_FLASH_SIZE 0x01000000
-+# define CERF_FLASH_SIZE 0x01000000
-+#elif defined CONFIG_SA1100_CERF_FLASH_8MB
-+# define CERF_FLASH_SIZE 0x00800000
-+#else
-+# error "Undefined flash size for CERF in sa1100-flash.c"
-+#endif
-+
- static struct mtd_partition cerf_partitions[] = {
- {
-- name: "firmware",
-- size: 0x00020000,
-- offset: 0,
-+ .name = "Bootloader",
-+ .size = 0x00020000,
-+ .offset = 0x00000000,
- }, {
-- name: "params",
-- size: 0x00020000,
-- offset: 0x00020000,
-+ .name = "Params",
-+ .size = 0x00040000,
-+ .offset = 0x00020000,
- }, {
-- name: "kernel",
-- size: 0x00100000,
-- offset: 0x00040000,
-+ .name = "Kernel",
-+ .size = 0x00100000,
-+ .offset = 0x00060000,
- }, {
-- name: "rootdisk",
-- size: 0x00EC0000,
-- offset: 0x00140000,
-+ .name = "Filesystem",
-+ .size = CERF_FLASH_SIZE-0x00160000,
-+ .offset = 0x00160000,
- }
- };
--#elif defined CONFIG_SA1100_CERF_FLASH_8MB
--# error "Unwritten type definition"
--#else
--# error "Undefined memory orientation for CERF in sa1100-flash.c"
--#endif
- #endif
-
- #ifdef CONFIG_SA1100_CONSUS
--#define CONSUS_FLASH_SIZE 0x02000000
- static struct mtd_partition consus_partitions[] = {
- {
-- name: "Consus boot firmware",
-- offset: 0,
-- size: 0x00040000,
-- mask_flags: MTD_WRITABLE, /* force read-only */
-+ .name = "Consus boot firmware",
-+ .offset = 0,
-+ .size = 0x00040000,
-+ .mask_flags = MTD_WRITABLE, /* force read-only */
- }, {
-- name: "Consus kernel",
-- offset: 0x00040000,
-- size: 0x00100000,
-- mask_flags: 0,
-+ .name = "Consus kernel",
-+ .offset = 0x00040000,
-+ .size = 0x00100000,
-+ .mask_flags = 0,
- }, {
-- name: "Consus disk",
-- offset: 0x00140000,
-+ .name = "Consus disk",
-+ .offset = 0x00140000,
- /* The rest (up to 16M) for jffs. We could put 0 and
- make it find the size automatically, but right now
- i have 32 megs. jffs will use all 32 megs if given
- the chance, and this leads to horrible problems
- when you try to re-flash the image because blob
- won't erase the whole partition. */
-- size: 0x01000000 - 0x00140000,
-- mask_flags: 0,
-+ .size = 0x01000000 - 0x00140000,
-+ .mask_flags = 0,
- }, {
- /* this disk is a secondary disk, which can be used as
- needed, for simplicity, make it the size of the other
- consus partition, although realistically it could be
- the remainder of the disk (depending on the file
- system used) */
-- name: "Consus disk2",
-- offset: 0x01000000,
-- size: 0x01000000 - 0x00140000,
-- mask_flags: 0,
-+ .name = "Consus disk2",
-+ .offset = 0x01000000,
-+ .size = 0x01000000 - 0x00140000,
-+ .mask_flags = 0,
- }
- };
- #endif
-@@ -344,96 +226,95 @@
- #define FLEXANET_FLASH_SIZE 0x02000000
- static struct mtd_partition flexanet_partitions[] = {
- {
-- name: "bootloader",
-- size: 0x00040000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE,
-+ .name = "bootloader",
-+ .size = 0x00040000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE,
- }, {
-- name: "bootloader params",
-- size: 0x00040000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-+ .name = "bootloader params",
-+ .size = 0x00040000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
- }, {
-- name: "kernel",
-- size: 0x000C0000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-+ .name = "kernel",
-+ .size = 0x000C0000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
- }, {
-- name: "altkernel",
-- size: 0x000C0000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-+ .name = "altkernel",
-+ .size = 0x000C0000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
- }, {
-- name: "root",
-- size: 0x00400000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-+ .name = "root",
-+ .size = 0x00400000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
- }, {
-- name: "free1",
-- size: 0x00300000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-+ .name = "free1",
-+ .size = 0x00300000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
- }, {
-- name: "free2",
-- size: 0x00300000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-+ .name = "free2",
-+ .size = 0x00300000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
- }, {
-- name: "free3",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-+ .name = "free3",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_FREEBIRD
--#define FREEBIRD_FLASH_SIZE 0x02000000
- static struct mtd_partition freebird_partitions[] = {
--#if CONFIG_SA1100_FREEBIRD_NEW
-+#ifdef CONFIG_SA1100_FREEBIRD_NEW
- {
-- name: "firmware",
-- size: 0x00040000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "firmware",
-+ .size = 0x00040000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "kernel",
-- size: 0x00080000,
-- offset: 0x00040000,
-+ .name = "kernel",
-+ .size = 0x00080000,
-+ .offset = 0x00040000,
- }, {
-- name: "params",
-- size: 0x00040000,
-- offset: 0x000C0000,
-+ .name = "params",
-+ .size = 0x00040000,
-+ .offset = 0x000C0000,
- }, {
-- name: "initrd",
-- size: 0x00100000,
-- offset: 0x00100000,
-+ .name = "initrd",
-+ .size = 0x00100000,
-+ .offset = 0x00100000,
- }, {
-- name: "root cramfs",
-- size: 0x00300000,
-- offset: 0x00200000,
-+ .name = "root cramfs",
-+ .size = 0x00300000,
-+ .offset = 0x00200000,
- }, {
-- name: "usr cramfs",
-- size: 0x00C00000,
-- offset: 0x00500000,
-+ .name = "usr cramfs",
-+ .size = 0x00C00000,
-+ .offset = 0x00500000,
- }, {
-- name: "local",
-- size: MTDPART_SIZ_FULL,
-- offset: 0x01100000,
-+ .name = "local",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = 0x01100000,
- }
- #else
- {
-- size: 0x00040000,
-- offset: 0,
-+ .size = 0x00040000,
-+ .offset = 0,
- }, {
-- size: 0x000c0000,
-- offset: MTDPART_OFS_APPEND,
-+ .size = 0x000c0000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- size: 0x00400000,
-- offset: MTDPART_OFS_APPEND,
-+ .size = 0x00400000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- #endif
- };
-@@ -441,206 +322,237 @@
-
- #ifdef CONFIG_SA1100_FRODO
- /* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
--#define FRODO_FLASH_SIZE 0x02000000
- static struct mtd_partition frodo_partitions[] =
- {
- {
-- name: "Boot Loader",
-- size: 0x00040000,
-- offset: 0x00000000
-+ .name = "bootloader",
-+ .size = 0x00040000,
-+ .offset = 0x00000000,
-+ .mask_flags = MTD_WRITEABLE
- }, {
-- name: "Parameter Block",
-- size: 0x00040000,
-- offset: MTDPART_OFS_APPEND
-+ .name = "bootloader params",
-+ .size = 0x00040000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE
- }, {
-- name: "Linux Kernel",
-- size: 0x00100000,
-- offset: MTDPART_OFS_APPEND
-+ .name = "kernel",
-+ .size = 0x00100000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE
- }, {
-- name: "Ramdisk",
-- size: 0x00680000,
-- offset: MTDPART_OFS_APPEND
-+ .name = "ramdisk",
-+ .size = 0x00400000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE
- }, {
-- name: "Flash File System",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND
-+ .name = "file system",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_GRAPHICSCLIENT
--#define GRAPHICSCLIENT_FLASH_SIZE 0x02000000
- static struct mtd_partition graphicsclient_partitions[] = {
- {
-- name: "zImage",
-- size: 0x100000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "zImage",
-+ .size = 0x100000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "ramdisk.gz",
-- size: 0x300000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "ramdisk.gz",
-+ .size = 0x300000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "User FS",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "User FS",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_GRAPHICSMASTER
--#define GRAPHICSMASTER_FLASH_SIZE 0x02000000
- static struct mtd_partition graphicsmaster_partitions[] = {
- {
-- name: "zImage",
-- size: 0x100000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "zImage",
-+ .size = 0x100000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
-- name: "ramdisk.gz",
-- size: 0x300000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "ramdisk.gz",
-+ .size = 0x300000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
-- name: "User FS",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "User FS",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #endif
-
--#ifdef CONFIG_SA1100_H3600
--#define H3600_FLASH_SIZE 0x02000000
--static struct mtd_partition h3600_partitions[] = {
-+#ifdef CONFIG_SA1100_H3XXX
-+static struct mtd_partition h3xxx_partitions[] = {
- {
-- name: "H3600 boot firmware",
-- size: 0x00040000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "H3XXX boot firmware",
-+ .size = 0x00040000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "H3600 kernel",
-- size: 0x00080000,
-- offset: 0x00040000,
-+#ifdef CONFIG_MTD_2PARTS_IPAQ
-+ .name = "H3XXX root jffs2",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = 0x00040000,
-+#else
-+ .name = "H3XXX kernel",
-+ .size = 0x00080000,
-+ .offset = 0x00040000,
- }, {
-- name: "H3600 params",
-- size: 0x00040000,
-- offset: 0x000C0000,
-+ .name = "H3XXX params",
-+ .size = 0x00040000,
-+ .offset = 0x000C0000,
- }, {
- #ifdef CONFIG_JFFS2_FS
-- name: "H3600 root jffs2",
-- size: MTDPART_SIZ_FULL,
-- offset: 0x00100000,
-+ .name = "H3XXX root jffs2",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = 0x00100000,
- #else
-- name: "H3600 initrd",
-- size: 0x00100000,
-- offset: 0x00100000,
-+ .name = "H3XXX initrd",
-+ .size = 0x00100000,
-+ .offset = 0x00100000,
- }, {
-- name: "H3600 root cramfs",
-- size: 0x00300000,
-- offset: 0x00200000,
-+ .name = "H3XXX root cramfs",
-+ .size = 0x00300000,
-+ .offset = 0x00200000,
- }, {
-- name: "H3600 usr cramfs",
-- size: 0x00800000,
-- offset: 0x00500000,
-+ .name = "H3XXX usr cramfs",
-+ .size = 0x00800000,
-+ .offset = 0x00500000,
- }, {
-- name: "H3600 usr local",
-- size: MTDPART_SIZ_FULL,
-- offset: 0x00d00000,
-+ .name = "H3XXX usr local",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = 0x00d00000,
-+#endif
- #endif
- }
- };
-
--static void h3600_set_vpp(struct map_info *map, int vpp)
-+static void h3xxx_set_vpp(struct map_info *map, int vpp)
- {
- assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, vpp);
- }
-+#else
-+#define h3xxx_set_vpp NULL
- #endif
-
- #ifdef CONFIG_SA1100_HACKKIT
--#define HACKKIT_FLASH_SIZE 0x01000000
- static struct mtd_partition hackkit_partitions[] = {
- {
-- name: "BLOB",
-- size: 0x00040000,
-- offset: 0x00000000,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "BLOB",
-+ .size = 0x00040000,
-+ .offset = 0x00000000,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "config",
-- size: 0x00040000,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "config",
-+ .size = 0x00040000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- name: "kernel",
-- size: 0x00100000,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "kernel",
-+ .size = 0x00100000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- name: "initrd",
-- size: 0x00180000,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "initrd",
-+ .size = 0x00180000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- name: "rootfs",
-- size: 0x700000,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "rootfs",
-+ .size = 0x700000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- name: "data",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "data",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_HUW_WEBPANEL
--#define HUW_WEBPANEL_FLASH_SIZE 0x01000000
- static struct mtd_partition huw_webpanel_partitions[] = {
- {
-- name: "Loader",
-- size: 0x00040000,
-- offset: 0,
-+ .name = "Loader",
-+ .size = 0x00040000,
-+ .offset = 0,
- }, {
-- name: "Sector 1",
-- size: 0x00040000,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "Sector 1",
-+ .size = 0x00040000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #endif
-
-+#ifdef CONFIG_SA1100_JORNADA56X
-+static struct mtd_partition jornada56x_partitions[] = {
-+ {
-+ .name = "bootldr",
-+ .size = 0x00040000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE,
-+ }, {
-+ .name = "rootfs",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
-+ }
-+};
-+
-+static void jornada56x_set_vpp(struct map_info *map, int vpp)
-+{
-+ if (vpp)
-+ GPSR = GPIO_GPIO26;
-+ else
-+ GPCR = GPIO_GPIO26;
-+ GPDR |= GPIO_GPIO26;
-+}
-+#else
-+#define jornada56x_set_vpp NULL
-+#endif
-+
- #ifdef CONFIG_SA1100_JORNADA720
--#define JORNADA720_FLASH_SIZE 0x02000000
- static struct mtd_partition jornada720_partitions[] = {
- {
-- name: "JORNADA720 boot firmware",
-- size: 0x00040000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "JORNADA720 boot firmware",
-+ .size = 0x00040000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "JORNADA720 kernel",
-- size: 0x000c0000,
-- offset: 0x00040000,
-+ .name = "JORNADA720 kernel",
-+ .size = 0x000c0000,
-+ .offset = 0x00040000,
- }, {
-- name: "JORNADA720 params",
-- size: 0x00040000,
-- offset: 0x00100000,
-+ .name = "JORNADA720 params",
-+ .size = 0x00040000,
-+ .offset = 0x00100000,
- }, {
-- name: "JORNADA720 initrd",
-- size: 0x00100000,
-- offset: 0x00140000,
-+ .name = "JORNADA720 initrd",
-+ .size = 0x00100000,
-+ .offset = 0x00140000,
- }, {
-- name: "JORNADA720 root cramfs",
-- size: 0x00300000,
-- offset: 0x00240000,
-+ .name = "JORNADA720 root cramfs",
-+ .size = 0x00300000,
-+ .offset = 0x00240000,
- }, {
-- name: "JORNADA720 usr cramfs",
-- size: 0x00800000,
-- offset: 0x00540000,
-+ .name = "JORNADA720 usr cramfs",
-+ .size = 0x00800000,
-+ .offset = 0x00540000,
- }, {
-- name: "JORNADA720 usr local",
-- size: 0, /* will expand to the end of the flash */
-- offset: 0x00d00000,
-+ .name = "JORNADA720 usr local",
-+ .size = 0, /* will expand to the end of the flash */
-+ .offset = 0x00d00000,
- }
- };
-
-@@ -652,540 +564,820 @@
- PPSR &= ~0x80;
- PPDR |= 0x80;
- }
--
--#endif
--
--#ifdef CONFIG_SA1100_NANOENGINE
--/* nanoEngine has one 28F320B3B Flash part in bank 0: */
--#define NANOENGINE_FLASH_SIZE 0x00400000
--static struct mtd_partition nanoengine_partitions[] = {
-- {
-- name: "nanoEngine boot firmware and parameter table",
-- size: 0x00010000, /* 32K */
-- offset: 0x00000000,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- },{
-- name: "kernel/initrd reserved",
-- size: 0x002f0000,
-- offset: 0x00010000,
-- },{
-- name: "experimental filesystem allocation",
-- size: 0x00100000,
-- offset: 0x00300000,
-- }
--};
-+#else
-+#define jornada720_set_vpp NULL
- #endif
-
- #ifdef CONFIG_SA1100_PANGOLIN
--#define PANGOLIN_FLASH_SIZE 0x04000000
- static struct mtd_partition pangolin_partitions[] = {
- {
-- name: "boot firmware",
-- size: 0x00080000,
-- offset: 0x00000000,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "boot firmware",
-+ .size = 0x00080000,
-+ .offset = 0x00000000,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "kernel",
-- size: 0x00100000,
-- offset: 0x00080000,
-+ .name = "kernel",
-+ .size = 0x00100000,
-+ .offset = 0x00080000,
- }, {
-- name: "initrd",
-- size: 0x00280000,
-- offset: 0x00180000,
-+ .name = "initrd",
-+ .size = 0x00280000,
-+ .offset = 0x00180000,
- }, {
-- name: "initrd-test",
-- size: 0x03C00000,
-- offset: 0x00400000,
-+ .name = "initrd-test",
-+ .size = 0x03C00000,
-+ .offset = 0x00400000,
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_PT_SYSTEM3
- /* erase size is 0x40000 == 256k partitions have to have this boundary */
--#define SYSTEM3_FLASH_SIZE 0x01000000
- static struct mtd_partition system3_partitions[] = {
- {
-- name: "BLOB",
-- size: 0x00040000,
-- offset: 0x00000000,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "BLOB",
-+ .size = 0x00040000,
-+ .offset = 0x00000000,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "config",
-- size: 0x00040000,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "config",
-+ .size = 0x00040000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- name: "kernel",
-- size: 0x00100000,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "kernel",
-+ .size = 0x00100000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- name: "root",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "root",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_SHANNON
--#define SHANNON_FLASH_SIZE 0x00400000
- static struct mtd_partition shannon_partitions[] = {
- {
-- name: "BLOB boot loader",
-- offset: 0,
-- size: 0x20000
-+ .name = "BLOB boot loader",
-+ .offset = 0,
-+ .size = 0x20000
- },
- {
-- name: "kernel",
-- offset: MTDPART_OFS_APPEND,
-- size: 0xe0000
-+ .name = "kernel",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = 0xe0000
- },
- {
-- name: "initrd",
-- offset: MTDPART_OFS_APPEND,
-- size: MTDPART_SIZ_FULL
-+ .name = "initrd",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = MTDPART_SIZ_FULL
- }
- };
-
- #endif
-
- #ifdef CONFIG_SA1100_SHERMAN
--#define SHERMAN_FLASH_SIZE 0x02000000
- static struct mtd_partition sherman_partitions[] = {
- {
-- size: 0x50000,
-- offset: 0,
-+ .size = 0x50000,
-+ .offset = 0,
- }, {
-- size: 0x70000,
-- offset: MTDPART_OFS_APPEND,
-+ .size = 0x70000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- size: 0x600000,
-- offset: MTDPART_OFS_APPEND,
-+ .size = 0x600000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- size: 0xA0000,
-- offset: MTDPART_OFS_APPEND,
-+ .size = 0xA0000,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_SIMPAD
--#define SIMPAD_FLASH_SIZE 0x02000000
- static struct mtd_partition simpad_partitions[] = {
- {
-- name: "SIMpad boot firmware",
-- size: 0x00080000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "SIMpad kernel",
-- size: 0x00100000,
-- offset: 0x00080000,
-- }, {
--#ifdef CONFIG_JFFS2_FS
-- name: "SIMpad root jffs2",
-- size: MTDPART_SIZ_FULL,
-- offset: 0x00180000,
--#else
-- name: "SIMpad initrd",
-- size: 0x00300000,
-- offset: 0x00180000,
-+ .name = "SIMpad boot firmware",
-+ .size = 0x00080000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "SIMpad root cramfs",
-- size: 0x00300000,
-- offset: 0x00480000,
-+ .name = "SIMpad kernel",
-+ .size = 0x00100000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- name: "SIMpad usr cramfs",
-- size: 0x005c0000,
-- offset: 0x00780000,
-+#ifdef CONFIG_ROOT_CRAMFS
-+ .name = "SIMpad root cramfs",
-+ .size =0x00D80000,
-+ .offset = MTDPART_OFS_APPEND
-+
- }, {
-- name: "SIMpad usr local",
-- size: MTDPART_SIZ_FULL,
-- offset: 0x00d40000,
-+ .name = "SIMpad local jffs2",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND
-+#else
-+ .name = "SIMpad root jffs2",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND
- #endif
- }
- };
- #endif /* CONFIG_SA1100_SIMPAD */
-
--#ifdef CONFIG_SA1100_SIMPUTER
--#define SIMPUTER_FLASH_SIZE 0x02000000
--static struct mtd_partition simputer_partitions[] = {
-- {
-- name: "blob+logo",
-- offset: 0,
-- size: 0x00040000
-- },
-- {
-- name: "kernel",
-- offset: MTDPART_OFS_APPEND,
-- size: 0x000C0000
-- },
-- {
-- name: "/(cramfs)",
-- offset: MTDPART_OFS_APPEND,
-- size: 0x00200000
-- },
-- {
-- name: "/usr/local(jffs2)",
-- offset: MTDPART_OFS_APPEND,
-- size: MTDPART_SIZ_FULL /* expand till the end */
-- }
--};
--#endif
--
- #ifdef CONFIG_SA1100_STORK
--#define STORK_FLASH_SIZE 0x02000000
- static struct mtd_partition stork_partitions[] = {
- {
-- name: "STORK boot firmware",
-- size: 0x00040000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "STORK boot firmware",
-+ .size = 0x00040000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "STORK params",
-- size: 0x00040000,
-- offset: 0x00040000,
-+ .name = "STORK params",
-+ .size = 0x00040000,
-+ .offset = 0x00040000,
- }, {
-- name: "STORK kernel",
-- size: 0x00100000,
-- offset: 0x00080000,
-+ .name = "STORK kernel",
-+ .size = 0x00100000,
-+ .offset = 0x00080000,
- }, {
- #ifdef CONFIG_JFFS2_FS
-- name: "STORK root jffs2",
-- offset: 0x00180000,
-- size: MTDPART_SIZ_FULL,
-+ .name = "STORK root jffs2",
-+ .offset = 0x00180000,
-+ .size = MTDPART_SIZ_FULL,
- #else
-- name: "STORK initrd",
-- size: 0x00100000,
-- offset: 0x00180000,
-+ .name = "STORK initrd",
-+ .size = 0x00100000,
-+ .offset = 0x00180000,
- }, {
-- name: "STORK root cramfs",
-- size: 0x00300000,
-- offset: 0x00280000,
-+ .name = "STORK root cramfs",
-+ .size = 0x00300000,
-+ .offset = 0x00280000,
- }, {
-- name: "STORK usr cramfs",
-- size: 0x00800000,
-- offset: 0x00580000,
-+ .name = "STORK usr cramfs",
-+ .size = 0x00800000,
-+ .offset = 0x00580000,
- }, {
-- name: "STORK usr local",
-- offset: 0x00d80000,
-- size: MTDPART_SIZ_FULL,
-+ .name = "STORK usr local",
-+ .offset = 0x00d80000,
-+ .size = MTDPART_SIZ_FULL,
- #endif
- }
- };
- #endif
-
-+#ifdef CONFIG_SA1100_TRIZEPS
-+static struct mtd_partition trizeps_partitions[] = {
-+ {
-+ .name = "Bootloader",
-+ .size = 0x00100000,
-+ .offset = 0,
-+ }, {
-+ .name = "Kernel",
-+ .size = 0x00100000,
-+ .offset = MTDPART_OFS_APPEND,
-+ }, {
-+ .name = "root",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
-+ }
-+};
-+#endif
-+
- #ifdef CONFIG_SA1100_YOPY
--#define YOPY_FLASH_SIZE 0x08000000
- static struct mtd_partition yopy_partitions[] = {
- {
-- name: "boot firmware",
-- size: 0x00040000,
-- offset: 0x00000000,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "boot firmware",
-+ .size = 0x00040000,
-+ .offset = 0x00000000,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "kernel",
-- size: 0x00080000,
-- offset: 0x00080000,
-+ .name = "kernel",
-+ .size = 0x00080000,
-+ .offset = 0x00080000,
- }, {
-- name: "initrd",
-- size: 0x00300000,
-- offset: 0x00100000,
-+ .name = "initrd",
-+ .size = 0x00300000,
-+ .offset = 0x00100000,
- }, {
-- name: "root",
-- size: 0x01000000,
-- offset: 0x00400000,
-+ .name = "root",
-+ .size = 0x01000000,
-+ .offset = 0x00400000,
- }
- };
- #endif
-
--extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
--extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
--
--static struct mtd_partition *parsed_parts;
--static struct mtd_info *mymtd;
--
--int __init sa1100_mtd_init(void)
-+static int __init sa1100_static_partitions(struct mtd_partition **parts)
- {
-- struct mtd_partition *parts;
-- int nb_parts = 0, ret;
-- int parsed_nr_parts = 0;
-- const char *part_type;
-- unsigned long base = -1UL;
--
-- /* Default flash buswidth */
-- sa1100_map.buswidth = (MSC0 & MSC_RBW) ? 2 : 4;
--
-- /*
-- * Static partition definition selection
-- */
-- part_type = "static";
-+ int nb_parts = 0;
-
--#ifdef CONFIG_SA1100_ADSAGC
-- if (machine_is_adsagc()) {
-- parts = adsagc_partitions;
-- nb_parts = ARRAY_SIZE(adsagc_partitions);
-- sa1100_map.size = ADSAGC_FLASH_SIZE;
-- sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4;
-- }
--#endif
- #ifdef CONFIG_SA1100_ADSBITSY
- if (machine_is_adsbitsy()) {
-- parts = adsbitsy_partitions;
-+ *parts = adsbitsy_partitions;
- nb_parts = ARRAY_SIZE(adsbitsy_partitions);
-- sa1100_map.size = ADSBITSY_FLASH_SIZE;
-- sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4;
-- }
--#endif
--#ifdef CONFIG_SA1100_ADSBITSYPLUS
-- if (machine_is_adsbitsyplus()) {
-- parts = adsbitsyplus_partitions;
-- nb_parts = ARRAY_SIZE(adsbitsyplus_partitions);
-- sa1100_map.size = ADSBITSYPLUS_FLASH_SIZE;
-- sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4;
- }
- #endif
- #ifdef CONFIG_SA1100_ASSABET
- if (machine_is_assabet()) {
-- parts = assabet_partitions;
-+ *parts = assabet_partitions;
- nb_parts = ARRAY_SIZE(assabet_partitions);
-- sa1100_map.size = ASSABET_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_BADGE4
- if (machine_is_badge4()) {
-- parts = badge4_partitions;
-+ *parts = badge4_partitions;
- nb_parts = ARRAY_SIZE(badge4_partitions);
-- sa1100_map.size = BADGE4_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_CERF
- if (machine_is_cerf()) {
-- parts = cerf_partitions;
-+ *parts = cerf_partitions;
- nb_parts = ARRAY_SIZE(cerf_partitions);
-- sa1100_map.size = CERF_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_CONSUS
- if (machine_is_consus()) {
-- parts = consus_partitions;
-+ *parts = consus_partitions;
- nb_parts = ARRAY_SIZE(consus_partitions);
-- sa1100_map.size = CONSUS_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_FLEXANET
- if (machine_is_flexanet()) {
-- parts = flexanet_partitions;
-+ *parts = flexanet_partitions;
- nb_parts = ARRAY_SIZE(flexanet_partitions);
-- sa1100_map.size = FLEXANET_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_FREEBIRD
- if (machine_is_freebird()) {
-- parts = freebird_partitions;
-+ *parts = freebird_partitions;
- nb_parts = ARRAY_SIZE(freebird_partitions);
-- sa1100_map.size = FREEBIRD_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_FRODO
- if (machine_is_frodo()) {
-- parts = frodo_partitions;
-+ *parts = frodo_partitions;
- nb_parts = ARRAY_SIZE(frodo_partitions);
-- sa1100_map.size = FRODO_FLASH_SIZE;
-- base = 0x00000000;
- }
- #endif
- #ifdef CONFIG_SA1100_GRAPHICSCLIENT
- if (machine_is_graphicsclient()) {
-- parts = graphicsclient_partitions;
-+ *parts = graphicsclient_partitions;
- nb_parts = ARRAY_SIZE(graphicsclient_partitions);
-- sa1100_map.size = GRAPHICSCLIENT_FLASH_SIZE;
-- sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4;
- }
- #endif
- #ifdef CONFIG_SA1100_GRAPHICSMASTER
- if (machine_is_graphicsmaster()) {
-- parts = graphicsmaster_partitions;
-+ *parts = graphicsmaster_partitions;
- nb_parts = ARRAY_SIZE(graphicsmaster_partitions);
-- sa1100_map.size = GRAPHICSMASTER_FLASH_SIZE;
-- sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4;
- }
- #endif
--#ifdef CONFIG_SA1100_H3600
-- if (machine_is_h3600()) {
-- parts = h3600_partitions;
-- nb_parts = ARRAY_SIZE(h3600_partitions);
-- sa1100_map.size = H3600_FLASH_SIZE;
-- sa1100_map.set_vpp = h3600_set_vpp;
-+#ifdef CONFIG_SA1100_H3XXX
-+ if (machine_is_h3xxx()) {
-+ *parts = h3xxx_partitions;
-+ nb_parts = ARRAY_SIZE(h3xxx_partitions);
- }
- #endif
- #ifdef CONFIG_SA1100_HACKKIT
- if (machine_is_hackkit()) {
-- parts = hackkit_partitions;
-+ *parts = hackkit_partitions;
- nb_parts = ARRAY_SIZE(hackkit_partitions);
-- sa1100_map.size = HACKKIT_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_HUW_WEBPANEL
- if (machine_is_huw_webpanel()) {
-- parts = huw_webpanel_partitions;
-+ *parts = huw_webpanel_partitions;
- nb_parts = ARRAY_SIZE(huw_webpanel_partitions);
-- sa1100_map.size = HUW_WEBPANEL_FLASH_SIZE;
-+ }
-+#endif
-+#ifdef CONFIG_SA1100_JORNADA56X
-+ if (machine_is_jornada56x()) {
-+ *parts = jornada56x_partitions;
-+ nb_parts = ARRAY_SIZE(jornada56x_partitions);
- }
- #endif
- #ifdef CONFIG_SA1100_JORNADA720
- if (machine_is_jornada720()) {
-- parts = jornada720_partitions;
-+ *parts = jornada720_partitions;
- nb_parts = ARRAY_SIZE(jornada720_partitions);
-- sa1100_map.size = JORNADA720_FLASH_SIZE;
-- sa1100_map.set_vpp = jornada720_set_vpp;
-- }
--#endif
--#ifdef CONFIG_SA1100_NANOENGINE
-- if (machine_is_nanoengine()) {
-- parts = nanoengine_partitions;
-- nb_parts = ARRAY_SIZE(nanoengine_partitions);
-- sa1100_map.size = NANOENGINE_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_PANGOLIN
- if (machine_is_pangolin()) {
-- parts = pangolin_partitions;
-+ *parts = pangolin_partitions;
- nb_parts = ARRAY_SIZE(pangolin_partitions);
-- sa1100_map.size = PANGOLIN_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_PT_SYSTEM3
- if (machine_is_pt_system3()) {
-- parts = system3_partitions;
-+ *parts = system3_partitions;
- nb_parts = ARRAY_SIZE(system3_partitions);
-- sa1100_map.size = SYSTEM3_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_SHANNON
- if (machine_is_shannon()) {
-- parts = shannon_partitions;
-+ *parts = shannon_partitions;
- nb_parts = ARRAY_SIZE(shannon_partitions);
-- sa1100_map.size = SHANNON_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_SHERMAN
- if (machine_is_sherman()) {
-- parts = sherman_partitions;
-+ *parts = sherman_partitions;
- nb_parts = ARRAY_SIZE(sherman_partitions);
-- sa1100_map.size = SHERMAN_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_SIMPAD
- if (machine_is_simpad()) {
-- parts = simpad_partitions;
-+ *parts = simpad_partitions;
- nb_parts = ARRAY_SIZE(simpad_partitions);
-- sa1100_map.size = SIMPAD_FLASH_SIZE;
-- }
--#endif
--#ifdef CONFIG_SA1100_SIMPUTER
-- if (machine_is_simputer()) {
-- parts = simputer_partitions;
-- nb_parts = ARRAY_SIZE(simputer_partitions);
-- sa1100_map.size = SIMPUTER_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_STORK
- if (machine_is_stork()) {
-- parts = stork_partitions;
-+ *parts = stork_partitions;
- nb_parts = ARRAY_SIZE(stork_partitions);
-- sa1100_map.size = STORK_FLASH_SIZE;
-+ }
-+#endif
-+#ifdef CONFIG_SA1100_TRIZEPS
-+ if (machine_is_trizeps()) {
-+ *parts = trizeps_partitions;
-+ nb_parts = ARRAY_SIZE(trizeps_partitions);
- }
- #endif
- #ifdef CONFIG_SA1100_YOPY
- if (machine_is_yopy()) {
-- parts = yopy_partitions;
-+ *parts = yopy_partitions;
- nb_parts = ARRAY_SIZE(yopy_partitions);
-- sa1100_map.size = YOPY_FLASH_SIZE;
- }
- #endif
-
-+ return nb_parts;
-+}
-+#endif
-+
-+struct sa_info {
-+ unsigned long base;
-+ unsigned long size;
-+ int width;
-+ void (*set_vpp)(struct map_info *, int);
-+ char name[16];
-+ struct map_info *map;
-+ struct mtd_info *mtd;
-+};
-+
-+#define NR_SUBMTD 4
-+
-+static struct sa_info info[NR_SUBMTD];
-+
-+static int __init sa1100_setup_mtd(struct sa_info *sa, int nr, struct mtd_info **rmtd)
-+{
-+ struct mtd_info *subdev[nr];
-+ struct map_info *maps;
-+ int i, found = 0, ret = 0;
-+
- /*
-- * For simple flash devices, use ioremap to map the flash.
-+ * Allocate the map_info structs in one go.
- */
-- if (base != (unsigned long)-1) {
-- if (!request_mem_region(base, sa1100_map.size, "flash"))
-- return -EBUSY;
-- sa1100_map.map_priv_2 = base;
-- sa1100_map.map_priv_1 = (unsigned long)
-- ioremap(base, sa1100_map.size);
-+ maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
-+ if (!maps)
-+ return -ENOMEM;
-+
-+ memset(maps, 0, sizeof(struct map_info) * nr);
-+
-+ /*
-+ * Claim and then map the memory regions.
-+ */
-+ for (i = 0; i < nr; i++) {
-+ if (sa[i].base == (unsigned long)-1)
-+ break;
-+
-+ sa[i].map = maps + i;
-+ sa[i].map->name = sa[i].name;
-+ sprintf(sa[i].name, "sa1100-%d", i);
-+
-+ if (!request_mem_region(sa[i].base, sa[i].size, sa[i].name)) {
-+ i -= 1;
-+ ret = -EBUSY;
-+ break;
-+ }
-+
-+ sa[i].map->virt = ioremap(sa[i].base, sa[i].size);
-+ if (!sa[i].map->virt) {
- ret = -ENOMEM;
-- if (!sa1100_map.map_priv_1)
-- goto out_err;
-+ break;
- }
-
-+ sa[i].map->phys = sa[i].base;
-+ sa[i].map->set_vpp = sa[i].set_vpp;
-+ sa[i].map->bankwidth = sa[i].width;
-+ sa[i].map->size = sa[i].size;
-+
-+ simple_map_init(sa[i].map);
-+
- /*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
- */
-- printk(KERN_NOTICE "SA1100 flash: probing %d-bit flash bus\n", sa1100_map.buswidth*8);
-- mymtd = do_map_probe("jedec_probe", &sa1100_map);
-- if (!mymtd)
-- mymtd = do_map_probe("cfi_probe", &sa1100_map);
-+ sa[i].mtd = do_map_probe("cfi_probe", sa[i].map);
-+ if (sa[i].mtd == NULL) {
- ret = -ENXIO;
-- if (!mymtd)
-- goto out_err;
-- mymtd->module = THIS_MODULE;
-+ break;
-+ }
-+ sa[i].mtd->owner = THIS_MODULE;
-+ subdev[i] = sa[i].mtd;
-+
-+ printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
-+ "%d-bit\n", sa[i].base, sa[i].mtd->size >> 20,
-+ sa[i].width * 8);
-+ found += 1;
-+ }
-
- /*
-- * Dynamic partition selection stuff (might override the static ones)
-+ * ENXIO is special. It means we didn't find a chip when
-+ * we probed. We need to tear down the mapping, free the
-+ * resource and mark it as such.
- */
--#ifdef CONFIG_MTD_REDBOOT_PARTS
-- if (parsed_nr_parts == 0) {
-- int ret = parse_redboot_partitions(mymtd, &parsed_parts);
-+ if (ret == -ENXIO) {
-+ iounmap(sa[i].map->virt);
-+ sa[i].map->virt = NULL;
-+ release_mem_region(sa[i].base, sa[i].size);
-+ }
-
-- if (ret > 0) {
-- part_type = "RedBoot";
-- parsed_nr_parts = ret;
-+ /*
-+ * If we found one device, don't bother with concat support.
-+ * If we found multiple devices, use concat if we have it
-+ * available, otherwise fail.
-+ */
-+ if (ret == 0 || ret == -ENXIO) {
-+ if (found == 1) {
-+ *rmtd = subdev[0];
-+ ret = 0;
-+ } else if (found > 1) {
-+ /*
-+ * We detected multiple devices. Concatenate
-+ * them together.
-+ */
-+#ifdef CONFIG_MTD_CONCAT
-+ *rmtd = mtd_concat_create(subdev, found,
-+ "sa1100");
-+ if (*rmtd == NULL)
-+ ret = -ENXIO;
-+#else
-+ printk(KERN_ERR "SA1100 flash: multiple devices "
-+ "found but MTD concat support disabled.\n");
-+ ret = -ENXIO;
-+#endif
-+ }
- }
-+
-+ /*
-+ * If we failed, clean up.
-+ */
-+ if (ret) {
-+ do {
-+ if (sa[i].mtd)
-+ map_destroy(sa[i].mtd);
-+ if (sa[i].map->virt)
-+ iounmap(sa[i].map->virt);
-+ release_mem_region(sa[i].base, sa[i].size);
-+ } while (i-- > 0);
-+
-+ kfree(maps);
- }
-+
-+ return ret;
-+}
-+
-+static void __exit sa1100_destroy_mtd(struct sa_info *sa, struct mtd_info *mtd)
-+{
-+ int i;
-+
-+ del_mtd_partitions(mtd);
-+
-+#ifdef CONFIG_MTD_CONCAT
-+ if (mtd != sa[0].mtd)
-+ mtd_concat_destroy(mtd);
- #endif
--#ifdef CONFIG_MTD_CMDLINE_PARTS
-- if (parsed_nr_parts == 0) {
-- int ret = parse_cmdline_partitions(mymtd, &parsed_parts, "sa1100");
-- if (ret > 0) {
-- part_type = "Command Line";
-- parsed_nr_parts = ret;
-+
-+ for (i = NR_SUBMTD; i >= 0; i--) {
-+ if (sa[i].mtd)
-+ map_destroy(sa[i].mtd);
-+ if (sa[i].map->virt)
-+ iounmap(sa[i].map->virt);
-+ release_mem_region(sa[i].base, sa[i].size);
- }
-+ kfree(sa[0].map);
-+}
-+
-+/*
-+ * A Thought: can we automatically detect the flash?
-+ * - Check to see if the region is busy (yes -> failure)
-+ * - Is the MSC setup for flash (no -> failure)
-+ * - Probe for flash
-+ */
-+static void __init sa1100_probe_one_cs(unsigned int msc, unsigned long phys)
-+{
-+ struct map_info map;
-+ struct mtd_info *mtd;
-+
-+ printk(KERN_INFO "* Probing 0x%08lx: MSC = 0x%04x %d bit ",
-+ phys, msc & 0xffff, msc & MSC_RBW ? 16 : 32);
-+
-+ if (check_mem_region(phys, 0x08000000)) {
-+ printk("busy\n");
-+ return;
- }
--#endif
-
-- if (parsed_nr_parts > 0) {
-- parts = parsed_parts;
-- nb_parts = parsed_nr_parts;
-+ if ((msc & 3) == 1) {
-+ printk("wrong type\n");
-+ return;
- }
-
-- if (nb_parts == 0) {
-- printk(KERN_NOTICE "SA1100 flash: no partition info available, registering whole flash at once\n");
-- add_mtd_device(mymtd);
-- } else {
-- printk(KERN_NOTICE "Using %s partition definition\n", part_type);
-- add_mtd_partitions(mymtd, parts, nb_parts);
-+ memset(&map, 0, sizeof(struct map_info));
-+
-+ map.name = "Probe";
-+ map.bankwidth = msc & MSC_RBW ? 2 : 4;
-+ map.size = SZ_1M;
-+ map.phys = phys;
-+ map.virt = ioremap(phys, SZ_1M);
-+ if (map.virt == NULL)
-+ goto fail;
-+
-+ simple_map_init(&map);
-+
-+ /* Shame cfi_probe blurts out kernel messages... */
-+ mtd = do_map_probe("cfi_probe", &map);
-+ if (mtd)
-+ map_destroy(mtd);
-+ iounmap(map.virt);
-+
-+ if (!mtd)
-+ goto fail;
-+
-+ printk("pass\n");
-+ return;
-+
-+ fail:
-+ printk("failed\n");
-+}
-+
-+static void __init sa1100_probe_flash(void)
-+{
-+ printk(KERN_INFO "-- SA11xx Flash probe. Please report results.\n");
-+ sa1100_probe_one_cs(MSC0, SA1100_CS0_PHYS);
-+ sa1100_probe_one_cs(MSC0 >> 16, SA1100_CS1_PHYS);
-+ sa1100_probe_one_cs(MSC1, SA1100_CS2_PHYS);
-+ sa1100_probe_one_cs(MSC1 >> 16, SA1100_CS3_PHYS);
-+ sa1100_probe_one_cs(MSC2, SA1100_CS4_PHYS);
-+ sa1100_probe_one_cs(MSC2 >> 16, SA1100_CS5_PHYS);
-+ printk(KERN_INFO "-- SA11xx Flash probe complete.\n");
-+}
-+
-+static int __init sa1100_locate_flash(void)
-+{
-+ int i, nr = -ENODEV;
-+
-+ sa1100_probe_flash();
-+
-+ if (machine_is_adsbitsy()) {
-+ info[0].base = SA1100_CS1_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_assabet()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ info[1].base = SA1100_CS1_PHYS; /* neponset */
-+ info[1].size = SZ_32M;
-+ nr = 2;
-+ }
-+ if (machine_is_badge4()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_64M;
-+ nr = 1;
-+ }
-+ if (machine_is_cerf()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_consus()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_flexanet()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_freebird()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_frodo()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_graphicsclient()) {
-+ info[0].base = SA1100_CS1_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_graphicsmaster()) {
-+ info[0].base = SA1100_CS1_PHYS;
-+ info[0].size = SZ_16M;
-+ nr = 1;
-+ }
-+ if (machine_is_h3xxx()) {
-+ info[0].set_vpp = h3xxx_set_vpp;
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_huw_webpanel()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_16M;
-+ nr = 1;
-+ }
-+ if (machine_is_itsy()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_jornada56x()) {
-+ info[0].set_vpp = jornada56x_set_vpp;
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_jornada720()) {
-+ info[0].set_vpp = jornada720_set_vpp;
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_nanoengine()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[1].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_pangolin()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_64M;
-+ nr = 1;
-+ }
-+ if (machine_is_pfs168()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_pleb()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_4M;
-+ info[1].base = SA1100_CS1_PHYS;
-+ info[1].size = SZ_4M;
-+ nr = 2;
-+ }
-+ if (machine_is_pt_system3()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_16M;
-+ nr = 1;
-+ }
-+ if (machine_is_shannon()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_4M;
-+ nr = 1;
-+ }
-+ if (machine_is_sherman()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_simpad()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_16M;
-+ info[1].base = SA1100_CS1_PHYS;
-+ info[1].size = SZ_16M;
-+ nr = 2;
-+ }
-+ if (machine_is_stork()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_trizeps()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_16M;
-+ nr = 1;
-+ }
-+ if (machine_is_victor()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_2M;
-+ nr = 1;
-+ }
-+ if (machine_is_yopy()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_64M;
-+ info[1].base = SA1100_CS1_PHYS;
-+ info[1].size = SZ_64M;
-+ nr = 2;
- }
-- return 0;
-
-- out_err:
-- if (sa1100_map.map_priv_2 != -1) {
-- iounmap((void *)sa1100_map.map_priv_1);
-- release_mem_region(sa1100_map.map_priv_2, sa1100_map.size);
-+ if (nr < 0)
-+ return nr;
-+
-+ /*
-+ * Retrieve the bankwidth from the MSC registers.
-+ * We currently only implement CS0 and CS1 here.
-+ */
-+ for (i = 0; i < nr; i++) {
-+ switch (info[i].base) {
-+ default:
-+ printk(KERN_WARNING "SA1100 flash: unknown base address "
-+ "0x%08lx, assuming CS0\n", info[i].base);
-+ case SA1100_CS0_PHYS:
-+ info[i].width = (MSC0 & MSC_RBW) ? 2 : 4;
-+ break;
-+
-+ case SA1100_CS1_PHYS:
-+ info[i].width = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
-+ break;
- }
-- return ret;
-+ }
-+
-+ return nr;
- }
-
--static void __exit sa1100_mtd_cleanup(void)
-+static struct mtd_partition *parsed_parts;
-+const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
-+
-+static void __init sa1100_locate_partitions(struct mtd_info *mtd)
- {
-- if (mymtd) {
-- del_mtd_partitions(mymtd);
-- map_destroy(mymtd);
-- if (parsed_parts)
-- kfree(parsed_parts);
-+ const char *part_type = NULL;
-+ int nr_parts = 0;
-+
-+ do {
-+ /*
-+ * Partition selection stuff.
-+ */
-+#ifdef CONFIG_MTD_PARTITIONS
-+ nr_parts = parse_mtd_partitions(mtd, part_probes, &parsed_parts, 0);
-+ if (nr_parts > 0) {
-+ part_type = "dynamic";
-+ break;
- }
-- if (sa1100_map.map_priv_2 != -1) {
-- iounmap((void *)sa1100_map.map_priv_1);
-- release_mem_region(sa1100_map.map_priv_2, sa1100_map.size);
-+#endif
-+#ifdef CONFIG_MTD_SA1100_STATICMAP
-+ nr_parts = sa1100_static_partitions(&parsed_parts);
-+ if (nr_parts > 0) {
-+ part_type = "static";
-+ break;
-+ }
-+#endif
-+ } while (0);
-+
-+ if (nr_parts == 0) {
-+ printk(KERN_NOTICE "SA1100 flash: no partition info "
-+ "available, registering whole flash\n");
-+ add_mtd_device(mtd);
-+ } else {
-+ printk(KERN_NOTICE "SA1100 flash: using %s partition "
-+ "definition\n", part_type);
-+ add_mtd_partitions(mtd, parsed_parts, nr_parts);
- }
-+
-+ /* Always succeeds. */
-+}
-+
-+static void __exit sa1100_destroy_partitions(void)
-+{
-+ if (parsed_parts)
-+ kfree(parsed_parts);
-+}
-+
-+static struct mtd_info *mymtd;
-+
-+static int __init sa1100_mtd_init(void)
-+{
-+ int ret;
-+ int nr;
-+
-+ nr = sa1100_locate_flash();
-+ if (nr < 0)
-+ return nr;
-+
-+ ret = sa1100_setup_mtd(info, nr, &mymtd);
-+ if (ret == 0)
-+ sa1100_locate_partitions(mymtd);
-+
-+ return ret;
-+}
-+
-+static void __exit sa1100_mtd_cleanup(void)
-+{
-+ sa1100_destroy_mtd(info, mymtd);
-+ sa1100_destroy_partitions();
- }
-
- module_init(sa1100_mtd_init);
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/sbc8240.c
-@@ -0,0 +1,247 @@
-+/*
-+ * Handle mapping of the flash memory access routines on the SBC8240 board.
-+ *
-+ * Carolyn Smith, Tektronix, Inc.
-+ *
-+ * This code is GPLed
-+ *
-+ * $Id: sbc8240.c,v 1.4 2004/07/12 22:38:29 dwmw2 Exp $
-+ *
-+ */
-+
-+/*
-+ * The SBC8240 has 2 flash banks.
-+ * Bank 0 is a 512 KiB AMD AM29F040B; 8 x 64 KiB sectors.
-+ * It contains the U-Boot code (7 sectors) and the environment (1 sector).
-+ * Bank 1 is 4 x 1 MiB AMD AM29LV800BT; 15 x 64 KiB sectors, 1 x 32 KiB sector,
-+ * 2 x 8 KiB sectors, 1 x 16 KiB sectors.
-+ * Both parts are JEDEC compatible.
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <asm/io.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/cfi.h>
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+#include <linux/mtd/partitions.h>
-+#endif
-+
-+#define DEBUG
-+
-+#ifdef DEBUG
-+# define debugk(fmt,args...) printk(fmt ,##args)
-+#else
-+# define debugk(fmt,args...)
-+#endif
-+
-+
-+#define WINDOW_ADDR0 0xFFF00000 /* 512 KiB */
-+#define WINDOW_SIZE0 0x00080000
-+#define BUSWIDTH0 1
-+
-+#define WINDOW_ADDR1 0xFF000000 /* 4 MiB */
-+#define WINDOW_SIZE1 0x00400000
-+#define BUSWIDTH1 8
-+
-+#define MSG_PREFIX "sbc8240:" /* prefix for our printk()'s */
-+#define MTDID "sbc8240-%d" /* for mtdparts= partitioning */
-+
-+
-+static struct map_info sbc8240_map[2] = {
-+ {
-+ .name = "sbc8240 Flash Bank #0",
-+ .size = WINDOW_SIZE0,
-+ .bankwidth = BUSWIDTH0,
-+ },
-+ {
-+ .name = "sbc8240 Flash Bank #1",
-+ .size = WINDOW_SIZE1,
-+ .bankwidth = BUSWIDTH1,
-+ }
-+};
-+
-+#define NUM_FLASH_BANKS (sizeof(sbc8240_map) / sizeof(struct map_info))
-+
-+/*
-+ * The following defines the partition layout of SBC8240 boards.
-+ *
-+ * See include/linux/mtd/partitions.h for definition of the
-+ * mtd_partition structure.
-+ *
-+ * The *_max_flash_size is the maximum possible mapped flash size
-+ * which is not necessarily the actual flash size. It must correspond
-+ * to the value specified in the mapping definition defined by the
-+ * "struct map_desc *_io_desc" for the corresponding machine.
-+ */
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+
-+static struct mtd_partition sbc8240_uboot_partitions [] = {
-+ /* Bank 0 */
-+ {
-+ .name = "U-boot", /* U-Boot Firmware */
-+ .offset = 0,
-+ .size = 0x00070000, /* 7 x 64 KiB sectors */
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
-+ },
-+ {
-+ .name = "environment", /* U-Boot environment */
-+ .offset = 0x00070000,
-+ .size = 0x00010000, /* 1 x 64 KiB sector */
-+ },
-+};
-+
-+static struct mtd_partition sbc8240_fs_partitions [] = {
-+ {
-+ .name = "jffs", /* JFFS filesystem */
-+ .offset = 0,
-+ .size = 0x003C0000, /* 4 * 15 * 64KiB */
-+ },
-+ {
-+ .name = "tmp32",
-+ .offset = 0x003C0000,
-+ .size = 0x00020000, /* 4 * 32KiB */
-+ },
-+ {
-+ .name = "tmp8a",
-+ .offset = 0x003E0000,
-+ .size = 0x00008000, /* 4 * 8KiB */
-+ },
-+ {
-+ .name = "tmp8b",
-+ .offset = 0x003E8000,
-+ .size = 0x00008000, /* 4 * 8KiB */
-+ },
-+ {
-+ .name = "tmp16",
-+ .offset = 0x003F0000,
-+ .size = 0x00010000, /* 4 * 16KiB */
-+ }
-+};
-+
-+#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
-+
-+/* trivial struct to describe partition information */
-+struct mtd_part_def
-+{
-+ int nums;
-+ unsigned char *type;
-+ struct mtd_partition* mtd_part;
-+};
-+
-+static struct mtd_info *sbc8240_mtd[NUM_FLASH_BANKS];
-+static struct mtd_part_def sbc8240_part_banks[NUM_FLASH_BANKS];
-+
-+
-+#endif /* CONFIG_MTD_PARTITIONS */
-+
-+
-+int __init init_sbc8240_mtd (void)
-+{
-+ static struct _cjs {
-+ u_long addr;
-+ u_long size;
-+ } pt[NUM_FLASH_BANKS] = {
-+ {
-+ .addr = WINDOW_ADDR0,
-+ .size = WINDOW_SIZE0
-+ },
-+ {
-+ .addr = WINDOW_ADDR1,
-+ .size = WINDOW_SIZE1
-+ },
-+ };
-+
-+ int devicesfound = 0;
-+ int i;
-+
-+ for (i = 0; i < NUM_FLASH_BANKS; i++) {
-+ printk (KERN_NOTICE MSG_PREFIX
-+ "Probing 0x%08lx at 0x%08lx\n", pt[i].size, pt[i].addr);
-+
-+ sbc8240_map[i].map_priv_1 =
-+ (unsigned long) ioremap (pt[i].addr, pt[i].size);
-+ if (!sbc8240_map[i].map_priv_1) {
-+ printk (MSG_PREFIX "failed to ioremap\n");
-+ return -EIO;
-+ }
-+ simple_map_init(&sbc8240_mtd[i]);
-+
-+ sbc8240_mtd[i] = do_map_probe("jedec_probe", &sbc8240_map[i]);
-+
-+ if (sbc8240_mtd[i]) {
-+ sbc8240_mtd[i]->module = THIS_MODULE;
-+ devicesfound++;
-+ }
-+ }
-+
-+ if (!devicesfound) {
-+ printk(KERN_NOTICE MSG_PREFIX
-+ "No suppported flash chips found!\n");
-+ return -ENXIO;
-+ }
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+ sbc8240_part_banks[0].mtd_part = sbc8240_uboot_partitions;
-+ sbc8240_part_banks[0].type = "static image";
-+ sbc8240_part_banks[0].nums = NB_OF(sbc8240_uboot_partitions);
-+ sbc8240_part_banks[1].mtd_part = sbc8240_fs_partitions;
-+ sbc8240_part_banks[1].type = "static file system";
-+ sbc8240_part_banks[1].nums = NB_OF(sbc8240_fs_partitions);
-+
-+ for (i = 0; i < NUM_FLASH_BANKS; i++) {
-+
-+ if (!sbc8240_mtd[i]) continue;
-+ if (sbc8240_part_banks[i].nums == 0) {
-+ printk (KERN_NOTICE MSG_PREFIX
-+ "No partition info available, registering whole device\n");
-+ add_mtd_device(sbc8240_mtd[i]);
-+ } else {
-+ printk (KERN_NOTICE MSG_PREFIX
-+ "Using %s partition definition\n", sbc8240_part_banks[i].mtd_part->name);
-+ add_mtd_partitions (sbc8240_mtd[i],
-+ sbc8240_part_banks[i].mtd_part,
-+ sbc8240_part_banks[i].nums);
-+ }
-+ }
-+#else
-+ printk(KERN_NOTICE MSG_PREFIX
-+ "Registering %d flash banks at once\n", devicesfound);
-+
-+ for (i = 0; i < devicesfound; i++) {
-+ add_mtd_device(sbc8240_mtd[i]);
-+ }
-+#endif /* CONFIG_MTD_PARTITIONS */
-+
-+ return devicesfound == 0 ? -ENXIO : 0;
-+}
-+
-+static void __exit cleanup_sbc8240_mtd (void)
-+{
-+ int i;
-+
-+ for (i = 0; i < NUM_FLASH_BANKS; i++) {
-+ if (sbc8240_mtd[i]) {
-+ del_mtd_device (sbc8240_mtd[i]);
-+ map_destroy (sbc8240_mtd[i]);
-+ }
-+ if (sbc8240_map[i].map_priv_1) {
-+ iounmap ((void *) sbc8240_map[i].map_priv_1);
-+ sbc8240_map[i].map_priv_1 = 0;
-+ }
-+ }
-+}
-+
-+module_init (init_sbc8240_mtd);
-+module_exit (cleanup_sbc8240_mtd);
-+
-+MODULE_LICENSE ("GPL");
-+MODULE_AUTHOR ("Carolyn Smith <carolyn.smith@tektronix.com>");
-+MODULE_DESCRIPTION ("MTD map driver for SBC8240 boards");
-+
---- linux-2.4.21/drivers/mtd/maps/sbc_gxx.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/sbc_gxx.c
-@@ -17,7 +17,7 @@
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
-
-- $Id: sbc_gxx.c,v 1.21 2003/01/24 13:40:14 dwmw2 Exp $
-+ $Id: sbc_gxx.c,v 1.34 2005/01/12 22:34:35 gleixner Exp $
-
- The SBC-MediaGX / SBC-GXx has up to 16 MiB of
- Intel StrataFlash (28F320/28F640) in x8 mode.
-@@ -84,21 +84,21 @@
- // Globals
-
- static volatile int page_in_window = -1; // Current page in window.
--static unsigned long iomapadr;
--static spinlock_t sbc_gxx_spin = SPIN_LOCK_UNLOCKED;
-+static void __iomem *iomapadr;
-+static DEFINE_SPINLOCK(sbc_gxx_spin);
-
- /* partition_info gives details on the logical partitions that the split the
- * single flash device into. If the size if zero we use up to the end of the
- * device. */
- static struct mtd_partition partition_info[]={
-- { name: "SBC-GXx flash boot partition",
-- offset: 0,
-- size: BOOT_PARTITION_SIZE_KiB*1024 },
-- { name: "SBC-GXx flash data partition",
-- offset: BOOT_PARTITION_SIZE_KiB*1024,
-- size: (DATA_PARTITION_SIZE_KiB)*1024 },
-- { name: "SBC-GXx flash application partition",
-- offset: (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 }
-+ { .name = "SBC-GXx flash boot partition",
-+ .offset = 0,
-+ .size = BOOT_PARTITION_SIZE_KiB*1024 },
-+ { .name = "SBC-GXx flash data partition",
-+ .offset = BOOT_PARTITION_SIZE_KiB*1024,
-+ .size = (DATA_PARTITION_SIZE_KiB)*1024 },
-+ { .name = "SBC-GXx flash application partition",
-+ .offset = (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 }
- };
-
- #define NUM_PARTITIONS 3
-@@ -114,32 +114,12 @@
- }
-
-
--static __u8 sbc_gxx_read8(struct map_info *map, unsigned long ofs)
--{
-- __u8 ret;
-- spin_lock(&sbc_gxx_spin);
-- sbc_gxx_page(map, ofs);
-- ret = readb(iomapadr + (ofs & WINDOW_MASK));
-- spin_unlock(&sbc_gxx_spin);
-- return ret;
--}
--
--static __u16 sbc_gxx_read16(struct map_info *map, unsigned long ofs)
--{
-- __u16 ret;
-- spin_lock(&sbc_gxx_spin);
-- sbc_gxx_page(map, ofs);
-- ret = readw(iomapadr + (ofs & WINDOW_MASK));
-- spin_unlock(&sbc_gxx_spin);
-- return ret;
--}
--
--static __u32 sbc_gxx_read32(struct map_info *map, unsigned long ofs)
-+static map_word sbc_gxx_read8(struct map_info *map, unsigned long ofs)
- {
-- __u32 ret;
-+ map_word ret;
- spin_lock(&sbc_gxx_spin);
- sbc_gxx_page(map, ofs);
-- ret = readl(iomapadr + (ofs & WINDOW_MASK));
-+ ret.x[0] = readb(iomapadr + (ofs & WINDOW_MASK));
- spin_unlock(&sbc_gxx_spin);
- return ret;
- }
-@@ -155,33 +135,17 @@
- sbc_gxx_page(map, from);
- memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen);
- spin_unlock(&sbc_gxx_spin);
-- (__u8*)to += thislen;
-+ to += thislen;
- from += thislen;
- len -= thislen;
- }
- }
-
--static void sbc_gxx_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- spin_lock(&sbc_gxx_spin);
-- sbc_gxx_page(map, adr);
-- writeb(d, iomapadr + (adr & WINDOW_MASK));
-- spin_unlock(&sbc_gxx_spin);
--}
--
--static void sbc_gxx_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- spin_lock(&sbc_gxx_spin);
-- sbc_gxx_page(map, adr);
-- writew(d, iomapadr + (adr & WINDOW_MASK));
-- spin_unlock(&sbc_gxx_spin);
--}
--
--static void sbc_gxx_write32(struct map_info *map, __u32 d, unsigned long adr)
-+static void sbc_gxx_write8(struct map_info *map, map_word d, unsigned long adr)
- {
- spin_lock(&sbc_gxx_spin);
- sbc_gxx_page(map, adr);
-- writel(d, iomapadr + (adr & WINDOW_MASK));
-+ writeb(d.x[0], iomapadr + (adr & WINDOW_MASK));
- spin_unlock(&sbc_gxx_spin);
- }
-
-@@ -203,19 +167,16 @@
- }
-
- static struct map_info sbc_gxx_map = {
-- name: "SBC-GXx flash",
-- size: MAX_SIZE_KiB*1024, /* this must be set to a maximum possible amount
-+ .name = "SBC-GXx flash",
-+ .phys = NO_XIP,
-+ .size = MAX_SIZE_KiB*1024, /* this must be set to a maximum possible amount
- of flash so the cfi probe routines find all
- the chips */
-- buswidth: 1,
-- read8: sbc_gxx_read8,
-- read16: sbc_gxx_read16,
-- read32: sbc_gxx_read32,
-- copy_from: sbc_gxx_copy_from,
-- write8: sbc_gxx_write8,
-- write16: sbc_gxx_write16,
-- write32: sbc_gxx_write32,
-- copy_to: sbc_gxx_copy_to
-+ .bankwidth = 1,
-+ .read = sbc_gxx_read8,
-+ .copy_from = sbc_gxx_copy_from,
-+ .write = sbc_gxx_write8,
-+ .copy_to = sbc_gxx_copy_to
- };
-
- /* MTD device for all of the flash. */
-@@ -228,26 +189,27 @@
- map_destroy( all_mtd );
- }
-
-- iounmap((void *)iomapadr);
-+ iounmap(iomapadr);
- release_region(PAGE_IO,PAGE_IO_SIZE);
- }
-
--int __init init_sbc_gxx(void)
-+static int __init init_sbc_gxx(void)
- {
-- if (check_region(PAGE_IO,PAGE_IO_SIZE) != 0) {
-- printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n",
-- sbc_gxx_map.name,
-- PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 );
-- return -EAGAIN;
-- }
-- iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
-+ iomapadr = ioremap(WINDOW_START, WINDOW_LENGTH);
- if (!iomapadr) {
- printk( KERN_ERR"%s: failed to ioremap memory region\n",
- sbc_gxx_map.name );
- return -EIO;
- }
-
-- request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash" );
-+ if (!request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash")) {
-+ printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n",
-+ sbc_gxx_map.name,
-+ PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 );
-+ iounmap(iomapadr);
-+ return -EAGAIN;
-+ }
-+
-
- printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n",
- sbc_gxx_map.name,
-@@ -261,7 +223,7 @@
- return -ENXIO;
- }
-
-- all_mtd->module=THIS_MODULE;
-+ all_mtd->owner = THIS_MODULE;
-
- /* Create MTD devices for each partition. */
- add_mtd_partitions(all_mtd, partition_info, NUM_PARTITIONS );
---- linux-2.4.21/drivers/mtd/maps/sc520cdp.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/sc520cdp.c
-@@ -16,7 +16,7 @@
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- *
-- * $Id: sc520cdp.c,v 1.11 2002/03/08 16:34:35 rkaiser Exp $
-+ * $Id: sc520cdp.c,v 1.21 2004/12/13 10:27:08 dedekind Exp $
- *
- *
- * The SC520CDP is an evaluation board for the Elan SC520 processor available
-@@ -29,6 +29,7 @@
- #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>
-@@ -84,88 +85,25 @@
- #define WINDOW_SIZE_1 0x00800000
- #define WINDOW_SIZE_2 0x00080000
-
--static __u8 sc520cdp_read8(struct map_info *map, unsigned long ofs)
--{
-- return readb(map->map_priv_1 + ofs);
--}
--
--static __u16 sc520cdp_read16(struct map_info *map, unsigned long ofs)
--{
-- return readw(map->map_priv_1 + ofs);
--}
--
--static __u32 sc520cdp_read32(struct map_info *map, unsigned long ofs)
--{
-- return readl(map->map_priv_1 + ofs);
--}
--
--static void sc520cdp_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
--}
--
--static void sc520cdp_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- writeb(d, map->map_priv_1 + adr);
--}
--
--static void sc520cdp_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- writew(d, map->map_priv_1 + adr);
--}
--
--static void sc520cdp_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- writel(d, map->map_priv_1 + adr);
--}
--
--static void sc520cdp_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio((void *)(map->map_priv_1 + to), from, len);
--}
-
- static struct map_info sc520cdp_map[] = {
- {
-- name: "SC520CDP Flash Bank #0",
-- size: WINDOW_SIZE_0,
-- buswidth: 4,
-- read8: sc520cdp_read8,
-- read16: sc520cdp_read16,
-- read32: sc520cdp_read32,
-- copy_from: sc520cdp_copy_from,
-- write8: sc520cdp_write8,
-- write16: sc520cdp_write16,
-- write32: sc520cdp_write32,
-- copy_to: sc520cdp_copy_to,
-- map_priv_2: WINDOW_ADDR_0
-+ .name = "SC520CDP Flash Bank #0",
-+ .size = WINDOW_SIZE_0,
-+ .bankwidth = 4,
-+ .phys = WINDOW_ADDR_0
- },
- {
-- name: "SC520CDP Flash Bank #1",
-- size: WINDOW_SIZE_1,
-- buswidth: 4,
-- read8: sc520cdp_read8,
-- read16: sc520cdp_read16,
-- read32: sc520cdp_read32,
-- copy_from: sc520cdp_copy_from,
-- write8: sc520cdp_write8,
-- write16: sc520cdp_write16,
-- write32: sc520cdp_write32,
-- copy_to: sc520cdp_copy_to,
-- map_priv_2: WINDOW_ADDR_1
-+ .name = "SC520CDP Flash Bank #1",
-+ .size = WINDOW_SIZE_1,
-+ .bankwidth = 4,
-+ .phys = WINDOW_ADDR_1
- },
- {
-- name: "SC520CDP DIL Flash",
-- size: WINDOW_SIZE_2,
-- buswidth: 1,
-- read8: sc520cdp_read8,
-- read16: sc520cdp_read16,
-- read32: sc520cdp_read32,
-- copy_from: sc520cdp_copy_from,
-- write8: sc520cdp_write8,
-- write16: sc520cdp_write16,
-- write32: sc520cdp_write32,
-- copy_to: sc520cdp_copy_to,
-- map_priv_2: WINDOW_ADDR_2
-+ .name = "SC520CDP DIL Flash",
-+ .size = WINDOW_SIZE_2,
-+ .bankwidth = 1,
-+ .phys = WINDOW_ADDR_2
- },
- };
-
-@@ -248,16 +186,16 @@
-
- static void sc520cdp_setup_par(void)
- {
-- volatile unsigned long *mmcr;
-+ volatile unsigned long __iomem *mmcr;
- unsigned long mmcr_val;
- int i, j;
-
- /* map in SC520's MMCR area */
-- mmcr = (unsigned long *)ioremap_nocache(SC520_MMCR_BASE, SC520_MMCR_EXTENT);
-+ mmcr = ioremap_nocache(SC520_MMCR_BASE, SC520_MMCR_EXTENT);
- if(!mmcr) { /* ioremap_nocache failed: skip the PAR reprogramming */
-- /* force map_priv_2 fields to BIOS defaults: */
-+ /* force physical address fields to BIOS defaults: */
- for(i = 0; i < NUM_FLASH_BANKS; i++)
-- sc520cdp_map[i].map_priv_2 = par_table[i].default_address;
-+ sc520cdp_map[i].phys = par_table[i].default_address;
- return;
- }
-
-@@ -282,10 +220,10 @@
- sc520cdp_map[i].name);
- printk(KERN_NOTICE "Trying default address 0x%lx\n",
- par_table[i].default_address);
-- sc520cdp_map[i].map_priv_2 = par_table[i].default_address;
-+ sc520cdp_map[i].phys = par_table[i].default_address;
- }
- }
-- iounmap((void *)mmcr);
-+ iounmap(mmcr);
- }
- #endif
-
-@@ -300,13 +238,18 @@
- #endif
-
- for (i = 0; i < NUM_FLASH_BANKS; i++) {
-- printk(KERN_NOTICE "SC520 CDP flash device: %lx at %lx\n", sc520cdp_map[i].size, sc520cdp_map[i].map_priv_2);
-- sc520cdp_map[i].map_priv_1 = (unsigned long)ioremap_nocache(sc520cdp_map[i].map_priv_2, sc520cdp_map[i].size);
-+ printk(KERN_NOTICE "SC520 CDP flash device: 0x%lx at 0x%lx\n",
-+ sc520cdp_map[i].size, sc520cdp_map[i].phys);
-
-- if (!sc520cdp_map[i].map_priv_1) {
-+ sc520cdp_map[i].virt = ioremap_nocache(sc520cdp_map[i].phys, sc520cdp_map[i].size);
-+
-+ if (!sc520cdp_map[i].virt) {
- printk("Failed to ioremap_nocache\n");
- return -EIO;
- }
-+
-+ simple_map_init(&sc520cdp_map[i]);
-+
- mymtd[i] = do_map_probe("cfi_probe", &sc520cdp_map[i]);
- if(!mymtd[i])
- mymtd[i] = do_map_probe("jedec_probe", &sc520cdp_map[i]);
-@@ -314,11 +257,11 @@
- mymtd[i] = do_map_probe("map_rom", &sc520cdp_map[i]);
-
- if (mymtd[i]) {
-- mymtd[i]->module = THIS_MODULE;
-+ mymtd[i]->owner = THIS_MODULE;
- ++devices_found;
- }
- else {
-- iounmap((void *)sc520cdp_map[i].map_priv_1);
-+ iounmap(sc520cdp_map[i].virt);
- }
- }
- if(devices_found >= 2) {
-@@ -346,9 +289,9 @@
- for (i = 0; i < NUM_FLASH_BANKS; i++) {
- if (mymtd[i])
- map_destroy(mymtd[i]);
-- if (sc520cdp_map[i].map_priv_1) {
-- iounmap((void *)sc520cdp_map[i].map_priv_1);
-- sc520cdp_map[i].map_priv_1 = 0;
-+ if (sc520cdp_map[i].virt) {
-+ iounmap(sc520cdp_map[i].virt);
-+ sc520cdp_map[i].virt = NULL;
- }
- }
- }
---- linux-2.4.21/drivers/mtd/maps/scb2_flash.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/scb2_flash.c
-@@ -1,6 +1,6 @@
- /*
- * MTD map driver for BIOS Flash on Intel SCB2 boards
-- * $Id: scb2_flash.c,v 1.2 2003/01/24 13:09:56 dwmw2 Exp $
-+ * $Id: scb2_flash.c,v 1.11 2004/11/28 09:40:40 dwmw2 Exp $
- * Copyright (C) 2002 Sun Microsystems, Inc.
- * Tim Hockin <thockin@sun.com>
- *
-@@ -14,7 +14,7 @@
- * try to request it here, but if it fails, we carry on anyway.
- *
- * This is how the chip is attached, so said the schematic:
-- * * a 4 MiB (32 Mb) 16 bit chip
-+ * * a 4 MiB (32 Mib) 16 bit chip
- * * a 1 MiB memory region
- * * A20 and A21 pulled up
- * * D8-D15 ignored
-@@ -31,23 +31,24 @@
- *
- * The actual BIOS layout has been mostly reverse engineered. Intel BIOS
- * updates for this board include 10 related (*.bio - &.bi9) binary files and
-- * another seperate (*.bbo) binary file. The 10 files are 64k of data + a
-+ * another separate (*.bbo) binary file. The 10 files are 64k of data + a
- * small header. If the headers are stripped off, the 10 64k files can be
- * concatenated into a 640k image. This is your BIOS image, proper. The
-- * seperate .bbo file also has a small header. It is the 'Boot Block'
-+ * separate .bbo file also has a small header. It is the 'Boot Block'
- * recovery BIOS. Once the header is stripped, no further prep is needed.
- * As best I can tell, the BIOS is arranged as such:
- * offset 0x00000 to 0x4ffff (320k): unknown - SCSI BIOS, etc?
- * offset 0x50000 to 0xeffff (640k): BIOS proper
- * offset 0xf0000 ty 0xfffff (64k): Boot Block region
- *
-- * Intel's BIOS update program flashes the BIOS and Boot Block in seperate
-+ * Intel's BIOS update program flashes the BIOS and Boot Block in separate
- * steps. Probably a wise thing to do.
- */
-
- #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>
-@@ -60,65 +61,13 @@
- #define SCB2_ADDR 0xfff00000
- #define SCB2_WINDOW 0x00100000
-
--static __u8 scb2_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--static __u16 scb2_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--static __u32 scb2_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--static void scb2_copy_from(struct map_info *map, void *to,
-- unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--static void scb2_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--static void scb2_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--static void scb2_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--static void scb2_copy_to(struct map_info *map, unsigned long to,
-- const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
-
--static void *scb2_ioaddr;
-+static void __iomem *scb2_ioaddr;
- static struct mtd_info *scb2_mtd;
--struct map_info scb2_map = {
-- name: "SCB2 BIOS Flash",
-- size: 0,
-- buswidth: 1,
-- read8: scb2_read8,
-- read16: scb2_read16,
-- read32: scb2_read32,
-- copy_from: scb2_copy_from,
-- write8: scb2_write8,
-- write16: scb2_write16,
-- write32: scb2_write32,
-- copy_to: scb2_copy_to,
-+static struct map_info scb2_map = {
-+ .name = "SCB2 BIOS Flash",
-+ .size = 0,
-+ .bankwidth = 1,
- };
- static int region_fail;
-
-@@ -137,6 +86,8 @@
- return -1;
- }
-
-+ /* I wasn't here. I didn't see. dwmw2. */
-+
- /* the chip is sometimes bigger than the map - what a waste */
- mtd->size = map->size;
-
-@@ -211,9 +162,12 @@
- return -ENOMEM;
- }
-
-- scb2_map.map_priv_1 = (unsigned long)scb2_ioaddr;
-+ scb2_map.phys = SCB2_ADDR;
-+ scb2_map.virt = scb2_ioaddr;
- scb2_map.size = SCB2_WINDOW;
-
-+ simple_map_init(&scb2_map);
-+
- /* try to find a chip */
- scb2_mtd = do_map_probe("cfi_probe", &scb2_map);
-
-@@ -225,7 +179,7 @@
- return -ENODEV;
- }
-
-- scb2_mtd->module = THIS_MODULE;
-+ scb2_mtd->owner = THIS_MODULE;
- if (scb2_fixup_mtd(scb2_mtd) < 0) {
- del_mtd_device(scb2_mtd);
- map_destroy(scb2_mtd);
-@@ -235,7 +189,7 @@
- return -ENODEV;
- }
-
-- printk(KERN_NOTICE MODNAME ": chip size %x at offset %x\n",
-+ printk(KERN_NOTICE MODNAME ": chip size 0x%x at offset 0x%x\n",
- scb2_mtd->size, SCB2_WINDOW - scb2_mtd->size);
-
- add_mtd_device(scb2_mtd);
-@@ -264,21 +218,21 @@
- pci_set_drvdata(dev, NULL);
- }
-
--static struct pci_device_id scb2_flash_pci_ids[] __devinitdata = {
-+static struct pci_device_id scb2_flash_pci_ids[] = {
- {
-- vendor: PCI_VENDOR_ID_SERVERWORKS,
-- device: PCI_DEVICE_ID_SERVERWORKS_CSB5,
-- subvendor: PCI_ANY_ID,
-- subdevice: PCI_ANY_ID
-+ .vendor = PCI_VENDOR_ID_SERVERWORKS,
-+ .device = PCI_DEVICE_ID_SERVERWORKS_CSB5,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID
- },
- { 0, }
- };
-
- static struct pci_driver scb2_flash_driver = {
-- name: "Intel SCB2 BIOS Flash",
-- id_table: scb2_flash_pci_ids,
-- probe: scb2_flash_probe,
-- remove: __devexit_p(scb2_flash_remove),
-+ .name = "Intel SCB2 BIOS Flash",
-+ .id_table = scb2_flash_pci_ids,
-+ .probe = scb2_flash_probe,
-+ .remove = __devexit_p(scb2_flash_remove),
- };
-
- static int __init
---- linux-2.4.21/drivers/mtd/maps/scx200_docflash.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/scx200_docflash.c
-@@ -2,7 +2,7 @@
-
- Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
-
-- $Id: scx200_docflash.c,v 1.1 2003/01/24 13:20:40 dwmw2 Exp $
-+ $Id: scx200_docflash.c,v 1.10 2004/11/28 09:40:40 dwmw2 Exp $
-
- National Semiconductor SCx200 flash mapped with DOCCS
- */
-@@ -11,6 +11,7 @@
- #include <linux/config.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>
-@@ -75,49 +76,12 @@
- #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
- #endif
-
--static __u8 scx200_docflash_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--static __u16 scx200_docflash_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--static void scx200_docflash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--static void scx200_docflash_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--static void scx200_docflash_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--static void scx200_docflash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
-
- static struct map_info scx200_docflash_map = {
- .name = "NatSemi SCx200 DOCCS Flash",
-- .read8 = scx200_docflash_read8,
-- .read16 = scx200_docflash_read16,
-- .copy_from = scx200_docflash_copy_from,
-- .write8 = scx200_docflash_write8,
-- .write16 = scx200_docflash_write16,
-- .copy_to = scx200_docflash_copy_to
- };
-
--int __init init_scx200_docflash(void)
-+static int __init init_scx200_docflash(void)
- {
- unsigned u;
- unsigned base;
-@@ -209,12 +173,15 @@
-
- scx200_docflash_map.size = size;
- if (width == 8)
-- scx200_docflash_map.buswidth = 1;
-+ scx200_docflash_map.bankwidth = 1;
- else
-- scx200_docflash_map.buswidth = 2;
-+ scx200_docflash_map.bankwidth = 2;
-
-- scx200_docflash_map.map_priv_1 = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size);
-- if (!scx200_docflash_map.map_priv_1) {
-+ simple_map_init(&scx200_docflash_map);
-+
-+ scx200_docflash_map.phys = docmem.start;
-+ scx200_docflash_map.virt = ioremap(docmem.start, scx200_docflash_map.size);
-+ if (!scx200_docflash_map.virt) {
- printk(KERN_ERR NAME ": failed to ioremap the flash\n");
- release_resource(&docmem);
- return -EIO;
-@@ -223,7 +190,7 @@
- mymtd = do_map_probe(flashtype, &scx200_docflash_map);
- if (!mymtd) {
- printk(KERN_ERR NAME ": unable to detect flash\n");
-- iounmap((void *)scx200_docflash_map.map_priv_1);
-+ iounmap(scx200_docflash_map.virt);
- release_resource(&docmem);
- return -ENXIO;
- }
-@@ -231,7 +198,7 @@
- if (size < mymtd->size)
- printk(KERN_WARNING NAME ": warning, flash mapping is smaller than flash size\n");
-
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
- #if PARTITION
- partition_info[3].offset = mymtd->size-partition_info[3].size;
-@@ -253,8 +220,8 @@
- #endif
- map_destroy(mymtd);
- }
-- if (scx200_docflash_map.map_priv_1) {
-- iounmap((void *)scx200_docflash_map.map_priv_1);
-+ if (scx200_docflash_map.virt) {
-+ iounmap(scx200_docflash_map.virt);
- release_resource(&docmem);
- }
- }
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/sharpsl-flash.c
-@@ -0,0 +1,101 @@
-+/*
-+ * sharpsl-flash.c
-+ *
-+ * Copyright (C) 2001 Lineo Japan, Inc.
-+ * Copyright (C) 2002 SHARP
-+ *
-+ * $Id: sharpsl-flash.c,v 1.2 2004/11/24 20:38:06 rpurdie Exp $
-+ *
-+ * based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp
-+ * Handle mapping of the flash on the RPX Lite and CLLF boards
-+ *
-+ * This program is free software; 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.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <asm/io.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#define WINDOW_ADDR 0x00000000
-+#define WINDOW_SIZE 0x01000000
-+#define BANK_WIDTH 2
-+
-+static struct mtd_info *mymtd;
-+
-+struct map_info sharpsl_map = {
-+ .name = "sharpsl-flash",
-+ .size = WINDOW_SIZE,
-+ .bankwidth = BANK_WIDTH,
-+ .phys = WINDOW_ADDR
-+};
-+
-+static struct mtd_partition sharpsl_partitions[1] = {
-+ {
-+ name: "Filesystem",
-+ size: 0x006d0000,
-+ offset: 0x00120000
-+ }
-+};
-+
-+#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
-+
-+int __init init_sharpsl(void)
-+{
-+ struct mtd_partition *parts;
-+ int nb_parts = 0;
-+ char *part_type = "static";
-+
-+ printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
-+ sharpsl_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+ if (!sharpsl_map.virt) {
-+ printk("Failed to ioremap\n");
-+ return -EIO;
-+ }
-+ mymtd = do_map_probe("map_rom", &sharpsl_map);
-+ if (!mymtd) {
-+ iounmap(sharpsl_map.virt);
-+ return -ENXIO;
-+ }
-+
-+ mymtd->owner = THIS_MODULE;
-+
-+ parts = sharpsl_partitions;
-+ nb_parts = NB_OF(sharpsl_partitions);
-+
-+ printk(KERN_NOTICE "Using %s partision definition\n", part_type);
-+ add_mtd_partitions(mymtd, parts, nb_parts);
-+
-+ return 0;
-+}
-+
-+static void __exit cleanup_sharpsl(void)
-+{
-+ if (mymtd) {
-+ del_mtd_partitions(mymtd);
-+ map_destroy(mymtd);
-+ }
-+ if (sharpsl_map.virt) {
-+ iounmap(sharpsl_map.virt);
-+ sharpsl_map.virt = 0;
-+ }
-+}
-+
-+module_init(init_sharpsl);
-+module_exit(cleanup_sharpsl);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("SHARP (Original: Arnold Christensen <AKC@pel.dk>)");
-+MODULE_DESCRIPTION("MTD map driver for SHARP SL series");
---- linux-2.4.21/drivers/mtd/maps/solutionengine.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/solutionengine.c
-@@ -1,5 +1,5 @@
- /*
-- * $Id: solutionengine.c,v 1.4 2001/11/07 01:20:59 jsiegel Exp $
-+ * $Id: solutionengine.c,v 1.14 2004/09/16 23:27:14 gleixner Exp $
- *
- * Flash and EPROM on Hitachi Solution Engine and similar boards.
- *
-@@ -11,31 +11,13 @@
- #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/mtd/partitions.h>
- #include <linux/config.h>
--
--
--extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
--
--__u32 soleng_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void soleng_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void soleng_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
-+#include <linux/errno.h>
-
- static struct mtd_info *flash_mtd;
- static struct mtd_info *eprom_mtd;
-@@ -43,35 +25,33 @@
- static struct mtd_partition *parsed_parts;
-
- struct map_info soleng_eprom_map = {
-- name: "Solution Engine EPROM",
-- size: 0x400000,
-- buswidth: 4,
-- copy_from: soleng_copy_from,
-+ .name = "Solution Engine EPROM",
-+ .size = 0x400000,
-+ .bankwidth = 4,
- };
-
- struct map_info soleng_flash_map = {
-- name: "Solution Engine FLASH",
-- size: 0x400000,
-- buswidth: 4,
-- read32: soleng_read32,
-- copy_from: soleng_copy_from,
-- write32: soleng_write32,
-+ .name = "Solution Engine FLASH",
-+ .size = 0x400000,
-+ .bankwidth = 4,
- };
-
-+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-+
- #ifdef CONFIG_MTD_SUPERH_RESERVE
- static struct mtd_partition superh_se_partitions[] = {
- /* Reserved for boot code, read-only */
- {
-- name: "flash_boot",
-- offset: 0x00000000,
-- size: CONFIG_MTD_SUPERH_RESERVE,
-- mask_flags: MTD_WRITEABLE,
-+ .name = "flash_boot",
-+ .offset = 0x00000000,
-+ .size = CONFIG_MTD_SUPERH_RESERVE,
-+ .mask_flags = MTD_WRITEABLE,
- },
- /* All else is writable (e.g. JFFS) */
- {
-- name: "Flash FS",
-- offset: MTDPART_OFS_NXTBLK,
-- size: MTDPART_SIZ_FULL,
-+ .name = "Flash FS",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = MTDPART_SIZ_FULL,
- }
- };
- #endif /* CONFIG_MTD_SUPERH_RESERVE */
-@@ -81,16 +61,22 @@
- int nr_parts = 0;
-
- /* First probe at offset 0 */
-- soleng_flash_map.map_priv_1 = P2SEGADDR(0);
-- soleng_eprom_map.map_priv_1 = P1SEGADDR(0x01000000);
-+ soleng_flash_map.phys = 0;
-+ soleng_flash_map.virt = (void __iomem *)P2SEGADDR(0);
-+ soleng_eprom_map.phys = 0x01000000;
-+ soleng_eprom_map.virt = (void __iomem *)P1SEGADDR(0x01000000);
-+ simple_map_init(&soleng_eprom_map);
-+ simple_map_init(&soleng_flash_map);
-
- printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n");
- flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map);
- if (!flash_mtd) {
- /* Not there. Try swapping */
- printk(KERN_NOTICE "Probing for flash chips at 0x01000000:\n");
-- soleng_flash_map.map_priv_1 = P2SEGADDR(0x01000000);
-- soleng_eprom_map.map_priv_1 = P1SEGADDR(0);
-+ soleng_flash_map.phys = 0x01000000;
-+ soleng_flash_map.virt = P2SEGADDR(0x01000000);
-+ soleng_eprom_map.phys = 0;
-+ soleng_eprom_map.virt = P1SEGADDR(0);
- flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map);
- if (!flash_mtd) {
- /* Eep. */
-@@ -99,25 +85,20 @@
- }
- }
- printk(KERN_NOTICE "Solution Engine: Flash at 0x%08lx, EPROM at 0x%08lx\n",
-- soleng_flash_map.map_priv_1 & 0x1fffffff,
-- soleng_eprom_map.map_priv_1 & 0x1fffffff);
-- flash_mtd->module = THIS_MODULE;
-+ soleng_flash_map.phys & 0x1fffffff,
-+ soleng_eprom_map.phys & 0x1fffffff);
-+ flash_mtd->owner = THIS_MODULE;
-
- eprom_mtd = do_map_probe("map_rom", &soleng_eprom_map);
- if (eprom_mtd) {
-- eprom_mtd->module = THIS_MODULE;
-+ eprom_mtd->owner = THIS_MODULE;
- add_mtd_device(eprom_mtd);
- }
-
--#ifdef CONFIG_MTD_REDBOOT_PARTS
-- nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts);
-- if (nr_parts > 0)
-- printk(KERN_NOTICE "Found RedBoot partition table.\n");
-- else if (nr_parts < 0)
-- printk(KERN_NOTICE "Error looking for RedBoot partitions.\n");
--#endif /* CONFIG_MTD_REDBOOT_PARTS */
--#if CONFIG_MTD_SUPERH_RESERVE
-- if (nr_parts == 0) {
-+ nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0);
-+
-+#ifdef CONFIG_MTD_SUPERH_RESERVE
-+ if (nr_parts <= 0) {
- printk(KERN_NOTICE "Using configured partition at 0x%08x.\n",
- CONFIG_MTD_SUPERH_RESERVE);
- parsed_parts = superh_se_partitions;
---- linux-2.4.21/drivers/mtd/maps/sun_uflash.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/sun_uflash.c
-@@ -1,4 +1,4 @@
--/* $Id: sun_uflash.c,v 1.4 2001/10/02 15:05:14 dwmw2 Exp $
-+/* $Id: sun_uflash.c,v 1.11 2004/11/04 13:24:15 gleixner Exp $
- *
- * sun_uflash - Driver implementation for user-programmable flash
- * present on many Sun Microsystems SME boardsets.
-@@ -12,7 +12,6 @@
-
- #include <linux/kernel.h>
- #include <linux/module.h>
--#include <linux/version.h>
- #include <linux/fs.h>
- #include <linux/errno.h>
- #include <linux/init.h>
-@@ -48,60 +47,11 @@
- struct list_head list;
- };
-
--__u8 uflash_read8(struct map_info *map, unsigned long ofs)
--{
-- return(__raw_readb(map->map_priv_1 + ofs));
--}
--
--__u16 uflash_read16(struct map_info *map, unsigned long ofs)
--{
-- return(__raw_readw(map->map_priv_1 + ofs));
--}
--
--__u32 uflash_read32(struct map_info *map, unsigned long ofs)
--{
-- return(__raw_readl(map->map_priv_1 + ofs));
--}
--
--void uflash_copy_from(struct map_info *map, void *to, unsigned long from,
-- ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void uflash_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
--}
--
--void uflash_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
--}
--
--void uflash_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
--}
--
--void uflash_copy_to(struct map_info *map, unsigned long to, const void *from,
-- ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
-
- struct map_info uflash_map_templ = {
-- name: "SUNW,???-????",
-- size: UFLASH_WINDOW_SIZE,
-- buswidth: UFLASH_BUSWIDTH,
-- read8: uflash_read8,
-- read16: uflash_read16,
-- read32: uflash_read32,
-- copy_from: uflash_copy_from,
-- write8: uflash_write8,
-- write16: uflash_write16,
-- write32: uflash_write32,
-- copy_to: uflash_copy_to
-+ .name = "SUNW,???-????",
-+ .size = UFLASH_WINDOW_SIZE,
-+ .bankwidth = UFLASH_BUSWIDTH,
- };
-
- int uflash_devinit(struct linux_ebus_device* edev)
-@@ -145,20 +95,21 @@
- if(0 != pdev->name && 0 < strlen(pdev->name)) {
- pdev->map.name = pdev->name;
- }
--
-- pdev->map.map_priv_1 =
-- (unsigned long)ioremap_nocache(edev->resource[0].start, pdev->map.size);
-- if(0 == pdev->map.map_priv_1) {
-+ pdev->map.phys = edev->resource[0].start;
-+ pdev->map.virt = ioremap_nocache(edev->resource[0].start, pdev->map.size);
-+ if(0 == pdev->map.virt) {
- printk("%s: failed to map device\n", __FUNCTION__);
- kfree(pdev->name);
- kfree(pdev);
- return(-1);
- }
-
-+ simple_map_init(&pdev->map);
-+
- /* MTD registration */
- pdev->mtd = do_map_probe("cfi_probe", &pdev->map);
- if(0 == pdev->mtd) {
-- iounmap((void *)pdev->map.map_priv_1);
-+ iounmap((void *)pdev->map.virt);
- kfree(pdev->name);
- kfree(pdev);
- return(-ENXIO);
-@@ -166,7 +117,7 @@
-
- list_add(&pdev->list, &device_list);
-
-- pdev->mtd->module = THIS_MODULE;
-+ pdev->mtd->owner = THIS_MODULE;
-
- add_mtd_device(pdev->mtd);
- return(0);
-@@ -211,9 +162,9 @@
- del_mtd_device(udev->mtd);
- map_destroy(udev->mtd);
- }
-- if(0 != udev->map.map_priv_1) {
-- iounmap((void*)udev->map.map_priv_1);
-- udev->map.map_priv_1 = 0;
-+ if(0 != udev->map.virt) {
-+ iounmap((void*)udev->map.virt);
-+ udev->map.virt = 0;
- }
- if(0 != udev->name) {
- kfree(udev->name);
---- linux-2.4.21/drivers/mtd/maps/tqm8xxl.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/tqm8xxl.c
-@@ -2,7 +2,7 @@
- * Handle mapping of the flash memory access routines
- * on TQM8xxL based devices.
- *
-- * $Id: tqm8xxl.c,v 1.4 2002/06/20 13:41:20 mag Exp $
-+ * $Id: tqm8xxl.c,v 1.13 2004/10/20 22:21:53 dwmw2 Exp $
- *
- * based on rpxlite.c
- *
-@@ -26,6 +26,7 @@
- #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>
-@@ -49,47 +50,7 @@
- static struct map_info* map_banks[FLASH_BANK_MAX];
- static struct mtd_part_def part_banks[FLASH_BANK_MAX];
- static unsigned long num_banks;
--static unsigned long start_scan_addr;
--
--__u8 tqm8xxl_read8(struct map_info *map, unsigned long ofs)
--{
-- return *((__u8 *)(map->map_priv_1 + ofs));
--}
--
--__u16 tqm8xxl_read16(struct map_info *map, unsigned long ofs)
--{
-- return *((__u16 *)(map->map_priv_1 + ofs));
--}
--
--__u32 tqm8xxl_read32(struct map_info *map, unsigned long ofs)
--{
-- return *((__u32 *)(map->map_priv_1 + ofs));
--}
--
--void tqm8xxl_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
--}
--
--void tqm8xxl_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- *((__u8 *)(map->map_priv_1 + adr)) = d;
--}
--
--void tqm8xxl_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- *((__u16 *)( map->map_priv_1 + adr)) = d;
--}
--
--void tqm8xxl_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- *((__u32 *)(map->map_priv_1 + adr)) = d;
--}
--
--void tqm8xxl_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio((void *)(map->map_priv_1 + to), from, len);
--}
-+static void __iomem *start_scan_addr;
-
- /*
- * Here are partition information for all known TQM8xxL series devices.
-@@ -107,50 +68,48 @@
- static unsigned long tqm8xxl_max_flash_size = 0x00800000;
-
- /* partition definition for first flash bank
-- * also ref. to "drivers\char\flash_config.c"
-+ * (cf. "drivers/char/flash_config.c")
- */
- static struct mtd_partition tqm8xxl_partitions[] = {
- {
-- name: "ppcboot",
-- offset: 0x00000000,
-- size: 0x00020000, /* 128KB */
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "ppcboot",
-+ .offset = 0x00000000,
-+ .size = 0x00020000, /* 128KB */
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
-- name: "kernel", /* default kernel image */
-- offset: 0x00020000,
-- size: 0x000e0000,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "kernel", /* default kernel image */
-+ .offset = 0x00020000,
-+ .size = 0x000e0000,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
-- name: "user",
-- offset: 0x00100000,
-- size: 0x00100000,
-+ .name = "user",
-+ .offset = 0x00100000,
-+ .size = 0x00100000,
- },
- {
-- name: "initrd",
-- offset: 0x00200000,
-- size: 0x00200000,
-+ .name = "initrd",
-+ .offset = 0x00200000,
-+ .size = 0x00200000,
- }
- };
--/* partition definition for second flahs bank */
-+/* partition definition for second flash bank */
- static struct mtd_partition tqm8xxl_fs_partitions[] = {
- {
-- name: "cramfs",
-- offset: 0x00000000,
-- size: 0x00200000,
-+ .name = "cramfs",
-+ .offset = 0x00000000,
-+ .size = 0x00200000,
- },
- {
-- name: "jffs",
-- offset: 0x00200000,
-- size: 0x00200000,
-- //size: MTDPART_SIZ_FULL,
-+ .name = "jffs",
-+ .offset = 0x00200000,
-+ .size = 0x00200000,
-+ //.size = MTDPART_SIZ_FULL,
- }
- };
- #endif
-
--#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
--
- int __init init_tqm_mtd(void)
- {
- int idx = 0, ret = 0;
-@@ -160,67 +119,73 @@
-
- flash_addr = bd->bi_flashstart;
- flash_size = bd->bi_flashsize;
-- //request maximum flash size address spzce
-- start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size);
-+
-+ //request maximum flash size address space
-+ start_scan_addr = ioremap(flash_addr, flash_size);
- if (!start_scan_addr) {
-- //printk("%s:Failed to ioremap address:0x%x\n", __FUNCTION__, FLASH_ADDR);
-- printk("%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr);
-+ printk(KERN_WARNING "%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr);
- return -EIO;
- }
-- for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++)
-- {
-+
-+ for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
- if(mtd_size >= flash_size)
- break;
-
-- printk("%s: chip probing count %d\n", __FUNCTION__, idx);
-+ printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx);
-
- map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL);
-- if(map_banks[idx] == NULL)
-- {
-- //return -ENOMEM;
-+ if(map_banks[idx] == NULL) {
- ret = -ENOMEM;
-+ /* FIXME: What if some MTD devices were probed already? */
- goto error_mem;
- }
-+
- memset((void *)map_banks[idx], 0, sizeof(struct map_info));
- map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL);
-- if(map_banks[idx]->name == NULL)
-- {
-- //return -ENOMEM;
-+
-+ if (!map_banks[idx]->name) {
- ret = -ENOMEM;
-+ /* FIXME: What if some MTD devices were probed already? */
- goto error_mem;
- }
-- memset((void *)map_banks[idx]->name, 0, 16);
--
- sprintf(map_banks[idx]->name, "TQM8xxL%d", idx);
-+
- map_banks[idx]->size = flash_size;
-- map_banks[idx]->buswidth = 4;
-- map_banks[idx]->read8 = tqm8xxl_read8;
-- map_banks[idx]->read16 = tqm8xxl_read16;
-- map_banks[idx]->read32 = tqm8xxl_read32;
-- map_banks[idx]->copy_from = tqm8xxl_copy_from;
-- map_banks[idx]->write8 = tqm8xxl_write8;
-- map_banks[idx]->write16 = tqm8xxl_write16;
-- map_banks[idx]->write32 = tqm8xxl_write32;
-- map_banks[idx]->copy_to = tqm8xxl_copy_to;
-+ map_banks[idx]->bankwidth = 4;
-+
-+ simple_map_init(map_banks[idx]);
-+
-+ map_banks[idx]->virt = start_scan_addr;
-+ map_banks[idx]->phys = flash_addr;
-+ /* FIXME: This looks utterly bogus, but I'm trying to
-+ preserve the behaviour of the original (shown here)...
-+
- map_banks[idx]->map_priv_1 =
- start_scan_addr + ((idx > 0) ?
- (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0);
-+ */
-+
-+ if (idx && mtd_banks[idx-1]) {
-+ map_banks[idx]->virt += mtd_banks[idx-1]->size;
-+ map_banks[idx]->phys += mtd_banks[idx-1]->size;
-+ }
-+
- //start to probe flash chips
- mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]);
-- if(mtd_banks[idx])
-- {
-- mtd_banks[idx]->module = THIS_MODULE;
-+
-+ if (mtd_banks[idx]) {
-+ mtd_banks[idx]->owner = THIS_MODULE;
- mtd_size += mtd_banks[idx]->size;
- num_banks++;
-- printk("%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks,
-+
-+ printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks,
- mtd_banks[idx]->name, mtd_banks[idx]->size);
- }
- }
-
- /* no supported flash chips found */
-- if(!num_banks)
-- {
-- printk("TQM8xxL: No support flash chips found!\n");
-+ if (!num_banks) {
-+ printk(KERN_NOTICE "TQM8xxL: No support flash chips found!\n");
- ret = -ENXIO;
- goto error_mem;
- }
-@@ -231,12 +196,13 @@
- */
- part_banks[0].mtd_part = tqm8xxl_partitions;
- part_banks[0].type = "Static image";
-- part_banks[0].nums = NB_OF(tqm8xxl_partitions);
-+ part_banks[0].nums = ARRAY_SIZE(tqm8xxl_partitions);
-+
- part_banks[1].mtd_part = tqm8xxl_fs_partitions;
- part_banks[1].type = "Static file system";
-- part_banks[1].nums = NB_OF(tqm8xxl_fs_partitions);
-- for(idx = 0; idx < num_banks ; idx++)
-- {
-+ part_banks[1].nums = ARRAY_SIZE(tqm8xxl_fs_partitions);
-+
-+ for(idx = 0; idx < num_banks ; idx++) {
- if (part_banks[idx].nums == 0) {
- printk(KERN_NOTICE "TQM flash%d: no partition info available, registering whole flash at once\n", idx);
- add_mtd_device(mtd_banks[idx]);
-@@ -254,12 +220,9 @@
- #endif
- return 0;
- error_mem:
-- for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++)
-- {
-- if(map_banks[idx] != NULL)
-- {
-- if(map_banks[idx]->name != NULL)
-- {
-+ for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
-+ if(map_banks[idx] != NULL) {
-+ if(map_banks[idx]->name != NULL) {
- kfree(map_banks[idx]->name);
- map_banks[idx]->name = NULL;
- }
-@@ -267,18 +230,15 @@
- map_banks[idx] = NULL;
- }
- }
-- //return -ENOMEM;
- error:
-- iounmap((void *)start_scan_addr);
-- //return -ENXIO;
-+ iounmap(start_scan_addr);
- return ret;
- }
-
- static void __exit cleanup_tqm_mtd(void)
- {
- unsigned int idx = 0;
-- for(idx = 0 ; idx < num_banks ; idx++)
-- {
-+ for(idx = 0 ; idx < num_banks ; idx++) {
- /* destroy mtd_info previously allocated */
- if (mtd_banks[idx]) {
- del_mtd_partitions(mtd_banks[idx]);
-@@ -288,8 +248,9 @@
- kfree(map_banks[idx]->name);
- kfree(map_banks[idx]);
- }
-+
- if (start_scan_addr) {
-- iounmap((void *)start_scan_addr);
-+ iounmap(start_scan_addr);
- start_scan_addr = 0;
- }
- }
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/ts5500_flash.c
-@@ -0,0 +1,141 @@
-+/*
-+ * ts5500_flash.c -- MTD map driver for Technology Systems TS-5500 board
-+ *
-+ * Copyright (C) 2004 Sean Young <sean@mess.org>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
-+ *
-+ * Note:
-+ * - In order for detection to work, jumper 3 must be set.
-+ * - Drive A and B use a proprietary FTL from General Software which isn't
-+ * supported as of yet so standard drives can't be mounted; you can create
-+ * your own (e.g. jffs) file system.
-+ * - If you have created your own jffs file system and the bios overwrites
-+ * it during boot, try disabling Drive A: and B: in the boot order.
-+ *
-+ * $Id: ts5500_flash.c,v 1.2 2004/11/28 09:40:40 dwmw2 Exp $
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+#include <linux/mtd/partitions.h>
-+#endif
-+
-+#define WINDOW_ADDR 0x09400000
-+#define WINDOW_SIZE 0x00200000
-+
-+static struct map_info ts5500_map = {
-+ .name = "TS-5500 Flash",
-+ .size = WINDOW_SIZE,
-+ .bankwidth = 1,
-+ .phys = WINDOW_ADDR
-+};
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+static struct mtd_partition ts5500_partitions[] = {
-+ {
-+ .name = "Drive A",
-+ .offset = 0,
-+ .size = 0x0e0000
-+ },
-+ {
-+ .name = "BIOS",
-+ .offset = 0x0e0000,
-+ .size = 0x020000,
-+ },
-+ {
-+ .name = "Drive B",
-+ .offset = 0x100000,
-+ .size = 0x100000
-+ }
-+};
-+
-+#define NUM_PARTITIONS (sizeof(ts5500_partitions)/sizeof(struct mtd_partition))
-+
-+#endif
-+
-+static struct mtd_info *mymtd;
-+
-+static int __init init_ts5500_map(void)
-+{
-+ int rc = 0;
-+
-+ ts5500_map.virt = ioremap_nocache(ts5500_map.phys, ts5500_map.size);
-+
-+ if(!ts5500_map.virt) {
-+ printk(KERN_ERR "Failed to ioremap_nocache\n");
-+ rc = -EIO;
-+ goto err_out_ioremap;
-+ }
-+
-+ simple_map_init(&ts5500_map);
-+
-+ mymtd = do_map_probe("jedec_probe", &ts5500_map);
-+ if(!mymtd)
-+ mymtd = do_map_probe("map_rom", &ts5500_map);
-+
-+ if(!mymtd) {
-+ rc = -ENXIO;
-+ goto err_out_map;
-+ }
-+
-+ mymtd->owner = THIS_MODULE;
-+#ifdef CONFIG_MTD_PARTITIONS
-+ add_mtd_partitions(mymtd, ts5500_partitions, NUM_PARTITIONS);
-+#else
-+ add_mtd_device(mymtd);
-+#endif
-+
-+ return 0;
-+
-+err_out_map:
-+ map_destroy(mymtd);
-+err_out_ioremap:
-+ iounmap(ts5500_map.virt);
-+
-+ return rc;
-+}
-+
-+static void __exit cleanup_ts5500_map(void)
-+{
-+ if (mymtd) {
-+#ifdef CONFIG_MTD_PARTITIONS
-+ del_mtd_partitions(mymtd);
-+#else
-+ del_mtd_device(mymtd);
-+#endif
-+ map_destroy(mymtd);
-+ }
-+
-+ if (ts5500_map.virt) {
-+ iounmap(ts5500_map.virt);
-+ ts5500_map.virt = NULL;
-+ }
-+}
-+
-+module_init(init_ts5500_map);
-+module_exit(cleanup_ts5500_map);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Sean Young <sean@mess.org>");
-+MODULE_DESCRIPTION("MTD map driver for Techology Systems TS-5500 board");
-+
---- linux-2.4.21/drivers/mtd/maps/tsunami_flash.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/tsunami_flash.c
-@@ -2,25 +2,29 @@
- * tsunami_flash.c
- *
- * flash chip on alpha ds10...
-- * $Id: tsunami_flash.c,v 1.1 2002/01/10 22:59:13 eric Exp $
-+ * $Id: tsunami_flash.c,v 1.9 2004/07/14 09:52:55 dwmw2 Exp $
- */
- #include <asm/io.h>
- #include <asm/core_tsunami.h>
-+#include <linux/init.h>
- #include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
-
- #define FLASH_ENABLE_PORT 0x00C00001
- #define FLASH_ENABLE_BYTE 0x01
- #define FLASH_DISABLE_BYTE 0x00
-
- #define MAX_TIG_FLASH_SIZE (12*1024*1024)
--static inline __u8 tsunami_flash_read8(struct map_info *map, unsigned long offset)
-+static inline map_word tsunami_flash_read8(struct map_info *map, unsigned long offset)
- {
-- return tsunami_tig_readb(offset);
-+ map_word val;
-+ val.x[0] = tsunami_tig_readb(offset);
-+ return val;
- }
-
--static void tsunami_flash_write8(struct map_info *map, __u8 value, unsigned long offset)
-+static void tsunami_flash_write8(struct map_info *map, map_word value, unsigned long offset)
- {
-- tsunami_tig_writeb(value, offset);
-+ tsunami_tig_writeb(value.x[0], offset);
- }
-
- static void tsunami_flash_copy_from(
-@@ -58,18 +62,12 @@
- static struct map_info tsunami_flash_map = {
- .name = "flash chip on the Tsunami TIG bus",
- .size = MAX_TIG_FLASH_SIZE,
-- .buswidth = 1,
-- .read8 = tsunami_flash_read8,
-- .read16 = 0,
-- .read32 = 0,
-+ .phys = NO_XIP;
-+ .bankwidth = 1,
-+ .read = tsunami_flash_read8,
- .copy_from = tsunami_flash_copy_from,
-- .write8 = tsunami_flash_write8,
-- .write16 = 0,
-- .write32 = 0,
-+ .write = tsunami_flash_write8,
- .copy_to = tsunami_flash_copy_to,
-- .set_vpp = 0,
-- .map_priv_1 = 0,
--
- };
-
- static struct mtd_info *tsunami_flash_mtd;
-@@ -88,7 +86,7 @@
-
- static int __init init_tsunami_flash(void)
- {
-- static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 };
-+ static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
- char **type;
-
- tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT);
-@@ -99,7 +97,7 @@
- tsunami_flash_mtd = do_map_probe(*type, &tsunami_flash_map);
- }
- if (tsunami_flash_mtd) {
-- tsunami_flash_mtd->module = THIS_MODULE;
-+ tsunami_flash_mtd->owner = THIS_MODULE;
- add_mtd_device(tsunami_flash_mtd);
- return 0;
- }
---- linux-2.4.21/drivers/mtd/maps/uclinux.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/uclinux.c
-@@ -5,7 +5,7 @@
- *
- * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
- *
-- * $Id: uclinux.c,v 1.2 2002/08/07 00:43:45 gerg Exp $
-+ * $Id: uclinux.c,v 1.10 2005/01/05 18:05:13 dwmw2 Exp $
- */
-
- /****************************************************************************/
-@@ -17,6 +17,7 @@
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <linux/major.h>
-+#include <linux/root_dev.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/partitions.h>
-@@ -24,58 +25,11 @@
-
- /****************************************************************************/
-
--__u8 uclinux_read8(struct map_info *map, unsigned long ofs)
--{
-- return(*((__u8 *) (map->map_priv_1 + ofs)));
--}
--
--__u16 uclinux_read16(struct map_info *map, unsigned long ofs)
--{
-- return(*((__u16 *) (map->map_priv_1 + ofs)));
--}
--
--__u32 uclinux_read32(struct map_info *map, unsigned long ofs)
--{
-- return(*((__u32 *) (map->map_priv_1 + ofs)));
--}
--
--void uclinux_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy(to, (void *)(map->map_priv_1 + from), len);
--}
--
--void uclinux_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- *((__u8 *) (map->map_priv_1 + adr)) = d;
--}
--
--void uclinux_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- *((__u16 *) (map->map_priv_1 + adr)) = d;
--}
--
--void uclinux_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- *((__u32 *) (map->map_priv_1 + adr)) = d;
--}
--
--void uclinux_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy((void *) (map->map_priv_1 + to), from, len);
--}
-
- /****************************************************************************/
-
- struct map_info uclinux_ram_map = {
-- name: "RAM",
-- read8: uclinux_read8,
-- read16: uclinux_read16,
-- read32: uclinux_read32,
-- copy_from: uclinux_copy_from,
-- write8: uclinux_write8,
-- write16: uclinux_write16,
-- write32: uclinux_write32,
-- copy_to: uclinux_copy_to,
-+ .name = "RAM",
- };
-
- struct mtd_info *uclinux_ram_mtdinfo;
-@@ -83,7 +37,7 @@
- /****************************************************************************/
-
- struct mtd_partition uclinux_romfs[] = {
-- { name: "ROMfs", offset: 0 }
-+ { .name = "ROMfs" }
- };
-
- #define NUM_PARTITIONS (sizeof(uclinux_romfs) / sizeof(uclinux_romfs[0]))
-@@ -93,8 +47,8 @@
- int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf)
- {
-- struct map_info *map = (struct map_info *) mtd->priv;
-- *mtdbuf = (u_char *) (map->map_priv_1 + ((int) from));
-+ struct map_info *map = mtd->priv;
-+ *mtdbuf = (u_char *) (map->virt + ((int) from));
- *retlen = len;
- return(0);
- }
-@@ -108,29 +62,30 @@
- extern char _ebss;
-
- mapp = &uclinux_ram_map;
-- mapp->map_priv_2 = (unsigned long) &_ebss;
-+ mapp->phys = (unsigned long) &_ebss;
- mapp->size = PAGE_ALIGN(*((unsigned long *)((&_ebss) + 8)));
-- mapp->buswidth = 4;
-+ mapp->bankwidth = 4;
-
- printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n",
- (int) mapp->map_priv_2, (int) mapp->size);
-
-- mapp->map_priv_1 = (unsigned long)
-- ioremap_nocache(mapp->map_priv_2, mapp->size);
-+ mapp->virt = ioremap_nocache(mapp->phys, mapp->size);
-
-- if (mapp->map_priv_1 == 0) {
-+ if (mapp->virt == 0) {
- printk("uclinux[mtd]: ioremap_nocache() failed\n");
- return(-EIO);
- }
-
-+ simple_map_init(mapp);
-+
- mtd = do_map_probe("map_ram", mapp);
- if (!mtd) {
- printk("uclinux[mtd]: failed to find a mapping?\n");
-- iounmap((void *) mapp->map_priv_1);
-+ iounmap(mapp->virt);
- return(-ENXIO);
- }
-
-- mtd->module = THIS_MODULE;
-+ mtd->owner = THIS_MODULE;
- mtd->point = uclinux_point;
- mtd->priv = mapp;
-
-@@ -155,8 +110,8 @@
- uclinux_ram_mtdinfo = NULL;
- }
- if (uclinux_ram_map.map_priv_1) {
-- iounmap((void *) uclinux_ram_map.map_priv_1);
-- uclinux_ram_map.map_priv_1 = 0;
-+ iounmap((void *) uclinux_ram_map.virt);
-+ uclinux_ram_map.virt = 0;
- }
- }
-
---- linux-2.4.21/drivers/mtd/maps/vmax301.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/maps/vmax301.c
-@@ -1,4 +1,4 @@
--// $Id: vmax301.c,v 1.24 2001/10/02 15:05:14 dwmw2 Exp $
-+// $Id: vmax301.c,v 1.31 2005/01/12 22:34:35 gleixner Exp $
- /* ######################################################################
-
- Tempustech VMAX SBC301 MTD Driver.
-@@ -24,6 +24,7 @@
- #include <asm/io.h>
-
- #include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
-
-
- #define WINDOW_START 0xd8000
-@@ -37,7 +38,7 @@
- the extra indirection from having one of the map->map_priv
- fields pointing to yet another private struct.
- */
--static spinlock_t vmax301_spin = SPIN_LOCK_UNLOCKED;
-+static DEFINE_SPINLOCK(vmax301_spin);
-
- static void __vmax301_page(struct map_info *map, unsigned long page)
- {
-@@ -53,32 +54,12 @@
- __vmax301_page(map, page);
- }
-
--static __u8 vmax301_read8(struct map_info *map, unsigned long ofs)
--{
-- __u8 ret;
-- spin_lock(&vmax301_spin);
-- vmax301_page(map, ofs);
-- ret = readb(map->map_priv_2 + (ofs & WINDOW_MASK));
-- spin_unlock(&vmax301_spin);
-- return ret;
--}
--
--static __u16 vmax301_read16(struct map_info *map, unsigned long ofs)
--{
-- __u16 ret;
-- spin_lock(&vmax301_spin);
-- vmax301_page(map, ofs);
-- ret = readw(map->map_priv_2 + (ofs & WINDOW_MASK));
-- spin_unlock(&vmax301_spin);
-- return ret;
--}
--
--static __u32 vmax301_read32(struct map_info *map, unsigned long ofs)
-+static map_word vmax301_read8(struct map_info *map, unsigned long ofs)
- {
-- __u32 ret;
-+ map_word ret;
- spin_lock(&vmax301_spin);
- vmax301_page(map, ofs);
-- ret = readl(map->map_priv_2 + (ofs & WINDOW_MASK));
-+ ret.x[0] = readb(map->map_priv_2 + (ofs & WINDOW_MASK));
- spin_unlock(&vmax301_spin);
- return ret;
- }
-@@ -99,27 +80,11 @@
- }
- }
-
--static void vmax301_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- spin_lock(&vmax301_spin);
-- vmax301_page(map, adr);
-- writeb(d, map->map_priv_2 + (adr & WINDOW_MASK));
-- spin_unlock(&vmax301_spin);
--}
--
--static void vmax301_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- spin_lock(&vmax301_spin);
-- vmax301_page(map, adr);
-- writew(d, map->map_priv_2 + (adr & WINDOW_MASK));
-- spin_unlock(&vmax301_spin);
--}
--
--static void vmax301_write32(struct map_info *map, __u32 d, unsigned long adr)
-+static void vmax301_write8(struct map_info *map, map_word d, unsigned long adr)
- {
- spin_lock(&vmax301_spin);
- vmax301_page(map, adr);
-- writel(d, map->map_priv_2 + (adr & WINDOW_MASK));
-+ writeb(d.x[0], map->map_priv_2 + (adr & WINDOW_MASK));
- spin_unlock(&vmax301_spin);
- }
-
-@@ -142,34 +107,28 @@
-
- static struct map_info vmax_map[2] = {
- {
-- name: "VMAX301 Internal Flash",
-- size: 3*2*1024*1024,
-- buswidth: 1,
-- read8: vmax301_read8,
-- read16: vmax301_read16,
-- read32: vmax301_read32,
-- copy_from: vmax301_copy_from,
-- write8: vmax301_write8,
-- write16: vmax301_write16,
-- write32: vmax301_write32,
-- copy_to: vmax301_copy_to,
-- map_priv_1: WINDOW_START + WINDOW_LENGTH,
-- map_priv_2: 0xFFFFFFFF
-+ .name = "VMAX301 Internal Flash",
-+ .phys = NO_XIP,
-+ .size = 3*2*1024*1024,
-+ .bankwidth = 1,
-+ .read = vmax301_read8,
-+ .copy_from = vmax301_copy_from,
-+ .write = vmax301_write8,
-+ .copy_to = vmax301_copy_to,
-+ .map_priv_1 = WINDOW_START + WINDOW_LENGTH,
-+ .map_priv_2 = 0xFFFFFFFF
- },
- {
-- name: "VMAX301 Socket",
-- size: 0,
-- buswidth: 1,
-- read8: vmax301_read8,
-- read16: vmax301_read16,
-- read32: vmax301_read32,
-- copy_from: vmax301_copy_from,
-- write8: vmax301_write8,
-- write16: vmax301_write16,
-- write32: vmax301_write32,
-- copy_to: vmax301_copy_to,
-- map_priv_1: WINDOW_START + (3*WINDOW_LENGTH),
-- map_priv_2: 0xFFFFFFFF
-+ .name = "VMAX301 Socket",
-+ .phys = NO_XIP,
-+ .size = 0,
-+ .bankwidth = 1,
-+ .read = vmax301_read8,
-+ .copy_from = vmax301_copy_from,
-+ .write = vmax301_write8,
-+ .copy_to = vmax301_copy_to,
-+ .map_priv_1 = WINDOW_START + (3*WINDOW_LENGTH),
-+ .map_priv_2 = 0xFFFFFFFF
- }
- };
-
-@@ -206,8 +165,8 @@
- address of the first half, because it's used more
- often.
- */
-- vmax_map[0].map_priv_1 = iomapadr + WINDOW_START;
-- vmax_map[1].map_priv_1 = iomapadr + (3*WINDOW_START);
-+ vmax_map[0].map_priv_2 = iomapadr + WINDOW_START;
-+ vmax_map[1].map_priv_2 = iomapadr + (3*WINDOW_START);
-
- for (i=0; i<2; i++) {
- vmax_mtd[i] = do_map_probe("cfi_probe", &vmax_map[i]);
-@@ -218,7 +177,7 @@
- if (!vmax_mtd[i])
- vmax_mtd[i] = do_map_probe("map_rom", &vmax_map[i]);
- if (vmax_mtd[i]) {
-- vmax_mtd[i]->module = THIS_MODULE;
-+ vmax_mtd[i]->owner = THIS_MODULE;
- add_mtd_device(vmax_mtd[i]);
- }
- }
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/walnut.c
-@@ -0,0 +1,122 @@
-+/*
-+ * $Id: walnut.c,v 1.2 2004/12/10 12:07:42 holindho Exp $
-+ *
-+ * Mapping for Walnut flash
-+ * (used ebony.c as a "framework")
-+ *
-+ * Heikki Lindholm <holindho@infradead.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/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <asm/io.h>
-+#include <asm/ibm4xx.h>
-+#include <platforms/4xx/walnut.h>
-+
-+/* these should be in platforms/4xx/walnut.h ? */
-+#define WALNUT_FLASH_ONBD_N(x) (x & 0x02)
-+#define WALNUT_FLASH_SRAM_SEL(x) (x & 0x01)
-+#define WALNUT_FLASH_LOW 0xFFF00000
-+#define WALNUT_FLASH_HIGH 0xFFF80000
-+#define WALNUT_FLASH_SIZE 0x80000
-+
-+static struct mtd_info *flash;
-+
-+static struct map_info walnut_map = {
-+ .name = "Walnut flash",
-+ .size = WALNUT_FLASH_SIZE,
-+ .bankwidth = 1,
-+};
-+
-+/* Actually, OpenBIOS is the last 128 KiB of the flash - better
-+ * partitioning could be made */
-+static struct mtd_partition walnut_partitions[] = {
-+ {
-+ .name = "OpenBIOS",
-+ .offset = 0x0,
-+ .size = WALNUT_FLASH_SIZE,
-+ /*.mask_flags = MTD_WRITEABLE, */ /* force read-only */
-+ }
-+};
-+
-+int __init init_walnut(void)
-+{
-+ u8 fpga_brds1;
-+ void *fpga_brds1_adr;
-+ void *fpga_status_adr;
-+ unsigned long flash_base;
-+
-+ /* this should already be mapped (platform/4xx/walnut.c) */
-+ fpga_status_adr = ioremap(WALNUT_FPGA_BASE, 8);
-+ if (!fpga_status_adr)
-+ return -ENOMEM;
-+
-+ fpga_brds1_adr = fpga_status_adr+5;
-+ fpga_brds1 = readb(fpga_brds1_adr);
-+ /* iounmap(fpga_status_adr); */
-+
-+ if (WALNUT_FLASH_ONBD_N(fpga_brds1)) {
-+ printk("The on-board flash is disabled (U79 sw 5)!");
-+ return -EIO;
-+ }
-+ if (WALNUT_FLASH_SRAM_SEL(fpga_brds1))
-+ flash_base = WALNUT_FLASH_LOW;
-+ else
-+ flash_base = WALNUT_FLASH_HIGH;
-+
-+ walnut_map.phys = flash_base;
-+ walnut_map.virt =
-+ (void __iomem *)ioremap(flash_base, walnut_map.size);
-+
-+ if (!walnut_map.virt) {
-+ printk("Failed to ioremap flash.\n");
-+ return -EIO;
-+ }
-+
-+ simple_map_init(&walnut_map);
-+
-+ flash = do_map_probe("jedec_probe", &walnut_map);
-+ if (flash) {
-+ flash->owner = THIS_MODULE;
-+ add_mtd_partitions(flash, walnut_partitions,
-+ ARRAY_SIZE(walnut_partitions));
-+ } else {
-+ printk("map probe failed for flash\n");
-+ return -ENXIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static void __exit cleanup_walnut(void)
-+{
-+ if (flash) {
-+ del_mtd_partitions(flash);
-+ map_destroy(flash);
-+ }
-+
-+ if (walnut_map.virt) {
-+ iounmap((void *)walnut_map.virt);
-+ walnut_map.virt = 0;
-+ }
-+}
-+
-+module_init(init_walnut);
-+module_exit(cleanup_walnut);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Heikki Lindholm <holindho@infradead.org>");
-+MODULE_DESCRIPTION("MTD map and partitions for IBM 405GP Walnut boards");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/maps/wr_sbc82xx_flash.c
-@@ -0,0 +1,181 @@
-+/*
-+ * $Id: wr_sbc82xx_flash.c,v 1.7 2004/11/04 13:24:15 gleixner Exp $
-+ *
-+ * Map for flash chips on Wind River PowerQUICC II SBC82xx board.
-+ *
-+ * Copyright (C) 2004 Red Hat, Inc.
-+ *
-+ * Author: David Woodhouse <dwmw2@infradead.org>
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <asm/io.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/config.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/immap_cpm2.h>
-+
-+static struct mtd_info *sbcmtd[3];
-+static struct mtd_partition *sbcmtd_parts[3];
-+
-+struct map_info sbc82xx_flash_map[3] = {
-+ {.name = "Boot flash"},
-+ {.name = "Alternate boot flash"},
-+ {.name = "User flash"}
-+};
-+
-+static struct mtd_partition smallflash_parts[] = {
-+ {
-+ .name = "space",
-+ .size = 0x100000,
-+ .offset = 0,
-+ }, {
-+ .name = "bootloader",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
-+ }
-+};
-+
-+static struct mtd_partition bigflash_parts[] = {
-+ {
-+ .name = "bootloader",
-+ .size = 0x00100000,
-+ .offset = 0,
-+ }, {
-+ .name = "file system",
-+ .size = 0x01f00000,
-+ .offset = MTDPART_OFS_APPEND,
-+ }, {
-+ .name = "boot config",
-+ .size = 0x00100000,
-+ .offset = MTDPART_OFS_APPEND,
-+ }, {
-+ .name = "space",
-+ .size = 0x01f00000,
-+ .offset = MTDPART_OFS_APPEND,
-+ }
-+};
-+
-+static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL};
-+
-+#define init_sbc82xx_one_flash(map, br, or) \
-+do { \
-+ (map).phys = (br & 1) ? (br & 0xffff8000) : 0; \
-+ (map).size = (br & 1) ? (~(or & 0xffff8000) + 1) : 0; \
-+ switch (br & 0x00001800) { \
-+ case 0x00000000: \
-+ case 0x00000800: (map).bankwidth = 1; break; \
-+ case 0x00001000: (map).bankwidth = 2; break; \
-+ case 0x00001800: (map).bankwidth = 4; break; \
-+ } \
-+} while (0);
-+
-+int __init init_sbc82xx_flash(void)
-+{
-+ volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl;
-+ int bigflash;
-+ int i;
-+
-+#ifdef CONFIG_SBC8560
-+ mc = ioremap(0xff700000 + 0x5000, sizeof(memctl_cpm2_t));
-+#else
-+ mc = &cpm2_immr->im_memctl;
-+#endif
-+
-+ bigflash = 1;
-+ if ((mc->memc_br0 & 0x00001800) == 0x00001800)
-+ bigflash = 0;
-+
-+ init_sbc82xx_one_flash(sbc82xx_flash_map[0], mc->memc_br0, mc->memc_or0);
-+ init_sbc82xx_one_flash(sbc82xx_flash_map[1], mc->memc_br6, mc->memc_or6);
-+ init_sbc82xx_one_flash(sbc82xx_flash_map[2], mc->memc_br1, mc->memc_or1);
-+
-+#ifdef CONFIG_SBC8560
-+ iounmap((void *) mc);
-+#endif
-+
-+ for (i=0; i<3; i++) {
-+ int8_t flashcs[3] = { 0, 6, 1 };
-+ int nr_parts;
-+
-+ printk(KERN_NOTICE "PowerQUICC II %s (%ld MiB on CS%d",
-+ sbc82xx_flash_map[i].name,
-+ (sbc82xx_flash_map[i].size >> 20),
-+ flashcs[i]);
-+ if (!sbc82xx_flash_map[i].phys) {
-+ /* We know it can't be at zero. */
-+ printk("): disabled by bootloader.\n");
-+ continue;
-+ }
-+ printk(" at %08lx)\n", sbc82xx_flash_map[i].phys);
-+
-+ sbc82xx_flash_map[i].virt = ioremap(sbc82xx_flash_map[i].phys, sbc82xx_flash_map[i].size);
-+
-+ if (!sbc82xx_flash_map[i].virt) {
-+ printk("Failed to ioremap\n");
-+ continue;
-+ }
-+
-+ simple_map_init(&sbc82xx_flash_map[i]);
-+
-+ sbcmtd[i] = do_map_probe("cfi_probe", &sbc82xx_flash_map[i]);
-+
-+ if (!sbcmtd[i])
-+ continue;
-+
-+ sbcmtd[i]->owner = THIS_MODULE;
-+
-+ nr_parts = parse_mtd_partitions(sbcmtd[i], part_probes,
-+ &sbcmtd_parts[i], 0);
-+ if (nr_parts > 0) {
-+ add_mtd_partitions (sbcmtd[i], sbcmtd_parts[i], nr_parts);
-+ continue;
-+ }
-+
-+ /* No partitioning detected. Use default */
-+ if (i == 2) {
-+ add_mtd_device(sbcmtd[i]);
-+ } else if (i == bigflash) {
-+ add_mtd_partitions (sbcmtd[i], bigflash_parts, ARRAY_SIZE(bigflash_parts));
-+ } else {
-+ add_mtd_partitions (sbcmtd[i], smallflash_parts, ARRAY_SIZE(smallflash_parts));
-+ }
-+ }
-+ return 0;
-+}
-+
-+static void __exit cleanup_sbc82xx_flash(void)
-+{
-+ int i;
-+
-+ for (i=0; i<3; i++) {
-+ if (!sbcmtd[i])
-+ continue;
-+
-+ if (i<2 || sbcmtd_parts[i])
-+ del_mtd_partitions(sbcmtd[i]);
-+ else
-+ del_mtd_device(sbcmtd[i]);
-+
-+ kfree(sbcmtd_parts[i]);
-+ map_destroy(sbcmtd[i]);
-+
-+ iounmap((void *)sbc82xx_flash_map[i].virt);
-+ sbc82xx_flash_map[i].virt = 0;
-+ }
-+}
-+
-+module_init(init_sbc82xx_flash);
-+module_exit(cleanup_sbc82xx_flash);
-+
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-+MODULE_DESCRIPTION("Flash map driver for WindRiver PowerQUICC II");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/mtd_blkdevs-24.c
-@@ -0,0 +1,692 @@
-+/*
-+ * $Id: mtd_blkdevs-24.c,v 1.17 2005/01/05 17:35:22 dwmw2 Exp $
-+ *
-+ * (C) 2003 David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * Interface to Linux 2.4 block layer for MTD 'translation layers'.
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/list.h>
-+#include <linux/fs.h>
-+#include <linux/mtd/blktrans.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/blkdev.h>
-+#include <linux/blk.h>
-+#include <linux/blkpg.h>
-+#include <linux/spinlock.h>
-+#include <linux/hdreg.h>
-+#include <linux/init.h>
-+#include <asm/semaphore.h>
-+#include <asm/uaccess.h>
-+
-+static LIST_HEAD(blktrans_majors);
-+
-+extern struct semaphore mtd_table_mutex;
-+extern struct mtd_info *mtd_table[];
-+
-+struct mtd_blkcore_priv {
-+ devfs_handle_t devfs_dir_handle;
-+ int blksizes[256];
-+ int sizes[256];
-+ struct hd_struct part_table[256];
-+ struct gendisk gd;
-+ spinlock_t devs_lock; /* See comment in _request function */
-+ struct completion thread_dead;
-+ int exiting;
-+ wait_queue_head_t thread_wq;
-+};
-+
-+static inline struct mtd_blktrans_dev *tr_get_dev(struct mtd_blktrans_ops *tr,
-+ int devnum)
-+{
-+ struct list_head *this;
-+ struct mtd_blktrans_dev *d;
-+
-+ list_for_each(this, &tr->devs) {
-+ d = list_entry(this, struct mtd_blktrans_dev, list);
-+
-+ if (d->devnum == devnum)
-+ return d;
-+ }
-+ return NULL;
-+}
-+
-+static inline struct mtd_blktrans_ops *get_tr(int major)
-+{
-+ struct list_head *this;
-+ struct mtd_blktrans_ops *t;
-+
-+ list_for_each(this, &blktrans_majors) {
-+ t = list_entry(this, struct mtd_blktrans_ops, list);
-+
-+ if (t->major == major)
-+ return t;
-+ }
-+ return NULL;
-+}
-+
-+static int do_blktrans_request(struct mtd_blktrans_ops *tr,
-+ struct mtd_blktrans_dev *dev,
-+ struct request *req)
-+{
-+ unsigned long block, nsect;
-+ char *buf;
-+ int minor;
-+
-+ minor = MINOR(req->rq_dev);
-+ block = req->sector;
-+ nsect = req->current_nr_sectors;
-+ buf = req->buffer;
-+
-+ if (block + nsect > tr->blkcore_priv->part_table[minor].nr_sects) {
-+ printk(KERN_WARNING "Access beyond end of device.\n");
-+ return 0;
-+ }
-+ block += tr->blkcore_priv->part_table[minor].start_sect;
-+
-+ switch(req->cmd) {
-+ case READ:
-+ for (; nsect > 0; nsect--, block++, buf += 512)
-+ if (tr->readsect(dev, block, buf))
-+ return 0;
-+ return 1;
-+
-+ case WRITE:
-+ if (!tr->writesect)
-+ return 0;
-+
-+ for (; nsect > 0; nsect--, block++, buf += 512)
-+ if (tr->writesect(dev, block, buf))
-+ return 0;
-+ return 1;
-+
-+ default:
-+ printk(KERN_NOTICE "Unknown request cmd %d\n", req->cmd);
-+ return 0;
-+ }
-+}
-+
-+static int mtd_blktrans_thread(void *arg)
-+{
-+ struct mtd_blktrans_ops *tr = arg;
-+ struct request_queue *rq = BLK_DEFAULT_QUEUE(tr->major);
-+
-+ /* we might get involved when memory gets low, so use PF_MEMALLOC */
-+ current->flags |= PF_MEMALLOC;
-+
-+ snprintf(current->comm, sizeof(current->comm), "%sd", tr->name);
-+
-+ /* daemonize() doesn't do this for us since some kernel threads
-+ actually want to deal with signals. We can't just call
-+ exit_sighand() since that'll cause an oops when we finally
-+ do exit. */
-+ spin_lock_irq(&current->sigmask_lock);
-+ sigfillset(&current->blocked);
-+ recalc_sigpending();
-+ spin_unlock_irq(&current->sigmask_lock);
-+
-+ daemonize("%sd", tr->name);
-+
-+ while (!tr->blkcore_priv->exiting) {
-+ struct request *req;
-+ struct mtd_blktrans_dev *dev;
-+ int devnum;
-+ int res = 0;
-+ DECLARE_WAITQUEUE(wait, current);
-+
-+ spin_lock_irq(&io_request_lock);
-+
-+ if (list_empty(&rq->queue_head)) {
-+
-+ add_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ spin_unlock_irq(&io_request_lock);
-+
-+ schedule();
-+ remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
-+
-+ continue;
-+ }
-+
-+ req = blkdev_entry_next_request(&rq->queue_head);
-+
-+ devnum = MINOR(req->rq_dev) >> tr->part_bits;
-+
-+ /* The ll_rw_blk code knows not to touch the request
-+ at the head of the queue */
-+ spin_unlock_irq(&io_request_lock);
-+
-+ /* FIXME: Where can we store the dev, on which
-+ we already have a refcount anyway? We need to
-+ lock against concurrent addition/removal of devices,
-+ but if we use the mtd_table_mutex we deadlock when
-+ grok_partitions is called from the registration
-+ callbacks. */
-+ spin_lock(&tr->blkcore_priv->devs_lock);
-+ dev = tr_get_dev(tr, devnum);
-+ spin_unlock(&tr->blkcore_priv->devs_lock);
-+
-+ BUG_ON(!dev);
-+
-+ /* Ensure serialisation of requests */
-+ down(&dev->sem);
-+
-+ res = do_blktrans_request(tr, dev, req);
-+ up(&dev->sem);
-+
-+ if (!end_that_request_first(req, res, tr->name)) {
-+ spin_lock_irq(&io_request_lock);
-+ blkdev_dequeue_request(req);
-+ end_that_request_last(req);
-+ spin_unlock_irq(&io_request_lock);
-+ }
-+ }
-+ complete_and_exit(&tr->blkcore_priv->thread_dead, 0);
-+}
-+
-+static void mtd_blktrans_request(struct request_queue *rq)
-+{
-+ struct mtd_blktrans_ops *tr = rq->queuedata;
-+ wake_up(&tr->blkcore_priv->thread_wq);
-+}
-+
-+int blktrans_open(struct inode *i, struct file *f)
-+{
-+ struct mtd_blktrans_ops *tr = NULL;
-+ struct mtd_blktrans_dev *dev = NULL;
-+ int major_nr = MAJOR(i->i_rdev);
-+ int minor_nr = MINOR(i->i_rdev);
-+ int devnum;
-+ int ret = -ENODEV;
-+
-+ if (is_read_only(i->i_rdev) && (f->f_mode & FMODE_WRITE))
-+ return -EROFS;
-+
-+ down(&mtd_table_mutex);
-+
-+ tr = get_tr(major_nr);
-+
-+ if (!tr)
-+ goto out;
-+
-+ devnum = minor_nr >> tr->part_bits;
-+
-+ dev = tr_get_dev(tr, devnum);
-+
-+ if (!dev)
-+ goto out;
-+
-+ if (!tr->blkcore_priv->part_table[minor_nr].nr_sects) {
-+ ret = -ENODEV;
-+ goto out;
-+ }
-+
-+ if (!try_inc_mod_count(dev->mtd->owner))
-+ goto out;
-+
-+ if (!try_inc_mod_count(tr->owner))
-+ goto out_tr;
-+
-+ dev->mtd->usecount++;
-+
-+ ret = 0;
-+ if (tr->open && (ret = tr->open(dev))) {
-+ dev->mtd->usecount--;
-+ if (dev->mtd->owner)
-+ __MOD_DEC_USE_COUNT(dev->mtd->owner);
-+ out_tr:
-+ if (tr->owner)
-+ __MOD_DEC_USE_COUNT(tr->owner);
-+ }
-+ out:
-+ up(&mtd_table_mutex);
-+
-+ return ret;
-+}
-+
-+int blktrans_release(struct inode *i, struct file *f)
-+{
-+ struct mtd_blktrans_dev *dev;
-+ struct mtd_blktrans_ops *tr;
-+ int ret = 0;
-+ int devnum;
-+
-+ down(&mtd_table_mutex);
-+
-+ tr = get_tr(MAJOR(i->i_rdev));
-+ if (!tr) {
-+ up(&mtd_table_mutex);
-+ return -ENODEV;
-+ }
-+
-+ devnum = MINOR(i->i_rdev) >> tr->part_bits;
-+ dev = tr_get_dev(tr, devnum);
-+
-+ if (!dev) {
-+ up(&mtd_table_mutex);
-+ return -ENODEV;
-+ }
-+
-+ if (tr->release)
-+ ret = tr->release(dev);
-+
-+ if (!ret) {
-+ dev->mtd->usecount--;
-+ if (dev->mtd->owner)
-+ __MOD_DEC_USE_COUNT(dev->mtd->owner);
-+ if (tr->owner)
-+ __MOD_DEC_USE_COUNT(tr->owner);
-+ }
-+
-+ up(&mtd_table_mutex);
-+
-+ return ret;
-+}
-+
-+static int mtd_blktrans_rrpart(kdev_t rdev, struct mtd_blktrans_ops *tr,
-+ struct mtd_blktrans_dev *dev)
-+{
-+ struct gendisk *gd = &(tr->blkcore_priv->gd);
-+ int i;
-+ int minor = MINOR(rdev);
-+
-+ if (minor & ((1<<tr->part_bits)-1) || !tr->part_bits) {
-+ /* BLKRRPART on a partition. Go away. */
-+ return -ENOTTY;
-+ }
-+
-+ if (!capable(CAP_SYS_ADMIN))
-+ return -EACCES;
-+
-+ /* We are required to prevent simultaneous open() ourselves.
-+ The core doesn't do that for us. Did I ever mention how
-+ much the Linux block layer sucks? Sledgehammer approach... */
-+ down(&mtd_table_mutex);
-+
-+ for (i=0; i < (1<<tr->part_bits); i++) {
-+ invalidate_device(MKDEV(tr->major, minor+i), 1);
-+ gd->part[minor + i].start_sect = 0;
-+ gd->part[minor + i].nr_sects = 0;
-+ }
-+
-+ grok_partitions(gd, minor, 1 << tr->part_bits,
-+ dev->size);
-+ up(&mtd_table_mutex);
-+
-+ return 0;
-+}
-+
-+static int blktrans_ioctl(struct inode *inode, struct file *file,
-+ unsigned int cmd, unsigned long arg)
-+{
-+ struct mtd_blktrans_dev *dev;
-+ struct mtd_blktrans_ops *tr;
-+ int devnum;
-+
-+ switch(cmd) {
-+ case BLKGETSIZE:
-+ case BLKGETSIZE64:
-+ case BLKBSZSET:
-+ case BLKBSZGET:
-+ case BLKROSET:
-+ case BLKROGET:
-+ case BLKRASET:
-+ case BLKRAGET:
-+ case BLKPG:
-+ case BLKELVGET:
-+ case BLKELVSET:
-+ return blk_ioctl(inode->i_rdev, cmd, arg);
-+ }
-+
-+ down(&mtd_table_mutex);
-+
-+ tr = get_tr(MAJOR(inode->i_rdev));
-+ if (!tr) {
-+ up(&mtd_table_mutex);
-+ return -ENODEV;
-+ }
-+
-+ devnum = MINOR(inode->i_rdev) >> tr->part_bits;
-+ dev = tr_get_dev(tr, devnum);
-+
-+ up(&mtd_table_mutex);
-+
-+ if (!dev)
-+ return -ENODEV;
-+
-+ switch(cmd) {
-+ case BLKRRPART:
-+ return mtd_blktrans_rrpart(inode->i_rdev, tr, dev);
-+
-+ case BLKFLSBUF:
-+ blk_ioctl(inode->i_rdev, cmd, arg);
-+ if (tr->flush)
-+ return tr->flush(dev);
-+ /* The core code did the work, we had nothing to do. */
-+ return 0;
-+
-+ case HDIO_GETGEO:
-+ if (tr->getgeo) {
-+ struct hd_geometry g;
-+ struct gendisk *gd = &(tr->blkcore_priv->gd);
-+ int ret;
-+
-+ memset(&g, 0, sizeof(g));
-+ ret = tr->getgeo(dev, &g);
-+ if (ret)
-+ return ret;
-+
-+ g.start = gd->part[MINOR(inode->i_rdev)].start_sect;
-+ if (copy_to_user((void *)arg, &g, sizeof(g)))
-+ return -EFAULT;
-+ return 0;
-+ } /* else */
-+ default:
-+ return -ENOTTY;
-+ }
-+}
-+
-+struct block_device_operations mtd_blktrans_ops = {
-+ .owner = THIS_MODULE,
-+ .open = blktrans_open,
-+ .release = blktrans_release,
-+ .ioctl = blktrans_ioctl,
-+};
-+
-+int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
-+{
-+ struct mtd_blktrans_ops *tr = new->tr;
-+ struct list_head *this;
-+ int last_devnum = -1;
-+ int i;
-+
-+ if (!down_trylock(&mtd_table_mutex)) {
-+ up(&mtd_table_mutex);
-+ BUG();
-+ }
-+
-+ spin_lock(&tr->blkcore_priv->devs_lock);
-+
-+ list_for_each(this, &tr->devs) {
-+ struct mtd_blktrans_dev *d = list_entry(this, struct mtd_blktrans_dev, list);
-+ if (new->devnum == -1) {
-+ /* Use first free number */
-+ if (d->devnum != last_devnum+1) {
-+ /* Found a free devnum. Plug it in here */
-+ new->devnum = last_devnum+1;
-+ list_add_tail(&new->list, &d->list);
-+ goto added;
-+ }
-+ } else if (d->devnum == new->devnum) {
-+ /* Required number taken */
-+ spin_unlock(&tr->blkcore_priv->devs_lock);
-+ return -EBUSY;
-+ } else if (d->devnum > new->devnum) {
-+ /* Required number was free */
-+ list_add_tail(&new->list, &d->list);
-+ goto added;
-+ }
-+ last_devnum = d->devnum;
-+ }
-+ if (new->devnum == -1)
-+ new->devnum = last_devnum+1;
-+
-+ if ((new->devnum << tr->part_bits) > 256) {
-+ spin_unlock(&tr->blkcore_priv->devs_lock);
-+ return -EBUSY;
-+ }
-+
-+ init_MUTEX(&new->sem);
-+ list_add_tail(&new->list, &tr->devs);
-+ added:
-+ spin_unlock(&tr->blkcore_priv->devs_lock);
-+
-+ if (!tr->writesect)
-+ new->readonly = 1;
-+
-+ for (i = new->devnum << tr->part_bits;
-+ i < (new->devnum+1) << tr->part_bits;
-+ i++) {
-+ set_device_ro(MKDEV(tr->major, i), new->readonly);
-+ tr->blkcore_priv->blksizes[i] = new->blksize;
-+ tr->blkcore_priv->sizes[i] = 0;
-+ tr->blkcore_priv->part_table[i].nr_sects = 0;
-+ tr->blkcore_priv->part_table[i].start_sect = 0;
-+ }
-+
-+ /*
-+ <viro_zzz> dwmw2: BLOCK_SIZE_BITS has nothing to do with block devices
-+ <viro> dwmw2: any code which sets blk_size[][] should be
-+ size >> 10 /+ 2.4 and its dumb units */
-+
-+ tr->blkcore_priv->sizes[new->devnum << tr->part_bits] =
-+ (new->size * new->blksize) >> 10; /* 2.4 and its dumb units */
-+
-+ /* But this is still in device's sectors? $DEITY knows */
-+ tr->blkcore_priv->part_table[new->devnum << tr->part_bits].nr_sects = new->size;
-+
-+ if (tr->part_bits) {
-+ grok_partitions(&tr->blkcore_priv->gd, new->devnum,
-+ 1 << tr->part_bits, new->size);
-+ }
-+#ifdef CONFIG_DEVFS_FS
-+ if (!tr->part_bits) {
-+ char name[2];
-+
-+ name[0] = '0' + new->devnum;
-+ name[1] = 0;
-+
-+ new->blkcore_priv =
-+ devfs_register(tr->blkcore_priv->devfs_dir_handle,
-+ name, DEVFS_FL_DEFAULT, tr->major,
-+ new->devnum, S_IFBLK|S_IRUGO|S_IWUGO,
-+ &mtd_blktrans_ops, NULL);
-+ }
-+#endif
-+ return 0;
-+}
-+
-+int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
-+{
-+ struct mtd_blktrans_ops *tr = old->tr;
-+ int i;
-+
-+ if (!down_trylock(&mtd_table_mutex)) {
-+ up(&mtd_table_mutex);
-+ BUG();
-+ }
-+
-+#ifdef CONFIG_DEVFS_FS
-+ if (!tr->part_bits) {
-+ devfs_unregister(old->blkcore_priv);
-+ old->blkcore_priv = NULL;
-+ } else {
-+ devfs_register_partitions(&tr->blkcore_priv->gd,
-+ old->devnum << tr->part_bits, 1);
-+ }
-+#endif
-+ spin_lock(&tr->blkcore_priv->devs_lock);
-+ list_del(&old->list);
-+ spin_unlock(&tr->blkcore_priv->devs_lock);
-+
-+ for (i = (old->devnum << tr->part_bits);
-+ i < ((old->devnum+1) << tr->part_bits); i++) {
-+ tr->blkcore_priv->sizes[i] = 0;
-+ tr->blkcore_priv->part_table[i].nr_sects = 0;
-+ tr->blkcore_priv->part_table[i].start_sect = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+void blktrans_notify_remove(struct mtd_info *mtd)
-+{
-+ struct list_head *this, *this2, *next;
-+
-+ list_for_each(this, &blktrans_majors) {
-+ struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
-+
-+ list_for_each_safe(this2, next, &tr->devs) {
-+ struct mtd_blktrans_dev *dev = list_entry(this2, struct mtd_blktrans_dev, list);
-+
-+ if (dev->mtd == mtd)
-+ tr->remove_dev(dev);
-+ }
-+ }
-+}
-+
-+void blktrans_notify_add(struct mtd_info *mtd)
-+{
-+ struct list_head *this;
-+
-+ if (mtd->type == MTD_ABSENT)
-+ return;
-+
-+ list_for_each(this, &blktrans_majors) {
-+ struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
-+
-+ tr->add_mtd(tr, mtd);
-+ }
-+
-+}
-+
-+static struct mtd_notifier blktrans_notifier = {
-+ .add = blktrans_notify_add,
-+ .remove = blktrans_notify_remove,
-+};
-+
-+int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
-+{
-+ int ret, i;
-+
-+ /* Register the notifier if/when the first device type is
-+ registered, to prevent the link/init ordering from fucking
-+ us over. */
-+ if (!blktrans_notifier.list.next)
-+ register_mtd_user(&blktrans_notifier);
-+
-+ tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);
-+ if (!tr->blkcore_priv)
-+ return -ENOMEM;
-+
-+ memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv));
-+
-+ down(&mtd_table_mutex);
-+
-+ ret = devfs_register_blkdev(tr->major, tr->name, &mtd_blktrans_ops);
-+ if (ret) {
-+ printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n",
-+ tr->name, tr->major, ret);
-+ kfree(tr->blkcore_priv);
-+ up(&mtd_table_mutex);
-+ return ret;
-+ }
-+
-+ blk_init_queue(BLK_DEFAULT_QUEUE(tr->major), &mtd_blktrans_request);
-+ (BLK_DEFAULT_QUEUE(tr->major))->queuedata = tr;
-+
-+ init_completion(&tr->blkcore_priv->thread_dead);
-+ init_waitqueue_head(&tr->blkcore_priv->thread_wq);
-+
-+ ret = kernel_thread(mtd_blktrans_thread, tr,
-+ CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
-+ if (ret < 0) {
-+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(tr->major));
-+ devfs_unregister_blkdev(tr->major, tr->name);
-+ kfree(tr->blkcore_priv);
-+ up(&mtd_table_mutex);
-+ return ret;
-+ }
-+
-+ tr->blkcore_priv->devfs_dir_handle =
-+ devfs_mk_dir(NULL, tr->name, NULL);
-+
-+ blksize_size[tr->major] = tr->blkcore_priv->blksizes;
-+ blk_size[tr->major] = tr->blkcore_priv->sizes;
-+
-+ tr->blkcore_priv->gd.major = tr->major;
-+ tr->blkcore_priv->gd.major_name = tr->name;
-+ tr->blkcore_priv->gd.minor_shift = tr->part_bits;
-+ tr->blkcore_priv->gd.max_p = (1<<tr->part_bits) - 1;
-+ tr->blkcore_priv->gd.part = tr->blkcore_priv->part_table;
-+ tr->blkcore_priv->gd.sizes = tr->blkcore_priv->sizes;
-+ tr->blkcore_priv->gd.nr_real = 256 >> tr->part_bits;
-+
-+ spin_lock_init(&tr->blkcore_priv->devs_lock);
-+
-+ add_gendisk(&tr->blkcore_priv->gd);
-+
-+ INIT_LIST_HEAD(&tr->devs);
-+ list_add(&tr->list, &blktrans_majors);
-+
-+ for (i=0; i<MAX_MTD_DEVICES; i++) {
-+ if (mtd_table[i] && mtd_table[i]->type != MTD_ABSENT)
-+ tr->add_mtd(tr, mtd_table[i]);
-+ }
-+ up(&mtd_table_mutex);
-+
-+ return 0;
-+}
-+
-+int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr)
-+{
-+ struct list_head *this, *next;
-+
-+ down(&mtd_table_mutex);
-+
-+ /* Clean up the kernel thread */
-+ tr->blkcore_priv->exiting = 1;
-+ wake_up(&tr->blkcore_priv->thread_wq);
-+ wait_for_completion(&tr->blkcore_priv->thread_dead);
-+
-+ /* Remove it from the list of active majors */
-+ list_del(&tr->list);
-+
-+ /* Remove each of its devices */
-+ list_for_each_safe(this, next, &tr->devs) {
-+ struct mtd_blktrans_dev *dev = list_entry(this, struct mtd_blktrans_dev, list);
-+ tr->remove_dev(dev);
-+ }
-+
-+ blksize_size[tr->major] = NULL;
-+ blk_size[tr->major] = NULL;
-+
-+ del_gendisk(&tr->blkcore_priv->gd);
-+
-+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(tr->major));
-+ devfs_unregister_blkdev(tr->major, tr->name);
-+
-+ devfs_unregister(tr->blkcore_priv->devfs_dir_handle);
-+
-+ up(&mtd_table_mutex);
-+
-+ kfree(tr->blkcore_priv);
-+
-+ if (!list_empty(&tr->devs))
-+ BUG();
-+ return 0;
-+}
-+
-+static void __exit mtd_blktrans_exit(void)
-+{
-+ /* No race here -- if someone's currently in register_mtd_blktrans
-+ we're screwed anyway. */
-+ if (blktrans_notifier.list.next)
-+ unregister_mtd_user(&blktrans_notifier);
-+}
-+
-+module_exit(mtd_blktrans_exit);
-+
-+EXPORT_SYMBOL_GPL(register_mtd_blktrans);
-+EXPORT_SYMBOL_GPL(deregister_mtd_blktrans);
-+EXPORT_SYMBOL_GPL(add_mtd_blktrans_dev);
-+EXPORT_SYMBOL_GPL(del_mtd_blktrans_dev);
-+
-+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Common interface to block layer for MTD 'translation layers'");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/mtd_blkdevs.c
-@@ -0,0 +1,478 @@
-+/*
-+ * $Id: mtd_blkdevs.c,v 1.24 2004/11/16 18:28:59 dwmw2 Exp $
-+ *
-+ * (C) 2003 David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * Interface to Linux 2.5 block layer for MTD 'translation layers'.
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/list.h>
-+#include <linux/fs.h>
-+#include <linux/mtd/blktrans.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/blkdev.h>
-+#include <linux/blkpg.h>
-+#include <linux/spinlock.h>
-+#include <linux/hdreg.h>
-+#include <linux/init.h>
-+#include <asm/semaphore.h>
-+#include <asm/uaccess.h>
-+#include <linux/devfs_fs_kernel.h>
-+
-+static LIST_HEAD(blktrans_majors);
-+
-+extern struct semaphore mtd_table_mutex;
-+extern struct mtd_info *mtd_table[];
-+
-+struct mtd_blkcore_priv {
-+ struct completion thread_dead;
-+ int exiting;
-+ wait_queue_head_t thread_wq;
-+ struct request_queue *rq;
-+ spinlock_t queue_lock;
-+};
-+
-+static int do_blktrans_request(struct mtd_blktrans_ops *tr,
-+ struct mtd_blktrans_dev *dev,
-+ struct request *req)
-+{
-+ unsigned long block, nsect;
-+ char *buf;
-+
-+ block = req->sector;
-+ nsect = req->current_nr_sectors;
-+ buf = req->buffer;
-+
-+ if (!(req->flags & REQ_CMD))
-+ return 0;
-+
-+ if (block + nsect > get_capacity(req->rq_disk))
-+ return 0;
-+
-+ switch(rq_data_dir(req)) {
-+ case READ:
-+ for (; nsect > 0; nsect--, block++, buf += 512)
-+ if (tr->readsect(dev, block, buf))
-+ return 0;
-+ return 1;
-+
-+ case WRITE:
-+ if (!tr->writesect)
-+ return 0;
-+
-+ for (; nsect > 0; nsect--, block++, buf += 512)
-+ if (tr->writesect(dev, block, buf))
-+ return 0;
-+ return 1;
-+
-+ default:
-+ printk(KERN_NOTICE "Unknown request %ld\n", rq_data_dir(req));
-+ return 0;
-+ }
-+}
-+
-+static int mtd_blktrans_thread(void *arg)
-+{
-+ struct mtd_blktrans_ops *tr = arg;
-+ struct request_queue *rq = tr->blkcore_priv->rq;
-+
-+ /* we might get involved when memory gets low, so use PF_MEMALLOC */
-+ current->flags |= PF_MEMALLOC | PF_NOFREEZE;
-+
-+ daemonize("%sd", tr->name);
-+
-+ /* daemonize() doesn't do this for us since some kernel threads
-+ actually want to deal with signals. We can't just call
-+ exit_sighand() since that'll cause an oops when we finally
-+ do exit. */
-+ spin_lock_irq(&current->sighand->siglock);
-+ sigfillset(&current->blocked);
-+ recalc_sigpending();
-+ spin_unlock_irq(&current->sighand->siglock);
-+
-+ spin_lock_irq(rq->queue_lock);
-+
-+ while (!tr->blkcore_priv->exiting) {
-+ struct request *req;
-+ struct mtd_blktrans_dev *dev;
-+ int res = 0;
-+ DECLARE_WAITQUEUE(wait, current);
-+
-+ req = elv_next_request(rq);
-+
-+ if (!req) {
-+ add_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ spin_unlock_irq(rq->queue_lock);
-+
-+ schedule();
-+ remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
-+
-+ spin_lock_irq(rq->queue_lock);
-+
-+ continue;
-+ }
-+
-+ dev = req->rq_disk->private_data;
-+ tr = dev->tr;
-+
-+ spin_unlock_irq(rq->queue_lock);
-+
-+ down(&dev->sem);
-+ res = do_blktrans_request(tr, dev, req);
-+ up(&dev->sem);
-+
-+ spin_lock_irq(rq->queue_lock);
-+
-+ end_request(req, res);
-+ }
-+ spin_unlock_irq(rq->queue_lock);
-+
-+ complete_and_exit(&tr->blkcore_priv->thread_dead, 0);
-+}
-+
-+static void mtd_blktrans_request(struct request_queue *rq)
-+{
-+ struct mtd_blktrans_ops *tr = rq->queuedata;
-+ wake_up(&tr->blkcore_priv->thread_wq);
-+}
-+
-+
-+static int blktrans_open(struct inode *i, struct file *f)
-+{
-+ struct mtd_blktrans_dev *dev;
-+ struct mtd_blktrans_ops *tr;
-+ int ret = -ENODEV;
-+
-+ dev = i->i_bdev->bd_disk->private_data;
-+ tr = dev->tr;
-+
-+ if (!try_module_get(dev->mtd->owner))
-+ goto out;
-+
-+ if (!try_module_get(tr->owner))
-+ goto out_tr;
-+
-+ /* FIXME: Locking. A hot pluggable device can go away
-+ (del_mtd_device can be called for it) without its module
-+ being unloaded. */
-+ dev->mtd->usecount++;
-+
-+ ret = 0;
-+ if (tr->open && (ret = tr->open(dev))) {
-+ dev->mtd->usecount--;
-+ module_put(dev->mtd->owner);
-+ out_tr:
-+ module_put(tr->owner);
-+ }
-+ out:
-+ return ret;
-+}
-+
-+static int blktrans_release(struct inode *i, struct file *f)
-+{
-+ struct mtd_blktrans_dev *dev;
-+ struct mtd_blktrans_ops *tr;
-+ int ret = 0;
-+
-+ dev = i->i_bdev->bd_disk->private_data;
-+ tr = dev->tr;
-+
-+ if (tr->release)
-+ ret = tr->release(dev);
-+
-+ if (!ret) {
-+ dev->mtd->usecount--;
-+ module_put(dev->mtd->owner);
-+ module_put(tr->owner);
-+ }
-+
-+ return ret;
-+}
-+
-+
-+static int blktrans_ioctl(struct inode *inode, struct file *file,
-+ unsigned int cmd, unsigned long arg)
-+{
-+ struct mtd_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data;
-+ struct mtd_blktrans_ops *tr = dev->tr;
-+
-+ switch (cmd) {
-+ case BLKFLSBUF:
-+ if (tr->flush)
-+ return tr->flush(dev);
-+ /* The core code did the work, we had nothing to do. */
-+ return 0;
-+
-+ case HDIO_GETGEO:
-+ if (tr->getgeo) {
-+ struct hd_geometry g;
-+ int ret;
-+
-+ memset(&g, 0, sizeof(g));
-+ ret = tr->getgeo(dev, &g);
-+ if (ret)
-+ return ret;
-+
-+ g.start = get_start_sect(inode->i_bdev);
-+ if (copy_to_user((void __user *)arg, &g, sizeof(g)))
-+ return -EFAULT;
-+ return 0;
-+ } /* else */
-+ default:
-+ return -ENOTTY;
-+ }
-+}
-+
-+struct block_device_operations mtd_blktrans_ops = {
-+ .owner = THIS_MODULE,
-+ .open = blktrans_open,
-+ .release = blktrans_release,
-+ .ioctl = blktrans_ioctl,
-+};
-+
-+int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
-+{
-+ struct mtd_blktrans_ops *tr = new->tr;
-+ struct list_head *this;
-+ int last_devnum = -1;
-+ struct gendisk *gd;
-+
-+ if (!down_trylock(&mtd_table_mutex)) {
-+ up(&mtd_table_mutex);
-+ BUG();
-+ }
-+
-+ list_for_each(this, &tr->devs) {
-+ struct mtd_blktrans_dev *d = list_entry(this, struct mtd_blktrans_dev, list);
-+ if (new->devnum == -1) {
-+ /* Use first free number */
-+ if (d->devnum != last_devnum+1) {
-+ /* Found a free devnum. Plug it in here */
-+ new->devnum = last_devnum+1;
-+ list_add_tail(&new->list, &d->list);
-+ goto added;
-+ }
-+ } else if (d->devnum == new->devnum) {
-+ /* Required number taken */
-+ return -EBUSY;
-+ } else if (d->devnum > new->devnum) {
-+ /* Required number was free */
-+ list_add_tail(&new->list, &d->list);
-+ goto added;
-+ }
-+ last_devnum = d->devnum;
-+ }
-+ if (new->devnum == -1)
-+ new->devnum = last_devnum+1;
-+
-+ if ((new->devnum << tr->part_bits) > 256) {
-+ return -EBUSY;
-+ }
-+
-+ init_MUTEX(&new->sem);
-+ list_add_tail(&new->list, &tr->devs);
-+ added:
-+ if (!tr->writesect)
-+ new->readonly = 1;
-+
-+ gd = alloc_disk(1 << tr->part_bits);
-+ if (!gd) {
-+ list_del(&new->list);
-+ return -ENOMEM;
-+ }
-+ gd->major = tr->major;
-+ gd->first_minor = (new->devnum) << tr->part_bits;
-+ gd->fops = &mtd_blktrans_ops;
-+
-+ snprintf(gd->disk_name, sizeof(gd->disk_name),
-+ "%s%c", tr->name, (tr->part_bits?'a':'0') + new->devnum);
-+ snprintf(gd->devfs_name, sizeof(gd->devfs_name),
-+ "%s/%c", tr->name, (tr->part_bits?'a':'0') + new->devnum);
-+
-+ /* 2.5 has capacity in units of 512 bytes while still
-+ having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */
-+ set_capacity(gd, (new->size * new->blksize) >> 9);
-+
-+ gd->private_data = new;
-+ new->blkcore_priv = gd;
-+ gd->queue = tr->blkcore_priv->rq;
-+
-+ if (new->readonly)
-+ set_disk_ro(gd, 1);
-+
-+ add_disk(gd);
-+
-+ return 0;
-+}
-+
-+int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
-+{
-+ if (!down_trylock(&mtd_table_mutex)) {
-+ up(&mtd_table_mutex);
-+ BUG();
-+ }
-+
-+ list_del(&old->list);
-+
-+ del_gendisk(old->blkcore_priv);
-+ put_disk(old->blkcore_priv);
-+
-+ return 0;
-+}
-+
-+static void blktrans_notify_remove(struct mtd_info *mtd)
-+{
-+ struct list_head *this, *this2, *next;
-+
-+ list_for_each(this, &blktrans_majors) {
-+ struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
-+
-+ list_for_each_safe(this2, next, &tr->devs) {
-+ struct mtd_blktrans_dev *dev = list_entry(this2, struct mtd_blktrans_dev, list);
-+
-+ if (dev->mtd == mtd)
-+ tr->remove_dev(dev);
-+ }
-+ }
-+}
-+
-+static void blktrans_notify_add(struct mtd_info *mtd)
-+{
-+ struct list_head *this;
-+
-+ if (mtd->type == MTD_ABSENT)
-+ return;
-+
-+ list_for_each(this, &blktrans_majors) {
-+ struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
-+
-+ tr->add_mtd(tr, mtd);
-+ }
-+
-+}
-+
-+static struct mtd_notifier blktrans_notifier = {
-+ .add = blktrans_notify_add,
-+ .remove = blktrans_notify_remove,
-+};
-+
-+int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
-+{
-+ int ret, i;
-+
-+ /* Register the notifier if/when the first device type is
-+ registered, to prevent the link/init ordering from fucking
-+ us over. */
-+ if (!blktrans_notifier.list.next)
-+ register_mtd_user(&blktrans_notifier);
-+
-+ tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);
-+ if (!tr->blkcore_priv)
-+ return -ENOMEM;
-+
-+ memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv));
-+
-+ down(&mtd_table_mutex);
-+
-+ ret = register_blkdev(tr->major, tr->name);
-+ if (ret) {
-+ printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n",
-+ tr->name, tr->major, ret);
-+ kfree(tr->blkcore_priv);
-+ up(&mtd_table_mutex);
-+ return ret;
-+ }
-+ spin_lock_init(&tr->blkcore_priv->queue_lock);
-+ init_completion(&tr->blkcore_priv->thread_dead);
-+ init_waitqueue_head(&tr->blkcore_priv->thread_wq);
-+
-+ tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);
-+ if (!tr->blkcore_priv->rq) {
-+ unregister_blkdev(tr->major, tr->name);
-+ kfree(tr->blkcore_priv);
-+ up(&mtd_table_mutex);
-+ return -ENOMEM;
-+ }
-+
-+ tr->blkcore_priv->rq->queuedata = tr;
-+
-+ ret = kernel_thread(mtd_blktrans_thread, tr, CLONE_KERNEL);
-+ if (ret < 0) {
-+ blk_cleanup_queue(tr->blkcore_priv->rq);
-+ unregister_blkdev(tr->major, tr->name);
-+ kfree(tr->blkcore_priv);
-+ up(&mtd_table_mutex);
-+ return ret;
-+ }
-+
-+ devfs_mk_dir(tr->name);
-+
-+ INIT_LIST_HEAD(&tr->devs);
-+ list_add(&tr->list, &blktrans_majors);
-+
-+ for (i=0; i<MAX_MTD_DEVICES; i++) {
-+ if (mtd_table[i] && mtd_table[i]->type != MTD_ABSENT)
-+ tr->add_mtd(tr, mtd_table[i]);
-+ }
-+
-+ up(&mtd_table_mutex);
-+
-+ return 0;
-+}
-+
-+int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr)
-+{
-+ struct list_head *this, *next;
-+
-+ down(&mtd_table_mutex);
-+
-+ /* Clean up the kernel thread */
-+ tr->blkcore_priv->exiting = 1;
-+ wake_up(&tr->blkcore_priv->thread_wq);
-+ wait_for_completion(&tr->blkcore_priv->thread_dead);
-+
-+ /* Remove it from the list of active majors */
-+ list_del(&tr->list);
-+
-+ list_for_each_safe(this, next, &tr->devs) {
-+ struct mtd_blktrans_dev *dev = list_entry(this, struct mtd_blktrans_dev, list);
-+ tr->remove_dev(dev);
-+ }
-+
-+ devfs_remove(tr->name);
-+ blk_cleanup_queue(tr->blkcore_priv->rq);
-+ unregister_blkdev(tr->major, tr->name);
-+
-+ up(&mtd_table_mutex);
-+
-+ kfree(tr->blkcore_priv);
-+
-+ if (!list_empty(&tr->devs))
-+ BUG();
-+ return 0;
-+}
-+
-+static void __exit mtd_blktrans_exit(void)
-+{
-+ /* No race here -- if someone's currently in register_mtd_blktrans
-+ we're screwed anyway. */
-+ if (blktrans_notifier.list.next)
-+ unregister_mtd_user(&blktrans_notifier);
-+}
-+
-+module_exit(mtd_blktrans_exit);
-+
-+EXPORT_SYMBOL_GPL(register_mtd_blktrans);
-+EXPORT_SYMBOL_GPL(deregister_mtd_blktrans);
-+EXPORT_SYMBOL_GPL(add_mtd_blktrans_dev);
-+EXPORT_SYMBOL_GPL(del_mtd_blktrans_dev);
-+
-+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Common interface to block layer for MTD 'translation layers'");
---- linux-2.4.21/drivers/mtd/mtdblock.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/mtdblock.c
-@@ -1,52 +1,25 @@
- /*
- * Direct MTD block device access
- *
-- * $Id: mtdblock.c,v 1.51 2001/11/20 11:42:33 dwmw2 Exp $
-+ * $Id: mtdblock.c,v 1.66 2004/11/25 13:52:52 joern Exp $
- *
-- * 02-nov-2000 Nicolas Pitre Added read-modify-write with cache
-+ * (C) 2000-2003 Nicolas Pitre <nico@cam.org>
-+ * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
- */
-
- #include <linux/config.h>
- #include <linux/types.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
-+#include <linux/fs.h>
-+#include <linux/init.h>
- #include <linux/slab.h>
-+#include <linux/vmalloc.h>
- #include <linux/mtd/mtd.h>
--#include <linux/mtd/compatmac.h>
--
--#define MAJOR_NR MTD_BLOCK_MAJOR
--#define DEVICE_NAME "mtdblock"
--#define DEVICE_REQUEST mtdblock_request
--#define DEVICE_NR(device) (device)
--#define DEVICE_ON(device)
--#define DEVICE_OFF(device)
--#define DEVICE_NO_RANDOM
--#include <linux/blk.h>
--/* for old kernels... */
--#ifndef QUEUE_EMPTY
--#define QUEUE_EMPTY (!CURRENT)
--#endif
--#if LINUX_VERSION_CODE < 0x20300
--#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync)
--#else
--#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged)
--#endif
--
--#ifdef CONFIG_DEVFS_FS
--#include <linux/devfs_fs_kernel.h>
--static void mtd_notify_add(struct mtd_info* mtd);
--static void mtd_notify_remove(struct mtd_info* mtd);
--static struct mtd_notifier notifier = {
-- mtd_notify_add,
-- mtd_notify_remove,
-- NULL
--};
--static devfs_handle_t devfs_dir_handle = NULL;
--static devfs_handle_t devfs_rw_handle[MAX_MTD_DEVICES];
--#endif
-+#include <linux/mtd/blktrans.h>
-
- static struct mtdblk_dev {
-- struct mtd_info *mtd; /* Locked */
-+ struct mtd_info *mtd;
- int count;
- struct semaphore cache_sem;
- unsigned char *cache_data;
-@@ -55,19 +28,6 @@
- enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
- } *mtdblks[MAX_MTD_DEVICES];
-
--static spinlock_t mtdblks_lock;
--
--static int mtd_sizes[MAX_MTD_DEVICES];
--static int mtd_blksizes[MAX_MTD_DEVICES];
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
--#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
--#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
--#else
--#define BLK_INC_USE_COUNT do {} while(0)
--#define BLK_DEC_USE_COUNT do {} while(0)
--#endif
--
- /*
- * Cache stuff...
- *
-@@ -151,7 +111,7 @@
- return ret;
-
- /*
-- * Here we could argably set the cache state to STATE_CLEAN.
-+ * Here we could argubly set the cache state to STATE_CLEAN.
- * However this could lead to inconsistency since we will not
- * be notified if this content is altered on the flash by other
- * means. Let's declare it empty and leave buffering tasks to
-@@ -277,57 +237,47 @@
- return 0;
- }
-
-+static int mtdblock_readsect(struct mtd_blktrans_dev *dev,
-+ unsigned long block, char *buf)
-+{
-+ struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
-+ return do_cached_read(mtdblk, block<<9, 512, buf);
-+}
-
-+static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
-+ unsigned long block, char *buf)
-+{
-+ struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
-+ if (unlikely(!mtdblk->cache_data && mtdblk->cache_size)) {
-+ mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);
-+ if (!mtdblk->cache_data)
-+ return -EINTR;
-+ /* -EINTR is not really correct, but it is the best match
-+ * documented in man 2 write for all cases. We could also
-+ * return -EAGAIN sometimes, but why bother?
-+ */
-+ }
-+ return do_cached_write(mtdblk, block<<9, 512, buf);
-+}
-
--static int mtdblock_open(struct inode *inode, struct file *file)
-+static int mtdblock_open(struct mtd_blktrans_dev *mbd)
- {
- struct mtdblk_dev *mtdblk;
-- struct mtd_info *mtd;
-- int dev;
-+ struct mtd_info *mtd = mbd->mtd;
-+ int dev = mbd->devnum;
-
- DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");
-
-- if (!inode)
-- return -EINVAL;
--
-- dev = MINOR(inode->i_rdev);
-- if (dev >= MAX_MTD_DEVICES)
-- return -EINVAL;
--
-- BLK_INC_USE_COUNT;
--
-- mtd = get_mtd_device(NULL, dev);
-- if (!mtd)
-- return -ENODEV;
-- if (MTD_ABSENT == mtd->type) {
-- put_mtd_device(mtd);
-- BLK_DEC_USE_COUNT;
-- return -ENODEV;
-- }
--
-- spin_lock(&mtdblks_lock);
--
-- /* If it's already open, no need to piss about. */
- if (mtdblks[dev]) {
- mtdblks[dev]->count++;
-- spin_unlock(&mtdblks_lock);
-- put_mtd_device(mtd);
- return 0;
- }
-
-- /* OK, it's not open. Try to find it */
--
-- /* First we have to drop the lock, because we have to
-- to things which might sleep.
-- */
-- spin_unlock(&mtdblks_lock);
--
-+ /* OK, it's not open. Create cache info for it */
- mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
-- if (!mtdblk) {
-- put_mtd_device(mtd);
-- BLK_DEC_USE_COUNT;
-+ if (!mtdblk)
- return -ENOMEM;
-- }
-+
- memset(mtdblk, 0, sizeof(*mtdblk));
- mtdblk->count = 1;
- mtdblk->mtd = mtd;
-@@ -337,336 +287,102 @@
- if ((mtdblk->mtd->flags & MTD_CAP_RAM) != MTD_CAP_RAM &&
- mtdblk->mtd->erasesize) {
- mtdblk->cache_size = mtdblk->mtd->erasesize;
-- mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);
-- if (!mtdblk->cache_data) {
-- put_mtd_device(mtdblk->mtd);
-- kfree(mtdblk);
-- BLK_DEC_USE_COUNT;
-- return -ENOMEM;
-- }
-- }
--
-- /* OK, we've created a new one. Add it to the list. */
--
-- spin_lock(&mtdblks_lock);
--
-- if (mtdblks[dev]) {
-- /* Another CPU made one at the same time as us. */
-- mtdblks[dev]->count++;
-- spin_unlock(&mtdblks_lock);
-- put_mtd_device(mtdblk->mtd);
-- vfree(mtdblk->cache_data);
-- kfree(mtdblk);
-- return 0;
-+ mtdblk->cache_data = NULL;
- }
-
- mtdblks[dev] = mtdblk;
-- mtd_sizes[dev] = mtdblk->mtd->size/1024;
-- if (mtdblk->mtd->erasesize)
-- mtd_blksizes[dev] = mtdblk->mtd->erasesize;
-- if (mtd_blksizes[dev] > PAGE_SIZE)
-- mtd_blksizes[dev] = PAGE_SIZE;
-- set_device_ro (inode->i_rdev, !(mtdblk->mtd->flags & MTD_WRITEABLE));
--
-- spin_unlock(&mtdblks_lock);
-
- DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
-
- return 0;
- }
-
--static release_t mtdblock_release(struct inode *inode, struct file *file)
-+static int mtdblock_release(struct mtd_blktrans_dev *mbd)
- {
-- int dev;
-- struct mtdblk_dev *mtdblk;
-- DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
--
-- if (inode == NULL)
-- release_return(-ENODEV);
-+ int dev = mbd->devnum;
-+ struct mtdblk_dev *mtdblk = mtdblks[dev];
-
-- dev = MINOR(inode->i_rdev);
-- mtdblk = mtdblks[dev];
-+ DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
-
- down(&mtdblk->cache_sem);
- write_cached_data(mtdblk);
- up(&mtdblk->cache_sem);
-
-- spin_lock(&mtdblks_lock);
- if (!--mtdblk->count) {
- /* It was the last usage. Free the device */
- mtdblks[dev] = NULL;
-- spin_unlock(&mtdblks_lock);
- if (mtdblk->mtd->sync)
- mtdblk->mtd->sync(mtdblk->mtd);
-- put_mtd_device(mtdblk->mtd);
- vfree(mtdblk->cache_data);
- kfree(mtdblk);
-- } else {
-- spin_unlock(&mtdblks_lock);
- }
--
- DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
-
-- BLK_DEC_USE_COUNT;
-- release_return(0);
--}
--
--
--/*
-- * This is a special request_fn because it is executed in a process context
-- * to be able to sleep independently of the caller. The io_request_lock
-- * is held upon entry and exit.
-- * The head of our request queue is considered active so there is no need
-- * to dequeue requests before we are done.
-- */
--static void handle_mtdblock_request(void)
--{
-- struct request *req;
-- struct mtdblk_dev *mtdblk;
-- unsigned int res;
--
-- for (;;) {
-- INIT_REQUEST;
-- req = CURRENT;
-- spin_unlock_irq(&io_request_lock);
-- mtdblk = mtdblks[MINOR(req->rq_dev)];
-- res = 0;
--
-- if (MINOR(req->rq_dev) >= MAX_MTD_DEVICES)
-- panic("%s: minor out of bounds", __FUNCTION__);
--
-- if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9))
-- goto end_req;
--
-- // Handle the request
-- switch (req->cmd)
-- {
-- int err;
--
-- case READ:
-- down(&mtdblk->cache_sem);
-- err = do_cached_read (mtdblk, req->sector << 9,
-- req->current_nr_sectors << 9,
-- req->buffer);
-- up(&mtdblk->cache_sem);
-- if (!err)
-- res = 1;
-- break;
--
-- case WRITE:
-- // Read only device
-- if ( !(mtdblk->mtd->flags & MTD_WRITEABLE) )
-- break;
--
-- // Do the write
-- down(&mtdblk->cache_sem);
-- err = do_cached_write (mtdblk, req->sector << 9,
-- req->current_nr_sectors << 9,
-- req->buffer);
-- up(&mtdblk->cache_sem);
-- if (!err)
-- res = 1;
-- break;
-- }
--
--end_req:
-- spin_lock_irq(&io_request_lock);
-- end_request(res);
-- }
--}
--
--static volatile int leaving = 0;
--static DECLARE_MUTEX_LOCKED(thread_sem);
--static DECLARE_WAIT_QUEUE_HEAD(thr_wq);
--
--int mtdblock_thread(void *dummy)
--{
-- struct task_struct *tsk = current;
-- DECLARE_WAITQUEUE(wait, tsk);
--
-- /* we might get involved when memory gets low, so use PF_MEMALLOC */
-- tsk->flags |= PF_MEMALLOC;
-- strcpy(tsk->comm, "mtdblockd");
-- spin_lock_irq(&tsk->sigmask_lock);
-- sigfillset(&tsk->blocked);
-- recalc_sigpending(tsk);
-- spin_unlock_irq(&tsk->sigmask_lock);
-- daemonize();
--
-- while (!leaving) {
-- add_wait_queue(&thr_wq, &wait);
-- set_current_state(TASK_INTERRUPTIBLE);
-- spin_lock_irq(&io_request_lock);
-- if (QUEUE_EMPTY || QUEUE_PLUGGED) {
-- spin_unlock_irq(&io_request_lock);
-- schedule();
-- remove_wait_queue(&thr_wq, &wait);
-- } else {
-- remove_wait_queue(&thr_wq, &wait);
-- set_current_state(TASK_RUNNING);
-- handle_mtdblock_request();
-- spin_unlock_irq(&io_request_lock);
-- }
-- }
--
-- up(&thread_sem);
- return 0;
- }
-
--#if LINUX_VERSION_CODE < 0x20300
--#define RQFUNC_ARG void
--#else
--#define RQFUNC_ARG request_queue_t *q
--#endif
--
--static void mtdblock_request(RQFUNC_ARG)
--{
-- /* Don't do anything, except wake the thread if necessary */
-- wake_up(&thr_wq);
--}
--
--
--static int mtdblock_ioctl(struct inode * inode, struct file * file,
-- unsigned int cmd, unsigned long arg)
-+static int mtdblock_flush(struct mtd_blktrans_dev *dev)
- {
-- struct mtdblk_dev *mtdblk;
--
-- mtdblk = mtdblks[MINOR(inode->i_rdev)];
--
--#ifdef PARANOIA
-- if (!mtdblk)
-- BUG();
--#endif
--
-- switch (cmd) {
-- case BLKGETSIZE: /* Return device size */
-- return put_user((mtdblk->mtd->size >> 9), (unsigned long *) arg);
--
--#ifdef BLKGETSIZE64
-- case BLKGETSIZE64:
-- return put_user((u64)mtdblk->mtd->size, (u64 *)arg);
--#endif
-+ struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
-
-- case BLKFLSBUF:
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-- if(!capable(CAP_SYS_ADMIN))
-- return -EACCES;
--#endif
-- fsync_dev(inode->i_rdev);
-- invalidate_buffers(inode->i_rdev);
- down(&mtdblk->cache_sem);
- write_cached_data(mtdblk);
- up(&mtdblk->cache_sem);
-+
- if (mtdblk->mtd->sync)
- mtdblk->mtd->sync(mtdblk->mtd);
- return 0;
--
-- default:
-- return -EINVAL;
-- }
- }
-
--#if LINUX_VERSION_CODE < 0x20326
--static struct file_operations mtd_fops =
--{
-- open: mtdblock_open,
-- ioctl: mtdblock_ioctl,
-- release: mtdblock_release,
-- read: block_read,
-- write: block_write
--};
--#else
--static struct block_device_operations mtd_fops =
--{
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
-- owner: THIS_MODULE,
--#endif
-- open: mtdblock_open,
-- release: mtdblock_release,
-- ioctl: mtdblock_ioctl
--};
--#endif
--
--#ifdef CONFIG_DEVFS_FS
--/* Notification that a new device has been added. Create the devfs entry for
-- * it. */
--
--static void mtd_notify_add(struct mtd_info* mtd)
-+static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
- {
-- char name[8];
-+ struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
-
-- if (!mtd || mtd->type == MTD_ABSENT)
-+ if (!dev)
- return;
-
-- sprintf(name, "%d", mtd->index);
-- devfs_rw_handle[mtd->index] = devfs_register(devfs_dir_handle, name,
-- DEVFS_FL_DEFAULT, MTD_BLOCK_MAJOR, mtd->index,
-- S_IFBLK | S_IRUGO | S_IWUGO,
-- &mtd_fops, NULL);
--}
-+ memset(dev, 0, sizeof(*dev));
-
--static void mtd_notify_remove(struct mtd_info* mtd)
--{
-- if (!mtd || mtd->type == MTD_ABSENT)
-- return;
-+ dev->mtd = mtd;
-+ dev->devnum = mtd->index;
-+ dev->blksize = 512;
-+ dev->size = mtd->size >> 9;
-+ dev->tr = tr;
-
-- devfs_unregister(devfs_rw_handle[mtd->index]);
-+ if (!(mtd->flags & MTD_WRITEABLE))
-+ dev->readonly = 1;
-+
-+ add_mtd_blktrans_dev(dev);
- }
--#endif
-
--int __init init_mtdblock(void)
-+static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev)
- {
-- int i;
--
-- spin_lock_init(&mtdblks_lock);
--#ifdef CONFIG_DEVFS_FS
-- if (devfs_register_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME, &mtd_fops))
-- {
-- printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
-- MTD_BLOCK_MAJOR);
-- return -EAGAIN;
-- }
--
-- devfs_dir_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL);
-- register_mtd_user(&notifier);
--#else
-- if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) {
-- printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
-- MTD_BLOCK_MAJOR);
-- return -EAGAIN;
-- }
--#endif
-+ del_mtd_blktrans_dev(dev);
-+ kfree(dev);
-+}
-
-- /* We fill it in at open() time. */
-- for (i=0; i< MAX_MTD_DEVICES; i++) {
-- mtd_sizes[i] = 0;
-- mtd_blksizes[i] = BLOCK_SIZE;
-- }
-- init_waitqueue_head(&thr_wq);
-- /* Allow the block size to default to BLOCK_SIZE. */
-- blksize_size[MAJOR_NR] = mtd_blksizes;
-- blk_size[MAJOR_NR] = mtd_sizes;
-+static struct mtd_blktrans_ops mtdblock_tr = {
-+ .name = "mtdblock",
-+ .major = 31,
-+ .part_bits = 0,
-+ .open = mtdblock_open,
-+ .flush = mtdblock_flush,
-+ .release = mtdblock_release,
-+ .readsect = mtdblock_readsect,
-+ .writesect = mtdblock_writesect,
-+ .add_mtd = mtdblock_add_mtd,
-+ .remove_dev = mtdblock_remove_dev,
-+ .owner = THIS_MODULE,
-+};
-
-- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request);
-- kernel_thread (mtdblock_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
-- return 0;
-+static int __init init_mtdblock(void)
-+{
-+ return register_mtd_blktrans(&mtdblock_tr);
- }
-
- static void __exit cleanup_mtdblock(void)
- {
-- leaving = 1;
-- wake_up(&thr_wq);
-- down(&thread_sem);
--#ifdef CONFIG_DEVFS_FS
-- unregister_mtd_user(&notifier);
-- devfs_unregister(devfs_dir_handle);
-- devfs_unregister_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME);
--#else
-- unregister_blkdev(MAJOR_NR,DEVICE_NAME);
--#endif
-- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-- blksize_size[MAJOR_NR] = NULL;
-- blk_size[MAJOR_NR] = NULL;
-+ deregister_mtd_blktrans(&mtdblock_tr);
- }
-
- module_init(init_mtdblock);
---- linux-2.4.21/drivers/mtd/mtdblock_ro.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/mtdblock_ro.c
-@@ -1,301 +1,87 @@
- /*
-- * $Id: mtdblock_ro.c,v 1.12 2001/11/20 11:42:33 dwmw2 Exp $
-+ * $Id: mtdblock_ro.c,v 1.19 2004/11/16 18:28:59 dwmw2 Exp $
- *
-- * Read-only version of the mtdblock device, without the
-- * read/erase/modify/writeback stuff
-+ * (C) 2003 David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * Simple read-only (writable only for RAM) mtdblock driver
- */
-
--#ifdef MTDBLOCK_DEBUG
--#define DEBUGLVL debug
--#endif
--
--
--#include <linux/module.h>
--#include <linux/types.h>
--
-+#include <linux/init.h>
-+#include <linux/slab.h>
- #include <linux/mtd/mtd.h>
--#include <linux/mtd/compatmac.h>
--
--#define MAJOR_NR MTD_BLOCK_MAJOR
--#define DEVICE_NAME "mtdblock"
--#define DEVICE_REQUEST mtdblock_request
--#define DEVICE_NR(device) (device)
--#define DEVICE_ON(device)
--#define DEVICE_OFF(device)
--#define DEVICE_NO_RANDOM
--#include <linux/blk.h>
--
--#if LINUX_VERSION_CODE < 0x20300
--#define RQFUNC_ARG void
--#define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0)
--#else
--#define RQFUNC_ARG request_queue_t *q
--#endif
--
--#ifdef MTDBLOCK_DEBUG
--static int debug = MTDBLOCK_DEBUG;
--MODULE_PARM(debug, "i");
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
--#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
--#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
--#else
--#define BLK_INC_USE_COUNT do {} while(0)
--#define BLK_DEC_USE_COUNT do {} while(0)
--#endif
--
--static int mtd_sizes[MAX_MTD_DEVICES];
--
-+#include <linux/mtd/blktrans.h>
-
--static int mtdblock_open(struct inode *inode, struct file *file)
-+static int mtdblock_readsect(struct mtd_blktrans_dev *dev,
-+ unsigned long block, char *buf)
- {
-- struct mtd_info *mtd = NULL;
--
-- int dev;
--
-- DEBUG(1,"mtdblock_open\n");
--
-- if (inode == 0)
-- return -EINVAL;
--
-- dev = MINOR(inode->i_rdev);
--
-- mtd = get_mtd_device(NULL, dev);
-- if (!mtd)
-- return -EINVAL;
-- if (MTD_ABSENT == mtd->type) {
-- put_mtd_device(mtd);
-- return -EINVAL;
-- }
--
-- BLK_INC_USE_COUNT;
--
-- mtd_sizes[dev] = mtd->size>>9;
--
-- DEBUG(1, "ok\n");
-+ size_t retlen;
-
-+ if (dev->mtd->read(dev->mtd, (block * 512), 512, &retlen, buf))
-+ return 1;
- return 0;
- }
-
--static release_t mtdblock_release(struct inode *inode, struct file *file)
-+static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
-+ unsigned long block, char *buf)
- {
-- int dev;
-- struct mtd_info *mtd;
--
-- DEBUG(1, "mtdblock_release\n");
--
-- if (inode == NULL)
-- release_return(-ENODEV);
--
-- dev = MINOR(inode->i_rdev);
-- mtd = __get_mtd_device(NULL, dev);
--
-- if (!mtd) {
-- printk(KERN_WARNING "MTD device is absent on mtd_release!\n");
-- BLK_DEC_USE_COUNT;
-- release_return(-ENODEV);
-- }
--
-- if (mtd->sync)
-- mtd->sync(mtd);
--
-- put_mtd_device(mtd);
--
-- DEBUG(1, "ok\n");
-+ size_t retlen;
-
-- BLK_DEC_USE_COUNT;
-- release_return(0);
-+ if (dev->mtd->write(dev->mtd, (block * 512), 512, &retlen, buf))
-+ return 1;
-+ return 0;
- }
-
--
--static void mtdblock_request(RQFUNC_ARG)
-+static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
- {
-- struct request *current_request;
-- unsigned int res = 0;
-- struct mtd_info *mtd;
--
-- while (1)
-- {
-- /* Grab the Request and unlink it from the request list, INIT_REQUEST
-- will execute a return if we are done. */
-- INIT_REQUEST;
-- current_request = CURRENT;
--
-- if (MINOR(current_request->rq_dev) >= MAX_MTD_DEVICES)
-- {
-- printk("mtd: Unsupported device!\n");
-- end_request(0);
-- continue;
-- }
--
-- // Grab our MTD structure
--
-- mtd = __get_mtd_device(NULL, MINOR(current_request->rq_dev));
-- if (!mtd) {
-- printk("MTD device %d doesn't appear to exist any more\n", CURRENT_DEV);
-- end_request(0);
-- }
--
-- if (current_request->sector << 9 > mtd->size ||
-- (current_request->sector + current_request->current_nr_sectors) << 9 > mtd->size)
-- {
-- printk("mtd: Attempt to read past end of device!\n");
-- printk("size: %x, sector: %lx, nr_sectors %lx\n", mtd->size,
-- current_request->sector, current_request->current_nr_sectors);
-- end_request(0);
-- continue;
-- }
--
-- /* Remove the request we are handling from the request list so nobody messes
-- with it */
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-- /* Now drop the lock that the ll_rw_blk functions grabbed for us
-- and process the request. This is necessary due to the extreme time
-- we spend processing it. */
-- spin_unlock_irq(&io_request_lock);
--#endif
--
-- // Handle the request
-- switch (current_request->cmd)
-- {
-- size_t retlen;
--
-- case READ:
-- if (MTD_READ(mtd,current_request->sector<<9,
-- current_request->current_nr_sectors << 9,
-- &retlen, current_request->buffer) == 0)
-- res = 1;
-- else
-- res = 0;
-- break;
--
-- case WRITE:
--
-- /* printk("mtdblock_request WRITE sector=%d(%d)\n",current_request->sector,
-- current_request->current_nr_sectors);
-- */
-+ struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
-
-- // Read only device
-- if ((mtd->flags & MTD_CAP_RAM) == 0)
-- {
-- res = 0;
-- break;
-- }
-+ if (!dev)
-+ return;
-
-- // Do the write
-- if (MTD_WRITE(mtd,current_request->sector<<9,
-- current_request->current_nr_sectors << 9,
-- &retlen, current_request->buffer) == 0)
-- res = 1;
-- else
-- res = 0;
-- break;
-+ memset(dev, 0, sizeof(*dev));
-
-- // Shouldn't happen
-- default:
-- printk("mtd: unknown request\n");
-- break;
-- }
-+ dev->mtd = mtd;
-+ dev->devnum = mtd->index;
-+ dev->blksize = 512;
-+ dev->size = mtd->size >> 9;
-+ dev->tr = tr;
-+ if ((mtd->flags & (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEABLE)) !=
-+ (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEABLE))
-+ dev->readonly = 1;
-
-- // Grab the lock and re-thread the item onto the linked list
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-- spin_lock_irq(&io_request_lock);
--#endif
-- end_request(res);
-- }
-+ add_mtd_blktrans_dev(dev);
- }
-
--
--
--static int mtdblock_ioctl(struct inode * inode, struct file * file,
-- unsigned int cmd, unsigned long arg)
-+static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev)
- {
-- struct mtd_info *mtd;
--
-- mtd = __get_mtd_device(NULL, MINOR(inode->i_rdev));
--
-- if (!mtd) return -EINVAL;
--
-- switch (cmd) {
-- case BLKGETSIZE: /* Return device size */
-- return put_user((mtd->size >> 9), (unsigned long *) arg);
--
--#ifdef BLKGETSIZE64
-- case BLKGETSIZE64:
-- return put_user((u64)mtd->size, (u64 *)arg);
--#endif
--
-- case BLKFLSBUF:
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-- if(!capable(CAP_SYS_ADMIN)) return -EACCES;
--#endif
-- fsync_dev(inode->i_rdev);
-- invalidate_buffers(inode->i_rdev);
-- if (mtd->sync)
-- mtd->sync(mtd);
-- return 0;
--
-- default:
-- return -ENOTTY;
-- }
-+ del_mtd_blktrans_dev(dev);
-+ kfree(dev);
- }
-
--#if LINUX_VERSION_CODE < 0x20326
--static struct file_operations mtd_fops =
--{
-- open: mtdblock_open,
-- ioctl: mtdblock_ioctl,
-- release: mtdblock_release,
-- read: block_read,
-- write: block_write
--};
--#else
--static struct block_device_operations mtd_fops =
--{
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
-- owner: THIS_MODULE,
--#endif
-- open: mtdblock_open,
-- release: mtdblock_release,
-- ioctl: mtdblock_ioctl
-+static struct mtd_blktrans_ops mtdblock_tr = {
-+ .name = "mtdblock",
-+ .major = 31,
-+ .part_bits = 0,
-+ .readsect = mtdblock_readsect,
-+ .writesect = mtdblock_writesect,
-+ .add_mtd = mtdblock_add_mtd,
-+ .remove_dev = mtdblock_remove_dev,
-+ .owner = THIS_MODULE,
- };
--#endif
-
--int __init init_mtdblock(void)
-+static int __init mtdblock_init(void)
- {
-- int i;
--
-- if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) {
-- printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
-- MTD_BLOCK_MAJOR);
-- return -EAGAIN;
-- }
--
-- /* We fill it in at open() time. */
-- for (i=0; i< MAX_MTD_DEVICES; i++) {
-- mtd_sizes[i] = 0;
-- }
--
-- /* Allow the block size to default to BLOCK_SIZE. */
-- blksize_size[MAJOR_NR] = NULL;
-- blk_size[MAJOR_NR] = mtd_sizes;
--
-- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request);
-- return 0;
-+ return register_mtd_blktrans(&mtdblock_tr);
- }
-
--static void __exit cleanup_mtdblock(void)
-+static void __exit mtdblock_exit(void)
- {
-- unregister_blkdev(MAJOR_NR,DEVICE_NAME);
-- blk_size[MAJOR_NR] = NULL;
-- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-+ deregister_mtd_blktrans(&mtdblock_tr);
- }
-
--module_init(init_mtdblock);
--module_exit(cleanup_mtdblock);
--
-+module_init(mtdblock_init);
-+module_exit(mtdblock_exit);
-
- MODULE_LICENSE("GPL");
--MODULE_AUTHOR("Erwin Authried <eauth@softsys.co.at> et al.");
-+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
- MODULE_DESCRIPTION("Simple read-only block device emulation access to MTD devices");
---- linux-2.4.21/drivers/mtd/mtdchar.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/mtdchar.c
-@@ -1,8 +1,7 @@
- /*
-- * $Id: mtdchar.c,v 1.49 2003/01/24 12:02:58 dwmw2 Exp $
-+ * $Id: mtdchar.c,v 1.68 2005/02/08 19:12:50 nico Exp $
- *
- * Character-device access to raw MTD devices.
-- * Pure 2.4 version - compatibility cruft removed to mtdchar-compat.c
- *
- */
-
-@@ -10,10 +9,15 @@
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/mtd/mtd.h>
-+#include <linux/mtd/compatmac.h>
- #include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/fs.h>
-+#include <asm/uaccess.h>
-
- #ifdef CONFIG_DEVFS_FS
- #include <linux/devfs_fs_kernel.h>
-+#ifndef NEW
- static void mtd_notify_add(struct mtd_info* mtd);
- static void mtd_notify_remove(struct mtd_info* mtd);
-
-@@ -27,9 +31,98 @@
- static devfs_handle_t devfs_ro_handle[MAX_MTD_DEVICES];
- #endif
-
-+static void mtd_notify_add(struct mtd_info* mtd)
-+{
-+#ifndef NEW
-+ char name[8];
-+#endif
-+ if (!mtd)
-+ return;
-+
-+#ifdef NEW
-+ devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
-+ S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%d", mtd->index);
-+
-+ devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
-+ S_IFCHR | S_IRUGO, "mtd/%dro", mtd->index);
-+#else
-+ struct file_operations mtd_fops;
-+
-+ sprintf(name, "%d", mtd->index);
-+ devfs_rw_handle[mtd->index] = devfs_register(devfs_dir_handle, name,
-+ DEVFS_FL_DEFAULT, MTD_CHAR_MAJOR, mtd->index*2,
-+ S_IFCHR | S_IRUGO | S_IWUGO,
-+ &mtd_fops, NULL);
-+
-+ sprintf(name, "%dro", mtd->index);
-+ devfs_ro_handle[mtd->index] = devfs_register(devfs_dir_handle, name,
-+ DEVFS_FL_DEFAULT, MTD_CHAR_MAJOR, mtd->index*2+1,
-+ S_IFCHR | S_IRUGO,
-+ &mtd_fops, NULL);
-+#endif
-+}
-+
-+static void mtd_notify_remove(struct mtd_info* mtd)
-+{
-+ if (!mtd)
-+ return;
-+#ifdef NEW
-+ devfs_remove("mtd/%d", mtd->index);
-+ devfs_remove("mtd/%dro", mtd->index);
-+#else
-+ devfs_unregister(devfs_rw_handle[mtd->index]);
-+ devfs_unregister(devfs_ro_handle[mtd->index]);
-+#endif
-+}
-+
-+#ifdef NEW
-+static struct mtd_notifier notifier = {
-+ .add = mtd_notify_add,
-+ .remove = mtd_notify_remove,
-+};
-+#endif
-+
-+static inline void mtdchar_devfs_init(void)
-+{
-+#ifdef NEW
-+ devfs_mk_dir("mtd");
-+ register_mtd_user(&notifier);
-+#else
-+ devfs_dir_handle = devfs_mk_dir(NULL, "mtd", NULL);
-+
-+ register_mtd_user(&notifier);
-+#endif
-+}
-+
-+static inline void mtdchar_devfs_exit(void)
-+{
-+ unregister_mtd_user(&notifier);
-+ devfs_remove("mtd");
-+}
-+#else /* !DEVFS */
-+#define mtdchar_devfs_init() do { } while(0)
-+#define mtdchar_devfs_exit() do { } while(0)
-+#endif
-+
-+/*
-+ * We use file->private_data to store a pointer to the MTDdevice.
-+ * Since alighment is at least 32 bits, we have 2 bits free for OTP
-+ * modes as well.
-+ */
-+
-+#define TO_MTD(file) (struct mtd_info *)((long)((file)->private_data) & ~3L)
-+
-+#define MTD_MODE_OTP_FACT 1
-+#define MTD_MODE_OTP_USER 2
-+#define MTD_MODE(file) ((long)((file)->private_data) & 3)
-+
-+#define SET_MTD_MODE(file, mode) \
-+ do { long __p = (long)((file)->private_data); \
-+ (file)->private_data = (void *)((__p & ~3L) | mode); } while (0)
-+
- static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
- {
-- struct mtd_info *mtd=(struct mtd_info *)file->private_data;
-+ struct mtd_info *mtd = TO_MTD(file);
-
- switch (orig) {
- case 0:
-@@ -60,7 +153,7 @@
-
- static int mtd_open(struct inode *inode, struct file *file)
- {
-- int minor = minor(inode->i_rdev);
-+ int minor = iminor(inode);
- int devnum = minor >> 1;
- struct mtd_info *mtd;
-
-@@ -102,7 +195,7 @@
-
- DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
-
-- mtd = (struct mtd_info *)file->private_data;
-+ mtd = TO_MTD(file);
-
- if (mtd->sync)
- mtd->sync(mtd);
-@@ -117,9 +210,9 @@
- */
- #define MAX_KMALLOC_SIZE 0x20000
-
--static ssize_t mtd_read(struct file *file, char *buf, size_t count,loff_t *ppos)
-+static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)
- {
-- struct mtd_info *mtd = (struct mtd_info *)file->private_data;
-+ struct mtd_info *mtd = TO_MTD(file);
- size_t retlen=0;
- size_t total_retlen=0;
- int ret=0;
-@@ -146,8 +239,23 @@
- if (!kbuf)
- return -ENOMEM;
-
-+ switch (MTD_MODE(file)) {
-+ case MTD_MODE_OTP_FACT:
-+ ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf);
-+ break;
-+ case MTD_MODE_OTP_USER:
-+ ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf);
-+ break;
-+ default:
- ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf);
-- if (!ret) {
-+ }
-+ /* Nand returns -EBADMSG on ecc errors, but it returns
-+ * the data. For our userspace tools it is important
-+ * to dump areas with ecc errors !
-+ * Userspace software which accesses NAND this way
-+ * must be aware of the fact that it deals with NAND
-+ */
-+ if (!ret || (ret == -EBADMSG)) {
- *ppos += retlen;
- if (copy_to_user(buf, kbuf, retlen)) {
- kfree(kbuf);
-@@ -158,6 +266,8 @@
-
- count -= retlen;
- buf += retlen;
-+ if (retlen == 0)
-+ count = 0;
- }
- else {
- kfree(kbuf);
-@@ -170,9 +280,9 @@
- return total_retlen;
- } /* mtd_read */
-
--static ssize_t mtd_write(struct file *file, const char *buf, size_t count,loff_t *ppos)
-+static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos)
- {
-- struct mtd_info *mtd = (struct mtd_info *)file->private_data;
-+ struct mtd_info *mtd = TO_MTD(file);
- char *kbuf;
- size_t retlen;
- size_t total_retlen=0;
-@@ -207,7 +317,20 @@
- return -EFAULT;
- }
-
-+ switch (MTD_MODE(file)) {
-+ case MTD_MODE_OTP_FACT:
-+ ret = -EROFS;
-+ break;
-+ case MTD_MODE_OTP_USER:
-+ if (!mtd->write_user_prot_reg) {
-+ ret = -EOPNOTSUPP;
-+ break;
-+ }
-+ ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf);
-+ break;
-+ default:
- ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf);
-+ }
- if (!ret) {
- *ppos += retlen;
- total_retlen += retlen;
-@@ -230,7 +353,7 @@
- IOCTL calls for getting device parameters.
-
- ======================================================================*/
--static void mtd_erase_callback (struct erase_info *instr)
-+static void mtdchar_erase_callback (struct erase_info *instr)
- {
- wake_up((wait_queue_head_t *)instr->priv);
- }
-@@ -238,7 +361,8 @@
- static int mtd_ioctl(struct inode *inode, struct file *file,
- u_int cmd, u_long arg)
- {
-- struct mtd_info *mtd = (struct mtd_info *)file->private_data;
-+ struct mtd_info *mtd = TO_MTD(file);
-+ void __user *argp = (void __user *)arg;
- int ret = 0;
- u_long size;
-
-@@ -246,17 +370,17 @@
-
- size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
- if (cmd & IOC_IN) {
-- ret = verify_area(VERIFY_READ, (char *)arg, size);
-+ ret = verify_area(VERIFY_READ, argp, size);
- if (ret) return ret;
- }
- if (cmd & IOC_OUT) {
-- ret = verify_area(VERIFY_WRITE, (char *)arg, size);
-+ ret = verify_area(VERIFY_WRITE, argp, size);
- if (ret) return ret;
- }
-
- switch (cmd) {
- case MEMGETREGIONCOUNT:
-- if (copy_to_user((int *) arg, &(mtd->numeraseregions), sizeof(int)))
-+ if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int)))
- return -EFAULT;
- break;
-
-@@ -264,24 +388,19 @@
- {
- struct region_info_user ur;
-
-- if (copy_from_user( &ur,
-- (struct region_info_user *)arg,
-- sizeof(struct region_info_user))) {
-+ if (copy_from_user(&ur, argp, sizeof(struct region_info_user)))
- return -EFAULT;
-- }
-
- if (ur.regionindex >= mtd->numeraseregions)
- return -EINVAL;
-- if (copy_to_user((struct mtd_erase_region_info *) arg,
-- &(mtd->eraseregions[ur.regionindex]),
-+ if (copy_to_user(argp, &(mtd->eraseregions[ur.regionindex]),
- sizeof(struct mtd_erase_region_info)))
- return -EFAULT;
- break;
- }
-
- case MEMGETINFO:
-- if (copy_to_user((struct mtd_info *)arg, mtd,
-- sizeof(struct mtd_info_user)))
-+ if (copy_to_user(argp, mtd, sizeof(struct mtd_info_user)))
- return -EFAULT;
- break;
-
-@@ -302,13 +421,13 @@
- init_waitqueue_head(&waitq);
-
- memset (erase,0,sizeof(struct erase_info));
-- if (copy_from_user(&erase->addr, (u_long *)arg,
-- 2 * sizeof(u_long))) {
-+ if (copy_from_user(&erase->addr, argp,
-+ sizeof(struct erase_info_user))) {
- kfree(erase);
- return -EFAULT;
- }
- erase->mtd = mtd;
-- erase->callback = mtd_erase_callback;
-+ erase->callback = mtdchar_erase_callback;
- erase->priv = (unsigned long)&waitq;
-
- /*
-@@ -346,7 +465,7 @@
- if(!(file->f_mode & 2))
- return -EPERM;
-
-- if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
-+ if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
- return -EFAULT;
-
- if (buf.length > 0x4096)
-@@ -355,7 +474,7 @@
- if (!mtd->write_oob)
- ret = -EOPNOTSUPP;
- else
-- ret = verify_area(VERIFY_READ, (char *)buf.ptr, buf.length);
-+ ret = verify_area(VERIFY_READ, buf.ptr, buf.length);
-
- if (ret)
- return ret;
-@@ -371,7 +490,7 @@
-
- ret = (mtd->write_oob)(mtd, buf.start, buf.length, &retlen, databuf);
-
-- if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
-+ if (copy_to_user(argp + sizeof(uint32_t), &retlen, sizeof(uint32_t)))
- ret = -EFAULT;
-
- kfree(databuf);
-@@ -385,7 +504,7 @@
- void *databuf;
- ssize_t retlen;
-
-- if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
-+ if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
- return -EFAULT;
-
- if (buf.length > 0x4096)
-@@ -394,7 +513,7 @@
- if (!mtd->read_oob)
- ret = -EOPNOTSUPP;
- else
-- ret = verify_area(VERIFY_WRITE, (char *)buf.ptr, buf.length);
-+ ret = verify_area(VERIFY_WRITE, buf.ptr, buf.length);
-
- if (ret)
- return ret;
-@@ -405,7 +524,7 @@
-
- ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf);
-
-- if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
-+ if (put_user(retlen, (uint32_t __user *)argp))
- ret = -EFAULT;
- else if (retlen && copy_to_user(buf.ptr, databuf, retlen))
- ret = -EFAULT;
-@@ -416,109 +535,146 @@
-
- case MEMLOCK:
- {
-- unsigned long adrs[2];
-+ struct erase_info_user info;
-
-- if (copy_from_user(adrs ,(void *)arg, 2* sizeof(unsigned long)))
-+ if (copy_from_user(&info, argp, sizeof(info)))
- return -EFAULT;
-
- if (!mtd->lock)
- ret = -EOPNOTSUPP;
- else
-- ret = mtd->lock(mtd, adrs[0], adrs[1]);
-+ ret = mtd->lock(mtd, info.start, info.length);
- break;
- }
-
- case MEMUNLOCK:
- {
-- unsigned long adrs[2];
-+ struct erase_info_user info;
-
-- if (copy_from_user(adrs, (void *)arg, 2* sizeof(unsigned long)))
-+ if (copy_from_user(&info, argp, sizeof(info)))
- return -EFAULT;
-
- if (!mtd->unlock)
- ret = -EOPNOTSUPP;
- else
-- ret = mtd->unlock(mtd, adrs[0], adrs[1]);
-+ ret = mtd->unlock(mtd, info.start, info.length);
- break;
- }
-
-- case MEMWRITEDATA:
-+ case MEMSETOOBSEL:
- {
-- struct mtd_oob_buf buf;
-- void *databuf;
-- ssize_t retlen;
-+ if (copy_from_user(&mtd->oobinfo, argp, sizeof(struct nand_oobinfo)))
-+ return -EFAULT;
-+ break;
-+ }
-
-- if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
-+ case MEMGETOOBSEL:
-+ {
-+ if (copy_to_user(argp, &(mtd->oobinfo), sizeof(struct nand_oobinfo)))
- return -EFAULT;
-+ break;
-+ }
-
-- if (buf.length > 0x4096)
-- return -EINVAL;
-+ case MEMGETBADBLOCK:
-+ {
-+ loff_t offs;
-
-- if (!mtd->write_ecc)
-+ if (copy_from_user(&offs, argp, sizeof(loff_t)))
-+ return -EFAULT;
-+ if (!mtd->block_isbad)
- ret = -EOPNOTSUPP;
- else
-- ret = verify_area(VERIFY_READ, (char *)buf.ptr, buf.length);
--
-- if (ret)
-- return ret;
--
-- databuf = kmalloc(buf.length, GFP_KERNEL);
-- if (!databuf)
-- return -ENOMEM;
--
-- if (copy_from_user(databuf, buf.ptr, buf.length)) {
-- kfree(databuf);
-- return -EFAULT;
-+ return mtd->block_isbad(mtd, offs);
-+ break;
- }
-
-- ret = (mtd->write_ecc)(mtd, buf.start, buf.length, &retlen, databuf, NULL, 0);
--
-- if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
-- ret = -EFAULT;
-+ case MEMSETBADBLOCK:
-+ {
-+ loff_t offs;
-
-- kfree(databuf);
-+ if (copy_from_user(&offs, argp, sizeof(loff_t)))
-+ return -EFAULT;
-+ if (!mtd->block_markbad)
-+ ret = -EOPNOTSUPP;
-+ else
-+ return mtd->block_markbad(mtd, offs);
- break;
--
- }
-
-- case MEMREADDATA:
-+#ifdef CONFIG_MTD_OTP
-+ case OTPSELECT:
- {
-- struct mtd_oob_buf buf;
-- void *databuf;
-- ssize_t retlen = 0;
--
-- if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
-+ int mode;
-+ if (copy_from_user(&mode, argp, sizeof(int)))
- return -EFAULT;
--
-- if (buf.length > 0x4096)
-- return -EINVAL;
--
-- if (!mtd->read_ecc)
-+ SET_MTD_MODE(file, 0);
-+ switch (mode) {
-+ case MTD_OTP_FACTORY:
-+ if (!mtd->read_fact_prot_reg)
- ret = -EOPNOTSUPP;
- else
-- ret = verify_area(VERIFY_WRITE, (char *)buf.ptr, buf.length);
--
-- if (ret)
-- return ret;
-+ SET_MTD_MODE(file, MTD_MODE_OTP_FACT);
-+ break;
-+ case MTD_OTP_USER:
-+ if (!mtd->read_fact_prot_reg)
-+ ret = -EOPNOTSUPP;
-+ else
-+ SET_MTD_MODE(file, MTD_MODE_OTP_USER);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ case MTD_OTP_OFF:
-+ break;
-+ }
-+ break;
-+ }
-
-- databuf = kmalloc(buf.length, GFP_KERNEL);
-- if (!databuf)
-+ case OTPGETREGIONCOUNT:
-+ case OTPGETREGIONINFO:
-+ {
-+ struct otp_info *buf = kmalloc(4096, GFP_KERNEL);
-+ if (!buf)
- return -ENOMEM;
--
-- ret = (mtd->read_ecc)(mtd, buf.start, buf.length, &retlen, databuf, NULL, 0);
--
-- if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
-- ret = -EFAULT;
-- else if (retlen && copy_to_user(buf.ptr, databuf, retlen))
-+ ret = -EOPNOTSUPP;
-+ switch (MTD_MODE(file)) {
-+ case MTD_MODE_OTP_FACT:
-+ if (mtd->get_fact_prot_info)
-+ ret = mtd->get_fact_prot_info(mtd, buf, 4096);
-+ break;
-+ case MTD_MODE_OTP_USER:
-+ if (mtd->get_user_prot_info)
-+ ret = mtd->get_user_prot_info(mtd, buf, 4096);
-+ break;
-+ }
-+ if (ret >= 0) {
-+ if (cmd == OTPGETREGIONCOUNT) {
-+ int nbr = ret / sizeof(struct otp_info);
-+ ret = copy_to_user(argp, &nbr, sizeof(int));
-+ } else
-+ ret = copy_to_user(argp, buf, ret);
-+ if (ret)
- ret = -EFAULT;
--
-- kfree(databuf);
-+ }
-+ kfree(buf);
- break;
- }
-
-+ case OTPLOCK:
-+ {
-+ struct otp_info info;
-+
-+ if (MTD_MODE(file) != MTD_MODE_OTP_USER)
-+ return -EINVAL;
-+ if (copy_from_user(&info, argp, sizeof(info)))
-+ return -EFAULT;
-+ if (!mtd->lock_user_prot_reg)
-+ return -EOPNOTSUPP;
-+ ret = mtd->lock_user_prot_reg(mtd, info.start, info.length);
-+ break;
-+ }
-+#endif
-
- default:
-- DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %x)\n", cmd, MEMGETINFO);
- ret = -ENOTTY;
- }
-
-@@ -526,84 +682,31 @@
- } /* memory_ioctl */
-
- static struct file_operations mtd_fops = {
-- owner: THIS_MODULE,
-- llseek: mtd_lseek, /* lseek */
-- read: mtd_read, /* read */
-- write: mtd_write, /* write */
-- ioctl: mtd_ioctl, /* ioctl */
-- open: mtd_open, /* open */
-- release: mtd_close, /* release */
-+ .owner = THIS_MODULE,
-+ .llseek = mtd_lseek,
-+ .read = mtd_read,
-+ .write = mtd_write,
-+ .ioctl = mtd_ioctl,
-+ .open = mtd_open,
-+ .release = mtd_close,
- };
-
--
--#ifdef CONFIG_DEVFS_FS
--/* Notification that a new device has been added. Create the devfs entry for
-- * it. */
--
--static void mtd_notify_add(struct mtd_info* mtd)
--{
-- char name[8];
--
-- if (!mtd)
-- return;
--
-- sprintf(name, "%d", mtd->index);
-- devfs_rw_handle[mtd->index] = devfs_register(devfs_dir_handle, name,
-- DEVFS_FL_DEFAULT, MTD_CHAR_MAJOR, mtd->index*2,
-- S_IFCHR | S_IRUGO | S_IWUGO,
-- &mtd_fops, NULL);
--
-- sprintf(name, "%dro", mtd->index);
-- devfs_ro_handle[mtd->index] = devfs_register(devfs_dir_handle, name,
-- DEVFS_FL_DEFAULT, MTD_CHAR_MAJOR, mtd->index*2+1,
-- S_IFCHR | S_IRUGO,
-- &mtd_fops, NULL);
--}
--
--static void mtd_notify_remove(struct mtd_info* mtd)
--{
-- if (!mtd)
-- return;
--
-- devfs_unregister(devfs_rw_handle[mtd->index]);
-- devfs_unregister(devfs_ro_handle[mtd->index]);
--}
--#endif
--
- static int __init init_mtdchar(void)
- {
--#ifdef CONFIG_DEVFS_FS
-- if (devfs_register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops))
-- {
-- printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
-- MTD_CHAR_MAJOR);
-- return -EAGAIN;
-- }
--
-- devfs_dir_handle = devfs_mk_dir(NULL, "mtd", NULL);
--
-- register_mtd_user(&notifier);
--#else
-- if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops))
-- {
-+ if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) {
- printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
- MTD_CHAR_MAJOR);
- return -EAGAIN;
- }
--#endif
-
-+ mtdchar_devfs_init();
- return 0;
- }
-
- static void __exit cleanup_mtdchar(void)
- {
--#ifdef CONFIG_DEVFS_FS
-- unregister_mtd_user(&notifier);
-- devfs_unregister(devfs_dir_handle);
-- devfs_unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
--#else
-+ mtdchar_devfs_exit();
- unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
--#endif
- }
-
- module_init(init_mtdchar);
---- linux-2.4.21/drivers/mtd/mtdconcat.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/mtdconcat.c
-@@ -3,9 +3,11 @@
- *
- * (C) 2002 Robert Kaiser <rkaiser@sysgo.de>
- *
-+ * NAND support by Christian Gan <cgan@iders.ca>
-+ *
- * This code is GPL
- *
-- * $Id: mtdconcat.c,v 1.3 2002/05/21 21:04:25 dwmw2 Exp $
-+ * $Id: mtdconcat.c,v 1.9 2004/06/30 15:17:41 dbrown Exp $
- */
-
- #include <linux/module.h>
-@@ -35,21 +37,20 @@
- #define SIZEOF_STRUCT_MTD_CONCAT(num_subdev) \
- ((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *)))
-
--
- /*
- * Given a pointer to the MTD object in the mtd_concat structure,
- * we can retrieve the pointer to that structure with this macro.
- */
- #define CONCAT(x) ((struct mtd_concat *)(x))
-
--
- /*
- * MTD methods which look up the relevant subdevice, translate the
- * effective address and pass through to the subdevice.
- */
-
--static int concat_read (struct mtd_info *mtd, loff_t from, size_t len,
-- size_t *retlen, u_char *buf)
-+static int
-+concat_read(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t * retlen, u_char * buf)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- int err = -EINVAL;
-@@ -57,43 +58,43 @@
-
- *retlen = 0;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- size_t size, retsize;
-
-- if (from >= subdev->size)
-- {
-+ if (from >= subdev->size) {
-+ /* Not destined for this subdev */
- size = 0;
- from -= subdev->size;
-+ continue;
- }
-- else
-- {
- if (from + len > subdev->size)
-+ /* First part goes into this subdev */
- size = subdev->size - from;
- else
-+ /* Entire transaction goes into this subdev */
- size = len;
-
- err = subdev->read(subdev, from, size, &retsize, buf);
-
-- if(err)
-+ if (err)
- break;
-
- *retlen += retsize;
- len -= size;
-- if(len == 0)
-+ if (len == 0)
- break;
-
- err = -EINVAL;
- buf += size;
- from = 0;
- }
-- }
- return err;
- }
-
--static int concat_write (struct mtd_info *mtd, loff_t to, size_t len,
-- size_t *retlen, const u_char *buf)
-+static int
-+concat_write(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t * retlen, const u_char * buf)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- int err = -EINVAL;
-@@ -104,18 +105,15 @@
-
- *retlen = 0;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- size_t size, retsize;
-
-- if (to >= subdev->size)
-- {
-+ if (to >= subdev->size) {
- size = 0;
- to -= subdev->size;
-+ continue;
- }
-- else
-- {
- if (to + len > subdev->size)
- size = subdev->size - to;
- else
-@@ -126,25 +124,232 @@
- else
- err = subdev->write(subdev, to, size, &retsize, buf);
-
-- if(err)
-+ if (err)
- break;
-
- *retlen += retsize;
- len -= size;
-- if(len == 0)
-+ if (len == 0)
- break;
-
- err = -EINVAL;
- buf += size;
- to = 0;
- }
-+ return err;
-+}
-+
-+static int
-+concat_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)
-+{
-+ struct mtd_concat *concat = CONCAT(mtd);
-+ int err = -EINVAL;
-+ int i;
-+
-+ *retlen = 0;
-+
-+ for (i = 0; i < concat->num_subdev; i++) {
-+ struct mtd_info *subdev = concat->subdev[i];
-+ size_t size, retsize;
-+
-+ if (from >= subdev->size) {
-+ /* Not destined for this subdev */
-+ size = 0;
-+ from -= subdev->size;
-+ continue;
-+ }
-+
-+ if (from + len > subdev->size)
-+ /* First part goes into this subdev */
-+ size = subdev->size - from;
-+ else
-+ /* Entire transaction goes into this subdev */
-+ size = len;
-+
-+ if (subdev->read_ecc)
-+ err = subdev->read_ecc(subdev, from, size,
-+ &retsize, buf, eccbuf, oobsel);
-+ else
-+ err = -EINVAL;
-+
-+ if (err)
-+ break;
-+
-+ *retlen += retsize;
-+ len -= size;
-+ if (len == 0)
-+ break;
-+
-+ err = -EINVAL;
-+ buf += size;
-+ if (eccbuf) {
-+ eccbuf += subdev->oobsize;
-+ /* in nand.c at least, eccbufs are
-+ tagged with 2 (int)eccstatus'; we
-+ must account for these */
-+ eccbuf += 2 * (sizeof (int));
-+ }
-+ from = 0;
- }
- return err;
- }
-
--static void concat_erase_callback (struct erase_info *instr)
-+static int
-+concat_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)
- {
-- wake_up((wait_queue_head_t *)instr->priv);
-+ struct mtd_concat *concat = CONCAT(mtd);
-+ int err = -EINVAL;
-+ int i;
-+
-+ if (!(mtd->flags & MTD_WRITEABLE))
-+ return -EROFS;
-+
-+ *retlen = 0;
-+
-+ for (i = 0; i < concat->num_subdev; i++) {
-+ struct mtd_info *subdev = concat->subdev[i];
-+ size_t size, retsize;
-+
-+ if (to >= subdev->size) {
-+ size = 0;
-+ to -= subdev->size;
-+ continue;
-+ }
-+ if (to + len > subdev->size)
-+ size = subdev->size - to;
-+ else
-+ size = len;
-+
-+ if (!(subdev->flags & MTD_WRITEABLE))
-+ err = -EROFS;
-+ else if (subdev->write_ecc)
-+ err = subdev->write_ecc(subdev, to, size,
-+ &retsize, buf, eccbuf, oobsel);
-+ else
-+ err = -EINVAL;
-+
-+ if (err)
-+ break;
-+
-+ *retlen += retsize;
-+ len -= size;
-+ if (len == 0)
-+ break;
-+
-+ err = -EINVAL;
-+ buf += size;
-+ if (eccbuf)
-+ eccbuf += subdev->oobsize;
-+ to = 0;
-+ }
-+ return err;
-+}
-+
-+static int
-+concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t * retlen, u_char * buf)
-+{
-+ struct mtd_concat *concat = CONCAT(mtd);
-+ int err = -EINVAL;
-+ int i;
-+
-+ *retlen = 0;
-+
-+ for (i = 0; i < concat->num_subdev; i++) {
-+ struct mtd_info *subdev = concat->subdev[i];
-+ size_t size, retsize;
-+
-+ if (from >= subdev->size) {
-+ /* Not destined for this subdev */
-+ size = 0;
-+ from -= subdev->size;
-+ continue;
-+ }
-+ if (from + len > subdev->size)
-+ /* First part goes into this subdev */
-+ size = subdev->size - from;
-+ else
-+ /* Entire transaction goes into this subdev */
-+ size = len;
-+
-+ if (subdev->read_oob)
-+ err = subdev->read_oob(subdev, from, size,
-+ &retsize, buf);
-+ else
-+ err = -EINVAL;
-+
-+ if (err)
-+ break;
-+
-+ *retlen += retsize;
-+ len -= size;
-+ if (len == 0)
-+ break;
-+
-+ err = -EINVAL;
-+ buf += size;
-+ from = 0;
-+ }
-+ return err;
-+}
-+
-+static int
-+concat_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t * retlen, const u_char * buf)
-+{
-+ struct mtd_concat *concat = CONCAT(mtd);
-+ int err = -EINVAL;
-+ int i;
-+
-+ if (!(mtd->flags & MTD_WRITEABLE))
-+ return -EROFS;
-+
-+ *retlen = 0;
-+
-+ for (i = 0; i < concat->num_subdev; i++) {
-+ struct mtd_info *subdev = concat->subdev[i];
-+ size_t size, retsize;
-+
-+ if (to >= subdev->size) {
-+ size = 0;
-+ to -= subdev->size;
-+ continue;
-+ }
-+ if (to + len > subdev->size)
-+ size = subdev->size - to;
-+ else
-+ size = len;
-+
-+ if (!(subdev->flags & MTD_WRITEABLE))
-+ err = -EROFS;
-+ else if (subdev->write_oob)
-+ err = subdev->write_oob(subdev, to, size, &retsize,
-+ buf);
-+ else
-+ err = -EINVAL;
-+
-+ if (err)
-+ break;
-+
-+ *retlen += retsize;
-+ len -= size;
-+ if (len == 0)
-+ break;
-+
-+ err = -EINVAL;
-+ buf += size;
-+ to = 0;
-+ }
-+ return err;
-+}
-+
-+static void concat_erase_callback(struct erase_info *instr)
-+{
-+ wake_up((wait_queue_head_t *) instr->priv);
- }
-
- static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
-@@ -160,18 +365,18 @@
-
- erase->mtd = mtd;
- erase->callback = concat_erase_callback;
-- erase->priv = (unsigned long)&waitq;
-+ erase->priv = (unsigned long) &waitq;
-
- /*
- * FIXME: Allow INTERRUPTIBLE. Which means
- * not having the wait_queue head on the stack.
- */
- err = mtd->erase(mtd, erase);
-- if (!err)
-- {
-+ if (!err) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&waitq, &wait);
-- if (erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED)
-+ if (erase->state != MTD_ERASE_DONE
-+ && erase->state != MTD_ERASE_FAILED)
- schedule();
- remove_wait_queue(&waitq, &wait);
- set_current_state(TASK_RUNNING);
-@@ -181,21 +386,21 @@
- return err;
- }
-
--static int concat_erase (struct mtd_info *mtd, struct erase_info *instr)
-+static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- struct mtd_info *subdev;
- int i, err;
-- u_int32_t length;
-+ u_int32_t length, offset = 0;
- struct erase_info *erase;
-
- if (!(mtd->flags & MTD_WRITEABLE))
- return -EROFS;
-
-- if(instr->addr > concat->mtd.size)
-+ if (instr->addr > concat->mtd.size)
- return -EINVAL;
-
-- if(instr->len + instr->addr > concat->mtd.size)
-+ if (instr->len + instr->addr > concat->mtd.size)
- return -EINVAL;
-
- /*
-@@ -204,23 +409,22 @@
- * region info rather than looking at each particular sub-device
- * in turn.
- */
-- if (!concat->mtd.numeraseregions)
-- { /* the easy case: device has uniform erase block size */
-- if(instr->addr & (concat->mtd.erasesize - 1))
-+ if (!concat->mtd.numeraseregions) {
-+ /* the easy case: device has uniform erase block size */
-+ if (instr->addr & (concat->mtd.erasesize - 1))
- return -EINVAL;
-- if(instr->len & (concat->mtd.erasesize - 1))
-+ if (instr->len & (concat->mtd.erasesize - 1))
- return -EINVAL;
-- }
-- else
-- { /* device has variable erase size */
-- struct mtd_erase_region_info *erase_regions = concat->mtd.eraseregions;
-+ } else {
-+ /* device has variable erase size */
-+ struct mtd_erase_region_info *erase_regions =
-+ concat->mtd.eraseregions;
-
- /*
- * Find the erase region where the to-be-erased area begins:
- */
-- for(i = 0; i < concat->mtd.numeraseregions &&
-- instr->addr >= erase_regions[i].offset; i++)
-- ;
-+ for (i = 0; i < concat->mtd.numeraseregions &&
-+ instr->addr >= erase_regions[i].offset; i++) ;
- --i;
-
- /*
-@@ -228,25 +432,28 @@
- * to-be-erased area begins. Verify that the starting
- * offset is aligned to this region's erase size:
- */
-- if (instr->addr & (erase_regions[i].erasesize-1))
-+ if (instr->addr & (erase_regions[i].erasesize - 1))
- return -EINVAL;
-
- /*
- * now find the erase region where the to-be-erased area ends:
- */
-- for(; i < concat->mtd.numeraseregions &&
-- (instr->addr + instr->len) >= erase_regions[i].offset ; ++i)
-- ;
-+ for (; i < concat->mtd.numeraseregions &&
-+ (instr->addr + instr->len) >= erase_regions[i].offset;
-+ ++i) ;
- --i;
- /*
- * check if the ending offset is aligned to this region's erase size
- */
-- if ((instr->addr + instr->len) & (erase_regions[i].erasesize-1))
-+ if ((instr->addr + instr->len) & (erase_regions[i].erasesize -
-+ 1))
- return -EINVAL;
- }
-
-+ instr->fail_addr = 0xffffffff;
-+
- /* make a local copy of instr to avoid modifying the caller's struct */
-- erase = kmalloc(sizeof(struct erase_info),GFP_KERNEL);
-+ erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
-
- if (!erase)
- return -ENOMEM;
-@@ -258,39 +465,44 @@
- * find the subdevice where the to-be-erased area begins, adjust
- * starting offset to be relative to the subdevice start
- */
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- subdev = concat->subdev[i];
-- if(subdev->size <= erase->addr)
-+ if (subdev->size <= erase->addr) {
- erase->addr -= subdev->size;
-- else
-+ offset += subdev->size;
-+ } else {
- break;
- }
-- if(i >= concat->num_subdev) /* must never happen since size */
-- BUG(); /* limit has been verified above */
-+ }
-+
-+ /* must never happen since size limit has been verified above */
-+ if (i >= concat->num_subdev)
-+ BUG();
-
- /* now do the erase: */
- err = 0;
-- for(;length > 0; i++) /* loop for all subevices affected by this request */
-- {
-+ for (; length > 0; i++) {
-+ /* loop for all subdevices affected by this request */
- subdev = concat->subdev[i]; /* get current subdevice */
-
- /* limit length to subdevice's size: */
-- if(erase->addr + length > subdev->size)
-+ if (erase->addr + length > subdev->size)
- erase->len = subdev->size - erase->addr;
- else
- erase->len = length;
-
-- if (!(subdev->flags & MTD_WRITEABLE))
-- {
-+ if (!(subdev->flags & MTD_WRITEABLE)) {
- err = -EROFS;
- break;
- }
- length -= erase->len;
-- if ((err = concat_dev_erase(subdev, erase)))
-- {
-- if(err == -EINVAL) /* sanity check: must never happen since */
-- BUG(); /* block alignment has been checked above */
-+ if ((err = concat_dev_erase(subdev, erase))) {
-+ /* sanity check: should never happen since
-+ * block alignment has been checked above */
-+ if (err == -EINVAL)
-+ BUG();
-+ if (erase->fail_addr != 0xffffffff)
-+ instr->fail_addr = erase->fail_addr + offset;
- break;
- }
- /*
-@@ -302,18 +514,19 @@
- * current subdevice, i.e. at offset zero.
- */
- erase->addr = 0;
-+ offset += subdev->size;
- }
-+ instr->state = erase->state;
- kfree(erase);
- if (err)
- return err;
-
-- instr->state = MTD_ERASE_DONE;
- if (instr->callback)
- instr->callback(instr);
- return 0;
- }
-
--static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
-+static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- int i, err = -EINVAL;
-@@ -321,18 +534,15 @@
- if ((len + ofs) > mtd->size)
- return -EINVAL;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- size_t size;
-
-- if (ofs >= subdev->size)
-- {
-+ if (ofs >= subdev->size) {
- size = 0;
- ofs -= subdev->size;
-+ continue;
- }
-- else
-- {
- if (ofs + len > subdev->size)
- size = subdev->size - ofs;
- else
-@@ -340,21 +550,21 @@
-
- err = subdev->lock(subdev, ofs, size);
-
-- if(err)
-+ if (err)
- break;
-
- len -= size;
-- if(len == 0)
-+ if (len == 0)
- break;
-
- err = -EINVAL;
- ofs = 0;
- }
-- }
-+
- return err;
- }
-
--static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
-+static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- int i, err = 0;
-@@ -362,18 +572,15 @@
- if ((len + ofs) > mtd->size)
- return -EINVAL;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- size_t size;
-
-- if (ofs >= subdev->size)
-- {
-+ if (ofs >= subdev->size) {
- size = 0;
- ofs -= subdev->size;
-+ continue;
- }
-- else
-- {
- if (ofs + len > subdev->size)
- size = subdev->size - ofs;
- else
-@@ -381,17 +588,17 @@
-
- err = subdev->unlock(subdev, ofs, size);
-
-- if(err)
-+ if (err)
- break;
-
- len -= size;
-- if(len == 0)
-+ if (len == 0)
- break;
-
- err = -EINVAL;
- ofs = 0;
- }
-- }
-+
- return err;
- }
-
-@@ -400,8 +607,7 @@
- struct mtd_concat *concat = CONCAT(mtd);
- int i;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- subdev->sync(subdev);
- }
-@@ -412,10 +618,9 @@
- struct mtd_concat *concat = CONCAT(mtd);
- int i, rc = 0;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
-- if((rc = subdev->suspend(subdev)) < 0)
-+ if ((rc = subdev->suspend(subdev)) < 0)
- return rc;
- }
- return rc;
-@@ -426,8 +631,7 @@
- struct mtd_concat *concat = CONCAT(mtd);
- int i;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- subdev->resume(subdev);
- }
-@@ -439,11 +643,10 @@
- * stored to *new_dev upon success. This function does _not_
- * register any devices: this is the caller's responsibility.
- */
--struct mtd_info *mtd_concat_create(
-- struct mtd_info *subdev[], /* subdevices to concatenate */
-+struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to concatenate */
- int num_devs, /* number of subdevices */
-- char *name) /* name for the new device */
--{
-+ char *name)
-+{ /* name for the new device */
- int i;
- size_t size;
- struct mtd_concat *concat;
-@@ -451,21 +654,21 @@
- int num_erase_region;
-
- printk(KERN_NOTICE "Concatenating MTD devices:\n");
-- for(i = 0; i < num_devs; i++)
-+ for (i = 0; i < num_devs; i++)
- printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name);
- printk(KERN_NOTICE "into device \"%s\"\n", name);
-
- /* allocate the device structure */
- size = SIZEOF_STRUCT_MTD_CONCAT(num_devs);
-- concat = kmalloc (size, GFP_KERNEL);
-- if(!concat)
-- {
-- printk ("memory allocation error while creating concatenated device \"%s\"\n",
-+ concat = kmalloc(size, GFP_KERNEL);
-+ if (!concat) {
-+ printk
-+ ("memory allocation error while creating concatenated device \"%s\"\n",
- name);
- return NULL;
- }
- memset(concat, 0, size);
-- concat->subdev = (struct mtd_info **)(concat + 1);
-+ concat->subdev = (struct mtd_info **) (concat + 1);
-
- /*
- * Set up the new "super" device's MTD object structure, check for
-@@ -479,39 +682,53 @@
- concat->mtd.oobsize = subdev[0]->oobsize;
- concat->mtd.ecctype = subdev[0]->ecctype;
- concat->mtd.eccsize = subdev[0]->eccsize;
-+ if (subdev[0]->read_ecc)
-+ concat->mtd.read_ecc = concat_read_ecc;
-+ if (subdev[0]->write_ecc)
-+ concat->mtd.write_ecc = concat_write_ecc;
-+ if (subdev[0]->read_oob)
-+ concat->mtd.read_oob = concat_read_oob;
-+ if (subdev[0]->write_oob)
-+ concat->mtd.write_oob = concat_write_oob;
-
- concat->subdev[0] = subdev[0];
-
-- for(i = 1; i < num_devs; i++)
-- {
-- if(concat->mtd.type != subdev[i]->type)
-- {
-+ for (i = 1; i < num_devs; i++) {
-+ if (concat->mtd.type != subdev[i]->type) {
- kfree(concat);
-- printk ("Incompatible device type on \"%s\"\n", subdev[i]->name);
-+ printk("Incompatible device type on \"%s\"\n",
-+ subdev[i]->name);
- return NULL;
- }
-- if(concat->mtd.flags != subdev[i]->flags)
-- { /*
-- * Expect all flags except MTD_WRITEABLE to be equal on
-- * all subdevices.
-+ if (concat->mtd.flags != subdev[i]->flags) {
-+ /*
-+ * Expect all flags except MTD_WRITEABLE to be
-+ * equal on all subdevices.
- */
-- if((concat->mtd.flags ^ subdev[i]->flags) & ~MTD_WRITEABLE)
-- {
-+ if ((concat->mtd.flags ^ subdev[i]->
-+ flags) & ~MTD_WRITEABLE) {
- kfree(concat);
-- printk ("Incompatible device flags on \"%s\"\n", subdev[i]->name);
-+ printk("Incompatible device flags on \"%s\"\n",
-+ subdev[i]->name);
- return NULL;
-- }
-- else /* if writeable attribute differs, make super device writeable */
-- concat->mtd.flags |= subdev[i]->flags & MTD_WRITEABLE;
-+ } else
-+ /* if writeable attribute differs,
-+ make super device writeable */
-+ concat->mtd.flags |=
-+ subdev[i]->flags & MTD_WRITEABLE;
- }
- concat->mtd.size += subdev[i]->size;
-- if(concat->mtd.oobblock != subdev[i]->oobblock ||
-+ if (concat->mtd.oobblock != subdev[i]->oobblock ||
- concat->mtd.oobsize != subdev[i]->oobsize ||
- concat->mtd.ecctype != subdev[i]->ecctype ||
-- concat->mtd.eccsize != subdev[i]->eccsize)
-- {
-+ concat->mtd.eccsize != subdev[i]->eccsize ||
-+ !concat->mtd.read_ecc != !subdev[i]->read_ecc ||
-+ !concat->mtd.write_ecc != !subdev[i]->write_ecc ||
-+ !concat->mtd.read_oob != !subdev[i]->read_oob ||
-+ !concat->mtd.write_oob != !subdev[i]->write_oob) {
- kfree(concat);
-- printk ("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name);
-+ printk("Incompatible OOB or ECC data on \"%s\"\n",
-+ subdev[i]->name);
- return NULL;
- }
- concat->subdev[i] = subdev[i];
-@@ -535,7 +752,6 @@
- concat->mtd.suspend = concat_suspend;
- concat->mtd.resume = concat_resume;
-
--
- /*
- * Combine the erase block size info of the subdevices:
- *
-@@ -544,44 +760,44 @@
- */
- max_erasesize = curr_erasesize = subdev[0]->erasesize;
- num_erase_region = 1;
-- for(i = 0; i < num_devs; i++)
-- {
-- if(subdev[i]->numeraseregions == 0)
-- { /* current subdevice has uniform erase size */
-- if(subdev[i]->erasesize != curr_erasesize)
-- { /* if it differs from the last subdevice's erase size, count it */
-+ for (i = 0; i < num_devs; i++) {
-+ if (subdev[i]->numeraseregions == 0) {
-+ /* current subdevice has uniform erase size */
-+ if (subdev[i]->erasesize != curr_erasesize) {
-+ /* if it differs from the last subdevice's erase size, count it */
- ++num_erase_region;
- curr_erasesize = subdev[i]->erasesize;
-- if(curr_erasesize > max_erasesize)
-+ if (curr_erasesize > max_erasesize)
- max_erasesize = curr_erasesize;
- }
-- }
-- else
-- { /* current subdevice has variable erase size */
-+ } else {
-+ /* current subdevice has variable erase size */
- int j;
-- for(j = 0; j < subdev[i]->numeraseregions; j++)
-- { /* walk the list of erase regions, count any changes */
-- if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
-- {
-+ for (j = 0; j < subdev[i]->numeraseregions; j++) {
-+
-+ /* walk the list of erase regions, count any changes */
-+ if (subdev[i]->eraseregions[j].erasesize !=
-+ curr_erasesize) {
- ++num_erase_region;
-- curr_erasesize = subdev[i]->eraseregions[j].erasesize;
-- if(curr_erasesize > max_erasesize)
-+ curr_erasesize =
-+ subdev[i]->eraseregions[j].
-+ erasesize;
-+ if (curr_erasesize > max_erasesize)
- max_erasesize = curr_erasesize;
- }
- }
- }
- }
-
-- if(num_erase_region == 1)
-- { /*
-+ if (num_erase_region == 1) {
-+ /*
- * All subdevices have the same uniform erase size.
- * This is easy:
- */
- concat->mtd.erasesize = curr_erasesize;
- concat->mtd.numeraseregions = 0;
-- }
-- else
-- { /*
-+ } else {
-+ /*
- * erase block size varies across the subdevices: allocate
- * space to store the data describing the variable erase regions
- */
-@@ -590,12 +806,13 @@
-
- concat->mtd.erasesize = max_erasesize;
- concat->mtd.numeraseregions = num_erase_region;
-- concat->mtd.eraseregions = erase_region_p = kmalloc (
-- num_erase_region * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
-- if(!erase_region_p)
-- {
-+ concat->mtd.eraseregions = erase_region_p =
-+ kmalloc(num_erase_region *
-+ sizeof (struct mtd_erase_region_info), GFP_KERNEL);
-+ if (!erase_region_p) {
- kfree(concat);
-- printk ("memory allocation error while creating erase region list"
-+ printk
-+ ("memory allocation error while creating erase region list"
- " for device \"%s\"\n", name);
- return NULL;
- }
-@@ -606,41 +823,48 @@
- */
- curr_erasesize = subdev[0]->erasesize;
- begin = position = 0;
-- for(i = 0; i < num_devs; i++)
-- {
-- if(subdev[i]->numeraseregions == 0)
-- { /* current subdevice has uniform erase size */
-- if(subdev[i]->erasesize != curr_erasesize)
-- { /*
-+ for (i = 0; i < num_devs; i++) {
-+ if (subdev[i]->numeraseregions == 0) {
-+ /* current subdevice has uniform erase size */
-+ if (subdev[i]->erasesize != curr_erasesize) {
-+ /*
- * fill in an mtd_erase_region_info structure for the area
- * we have walked so far:
- */
- erase_region_p->offset = begin;
-- erase_region_p->erasesize = curr_erasesize;
-- erase_region_p->numblocks = (position - begin) / curr_erasesize;
-+ erase_region_p->erasesize =
-+ curr_erasesize;
-+ erase_region_p->numblocks =
-+ (position - begin) / curr_erasesize;
- begin = position;
-
- curr_erasesize = subdev[i]->erasesize;
- ++erase_region_p;
- }
- position += subdev[i]->size;
-- }
-- else
-- { /* current subdevice has variable erase size */
-+ } else {
-+ /* current subdevice has variable erase size */
- int j;
-- for(j = 0; j < subdev[i]->numeraseregions; j++)
-- { /* walk the list of erase regions, count any changes */
-- if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
-- {
-+ for (j = 0; j < subdev[i]->numeraseregions; j++) {
-+ /* walk the list of erase regions, count any changes */
-+ if (subdev[i]->eraseregions[j].
-+ erasesize != curr_erasesize) {
- erase_region_p->offset = begin;
-- erase_region_p->erasesize = curr_erasesize;
-- erase_region_p->numblocks = (position - begin) / curr_erasesize;
-+ erase_region_p->erasesize =
-+ curr_erasesize;
-+ erase_region_p->numblocks =
-+ (position -
-+ begin) / curr_erasesize;
- begin = position;
-
-- curr_erasesize = subdev[i]->eraseregions[j].erasesize;
-+ curr_erasesize =
-+ subdev[i]->eraseregions[j].
-+ erasesize;
- ++erase_region_p;
- }
-- position += subdev[i]->eraseregions[j].numblocks * curr_erasesize;
-+ position +=
-+ subdev[i]->eraseregions[j].
-+ numblocks * curr_erasesize;
- }
- }
- }
-@@ -660,16 +884,14 @@
- void mtd_concat_destroy(struct mtd_info *mtd)
- {
- struct mtd_concat *concat = CONCAT(mtd);
-- if(concat->mtd.numeraseregions)
-+ if (concat->mtd.numeraseregions)
- kfree(concat->mtd.eraseregions);
- kfree(concat);
- }
-
--
- EXPORT_SYMBOL(mtd_concat_create);
- EXPORT_SYMBOL(mtd_concat_destroy);
-
--
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Robert Kaiser <rkaiser@sysgo.de>");
- MODULE_DESCRIPTION("Generic support for concatenating of MTD devices");
---- linux-2.4.21/drivers/mtd/mtdcore.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/mtdcore.c
-@@ -1,5 +1,5 @@
- /*
-- * $Id: mtdcore.c,v 1.34 2003/01/24 23:32:25 dwmw2 Exp $
-+ * $Id: mtdcore.c,v 1.45 2005/02/18 14:34:50 dedekind Exp $
- *
- * Core registration and callback routines for MTD
- * drivers and users.
-@@ -17,6 +17,7 @@
- #include <linux/major.h>
- #include <linux/fs.h>
- #include <linux/ioctl.h>
-+#include <linux/init.h>
- #include <linux/mtd/compatmac.h>
- #ifdef CONFIG_PROC_FS
- #include <linux/proc_fs.h>
-@@ -24,9 +25,15 @@
-
- #include <linux/mtd/mtd.h>
-
--static DECLARE_MUTEX(mtd_table_mutex);
--static struct mtd_info *mtd_table[MAX_MTD_DEVICES];
--static struct mtd_notifier *mtd_notifiers = NULL;
-+/* These are exported solely for the purpose of mtd_blkdevs.c. You
-+ should not use them for _anything_ else */
-+DECLARE_MUTEX(mtd_table_mutex);
-+struct mtd_info *mtd_table[MAX_MTD_DEVICES];
-+
-+EXPORT_SYMBOL_GPL(mtd_table_mutex);
-+EXPORT_SYMBOL_GPL(mtd_table);
-+
-+static LIST_HEAD(mtd_notifiers);
-
- /**
- * add_mtd_device - register an MTD device
-@@ -44,21 +51,28 @@
-
- down(&mtd_table_mutex);
-
-- for (i=0; i< MAX_MTD_DEVICES; i++)
-- if (!mtd_table[i])
-- {
-- struct mtd_notifier *not=mtd_notifiers;
-+ for (i=0; i < MAX_MTD_DEVICES; i++)
-+ if (!mtd_table[i]) {
-+ struct list_head *this;
-
- mtd_table[i] = mtd;
- mtd->index = i;
-+ mtd->usecount = 0;
-+
- DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
-- while (not)
-- {
-- (*(not->add))(mtd);
-- not = not->next;
-+ /* No need to get a refcount on the module containing
-+ the notifier, since we hold the mtd_table_mutex */
-+ list_for_each(this, &mtd_notifiers) {
-+ struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
-+ not->add(mtd);
- }
-+
- up(&mtd_table_mutex);
-- MOD_INC_USE_COUNT;
-+ /* We _know_ we aren't being removed, because
-+ our caller is still holding us here. So none
-+ of this try_ nonsense, and no bitching about it
-+ either. :) */
-+ __module_get(THIS_MODULE);
- return 0;
- }
-
-@@ -78,29 +92,34 @@
-
- int del_mtd_device (struct mtd_info *mtd)
- {
-- struct mtd_notifier *not=mtd_notifiers;
-- int i;
-+ int ret;
-
- down(&mtd_table_mutex);
-
-- for (i=0; i < MAX_MTD_DEVICES; i++)
-- {
-- if (mtd_table[i] == mtd)
-- {
-- while (not)
-- {
-- (*(not->remove))(mtd);
-- not = not->next;
-- }
-- mtd_table[i] = NULL;
-- up (&mtd_table_mutex);
-- MOD_DEC_USE_COUNT;
-- return 0;
-+ if (mtd_table[mtd->index] != mtd) {
-+ ret = -ENODEV;
-+ } else if (mtd->usecount) {
-+ printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n",
-+ mtd->index, mtd->name, mtd->usecount);
-+ ret = -EBUSY;
-+ } else {
-+ struct list_head *this;
-+
-+ /* No need to get a refcount on the module containing
-+ the notifier, since we hold the mtd_table_mutex */
-+ list_for_each(this, &mtd_notifiers) {
-+ struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
-+ not->remove(mtd);
- }
-+
-+ mtd_table[mtd->index] = NULL;
-+
-+ module_put(THIS_MODULE);
-+ ret = 0;
- }
-
- up(&mtd_table_mutex);
-- return 1;
-+ return ret;
- }
-
- /**
-@@ -118,10 +137,9 @@
-
- down(&mtd_table_mutex);
-
-- new->next = mtd_notifiers;
-- mtd_notifiers = new;
-+ list_add(&new->list, &mtd_notifiers);
-
-- MOD_INC_USE_COUNT;
-+ __module_get(THIS_MODULE);
-
- for (i=0; i< MAX_MTD_DEVICES; i++)
- if (mtd_table[i])
-@@ -131,8 +149,8 @@
- }
-
- /**
-- * register_mtd_user - unregister a 'user' of MTD devices.
-- * @new: pointer to notifier info structure
-+ * unregister_mtd_user - unregister a 'user' of MTD devices.
-+ * @old: pointer to notifier info structure
- *
- * Removes a callback function pair from the list of 'users' to be
- * notified upon addition or removal of MTD devices. Causes the
-@@ -142,34 +160,24 @@
-
- int unregister_mtd_user (struct mtd_notifier *old)
- {
-- struct mtd_notifier **prev = &mtd_notifiers;
-- struct mtd_notifier *cur;
- int i;
-
- down(&mtd_table_mutex);
-
-- while ((cur = *prev)) {
-- if (cur == old) {
-- *prev = cur->next;
--
-- MOD_DEC_USE_COUNT;
-+ module_put(THIS_MODULE);
-
- for (i=0; i< MAX_MTD_DEVICES; i++)
- if (mtd_table[i])
- old->remove(mtd_table[i]);
-
-+ list_del(&old->list);
- up(&mtd_table_mutex);
- return 0;
-- }
-- prev = &cur->next;
-- }
-- up(&mtd_table_mutex);
-- return 1;
- }
-
-
- /**
-- * __get_mtd_device - obtain a validated handle for an MTD device
-+ * get_mtd_device - obtain a validated handle for an MTD device
- * @mtd: last known address of the required MTD device
- * @num: internal device number of the required MTD device
- *
-@@ -177,11 +185,10 @@
- * table, if any. Given an address and num == -1, search the device table
- * for a device with that address and return if it's still present. Given
- * both, return the num'th driver only if its address matches. Return NULL
-- * if not. get_mtd_device() increases the use count, but
-- * __get_mtd_device() doesn't - you should generally use get_mtd_device().
-+ * if not.
- */
-
--struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num)
-+struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
- {
- struct mtd_info *ret = NULL;
- int i;
-@@ -198,16 +205,33 @@
- ret = NULL;
- }
-
-+ if (ret && !try_module_get(ret->owner))
-+ ret = NULL;
-+
-+ if (ret)
-+ ret->usecount++;
-+
- up(&mtd_table_mutex);
- return ret;
- }
-
-+void put_mtd_device(struct mtd_info *mtd)
-+{
-+ int c;
-+
-+ down(&mtd_table_mutex);
-+ c = --mtd->usecount;
-+ up(&mtd_table_mutex);
-+ BUG_ON(c < 0);
-+
-+ module_put(mtd->owner);
-+}
-
- /* default_mtd_writev - default mtd writev method for MTD devices that
- * dont implement their own
- */
-
--int default_mtd_writev(struct mtd_info *mtd, const struct iovec *vecs,
-+int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
- unsigned long count, loff_t to, size_t *retlen)
- {
- unsigned long i;
-@@ -237,7 +261,7 @@
- * implement their own
- */
-
--int default_mtd_readv(struct mtd_info *mtd, struct iovec *vecs,
-+int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,
- unsigned long count, loff_t from, size_t *retlen)
- {
- unsigned long i;
-@@ -265,7 +289,8 @@
-
- EXPORT_SYMBOL(add_mtd_device);
- EXPORT_SYMBOL(del_mtd_device);
--EXPORT_SYMBOL(__get_mtd_device);
-+EXPORT_SYMBOL(get_mtd_device);
-+EXPORT_SYMBOL(put_mtd_device);
- EXPORT_SYMBOL(register_mtd_user);
- EXPORT_SYMBOL(unregister_mtd_user);
- EXPORT_SYMBOL(default_mtd_writev);
-@@ -308,10 +333,7 @@
- /* Support for /proc/mtd */
-
- #ifdef CONFIG_PROC_FS
--
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
- static struct proc_dir_entry *proc_mtd;
--#endif
-
- static inline int mtd_proc_info (char *buf, int i)
- {
-@@ -324,13 +346,8 @@
- this->erasesize, this->name);
- }
-
--static int mtd_read_proc ( char *page, char **start, off_t off,int count
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-- ,int *eof, void *data_unused
--#else
-- ,int unused
--#endif
-- )
-+static int mtd_read_proc (char *page, char **start, off_t off, int count,
-+ int *eof, void *data_unused)
- {
- int len, l, i;
- off_t begin = 0;
-@@ -350,9 +367,7 @@
- }
- }
-
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
- *eof = 1;
--#endif
-
- done:
- up(&mtd_table_mutex);
-@@ -362,36 +377,16 @@
- return ((count < begin+len-off) ? count : begin+len-off);
- }
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
--struct proc_dir_entry mtd_proc_entry = {
-- 0, /* low_ino: the inode -- dynamic */
-- 3, "mtd", /* len of name and name */
-- S_IFREG | S_IRUGO, /* mode */
-- 1, 0, 0, /* nlinks, owner, group */
-- 0, NULL, /* size - unused; operations -- use default */
-- &mtd_read_proc, /* function used to read data */
-- /* nothing more */
-- };
--#endif
--
- #endif /* CONFIG_PROC_FS */
-
- /*====================================================================*/
- /* Init code */
-
--int __init init_mtd(void)
-+static int __init init_mtd(void)
- {
- #ifdef CONFIG_PROC_FS
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-- if ((proc_mtd = create_proc_entry( "mtd", 0, 0 )))
-+ if ((proc_mtd = create_proc_entry( "mtd", 0, NULL )))
- proc_mtd->read_proc = mtd_read_proc;
--#else
-- proc_register_dynamic(&proc_root,&mtd_proc_entry);
--#endif
--#endif
--
--#if LINUX_VERSION_CODE < 0x20212
-- init_mtd_devices();
- #endif
-
- #ifdef CONFIG_PM
-@@ -410,12 +405,8 @@
- #endif
-
- #ifdef CONFIG_PROC_FS
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
- if (proc_mtd)
-- remove_proc_entry( "mtd", 0);
--#else
-- proc_unregister(&proc_root,mtd_proc_entry.low_ino);
--#endif
-+ remove_proc_entry( "mtd", NULL);
- #endif
- }
-
---- linux-2.4.21/drivers/mtd/mtdpart.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/mtdpart.c
-@@ -5,7 +5,7 @@
- *
- * This code is GPL
- *
-- * $Id: mtdpart.c,v 1.32 2002/10/21 13:40:05 jocke Exp $
-+ * $Id: mtdpart.c,v 1.53 2005/02/08 17:11:13 nico Exp $
- *
- * 02-21-2002 Thomas Gleixner <gleixner@autronix.de>
- * added support for read_oob, write_oob
-@@ -16,10 +16,11 @@
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/list.h>
--
-+#include <linux/config.h>
-+#include <linux/kmod.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
--
-+#include <linux/mtd/compatmac.h>
-
- /* Our partition linked list */
- static LIST_HEAD(mtd_partitions);
-@@ -54,8 +55,12 @@
- len = 0;
- else if (from + len > mtd->size)
- len = mtd->size - from;
-+ if (part->master->read_ecc == NULL)
- return part->master->read (part->master, from + part->offset,
- len, retlen, buf);
-+ else
-+ return part->master->read_ecc (part->master, from + part->offset,
-+ len, retlen, buf, NULL, &mtd->oobinfo);
- }
-
- static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
-@@ -78,9 +83,11 @@
-
-
- static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-- size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel)
-+ size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
- {
- struct mtd_part *part = PART(mtd);
-+ if (oobsel == NULL)
-+ oobsel = &mtd->oobinfo;
- if (from >= mtd->size)
- len = 0;
- else if (from + len > mtd->size)
-@@ -109,14 +116,28 @@
- len, retlen, buf);
- }
-
-+static int part_get_user_prot_info (struct mtd_info *mtd,
-+ struct otp_info *buf, size_t len)
-+{
-+ struct mtd_part *part = PART(mtd);
-+ return part->master->get_user_prot_info (part->master, buf, len);
-+}
-+
- static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
- {
- struct mtd_part *part = PART(mtd);
-- return part->master->read_user_prot_reg (part->master, from,
-+ return part->master->read_fact_prot_reg (part->master, from,
- len, retlen, buf);
- }
-
-+static int part_get_fact_prot_info (struct mtd_info *mtd,
-+ struct otp_info *buf, size_t len)
-+{
-+ struct mtd_part *part = PART(mtd);
-+ return part->master->get_fact_prot_info (part->master, buf, len);
-+}
-+
- static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
- {
-@@ -127,17 +148,24 @@
- len = 0;
- else if (to + len > mtd->size)
- len = mtd->size - to;
-+ if (part->master->write_ecc == NULL)
- return part->master->write (part->master, to + part->offset,
- len, retlen, buf);
-+ else
-+ return part->master->write_ecc (part->master, to + part->offset,
-+ len, retlen, buf, NULL, &mtd->oobinfo);
-+
- }
-
- static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf,
-- u_char *eccbuf, int oobsel)
-+ u_char *eccbuf, struct nand_oobinfo *oobsel)
- {
- struct mtd_part *part = PART(mtd);
- if (!(mtd->flags & MTD_WRITEABLE))
- return -EROFS;
-+ if (oobsel == NULL)
-+ oobsel = &mtd->oobinfo;
- if (to >= mtd->size)
- len = 0;
- else if (to + len > mtd->size)
-@@ -168,41 +196,61 @@
- len, retlen, buf);
- }
-
--static int part_writev (struct mtd_info *mtd, const struct iovec *vecs,
-+static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len)
-+{
-+ struct mtd_part *part = PART(mtd);
-+ return part->master->lock_user_prot_reg (part->master, from, len);
-+}
-+
-+static int part_writev (struct mtd_info *mtd, const struct kvec *vecs,
- unsigned long count, loff_t to, size_t *retlen)
- {
- struct mtd_part *part = PART(mtd);
- if (!(mtd->flags & MTD_WRITEABLE))
- return -EROFS;
-+ if (part->master->writev_ecc == NULL)
- return part->master->writev (part->master, vecs, count,
- to + part->offset, retlen);
-+ else
-+ return part->master->writev_ecc (part->master, vecs, count,
-+ to + part->offset, retlen,
-+ NULL, &mtd->oobinfo);
- }
-
--static int part_readv (struct mtd_info *mtd, struct iovec *vecs,
-+static int part_readv (struct mtd_info *mtd, struct kvec *vecs,
- unsigned long count, loff_t from, size_t *retlen)
- {
- struct mtd_part *part = PART(mtd);
-+ if (part->master->readv_ecc == NULL)
- return part->master->readv (part->master, vecs, count,
- from + part->offset, retlen);
-+ else
-+ return part->master->readv_ecc (part->master, vecs, count,
-+ from + part->offset, retlen,
-+ NULL, &mtd->oobinfo);
- }
-
--static int part_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs,
-+static int part_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs,
- unsigned long count, loff_t to, size_t *retlen,
-- u_char *eccbuf, int oobsel)
-+ u_char *eccbuf, struct nand_oobinfo *oobsel)
- {
- struct mtd_part *part = PART(mtd);
- if (!(mtd->flags & MTD_WRITEABLE))
- return -EROFS;
-+ if (oobsel == NULL)
-+ oobsel = &mtd->oobinfo;
- return part->master->writev_ecc (part->master, vecs, count,
- to + part->offset, retlen,
- eccbuf, oobsel);
- }
-
--static int part_readv_ecc (struct mtd_info *mtd, struct iovec *vecs,
-+static int part_readv_ecc (struct mtd_info *mtd, struct kvec *vecs,
- unsigned long count, loff_t from, size_t *retlen,
-- u_char *eccbuf, int oobsel)
-+ u_char *eccbuf, struct nand_oobinfo *oobsel)
- {
- struct mtd_part *part = PART(mtd);
-+ if (oobsel == NULL)
-+ oobsel = &mtd->oobinfo;
- return part->master->readv_ecc (part->master, vecs, count,
- from + part->offset, retlen,
- eccbuf, oobsel);
-@@ -211,13 +259,29 @@
- static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
- {
- struct mtd_part *part = PART(mtd);
-+ int ret;
- if (!(mtd->flags & MTD_WRITEABLE))
- return -EROFS;
- if (instr->addr >= mtd->size)
- return -EINVAL;
- instr->addr += part->offset;
-- return part->master->erase(part->master, instr);
-+ ret = part->master->erase(part->master, instr);
-+ return ret;
-+}
-+
-+void mtd_erase_callback(struct erase_info *instr)
-+{
-+ if (instr->mtd->erase == part_erase) {
-+ struct mtd_part *part = PART(instr->mtd);
-+
-+ if (instr->fail_addr != 0xffffffff)
-+ instr->fail_addr -= part->offset;
-+ instr->addr -= part->offset;
-+ }
-+ if (instr->callback)
-+ instr->callback(instr);
- }
-+EXPORT_SYMBOL_GPL(mtd_erase_callback);
-
- static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
- {
-@@ -253,6 +317,26 @@
- part->master->resume(part->master);
- }
-
-+static int part_block_isbad (struct mtd_info *mtd, loff_t ofs)
-+{
-+ struct mtd_part *part = PART(mtd);
-+ if (ofs >= mtd->size)
-+ return -EINVAL;
-+ ofs += part->offset;
-+ return part->master->block_isbad(part->master, ofs);
-+}
-+
-+static int part_block_markbad (struct mtd_info *mtd, loff_t ofs)
-+{
-+ struct mtd_part *part = PART(mtd);
-+ if (!(mtd->flags & MTD_WRITEABLE))
-+ return -EROFS;
-+ if (ofs >= mtd->size)
-+ return -EINVAL;
-+ ofs += part->offset;
-+ return part->master->block_markbad(part->master, ofs);
-+}
-+
- /*
- * This function unregisters and destroy all slave MTD objects which are
- * attached to the given master MTD object.
-@@ -288,7 +372,7 @@
- */
-
- int add_mtd_partitions(struct mtd_info *master,
-- struct mtd_partition *parts,
-+ const struct mtd_partition *parts,
- int nbparts)
- {
- struct mtd_part *slave;
-@@ -321,7 +405,7 @@
-
- slave->mtd.name = parts[i].name;
- slave->mtd.bank_size = master->bank_size;
-- slave->mtd.module = master->module;
-+ slave->mtd.owner = master->owner;
-
- slave->mtd.read = part_read;
- slave->mtd.write = part_write;
-@@ -345,6 +429,12 @@
- slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
- if(master->write_user_prot_reg)
- slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
-+ if(master->lock_user_prot_reg)
-+ slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
-+ if(master->get_user_prot_info)
-+ slave->mtd.get_user_prot_info = part_get_user_prot_info;
-+ if(master->get_fact_prot_info)
-+ slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
- if (master->sync)
- slave->mtd.sync = part_sync;
- if (!i && master->suspend && master->resume) {
-@@ -363,6 +453,10 @@
- slave->mtd.lock = part_lock;
- if (master->unlock)
- slave->mtd.unlock = part_unlock;
-+ if (master->block_isbad)
-+ slave->mtd.block_isbad = part_block_isbad;
-+ if (master->block_markbad)
-+ slave->mtd.block_markbad = part_block_markbad;
- slave->mtd.erase = part_erase;
- slave->master = master;
- slave->offset = parts[i].offset;
-@@ -433,6 +527,9 @@
- parts[i].name);
- }
-
-+ /* copy oobinfo from master */
-+ memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo));
-+
- if(parts[i].mtdp)
- { /* store the object pointer (caller may or may not register it */
- *parts[i].mtdp = &slave->mtd;
-@@ -452,6 +549,75 @@
- EXPORT_SYMBOL(add_mtd_partitions);
- EXPORT_SYMBOL(del_mtd_partitions);
-
-+static DEFINE_SPINLOCK(part_parser_lock);
-+static LIST_HEAD(part_parsers);
-+
-+static struct mtd_part_parser *get_partition_parser(const char *name)
-+{
-+ struct list_head *this;
-+ void *ret = NULL;
-+ spin_lock(&part_parser_lock);
-+
-+ list_for_each(this, &part_parsers) {
-+ struct mtd_part_parser *p = list_entry(this, struct mtd_part_parser, list);
-+
-+ if (!strcmp(p->name, name) && try_module_get(p->owner)) {
-+ ret = p;
-+ break;
-+ }
-+ }
-+ spin_unlock(&part_parser_lock);
-+
-+ return ret;
-+}
-+
-+int register_mtd_parser(struct mtd_part_parser *p)
-+{
-+ spin_lock(&part_parser_lock);
-+ list_add(&p->list, &part_parsers);
-+ spin_unlock(&part_parser_lock);
-+
-+ return 0;
-+}
-+
-+int deregister_mtd_parser(struct mtd_part_parser *p)
-+{
-+ spin_lock(&part_parser_lock);
-+ list_del(&p->list);
-+ spin_unlock(&part_parser_lock);
-+ return 0;
-+}
-+
-+int parse_mtd_partitions(struct mtd_info *master, const char **types,
-+ struct mtd_partition **pparts, unsigned long origin)
-+{
-+ struct mtd_part_parser *parser;
-+ int ret = 0;
-+
-+ for ( ; ret <= 0 && *types; types++) {
-+ parser = get_partition_parser(*types);
-+#ifdef CONFIG_KMOD
-+ if (!parser && !request_module("%s", *types))
-+ parser = get_partition_parser(*types);
-+#endif
-+ if (!parser) {
-+ printk(KERN_NOTICE "%s partition parsing not available\n",
-+ *types);
-+ continue;
-+ }
-+ ret = (*parser->parse_fn)(master, pparts, origin);
-+ if (ret > 0) {
-+ printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
-+ ret, parser->name, master->name);
-+ }
-+ put_partition_parser(parser);
-+ }
-+ return ret;
-+}
-+
-+EXPORT_SYMBOL_GPL(parse_mtd_partitions);
-+EXPORT_SYMBOL_GPL(register_mtd_parser);
-+EXPORT_SYMBOL_GPL(deregister_mtd_parser);
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
---- linux-2.4.21/drivers/mtd/nand/Config.in~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/nand/Config.in
-@@ -1,6 +1,6 @@
- # drivers/mtd/nand/Config.in
-
--# $Id: Config.in,v 1.11 2002/12/01 13:23:05 gleixner Exp $
-+# $Id: Config.in,v 1.24 2005/01/17 18:25:19 dmarlin Exp $
-
- mainmenu_option next_comment
-
-@@ -11,26 +11,56 @@
- bool ' Verify NAND page writes' CONFIG_MTD_NAND_VERIFY_WRITE
- fi
-
--if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_P720T" = "y" ]; then
-- dep_tristate ' NAND Flash device on SPIA board' CONFIG_MTD_NAND_SPIA $CONFIG_MTD_NAND
-+if [ "$CONFIG_ARM" = "y" ]; then
-+ dep_tristate ' NAND Flash device on SPIA board' CONFIG_MTD_NAND_SPIA $CONFIG_MTD_NAND $CONFIG_ARCH_P720T
-+ dep_tristate ' NAND Flash device on TOTO board' CONFIG_MTD_NAND_TOTO $CONFIG_MTD_NAND $CONFIG_ARCH_OMAP
-+ dep_tristate ' SmartMedia Card on AUTCPU12 board' CONFIG_MTD_NAND_AUTCPU12 $CONFIG_MTD_NAND $CONFIG_ARCH_AUTCPU12
-+ dep_tristate ' NAND Flash device on EDP7312 board' CONFIG_MTD_NAND_EDB7312 $CONFIG_MTD_NAND $CONFIG_ARCH_EDB7312
- fi
-
--if [ "$CONFIG_ARCH_AUTCPU12" = "y" ]; then
-- dep_tristate ' SmartMedia Card on AUTCPU12 board' CONFIG_MTD_NAND_AUTCPU12 $CONFIG_MTD_NAND
-+if [ "$CONFIG_MTD_DOC2001PLUS" = "y" -o "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" -o "$CONFIG_MTD_NAND" = "y" ]; then
-+ define_bool CONFIG_MTD_NAND_IDS y
-+else
-+ if [ "$CONFIG_MTD_DOC2001PLUS" = "m" -o "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" -o "$CONFIG_MTD_NAND" = "m" ]; then
-+ define_bool CONFIG_MTD_NAND_IDS m
-+ fi
- fi
-
--if [ "$CONFIG_ARCH_EDB7312" = "y" ]; then
-- dep_tristate ' NAND Flash device on EDP7312 board' CONFIG_MTD_NAND_EDB7312 $CONFIG_MTD_NAND
-+if [ "$CONFIG_TOSHIBA_RBTX4925" = "y" ]; then
-+ dep_tristate ' SmartMedia Card on Toshiba RBTX4925 reference board' CONFIG_MTD_NAND_TX4925NDFMC $CONFIG_MTD_NAND $CONFIG_TOSHIBA_RBTX4925_MPLEX_NAND
- fi
-
--if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" -o "$CONFIG_MTD_NAND" = "y" ]; then
-- define_bool CONFIG_MTD_NAND_IDS y
-+if [ "$CONFIG_TOSHIBA_RBTX4938" = "y" ]; then
-+ dep_tristate ' NAND Flash device on Toshiba RBTX4938 reference board' CONFIG_MTD_NAND_TX4938NDFMC $CONFIG_MTD_NAND $CONFIG_TOSHIBA_RBTX4938_MPLEX_NAND
- fi
-
--if [ "$CONFIG_MTD_NAND_IDS" != "y" ]; then
--if [ "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" -o "$CONFIG_MTD_NAND" = "m" ]; then
-- define_bool CONFIG_MTD_NAND_IDS m
-+if [ "$CONFIG_PPCHAMELEONEVB" = "y" ]; then
-+ dep_tristate ' NAND Flash device on PPChameleonEVB board' CONFIG_MTD_NAND_PPCHAMELEONEVB $CONFIG_MTD_NAND
-+fi
-+
-+if [ "$CONFIG_SOC_AU1550" = "y" ]; then
-+ dep_tristate ' NAND Flash Driver for Au1550 controller' CONFIG_MTD_NAND_AU1550 $CONFIG_MTD_NAND
- fi
-+
-+if [ "$CONFIG_SH_SOLUTION_ENGINE" = "y" ]; then
-+ dep_tristate ' Renesas Flash ROM 4-slot interface board (FROM_BOARD4)' CONFIG_MTD_NAND_RTC_FROM4 $CONFIG_MTD_NAND
-+ if [ "$CONFIG_MTD_NAND_RTC_FROM4" = "y" ]; then
-+ define_bool CONFIG_REED_SOLOMON y
-+ define_bool CONFIG_REED_SOLOMON_DEC8 y
-+ else
-+ if [ "$CONFIG_MTD_NAND_RTC_FROM4" = "m" ]; then
-+ define_bool CONFIG_REED_SOLOMON m
-+ define_bool CONFIG_REED_SOLOMON_DEC8 m
-+ fi
-+ fi
-+fi
-+
-+dep_tristate ' DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)' CONFIG_MTD_NAND_DISKONCHIP $CONFIG_MTD_NAND $CONFIG_EXPERIMENTAL
-+if [ "$CONFIG_MTD_NAND_DISKONCHIP" = "y" -o "$CONFIG_MTD_NAND_DISKONCHIP" = "m" ]; then
-+ bool ' Advanced detection options for DiskOnChip' CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED
-+ hex ' Physical address of DiskOnChip' CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS
-+ bool ' Probe high addresses' CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH $CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED
-+ bool ' Allow BBT write on DiskOnChip Millennium and 2000TSOP' CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE
- fi
-
- endmenu
---- linux-2.4.21/drivers/mtd/nand/Makefile~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/nand/Makefile
-@@ -1,16 +1,16 @@
- #
--# linux/drivers/nand/Makefile
-+# linux/drivers/nand/Makefile.24
-+# Makefile for obsolete kernels.
- #
--# $Id: Makefile,v 1.10 2002/12/01 13:23:05 gleixner Exp $
-+# $Id: Makefile.24,v 1.1 2004/07/12 16:08:17 dwmw2 Exp $
-
- O_TARGET := nandlink.o
-+export-objs := nand_base.o nand_bbt.o nand_ecc.o nand_ids.o
-+list-multi := nand.o
-
--export-objs := nand.o nand_ecc.o nand_ids.o
--
--obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o
--obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
--obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
--obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o
--obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
-+include Makefile.common
-
- include $(TOPDIR)/Rules.make
-+
-+nand.o: $(nand-objs)
-+ $(LD) -r -o $@ $(nand-objs)
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/nand/Makefile.common
-@@ -0,0 +1,24 @@
-+#
-+# linux/drivers/nand/Makefile
-+#
-+# $Id: Makefile.common,v 1.15 2004/11/26 12:28:22 dedekind Exp $
-+
-+obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o
-+obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
-+
-+obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
-+obj-$(CONFIG_MTD_NAND_TOTO) += toto.o
-+obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
-+obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o
-+obj-$(CONFIG_MTD_NAND_TX4925NDFMC) += tx4925ndfmc.o
-+obj-$(CONFIG_MTD_NAND_TX4938NDFMC) += tx4938ndfmc.o
-+obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
-+obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o
-+obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
-+obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
-+obj-$(CONFIG_MTD_NAND_H1900) += h1910.o
-+obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o
-+obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
-+obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
-+
-+nand-objs = nand_base.o nand_bbt.o
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/nand/au1550nd.c
-@@ -0,0 +1,477 @@
-+/*
-+ * drivers/mtd/nand/au1550nd.c
-+ *
-+ * Copyright (C) 2004 Embedded Edge, LLC
-+ *
-+ * $Id: au1550nd.c,v 1.11 2004/11/04 12:53:10 gleixner 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/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 <asm/io.h>
-+
-+/* fixme: this is ugly */
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
-+#include <asm/mach-au1x00/au1000.h>
-+#ifdef CONFIG_MIPS_PB1550
-+#include <asm/mach-pb1x00/pb1550.h>
-+#endif
-+#ifdef CONFIG_MIPS_DB1550
-+#include <asm/mach-db1x00/db1x00.h>
-+#endif
-+#else
-+#include <asm/au1000.h>
-+#ifdef CONFIG_MIPS_PB1550
-+#include <asm/pb1550.h>
-+#endif
-+#ifdef CONFIG_MIPS_DB1550
-+#include <asm/db1x00.h>
-+#endif
-+#endif
-+
-+/*
-+ * MTD structure for NAND controller
-+ */
-+static struct mtd_info *au1550_mtd = NULL;
-+static void __iomem *p_nand;
-+static int nand_width = 1; /* default x8*/
-+
-+#define NAND_CS 1
-+
-+/*
-+ * Define partitions for flash device
-+ */
-+const static struct mtd_partition partition_info[] = {
-+#ifdef CONFIG_MIPS_PB1550
-+#define NUM_PARTITIONS 2
-+ {
-+ .name = "Pb1550 NAND FS 0",
-+ .offset = 0,
-+ .size = 8*1024*1024
-+ },
-+ {
-+ .name = "Pb1550 NAND FS 1",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = MTDPART_SIZ_FULL
-+ }
-+#endif
-+#ifdef CONFIG_MIPS_DB1550
-+#define NUM_PARTITIONS 2
-+ {
-+ .name = "Db1550 NAND FS 0",
-+ .offset = 0,
-+ .size = 8*1024*1024
-+ },
-+ {
-+ .name = "Db1550 NAND FS 1",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = MTDPART_SIZ_FULL
-+ }
-+#endif
-+};
-+
-+
-+/**
-+ * au_read_byte - read one byte from the chip
-+ * @mtd: MTD device structure
-+ *
-+ * read function for 8bit buswith
-+ */
-+static u_char au_read_byte(struct mtd_info *mtd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ u_char ret = readb(this->IO_ADDR_R);
-+ au_sync();
-+ return ret;
-+}
-+
-+/**
-+ * au_write_byte - write one byte to the chip
-+ * @mtd: MTD device structure
-+ * @byte: pointer to data byte to write
-+ *
-+ * write function for 8it buswith
-+ */
-+static void au_write_byte(struct mtd_info *mtd, u_char byte)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ writeb(byte, this->IO_ADDR_W);
-+ au_sync();
-+}
-+
-+/**
-+ * au_read_byte16 - read one byte endianess aware from the chip
-+ * @mtd: MTD device structure
-+ *
-+ * read function for 16bit buswith with
-+ * endianess conversion
-+ */
-+static u_char au_read_byte16(struct mtd_info *mtd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ u_char ret = (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
-+ au_sync();
-+ return ret;
-+}
-+
-+/**
-+ * au_write_byte16 - write one byte endianess aware to the chip
-+ * @mtd: MTD device structure
-+ * @byte: pointer to data byte to write
-+ *
-+ * write function for 16bit buswith with
-+ * endianess conversion
-+ */
-+static void au_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);
-+ au_sync();
-+}
-+
-+/**
-+ * au_read_word - read one word from the chip
-+ * @mtd: MTD device structure
-+ *
-+ * read function for 16bit buswith without
-+ * endianess conversion
-+ */
-+static u16 au_read_word(struct mtd_info *mtd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ u16 ret = readw(this->IO_ADDR_R);
-+ au_sync();
-+ return ret;
-+}
-+
-+/**
-+ * au_write_word - write one word to the chip
-+ * @mtd: MTD device structure
-+ * @word: data word to write
-+ *
-+ * write function for 16bit buswith without
-+ * endianess conversion
-+ */
-+static void au_write_word(struct mtd_info *mtd, u16 word)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ writew(word, this->IO_ADDR_W);
-+ au_sync();
-+}
-+
-+/**
-+ * au_write_buf - write buffer to chip
-+ * @mtd: MTD device structure
-+ * @buf: data buffer
-+ * @len: number of bytes to write
-+ *
-+ * write function for 8bit buswith
-+ */
-+static void au_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);
-+ au_sync();
-+ }
-+}
-+
-+/**
-+ * au_read_buf - read chip data into buffer
-+ * @mtd: MTD device structure
-+ * @buf: buffer to store date
-+ * @len: number of bytes to read
-+ *
-+ * read function for 8bit buswith
-+ */
-+static void au_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);
-+ au_sync();
-+ }
-+}
-+
-+/**
-+ * au_verify_buf - Verify chip data against buffer
-+ * @mtd: MTD device structure
-+ * @buf: buffer containing the data to compare
-+ * @len: number of bytes to compare
-+ *
-+ * verify function for 8bit buswith
-+ */
-+static int au_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;
-+ au_sync();
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+ * au_write_buf16 - write buffer to chip
-+ * @mtd: MTD device structure
-+ * @buf: data buffer
-+ * @len: number of bytes to write
-+ *
-+ * write function for 16bit buswith
-+ */
-+static void au_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);
-+ au_sync();
-+ }
-+
-+}
-+
-+/**
-+ * au_read_buf16 - read chip data into buffer
-+ * @mtd: MTD device structure
-+ * @buf: buffer to store date
-+ * @len: number of bytes to read
-+ *
-+ * read function for 16bit buswith
-+ */
-+static void au_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);
-+ au_sync();
-+ }
-+}
-+
-+/**
-+ * au_verify_buf16 - Verify chip data against buffer
-+ * @mtd: MTD device structure
-+ * @buf: buffer containing the data to compare
-+ * @len: number of bytes to compare
-+ *
-+ * verify function for 16bit buswith
-+ */
-+static int au_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;
-+ au_sync();
-+ }
-+ return 0;
-+}
-+
-+
-+static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+ register struct nand_chip *this = mtd->priv;
-+
-+ switch(cmd){
-+
-+ case NAND_CTL_SETCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_CMD; break;
-+ case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; break;
-+
-+ case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; break;
-+ case NAND_CTL_CLRALE:
-+ this->IO_ADDR_W = p_nand + MEM_STNAND_DATA;
-+ /* FIXME: Nobody knows why this is neccecary,
-+ * but it works only that way */
-+ udelay(1);
-+ break;
-+
-+ case NAND_CTL_SETNCE:
-+ /* assert (force assert) chip enable */
-+ au_writel((1<<(4+NAND_CS)) , MEM_STNDCTL); break;
-+ break;
-+
-+ case NAND_CTL_CLRNCE:
-+ /* deassert chip enable */
-+ au_writel(0, MEM_STNDCTL); break;
-+ break;
-+ }
-+
-+ this->IO_ADDR_R = this->IO_ADDR_W;
-+
-+ /* Drain the writebuffer */
-+ au_sync();
-+}
-+
-+int au1550_device_ready(struct mtd_info *mtd)
-+{
-+ int ret = (au_readl(MEM_STSTAT) & 0x1) ? 1 : 0;
-+ au_sync();
-+ return ret;
-+}
-+
-+/*
-+ * Main initialization routine
-+ */
-+int __init au1550_init (void)
-+{
-+ struct nand_chip *this;
-+ u16 boot_swapboot = 0; /* default value */
-+ int retval;
-+
-+ /* Allocate memory for MTD device structure and private data */
-+ au1550_mtd = kmalloc (sizeof(struct mtd_info) +
-+ sizeof (struct nand_chip), GFP_KERNEL);
-+ if (!au1550_mtd) {
-+ printk ("Unable to allocate NAND MTD dev structure.\n");
-+ return -ENOMEM;
-+ }
-+
-+ /* Get pointer to private data */
-+ this = (struct nand_chip *) (&au1550_mtd[1]);
-+
-+ /* Initialize structures */
-+ memset((char *) au1550_mtd, 0, sizeof(struct mtd_info));
-+ memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+ /* Link the private data with the MTD structure */
-+ au1550_mtd->priv = this;
-+
-+
-+ /* MEM_STNDCTL: disable ints, disable nand boot */
-+ au_writel(0, MEM_STNDCTL);
-+
-+#ifdef CONFIG_MIPS_PB1550
-+ /* set gpio206 high */
-+ au_writel(au_readl(GPIO2_DIR) & ~(1<<6), GPIO2_DIR);
-+
-+ boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) |
-+ ((bcsr->status >> 6) & 0x1);
-+ switch (boot_swapboot) {
-+ case 0:
-+ case 2:
-+ case 8:
-+ case 0xC:
-+ case 0xD:
-+ /* x16 NAND Flash */
-+ nand_width = 0;
-+ break;
-+ case 1:
-+ case 9:
-+ case 3:
-+ case 0xE:
-+ case 0xF:
-+ /* x8 NAND Flash */
-+ nand_width = 1;
-+ break;
-+ default:
-+ printk("Pb1550 NAND: bad boot:swap\n");
-+ retval = -EINVAL;
-+ goto outmem;
-+ }
-+#endif
-+
-+ /* Configure RCE1 - should be done by YAMON */
-+ au_writel(0x5 | (nand_width << 22), 0xB4001010); /* MEM_STCFG1 */
-+ au_writel(NAND_TIMING, 0xB4001014); /* MEM_STTIME1 */
-+ au_sync();
-+
-+ /* setup and enable chip select, MEM_STADDR1 */
-+ /* we really need to decode offsets only up till 0x20 */
-+ au_writel((1<<28) | (NAND_PHYS_ADDR>>4) |
-+ (((NAND_PHYS_ADDR + 0x1000)-1) & (0x3fff<<18)>>18),
-+ MEM_STADDR1);
-+ au_sync();
-+
-+ p_nand = ioremap(NAND_PHYS_ADDR, 0x1000);
-+
-+ /* Set address of hardware control function */
-+ this->hwcontrol = au1550_hwcontrol;
-+ this->dev_ready = au1550_device_ready;
-+ /* 30 us command delay time */
-+ this->chip_delay = 30;
-+ this->eccmode = NAND_ECC_SOFT;
-+
-+ this->options = NAND_NO_AUTOINCR;
-+
-+ if (!nand_width)
-+ this->options |= NAND_BUSWIDTH_16;
-+
-+ this->read_byte = (!nand_width) ? au_read_byte16 : au_read_byte;
-+ this->write_byte = (!nand_width) ? au_write_byte16 : au_write_byte;
-+ this->write_word = au_write_word;
-+ this->read_word = au_read_word;
-+ this->write_buf = (!nand_width) ? au_write_buf16 : au_write_buf;
-+ this->read_buf = (!nand_width) ? au_read_buf16 : au_read_buf;
-+ this->verify_buf = (!nand_width) ? au_verify_buf16 : au_verify_buf;
-+
-+ /* Scan to find existence of the device */
-+ if (nand_scan (au1550_mtd, 1)) {
-+ retval = -ENXIO;
-+ goto outio;
-+ }
-+
-+ /* Register the partitions */
-+ add_mtd_partitions(au1550_mtd, partition_info, NUM_PARTITIONS);
-+
-+ return 0;
-+
-+ outio:
-+ iounmap ((void *)p_nand);
-+
-+ outmem:
-+ kfree (au1550_mtd);
-+ return retval;
-+}
-+
-+module_init(au1550_init);
-+
-+/*
-+ * Clean up routine
-+ */
-+#ifdef MODULE
-+static void __exit au1550_cleanup (void)
-+{
-+ struct nand_chip *this = (struct nand_chip *) &au1550_mtd[1];
-+
-+ /* Release resources, unregister device */
-+ nand_release (au1550_mtd);
-+
-+ /* Free the MTD device structure */
-+ kfree (au1550_mtd);
-+
-+ /* Unmap */
-+ iounmap ((void *)p_nand);
-+}
-+module_exit(au1550_cleanup);
-+#endif
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Embedded Edge, LLC");
-+MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on Pb1550 board");
---- linux-2.4.21/drivers/mtd/nand/autcpu12.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/nand/autcpu12.c
-@@ -4,9 +4,9 @@
- * Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de>
- *
- * Derived from drivers/mtd/spia.c
-- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
-+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
- *
-- * $Id: autcpu12.c,v 1.6 2002/11/11 15:47:56 gleixner Exp $
-+ * $Id: autcpu12.c,v 1.22 2004/11/04 12:53:10 gleixner 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
-@@ -15,7 +15,7 @@
- * Overview:
- * This is a device driver for the NAND flash device found on the
- * autronix autcpu12 board, which is a SmartMediaCard. It supports
-- * 16MB, 32MB and 64MB cards.
-+ * 16MiB, 32MiB and 64MiB cards.
- *
- *
- * 02-12-2002 TG Cleanup of module params
-@@ -25,10 +25,11 @@
- * added page_cache
- *
- * 10-06-2002 TG 128K card support added
-- *
- */
-
-+#include <linux/version.h>
- #include <linux/slab.h>
-+#include <linux/init.h>
- #include <linux/module.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
-@@ -43,68 +44,49 @@
- */
- static struct mtd_info *autcpu12_mtd = NULL;
-
--/*
-- * Module stuff
-- */
--#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
--#define autcpu12_init init_module
--#define autcpu12_cleanup cleanup_module
--#endif
--
- static int autcpu12_io_base = CS89712_VIRT_BASE;
- static int autcpu12_fio_pbase = AUTCPU12_PHYS_SMC;
- static int autcpu12_fio_ctrl = AUTCPU12_SMC_SELECT_OFFSET;
- static int autcpu12_pedr = AUTCPU12_SMC_PORT_OFFSET;
--static int autcpu12_fio_base;
--
--#ifdef MODULE
--MODULE_PARM(autcpu12_fio_pbase, "i");
--MODULE_PARM(autcpu12_fio_ctrl, "i");
--MODULE_PARM(autcpu12_pedr, "i");
--
--__setup("autcpu12_fio_pbase=",autcpu12_fio_pbase);
--__setup("autcpu12_fio_ctrl=",autcpu12_fio_ctrl);
--__setup("autcpu12_pedr=",autcpu12_pedr);
--#endif
-+static void __iomem * autcpu12_fio_base;
-
- /*
- * Define partitions for flash devices
- */
--
- static struct mtd_partition partition_info16k[] = {
-- { name: "AUTCPU12 flash partition 1",
-- offset: 0,
-- size: 8 * SZ_1M },
-- { name: "AUTCPU12 flash partition 2",
-- offset: 8 * SZ_1M,
-- size: 8 * SZ_1M },
-+ { .name = "AUTCPU12 flash partition 1",
-+ .offset = 0,
-+ .size = 8 * SZ_1M },
-+ { .name = "AUTCPU12 flash partition 2",
-+ .offset = 8 * SZ_1M,
-+ .size = 8 * SZ_1M },
- };
-
- static struct mtd_partition partition_info32k[] = {
-- { name: "AUTCPU12 flash partition 1",
-- offset: 0,
-- size: 8 * SZ_1M },
-- { name: "AUTCPU12 flash partition 2",
-- offset: 8 * SZ_1M,
-- size: 24 * SZ_1M },
-+ { .name = "AUTCPU12 flash partition 1",
-+ .offset = 0,
-+ .size = 8 * SZ_1M },
-+ { .name = "AUTCPU12 flash partition 2",
-+ .offset = 8 * SZ_1M,
-+ .size = 24 * SZ_1M },
- };
-
- static struct mtd_partition partition_info64k[] = {
-- { name: "AUTCPU12 flash partition 1",
-- offset: 0,
-- size: 16 * SZ_1M },
-- { name: "AUTCPU12 flash partition 2",
-- offset: 16 * SZ_1M,
-- size: 48 * SZ_1M},
-+ { .name = "AUTCPU12 flash partition 1",
-+ .offset = 0,
-+ .size = 16 * SZ_1M },
-+ { .name = "AUTCPU12 flash partition 2",
-+ .offset = 16 * SZ_1M,
-+ .size = 48 * SZ_1M },
- };
-
- static struct mtd_partition partition_info128k[] = {
-- { name: "AUTCPU12 flash partition 1",
-- offset: 0,
-- size: 16 * SZ_1M },
-- { name: "AUTCPU12 flash partition 2",
-- offset: 16 * SZ_1M,
-- size: 112 * SZ_1M},
-+ { .name = "AUTCPU12 flash partition 1",
-+ .offset = 0,
-+ .size = 16 * SZ_1M },
-+ { .name = "AUTCPU12 flash partition 2",
-+ .offset = 16 * SZ_1M,
-+ .size = 112 * SZ_1M },
- };
-
- #define NUM_PARTITIONS16K 2
-@@ -114,7 +96,7 @@
- /*
- * hardware specific access to control-lines
- */
--void autcpu12_hwcontrol(int cmd)
-+static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd)
- {
-
- switch(cmd){
-@@ -133,12 +115,13 @@
- /*
- * read device ready pin
- */
--int autcpu12_device_ready(void)
-+int autcpu12_device_ready(struct mtd_info *mtd)
- {
-
- return ( (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0;
-
- }
-+
- /*
- * Main initialization routine
- */
-@@ -157,7 +140,7 @@
- }
-
- /* map physical adress */
-- autcpu12_fio_base=(unsigned long)ioremap(autcpu12_fio_pbase,SZ_1K);
-+ autcpu12_fio_base = ioremap(autcpu12_fio_pbase,SZ_1K);
- if(!autcpu12_fio_base){
- printk("Ioremap autcpu12 SmartMedia Card failed\n");
- err = -EIO;
-@@ -183,29 +166,18 @@
- this->chip_delay = 20;
- this->eccmode = NAND_ECC_SOFT;
-
-+ /* Enable the following for a flash based bad block table */
-+ /*
-+ this->options = NAND_USE_FLASH_BBT;
-+ */
-+ this->options = NAND_USE_FLASH_BBT;
-+
- /* Scan to find existance of the device */
-- if (nand_scan (autcpu12_mtd)) {
-+ if (nand_scan (autcpu12_mtd, 1)) {
- err = -ENXIO;
- goto out_ior;
- }
-
-- /* Allocate memory for internal data buffer */
-- this->data_buf = kmalloc (sizeof(u_char) * (autcpu12_mtd->oobblock + autcpu12_mtd->oobsize), GFP_KERNEL);
-- if (!this->data_buf) {
-- printk ("Unable to allocate NAND data buffer for AUTCPU12.\n");
-- err = -ENOMEM;
-- goto out_ior;
-- }
--
-- /* Allocate memory for internal data buffer */
-- this->data_cache = kmalloc (sizeof(u_char) * (autcpu12_mtd->oobblock + autcpu12_mtd->oobsize), GFP_KERNEL);
-- if (!this->data_cache) {
-- printk ("Unable to allocate NAND data cache for AUTCPU12.\n");
-- err = -ENOMEM;
-- goto out_buf;
-- }
-- this->cache_page = -1;
--
- /* Register the partitions */
- switch(autcpu12_mtd->size){
- case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break;
-@@ -215,15 +187,11 @@
- default: {
- printk ("Unsupported SmartMedia device\n");
- err = -ENXIO;
-- goto out_cac;
-+ goto out_ior;
- }
- }
- goto out;
-
--out_cac:
-- kfree (this->data_cache);
--out_buf:
-- kfree (this->data_buf);
- out_ior:
- iounmap((void *)autcpu12_fio_base);
- out_mtd:
-@@ -240,17 +208,8 @@
- #ifdef MODULE
- static void __exit autcpu12_cleanup (void)
- {
-- struct nand_chip *this = (struct nand_chip *) &autcpu12_mtd[1];
--
-- /* Unregister partitions */
-- del_mtd_partitions(autcpu12_mtd);
--
-- /* Unregister the device */
-- del_mtd_device (autcpu12_mtd);
--
-- /* Free internal data buffers */
-- kfree (this->data_buf);
-- kfree (this->data_cache);
-+ /* Release resources, unregister device */
-+ nand_release (autcpu12_mtd);
-
- /* unmap physical adress */
- iounmap((void *)autcpu12_fio_base);
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/nand/diskonchip.c
-@@ -0,0 +1,1780 @@
-+/*
-+ * 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>
-+ *
-+ * Error correction code lifted from the old docecc code
-+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
-+ * Copyright (C) 2000 Netgem S.A.
-+ * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de>
-+ *
-+ * Interface to generic NAND code for M-Systems DiskOnChip devices
-+ *
-+ * $Id: diskonchip.c,v 1.49 2005/02/22 21:48:21 gleixner Exp $
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/delay.h>
-+#include <linux/rslib.h>
-+#include <linux/moduleparam.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_NAND_DISKONCHIP_PROBE_ADDRESS
-+#define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0
-+#endif
-+
-+static unsigned long __initdata doc_locations[] = {
-+#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
-+#ifdef CONFIG_MTD_NAND_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 {
-+ void __iomem *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_param(debug, int, 0);
-+
-+static int try_dword=1;
-+module_param(try_dword, int, 0);
-+
-+static int no_ecc_failures=0;
-+module_param(no_ecc_failures, int, 0);
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+static int no_autopart=0;
-+module_param(no_autopart, int, 0);
-+#endif
-+
-+#ifdef MTD_NAND_DISKONCHIP_BBTWRITE
-+static int inftl_bbt_write=1;
-+#else
-+static int inftl_bbt_write=0;
-+#endif
-+module_param(inftl_bbt_write, int, 0);
-+
-+static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;
-+module_param(doc_config_location, ulong, 0);
-+MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
-+
-+
-+/* Sector size for HW ECC */
-+#define SECTOR_SIZE 512
-+/* The sector bytes are packed into NB_DATA 10 bit words */
-+#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / 10)
-+/* Number of roots */
-+#define NROOTS 4
-+/* First consective root */
-+#define FCR 510
-+/* Number of symbols */
-+#define NN 1023
-+
-+/* the Reed Solomon control structure */
-+static struct rs_control *rs_decoder;
-+
-+/*
-+ * The HW decoder in the DoC ASIC's provides us a error syndrome,
-+ * which we must convert to a standard syndrom usable by the generic
-+ * Reed-Solomon library code.
-+ *
-+ * Fabrice Bellard figured this out in the old docecc code. I added
-+ * some comments, improved a minor bit and converted it to make use
-+ * of the generic Reed-Solomon libary. tglx
-+ */
-+static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
-+{
-+ int i, j, nerr, errpos[8];
-+ uint8_t parity;
-+ uint16_t ds[4], s[5], tmp, errval[8], syn[4];
-+
-+ /* Convert the ecc bytes into words */
-+ ds[0] = ((ecc[4] & 0xff) >> 0) | ((ecc[5] & 0x03) << 8);
-+ ds[1] = ((ecc[5] & 0xfc) >> 2) | ((ecc[2] & 0x0f) << 6);
-+ ds[2] = ((ecc[2] & 0xf0) >> 4) | ((ecc[3] & 0x3f) << 4);
-+ ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2);
-+ parity = ecc[1];
-+
-+ /* Initialize the syndrom buffer */
-+ for (i = 0; i < NROOTS; i++)
-+ s[i] = ds[0];
-+ /*
-+ * Evaluate
-+ * s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0]
-+ * where x = alpha^(FCR + i)
-+ */
-+ for(j = 1; j < NROOTS; j++) {
-+ if(ds[j] == 0)
-+ continue;
-+ tmp = rs->index_of[ds[j]];
-+ for(i = 0; i < NROOTS; i++)
-+ s[i] ^= rs->alpha_to[rs_modnn(rs, tmp + (FCR + i) * j)];
-+ }
-+
-+ /* Calc s[i] = s[i] / alpha^(v + i) */
-+ for (i = 0; i < NROOTS; i++) {
-+ if (syn[i])
-+ syn[i] = rs_modnn(rs, rs->index_of[s[i]] + (NN - FCR - i));
-+ }
-+ /* Call the decoder library */
-+ nerr = decode_rs16(rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval);
-+
-+ /* Incorrectable errors ? */
-+ if (nerr < 0)
-+ return nerr;
-+
-+ /*
-+ * Correct the errors. The bitpositions are a bit of magic,
-+ * but they are given by the design of the de/encoder circuit
-+ * in the DoC ASIC's.
-+ */
-+ for(i = 0;i < nerr; i++) {
-+ int index, bitpos, pos = 1015 - errpos[i];
-+ uint8_t val;
-+ if (pos >= NB_DATA && pos < 1019)
-+ continue;
-+ if (pos < NB_DATA) {
-+ /* extract bit position (MSB first) */
-+ pos = 10 * (NB_DATA - 1 - pos) - 6;
-+ /* now correct the following 10 bits. At most two bytes
-+ can be modified since pos is even */
-+ index = (pos >> 3) ^ 1;
-+ bitpos = pos & 7;
-+ if ((index >= 0 && index < SECTOR_SIZE) ||
-+ index == (SECTOR_SIZE + 1)) {
-+ val = (uint8_t) (errval[i] >> (2 + bitpos));
-+ parity ^= val;
-+ if (index < SECTOR_SIZE)
-+ data[index] ^= val;
-+ }
-+ index = ((pos >> 3) + 1) ^ 1;
-+ bitpos = (bitpos + 10) & 7;
-+ if (bitpos == 0)
-+ bitpos = 8;
-+ if ((index >= 0 && index < SECTOR_SIZE) ||
-+ index == (SECTOR_SIZE + 1)) {
-+ val = (uint8_t)(errval[i] << (8 - bitpos));
-+ parity ^= val;
-+ if (index < SECTOR_SIZE)
-+ data[index] ^= val;
-+ }
-+ }
-+ }
-+ /* If the parity is wrong, no rescue possible */
-+ return parity ? -1 : nerr;
-+}
-+
-+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)
-+{
-+ void __iomem *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)
-+{
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = 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);
-+
-+ /* We cant' use dev_ready here, but at least we wait for the
-+ * command to complete
-+ */
-+ udelay(50);
-+
-+ 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;
-+ void __iomem *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);
-+
-+ udelay(50);
-+
-+ 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 = 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 = 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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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 = this->priv;
-+ void __iomem *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_ecc_decode (rs_decoder, 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 = 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 = 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;
-+
-+ mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits);
-+ mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN);
-+ mh->FormattedSize = le32_to_cpu(mh->FormattedSize);
-+
-+ 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);
-+
-+ 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 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 = 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);
-+
-+ 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);
-+
-+ 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);
-+
-+ 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);
-+
-+#if 0
-+ 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;
-+ }
-+#endif
-+
-+ 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 = 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 = 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 = 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 = 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 = 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;
-+ void __iomem *virtadr;
-+ unsigned char save_control;
-+ unsigned char tmp, tmpb, tmpc;
-+ int reg, len, numchips;
-+ int ret = 0;
-+
-+ virtadr = 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 = 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 = nand;
-+ mtd->owner = THIS_MODULE;
-+
-+ nand->priv = 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->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(virtadr);
-+ return ret;
-+}
-+
-+static void release_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 = nand->priv;
-+
-+ nextmtd = doc->nextdoc;
-+ nand_release(mtd);
-+ iounmap(doc->virtadr);
-+ kfree(mtd);
-+ }
-+}
-+
-+static int __init init_nanddoc(void)
-+{
-+ int i, ret = 0;
-+
-+ /* We could create the decoder on demand, if memory is a concern.
-+ * This way we have it handy, if an error happens
-+ *
-+ * Symbolsize is 10 (bits)
-+ * Primitve polynomial is x^10+x^3+1
-+ * first consecutive root is 510
-+ * primitve element to generate roots = 1
-+ * generator polinomial degree = 4
-+ */
-+ rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS);
-+ if (!rs_decoder) {
-+ printk (KERN_ERR "DiskOnChip: Could not create a RS decoder\n");
-+ return -ENOMEM;
-+ }
-+
-+ if (doc_config_location) {
-+ printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
-+ ret = doc_probe(doc_config_location);
-+ if (ret < 0)
-+ goto outerr;
-+ } 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");
-+ ret = -ENODEV;
-+ goto outerr;
-+ }
-+ return 0;
-+outerr:
-+ free_rs(rs_decoder);
-+ return ret;
-+}
-+
-+static void __exit cleanup_nanddoc(void)
-+{
-+ /* Cleanup the nand/DoC resources */
-+ release_nanddoc();
-+
-+ /* Free the reed solomon resources */
-+ if (rs_decoder) {
-+ free_rs(rs_decoder);
-+ }
-+}
-+
-+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");
---- linux-2.4.21/drivers/mtd/nand/edb7312.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/nand/edb7312.c
-@@ -6,7 +6,7 @@
- * Derived from drivers/mtd/nand/autcpu12.c
- * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
- *
-- * $Id: edb7312.c,v 1.3 2002/06/06 12:58:16 mag Exp $
-+ * $Id: edb7312.c,v 1.11 2004/11/04 12:53:10 gleixner 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
-@@ -20,6 +20,7 @@
-
- #include <linux/slab.h>
- #include <linux/module.h>
-+#include <linux/init.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
- #include <linux/mtd/partitions.h>
-@@ -52,41 +53,28 @@
- * Module stuff
- */
-
--static int ep7312_fio_pbase = EP7312_FIO_PBASE;
--static int ep7312_pxdr = EP7312_PXDR;
--static int ep7312_pxddr = EP7312_PXDDR;
--
--#ifdef MODULE
--MODULE_PARM(ep7312_fio_pbase, "i");
--MODULE_PARM(ep7312_pxdr, "i");
--MODULE_PARM(ep7312_pxddr, "i");
--
--__setup("ep7312_fio_pbase=",ep7312_fio_pbase);
--__setup("ep7312_pxdr=",ep7312_pxdr);
--__setup("ep7312_pxddr=",ep7312_pxddr);
--#endif
-+static unsigned long ep7312_fio_pbase = EP7312_FIO_PBASE;
-+static void __iomem * ep7312_pxdr = (void __iomem *) EP7312_PXDR;
-+static void __iomem * ep7312_pxddr = (void __iomem *) EP7312_PXDDR;
-
- #ifdef CONFIG_MTD_PARTITIONS
- /*
- * Define static partitions for flash device
- */
- static struct mtd_partition partition_info[] = {
-- { name: "EP7312 Nand Flash",
-- offset: 0,
-- size: 8*1024*1024 }
-+ { .name = "EP7312 Nand Flash",
-+ .offset = 0,
-+ .size = 8*1024*1024 }
- };
- #define NUM_PARTITIONS 1
-
--extern int parse_cmdline_partitions(struct mtd_info *master,
-- struct mtd_partition **pparts,
-- const char *mtd_id);
- #endif
-
-
- /*
- * hardware specific access to control-lines
- */
--static void ep7312_hwcontrol(int cmd)
-+static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd)
- {
- switch(cmd) {
-
-@@ -116,10 +104,13 @@
- /*
- * read device ready pin
- */
--static int ep7312_device_ready(void)
-+static int ep7312_device_ready(struct mtd_info *mtd)
- {
- return 1;
- }
-+#ifdef CONFIG_MTD_PARTITIONS
-+const char *part_probes[] = { "cmdlinepart", NULL };
-+#endif
-
- /*
- * Main initialization routine
-@@ -130,7 +121,7 @@
- const char *part_type = 0;
- int mtd_parts_nb = 0;
- struct mtd_partition *mtd_parts = 0;
-- int ep7312_fio_base;
-+ void __iomem * ep7312_fio_base;
-
- /* Allocate memory for MTD device structure and private data */
- ep7312_mtd = kmalloc(sizeof(struct mtd_info) +
-@@ -142,7 +133,7 @@
- }
-
- /* map physical adress */
-- ep7312_fio_base = (unsigned long)ioremap(ep7312_fio_pbase, SZ_1K);
-+ ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K);
- if(!ep7312_fio_base) {
- printk("ioremap EDB7312 NAND flash failed\n");
- kfree(ep7312_mtd);
-@@ -174,42 +165,22 @@
- this->chip_delay = 15;
-
- /* Scan to find existence of the device */
-- if (nand_scan (ep7312_mtd)) {
-+ if (nand_scan (ep7312_mtd, 1)) {
- iounmap((void *)ep7312_fio_base);
- kfree (ep7312_mtd);
- return -ENXIO;
- }
-
-- /* Allocate memory for internal data buffer */
-- this->data_buf = kmalloc (sizeof(u_char) * (ep7312_mtd->oobblock + ep7312_mtd->oobsize), GFP_KERNEL);
-- if (!this->data_buf) {
-- printk("Unable to allocate NAND data buffer for EDB7312.\n");
-- iounmap((void *)ep7312_fio_base);
-- kfree (ep7312_mtd);
-- return -ENOMEM;
-- }
--
-- /* Allocate memory for internal data buffer */
-- this->data_cache = kmalloc (sizeof(u_char) * (ep7312_mtd->oobblock + ep7312_mtd->oobsize), GFP_KERNEL);
-- if (!this->data_cache) {
-- printk("Unable to allocate NAND data cache for EDB7312.\n");
-- kfree (this->data_buf);
-- iounmap((void *)ep7312_fio_base);
-- kfree (ep7312_mtd);
-- return -ENOMEM;
-- }
-- this->cache_page = -1;
--
--#ifdef CONFIG_MTD_CMDLINE_PARTS
-- mtd_parts_nb = parse_cmdline_partitions(ep7312_mtd, &mtd_parts,
-- "edb7312-nand");
-+#ifdef CONFIG_MTD_PARTITIONS
-+ ep7312_mtd->name = "edb7312-nand";
-+ mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes,
-+ &mtd_parts, 0);
- if (mtd_parts_nb > 0)
- part_type = "command line";
- else
- mtd_parts_nb = 0;
- #endif
-- if (mtd_parts_nb == 0)
-- {
-+ if (mtd_parts_nb == 0) {
- mtd_parts = partition_info;
- mtd_parts_nb = NUM_PARTITIONS;
- part_type = "static";
-@@ -231,12 +202,11 @@
- {
- struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1];
-
-- /* Unregister the device */
-- del_mtd_device (ep7312_mtd);
-+ /* Release resources, unregister device */
-+ nand_release (ap7312_mtd);
-
- /* Free internal data buffer */
- kfree (this->data_buf);
-- kfree (this->data_cache);
-
- /* Free the MTD device structure */
- kfree (ep7312_mtd);
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/nand/h1910.c
-@@ -0,0 +1,208 @@
-+/*
-+ * drivers/mtd/nand/h1910.c
-+ *
-+ * Copyright (C) 2003 Joshua Wise (joshua@joshuawise.com)
-+ *
-+ * Derived from drivers/mtd/nand/edb7312.c
-+ * Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
-+ * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
-+ *
-+ * $Id: h1910.c,v 1.5 2004/11/04 12:53:10 gleixner 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.
-+ *
-+ * Overview:
-+ * This is a device driver for the NAND flash device found on the
-+ * iPAQ h1910 board which utilizes the Samsung K9F2808 part. This is
-+ * a 128Mibit (16MiB x 8 bits) NAND flash device.
-+ */
-+
-+#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 <asm/io.h>
-+#include <asm/arch/hardware.h> /* for CLPS7111_VIRT_BASE */
-+#include <asm/sizes.h>
-+#include <asm/arch/h1900-gpio.h>
-+#include <asm/arch/ipaq.h>
-+
-+/*
-+ * MTD structure for EDB7312 board
-+ */
-+static struct mtd_info *h1910_nand_mtd = NULL;
-+
-+/*
-+ * Module stuff
-+ */
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+/*
-+ * Define static partitions for flash device
-+ */
-+static struct mtd_partition partition_info[] = {
-+ { name: "h1910 NAND Flash",
-+ offset: 0,
-+ size: 16*1024*1024 }
-+};
-+#define NUM_PARTITIONS 1
-+
-+#endif
-+
-+
-+/*
-+ * hardware specific access to control-lines
-+ */
-+static void h1910_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+ struct nand_chip* this = (struct nand_chip *) (mtd->priv);
-+
-+ switch(cmd) {
-+
-+ case NAND_CTL_SETCLE:
-+ this->IO_ADDR_R |= (1 << 2);
-+ this->IO_ADDR_W |= (1 << 2);
-+ break;
-+ case NAND_CTL_CLRCLE:
-+ this->IO_ADDR_R &= ~(1 << 2);
-+ this->IO_ADDR_W &= ~(1 << 2);
-+ break;
-+
-+ case NAND_CTL_SETALE:
-+ this->IO_ADDR_R |= (1 << 3);
-+ this->IO_ADDR_W |= (1 << 3);
-+ break;
-+ case NAND_CTL_CLRALE:
-+ this->IO_ADDR_R &= ~(1 << 3);
-+ this->IO_ADDR_W &= ~(1 << 3);
-+ break;
-+
-+ case NAND_CTL_SETNCE:
-+ break;
-+ case NAND_CTL_CLRNCE:
-+ break;
-+ }
-+}
-+
-+/*
-+ * read device ready pin
-+ */
-+#if 0
-+static int h1910_device_ready(struct mtd_info *mtd)
-+{
-+ return (GPLR(55) & GPIO_bit(55));
-+}
-+#endif
-+
-+/*
-+ * Main initialization routine
-+ */
-+static int __init h1910_init (void)
-+{
-+ struct nand_chip *this;
-+ const char *part_type = 0;
-+ int mtd_parts_nb = 0;
-+ struct mtd_partition *mtd_parts = 0;
-+ void __iomem *nandaddr;
-+
-+ if (!machine_is_h1900())
-+ return -ENODEV;
-+
-+ nandaddr = __ioremap(0x08000000, 0x1000, 0, 1);
-+ if (!nandaddr) {
-+ printk("Failed to ioremap nand flash.\n");
-+ return -ENOMEM;
-+ }
-+
-+ /* Allocate memory for MTD device structure and private data */
-+ h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) +
-+ sizeof(struct nand_chip),
-+ GFP_KERNEL);
-+ if (!h1910_nand_mtd) {
-+ printk("Unable to allocate h1910 NAND MTD device structure.\n");
-+ iounmap ((void *) nandaddr);
-+ return -ENOMEM;
-+ }
-+
-+ /* Get pointer to private data */
-+ this = (struct nand_chip *) (&h1910_nand_mtd[1]);
-+
-+ /* Initialize structures */
-+ memset((char *) h1910_nand_mtd, 0, sizeof(struct mtd_info));
-+ memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+ /* Link the private data with the MTD structure */
-+ h1910_nand_mtd->priv = this;
-+
-+ /*
-+ * Enable VPEN
-+ */
-+ GPSR(37) = GPIO_bit(37);
-+
-+ /* insert callbacks */
-+ this->IO_ADDR_R = nandaddr;
-+ this->IO_ADDR_W = nandaddr;
-+ this->hwcontrol = h1910_hwcontrol;
-+ this->dev_ready = NULL; /* unknown whether that was correct or not so we will just do it like this */
-+ /* 15 us command delay time */
-+ this->chip_delay = 50;
-+ this->eccmode = NAND_ECC_SOFT;
-+ this->options = NAND_NO_AUTOINCR;
-+
-+ /* Scan to find existence of the device */
-+ if (nand_scan (h1910_nand_mtd, 1)) {
-+ printk(KERN_NOTICE "No NAND device - returning -ENXIO\n");
-+ kfree (h1910_nand_mtd);
-+ iounmap ((void *) nandaddr);
-+ return -ENXIO;
-+ }
-+
-+#ifdef CONFIG_MTD_CMDLINE_PARTS
-+ mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts,
-+ "h1910-nand");
-+ if (mtd_parts_nb > 0)
-+ part_type = "command line";
-+ else
-+ mtd_parts_nb = 0;
-+#endif
-+ if (mtd_parts_nb == 0)
-+ {
-+ mtd_parts = partition_info;
-+ mtd_parts_nb = NUM_PARTITIONS;
-+ part_type = "static";
-+ }
-+
-+ /* Register the partitions */
-+ printk(KERN_NOTICE "Using %s partition definition\n", part_type);
-+ add_mtd_partitions(h1910_nand_mtd, mtd_parts, mtd_parts_nb);
-+
-+ /* Return happy */
-+ return 0;
-+}
-+module_init(h1910_init);
-+
-+/*
-+ * Clean up routine
-+ */
-+static void __exit h1910_cleanup (void)
-+{
-+ struct nand_chip *this = (struct nand_chip *) &h1910_nand_mtd[1];
-+
-+ /* Release resources, unregister device */
-+ nand_release (h1910_nand_mtd);
-+
-+ /* Release io resource */
-+ iounmap ((void *) this->IO_ADDR_W);
-+
-+ /* Free the MTD device structure */
-+ kfree (h1910_nand_mtd);
-+}
-+module_exit(h1910_cleanup);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Joshua Wise <joshua at joshuawise dot com>");
-+MODULE_DESCRIPTION("NAND flash driver for iPAQ h1910");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/nand/nand_base.c
-@@ -0,0 +1,2691 @@
-+/*
-+ * 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
-+ *
-+ * 09-24-2004 tglx: add support for hardware controllers (e.g. ECC) shared
-+ * among multiple independend devices. Suggestions and initial patch
-+ * from Ben Dooks <ben-mtd@fluff.org>
-+ *
-+ * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue.
-+ * Basically, any block not rewritten may lose data when surrounding blocks
-+ * are rewritten many times. JFFS2 ensures this doesn't happen for blocks
-+ * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they
-+ * do not lose data, force them to be rewritten when some of the surrounding
-+ * blocks are erased. Rather than tracking a specific nearby block (which
-+ * could itself go bad), use a page address 'mask' to select several blocks
-+ * in the same area, and rewrite the BBT when any of them are erased.
-+ *
-+ * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas
-+ * AG-AND chips. If there was a sudden loss of power during an erase operation,
-+ * a "device recovery" operation must be performed when power is restored
-+ * to ensure correct operation.
-+ *
-+ * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to
-+ * perform extra error status checks on erase and write failures. This required
-+ * adding a wrapper function for nand_read_ecc.
-+ *
-+ * 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.135 2005/03/01 09:32:45 gleixner 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_device (struct nand_chip *this, struct mtd_info *mtd, int new_state);
-+
-+/**
-+ * nand_release_device - [GENERIC] release chip
-+ * @mtd: MTD device structure
-+ *
-+ * Deselect, release chip lock and wake up anyone waiting on the device
-+ */
-+static void nand_release_device (struct mtd_info *mtd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+
-+ /* De-select the NAND device */
-+ this->select_chip(mtd, -1);
-+ /* Do we have a hardware controller ? */
-+ if (this->controller) {
-+ spin_lock(&this->controller->lock);
-+ this->controller->active = NULL;
-+ spin_unlock(&this->controller->lock);
-+ }
-+ /* Release the chip */
-+ spin_lock (&this->chip_lock);
-+ this->state = FL_READY;
-+ wake_up (&this->wq);
-+ spin_unlock (&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_device (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_device(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;
-+ if (this->bbt)
-+ 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) & NAND_STATUS_WP) ? 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);
-+}
-+
-+/*
-+ * Wait for the ready pin, after a command
-+ * The timeout is catched later.
-+ */
-+static void nand_wait_ready(struct mtd_info *mtd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ unsigned long timeo = jiffies + 2;
-+
-+ /* wait until command is processed or timeout occures */
-+ do {
-+ if (this->dev_ready(mtd))
-+ return;
-+ } while (time_before(jiffies, timeo));
-+}
-+
-+/**
-+ * 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 devices > 32MiB */
-+ if (this->chipsize > (32 << 20))
-+ 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) & NAND_STATUS_READY));
-+ 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);
-+
-+ nand_wait_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 & 0xff));
-+ /* 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, sequential in, and deplete1 need 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:
-+ case NAND_CMD_DEPLETE1:
-+ return;
-+
-+ /*
-+ * read error status commands require only a short delay
-+ */
-+ case NAND_CMD_STATUS_ERROR:
-+ case NAND_CMD_STATUS_ERROR0:
-+ case NAND_CMD_STATUS_ERROR1:
-+ case NAND_CMD_STATUS_ERROR2:
-+ case NAND_CMD_STATUS_ERROR3:
-+ udelay(this->chip_delay);
-+ 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) & NAND_STATUS_READY));
-+ 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);
-+
-+ nand_wait_ready(mtd);
-+}
-+
-+/**
-+ * nand_get_device - [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_device (struct nand_chip *this, struct mtd_info *mtd, int new_state)
-+{
-+ struct nand_chip *active = this;
-+
-+ DECLARE_WAITQUEUE (wait, current);
-+
-+ /*
-+ * Grab the lock and see if the device is available
-+ */
-+retry:
-+ /* Hardware controller shared among independend devices */
-+ if (this->controller) {
-+ spin_lock (&this->controller->lock);
-+ if (this->controller->active)
-+ active = this->controller->active;
-+ else
-+ this->controller->active = this;
-+ spin_unlock (&this->controller->lock);
-+ }
-+
-+ if (active == this) {
-+ spin_lock (&this->chip_lock);
-+ if (this->state == FL_READY) {
-+ this->state = new_state;
-+ spin_unlock (&this->chip_lock);
-+ return;
-+ }
-+ }
-+ set_current_state (TASK_UNINTERRUPTIBLE);
-+ add_wait_queue (&active->wq, &wait);
-+ spin_unlock (&active->chip_lock);
-+ schedule ();
-+ remove_wait_queue (&active->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);
-+
-+ 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)
-+ return 0;
-+
-+ if (this->dev_ready) {
-+ if (this->dev_ready(mtd))
-+ break;
-+ } else {
-+ if (this->read_byte(mtd) & NAND_STATUS_READY)
-+ break;
-+ }
-+ cond_resched();
-+ }
-+ status = (int) this->read_byte(mtd);
-+ 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[32];
-+ 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;
-+ default:
-+ eccbytes = this->eccbytes;
-+ 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;
-+ }
-+
-+ /* 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 operation failed and additional status checks are available */
-+ if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
-+ status = this->errstat(mtd, this, FL_WRITING, status, page);
-+ }
-+
-+ /* See if device thinks it succeeded */
-+ if (status & NAND_STATUS_FAIL) {
-+ 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
-+ nand_wait_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_do_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_do_read_ecc with oob buffer and oobsel = NULL
-+ * and flags = 0xff
-+ */
-+static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
-+{
-+ return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, NULL, 0xff);
-+}
-+
-+
-+/**
-+ * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_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
-+ * @oob_buf: filesystem supplied oob data buffer
-+ * @oobsel: oob selection structure
-+ *
-+ * This function simply calls nand_do_read_ecc with flags = 0xff
-+ */
-+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)
-+{
-+ return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
-+}
-+
-+
-+/**
-+ * nand_do_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
-+ * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
-+ * and how many corrected error bits are acceptable:
-+ * bits 0..7 - number of tolerable errors
-+ * bit 8 - 0 == do not get/release chip, 1 == get/release chip
-+ *
-+ * NAND read with ECC
-+ */
-+int nand_do_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 flags)
-+{
-+ 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;
-+ 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 */
-+ if (flags & NAND_GET_DEVICE)
-+ nand_get_device (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;
-+ eccbytes = this->eccbytes;
-+
-+ if ((eccmode == NAND_ECC_NONE) || (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;
-+
-+ default:
-+ 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 */
-+ ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
-+ if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
-+ 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;
-+ }
-+
-+ /* 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) || (ecc_status > (flags && 0xff))) {
-+ 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
-+ nand_wait_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 */
-+ if (flags & NAND_GET_DEVICE)
-+ nand_release_device(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_device (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
-+ nand_wait_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_device(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_device (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
-+ nand_wait_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_device(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_device (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_device(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_device (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 & NAND_STATUS_FAIL) {
-+ 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_device(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_device (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_device(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);
-+}
-+
-+#define BBT_PAGE_MASK 0xffffff3f
-+/**
-+ * 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;
-+ int rewrite_bbt[NAND_MAX_CHIPS]={0}; /* flags to indicate the page, if bbt needs to be rewritten. */
-+ unsigned int bbt_masked_page; /* bbt mask to compare to page being erased. */
-+ /* It is used to see if the current page is in the same */
-+ /* 256 block group and the same bank as the bbt. */
-+
-+ 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_device (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;
-+ }
-+
-+ /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */
-+ if (this->options & BBT_AUTO_REFRESH) {
-+ bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
-+ } else {
-+ bbt_masked_page = 0xffffffff; /* should not match anything */
-+ }
-+
-+ /* 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 operation failed and additional status checks are available */
-+ if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
-+ status = this->errstat(mtd, this, FL_ERASING, status, page);
-+ }
-+
-+ /* See if block erase succeeded */
-+ if (status & NAND_STATUS_FAIL) {
-+ 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;
-+ }
-+
-+ /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */
-+ if (this->options & BBT_AUTO_REFRESH) {
-+ if (((page & BBT_PAGE_MASK) == bbt_masked_page) &&
-+ (page != this->bbt_td->pages[chipnr])) {
-+ rewrite_bbt[chipnr] = (page << this->page_shift);
-+ }
-+ }
-+
-+ /* 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);
-+
-+ /* if BBT requires refresh and BBT-PERCHIP,
-+ * set the BBT page mask to see if this BBT should be rewritten */
-+ if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) {
-+ bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
-+ }
-+
-+ }
-+ }
-+ 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_device(mtd);
-+
-+ /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */
-+ if ((this->options & BBT_AUTO_REFRESH) && (!ret)) {
-+ for (chipnr = 0; chipnr < this->numchips; chipnr++) {
-+ if (rewrite_bbt[chipnr]) {
-+ /* update the BBT for chip */
-+ DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n",
-+ chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]);
-+ nand_update_bbt (mtd, rewrite_bbt[chipnr]);
-+ }
-+ }
-+ }
-+
-+ /* 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;
-+
-+ DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");
-+
-+ /* Grab the lock and see if the device is available */
-+ nand_get_device (this, mtd, FL_SYNCING);
-+ /* Release it and go back */
-+ nand_release_device (mtd);
-+}
-+
-+
-+/**
-+ * 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, maf_id;
-+ 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;
-+ }
-+
-+ /* Try to identify manufacturer */
-+ for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) {
-+ if (nand_manuf_ids[maf_id].id == nand_maf_id)
-+ break;
-+ }
-+
-+ /* 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[maf_id].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;
-+
-+ 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[maf_id].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 */
-+ this->eccbytes = 3;
-+
-+ switch (this->eccmode) {
-+ case NAND_ECC_HW12_2048:
-+ if (mtd->oobblock < 2048) {
-+ printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
-+ mtd->oobblock);
-+ this->eccmode = NAND_ECC_SOFT;
-+ this->calculate_ecc = nand_calculate_ecc;
-+ this->correct_data = nand_correct_data;
-+ } else
-+ this->eccsize = 2048;
-+ break;
-+
-+ 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;
-+ } else
-+ this->eccsize = 512; /* set eccsize to 512 */
-+ break;
-+
-+ case NAND_ECC_HW3_256:
-+ break;
-+
-+ 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();
-+ }
-+
-+ /* Check hardware ecc function availability and adjust number of ecc bytes per
-+ * calculation step
-+ */
-+ switch (this->eccmode) {
-+ case NAND_ECC_HW12_2048:
-+ this->eccbytes += 4;
-+ case NAND_ECC_HW8_512:
-+ this->eccbytes += 2;
-+ case NAND_ECC_HW6_512:
-+ this->eccbytes += 3;
-+ case NAND_ECC_HW3_512:
-+ 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();
-+ }
-+
-+ mtd->eccsize = this->eccsize;
-+
-+ /* Set the number of read / write steps for one page to ensure ECC generation */
-+ switch (this->eccmode) {
-+ case NAND_ECC_HW12_2048:
-+ this->eccsteps = mtd->oobblock / 2048;
-+ break;
-+ 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;
-+
-+ /* Check, if we should skip the bad block table scan */
-+ if (this->options & NAND_SKIP_BBTSCAN)
-+ return 0;
-+
-+ /* 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");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/nand/nand_bbt.c
-@@ -0,0 +1,1081 @@
-+/*
-+ * drivers/mtd/nand_bbt.c
-+ *
-+ * Overview:
-+ * Bad block table support for the NAND driver
-+ *
-+ * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
-+ *
-+ * $Id: nand_bbt.c,v 1.31 2005/02/16 17:09:36 dedekind 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.
-+ *
-+ * Description:
-+ *
-+ * When nand_scan_bbt is called, then it tries to find the bad block table
-+ * depending on the options in the bbt descriptor(s). If a bbt is found
-+ * then the contents are read and the memory based bbt is created. If a
-+ * mirrored bbt is selected then the mirror is searched too and the
-+ * versions are compared. If the mirror has a greater version number
-+ * than the mirror bbt is used to build the memory based bbt.
-+ * If the tables are not versioned, then we "or" the bad block information.
-+ * If one of the bbt's is out of date or does not exist it is (re)created.
-+ * If no bbt exists at all then the device is scanned for factory marked
-+ * good / bad blocks and the bad block tables are created.
-+ *
-+ * For manufacturer created bbts like the one found on M-SYS DOC devices
-+ * the bbt is searched and read but never created
-+ *
-+ * The autogenerated bad block table is located in the last good blocks
-+ * of the device. The table is mirrored, so it can be updated eventually.
-+ * The table is marked in the oob area with an ident pattern and a version
-+ * number which indicates which of both tables is more up to date.
-+ *
-+ * The table uses 2 bits per block
-+ * 11b: block is good
-+ * 00b: block is factory marked bad
-+ * 01b, 10b: block is marked bad due to wear
-+ *
-+ * The memory bad block table uses the following scheme:
-+ * 00b: block is good
-+ * 01b: block is marked bad due to wear
-+ * 10b: block is reserved (to protect the bbt area)
-+ * 11b: block is factory marked bad
-+ *
-+ * Multichip devices like DOC store the bad block info per floor.
-+ *
-+ * Following assumptions are made:
-+ * - bbts start at a page boundary, if autolocated on a block boundary
-+ * - the space neccecary for a bbt in FLASH does not exceed a block boundary
-+ *
-+ */
-+
-+#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/bitops.h>
-+#include <linux/delay.h>
-+
-+
-+/**
-+ * check_pattern - [GENERIC] check if a pattern is in the buffer
-+ * @buf: the buffer to search
-+ * @len: the length of buffer to search
-+ * @paglen: the pagelength
-+ * @td: search pattern descriptor
-+ *
-+ * Check for a pattern at the given place. Used to search bad block
-+ * tables and good / bad block identifiers.
-+ * If the SCAN_EMPTY option is set then check, if all bytes except the
-+ * pattern area contain 0xff
-+ *
-+*/
-+static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
-+{
-+ int i, end = 0;
-+ uint8_t *p = buf;
-+
-+ if (td->options & NAND_BBT_SCANEMPTY) {
-+ end = paglen + td->offs;
-+ for (i = 0; i < end; i++) {
-+ if (p[i] != 0xff)
-+ return -1;
-+ }
-+ p += end;
-+ }
-+
-+ /* Compare the pattern */
-+ for (i = 0; i < td->len; i++) {
-+ if (p[i] != td->pattern[i])
-+ return -1;
-+ }
-+
-+ if (td->options & NAND_BBT_SCANEMPTY) {
-+ p += td->len;
-+ end += td->len;
-+ for (i = end; i < len; i++) {
-+ if (*p++ != 0xff)
-+ return -1;
-+ }
-+ }
-+ return 0;
-+}
-+
-+/**
-+ * read_bbt - [GENERIC] Read the bad block table starting from page
-+ * @mtd: MTD device structure
-+ * @buf: temporary buffer
-+ * @page: the starting page
-+ * @num: the number of bbt descriptors to read
-+ * @bits: number of bits per block
-+ * @offs: offset in the memory table
-+ * @reserved_block_code: Pattern to identify reserved blocks
-+ *
-+ * Read the bad block table starting from page.
-+ *
-+ */
-+static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
-+ int bits, int offs, int reserved_block_code)
-+{
-+ int res, i, j, act = 0;
-+ struct nand_chip *this = mtd->priv;
-+ size_t retlen, len, totlen;
-+ loff_t from;
-+ uint8_t msk = (uint8_t) ((1 << bits) - 1);
-+
-+ totlen = (num * bits) >> 3;
-+ from = ((loff_t)page) << this->page_shift;
-+
-+ while (totlen) {
-+ len = min (totlen, (size_t) (1 << this->bbt_erase_shift));
-+ res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob);
-+ if (res < 0) {
-+ if (retlen != len) {
-+ printk (KERN_INFO "nand_bbt: Error reading bad block table\n");
-+ return res;
-+ }
-+ printk (KERN_WARNING "nand_bbt: ECC error while reading bad block table\n");
-+ }
-+
-+ /* Analyse data */
-+ for (i = 0; i < len; i++) {
-+ uint8_t dat = buf[i];
-+ for (j = 0; j < 8; j += bits, act += 2) {
-+ uint8_t tmp = (dat >> j) & msk;
-+ if (tmp == msk)
-+ continue;
-+ if (reserved_block_code &&
-+ (tmp == reserved_block_code)) {
-+ printk (KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n",
-+ ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
-+ this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
-+ continue;
-+ }
-+ /* Leave it for now, if its matured we can move this
-+ * message to MTD_DEBUG_LEVEL0 */
-+ printk (KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n",
-+ ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
-+ /* Factory marked bad or worn out ? */
-+ if (tmp == 0)
-+ this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
-+ else
-+ this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);
-+ }
-+ }
-+ totlen -= len;
-+ from += len;
-+ }
-+ return 0;
-+}
-+
-+/**
-+ * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
-+ * @mtd: MTD device structure
-+ * @buf: temporary buffer
-+ * @td: descriptor for the bad block table
-+ * @chip: read the table for a specific chip, -1 read all chips.
-+ * Applies only if NAND_BBT_PERCHIP option is set
-+ *
-+ * Read the bad block table for all chips starting at a given page
-+ * We assume that the bbt bits are in consecutive order.
-+*/
-+static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ int res = 0, i;
-+ int bits;
-+
-+ bits = td->options & NAND_BBT_NRBITS_MSK;
-+ if (td->options & NAND_BBT_PERCHIP) {
-+ int offs = 0;
-+ for (i = 0; i < this->numchips; i++) {
-+ if (chip == -1 || chip == i)
-+ res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code);
-+ if (res)
-+ return res;
-+ offs += this->chipsize >> (this->bbt_erase_shift + 2);
-+ }
-+ } else {
-+ res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code);
-+ if (res)
-+ return res;
-+ }
-+ return 0;
-+}
-+
-+/**
-+ * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
-+ * @mtd: MTD device structure
-+ * @buf: temporary buffer
-+ * @td: descriptor for the bad block table
-+ * @md: descriptor for the bad block table mirror
-+ *
-+ * Read the bad block table(s) for all chips starting at a given page
-+ * We assume that the bbt bits are in consecutive order.
-+ *
-+*/
-+static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td,
-+ struct nand_bbt_descr *md)
-+{
-+ struct nand_chip *this = mtd->priv;
-+
-+ /* Read the primary version, if available */
-+ if (td->options & NAND_BBT_VERSION) {
-+ nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize);
-+ td->version[0] = buf[mtd->oobblock + td->veroffs];
-+ printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]);
-+ }
-+
-+ /* Read the mirror version, if available */
-+ if (md && (md->options & NAND_BBT_VERSION)) {
-+ nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize);
-+ md->version[0] = buf[mtd->oobblock + md->veroffs];
-+ printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]);
-+ }
-+
-+ return 1;
-+}
-+
-+/**
-+ * create_bbt - [GENERIC] Create a bad block table by scanning the device
-+ * @mtd: MTD device structure
-+ * @buf: temporary buffer
-+ * @bd: descriptor for the good/bad block search pattern
-+ * @chip: create the table for a specific chip, -1 read all chips.
-+ * Applies only if NAND_BBT_PERCHIP option is set
-+ *
-+ * Create a bad block table by scanning the device
-+ * for the given good/bad block identify pattern
-+ */
-+static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ int i, j, numblocks, len, scanlen;
-+ int startblock;
-+ loff_t from;
-+ size_t readlen, ooblen;
-+
-+ printk (KERN_INFO "Scanning device for bad blocks\n");
-+
-+ if (bd->options & NAND_BBT_SCANALLPAGES)
-+ len = 1 << (this->bbt_erase_shift - this->page_shift);
-+ else {
-+ if (bd->options & NAND_BBT_SCAN2NDPAGE)
-+ len = 2;
-+ else
-+ len = 1;
-+ }
-+
-+ if (!(bd->options & NAND_BBT_SCANEMPTY)) {
-+ /* We need only read few bytes from the OOB area */
-+ scanlen = ooblen = 0;
-+ readlen = bd->len;
-+ } else {
-+ /* Full page content should be read */
-+ scanlen = mtd->oobblock + mtd->oobsize;
-+ readlen = len * mtd->oobblock;
-+ ooblen = len * mtd->oobsize;
-+ }
-+
-+ if (chip == -1) {
-+ /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it
-+ * makes shifting and masking less painful */
-+ numblocks = mtd->size >> (this->bbt_erase_shift - 1);
-+ startblock = 0;
-+ from = 0;
-+ } else {
-+ if (chip >= this->numchips) {
-+ printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n",
-+ chip + 1, this->numchips);
-+ return -EINVAL;
-+ }
-+ numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
-+ startblock = chip * numblocks;
-+ numblocks += startblock;
-+ from = startblock << (this->bbt_erase_shift - 1);
-+ }
-+
-+ for (i = startblock; i < numblocks;) {
-+ int ret;
-+
-+ if (bd->options & NAND_BBT_SCANEMPTY)
-+ if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen)))
-+ return ret;
-+
-+ for (j = 0; j < len; j++) {
-+ if (!(bd->options & NAND_BBT_SCANEMPTY)) {
-+ size_t retlen;
-+
-+ /* No need to read pages fully, just read required OOB bytes */
-+ ret = mtd->read_oob(mtd, from + j * mtd->oobblock + bd->offs,
-+ readlen, &retlen, &buf[0]);
-+ if (ret)
-+ return ret;
-+ }
-+ if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
-+ this->bbt[i >> 3] |= 0x03 << (i & 0x6);
-+ printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
-+ i >> 1, (unsigned int) from);
-+ break;
-+ }
-+ }
-+ i += 2;
-+ from += (1 << this->bbt_erase_shift);
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+ * search_bbt - [GENERIC] scan the device for a specific bad block table
-+ * @mtd: MTD device structure
-+ * @buf: temporary buffer
-+ * @td: descriptor for the bad block table
-+ *
-+ * Read the bad block table by searching for a given ident pattern.
-+ * Search is preformed either from the beginning up or from the end of
-+ * the device downwards. The search starts always at the start of a
-+ * block.
-+ * If the option NAND_BBT_PERCHIP is given, each chip is searched
-+ * for a bbt, which contains the bad block information of this chip.
-+ * This is neccecary to provide support for certain DOC devices.
-+ *
-+ * The bbt ident pattern resides in the oob area of the first page
-+ * in a block.
-+ */
-+static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ int i, chips;
-+ int bits, startblock, block, dir;
-+ int scanlen = mtd->oobblock + mtd->oobsize;
-+ int bbtblocks;
-+
-+ /* Search direction top -> down ? */
-+ if (td->options & NAND_BBT_LASTBLOCK) {
-+ startblock = (mtd->size >> this->bbt_erase_shift) -1;
-+ dir = -1;
-+ } else {
-+ startblock = 0;
-+ dir = 1;
-+ }
-+
-+ /* Do we have a bbt per chip ? */
-+ if (td->options & NAND_BBT_PERCHIP) {
-+ chips = this->numchips;
-+ bbtblocks = this->chipsize >> this->bbt_erase_shift;
-+ startblock &= bbtblocks - 1;
-+ } else {
-+ chips = 1;
-+ bbtblocks = mtd->size >> this->bbt_erase_shift;
-+ }
-+
-+ /* Number of bits for each erase block in the bbt */
-+ bits = td->options & NAND_BBT_NRBITS_MSK;
-+
-+ for (i = 0; i < chips; i++) {
-+ /* Reset version information */
-+ td->version[i] = 0;
-+ td->pages[i] = -1;
-+ /* Scan the maximum number of blocks */
-+ for (block = 0; block < td->maxblocks; block++) {
-+ int actblock = startblock + dir * block;
-+ /* Read first page */
-+ nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize);
-+ if (!check_pattern(buf, scanlen, mtd->oobblock, td)) {
-+ td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift);
-+ if (td->options & NAND_BBT_VERSION) {
-+ td->version[i] = buf[mtd->oobblock + td->veroffs];
-+ }
-+ break;
-+ }
-+ }
-+ startblock += this->chipsize >> this->bbt_erase_shift;
-+ }
-+ /* Check, if we found a bbt for each requested chip */
-+ for (i = 0; i < chips; i++) {
-+ if (td->pages[i] == -1)
-+ printk (KERN_WARNING "Bad block table not found for chip %d\n", i);
-+ else
-+ printk (KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]);
-+ }
-+ return 0;
-+}
-+
-+/**
-+ * search_read_bbts - [GENERIC] scan the device for bad block table(s)
-+ * @mtd: MTD device structure
-+ * @buf: temporary buffer
-+ * @td: descriptor for the bad block table
-+ * @md: descriptor for the bad block table mirror
-+ *
-+ * Search and read the bad block table(s)
-+*/
-+static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf,
-+ struct nand_bbt_descr *td, struct nand_bbt_descr *md)
-+{
-+ /* Search the primary table */
-+ search_bbt (mtd, buf, td);
-+
-+ /* Search the mirror table */
-+ if (md)
-+ search_bbt (mtd, buf, md);
-+
-+ /* Force result check */
-+ return 1;
-+}
-+
-+
-+/**
-+ * write_bbt - [GENERIC] (Re)write the bad block table
-+ *
-+ * @mtd: MTD device structure
-+ * @buf: temporary buffer
-+ * @td: descriptor for the bad block table
-+ * @md: descriptor for the bad block table mirror
-+ * @chipsel: selector for a specific chip, -1 for all
-+ *
-+ * (Re)write the bad block table
-+ *
-+*/
-+static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
-+ struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct nand_oobinfo oobinfo;
-+ struct erase_info einfo;
-+ int i, j, res, chip = 0;
-+ int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
-+ int nrchips, bbtoffs, pageoffs;
-+ uint8_t msk[4];
-+ uint8_t rcode = td->reserved_block_code;
-+ size_t retlen, len = 0;
-+ loff_t to;
-+
-+ if (!rcode)
-+ rcode = 0xff;
-+ /* Write bad block table per chip rather than per device ? */
-+ if (td->options & NAND_BBT_PERCHIP) {
-+ numblocks = (int) (this->chipsize >> this->bbt_erase_shift);
-+ /* Full device write or specific chip ? */
-+ if (chipsel == -1) {
-+ nrchips = this->numchips;
-+ } else {
-+ nrchips = chipsel + 1;
-+ chip = chipsel;
-+ }
-+ } else {
-+ numblocks = (int) (mtd->size >> this->bbt_erase_shift);
-+ nrchips = 1;
-+ }
-+
-+ /* Loop through the chips */
-+ for (; chip < nrchips; chip++) {
-+
-+ /* There was already a version of the table, reuse the page
-+ * This applies for absolute placement too, as we have the
-+ * page nr. in td->pages.
-+ */
-+ if (td->pages[chip] != -1) {
-+ page = td->pages[chip];
-+ goto write;
-+ }
-+
-+ /* Automatic placement of the bad block table */
-+ /* Search direction top -> down ? */
-+ if (td->options & NAND_BBT_LASTBLOCK) {
-+ startblock = numblocks * (chip + 1) - 1;
-+ dir = -1;
-+ } else {
-+ startblock = chip * numblocks;
-+ dir = 1;
-+ }
-+
-+ for (i = 0; i < td->maxblocks; i++) {
-+ int block = startblock + dir * i;
-+ /* Check, if the block is bad */
-+ switch ((this->bbt[block >> 2] >> (2 * (block & 0x03))) & 0x03) {
-+ case 0x01:
-+ case 0x03:
-+ continue;
-+ }
-+ page = block << (this->bbt_erase_shift - this->page_shift);
-+ /* Check, if the block is used by the mirror table */
-+ if (!md || md->pages[chip] != page)
-+ goto write;
-+ }
-+ printk (KERN_ERR "No space left to write bad block table\n");
-+ return -ENOSPC;
-+write:
-+
-+ /* Set up shift count and masks for the flash table */
-+ bits = td->options & NAND_BBT_NRBITS_MSK;
-+ switch (bits) {
-+ case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x01; break;
-+ case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x03; break;
-+ case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; msk[2] = ~rcode; msk[3] = 0x0f; break;
-+ case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break;
-+ default: return -EINVAL;
-+ }
-+
-+ bbtoffs = chip * (numblocks >> 2);
-+
-+ to = ((loff_t) page) << this->page_shift;
-+
-+ memcpy (&oobinfo, this->autooob, sizeof(oobinfo));
-+ oobinfo.useecc = MTD_NANDECC_PLACEONLY;
-+
-+ /* Must we save the block contents ? */
-+ if (td->options & NAND_BBT_SAVECONTENT) {
-+ /* Make it block aligned */
-+ to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1));
-+ len = 1 << this->bbt_erase_shift;
-+ res = mtd->read_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
-+ if (res < 0) {
-+ if (retlen != len) {
-+ printk (KERN_INFO "nand_bbt: Error reading block for writing the bad block table\n");
-+ return res;
-+ }
-+ printk (KERN_WARNING "nand_bbt: ECC error while reading block for writing bad block table\n");
-+ }
-+ /* Calc the byte offset in the buffer */
-+ pageoffs = page - (int)(to >> this->page_shift);
-+ offs = pageoffs << this->page_shift;
-+ /* Preset the bbt area with 0xff */
-+ memset (&buf[offs], 0xff, (size_t)(numblocks >> sft));
-+ /* Preset the bbt's oob area with 0xff */
-+ memset (&buf[len + pageoffs * mtd->oobsize], 0xff,
-+ ((len >> this->page_shift) - pageoffs) * mtd->oobsize);
-+ if (td->options & NAND_BBT_VERSION) {
-+ buf[len + (pageoffs * mtd->oobsize) + td->veroffs] = td->version[chip];
-+ }
-+ } else {
-+ /* Calc length */
-+ len = (size_t) (numblocks >> sft);
-+ /* Make it page aligned ! */
-+ len = (len + (mtd->oobblock-1)) & ~(mtd->oobblock-1);
-+ /* Preset the buffer with 0xff */
-+ memset (buf, 0xff, len + (len >> this->page_shift) * mtd->oobsize);
-+ offs = 0;
-+ /* Pattern is located in oob area of first page */
-+ memcpy (&buf[len + td->offs], td->pattern, td->len);
-+ if (td->options & NAND_BBT_VERSION) {
-+ buf[len + td->veroffs] = td->version[chip];
-+ }
-+ }
-+
-+ /* walk through the memory table */
-+ for (i = 0; i < numblocks; ) {
-+ uint8_t dat;
-+ dat = this->bbt[bbtoffs + (i >> 2)];
-+ for (j = 0; j < 4; j++ , i++) {
-+ int sftcnt = (i << (3 - sft)) & sftmsk;
-+ /* Do not store the reserved bbt blocks ! */
-+ buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt);
-+ dat >>= 2;
-+ }
-+ }
-+
-+ memset (&einfo, 0, sizeof (einfo));
-+ einfo.mtd = mtd;
-+ einfo.addr = (unsigned long) to;
-+ einfo.len = 1 << this->bbt_erase_shift;
-+ res = nand_erase_nand (mtd, &einfo, 1);
-+ if (res < 0) {
-+ printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res);
-+ return res;
-+ }
-+
-+ res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
-+ if (res < 0) {
-+ printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res);
-+ return res;
-+ }
-+ printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n",
-+ (unsigned int) to, td->version[chip]);
-+
-+ /* Mark it as used */
-+ td->pages[chip] = page;
-+ }
-+ return 0;
-+}
-+
-+/**
-+ * nand_memory_bbt - [GENERIC] create a memory based bad block table
-+ * @mtd: MTD device structure
-+ * @bd: descriptor for the good/bad block search pattern
-+ *
-+ * The function creates a memory based bbt by scanning the device
-+ * for manufacturer / software marked good / bad blocks
-+*/
-+static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+
-+ bd->options &= ~NAND_BBT_SCANEMPTY;
-+ return create_bbt (mtd, this->data_buf, bd, -1);
-+}
-+
-+/**
-+ * check_create - [GENERIC] create and write bbt(s) if neccecary
-+ * @mtd: MTD device structure
-+ * @buf: temporary buffer
-+ * @bd: descriptor for the good/bad block search pattern
-+ *
-+ * The function checks the results of the previous call to read_bbt
-+ * and creates / updates the bbt(s) if neccecary
-+ * Creation is neccecary if no bbt was found for the chip/device
-+ * Update is neccecary if one of the tables is missing or the
-+ * version nr. of one table is less than the other
-+*/
-+static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
-+{
-+ int i, chips, writeops, chipsel, res;
-+ struct nand_chip *this = mtd->priv;
-+ struct nand_bbt_descr *td = this->bbt_td;
-+ struct nand_bbt_descr *md = this->bbt_md;
-+ struct nand_bbt_descr *rd, *rd2;
-+
-+ /* Do we have a bbt per chip ? */
-+ if (td->options & NAND_BBT_PERCHIP)
-+ chips = this->numchips;
-+ else
-+ chips = 1;
-+
-+ for (i = 0; i < chips; i++) {
-+ writeops = 0;
-+ rd = NULL;
-+ rd2 = NULL;
-+ /* Per chip or per device ? */
-+ chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
-+ /* Mirrored table avilable ? */
-+ if (md) {
-+ if (td->pages[i] == -1 && md->pages[i] == -1) {
-+ writeops = 0x03;
-+ goto create;
-+ }
-+
-+ if (td->pages[i] == -1) {
-+ rd = md;
-+ td->version[i] = md->version[i];
-+ writeops = 1;
-+ goto writecheck;
-+ }
-+
-+ if (md->pages[i] == -1) {
-+ rd = td;
-+ md->version[i] = td->version[i];
-+ writeops = 2;
-+ goto writecheck;
-+ }
-+
-+ if (td->version[i] == md->version[i]) {
-+ rd = td;
-+ if (!(td->options & NAND_BBT_VERSION))
-+ rd2 = md;
-+ goto writecheck;
-+ }
-+
-+ if (((int8_t) (td->version[i] - md->version[i])) > 0) {
-+ rd = td;
-+ md->version[i] = td->version[i];
-+ writeops = 2;
-+ } else {
-+ rd = md;
-+ td->version[i] = md->version[i];
-+ writeops = 1;
-+ }
-+
-+ goto writecheck;
-+
-+ } else {
-+ if (td->pages[i] == -1) {
-+ writeops = 0x01;
-+ goto create;
-+ }
-+ rd = td;
-+ goto writecheck;
-+ }
-+create:
-+ /* Create the bad block table by scanning the device ? */
-+ if (!(td->options & NAND_BBT_CREATE))
-+ continue;
-+
-+ /* Create the table in memory by scanning the chip(s) */
-+ create_bbt (mtd, buf, bd, chipsel);
-+
-+ td->version[i] = 1;
-+ if (md)
-+ md->version[i] = 1;
-+writecheck:
-+ /* read back first ? */
-+ if (rd)
-+ read_abs_bbt (mtd, buf, rd, chipsel);
-+ /* If they weren't versioned, read both. */
-+ if (rd2)
-+ read_abs_bbt (mtd, buf, rd2, chipsel);
-+
-+ /* Write the bad block table to the device ? */
-+ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
-+ res = write_bbt (mtd, buf, td, md, chipsel);
-+ if (res < 0)
-+ return res;
-+ }
-+
-+ /* Write the mirror bad block table to the device ? */
-+ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
-+ res = write_bbt (mtd, buf, md, td, chipsel);
-+ if (res < 0)
-+ return res;
-+ }
-+ }
-+ return 0;
-+}
-+
-+/**
-+ * mark_bbt_regions - [GENERIC] mark the bad block table regions
-+ * @mtd: MTD device structure
-+ * @td: bad block table descriptor
-+ *
-+ * The bad block table regions are marked as "bad" to prevent
-+ * accidental erasures / writes. The regions are identified by
-+ * the mark 0x02.
-+*/
-+static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ int i, j, chips, block, nrblocks, update;
-+ uint8_t oldval, newval;
-+
-+ /* Do we have a bbt per chip ? */
-+ if (td->options & NAND_BBT_PERCHIP) {
-+ chips = this->numchips;
-+ nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
-+ } else {
-+ chips = 1;
-+ nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
-+ }
-+
-+ for (i = 0; i < chips; i++) {
-+ if ((td->options & NAND_BBT_ABSPAGE) ||
-+ !(td->options & NAND_BBT_WRITE)) {
-+ if (td->pages[i] == -1) continue;
-+ block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
-+ block <<= 1;
-+ oldval = this->bbt[(block >> 3)];
-+ newval = oldval | (0x2 << (block & 0x06));
-+ this->bbt[(block >> 3)] = newval;
-+ if ((oldval != newval) && td->reserved_block_code)
-+ nand_update_bbt(mtd, block << (this->bbt_erase_shift - 1));
-+ continue;
-+ }
-+ update = 0;
-+ if (td->options & NAND_BBT_LASTBLOCK)
-+ block = ((i + 1) * nrblocks) - td->maxblocks;
-+ else
-+ block = i * nrblocks;
-+ block <<= 1;
-+ for (j = 0; j < td->maxblocks; j++) {
-+ oldval = this->bbt[(block >> 3)];
-+ newval = oldval | (0x2 << (block & 0x06));
-+ this->bbt[(block >> 3)] = newval;
-+ if (oldval != newval) update = 1;
-+ block += 2;
-+ }
-+ /* If we want reserved blocks to be recorded to flash, and some
-+ new ones have been marked, then we need to update the stored
-+ bbts. This should only happen once. */
-+ if (update && td->reserved_block_code)
-+ nand_update_bbt(mtd, (block - 2) << (this->bbt_erase_shift - 1));
-+ }
-+}
-+
-+/**
-+ * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
-+ * @mtd: MTD device structure
-+ * @bd: descriptor for the good/bad block search pattern
-+ *
-+ * The function checks, if a bad block table(s) is/are already
-+ * available. If not it scans the device for manufacturer
-+ * marked good / bad blocks and writes the bad block table(s) to
-+ * the selected place.
-+ *
-+ * The bad block table memory is allocated here. It must be freed
-+ * by calling the nand_free_bbt function.
-+ *
-+*/
-+int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ int len, res = 0;
-+ uint8_t *buf;
-+ struct nand_bbt_descr *td = this->bbt_td;
-+ struct nand_bbt_descr *md = this->bbt_md;
-+
-+ len = mtd->size >> (this->bbt_erase_shift + 2);
-+ /* Allocate memory (2bit per block) */
-+ this->bbt = kmalloc (len, GFP_KERNEL);
-+ if (!this->bbt) {
-+ printk (KERN_ERR "nand_scan_bbt: Out of memory\n");
-+ return -ENOMEM;
-+ }
-+ /* Clear the memory bad block table */
-+ memset (this->bbt, 0x00, len);
-+
-+ /* If no primary table decriptor is given, scan the device
-+ * to build a memory based bad block table
-+ */
-+ if (!td) {
-+ if ((res = nand_memory_bbt(mtd, bd))) {
-+ printk (KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n");
-+ kfree (this->bbt);
-+ this->bbt = NULL;
-+ }
-+ return res;
-+ }
-+
-+ /* Allocate a temporary buffer for one eraseblock incl. oob */
-+ len = (1 << this->bbt_erase_shift);
-+ len += (len >> this->page_shift) * mtd->oobsize;
-+ buf = kmalloc (len, GFP_KERNEL);
-+ if (!buf) {
-+ printk (KERN_ERR "nand_bbt: Out of memory\n");
-+ kfree (this->bbt);
-+ this->bbt = NULL;
-+ return -ENOMEM;
-+ }
-+
-+ /* Is the bbt at a given page ? */
-+ if (td->options & NAND_BBT_ABSPAGE) {
-+ res = read_abs_bbts (mtd, buf, td, md);
-+ } else {
-+ /* Search the bad block table using a pattern in oob */
-+ res = search_read_bbts (mtd, buf, td, md);
-+ }
-+
-+ if (res)
-+ res = check_create (mtd, buf, bd);
-+
-+ /* Prevent the bbt regions from erasing / writing */
-+ mark_bbt_region (mtd, td);
-+ if (md)
-+ mark_bbt_region (mtd, md);
-+
-+ kfree (buf);
-+ return res;
-+}
-+
-+
-+/**
-+ * nand_update_bbt - [NAND Interface] update bad block table(s)
-+ * @mtd: MTD device structure
-+ * @offs: the offset of the newly marked block
-+ *
-+ * The function updates the bad block table(s)
-+*/
-+int nand_update_bbt (struct mtd_info *mtd, loff_t offs)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ int len, res = 0, writeops = 0;
-+ int chip, chipsel;
-+ uint8_t *buf;
-+ struct nand_bbt_descr *td = this->bbt_td;
-+ struct nand_bbt_descr *md = this->bbt_md;
-+
-+ if (!this->bbt || !td)
-+ return -EINVAL;
-+
-+ len = mtd->size >> (this->bbt_erase_shift + 2);
-+ /* Allocate a temporary buffer for one eraseblock incl. oob */
-+ len = (1 << this->bbt_erase_shift);
-+ len += (len >> this->page_shift) * mtd->oobsize;
-+ buf = kmalloc (len, GFP_KERNEL);
-+ if (!buf) {
-+ printk (KERN_ERR "nand_update_bbt: Out of memory\n");
-+ return -ENOMEM;
-+ }
-+
-+ writeops = md != NULL ? 0x03 : 0x01;
-+
-+ /* Do we have a bbt per chip ? */
-+ if (td->options & NAND_BBT_PERCHIP) {
-+ chip = (int) (offs >> this->chip_shift);
-+ chipsel = chip;
-+ } else {
-+ chip = 0;
-+ chipsel = -1;
-+ }
-+
-+ td->version[chip]++;
-+ if (md)
-+ md->version[chip]++;
-+
-+ /* Write the bad block table to the device ? */
-+ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
-+ res = write_bbt (mtd, buf, td, md, chipsel);
-+ if (res < 0)
-+ goto out;
-+ }
-+ /* Write the mirror bad block table to the device ? */
-+ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
-+ res = write_bbt (mtd, buf, md, td, chipsel);
-+ }
-+
-+out:
-+ kfree (buf);
-+ return res;
-+}
-+
-+/* Define some generic bad / good block scan pattern which are used
-+ * while scanning a device for factory marked good / bad blocks. */
-+static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
-+
-+static struct nand_bbt_descr smallpage_memorybased = {
-+ .options = NAND_BBT_SCAN2NDPAGE,
-+ .offs = 5,
-+ .len = 1,
-+ .pattern = scan_ff_pattern
-+};
-+
-+static struct nand_bbt_descr largepage_memorybased = {
-+ .options = 0,
-+ .offs = 0,
-+ .len = 2,
-+ .pattern = scan_ff_pattern
-+};
-+
-+static struct nand_bbt_descr smallpage_flashbased = {
-+ .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
-+ .offs = 5,
-+ .len = 1,
-+ .pattern = scan_ff_pattern
-+};
-+
-+static struct nand_bbt_descr largepage_flashbased = {
-+ .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
-+ .offs = 0,
-+ .len = 2,
-+ .pattern = scan_ff_pattern
-+};
-+
-+static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };
-+
-+static struct nand_bbt_descr agand_flashbased = {
-+ .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
-+ .offs = 0x20,
-+ .len = 6,
-+ .pattern = scan_agand_pattern
-+};
-+
-+/* Generic flash bbt decriptors
-+*/
-+static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
-+static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
-+
-+static struct nand_bbt_descr bbt_main_descr = {
-+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-+ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-+ .offs = 8,
-+ .len = 4,
-+ .veroffs = 12,
-+ .maxblocks = 4,
-+ .pattern = bbt_pattern
-+};
-+
-+static struct nand_bbt_descr bbt_mirror_descr = {
-+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-+ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-+ .offs = 8,
-+ .len = 4,
-+ .veroffs = 12,
-+ .maxblocks = 4,
-+ .pattern = mirror_pattern
-+};
-+
-+/**
-+ * nand_default_bbt - [NAND Interface] Select a default bad block table for the device
-+ * @mtd: MTD device structure
-+ *
-+ * This function selects the default bad block table
-+ * support for the device and calls the nand_scan_bbt function
-+ *
-+*/
-+int nand_default_bbt (struct mtd_info *mtd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+
-+ /* Default for AG-AND. We must use a flash based
-+ * bad block table as the devices have factory marked
-+ * _good_ blocks. Erasing those blocks leads to loss
-+ * of the good / bad information, so we _must_ store
-+ * this information in a good / bad table during
-+ * startup
-+ */
-+ if (this->options & NAND_IS_AND) {
-+ /* Use the default pattern descriptors */
-+ if (!this->bbt_td) {
-+ this->bbt_td = &bbt_main_descr;
-+ this->bbt_md = &bbt_mirror_descr;
-+ }
-+ this->options |= NAND_USE_FLASH_BBT;
-+ return nand_scan_bbt (mtd, &agand_flashbased);
-+ }
-+
-+
-+ /* Is a flash based bad block table requested ? */
-+ if (this->options & NAND_USE_FLASH_BBT) {
-+ /* Use the default pattern descriptors */
-+ if (!this->bbt_td) {
-+ this->bbt_td = &bbt_main_descr;
-+ this->bbt_md = &bbt_mirror_descr;
-+ }
-+ if (!this->badblock_pattern) {
-+ this->badblock_pattern = (mtd->oobblock > 512) ?
-+ &largepage_flashbased : &smallpage_flashbased;
-+ }
-+ } else {
-+ this->bbt_td = NULL;
-+ this->bbt_md = NULL;
-+ if (!this->badblock_pattern) {
-+ this->badblock_pattern = (mtd->oobblock > 512) ?
-+ &largepage_memorybased : &smallpage_memorybased;
-+ }
-+ }
-+ return nand_scan_bbt (mtd, this->badblock_pattern);
-+}
-+
-+/**
-+ * nand_isbad_bbt - [NAND Interface] Check if a block is bad
-+ * @mtd: MTD device structure
-+ * @offs: offset in the device
-+ * @allowbbt: allow access to bad block table region
-+ *
-+*/
-+int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ int block;
-+ uint8_t res;
-+
-+ /* Get block number * 2 */
-+ block = (int) (offs >> (this->bbt_erase_shift - 1));
-+ res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
-+
-+ DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
-+ (unsigned int)offs, block >> 1, res);
-+
-+ switch ((int)res) {
-+ case 0x00: return 0;
-+ case 0x01: return 1;
-+ case 0x02: return allowbbt ? 0 : 1;
-+ }
-+ return 1;
-+}
-+
-+EXPORT_SYMBOL (nand_scan_bbt);
-+EXPORT_SYMBOL (nand_default_bbt);
---- linux-2.4.21/drivers/mtd/nand/nand_ecc.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/nand/nand_ecc.c
-@@ -1,22 +1,44 @@
- /*
-- * drivers/mtd/nand_ecc.c
-+ * This file contains an ECC algorithm from Toshiba that detects and
-+ * corrects 1 bit errors in a 256 byte block of data.
- *
-- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
-+ * drivers/mtd/nand/nand_ecc.c
-+ *
-+ * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com)
- * Toshiba America Electronics Components, Inc.
- *
-- * $Id: nand_ecc.c,v 1.8 2002/09/16 09:19:53 dwmw2 Exp $
-+ * $Id: nand_ecc.c,v 1.14 2004/06/16 15:34:37 gleixner Exp $
- *
-- * This program is free software; you can redistribute it and/or
-- * modify it under the terms of the GNU Lesser General Public License
-- * version 2.1 as published by the Free Software Foundation.
-+ * This file is free software; 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 file contains an ECC algorithm from Toshiba that detects and
-- * corrects 1 bit errors in a 256 byte block of data.
-+ * This file is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-+ * for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License along
-+ * with this file; if not, write to the Free Software Foundation, Inc.,
-+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-+ *
-+ * As a special exception, if other files instantiate templates or use
-+ * macros or inline functions from these files, or you compile these
-+ * files and link them with other works to produce a work based on these
-+ * files, these files do not by themselves cause the resulting work to be
-+ * covered by the GNU General Public License. However the source code for
-+ * these files must still be made available in accordance with section (3)
-+ * of the GNU General Public License.
-+ *
-+ * This exception does not invalidate any other reasons why a work based on
-+ * this file might be covered by the GNU General Public License.
- */
-
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
-+#include <linux/mtd/nand_ecc.h>
-
- /*
- * Pre-calculated 256-way 1 byte column parity
-@@ -41,7 +63,12 @@
- };
-
-
--/*
-+/**
-+ * nand_trans_result - [GENERIC] create non-inverted ECC
-+ * @reg2: line parity reg 2
-+ * @reg3: line parity reg 3
-+ * @ecc_code: ecc
-+ *
- * Creates non-inverted ECC code from line parity
- */
- static void nand_trans_result(u_char reg2, u_char reg3,
-@@ -81,10 +108,13 @@
- ecc_code[1] = tmp2;
- }
-
--/*
-- * Calculate 3 byte ECC code for 256 byte block
-+/**
-+ * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for 256 byte block
-+ * @mtd: MTD block structure
-+ * @dat: raw data
-+ * @ecc_code: buffer for ECC
- */
--void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
-+int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
- {
- u_char idx, reg1, reg2, reg3;
- int j;
-@@ -114,12 +144,19 @@
- ecc_code[0] = ~ecc_code[0];
- ecc_code[1] = ~ecc_code[1];
- ecc_code[2] = ((~reg1) << 2) | 0x03;
-+ return 0;
- }
-
--/*
-+/**
-+ * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
-+ * @mtd: MTD block structure
-+ * @dat: raw data read from the chip
-+ * @read_ecc: ECC from the chip
-+ * @calc_ecc: the ECC calculated from raw data
-+ *
- * Detect and correct a 1 bit error for 256 byte block
- */
--int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)
-+int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
- {
- u_char a, b, c, d1, d2, d3, add, bit, i;
-
-@@ -209,5 +246,5 @@
- EXPORT_SYMBOL(nand_correct_data);
-
- MODULE_LICENSE("GPL");
--MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com>");
-+MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
- MODULE_DESCRIPTION("Generic NAND ECC support");
---- linux-2.4.21/drivers/mtd/nand/nand_ids.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/nand/nand_ids.c
-@@ -3,8 +3,7 @@
- *
- * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
- *
-- *
-- * $Id: nand_ids.c,v 1.1 2002/12/02 22:06:04 gleixner Exp $
-+ * $Id: nand_ids.c,v 1.12 2005/02/16 09:33:27 gleixner 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
-@@ -13,26 +12,97 @@
- */
- #include <linux/module.h>
- #include <linux/mtd/nand.h>
--
- /*
- * Chip ID list
-+*
-+* Name. ID code, pagesize, chipsize in MegaByte, eraseblock size,
-+* options
-+*
-+* Pagesize; 0, 256, 512
-+* 0 get this information from the extended chip ID
-++ 256 256 Byte page size
-+* 512 512 Byte page size
- */
- struct nand_flash_dev nand_flash_ids[] = {
-- {"NAND 1MB 5V", 0x6e, 20, 0x1000, 1}, // 1Mb 5V
-- {"NAND 2MB 5V", 0x64, 21, 0x1000, 1}, // 2Mb 5V
-- {"NAND 4MB 5V", 0x6b, 22, 0x2000, 0}, // 4Mb 5V
-- {"NAND 1MB 3,3V", 0xe8, 20, 0x1000, 1}, // 1Mb 3.3V
-- {"NAND 1MB 3,3V", 0xec, 20, 0x1000, 1}, // 1Mb 3.3V
-- {"NAND 2MB 3,3V", 0xea, 21, 0x1000, 1}, // 2Mb 3.3V
-- {"NAND 4MB 3,3V", 0xd5, 22, 0x2000, 0}, // 4Mb 3.3V
-- {"NAND 4MB 3,3V", 0xe3, 22, 0x2000, 0}, // 4Mb 3.3V
-- {"NAND 4MB 3,3V", 0xe5, 22, 0x2000, 0}, // 4Mb 3.3V
-- {"NAND 8MB 3,3V", 0xd6, 23, 0x2000, 0}, // 8Mb 3.3V
-- {"NAND 8MB 3,3V", 0xe6, 23, 0x2000, 0}, // 8Mb 3.3V
-- {"NAND 16MB 3,3V", 0x73, 24, 0x4000, 0},// 16Mb 3,3V
-- {"NAND 32MB 3,3V", 0x75, 25, 0x4000, 0}, // 32Mb 3,3V
-- {"NAND 64MB 3,3V", 0x76, 26, 0x4000, 0}, // 64Mb 3,3V
-- {"NAND 128MB 3,3V", 0x79, 27, 0x4000, 0}, // 128Mb 3,3V
-+ {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0},
-+ {"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0},
-+ {"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0},
-+ {"NAND 1MiB 3,3V 8-bit", 0xe8, 256, 1, 0x1000, 0},
-+ {"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, 0},
-+ {"NAND 2MiB 3,3V 8-bit", 0xea, 256, 2, 0x1000, 0},
-+ {"NAND 4MiB 3,3V 8-bit", 0xd5, 512, 4, 0x2000, 0},
-+ {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0},
-+ {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0},
-+ {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0},
-+
-+ {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0},
-+ {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0},
-+ {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
-+ {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
-+
-+ {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},
-+ {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},
-+ {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
-+ {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
-+
-+ {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0},
-+ {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0},
-+ {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
-+ {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
-+
-+ {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0},
-+ {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0},
-+ {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
-+ {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
-+
-+ {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0},
-+ {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0},
-+ {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
-+ {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
-+
-+ {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0},
-+
-+ /* These are the new chips with large page size. The pagesize
-+ * and the erasesize is determined from the extended id bytes
-+ */
-+ /* 1 Gigabit */
-+ {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
-+ {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
-+ {"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
-+ {"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
-+
-+ /* 2 Gigabit */
-+ {"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
-+ {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
-+ {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
-+ {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
-+
-+ /* 4 Gigabit */
-+ {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
-+ {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
-+ {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
-+ {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
-+
-+ /* 8 Gigabit */
-+ {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
-+ {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
-+ {"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
-+ {"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
-+
-+ /* 16 Gigabit */
-+ {"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
-+ {"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
-+ {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
-+ {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
-+
-+ /* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout !
-+ * The chosen minimum erasesize is 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page planes
-+ * 1 block = 2 pages, but due to plane arrangement the blocks 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7
-+ * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go
-+ * There are more speed improvements for reads and writes possible, but not implemented now
-+ */
-+ {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
-+
- {NULL,}
- };
-
-@@ -44,10 +114,11 @@
- {NAND_MFR_SAMSUNG, "Samsung"},
- {NAND_MFR_FUJITSU, "Fujitsu"},
- {NAND_MFR_NATIONAL, "National"},
-+ {NAND_MFR_RENESAS, "Renesas"},
-+ {NAND_MFR_STMICRO, "ST Micro"},
- {0x0, "Unknown"}
- };
-
--
- EXPORT_SYMBOL (nand_manuf_ids);
- EXPORT_SYMBOL (nand_flash_ids);
-
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/nand/nandsim.c
-@@ -0,0 +1,1613 @@
-+/*
-+ * NAND flash simulator.
-+ *
-+ * Author: Artem B. Bityuckiy <dedekind@oktetlabs.ru>, <dedekind@infradead.org>
-+ *
-+ * Copyright (C) 2004 Nokia Corporation
-+ *
-+ * Note: NS means "NAND Simulator".
-+ * Note: Input means input TO flash chip, output means output FROM chip.
-+ *
-+ * This program is free software; 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
-+ *
-+ * $Id: nandsim.c,v 1.7 2004/12/06 11:53:06 dedekind Exp $
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/init.h>
-+#include <linux/types.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/vmalloc.h>
-+#include <linux/slab.h>
-+#include <linux/errno.h>
-+#include <linux/string.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/delay.h>
-+#ifdef CONFIG_NS_ABS_POS
-+#include <asm/io.h>
-+#endif
-+
-+
-+/* Default simulator parameters values */
-+#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \
-+ !defined(CONFIG_NANDSIM_SECOND_ID_BYTE) || \
-+ !defined(CONFIG_NANDSIM_THIRD_ID_BYTE) || \
-+ !defined(CONFIG_NANDSIM_FOURTH_ID_BYTE)
-+#define CONFIG_NANDSIM_FIRST_ID_BYTE 0x98
-+#define CONFIG_NANDSIM_SECOND_ID_BYTE 0x39
-+#define CONFIG_NANDSIM_THIRD_ID_BYTE 0xFF /* No byte */
-+#define CONFIG_NANDSIM_FOURTH_ID_BYTE 0xFF /* No byte */
-+#endif
-+
-+#ifndef CONFIG_NANDSIM_ACCESS_DELAY
-+#define CONFIG_NANDSIM_ACCESS_DELAY 25
-+#endif
-+#ifndef CONFIG_NANDSIM_PROGRAMM_DELAY
-+#define CONFIG_NANDSIM_PROGRAMM_DELAY 200
-+#endif
-+#ifndef CONFIG_NANDSIM_ERASE_DELAY
-+#define CONFIG_NANDSIM_ERASE_DELAY 2
-+#endif
-+#ifndef CONFIG_NANDSIM_OUTPUT_CYCLE
-+#define CONFIG_NANDSIM_OUTPUT_CYCLE 40
-+#endif
-+#ifndef CONFIG_NANDSIM_INPUT_CYCLE
-+#define CONFIG_NANDSIM_INPUT_CYCLE 50
-+#endif
-+#ifndef CONFIG_NANDSIM_BUS_WIDTH
-+#define CONFIG_NANDSIM_BUS_WIDTH 8
-+#endif
-+#ifndef CONFIG_NANDSIM_DO_DELAYS
-+#define CONFIG_NANDSIM_DO_DELAYS 0
-+#endif
-+#ifndef CONFIG_NANDSIM_LOG
-+#define CONFIG_NANDSIM_LOG 0
-+#endif
-+#ifndef CONFIG_NANDSIM_DBG
-+#define CONFIG_NANDSIM_DBG 0
-+#endif
-+
-+static uint first_id_byte = CONFIG_NANDSIM_FIRST_ID_BYTE;
-+static uint second_id_byte = CONFIG_NANDSIM_SECOND_ID_BYTE;
-+static uint third_id_byte = CONFIG_NANDSIM_THIRD_ID_BYTE;
-+static uint fourth_id_byte = CONFIG_NANDSIM_FOURTH_ID_BYTE;
-+static uint access_delay = CONFIG_NANDSIM_ACCESS_DELAY;
-+static uint programm_delay = CONFIG_NANDSIM_PROGRAMM_DELAY;
-+static uint erase_delay = CONFIG_NANDSIM_ERASE_DELAY;
-+static uint output_cycle = CONFIG_NANDSIM_OUTPUT_CYCLE;
-+static uint input_cycle = CONFIG_NANDSIM_INPUT_CYCLE;
-+static uint bus_width = CONFIG_NANDSIM_BUS_WIDTH;
-+static uint do_delays = CONFIG_NANDSIM_DO_DELAYS;
-+static uint log = CONFIG_NANDSIM_LOG;
-+static uint dbg = CONFIG_NANDSIM_DBG;
-+
-+module_param(first_id_byte, uint, 0400);
-+module_param(second_id_byte, uint, 0400);
-+module_param(third_id_byte, uint, 0400);
-+module_param(fourth_id_byte, uint, 0400);
-+module_param(access_delay, uint, 0400);
-+module_param(programm_delay, uint, 0400);
-+module_param(erase_delay, uint, 0400);
-+module_param(output_cycle, uint, 0400);
-+module_param(input_cycle, uint, 0400);
-+module_param(bus_width, uint, 0400);
-+module_param(do_delays, uint, 0400);
-+module_param(log, uint, 0400);
-+module_param(dbg, uint, 0400);
-+
-+MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)");
-+MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)");
-+MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command");
-+MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command");
-+MODULE_PARM_DESC(access_delay, "Initial page access delay (microiseconds)");
-+MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds");
-+MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)");
-+MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)");
-+MODULE_PARM_DESC(input_cycle, "Word input (to flash) time (nanodeconds)");
-+MODULE_PARM_DESC(bus_width, "Chip's bus width (8- or 16-bit)");
-+MODULE_PARM_DESC(do_delays, "Simulate NAND delays using busy-waits if not zero");
-+MODULE_PARM_DESC(log, "Perform logging if not zero");
-+MODULE_PARM_DESC(dbg, "Output debug information if not zero");
-+
-+/* The largest possible page size */
-+#define NS_LARGEST_PAGE_SIZE 2048
-+
-+/* The prefix for simulator output */
-+#define NS_OUTPUT_PREFIX "[nandsim]"
-+
-+/* Simulator's output macros (logging, debugging, warning, error) */
-+#define NS_LOG(args...) \
-+ do { if (log) printk(KERN_DEBUG NS_OUTPUT_PREFIX " log: " args); } while(0)
-+#define NS_DBG(args...) \
-+ do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0)
-+#define NS_WARN(args...) \
-+ do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warnig: " args); } while(0)
-+#define NS_ERR(args...) \
-+ do { printk(KERN_ERR NS_OUTPUT_PREFIX " errorr: " args); } while(0)
-+
-+/* Busy-wait delay macros (microseconds, milliseconds) */
-+#define NS_UDELAY(us) \
-+ do { if (do_delays) udelay(us); } while(0)
-+#define NS_MDELAY(us) \
-+ do { if (do_delays) mdelay(us); } while(0)
-+
-+/* Is the nandsim structure initialized ? */
-+#define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0)
-+
-+/* Good operation completion status */
-+#define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0)))
-+
-+/* Operation failed completion status */
-+#define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns))
-+
-+/* Calculate the page offset in flash RAM image by (row, column) address */
-+#define NS_RAW_OFFSET(ns) \
-+ (((ns)->regs.row << (ns)->geom.pgshift) + ((ns)->regs.row * (ns)->geom.oobsz) + (ns)->regs.column)
-+
-+/* Calculate the OOB offset in flash RAM image by (row, column) address */
-+#define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz)
-+
-+/* After a command is input, the simulator goes to one of the following states */
-+#define STATE_CMD_READ0 0x00000001 /* read data from the beginning of page */
-+#define STATE_CMD_READ1 0x00000002 /* read data from the second half of page */
-+#define STATE_CMD_READSTART 0x00000003 /* read data second command (large page devices) */
-+#define STATE_CMD_PAGEPROG 0x00000004 /* start page programm */
-+#define STATE_CMD_READOOB 0x00000005 /* read OOB area */
-+#define STATE_CMD_ERASE1 0x00000006 /* sector erase first command */
-+#define STATE_CMD_STATUS 0x00000007 /* read status */
-+#define STATE_CMD_STATUS_M 0x00000008 /* read multi-plane status (isn't implemented) */
-+#define STATE_CMD_SEQIN 0x00000009 /* sequential data imput */
-+#define STATE_CMD_READID 0x0000000A /* read ID */
-+#define STATE_CMD_ERASE2 0x0000000B /* sector erase second command */
-+#define STATE_CMD_RESET 0x0000000C /* reset */
-+#define STATE_CMD_MASK 0x0000000F /* command states mask */
-+
-+/* After an addres is input, the simulator goes to one of these states */
-+#define STATE_ADDR_PAGE 0x00000010 /* full (row, column) address is accepted */
-+#define STATE_ADDR_SEC 0x00000020 /* sector address was accepted */
-+#define STATE_ADDR_ZERO 0x00000030 /* one byte zero address was accepted */
-+#define STATE_ADDR_MASK 0x00000030 /* address states mask */
-+
-+/* Durind data input/output the simulator is in these states */
-+#define STATE_DATAIN 0x00000100 /* waiting for data input */
-+#define STATE_DATAIN_MASK 0x00000100 /* data input states mask */
-+
-+#define STATE_DATAOUT 0x00001000 /* waiting for page data output */
-+#define STATE_DATAOUT_ID 0x00002000 /* waiting for ID bytes output */
-+#define STATE_DATAOUT_STATUS 0x00003000 /* waiting for status output */
-+#define STATE_DATAOUT_STATUS_M 0x00004000 /* waiting for multi-plane status output */
-+#define STATE_DATAOUT_MASK 0x00007000 /* data output states mask */
-+
-+/* Previous operation is done, ready to accept new requests */
-+#define STATE_READY 0x00000000
-+
-+/* This state is used to mark that the next state isn't known yet */
-+#define STATE_UNKNOWN 0x10000000
-+
-+/* Simulator's actions bit masks */
-+#define ACTION_CPY 0x00100000 /* copy page/OOB to the internal buffer */
-+#define ACTION_PRGPAGE 0x00200000 /* programm the internal buffer to flash */
-+#define ACTION_SECERASE 0x00300000 /* erase sector */
-+#define ACTION_ZEROOFF 0x00400000 /* don't add any offset to address */
-+#define ACTION_HALFOFF 0x00500000 /* add to address half of page */
-+#define ACTION_OOBOFF 0x00600000 /* add to address OOB offset */
-+#define ACTION_MASK 0x00700000 /* action mask */
-+
-+#define NS_OPER_NUM 12 /* Number of operations supported by the simulator */
-+#define NS_OPER_STATES 6 /* Maximum number of states in operation */
-+
-+#define OPT_ANY 0xFFFFFFFF /* any chip supports this operation */
-+#define OPT_PAGE256 0x00000001 /* 256-byte page chips */
-+#define OPT_PAGE512 0x00000002 /* 512-byte page chips */
-+#define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */
-+#define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */
-+#define OPT_AUTOINCR 0x00000020 /* page number auto inctimentation is possible */
-+#define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */
-+#define OPT_LARGEPAGE (OPT_PAGE2048) /* 2048-byte page chips */
-+#define OPT_SMALLPAGE (OPT_PAGE256 | OPT_PAGE512) /* 256 and 512-byte page chips */
-+
-+/* Remove action bits ftom state */
-+#define NS_STATE(x) ((x) & ~ACTION_MASK)
-+
-+/*
-+ * Maximum previous states which need to be saved. Currently saving is
-+ * only needed for page programm operation with preceeded read command
-+ * (which is only valid for 512-byte pages).
-+ */
-+#define NS_MAX_PREVSTATES 1
-+
-+/*
-+ * The structure which describes all the internal simulator data.
-+ */
-+struct nandsim {
-+ struct mtd_partition part;
-+
-+ uint busw; /* flash chip bus width (8 or 16) */
-+ u_char ids[4]; /* chip's ID bytes */
-+ uint32_t options; /* chip's characteristic bits */
-+ uint32_t state; /* current chip state */
-+ uint32_t nxstate; /* next expected state */
-+
-+ uint32_t *op; /* current operation, NULL operations isn't known yet */
-+ uint32_t pstates[NS_MAX_PREVSTATES]; /* previous states */
-+ uint16_t npstates; /* number of previous states saved */
-+ uint16_t stateidx; /* current state index */
-+
-+ /* The simulated NAND flash image */
-+ union flash_media {
-+ u_char *byte;
-+ uint16_t *word;
-+ } mem;
-+
-+ /* Internal buffer of page + OOB size bytes */
-+ union internal_buffer {
-+ u_char *byte; /* for byte access */
-+ uint16_t *word; /* for 16-bit word access */
-+ } buf;
-+
-+ /* NAND flash "geometry" */
-+ struct nandsin_geometry {
-+ uint32_t totsz; /* total flash size, bytes */
-+ uint32_t secsz; /* flash sector (erase block) size, bytes */
-+ uint pgsz; /* NAND flash page size, bytes */
-+ uint oobsz; /* page OOB area size, bytes */
-+ uint32_t totszoob; /* total flash size including OOB, bytes */
-+ uint pgszoob; /* page size including OOB , bytes*/
-+ uint secszoob; /* sector size including OOB, bytes */
-+ uint pgnum; /* total number of pages */
-+ uint pgsec; /* number of pages per sector */
-+ uint secshift; /* bits number in sector size */
-+ uint pgshift; /* bits number in page size */
-+ uint oobshift; /* bits number in OOB size */
-+ uint pgaddrbytes; /* bytes per page address */
-+ uint secaddrbytes; /* bytes per sector address */
-+ uint idbytes; /* the number ID bytes that this chip outputs */
-+ } geom;
-+
-+ /* NAND flash internal registers */
-+ struct nandsim_regs {
-+ unsigned command; /* the command register */
-+ u_char status; /* the status register */
-+ uint row; /* the page number */
-+ uint column; /* the offset within page */
-+ uint count; /* internal counter */
-+ uint num; /* number of bytes which must be processed */
-+ uint off; /* fixed page offset */
-+ } regs;
-+
-+ /* NAND flash lines state */
-+ struct ns_lines_status {
-+ int ce; /* chip Enable */
-+ int cle; /* command Latch Enable */
-+ int ale; /* address Latch Enable */
-+ int wp; /* write Protect */
-+ } lines;
-+};
-+
-+/*
-+ * Operations array. To perform any operation the simulator must pass
-+ * through the correspondent states chain.
-+ */
-+static struct nandsim_operations {
-+ uint32_t reqopts; /* options which are required to perform the operation */
-+ uint32_t states[NS_OPER_STATES]; /* operation's states */
-+} ops[NS_OPER_NUM] = {
-+ /* Read page + OOB from the beginning */
-+ {OPT_SMALLPAGE, {STATE_CMD_READ0 | ACTION_ZEROOFF, STATE_ADDR_PAGE | ACTION_CPY,
-+ STATE_DATAOUT, STATE_READY}},
-+ /* Read page + OOB from the second half */
-+ {OPT_PAGE512_8BIT, {STATE_CMD_READ1 | ACTION_HALFOFF, STATE_ADDR_PAGE | ACTION_CPY,
-+ STATE_DATAOUT, STATE_READY}},
-+ /* Read OOB */
-+ {OPT_SMALLPAGE, {STATE_CMD_READOOB | ACTION_OOBOFF, STATE_ADDR_PAGE | ACTION_CPY,
-+ STATE_DATAOUT, STATE_READY}},
-+ /* Programm page starting from the beginning */
-+ {OPT_ANY, {STATE_CMD_SEQIN, STATE_ADDR_PAGE, STATE_DATAIN,
-+ STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
-+ /* Programm page starting from the beginning */
-+ {OPT_SMALLPAGE, {STATE_CMD_READ0, STATE_CMD_SEQIN | ACTION_ZEROOFF, STATE_ADDR_PAGE,
-+ STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
-+ /* Programm page starting from the second half */
-+ {OPT_PAGE512, {STATE_CMD_READ1, STATE_CMD_SEQIN | ACTION_HALFOFF, STATE_ADDR_PAGE,
-+ STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
-+ /* Programm OOB */
-+ {OPT_SMALLPAGE, {STATE_CMD_READOOB, STATE_CMD_SEQIN | ACTION_OOBOFF, STATE_ADDR_PAGE,
-+ STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
-+ /* Erase sector */
-+ {OPT_ANY, {STATE_CMD_ERASE1, STATE_ADDR_SEC, STATE_CMD_ERASE2 | ACTION_SECERASE, STATE_READY}},
-+ /* Read status */
-+ {OPT_ANY, {STATE_CMD_STATUS, STATE_DATAOUT_STATUS, STATE_READY}},
-+ /* Read multi-plane status */
-+ {OPT_SMARTMEDIA, {STATE_CMD_STATUS_M, STATE_DATAOUT_STATUS_M, STATE_READY}},
-+ /* Read ID */
-+ {OPT_ANY, {STATE_CMD_READID, STATE_ADDR_ZERO, STATE_DATAOUT_ID, STATE_READY}},
-+ /* Large page devices read page */
-+ {OPT_LARGEPAGE, {STATE_CMD_READ0, STATE_ADDR_PAGE, STATE_CMD_READSTART | ACTION_CPY,
-+ STATE_DATAOUT, STATE_READY}}
-+};
-+
-+/* MTD structure for NAND controller */
-+static struct mtd_info *nsmtd;
-+
-+static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE];
-+
-+/*
-+ * Initialize the nandsim structure.
-+ *
-+ * RETURNS: 0 if success, -ERRNO if failure.
-+ */
-+static int
-+init_nandsim(struct mtd_info *mtd)
-+{
-+ struct nand_chip *chip = (struct nand_chip *)mtd->priv;
-+ struct nandsim *ns = (struct nandsim *)(chip->priv);
-+ int i;
-+
-+ if (NS_IS_INITIALIZED(ns)) {
-+ NS_ERR("init_nandsim: nandsim is already initialized\n");
-+ return -EIO;
-+ }
-+
-+ /* Force mtd to not do delays */
-+ chip->chip_delay = 0;
-+
-+ /* Initialize the NAND flash parameters */
-+ ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8;
-+ ns->geom.totsz = mtd->size;
-+ ns->geom.pgsz = mtd->oobblock;
-+ ns->geom.oobsz = mtd->oobsize;
-+ ns->geom.secsz = mtd->erasesize;
-+ ns->geom.pgszoob = ns->geom.pgsz + ns->geom.oobsz;
-+ ns->geom.pgnum = ns->geom.totsz / ns->geom.pgsz;
-+ ns->geom.totszoob = ns->geom.totsz + ns->geom.pgnum * ns->geom.oobsz;
-+ ns->geom.secshift = ffs(ns->geom.secsz) - 1;
-+ ns->geom.pgshift = chip->page_shift;
-+ ns->geom.oobshift = ffs(ns->geom.oobsz) - 1;
-+ ns->geom.pgsec = ns->geom.secsz / ns->geom.pgsz;
-+ ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec;
-+ ns->options = 0;
-+
-+ if (ns->geom.pgsz == 256) {
-+ ns->options |= OPT_PAGE256;
-+ }
-+ else if (ns->geom.pgsz == 512) {
-+ ns->options |= (OPT_PAGE512 | OPT_AUTOINCR);
-+ if (ns->busw == 8)
-+ ns->options |= OPT_PAGE512_8BIT;
-+ } else if (ns->geom.pgsz == 2048) {
-+ ns->options |= OPT_PAGE2048;
-+ } else {
-+ NS_ERR("init_nandsim: unknown page size %u\n", ns->geom.pgsz);
-+ return -EIO;
-+ }
-+
-+ if (ns->options & OPT_SMALLPAGE) {
-+ if (ns->geom.totsz < (64 << 20)) {
-+ ns->geom.pgaddrbytes = 3;
-+ ns->geom.secaddrbytes = 2;
-+ } else {
-+ ns->geom.pgaddrbytes = 4;
-+ ns->geom.secaddrbytes = 3;
-+ }
-+ } else {
-+ if (ns->geom.totsz <= (128 << 20)) {
-+ ns->geom.pgaddrbytes = 5;
-+ ns->geom.secaddrbytes = 2;
-+ } else {
-+ ns->geom.pgaddrbytes = 5;
-+ ns->geom.secaddrbytes = 3;
-+ }
-+ }
-+
-+ /* Detect how many ID bytes the NAND chip outputs */
-+ for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-+ if (second_id_byte != nand_flash_ids[i].id)
-+ continue;
-+ if (!(nand_flash_ids[i].options & NAND_NO_AUTOINCR))
-+ ns->options |= OPT_AUTOINCR;
-+ }
-+
-+ if (ns->busw == 16)
-+ NS_WARN("16-bit flashes support wasn't tested\n");
-+
-+ printk("flash size: %u MiB\n", ns->geom.totsz >> 20);
-+ printk("page size: %u bytes\n", ns->geom.pgsz);
-+ printk("OOB area size: %u bytes\n", ns->geom.oobsz);
-+ printk("sector size: %u KiB\n", ns->geom.secsz >> 10);
-+ printk("pages number: %u\n", ns->geom.pgnum);
-+ printk("pages per sector: %u\n", ns->geom.pgsec);
-+ printk("bus width: %u\n", ns->busw);
-+ printk("bits in sector size: %u\n", ns->geom.secshift);
-+ printk("bits in page size: %u\n", ns->geom.pgshift);
-+ printk("bits in OOB size: %u\n", ns->geom.oobshift);
-+ printk("flash size with OOB: %u KiB\n", ns->geom.totszoob >> 10);
-+ printk("page address bytes: %u\n", ns->geom.pgaddrbytes);
-+ printk("sector address bytes: %u\n", ns->geom.secaddrbytes);
-+ printk("options: %#x\n", ns->options);
-+
-+ /* Map / allocate and initialize the flash image */
-+#ifdef CONFIG_NS_ABS_POS
-+ ns->mem.byte = ioremap(CONFIG_NS_ABS_POS, ns->geom.totszoob);
-+ if (!ns->mem.byte) {
-+ NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n",
-+ (void *)CONFIG_NS_ABS_POS);
-+ return -ENOMEM;
-+ }
-+#else
-+ ns->mem.byte = vmalloc(ns->geom.totszoob);
-+ if (!ns->mem.byte) {
-+ NS_ERR("init_nandsim: unable to allocate %u bytes for flash image\n",
-+ ns->geom.totszoob);
-+ return -ENOMEM;
-+ }
-+ memset(ns->mem.byte, 0xFF, ns->geom.totszoob);
-+#endif
-+
-+ /* Allocate / initialize the internal buffer */
-+ ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
-+ if (!ns->buf.byte) {
-+ NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n",
-+ ns->geom.pgszoob);
-+ goto error;
-+ }
-+ memset(ns->buf.byte, 0xFF, ns->geom.pgszoob);
-+
-+ /* Fill the partition_info structure */
-+ ns->part.name = "NAND simulator partition";
-+ ns->part.offset = 0;
-+ ns->part.size = ns->geom.totsz;
-+
-+ return 0;
-+
-+error:
-+#ifdef CONFIG_NS_ABS_POS
-+ iounmap(ns->mem.byte);
-+#else
-+ vfree(ns->mem.byte);
-+#endif
-+
-+ return -ENOMEM;
-+}
-+
-+/*
-+ * Free the nandsim structure.
-+ */
-+static void
-+free_nandsim(struct nandsim *ns)
-+{
-+ kfree(ns->buf.byte);
-+
-+#ifdef CONFIG_NS_ABS_POS
-+ iounmap(ns->mem.byte);
-+#else
-+ vfree(ns->mem.byte);
-+#endif
-+
-+ return;
-+}
-+
-+/*
-+ * Returns the string representation of 'state' state.
-+ */
-+static char *
-+get_state_name(uint32_t state)
-+{
-+ switch (NS_STATE(state)) {
-+ case STATE_CMD_READ0:
-+ return "STATE_CMD_READ0";
-+ case STATE_CMD_READ1:
-+ return "STATE_CMD_READ1";
-+ case STATE_CMD_PAGEPROG:
-+ return "STATE_CMD_PAGEPROG";
-+ case STATE_CMD_READOOB:
-+ return "STATE_CMD_READOOB";
-+ case STATE_CMD_READSTART:
-+ return "STATE_CMD_READSTART";
-+ case STATE_CMD_ERASE1:
-+ return "STATE_CMD_ERASE1";
-+ case STATE_CMD_STATUS:
-+ return "STATE_CMD_STATUS";
-+ case STATE_CMD_STATUS_M:
-+ return "STATE_CMD_STATUS_M";
-+ case STATE_CMD_SEQIN:
-+ return "STATE_CMD_SEQIN";
-+ case STATE_CMD_READID:
-+ return "STATE_CMD_READID";
-+ case STATE_CMD_ERASE2:
-+ return "STATE_CMD_ERASE2";
-+ case STATE_CMD_RESET:
-+ return "STATE_CMD_RESET";
-+ case STATE_ADDR_PAGE:
-+ return "STATE_ADDR_PAGE";
-+ case STATE_ADDR_SEC:
-+ return "STATE_ADDR_SEC";
-+ case STATE_ADDR_ZERO:
-+ return "STATE_ADDR_ZERO";
-+ case STATE_DATAIN:
-+ return "STATE_DATAIN";
-+ case STATE_DATAOUT:
-+ return "STATE_DATAOUT";
-+ case STATE_DATAOUT_ID:
-+ return "STATE_DATAOUT_ID";
-+ case STATE_DATAOUT_STATUS:
-+ return "STATE_DATAOUT_STATUS";
-+ case STATE_DATAOUT_STATUS_M:
-+ return "STATE_DATAOUT_STATUS_M";
-+ case STATE_READY:
-+ return "STATE_READY";
-+ case STATE_UNKNOWN:
-+ return "STATE_UNKNOWN";
-+ }
-+
-+ NS_ERR("get_state_name: unknown state, BUG\n");
-+ return NULL;
-+}
-+
-+/*
-+ * Check if command is valid.
-+ *
-+ * RETURNS: 1 if wrong command, 0 if right.
-+ */
-+static int
-+check_command(int cmd)
-+{
-+ switch (cmd) {
-+
-+ case NAND_CMD_READ0:
-+ case NAND_CMD_READSTART:
-+ case NAND_CMD_PAGEPROG:
-+ case NAND_CMD_READOOB:
-+ case NAND_CMD_ERASE1:
-+ case NAND_CMD_STATUS:
-+ case NAND_CMD_SEQIN:
-+ case NAND_CMD_READID:
-+ case NAND_CMD_ERASE2:
-+ case NAND_CMD_RESET:
-+ case NAND_CMD_READ1:
-+ return 0;
-+
-+ case NAND_CMD_STATUS_MULTI:
-+ default:
-+ return 1;
-+ }
-+}
-+
-+/*
-+ * Returns state after command is accepted by command number.
-+ */
-+static uint32_t
-+get_state_by_command(unsigned command)
-+{
-+ switch (command) {
-+ case NAND_CMD_READ0:
-+ return STATE_CMD_READ0;
-+ case NAND_CMD_READ1:
-+ return STATE_CMD_READ1;
-+ case NAND_CMD_PAGEPROG:
-+ return STATE_CMD_PAGEPROG;
-+ case NAND_CMD_READSTART:
-+ return STATE_CMD_READSTART;
-+ case NAND_CMD_READOOB:
-+ return STATE_CMD_READOOB;
-+ case NAND_CMD_ERASE1:
-+ return STATE_CMD_ERASE1;
-+ case NAND_CMD_STATUS:
-+ return STATE_CMD_STATUS;
-+ case NAND_CMD_STATUS_MULTI:
-+ return STATE_CMD_STATUS_M;
-+ case NAND_CMD_SEQIN:
-+ return STATE_CMD_SEQIN;
-+ case NAND_CMD_READID:
-+ return STATE_CMD_READID;
-+ case NAND_CMD_ERASE2:
-+ return STATE_CMD_ERASE2;
-+ case NAND_CMD_RESET:
-+ return STATE_CMD_RESET;
-+ }
-+
-+ NS_ERR("get_state_by_command: unknown command, BUG\n");
-+ return 0;
-+}
-+
-+/*
-+ * Move an address byte to the correspondent internal register.
-+ */
-+static inline void
-+accept_addr_byte(struct nandsim *ns, u_char bt)
-+{
-+ uint byte = (uint)bt;
-+
-+ if (ns->regs.count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes))
-+ ns->regs.column |= (byte << 8 * ns->regs.count);
-+ else {
-+ ns->regs.row |= (byte << 8 * (ns->regs.count -
-+ ns->geom.pgaddrbytes +
-+ ns->geom.secaddrbytes));
-+ }
-+
-+ return;
-+}
-+
-+/*
-+ * Switch to STATE_READY state.
-+ */
-+static inline void
-+switch_to_ready_state(struct nandsim *ns, u_char status)
-+{
-+ NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY));
-+
-+ ns->state = STATE_READY;
-+ ns->nxstate = STATE_UNKNOWN;
-+ ns->op = NULL;
-+ ns->npstates = 0;
-+ ns->stateidx = 0;
-+ ns->regs.num = 0;
-+ ns->regs.count = 0;
-+ ns->regs.off = 0;
-+ ns->regs.row = 0;
-+ ns->regs.column = 0;
-+ ns->regs.status = status;
-+}
-+
-+/*
-+ * If the operation isn't known yet, try to find it in the global array
-+ * of supported operations.
-+ *
-+ * Operation can be unknown because of the following.
-+ * 1. New command was accepted and this is the firs call to find the
-+ * correspondent states chain. In this case ns->npstates = 0;
-+ * 2. There is several operations which begin with the same command(s)
-+ * (for example program from the second half and read from the
-+ * second half operations both begin with the READ1 command). In this
-+ * case the ns->pstates[] array contains previous states.
-+ *
-+ * Thus, the function tries to find operation containing the following
-+ * states (if the 'flag' parameter is 0):
-+ * ns->pstates[0], ... ns->pstates[ns->npstates], ns->state
-+ *
-+ * If (one and only one) matching operation is found, it is accepted (
-+ * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is
-+ * zeroed).
-+ *
-+ * If there are several maches, the current state is pushed to the
-+ * ns->pstates.
-+ *
-+ * The operation can be unknown only while commands are input to the chip.
-+ * As soon as address command is accepted, the operation must be known.
-+ * In such situation the function is called with 'flag' != 0, and the
-+ * operation is searched using the following pattern:
-+ * ns->pstates[0], ... ns->pstates[ns->npstates], <address input>
-+ *
-+ * It is supposed that this pattern must either match one operation on
-+ * none. There can't be ambiguity in that case.
-+ *
-+ * If no matches found, the functions does the following:
-+ * 1. if there are saved states present, try to ignore them and search
-+ * again only using the last command. If nothing was found, switch
-+ * to the STATE_READY state.
-+ * 2. if there are no saved states, switch to the STATE_READY state.
-+ *
-+ * RETURNS: -2 - no matched operations found.
-+ * -1 - several matches.
-+ * 0 - operation is found.
-+ */
-+static int
-+find_operation(struct nandsim *ns, uint32_t flag)
-+{
-+ int opsfound = 0;
-+ int i, j, idx = 0;
-+
-+ for (i = 0; i < NS_OPER_NUM; i++) {
-+
-+ int found = 1;
-+
-+ if (!(ns->options & ops[i].reqopts))
-+ /* Ignore operations we can't perform */
-+ continue;
-+
-+ if (flag) {
-+ if (!(ops[i].states[ns->npstates] & STATE_ADDR_MASK))
-+ continue;
-+ } else {
-+ if (NS_STATE(ns->state) != NS_STATE(ops[i].states[ns->npstates]))
-+ continue;
-+ }
-+
-+ for (j = 0; j < ns->npstates; j++)
-+ if (NS_STATE(ops[i].states[j]) != NS_STATE(ns->pstates[j])
-+ && (ns->options & ops[idx].reqopts)) {
-+ found = 0;
-+ break;
-+ }
-+
-+ if (found) {
-+ idx = i;
-+ opsfound += 1;
-+ }
-+ }
-+
-+ if (opsfound == 1) {
-+ /* Exact match */
-+ ns->op = &ops[idx].states[0];
-+ if (flag) {
-+ /*
-+ * In this case the find_operation function was
-+ * called when address has just began input. But it isn't
-+ * yet fully input and the current state must
-+ * not be one of STATE_ADDR_*, but the STATE_ADDR_*
-+ * state must be the next state (ns->nxstate).
-+ */
-+ ns->stateidx = ns->npstates - 1;
-+ } else {
-+ ns->stateidx = ns->npstates;
-+ }
-+ ns->npstates = 0;
-+ ns->state = ns->op[ns->stateidx];
-+ ns->nxstate = ns->op[ns->stateidx + 1];
-+ NS_DBG("find_operation: operation found, index: %d, state: %s, nxstate %s\n",
-+ idx, get_state_name(ns->state), get_state_name(ns->nxstate));
-+ return 0;
-+ }
-+
-+ if (opsfound == 0) {
-+ /* Nothing was found. Try to ignore previous commands (if any) and search again */
-+ if (ns->npstates != 0) {
-+ NS_DBG("find_operation: no operation found, try again with state %s\n",
-+ get_state_name(ns->state));
-+ ns->npstates = 0;
-+ return find_operation(ns, 0);
-+
-+ }
-+ NS_DBG("find_operation: no operations found\n");
-+ switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-+ return -2;
-+ }
-+
-+ if (flag) {
-+ /* This shouldn't happen */
-+ NS_DBG("find_operation: BUG, operation must be known if address is input\n");
-+ return -2;
-+ }
-+
-+ NS_DBG("find_operation: there is still ambiguity\n");
-+
-+ ns->pstates[ns->npstates++] = ns->state;
-+
-+ return -1;
-+}
-+
-+/*
-+ * If state has any action bit, perform this action.
-+ *
-+ * RETURNS: 0 if success, -1 if error.
-+ */
-+static int
-+do_state_action(struct nandsim *ns, uint32_t action)
-+{
-+ int i, num;
-+ int busdiv = ns->busw == 8 ? 1 : 2;
-+
-+ action &= ACTION_MASK;
-+
-+ /* Check that page address input is correct */
-+ if (action != ACTION_SECERASE && ns->regs.row >= ns->geom.pgnum) {
-+ NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs.row);
-+ return -1;
-+ }
-+
-+ switch (action) {
-+
-+ case ACTION_CPY:
-+ /*
-+ * Copy page data to the internal buffer.
-+ */
-+
-+ /* Column shouldn't be very large */
-+ if (ns->regs.column >= (ns->geom.pgszoob - ns->regs.off)) {
-+ NS_ERR("do_state_action: column number is too large\n");
-+ break;
-+ }
-+ num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
-+ memcpy(ns->buf.byte, ns->mem.byte + NS_RAW_OFFSET(ns) + ns->regs.off, num);
-+
-+ NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
-+ num, NS_RAW_OFFSET(ns) + ns->regs.off);
-+
-+ if (ns->regs.off == 0)
-+ NS_LOG("read page %d\n", ns->regs.row);
-+ else if (ns->regs.off < ns->geom.pgsz)
-+ NS_LOG("read page %d (second half)\n", ns->regs.row);
-+ else
-+ NS_LOG("read OOB of page %d\n", ns->regs.row);
-+
-+ NS_UDELAY(access_delay);
-+ NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv);
-+
-+ break;
-+
-+ case ACTION_SECERASE:
-+ /*
-+ * Erase sector.
-+ */
-+
-+ if (ns->lines.wp) {
-+ NS_ERR("do_state_action: device is write-protected, ignore sector erase\n");
-+ return -1;
-+ }
-+
-+ if (ns->regs.row >= ns->geom.pgnum - ns->geom.pgsec
-+ || (ns->regs.row & ~(ns->geom.secsz - 1))) {
-+ NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs.row);
-+ return -1;
-+ }
-+
-+ ns->regs.row = (ns->regs.row <<
-+ 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column;
-+ ns->regs.column = 0;
-+
-+ NS_DBG("do_state_action: erase sector at address %#x, off = %d\n",
-+ ns->regs.row, NS_RAW_OFFSET(ns));
-+ NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift));
-+
-+ memset(ns->mem.byte + NS_RAW_OFFSET(ns), 0xFF, ns->geom.secszoob);
-+
-+ NS_MDELAY(erase_delay);
-+
-+ break;
-+
-+ case ACTION_PRGPAGE:
-+ /*
-+ * Programm page - move internal buffer data to the page.
-+ */
-+
-+ if (ns->lines.wp) {
-+ NS_WARN("do_state_action: device is write-protected, programm\n");
-+ return -1;
-+ }
-+
-+ num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
-+ if (num != ns->regs.count) {
-+ NS_ERR("do_state_action: too few bytes were input (%d instead of %d)\n",
-+ ns->regs.count, num);
-+ return -1;
-+ }
-+
-+ for (i = 0; i < num; i++)
-+ ns->mem.byte[NS_RAW_OFFSET(ns) + ns->regs.off + i] &= ns->buf.byte[i];
-+
-+ NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
-+ num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
-+ NS_LOG("programm page %d\n", ns->regs.row);
-+
-+ NS_UDELAY(programm_delay);
-+ NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
-+
-+ break;
-+
-+ case ACTION_ZEROOFF:
-+ NS_DBG("do_state_action: set internal offset to 0\n");
-+ ns->regs.off = 0;
-+ break;
-+
-+ case ACTION_HALFOFF:
-+ if (!(ns->options & OPT_PAGE512_8BIT)) {
-+ NS_ERR("do_state_action: BUG! can't skip half of page for non-512"
-+ "byte page size 8x chips\n");
-+ return -1;
-+ }
-+ NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz/2);
-+ ns->regs.off = ns->geom.pgsz/2;
-+ break;
-+
-+ case ACTION_OOBOFF:
-+ NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz);
-+ ns->regs.off = ns->geom.pgsz;
-+ break;
-+
-+ default:
-+ NS_DBG("do_state_action: BUG! unknown action\n");
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * Switch simulator's state.
-+ */
-+static void
-+switch_state(struct nandsim *ns)
-+{
-+ if (ns->op) {
-+ /*
-+ * The current operation have already been identified.
-+ * Just follow the states chain.
-+ */
-+
-+ ns->stateidx += 1;
-+ ns->state = ns->nxstate;
-+ ns->nxstate = ns->op[ns->stateidx + 1];
-+
-+ NS_DBG("switch_state: operation is known, switch to the next state, "
-+ "state: %s, nxstate: %s\n",
-+ get_state_name(ns->state), get_state_name(ns->nxstate));
-+
-+ /* See, whether we need to do some action */
-+ if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
-+ switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-+ return;
-+ }
-+
-+ } else {
-+ /*
-+ * We don't yet know which operation we perform.
-+ * Try to identify it.
-+ */
-+
-+ /*
-+ * The only event causing the switch_state function to
-+ * be called with yet unknown operation is new command.
-+ */
-+ ns->state = get_state_by_command(ns->regs.command);
-+
-+ NS_DBG("switch_state: operation is unknown, try to find it\n");
-+
-+ if (find_operation(ns, 0) != 0)
-+ return;
-+
-+ if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
-+ switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-+ return;
-+ }
-+ }
-+
-+ /* For 16x devices column means the page offset in words */
-+ if ((ns->nxstate & STATE_ADDR_MASK) && ns->busw == 16) {
-+ NS_DBG("switch_state: double the column number for 16x device\n");
-+ ns->regs.column <<= 1;
-+ }
-+
-+ if (NS_STATE(ns->nxstate) == STATE_READY) {
-+ /*
-+ * The current state is the last. Return to STATE_READY
-+ */
-+
-+ u_char status = NS_STATUS_OK(ns);
-+
-+ /* In case of data states, see if all bytes were input/output */
-+ if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK))
-+ && ns->regs.count != ns->regs.num) {
-+ NS_WARN("switch_state: not all bytes were processed, %d left\n",
-+ ns->regs.num - ns->regs.count);
-+ status = NS_STATUS_FAILED(ns);
-+ }
-+
-+ NS_DBG("switch_state: operation complete, switch to STATE_READY state\n");
-+
-+ switch_to_ready_state(ns, status);
-+
-+ return;
-+ } else if (ns->nxstate & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) {
-+ /*
-+ * If the next state is data input/output, switch to it now
-+ */
-+
-+ ns->state = ns->nxstate;
-+ ns->nxstate = ns->op[++ns->stateidx + 1];
-+ ns->regs.num = ns->regs.count = 0;
-+
-+ NS_DBG("switch_state: the next state is data I/O, switch, "
-+ "state: %s, nxstate: %s\n",
-+ get_state_name(ns->state), get_state_name(ns->nxstate));
-+
-+ /*
-+ * Set the internal register to the count of bytes which
-+ * are expected to be input or output
-+ */
-+ switch (NS_STATE(ns->state)) {
-+ case STATE_DATAIN:
-+ case STATE_DATAOUT:
-+ ns->regs.num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
-+ break;
-+
-+ case STATE_DATAOUT_ID:
-+ ns->regs.num = ns->geom.idbytes;
-+ break;
-+
-+ case STATE_DATAOUT_STATUS:
-+ case STATE_DATAOUT_STATUS_M:
-+ ns->regs.count = ns->regs.num = 0;
-+ break;
-+
-+ default:
-+ NS_ERR("switch_state: BUG! unknown data state\n");
-+ }
-+
-+ } else if (ns->nxstate & STATE_ADDR_MASK) {
-+ /*
-+ * If the next state is address input, set the internal
-+ * register to the number of expected address bytes
-+ */
-+
-+ ns->regs.count = 0;
-+
-+ switch (NS_STATE(ns->nxstate)) {
-+ case STATE_ADDR_PAGE:
-+ ns->regs.num = ns->geom.pgaddrbytes;
-+
-+ break;
-+ case STATE_ADDR_SEC:
-+ ns->regs.num = ns->geom.secaddrbytes;
-+ break;
-+
-+ case STATE_ADDR_ZERO:
-+ ns->regs.num = 1;
-+ break;
-+
-+ default:
-+ NS_ERR("switch_state: BUG! unknown address state\n");
-+ }
-+ } else {
-+ /*
-+ * Just reset internal counters.
-+ */
-+
-+ ns->regs.num = 0;
-+ ns->regs.count = 0;
-+ }
-+}
-+
-+static void
-+ns_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+ struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
-+
-+ switch (cmd) {
-+
-+ /* set CLE line high */
-+ case NAND_CTL_SETCLE:
-+ NS_DBG("ns_hwcontrol: start command latch cycles\n");
-+ ns->lines.cle = 1;
-+ break;
-+
-+ /* set CLE line low */
-+ case NAND_CTL_CLRCLE:
-+ NS_DBG("ns_hwcontrol: stop command latch cycles\n");
-+ ns->lines.cle = 0;
-+ break;
-+
-+ /* set ALE line high */
-+ case NAND_CTL_SETALE:
-+ NS_DBG("ns_hwcontrol: start address latch cycles\n");
-+ ns->lines.ale = 1;
-+ break;
-+
-+ /* set ALE line low */
-+ case NAND_CTL_CLRALE:
-+ NS_DBG("ns_hwcontrol: stop address latch cycles\n");
-+ ns->lines.ale = 0;
-+ break;
-+
-+ /* set WP line high */
-+ case NAND_CTL_SETWP:
-+ NS_DBG("ns_hwcontrol: enable write protection\n");
-+ ns->lines.wp = 1;
-+ break;
-+
-+ /* set WP line low */
-+ case NAND_CTL_CLRWP:
-+ NS_DBG("ns_hwcontrol: disable write protection\n");
-+ ns->lines.wp = 0;
-+ break;
-+
-+ /* set CE line low */
-+ case NAND_CTL_SETNCE:
-+ NS_DBG("ns_hwcontrol: enable chip\n");
-+ ns->lines.ce = 1;
-+ break;
-+
-+ /* set CE line high */
-+ case NAND_CTL_CLRNCE:
-+ NS_DBG("ns_hwcontrol: disable chip\n");
-+ ns->lines.ce = 0;
-+ break;
-+
-+ default:
-+ NS_ERR("hwcontrol: unknown command\n");
-+ }
-+
-+ return;
-+}
-+
-+static u_char
-+ns_nand_read_byte(struct mtd_info *mtd)
-+{
-+ struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
-+ u_char outb = 0x00;
-+
-+ /* Sanity and correctness checks */
-+ if (!ns->lines.ce) {
-+ NS_ERR("read_byte: chip is disabled, return %#x\n", (uint)outb);
-+ return outb;
-+ }
-+ if (ns->lines.ale || ns->lines.cle) {
-+ NS_ERR("read_byte: ALE or CLE pin is high, return %#x\n", (uint)outb);
-+ return outb;
-+ }
-+ if (!(ns->state & STATE_DATAOUT_MASK)) {
-+ NS_WARN("read_byte: unexpected data output cycle, state is %s "
-+ "return %#x\n", get_state_name(ns->state), (uint)outb);
-+ return outb;
-+ }
-+
-+ /* Status register may be read as many times as it is wanted */
-+ if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS) {
-+ NS_DBG("read_byte: return %#x status\n", ns->regs.status);
-+ return ns->regs.status;
-+ }
-+
-+ /* Check if there is any data in the internal buffer which may be read */
-+ if (ns->regs.count == ns->regs.num) {
-+ NS_WARN("read_byte: no more data to output, return %#x\n", (uint)outb);
-+ return outb;
-+ }
-+
-+ switch (NS_STATE(ns->state)) {
-+ case STATE_DATAOUT:
-+ if (ns->busw == 8) {
-+ outb = ns->buf.byte[ns->regs.count];
-+ ns->regs.count += 1;
-+ } else {
-+ outb = (u_char)cpu_to_le16(ns->buf.word[ns->regs.count >> 1]);
-+ ns->regs.count += 2;
-+ }
-+ break;
-+ case STATE_DATAOUT_ID:
-+ NS_DBG("read_byte: read ID byte %d, total = %d\n", ns->regs.count, ns->regs.num);
-+ outb = ns->ids[ns->regs.count];
-+ ns->regs.count += 1;
-+ break;
-+ default:
-+ BUG();
-+ }
-+
-+ if (ns->regs.count == ns->regs.num) {
-+ NS_DBG("read_byte: all bytes were read\n");
-+
-+ /*
-+ * The OPT_AUTOINCR allows to read next conseqitive pages without
-+ * new read operation cycle.
-+ */
-+ if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) {
-+ ns->regs.count = 0;
-+ if (ns->regs.row + 1 < ns->geom.pgnum)
-+ ns->regs.row += 1;
-+ NS_DBG("read_byte: switch to the next page (%#x)\n", ns->regs.row);
-+ do_state_action(ns, ACTION_CPY);
-+ }
-+ else if (NS_STATE(ns->nxstate) == STATE_READY)
-+ switch_state(ns);
-+
-+ }
-+
-+ return outb;
-+}
-+
-+static void
-+ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
-+{
-+ struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
-+
-+ /* Sanity and correctness checks */
-+ if (!ns->lines.ce) {
-+ NS_ERR("write_byte: chip is disabled, ignore write\n");
-+ return;
-+ }
-+ if (ns->lines.ale && ns->lines.cle) {
-+ NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n");
-+ return;
-+ }
-+
-+ if (ns->lines.cle == 1) {
-+ /*
-+ * The byte written is a command.
-+ */
-+
-+ if (byte == NAND_CMD_RESET) {
-+ NS_LOG("reset chip\n");
-+ switch_to_ready_state(ns, NS_STATUS_OK(ns));
-+ return;
-+ }
-+
-+ /*
-+ * Chip might still be in STATE_DATAOUT
-+ * (if OPT_AUTOINCR feature is supported), STATE_DATAOUT_STATUS or
-+ * STATE_DATAOUT_STATUS_M state. If so, switch state.
-+ */
-+ if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS
-+ || NS_STATE(ns->state) == STATE_DATAOUT_STATUS_M
-+ || ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT))
-+ switch_state(ns);
-+
-+ /* Check if chip is expecting command */
-+ if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) {
-+ /*
-+ * We are in situation when something else (not command)
-+ * was expected but command was input. In this case ignore
-+ * previous command(s)/state(s) and accept the last one.
-+ */
-+ NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, "
-+ "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate));
-+ switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-+ }
-+
-+ /* Check that the command byte is correct */
-+ if (check_command(byte)) {
-+ NS_ERR("write_byte: unknown command %#x\n", (uint)byte);
-+ return;
-+ }
-+
-+ NS_DBG("command byte corresponding to %s state accepted\n",
-+ get_state_name(get_state_by_command(byte)));
-+ ns->regs.command = byte;
-+ switch_state(ns);
-+
-+ } else if (ns->lines.ale == 1) {
-+ /*
-+ * The byte written is an address.
-+ */
-+
-+ if (NS_STATE(ns->nxstate) == STATE_UNKNOWN) {
-+
-+ NS_DBG("write_byte: operation isn't known yet, identify it\n");
-+
-+ if (find_operation(ns, 1) < 0)
-+ return;
-+
-+ if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
-+ switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-+ return;
-+ }
-+
-+ ns->regs.count = 0;
-+ switch (NS_STATE(ns->nxstate)) {
-+ case STATE_ADDR_PAGE:
-+ ns->regs.num = ns->geom.pgaddrbytes;
-+ break;
-+ case STATE_ADDR_SEC:
-+ ns->regs.num = ns->geom.secaddrbytes;
-+ break;
-+ case STATE_ADDR_ZERO:
-+ ns->regs.num = 1;
-+ break;
-+ default:
-+ BUG();
-+ }
-+ }
-+
-+ /* Check that chip is expecting address */
-+ if (!(ns->nxstate & STATE_ADDR_MASK)) {
-+ NS_ERR("write_byte: address (%#x) isn't expected, expected state is %s, "
-+ "switch to STATE_READY\n", (uint)byte, get_state_name(ns->nxstate));
-+ switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-+ return;
-+ }
-+
-+ /* Check if this is expected byte */
-+ if (ns->regs.count == ns->regs.num) {
-+ NS_ERR("write_byte: no more address bytes expected\n");
-+ switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-+ return;
-+ }
-+
-+ accept_addr_byte(ns, byte);
-+
-+ ns->regs.count += 1;
-+
-+ NS_DBG("write_byte: address byte %#x was accepted (%d bytes input, %d expected)\n",
-+ (uint)byte, ns->regs.count, ns->regs.num);
-+
-+ if (ns->regs.count == ns->regs.num) {
-+ NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column);
-+ switch_state(ns);
-+ }
-+
-+ } else {
-+ /*
-+ * The byte written is an input data.
-+ */
-+
-+ /* Check that chip is expecting data input */
-+ if (!(ns->state & STATE_DATAIN_MASK)) {
-+ NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, "
-+ "switch to %s\n", (uint)byte,
-+ get_state_name(ns->state), get_state_name(STATE_READY));
-+ switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-+ return;
-+ }
-+
-+ /* Check if this is expected byte */
-+ if (ns->regs.count == ns->regs.num) {
-+ NS_WARN("write_byte: %u input bytes has already been accepted, ignore write\n",
-+ ns->regs.num);
-+ return;
-+ }
-+
-+ if (ns->busw == 8) {
-+ ns->buf.byte[ns->regs.count] = byte;
-+ ns->regs.count += 1;
-+ } else {
-+ ns->buf.word[ns->regs.count >> 1] = cpu_to_le16((uint16_t)byte);
-+ ns->regs.count += 2;
-+ }
-+ }
-+
-+ return;
-+}
-+
-+static int
-+ns_device_ready(struct mtd_info *mtd)
-+{
-+ NS_DBG("device_ready\n");
-+ return 1;
-+}
-+
-+static uint16_t
-+ns_nand_read_word(struct mtd_info *mtd)
-+{
-+ struct nand_chip *chip = (struct nand_chip *)mtd->priv;
-+
-+ NS_DBG("read_word\n");
-+
-+ return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
-+}
-+
-+static void
-+ns_nand_write_word(struct mtd_info *mtd, uint16_t word)
-+{
-+ struct nand_chip *chip = (struct nand_chip *)mtd->priv;
-+
-+ NS_DBG("write_word\n");
-+
-+ chip->write_byte(mtd, word & 0xFF);
-+ chip->write_byte(mtd, word >> 8);
-+}
-+
-+static void
-+ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+ struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
-+
-+ /* Check that chip is expecting data input */
-+ if (!(ns->state & STATE_DATAIN_MASK)) {
-+ NS_ERR("write_buf: data input isn't expected, state is %s, "
-+ "switch to STATE_READY\n", get_state_name(ns->state));
-+ switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-+ return;
-+ }
-+
-+ /* Check if these are expected bytes */
-+ if (ns->regs.count + len > ns->regs.num) {
-+ NS_ERR("write_buf: too many input bytes\n");
-+ switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-+ return;
-+ }
-+
-+ memcpy(ns->buf.byte + ns->regs.count, buf, len);
-+ ns->regs.count += len;
-+
-+ if (ns->regs.count == ns->regs.num) {
-+ NS_DBG("write_buf: %d bytes were written\n", ns->regs.count);
-+ }
-+}
-+
-+static void
-+ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-+{
-+ struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
-+
-+ /* Sanity and correctness checks */
-+ if (!ns->lines.ce) {
-+ NS_ERR("read_buf: chip is disabled\n");
-+ return;
-+ }
-+ if (ns->lines.ale || ns->lines.cle) {
-+ NS_ERR("read_buf: ALE or CLE pin is high\n");
-+ return;
-+ }
-+ if (!(ns->state & STATE_DATAOUT_MASK)) {
-+ NS_WARN("read_buf: unexpected data output cycle, current state is %s\n",
-+ get_state_name(ns->state));
-+ return;
-+ }
-+
-+ if (NS_STATE(ns->state) != STATE_DATAOUT) {
-+ int i;
-+
-+ for (i = 0; i < len; i++)
-+ buf[i] = ((struct nand_chip *)mtd->priv)->read_byte(mtd);
-+
-+ return;
-+ }
-+
-+ /* Check if these are expected bytes */
-+ if (ns->regs.count + len > ns->regs.num) {
-+ NS_ERR("read_buf: too many bytes to read\n");
-+ switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-+ return;
-+ }
-+
-+ memcpy(buf, ns->buf.byte + ns->regs.count, len);
-+ ns->regs.count += len;
-+
-+ if (ns->regs.count == ns->regs.num) {
-+ if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) {
-+ ns->regs.count = 0;
-+ if (ns->regs.row + 1 < ns->geom.pgnum)
-+ ns->regs.row += 1;
-+ NS_DBG("read_buf: switch to the next page (%#x)\n", ns->regs.row);
-+ do_state_action(ns, ACTION_CPY);
-+ }
-+ else if (NS_STATE(ns->nxstate) == STATE_READY)
-+ switch_state(ns);
-+ }
-+
-+ return;
-+}
-+
-+static int
-+ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+ ns_nand_read_buf(mtd, (u_char *)&ns_verify_buf[0], len);
-+
-+ if (!memcmp(buf, &ns_verify_buf[0], len)) {
-+ NS_DBG("verify_buf: the buffer is OK\n");
-+ return 0;
-+ } else {
-+ NS_DBG("verify_buf: the buffer is wrong\n");
-+ return -EFAULT;
-+ }
-+}
-+
-+/*
-+ * Having only NAND chip IDs we call nand_scan which detects NAND flash
-+ * parameters and then calls scan_bbt in order to scan/find/build the
-+ * NAND flash bad block table. But since at that moment the NAND flash
-+ * image isn't allocated in the simulator, errors arise. To avoid this
-+ * we redefine the scan_bbt callback and initialize the nandsim structure
-+ * before the flash media scanning.
-+ */
-+int ns_scan_bbt(struct mtd_info *mtd)
-+{
-+ struct nand_chip *chip = (struct nand_chip *)mtd->priv;
-+ struct nandsim *ns = (struct nandsim *)(chip->priv);
-+ int retval;
-+
-+ if (!NS_IS_INITIALIZED(ns))
-+ if ((retval = init_nandsim(mtd)) != 0) {
-+ NS_ERR("scan_bbt: can't initialize the nandsim structure\n");
-+ return retval;
-+ }
-+ if ((retval = nand_default_bbt(mtd)) != 0) {
-+ free_nandsim(ns);
-+ return retval;
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * Module initialization function
-+ */
-+int __init ns_init_module(void)
-+{
-+ struct nand_chip *chip;
-+ struct nandsim *nand;
-+ int retval = -ENOMEM;
-+
-+ if (bus_width != 8 && bus_width != 16) {
-+ NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width);
-+ return -EINVAL;
-+ }
-+
-+ /* Allocate and initialize mtd_info, nand_chip and nandsim structures */
-+ nsmtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip)
-+ + sizeof(struct nandsim), GFP_KERNEL);
-+ if (!nsmtd) {
-+ NS_ERR("unable to allocate core structures.\n");
-+ return -ENOMEM;
-+ }
-+ memset(nsmtd, 0, sizeof(struct mtd_info) + sizeof(struct nand_chip) +
-+ sizeof(struct nandsim));
-+ chip = (struct nand_chip *)(nsmtd + 1);
-+ nsmtd->priv = (void *)chip;
-+ nand = (struct nandsim *)(chip + 1);
-+ chip->priv = (void *)nand;
-+
-+ /*
-+ * Register simulator's callbacks.
-+ */
-+ chip->hwcontrol = ns_hwcontrol;
-+ chip->read_byte = ns_nand_read_byte;
-+ chip->dev_ready = ns_device_ready;
-+ chip->scan_bbt = ns_scan_bbt;
-+ chip->write_byte = ns_nand_write_byte;
-+ chip->write_buf = ns_nand_write_buf;
-+ chip->read_buf = ns_nand_read_buf;
-+ chip->verify_buf = ns_nand_verify_buf;
-+ chip->write_word = ns_nand_write_word;
-+ chip->read_word = ns_nand_read_word;
-+ chip->eccmode = NAND_ECC_SOFT;
-+
-+ /*
-+ * Perform minimum nandsim structure initialization to handle
-+ * the initial ID read command correctly
-+ */
-+ if (third_id_byte != 0xFF || fourth_id_byte != 0xFF)
-+ nand->geom.idbytes = 4;
-+ else
-+ nand->geom.idbytes = 2;
-+ nand->regs.status = NS_STATUS_OK(nand);
-+ nand->nxstate = STATE_UNKNOWN;
-+ nand->options |= OPT_PAGE256; /* temporary value */
-+ nand->ids[0] = first_id_byte;
-+ nand->ids[1] = second_id_byte;
-+ nand->ids[2] = third_id_byte;
-+ nand->ids[3] = fourth_id_byte;
-+ if (bus_width == 16) {
-+ nand->busw = 16;
-+ chip->options |= NAND_BUSWIDTH_16;
-+ }
-+
-+ if ((retval = nand_scan(nsmtd, 1)) != 0) {
-+ NS_ERR("can't register NAND Simulator\n");
-+ if (retval > 0)
-+ retval = -ENXIO;
-+ goto error;
-+ }
-+
-+ /* Register NAND as one big partition */
-+ add_mtd_partitions(nsmtd, &nand->part, 1);
-+
-+ return 0;
-+
-+error:
-+ kfree(nsmtd);
-+
-+ return retval;
-+}
-+
-+module_init(ns_init_module);
-+
-+/*
-+ * Module clean-up function
-+ */
-+static void __exit ns_cleanup_module(void)
-+{
-+ struct nandsim *ns = (struct nandsim *)(((struct nand_chip *)nsmtd->priv)->priv);
-+
-+ free_nandsim(ns); /* Free nandsim private resources */
-+ nand_release(nsmtd); /* Unregisterd drived */
-+ kfree(nsmtd); /* Free other structures */
-+}
-+
-+module_exit(ns_cleanup_module);
-+
-+MODULE_LICENSE ("GPL");
-+MODULE_AUTHOR ("Artem B. Bityuckiy");
-+MODULE_DESCRIPTION ("The NAND flash simulator");
-+
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/nand/ppchameleonevb.c
-@@ -0,0 +1,420 @@
-+/*
-+ * drivers/mtd/nand/ppchameleonevb.c
-+ *
-+ * Copyright (C) 2003 DAVE Srl (info@wawnet.biz)
-+ *
-+ * Derived from drivers/mtd/nand/edb7312.c
-+ *
-+ *
-+ * $Id: ppchameleonevb.c,v 1.6 2004/11/05 16:07:16 kalev 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.
-+ *
-+ * Overview:
-+ * This is a device driver for the NAND flash devices found on the
-+ * PPChameleon/PPChameleonEVB system.
-+ * PPChameleon options (autodetected):
-+ * - BA model: no NAND
-+ * - ME model: 32MB (Samsung K9F5608U0B)
-+ * - HI model: 128MB (Samsung K9F1G08UOM)
-+ * PPChameleonEVB options:
-+ * - 32MB (Samsung K9F5608U0B)
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/io.h>
-+#include <platforms/PPChameleonEVB.h>
-+
-+#undef USE_READY_BUSY_PIN
-+#define USE_READY_BUSY_PIN
-+/* see datasheets (tR) */
-+#define NAND_BIG_DELAY_US 25
-+#define NAND_SMALL_DELAY_US 10
-+
-+/* handy sizes */
-+#define SZ_4M 0x00400000
-+#define NAND_SMALL_SIZE 0x02000000
-+#define NAND_MTD_NAME "ppchameleon-nand"
-+#define NAND_EVB_MTD_NAME "ppchameleonevb-nand"
-+
-+/* GPIO pins used to drive NAND chip mounted on processor module */
-+#define NAND_nCE_GPIO_PIN (0x80000000 >> 1)
-+#define NAND_CLE_GPIO_PIN (0x80000000 >> 2)
-+#define NAND_ALE_GPIO_PIN (0x80000000 >> 3)
-+#define NAND_RB_GPIO_PIN (0x80000000 >> 4)
-+/* GPIO pins used to drive NAND chip mounted on EVB */
-+#define NAND_EVB_nCE_GPIO_PIN (0x80000000 >> 14)
-+#define NAND_EVB_CLE_GPIO_PIN (0x80000000 >> 15)
-+#define NAND_EVB_ALE_GPIO_PIN (0x80000000 >> 16)
-+#define NAND_EVB_RB_GPIO_PIN (0x80000000 >> 31)
-+
-+/*
-+ * MTD structure for PPChameleonEVB board
-+ */
-+static struct mtd_info *ppchameleon_mtd = NULL;
-+static struct mtd_info *ppchameleonevb_mtd = NULL;
-+
-+/*
-+ * Module stuff
-+ */
-+static unsigned long ppchameleon_fio_pbase = CFG_NAND0_PADDR;
-+static unsigned long ppchameleonevb_fio_pbase = CFG_NAND1_PADDR;
-+
-+#ifdef MODULE
-+module_param(ppchameleon_fio_pbase, ulong, 0);
-+module_param(ppchameleonevb_fio_pbase, ulong, 0);
-+#else
-+__setup("ppchameleon_fio_pbase=",ppchameleon_fio_pbase);
-+__setup("ppchameleonevb_fio_pbase=",ppchameleonevb_fio_pbase);
-+#endif
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+/*
-+ * Define static partitions for flash devices
-+ */
-+static struct mtd_partition partition_info_hi[] = {
-+ { name: "PPChameleon HI Nand Flash",
-+ offset: 0,
-+ size: 128*1024*1024 }
-+};
-+
-+static struct mtd_partition partition_info_me[] = {
-+ { name: "PPChameleon ME Nand Flash",
-+ offset: 0,
-+ size: 32*1024*1024 }
-+};
-+
-+static struct mtd_partition partition_info_evb[] = {
-+ { name: "PPChameleonEVB Nand Flash",
-+ offset: 0,
-+ size: 32*1024*1024 }
-+};
-+
-+#define NUM_PARTITIONS 1
-+
-+extern int parse_cmdline_partitions(struct mtd_info *master,
-+ struct mtd_partition **pparts,
-+ const char *mtd_id);
-+#endif
-+
-+
-+/*
-+ * hardware specific access to control-lines
-+ */
-+static void ppchameleon_hwcontrol(struct mtd_info *mtdinfo, int cmd)
-+{
-+ switch(cmd) {
-+
-+ case NAND_CTL_SETCLE:
-+ MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND0_PADDR);
-+ break;
-+ case NAND_CTL_CLRCLE:
-+ MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND0_PADDR);
-+ break;
-+ case NAND_CTL_SETALE:
-+ MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND0_PADDR);
-+ break;
-+ case NAND_CTL_CLRALE:
-+ MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND0_PADDR);
-+ break;
-+ case NAND_CTL_SETNCE:
-+ MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND0_PADDR);
-+ break;
-+ case NAND_CTL_CLRNCE:
-+ MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND0_PADDR);
-+ break;
-+ }
-+}
-+
-+static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd)
-+{
-+ switch(cmd) {
-+
-+ case NAND_CTL_SETCLE:
-+ MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND1_PADDR);
-+ break;
-+ case NAND_CTL_CLRCLE:
-+ MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND1_PADDR);
-+ break;
-+ case NAND_CTL_SETALE:
-+ MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND1_PADDR);
-+ break;
-+ case NAND_CTL_CLRALE:
-+ MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND1_PADDR);
-+ break;
-+ case NAND_CTL_SETNCE:
-+ MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND1_PADDR);
-+ break;
-+ case NAND_CTL_CLRNCE:
-+ MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND1_PADDR);
-+ break;
-+ }
-+}
-+
-+#ifdef USE_READY_BUSY_PIN
-+/*
-+ * read device ready pin
-+ */
-+static int ppchameleon_device_ready(struct mtd_info *minfo)
-+{
-+ if (in_be32((volatile unsigned*)GPIO0_IR) & NAND_RB_GPIO_PIN)
-+ return 1;
-+ return 0;
-+}
-+
-+static int ppchameleonevb_device_ready(struct mtd_info *minfo)
-+{
-+ if (in_be32((volatile unsigned*)GPIO0_IR) & NAND_EVB_RB_GPIO_PIN)
-+ return 1;
-+ return 0;
-+}
-+#endif
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+const char *part_probes[] = { "cmdlinepart", NULL };
-+const char *part_probes_evb[] = { "cmdlinepart", NULL };
-+#endif
-+
-+/*
-+ * Main initialization routine
-+ */
-+static int __init ppchameleonevb_init (void)
-+{
-+ struct nand_chip *this;
-+ const char *part_type = 0;
-+ int mtd_parts_nb = 0;
-+ struct mtd_partition *mtd_parts = 0;
-+ void __iomem *ppchameleon_fio_base;
-+ void __iomem *ppchameleonevb_fio_base;
-+
-+
-+ /*********************************
-+ * Processor module NAND (if any) *
-+ *********************************/
-+ /* Allocate memory for MTD device structure and private data */
-+ ppchameleon_mtd = kmalloc(sizeof(struct mtd_info) +
-+ sizeof(struct nand_chip), GFP_KERNEL);
-+ if (!ppchameleon_mtd) {
-+ printk("Unable to allocate PPChameleon NAND MTD device structure.\n");
-+ return -ENOMEM;
-+ }
-+
-+ /* map physical address */
-+ ppchameleon_fio_base = ioremap(ppchameleon_fio_pbase, SZ_4M);
-+ if(!ppchameleon_fio_base) {
-+ printk("ioremap PPChameleon NAND flash failed\n");
-+ kfree(ppchameleon_mtd);
-+ return -EIO;
-+ }
-+
-+ /* Get pointer to private data */
-+ this = (struct nand_chip *) (&ppchameleon_mtd[1]);
-+
-+ /* Initialize structures */
-+ memset((char *) ppchameleon_mtd, 0, sizeof(struct mtd_info));
-+ memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+ /* Link the private data with the MTD structure */
-+ ppchameleon_mtd->priv = this;
-+
-+ /* Initialize GPIOs */
-+ /* Pin mapping for NAND chip */
-+ /*
-+ CE GPIO_01
-+ CLE GPIO_02
-+ ALE GPIO_03
-+ R/B GPIO_04
-+ */
-+ /* output select */
-+ out_be32((volatile unsigned*)GPIO0_OSRH, in_be32((volatile unsigned*)GPIO0_OSRH) & 0xC0FFFFFF);
-+ /* three-state select */
-+ out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xC0FFFFFF);
-+ /* enable output driver */
-+ out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_nCE_GPIO_PIN | NAND_CLE_GPIO_PIN | NAND_ALE_GPIO_PIN);
-+#ifdef USE_READY_BUSY_PIN
-+ /* three-state select */
-+ out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFF3FFFFF);
-+ /* high-impedecence */
-+ out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) & (~NAND_RB_GPIO_PIN));
-+ /* input select */
-+ out_be32((volatile unsigned*)GPIO0_ISR1H, (in_be32((volatile unsigned*)GPIO0_ISR1H) & 0xFF3FFFFF) | 0x00400000);
-+#endif
-+
-+ /* insert callbacks */
-+ this->IO_ADDR_R = ppchameleon_fio_base;
-+ this->IO_ADDR_W = ppchameleon_fio_base;
-+ this->hwcontrol = ppchameleon_hwcontrol;
-+#ifdef USE_READY_BUSY_PIN
-+ this->dev_ready = ppchameleon_device_ready;
-+#endif
-+ this->chip_delay = NAND_BIG_DELAY_US;
-+ /* ECC mode */
-+ this->eccmode = NAND_ECC_SOFT;
-+
-+ /* Scan to find existence of the device (it could not be mounted) */
-+ if (nand_scan (ppchameleon_mtd, 1)) {
-+ iounmap((void *)ppchameleon_fio_base);
-+ kfree (ppchameleon_mtd);
-+ goto nand_evb_init;
-+ }
-+
-+#ifndef USE_READY_BUSY_PIN
-+ /* Adjust delay if necessary */
-+ if (ppchameleon_mtd->size == NAND_SMALL_SIZE)
-+ this->chip_delay = NAND_SMALL_DELAY_US;
-+#endif
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+ ppchameleon_mtd->name = "ppchameleon-nand";
-+ mtd_parts_nb = parse_mtd_partitions(ppchameleon_mtd, part_probes, &mtd_parts, 0);
-+ if (mtd_parts_nb > 0)
-+ part_type = "command line";
-+ else
-+ mtd_parts_nb = 0;
-+#endif
-+ if (mtd_parts_nb == 0)
-+ {
-+ if (ppchameleon_mtd->size == NAND_SMALL_SIZE)
-+ mtd_parts = partition_info_me;
-+ else
-+ mtd_parts = partition_info_hi;
-+ mtd_parts_nb = NUM_PARTITIONS;
-+ part_type = "static";
-+ }
-+
-+ /* Register the partitions */
-+ printk(KERN_NOTICE "Using %s partition definition\n", part_type);
-+ add_mtd_partitions(ppchameleon_mtd, mtd_parts, mtd_parts_nb);
-+
-+nand_evb_init:
-+ /****************************
-+ * EVB NAND (always present) *
-+ ****************************/
-+ /* Allocate memory for MTD device structure and private data */
-+ ppchameleonevb_mtd = kmalloc(sizeof(struct mtd_info) +
-+ sizeof(struct nand_chip), GFP_KERNEL);
-+ if (!ppchameleonevb_mtd) {
-+ printk("Unable to allocate PPChameleonEVB NAND MTD device structure.\n");
-+ return -ENOMEM;
-+ }
-+
-+ /* map physical address */
-+ ppchameleonevb_fio_base = ioremap(ppchameleonevb_fio_pbase, SZ_4M);
-+ if(!ppchameleonevb_fio_base) {
-+ printk("ioremap PPChameleonEVB NAND flash failed\n");
-+ kfree(ppchameleonevb_mtd);
-+ return -EIO;
-+ }
-+
-+ /* Get pointer to private data */
-+ this = (struct nand_chip *) (&ppchameleonevb_mtd[1]);
-+
-+ /* Initialize structures */
-+ memset((char *) ppchameleonevb_mtd, 0, sizeof(struct mtd_info));
-+ memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+ /* Link the private data with the MTD structure */
-+ ppchameleonevb_mtd->priv = this;
-+
-+ /* Initialize GPIOs */
-+ /* Pin mapping for NAND chip */
-+ /*
-+ CE GPIO_14
-+ CLE GPIO_15
-+ ALE GPIO_16
-+ R/B GPIO_31
-+ */
-+ /* output select */
-+ out_be32((volatile unsigned*)GPIO0_OSRH, in_be32((volatile unsigned*)GPIO0_OSRH) & 0xFFFFFFF0);
-+ out_be32((volatile unsigned*)GPIO0_OSRL, in_be32((volatile unsigned*)GPIO0_OSRL) & 0x3FFFFFFF);
-+ /* three-state select */
-+ out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFFFFFFF0);
-+ out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0x3FFFFFFF);
-+ /* enable output driver */
-+ out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN |
-+ NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN);
-+#ifdef USE_READY_BUSY_PIN
-+ /* three-state select */
-+ out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0xFFFFFFFC);
-+ /* high-impedecence */
-+ out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) & (~NAND_EVB_RB_GPIO_PIN));
-+ /* input select */
-+ out_be32((volatile unsigned*)GPIO0_ISR1L, (in_be32((volatile unsigned*)GPIO0_ISR1L) & 0xFFFFFFFC) | 0x00000001);
-+#endif
-+
-+ /* insert callbacks */
-+ this->IO_ADDR_R = ppchameleonevb_fio_base;
-+ this->IO_ADDR_W = ppchameleonevb_fio_base;
-+ this->hwcontrol = ppchameleonevb_hwcontrol;
-+#ifdef USE_READY_BUSY_PIN
-+ this->dev_ready = ppchameleonevb_device_ready;
-+#endif
-+ this->chip_delay = NAND_SMALL_DELAY_US;
-+
-+ /* ECC mode */
-+ this->eccmode = NAND_ECC_SOFT;
-+
-+ /* Scan to find existence of the device */
-+ if (nand_scan (ppchameleonevb_mtd, 1)) {
-+ iounmap((void *)ppchameleonevb_fio_base);
-+ kfree (ppchameleonevb_mtd);
-+ return -ENXIO;
-+ }
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+ ppchameleonevb_mtd->name = NAND_EVB_MTD_NAME;
-+ mtd_parts_nb = parse_mtd_partitions(ppchameleonevb_mtd, part_probes_evb, &mtd_parts, 0);
-+ if (mtd_parts_nb > 0)
-+ part_type = "command line";
-+ else
-+ mtd_parts_nb = 0;
-+#endif
-+ if (mtd_parts_nb == 0)
-+ {
-+ mtd_parts = partition_info_evb;
-+ mtd_parts_nb = NUM_PARTITIONS;
-+ part_type = "static";
-+ }
-+
-+ /* Register the partitions */
-+ printk(KERN_NOTICE "Using %s partition definition\n", part_type);
-+ add_mtd_partitions(ppchameleonevb_mtd, mtd_parts, mtd_parts_nb);
-+
-+ /* Return happy */
-+ return 0;
-+}
-+module_init(ppchameleonevb_init);
-+
-+/*
-+ * Clean up routine
-+ */
-+static void __exit ppchameleonevb_cleanup (void)
-+{
-+ struct nand_chip *this;
-+
-+ /* Release resources, unregister device(s) */
-+ nand_release (ppchameleon_mtd);
-+ nand_release (ppchameleonevb_mtd);
-+
-+ /* Release iomaps */
-+ this = (struct nand_chip *) &ppchameleon_mtd[1];
-+ iounmap((void *) this->IO_ADDR_R;
-+ this = (struct nand_chip *) &ppchameleonevb_mtd[1];
-+ iounmap((void *) this->IO_ADDR_R;
-+
-+ /* Free the MTD device structure */
-+ kfree (ppchameleon_mtd);
-+ kfree (ppchameleonevb_mtd);
-+}
-+module_exit(ppchameleonevb_cleanup);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("DAVE Srl <support-ppchameleon@dave-tech.it>");
-+MODULE_DESCRIPTION("MTD map driver for DAVE Srl PPChameleonEVB board");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/nand/rtc_from4.c
-@@ -0,0 +1,683 @@
-+/*
-+ * drivers/mtd/nand/rtc_from4.c
-+ *
-+ * Copyright (C) 2004 Red Hat, Inc.
-+ *
-+ * Derived from drivers/mtd/nand/spia.c
-+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
-+ *
-+ * $Id: rtc_from4.c,v 1.9 2005/01/24 20:40:11 dmarlin 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.
-+ *
-+ * Overview:
-+ * This is a device driver for the AG-AND flash device found on the
-+ * Renesas Technology Corp. Flash ROM 4-slot interface board (FROM_BOARD4),
-+ * which utilizes the Renesas HN29V1G91T-30 part.
-+ * This chip is a 1 GBibit (128MiB x 8 bits) AG-AND flash device.
-+ */
-+
-+#include <linux/delay.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/rslib.h>
-+#include <linux/module.h>
-+#include <linux/mtd/compatmac.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/io.h>
-+
-+/*
-+ * MTD structure for Renesas board
-+ */
-+static struct mtd_info *rtc_from4_mtd = NULL;
-+
-+#define RTC_FROM4_MAX_CHIPS 2
-+
-+/* HS77x9 processor register defines */
-+#define SH77X9_BCR1 ((volatile unsigned short *)(0xFFFFFF60))
-+#define SH77X9_BCR2 ((volatile unsigned short *)(0xFFFFFF62))
-+#define SH77X9_WCR1 ((volatile unsigned short *)(0xFFFFFF64))
-+#define SH77X9_WCR2 ((volatile unsigned short *)(0xFFFFFF66))
-+#define SH77X9_MCR ((volatile unsigned short *)(0xFFFFFF68))
-+#define SH77X9_PCR ((volatile unsigned short *)(0xFFFFFF6C))
-+#define SH77X9_FRQCR ((volatile unsigned short *)(0xFFFFFF80))
-+
-+/*
-+ * Values specific to the Renesas Technology Corp. FROM_BOARD4 (used with HS77x9 processor)
-+ */
-+/* Address where flash is mapped */
-+#define RTC_FROM4_FIO_BASE 0x14000000
-+
-+/* CLE and ALE are tied to address lines 5 & 4, respectively */
-+#define RTC_FROM4_CLE (1 << 5)
-+#define RTC_FROM4_ALE (1 << 4)
-+
-+/* address lines A24-A22 used for chip selection */
-+#define RTC_FROM4_NAND_ADDR_SLOT3 (0x00800000)
-+#define RTC_FROM4_NAND_ADDR_SLOT4 (0x00C00000)
-+#define RTC_FROM4_NAND_ADDR_FPGA (0x01000000)
-+/* mask address lines A24-A22 used for chip selection */
-+#define RTC_FROM4_NAND_ADDR_MASK (RTC_FROM4_NAND_ADDR_SLOT3 | RTC_FROM4_NAND_ADDR_SLOT4 | RTC_FROM4_NAND_ADDR_FPGA)
-+
-+/* FPGA status register for checking device ready (bit zero) */
-+#define RTC_FROM4_FPGA_SR (RTC_FROM4_NAND_ADDR_FPGA | 0x00000002)
-+#define RTC_FROM4_DEVICE_READY 0x0001
-+
-+/* FPGA Reed-Solomon ECC Control register */
-+
-+#define RTC_FROM4_RS_ECC_CTL (RTC_FROM4_NAND_ADDR_FPGA | 0x00000050)
-+#define RTC_FROM4_RS_ECC_CTL_CLR (1 << 7)
-+#define RTC_FROM4_RS_ECC_CTL_GEN (1 << 6)
-+#define RTC_FROM4_RS_ECC_CTL_FD_E (1 << 5)
-+
-+/* FPGA Reed-Solomon ECC code base */
-+#define RTC_FROM4_RS_ECC (RTC_FROM4_NAND_ADDR_FPGA | 0x00000060)
-+#define RTC_FROM4_RS_ECCN (RTC_FROM4_NAND_ADDR_FPGA | 0x00000080)
-+
-+/* FPGA Reed-Solomon ECC check register */
-+#define RTC_FROM4_RS_ECC_CHK (RTC_FROM4_NAND_ADDR_FPGA | 0x00000070)
-+#define RTC_FROM4_RS_ECC_CHK_ERROR (1 << 7)
-+
-+#define ERR_STAT_ECC_AVAILABLE 0x20
-+
-+/* Undefine for software ECC */
-+#define RTC_FROM4_HWECC 1
-+
-+/* Define as 1 for no virtual erase blocks (in JFFS2) */
-+#define RTC_FROM4_NO_VIRTBLOCKS 0
-+
-+/*
-+ * Module stuff
-+ */
-+static void __iomem *rtc_from4_fio_base = (void *)P2SEGADDR(RTC_FROM4_FIO_BASE);
-+
-+const static struct mtd_partition partition_info[] = {
-+ {
-+ .name = "Renesas flash partition 1",
-+ .offset = 0,
-+ .size = MTDPART_SIZ_FULL
-+ },
-+};
-+#define NUM_PARTITIONS 1
-+
-+/*
-+ * hardware specific flash bbt decriptors
-+ * Note: this is to allow debugging by disabling
-+ * NAND_BBT_CREATE and/or NAND_BBT_WRITE
-+ *
-+ */
-+static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
-+static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
-+
-+static struct nand_bbt_descr rtc_from4_bbt_main_descr = {
-+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-+ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-+ .offs = 40,
-+ .len = 4,
-+ .veroffs = 44,
-+ .maxblocks = 4,
-+ .pattern = bbt_pattern
-+};
-+
-+static struct nand_bbt_descr rtc_from4_bbt_mirror_descr = {
-+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-+ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-+ .offs = 40,
-+ .len = 4,
-+ .veroffs = 44,
-+ .maxblocks = 4,
-+ .pattern = mirror_pattern
-+};
-+
-+
-+
-+#ifdef RTC_FROM4_HWECC
-+
-+/* the Reed Solomon control structure */
-+static struct rs_control *rs_decoder;
-+
-+/*
-+ * hardware specific Out Of Band information
-+ */
-+static struct nand_oobinfo rtc_from4_nand_oobinfo = {
-+ .useecc = MTD_NANDECC_AUTOPLACE,
-+ .eccbytes = 32,
-+ .eccpos = {
-+ 0, 1, 2, 3, 4, 5, 6, 7,
-+ 8, 9, 10, 11, 12, 13, 14, 15,
-+ 16, 17, 18, 19, 20, 21, 22, 23,
-+ 24, 25, 26, 27, 28, 29, 30, 31},
-+ .oobfree = { {32, 32} }
-+};
-+
-+/* Aargh. I missed the reversed bit order, when I
-+ * was talking to Renesas about the FPGA.
-+ *
-+ * The table is used for bit reordering and inversion
-+ * of the ecc byte which we get from the FPGA
-+ */
-+static uint8_t revbits[256] = {
-+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
-+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
-+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
-+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
-+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
-+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
-+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
-+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
-+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
-+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
-+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
-+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
-+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
-+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
-+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
-+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
-+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
-+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
-+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
-+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
-+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
-+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
-+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
-+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
-+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
-+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
-+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
-+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
-+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
-+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
-+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
-+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
-+};
-+
-+#endif
-+
-+
-+
-+/*
-+ * rtc_from4_hwcontrol - hardware specific access to control-lines
-+ * @mtd: MTD device structure
-+ * @cmd: hardware control command
-+ *
-+ * Address lines (A5 and A4) are used to control Command and Address Latch
-+ * Enable on this board, so set the read/write address appropriately.
-+ *
-+ * Chip Enable is also controlled by the Chip Select (CS5) and
-+ * Address lines (A24-A22), so no action is required here.
-+ *
-+ */
-+static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+ struct nand_chip* this = (struct nand_chip *) (mtd->priv);
-+
-+ switch(cmd) {
-+
-+ case NAND_CTL_SETCLE:
-+ this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_CLE);
-+ break;
-+ case NAND_CTL_CLRCLE:
-+ this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_CLE);
-+ break;
-+
-+ case NAND_CTL_SETALE:
-+ this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_ALE);
-+ break;
-+ case NAND_CTL_CLRALE:
-+ this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_ALE);
-+ break;
-+
-+ case NAND_CTL_SETNCE:
-+ break;
-+ case NAND_CTL_CLRNCE:
-+ break;
-+
-+ }
-+}
-+
-+
-+/*
-+ * rtc_from4_nand_select_chip - hardware specific chip select
-+ * @mtd: MTD device structure
-+ * @chip: Chip to select (0 == slot 3, 1 == slot 4)
-+ *
-+ * The chip select is based on address lines A24-A22.
-+ * This driver uses flash slots 3 and 4 (A23-A22).
-+ *
-+ */
-+static void rtc_from4_nand_select_chip(struct mtd_info *mtd, int chip)
-+{
-+ struct nand_chip *this = mtd->priv;
-+
-+ this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R & ~RTC_FROM4_NAND_ADDR_MASK);
-+ this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_NAND_ADDR_MASK);
-+
-+ switch(chip) {
-+
-+ case 0: /* select slot 3 chip */
-+ this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R | RTC_FROM4_NAND_ADDR_SLOT3);
-+ this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_NAND_ADDR_SLOT3);
-+ break;
-+ case 1: /* select slot 4 chip */
-+ this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R | RTC_FROM4_NAND_ADDR_SLOT4);
-+ this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_NAND_ADDR_SLOT4);
-+ break;
-+
-+ }
-+}
-+
-+
-+/*
-+ * rtc_from4_nand_device_ready - hardware specific ready/busy check
-+ * @mtd: MTD device structure
-+ *
-+ * This board provides the Ready/Busy state in the status register
-+ * of the FPGA. Bit zero indicates the RDY(1)/BSY(0) signal.
-+ *
-+ */
-+static int rtc_from4_nand_device_ready(struct mtd_info *mtd)
-+{
-+ unsigned short status;
-+
-+ status = *((volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_FPGA_SR));
-+
-+ return (status & RTC_FROM4_DEVICE_READY);
-+
-+}
-+
-+
-+/*
-+ * deplete - code to perform device recovery in case there was a power loss
-+ * @mtd: MTD device structure
-+ * @chip: Chip to select (0 == slot 3, 1 == slot 4)
-+ *
-+ * If there was a sudden loss of power during an erase operation, a
-+ * "device recovery" operation must be performed when power is restored
-+ * to ensure correct operation. This routine performs the required steps
-+ * for the requested chip.
-+ *
-+ * See page 86 of the data sheet for details.
-+ *
-+ */
-+static void deplete(struct mtd_info *mtd, int chip)
-+{
-+ struct nand_chip *this = mtd->priv;
-+
-+ /* wait until device is ready */
-+ while (!this->dev_ready(mtd));
-+
-+ this->select_chip(mtd, chip);
-+
-+ /* Send the commands for device recovery, phase 1 */
-+ this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000);
-+ this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1);
-+
-+ /* Send the commands for device recovery, phase 2 */
-+ this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0004);
-+ this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1);
-+
-+}
-+
-+
-+#ifdef RTC_FROM4_HWECC
-+/*
-+ * rtc_from4_enable_hwecc - hardware specific hardware ECC enable function
-+ * @mtd: MTD device structure
-+ * @mode: I/O mode; read or write
-+ *
-+ * enable hardware ECC for data read or write
-+ *
-+ */
-+static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode)
-+{
-+ volatile unsigned short * rs_ecc_ctl = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CTL);
-+ unsigned short status;
-+
-+ switch (mode) {
-+ case NAND_ECC_READ :
-+ status = RTC_FROM4_RS_ECC_CTL_CLR
-+ | RTC_FROM4_RS_ECC_CTL_FD_E;
-+
-+ *rs_ecc_ctl = status;
-+ break;
-+
-+ case NAND_ECC_READSYN :
-+ status = 0x00;
-+
-+ *rs_ecc_ctl = status;
-+ break;
-+
-+ case NAND_ECC_WRITE :
-+ status = RTC_FROM4_RS_ECC_CTL_CLR
-+ | RTC_FROM4_RS_ECC_CTL_GEN
-+ | RTC_FROM4_RS_ECC_CTL_FD_E;
-+
-+ *rs_ecc_ctl = status;
-+ break;
-+
-+ default:
-+ BUG();
-+ break;
-+ }
-+
-+}
-+
-+
-+/*
-+ * rtc_from4_calculate_ecc - hardware specific code to read ECC code
-+ * @mtd: MTD device structure
-+ * @dat: buffer containing the data to generate ECC codes
-+ * @ecc_code ECC codes calculated
-+ *
-+ * The ECC code is calculated by the FPGA. All we have to do is read the values
-+ * from the FPGA registers.
-+ *
-+ * Note: We read from the inverted registers, since data is inverted before
-+ * the code is calculated. So all 0xff data (blank page) results in all 0xff rs code
-+ *
-+ */
-+static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
-+{
-+ volatile unsigned short * rs_eccn = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECCN);
-+ unsigned short value;
-+ int i;
-+
-+ for (i = 0; i < 8; i++) {
-+ value = *rs_eccn;
-+ ecc_code[i] = (unsigned char)value;
-+ rs_eccn++;
-+ }
-+ ecc_code[7] |= 0x0f; /* set the last four bits (not used) */
-+}
-+
-+
-+/*
-+ * rtc_from4_correct_data - hardware specific code to correct data using ECC code
-+ * @mtd: MTD device structure
-+ * @buf: buffer containing the data to generate ECC codes
-+ * @ecc1 ECC codes read
-+ * @ecc2 ECC codes calculated
-+ *
-+ * The FPGA tells us fast, if there's an error or not. If no, we go back happy
-+ * else we read the ecc results from the fpga and call the rs library to decode
-+ * and hopefully correct the error.
-+ *
-+ */
-+static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2)
-+{
-+ int i, j, res;
-+ unsigned short status;
-+ uint16_t par[6], syn[6];
-+ uint8_t ecc[8];
-+ volatile unsigned short *rs_ecc;
-+
-+ status = *((volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CHK));
-+
-+ if (!(status & RTC_FROM4_RS_ECC_CHK_ERROR)) {
-+ return 0;
-+ }
-+
-+ /* Read the syndrom pattern from the FPGA and correct the bitorder */
-+ rs_ecc = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC);
-+ for (i = 0; i < 8; i++) {
-+ ecc[i] = revbits[(*rs_ecc) & 0xFF];
-+ rs_ecc++;
-+ }
-+
-+ /* convert into 6 10bit syndrome fields */
-+ par[5] = rs_decoder->index_of[(((uint16_t)ecc[0] >> 0) & 0x0ff) |
-+ (((uint16_t)ecc[1] << 8) & 0x300)];
-+ par[4] = rs_decoder->index_of[(((uint16_t)ecc[1] >> 2) & 0x03f) |
-+ (((uint16_t)ecc[2] << 6) & 0x3c0)];
-+ par[3] = rs_decoder->index_of[(((uint16_t)ecc[2] >> 4) & 0x00f) |
-+ (((uint16_t)ecc[3] << 4) & 0x3f0)];
-+ par[2] = rs_decoder->index_of[(((uint16_t)ecc[3] >> 6) & 0x003) |
-+ (((uint16_t)ecc[4] << 2) & 0x3fc)];
-+ par[1] = rs_decoder->index_of[(((uint16_t)ecc[5] >> 0) & 0x0ff) |
-+ (((uint16_t)ecc[6] << 8) & 0x300)];
-+ par[0] = (((uint16_t)ecc[6] >> 2) & 0x03f) | (((uint16_t)ecc[7] << 6) & 0x3c0);
-+
-+ /* Convert to computable syndrome */
-+ for (i = 0; i < 6; i++) {
-+ syn[i] = par[0];
-+ for (j = 1; j < 6; j++)
-+ if (par[j] != rs_decoder->nn)
-+ syn[i] ^= rs_decoder->alpha_to[rs_modnn(rs_decoder, par[j] + i * j)];
-+
-+ /* Convert to index form */
-+ syn[i] = rs_decoder->index_of[syn[i]];
-+ }
-+
-+ /* Let the library code do its magic.*/
-+ res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL);
-+ if (res > 0) {
-+ DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: "
-+ "ECC corrected %d errors on read\n", res);
-+ }
-+ return res;
-+}
-+
-+
-+/**
-+ * rtc_from4_errstat - perform additional error status checks
-+ * @mtd: MTD device structure
-+ * @this: NAND chip structure
-+ * @state: state or the operation
-+ * @status: status code returned from read status
-+ * @page: startpage inside the chip, must be called with (page & this->pagemask)
-+ *
-+ * Perform additional error status checks on erase and write failures
-+ * to determine if errors are correctable. For this device, correctable
-+ * 1-bit errors on erase and write are considered acceptable.
-+ *
-+ * note: see pages 34..37 of data sheet for details.
-+ *
-+ */
-+static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page)
-+{
-+ int er_stat=0;
-+ int rtn, retlen;
-+ size_t len;
-+ uint8_t *buf;
-+ int i;
-+
-+ this->cmdfunc (mtd, NAND_CMD_STATUS_CLEAR, -1, -1);
-+
-+ if (state == FL_ERASING) {
-+ for (i=0; i<4; i++) {
-+ if (status & 1<<(i+1)) {
-+ this->cmdfunc (mtd, (NAND_CMD_STATUS_ERROR + i + 1), -1, -1);
-+ rtn = this->read_byte(mtd);
-+ this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1);
-+ if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {
-+ er_stat |= 1<<(i+1); /* err_ecc_not_avail */
-+ }
-+ }
-+ }
-+ } else if (state == FL_WRITING) {
-+ /* single bank write logic */
-+ this->cmdfunc (mtd, NAND_CMD_STATUS_ERROR, -1, -1);
-+ rtn = this->read_byte(mtd);
-+ this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1);
-+ if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {
-+ er_stat |= 1<<1; /* err_ecc_not_avail */
-+ } else {
-+ len = mtd->oobblock;
-+ buf = kmalloc (len, GFP_KERNEL);
-+ if (!buf) {
-+ printk (KERN_ERR "rtc_from4_errstat: Out of memory!\n");
-+ er_stat = 1; /* if we can't check, assume failed */
-+ } else {
-+ /* recovery read */
-+ /* page read */
-+ rtn = nand_do_read_ecc (mtd, page, len, &retlen, buf, NULL, this->autooob, 1);
-+ if (rtn) { /* if read failed or > 1-bit error corrected */
-+ er_stat |= 1<<1; /* ECC read failed */
-+ }
-+ kfree(buf);
-+ }
-+ }
-+ }
-+
-+ rtn = status;
-+ if (er_stat == 0) { /* if ECC is available */
-+ rtn = (status & ~NAND_STATUS_FAIL); /* clear the error bit */
-+ }
-+
-+ return rtn;
-+}
-+#endif
-+
-+
-+/*
-+ * Main initialization routine
-+ */
-+int __init rtc_from4_init (void)
-+{
-+ struct nand_chip *this;
-+ unsigned short bcr1, bcr2, wcr2;
-+ int i;
-+
-+ /* Allocate memory for MTD device structure and private data */
-+ rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip),
-+ GFP_KERNEL);
-+ if (!rtc_from4_mtd) {
-+ printk ("Unable to allocate Renesas NAND MTD device structure.\n");
-+ return -ENOMEM;
-+ }
-+
-+ /* Get pointer to private data */
-+ this = (struct nand_chip *) (&rtc_from4_mtd[1]);
-+
-+ /* Initialize structures */
-+ memset((char *) rtc_from4_mtd, 0, sizeof(struct mtd_info));
-+ memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+ /* Link the private data with the MTD structure */
-+ rtc_from4_mtd->priv = this;
-+
-+ /* set area 5 as PCMCIA mode to clear the spec of tDH(Data hold time;9ns min) */
-+ bcr1 = *SH77X9_BCR1 & ~0x0002;
-+ bcr1 |= 0x0002;
-+ *SH77X9_BCR1 = bcr1;
-+
-+ /* set */
-+ bcr2 = *SH77X9_BCR2 & ~0x0c00;
-+ bcr2 |= 0x0800;
-+ *SH77X9_BCR2 = bcr2;
-+
-+ /* set area 5 wait states */
-+ wcr2 = *SH77X9_WCR2 & ~0x1c00;
-+ wcr2 |= 0x1c00;
-+ *SH77X9_WCR2 = wcr2;
-+
-+ /* Set address of NAND IO lines */
-+ this->IO_ADDR_R = rtc_from4_fio_base;
-+ this->IO_ADDR_W = rtc_from4_fio_base;
-+ /* Set address of hardware control function */
-+ this->hwcontrol = rtc_from4_hwcontrol;
-+ /* Set address of chip select function */
-+ this->select_chip = rtc_from4_nand_select_chip;
-+ /* command delay time (in us) */
-+ this->chip_delay = 100;
-+ /* return the status of the Ready/Busy line */
-+ this->dev_ready = rtc_from4_nand_device_ready;
-+
-+#ifdef RTC_FROM4_HWECC
-+ printk(KERN_INFO "rtc_from4_init: using hardware ECC detection.\n");
-+
-+ this->eccmode = NAND_ECC_HW8_512;
-+ this->options |= NAND_HWECC_SYNDROME;
-+ /* return the status of extra status and ECC checks */
-+ this->errstat = rtc_from4_errstat;
-+ /* set the nand_oobinfo to support FPGA H/W error detection */
-+ this->autooob = &rtc_from4_nand_oobinfo;
-+ this->enable_hwecc = rtc_from4_enable_hwecc;
-+ this->calculate_ecc = rtc_from4_calculate_ecc;
-+ this->correct_data = rtc_from4_correct_data;
-+#else
-+ printk(KERN_INFO "rtc_from4_init: using software ECC detection.\n");
-+
-+ this->eccmode = NAND_ECC_SOFT;
-+#endif
-+
-+ /* set the bad block tables to support debugging */
-+ this->bbt_td = &rtc_from4_bbt_main_descr;
-+ this->bbt_md = &rtc_from4_bbt_mirror_descr;
-+
-+ /* Scan to find existence of the device */
-+ if (nand_scan(rtc_from4_mtd, RTC_FROM4_MAX_CHIPS)) {
-+ kfree(rtc_from4_mtd);
-+ return -ENXIO;
-+ }
-+
-+ /* Perform 'device recovery' for each chip in case there was a power loss. */
-+ for (i=0; i < this->numchips; i++) {
-+ deplete(rtc_from4_mtd, i);
-+ }
-+
-+#if RTC_FROM4_NO_VIRTBLOCKS
-+ /* use a smaller erase block to minimize wasted space when a block is bad */
-+ /* note: this uses eight times as much RAM as using the default and makes */
-+ /* mounts take four times as long. */
-+ rtc_from4_mtd->flags |= MTD_NO_VIRTBLOCKS;
-+#endif
-+
-+ /* Register the partitions */
-+ add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS);
-+
-+#ifdef RTC_FROM4_HWECC
-+ /* We could create the decoder on demand, if memory is a concern.
-+ * This way we have it handy, if an error happens
-+ *
-+ * Symbolsize is 10 (bits)
-+ * Primitve polynomial is x^10+x^3+1
-+ * first consecutive root is 0
-+ * primitve element to generate roots = 1
-+ * generator polinomial degree = 6
-+ */
-+ rs_decoder = init_rs(10, 0x409, 0, 1, 6);
-+ if (!rs_decoder) {
-+ printk (KERN_ERR "Could not create a RS decoder\n");
-+ nand_release(rtc_from4_mtd);
-+ kfree(rtc_from4_mtd);
-+ return -ENOMEM;
-+ }
-+#endif
-+ /* Return happy */
-+ return 0;
-+}
-+module_init(rtc_from4_init);
-+
-+
-+/*
-+ * Clean up routine
-+ */
-+#ifdef MODULE
-+static void __exit rtc_from4_cleanup (void)
-+{
-+ /* Release resource, unregister partitions */
-+ nand_release(rtc_from4_mtd);
-+
-+ /* Free the MTD device structure */
-+ kfree (rtc_from4_mtd);
-+
-+#ifdef RTC_FROM4_HWECC
-+ /* Free the reed solomon resources */
-+ if (rs_decoder) {
-+ free_rs(rs_decoder);
-+ }
-+#endif
-+}
-+module_exit(rtc_from4_cleanup);
-+#endif
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("d.marlin <dmarlin@redhat.com");
-+MODULE_DESCRIPTION("Board-specific glue layer for AG-AND flash on Renesas FROM_BOARD4");
-+
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/nand/s3c2410.c
-@@ -0,0 +1,706 @@
-+/* linux/drivers/mtd/nand/s3c2410.c
-+ *
-+ * Copyright (c) 2004 Simtec Electronics
-+ * http://www.simtec.co.uk/products/SWLINUX/
-+ * Ben Dooks <ben@simtec.co.uk>
-+ *
-+ * Samsung S3C2410 NAND driver
-+ *
-+ * Changelog:
-+ * 21-Sep-2004 BJD Initial version
-+ * 23-Sep-2004 BJD Mulitple device support
-+ * 28-Sep-2004 BJD Fixed ECC placement for Hardware mode
-+ * 12-Oct-2004 BJD Fixed errors in use of platform data
-+ * 18-Feb-2004 BJD Fix sparse errors
-+ *
-+ * $Id: s3c2410.c,v 1.8 2005/02/18 14:46:12 bjd Exp $
-+ *
-+ * This program is free software; 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 <config/mtd/nand/s3c2410/hwecc.h>
-+#include <config/mtd/nand/s3c2410/debug.h>
-+
-+#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG
-+#define DEBUG
-+#endif
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/ioport.h>
-+#include <linux/device.h>
-+#include <linux/delay.h>
-+#include <linux/err.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/nand_ecc.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/io.h>
-+#include <asm/mach-types.h>
-+#include <asm/hardware/clock.h>
-+
-+#include <asm/arch/regs-nand.h>
-+#include <asm/arch/nand.h>
-+
-+#define PFX "s3c2410-nand: "
-+
-+#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
-+static int hardware_ecc = 1;
-+#else
-+static int hardware_ecc = 0;
-+#endif
-+
-+/* new oob placement block for use with hardware ecc generation
-+ */
-+
-+static struct nand_oobinfo nand_hw_eccoob = {
-+ .useecc = MTD_NANDECC_AUTOPLACE,
-+ .eccbytes = 3,
-+ .eccpos = {0, 1, 2 },
-+ .oobfree = { {8, 8} }
-+};
-+
-+/* controller and mtd information */
-+
-+struct s3c2410_nand_info;
-+
-+struct s3c2410_nand_mtd {
-+ struct mtd_info mtd;
-+ struct nand_chip chip;
-+ struct s3c2410_nand_set *set;
-+ struct s3c2410_nand_info *info;
-+ int scan_res;
-+};
-+
-+/* overview of the s3c2410 nand state */
-+
-+struct s3c2410_nand_info {
-+ /* mtd info */
-+ struct nand_hw_control controller;
-+ struct s3c2410_nand_mtd *mtds;
-+ struct s3c2410_platform_nand *platform;
-+
-+ /* device info */
-+ struct device *device;
-+ struct resource *area;
-+ struct clk *clk;
-+ void __iomem *regs;
-+ int mtd_count;
-+};
-+
-+/* conversion functions */
-+
-+static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
-+{
-+ return container_of(mtd, struct s3c2410_nand_mtd, mtd);
-+}
-+
-+static struct s3c2410_nand_info *s3c2410_nand_mtd_toinfo(struct mtd_info *mtd)
-+{
-+ return s3c2410_nand_mtd_toours(mtd)->info;
-+}
-+
-+static struct s3c2410_nand_info *to_nand_info(struct device *dev)
-+{
-+ return dev_get_drvdata(dev);
-+}
-+
-+static struct s3c2410_platform_nand *to_nand_plat(struct device *dev)
-+{
-+ return dev->platform_data;
-+}
-+
-+/* timing calculations */
-+
-+#define NS_IN_KHZ 10000000
-+
-+static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max)
-+{
-+ int result;
-+
-+ result = (wanted * NS_IN_KHZ) / clk;
-+ result++;
-+
-+ pr_debug("result %d from %ld, %d\n", result, clk, wanted);
-+
-+ if (result > max) {
-+ printk("%d ns is too big for current clock rate %ld\n",
-+ wanted, clk);
-+ return -1;
-+ }
-+
-+ if (result < 1)
-+ result = 1;
-+
-+ return result;
-+}
-+
-+#define to_ns(ticks,clk) (((clk) * (ticks)) / NS_IN_KHZ)
-+
-+/* controller setup */
-+
-+static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
-+ struct device *dev)
-+{
-+ struct s3c2410_platform_nand *plat = to_nand_plat(dev);
-+ unsigned int tacls, twrph0, twrph1;
-+ unsigned long clkrate = clk_get_rate(info->clk);
-+ unsigned long cfg;
-+
-+ /* calculate the timing information for the controller */
-+
-+ if (plat != NULL) {
-+ tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 8);
-+ twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
-+ twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8);
-+ } else {
-+ /* default timings */
-+ tacls = 8;
-+ twrph0 = 8;
-+ twrph1 = 8;
-+ }
-+
-+ if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {
-+ printk(KERN_ERR PFX "cannot get timings suitable for board\n");
-+ return -EINVAL;
-+ }
-+
-+ printk(KERN_INFO PFX "timing: Tacls %ldns, Twrph0 %ldns, Twrph1 %ldns\n",
-+ to_ns(tacls, clkrate),
-+ to_ns(twrph0, clkrate),
-+ to_ns(twrph1, clkrate));
-+
-+ cfg = S3C2410_NFCONF_EN;
-+ cfg |= S3C2410_NFCONF_TACLS(tacls-1);
-+ cfg |= S3C2410_NFCONF_TWRPH0(twrph0-1);
-+ cfg |= S3C2410_NFCONF_TWRPH1(twrph1-1);
-+
-+ pr_debug(PFX "NF_CONF is 0x%lx\n", cfg);
-+
-+ writel(cfg, info->regs + S3C2410_NFCONF);
-+ return 0;
-+}
-+
-+/* select chip */
-+
-+static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
-+{
-+ struct s3c2410_nand_info *info;
-+ struct s3c2410_nand_mtd *nmtd;
-+ struct nand_chip *this = mtd->priv;
-+ unsigned long cur;
-+
-+ nmtd = this->priv;
-+ info = nmtd->info;
-+
-+ cur = readl(info->regs + S3C2410_NFCONF);
-+
-+ if (chip == -1) {
-+ cur |= S3C2410_NFCONF_nFCE;
-+ } else {
-+ if (chip > nmtd->set->nr_chips) {
-+ printk(KERN_ERR PFX "chip %d out of range\n", chip);
-+ return;
-+ }
-+
-+ if (info->platform != NULL) {
-+ if (info->platform->select_chip != NULL)
-+ (info->platform->select_chip)(nmtd->set, chip);
-+ }
-+
-+ cur &= ~S3C2410_NFCONF_nFCE;
-+ }
-+
-+ writel(cur, info->regs + S3C2410_NFCONF);
-+}
-+
-+/* command and control functions */
-+
-+static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-+ unsigned long cur;
-+
-+ switch (cmd) {
-+ case NAND_CTL_SETNCE:
-+ cur = readl(info->regs + S3C2410_NFCONF);
-+ cur &= ~S3C2410_NFCONF_nFCE;
-+ writel(cur, info->regs + S3C2410_NFCONF);
-+ break;
-+
-+ case NAND_CTL_CLRNCE:
-+ cur = readl(info->regs + S3C2410_NFCONF);
-+ cur |= S3C2410_NFCONF_nFCE;
-+ writel(cur, info->regs + S3C2410_NFCONF);
-+ break;
-+
-+ /* we don't need to implement these */
-+ case NAND_CTL_SETCLE:
-+ case NAND_CTL_CLRCLE:
-+ case NAND_CTL_SETALE:
-+ case NAND_CTL_CLRALE:
-+ pr_debug(PFX "s3c2410_nand_hwcontrol(%d) unusedn", cmd);
-+ break;
-+ }
-+}
-+
-+/* s3c2410_nand_command
-+ *
-+ * This function implements sending commands and the relevant address
-+ * information to the chip, via the hardware controller. Since the
-+ * S3C2410 generates the correct ALE/CLE signaling automatically, we
-+ * do not need to use hwcontrol.
-+*/
-+
-+static void s3c2410_nand_command (struct mtd_info *mtd, unsigned command,
-+ int column, int page_addr)
-+{
-+ register struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-+ register struct nand_chip *this = mtd->priv;
-+
-+ /*
-+ * 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;
-+ }
-+
-+ writeb(readcmd, info->regs + S3C2410_NFCMD);
-+ }
-+ writeb(command, info->regs + S3C2410_NFCMD);
-+
-+ /* Set ALE and clear CLE to start address cycle */
-+
-+ 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;
-+ writeb(column, info->regs + S3C2410_NFADDR);
-+ }
-+ if (page_addr != -1) {
-+ writeb((unsigned char) (page_addr), info->regs + S3C2410_NFADDR);
-+ writeb((unsigned char) (page_addr >> 8), info->regs + S3C2410_NFADDR);
-+ /* One more address cycle for higher density devices */
-+ if (this->chipsize & 0x0c000000)
-+ writeb((unsigned char) ((page_addr >> 16) & 0x0f),
-+ info->regs + S3C2410_NFADDR);
-+ }
-+ /* Latch in address */
-+ }
-+
-+ /*
-+ * 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);
-+ writeb(NAND_CMD_STATUS, info->regs + S3C2410_NFCMD);
-+
-+ 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));
-+}
-+
-+
-+/* s3c2410_nand_devready()
-+ *
-+ * returns 0 if the nand is busy, 1 if it is ready
-+*/
-+
-+static int s3c2410_nand_devready(struct mtd_info *mtd)
-+{
-+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-+
-+ return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
-+}
-+
-+/* ECC handling functions */
-+
-+static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
-+ u_char *read_ecc, u_char *calc_ecc)
-+{
-+ pr_debug("s3c2410_nand_correct_data(%p,%p,%p,%p)\n",
-+ mtd, dat, read_ecc, calc_ecc);
-+
-+ pr_debug("eccs: read %02x,%02x,%02x vs calc %02x,%02x,%02x\n",
-+ read_ecc[0], read_ecc[1], read_ecc[2],
-+ calc_ecc[0], calc_ecc[1], calc_ecc[2]);
-+
-+ if (read_ecc[0] == calc_ecc[0] &&
-+ read_ecc[1] == calc_ecc[1] &&
-+ read_ecc[2] == calc_ecc[2])
-+ return 0;
-+
-+ /* we curently have no method for correcting the error */
-+
-+ return -1;
-+}
-+
-+static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
-+{
-+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-+ unsigned long ctrl;
-+
-+ ctrl = readl(info->regs + S3C2410_NFCONF);
-+ ctrl |= S3C2410_NFCONF_INITECC;
-+ writel(ctrl, info->regs + S3C2410_NFCONF);
-+}
-+
-+static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd,
-+ const u_char *dat, u_char *ecc_code)
-+{
-+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-+
-+ ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);
-+ ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);
-+ ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);
-+
-+ pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n",
-+ ecc_code[0], ecc_code[1], ecc_code[2]);
-+
-+ return 0;
-+}
-+
-+
-+/* over-ride the standard functions for a little more speed? */
-+
-+static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ readsb(this->IO_ADDR_R, buf, len);
-+}
-+
-+static void s3c2410_nand_write_buf(struct mtd_info *mtd,
-+ const u_char *buf, int len)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ writesb(this->IO_ADDR_W, buf, len);
-+}
-+
-+/* device management functions */
-+
-+static int s3c2410_nand_remove(struct device *dev)
-+{
-+ struct s3c2410_nand_info *info = to_nand_info(dev);
-+
-+ dev_set_drvdata(dev, NULL);
-+
-+ if (info == NULL)
-+ return 0;
-+
-+ /* first thing we need to do is release all our mtds
-+ * and their partitions, then go through freeing the
-+ * resources used
-+ */
-+
-+ if (info->mtds != NULL) {
-+ struct s3c2410_nand_mtd *ptr = info->mtds;
-+ int mtdno;
-+
-+ for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {
-+ pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);
-+ nand_release(&ptr->mtd);
-+ }
-+
-+ kfree(info->mtds);
-+ }
-+
-+ /* free the common resources */
-+
-+ if (info->clk != NULL && !IS_ERR(info->clk)) {
-+ clk_disable(info->clk);
-+ clk_unuse(info->clk);
-+ clk_put(info->clk);
-+ }
-+
-+ if (info->regs != NULL) {
-+ iounmap(info->regs);
-+ info->regs = NULL;
-+ }
-+
-+ if (info->area != NULL) {
-+ release_resource(info->area);
-+ kfree(info->area);
-+ info->area = NULL;
-+ }
-+
-+ kfree(info);
-+
-+ return 0;
-+}
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
-+ struct s3c2410_nand_mtd *mtd,
-+ struct s3c2410_nand_set *set)
-+{
-+ if (set == NULL)
-+ return add_mtd_device(&mtd->mtd);
-+
-+ if (set->nr_partitions > 0 && set->partitions != NULL) {
-+ return add_mtd_partitions(&mtd->mtd,
-+ set->partitions,
-+ set->nr_partitions);
-+ }
-+
-+ return add_mtd_device(&mtd->mtd);
-+}
-+#else
-+static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
-+ struct s3c2410_nand_mtd *mtd,
-+ struct s3c2410_nand_set *set)
-+{
-+ return add_mtd_device(&mtd->mtd);
-+}
-+#endif
-+
-+/* s3c2410_nand_init_chip
-+ *
-+ * init a single instance of an chip
-+*/
-+
-+static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
-+ struct s3c2410_nand_mtd *nmtd,
-+ struct s3c2410_nand_set *set)
-+{
-+ struct nand_chip *chip = &nmtd->chip;
-+
-+ chip->IO_ADDR_R = info->regs + S3C2410_NFDATA;
-+ chip->IO_ADDR_W = info->regs + S3C2410_NFDATA;
-+ chip->hwcontrol = s3c2410_nand_hwcontrol;
-+ chip->dev_ready = s3c2410_nand_devready;
-+ chip->cmdfunc = s3c2410_nand_command;
-+ chip->write_buf = s3c2410_nand_write_buf;
-+ chip->read_buf = s3c2410_nand_read_buf;
-+ chip->select_chip = s3c2410_nand_select_chip;
-+ chip->chip_delay = 50;
-+ chip->priv = nmtd;
-+ chip->options = 0;
-+ chip->controller = &info->controller;
-+
-+ nmtd->info = info;
-+ nmtd->mtd.priv = chip;
-+ nmtd->set = set;
-+
-+ if (hardware_ecc) {
-+ chip->correct_data = s3c2410_nand_correct_data;
-+ chip->enable_hwecc = s3c2410_nand_enable_hwecc;
-+ chip->calculate_ecc = s3c2410_nand_calculate_ecc;
-+ chip->eccmode = NAND_ECC_HW3_512;
-+ chip->autooob = &nand_hw_eccoob;
-+ } else {
-+ chip->eccmode = NAND_ECC_SOFT;
-+ }
-+}
-+
-+/* s3c2410_nand_probe
-+ *
-+ * called by device layer when it finds a device matching
-+ * one our driver can handled. This code checks to see if
-+ * it can allocate all necessary resources then calls the
-+ * nand layer to look for devices
-+*/
-+
-+static int s3c2410_nand_probe(struct device *dev)
-+{
-+ struct platform_device *pdev = to_platform_device(dev);
-+ struct s3c2410_platform_nand *plat = to_nand_plat(dev);
-+ struct s3c2410_nand_info *info;
-+ struct s3c2410_nand_mtd *nmtd;
-+ struct s3c2410_nand_set *sets;
-+ struct resource *res;
-+ int err = 0;
-+ int size;
-+ int nr_sets;
-+ int setno;
-+
-+ pr_debug("s3c2410_nand_probe(%p)\n", dev);
-+
-+ info = kmalloc(sizeof(*info), GFP_KERNEL);
-+ if (info == NULL) {
-+ printk(KERN_ERR PFX "no memory for flash info\n");
-+ err = -ENOMEM;
-+ goto exit_error;
-+ }
-+
-+ memzero(info, sizeof(*info));
-+ dev_set_drvdata(dev, info);
-+
-+ spin_lock_init(&info->controller.lock);
-+
-+ /* get the clock source and enable it */
-+
-+ info->clk = clk_get(dev, "nand");
-+ if (IS_ERR(info->clk)) {
-+ printk(KERN_ERR PFX "failed to get clock");
-+ err = -ENOENT;
-+ goto exit_error;
-+ }
-+
-+ clk_use(info->clk);
-+ clk_enable(info->clk);
-+
-+ /* allocate and map the resource */
-+
-+ res = pdev->resource; /* assume that the flash has one resource */
-+ size = res->end - res->start + 1;
-+
-+ info->area = request_mem_region(res->start, size, pdev->name);
-+
-+ if (info->area == NULL) {
-+ printk(KERN_ERR PFX "cannot reserve register region\n");
-+ err = -ENOENT;
-+ goto exit_error;
-+ }
-+
-+ info->device = dev;
-+ info->platform = plat;
-+ info->regs = ioremap(res->start, size);
-+
-+ if (info->regs == NULL) {
-+ printk(KERN_ERR PFX "cannot reserve register region\n");
-+ err = -EIO;
-+ goto exit_error;
-+ }
-+
-+ printk(KERN_INFO PFX "mapped registers at %p\n", info->regs);
-+
-+ /* initialise the hardware */
-+
-+ err = s3c2410_nand_inithw(info, dev);
-+ if (err != 0)
-+ goto exit_error;
-+
-+ sets = (plat != NULL) ? plat->sets : NULL;
-+ nr_sets = (plat != NULL) ? plat->nr_sets : 1;
-+
-+ info->mtd_count = nr_sets;
-+
-+ /* allocate our information */
-+
-+ size = nr_sets * sizeof(*info->mtds);
-+ info->mtds = kmalloc(size, GFP_KERNEL);
-+ if (info->mtds == NULL) {
-+ printk(KERN_ERR PFX "failed to allocate mtd storage\n");
-+ err = -ENOMEM;
-+ goto exit_error;
-+ }
-+
-+ memzero(info->mtds, size);
-+
-+ /* initialise all possible chips */
-+
-+ nmtd = info->mtds;
-+
-+ for (setno = 0; setno < nr_sets; setno++, nmtd++) {
-+ pr_debug("initialising set %d (%p, info %p)\n",
-+ setno, nmtd, info);
-+
-+ s3c2410_nand_init_chip(info, nmtd, sets);
-+
-+ nmtd->scan_res = nand_scan(&nmtd->mtd,
-+ (sets) ? sets->nr_chips : 1);
-+
-+ if (nmtd->scan_res == 0) {
-+ s3c2410_nand_add_partition(info, nmtd, sets);
-+ }
-+
-+ if (sets != NULL)
-+ sets++;
-+ }
-+
-+ pr_debug("initialised ok\n");
-+ return 0;
-+
-+ exit_error:
-+ s3c2410_nand_remove(dev);
-+
-+ if (err == 0)
-+ err = -EINVAL;
-+ return err;
-+}
-+
-+static struct device_driver s3c2410_nand_driver = {
-+ .name = "s3c2410-nand",
-+ .bus = &platform_bus_type,
-+ .probe = s3c2410_nand_probe,
-+ .remove = s3c2410_nand_remove,
-+};
-+
-+static int __init s3c2410_nand_init(void)
-+{
-+ printk("S3C2410 NAND Driver, (c) 2004 Simtec Electronics\n");
-+ return driver_register(&s3c2410_nand_driver);
-+}
-+
-+static void __exit s3c2410_nand_exit(void)
-+{
-+ driver_unregister(&s3c2410_nand_driver);
-+}
-+
-+module_init(s3c2410_nand_init);
-+module_exit(s3c2410_nand_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-+MODULE_DESCRIPTION("S3C2410 MTD NAND driver");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/nand/sharpsl.c
-@@ -0,0 +1,260 @@
-+/*
-+ * drivers/mtd/nand/sharpsl.c
-+ *
-+ * Copyright (C) 2004 Richard Purdie
-+ *
-+ * $Id: sharpsl.c,v 1.4 2005/01/23 11:09:19 rpurdie Exp $
-+ *
-+ * Based on Sharp's NAND driver sharp_sl.c
-+ *
-+ * 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/genhd.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/nand_ecc.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/interrupt.h>
-+#include <asm/io.h>
-+#include <asm/hardware.h>
-+#include <asm/mach-types.h>
-+
-+static void __iomem *sharpsl_io_base;
-+static int sharpsl_phys_base = 0x0C000000;
-+
-+/* register offset */
-+#define ECCLPLB sharpsl_io_base+0x00 /* line parity 7 - 0 bit */
-+#define ECCLPUB sharpsl_io_base+0x04 /* line parity 15 - 8 bit */
-+#define ECCCP sharpsl_io_base+0x08 /* column parity 5 - 0 bit */
-+#define ECCCNTR sharpsl_io_base+0x0C /* ECC byte counter */
-+#define ECCCLRR sharpsl_io_base+0x10 /* cleare ECC */
-+#define FLASHIO sharpsl_io_base+0x14 /* Flash I/O */
-+#define FLASHCTL sharpsl_io_base+0x18 /* Flash Control */
-+
-+/* Flash control bit */
-+#define FLRYBY (1 << 5)
-+#define FLCE1 (1 << 4)
-+#define FLWP (1 << 3)
-+#define FLALE (1 << 2)
-+#define FLCLE (1 << 1)
-+#define FLCE0 (1 << 0)
-+
-+
-+/*
-+ * MTD structure for SharpSL
-+ */
-+static struct mtd_info *sharpsl_mtd = NULL;
-+
-+/*
-+ * Define partitions for flash device
-+ */
-+#define DEFAULT_NUM_PARTITIONS 3
-+
-+static int nr_partitions;
-+static struct mtd_partition sharpsl_nand_default_partition_info[] = {
-+ {
-+ .name = "System Area",
-+ .offset = 0,
-+ .size = 7 * 1024 * 1024,
-+ },
-+ {
-+ .name = "Root Filesystem",
-+ .offset = 7 * 1024 * 1024,
-+ .size = 30 * 1024 * 1024,
-+ },
-+ {
-+ .name = "Home Filesystem",
-+ .offset = MTDPART_OFS_APPEND ,
-+ .size = MTDPART_SIZ_FULL ,
-+ },
-+};
-+
-+/*
-+ * hardware specific access to control-lines
-+ */
-+static void
-+sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd)
-+{
-+ switch (cmd) {
-+ case NAND_CTL_SETCLE:
-+ writeb(readb(FLASHCTL) | FLCLE, FLASHCTL);
-+ break;
-+ case NAND_CTL_CLRCLE:
-+ writeb(readb(FLASHCTL) & ~FLCLE, FLASHCTL);
-+ break;
-+
-+ case NAND_CTL_SETALE:
-+ writeb(readb(FLASHCTL) | FLALE, FLASHCTL);
-+ break;
-+ case NAND_CTL_CLRALE:
-+ writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL);
-+ break;
-+
-+ case NAND_CTL_SETNCE:
-+ writeb(readb(FLASHCTL) & ~(FLCE0|FLCE1), FLASHCTL);
-+ break;
-+ case NAND_CTL_CLRNCE:
-+ writeb(readb(FLASHCTL) | (FLCE0|FLCE1), FLASHCTL);
-+ break;
-+ }
-+}
-+
-+static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
-+
-+static struct nand_bbt_descr sharpsl_bbt = {
-+ .options = 0,
-+ .offs = 4,
-+ .len = 2,
-+ .pattern = scan_ff_pattern
-+};
-+
-+static int
-+sharpsl_nand_dev_ready(struct mtd_info* mtd)
-+{
-+ return !((readb(FLASHCTL) & FLRYBY) == 0);
-+}
-+
-+static void
-+sharpsl_nand_enable_hwecc(struct mtd_info* mtd, int mode)
-+{
-+ writeb(0 ,ECCCLRR);
-+}
-+
-+static int
-+sharpsl_nand_calculate_ecc(struct mtd_info* mtd, const u_char* dat,
-+ u_char* ecc_code)
-+{
-+ ecc_code[0] = ~readb(ECCLPUB);
-+ ecc_code[1] = ~readb(ECCLPLB);
-+ ecc_code[2] = (~readb(ECCCP) << 2) | 0x03;
-+ return readb(ECCCNTR) != 0;
-+}
-+
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+const char *part_probes[] = { "cmdlinepart", NULL };
-+#endif
-+
-+
-+/*
-+ * Main initialization routine
-+ */
-+int __init
-+sharpsl_nand_init(void)
-+{
-+ struct nand_chip *this;
-+ struct mtd_partition* sharpsl_partition_info;
-+ int err = 0;
-+
-+ /* Allocate memory for MTD device structure and private data */
-+ sharpsl_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip),
-+ GFP_KERNEL);
-+ if (!sharpsl_mtd) {
-+ printk ("Unable to allocate SharpSL NAND MTD device structure.\n");
-+ return -ENOMEM;
-+ }
-+
-+ /* map physical adress */
-+ sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000);
-+ if(!sharpsl_io_base){
-+ printk("ioremap to access Sharp SL NAND chip failed\n");
-+ kfree(sharpsl_mtd);
-+ return -EIO;
-+ }
-+
-+ /* Get pointer to private data */
-+ this = (struct nand_chip *) (&sharpsl_mtd[1]);
-+
-+ /* Initialize structures */
-+ memset((char *) sharpsl_mtd, 0, sizeof(struct mtd_info));
-+ memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+ /* Link the private data with the MTD structure */
-+ sharpsl_mtd->priv = this;
-+
-+ /*
-+ * PXA initialize
-+ */
-+ writeb(readb(FLASHCTL) | FLWP, FLASHCTL);
-+
-+ /* Set address of NAND IO lines */
-+ this->IO_ADDR_R = FLASHIO;
-+ this->IO_ADDR_W = FLASHIO;
-+ /* Set address of hardware control function */
-+ this->hwcontrol = sharpsl_nand_hwcontrol;
-+ this->dev_ready = sharpsl_nand_dev_ready;
-+ /* 15 us command delay time */
-+ this->chip_delay = 15;
-+ /* set eccmode using hardware ECC */
-+ this->eccmode = NAND_ECC_HW3_256;
-+ this->enable_hwecc = sharpsl_nand_enable_hwecc;
-+ this->calculate_ecc = sharpsl_nand_calculate_ecc;
-+ this->correct_data = nand_correct_data;
-+ this->badblock_pattern = &sharpsl_bbt;
-+
-+ /* Scan to find existence of the device */
-+ err=nand_scan(sharpsl_mtd,1);
-+ if (err) {
-+ iounmap(sharpsl_io_base);
-+ kfree(sharpsl_mtd);
-+ return err;
-+ }
-+
-+ /* Register the partitions */
-+ sharpsl_mtd->name = "sharpsl-nand";
-+ nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes,
-+ &sharpsl_partition_info, 0);
-+
-+ if (nr_partitions <= 0) {
-+ nr_partitions = DEFAULT_NUM_PARTITIONS;
-+ sharpsl_partition_info = sharpsl_nand_default_partition_info;
-+ if (machine_is_poodle()) {
-+ sharpsl_partition_info[1].size=30 * 1024 * 1024;
-+ } else if (machine_is_corgi() || machine_is_shepherd()) {
-+ sharpsl_partition_info[1].size=25 * 1024 * 1024;
-+ } else if (machine_is_husky()) {
-+ sharpsl_partition_info[1].size=53 * 1024 * 1024;
-+ }
-+ }
-+
-+ if (machine_is_husky()) {
-+ /* Need to use small eraseblock size for backward compatibility */
-+ sharpsl_mtd->flags |= MTD_NO_VIRTBLOCKS;
-+ }
-+
-+ add_mtd_partitions(sharpsl_mtd, sharpsl_partition_info, nr_partitions);
-+
-+ /* Return happy */
-+ return 0;
-+}
-+module_init(sharpsl_nand_init);
-+
-+/*
-+ * Clean up routine
-+ */
-+#ifdef MODULE
-+static void __exit sharpsl_nand_cleanup(void)
-+{
-+ struct nand_chip *this = (struct nand_chip *) &sharpsl_mtd[1];
-+
-+ /* Release resources, unregister device */
-+ nand_release(sharpsl_mtd);
-+
-+ iounmap(sharpsl_io_base);
-+
-+ /* Free the MTD device structure */
-+ kfree(sharpsl_mtd);
-+}
-+module_exit(sharpsl_nand_cleanup);
-+#endif
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
-+MODULE_DESCRIPTION("Device specific logic for NAND flash on Sharp SL-C7xx Series");
---- linux-2.4.21/drivers/mtd/nand/spia.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/nand/spia.c
-@@ -1,14 +1,14 @@
- /*
- * drivers/mtd/nand/spia.c
- *
-- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
-+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
- *
- *
- * 10-29-2001 TG change to support hardwarespecific access
- * to controllines (due to change in nand.c)
- * page_cache added
- *
-- * $Id: spia.c,v 1.16 2002/03/05 13:50:47 dwmw2 Exp $
-+ * $Id: spia.c,v 1.24 2004/11/04 12:53:10 gleixner 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
-@@ -20,6 +20,8 @@
- * a 64Mibit (8MiB x 8 bits) NAND flash device.
- */
-
-+#include <linux/kernel.h>
-+#include <linux/init.h>
- #include <linux/slab.h>
- #include <linux/module.h>
- #include <linux/mtd/mtd.h>
-@@ -35,14 +37,14 @@
- /*
- * Values specific to the SPIA board (used with EP7212 processor)
- */
--#define SPIA_IO_ADDR = 0xd0000000 /* Start of EP7212 IO address space */
--#define SPIA_FIO_ADDR = 0xf0000000 /* Address where flash is mapped */
--#define SPIA_PEDR = 0x0080 /*
-+#define SPIA_IO_BASE 0xd0000000 /* Start of EP7212 IO address space */
-+#define SPIA_FIO_BASE 0xf0000000 /* Address where flash is mapped */
-+#define SPIA_PEDR 0x0080 /*
- * IO offset to Port E data register
- * where the CLE, ALE and NCE pins
- * are wired to.
- */
--#define SPIA_PEDDR = 0x00c0 /*
-+#define SPIA_PEDDR 0x00c0 /*
- * IO offset to Port E data direction
- * register so we can control the IO
- * lines.
-@@ -57,26 +59,25 @@
- static int spia_pedr = SPIA_PEDR;
- static int spia_peddr = SPIA_PEDDR;
-
--MODULE_PARM(spia_io_base, "i");
--MODULE_PARM(spia_fio_base, "i");
--MODULE_PARM(spia_pedr, "i");
--MODULE_PARM(spia_peddr, "i");
--
--__setup("spia_io_base=",spia_io_base);
--__setup("spia_fio_base=",spia_fio_base);
--__setup("spia_pedr=",spia_pedr);
--__setup("spia_peddr=",spia_peddr);
-+module_param(spia_io_base, int, 0);
-+module_param(spia_fio_base, int, 0);
-+module_param(spia_pedr, int, 0);
-+module_param(spia_peddr, int, 0);
-
- /*
- * Define partitions for flash device
- */
- const static struct mtd_partition partition_info[] = {
-- { name: "SPIA flash partition 1",
-- offset: 0,
-- size: 2*1024*1024 },
-- { name: "SPIA flash partition 2",
-- offset: 2*1024*1024,
-- size: 6*1024*1024 }
-+ {
-+ .name = "SPIA flash partition 1",
-+ .offset = 0,
-+ .size = 2*1024*1024
-+ },
-+ {
-+ .name = "SPIA flash partition 2",
-+ .offset = 2*1024*1024,
-+ .size = 6*1024*1024
-+ }
- };
- #define NUM_PARTITIONS 2
-
-@@ -84,7 +85,7 @@
- /*
- * hardware specific access to control-lines
- */
--void spia_hwcontrol(int cmd){
-+static void spia_hwcontrol(struct mtd_info *mtd, int cmd){
-
- switch(cmd){
-
-@@ -131,37 +132,19 @@
- (*(volatile unsigned char *) (spia_io_base + spia_peddr)) = 0x07;
-
- /* Set address of NAND IO lines */
-- this->IO_ADDR_R = spia_fio_base;
-- this->IO_ADDR_W = spia_fio_base;
-+ this->IO_ADDR_R = (void __iomem *) spia_fio_base;
-+ this->IO_ADDR_W = (void __iomem *) spia_fio_base;
- /* Set address of hardware control function */
- this->hwcontrol = spia_hwcontrol;
- /* 15 us command delay time */
- this->chip_delay = 15;
-
- /* Scan to find existence of the device */
-- if (nand_scan (spia_mtd)) {
-+ if (nand_scan (spia_mtd, 1)) {
- kfree (spia_mtd);
- return -ENXIO;
- }
-
-- /* Allocate memory for internal data buffer */
-- this->data_buf = kmalloc (sizeof(u_char) * (spia_mtd->oobblock + spia_mtd->oobsize), GFP_KERNEL);
-- if (!this->data_buf) {
-- printk ("Unable to allocate NAND data buffer for SPIA.\n");
-- kfree (spia_mtd);
-- return -ENOMEM;
-- }
--
-- /* Allocate memory for internal data buffer */
-- this->data_cache = kmalloc (sizeof(u_char) * (spia_mtd->oobblock + spia_mtd->oobsize), GFP_KERNEL);
-- if (!this->data_cache) {
-- printk ("Unable to allocate NAND data cache for SPIA.\n");
-- kfree (this->data_buf);
-- kfree (spia_mtd);
-- return = -ENOMEM;
-- }
-- this->cache_page = -1;
--
- /* Register the partitions */
- add_mtd_partitions(spia_mtd, partition_info, NUM_PARTITIONS);
-
-@@ -176,14 +159,8 @@
- #ifdef MODULE
- static void __exit spia_cleanup (void)
- {
-- struct nand_chip *this = (struct nand_chip *) &spia_mtd[1];
--
-- /* Unregister the device */
-- del_mtd_device (spia_mtd);
--
-- /* Free internal data buffer */
-- kfree (this->data_buf);
-- kfree (this->page_cache);
-+ /* Release resources, unregister device */
-+ nand_release (spia_mtd);
-
- /* Free the MTD device structure */
- kfree (spia_mtd);
-@@ -192,5 +169,5 @@
- #endif
-
- MODULE_LICENSE("GPL");
--MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com");
-+MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com");
- MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on SPIA board");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/nand/toto.c
-@@ -0,0 +1,205 @@
-+/*
-+ * drivers/mtd/nand/toto.c
-+ *
-+ * Copyright (c) 2003 Texas Instruments
-+ *
-+ * Derived from drivers/mtd/autcpu12.c
-+ *
-+ * Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de>
-+ *
-+ * 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.
-+ *
-+ * Overview:
-+ * This is a device driver for the NAND flash device found on the
-+ * TI fido board. It supports 32MiB and 64MiB cards
-+ *
-+ * $Id: toto.c,v 1.4 2004/10/05 13:50:20 gleixner Exp $
-+ */
-+
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/io.h>
-+#include <asm/arch/hardware.h>
-+#include <asm/sizes.h>
-+#include <asm/arch/toto.h>
-+#include <asm/arch-omap1510/hardware.h>
-+#include <asm/arch/gpio.h>
-+
-+/*
-+ * MTD structure for TOTO board
-+ */
-+static struct mtd_info *toto_mtd = NULL;
-+
-+static unsigned long toto_io_base = OMAP_FLASH_1_BASE;
-+
-+#define CONFIG_NAND_WORKAROUND 1
-+
-+#define NAND_NCE 0x4000
-+#define NAND_CLE 0x1000
-+#define NAND_ALE 0x0002
-+#define NAND_MASK (NAND_CLE | NAND_ALE | NAND_NCE)
-+
-+#define T_NAND_CTL_CLRALE(iob) gpiosetout(NAND_ALE, 0)
-+#define T_NAND_CTL_SETALE(iob) gpiosetout(NAND_ALE, NAND_ALE)
-+#ifdef CONFIG_NAND_WORKAROUND /* "some" dev boards busted, blue wired to rts2 :( */
-+#define T_NAND_CTL_CLRCLE(iob) gpiosetout(NAND_CLE, 0); rts2setout(2, 2)
-+#define T_NAND_CTL_SETCLE(iob) gpiosetout(NAND_CLE, NAND_CLE); rts2setout(2, 0)
-+#else
-+#define T_NAND_CTL_CLRCLE(iob) gpiosetout(NAND_CLE, 0)
-+#define T_NAND_CTL_SETCLE(iob) gpiosetout(NAND_CLE, NAND_CLE)
-+#endif
-+#define T_NAND_CTL_SETNCE(iob) gpiosetout(NAND_NCE, 0)
-+#define T_NAND_CTL_CLRNCE(iob) gpiosetout(NAND_NCE, NAND_NCE)
-+
-+/*
-+ * Define partitions for flash devices
-+ */
-+
-+static struct mtd_partition partition_info64M[] = {
-+ { .name = "toto kernel partition 1",
-+ .offset = 0,
-+ .size = 2 * SZ_1M },
-+ { .name = "toto file sys partition 2",
-+ .offset = 2 * SZ_1M,
-+ .size = 14 * SZ_1M },
-+ { .name = "toto user partition 3",
-+ .offset = 16 * SZ_1M,
-+ .size = 16 * SZ_1M },
-+ { .name = "toto devboard extra partition 4",
-+ .offset = 32 * SZ_1M,
-+ .size = 32 * SZ_1M },
-+};
-+
-+static struct mtd_partition partition_info32M[] = {
-+ { .name = "toto kernel partition 1",
-+ .offset = 0,
-+ .size = 2 * SZ_1M },
-+ { .name = "toto file sys partition 2",
-+ .offset = 2 * SZ_1M,
-+ .size = 14 * SZ_1M },
-+ { .name = "toto user partition 3",
-+ .offset = 16 * SZ_1M,
-+ .size = 16 * SZ_1M },
-+};
-+
-+#define NUM_PARTITIONS32M 3
-+#define NUM_PARTITIONS64M 4
-+/*
-+ * hardware specific access to control-lines
-+*/
-+
-+static void toto_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+
-+ udelay(1); /* hopefully enough time for tc make proceding write to clear */
-+ switch(cmd){
-+
-+ case NAND_CTL_SETCLE: T_NAND_CTL_SETCLE(cmd); break;
-+ case NAND_CTL_CLRCLE: T_NAND_CTL_CLRCLE(cmd); break;
-+
-+ case NAND_CTL_SETALE: T_NAND_CTL_SETALE(cmd); break;
-+ case NAND_CTL_CLRALE: T_NAND_CTL_CLRALE(cmd); break;
-+
-+ case NAND_CTL_SETNCE: T_NAND_CTL_SETNCE(cmd); break;
-+ case NAND_CTL_CLRNCE: T_NAND_CTL_CLRNCE(cmd); break;
-+ }
-+ udelay(1); /* allow time to ensure gpio state to over take memory write */
-+}
-+
-+/*
-+ * Main initialization routine
-+ */
-+int __init toto_init (void)
-+{
-+ struct nand_chip *this;
-+ int err = 0;
-+
-+ /* Allocate memory for MTD device structure and private data */
-+ toto_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
-+ GFP_KERNEL);
-+ if (!toto_mtd) {
-+ printk (KERN_WARNING "Unable to allocate toto NAND MTD device structure.\n");
-+ err = -ENOMEM;
-+ goto out;
-+ }
-+
-+ /* Get pointer to private data */
-+ this = (struct nand_chip *) (&toto_mtd[1]);
-+
-+ /* Initialize structures */
-+ memset((char *) toto_mtd, 0, sizeof(struct mtd_info));
-+ memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+ /* Link the private data with the MTD structure */
-+ toto_mtd->priv = this;
-+
-+ /* Set address of NAND IO lines */
-+ this->IO_ADDR_R = toto_io_base;
-+ this->IO_ADDR_W = toto_io_base;
-+ this->hwcontrol = toto_hwcontrol;
-+ this->dev_ready = NULL;
-+ /* 25 us command delay time */
-+ this->chip_delay = 30;
-+ this->eccmode = NAND_ECC_SOFT;
-+
-+ /* Scan to find existance of the device */
-+ if (nand_scan (toto_mtd, 1)) {
-+ err = -ENXIO;
-+ goto out_mtd;
-+ }
-+
-+ /* Register the partitions */
-+ switch(toto_mtd->size){
-+ case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break;
-+ case SZ_32M: add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); break;
-+ default: {
-+ printk (KERN_WARNING "Unsupported Nand device\n");
-+ err = -ENXIO;
-+ goto out_buf;
-+ }
-+ }
-+
-+ gpioreserve(NAND_MASK); /* claim our gpios */
-+ archflashwp(0,0); /* open up flash for writing */
-+
-+ goto out;
-+
-+out_buf:
-+ kfree (this->data_buf);
-+out_mtd:
-+ kfree (toto_mtd);
-+out:
-+ return err;
-+}
-+
-+module_init(toto_init);
-+
-+/*
-+ * Clean up routine
-+ */
-+static void __exit toto_cleanup (void)
-+{
-+ /* Release resources, unregister device */
-+ nand_release (toto_mtd);
-+
-+ /* Free the MTD device structure */
-+ kfree (toto_mtd);
-+
-+ /* stop flash writes */
-+ archflashwp(0,1);
-+
-+ /* release gpios to system */
-+ gpiorelease(NAND_MASK);
-+}
-+module_exit(toto_cleanup);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Richard Woodruff <r-woodruff2@ti.com>");
-+MODULE_DESCRIPTION("Glue layer for NAND flash on toto board");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/nand/tx4925ndfmc.c
-@@ -0,0 +1,416 @@
-+/*
-+ * 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.5 2004/10/05 13:50:20 gleixner 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 = (void __iomem *)&(tx4925_ndfmcptr->dtr);
-+ this->IO_ADDR_W = (void __iomem *)&(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;
-+ }
-+
-+ /* 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_ior;
-+ }
-+ }
-+#endif /* ifdef CONFIG_MTD_CMDLINE_PARTS */
-+ goto out;
-+
-+out_ior:
-+out:
-+ return err;
-+}
-+
-+module_init(tx4925ndfmc_init);
-+
-+/*
-+ * Clean up routine
-+ */
-+#ifdef MODULE
-+static void __exit tx4925ndfmc_cleanup (void)
-+{
-+ /* Release resources, unregister device */
-+ nand_release (tx4925ndfmc_mtd);
-+
-+ /* 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");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/nand/tx4938ndfmc.c
-@@ -0,0 +1,406 @@
-+/*
-+ * drivers/mtd/nand/tx4938ndfmc.c
-+ *
-+ * Overview:
-+ * This is a device driver for the NAND flash device connected to
-+ * TX4938 internal NAND Memory Controller.
-+ * TX4938 NDFMC is almost same as TX4925 NDFMC, but register size are 64 bit.
-+ *
-+ * Author: source@mvista.com
-+ *
-+ * Based on spia.c by Steven J. Hill
-+ *
-+ * $Id: tx4938ndfmc.c,v 1.4 2004/10/05 13:50:20 gleixner Exp $
-+ *
-+ * Copyright (C) 2000-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/config.h>
-+#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/nand_ecc.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/io.h>
-+#include <asm/bootinfo.h>
-+#include <linux/delay.h>
-+#include <asm/tx4938/rbtx4938.h>
-+
-+extern struct nand_oobinfo jffs2_oobinfo;
-+
-+/*
-+ * MTD structure for TX4938 NDFMC
-+ */
-+static struct mtd_info *tx4938ndfmc_mtd;
-+
-+/*
-+ * Define partitions for flash device
-+ */
-+#define flush_wb() (void)tx4938_ndfmcptr->mcr;
-+
-+#define NUM_PARTITIONS 3
-+#define NUMBER_OF_CIS_BLOCKS 24
-+#define SIZE_OF_BLOCK 0x00004000
-+#define NUMBER_OF_BLOCK_PER_ZONE 1024
-+#define SIZE_OF_ZONE (NUMBER_OF_BLOCK_PER_ZONE * SIZE_OF_BLOCK)
-+#ifndef CONFIG_MTD_CMDLINE_PARTS
-+/*
-+ * You can use the following sample of MTD partitions
-+ * on the NAND Flash Memory 32MB or more.
-+ *
-+ * The following figure shows the image of the sample partition on
-+ * the 32MB NAND Flash Memory.
-+ *
-+ * Block No.
-+ * 0 +-----------------------------+ ------
-+ * | CIS | ^
-+ * 24 +-----------------------------+ |
-+ * | kernel image | | Zone 0
-+ * | | |
-+ * +-----------------------------+ |
-+ * 1023 | unused area | v
-+ * +-----------------------------+ ------
-+ * 1024 | JFFS2 | ^
-+ * | | |
-+ * | | | Zone 1
-+ * | | |
-+ * | | |
-+ * | | v
-+ * 2047 +-----------------------------+ ------
-+ *
-+ */
-+static struct mtd_partition partition_info[NUM_PARTITIONS] = {
-+ {
-+ .name = "RBTX4938 CIS Area",
-+ .offset = 0,
-+ .size = (NUMBER_OF_CIS_BLOCKS * SIZE_OF_BLOCK),
-+ .mask_flags = MTD_WRITEABLE /* This partition is NOT writable */
-+ },
-+ {
-+ .name = "RBTX4938 kernel image",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = 8 * 0x00100000, /* 8MB (Depends on size of kernel image) */
-+ .mask_flags = MTD_WRITEABLE /* This partition is NOT writable */
-+ },
-+ {
-+ .name = "Root FS (JFFS2)",
-+ .offset = (0 + SIZE_OF_ZONE), /* start address of next zone */
-+ .size = MTDPART_SIZ_FULL
-+ },
-+};
-+#endif
-+
-+static void tx4938ndfmc_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+ switch (cmd) {
-+ case NAND_CTL_SETCLE:
-+ tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_CLE;
-+ break;
-+ case NAND_CTL_CLRCLE:
-+ tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_CLE;
-+ break;
-+ case NAND_CTL_SETALE:
-+ tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_ALE;
-+ break;
-+ case NAND_CTL_CLRALE:
-+ tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_ALE;
-+ break;
-+ /* TX4938_NDFMCR_CE bit is 0:high 1:low */
-+ case NAND_CTL_SETNCE:
-+ tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_CE;
-+ break;
-+ case NAND_CTL_CLRNCE:
-+ tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_CE;
-+ break;
-+ case NAND_CTL_SETWP:
-+ tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_WE;
-+ break;
-+ case NAND_CTL_CLRWP:
-+ tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_WE;
-+ break;
-+ }
-+}
-+static int tx4938ndfmc_dev_ready(struct mtd_info *mtd)
-+{
-+ flush_wb();
-+ return !(tx4938_ndfmcptr->sr & TX4938_NDFSR_BUSY);
-+}
-+static void tx4938ndfmc_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
-+{
-+ u32 mcr = tx4938_ndfmcptr->mcr;
-+ mcr &= ~TX4938_NDFMCR_ECC_ALL;
-+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF;
-+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_READ;
-+ ecc_code[1] = tx4938_ndfmcptr->dtr;
-+ ecc_code[0] = tx4938_ndfmcptr->dtr;
-+ ecc_code[2] = tx4938_ndfmcptr->dtr;
-+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF;
-+}
-+static void tx4938ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
-+{
-+ u32 mcr = tx4938_ndfmcptr->mcr;
-+ mcr &= ~TX4938_NDFMCR_ECC_ALL;
-+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_RESET;
-+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF;
-+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_ON;
-+}
-+
-+static u_char tx4938ndfmc_nand_read_byte(struct mtd_info *mtd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ return tx4938_read_nfmc(this->IO_ADDR_R);
-+}
-+
-+static void tx4938ndfmc_nand_write_byte(struct mtd_info *mtd, u_char byte)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ tx4938_write_nfmc(byte, this->IO_ADDR_W);
-+}
-+
-+static void tx4938ndfmc_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++)
-+ tx4938_write_nfmc(buf[i], this->IO_ADDR_W);
-+}
-+
-+static void tx4938ndfmc_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] = tx4938_read_nfmc(this->IO_ADDR_R);
-+}
-+
-+static int tx4938ndfmc_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] != tx4938_read_nfmc(this->IO_ADDR_R))
-+ return -EFAULT;
-+
-+ return 0;
-+}
-+
-+/*
-+ * Send command to NAND device
-+ */
-+static void tx4938ndfmc_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_partition **pparts, char *);
-+#endif
-+/*
-+ * Main initialization routine
-+ */
-+int __init tx4938ndfmc_init (void)
-+{
-+ struct nand_chip *this;
-+ int bsprt = 0, hold = 0xf, spw = 0xf;
-+ int protected = 0;
-+
-+ if ((*rbtx4938_piosel_ptr & 0x0c) != 0x08) {
-+ printk("TX4938 NDFMC: disabled by IOC PIOSEL\n");
-+ return -ENODEV;
-+ }
-+ bsprt = 1;
-+ hold = 2;
-+ spw = 9 - 1; /* 8 GBUSCLK = 80ns (@ GBUSCLK 100MHz) */
-+
-+ if ((tx4938_ccfgptr->pcfg &
-+ (TX4938_PCFG_ATA_SEL|TX4938_PCFG_ISA_SEL|TX4938_PCFG_NDF_SEL))
-+ != TX4938_PCFG_NDF_SEL) {
-+ printk("TX4938 NDFMC: disabled by PCFG.\n");
-+ return -ENODEV;
-+ }
-+
-+ /* reset NDFMC */
-+ tx4938_ndfmcptr->rstr |= TX4938_NDFRSTR_RST;
-+ while (tx4938_ndfmcptr->rstr & TX4938_NDFRSTR_RST)
-+ ;
-+ /* setup BusSeparete, Hold Time, Strobe Pulse Width */
-+ tx4938_ndfmcptr->mcr = bsprt ? TX4938_NDFMCR_BSPRT : 0;
-+ tx4938_ndfmcptr->spr = hold << 4 | spw;
-+
-+ /* Allocate memory for MTD device structure and private data */
-+ tx4938ndfmc_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
-+ GFP_KERNEL);
-+ if (!tx4938ndfmc_mtd) {
-+ printk ("Unable to allocate TX4938 NDFMC MTD device structure.\n");
-+ return -ENOMEM;
-+ }
-+
-+ /* Get pointer to private data */
-+ this = (struct nand_chip *) (&tx4938ndfmc_mtd[1]);
-+
-+ /* Initialize structures */
-+ memset((char *) tx4938ndfmc_mtd, 0, sizeof(struct mtd_info));
-+ memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+ /* Link the private data with the MTD structure */
-+ tx4938ndfmc_mtd->priv = this;
-+
-+ /* Set address of NAND IO lines */
-+ this->IO_ADDR_R = (unsigned long)&tx4938_ndfmcptr->dtr;
-+ this->IO_ADDR_W = (unsigned long)&tx4938_ndfmcptr->dtr;
-+ this->hwcontrol = tx4938ndfmc_hwcontrol;
-+ this->dev_ready = tx4938ndfmc_dev_ready;
-+ this->calculate_ecc = tx4938ndfmc_calculate_ecc;
-+ this->correct_data = nand_correct_data;
-+ this->enable_hwecc = tx4938ndfmc_enable_hwecc;
-+ this->eccmode = NAND_ECC_HW3_256;
-+ this->chip_delay = 100;
-+ this->read_byte = tx4938ndfmc_nand_read_byte;
-+ this->write_byte = tx4938ndfmc_nand_write_byte;
-+ this->cmdfunc = tx4938ndfmc_nand_command;
-+ this->write_buf = tx4938ndfmc_nand_write_buf;
-+ this->read_buf = tx4938ndfmc_nand_read_buf;
-+ this->verify_buf = tx4938ndfmc_nand_verify_buf;
-+
-+ /* Scan to find existance of the device */
-+ if (nand_scan (tx4938ndfmc_mtd, 1)) {
-+ kfree (tx4938ndfmc_mtd);
-+ return -ENXIO;
-+ }
-+
-+ if (protected) {
-+ printk(KERN_INFO "TX4938 NDFMC: write protected.\n");
-+ tx4938ndfmc_mtd->flags &= ~(MTD_WRITEABLE | MTD_ERASEABLE);
-+ }
-+
-+#ifdef CONFIG_MTD_CMDLINE_PARTS
-+ {
-+ int mtd_parts_nb = 0;
-+ struct mtd_partition *mtd_parts = 0;
-+ mtd_parts_nb = parse_cmdline_partitions(tx4938ndfmc_mtd, &mtd_parts, "tx4938ndfmc");
-+ if (mtd_parts_nb > 0)
-+ add_mtd_partitions(tx4938ndfmc_mtd, mtd_parts, mtd_parts_nb);
-+ else
-+ add_mtd_device(tx4938ndfmc_mtd);
-+ }
-+#else
-+ add_mtd_partitions(tx4938ndfmc_mtd, partition_info, NUM_PARTITIONS );
-+#endif
-+
-+ return 0;
-+}
-+module_init(tx4938ndfmc_init);
-+
-+/*
-+ * Clean up routine
-+ */
-+static void __exit tx4938ndfmc_cleanup (void)
-+{
-+ /* Release resources, unregister device */
-+ nand_release (tx4938ndfmc_mtd);
-+
-+ /* Free the MTD device structure */
-+ kfree (tx4938ndfmc_mtd);
-+}
-+module_exit(tx4938ndfmc_cleanup);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>");
-+MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on TX4938 NDFMC");
---- linux-2.4.21/drivers/mtd/nftlcore.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/nftlcore.c
-@@ -1,7 +1,7 @@
- /* Linux driver for NAND Flash Translation Layer */
- /* (c) 1999 Machine Vision Holdings, Inc. */
- /* Author: David Woodhouse <dwmw2@infradead.org> */
--/* $Id: nftlcore.c,v 1.87 2002/09/13 14:35:33 dwmw2 Exp $ */
-+/* $Id: nftlcore.c,v 1.97 2004/11/16 18:28:59 dwmw2 Exp $ */
-
- /*
- The contents of this file are distributed under the GNU General
-@@ -23,15 +23,13 @@
- #include <linux/slab.h>
- #include <linux/sched.h>
- #include <linux/init.h>
--#include <linux/blkpg.h>
-+#include <linux/hdreg.h>
-
--#ifdef CONFIG_KMOD
- #include <linux/kmod.h>
--#endif
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
- #include <linux/mtd/nftl.h>
--#include <linux/mtd/compatmac.h>
-+#include <linux/mtd/blktrans.h>
-
- /* maximum number of loops while examining next block, to have a
- chance to detect consistency problems (they should never happen
-@@ -39,187 +37,107 @@
-
- #define MAX_LOOPS 10000
-
--/* NFTL block device stuff */
--#define MAJOR_NR NFTL_MAJOR
--#define DEVICE_REQUEST nftl_request
--#define DEVICE_OFF(device)
--
--
--#include <linux/blk.h>
--#include <linux/hdreg.h>
--
--/* Linux-specific block device functions */
--
--/* I _HATE_ the Linux block device setup more than anything else I've ever
-- * encountered, except ...
-- */
--
--static int nftl_sizes[256];
--static int nftl_blocksizes[256];
--
--/* .. for the Linux partition table handling. */
--struct hd_struct part_table[256];
--
--#if LINUX_VERSION_CODE < 0x20328
--static void dummy_init (struct gendisk *crap)
--{}
--#endif
--
--static struct gendisk nftl_gendisk = {
-- major: MAJOR_NR,
-- major_name: "nftl",
-- minor_shift: NFTL_PARTN_BITS, /* Bits to shift to get real from partition */
-- max_p: (1<<NFTL_PARTN_BITS)-1, /* Number of partitions per real */
--#if LINUX_VERSION_CODE < 0x20328
-- max_nr: MAX_NFTLS, /* maximum number of real */
-- init: dummy_init, /* init function */
--#endif
-- part: part_table, /* hd struct */
-- sizes: nftl_sizes, /* block sizes */
--};
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
--#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
--#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
--#else
--#define BLK_INC_USE_COUNT do {} while(0)
--#define BLK_DEC_USE_COUNT do {} while(0)
--#endif
--
--struct NFTLrecord *NFTLs[MAX_NFTLS];
-
--static void NFTL_setup(struct mtd_info *mtd)
-+static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
- {
-- int i;
- struct NFTLrecord *nftl;
- unsigned long temp;
-- int firstfree = -1;
--
-- DEBUG(MTD_DEBUG_LEVEL1,"NFTL_setup\n");
-
-- for (i = 0; i < MAX_NFTLS; i++) {
-- if (!NFTLs[i] && firstfree == -1)
-- firstfree = i;
-- else if (NFTLs[i] && NFTLs[i]->mtd == mtd) {
-- /* This is a Spare Media Header for an NFTL we've already found */
-- DEBUG(MTD_DEBUG_LEVEL1, "MTD already mounted as NFTL\n");
-+ if (mtd->type != MTD_NANDFLASH)
- return;
-- }
-- }
-- if (firstfree == -1) {
-- printk(KERN_WARNING "No more NFTL slot available\n");
-+ /* OK, this is moderately ugly. But probably safe. Alternatives? */
-+ if (memcmp(mtd->name, "DiskOnChip", 10))
-+ return;
-+
-+ if (!mtd->block_isbad) {
-+ printk(KERN_ERR
-+"NFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
-+"Please use the new diskonchip driver under the NAND subsystem.\n");
- return;
- }
-
-+ DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name);
-+
- nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
-+
- if (!nftl) {
-- printk(KERN_WARNING "Out of memory for NFTL data structures\n");
-+ printk(KERN_WARNING "NFTL: out of memory for data structures\n");
- return;
- }
-+ memset(nftl, 0, sizeof(*nftl));
-
-- init_MUTEX(&nftl->mutex);
--
-- nftl->mtd = mtd;
-+ nftl->mbd.mtd = mtd;
-+ nftl->mbd.devnum = -1;
-+ nftl->mbd.blksize = 512;
-+ nftl->mbd.tr = tr;
-+ memcpy(&nftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo));
-+ nftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY;
-
- if (NFTL_mount(nftl) < 0) {
-- printk(KERN_WARNING "Could not mount NFTL device\n");
-+ printk(KERN_WARNING "NFTL: could not mount device\n");
- kfree(nftl);
- return;
- }
-
- /* OK, it's a new one. Set up all the data structures. */
--#ifdef PSYCHO_DEBUG
-- printk("Found new NFTL nftl%c\n", firstfree + 'a');
--#endif
-
-- /* linux stuff */
-- nftl->usecount = 0;
-+ /* Calculate geometry */
- nftl->cylinders = 1024;
- nftl->heads = 16;
-
- temp = nftl->cylinders * nftl->heads;
-- nftl->sectors = nftl->nr_sects / temp;
-- if (nftl->nr_sects % temp) {
-+ nftl->sectors = nftl->mbd.size / temp;
-+ if (nftl->mbd.size % temp) {
- nftl->sectors++;
- temp = nftl->cylinders * nftl->sectors;
-- nftl->heads = nftl->nr_sects / temp;
-+ nftl->heads = nftl->mbd.size / temp;
-
-- if (nftl->nr_sects % temp) {
-+ if (nftl->mbd.size % temp) {
- nftl->heads++;
- temp = nftl->heads * nftl->sectors;
-- nftl->cylinders = nftl->nr_sects / temp;
-+ nftl->cylinders = nftl->mbd.size / temp;
- }
- }
-
-- if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) {
-- printk(KERN_WARNING "Cannot calculate an NFTL geometry to "
-- "match size of 0x%x.\n", nftl->nr_sects);
-- printk(KERN_WARNING "Using C:%d H:%d S:%d (== 0x%lx sects)\n",
-+ if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) {
-+ /*
-+ Oh no we don't have
-+ mbd.size == heads * cylinders * sectors
-+ */
-+ printk(KERN_WARNING "NFTL: cannot calculate a geometry to "
-+ "match size of 0x%lx.\n", nftl->mbd.size);
-+ printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d "
-+ "(== 0x%lx sects)\n",
- nftl->cylinders, nftl->heads , nftl->sectors,
-- (long)nftl->cylinders * (long)nftl->heads * (long)nftl->sectors );
--
-- /* Oh no we don't have nftl->nr_sects = nftl->heads * nftl->cylinders * nftl->sectors; */
-+ (long)nftl->cylinders * (long)nftl->heads *
-+ (long)nftl->sectors );
- }
-- NFTLs[firstfree] = nftl;
-- /* Finally, set up the block device sizes */
-- nftl_sizes[firstfree * 16] = nftl->nr_sects;
-- //nftl_blocksizes[firstfree*16] = 512;
-- part_table[firstfree * 16].nr_sects = nftl->nr_sects;
--
-- nftl_gendisk.nr_real++;
--
-- /* partition check ... */
--#if LINUX_VERSION_CODE < 0x20328
-- resetup_one_dev(&nftl_gendisk, firstfree);
--#else
-- grok_partitions(&nftl_gendisk, firstfree, 1<<NFTL_PARTN_BITS, nftl->nr_sects);
--#endif
--}
--
--static void NFTL_unsetup(int i)
--{
-- struct NFTLrecord *nftl = NFTLs[i];
--
-- DEBUG(MTD_DEBUG_LEVEL1, "NFTL_unsetup %d\n", i);
--
-- NFTLs[i] = NULL;
-
-+ if (add_mtd_blktrans_dev(&nftl->mbd)) {
- if (nftl->ReplUnitTable)
- kfree(nftl->ReplUnitTable);
- if (nftl->EUNtable)
- kfree(nftl->EUNtable);
--
-- nftl_gendisk.nr_real--;
- kfree(nftl);
--}
--
--/* Search the MTD device for NFTL partitions */
--static void NFTL_notify_add(struct mtd_info *mtd)
--{
-- DEBUG(MTD_DEBUG_LEVEL1, "NFTL_notify_add for %s\n", mtd->name);
--
-- if (mtd) {
-- if (!mtd->read_oob) {
-- /* If this MTD doesn't have out-of-band data,
-- then there's no point continuing */
-- DEBUG(MTD_DEBUG_LEVEL1, "No OOB data, quitting\n");
- return;
- }
-- DEBUG(MTD_DEBUG_LEVEL3, "mtd->read = %p, size = %d, erasesize = %d\n",
-- mtd->read, mtd->size, mtd->erasesize);
--
-- NFTL_setup(mtd);
-- }
-+#ifdef PSYCHO_DEBUG
-+ printk(KERN_INFO "NFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a');
-+#endif
- }
-
--static void NFTL_notify_remove(struct mtd_info *mtd)
-+static void nftl_remove_dev(struct mtd_blktrans_dev *dev)
- {
-- int i;
-+ struct NFTLrecord *nftl = (void *)dev;
-
-- for (i = 0; i < MAX_NFTLS; i++) {
-- if (NFTLs[i] && NFTLs[i]->mtd == mtd)
-- NFTL_unsetup(i);
-- }
-+ DEBUG(MTD_DEBUG_LEVEL1, "NFTL: remove_dev (i=%d)\n", dev->devnum);
-+
-+ del_mtd_blktrans_dev(dev);
-+ if (nftl->ReplUnitTable)
-+ kfree(nftl->ReplUnitTable);
-+ if (nftl->EUNtable)
-+ kfree(nftl->EUNtable);
-+ kfree(nftl);
- }
-
- #ifdef CONFIG_NFTL_RW
-@@ -303,7 +221,7 @@
-
- targetEUN = thisEUN;
- for (block = 0; block < nftl->EraseSize / 512; block ++) {
-- MTD_READOOB(nftl->mtd,
-+ MTD_READOOB(nftl->mbd.mtd,
- (thisEUN * nftl->EraseSize) + (block * 512),
- 16 , &retlen, (char *)&oob);
- if (block == 2) {
-@@ -420,7 +338,7 @@
- chain by selecting the longer one */
- oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
- oob.u.c.unused = 0xffffffff;
-- MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
-+ MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
- 8, &retlen, (char *)&oob.u);
- }
-
-@@ -444,17 +362,19 @@
- if (BlockMap[block] == BLOCK_NIL)
- continue;
-
-- ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
-- 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
-+ ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
-+ 512, &retlen, movebuf);
- if (ret < 0) {
-- ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
-+ ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block])
- + (block * 512), 512, &retlen,
-- movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
-+ movebuf);
- if (ret != -EIO)
- printk("Error went away on retry.\n");
- }
-- MTD_WRITEECC(nftl->mtd, (nftl->EraseSize * targetEUN) + (block * 512),
-- 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
-+ memset(&oob, 0xff, sizeof(struct nftl_oob));
-+ oob.b.Status = oob.b.Status1 = SECTOR_USED;
-+ MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512),
-+ 512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo);
- }
-
- /* add the header so that it is now a valid chain */
-@@ -462,7 +382,7 @@
- = cpu_to_le16(thisVUC);
- oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
-
-- MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 8,
-+ MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8,
- 8, &retlen, (char *)&oob.u);
-
- /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
-@@ -484,7 +404,6 @@
-
- if (NFTL_formatblock(nftl, thisEUN) < 0) {
- /* could not erase : mark block as reserved
-- * FixMe: Update Bad Unit Table on disk
- */
- nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
- } else {
-@@ -502,7 +421,7 @@
- return targetEUN;
- }
-
--u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
-+static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
- {
- /* This is the part that needs some cleverness applied.
- For now, I'm doing the minimum applicable to actually
-@@ -582,7 +501,7 @@
-
- lastEUN = writeEUN;
-
-- MTD_READOOB(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
-+ MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
- 8, &retlen, (char *)&bci);
-
- DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
-@@ -670,12 +589,12 @@
- nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
-
- /* ... and on the flash itself */
-- MTD_READOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
-+ MTD_READOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8,
- &retlen, (char *)&oob.u);
-
- oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
-
-- MTD_WRITEOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
-+ MTD_WRITEOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8,
- &retlen, (char *)&oob.u);
-
- /* we link the new block to the chain only after the
-@@ -685,13 +604,13 @@
- /* Both in our cache... */
- nftl->ReplUnitTable[lastEUN] = writeEUN;
- /* ... and on the flash itself */
-- MTD_READOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
-+ MTD_READOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8,
- 8, &retlen, (char *)&oob.u);
-
- oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
- = cpu_to_le16(writeEUN);
-
-- MTD_WRITEOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
-+ MTD_WRITEOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8,
- 8, &retlen, (char *)&oob.u);
- }
-
-@@ -704,12 +623,14 @@
- return 0xffff;
- }
-
--static int NFTL_writeblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
-+static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
-+ char *buffer)
- {
-+ struct NFTLrecord *nftl = (void *)mbd;
- u16 writeEUN;
- unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
- size_t retlen;
-- u8 eccbuf[6];
-+ struct nftl_oob oob;
-
- writeEUN = NFTL_findwriteunit(nftl, block);
-
-@@ -720,16 +641,20 @@
- return 1;
- }
-
-- MTD_WRITEECC(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
-- 512, &retlen, (char *)buffer, (char *)eccbuf, NAND_ECC_DISKONCHIP);
-- /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */
-+ memset(&oob, 0xff, sizeof(struct nftl_oob));
-+ oob.b.Status = oob.b.Status1 = SECTOR_USED;
-+ MTD_WRITEECC(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
-+ 512, &retlen, (char *)buffer, (char *)&oob, &nftl->oobinfo);
-+ /* need to write SECTOR_USED flags since they are not written in mtd_writeecc */
-
- return 0;
- }
- #endif /* CONFIG_NFTL_RW */
-
--static int NFTL_readblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
-+static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
-+ char *buffer)
- {
-+ struct NFTLrecord *nftl = (void *)mbd;
- u16 lastgoodEUN;
- u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
- unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
-@@ -742,7 +667,7 @@
-
- if (thisEUN != BLOCK_NIL) {
- while (thisEUN < nftl->nb_blocks) {
-- if (MTD_READOOB(nftl->mtd, (thisEUN * nftl->EraseSize) + blockofs,
-+ if (MTD_READOOB(nftl->mbd.mtd, (thisEUN * nftl->EraseSize) + blockofs,
- 8, &retlen, (char *)&bci) < 0)
- status = SECTOR_IGNORE;
- else
-@@ -761,13 +686,13 @@
- case SECTOR_IGNORE:
- break;
- default:
-- printk("Unknown status for block %d in EUN %d: %x\n",
-+ printk("Unknown status for block %ld in EUN %d: %x\n",
- block, thisEUN, status);
- break;
- }
-
- if (!silly--) {
-- printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
-+ printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%lx\n",
- block / (nftl->EraseSize / 512));
- return 1;
- }
-@@ -782,265 +707,22 @@
- } else {
- loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
- size_t retlen;
-- u_char eccbuf[6];
-- if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP))
-+ if (MTD_READ(nftl->mbd.mtd, ptr, 512, &retlen, buffer))
- return -EIO;
- }
- return 0;
- }
-
--static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
--{
-- struct NFTLrecord *nftl;
-- int p;
--
-- nftl = NFTLs[MINOR(inode->i_rdev) >> NFTL_PARTN_BITS];
--
-- if (!nftl) return -EINVAL;
--
-- switch (cmd) {
-- case HDIO_GETGEO: {
-- struct hd_geometry g;
--
-- g.heads = nftl->heads;
-- g.sectors = nftl->sectors;
-- g.cylinders = nftl->cylinders;
-- g.start = part_table[MINOR(inode->i_rdev)].start_sect;
-- return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0;
-- }
-- case BLKGETSIZE: /* Return device size */
-- return put_user(part_table[MINOR(inode->i_rdev)].nr_sects,
-- (unsigned long *) arg);
--
--#ifdef BLKGETSIZE64
-- case BLKGETSIZE64:
-- return put_user((u64)part_table[MINOR(inode->i_rdev)].nr_sects << 9,
-- (u64 *)arg);
--#endif
--
-- case BLKFLSBUF:
-- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-- fsync_dev(inode->i_rdev);
-- invalidate_buffers(inode->i_rdev);
-- if (nftl->mtd->sync)
-- nftl->mtd->sync(nftl->mtd);
-- return 0;
--
-- case BLKRRPART:
-- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-- if (nftl->usecount > 1) return -EBUSY;
-- /*
-- * We have to flush all buffers and invalidate caches,
-- * or we won't be able to re-use the partitions,
-- * if there was a change and we don't want to reboot
-- */
-- p = (1<<NFTL_PARTN_BITS) - 1;
-- while (p-- > 0) {
-- kdev_t devp = MKDEV(MAJOR(inode->i_dev), MINOR(inode->i_dev)+p);
-- if (part_table[p].nr_sects > 0)
-- invalidate_device (devp, 1);
--
-- part_table[MINOR(inode->i_dev)+p].start_sect = 0;
-- part_table[MINOR(inode->i_dev)+p].nr_sects = 0;
-- }
--
--#if LINUX_VERSION_CODE < 0x20328
-- resetup_one_dev(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS);
--#else
-- grok_partitions(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS,
-- 1<<NFTL_PARTN_BITS, nftl->nr_sects);
--#endif
-- return 0;
--
--#if (LINUX_VERSION_CODE < 0x20303)
-- RO_IOCTLS(inode->i_rdev, arg); /* ref. linux/blk.h */
--#else
-- case BLKROSET:
-- case BLKROGET:
-- case BLKSSZGET:
-- return blk_ioctl(inode->i_rdev, cmd, arg);
--#endif
--
-- default:
-- return -EINVAL;
-- }
--}
--
--void nftl_request(RQFUNC_ARG)
--{
-- unsigned int dev, block, nsect;
-- struct NFTLrecord *nftl;
-- char *buffer;
-- struct request *req;
-- int res;
--
-- while (1) {
-- INIT_REQUEST; /* blk.h */
-- req = CURRENT;
--
-- /* We can do this because the generic code knows not to
-- touch the request at the head of the queue */
-- spin_unlock_irq(&io_request_lock);
--
-- DEBUG(MTD_DEBUG_LEVEL2, "NFTL_request\n");
-- DEBUG(MTD_DEBUG_LEVEL3, "NFTL %s request, from sector 0x%04lx for 0x%04lx sectors\n",
-- (req->cmd == READ) ? "Read " : "Write",
-- req->sector, req->current_nr_sectors);
--
-- dev = MINOR(req->rq_dev);
-- block = req->sector;
-- nsect = req->current_nr_sectors;
-- buffer = req->buffer;
-- res = 1; /* succeed */
--
-- if (dev >= MAX_NFTLS * (1<<NFTL_PARTN_BITS)) {
-- /* there is no such partition */
-- printk("nftl: bad minor number: device = %s\n",
-- kdevname(req->rq_dev));
-- res = 0; /* fail */
-- goto repeat;
-- }
--
-- nftl = NFTLs[dev / (1<<NFTL_PARTN_BITS)];
-- DEBUG(MTD_DEBUG_LEVEL3, "Waiting for mutex\n");
-- down(&nftl->mutex);
-- DEBUG(MTD_DEBUG_LEVEL3, "Got mutex\n");
--
-- if (block + nsect > part_table[dev].nr_sects) {
-- /* access past the end of device */
-- printk("nftl%c%d: bad access: block = %d, count = %d\n",
-- (MINOR(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect);
-- up(&nftl->mutex);
-- res = 0; /* fail */
-- goto repeat;
-- }
--
-- block += part_table[dev].start_sect;
--
-- if (req->cmd == READ) {
-- DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request of 0x%x sectors @ %x "
-- "(req->nr_sectors == %lx)\n", nsect, block, req->nr_sectors);
--
-- for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
-- /* Read a single sector to req->buffer + (512 * i) */
-- if (NFTL_readblock(nftl, block, buffer)) {
-- DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request failed\n");
-- up(&nftl->mutex);
-- res = 0;
-- goto repeat;
-- }
-- }
--
-- DEBUG(MTD_DEBUG_LEVEL2,"NFTL read request completed OK\n");
-- up(&nftl->mutex);
-- goto repeat;
-- } else if (req->cmd == WRITE) {
-- DEBUG(MTD_DEBUG_LEVEL2, "NFTL write request of 0x%x sectors @ %x "
-- "(req->nr_sectors == %lx)\n", nsect, block,
-- req->nr_sectors);
--#ifdef CONFIG_NFTL_RW
-- for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
-- /* Read a single sector to req->buffer + (512 * i) */
-- if (NFTL_writeblock(nftl, block, buffer)) {
-- DEBUG(MTD_DEBUG_LEVEL1,"NFTL write request failed\n");
-- up(&nftl->mutex);
-- res = 0;
-- goto repeat;
-- }
-- }
-- DEBUG(MTD_DEBUG_LEVEL2,"NFTL write request completed OK\n");
--#else
-- res = 0; /* Writes always fail */
--#endif /* CONFIG_NFTL_RW */
-- up(&nftl->mutex);
-- goto repeat;
-- } else {
-- DEBUG(MTD_DEBUG_LEVEL0, "NFTL unknown request\n");
-- up(&nftl->mutex);
-- res = 0;
-- goto repeat;
-- }
-- repeat:
-- DEBUG(MTD_DEBUG_LEVEL3, "end_request(%d)\n", res);
-- spin_lock_irq(&io_request_lock);
-- end_request(res);
-- }
--}
--
--static int nftl_open(struct inode *ip, struct file *fp)
--{
-- int nftlnum = MINOR(ip->i_rdev) >> NFTL_PARTN_BITS;
-- struct NFTLrecord *thisNFTL;
-- thisNFTL = NFTLs[nftlnum];
--
-- DEBUG(MTD_DEBUG_LEVEL2,"NFTL_open\n");
--
--#ifdef CONFIG_KMOD
-- if (!thisNFTL && nftlnum == 0) {
-- request_module("docprobe");
-- thisNFTL = NFTLs[nftlnum];
-- }
--#endif
-- if (!thisNFTL) {
-- DEBUG(MTD_DEBUG_LEVEL2,"ENODEV: thisNFTL = %d, minor = %d, ip = %p, fp = %p\n",
-- nftlnum, ip->i_rdev, ip, fp);
-- return -ENODEV;
-- }
--
--#ifndef CONFIG_NFTL_RW
-- if (fp->f_mode & FMODE_WRITE)
-- return -EROFS;
--#endif /* !CONFIG_NFTL_RW */
--
-- thisNFTL->usecount++;
-- BLK_INC_USE_COUNT;
-- if (!get_mtd_device(thisNFTL->mtd, -1)) {
-- BLK_DEC_USE_COUNT;
-- return -ENXIO;
-- }
--
-- return 0;
--}
--
--static int nftl_release(struct inode *inode, struct file *fp)
-+static int nftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
- {
-- struct NFTLrecord *thisNFTL;
--
-- thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16];
--
-- DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n");
--
-- if (thisNFTL->mtd->sync)
-- thisNFTL->mtd->sync(thisNFTL->mtd);
-- thisNFTL->usecount--;
-- BLK_DEC_USE_COUNT;
-+ struct NFTLrecord *nftl = (void *)dev;
-
-- put_mtd_device(thisNFTL->mtd);
-+ geo->heads = nftl->heads;
-+ geo->sectors = nftl->sectors;
-+ geo->cylinders = nftl->cylinders;
-
- return 0;
- }
--#if LINUX_VERSION_CODE < 0x20326
--static struct file_operations nftl_fops = {
-- read: block_read,
-- write: block_write,
-- ioctl: nftl_ioctl,
-- open: nftl_open,
-- release: nftl_release,
-- fsync: block_fsync,
--};
--#else
--static struct block_device_operations nftl_fops =
--{
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
-- owner: THIS_MODULE,
--#endif
-- open: nftl_open,
-- release: nftl_release,
-- ioctl: nftl_ioctl
--};
--#endif
--
--
-
- /****************************************************************************
- *
-@@ -1048,49 +730,33 @@
- *
- ****************************************************************************/
-
--static struct mtd_notifier nftl_notifier = {
-- add: NFTL_notify_add,
-- remove: NFTL_notify_remove
-+
-+static struct mtd_blktrans_ops nftl_tr = {
-+ .name = "nftl",
-+ .major = NFTL_MAJOR,
-+ .part_bits = NFTL_PARTN_BITS,
-+ .getgeo = nftl_getgeo,
-+ .readsect = nftl_readblock,
-+#ifdef CONFIG_NFTL_RW
-+ .writesect = nftl_writeblock,
-+#endif
-+ .add_mtd = nftl_add_mtd,
-+ .remove_dev = nftl_remove_dev,
-+ .owner = THIS_MODULE,
- };
-
- extern char nftlmountrev[];
-
--int __init init_nftl(void)
-+static int __init init_nftl(void)
- {
-- int i;
--
--#ifdef PRERELEASE
-- printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.87 $, nftlmount.c %s\n", nftlmountrev);
--#endif
--
-- if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){
-- printk("unable to register NFTL block device on major %d\n", MAJOR_NR);
-- return -EBUSY;
-- } else {
-- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &nftl_request);
--
-- /* set block size to 1kB each */
-- for (i = 0; i < 256; i++) {
-- nftl_blocksizes[i] = 1024;
-- }
-- blksize_size[MAJOR_NR] = nftl_blocksizes;
--
-- add_gendisk(&nftl_gendisk);
-- }
--
-- register_mtd_user(&nftl_notifier);
-+ printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.97 $, nftlmount.c %s\n", nftlmountrev);
-
-- return 0;
-+ return register_mtd_blktrans(&nftl_tr);
- }
-
- static void __exit cleanup_nftl(void)
- {
-- unregister_mtd_user(&nftl_notifier);
-- unregister_blkdev(MAJOR_NR, "nftl");
--
-- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
--
-- del_gendisk(&nftl_gendisk);
-+ deregister_mtd_blktrans(&nftl_tr);
- }
-
- module_init(init_nftl);
---- linux-2.4.21/drivers/mtd/nftlmount.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/nftlmount.c
-@@ -4,7 +4,7 @@
- * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
- * Copyright (C) 2000 Netgem S.A.
- *
-- * $Id: nftlmount.c,v 1.31 2002/11/15 16:34:43 dwmw2 Exp $
-+ * $Id: nftlmount.c,v 1.40 2004/11/22 14:38:29 kalev Exp $
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
-@@ -21,26 +21,17 @@
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
--#define __NO_VERSION__
- #include <linux/kernel.h>
--#include <linux/module.h>
- #include <asm/errno.h>
--#include <asm/io.h>
--#include <asm/uaccess.h>
--#include <linux/miscdevice.h>
--#include <linux/pci.h>
- #include <linux/delay.h>
- #include <linux/slab.h>
--#include <linux/sched.h>
--#include <linux/init.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
- #include <linux/mtd/nftl.h>
--#include <linux/mtd/compatmac.h>
-
- #define SECTORSIZE 512
-
--char nftlmountrev[]="$Revision: 1.31 $";
-+char nftlmountrev[]="$Revision: 1.40 $";
-
- /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
- * various device information of the NFTL partition and Bad Unit Table. Update
-@@ -50,7 +41,6 @@
- static int find_boot_record(struct NFTLrecord *nftl)
- {
- struct nftl_uci1 h1;
-- struct nftl_oob oob;
- unsigned int block, boot_record_count = 0;
- size_t retlen;
- u8 buf[SECTORSIZE];
-@@ -59,8 +49,12 @@
-
- /* Assume logical EraseSize == physical erasesize for starting the scan.
- We'll sort it out later if we find a MediaHeader which says otherwise */
-- nftl->EraseSize = nftl->mtd->erasesize;
-- nftl->nb_blocks = nftl->mtd->size / nftl->EraseSize;
-+ /* Actually, we won't. The new DiskOnChip driver has already scanned
-+ the MediaHeader and adjusted the virtual erasesize it presents in
-+ the mtd device accordingly. We could even get rid of
-+ nftl->EraseSize if there were any point in doing so. */
-+ nftl->EraseSize = nftl->mbd.mtd->erasesize;
-+ nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize;
-
- nftl->MediaUnit = BLOCK_NIL;
- nftl->SpareMediaUnit = BLOCK_NIL;
-@@ -71,12 +65,15 @@
-
- /* Check for ANAND header first. Then can whinge if it's found but later
- checks fail */
-- if ((ret = MTD_READ(nftl->mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf))) {
-+ ret = MTD_READ(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf);
-+ /* We ignore ret in case the ECC of the MediaHeader is invalid
-+ (which is apparently acceptable) */
-+ if (retlen != SECTORSIZE) {
- static int warncount = 5;
-
- if (warncount) {
- printk(KERN_WARNING "Block read at 0x%x of mtd%d failed: %d\n",
-- block * nftl->EraseSize, nftl->mtd->index, ret);
-+ block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
- if (!--warncount)
- printk(KERN_WARNING "Further failures for this block will not be printed\n");
- }
-@@ -87,16 +84,16 @@
- /* ANAND\0 not found. Continue */
- #if 0
- printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n",
-- block * nftl->EraseSize, nftl->mtd->index);
-+ block * nftl->EraseSize, nftl->mbd.mtd->index);
- #endif
- continue;
- }
-
- /* To be safer with BIOS, also use erase mark as discriminant */
-- if ((ret = MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8,
-- 8, &retlen, (char *)&h1)) < 0) {
-+ if ((ret = MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8,
-+ 8, &retlen, (char *)&h1) < 0)) {
- printk(KERN_WARNING "ANAND header found at 0x%x in mtd%d, but OOB data read failed (err %d)\n",
-- block * nftl->EraseSize, nftl->mtd->index, ret);
-+ block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
- continue;
- }
-
-@@ -106,23 +103,23 @@
- */
- if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) {
- printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n",
-- block * nftl->EraseSize, nftl->mtd->index,
-+ block * nftl->EraseSize, nftl->mbd.mtd->index,
- le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1));
- continue;
- }
-
- /* Finally reread to check ECC */
-- if ((ret = MTD_READECC(nftl->mtd, block * nftl->EraseSize, SECTORSIZE,
-- &retlen, buf, (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) {
-+ if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE,
-+ &retlen, buf, (char *)&oob, NULL) < 0)) {
- printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n",
-- block * nftl->EraseSize, nftl->mtd->index, ret);
-+ block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
- continue;
- }
-
- /* Paranoia. Check the ANAND header is still there after the ECC read */
- if (memcmp(buf, "ANAND", 6)) {
- printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but went away on reread!\n",
-- block * nftl->EraseSize, nftl->mtd->index);
-+ block * nftl->EraseSize, nftl->mbd.mtd->index);
- printk(KERN_NOTICE "New data are: %02x %02x %02x %02x %02x %02x\n",
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
- continue;
-@@ -137,8 +134,12 @@
- printk(KERN_NOTICE "NFTL Media Headers at 0x%x and 0x%x disagree.\n",
- nftl->MediaUnit * nftl->EraseSize, block * nftl->EraseSize);
- /* if (debug) Print both side by side */
-+ if (boot_record_count < 2) {
-+ /* We haven't yet seen two real ones */
- return -1;
- }
-+ continue;
-+ }
- if (boot_record_count == 1)
- nftl->SpareMediaUnit = block;
-
-@@ -154,6 +155,10 @@
- memcpy(mh, buf, sizeof(struct NFTLMediaHeader));
-
- /* Do some sanity checks on it */
-+#if 0
-+The new DiskOnChip driver scans the MediaHeader itself, and presents a virtual
-+erasesize based on UnitSizeFactor. So the erasesize we read from the mtd
-+device is already correct.
- if (mh->UnitSizeFactor == 0) {
- printk(KERN_NOTICE "NFTL: UnitSizeFactor 0x00 detected. This violates the spec but we think we know what it means...\n");
- } else if (mh->UnitSizeFactor < 0xfc) {
-@@ -163,9 +168,10 @@
- } else if (mh->UnitSizeFactor != 0xff) {
- printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n",
- mh->UnitSizeFactor);
-- nftl->EraseSize = nftl->mtd->erasesize << (0xff - mh->UnitSizeFactor);
-- nftl->nb_blocks = nftl->mtd->size / nftl->EraseSize;
-+ nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor);
-+ nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize;
- }
-+#endif
- nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
- if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
- printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
-@@ -182,7 +188,7 @@
- return -1;
- }
-
-- nftl->nr_sects = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
-+ nftl->mbd.size = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
-
- /* If we're not using the last sectors in the device for some reason,
- reduce nb_blocks accordingly so we forget they're there */
-@@ -218,11 +224,13 @@
-
- /* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */
- for (i = 0; i < nftl->nb_blocks; i++) {
-+#if 0
-+The new DiskOnChip driver already scanned the bad block table. Just query it.
- if ((i & (SECTORSIZE - 1)) == 0) {
- /* read one sector for every SECTORSIZE of blocks */
-- if ((ret = MTD_READECC(nftl->mtd, block * nftl->EraseSize +
-+ if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize +
- i + SECTORSIZE, SECTORSIZE, &retlen, buf,
-- (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) {
-+ (char *)&oob, NULL)) < 0) {
- printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n",
- ret);
- kfree(nftl->ReplUnitTable);
-@@ -233,6 +241,9 @@
- /* mark the Bad Erase Unit as RESERVED in ReplUnitTable */
- if (buf[i & (SECTORSIZE - 1)] != 0xff)
- nftl->ReplUnitTable[i] = BLOCK_RESERVED;
-+#endif
-+ if (nftl->mbd.mtd->block_isbad(nftl->mbd.mtd, i * nftl->EraseSize))
-+ nftl->ReplUnitTable[i] = BLOCK_RESERVED;
- }
-
- nftl->MediaUnit = block;
-@@ -257,22 +268,18 @@
- static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len,
- int check_oob)
- {
-- int i, retlen;
-- u8 buf[SECTORSIZE];
-+ int i;
-+ size_t retlen;
-+ u8 buf[SECTORSIZE + nftl->mbd.mtd->oobsize];
-
- for (i = 0; i < len; i += SECTORSIZE) {
-- /* we want to read the sector without ECC check here since a free
-- sector does not have ECC syndrome on it yet */
-- if (MTD_READ(nftl->mtd, address, SECTORSIZE, &retlen, buf) < 0)
-+ if (MTD_READECC(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &nftl->oobinfo) < 0)
- return -1;
- if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
- return -1;
-
- if (check_oob) {
-- if (MTD_READOOB(nftl->mtd, address, nftl->mtd->oobsize,
-- &retlen, buf) < 0)
-- return -1;
-- if (memcmpb(buf, 0xff, nftl->mtd->oobsize) != 0)
-+ if (memcmpb(buf + SECTORSIZE, 0xff, nftl->mbd.mtd->oobsize) != 0)
- return -1;
- }
- address += SECTORSIZE;
-@@ -287,7 +294,6 @@
- * Return: 0 when succeed, -1 on error.
- *
- * ToDo: 1. Is it neceressary to check_free_sector after erasing ??
-- * 2. UnitSizeFactor != 0xFF
- */
- int NFTL_formatblock(struct NFTLrecord *nftl, int block)
- {
-@@ -297,7 +303,7 @@
- struct erase_info *instr = &nftl->instr;
-
- /* Read the Unit Control Information #1 for Wear-Leveling */
-- if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8,
-+ if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8,
- 8, &retlen, (char *)&uci) < 0)
- goto default_uci1;
-
-@@ -312,16 +318,16 @@
- memset(instr, 0, sizeof(struct erase_info));
-
- /* XXX: use async erase interface, XXX: test return code */
-+ instr->mtd = nftl->mbd.mtd;
- instr->addr = block * nftl->EraseSize;
- instr->len = nftl->EraseSize;
-- MTD_ERASE(nftl->mtd, instr);
-+ MTD_ERASE(nftl->mbd.mtd, instr);
-
- if (instr->state == MTD_ERASE_FAILED) {
-- /* could not format, FixMe: We should update the BadUnitTable
-- both in memory and on disk */
- printk("Error while formatting block %d\n", block);
-- return -1;
-- } else {
-+ goto fail;
-+ }
-+
- /* increase and write Wear-Leveling info */
- nb_erases = le32_to_cpu(uci.WearInfo);
- nb_erases++;
-@@ -334,14 +340,18 @@
- * FixMe: is this check really necessary ? since we have check the
- * return code after the erase operation. */
- if (check_free_sectors(nftl, instr->addr, nftl->EraseSize, 1) != 0)
-- return -1;
-+ goto fail;
-
- uci.WearInfo = le32_to_cpu(nb_erases);
-- if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
-+ if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
- &retlen, (char *)&uci) < 0)
-- return -1;
-+ goto fail;
- return 0;
-- }
-+fail:
-+ /* could not format, update the bad block table (caller is responsible
-+ for setting the ReplUnitTable to BLOCK_RESERVED on failure) */
-+ nftl->mbd.mtd->block_markbad(nftl->mbd.mtd, instr->addr);
-+ return -1;
- }
-
- /* check_sectors_in_chain: Check that each sector of a Virtual Unit Chain is correct.
-@@ -357,13 +367,14 @@
- {
- unsigned int block, i, status;
- struct nftl_bci bci;
-- int sectors_per_block, retlen;
-+ int sectors_per_block;
-+ size_t retlen;
-
- sectors_per_block = nftl->EraseSize / SECTORSIZE;
- block = first_block;
- for (;;) {
- for (i = 0; i < sectors_per_block; i++) {
-- if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i * SECTORSIZE,
-+ if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + i * SECTORSIZE,
- 8, &retlen, (char *)&bci) < 0)
- status = SECTOR_IGNORE;
- else
-@@ -383,7 +394,7 @@
- /* sector not free actually : mark it as SECTOR_IGNORE */
- bci.Status = SECTOR_IGNORE;
- bci.Status1 = SECTOR_IGNORE;
-- MTD_WRITEOOB(nftl->mtd,
-+ MTD_WRITEOOB(nftl->mbd.mtd,
- block * nftl->EraseSize + i * SECTORSIZE,
- 8, &retlen, (char *)&bci);
- }
-@@ -446,8 +457,7 @@
-
- printk("Formatting block %d\n", block);
- if (NFTL_formatblock(nftl, block) < 0) {
-- /* cannot format !!!! Mark it as Bad Unit,
-- FixMe: update the BadUnitTable on disk */
-+ /* cannot format !!!! Mark it as Bad Unit */
- nftl->ReplUnitTable[block] = BLOCK_RESERVED;
- } else {
- nftl->ReplUnitTable[block] = BLOCK_FREE;
-@@ -476,7 +486,7 @@
- size_t retlen;
-
- /* check erase mark. */
-- if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
-+ if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
- &retlen, (char *)&h1) < 0)
- return -1;
-
-@@ -491,7 +501,7 @@
- h1.EraseMark = cpu_to_le16(ERASE_MARK);
- h1.EraseMark1 = cpu_to_le16(ERASE_MARK);
- h1.WearInfo = cpu_to_le32(0);
-- if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
-+ if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
- &retlen, (char *)&h1) < 0)
- return -1;
- } else {
-@@ -503,7 +513,7 @@
- SECTORSIZE, 0) != 0)
- return -1;
-
-- if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i,
-+ if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + i,
- 16, &retlen, buf) < 0)
- return -1;
- if (i == SECTORSIZE) {
-@@ -533,7 +543,7 @@
- struct nftl_uci2 uci;
- size_t retlen;
-
-- if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
-+ if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
- 8, &retlen, (char *)&uci) < 0)
- return 0;
-
-@@ -572,9 +582,9 @@
-
- for (;;) {
- /* read the block header. If error, we format the chain */
-- if (MTD_READOOB(s->mtd, block * s->EraseSize + 8, 8,
-+ if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8,
- &retlen, (char *)&h0) < 0 ||
-- MTD_READOOB(s->mtd, block * s->EraseSize + SECTORSIZE + 8, 8,
-+ MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8,
- &retlen, (char *)&h1) < 0) {
- s->ReplUnitTable[block] = BLOCK_NIL;
- do_format_chain = 1;
---- linux-2.4.21/drivers/mtd/redboot.c~mtd-cvs
-+++ linux-2.4.21/drivers/mtd/redboot.c
-@@ -1,5 +1,5 @@
- /*
-- * $Id: redboot.c,v 1.6 2001/10/25 09:16:06 dwmw2 Exp $
-+ * $Id: redboot.c,v 1.17 2004/11/22 11:33:56 ijc Exp $
- *
- * Parse RedBoot-style Flash Image System (FIS) tables and
- * produce a Linux partition array to match.
-@@ -7,6 +7,8 @@
-
- #include <linux/kernel.h>
- #include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/vmalloc.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
-@@ -28,13 +30,18 @@
- struct fis_list *next;
- };
-
-+static int directory = CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK;
-+module_param(directory, int, 0);
-+
- static inline int redboot_checksum(struct fis_image_desc *img)
- {
- /* RedBoot doesn't actually write the desc_cksum field yet AFAICT */
- return 1;
- }
-
--int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts)
-+static int parse_redboot_partitions(struct mtd_info *master,
-+ struct mtd_partition **pparts,
-+ unsigned long fis_origin)
- {
- int nrparts = 0;
- struct fis_image_desc *buf;
-@@ -43,31 +50,49 @@
- int ret, i;
- size_t retlen;
- char *names;
-+ char *nullname;
- int namelen = 0;
-+ int nulllen = 0;
-+ int numslots;
-+ unsigned long offset;
-+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
-+ static char nullstring[] = "unallocated";
-+#endif
-
-- buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-+ buf = vmalloc(master->erasesize);
-
- if (!buf)
- return -ENOMEM;
-
-- /* Read the start of the last erase block */
-- ret = master->read(master, master->size - master->erasesize,
-- PAGE_SIZE, &retlen, (void *)buf);
-+ if ( directory < 0 )
-+ offset = master->size + directory*master->erasesize;
-+ else
-+ offset = directory*master->erasesize;
-+
-+ printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
-+ master->name, offset);
-+
-+ ret = master->read(master, offset,
-+ master->erasesize, &retlen, (void *)buf);
-
- if (ret)
- goto out;
-
-- if (retlen != PAGE_SIZE) {
-+ if (retlen != master->erasesize) {
- ret = -EIO;
- goto out;
- }
-
-- /* RedBoot image could appear in any of the first three slots */
-- for (i = 0; i < 3; i++) {
-- if (!memcmp(buf[i].name, "RedBoot", 8))
-+ numslots = (master->erasesize / sizeof(struct fis_image_desc));
-+ for (i = 0; i < numslots; i++) {
-+ if (buf[i].name[0] == 0xff) {
-+ i = numslots;
- break;
- }
-- if (i == 3) {
-+ if (!memcmp(buf[i].name, "FIS directory", 14))
-+ break;
-+ }
-+ if (i == numslots) {
- /* Didn't find it */
- printk(KERN_NOTICE "No RedBoot partition table detected in %s\n",
- master->name);
-@@ -75,7 +100,7 @@
- goto out;
- }
-
-- for (i = 0; i < PAGE_SIZE / sizeof(struct fis_image_desc); i++) {
-+ for (i = 0; i < numslots; i++) {
- struct fis_list *new_fl, **prev;
-
- if (buf[i].name[0] == 0xff)
-@@ -90,7 +115,11 @@
- goto out;
- }
- new_fl->img = &buf[i];
-+ if (fis_origin) {
-+ buf[i].flash_base -= fis_origin;
-+ } else {
- buf[i].flash_base &= master->size-1;
-+ }
-
- /* I'm sure the JFFS2 code has done me permanent damage.
- * I now think the following is _normal_
-@@ -103,42 +132,69 @@
-
- nrparts++;
- }
-- if (fl->img->flash_base)
-+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
-+ if (fl->img->flash_base) {
- nrparts++;
-+ nulllen = sizeof(nullstring);
-+ }
-
- for (tmp_fl = fl; tmp_fl->next; tmp_fl = tmp_fl->next) {
-- if (tmp_fl->img->flash_base + tmp_fl->img->size + master->erasesize < tmp_fl->next->img->flash_base)
-+ if (tmp_fl->img->flash_base + tmp_fl->img->size + master->erasesize <= tmp_fl->next->img->flash_base) {
- nrparts++;
-+ nulllen = sizeof(nullstring);
- }
-- parts = kmalloc(sizeof(*parts)*nrparts + namelen, GFP_KERNEL);
-+ }
-+#endif
-+ parts = kmalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL);
-
- if (!parts) {
- ret = -ENOMEM;
- goto out;
- }
-- names = (char *)&parts[nrparts];
-- memset(parts, 0, sizeof(*parts)*nrparts + namelen);
-+
-+ memset(parts, 0, sizeof(*parts)*nrparts + nulllen + namelen);
-+
-+ nullname = (char *)&parts[nrparts];
-+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
-+ if (nulllen > 0) {
-+ strcpy(nullname, nullstring);
-+ }
-+#endif
-+ names = nullname + nulllen;
-+
- i=0;
-
-+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
- if (fl->img->flash_base) {
-- parts[0].name = "unallocated space";
-+ parts[0].name = nullname;
- parts[0].size = fl->img->flash_base;
- parts[0].offset = 0;
-+ i++;
- }
-+#endif
- for ( ; i<nrparts; i++) {
- parts[i].size = fl->img->size;
- parts[i].offset = fl->img->flash_base;
- parts[i].name = names;
-
- strcpy(names, fl->img->name);
-+#ifdef CONFIG_MTD_REDBOOT_PARTS_READONLY
-+ if (!memcmp(names, "RedBoot", 8) ||
-+ !memcmp(names, "RedBoot config", 15) ||
-+ !memcmp(names, "FIS directory", 14)) {
-+ parts[i].mask_flags = MTD_WRITEABLE;
-+ }
-+#endif
- names += strlen(names)+1;
-
-- if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize < fl->next->img->flash_base) {
-+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
-+ if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
- i++;
- parts[i].offset = parts[i-1].size + parts[i-1].offset;
- parts[i].size = fl->next->img->flash_base - parts[i].offset;
-- parts[i].name = "unallocated space";
-+ parts[i].name = nullname;
- }
-+#endif
- tmp_fl = fl;
- fl = fl->next;
- kfree(tmp_fl);
-@@ -151,11 +207,28 @@
- fl = fl->next;
- kfree(old);
- }
-- kfree(buf);
-+ vfree(buf);
- return ret;
- }
-
--EXPORT_SYMBOL(parse_redboot_partitions);
-+static struct mtd_part_parser redboot_parser = {
-+ .owner = THIS_MODULE,
-+ .parse_fn = parse_redboot_partitions,
-+ .name = "RedBoot",
-+};
-+
-+static int __init redboot_parser_init(void)
-+{
-+ return register_mtd_parser(&redboot_parser);
-+}
-+
-+static void __exit redboot_parser_exit(void)
-+{
-+ deregister_mtd_parser(&redboot_parser);
-+}
-+
-+module_init(redboot_parser_init);
-+module_exit(redboot_parser_exit);
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>");
---- /dev/null
-+++ linux-2.4.21/drivers/mtd/ssfdc.c
-@@ -0,0 +1,1132 @@
-+/*
-+ * drivers/mtd/ssfdc.c
-+ *
-+ * Copyright (C) 2003 Simon Haynes (simon@baydel.con)
-+ * Baydel Ltd
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public License
-+ * version 2.1 as published by the Free Software Foundation.
-+ *
-+ * This module provides a translation layer, via mtd, for smart
-+ * media card access. It essentially enables the possibility
-+ * of using cards on a hardware which does not have a hardware translation
-+ * layer and interchanging them with hardware that does ie: PC card readers
-+ *
-+ * I had to write this module for a specific task and in a short timeframe
-+ * for this reason I have imposed some restricions to make the job easier.
-+ *
-+ * To build an compile the driver I added the following lines
-+ * to mtd/Config.in
-+ *
-+ * dep_tristate ' SSFDC support' CONFIG_SSFDC $CONFIG_MTD
-+ *
-+ * to /mtd/Makefile
-+ *
-+ * obj-$(CONFIG_SSFDC) += ssfdc.o
-+ *
-+ * and compiled the kernel via the usual methods.
-+ *
-+ * I am sure that there are many problems I don't know about but here are
-+ * some that I know of
-+ *
-+ * Currently the driver uses MAJOR number 44 which I think is FTL or NFTL
-+ * I did this because I wanted a static number and I didn't know
-+ * how to go about getting a new one. This needs addressing
-+ * The dev nodes required are like standard. I only use minor 0
-+ * (/dev/ssfdca), and minor 1 (/dev/ssfdca1).
-+ * You should be able to run fdisk on /dev/ssfdca and the first partition
-+ * is /dev/ssfdca1. There is no working code in the module for changing the
-+ * SMC and rebuilding the maps so the card should not be changed once the
-+ * module is loaded. At present I only look for 1 partition. But this is a
-+ * small commented hack.
-+ *
-+ * There is no support cards which do not have a 512 byte page size with 16
-+ * bytes of oob and an erase size of 16K.
-+ * There are no checks for this at present. In addition the MTD reported size
-+ * must be 16M or a multiple.
-+ *
-+ * Code to handle multiple partitions or multiple cards is incomplete
-+ * Need to allocate data buffer and oob buffer on a per partition basis.
-+ * As I am only concerned with one partition I will do this if I ever need to.
-+ * The cached physical address variable also needs this attention.
-+ *
-+ * Recently I have started to work on media changes. Some of this is specific
-+ * to my hardware and you will see references to pt_ssfdc_smc and smc_status.
-+ * This code is incomplete and does not work. I have commented it for the moment
-+ * but it should give an indication of what I think is required. Maybe there is
-+ * something it mtd that can help
-+ *
-+ * 17th August 2004 MHB
-+ *
-+ * Following updating CVS I noticed some single bit data corruption. I believe
-+ * that this was down to the fact that I was using mtd->read instead of mtd->read_ecc
-+ * and that mtd->read was applying it's own error corretion from the wrong ecc bytes
-+ * I have now corrected this.
-+ *
-+ * During this time I noticed that while in allocate new I only seem to look for blocks
-+ * in 1 zone. So this limits the partition size to 16MB with all the other SMC size
-+ * restrictions
-+
-+
-+*/
-+
-+#include <linux/config.h>
-+#include <linux/types.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/fs.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/vmalloc.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/blktrans.h>
-+#include <linux/mtd/nand_ecc.h>
-+#include <linux/sched.h>
-+#include <linux/ptrace.h>
-+#include <linux/string.h>
-+#include <linux/timer.h>
-+#include <linux/major.h>
-+#include <linux/ioctl.h>
-+#include <linux/hdreg.h>
-+#include <linux/list.h>
-+#include <asm/semaphore.h>
-+#include <asm/uaccess.h>
-+
-+
-+#if (LINUX_VERSION_CODE >= 0x20100)
-+#include <linux/vmalloc.h>
-+#endif
-+#if (LINUX_VERSION_CODE >= 0x20303)
-+#include <linux/blkpg.h>
-+#endif
-+
-+#include <asm/semaphore.h>
-+
-+#define SSFDC_FORMAT 1
-+
-+#define PDEBUG(fmt, args...)
-+
-+#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
-+#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
-+
-+#if (LINUX_VERSION_CODE < 0x20320)
-+#define BLK_DEFAULT_QUEUE(n) blk_dev[n].request_fn
-+#define blk_init_queue(q, req) q = (req)
-+#define blk_cleanup_queue(q) q = NULL
-+#define request_arg_t void
-+#else
-+#define request_arg_t request_queue_t *q
-+#endif
-+
-+#define TRUE 1
-+#define FALSE 0
-+
-+#define SSFDC_MAJOR 44
-+
-+#define MAJOR_NR SSFDC_MAJOR
-+#define DEVICE_NAME "ssfdc"
-+#define DEVICE_REQUEST do_ssfdc_request
-+#define DEVICE_ON(device)
-+#define DEVICE_OFF(device)
-+
-+#include <linux/blk.h>
-+
-+#include "/home/simon/ebony/dbwhatu/dbwhatu/smccontrol.h"
-+
-+
-+
-+#define ZONE_SIZE (16 * 1024 * 1024)
-+#define SMC_BLOCK_SIZE (16 * 1024)
-+#define SECTOR_SIZE 512
-+#define SECTORS_PER_ZONE (ZONE_SIZE / SECTOR_SIZE)
-+#define BLOCKS_PER_ZONE (ZONE_SIZE / SMC_BLOCK_SIZE)
-+#define SECTORS_PER_BLOCK (SMC_BLOCK_SIZE / SECTOR_SIZE)
-+#define OOB_SIZE 16
-+
-+
-+#define MAX_DEVICES 4
-+#define MAX_PARTITIONS 8
-+#define PARTITION_BITS 3
-+#define MAX_ZONES 8
-+
-+
-+int ssfdc_major = SSFDC_MAJOR;
-+unsigned int ssfdc_cached = 0xFFFFFFFF;
-+static unsigned char ssfdc_scratch[16384];
-+static unsigned char ssfdc_buffer[16];
-+static unsigned char ssfdc_ffoob_buf[OOB_SIZE * SECTORS_PER_BLOCK];
-+static unsigned char ssfdc_oob_buf[OOB_SIZE * SECTORS_PER_BLOCK];
-+
-+
-+static struct nand_oobinfo ssfdc_ffoob_info = {
-+ .useecc = 0,
-+};
-+
-+
-+typedef struct minor_t {
-+ atomic_t open;
-+ int cached;
-+ unsigned char * pt_data;
-+ unsigned char * pt_oob;
-+} minor_t;
-+
-+
-+
-+typedef struct partition_t {
-+ int type;
-+ struct mtd_info *mtd;
-+ int count;
-+ unsigned int *zone;
-+ unsigned int zoneCount;
-+ minor_t minor[MAX_PARTITIONS];
-+ unsigned int last_written[MAX_ZONES];
-+} partition_t;
-+
-+partition_t SMCParts[MAX_DEVICES];
-+
-+
-+static unsigned char ssfdc_ecc[] = {14, 13, 15, 9, 8, 10};
-+
-+static struct hd_struct ssfdc_hd[MAX_DEVICES * MAX_PARTITIONS];
-+static int ssfdc_sizes[MAX_DEVICES * MAX_PARTITIONS];
-+static int ssfdc_blocksizes[MAX_DEVICES * MAX_PARTITIONS];
-+smc_control * pt_ssfdc_smc;
-+
-+
-+static struct gendisk ssfdc_gendisk = {
-+ major: SSFDC_MAJOR,
-+ major_name: "ssfdc",
-+ minor_shift: PARTITION_BITS,
-+ max_p: MAX_PARTITIONS,
-+ part: ssfdc_hd,
-+ sizes: ssfdc_sizes,
-+};
-+
-+
-+static int ssfdc_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg);
-+static int ssfdc_open(struct inode *inode, struct file *file);
-+static int ssfdc_close(struct inode *inode, struct file *file);
-+static int ssfdc_write(partition_t *part, caddr_t buffer, u_long sector, u_long nblocks);
-+static int ssfdc_read(partition_t *part, caddr_t buffer, u_long sector, u_long nblocks);
-+static int ssfdc_physical(partition_t * pt_smcpart, int zone, int block);
-+static int ssfdc_erase(partition_t *pt_smcpart, unsigned int offset);
-+static int ssfdc_read_partitions(partition_t * pt_smcpart);
-+static void ssfdc_notify_add(struct mtd_info *mtd);
-+static void ssfdc_notify_remove(struct mtd_info *mtd);
-+static void ssfdc_tables(partition_t * pt_smcpart);
-+static int ssfdc_sector_blank(partition_t * pt_smcpart, int sc);
-+static int ssfdc_allocate_new(partition_t * pt_smcpart, int zone);
-+int ssfdc_parity(int number);
-+static void ssfdc_erase_callback(struct erase_info *erase);
-+
-+
-+
-+static DECLARE_WAIT_QUEUE_HEAD(ssfdc_wq);
-+
-+
-+static struct mtd_notifier ssfdc_notifier = {
-+ add: ssfdc_notify_add,
-+ remove: ssfdc_notify_remove,
-+};
-+
-+
-+
-+static struct block_device_operations ssfdc_fops = {
-+ open: ssfdc_open,
-+ release: ssfdc_close,
-+ ioctl: ssfdc_ioctl,
-+};
-+
-+static struct semaphore ssfdc_semaphore;
-+
-+static void ssfdc_notify_add(struct mtd_info *mtd) {
-+
-+
-+
-+
-+ if(mtd->index >= 1) return; // Hack to limit SSFDC to 1 partition
-+
-+ if( ((mtd->size % ZONE_SIZE) != 0) && (mtd->size < (ZONE_SIZE * MAX_ZONES)) ){
-+ PDEBUG("ssfdc_notify_add : mtd partition %d is not modulus 16M, not SSFDC\n", mtd->index);
-+ }
-+ else {
-+ memset((void *)&SMCParts[mtd->index].type, 0, sizeof(partition_t));
-+ SMCParts[mtd->index].mtd = mtd;
-+ SMCParts[mtd->index].count = mtd->index;
-+ SMCParts[mtd->index].type = 1;
-+ SMCParts[mtd->index].zoneCount = mtd->size / ZONE_SIZE;
-+ SMCParts[mtd->index].zone = kmalloc(SMCParts[mtd->index].zoneCount * 8192, GFP_KERNEL);
-+
-+
-+ if(!SMCParts[mtd->index].zone) {
-+ printk(KERN_NOTICE "ssfdc_notify_add : mtd partition %d, failed to allocate mapping table\n", mtd->index);
-+ SMCParts[mtd->index].type = 0;
-+ }
-+ else {
-+ memset((void *)SMCParts[mtd->index].zone, 0xFF, SMCParts[mtd->index].zoneCount * 8192);
-+ }
-+
-+ ssfdc_read_partitions((partition_t *)&SMCParts[mtd->index].type);
-+ }
-+ return;
-+
-+}
-+static int ssfdc_read_partitions(partition_t * pt_smcpart) {
-+
-+ int whole, i, j, size;
-+
-+//=printk("ssfdc_read_partitions : start\n");
-+
-+ for(i=0; i<MAX_PARTITIONS; i++)
-+ if ((atomic_read(&pt_smcpart->minor[i].open) > 1)) {
-+//=printk("ssfdc_read_partitions : part %d busy\n", i);
-+
-+ return -EBUSY;
-+ }
-+
-+
-+//=printk("ssfdc_read_partitions : tables start\n");
-+ ssfdc_tables(pt_smcpart);
-+//=printk("ssfdc_read_partitions : tables end\n");
-+
-+ whole = pt_smcpart->count << PARTITION_BITS;
-+
-+
-+ j = MAX_PARTITIONS - 1;
-+ while (j-- > 0) {
-+ if (ssfdc_hd[whole+j].nr_sects > 0) {
-+ kdev_t rdev = MKDEV(SSFDC_MAJOR, whole+j);
-+ invalidate_device(rdev, 1);
-+ }
-+ ssfdc_hd[whole+j].start_sect = 0;
-+ ssfdc_hd[whole+j].nr_sects = 0;
-+ }
-+
-+
-+ size = (((pt_smcpart->mtd->size / 16384) * 1000) / 1024) * 32;
-+ size /= (0x8 * 0x20);
-+ size = size * (0x8 * 0x20);
-+
-+//=printk("ssfdc_read_partitions : register start\n");
-+
-+ register_disk(&ssfdc_gendisk, whole >> PARTITION_BITS, MAX_PARTITIONS,
-+ &ssfdc_fops, size);
-+
-+//=printk("ssfdc_read_partitions : register end\n");
-+
-+
-+ return 0;
-+}
-+
-+
-+static void ssfdc_notify_remove(struct mtd_info *mtd) {
-+int i, j, whole;
-+
-+ i=mtd->index;
-+ whole = i << PARTITION_BITS;
-+ if(SMCParts[i].mtd == mtd) {
-+ if(SMCParts[i].zone)kfree(SMCParts[i].zone);
-+ memset((void *)&SMCParts[i].type, 0, sizeof(partition_t));
-+ for (j = 0; j < MAX_PARTITIONS; j++) {
-+ if (ssfdc_hd[whole+j].nr_sects > 0) {
-+ ssfdc_hd[whole+j].start_sect = 0;
-+ ssfdc_hd[whole+j].nr_sects=0;
-+ }
-+ }
-+ return;
-+ }
-+ return;
-+}
-+
-+
-+
-+static int ssfdc_ioctl(struct inode *inode, struct file *file,
-+ u_int cmd, u_long arg) {
-+
-+ int minor = MINOR(inode->i_rdev);
-+ int ret = -EINVAL;
-+ partition_t * pt_smcpart = (partition_t *)&SMCParts[(minor & ~(MAX_PARTITIONS -1)) >> PARTITION_BITS].type;
-+ struct hd_geometry geo;
-+ int size;
-+/*
-+ unsigned char smc_status;
-+
-+ smc_status = in_8((void *)&pt_ssfdc_smc->smc_status);
-+ if(!(smc_status & SMC_PRESENT)) {
-+ printk("ssfdc : media not present\n");
-+ ret = 1;
-+ goto ssfdc_ioctl_error;
-+ }
-+
-+ if(smc_status & SMC_CHANGED) {
-+ out_8((void *)&pt_ssfdc_smc->smc_status, smc_status);
-+ if(minor & ((1<< PARTITION_BITS) - 1)) return -ENOTTY;
-+ ssfdc_read_partitions(pt_smcpart);
-+ printk("ssfdc : media change\n");
-+ }
-+*/
-+ switch(cmd) {
-+
-+ case HDIO_GETGEO:
-+ memset(&geo, 0, sizeof(geo));
-+ size = (((pt_smcpart->mtd->size / 16384) * 1000) / 1024) * 32;
-+ size /= (0x8 * 0x20);
-+ geo.heads = 0x8;
-+ geo.sectors = 0x20;
-+ geo.cylinders = size;
-+ geo.start = ssfdc_hd[minor].start_sect;
-+// printk(KERN_WARNING "ssfdc : HDIO_GETGEO heads %d, sectors %d, cylinders %d, start %lu\n",
-+// geo.heads, geo.sectors, geo.cylinders, geo.start);
-+ copy_to_user((void *)arg, &geo, sizeof(geo));
-+ ret = 0;
-+ break;
-+
-+ case BLKGETSIZE64:
-+ case BLKGETSIZE:
-+ size = (((pt_smcpart->mtd->size / 16384) * 1000) / 1024) * 32;
-+ //=printk(KERN_WARNING "ssfdc : BLKGETSIZE %d, minor %d\n", size, minor);
-+ ret = copy_to_user((unsigned long *)arg, &size, sizeof(size));
-+ break;
-+ case BLKSSZGET:
-+ size = 512;
-+ ret = copy_to_user((unsigned long *)arg, &size, sizeof(size));
-+ break;
-+ break;
-+
-+ case BLKRRPART:
-+ if(minor & ((1<< PARTITION_BITS) - 1)) return -ENOTTY;
-+ ssfdc_read_partitions(pt_smcpart);
-+ ret=0;
-+ break;
-+ case BLKFLSBUF:
-+ printk(KERN_WARNING "ssfdc : block ioctl 0x%x\n", cmd);
-+ break;
-+
-+ default:
-+ printk(KERN_WARNING "ssfdc: unknown ioctl 0x%x\n", cmd);
-+ }
-+
-+//ssfdc_ioctl_error:
-+ return(ret);
-+
-+}
-+static int ssfdc_open(struct inode *inode, struct file *file)
-+{
-+ int minor = MINOR(inode->i_rdev);
-+ partition_t *pt_smcpart;
-+ int index;
-+
-+ if (minor >= MAX_MTD_DEVICES)
-+ return -ENODEV;
-+
-+ index = (minor & ~(MAX_PARTITIONS -1)) >> PARTITION_BITS;
-+
-+
-+ if(SMCParts[index].type != SSFDC_FORMAT)
-+ return -ENXIO;
-+
-+ pt_smcpart = &SMCParts[index];
-+
-+
-+ if(!pt_smcpart->zone)
-+ return -ENXIO;
-+
-+
-+ BLK_INC_USE_COUNT;
-+
-+ if (!get_mtd_device(pt_smcpart->mtd, -1)) {
-+ BLK_DEC_USE_COUNT;
-+ return -ENXIO;
-+ }
-+
-+ if ((file->f_mode & 2) && !(pt_smcpart->mtd->flags & MTD_CLEAR_BITS) ) {
-+ put_mtd_device(pt_smcpart->mtd);
-+ BLK_DEC_USE_COUNT;
-+ return -EROFS;
-+ }
-+
-+
-+ atomic_inc(&pt_smcpart->minor[minor & ~(MAX_PARTITIONS -1)].open);
-+
-+ PDEBUG("ssfdc_open : device %d\n", minor);
-+
-+ return(0);
-+}
-+
-+static void ssfdc_tables(partition_t * pt_smcpart) {
-+
-+ int * logical, * physical;
-+ int offset = 0;
-+ int zone, block;
-+ int i, retlen;
-+ int block_address, parity;
-+ int h, l;
-+
-+ for(zone=0; zone<pt_smcpart->zoneCount; zone++) {
-+ logical = pt_smcpart->zone + (2048 * zone);
-+ memset((void *)logical, 0xFF, 1024 * sizeof(int));
-+ physical = pt_smcpart->zone + (2048 * zone) + 1024;
-+ memset((void *)physical, 0xFF, 1024 * sizeof(int));
-+
-+ for(block=0; block < 1024; block++) {
-+ offset = (zone * ZONE_SIZE) + (block * SMC_BLOCK_SIZE);
-+ pt_smcpart->mtd->read_oob(pt_smcpart->mtd, offset, sizeof(ssfdc_buffer), &retlen, ssfdc_buffer);
-+ if(retlen != sizeof(ssfdc_buffer)) {
-+ printk(KERN_WARNING "ssfdc_tables : failed to read OOB\n");
-+ pt_smcpart->type = 0;
-+ return;
-+ }
-+
-+ l = (ssfdc_buffer[7] & 0xFF);
-+ h = (ssfdc_buffer[6] & 0xFF);
-+ block_address = l + (h << 8L);
-+
-+ if((block_address & ~0x7FF) != 0x1000) {
-+ continue;
-+ }
-+
-+ parity = block_address & 0x01;
-+
-+ block_address &= 0x7FF;
-+ block_address >>= 1;
-+
-+
-+ if(ssfdc_parity(block_address) != parity) {
-+ printk(KERN_WARNING "ssfdc_tables : parity error offset 0x%x, block 0x%x, parity 0x%x\nOOB : "
-+ , offset, block_address, parity);
-+ for(i=0; i<16; i++) {
-+ printk("0x%02x ", (unsigned char)ssfdc_buffer[i]);
-+ }
-+ printk("\n");
-+ pt_smcpart->type = 0;
-+ return;
-+ }
-+
-+
-+ /* Ok we have a valid block number so insert it */
-+ *(logical + block_address) = (offset/SMC_BLOCK_SIZE);
-+ PDEBUG("ssfdc_tables : logical 0x%x + 0x%x = 0x%x\n",
-+ (unsigned int)logical, block_address, (offset/SMC_BLOCK_SIZE));
-+ *(physical + block) = block_address;
-+ PDEBUG("ssfdc_tables : physical 0x%x + 0x%x = 0x%x\n", (unsigned int)physical, block, block_address);
-+
-+
-+ }
-+ }
-+ return;
-+}
-+int ssfdc_parity(int number) {
-+ int i;
-+ int parity = 1; // the 0x1000 bit
-+
-+ for(i=0; i<10; i++) {
-+ parity += ((number >> i) & 1);
-+ }
-+ PDEBUG("ssfdc_parity : number 0x%x, parity 0x%x\n", number, parity);
-+ return(parity % 2);
-+}
-+static int ssfdc_physical(partition_t * pt_smcpart, int zone, int block) {
-+
-+ unsigned int * logical;
-+
-+ logical = pt_smcpart->zone + (zone * 2048);
-+
-+ logical += block;
-+
-+ if(*logical == 0xFFFFFFFF) {
-+ PDEBUG("ssfdc_physical : physical for zone %d, block %d invalid\n", zone, block);
-+ return(-1);
-+ }
-+
-+ PDEBUG("ssfdc_physical : physical for zone %d, block %d, 0x%x\n", zone, block, (*logical * SMC_BLOCK_SIZE));
-+ return(*logical * SMC_BLOCK_SIZE);
-+}
-+
-+static int ssfdc_close(struct inode *inode, struct file *file)
-+{
-+ int minor = MINOR(inode->i_rdev);
-+ partition_t *pt_smcpart;
-+ int index = (minor & ~(MAX_PARTITIONS -1)) >> PARTITION_BITS;
-+
-+ if (minor >= MAX_MTD_DEVICES)
-+ return -ENODEV;
-+
-+ if(SMCParts[index].type != SSFDC_FORMAT)
-+ return -ENXIO;
-+
-+ pt_smcpart = &SMCParts[index];
-+ atomic_dec(&pt_smcpart->minor[minor & ~(MAX_PARTITIONS -1)].open);
-+ put_mtd_device(pt_smcpart->mtd);
-+ BLK_DEC_USE_COUNT;
-+
-+ return(0);
-+}
-+
-+
-+static void do_ssfdc_request(request_arg_t)
-+{
-+ int ret, minor;
-+ partition_t *pt_smcpart;
-+ int index;
-+ do {
-+
-+ INIT_REQUEST;
-+
-+
-+
-+ minor = MINOR(CURRENT->rq_dev);
-+ index = (minor & ~(MAX_PARTITIONS -1)) >> PARTITION_BITS;
-+
-+ pt_smcpart = &SMCParts[index];
-+ if (pt_smcpart->type == SSFDC_FORMAT) {
-+ ret = 0;
-+ switch (CURRENT->cmd) {
-+ case READ:
-+ ret = ssfdc_read(pt_smcpart, CURRENT->buffer,
-+ CURRENT->sector + ssfdc_hd[minor].start_sect,
-+ CURRENT->current_nr_sectors);
-+ break;
-+
-+ case WRITE:
-+ ret = ssfdc_write(pt_smcpart, CURRENT->buffer,
-+ CURRENT->sector + ssfdc_hd[minor].start_sect,
-+ CURRENT->current_nr_sectors);
-+ break;
-+
-+ default:
-+ panic("do_ssfdc_request : unknown block command!\n");
-+ }
-+
-+ } else {
-+ ret = 1;
-+ PDEBUG("not ssfdc partition type\n");
-+ }
-+
-+ if (!ret) {
-+ CURRENT->sector += CURRENT->current_nr_sectors;
-+ }
-+
-+ end_request((ret == 0) ? 1 : 0);
-+ } while (1);
-+}
-+
-+static int ssfdc_write(partition_t *pt_smcpart, caddr_t buffer,
-+ u_long sector, u_long nblocks)
-+{
-+ int zone, block, offset;
-+ int sectors_written = 0;
-+ int physical;
-+ int * pt_logical;
-+ int * pt_physical;
-+ int new = -1;
-+ int size;
-+ int retlen;
-+ int i;
-+ int sc;
-+ int ptr_done = 0;
-+ unsigned char * ptr = (unsigned char *)buffer;
-+ unsigned char ecc_code[6], ecc_calc[6];
-+ int do_erase;
-+// unsigned char smc_status;
-+
-+
-+
-+ offset = (sector % SECTORS_PER_ZONE) % SECTORS_PER_BLOCK ;
-+
-+ PDEBUG("write device %d, sector %d, count %d\n",
-+ pt_smcpart->count, sector, nblocks);
-+/*
-+ smc_status = in_8((void *)&pt_ssfdc_smc->smc_status);
-+ if(!(smc_status & SMC_PRESENT)) {
-+ printk("ssfdc : media not present\n");
-+ return -ENXIO;
-+ }
-+
-+ if(smc_status & SMC_CHANGED) {
-+ out_8((void *)&pt_ssfdc_smc->smc_status, smc_status);
-+ ssfdc_read_partitions(pt_smcpart);
-+ printk("ssfdc : media change\n");
-+ }
-+*/
-+ while(sectors_written < nblocks) {
-+
-+ new = -1;
-+ do_erase = FALSE;
-+
-+ zone = (sector + sectors_written) / SECTORS_PER_ZONE;
-+ block = ((sector + sectors_written) % SECTORS_PER_ZONE) / SECTORS_PER_BLOCK ;
-+ offset = ((sector + sectors_written) % SECTORS_PER_ZONE) % SECTORS_PER_BLOCK ;
-+
-+ pt_logical = pt_smcpart->zone + (zone * 2048);
-+ pt_physical = pt_smcpart->zone + (zone * 2048) + 1024;
-+
-+ size = ((SECTORS_PER_BLOCK - offset) < (nblocks - sectors_written)) ?
-+ (SECTORS_PER_BLOCK - offset) : (nblocks - sectors_written);
-+ size *= SECTOR_SIZE;
-+
-+ PDEBUG("write device %d, sector %d, count %d, zone %d, block %d, offset %d, done %d, size %d, address 0x%x\n",
-+ pt_smcpart->count, sector, nblocks, zone, block, offset, sectors_written, size, (unsigned int)ptr);
-+
-+ physical = ssfdc_physical(pt_smcpart, zone, block);
-+
-+
-+ if(physical >= 0) {
-+ if(ssfdc_cached != physical) {
-+ pt_smcpart->mtd->read_ecc(pt_smcpart->mtd, physical, SMC_BLOCK_SIZE, &retlen, ssfdc_scratch,
-+ ssfdc_oob_buf, &ssfdc_ffoob_info);
-+ if(retlen != SMC_BLOCK_SIZE) {
-+ printk(KERN_WARNING "ssfdc_write : failed to read physical\n");
-+ return -ENXIO;
-+ }
-+
-+ for(sc=0; sc<SECTORS_PER_BLOCK; sc++) {
-+ pt_smcpart->mtd->read_oob(pt_smcpart->mtd, physical + (sc * SECTOR_SIZE), sizeof(ssfdc_buffer), &retlen, ssfdc_buffer);
-+ if(retlen != sizeof(ssfdc_buffer)) {
-+ printk(KERN_WARNING "ssfdc_write : failed to read physical oob\n");
-+ return -ENXIO;
-+ }
-+
-+ nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_calc[0]);
-+ nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_calc[3]);
-+ for(i=0; i<6; i++) ecc_code[i] = ssfdc_buffer[ssfdc_ecc[i]];
-+ nand_correct_data(pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_code[0], &ecc_calc[0]);
-+ nand_correct_data(pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_code[3], &ecc_calc[3]);
-+ }
-+
-+ }
-+
-+ for(sc=0; sc<SECTORS_PER_BLOCK; sc++) {
-+ if(offset > sc) {
-+ PDEBUG("offset %d, sector %d\n", offset, sc);
-+ continue;
-+ }
-+ pt_smcpart->mtd->read_oob(pt_smcpart->mtd, physical + (sc * SECTOR_SIZE), sizeof(ssfdc_buffer), &retlen, ssfdc_buffer);
-+ if(retlen != sizeof(ssfdc_buffer)) {
-+ printk(KERN_WARNING "ssfdc_write : failed to read physical oob\n");
-+ return -ENXIO;
-+ }
-+
-+ nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_calc[0]);
-+ nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_calc[3]);
-+ for(i=0; i<6; i++) ecc_code[i] = ssfdc_buffer[ssfdc_ecc[i]];
-+ nand_correct_data(pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_code[0], &ecc_calc[0]);
-+ nand_correct_data(pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_code[3], &ecc_calc[3]);
-+
-+ /* find out if the block is being used */
-+
-+
-+ if(ssfdc_sector_blank(pt_smcpart, sc)) {
-+ PDEBUG("ssfdc_write : zone %d, block %d, sector %d, lbn %d, blank, physical 0x%x\n",
-+ zone, block, sc, sector, physical);
-+ memcpy(&ssfdc_scratch[(sc * SECTOR_SIZE)], ptr+ptr_done, SECTOR_SIZE);
-+ nand_calculate_ecc (pt_smcpart->mtd, (ptr + ptr_done), &ecc_calc[0]);
-+ nand_calculate_ecc (pt_smcpart->mtd, (ptr + ptr_done + 256), &ecc_calc[3]);
-+ for(i=0; i<6; i++) ssfdc_buffer[ssfdc_ecc[i]] = ecc_calc[i];
-+ i = (block << 1) | 0x1000;
-+ i |= ssfdc_parity(block);
-+ ssfdc_buffer[7] = ssfdc_buffer[12] = i & 0xFF;
-+ ssfdc_buffer[6] = ssfdc_buffer[11] = (i & 0xFF00) >> 0x08;
-+
-+ pt_smcpart->mtd->write_ecc(pt_smcpart->mtd, physical + (sc * SECTOR_SIZE), SECTOR_SIZE, &retlen,
-+ ptr + ptr_done, ssfdc_buffer, &ssfdc_ffoob_info);
-+ if(retlen != SECTOR_SIZE) {
-+ printk(KERN_WARNING "ssfdc_write : failed to write physical 0x%x, sector 0x%x, blank, retlen %d\n"
-+ , physical, sc, retlen);
-+ return -ENXIO;
-+ }
-+
-+ ptr_done += SECTOR_SIZE;
-+ if(ptr_done >= size) break;
-+ }
-+ else {
-+ new = ssfdc_allocate_new(pt_smcpart, zone);
-+ /* erase the old block */
-+ *(pt_physical + ((physical % ZONE_SIZE) / SMC_BLOCK_SIZE)) = 0xFFFFFFFF;
-+
-+ PDEBUG("ssfdc_write : physical 0x%x + 0x%x = 0x%x\n",
-+ (unsigned int)pt_physical, ((physical % ZONE_SIZE) / SMC_BLOCK_SIZE), 0xFFFFFFFF);
-+ do_erase = TRUE;
-+ PDEBUG("ssfdc_write : zone %d, block %d, sector %d, lbn %d, written, physical 0x%x, new 0x%x\n",
-+ zone, block, sc, sector, physical, new);
-+ break;
-+ }
-+ }
-+ }
-+ else {
-+ ssfdc_cached = 0xFFFFFFFF;
-+ memset(ssfdc_scratch, 0xFF, sizeof(ssfdc_scratch));
-+ new = ssfdc_allocate_new(pt_smcpart, zone);
-+ PDEBUG("ssfdc_write : zone %d, block %d, lbn %d, physical 0x%x, unallocated, new 0x%x\n",
-+ zone, block, sector, physical, new);
-+ }
-+
-+
-+
-+ if(new != -1) {
-+
-+
-+ memcpy(&ssfdc_scratch[(offset * SECTOR_SIZE)], ptr, size);
-+ PDEBUG("ssfdc_write : new 0x%x, offset 0x%x, size 0x%x, block 0x%x\n", new, offset, size, block);
-+ for(sc=0; sc<SECTORS_PER_BLOCK; sc++) {
-+ memset(ssfdc_buffer, 0xFF, OOB_SIZE);
-+ nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_calc[0]);
-+ nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_calc[3]);
-+ for(i=0; i<6; i++) ssfdc_buffer[ssfdc_ecc[i]] = ecc_calc[i];
-+ i = (block << 1) | 0x1000;
-+ i |= ssfdc_parity(block);
-+ ssfdc_buffer[7] = ssfdc_buffer[12] = i & 0xFF;
-+ ssfdc_buffer[6] = ssfdc_buffer[11] = (i & 0xFF00) >> 0x08;
-+ memcpy(&ssfdc_oob_buf[sc * OOB_SIZE], ssfdc_buffer, OOB_SIZE);
-+ }
-+
-+
-+ pt_smcpart->mtd->write_ecc(pt_smcpart->mtd, new, SMC_BLOCK_SIZE, &retlen, ssfdc_scratch,
-+ ssfdc_oob_buf, &ssfdc_ffoob_info);
-+ if(retlen != SMC_BLOCK_SIZE) {
-+ printk(KERN_WARNING "ssfdc_write : failed to write block, physical 0x%x, returned 0x%x\n", new, retlen);
-+ return -ENXIO;
-+ }
-+ /* change the mapping table to reflect the new block placement */
-+
-+ *(pt_logical + block) = (new % ZONE_SIZE) / SMC_BLOCK_SIZE;
-+ PDEBUG("ssfdc_write : logical 0x%x + 0x%x = 0x%x\n",
-+ (unsigned int)pt_logical, block, (new % ZONE_SIZE) / SMC_BLOCK_SIZE);
-+
-+ *(pt_physical + ((new % ZONE_SIZE) / SMC_BLOCK_SIZE)) = block;
-+ PDEBUG("ssfdc_write : physical 0x%x + 0x%x = 0x%x\n",
-+ (unsigned int)pt_physical, ((new % ZONE_SIZE) / SMC_BLOCK_SIZE), block);
-+
-+
-+ ssfdc_cached = new;
-+ }
-+
-+
-+ ptr += size;
-+ ptr_done = 0;
-+ sectors_written += (size / SECTOR_SIZE);
-+ if(do_erase) ssfdc_erase(pt_smcpart, physical);
-+
-+ }
-+
-+
-+
-+
-+ return(0);
-+}
-+static int ssfdc_sector_blank(partition_t * pt_smcpart, int sc) {
-+int b;
-+
-+ for(b=0; b<SECTOR_SIZE; b++) {
-+ if(ssfdc_scratch[b + (sc * SECTOR_SIZE)] != 0xFF) return(0);
-+ }
-+ for(b=0; b<OOB_SIZE; b++) {
-+ if((b==6) || (b==7) || (b==11) || (b==12)) continue; // Block address fields
-+ if(ssfdc_buffer[b] != 0xFF) return(0);
-+ }
-+ return(1);
-+}
-+static int ssfdc_allocate_new(partition_t * pt_smcpart, int zone) {
-+
-+ int new = pt_smcpart->last_written[zone] + 1;
-+ int * pt_physical;
-+ int physical;
-+ int block;
-+ int retlen;
-+ unsigned char oob[16];
-+
-+
-+ if(new >= BLOCKS_PER_ZONE) new = 0;
-+
-+
-+ while (new != pt_smcpart->last_written[zone]) {
-+ block = new % BLOCKS_PER_ZONE;
-+ pt_physical = pt_smcpart->zone + (zone * 2048) + 1024 + block;
-+ physical = (zone * ZONE_SIZE) + (block * SMC_BLOCK_SIZE);
-+
-+ PDEBUG("ssfdc_allocate_new : zone %d, block %d, address 0x%08x, data 0x%08x\n",
-+ zone, block, (unsigned int)pt_physical, *pt_physical);
-+ if(*pt_physical == 0xFFFFFFFF) {
-+ PDEBUG("ssfdc_allocate_new : physical 0x%x = 0x%x\n", (unsigned int)pt_physical, *pt_physical);
-+ memset(oob, 0, OOB_SIZE);
-+ pt_smcpart->mtd->read_oob(pt_smcpart->mtd, physical, OOB_SIZE, &retlen, oob);
-+ if((oob[5] == 0xFF) && (retlen == OOB_SIZE)) { // If not a bad block
-+ pt_smcpart->last_written[zone] = new;
-+ return((new * SMC_BLOCK_SIZE) + (zone * ZONE_SIZE));
-+ }
-+ else {
-+ PDEBUG("ssfdc_allocate_new : new 0x%x, physical 0x%x, block status 0x%x, oob length 0x%x\n", new, physical, oob[5], retlen);
-+ }
-+ }
-+ new++;
-+ if(new >= BLOCKS_PER_ZONE) new = 0;
-+ }
-+
-+ panic("ssfdc_allocate_new : cant find free block\n");
-+
-+}
-+
-+
-+
-+static int ssfdc_read(partition_t *pt_smcpart, caddr_t buffer,
-+ u_long sector, u_long nblocks)
-+{
-+ int zone, block, offset;
-+ int sectors_read = 0;
-+ int physical;
-+ int size;
-+ int retlen;
-+ int i;
-+ int sc;
-+ unsigned char * ptr = (unsigned char *)buffer;
-+ unsigned char ecc_code[6], ecc_calc[6];
-+/*
-+ unsigned char smc_status;
-+
-+ smc_status = in_8((void *)&pt_ssfdc_smc->smc_status);
-+ if(!(smc_status & SMC_PRESENT)) {
-+ printk("ssfdc : media not present\n");
-+ return -ENXIO;
-+ }
-+
-+
-+
-+ if(smc_status & SMC_CHANGED) {
-+ out_8((void *)&pt_ssfdc_smc->smc_status, smc_status);
-+ ssfdc_read_partitions(pt_smcpart);
-+ printk("ssfdc : media change\n");
-+ }
-+*/
-+ while(sectors_read < nblocks) {
-+
-+ zone = (sector + sectors_read) / SECTORS_PER_ZONE;
-+ block = ((sector + sectors_read) % SECTORS_PER_ZONE) / SECTORS_PER_BLOCK ;
-+ offset = ((sector + sectors_read) % SECTORS_PER_ZONE) % SECTORS_PER_BLOCK ;
-+
-+
-+ if(offset) {
-+ size = ((SECTORS_PER_BLOCK - offset) < (nblocks - sectors_read)) ?
-+ (SECTORS_PER_BLOCK - offset) : (nblocks - sectors_read);
-+ }
-+ else {
-+ size = (SECTORS_PER_BLOCK < (nblocks - sectors_read)) ? SECTORS_PER_BLOCK : nblocks - sectors_read;
-+ }
-+ size *= SECTOR_SIZE;
-+
-+ PDEBUG("ssfdc_read : device %d, sector %d, count %d, zone %d, block %d, offset %d, done %d, size %d, address 0x%x\n",
-+ pt_smcpart->count, sector, nblocks, zone, block, offset, sectors_read, size, (unsigned int)ptr);
-+
-+
-+ physical = ssfdc_physical(pt_smcpart, zone, block);
-+ if(physical >= 0) {
-+ if(ssfdc_cached != physical) {
-+ pt_smcpart->mtd->read_ecc(pt_smcpart->mtd, physical, SMC_BLOCK_SIZE, &retlen, ssfdc_scratch,
-+ ssfdc_oob_buf, &ssfdc_ffoob_info);
-+ if(retlen != SMC_BLOCK_SIZE) {
-+ printk(KERN_WARNING "ssfdc_read : failed to read physical\n");
-+ return -ENXIO;
-+ }
-+ for(sc=0; sc<SECTORS_PER_BLOCK; sc++) {
-+ pt_smcpart->mtd->read_oob(pt_smcpart->mtd, physical + (sc * SECTOR_SIZE), sizeof(ssfdc_buffer), &retlen, ssfdc_buffer);
-+ if(retlen != sizeof(ssfdc_buffer)) {
-+ printk(KERN_WARNING "ssfdc_read : failed to read physical oob\n");
-+ return -ENXIO;
-+ }
-+ nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_calc[0]);
-+ nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_calc[3]);
-+ for(i=0; i<3; i++) ecc_code[i] = ssfdc_buffer[ssfdc_ecc[i]];
-+ for(i=3; i<6; i++) ecc_code[i] = ssfdc_buffer[ssfdc_ecc[i]];
-+ nand_correct_data(pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_code[0], &ecc_calc[0]);
-+ nand_correct_data(pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_code[3], &ecc_calc[3]);
-+ }
-+
-+ /* Get the ecc bytes and check that they are ok */
-+
-+
-+ }
-+ ssfdc_cached = physical;
-+
-+
-+ }
-+ else {
-+ memset(ssfdc_scratch, 0xFF, sizeof(ssfdc_scratch));
-+ ssfdc_cached = 0xFFFFFFFF;
-+ }
-+
-+
-+ memcpy(ptr, &ssfdc_scratch[(offset * SECTOR_SIZE)], size);
-+ ptr += size;
-+ sectors_read += (size / SECTOR_SIZE);
-+ }
-+
-+
-+
-+ return(0);
-+}
-+
-+static void ssfdc_erase_callback(struct erase_info *erase) {
-+
-+ PDEBUG("ssfdc_erase_callback : wake erase\n");
-+ up(&ssfdc_semaphore);
-+ PDEBUG("ssfdc_erase_callback : woken erase\n");
-+}
-+
-+static int ssfdc_erase(partition_t *pt_smcpart, unsigned int offset)
-+{
-+ int ret = 0;
-+ struct erase_info *erase;
-+ unsigned char * junk;
-+ unsigned char * oob;
-+ int retlen;
-+ int b, sc;
-+
-+
-+ PDEBUG("ssfdc_erase : offset 0x%08x\n", offset);
-+
-+ erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
-+ junk=kmalloc(pt_smcpart->mtd->erasesize + 16, GFP_KERNEL);
-+ oob = junk + pt_smcpart->mtd->erasesize;
-+
-+ if (!erase)
-+ return -ENOMEM;
-+ if (!junk)
-+ return -ENOMEM;
-+
-+ erase->addr = offset;
-+ erase->len = pt_smcpart->mtd->erasesize;
-+ erase->callback = ssfdc_erase_callback;
-+ ret = pt_smcpart->mtd->erase(pt_smcpart->mtd, erase);
-+ if(ret) {
-+ printk(KERN_WARNING "ssfdc_erase : failed status 0x%x\n", ret);
-+ goto end;
-+
-+ }
-+
-+ down(&ssfdc_semaphore);
-+
-+ pt_smcpart->mtd->read_ecc(pt_smcpart->mtd, offset, SMC_BLOCK_SIZE, &retlen, junk,
-+ ssfdc_oob_buf, &ssfdc_ffoob_info);
-+ if(retlen != SMC_BLOCK_SIZE) {
-+ printk(KERN_WARNING "ssfdc_erase : offset 0x%x, read returned length %d\n", offset, retlen);
-+ goto end;
-+ }
-+
-+
-+ for(sc=0; sc < SECTORS_PER_BLOCK; sc++) {
-+ for(b=0; b<SECTOR_SIZE; b++) {
-+ if(*(junk + (b + (sc * SECTOR_SIZE))) != 0xFF) {
-+ printk(KERN_WARNING "ssfdc_erase : offset 0x%x, sector 0x%x, byte 0x%x, data 0x%02x, expected 0xff\n"
-+ , offset, sc, b, *(junk + (b + (sc * SECTOR_SIZE))));
-+ goto end;
-+ }
-+ }
-+ pt_smcpart->mtd->read_oob(pt_smcpart->mtd, offset + (sc * SECTOR_SIZE), OOB_SIZE, &retlen, oob);
-+ if(retlen != OOB_SIZE) {
-+ printk(KERN_WARNING "ssfdc_erase : offset 0x%x, read oob returned length %d\n", offset, retlen);
-+ goto end;
-+ }
-+ for(b=0; b<OOB_SIZE; b++) {
-+ if(*(oob+b) != 0xFF) {
-+ printk(KERN_WARNING "ssfdc_erase : offset 0x%x, byte 0x%x, oob got 0x%02x, expected 0xff\n",
-+ offset, b, *(oob+b));
-+ goto end;
-+ }
-+ }
-+ }
-+
-+end:
-+
-+ kfree(erase);
-+ kfree(junk);
-+
-+ return ret;
-+} /* erase_xfer */
-+
-+
-+
-+
-+
-+int init_ssfdc(void)
-+{
-+ int result, i;
-+
-+// unsigned char smc_status;
-+// #define B01159_FIO_PBASE 0x0000000148000000 /* Physical Base address of SMC control chip */
-+
-+ printk(KERN_INFO "SSFDC block device translation layer V1.0\n");
-+/*
-+ pt_ssfdc_smc = ioremap64(B01159_FIO_PBASE, 1024);
-+ if(!pt_ssfdc_smc){
-+ printk("ssfdc : failed to map SMC control device\n");
-+ return(-EFAULT);
-+ }
-+
-+ smc_status = in_8((void *)&pt_ssfdc_smc->smc_status);
-+*/
-+ memset(ssfdc_ffoob_buf, 0xFF, sizeof(ssfdc_ffoob_buf));
-+
-+ for (i = 0; i < MAX_DEVICES*MAX_PARTITIONS; i++) {
-+ ssfdc_hd[i].nr_sects = 0;
-+ ssfdc_hd[i].start_sect = 0;
-+ ssfdc_blocksizes[i] = 4096;
-+ }
-+ blksize_size[SSFDC_MAJOR] = ssfdc_blocksizes;
-+ ssfdc_gendisk.major = SSFDC_MAJOR;
-+
-+
-+ memset(ssfdc_scratch, 0xFF, sizeof(ssfdc_scratch));
-+
-+ result = register_blkdev(ssfdc_major, "ssfdc", &ssfdc_fops);
-+ if(result != 0) {
-+ printk(KERN_WARNING "ssfdc : failed to get a major number\n");
-+ return(result);
-+ }
-+// if(ssfdc_major == 0) ssfdc_major = result;
-+
-+ blk_init_queue(BLK_DEFAULT_QUEUE(ssfdc_major), &do_ssfdc_request);
-+
-+ add_gendisk(&ssfdc_gendisk);
-+
-+
-+
-+ register_mtd_user(&ssfdc_notifier);
-+
-+
-+ init_MUTEX_LOCKED(&ssfdc_semaphore);
-+
-+
-+
-+ return 0;
-+}
-+
-+static void __exit cleanup_ssfdc(void)
-+{
-+ int i;
-+
-+ for(i=0; i<MAX_DEVICES; i++) {
-+ if(SMCParts[i].zone)kfree(SMCParts[i].zone);
-+ }
-+
-+
-+ unregister_mtd_user(&ssfdc_notifier);
-+ unregister_blkdev(ssfdc_major, "ssfdc");
-+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(ssfdc_major));
-+
-+
-+
-+ blksize_size[SSFDC_MAJOR] = NULL;
-+ del_gendisk(&ssfdc_gendisk);
-+
-+}
-+
-+module_init(init_ssfdc);
-+module_exit(cleanup_ssfdc);
-+
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Simon Haynes <simon@baydel.com>");
-+MODULE_DESCRIPTION("SSFDC translation layer support for MTD");
-+
-+
-+
-+
---- linux-2.4.21/drivers/net/irda/pxa_ir.c~pxa-irda
-+++ linux-2.4.21/drivers/net/irda/pxa_ir.c
-@@ -38,6 +38,7 @@
- #include <net/irda/wrapper.h>
- #include <net/irda/irda_device.h>
-
-+#include <asm/io.h>
- #include <asm/irq.h>
- #include <asm/dma.h>
- #include <asm/hardware.h>
-@@ -786,6 +787,7 @@
- * Suspend the IrDA interface.
- */
-
-+/*
- static int pxa250_irda_shutdown(struct pxa250_irda *si)
- {
-
-@@ -793,6 +795,7 @@
- return 0;
-
- }
-+*/
-
-
- static int pxa250_irda_suspend(struct net_device *dev, int state)
-@@ -1141,11 +1144,11 @@
- /* allocate consistent buffers for dma access
- * buffers have to be aligned and situated in dma capable memory region;
- */
-- si->rxbuf_dma_virt = consistent_alloc(GFP_KERNEL | GFP_DMA ,HPSIR_MAX_RXLEN , &si->rxbuf_dma);
-+ si->rxbuf_dma_virt = consistent_alloc(GFP_KERNEL | GFP_DMA ,HPSIR_MAX_RXLEN , &si->rxbuf_dma, 0);
- if (! si->rxbuf_dma_virt )
- goto err_rxbuf_dma;
-
-- si->txbuf_dma_virt = consistent_alloc(GFP_KERNEL | GFP_DMA, HPSIR_MAX_TXLEN, &si->txbuf_dma);
-+ si->txbuf_dma_virt = consistent_alloc(GFP_KERNEL | GFP_DMA, HPSIR_MAX_TXLEN, &si->txbuf_dma, 0);
- if (! si->txbuf_dma_virt )
- goto err_txbuf_dma;
-
---- linux-2.4.21/drivers/net/smc91x.c~pxa-smc91x
-+++ linux-2.4.21/drivers/net/smc91x.c
-@@ -46,10 +46,13 @@
- . 12/20/01 Jeff Sutherland initial port to Xscale PXA with DMA support
- . 04/07/03 Nicolas Pitre unified SMC91x driver, killed irq races,
- . more bus abstraction, big cleanup, etc.
-+ . 20/08/03 Holger Schurig add ethtool support
- ----------------------------------------------------------------------------*/
-
-+#define DRV_NAME "smc91x"
-+
- static const char version[] =
-- "smc91x.c: v1.0, mar 07 2003 by Nicolas Pitre <nico@cam.org>\n";
-+ DRV_NAME ": v1.1 Aug 20 2003 by Nicolas Pitre <nico@cam.org>\n";
-
- /* Debugging level */
- #ifndef SMC_DEBUG
-@@ -67,6 +70,7 @@
- #include <linux/timer.h>
- #include <linux/errno.h>
- #include <linux/ioport.h>
-+#include <linux/ethtool.h>
-
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
-@@ -78,6 +82,7 @@
- #include <asm/io.h>
- #include <asm/hardware.h>
- #include <asm/irq.h>
-+#include <asm/uaccess.h>
-
- #include "smc91x.h"
-
-@@ -105,7 +110,7 @@
- static int irq = SMC_IRQ;
-
- #ifndef SMC_NOWAIT
--# define SMC_NOWAIT 0
-+# define SMC_NOWAIT 1
- #endif
- static int nowait = SMC_NOWAIT;
-
-@@ -116,6 +121,11 @@
- MODULE_PARM_DESC(irq, "IRQ number");
- MODULE_PARM_DESC(nowait, "set to 1 for no wait state");
-
-+static int
-+smc_read_phy_register(unsigned long ioaddr, int phyaddr, int phyreg);
-+static void
-+smc_write_phy_register( unsigned long ioaddr, int phyaddr,
-+ int phyreg, int phydata );
-
- /*------------------------------------------------------------------------
- .
-@@ -143,7 +153,12 @@
- . but to the expense of reduced TX throughput and increased IRQ overhead.
- . Note this is not a cure for a too slow data bus or too high IRQ latency.
- */
--#define THROTTLE_TX_PKTS 0
-+#define THROTTLE_TX_PKTS 1
-+
-+/*
-+ . This defines if we want to compile ethtool support into the driver
-+*/
-+#define WITH_ETHTOOL 1
-
-
- /* store this information for the driver.. */
-@@ -310,14 +325,14 @@
- if (nowait)
- SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_NO_WAIT );
-
--#ifdef POWER_DOWN
-+#if POWER_DOWN
- /* Release from possible power-down state */
- /* Configuration register is not affected by Soft Reset */
- SMC_SELECT_BANK( 1 );
- SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_EPH_POWER_EN );
- status = smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG);
- status &= ~PHY_CNTL_PDN;
-- smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG);
-+ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, status);
- #endif
-
- /* this should pause enough for the chip to be happy */
-@@ -390,10 +405,10 @@
- SMC_SET_RCR( RCR_CLEAR );
- SMC_SET_TCR( TCR_CLEAR );
-
--#ifdef POWER_DOWN
-+#if POWER_DOWN
- status = smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG);
- status |= PHY_CNTL_PDN;
-- smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG);
-+ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, status);
-
- /* finally, shut the chip down */
- SMC_SELECT_BANK( 1 );
-@@ -1628,14 +1643,18 @@
- // Setup the default Register Modes
- lp->tcr_cur_mode = TCR_DEFAULT;
- lp->rcr_cur_mode = RCR_DEFAULT;
-- lp->rpc_cur_mode = RPC_DEFAULT;
-
- /* Set default parameters */
- #ifdef CONFIG_ARCH_RAMSES
-- lp->ctl_autoneg = 0;
-- lp->ctl_rfduplx = 0;
-+ lp->rpc_cur_mode = (RPC_ANEG | (RPC_LED_10 << RPC_LSXA_SHFT) | (RPC_LED_TX_RX << RPC_LSXB_SHFT) | RPC_DPLX);
-+
-+ // 10 MBit/S, auto-negotiation only for 10 MB/s
-+ lp->ctl_autoneg = 1;
-+ lp->ctl_rfduplx = 1;
- lp->ctl_rspeed = 10;
- #else
-+ lp->rpc_cur_mode = RPC_DEFAULT;
-+
- lp->ctl_autoneg = 1;
- lp->ctl_rfduplx = 1;
- lp->ctl_rspeed = 100;
-@@ -1680,6 +1699,127 @@
- return 0;
- }
-
-+/*----------------------------------------------------
-+ . smc_ioctl
-+ .
-+ . This ioctl is currently only used by ethtool(8) to
-+ . access the serial EEPROM
-+ -----------------------------------------------------*/
-+
-+#if WITH_ETHTOOL
-+
-+#define SMC91x_EEPROM_SIZE (0x40*2)
-+
-+u16 smc_eeprom_read(long ioaddr, u16 location)
-+{
-+ u16 val;
-+ u16 oldBank;
-+ u16 oldPtr;
-+
-+ cli();
-+ // Save chip settings
-+ oldBank = SMC_CURRENT_BANK();
-+ SMC_SELECT_BANK( 2 );
-+ oldPtr = SMC_GET_PTR();
-+
-+ // Set location in EEPROM to be read
-+ SMC_SET_PTR(location);
-+
-+ // Set EEPROM_SELECT and RELOAD bits in control register
-+ SMC_SELECT_BANK( 1 );
-+ val = SMC_GET_CTL();
-+ SMC_SET_CTL(val | CTL_EEPROM_SELECT | CTL_RELOAD);
-+
-+ // Wait until RELEAD is finished
-+ while (SMC_GET_CTL() & CTL_RELOAD) ;
-+
-+ // Get EEPROM data
-+ val = SMC_inw(ioaddr, GP_REG);
-+
-+ // Restore chip settings
-+ SMC_SELECT_BANK( 2 );
-+ SMC_SET_PTR(oldPtr);
-+ SMC_SELECT_BANK( oldBank );
-+ sti();
-+
-+ return val;
-+}
-+
-+static int smc_get_eeprom(struct net_device *dev, u8 *buf)
-+{
-+ int i;
-+ u16 *ebuf = (u16 *)buf;
-+
-+ for (i = 0; i < SMC91x_EEPROM_SIZE/2; i++) {
-+ ebuf[i] = smc_eeprom_read(dev->base_addr, i);
-+ }
-+ return 0;
-+}
-+
-+static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-+{
-+ u32 etcmd;
-+ int ret = -EINVAL;
-+
-+ if (cmd != SIOCETHTOOL)
-+ return -EOPNOTSUPP;
-+
-+ if (get_user(etcmd, (u32 *)rq->ifr_data))
-+ return -EFAULT;
-+
-+ switch (etcmd) {
-+
-+ /* Get driver info */
-+ case ETHTOOL_GDRVINFO: {
-+ struct ethtool_drvinfo edrv;
-+
-+ memset(&edrv, 0, sizeof(edrv));
-+ edrv.cmd = etcmd;
-+ strcpy(edrv.driver, DRV_NAME);
-+ sprintf(edrv.bus_info, "ISA:%8.8lx:%d", dev->base_addr, dev->irq);
-+ edrv.eedump_len = SMC91x_EEPROM_SIZE;
-+ ret = copy_to_user(rq->ifr_data, &edrv, sizeof(edrv)) ? -EFAULT : 0;
-+ break;
-+ }
-+
-+ /* Get EEPROM data */
-+ case ETHTOOL_GEEPROM: {
-+ struct ethtool_eeprom eeprom;
-+ u8 eebuf[SMC91x_EEPROM_SIZE];
-+ int r;
-+
-+ if (copy_from_user(&eeprom, rq->ifr_data, sizeof(eeprom)))
-+ return -EFAULT;
-+
-+ if (eeprom.offset > eeprom.offset+eeprom.len)
-+ return -EINVAL;
-+
-+ if ((eeprom.offset+eeprom.len) > SMC91x_EEPROM_SIZE) {
-+ eeprom.len = SMC91x_EEPROM_SIZE-eeprom.offset;
-+ }
-+ eeprom.magic = 0;
-+ if (copy_to_user(rq->ifr_data, &eeprom, sizeof(eeprom)))
-+ return -EFAULT;
-+
-+ rq->ifr_data += offsetof(struct ethtool_eeprom, data);
-+
-+ r = smc_get_eeprom(dev, eebuf);
-+
-+ if (r)
-+ return r;
-+ if (copy_to_user(rq->ifr_data, eebuf+eeprom.offset, eeprom.len))
-+ return -EFAULT;
-+ return 0;
-+
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+#endif
-+
-+
- /*------------------------------------------------------------
- . Get the current statistics.
- . This may be called with the card open or closed.
-@@ -1925,6 +2065,9 @@
- dev->watchdog_timeo = HZ/10;
- dev->get_stats = smc_query_statistics;
- dev->set_multicast_list = smc_set_multicast_list;
-+#if WITH_ETHTOOL
-+ dev->do_ioctl = smc_ioctl;
-+#endif
-
- return 0;
-
-@@ -1961,12 +2104,17 @@
- smc_shutdown(global_dev);
- break;
- case PM_RESUME:
-+ udelay(5000);
- smc_reset(global_dev);
- smc_enable(global_dev);
- SMC_SELECT_BANK( 1 );
- SMC_SET_MAC_ADDR(global_dev->dev_addr);
-- if (lp->version >= 0x70)
-- smc_phy_configure(global_dev);
-+ if (global_dev->flags & IFF_UP) {
-+ if (lp->version >= 0x70)
-+ smc_phy_configure(global_dev);
-+ } else {
-+ smc_shutdown(global_dev);
-+ }
- break;
- }
- return 0;
-@@ -2054,6 +2202,15 @@
- int ioaddr = RAMSES_ETH_BASE + 0x300;
- global_dev->irq = SMC_IRQ;
- ret = smc_probe(global_dev, ioaddr);
-+#ifdef POWER_DOWN
-+ smc_shutdown(global_dev);
-+#endif
-+ }
-+#elif defined(CONFIG_ARCH_RAMSES)
-+ {
-+ int ioaddr = RAMSES_ETH_BASE + 0x300;
-+ global_dev->irq = SMC_IRQ;
-+ ret = smc_probe(global_dev, ioaddr);
- }
- #else
- if (global_dev->base_addr == -1) {
-@@ -2083,7 +2240,11 @@
- #ifdef CONFIG_PM
- if (ret == 0) {
- struct smc_local *lp = (struct smc_local *)global_dev->priv;
-+#ifdef PM_DEBUG
-+ lp->pm = pm_register(PM_SYS_UNKNOWN, 0x73393178, smc_pm_callback, "smc91x");
-+#else
- lp->pm = pm_register(PM_SYS_UNKNOWN, 0x73393178, smc_pm_callback);
-+#endif
- }
- #endif
-
---- linux-2.4.21/drivers/net/smc91x.h~ramses-smc91x
-+++ linux-2.4.21/drivers/net/smc91x.h
-@@ -79,6 +79,11 @@
- #include <asm/arch/ramses.h>
- #define SMC_IOADDR (RAMSES_ETH_PHYS + 0x300)
- #define SMC_IRQ ETHERNET_IRQ
-+
-+#elif CONFIG_ARCH_RAMSES
-+#include <asm/arch/ramses.h>
-+#define SMC_IOADDR (RAMSES_ETH_PHYS + 0x300)
-+#define SMC_IRQ ETHERNET_IRQ
- #endif
-
- #define SMC_CAN_USE_8BIT 1
---- linux-2.4.21/drivers/net/wireless/hermes.c~orinoco013e
-+++ linux-2.4.21/drivers/net/wireless/hermes.c
-@@ -52,7 +52,6 @@
-
- #include "hermes.h"
-
--static char version[] __initdata = "hermes.c: 4 Dec 2002 David Gibson <hermes@gibson.dropbear.id.au>";
- MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller");
- MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
- #ifdef MODULE_LICENSE
-@@ -226,7 +225,8 @@
- * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware
- *
- * Callable from any context, but locking is your problem. */
--int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp)
-+int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
-+ hermes_response_t *resp)
- {
- int err;
- int k;
-@@ -469,13 +469,17 @@
-
- err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
- if (err)
-- goto out;
-+ return err;
-
- err = hermes_bap_seek(hw, bap, rid, 0);
- if (err)
-- goto out;
-+ return err;
-
- rlength = hermes_read_reg(hw, dreg);
-+
-+ if (! rlength)
-+ return -ENOENT;
-+
- rtype = hermes_read_reg(hw, dreg);
-
- if (length)
-@@ -495,8 +499,7 @@
- nwords = min((unsigned)rlength - 1, bufsize / 2);
- hermes_read_words(hw, dreg, buf, nwords);
-
-- out:
-- return err;
-+ return 0;
- }
-
- int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
-@@ -511,7 +514,7 @@
-
- err = hermes_bap_seek(hw, bap, rid, 0);
- if (err)
-- goto out;
-+ return err;
-
- hermes_write_reg(hw, dreg, length);
- hermes_write_reg(hw, dreg, rid);
-@@ -523,7 +526,6 @@
- err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
- rid, NULL);
-
-- out:
- return err;
- }
-
-@@ -539,9 +541,12 @@
-
- static int __init init_hermes(void)
- {
-- printk(KERN_DEBUG "%s\n", version);
--
- return 0;
- }
-
-+static void __exit exit_hermes(void)
-+{
-+}
-+
- module_init(init_hermes);
-+module_exit(exit_hermes);
---- linux-2.4.21/drivers/net/wireless/hermes.h~orinoco013e
-+++ linux-2.4.21/drivers/net/wireless/hermes.h
-@@ -250,7 +250,6 @@
- u16 scanreason; /* ??? */
- struct hermes_scan_apinfo aps[35]; /* Scan result */
- } __attribute__ ((packed));
--
- #define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000)
- #define HERMES_LINKSTATUS_CONNECTED (0x0001)
- #define HERMES_LINKSTATUS_DISCONNECTED (0x0002)
-@@ -278,7 +277,7 @@
-
- /* Basic control structure */
- typedef struct hermes {
-- ulong iobase;
-+ unsigned long iobase;
- int io_space; /* 1 if we IO-mapped IO, 0 for memory-mapped IO? */
- #define HERMES_IO 1
- #define HERMES_MEM 0
-@@ -368,7 +367,7 @@
- if (hw->io_space) {
- insw(hw->iobase + off, buf, count);
- } else {
-- int i;
-+ unsigned i;
- u16 *p;
-
- /* This needs to *not* byteswap (like insw()) but
-@@ -388,7 +387,7 @@
- if (hw->io_space) {
- outsw(hw->iobase + off, buf, count);
- } else {
-- int i;
-+ unsigned i;
- const u16 *p;
-
- /* This needs to *not* byteswap (like outsw()) but
-@@ -401,6 +400,21 @@
- }
- }
-
-+static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count)
-+{
-+ unsigned i;
-+
-+ off = off << hw->reg_spacing;;
-+
-+ if (hw->io_space) {
-+ for (i = 0; i < count; i++)
-+ outw(0, hw->iobase + off);
-+ } else {
-+ for (i = 0; i < count; i++)
-+ writew(0, hw->iobase + off);
-+ }
-+}
-+
- #define HERMES_READ_RECORD(hw, bap, rid, buf) \
- (hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf)))
- #define HERMES_WRITE_RECORD(hw, bap, rid, buf) \
---- linux-2.4.21/drivers/net/wireless/ieee802_11.h~orinoco013e
-+++ linux-2.4.21/drivers/net/wireless/ieee802_11.h
-@@ -9,6 +9,8 @@
- bytes is allowed, which is a bit confusing, I suspect this
- represents the 2304 bytes of real data, plus a possible 8 bytes of
- WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
-+
-+
- #define IEEE802_11_HLEN 30
- #define IEEE802_11_FRAME_LEN (IEEE802_11_DATA_LEN + IEEE802_11_HLEN)
-
---- linux-2.4.21/drivers/net/wireless/orinoco.c~orinoco013e
-+++ linux-2.4.21/drivers/net/wireless/orinoco.c
-@@ -1,4 +1,4 @@
--/* orinoco.c 0.13b - (formerly known as dldwd_cs.c and orinoco_cs.c)
-+/* orinoco.c 0.13e - (formerly known as dldwd_cs.c and orinoco_cs.c)
- *
- * A driver for Hermes or Prism 2 chipset based PCMCIA wireless
- * adaptors, with Lucent/Agere, Intersil or Symbol firmware.
-@@ -117,7 +117,7 @@
- * o Init of priv->tx_rate_ctrl in firmware specific section.
- * o Prism2/Symbol rate, upto should be 0xF and not 0x15. Doh !
- * o Spectrum card always need cor_reset (for every reset)
-- * o Fix cor_reset to not loose bit 7 in the register
-+ * o Fix cor_reset to not lose bit 7 in the register
- * o flush_stale_links to remove zombie Pcmcia instances
- * o Ack previous hermes event before reset
- * Me (with my little hands)
-@@ -289,7 +289,7 @@
- * which are used as the dev->open, dev->stop, priv->reset
- * callbacks if none are specified when alloc_orinocodev() is
- * called.
-- * o Removed orinoco_plx_interupt() and orinoco_pci_interrupt().
-+ * o Removed orinoco_plx_interrupt() and orinoco_pci_interrupt().
- * They didn't do anything.
- *
- * v0.12 -> v0.12a - 4 Jul 2002 - David Gibson
-@@ -345,13 +345,54 @@
- * we are connected (avoids cofusing the firmware), and only
- * give LINKSTATUS printk()s if the status has changed.
- *
-+ * v0.13b -> v0.13c - 11 Mar 2003 - David Gibson
-+ * o Cleanup: use dev instead of priv in various places.
-+ * o Bug fix: Don't ReleaseConfiguration on RESET_PHYSICAL event
-+ * if we're in the middle of a (driver initiated) hard reset.
-+ * o Bug fix: ETH_ZLEN is supposed to include the header
-+ * (Dionysus Blazakis & Manish Karir)
-+ * o Convert to using workqueues instead of taskqueues (and
-+ * backwards compatibility macros for pre 2.5.41 kernels).
-+ * o Drop redundant (I think...) MOD_{INC,DEC}_USE_COUNT in
-+ * airport.c
-+ * o New orinoco_tmd.c init module from Joerg Dorchain for
-+ * TMD7160 based PCI to PCMCIA bridges (similar to
-+ * orinoco_plx.c).
-+ *
-+ * v0.13c -> v0.13d - 22 Apr 2003 - David Gibson
-+ * o Make hw_unavailable a counter, rather than just a flag, this
-+ * is necessary to avoid some races (such as a card being
-+ * removed in the middle of orinoco_reset().
-+ * o Restore Release/RequestConfiguration in the PCMCIA event handler
-+ * when dealing with a driver initiated hard reset. This is
-+ * necessary to prevent hangs due to a spurious interrupt while
-+ * the reset is in progress.
-+ * o Clear the 802.11 header when transmitting, even though we
-+ * don't use it. This fixes a long standing bug on some
-+ * firmwares, which seem to get confused if that isn't done.
-+ * o Be less eager to de-encapsulate SNAP frames, only do so if
-+ * the OUI is 00:00:00 or 00:00:f8, leave others alone. The old
-+ * behaviour broke CDP (Cisco Discovery Protocol).
-+ * o Use dev instead of priv for free_irq() as well as
-+ * request_irq() (oops).
-+ * o Attempt to reset rather than giving up if we get too many
-+ * IRQs.
-+ * o Changed semantics of __orinoco_down() so it can be called
-+ * safely with hw_unavailable set. It also now clears the
-+ * linkstatus (since we're going to have to reassociate).
-+ *
-+ * v0.13d -> v0.13e - 12 May 2003 - David Gibson
-+ * o Support for post-2.5.68 return values from irq handler.
-+ * o Fixed bug where underlength packets would be double counted
-+ * in the rx_dropped statistics.
-+ * o Provided a module parameter to suppress linkstatus messages.
-+ *
- * TODO
--
- * o New wireless extensions API (patch from Moustafa
-- * Youssef, updated by Jim Carter).
-- * o Fix PCMCIA hard resets with pcmcia-cs.
-+ * Youssef, updated by Jim Carter and Pavel Roskin).
- * o Handle de-encapsulation within network layer, provide 802.11
- * headers (patch from Thomas 'Dent' Mirlacher)
-+ * o RF monitor mode support
- * o Fix possible races in SPY handling.
- * o Disconnect wireless extensions from fundamental configuration.
- * o (maybe) Software WEP support (patch from Stano Meduna).
-@@ -373,27 +414,27 @@
- * flag after taking the lock, and if it is set, give up on whatever
- * they are doing and drop the lock again. The orinoco_lock()
- * function handles this (it unlocks and returns -EBUSY if
-- * hw_unavailable is true). */
-+ * hw_unavailable is non-zero). */
-
- #include <linux/config.h>
-
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
--#include <linux/sched.h>
- #include <linux/ptrace.h>
- #include <linux/slab.h>
- #include <linux/string.h>
- #include <linux/timer.h>
- #include <linux/ioport.h>
--#include <asm/uaccess.h>
--#include <asm/io.h>
--#include <asm/system.h>
- #include <linux/netdevice.h>
- #include <linux/if_arp.h>
- #include <linux/etherdevice.h>
- #include <linux/wireless.h>
-
-+#include <asm/uaccess.h>
-+#include <asm/io.h>
-+#include <asm/system.h>
-+
- #include "hermes.h"
- #include "hermes_rid.h"
- #include "orinoco.h"
-@@ -416,6 +457,9 @@
- EXPORT_SYMBOL(orinoco_debug);
- #endif
-
-+static int suppress_linkstatus; /* = 0 */
-+MODULE_PARM(suppress_linkstatus, "i");
-+
- /********************************************************************/
- /* Compile time configuration and compatibility stuff */
- /********************************************************************/
-@@ -443,8 +487,10 @@
- #define USER_BAP 0
- #define IRQ_BAP 1
- #define MAX_IRQLOOPS_PER_IRQ 10
--#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of how many events the
-- device could legitimately generate */
-+#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of
-+ * how many events the
-+ * device could
-+ * legitimately generate */
- #define SMALL_KEY_SIZE 5
- #define LARGE_KEY_SIZE 13
- #define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */
-@@ -480,8 +526,8 @@
- {10, 1, 1, 1},
- {20, 0, 2, 2},
- {20, 1, 6, 3},
-- {55, 0, 4, 4},
-- {55, 1, 7, 7},
-+ {55, 0, 4, 4},
-+ {55, 1, 7, 7},
- {110, 0, 5, 8},
- };
- #define BITRATE_TABLE_SIZE (sizeof(bitrate_table) / sizeof(bitrate_table[0]))
-@@ -522,7 +568,7 @@
-
- /* Hardware control routines */
-
--static int __orinoco_program_rids(struct orinoco_private *priv);
-+static int __orinoco_program_rids(struct net_device *dev);
-
- static int __orinoco_hw_set_bitrate(struct orinoco_private *priv);
- static int __orinoco_hw_setup_wep(struct orinoco_private *priv);
-@@ -535,37 +581,17 @@
- static void __orinoco_set_multicast_list(struct net_device *dev);
-
- /* Interrupt handling routines */
--static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw);
--static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw);
--static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw);
--static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw);
--static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw);
--static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw);
--static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw);
--static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw);
-+static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw);
-+static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw);
-+static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw);
-+static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw);
-+static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw);
-+static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw);
-+static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw);
-+static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw);
-
- /* ioctl() routines */
--static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq);
--static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq);
--static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq);
--static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq);
--static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq);
--static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq);
--static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq);
--static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq);
--static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq);
--static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq);
--static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq);
--static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq);
--static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq);
--static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *frq);
--static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *frq);
--static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq);
--static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq);
--static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq);
--static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq);
--
--static int orinoco_debug_dump_recs(struct orinoco_private *priv);
-+static int orinoco_debug_dump_recs(struct net_device *dev);
-
- /********************************************************************/
- /* Function prototypes */
-@@ -577,7 +603,7 @@
- struct hermes *hw = &priv->hw;
- int err;
-
-- err = __orinoco_program_rids(priv);
-+ err = __orinoco_program_rids(dev);
- if (err) {
- printk(KERN_ERR "%s: Error %d configuring card\n",
- dev->name, err);
-@@ -606,14 +632,25 @@
-
- netif_stop_queue(dev);
-
-- err = hermes_disable_port(hw, 0);
-- if (err) {
-- printk(KERN_ERR "%s: Error %d disabling MAC port\n",
-- dev->name, err);
-- return err;
-+ if (! priv->hw_unavailable) {
-+ if (! priv->broken_disableport) {
-+ err = hermes_disable_port(hw, 0);
-+ if (err) {
-+ /* Some firmwares (e.g. Intersil 1.3.x) seem
-+ * to have problems disabling the port, oh
-+ * well, too bad. */
-+ printk(KERN_WARNING "%s: Error %d disabling MAC port\n",
-+ dev->name, err);
-+ priv->broken_disableport = 1;
-+ }
-+ }
-+ hermes_set_irqmask(hw, 0);
-+ hermes_write_regn(hw, EVACK, 0xffff);
- }
-- hermes_set_irqmask(hw, 0);
-- hermes_write_regn(hw, EVACK, 0xffff);
-+
-+ /* firmware will have to reassociate */
-+ priv->last_linkstatus = 0xffff;
-+ priv->connected = 0;
-
- return 0;
- }
-@@ -656,38 +693,38 @@
- if (err)
- return err;
-
-- priv->open = 1;
--
- err = __orinoco_up(dev);
-
-+ if (! err)
-+ priv->open = 1;
-+
- orinoco_unlock(priv, &flags);
-
- return err;
- }
-
--static int orinoco_stop(struct net_device *dev)
-+int orinoco_stop(struct net_device *dev)
- {
- struct orinoco_private *priv = dev->priv;
- int err = 0;
-
- /* We mustn't use orinoco_lock() here, because we need to be
-- able to close the interface, even if hw_unavailable is set
-+ able to close the interface even if hw_unavailable is set
- (e.g. as we're released after a PC Card removal) */
- spin_lock_irq(&priv->lock);
-
- priv->open = 0;
-
-- if (! priv->hw_unavailable)
-- err = __orinoco_down(dev);
-+ err = __orinoco_down(dev);
-
- spin_unlock_irq(&priv->lock);
-
- return err;
- }
-
--static int __orinoco_program_rids(struct orinoco_private *priv)
-+static int __orinoco_program_rids(struct net_device *dev)
- {
-- struct net_device *dev = priv->ndev;
-+ struct orinoco_private *priv = dev->priv;
- hermes_t *hw = &priv->hw;
- int err;
- struct hermes_idstring idbuf;
-@@ -873,51 +910,84 @@
- }
-
- /* xyzzy */
--static int orinoco_reconfigure(struct orinoco_private *priv)
-+static int orinoco_reconfigure(struct net_device *dev)
- {
-+ struct orinoco_private *priv = dev->priv;
- struct hermes *hw = &priv->hw;
- unsigned long flags;
- int err = 0;
-
-- orinoco_lock(priv, &flags);
-+ if (priv->broken_disableport) {
-+ schedule_work(&priv->reset_work);
-+ return 0;
-+ }
-+
-+ err = orinoco_lock(priv, &flags);
-+ if (err)
-+ return err;
-
-+
- err = hermes_disable_port(hw, 0);
- if (err) {
-- printk(KERN_ERR "%s: Unable to disable port in orinco_reconfigure()\n",
-- priv->ndev->name);
-+ printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n",
-+ dev->name);
-+ priv->broken_disableport = 1;
- goto out;
- }
-
-- err = __orinoco_program_rids(priv);
-- if (err)
-+ err = __orinoco_program_rids(dev);
-+ if (err) {
-+ printk(KERN_WARNING "%s: Unable to reconfigure card\n",
-+ dev->name);
- goto out;
-+ }
-
- err = hermes_enable_port(hw, 0);
- if (err) {
-- printk(KERN_ERR "%s: Unable to enable port in orinco_reconfigure()\n",
-- priv->ndev->name);
-+ printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
-+ dev->name);
- goto out;
- }
-
- out:
-+ if (err) {
-+ printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
-+ schedule_work(&priv->reset_work);
-+ err = 0;
-+ }
-+
- orinoco_unlock(priv, &flags);
- return err;
-
- }
-
- /* This must be called from user context, without locks held - use
-- * schedule_task() */
-+ * schedule_work() */
- static void orinoco_reset(struct net_device *dev)
- {
- struct orinoco_private *priv = dev->priv;
-+ struct hermes *hw = &priv->hw;
- int err;
- unsigned long flags;
-
- err = orinoco_lock(priv, &flags);
- if (err)
-+ /* When the hardware becomes available again, whatever
-+ * detects that is responsible for re-initializing
-+ * it. So no need for anything further*/
- return;
-
-- priv->hw_unavailable = 1;
-+ netif_stop_queue(dev);
-+
-+ /* Shut off interrupts. Depending on what state the hardware
-+ * is in, this might not work, but we'll try anyway */
-+ hermes_set_irqmask(hw, 0);
-+ hermes_write_regn(hw, EVACK, 0xffff);
-+
-+ priv->hw_unavailable++;
-+ priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */
-+ priv->connected = 0;
-+
- orinoco_unlock(priv, &flags);
-
- if (priv->hard_reset)
-@@ -936,18 +1006,22 @@
- return;
- }
-
-- spin_lock_irqsave(&priv->lock, flags);
-+ spin_lock_irq(&priv->lock); /* This has to be called from user context */
-
-- priv->hw_unavailable = 0;
-+ priv->hw_unavailable--;
-
-- err = __orinoco_up(dev);
-- if (err) {
-- printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
-- dev->name, err);
-- } else
-- dev->trans_start = jiffies;
-+ /* priv->open or priv->hw_unavailable might have changed while
-+ * we dropped the lock */
-+ if (priv->open && (! priv->hw_unavailable)) {
-+ err = __orinoco_up(dev);
-+ if (err) {
-+ printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
-+ dev->name, err);
-+ } else
-+ dev->trans_start = jiffies;
-+ }
-
-- orinoco_unlock(priv, &flags);
-+ spin_unlock_irq(&priv->lock);
-
- return;
- }
-@@ -979,10 +1053,18 @@
- }
- }
-
-+/* Does the frame have a SNAP header indicating it should be
-+ * de-encapsulated to Ethernet-II? */
- static inline int
--is_snap(struct header_struct *hdr)
-+is_ethersnap(struct header_struct *hdr)
- {
-- return (hdr->dsap == 0xAA) && (hdr->ssap == 0xAA) && (hdr->ctrl == 0x3);
-+ /* We de-encapsulate all packets which, a) have SNAP headers
-+ * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header
-+ * and where b) the OUI of the SNAP header is 00:00:00 or
-+ * 00:00:f8 - we need both because different APs appear to use
-+ * different OUIs for some reason */
-+ return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0)
-+ && ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) );
- }
-
- static void
-@@ -1140,7 +1222,8 @@
- return 0;
- }
-
--static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN])
-+static int orinoco_hw_get_bssid(struct orinoco_private *priv,
-+ char buf[ETH_ALEN])
- {
- hermes_t *hw = &priv->hw;
- int err = 0;
-@@ -1159,7 +1242,7 @@
- }
-
- static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
-- char buf[IW_ESSID_MAX_SIZE+1])
-+ char buf[IW_ESSID_MAX_SIZE+1])
- {
- hermes_t *hw = &priv->hw;
- int err = 0;
-@@ -1236,9 +1319,8 @@
- }
-
- if ( (channel < 1) || (channel > NUM_CHANNELS) ) {
-- struct net_device *dev = priv->ndev;
--
-- printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel);
-+ printk(KERN_WARNING "%s: Channel out of range (%d)!\n",
-+ priv->ndev->name, channel);
- err = -EBUSY;
- goto out;
-
-@@ -1253,8 +1335,8 @@
- return err ? err : freq;
- }
-
--static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates,
-- s32 *rates, int max)
-+static int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
-+ int *numrates, s32 *rates, int max)
- {
- hermes_t *hw = &priv->hw;
- struct hermes_idstring list;
-@@ -1287,9 +1369,6 @@
- }
-
- #if 0
--#ifndef ORINOCO_DEBUG
--static inline void show_rx_frame(struct orinoco_rxframe_hdr *frame) {}
--#else
- static void show_rx_frame(struct orinoco_rxframe_hdr *frame)
- {
- printk(KERN_DEBUG "RX descriptor:\n");
-@@ -1346,17 +1425,16 @@
- frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]);
- printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype);
- }
--#endif
--#endif
-+#endif /* 0 */
-
- /*
- * Interrupt handler
- */
--void orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-+irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs)
- {
-- struct orinoco_private *priv = (struct orinoco_private *) dev_id;
-+ struct net_device *dev = (struct net_device *)dev_id;
-+ struct orinoco_private *priv = dev->priv;
- hermes_t *hw = &priv->hw;
-- struct net_device *dev = priv->ndev;
- int count = MAX_IRQLOOPS_PER_IRQ;
- u16 evstat, events;
- /* These are used to detect a runaway interrupt situation */
-@@ -1367,12 +1445,17 @@
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0) {
-- /* If hw is unavailable */
-- return;
-+ /* If hw is unavailable - we don't know if the irq was
-+ * for us or not */
-+ return IRQ_HANDLED;
- }
-
- evstat = hermes_read_regn(hw, EVSTAT);
- events = evstat & hw->inten;
-+ if (! events) {
-+ orinoco_unlock(priv, &flags);
-+ return IRQ_NONE;
-+ }
-
- if (jiffies != last_irq_jiffy)
- loops_this_jiffy = 0;
-@@ -1380,11 +1463,11 @@
-
- while (events && count--) {
- if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) {
-- printk(KERN_CRIT "%s: IRQ handler is looping too \
--much! Shutting down.\n",
-- dev->name);
-- /* Perform an emergency shutdown */
-+ printk(KERN_WARNING "%s: IRQ handler is looping too "
-+ "much! Resetting.\n", dev->name);
-+ /* Disable interrupts for now */
- hermes_set_irqmask(hw, 0);
-+ schedule_work(&priv->reset_work);
- break;
- }
-
-@@ -1395,21 +1478,21 @@
- }
-
- if (events & HERMES_EV_TICK)
-- __orinoco_ev_tick(priv, hw);
-+ __orinoco_ev_tick(dev, hw);
- if (events & HERMES_EV_WTERR)
-- __orinoco_ev_wterr(priv, hw);
-+ __orinoco_ev_wterr(dev, hw);
- if (events & HERMES_EV_INFDROP)
-- __orinoco_ev_infdrop(priv, hw);
-+ __orinoco_ev_infdrop(dev, hw);
- if (events & HERMES_EV_INFO)
-- __orinoco_ev_info(priv, hw);
-+ __orinoco_ev_info(dev, hw);
- if (events & HERMES_EV_RX)
-- __orinoco_ev_rx(priv, hw);
-+ __orinoco_ev_rx(dev, hw);
- if (events & HERMES_EV_TXEXC)
-- __orinoco_ev_txexc(priv, hw);
-+ __orinoco_ev_txexc(dev, hw);
- if (events & HERMES_EV_TX)
-- __orinoco_ev_tx(priv, hw);
-+ __orinoco_ev_tx(dev, hw);
- if (events & HERMES_EV_ALLOC)
-- __orinoco_ev_alloc(priv, hw);
-+ __orinoco_ev_alloc(dev, hw);
-
- hermes_write_regn(hw, EVACK, events);
-
-@@ -1418,30 +1501,34 @@
- };
-
- orinoco_unlock(priv, &flags);
-+ return IRQ_HANDLED;
- }
-
--static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw)
-+static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw)
- {
-- printk(KERN_DEBUG "%s: TICK\n", priv->ndev->name);
-+ printk(KERN_DEBUG "%s: TICK\n", dev->name);
- }
-
--static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw)
-+static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw)
- {
- /* This seems to happen a fair bit under load, but ignoring it
- seems to work fine...*/
- printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n",
-- priv->ndev->name);
-+ dev->name);
- }
-
--static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw)
-+static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
- {
-- printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev->name);
-+ printk(KERN_WARNING "%s: Information frame lost.\n", dev->name);
- }
-
- static void print_linkstatus(struct net_device *dev, u16 status)
- {
- char * s;
-
-+ if (suppress_linkstatus)
-+ return;
-+
- switch (status) {
- case HERMES_LINKSTATUS_NOT_CONNECTED:
- s = "Not Connected";
-@@ -1472,9 +1559,9 @@
- dev->name, s, status);
- }
-
--static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw)
-+static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
- {
-- struct net_device *dev = priv->ndev;
-+ struct orinoco_private *priv = dev->priv;
- u16 infofid;
- struct {
- u16 len;
-@@ -1573,9 +1660,9 @@
- }
- }
-
--static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw)
-+static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
- {
-- struct net_device *dev = priv->ndev;
-+ struct orinoco_private *priv = dev->priv;
- struct net_device_stats *stats = &priv->stats;
- struct iw_statistics *wstats = &priv->wstats;
- struct sk_buff *skb = NULL;
-@@ -1664,14 +1751,13 @@
- * So, check ourselves */
- if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
- ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
-- is_snap(&hdr)) {
-+ is_ethersnap(&hdr)) {
- /* These indicate a SNAP within 802.2 LLC within
- 802.11 frame which we'll need to de-encapsulate to
- the original EthernetII frame. */
-
- if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */
- stats->rx_length_errors++;
-- stats->rx_dropped++;
- goto drop;
- }
-
-@@ -1726,9 +1812,9 @@
- return;
- }
-
--static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw)
-+static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
- {
-- struct net_device *dev = priv->ndev;
-+ struct orinoco_private *priv = dev->priv;
- struct net_device_stats *stats = &priv->stats;
- u16 fid = hermes_read_regn(hw, TXCOMPLFID);
- struct hermes_tx_descriptor desc;
-@@ -1752,8 +1838,9 @@
- hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
- }
-
--static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw)
-+static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
- {
-+ struct orinoco_private *priv = dev->priv;
- struct net_device_stats *stats = &priv->stats;
-
- stats->tx_packets++;
-@@ -1761,9 +1848,10 @@
- hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
- }
-
--static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw)
-+static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
- {
-- struct net_device *dev = priv->ndev;
-+ struct orinoco_private *priv = dev->priv;
-+
- u16 fid = hermes_read_regn(hw, ALLOCFID);
-
- if (fid != priv->txfid) {
-@@ -1945,7 +2033,7 @@
-
- TRACE_ENTER(dev->name);
-
-- /* No need to lock, the resetting flag is already set in
-+ /* No need to lock, the hw_unavailable flag is already set in
- * alloc_orinocodev() */
- priv->nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN;
-
-@@ -2081,8 +2169,6 @@
- priv->wep_on = 0;
- priv->tx_key = 0;
-
-- priv->hw_unavailable = 0;
--
- err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
- if (err == -EIO) {
- /* Try workaround for old Symbol firmware bug */
-@@ -2102,6 +2188,12 @@
- goto out;
- }
-
-+ /* Make the hardware available, as long as it hasn't been
-+ * removed elsewhere (e.g. by PCMCIA hot unplug) */
-+ spin_lock_irq(&priv->lock);
-+ priv->hw_unavailable--;
-+ spin_unlock_irq(&priv->lock);
-+
- printk(KERN_DEBUG "%s: ready\n", dev->name);
-
- out:
-@@ -2267,7 +2359,7 @@
-
- /* Length of the packet body */
- /* FIXME: what if the skb is smaller than this? */
-- len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN);
-+ len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN);
-
- eh = (struct ethhdr *)skb->data;
-
-@@ -2281,6 +2373,12 @@
- goto fail;
- }
-
-+ /* Clear the 802.11 header and data length fields - some
-+ * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
-+ * if this isn't done. */
-+ hermes_clear_words(hw, HERMES_DATA0,
-+ HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
-+
- /* Encapsulate Ethernet-II frames */
- if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */
- struct header_struct hdr;
-@@ -2362,7 +2460,7 @@
-
- stats->tx_errors++;
-
-- schedule_task(&priv->timeout_task);
-+ schedule_work(&priv->reset_work);
- }
-
- static int
-@@ -2532,7 +2630,7 @@
- }
-
- err = orinoco_hw_get_bitratelist(priv, &numrates,
-- range.bitrate, IW_MAX_BITRATES);
-+ range.bitrate, IW_MAX_BITRATES);
- if (err)
- return err;
- range.num_bitrates = numrates;
-@@ -2799,7 +2897,7 @@
- erq->flags = 1;
- erq->length = strlen(essidbuf) + 1;
- if (erq->pointer)
-- if ( copy_to_user(erq->pointer, essidbuf, erq->length) )
-+ if (copy_to_user(erq->pointer, essidbuf, erq->length))
- return -EFAULT;
-
- TRACE_EXIT(dev->name);
-@@ -3128,7 +3226,7 @@
- rrq->value = 5500000;
- else
- rrq->value = val * 1000000;
-- break;
-+ break;
- case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
- case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
- for (i = 0; i < BITRATE_TABLE_SIZE; i++)
-@@ -3754,7 +3852,7 @@
-
- printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
-
-- schedule_task(&priv->timeout_task);
-+ schedule_work(&priv->reset_work);
- break;
-
- case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */
-@@ -3827,7 +3925,7 @@
- break;
-
- case SIOCIWLASTPRIV:
-- err = orinoco_debug_dump_recs(priv);
-+ err = orinoco_debug_dump_recs(dev);
- if (err)
- printk(KERN_ERR "%s: Unable to dump records (%d)\n",
- dev->name, err);
-@@ -3839,7 +3937,7 @@
- }
-
- if (! err && changed && netif_running(dev)) {
-- err = orinoco_reconfigure(priv);
-+ err = orinoco_reconfigure(dev);
- }
-
- TRACE_EXIT(dev->name);
-@@ -3924,7 +4022,7 @@
- DEBUG_REC(PRIID,WORDS),
- DEBUG_REC(PRISUPRANGE,WORDS),
- DEBUG_REC(CFIACTRANGES,WORDS),
-- DEBUG_REC(NICSERNUM,WORDS),
-+ DEBUG_REC(NICSERNUM,XSTRING),
- DEBUG_REC(NICID,WORDS),
- DEBUG_REC(MFISUPRANGE,WORDS),
- DEBUG_REC(CFISUPRANGE,WORDS),
-@@ -3961,8 +4059,9 @@
-
- #define DEBUG_LTV_SIZE 128
-
--static int orinoco_debug_dump_recs(struct orinoco_private *priv)
-+static int orinoco_debug_dump_recs(struct net_device *dev)
- {
-+ struct orinoco_private *priv = dev->priv;
- hermes_t *hw = &priv->hw;
- u8 *val8;
- u16 *val16;
-@@ -4051,6 +4150,7 @@
- dev->do_ioctl = orinoco_ioctl;
- dev->change_mtu = orinoco_change_mtu;
- dev->set_multicast_list = orinoco_set_multicast_list;
-+ /* we use the default eth_mac_addr for setting the MAC addr */
-
- /* Set up default callbacks */
- dev->open = orinoco_open;
-@@ -4062,7 +4162,7 @@
- priv->hw_unavailable = 1; /* orinoco_init() must clear this
- * before anything else touches the
- * hardware */
-- INIT_TQUEUE(&priv->timeout_task, (void (*)(void *))orinoco_reset, dev);
-+ INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev);
-
- priv->last_linkstatus = 0xffff;
- priv->connected = 0;
-@@ -4079,13 +4179,14 @@
-
- EXPORT_SYMBOL(__orinoco_up);
- EXPORT_SYMBOL(__orinoco_down);
-+EXPORT_SYMBOL(orinoco_stop);
- EXPORT_SYMBOL(orinoco_reinit_firmware);
-
- EXPORT_SYMBOL(orinoco_interrupt);
-
- /* Can't be declared "const" or the whole __initdata section will
- * become const */
--static char version[] __initdata = "orinoco.c 0.13b (David Gibson <hermes@gibson.dropbear.id.au> and others)";
-+static char version[] __initdata = "orinoco.c 0.13e (David Gibson <hermes@gibson.dropbear.id.au> and others)";
-
- static int __init init_orinoco(void)
- {
---- linux-2.4.21/drivers/net/wireless/orinoco.h~orinoco013e
-+++ linux-2.4.21/drivers/net/wireless/orinoco.h
-@@ -11,9 +11,29 @@
- #include <linux/spinlock.h>
- #include <linux/netdevice.h>
- #include <linux/wireless.h>
--#include <linux/tqueue.h>
-+#include <linux/version.h>
- #include "hermes.h"
-
-+/* Workqueue / task queue backwards compatibility stuff */
-+
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
-+#include <linux/workqueue.h>
-+#else
-+#include <linux/tqueue.h>
-+#define work_struct tq_struct
-+#define INIT_WORK INIT_TQUEUE
-+#define schedule_work schedule_task
-+#endif
-+
-+/* Interrupt handler backwards compatibility stuff */
-+#ifndef IRQ_NONE
-+
-+#define IRQ_NONE
-+#define IRQ_HANDLED
-+typedef void irqreturn_t;
-+
-+#endif
-+
- /* To enable debug messages */
- //#define ORINOCO_DEBUG 3
-
-@@ -36,13 +56,13 @@
-
-
- struct orinoco_private {
-- void *card; /* Pointer to card dependant structure */
-+ void *card; /* Pointer to card dependent structure */
- int (*hard_reset)(struct orinoco_private *);
-
- /* Synchronisation stuff */
- spinlock_t lock;
- int hw_unavailable;
-- struct tq_struct timeout_task;
-+ struct work_struct reset_work;
-
- /* driver state */
- int open;
-@@ -72,6 +92,7 @@
- int has_sensitivity;
- int nicbuf_size;
- u16 channel_mask;
-+ int broken_disableport;
-
- /* Configuration paramaters */
- u32 iw_mode;
-@@ -111,9 +132,9 @@
- int (*hard_reset)(struct orinoco_private *));
- extern int __orinoco_up(struct net_device *dev);
- extern int __orinoco_down(struct net_device *dev);
--int orinoco_reinit_firmware(struct net_device *dev);
--
--extern void orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs);
-+extern int orinoco_stop(struct net_device *dev);
-+extern int orinoco_reinit_firmware(struct net_device *dev);
-+extern irqreturn_t orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs);
-
- /********************************************************************/
- /* Locking and synchronization functions */
---- linux-2.4.21/drivers/net/wireless/orinoco_cs.c~orinoco013e
-+++ linux-2.4.21/drivers/net/wireless/orinoco_cs.c
-@@ -1,4 +1,4 @@
--/* orinoco_cs.c 0.13b - (formerly known as dldwd_cs.c)
-+/* orinoco_cs.c 0.13e - (formerly known as dldwd_cs.c)
- *
- * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
- * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
-@@ -22,11 +22,7 @@
- #include <linux/ptrace.h>
- #include <linux/slab.h>
- #include <linux/string.h>
--#include <linux/timer.h>
- #include <linux/ioport.h>
--#include <asm/uaccess.h>
--#include <asm/io.h>
--#include <asm/system.h>
- #include <linux/netdevice.h>
- #include <linux/if_arp.h>
- #include <linux/etherdevice.h>
-@@ -38,7 +34,10 @@
- #include <pcmcia/cistpl.h>
- #include <pcmcia/cisreg.h>
- #include <pcmcia/ds.h>
--#include <pcmcia/bus_ops.h>
-+
-+#include <asm/uaccess.h>
-+#include <asm/io.h>
-+#include <asm/system.h>
-
- #include "orinoco.h"
-
-@@ -62,7 +61,7 @@
-
- /* Some D-Link cards have buggy CIS. They do work at 5v properly, but
- * don't have any CIS entry for it. This workaround it... */
--static int ignore_cis_vcc; /* = 0 */
-+static int ignore_cis_vcc = 1;
-
- MODULE_PARM(irq_mask, "i");
- MODULE_PARM(irq_list, "1-4i");
-@@ -145,8 +144,10 @@
- /* PCMCIA stuff */
- /********************************************************************/
-
-+/* In 2.5 (as of 2.5.69 at least) there is a cs_error exported which
-+ * does this, but it's not in 2.4 so we do our own for now. */
- static void
--cs_error(client_handle_t handle, int func, int ret)
-+orinoco_cs_error(client_handle_t handle, int func, int ret)
- {
- error_info_t err = { func, ret };
- CardServices(ReportError, handle, &err);
-@@ -202,6 +203,7 @@
- link->priv = dev;
-
- /* Initialize the dev_link_t structure */
-+ init_timer(&link->release);
- link->release.function = &orinoco_cs_release;
- link->release.data = (u_long) link;
-
-@@ -240,7 +242,7 @@
-
- ret = CardServices(RegisterClient, &link->handle, &client_reg);
- if (ret != CS_SUCCESS) {
-- cs_error(link->handle, RegisterClient, ret);
-+ orinoco_cs_error(link->handle, RegisterClient, ret);
- orinoco_cs_detach(link);
- return NULL;
- }
-@@ -269,19 +271,12 @@
- return;
- }
-
-- /*
-- If the device is currently configured and active, we won't
-- actually delete it yet. Instead, it is marked so that when
-- the release() function is called, that will trigger a proper
-- detach().
-- */
- if (link->state & DEV_CONFIG) {
--#ifdef PCMCIA_DEBUG
-- printk(KERN_DEBUG "orinoco_cs: detach postponed, '%s' "
-- "still locked\n", link->dev->dev_name);
--#endif
-- link->state |= DEV_STALE_LINK;
-- return;
-+ orinoco_cs_release((u_long)link);
-+ if (link->state & DEV_CONFIG) {
-+ link->state |= DEV_STALE_LINK;
-+ return;
-+ }
- }
-
- /* Break the link with Card Services */
-@@ -368,7 +363,7 @@
- CS_CHECK(GetFirstTuple, handle, &tuple);
- while (1) {
- cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-- cistpl_cftable_entry_t dflt = { index: 0 };
-+ cistpl_cftable_entry_t dflt = { .index = 0 };
-
- CFG_CHECK(GetTupleData, handle, &tuple);
- CFG_CHECK(ParseTuple, handle, &tuple, &parse);
-@@ -472,7 +467,7 @@
- link->irq.IRQInfo2 |= 1 << irq_list[i];
-
- link->irq.Handler = orinoco_interrupt;
-- link->irq.Instance = priv;
-+ link->irq.Instance = dev;
-
- CS_CHECK(RequestIRQ, link->handle, &link->irq);
- }
-@@ -532,7 +527,7 @@
- return;
-
- cs_failed:
-- cs_error(link->handle, last_fn, last_ret);
-+ orinoco_cs_error(link->handle, last_fn, last_ret);
-
- failed:
- orinoco_cs_release((u_long) link);
-@@ -549,18 +544,13 @@
- dev_link_t *link = (dev_link_t *) arg;
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = dev->priv;
-+ unsigned long flags;
-
-- /*
-- If the device is currently in use, we won't release until it
-- is actually closed, because until then, we can't be sure that
-- no one will try to access the device or its data structures.
-- */
-- if (priv->open) {
-- DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n",
-- link->dev->dev_name);
-- link->state |= DEV_STALE_CONFIG;
-- return;
-- }
-+ /* We're committed to taking the device away now, so mark the
-+ * hardware as unavailable */
-+ spin_lock_irqsave(&priv->lock, flags);
-+ priv->hw_unavailable++;
-+ spin_unlock_irqrestore(&priv->lock, flags);
-
- /* Don't bother checking to see if these succeed or not */
- CardServices(ReleaseConfiguration, link->handle);
-@@ -593,14 +583,9 @@
- orinoco_lock(priv, &flags);
-
- netif_device_detach(dev);
-- priv->hw_unavailable = 1;
-+ priv->hw_unavailable++;
-
- orinoco_unlock(priv, &flags);
--
--/* if (link->open) */
--/* orinoco_cs_stop(dev); */
--
-- mod_timer(&link->release, jiffies + HZ / 20);
- }
- break;
-
-@@ -619,13 +604,8 @@
- a better way, short of rewriting the PCMCIA
- layer to not suck :-( */
- if (! test_bit(0, &card->hard_reset_in_progress)) {
-- err = orinoco_lock(priv, &flags);
-- if (err) {
-- printk(KERN_ERR "%s: hw_unavailable on SUSPEND/RESET_PHYSICAL\n",
-- dev->name);
-- break;
-- }
--
-+ spin_lock_irqsave(&priv->lock, flags);
-+
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: %s: Error %d downing interface\n",
-@@ -634,9 +614,9 @@
- err);
-
- netif_device_detach(dev);
-- priv->hw_unavailable = 1;
--
-- orinoco_unlock(priv, &flags);
-+ priv->hw_unavailable++;
-+
-+ spin_unlock_irqrestore(&priv->lock, flags);
- }
-
- CardServices(ReleaseConfiguration, link->handle);
-@@ -653,10 +633,6 @@
- CardServices(RequestConfiguration, link->handle,
- &link->conf);
-
-- /* If we're only getting these events because
-- of the ResetCard in the hard reset, we
-- don't need to do anything - orinoco_reset()
-- will handle reinitialization. */
- if (! test_bit(0, &card->hard_reset_in_progress)) {
- err = orinoco_reinit_firmware(dev);
- if (err) {
-@@ -668,9 +644,9 @@
- spin_lock_irqsave(&priv->lock, flags);
-
- netif_device_attach(dev);
-- priv->hw_unavailable = 0;
-+ priv->hw_unavailable--;
-
-- if (priv->open) {
-+ if (priv->open && ! priv->hw_unavailable) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card\n",
-@@ -678,7 +654,7 @@
-
- }
-
-- orinoco_unlock(priv, &flags);
-+ spin_unlock_irqrestore(&priv->lock, flags);
- }
- }
- break;
-@@ -693,7 +669,7 @@
-
- /* Can't be declared "const" or the whole __initdata section will
- * become const */
--static char version[] __initdata = "orinoco_cs.c 0.13b (David Gibson <hermes@gibson.dropbear.id.au> and others)";
-+static char version[] __initdata = "orinoco_cs.c 0.13e (David Gibson <hermes@gibson.dropbear.id.au> and others)";
-
- static int __init
- init_orinoco_cs(void)
-@@ -722,7 +698,6 @@
- if (dev_list)
- DEBUG(0, "orinoco_cs: Removing leftover devices.\n");
- while (dev_list != NULL) {
-- del_timer(&dev_list->release);
- if (dev_list->state & DEV_CONFIG)
- orinoco_cs_release((u_long) dev_list);
- orinoco_cs_detach(dev_list);
---- linux-2.4.21/drivers/pcmcia/pxa/Makefile~ramses-pcmcia
-+++ linux-2.4.21/drivers/pcmcia/pxa/Makefile
-@@ -12,6 +12,7 @@
- obj-$(CONFIG_ARCH_PXA_IDP) += pxa_idp.o
- obj-$(CONFIG_ARCH_TRIZEPS2) += trizeps2.o
- obj-$(CONFIG_ARCH_PXA_CERF) += ../sa1100_cerf.o
-+obj-$(CONFIG_ARCH_RAMSES) += ramses.o
-
- obj-m := $(O_TARGET)
-
---- linux-2.4.21/drivers/pcmcia/pxa/pxa.c~pxa-pcmcia
-+++ linux-2.4.21/drivers/pcmcia/pxa/pxa.c
-@@ -187,7 +187,6 @@
- struct pcmcia_state state[PXA_PCMCIA_MAX_SOCK];
- struct pcmcia_state_array state_array;
- unsigned int i, clock;
-- unsigned long mecr;
-
- printk(KERN_INFO "Intel PXA250/210 PCMCIA (CS release %s)\n", CS_RELEASE);
-
-@@ -240,6 +239,8 @@
- pcmcia_low_level=&pxa_idp_pcmcia_ops;
- } else if( machine_is_pxa_cerf()){
- pcmcia_low_level=&cerf_pcmcia_ops;
-+ } else if( machine_is_ramses()){
-+ pcmcia_low_level=&ramses_pcmcia_ops;
- } else if (machine_is_trizeps2()){
- #ifdef CONFIG_ARCH_TRIZEPS2
- pcmcia_low_level=&trizeps2_pcmcia_ops;
-@@ -835,7 +836,7 @@
- static int pxa_pcmcia_set_io_map(unsigned int sock,
- struct pccard_io_map *map){
- unsigned int clock, speed;
-- unsigned long mecr, start;
-+ unsigned long start;
-
- DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
-
-@@ -941,7 +942,7 @@
- static int pxa_pcmcia_set_mem_map(unsigned int sock,
- struct pccard_mem_map *map){
- unsigned int clock, speed;
-- unsigned long mecr, start;
-+ unsigned long start;
-
- DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
-
-@@ -1076,7 +1077,6 @@
- char *p=buf;
- unsigned int sock=(unsigned int)data;
- unsigned int clock = get_lclk_frequency_10khz();
-- unsigned long mecr = MECR;
-
- p+=sprintf(p, "k_flags : %s%s%s%s%s%s%s\n",
- pxa_pcmcia_socket[sock].k_state.detect?"detect ":"",
---- linux-2.4.21/drivers/pcmcia/pxa/pxa.h~ramses-pcmcia
-+++ linux-2.4.21/drivers/pcmcia/pxa/pxa.h
-@@ -228,6 +228,7 @@
- extern struct pcmcia_low_level lubbock_pcmcia_ops;
- extern struct pcmcia_low_level pxa_idp_pcmcia_ops;
- extern struct pcmcia_low_level cerf_pcmcia_ops;
-+extern struct pcmcia_low_level ramses_pcmcia_ops;
- extern struct pcmcia_low_level trizeps2_pcmcia_ops;
-
- #endif /* !defined(_PCMCIA_PXA_H) */
---- /dev/null
-+++ linux-2.4.21/drivers/pcmcia/pxa/ramses.c
-@@ -0,0 +1,223 @@
-+/*
-+ * linux/drivers/pcmcia/pxa/ramses.c
-+ *
-+ * 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.
-+ *
-+ * Copyright (c) 2003 M&N Logistik-Lösungen Online GmbH
-+ *
-+ * Platform specific routines for the Ramses, based on those
-+ * first done for the Lubbock and PXA IDP.
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+
-+#include <pcmcia/ss.h>
-+
-+#include <asm/delay.h>
-+#include <asm/hardware.h>
-+#include <asm/irq.h>
-+#include <asm/arch/pcmcia.h>
-+
-+static int
-+ramses_pcmcia_init(struct pcmcia_init *init)
-+{
-+ int return_val = 0;
-+
-+ /* Set PCMCIA Socket 0 power to standby mode.
-+ * RAMSES has dedicated CPLD pins for all this stuff :-)
-+ */
-+
-+ /* both slots disabled, reset NOT active */
-+ RAMSES_CPLD_PCCARD_EN = PCC0_ENABLE | PCC1_ENABLE;
-+
-+ RAMSES_CPLD_PCCARD_PWR = 0; //all power to both slots off
-+ //GPDR(IRQ_TO_GPIO_2_80(CFCARD_CD_VALID)) &= ~GPIO_bit(IRQ_TO_GPIO_2_80(CFCARD_CD_VALID));
-+ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(CFCARD_CD_VALID), GPIO_BOTH_EDGES);
-+ //GPDR(IRQ_TO_GPIO_2_80(CFCARD_RDYINT)) &= ~GPIO_bit(IRQ_TO_GPIO_2_80(CFCARD_RDYINT));
-+ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(CFCARD_RDYINT), GPIO_FALLING_EDGE);
-+
-+ return_val +=
-+ request_irq(CFCARD_CD_VALID, init->handler, SA_INTERRUPT,
-+ "CF-Card CD", NULL);
-+
-+ if (return_val < 0) {
-+ return -1;
-+ }
-+
-+ return 2;
-+}
-+
-+static int
-+ramses_pcmcia_shutdown(void)
-+{
-+
-+ free_irq(CFCARD_CD_VALID, NULL);
-+
-+ RAMSES_CPLD_PCCARD_EN = 0x03; //disable slots
-+ udelay(200);
-+ RAMSES_CPLD_PCCARD_PWR = 0; //shut off all power
-+
-+ return 0;
-+}
-+
-+static int
-+ramses_pcmcia_socket_state(struct pcmcia_state_array *state_array)
-+{
-+ unsigned long status;
-+ int return_val = 1;
-+ int i;
-+ volatile unsigned long *stat_regs[2] = {
-+ &RAMSES_CPLD_PCCARD0_STATUS,
-+ &RAMSES_CPLD_PCCARD1_STATUS
-+ };
-+
-+ if (state_array->size < 2)
-+ return -1;
-+
-+ memset(state_array->state, 0,
-+ (state_array->size) * sizeof (struct pcmcia_state));
-+
-+ for (i = 1; i < 2; i++) {
-+
-+ status = *stat_regs[i];
-+
-+ /* this one is a gpio */
-+ state_array->state[i].detect = (PCC_DETECT(i)) ? 0 : 1;
-+
-+ state_array->state[i].ready = ((status & _PCC_IRQ) == 0) ? 0 : 1;
-+ state_array->state[i].bvd1 = (status & PCC_BVD1) ? 0 : 1;
-+ state_array->state[i].bvd2 = (status & PCC_BVD2) ? 0 : 1;
-+ state_array->state[i].wrprot = (status & _PCC_WRPROT) ? 1 : 0;
-+ state_array->state[i].vs_3v = (status & PCC_VS1) ? 0 : 1;
-+ state_array->state[i].vs_Xv = (status & PCC_VS2) ? 0 : 1;
-+ }
-+
-+ state_array->state[0].detect = 0;
-+ state_array->state[0].ready = 0;
-+ state_array->state[0].bvd1 = 0;
-+ state_array->state[0].bvd2 = 0;
-+ state_array->state[0].wrprot = 0;
-+ state_array->state[0].vs_3v = 0;
-+ state_array->state[0].vs_Xv = 0;
-+
-+ return return_val;
-+}
-+
-+static int
-+ramses_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
-+{
-+ switch (info->sock) {
-+ case 0:
-+ //info->irq = PCMCIA_S0_RDYINT;
-+ //printk("//hs ramses_pcmcia_get_irq_info called for slot 0\n");
-+ break;
-+
-+ case 1:
-+ info->irq = CFCARD_RDYINT;
-+ break;
-+
-+ default:
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+ramses_pcmcia_configure_socket(unsigned int sock, socket_state_t *state)
-+{
-+ /* The Ramses uses the Maxim MAX1602, with the following connections:
-+ *
-+ * Socket 0 (PCMCIA):
-+ * MAX1602 PXA_IDP Register
-+ * Pin Signal RAMSES_CPLD_PCCARD_PWR:
-+ * ----- ------- ----------------------
-+ * A0VPP PCC0_PWR0 bit0
-+ * A1VPP PCC0_PWR1 bit1
-+ * A0VCC PCC0_PWR2 bit2
-+ * A1VCC PCC0_PWR3 bit3
-+ * VX VCC
-+ * VY +3.3V
-+ * 12IN +12V
-+ * CODE +3.3V Cirrus Code, CODE = High (VY)
-+ *
-+ * Socket 1 (PCMCIA):
-+ * MAX1602 PXA_IDP Register
-+ * Pin Signal RAMSES_CPLD_PCCARD_PWR:
-+ * ----- ------- ----------------------
-+ * A0VPP PCC1_PWR0 bit4
-+ * A1VPP PCC1_PWR1 bit5
-+ * A0VCC PCC1_PWR2 bit6
-+ * A1VCC PCC1_PWR3 bit7
-+ * VX VCC
-+ * VY +3.3V
-+ * 12IN +12V
-+ * CODE +3.3V Cirrus Code, CODE = High (VY)
-+ *
-+ */
-+
-+ if (sock == 1) {
-+
-+ switch (state->Vcc) {
-+ case 0:
-+ RAMSES_CPLD_PCCARD_EN |= PCC1_ENABLE; // disable socket
-+ udelay(200);
-+ RAMSES_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3);
-+ break;
-+
-+ case 33:
-+ RAMSES_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3);
-+ RAMSES_CPLD_PCCARD_PWR |= PCC1_PWR3;
-+ RAMSES_CPLD_PCCARD_EN &= ~PCC1_ENABLE; //turn it on
-+ break;
-+
-+ case 50:
-+ RAMSES_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3);
-+ RAMSES_CPLD_PCCARD_PWR |= PCC1_PWR2;
-+ RAMSES_CPLD_PCCARD_EN &= ~PCC1_ENABLE;
-+ break;
-+
-+ default:
-+ printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
-+ __FUNCTION__, state->Vcc);
-+ return -1;
-+ }
-+
-+ switch (state->Vpp) {
-+ case 0:
-+ RAMSES_CPLD_PCCARD_PWR &= ~(PCC1_PWR0 | PCC1_PWR1);
-+ break;
-+
-+ case 120:
-+ RAMSES_CPLD_PCCARD_PWR &= ~(PCC1_PWR0 | PCC1_PWR1);
-+ RAMSES_CPLD_PCCARD_PWR |= PCC1_PWR1;
-+ break;
-+
-+ default:
-+ if (state->Vpp == state->Vcc)
-+ RAMSES_CPLD_PCCARD_PWR =
-+ (RAMSES_CPLD_PCCARD_PWR &
-+ ~(PCC1_PWR0 | PCC1_PWR1)) | PCC1_PWR0;
-+ else {
-+ printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
-+ __FUNCTION__, state->Vpp);
-+ return -1;
-+ }
-+ }
-+ RAMSES_CPLD_PCCARD_EN = (state->flags & SS_RESET) ? (RAMSES_CPLD_PCCARD_EN | PCC1_RESET)
-+ : (RAMSES_CPLD_PCCARD_EN & ~PCC1_RESET);
-+ }
-+ return 0;
-+}
-+
-+struct pcmcia_low_level ramses_pcmcia_ops = {
-+ ramses_pcmcia_init,
-+ ramses_pcmcia_shutdown,
-+ ramses_pcmcia_socket_state,
-+ ramses_pcmcia_get_irq_info,
-+ ramses_pcmcia_configure_socket
-+};
---- linux-2.4.21/drivers/scsi/scsi.h~usb-sonycamera
-+++ linux-2.4.21/drivers/scsi/scsi.h
-@@ -610,6 +610,7 @@
- unsigned remap:1; /* support remapping */
- unsigned starved:1; /* unable to process commands because
- host busy */
-+ unsigned no_start_on_add:1; /* do not issue start on add */
-
- // Flag to allow revalidate to succeed in sd_open
- int allow_revalidate;
---- linux-2.4.21/drivers/scsi/scsi_scan.c~usb-sonycamera
-+++ linux-2.4.21/drivers/scsi/scsi_scan.c
-@@ -37,6 +37,8 @@
- #define BLIST_ISDISK 0x100 /* Treat as (removable) disk */
- #define BLIST_ISROM 0x200 /* Treat as (removable) CD-ROM */
- #define BLIST_LARGELUN 0x400 /* LUNs larger than 7 despite reporting as SCSI 2 */
-+#define BLIST_NOSTARTONADD 0x1000 /* do not do automatic start on add */
-+
-
- static void print_inquiry(unsigned char *data);
- static int scan_scsis_single(unsigned int channel, unsigned int dev,
-@@ -110,9 +112,10 @@
- {"HP", "C1750A", "3226", BLIST_NOLUN}, /* scanjet iic */
- {"HP", "C1790A", "", BLIST_NOLUN}, /* scanjet iip */
- {"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */
-- {"HP", "A6188A", "*", BLIST_SPARSELUN}, /* HP Va7100 Array */
-- {"HP", "A6189A", "*", BLIST_SPARSELUN}, /* HP Va7400 Array */
-- {"HP", "A6189B", "*", BLIST_SPARSELUN}, /* HP Va7410 Array */
-+ {"HP", "A6188A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7100 Array */
-+ {"HP", "A6189A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7400 Array */
-+ {"HP", "A6189B", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7110 Array */
-+ {"HP", "A6218A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7410 Array */
- {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
- {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0
- * extra reset */
-@@ -145,7 +148,7 @@
- {"EMULEX", "MD21/S2 ESDI", "*", BLIST_SINGLELUN},
- {"CANON", "IPUBJD", "*", BLIST_SPARSELUN},
- {"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN},
-- {"DEC","HSG80","*", BLIST_FORCELUN},
-+ {"DEC","HSG80","*", BLIST_FORCELUN | BLIST_NOSTARTONADD},
- {"COMPAQ","LOGICAL VOLUME","*", BLIST_FORCELUN},
- {"COMPAQ","CR3500","*", BLIST_FORCELUN},
- {"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-@@ -173,7 +176,11 @@
- {"HP", "NetRAID-4M", "*", BLIST_FORCELUN},
- {"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN},
- {"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN},
-- {"COMPAQ", "MSA1000", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-+ {"APPLE", "Xserve", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-+ {"COMPAQ", "MSA1000", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_NOSTARTONADD},
-+ {"COMPAQ", "MSA1000 VOLUME", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_NOSTARTONADD},
-+ {"COMPAQ", "HSV110", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_NOSTARTONADD},
-+ {"HP", "HSV100", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_NOSTARTONADD},
- {"HP", "C1557A", "*", BLIST_FORCELUN},
- {"IBM", "AuSaV1S2", "*", BLIST_FORCELUN},
- {"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-@@ -182,7 +189,8 @@
- {"HITACHI", "DF500", "*", BLIST_SPARSELUN},
- {"HITACHI", "DF600", "*", BLIST_SPARSELUN},
- {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-- {"HITACHI", "OPEN-", "*", BLIST_SPARSELUN}, /* HITACHI XP Arrays */
-+ {"HITACHI", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HITACHI XP Arrays */
-+ {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HITACHI 9960 */
- {"WINSYS","FLASHDISK G6", "*", BLIST_SPARSELUN},
- {"DotHill","SANnet RAID X300", "*", BLIST_SPARSELUN},
- {"SUN", "T300", "*", BLIST_SPARSELUN},
-@@ -194,6 +202,12 @@
- {"SGI", "TP9400", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
- {"SGI", "TP9500", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
- {"MYLEX", "DACARMRB", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-+ {"PLATYPUS", "CX5", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-+ {"Raidtec", "FCR", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-+ {"HP", "C7200", "*", BLIST_SPARSELUN}, /* Medium Changer */
-+ {"SMSC", "USB 2 HS", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-+ {"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-+ {"NEC", "iStorage", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
-
- /*
- * Must be at end of list...
-@@ -209,10 +223,14 @@
- static unsigned int max_scsi_luns = 1;
- #endif
-
-+static unsigned int scsi_allow_ghost_devices = 0;
-+
- #ifdef MODULE
-
- MODULE_PARM(max_scsi_luns, "i");
- MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 2^32-1)");
-+MODULE_PARM(scsi_allow_ghost_devices, "i");
-+MODULE_PARM_DESC(scsi_allow_ghost_devices, "allow devices marked as being offline to be accessed anyway (0 = off, else allow ghosts on lun 0 through scsi_allow_ghost_devices - 1");
-
- #else
-
-@@ -232,6 +250,21 @@
-
- __setup("max_scsi_luns=", scsi_luns_setup);
-
-+static int __init scsi_allow_ghost_devices_setup(char *str)
-+{
-+ unsigned int tmp;
-+
-+ if (get_option(&str, &tmp) == 1) {
-+ scsi_allow_ghost_devices = tmp;
-+ return 1;
-+ } else {
-+ printk("scsi_allow_ghost_devices_setup: usage scsi_allow_ghost_devices=n (0: off else\nallow ghost devices (ghost devices are devices that report themselves as\nbeing offline but which we allow access to anyway) on lun 0 through n - 1.\n");
-+ return 0;
-+ }
-+}
-+
-+__setup("scsi_allow_ghost_devices=", scsi_allow_ghost_devices_setup);
-+
- #endif
-
- static void print_inquiry(unsigned char *data)
-@@ -608,6 +641,7 @@
- } else {
- /* assume no peripheral if any other sort of error */
- scsi_release_request(SRpnt);
-+ scsi_release_commandblocks(SDpnt);
- return 0;
- }
- }
-@@ -618,6 +652,24 @@
- */
-
- /*
-+ * If we are offline and we are on a LUN != 0, then skip this entry.
-+ * If we are on a BLIST_FORCELUN device this will stop the scan at
-+ * the first offline LUN (typically the correct thing to do). If
-+ * we are on a BLIST_SPARSELUN device then this won't stop the scan,
-+ * but it will keep us from having false entries in our device
-+ * array. DL
-+ *
-+ * NOTE: Need to test this to make sure it doesn't cause problems
-+ * with tape autoloaders, multidisc CD changers, and external
-+ * RAID chassis that might use sparse luns or multiluns... DL
-+ */
-+ if (lun != 0 && (scsi_result[0] >> 5) == 1) {
-+ scsi_release_request(SRpnt);
-+ scsi_release_commandblocks(SDpnt);
-+ return 0;
-+ }
-+
-+ /*
- * Get any flags for this device.
- */
- bflags = get_device_flags (scsi_result);
-@@ -655,8 +707,11 @@
-
- SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
- /* Use the peripheral qualifier field to determine online/offline */
-- if (((scsi_result[0] >> 5) & 7) == 1) SDpnt->online = FALSE;
-- else SDpnt->online = TRUE;
-+ if ((((scsi_result[0] >> 5) & 7) == 1) &&
-+ (lun >= scsi_allow_ghost_devices))
-+ SDpnt->online = FALSE;
-+ else
-+ SDpnt->online = TRUE;
- SDpnt->lockable = SDpnt->removable;
- SDpnt->changed = 0;
- SDpnt->access_count = 0;
-@@ -742,6 +797,13 @@
- if ((bflags & BLIST_BORKEN) == 0)
- SDpnt->borken = 0;
-
-+ /*
-+ * Some devices may not want to have a start command automatically
-+ * issued when a device is added.
-+ */
-+ if (bflags & BLIST_NOSTARTONADD)
-+ SDpnt->no_start_on_add = 1;
-+
- /*
- * If we want to only allow I/O to one of the luns attached to this device
- * at a time, then we set this flag.
-@@ -857,11 +919,26 @@
- * I think we need REPORT LUNS in future to avoid scanning
- * of unused LUNs. But, that is another item.
- */
-+ /*
- if (*max_dev_lun < shpnt->max_lun)
- *max_dev_lun = shpnt->max_lun;
- else if ((max_scsi_luns >> 1) >= *max_dev_lun)
- *max_dev_lun += shpnt->max_lun;
- else *max_dev_lun = max_scsi_luns;
-+ */
-+ /*
-+ * Blech...the above code is broken. When you have a device
-+ * that is present, and it is a FORCELUN device, then we
-+ * need to scan *all* the luns on that device. Besides,
-+ * skipping the scanning of LUNs is a false optimization.
-+ * Scanning for a LUN on a present device is a very fast
-+ * operation, it's scanning for devices that don't exist that
-+ * is expensive and slow (although if you are truly scanning
-+ * through MAX_SCSI_LUNS devices that would be bad, I hope
-+ * all of the controllers out there set a reasonable value
-+ * in shpnt->max_lun). DL
-+ */
-+ *max_dev_lun = shpnt->max_lun;
- return 1;
- }
- /*
---- linux-2.4.21/drivers/scsi/sd.c~usb-sonycamera
-+++ linux-2.4.21/drivers/scsi/sd.c
-@@ -775,7 +775,8 @@
- char nbuff[6];
- unsigned char *buffer;
- unsigned long spintime_value = 0;
-- int the_result, retries, spintime;
-+ int retries, spintime;
-+ unsigned int the_result;
- int sector_size;
- Scsi_Request *SRpnt;
-
-@@ -817,7 +818,7 @@
- do {
- retries = 0;
-
-- while (retries < 3) {
-+ do {
- cmd[0] = TEST_UNIT_READY;
- cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
- ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
-@@ -832,10 +833,10 @@
-
- the_result = SRpnt->sr_result;
- retries++;
-- if (the_result == 0
-- || SRpnt->sr_sense_buffer[2] != UNIT_ATTENTION)
-- break;
-- }
-+ } while (retries < 3
-+ && (the_result !=0
-+ || ((driver_byte(the_result) & DRIVER_SENSE)
-+ && SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION)));
-
- /*
- * If the drive has indicated to us that it doesn't have
-@@ -853,24 +854,47 @@
- break;
- }
-
-+ if ((driver_byte(the_result) & DRIVER_SENSE) == 0) {
-+ /* no sense, TUR either succeeded or failed
-+ * with a status error */
-+ if(!spintime && the_result != 0)
-+ printk(KERN_NOTICE "%s: Unit Not Ready, error = 0x%x\n", nbuff, the_result);
-+ break;
-+ }
-+
-+ /*
-+ * The device does not want the automatic start to be issued.
-+ */
-+ if (rscsi_disks[i].device->no_start_on_add) {
-+ break;
-+ }
-+
-+ /*
-+ * If manual intervention is required, or this is an
-+ * absent USB storage device, a spinup is meaningless.
-+ */
-+ if (SRpnt->sr_sense_buffer[2] == NOT_READY &&
-+ SRpnt->sr_sense_buffer[12] == 4 /* not ready */ &&
-+ SRpnt->sr_sense_buffer[13] == 3) {
-+ break; /* manual intervention required */
- /* Look for non-removable devices that return NOT_READY.
- * Issue command to spin up drive for these cases. */
-- if (the_result && !rscsi_disks[i].device->removable &&
-- SRpnt->sr_sense_buffer[2] == NOT_READY) {
-+ } else if (the_result && !rscsi_disks[i].device->removable &&
-+ SRpnt->sr_sense_buffer[2] == NOT_READY) {
- unsigned long time1;
- if (!spintime) {
- printk("%s: Spinning up disk...", nbuff);
- cmd[0] = START_STOP;
- cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
-- ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
-- cmd[1] |= 1; /* Return immediately */
-+ ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
-+ cmd[1] |= 1; /* Return immediately */
- memset((void *) &cmd[2], 0, 8);
-- cmd[4] = 1; /* Start spin cycle */
-+ cmd[4] = 1; /* Start spin cycle */
- SRpnt->sr_cmd_len = 0;
- SRpnt->sr_sense_buffer[0] = 0;
- SRpnt->sr_sense_buffer[2] = 0;
-
-- SRpnt->sr_data_direction = SCSI_DATA_READ;
-+ SRpnt->sr_data_direction = SCSI_DATA_NONE;
- scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
- 0/*512*/, SD_TIMEOUT, MAX_RETRIES);
- spintime_value = jiffies;
-@@ -883,6 +907,14 @@
- time1 = schedule_timeout(time1);
- } while(time1);
- printk(".");
-+ } else {
-+ /* we don't understand the sense code, so it's
-+ * probably pointless to loop */
-+ if(!spintime) {
-+ printk(KERN_NOTICE "%s: Unit Not Ready, sense:\n", nbuff);
-+ print_req_sense("", SRpnt);
-+ }
-+ break;
- }
- } while (the_result && spintime &&
- time_after(spintime_value + 100 * HZ, jiffies));
---- linux-2.4.21/drivers/sound/ac97_codec.c~ucb1x00
-+++ linux-2.4.21/drivers/sound/ac97_codec.c
-@@ -547,6 +547,12 @@
- val = SOUND_CAP_EXCL_INPUT;
- break;
-
-+ case SOUND_MIXER_AC97:
-+ if (get_user(val, (int *)arg))
-+ return -EFAULT;
-+ val = codec->codec_read(codec, val);
-+ return put_user(val, (int *)arg);
-+
- default: /* read a specific mixer */
- i = _IOC_NR(cmd);
-
-@@ -575,6 +581,11 @@
- codec->recmask_io(codec, 0, val);
-
- return 0;
-+
-+ case SOUND_MIXER_AC97:
-+ codec->codec_write(codec, val >> 16 & 0xffff, val & 0xffff);
-+ return 0;
-+
- default: /* write a specific mixer */
- i = _IOC_NR(cmd);
-
---- linux-2.4.21/drivers/sound/pxa-ac97.c~pxa-ac97
-+++ linux-2.4.21/drivers/sound/pxa-ac97.c
-@@ -27,6 +27,7 @@
- #include <linux/sound.h>
- #include <linux/soundcard.h>
- #include <linux/ac97_codec.h>
-+#include <linux/pm.h>
-
- #include <asm/hardware.h>
- #include <asm/irq.h>
-@@ -164,6 +165,11 @@
- //pxa_ac97_write(&pxa_ac97_codec, 0x6a, 0x1ff7);
- pxa_ac97_write(&pxa_ac97_codec, 0x6a, 0x0050);
- pxa_ac97_write(&pxa_ac97_codec, 0x6c, 0x0030);
-+#if CONFIG_ARCH_RAMSES
-+ pxa_ac97_codec.supported_mixers = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN;
-+ pxa_ac97_codec.stereo_mixers = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN;
-+ pxa_ac97_codec.record_sources = SOUND_MASK_MIC | SOUND_MASK_LINE;
-+#endif
- }
-
- pxa_ac97_refcount++;
-@@ -198,7 +204,7 @@
- static int mixer_ioctl( struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
- {
-- int ret, val;
-+ int ret;
-
- ret = pxa_ac97_codec.mixer_ioctl(&pxa_ac97_codec, cmd, arg);
- if (ret)
-@@ -282,6 +288,7 @@
- /* fall through */
-
- case SOUND_PCM_READ_RATE:
-+ val = 0;
- if (file->f_mode & FMODE_READ)
- val = codec_adc_rate;
- if (file->f_mode & FMODE_WRITE)
-@@ -342,6 +349,44 @@
- };
-
-
-+#ifdef CONFIG_PM
-+
-+static int pxa_ac97_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
-+{
-+ down(&pxa_ac97_mutex);
-+
-+ switch (rqst) {
-+ case PM_SUSPEND:
-+ // TODO: set to low-power state?
-+ GCR = GCR_ACLINK_OFF;
-+ CKEN &= ~CKEN2_AC97;
-+ break;
-+
-+ case PM_RESUME:
-+ CKEN |= CKEN2_AC97;
-+
-+ GCR = 0;
-+ udelay(10);
-+ GCR = GCR_COLD_RST|GCR_CDONE_IE|GCR_SDONE_IE;
-+ while (!(GSR & GSR_PCR)) {
-+ schedule();
-+ }
-+
-+ // need little hack for UCB1400 (should be moved elsewhere)
-+ pxa_ac97_write(&pxa_ac97_codec,AC97_EXTENDED_STATUS,1);
-+ pxa_ac97_write(&pxa_ac97_codec, 0x6a, 0x0050);
-+ pxa_ac97_write(&pxa_ac97_codec, 0x6c, 0x0030);
-+ break;
-+ }
-+
-+ up(&pxa_ac97_mutex);
-+
-+ return 0;
-+}
-+
-+#endif
-+
-+
- static int __init pxa_ac97_init(void)
- {
- int ret;
-@@ -354,11 +399,18 @@
- ac97_audio_state.dev_dsp = register_sound_dsp(&ac97_audio_fops, -1);
- pxa_ac97_codec.dev_mixer = register_sound_mixer(&mixer_fops, -1);
-
-+#ifdef PM_DEBUG
-+ ac97_audio_state.pmdev = pm_register(PM_SYS_UNKNOWN, 0x71783937, pxa_ac97_pm_callback, "pxa-ac97");
-+#else
-+ ac97_audio_state.pmdev = pm_register(PM_SYS_UNKNOWN, 0x71783937, pxa_ac97_pm_callback);
-+#endif
-+
- return 0;
- }
-
- static void __exit pxa_ac97_exit(void)
- {
-+ pm_unregister(ac97_audio_state.pmdev);
- unregister_sound_dsp(ac97_audio_state.dev_dsp);
- unregister_sound_mixer(pxa_ac97_codec.dev_mixer);
- pxa_ac97_put();
---- linux-2.4.21/drivers/sound/pxa-audio.h~pm
-+++ linux-2.4.21/drivers/sound/pxa-audio.h
-@@ -47,6 +47,9 @@
- int wr_ref:1; /* open reference for playback */
- int (*client_ioctl)(struct inode *, struct file *, uint, ulong);
- struct semaphore sem; /* prevent races in attach/release */
-+#ifdef CONFIG_PM
-+ struct pm_dev *pmdev; /* Power management */
-+#endif
- } audio_state_t;
-
- extern int pxa_audio_attach(struct inode *inode, struct file *file,
---- linux-2.4.21/drivers/usb/Config.in~pxa-usb
-+++ linux-2.4.21/drivers/usb/Config.in
-@@ -5,7 +5,7 @@
- comment 'USB support'
-
- # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
--if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SA1111" = "y" -o "$CONFIG_ARCH_AT91RM9200" = "y" ]; then
-+if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SA1111" = "y" -o "$CONFIG_ARCH_AT91RM9200" = "y" -o "$CONFIG_ARCH_PXA" = "y" ]; then
- tristate 'Support for USB' CONFIG_USB
- else
- define_bool CONFIG_USB n
---- linux-2.4.21/drivers/usb/Makefile~usb-sl811
-+++ linux-2.4.21/drivers/usb/Makefile
-@@ -80,6 +80,9 @@
- ifeq ($(CONFIG_USB_OHCI),y)
- obj-y += host/usb-ohci.o host/usb-ohci-sa1111.o
- endif
-+
-+subdir-$(CONFIG_USB_SL811HS_ALT)+= host
-+
- subdir-$(CONFIG_USB_OHCI_AT91) += host
- ifeq ($(CONFIG_USB_OHCI_AT91),y)
- obj-y += host/usb-ohci.o
---- linux-2.4.21/drivers/usb/hcd.c~ramses-usb
-+++ linux-2.4.21/drivers/usb/hcd.c
-@@ -662,7 +662,9 @@
- pci_set_drvdata(dev, hcd);
- hcd->driver = driver;
- hcd->description = driver->description;
-+#ifdef TODO
- hcd->pdev = dev;
-+#endif
- printk (KERN_INFO "%s %s: %s\n",
- hcd->description, dev->slot_name, dev->name);
-
-@@ -1201,6 +1203,7 @@
- return status;
-
- // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag
-+#ifdef TODO
- if (usb_pipecontrol (urb->pipe))
- urb->setup_dma = pci_map_single (
- #ifdef CONFIG_PCI
-@@ -1223,7 +1226,7 @@
- usb_pipein (urb->pipe)
- ? PCI_DMA_FROMDEVICE
- : PCI_DMA_TODEVICE);
--
-+#endif
- if (urb->dev == hcd->bus->root_hub)
- status = rh_urb_enqueue (hcd, urb);
- else
-@@ -1488,6 +1491,7 @@
- // hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev)
-
- // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag
-+#ifdef TODO
- if (usb_pipecontrol (urb->pipe))
- pci_unmap_single (
- #ifdef CONFIG_PCI
-@@ -1510,6 +1514,7 @@
- usb_pipein (urb->pipe)
- ? PCI_DMA_FROMDEVICE
- : PCI_DMA_TODEVICE);
-+#endif
-
- /* pass ownership to the completion handler */
- urb->complete (urb);
---- linux-2.4.21/drivers/usb/hid-core.c~bluetooth
-+++ linux-2.4.21/drivers/usb/hid-core.c
-@@ -211,6 +211,8 @@
-
- offset = report->size;
- report->size += parser->global.report_size * parser->global.report_count;
-+ if (usages < parser->global.report_count)
-+ usages = parser->global.report_count;
-
- if (usages == 0)
- return 0; /* ignore padding fields */
---- linux-2.4.21/drivers/usb/host/Config.in~usb-sl811
-+++ linux-2.4.21/drivers/usb/host/Config.in
-@@ -13,6 +13,9 @@
- fi
- dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
- dep_tristate ' SA1111 OHCI-compatible host interface support' CONFIG_USB_OHCI_SA1111 $CONFIG_USB
-+if [ "$CONFIG_ARM" = "y" -o "$CONFIG_X86" = "y" ]; then
-+ dep_tristate ' SL811HS Alternate (x86, StrongARM, isosynchronous mode)' CONFIG_USB_SL811HS_ALT $CONFIG_USB $CONFIG_EXPERIMENTAL
-+fi
- if [ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then
- dep_tristate ' AT91RM9200 OHCI-compatible host interface support' CONFIG_USB_OHCI_AT91 $CONFIG_USB
- fi
---- linux-2.4.21/drivers/usb/host/Makefile~usb-sl811
-+++ linux-2.4.21/drivers/usb/host/Makefile
-@@ -10,6 +10,7 @@
- obj-$(CONFIG_USB_UHCI) += usb-uhci.o
- obj-$(CONFIG_USB_OHCI) += usb-ohci.o usb-ohci-pci.o
- obj-$(CONFIG_USB_OHCI_SA1111) += usb-ohci.o usb-ohci-sa1111.o
-+obj-$(CONFIG_USB_SL811HS_ALT) += sl811.o
- obj-$(CONFIG_USB_OHCI_AT91) += usb-ohci.o
-
- # Extract lists of the multi-part drivers.
---- /dev/null
-+++ linux-2.4.21/drivers/usb/host/sl811.c
-@@ -0,0 +1,2782 @@
-+/*
-+ * SL811 Host Controller Interface driver for USB.
-+ *
-+ * Copyright (c) 2003/06, Courage Co., Ltd.
-+ *
-+ * Based on:
-+ * 1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
-+ * Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
-+ * Adam Richter, Gregory P. Smith;
-+ * 2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
-+ * 3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
-+ *
-+ * It's now support isochornous mode and more effective than hc_sl811.o
-+ * Support x86 architecture now.
-+ *
-+ * 19.09.2003 (05.06.2003) HNE
-+ * sl811_alloc_hc: Set "bus->bus_name" at init.
-+ * sl811_reg_test (hc_reset,regTest):
-+ * Stop output at first failed pattern.
-+ * Down-Grade for Kernel 2.4.20 and from 2.4.22
-+ * Split hardware dependency into files sl811-x86.h and sl811-arm.h.
-+ *
-+ * 22.09.2003 HNE
-+ * sl811_found_hc: First patterntest, than interrupt enable.
-+ * Do nothing, if patterntest failed. Release IO if failed.
-+ * Stop Interrupts first, than remove handle. (Old blocked Shared IRQ)
-+ * Alternate IO-Base for second Controller (CF/USB1).
-+ *
-+ * 24.09.2003 HNE
-+ * Remove all arm specific source (moved into include/asm/sl811-hw.h).
-+ *
-+ * 03.10.2003 HNE
-+ * Low level only for port IO into hardware-include.
-+ *
-+ * To do:
-+ * 1.Modify the timeout part, it's some messy
-+ * 2.Use usb-a and usb-b set in Ping-Pong mode
-+ * o Floppy do not work.
-+ * o driver crash, if io region can't register
-+ * o Only tested as module. Compiled-in version not tested!
-+ *
-+ * This program is free software; 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/module.h>
-+#include <linux/kernel.h>
-+#include <linux/delay.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/errno.h>
-+#include <linux/init.h>
-+#include <linux/smp_lock.h>
-+#include <linux/list.h>
-+#include <linux/ioport.h>
-+#include <asm/io.h>
-+#include <asm/irq.h>
-+#include <asm/hardware.h>
-+#include <linux/usb.h>
-+
-+#include "../hcd.h"
-+#include "../hub.h"
-+#include "sl811.h"
-+
-+#define DRIVER_VERSION "v0.30"
-+#define MODNAME "SL811"
-+#define DRIVER_AUTHOR "Yin Aihua <yinah@couragetech.com.cn>, Henry Nestler <hne@ist1.de>"
-+#define DRIVER_DESC "Sl811 USB Host Controller Alternate Driver"
-+
-+static LIST_HEAD(sl811_hcd_list);
-+
-+/*
-+ * 0: normal prompt and information
-+ * 1: error should not occur in normal
-+ * 2: error maybe occur in normal
-+ * 3: useful and detail debug information
-+ * 4: function level enter and level inforamtion
-+ * 5: endless information will output because of timer function or interrupt
-+ */
-+static int debug = 0;
-+MODULE_PARM(debug,"i");
-+MODULE_PARM_DESC(debug,"debug level");
-+
-+#include <asm/sl811-hw.h> /* Include hardware and board depens */
-+
-+static void sl811_rh_int_timer_do(unsigned long ptr);
-+static void sl811_transfer_done(struct sl811_hc *hc, int sof);
-+
-+/*
-+ * Read a byte of data from the SL811H/SL11H
-+ */
-+static __u8 inline sl811_read(struct sl811_hc *hc, __u8 offset)
-+{
-+ sl811_write_index (hc, offset);
-+ return (sl811_read_data (hc));
-+}
-+
-+/*
-+ * Write a byte of data to the SL811H/SL11H
-+ */
-+static void inline sl811_write(struct sl811_hc *hc, __u8 offset, __u8 data)
-+{
-+ sl811_write_index_data (hc, offset, data);
-+}
-+
-+/*
-+ * Read consecutive bytes of data from the SL811H/SL11H buffer
-+ */
-+static void inline sl811_read_buf(struct sl811_hc *hc, __u8 offset, __u8 *buf, __u8 size)
-+{
-+ sl811_write_index (hc, offset);
-+ while (size--) {
-+ *buf++ = sl811_read_data(hc);
-+ }
-+}
-+
-+/*
-+ * Write consecutive bytes of data to the SL811H/SL11H buffer
-+ */
-+static void inline sl811_write_buf(struct sl811_hc *hc, __u8 offset, __u8 *buf, __u8 size)
-+{
-+ sl811_write_index (hc, offset);
-+ while (size--) {
-+ sl811_write_data (hc, *buf);
-+ buf++;
-+ }
-+}
-+
-+/*
-+ * This routine test the Read/Write functionality of SL811HS registers
-+ */
-+static int sl811_reg_test(struct sl811_hc *hc)
-+{
-+ int i, data, result = 0;
-+ __u8 buf[256];
-+
-+ for (i = 0x10; i < 256; i++) {
-+ /* save the original buffer */
-+ buf[i] = sl811_read(hc, i);
-+
-+ /* Write the new data to the buffer */
-+ sl811_write(hc, i, ~i);
-+ }
-+
-+ /* compare the written data */
-+ for (i = 0x10; i < 256; i++) {
-+ data = sl811_read(hc, i);
-+ if (data != (__u8) ~i) {
-+ PDEBUG(1, "reg %02x expected %02x got %02x", i, (__u8) ~i, data);
-+ result = -1;
-+
-+ /* If no Debug, show only first failed Address */
-+ if (!debug)
-+ break;
-+ }
-+ }
-+
-+ /* restore the data */
-+ for (i = 0x10; i < 256; i++)
-+ sl811_write(hc, i, buf[i]);
-+
-+ return result;
-+}
-+
-+/*
-+ * Display all SL811HS register values
-+ */
-+#if 0 /* unused (hne) */
-+static void sl811_reg_show(struct sl811_hc *hc)
-+{
-+ int i;
-+
-+ for (i = 0; i < 256; i++)
-+ PDEBUG(4, "offset %d: 0x%x", i, sl811_read(hc, i));
-+}
-+#endif
-+
-+/*
-+ * This function enables SL811HS interrupts
-+ */
-+static void sl811_enable_interrupt(struct sl811_hc *hc)
-+{
-+ PDEBUG(4, "enter");
-+ sl811_write(hc, SL811_INTR, SL811_INTR_DONE_A | SL811_INTR_SOF | SL811_INTR_INSRMV);
-+}
-+
-+/*
-+ * This function disables SL811HS interrupts
-+ */
-+static void sl811_disable_interrupt(struct sl811_hc *hc)
-+{
-+ PDEBUG(4, "enter");
-+ // Disable all other interrupt except for insert/remove.
-+ sl811_write(hc, SL811_INTR, SL811_INTR_INSRMV);
-+}
-+
-+/*
-+ * SL811 Virtual Root Hub
-+ */
-+
-+/* Device descriptor */
-+static __u8 sl811_rh_dev_des[] =
-+{
-+ 0x12, /* __u8 bLength; */
-+ 0x01, /* __u8 bDescriptorType; Device */
-+ 0x10, /* __u16 bcdUSB; v1.1 */
-+ 0x01,
-+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
-+ 0x00, /* __u8 bDeviceSubClass; */
-+ 0x00, /* __u8 bDeviceProtocol; */
-+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
-+ 0x00, /* __u16 idVendor; */
-+ 0x00,
-+ 0x00, /* __u16 idProduct; */
-+ 0x00,
-+ 0x00, /* __u16 bcdDevice; */
-+ 0x00,
-+ 0x00, /* __u8 iManufacturer; */
-+ 0x02, /* __u8 iProduct; */
-+ 0x01, /* __u8 iSerialNumber; */
-+ 0x01 /* __u8 bNumConfigurations; */
-+};
-+
-+/* Configuration descriptor */
-+static __u8 sl811_rh_config_des[] =
-+{
-+ 0x09, /* __u8 bLength; */
-+ 0x02, /* __u8 bDescriptorType; Configuration */
-+ 0x19, /* __u16 wTotalLength; */
-+ 0x00,
-+ 0x01, /* __u8 bNumInterfaces; */
-+ 0x01, /* __u8 bConfigurationValue; */
-+ 0x00, /* __u8 iConfiguration; */
-+ 0x40, /* __u8 bmAttributes;
-+ Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup,
-+ 4..0: resvd */
-+ 0x00, /* __u8 MaxPower; */
-+
-+ /* interface */
-+ 0x09, /* __u8 if_bLength; */
-+ 0x04, /* __u8 if_bDescriptorType; Interface */
-+ 0x00, /* __u8 if_bInterfaceNumber; */
-+ 0x00, /* __u8 if_bAlternateSetting; */
-+ 0x01, /* __u8 if_bNumEndpoints; */
-+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
-+ 0x00, /* __u8 if_bInterfaceSubClass; */
-+ 0x00, /* __u8 if_bInterfaceProtocol; */
-+ 0x00, /* __u8 if_iInterface; */
-+
-+ /* endpoint */
-+ 0x07, /* __u8 ep_bLength; */
-+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
-+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
-+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
-+ 0x08, /* __u16 ep_wMaxPacketSize; */
-+ 0x00,
-+ 0xff /* __u8 ep_bInterval; 255 ms */
-+};
-+
-+/* root hub class descriptor*/
-+static __u8 sl811_rh_hub_des[] =
-+{
-+ 0x09, /* __u8 bLength; */
-+ 0x29, /* __u8 bDescriptorType; Hub-descriptor */
-+ 0x01, /* __u8 bNbrPorts; */
-+ 0x00, /* __u16 wHubCharacteristics; */
-+ 0x00,
-+ 0x50, /* __u8 bPwrOn2pwrGood; 2ms */
-+ 0x00, /* __u8 bHubContrCurrent; 0 mA */
-+ 0xfc, /* __u8 DeviceRemovable; *** 7 Ports max *** */
-+ 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
-+};
-+
-+/*
-+ * This function examine the port change in the virtual root hub. HUB INTERRUPT ENDPOINT.
-+ */
-+static int sl811_rh_send_irq(struct sl811_hc *hc, __u8 *rh_change, int rh_len)
-+{
-+ __u8 data = 0;
-+
-+ PDEBUG(5, "enter");
-+
-+ /*
-+ * Right now, It is assume the power is good and no changes and only one port.
-+ */
-+ if (hc->rh_status.wPortChange & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) {
-+ data = 1<<1;
-+ *(__u8 *)rh_change = data;
-+ return 1;
-+ } else
-+ return 0;
-+}
-+
-+/*
-+ * This function creates a timer that act as interrupt pipe in the virtual hub.
-+ *
-+ * Note: The virtual root hub's interrupt pipe are polled by the timer
-+ * every "interval" ms
-+ */
-+static void sl811_rh_init_int_timer(struct urb * urb)
-+{
-+ struct sl811_hc *hc = urb->dev->bus->hcpriv;
-+ hc->rh.interval = urb->interval;
-+
-+ init_timer(&hc->rh.rh_int_timer);
-+ hc->rh.rh_int_timer.function = sl811_rh_int_timer_do;
-+ hc->rh.rh_int_timer.data = (unsigned long)urb;
-+ hc->rh.rh_int_timer.expires = jiffies +
-+ (HZ * (urb->interval < 30? 30: urb->interval)) / 1000;
-+ add_timer (&hc->rh.rh_int_timer);
-+}
-+
-+/*
-+ * This function is called when the timer expires. It gets the the port
-+ * change data and pass along to the upper protocol.
-+ */
-+static void sl811_rh_int_timer_do(unsigned long ptr)
-+{
-+ int len;
-+ struct urb *urb = (struct urb *)ptr;
-+ struct sl811_hc *hc = urb->dev->bus->hcpriv;
-+ PDEBUG (5, "enter");
-+
-+ if(hc->rh.send) {
-+ len = sl811_rh_send_irq(hc, urb->transfer_buffer,
-+ urb->transfer_buffer_length);
-+ if (len > 0) {
-+ urb->actual_length = len;
-+ if (urb->complete)
-+ urb->complete(urb);
-+ }
-+ }
-+
-+#ifdef SL811_TIMEOUT
-+
-+{
-+ struct list_head *head, *tmp;
-+ struct sl811_urb_priv *urbp;
-+ struct urb *u;
-+ int i;
-+ static int timeout_count = 0;
-+
-+// check time out every second
-+ if (++timeout_count > 4) {
-+ int max_scan = hc->active_urbs;
-+ timeout_count = 0;
-+ for (i = 0; i < 6; ++i) {
-+ head = &hc->urb_list[i];
-+ tmp = head->next;
-+ while (tmp != head && max_scan--) {
-+ u = list_entry(tmp, struct urb, urb_list);
-+ urbp = (struct sl811_urb_priv *)u->hcpriv;
-+ tmp = tmp->next;
-+ // Check if the URB timed out
-+ if (u->timeout && time_after_eq(jiffies, urbp->inserttime + u->timeout)) {
-+ PDEBUG(3, "urb = %p time out, we kill it", urb);
-+ u->transfer_flags |= USB_TIMEOUT_KILLED;
-+ }
-+ }
-+ }
-+ }
-+}
-+
-+#endif
-+ // re-activate the timer
-+ sl811_rh_init_int_timer(urb);
-+}
-+
-+/* helper macro */
-+#define OK(x) len = (x); break
-+
-+/*
-+ * This function handles all USB request to the the virtual root hub
-+ */
-+static int sl811_rh_submit_urb(struct urb *urb)
-+{
-+ struct usb_device *usb_dev = urb->dev;
-+ struct sl811_hc *hc = usb_dev->bus->hcpriv;
-+ struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *)urb->setup_packet;
-+ void *data = urb->transfer_buffer;
-+ int buf_len = urb->transfer_buffer_length;
-+ unsigned int pipe = urb->pipe;
-+ __u8 data_buf[16];
-+ __u8 *bufp = data_buf;
-+ int len = 0;
-+ int status = 0;
-+
-+ __u16 bmRType_bReq;
-+ __u16 wValue;
-+ __u16 wIndex;
-+ __u16 wLength;
-+
-+ if (usb_pipeint(pipe)) {
-+ hc->rh.urb = urb;
-+ hc->rh.send = 1;
-+ hc->rh.interval = urb->interval;
-+ sl811_rh_init_int_timer(urb);
-+ urb->status = 0;
-+
-+ return 0;
-+ }
-+
-+ bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8);
-+ wValue = le16_to_cpu (cmd->wValue);
-+ wIndex = le16_to_cpu (cmd->wIndex);
-+ wLength = le16_to_cpu (cmd->wLength);
-+
-+ PDEBUG(5, "submit rh urb, req = %d(%x) len=%d", bmRType_bReq, bmRType_bReq, wLength);
-+
-+ /* Request Destination:
-+ without flags: Device,
-+ USB_RECIP_INTERFACE: interface,
-+ USB_RECIP_ENDPOINT: endpoint,
-+ USB_TYPE_CLASS means HUB here,
-+ USB_RECIP_OTHER | USB_TYPE_CLASS almost ever means HUB_PORT here
-+ */
-+ switch (bmRType_bReq) {
-+ case RH_GET_STATUS:
-+ *(__u16 *)bufp = cpu_to_le16(1);
-+ OK(2);
-+
-+ case RH_GET_STATUS | USB_RECIP_INTERFACE:
-+ *(__u16 *)bufp = cpu_to_le16(0);
-+ OK(2);
-+
-+ case RH_GET_STATUS | USB_RECIP_ENDPOINT:
-+ *(__u16 *)bufp = cpu_to_le16(0);
-+ OK(2);
-+
-+ case RH_GET_STATUS | USB_TYPE_CLASS:
-+ *(__u32 *)bufp = cpu_to_le32(0);
-+ OK(4);
-+
-+ case RH_GET_STATUS | USB_RECIP_OTHER | USB_TYPE_CLASS:
-+ *(__u32 *)bufp = cpu_to_le32(hc->rh_status.wPortChange<<16 | hc->rh_status.wPortStatus);
-+ OK(4);
-+
-+ case RH_CLEAR_FEATURE | USB_RECIP_ENDPOINT:
-+ switch (wValue) {
-+ case 1:
-+ OK(0);
-+ }
-+ break;
-+
-+ case RH_CLEAR_FEATURE | USB_TYPE_CLASS:
-+ switch (wValue) {
-+ case C_HUB_LOCAL_POWER:
-+ OK(0);
-+
-+ case C_HUB_OVER_CURRENT:
-+ OK(0);
-+ }
-+ break;
-+
-+ case RH_CLEAR_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
-+ switch (wValue) {
-+ case USB_PORT_FEAT_ENABLE:
-+ hc->rh_status.wPortStatus &= ~USB_PORT_STAT_ENABLE;
-+ OK(0);
-+
-+ case USB_PORT_FEAT_SUSPEND:
-+ hc->rh_status.wPortStatus &= ~USB_PORT_STAT_SUSPEND;
-+ OK(0);
-+
-+ case USB_PORT_FEAT_POWER:
-+ hc->rh_status.wPortStatus &= ~USB_PORT_STAT_POWER;
-+ OK(0);
-+
-+ case USB_PORT_FEAT_C_CONNECTION:
-+ hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_CONNECTION;
-+ OK(0);
-+
-+ case USB_PORT_FEAT_C_ENABLE:
-+ hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_ENABLE;
-+ OK(0);
-+
-+ case USB_PORT_FEAT_C_SUSPEND:
-+ hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_SUSPEND;
-+ OK(0);
-+
-+ case USB_PORT_FEAT_C_OVER_CURRENT:
-+ hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_OVERCURRENT;
-+ OK(0);
-+
-+ case USB_PORT_FEAT_C_RESET:
-+ hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_RESET;
-+ OK(0);
-+ }
-+ break;
-+
-+ case RH_SET_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
-+ switch (wValue) {
-+ case USB_PORT_FEAT_SUSPEND:
-+ hc->rh_status.wPortStatus |= USB_PORT_STAT_SUSPEND;
-+ OK(0);
-+
-+ case USB_PORT_FEAT_RESET:
-+ hc->rh_status.wPortStatus |= USB_PORT_STAT_RESET;
-+ hc->rh_status.wPortChange = 0;
-+ hc->rh_status.wPortChange |= USB_PORT_STAT_C_RESET;
-+ hc->rh_status.wPortStatus &= ~USB_PORT_STAT_RESET;
-+ hc->rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
-+ OK(0);
-+
-+ case USB_PORT_FEAT_POWER:
-+ hc->rh_status.wPortStatus |= USB_PORT_STAT_POWER;
-+ OK(0);
-+
-+ case USB_PORT_FEAT_ENABLE:
-+ hc->rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
-+ OK(0);
-+ }
-+ break;
-+
-+ case RH_SET_ADDRESS:
-+ hc->rh.devnum = wValue;
-+ OK(0);
-+
-+ case RH_GET_DESCRIPTOR:
-+ switch ((wValue & 0xff00) >> 8) {
-+ case USB_DT_DEVICE:
-+ len = sizeof(sl811_rh_dev_des);
-+ bufp = sl811_rh_dev_des;
-+ OK(len);
-+
-+ case USB_DT_CONFIG:
-+ len = sizeof(sl811_rh_config_des);
-+ bufp = sl811_rh_config_des;
-+ OK(len);
-+
-+ case USB_DT_STRING:
-+ len = usb_root_hub_string(wValue & 0xff, (int)(long)0, "SL811HS", data, wLength);
-+ if (len > 0) {
-+ bufp = data;
-+ OK(len);
-+ }
-+
-+ default:
-+ status = -EPIPE;
-+ }
-+ break;
-+
-+ case RH_GET_DESCRIPTOR | USB_TYPE_CLASS:
-+ len = sizeof(sl811_rh_hub_des);
-+ bufp = sl811_rh_hub_des;
-+ OK(len);
-+
-+ case RH_GET_CONFIGURATION:
-+ bufp[0] = 0x01;
-+ OK(1);
-+
-+ case RH_SET_CONFIGURATION:
-+ OK(0);
-+
-+ default:
-+ PDEBUG(1, "unsupported root hub command");
-+ status = -EPIPE;
-+ }
-+
-+ len = min(len, buf_len);
-+ if (data != bufp)
-+ memcpy(data, bufp, len);
-+ urb->actual_length = len;
-+ urb->status = status;
-+
-+ PDEBUG(5, "len = %d, status = %d", len, status);
-+
-+ urb->hcpriv = NULL;
-+ urb->dev = NULL;
-+ if (urb->complete)
-+ urb->complete(urb);
-+
-+ return 0;
-+}
-+
-+/*
-+ * This function unlinks the URB
-+ */
-+static int sl811_rh_unlink_urb(struct urb *urb)
-+{
-+ struct sl811_hc *hc = urb->dev->bus->hcpriv;
-+
-+ PDEBUG(5, "enter");
-+
-+ if (hc->rh.urb == urb) {
-+ hc->rh.send = 0;
-+ del_timer(&hc->rh.rh_int_timer);
-+ hc->rh.urb = NULL;
-+ urb->hcpriv = NULL;
-+ usb_dec_dev_use(urb->dev);
-+ urb->dev = NULL;
-+ if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-+ urb->status = -ECONNRESET;
-+ if (urb->complete)
-+ urb->complete(urb);
-+ } else
-+ urb->status = -ENOENT;
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * This function connect the virtual root hub to the USB stack
-+ */
-+static int sl811_connect_rh(struct sl811_hc * hc)
-+{
-+ struct usb_device *usb_dev;
-+
-+ hc->rh.devnum = 0;
-+ usb_dev = usb_alloc_dev(NULL, hc->bus);
-+ if (!usb_dev)
-+ return -ENOMEM;
-+
-+ hc->bus->root_hub = usb_dev;
-+ usb_connect(usb_dev);
-+
-+ if (usb_new_device(usb_dev)) {
-+ usb_free_dev(usb_dev);
-+ return -ENODEV;
-+ }
-+
-+ PDEBUG(5, "leave success");
-+
-+ return 0;
-+}
-+
-+/*
-+ * This function allocates private data space for the usb device
-+ */
-+static int sl811_alloc_dev_priv(struct usb_device *usb_dev)
-+{
-+ return 0;
-+}
-+
-+/*
-+ * This function de-allocates private data space for the usb devic
-+ */
-+static int sl811_free_dev_priv (struct usb_device *usb_dev)
-+{
-+ return 0;
-+}
-+
-+/*
-+ * This function allocates private data space for the urb
-+ */
-+static struct sl811_urb_priv* sl811_alloc_urb_priv(struct urb *urb)
-+{
-+ struct sl811_urb_priv *urbp;
-+
-+ urbp = kmalloc(sizeof(*urbp), GFP_KERNEL);
-+ if (!urbp)
-+ return NULL;
-+
-+ memset(urbp, 0, sizeof(*urbp));
-+
-+ INIT_LIST_HEAD(&urbp->td_list);
-+
-+ urbp->urb = urb;
-+ urb->hcpriv = urbp;
-+
-+ return urbp;
-+}
-+
-+/*
-+ * This function free private data space for the urb
-+ */
-+static void sl811_free_urb_priv(struct urb *urb)
-+{
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+ struct sl811_td *td;
-+ struct list_head *head, *tmp;
-+
-+ if (!urbp)
-+ return ;
-+
-+ head = &urbp->td_list;
-+ tmp = head->next;
-+
-+ while (tmp != head) {
-+ td = list_entry(tmp, struct sl811_td, td_list);
-+ tmp = tmp->next;
-+ kfree(td);
-+ }
-+
-+ kfree(urbp);
-+ urb->hcpriv = NULL;
-+
-+ return ;
-+}
-+
-+/*
-+ * This function calculate the bus time need by this td.
-+ * Fix me! Can this use usb_calc_bus_time()?
-+ */
-+static void sl811_calc_td_time(struct sl811_td *td)
-+{
-+#if 1
-+ int time;
-+ int len = td->len;
-+ struct sl811_hc *hc = td->urb->dev->bus->hcpriv;
-+
-+ if (hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED)
-+ time = 8*8*len + 1024;
-+ else {
-+ if (td->ctrl & SL811_USB_CTRL_PREAMBLE)
-+ time = 8*8*len + 2048;
-+ else
-+ time = 8*len + 256;
-+ }
-+
-+ time += 2*10 * len;
-+
-+ td->bustime = time;
-+
-+#else
-+
-+ unsigned long tmp;
-+ int time;
-+ int low_speed = usb_pipeslow(td->urb->pipe);
-+ int input_dir = usb_pipein(td->urb->pipe);
-+ int bytecount = td->len;
-+ int isoc = usb_pipeisoc(td->urb->pipe);
-+
-+ if (low_speed) { /* no isoc. here */
-+ if (input_dir) {
-+ tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L;
-+ time = (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
-+ } else {
-+ tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L;
-+ time = (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
-+ }
-+ } else if (!isoc){ /* for full-speed: */
-+ tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
-+ time = (9107L + BW_HOST_DELAY + tmp);
-+ } else { /* for isoc: */
-+ tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
-+ time = (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp);
-+ }
-+
-+ td->bustime = time / 84;
-+
-+#endif
-+}
-+
-+/*
-+ * This function calculate the remainder bus time in current frame.
-+ */
-+static inline int sl811_calc_bus_remainder(struct sl811_hc *hc)
-+{
-+ return (sl811_read(hc, SL811_SOFCNTDIV) * 64);
-+}
-+
-+/*
-+ * This function allocates td for the urb
-+ */
-+static struct sl811_td* sl811_alloc_td(struct urb *urb)
-+{
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+ struct sl811_td *td;
-+
-+ td = kmalloc(sizeof (*td), GFP_KERNEL);
-+ if (!td)
-+ return NULL;
-+
-+ memset(td, 0, sizeof(*td));
-+
-+ INIT_LIST_HEAD(&td->td_list);
-+
-+ td->urb = urb;
-+ list_add_tail(&td->td_list, &urbp->td_list);
-+
-+ return td;
-+}
-+
-+/*
-+ * Fill the td.
-+ */
-+static inline void sl811_fill_td(struct sl811_td *td, __u8 ctrl, __u8 addr, __u8 len, __u8 pidep, __u8 dev, __u8 *buf)
-+{
-+ td->ctrl = ctrl;
-+ td->addr = addr;
-+ td->len = len;
-+ td->pidep = pidep;
-+ td->dev = dev;
-+ td->buf = buf;
-+ td->left = len;
-+ td->errcnt = 3;
-+}
-+
-+/*
-+ * Fill the td.
-+ */
-+static inline void sl811_reset_td(struct sl811_td *td)
-+{
-+ td->status = 0;
-+ td->left = td->len;
-+ td->done = 0;
-+ td->errcnt = 3;
-+ td->nakcnt = 0;
-+ td->td_status = 0;
-+}
-+
-+static void sl811_print_td(int level, struct sl811_td *td)
-+{
-+ PDEBUG(level, "td = %p, ctrl = %x, addr = %x, len = %x, pidep = %x\n "
-+ "dev = %x, status = %x, left = %x, errcnt = %x, done = %x\n "
-+ "buf = %p, bustime = %d, td_status = %d\n",
-+ td, td->ctrl, td->addr, td->len, td->pidep,
-+ td->dev, td->status, td->left, td->errcnt, td->done,
-+ td->buf, td->bustime, td->td_status);
-+}
-+
-+/*
-+ * Isochronous transfers
-+ */
-+static int sl811_submit_isochronous(struct urb *urb)
-+{
-+ __u8 dev = usb_pipedevice(urb->pipe);
-+ __u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
-+ __u8 ctrl = 0;
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+ struct sl811_td *td = NULL;
-+ int i;
-+
-+ PDEBUG(4, "enter, urb = %p, urbp = %p", urb, urbp);
-+
-+ /* Can't have low speed bulk transfers */
-+ if (usb_pipeslow(urb->pipe)) {
-+ PDEBUG(1, "error, urb = %p, low speed device", urb);
-+ return -EINVAL;
-+ }
-+
-+ if (usb_pipeout(urb->pipe))
-+ ctrl |= SL811_USB_CTRL_DIR_OUT;
-+
-+ ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE | SL811_USB_CTRL_ISO;
-+
-+ for (i = 0; i < urb->number_of_packets; i++) {
-+ urb->iso_frame_desc[i].actual_length = 0;
-+ urb->iso_frame_desc[i].status = -EXDEV;
-+
-+ td = sl811_alloc_td(urb);
-+ if (!td)
-+ return -ENOMEM;
-+
-+ sl811_fill_td(td, ctrl, SL811_DATA_START,
-+ urb->iso_frame_desc[i].length,
-+ pidep, dev,
-+ urb->transfer_buffer + urb->iso_frame_desc[i].offset);
-+ sl811_calc_td_time(td);
-+ if (urbp->cur_td == NULL)
-+ urbp->cur_td = urbp->first_td = td;
-+ }
-+
-+ urbp->last_td = td;
-+
-+ PDEBUG(4, "leave success");
-+
-+/*
-+// for debug
-+ {
-+ struct list_head *head, *tmp;
-+ struct sl811_td *td;
-+ int i = 0;
-+ head = &urbp->td_list;
-+ tmp = head->next;
-+
-+ if (list_empty(&urbp->td_list)) {
-+ PDEBUG(1, "bug!!! td list is empty!");
-+ return -ENODEV;
-+ }
-+
-+ while (tmp != head) {
-+ ++i;
-+ td = list_entry(tmp, struct sl811_td, td_list);
-+ PDEBUG(2, "td = %p, i = %d", td, i);
-+ tmp = tmp->next;
-+ }
-+ }
-+*/
-+ return 0;
-+}
-+
-+/*
-+ * Reset isochronous transfers
-+ */
-+static void sl811_reset_isochronous(struct urb *urb)
-+{
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+ struct sl811_td *td = NULL;
-+ struct list_head *head, *tmp;
-+ int i;
-+
-+ PDEBUG(4, "enter, urb = %p", urb);
-+
-+ for (i = 0; i < urb->number_of_packets; i++) {
-+ urb->iso_frame_desc[i].actual_length = 0;
-+ urb->iso_frame_desc[i].status = -EXDEV;
-+ }
-+
-+ head = &urbp->td_list;
-+ tmp = head->next;
-+ while (tmp != head) {
-+ td = list_entry(tmp, struct sl811_td, td_list);
-+ tmp = tmp->next;
-+ sl811_reset_td(td);
-+ }
-+
-+ urbp->cur_td = urbp->first_td;
-+
-+ urb->status = -EINPROGRESS;
-+ urb->actual_length = 0;
-+ urb->error_count = 0;
-+}
-+
-+/*
-+ * Result the iso urb.
-+ */
-+static void sl811_result_isochronous(struct urb *urb)
-+{
-+ struct list_head *tmp, *head;
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+ int status = 0;
-+ struct sl811_td *td;
-+ int i;
-+
-+ PDEBUG(4, "enter, urb = %p", urb);
-+
-+ urb->actual_length = 0;
-+
-+ i = 0;
-+ head = &urbp->td_list;
-+ tmp = head->next;
-+ while (tmp != head) {
-+ td = list_entry(tmp, struct sl811_td, td_list);
-+ tmp = tmp->next;
-+
-+ if (!td->done) {
-+ if (urbp->unlink)
-+ urb->status = -ENOENT;
-+ else {
-+ PDEBUG(1, "we should not get here!");
-+ urb->status = -EXDEV;
-+ }
-+ return ;
-+ }
-+ if (td->td_status) {
-+ status = td->td_status;
-+ urb->error_count++;
-+ PDEBUG(1, "error: td = %p, td status = %d", td, td->td_status);
-+ }
-+
-+ urb->iso_frame_desc[i].actual_length = td->len - td->left;
-+ urb->actual_length += td->len - td->left;
-+ urb->iso_frame_desc[i].status = td->td_status;
-+ ++i;
-+ if (td->left)
-+ PDEBUG(3, "short packet, td = %p, len = %d, left = %d", td, td->len, td->left);
-+ }
-+
-+ urb->status = status;
-+/*
-+// for debug
-+ PDEBUG(2, "iso urb complete, len = %d, status =%d ", urb->actual_length, urb->status);
-+*/
-+ PDEBUG(4, "leave success");
-+}
-+
-+/*
-+ * Interrupt transfers
-+ */
-+static int sl811_submit_interrupt(struct urb *urb)
-+{
-+ int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-+ int len = urb->transfer_buffer_length;
-+ __u8 *data = urb->transfer_buffer;
-+ __u8 dev = usb_pipedevice(urb->pipe);
-+ __u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
-+ __u8 ctrl = 0;
-+ struct sl811_hc *hc = urb->dev->bus->hcpriv;
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+ struct sl811_td *td = NULL;
-+
-+ PDEBUG(4, "enter, urb = %p", urb);
-+
-+ if (len > maxsze) {
-+ PDEBUG(1, "length is big than max packet size, len = %d, max packet = %d", len, maxsze);
-+ return -EINVAL;
-+ }
-+ if (usb_pipeslow(urb->pipe) && !(hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED))
-+ ctrl |= SL811_USB_CTRL_PREAMBLE;
-+
-+ ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
-+ if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
-+ ctrl |= SL811_USB_CTRL_TOGGLE_1;
-+ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-+ td = sl811_alloc_td(urb);
-+ if (!td)
-+ return -ENOMEM;
-+
-+ sl811_fill_td(td, ctrl, SL811_DATA_START, len, pidep, dev, data);
-+ sl811_calc_td_time(td);
-+ urbp->cur_td = urbp->first_td = urbp->last_td = td;
-+ urbp->interval = 0;
-+
-+ PDEBUG(4, "leave success");
-+
-+ return 0;
-+}
-+
-+/*
-+ * Reset interrupt transfers
-+ */
-+static void sl811_reset_interrupt(struct urb *urb)
-+{
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+ struct sl811_td *td = urbp->cur_td;
-+
-+ PDEBUG(4, "enter, interval = %d", urb->interval);
-+
-+ td->ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
-+ if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
-+ td->ctrl |= SL811_USB_CTRL_TOGGLE_1;
-+ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-+
-+ sl811_reset_td(td);
-+
-+ urbp->interval = urb->interval;
-+
-+ urb->status = -EINPROGRESS;
-+ urb->actual_length = 0;
-+}
-+
-+/*
-+ * Result the interrupt urb.
-+ */
-+static void sl811_result_interrupt(struct urb *urb)
-+{
-+ struct list_head *tmp;
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+ struct sl811_td *td;
-+ int toggle;
-+
-+ PDEBUG(4, "enter, urb = %p", urb);
-+
-+ urb->actual_length = 0;
-+
-+ tmp = &urbp->td_list;
-+ tmp = tmp->next;
-+ td = list_entry(tmp, struct sl811_td, td_list);
-+
-+ // success.
-+ if (td->done && td->td_status == 0) {
-+ urb->actual_length += td->len - td->left;
-+ urb->status = 0;
-+ return ;
-+ }
-+ // tranfer is done but fail, reset the toggle.
-+ else if (td->done && td->td_status) {
-+ urb->status = td->td_status;
-+reset_toggle:
-+ toggle = (td->ctrl & SL811_USB_CTRL_TOGGLE_1) ? 1 : 0;
-+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), toggle);
-+ PDEBUG(3, "error: td = %p, td status = %d", td, td->td_status);
-+ return ;
-+ }
-+ // unlink, and not do transfer yet
-+ else if (td->done == 0 && urbp->unlink && td->td_status == 0) {
-+ urb->status = -ENOENT;
-+ PDEBUG(3, "unlink and not transfer!");
-+ return ;
-+ }
-+ // unlink, and transfer not complete yet.
-+ else if (td->done == 0 && urbp->unlink && td->td_status) {
-+ urb->status = -ENOENT;
-+ PDEBUG(3, "unlink and not complete!");
-+ goto reset_toggle;
-+ }
-+ // must be bug!!!
-+ else {// (td->done == 0 && urbp->unlink == 0)
-+ PDEBUG(1, "we should not get here!");
-+ urb->status = -EPIPE;
-+ return ;
-+ }
-+}
-+
-+/*
-+ * Control transfers
-+ */
-+static int sl811_submit_control(struct urb *urb)
-+{
-+ int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-+ int len = urb->transfer_buffer_length;
-+ __u8 *data = urb->transfer_buffer;
-+ __u8 dev = usb_pipedevice(urb->pipe);
-+ __u8 pidep = 0;
-+ __u8 ctrl = 0;
-+ struct sl811_hc *hc = urb->dev->bus->hcpriv;
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+ struct sl811_td *td = NULL;
-+
-+ PDEBUG(4, "enter, urb = %p", urb);
-+
-+ if (usb_pipeslow(urb->pipe) && !(hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED))
-+ ctrl |= SL811_USB_CTRL_PREAMBLE;
-+
-+ /* Build SETUP TD */
-+ pidep = PIDEP(USB_PID_SETUP, usb_pipeendpoint(urb->pipe));
-+ ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE | SL811_USB_CTRL_DIR_OUT;
-+ td = sl811_alloc_td(urb);
-+ if (!td)
-+ return -ENOMEM;
-+
-+ sl811_fill_td(td, ctrl, SL811_DATA_START, 8, pidep, dev, urb->setup_packet);
-+ sl811_calc_td_time(td);
-+
-+ urbp->cur_td = urbp->first_td = td;
-+
-+ /*
-+ * If direction is "send", change the frame from SETUP (0x2D)
-+ * to OUT (0xE1). Else change it from SETUP to IN (0x69).
-+ */
-+ pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
-+ if (usb_pipeout(urb->pipe))
-+ ctrl |= SL811_USB_CTRL_DIR_OUT;
-+ else
-+ ctrl &= ~SL811_USB_CTRL_DIR_OUT;
-+
-+ /* Build the DATA TD's */
-+ while (len > 0) {
-+ int pktsze = len;
-+
-+ if (pktsze > maxsze)
-+ pktsze = maxsze;
-+
-+ /* Alternate Data0/1 (start with Data1) */
-+ ctrl ^= SL811_USB_CTRL_TOGGLE_1;
-+
-+ td = sl811_alloc_td(urb);
-+ if (!td)
-+ return -ENOMEM;
-+
-+ sl811_fill_td(td, ctrl, SL811_DATA_START, pktsze, pidep, dev, data);
-+ sl811_calc_td_time(td);
-+
-+ data += pktsze;
-+ len -= pktsze;
-+ }
-+
-+ /* Build the final TD for control status */
-+ td = sl811_alloc_td(urb);
-+ if (!td)
-+ return -ENOMEM;
-+
-+ /* It's IN if the pipe is an output pipe or we're not expecting data back */
-+ if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length) {
-+ pidep = PIDEP(USB_PID_IN, usb_pipeendpoint(urb->pipe));
-+ ctrl &= ~SL811_USB_CTRL_DIR_OUT;
-+ } else {
-+ pidep = PIDEP(USB_PID_OUT, usb_pipeendpoint(urb->pipe));
-+ ctrl |= SL811_USB_CTRL_DIR_OUT;
-+ }
-+
-+ /* End in Data1 */
-+ ctrl |= SL811_USB_CTRL_TOGGLE_1;
-+
-+ sl811_fill_td(td, ctrl, SL811_DATA_START, 0, pidep, dev, 0);
-+ sl811_calc_td_time(td);
-+ urbp->last_td = td;
-+/*
-+// for debug
-+ {
-+ struct list_head *head, *tmp;
-+ struct sl811_td *td;
-+ int i = 0;
-+ head = &urbp->td_list;
-+ tmp = head->next;
-+
-+ if (list_empty(&urbp->td_list)) {
-+ PDEBUG(1, "bug!!! td list is empty!");
-+ return -ENODEV;
-+ }
-+
-+ while (tmp != head) {
-+ ++i;
-+ td = list_entry(tmp, struct sl811_td, td_list);
-+ PDEBUG(3, "td = %p, i = %d", td, i);
-+ tmp = tmp->next;
-+ }
-+ }
-+*/
-+ PDEBUG(4, "leave success");
-+
-+ return 0;
-+}
-+
-+/*
-+ * Result the control urb.
-+ */
-+static void sl811_result_control(struct urb *urb)
-+{
-+ struct list_head *tmp, *head;
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+ struct sl811_td *td;
-+
-+ PDEBUG(4, "enter, urb = %p", urb);
-+
-+ if (list_empty(&urbp->td_list)) {
-+ PDEBUG(1, "td list is empty");
-+ return ;
-+ }
-+
-+ head = &urbp->td_list;
-+
-+ tmp = head->next;
-+ td = list_entry(tmp, struct sl811_td, td_list);
-+
-+ /* The first TD is the SETUP phase, check the status, but skip the count */
-+ if (!td->done) {
-+ PDEBUG(3, "setup phase error, td = %p, done = %d", td, td->done);
-+ goto err_done;
-+ }
-+ if (td->td_status) {
-+ PDEBUG(3, "setup phase error, td = %p, td status = %d", td, td->td_status);
-+ goto err_status;
-+ }
-+
-+ urb->actual_length = 0;
-+
-+ /* The rest of the TD's (but the last) are data */
-+ tmp = tmp->next;
-+ while (tmp != head && tmp->next != head) {
-+ td = list_entry(tmp, struct sl811_td, td_list);
-+ tmp = tmp->next;
-+ if (!td->done) {
-+ PDEBUG(3, "data phase error, td = %p, done = %d", td, td->done);
-+ goto err_done;
-+ }
-+ if (td->td_status) {
-+ PDEBUG(3, "data phase error, td = %p, td status = %d", td, td->td_status);
-+ goto err_status;
-+ }
-+
-+ urb->actual_length += td->len - td->left;
-+ // short packet.
-+ if (td->left) {
-+ PDEBUG(3, "data phase short packet, td = %p, count = %d", td, td->len - td->left);
-+ break;
-+ }
-+ }
-+
-+ /* The last td is status phase */
-+ td = urbp->last_td;
-+ if (!td->done) {
-+ PDEBUG(3, "status phase error, td = %p, done = %d", td, td->done);
-+ goto err_done;
-+ }
-+ if (td->td_status) {
-+ PDEBUG(3, "status phase error, td = %p, td status = %d", td, td->td_status);
-+ goto err_status;
-+ }
-+
-+ PDEBUG(4, "leave success");
-+
-+ urb->status = 0;
-+ return ;
-+
-+err_done:
-+ if (urbp->unlink)
-+ urb->status = -ENOENT;
-+ else {
-+ PDEBUG(1, "we should not get here! td = %p", td);
-+ urb->status = -EPIPE;
-+ }
-+ return ;
-+
-+err_status:
-+ urb->status = td->td_status;
-+ return ;
-+}
-+
-+/*
-+ * Bulk transfers
-+ */
-+static int sl811_submit_bulk(struct urb *urb)
-+{
-+ int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-+ int len = urb->transfer_buffer_length;
-+ __u8 *data = urb->transfer_buffer;
-+ __u8 dev = usb_pipedevice(urb->pipe);
-+ __u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
-+ __u8 ctrl = 0;
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+ struct sl811_td *td = NULL;
-+
-+ PDEBUG(4, "enter, urb = %p", urb);
-+
-+ if (len < 0) {
-+ PDEBUG(1, "error, urb = %p, len = %d", urb, len);
-+ return -EINVAL;
-+ }
-+
-+ /* Can't have low speed bulk transfers */
-+ if (usb_pipeslow(urb->pipe)) {
-+ PDEBUG(1, "error, urb = %p, low speed device", urb);
-+ return -EINVAL;
-+ }
-+
-+ if (usb_pipeout(urb->pipe))
-+ ctrl |= SL811_USB_CTRL_DIR_OUT;
-+
-+ ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
-+
-+ /* Build the DATA TD's */
-+ do { /* Allow zero length packets */
-+ int pktsze = len;
-+
-+ if (pktsze > maxsze)
-+ pktsze = maxsze;
-+
-+ td = sl811_alloc_td(urb);
-+ if (!td)
-+ return -ENOMEM;
-+
-+ /* Alternate Data0/1 (start with Data1) */
-+ ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
-+ if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
-+ ctrl |= SL811_USB_CTRL_TOGGLE_1;
-+ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-+
-+ sl811_fill_td(td, ctrl, SL811_DATA_START, pktsze, pidep, dev, data);
-+ sl811_calc_td_time(td);
-+
-+ if (urbp->cur_td == NULL)
-+ urbp->cur_td = urbp->first_td = td;
-+
-+ data += pktsze;
-+ len -= maxsze;
-+ } while (len > 0);
-+
-+ /*
-+ * USB_ZERO_PACKET means adding a 0-length packet, if
-+ * direction is OUT and the transfer_length was an
-+ * exact multiple of maxsze, hence
-+ * (len = transfer_length - N * maxsze) == 0
-+ * however, if transfer_length == 0, the zero packet
-+ * was already prepared above.
-+ */
-+ if (usb_pipeout(urb->pipe) && (urb->transfer_flags & USB_ZERO_PACKET) &&
-+ !len && urb->transfer_buffer_length) {
-+
-+ td = sl811_alloc_td(urb);
-+ if (!td)
-+ return -ENOMEM;
-+
-+ /* Alternate Data0/1 (start with Data1) */
-+ ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
-+ if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
-+ ctrl |= SL811_USB_CTRL_TOGGLE_1;
-+ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-+
-+ sl811_fill_td(td, ctrl, SL811_DATA_START, 0, pidep, dev, 0);
-+ sl811_calc_td_time(td);
-+ }
-+
-+ urbp->last_td = td;
-+
-+ PDEBUG(4, "leave success");
-+
-+ return 0;
-+}
-+
-+/*
-+ * Reset bulk transfers
-+ */
-+static int sl811_reset_bulk(struct urb *urb)
-+{
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+ struct sl811_td *td;
-+ struct list_head *head, *tmp;
-+
-+ PDEBUG(4, "enter, urb = %p", urb);
-+
-+
-+ head = &urbp->td_list;
-+ tmp = head->next;
-+
-+ while (tmp != head) {
-+ td = list_entry(tmp, struct sl811_td, td_list);
-+
-+ /* Alternate Data0/1 (start with Data1) */
-+ td->ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
-+ if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
-+ td->ctrl |= SL811_USB_CTRL_TOGGLE_1;
-+ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-+
-+ sl811_reset_td(td);
-+ }
-+
-+ urb->status = -EINPROGRESS;
-+ urb->actual_length = 0;
-+ urbp->cur_td = urbp->first_td;
-+
-+ PDEBUG(4, "leave success");
-+
-+ return 0;
-+}
-+
-+/*
-+ * Result the bulk urb.
-+ */
-+static void sl811_result_bulk(struct urb *urb)
-+{
-+ struct list_head *tmp, *head;
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+ struct sl811_td *td = NULL;
-+ int toggle;
-+
-+ PDEBUG(4, "enter, urb = %p", urb);
-+
-+ urb->actual_length = 0;
-+
-+ head = &urbp->td_list;
-+ tmp = head->next;
-+ while (tmp != head) {
-+ td = list_entry(tmp, struct sl811_td, td_list);
-+ tmp = tmp->next;
-+
-+ // success.
-+ if (td->done && td->td_status == 0) {
-+ urb->actual_length += td->len - td->left;
-+
-+ // short packet
-+ if (td->left) {
-+ urb->status = 0;
-+ PDEBUG(3, "short packet, td = %p, count = %d", td, td->len - td->left);
-+ goto reset_toggle;
-+ }
-+ }
-+ // tranfer is done but fail, reset the toggle.
-+ else if (td->done && td->td_status) {
-+ urb->status = td->td_status;
-+ PDEBUG(3, "error: td = %p, td status = %d", td, td->td_status);
-+ goto reset_toggle;
-+ }
-+ // unlink, and not do transfer yet
-+ else if (td->done == 0 && urbp->unlink && td->td_status == 0) {
-+ urb->status = -ENOENT;
-+ PDEBUG(3, "unlink and not transfer!");
-+ return ;
-+ }
-+ // unlink, and transfer not complete yet.
-+ else if (td->done == 0 && urbp->unlink && td->td_status) {
-+ PDEBUG(3, "unlink and not complete!");
-+ urb->status = -ENOENT;
-+ goto reset_toggle;
-+ }
-+ // must be bug!!!
-+ else {// (td->done == 0 && urbp->unlink == 0)
-+ urb->status = -EPIPE;
-+ PDEBUG(1, "we should not get here!");
-+ return ;
-+ }
-+ }
-+
-+ PDEBUG(4, "leave success");
-+ urb->status = 0;
-+ return ;
-+
-+reset_toggle:
-+ toggle = (td->ctrl & SL811_USB_CTRL_TOGGLE_1) ? 1 : 0;
-+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), toggle);
-+}
-+
-+/*
-+ * Find the first urb have the same dev and endpoint.
-+ */
-+static inline int sl811_find_same_urb(struct list_head *head, struct urb *urb)
-+{
-+ struct list_head *tmp;
-+ struct urb *u;
-+
-+ if (!head || !urb)
-+ return 0;
-+
-+ tmp = head->next;
-+
-+ while (tmp != head) {
-+ u = list_entry(tmp, struct urb, urb_list);
-+ if (u == urb)
-+ return 1;
-+ tmp = tmp->next;
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * Find the first urb have the same dev and endpoint.
-+ */
-+static inline struct urb* sl811_find_same_devep(struct list_head *head, struct urb *urb)
-+{
-+ struct list_head *tmp;
-+ struct urb *u;
-+
-+ if (!head || !urb)
-+ return NULL;
-+
-+ tmp = head->next;
-+
-+ while (tmp != head) {
-+ u = list_entry(tmp, struct urb, urb_list);
-+ if ((usb_pipe_endpdev(u->pipe)) == (usb_pipe_endpdev(urb->pipe)))
-+ return u;
-+ tmp = tmp->next;
-+ }
-+
-+ return NULL;
-+}
-+
-+/*
-+ * This function is called by the USB core API when an URB is available to
-+ * process.
-+ */
-+static int sl811_submit_urb(struct urb *urb)
-+{
-+ struct sl811_hc *hc = urb->dev->bus->hcpriv;
-+ unsigned int pipe = urb->pipe;
-+ struct list_head *head = NULL;
-+ unsigned long flags;
-+ int bustime;
-+ int ret = 0;
-+
-+ if (!urb) {
-+ PDEBUG(1, "urb is null");
-+ return -EINVAL;
-+ }
-+
-+ if (urb->hcpriv) {
-+ PDEBUG(1, "urbp is not null, urb = %p, urbp = %p", urb, urb->hcpriv);
-+ return -EINVAL;
-+ }
-+
-+ if (!urb->dev || !urb->dev->bus || !hc) {
-+ PDEBUG(1, "dev or bus or hc is null");
-+ return -ENODEV;
-+ }
-+
-+ if (usb_endpoint_halted(urb->dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
-+ PDEBUG(2, "sl811_submit_urb: endpoint_halted");
-+ return -EPIPE;
-+ }
-+
-+ if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) > SL811_DATA_LIMIT) {
-+ printk(KERN_ERR "Packet size is big for SL811, should < %d!\n", SL811_DATA_LIMIT);
-+ return -EINVAL;
-+ }
-+
-+ /* a request to the virtual root hub */
-+ if (usb_pipedevice(pipe) == hc->rh.devnum)
-+ return sl811_rh_submit_urb(urb);
-+
-+ spin_lock_irqsave(&hc->hc_lock, flags);
-+ spin_lock(&urb->lock);
-+
-+ switch (usb_pipetype(urb->pipe)) {
-+ case PIPE_ISOCHRONOUS:
-+ head = &hc->iso_list;
-+ break;
-+ case PIPE_INTERRUPT:
-+ head = &hc->intr_list;
-+ break;
-+ case PIPE_CONTROL:
-+ head = &hc->ctrl_list;
-+ break;
-+ case PIPE_BULK:
-+ head = &hc->bulk_list;
-+ break;
-+ }
-+
-+ if (sl811_find_same_devep(head, urb)) {
-+ list_add(&urb->urb_list, &hc->wait_list);
-+ PDEBUG(4, "add to wait list");
-+ goto out_unlock;
-+ }
-+
-+ if (!sl811_alloc_urb_priv(urb)) {
-+ ret = -ENOMEM;
-+ goto out_unlock;
-+ }
-+
-+ switch (usb_pipetype(urb->pipe)) {
-+ case PIPE_ISOCHRONOUS:
-+ if (urb->number_of_packets <= 0) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+ bustime = usb_check_bandwidth(urb->dev, urb);
-+ if (bustime < 0) {
-+ ret = bustime;
-+ break;
-+ }
-+ if (!(ret = sl811_submit_isochronous(urb)))
-+ usb_claim_bandwidth(urb->dev, urb, bustime, 1);
-+ break;
-+ case PIPE_INTERRUPT:
-+ bustime = usb_check_bandwidth(urb->dev, urb);
-+ if (bustime < 0)
-+ ret = bustime;
-+ else if (!(ret = sl811_submit_interrupt(urb)))
-+ usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-+ break;
-+ case PIPE_CONTROL:
-+ ret = sl811_submit_control(urb);
-+ break;
-+ case PIPE_BULK:
-+ ret = sl811_submit_bulk(urb);
-+ break;
-+ }
-+
-+ if (!ret) {
-+ ((struct sl811_urb_priv *)urb->hcpriv)->inserttime = jiffies;
-+ list_add(&urb->urb_list, head);
-+ PDEBUG(4, "add to type list");
-+ urb->status = -EINPROGRESS;
-+ if (++hc->active_urbs == 1)
-+ sl811_enable_interrupt(hc);
-+ goto out_unlock;
-+ } else {
-+ PDEBUG(2, "submit urb fail! error = %d", ret);
-+ sl811_free_urb_priv(urb);
-+ }
-+
-+out_unlock:
-+ spin_unlock(&urb->lock);
-+ spin_unlock_irqrestore(&hc->hc_lock, flags);
-+
-+ return ret;
-+}
-+
-+/*
-+ * Submit the urb the wait list.
-+ */
-+static int sl811_submit_urb_with_lock(struct urb *urb)
-+{
-+ struct sl811_hc *hc = urb->dev->bus->hcpriv;
-+ struct list_head *head = NULL;
-+ int bustime;
-+ int ret = 0;
-+
-+ spin_lock(&urb->lock);
-+
-+ switch (usb_pipetype(urb->pipe)) {
-+ case PIPE_ISOCHRONOUS:
-+ head = &hc->iso_list;
-+ break;
-+ case PIPE_INTERRUPT:
-+ head = &hc->intr_list;
-+ break;
-+ case PIPE_CONTROL:
-+ head = &hc->ctrl_list;
-+ break;
-+ case PIPE_BULK:
-+ head = &hc->bulk_list;
-+ break;
-+ }
-+
-+ if (!sl811_alloc_urb_priv(urb)) {
-+ ret = -ENOMEM;
-+ goto out_unlock;
-+ }
-+
-+ switch (usb_pipetype(urb->pipe)) {
-+ case PIPE_ISOCHRONOUS:
-+ if (urb->number_of_packets <= 0) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+ bustime = usb_check_bandwidth(urb->dev, urb);
-+ if (bustime < 0) {
-+ ret = bustime;
-+ break;
-+ }
-+ if (!(ret = sl811_submit_isochronous(urb)))
-+ usb_claim_bandwidth(urb->dev, urb, bustime, 1);
-+ break;
-+ case PIPE_INTERRUPT:
-+ bustime = usb_check_bandwidth(urb->dev, urb);
-+ if (bustime < 0)
-+ ret = bustime;
-+ else if (!(ret = sl811_submit_interrupt(urb)))
-+ usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-+ break;
-+ case PIPE_CONTROL:
-+ ret = sl811_submit_control(urb);
-+ break;
-+ case PIPE_BULK:
-+ ret = sl811_submit_bulk(urb);
-+ break;
-+ }
-+
-+ if (ret == 0) {
-+ ((struct sl811_urb_priv *)urb->hcpriv)->inserttime = jiffies;
-+ list_add(&urb->urb_list, head);
-+ PDEBUG(4, "add to type list");
-+ urb->status = -EINPROGRESS;
-+ if (++hc->active_urbs == 1)
-+ sl811_enable_interrupt(hc);
-+ goto out_unlock;
-+ } else {
-+ PDEBUG(2, "submit urb fail! error = %d", ret);
-+ sl811_free_urb_priv(urb);
-+ }
-+
-+out_unlock:
-+ spin_unlock(&urb->lock);
-+
-+ return ret;
-+}
-+
-+/*
-+ * Reset the urb
-+ */
-+static void sl811_reset_urb(struct urb *urb)
-+{
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+
-+ switch (usb_pipetype(urb->pipe)) {
-+ case PIPE_ISOCHRONOUS:
-+ sl811_reset_isochronous(urb);
-+ break;
-+ case PIPE_INTERRUPT:
-+ sl811_reset_interrupt(urb);
-+ break;
-+ case PIPE_CONTROL:
-+ return;
-+ case PIPE_BULK:
-+ sl811_reset_bulk(urb);
-+ break;
-+ }
-+ urbp->inserttime = jiffies;
-+}
-+
-+/*
-+ * Return the result of a transfer
-+ */
-+static void sl811_result_urb(struct urb *urb)
-+{
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+ struct sl811_hc *hc = urb->dev->bus->hcpriv;
-+ struct list_head *head = NULL;
-+ struct urb *u = NULL;
-+ int reset = 0;
-+ int ring = 0;
-+
-+ if (urb->status != -EINPROGRESS) {
-+ PDEBUG(1, "urb status is not EINPROGRESS!");
-+ return ;
-+ }
-+
-+ spin_lock(&urb->lock);
-+
-+ switch (usb_pipetype(urb->pipe)) {
-+ case PIPE_ISOCHRONOUS:
-+ head = &hc->iso_list;
-+ sl811_result_isochronous(urb);
-+
-+ // if the urb is not unlink and is in a urb "ring", we reset it
-+ if (!urbp->unlink && urb->next)
-+ ring = 1;
-+ break;
-+ case PIPE_INTERRUPT:
-+ head = &hc->intr_list;
-+ sl811_result_interrupt(urb);
-+
-+ // if the urb is not unlink and not "once" query, we reset.
-+ if (!urbp->unlink && urb->interval)
-+ reset = 1;
-+ break;
-+ case PIPE_CONTROL:
-+ head = &hc->ctrl_list;
-+ sl811_result_control(urb);
-+ break;
-+ case PIPE_BULK:
-+ head = &hc->bulk_list;
-+ sl811_result_bulk(urb);
-+
-+ // if the urb is not unlink and is in a urb "ring", we reset it
-+ if (!urbp->unlink && urb->next)
-+ ring = 1;
-+ break;
-+ }
-+
-+ PDEBUG(4, "result urb status = %d", urb->status);
-+
-+ if (ring && urb->next == urb)
-+ reset = 1;
-+
-+ if (!reset) {
-+ switch (usb_pipetype(urb->pipe)) {
-+ case PIPE_ISOCHRONOUS:
-+ usb_release_bandwidth(urb->dev, urb, 1);
-+ break;
-+ case PIPE_INTERRUPT:
-+ usb_release_bandwidth(urb->dev, urb, 0);
-+ break;
-+ }
-+ sl811_free_urb_priv(urb);
-+ }
-+
-+ spin_unlock(&urb->lock);
-+
-+ if (urb->complete)
-+ urb->complete(urb);
-+
-+ if (reset) {
-+ spin_lock(&urb->lock);
-+ sl811_reset_urb(urb);
-+ if (usb_pipeint(urb->pipe))
-+ list_add(&urb->urb_list, &hc->idle_intr_list);
-+ else
-+ list_add(&urb->urb_list, head);
-+ spin_unlock(&urb->lock);
-+ } else {
-+ if (--hc->active_urbs <= 0) {
-+ hc->active_urbs = 0;
-+ sl811_disable_interrupt(hc);
-+ }
-+
-+ if (ring)
-+ u = urb->next;
-+ else
-+ u = sl811_find_same_devep(&hc->wait_list, urb);
-+
-+ if (u) {
-+ if (!list_empty(&u->urb_list))
-+ list_del(&u->urb_list);
-+ if (sl811_submit_urb_with_lock(u))
-+ list_add(&u->urb_list, &hc->wait_list);
-+ }
-+ }
-+}
-+
-+
-+#ifdef SL811_TIMEOUT
-+
-+/*
-+ * Unlink the urb from the urb list
-+ */
-+static int sl811_unlink_urb(struct urb *urb)
-+{
-+ unsigned long flags;
-+ struct sl811_hc *hc;
-+ struct sl811_urb_priv *urbp;
-+ int call = 0;
-+ int schedule = 0;
-+ int count = 0;
-+
-+ if (!urb) {
-+ PDEBUG(1, "urb is null");
-+ return -EINVAL;
-+ }
-+
-+ if (!urb->dev || !urb->dev->bus) {
-+ PDEBUG(1, "dev or bus is null");
-+ return -ENODEV;
-+ }
-+
-+ hc = urb->dev->bus->hcpriv;
-+ urbp = urb->hcpriv;
-+
-+ /* a request to the virtual root hub */
-+ if (usb_pipedevice(urb->pipe) == hc->rh.devnum)
-+ return sl811_rh_unlink_urb(urb);
-+
-+ spin_lock_irqsave(&hc->hc_lock, flags);
-+ spin_lock(&urb->lock);
-+
-+ // in wait list
-+ if (sl811_find_same_urb(&hc->wait_list, urb)) {
-+ PDEBUG(4, "unlink urb in wait list");
-+ list_del_init(&urb->urb_list);
-+ urb->status = -ENOENT;
-+ call = 1;
-+ goto out;
-+ }
-+
-+ // in intr idle list.
-+ if (sl811_find_same_urb(&hc->idle_intr_list, urb)) {
-+ PDEBUG(4, "unlink urb in idle intr list");
-+ list_del_init(&urb->urb_list);
-+ urb->status = -ENOENT;
-+ sl811_free_urb_priv(urb);
-+ usb_release_bandwidth(urb->dev, urb, 0);
-+ if (--hc->active_urbs <= 0) {
-+ hc->active_urbs = 0;
-+ sl811_disable_interrupt(hc);
-+ }
-+ call = 1;
-+ goto out;
-+ }
-+
-+ if (urb->status == -EINPROGRESS) {
-+ PDEBUG(3, "urb is still in progress");
-+ urbp->unlink = 1;
-+
-+re_unlink:
-+ // Is it in progress?
-+ urbp = urb->hcpriv;
-+ if (urbp && hc->cur_td == urbp->cur_td) {
-+ ++count;
-+ if (sl811_read(hc, 0) & SL811_USB_CTRL_ARM) {
-+ PDEBUG(3, "unlink: cur td is still in progress! count = %d", count);
-+re_schedule:
-+ schedule = 1;
-+ spin_unlock(&urb->lock);
-+ spin_unlock_irqrestore(&hc->hc_lock, flags);
-+ schedule_timeout(HZ/50);
-+ spin_lock_irqsave(&hc->hc_lock, flags);
-+ spin_lock(&urb->lock);
-+ } else {
-+ PDEBUG(3, "unlink: lost of interrupt? do parse! count = %d", count);
-+ spin_unlock(&urb->lock);
-+ sl811_transfer_done(hc, 0);
-+ spin_lock(&urb->lock);
-+ }
-+ goto re_unlink;
-+ }
-+
-+ if (list_empty(&urb->urb_list)) {
-+ PDEBUG(3, "unlink: list empty!");
-+ goto out;
-+ }
-+
-+ if (urb->transfer_flags & USB_TIMEOUT_KILLED) {
-+ PDEBUG(3, "unlink: time out killed");
-+ // it is timeout killed by us
-+ goto result;
-+ } else if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-+ // we do nothing, just let it be processing later
-+ PDEBUG(3, "unlink async, do nothing");
-+ goto out;
-+ } else {
-+ // synchron without callback
-+ PDEBUG(3, "unlink synchron, we wait the urb complete or timeout");
-+ if (schedule == 0) {
-+ PDEBUG(3, "goto re_schedule");
-+ goto re_schedule;
-+ } else {
-+ PDEBUG(3, "already scheduled");
-+ goto result;
-+ }
-+ }
-+ } else if (!list_empty(&urb->urb_list)) {
-+ PDEBUG(1, "urb = %p, status = %d is in a list, why?", urb, urb->status);
-+ //list_del_init(&urb->urb_list);
-+ //call = 1;
-+ }
-+
-+out:
-+ spin_unlock(&urb->lock);
-+ spin_unlock_irqrestore(&hc->hc_lock, flags);
-+
-+ if (call && urb->complete)
-+ urb->complete(urb);
-+
-+ return 0;
-+
-+result:
-+ spin_unlock(&urb->lock);
-+
-+ list_del_init(&urb->urb_list);
-+ sl811_result_urb(urb);
-+
-+ spin_unlock_irqrestore(&hc->hc_lock, flags);
-+
-+ return 0;
-+}
-+
-+#else
-+
-+/*
-+ * Unlink the urb from the urb list
-+ */
-+static int sl811_unlink_urb(struct urb *urb)
-+{
-+ unsigned long flags;
-+ struct sl811_hc *hc;
-+ struct sl811_urb_priv *urbp;
-+ int call = 0;
-+
-+ if (!urb) {
-+ PDEBUG(1, "urb is null");
-+ return -EINVAL;
-+ }
-+
-+ if (!urb->dev || !urb->dev->bus) {
-+ PDEBUG(1, "dev or bus is null");
-+ return -ENODEV;
-+ }
-+
-+ hc = urb->dev->bus->hcpriv;
-+ urbp = urb->hcpriv;
-+
-+ /* a request to the virtual root hub */
-+ if (usb_pipedevice(urb->pipe) == hc->rh.devnum)
-+ return sl811_rh_unlink_urb(urb);
-+
-+ spin_lock_irqsave(&hc->hc_lock, flags);
-+ spin_lock(&urb->lock);
-+
-+ // in wait list
-+ if (sl811_find_same_urb(&hc->wait_list, urb)) {
-+ PDEBUG(2, "unlink urb in wait list");
-+ list_del_init(&urb->urb_list);
-+ urb->status = -ENOENT;
-+ call = 1;
-+ goto out;
-+ }
-+
-+ if (urb->status == -EINPROGRESS) {
-+ PDEBUG(2, "urb is still in progress");
-+ urbp->unlink = 1;
-+
-+ // Is it in progress?
-+ urbp = urb->hcpriv;
-+ if (urbp && hc->cur_td == urbp->cur_td) {
-+ // simple, let it out
-+ PDEBUG(2, "unlink: cur td is still in progress!");
-+ hc->cur_td = NULL;
-+ }
-+
-+ goto result;
-+ } else if (!list_empty(&urb->urb_list)) {
-+ PDEBUG(1, "urb = %p, status = %d is in a list, why?", urb, urb->status);
-+ list_del_init(&urb->urb_list);
-+ if (urbp)
-+ goto result;
-+ else
-+ call = 1;
-+ }
-+
-+out:
-+ spin_unlock(&urb->lock);
-+ spin_unlock_irqrestore(&hc->hc_lock, flags);
-+
-+ if (call && urb->complete)
-+ urb->complete(urb);
-+
-+ return 0;
-+
-+result:
-+ spin_unlock(&urb->lock);
-+
-+ list_del_init(&urb->urb_list);
-+ sl811_result_urb(urb);
-+
-+ spin_unlock_irqrestore(&hc->hc_lock, flags);
-+
-+ return 0;
-+}
-+
-+#endif
-+
-+static int sl811_get_current_frame_number(struct usb_device *usb_dev)
-+{
-+ return ((struct sl811_hc *)(usb_dev->bus->hcpriv))->frame_number;
-+}
-+
-+static struct usb_operations sl811_device_operations =
-+{
-+ sl811_alloc_dev_priv,
-+ sl811_free_dev_priv,
-+ sl811_get_current_frame_number,
-+ sl811_submit_urb,
-+ sl811_unlink_urb
-+};
-+
-+/*
-+ * This functions transmit a td.
-+ */
-+static inline void sl811_trans_cur_td(struct sl811_hc *hc, struct sl811_td *td)
-+{
-+ sl811_print_td(4, td);
-+ sl811_write_buf(hc, SL811_ADDR_A, &td->addr, 4);
-+ if (td->len && (td->ctrl & SL811_USB_CTRL_DIR_OUT))
-+ sl811_write_buf(hc, td->addr, td->buf, td->len);
-+
-+ sl811_write(hc, SL811_CTRL_A, td->ctrl);
-+}
-+
-+
-+/*
-+ * This function checks the status of the transmitted or received packet
-+ * and copy the data from the SL811HS register into a buffer.
-+ */
-+static void sl811_parse_cur_td(struct sl811_hc *hc, struct sl811_td *td)
-+{
-+ struct urb *urb = td->urb;
-+#ifdef SL811_DEBUG
-+ int dev = usb_pipedevice(td->urb->pipe);
-+ int ep = usb_pipeendpoint(td->urb->pipe);
-+#endif
-+
-+ sl811_read_buf(hc, SL811_STS_A, &td->status, 2);
-+
-+ if (td->status & SL811_USB_STS_ACK) {
-+ td->done = 1;
-+
-+/* if ((td->ctrl & SL811_USB_CTRL_TOGGLE_1) != (td->status & SL811_USB_STS_TOGGLE_1)) {
-+ PDEBUG(2, "dev %d endpoint %d unexpect data toggle!", dev, ep);
-+ td->td_status = -EILSEQ;
-+ }
-+*/
-+ if (!(td->ctrl & SL811_USB_CTRL_DIR_OUT) && td->len > 0)
-+ sl811_read_buf(hc, td->addr, td->buf, td->len - td->left);
-+
-+ if (td->left && (urb->transfer_flags & USB_DISABLE_SPD)) {
-+ PDEBUG(2, "dev %d endpoint %d unexpect short packet! td = %p", dev, ep, td);
-+ td->td_status = -EREMOTEIO;
-+ } else
-+ td->td_status = 0;
-+ } else if (td->status & SL811_USB_STS_STALL) {
-+ PDEBUG(2, "dev %d endpoint %d halt, td = %p", dev, ep, td);
-+ td->td_status = -EPIPE;
-+ if (urb->dev)
-+ usb_endpoint_halt(td->urb->dev, usb_pipeendpoint(td->urb->pipe), usb_pipeout(td->urb->pipe));
-+ td->done = 1;
-+ } else if (td->status & SL811_USB_STS_OVERFLOW) {
-+ PDEBUG(1, "dev %d endpoint %d overflow, sl811 only support packet less than %d", dev, ep, SL811_DATA_LIMIT);
-+ td->td_status = -EOVERFLOW;
-+ td->done = 1;
-+ } else if (td->status & SL811_USB_STS_TIMEOUT ) {
-+ PDEBUG(2, "dev %d endpoint %d timeout, td = %p", dev, ep, td);
-+ td->td_status = -ETIMEDOUT;
-+ if (--td->errcnt == 0)
-+ td->done = 1;
-+ } else if (td->status & SL811_USB_STS_ERROR) {
-+ PDEBUG(2, "dev %d endpoint %d error, td = %p", dev, ep, td);
-+ td->td_status = -EILSEQ;
-+ if (--td->errcnt == 0)
-+ td->done = 1;
-+ } else if (td->status & SL811_USB_STS_NAK) {
-+ ++td->nakcnt;
-+ PDEBUG(3, "dev %d endpoint %d nak, td = %p, count = %d", dev, ep, td, td->nakcnt);
-+ td->td_status = -EINPROGRESS;
-+ if (!usb_pipeslow(td->urb->pipe) && td->nakcnt > 1024) {
-+ PDEBUG(2, "too many naks, td = %p, count = %d", td, td->nakcnt);
-+ td->td_status = -ETIMEDOUT;
-+ td->done = 1;
-+ }
-+ }
-+
-+ sl811_print_td(4, td);
-+}
-+
-+/*
-+ * This function checks the status of current urb.
-+ */
-+static int sl811_parse_cur_urb(struct urb *urb)
-+{
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+ struct sl811_td *td = urbp->cur_td;
-+ struct list_head *tmp;
-+
-+ sl811_print_td(5, td);
-+
-+ // this td not done yet.
-+ if (!td->done)
-+ return 0;
-+
-+ // the last ld, so the urb is done.
-+ if (td == urbp->last_td) {
-+ PDEBUG(4, "urb = %p is done success", td->urb);
-+ if (usb_pipeisoc(td->urb->pipe))
-+ PDEBUG(4, "ISO URB DONE, td = %p", td);
-+ return 1;
-+ }
-+
-+ // iso transfer, we always advance to next td
-+ if (usb_pipeisoc(td->urb->pipe)) {
-+ tmp = &td->td_list;
-+ tmp = tmp->next;
-+ urbp->cur_td = list_entry(tmp, struct sl811_td, td_list);
-+ PDEBUG(4, "ISO NEXT, td = %p", urbp->cur_td);
-+ return 0;
-+ }
-+
-+ // some error occur, so the urb is done.
-+ if (td->td_status) {
-+ PDEBUG(3, "urb = %p is done error, td status is = %d", td->urb, td->td_status);
-+ return 1;
-+ }
-+
-+ // short packet.
-+ if (td->left) {
-+ if (usb_pipecontrol(td->urb->pipe)) {
-+ // control packet, we advance to the last td
-+ PDEBUG(3, "ctrl short packet, advance to last td");
-+ urbp->cur_td = urbp->last_td;
-+ return 0;
-+ } else {
-+ // interrut and bulk packet, urb is over.
-+ PDEBUG(3, "bulk or intr short packet, urb is over");
-+ return 1;
-+ }
-+ }
-+
-+ // we advance to next td.
-+ tmp = &td->td_list;
-+ tmp = tmp->next;
-+ urbp->cur_td = list_entry(tmp, struct sl811_td, td_list);
-+#ifdef SL811_DEBUG
-+ PDEBUG(4, "advance to the next td, urb = %p, td = %p", urb, urbp->cur_td);
-+ sl811_print_td(5, urbp->cur_td);
-+ if (td == urbp->cur_td)
-+ PDEBUG(1, "bug!!!");
-+#endif
-+ return 0;
-+}
-+
-+/*
-+ * Find the next td to transfer.
-+ */
-+static inline struct sl811_td* sl811_schedule_next_td(struct urb *urb, struct sl811_td *cur_td)
-+{
-+ struct sl811_urb_priv *urbp = urb->hcpriv;
-+
-+ PDEBUG(4, "urb at %p, cur td at %p", urb, cur_td);
-+
-+ // iso don't schedule the td in the same frame.
-+ if (usb_pipeisoc(cur_td->urb->pipe))
-+ return NULL;
-+
-+ // cur td is not complete
-+ if (!cur_td->done)
-+ return NULL;
-+
-+ // here, urbp->cur_td is already the next td;
-+ return urbp->cur_td;
-+}
-+
-+/*
-+ * Scan the list to find a active urb
-+ */
-+static inline struct urb* sl811_get_list_next_urb(struct sl811_hc *hc, struct list_head *next)
-+{
-+ struct urb *urb;
-+ int i;
-+
-+ if (list_empty(next))
-+ return NULL;
-+
-+ if (next == hc->cur_list)
-+ return NULL;
-+
-+ for (i = 0; i < 4; ++i)
-+ if (next == &hc->urb_list[i])
-+ return NULL;
-+
-+ urb = list_entry(next, struct urb, urb_list);
-+ PDEBUG(4, "next urb in list is at %p", urb);
-+
-+ return urb;
-+}
-+
-+/*
-+ * Find the next td to transfer.
-+ */
-+static struct sl811_td* sl811_schedule_next_urb(struct sl811_hc *hc, struct list_head *next)
-+{
-+ struct urb *urb = NULL;
-+ int back_loop = 1;
-+ struct list_head *old_list = hc->cur_list;
-+
-+ // try to get next urb in the same list.
-+ if (next) {
-+ urb = sl811_get_list_next_urb(hc, next);
-+ if (!urb)
-+ ++hc->cur_list;
-+ }
-+
-+ // try other list.
-+ if (!urb) {
-+re_loop:
-+ // try all the list.
-+ while (hc->cur_list < &hc->urb_list[4]) {
-+ if ((urb = sl811_get_list_next_urb(hc, hc->cur_list->next)))
-+ return ((struct sl811_urb_priv *)urb->hcpriv)->cur_td;
-+ ++hc->cur_list;
-+ }
-+ // the last list is try
-+ if (back_loop && (old_list >= &hc->ctrl_list)) {
-+ hc->cur_list = &hc->ctrl_list;
-+ back_loop = 0;
-+ goto re_loop;
-+ }
-+ }
-+
-+ if (hc->cur_list > &hc->urb_list[3])
-+ hc->cur_list = &hc->ctrl_list;
-+
-+ return NULL;
-+}
-+
-+/*
-+ * This function process the transfer rusult.
-+ */
-+static void sl811_transfer_done(struct sl811_hc *hc, int sof)
-+{
-+ struct sl811_td *cur_td = hc->cur_td, *next_td = NULL;
-+ struct urb *cur_urb = NULL;
-+ struct list_head *next = NULL;
-+ int done;
-+
-+ PDEBUG(5, "enter");
-+
-+ if (cur_td == NULL) {
-+ PDEBUG(1, "in done interrupt, but td is null, be already parsed?");
-+ return ;
-+ }
-+
-+ cur_urb = cur_td->urb;
-+ hc->cur_td = NULL;
-+ next = &cur_urb->urb_list;
-+ next = next->next;
-+
-+ spin_lock(&cur_urb->lock);
-+ sl811_parse_cur_td(hc, cur_td);
-+ done = sl811_parse_cur_urb(cur_urb);
-+ spin_unlock(&cur_urb->lock);
-+
-+ if (done) {
-+ list_del_init(&cur_urb->urb_list);
-+ cur_td = NULL;
-+ sl811_result_urb(cur_urb);
-+ }
-+
-+ if (sof)
-+ return ;
-+
-+ if (!done) {
-+ next_td = sl811_schedule_next_td(cur_urb, cur_td);
-+ if (next_td && next_td != cur_td && (sl811_calc_bus_remainder(hc) > next_td->bustime)) {
-+ hc->cur_td = next_td;
-+ PDEBUG(5, "ADD TD");
-+ sl811_trans_cur_td(hc, next_td);
-+ return ;
-+ }
-+ }
-+
-+ while (1) {
-+ next_td = sl811_schedule_next_urb(hc, next);
-+ if (!next_td)
-+ return;
-+ if (next_td == cur_td)
-+ return;
-+ next = &next_td->urb->urb_list;
-+ next = next->next;
-+ if (sl811_calc_bus_remainder(hc) > next_td->bustime) {
-+ hc->cur_td = next_td;
-+ PDEBUG(5, "ADD TD");
-+ sl811_trans_cur_td(hc, next_td);
-+ return ;
-+ }
-+ }
-+}
-+
-+/*
-+ *
-+ */
-+static void inline sl811_dec_intr_interval(struct sl811_hc *hc)
-+{
-+ struct list_head *head, *tmp;
-+ struct urb *urb;
-+ struct sl811_urb_priv *urbp;
-+
-+ if (list_empty(&hc->idle_intr_list))
-+ return ;
-+
-+ head = &hc->idle_intr_list;
-+ tmp = head->next;
-+
-+ while (tmp != head) {
-+ urb = list_entry(tmp, struct urb, urb_list);
-+ tmp = tmp->next;
-+ spin_lock(&urb->lock);
-+ urbp = urb->hcpriv;
-+ if (--urbp->interval == 0) {
-+ list_del(&urb->urb_list);
-+ list_add(&urb->urb_list, &hc->intr_list);
-+ PDEBUG(4, "intr urb active");
-+ }
-+ spin_unlock(&urb->lock);
-+ }
-+}
-+
-+/*
-+ * The sof interrupt is happen.
-+ */
-+static void sl811_start_sof(struct sl811_hc *hc)
-+{
-+ struct sl811_td *next_td;
-+#ifdef SL811_DEBUG
-+ static struct sl811_td *repeat_td = NULL;
-+ static int repeat_cnt = 1;
-+#endif
-+ if (++hc->frame_number > 1024)
-+ hc->frame_number = 0;
-+
-+ if (hc->active_urbs == 0)
-+ return ;
-+
-+ sl811_dec_intr_interval(hc);
-+
-+ if (hc->cur_td) {
-+ if (sl811_read(hc, 0) & SL811_USB_CTRL_ARM) {
-+#ifdef SL811_DEBUG
-+ if (repeat_td == hc->cur_td)
-+ ++repeat_cnt;
-+ else {
-+ if (repeat_cnt >= 2)
-+ PDEBUG(2, "cur td = %p repeat %d", hc->cur_td, repeat_cnt);
-+ repeat_cnt = 1;
-+ repeat_td = hc->cur_td;
-+ }
-+#endif
-+ return ;
-+ } else {
-+ PDEBUG(2, "lost of interrupt in sof? do parse!");
-+ sl811_transfer_done(hc, 1);
-+
-+ // let this frame idle
-+ return;
-+ }
-+ }
-+
-+ hc->cur_list = &hc->iso_list;
-+
-+ if (hc->active_urbs == 0)
-+ return ;
-+
-+ next_td = sl811_schedule_next_urb(hc, NULL);
-+ if (!next_td) {
-+#ifdef SL811_DEBUG
-+ if (list_empty(&hc->idle_intr_list))
-+ PDEBUG(2, "not schedule a td, why? urbs = %d", hc->active_urbs);
-+#endif
-+ return;
-+ }
-+ if (sl811_calc_bus_remainder(hc) > next_td->bustime) {
-+ hc->cur_td = next_td;
-+ sl811_trans_cur_td(hc, next_td);
-+ } else
-+ PDEBUG(2, "bus time if not enough, why?");
-+}
-+
-+/*
-+ * This function resets SL811HS controller and detects the speed of
-+ * the connecting device
-+ *
-+ * Return: 0 = no device attached; 1 = USB device attached
-+ */
-+static int sl811_hc_reset(struct sl811_hc *hc)
-+{
-+ int status ;
-+
-+ sl811_write(hc, SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
-+ sl811_write(hc, SL811_CTRL1, SL811_CTRL1_RESET);
-+
-+ mdelay(20);
-+
-+ // Disable hardware SOF generation, clear all irq status.
-+ sl811_write(hc, SL811_CTRL1, 0);
-+ mdelay(2);
-+ sl811_write(hc, SL811_INTRSTS, 0xff);
-+ status = sl811_read(hc, SL811_INTRSTS);
-+
-+ if (status & SL811_INTR_NOTPRESENT) {
-+ // Device is not present
-+ PDEBUG(0, "Device not present");
-+ hc->rh_status.wPortStatus &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE);
-+ hc->rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
-+ sl811_write(hc, SL811_INTR, SL811_INTR_INSRMV);
-+ return 0;
-+ }
-+
-+ // Send SOF to address 0, endpoint 0.
-+ sl811_write(hc, SL811_LEN_B, 0);
-+ sl811_write(hc, SL811_PIDEP_B, PIDEP(USB_PID_SOF, 0));
-+ sl811_write(hc, SL811_DEV_B, 0x00);
-+ sl811_write (hc, SL811_SOFLOW, SL811_12M_HI);
-+
-+ if (status & SL811_INTR_SPEED_FULL) {
-+ /* full speed device connect directly to root hub */
-+ PDEBUG (0, "Full speed Device attached");
-+
-+ sl811_write(hc, SL811_CTRL1, SL811_CTRL1_RESET);
-+ mdelay(20);
-+ sl811_write(hc, SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
-+ sl811_write(hc, SL811_CTRL1, SL811_CTRL1_SOF);
-+
-+ /* start the SOF or EOP */
-+ sl811_write(hc, SL811_CTRL_B, SL811_USB_CTRL_ARM);
-+ hc->rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION;
-+ hc->rh_status.wPortStatus &= ~USB_PORT_STAT_LOW_SPEED;
-+ mdelay(2);
-+ sl811_write (hc, SL811_INTRSTS, 0xff);
-+ } else {
-+ /* slow speed device connect directly to root-hub */
-+ PDEBUG(0, "Low speed Device attached");
-+
-+ sl811_write(hc, SL811_CTRL1, SL811_CTRL1_RESET);
-+ mdelay(20);
-+ sl811_write(hc, SL811_CTRL2, SL811_CTL2_HOST | SL811_CTL2_DSWAP | SL811_12M_HI);
-+ sl811_write(hc, SL811_CTRL1, SL811_CTRL1_SPEED_LOW | SL811_CTRL1_SOF);
-+
-+ /* start the SOF or EOP */
-+ sl811_write(hc, SL811_CTRL_B, SL811_USB_CTRL_ARM);
-+ hc->rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION | USB_PORT_STAT_LOW_SPEED;
-+ mdelay(2);
-+ sl811_write(hc, SL811_INTRSTS, 0xff);
-+ }
-+
-+ hc->rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
-+ sl811_write(hc, SL811_INTR, SL811_INTR_INSRMV);
-+
-+ return 1;
-+}
-+
-+/*
-+ * Interrupt service routine.
-+ */
-+static void sl811_interrupt(int irq, void *__hc, struct pt_regs * r)
-+{
-+ __u8 status;
-+ struct sl811_hc *hc = __hc;
-+
-+ status = sl811_read(hc, SL811_INTRSTS);
-+ if (status == 0)
-+ return ; /* Not me */
-+
-+ sl811_write(hc, SL811_INTRSTS, 0xff);
-+
-+ if (status & SL811_INTR_INSRMV) {
-+ sl811_write(hc, SL811_INTR, 0);
-+ sl811_write(hc, SL811_CTRL1, 0);
-+ // wait for device stable
-+ mdelay(100);
-+ sl811_hc_reset(hc);
-+ return ;
-+ }
-+
-+ spin_lock(&hc->hc_lock);
-+
-+ if (status & SL811_INTR_DONE_A) {
-+ if (status & SL811_INTR_SOF) {
-+ sl811_transfer_done(hc, 1);
-+ PDEBUG(4, "sof in done!");
-+ sl811_start_sof(hc);
-+ } else
-+ sl811_transfer_done(hc, 0);
-+ } else if (status & SL811_INTR_SOF)
-+ sl811_start_sof(hc);
-+
-+ spin_unlock(&hc->hc_lock);
-+
-+ return ;
-+}
-+
-+/*
-+ * This function allocates all data structure and store in the
-+ * private data structure.
-+ *
-+ * Return value : data structure for the host controller
-+ */
-+static struct sl811_hc* __devinit sl811_alloc_hc(void)
-+{
-+ struct sl811_hc *hc;
-+ struct usb_bus *bus;
-+ int i;
-+
-+ PDEBUG(4, "enter");
-+
-+ hc = (struct sl811_hc *)kmalloc(sizeof(struct sl811_hc), GFP_KERNEL);
-+ if (!hc)
-+ return NULL;
-+
-+ memset(hc, 0, sizeof(struct sl811_hc));
-+
-+ hc->rh_status.wPortStatus = USB_PORT_STAT_POWER;
-+ hc->rh_status.wPortChange = 0;
-+
-+ hc->active_urbs = 0;
-+ INIT_LIST_HEAD(&hc->hc_hcd_list);
-+ list_add(&hc->hc_hcd_list, &sl811_hcd_list);
-+
-+ init_waitqueue_head(&hc->waitq);
-+
-+ for (i = 0; i < 6; ++i)
-+ INIT_LIST_HEAD(&hc->urb_list[i]);
-+
-+ hc->cur_list = &hc->iso_list;
-+
-+ bus = usb_alloc_bus(&sl811_device_operations);
-+ if (!bus) {
-+ kfree (hc);
-+ return NULL;
-+ }
-+
-+ hc->bus = bus;
-+ bus->bus_name = MODNAME;
-+ bus->hcpriv = hc;
-+
-+ return hc;
-+}
-+
-+/*
-+ * This function De-allocate all resources
-+ */
-+static void sl811_release_hc(struct sl811_hc *hc)
-+{
-+ PDEBUG(4, "enter");
-+
-+ /* disconnect all devices */
-+ if (hc->bus->root_hub)
-+ usb_disconnect(&hc->bus->root_hub);
-+
-+ // Stop interrupt handle
-+ if (hc->irq)
-+ free_irq(hc->irq, hc);
-+ hc->irq = 0;
-+
-+ /* Stop interrupt for sharing */
-+ if (hc->addr_io) {
-+ /* Disable Interrupts */
-+ sl811_write(hc, SL811_INTR, 0);
-+
-+ /* Remove all Interrupt events */
-+ mdelay(2);
-+ sl811_write(hc, SL811_INTRSTS, 0xff);
-+ }
-+
-+ /* free io regions */
-+ sl811_release_regions(hc);
-+
-+ usb_deregister_bus(hc->bus);
-+ usb_free_bus(hc->bus);
-+
-+ list_del(&hc->hc_hcd_list);
-+ INIT_LIST_HEAD(&hc->hc_hcd_list);
-+
-+ kfree (hc);
-+}
-+
-+/*
-+ * This function request IO memory regions, request IRQ, and
-+ * allocate all other resources.
-+ *
-+ * Input: addr_io = first IO address
-+ * data_io = second IO address
-+ * irq = interrupt number
-+ *
-+ * Return: 0 = success or error condition
-+ */
-+static int __devinit sl811_found_hc(int addr_io, int data_io, int irq)
-+{
-+ struct sl811_hc *hc;
-+
-+ PDEBUG(4, "enter");
-+
-+ hc = sl811_alloc_hc();
-+ if (!hc)
-+ return -ENOMEM;
-+
-+ if (sl811_request_regions (hc, addr_io, data_io, MODNAME)) {
-+ PDEBUG(1, "ioport %X,%X is in use!", addr_io, data_io);
-+ sl811_release_hc(hc);
-+ return -EBUSY;
-+ }
-+
-+ if (sl811_reg_test(hc)) {
-+ PDEBUG(1, "SL811 register test failed!");
-+ sl811_release_hc(hc);
-+ return -ENODEV;
-+ }
-+
-+//#ifdef SL811_DEBUG_VERBOSE
-+ {
-+ __u8 u = sl811_read(hc, SL811_HWREV);
-+
-+ // Show the hardware revision of chip
-+ PDEBUG(1, "SL811 HW: %02Xh", u);
-+ switch (u & 0xF0) {
-+ case 0x00: PDEBUG(1, "SL11H"); break;
-+ case 0x10: PDEBUG(1, "SL811HS rev1.2"); break;
-+ case 0x20: PDEBUG(1, "SL811HS rev1.5"); break;
-+ default: PDEBUG(1, "Revision unknown!");
-+ }
-+ }
-+//#endif // SL811_DEBUG_VERBOSE
-+
-+ sl811_init_irq();
-+
-+ usb_register_bus(hc->bus);
-+
-+ if (request_irq(irq, sl811_interrupt, SA_SHIRQ, MODNAME, hc)) {
-+ PDEBUG(1, "request interrupt %d failed", irq);
-+ sl811_release_hc(hc);
-+ return -EBUSY;
-+ }
-+ hc->irq = irq;
-+
-+ printk(KERN_INFO __FILE__ ": USB SL811 at %08x,%08x, IRQ %d\n",
-+ hc->addr_io, hc->data_io, irq);
-+
-+ sl811_hc_reset(hc);
-+ sl811_connect_rh(hc);
-+
-+ return 0;
-+}
-+
-+/*
-+ * This is an init function, and it is the first function being called
-+ *
-+ * Return: 0 = success or error condition
-+ */
-+static int __init sl811_hcd_init(void)
-+{
-+ int ret = -ENODEV;
-+
-+ PDEBUG(4, "enter");
-+
-+ info(DRIVER_VERSION " : " DRIVER_DESC);
-+
-+#ifdef CONFIG_X86
-+ {
-+ int count;
-+ // registering some instance
-+ for (count = 0; count < MAX_CONTROLERS; count++) {
-+ if (io[count]) {
-+ ret = sl811_found_hc(io[count], io[count]+OFFSET_DATA_REG, irq[count]);
-+ if (ret)
-+ return (ret);
-+ }
-+ }
-+ }
-+#endif
-+#ifdef CONFIG_ARCH_RAMSES
-+ ret = sl811_found_hc(0,0,SL811HS_IRQ);
-+#endif
-+
-+ return ret;
-+}
-+
-+/*
-+ * This is a cleanup function, and it is called when module is unloaded.
-+ */
-+static void __exit sl811_hcd_cleanup(void)
-+{
-+ struct list_head *list = sl811_hcd_list.next;
-+ struct sl811_hc *hc;
-+
-+ PDEBUG(4, "enter");
-+
-+ for (; list != &sl811_hcd_list; ) {
-+ hc = list_entry(list, struct sl811_hc, hc_hcd_list);
-+ list = list->next;
-+ sl811_release_hc(hc);
-+ }
-+}
-+
-+module_init(sl811_hcd_init);
-+module_exit(sl811_hcd_cleanup);
-+
-+MODULE_AUTHOR(DRIVER_AUTHOR);
-+MODULE_DESCRIPTION(DRIVER_DESC);
---- /dev/null
-+++ linux-2.4.21/drivers/usb/host/sl811.h
-@@ -0,0 +1,177 @@
-+#ifndef __LINUX_SL811_H
-+#define __LINUX_SL811_H
-+
-+#define SL811_DEBUG
-+
-+#ifdef SL811_DEBUG
-+ #define PDEBUG(level, fmt, args...) \
-+ if (debug >= (level)) info("[%s:%d] " fmt, \
-+ __PRETTY_FUNCTION__, __LINE__ , ## args)
-+#else
-+ #define PDEBUG(level, fmt, args...) do {} while(0)
-+#endif
-+
-+//#define SL811_TIMEOUT
-+
-+/* Sl811 host control register */
-+#define SL811_CTRL_A 0x00
-+#define SL811_ADDR_A 0x01
-+#define SL811_LEN_A 0x02
-+#define SL811_STS_A 0x03 /* read */
-+#define SL811_PIDEP_A 0x03 /* write */
-+#define SL811_CNT_A 0x04 /* read */
-+#define SL811_DEV_A 0x04 /* write */
-+#define SL811_CTRL1 0x05
-+#define SL811_INTR 0x06
-+#define SL811_CTRL_B 0x08
-+#define SL811_ADDR_B 0x09
-+#define SL811_LEN_B 0x0A
-+#define SL811_STS_B 0x0B /* read */
-+#define SL811_PIDEP_B 0x0B /* write */
-+#define SL811_CNT_B 0x0C /* read */
-+#define SL811_DEV_B 0x0C /* write */
-+#define SL811_INTRSTS 0x0D /* write clears bitwise */
-+#define SL811_HWREV 0x0E /* read */
-+#define SL811_SOFLOW 0x0E /* write */
-+#define SL811_SOFCNTDIV 0x0F /* read */
-+#define SL811_CTRL2 0x0F /* write */
-+
-+/* USB control register bits (addr 0x00 and addr 0x08) */
-+#define SL811_USB_CTRL_ARM 0x01
-+#define SL811_USB_CTRL_ENABLE 0x02
-+#define SL811_USB_CTRL_DIR_OUT 0x04
-+#define SL811_USB_CTRL_ISO 0x10
-+#define SL811_USB_CTRL_SOF 0x20
-+#define SL811_USB_CTRL_TOGGLE_1 0x40
-+#define SL811_USB_CTRL_PREAMBLE 0x80
-+
-+/* USB status register bits (addr 0x03 and addr 0x0B) */
-+#define SL811_USB_STS_ACK 0x01
-+#define SL811_USB_STS_ERROR 0x02
-+#define SL811_USB_STS_TIMEOUT 0x04
-+#define SL811_USB_STS_TOGGLE_1 0x08
-+#define SL811_USB_STS_SETUP 0x10
-+#define SL811_USB_STS_OVERFLOW 0x20
-+#define SL811_USB_STS_NAK 0x40
-+#define SL811_USB_STS_STALL 0x80
-+
-+/* Control register 1 bits (addr 0x05) */
-+#define SL811_CTRL1_SOF 0x01
-+#define SL811_CTRL1_RESET 0x08
-+#define SL811_CTRL1_JKSTATE 0x10
-+#define SL811_CTRL1_SPEED_LOW 0x20
-+#define SL811_CTRL1_SUSPEND 0x40
-+
-+/* Interrut enable (addr 0x06) and interrupt status register bits (addr 0x0D) */
-+#define SL811_INTR_DONE_A 0x01
-+#define SL811_INTR_DONE_B 0x02
-+#define SL811_INTR_SOF 0x10
-+#define SL811_INTR_INSRMV 0x20
-+#define SL811_INTR_DETECT 0x40
-+#define SL811_INTR_NOTPRESENT 0x40
-+#define SL811_INTR_SPEED_FULL 0x80 /* only in status reg */
-+
-+/* HW rev and SOF lo register bits (addr 0x0E) */
-+#define SL811_HWR_HWREV 0xF0
-+
-+/* SOF counter and control reg 2 (addr 0x0F) */
-+#define SL811_CTL2_SOFHI 0x3F
-+#define SL811_CTL2_DSWAP 0x40
-+#define SL811_CTL2_HOST 0x80
-+
-+/* Set up for 1-ms SOF time. */
-+#define SL811_12M_LOW 0xE0
-+#define SL811_12M_HI 0x2E
-+
-+#define SL811_DATA_START 0x10
-+#define SL811_DATA_LIMIT 240
-+
-+
-+/* Requests: bRequest << 8 | bmRequestType */
-+#define RH_GET_STATUS 0x0080
-+#define RH_CLEAR_FEATURE 0x0100
-+#define RH_SET_FEATURE 0x0300
-+#define RH_SET_ADDRESS 0x0500
-+#define RH_GET_DESCRIPTOR 0x0680
-+#define RH_SET_DESCRIPTOR 0x0700
-+#define RH_GET_CONFIGURATION 0x0880
-+#define RH_SET_CONFIGURATION 0x0900
-+#define RH_GET_STATE 0x0280
-+#define RH_GET_INTERFACE 0x0A80
-+#define RH_SET_INTERFACE 0x0B00
-+#define RH_SYNC_FRAME 0x0C80
-+
-+
-+#define PIDEP(pid, ep) (((pid) & 0x0f) << 4 | (ep))
-+
-+/* Virtual Root HUB */
-+struct virt_root_hub {
-+ int devnum; /* Address of Root Hub endpoint */
-+ void *urb; /* interrupt URB of root hub */
-+ int send; /* active flag */
-+ int interval; /* intervall of roothub interrupt transfers */
-+ struct timer_list rh_int_timer; /* intervall timer for rh interrupt EP */
-+};
-+
-+struct sl811_td {
-+ /* hardware */
-+ __u8 ctrl; /* control register */
-+
-+ /* write */
-+ __u8 addr; /* base adrress register */
-+ __u8 len; /* base length register */
-+ __u8 pidep; /* PId and endpoint register */
-+ __u8 dev; /* device address register */
-+
-+ /* read */
-+ __u8 status; /* status register */
-+ __u8 left; /* transfer count register */
-+
-+ /* software */
-+ __u8 errcnt; /* error count, begin with 3 */
-+ __u8 done; /* is this td tranfer done */
-+ __u8 *buf; /* point to data buffer for tranfer */
-+ int bustime; /* the bus time need by this td */
-+ int td_status; /* the status of this td */
-+ int nakcnt; /* number of naks */
-+ struct urb *urb; /* the urb this td belongs to */
-+ struct list_head td_list; /* link to a list of the urb */
-+};
-+
-+struct sl811_urb_priv {
-+ struct urb *urb; /* the urb this priv beloings to */
-+ struct list_head td_list; /* list of all the td of this urb */
-+ struct sl811_td *cur_td; /* current td is in processing or it will be */
-+ struct sl811_td *first_td; /* the first td of this urb */
-+ struct sl811_td *last_td; /* the last td of this urb */
-+ int interval; /* the query time value for intr urb */
-+ int unlink; /* is the this urb unlinked */
-+ unsigned long inserttime; /* the time when insert to list */
-+};
-+
-+struct sl811_hc {
-+ spinlock_t hc_lock; /* Lock for this structure */
-+
-+ int irq; /* IRQ number this hc use */
-+ int addr_io; /* I/O address line address */
-+ int data_io; /* I/O data line address */
-+ struct virt_root_hub rh; /* root hub */
-+ struct usb_port_status rh_status;/* root hub port status */
-+ struct list_head urb_list[6]; /* set of urbs, the order is iso,intr,ctrl,bulk,inactive intr, wait */
-+ struct list_head *cur_list; /* the current list is in process */
-+ wait_queue_head_t waitq; /* deletion of URBs and devices needs a waitqueue */
-+ struct sl811_td *cur_td; /* point to the td is in process */
-+ struct list_head hc_hcd_list; /* list of all hci_hcd */
-+ struct usb_bus *bus; /* our bus */
-+ int active_urbs; /* total number of active usbs */
-+ int frame_number; /* the current frame number, we do't use it, any one need it? */
-+};
-+
-+#define iso_list urb_list[0] /* set of isoc urbs */
-+#define intr_list urb_list[1] /* ordered (tree) set of int urbs */
-+#define ctrl_list urb_list[2] /* set of ctrl urbs */
-+#define bulk_list urb_list[3] /* set of bulk urbs */
-+#define idle_intr_list urb_list[4] /* set of intr urbs in its idle time*/
-+#define wait_list urb_list[5] /* set of wait urbs */
-+
-+#endif
---- linux-2.4.21/drivers/usb/storage/transport.h~usb-sonycamera
-+++ linux-2.4.21/drivers/usb/storage/transport.h
-@@ -75,6 +75,8 @@
- #define US_PR_JUMPSHOT 0xf3 /* Lexar Jumpshot */
- #endif
-
-+#define US_PR_DEVICE 0xff /* Use device's value */
-+
- /*
- * Bulk only data structures
- */
---- linux-2.4.21/drivers/usb/storage/unusual_devs.h~usb-sonycamera
-+++ linux-2.4.21/drivers/usb/storage/unusual_devs.h
-@@ -223,10 +223,10 @@
- US_FL_FIX_INQUIRY | US_FL_START_STOP ),
-
- /* This entry is needed because the device reports Sub=ff */
--UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0440,
-+UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450,
- "Sony",
-- "DSC-S30/S70/S75/505V/F505/F707/F717",
-- US_SC_SCSI, US_PR_CB, NULL,
-+ "DSC-S30/S70/S75/505V/F505/F707/F717/P8",
-+ US_SC_SCSI, US_PR_DEVICE, NULL,
- US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ),
-
- /* Reported by wim@geeks.nl */
---- linux-2.4.21/drivers/usb/storage/usb.c~usb-sonycamera
-+++ linux-2.4.21/drivers/usb/storage/usb.c
-@@ -622,7 +622,9 @@
-
- /* Determine subclass and protocol, or copy from the interface */
- subclass = unusual_dev->useProtocol;
-- protocol = unusual_dev->useTransport;
-+ protocol = (unusual_dev->useTransport == US_PR_DEVICE) ?
-+ altsetting->bInterfaceProtocol :
-+ unusual_dev->useTransport;
- flags = unusual_dev->flags;
-
- /*
---- linux-2.4.21/drivers/video/fbcon-cfb16.c~fb-turn180
-+++ linux-2.4.21/drivers/video/fbcon-cfb16.c
-@@ -34,6 +34,41 @@
- #endif
- };
-
-+static u8 mirrortab_cfb16[] = {
-+ 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,
-+ 0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
-+ 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,
-+ 0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
-+ 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,
-+ 0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
-+ 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,
-+ 0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
-+ 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,
-+ 0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
-+ 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,
-+ 0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
-+ 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,
-+ 0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
-+ 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,
-+ 0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
-+ 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,
-+ 0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
-+ 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,
-+ 0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
-+ 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,
-+ 0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
-+ 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,
-+ 0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
-+ 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,
-+ 0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
-+ 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,
-+ 0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
-+ 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,
-+ 0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
-+ 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,
-+ 0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
-+};
-+
- void fbcon_cfb16_setup(struct display *p)
- {
- p->next_line = p->line_length ? p->line_length : p->var.xres_virtual<<1;
-@@ -46,6 +81,53 @@
- int bytes = p->next_line, linesize = bytes * fontheight(p), rows;
- u8 *src, *dst;
-
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ char *scrn_end = p->screen_base + p->var.xres*p->var.yres * 2;
-+/*
-+ printk("---@paul@-------------------------\n"\
-+ "fbcon_cfb16_bmove() %d %d %d %d %d %d\n",
-+ sx,sy,dx,dy,height,width
-+ );
-+*/
-+ if (sx == 0 && dx == 0 && width * fontwidth(p) * 2 == bytes)
-+ {
-+ fb_memmove(
-+ scrn_end - dy * linesize,
-+ scrn_end - sy * linesize,
-+ height * linesize
-+ );
-+ return;
-+ }
-+ if (fontwidthlog(p)) {
-+ sx <<= fontwidthlog(p)+1;
-+ dx <<= fontwidthlog(p)+1;
-+ width <<= fontwidthlog(p)+1;
-+ } else {
-+ sx *= fontwidth(p)*2;
-+ dx *= fontwidth(p)*2;
-+ width *= fontwidth(p)*2;
-+ }
-+ if (dy < sy || (dy == sy && dx < sx)) {
-+ src = scrn_end + sy * linesize + sx;
-+ dst = scrn_end + dy * linesize + dx;
-+ for (rows = height * fontheight(p); rows--;)
-+ {
-+ fb_memmove(dst, src, width);
-+ src += bytes;
-+ dst += bytes;
-+ }
-+ } else {
-+ src = scrn_end + (sy+height) * linesize + sx - bytes;
-+ dst = scrn_end + (dy+height) * linesize + dx - bytes;
-+ for (rows = height * fontheight(p); rows--;)
-+ {
-+ fb_memmove(dst, src, width);
-+ src -= bytes;
-+ dst -= bytes;
-+ }
-+ }
-+/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
-+ } else {
- if (sx == 0 && dx == 0 && width * fontwidth(p) * 2 == bytes) {
- fb_memmove(p->screen_base + dy * linesize,
- p->screen_base + sy * linesize,
-@@ -78,6 +160,8 @@
- dst -= bytes;
- }
- }
-+ }
-+/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
- }
-
- static inline void rectfill(u8 *dest, int width, int height, u32 data,
-@@ -108,10 +192,16 @@
- int bytes = p->next_line, lines = height * fontheight(p);
- u32 bgx;
-
-- dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 2;
--
-- bgx = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
--
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ dest = p->screen_base
-+ + p->var.xres*p->var.yres * 2
-+ - (sy+height) * fontheight(p) * bytes
-+ + sx * fontwidth(p) * 2;
-+ bgx = 1;
-+ } else {
-+ dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 2;
-+ bgx = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
-+ }
- width *= fontwidth(p)/4;
- if (width * 8 == bytes)
- rectfill(dest, lines * width * 4, 1, bgx, bytes);
-@@ -126,14 +216,69 @@
- int bytes = p->next_line, rows;
- u32 eorx, fgx, bgx;
-
-- dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2;
--
- fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)];
- bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)];
- fgx |= (fgx << 16);
- bgx |= (bgx << 16);
- eorx = fgx ^ bgx;
-
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ dest = p->screen_base
-+ + p->var.xres*p->var.yres * 2
-+ - yy * fontheight(p) * bytes
-+ - xx * fontwidth(p) * 2;
-+
-+ switch (fontwidth(p)) {
-+ case 4:
-+ cdat = p->fontdata + (c & p->charmask) * fontheight(p);
-+ for (rows = fontheight(p); rows--; dest += bytes)
-+ {
-+ bits = mirrortab_cfb16[*cdat++];
-+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-8);
-+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-4);
-+ }
-+ case 8:
-+ cdat = p->fontdata + (c & p->charmask) * fontheight(p);
-+ for (rows = fontheight(p); rows--; dest += bytes)
-+ {
-+ bits = mirrortab_cfb16[*cdat++];
-+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-16);
-+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-12);
-+ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-8);
-+ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-4);
-+ }
-+ break;
-+ case 12:
-+ cdat = p->fontdata + ((c & p->charmask) * fontheight(p) << 1);
-+ for (rows = fontheight(p); rows--; dest += bytes) {
-+ bits = mirrortab_cfb16[*cdat++];
-+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-24);
-+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-20);
-+ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-16);
-+ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-12);
-+ bits = mirrortab_cfb16[*cdat++];
-+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-8);
-+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-4);
-+ }
-+ case 16:
-+ cdat = p->fontdata + ((c & p->charmask) * fontheight(p) << 1);
-+ for (rows = fontheight(p); rows--; dest += bytes) {
-+ bits = mirrortab_cfb16[*cdat++];
-+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-32);
-+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-28);
-+ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-24);
-+ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-20);
-+ bits = mirrortab_cfb16[*cdat++];
-+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-16);
-+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-12);
-+ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-8);
-+ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-4);
-+ }
-+ break;
-+ }
-+/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
-+ } else {
-+ dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2;
- switch (fontwidth(p)) {
- case 4:
- case 8:
-@@ -167,6 +312,8 @@
- }
- break;
- }
-+ }
-+/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
- }
-
- void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p,
-@@ -177,7 +324,6 @@
- int rows, bytes = p->next_line;
- u32 eorx, fgx, bgx;
-
-- dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2;
- c = scr_readw(s);
- fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)];
- bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)];
-@@ -185,6 +331,81 @@
- bgx |= (bgx << 16);
- eorx = fgx ^ bgx;
-
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ dest0 = p->screen_base
-+ + p->var.xres * p->var.yres * 2
-+ - yy * fontheight(p) * bytes
-+ - xx * fontwidth(p) * 2;
-+
-+ switch (fontwidth(p)) {
-+ case 4:
-+ while (count--) {
-+ c = scr_readw(s++) & p->charmask;
-+ cdat = p->fontdata + c * fontheight(p);
-+ for (rows = fontheight(p), dest = dest0; rows--; dest -= bytes)
-+ {
-+ u8 bits = mirrortab_cfb16[*cdat++];
-+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-8);
-+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-4);
-+ }
-+ dest0 -= fontwidth(p)*2;
-+ }
-+ case 8:
-+ while (count--) {
-+ c = scr_readw(s++) & p->charmask;
-+ cdat = p->fontdata + c * fontheight(p);
-+ for (rows = fontheight(p), dest = dest0; rows--; dest -= bytes)
-+ {
-+ u8 bits = mirrortab_cfb16[*cdat++];
-+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-16);
-+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-12);
-+ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-8);
-+ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-4);
-+ }
-+ dest0 -= fontwidth(p)*2;
-+ }
-+ break;
-+ case 12:
-+ while (count--) {
-+ c = scr_readw(s++) & p->charmask;
-+ cdat = p->fontdata + (c * fontheight(p) << 1);
-+ for (rows = fontheight(p), dest = dest0; rows--; dest -= bytes)
-+ {
-+ u8 bits = mirrortab_cfb16[*cdat++];
-+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-24);
-+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-20);
-+ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-16);
-+ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-12);
-+ bits = mirrortab_cfb16[*cdat++];
-+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-8);
-+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-4);
-+ }
-+ dest0 -= fontwidth(p)*2;
-+ }
-+ case 16:
-+ while (count--) {
-+ c = scr_readw(s++) & p->charmask;
-+ cdat = p->fontdata + (c * fontheight(p) << 1);
-+ for (rows = fontheight(p), dest = dest0; rows--; dest -= bytes)
-+ {
-+ u8 bits = mirrortab_cfb16[*cdat++];
-+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-32);
-+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-28);
-+ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-24);
-+ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-20);
-+ bits = mirrortab_cfb16[*cdat++];
-+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-16);
-+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-12);
-+ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-8);
-+ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-4);
-+ }
-+ dest0 -= fontwidth(p)*2;
-+ }
-+ break;
-+ }
-+/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
-+ } else {
-+ dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2;
- switch (fontwidth(p)) {
- case 4:
- case 8:
-@@ -226,6 +447,8 @@
- }
- break;
- }
-+ }
-+/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
- }
-
- void fbcon_cfb16_revc(struct display *p, int xx, int yy)
-@@ -233,6 +456,32 @@
- u8 *dest;
- int bytes = p->next_line, rows;
-
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ dest = p->screen_base
-+ + p->var.xres*p->var.yres * 2
-+ - yy * fontheight(p) * bytes
-+ - xx * fontwidth(p) * 2;
-+ for (rows = fontheight(p); rows--; dest -= bytes) {
-+ switch (fontwidth(p)) {
-+ case 16:
-+ fb_writel(fb_readl(dest-32) ^ 0xffffffff, dest-32);
-+ fb_writel(fb_readl(dest-28) ^ 0xffffffff, dest-28);
-+ /* FALL THROUGH */
-+ case 12:
-+ fb_writel(fb_readl(dest-24) ^ 0xffffffff, dest-24);
-+ fb_writel(fb_readl(dest-20) ^ 0xffffffff, dest-20);
-+ /* FALL THROUGH */
-+ case 8:
-+ fb_writel(fb_readl(dest-16) ^ 0xffffffff, dest-16);
-+ fb_writel(fb_readl(dest-12) ^ 0xffffffff, dest-12);
-+ /* FALL THROUGH */
-+ case 4:
-+ fb_writel(fb_readl(dest-8) ^ 0xffffffff, dest-8);
-+ fb_writel(fb_readl(dest-4) ^ 0xffffffff, dest-4);
-+ }
-+ }
-+/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
-+ } else {
- dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p)*2;
- for (rows = fontheight(p); rows--; dest += bytes) {
- switch (fontwidth(p)) {
-@@ -253,6 +502,8 @@
- fb_writel(fb_readl(dest+4) ^ 0xffffffff, dest+4);
- }
- }
-+ }
-+/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
- }
-
- void fbcon_cfb16_clear_margins(struct vc_data *conp, struct display *p,
-@@ -268,6 +519,9 @@
- bgx = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
-
- if (!bottom_only && (right_width = p->var.xres-right_start))
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ printk("---@paul@------------------------- fbcon-cfb16 clear margins\n");
-+ }
- rectfill(p->screen_base+right_start*2, right_width,
- p->var.yres_virtual, bgx, bytes);
- if ((bottom_width = p->var.yres-bottom_start))
---- linux-2.4.21/drivers/video/fbcon-cfb8.c~fb-turn180
-+++ linux-2.4.21/drivers/video/fbcon-cfb8.c
-@@ -39,6 +39,41 @@
- #endif
- };
-
-+static u8 mirrortab_cfb8[] = {
-+ 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,
-+ 0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
-+ 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,
-+ 0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
-+ 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,
-+ 0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
-+ 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,
-+ 0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
-+ 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,
-+ 0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
-+ 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,
-+ 0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
-+ 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,
-+ 0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
-+ 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,
-+ 0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
-+ 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,
-+ 0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
-+ 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,
-+ 0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
-+ 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,
-+ 0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
-+ 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,
-+ 0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
-+ 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,
-+ 0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
-+ 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,
-+ 0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
-+ 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,
-+ 0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
-+ 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,
-+ 0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
-+};
-+
- void fbcon_cfb8_setup(struct display *p)
- {
- p->next_line = p->line_length ? p->line_length : p->var.xres_virtual;
-@@ -51,10 +86,57 @@
- int bytes = p->next_line, linesize = bytes * fontheight(p), rows;
- u8 *src,*dst;
-
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+/*
-+ printk("---@paul@-------------------------\n"\
-+ "fbcon_cfb8_bmove() %d %d %d %d %d %d\n",
-+ sx,sy,dx,dy,height,width
-+ );
-+*/
-+ if (sx == 0 && dx == 0 && width * fontwidth(p) == bytes)
-+ {
-+ fb_memmove(
-+ p->screen_base + p->var.xres*p->var.yres - dy * linesize,
-+ p->screen_base + p->var.xres*p->var.yres - sy * linesize,
-+ height * linesize);
-+ return;
-+ }
-+ if (fontwidthlog(p)) {
-+ sx <<= fontwidthlog(p); dx <<= fontwidthlog(p); width <<= fontwidthlog(p);
-+ } else {
-+ sx *= fontwidth(p); dx *= fontwidth(p); width *= fontwidth(p);
-+ }
-+ if (dy < sy || (dy == sy && dx < sx))
-+ {
-+ src = p->screen_base + p->var.xres*p->var.yres
-+ - sy * linesize - sx;
-+ dst = p->screen_base + p->var.xres*p->var.yres
-+ - dy * linesize - dx;
-+ for (rows = height * fontheight(p) ; rows-- ;)
-+ {
-+ fb_memmove(dst, src, width);
-+ src += bytes;
-+ dst += bytes;
-+ }
-+ } else
-+ {
-+ src = p->screen_base + p->var.xres*p->var.yres
-+ - (sy+height) * linesize - sx + bytes;
-+ dst = p->screen_base + p->var.xres*p->var.yres
-+ - (dy+height) * linesize - dx + bytes;
-+ for (rows = height * fontheight(p) ; rows-- ;)
-+ {
-+ fb_memmove(dst, src, width);
-+ src -= bytes;
-+ dst -= bytes;
-+ }
-+ }
-+/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
-+ } else {
- if (sx == 0 && dx == 0 && width * fontwidth(p) == bytes) {
-- fb_memmove(p->screen_base + dy * linesize,
-- p->screen_base + sy * linesize,
-- height * linesize);
-+ fb_memmove(p->screen_base + dy * linesize,
-+ p->screen_base + sy * linesize,
-+ height * linesize);
- return;
- }
- if (fontwidthlog(p)) {
-@@ -79,6 +161,7 @@
- dst -= bytes;
- }
- }
-+/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
- }
-
- static inline void rectfill(u8 *dest, int width, int height, u8 data,
-@@ -97,11 +180,17 @@
- int bytes=p->next_line,lines=height * fontheight(p);
- u8 bgx;
-
-- dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p);
--
-- bgx=attr_bgcol_ec(p,conp);
--
-- width *= fontwidth(p);
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ bgx=attr_bgcol_ec(p,conp);
-+ width *= fontwidth(p);
-+ dest = p->screen_base + p->var.xres*p->var.yres
-+ - (sy+height) * fontheight(p) * bytes
-+ + sx * fontwidth(p);
-+ } else {
-+ dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p);
-+ bgx=attr_bgcol_ec(p,conp);
-+ width *= fontwidth(p);
-+ }
- if (width == bytes)
- rectfill(dest, lines * width, 1, bgx, bytes);
- else
-@@ -114,8 +203,8 @@
- u8 *dest,*cdat;
- int bytes=p->next_line,rows;
- u32 eorx,fgx,bgx;
-+ u8 chrrow;
-
-- dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
- if (fontwidth(p) <= 8)
- cdat = p->fontdata + (c & p->charmask) * fontheight(p);
- else
-@@ -129,6 +218,53 @@
- bgx |= (bgx << 16);
- eorx = fgx ^ bgx;
-
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ dest = p->screen_base
-+ + p->var.xres*p->var.yres
-+ - yy * fontheight(p) * bytes
-+ - xx * fontwidth(p);
-+
-+ switch (fontwidth(p)) {
-+ case 4:
-+ for (rows = fontheight(p) ; rows-- ; dest += bytes)
-+ {
-+ chrrow = mirrortab_cfb8[*cdat++];
-+ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-4);
-+ }
-+ break;
-+ case 8:
-+ for (rows = fontheight(p) ; rows-- ; dest += bytes)
-+ {
-+ chrrow = mirrortab_cfb8[*cdat++];
-+ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-8);
-+ fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-4);
-+ }
-+ break;
-+ case 12:
-+ for (rows = fontheight(p) ; rows-- ; dest += bytes)
-+ {
-+ chrrow = mirrortab_cfb8[*cdat++];
-+ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-12);
-+ fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-8);
-+ chrrow = mirrortab_cfb8[*cdat++];
-+ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-4);
-+ }
-+ break;
-+ case 16:
-+ for (rows = fontheight(p) ; rows-- ; dest += bytes)
-+ {
-+ chrrow = mirrortab_cfb8[*cdat++];
-+ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-16);
-+ fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-12);
-+ chrrow = mirrortab_cfb8[*cdat++];
-+ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-8);
-+ fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-4);
-+ }
-+ break;
-+ }
-+/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
-+ } else {
-+ dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
- switch (fontwidth(p)) {
- case 4:
- for (rows = fontheight(p) ; rows-- ; dest += bytes)
-@@ -152,6 +288,8 @@
- }
- break;
- }
-+ }
-+/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
- }
-
- void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p,
-@@ -161,8 +299,8 @@
- u16 c;
- int rows,bytes=p->next_line;
- u32 eorx, fgx, bgx;
-+ u8 chrrow;
-
-- dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
- c = scr_readw(s);
- fgx = attr_fgcol(p, c);
- bgx = attr_bgcol(p, c);
-@@ -171,6 +309,76 @@
- bgx |= (bgx << 8);
- bgx |= (bgx << 16);
- eorx = fgx ^ bgx;
-+
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ dest0 = p->screen_base
-+ + p->var.xres*p->var.yres
-+ - yy * fontheight(p) * bytes
-+ - xx * fontwidth(p);
-+ switch (fontwidth(p)) {
-+ case 4:
-+ while (count--) {
-+ c = scr_readw(s++) & p->charmask;
-+ cdat = p->fontdata + c * fontheight(p);
-+
-+ for (rows = fontheight(p), dest = dest0; rows-- ; dest -= bytes)
-+ {
-+ chrrow = mirrortab_cfb8[*cdat++];
-+ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-4);
-+ }
-+ dest0 -= 4;
-+ }
-+ break;
-+ case 8:
-+ while (count--) {
-+ c = scr_readw(s++) & p->charmask;
-+ cdat = p->fontdata + c * fontheight(p);
-+ for (rows = fontheight(p), dest = dest0; rows-- ; dest -= bytes)
-+ {
-+ chrrow = mirrortab_cfb8[*cdat++];
-+ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-8);
-+ fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-4);
-+ }
-+ dest0 -= 8;
-+ }
-+ break;
-+ case 12:
-+ while (count--) {
-+ c = scr_readw(s++) & p->charmask;
-+ cdat = p->fontdata + (c * fontheight(p) << 1);
-+
-+ for (rows = fontheight(p), dest = dest0; rows-- ; dest -= bytes)
-+ {
-+ chrrow = mirrortab_cfb8[*cdat++];
-+ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-12);
-+ fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-8);
-+ chrrow = mirrortab_cfb8[*cdat++];
-+ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-4);
-+ }
-+ dest0 -= fontwidth(p);
-+ }
-+ break;
-+ case 16:
-+ while (count--) {
-+ c = scr_readw(s++) & p->charmask;
-+ cdat = p->fontdata + (c * fontheight(p) << 1);
-+
-+ for (rows = fontheight(p), dest = dest0; rows-- ; dest -= bytes)
-+ {
-+ chrrow = mirrortab_cfb8[*cdat++];
-+ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-16);
-+ fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-12);
-+ chrrow = mirrortab_cfb8[*cdat++];
-+ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-8);
-+ fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-4);
-+ }
-+ dest0 -= fontwidth(p);
-+ }
-+ break;
-+ } /* switch (fontwidth(p)) */
-+/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
-+ } else {
-+ dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
- switch (fontwidth(p)) {
- case 4:
- while (count--) {
-@@ -212,6 +420,8 @@
- }
- break;
- }
-+ }
-+/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
- }
-
- void fbcon_cfb8_revc(struct display *p, int xx, int yy)
-@@ -219,6 +429,21 @@
- u8 *dest;
- int bytes=p->next_line, rows;
-
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ dest = p->screen_base + p->var.xres*p->var.yres
-+ - yy * fontheight(p) * bytes
-+ - xx * fontwidth(p);
-+ for (rows = fontheight(p) ; rows-- ; dest -= bytes) {
-+ switch (fontwidth(p)) {
-+ case 16: fb_writel(fb_readl(dest-16) ^ 0x0f0f0f0f, dest-16); /* fall thru */
-+ case 12: fb_writel(fb_readl(dest-12) ^ 0x0f0f0f0f, dest-12); /* fall thru */
-+ case 8: fb_writel(fb_readl(dest-8) ^ 0x0f0f0f0f, dest-8); /* fall thru */
-+ case 4: fb_writel(fb_readl(dest-4) ^ 0x0f0f0f0f, dest-4); /* fall thru */
-+ default: break;
-+ }
-+ }
-+/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
-+ } else {
- dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
- for (rows = fontheight(p) ; rows-- ; dest += bytes) {
- switch (fontwidth(p)) {
-@@ -229,6 +454,8 @@
- default: break;
- }
- }
-+ }
-+/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
- }
-
- void fbcon_cfb8_clear_margins(struct vc_data *conp, struct display *p,
-@@ -244,6 +471,9 @@
- bgx=attr_bgcol_ec(p,conp);
-
- if (!bottom_only && (right_width = p->var.xres-right_start))
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ printk("---@paul@------------------------- fbcon-cfb8 clear margins\n");
-+ }
- rectfill(p->screen_base+right_start, right_width, p->var.yres_virtual,
- bgx, bytes);
- if ((bottom_width = p->var.yres-bottom_start))
---- linux-2.4.21/drivers/video/fbcon.c~fb-turn180
-+++ linux-2.4.21/drivers/video/fbcon.c
-@@ -1558,6 +1558,7 @@
- update_region(fg_console,
- conp->vc_origin + conp->vc_size_row * conp->vc_top,
- conp->vc_size_row * (conp->vc_bottom - conp->vc_top) / 2);
-+ conp->vc_top = 0;
- return 0;
- }
- return 1;
-@@ -2209,7 +2210,16 @@
- src = logo;
- bdepth = depth/8;
- for( y1 = 0; y1 < LOGO_H; y1++ ) {
-- dst = fb + y1*line + x*bdepth;
-+
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+/*
-+ Das ist NICHT die richtige Stelle für den Ramses 16 BPP Modus
-+ aber dafür die weiter unten.
-+*/
-+ dst = fb + p->var.xres*p->var.yres*bdepth -1 - y1*line - x*bdepth;
-+ } else {
-+ dst = fb + y1*line + x*bdepth;
-+ }
- for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
- val = (*src << redshift) |
- (*src << greenshift) |
-@@ -2217,18 +2227,32 @@
- if (bdepth == 4 && !((long)dst & 3)) {
- /* Some cards require 32bit access */
- fb_writel (val, dst);
-- dst += 4;
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ dst -= 4;
-+ } else {
-+ dst += 4;
-+ }
- } else if (bdepth == 2 && !((long)dst & 1)) {
- /* others require 16bit access */
- fb_writew (val,dst);
-- dst +=2;
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ dst -= 2;
-+ } else {
-+ dst +=2;
-+ }
- } else {
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ for( i = bdepth-1; i >= 0; --i )
-+ fb_writeb (val >> (i*8), dst--);
-+
-+ } else {
- #ifdef __LITTLE_ENDIAN
-- for( i = 0; i < bdepth; ++i )
-+ for( i = 0; i < bdepth; ++i )
- #else
-- for( i = bdepth-1; i >= 0; --i )
-+ for( i = bdepth-1; i >= 0; --i )
- #endif
-- fb_writeb (val >> (i*8), dst++);
-+ fb_writeb (val >> (i*8), dst++);
-+ }
- }
- }
- }
-@@ -2239,28 +2263,42 @@
- src = linux_logo16;
- bdepth = (depth+7)/8;
- for( y1 = 0; y1 < LOGO_H; y1++ ) {
-- dst = fb + y1*line + x*bdepth;
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ dst = fb + p->var.xres*p->var.yres*bdepth -1 - y1*line - x*bdepth;
-+ } else {
-+ dst = fb + y1*line + x*bdepth;
-+ }
- for( x1 = 0; x1 < LOGO_W/2; x1++, src++ ) {
- pix = *src >> 4; /* upper nibble */
- val = (pix << redshift) |
- (pix << greenshift) |
- (pix << blueshift);
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ for( i = bdepth-1; i >= 0; --i )
-+ fb_writeb (val >> (i*8), dst--);
-+ } else {
- #ifdef __LITTLE_ENDIAN
-- for( i = 0; i < bdepth; ++i )
-+ for( i = 0; i < bdepth; ++i )
- #else
-- for( i = bdepth-1; i >= 0; --i )
-+ for( i = bdepth-1; i >= 0; --i )
- #endif
-- fb_writeb (val >> (i*8), dst++);
-+ fb_writeb (val >> (i*8), dst++);
-+ }
- pix = *src & 0x0f; /* lower nibble */
- val = (pix << redshift) |
- (pix << greenshift) |
- (pix << blueshift);
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ for( i = bdepth-1; i >= 0; --i )
-+ fb_writeb (val >> (i*8), dst--);
-+ } else {
- #ifdef __LITTLE_ENDIAN
-- for( i = 0; i < bdepth; ++i )
-+ for( i = 0; i < bdepth; ++i )
- #else
-- for( i = bdepth-1; i >= 0; --i )
-+ for( i = bdepth-1; i >= 0; --i )
- #endif
-- fb_writeb (val >> (i*8), dst++);
-+ fb_writeb (val >> (i*8), dst++);
-+ }
- }
- }
- }
-@@ -2287,7 +2325,11 @@
-
- src = logo;
- for( y1 = 0; y1 < LOGO_H; y1++ ) {
-- dst = fb + y1*line + x*bdepth;
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ dst = fb + p->var.xres*p->var.yres*bdepth -1 - y1*line - x*bdepth;
-+ } else {
-+ dst = fb + y1*line + x*bdepth;
-+ }
- for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
- val = safe_shift((linux_logo_red[*src-32] & redmask), redshift) |
- safe_shift((linux_logo_green[*src-32] & greenmask), greenshift) |
-@@ -2295,18 +2337,31 @@
- if (bdepth == 4 && !((long)dst & 3)) {
- /* Some cards require 32bit access */
- fb_writel (val, dst);
-- dst += 4;
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ dst -= 4;
-+ } else {
-+ dst += 4;
-+ }
- } else if (bdepth == 2 && !((long)dst & 1)) {
- /* others require 16bit access */
- fb_writew (val,dst);
-- dst +=2;
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ dst -= 2;
-+ } else {
-+ dst +=2;
-+ }
- } else {
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ for( i = bdepth-1; i >= 0; --i )
-+ fb_writeb (val >> (i*8), dst--);
-+ } else {
- #ifdef __LITTLE_ENDIAN
-- for( i = 0; i < bdepth; ++i )
-+ for( i = 0; i < bdepth; ++i )
- #else
-- for( i = bdepth-1; i >= 0; --i )
-+ for( i = bdepth-1; i >= 0; --i )
- #endif
-- fb_writeb (val >> (i*8), dst++);
-+ fb_writeb (val >> (i*8), dst++);
-+ }
- }
- }
- }
-@@ -2331,13 +2386,24 @@
- if (depth == 8 && p->type == FB_TYPE_PACKED_PIXELS) {
- /* depth 8 or more, packed, with color registers */
-
-- src = logo;
-- for( y1 = 0; y1 < LOGO_H; y1++ ) {
-- dst = fb + y1*line + x;
-- for( x1 = 0; x1 < LOGO_W; x1++ )
-- fb_writeb (*src++, dst++);
-- }
-- done = 1;
-+ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
-+ src = logo;
-+ for( y1 = 0; y1 < LOGO_H; y1++ )
-+ {
-+ dst = fb + p->var.xres*p->var.yres -1 - y1*line - x;
-+ for( x1 = 0; x1 < LOGO_W; x1++ )
-+ fb_writeb (*src++, dst--);
-+ }
-+ done = 1;
-+ } else {
-+ src = logo;
-+ for( y1 = 0; y1 < LOGO_H; y1++ ) {
-+ dst = fb + y1*line + x;
-+ for( x1 = 0; x1 < LOGO_W; x1++ )
-+ fb_writeb (*src++, dst++);
-+ }
-+ done = 1;
-+ }
- }
- #endif
- #if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_ILBM) || \
---- linux-2.4.21/drivers/video/fbmem.c~fb-buffered
-+++ linux-2.4.21/drivers/video/fbmem.c
-@@ -302,7 +302,7 @@
- { "sa1100", sa1100fb_init, NULL },
- #endif
- #ifdef CONFIG_FB_PXA
-- { "pxa", pxafb_init, NULL },
-+ { "pxa", pxafb_init, NULL },
- #endif
- #ifdef CONFIG_FB_SUN3
- { "sun3", sun3fb_init, sun3fb_setup },
-@@ -672,7 +672,11 @@
- #elif defined(__hppa__)
- pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
- #elif defined(__ia64__) || defined(__arm__)
-+#ifdef CONFIG_PXA
-+ vma->vm_page_prot = pgprot_noncached_buffered(vma->vm_page_prot);
-+#else
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
-+#endif
- #elif defined(__hppa__)
- pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
- #else
---- linux-2.4.21/drivers/video/pxafb.c~ramses-lcd
-+++ linux-2.4.21/drivers/video/pxafb.c
-@@ -45,8 +45,6 @@
-
- #include <video/fbcon.h>
- #include <video/fbcon-mfb.h>
--#include <video/fbcon-cfb4.h>
--#include <video/fbcon-cfb8.h>
- #include <video/fbcon-cfb16.h>
- #include <video/lcdctrl.h> /* brightness, contrast, etc. control */
-
-@@ -57,7 +55,7 @@
- /*
- * Complain if VAR is out of range.
- */
--#define DEBUG_VAR 1
-+#define DEBUG_VAR 0
-
- #undef ASSABET_PAL_VIDEO
-
-@@ -66,16 +64,6 @@
- void (*pxafb_blank_helper)(int blank);
- EXPORT_SYMBOL(pxafb_blank_helper);
-
--/*
-- * IMHO this looks wrong. In 8BPP, length should be 8.
-- */
--static struct pxafb_rgb rgb_8 = {
-- red: { offset: 0, length: 4, },
-- green: { offset: 0, length: 4, },
-- blue: { offset: 0, length: 4, },
-- transp: { offset: 0, length: 0, },
--};
--
- static struct pxafb_rgb def_rgb_16 = {
- red: { offset: 11, length: 5, },
- green: { offset: 5, length: 6, },
-@@ -99,10 +87,29 @@
- lccr3: LCD_LCCR3
- };
-
-+static struct pxafb_mach_info torisan_fb_info __initdata = {
-+ pixclock: 30000,
-+ bpp: LCD_BPP,
-+ xres: 320,
-+ yres: 240,
-+ hsync_len: 2,
-+ vsync_len: 2,
-+ left_margin: 1,
-+ upper_margin: 4,
-+ right_margin: 139,
-+ lower_margin: 4,
-+ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-+ lccr0: LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_QDM | LCCR0_BM | LCCR0_OUM | LCCR0_PAS,
-+ lccr3: 0x04700007
-+};
-+
- static struct pxafb_mach_info * __init
- pxafb_get_machine_info(struct pxafb_info *fbi)
- {
-- return &pxa_fb_info;
-+ if (ramses_lcd_type == 2)
-+ return &torisan_fb_info;
-+ else
-+ return &pxa_fb_info;
- }
-
- static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);
-@@ -276,13 +283,7 @@
- * 16 bits works apparemtly fine in passive mode for those,
- * so don't complain
- */
-- if (machine_is_lubbock() ||
-- machine_is_pxa_cerf()) {
-- ret = 0;
-- } else
-- /* make sure we are in active mode */
-- if ((fbi->lccr0 & LCCR0_PAS))
-- ret = 0;
-+ ret = 0;
- break;
- #endif
- default:
-@@ -671,7 +672,7 @@
- static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi)
- {
- struct pxafb_lcd_reg new_regs;
--// u_int pcd = get_pcd(var->pixclock);
-+ u_int pcd = get_pcd(var->pixclock);
- u_long flags;
-
- DPRINTK("Configuring PXA LCD\n");
-@@ -710,7 +711,6 @@
- fbi->fb.fix.id, var->lower_margin);
- #endif
-
--#if defined (CONFIG_PXA_CERF_PDA)
- new_regs.lccr0 = fbi->lccr0;
- new_regs.lccr1 =
- LCCR1_DisWdth(var->xres) +
-@@ -728,47 +728,9 @@
- |
- (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
- (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
--#elif defined (CONFIG_FB_PXA_QVGA)
-- new_regs.lccr0 = fbi->lccr0;
-- new_regs.lccr1 =
-- LCCR1_DisWdth(var->xres) +
-- LCCR1_HorSnchWdth(var->hsync_len) +
-- LCCR1_BegLnDel(var->left_margin) +
-- LCCR1_EndLnDel(var->right_margin);
-- new_regs.lccr2 =
-- LCCR2_DisHght(var->yres) +
-- LCCR2_VrtSnchWdth(var->vsync_len) +
-- LCCR2_BegFrmDel(var->upper_margin) +
-- LCCR2_EndFrmDel(var->lower_margin);
-- new_regs.lccr3 = fbi->lccr3;
--#else
-- // FIXME using hardcoded values for now
-- new_regs.lccr0 = fbi->lccr0;
--// |
--// LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
--// LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
--
-- new_regs.lccr1 = 0x3030A7F;
--// LCCR1_DisWdth(var->xres) +
--// LCCR1_HorSnchWdth(var->hsync_len) +
--// LCCR1_BegLnDel(var->left_margin) +
--// LCCR1_EndLnDel(var->right_margin);
--
-- new_regs.lccr2 = 0x4EF;
--// LCCR2_DisHght(var->yres) +
--// LCCR2_VrtSnchWdth(var->vsync_len) +
--// LCCR2_BegFrmDel(var->upper_margin) +
--// LCCR2_EndFrmDel(var->lower_margin);
-
-- new_regs.lccr3 = fbi->lccr3;
--// |
--// (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
--// (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL) |
--// LCCR3_ACBsCntOff;
--#endif
--
--// if (pcd)
--// new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
-+ if (pcd)
-+ new_regs.lccr3 = (new_regs.lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
-
- DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0);
- DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1);
-@@ -820,25 +782,6 @@
- fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */
- }
-
-- DPRINTK("fbi->dmadesc_fblow_cpu = 0x%x\n", fbi->dmadesc_fblow_cpu);
-- DPRINTK("fbi->dmadesc_fbhigh_cpu = 0x%x\n", fbi->dmadesc_fbhigh_cpu);
-- DPRINTK("fbi->dmadesc_palette_cpu = 0x%x\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);
--
- fbi->reg_lccr0 = new_regs.lccr0;
- fbi->reg_lccr1 = new_regs.lccr1;
- fbi->reg_lccr2 = new_regs.lccr2;
-@@ -873,15 +816,11 @@
- {
- DPRINTK("backlight on\n");
-
--#ifdef CONFIG_ARCH_PXA_IDP
-- if(machine_is_pxa_idp()) {
-- FB_BACKLIGHT_ON();
-- }
--#endif
-+ ramses_lcd_backlight_on();
- }
-
- /*
-- * FIXME: move LCD power stuf into pxafb_power_down_lcd()
-+ * FIXME: move LCD power stuff into pxafb_power_down_lcd()
- * Also, I'm expecting that the backlight stuff should
- * be handled differently.
- */
-@@ -889,12 +828,7 @@
- {
- DPRINTK("backlight off\n");
-
--#ifdef CONFIG_ARCH_PXA_IDP
-- if(machine_is_pxa_idp()) {
-- FB_BACKLIGHT_OFF();
-- }
--#endif
--
-+ ramses_lcd_backlight_off();
- }
-
- static void pxafb_power_up_lcd(struct pxafb_info *fbi)
-@@ -902,38 +836,16 @@
- DPRINTK("LCD power on\n");
- CKEN |= CKEN16_LCD;
-
-- if(machine_is_pxa_cerf()) {
-- lcdctrl_enable();
-- }
--
--#if CONFIG_ARCH_PXA_IDP
-- /* set GPIOs, etc */
-- if(machine_is_pxa_idp()) {
-- // FIXME need to add proper delays
-- FB_PWR_ON();
-- FB_VLCD_ON(); // FIXME this should be after scanning starts
-- }
--#endif
-+ ramses_lcd_power_on();
- }
-
- static void pxafb_power_down_lcd(struct pxafb_info *fbi)
- {
- DPRINTK("LCD power off\n");
-- CKEN &= ~CKEN16_LCD;
--
-- if(machine_is_pxa_cerf()) {
-- lcdctrl_disable();
-- }
-
-- /* set GPIOs, etc */
--#if CONFIG_ARCH_PXA_IDP
-- if(machine_is_pxa_idp()) {
-- // FIXME need to add proper delays
-- FB_PWR_OFF();
-- FB_VLCD_OFF(); // FIXME this should be before scanning stops
-- }
--#endif
-+ ramses_lcd_power_off();
-
-+ CKEN &= ~CKEN16_LCD;
- }
-
- static void pxafb_setup_gpio(struct pxafb_info *fbi)
-@@ -1082,6 +994,8 @@
- if (old_state != C_DISABLE) {
- fbi->state = state;
-
-+ ramses_lcd_power_off();
-+
- pxafb_backlight_off(fbi);
- if (old_state != C_DISABLE_CLKCHANGE)
- pxafb_disable_controller(fbi);
-@@ -1191,6 +1105,7 @@
-
- if (state == 0) {
- /* Enter D0. */
-+//printk("--> pxafb_pm_callback(%d)\n", req);
- set_ctrlr_state(fbi, C_ENABLE);
- } else {
- /* Enter D1-D3. Disable the LCD controller. */
-@@ -1300,7 +1215,6 @@
- fbi->fb.disp = (struct display *)(fbi + 1);
- fbi->fb.pseudo_palette = (void *)(fbi->fb.disp + 1);
-
-- fbi->rgb[RGB_8] = &rgb_8;
- fbi->rgb[RGB_16] = &def_rgb_16;
-
- inf = pxafb_get_machine_info(fbi);
-@@ -1348,11 +1262,6 @@
- if (!fbi)
- goto failed;
-
-- if(machine_is_pxa_cerf()) {
-- // brightness&contrast is handled via lcdctrl.
-- lcdctrl_init();
-- }
--
- /* Initialize video memory */
- ret = pxafb_map_video_memory(fbi);
- if (ret)
---- linux-2.4.21/drivers/video/pxafb.h~ramses-lcd
-+++ linux-2.4.21/drivers/video/pxafb.h
-@@ -235,4 +235,22 @@
- #define LCD_LCCR0 (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_QDM | LCCR0_BM | LCCR0_OUM)
- #define LCD_LCCR3 (LCCR3_PCP | LCCR3_PixClkDiv(0x12) | LCCR3_Bpp(PXAFB_BPP_BITS) | LCCR3_Acb(0x18))
-
-+#elif defined CONFIG_ARCH_RAMSES
-+#define LCD_PIXCLOCK 100000
-+#define LCD_BPP PXAFB_BPP
-+#define LCD_XRES 240
-+#define LCD_YRES 320
-+#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH 6
-+#define LCD_VERTICAL_SYNC_PULSE_WIDTH 1
-+#define LCD_BEGIN_OF_LINE_WAIT_COUNT 21
-+#define LCD_BEGIN_FRAME_WAIT_COUNT 7
-+#define LCD_END_OF_LINE_WAIT_COUNT 21
-+#define LCD_END_OF_FRAME_WAIT_COUNT 1
-+#define LCD_SYNC (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT)
-+#define LCD_LCCR0 (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_QDM | LCCR0_BM | LCCR0_OUM)
-+#define LCD_LCCR3 (LCCR3_PCP | LCCR3_Bpp(PXAFB_BPP_BITS) | LCCR3_Acb(0xe))
-+
-+// PCD 21 ist noch ok
-+// PIXCLOCK 150000 ergibt LCCR3_PCD von 15
-+
- #endif
---- linux-2.4.21/fs/Config.in~mtd-cvs
-+++ linux-2.4.21/fs/Config.in
-@@ -45,6 +45,18 @@
- dep_tristate 'Journalling Flash File System v2 (JFFS2) support' CONFIG_JFFS2_FS $CONFIG_MTD
- if [ "$CONFIG_JFFS2_FS" = "y" -o "$CONFIG_JFFS2_FS" = "m" ] ; then
- int 'JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0
-+ bool 'JFFS2 write-buffering support' CONFIG_JFFS2_FS_WRITEBUFFER
-+ bool 'JFFS2 ZLIB compression support (recommended)' CONFIG_JFFS2_ZLIB
-+ bool 'JFFS2 RTIME compression support (recommended)' CONFIG_JFFS2_RTIME
-+ bool 'JFFS2 RUBIN compression support' CONFIG_JFFS2_RUBIN
-+ bool 'JFFS2 LZO compression support' CONFIG_JFFS2_LZO
-+ bool 'JFFS2 LZARI compression support' CONFIG_JFFS2_LZARI
-+ choice 'JFFS2 default compression mode' \
-+ "none CONFIG_JFFS2_CMODE_NONE \
-+ priority CONFIG_JFFS2_CMODE_PRIORITY \
-+ size CONFIG_JFFS2_CMODE_SIZE" priority
-+
-+ bool 'JFFS2 proc interface support' CONFIG_JFFS2_PROC
- fi
- tristate 'Compressed ROM file system support' CONFIG_CRAMFS
- dep_mbool ' Use linear addressing for cramfs' CONFIG_CRAMFS_LINEAR $CONFIG_CRAMFS
---- linux-2.4.21/fs/inode.c~mtd-cvs
-+++ linux-2.4.21/fs/inode.c
-@@ -942,6 +942,38 @@
-
- }
-
-+/**
-+ * ilookup - search for an inode in the inode cache
-+ * @sb: super block of file system to search
-+ * @ino: inode number to search for
-+ *
-+ * If the inode is in the cache, the inode is returned with an
-+ * incremented reference count.
-+ *
-+ * Otherwise, %NULL is returned.
-+ *
-+ * This is almost certainly not the function you are looking for.
-+ * If you think you need to use this, consult an expert first.
-+ */
-+struct inode *ilookup(struct super_block *sb, unsigned long ino)
-+{
-+ struct list_head * head = inode_hashtable + hash(sb,ino);
-+ struct inode * inode;
-+
-+ spin_lock(&inode_lock);
-+ inode = find_inode(sb, ino, head, NULL, NULL);
-+ if (inode) {
-+ __iget(inode);
-+ spin_unlock(&inode_lock);
-+ wait_on_inode(inode);
-+ return inode;
-+ }
-+ spin_unlock(&inode_lock);
-+
-+ return inode;
-+}
-+
-+
- struct inode *igrab(struct inode *inode)
- {
- spin_lock(&inode_lock);
---- linux-2.4.21/fs/jffs2/Makefile~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/Makefile
-@@ -1,25 +1,42 @@
- #
--# Makefile for the linux Journalling Flash FileSystem (JFFS) routines.
--#
--# $Id: Makefile,v 1.25.2.1 2002/10/11 09:04:44 dwmw2 Exp $
--#
--# Note! Dependencies are done automagically by 'make dep', which also
--# removes any old dependencies. DON'T put your own dependencies here
--# unless it's something special (ie not a .c file).
-+# fs/jffs2/Makefile.24
- #
--# Note 2! The CFLAGS definitions are now in the main makefile...
-+# $Id: Makefile,v 1.43 2003/10/06 12:54:49 dwmw2 Exp $
-
-+ifdef OUT_OF_TREE_BUILD
-+include $(mtd)/defconfig
-
--COMPR_OBJS := compr.o compr_rubin.o compr_rtime.o pushpull.o \
-- compr_zlib.o
--JFFS2_OBJS := crc32.o dir.o file.o ioctl.o nodelist.o malloc.o \
-- read.o nodemgmt.o readinode.o super.o write.o scan.o gc.o \
-- symlink.o build.o erase.o background.o
-+# This must be first in the include path, so it goes in $(CC) rather
-+# then $(EXTRA_CFLAGS)
-
--O_TARGET := jffs2.o
-+CC += -I$(mtd)/../../include
-+EXTRA_CFLAGS := -g -Werror
-
--obj-y := $(COMPR_OBJS) $(JFFS2_OBJS)
--obj-m := $(O_TARGET)
-+ifndef CONFIG_MTD
-+EXTRA_CFLAGS += -DMTD_OUT_OF_TREE
-+endif
-+
-+ifdef NONAND
-+EXTRA_CFLAGS += -DNONAND
-+endif
-+endif
-+
-+obj-$(CONFIG_JFFS2_FS) += jffs2.o
-+
-+JFFS2_OBJS := compr.o dir.o file.o ioctl.o nodelist.o malloc.o
-+JFFS2_OBJS += read.o nodemgmt.o readinode.o write.o scan.o gc.o
-+JFFS2_OBJS += symlink-v24.o build.o erase.o background.o fs.o writev.o
-+
-+LINUX_OBJS += super-v24.o crc32.o rbtree.o
-+
-+WBUF_OBJS-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o
-+
-+COMPR_OBJS-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o
-+COMPR_OBJS-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
-+COMPR_OBJS-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o
-+
-+obj-y := $(COMPR_OBJS-y) $(JFFS2_OBJS) $(LINUX_OBJS) $(WBUF_OBJS-y)
-+O_TARGET := jffs2.o
-
- include $(TOPDIR)/Rules.make
-
---- /dev/null
-+++ linux-2.4.21/fs/jffs2/Makefile.common
-@@ -0,0 +1,17 @@
-+#
-+# Makefile for the Linux Journalling Flash File System v2 (JFFS2)
-+#
-+# $Id: Makefile.common,v 1.9 2005/02/09 09:23:53 pavlov Exp $
-+#
-+
-+obj-$(CONFIG_JFFS2_FS) += jffs2.o
-+
-+jffs2-y := compr.o dir.o file.o ioctl.o nodelist.o malloc.o
-+jffs2-y += read.o nodemgmt.o readinode.o write.o scan.o gc.o
-+jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o
-+jffs2-y += super.o
-+
-+jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o
-+jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o
-+jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
-+jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o
---- linux-2.4.21/fs/jffs2/background.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/background.c
-@@ -1,61 +1,32 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: background.c,v 1.16 2001/10/08 09:22:38 dwmw2 Exp $
-+ * $Id: background.c,v 1.50 2004/11/16 20:36:10 dwmw2 Exp $
- *
- */
-
--#define __KERNEL_SYSCALLS__
--
- #include <linux/kernel.h>
--#include <linux/sched.h>
--#include <linux/unistd.h>
- #include <linux/jffs2.h>
- #include <linux/mtd/mtd.h>
--#include <linux/interrupt.h>
- #include <linux/completion.h>
-+#include <linux/suspend.h>
- #include "nodelist.h"
-
-
- static int jffs2_garbage_collect_thread(void *);
--static int thread_should_wake(struct jffs2_sb_info *c);
-
- void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
- {
-- spin_lock_bh(&c->erase_completion_lock);
-- if (c->gc_task && thread_should_wake(c))
-+ spin_lock(&c->erase_completion_lock);
-+ if (c->gc_task && jffs2_thread_should_wake(c))
- send_sig(SIGHUP, c->gc_task, 1);
-- spin_unlock_bh(&c->erase_completion_lock);
-+ spin_unlock(&c->erase_completion_lock);
- }
-
- /* This must only ever be called when no GC thread is currently running */
-@@ -86,12 +57,12 @@
-
- void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c)
- {
-- spin_lock_bh(&c->erase_completion_lock);
-+ spin_lock(&c->erase_completion_lock);
- if (c->gc_task) {
- D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid));
- send_sig(SIGKILL, c->gc_task, 1);
- }
-- spin_unlock_bh(&c->erase_completion_lock);
-+ spin_unlock(&c->erase_completion_lock);
- wait_for_completion(&c->gc_thread_exit);
- }
-
-@@ -99,34 +70,37 @@
- {
- struct jffs2_sb_info *c = _c;
-
-- daemonize();
-- current->tty = NULL;
-+ daemonize("jffs2_gcd_mtd%d", c->mtd->index);
-+ allow_signal(SIGKILL);
-+ allow_signal(SIGSTOP);
-+ allow_signal(SIGCONT);
-+
- c->gc_task = current;
- up(&c->gc_thread_start);
-
-- sprintf(current->comm, "jffs2_gcd_mtd%d", c->mtd->index);
--
-- /* FIXME in the 2.2 backport */
-- current->nice = 10;
-+ set_user_nice(current, 10);
-
- for (;;) {
-- spin_lock_irq(&current->sigmask_lock);
-- siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
-- recalc_sigpending(current);
-- spin_unlock_irq(&current->sigmask_lock);
-+ allow_signal(SIGHUP);
-
-- if (!thread_should_wake(c)) {
-+ if (!jffs2_thread_should_wake(c)) {
- set_current_state (TASK_INTERRUPTIBLE);
- D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n"));
-- /* Yes, there's a race here; we checked thread_should_wake() before
-- setting current->state to TASK_INTERRUPTIBLE. But it doesn't
-+ /* Yes, there's a race here; we checked jffs2_thread_should_wake()
-+ before setting current->state to TASK_INTERRUPTIBLE. But it doesn't
- matter - We don't care if we miss a wakeup, because the GC thread
- is only an optimisation anyway. */
- schedule();
- }
-
-- if (current->need_resched)
-- schedule();
-+ if (current->flags & PF_FREEZE) {
-+ refrigerator(0);
-+ /* refrigerator() should recalc sigpending for us
-+ but doesn't. No matter - allow_signal() will. */
-+ continue;
-+ }
-+
-+ cond_resched();
-
- /* Put_super will send a SIGKILL and then wait on the sem.
- */
-@@ -134,9 +108,7 @@
- siginfo_t info;
- unsigned long signr;
-
-- spin_lock_irq(&current->sigmask_lock);
-- signr = dequeue_signal(&current->blocked, &info);
-- spin_unlock_irq(&current->sigmask_lock);
-+ signr = dequeue_signal_lock(current, &current->blocked, &info);
-
- switch(signr) {
- case SIGSTOP:
-@@ -147,37 +119,27 @@
-
- case SIGKILL:
- D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGKILL received.\n"));
-- spin_lock_bh(&c->erase_completion_lock);
-- c->gc_task = NULL;
-- spin_unlock_bh(&c->erase_completion_lock);
-- complete_and_exit(&c->gc_thread_exit, 0);
-+ goto die;
-
- case SIGHUP:
- D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGHUP received.\n"));
- break;
- default:
- D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): signal %ld received\n", signr));
--
- }
- }
- /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
-- spin_lock_irq(&current->sigmask_lock);
-- siginitsetinv (&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
-- recalc_sigpending(current);
-- spin_unlock_irq(&current->sigmask_lock);
-+ disallow_signal(SIGHUP);
-
- D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): pass\n"));
-- jffs2_garbage_collect_pass(c);
-+ if (jffs2_garbage_collect_pass(c) == -ENOSPC) {
-+ printk(KERN_NOTICE "No space for garbage collection. Aborting GC thread\n");
-+ goto die;
- }
--}
--
--static int thread_should_wake(struct jffs2_sb_info *c)
--{
-- D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x\n",
-- c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size));
-- if (c->nr_free_blocks + c->nr_erasing_blocks < JFFS2_RESERVED_BLOCKS_GCTRIGGER &&
-- c->dirty_size > c->sector_size)
-- return 1;
-- else
-- return 0;
-+ }
-+ die:
-+ spin_lock(&c->erase_completion_lock);
-+ c->gc_task = NULL;
-+ spin_unlock(&c->erase_completion_lock);
-+ complete_and_exit(&c->gc_thread_exit, 0);
- }
---- linux-2.4.21/fs/jffs2/build.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/build.c
-@@ -1,47 +1,24 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: build.c,v 1.16.2.3 2003/04/30 09:43:32 dwmw2 Exp $
-+ * $Id: build.c,v 1.70 2005/02/28 08:21:05 dedekind Exp $
- *
- */
-
- #include <linux/kernel.h>
--#include <linux/jffs2.h>
-+#include <linux/sched.h>
- #include <linux/slab.h>
-+#include <linux/vmalloc.h>
-+#include <linux/mtd/mtd.h>
- #include "nodelist.h"
-
--int jffs2_build_inode_pass1(struct jffs2_sb_info *, struct jffs2_inode_cache *);
--int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *);
-+static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *, struct jffs2_full_dirent **);
-
- static inline struct jffs2_inode_cache *
- first_inode_chain(int *i, struct jffs2_sb_info *c)
-@@ -68,38 +45,80 @@
- ic; \
- ic = next_inode(&i, ic, (c)))
-
-+
-+static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
-+{
-+ struct jffs2_full_dirent *fd;
-+
-+ D1(printk(KERN_DEBUG "jffs2_build_inode building directory inode #%u\n", ic->ino));
-+
-+ /* For each child, increase nlink */
-+ for(fd = ic->scan_dents; fd; fd = fd->next) {
-+ struct jffs2_inode_cache *child_ic;
-+ if (!fd->ino)
-+ continue;
-+
-+ /* XXX: Can get high latency here with huge directories */
-+
-+ child_ic = jffs2_get_ino_cache(c, fd->ino);
-+ if (!child_ic) {
-+ printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
-+ fd->name, fd->ino, ic->ino);
-+ jffs2_mark_node_obsolete(c, fd->raw);
-+ continue;
-+ }
-+
-+ if (child_ic->nlink++ && fd->type == DT_DIR) {
-+ printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino);
-+ if (fd->ino == 1 && ic->ino == 1) {
-+ printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n");
-+ printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n");
-+ }
-+ /* What do we do about it? */
-+ }
-+ D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino));
-+ /* Can't free them. We might need them in pass 2 */
-+ }
-+}
-+
- /* Scan plan:
- - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go
- - Scan directory tree from top down, setting nlink in inocaches
- - Scan inocaches for inodes with nlink==0
- */
--int jffs2_build_filesystem(struct jffs2_sb_info *c)
-+static int jffs2_build_filesystem(struct jffs2_sb_info *c)
- {
- int ret;
- int i;
- struct jffs2_inode_cache *ic;
-+ struct jffs2_full_dirent *fd;
-+ struct jffs2_full_dirent *dead_fds = NULL;
-
- /* First, scan the medium and build all the inode caches with
- lists of physical nodes */
-
-- c->flags |= JFFS2_SB_FLAG_MOUNTING;
-+ c->flags |= JFFS2_SB_FLAG_SCANNING;
- ret = jffs2_scan_medium(c);
-- c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
--
-+ c->flags &= ~JFFS2_SB_FLAG_SCANNING;
- if (ret)
-- return ret;
-+ goto exit;
-
- D1(printk(KERN_DEBUG "Scanned flash completely\n"));
-- /* Now build the data map for each inode, marking obsoleted nodes
-- as such, and also increase nlink of any children. */
-+ D2(jffs2_dump_block_lists(c));
-+
-+ c->flags |= JFFS2_SB_FLAG_BUILDING;
-+ /* Now scan the directory tree, increasing nlink according to every dirent found. */
- for_each_inode(i, c, ic) {
- D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino));
-- ret = jffs2_build_inode_pass1(c, ic);
-- if (ret) {
-- D1(printk(KERN_WARNING "Eep. jffs2_build_inode_pass1 for ino %d returned %d\n", ic->ino, ret));
-- return ret;
-+
-+ D1(BUG_ON(ic->ino > c->highest_ino));
-+
-+ if (ic->scan_dents) {
-+ jffs2_build_inode_pass1(c, ic);
-+ cond_resched();
- }
- }
-+
- D1(printk(KERN_DEBUG "Pass 1 complete\n"));
-
- /* Next, scan for inodes with nlink == 0 and remove them. If
-@@ -107,181 +126,249 @@
- children too, and repeat the scan. As that's going to be
- a fairly uncommon occurrence, it's not so evil to do it this
- way. Recursion bad. */
-- do {
-- D1(printk(KERN_DEBUG "Pass 2 (re)starting\n"));
-- ret = 0;
-+ D1(printk(KERN_DEBUG "Pass 2 starting\n"));
-+
- for_each_inode(i, c, ic) {
- D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes));
- if (ic->nlink)
- continue;
-
-- ret = jffs2_build_remove_unlinked_inode(c, ic);
-- if (ret)
-- break;
-- /* -EAGAIN means the inode's nlink was zero, so we deleted it,
-- and furthermore that it had children and their nlink has now
-- gone to zero too. So we have to restart the scan. */
-+ jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
-+ cond_resched();
-+ }
-+
-+ D1(printk(KERN_DEBUG "Pass 2a starting\n"));
-+
-+ while (dead_fds) {
-+ fd = dead_fds;
-+ dead_fds = fd->next;
-+
-+ ic = jffs2_get_ino_cache(c, fd->ino);
-+ D1(printk(KERN_DEBUG "Removing dead_fd ino #%u (\"%s\"), ic at %p\n", fd->ino, fd->name, ic));
-+
-+ if (ic)
-+ jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
-+ jffs2_free_full_dirent(fd);
- }
-- } while(ret == -EAGAIN);
-
- D1(printk(KERN_DEBUG "Pass 2 complete\n"));
-
-- /* Finally, we can scan again and free the dirent nodes and scan_info structs */
-+ /* Finally, we can scan again and free the dirent structs */
- for_each_inode(i, c, ic) {
-- struct jffs2_scan_info *scan = ic->scan;
-- struct jffs2_full_dirent *fd;
- D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes));
-- if (!scan) {
-- if (ic->nlink) {
-- D1(printk(KERN_WARNING "Why no scan struct for ino #%u which has nlink %d?\n", ic->ino, ic->nlink));
-+
-+ while(ic->scan_dents) {
-+ fd = ic->scan_dents;
-+ ic->scan_dents = fd->next;
-+ jffs2_free_full_dirent(fd);
- }
-- continue;
-+ ic->scan_dents = NULL;
-+ cond_resched();
- }
-- ic->scan = NULL;
-- while(scan->dents) {
-- fd = scan->dents;
-- scan->dents = fd->next;
-+ c->flags &= ~JFFS2_SB_FLAG_BUILDING;
-+
-+ D1(printk(KERN_DEBUG "Pass 3 complete\n"));
-+ D2(jffs2_dump_block_lists(c));
-+
-+ /* Rotate the lists by some number to ensure wear levelling */
-+ jffs2_rotate_lists(c);
-+
-+ ret = 0;
-+
-+exit:
-+ if (ret) {
-+ for_each_inode(i, c, ic) {
-+ while(ic->scan_dents) {
-+ fd = ic->scan_dents;
-+ ic->scan_dents = fd->next;
- jffs2_free_full_dirent(fd);
- }
-- kfree(scan);
- }
-- D1(printk(KERN_DEBUG "Pass 3 complete\n"));
-+ }
-
- return ret;
- }
-
--int jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
-+static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, struct jffs2_full_dirent **dead_fds)
- {
-- struct jffs2_tmp_dnode_info *tn;
-+ struct jffs2_raw_node_ref *raw;
- struct jffs2_full_dirent *fd;
-- struct jffs2_node_frag *fraglist = NULL;
-- struct jffs2_tmp_dnode_info *metadata = NULL;
--
-- D1(printk(KERN_DEBUG "jffs2_build_inode building inode #%u\n", ic->ino));
-- if (ic->ino > c->highest_ino)
-- c->highest_ino = ic->ino;
--
-- if (!ic->scan->tmpnodes && ic->ino != 1) {
-- D1(printk(KERN_DEBUG "jffs2_build_inode: ino #%u has no data nodes!\n", ic->ino));
-- }
-- /* Build the list to make sure any obsolete nodes are marked as such */
-- while(ic->scan->tmpnodes) {
-- tn = ic->scan->tmpnodes;
-- ic->scan->tmpnodes = tn->next;
-
-- if (metadata && tn->version > metadata->version) {
-- D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring old metadata at 0x%08x\n",
-- metadata->fn->raw->flash_offset &~3));
-+ D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino));
-
-- jffs2_free_full_dnode(metadata->fn);
-- jffs2_free_tmp_dnode_info(metadata);
-- metadata = NULL;
-+ raw = ic->nodes;
-+ while (raw != (void *)ic) {
-+ struct jffs2_raw_node_ref *next = raw->next_in_ino;
-+ D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", ref_offset(raw)));
-+ jffs2_mark_node_obsolete(c, raw);
-+ raw = next;
- }
-
-- if (tn->fn->size) {
-- jffs2_add_full_dnode_to_fraglist (c, &fraglist, tn->fn);
-- jffs2_free_tmp_dnode_info(tn);
-- } else {
-- if (!metadata) {
-- metadata = tn;
-- } else {
-- D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring new metadata at 0x%08x\n",
-- tn->fn->raw->flash_offset &~3));
--
-- jffs2_free_full_dnode(tn->fn);
-- jffs2_free_tmp_dnode_info(tn);
-- }
-- }
-- }
-+ if (ic->scan_dents) {
-+ int whinged = 0;
-+ D1(printk(KERN_DEBUG "Inode #%u was a directory which may have children...\n", ic->ino));
-
-- /* OK. Now clear up */
-- if (metadata) {
-- jffs2_free_full_dnode(metadata->fn);
-- jffs2_free_tmp_dnode_info(metadata);
-- }
-- metadata = NULL;
-+ while(ic->scan_dents) {
-+ struct jffs2_inode_cache *child_ic;
-
-- while (fraglist) {
-- struct jffs2_node_frag *frag;
-- frag = fraglist;
-- fraglist = fraglist->next;
-+ fd = ic->scan_dents;
-+ ic->scan_dents = fd->next;
-
-- if (frag->node && !(--frag->node->frags)) {
-- jffs2_free_full_dnode(frag->node);
-+ if (!fd->ino) {
-+ /* It's a deletion dirent. Ignore it */
-+ D1(printk(KERN_DEBUG "Child \"%s\" is a deletion dirent, skipping...\n", fd->name));
-+ jffs2_free_full_dirent(fd);
-+ continue;
- }
-- jffs2_free_node_frag(frag);
-+ if (!whinged) {
-+ whinged = 1;
-+ printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino);
- }
-
-- /* Now for each child, increase nlink */
-- for(fd=ic->scan->dents; fd; fd = fd->next) {
-- struct jffs2_inode_cache *child_ic;
-- if (!fd->ino)
-- continue;
-+ D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n",
-+ fd->name, fd->ino));
-
- child_ic = jffs2_get_ino_cache(c, fd->ino);
- if (!child_ic) {
-- printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
-- fd->name, fd->ino, ic->ino);
-+ printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino);
-+ jffs2_free_full_dirent(fd);
- continue;
- }
-
-- if (child_ic->nlink++ && fd->type == DT_DIR) {
-- printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino);
-- if (fd->ino == 1 && ic->ino == 1) {
-- printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n");
-- printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n");
-+ /* Reduce nlink of the child. If it's now zero, stick it on the
-+ dead_fds list to be cleaned up later. Else just free the fd */
-+
-+ child_ic->nlink--;
-+
-+ if (!child_ic->nlink) {
-+ D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got zero nlink. Adding to dead_fds list.\n",
-+ fd->ino, fd->name));
-+ fd->next = *dead_fds;
-+ *dead_fds = fd;
-+ } else {
-+ D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got nlink %d. Ignoring.\n",
-+ fd->ino, fd->name, child_ic->nlink));
-+ jffs2_free_full_dirent(fd);
- }
-- /* What do we do about it? */
- }
-- D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino));
-- /* Can't free them. We might need them in pass 2 */
- }
-- return 0;
-+
-+ /*
-+ We don't delete the inocache from the hash list and free it yet.
-+ The erase code will do that, when all the nodes are completely gone.
-+ */
- }
-
--int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
-+static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
- {
-- struct jffs2_raw_node_ref *raw;
-- struct jffs2_full_dirent *fd;
-- int ret = 0;
-+ uint32_t size;
-
-- if(!ic->scan) {
-- D1(printk(KERN_DEBUG "ino #%u was already removed\n", ic->ino));
-- return 0;
-- }
-+ /* Deletion should almost _always_ be allowed. We're fairly
-+ buggered once we stop allowing people to delete stuff
-+ because there's not enough free space... */
-+ c->resv_blocks_deletion = 2;
-
-- D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino));
-+ /* Be conservative about how much space we need before we allow writes.
-+ On top of that which is required for deletia, require an extra 2%
-+ of the medium to be available, for overhead caused by nodes being
-+ split across blocks, etc. */
-
-- for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_ino) {
-- D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", raw->flash_offset&~3));
-- jffs2_mark_node_obsolete(c, raw);
-- }
-+ size = c->flash_size / 50; /* 2% of flash size */
-+ size += c->nr_blocks * 100; /* And 100 bytes per eraseblock */
-+ size += c->sector_size - 1; /* ... and round up */
-
-- if (ic->scan->dents) {
-- printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino);
-+ c->resv_blocks_write = c->resv_blocks_deletion + (size / c->sector_size);
-
-- while(ic->scan->dents) {
-- struct jffs2_inode_cache *child_ic;
-+ /* When do we let the GC thread run in the background */
-
-- fd = ic->scan->dents;
-- ic->scan->dents = fd->next;
-+ c->resv_blocks_gctrigger = c->resv_blocks_write + 1;
-
-- D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n",
-- fd->name, fd->ino));
-+ /* When do we allow garbage collection to merge nodes to make
-+ long-term progress at the expense of short-term space exhaustion? */
-+ c->resv_blocks_gcmerge = c->resv_blocks_deletion + 1;
-
-- child_ic = jffs2_get_ino_cache(c, fd->ino);
-- if (!child_ic) {
-- printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino);
-- continue;
-+ /* When do we allow garbage collection to eat from bad blocks rather
-+ than actually making progress? */
-+ c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2;
-+
-+ /* If there's less than this amount of dirty space, don't bother
-+ trying to GC to make more space. It'll be a fruitless task */
-+ c->nospc_dirty_size = c->sector_size + (c->flash_size / 100);
-+
-+ D1(printk(KERN_DEBUG "JFFS2 trigger levels (size %d KiB, block size %d KiB, %d blocks)\n",
-+ c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks));
-+ D1(printk(KERN_DEBUG "Blocks required to allow deletion: %d (%d KiB)\n",
-+ c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024));
-+ D1(printk(KERN_DEBUG "Blocks required to allow writes: %d (%d KiB)\n",
-+ c->resv_blocks_write, c->resv_blocks_write*c->sector_size/1024));
-+ D1(printk(KERN_DEBUG "Blocks required to quiesce GC thread: %d (%d KiB)\n",
-+ c->resv_blocks_gctrigger, c->resv_blocks_gctrigger*c->sector_size/1024));
-+ D1(printk(KERN_DEBUG "Blocks required to allow GC merges: %d (%d KiB)\n",
-+ c->resv_blocks_gcmerge, c->resv_blocks_gcmerge*c->sector_size/1024));
-+ D1(printk(KERN_DEBUG "Blocks required to GC bad blocks: %d (%d KiB)\n",
-+ c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024));
-+ D1(printk(KERN_DEBUG "Amount of dirty space required to GC: %d bytes\n",
-+ c->nospc_dirty_size));
-+}
-+
-+int jffs2_do_mount_fs(struct jffs2_sb_info *c)
-+{
-+ int i;
-+
-+ c->free_size = c->flash_size;
-+ c->nr_blocks = c->flash_size / c->sector_size;
-+ if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
-+ c->blocks = vmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks);
-+ else
-+ c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
-+ if (!c->blocks)
-+ return -ENOMEM;
-+ for (i=0; i<c->nr_blocks; i++) {
-+ INIT_LIST_HEAD(&c->blocks[i].list);
-+ c->blocks[i].offset = i * c->sector_size;
-+ c->blocks[i].free_size = c->sector_size;
-+ c->blocks[i].dirty_size = 0;
-+ c->blocks[i].wasted_size = 0;
-+ c->blocks[i].unchecked_size = 0;
-+ c->blocks[i].used_size = 0;
-+ c->blocks[i].first_node = NULL;
-+ c->blocks[i].last_node = NULL;
-+ c->blocks[i].bad_count = 0;
- }
-- jffs2_free_full_dirent(fd);
-- child_ic->nlink--;
-+
-+ init_MUTEX(&c->alloc_sem);
-+ init_MUTEX(&c->erase_free_sem);
-+ init_waitqueue_head(&c->erase_wait);
-+ init_waitqueue_head(&c->inocache_wq);
-+ spin_lock_init(&c->erase_completion_lock);
-+ spin_lock_init(&c->inocache_lock);
-+
-+ INIT_LIST_HEAD(&c->clean_list);
-+ INIT_LIST_HEAD(&c->very_dirty_list);
-+ INIT_LIST_HEAD(&c->dirty_list);
-+ INIT_LIST_HEAD(&c->erasable_list);
-+ INIT_LIST_HEAD(&c->erasing_list);
-+ INIT_LIST_HEAD(&c->erase_pending_list);
-+ INIT_LIST_HEAD(&c->erasable_pending_wbuf_list);
-+ INIT_LIST_HEAD(&c->erase_complete_list);
-+ INIT_LIST_HEAD(&c->free_list);
-+ INIT_LIST_HEAD(&c->bad_list);
-+ INIT_LIST_HEAD(&c->bad_used_list);
-+ c->highest_ino = 1;
-+
-+ if (jffs2_build_filesystem(c)) {
-+ D1(printk(KERN_DEBUG "build_fs failed\n"));
-+ jffs2_free_ino_caches(c);
-+ jffs2_free_raw_node_refs(c);
-+ if (c->mtd->flags & MTD_NO_VIRTBLOCKS) {
-+ vfree(c->blocks);
-+ } else {
-+ kfree(c->blocks);
- }
-- ret = -EAGAIN;
-+ return -EIO;
- }
-- kfree(ic->scan);
-- ic->scan = NULL;
-- // jffs2_del_ino_cache(c, ic);
-- // jffs2_free_inode_cache(ic);
-- return ret;
-+
-+ jffs2_calc_trigger_levels(c);
-+
-+ return 0;
- }
---- linux-2.4.21/fs/jffs2/compr.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/compr.c
-@@ -1,151 +1,479 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- * Created by Arjan van de Ven <arjanv@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
-+ * University of Szeged, Hungary
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: compr.c,v 1.17 2001/09/23 09:56:46 dwmw2 Exp $
-+ * $Id: compr.c,v 1.43 2005/01/12 22:34:35 gleixner Exp $
- *
- */
-
--#include <linux/kernel.h>
--#include <linux/string.h>
--#include <linux/types.h>
--#include <linux/errno.h>
--#include <linux/jffs2.h>
-+#include "compr.h"
-
--int zlib_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen);
--void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen);
--int rtime_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen);
--void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen);
--int rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen);
--void rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen);
--int dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen);
--void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen);
-+static DEFINE_SPINLOCK(jffs2_compressor_list_lock);
-
-+/* Available compressors are on this list */
-+static LIST_HEAD(jffs2_compressor_list);
-+
-+/* Actual compression mode */
-+static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
-+
-+void jffs2_set_compression_mode(int mode)
-+{
-+ jffs2_compression_mode = mode;
-+}
-+
-+int jffs2_get_compression_mode(void)
-+{
-+ return jffs2_compression_mode;
-+}
-+
-+/* Statistics for blocks stored without compression */
-+static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
-
- /* jffs2_compress:
- * @data: Pointer to uncompressed data
-- * @cdata: Pointer to buffer for compressed data
-+ * @cdata: Pointer to returned pointer to buffer for compressed data
- * @datalen: On entry, holds the amount of data available for compression.
- * On exit, expected to hold the amount of data actually compressed.
- * @cdatalen: On entry, holds the amount of space available for compressed
- * data. On exit, expected to hold the actual size of the compressed
- * data.
- *
-- * Returns: Byte to be stored with data indicating compression type used.
-+ * Returns: Lower byte to be stored with data indicating compression type used.
- * Zero is used to show that the data could not be compressed - the
- * compressed version was actually larger than the original.
-+ * Upper byte will be used later. (soon)
- *
- * If the cdata buffer isn't large enough to hold all the uncompressed data,
- * jffs2_compress should compress as much as will fit, and should set
- * *datalen accordingly to show the amount of data which were compressed.
- */
--unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 *datalen, __u32 *cdatalen)
-+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 ret;
-+ int ret = JFFS2_COMPR_NONE;
-+ int compr_ret;
-+ struct jffs2_compressor *this, *best=NULL;
-+ unsigned char *output_buf = NULL, *tmp_buf;
-+ uint32_t orig_slen, orig_dlen;
-+ uint32_t best_slen=0, best_dlen=0;
-
-- ret = zlib_compress(data_in, cpage_out, datalen, cdatalen);
-- if (!ret) {
-- return JFFS2_COMPR_ZLIB;
-+ switch (jffs2_compression_mode) {
-+ case JFFS2_COMPR_MODE_NONE:
-+ break;
-+ case JFFS2_COMPR_MODE_PRIORITY:
-+ output_buf = kmalloc(*cdatalen,GFP_KERNEL);
-+ if (!output_buf) {
-+ printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n");
-+ goto out;
- }
--#if 0 /* Disabled 23/9/1. With zlib it hardly ever gets a look in */
-- ret = dynrubin_compress(data_in, cpage_out, datalen, cdatalen);
-- if (!ret) {
-- return JFFS2_COMPR_DYNRUBIN;
-+ orig_slen = *datalen;
-+ orig_dlen = *cdatalen;
-+ spin_lock(&jffs2_compressor_list_lock);
-+ list_for_each_entry(this, &jffs2_compressor_list, list) {
-+ /* Skip decompress-only backwards-compatibility and disabled modules */
-+ if ((!this->compress)||(this->disabled))
-+ continue;
-+
-+ this->usecount++;
-+ spin_unlock(&jffs2_compressor_list_lock);
-+ *datalen = orig_slen;
-+ *cdatalen = orig_dlen;
-+ compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL);
-+ spin_lock(&jffs2_compressor_list_lock);
-+ this->usecount--;
-+ if (!compr_ret) {
-+ ret = this->compr;
-+ this->stat_compr_blocks++;
-+ this->stat_compr_orig_size += *datalen;
-+ this->stat_compr_new_size += *cdatalen;
-+ break;
- }
--#endif
--#if 0 /* Disabled 26/2/1. Obsoleted by dynrubin */
-- ret = rubinmips_compress(data_in, cpage_out, datalen, cdatalen);
-- if (!ret) {
-- return JFFS2_COMPR_RUBINMIPS;
- }
--#endif
-- /* rtime does manage to recompress already-compressed data */
-- ret = rtime_compress(data_in, cpage_out, datalen, cdatalen);
-- if (!ret) {
-- return JFFS2_COMPR_RTIME;
-+ spin_unlock(&jffs2_compressor_list_lock);
-+ if (ret == JFFS2_COMPR_NONE) kfree(output_buf);
-+ break;
-+ case JFFS2_COMPR_MODE_SIZE:
-+ orig_slen = *datalen;
-+ orig_dlen = *cdatalen;
-+ spin_lock(&jffs2_compressor_list_lock);
-+ list_for_each_entry(this, &jffs2_compressor_list, list) {
-+ /* Skip decompress-only backwards-compatibility and disabled modules */
-+ if ((!this->compress)||(this->disabled))
-+ continue;
-+ /* Allocating memory for output buffer if necessary */
-+ if ((this->compr_buf_size<orig_dlen)&&(this->compr_buf)) {
-+ spin_unlock(&jffs2_compressor_list_lock);
-+ kfree(this->compr_buf);
-+ spin_lock(&jffs2_compressor_list_lock);
-+ this->compr_buf_size=0;
-+ this->compr_buf=NULL;
- }
--#if 0
-- /* We don't need to copy. Let the caller special-case the COMPR_NONE case. */
-- /* If we get here, no compression is going to work */
-- /* But we might want to use the fragmentation part -- Arjan */
-- memcpy(cpage_out,data_in,min(*datalen,*cdatalen));
-- if (*datalen > *cdatalen)
-+ if (!this->compr_buf) {
-+ spin_unlock(&jffs2_compressor_list_lock);
-+ tmp_buf = kmalloc(orig_dlen,GFP_KERNEL);
-+ spin_lock(&jffs2_compressor_list_lock);
-+ if (!tmp_buf) {
-+ printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
-+ continue;
-+ }
-+ else {
-+ this->compr_buf = tmp_buf;
-+ this->compr_buf_size = orig_dlen;
-+ }
-+ }
-+ this->usecount++;
-+ spin_unlock(&jffs2_compressor_list_lock);
-+ *datalen = orig_slen;
-+ *cdatalen = orig_dlen;
-+ compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL);
-+ spin_lock(&jffs2_compressor_list_lock);
-+ this->usecount--;
-+ if (!compr_ret) {
-+ if ((!best_dlen)||(best_dlen>*cdatalen)) {
-+ best_dlen = *cdatalen;
-+ best_slen = *datalen;
-+ best = this;
-+ }
-+ }
-+ }
-+ if (best_dlen) {
-+ *cdatalen = best_dlen;
-+ *datalen = best_slen;
-+ output_buf = best->compr_buf;
-+ best->compr_buf = NULL;
-+ best->compr_buf_size = 0;
-+ best->stat_compr_blocks++;
-+ best->stat_compr_orig_size += best_slen;
-+ best->stat_compr_new_size += best_dlen;
-+ ret = best->compr;
-+ }
-+ spin_unlock(&jffs2_compressor_list_lock);
-+ break;
-+ default:
-+ printk(KERN_ERR "JFFS2: unknow compression mode.\n");
-+ }
-+ out:
-+ if (ret == JFFS2_COMPR_NONE) {
-+ *cpage_out = data_in;
- *datalen = *cdatalen;
--#endif
-- return JFFS2_COMPR_NONE; /* We failed to compress */
--
-+ none_stat_compr_blocks++;
-+ none_stat_compr_size += *datalen;
-+ }
-+ else {
-+ *cpage_out = output_buf;
-+ }
-+ return ret;
- }
-
--
--int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in,
-- unsigned char *data_out, __u32 cdatalen, __u32 datalen)
-+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)
- {
-- switch (comprtype) {
-+ struct jffs2_compressor *this;
-+ int ret;
-+
-+ /* Older code had a bug where it would write non-zero 'usercompr'
-+ fields. Deal with it. */
-+ if ((comprtype & 0xff) <= JFFS2_COMPR_ZLIB)
-+ comprtype &= 0xff;
-+
-+ switch (comprtype & 0xff) {
- case JFFS2_COMPR_NONE:
- /* This should be special-cased elsewhere, but we might as well deal with it */
- memcpy(data_out, cdata_in, datalen);
-+ none_stat_decompr_blocks++;
- break;
--
- case JFFS2_COMPR_ZERO:
- memset(data_out, 0, datalen);
- break;
-+ default:
-+ spin_lock(&jffs2_compressor_list_lock);
-+ list_for_each_entry(this, &jffs2_compressor_list, list) {
-+ if (comprtype == this->compr) {
-+ this->usecount++;
-+ spin_unlock(&jffs2_compressor_list_lock);
-+ ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL);
-+ spin_lock(&jffs2_compressor_list_lock);
-+ if (ret) {
-+ printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret);
-+ }
-+ else {
-+ this->stat_decompr_blocks++;
-+ }
-+ this->usecount--;
-+ spin_unlock(&jffs2_compressor_list_lock);
-+ return ret;
-+ }
-+ }
-+ printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype);
-+ spin_unlock(&jffs2_compressor_list_lock);
-+ return -EIO;
-+ }
-+ return 0;
-+}
-
-- case JFFS2_COMPR_ZLIB:
-- zlib_decompress(cdata_in, data_out, cdatalen, datalen);
-- break;
-+int jffs2_register_compressor(struct jffs2_compressor *comp)
-+{
-+ struct jffs2_compressor *this;
-
-- case JFFS2_COMPR_RTIME:
-- rtime_decompress(cdata_in, data_out, cdatalen, datalen);
-- break;
-+ if (!comp->name) {
-+ printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n");
-+ return -1;
-+ }
-+ comp->compr_buf_size=0;
-+ comp->compr_buf=NULL;
-+ comp->usecount=0;
-+ comp->stat_compr_orig_size=0;
-+ comp->stat_compr_new_size=0;
-+ comp->stat_compr_blocks=0;
-+ comp->stat_decompr_blocks=0;
-+ D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name));
-+
-+ spin_lock(&jffs2_compressor_list_lock);
-+
-+ list_for_each_entry(this, &jffs2_compressor_list, list) {
-+ if (this->priority < comp->priority) {
-+ list_add(&comp->list, this->list.prev);
-+ goto out;
-+ }
-+ }
-+ list_add_tail(&comp->list, &jffs2_compressor_list);
-+out:
-+ D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
-+ printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
-+ })
-+
-+ spin_unlock(&jffs2_compressor_list_lock);
-+
-+ return 0;
-+}
-+
-+int jffs2_unregister_compressor(struct jffs2_compressor *comp)
-+{
-+ D2(struct jffs2_compressor *this;)
-+
-+ D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name));
-+
-+ spin_lock(&jffs2_compressor_list_lock);
-+
-+ if (comp->usecount) {
-+ spin_unlock(&jffs2_compressor_list_lock);
-+ printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n");
-+ return -1;
-+ }
-+ list_del(&comp->list);
-+
-+ D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
-+ printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
-+ })
-+ spin_unlock(&jffs2_compressor_list_lock);
-+ return 0;
-+}
-+
-+#ifdef CONFIG_JFFS2_PROC
-+
-+#define JFFS2_STAT_BUF_SIZE 16000
-+
-+char *jffs2_list_compressors(void)
-+{
-+ struct jffs2_compressor *this;
-+ char *buf, *act_buf;
-+
-+ act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL);
-+ list_for_each_entry(this, &jffs2_compressor_list, list) {
-+ act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority);
-+ if ((this->disabled)||(!this->compress))
-+ act_buf += sprintf(act_buf,"disabled");
-+ else
-+ act_buf += sprintf(act_buf,"enabled");
-+ act_buf += sprintf(act_buf,"\n");
-+ }
-+ return buf;
-+}
-+
-+char *jffs2_stats(void)
-+{
-+ struct jffs2_compressor *this;
-+ char *buf, *act_buf;
-+
-+ act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL);
-+
-+ act_buf += sprintf(act_buf,"JFFS2 compressor statistics:\n");
-+ act_buf += sprintf(act_buf,"%10s ","none");
-+ act_buf += sprintf(act_buf,"compr: %d blocks (%d) decompr: %d blocks\n", none_stat_compr_blocks,
-+ none_stat_compr_size, none_stat_decompr_blocks);
-+ spin_lock(&jffs2_compressor_list_lock);
-+ list_for_each_entry(this, &jffs2_compressor_list, list) {
-+ act_buf += sprintf(act_buf,"%10s ",this->name);
-+ if ((this->disabled)||(!this->compress))
-+ act_buf += sprintf(act_buf,"- ");
-+ else
-+ act_buf += sprintf(act_buf,"+ ");
-+ act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d) decompr: %d blocks ", this->stat_compr_blocks,
-+ this->stat_compr_new_size, this->stat_compr_orig_size,
-+ this->stat_decompr_blocks);
-+ act_buf += sprintf(act_buf,"\n");
-+ }
-+ spin_unlock(&jffs2_compressor_list_lock);
-+
-+ return buf;
-+}
-+
-+char *jffs2_get_compression_mode_name(void)
-+{
-+ switch (jffs2_compression_mode) {
-+ case JFFS2_COMPR_MODE_NONE:
-+ return "none";
-+ case JFFS2_COMPR_MODE_PRIORITY:
-+ return "priority";
-+ case JFFS2_COMPR_MODE_SIZE:
-+ return "size";
-+ }
-+ return "unkown";
-+}
-+
-+int jffs2_set_compression_mode_name(const char *name)
-+{
-+ if (!strcmp("none",name)) {
-+ jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
-+ return 0;
-+ }
-+ if (!strcmp("priority",name)) {
-+ jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
-+ return 0;
-+ }
-+ if (!strcmp("size",name)) {
-+ jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
-+ return 0;
-+ }
-+ return 1;
-+}
-+
-+static int jffs2_compressor_Xable(const char *name, int disabled)
-+{
-+ struct jffs2_compressor *this;
-+ spin_lock(&jffs2_compressor_list_lock);
-+ list_for_each_entry(this, &jffs2_compressor_list, list) {
-+ if (!strcmp(this->name, name)) {
-+ this->disabled = disabled;
-+ spin_unlock(&jffs2_compressor_list_lock);
-+ return 0;
-+ }
-+ }
-+ spin_unlock(&jffs2_compressor_list_lock);
-+ printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);
-+ return 1;
-+}
-+
-+int jffs2_enable_compressor_name(const char *name)
-+{
-+ return jffs2_compressor_Xable(name, 0);
-+}
-+
-+int jffs2_disable_compressor_name(const char *name)
-+{
-+ return jffs2_compressor_Xable(name, 1);
-+}
-+
-+int jffs2_set_compressor_priority(const char *name, int priority)
-+{
-+ struct jffs2_compressor *this,*comp;
-+ spin_lock(&jffs2_compressor_list_lock);
-+ list_for_each_entry(this, &jffs2_compressor_list, list) {
-+ if (!strcmp(this->name, name)) {
-+ this->priority = priority;
-+ comp = this;
-+ goto reinsert;
-+ }
-+ }
-+ spin_unlock(&jffs2_compressor_list_lock);
-+ printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);
-+ return 1;
-+reinsert:
-+ /* list is sorted in the order of priority, so if
-+ we change it we have to reinsert it into the
-+ good place */
-+ list_del(&comp->list);
-+ list_for_each_entry(this, &jffs2_compressor_list, list) {
-+ if (this->priority < comp->priority) {
-+ list_add(&comp->list, this->list.prev);
-+ spin_unlock(&jffs2_compressor_list_lock);
-+ return 0;
-+ }
-+ }
-+ list_add_tail(&comp->list, &jffs2_compressor_list);
-+ spin_unlock(&jffs2_compressor_list_lock);
-+ return 0;
-+}
-
-- case JFFS2_COMPR_RUBINMIPS:
--#if 0 /* Disabled 23/9/1 */
-- rubinmips_decompress(cdata_in, data_out, cdatalen, datalen);
--#else
-- printk(KERN_WARNING "JFFS2: Rubinmips compression encountered but support not compiled in!\n");
- #endif
-- break;
-- case JFFS2_COMPR_DYNRUBIN:
--#if 1 /* Phase this one out */
-- dynrubin_decompress(cdata_in, data_out, cdatalen, datalen);
-+
-+void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
-+{
-+ if (orig != comprbuf)
-+ kfree(comprbuf);
-+}
-+
-+int jffs2_compressors_init(void)
-+{
-+/* Registering compressors */
-+#ifdef CONFIG_JFFS2_ZLIB
-+ jffs2_zlib_init();
-+#endif
-+#ifdef CONFIG_JFFS2_RTIME
-+ jffs2_rtime_init();
-+#endif
-+#ifdef CONFIG_JFFS2_RUBIN
-+ jffs2_rubinmips_init();
-+ jffs2_dynrubin_init();
-+#endif
-+#ifdef CONFIG_JFFS2_LZARI
-+ jffs2_lzari_init();
-+#endif
-+#ifdef CONFIG_JFFS2_LZO
-+ jffs2_lzo_init();
-+#endif
-+/* Setting default compression mode */
-+#ifdef CONFIG_JFFS2_CMODE_NONE
-+ jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
-+ D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");)
- #else
-- printk(KERN_WARNING "JFFS2: Dynrubin compression encountered but support not compiled in!\n");
-+#ifdef CONFIG_JFFS2_CMODE_SIZE
-+ jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
-+ D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");)
-+#else
-+ D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");)
- #endif
-- break;
-+#endif
-+ return 0;
-+}
-
-- default:
-- printk(KERN_NOTICE "Unknown JFFS2 compression type 0x%02x\n", comprtype);
-- return -EIO;
-- }
-+int jffs2_compressors_exit(void)
-+{
-+/* Unregistering compressors */
-+#ifdef CONFIG_JFFS2_LZO
-+ jffs2_lzo_exit();
-+#endif
-+#ifdef CONFIG_JFFS2_LZARI
-+ jffs2_lzari_exit();
-+#endif
-+#ifdef CONFIG_JFFS2_RUBIN
-+ jffs2_dynrubin_exit();
-+ jffs2_rubinmips_exit();
-+#endif
-+#ifdef CONFIG_JFFS2_RTIME
-+ jffs2_rtime_exit();
-+#endif
-+#ifdef CONFIG_JFFS2_ZLIB
-+ jffs2_zlib_exit();
-+#endif
- return 0;
- }
---- /dev/null
-+++ linux-2.4.21/fs/jffs2/compr.h
-@@ -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__ */
---- /dev/null
-+++ linux-2.4.21/fs/jffs2/compr_lzari.c
-@@ -0,0 +1,717 @@
-+/*
-+ * JFFS2 -- Journalling Flash File System, Version 2.
-+ *
-+ * Copyright (C) 2004 Patrik Kluba,
-+ * University of Szeged, Hungary
-+ *
-+ * For licensing information, see the file 'LICENCE' in the
-+ * jffs2 directory.
-+ *
-+ * $Id: compr_lzari.c,v 1.3 2004/06/23 16:34:39 havasi Exp $
-+ *
-+ */
-+
-+/*
-+ Lempel-Ziv-Arithmetic coding compression module for jffs2
-+ Based on the LZARI source included in LDS (lossless datacompression sources)
-+*/
-+
-+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
-+
-+/*
-+Original copyright follows:
-+
-+**************************************************************
-+ LZARI.C -- A Data Compression Program
-+ (tab = 4 spaces)
-+**************************************************************
-+ 4/7/1989 Haruhiko Okumura
-+ Use, distribute, and modify this program freely.
-+ Please send me your improved versions.
-+ PC-VAN SCIENCE
-+ NIFTY-Serve PAF01022
-+ CompuServe 74050,1022
-+**************************************************************
-+
-+LZARI.C (c)1989 by Haruyasu Yoshizaki, Haruhiko Okumura, and Kenji Rikitake.
-+All rights reserved. Permission granted for non-commercial use.
-+
-+*/
-+
-+/*
-+
-+ 2004-02-18 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
-+ Removed unused variables and fixed no return value
-+
-+ 2004-02-16 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
-+ Initial release
-+
-+*/
-+
-+/* lzari.c */
-+
-+#define N 4096 /* size of ring buffer */
-+#define F 60 /* upper limit for match_length */
-+#define THRESHOLD 2 /* encode string into position and length
-+ if match_length is greater than this */
-+#define NIL N /* index for root of binary search trees */
-+
-+static unsigned char
-+ text_buf[N + F - 1]; /* ring buffer of size N,
-+ with extra F-1 bytes to facilitate string comparison */
-+static unsigned long match_position, match_length, /* of longest match. These are
-+ set by the InsertNode() procedure. */
-+ lson[N + 1], rson[N + 257], dad[N + 1]; /* left & right children &
-+ parents -- These constitute binary search trees. */
-+
-+static void InitTree(void) /* Initialize trees */
-+{
-+ unsigned long i;
-+
-+ /* For i = 0 to N - 1, rson[i] and lson[i] will be the right and
-+ left children of node i. These nodes need not be initialized.
-+ Also, dad[i] is the parent of node i. These are initialized to
-+ NIL (= N), which stands for 'not used.'
-+ For i = 0 to 255, rson[N + i + 1] is the root of the tree
-+ for strings that begin with character i. These are initialized
-+ to NIL. Note there are 256 trees. */
-+
-+ for (i = N + 1; i <= N + 256; i++) rson[i] = NIL; /* root */
-+ for (i = 0; i < N; i++) dad[i] = NIL; /* node */
-+}
-+
-+static void InsertNode(unsigned long r)
-+ /* Inserts string of length F, text_buf[r..r+F-1], into one of the
-+ trees (text_buf[r]'th tree) and returns the longest-match position
-+ and length via the global variables match_position and match_length.
-+ If match_length = F, then removes the old node in favor of the new
-+ one, because the old one will be deleted sooner.
-+ Note r plays double role, as tree node and position in buffer. */
-+{
-+ unsigned long i, p, temp;
-+ unsigned char *key;
-+ signed long cmp;
-+
-+ cmp = 1; key = &text_buf[r]; p = N + 1 + key[0];
-+ rson[r] = lson[r] = NIL; match_length = 0;
-+ for ( ; ; ) {
-+ if (cmp >= 0) {
-+ if (rson[p] != NIL) p = rson[p];
-+ else { rson[p] = r; dad[r] = p; return; }
-+ } else {
-+ if (lson[p] != NIL) p = lson[p];
-+ else { lson[p] = r; dad[r] = p; return; }
-+ }
-+ for (i = 1; i < F; i++)
-+ if ((cmp = key[i] - text_buf[p + i]) != 0) break;
-+ if (i > THRESHOLD) {
-+ if (i > match_length) {
-+ match_position = (r - p) & (N - 1);
-+ if ((match_length = i) >= F) break;
-+ } else if (i == match_length) {
-+ if ((temp = (r - p) & (N - 1)) < match_position)
-+ match_position = temp;
-+ }
-+ }
-+ }
-+ dad[r] = dad[p]; lson[r] = lson[p]; rson[r] = rson[p];
-+ dad[lson[p]] = r; dad[rson[p]] = r;
-+ if (rson[dad[p]] == p) rson[dad[p]] = r;
-+ else lson[dad[p]] = r;
-+ dad[p] = NIL; /* remove p */
-+}
-+
-+static void DeleteNode(unsigned long p) /* Delete node p from tree */
-+{
-+ unsigned long q;
-+
-+ if (dad[p] == NIL) return; /* not in tree */
-+ if (rson[p] == NIL) q = lson[p];
-+ else if (lson[p] == NIL) q = rson[p];
-+ else {
-+ q = lson[p];
-+ if (rson[q] != NIL) {
-+ do { q = rson[q]; } while (rson[q] != NIL);
-+ rson[dad[q]] = lson[q]; dad[lson[q]] = dad[q];
-+ lson[q] = lson[p]; dad[lson[p]] = q;
-+ }
-+ rson[q] = rson[p]; dad[rson[p]] = q;
-+ }
-+ dad[q] = dad[p];
-+ if (rson[dad[p]] == p) rson[dad[p]] = q;
-+ else lson[dad[p]] = q;
-+ dad[p] = NIL;
-+}
-+
-+/********** Arithmetic Compression **********/
-+
-+/* If you are not familiar with arithmetic compression, you should read
-+ I. E. Witten, R. M. Neal, and J. G. Cleary,
-+ Communications of the ACM, Vol. 30, pp. 520-540 (1987),
-+ from which much have been borrowed. */
-+
-+#define M 15
-+
-+/* Q1 (= 2 to the M) must be sufficiently large, but not so
-+ large as the unsigned long 4 * Q1 * (Q1 - 1) overflows. */
-+
-+#define Q1 (1UL << M)
-+#define Q2 (2 * Q1)
-+#define Q3 (3 * Q1)
-+#define Q4 (4 * Q1)
-+#define MAX_CUM (Q1 - 1)
-+
-+#define N_CHAR (256 - THRESHOLD + F)
-+ /* character code = 0, 1, ..., N_CHAR - 1 */
-+
-+static unsigned long char_to_sym[N_CHAR], sym_to_char[N_CHAR + 1];
-+static unsigned long
-+ sym_freq[N_CHAR + 1], /* frequency for symbols */
-+ sym_cum[N_CHAR + 1], /* cumulative freq for symbols */
-+ position_cum[N + 1]; /* cumulative freq for positions */
-+
-+static void StartModel(void) /* Initialize model */
-+{
-+ unsigned long ch, sym, i;
-+
-+ sym_cum[N_CHAR] = 0;
-+ for (sym = N_CHAR; sym >= 1; sym--) {
-+ ch = sym - 1;
-+ char_to_sym[ch] = sym; sym_to_char[sym] = ch;
-+ sym_freq[sym] = 1;
-+ sym_cum[sym - 1] = sym_cum[sym] + sym_freq[sym];
-+ }
-+ sym_freq[0] = 0; /* sentinel (!= sym_freq[1]) */
-+ position_cum[N] = 0;
-+ for (i = N; i >= 1; i--)
-+ position_cum[i - 1] = position_cum[i] + 10000 / (i + 200);
-+ /* empirical distribution function (quite tentative) */
-+ /* Please devise a better mechanism! */
-+}
-+
-+static void UpdateModel(unsigned long sym)
-+{
-+ unsigned long c, ch_i, ch_sym;
-+ unsigned long i;
-+ if (sym_cum[0] >= MAX_CUM) {
-+ c = 0;
-+ for (i = N_CHAR; i > 0; i--) {
-+ sym_cum[i] = c;
-+ c += (sym_freq[i] = (sym_freq[i] + 1) >> 1);
-+ }
-+ sym_cum[0] = c;
-+ }
-+ for (i = sym; sym_freq[i] == sym_freq[i - 1]; i--) ;
-+ if (i < sym) {
-+ ch_i = sym_to_char[i]; ch_sym = sym_to_char[sym];
-+ sym_to_char[i] = ch_sym; sym_to_char[sym] = ch_i;
-+ char_to_sym[ch_i] = sym; char_to_sym[ch_sym] = i;
-+ }
-+ sym_freq[i]++;
-+ while (--i > 0) sym_cum[i]++;
-+ sym_cum[0]++;
-+}
-+
-+static unsigned long BinarySearchSym(unsigned long x)
-+ /* 1 if x >= sym_cum[1],
-+ N_CHAR if sym_cum[N_CHAR] > x,
-+ i such that sym_cum[i - 1] > x >= sym_cum[i] otherwise */
-+{
-+ unsigned long i, j, k;
-+
-+ i = 1; j = N_CHAR;
-+ while (i < j) {
-+ k = (i + j) / 2;
-+ if (sym_cum[k] > x) i = k + 1; else j = k;
-+ }
-+ return i;
-+}
-+
-+unsigned long BinarySearchPos(unsigned long x)
-+ /* 0 if x >= position_cum[1],
-+ N - 1 if position_cum[N] > x,
-+ i such that position_cum[i] > x >= position_cum[i + 1] otherwise */
-+{
-+ unsigned long i, j, k;
-+
-+ i = 1; j = N;
-+ while (i < j) {
-+ k = (i + j) / 2;
-+ if (position_cum[k] > x) i = k + 1; else j = k;
-+ }
-+ return i - 1;
-+}
-+
-+/* modified for block compression */
-+/* on return, srclen will contain the number of successfully compressed bytes
-+ and dstlen will contain completed compressed bytes */
-+
-+static int Encode(unsigned char *srcbuf, unsigned char *dstbuf, unsigned long *srclen,
-+ unsigned long *dstlen)
-+{
-+ unsigned long c, i, len, r, s, last_match_length, sym, range;
-+ unsigned long low = 0;
-+ unsigned long high = Q4;
-+ unsigned long shifts = 0; /* counts for magnifying low and high around Q2 */
-+ unsigned char *ip, *op;
-+ unsigned long written = 0;
-+ unsigned long read = 0;
-+ unsigned char buffer = 0;
-+ unsigned char mask = 128;
-+ unsigned char *srcend = srcbuf + *srclen;
-+ unsigned char *dstend = dstbuf + *dstlen;
-+ ip = srcbuf;
-+ op = dstbuf;
-+ StartModel();
-+ InitTree(); /* initialize trees */
-+ s = 0; r = N - F;
-+ for (i = s; i < r; i++) text_buf[i] = ' '; /* Clear the buffer with
-+ any character that will appear often. */
-+ for (len = 0; (len < F) && (ip < srcend); len++)
-+ text_buf[r + len] = *(ip++); /* Read F bytes into the last F bytes of
-+ the buffer */
-+ read = len;
-+ for (i = 1; i <= F; i++) InsertNode(r - i); /* Insert the F strings,
-+ each of which begins with one or more 'space' characters. Note
-+ the order in which these strings are inserted. This way,
-+ degenerate trees will be less likely to occur. */
-+ InsertNode(r); /* Finally, insert the whole string just read. The
-+ global variables match_length and match_position are set. */
-+ do {
-+ if (match_length > len) match_length = len; /* match_length
-+ may be spuriously long near the end of text. */
-+ if (match_length <= THRESHOLD) {
-+ match_length = 1; /* Not long enough match. Send one byte. */
-+ sym = char_to_sym[text_buf[r]];
-+ range = high - low;
-+ high = low + (range * sym_cum[sym - 1]) / sym_cum[0];
-+ low += (range * sym_cum[sym ]) / sym_cum[0];
-+ for ( ; ; ) {
-+ if (high <= Q2) {
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ for ( ; shifts > 0; shifts--) {
-+ buffer |= mask;
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ }
-+ } else if (low >= Q2) {
-+ buffer |= mask;
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ for ( ; shifts > 0; shifts--) {
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ }
-+ low -= Q2;
-+ high -= Q2;
-+ } else if (low >= Q1 && high <= Q3) {
-+ shifts++;
-+ low -= Q1;
-+ high -= Q1;
-+ } else break;
-+ low += low; high += high;
-+ }
-+ UpdateModel(sym);
-+ } else {
-+ sym = char_to_sym[255 - THRESHOLD + match_length];
-+ range = high - low;
-+ high = low + (range * sym_cum[sym - 1]) / sym_cum[0];
-+ low += (range * sym_cum[sym ]) / sym_cum[0];
-+ for ( ; ; ) {
-+ if (high <= Q2) {
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ for ( ; shifts > 0; shifts--) {
-+ buffer |= mask;
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ }
-+ } else if (low >= Q2) {
-+ buffer |= mask;
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ for ( ; shifts > 0; shifts--) {
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ }
-+ low -= Q2;
-+ high -= Q2;
-+ } else if (low >= Q1 && high <= Q3) {
-+ shifts++;
-+ low -= Q1;
-+ high -= Q1;
-+ } else break;
-+ low += low; high += high;
-+ }
-+ UpdateModel(sym);
-+ range = high - low;
-+ high = low + (range * position_cum[match_position - 1]) / position_cum[0];
-+ low += (range * position_cum[match_position ]) / position_cum[0];
-+ for ( ; ; ) {
-+ if (high <= Q2) {
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ for ( ; shifts > 0; shifts--) {
-+ buffer |= mask;
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ }
-+ } else {
-+ if (low >= Q2) {
-+ buffer |= mask;
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ for ( ; shifts > 0; shifts--) {
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ }
-+ low -= Q2;
-+ high -= Q2;
-+ } else {
-+ if ((low >= Q1) && (high <= Q3)) {
-+ shifts++;
-+ low -= Q1;
-+ high -= Q1;
-+ } else {
-+ break;
-+ }
-+ }
-+ }
-+ low += low;
-+ high += high;
-+ }
-+ }
-+ last_match_length = match_length;
-+ for (i = 0; (i < last_match_length) && (ip < srcend); i++) {
-+ c = *(ip++);
-+ DeleteNode(s);
-+ text_buf[s] = c;
-+ if (s < F - 1)
-+ text_buf[s + N] = c;
-+ s = (s + 1) & (N - 1);
-+ r = (r + 1) & (N - 1);
-+ InsertNode(r);
-+ }
-+ read += i;
-+ while (i++ < last_match_length) {
-+ DeleteNode(s);
-+ s = (s + 1) & (N - 1);
-+ r = (r + 1) & (N - 1);
-+ if (--len) InsertNode(r);
-+ }
-+ } while (len > 0);
-+ shifts++;
-+ if (low < Q1) {
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ for ( ; shifts > 0; shifts--) {
-+ buffer |= mask;
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ }
-+ } else {
-+ buffer |= mask;
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ for ( ; shifts > 0; shifts--) {
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ }
-+ }
-+ for (i = 0; i < 7; i++) {
-+ if ((mask >>= 1) == 0) {
-+ if (op >= dstend) {
-+ *dstlen = written;
-+ return -1;
-+ }
-+ *(op++) = buffer;
-+ buffer = 0;
-+ mask = 128;
-+ written++;
-+ *srclen = read;
-+ }
-+ }
-+ *dstlen = written;
-+ return 0;
-+}
-+
-+static int Decode(unsigned char *srcbuf, unsigned char *dstbuf, unsigned long srclen,
-+ unsigned long dstlen) /* Just the reverse of Encode(). */
-+{
-+ unsigned long i, r, j, k, c, range, sym;
-+ unsigned char *ip, *op;
-+ unsigned char *srcend = srcbuf + srclen;
-+ unsigned char *dstend = dstbuf + dstlen;
-+ unsigned char buffer = 0;
-+ unsigned char mask = 0;
-+ unsigned long low = 0;
-+ unsigned long high = Q4;
-+ unsigned long value = 0;
-+ ip = srcbuf;
-+ op = dstbuf;
-+ for (i = 0; i < M + 2; i++) {
-+ value *= 2;
-+ if ((mask >>= 1) == 0) {
-+ buffer = (ip >= srcend) ? 0 : *(ip++);
-+ mask = 128;
-+ }
-+ value += ((buffer & mask) != 0);
-+ }
-+ StartModel();
-+ for (i = 0; i < N - F; i++) text_buf[i] = ' ';
-+ r = N - F;
-+ while (op < dstend) {
-+ range = high - low;
-+ sym = BinarySearchSym((unsigned long)
-+ (((value - low + 1) * sym_cum[0] - 1) / range));
-+ high = low + (range * sym_cum[sym - 1]) / sym_cum[0];
-+ low += (range * sym_cum[sym ]) / sym_cum[0];
-+ for ( ; ; ) {
-+ if (low >= Q2) {
-+ value -= Q2; low -= Q2; high -= Q2;
-+ } else if (low >= Q1 && high <= Q3) {
-+ value -= Q1; low -= Q1; high -= Q1;
-+ } else if (high > Q2) break;
-+ low += low; high += high;
-+ value *= 2;
-+ if ((mask >>= 1) == 0) {
-+ buffer = (ip >= srcend) ? 0 : *(ip++);
-+ mask = 128;
-+ }
-+ value += ((buffer & mask) != 0);
-+ }
-+ c = sym_to_char[sym];
-+ UpdateModel(sym);
-+ if (c < 256) {
-+ if (op >= dstend) return -1;
-+ *(op++) = c;
-+ text_buf[r++] = c;
-+ r &= (N - 1);
-+ } else {
-+ j = c - 255 + THRESHOLD;
-+ range = high - low;
-+ i = BinarySearchPos((unsigned long)
-+ (((value - low + 1) * position_cum[0] - 1) / range));
-+ high = low + (range * position_cum[i ]) / position_cum[0];
-+ low += (range * position_cum[i + 1]) / position_cum[0];
-+ for ( ; ; ) {
-+ if (low >= Q2) {
-+ value -= Q2; low -= Q2; high -= Q2;
-+ } else if (low >= Q1 && high <= Q3) {
-+ value -= Q1; low -= Q1; high -= Q1;
-+ } else if (high > Q2) break;
-+ low += low; high += high;
-+ value *= 2;
-+ if ((mask >>= 1) == 0) {
-+ buffer = (ip >= srcend) ? 0 : *(ip++);
-+ mask = 128;
-+ }
-+ value += ((buffer & mask) != 0);
-+ }
-+ i = (r - i - 1) & (N - 1);
-+ for (k = 0; k < j; k++) {
-+ c = text_buf[(i + k) & (N - 1)];
-+ if (op >= dstend) return -1;
-+ *(op++) = c;
-+ text_buf[r++] = c;
-+ r &= (N - 1);
-+ }
-+ }
-+ }
-+ return 0;
-+}
-+
-+/* interface to jffs2 follows */
-+
-+#include "compr.h"
-+#include <linux/jffs2.h>
-+
-+int jffs2_lzari_compress (unsigned char *input,
-+ unsigned char *output, uint32_t *sourcelen,
-+ uint32_t *dstlen, void *model);
-+
-+int jffs2_lzari_decompress (unsigned char *input,
-+ unsigned char *output, uint32_t sourcelen,
-+ uint32_t dstlen, void *model);
-+
-+struct jffs2_compressor jffs2_lzari_comp = {
-+ .priority = JFFS2_LZARI_PRIORITY,
-+ .name = "lzari",
-+ .compr = JFFS2_COMPR_LZARI,
-+ .compress = &jffs2_lzari_compress,
-+ .decompress = &jffs2_lzari_decompress,
-+#ifdef JFFS2_LZARI_DISABLED
-+ .disabled = 1,
-+#else
-+ .disabled = 0,
-+#endif
-+};
-+
-+int jffs2_lzari_compress (unsigned char *input,
-+ unsigned char *output, uint32_t *sourcelen,
-+ uint32_t *dstlen, void *model)
-+{
-+ return Encode(input, output, (unsigned long *)sourcelen, (unsigned long *)dstlen);
-+}
-+
-+int jffs2_lzari_decompress (unsigned char *input,
-+ unsigned char *output, uint32_t sourcelen,
-+ uint32_t dstlen, void *model)
-+{
-+ return Decode(input, output, sourcelen, dstlen);
-+}
-+
-+int jffs2_lzari_init (void)
-+{
-+ return jffs2_register_compressor(&jffs2_lzari_comp);
-+}
-+
-+void jffs2_lzari_exit (void)
-+{
-+ jffs2_unregister_compressor (&jffs2_lzari_comp);
-+}
---- /dev/null
-+++ linux-2.4.21/fs/jffs2/compr_lzo.c
-@@ -0,0 +1,2329 @@
-+/*
-+ * JFFS2 -- Journalling Flash File System, Version 2.
-+ *
-+ * Copyright (C) 2004 Patrik Kluba,
-+ * University of Szeged, Hungary
-+ *
-+ * For licensing information, see the file 'LICENCE' in the
-+ * jffs2 directory.
-+ *
-+ * $Id: compr_lzo.c,v 1.3 2004/06/23 16:34:39 havasi Exp $
-+ *
-+ */
-+
-+/*
-+ LZO1X-1 (and -999) compression module for jffs2
-+ based on the original LZO sources
-+*/
-+
-+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
-+
-+/*
-+ Original copyright notice follows:
-+
-+ lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm
-+ lzo_ptr.h -- low-level pointer constructs
-+ lzo_swd.ch -- sliding window dictionary
-+ lzoconf.h -- configuration for the LZO real-time data compression library
-+ lzo_mchw.ch -- matching functions using a window
-+ minilzo.c -- mini subset of the LZO real-time data compression library
-+ config1x.h -- configuration for the LZO1X algorithm
-+ lzo1x.h -- public interface of the LZO1X compression algorithm
-+
-+ These files are part of the LZO real-time data compression library.
-+
-+ Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
-+ All Rights Reserved.
-+
-+ The LZO library is free software; 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.
-+
-+ The LZO library is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with the LZO library; see the file COPYING.
-+ If not, write to the Free Software Foundation, Inc.,
-+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+
-+ Markus F.X.J. Oberhumer
-+ <markus@oberhumer.com>
-+*/
-+
-+/*
-+
-+ 2004-02-16 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
-+ Initial release
-+ -removed all 16 bit code
-+ -all sensitive data will be on 4 byte boundary
-+ -removed check parts for library use
-+ -removed all but LZO1X-* compression
-+
-+*/
-+
-+#ifndef __KERNEL__
-+ #include <sys/types.h>
-+ #include <stddef.h>
-+ #include <string.h>
-+ #include <limits.h>
-+#else
-+ #include <linux/kernel.h>
-+ #include <linux/types.h>
-+ #include <linux/stddef.h>
-+ #include <linux/string.h>
-+ #define USHRT_MAX 65535
-+ /* #define UINT_MAX 4294967295U */
-+#endif
-+
-+/* data type definitions */
-+#define U32 unsigned long
-+#define S32 signed long
-+#define I32 long
-+#define U16 unsigned short
-+#define S16 signed short
-+#define I16 short
-+#define U8 unsigned char
-+#define S8 signed char
-+#define I8 char
-+
-+/*************************************/
-+
-+/* lzo_swd.ch */
-+
-+#define SWD_N N
-+#define SWD_F F
-+#define SWD_THRESHOLD THRESHOLD
-+
-+/* shortest unsigned int that 2 * SWD_F + SWD_N (currently 53248) fits in */
-+typedef unsigned short swd_uint;
-+/* upper limit of that data type */
-+#define SWD_UINT_MAX USHRT_MAX
-+
-+/* minilzo.c */
-+
-+#define LZO_VERSION_DATE "Jul 12 2002"
-+#define LZO_VERSION_STRING "1.08"
-+#define LZO_VERSION 0x1080
-+
-+/* lzo_ptr.h */
-+
-+/* Integral types that have *exactly* the same number of bits as a lzo_voidp */
-+typedef unsigned long lzo_ptr_t;
-+typedef long lzo_sptr_t;
-+
-+
-+/*************************************/
-+
-+/* config1x.h */
-+
-+#define M1_MAX_OFFSET 0x0400
-+#define M2_MAX_OFFSET 0x0800
-+#define M3_MAX_OFFSET 0x4000
-+#define M4_MAX_OFFSET 0xbfff
-+
-+#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET)
-+
-+#define M1_MIN_LEN 2
-+#define M1_MAX_LEN 2
-+#define M2_MIN_LEN 3
-+#define M2_MAX_LEN 8
-+#define M3_MIN_LEN 3
-+#define M3_MAX_LEN 33
-+#define M4_MIN_LEN 3
-+#define M4_MAX_LEN 9
-+
-+#define M1_MARKER 0
-+#define M2_MARKER 64
-+#define M3_MARKER 32
-+#define M4_MARKER 16
-+
-+#define MIN_LOOKAHEAD (M2_MAX_LEN + 1)
-+
-+/* minilzo.c */
-+
-+#define LZO_BYTE(x) ((unsigned char) ((x) & 0xff))
-+
-+#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b))
-+#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b))
-+#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c))
-+#define LZO_MIN3(a,b,c) ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c))
-+
-+#define lzo_sizeof(type) ((lzo_uint) (sizeof(type)))
-+
-+#define LZO_HIGH(array) ((lzo_uint) (sizeof(array)/sizeof(*(array))))
-+
-+#define LZO_SIZE(bits) (1u << (bits))
-+#define LZO_MASK(bits) (LZO_SIZE(bits) - 1)
-+
-+#define LZO_LSIZE(bits) (1ul << (bits))
-+#define LZO_LMASK(bits) (LZO_LSIZE(bits) - 1)
-+
-+#define LZO_USIZE(bits) ((lzo_uint) 1 << (bits))
-+#define LZO_UMASK(bits) (LZO_USIZE(bits) - 1)
-+
-+#define LZO_STYPE_MAX(b) (((1l << (8*(b)-2)) - 1l) + (1l << (8*(b)-2)))
-+#define LZO_UTYPE_MAX(b) (((1ul << (8*(b)-1)) - 1ul) + (1ul << (8*(b)-1)))
-+
-+#define _LZO_STRINGIZE(x) #x
-+#define _LZO_MEXPAND(x) _LZO_STRINGIZE(x)
-+
-+#define _LZO_CONCAT2(a,b) a ## b
-+#define _LZO_CONCAT3(a,b,c) a ## b ## c
-+#define _LZO_CONCAT4(a,b,c,d) a ## b ## c ## d
-+#define _LZO_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e
-+
-+#define _LZO_ECONCAT2(a,b) _LZO_CONCAT2(a,b)
-+#define _LZO_ECONCAT3(a,b,c) _LZO_CONCAT3(a,b,c)
-+#define _LZO_ECONCAT4(a,b,c,d) _LZO_CONCAT4(a,b,c,d)
-+#define _LZO_ECONCAT5(a,b,c,d,e) _LZO_CONCAT5(a,b,c,d,e)
-+
-+#define lzo_dict_t const lzo_bytep
-+#define lzo_dict_p lzo_dict_t *
-+#define lzo_moff_t lzo_uint
-+
-+#define MEMCPY8_DS(dest,src,len) \
-+ memcpy(dest,src,len); \
-+ dest += len; \
-+ src += len
-+
-+#define MEMCPY_DS(dest,src,len) \
-+ do *dest++ = *src++; \
-+ while (--len > 0)
-+
-+#define MEMMOVE_DS(dest,src,len) \
-+ do *dest++ = *src++; \
-+ while (--len > 0)
-+
-+#define BZERO8_PTR(s,l,n) memset((s),0,(lzo_uint)(l)*(n))
-+
-+#define LZO_BASE 65521u
-+#define LZO_NMAX 5552
-+
-+#define LZO_DO1(buf,i) {s1 += buf[i]; s2 += s1;}
-+#define LZO_DO2(buf,i) LZO_DO1(buf,i); LZO_DO1(buf,i+1);
-+#define LZO_DO4(buf,i) LZO_DO2(buf,i); LZO_DO2(buf,i+2);
-+#define LZO_DO8(buf,i) LZO_DO4(buf,i); LZO_DO4(buf,i+4);
-+#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8);
-+
-+#define IS_SIGNED(type) (((type) (-1)) < ((type) 0))
-+#define IS_UNSIGNED(type) (((type) (-1)) > ((type) 0))
-+
-+#define IS_POWER_OF_2(x) (((x) & ((x) - 1)) == 0)
-+
-+#define D_BITS 14
-+#define D_INDEX1(d,p) d = DM((0x21*DX3(p,5,5,6)) >> 5)
-+#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
-+
-+#define LZO_HASH LZO_HASH_LZO_INCREMENTAL_B
-+
-+#define DL_MIN_LEN M2_MIN_LEN
-+
-+#define D_SIZE LZO_SIZE(D_BITS)
-+#define D_MASK LZO_MASK(D_BITS)
-+
-+#define D_HIGH ((D_MASK >> 1) + 1)
-+
-+#define DINDEX1 D_INDEX1
-+#define DINDEX2 D_INDEX2
-+
-+#define DX2(p,s1,s2) \
-+ (((((lzo_uint32)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0])
-+
-+#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0])
-+#define DMS(v,s) ((lzo_uint) (((v) & (D_MASK >> (s))) << (s)))
-+#define DM(v) DMS(v,0)
-+
-+#define DENTRY(p,in) (p)
-+#define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex]
-+
-+#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
-+ (m_pos == NULL || (m_off = (lzo_moff_t) (ip - m_pos)) > max_offset)
-+
-+#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
-+ (BOUNDS_CHECKING_OFF_IN_EXPR( \
-+ (PTR_LT(m_pos,in) || \
-+ (m_off = (lzo_moff_t) PTR_DIFF(ip,m_pos)) <= 0 || \
-+ m_off > max_offset) ))
-+
-+#define BOUNDS_CHECKING_OFF_IN_EXPR(expr) (expr)
-+
-+#define DD_BITS 0
-+#define DD_SIZE LZO_SIZE(DD_BITS)
-+#define DD_MASK LZO_MASK(DD_BITS)
-+
-+#define DL_BITS (D_BITS - DD_BITS)
-+#define DL_SIZE LZO_SIZE(DL_BITS)
-+#define DL_MASK LZO_MASK(DL_BITS)
-+
-+#define UPDATE_D(dict,drun,dv,p,in) dict[ DINDEX(dv,p) ] = DENTRY(p,in)
-+#define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in)
-+#define UPDATE_P(ptr,drun,p,in) (ptr)[0] = DENTRY(p,in)
-+
-+#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
-+#define COPY4(dst,src) __COPY4((lzo_ptr_t)(dst),(lzo_ptr_t)(src))
-+
-+#define TEST_IP (ip < ip_end)
-+#define TEST_OP (op <= op_end)
-+
-+#define NEED_IP(x) \
-+ if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun
-+#define NEED_OP(x) \
-+ if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun
-+#define TEST_LOOKBEHIND(m_pos,out) if (m_pos < out) goto lookbehind_overrun
-+
-+/* lzo1x_9x.c */
-+
-+#define LZO_UINT_MAX UINT_MAX
-+#define N M4_MAX_OFFSET
-+#define THRESHOLD 1
-+#define F 2048
-+
-+#define SWD_BEST_OFF (LZO_MAX3( M2_MAX_LEN, M3_MAX_LEN, M4_MAX_LEN ) + 1)
-+
-+/* ../include/lzoconf.h */
-+
-+typedef U32 lzo_uint32;
-+typedef I32 lzo_int32;
-+typedef U32 lzo_uint;
-+typedef I32 lzo_int;
-+typedef int lzo_bool;
-+
-+#define lzo_byte U8
-+#define lzo_bytep U8 *
-+#define lzo_charp char *
-+#define lzo_voidp void *
-+#define lzo_shortp short *
-+#define lzo_ushortp unsigned short *
-+#define lzo_uint32p lzo_uint32 *
-+#define lzo_int32p lzo_int32 *
-+#define lzo_uintp lzo_uint *
-+#define lzo_intp lzo_int *
-+#define lzo_voidpp lzo_voidp *
-+#define lzo_bytepp lzo_bytep *
-+#define lzo_sizeof_dict_t sizeof(lzo_bytep)
-+
-+#define LZO_E_OK 0
-+#define LZO_E_ERROR (-1)
-+#define LZO_E_OUT_OF_MEMORY (-2) /* not used right now */
-+#define LZO_E_NOT_COMPRESSIBLE (-3) /* not used right now */
-+#define LZO_E_INPUT_OVERRUN (-4)
-+#define LZO_E_OUTPUT_OVERRUN (-5)
-+#define LZO_E_LOOKBEHIND_OVERRUN (-6)
-+#define LZO_E_EOF_NOT_FOUND (-7)
-+#define LZO_E_INPUT_NOT_CONSUMED (-8)
-+
-+#define LZO_PTR_ALIGN_UP(_ptr,_size) \
-+ ((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size)))
-+#define LZO_ALIGN(_ptr,_size) LZO_PTR_ALIGN_UP(_ptr,_size)
-+
-+typedef int
-+ (*lzo_compress_t) (const lzo_byte * src, lzo_uint src_len,
-+ lzo_byte * dst, lzo_uintp dst_len,
-+ lzo_voidp wrkmem);
-+
-+typedef int
-+ (*lzo_decompress_t) (const lzo_byte * src, lzo_uint src_len,
-+ lzo_byte * dst, lzo_uintp dst_len,
-+ lzo_voidp wrkmem);
-+
-+typedef int
-+ (*lzo_optimize_t) (lzo_byte * src, lzo_uint src_len,
-+ lzo_byte * dst, lzo_uintp dst_len,
-+ lzo_voidp wrkmem);
-+
-+typedef int
-+ (*lzo_compress_dict_t) (const lzo_byte * src, lzo_uint src_len,
-+ lzo_byte * dst, lzo_uintp dst_len,
-+ lzo_voidp wrkmem,
-+ const lzo_byte * dict, lzo_uint dict_len);
-+
-+typedef int
-+ (*lzo_decompress_dict_t) (const lzo_byte * src, lzo_uint src_len,
-+ lzo_byte * dst, lzo_uintp dst_len,
-+ lzo_voidp wrkmem,
-+ const lzo_byte * dict, lzo_uint dict_len);
-+
-+typedef int
-+ (*lzo_compress_asm_t) (const lzo_byte * src, lzo_uint src_len,
-+ lzo_byte * dst, lzo_uintp dst_len,
-+ lzo_voidp wrkmem);
-+
-+typedef int
-+ (*lzo_decompress_asm_t) (const lzo_byte * src, lzo_uint src_len,
-+ lzo_byte * dst, lzo_uintp dst_len,
-+ lzo_voidp wrkmem);
-+
-+typedef void (*lzo_progress_callback_t) (lzo_uint, lzo_uint);
-+
-+typedef union
-+{
-+ lzo_bytep p;
-+ lzo_uint u;
-+} __lzo_pu_u;
-+typedef union
-+{
-+ lzo_bytep p;
-+ lzo_uint32 u32;
-+} __lzo_pu32_u;
-+typedef union
-+{
-+ void *vp;
-+ lzo_bytep bp;
-+ lzo_uint32 u32;
-+ long l;
-+} lzo_align_t;
-+
-+/* lzo1x.h */
-+
-+#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
-+#define LZO1X_999_MEM_COMPRESS ((lzo_uint32) (14 * 16384L * sizeof(short)))
-+
-+/* lzo_ptr.h */
-+
-+#define PTR(a) ((lzo_ptr_t) (a))
-+#define PTR_LINEAR(a) PTR(a)
-+#define PTR_ALIGNED_4(a) ((PTR_LINEAR(a) & 3) == 0)
-+#define PTR_ALIGNED_8(a) ((PTR_LINEAR(a) & 7) == 0)
-+#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0)
-+#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0)
-+#define PTR_LT(a,b) (PTR(a) < PTR(b))
-+#define PTR_GE(a,b) (PTR(a) >= PTR(b))
-+#define PTR_DIFF(a,b) ((lzo_ptrdiff_t) (PTR(a) - PTR(b)))
-+#define pd(a,b) ((lzo_uint) ((a)-(b)))
-+
-+typedef ptrdiff_t lzo_ptrdiff_t;
-+
-+typedef union
-+{
-+ char a_char;
-+ unsigned char a_uchar;
-+ short a_short;
-+ unsigned short a_ushort;
-+ int a_int;
-+ unsigned int a_uint;
-+ long a_long;
-+ unsigned long a_ulong;
-+ lzo_int a_lzo_int;
-+ lzo_uint a_lzo_uint;
-+ lzo_int32 a_lzo_int32;
-+ lzo_uint32 a_lzo_uint32;
-+ ptrdiff_t a_ptrdiff_t;
-+ lzo_ptrdiff_t a_lzo_ptrdiff_t;
-+ lzo_ptr_t a_lzo_ptr_t;
-+ lzo_voidp a_lzo_voidp;
-+ void *a_void_p;
-+ lzo_bytep a_lzo_bytep;
-+ lzo_bytepp a_lzo_bytepp;
-+ lzo_uintp a_lzo_uintp;
-+ lzo_uint *a_lzo_uint_p;
-+ lzo_uint32p a_lzo_uint32p;
-+ lzo_uint32 *a_lzo_uint32_p;
-+ unsigned char *a_uchar_p;
-+ char *a_char_p;
-+}
-+lzo_full_align_t;
-+
-+/* lzo_mchw.ch */
-+
-+typedef struct
-+{
-+ int init;
-+
-+ lzo_uint look;
-+
-+ lzo_uint m_len;
-+ lzo_uint m_off;
-+
-+ lzo_uint last_m_len;
-+ lzo_uint last_m_off;
-+
-+ const lzo_byte *bp;
-+ const lzo_byte *ip;
-+ const lzo_byte *in;
-+ const lzo_byte *in_end;
-+ lzo_byte *out;
-+
-+ lzo_progress_callback_t cb;
-+
-+ lzo_uint textsize;
-+ lzo_uint codesize;
-+ lzo_uint printcount;
-+
-+ unsigned long lit_bytes;
-+ unsigned long match_bytes;
-+ unsigned long rep_bytes;
-+ unsigned long lazy;
-+
-+ lzo_uint r1_lit;
-+ lzo_uint r1_m_len;
-+
-+ unsigned long m1a_m, m1b_m, m2_m, m3_m, m4_m;
-+ unsigned long lit1_r, lit2_r, lit3_r;
-+}
-+lzo1x_999_t;
-+
-+#define getbyte(c) ((c).ip < (c).in_end ? *((c).ip)++ : (-1))
-+
-+/* lzo_swd.ch */
-+
-+#define SWD_UINT(x) ((swd_uint)(x))
-+#define SWD_HSIZE 16384
-+#define SWD_MAX_CHAIN 2048
-+#define HEAD3(b,p) \
-+ (((0x9f5f*(((((lzo_uint32)b[p]<<5)^b[p+1])<<5)^b[p+2]))>>5) & (SWD_HSIZE-1))
-+#define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8))
-+#define NIL2 SWD_UINT_MAX
-+
-+typedef struct
-+{
-+ lzo_uint n;
-+ lzo_uint f;
-+ lzo_uint threshold;
-+
-+ lzo_uint max_chain;
-+ lzo_uint nice_length;
-+ lzo_bool use_best_off;
-+ lzo_uint lazy_insert;
-+
-+ lzo_uint m_len;
-+ lzo_uint m_off;
-+ lzo_uint look;
-+ int b_char;
-+
-+ lzo_uint best_off[SWD_BEST_OFF];
-+
-+ lzo1x_999_t *c;
-+ lzo_uint m_pos;
-+
-+ lzo_uint best_pos[SWD_BEST_OFF];
-+
-+ const lzo_byte *dict;
-+ const lzo_byte *dict_end;
-+ lzo_uint dict_len;
-+
-+ lzo_uint ip;
-+ lzo_uint bp;
-+ lzo_uint rp;
-+ lzo_uint b_size;
-+
-+ unsigned char *b_wrap;
-+
-+ lzo_uint node_count;
-+ lzo_uint first_rp;
-+
-+ unsigned char b[SWD_N + SWD_F + SWD_F];
-+ swd_uint head3[SWD_HSIZE];
-+ swd_uint succ3[SWD_N + SWD_F];
-+ swd_uint best3[SWD_N + SWD_F];
-+ swd_uint llen3[SWD_HSIZE];
-+
-+ swd_uint head2[65536L];
-+}
-+lzo1x_999_swd_t;
-+
-+#define s_head3(s,key) s->head3[key]
-+#define swd_pos2off(s,pos) \
-+ (s->bp > (pos) ? s->bp - (pos) : s->b_size - ((pos) - s->bp))
-+
-+static __inline__ void
-+swd_getbyte (lzo1x_999_swd_t * s)
-+{
-+ int c;
-+
-+ if ((c = getbyte (*(s->c))) < 0)
-+ {
-+ if (s->look > 0)
-+ --s->look;
-+ }
-+ else
-+ {
-+ s->b[s->ip] = LZO_BYTE (c);
-+ if (s->ip < s->f)
-+ s->b_wrap[s->ip] = LZO_BYTE (c);
-+ }
-+ if (++s->ip == s->b_size)
-+ s->ip = 0;
-+ if (++s->bp == s->b_size)
-+ s->bp = 0;
-+ if (++s->rp == s->b_size)
-+ s->rp = 0;
-+}
-+
-+static void
-+swd_initdict (lzo1x_999_swd_t * s, const lzo_byte * dict, lzo_uint dict_len)
-+{
-+ s->dict = s->dict_end = NULL;
-+ s->dict_len = 0;
-+
-+ if (!dict || dict_len <= 0)
-+ return;
-+ if (dict_len > s->n)
-+ {
-+ dict += dict_len - s->n;
-+ dict_len = s->n;
-+ }
-+
-+ s->dict = dict;
-+ s->dict_len = dict_len;
-+ s->dict_end = dict + dict_len;
-+ memcpy (s->b, dict, dict_len);
-+ s->ip = dict_len;
-+}
-+
-+static void
-+swd_insertdict (lzo1x_999_swd_t * s, lzo_uint node, lzo_uint len)
-+{
-+ lzo_uint key;
-+
-+ s->node_count = s->n - len;
-+ s->first_rp = node;
-+
-+ while (len-- > 0)
-+ {
-+ key = HEAD3 (s->b, node);
-+ s->succ3[node] = s_head3 (s, key);
-+ s->head3[key] = SWD_UINT (node);
-+ s->best3[node] = SWD_UINT (s->f + 1);
-+ s->llen3[key]++;
-+
-+ key = HEAD2 (s->b, node);
-+ s->head2[key] = SWD_UINT (node);
-+
-+ node++;
-+ }
-+}
-+
-+static int
-+swd_init (lzo1x_999_swd_t * s, const lzo_byte * dict, lzo_uint dict_len)
-+{
-+
-+ s->n = SWD_N;
-+ s->f = SWD_F;
-+ s->threshold = SWD_THRESHOLD;
-+
-+
-+
-+ s->max_chain = SWD_MAX_CHAIN;
-+ s->nice_length = SWD_F;
-+ s->use_best_off = 0;
-+ s->lazy_insert = 0;
-+
-+ s->b_size = s->n + s->f;
-+ if (2 * s->f >= s->n || s->b_size + s->f >= NIL2)
-+ return LZO_E_ERROR;
-+ s->b_wrap = s->b + s->b_size;
-+ s->node_count = s->n;
-+
-+ memset (s->llen3, 0, sizeof (s->llen3[0]) * SWD_HSIZE);
-+ memset (s->head2, 0xff, sizeof (s->head2[0]) * 65536L);
-+
-+ s->ip = 0;
-+ swd_initdict (s, dict, dict_len);
-+ s->bp = s->ip;
-+ s->first_rp = s->ip;
-+
-+ s->look = (lzo_uint) (s->c->in_end - s->c->ip);
-+ if (s->look > 0)
-+ {
-+ if (s->look > s->f)
-+ s->look = s->f;
-+ memcpy (&s->b[s->ip], s->c->ip, s->look);
-+ s->c->ip += s->look;
-+ s->ip += s->look;
-+ }
-+
-+ if (s->ip == s->b_size)
-+ s->ip = 0;
-+
-+ if (s->look >= 2 && s->dict_len > 0)
-+ swd_insertdict (s, 0, s->dict_len);
-+
-+ s->rp = s->first_rp;
-+ if (s->rp >= s->node_count)
-+ s->rp -= s->node_count;
-+ else
-+ s->rp += s->b_size - s->node_count;
-+
-+ return LZO_E_OK;
-+}
-+
-+static __inline__ void
-+swd_remove_node (lzo1x_999_swd_t * s, lzo_uint node)
-+{
-+ if (s->node_count == 0)
-+ {
-+ lzo_uint key;
-+
-+ key = HEAD3 (s->b, node);
-+
-+ --s->llen3[key];
-+
-+ key = HEAD2 (s->b, node);
-+
-+ if ((lzo_uint) s->head2[key] == node)
-+ s->head2[key] = NIL2;
-+ }
-+ else
-+ --s->node_count;
-+}
-+
-+static void
-+swd_accept (lzo1x_999_swd_t * s, lzo_uint n)
-+{
-+
-+ while (n--)
-+ {
-+ lzo_uint key;
-+
-+ swd_remove_node (s, s->rp);
-+
-+ key = HEAD3 (s->b, s->bp);
-+ s->succ3[s->bp] = s_head3 (s, key);
-+ s->head3[key] = SWD_UINT (s->bp);
-+ s->best3[s->bp] = SWD_UINT (s->f + 1);
-+ s->llen3[key]++;
-+
-+ key = HEAD2 (s->b, s->bp);
-+ s->head2[key] = SWD_UINT (s->bp);;
-+
-+ swd_getbyte (s);
-+ }
-+}
-+
-+static void
-+swd_search (lzo1x_999_swd_t * s, lzo_uint node, lzo_uint cnt)
-+{
-+ const unsigned char *p1;
-+ const unsigned char *p2;
-+ const unsigned char *px;
-+
-+ lzo_uint m_len = s->m_len;
-+ const unsigned char *b = s->b;
-+ const unsigned char *bp = s->b + s->bp;
-+ const unsigned char *bx = s->b + s->bp + s->look;
-+ unsigned char scan_end1;
-+
-+ scan_end1 = bp[m_len - 1];
-+ for (; cnt-- > 0; node = s->succ3[node])
-+ {
-+ p1 = bp;
-+ p2 = b + node;
-+ px = bx;
-+
-+ if (p2[m_len - 1] == scan_end1 &&
-+ p2[m_len] == p1[m_len] &&
-+ p2[0] == p1[0] && p2[1] == p1[1])
-+ {
-+ lzo_uint i;
-+
-+ p1 += 2;
-+ p2 += 2;
-+ do
-+ {
-+ }
-+ while (++p1 < px && *p1 == *++p2);
-+
-+ i = p1 - bp;
-+
-+ if (i < SWD_BEST_OFF)
-+ {
-+ if (s->best_pos[i] == 0)
-+ s->best_pos[i] = node + 1;
-+ }
-+
-+ if (i > m_len)
-+ {
-+ s->m_len = m_len = i;
-+ s->m_pos = node;
-+ if (m_len == s->look)
-+ return;
-+ if (m_len >= s->nice_length)
-+ return;
-+ if (m_len > (lzo_uint) s->best3[node])
-+ return;
-+ scan_end1 = bp[m_len - 1];
-+ }
-+ }
-+ }
-+}
-+
-+static lzo_bool
-+swd_search2 (lzo1x_999_swd_t * s)
-+{
-+ lzo_uint key;
-+
-+ key = s->head2[HEAD2 (s->b, s->bp)];
-+ if (key == NIL2)
-+ return 0;
-+
-+ if (s->best_pos[2] == 0)
-+ s->best_pos[2] = key + 1;
-+
-+ if (s->m_len < 2)
-+ {
-+ s->m_len = 2;
-+ s->m_pos = key;
-+ }
-+ return 1;
-+}
-+
-+static void
-+swd_findbest (lzo1x_999_swd_t * s)
-+{
-+ lzo_uint key;
-+ lzo_uint cnt, node;
-+ lzo_uint len;
-+
-+ key = HEAD3 (s->b, s->bp);
-+ node = s->succ3[s->bp] = s_head3 (s, key);
-+ cnt = s->llen3[key]++;
-+
-+ if (cnt > s->max_chain && s->max_chain > 0)
-+ cnt = s->max_chain;
-+ s->head3[key] = SWD_UINT (s->bp);
-+
-+ s->b_char = s->b[s->bp];
-+ len = s->m_len;
-+ if (s->m_len >= s->look)
-+ {
-+ if (s->look == 0)
-+ s->b_char = -1;
-+ s->m_off = 0;
-+ s->best3[s->bp] = SWD_UINT (s->f + 1);
-+ }
-+ else
-+ {
-+
-+ if (swd_search2 (s))
-+
-+ if (s->look >= 3)
-+ swd_search (s, node, cnt);
-+ if (s->m_len > len)
-+ s->m_off = swd_pos2off (s, s->m_pos);
-+ s->best3[s->bp] = SWD_UINT (s->m_len);
-+
-+ if (s->use_best_off)
-+ {
-+ int i;
-+ for (i = 2; i < SWD_BEST_OFF; i++)
-+ if (s->best_pos[i] > 0)
-+ s->best_off[i] =
-+ swd_pos2off (s,
-+ s->best_pos[i] -
-+ 1);
-+ else
-+ s->best_off[i] = 0;
-+ }
-+
-+ }
-+
-+ swd_remove_node (s, s->rp);
-+
-+ key = HEAD2 (s->b, s->bp);
-+ s->head2[key] = SWD_UINT (s->bp);
-+
-+}
-+
-+/* lzo_mchw.ch */
-+
-+static int
-+init_match (lzo1x_999_t * c, lzo1x_999_swd_t * s,
-+ const lzo_byte * dict, lzo_uint dict_len, lzo_uint32 flags)
-+{
-+ int r;
-+
-+ c->init = 1;
-+
-+ s->c = c;
-+
-+ c->last_m_len = c->last_m_off = 0;
-+
-+ c->textsize = c->codesize = c->printcount = 0;
-+ c->lit_bytes = c->match_bytes = c->rep_bytes = 0;
-+ c->lazy = 0;
-+
-+ r = swd_init (s, dict, dict_len);
-+ if (r != 0)
-+ return r;
-+
-+ s->use_best_off = (flags & 1) ? 1 : 0;
-+ return r;
-+}
-+
-+static int
-+find_match (lzo1x_999_t * c, lzo1x_999_swd_t * s,
-+ lzo_uint this_len, lzo_uint skip)
-+{
-+ if (skip > 0)
-+ {
-+ swd_accept (s, this_len - skip);
-+ c->textsize += this_len - skip + 1;
-+ }
-+ else
-+ {
-+ c->textsize += this_len - skip;
-+ }
-+
-+ s->m_len = 1;
-+ s->m_len = 1;
-+
-+ if (s->use_best_off)
-+ memset (s->best_pos, 0, sizeof (s->best_pos));
-+
-+ swd_findbest (s);
-+ c->m_len = s->m_len;
-+ c->m_off = s->m_off;
-+
-+ swd_getbyte (s);
-+
-+ if (s->b_char < 0)
-+ {
-+ c->look = 0;
-+ c->m_len = 0;
-+ }
-+ else
-+ {
-+ c->look = s->look + 1;
-+ }
-+ c->bp = c->ip - c->look;
-+
-+ if (c->cb && c->textsize > c->printcount)
-+ {
-+ (*c->cb) (c->textsize, c->codesize);
-+ c->printcount += 1024;
-+ }
-+
-+ return LZO_E_OK;
-+}
-+
-+/* lzo1x_9x.c */
-+
-+static lzo_byte *
-+code_match (lzo1x_999_t * c, lzo_byte * op, lzo_uint m_len, lzo_uint m_off)
-+{
-+ lzo_uint x_len = m_len;
-+ lzo_uint x_off = m_off;
-+
-+ c->match_bytes += m_len;
-+
-+ if (m_len == 2)
-+ {
-+ m_off -= 1;
-+
-+ *op++ = LZO_BYTE (M1_MARKER | ((m_off & 3) << 2));
-+ *op++ = LZO_BYTE (m_off >> 2);
-+
-+ c->m1a_m++;
-+ }
-+
-+ else if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)
-+
-+ {
-+
-+ m_off -= 1;
-+ *op++ = LZO_BYTE (((m_len - 1) << 5) | ((m_off & 7) << 2));
-+ *op++ = LZO_BYTE (m_off >> 3);
-+ c->m2_m++;
-+ }
-+ else if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET
-+ && c->r1_lit >= 4)
-+ {
-+ m_off -= 1 + M2_MAX_OFFSET;
-+
-+ *op++ = LZO_BYTE (M1_MARKER | ((m_off & 3) << 2));
-+ *op++ = LZO_BYTE (m_off >> 2);
-+
-+ c->m1b_m++;
-+ }
-+ else if (m_off <= M3_MAX_OFFSET)
-+ {
-+ m_off -= 1;
-+ if (m_len <= M3_MAX_LEN)
-+ *op++ = LZO_BYTE (M3_MARKER | (m_len - 2));
-+ else
-+ {
-+ m_len -= M3_MAX_LEN;
-+ *op++ = M3_MARKER | 0;
-+ while (m_len > 255)
-+ {
-+ m_len -= 255;
-+ *op++ = 0;
-+ }
-+ *op++ = LZO_BYTE (m_len);
-+ }
-+
-+ *op++ = LZO_BYTE (m_off << 2);
-+ *op++ = LZO_BYTE (m_off >> 6);
-+
-+ c->m3_m++;
-+ }
-+ else
-+ {
-+ lzo_uint k;
-+
-+ m_off -= 0x4000;
-+ k = (m_off & 0x4000) >> 11;
-+ if (m_len <= M4_MAX_LEN)
-+ *op++ = LZO_BYTE (M4_MARKER | k | (m_len - 2));
-+ else
-+ {
-+ m_len -= M4_MAX_LEN;
-+ *op++ = LZO_BYTE (M4_MARKER | k | 0);
-+ while (m_len > 255)
-+ {
-+ m_len -= 255;
-+ *op++ = 0;
-+ }
-+ *op++ = LZO_BYTE (m_len);
-+ }
-+
-+ *op++ = LZO_BYTE (m_off << 2);
-+ *op++ = LZO_BYTE (m_off >> 6);
-+
-+ c->m4_m++;
-+ }
-+
-+ c->last_m_len = x_len;
-+ c->last_m_off = x_off;
-+ return op;
-+}
-+
-+static lzo_byte *
-+STORE_RUN (lzo1x_999_t * c, lzo_byte * op, const lzo_byte * ii, lzo_uint t)
-+{
-+ c->lit_bytes += t;
-+
-+ if (op == c->out && t <= 238)
-+ {
-+ *op++ = LZO_BYTE (17 + t);
-+ }
-+ else if (t <= 3)
-+ {
-+ op[-2] |= LZO_BYTE (t);
-+
-+ c->lit1_r++;
-+ }
-+ else if (t <= 18)
-+ {
-+ *op++ = LZO_BYTE (t - 3);
-+ c->lit2_r++;
-+ }
-+ else
-+ {
-+ lzo_uint tt = t - 18;
-+
-+ *op++ = 0;
-+ while (tt > 255)
-+ {
-+ tt -= 255;
-+ *op++ = 0;
-+ }
-+ *op++ = LZO_BYTE (tt);
-+ c->lit3_r++;
-+ }
-+ do
-+ *op++ = *ii++;
-+ while (--t > 0);
-+
-+ return op;
-+}
-+
-+static lzo_byte *
-+code_run (lzo1x_999_t * c, lzo_byte * op, const lzo_byte * ii,
-+ lzo_uint lit, lzo_uint m_len)
-+{
-+ if (lit > 0)
-+ {
-+ op = STORE_RUN (c, op, ii, lit);
-+ c->r1_m_len = m_len;
-+ c->r1_lit = lit;
-+ }
-+ else
-+ {
-+ c->r1_m_len = 0;
-+ c->r1_lit = 0;
-+ }
-+
-+ return op;
-+}
-+
-+static int
-+len_of_coded_match (lzo_uint m_len, lzo_uint m_off, lzo_uint lit)
-+{
-+ int n = 4;
-+
-+ if (m_len < 2)
-+ return -1;
-+ if (m_len == 2)
-+ return (m_off <= M1_MAX_OFFSET && lit > 0
-+ && lit < 4) ? 2 : -1;
-+ if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)
-+ return 2;
-+ if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && lit >= 4)
-+ return 2;
-+ if (m_off <= M3_MAX_OFFSET)
-+ {
-+ if (m_len <= M3_MAX_LEN)
-+ return 3;
-+ m_len -= M3_MAX_LEN;
-+ while (m_len > 255)
-+ {
-+ m_len -= 255;
-+ n++;
-+ }
-+ return n;
-+ }
-+ if (m_off <= M4_MAX_OFFSET)
-+ {
-+ if (m_len <= M4_MAX_LEN)
-+ return 3;
-+ m_len -= M4_MAX_LEN;
-+ while (m_len > 255)
-+ {
-+ m_len -= 255;
-+ n++;
-+ }
-+ return n;
-+ }
-+ return -1;
-+}
-+
-+static lzo_int
-+min_gain (lzo_uint ahead, lzo_uint lit1, lzo_uint lit2, int l1, int l2,
-+ int l3)
-+{
-+ lzo_int lazy_match_min_gain = 0;
-+
-+ lazy_match_min_gain += ahead;
-+
-+ if (lit1 <= 3)
-+ lazy_match_min_gain += (lit2 <= 3) ? 0 : 2;
-+ else if (lit1 <= 18)
-+ lazy_match_min_gain += (lit2 <= 18) ? 0 : 1;
-+
-+ lazy_match_min_gain += (l2 - l1) * 2;
-+ if (l3 > 0)
-+ lazy_match_min_gain -= (ahead - l3) * 2;
-+
-+ if (lazy_match_min_gain < 0)
-+ lazy_match_min_gain = 0;
-+
-+ return lazy_match_min_gain;
-+}
-+
-+static void
-+better_match (const lzo1x_999_swd_t * swd, lzo_uint * m_len, lzo_uint * m_off)
-+{
-+ if (*m_len <= M2_MIN_LEN)
-+ return;
-+
-+ if (*m_off <= M2_MAX_OFFSET)
-+ return;
-+
-+ if (*m_off > M2_MAX_OFFSET &&
-+ *m_len >= M2_MIN_LEN + 1 && *m_len <= M2_MAX_LEN + 1 &&
-+ swd->best_off[*m_len - 1]
-+ && swd->best_off[*m_len - 1] <= M2_MAX_OFFSET)
-+ {
-+ *m_len = *m_len - 1;
-+ *m_off = swd->best_off[*m_len];
-+ return;
-+ }
-+
-+ if (*m_off > M3_MAX_OFFSET &&
-+ *m_len >= M4_MAX_LEN + 1 && *m_len <= M2_MAX_LEN + 2 &&
-+ swd->best_off[*m_len - 2]
-+ && swd->best_off[*m_len - 2] <= M2_MAX_OFFSET)
-+ {
-+ *m_len = *m_len - 2;
-+ *m_off = swd->best_off[*m_len];
-+ return;
-+ }
-+
-+ if (*m_off > M3_MAX_OFFSET &&
-+ *m_len >= M4_MAX_LEN + 1 && *m_len <= M3_MAX_LEN + 1 &&
-+ swd->best_off[*m_len - 1]
-+ && swd->best_off[*m_len - 1] <= M3_MAX_OFFSET)
-+ {
-+ *m_len = *m_len - 1;
-+ *m_off = swd->best_off[*m_len];
-+ }
-+
-+}
-+
-+/* minilzo.c */
-+
-+static lzo_bool
-+lzo_assert (int expr)
-+{
-+ return (expr) ? 1 : 0;
-+}
-+
-+/* lzo1x_9x.c */
-+
-+static int
-+lzo1x_999_compress_internal (const lzo_byte * in, lzo_uint in_len,
-+ lzo_byte * out, lzo_uintp out_len,
-+ lzo_voidp wrkmem,
-+ const lzo_byte * dict, lzo_uint dict_len,
-+ lzo_progress_callback_t cb,
-+ int try_lazy,
-+ lzo_uint good_length,
-+ lzo_uint max_lazy,
-+ lzo_uint nice_length,
-+ lzo_uint max_chain, lzo_uint32 flags)
-+{
-+ lzo_byte *op;
-+ const lzo_byte *ii;
-+ lzo_uint lit;
-+ lzo_uint m_len, m_off;
-+ lzo1x_999_t cc;
-+ lzo1x_999_t *const c = &cc;
-+ lzo1x_999_swd_t *const swd = (lzo1x_999_swd_t *) wrkmem;
-+ int r;
-+
-+ if (!lzo_assert
-+ (LZO1X_999_MEM_COMPRESS >= lzo_sizeof (lzo1x_999_swd_t)))
-+ return LZO_E_ERROR;
-+
-+ if (try_lazy < 0)
-+ try_lazy = 1;
-+
-+ if (good_length <= 0)
-+ good_length = 32;
-+
-+ if (max_lazy <= 0)
-+ max_lazy = 32;
-+
-+ if (nice_length <= 0)
-+ nice_length = 0;
-+
-+ if (max_chain <= 0)
-+ max_chain = SWD_MAX_CHAIN;
-+
-+ c->init = 0;
-+ c->ip = c->in = in;
-+ c->in_end = in + in_len;
-+ c->out = out;
-+ c->cb = cb;
-+ c->m1a_m = c->m1b_m = c->m2_m = c->m3_m = c->m4_m = 0;
-+ c->lit1_r = c->lit2_r = c->lit3_r = 0;
-+
-+ op = out;
-+ ii = c->ip;
-+ lit = 0;
-+ c->r1_lit = c->r1_m_len = 0;
-+
-+ r = init_match (c, swd, dict, dict_len, flags);
-+ if (r != 0)
-+ return r;
-+ if (max_chain > 0)
-+ swd->max_chain = max_chain;
-+ if (nice_length > 0)
-+ swd->nice_length = nice_length;
-+
-+ r = find_match (c, swd, 0, 0);
-+ if (r != 0)
-+ return r;
-+ while (c->look > 0)
-+ {
-+ lzo_uint ahead;
-+ lzo_uint max_ahead;
-+ int l1, l2, l3;
-+
-+ c->codesize = op - out;
-+
-+ m_len = c->m_len;
-+ m_off = c->m_off;
-+
-+ if (lit == 0)
-+ ii = c->bp;
-+
-+ if (m_len < 2 ||
-+ (m_len == 2
-+ && (m_off > M1_MAX_OFFSET || lit == 0 || lit >= 4))
-+ || (m_len == 2 && op == out) || (op == out && lit == 0))
-+ {
-+
-+ m_len = 0;
-+ }
-+ else if (m_len == M2_MIN_LEN)
-+ {
-+
-+ if (m_off > MX_MAX_OFFSET && lit >= 4)
-+ m_len = 0;
-+ }
-+
-+ if (m_len == 0)
-+ {
-+
-+ lit++;
-+ swd->max_chain = max_chain;
-+ r = find_match (c, swd, 1, 0);
-+ continue;
-+ }
-+
-+ if (swd->use_best_off)
-+ better_match (swd, &m_len, &m_off);
-+
-+ ahead = 0;
-+ if (try_lazy <= 0 || m_len >= max_lazy)
-+ {
-+
-+ l1 = 0;
-+ max_ahead = 0;
-+ }
-+ else
-+ {
-+
-+ l1 = len_of_coded_match (m_len, m_off, lit);
-+
-+ max_ahead = LZO_MIN (try_lazy, l1 - 1);
-+
-+ }
-+
-+ while (ahead < max_ahead && c->look > m_len)
-+ {
-+ lzo_int lazy_match_min_gain;
-+
-+ if (m_len >= good_length)
-+ swd->max_chain = max_chain >> 2;
-+ else
-+ swd->max_chain = max_chain;
-+ r = find_match (c, swd, 1, 0);
-+ ahead++;
-+
-+ if (c->m_len < m_len)
-+ continue;
-+
-+ if (c->m_len == m_len && c->m_off >= m_off)
-+ continue;
-+
-+ if (swd->use_best_off)
-+ better_match (swd, &c->m_len, &c->m_off);
-+
-+ l2 = len_of_coded_match (c->m_len, c->m_off,
-+ lit + ahead);
-+ if (l2 < 0)
-+ continue;
-+
-+ l3 = (op == out) ? -1 : len_of_coded_match (ahead,
-+ m_off,
-+ lit);
-+
-+ lazy_match_min_gain =
-+ min_gain (ahead, lit, lit + ahead, l1, l2,
-+ l3);
-+ if (c->m_len >= m_len + lazy_match_min_gain)
-+ {
-+ c->lazy++;
-+
-+ if (l3 > 0)
-+ {
-+
-+ op = code_run (c, op, ii, lit, ahead);
-+ lit = 0;
-+
-+ op = code_match (c, op, ahead, m_off);
-+ }
-+ else
-+ {
-+ lit += ahead;
-+ }
-+ goto lazy_match_done;
-+ }
-+ }
-+
-+ op = code_run (c, op, ii, lit, m_len);
-+ lit = 0;
-+
-+ op = code_match (c, op, m_len, m_off);
-+ swd->max_chain = max_chain;
-+ r = find_match (c, swd, m_len, 1 + ahead);
-+
-+ lazy_match_done:;
-+ }
-+
-+ if (lit > 0)
-+ op = STORE_RUN (c, op, ii, lit);
-+
-+ *op++ = M4_MARKER | 1;
-+ *op++ = 0;
-+ *op++ = 0;
-+
-+ c->codesize = op - out;
-+
-+ *out_len = op - out;
-+
-+ if (c->cb)
-+ (*c->cb) (c->textsize, c->codesize);
-+
-+ return LZO_E_OK;
-+}
-+
-+static int
-+lzo1x_999_compress_level (const lzo_byte * in, lzo_uint in_len,
-+ lzo_byte * out, lzo_uintp out_len,
-+ lzo_voidp wrkmem,
-+ const lzo_byte * dict, lzo_uint dict_len,
-+ lzo_progress_callback_t cb, int compression_level)
-+{
-+ static const struct
-+ {
-+ int try_lazy;
-+ lzo_uint good_length;
-+ lzo_uint max_lazy;
-+ lzo_uint nice_length;
-+ lzo_uint max_chain;
-+ lzo_uint32 flags;
-+ } c[9] =
-+ {
-+ {
-+ 0, 0, 0, 8, 4, 0},
-+ {
-+ 0, 0, 0, 16, 8, 0},
-+ {
-+ 0, 0, 0, 32, 16, 0},
-+ {
-+ 1, 4, 4, 16, 16, 0},
-+ {
-+ 1, 8, 16, 32, 32, 0},
-+ {
-+ 1, 8, 16, 128, 128, 0},
-+ {
-+ 2, 8, 32, 128, 256, 0},
-+ {
-+ 2, 32, 128, F, 2048, 1},
-+ {
-+ 2, F, F, F, 4096, 1}
-+ };
-+
-+ if (compression_level < 1 || compression_level > 9)
-+ return LZO_E_ERROR;
-+
-+ compression_level -= 1;
-+ return lzo1x_999_compress_internal (in, in_len, out, out_len, wrkmem,
-+ dict, dict_len, cb,
-+ c[compression_level].try_lazy,
-+ c[compression_level].good_length,
-+ c[compression_level].max_lazy,
-+ 0,
-+ c[compression_level].max_chain,
-+ c[compression_level].flags);
-+}
-+
-+static int
-+lzo1x_999_compress (const lzo_byte * in, lzo_uint in_len,
-+ lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
-+{
-+ return lzo1x_999_compress_level (in, in_len, out, out_len, wrkmem,
-+ NULL, 0, 0, 8);
-+}
-+
-+/* minilzo.c */
-+
-+#ifdef JFFS2_LZO_1
-+static const lzo_byte __lzo_copyright[] = LZO_VERSION_STRING;
-+
-+static lzo_uint
-+_lzo1x_1_do_compress (const lzo_byte * in, lzo_uint in_len,
-+ lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
-+{
-+
-+ register const lzo_byte *ip;
-+
-+ lzo_byte *op;
-+ const lzo_byte *const in_end = in + in_len;
-+ const lzo_byte *const ip_end = in + in_len - 8 - 5;
-+ const lzo_byte *ii;
-+ lzo_dict_p const dict = (lzo_dict_p) wrkmem;
-+
-+ op = out;
-+ ip = in;
-+ ii = ip;
-+
-+ ip += 4;
-+ for (;;)
-+ {
-+ register const lzo_byte *m_pos;
-+
-+ lzo_uint m_off;
-+ lzo_uint m_len;
-+ lzo_uint dindex;
-+
-+ DINDEX1 (dindex, ip);
-+ GINDEX (m_pos, m_off, dict, dindex, in);
-+ if (LZO_CHECK_MPOS_NON_DET
-+ (m_pos, m_off, in, ip, M4_MAX_OFFSET))
-+ goto literal;
-+
-+ if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
-+ goto try_match;
-+ DINDEX2 (dindex, ip);
-+ GINDEX (m_pos, m_off, dict, dindex, in);
-+
-+ if (LZO_CHECK_MPOS_NON_DET
-+ (m_pos, m_off, in, ip, M4_MAX_OFFSET))
-+ goto literal;
-+ if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
-+ goto try_match;
-+ goto literal;
-+
-+ try_match:
-+ if (m_pos[0] != ip[0] || m_pos[1] != ip[1])
-+ {
-+ }
-+ else
-+ {
-+ if (m_pos[2] == ip[2])
-+ {
-+ goto match;
-+ }
-+ else
-+ {
-+ }
-+ }
-+
-+ literal:
-+ UPDATE_I (dict, 0, dindex, ip, in);
-+ ++ip;
-+ if (ip >= ip_end)
-+ break;
-+ continue;
-+
-+ match:
-+ UPDATE_I (dict, 0, dindex, ip, in);
-+
-+ if (pd (ip, ii) > 0)
-+ {
-+ register lzo_uint t = pd (ip, ii);
-+
-+ if (t <= 3)
-+ {
-+ op[-2] |= LZO_BYTE (t);
-+ }
-+ else if (t <= 18)
-+ *op++ = LZO_BYTE (t - 3);
-+ else
-+ {
-+ register lzo_uint tt = t - 18;
-+
-+ *op++ = 0;
-+ while (tt > 255)
-+ {
-+ tt -= 255;
-+ *op++ = 0;
-+ }
-+ *op++ = LZO_BYTE (tt);;
-+ }
-+ do
-+ *op++ = *ii++;
-+ while (--t > 0);
-+ }
-+
-+ ip += 3;
-+ if (m_pos[3] != *ip++ || m_pos[4] != *ip++
-+ || m_pos[5] != *ip++ || m_pos[6] != *ip++
-+ || m_pos[7] != *ip++ || m_pos[8] != *ip++)
-+ {
-+ --ip;
-+ m_len = ip - ii;
-+
-+ if (m_off <= M2_MAX_OFFSET)
-+ {
-+ m_off -= 1;
-+
-+ *op++ = LZO_BYTE (((m_len -
-+ 1) << 5) | ((m_off & 7) <<
-+ 2));
-+ *op++ = LZO_BYTE (m_off >> 3);
-+ }
-+ else if (m_off <= M3_MAX_OFFSET)
-+ {
-+ m_off -= 1;
-+ *op++ = LZO_BYTE (M3_MARKER | (m_len - 2));
-+ goto m3_m4_offset;
-+ }
-+ else
-+
-+ {
-+ m_off -= 0x4000;
-+
-+ *op++ = LZO_BYTE (M4_MARKER |
-+ ((m_off & 0x4000) >> 11) |
-+ (m_len - 2));
-+ goto m3_m4_offset;
-+ }
-+ }
-+ else
-+ {
-+ {
-+ const lzo_byte *end = in_end;
-+ const lzo_byte *m = m_pos + M2_MAX_LEN + 1;
-+ while (ip < end && *m == *ip)
-+ m++, ip++;
-+ m_len = (ip - ii);
-+ }
-+
-+
-+ if (m_off <= M3_MAX_OFFSET)
-+ {
-+ m_off -= 1;
-+ if (m_len <= 33)
-+ *op++ = LZO_BYTE (M3_MARKER |
-+ (m_len - 2));
-+ else
-+ {
-+ m_len -= 33;
-+ *op++ = M3_MARKER | 0;
-+ goto m3_m4_len;
-+ }
-+ }
-+ else
-+ {
-+ m_off -= 0x4000;
-+
-+ if (m_len <= M4_MAX_LEN)
-+ *op++ = LZO_BYTE (M4_MARKER |
-+ ((m_off & 0x4000) >>
-+ 11) | (m_len - 2));
-+
-+ else
-+ {
-+ m_len -= M4_MAX_LEN;
-+ *op++ = LZO_BYTE (M4_MARKER |
-+ ((m_off & 0x4000) >>
-+ 11));
-+ m3_m4_len:
-+ while (m_len > 255)
-+ {
-+ m_len -= 255;
-+ *op++ = 0;
-+ }
-+
-+ *op++ = LZO_BYTE (m_len);
-+ }
-+ }
-+
-+ m3_m4_offset:
-+ *op++ = LZO_BYTE ((m_off & 63) << 2);
-+ *op++ = LZO_BYTE (m_off >> 6);
-+ }
-+ ii = ip;
-+ if (ip >= ip_end)
-+ break;
-+ }
-+
-+ *out_len = op - out;
-+ return pd (in_end, ii);
-+}
-+#endif
-+
-+#ifdef JFFS2_LZO_1
-+static int
-+lzo1x_1_compress (const lzo_byte * in, lzo_uint in_len,
-+ lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
-+{
-+ lzo_byte *op = out;
-+ lzo_uint t;
-+
-+ if (in_len <= M2_MAX_LEN + 5)
-+ t = in_len;
-+ else
-+ {
-+ t = _lzo1x_1_do_compress (in, in_len, op, out_len, wrkmem);
-+ op += *out_len;
-+ }
-+
-+ if (t > 0)
-+ {
-+ const lzo_byte *ii = in + in_len - t;
-+
-+ if (op == out && t <= 238)
-+ *op++ = LZO_BYTE (17 + t);
-+ else if (t <= 3)
-+ op[-2] |= LZO_BYTE (t);
-+ else if (t <= 18)
-+ *op++ = LZO_BYTE (t - 3);
-+ else
-+ {
-+ lzo_uint tt = t - 18;
-+
-+ *op++ = 0;
-+ while (tt > 255)
-+ {
-+ tt -= 255;
-+ *op++ = 0;
-+ }
-+
-+ *op++ = LZO_BYTE (tt);
-+ }
-+ do
-+ *op++ = *ii++;
-+ while (--t > 0);
-+ }
-+
-+ *op++ = M4_MARKER | 1;
-+ *op++ = 0;
-+ *op++ = 0;
-+
-+ *out_len = op - out;
-+ return 0;
-+}
-+#endif
-+
-+static int
-+lzo1x_decompress (const lzo_byte * in, lzo_uint in_len,
-+ lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
-+{
-+ register lzo_byte *op;
-+ register const lzo_byte *ip;
-+ register lzo_uint t;
-+
-+ register const lzo_byte *m_pos;
-+
-+ const lzo_byte *const ip_end = in + in_len;
-+ lzo_byte *const op_end = out + *out_len;
-+
-+ *out_len = 0;
-+
-+ op = out;
-+ ip = in;
-+
-+ if (*ip > 17)
-+ {
-+ t = *ip++ - 17;
-+ if (t < 4)
-+ goto match_next;
-+ NEED_OP (t);
-+ NEED_IP (t + 1);
-+ do
-+ *op++ = *ip++;
-+ while (--t > 0);
-+ goto first_literal_run;
-+ }
-+
-+ while (TEST_IP && TEST_OP)
-+ {
-+ t = *ip++;
-+ if (t >= 16)
-+ goto match;
-+ if (t == 0)
-+ {
-+ NEED_IP (1);
-+ while (*ip == 0)
-+ {
-+ t += 255;
-+ ip++;
-+ NEED_IP (1);
-+ }
-+ t += 15 + *ip++;
-+ }
-+ NEED_OP (t + 3);
-+ NEED_IP (t + 4);
-+ if (PTR_ALIGNED2_4 (op, ip))
-+ {
-+ COPY4 (op, ip);
-+
-+ op += 4;
-+ ip += 4;
-+ if (--t > 0)
-+ {
-+ if (t >= 4)
-+ {
-+ do
-+ {
-+ COPY4 (op, ip);
-+ op += 4;
-+ ip += 4;
-+ t -= 4;
-+ }
-+ while (t >= 4);
-+ if (t > 0)
-+ do
-+ *op++ = *ip++;
-+ while (--t > 0);
-+ }
-+ else
-+ do
-+ *op++ = *ip++;
-+ while (--t > 0);
-+ }
-+ }
-+ else
-+ {
-+ *op++ = *ip++;
-+ *op++ = *ip++;
-+ *op++ = *ip++;
-+ do
-+ *op++ = *ip++;
-+ while (--t > 0);
-+ }
-+ first_literal_run:
-+
-+ t = *ip++;
-+ if (t >= 16)
-+ goto match;
-+
-+ m_pos = op - (1 + M2_MAX_OFFSET);
-+ m_pos -= t >> 2;
-+ m_pos -= *ip++ << 2;
-+ TEST_LOOKBEHIND (m_pos, out);
-+ NEED_OP (3);
-+ *op++ = *m_pos++;
-+ *op++ = *m_pos++;
-+ *op++ = *m_pos;
-+
-+ goto match_done;
-+
-+ while (TEST_IP && TEST_OP)
-+ {
-+ match:
-+ if (t >= 64)
-+ {
-+ m_pos = op - 1;
-+ m_pos -= (t >> 2) & 7;
-+ m_pos -= *ip++ << 3;
-+ t = (t >> 5) - 1;
-+ TEST_LOOKBEHIND (m_pos, out);
-+ NEED_OP (t + 3 - 1);
-+ goto copy_match;
-+
-+ }
-+ else if (t >= 32)
-+ {
-+ t &= 31;
-+ if (t == 0)
-+ {
-+ NEED_IP (1);
-+ while (*ip == 0)
-+ {
-+ t += 255;
-+ ip++;
-+ NEED_IP (1);
-+ }
-+ t += 31 + *ip++;
-+ }
-+
-+ m_pos = op - 1;
-+ m_pos -= (ip[0] >> 2) + (ip[1] << 6);
-+
-+ ip += 2;
-+ }
-+ else if (t >= 16)
-+ {
-+ m_pos = op;
-+ m_pos -= (t & 8) << 11;
-+
-+ t &= 7;
-+ if (t == 0)
-+ {
-+ NEED_IP (1);
-+ while (*ip == 0)
-+ {
-+ t += 255;
-+ ip++;
-+ NEED_IP (1);
-+ }
-+ t += 7 + *ip++;
-+ }
-+
-+ m_pos -= (ip[0] >> 2) + (ip[1] << 6);
-+
-+ ip += 2;
-+ if (m_pos == op)
-+ goto eof_found;
-+ m_pos -= 0x4000;
-+ }
-+ else
-+ {
-+
-+ m_pos = op - 1;
-+ m_pos -= t >> 2;
-+ m_pos -= *ip++ << 2;
-+ TEST_LOOKBEHIND (m_pos, out);
-+ NEED_OP (2);
-+ *op++ = *m_pos++;
-+ *op++ = *m_pos;
-+
-+ goto match_done;
-+ }
-+
-+ TEST_LOOKBEHIND (m_pos, out);
-+ NEED_OP (t + 3 - 1);
-+ if (t >= 2 * 4 - (3 - 1)
-+ && PTR_ALIGNED2_4 (op, m_pos))
-+ {
-+ COPY4 (op, m_pos);
-+ op += 4;
-+ m_pos += 4;
-+ t -= 4 - (3 - 1);
-+ do
-+ {
-+ COPY4 (op, m_pos);
-+ op += 4;
-+ m_pos += 4;
-+ t -= 4;
-+ }
-+ while (t >= 4);
-+ if (t > 0)
-+ do
-+ *op++ = *m_pos++;
-+ while (--t > 0);
-+ }
-+ else
-+
-+ {
-+ copy_match:
-+ *op++ = *m_pos++;
-+ *op++ = *m_pos++;
-+ do
-+ *op++ = *m_pos++;
-+ while (--t > 0);
-+ }
-+
-+ match_done:
-+ t = ip[-2] & 3;
-+
-+ if (t == 0)
-+ break;
-+
-+ match_next:
-+ NEED_OP (t);
-+ NEED_IP (t + 1);
-+ do
-+ *op++ = *ip++;
-+ while (--t > 0);
-+ t = *ip++;
-+ }
-+ }
-+ *out_len = op - out;
-+ return LZO_E_EOF_NOT_FOUND;
-+
-+ eof_found:
-+ *out_len = op - out;
-+ return (ip == ip_end ? LZO_E_OK :
-+ (ip <
-+ ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
-+
-+ input_overrun:
-+ *out_len = op - out;
-+ return LZO_E_INPUT_OVERRUN;
-+
-+ output_overrun:
-+ *out_len = op - out;
-+ return LZO_E_OUTPUT_OVERRUN;
-+
-+ lookbehind_overrun:
-+ *out_len = op - out;
-+ return LZO_E_LOOKBEHIND_OVERRUN;
-+}
-+
-+/* lzo1x_oo.ch */
-+
-+#define NO_LIT LZO_UINT_MAX
-+
-+static void
-+copy2 (lzo_byte * ip, const lzo_byte * m_pos, lzo_ptrdiff_t off)
-+{
-+ ip[0] = m_pos[0];
-+ if (off == 1)
-+ ip[1] = m_pos[0];
-+ else
-+ ip[1] = m_pos[1];
-+}
-+
-+static void
-+copy3 (lzo_byte * ip, const lzo_byte * m_pos, lzo_ptrdiff_t off)
-+{
-+ ip[0] = m_pos[0];
-+ if (off == 1)
-+ {
-+ ip[2] = ip[1] = m_pos[0];
-+ }
-+ else if (off == 2)
-+ {
-+ ip[1] = m_pos[1];
-+ ip[2] = m_pos[0];
-+ }
-+ else
-+ {
-+ ip[1] = m_pos[1];
-+ ip[2] = m_pos[2];
-+ }
-+}
-+
-+static int
-+lzo1x_optimize (lzo_byte * in, lzo_uint in_len,
-+ lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
-+{
-+ register lzo_byte *op;
-+ register lzo_byte *ip;
-+ register lzo_uint t;
-+ register lzo_byte *m_pos;
-+ lzo_uint nl;
-+ const lzo_byte *const ip_end = in + in_len;
-+ const lzo_byte *const op_end = out + *out_len;
-+ lzo_byte *litp = NULL;
-+ lzo_uint lit = 0;
-+ lzo_uint next_lit = NO_LIT;
-+ long o_m1_a = 0, o_m1_b = 0, o_m2 = 0, o_m3_a = 0, o_m3_b = 0;
-+
-+ *out_len = 0;
-+
-+ op = out;
-+ ip = in;
-+
-+ if (*ip > 17)
-+ {
-+ t = *ip++ - 17;
-+ if (t < 4)
-+ goto match_next;
-+ goto first_literal_run;
-+ }
-+
-+ while (TEST_IP && TEST_OP)
-+ {
-+ t = *ip++;
-+ if (t >= 16)
-+ goto match;
-+ litp = ip - 1;
-+ if (t == 0)
-+ {
-+ t = 15;
-+ while (*ip == 0)
-+ t += 255, ip++;
-+ t += *ip++;
-+ }
-+ lit = t + 3;
-+ copy_literal_run:
-+ *op++ = *ip++;
-+ *op++ = *ip++;
-+ *op++ = *ip++;
-+ first_literal_run:
-+ do
-+ *op++ = *ip++;
-+ while (--t > 0);
-+
-+ t = *ip++;
-+
-+ if (t >= 16)
-+ goto match;
-+ m_pos = op - 1 - 0x800;
-+ m_pos -= t >> 2;
-+ m_pos -= *ip++ << 2;
-+ *op++ = *m_pos++;
-+ *op++ = *m_pos++;
-+ *op++ = *m_pos++;
-+ lit = 0;
-+ goto match_done;
-+
-+ while (TEST_IP && TEST_OP)
-+ {
-+ if (t < 16)
-+ {
-+ m_pos = op - 1;
-+ m_pos -= t >> 2;
-+ m_pos -= *ip++ << 2;
-+
-+ if (litp == NULL)
-+ goto copy_m1;
-+
-+ nl = ip[-2] & 3;
-+ if (nl == 0 && lit == 1 && ip[0] >= 16)
-+ {
-+ next_lit = nl;
-+ lit += 2;
-+ *litp = LZO_BYTE ((*litp & ~3) | lit);
-+ copy2 (ip - 2, m_pos, op - m_pos);
-+ o_m1_a++;
-+ }
-+ else if (nl == 0 && ip[0] < 16 && ip[0] != 0
-+ && (lit + 2 + ip[0] < 16))
-+ {
-+ t = *ip++;
-+ *litp &= ~3;
-+ copy2 (ip - 3 + 1, m_pos, op - m_pos);
-+ litp += 2;
-+ if (lit > 0)
-+ memmove (litp + 1, litp, lit);
-+ lit += 2 + t + 3;
-+ *litp = LZO_BYTE (lit - 3);
-+
-+ o_m1_b++;
-+ *op++ = *m_pos++;
-+ *op++ = *m_pos++;
-+ goto copy_literal_run;
-+ }
-+ copy_m1:
-+ *op++ = *m_pos++;
-+ *op++ = *m_pos++;
-+ }
-+ else
-+ {
-+ match:
-+ if (t >= 64)
-+ {
-+ m_pos = op - 1;
-+ m_pos -= (t >> 2) & 7;
-+ m_pos -= *ip++ << 3;
-+ t = (t >> 5) - 1;
-+ if (litp == NULL)
-+ goto copy_m;
-+
-+ nl = ip[-2] & 3;
-+ if (t == 1 && lit > 3 && nl == 0 &&
-+ ip[0] < 16 && ip[0] != 0
-+ && (lit + 3 + ip[0] < 16))
-+ {
-+ t = *ip++;
-+ copy3 (ip - 1 - 2, m_pos,
-+ op - m_pos);
-+ lit += 3 + t + 3;
-+ *litp = LZO_BYTE (lit - 3);
-+ o_m2++;
-+ *op++ = *m_pos++;
-+ *op++ = *m_pos++;
-+ *op++ = *m_pos++;
-+ goto copy_literal_run;
-+ }
-+ }
-+ else
-+ {
-+ if (t >= 32)
-+ {
-+ t &= 31;
-+ if (t == 0)
-+ {
-+ t = 31;
-+ while (*ip == 0)
-+ t += 255,
-+ ip++;
-+ t += *ip++;
-+ }
-+ m_pos = op - 1;
-+ m_pos -= *ip++ >> 2;
-+ m_pos -= *ip++ << 6;
-+ }
-+ else
-+ {
-+ m_pos = op;
-+ m_pos -= (t & 8) << 11;
-+ t &= 7;
-+ if (t == 0)
-+ {
-+ t = 7;
-+ while (*ip == 0)
-+ t += 255,
-+ ip++;
-+ t += *ip++;
-+ }
-+ m_pos -= *ip++ >> 2;
-+ m_pos -= *ip++ << 6;
-+ if (m_pos == op)
-+ goto eof_found;
-+ m_pos -= 0x4000;
-+ }
-+ if (litp == NULL)
-+ goto copy_m;
-+
-+ nl = ip[-2] & 3;
-+ if (t == 1 && lit == 0 && nl == 0
-+ && ip[0] >= 16)
-+ {
-+ next_lit = nl;
-+ lit += 3;
-+ *litp = LZO_BYTE ((*litp & ~3)
-+ | lit);
-+ copy3 (ip - 3, m_pos,
-+ op - m_pos);
-+ o_m3_a++;
-+ }
-+ else if (t == 1 && lit <= 3 && nl == 0
-+ && ip[0] < 16 && ip[0] != 0
-+ && (lit + 3 + ip[0] < 16))
-+ {
-+ t = *ip++;
-+ *litp &= ~3;
-+ copy3 (ip - 4 + 1, m_pos,
-+ op - m_pos);
-+ litp += 2;
-+ if (lit > 0)
-+ memmove (litp + 1,
-+ litp, lit);
-+ lit += 3 + t + 3;
-+ *litp = LZO_BYTE (lit - 3);
-+
-+ o_m3_b++;
-+ *op++ = *m_pos++;
-+ *op++ = *m_pos++;
-+ *op++ = *m_pos++;
-+ goto copy_literal_run;
-+ }
-+ }
-+ copy_m:
-+ *op++ = *m_pos++;
-+ *op++ = *m_pos++;
-+ do
-+ *op++ = *m_pos++;
-+ while (--t > 0);
-+ }
-+
-+ match_done:
-+ if (next_lit == NO_LIT)
-+ {
-+ t = ip[-2] & 3;
-+ lit = t;
-+ litp = ip - 2;
-+ }
-+ else
-+ t = next_lit;
-+ next_lit = NO_LIT;
-+ if (t == 0)
-+ break;
-+ match_next:
-+ do
-+ *op++ = *ip++;
-+ while (--t > 0);
-+ t = *ip++;
-+ }
-+ }
-+
-+ *out_len = op - out;
-+ return LZO_E_EOF_NOT_FOUND;
-+
-+ eof_found:
-+ *out_len = op - out;
-+ return (ip == ip_end ? LZO_E_OK :
-+ (ip <
-+ ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
-+}
-+
-+/* interface to jffs2 follows */
-+
-+#include "compr.h"
-+#include <linux/jffs2.h>
-+
-+/*#define BLOCKSIZE JFFS2_PAGE_SIZE
-+#define OUTBLOCKSIZE (BLOCKSIZE + BLOCKSIZE / 64 + 16 + 3)*/
-+
-+int jffs2_lzo_compress (unsigned char *input,
-+ unsigned char *output, uint32_t *sourcelen,
-+ uint32_t *dstlen, void *model);
-+
-+int jffs2_lzo_decompress (unsigned char *input,
-+ unsigned char *output, uint32_t sourcelen,
-+ uint32_t dstlen, void *model);
-+
-+static struct jffs2_compressor jffs2_lzo_comp = {
-+ .priority = JFFS2_LZO_PRIORITY,
-+ .name = "lzo",
-+ .compr = JFFS2_COMPR_LZO,
-+ .compress = &jffs2_lzo_compress,
-+ .decompress = &jffs2_lzo_decompress,
-+#ifdef JFFS2_LZO_DISABLED
-+ .disabled = 1,
-+#else
-+ .disabled = 0,
-+#endif
-+};
-+
-+#ifdef JFFS2_LZO_1
-+static int
-+no_lzo1x_optimize (lzo_byte * src, lzo_uint src_len,
-+ lzo_byte * dst, lzo_uintp dst_len, lzo_voidp wrkmem)
-+{
-+ return 0;
-+}
-+#endif
-+
-+static lzo_compress_t lzo1x_compressor = lzo1x_999_compress;
-+static lzo_optimize_t lzo1x_optimizer = lzo1x_optimize;
-+#ifdef JFFS2_LZO_1
-+static int lzo1x_compressor_type = 999;
-+static int lzo1x_optimize_type = 1;
-+#endif
-+static unsigned long lzo1x_compressor_memsize = LZO1X_999_MEM_COMPRESS;
-+
-+static lzo_bytep wrkmem = NULL; /* temporary buffer for compression, used by lzo */
-+static lzo_bytep cmprssmem = NULL; /* temporary buffer for compression, used by interface */
-+static int cmprssmem_size = 0;
-+
-+static int prepare_out_buf(uint32_t ssize, uint32_t dsize)
-+{
-+ uint32_t msize,req;
-+
-+ msize = (ssize>dsize)? ssize : dsize;
-+ req = (msize<<1) + 20;
-+ if ((!cmprssmem)||(cmprssmem_size<req)) {
-+ if (!cmprssmem) {
-+ vfree(cmprssmem);
-+ cmprssmem = NULL;
-+ cmprssmem_size = 0;
-+ }
-+ cmprssmem = vmalloc(req);
-+ if (!cmprssmem) {
-+ return -1;
-+ }
-+ cmprssmem_size = req;
-+ }
-+ return 0;
-+}
-+
-+int jffs2_lzo_compress (unsigned char *input,
-+ unsigned char *output, uint32_t *sourcelen,
-+ uint32_t *dstlen, void *model)
-+{
-+ lzo_uint csize = *dstlen; /*BLOCKSIZE;*/
-+ lzo_uint isize = *sourcelen;
-+ int retval;
-+
-+ if (prepare_out_buf(*sourcelen,*dstlen)) {
-+ return -1;
-+ }
-+ if ((retval =
-+ lzo1x_compressor (input, *sourcelen, cmprssmem, &csize,
-+ wrkmem)) != LZO_E_OK)
-+ {
-+ return retval;
-+ }
-+ else
-+ {
-+ retval = lzo1x_optimizer (cmprssmem, csize, input, &isize,
-+ NULL);
-+ if (csize <= *dstlen) {
-+ *dstlen = csize;
-+ memcpy (output, cmprssmem, csize);
-+ return retval;
-+ } else {
-+ return -1;
-+ }
-+ }
-+}
-+
-+int jffs2_lzo_decompress (unsigned char *input,
-+ unsigned char *output, uint32_t sourcelen,
-+ uint32_t dstlen, void *model)
-+{
-+ lzo_uint outlen = dstlen;
-+ return lzo1x_decompress (input, sourcelen, output, &outlen, NULL);
-+}
-+
-+int jffs2_lzo_init (void)
-+{
-+ wrkmem = (lzo_bytep) vmalloc(lzo1x_compressor_memsize);
-+ if (!wrkmem) return -1;
-+ jffs2_register_compressor(&jffs2_lzo_comp);
-+ return 0;
-+}
-+
-+void jffs2_lzo_exit (void)
-+{
-+ jffs2_unregister_compressor (&jffs2_lzo_comp);
-+ if (cmprssmem) vfree(cmprssmem);
-+ vfree(wrkmem);
-+}
---- linux-2.4.21/fs/jffs2/compr_rtime.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/compr_rtime.c
-@@ -1,43 +1,19 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
- * Created by Arjan van de Ven <arjanv@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: compr_rtime.c,v 1.5 2001/03/15 15:38:23 dwmw2 Exp $
-+ * $Id: compr_rtime.c,v 1.14 2004/06/23 16:34:40 havasi Exp $
- *
- *
- * Very simple lz77-ish encoder.
- *
- * Theory of operation: Both encoder and decoder have a list of "last
-- * occurances" for every possible source-value; after sending the
-+ * occurrences" for every possible source-value; after sending the
- * first source-byte, the second byte indicated the "run" length of
- * matches
- *
-@@ -49,12 +25,14 @@
- #include <linux/types.h>
- #include <linux/errno.h>
- #include <linux/string.h>
-+#include <linux/jffs2.h>
-+#include "compr.h"
-
- /* _compress returns the compressed size, -1 if bigger */
--int rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 *sourcelen, __u32 *dstlen)
-+int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t *sourcelen, uint32_t *dstlen, void *model)
- {
-- int positions[256];
-+ short positions[256];
- int outpos = 0;
- int pos=0;
-
-@@ -91,10 +69,10 @@
- }
-
-
--void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 srclen, __u32 destlen)
-+int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t srclen, uint32_t destlen, void *model)
- {
-- int positions[256];
-+ short positions[256];
- int outpos = 0;
- int pos=0;
-
-@@ -123,6 +101,28 @@
- }
- }
- }
-+ return 0;
- }
-
-+static struct jffs2_compressor jffs2_rtime_comp = {
-+ .priority = JFFS2_RTIME_PRIORITY,
-+ .name = "rtime",
-+ .compr = JFFS2_COMPR_RTIME,
-+ .compress = &jffs2_rtime_compress,
-+ .decompress = &jffs2_rtime_decompress,
-+#ifdef JFFS2_RTIME_DISABLED
-+ .disabled = 1,
-+#else
-+ .disabled = 0,
-+#endif
-+};
-+
-+int jffs2_rtime_init(void)
-+{
-+ return jffs2_register_compressor(&jffs2_rtime_comp);
-+}
-
-+void jffs2_rtime_exit(void)
-+{
-+ jffs2_unregister_compressor(&jffs2_rtime_comp);
-+}
---- linux-2.4.21/fs/jffs2/compr_rubin.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/compr_rubin.c
-@@ -1,49 +1,25 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001, 2002 Red Hat, Inc.
- *
- * Created by Arjan van de Ven <arjanv@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: compr_rubin.c,v 1.13 2001/09/23 10:06:05 rmk Exp $
-+ * $Id: compr_rubin.c,v 1.20 2004/06/23 16:34:40 havasi Exp $
- *
- */
-
-
- #include <linux/string.h>
- #include <linux/types.h>
-+#include <linux/jffs2.h>
- #include "compr_rubin.h"
- #include "histo_mips.h"
-+#include "compr.h"
-
--
--
--void init_rubin(struct rubin_state *rs, int div, int *bits)
-+static void init_rubin(struct rubin_state *rs, int div, int *bits)
- {
- int c;
-
-@@ -56,7 +32,7 @@
- }
-
-
--int encode(struct rubin_state *rs, long A, long B, int symbol)
-+static int encode(struct rubin_state *rs, long A, long B, int symbol)
- {
-
- long i0, i1;
-@@ -91,7 +67,7 @@
- }
-
-
--void end_rubin(struct rubin_state *rs)
-+static void end_rubin(struct rubin_state *rs)
- {
-
- int i;
-@@ -104,7 +80,7 @@
- }
-
-
--void init_decode(struct rubin_state *rs, int div, int *bits)
-+static void init_decode(struct rubin_state *rs, int div, int *bits)
- {
- init_rubin(rs, div, bits);
-
-@@ -151,7 +127,7 @@
- rs->rec_q = rec_q;
- }
-
--int decode(struct rubin_state *rs, long A, long B)
-+static int decode(struct rubin_state *rs, long A, long B)
- {
- unsigned long p = rs->p, q = rs->q;
- long i0, threshold;
-@@ -212,8 +188,8 @@
-
-
-
--int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in,
-- unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen)
-+static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in,
-+ unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen)
- {
- int outpos = 0;
- int pos=0;
-@@ -246,20 +222,20 @@
- }
- #if 0
- /* _compress returns the compressed size, -1 if bigger */
--int rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 *sourcelen, __u32 *dstlen)
-+int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t *sourcelen, uint32_t *dstlen, void *model)
- {
- return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
- }
- #endif
--int dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 *sourcelen, __u32 *dstlen)
-+int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t *sourcelen, uint32_t *dstlen, void *model)
- {
- int bits[8];
- unsigned char histo[256];
- int i;
- int ret;
-- __u32 mysrclen, mydstlen;
-+ uint32_t mysrclen, mydstlen;
-
- mysrclen = *sourcelen;
- mydstlen = *dstlen - 8;
-@@ -315,8 +291,8 @@
- return 0;
- }
-
--void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in,
-- unsigned char *page_out, __u32 srclen, __u32 destlen)
-+static void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in,
-+ unsigned char *page_out, uint32_t srclen, uint32_t destlen)
- {
- int outpos = 0;
- struct rubin_state rs;
-@@ -330,14 +306,15 @@
- }
-
-
--void rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 sourcelen, __u32 dstlen)
-+int jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t sourcelen, uint32_t dstlen, void *model)
- {
- rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
-+ return 0;
- }
-
--void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 sourcelen, __u32 dstlen)
-+int jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t sourcelen, uint32_t dstlen, void *model)
- {
- int bits[8];
- int c;
-@@ -346,4 +323,51 @@
- bits[c] = data_in[c];
-
- rubin_do_decompress(256, bits, data_in+8, cpage_out, sourcelen-8, dstlen);
-+ return 0;
-+}
-+
-+static struct jffs2_compressor jffs2_rubinmips_comp = {
-+ .priority = JFFS2_RUBINMIPS_PRIORITY,
-+ .name = "rubinmips",
-+ .compr = JFFS2_COMPR_DYNRUBIN,
-+ .compress = NULL, /*&jffs2_rubinmips_compress,*/
-+ .decompress = &jffs2_rubinmips_decompress,
-+#ifdef JFFS2_RUBINMIPS_DISABLED
-+ .disabled = 1,
-+#else
-+ .disabled = 0,
-+#endif
-+};
-+
-+int jffs2_rubinmips_init(void)
-+{
-+ return jffs2_register_compressor(&jffs2_rubinmips_comp);
-+}
-+
-+void jffs2_rubinmips_exit(void)
-+{
-+ jffs2_unregister_compressor(&jffs2_rubinmips_comp);
-+}
-+
-+static struct jffs2_compressor jffs2_dynrubin_comp = {
-+ .priority = JFFS2_DYNRUBIN_PRIORITY,
-+ .name = "dynrubin",
-+ .compr = JFFS2_COMPR_RUBINMIPS,
-+ .compress = jffs2_dynrubin_compress,
-+ .decompress = &jffs2_dynrubin_decompress,
-+#ifdef JFFS2_DYNRUBIN_DISABLED
-+ .disabled = 1,
-+#else
-+ .disabled = 0,
-+#endif
-+};
-+
-+int jffs2_dynrubin_init(void)
-+{
-+ return jffs2_register_compressor(&jffs2_dynrubin_comp);
-+}
-+
-+void jffs2_dynrubin_exit(void)
-+{
-+ jffs2_unregister_compressor(&jffs2_dynrubin_comp);
- }
---- linux-2.4.21/fs/jffs2/compr_rubin.h~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/compr_rubin.h
-@@ -1,7 +1,7 @@
- /* Rubin encoder/decoder header */
- /* work started at : aug 3, 1994 */
- /* last modification : aug 15, 1994 */
--/* $Id: compr_rubin.h,v 1.5 2001/02/26 13:50:01 dwmw2 Exp $ */
-+/* $Id: compr_rubin.h,v 1.6 2002/01/25 01:49:26 dwmw2 Exp $ */
-
- #include "pushpull.h"
-
-@@ -19,10 +19,3 @@
- int bit_divider;
- int bits[8];
- };
--
--
--void init_rubin (struct rubin_state *rs, int div, int *bits);
--int encode (struct rubin_state *, long, long, int);
--void end_rubin (struct rubin_state *);
--void init_decode (struct rubin_state *, int div, int *bits);
--int decode (struct rubin_state *, long, long);
---- linux-2.4.21/fs/jffs2/compr_zlib.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/compr_zlib.c
-@@ -1,51 +1,28 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001, 2002 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: compr_zlib.c,v 1.8.2.1 2002/10/11 09:04:44 dwmw2 Exp $
-+ * $Id: compr_zlib.c,v 1.29 2004/11/16 20:36:11 dwmw2 Exp $
- *
- */
-
--#ifndef __KERNEL__
-+#if !defined(__KERNEL__) && !defined(__ECOS)
- #error "The userspace support got too messy and was removed. Update your mkfs.jffs2"
- #endif
-
- #include <linux/config.h>
- #include <linux/kernel.h>
--#include <linux/mtd/compatmac.h> /* for min() */
- #include <linux/slab.h>
--#include <linux/jffs2.h>
- #include <linux/zlib.h>
-+#include <linux/zutil.h>
-+#include <asm/semaphore.h>
- #include "nodelist.h"
-+#include "compr.h"
-
- /* Plan: call deflate() with avail_in == *sourcelen,
- avail_out = *dstlen - 12 and flush == Z_FINISH.
-@@ -58,120 +35,184 @@
-
- static DECLARE_MUTEX(deflate_sem);
- static DECLARE_MUTEX(inflate_sem);
--static void *deflate_workspace;
--static void *inflate_workspace;
-+static z_stream inf_strm, def_strm;
-
--int __init jffs2_zlib_init(void)
-+#ifdef __KERNEL__ /* Linux-only */
-+#include <linux/vmalloc.h>
-+#include <linux/init.h>
-+
-+static int __init alloc_workspaces(void)
- {
-- deflate_workspace = vmalloc(zlib_deflate_workspacesize());
-- if (!deflate_workspace) {
-+ def_strm.workspace = vmalloc(zlib_deflate_workspacesize());
-+ if (!def_strm.workspace) {
- printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize());
- return -ENOMEM;
- }
- D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize()));
-- inflate_workspace = vmalloc(zlib_inflate_workspacesize());
-- if (!inflate_workspace) {
-+ inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
-+ if (!inf_strm.workspace) {
- printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize());
-- vfree(deflate_workspace);
-+ vfree(def_strm.workspace);
- return -ENOMEM;
- }
- D1(printk(KERN_DEBUG "Allocated %d bytes for inflate workspace\n", zlib_inflate_workspacesize()));
- return 0;
- }
-
--void jffs2_zlib_exit(void)
-+static void free_workspaces(void)
- {
-- vfree(deflate_workspace);
-- vfree(inflate_workspace);
-+ vfree(def_strm.workspace);
-+ vfree(inf_strm.workspace);
- }
-+#else
-+#define alloc_workspaces() (0)
-+#define free_workspaces() do { } while(0)
-+#endif /* __KERNEL__ */
-
--int zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 *sourcelen, __u32 *dstlen)
-+int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t *sourcelen, uint32_t *dstlen, void *model)
- {
-- z_stream strm;
- int ret;
-
- if (*dstlen <= STREAM_END_SPACE)
- return -1;
-
- down(&deflate_sem);
-- strm.workspace = deflate_workspace;
-
-- if (Z_OK != zlib_deflateInit(&strm, 3)) {
-+ if (Z_OK != zlib_deflateInit(&def_strm, 3)) {
- printk(KERN_WARNING "deflateInit failed\n");
- up(&deflate_sem);
- return -1;
- }
-
-- strm.next_in = data_in;
-- strm.total_in = 0;
-+ def_strm.next_in = data_in;
-+ def_strm.total_in = 0;
-
-- strm.next_out = cpage_out;
-- strm.total_out = 0;
-+ def_strm.next_out = cpage_out;
-+ def_strm.total_out = 0;
-
-- while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) {
-- strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE);
-- strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out);
-+ while (def_strm.total_out < *dstlen - STREAM_END_SPACE && def_strm.total_in < *sourcelen) {
-+ def_strm.avail_out = *dstlen - (def_strm.total_out + STREAM_END_SPACE);
-+ def_strm.avail_in = min((unsigned)(*sourcelen-def_strm.total_in), def_strm.avail_out);
- D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n",
-- strm.avail_in, strm.avail_out));
-- ret = zlib_deflate(&strm, Z_PARTIAL_FLUSH);
-+ def_strm.avail_in, def_strm.avail_out));
-+ ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH);
- D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n",
-- strm.avail_in, strm.avail_out, strm.total_in, strm.total_out));
-+ def_strm.avail_in, def_strm.avail_out, def_strm.total_in, def_strm.total_out));
- if (ret != Z_OK) {
- D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret));
-- zlib_deflateEnd(&strm);
-+ zlib_deflateEnd(&def_strm);
- up(&deflate_sem);
- return -1;
- }
- }
-- strm.avail_out += STREAM_END_SPACE;
-- strm.avail_in = 0;
-- ret = zlib_deflate(&strm, Z_FINISH);
-- zlib_deflateEnd(&strm);
-- up(&deflate_sem);
-+ def_strm.avail_out += STREAM_END_SPACE;
-+ def_strm.avail_in = 0;
-+ ret = zlib_deflate(&def_strm, Z_FINISH);
-+ zlib_deflateEnd(&def_strm);
-+
- if (ret != Z_STREAM_END) {
- D1(printk(KERN_DEBUG "final deflate returned %d\n", ret));
-- return -1;
-+ ret = -1;
-+ goto out;
- }
-
-- D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n",
-- strm.total_in, strm.total_out));
-+ if (def_strm.total_out >= def_strm.total_in) {
-+ D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld; failing\n",
-+ def_strm.total_in, def_strm.total_out));
-+ ret = -1;
-+ goto out;
-+ }
-
-- if (strm.total_out >= strm.total_in)
-- return -1;
-+ D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n",
-+ def_strm.total_in, def_strm.total_out));
-
-- *dstlen = strm.total_out;
-- *sourcelen = strm.total_in;
-- return 0;
-+ *dstlen = def_strm.total_out;
-+ *sourcelen = def_strm.total_in;
-+ ret = 0;
-+ out:
-+ up(&deflate_sem);
-+ return ret;
- }
-
--void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 srclen, __u32 destlen)
-+int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t srclen, uint32_t destlen, void *model)
- {
-- z_stream strm;
- int ret;
-+ int wbits = MAX_WBITS;
-
- down(&inflate_sem);
-- strm.workspace = inflate_workspace;
-
-- if (Z_OK != zlib_inflateInit(&strm)) {
-+ inf_strm.next_in = data_in;
-+ inf_strm.avail_in = srclen;
-+ inf_strm.total_in = 0;
-+
-+ inf_strm.next_out = cpage_out;
-+ inf_strm.avail_out = destlen;
-+ inf_strm.total_out = 0;
-+
-+ /* If it's deflate, and it's got no preset dictionary, then
-+ we can tell zlib to skip the adler32 check. */
-+ if (srclen > 2 && !(data_in[1] & PRESET_DICT) &&
-+ ((data_in[0] & 0x0f) == Z_DEFLATED) &&
-+ !(((data_in[0]<<8) + data_in[1]) % 31)) {
-+
-+ D2(printk(KERN_DEBUG "inflate skipping adler32\n"));
-+ wbits = -((data_in[0] >> 4) + 8);
-+ inf_strm.next_in += 2;
-+ inf_strm.avail_in -= 2;
-+ } else {
-+ /* Let this remain D1 for now -- it should never happen */
-+ D1(printk(KERN_DEBUG "inflate not skipping adler32\n"));
-+ }
-+
-+
-+ if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) {
- printk(KERN_WARNING "inflateInit failed\n");
- up(&inflate_sem);
-- return;
-+ return 1;
- }
-- strm.next_in = data_in;
-- strm.avail_in = srclen;
-- strm.total_in = 0;
--
-- strm.next_out = cpage_out;
-- strm.avail_out = destlen;
-- strm.total_out = 0;
-
-- while((ret = zlib_inflate(&strm, Z_FINISH)) == Z_OK)
-+ while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK)
- ;
- if (ret != Z_STREAM_END) {
- printk(KERN_NOTICE "inflate returned %d\n", ret);
- }
-- zlib_inflateEnd(&strm);
-+ zlib_inflateEnd(&inf_strm);
- up(&inflate_sem);
-+ return 0;
-+}
-+
-+static struct jffs2_compressor jffs2_zlib_comp = {
-+ .priority = JFFS2_ZLIB_PRIORITY,
-+ .name = "zlib",
-+ .compr = JFFS2_COMPR_ZLIB,
-+ .compress = &jffs2_zlib_compress,
-+ .decompress = &jffs2_zlib_decompress,
-+#ifdef JFFS2_ZLIB_DISABLED
-+ .disabled = 1,
-+#else
-+ .disabled = 0,
-+#endif
-+};
-+
-+int __init jffs2_zlib_init(void)
-+{
-+ int ret;
-+
-+ ret = alloc_workspaces();
-+ if (ret)
-+ return ret;
-+
-+ ret = jffs2_register_compressor(&jffs2_zlib_comp);
-+ if (ret)
-+ free_workspaces();
-+
-+ return ret;
-+}
-+
-+void jffs2_zlib_exit(void)
-+{
-+ jffs2_unregister_compressor(&jffs2_zlib_comp);
-+ free_workspaces();
- }
---- linux-2.4.21/fs/jffs2/crc32.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/crc32.c
-@@ -37,11 +37,11 @@
- * polynomial $edb88320
- */
-
--/* $Id: crc32.c,v 1.3 2001/02/07 16:45:32 dwmw2 Exp $ */
-+/* $Id: crc32.c,v 1.4 2002/01/03 15:20:44 dwmw2 Exp $ */
-
- #include "crc32.h"
-
--const __u32 crc32_table[256] = {
-+const uint32_t crc32_table[256] = {
- 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
- 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
- 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
---- linux-2.4.21/fs/jffs2/crc32.h~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/crc32.h
-@@ -1,16 +1,16 @@
- #ifndef CRC32_H
- #define CRC32_H
-
--/* $Id: crc32.h,v 1.3 2001/02/26 14:44:37 dwmw2 Exp $ */
-+/* $Id: crc32.h,v 1.4 2002/01/03 15:20:44 dwmw2 Exp $ */
-
- #include <linux/types.h>
-
--extern const __u32 crc32_table[256];
-+extern const uint32_t crc32_table[256];
-
- /* Return a 32-bit CRC of the contents of the buffer. */
-
--static inline __u32
--crc32(__u32 val, const void *ss, int len)
-+static inline uint32_t
-+crc32(uint32_t val, const void *ss, int len)
- {
- const unsigned char *s = ss;
- while (--len >= 0)
---- linux-2.4.21/fs/jffs2/dir.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/dir.c
-@@ -1,84 +1,73 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: dir.c,v 1.45.2.7 2002/08/26 15:30:18 dwmw2 Exp $
-+ * $Id: dir.c,v 1.85 2005/03/01 10:34:03 dedekind Exp $
- *
- */
-
- #include <linux/kernel.h>
- #include <linux/slab.h>
-+#include <linux/sched.h>
- #include <linux/fs.h>
--#include <linux/mtd/compatmac.h> /* For completion */
-+#include <linux/crc32.h>
- #include <linux/jffs2.h>
- #include <linux/jffs2_fs_i.h>
- #include <linux/jffs2_fs_sb.h>
-+#include <linux/time.h>
- #include "nodelist.h"
--#include "crc32.h"
-+
-+/* Urgh. Please tell me there's a nicer way of doing these. */
-+#include <linux/version.h>
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48)
-+typedef int mknod_arg_t;
-+#define NAMEI_COMPAT(x) ((void *)x)
-+#else
-+typedef dev_t mknod_arg_t;
-+#define NAMEI_COMPAT(x) (x)
-+#endif
-
- static int jffs2_readdir (struct file *, void *, filldir_t);
-
--static int jffs2_create (struct inode *,struct dentry *,int);
--static struct dentry *jffs2_lookup (struct inode *,struct dentry *);
-+static int jffs2_create (struct inode *,struct dentry *,int,
-+ struct nameidata *);
-+static struct dentry *jffs2_lookup (struct inode *,struct dentry *,
-+ struct nameidata *);
- static int jffs2_link (struct dentry *,struct inode *,struct dentry *);
- static int jffs2_unlink (struct inode *,struct dentry *);
- static int jffs2_symlink (struct inode *,struct dentry *,const char *);
- static int jffs2_mkdir (struct inode *,struct dentry *,int);
- static int jffs2_rmdir (struct inode *,struct dentry *);
--static int jffs2_mknod (struct inode *,struct dentry *,int,int);
-+static int jffs2_mknod (struct inode *,struct dentry *,int,mknod_arg_t);
- static int jffs2_rename (struct inode *, struct dentry *,
- struct inode *, struct dentry *);
-
- struct file_operations jffs2_dir_operations =
- {
-- read: generic_read_dir,
-- readdir: jffs2_readdir,
-- ioctl: jffs2_ioctl,
-- fsync: jffs2_null_fsync
-+ .read = generic_read_dir,
-+ .readdir = jffs2_readdir,
-+ .ioctl = jffs2_ioctl,
-+ .fsync = jffs2_fsync
- };
-
-
- struct inode_operations jffs2_dir_inode_operations =
- {
-- create: jffs2_create,
-- lookup: jffs2_lookup,
-- link: jffs2_link,
-- unlink: jffs2_unlink,
-- symlink: jffs2_symlink,
-- mkdir: jffs2_mkdir,
-- rmdir: jffs2_rmdir,
-- mknod: jffs2_mknod,
-- rename: jffs2_rename,
-- setattr: jffs2_setattr,
-+ .create = NAMEI_COMPAT(jffs2_create),
-+ .lookup = NAMEI_COMPAT(jffs2_lookup),
-+ .link = jffs2_link,
-+ .unlink = jffs2_unlink,
-+ .symlink = jffs2_symlink,
-+ .mkdir = jffs2_mkdir,
-+ .rmdir = jffs2_rmdir,
-+ .mknod = jffs2_mknod,
-+ .rename = jffs2_rename,
-+ .setattr = jffs2_setattr,
- };
-
- /***********************************************************************/
-@@ -88,12 +77,13 @@
- and we use the same hash function as the dentries. Makes this
- nice and simple
- */
--static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target)
-+static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
-+ struct nameidata *nd)
- {
- struct jffs2_inode_info *dir_f;
- struct jffs2_sb_info *c;
- struct jffs2_full_dirent *fd = NULL, *fd_list;
-- __u32 ino = 0;
-+ uint32_t ino = 0;
- struct inode *inode = NULL;
-
- D1(printk(KERN_DEBUG "jffs2_lookup()\n"));
-@@ -153,8 +143,9 @@
- offset++;
- }
- if (offset == 1) {
-- D1(printk(KERN_DEBUG "Dirent 1: \"..\", ino #%lu\n", filp->f_dentry->d_parent->d_inode->i_ino));
-- if (filldir(dirent, "..", 2, 1, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
-+ unsigned long pino = parent_ino(filp->f_dentry);
-+ D1(printk(KERN_DEBUG "Dirent 1: \"..\", ino #%lu\n", pino));
-+ if (filldir(dirent, "..", 2, 1, pino, DT_DIR) < 0)
- goto out;
- offset++;
- }
-@@ -188,18 +179,14 @@
-
- /***********************************************************************/
-
--static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode)
-+
-+static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
-+ struct nameidata *nd)
- {
-+ struct jffs2_raw_inode *ri;
- struct jffs2_inode_info *f, *dir_f;
- struct jffs2_sb_info *c;
- struct inode *inode;
-- struct jffs2_raw_inode *ri;
-- struct jffs2_raw_dirent *rd;
-- struct jffs2_full_dnode *fn;
-- struct jffs2_full_dirent *fd;
-- int namelen;
-- __u32 alloclen, phys_ofs;
-- __u32 writtenlen;
- int ret;
-
- ri = jffs2_alloc_raw_inode();
-@@ -210,23 +197,11 @@
-
- D1(printk(KERN_DEBUG "jffs2_create()\n"));
-
-- /* Try to reserve enough space for both node and dirent.
-- * Just the node will do for now, though
-- */
-- namelen = dentry->d_name.len;
-- ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);
-- D1(printk(KERN_DEBUG "jffs2_create(): reserved 0x%x bytes\n", alloclen));
-- if (ret) {
-- jffs2_free_raw_inode(ri);
-- return ret;
-- }
--
- inode = jffs2_new_inode(dir_i, mode, ri);
-
- if (IS_ERR(inode)) {
- D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n"));
- jffs2_free_raw_inode(ri);
-- jffs2_complete_reservation(c);
- return PTR_ERR(inode);
- }
-
-@@ -236,93 +211,21 @@
- inode->i_mapping->nrpages = 0;
-
- f = JFFS2_INODE_INFO(inode);
-+ dir_f = JFFS2_INODE_INFO(dir_i);
-
-- ri->data_crc = 0;
-- ri->node_crc = crc32(0, ri, sizeof(*ri)-8);
--
-- fn = jffs2_write_dnode(inode, ri, NULL, 0, phys_ofs, &writtenlen);
-- D1(printk(KERN_DEBUG "jffs2_create created file with mode 0x%x\n", ri->mode));
-- jffs2_free_raw_inode(ri);
--
-- if (IS_ERR(fn)) {
-- D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n"));
-- /* Eeek. Wave bye bye */
-- up(&f->sem);
-- jffs2_complete_reservation(c);
-- jffs2_clear_inode(inode);
-- return PTR_ERR(fn);
-- }
-- /* No data here. Only a metadata node, which will be
-- obsoleted by the first data write
-- */
-- f->metadata = fn;
--
-- /* Work out where to put the dirent node now. */
-- writtenlen = PAD(writtenlen);
-- phys_ofs += writtenlen;
-- alloclen -= writtenlen;
-- up(&f->sem);
--
-- if (alloclen < sizeof(*rd)+namelen) {
-- /* Not enough space left in this chunk. Get some more */
-- jffs2_complete_reservation(c);
-- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
-+ ret = jffs2_do_create(c, dir_f, f, ri,
-+ dentry->d_name.name, dentry->d_name.len);
-
- if (ret) {
-- /* Eep. */
-- D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n"));
-- jffs2_clear_inode(inode);
-+ make_bad_inode(inode);
-+ iput(inode);
-+ jffs2_free_raw_inode(ri);
- return ret;
- }
-- }
--
-- rd = jffs2_alloc_raw_dirent();
-- if (!rd) {
-- /* Argh. Now we treat it like a normal delete */
-- jffs2_complete_reservation(c);
-- jffs2_clear_inode(inode);
-- return -ENOMEM;
-- }
--
-- dir_f = JFFS2_INODE_INFO(dir_i);
-- down(&dir_f->sem);
--
-- rd->magic = JFFS2_MAGIC_BITMASK;
-- rd->nodetype = JFFS2_NODETYPE_DIRENT;
-- rd->totlen = sizeof(*rd) + namelen;
-- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
-
-- rd->pino = dir_i->i_ino;
-- rd->version = ++dir_f->highest_version;
-- rd->ino = inode->i_ino;
-- rd->mctime = CURRENT_TIME;
-- rd->nsize = namelen;
-- rd->type = DT_REG;
-- rd->node_crc = crc32(0, rd, sizeof(*rd)-8);
-- rd->name_crc = crc32(0, dentry->d_name.name, namelen);
--
-- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
--
-- jffs2_complete_reservation(c);
--
-- if (IS_ERR(fd)) {
-- /* dirent failed to write. Delete the inode normally
-- as if it were the final unlink() */
-- jffs2_free_raw_dirent(rd);
-- up(&dir_f->sem);
-- jffs2_clear_inode(inode);
-- return PTR_ERR(fd);
-- }
--
-- dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
--
-- jffs2_free_raw_dirent(rd);
--
-- /* Link the fd into the inode's list, obsoleting an old
-- one if necessary. */
-- jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-- up(&dir_f->sem);
-+ dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime));
-
-+ jffs2_free_raw_inode(ri);
- d_instantiate(dentry, inode);
-
- D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n",
-@@ -332,173 +235,48 @@
-
- /***********************************************************************/
-
--static int jffs2_do_unlink(struct inode *dir_i, struct dentry *dentry, int rename)
--{
-- struct jffs2_inode_info *dir_f, *f;
-- struct jffs2_sb_info *c;
-- struct jffs2_raw_dirent *rd;
-- struct jffs2_full_dirent *fd;
-- __u32 alloclen, phys_ofs;
-- int ret;
--
-- c = JFFS2_SB_INFO(dir_i->i_sb);
--
-- rd = jffs2_alloc_raw_dirent();
-- if (!rd)
-- return -ENOMEM;
--
-- ret = jffs2_reserve_space(c, sizeof(*rd)+dentry->d_name.len, &phys_ofs, &alloclen, ALLOC_DELETION);
-- if (ret) {
-- jffs2_free_raw_dirent(rd);
-- return ret;
-- }
--
-- dir_f = JFFS2_INODE_INFO(dir_i);
-- down(&dir_f->sem);
--
-- /* Build a deletion node */
-- rd->magic = JFFS2_MAGIC_BITMASK;
-- rd->nodetype = JFFS2_NODETYPE_DIRENT;
-- rd->totlen = sizeof(*rd) + dentry->d_name.len;
-- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
--
-- rd->pino = dir_i->i_ino;
-- rd->version = ++dir_f->highest_version;
-- rd->ino = 0;
-- rd->mctime = CURRENT_TIME;
-- rd->nsize = dentry->d_name.len;
-- rd->type = DT_UNKNOWN;
-- rd->node_crc = crc32(0, rd, sizeof(*rd)-8);
-- rd->name_crc = crc32(0, dentry->d_name.name, dentry->d_name.len);
--
-- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, dentry->d_name.len, phys_ofs, NULL);
--
-- jffs2_complete_reservation(c);
-- jffs2_free_raw_dirent(rd);
--
-- if (IS_ERR(fd)) {
-- up(&dir_f->sem);
-- return PTR_ERR(fd);
-- }
--
-- /* File it. This will mark the old one obsolete. */
-- jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-- up(&dir_f->sem);
--
-- if (!rename) {
-- f = JFFS2_INODE_INFO(dentry->d_inode);
-- down(&f->sem);
--
-- while (f->dents) {
-- /* There can be only deleted ones */
-- fd = f->dents;
--
-- f->dents = fd->next;
--
-- if (fd->ino) {
-- printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
-- f->inocache->ino, fd->name, fd->ino);
-- } else {
-- D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, f->inocache->ino));
-- }
-- jffs2_mark_node_obsolete(c, fd->raw);
-- jffs2_free_full_dirent(fd);
-- }
-- /* Don't oops on unlinking a bad inode */
-- if (f->inocache)
-- f->inocache->nlink--;
-- dentry->d_inode->i_nlink--;
-- up(&f->sem);
-- }
--
-- return 0;
--}
-
- static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
- {
-- return jffs2_do_unlink(dir_i, dentry, 0);
--}
--/***********************************************************************/
--
--static int jffs2_do_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry, int rename)
--{
-- struct jffs2_inode_info *dir_f, *f;
-- struct jffs2_sb_info *c;
-- struct jffs2_raw_dirent *rd;
-- struct jffs2_full_dirent *fd;
-- __u32 alloclen, phys_ofs;
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
-+ struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
-+ struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(dentry->d_inode);
- int ret;
-
-- c = JFFS2_SB_INFO(dir_i->i_sb);
--
-- rd = jffs2_alloc_raw_dirent();
-- if (!rd)
-- return -ENOMEM;
--
-- ret = jffs2_reserve_space(c, sizeof(*rd)+dentry->d_name.len, &phys_ofs, &alloclen, ALLOC_NORMAL);
-- if (ret) {
-- jffs2_free_raw_dirent(rd);
-+ ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
-+ dentry->d_name.len, dead_f);
-+ if (dead_f->inocache)
-+ dentry->d_inode->i_nlink = dead_f->inocache->nlink;
- return ret;
-- }
--
-- dir_f = JFFS2_INODE_INFO(dir_i);
-- down(&dir_f->sem);
--
-- /* Build a deletion node */
-- rd->magic = JFFS2_MAGIC_BITMASK;
-- rd->nodetype = JFFS2_NODETYPE_DIRENT;
-- rd->totlen = sizeof(*rd) + dentry->d_name.len;
-- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
--
-- rd->pino = dir_i->i_ino;
-- rd->version = ++dir_f->highest_version;
-- rd->ino = old_dentry->d_inode->i_ino;
-- rd->mctime = CURRENT_TIME;
-- rd->nsize = dentry->d_name.len;
--
-- /* XXX: This is ugly. */
-- rd->type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12;
-- if (!rd->type) rd->type = DT_REG;
--
-- rd->node_crc = crc32(0, rd, sizeof(*rd)-8);
-- rd->name_crc = crc32(0, dentry->d_name.name, dentry->d_name.len);
--
-- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, dentry->d_name.len, phys_ofs, NULL);
--
-- jffs2_complete_reservation(c);
-- jffs2_free_raw_dirent(rd);
--
-- if (IS_ERR(fd)) {
-- up(&dir_f->sem);
-- return PTR_ERR(fd);
-- }
--
-- /* File it. This will mark the old one obsolete. */
-- jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-- up(&dir_f->sem);
--
-- if (!rename) {
-- f = JFFS2_INODE_INFO(old_dentry->d_inode);
-- down(&f->sem);
-- old_dentry->d_inode->i_nlink = ++f->inocache->nlink;
-- up(&f->sem);
-- }
-- return 0;
- }
-+/***********************************************************************/
-+
-
- static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
- {
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_inode->i_sb);
-+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
-+ struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
- int ret;
-+ uint8_t type;
-
-- /* Can't link a bad inode. */
-- if (!JFFS2_INODE_INFO(old_dentry->d_inode)->inocache)
-+ /* Don't let people make hard links to bad inodes. */
-+ if (!f->inocache)
- return -EIO;
-
- if (S_ISDIR(old_dentry->d_inode->i_mode))
- return -EPERM;
-
-- ret = jffs2_do_link(old_dentry, dir_i, dentry, 0);
-+ /* XXX: This is ugly */
-+ type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12;
-+ if (!type) type = DT_REG;
-+
-+ ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len);
-+
- if (!ret) {
-+ down(&f->sem);
-+ old_dentry->d_inode->i_nlink = ++f->inocache->nlink;
-+ up(&f->sem);
- d_instantiate(dentry, old_dentry->d_inode);
- atomic_inc(&old_dentry->d_inode->i_count);
- }
-@@ -517,13 +295,12 @@
- struct jffs2_full_dnode *fn;
- struct jffs2_full_dirent *fd;
- int namelen;
-- __u32 alloclen, phys_ofs;
-- __u32 writtenlen;
-- int ret;
-+ uint32_t alloclen, phys_ofs;
-+ int ret, targetlen = strlen(target);
-
- /* FIXME: If you care. We'd need to use frags for the target
- if it grows much more than this */
-- if (strlen(target) > 254)
-+ if (targetlen > 254)
- return -EINVAL;
-
- ri = jffs2_alloc_raw_inode();
-@@ -537,7 +314,7 @@
- * Just the node will do for now, though
- */
- namelen = dentry->d_name.len;
-- ret = jffs2_reserve_space(c, sizeof(*ri) + strlen(target), &phys_ofs, &alloclen, ALLOC_NORMAL);
-+ ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL);
-
- if (ret) {
- jffs2_free_raw_inode(ri);
-@@ -556,15 +333,16 @@
-
- f = JFFS2_INODE_INFO(inode);
-
-- inode->i_size = ri->isize = ri->dsize = ri->csize = strlen(target);
-- ri->totlen = sizeof(*ri) + ri->dsize;
-- ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4);
-+ inode->i_size = targetlen;
-+ ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size);
-+ ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size);
-+ ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
-
- ri->compr = JFFS2_COMPR_NONE;
-- ri->data_crc = crc32(0, target, strlen(target));
-- ri->node_crc = crc32(0, ri, sizeof(*ri)-8);
-+ ri->data_crc = cpu_to_je32(crc32(0, target, targetlen));
-+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-
-- fn = jffs2_write_dnode(inode, ri, target, strlen(target), phys_ofs, &writtenlen);
-+ fn = jffs2_write_dnode(c, f, ri, target, targetlen, phys_ofs, ALLOC_NORMAL);
-
- jffs2_free_raw_inode(ri);
-
-@@ -575,19 +353,26 @@
- jffs2_clear_inode(inode);
- return PTR_ERR(fn);
- }
-+
-+ /* We use f->dents field to store the target path. */
-+ f->dents = kmalloc(targetlen + 1, GFP_KERNEL);
-+ if (!f->dents) {
-+ printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1);
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+ jffs2_clear_inode(inode);
-+ return -ENOMEM;
-+ }
-+
-+ memcpy(f->dents, target, targetlen + 1);
-+ D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->dents));
-+
- /* No data here. Only a metadata node, which will be
- obsoleted by the first data write
- */
- f->metadata = fn;
- up(&f->sem);
-
-- /* Work out where to put the dirent node now. */
-- writtenlen = (writtenlen+3)&~3;
-- phys_ofs += writtenlen;
-- alloclen -= writtenlen;
--
-- if (alloclen < sizeof(*rd)+namelen) {
-- /* Not enough space left in this chunk. Get some more */
- jffs2_complete_reservation(c);
- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
- if (ret) {
-@@ -595,7 +380,6 @@
- jffs2_clear_inode(inode);
- return ret;
- }
-- }
-
- rd = jffs2_alloc_raw_dirent();
- if (!rd) {
-@@ -608,41 +392,42 @@
- dir_f = JFFS2_INODE_INFO(dir_i);
- down(&dir_f->sem);
-
-- rd->magic = JFFS2_MAGIC_BITMASK;
-- rd->nodetype = JFFS2_NODETYPE_DIRENT;
-- rd->totlen = sizeof(*rd) + namelen;
-- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
-+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
-+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
-+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
-
-- rd->pino = dir_i->i_ino;
-- rd->version = ++dir_f->highest_version;
-- rd->ino = inode->i_ino;
-- rd->mctime = CURRENT_TIME;
-+ rd->pino = cpu_to_je32(dir_i->i_ino);
-+ rd->version = cpu_to_je32(++dir_f->highest_version);
-+ rd->ino = cpu_to_je32(inode->i_ino);
-+ rd->mctime = cpu_to_je32(get_seconds());
- rd->nsize = namelen;
- rd->type = DT_LNK;
-- rd->node_crc = crc32(0, rd, sizeof(*rd)-8);
-- rd->name_crc = crc32(0, dentry->d_name.name, namelen);
--
-- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
-+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-+ rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
-
-- jffs2_complete_reservation(c);
-+ fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL);
-
- if (IS_ERR(fd)) {
- /* dirent failed to write. Delete the inode normally
- as if it were the final unlink() */
-+ jffs2_complete_reservation(c);
- jffs2_free_raw_dirent(rd);
- up(&dir_f->sem);
- jffs2_clear_inode(inode);
- return PTR_ERR(fd);
- }
-
-- dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
-+ dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
-
- jffs2_free_raw_dirent(rd);
-
- /* Link the fd into the inode's list, obsoleting an old
- one if necessary. */
- jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-+
- up(&dir_f->sem);
-+ jffs2_complete_reservation(c);
-
- d_instantiate(dentry, inode);
- return 0;
-@@ -659,8 +444,7 @@
- struct jffs2_full_dnode *fn;
- struct jffs2_full_dirent *fd;
- int namelen;
-- __u32 alloclen, phys_ofs;
-- __u32 writtenlen;
-+ uint32_t alloclen, phys_ofs;
- int ret;
-
- mode |= S_IFDIR;
-@@ -692,13 +476,15 @@
-
- inode->i_op = &jffs2_dir_inode_operations;
- inode->i_fop = &jffs2_dir_operations;
-+ /* Directories get nlink 2 at start */
-+ inode->i_nlink = 2;
-
- f = JFFS2_INODE_INFO(inode);
-
-- ri->data_crc = 0;
-- ri->node_crc = crc32(0, ri, sizeof(*ri)-8);
-+ ri->data_crc = cpu_to_je32(0);
-+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-
-- fn = jffs2_write_dnode(inode, ri, NULL, 0, phys_ofs, &writtenlen);
-+ fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
-
- jffs2_free_raw_inode(ri);
-
-@@ -715,13 +501,6 @@
- f->metadata = fn;
- up(&f->sem);
-
-- /* Work out where to put the dirent node now. */
-- writtenlen = PAD(writtenlen);
-- phys_ofs += writtenlen;
-- alloclen -= writtenlen;
--
-- if (alloclen < sizeof(*rd)+namelen) {
-- /* Not enough space left in this chunk. Get some more */
- jffs2_complete_reservation(c);
- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
- if (ret) {
-@@ -729,7 +508,6 @@
- jffs2_clear_inode(inode);
- return ret;
- }
-- }
-
- rd = jffs2_alloc_raw_dirent();
- if (!rd) {
-@@ -742,41 +520,43 @@
- dir_f = JFFS2_INODE_INFO(dir_i);
- down(&dir_f->sem);
-
-- rd->magic = JFFS2_MAGIC_BITMASK;
-- rd->nodetype = JFFS2_NODETYPE_DIRENT;
-- rd->totlen = sizeof(*rd) + namelen;
-- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
-+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
-+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
-+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
-
-- rd->pino = dir_i->i_ino;
-- rd->version = ++dir_f->highest_version;
-- rd->ino = inode->i_ino;
-- rd->mctime = CURRENT_TIME;
-+ rd->pino = cpu_to_je32(dir_i->i_ino);
-+ rd->version = cpu_to_je32(++dir_f->highest_version);
-+ rd->ino = cpu_to_je32(inode->i_ino);
-+ rd->mctime = cpu_to_je32(get_seconds());
- rd->nsize = namelen;
- rd->type = DT_DIR;
-- rd->node_crc = crc32(0, rd, sizeof(*rd)-8);
-- rd->name_crc = crc32(0, dentry->d_name.name, namelen);
--
-- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
-+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-+ rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
-
-- jffs2_complete_reservation(c);
-+ fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL);
-
- if (IS_ERR(fd)) {
- /* dirent failed to write. Delete the inode normally
- as if it were the final unlink() */
-+ jffs2_complete_reservation(c);
- jffs2_free_raw_dirent(rd);
- up(&dir_f->sem);
- jffs2_clear_inode(inode);
- return PTR_ERR(fd);
- }
-
-- dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
-+ dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
-+ dir_i->i_nlink++;
-
- jffs2_free_raw_dirent(rd);
-
- /* Link the fd into the inode's list, obsoleting an old
- one if necessary. */
- jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-+
- up(&dir_f->sem);
-+ jffs2_complete_reservation(c);
-
- d_instantiate(dentry, inode);
- return 0;
-@@ -786,15 +566,19 @@
- {
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
- struct jffs2_full_dirent *fd;
-+ int ret;
-
- for (fd = f->dents ; fd; fd = fd->next) {
- if (fd->ino)
- return -ENOTEMPTY;
- }
-- return jffs2_unlink(dir_i, dentry);
-+ ret = jffs2_unlink(dir_i, dentry);
-+ if (!ret)
-+ dir_i->i_nlink--;
-+ return ret;
- }
-
--static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, int rdev)
-+static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, mknod_arg_t rdev)
- {
- struct jffs2_inode_info *f, *dir_f;
- struct jffs2_sb_info *c;
-@@ -804,12 +588,14 @@
- struct jffs2_full_dnode *fn;
- struct jffs2_full_dirent *fd;
- int namelen;
-- unsigned short dev;
-+ jint16_t dev;
- int devlen = 0;
-- __u32 alloclen, phys_ofs;
-- __u32 writtenlen;
-+ uint32_t alloclen, phys_ofs;
- int ret;
-
-+ if (!old_valid_dev(rdev))
-+ return -EINVAL;
-+
- ri = jffs2_alloc_raw_inode();
- if (!ri)
- return -ENOMEM;
-@@ -817,7 +603,7 @@
- c = JFFS2_SB_INFO(dir_i->i_sb);
-
- if (S_ISBLK(mode) || S_ISCHR(mode)) {
-- dev = (MAJOR(to_kdev_t(rdev)) << 8) | MINOR(to_kdev_t(rdev));
-+ dev = cpu_to_je16(old_encode_dev(rdev));
- devlen = sizeof(dev);
- }
-
-@@ -844,15 +630,15 @@
-
- f = JFFS2_INODE_INFO(inode);
-
-- ri->dsize = ri->csize = devlen;
-- ri->totlen = sizeof(*ri) + ri->csize;
-- ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4);
-+ ri->dsize = ri->csize = cpu_to_je32(devlen);
-+ ri->totlen = cpu_to_je32(sizeof(*ri) + devlen);
-+ ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
-
- ri->compr = JFFS2_COMPR_NONE;
-- ri->data_crc = crc32(0, &dev, devlen);
-- ri->node_crc = crc32(0, ri, sizeof(*ri)-8);
-+ ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen));
-+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-
-- fn = jffs2_write_dnode(inode, ri, (char *)&dev, devlen, phys_ofs, &writtenlen);
-+ fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, ALLOC_NORMAL);
-
- jffs2_free_raw_inode(ri);
-
-@@ -869,13 +655,6 @@
- f->metadata = fn;
- up(&f->sem);
-
-- /* Work out where to put the dirent node now. */
-- writtenlen = (writtenlen+3)&~3;
-- phys_ofs += writtenlen;
-- alloclen -= writtenlen;
--
-- if (alloclen < sizeof(*rd)+namelen) {
-- /* Not enough space left in this chunk. Get some more */
- jffs2_complete_reservation(c);
- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
- if (ret) {
-@@ -883,7 +662,6 @@
- jffs2_clear_inode(inode);
- return ret;
- }
-- }
-
- rd = jffs2_alloc_raw_dirent();
- if (!rd) {
-@@ -896,44 +674,45 @@
- dir_f = JFFS2_INODE_INFO(dir_i);
- down(&dir_f->sem);
-
-- rd->magic = JFFS2_MAGIC_BITMASK;
-- rd->nodetype = JFFS2_NODETYPE_DIRENT;
-- rd->totlen = sizeof(*rd) + namelen;
-- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
-+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
-+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
-+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
-
-- rd->pino = dir_i->i_ino;
-- rd->version = ++dir_f->highest_version;
-- rd->ino = inode->i_ino;
-- rd->mctime = CURRENT_TIME;
-+ rd->pino = cpu_to_je32(dir_i->i_ino);
-+ rd->version = cpu_to_je32(++dir_f->highest_version);
-+ rd->ino = cpu_to_je32(inode->i_ino);
-+ rd->mctime = cpu_to_je32(get_seconds());
- rd->nsize = namelen;
-
- /* XXX: This is ugly. */
- rd->type = (mode & S_IFMT) >> 12;
-
-- rd->node_crc = crc32(0, rd, sizeof(*rd)-8);
-- rd->name_crc = crc32(0, dentry->d_name.name, namelen);
--
-- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
-+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-+ rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
-
-- jffs2_complete_reservation(c);
-+ fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL);
-
- if (IS_ERR(fd)) {
- /* dirent failed to write. Delete the inode normally
- as if it were the final unlink() */
-+ jffs2_complete_reservation(c);
- jffs2_free_raw_dirent(rd);
- up(&dir_f->sem);
- jffs2_clear_inode(inode);
- return PTR_ERR(fd);
- }
-
-- dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
-+ dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
-
- jffs2_free_raw_dirent(rd);
-
- /* Link the fd into the inode's list, obsoleting an old
- one if necessary. */
- jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-+
- up(&dir_f->sem);
-+ jffs2_complete_reservation(c);
-
- d_instantiate(dentry, inode);
-
-@@ -944,7 +723,9 @@
- struct inode *new_dir_i, struct dentry *new_dentry)
- {
- int ret;
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
- struct jffs2_inode_info *victim_f = NULL;
-+ uint8_t type;
-
- /* The VFS will check for us and prevent trying to rename a
- * file over a directory and vice versa, but if it's a directory,
-@@ -973,7 +754,15 @@
- */
-
- /* Make a hard link */
-- ret = jffs2_do_link(old_dentry, new_dir_i, new_dentry, 1);
-+
-+ /* XXX: This is ugly */
-+ type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12;
-+ if (!type) type = DT_REG;
-+
-+ ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i),
-+ old_dentry->d_inode->i_ino, type,
-+ new_dentry->d_name.name, new_dentry->d_name.len);
-+
- if (ret)
- return ret;
-
-@@ -989,22 +778,36 @@
- }
- }
-
-+ /* If it was a directory we moved, and there was no victim,
-+ increase i_nlink on its new parent */
-+ if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f)
-+ new_dir_i->i_nlink++;
-+
- /* Unlink the original */
-- ret = jffs2_do_unlink(old_dir_i, old_dentry, 1);
-+ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
-+ old_dentry->d_name.name, old_dentry->d_name.len, NULL);
-+
-+ /* We don't touch inode->i_nlink */
-
- if (ret) {
- /* Oh shit. We really ought to make a single node which can do both atomically */
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
- down(&f->sem);
-+ old_dentry->d_inode->i_nlink++;
- if (f->inocache)
-- old_dentry->d_inode->i_nlink = f->inocache->nlink++;
-+ f->inocache->nlink++;
- up(&f->sem);
-
- printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
- /* Might as well let the VFS know */
- d_instantiate(new_dentry, old_dentry->d_inode);
- atomic_inc(&old_dentry->d_inode->i_count);
-- }
- return ret;
-+ }
-+
-+ if (S_ISDIR(old_dentry->d_inode->i_mode))
-+ old_dir_i->i_nlink--;
-+
-+ return 0;
- }
-
---- linux-2.4.21/fs/jffs2/erase.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/erase.c
-@@ -1,68 +1,63 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: erase.c,v 1.24 2001/12/06 16:38:38 dwmw2 Exp $
-+ * $Id: erase.c,v 1.72 2005/02/27 23:01:32 dwmw2 Exp $
- *
- */
-+
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/mtd/mtd.h>
--#include <linux/jffs2.h>
--#include <linux/interrupt.h>
-+#include <linux/compiler.h>
-+#include <linux/crc32.h>
-+#include <linux/sched.h>
-+#include <linux/pagemap.h>
- #include "nodelist.h"
--#include "crc32.h"
-
- struct erase_priv_struct {
- struct jffs2_eraseblock *jeb;
- struct jffs2_sb_info *c;
- };
-
-+#ifndef __ECOS
- static void jffs2_erase_callback(struct erase_info *);
-+#endif
-+static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
-+static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
- static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-+static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-
- void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
- {
-- struct erase_info *instr;
- int ret;
-+ uint32_t bad_offset;
-+#ifdef __ECOS
-+ ret = jffs2_flash_erase(c, jeb);
-+ if (!ret) {
-+ jffs2_erase_succeeded(c, jeb);
-+ return;
-+ }
-+ bad_offset = jeb->offset;
-+#else /* Linux */
-+ struct erase_info *instr;
-
-+ D1(printk(KERN_DEBUG "jffs2_erase_block(): erase block %#x (range %#x-%#x)\n", jeb->offset, jeb->offset, jeb->offset + c->sector_size));
- instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL);
- if (!instr) {
- printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
-- spin_lock_bh(&c->erase_completion_lock);
-+ spin_lock(&c->erase_completion_lock);
- list_del(&jeb->list);
- list_add(&jeb->list, &c->erase_pending_list);
- c->erasing_size -= c->sector_size;
-- spin_unlock_bh(&c->erase_completion_lock);
-+ c->dirty_size += c->sector_size;
-+ jeb->dirty_size = c->sector_size;
-+ spin_unlock(&c->erase_completion_lock);
- return;
- }
-
-@@ -73,23 +68,29 @@
- instr->len = c->sector_size;
- instr->callback = jffs2_erase_callback;
- instr->priv = (unsigned long)(&instr[1]);
-+ instr->fail_addr = 0xffffffff;
-
- ((struct erase_priv_struct *)instr->priv)->jeb = jeb;
- ((struct erase_priv_struct *)instr->priv)->c = c;
-
- ret = c->mtd->erase(c->mtd, instr);
-- if (!ret) {
-+ if (!ret)
- return;
-- }
-+
-+ bad_offset = instr->fail_addr;
-+ kfree(instr);
-+#endif /* __ECOS */
-+
- if (ret == -ENOMEM || ret == -EAGAIN) {
- /* Erase failed immediately. Refile it on the list */
- D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret));
-- spin_lock_bh(&c->erase_completion_lock);
-+ spin_lock(&c->erase_completion_lock);
- list_del(&jeb->list);
- list_add(&jeb->list, &c->erase_pending_list);
- c->erasing_size -= c->sector_size;
-- spin_unlock_bh(&c->erase_completion_lock);
-- kfree(instr);
-+ c->dirty_size += c->sector_size;
-+ jeb->dirty_size = c->sector_size;
-+ spin_unlock(&c->erase_completion_lock);
- return;
- }
-
-@@ -97,74 +98,119 @@
- printk(KERN_WARNING "Erase at 0x%08x failed immediately: -EROFS. Is the sector locked?\n", jeb->offset);
- else
- printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret);
-- spin_lock_bh(&c->erase_completion_lock);
-- list_del(&jeb->list);
-- list_add(&jeb->list, &c->bad_list);
-- c->nr_erasing_blocks--;
-- c->bad_size += c->sector_size;
-- c->erasing_size -= c->sector_size;
-- spin_unlock_bh(&c->erase_completion_lock);
-- wake_up(&c->erase_wait);
-- kfree(instr);
-+
-+ jffs2_erase_failed(c, jeb, bad_offset);
- }
-
--void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
-+void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
- {
- struct jffs2_eraseblock *jeb;
-
-- spin_lock_bh(&c->erase_completion_lock);
-- while (!list_empty(&c->erase_pending_list)) {
-+ down(&c->erase_free_sem);
-
-- jeb = list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list);
-+ spin_lock(&c->erase_completion_lock);
-
-- D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset));
-+ while (!list_empty(&c->erase_complete_list) ||
-+ !list_empty(&c->erase_pending_list)) {
-+
-+ if (!list_empty(&c->erase_complete_list)) {
-+ jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list);
-+ list_del(&jeb->list);
-+ spin_unlock(&c->erase_completion_lock);
-+ jffs2_mark_erased_block(c, jeb);
-+
-+ if (!--count) {
-+ D1(printk(KERN_DEBUG "Count reached. jffs2_erase_pending_blocks leaving\n"));
-+ goto done;
-+ }
-
-+ } else if (!list_empty(&c->erase_pending_list)) {
-+ jeb = list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list);
-+ D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset));
- list_del(&jeb->list);
- c->erasing_size += c->sector_size;
-+ c->wasted_size -= jeb->wasted_size;
- c->free_size -= jeb->free_size;
- c->used_size -= jeb->used_size;
- c->dirty_size -= jeb->dirty_size;
-- jeb->used_size = jeb->dirty_size = jeb->free_size = 0;
-+ jeb->wasted_size = jeb->used_size = jeb->dirty_size = jeb->free_size = 0;
- jffs2_free_all_node_refs(c, jeb);
- list_add(&jeb->list, &c->erasing_list);
-- spin_unlock_bh(&c->erase_completion_lock);
-+ spin_unlock(&c->erase_completion_lock);
-
- jffs2_erase_block(c, jeb);
-+
-+ } else {
-+ BUG();
-+ }
-+
- /* Be nice */
-- if (current->need_resched)
-- schedule();
-- spin_lock_bh(&c->erase_completion_lock);
-+ cond_resched();
-+ spin_lock(&c->erase_completion_lock);
- }
-- spin_unlock_bh(&c->erase_completion_lock);
-+
-+ spin_unlock(&c->erase_completion_lock);
-+ done:
- D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n"));
-+
-+ up(&c->erase_free_sem);
- }
-
-+static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
-+{
-+ D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset));
-+ spin_lock(&c->erase_completion_lock);
-+ list_del(&jeb->list);
-+ list_add_tail(&jeb->list, &c->erase_complete_list);
-+ spin_unlock(&c->erase_completion_lock);
-+ /* Ensure that kupdated calls us again to mark them clean */
-+ jffs2_erase_pending_trigger(c);
-+}
-
-+static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset)
-+{
-+ /* For NAND, if the failure did not occur at the device level for a
-+ specific physical page, don't bother updating the bad block table. */
-+ if (jffs2_cleanmarker_oob(c) && (bad_offset != 0xffffffff)) {
-+ /* We had a device-level failure to erase. Let's see if we've
-+ failed too many times. */
-+ if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) {
-+ /* We'd like to give this block another try. */
-+ spin_lock(&c->erase_completion_lock);
-+ list_del(&jeb->list);
-+ list_add(&jeb->list, &c->erase_pending_list);
-+ c->erasing_size -= c->sector_size;
-+ c->dirty_size += c->sector_size;
-+ jeb->dirty_size = c->sector_size;
-+ spin_unlock(&c->erase_completion_lock);
-+ return;
-+ }
-+ }
-+
-+ spin_lock(&c->erase_completion_lock);
-+ c->erasing_size -= c->sector_size;
-+ c->bad_size += c->sector_size;
-+ list_del(&jeb->list);
-+ list_add(&jeb->list, &c->bad_list);
-+ c->nr_erasing_blocks--;
-+ spin_unlock(&c->erase_completion_lock);
-+ wake_up(&c->erase_wait);
-+}
-+
-+#ifndef __ECOS
- static void jffs2_erase_callback(struct erase_info *instr)
- {
- struct erase_priv_struct *priv = (void *)instr->priv;
-
- if(instr->state != MTD_ERASE_DONE) {
- printk(KERN_WARNING "Erase at 0x%08x finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n", instr->addr, instr->state);
-- spin_lock(&priv->c->erase_completion_lock);
-- priv->c->erasing_size -= priv->c->sector_size;
-- priv->c->bad_size += priv->c->sector_size;
-- list_del(&priv->jeb->list);
-- list_add(&priv->jeb->list, &priv->c->bad_list);
-- priv->c->nr_erasing_blocks--;
-- spin_unlock(&priv->c->erase_completion_lock);
-- wake_up(&priv->c->erase_wait);
-+ jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr);
- } else {
-- D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", instr->addr));
-- spin_lock(&priv->c->erase_completion_lock);
-- list_del(&priv->jeb->list);
-- list_add_tail(&priv->jeb->list, &priv->c->erase_complete_list);
-- spin_unlock(&priv->c->erase_completion_lock);
-+ jffs2_erase_succeeded(priv->c, priv->jeb);
- }
-- /* Make sure someone picks up the block off the erase_complete list */
-- OFNI_BS_2SFFJ(priv->c)->s_dirt = 1;
- kfree(instr);
- }
-+#endif /* !__ECOS */
-
- /* Hmmm. Maybe we should accept the extra space it takes and make
- this a standard doubly-linked list? */
-@@ -187,7 +233,7 @@
- continue;
- }
-
-- if (((*prev)->flash_offset & ~(c->sector_size -1)) == jeb->offset) {
-+ if (SECTOR_ADDR((*prev)->flash_offset) == jeb->offset) {
- /* It's in the block we're erasing */
- struct jffs2_raw_node_ref *this;
-
-@@ -221,7 +267,7 @@
- this = ic->nodes;
-
- while(this) {
-- printk( "0x%08x(%d)->", this->flash_offset & ~3, this->flash_offset &3);
-+ printk( "0x%08x(%d)->", ref_offset(this), ref_flags(this));
- if (++i == 5) {
- printk("\n" KERN_DEBUG);
- i=0;
-@@ -231,11 +277,8 @@
- printk("\n");
- });
-
-- if (ic->nodes == (void *)ic) {
-- D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino));
-+ if (ic->nodes == (void *)ic)
- jffs2_del_ino_cache(c, ic);
-- jffs2_free_inode_cache(ic);
-- }
- }
-
- static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
-@@ -256,118 +299,148 @@
- jeb->last_node = NULL;
- }
-
--void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
--{
-- OFNI_BS_2SFFJ(c)->s_dirt = 1;
--}
--
--void jffs2_mark_erased_blocks(struct jffs2_sb_info *c)
-+static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
- {
-- static struct jffs2_unknown_node marker = {JFFS2_MAGIC_BITMASK, JFFS2_NODETYPE_CLEANMARKER, sizeof(struct jffs2_unknown_node)};
-- struct jffs2_eraseblock *jeb;
-- struct jffs2_raw_node_ref *marker_ref;
-+ struct jffs2_raw_node_ref *marker_ref = NULL;
- unsigned char *ebuf;
-- ssize_t retlen;
-+ size_t retlen;
- int ret;
-+ uint32_t bad_offset;
-
-- marker.hdr_crc = crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4);
--
-- spin_lock_bh(&c->erase_completion_lock);
-- while (!list_empty(&c->erase_complete_list)) {
-- jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list);
-- list_del(&jeb->list);
-- spin_unlock_bh(&c->erase_completion_lock);
--
-+ if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) {
- marker_ref = jffs2_alloc_raw_node_ref();
- if (!marker_ref) {
- printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n");
-- /* Come back later */
-+ /* Stick it back on the list from whence it came and come back later */
- jffs2_erase_pending_trigger(c);
-+ spin_lock(&c->erase_completion_lock);
-+ list_add(&jeb->list, &c->erase_complete_list);
-+ spin_unlock(&c->erase_completion_lock);
- return;
- }
--
-+ }
- ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!ebuf) {
- printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Assuming it worked\n", jeb->offset);
- } else {
-- __u32 ofs = jeb->offset;
-+ uint32_t ofs = jeb->offset;
-
- D1(printk(KERN_DEBUG "Verifying erase at 0x%08x\n", jeb->offset));
- while(ofs < jeb->offset + c->sector_size) {
-- __u32 readlen = min((__u32)PAGE_SIZE, jeb->offset + c->sector_size - ofs);
-+ uint32_t readlen = min((uint32_t)PAGE_SIZE, jeb->offset + c->sector_size - ofs);
- int i;
-
-- ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf);
-- if (ret < 0) {
-+ bad_offset = ofs;
-+
-+ ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf);
-+ if (ret) {
- printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
- goto bad;
- }
- if (retlen != readlen) {
-- printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %d\n", ofs, readlen, retlen);
-+ printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen);
- goto bad;
- }
- for (i=0; i<readlen; i += sizeof(unsigned long)) {
- /* It's OK. We know it's properly aligned */
- unsigned long datum = *(unsigned long *)(&ebuf[i]);
- if (datum + 1) {
-- printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, ofs + i);
-+ bad_offset += i;
-+ printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset);
- bad:
-+ if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0))
- jffs2_free_raw_node_ref(marker_ref);
- kfree(ebuf);
- bad2:
-- spin_lock_bh(&c->erase_completion_lock);
-- c->erasing_size -= c->sector_size;
-- c->bad_size += c->sector_size;
--
-- list_add_tail(&jeb->list, &c->bad_list);
-- c->nr_erasing_blocks--;
-- spin_unlock_bh(&c->erase_completion_lock);
-- wake_up(&c->erase_wait);
-+ spin_lock(&c->erase_completion_lock);
-+ /* Stick it on a list (any list) so
-+ erase_failed can take it right off
-+ again. Silly, but shouldn't happen
-+ often. */
-+ list_add(&jeb->list, &c->erasing_list);
-+ spin_unlock(&c->erase_completion_lock);
-+ jffs2_erase_failed(c, jeb, bad_offset);
- return;
- }
- }
- ofs += readlen;
-+ cond_resched();
- }
- kfree(ebuf);
- }
-
-+ bad_offset = jeb->offset;
-+
- /* Write the erase complete marker */
- D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset));
-- ret = c->mtd->write(c->mtd, jeb->offset, sizeof(marker), &retlen, (char *)&marker);
-+ if (jffs2_cleanmarker_oob(c)) {
-+
-+ if (jffs2_write_nand_cleanmarker(c, jeb))
-+ goto bad2;
-+
-+ jeb->first_node = jeb->last_node = NULL;
-+
-+ jeb->free_size = c->sector_size;
-+ jeb->used_size = 0;
-+ jeb->dirty_size = 0;
-+ jeb->wasted_size = 0;
-+ } else if (c->cleanmarker_size == 0) {
-+ jeb->first_node = jeb->last_node = NULL;
-+
-+ jeb->free_size = c->sector_size;
-+ jeb->used_size = 0;
-+ jeb->dirty_size = 0;
-+ jeb->wasted_size = 0;
-+ } else {
-+ struct kvec vecs[1];
-+ struct jffs2_unknown_node marker = {
-+ .magic = cpu_to_je16(JFFS2_MAGIC_BITMASK),
-+ .nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
-+ .totlen = cpu_to_je32(c->cleanmarker_size)
-+ };
-+
-+ marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4));
-+
-+ vecs[0].iov_base = (unsigned char *) &marker;
-+ vecs[0].iov_len = sizeof(marker);
-+ ret = jffs2_flash_direct_writev(c, vecs, 1, jeb->offset, &retlen);
-+
- if (ret) {
- printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n",
- jeb->offset, ret);
- goto bad2;
- }
- if (retlen != sizeof(marker)) {
-- printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %d\n",
-+ printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %zd, got %zd\n",
- jeb->offset, sizeof(marker), retlen);
- goto bad2;
- }
-
- marker_ref->next_in_ino = NULL;
- marker_ref->next_phys = NULL;
-- marker_ref->flash_offset = jeb->offset;
-- marker_ref->totlen = PAD(sizeof(marker));
-+ marker_ref->flash_offset = jeb->offset | REF_NORMAL;
-+ marker_ref->__totlen = c->cleanmarker_size;
-
- jeb->first_node = jeb->last_node = marker_ref;
-
-- jeb->free_size = c->sector_size - marker_ref->totlen;
-- jeb->used_size = marker_ref->totlen;
-+ jeb->free_size = c->sector_size - c->cleanmarker_size;
-+ jeb->used_size = c->cleanmarker_size;
- jeb->dirty_size = 0;
-+ jeb->wasted_size = 0;
-+ }
-
-- spin_lock_bh(&c->erase_completion_lock);
-+ spin_lock(&c->erase_completion_lock);
- c->erasing_size -= c->sector_size;
- c->free_size += jeb->free_size;
- c->used_size += jeb->used_size;
-
- ACCT_SANITY_CHECK(c,jeb);
-- ACCT_PARANOIA_CHECK(jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-
- list_add_tail(&jeb->list, &c->free_list);
- c->nr_erasing_blocks--;
- c->nr_free_blocks++;
-+ spin_unlock(&c->erase_completion_lock);
- wake_up(&c->erase_wait);
-- }
-- spin_unlock_bh(&c->erase_completion_lock);
- }
-+
---- linux-2.4.21/fs/jffs2/file.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/file.c
-@@ -1,319 +1,106 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: file.c,v 1.58.2.6 2002/11/12 13:17:01 dwmw2 Exp $
-+ * $Id: file.c,v 1.99 2004/11/16 20:36:11 dwmw2 Exp $
- *
- */
-
-+#include <linux/version.h>
- #include <linux/kernel.h>
--#include <linux/mtd/compatmac.h> /* for min() */
- #include <linux/slab.h>
- #include <linux/fs.h>
-+#include <linux/time.h>
- #include <linux/pagemap.h>
-+#include <linux/highmem.h>
-+#include <linux/crc32.h>
- #include <linux/jffs2.h>
- #include "nodelist.h"
--#include "crc32.h"
-
- extern int generic_file_open(struct inode *, struct file *) __attribute__((weak));
- extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) __attribute__((weak));
-
-
--int jffs2_null_fsync(struct file *filp, struct dentry *dentry, int datasync)
-+int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync)
- {
-- /* Move along. Nothing to see here */
-+ struct inode *inode = dentry->d_inode;
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-+
-+ /* Trigger GC to flush any pending writes for this inode */
-+ jffs2_flush_wbuf_gc(c, inode->i_ino);
-+
- return 0;
- }
-
- struct file_operations jffs2_file_operations =
- {
-- llseek: generic_file_llseek,
-- open: generic_file_open,
-- read: generic_file_read,
-- write: generic_file_write,
-- ioctl: jffs2_ioctl,
-- mmap: generic_file_mmap,
-- fsync: jffs2_null_fsync
-+ .llseek = generic_file_llseek,
-+ .open = generic_file_open,
-+ .read = generic_file_read,
-+ .write = generic_file_write,
-+ .ioctl = jffs2_ioctl,
-+ .mmap = generic_file_readonly_mmap,
-+ .fsync = jffs2_fsync,
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,29)
-+ .sendfile = generic_file_sendfile
-+#endif
- };
-
- /* jffs2_file_inode_operations */
-
- struct inode_operations jffs2_file_inode_operations =
- {
-- setattr: jffs2_setattr
-+ .setattr = jffs2_setattr
- };
-
- struct address_space_operations jffs2_file_address_operations =
- {
-- readpage: jffs2_readpage,
-- prepare_write: jffs2_prepare_write,
-- commit_write: jffs2_commit_write
-+ .readpage = jffs2_readpage,
-+ .prepare_write =jffs2_prepare_write,
-+ .commit_write = jffs2_commit_write
- };
-
--int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
--{
-- struct jffs2_full_dnode *old_metadata, *new_metadata;
-- struct inode *inode = dentry->d_inode;
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-- struct jffs2_raw_inode *ri;
-- unsigned short dev;
-- unsigned char *mdata = NULL;
-- int mdatalen = 0;
-- unsigned int ivalid;
-- __u32 phys_ofs, alloclen;
-- int ret;
-- D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino));
-- ret = inode_change_ok(inode, iattr);
-- if (ret)
-- return ret;
--
-- /* Special cases - we don't want more than one data node
-- for these types on the medium at any time. So setattr
-- must read the original data associated with the node
-- (i.e. the device numbers or the target name) and write
-- it out again with the appropriate data attached */
-- if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
-- /* For these, we don't actually need to read the old node */
-- dev = (MAJOR(to_kdev_t(dentry->d_inode->i_rdev)) << 8) |
-- MINOR(to_kdev_t(dentry->d_inode->i_rdev));
-- mdata = (char *)&dev;
-- mdatalen = sizeof(dev);
-- D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen));
-- } else if (S_ISLNK(inode->i_mode)) {
-- mdatalen = f->metadata->size;
-- mdata = kmalloc(f->metadata->size, GFP_USER);
-- if (!mdata)
-- return -ENOMEM;
-- ret = jffs2_read_dnode(c, f->metadata, mdata, 0, mdatalen);
-- if (ret) {
-- kfree(mdata);
-- return ret;
-- }
-- D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen));
-- }
--
-- ri = jffs2_alloc_raw_inode();
-- if (!ri) {
-- if (S_ISLNK(inode->i_mode))
-- kfree(mdata);
-- return -ENOMEM;
-- }
--
-- ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL);
-- if (ret) {
-- jffs2_free_raw_inode(ri);
-- if (S_ISLNK(inode->i_mode))
-- kfree(mdata);
-- return ret;
-- }
-- down(&f->sem);
-- ivalid = iattr->ia_valid;
--
-- ri->magic = JFFS2_MAGIC_BITMASK;
-- ri->nodetype = JFFS2_NODETYPE_INODE;
-- ri->totlen = sizeof(*ri) + mdatalen;
-- ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4);
--
-- ri->ino = inode->i_ino;
-- ri->version = ++f->highest_version;
--
-- ri->mode = (ivalid & ATTR_MODE)?iattr->ia_mode:inode->i_mode;
-- ri->uid = (ivalid & ATTR_UID)?iattr->ia_uid:inode->i_uid;
-- ri->gid = (ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid;
--
-- if (ivalid & ATTR_MODE && ri->mode & S_ISGID &&
-- !in_group_p(ri->gid) && !capable(CAP_FSETID))
-- ri->mode &= ~S_ISGID;
--
-- ri->isize = (ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size;
-- ri->atime = (ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime;
-- ri->mtime = (ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime;
-- ri->ctime = (ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime;
--
-- ri->offset = 0;
-- ri->csize = ri->dsize = mdatalen;
-- ri->compr = JFFS2_COMPR_NONE;
-- if (inode->i_size < ri->isize) {
-- /* It's an extension. Make it a hole node */
-- ri->compr = JFFS2_COMPR_ZERO;
-- ri->dsize = ri->isize - inode->i_size;
-- ri->offset = inode->i_size;
-- }
-- ri->node_crc = crc32(0, ri, sizeof(*ri)-8);
-- if (mdatalen)
-- ri->data_crc = crc32(0, mdata, mdatalen);
-- else
-- ri->data_crc = 0;
--
-- new_metadata = jffs2_write_dnode(inode, ri, mdata, mdatalen, phys_ofs, NULL);
-- if (S_ISLNK(inode->i_mode))
-- kfree(mdata);
--
-- jffs2_complete_reservation(c);
--
-- if (IS_ERR(new_metadata)) {
-- jffs2_free_raw_inode(ri);
-- up(&f->sem);
-- return PTR_ERR(new_metadata);
-- }
-- /* It worked. Update the inode */
-- inode->i_atime = ri->atime;
-- inode->i_ctime = ri->ctime;
-- inode->i_mtime = ri->mtime;
-- inode->i_mode = ri->mode;
-- inode->i_uid = ri->uid;
-- inode->i_gid = ri->gid;
--
--
-- old_metadata = f->metadata;
--
-- if (inode->i_size > ri->isize) {
-- vmtruncate(inode, ri->isize);
-- jffs2_truncate_fraglist (c, &f->fraglist, ri->isize);
-- }
--
-- if (inode->i_size < ri->isize) {
-- jffs2_add_full_dnode_to_inode(c, f, new_metadata);
-- inode->i_size = ri->isize;
-- f->metadata = NULL;
-- } else {
-- f->metadata = new_metadata;
-- }
-- if (old_metadata) {
-- jffs2_mark_node_obsolete(c, old_metadata->raw);
-- jffs2_free_full_dnode(old_metadata);
-- }
-- jffs2_free_raw_inode(ri);
-- up(&f->sem);
-- return 0;
--}
--
- int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg)
- {
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-- struct jffs2_node_frag *frag = f->fraglist;
-- __u32 offset = pg->index << PAGE_CACHE_SHIFT;
-- __u32 end = offset + PAGE_CACHE_SIZE;
- unsigned char *pg_buf;
- int ret;
-
-- D1(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%x\n", inode->i_ino, offset));
-+ D2(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT));
-
- if (!PageLocked(pg))
- PAGE_BUG(pg);
-
-- while(frag && frag->ofs + frag->size <= offset) {
-- // D1(printk(KERN_DEBUG "skipping frag %d-%d; before the region we care about\n", frag->ofs, frag->ofs + frag->size));
-- frag = frag->next;
-- }
--
- pg_buf = kmap(pg);
-+ /* FIXME: Can kmap fail? */
-
-- /* XXX FIXME: Where a single physical node actually shows up in two
-- frags, we read it twice. Don't do that. */
-- /* Now we're pointing at the first frag which overlaps our page */
-- while(offset < end) {
-- D2(printk(KERN_DEBUG "jffs2_readpage: offset %d, end %d\n", offset, end));
-- if (!frag || frag->ofs > offset) {
-- __u32 holesize = end - offset;
-- if (frag) {
-- D1(printk(KERN_NOTICE "Eep. Hole in ino %ld fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", inode->i_ino, frag->ofs, offset));
-- holesize = min(holesize, frag->ofs - offset);
-- D1(jffs2_print_frag_list(f));
-- }
-- D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize));
-- memset(pg_buf, 0, holesize);
-- pg_buf += holesize;
-- offset += holesize;
-- continue;
-- } else if (frag->ofs < offset && (offset & (PAGE_CACHE_SIZE-1)) != 0) {
-- D1(printk(KERN_NOTICE "Eep. Overlap in ino #%ld fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n",
-- inode->i_ino, frag->ofs, offset));
-- D1(jffs2_print_frag_list(f));
-- memset(pg_buf, 0, end - offset);
-- ClearPageUptodate(pg);
-- SetPageError(pg);
-- kunmap(pg);
-- return -EIO;
-- } else if (!frag->node) {
-- __u32 holeend = min(end, frag->ofs + frag->size);
-- D1(printk(KERN_DEBUG "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset, holeend, frag->ofs, frag->ofs + frag->size));
-- memset(pg_buf, 0, holeend - offset);
-- pg_buf += holeend - offset;
-- offset = holeend;
-- frag = frag->next;
-- continue;
-- } else {
-- __u32 readlen;
-- __u32 fragofs; /* offset within the frag to start reading */
-+ ret = jffs2_read_inode_range(c, f, pg_buf, pg->index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE);
-
-- fragofs = offset - frag->ofs;
-- readlen = min(frag->size - fragofs, end - offset);
-- D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%x\n", frag->ofs+fragofs,
-- fragofs+frag->ofs+readlen, frag->node->raw->flash_offset & ~3));
-- ret = jffs2_read_dnode(c, frag->node, pg_buf, fragofs + frag->ofs - frag->node->ofs, readlen);
-- D2(printk(KERN_DEBUG "node read done\n"));
- if (ret) {
-- D1(printk(KERN_DEBUG"jffs2_readpage error %d\n",ret));
-- memset(pg_buf, 0, readlen);
- ClearPageUptodate(pg);
- SetPageError(pg);
-- kunmap(pg);
-- return ret;
-- }
--
-- pg_buf += readlen;
-- offset += readlen;
-- frag = frag->next;
-- D2(printk(KERN_DEBUG "node read was OK. Looping\n"));
-- }
-- }
-- D2(printk(KERN_DEBUG "readpage finishing\n"));
-+ } else {
- SetPageUptodate(pg);
- ClearPageError(pg);
-+ }
-
- flush_dcache_page(pg);
--
- kunmap(pg);
-- D1(printk(KERN_DEBUG "readpage finished\n"));
-+
-+ D2(printk(KERN_DEBUG "readpage finished\n"));
- return 0;
- }
-
- int jffs2_do_readpage_unlock(struct inode *inode, struct page *pg)
- {
- int ret = jffs2_do_readpage_nolock(inode, pg);
-- UnlockPage(pg);
-+ unlock_page(pg);
- return ret;
- }
-
-@@ -333,17 +120,17 @@
- {
- struct inode *inode = pg->mapping->host;
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-- __u32 pageofs = pg->index << PAGE_CACHE_SHIFT;
-+ uint32_t pageofs = pg->index << PAGE_CACHE_SHIFT;
- int ret = 0;
-
-- D1(printk(KERN_DEBUG "jffs2_prepare_write() nrpages %ld\n", inode->i_mapping->nrpages));
-+ D1(printk(KERN_DEBUG "jffs2_prepare_write()\n"));
-
- if (pageofs > inode->i_size) {
- /* Make new hole frag from old EOF to new page */
- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
- struct jffs2_raw_inode ri;
- struct jffs2_full_dnode *fn;
-- __u32 phys_ofs, alloc_len;
-+ uint32_t phys_ofs, alloc_len;
-
- D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
- (unsigned int)inode->i_size, pageofs));
-@@ -355,29 +142,30 @@
- down(&f->sem);
- memset(&ri, 0, sizeof(ri));
-
-- ri.magic = JFFS2_MAGIC_BITMASK;
-- ri.nodetype = JFFS2_NODETYPE_INODE;
-- ri.totlen = sizeof(ri);
-- ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4);
-+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-+ ri.totlen = cpu_to_je32(sizeof(ri));
-+ ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
-
-- ri.ino = f->inocache->ino;
-- ri.version = ++f->highest_version;
-- ri.mode = inode->i_mode;
-- ri.uid = inode->i_uid;
-- ri.gid = inode->i_gid;
-- ri.isize = max((__u32)inode->i_size, pageofs);
-- ri.atime = ri.ctime = ri.mtime = CURRENT_TIME;
-- ri.offset = inode->i_size;
-- ri.dsize = pageofs - inode->i_size;
-- ri.csize = 0;
-+ ri.ino = cpu_to_je32(f->inocache->ino);
-+ ri.version = cpu_to_je32(++f->highest_version);
-+ ri.mode = cpu_to_jemode(inode->i_mode);
-+ ri.uid = cpu_to_je16(inode->i_uid);
-+ ri.gid = cpu_to_je16(inode->i_gid);
-+ ri.isize = cpu_to_je32(max((uint32_t)inode->i_size, pageofs));
-+ ri.atime = ri.ctime = ri.mtime = cpu_to_je32(get_seconds());
-+ ri.offset = cpu_to_je32(inode->i_size);
-+ ri.dsize = cpu_to_je32(pageofs - inode->i_size);
-+ ri.csize = cpu_to_je32(0);
- ri.compr = JFFS2_COMPR_ZERO;
-- ri.node_crc = crc32(0, &ri, sizeof(ri)-8);
-- ri.data_crc = 0;
-+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
-+ ri.data_crc = cpu_to_je32(0);
-+
-+ fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
-
-- fn = jffs2_write_dnode(inode, &ri, NULL, 0, phys_ofs, NULL);
-- jffs2_complete_reservation(c);
- if (IS_ERR(fn)) {
- ret = PTR_ERR(fn);
-+ jffs2_complete_reservation(c);
- up(&f->sem);
- return ret;
- }
-@@ -391,16 +179,17 @@
- D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in prepare_write, returned %d\n", ret));
- jffs2_mark_node_obsolete(c, fn->raw);
- jffs2_free_full_dnode(fn);
-+ jffs2_complete_reservation(c);
- up(&f->sem);
- return ret;
- }
-+ jffs2_complete_reservation(c);
- inode->i_size = pageofs;
- up(&f->sem);
- }
-
--
- /* Read in the page if it wasn't already present, unless it's a whole page */
-- if (!Page_Uptodate(pg) && (start || end < PAGE_CACHE_SIZE)) {
-+ if (!PageUptodate(pg) && (start || end < PAGE_CACHE_SIZE)) {
- down(&f->sem);
- ret = jffs2_do_readpage_nolock(inode, pg);
- up(&f->sem);
-@@ -417,14 +206,13 @@
- struct inode *inode = pg->mapping->host;
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-- __u32 newsize = max_t(__u32, filp->f_dentry->d_inode->i_size, (pg->index << PAGE_CACHE_SHIFT) + end);
-- __u32 file_ofs = (pg->index << PAGE_CACHE_SHIFT);
-- __u32 writelen = min((__u32)PAGE_CACHE_SIZE, newsize - file_ofs);
- struct jffs2_raw_inode *ri;
-+ unsigned aligned_start = start & ~3;
- int ret = 0;
-- ssize_t writtenlen = 0;
-+ uint32_t writtenlen = 0;
-
-- D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags));
-+ D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n",
-+ inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags));
-
- if (!start && end == PAGE_CACHE_SIZE) {
- /* We need to avoid deadlock with page_cache_read() in
-@@ -435,109 +223,53 @@
- }
-
- ri = jffs2_alloc_raw_inode();
-- if (!ri)
-- return -ENOMEM;
--
-- while(writelen) {
-- struct jffs2_full_dnode *fn;
-- unsigned char *comprbuf = NULL;
-- unsigned char comprtype = JFFS2_COMPR_NONE;
-- __u32 phys_ofs, alloclen;
-- __u32 datalen, cdatalen;
-
-- D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, file_ofs));
--
-- ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL);
-- if (ret) {
-- SetPageError(pg);
-- D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret));
-- break;
-- }
-- down(&f->sem);
-- datalen = writelen;
-- cdatalen = min(alloclen - sizeof(*ri), writelen);
--
-- comprbuf = kmalloc(cdatalen, GFP_KERNEL);
-- if (comprbuf) {
-- comprtype = jffs2_compress(page_address(pg)+ (file_ofs & (PAGE_CACHE_SIZE-1)), comprbuf, &datalen, &cdatalen);
-- }
-- if (comprtype == JFFS2_COMPR_NONE) {
-- /* Either compression failed, or the allocation of comprbuf failed */
-- if (comprbuf)
-- kfree(comprbuf);
-- comprbuf = page_address(pg) + (file_ofs & (PAGE_CACHE_SIZE -1));
-- datalen = cdatalen;
-+ if (!ri) {
-+ D1(printk(KERN_DEBUG "jffs2_commit_write(): Allocation of raw inode failed\n"));
-+ return -ENOMEM;
- }
-- /* Now comprbuf points to the data to be written, be it compressed or not.
-- comprtype holds the compression type, and comprtype == JFFS2_COMPR_NONE means
-- that the comprbuf doesn't need to be kfree()d.
-- */
-
-- ri->magic = JFFS2_MAGIC_BITMASK;
-- ri->nodetype = JFFS2_NODETYPE_INODE;
-- ri->totlen = sizeof(*ri) + cdatalen;
-- ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4);
--
-- ri->ino = inode->i_ino;
-- ri->version = ++f->highest_version;
-- ri->mode = inode->i_mode;
-- ri->uid = inode->i_uid;
-- ri->gid = inode->i_gid;
-- ri->isize = max((__u32)inode->i_size, file_ofs + datalen);
-- ri->atime = ri->ctime = ri->mtime = CURRENT_TIME;
-- ri->offset = file_ofs;
-- ri->csize = cdatalen;
-- ri->dsize = datalen;
-- ri->compr = comprtype;
-- ri->node_crc = crc32(0, ri, sizeof(*ri)-8);
-- ri->data_crc = crc32(0, comprbuf, cdatalen);
-+ /* Set the fields that the generic jffs2_write_inode_range() code can't find */
-+ ri->ino = cpu_to_je32(inode->i_ino);
-+ ri->mode = cpu_to_jemode(inode->i_mode);
-+ ri->uid = cpu_to_je16(inode->i_uid);
-+ ri->gid = cpu_to_je16(inode->i_gid);
-+ ri->isize = cpu_to_je32((uint32_t)inode->i_size);
-+ ri->atime = ri->ctime = ri->mtime = cpu_to_je32(get_seconds());
-
-- fn = jffs2_write_dnode(inode, ri, comprbuf, cdatalen, phys_ofs, NULL);
-+ /* In 2.4, it was already kmapped by generic_file_write(). Doesn't
-+ hurt to do it again. The alternative is ifdefs, which are ugly. */
-+ kmap(pg);
-
-- jffs2_complete_reservation(c);
-+ ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + aligned_start,
-+ (pg->index << PAGE_CACHE_SHIFT) + aligned_start,
-+ end - aligned_start, &writtenlen);
-
-- if (comprtype != JFFS2_COMPR_NONE)
-- kfree(comprbuf);
-+ kunmap(pg);
-
-- if (IS_ERR(fn)) {
-- ret = PTR_ERR(fn);
-- up(&f->sem);
-- SetPageError(pg);
-- break;
-- }
-- ret = jffs2_add_full_dnode_to_inode(c, f, fn);
-- if (f->metadata) {
-- jffs2_mark_node_obsolete(c, f->metadata->raw);
-- jffs2_free_full_dnode(f->metadata);
-- f->metadata = NULL;
-- }
-- up(&f->sem);
- if (ret) {
-- /* Eep */
-- D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in commit_write, returned %d\n", ret));
-- jffs2_mark_node_obsolete(c, fn->raw);
-- jffs2_free_full_dnode(fn);
-+ /* There was an error writing. */
- SetPageError(pg);
-- break;
- }
-- inode->i_size = ri->isize;
-+
-+ /* Adjust writtenlen for the padding we did, so we don't confuse our caller */
-+ if (writtenlen < (start&3))
-+ writtenlen = 0;
-+ else
-+ writtenlen -= (start&3);
-+
-+ if (writtenlen) {
-+ if (inode->i_size < (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen) {
-+ inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen;
- inode->i_blocks = (inode->i_size + 511) >> 9;
-- inode->i_ctime = inode->i_mtime = ri->ctime;
-- if (!datalen) {
-- printk(KERN_WARNING "Eep. We didn't actually write any bloody data\n");
-- ret = -EIO;
-- SetPageError(pg);
-- break;
-+
-+ inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime));
- }
-- D1(printk(KERN_DEBUG "increasing writtenlen by %d\n", datalen));
-- writtenlen += datalen;
-- file_ofs += datalen;
-- writelen -= datalen;
- }
-
- jffs2_free_raw_inode(ri);
-
-- if (writtenlen < end) {
-+ if (start+writtenlen < end) {
- /* generic_file_write has written more to the page cache than we've
- actually written to the medium. Mark the page !Uptodate so that
- it gets reread */
-@@ -545,13 +277,7 @@
- SetPageError(pg);
- ClearPageUptodate(pg);
- }
-- if (writtenlen <= start) {
-- /* We didn't even get to the start of the affected part */
-- ret = ret?ret:-ENOSPC;
-- D1(printk(KERN_DEBUG "jffs2_commit_write(): Only %x bytes written to page. start (%x) not reached, returning %d\n", writtenlen, start, ret));
-- }
-- writtenlen = min(end-start, writtenlen-start);
-
-- D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d. nrpages is %ld\n",writtenlen?writtenlen:ret, inode->i_mapping->nrpages));
-+ D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d\n",writtenlen?writtenlen:ret));
- return writtenlen?writtenlen:ret;
- }
---- /dev/null
-+++ linux-2.4.21/fs/jffs2/fs.c
-@@ -0,0 +1,693 @@
-+/*
-+ * JFFS2 -- Journalling Flash File System, Version 2.
-+ *
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
-+ *
-+ * Created by David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * For licensing information, see the file 'LICENCE' in this directory.
-+ *
-+ * $Id: fs.c,v 1.53 2005/02/09 09:23:53 pavlov Exp $
-+ *
-+ */
-+
-+#include <linux/version.h>
-+#include <linux/config.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/fs.h>
-+#include <linux/list.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/pagemap.h>
-+#include <linux/slab.h>
-+#include <linux/vmalloc.h>
-+#include <linux/vfs.h>
-+#include <linux/crc32.h>
-+#include "nodelist.h"
-+
-+
-+static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
-+{
-+ struct jffs2_full_dnode *old_metadata, *new_metadata;
-+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-+ struct jffs2_raw_inode *ri;
-+ unsigned short dev;
-+ unsigned char *mdata = NULL;
-+ int mdatalen = 0;
-+ unsigned int ivalid;
-+ uint32_t phys_ofs, alloclen;
-+ int ret;
-+ D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino));
-+ ret = inode_change_ok(inode, iattr);
-+ if (ret)
-+ return ret;
-+
-+ /* Special cases - we don't want more than one data node
-+ for these types on the medium at any time. So setattr
-+ must read the original data associated with the node
-+ (i.e. the device numbers or the target name) and write
-+ it out again with the appropriate data attached */
-+ if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
-+ /* For these, we don't actually need to read the old node */
-+ dev = old_encode_dev(inode->i_rdev);
-+ mdata = (char *)&dev;
-+ mdatalen = sizeof(dev);
-+ D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen));
-+ } else if (S_ISLNK(inode->i_mode)) {
-+ mdatalen = f->metadata->size;
-+ mdata = kmalloc(f->metadata->size, GFP_USER);
-+ if (!mdata)
-+ return -ENOMEM;
-+ ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen);
-+ if (ret) {
-+ kfree(mdata);
-+ return ret;
-+ }
-+ D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen));
-+ }
-+
-+ ri = jffs2_alloc_raw_inode();
-+ if (!ri) {
-+ if (S_ISLNK(inode->i_mode))
-+ kfree(mdata);
-+ return -ENOMEM;
-+ }
-+
-+ ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL);
-+ if (ret) {
-+ jffs2_free_raw_inode(ri);
-+ if (S_ISLNK(inode->i_mode & S_IFMT))
-+ kfree(mdata);
-+ return ret;
-+ }
-+ down(&f->sem);
-+ ivalid = iattr->ia_valid;
-+
-+ ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-+ ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen);
-+ ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
-+
-+ ri->ino = cpu_to_je32(inode->i_ino);
-+ ri->version = cpu_to_je32(++f->highest_version);
-+
-+ ri->uid = cpu_to_je16((ivalid & ATTR_UID)?iattr->ia_uid:inode->i_uid);
-+ ri->gid = cpu_to_je16((ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid);
-+
-+ if (ivalid & ATTR_MODE)
-+ if (iattr->ia_mode & S_ISGID &&
-+ !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID))
-+ ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID);
-+ else
-+ ri->mode = cpu_to_jemode(iattr->ia_mode);
-+ else
-+ ri->mode = cpu_to_jemode(inode->i_mode);
-+
-+
-+ ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size);
-+ ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime));
-+ ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime));
-+ ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime));
-+
-+ ri->offset = cpu_to_je32(0);
-+ ri->csize = ri->dsize = cpu_to_je32(mdatalen);
-+ ri->compr = JFFS2_COMPR_NONE;
-+ if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
-+ /* It's an extension. Make it a hole node */
-+ ri->compr = JFFS2_COMPR_ZERO;
-+ ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size);
-+ ri->offset = cpu_to_je32(inode->i_size);
-+ }
-+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-+ if (mdatalen)
-+ ri->data_crc = cpu_to_je32(crc32(0, mdata, mdatalen));
-+ else
-+ ri->data_crc = cpu_to_je32(0);
-+
-+ new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, phys_ofs, ALLOC_NORMAL);
-+ if (S_ISLNK(inode->i_mode))
-+ kfree(mdata);
-+
-+ if (IS_ERR(new_metadata)) {
-+ jffs2_complete_reservation(c);
-+ jffs2_free_raw_inode(ri);
-+ up(&f->sem);
-+ return PTR_ERR(new_metadata);
-+ }
-+ /* It worked. Update the inode */
-+ inode->i_atime = ITIME(je32_to_cpu(ri->atime));
-+ inode->i_ctime = ITIME(je32_to_cpu(ri->ctime));
-+ inode->i_mtime = ITIME(je32_to_cpu(ri->mtime));
-+ inode->i_mode = jemode_to_cpu(ri->mode);
-+ inode->i_uid = je16_to_cpu(ri->uid);
-+ inode->i_gid = je16_to_cpu(ri->gid);
-+
-+
-+ old_metadata = f->metadata;
-+
-+ if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size)
-+ jffs2_truncate_fraglist (c, &f->fragtree, iattr->ia_size);
-+
-+ if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
-+ jffs2_add_full_dnode_to_inode(c, f, new_metadata);
-+ inode->i_size = iattr->ia_size;
-+ f->metadata = NULL;
-+ } else {
-+ f->metadata = new_metadata;
-+ }
-+ if (old_metadata) {
-+ jffs2_mark_node_obsolete(c, old_metadata->raw);
-+ jffs2_free_full_dnode(old_metadata);
-+ }
-+ jffs2_free_raw_inode(ri);
-+
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+
-+ /* We have to do the vmtruncate() without f->sem held, since
-+ some pages may be locked and waiting for it in readpage().
-+ We are protected from a simultaneous write() extending i_size
-+ back past iattr->ia_size, because do_truncate() holds the
-+ generic inode semaphore. */
-+ if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size)
-+ vmtruncate(inode, iattr->ia_size);
-+
-+ return 0;
-+}
-+
-+int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
-+{
-+ return jffs2_do_setattr(dentry->d_inode, iattr);
-+}
-+
-+int jffs2_statfs(struct super_block *sb, struct kstatfs *buf)
-+{
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-+ unsigned long avail;
-+
-+ buf->f_type = JFFS2_SUPER_MAGIC;
-+ buf->f_bsize = 1 << PAGE_SHIFT;
-+ buf->f_blocks = c->flash_size >> PAGE_SHIFT;
-+ buf->f_files = 0;
-+ buf->f_ffree = 0;
-+ buf->f_namelen = JFFS2_MAX_NAME_LEN;
-+
-+ spin_lock(&c->erase_completion_lock);
-+
-+ avail = c->dirty_size + c->free_size;
-+ if (avail > c->sector_size * c->resv_blocks_write)
-+ avail -= c->sector_size * c->resv_blocks_write;
-+ else
-+ avail = 0;
-+
-+ buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT;
-+
-+ D2(jffs2_dump_block_lists(c));
-+
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ return 0;
-+}
-+
-+
-+void jffs2_clear_inode (struct inode *inode)
-+{
-+ /* We can forget about this inode for now - drop all
-+ * the nodelists associated with it, etc.
-+ */
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-+
-+ D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
-+
-+ jffs2_do_clear_inode(c, f);
-+}
-+
-+void jffs2_read_inode (struct inode *inode)
-+{
-+ struct jffs2_inode_info *f;
-+ struct jffs2_sb_info *c;
-+ struct jffs2_raw_inode latest_node;
-+ int ret;
-+
-+ D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino));
-+
-+ f = JFFS2_INODE_INFO(inode);
-+ c = JFFS2_SB_INFO(inode->i_sb);
-+
-+ jffs2_init_inode_info(f);
-+
-+ ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
-+
-+ if (ret) {
-+ make_bad_inode(inode);
-+ up(&f->sem);
-+ return;
-+ }
-+ inode->i_mode = jemode_to_cpu(latest_node.mode);
-+ inode->i_uid = je16_to_cpu(latest_node.uid);
-+ inode->i_gid = je16_to_cpu(latest_node.gid);
-+ inode->i_size = je32_to_cpu(latest_node.isize);
-+ inode->i_atime = ITIME(je32_to_cpu(latest_node.atime));
-+ inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime));
-+ inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime));
-+
-+ inode->i_nlink = f->inocache->nlink;
-+
-+ inode->i_blksize = PAGE_SIZE;
-+ inode->i_blocks = (inode->i_size + 511) >> 9;
-+
-+ switch (inode->i_mode & S_IFMT) {
-+ jint16_t rdev;
-+
-+ case S_IFLNK:
-+ inode->i_op = &jffs2_symlink_inode_operations;
-+ break;
-+
-+ case S_IFDIR:
-+ {
-+ struct jffs2_full_dirent *fd;
-+
-+ for (fd=f->dents; fd; fd = fd->next) {
-+ if (fd->type == DT_DIR && fd->ino)
-+ inode->i_nlink++;
-+ }
-+ /* and '..' */
-+ inode->i_nlink++;
-+ /* Root dir gets i_nlink 3 for some reason */
-+ if (inode->i_ino == 1)
-+ inode->i_nlink++;
-+
-+ inode->i_op = &jffs2_dir_inode_operations;
-+ inode->i_fop = &jffs2_dir_operations;
-+ break;
-+ }
-+ case S_IFREG:
-+ inode->i_op = &jffs2_file_inode_operations;
-+ inode->i_fop = &jffs2_file_operations;
-+ inode->i_mapping->a_ops = &jffs2_file_address_operations;
-+ inode->i_mapping->nrpages = 0;
-+ break;
-+
-+ case S_IFBLK:
-+ case S_IFCHR:
-+ /* Read the device numbers from the media */
-+ D1(printk(KERN_DEBUG "Reading device numbers from flash\n"));
-+ if (jffs2_read_dnode(c, f, f->metadata, (char *)&rdev, 0, sizeof(rdev)) < 0) {
-+ /* Eep */
-+ printk(KERN_NOTICE "Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino);
-+ up(&f->sem);
-+ jffs2_do_clear_inode(c, f);
-+ make_bad_inode(inode);
-+ return;
-+ }
-+
-+ case S_IFSOCK:
-+ case S_IFIFO:
-+ inode->i_op = &jffs2_file_inode_operations;
-+ init_special_inode(inode, inode->i_mode,
-+ old_decode_dev((je16_to_cpu(rdev))));
-+ break;
-+
-+ default:
-+ printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu\n", inode->i_mode, (unsigned long)inode->i_ino);
-+ }
-+
-+ up(&f->sem);
-+
-+ D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
-+}
-+
-+void jffs2_dirty_inode(struct inode *inode)
-+{
-+ struct iattr iattr;
-+
-+ if (!(inode->i_state & I_DIRTY_DATASYNC)) {
-+ D2(printk(KERN_DEBUG "jffs2_dirty_inode() not calling setattr() for ino #%lu\n", inode->i_ino));
-+ return;
-+ }
-+
-+ D1(printk(KERN_DEBUG "jffs2_dirty_inode() calling setattr() for ino #%lu\n", inode->i_ino));
-+
-+ iattr.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME;
-+ iattr.ia_mode = inode->i_mode;
-+ iattr.ia_uid = inode->i_uid;
-+ iattr.ia_gid = inode->i_gid;
-+ iattr.ia_atime = inode->i_atime;
-+ iattr.ia_mtime = inode->i_mtime;
-+ iattr.ia_ctime = inode->i_ctime;
-+
-+ jffs2_do_setattr(inode, &iattr);
-+}
-+
-+int jffs2_remount_fs (struct super_block *sb, int *flags, char *data)
-+{
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-+
-+ if (c->flags & JFFS2_SB_FLAG_RO && !(sb->s_flags & MS_RDONLY))
-+ return -EROFS;
-+
-+ /* We stop if it was running, then restart if it needs to.
-+ This also catches the case where it was stopped and this
-+ is just a remount to restart it.
-+ Flush the writebuffer, if neccecary, else we loose it */
-+ if (!(sb->s_flags & MS_RDONLY)) {
-+ jffs2_stop_garbage_collect_thread(c);
-+ down(&c->alloc_sem);
-+ jffs2_flush_wbuf_pad(c);
-+ up(&c->alloc_sem);
-+ }
-+
-+ if (!(*flags & MS_RDONLY))
-+ jffs2_start_garbage_collect_thread(c);
-+
-+ *flags |= MS_NOATIME;
-+
-+ return 0;
-+}
-+
-+void jffs2_write_super (struct super_block *sb)
-+{
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-+ sb->s_dirt = 0;
-+
-+ if (sb->s_flags & MS_RDONLY)
-+ return;
-+
-+ D1(printk(KERN_DEBUG "jffs2_write_super()\n"));
-+ jffs2_garbage_collect_trigger(c);
-+ jffs2_erase_pending_blocks(c, 0);
-+ jffs2_flush_wbuf_gc(c, 0);
-+}
-+
-+
-+/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
-+ fill in the raw_inode while you're at it. */
-+struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri)
-+{
-+ struct inode *inode;
-+ struct super_block *sb = dir_i->i_sb;
-+ struct jffs2_sb_info *c;
-+ struct jffs2_inode_info *f;
-+ int ret;
-+
-+ D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode));
-+
-+ c = JFFS2_SB_INFO(sb);
-+
-+ inode = new_inode(sb);
-+
-+ if (!inode)
-+ return ERR_PTR(-ENOMEM);
-+
-+ f = JFFS2_INODE_INFO(inode);
-+ jffs2_init_inode_info(f);
-+
-+ memset(ri, 0, sizeof(*ri));
-+ /* Set OS-specific defaults for new inodes */
-+ ri->uid = cpu_to_je16(current->fsuid);
-+
-+ if (dir_i->i_mode & S_ISGID) {
-+ ri->gid = cpu_to_je16(dir_i->i_gid);
-+ if (S_ISDIR(mode))
-+ mode |= S_ISGID;
-+ } else {
-+ ri->gid = cpu_to_je16(current->fsgid);
-+ }
-+ ri->mode = cpu_to_jemode(mode);
-+ ret = jffs2_do_new_inode (c, f, mode, ri);
-+ if (ret) {
-+ make_bad_inode(inode);
-+ iput(inode);
-+ return ERR_PTR(ret);
-+ }
-+ inode->i_nlink = 1;
-+ inode->i_ino = je32_to_cpu(ri->ino);
-+ inode->i_mode = jemode_to_cpu(ri->mode);
-+ inode->i_gid = je16_to_cpu(ri->gid);
-+ inode->i_uid = je16_to_cpu(ri->uid);
-+ inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-+ ri->atime = ri->mtime = ri->ctime = cpu_to_je32(I_SEC(inode->i_mtime));
-+
-+ inode->i_blksize = PAGE_SIZE;
-+ inode->i_blocks = 0;
-+ inode->i_size = 0;
-+
-+ insert_inode_hash(inode);
-+
-+ return inode;
-+}
-+
-+
-+int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
-+{
-+ struct jffs2_sb_info *c;
-+ struct inode *root_i;
-+ int ret;
-+ size_t blocks;
-+
-+ c = JFFS2_SB_INFO(sb);
-+
-+#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
-+ if (c->mtd->type == MTD_NANDFLASH) {
-+ printk(KERN_ERR "jffs2: Cannot operate on NAND flash unless jffs2 NAND support is compiled in.\n");
-+ return -EINVAL;
-+ }
-+ if (c->mtd->type == MTD_DATAFLASH) {
-+ printk(KERN_ERR "jffs2: Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in.\n");
-+ return -EINVAL;
-+ }
-+#endif
-+
-+ c->flash_size = c->mtd->size;
-+
-+ /*
-+ * Check, if we have to concatenate physical blocks to larger virtual blocks
-+ * to reduce the memorysize for c->blocks. (kmalloc allows max. 128K allocation)
-+ */
-+ c->sector_size = c->mtd->erasesize;
-+ blocks = c->flash_size / c->sector_size;
-+ if (!(c->mtd->flags & MTD_NO_VIRTBLOCKS)) {
-+ while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) {
-+ blocks >>= 1;
-+ c->sector_size <<= 1;
-+ }
-+ }
-+
-+ /*
-+ * Size alignment check
-+ */
-+ if ((c->sector_size * blocks) != c->flash_size) {
-+ c->flash_size = c->sector_size * blocks;
-+ printk(KERN_INFO "jffs2: Flash size not aligned to erasesize, reducing to %dKiB\n",
-+ c->flash_size / 1024);
-+ }
-+
-+ if (c->sector_size != c->mtd->erasesize)
-+ printk(KERN_INFO "jffs2: Erase block size too small (%dKiB). Using virtual blocks size (%dKiB) instead\n",
-+ c->mtd->erasesize / 1024, c->sector_size / 1024);
-+
-+ if (c->flash_size < 5*c->sector_size) {
-+ printk(KERN_ERR "jffs2: Too few erase blocks (%d)\n", c->flash_size / c->sector_size);
-+ return -EINVAL;
-+ }
-+
-+ c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
-+ /* Joern -- stick alignment for weird 8-byte-page flash here */
-+
-+ /* NAND (or other bizarre) flash... do setup accordingly */
-+ ret = jffs2_flash_setup(c);
-+ if (ret)
-+ return ret;
-+
-+ c->inocache_list = kmalloc(INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *), GFP_KERNEL);
-+ if (!c->inocache_list) {
-+ ret = -ENOMEM;
-+ goto out_wbuf;
-+ }
-+ memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *));
-+
-+ if ((ret = jffs2_do_mount_fs(c)))
-+ goto out_inohash;
-+
-+ ret = -EINVAL;
-+
-+ D1(printk(KERN_DEBUG "jffs2_do_fill_super(): Getting root inode\n"));
-+ root_i = iget(sb, 1);
-+ if (is_bad_inode(root_i)) {
-+ D1(printk(KERN_WARNING "get root inode failed\n"));
-+ goto out_nodes;
-+ }
-+
-+ D1(printk(KERN_DEBUG "jffs2_do_fill_super(): d_alloc_root()\n"));
-+ sb->s_root = d_alloc_root(root_i);
-+ if (!sb->s_root)
-+ goto out_root_i;
-+
-+#if LINUX_VERSION_CODE >= 0x20403
-+ sb->s_maxbytes = 0xFFFFFFFF;
-+#endif
-+ sb->s_blocksize = PAGE_CACHE_SIZE;
-+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
-+ sb->s_magic = JFFS2_SUPER_MAGIC;
-+ if (!(sb->s_flags & MS_RDONLY))
-+ jffs2_start_garbage_collect_thread(c);
-+ return 0;
-+
-+ out_root_i:
-+ iput(root_i);
-+ out_nodes:
-+ jffs2_free_ino_caches(c);
-+ jffs2_free_raw_node_refs(c);
-+ if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
-+ vfree(c->blocks);
-+ else
-+ kfree(c->blocks);
-+ out_inohash:
-+ kfree(c->inocache_list);
-+ out_wbuf:
-+ jffs2_flash_cleanup(c);
-+
-+ return ret;
-+}
-+
-+void jffs2_gc_release_inode(struct jffs2_sb_info *c,
-+ struct jffs2_inode_info *f)
-+{
-+ iput(OFNI_EDONI_2SFFJ(f));
-+}
-+
-+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
-+ int inum, int nlink)
-+{
-+ struct inode *inode;
-+ struct jffs2_inode_cache *ic;
-+ if (!nlink) {
-+ /* The inode has zero nlink but its nodes weren't yet marked
-+ obsolete. This has to be because we're still waiting for
-+ the final (close() and) iput() to happen.
-+
-+ There's a possibility that the final iput() could have
-+ happened while we were contemplating. In order to ensure
-+ that we don't cause a new read_inode() (which would fail)
-+ for the inode in question, we use ilookup() in this case
-+ instead of iget().
-+
-+ The nlink can't _become_ zero at this point because we're
-+ holding the alloc_sem, and jffs2_do_unlink() would also
-+ need that while decrementing nlink on any inode.
-+ */
-+ inode = ilookup(OFNI_BS_2SFFJ(c), inum);
-+ if (!inode) {
-+ D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n",
-+ inum));
-+
-+ spin_lock(&c->inocache_lock);
-+ ic = jffs2_get_ino_cache(c, inum);
-+ if (!ic) {
-+ D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.\n", inum));
-+ spin_unlock(&c->inocache_lock);
-+ return NULL;
-+ }
-+ if (ic->state != INO_STATE_CHECKEDABSENT) {
-+ /* Wait for progress. Don't just loop */
-+ D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d\n",
-+ ic->ino, ic->state));
-+ sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
-+ } else {
-+ spin_unlock(&c->inocache_lock);
-+ }
-+
-+ return NULL;
-+ }
-+ } else {
-+ /* Inode has links to it still; they're not going away because
-+ jffs2_do_unlink() would need the alloc_sem and we have it.
-+ Just iget() it, and if read_inode() is necessary that's OK.
-+ */
-+ inode = iget(OFNI_BS_2SFFJ(c), inum);
-+ if (!inode)
-+ return ERR_PTR(-ENOMEM);
-+ }
-+ if (is_bad_inode(inode)) {
-+ printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. nlink %d\n",
-+ inum, nlink);
-+ /* NB. This will happen again. We need to do something appropriate here. */
-+ iput(inode);
-+ return ERR_PTR(-EIO);
-+ }
-+
-+ return JFFS2_INODE_INFO(inode);
-+}
-+
-+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
-+ struct jffs2_inode_info *f,
-+ unsigned long offset,
-+ unsigned long *priv)
-+{
-+ struct inode *inode = OFNI_EDONI_2SFFJ(f);
-+ struct page *pg;
-+
-+ pg = read_cache_page(inode->i_mapping, offset >> PAGE_CACHE_SHIFT,
-+ (void *)jffs2_do_readpage_unlock, inode);
-+ if (IS_ERR(pg))
-+ return (void *)pg;
-+
-+ *priv = (unsigned long)pg;
-+ return kmap(pg);
-+}
-+
-+void jffs2_gc_release_page(struct jffs2_sb_info *c,
-+ unsigned char *ptr,
-+ unsigned long *priv)
-+{
-+ struct page *pg = (void *)*priv;
-+
-+ kunmap(pg);
-+ page_cache_release(pg);
-+}
-+
-+int jffs2_flash_setup(struct jffs2_sb_info *c) {
-+ int ret = 0;
-+
-+ if (jffs2_cleanmarker_oob(c)) {
-+ /* NAND flash... do setup accordingly */
-+ ret = jffs2_nand_flash_setup(c);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ /* add setups for other bizarre flashes here... */
-+ if (jffs2_nor_ecc(c)) {
-+ ret = jffs2_nor_ecc_flash_setup(c);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ /* and Dataflash */
-+ if (jffs2_dataflash(c)) {
-+ ret = jffs2_dataflash_setup(c);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ return ret;
-+}
-+
-+void jffs2_flash_cleanup(struct jffs2_sb_info *c) {
-+
-+ if (jffs2_cleanmarker_oob(c)) {
-+ jffs2_nand_flash_cleanup(c);
-+ }
-+
-+ /* add cleanups for other bizarre flashes here... */
-+ if (jffs2_nor_ecc(c)) {
-+ jffs2_nor_ecc_flash_cleanup(c);
-+ }
-+
-+ /* and DataFlash */
-+ if (jffs2_dataflash(c)) {
-+ jffs2_dataflash_cleanup(c);
-+ }
-+}
---- linux-2.4.21/fs/jffs2/gc.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/gc.c
-@@ -1,76 +1,68 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: gc.c,v 1.52.2.5 2002/10/10 13:18:38 dwmw2 Exp $
-+ * $Id: gc.c,v 1.145 2005/02/09 09:09:01 pavlov Exp $
- *
- */
-
- #include <linux/kernel.h>
- #include <linux/mtd/mtd.h>
- #include <linux/slab.h>
--#include <linux/jffs2.h>
--#include <linux/sched.h>
--#include <linux/interrupt.h>
- #include <linux/pagemap.h>
-+#include <linux/crc32.h>
-+#include <linux/compiler.h>
-+#include <linux/stat.h>
- #include "nodelist.h"
--#include "crc32.h"
-+#include "compr.h"
-
-+static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
-+ struct jffs2_inode_cache *ic,
-+ struct jffs2_raw_node_ref *raw);
- static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dnode *fd);
-+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fd);
- static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dirent *fd);
-+ struct jffs2_inode_info *f, struct jffs2_full_dirent *fd);
- static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dirent *fd);
-+ struct jffs2_inode_info *f, struct jffs2_full_dirent *fd);
- static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *indeo, struct jffs2_full_dnode *fn,
-- __u32 start, __u32 end);
-+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
-+ uint32_t start, uint32_t end);
- static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dnode *fn,
-- __u32 start, __u32 end);
-+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
-+ uint32_t start, uint32_t end);
-+static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-+ struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f);
-
- /* Called with erase_completion_lock held */
- static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
- {
- struct jffs2_eraseblock *ret;
- struct list_head *nextlist = NULL;
-+ int n = jiffies % 128;
-
- /* Pick an eraseblock to garbage collect next. This is where we'll
- put the clever wear-levelling algorithms. Eventually. */
-- if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > JFFS2_RESERVED_BLOCKS_GCBAD) {
-+ /* We possibly want to favour the dirtier blocks more when the
-+ number of free blocks is low. */
-+ if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) {
- D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n"));
- nextlist = &c->bad_used_list;
-- } else if (jiffies % 100 && !list_empty(&c->dirty_list)) {
-- /* Most of the time, pick one off the dirty list */
-+ } else if (n < 50 && !list_empty(&c->erasable_list)) {
-+ /* Note that most of them will have gone directly to be erased.
-+ So don't favour the erasable_list _too_ much. */
-+ D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next\n"));
-+ nextlist = &c->erasable_list;
-+ } else if (n < 110 && !list_empty(&c->very_dirty_list)) {
-+ /* Most of the time, pick one off the very_dirty list */
-+ D1(printk(KERN_DEBUG "Picking block from very_dirty_list to GC next\n"));
-+ nextlist = &c->very_dirty_list;
-+ } else if (n < 126 && !list_empty(&c->dirty_list)) {
- D1(printk(KERN_DEBUG "Picking block from dirty_list to GC next\n"));
- nextlist = &c->dirty_list;
- } else if (!list_empty(&c->clean_list)) {
-@@ -80,9 +72,16 @@
- D1(printk(KERN_DEBUG "Picking block from dirty_list to GC next (clean_list was empty)\n"));
-
- nextlist = &c->dirty_list;
-+ } else if (!list_empty(&c->very_dirty_list)) {
-+ D1(printk(KERN_DEBUG "Picking block from very_dirty_list to GC next (clean_list and dirty_list were empty)\n"));
-+ nextlist = &c->very_dirty_list;
-+ } else if (!list_empty(&c->erasable_list)) {
-+ D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty)\n"));
-+
-+ nextlist = &c->erasable_list;
- } else {
-- /* Eep. Both were empty */
-- printk(KERN_NOTICE "jffs2: No clean _or_ dirty blocks to GC from! Where are they all?\n");
-+ /* Eep. All were empty */
-+ D1(printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n"));
- return NULL;
- }
-
-@@ -94,6 +93,17 @@
- printk(KERN_WARNING "Eep. ret->gc_node for block at 0x%08x is NULL\n", ret->offset);
- BUG();
- }
-+
-+ /* Have we accidentally picked a clean block with wasted space ? */
-+ if (ret->wasted_size) {
-+ D1(printk(KERN_DEBUG "Converting wasted_size %08x to dirty_size\n", ret->wasted_size));
-+ ret->dirty_size += ret->wasted_size;
-+ c->wasted_size -= ret->wasted_size;
-+ c->dirty_size += ret->wasted_size;
-+ ret->wasted_size = 0;
-+ }
-+
-+ D2(jffs2_dump_block_lists(c));
- return ret;
- }
-
-@@ -103,21 +113,90 @@
- */
- int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
- {
-- struct jffs2_eraseblock *jeb;
- struct jffs2_inode_info *f;
-+ struct jffs2_inode_cache *ic;
-+ struct jffs2_eraseblock *jeb;
- struct jffs2_raw_node_ref *raw;
-- struct jffs2_node_frag *frag;
-- struct jffs2_full_dnode *fn = NULL;
-- struct jffs2_full_dirent *fd;
-- __u32 start = 0, end = 0, nrfrags = 0;
-- __u32 inum;
-- struct inode *inode;
-- int ret = 0;
-+ int ret = 0, inum, nlink;
-
- if (down_interruptible(&c->alloc_sem))
- return -EINTR;
-
-- spin_lock_bh(&c->erase_completion_lock);
-+ for (;;) {
-+ spin_lock(&c->erase_completion_lock);
-+ if (!c->unchecked_size)
-+ break;
-+
-+ /* We can't start doing GC yet. We haven't finished checking
-+ the node CRCs etc. Do it now. */
-+
-+ /* checked_ino is protected by the alloc_sem */
-+ if (c->checked_ino > c->highest_ino) {
-+ printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n",
-+ c->unchecked_size);
-+ D2(jffs2_dump_block_lists(c));
-+ spin_unlock(&c->erase_completion_lock);
-+ BUG();
-+ }
-+
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ spin_lock(&c->inocache_lock);
-+
-+ ic = jffs2_get_ino_cache(c, c->checked_ino++);
-+
-+ if (!ic) {
-+ spin_unlock(&c->inocache_lock);
-+ continue;
-+ }
-+
-+ if (!ic->nlink) {
-+ D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n",
-+ ic->ino));
-+ spin_unlock(&c->inocache_lock);
-+ continue;
-+ }
-+ switch(ic->state) {
-+ case INO_STATE_CHECKEDABSENT:
-+ case INO_STATE_PRESENT:
-+ D1(printk(KERN_DEBUG "Skipping ino #%u already checked\n", ic->ino));
-+ spin_unlock(&c->inocache_lock);
-+ continue;
-+
-+ case INO_STATE_GC:
-+ case INO_STATE_CHECKING:
-+ printk(KERN_WARNING "Inode #%u is in state %d during CRC check phase!\n", ic->ino, ic->state);
-+ spin_unlock(&c->inocache_lock);
-+ BUG();
-+
-+ case INO_STATE_READING:
-+ /* We need to wait for it to finish, lest we move on
-+ and trigger the BUG() above while we haven't yet
-+ finished checking all its nodes */
-+ D1(printk(KERN_DEBUG "Waiting for ino #%u to finish reading\n", ic->ino));
-+ up(&c->alloc_sem);
-+ sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
-+ return 0;
-+
-+ default:
-+ BUG();
-+
-+ case INO_STATE_UNCHECKED:
-+ ;
-+ }
-+ ic->state = INO_STATE_CHECKING;
-+ spin_unlock(&c->inocache_lock);
-+
-+ D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%u\n", ic->ino));
-+
-+ ret = jffs2_do_crccheck_inode(c, ic);
-+ if (ret)
-+ printk(KERN_WARNING "Returned error for crccheck of ino #%u. Expect badness...\n", ic->ino);
-+
-+ jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT);
-+ up(&c->alloc_sem);
-+ return ret;
-+ }
-
- /* First, work out which block we're garbage-collecting */
- jeb = c->gcblock;
-@@ -126,13 +205,15 @@
- jeb = jffs2_find_gc_block(c);
-
- if (!jeb) {
-- printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n");
-- spin_unlock_bh(&c->erase_completion_lock);
-+ D1 (printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n"));
-+ spin_unlock(&c->erase_completion_lock);
- up(&c->alloc_sem);
- return -EIO;
- }
-
-- D1(printk(KERN_DEBUG "garbage collect from block at phys 0x%08x\n", jeb->offset));
-+ D1(printk(KERN_DEBUG "GC from block %08x, used_size %08x, dirty_size %08x, free_size %08x\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size));
-+ D1(if (c->nextblock)
-+ printk(KERN_DEBUG "Nextblock at %08x, used_size %08x, dirty_size %08x, wasted_size %08x, free_size %08x\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->free_size));
-
- if (!jeb->used_size) {
- up(&c->alloc_sem);
-@@ -141,61 +222,215 @@
-
- raw = jeb->gc_node;
-
-- while(raw->flash_offset & 1) {
-- D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", raw->flash_offset &~3));
-- jeb->gc_node = raw = raw->next_phys;
-- if (!raw) {
-+ while(ref_obsolete(raw)) {
-+ D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw)));
-+ raw = raw->next_phys;
-+ if (unlikely(!raw)) {
- printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n");
- printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n",
- jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size);
-- spin_unlock_bh(&c->erase_completion_lock);
-+ jeb->gc_node = raw;
-+ spin_unlock(&c->erase_completion_lock);
- up(&c->alloc_sem);
- BUG();
- }
- }
-- D1(printk(KERN_DEBUG "Going to garbage collect node at 0x%08x\n", raw->flash_offset &~3));
-+ jeb->gc_node = raw;
-+
-+ D1(printk(KERN_DEBUG "Going to garbage collect node at 0x%08x\n", ref_offset(raw)));
-+
- if (!raw->next_in_ino) {
- /* Inode-less node. Clean marker, snapshot or something like that */
-- spin_unlock_bh(&c->erase_completion_lock);
-+ /* FIXME: If it's something that needs to be copied, including something
-+ we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */
-+ spin_unlock(&c->erase_completion_lock);
- jffs2_mark_node_obsolete(c, raw);
- up(&c->alloc_sem);
- goto eraseit_lock;
- }
-
-- inum = jffs2_raw_ref_to_inum(raw);
-- D1(printk(KERN_DEBUG "Inode number is #%u\n", inum));
-+ ic = jffs2_raw_ref_to_ic(raw);
-
-- spin_unlock_bh(&c->erase_completion_lock);
-+ /* We need to hold the inocache. Either the erase_completion_lock or
-+ the inocache_lock are sufficient; we trade down since the inocache_lock
-+ causes less contention. */
-+ spin_lock(&c->inocache_lock);
-
-- D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x, ino #%u\n", jeb->offset, raw->flash_offset&~3, inum));
-+ spin_unlock(&c->erase_completion_lock);
-
-- inode = iget(OFNI_BS_2SFFJ(c), inum);
-- if (is_bad_inode(inode)) {
-- printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", inum);
-- /* NB. This will happen again. We need to do something appropriate here. */
-+ D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x(%d), ino #%u\n", jeb->offset, ref_offset(raw), ref_flags(raw), ic->ino));
-+
-+ /* Three possibilities:
-+ 1. Inode is already in-core. We must iget it and do proper
-+ updating to its fragtree, etc.
-+ 2. Inode is not in-core, node is REF_PRISTINE. We lock the
-+ inocache to prevent a read_inode(), copy the node intact.
-+ 3. Inode is not in-core, node is not pristine. We must iget()
-+ and take the slow path.
-+ */
-+
-+ switch(ic->state) {
-+ case INO_STATE_CHECKEDABSENT:
-+ /* It's been checked, but it's not currently in-core.
-+ We can just copy any pristine nodes, but have
-+ to prevent anyone else from doing read_inode() while
-+ we're at it, so we set the state accordingly */
-+ if (ref_flags(raw) == REF_PRISTINE)
-+ ic->state = INO_STATE_GC;
-+ else {
-+ D1(printk(KERN_DEBUG "Ino #%u is absent but node not REF_PRISTINE. Reading.\n",
-+ ic->ino));
-+ }
-+ break;
-+
-+ case INO_STATE_PRESENT:
-+ /* It's in-core. GC must iget() it. */
-+ break;
-+
-+ case INO_STATE_UNCHECKED:
-+ case INO_STATE_CHECKING:
-+ case INO_STATE_GC:
-+ /* Should never happen. We should have finished checking
-+ by the time we actually start doing any GC, and since
-+ we're holding the alloc_sem, no other garbage collection
-+ can happen.
-+ */
-+ printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n",
-+ ic->ino, ic->state);
- up(&c->alloc_sem);
-- iput(inode);
-- return -EIO;
-+ spin_unlock(&c->inocache_lock);
-+ BUG();
-+
-+ case INO_STATE_READING:
-+ /* Someone's currently trying to read it. We must wait for
-+ them to finish and then go through the full iget() route
-+ to do the GC. However, sometimes read_inode() needs to get
-+ the alloc_sem() (for marking nodes invalid) so we must
-+ drop the alloc_sem before sleeping. */
-+
-+ up(&c->alloc_sem);
-+ D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n",
-+ ic->ino, ic->state));
-+ sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
-+ /* And because we dropped the alloc_sem we must start again from the
-+ beginning. Ponder chance of livelock here -- we're returning success
-+ without actually making any progress.
-+
-+ Q: What are the chances that the inode is back in INO_STATE_READING
-+ again by the time we next enter this function? And that this happens
-+ enough times to cause a real delay?
-+
-+ A: Small enough that I don't care :)
-+ */
-+ return 0;
- }
-
-- f = JFFS2_INODE_INFO(inode);
-+ /* OK. Now if the inode is in state INO_STATE_GC, we are going to copy the
-+ node intact, and we don't have to muck about with the fragtree etc.
-+ because we know it's not in-core. If it _was_ in-core, we go through
-+ all the iget() crap anyway */
-+
-+ if (ic->state == INO_STATE_GC) {
-+ spin_unlock(&c->inocache_lock);
-+
-+ ret = jffs2_garbage_collect_pristine(c, ic, raw);
-+
-+ spin_lock(&c->inocache_lock);
-+ ic->state = INO_STATE_CHECKEDABSENT;
-+ wake_up(&c->inocache_wq);
-+
-+ if (ret != -EBADFD) {
-+ spin_unlock(&c->inocache_lock);
-+ goto release_sem;
-+ }
-+
-+ /* Fall through if it wanted us to, with inocache_lock held */
-+ }
-+
-+ /* Prevent the fairly unlikely race where the gcblock is
-+ entirely obsoleted by the final close of a file which had
-+ the only valid nodes in the block, followed by erasure,
-+ followed by freeing of the ic because the erased block(s)
-+ held _all_ the nodes of that inode.... never been seen but
-+ it's vaguely possible. */
-+
-+ inum = ic->ino;
-+ nlink = ic->nlink;
-+ spin_unlock(&c->inocache_lock);
-+
-+ f = jffs2_gc_fetch_inode(c, inum, nlink);
-+ if (IS_ERR(f)) {
-+ ret = PTR_ERR(f);
-+ goto release_sem;
-+ }
-+ if (!f) {
-+ ret = 0;
-+ goto release_sem;
-+ }
-+
-+ ret = jffs2_garbage_collect_live(c, jeb, raw, f);
-+
-+ jffs2_gc_release_inode(c, f);
-+
-+ release_sem:
-+ up(&c->alloc_sem);
-+
-+ eraseit_lock:
-+ /* If we've finished this block, start it erasing */
-+ spin_lock(&c->erase_completion_lock);
-+
-+ eraseit:
-+ if (c->gcblock && !c->gcblock->used_size) {
-+ D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset));
-+ /* We're GC'ing an empty block? */
-+ list_add_tail(&c->gcblock->list, &c->erase_pending_list);
-+ c->gcblock = NULL;
-+ c->nr_erasing_blocks++;
-+ jffs2_erase_pending_trigger(c);
-+ }
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ return ret;
-+}
-+
-+static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-+ struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f)
-+{
-+ struct jffs2_node_frag *frag;
-+ struct jffs2_full_dnode *fn = NULL;
-+ struct jffs2_full_dirent *fd;
-+ uint32_t start = 0, end = 0, nrfrags = 0;
-+ int ret = 0;
-+
- down(&f->sem);
-+
- /* Now we have the lock for this inode. Check that it's still the one at the head
- of the list. */
-
-- if (raw->flash_offset & 1) {
-+ spin_lock(&c->erase_completion_lock);
-+
-+ if (c->gcblock != jeb) {
-+ spin_unlock(&c->erase_completion_lock);
-+ D1(printk(KERN_DEBUG "GC block is no longer gcblock. Restart\n"));
-+ goto upnout;
-+ }
-+ if (ref_obsolete(raw)) {
-+ spin_unlock(&c->erase_completion_lock);
- D1(printk(KERN_DEBUG "node to be GC'd was obsoleted in the meantime.\n"));
- /* They'll call again */
- goto upnout;
- }
-+ spin_unlock(&c->erase_completion_lock);
-+
- /* OK. Looks safe. And nobody can get us now because we have the semaphore. Move the block */
- if (f->metadata && f->metadata->raw == raw) {
- fn = f->metadata;
-- ret = jffs2_garbage_collect_metadata(c, jeb, inode, fn);
-+ ret = jffs2_garbage_collect_metadata(c, jeb, f, fn);
- goto upnout;
- }
-
-- for (frag = f->fraglist; frag; frag = frag->next) {
-+ /* FIXME. Read node and do lookup? */
-+ for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
- if (frag->node && frag->node->raw == raw) {
- fn = frag->node;
- end = frag->ofs + frag->size;
-@@ -206,13 +441,22 @@
- }
- }
- if (fn) {
-+ if (ref_flags(raw) == REF_PRISTINE) {
-+ ret = jffs2_garbage_collect_pristine(c, f->inocache, raw);
-+ if (!ret) {
-+ /* Urgh. Return it sensibly. */
-+ frag->node->raw = f->inocache->nodes;
-+ }
-+ if (ret != -EBADFD)
-+ goto upnout;
-+ }
- /* We found a datanode. Do the GC */
- if((start >> PAGE_CACHE_SHIFT) < ((end-1) >> PAGE_CACHE_SHIFT)) {
- /* It crosses a page boundary. Therefore, it must be a hole. */
-- ret = jffs2_garbage_collect_hole(c, jeb, inode, fn, start, end);
-+ ret = jffs2_garbage_collect_hole(c, jeb, f, fn, start, end);
- } else {
- /* It could still be a hole. But we GC the page this way anyway */
-- ret = jffs2_garbage_collect_dnode(c, jeb, inode, fn, start, end);
-+ ret = jffs2_garbage_collect_dnode(c, jeb, f, fn, start, end);
- }
- goto upnout;
- }
-@@ -224,12 +468,13 @@
- }
-
- if (fd && fd->ino) {
-- ret = jffs2_garbage_collect_dirent(c, jeb, inode, fd);
-+ ret = jffs2_garbage_collect_dirent(c, jeb, f, fd);
- } else if (fd) {
-- ret = jffs2_garbage_collect_deletion_dirent(c, jeb, inode, fd);
-+ ret = jffs2_garbage_collect_deletion_dirent(c, jeb, f, fd);
- } else {
-- printk(KERN_WARNING "Raw node at 0x%08x wasn't in node lists for ino #%lu\n", raw->flash_offset&~3, inode->i_ino);
-- if (raw->flash_offset & 1) {
-+ printk(KERN_WARNING "Raw node at 0x%08x wasn't in node lists for ino #%u\n",
-+ ref_offset(raw), f->inocache->ino);
-+ if (ref_obsolete(raw)) {
- printk(KERN_WARNING "But it's obsolete so we don't mind too much\n");
- } else {
- ret = -EIO;
-@@ -237,53 +482,207 @@
- }
- upnout:
- up(&f->sem);
-- up(&c->alloc_sem);
-- iput(inode);
-
-- eraseit_lock:
-- /* If we've finished this block, start it erasing */
-- spin_lock_bh(&c->erase_completion_lock);
-+ return ret;
-+}
-
-- eraseit:
-- if (c->gcblock && !c->gcblock->used_size) {
-- D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset));
-- /* We're GC'ing an empty block? */
-- list_add_tail(&c->gcblock->list, &c->erase_pending_list);
-- c->gcblock = NULL;
-- c->nr_erasing_blocks++;
-- jffs2_erase_pending_trigger(c);
-+static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
-+ struct jffs2_inode_cache *ic,
-+ struct jffs2_raw_node_ref *raw)
-+{
-+ union jffs2_node_union *node;
-+ struct jffs2_raw_node_ref *nraw;
-+ size_t retlen;
-+ int ret;
-+ uint32_t phys_ofs, alloclen;
-+ uint32_t crc, rawlen;
-+ int retried = 0;
-+
-+ D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw)));
-+
-+ rawlen = ref_totlen(c, c->gcblock, raw);
-+
-+ /* Ask for a small amount of space (or the totlen if smaller) because we
-+ don't want to force wastage of the end of a block if splitting would
-+ work. */
-+ ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN,
-+ rawlen), &phys_ofs, &alloclen);
-+ if (ret)
-+ return ret;
-+
-+ if (alloclen < rawlen) {
-+ /* Doesn't fit untouched. We'll go the old route and split it */
-+ return -EBADFD;
- }
-- spin_unlock_bh(&c->erase_completion_lock);
-
-+ node = kmalloc(rawlen, GFP_KERNEL);
-+ if (!node)
-+ return -ENOMEM;
-+
-+ ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node);
-+ if (!ret && retlen != rawlen)
-+ ret = -EIO;
-+ if (ret)
-+ goto out_node;
-+
-+ crc = crc32(0, node, sizeof(struct jffs2_unknown_node)-4);
-+ if (je32_to_cpu(node->u.hdr_crc) != crc) {
-+ printk(KERN_WARNING "Header CRC failed on REF_PRISTINE node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-+ ref_offset(raw), je32_to_cpu(node->u.hdr_crc), crc);
-+ goto bail;
-+ }
-+
-+ switch(je16_to_cpu(node->u.nodetype)) {
-+ case JFFS2_NODETYPE_INODE:
-+ crc = crc32(0, node, sizeof(node->i)-8);
-+ if (je32_to_cpu(node->i.node_crc) != crc) {
-+ printk(KERN_WARNING "Node CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-+ ref_offset(raw), je32_to_cpu(node->i.node_crc), crc);
-+ goto bail;
-+ }
-+
-+ if (je32_to_cpu(node->i.dsize)) {
-+ crc = crc32(0, node->i.data, je32_to_cpu(node->i.csize));
-+ if (je32_to_cpu(node->i.data_crc) != crc) {
-+ printk(KERN_WARNING "Data CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-+ ref_offset(raw), je32_to_cpu(node->i.data_crc), crc);
-+ goto bail;
-+ }
-+ }
-+ break;
-+
-+ case JFFS2_NODETYPE_DIRENT:
-+ crc = crc32(0, node, sizeof(node->d)-8);
-+ if (je32_to_cpu(node->d.node_crc) != crc) {
-+ printk(KERN_WARNING "Node CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-+ ref_offset(raw), je32_to_cpu(node->d.node_crc), crc);
-+ goto bail;
-+ }
-+
-+ if (node->d.nsize) {
-+ crc = crc32(0, node->d.name, node->d.nsize);
-+ if (je32_to_cpu(node->d.name_crc) != crc) {
-+ printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent ode at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-+ ref_offset(raw), je32_to_cpu(node->d.name_crc), crc);
-+ goto bail;
-+ }
-+ }
-+ break;
-+ default:
-+ printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n",
-+ ref_offset(raw), je16_to_cpu(node->u.nodetype));
-+ goto bail;
-+ }
-+
-+ nraw = jffs2_alloc_raw_node_ref();
-+ if (!nraw) {
-+ ret = -ENOMEM;
-+ goto out_node;
-+ }
-+
-+ /* OK, all the CRCs are good; this node can just be copied as-is. */
-+ retry:
-+ nraw->flash_offset = phys_ofs;
-+ nraw->__totlen = rawlen;
-+ nraw->next_phys = NULL;
-+
-+ ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node);
-+
-+ if (ret || (retlen != rawlen)) {
-+ printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n",
-+ rawlen, phys_ofs, ret, retlen);
-+ if (retlen) {
-+ /* Doesn't belong to any inode */
-+ nraw->next_in_ino = NULL;
-+
-+ nraw->flash_offset |= REF_OBSOLETE;
-+ jffs2_add_physical_node_ref(c, nraw);
-+ jffs2_mark_node_obsolete(c, nraw);
-+ } else {
-+ printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset);
-+ jffs2_free_raw_node_ref(nraw);
-+ }
-+ if (!retried && (nraw = jffs2_alloc_raw_node_ref())) {
-+ /* Try to reallocate space and retry */
-+ uint32_t dummy;
-+ struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size];
-+
-+ retried = 1;
-+
-+ D1(printk(KERN_DEBUG "Retrying failed write of REF_PRISTINE node.\n"));
-+
-+ ACCT_SANITY_CHECK(c,jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+
-+ ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy);
-+
-+ if (!ret) {
-+ D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs));
-+
-+ ACCT_SANITY_CHECK(c,jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+
-+ goto retry;
-+ }
-+ D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
-+ jffs2_free_raw_node_ref(nraw);
-+ }
-+
-+ jffs2_free_raw_node_ref(nraw);
-+ if (!ret)
-+ ret = -EIO;
-+ goto out_node;
-+ }
-+ nraw->flash_offset |= REF_PRISTINE;
-+ jffs2_add_physical_node_ref(c, nraw);
-+
-+ /* Link into per-inode list. This is safe because of the ic
-+ state being INO_STATE_GC. Note that if we're doing this
-+ for an inode which is in-core, the 'nraw' pointer is then
-+ going to be fetched from ic->nodes by our caller. */
-+ spin_lock(&c->erase_completion_lock);
-+ nraw->next_in_ino = ic->nodes;
-+ ic->nodes = nraw;
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ jffs2_mark_node_obsolete(c, raw);
-+ D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw)));
-+
-+ out_node:
-+ kfree(node);
- return ret;
-+ bail:
-+ ret = -EBADFD;
-+ goto out_node;
- }
-
- static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dnode *fn)
-+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fn)
- {
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_full_dnode *new_fn;
- struct jffs2_raw_inode ri;
-- unsigned short dev;
-+ jint16_t dev;
- char *mdata = NULL, mdatalen = 0;
-- __u32 alloclen, phys_ofs;
-+ uint32_t alloclen, phys_ofs;
- int ret;
-
-- if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
-+ if (S_ISBLK(JFFS2_F_I_MODE(f)) ||
-+ S_ISCHR(JFFS2_F_I_MODE(f)) ) {
- /* For these, we don't actually need to read the old node */
-- dev = (MAJOR(to_kdev_t(inode->i_rdev)) << 8) |
-- MINOR(to_kdev_t(inode->i_rdev));
-+ /* FIXME: for minor or major > 255. */
-+ dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) |
-+ JFFS2_F_I_RDEV_MIN(f)));
- mdata = (char *)&dev;
- mdatalen = sizeof(dev);
- D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen));
-- } else if (S_ISLNK(inode->i_mode)) {
-+ } else if (S_ISLNK(JFFS2_F_I_MODE(f))) {
- mdatalen = fn->size;
- mdata = kmalloc(fn->size, GFP_KERNEL);
- if (!mdata) {
- printk(KERN_WARNING "kmalloc of mdata failed in jffs2_garbage_collect_metadata()\n");
- return -ENOMEM;
- }
-- ret = jffs2_read_dnode(c, fn, mdata, 0, mdatalen);
-+ ret = jffs2_read_dnode(c, f, fn, mdata, 0, mdatalen);
- if (ret) {
- printk(KERN_WARNING "read of old metadata failed in jffs2_garbage_collect_metadata(): %d\n", ret);
- kfree(mdata);
-@@ -295,34 +694,34 @@
-
- ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen);
- if (ret) {
-- printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_metadata failed: %d\n",
-+ printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n",
- sizeof(ri)+ mdatalen, ret);
- goto out;
- }
-
- memset(&ri, 0, sizeof(ri));
-- ri.magic = JFFS2_MAGIC_BITMASK;
-- ri.nodetype = JFFS2_NODETYPE_INODE;
-- ri.totlen = sizeof(ri) + mdatalen;
-- ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4);
-+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-+ ri.totlen = cpu_to_je32(sizeof(ri) + mdatalen);
-+ ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
-
-- ri.ino = inode->i_ino;
-- ri.version = ++f->highest_version;
-- ri.mode = inode->i_mode;
-- ri.uid = inode->i_uid;
-- ri.gid = inode->i_gid;
-- ri.isize = inode->i_size;
-- ri.atime = inode->i_atime;
-- ri.ctime = inode->i_ctime;
-- ri.mtime = inode->i_mtime;
-- ri.offset = 0;
-- ri.csize = mdatalen;
-- ri.dsize = mdatalen;
-+ ri.ino = cpu_to_je32(f->inocache->ino);
-+ ri.version = cpu_to_je32(++f->highest_version);
-+ ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f));
-+ ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
-+ ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
-+ ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
-+ ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f));
-+ ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f));
-+ ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f));
-+ ri.offset = cpu_to_je32(0);
-+ ri.csize = cpu_to_je32(mdatalen);
-+ ri.dsize = cpu_to_je32(mdatalen);
- ri.compr = JFFS2_COMPR_NONE;
-- ri.node_crc = crc32(0, &ri, sizeof(ri)-8);
-- ri.data_crc = crc32(0, mdata, mdatalen);
-+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
-+ ri.data_crc = cpu_to_je32(crc32(0, mdata, mdatalen));
-
-- new_fn = jffs2_write_dnode(inode, &ri, mdata, mdatalen, phys_ofs, NULL);
-+ new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, phys_ofs, ALLOC_GC);
-
- if (IS_ERR(new_fn)) {
- printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));
-@@ -333,41 +732,40 @@
- jffs2_free_full_dnode(fn);
- f->metadata = new_fn;
- out:
-- if (S_ISLNK(inode->i_mode))
-+ if (S_ISLNK(JFFS2_F_I_MODE(f)))
- kfree(mdata);
- return ret;
- }
-
- static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dirent *fd)
-+ struct jffs2_inode_info *f, struct jffs2_full_dirent *fd)
- {
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_full_dirent *new_fd;
- struct jffs2_raw_dirent rd;
-- __u32 alloclen, phys_ofs;
-+ uint32_t alloclen, phys_ofs;
- int ret;
-
-- rd.magic = JFFS2_MAGIC_BITMASK;
-- rd.nodetype = JFFS2_NODETYPE_DIRENT;
-+ rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
- rd.nsize = strlen(fd->name);
-- rd.totlen = sizeof(rd) + rd.nsize;
-- rd.hdr_crc = crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4);
-+ rd.totlen = cpu_to_je32(sizeof(rd) + rd.nsize);
-+ rd.hdr_crc = cpu_to_je32(crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4));
-
-- rd.pino = inode->i_ino;
-- rd.version = ++f->highest_version;
-- rd.ino = fd->ino;
-- rd.mctime = max(inode->i_mtime, inode->i_ctime);
-+ rd.pino = cpu_to_je32(f->inocache->ino);
-+ rd.version = cpu_to_je32(++f->highest_version);
-+ rd.ino = cpu_to_je32(fd->ino);
-+ rd.mctime = cpu_to_je32(max(JFFS2_F_I_MTIME(f), JFFS2_F_I_CTIME(f)));
- rd.type = fd->type;
-- rd.node_crc = crc32(0, &rd, sizeof(rd)-8);
-- rd.name_crc = crc32(0, fd->name, rd.nsize);
-+ rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8));
-+ rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize));
-
- ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen);
- if (ret) {
-- printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dirent failed: %d\n",
-+ printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n",
- sizeof(rd)+rd.nsize, ret);
- return ret;
- }
-- new_fd = jffs2_write_dirent(inode, &rd, fd->name, rd.nsize, phys_ofs, NULL);
-+ new_fd = jffs2_write_dirent(c, f, &rd, fd->name, rd.nsize, phys_ofs, ALLOC_GC);
-
- if (IS_ERR(new_fd)) {
- printk(KERN_WARNING "jffs2_write_dirent in garbage_collect_dirent failed: %ld\n", PTR_ERR(new_fd));
-@@ -378,19 +776,97 @@
- }
-
- static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dirent *fd)
-+ struct jffs2_inode_info *f, struct jffs2_full_dirent *fd)
- {
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_full_dirent **fdp = &f->dents;
- int found = 0;
-
-- /* FIXME: When we run on NAND flash, we need to work out whether
-- this deletion dirent is still needed to actively delete a
-- 'real' dirent with the same name that's still somewhere else
-- on the flash. For now, we know that we've actually obliterated
-- all the older dirents when they became obsolete, so we didn't
-- really need to write the deletion to flash in the first place.
-- */
-+ /* On a medium where we can't actually mark nodes obsolete
-+ pernamently, such as NAND flash, we need to work out
-+ whether this deletion dirent is still needed to actively
-+ delete a 'real' dirent with the same name that's still
-+ somewhere else on the flash. */
-+ if (!jffs2_can_mark_obsolete(c)) {
-+ struct jffs2_raw_dirent *rd;
-+ struct jffs2_raw_node_ref *raw;
-+ int ret;
-+ size_t retlen;
-+ int name_len = strlen(fd->name);
-+ uint32_t name_crc = crc32(0, fd->name, name_len);
-+ uint32_t rawlen = ref_totlen(c, jeb, fd->raw);
-+
-+ rd = kmalloc(rawlen, GFP_KERNEL);
-+ if (!rd)
-+ return -ENOMEM;
-+
-+ /* Prevent the erase code from nicking the obsolete node refs while
-+ we're looking at them. I really don't like this extra lock but
-+ can't see any alternative. Suggestions on a postcard to... */
-+ down(&c->erase_free_sem);
-+
-+ for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) {
-+
-+ /* We only care about obsolete ones */
-+ if (!(ref_obsolete(raw)))
-+ continue;
-+
-+ /* Any dirent with the same name is going to have the same length... */
-+ if (ref_totlen(c, NULL, raw) != rawlen)
-+ continue;
-+
-+ /* Doesn't matter if there's one in the same erase block. We're going to
-+ delete it too at the same time. */
-+ if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset))
-+ continue;
-+
-+ D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw)));
-+
-+ /* This is an obsolete node belonging to the same directory, and it's of the right
-+ length. We need to take a closer look...*/
-+ ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)rd);
-+ if (ret) {
-+ printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading obsolete node at %08x\n", ret, ref_offset(raw));
-+ /* If we can't read it, we don't need to continue to obsolete it. Continue */
-+ continue;
-+ }
-+ if (retlen != rawlen) {
-+ printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %u) reading header from obsolete node at %08x\n",
-+ retlen, rawlen, ref_offset(raw));
-+ continue;
-+ }
-+
-+ if (je16_to_cpu(rd->nodetype) != JFFS2_NODETYPE_DIRENT)
-+ continue;
-+
-+ /* If the name CRC doesn't match, skip */
-+ if (je32_to_cpu(rd->name_crc) != name_crc)
-+ continue;
-+
-+ /* If the name length doesn't match, or it's another deletion dirent, skip */
-+ if (rd->nsize != name_len || !je32_to_cpu(rd->ino))
-+ continue;
-+
-+ /* OK, check the actual name now */
-+ if (memcmp(rd->name, fd->name, name_len))
-+ continue;
-+
-+ /* OK. The name really does match. There really is still an older node on
-+ the flash which our deletion dirent obsoletes. So we have to write out
-+ a new deletion dirent to replace it */
-+ up(&c->erase_free_sem);
-+
-+ D1(printk(KERN_DEBUG "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n",
-+ ref_offset(fd->raw), fd->name, ref_offset(raw), je32_to_cpu(rd->ino)));
-+ kfree(rd);
-+
-+ return jffs2_garbage_collect_dirent(c, jeb, f, fd);
-+ }
-+
-+ up(&c->erase_free_sem);
-+ kfree(rd);
-+ }
-+
-+ /* No need for it any more. Just mark it obsolete and remove it from the list */
- while (*fdp) {
- if ((*fdp) == fd) {
- found = 1;
-@@ -400,7 +876,7 @@
- fdp = &(*fdp)->next;
- }
- if (!found) {
-- printk(KERN_WARNING "Deletion dirent \"%s\" not found in list for ino #%lu\n", fd->name, inode->i_ino);
-+ printk(KERN_WARNING "Deletion dirent \"%s\" not found in list for ino #%u\n", fd->name, f->inocache->ino);
- }
- jffs2_mark_node_obsolete(c, fd->raw);
- jffs2_free_full_dirent(fd);
-@@ -408,93 +884,95 @@
- }
-
- static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dnode *fn,
-- __u32 start, __u32 end)
-+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
-+ uint32_t start, uint32_t end)
- {
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_raw_inode ri;
- struct jffs2_node_frag *frag;
- struct jffs2_full_dnode *new_fn;
-- __u32 alloclen, phys_ofs;
-+ uint32_t alloclen, phys_ofs;
- int ret;
-
-- D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%lu from offset 0x%x to 0x%x\n",
-- inode->i_ino, start, end));
-+ D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n",
-+ f->inocache->ino, start, end));
-
- memset(&ri, 0, sizeof(ri));
-
- if(fn->frags > 1) {
- size_t readlen;
-- __u32 crc;
-+ uint32_t crc;
- /* It's partially obsoleted by a later write. So we have to
- write it out again with the _same_ version as before */
-- ret = c->mtd->read(c->mtd, fn->raw->flash_offset & ~3, sizeof(ri), &readlen, (char *)&ri);
-+ ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri);
- if (readlen != sizeof(ri) || ret) {
-- printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %d. Data will be lost by writing new hold node\n", ret, readlen);
-+ printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %zd. Data will be lost by writing new hole node\n", ret, readlen);
- goto fill;
- }
-- if (ri.nodetype != JFFS2_NODETYPE_INODE) {
-+ if (je16_to_cpu(ri.nodetype) != JFFS2_NODETYPE_INODE) {
- printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had node type 0x%04x instead of JFFS2_NODETYPE_INODE(0x%04x)\n",
-- fn->raw->flash_offset & ~3, ri.nodetype, JFFS2_NODETYPE_INODE);
-+ ref_offset(fn->raw),
-+ je16_to_cpu(ri.nodetype), JFFS2_NODETYPE_INODE);
- return -EIO;
- }
-- if (ri.totlen != sizeof(ri)) {
-- printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%x\n",
-- fn->raw->flash_offset & ~3, ri.totlen, sizeof(ri));
-+ if (je32_to_cpu(ri.totlen) != sizeof(ri)) {
-+ printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%zx\n",
-+ ref_offset(fn->raw),
-+ je32_to_cpu(ri.totlen), sizeof(ri));
- return -EIO;
- }
- crc = crc32(0, &ri, sizeof(ri)-8);
-- if (crc != ri.node_crc) {
-+ if (crc != je32_to_cpu(ri.node_crc)) {
- printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n",
-- fn->raw->flash_offset & ~3, ri.node_crc, crc);
-+ ref_offset(fn->raw),
-+ je32_to_cpu(ri.node_crc), crc);
- /* FIXME: We could possibly deal with this by writing new holes for each frag */
-- printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%lu will be lost\n",
-- start, end, inode->i_ino);
-+ printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n",
-+ start, end, f->inocache->ino);
- goto fill;
- }
- if (ri.compr != JFFS2_COMPR_ZERO) {
-- printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", fn->raw->flash_offset & ~3);
-- printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%lu will be lost\n",
-- start, end, inode->i_ino);
-+ printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", ref_offset(fn->raw));
-+ printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n",
-+ start, end, f->inocache->ino);
- goto fill;
- }
- } else {
- fill:
-- ri.magic = JFFS2_MAGIC_BITMASK;
-- ri.nodetype = JFFS2_NODETYPE_INODE;
-- ri.totlen = sizeof(ri);
-- ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4);
-+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-+ ri.totlen = cpu_to_je32(sizeof(ri));
-+ ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
-
-- ri.ino = inode->i_ino;
-- ri.version = ++f->highest_version;
-- ri.offset = start;
-- ri.dsize = end - start;
-- ri.csize = 0;
-+ ri.ino = cpu_to_je32(f->inocache->ino);
-+ ri.version = cpu_to_je32(++f->highest_version);
-+ ri.offset = cpu_to_je32(start);
-+ ri.dsize = cpu_to_je32(end - start);
-+ ri.csize = cpu_to_je32(0);
- ri.compr = JFFS2_COMPR_ZERO;
- }
-- ri.mode = inode->i_mode;
-- ri.uid = inode->i_uid;
-- ri.gid = inode->i_gid;
-- ri.isize = inode->i_size;
-- ri.atime = inode->i_atime;
-- ri.ctime = inode->i_ctime;
-- ri.mtime = inode->i_mtime;
-- ri.data_crc = 0;
-- ri.node_crc = crc32(0, &ri, sizeof(ri)-8);
-+ ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f));
-+ ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
-+ ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
-+ ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
-+ ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f));
-+ ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f));
-+ ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f));
-+ ri.data_crc = cpu_to_je32(0);
-+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
-
- ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen);
- if (ret) {
-- printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_hole failed: %d\n",
-+ printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n",
- sizeof(ri), ret);
- return ret;
- }
-- new_fn = jffs2_write_dnode(inode, &ri, NULL, 0, phys_ofs, NULL);
-+ new_fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_GC);
-
- if (IS_ERR(new_fn)) {
- printk(KERN_WARNING "Error writing new hole node: %ld\n", PTR_ERR(new_fn));
- return PTR_ERR(new_fn);
- }
-- if (ri.version == f->highest_version) {
-+ if (je32_to_cpu(ri.version) == f->highest_version) {
- jffs2_add_full_dnode_to_inode(c, f, new_fn);
- if (f->metadata) {
- jffs2_mark_node_obsolete(c, f->metadata->raw);
-@@ -510,12 +988,17 @@
- * number as before. (Except in case of error -- see 'goto fill;'
- * above.)
- */
-- D1(if(fn->frags <= 1) {
-+ D1(if(unlikely(fn->frags <= 1)) {
- printk(KERN_WARNING "jffs2_garbage_collect_hole: Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d\n",
-- fn->frags, ri.version, f->highest_version, ri.ino);
-+ fn->frags, je32_to_cpu(ri.version), f->highest_version,
-+ je32_to_cpu(ri.ino));
- });
-
-- for (frag = f->fraglist; frag; frag = frag->next) {
-+ /* This is a partially-overlapped hole node. Mark it REF_NORMAL not REF_PRISTINE */
-+ mark_ref_normal(new_fn->raw);
-+
-+ for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs);
-+ frag; frag = frag_next(frag)) {
- if (frag->ofs > fn->size + fn->ofs)
- break;
- if (frag->node == fn) {
-@@ -540,49 +1023,146 @@
- }
-
- static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dnode *fn,
-- __u32 start, __u32 end)
-+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
-+ uint32_t start, uint32_t end)
- {
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_full_dnode *new_fn;
- struct jffs2_raw_inode ri;
-- __u32 alloclen, phys_ofs, offset, orig_end;
-+ uint32_t alloclen, phys_ofs, offset, orig_end, orig_start;
- int ret = 0;
- unsigned char *comprbuf = NULL, *writebuf;
-- struct page *pg;
-+ unsigned long pg;
- unsigned char *pg_ptr;
-
--
- memset(&ri, 0, sizeof(ri));
-
-- D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%lu from offset 0x%x to 0x%x\n",
-- inode->i_ino, start, end));
-+ D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x\n",
-+ f->inocache->ino, start, end));
-
- orig_end = end;
-+ orig_start = start;
-
-+ if (c->nr_free_blocks + c->nr_erasing_blocks > c->resv_blocks_gcmerge) {
-+ /* Attempt to do some merging. But only expand to cover logically
-+ adjacent frags if the block containing them is already considered
-+ to be dirty. Otherwise we end up with GC just going round in
-+ circles dirtying the nodes it already wrote out, especially
-+ on NAND where we have small eraseblocks and hence a much higher
-+ chance of nodes having to be split to cross boundaries. */
-
-- /* If we're looking at the last node in the block we're
-- garbage-collecting, we allow ourselves to merge as if the
-- block was already erasing. We're likely to be GC'ing a
-- partial page, and the next block we GC is likely to have
-- the other half of this page right at the beginning, which
-- means we'd expand it _then_, as nr_erasing_blocks would have
-- increased since we checked, and in doing so would obsolete
-- the partial node which we'd have written here. Meaning that
-- the GC would churn and churn, and just leave dirty blocks in
-- it's wake.
-- */
-- if(c->nr_free_blocks + c->nr_erasing_blocks > JFFS2_RESERVED_BLOCKS_GCMERGE - (fn->raw->next_phys?0:1)) {
-- /* Shitloads of space */
-- /* FIXME: Integrate this properly with GC calculations */
-- start &= ~(PAGE_CACHE_SIZE-1);
-- end = min_t(__u32, start + PAGE_CACHE_SIZE, inode->i_size);
-- D1(printk(KERN_DEBUG "Plenty of free space, so expanding to write from offset 0x%x to 0x%x\n",
-- start, end));
-- if (end < orig_end) {
-- printk(KERN_WARNING "Eep. jffs2_garbage_collect_dnode extended node to write, but it got smaller: start 0x%x, orig_end 0x%x, end 0x%x\n", start, orig_end, end);
-- end = orig_end;
-+ struct jffs2_node_frag *frag;
-+ uint32_t min, max;
-+
-+ min = start & ~(PAGE_CACHE_SIZE-1);
-+ max = min + PAGE_CACHE_SIZE;
-+
-+ frag = jffs2_lookup_node_frag(&f->fragtree, start);
-+
-+ /* BUG_ON(!frag) but that'll happen anyway... */
-+
-+ BUG_ON(frag->ofs != start);
-+
-+ /* First grow down... */
-+ while((frag = frag_prev(frag)) && frag->ofs >= min) {
-+
-+ /* If the previous frag doesn't even reach the beginning, there's
-+ excessive fragmentation. Just merge. */
-+ if (frag->ofs > min) {
-+ D1(printk(KERN_DEBUG "Expanding down to cover partial frag (0x%x-0x%x)\n",
-+ frag->ofs, frag->ofs+frag->size));
-+ start = frag->ofs;
-+ continue;
-+ }
-+ /* OK. This frag holds the first byte of the page. */
-+ if (!frag->node || !frag->node->raw) {
-+ D1(printk(KERN_DEBUG "First frag in page is hole (0x%x-0x%x). Not expanding down.\n",
-+ frag->ofs, frag->ofs+frag->size));
-+ break;
-+ } else {
-+
-+ /* OK, it's a frag which extends to the beginning of the page. Does it live
-+ in a block which is still considered clean? If so, don't obsolete it.
-+ If not, cover it anyway. */
-+
-+ struct jffs2_raw_node_ref *raw = frag->node->raw;
-+ struct jffs2_eraseblock *jeb;
-+
-+ jeb = &c->blocks[raw->flash_offset / c->sector_size];
-+
-+ if (jeb == c->gcblock) {
-+ D1(printk(KERN_DEBUG "Expanding down to cover frag (0x%x-0x%x) in gcblock at %08x\n",
-+ frag->ofs, frag->ofs+frag->size, ref_offset(raw)));
-+ start = frag->ofs;
-+ break;
- }
-+ if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) {
-+ D1(printk(KERN_DEBUG "Not expanding down to cover frag (0x%x-0x%x) in clean block %08x\n",
-+ frag->ofs, frag->ofs+frag->size, jeb->offset));
-+ break;
-+ }
-+
-+ D1(printk(KERN_DEBUG "Expanding down to cover frag (0x%x-0x%x) in dirty block %08x\n",
-+ frag->ofs, frag->ofs+frag->size, jeb->offset));
-+ start = frag->ofs;
-+ break;
-+ }
-+ }
-+
-+ /* ... then up */
-+
-+ /* Find last frag which is actually part of the node we're to GC. */
-+ frag = jffs2_lookup_node_frag(&f->fragtree, end-1);
-+
-+ while((frag = frag_next(frag)) && frag->ofs+frag->size <= max) {
-+
-+ /* If the previous frag doesn't even reach the beginning, there's lots
-+ of fragmentation. Just merge. */
-+ if (frag->ofs+frag->size < max) {
-+ D1(printk(KERN_DEBUG "Expanding up to cover partial frag (0x%x-0x%x)\n",
-+ frag->ofs, frag->ofs+frag->size));
-+ end = frag->ofs + frag->size;
-+ continue;
-+ }
-+
-+ if (!frag->node || !frag->node->raw) {
-+ D1(printk(KERN_DEBUG "Last frag in page is hole (0x%x-0x%x). Not expanding up.\n",
-+ frag->ofs, frag->ofs+frag->size));
-+ break;
-+ } else {
-+
-+ /* OK, it's a frag which extends to the beginning of the page. Does it live
-+ in a block which is still considered clean? If so, don't obsolete it.
-+ If not, cover it anyway. */
-+
-+ struct jffs2_raw_node_ref *raw = frag->node->raw;
-+ struct jffs2_eraseblock *jeb;
-+
-+ jeb = &c->blocks[raw->flash_offset / c->sector_size];
-+
-+ if (jeb == c->gcblock) {
-+ D1(printk(KERN_DEBUG "Expanding up to cover frag (0x%x-0x%x) in gcblock at %08x\n",
-+ frag->ofs, frag->ofs+frag->size, ref_offset(raw)));
-+ end = frag->ofs + frag->size;
-+ break;
-+ }
-+ if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) {
-+ D1(printk(KERN_DEBUG "Not expanding up to cover frag (0x%x-0x%x) in clean block %08x\n",
-+ frag->ofs, frag->ofs+frag->size, jeb->offset));
-+ break;
-+ }
-+
-+ D1(printk(KERN_DEBUG "Expanding up to cover frag (0x%x-0x%x) in dirty block %08x\n",
-+ frag->ofs, frag->ofs+frag->size, jeb->offset));
-+ end = frag->ofs + frag->size;
-+ break;
-+ }
-+ }
-+ D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n",
-+ orig_start, orig_end, start, end));
-+
-+ BUG_ON(end > JFFS2_F_I_SIZE(f));
-+ BUG_ON(end < orig_end);
-+ BUG_ON(start > orig_start);
- }
-
- /* First, use readpage() to read the appropriate page into the page cache */
-@@ -592,63 +1172,58 @@
- * page OK. We'll actually write it out again in commit_write, which is a little
- * suboptimal, but at least we're correct.
- */
-- pg = read_cache_page(inode->i_mapping, start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode);
-+ pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg);
-
-- if (IS_ERR(pg)) {
-- printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg));
-- return PTR_ERR(pg);
-+ if (IS_ERR(pg_ptr)) {
-+ printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg_ptr));
-+ return PTR_ERR(pg_ptr);
- }
-- pg_ptr = (char *)kmap(pg);
-- comprbuf = kmalloc(end - start, GFP_KERNEL);
-
- offset = start;
- while(offset < orig_end) {
-- __u32 datalen;
-- __u32 cdatalen;
-- char comprtype = JFFS2_COMPR_NONE;
-+ uint32_t datalen;
-+ uint32_t cdatalen;
-+ uint16_t comprtype = JFFS2_COMPR_NONE;
-
- ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen);
-
- if (ret) {
-- printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dnode failed: %d\n",
-+ printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n",
- sizeof(ri)+ JFFS2_MIN_DATA_LEN, ret);
- break;
- }
-- cdatalen = min(alloclen - sizeof(ri), end - offset);
-+ cdatalen = min_t(uint32_t, alloclen - sizeof(ri), end - offset);
- datalen = end - offset;
-
- writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1));
-
-- if (comprbuf) {
-- comprtype = jffs2_compress(writebuf, comprbuf, &datalen, &cdatalen);
-- }
-- if (comprtype) {
-- writebuf = comprbuf;
-- } else {
-- datalen = cdatalen;
-- }
-- ri.magic = JFFS2_MAGIC_BITMASK;
-- ri.nodetype = JFFS2_NODETYPE_INODE;
-- ri.totlen = sizeof(ri) + cdatalen;
-- ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4);
-+ comprtype = jffs2_compress(c, f, writebuf, &comprbuf, &datalen, &cdatalen);
-
-- ri.ino = inode->i_ino;
-- ri.version = ++f->highest_version;
-- ri.mode = inode->i_mode;
-- ri.uid = inode->i_uid;
-- ri.gid = inode->i_gid;
-- ri.isize = inode->i_size;
-- ri.atime = inode->i_atime;
-- ri.ctime = inode->i_ctime;
-- ri.mtime = inode->i_mtime;
-- ri.offset = offset;
-- ri.csize = cdatalen;
-- ri.dsize = datalen;
-- ri.compr = comprtype;
-- ri.node_crc = crc32(0, &ri, sizeof(ri)-8);
-- ri.data_crc = crc32(0, writebuf, cdatalen);
-+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-+ ri.totlen = cpu_to_je32(sizeof(ri) + cdatalen);
-+ ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
-
-- new_fn = jffs2_write_dnode(inode, &ri, writebuf, cdatalen, phys_ofs, NULL);
-+ ri.ino = cpu_to_je32(f->inocache->ino);
-+ ri.version = cpu_to_je32(++f->highest_version);
-+ ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f));
-+ ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
-+ ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
-+ ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
-+ ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f));
-+ ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f));
-+ ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f));
-+ ri.offset = cpu_to_je32(offset);
-+ ri.csize = cpu_to_je32(cdatalen);
-+ ri.dsize = cpu_to_je32(datalen);
-+ ri.compr = comprtype & 0xff;
-+ ri.usercompr = (comprtype >> 8) & 0xff;
-+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
-+ ri.data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
-+
-+ new_fn = jffs2_write_dnode(c, f, &ri, comprbuf, cdatalen, phys_ofs, ALLOC_GC);
-+
-+ jffs2_free_comprbuf(comprbuf, writebuf);
-
- if (IS_ERR(new_fn)) {
- printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));
-@@ -663,12 +1238,8 @@
- f->metadata = NULL;
- }
- }
-- if (comprbuf) kfree(comprbuf);
-
-- kunmap(pg);
-- /* XXX: Does the page get freed automatically? */
-- /* AAA: Judging by the unmount getting stuck in __wait_on_page, nope. */
-- page_cache_release(pg);
-+ jffs2_gc_release_page(c, pg_ptr, &pg);
- return ret;
- }
-
---- linux-2.4.21/fs/jffs2/ioctl.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/ioctl.c
-@@ -1,37 +1,13 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: ioctl.c,v 1.5 2001/03/15 15:38:24 dwmw2 Exp $
-+ * $Id: ioctl.c,v 1.9 2004/11/16 20:36:11 dwmw2 Exp $
- *
- */
-
-@@ -42,6 +18,6 @@
- {
- /* Later, this will provide for lsattr.jffs2 and chattr.jffs2, which
- will include compression support etc. */
-- return -EINVAL;
-+ return -ENOTTY;
- }
-
---- linux-2.4.21/fs/jffs2/malloc.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/malloc.c
-@@ -1,37 +1,13 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: malloc.c,v 1.16 2001/03/15 15:38:24 dwmw2 Exp $
-+ * $Id: malloc.c,v 1.28 2004/11/16 20:36:11 dwmw2 Exp $
- *
- */
-
-@@ -47,6 +23,9 @@
- #define JFFS2_SLAB_POISON 0
- #endif
-
-+// replace this by #define D3 (x) x for cache debugging
-+#define D3(x)
-+
- /* These are initialised to NULL in the kernel startup code.
- If you're porting to other operating systems, beware */
- static kmem_cache_t *full_dnode_slab;
-@@ -57,57 +36,47 @@
- static kmem_cache_t *node_frag_slab;
- static kmem_cache_t *inode_cache_slab;
-
--void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn)
--{
-- struct jffs2_tmp_dnode_info *next;
--
-- while (tn) {
-- next = tn;
-- tn = tn->next;
-- jffs2_free_full_dnode(next->fn);
-- jffs2_free_tmp_dnode_info(next);
-- }
--}
--
--void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd)
--{
-- struct jffs2_full_dirent *next;
--
-- while (fd) {
-- next = fd->next;
-- jffs2_free_full_dirent(fd);
-- fd = next;
-- }
--}
--
- int __init jffs2_create_slab_caches(void)
- {
-- full_dnode_slab = kmem_cache_create("jffs2_full_dnode", sizeof(struct jffs2_full_dnode), 0, JFFS2_SLAB_POISON, NULL, NULL);
-+ full_dnode_slab = kmem_cache_create("jffs2_full_dnode",
-+ sizeof(struct jffs2_full_dnode),
-+ 0, JFFS2_SLAB_POISON, NULL, NULL);
- if (!full_dnode_slab)
- goto err;
-
-- raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", sizeof(struct jffs2_raw_dirent), 0, JFFS2_SLAB_POISON, NULL, NULL);
-+ raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent",
-+ sizeof(struct jffs2_raw_dirent),
-+ 0, JFFS2_SLAB_POISON, NULL, NULL);
- if (!raw_dirent_slab)
- goto err;
-
-- raw_inode_slab = kmem_cache_create("jffs2_raw_inode", sizeof(struct jffs2_raw_inode), 0, JFFS2_SLAB_POISON, NULL, NULL);
-+ raw_inode_slab = kmem_cache_create("jffs2_raw_inode",
-+ sizeof(struct jffs2_raw_inode),
-+ 0, JFFS2_SLAB_POISON, NULL, NULL);
- if (!raw_inode_slab)
- goto err;
-
-- tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", sizeof(struct jffs2_tmp_dnode_info), 0, JFFS2_SLAB_POISON, NULL, NULL);
-+ tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode",
-+ sizeof(struct jffs2_tmp_dnode_info),
-+ 0, JFFS2_SLAB_POISON, NULL, NULL);
- if (!tmp_dnode_info_slab)
- goto err;
-
-- raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref", sizeof(struct jffs2_raw_node_ref), 0, JFFS2_SLAB_POISON, NULL, NULL);
-+ raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref",
-+ sizeof(struct jffs2_raw_node_ref),
-+ 0, JFFS2_SLAB_POISON, NULL, NULL);
- if (!raw_node_ref_slab)
- goto err;
-
-- node_frag_slab = kmem_cache_create("jffs2_node_frag", sizeof(struct jffs2_node_frag), 0, JFFS2_SLAB_POISON, NULL, NULL);
-+ node_frag_slab = kmem_cache_create("jffs2_node_frag",
-+ sizeof(struct jffs2_node_frag),
-+ 0, JFFS2_SLAB_POISON, NULL, NULL);
- if (!node_frag_slab)
- goto err;
-
-- inode_cache_slab = kmem_cache_create("jffs2_inode_cache", sizeof(struct jffs2_inode_cache), 0, JFFS2_SLAB_POISON, NULL, NULL);
--
-+ inode_cache_slab = kmem_cache_create("jffs2_inode_cache",
-+ sizeof(struct jffs2_inode_cache),
-+ 0, JFFS2_SLAB_POISON, NULL, NULL);
- if (inode_cache_slab)
- return 0;
- err:
-@@ -131,7 +100,6 @@
- kmem_cache_destroy(node_frag_slab);
- if(inode_cache_slab)
- kmem_cache_destroy(inode_cache_slab);
--
- }
-
- struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize)
-@@ -146,75 +114,92 @@
-
- struct jffs2_full_dnode *jffs2_alloc_full_dnode(void)
- {
-- void *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL);
-+ struct jffs2_full_dnode *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL);
-+ D3 (printk (KERN_DEBUG "alloc_full_dnode at %p\n", ret));
- return ret;
- }
-
- void jffs2_free_full_dnode(struct jffs2_full_dnode *x)
- {
-+ D3 (printk (KERN_DEBUG "free full_dnode at %p\n", x));
- kmem_cache_free(full_dnode_slab, x);
- }
-
- struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void)
- {
-- return kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL);
-+ struct jffs2_raw_dirent *ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL);
-+ D3 (printk (KERN_DEBUG "alloc_raw_dirent\n", ret));
-+ return ret;
- }
-
- void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x)
- {
-+ D3 (printk (KERN_DEBUG "free_raw_dirent at %p\n", x));
- kmem_cache_free(raw_dirent_slab, x);
- }
-
- struct jffs2_raw_inode *jffs2_alloc_raw_inode(void)
- {
-- return kmem_cache_alloc(raw_inode_slab, GFP_KERNEL);
-+ struct jffs2_raw_inode *ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL);
-+ D3 (printk (KERN_DEBUG "alloc_raw_inode at %p\n", ret));
-+ return ret;
- }
-
- void jffs2_free_raw_inode(struct jffs2_raw_inode *x)
- {
-+ D3 (printk (KERN_DEBUG "free_raw_inode at %p\n", x));
- kmem_cache_free(raw_inode_slab, x);
- }
-
- struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void)
- {
-- return kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL);
-+ struct jffs2_tmp_dnode_info *ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL);
-+ D3 (printk (KERN_DEBUG "alloc_tmp_dnode_info at %p\n", ret));
-+ return ret;
- }
-
- void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x)
- {
-+ D3 (printk (KERN_DEBUG "free_tmp_dnode_info at %p\n", x));
- kmem_cache_free(tmp_dnode_info_slab, x);
- }
-
- struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void)
- {
-- return kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL);
-+ struct jffs2_raw_node_ref *ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL);
-+ D3 (printk (KERN_DEBUG "alloc_raw_node_ref at %p\n", ret));
-+ return ret;
- }
-
- void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x)
- {
-+ D3 (printk (KERN_DEBUG "free_raw_node_ref at %p\n", x));
- kmem_cache_free(raw_node_ref_slab, x);
- }
-
- struct jffs2_node_frag *jffs2_alloc_node_frag(void)
- {
-- return kmem_cache_alloc(node_frag_slab, GFP_KERNEL);
-+ struct jffs2_node_frag *ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL);
-+ D3 (printk (KERN_DEBUG "alloc_node_frag at %p\n", ret));
-+ return ret;
- }
-
- void jffs2_free_node_frag(struct jffs2_node_frag *x)
- {
-+ D3 (printk (KERN_DEBUG "free_node_frag at %p\n", x));
- kmem_cache_free(node_frag_slab, x);
- }
-
- struct jffs2_inode_cache *jffs2_alloc_inode_cache(void)
- {
- struct jffs2_inode_cache *ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL);
-- D1(printk(KERN_DEBUG "Allocated inocache at %p\n", ret));
-+ D3 (printk(KERN_DEBUG "Allocated inocache at %p\n", ret));
- return ret;
- }
-
- void jffs2_free_inode_cache(struct jffs2_inode_cache *x)
- {
-- D1(printk(KERN_DEBUG "Freeing inocache at %p\n", x));
-+ D3 (printk(KERN_DEBUG "Freeing inocache at %p\n", x));
- kmem_cache_free(inode_cache_slab, x);
- }
-
---- linux-2.4.21/fs/jffs2/nodelist.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/nodelist.c
-@@ -1,44 +1,24 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001, 2002 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: nodelist.c,v 1.30.2.6 2003/02/24 21:49:33 dwmw2 Exp $
-+ * $Id: nodelist.c,v 1.93 2005/02/27 23:01:32 dwmw2 Exp $
- *
- */
-
- #include <linux/kernel.h>
--#include <linux/jffs2.h>
-+#include <linux/sched.h>
- #include <linux/fs.h>
- #include <linux/mtd/mtd.h>
-+#include <linux/rbtree.h>
-+#include <linux/crc32.h>
-+#include <linux/slab.h>
-+#include <linux/pagemap.h>
- #include "nodelist.h"
-
- void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list)
-@@ -78,7 +58,7 @@
- /* Put a new tmp_dnode_info into the list, keeping the list in
- order of increasing version
- */
--void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list)
-+static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list)
- {
- struct jffs2_tmp_dnode_info **prev = list;
-
-@@ -89,93 +69,156 @@
- *prev = tn;
- }
-
-+static void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn)
-+{
-+ struct jffs2_tmp_dnode_info *next;
-+
-+ while (tn) {
-+ next = tn;
-+ tn = tn->next;
-+ jffs2_free_full_dnode(next->fn);
-+ jffs2_free_tmp_dnode_info(next);
-+ }
-+}
-+
-+static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd)
-+{
-+ struct jffs2_full_dirent *next;
-+
-+ while (fd) {
-+ next = fd->next;
-+ jffs2_free_full_dirent(fd);
-+ fd = next;
-+ }
-+}
-+
-+/* Returns first valid node after 'ref'. May return 'ref' */
-+static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_ref *ref)
-+{
-+ while (ref && ref->next_in_ino) {
-+ if (!ref_obsolete(ref))
-+ return ref;
-+ D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref)));
-+ ref = ref->next_in_ino;
-+ }
-+ return NULL;
-+}
-+
- /* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated
- with this ino, returning the former in order of version */
-
--int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f,
-+int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
- struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
-- __u32 *highest_version, __u32 *latest_mctime,
-- __u32 *mctime_ver)
-+ uint32_t *highest_version, uint32_t *latest_mctime,
-+ uint32_t *mctime_ver)
- {
-- struct jffs2_raw_node_ref *ref = f->inocache->nodes;
-+ struct jffs2_raw_node_ref *ref, *valid_ref;
- struct jffs2_tmp_dnode_info *tn, *ret_tn = NULL;
- struct jffs2_full_dirent *fd, *ret_fd = NULL;
--
- union jffs2_node_union node;
- size_t retlen;
- int err;
-
- *mctime_ver = 0;
-
-- D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%lu\n", ino));
-- if (!f->inocache->nodes) {
-- printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", ino);
-- }
-- for (ref = f->inocache->nodes; ref && ref->next_in_ino; ref = ref->next_in_ino) {
-- /* Work out whether it's a data node or a dirent node */
-- if (ref->flash_offset & 1) {
-- /* FIXME: On NAND flash we may need to read these */
-- D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref->flash_offset &~3));
-- continue;
-- }
-- err = c->mtd->read(c->mtd, (ref->flash_offset & ~3), min(ref->totlen, sizeof(node)), &retlen, (void *)&node);
-+ D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%u\n", f->inocache->ino));
-+
-+ spin_lock(&c->erase_completion_lock);
-+
-+ valid_ref = jffs2_first_valid_node(f->inocache->nodes);
-+
-+ if (!valid_ref && (f->inocache->ino != 1))
-+ printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino);
-+
-+ while (valid_ref) {
-+ /* We can hold a pointer to a non-obsolete node without the spinlock,
-+ but _obsolete_ nodes may disappear at any time, if the block
-+ they're in gets erased. So if we mark 'ref' obsolete while we're
-+ not holding the lock, it can go away immediately. For that reason,
-+ we find the next valid node first, before processing 'ref'.
-+ */
-+ ref = valid_ref;
-+ valid_ref = jffs2_first_valid_node(ref->next_in_ino);
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ cond_resched();
-+
-+ /* FIXME: point() */
-+ err = jffs2_flash_read(c, (ref_offset(ref)),
-+ min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node)),
-+ &retlen, (void *)&node);
- if (err) {
-- printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, (ref->flash_offset) & ~3);
-+ printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref));
- goto free_out;
- }
-
-
- /* Check we've managed to read at least the common node header */
-- if (retlen < min(ref->totlen, sizeof(node.u))) {
-+ if (retlen < min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node.u))) {
- printk(KERN_WARNING "short read in get_inode_nodes()\n");
- err = -EIO;
- goto free_out;
- }
-
-- switch (node.u.nodetype) {
-+ switch (je16_to_cpu(node.u.nodetype)) {
- case JFFS2_NODETYPE_DIRENT:
-- D1(printk(KERN_DEBUG "Node at %08x is a dirent node\n", ref->flash_offset &~3));
-+ D1(printk(KERN_DEBUG "Node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref)));
-+ if (ref_flags(ref) == REF_UNCHECKED) {
-+ printk(KERN_WARNING "BUG: Dirent node at 0x%08x never got checked? How?\n", ref_offset(ref));
-+ BUG();
-+ }
- if (retlen < sizeof(node.d)) {
- printk(KERN_WARNING "short read in get_inode_nodes()\n");
- err = -EIO;
- goto free_out;
- }
-- if (node.d.version > *highest_version)
-- *highest_version = node.d.version;
-- if (ref->flash_offset & 1) {
-- /* Obsoleted */
-+ /* sanity check */
-+ if (PAD((node.d.nsize + sizeof (node.d))) != PAD(je32_to_cpu (node.d.totlen))) {
-+ printk(KERN_NOTICE "jffs2_get_inode_nodes(): Illegal nsize in node at 0x%08x: nsize 0x%02x, totlen %04x\n",
-+ ref_offset(ref), node.d.nsize, je32_to_cpu(node.d.totlen));
-+ jffs2_mark_node_obsolete(c, ref);
-+ spin_lock(&c->erase_completion_lock);
- continue;
- }
-+ if (je32_to_cpu(node.d.version) > *highest_version)
-+ *highest_version = je32_to_cpu(node.d.version);
-+ if (ref_obsolete(ref)) {
-+ /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
-+ printk(KERN_ERR "Dirent node at 0x%08x became obsolete while we weren't looking\n",
-+ ref_offset(ref));
-+ BUG();
-+ }
-+
- fd = jffs2_alloc_full_dirent(node.d.nsize+1);
- if (!fd) {
- err = -ENOMEM;
- goto free_out;
- }
-- memset(fd,0,sizeof(struct jffs2_full_dirent) + node.d.nsize+1);
- fd->raw = ref;
-- fd->version = node.d.version;
-- fd->ino = node.d.ino;
-+ fd->version = je32_to_cpu(node.d.version);
-+ fd->ino = je32_to_cpu(node.d.ino);
- fd->type = node.d.type;
-
- /* Pick out the mctime of the latest dirent */
- if(fd->version > *mctime_ver) {
- *mctime_ver = fd->version;
-- *latest_mctime = node.d.mctime;
-+ *latest_mctime = je32_to_cpu(node.d.mctime);
- }
-
- /* memcpy as much of the name as possible from the raw
- dirent we've already read from the flash
- */
- if (retlen > sizeof(struct jffs2_raw_dirent))
-- memcpy(&fd->name[0], &node.d.name[0], min((__u32)node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent))));
-+ memcpy(&fd->name[0], &node.d.name[0], min_t(uint32_t, node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent))));
-
- /* Do we need to copy any more of the name directly
- from the flash?
- */
- if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) {
-+ /* FIXME: point() */
- int already = retlen - sizeof(struct jffs2_raw_dirent);
-
-- err = c->mtd->read(c->mtd, (ref->flash_offset & ~3) + retlen,
-+ err = jffs2_flash_read(c, (ref_offset(ref)) + retlen,
- node.d.nsize - already, &retlen, &fd->name[already]);
- if (!err && retlen != node.d.nsize - already)
- err = -EIO;
-@@ -188,6 +231,7 @@
- }
- fd->nhash = full_name_hash(fd->name, node.d.nsize);
- fd->next = NULL;
-+ fd->name[node.d.nsize] = '\0';
- /* Wheee. We now have a complete jffs2_full_dirent structure, with
- the name in it and everything. Link it into the list
- */
-@@ -196,21 +240,126 @@
- break;
-
- case JFFS2_NODETYPE_INODE:
-- D1(printk(KERN_DEBUG "Node at %08x is a data node\n", ref->flash_offset &~3));
-+ D1(printk(KERN_DEBUG "Node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref)));
- if (retlen < sizeof(node.i)) {
- printk(KERN_WARNING "read too short for dnode\n");
- err = -EIO;
- goto free_out;
- }
-- if (node.i.version > *highest_version)
-- *highest_version = node.i.version;
-- D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", node.i.version, *highest_version));
-+ if (je32_to_cpu(node.i.version) > *highest_version)
-+ *highest_version = je32_to_cpu(node.i.version);
-+ D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", je32_to_cpu(node.i.version), *highest_version));
-
-- if (ref->flash_offset & 1) {
-- D1(printk(KERN_DEBUG "obsoleted\n"));
-- /* Obsoleted */
-+ if (ref_obsolete(ref)) {
-+ /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
-+ printk(KERN_ERR "Inode node at 0x%08x became obsolete while we weren't looking\n",
-+ ref_offset(ref));
-+ BUG();
-+ }
-+
-+ /* If we've never checked the CRCs on this node, check them now. */
-+ if (ref_flags(ref) == REF_UNCHECKED) {
-+ uint32_t crc, len;
-+ struct jffs2_eraseblock *jeb;
-+
-+ crc = crc32(0, &node, sizeof(node.i)-8);
-+ if (crc != je32_to_cpu(node.i.node_crc)) {
-+ printk(KERN_NOTICE "jffs2_get_inode_nodes(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-+ ref_offset(ref), je32_to_cpu(node.i.node_crc), crc);
-+ jffs2_mark_node_obsolete(c, ref);
-+ spin_lock(&c->erase_completion_lock);
-+ continue;
-+ }
-+
-+ /* sanity checks */
-+ if ( je32_to_cpu(node.i.offset) > je32_to_cpu(node.i.isize) ||
-+ PAD(je32_to_cpu(node.i.csize) + sizeof (node.i)) != PAD(je32_to_cpu(node.i.totlen))) {
-+ printk(KERN_NOTICE "jffs2_get_inode_nodes(): Inode corrupted at 0x%08x, totlen %d, #ino %d, version %d, isize %d, csize %d, dsize %d \n",
-+ ref_offset(ref), je32_to_cpu(node.i.totlen), je32_to_cpu(node.i.ino),
-+ je32_to_cpu(node.i.version), je32_to_cpu(node.i.isize),
-+ je32_to_cpu(node.i.csize), je32_to_cpu(node.i.dsize));
-+ jffs2_mark_node_obsolete(c, ref);
-+ spin_lock(&c->erase_completion_lock);
-+ continue;
-+ }
-+
-+ if (node.i.compr != JFFS2_COMPR_ZERO && je32_to_cpu(node.i.csize)) {
-+ unsigned char *buf=NULL;
-+ uint32_t pointed = 0;
-+#ifndef __ECOS
-+ if (c->mtd->point) {
-+ err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize),
-+ &retlen, &buf);
-+ if (!err && retlen < je32_to_cpu(node.i.csize)) {
-+ D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen));
-+ c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize));
-+ } else if (err){
-+ D1(printk(KERN_DEBUG "MTD point failed %d\n", err));
-+ } else
-+ pointed = 1; /* succefully pointed to device */
-+ }
-+#endif
-+ if(!pointed){
-+ buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL);
-+ if (!buf)
-+ return -ENOMEM;
-+
-+ err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize),
-+ &retlen, buf);
-+ if (!err && retlen != je32_to_cpu(node.i.csize))
-+ err = -EIO;
-+ if (err) {
-+ kfree(buf);
-+ return err;
-+ }
-+ }
-+ crc = crc32(0, buf, je32_to_cpu(node.i.csize));
-+ if(!pointed)
-+ kfree(buf);
-+#ifndef __ECOS
-+ else
-+ c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize));
-+#endif
-+
-+ if (crc != je32_to_cpu(node.i.data_crc)) {
-+ printk(KERN_NOTICE "jffs2_get_inode_nodes(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-+ ref_offset(ref), je32_to_cpu(node.i.data_crc), crc);
-+ jffs2_mark_node_obsolete(c, ref);
-+ spin_lock(&c->erase_completion_lock);
- continue;
- }
-+
-+ }
-+
-+ /* Mark the node as having been checked and fix the accounting accordingly */
-+ spin_lock(&c->erase_completion_lock);
-+ jeb = &c->blocks[ref->flash_offset / c->sector_size];
-+ len = ref_totlen(c, jeb, ref);
-+
-+ jeb->used_size += len;
-+ jeb->unchecked_size -= len;
-+ c->used_size += len;
-+ c->unchecked_size -= len;
-+
-+ /* If node covers at least a whole page, or if it starts at the
-+ beginning of a page and runs to the end of the file, or if
-+ it's a hole node, mark it REF_PRISTINE, else REF_NORMAL.
-+
-+ If it's actually overlapped, it'll get made NORMAL (or OBSOLETE)
-+ when the overlapping node(s) get added to the tree anyway.
-+ */
-+ if ((je32_to_cpu(node.i.dsize) >= PAGE_CACHE_SIZE) ||
-+ ( ((je32_to_cpu(node.i.offset)&(PAGE_CACHE_SIZE-1))==0) &&
-+ (je32_to_cpu(node.i.dsize)+je32_to_cpu(node.i.offset) == je32_to_cpu(node.i.isize)))) {
-+ D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_PRISTINE\n", ref_offset(ref)));
-+ ref->flash_offset = ref_offset(ref) | REF_PRISTINE;
-+ } else {
-+ D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_NORMAL\n", ref_offset(ref)));
-+ ref->flash_offset = ref_offset(ref) | REF_NORMAL;
-+ }
-+ spin_unlock(&c->erase_completion_lock);
-+ }
-+
- tn = jffs2_alloc_tmp_dnode_info();
- if (!tn) {
- D1(printk(KERN_DEBUG "alloc tn failed\n"));
-@@ -225,36 +374,76 @@
- jffs2_free_tmp_dnode_info(tn);
- goto free_out;
- }
-- tn->version = node.i.version;
-- tn->fn->ofs = node.i.offset;
-+ tn->version = je32_to_cpu(node.i.version);
-+ tn->fn->ofs = je32_to_cpu(node.i.offset);
- /* There was a bug where we wrote hole nodes out with
- csize/dsize swapped. Deal with it */
-- if (node.i.compr == JFFS2_COMPR_ZERO && !node.i.dsize && node.i.csize)
-- tn->fn->size = node.i.csize;
-+ if (node.i.compr == JFFS2_COMPR_ZERO && !je32_to_cpu(node.i.dsize) && je32_to_cpu(node.i.csize))
-+ tn->fn->size = je32_to_cpu(node.i.csize);
- else // normal case...
-- tn->fn->size = node.i.dsize;
-+ tn->fn->size = je32_to_cpu(node.i.dsize);
- tn->fn->raw = ref;
-- D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n", ref->flash_offset &~3, node.i.version, node.i.offset, node.i.dsize));
-+ D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n",
-+ ref_offset(ref), je32_to_cpu(node.i.version),
-+ je32_to_cpu(node.i.offset), je32_to_cpu(node.i.dsize)));
- jffs2_add_tn_to_list(tn, &ret_tn);
- break;
-
- default:
-- switch(node.u.nodetype & JFFS2_COMPAT_MASK) {
-+ if (ref_flags(ref) == REF_UNCHECKED) {
-+ struct jffs2_eraseblock *jeb;
-+ uint32_t len;
-+
-+ printk(KERN_ERR "Eep. Unknown node type %04x at %08x was marked REF_UNCHECKED\n",
-+ je16_to_cpu(node.u.nodetype), ref_offset(ref));
-+
-+ /* Mark the node as having been checked and fix the accounting accordingly */
-+ spin_lock(&c->erase_completion_lock);
-+ jeb = &c->blocks[ref->flash_offset / c->sector_size];
-+ len = ref_totlen(c, jeb, ref);
-+
-+ jeb->used_size += len;
-+ jeb->unchecked_size -= len;
-+ c->used_size += len;
-+ c->unchecked_size -= len;
-+
-+ mark_ref_normal(ref);
-+ spin_unlock(&c->erase_completion_lock);
-+ }
-+ node.u.nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(node.u.nodetype));
-+ if (crc32(0, &node, sizeof(struct jffs2_unknown_node)-4) != je32_to_cpu(node.u.hdr_crc)) {
-+ /* Hmmm. This should have been caught at scan time. */
-+ printk(KERN_ERR "Node header CRC failed at %08x. But it must have been OK earlier.\n",
-+ ref_offset(ref));
-+ printk(KERN_ERR "Node was: { %04x, %04x, %08x, %08x }\n",
-+ je16_to_cpu(node.u.magic), je16_to_cpu(node.u.nodetype), je32_to_cpu(node.u.totlen),
-+ je32_to_cpu(node.u.hdr_crc));
-+ jffs2_mark_node_obsolete(c, ref);
-+ } else switch(je16_to_cpu(node.u.nodetype) & JFFS2_COMPAT_MASK) {
- case JFFS2_FEATURE_INCOMPAT:
-- printk(KERN_NOTICE "Unknown INCOMPAT nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3);
-+ printk(KERN_NOTICE "Unknown INCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
-+ /* EEP */
-+ BUG();
- break;
- case JFFS2_FEATURE_ROCOMPAT:
-- printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3);
-+ printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
-+ if (!(c->flags & JFFS2_SB_FLAG_RO))
-+ BUG();
- break;
- case JFFS2_FEATURE_RWCOMPAT_COPY:
-- printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3);
-+ printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
- break;
- case JFFS2_FEATURE_RWCOMPAT_DELETE:
-- printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3);
-+ printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
-+ jffs2_mark_node_obsolete(c, ref);
- break;
- }
-+
- }
-+ spin_lock(&c->erase_completion_lock);
-+
- }
-+ spin_unlock(&c->erase_completion_lock);
- *tnp = ret_tn;
- *fdp = ret_fd;
-
-@@ -266,19 +455,30 @@
- return err;
- }
-
-+void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state)
-+{
-+ spin_lock(&c->inocache_lock);
-+ ic->state = state;
-+ wake_up(&c->inocache_wq);
-+ spin_unlock(&c->inocache_lock);
-+}
-+
-+/* During mount, this needs no locking. During normal operation, its
-+ callers want to do other stuff while still holding the inocache_lock.
-+ Rather than introducing special case get_ino_cache functions or
-+ callbacks, we just let the caller do the locking itself. */
-+
- struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
- {
- struct jffs2_inode_cache *ret;
-
- D2(printk(KERN_DEBUG "jffs2_get_ino_cache(): ino %u\n", ino));
-- spin_lock (&c->inocache_lock);
-+
- ret = c->inocache_list[ino % INOCACHE_HASHSIZE];
- while (ret && ret->ino < ino) {
- ret = ret->next;
- }
-
-- spin_unlock(&c->inocache_lock);
--
- if (ret && ret->ino != ino)
- ret = NULL;
-
-@@ -290,6 +490,8 @@
- {
- struct jffs2_inode_cache **prev;
- D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino));
-+ BUG_ON(!new->ino);
-+
- spin_lock(&c->inocache_lock);
-
- prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE];
-@@ -299,13 +501,14 @@
- }
- new->next = *prev;
- *prev = new;
-+
- spin_unlock(&c->inocache_lock);
- }
-
- void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old)
- {
- struct jffs2_inode_cache **prev;
-- D2(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino));
-+ D1(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino));
- spin_lock(&c->inocache_lock);
-
- prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE];
-@@ -316,6 +519,15 @@
- if ((*prev) == old) {
- *prev = old->next;
- }
-+
-+ /* Free it now unless it's in READING or CLEARING state, which
-+ are the transitions upon read_inode() and clear_inode(). The
-+ rest of the time we know nobody else is looking at it, and
-+ if it's held by read_inode() or clear_inode() they'll free it
-+ for themselves. */
-+ if (old->state != INO_STATE_READING && old->state != INO_STATE_CLEARING)
-+ jffs2_free_inode_cache(old);
-+
- spin_unlock(&c->inocache_lock);
- }
-
-@@ -328,7 +540,6 @@
- this = c->inocache_list[i];
- while (this) {
- next = this->next;
-- D2(printk(KERN_DEBUG "jffs2_free_ino_caches: Freeing ino #%u at %p\n", this->ino, this));
- jffs2_free_inode_cache(this);
- this = next;
- }
-@@ -352,3 +563,128 @@
- }
- }
-
-+struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset)
-+{
-+ /* The common case in lookup is that there will be a node
-+ which precisely matches. So we go looking for that first */
-+ struct rb_node *next;
-+ struct jffs2_node_frag *prev = NULL;
-+ struct jffs2_node_frag *frag = NULL;
-+
-+ D2(printk(KERN_DEBUG "jffs2_lookup_node_frag(%p, %d)\n", fragtree, offset));
-+
-+ next = fragtree->rb_node;
-+
-+ while(next) {
-+ frag = rb_entry(next, struct jffs2_node_frag, rb);
-+
-+ D2(printk(KERN_DEBUG "Considering frag %d-%d (%p). left %p, right %p\n",
-+ frag->ofs, frag->ofs+frag->size, frag, frag->rb.rb_left, frag->rb.rb_right));
-+ if (frag->ofs + frag->size <= offset) {
-+ D2(printk(KERN_DEBUG "Going right from frag %d-%d, before the region we care about\n",
-+ frag->ofs, frag->ofs+frag->size));
-+ /* Remember the closest smaller match on the way down */
-+ if (!prev || frag->ofs > prev->ofs)
-+ prev = frag;
-+ next = frag->rb.rb_right;
-+ } else if (frag->ofs > offset) {
-+ D2(printk(KERN_DEBUG "Going left from frag %d-%d, after the region we care about\n",
-+ frag->ofs, frag->ofs+frag->size));
-+ next = frag->rb.rb_left;
-+ } else {
-+ D2(printk(KERN_DEBUG "Returning frag %d,%d, matched\n",
-+ frag->ofs, frag->ofs+frag->size));
-+ return frag;
-+ }
-+ }
-+
-+ /* Exact match not found. Go back up looking at each parent,
-+ and return the closest smaller one */
-+
-+ if (prev)
-+ D2(printk(KERN_DEBUG "No match. Returning frag %d,%d, closest previous\n",
-+ prev->ofs, prev->ofs+prev->size));
-+ else
-+ D2(printk(KERN_DEBUG "Returning NULL, empty fragtree\n"));
-+
-+ return prev;
-+}
-+
-+/* Pass 'c' argument to indicate that nodes should be marked obsolete as
-+ they're killed. */
-+void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c)
-+{
-+ struct jffs2_node_frag *frag;
-+ struct jffs2_node_frag *parent;
-+
-+ if (!root->rb_node)
-+ return;
-+
-+ frag = (rb_entry(root->rb_node, struct jffs2_node_frag, rb));
-+
-+ while(frag) {
-+ if (frag->rb.rb_left) {
-+ D2(printk(KERN_DEBUG "Going left from frag (%p) %d-%d\n",
-+ frag, frag->ofs, frag->ofs+frag->size));
-+ frag = frag_left(frag);
-+ continue;
-+ }
-+ if (frag->rb.rb_right) {
-+ D2(printk(KERN_DEBUG "Going right from frag (%p) %d-%d\n",
-+ frag, frag->ofs, frag->ofs+frag->size));
-+ frag = frag_right(frag);
-+ continue;
-+ }
-+
-+ D2(printk(KERN_DEBUG "jffs2_kill_fragtree: frag at 0x%x-0x%x: node %p, frags %d--\n",
-+ frag->ofs, frag->ofs+frag->size, frag->node,
-+ frag->node?frag->node->frags:0));
-+
-+ if (frag->node && !(--frag->node->frags)) {
-+ /* Not a hole, and it's the final remaining frag
-+ of this node. Free the node */
-+ if (c)
-+ jffs2_mark_node_obsolete(c, frag->node->raw);
-+
-+ jffs2_free_full_dnode(frag->node);
-+ }
-+ parent = frag_parent(frag);
-+ if (parent) {
-+ if (frag_left(parent) == frag)
-+ parent->rb.rb_left = NULL;
-+ else
-+ parent->rb.rb_right = NULL;
-+ }
-+
-+ jffs2_free_node_frag(frag);
-+ frag = parent;
-+
-+ cond_resched();
-+ }
-+}
-+
-+void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base)
-+{
-+ struct rb_node *parent = &base->rb;
-+ struct rb_node **link = &parent;
-+
-+ D2(printk(KERN_DEBUG "jffs2_fragtree_insert(%p; %d-%d, %p)\n", newfrag,
-+ newfrag->ofs, newfrag->ofs+newfrag->size, base));
-+
-+ while (*link) {
-+ parent = *link;
-+ base = rb_entry(parent, struct jffs2_node_frag, rb);
-+
-+ D2(printk(KERN_DEBUG "fragtree_insert considering frag at 0x%x\n", base->ofs));
-+ if (newfrag->ofs > base->ofs)
-+ link = &base->rb.rb_right;
-+ else if (newfrag->ofs < base->ofs)
-+ link = &base->rb.rb_left;
-+ else {
-+ printk(KERN_CRIT "Duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base);
-+ BUG();
-+ }
-+ }
-+
-+ rb_link_node(&newfrag->rb, &base->rb, link);
-+}
---- linux-2.4.21/fs/jffs2/nodelist.h~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/nodelist.h
-@@ -1,48 +1,35 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: nodelist.h,v 1.46.2.4 2003/02/24 21:49:33 dwmw2 Exp $
-+ * $Id: nodelist.h,v 1.128 2005/02/27 23:01:32 dwmw2 Exp $
- *
- */
-
-+#ifndef __JFFS2_NODELIST_H__
-+#define __JFFS2_NODELIST_H__
-+
- #include <linux/config.h>
- #include <linux/fs.h>
--
-+#include <linux/types.h>
-+#include <linux/jffs2.h>
- #include <linux/jffs2_fs_sb.h>
- #include <linux/jffs2_fs_i.h>
-
-+#ifdef __ECOS
-+#include "os-ecos.h"
-+#else
-+#include <linux/mtd/compatmac.h> /* For min/max in older kernels */
-+#include "os-linux.h"
-+#endif
-+
- #ifndef CONFIG_JFFS2_FS_DEBUG
--#define CONFIG_JFFS2_FS_DEBUG 2
-+#define CONFIG_JFFS2_FS_DEBUG 1
- #endif
-
- #if CONFIG_JFFS2_FS_DEBUG > 0
-@@ -57,6 +44,39 @@
- #define D2(x)
- #endif
-
-+#define JFFS2_NATIVE_ENDIAN
-+
-+/* Note we handle mode bits conversion from JFFS2 (i.e. Linux) to/from
-+ whatever OS we're actually running on here too. */
-+
-+#if defined(JFFS2_NATIVE_ENDIAN)
-+#define cpu_to_je16(x) ((jint16_t){x})
-+#define cpu_to_je32(x) ((jint32_t){x})
-+#define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)})
-+
-+#define je16_to_cpu(x) ((x).v16)
-+#define je32_to_cpu(x) ((x).v32)
-+#define jemode_to_cpu(x) (jffs2_to_os_mode((x).m))
-+#elif defined(JFFS2_BIG_ENDIAN)
-+#define cpu_to_je16(x) ((jint16_t){cpu_to_be16(x)})
-+#define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)})
-+#define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))})
-+
-+#define je16_to_cpu(x) (be16_to_cpu(x.v16))
-+#define je32_to_cpu(x) (be32_to_cpu(x.v32))
-+#define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m)))
-+#elif defined(JFFS2_LITTLE_ENDIAN)
-+#define cpu_to_je16(x) ((jint16_t){cpu_to_le16(x)})
-+#define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)})
-+#define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))})
-+
-+#define je16_to_cpu(x) (le16_to_cpu(x.v16))
-+#define je32_to_cpu(x) (le32_to_cpu(x.v32))
-+#define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m)))
-+#else
-+#error wibble
-+#endif
-+
- /*
- This is all we need to keep in-core for each raw node during normal
- operation. As and when we do read_inode on a particular inode, we can
-@@ -71,27 +91,21 @@
- for this inode instead. The inode_cache will have NULL in the first
- word so you know when you've got there :) */
- struct jffs2_raw_node_ref *next_phys;
-- // __u32 ino;
-- __u32 flash_offset;
-- __u32 totlen;
--// __u16 nodetype;
-+ uint32_t flash_offset;
-+ uint32_t __totlen; /* This may die; use ref_totlen(c, jeb, ) below */
-+};
-
- /* flash_offset & 3 always has to be zero, because nodes are
- always aligned at 4 bytes. So we have a couple of extra bits
-- to play with. So we set the least significant bit to 1 to
-- signify that the node is obsoleted by later nodes.
-- */
--};
--
--/*
-- Used for keeping track of deletion nodes &c, which can only be marked
-- as obsolete when the node which they mark as deleted has actually been
-- removed from the flash.
--*/
--struct jffs2_raw_node_ref_list {
-- struct jffs2_raw_node_ref *rew;
-- struct jffs2_raw_node_ref_list *next;
--};
-+ to play with, which indicate the node's status; see below: */
-+#define REF_UNCHECKED 0 /* We haven't yet checked the CRC or built its inode */
-+#define REF_OBSOLETE 1 /* Obsolete, can be completely ignored */
-+#define REF_PRISTINE 2 /* Completely clean. GC without looking */
-+#define REF_NORMAL 3 /* Possibly overlapped. Read the page and write again on GC */
-+#define ref_flags(ref) ((ref)->flash_offset & 3)
-+#define ref_offset(ref) ((ref)->flash_offset & ~3)
-+#define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE)
-+#define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0)
-
- /* For each inode in the filesystem, we need to keep a record of
- nlink, because it would be a PITA to scan the whole directory tree
-@@ -101,20 +115,30 @@
- a pointer to the first physical node which is part of this inode, too.
- */
- struct jffs2_inode_cache {
-- struct jffs2_scan_info *scan; /* Used during scan to hold
-- temporary lists of nodes, and later must be set to
-+ struct jffs2_full_dirent *scan_dents; /* Used during scan to hold
-+ temporary lists of dirents, and later must be set to
- NULL to mark the end of the raw_node_ref->next_in_ino
- chain. */
- struct jffs2_inode_cache *next;
- struct jffs2_raw_node_ref *nodes;
-- __u32 ino;
-+ uint32_t ino;
- int nlink;
-+ int state;
- };
-
--struct jffs2_scan_info {
-- struct jffs2_full_dirent *dents;
-- struct jffs2_tmp_dnode_info *tmpnodes;
--};
-+/* Inode states for 'state' above. We need the 'GC' state to prevent
-+ someone from doing a read_inode() while we're moving a 'REF_PRISTINE'
-+ node without going through all the iget() nonsense */
-+#define INO_STATE_UNCHECKED 0 /* CRC checks not yet done */
-+#define INO_STATE_CHECKING 1 /* CRC checks in progress */
-+#define INO_STATE_PRESENT 2 /* In core */
-+#define INO_STATE_CHECKEDABSENT 3 /* Checked, cleared again */
-+#define INO_STATE_GC 4 /* GCing a 'pristine' node */
-+#define INO_STATE_READING 5 /* In read_inode() */
-+#define INO_STATE_CLEARING 6 /* In clear_inode() */
-+
-+#define INOCACHE_HASHSIZE 128
-+
- /*
- Larger representation of a raw node, kept in-core only when the
- struct inode for this particular ino is instantiated.
-@@ -123,12 +147,11 @@
- struct jffs2_full_dnode
- {
- struct jffs2_raw_node_ref *raw;
-- __u32 ofs; /* Don't really need this, but optimisation */
-- __u32 size;
-- __u32 frags; /* Number of fragments which currently refer
-+ uint32_t ofs; /* The offset to which the data of this node belongs */
-+ uint32_t size;
-+ uint32_t frags; /* Number of fragments which currently refer
- to this node. When this reaches zero,
-- the node is obsolete.
-- */
-+ the node is obsolete. */
- };
-
- /*
-@@ -140,144 +163,265 @@
- {
- struct jffs2_tmp_dnode_info *next;
- struct jffs2_full_dnode *fn;
-- __u32 version;
-+ uint32_t version;
- };
-
- struct jffs2_full_dirent
- {
- struct jffs2_raw_node_ref *raw;
- struct jffs2_full_dirent *next;
-- __u32 version;
-- __u32 ino; /* == zero for unlink */
-+ uint32_t version;
-+ uint32_t ino; /* == zero for unlink */
- unsigned int nhash;
- unsigned char type;
- unsigned char name[0];
- };
-+
- /*
- Fragments - used to build a map of which raw node to obtain
- data from for each part of the ino
- */
- struct jffs2_node_frag
- {
-- struct jffs2_node_frag *next;
-+ struct rb_node rb;
- struct jffs2_full_dnode *node; /* NULL for holes */
-- __u32 size;
-- __u32 ofs; /* Don't really need this, but optimisation */
-+ uint32_t size;
-+ uint32_t ofs; /* The offset to which this fragment belongs */
- };
-
- struct jffs2_eraseblock
- {
- struct list_head list;
- int bad_count;
-- __u32 offset; /* of this block in the MTD */
-+ uint32_t offset; /* of this block in the MTD */
-
-- __u32 used_size;
-- __u32 dirty_size;
-- __u32 free_size; /* Note that sector_size - free_size
-+ uint32_t unchecked_size;
-+ uint32_t used_size;
-+ uint32_t dirty_size;
-+ uint32_t wasted_size;
-+ uint32_t free_size; /* Note that sector_size - free_size
- is the address of the first free space */
- struct jffs2_raw_node_ref *first_node;
- struct jffs2_raw_node_ref *last_node;
-
- struct jffs2_raw_node_ref *gc_node; /* Next node to be garbage collected */
--
-- /* For deletia. When a dirent node in this eraseblock is
-- deleted by a node elsewhere, that other node can only
-- be marked as obsolete when this block is actually erased.
-- So we keep a list of the nodes to mark as obsolete when
-- the erase is completed.
-- */
-- // MAYBE struct jffs2_raw_node_ref_list *deletia;
- };
-
- #define ACCT_SANITY_CHECK(c, jeb) do { \
-- if (jeb->used_size + jeb->dirty_size + jeb->free_size != c->sector_size) { \
-- printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", jeb->offset); \
-- printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x != total %08x\n", \
-- jeb->free_size, jeb->dirty_size, jeb->used_size, c->sector_size); \
-+ struct jffs2_eraseblock *___j = jeb; \
-+ if ((___j) && ___j->used_size + ___j->dirty_size + ___j->free_size + ___j->wasted_size + ___j->unchecked_size != c->sector_size) { \
-+ printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", ___j->offset); \
-+ printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + wasted %08x + unchecked %08x != total %08x\n", \
-+ ___j->free_size, ___j->dirty_size, ___j->used_size, ___j->wasted_size, ___j->unchecked_size, c->sector_size); \
- BUG(); \
- } \
-- if (c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size != c->flash_size) { \
-+ if (c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size + c->wasted_size + c->unchecked_size != c->flash_size) { \
- printk(KERN_NOTICE "Eeep. Space accounting superblock info is screwed\n"); \
-- printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + erasing %08x + bad %08x != total %08x\n", \
-- c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, c->flash_size); \
-+ printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + erasing %08x + bad %08x + wasted %08x + unchecked %08x != total %08x\n", \
-+ c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, c->wasted_size, c->unchecked_size, c->flash_size); \
- BUG(); \
- } \
- } while(0)
-
-+static inline void paranoia_failed_dump(struct jffs2_eraseblock *jeb)
-+{
-+ struct jffs2_raw_node_ref *ref;
-+ int i=0;
-+
-+ printk(KERN_NOTICE);
-+ for (ref = jeb->first_node; ref; ref = ref->next_phys) {
-+ printk("%08x->", ref_offset(ref));
-+ if (++i == 8) {
-+ i = 0;
-+ printk("\n" KERN_NOTICE);
-+ }
-+ }
-+ printk("\n");
-+}
-+
-+
- #define ACCT_PARANOIA_CHECK(jeb) do { \
-- __u32 my_used_size = 0; \
-+ uint32_t my_used_size = 0; \
-+ uint32_t my_unchecked_size = 0; \
- struct jffs2_raw_node_ref *ref2 = jeb->first_node; \
- while (ref2) { \
-- if (!(ref2->flash_offset & 1)) \
-- my_used_size += ref2->totlen; \
-+ if (unlikely(ref2->flash_offset < jeb->offset || \
-+ ref2->flash_offset > jeb->offset + c->sector_size)) { \
-+ printk(KERN_NOTICE "Node %08x shouldn't be in block at %08x!\n", \
-+ ref_offset(ref2), jeb->offset); \
-+ paranoia_failed_dump(jeb); \
-+ BUG(); \
-+ } \
-+ if (ref_flags(ref2) == REF_UNCHECKED) \
-+ my_unchecked_size += ref_totlen(c, jeb, ref2); \
-+ else if (!ref_obsolete(ref2)) \
-+ my_used_size += ref_totlen(c, jeb, ref2); \
-+ if (unlikely((!ref2->next_phys) != (ref2 == jeb->last_node))) { \
-+ if (!ref2->next_phys) \
-+ printk("ref for node at %p (phys %08x) has next_phys->%p (----), last_node->%p (phys %08x)\n", \
-+ ref2, ref_offset(ref2), ref2->next_phys, \
-+ jeb->last_node, ref_offset(jeb->last_node)); \
-+ else \
-+ printk("ref for node at %p (phys %08x) has next_phys->%p (%08x), last_node->%p (phys %08x)\n", \
-+ ref2, ref_offset(ref2), ref2->next_phys, ref_offset(ref2->next_phys), \
-+ jeb->last_node, ref_offset(jeb->last_node)); \
-+ paranoia_failed_dump(jeb); \
-+ BUG(); \
-+ } \
- ref2 = ref2->next_phys; \
- } \
- if (my_used_size != jeb->used_size) { \
- printk(KERN_NOTICE "Calculated used size %08x != stored used size %08x\n", my_used_size, jeb->used_size); \
- BUG(); \
- } \
-+ if (my_unchecked_size != jeb->unchecked_size) { \
-+ printk(KERN_NOTICE "Calculated unchecked size %08x != stored unchecked size %08x\n", my_unchecked_size, jeb->unchecked_size); \
-+ BUG(); \
-+ } \
- } while(0)
-
-+/* Calculate totlen from surrounding nodes or eraseblock */
-+static inline uint32_t __ref_totlen(struct jffs2_sb_info *c,
-+ struct jffs2_eraseblock *jeb,
-+ struct jffs2_raw_node_ref *ref)
-+{
-+ uint32_t ref_end;
-+
-+ if (ref->next_phys)
-+ ref_end = ref_offset(ref->next_phys);
-+ else {
-+ if (!jeb)
-+ jeb = &c->blocks[ref->flash_offset / c->sector_size];
-+
-+ /* Last node in block. Use free_space */
-+ BUG_ON(ref != jeb->last_node);
-+ ref_end = jeb->offset + c->sector_size - jeb->free_size;
-+ }
-+ return ref_end - ref_offset(ref);
-+}
-+
-+static inline uint32_t ref_totlen(struct jffs2_sb_info *c,
-+ struct jffs2_eraseblock *jeb,
-+ struct jffs2_raw_node_ref *ref)
-+{
-+ uint32_t ret;
-+
-+ D1(if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) {
-+ printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n",
-+ jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref));
-+ BUG();
-+ })
-+
-+#if 1
-+ ret = ref->__totlen;
-+#else
-+ /* This doesn't actually work yet */
-+ ret = __ref_totlen(c, jeb, ref);
-+ if (ret != ref->__totlen) {
-+ printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n",
-+ ref, ref_offset(ref), ref_offset(ref)+ref->__totlen,
-+ ret, ref->__totlen);
-+ if (!jeb)
-+ jeb = &c->blocks[ref->flash_offset / c->sector_size];
-+ paranoia_failed_dump(jeb);
-+ BUG();
-+ }
-+#endif
-+ return ret;
-+}
-+
-+
- #define ALLOC_NORMAL 0 /* Normal allocation */
- #define ALLOC_DELETION 1 /* Deletion node. Best to allow it */
- #define ALLOC_GC 2 /* Space requested for GC. Give it or die */
-+#define ALLOC_NORETRY 3 /* For jffs2_write_dnode: On failure, return -EAGAIN instead of retrying */
-
--#define JFFS2_RESERVED_BLOCKS_BASE 3 /* Number of free blocks there must be before we... */
--#define JFFS2_RESERVED_BLOCKS_WRITE (JFFS2_RESERVED_BLOCKS_BASE + 2) /* ... allow a normal filesystem write */
--#define JFFS2_RESERVED_BLOCKS_DELETION (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... allow a normal filesystem deletion */
--#define JFFS2_RESERVED_BLOCKS_GCTRIGGER (JFFS2_RESERVED_BLOCKS_BASE + 3) /* ... wake up the GC thread */
--#define JFFS2_RESERVED_BLOCKS_GCBAD (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... pick a block from the bad_list to GC */
--#define JFFS2_RESERVED_BLOCKS_GCMERGE (JFFS2_RESERVED_BLOCKS_BASE) /* ... merge pages when garbage collecting */
-+/* How much dirty space before it goes on the very_dirty_list */
-+#define VERYDIRTY(c, size) ((size) >= ((c)->sector_size / 2))
-
-+/* check if dirty space is more than 255 Byte */
-+#define ISDIRTY(size) ((size) > sizeof (struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN)
-
- #define PAD(x) (((x)+3)&~3)
-
--static inline int jffs2_raw_ref_to_inum(struct jffs2_raw_node_ref *raw)
-+static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_node_ref *raw)
- {
- while(raw->next_in_ino) {
- raw = raw->next_in_ino;
- }
-
-- return ((struct jffs2_inode_cache *)raw)->ino;
-+ return ((struct jffs2_inode_cache *)raw);
- }
-
-+static inline struct jffs2_node_frag *frag_first(struct rb_root *root)
-+{
-+ struct rb_node *node = root->rb_node;
-+
-+ if (!node)
-+ return NULL;
-+ while(node->rb_left)
-+ node = node->rb_left;
-+ return rb_entry(node, struct jffs2_node_frag, rb);
-+}
-+#define rb_parent(rb) ((rb)->rb_parent)
-+#define frag_next(frag) rb_entry(rb_next(&(frag)->rb), struct jffs2_node_frag, rb)
-+#define frag_prev(frag) rb_entry(rb_prev(&(frag)->rb), struct jffs2_node_frag, rb)
-+#define frag_parent(frag) rb_entry(rb_parent(&(frag)->rb), struct jffs2_node_frag, rb)
-+#define frag_left(frag) rb_entry((frag)->rb.rb_left, struct jffs2_node_frag, rb)
-+#define frag_right(frag) rb_entry((frag)->rb.rb_right, struct jffs2_node_frag, rb)
-+#define frag_erase(frag, list) rb_erase(&frag->rb, list);
-+
- /* nodelist.c */
--D1(void jffs2_print_frag_list(struct jffs2_inode_info *f));
-+D2(void jffs2_print_frag_list(struct jffs2_inode_info *f));
- void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list);
--void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list);
--int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f,
-+int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
- struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
-- __u32 *highest_version, __u32 *latest_mctime,
-- __u32 *mctime_ver);
-+ uint32_t *highest_version, uint32_t *latest_mctime,
-+ uint32_t *mctime_ver);
-+void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state);
- struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino);
- void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new);
- void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old);
- void jffs2_free_ino_caches(struct jffs2_sb_info *c);
- void jffs2_free_raw_node_refs(struct jffs2_sb_info *c);
-+struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset);
-+void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c_delete);
-+void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base);
-+struct rb_node *rb_next(struct rb_node *);
-+struct rb_node *rb_prev(struct rb_node *);
-+void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root);
-
- /* nodemgmt.c */
--int jffs2_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len, int prio);
--int jffs2_reserve_space_gc(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len);
--int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, __u32 len, int dirty);
-+int jffs2_thread_should_wake(struct jffs2_sb_info *c);
-+int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio);
-+int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len);
-+int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new);
- void jffs2_complete_reservation(struct jffs2_sb_info *c);
- void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw);
-+void jffs2_dump_block_lists(struct jffs2_sb_info *c);
-
- /* write.c */
--struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri);
--struct jffs2_full_dnode *jffs2_write_dnode(struct inode *inode, struct jffs2_raw_inode *ri, const unsigned char *data, __u32 datalen, __u32 flash_ofs, __u32 *writelen);
--struct jffs2_full_dirent *jffs2_write_dirent(struct inode *inode, struct jffs2_raw_dirent *rd, const unsigned char *name, __u32 namelen, __u32 flash_ofs, __u32 *writelen);
-+int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri);
-+
-+struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode);
-+struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, int alloc_mode);
-+int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-+ struct jffs2_raw_inode *ri, unsigned char *buf,
-+ uint32_t offset, uint32_t writelen, uint32_t *retlen);
-+int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const char *name, int namelen);
-+int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, const char *name, int namelen, struct jffs2_inode_info *dead_f);
-+int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen);
-+
-
- /* readinode.c */
--void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct jffs2_node_frag **list, __u32 size);
--int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_frag **list, struct jffs2_full_dnode *fn);
-+void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size);
- int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn);
--void jffs2_read_inode (struct inode *);
--void jffs2_clear_inode (struct inode *);
-+int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-+ uint32_t ino, struct jffs2_raw_inode *latest_node);
-+int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
-+void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
-
- /* malloc.c */
--void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn);
--void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd);
--
- int jffs2_create_slab_caches(void);
- void jffs2_destroy_slab_caches(void);
-
-@@ -301,54 +445,31 @@
- /* gc.c */
- int jffs2_garbage_collect_pass(struct jffs2_sb_info *c);
-
--/* background.c */
--int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c);
--void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c);
--void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c);
--
--/* dir.c */
--extern struct file_operations jffs2_dir_operations;
--extern struct inode_operations jffs2_dir_inode_operations;
--
--/* file.c */
--extern struct file_operations jffs2_file_operations;
--extern struct inode_operations jffs2_file_inode_operations;
--extern struct address_space_operations jffs2_file_address_operations;
--int jffs2_null_fsync(struct file *, struct dentry *, int);
--int jffs2_setattr (struct dentry *dentry, struct iattr *iattr);
--int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg);
--int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg);
--int jffs2_readpage (struct file *, struct page *);
--int jffs2_prepare_write (struct file *, struct page *, unsigned, unsigned);
--int jffs2_commit_write (struct file *, struct page *, unsigned, unsigned);
--
--/* ioctl.c */
--int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
--
- /* read.c */
--int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len);
--
--/* compr.c */
--unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 *datalen, __u32 *cdatalen);
--int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in,
-- unsigned char *data_out, __u32 cdatalen, __u32 datalen);
-+int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-+ struct jffs2_full_dnode *fd, unsigned char *buf,
-+ int ofs, int len);
-+int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-+ unsigned char *buf, uint32_t offset, uint32_t len);
-+char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
-
- /* scan.c */
- int jffs2_scan_medium(struct jffs2_sb_info *c);
-+void jffs2_rotate_lists(struct jffs2_sb_info *c);
-
- /* build.c */
--int jffs2_build_filesystem(struct jffs2_sb_info *c);
--
--/* symlink.c */
--extern struct inode_operations jffs2_symlink_inode_operations;
-+int jffs2_do_mount_fs(struct jffs2_sb_info *c);
-
- /* erase.c */
- void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
--void jffs2_erase_pending_blocks(struct jffs2_sb_info *c);
--void jffs2_mark_erased_blocks(struct jffs2_sb_info *c);
--void jffs2_erase_pending_trigger(struct jffs2_sb_info *c);
-+void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count);
-
--/* compr_zlib.c */
--int jffs2_zlib_init(void);
--void jffs2_zlib_exit(void);
-+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
-+/* wbuf.c */
-+int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
-+int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
-+int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-+int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-+#endif
-+
-+#endif /* __JFFS2_NODELIST_H__ */
---- linux-2.4.21/fs/jffs2/nodemgmt.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/nodemgmt.c
-@@ -1,45 +1,21 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: nodemgmt.c,v 1.45.2.1 2002/02/23 14:13:34 dwmw2 Exp $
-+ * $Id: nodemgmt.c,v 1.119 2005/02/28 08:21:05 dedekind Exp $
- *
- */
-
- #include <linux/kernel.h>
- #include <linux/slab.h>
--#include <linux/jffs2.h>
- #include <linux/mtd/mtd.h>
--#include <linux/interrupt.h>
-+#include <linux/compiler.h>
-+#include <linux/sched.h> /* For cond_resched() */
- #include "nodelist.h"
-
- /**
-@@ -62,53 +38,95 @@
- * for the requested allocation.
- */
-
--static int jffs2_do_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len);
-+static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len);
-
--int jffs2_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len, int prio)
-+int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio)
- {
- int ret = -EAGAIN;
-- int blocksneeded = JFFS2_RESERVED_BLOCKS_WRITE;
-+ int blocksneeded = c->resv_blocks_write;
- /* align it */
- minsize = PAD(minsize);
-
-- if (prio == ALLOC_DELETION)
-- blocksneeded = JFFS2_RESERVED_BLOCKS_DELETION;
--
- D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize));
- down(&c->alloc_sem);
-
- D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n"));
-
-- spin_lock_bh(&c->erase_completion_lock);
-+ spin_lock(&c->erase_completion_lock);
-
-- /* this needs a little more thought */
-+ /* this needs a little more thought (true <tglx> :)) */
- while(ret == -EAGAIN) {
- while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) {
- int ret;
-+ uint32_t dirty, avail;
-+
-+ /* calculate real dirty size
-+ * dirty_size contains blocks on erase_pending_list
-+ * those blocks are counted in c->nr_erasing_blocks.
-+ * If one block is actually erased, it is not longer counted as dirty_space
-+ * but it is counted in c->nr_erasing_blocks, so we add it and subtract it
-+ * with c->nr_erasing_blocks * c->sector_size again.
-+ * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks
-+ * This helps us to force gc and pick eventually a clean block to spread the load.
-+ * We add unchecked_size here, as we hopefully will find some space to use.
-+ * This will affect the sum only once, as gc first finishes checking
-+ * of nodes.
-+ */
-+ dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size;
-+ if (dirty < c->nospc_dirty_size) {
-+ if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
-+ printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n");
-+ break;
-+ }
-+ D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n",
-+ dirty, c->unchecked_size, c->sector_size));
-+
-+ spin_unlock(&c->erase_completion_lock);
-+ up(&c->alloc_sem);
-+ return -ENOSPC;
-+ }
-+
-+ /* Calc possibly available space. Possibly available means that we
-+ * don't know, if unchecked size contains obsoleted nodes, which could give us some
-+ * more usable space. This will affect the sum only once, as gc first finishes checking
-+ * of nodes.
-+ + Return -ENOSPC, if the maximum possibly available space is less or equal than
-+ * blocksneeded * sector_size.
-+ * This blocks endless gc looping on a filesystem, which is nearly full, even if
-+ * the check above passes.
-+ */
-+ avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size;
-+ if ( (avail / c->sector_size) <= blocksneeded) {
-+ if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
-+ printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n");
-+ break;
-+ }
-
-+ D1(printk(KERN_DEBUG "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n",
-+ avail, blocksneeded * c->sector_size));
-+ spin_unlock(&c->erase_completion_lock);
- up(&c->alloc_sem);
-- if (c->dirty_size < c->sector_size) {
-- D1(printk(KERN_DEBUG "Short on space, but total dirty size 0x%08x < sector size 0x%08x, so -ENOSPC\n", c->dirty_size, c->sector_size));
-- spin_unlock_bh(&c->erase_completion_lock);
- return -ENOSPC;
- }
-- D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n",
-- c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size,
-- c->free_size + c->dirty_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size));
-- spin_unlock_bh(&c->erase_completion_lock);
-+
-+ up(&c->alloc_sem);
-+
-+ D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n",
-+ c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size,
-+ c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size));
-+ spin_unlock(&c->erase_completion_lock);
-
- ret = jffs2_garbage_collect_pass(c);
- if (ret)
- return ret;
-
-- if (current->need_resched)
-- schedule();
-+ cond_resched();
-
- if (signal_pending(current))
- return -EINTR;
-
- down(&c->alloc_sem);
-- spin_lock_bh(&c->erase_completion_lock);
-+ spin_lock(&c->erase_completion_lock);
- }
-
- ret = jffs2_do_reserve_space(c, minsize, ofs, len);
-@@ -116,45 +134,72 @@
- D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret));
- }
- }
-- spin_unlock_bh(&c->erase_completion_lock);
-+ spin_unlock(&c->erase_completion_lock);
- if (ret)
- up(&c->alloc_sem);
- return ret;
- }
-
--int jffs2_reserve_space_gc(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len)
-+int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len)
- {
- int ret = -EAGAIN;
- minsize = PAD(minsize);
-
- D1(printk(KERN_DEBUG "jffs2_reserve_space_gc(): Requested 0x%x bytes\n", minsize));
-
-- spin_lock_bh(&c->erase_completion_lock);
-+ spin_lock(&c->erase_completion_lock);
- while(ret == -EAGAIN) {
- ret = jffs2_do_reserve_space(c, minsize, ofs, len);
- if (ret) {
- D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret));
- }
- }
-- spin_unlock_bh(&c->erase_completion_lock);
-+ spin_unlock(&c->erase_completion_lock);
- return ret;
- }
-
- /* Called with alloc sem _and_ erase_completion_lock */
--static int jffs2_do_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len)
-+static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len)
- {
- struct jffs2_eraseblock *jeb = c->nextblock;
-
- restart:
- if (jeb && minsize > jeb->free_size) {
- /* Skip the end of this block and file it as having some dirty space */
-- c->dirty_size += jeb->free_size;
-+ /* If there's a pending write to it, flush now */
-+ if (jffs2_wbuf_dirty(c)) {
-+ spin_unlock(&c->erase_completion_lock);
-+ D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
-+ jffs2_flush_wbuf_pad(c);
-+ spin_lock(&c->erase_completion_lock);
-+ jeb = c->nextblock;
-+ goto restart;
-+ }
-+ c->wasted_size += jeb->free_size;
- c->free_size -= jeb->free_size;
-- jeb->dirty_size += jeb->free_size;
-+ jeb->wasted_size += jeb->free_size;
- jeb->free_size = 0;
-+
-+ /* Check, if we have a dirty block now, or if it was dirty already */
-+ if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) {
-+ c->dirty_size += jeb->wasted_size;
-+ c->wasted_size -= jeb->wasted_size;
-+ jeb->dirty_size += jeb->wasted_size;
-+ jeb->wasted_size = 0;
-+ if (VERYDIRTY(c, jeb->dirty_size)) {
-+ D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
-+ jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
-+ list_add_tail(&jeb->list, &c->very_dirty_list);
-+ } else {
- D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
- jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
- list_add_tail(&jeb->list, &c->dirty_list);
-+ }
-+ } else {
-+ D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
-+ jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
-+ list_add_tail(&jeb->list, &c->clean_list);
-+ }
- c->nextblock = jeb = NULL;
- }
-
-@@ -164,33 +209,44 @@
-
- if (list_empty(&c->free_list)) {
-
-- DECLARE_WAITQUEUE(wait, current);
-+ if (!c->nr_erasing_blocks &&
-+ !list_empty(&c->erasable_list)) {
-+ struct jffs2_eraseblock *ejeb;
-+
-+ ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list);
-+ list_del(&ejeb->list);
-+ list_add_tail(&ejeb->list, &c->erase_pending_list);
-+ c->nr_erasing_blocks++;
-+ jffs2_erase_pending_trigger(c);
-+ D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Triggering erase of erasable block at 0x%08x\n",
-+ ejeb->offset));
-+ }
-+
-+ if (!c->nr_erasing_blocks &&
-+ !list_empty(&c->erasable_pending_wbuf_list)) {
-+ D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
-+ /* c->nextblock is NULL, no update to c->nextblock allowed */
-+ spin_unlock(&c->erase_completion_lock);
-+ jffs2_flush_wbuf_pad(c);
-+ spin_lock(&c->erase_completion_lock);
-+ /* Have another go. It'll be on the erasable_list now */
-+ return -EAGAIN;
-+ }
-
- if (!c->nr_erasing_blocks) {
--// if (list_empty(&c->erasing_list) && list_empty(&c->erase_pending_list) && list_empty(c->erase_complete_list)) {
- /* Ouch. We're in GC, or we wouldn't have got here.
- And there's no space left. At all. */
-- printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasingempty: %s, erasependingempty: %s)\n",
-- c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
-+ printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n",
-+ c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no",
-+ list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
- return -ENOSPC;
- }
-- /* Make sure this can't deadlock. Someone has to start the erases
-- of erase_pending blocks */
-- set_current_state(TASK_INTERRUPTIBLE);
-- add_wait_queue(&c->erase_wait, &wait);
-- D1(printk(KERN_DEBUG "Waiting for erases to complete. erasing_blocks is %d. (erasingempty: %s, erasependingempty: %s)\n",
-- c->nr_erasing_blocks, list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no"));
-- if (!list_empty(&c->erase_pending_list)) {
-- D1(printk(KERN_DEBUG "Triggering pending erases\n"));
-- jffs2_erase_pending_trigger(c);
-- }
-- spin_unlock_bh(&c->erase_completion_lock);
-- schedule();
-- remove_wait_queue(&c->erase_wait, &wait);
-- spin_lock_bh(&c->erase_completion_lock);
-- if (signal_pending(current)) {
-- return -EINTR;
-- }
-+
-+ spin_unlock(&c->erase_completion_lock);
-+ /* Don't wait for it; just erase one right now */
-+ jffs2_erase_pending_blocks(c, 1);
-+ spin_lock(&c->erase_completion_lock);
-+
- /* An erase may have failed, decreasing the
- amount of free space available. So we must
- restart from the beginning */
-@@ -201,7 +257,8 @@
- list_del(next);
- c->nextblock = jeb = list_entry(next, struct jffs2_eraseblock, list);
- c->nr_free_blocks--;
-- if (jeb->free_size != c->sector_size - sizeof(struct jffs2_unknown_node)) {
-+
-+ if (jeb->free_size != c->sector_size - c->cleanmarker_size) {
- printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
- goto restart;
- }
-@@ -210,6 +267,20 @@
- enough space */
- *ofs = jeb->offset + (c->sector_size - jeb->free_size);
- *len = jeb->free_size;
-+
-+ if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size &&
-+ !jeb->first_node->next_in_ino) {
-+ /* Only node in it beforehand was a CLEANMARKER node (we think).
-+ So mark it obsolete now that there's going to be another node
-+ in the block. This will reduce used_size to zero but We've
-+ already set c->nextblock so that jffs2_mark_node_obsolete()
-+ won't try to refile it to the dirty_list.
-+ */
-+ spin_unlock(&c->erase_completion_lock);
-+ jffs2_mark_node_obsolete(c, jeb->first_node);
-+ spin_lock(&c->erase_completion_lock);
-+ }
-+
- D1(printk(KERN_DEBUG "jffs2_do_reserve_space(): Giving 0x%x bytes at 0x%x\n", *len, *ofs));
- return 0;
- }
-@@ -217,9 +288,9 @@
- /**
- * jffs2_add_physical_node_ref - add a physical node reference to the list
- * @c: superblock info
-- * @ofs: physical location of this physical node
-+ * @new: new node reference to add
- * @len: length of this physical node
-- * @ino: inode number with which this physical node is associated
-+ * @dirty: dirty flag for new node
- *
- * Should only be used to report nodes for which space has been allocated
- * by jffs2_reserve_space.
-@@ -227,47 +298,61 @@
- * Must be called with the alloc_sem held.
- */
-
--int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, __u32 len, int dirty)
-+int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new)
- {
- struct jffs2_eraseblock *jeb;
-+ uint32_t len;
-
-- len = PAD(len);
-- jeb = &c->blocks[(new->flash_offset & ~3) / c->sector_size];
-- D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x, size 0x%x\n", new->flash_offset & ~3, len));
-+ jeb = &c->blocks[new->flash_offset / c->sector_size];
-+ len = ref_totlen(c, jeb, new);
-+
-+ D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len));
- #if 1
-- if (jeb != c->nextblock || (new->flash_offset & ~3) != jeb->offset + (c->sector_size - jeb->free_size)) {
-+ /* we could get some obsolete nodes after nextblock was refiled
-+ in wbuf.c */
-+ if ((c->nextblock || !ref_obsolete(new))
-+ &&(jeb != c->nextblock || ref_offset(new) != jeb->offset + (c->sector_size - jeb->free_size))) {
- printk(KERN_WARNING "argh. node added in wrong place\n");
- jffs2_free_raw_node_ref(new);
- return -EINVAL;
- }
- #endif
-+ spin_lock(&c->erase_completion_lock);
-+
- if (!jeb->first_node)
- jeb->first_node = new;
- if (jeb->last_node)
- jeb->last_node->next_phys = new;
- jeb->last_node = new;
-
-- spin_lock_bh(&c->erase_completion_lock);
- jeb->free_size -= len;
- c->free_size -= len;
-- if (dirty) {
-- new->flash_offset |= 1;
-+ if (ref_obsolete(new)) {
- jeb->dirty_size += len;
- c->dirty_size += len;
- } else {
- jeb->used_size += len;
- c->used_size += len;
- }
-- spin_unlock_bh(&c->erase_completion_lock);
-- if (!jeb->free_size && !jeb->dirty_size) {
-+
-+ if (!jeb->free_size && !jeb->dirty_size && !ISDIRTY(jeb->wasted_size)) {
- /* If it lives on the dirty_list, jffs2_reserve_space will put it there */
- D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
- jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
-+ if (jffs2_wbuf_dirty(c)) {
-+ /* Flush the last write in the block if it's outstanding */
-+ spin_unlock(&c->erase_completion_lock);
-+ jffs2_flush_wbuf_pad(c);
-+ spin_lock(&c->erase_completion_lock);
-+ }
-+
- list_add_tail(&jeb->list, &c->clean_list);
- c->nextblock = NULL;
- }
- ACCT_SANITY_CHECK(c,jeb);
-- ACCT_PARANOIA_CHECK(jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+
-+ spin_unlock(&c->erase_completion_lock);
-
- return 0;
- }
-@@ -280,20 +365,34 @@
- up(&c->alloc_sem);
- }
-
-+static inline int on_list(struct list_head *obj, struct list_head *head)
-+{
-+ struct list_head *this;
-+
-+ list_for_each(this, head) {
-+ if (this == obj) {
-+ D1(printk("%p is on list at %p\n", obj, head));
-+ return 1;
-+
-+ }
-+ }
-+ return 0;
-+}
-+
- void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref)
- {
- struct jffs2_eraseblock *jeb;
- int blocknr;
- struct jffs2_unknown_node n;
-- int ret;
-- ssize_t retlen;
-+ int ret, addedsize;
-+ size_t retlen;
-
- if(!ref) {
- printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n");
- return;
- }
-- if (ref->flash_offset & 1) {
-- D1(printk(KERN_DEBUG "jffs2_mark_node_obsolete called with already obsolete node at 0x%08x\n", ref->flash_offset &~3));
-+ if (ref_obsolete(ref)) {
-+ D1(printk(KERN_DEBUG "jffs2_mark_node_obsolete called with already obsolete node at 0x%08x\n", ref_offset(ref)));
- return;
- }
- blocknr = ref->flash_offset / c->sector_size;
-@@ -302,91 +401,439 @@
- BUG();
- }
- jeb = &c->blocks[blocknr];
-- if (jeb->used_size < ref->totlen) {
-+
-+ if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) &&
-+ !(c->flags & (JFFS2_SB_FLAG_SCANNING | JFFS2_SB_FLAG_BUILDING))) {
-+ /* Hm. This may confuse static lock analysis. If any of the above
-+ three conditions is false, we're going to return from this
-+ function without actually obliterating any nodes or freeing
-+ any jffs2_raw_node_refs. So we don't need to stop erases from
-+ happening, or protect against people holding an obsolete
-+ jffs2_raw_node_ref without the erase_completion_lock. */
-+ down(&c->erase_free_sem);
-+ }
-+
-+ spin_lock(&c->erase_completion_lock);
-+
-+ if (ref_flags(ref) == REF_UNCHECKED) {
-+ D1(if (unlikely(jeb->unchecked_size < ref_totlen(c, jeb, ref))) {
-+ printk(KERN_NOTICE "raw unchecked node of size 0x%08x freed from erase block %d at 0x%08x, but unchecked_size was already 0x%08x\n",
-+ ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size);
-+ BUG();
-+ })
-+ D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref)));
-+ jeb->unchecked_size -= ref_totlen(c, jeb, ref);
-+ c->unchecked_size -= ref_totlen(c, jeb, ref);
-+ } else {
-+ D1(if (unlikely(jeb->used_size < ref_totlen(c, jeb, ref))) {
- printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n",
-- ref->totlen, blocknr, ref->flash_offset, jeb->used_size);
-+ ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size);
- BUG();
-+ })
-+ D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref)));
-+ jeb->used_size -= ref_totlen(c, jeb, ref);
-+ c->used_size -= ref_totlen(c, jeb, ref);
- }
-
-- spin_lock_bh(&c->erase_completion_lock);
-- jeb->used_size -= ref->totlen;
-- jeb->dirty_size += ref->totlen;
-- c->used_size -= ref->totlen;
-- c->dirty_size += ref->totlen;
-- ref->flash_offset |= 1;
-+ // Take care, that wasted size is taken into concern
-+ if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref_totlen(c, jeb, ref))) && jeb != c->nextblock) {
-+ D1(printk("Dirtying\n"));
-+ addedsize = ref_totlen(c, jeb, ref);
-+ jeb->dirty_size += ref_totlen(c, jeb, ref);
-+ c->dirty_size += ref_totlen(c, jeb, ref);
-+
-+ /* Convert wasted space to dirty, if not a bad block */
-+ if (jeb->wasted_size) {
-+ if (on_list(&jeb->list, &c->bad_used_list)) {
-+ D1(printk(KERN_DEBUG "Leaving block at %08x on the bad_used_list\n",
-+ jeb->offset));
-+ addedsize = 0; /* To fool the refiling code later */
-+ } else {
-+ D1(printk(KERN_DEBUG "Converting %d bytes of wasted space to dirty in block at %08x\n",
-+ jeb->wasted_size, jeb->offset));
-+ addedsize += jeb->wasted_size;
-+ jeb->dirty_size += jeb->wasted_size;
-+ c->dirty_size += jeb->wasted_size;
-+ c->wasted_size -= jeb->wasted_size;
-+ jeb->wasted_size = 0;
-+ }
-+ }
-+ } else {
-+ D1(printk("Wasting\n"));
-+ addedsize = 0;
-+ jeb->wasted_size += ref_totlen(c, jeb, ref);
-+ c->wasted_size += ref_totlen(c, jeb, ref);
-+ }
-+ ref->flash_offset = ref_offset(ref) | REF_OBSOLETE;
-
- ACCT_SANITY_CHECK(c, jeb);
-
-- ACCT_PARANOIA_CHECK(jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-
-- if (c->flags & JFFS2_SB_FLAG_MOUNTING) {
-- /* Mount in progress. Don't muck about with the block
-+ if (c->flags & JFFS2_SB_FLAG_SCANNING) {
-+ /* Flash scanning is in progress. Don't muck about with the block
- lists because they're not ready yet, and don't actually
- obliterate nodes that look obsolete. If they weren't
- marked obsolete on the flash at the time they _became_
- obsolete, there was probably a reason for that. */
-- spin_unlock_bh(&c->erase_completion_lock);
-+ spin_unlock(&c->erase_completion_lock);
-+ /* We didn't lock the erase_free_sem */
- return;
- }
-+
- if (jeb == c->nextblock) {
- D2(printk(KERN_DEBUG "Not moving nextblock 0x%08x to dirty/erase_pending list\n", jeb->offset));
-- } else if (jeb == c->gcblock) {
-- D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty/erase_pending list\n", jeb->offset));
--#if 0 /* We no longer do this here. It can screw the wear levelling. If you have a lot of static
-- data and a few blocks free, and you just create new files and keep deleting/overwriting
-- them, then you'd keep erasing and reusing those blocks without ever moving stuff around.
-- So we leave completely obsoleted blocks on the dirty_list and let the GC delete them
-- when it finds them there. That way, we still get the 'once in a while, take a clean block'
-- to spread out the flash usage */
-- } else if (!jeb->used_size) {
-+ } else if (!jeb->used_size && !jeb->unchecked_size) {
-+ if (jeb == c->gcblock) {
-+ D1(printk(KERN_DEBUG "gcblock at 0x%08x completely dirtied. Clearing gcblock...\n", jeb->offset));
-+ c->gcblock = NULL;
-+ } else {
- D1(printk(KERN_DEBUG "Eraseblock at 0x%08x completely dirtied. Removing from (dirty?) list...\n", jeb->offset));
- list_del(&jeb->list);
-+ }
-+ if (jffs2_wbuf_dirty(c)) {
-+ D1(printk(KERN_DEBUG "...and adding to erasable_pending_wbuf_list\n"));
-+ list_add_tail(&jeb->list, &c->erasable_pending_wbuf_list);
-+ } else {
-+ if (jiffies & 127) {
-+ /* Most of the time, we just erase it immediately. Otherwise we
-+ spend ages scanning it on mount, etc. */
- D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n"));
- list_add_tail(&jeb->list, &c->erase_pending_list);
- c->nr_erasing_blocks++;
- jffs2_erase_pending_trigger(c);
-- // OFNI_BS_2SFFJ(c)->s_dirt = 1;
-+ } else {
-+ /* Sometimes, however, we leave it elsewhere so it doesn't get
-+ immediately reused, and we spread the load a bit. */
-+ D1(printk(KERN_DEBUG "...and adding to erasable_list\n"));
-+ list_add_tail(&jeb->list, &c->erasable_list);
-+ }
-+ }
- D1(printk(KERN_DEBUG "Done OK\n"));
--#endif
-- } else if (jeb->dirty_size == ref->totlen) {
-+ } else if (jeb == c->gcblock) {
-+ D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty_list\n", jeb->offset));
-+ } else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - addedsize)) {
- D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n", jeb->offset));
- list_del(&jeb->list);
- D1(printk(KERN_DEBUG "...and adding to dirty_list\n"));
- list_add_tail(&jeb->list, &c->dirty_list);
-+ } else if (VERYDIRTY(c, jeb->dirty_size) &&
-+ !VERYDIRTY(c, jeb->dirty_size - addedsize)) {
-+ D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is now very dirty. Removing from dirty list...\n", jeb->offset));
-+ list_del(&jeb->list);
-+ D1(printk(KERN_DEBUG "...and adding to very_dirty_list\n"));
-+ list_add_tail(&jeb->list, &c->very_dirty_list);
-+ } else {
-+ D1(printk(KERN_DEBUG "Eraseblock at 0x%08x not moved anywhere. (free 0x%08x, dirty 0x%08x, used 0x%08x)\n",
-+ jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
- }
-- spin_unlock_bh(&c->erase_completion_lock);
-
-- if (c->mtd->type != MTD_NORFLASH && c->mtd->type != MTD_RAM)
-- return;
-- if (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c) ||
-+ (c->flags & JFFS2_SB_FLAG_BUILDING)) {
-+ /* We didn't lock the erase_free_sem */
- return;
-+ }
-
-- D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref->flash_offset &~3));
-- ret = c->mtd->read(c->mtd, ref->flash_offset &~3, sizeof(n), &retlen, (char *)&n);
-+ /* The erase_free_sem is locked, and has been since before we marked the node obsolete
-+ and potentially put its eraseblock onto the erase_pending_list. Thus, we know that
-+ the block hasn't _already_ been erased, and that 'ref' itself hasn't been freed yet
-+ by jffs2_free_all_node_refs() in erase.c. Which is nice. */
-+
-+ D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref_offset(ref)));
-+ ret = jffs2_flash_read(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n);
- if (ret) {
-- printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, ret);
-- return;
-+ printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret);
-+ goto out_erase_sem;
- }
- if (retlen != sizeof(n)) {
-- printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, retlen);
-- return;
-+ printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen);
-+ goto out_erase_sem;
- }
-- if (PAD(n.totlen) != PAD(ref->totlen)) {
-- printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen in node ref (0x%08x)\n", n.totlen, ref->totlen);
-- return;
-+ if (PAD(je32_to_cpu(n.totlen)) != PAD(ref_totlen(c, jeb, ref))) {
-+ printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), ref_totlen(c, jeb, ref));
-+ goto out_erase_sem;
- }
-- if (!(n.nodetype & JFFS2_NODE_ACCURATE)) {
-- D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x\n", ref->flash_offset &~3, n.nodetype));
-- return;
-+ if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) {
-+ D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x)\n", ref_offset(ref), je16_to_cpu(n.nodetype)));
-+ goto out_erase_sem;
- }
-- n.nodetype &= ~JFFS2_NODE_ACCURATE;
-- ret = c->mtd->write(c->mtd, ref->flash_offset&~3, sizeof(n), &retlen, (char *)&n);
-+ /* XXX FIXME: This is ugly now */
-+ n.nodetype = cpu_to_je16(je16_to_cpu(n.nodetype) & ~JFFS2_NODE_ACCURATE);
-+ ret = jffs2_flash_write(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n);
- if (ret) {
-- printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, ret);
-- return;
-+ printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret);
-+ goto out_erase_sem;
- }
- if (retlen != sizeof(n)) {
-- printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, retlen);
-- return;
-+ printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen);
-+ goto out_erase_sem;
-+ }
-+
-+ /* Nodes which have been marked obsolete no longer need to be
-+ associated with any inode. Remove them from the per-inode list.
-+
-+ Note we can't do this for NAND at the moment because we need
-+ obsolete dirent nodes to stay on the lists, because of the
-+ horridness in jffs2_garbage_collect_deletion_dirent(). Also
-+ because we delete the inocache, and on NAND we need that to
-+ stay around until all the nodes are actually erased, in order
-+ to stop us from giving the same inode number to another newly
-+ created inode. */
-+ if (ref->next_in_ino) {
-+ struct jffs2_inode_cache *ic;
-+ struct jffs2_raw_node_ref **p;
-+
-+ spin_lock(&c->erase_completion_lock);
-+
-+ ic = jffs2_raw_ref_to_ic(ref);
-+ for (p = &ic->nodes; (*p) != ref; p = &((*p)->next_in_ino))
-+ ;
-+
-+ *p = ref->next_in_ino;
-+ ref->next_in_ino = NULL;
-+
-+ if (ic->nodes == (void *)ic)
-+ jffs2_del_ino_cache(c, ic);
-+
-+ spin_unlock(&c->erase_completion_lock);
- }
-+
-+
-+ /* Merge with the next node in the physical list, if there is one
-+ and if it's also obsolete and if it doesn't belong to any inode */
-+ if (ref->next_phys && ref_obsolete(ref->next_phys) &&
-+ !ref->next_phys->next_in_ino) {
-+ struct jffs2_raw_node_ref *n = ref->next_phys;
-+
-+ spin_lock(&c->erase_completion_lock);
-+
-+ ref->__totlen += n->__totlen;
-+ ref->next_phys = n->next_phys;
-+ if (jeb->last_node == n) jeb->last_node = ref;
-+ if (jeb->gc_node == n) {
-+ /* gc will be happy continuing gc on this node */
-+ jeb->gc_node=ref;
-+ }
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ jffs2_free_raw_node_ref(n);
-+ }
-+
-+ /* Also merge with the previous node in the list, if there is one
-+ and that one is obsolete */
-+ if (ref != jeb->first_node ) {
-+ struct jffs2_raw_node_ref *p = jeb->first_node;
-+
-+ spin_lock(&c->erase_completion_lock);
-+
-+ while (p->next_phys != ref)
-+ p = p->next_phys;
-+
-+ if (ref_obsolete(p) && !ref->next_in_ino) {
-+ p->__totlen += ref->__totlen;
-+ if (jeb->last_node == ref) {
-+ jeb->last_node = p;
-+ }
-+ if (jeb->gc_node == ref) {
-+ /* gc will be happy continuing gc on this node */
-+ jeb->gc_node=p;
-+ }
-+ p->next_phys = ref->next_phys;
-+ jffs2_free_raw_node_ref(ref);
-+ }
-+ spin_unlock(&c->erase_completion_lock);
-+ }
-+ out_erase_sem:
-+ up(&c->erase_free_sem);
-+}
-+
-+#if CONFIG_JFFS2_FS_DEBUG >= 2
-+void jffs2_dump_block_lists(struct jffs2_sb_info *c)
-+{
-+
-+
-+ printk(KERN_DEBUG "jffs2_dump_block_lists:\n");
-+ printk(KERN_DEBUG "flash_size: %08x\n", c->flash_size);
-+ printk(KERN_DEBUG "used_size: %08x\n", c->used_size);
-+ printk(KERN_DEBUG "dirty_size: %08x\n", c->dirty_size);
-+ printk(KERN_DEBUG "wasted_size: %08x\n", c->wasted_size);
-+ printk(KERN_DEBUG "unchecked_size: %08x\n", c->unchecked_size);
-+ printk(KERN_DEBUG "free_size: %08x\n", c->free_size);
-+ printk(KERN_DEBUG "erasing_size: %08x\n", c->erasing_size);
-+ printk(KERN_DEBUG "bad_size: %08x\n", c->bad_size);
-+ printk(KERN_DEBUG "sector_size: %08x\n", c->sector_size);
-+ printk(KERN_DEBUG "jffs2_reserved_blocks size: %08x\n",c->sector_size * c->resv_blocks_write);
-+
-+ if (c->nextblock) {
-+ printk(KERN_DEBUG "nextblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->unchecked_size, c->nextblock->free_size);
-+ } else {
-+ printk(KERN_DEBUG "nextblock: NULL\n");
-+ }
-+ if (c->gcblock) {
-+ printk(KERN_DEBUG "gcblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size, c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size);
-+ } else {
-+ printk(KERN_DEBUG "gcblock: NULL\n");
-+ }
-+ if (list_empty(&c->clean_list)) {
-+ printk(KERN_DEBUG "clean_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+ int numblocks = 0;
-+ uint32_t dirty = 0;
-+
-+ list_for_each(this, &c->clean_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ numblocks ++;
-+ dirty += jeb->wasted_size;
-+ printk(KERN_DEBUG "clean_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ printk (KERN_DEBUG "Contains %d blocks with total wasted size %u, average wasted size: %u\n", numblocks, dirty, dirty / numblocks);
-+ }
-+ if (list_empty(&c->very_dirty_list)) {
-+ printk(KERN_DEBUG "very_dirty_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+ int numblocks = 0;
-+ uint32_t dirty = 0;
-+
-+ list_for_each(this, &c->very_dirty_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ numblocks ++;
-+ dirty += jeb->dirty_size;
-+ printk(KERN_DEBUG "very_dirty_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
-+ numblocks, dirty, dirty / numblocks);
-+ }
-+ if (list_empty(&c->dirty_list)) {
-+ printk(KERN_DEBUG "dirty_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+ int numblocks = 0;
-+ uint32_t dirty = 0;
-+
-+ list_for_each(this, &c->dirty_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ numblocks ++;
-+ dirty += jeb->dirty_size;
-+ printk(KERN_DEBUG "dirty_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
-+ numblocks, dirty, dirty / numblocks);
-+ }
-+ if (list_empty(&c->erasable_list)) {
-+ printk(KERN_DEBUG "erasable_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+
-+ list_for_each(this, &c->erasable_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ printk(KERN_DEBUG "erasable_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ }
-+ if (list_empty(&c->erasing_list)) {
-+ printk(KERN_DEBUG "erasing_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+
-+ list_for_each(this, &c->erasing_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ printk(KERN_DEBUG "erasing_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ }
-+ if (list_empty(&c->erase_pending_list)) {
-+ printk(KERN_DEBUG "erase_pending_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+
-+ list_for_each(this, &c->erase_pending_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ printk(KERN_DEBUG "erase_pending_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ }
-+ if (list_empty(&c->erasable_pending_wbuf_list)) {
-+ printk(KERN_DEBUG "erasable_pending_wbuf_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+
-+ list_for_each(this, &c->erasable_pending_wbuf_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ printk(KERN_DEBUG "erasable_pending_wbuf_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ }
-+ if (list_empty(&c->free_list)) {
-+ printk(KERN_DEBUG "free_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+
-+ list_for_each(this, &c->free_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ printk(KERN_DEBUG "free_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ }
-+ if (list_empty(&c->bad_list)) {
-+ printk(KERN_DEBUG "bad_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+
-+ list_for_each(this, &c->bad_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ printk(KERN_DEBUG "bad_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ }
-+ if (list_empty(&c->bad_used_list)) {
-+ printk(KERN_DEBUG "bad_used_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+
-+ list_for_each(this, &c->bad_used_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ printk(KERN_DEBUG "bad_used_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ }
-+}
-+#endif /* CONFIG_JFFS2_FS_DEBUG */
-+
-+int jffs2_thread_should_wake(struct jffs2_sb_info *c)
-+{
-+ int ret = 0;
-+ uint32_t dirty;
-+
-+ if (c->unchecked_size) {
-+ D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n",
-+ c->unchecked_size, c->checked_ino));
-+ return 1;
-+ }
-+
-+ /* dirty_size contains blocks on erase_pending_list
-+ * those blocks are counted in c->nr_erasing_blocks.
-+ * If one block is actually erased, it is not longer counted as dirty_space
-+ * but it is counted in c->nr_erasing_blocks, so we add it and subtract it
-+ * with c->nr_erasing_blocks * c->sector_size again.
-+ * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks
-+ * This helps us to force gc and pick eventually a clean block to spread the load.
-+ */
-+ dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size;
-+
-+ if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger &&
-+ (dirty > c->nospc_dirty_size))
-+ ret = 1;
-+
-+ D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n",
-+ c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no"));
-+
-+ return ret;
- }
---- /dev/null
-+++ linux-2.4.21/fs/jffs2/os-linux.h
-@@ -0,0 +1,227 @@
-+/*
-+ * JFFS2 -- Journalling Flash File System, Version 2.
-+ *
-+ * Copyright (C) 2002-2003 Red Hat, Inc.
-+ *
-+ * Created by David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * For licensing information, see the file 'LICENCE' in this directory.
-+ *
-+ * $Id: os-linux.h,v 1.54 2005/02/09 09:23:53 pavlov Exp $
-+ *
-+ */
-+
-+#ifndef __JFFS2_OS_LINUX_H__
-+#define __JFFS2_OS_LINUX_H__
-+#include <linux/version.h>
-+
-+/* JFFS2 uses Linux mode bits natively -- no need for conversion */
-+#define os_to_jffs2_mode(x) (x)
-+#define jffs2_to_os_mode(x) (x)
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,73)
-+#define kstatfs statfs
-+#endif
-+
-+struct kstatfs;
-+struct kvec;
-+
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
-+#define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode))
-+#define OFNI_EDONI_2SFFJ(f) (&(f)->vfs_inode)
-+#define JFFS2_SB_INFO(sb) (sb->s_fs_info)
-+#define OFNI_BS_2SFFJ(c) ((struct super_block *)c->os_priv)
-+#elif defined(JFFS2_OUT_OF_KERNEL)
-+#define JFFS2_INODE_INFO(i) ((struct jffs2_inode_info *) &(i)->u)
-+#define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) )
-+#define JFFS2_SB_INFO(sb) ((struct jffs2_sb_info *) &(sb)->u)
-+#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) )
-+#else
-+#define JFFS2_INODE_INFO(i) (&i->u.jffs2_i)
-+#define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) )
-+#define JFFS2_SB_INFO(sb) (&sb->u.jffs2_sb)
-+#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) )
-+#endif
-+
-+
-+#define JFFS2_F_I_SIZE(f) (OFNI_EDONI_2SFFJ(f)->i_size)
-+#define JFFS2_F_I_MODE(f) (OFNI_EDONI_2SFFJ(f)->i_mode)
-+#define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid)
-+#define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid)
-+
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,1)
-+#define JFFS2_F_I_RDEV_MIN(f) (iminor(OFNI_EDONI_2SFFJ(f)))
-+#define JFFS2_F_I_RDEV_MAJ(f) (imajor(OFNI_EDONI_2SFFJ(f)))
-+#else
-+#define JFFS2_F_I_RDEV_MIN(f) (MINOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev)))
-+#define JFFS2_F_I_RDEV_MAJ(f) (MAJOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev)))
-+#endif
-+
-+/* Urgh. The things we do to keep the 2.4 build working */
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,47)
-+#define ITIME(sec) ((struct timespec){sec, 0})
-+#define I_SEC(tv) ((tv).tv_sec)
-+#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime.tv_sec)
-+#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime.tv_sec)
-+#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime.tv_sec)
-+#else
-+#define ITIME(x) (x)
-+#define I_SEC(x) (x)
-+#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime)
-+#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime)
-+#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime)
-+#endif
-+
-+#define sleep_on_spinunlock(wq, s) \
-+ do { \
-+ DECLARE_WAITQUEUE(__wait, current); \
-+ add_wait_queue((wq), &__wait); \
-+ set_current_state(TASK_UNINTERRUPTIBLE); \
-+ spin_unlock(s); \
-+ schedule(); \
-+ remove_wait_queue((wq), &__wait); \
-+ } while(0)
-+
-+static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
-+{
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
-+ f->highest_version = 0;
-+ f->fragtree = RB_ROOT;
-+ f->metadata = NULL;
-+ f->dents = NULL;
-+ f->flags = 0;
-+ f->usercompr = 0;
-+#else
-+ memset(f, 0, sizeof(*f));
-+ init_MUTEX_LOCKED(&f->sem);
-+#endif
-+}
-+
-+
-+#define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
-+#define jffs2_is_writebuffered(c) (c->wbuf != NULL)
-+
-+#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
-+#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) )
-+#define jffs2_can_mark_obsolete(c) (1)
-+#define jffs2_cleanmarker_oob(c) (0)
-+#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
-+
-+#define jffs2_flash_write(c, ofs, len, retlen, buf) ((c)->mtd->write((c)->mtd, ofs, len, retlen, buf))
-+#define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf))
-+#define jffs2_flush_wbuf_pad(c) ({ (void)(c), 0; })
-+#define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 0; })
-+#define jffs2_write_nand_badblock(c,jeb,bad_offset) (1)
-+#define jffs2_nand_flash_setup(c) (0)
-+#define jffs2_nand_flash_cleanup(c) do {} while(0)
-+#define jffs2_wbuf_dirty(c) (0)
-+#define jffs2_flash_writev(a,b,c,d,e,f) jffs2_flash_direct_writev(a,b,c,d,e)
-+#define jffs2_wbuf_timeout NULL
-+#define jffs2_wbuf_process NULL
-+#define jffs2_nor_ecc(c) (0)
-+#define jffs2_dataflash(c) (0)
-+#define jffs2_nor_ecc_flash_setup(c) (0)
-+#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0)
-+
-+#else /* NAND and/or ECC'd NOR support present */
-+
-+#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size )
-+#define jffs2_can_mark_obsolete(c) ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & MTD_ECC)) || c->mtd->type == MTD_RAM)
-+#define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH)
-+
-+#define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf))
-+#define jffs2_flash_read_oob(c, ofs, len, retlen, buf) ((c)->mtd->read_oob((c)->mtd, ofs, len, retlen, buf))
-+#define jffs2_wbuf_dirty(c) (!!(c)->wbuf_len)
-+
-+/* wbuf.c */
-+int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino);
-+int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf);
-+int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf);
-+int jffs2_check_oob_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,int mode);
-+int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-+int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-+int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
-+void jffs2_wbuf_timeout(unsigned long data);
-+void jffs2_wbuf_process(void *data);
-+int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
-+int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
-+int jffs2_nand_flash_setup(struct jffs2_sb_info *c);
-+void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c);
-+
-+#define jffs2_nor_ecc(c) (c->mtd->type == MTD_NORFLASH && (c->mtd->flags & MTD_ECC))
-+int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c);
-+void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c);
-+
-+#define jffs2_dataflash(c) (c->mtd->type == MTD_DATAFLASH)
-+int jffs2_dataflash_setup(struct jffs2_sb_info *c);
-+void jffs2_dataflash_cleanup(struct jffs2_sb_info *c);
-+
-+#endif /* WRITEBUFFER */
-+
-+/* erase.c */
-+static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
-+{
-+ OFNI_BS_2SFFJ(c)->s_dirt = 1;
-+}
-+
-+/* background.c */
-+int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c);
-+void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c);
-+void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c);
-+
-+/* dir.c */
-+extern struct file_operations jffs2_dir_operations;
-+extern struct inode_operations jffs2_dir_inode_operations;
-+
-+/* file.c */
-+extern struct file_operations jffs2_file_operations;
-+extern struct inode_operations jffs2_file_inode_operations;
-+extern struct address_space_operations jffs2_file_address_operations;
-+int jffs2_fsync(struct file *, struct dentry *, int);
-+int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg);
-+int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg);
-+int jffs2_readpage (struct file *, struct page *);
-+int jffs2_prepare_write (struct file *, struct page *, unsigned, unsigned);
-+int jffs2_commit_write (struct file *, struct page *, unsigned, unsigned);
-+
-+/* ioctl.c */
-+int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
-+
-+/* symlink.c */
-+extern struct inode_operations jffs2_symlink_inode_operations;
-+
-+/* fs.c */
-+int jffs2_setattr (struct dentry *, struct iattr *);
-+void jffs2_read_inode (struct inode *);
-+void jffs2_clear_inode (struct inode *);
-+void jffs2_dirty_inode(struct inode *inode);
-+struct inode *jffs2_new_inode (struct inode *dir_i, int mode,
-+ struct jffs2_raw_inode *ri);
-+int jffs2_statfs (struct super_block *, struct kstatfs *);
-+void jffs2_write_super (struct super_block *);
-+int jffs2_remount_fs (struct super_block *, int *, char *);
-+int jffs2_do_fill_super(struct super_block *sb, void *data, int silent);
-+void jffs2_gc_release_inode(struct jffs2_sb_info *c,
-+ struct jffs2_inode_info *f);
-+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
-+ int inum, int nlink);
-+
-+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
-+ struct jffs2_inode_info *f,
-+ unsigned long offset,
-+ unsigned long *priv);
-+void jffs2_gc_release_page(struct jffs2_sb_info *c,
-+ unsigned char *pg,
-+ unsigned long *priv);
-+int jffs2_flash_setup(struct jffs2_sb_info *c);
-+void jffs2_flash_cleanup(struct jffs2_sb_info *c);
-+
-+
-+/* writev.c */
-+int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs,
-+ unsigned long count, loff_t to, size_t *retlen);
-+
-+
-+#endif /* __JFFS2_OS_LINUX_H__ */
-+
-+
---- linux-2.4.21/fs/jffs2/pushpull.h~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/pushpull.h
-@@ -1,42 +1,21 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001, 2002 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: pushpull.h,v 1.5 2001/09/23 10:04:15 rmk Exp $
-+ * $Id: pushpull.h,v 1.10 2004/11/16 20:36:11 dwmw2 Exp $
- *
- */
-
- #ifndef __PUSHPULL_H__
- #define __PUSHPULL_H__
-+
-+#include <linux/errno.h>
-+
- struct pushpull {
- unsigned char *buf;
- unsigned int buflen;
-@@ -44,9 +23,36 @@
- unsigned int reserve;
- };
-
--void init_pushpull(struct pushpull *, char *, unsigned, unsigned, unsigned);
--int pushbit(struct pushpull *pp, int bit, int use_reserved);
--int pushedbits(struct pushpull *pp);
-+
-+static inline void init_pushpull(struct pushpull *pp, char *buf, unsigned buflen, unsigned ofs, unsigned reserve)
-+{
-+ pp->buf = buf;
-+ pp->buflen = buflen;
-+ pp->ofs = ofs;
-+ pp->reserve = reserve;
-+}
-+
-+static inline int pushbit(struct pushpull *pp, int bit, int use_reserved)
-+{
-+ if (pp->ofs >= pp->buflen - (use_reserved?0:pp->reserve)) {
-+ return -ENOSPC;
-+ }
-+
-+ if (bit) {
-+ pp->buf[pp->ofs >> 3] |= (1<<(7-(pp->ofs &7)));
-+ }
-+ else {
-+ pp->buf[pp->ofs >> 3] &= ~(1<<(7-(pp->ofs &7)));
-+ }
-+ pp->ofs++;
-+
-+ return 0;
-+}
-+
-+static inline int pushedbits(struct pushpull *pp)
-+{
-+ return pp->ofs;
-+}
-
- static inline int pullbit(struct pushpull *pp)
- {
---- /dev/null
-+++ linux-2.4.21/fs/jffs2/rbtree.c
-@@ -0,0 +1,363 @@
-+/*
-+ Red Black Trees
-+ (C) 1999 Andrea Arcangeli <andrea@suse.de>
-+ (C) 2002 David Woodhouse <dwmw2@infradead.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 2 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+
-+ $Id: rbtree.c,v 1.3 2003/10/16 08:02:19 dwmw2 Exp $
-+*/
-+
-+#ifdef __ECOS /* This file is _not_ under the eCos licence; it is pure GPL. */
-+#error "Licence problem. eCos has its own rbtree code."
-+#endif
-+
-+#include <linux/version.h>
-+#include <linux/rbtree.h>
-+
-+/* This wasn't present till 2.4.11, wasn't exported till 2.4.19 */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,11) || \
-+ (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19) && defined(MODULE))
-+static void __rb_rotate_left(struct rb_node * node, struct rb_root * root)
-+{
-+ struct rb_node * right = node->rb_right;
-+
-+ if ((node->rb_right = right->rb_left))
-+ right->rb_left->rb_parent = node;
-+ right->rb_left = node;
-+
-+ if ((right->rb_parent = node->rb_parent))
-+ {
-+ if (node == node->rb_parent->rb_left)
-+ node->rb_parent->rb_left = right;
-+ else
-+ node->rb_parent->rb_right = right;
-+ }
-+ else
-+ root->rb_node = right;
-+ node->rb_parent = right;
-+}
-+
-+static void __rb_rotate_right(struct rb_node * node, struct rb_root * root)
-+{
-+ struct rb_node * left = node->rb_left;
-+
-+ if ((node->rb_left = left->rb_right))
-+ left->rb_right->rb_parent = node;
-+ left->rb_right = node;
-+
-+ if ((left->rb_parent = node->rb_parent))
-+ {
-+ if (node == node->rb_parent->rb_right)
-+ node->rb_parent->rb_right = left;
-+ else
-+ node->rb_parent->rb_left = left;
-+ }
-+ else
-+ root->rb_node = left;
-+ node->rb_parent = left;
-+}
-+
-+void rb_insert_color(struct rb_node * node, struct rb_root * root)
-+{
-+ struct rb_node * parent, * gparent;
-+
-+ while ((parent = node->rb_parent) && parent->rb_color == RB_RED)
-+ {
-+ gparent = parent->rb_parent;
-+
-+ if (parent == gparent->rb_left)
-+ {
-+ {
-+ register struct rb_node * uncle = gparent->rb_right;
-+ if (uncle && uncle->rb_color == RB_RED)
-+ {
-+ uncle->rb_color = RB_BLACK;
-+ parent->rb_color = RB_BLACK;
-+ gparent->rb_color = RB_RED;
-+ node = gparent;
-+ continue;
-+ }
-+ }
-+
-+ if (parent->rb_right == node)
-+ {
-+ register struct rb_node * tmp;
-+ __rb_rotate_left(parent, root);
-+ tmp = parent;
-+ parent = node;
-+ node = tmp;
-+ }
-+
-+ parent->rb_color = RB_BLACK;
-+ gparent->rb_color = RB_RED;
-+ __rb_rotate_right(gparent, root);
-+ } else {
-+ {
-+ register struct rb_node * uncle = gparent->rb_left;
-+ if (uncle && uncle->rb_color == RB_RED)
-+ {
-+ uncle->rb_color = RB_BLACK;
-+ parent->rb_color = RB_BLACK;
-+ gparent->rb_color = RB_RED;
-+ node = gparent;
-+ continue;
-+ }
-+ }
-+
-+ if (parent->rb_left == node)
-+ {
-+ register struct rb_node * tmp;
-+ __rb_rotate_right(parent, root);
-+ tmp = parent;
-+ parent = node;
-+ node = tmp;
-+ }
-+
-+ parent->rb_color = RB_BLACK;
-+ gparent->rb_color = RB_RED;
-+ __rb_rotate_left(gparent, root);
-+ }
-+ }
-+
-+ root->rb_node->rb_color = RB_BLACK;
-+}
-+
-+static void __rb_erase_color(struct rb_node * node, struct rb_node * parent,
-+ struct rb_root * root)
-+{
-+ struct rb_node * other;
-+
-+ while ((!node || node->rb_color == RB_BLACK) && node != root->rb_node)
-+ {
-+ if (parent->rb_left == node)
-+ {
-+ other = parent->rb_right;
-+ if (other->rb_color == RB_RED)
-+ {
-+ other->rb_color = RB_BLACK;
-+ parent->rb_color = RB_RED;
-+ __rb_rotate_left(parent, root);
-+ other = parent->rb_right;
-+ }
-+ if ((!other->rb_left ||
-+ other->rb_left->rb_color == RB_BLACK)
-+ && (!other->rb_right ||
-+ other->rb_right->rb_color == RB_BLACK))
-+ {
-+ other->rb_color = RB_RED;
-+ node = parent;
-+ parent = node->rb_parent;
-+ }
-+ else
-+ {
-+ if (!other->rb_right ||
-+ other->rb_right->rb_color == RB_BLACK)
-+ {
-+ register struct rb_node * o_left;
-+ if ((o_left = other->rb_left))
-+ o_left->rb_color = RB_BLACK;
-+ other->rb_color = RB_RED;
-+ __rb_rotate_right(other, root);
-+ other = parent->rb_right;
-+ }
-+ other->rb_color = parent->rb_color;
-+ parent->rb_color = RB_BLACK;
-+ if (other->rb_right)
-+ other->rb_right->rb_color = RB_BLACK;
-+ __rb_rotate_left(parent, root);
-+ node = root->rb_node;
-+ break;
-+ }
-+ }
-+ else
-+ {
-+ other = parent->rb_left;
-+ if (other->rb_color == RB_RED)
-+ {
-+ other->rb_color = RB_BLACK;
-+ parent->rb_color = RB_RED;
-+ __rb_rotate_right(parent, root);
-+ other = parent->rb_left;
-+ }
-+ if ((!other->rb_left ||
-+ other->rb_left->rb_color == RB_BLACK)
-+ && (!other->rb_right ||
-+ other->rb_right->rb_color == RB_BLACK))
-+ {
-+ other->rb_color = RB_RED;
-+ node = parent;
-+ parent = node->rb_parent;
-+ }
-+ else
-+ {
-+ if (!other->rb_left ||
-+ other->rb_left->rb_color == RB_BLACK)
-+ {
-+ register struct rb_node * o_right;
-+ if ((o_right = other->rb_right))
-+ o_right->rb_color = RB_BLACK;
-+ other->rb_color = RB_RED;
-+ __rb_rotate_left(other, root);
-+ other = parent->rb_left;
-+ }
-+ other->rb_color = parent->rb_color;
-+ parent->rb_color = RB_BLACK;
-+ if (other->rb_left)
-+ other->rb_left->rb_color = RB_BLACK;
-+ __rb_rotate_right(parent, root);
-+ node = root->rb_node;
-+ break;
-+ }
-+ }
-+ }
-+ if (node)
-+ node->rb_color = RB_BLACK;
-+}
-+
-+void rb_erase(struct rb_node * node, struct rb_root * root)
-+{
-+ struct rb_node * child, * parent;
-+ int color;
-+
-+ if (!node->rb_left)
-+ child = node->rb_right;
-+ else if (!node->rb_right)
-+ child = node->rb_left;
-+ else
-+ {
-+ struct rb_node * old = node, * left;
-+
-+ node = node->rb_right;
-+ while ((left = node->rb_left))
-+ node = left;
-+ child = node->rb_right;
-+ parent = node->rb_parent;
-+ color = node->rb_color;
-+
-+ if (child)
-+ child->rb_parent = parent;
-+ if (parent)
-+ {
-+ if (parent->rb_left == node)
-+ parent->rb_left = child;
-+ else
-+ parent->rb_right = child;
-+ }
-+ else
-+ root->rb_node = child;
-+
-+ if (node->rb_parent == old)
-+ parent = node;
-+ node->rb_parent = old->rb_parent;
-+ node->rb_color = old->rb_color;
-+ node->rb_right = old->rb_right;
-+ node->rb_left = old->rb_left;
-+
-+ if (old->rb_parent)
-+ {
-+ if (old->rb_parent->rb_left == old)
-+ old->rb_parent->rb_left = node;
-+ else
-+ old->rb_parent->rb_right = node;
-+ } else
-+ root->rb_node = node;
-+
-+ old->rb_left->rb_parent = node;
-+ if (old->rb_right)
-+ old->rb_right->rb_parent = node;
-+ goto color;
-+ }
-+
-+ parent = node->rb_parent;
-+ color = node->rb_color;
-+
-+ if (child)
-+ child->rb_parent = parent;
-+ if (parent)
-+ {
-+ if (parent->rb_left == node)
-+ parent->rb_left = child;
-+ else
-+ parent->rb_right = child;
-+ }
-+ else
-+ root->rb_node = child;
-+
-+ color:
-+ if (color == RB_BLACK)
-+ __rb_erase_color(child, parent, root);
-+}
-+#endif /* Before 2.4.11 */
-+
-+ /* These routines haven't made it into 2.4 (yet) */
-+struct rb_node *rb_next(struct rb_node *node)
-+{
-+ /* If we have a right-hand child, go down and then left as far
-+ as we can. */
-+ if (node->rb_right) {
-+ node = node->rb_right;
-+ while (node->rb_left)
-+ node=node->rb_left;
-+ return node;
-+ }
-+
-+ /* No right-hand children. Everything down and left is
-+ smaller than us, so any 'next' node must be in the general
-+ direction of our parent. Go up the tree; any time the
-+ ancestor is a right-hand child of its parent, keep going
-+ up. First time it's a left-hand child of its parent, said
-+ parent is our 'next' node. */
-+ while (node->rb_parent && node == node->rb_parent->rb_right)
-+ node = node->rb_parent;
-+
-+ return node->rb_parent;
-+}
-+
-+struct rb_node *rb_prev(struct rb_node *node)
-+{
-+ if (node->rb_left) {
-+ node = node->rb_left;
-+ while (node->rb_right)
-+ node=node->rb_right;
-+ return node;
-+ }
-+ while (node->rb_parent && node == node->rb_parent->rb_left)
-+ node = node->rb_parent;
-+
-+ return node->rb_parent;
-+}
-+
-+void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root)
-+{
-+ struct rb_node *parent = victim->rb_parent;
-+
-+ /* Set the surrounding nodes to point to the replacement */
-+ if (parent) {
-+ if (victim == parent->rb_left)
-+ parent->rb_left = new;
-+ else
-+ parent->rb_right = new;
-+ } else {
-+ root->rb_node = new;
-+ }
-+ if (victim->rb_left)
-+ victim->rb_left->rb_parent = new;
-+ if (victim->rb_right)
-+ victim->rb_right->rb_parent = new;
-+
-+ /* Copy the pointers/colour from the victim to the replacement */
-+ *new = *victim;
-+}
---- linux-2.4.21/fs/jffs2/read.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/read.c
-@@ -1,52 +1,32 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: read.c,v 1.13.2.1 2002/02/01 23:32:33 dwmw2 Exp $
-+ * $Id: read.c,v 1.39 2005/03/01 10:34:03 dedekind Exp $
- *
- */
-
- #include <linux/kernel.h>
- #include <linux/slab.h>
--#include <linux/jffs2.h>
-+#include <linux/crc32.h>
-+#include <linux/pagemap.h>
- #include <linux/mtd/mtd.h>
-+#include <linux/compiler.h>
- #include "nodelist.h"
--#include "crc32.h"
-+#include "compr.h"
-
--int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len)
-+int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-+ struct jffs2_full_dnode *fd, unsigned char *buf,
-+ int ofs, int len)
- {
- struct jffs2_raw_inode *ri;
- size_t readlen;
-- __u32 crc;
-+ uint32_t crc;
- unsigned char *decomprbuf = NULL;
- unsigned char *readbuf = NULL;
- int ret = 0;
-@@ -55,35 +35,41 @@
- if (!ri)
- return -ENOMEM;
-
-- ret = c->mtd->read(c->mtd, fd->raw->flash_offset & ~3, sizeof(*ri), &readlen, (char *)ri);
-+ ret = jffs2_flash_read(c, ref_offset(fd->raw), sizeof(*ri), &readlen, (char *)ri);
- if (ret) {
- jffs2_free_raw_inode(ri);
-- printk(KERN_WARNING "Error reading node from 0x%08x: %d\n", fd->raw->flash_offset & ~3, ret);
-+ printk(KERN_WARNING "Error reading node from 0x%08x: %d\n", ref_offset(fd->raw), ret);
- return ret;
- }
- if (readlen != sizeof(*ri)) {
- jffs2_free_raw_inode(ri);
-- printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%x bytes, got 0x%x\n",
-- fd->raw->flash_offset & ~3, sizeof(*ri), readlen);
-+ printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n",
-+ ref_offset(fd->raw), sizeof(*ri), readlen);
- return -EIO;
- }
- crc = crc32(0, ri, sizeof(*ri)-8);
-
-- D1(printk(KERN_DEBUG "Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p\n", fd->raw->flash_offset & ~3, ri->node_crc, crc, ri->dsize, ri->csize, ri->offset, buf));
-- if (crc != ri->node_crc) {
-- printk(KERN_WARNING "Node CRC %08x != calculated CRC %08x for node at %08x\n", ri->node_crc, crc, fd->raw->flash_offset & ~3);
-+ D1(printk(KERN_DEBUG "Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p\n",
-+ ref_offset(fd->raw), je32_to_cpu(ri->node_crc),
-+ crc, je32_to_cpu(ri->dsize), je32_to_cpu(ri->csize),
-+ je32_to_cpu(ri->offset), buf));
-+ if (crc != je32_to_cpu(ri->node_crc)) {
-+ printk(KERN_WARNING "Node CRC %08x != calculated CRC %08x for node at %08x\n",
-+ je32_to_cpu(ri->node_crc), crc, ref_offset(fd->raw));
- ret = -EIO;
- goto out_ri;
- }
- /* There was a bug where we wrote hole nodes out with csize/dsize
- swapped. Deal with it */
-- if (ri->compr == JFFS2_COMPR_ZERO && !ri->dsize && ri->csize) {
-+ if (ri->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(ri->dsize) &&
-+ je32_to_cpu(ri->csize)) {
- ri->dsize = ri->csize;
-- ri->csize = 0;
-+ ri->csize = cpu_to_je32(0);
- }
-
-- D1(if(ofs + len > ri->dsize) {
-- printk(KERN_WARNING "jffs2_read_dnode() asked for %d bytes at %d from %d-byte node\n", len, ofs, ri->dsize);
-+ D1(if(ofs + len > je32_to_cpu(ri->dsize)) {
-+ printk(KERN_WARNING "jffs2_read_dnode() asked for %d bytes at %d from %d-byte node\n",
-+ len, ofs, je32_to_cpu(ri->dsize));
- ret = -EINVAL;
- goto out_ri;
- });
-@@ -100,18 +86,18 @@
- Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy
- Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy
- */
-- if (ri->compr == JFFS2_COMPR_NONE && len == ri->dsize) {
-+ if (ri->compr == JFFS2_COMPR_NONE && len == je32_to_cpu(ri->dsize)) {
- readbuf = buf;
- } else {
-- readbuf = kmalloc(ri->csize, GFP_KERNEL);
-+ readbuf = kmalloc(je32_to_cpu(ri->csize), GFP_KERNEL);
- if (!readbuf) {
- ret = -ENOMEM;
- goto out_ri;
- }
- }
- if (ri->compr != JFFS2_COMPR_NONE) {
-- if (len < ri->dsize) {
-- decomprbuf = kmalloc(ri->dsize, GFP_KERNEL);
-+ if (len < je32_to_cpu(ri->dsize)) {
-+ decomprbuf = kmalloc(je32_to_cpu(ri->dsize), GFP_KERNEL);
- if (!decomprbuf) {
- ret = -ENOMEM;
- goto out_readbuf;
-@@ -123,31 +109,35 @@
- decomprbuf = readbuf;
- }
-
-- D2(printk(KERN_DEBUG "Read %d bytes to %p\n", ri->csize, readbuf));
-- ret = c->mtd->read(c->mtd, (fd->raw->flash_offset &~3) + sizeof(*ri), ri->csize, &readlen, readbuf);
-+ D2(printk(KERN_DEBUG "Read %d bytes to %p\n", je32_to_cpu(ri->csize),
-+ readbuf));
-+ ret = jffs2_flash_read(c, (ref_offset(fd->raw)) + sizeof(*ri),
-+ je32_to_cpu(ri->csize), &readlen, readbuf);
-
-- if (!ret && readlen != ri->csize)
-+ if (!ret && readlen != je32_to_cpu(ri->csize))
- ret = -EIO;
- if (ret)
- goto out_decomprbuf;
-
-- crc = crc32(0, readbuf, ri->csize);
-- if (crc != ri->data_crc) {
-- printk(KERN_WARNING "Data CRC %08x != calculated CRC %08x for node at %08x\n", ri->data_crc, crc, fd->raw->flash_offset & ~3);
-+ crc = crc32(0, readbuf, je32_to_cpu(ri->csize));
-+ if (crc != je32_to_cpu(ri->data_crc)) {
-+ printk(KERN_WARNING "Data CRC %08x != calculated CRC %08x for node at %08x\n",
-+ je32_to_cpu(ri->data_crc), crc, ref_offset(fd->raw));
- ret = -EIO;
- goto out_decomprbuf;
- }
- D2(printk(KERN_DEBUG "Data CRC matches calculated CRC %08x\n", crc));
- if (ri->compr != JFFS2_COMPR_NONE) {
-- D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n", ri->csize, readbuf, ri->dsize, decomprbuf));
-- ret = jffs2_decompress(ri->compr, readbuf, decomprbuf, ri->csize, ri->dsize);
-+ D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n",
-+ je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf));
-+ ret = jffs2_decompress(c, f, ri->compr | (ri->usercompr << 8), readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize));
- if (ret) {
- printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret);
- goto out_decomprbuf;
- }
- }
-
-- if (len < ri->dsize) {
-+ if (len < je32_to_cpu(ri->dsize)) {
- memcpy(buf, decomprbuf+ofs, len);
- }
- out_decomprbuf:
-@@ -161,3 +151,66 @@
-
- return ret;
- }
-+
-+int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-+ unsigned char *buf, uint32_t offset, uint32_t len)
-+{
-+ uint32_t end = offset + len;
-+ struct jffs2_node_frag *frag;
-+ int ret;
-+
-+ D1(printk(KERN_DEBUG "jffs2_read_inode_range: ino #%u, range 0x%08x-0x%08x\n",
-+ f->inocache->ino, offset, offset+len));
-+
-+ frag = jffs2_lookup_node_frag(&f->fragtree, offset);
-+
-+ /* XXX FIXME: Where a single physical node actually shows up in two
-+ frags, we read it twice. Don't do that. */
-+ /* Now we're pointing at the first frag which overlaps our page */
-+ while(offset < end) {
-+ D2(printk(KERN_DEBUG "jffs2_read_inode_range: offset %d, end %d\n", offset, end));
-+ if (unlikely(!frag || frag->ofs > offset)) {
-+ uint32_t holesize = end - offset;
-+ if (frag) {
-+ D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset));
-+ holesize = min(holesize, frag->ofs - offset);
-+ D2(jffs2_print_frag_list(f));
-+ }
-+ D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize));
-+ memset(buf, 0, holesize);
-+ buf += holesize;
-+ offset += holesize;
-+ continue;
-+ } else if (unlikely(!frag->node)) {
-+ uint32_t holeend = min(end, frag->ofs + frag->size);
-+ D1(printk(KERN_DEBUG "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset, holeend, frag->ofs, frag->ofs + frag->size));
-+ memset(buf, 0, holeend - offset);
-+ buf += holeend - offset;
-+ offset = holeend;
-+ frag = frag_next(frag);
-+ continue;
-+ } else {
-+ uint32_t readlen;
-+ uint32_t fragofs; /* offset within the frag to start reading */
-+
-+ fragofs = offset - frag->ofs;
-+ readlen = min(frag->size - fragofs, end - offset);
-+ D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%08x (%d)\n",
-+ frag->ofs+fragofs, frag->ofs+fragofs+readlen,
-+ ref_offset(frag->node->raw), ref_flags(frag->node->raw)));
-+ ret = jffs2_read_dnode(c, f, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen);
-+ D2(printk(KERN_DEBUG "node read done\n"));
-+ if (ret) {
-+ D1(printk(KERN_DEBUG"jffs2_read_inode_range error %d\n",ret));
-+ memset(buf, 0, readlen);
-+ return ret;
-+ }
-+ buf += readlen;
-+ offset += readlen;
-+ frag = frag_next(frag);
-+ D2(printk(KERN_DEBUG "node read was OK. Looping\n"));
-+ }
-+ }
-+ return 0;
-+}
-+
---- linux-2.4.21/fs/jffs2/readinode.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/readinode.c
-@@ -1,79 +1,124 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: readinode.c,v 1.58.2.6 2002/10/10 13:18:38 dwmw2 Exp $
-+ * $Id: readinode.c,v 1.119 2005/03/01 10:34:03 dedekind Exp $
- *
- */
-
--/* Given an inode, probably with existing list of fragments, add the new node
-- * to the fragment list.
-- */
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/fs.h>
-+#include <linux/crc32.h>
-+#include <linux/pagemap.h>
- #include <linux/mtd/mtd.h>
--#include <linux/jffs2.h>
-+#include <linux/compiler.h>
- #include "nodelist.h"
--#include "crc32.h"
-
-+static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag);
-
--D1(void jffs2_print_frag_list(struct jffs2_inode_info *f)
-+#if CONFIG_JFFS2_FS_DEBUG >= 2
-+static void jffs2_print_fragtree(struct rb_root *list, int permitbug)
- {
-- struct jffs2_node_frag *this = f->fraglist;
-+ struct jffs2_node_frag *this = frag_first(list);
-+ uint32_t lastofs = 0;
-+ int buggy = 0;
-
- while(this) {
- if (this->node)
-- printk(KERN_DEBUG "frag %04x-%04x: 0x%08x on flash (*%p->%p)\n", this->ofs, this->ofs+this->size, this->node->raw->flash_offset &~3, this, this->next);
-+ printk(KERN_DEBUG "frag %04x-%04x: 0x%08x(%d) on flash (*%p). left (%p), right (%p), parent (%p)\n",
-+ this->ofs, this->ofs+this->size, ref_offset(this->node->raw), ref_flags(this->node->raw),
-+ this, frag_left(this), frag_right(this), frag_parent(this));
- else
-- printk(KERN_DEBUG "frag %04x-%04x: hole (*%p->%p)\n", this->ofs, this->ofs+this->size, this, this->next);
-- this = this->next;
-+ printk(KERN_DEBUG "frag %04x-%04x: hole (*%p). left (%p} right (%p), parent (%p)\n", this->ofs,
-+ this->ofs+this->size, this, frag_left(this), frag_right(this), frag_parent(this));
-+ if (this->ofs != lastofs)
-+ buggy = 1;
-+ lastofs = this->ofs+this->size;
-+ this = frag_next(this);
- }
-- if (f->metadata) {
-- printk(KERN_DEBUG "metadata at 0x%08x\n", f->metadata->raw->flash_offset &~3);
-+ if (buggy && !permitbug) {
-+ printk(KERN_CRIT "Frag tree got a hole in it\n");
-+ BUG();
- }
--})
-+}
-
-+void jffs2_print_frag_list(struct jffs2_inode_info *f)
-+{
-+ jffs2_print_fragtree(&f->fragtree, 0);
-
--int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn)
-+ if (f->metadata) {
-+ printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
-+ }
-+}
-+#endif
-+
-+#if CONFIG_JFFS2_FS_DEBUG >= 1
-+static int jffs2_sanitycheck_fragtree(struct jffs2_inode_info *f)
- {
-- int ret;
-- D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn));
-+ struct jffs2_node_frag *frag;
-+ int bitched = 0;
-
-- ret = jffs2_add_full_dnode_to_fraglist(c, &f->fraglist, fn);
-+ for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
-
-- D2(jffs2_print_frag_list(f));
-- return ret;
-+ struct jffs2_full_dnode *fn = frag->node;
-+ if (!fn || !fn->raw)
-+ continue;
-+
-+ if (ref_flags(fn->raw) == REF_PRISTINE) {
-+
-+ if (fn->frags > 1) {
-+ printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", ref_offset(fn->raw), fn->frags);
-+ bitched = 1;
-+ }
-+ /* A hole node which isn't multi-page should be garbage-collected
-+ and merged anyway, so we just check for the frag size here,
-+ rather than mucking around with actually reading the node
-+ and checking the compression type, which is the real way
-+ to tell a hole node. */
-+ if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) {
-+ printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2\n",
-+ ref_offset(fn->raw));
-+ bitched = 1;
-+ }
-+
-+ if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) {
-+ printk(KERN_WARNING "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2\n",
-+ ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size);
-+ bitched = 1;
-+ }
-+ }
-+ }
-+
-+ if (bitched) {
-+ struct jffs2_node_frag *thisfrag;
-+
-+ printk(KERN_WARNING "Inode is #%u\n", f->inocache->ino);
-+ thisfrag = frag_first(&f->fragtree);
-+ while (thisfrag) {
-+ if (!thisfrag->node) {
-+ printk("Frag @0x%x-0x%x; node-less hole\n",
-+ thisfrag->ofs, thisfrag->size + thisfrag->ofs);
-+ } else if (!thisfrag->node->raw) {
-+ printk("Frag @0x%x-0x%x; raw-less hole\n",
-+ thisfrag->ofs, thisfrag->size + thisfrag->ofs);
-+ } else {
-+ printk("Frag @0x%x-0x%x; raw at 0x%08x(%d) (0x%x-0x%x)\n",
-+ thisfrag->ofs, thisfrag->size + thisfrag->ofs,
-+ ref_offset(thisfrag->node->raw), ref_flags(thisfrag->node->raw),
-+ thisfrag->node->ofs, thisfrag->node->ofs+thisfrag->node->size);
-+ }
-+ thisfrag = frag_next(thisfrag);
-+ }
-+ }
-+ return bitched;
- }
-+#endif /* D1 */
-
- static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this)
- {
-@@ -82,42 +127,38 @@
- if (!this->node->frags) {
- /* The node has no valid frags left. It's totally obsoleted */
- D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) obsolete\n",
-- this->node->raw->flash_offset &~3, this->node->ofs, this->node->ofs+this->node->size));
-+ ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size));
- jffs2_mark_node_obsolete(c, this->node->raw);
- jffs2_free_full_dnode(this->node);
- } else {
-- D2(printk(KERN_DEBUG "Not marking old node @0x%08x (0x%04x-0x%04x) obsolete. frags is %d\n",
-- this->node->raw->flash_offset &~3, this->node->ofs, this->node->ofs+this->node->size,
-+ D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL. frags is %d\n",
-+ ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size,
- this->node->frags));
-+ mark_ref_normal(this->node->raw);
- }
-
- }
- jffs2_free_node_frag(this);
- }
-
--/* Doesn't set inode->i_size */
--int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_frag **list, struct jffs2_full_dnode *fn)
-+/* Given an inode, probably with existing list of fragments, add the new node
-+ * to the fragment list.
-+ */
-+int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn)
- {
-+ int ret;
-+ struct jffs2_node_frag *newfrag;
-
-- struct jffs2_node_frag *this, **prev, *old;
-- struct jffs2_node_frag *newfrag, *newfrag2;
-- __u32 lastend = 0;
--
-+ D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn));
-
- newfrag = jffs2_alloc_node_frag();
-- if (!newfrag) {
-+ if (unlikely(!newfrag))
- return -ENOMEM;
-- }
-
-- D2(if (fn->raw)
-- printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, fn->raw->flash_offset &~3, newfrag);
-- else
-- printk(KERN_DEBUG "adding hole node %04x-%04x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, newfrag));
--
-- prev = list;
-- this = *list;
-+ D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n",
-+ fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag));
-
-- if (!fn->size) {
-+ if (unlikely(!fn->size)) {
- jffs2_free_node_frag(newfrag);
- return 0;
- }
-@@ -126,176 +167,358 @@
- newfrag->size = fn->size;
- newfrag->node = fn;
- newfrag->node->frags = 1;
-- newfrag->next = (void *)0xdeadbeef;
-+
-+ ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag);
-+ if (ret)
-+ return ret;
-+
-+ /* If we now share a page with other nodes, mark either previous
-+ or next node REF_NORMAL, as appropriate. */
-+ if (newfrag->ofs & (PAGE_CACHE_SIZE-1)) {
-+ struct jffs2_node_frag *prev = frag_prev(newfrag);
-+
-+ mark_ref_normal(fn->raw);
-+ /* If we don't start at zero there's _always_ a previous */
-+ if (prev->node)
-+ mark_ref_normal(prev->node->raw);
-+ }
-+
-+ if ((newfrag->ofs+newfrag->size) & (PAGE_CACHE_SIZE-1)) {
-+ struct jffs2_node_frag *next = frag_next(newfrag);
-+
-+ if (next) {
-+ mark_ref_normal(fn->raw);
-+ if (next->node)
-+ mark_ref_normal(next->node->raw);
-+ }
-+ }
-+ D2(if (jffs2_sanitycheck_fragtree(f)) {
-+ printk(KERN_WARNING "Just added node %04x-%04x @0x%08x on flash, newfrag *%p\n",
-+ fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag);
-+ return 0;
-+ })
-+ D2(jffs2_print_frag_list(f));
-+ return 0;
-+}
-+
-+/* Doesn't set inode->i_size */
-+static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag)
-+{
-+ struct jffs2_node_frag *this;
-+ uint32_t lastend;
-
- /* Skip all the nodes which are completed before this one starts */
-- while(this && fn->ofs >= this->ofs+this->size) {
-- lastend = this->ofs + this->size;
-+ this = jffs2_lookup_node_frag(list, newfrag->node->ofs);
-
-- D2(printk(KERN_DEBUG "j_a_f_d_t_f: skipping frag 0x%04x-0x%04x; phys 0x%08x (*%p->%p)\n",
-- this->ofs, this->ofs+this->size, this->node?(this->node->raw->flash_offset &~3):0xffffffff, this, this->next));
-- prev = &this->next;
-- this = this->next;
-+ if (this) {
-+ D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n",
-+ this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this));
-+ lastend = this->ofs + this->size;
-+ } else {
-+ D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave no frag\n"));
-+ lastend = 0;
- }
-
- /* See if we ran off the end of the list */
-- if (!this) {
-+ if (lastend <= newfrag->ofs) {
- /* We did */
-- if (lastend < fn->ofs) {
-+
-+ /* Check if 'this' node was on the same page as the new node.
-+ If so, both 'this' and the new node get marked REF_NORMAL so
-+ the GC can take a look.
-+ */
-+ if (lastend && (lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) {
-+ if (this->node)
-+ mark_ref_normal(this->node->raw);
-+ mark_ref_normal(newfrag->node->raw);
-+ }
-+
-+ if (lastend < newfrag->node->ofs) {
- /* ... and we need to put a hole in before the new node */
- struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag();
-- if (!holefrag)
-+ if (!holefrag) {
-+ jffs2_free_node_frag(newfrag);
- return -ENOMEM;
-+ }
- holefrag->ofs = lastend;
-- holefrag->size = fn->ofs - lastend;
-- holefrag->next = NULL;
-+ holefrag->size = newfrag->node->ofs - lastend;
- holefrag->node = NULL;
-- *prev = holefrag;
-- prev = &holefrag->next;
-+ if (this) {
-+ /* By definition, the 'this' node has no right-hand child,
-+ because there are no frags with offset greater than it.
-+ So that's where we want to put the hole */
-+ D2(printk(KERN_DEBUG "Adding hole frag (%p) on right of node at (%p)\n", holefrag, this));
-+ rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right);
-+ } else {
-+ D2(printk(KERN_DEBUG "Adding hole frag (%p) at root of tree\n", holefrag));
-+ rb_link_node(&holefrag->rb, NULL, &list->rb_node);
- }
-- newfrag->next = NULL;
-- *prev = newfrag;
-+ rb_insert_color(&holefrag->rb, list);
-+ this = holefrag;
-+ }
-+ if (this) {
-+ /* By definition, the 'this' node has no right-hand child,
-+ because there are no frags with offset greater than it.
-+ So that's where we want to put the hole */
-+ D2(printk(KERN_DEBUG "Adding new frag (%p) on right of node at (%p)\n", newfrag, this));
-+ rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right);
-+ } else {
-+ D2(printk(KERN_DEBUG "Adding new frag (%p) at root of tree\n", newfrag));
-+ rb_link_node(&newfrag->rb, NULL, &list->rb_node);
-+ }
-+ rb_insert_color(&newfrag->rb, list);
- return 0;
- }
-
-- D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p->%p)\n",
-- this->ofs, this->ofs+this->size, this->node?(this->node->raw->flash_offset &~3):0xffffffff, this, this->next));
-+ D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n",
-+ this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this));
-
-- /* OK. 'this' is pointing at the first frag that fn->ofs at least partially obsoletes,
-- * - i.e. fn->ofs < this->ofs+this->size && fn->ofs >= this->ofs
-+ /* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes,
-+ * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs
- */
-- if (fn->ofs > this->ofs) {
-+ if (newfrag->ofs > this->ofs) {
- /* This node isn't completely obsoleted. The start of it remains valid */
-- if (this->ofs + this->size > fn->ofs + fn->size) {
-+
-+ /* Mark the new node and the partially covered node REF_NORMAL -- let
-+ the GC take a look at them */
-+ mark_ref_normal(newfrag->node->raw);
-+ if (this->node)
-+ mark_ref_normal(this->node->raw);
-+
-+ if (this->ofs + this->size > newfrag->ofs + newfrag->size) {
- /* The new node splits 'this' frag into two */
-- newfrag2 = jffs2_alloc_node_frag();
-+ struct jffs2_node_frag *newfrag2 = jffs2_alloc_node_frag();
- if (!newfrag2) {
- jffs2_free_node_frag(newfrag);
- return -ENOMEM;
- }
-- D1(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size);
-+ D2(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size);
- if (this->node)
-- printk("phys 0x%08x\n", this->node->raw->flash_offset &~3);
-+ printk("phys 0x%08x\n", ref_offset(this->node->raw));
- else
- printk("hole\n");
- )
-- newfrag2->ofs = fn->ofs + fn->size;
-+
-+ /* New second frag pointing to this's node */
-+ newfrag2->ofs = newfrag->ofs + newfrag->size;
- newfrag2->size = (this->ofs+this->size) - newfrag2->ofs;
-- newfrag2->next = this->next;
- newfrag2->node = this->node;
- if (this->node)
- this->node->frags++;
-- newfrag->next = newfrag2;
-- this->next = newfrag;
-+
-+ /* Adjust size of original 'this' */
- this->size = newfrag->ofs - this->ofs;
-+
-+ /* Now, we know there's no node with offset
-+ greater than this->ofs but smaller than
-+ newfrag2->ofs or newfrag->ofs, for obvious
-+ reasons. So we can do a tree insert from
-+ 'this' to insert newfrag, and a tree insert
-+ from newfrag to insert newfrag2. */
-+ jffs2_fragtree_insert(newfrag, this);
-+ rb_insert_color(&newfrag->rb, list);
-+
-+ jffs2_fragtree_insert(newfrag2, newfrag);
-+ rb_insert_color(&newfrag2->rb, list);
-+
- return 0;
- }
- /* New node just reduces 'this' frag in size, doesn't split it */
-- this->size = fn->ofs - this->ofs;
-- newfrag->next = this->next;
-- this->next = newfrag;
-- this = newfrag->next;
-+ this->size = newfrag->ofs - this->ofs;
-+
-+ /* Again, we know it lives down here in the tree */
-+ jffs2_fragtree_insert(newfrag, this);
-+ rb_insert_color(&newfrag->rb, list);
- } else {
-- D2(printk(KERN_DEBUG "Inserting newfrag (*%p) in before 'this' (*%p)\n", newfrag, this));
-- *prev = newfrag;
-- newfrag->next = this;
-+ /* New frag starts at the same point as 'this' used to. Replace
-+ it in the tree without doing a delete and insertion */
-+ D2(printk(KERN_DEBUG "Inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n",
-+ newfrag, newfrag->ofs, newfrag->ofs+newfrag->size,
-+ this, this->ofs, this->ofs+this->size));
-+
-+ rb_replace_node(&this->rb, &newfrag->rb, list);
-+
-+ if (newfrag->ofs + newfrag->size >= this->ofs+this->size) {
-+ D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size));
-+ jffs2_obsolete_node_frag(c, this);
-+ } else {
-+ this->ofs += newfrag->size;
-+ this->size -= newfrag->size;
-+
-+ jffs2_fragtree_insert(this, newfrag);
-+ rb_insert_color(&this->rb, list);
-+ return 0;
- }
-- /* OK, now we have newfrag added in the correct place in the list, but
-- newfrag->next points to a fragment which may be overlapping it
-+ }
-+ /* OK, now we have newfrag added in the correct place in the tree, but
-+ frag_next(newfrag) may be a fragment which is overlapped by it
- */
-- while (this && newfrag->ofs + newfrag->size >= this->ofs + this->size) {
-- /* 'this' frag is obsoleted. */
-- old = this;
-- this = old->next;
-- jffs2_obsolete_node_frag(c, old);
-+ while ((this = frag_next(newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) {
-+ /* 'this' frag is obsoleted completely. */
-+ D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x) and removing from tree\n", this, this->ofs, this->ofs+this->size));
-+ rb_erase(&this->rb, list);
-+ jffs2_obsolete_node_frag(c, this);
- }
- /* Now we're pointing at the first frag which isn't totally obsoleted by
- the new frag */
-- newfrag->next = this;
-
- if (!this || newfrag->ofs + newfrag->size == this->ofs) {
- return 0;
- }
-- /* Still some overlap */
-+ /* Still some overlap but we don't need to move it in the tree */
- this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size);
- this->ofs = newfrag->ofs + newfrag->size;
-+
-+ /* And mark them REF_NORMAL so the GC takes a look at them */
-+ if (this->node)
-+ mark_ref_normal(this->node->raw);
-+ mark_ref_normal(newfrag->node->raw);
-+
- return 0;
- }
-
--void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct jffs2_node_frag **list, __u32 size)
-+void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size)
- {
-+ struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size);
-+
- D1(printk(KERN_DEBUG "Truncating fraglist to 0x%08x bytes\n", size));
-
-- while (*list) {
-- if ((*list)->ofs >= size) {
-- struct jffs2_node_frag *this = *list;
-- *list = this->next;
-- D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", this->ofs, this->ofs+this->size));
-- jffs2_obsolete_node_frag(c, this);
-- continue;
-- } else if ((*list)->ofs + (*list)->size > size) {
-- D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", (*list)->ofs, (*list)->ofs + (*list)->size));
-- (*list)->size = size - (*list)->ofs;
-+ /* We know frag->ofs <= size. That's what lookup does for us */
-+ if (frag && frag->ofs != size) {
-+ if (frag->ofs+frag->size >= size) {
-+ D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size));
-+ frag->size = size - frag->ofs;
- }
-- list = &(*list)->next;
-+ frag = frag_next(frag);
-+ }
-+ while (frag && frag->ofs >= size) {
-+ struct jffs2_node_frag *next = frag_next(frag);
-+
-+ D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size));
-+ frag_erase(frag, list);
-+ jffs2_obsolete_node_frag(c, frag);
-+ frag = next;
- }
- }
-
- /* Scan the list of all nodes present for this ino, build map of versions, etc. */
-
--void jffs2_read_inode (struct inode *inode)
-+static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
-+ struct jffs2_inode_info *f,
-+ struct jffs2_raw_inode *latest_node);
-+
-+int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-+ uint32_t ino, struct jffs2_raw_inode *latest_node)
- {
-- struct jffs2_tmp_dnode_info *tn_list, *tn;
-- struct jffs2_full_dirent *fd_list;
-- struct jffs2_inode_info *f;
-- struct jffs2_full_dnode *fn = NULL;
-- struct jffs2_sb_info *c;
-- struct jffs2_raw_inode latest_node;
-- __u32 latest_mctime, mctime_ver;
-- __u32 mdata_ver = 0;
-- int ret;
-- ssize_t retlen;
-+ D2(printk(KERN_DEBUG "jffs2_do_read_inode(): getting inocache\n"));
-
-- D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino));
-+ retry_inocache:
-+ spin_lock(&c->inocache_lock);
-+ f->inocache = jffs2_get_ino_cache(c, ino);
-
-- f = JFFS2_INODE_INFO(inode);
-- c = JFFS2_SB_INFO(inode->i_sb);
-+ D2(printk(KERN_DEBUG "jffs2_do_read_inode(): Got inocache at %p\n", f->inocache));
-
-- memset(f, 0, sizeof(*f));
-- D2(printk(KERN_DEBUG "getting inocache\n"));
-- init_MUTEX(&f->sem);
-- f->inocache = jffs2_get_ino_cache(c, inode->i_ino);
-- D2(printk(KERN_DEBUG "jffs2_read_inode(): Got inocache at %p\n", f->inocache));
-+ if (f->inocache) {
-+ /* Check its state. We may need to wait before we can use it */
-+ switch(f->inocache->state) {
-+ case INO_STATE_UNCHECKED:
-+ case INO_STATE_CHECKEDABSENT:
-+ f->inocache->state = INO_STATE_READING;
-+ break;
-
-- if (!f->inocache && inode->i_ino == 1) {
-+ case INO_STATE_CHECKING:
-+ case INO_STATE_GC:
-+ /* If it's in either of these states, we need
-+ to wait for whoever's got it to finish and
-+ put it back. */
-+ D1(printk(KERN_DEBUG "jffs2_get_ino_cache_read waiting for ino #%u in state %d\n",
-+ ino, f->inocache->state));
-+ sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
-+ goto retry_inocache;
-+
-+ case INO_STATE_READING:
-+ case INO_STATE_PRESENT:
-+ /* Eep. This should never happen. It can
-+ happen if Linux calls read_inode() again
-+ before clear_inode() has finished though. */
-+ printk(KERN_WARNING "Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state);
-+ /* Fail. That's probably better than allowing it to succeed */
-+ f->inocache = NULL;
-+ break;
-+
-+ default:
-+ BUG();
-+ }
-+ }
-+ spin_unlock(&c->inocache_lock);
-+
-+ if (!f->inocache && ino == 1) {
- /* Special case - no root inode on medium */
- f->inocache = jffs2_alloc_inode_cache();
- if (!f->inocache) {
-- printk(KERN_CRIT "jffs2_read_inode(): Cannot allocate inocache for root inode\n");
-- make_bad_inode(inode);
-- return;
-+ printk(KERN_CRIT "jffs2_do_read_inode(): Cannot allocate inocache for root inode\n");
-+ return -ENOMEM;
- }
-- D1(printk(KERN_DEBUG "jffs2_read_inode(): Creating inocache for root inode\n"));
-+ D1(printk(KERN_DEBUG "jffs2_do_read_inode(): Creating inocache for root inode\n"));
- memset(f->inocache, 0, sizeof(struct jffs2_inode_cache));
- f->inocache->ino = f->inocache->nlink = 1;
- f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
-+ f->inocache->state = INO_STATE_READING;
- jffs2_add_ino_cache(c, f->inocache);
- }
- if (!f->inocache) {
-- printk(KERN_WARNING "jffs2_read_inode() on nonexistent ino %lu\n", (unsigned long)inode->i_ino);
-- make_bad_inode(inode);
-- return;
-+ printk(KERN_WARNING "jffs2_do_read_inode() on nonexistent ino %u\n", ino);
-+ return -ENOENT;
- }
-- D1(printk(KERN_DEBUG "jffs2_read_inode(): ino #%lu nlink is %d\n", (unsigned long)inode->i_ino, f->inocache->nlink));
-- inode->i_nlink = f->inocache->nlink;
-+
-+ return jffs2_do_read_inode_internal(c, f, latest_node);
-+}
-+
-+int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
-+{
-+ struct jffs2_raw_inode n;
-+ struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL);
-+ int ret;
-+
-+ if (!f)
-+ return -ENOMEM;
-+
-+ memset(f, 0, sizeof(*f));
-+ init_MUTEX_LOCKED(&f->sem);
-+ f->inocache = ic;
-+
-+ ret = jffs2_do_read_inode_internal(c, f, &n);
-+ if (!ret) {
-+ up(&f->sem);
-+ jffs2_do_clear_inode(c, f);
-+ }
-+ kfree (f);
-+ return ret;
-+}
-+
-+static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
-+ struct jffs2_inode_info *f,
-+ struct jffs2_raw_inode *latest_node)
-+{
-+ struct jffs2_tmp_dnode_info *tn_list, *tn;
-+ struct jffs2_full_dirent *fd_list;
-+ struct jffs2_full_dnode *fn = NULL;
-+ uint32_t crc;
-+ uint32_t latest_mctime, mctime_ver;
-+ uint32_t mdata_ver = 0;
-+ size_t retlen;
-+ int ret;
-+
-+ D1(printk(KERN_DEBUG "jffs2_do_read_inode_internal(): ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink));
-
- /* Grab all nodes relevant to this ino */
-- ret = jffs2_get_inode_nodes(c, inode->i_ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver);
-+ ret = jffs2_get_inode_nodes(c, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver);
-
- if (ret) {
-- printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %lu returned %d\n", inode->i_ino, ret);
-- make_bad_inode(inode);
-- return;
-+ printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %u returned %d\n", f->inocache->ino, ret);
-+ if (f->inocache->state == INO_STATE_READING)
-+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
-+ return ret;
- }
- f->dents = fd_list;
-
-@@ -304,219 +527,217 @@
-
- fn = tn->fn;
-
-- if (f->metadata && tn->version > mdata_ver) {
-- D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", f->metadata->raw->flash_offset &~3));
-+ if (f->metadata) {
-+ if (likely(tn->version >= mdata_ver)) {
-+ D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw)));
- jffs2_mark_node_obsolete(c, f->metadata->raw);
- jffs2_free_full_dnode(f->metadata);
- f->metadata = NULL;
-
- mdata_ver = 0;
-+ } else {
-+ /* This should never happen. */
-+ printk(KERN_WARNING "Er. New metadata at 0x%08x with ver %d is actually older than previous ver %d at 0x%08x\n",
-+ ref_offset(fn->raw), tn->version, mdata_ver, ref_offset(f->metadata->raw));
-+ jffs2_mark_node_obsolete(c, fn->raw);
-+ jffs2_free_full_dnode(fn);
-+ /* Fill in latest_node from the metadata, not this one we're about to free... */
-+ fn = f->metadata;
-+ goto next_tn;
-+ }
- }
-
- if (fn->size) {
- jffs2_add_full_dnode_to_inode(c, f, fn);
- } else {
- /* Zero-sized node at end of version list. Just a metadata update */
-- D1(printk(KERN_DEBUG "metadata @%08x: ver %d\n", fn->raw->flash_offset &~3, tn->version));
-+ D1(printk(KERN_DEBUG "metadata @%08x: ver %d\n", ref_offset(fn->raw), tn->version));
- f->metadata = fn;
- mdata_ver = tn->version;
- }
-+ next_tn:
- tn_list = tn->next;
- jffs2_free_tmp_dnode_info(tn);
- }
-+ D1(jffs2_sanitycheck_fragtree(f));
-+
- if (!fn) {
- /* No data nodes for this inode. */
-- if (inode->i_ino != 1) {
-- printk(KERN_WARNING "jffs2_read_inode(): No data nodes found for ino #%lu\n", inode->i_ino);
-+ if (f->inocache->ino != 1) {
-+ printk(KERN_WARNING "jffs2_do_read_inode(): No data nodes found for ino #%u\n", f->inocache->ino);
- if (!fd_list) {
-- make_bad_inode(inode);
-- return;
-+ if (f->inocache->state == INO_STATE_READING)
-+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
-+ return -EIO;
- }
-- printk(KERN_WARNING "jffs2_read_inode(): But it has children so we fake some modes for it\n");
-+ printk(KERN_WARNING "jffs2_do_read_inode(): But it has children so we fake some modes for it\n");
- }
-- inode->i_mode = S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO;
-- latest_node.version = 0;
-- inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-- inode->i_nlink = f->inocache->nlink;
-- inode->i_size = 0;
-- } else {
-- __u32 crc;
--
-- ret = c->mtd->read(c->mtd, fn->raw->flash_offset & ~3, sizeof(latest_node), &retlen, (void *)&latest_node);
-- if (ret || retlen != sizeof(latest_node)) {
-- printk(KERN_NOTICE "MTD read in jffs2_read_inode() failed: Returned %d, %ld of %d bytes read\n",
-- ret, (long)retlen, sizeof(latest_node));
-- jffs2_clear_inode(inode);
-- make_bad_inode(inode);
-- return;
-+ latest_node->mode = cpu_to_jemode(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO);
-+ latest_node->version = cpu_to_je32(0);
-+ latest_node->atime = latest_node->ctime = latest_node->mtime = cpu_to_je32(0);
-+ latest_node->isize = cpu_to_je32(0);
-+ latest_node->gid = cpu_to_je16(0);
-+ latest_node->uid = cpu_to_je16(0);
-+ if (f->inocache->state == INO_STATE_READING)
-+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT);
-+ return 0;
- }
-
-- crc = crc32(0, &latest_node, sizeof(latest_node)-8);
-- if (crc != latest_node.node_crc) {
-- printk(KERN_NOTICE "CRC failed for read_inode of inode %ld at physical location 0x%x\n", inode->i_ino, fn->raw->flash_offset & ~3);
-- jffs2_clear_inode(inode);
-- make_bad_inode(inode);
-- return;
-+ ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node);
-+ if (ret || retlen != sizeof(*latest_node)) {
-+ printk(KERN_NOTICE "MTD read in jffs2_do_read_inode() failed: Returned %d, %zd of %zd bytes read\n",
-+ ret, retlen, sizeof(*latest_node));
-+ /* FIXME: If this fails, there seems to be a memory leak. Find it. */
-+ up(&f->sem);
-+ jffs2_do_clear_inode(c, f);
-+ return ret?ret:-EIO;
- }
-
-- inode->i_mode = latest_node.mode;
-- inode->i_uid = latest_node.uid;
-- inode->i_gid = latest_node.gid;
-- inode->i_size = latest_node.isize;
-- if (S_ISREG(inode->i_mode))
-- jffs2_truncate_fraglist(c, &f->fraglist, latest_node.isize);
-- inode->i_atime = latest_node.atime;
-- inode->i_mtime = latest_node.mtime;
-- inode->i_ctime = latest_node.ctime;
-+ crc = crc32(0, latest_node, sizeof(*latest_node)-8);
-+ if (crc != je32_to_cpu(latest_node->node_crc)) {
-+ printk(KERN_NOTICE "CRC failed for read_inode of inode %u at physical location 0x%x\n", f->inocache->ino, ref_offset(fn->raw));
-+ up(&f->sem);
-+ jffs2_do_clear_inode(c, f);
-+ return -EIO;
- }
-
-- /* OK, now the special cases. Certain inode types should
-- have only one data node, and it's kept as the metadata
-- node */
-- if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode) ||
-- S_ISLNK(inode->i_mode)) {
-- if (f->metadata) {
-- printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o had metadata node\n", inode->i_ino, inode->i_mode);
-- jffs2_clear_inode(inode);
-- make_bad_inode(inode);
-- return;
-- }
-- if (!f->fraglist) {
-- printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o has no fragments\n", inode->i_ino, inode->i_mode);
-- jffs2_clear_inode(inode);
-- make_bad_inode(inode);
-- return;
-- }
-- /* ASSERT: f->fraglist != NULL */
-- if (f->fraglist->next) {
-- printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o had more than one node\n", inode->i_ino, inode->i_mode);
-- /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */
-- jffs2_clear_inode(inode);
-- make_bad_inode(inode);
-- return;
-- }
-- /* OK. We're happy */
-- f->metadata = f->fraglist->node;
-- jffs2_free_node_frag(f->fraglist);
-- f->fraglist = NULL;
-+ switch(jemode_to_cpu(latest_node->mode) & S_IFMT) {
-+ case S_IFDIR:
-+ if (mctime_ver > je32_to_cpu(latest_node->version)) {
-+ /* The times in the latest_node are actually older than
-+ mctime in the latest dirent. Cheat. */
-+ latest_node->ctime = latest_node->mtime = cpu_to_je32(latest_mctime);
- }
-+ break;
-
-- inode->i_blksize = PAGE_SIZE;
-- inode->i_blocks = (inode->i_size + 511) >> 9;
-
-- switch (inode->i_mode & S_IFMT) {
-- unsigned short rdev;
-+ case S_IFREG:
-+ /* If it was a regular file, truncate it to the latest node's isize */
-+ jffs2_truncate_fraglist(c, &f->fragtree, je32_to_cpu(latest_node->isize));
-+ break;
-
- case S_IFLNK:
-- inode->i_op = &jffs2_symlink_inode_operations;
- /* Hack to work around broken isize in old symlink code.
- Remove this when dwmw2 comes to his senses and stops
- symlinks from being an entirely gratuitous special
- case. */
-- if (!inode->i_size)
-- inode->i_size = latest_node.dsize;
-- break;
-+ if (!je32_to_cpu(latest_node->isize))
-+ latest_node->isize = latest_node->dsize;
-
-- case S_IFDIR:
-- if (mctime_ver > latest_node.version) {
-- /* The times in the latest_node are actually older than
-- mctime in the latest dirent. Cheat. */
-- inode->i_mtime = inode->i_ctime = inode->i_atime =
-- latest_mctime;
-+ if (f->inocache->state != INO_STATE_CHECKING) {
-+ /* Symlink's inode data is the target path. Read it and
-+ * keep in RAM to facilitate quick follow symlink operation.
-+ * We use f->dents field to store the target path, which
-+ * is somewhat ugly. */
-+ f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL);
-+ if (!f->dents) {
-+ printk(KERN_WARNING "Can't allocate %d bytes of memory "
-+ "for the symlink target path cache\n",
-+ je32_to_cpu(latest_node->csize));
-+ up(&f->sem);
-+ jffs2_do_clear_inode(c, f);
-+ return -ENOMEM;
- }
-- inode->i_op = &jffs2_dir_inode_operations;
-- inode->i_fop = &jffs2_dir_operations;
-- break;
-
-- case S_IFREG:
-- inode->i_op = &jffs2_file_inode_operations;
-- inode->i_fop = &jffs2_file_operations;
-- inode->i_mapping->a_ops = &jffs2_file_address_operations;
-- inode->i_mapping->nrpages = 0;
-- break;
-+ ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node),
-+ je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents);
-+
-+ if (ret || retlen != je32_to_cpu(latest_node->csize)) {
-+ if (retlen != je32_to_cpu(latest_node->csize))
-+ ret = -EIO;
-+ kfree(f->dents);
-+ f->dents = NULL;
-+ up(&f->sem);
-+ jffs2_do_clear_inode(c, f);
-+ return -ret;
-+ }
-+
-+ ((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0';
-+ D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n",
-+ (char *)f->dents));
-+ }
-+
-+ /* fall through... */
-
- case S_IFBLK:
- case S_IFCHR:
-- /* Read the device numbers from the media */
-- D1(printk(KERN_DEBUG "Reading device numbers from flash\n"));
-- if (jffs2_read_dnode(c, f->metadata, (char *)&rdev, 0, sizeof(rdev)) < 0) {
-- /* Eep */
-- printk(KERN_NOTICE "Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino);
-- jffs2_clear_inode(inode);
-- make_bad_inode(inode);
-- return;
-+ /* Certain inode types should have only one data node, and it's
-+ kept as the metadata node */
-+ if (f->metadata) {
-+ printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had metadata node\n",
-+ f->inocache->ino, jemode_to_cpu(latest_node->mode));
-+ up(&f->sem);
-+ jffs2_do_clear_inode(c, f);
-+ return -EIO;
- }
--
-- case S_IFSOCK:
-- case S_IFIFO:
-- inode->i_op = &jffs2_file_inode_operations;
-- init_special_inode(inode, inode->i_mode, kdev_t_to_nr(MKDEV(rdev>>8, rdev&0xff)));
-+ if (!frag_first(&f->fragtree)) {
-+ printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n",
-+ f->inocache->ino, jemode_to_cpu(latest_node->mode));
-+ up(&f->sem);
-+ jffs2_do_clear_inode(c, f);
-+ return -EIO;
-+ }
-+ /* ASSERT: f->fraglist != NULL */
-+ if (frag_next(frag_first(&f->fragtree))) {
-+ printk(KERN_WARNING "Argh. Special inode #%u with mode 0x%x had more than one node\n",
-+ f->inocache->ino, jemode_to_cpu(latest_node->mode));
-+ /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */
-+ up(&f->sem);
-+ jffs2_do_clear_inode(c, f);
-+ return -EIO;
-+ }
-+ /* OK. We're happy */
-+ f->metadata = frag_first(&f->fragtree)->node;
-+ jffs2_free_node_frag(frag_first(&f->fragtree));
-+ f->fragtree = RB_ROOT;
- break;
--
-- default:
-- printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu", inode->i_mode, (unsigned long)inode->i_ino);
- }
-- D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
-+ if (f->inocache->state == INO_STATE_READING)
-+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT);
-+
-+ return 0;
- }
-
--void jffs2_clear_inode (struct inode *inode)
-+void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
- {
-- /* We can forget about this inode for now - drop all
-- * the nodelists associated with it, etc.
-- */
-- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-- struct jffs2_node_frag *frag, *frags;
- struct jffs2_full_dirent *fd, *fds;
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-- /* I don't think we care about the potential race due to reading this
-- without f->sem. It can never get undeleted. */
-- int deleted = f->inocache && !f->inocache->nlink;
--
-- D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
--
-- /* If it's a deleted inode, grab the alloc_sem. This prevents
-- jffs2_garbage_collect_pass() from deciding that it wants to
-- garbage collect one of the nodes we're just about to mark
-- obsolete -- by the time we drop alloc_sem and return, all
-- the nodes are marked obsolete, and jffs2_g_c_pass() won't
-- call iget() for the inode in question.
-- */
-- if (deleted)
-- down(&c->alloc_sem);
-+ int deleted;
-
- down(&f->sem);
-+ deleted = f->inocache && !f->inocache->nlink;
-+
-+ if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
-+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING);
-
-- frags = f->fraglist;
-- fds = f->dents;
- if (f->metadata) {
- if (deleted)
- jffs2_mark_node_obsolete(c, f->metadata->raw);
- jffs2_free_full_dnode(f->metadata);
- }
-
-- while (frags) {
-- frag = frags;
-- frags = frag->next;
-- D2(printk(KERN_DEBUG "jffs2_clear_inode: frag at 0x%x-0x%x: node %p, frags %d--\n", frag->ofs, frag->ofs+frag->size, frag->node, frag->node?frag->node->frags:0));
--
-- if (frag->node && !(--frag->node->frags)) {
-- /* Not a hole, and it's the final remaining frag of this node. Free the node */
-- if (deleted)
-- jffs2_mark_node_obsolete(c, frag->node->raw);
-+ jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL);
-
-- jffs2_free_full_dnode(frag->node);
-- }
-- jffs2_free_node_frag(frag);
-+ /* For symlink inodes we us f->dents to store the target path name */
-+ if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) {
-+ if (f->dents) {
-+ kfree(f->dents);
-+ f->dents = NULL;
- }
-+ } else {
-+ fds = f->dents;
-+
- while(fds) {
- fd = fds;
- fds = fd->next;
- jffs2_free_full_dirent(fd);
- }
-+ }
-
-- up(&f->sem);
--
-- if(deleted)
-- up(&c->alloc_sem);
--};
-+ if (f->inocache && f->inocache->state != INO_STATE_CHECKING) {
-+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
-+ if (f->inocache->nodes == (void *)f->inocache)
-+ jffs2_del_ino_cache(c, f->inocache);
-+ }
-
-+ up(&f->sem);
-+}
---- linux-2.4.21/fs/jffs2/scan.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/scan.c
-@@ -1,47 +1,25 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: scan.c,v 1.51.2.3 2002/07/25 20:49:06 dwmw2 Exp $
-+ * $Id: scan.c,v 1.119 2005/02/17 17:51:13 dedekind Exp $
- *
- */
- #include <linux/kernel.h>
-+#include <linux/sched.h>
- #include <linux/slab.h>
--#include <linux/jffs2.h>
- #include <linux/mtd/mtd.h>
- #include <linux/pagemap.h>
-+#include <linux/crc32.h>
-+#include <linux/compiler.h>
- #include "nodelist.h"
--#include "crc32.h"
-
-+#define DEFAULT_EMPTY_SCAN_SIZE 1024
-
- #define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
- c->free_size -= _x; c->dirty_size += _x; \
-@@ -51,6 +29,10 @@
- c->free_size -= _x; c->used_size += _x; \
- jeb->free_size -= _x ; jeb->used_size += _x; \
- }while(0)
-+#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
-+ c->free_size -= _x; c->unchecked_size += _x; \
-+ jeb->free_size -= _x ; jeb->unchecked_size += _x; \
-+ }while(0)
-
- #define noisy_printk(noise, args...) do { \
- if (*(noise)) { \
-@@ -63,39 +45,96 @@
- } while(0)
-
- static uint32_t pseudo_random;
--static void jffs2_rotate_lists(struct jffs2_sb_info *c);
-
--static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-+static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-+ unsigned char *buf, uint32_t buf_size);
-
- /* These helper functions _must_ increase ofs and also do the dirty/used space accounting.
- * Returning an error will abort the mount - bad checksums etc. should just mark the space
- * as dirty.
- */
--static int jffs2_scan_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs, int *noise);
--static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs);
--static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs);
-+static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-+ struct jffs2_raw_inode *ri, uint32_t ofs);
-+static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-+ struct jffs2_raw_dirent *rd, uint32_t ofs);
-+
-+#define BLK_STATE_ALLFF 0
-+#define BLK_STATE_CLEAN 1
-+#define BLK_STATE_PARTDIRTY 2
-+#define BLK_STATE_CLEANMARKER 3
-+#define BLK_STATE_ALLDIRTY 4
-+#define BLK_STATE_BADBLOCK 5
-+
-+static inline int min_free(struct jffs2_sb_info *c)
-+{
-+ uint32_t min = 2 * sizeof(struct jffs2_raw_inode);
-+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
-+ if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize)
-+ return c->wbuf_pagesize;
-+#endif
-+ return min;
-
-+}
-+
-+static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) {
-+ if (sector_size < DEFAULT_EMPTY_SCAN_SIZE)
-+ return sector_size;
-+ else
-+ return DEFAULT_EMPTY_SCAN_SIZE;
-+}
-
- int jffs2_scan_medium(struct jffs2_sb_info *c)
- {
- int i, ret;
-- __u32 empty_blocks = 0;
-+ uint32_t empty_blocks = 0, bad_blocks = 0;
-+ unsigned char *flashbuf = NULL;
-+ uint32_t buf_size = 0;
-+#ifndef __ECOS
-+ size_t pointlen;
-
-- if (!c->blocks) {
-- printk(KERN_WARNING "EEEK! c->blocks is NULL!\n");
-- return -EINVAL;
-+ if (c->mtd->point) {
-+ ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &flashbuf);
-+ if (!ret && pointlen < c->mtd->size) {
-+ /* Don't muck about if it won't let us point to the whole flash */
-+ D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen));
-+ c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size);
-+ flashbuf = NULL;
-+ }
-+ if (ret)
-+ D1(printk(KERN_DEBUG "MTD point failed %d\n", ret));
-+ }
-+#endif
-+ if (!flashbuf) {
-+ /* For NAND it's quicker to read a whole eraseblock at a time,
-+ apparently */
-+ if (jffs2_cleanmarker_oob(c))
-+ buf_size = c->sector_size;
-+ else
-+ buf_size = PAGE_SIZE;
-+
-+ /* Respect kmalloc limitations */
-+ if (buf_size > 128*1024)
-+ buf_size = 128*1024;
-+
-+ D1(printk(KERN_DEBUG "Allocating readbuf of %d bytes\n", buf_size));
-+ flashbuf = kmalloc(buf_size, GFP_KERNEL);
-+ if (!flashbuf)
-+ return -ENOMEM;
- }
-+
- for (i=0; i<c->nr_blocks; i++) {
- struct jffs2_eraseblock *jeb = &c->blocks[i];
-
-- ret = jffs2_scan_eraseblock(c, jeb);
-+ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), buf_size);
-+
- if (ret < 0)
-- return ret;
-+ goto out;
-
- ACCT_PARANOIA_CHECK(jeb);
-
- /* Now decide which list to put it on */
-- if (ret == 1) {
-+ switch(ret) {
-+ case BLK_STATE_ALLFF:
- /*
- * Empty block. Since we can't be sure it
- * was entirely erased, we just queue it for erase
-@@ -103,10 +142,12 @@
- * is complete. Meanwhile we still count it as empty
- * for later checks.
- */
-- list_add(&jeb->list, &c->erase_pending_list);
- empty_blocks++;
-+ list_add(&jeb->list, &c->erase_pending_list);
- c->nr_erasing_blocks++;
-- } else if (jeb->used_size == PAD(sizeof(struct jffs2_unknown_node)) && !jeb->first_node->next_in_ino) {
-+ break;
-+
-+ case BLK_STATE_CLEANMARKER:
- /* Only a CLEANMARKER node is valid */
- if (!jeb->dirty_size) {
- /* It's actually free */
-@@ -118,74 +159,224 @@
- list_add(&jeb->list, &c->erase_pending_list);
- c->nr_erasing_blocks++;
- }
-- } else if (jeb->used_size > c->sector_size - (2*sizeof(struct jffs2_raw_inode))) {
-+ break;
-+
-+ case BLK_STATE_CLEAN:
- /* Full (or almost full) of clean data. Clean list */
- list_add(&jeb->list, &c->clean_list);
-- } else if (jeb->used_size) {
-+ break;
-+
-+ case BLK_STATE_PARTDIRTY:
- /* Some data, but not full. Dirty list. */
-- /* Except that we want to remember the block with most free space,
-- and stick it in the 'nextblock' position to start writing to it.
-- Later when we do snapshots, this must be the most recent block,
-- not the one with most free space.
-- */
-- if (jeb->free_size > 2*sizeof(struct jffs2_raw_inode) &&
-+ /* We want to remember the block with most free space
-+ and stick it in the 'nextblock' position to start writing to it. */
-+ if (jeb->free_size > min_free(c) &&
- (!c->nextblock || c->nextblock->free_size < jeb->free_size)) {
- /* Better candidate for the next writes to go to */
-- if (c->nextblock)
-+ if (c->nextblock) {
-+ c->nextblock->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size;
-+ c->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size;
-+ c->free_size -= c->nextblock->free_size;
-+ c->wasted_size -= c->nextblock->wasted_size;
-+ c->nextblock->free_size = c->nextblock->wasted_size = 0;
-+ if (VERYDIRTY(c, c->nextblock->dirty_size)) {
-+ list_add(&c->nextblock->list, &c->very_dirty_list);
-+ } else {
- list_add(&c->nextblock->list, &c->dirty_list);
-+ }
-+ }
- c->nextblock = jeb;
- } else {
-+ jeb->dirty_size += jeb->free_size + jeb->wasted_size;
-+ c->dirty_size += jeb->free_size + jeb->wasted_size;
-+ c->free_size -= jeb->free_size;
-+ c->wasted_size -= jeb->wasted_size;
-+ jeb->free_size = jeb->wasted_size = 0;
-+ if (VERYDIRTY(c, jeb->dirty_size)) {
-+ list_add(&jeb->list, &c->very_dirty_list);
-+ } else {
- list_add(&jeb->list, &c->dirty_list);
- }
-- } else {
-+ }
-+ break;
-+
-+ case BLK_STATE_ALLDIRTY:
- /* Nothing valid - not even a clean marker. Needs erasing. */
- /* For now we just put it on the erasing list. We'll start the erases later */
-- printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset);
-+ D1(printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset));
- list_add(&jeb->list, &c->erase_pending_list);
- c->nr_erasing_blocks++;
-+ break;
-+
-+ case BLK_STATE_BADBLOCK:
-+ D1(printk(KERN_NOTICE "JFFS2: Block at 0x%08x is bad\n", jeb->offset));
-+ list_add(&jeb->list, &c->bad_list);
-+ c->bad_size += c->sector_size;
-+ c->free_size -= c->sector_size;
-+ bad_blocks++;
-+ break;
-+ default:
-+ printk(KERN_WARNING "jffs2_scan_medium(): unknown block state\n");
-+ BUG();
- }
- }
-- /* Rotate the lists by some number to ensure wear levelling */
-- jffs2_rotate_lists(c);
-
-+ /* Nextblock dirty is always seen as wasted, because we cannot recycle it now */
-+ if (c->nextblock && (c->nextblock->dirty_size)) {
-+ c->nextblock->wasted_size += c->nextblock->dirty_size;
-+ c->wasted_size += c->nextblock->dirty_size;
-+ c->dirty_size -= c->nextblock->dirty_size;
-+ c->nextblock->dirty_size = 0;
-+ }
-+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
-+ if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) {
-+ /* If we're going to start writing into a block which already
-+ contains data, and the end of the data isn't page-aligned,
-+ skip a little and align it. */
-+
-+ uint32_t skip = c->nextblock->free_size & (c->wbuf_pagesize-1);
-+
-+ D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment\n",
-+ skip));
-+ c->nextblock->wasted_size += skip;
-+ c->wasted_size += skip;
-+
-+ c->nextblock->free_size -= skip;
-+ c->free_size -= skip;
-+ }
-+#endif
- if (c->nr_erasing_blocks) {
-- if (!c->used_size && empty_blocks != c->nr_blocks) {
-+ if ( !c->used_size && ((c->nr_free_blocks+empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) {
- printk(KERN_NOTICE "Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n");
-- return -EIO;
-+ printk(KERN_NOTICE "empty_blocks %d, bad_blocks %d, c->nr_blocks %d\n",empty_blocks,bad_blocks,c->nr_blocks);
-+ ret = -EIO;
-+ goto out;
- }
- jffs2_erase_pending_trigger(c);
- }
-+ ret = 0;
-+ out:
-+ if (buf_size)
-+ kfree(flashbuf);
-+#ifndef __ECOS
-+ else
-+ c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size);
-+#endif
-+ return ret;
-+}
-+
-+static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf,
-+ uint32_t ofs, uint32_t len)
-+{
-+ int ret;
-+ size_t retlen;
-+
-+ ret = jffs2_flash_read(c, ofs, len, &retlen, buf);
-+ if (ret) {
-+ D1(printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%x) returned %d\n", len, ofs, ret));
-+ return ret;
-+ }
-+ if (retlen < len) {
-+ D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%zx bytes\n", ofs, retlen));
-+ return -EIO;
-+ }
-+ D2(printk(KERN_DEBUG "Read 0x%x bytes from 0x%08x into buf\n", len, ofs));
-+ D2(printk(KERN_DEBUG "000: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]));
- return 0;
- }
-
--static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) {
-- struct jffs2_unknown_node node;
-- __u32 ofs, prevofs;
-- __u32 hdr_crc, nodetype;
-+static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-+ unsigned char *buf, uint32_t buf_size) {
-+ struct jffs2_unknown_node *node;
-+ struct jffs2_unknown_node crcnode;
-+ uint32_t ofs, prevofs;
-+ uint32_t hdr_crc, buf_ofs, buf_len;
- int err;
- int noise = 0;
-+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
-+ int cleanmarkerfound = 0;
-+#endif
-
- ofs = jeb->offset;
- prevofs = jeb->offset - 1;
-
- D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs));
-
-- err = jffs2_scan_empty(c, jeb, &ofs, &noise);
-- if (err) return err;
-- if (ofs == jeb->offset + c->sector_size) {
-+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
-+ if (jffs2_cleanmarker_oob(c)) {
-+ int ret = jffs2_check_nand_cleanmarker(c, jeb);
-+ D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret));
-+ /* Even if it's not found, we still scan to see
-+ if the block is empty. We use this information
-+ to decide whether to erase it or not. */
-+ switch (ret) {
-+ case 0: cleanmarkerfound = 1; break;
-+ case 1: break;
-+ case 2: return BLK_STATE_BADBLOCK;
-+ case 3: return BLK_STATE_ALLDIRTY; /* Block has failed to erase min. once */
-+ default: return ret;
-+ }
-+ }
-+#endif
-+ buf_ofs = jeb->offset;
-+
-+ if (!buf_size) {
-+ buf_len = c->sector_size;
-+ } else {
-+ buf_len = EMPTY_SCAN_SIZE(c->sector_size);
-+ err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
-+ if (err)
-+ return err;
-+ }
-+
-+ /* We temporarily use 'ofs' as a pointer into the buffer/jeb */
-+ ofs = 0;
-+
-+ /* Scan only 4KiB of 0xFF before declaring it's empty */
-+ while(ofs < EMPTY_SCAN_SIZE(c->sector_size) && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
-+ ofs += 4;
-+
-+ if (ofs == EMPTY_SCAN_SIZE(c->sector_size)) {
-+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
-+ if (jffs2_cleanmarker_oob(c)) {
-+ /* scan oob, take care of cleanmarker */
-+ int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound);
-+ D2(printk(KERN_NOTICE "jffs2_check_oob_empty returned %d\n",ret));
-+ switch (ret) {
-+ case 0: return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF;
-+ case 1: return BLK_STATE_ALLDIRTY;
-+ default: return ret;
-+ }
-+ }
-+#endif
- D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset));
-- return 1; /* special return code */
-+ if (c->cleanmarker_size == 0)
-+ return BLK_STATE_CLEANMARKER; /* don't bother with re-erase */
-+ else
-+ return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */
-+ }
-+ if (ofs) {
-+ D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
-+ jeb->offset + ofs));
-+ DIRTY_SPACE(ofs);
- }
-
-+ /* Now ofs is a complete physical flash offset as it always was... */
-+ ofs += jeb->offset;
-+
- noise = 10;
-
-+scan_more:
- while(ofs < jeb->offset + c->sector_size) {
-- ssize_t retlen;
-- ACCT_PARANOIA_CHECK(jeb);
-+
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+
-+ cond_resched();
-
- if (ofs & 3) {
- printk(KERN_WARNING "Eep. ofs 0x%08x not word-aligned!\n", ofs);
-- ofs = (ofs+3)&~3;
-+ ofs = PAD(ofs);
- continue;
- }
- if (ofs == prevofs) {
-@@ -196,102 +387,183 @@
- }
- prevofs = ofs;
-
-- if (jeb->offset + c->sector_size < ofs + sizeof(node)) {
-- D1(printk(KERN_DEBUG "Fewer than %d bytes left to end of block. Not reading\n", sizeof(struct jffs2_unknown_node)));
-+ if (jeb->offset + c->sector_size < ofs + sizeof(*node)) {
-+ D1(printk(KERN_DEBUG "Fewer than %zd bytes left to end of block. (%x+%x<%x+%zx) Not reading\n", sizeof(struct jffs2_unknown_node),
-+ jeb->offset, c->sector_size, ofs, sizeof(*node)));
- DIRTY_SPACE((jeb->offset + c->sector_size)-ofs);
- break;
- }
-
-- err = c->mtd->read(c->mtd, ofs, sizeof(node), &retlen, (char *)&node);
--
-- if (err) {
-- D1(printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%x) returned %d\n", sizeof(node), ofs, err));
-+ if (buf_ofs + buf_len < ofs + sizeof(*node)) {
-+ buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
-+ D1(printk(KERN_DEBUG "Fewer than %zd bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n",
-+ sizeof(struct jffs2_unknown_node), buf_len, ofs));
-+ err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
-+ if (err)
- return err;
-+ buf_ofs = ofs;
- }
-- if (retlen < sizeof(node)) {
-- D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%x bytes\n", ofs, retlen));
-- DIRTY_SPACE(retlen);
-- ofs += retlen;
-- continue;
-+
-+ node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs];
-+
-+ if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
-+ uint32_t inbuf_ofs;
-+ uint32_t empty_start;
-+
-+ empty_start = ofs;
-+ ofs += 4;
-+
-+ D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs));
-+ more_empty:
-+ inbuf_ofs = ofs - buf_ofs;
-+ while (inbuf_ofs < buf_len) {
-+ if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff) {
-+ printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n",
-+ empty_start, ofs);
-+ DIRTY_SPACE(ofs-empty_start);
-+ goto scan_more;
- }
-
-- if (node.magic == JFFS2_EMPTY_BITMASK && node.nodetype == JFFS2_EMPTY_BITMASK) {
-- D1(printk(KERN_DEBUG "Found empty flash at 0x%x\n", ofs));
-- err = jffs2_scan_empty(c, jeb, &ofs, &noise);
-- if (err) return err;
-- continue;
-+ inbuf_ofs+=4;
-+ ofs += 4;
- }
-+ /* Ran off end. */
-+ D1(printk(KERN_DEBUG "Empty flash to end of buffer at 0x%08x\n", ofs));
-
-- if (ofs == jeb->offset && node.magic == KSAMTIB_CIGAM_2SFFJ) {
-+ /* If we're only checking the beginning of a block with a cleanmarker,
-+ bail now */
-+ if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) &&
-+ c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_phys) {
-+ D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size)));
-+ return BLK_STATE_CLEANMARKER;
-+ }
-+
-+ /* See how much more there is to read in this eraseblock... */
-+ buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
-+ if (!buf_len) {
-+ /* No more to read. Break out of main loop without marking
-+ this range of empty space as dirty (because it's not) */
-+ D1(printk(KERN_DEBUG "Empty flash at %08x runs to end of block. Treating as free_space\n",
-+ empty_start));
-+ break;
-+ }
-+ D1(printk(KERN_DEBUG "Reading another 0x%x at 0x%08x\n", buf_len, ofs));
-+ err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
-+ if (err)
-+ return err;
-+ buf_ofs = ofs;
-+ goto more_empty;
-+ }
-+
-+ if (ofs == jeb->offset && je16_to_cpu(node->magic) == KSAMTIB_CIGAM_2SFFJ) {
- printk(KERN_WARNING "Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?\n", ofs);
- DIRTY_SPACE(4);
- ofs += 4;
- continue;
- }
-- if (node.magic == JFFS2_DIRTY_BITMASK) {
-- D1(printk(KERN_DEBUG "Empty bitmask at 0x%08x\n", ofs));
-+ if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) {
-+ D1(printk(KERN_DEBUG "Dirty bitmask at 0x%08x\n", ofs));
- DIRTY_SPACE(4);
- ofs += 4;
- continue;
- }
-- if (node.magic == JFFS2_OLD_MAGIC_BITMASK) {
-+ if (je16_to_cpu(node->magic) == JFFS2_OLD_MAGIC_BITMASK) {
- printk(KERN_WARNING "Old JFFS2 bitmask found at 0x%08x\n", ofs);
- printk(KERN_WARNING "You cannot use older JFFS2 filesystems with newer kernels\n");
- DIRTY_SPACE(4);
- ofs += 4;
- continue;
- }
-- if (node.magic != JFFS2_MAGIC_BITMASK) {
-+ if (je16_to_cpu(node->magic) != JFFS2_MAGIC_BITMASK) {
- /* OK. We're out of possibilities. Whinge and move on */
-- noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n", JFFS2_MAGIC_BITMASK, ofs, node.magic);
-+ noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n",
-+ JFFS2_MAGIC_BITMASK, ofs,
-+ je16_to_cpu(node->magic));
- DIRTY_SPACE(4);
- ofs += 4;
- continue;
- }
- /* We seem to have a node of sorts. Check the CRC */
-- nodetype = node.nodetype;
-- node.nodetype |= JFFS2_NODE_ACCURATE;
-- hdr_crc = crc32(0, &node, sizeof(node)-4);
-- node.nodetype = nodetype;
-- if (hdr_crc != node.hdr_crc) {
-+ crcnode.magic = node->magic;
-+ crcnode.nodetype = cpu_to_je16( je16_to_cpu(node->nodetype) | JFFS2_NODE_ACCURATE);
-+ crcnode.totlen = node->totlen;
-+ hdr_crc = crc32(0, &crcnode, sizeof(crcnode)-4);
-+
-+ if (hdr_crc != je32_to_cpu(node->hdr_crc)) {
- noisy_printk(&noise, "jffs2_scan_eraseblock(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)\n",
-- ofs, node.magic, node.nodetype, node.totlen, node.hdr_crc, hdr_crc);
-+ ofs, je16_to_cpu(node->magic),
-+ je16_to_cpu(node->nodetype),
-+ je32_to_cpu(node->totlen),
-+ je32_to_cpu(node->hdr_crc),
-+ hdr_crc);
- DIRTY_SPACE(4);
- ofs += 4;
- continue;
- }
-
-- if (ofs + node.totlen > jeb->offset + c->sector_size) {
-+ if (ofs + je32_to_cpu(node->totlen) >
-+ jeb->offset + c->sector_size) {
- /* Eep. Node goes over the end of the erase block. */
- printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
-- ofs, node.totlen);
-+ ofs, je32_to_cpu(node->totlen));
- printk(KERN_WARNING "Perhaps the file system was created with the wrong erase size?\n");
- DIRTY_SPACE(4);
- ofs += 4;
- continue;
- }
-
-- switch(node.nodetype | JFFS2_NODE_ACCURATE) {
-+ if (!(je16_to_cpu(node->nodetype) & JFFS2_NODE_ACCURATE)) {
-+ /* Wheee. This is an obsoleted node */
-+ D2(printk(KERN_DEBUG "Node at 0x%08x is obsolete. Skipping\n", ofs));
-+ DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
-+ ofs += PAD(je32_to_cpu(node->totlen));
-+ continue;
-+ }
-+
-+ switch(je16_to_cpu(node->nodetype)) {
- case JFFS2_NODETYPE_INODE:
-- err = jffs2_scan_inode_node(c, jeb, &ofs);
-+ if (buf_ofs + buf_len < ofs + sizeof(struct jffs2_raw_inode)) {
-+ buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
-+ D1(printk(KERN_DEBUG "Fewer than %zd bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n",
-+ sizeof(struct jffs2_raw_inode), buf_len, ofs));
-+ err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
-+ if (err)
-+ return err;
-+ buf_ofs = ofs;
-+ node = (void *)buf;
-+ }
-+ err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs);
- if (err) return err;
-+ ofs += PAD(je32_to_cpu(node->totlen));
- break;
-
- case JFFS2_NODETYPE_DIRENT:
-- err = jffs2_scan_dirent_node(c, jeb, &ofs);
-+ if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
-+ buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
-+ D1(printk(KERN_DEBUG "Fewer than %d bytes (dirent node) left to end of buf. Reading 0x%x at 0x%08x\n",
-+ je32_to_cpu(node->totlen), buf_len, ofs));
-+ err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
-+ if (err)
-+ return err;
-+ buf_ofs = ofs;
-+ node = (void *)buf;
-+ }
-+ err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs);
- if (err) return err;
-+ ofs += PAD(je32_to_cpu(node->totlen));
- break;
-
- case JFFS2_NODETYPE_CLEANMARKER:
-- if (node.totlen != sizeof(struct jffs2_unknown_node)) {
-+ D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs));
-+ if (je32_to_cpu(node->totlen) != c->cleanmarker_size) {
- printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n",
-- ofs, node.totlen, sizeof(struct jffs2_unknown_node));
-+ ofs, je32_to_cpu(node->totlen), c->cleanmarker_size);
- DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
-+ ofs += PAD(sizeof(struct jffs2_unknown_node));
- } else if (jeb->first_node) {
- printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)\n", ofs, jeb->offset);
- DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
- ofs += PAD(sizeof(struct jffs2_unknown_node));
-- continue;
- } else {
- struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref();
- if (!marker_ref) {
-@@ -300,98 +572,80 @@
- }
- marker_ref->next_in_ino = NULL;
- marker_ref->next_phys = NULL;
-- marker_ref->flash_offset = ofs;
-- marker_ref->totlen = sizeof(struct jffs2_unknown_node);
-+ marker_ref->flash_offset = ofs | REF_NORMAL;
-+ marker_ref->__totlen = c->cleanmarker_size;
- jeb->first_node = jeb->last_node = marker_ref;
-
-- USED_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
-+ USED_SPACE(PAD(c->cleanmarker_size));
-+ ofs += PAD(c->cleanmarker_size);
- }
-- ofs += PAD(sizeof(struct jffs2_unknown_node));
-+ break;
-+
-+ case JFFS2_NODETYPE_PADDING:
-+ DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
-+ ofs += PAD(je32_to_cpu(node->totlen));
- break;
-
- default:
-- switch (node.nodetype & JFFS2_COMPAT_MASK) {
-+ switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) {
- case JFFS2_FEATURE_ROCOMPAT:
-- printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs);
-+ printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
- c->flags |= JFFS2_SB_FLAG_RO;
-- if (!(OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY))
-+ if (!(jffs2_is_readonly(c)))
- return -EROFS;
-- DIRTY_SPACE(PAD(node.totlen));
-- ofs += PAD(node.totlen);
-- continue;
-+ DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
-+ ofs += PAD(je32_to_cpu(node->totlen));
-+ break;
-
- case JFFS2_FEATURE_INCOMPAT:
-- printk(KERN_NOTICE "Incompatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs);
-+ printk(KERN_NOTICE "Incompatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
- return -EINVAL;
-
- case JFFS2_FEATURE_RWCOMPAT_DELETE:
-- printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs);
-- DIRTY_SPACE(PAD(node.totlen));
-- ofs += PAD(node.totlen);
-+ D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
-+ DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
-+ ofs += PAD(je32_to_cpu(node->totlen));
- break;
-
- case JFFS2_FEATURE_RWCOMPAT_COPY:
-- printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs);
-- USED_SPACE(PAD(node.totlen));
-- ofs += PAD(node.totlen);
-+ D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
-+ USED_SPACE(PAD(je32_to_cpu(node->totlen)));
-+ ofs += PAD(je32_to_cpu(node->totlen));
- break;
- }
- }
- }
-- D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, used 0x%08x\n", jeb->offset,
-- jeb->free_size, jeb->dirty_size, jeb->used_size));
-- return 0;
--}
-
--/* We're pointing at the first empty word on the flash. Scan and account for the whole dirty region */
--static int jffs2_scan_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *startofs, int *noise)
--{
-- __u32 *buf;
-- __u32 scanlen = (jeb->offset + c->sector_size) - *startofs;
-- __u32 curofs = *startofs;
-
-- buf = kmalloc(min((__u32)PAGE_SIZE, scanlen), GFP_KERNEL);
-- if (!buf) {
-- printk(KERN_WARNING "Scan buffer allocation failed\n");
-- return -ENOMEM;
-- }
-- while(scanlen) {
-- ssize_t retlen;
-- int ret, i;
-+ D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset,
-+ jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size));
-
-- ret = c->mtd->read(c->mtd, curofs, min((__u32)PAGE_SIZE, scanlen), &retlen, (char *)buf);
-- if(ret) {
-- D1(printk(KERN_WARNING "jffs2_scan_empty(): Read 0x%x bytes at 0x%08x returned %d\n", min((__u32)PAGE_SIZE, scanlen), curofs, ret));
-- kfree(buf);
-- return ret;
-- }
-- if (retlen < 4) {
-- D1(printk(KERN_WARNING "Eep. too few bytes read in scan_empty()\n"));
-- kfree(buf);
-- return -EIO;
-+ /* mark_node_obsolete can add to wasted !! */
-+ if (jeb->wasted_size) {
-+ jeb->dirty_size += jeb->wasted_size;
-+ c->dirty_size += jeb->wasted_size;
-+ c->wasted_size -= jeb->wasted_size;
-+ jeb->wasted_size = 0;
- }
-- for (i=0; i<(retlen / 4); i++) {
-- if (buf[i] != 0xffffffff) {
-- curofs += i*4;
-
-- noisy_printk(noise, "jffs2_scan_empty(): Empty block at 0x%08x ends at 0x%08x (with 0x%08x)! Marking dirty\n", *startofs, curofs, buf[i]);
-- DIRTY_SPACE(curofs - (*startofs));
-- *startofs = curofs;
-- kfree(buf);
-- return 0;
-- }
-- }
-- scanlen -= retlen&~3;
-- curofs += retlen&~3;
-- }
-+ if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size
-+ && (!jeb->first_node || !jeb->first_node->next_phys) )
-+ return BLK_STATE_CLEANMARKER;
-
-- D1(printk(KERN_DEBUG "Empty flash detected from 0x%08x to 0x%08x\n", *startofs, curofs));
-- kfree(buf);
-- *startofs = curofs;
-- return 0;
-+ /* move blocks with max 4 byte dirty space to cleanlist */
-+ else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) {
-+ c->dirty_size -= jeb->dirty_size;
-+ c->wasted_size += jeb->dirty_size;
-+ jeb->wasted_size += jeb->dirty_size;
-+ jeb->dirty_size = 0;
-+ return BLK_STATE_CLEAN;
-+ } else if (jeb->used_size || jeb->unchecked_size)
-+ return BLK_STATE_PARTDIRTY;
-+ else
-+ return BLK_STATE_ALLDIRTY;
- }
-
--static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, __u32 ino)
-+static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
- {
- struct jffs2_inode_cache *ic;
-
-@@ -399,137 +653,77 @@
- if (ic)
- return ic;
-
-+ if (ino > c->highest_ino)
-+ c->highest_ino = ino;
-+
- ic = jffs2_alloc_inode_cache();
- if (!ic) {
- printk(KERN_NOTICE "jffs2_scan_make_inode_cache(): allocation of inode cache failed\n");
- return NULL;
- }
- memset(ic, 0, sizeof(*ic));
-- ic->scan = kmalloc(sizeof(struct jffs2_scan_info), GFP_KERNEL);
-- if (!ic->scan) {
-- printk(KERN_NOTICE "jffs2_scan_make_inode_cache(): allocation of scan info for inode cache failed\n");
-- jffs2_free_inode_cache(ic);
-- return NULL;
-- }
-- memset(ic->scan, 0, sizeof(*ic->scan));
-+
- ic->ino = ino;
- ic->nodes = (void *)ic;
- jffs2_add_ino_cache(c, ic);
- if (ino == 1)
-- ic->nlink=1;
-+ ic->nlink = 1;
- return ic;
- }
-
--static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs)
-+static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-+ struct jffs2_raw_inode *ri, uint32_t ofs)
- {
- struct jffs2_raw_node_ref *raw;
-- struct jffs2_full_dnode *fn;
-- struct jffs2_tmp_dnode_info *tn, **tn_list;
- struct jffs2_inode_cache *ic;
-- struct jffs2_raw_inode ri;
-- __u32 crc;
-- __u16 oldnodetype;
-- int ret;
-- ssize_t retlen;
--
-- D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", *ofs));
--
-- ret = c->mtd->read(c->mtd, *ofs, sizeof(ri), &retlen, (char *)&ri);
-- if (ret) {
-- printk(KERN_NOTICE "jffs2_scan_inode_node(): Read error at 0x%08x: %d\n", *ofs, ret);
-- return ret;
-- }
-- if (retlen != sizeof(ri)) {
-- printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n",
-- retlen, *ofs, sizeof(ri));
-- return -EIO;
-- }
--
-- /* We sort of assume that the node was accurate when it was
-- first written to the medium :) */
-- oldnodetype = ri.nodetype;
-- ri.nodetype |= JFFS2_NODE_ACCURATE;
-- crc = crc32(0, &ri, sizeof(ri)-8);
-- ri.nodetype = oldnodetype;
--
-- if(crc != ri.node_crc) {
-- printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-- *ofs, ri.node_crc, crc);
-- /* FIXME: Why do we believe totlen? */
-- DIRTY_SPACE(4);
-- *ofs += 4;
-- return 0;
-- }
-- /* There was a bug where we wrote hole nodes out with csize/dsize
-- swapped. Deal with it */
-- if (ri.compr == JFFS2_COMPR_ZERO && !ri.dsize && ri.csize) {
-- ri.dsize = ri.csize;
-- ri.csize = 0;
-- }
-+ uint32_t ino = je32_to_cpu(ri->ino);
-
-- if (ri.csize) {
-- /* Check data CRC too */
-- unsigned char *dbuf;
-- __u32 crc;
-+ D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs));
-
-- dbuf = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
-- if (!dbuf) {
-- printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of temporary data buffer for CRC check failed\n");
-- return -ENOMEM;
-- }
-- ret = c->mtd->read(c->mtd, *ofs+sizeof(ri), ri.csize, &retlen, dbuf);
-- if (ret) {
-- printk(KERN_NOTICE "jffs2_scan_inode_node(): Read error at 0x%08x: %d\n", *ofs+sizeof(ri), ret);
-- kfree(dbuf);
-- return ret;
-- }
-- if (retlen != ri.csize) {
-- printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n",
-- retlen, *ofs+ sizeof(ri), ri.csize);
-- kfree(dbuf);
-- return -EIO;
-- }
-- crc = crc32(0, dbuf, ri.csize);
-- kfree(dbuf);
-- if (crc != ri.data_crc) {
-- printk(KERN_NOTICE "jffs2_scan_inode_node(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-- *ofs, ri.data_crc, crc);
-- DIRTY_SPACE(PAD(ri.totlen));
-- *ofs += PAD(ri.totlen);
-- return 0;
-- }
-- }
-+ /* We do very little here now. Just check the ino# to which we should attribute
-+ this node; we can do all the CRC checking etc. later. There's a tradeoff here --
-+ we used to scan the flash once only, reading everything we want from it into
-+ memory, then building all our in-core data structures and freeing the extra
-+ information. Now we allow the first part of the mount to complete a lot quicker,
-+ but we have to go _back_ to the flash in order to finish the CRC checking, etc.
-+ Which means that the _full_ amount of time to get to proper write mode with GC
-+ operational may actually be _longer_ than before. Sucks to be me. */
-
-- /* Wheee. It worked */
- raw = jffs2_alloc_raw_node_ref();
- if (!raw) {
- printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of node reference failed\n");
- return -ENOMEM;
- }
-- tn = jffs2_alloc_tmp_dnode_info();
-- if (!tn) {
-- jffs2_free_raw_node_ref(raw);
-- return -ENOMEM;
-- }
-- fn = jffs2_alloc_full_dnode();
-- if (!fn) {
-- jffs2_free_tmp_dnode_info(tn);
-+
-+ ic = jffs2_get_ino_cache(c, ino);
-+ if (!ic) {
-+ /* Inocache get failed. Either we read a bogus ino# or it's just genuinely the
-+ first node we found for this inode. Do a CRC check to protect against the former
-+ case */
-+ uint32_t crc = crc32(0, ri, sizeof(*ri)-8);
-+
-+ if (crc != je32_to_cpu(ri->node_crc)) {
-+ printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-+ ofs, je32_to_cpu(ri->node_crc), crc);
-+ /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
-+ DIRTY_SPACE(PAD(je32_to_cpu(ri->totlen)));
- jffs2_free_raw_node_ref(raw);
-- return -ENOMEM;
-+ return 0;
- }
-- ic = jffs2_scan_make_ino_cache(c, ri.ino);
-+ ic = jffs2_scan_make_ino_cache(c, ino);
- if (!ic) {
-- jffs2_free_full_dnode(fn);
-- jffs2_free_tmp_dnode_info(tn);
- jffs2_free_raw_node_ref(raw);
- return -ENOMEM;
- }
-+ }
-
-- /* Build the data structures and file them for later */
-- raw->flash_offset = *ofs;
-- raw->totlen = PAD(ri.totlen);
-+ /* Wheee. It worked */
-+
-+ raw->flash_offset = ofs | REF_UNCHECKED;
-+ raw->__totlen = PAD(je32_to_cpu(ri->totlen));
- raw->next_phys = NULL;
- raw->next_in_ino = ic->nodes;
-+
- ic->nodes = raw;
- if (!jeb->first_node)
- jeb->first_node = raw;
-@@ -538,134 +732,56 @@
- jeb->last_node = raw;
-
- D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n",
-- ri.ino, ri.version, ri.offset, ri.offset+ri.dsize));
--
-- pseudo_random += ri.version;
--
-- for (tn_list = &ic->scan->tmpnodes; *tn_list; tn_list = &((*tn_list)->next)) {
-- if ((*tn_list)->version < ri.version)
-- continue;
-- if ((*tn_list)->version > ri.version)
-- break;
-- /* Wheee. We've found another instance of the same version number.
-- We should obsolete one of them.
-- */
-- D1(printk(KERN_DEBUG "Duplicate version %d found in ino #%u. Previous one is at 0x%08x\n", ri.version, ic->ino, (*tn_list)->fn->raw->flash_offset &~3));
-- if (!jeb->used_size) {
-- D1(printk(KERN_DEBUG "No valid nodes yet found in this eraseblock 0x%08x, so obsoleting the new instance at 0x%08x\n",
-- jeb->offset, raw->flash_offset & ~3));
-- ri.nodetype &= ~JFFS2_NODE_ACCURATE;
-- /* Perhaps we could also mark it as such on the medium. Maybe later */
-- }
-- break;
-- }
--
-- if (ri.nodetype & JFFS2_NODE_ACCURATE) {
-- memset(fn,0,sizeof(*fn));
--
-- fn->ofs = ri.offset;
-- fn->size = ri.dsize;
-- fn->frags = 0;
-- fn->raw = raw;
--
-- tn->next = NULL;
-- tn->fn = fn;
-- tn->version = ri.version;
--
-- USED_SPACE(PAD(ri.totlen));
-- jffs2_add_tn_to_list(tn, &ic->scan->tmpnodes);
-- /* Make sure the one we just added is the _last_ in the list
-- with this version number, so the older ones get obsoleted */
-- while (tn->next && tn->next->version == tn->version) {
-+ je32_to_cpu(ri->ino), je32_to_cpu(ri->version),
-+ je32_to_cpu(ri->offset),
-+ je32_to_cpu(ri->offset)+je32_to_cpu(ri->dsize)));
-
-- D1(printk(KERN_DEBUG "Shifting new node at 0x%08x after other node at 0x%08x for version %d in list\n",
-- fn->raw->flash_offset&~3, tn->next->fn->raw->flash_offset &~3, ri.version));
-+ pseudo_random += je32_to_cpu(ri->version);
-
-- if(tn->fn != fn)
-- BUG();
-- tn->fn = tn->next->fn;
-- tn->next->fn = fn;
-- tn = tn->next;
-- }
-- } else {
-- jffs2_free_full_dnode(fn);
-- jffs2_free_tmp_dnode_info(tn);
-- raw->flash_offset |= 1;
-- DIRTY_SPACE(PAD(ri.totlen));
-- }
-- *ofs += PAD(ri.totlen);
-+ UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen)));
- return 0;
- }
-
--static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs)
-+static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-+ struct jffs2_raw_dirent *rd, uint32_t ofs)
- {
- struct jffs2_raw_node_ref *raw;
- struct jffs2_full_dirent *fd;
- struct jffs2_inode_cache *ic;
-- struct jffs2_raw_dirent rd;
-- __u16 oldnodetype;
-- int ret;
-- __u32 crc;
-- ssize_t retlen;
--
-- D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", *ofs));
-+ uint32_t crc;
-
-- ret = c->mtd->read(c->mtd, *ofs, sizeof(rd), &retlen, (char *)&rd);
-- if (ret) {
-- printk(KERN_NOTICE "jffs2_scan_dirent_node(): Read error at 0x%08x: %d\n", *ofs, ret);
-- return ret;
-- }
-- if (retlen != sizeof(rd)) {
-- printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n",
-- retlen, *ofs, sizeof(rd));
-- return -EIO;
-- }
-+ D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", ofs));
-
-- /* We sort of assume that the node was accurate when it was
-- first written to the medium :) */
-- oldnodetype = rd.nodetype;
-- rd.nodetype |= JFFS2_NODE_ACCURATE;
-- crc = crc32(0, &rd, sizeof(rd)-8);
-- rd.nodetype = oldnodetype;
-+ /* We don't get here unless the node is still valid, so we don't have to
-+ mask in the ACCURATE bit any more. */
-+ crc = crc32(0, rd, sizeof(*rd)-8);
-
-- if (crc != rd.node_crc) {
-+ if (crc != je32_to_cpu(rd->node_crc)) {
- printk(KERN_NOTICE "jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-- *ofs, rd.node_crc, crc);
-- /* FIXME: Why do we believe totlen? */
-- DIRTY_SPACE(4);
-- *ofs += 4;
-+ ofs, je32_to_cpu(rd->node_crc), crc);
-+ /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
-+ DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen)));
- return 0;
- }
-
-- pseudo_random += rd.version;
-+ pseudo_random += je32_to_cpu(rd->version);
-
-- fd = jffs2_alloc_full_dirent(rd.nsize+1);
-+ fd = jffs2_alloc_full_dirent(rd->nsize+1);
- if (!fd) {
- return -ENOMEM;
--}
-- ret = c->mtd->read(c->mtd, *ofs + sizeof(rd), rd.nsize, &retlen, &fd->name[0]);
-- if (ret) {
-- jffs2_free_full_dirent(fd);
-- printk(KERN_NOTICE "jffs2_scan_dirent_node(): Read error at 0x%08x: %d\n",
-- *ofs + sizeof(rd), ret);
-- return ret;
- }
-- if (retlen != rd.nsize) {
-- jffs2_free_full_dirent(fd);
-- printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n",
-- retlen, *ofs + sizeof(rd), rd.nsize);
-- return -EIO;
-- }
-- crc = crc32(0, fd->name, rd.nsize);
-- if (crc != rd.name_crc) {
-+ memcpy(&fd->name, rd->name, rd->nsize);
-+ fd->name[rd->nsize] = 0;
-+
-+ crc = crc32(0, fd->name, rd->nsize);
-+ if (crc != je32_to_cpu(rd->name_crc)) {
- printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-- *ofs, rd.name_crc, crc);
-- fd->name[rd.nsize]=0;
-- D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, rd.ino));
-+ ofs, je32_to_cpu(rd->name_crc), crc);
-+ D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd->ino)));
- jffs2_free_full_dirent(fd);
- /* FIXME: Why do we believe totlen? */
-- DIRTY_SPACE(PAD(rd.totlen));
-- *ofs += PAD(rd.totlen);
-+ /* We believe totlen because the CRC on the node _header_ was OK, just the name failed. */
-+ DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen)));
- return 0;
- }
- raw = jffs2_alloc_raw_node_ref();
-@@ -674,15 +790,15 @@
- printk(KERN_NOTICE "jffs2_scan_dirent_node(): allocation of node reference failed\n");
- return -ENOMEM;
- }
-- ic = jffs2_scan_make_ino_cache(c, rd.pino);
-+ ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(rd->pino));
- if (!ic) {
- jffs2_free_full_dirent(fd);
- jffs2_free_raw_node_ref(raw);
- return -ENOMEM;
- }
-
-- raw->totlen = PAD(rd.totlen);
-- raw->flash_offset = *ofs;
-+ raw->__totlen = PAD(je32_to_cpu(rd->totlen));
-+ raw->flash_offset = ofs | REF_PRISTINE;
- raw->next_phys = NULL;
- raw->next_in_ino = ic->nodes;
- ic->nodes = raw;
-@@ -692,24 +808,15 @@
- jeb->last_node->next_phys = raw;
- jeb->last_node = raw;
-
-- if (rd.nodetype & JFFS2_NODE_ACCURATE) {
- fd->raw = raw;
- fd->next = NULL;
-- fd->version = rd.version;
-- fd->ino = rd.ino;
-- fd->name[rd.nsize]=0;
-- fd->nhash = full_name_hash(fd->name, rd.nsize);
-- fd->type = rd.type;
--
-- USED_SPACE(PAD(rd.totlen));
-- jffs2_add_fd_to_list(c, fd, &ic->scan->dents);
-- } else {
-- raw->flash_offset |= 1;
-- jffs2_free_full_dirent(fd);
-+ fd->version = je32_to_cpu(rd->version);
-+ fd->ino = je32_to_cpu(rd->ino);
-+ fd->nhash = full_name_hash(fd->name, rd->nsize);
-+ fd->type = rd->type;
-+ USED_SPACE(PAD(je32_to_cpu(rd->totlen)));
-+ jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
-
-- DIRTY_SPACE(PAD(rd.totlen));
-- }
-- *ofs += PAD(rd.totlen);
- return 0;
- }
-
-@@ -731,26 +838,90 @@
- struct list_head *n = head->next;
-
- list_del(head);
-- while(count--)
-+ while(count--) {
- n = n->next;
-+ }
- list_add(head, n);
- }
-
--static void jffs2_rotate_lists(struct jffs2_sb_info *c)
-+void jffs2_rotate_lists(struct jffs2_sb_info *c)
- {
- uint32_t x;
-+ uint32_t rotateby;
-
- x = count_list(&c->clean_list);
-- if (x)
-- rotate_list((&c->clean_list), pseudo_random % x);
-+ if (x) {
-+ rotateby = pseudo_random % x;
-+ D1(printk(KERN_DEBUG "Rotating clean_list by %d\n", rotateby));
-+
-+ rotate_list((&c->clean_list), rotateby);
-+
-+ D1(printk(KERN_DEBUG "Erase block at front of clean_list is at %08x\n",
-+ list_entry(c->clean_list.next, struct jffs2_eraseblock, list)->offset));
-+ } else {
-+ D1(printk(KERN_DEBUG "Not rotating empty clean_list\n"));
-+ }
-+
-+ x = count_list(&c->very_dirty_list);
-+ if (x) {
-+ rotateby = pseudo_random % x;
-+ D1(printk(KERN_DEBUG "Rotating very_dirty_list by %d\n", rotateby));
-+
-+ rotate_list((&c->very_dirty_list), rotateby);
-+
-+ D1(printk(KERN_DEBUG "Erase block at front of very_dirty_list is at %08x\n",
-+ list_entry(c->very_dirty_list.next, struct jffs2_eraseblock, list)->offset));
-+ } else {
-+ D1(printk(KERN_DEBUG "Not rotating empty very_dirty_list\n"));
-+ }
-
- x = count_list(&c->dirty_list);
-- if (x)
-- rotate_list((&c->dirty_list), pseudo_random % x);
-+ if (x) {
-+ rotateby = pseudo_random % x;
-+ D1(printk(KERN_DEBUG "Rotating dirty_list by %d\n", rotateby));
-
-- if (c->nr_erasing_blocks)
-- rotate_list((&c->erase_pending_list), pseudo_random % c->nr_erasing_blocks);
-+ rotate_list((&c->dirty_list), rotateby);
-
-- if (c->nr_free_blocks) /* Not that it should ever be zero */
-- rotate_list((&c->free_list), pseudo_random % c->nr_free_blocks);
-+ D1(printk(KERN_DEBUG "Erase block at front of dirty_list is at %08x\n",
-+ list_entry(c->dirty_list.next, struct jffs2_eraseblock, list)->offset));
-+ } else {
-+ D1(printk(KERN_DEBUG "Not rotating empty dirty_list\n"));
-+ }
-+
-+ x = count_list(&c->erasable_list);
-+ if (x) {
-+ rotateby = pseudo_random % x;
-+ D1(printk(KERN_DEBUG "Rotating erasable_list by %d\n", rotateby));
-+
-+ rotate_list((&c->erasable_list), rotateby);
-+
-+ D1(printk(KERN_DEBUG "Erase block at front of erasable_list is at %08x\n",
-+ list_entry(c->erasable_list.next, struct jffs2_eraseblock, list)->offset));
-+ } else {
-+ D1(printk(KERN_DEBUG "Not rotating empty erasable_list\n"));
-+ }
-+
-+ if (c->nr_erasing_blocks) {
-+ rotateby = pseudo_random % c->nr_erasing_blocks;
-+ D1(printk(KERN_DEBUG "Rotating erase_pending_list by %d\n", rotateby));
-+
-+ rotate_list((&c->erase_pending_list), rotateby);
-+
-+ D1(printk(KERN_DEBUG "Erase block at front of erase_pending_list is at %08x\n",
-+ list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list)->offset));
-+ } else {
-+ D1(printk(KERN_DEBUG "Not rotating empty erase_pending_list\n"));
-+ }
-+
-+ if (c->nr_free_blocks) {
-+ rotateby = pseudo_random % c->nr_free_blocks;
-+ D1(printk(KERN_DEBUG "Rotating free_list by %d\n", rotateby));
-+
-+ rotate_list((&c->free_list), rotateby);
-+
-+ D1(printk(KERN_DEBUG "Erase block at front of free_list is at %08x\n",
-+ list_entry(c->free_list.next, struct jffs2_eraseblock, list)->offset));
-+ } else {
-+ D1(printk(KERN_DEBUG "Not rotating empty free_list\n"));
-+ }
- }
---- /dev/null
-+++ linux-2.4.21/fs/jffs2/super-v24.c
-@@ -0,0 +1,170 @@
-+/*
-+ * JFFS2 -- Journalling Flash File System, Version 2.
-+ *
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
-+ *
-+ * Created by David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * For licensing information, see the file 'LICENCE' in this directory.
-+ *
-+ * $Id: super-v24.c,v 1.83 2005/02/09 09:23:54 pavlov Exp $
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/version.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/list.h>
-+#include <linux/fs.h>
-+#include <linux/jffs2.h>
-+#include <linux/pagemap.h>
-+#include <linux/mtd/mtd.h>
-+#include "compr.h"
-+#include "nodelist.h"
-+
-+#ifndef MTD_BLOCK_MAJOR
-+#define MTD_BLOCK_MAJOR 31
-+#endif
-+
-+static void jffs2_put_super (struct super_block *);
-+
-+static struct super_operations jffs2_super_operations =
-+{
-+ .read_inode = jffs2_read_inode,
-+ .put_super = jffs2_put_super,
-+ .write_super = jffs2_write_super,
-+ .statfs = jffs2_statfs,
-+ .remount_fs = jffs2_remount_fs,
-+ .clear_inode = jffs2_clear_inode,
-+ .dirty_inode = jffs2_dirty_inode,
-+};
-+
-+
-+static struct super_block *jffs2_read_super(struct super_block *sb, void *data, int silent)
-+{
-+ struct jffs2_sb_info *c;
-+ int ret;
-+
-+ D1(printk(KERN_DEBUG "jffs2: read_super for device %s\n", kdevname(sb->s_dev)));
-+
-+ if (major(sb->s_dev) != MTD_BLOCK_MAJOR) {
-+ if (!silent)
-+ printk(KERN_DEBUG "jffs2: attempt to mount non-MTD device %s\n", kdevname(sb->s_dev));
-+ return NULL;
-+ }
-+
-+ c = JFFS2_SB_INFO(sb);
-+ memset(c, 0, sizeof(*c));
-+
-+ sb->s_op = &jffs2_super_operations;
-+
-+ c->mtd = get_mtd_device(NULL, minor(sb->s_dev));
-+ if (!c->mtd) {
-+ D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", minor(sb->s_dev)));
-+ return NULL;
-+ }
-+
-+ ret = jffs2_do_fill_super(sb, data, silent);
-+ if (ret) {
-+ put_mtd_device(c->mtd);
-+ return NULL;
-+ }
-+
-+ return sb;
-+}
-+
-+static void jffs2_put_super (struct super_block *sb)
-+{
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-+
-+ D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
-+
-+
-+ if (!(sb->s_flags & MS_RDONLY))
-+ jffs2_stop_garbage_collect_thread(c);
-+ down(&c->alloc_sem);
-+ jffs2_flush_wbuf_pad(c);
-+ up(&c->alloc_sem);
-+ jffs2_free_ino_caches(c);
-+ jffs2_free_raw_node_refs(c);
-+ if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
-+ vfree(c->blocks);
-+ else
-+ kfree(c->blocks);
-+ jffs2_flash_cleanup(c);
-+ kfree(c->inocache_list);
-+ if (c->mtd->sync)
-+ c->mtd->sync(c->mtd);
-+ put_mtd_device(c->mtd);
-+
-+ D1(printk(KERN_DEBUG "jffs2_put_super returning\n"));
-+}
-+
-+static DECLARE_FSTYPE_DEV(jffs2_fs_type, "jffs2", jffs2_read_super);
-+
-+static int __init init_jffs2_fs(void)
-+{
-+ int ret;
-+
-+ printk(KERN_INFO "JFFS2 version 2.2."
-+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
-+ " (NAND)"
-+#endif
-+ " (C) 2001-2003 Red Hat, Inc.\n");
-+
-+#ifdef JFFS2_OUT_OF_KERNEL
-+ /* sanity checks. Could we do these at compile time? */
-+ if (sizeof(struct jffs2_sb_info) > sizeof (((struct super_block *)NULL)->u)) {
-+ printk(KERN_ERR "JFFS2 error: struct jffs2_sb_info (%d bytes) doesn't fit in the super_block union (%d bytes)\n",
-+ sizeof(struct jffs2_sb_info), sizeof (((struct super_block *)NULL)->u));
-+ return -EIO;
-+ }
-+
-+ if (sizeof(struct jffs2_inode_info) > sizeof (((struct inode *)NULL)->u)) {
-+ printk(KERN_ERR "JFFS2 error: struct jffs2_inode_info (%d bytes) doesn't fit in the inode union (%d bytes)\n",
-+ sizeof(struct jffs2_inode_info), sizeof (((struct inode *)NULL)->u));
-+ return -EIO;
-+ }
-+#endif
-+ ret = jffs2_compressors_init();
-+ if (ret) {
-+ printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n");
-+ goto out;
-+ }
-+ ret = jffs2_create_slab_caches();
-+ if (ret) {
-+ printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
-+ goto out_compressors;
-+ }
-+ ret = register_filesystem(&jffs2_fs_type);
-+ if (ret) {
-+ printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n");
-+ goto out_slab;
-+ }
-+ return 0;
-+
-+ out_slab:
-+ jffs2_destroy_slab_caches();
-+ out_compressors:
-+ jffs2_compressors_exit();
-+ out:
-+ return ret;
-+}
-+
-+static void __exit exit_jffs2_fs(void)
-+{
-+ jffs2_destroy_slab_caches();
-+ jffs2_compressors_exit();
-+ unregister_filesystem(&jffs2_fs_type);
-+}
-+
-+module_init(init_jffs2_fs);
-+module_exit(exit_jffs2_fs);
-+
-+MODULE_DESCRIPTION("The Journalling Flash File System, v2");
-+MODULE_AUTHOR("Red Hat, Inc.");
-+MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
-+ // the sake of this tag. It's Free Software.
---- linux-2.4.21/fs/jffs2/super.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/super.c
-@@ -1,291 +1,270 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: super.c,v 1.48.2.3 2002/10/11 09:04:44 dwmw2 Exp $
-+ * $Id: super.c,v 1.105 2005/02/09 09:23:54 pavlov Exp $
- *
- */
-
- #include <linux/config.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
--#include <linux/version.h>
- #include <linux/slab.h>
- #include <linux/init.h>
- #include <linux/list.h>
- #include <linux/fs.h>
-+#include <linux/mount.h>
- #include <linux/jffs2.h>
- #include <linux/pagemap.h>
- #include <linux/mtd/mtd.h>
--#include <linux/interrupt.h>
-+#include <linux/ctype.h>
-+#include <linux/namei.h>
-+#include "compr.h"
- #include "nodelist.h"
-
--#ifndef MTD_BLOCK_MAJOR
--#define MTD_BLOCK_MAJOR 31
--#endif
-+static void jffs2_put_super(struct super_block *);
-
--extern void jffs2_read_inode (struct inode *);
--void jffs2_put_super (struct super_block *);
--void jffs2_write_super (struct super_block *);
--static int jffs2_statfs (struct super_block *, struct statfs *);
--int jffs2_remount_fs (struct super_block *, int *, char *);
--extern void jffs2_clear_inode (struct inode *);
-+static kmem_cache_t *jffs2_inode_cachep;
-+
-+static struct inode *jffs2_alloc_inode(struct super_block *sb)
-+{
-+ struct jffs2_inode_info *ei;
-+ ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, SLAB_KERNEL);
-+ if (!ei)
-+ return NULL;
-+ return &ei->vfs_inode;
-+}
-+
-+static void jffs2_destroy_inode(struct inode *inode)
-+{
-+ kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode));
-+}
-+
-+static void jffs2_i_init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
-+{
-+ struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo;
-+
-+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-+ SLAB_CTOR_CONSTRUCTOR) {
-+ init_MUTEX_LOCKED(&ei->sem);
-+ inode_init_once(&ei->vfs_inode);
-+ }
-+}
-+
-+static int jffs2_sync_fs(struct super_block *sb, int wait)
-+{
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-+
-+ down(&c->alloc_sem);
-+ jffs2_flush_wbuf_pad(c);
-+ up(&c->alloc_sem);
-+ return 0;
-+}
-
- static struct super_operations jffs2_super_operations =
- {
-- read_inode: jffs2_read_inode,
--// delete_inode: jffs2_delete_inode,
-- put_super: jffs2_put_super,
-- write_super: jffs2_write_super,
-- statfs: jffs2_statfs,
-- remount_fs: jffs2_remount_fs,
-- clear_inode: jffs2_clear_inode
-+ .alloc_inode = jffs2_alloc_inode,
-+ .destroy_inode =jffs2_destroy_inode,
-+ .read_inode = jffs2_read_inode,
-+ .put_super = jffs2_put_super,
-+ .write_super = jffs2_write_super,
-+ .statfs = jffs2_statfs,
-+ .remount_fs = jffs2_remount_fs,
-+ .clear_inode = jffs2_clear_inode,
-+ .dirty_inode = jffs2_dirty_inode,
-+ .sync_fs = jffs2_sync_fs,
- };
-
--static int jffs2_statfs(struct super_block *sb, struct statfs *buf)
-+static int jffs2_sb_compare(struct super_block *sb, void *data)
- {
-+ struct jffs2_sb_info *p = data;
- struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-- unsigned long avail;
-
-- buf->f_type = JFFS2_SUPER_MAGIC;
-- buf->f_bsize = 1 << PAGE_SHIFT;
-- buf->f_blocks = c->flash_size >> PAGE_SHIFT;
-- buf->f_files = 0;
-- buf->f_ffree = 0;
-- buf->f_namelen = JFFS2_MAX_NAME_LEN;
-+ /* The superblocks are considered to be equivalent if the underlying MTD
-+ device is the same one */
-+ if (c->mtd == p->mtd) {
-+ D1(printk(KERN_DEBUG "jffs2_sb_compare: match on device %d (\"%s\")\n", p->mtd->index, p->mtd->name));
-+ return 1;
-+ } else {
-+ D1(printk(KERN_DEBUG "jffs2_sb_compare: No match, device %d (\"%s\"), device %d (\"%s\")\n",
-+ c->mtd->index, c->mtd->name, p->mtd->index, p->mtd->name));
-+ return 0;
-+ }
-+}
-
-- spin_lock_bh(&c->erase_completion_lock);
-+static int jffs2_sb_set(struct super_block *sb, void *data)
-+{
-+ struct jffs2_sb_info *p = data;
-
-- avail = c->dirty_size + c->free_size;
-- if (avail > c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE)
-- avail -= c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE;
-- else
-- avail = 0;
-+ /* For persistence of NFS exports etc. we use the same s_dev
-+ each time we mount the device, don't just use an anonymous
-+ device */
-+ sb->s_fs_info = p;
-+ p->os_priv = sb;
-+ sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, p->mtd->index);
-
-- buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT;
-+ return 0;
-+}
-
--#if CONFIG_JFFS2_FS_DEBUG > 0
-- printk(KERN_DEBUG "STATFS:\n");
-- printk(KERN_DEBUG "flash_size: %08x\n", c->flash_size);
-- printk(KERN_DEBUG "used_size: %08x\n", c->used_size);
-- printk(KERN_DEBUG "dirty_size: %08x\n", c->dirty_size);
-- printk(KERN_DEBUG "free_size: %08x\n", c->free_size);
-- printk(KERN_DEBUG "erasing_size: %08x\n", c->erasing_size);
-- printk(KERN_DEBUG "bad_size: %08x\n", c->bad_size);
-- printk(KERN_DEBUG "sector_size: %08x\n", c->sector_size);
-+static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type,
-+ int flags, const char *dev_name,
-+ void *data, struct mtd_info *mtd)
-+{
-+ struct super_block *sb;
-+ struct jffs2_sb_info *c;
-+ int ret;
-
-- if (c->nextblock) {
-- printk(KERN_DEBUG "nextblock: 0x%08x\n", c->nextblock->offset);
-- } else {
-- printk(KERN_DEBUG "nextblock: NULL\n");
-- }
-- if (c->gcblock) {
-- printk(KERN_DEBUG "gcblock: 0x%08x\n", c->gcblock->offset);
-- } else {
-- printk(KERN_DEBUG "gcblock: NULL\n");
-- }
-- if (list_empty(&c->clean_list)) {
-- printk(KERN_DEBUG "clean_list: empty\n");
-- } else {
-- struct list_head *this;
-+ c = kmalloc(sizeof(*c), GFP_KERNEL);
-+ if (!c)
-+ return ERR_PTR(-ENOMEM);
-+ memset(c, 0, sizeof(*c));
-+ c->mtd = mtd;
-
-- list_for_each(this, &c->clean_list) {
-- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-- printk(KERN_DEBUG "clean_list: %08x\n", jeb->offset);
-- }
-- }
-- if (list_empty(&c->dirty_list)) {
-- printk(KERN_DEBUG "dirty_list: empty\n");
-- } else {
-- struct list_head *this;
-+ sb = sget(fs_type, jffs2_sb_compare, jffs2_sb_set, c);
-
-- list_for_each(this, &c->dirty_list) {
-- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-- printk(KERN_DEBUG "dirty_list: %08x\n", jeb->offset);
-- }
-- }
-- if (list_empty(&c->erasing_list)) {
-- printk(KERN_DEBUG "erasing_list: empty\n");
-- } else {
-- struct list_head *this;
-+ if (IS_ERR(sb))
-+ goto out_put;
-
-- list_for_each(this, &c->erasing_list) {
-- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-- printk(KERN_DEBUG "erasing_list: %08x\n", jeb->offset);
-- }
-+ if (sb->s_root) {
-+ /* New mountpoint for JFFS2 which is already mounted */
-+ D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): Device %d (\"%s\") is already mounted\n",
-+ mtd->index, mtd->name));
-+ goto out_put;
- }
-- if (list_empty(&c->erase_pending_list)) {
-- printk(KERN_DEBUG "erase_pending_list: empty\n");
-- } else {
-- struct list_head *this;
-
-- list_for_each(this, &c->erase_pending_list) {
-- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-- printk(KERN_DEBUG "erase_pending_list: %08x\n", jeb->offset);
-- }
-- }
-- if (list_empty(&c->free_list)) {
-- printk(KERN_DEBUG "free_list: empty\n");
-- } else {
-- struct list_head *this;
-+ D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): New superblock for device %d (\"%s\")\n",
-+ mtd->index, mtd->name));
-
-- list_for_each(this, &c->free_list) {
-- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-- printk(KERN_DEBUG "free_list: %08x\n", jeb->offset);
-- }
-- }
-- if (list_empty(&c->bad_list)) {
-- printk(KERN_DEBUG "bad_list: empty\n");
-- } else {
-- struct list_head *this;
-+ sb->s_op = &jffs2_super_operations;
-+ sb->s_flags = flags | MS_NOATIME;
-
-- list_for_each(this, &c->bad_list) {
-- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-- printk(KERN_DEBUG "bad_list: %08x\n", jeb->offset);
-- }
-- }
-- if (list_empty(&c->bad_used_list)) {
-- printk(KERN_DEBUG "bad_used_list: empty\n");
-- } else {
-- struct list_head *this;
-+ ret = jffs2_do_fill_super(sb, data, (flags&MS_VERBOSE)?1:0);
-
-- list_for_each(this, &c->bad_used_list) {
-- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-- printk(KERN_DEBUG "bad_used_list: %08x\n", jeb->offset);
-- }
-+ if (ret) {
-+ /* Failure case... */
-+ up_write(&sb->s_umount);
-+ deactivate_super(sb);
-+ return ERR_PTR(ret);
- }
--#endif /* CONFIG_JFFS2_FS_DEBUG */
-
-- spin_unlock_bh(&c->erase_completion_lock);
-+ sb->s_flags |= MS_ACTIVE;
-+ return sb;
-
-+ out_put:
-+ kfree(c);
-+ put_mtd_device(mtd);
-
-- return 0;
-+ return sb;
- }
-
--static struct super_block *jffs2_read_super(struct super_block *sb, void *data, int silent)
-+static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type,
-+ int flags, const char *dev_name,
-+ void *data, int mtdnr)
- {
-- struct jffs2_sb_info *c;
-- struct inode *root_i;
-- int i;
--
-- D1(printk(KERN_DEBUG "jffs2: read_super for device %s\n", kdevname(sb->s_dev)));
-+ struct mtd_info *mtd;
-
-- if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) {
-- if (!silent)
-- printk(KERN_DEBUG "jffs2: attempt to mount non-MTD device %s\n", kdevname(sb->s_dev));
-- return NULL;
-+ mtd = get_mtd_device(NULL, mtdnr);
-+ if (!mtd) {
-+ D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", mtdnr));
-+ return ERR_PTR(-EINVAL);
- }
-
-- c = JFFS2_SB_INFO(sb);
-- memset(c, 0, sizeof(*c));
-+ return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd);
-+}
-
-- c->mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
-- if (!c->mtd) {
-- D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", MINOR(sb->s_dev)));
-- return NULL;
-+static struct super_block *jffs2_get_sb(struct file_system_type *fs_type,
-+ int flags, const char *dev_name,
-+ void *data)
-+{
-+ int err;
-+ struct nameidata nd;
-+ int mtdnr;
-+
-+ if (!dev_name)
-+ return ERR_PTR(-EINVAL);
-+
-+ D1(printk(KERN_DEBUG "jffs2_get_sb(): dev_name \"%s\"\n", dev_name));
-+
-+ /* The preferred way of mounting in future; especially when
-+ CONFIG_BLK_DEV is implemented - we specify the underlying
-+ MTD device by number or by name, so that we don't require
-+ block device support to be present in the kernel. */
-+
-+ /* FIXME: How to do the root fs this way? */
-+
-+ if (dev_name[0] == 'm' && dev_name[1] == 't' && dev_name[2] == 'd') {
-+ /* Probably mounting without the blkdev crap */
-+ if (dev_name[3] == ':') {
-+ struct mtd_info *mtd;
-+
-+ /* Mount by MTD device name */
-+ D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd:%%s, name \"%s\"\n", dev_name+4));
-+ for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) {
-+ mtd = get_mtd_device(NULL, mtdnr);
-+ if (mtd) {
-+ if (!strcmp(mtd->name, dev_name+4))
-+ return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd);
-+ put_mtd_device(mtd);
- }
-- c->sector_size = c->mtd->erasesize;
-- c->free_size = c->flash_size = c->mtd->size;
-- c->nr_blocks = c->mtd->size / c->mtd->erasesize;
-- c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
-- if (!c->blocks)
-- goto out_mtd;
-- for (i=0; i<c->nr_blocks; i++) {
-- INIT_LIST_HEAD(&c->blocks[i].list);
-- c->blocks[i].offset = i * c->sector_size;
-- c->blocks[i].free_size = c->sector_size;
-- c->blocks[i].dirty_size = 0;
-- c->blocks[i].used_size = 0;
-- c->blocks[i].first_node = NULL;
-- c->blocks[i].last_node = NULL;
- }
-+ printk(KERN_NOTICE "jffs2_get_sb(): MTD device with name \"%s\" not found.\n", dev_name+4);
-+ } else if (isdigit(dev_name[3])) {
-+ /* Mount by MTD device number name */
-+ char *endptr;
-
-- spin_lock_init(&c->nodelist_lock);
-- init_MUTEX(&c->alloc_sem);
-- init_waitqueue_head(&c->erase_wait);
-- spin_lock_init(&c->erase_completion_lock);
-- spin_lock_init(&c->inocache_lock);
-+ mtdnr = simple_strtoul(dev_name+3, &endptr, 0);
-+ if (!*endptr) {
-+ /* It was a valid number */
-+ D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd%%d, mtdnr %d\n", mtdnr));
-+ return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr);
-+ }
-+ }
-+ }
-
-- INIT_LIST_HEAD(&c->clean_list);
-- INIT_LIST_HEAD(&c->dirty_list);
-- INIT_LIST_HEAD(&c->erasing_list);
-- INIT_LIST_HEAD(&c->erase_pending_list);
-- INIT_LIST_HEAD(&c->erase_complete_list);
-- INIT_LIST_HEAD(&c->free_list);
-- INIT_LIST_HEAD(&c->bad_list);
-- INIT_LIST_HEAD(&c->bad_used_list);
-- c->highest_ino = 1;
-+ /* Try the old way - the hack where we allowed users to mount
-+ /dev/mtdblock$(n) but didn't actually _use_ the blkdev */
-
-- if (jffs2_build_filesystem(c)) {
-- D1(printk(KERN_DEBUG "build_fs failed\n"));
-- goto out_nodes;
-- }
-+ err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
-
-- sb->s_op = &jffs2_super_operations;
-+ D1(printk(KERN_DEBUG "jffs2_get_sb(): path_lookup() returned %d, inode %p\n",
-+ err, nd.dentry->d_inode));
-
-- D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n"));
-- root_i = iget(sb, 1);
-- if (is_bad_inode(root_i)) {
-- D1(printk(KERN_WARNING "get root inode failed\n"));
-- goto out_nodes;
-+ if (err)
-+ return ERR_PTR(err);
-+
-+ err = -EINVAL;
-+
-+ if (!S_ISBLK(nd.dentry->d_inode->i_mode))
-+ goto out;
-+
-+ if (nd.mnt->mnt_flags & MNT_NODEV) {
-+ err = -EACCES;
-+ goto out;
- }
-
-- D1(printk(KERN_DEBUG "jffs2_read_super(): d_alloc_root()\n"));
-- sb->s_root = d_alloc_root(root_i);
-- if (!sb->s_root)
-- goto out_root_i;
-+ if (imajor(nd.dentry->d_inode) != MTD_BLOCK_MAJOR) {
-+ if (!(flags & MS_VERBOSE)) /* Yes I mean this. Strangely */
-+ printk(KERN_NOTICE "Attempt to mount non-MTD device \"%s\" as JFFS2\n",
-+ dev_name);
-+ goto out;
-+ }
-
--#if LINUX_VERSION_CODE >= 0x20403
-- sb->s_maxbytes = 0xFFFFFFFF;
--#endif
-- sb->s_blocksize = PAGE_CACHE_SIZE;
-- sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
-- sb->s_magic = JFFS2_SUPER_MAGIC;
-- if (!(sb->s_flags & MS_RDONLY))
-- jffs2_start_garbage_collect_thread(c);
-- return sb;
-+ mtdnr = iminor(nd.dentry->d_inode);
-+ path_release(&nd);
-
-- out_root_i:
-- iput(root_i);
-- out_nodes:
-- jffs2_free_ino_caches(c);
-- jffs2_free_raw_node_refs(c);
-- kfree(c->blocks);
-- out_mtd:
-- put_mtd_device(c->mtd);
-- return NULL;
-+ return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr);
-+
-+out:
-+ path_release(&nd);
-+ return ERR_PTR(err);
- }
-
--void jffs2_put_super (struct super_block *sb)
-+static void jffs2_put_super (struct super_block *sb)
- {
- struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-
-@@ -293,83 +272,65 @@
-
- if (!(sb->s_flags & MS_RDONLY))
- jffs2_stop_garbage_collect_thread(c);
-+ down(&c->alloc_sem);
-+ jffs2_flush_wbuf_pad(c);
-+ up(&c->alloc_sem);
- jffs2_free_ino_caches(c);
- jffs2_free_raw_node_refs(c);
-+ if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
-+ vfree(c->blocks);
-+ else
- kfree(c->blocks);
-+ jffs2_flash_cleanup(c);
-+ kfree(c->inocache_list);
- if (c->mtd->sync)
- c->mtd->sync(c->mtd);
-- put_mtd_device(c->mtd);
-
- D1(printk(KERN_DEBUG "jffs2_put_super returning\n"));
- }
-
--int jffs2_remount_fs (struct super_block *sb, int *flags, char *data)
--{
-- struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
--
-- if (c->flags & JFFS2_SB_FLAG_RO && !(sb->s_flags & MS_RDONLY))
-- return -EROFS;
--
-- /* We stop if it was running, then restart if it needs to.
-- This also catches the case where it was stopped and this
-- is just a remount to restart it */
-- if (!(sb->s_flags & MS_RDONLY))
-- jffs2_stop_garbage_collect_thread(c);
--
-- if (!(*flags & MS_RDONLY))
-- jffs2_start_garbage_collect_thread(c);
--
-- sb->s_flags = (sb->s_flags & ~MS_RDONLY)|(*flags & MS_RDONLY);
--
-- return 0;
--}
--
--void jffs2_write_super (struct super_block *sb)
-+static void jffs2_kill_sb(struct super_block *sb)
- {
- struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-- sb->s_dirt = 0;
--
-- if (sb->s_flags & MS_RDONLY)
-- return;
--
-- jffs2_garbage_collect_trigger(c);
-- jffs2_erase_pending_blocks(c);
-- jffs2_mark_erased_blocks(c);
-+ generic_shutdown_super(sb);
-+ put_mtd_device(c->mtd);
-+ kfree(c);
- }
-
--
--static DECLARE_FSTYPE_DEV(jffs2_fs_type, "jffs2", jffs2_read_super);
-+static struct file_system_type jffs2_fs_type = {
-+ .owner = THIS_MODULE,
-+ .name = "jffs2",
-+ .get_sb = jffs2_get_sb,
-+ .kill_sb = jffs2_kill_sb,
-+};
-
- static int __init init_jffs2_fs(void)
- {
- int ret;
-
-- printk(KERN_NOTICE "JFFS2 version 2.1. (C) 2001 Red Hat, Inc., designed by Axis Communications AB.\n");
--
--#ifdef JFFS2_OUT_OF_KERNEL
-- /* sanity checks. Could we do these at compile time? */
-- if (sizeof(struct jffs2_sb_info) > sizeof (((struct super_block *)NULL)->u)) {
-- printk(KERN_ERR "JFFS2 error: struct jffs2_sb_info (%d bytes) doesn't fit in the super_block union (%d bytes)\n",
-- sizeof(struct jffs2_sb_info), sizeof (((struct super_block *)NULL)->u));
-- return -EIO;
-- }
--
-- if (sizeof(struct jffs2_inode_info) > sizeof (((struct inode *)NULL)->u)) {
-- printk(KERN_ERR "JFFS2 error: struct jffs2_inode_info (%d bytes) doesn't fit in the inode union (%d bytes)\n",
-- sizeof(struct jffs2_inode_info), sizeof (((struct inode *)NULL)->u));
-- return -EIO;
-- }
-+ printk(KERN_INFO "JFFS2 version 2.2."
-+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
-+ " (NAND)"
- #endif
-+ " (C) 2001-2003 Red Hat, Inc.\n");
-
-- ret = jffs2_zlib_init();
-+ jffs2_inode_cachep = kmem_cache_create("jffs2_i",
-+ sizeof(struct jffs2_inode_info),
-+ 0, SLAB_RECLAIM_ACCOUNT,
-+ jffs2_i_init_once, NULL);
-+ if (!jffs2_inode_cachep) {
-+ printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
-+ return -ENOMEM;
-+ }
-+ ret = jffs2_compressors_init();
- if (ret) {
-- printk(KERN_ERR "JFFS2 error: Failed to initialise zlib workspaces\n");
-+ printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n");
- goto out;
- }
- ret = jffs2_create_slab_caches();
- if (ret) {
- printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
-- goto out_zlib;
-+ goto out_compressors;
- }
- ret = register_filesystem(&jffs2_fs_type);
- if (ret) {
-@@ -380,17 +341,19 @@
-
- out_slab:
- jffs2_destroy_slab_caches();
-- out_zlib:
-- jffs2_zlib_exit();
-+ out_compressors:
-+ jffs2_compressors_exit();
- out:
-+ kmem_cache_destroy(jffs2_inode_cachep);
- return ret;
- }
-
- static void __exit exit_jffs2_fs(void)
- {
-- jffs2_destroy_slab_caches();
-- jffs2_zlib_exit();
- unregister_filesystem(&jffs2_fs_type);
-+ jffs2_destroy_slab_caches();
-+ jffs2_compressors_exit();
-+ kmem_cache_destroy(jffs2_inode_cachep);
- }
-
- module_init(init_jffs2_fs);
---- /dev/null
-+++ linux-2.4.21/fs/jffs2/symlink-v24.c
-@@ -0,0 +1,52 @@
-+/*
-+ * JFFS2 -- Journalling Flash File System, Version 2.
-+ *
-+ * Copyright (C) 2001, 2002 Red Hat, Inc.
-+ *
-+ * Created by David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * For licensing information, see the file 'LICENCE' in this directory.
-+ *
-+ * $Id: symlink-v24.c,v 1.17 2005/03/04 13:12:25 dedekind Exp $
-+ *
-+ */
-+
-+
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/fs.h>
-+#include "nodelist.h"
-+
-+int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen);
-+int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd);
-+
-+struct inode_operations jffs2_symlink_inode_operations =
-+{
-+ .readlink = jffs2_readlink,
-+ .follow_link = jffs2_follow_link,
-+ .setattr = jffs2_setattr
-+};
-+
-+int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen)
-+{
-+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
-+
-+ if (!f->dents) {
-+ printk(KERN_ERR "jffs2_readlink(): can't find symlink taerget\n");
-+ return -EIO;
-+ }
-+
-+ return vfs_readlink(dentry, buffer, buflen, (char *)f->dents);
-+}
-+
-+int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
-+{
-+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
-+
-+ if (!f->dents) {
-+ printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n");
-+ return -EIO;
-+ }
-+
-+ return vfs_follow_link(nd, (char *)f->dents);
-+}
---- linux-2.4.21/fs/jffs2/symlink.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/symlink.c
-@@ -3,35 +3,11 @@
- *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: symlink.c,v 1.5.2.1 2002/01/15 10:39:06 dwmw2 Exp $
-+ * $Id: symlink.c,v 1.16 2005/03/01 10:50:48 dedekind Exp $
- *
- */
-
-@@ -39,72 +15,49 @@
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/fs.h>
--#include <linux/jffs2.h>
-+#include <linux/namei.h>
- #include "nodelist.h"
-
--int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen);
--int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd);
-+static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd);
-
- struct inode_operations jffs2_symlink_inode_operations =
- {
-- readlink: jffs2_readlink,
-- follow_link: jffs2_follow_link,
-- setattr: jffs2_setattr
-+ .readlink = generic_readlink,
-+ .follow_link = jffs2_follow_link,
-+ .setattr = jffs2_setattr
- };
-
--static char *jffs2_getlink(struct dentry *dentry)
-+static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
- {
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
-- char *buf;
-- int ret;
-
-- down(&f->sem);
-- if (!f->metadata) {
-- up(&f->sem);
-- printk(KERN_NOTICE "No metadata for symlink inode #%lu\n", dentry->d_inode->i_ino);
-- return ERR_PTR(-EINVAL);
-- }
-- buf = kmalloc(f->metadata->size+1, GFP_USER);
-- if (!buf) {
-- up(&f->sem);
-- return ERR_PTR(-ENOMEM);
-- }
-- buf[f->metadata->size]=0;
-+ /*
-+ * We don't acquire the f->sem mutex here since the only data we
-+ * use is f->dents which in case of the symlink inode points to the
-+ * symlink's target path.
-+ *
-+ * 1. If we are here the inode has already built and f->dents has
-+ * to point to the target path.
-+ * 2. Nobody uses f->dents (if the inode is symlink's inode). The
-+ * exception is inode freeing function which frees f->dents. But
-+ * it can't be called while we are here and before VFS has
-+ * stopped using our f->dents string which we provide by means of
-+ * nd_set_link() call.
-+ */
-
-- ret = jffs2_read_dnode(JFFS2_SB_INFO(dentry->d_inode->i_sb), f->metadata, buf, 0, f->metadata->size);
-- up(&f->sem);
-- if (ret) {
-- kfree(buf);
-- return ERR_PTR(ret);
-+ if (!f->dents) {
-+ printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n");
-+ return -EIO;
- }
-- return buf;
--
--}
--int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen)
--{
-- unsigned char *kbuf;
-- int ret;
-+ D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->dents));
-
-- kbuf = jffs2_getlink(dentry);
-- if (IS_ERR(kbuf))
-- return PTR_ERR(kbuf);
-+ nd_set_link(nd, (char *)f->dents);
-
-- ret = vfs_readlink(dentry, buffer, buflen, kbuf);
-- kfree(kbuf);
-- return ret;
-+ /*
-+ * We unlock the f->sem mutex but VFS will use the f->dents string. This is safe
-+ * since the only way that may cause f->dents to be changed is iput() operation.
-+ * But VFS will not use f->dents after iput() has been called.
-+ */
-+ return 0;
- }
-
--int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
--{
-- unsigned char *buf;
-- int ret;
--
-- buf = jffs2_getlink(dentry);
--
-- if (IS_ERR(buf))
-- return PTR_ERR(buf);
--
-- ret = vfs_follow_link(nd, buf);
-- kfree(buf);
-- return ret;
--}
---- /dev/null
-+++ linux-2.4.21/fs/jffs2/wbuf.c
-@@ -0,0 +1,1240 @@
-+/*
-+ * JFFS2 -- Journalling Flash File System, Version 2.
-+ *
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
-+ * Copyright (C) 2004 Thomas Gleixner <tglx@linutronix.de>
-+ *
-+ * Created by David Woodhouse <dwmw2@infradead.org>
-+ * Modified debugged and enhanced by Thomas Gleixner <tglx@linutronix.de>
-+ *
-+ * For licensing information, see the file 'LICENCE' in this directory.
-+ *
-+ * $Id: wbuf.c,v 1.89 2005/02/09 09:23:54 pavlov Exp $
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/crc32.h>
-+#include <linux/mtd/nand.h>
-+#include "nodelist.h"
-+
-+/* For testing write failures */
-+#undef BREAKME
-+#undef BREAKMEHEADER
-+
-+#ifdef BREAKME
-+static unsigned char *brokenbuf;
-+#endif
-+
-+/* max. erase failures before we mark a block bad */
-+#define MAX_ERASE_FAILURES 2
-+
-+/* two seconds timeout for timed wbuf-flushing */
-+#define WBUF_FLUSH_TIMEOUT 2 * HZ
-+
-+struct jffs2_inodirty {
-+ uint32_t ino;
-+ struct jffs2_inodirty *next;
-+};
-+
-+static struct jffs2_inodirty inodirty_nomem;
-+
-+static int jffs2_wbuf_pending_for_ino(struct jffs2_sb_info *c, uint32_t ino)
-+{
-+ struct jffs2_inodirty *this = c->wbuf_inodes;
-+
-+ /* If a malloc failed, consider _everything_ dirty */
-+ if (this == &inodirty_nomem)
-+ return 1;
-+
-+ /* If ino == 0, _any_ non-GC writes mean 'yes' */
-+ if (this && !ino)
-+ return 1;
-+
-+ /* Look to see if the inode in question is pending in the wbuf */
-+ while (this) {
-+ if (this->ino == ino)
-+ return 1;
-+ this = this->next;
-+ }
-+ return 0;
-+}
-+
-+static void jffs2_clear_wbuf_ino_list(struct jffs2_sb_info *c)
-+{
-+ struct jffs2_inodirty *this;
-+
-+ this = c->wbuf_inodes;
-+
-+ if (this != &inodirty_nomem) {
-+ while (this) {
-+ struct jffs2_inodirty *next = this->next;
-+ kfree(this);
-+ this = next;
-+ }
-+ }
-+ c->wbuf_inodes = NULL;
-+}
-+
-+static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino)
-+{
-+ struct jffs2_inodirty *new;
-+
-+ /* Mark the superblock dirty so that kupdated will flush... */
-+ OFNI_BS_2SFFJ(c)->s_dirt = 1;
-+
-+ if (jffs2_wbuf_pending_for_ino(c, ino))
-+ return;
-+
-+ new = kmalloc(sizeof(*new), GFP_KERNEL);
-+ if (!new) {
-+ D1(printk(KERN_DEBUG "No memory to allocate inodirty. Fallback to all considered dirty\n"));
-+ jffs2_clear_wbuf_ino_list(c);
-+ c->wbuf_inodes = &inodirty_nomem;
-+ return;
-+ }
-+ new->ino = ino;
-+ new->next = c->wbuf_inodes;
-+ c->wbuf_inodes = new;
-+ return;
-+}
-+
-+static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c)
-+{
-+ struct list_head *this, *next;
-+ static int n;
-+
-+ if (list_empty(&c->erasable_pending_wbuf_list))
-+ return;
-+
-+ list_for_each_safe(this, next, &c->erasable_pending_wbuf_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+
-+ D1(printk(KERN_DEBUG "Removing eraseblock at 0x%08x from erasable_pending_wbuf_list...\n", jeb->offset));
-+ list_del(this);
-+ if ((jiffies + (n++)) & 127) {
-+ /* Most of the time, we just erase it immediately. Otherwise we
-+ spend ages scanning it on mount, etc. */
-+ D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n"));
-+ list_add_tail(&jeb->list, &c->erase_pending_list);
-+ c->nr_erasing_blocks++;
-+ jffs2_erase_pending_trigger(c);
-+ } else {
-+ /* Sometimes, however, we leave it elsewhere so it doesn't get
-+ immediately reused, and we spread the load a bit. */
-+ D1(printk(KERN_DEBUG "...and adding to erasable_list\n"));
-+ list_add_tail(&jeb->list, &c->erasable_list);
-+ }
-+ }
-+}
-+
-+#define REFILE_NOTEMPTY 0
-+#define REFILE_ANYWAY 1
-+
-+static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int allow_empty)
-+{
-+ D1(printk("About to refile bad block at %08x\n", jeb->offset));
-+
-+ D2(jffs2_dump_block_lists(c));
-+ /* File the existing block on the bad_used_list.... */
-+ if (c->nextblock == jeb)
-+ c->nextblock = NULL;
-+ else /* Not sure this should ever happen... need more coffee */
-+ list_del(&jeb->list);
-+ if (jeb->first_node) {
-+ D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset));
-+ list_add(&jeb->list, &c->bad_used_list);
-+ } else {
-+ BUG_ON(allow_empty == REFILE_NOTEMPTY);
-+ /* It has to have had some nodes or we couldn't be here */
-+ D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset));
-+ list_add(&jeb->list, &c->erase_pending_list);
-+ c->nr_erasing_blocks++;
-+ jffs2_erase_pending_trigger(c);
-+ }
-+ D2(jffs2_dump_block_lists(c));
-+
-+ /* Adjust its size counts accordingly */
-+ c->wasted_size += jeb->free_size;
-+ c->free_size -= jeb->free_size;
-+ jeb->wasted_size += jeb->free_size;
-+ jeb->free_size = 0;
-+
-+ ACCT_SANITY_CHECK(c,jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+}
-+
-+/* Recover from failure to write wbuf. Recover the nodes up to the
-+ * wbuf, not the one which we were starting to try to write. */
-+
-+static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
-+{
-+ struct jffs2_eraseblock *jeb, *new_jeb;
-+ struct jffs2_raw_node_ref **first_raw, **raw;
-+ size_t retlen;
-+ int ret;
-+ unsigned char *buf;
-+ uint32_t start, end, ofs, len;
-+
-+ spin_lock(&c->erase_completion_lock);
-+
-+ jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
-+
-+ jffs2_block_refile(c, jeb, REFILE_NOTEMPTY);
-+
-+ /* Find the first node to be recovered, by skipping over every
-+ node which ends before the wbuf starts, or which is obsolete. */
-+ first_raw = &jeb->first_node;
-+ while (*first_raw &&
-+ (ref_obsolete(*first_raw) ||
-+ (ref_offset(*first_raw)+ref_totlen(c, jeb, *first_raw)) < c->wbuf_ofs)) {
-+ D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n",
-+ ref_offset(*first_raw), ref_flags(*first_raw),
-+ (ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw)),
-+ c->wbuf_ofs));
-+ first_raw = &(*first_raw)->next_phys;
-+ }
-+
-+ if (!*first_raw) {
-+ /* All nodes were obsolete. Nothing to recover. */
-+ D1(printk(KERN_DEBUG "No non-obsolete nodes to be recovered. Just filing block bad\n"));
-+ spin_unlock(&c->erase_completion_lock);
-+ return;
-+ }
-+
-+ start = ref_offset(*first_raw);
-+ end = ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw);
-+
-+ /* Find the last node to be recovered */
-+ raw = first_raw;
-+ while ((*raw)) {
-+ if (!ref_obsolete(*raw))
-+ end = ref_offset(*raw) + ref_totlen(c, jeb, *raw);
-+
-+ raw = &(*raw)->next_phys;
-+ }
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ D1(printk(KERN_DEBUG "wbuf recover %08x-%08x\n", start, end));
-+
-+ buf = NULL;
-+ if (start < c->wbuf_ofs) {
-+ /* First affected node was already partially written.
-+ * Attempt to reread the old data into our buffer. */
-+
-+ buf = kmalloc(end - start, GFP_KERNEL);
-+ if (!buf) {
-+ printk(KERN_CRIT "Malloc failure in wbuf recovery. Data loss ensues.\n");
-+
-+ goto read_failed;
-+ }
-+
-+ /* Do the read... */
-+ if (jffs2_cleanmarker_oob(c))
-+ ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo);
-+ else
-+ ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf);
-+
-+ if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) {
-+ /* ECC recovered */
-+ ret = 0;
-+ }
-+ if (ret || retlen != c->wbuf_ofs - start) {
-+ printk(KERN_CRIT "Old data are already lost in wbuf recovery. Data loss ensues.\n");
-+
-+ kfree(buf);
-+ buf = NULL;
-+ read_failed:
-+ first_raw = &(*first_raw)->next_phys;
-+ /* If this was the only node to be recovered, give up */
-+ if (!(*first_raw))
-+ return;
-+
-+ /* It wasn't. Go on and try to recover nodes complete in the wbuf */
-+ start = ref_offset(*first_raw);
-+ } else {
-+ /* Read succeeded. Copy the remaining data from the wbuf */
-+ memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs);
-+ }
-+ }
-+ /* OK... we're to rewrite (end-start) bytes of data from first_raw onwards.
-+ Either 'buf' contains the data, or we find it in the wbuf */
-+
-+
-+ /* ... and get an allocation of space from a shiny new block instead */
-+ ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len);
-+ if (ret) {
-+ printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n");
-+ kfree(buf);
-+ return;
-+ }
-+ if (end-start >= c->wbuf_pagesize) {
-+ /* Need to do another write immediately, but it's possible
-+ that this is just because the wbuf itself is completely
-+ full, and there's nothing earlier read back from the
-+ flash. Hence 'buf' isn't necessarily what we're writing
-+ from. */
-+ unsigned char *rewrite_buf = buf?:c->wbuf;
-+ uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize);
-+
-+ D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n",
-+ towrite, ofs));
-+
-+#ifdef BREAKMEHEADER
-+ static int breakme;
-+ if (breakme++ == 20) {
-+ printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs);
-+ breakme = 0;
-+ c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
-+ brokenbuf, NULL, c->oobinfo);
-+ ret = -EIO;
-+ } else
-+#endif
-+ if (jffs2_cleanmarker_oob(c))
-+ ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
-+ rewrite_buf, NULL, c->oobinfo);
-+ else
-+ ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, rewrite_buf);
-+
-+ if (ret || retlen != towrite) {
-+ /* Argh. We tried. Really we did. */
-+ printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n");
-+ kfree(buf);
-+
-+ if (retlen) {
-+ struct jffs2_raw_node_ref *raw2;
-+
-+ raw2 = jffs2_alloc_raw_node_ref();
-+ if (!raw2)
-+ return;
-+
-+ raw2->flash_offset = ofs | REF_OBSOLETE;
-+ raw2->__totlen = ref_totlen(c, jeb, *first_raw);
-+ raw2->next_phys = NULL;
-+ raw2->next_in_ino = NULL;
-+
-+ jffs2_add_physical_node_ref(c, raw2);
-+ }
-+ return;
-+ }
-+ printk(KERN_NOTICE "Recovery of wbuf succeeded to %08x\n", ofs);
-+
-+ c->wbuf_len = (end - start) - towrite;
-+ c->wbuf_ofs = ofs + towrite;
-+ memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len);
-+ /* Don't muck about with c->wbuf_inodes. False positives are harmless. */
-+ if (buf)
-+ kfree(buf);
-+ } else {
-+ /* OK, now we're left with the dregs in whichever buffer we're using */
-+ if (buf) {
-+ memcpy(c->wbuf, buf, end-start);
-+ kfree(buf);
-+ } else {
-+ memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start);
-+ }
-+ c->wbuf_ofs = ofs;
-+ c->wbuf_len = end - start;
-+ }
-+
-+ /* Now sort out the jffs2_raw_node_refs, moving them from the old to the next block */
-+ new_jeb = &c->blocks[ofs / c->sector_size];
-+
-+ spin_lock(&c->erase_completion_lock);
-+ if (new_jeb->first_node) {
-+ /* Odd, but possible with ST flash later maybe */
-+ new_jeb->last_node->next_phys = *first_raw;
-+ } else {
-+ new_jeb->first_node = *first_raw;
-+ }
-+
-+ raw = first_raw;
-+ while (*raw) {
-+ uint32_t rawlen = ref_totlen(c, jeb, *raw);
-+
-+ D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n",
-+ rawlen, ref_offset(*raw), ref_flags(*raw), ofs));
-+
-+ if (ref_obsolete(*raw)) {
-+ /* Shouldn't really happen much */
-+ new_jeb->dirty_size += rawlen;
-+ new_jeb->free_size -= rawlen;
-+ c->dirty_size += rawlen;
-+ } else {
-+ new_jeb->used_size += rawlen;
-+ new_jeb->free_size -= rawlen;
-+ jeb->dirty_size += rawlen;
-+ jeb->used_size -= rawlen;
-+ c->dirty_size += rawlen;
-+ }
-+ c->free_size -= rawlen;
-+ (*raw)->flash_offset = ofs | ref_flags(*raw);
-+ ofs += rawlen;
-+ new_jeb->last_node = *raw;
-+
-+ raw = &(*raw)->next_phys;
-+ }
-+
-+ /* Fix up the original jeb now it's on the bad_list */
-+ *first_raw = NULL;
-+ if (first_raw == &jeb->first_node) {
-+ jeb->last_node = NULL;
-+ D1(printk(KERN_DEBUG "Failing block at %08x is now empty. Moving to erase_pending_list\n", jeb->offset));
-+ list_del(&jeb->list);
-+ list_add(&jeb->list, &c->erase_pending_list);
-+ c->nr_erasing_blocks++;
-+ jffs2_erase_pending_trigger(c);
-+ }
-+ else
-+ jeb->last_node = container_of(first_raw, struct jffs2_raw_node_ref, next_phys);
-+
-+ ACCT_SANITY_CHECK(c,jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+
-+ ACCT_SANITY_CHECK(c,new_jeb);
-+ D1(ACCT_PARANOIA_CHECK(new_jeb));
-+
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ D1(printk(KERN_DEBUG "wbuf recovery completed OK\n"));
-+}
-+
-+/* Meaning of pad argument:
-+ 0: Do not pad. Probably pointless - we only ever use this when we can't pad anyway.
-+ 1: Pad, do not adjust nextblock free_size
-+ 2: Pad, adjust nextblock free_size
-+*/
-+#define NOPAD 0
-+#define PAD_NOACCOUNT 1
-+#define PAD_ACCOUNTING 2
-+
-+static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
-+{
-+ int ret;
-+ size_t retlen;
-+
-+ /* Nothing to do if not write-buffering the flash. In particular, we shouldn't
-+ del_timer() the timer we never initialised. */
-+ if (!jffs2_is_writebuffered(c))
-+ return 0;
-+
-+ if (!down_trylock(&c->alloc_sem)) {
-+ up(&c->alloc_sem);
-+ printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n");
-+ BUG();
-+ }
-+
-+ if (!c->wbuf_len) /* already checked c->wbuf above */
-+ return 0;
-+
-+ /* claim remaining space on the page
-+ this happens, if we have a change to a new block,
-+ or if fsync forces us to flush the writebuffer.
-+ if we have a switch to next page, we will not have
-+ enough remaining space for this.
-+ */
-+ if (pad && !jffs2_dataflash(c)) {
-+ c->wbuf_len = PAD(c->wbuf_len);
-+
-+ /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR
-+ with 8 byte page size */
-+ memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len);
-+
-+ if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) {
-+ struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len);
-+ padnode->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ padnode->nodetype = cpu_to_je16(JFFS2_NODETYPE_PADDING);
-+ padnode->totlen = cpu_to_je32(c->wbuf_pagesize - c->wbuf_len);
-+ padnode->hdr_crc = cpu_to_je32(crc32(0, padnode, sizeof(*padnode)-4));
-+ }
-+ }
-+ /* else jffs2_flash_writev has actually filled in the rest of the
-+ buffer for us, and will deal with the node refs etc. later. */
-+
-+#ifdef BREAKME
-+ static int breakme;
-+ if (breakme++ == 20) {
-+ printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs);
-+ breakme = 0;
-+ c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize,
-+ &retlen, brokenbuf, NULL, c->oobinfo);
-+ ret = -EIO;
-+ } else
-+#endif
-+
-+ if (jffs2_cleanmarker_oob(c))
-+ ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo);
-+ else
-+ ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf);
-+
-+ if (ret || retlen != c->wbuf_pagesize) {
-+ if (ret)
-+ printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n",ret);
-+ else {
-+ printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
-+ retlen, c->wbuf_pagesize);
-+ ret = -EIO;
-+ }
-+
-+ jffs2_wbuf_recover(c);
-+
-+ return ret;
-+ }
-+
-+ spin_lock(&c->erase_completion_lock);
-+
-+ /* Adjust free size of the block if we padded. */
-+ if (pad && !jffs2_dataflash(c)) {
-+ struct jffs2_eraseblock *jeb;
-+
-+ jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
-+
-+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n",
-+ (jeb==c->nextblock)?"next":"", jeb->offset));
-+
-+ /* wbuf_pagesize - wbuf_len is the amount of space that's to be
-+ padded. If there is less free space in the block than that,
-+ something screwed up */
-+ if (jeb->free_size < (c->wbuf_pagesize - c->wbuf_len)) {
-+ printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n",
-+ c->wbuf_ofs, c->wbuf_len, c->wbuf_pagesize-c->wbuf_len);
-+ printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n",
-+ jeb->offset, jeb->free_size);
-+ BUG();
-+ }
-+ jeb->free_size -= (c->wbuf_pagesize - c->wbuf_len);
-+ c->free_size -= (c->wbuf_pagesize - c->wbuf_len);
-+ jeb->wasted_size += (c->wbuf_pagesize - c->wbuf_len);
-+ c->wasted_size += (c->wbuf_pagesize - c->wbuf_len);
-+ }
-+
-+ /* Stick any now-obsoleted blocks on the erase_pending_list */
-+ jffs2_refile_wbuf_blocks(c);
-+ jffs2_clear_wbuf_ino_list(c);
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ memset(c->wbuf,0xff,c->wbuf_pagesize);
-+ /* adjust write buffer offset, else we get a non contiguous write bug */
-+ c->wbuf_ofs += c->wbuf_pagesize;
-+ c->wbuf_len = 0;
-+ return 0;
-+}
-+
-+/* Trigger garbage collection to flush the write-buffer.
-+ If ino arg is zero, do it if _any_ real (i.e. not GC) writes are
-+ outstanding. If ino arg non-zero, do it only if a write for the
-+ given inode is outstanding. */
-+int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
-+{
-+ uint32_t old_wbuf_ofs;
-+ uint32_t old_wbuf_len;
-+ int ret = 0;
-+
-+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino));
-+
-+ if (!c->wbuf)
-+ return 0;
-+
-+ down(&c->alloc_sem);
-+ if (!jffs2_wbuf_pending_for_ino(c, ino)) {
-+ D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino));
-+ up(&c->alloc_sem);
-+ return 0;
-+ }
-+
-+ old_wbuf_ofs = c->wbuf_ofs;
-+ old_wbuf_len = c->wbuf_len;
-+
-+ if (c->unchecked_size) {
-+ /* GC won't make any progress for a while */
-+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n"));
-+ down_write(&c->wbuf_sem);
-+ ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
-+ /* retry flushing wbuf in case jffs2_wbuf_recover
-+ left some data in the wbuf */
-+ if (ret)
-+ ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
-+ up_write(&c->wbuf_sem);
-+ } else while (old_wbuf_len &&
-+ old_wbuf_ofs == c->wbuf_ofs) {
-+
-+ up(&c->alloc_sem);
-+
-+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() calls gc pass\n"));
-+
-+ ret = jffs2_garbage_collect_pass(c);
-+ if (ret) {
-+ /* GC failed. Flush it with padding instead */
-+ down(&c->alloc_sem);
-+ down_write(&c->wbuf_sem);
-+ ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
-+ /* retry flushing wbuf in case jffs2_wbuf_recover
-+ left some data in the wbuf */
-+ if (ret)
-+ ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
-+ up_write(&c->wbuf_sem);
-+ break;
-+ }
-+ down(&c->alloc_sem);
-+ }
-+
-+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() ends...\n"));
-+
-+ up(&c->alloc_sem);
-+ return ret;
-+}
-+
-+/* Pad write-buffer to end and write it, wasting space. */
-+int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c)
-+{
-+ int ret;
-+
-+ if (!c->wbuf)
-+ return 0;
-+
-+ down_write(&c->wbuf_sem);
-+ ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
-+ /* retry - maybe wbuf recover left some data in wbuf. */
-+ if (ret)
-+ ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
-+ up_write(&c->wbuf_sem);
-+
-+ return ret;
-+}
-+
-+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
-+#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) )
-+#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) )
-+#else
-+#define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) )
-+#define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) )
-+#endif
-+
-+int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino)
-+{
-+ struct kvec outvecs[3];
-+ uint32_t totlen = 0;
-+ uint32_t split_ofs = 0;
-+ uint32_t old_totlen;
-+ int ret, splitvec = -1;
-+ int invec, outvec;
-+ size_t wbuf_retlen;
-+ unsigned char *wbuf_ptr;
-+ size_t donelen = 0;
-+ uint32_t outvec_to = to;
-+
-+ /* If not NAND flash, don't bother */
-+ if (!jffs2_is_writebuffered(c))
-+ return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
-+
-+ down_write(&c->wbuf_sem);
-+
-+ /* If wbuf_ofs is not initialized, set it to target address */
-+ if (c->wbuf_ofs == 0xFFFFFFFF) {
-+ c->wbuf_ofs = PAGE_DIV(to);
-+ c->wbuf_len = PAGE_MOD(to);
-+ memset(c->wbuf,0xff,c->wbuf_pagesize);
-+ }
-+
-+ /* Fixup the wbuf if we are moving to a new eraseblock. The checks below
-+ fail for ECC'd NOR because cleanmarker == 16, so a block starts at
-+ xxx0010. */
-+ if (jffs2_nor_ecc(c)) {
-+ if (((c->wbuf_ofs % c->sector_size) == 0) && !c->wbuf_len) {
-+ c->wbuf_ofs = PAGE_DIV(to);
-+ c->wbuf_len = PAGE_MOD(to);
-+ memset(c->wbuf,0xff,c->wbuf_pagesize);
-+ }
-+ }
-+
-+ /* Sanity checks on target address.
-+ It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs),
-+ and it's permitted to write at the beginning of a new
-+ erase block. Anything else, and you die.
-+ New block starts at xxx000c (0-b = block header)
-+ */
-+ if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) {
-+ /* It's a write to a new block */
-+ if (c->wbuf_len) {
-+ D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs));
-+ ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
-+ if (ret) {
-+ /* the underlying layer has to check wbuf_len to do the cleanup */
-+ D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));
-+ *retlen = 0;
-+ goto exit;
-+ }
-+ }
-+ /* set pointer to new block */
-+ c->wbuf_ofs = PAGE_DIV(to);
-+ c->wbuf_len = PAGE_MOD(to);
-+ }
-+
-+ if (to != PAD(c->wbuf_ofs + c->wbuf_len)) {
-+ /* We're not writing immediately after the writebuffer. Bad. */
-+ printk(KERN_CRIT "jffs2_flash_writev(): Non-contiguous write to %08lx\n", (unsigned long)to);
-+ if (c->wbuf_len)
-+ printk(KERN_CRIT "wbuf was previously %08x-%08x\n",
-+ c->wbuf_ofs, c->wbuf_ofs+c->wbuf_len);
-+ BUG();
-+ }
-+
-+ /* Note outvecs[3] above. We know count is never greater than 2 */
-+ if (count > 2) {
-+ printk(KERN_CRIT "jffs2_flash_writev(): count is %ld\n", count);
-+ BUG();
-+ }
-+
-+ invec = 0;
-+ outvec = 0;
-+
-+ /* Fill writebuffer first, if already in use */
-+ if (c->wbuf_len) {
-+ uint32_t invec_ofs = 0;
-+
-+ /* adjust alignment offset */
-+ if (c->wbuf_len != PAGE_MOD(to)) {
-+ c->wbuf_len = PAGE_MOD(to);
-+ /* take care of alignment to next page */
-+ if (!c->wbuf_len)
-+ c->wbuf_len = c->wbuf_pagesize;
-+ }
-+
-+ while(c->wbuf_len < c->wbuf_pagesize) {
-+ uint32_t thislen;
-+
-+ if (invec == count)
-+ goto alldone;
-+
-+ thislen = c->wbuf_pagesize - c->wbuf_len;
-+
-+ if (thislen >= invecs[invec].iov_len)
-+ thislen = invecs[invec].iov_len;
-+
-+ invec_ofs = thislen;
-+
-+ memcpy(c->wbuf + c->wbuf_len, invecs[invec].iov_base, thislen);
-+ c->wbuf_len += thislen;
-+ donelen += thislen;
-+ /* Get next invec, if actual did not fill the buffer */
-+ if (c->wbuf_len < c->wbuf_pagesize)
-+ invec++;
-+ }
-+
-+ /* write buffer is full, flush buffer */
-+ ret = __jffs2_flush_wbuf(c, NOPAD);
-+ if (ret) {
-+ /* the underlying layer has to check wbuf_len to do the cleanup */
-+ D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));
-+ /* Retlen zero to make sure our caller doesn't mark the space dirty.
-+ We've already done everything that's necessary */
-+ *retlen = 0;
-+ goto exit;
-+ }
-+ outvec_to += donelen;
-+ c->wbuf_ofs = outvec_to;
-+
-+ /* All invecs done ? */
-+ if (invec == count)
-+ goto alldone;
-+
-+ /* Set up the first outvec, containing the remainder of the
-+ invec we partially used */
-+ if (invecs[invec].iov_len > invec_ofs) {
-+ outvecs[0].iov_base = invecs[invec].iov_base+invec_ofs;
-+ totlen = outvecs[0].iov_len = invecs[invec].iov_len-invec_ofs;
-+ if (totlen > c->wbuf_pagesize) {
-+ splitvec = outvec;
-+ split_ofs = outvecs[0].iov_len - PAGE_MOD(totlen);
-+ }
-+ outvec++;
-+ }
-+ invec++;
-+ }
-+
-+ /* OK, now we've flushed the wbuf and the start of the bits
-+ we have been asked to write, now to write the rest.... */
-+
-+ /* totlen holds the amount of data still to be written */
-+ old_totlen = totlen;
-+ for ( ; invec < count; invec++,outvec++ ) {
-+ outvecs[outvec].iov_base = invecs[invec].iov_base;
-+ totlen += outvecs[outvec].iov_len = invecs[invec].iov_len;
-+ if (PAGE_DIV(totlen) != PAGE_DIV(old_totlen)) {
-+ splitvec = outvec;
-+ split_ofs = outvecs[outvec].iov_len - PAGE_MOD(totlen);
-+ old_totlen = totlen;
-+ }
-+ }
-+
-+ /* Now the outvecs array holds all the remaining data to write */
-+ /* Up to splitvec,split_ofs is to be written immediately. The rest
-+ goes into the (now-empty) wbuf */
-+
-+ if (splitvec != -1) {
-+ uint32_t remainder;
-+
-+ remainder = outvecs[splitvec].iov_len - split_ofs;
-+ outvecs[splitvec].iov_len = split_ofs;
-+
-+ /* We did cross a page boundary, so we write some now */
-+ if (jffs2_cleanmarker_oob(c))
-+ ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo);
-+ else
-+ ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen);
-+
-+ if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) {
-+ /* At this point we have no problem,
-+ c->wbuf is empty. However refile nextblock to avoid
-+ writing again to same address.
-+ */
-+ struct jffs2_eraseblock *jeb;
-+
-+ spin_lock(&c->erase_completion_lock);
-+
-+ jeb = &c->blocks[outvec_to / c->sector_size];
-+ jffs2_block_refile(c, jeb, REFILE_ANYWAY);
-+
-+ *retlen = 0;
-+ spin_unlock(&c->erase_completion_lock);
-+ goto exit;
-+ }
-+
-+ donelen += wbuf_retlen;
-+ c->wbuf_ofs = PAGE_DIV(outvec_to) + PAGE_DIV(totlen);
-+
-+ if (remainder) {
-+ outvecs[splitvec].iov_base += split_ofs;
-+ outvecs[splitvec].iov_len = remainder;
-+ } else {
-+ splitvec++;
-+ }
-+
-+ } else {
-+ splitvec = 0;
-+ }
-+
-+ /* Now splitvec points to the start of the bits we have to copy
-+ into the wbuf */
-+ wbuf_ptr = c->wbuf;
-+
-+ for ( ; splitvec < outvec; splitvec++) {
-+ /* Don't copy the wbuf into itself */
-+ if (outvecs[splitvec].iov_base == c->wbuf)
-+ continue;
-+ memcpy(wbuf_ptr, outvecs[splitvec].iov_base, outvecs[splitvec].iov_len);
-+ wbuf_ptr += outvecs[splitvec].iov_len;
-+ donelen += outvecs[splitvec].iov_len;
-+ }
-+ c->wbuf_len = wbuf_ptr - c->wbuf;
-+
-+ /* If there's a remainder in the wbuf and it's a non-GC write,
-+ remember that the wbuf affects this ino */
-+alldone:
-+ *retlen = donelen;
-+
-+ if (c->wbuf_len && ino)
-+ jffs2_wbuf_dirties_inode(c, ino);
-+
-+ ret = 0;
-+
-+exit:
-+ up_write(&c->wbuf_sem);
-+ return ret;
-+}
-+
-+/*
-+ * This is the entry for flash write.
-+ * Check, if we work on NAND FLASH, if so build an kvec and write it via vritev
-+*/
-+int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf)
-+{
-+ struct kvec vecs[1];
-+
-+ if (!jffs2_is_writebuffered(c))
-+ return c->mtd->write(c->mtd, ofs, len, retlen, buf);
-+
-+ vecs[0].iov_base = (unsigned char *) buf;
-+ vecs[0].iov_len = len;
-+ return jffs2_flash_writev(c, vecs, 1, ofs, retlen, 0);
-+}
-+
-+/*
-+ Handle readback from writebuffer and ECC failure return
-+*/
-+int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf)
-+{
-+ loff_t orbf = 0, owbf = 0, lwbf = 0;
-+ int ret;
-+
-+ if (!jffs2_is_writebuffered(c))
-+ return c->mtd->read(c->mtd, ofs, len, retlen, buf);
-+
-+ /* Read flash */
-+ if (jffs2_cleanmarker_oob(c))
-+ ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
-+ else
-+ ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
-+
-+ if ( (ret == -EBADMSG) && (*retlen == len) ) {
-+ printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
-+ len, ofs);
-+ /*
-+ * We have the raw data without ECC correction in the buffer, maybe
-+ * we are lucky and all data or parts are correct. We check the node.
-+ * If data are corrupted node check will sort it out.
-+ * We keep this block, it will fail on write or erase and the we
-+ * mark it bad. Or should we do that now? But we should give him a chance.
-+ * Maybe we had a system crash or power loss before the ecc write or
-+ * a erase was completed.
-+ * So we return success. :)
-+ */
-+ ret = 0;
-+ }
-+
-+ /* if no writebuffer available or write buffer empty, return */
-+ if (!c->wbuf_pagesize || !c->wbuf_len)
-+ return ret;;
-+
-+ /* if we read in a different block, return */
-+ if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs))
-+ return ret;
-+
-+ /* Lock only if we have reason to believe wbuf contains relevant data,
-+ so that checking an erased block during wbuf recovery space allocation
-+ does not deadlock. */
-+ down_read(&c->wbuf_sem);
-+
-+ if (ofs >= c->wbuf_ofs) {
-+ owbf = (ofs - c->wbuf_ofs); /* offset in write buffer */
-+ if (owbf > c->wbuf_len) /* is read beyond write buffer ? */
-+ goto exit;
-+ lwbf = c->wbuf_len - owbf; /* number of bytes to copy */
-+ if (lwbf > len)
-+ lwbf = len;
-+ } else {
-+ orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */
-+ if (orbf > len) /* is write beyond write buffer ? */
-+ goto exit;
-+ lwbf = len - orbf; /* number of bytes to copy */
-+ if (lwbf > c->wbuf_len)
-+ lwbf = c->wbuf_len;
-+ }
-+ if (lwbf > 0)
-+ memcpy(buf+orbf,c->wbuf+owbf,lwbf);
-+
-+exit:
-+ up_read(&c->wbuf_sem);
-+ return ret;
-+}
-+
-+/*
-+ * Check, if the out of band area is empty
-+ */
-+int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int mode)
-+{
-+ unsigned char *buf;
-+ int ret = 0;
-+ int i,len,page;
-+ size_t retlen;
-+ int oob_size;
-+
-+ /* allocate a buffer for all oob data in this sector */
-+ oob_size = c->mtd->oobsize;
-+ len = 4 * oob_size;
-+ buf = kmalloc(len, GFP_KERNEL);
-+ if (!buf) {
-+ printk(KERN_NOTICE "jffs2_check_oob_empty(): allocation of temporary data buffer for oob check failed\n");
-+ return -ENOMEM;
-+ }
-+ /*
-+ * if mode = 0, we scan for a total empty oob area, else we have
-+ * to take care of the cleanmarker in the first page of the block
-+ */
-+ ret = jffs2_flash_read_oob(c, jeb->offset, len , &retlen, buf);
-+ if (ret) {
-+ D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB failed %d for block at %08x\n", ret, jeb->offset));
-+ goto out;
-+ }
-+
-+ if (retlen < len) {
-+ D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB return short read "
-+ "(%zd bytes not %d) for block at %08x\n", retlen, len, jeb->offset));
-+ ret = -EIO;
-+ goto out;
-+ }
-+
-+ /* Special check for first page */
-+ for(i = 0; i < oob_size ; i++) {
-+ /* Yeah, we know about the cleanmarker. */
-+ if (mode && i >= c->fsdata_pos &&
-+ i < c->fsdata_pos + c->fsdata_len)
-+ continue;
-+
-+ if (buf[i] != 0xFF) {
-+ D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n",
-+ buf[page+i], page+i, jeb->offset));
-+ ret = 1;
-+ goto out;
-+ }
-+ }
-+
-+ /* we know, we are aligned :) */
-+ for (page = oob_size; page < len; page += sizeof(long)) {
-+ unsigned long dat = *(unsigned long *)(&buf[page]);
-+ if(dat != -1) {
-+ ret = 1;
-+ goto out;
-+ }
-+ }
-+
-+out:
-+ kfree(buf);
-+
-+ return ret;
-+}
-+
-+/*
-+* Scan for a valid cleanmarker and for bad blocks
-+* For virtual blocks (concatenated physical blocks) check the cleanmarker
-+* only in the first page of the first physical block, but scan for bad blocks in all
-+* physical blocks
-+*/
-+int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
-+{
-+ struct jffs2_unknown_node n;
-+ unsigned char buf[2 * NAND_MAX_OOBSIZE];
-+ unsigned char *p;
-+ int ret, i, cnt, retval = 0;
-+ size_t retlen, offset;
-+ int oob_size;
-+
-+ offset = jeb->offset;
-+ oob_size = c->mtd->oobsize;
-+
-+ /* Loop through the physical blocks */
-+ for (cnt = 0; cnt < (c->sector_size / c->mtd->erasesize); cnt++) {
-+ /* Check first if the block is bad. */
-+ if (c->mtd->block_isbad (c->mtd, offset)) {
-+ D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n", jeb->offset));
-+ return 2;
-+ }
-+ /*
-+ * We read oob data from page 0 and 1 of the block.
-+ * page 0 contains cleanmarker and badblock info
-+ * page 1 contains failure count of this block
-+ */
-+ ret = c->mtd->read_oob (c->mtd, offset, oob_size << 1, &retlen, buf);
-+
-+ if (ret) {
-+ D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB failed %d for block at %08x\n", ret, jeb->offset));
-+ return ret;
-+ }
-+ if (retlen < (oob_size << 1)) {
-+ D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size << 1, jeb->offset));
-+ return -EIO;
-+ }
-+
-+ /* Check cleanmarker only on the first physical block */
-+ if (!cnt) {
-+ n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
-+ n.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
-+ n.totlen = cpu_to_je32 (8);
-+ p = (unsigned char *) &n;
-+
-+ for (i = 0; i < c->fsdata_len; i++) {
-+ if (buf[c->fsdata_pos + i] != p[i]) {
-+ retval = 1;
-+ }
-+ }
-+ D1(if (retval == 1) {
-+ printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset);
-+ printk(KERN_WARNING "OOB at %08x was ", offset);
-+ for (i=0; i < oob_size; i++) {
-+ printk("%02x ", buf[i]);
-+ }
-+ printk("\n");
-+ })
-+ }
-+ offset += c->mtd->erasesize;
-+ }
-+ return retval;
-+}
-+
-+int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
-+{
-+ struct jffs2_unknown_node n;
-+ int ret;
-+ size_t retlen;
-+
-+ n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
-+ n.totlen = cpu_to_je32(8);
-+
-+ ret = jffs2_flash_write_oob(c, jeb->offset + c->fsdata_pos, c->fsdata_len, &retlen, (unsigned char *)&n);
-+
-+ if (ret) {
-+ D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
-+ return ret;
-+ }
-+ if (retlen != c->fsdata_len) {
-+ D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %zd not %d\n", jeb->offset, retlen, c->fsdata_len));
-+ return ret;
-+ }
-+ return 0;
-+}
-+
-+/*
-+ * On NAND we try to mark this block bad. If the block was erased more
-+ * than MAX_ERASE_FAILURES we mark it finaly bad.
-+ * Don't care about failures. This block remains on the erase-pending
-+ * or badblock list as long as nobody manipulates the flash with
-+ * a bootloader or something like that.
-+ */
-+
-+int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset)
-+{
-+ int ret;
-+
-+ /* if the count is < max, we try to write the counter to the 2nd page oob area */
-+ if( ++jeb->bad_count < MAX_ERASE_FAILURES)
-+ return 0;
-+
-+ if (!c->mtd->block_markbad)
-+ return 1; // What else can we do?
-+
-+ D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Marking bad block at %08x\n", bad_offset));
-+ ret = c->mtd->block_markbad(c->mtd, bad_offset);
-+
-+ if (ret) {
-+ D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
-+ return ret;
-+ }
-+ return 1;
-+}
-+
-+#define NAND_JFFS2_OOB16_FSDALEN 8
-+
-+static struct nand_oobinfo jffs2_oobinfo_docecc = {
-+ .useecc = MTD_NANDECC_PLACE,
-+ .eccbytes = 6,
-+ .eccpos = {0,1,2,3,4,5}
-+};
-+
-+
-+int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c)
-+{
-+ struct nand_oobinfo *oinfo = &c->mtd->oobinfo;
-+
-+ /* Do this only, if we have an oob buffer */
-+ if (!c->mtd->oobsize)
-+ return 0;
-+
-+ /* Cleanmarker is out-of-band, so inline size zero */
-+ c->cleanmarker_size = 0;
-+
-+ /* Should we use autoplacement ? */
-+ if (oinfo && oinfo->useecc == MTD_NANDECC_AUTOPLACE) {
-+ D1(printk(KERN_DEBUG "JFFS2 using autoplace on NAND\n"));
-+ /* Get the position of the free bytes */
-+ if (!oinfo->oobfree[0][1]) {
-+ printk (KERN_WARNING "jffs2_nand_set_oobinfo(): Eeep. Autoplacement selected and no empty space in oob\n");
-+ return -ENOSPC;
-+ }
-+ c->fsdata_pos = oinfo->oobfree[0][0];
-+ c->fsdata_len = oinfo->oobfree[0][1];
-+ if (c->fsdata_len > 8)
-+ c->fsdata_len = 8;
-+ } else {
-+ /* This is just a legacy fallback and should go away soon */
-+ switch(c->mtd->ecctype) {
-+ case MTD_ECC_RS_DiskOnChip:
-+ printk(KERN_WARNING "JFFS2 using DiskOnChip hardware ECC without autoplacement. Fix it!\n");
-+ c->oobinfo = &jffs2_oobinfo_docecc;
-+ c->fsdata_pos = 6;
-+ c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN;
-+ c->badblock_pos = 15;
-+ break;
-+
-+ default:
-+ D1(printk(KERN_DEBUG "JFFS2 on NAND. No autoplacment info found\n"));
-+ return -EINVAL;
-+ }
-+ }
-+ return 0;
-+}
-+
-+int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
-+{
-+ int res;
-+
-+ /* Initialise write buffer */
-+ init_rwsem(&c->wbuf_sem);
-+ c->wbuf_pagesize = c->mtd->oobblock;
-+ c->wbuf_ofs = 0xFFFFFFFF;
-+
-+ c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
-+ if (!c->wbuf)
-+ return -ENOMEM;
-+
-+ res = jffs2_nand_set_oobinfo(c);
-+
-+#ifdef BREAKME
-+ if (!brokenbuf)
-+ brokenbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
-+ if (!brokenbuf) {
-+ kfree(c->wbuf);
-+ return -ENOMEM;
-+ }
-+ memset(brokenbuf, 0xdb, c->wbuf_pagesize);
-+#endif
-+ return res;
-+}
-+
-+void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
-+{
-+ kfree(c->wbuf);
-+}
-+
-+int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
-+ c->cleanmarker_size = 0; /* No cleanmarkers needed */
-+
-+ /* Initialize write buffer */
-+ init_rwsem(&c->wbuf_sem);
-+ c->wbuf_pagesize = c->sector_size;
-+ c->wbuf_ofs = 0xFFFFFFFF;
-+
-+ c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
-+ if (!c->wbuf)
-+ return -ENOMEM;
-+
-+ printk(KERN_INFO "JFFS2 write-buffering enabled (%i)\n", c->wbuf_pagesize);
-+
-+ return 0;
-+}
-+
-+void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) {
-+ kfree(c->wbuf);
-+}
-+
-+int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) {
-+ /* Cleanmarker is actually larger on the flashes */
-+ c->cleanmarker_size = 16;
-+
-+ /* Initialize write buffer */
-+ init_rwsem(&c->wbuf_sem);
-+ c->wbuf_pagesize = c->mtd->eccsize;
-+ c->wbuf_ofs = 0xFFFFFFFF;
-+
-+ c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
-+ if (!c->wbuf)
-+ return -ENOMEM;
-+
-+ return 0;
-+}
-+
-+void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) {
-+ kfree(c->wbuf);
-+}
---- linux-2.4.21/fs/jffs2/write.c~mtd-cvs
-+++ linux-2.4.21/fs/jffs2/write.c
-@@ -1,154 +1,70 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * $Id: write.c,v 1.30.2.1 2002/08/08 08:36:31 dwmw2 Exp $
-+ * $Id: write.c,v 1.91 2005/03/01 10:34:03 dedekind Exp $
- *
- */
-
- #include <linux/kernel.h>
- #include <linux/fs.h>
--#include <linux/jffs2.h>
-+#include <linux/crc32.h>
-+#include <linux/slab.h>
-+#include <linux/pagemap.h>
- #include <linux/mtd/mtd.h>
- #include "nodelist.h"
--#include "crc32.h"
-+#include "compr.h"
-
--/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
-- fill in the raw_inode while you're at it. */
--struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri)
-+
-+int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri)
- {
-- struct inode *inode;
-- struct super_block *sb = dir_i->i_sb;
- struct jffs2_inode_cache *ic;
-- struct jffs2_sb_info *c;
-- struct jffs2_inode_info *f;
--
-- D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode));
--
-- c = JFFS2_SB_INFO(sb);
-- memset(ri, 0, sizeof(*ri));
-
- ic = jffs2_alloc_inode_cache();
- if (!ic) {
-- return ERR_PTR(-ENOMEM);
-- }
-- memset(ic, 0, sizeof(*ic));
--
-- inode = new_inode(sb);
--
-- if (!inode) {
-- jffs2_free_inode_cache(ic);
-- return ERR_PTR(-ENOMEM);
-+ return -ENOMEM;
- }
-
-- /* Alloc jffs2_inode_info when that's split in 2.5 */
-+ memset(ic, 0, sizeof(*ic));
-
-- f = JFFS2_INODE_INFO(inode);
-- memset(f, 0, sizeof(*f));
-- init_MUTEX_LOCKED(&f->sem);
- f->inocache = ic;
-- inode->i_nlink = f->inocache->nlink = 1;
-+ f->inocache->nlink = 1;
- f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
-- f->inocache->ino = ri->ino = inode->i_ino = ++c->highest_ino;
-- D1(printk(KERN_DEBUG "jffs2_new_inode(): Assigned ino# %d\n", ri->ino));
-- jffs2_add_ino_cache(c, f->inocache);
--
-- ri->magic = JFFS2_MAGIC_BITMASK;
-- ri->nodetype = JFFS2_NODETYPE_INODE;
-- ri->totlen = PAD(sizeof(*ri));
-- ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4);
-- ri->mode = mode;
-- f->highest_version = ri->version = 1;
-- ri->uid = current->fsuid;
-- if (dir_i->i_mode & S_ISGID) {
-- ri->gid = dir_i->i_gid;
-- if (S_ISDIR(mode))
-- ri->mode |= S_ISGID;
-- } else {
-- ri->gid = current->fsgid;
-- }
-- inode->i_mode = ri->mode;
-- inode->i_gid = ri->gid;
-- inode->i_uid = ri->uid;
-- inode->i_atime = inode->i_ctime = inode->i_mtime =
-- ri->atime = ri->mtime = ri->ctime = CURRENT_TIME;
-- inode->i_blksize = PAGE_SIZE;
-- inode->i_blocks = 0;
-- inode->i_size = 0;
--
-- insert_inode_hash(inode);
-+ f->inocache->ino = ++c->highest_ino;
-+ f->inocache->state = INO_STATE_PRESENT;
-
-- return inode;
--}
-+ ri->ino = cpu_to_je32(f->inocache->ino);
-
--/* This ought to be in core MTD code. All registered MTD devices
-- without writev should have this put in place. Bug the MTD
-- maintainer */
--static int mtd_fake_writev(struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen)
--{
-- unsigned long i;
-- size_t totlen = 0, thislen;
-- int ret = 0;
-+ D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
-+ jffs2_add_ino_cache(c, f->inocache);
-
-- for (i=0; i<count; i++) {
-- ret = mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base);
-- totlen += thislen;
-- if (ret || thislen != vecs[i].iov_len)
-- break;
-- to += vecs[i].iov_len;
-- }
-- if (retlen)
-- *retlen = totlen;
-- return ret;
--}
-+ ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-+ ri->totlen = cpu_to_je32(PAD(sizeof(*ri)));
-+ ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
-+ ri->mode = cpu_to_jemode(mode);
-
-+ f->highest_version = 1;
-+ ri->version = cpu_to_je32(f->highest_version);
-
--static inline int mtd_writev(struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen)
--{
-- if (mtd->writev)
-- return mtd->writev(mtd,vecs,count,to,retlen);
-- else
-- return mtd_fake_writev(mtd, vecs, count, to, retlen);
-+ return 0;
- }
-
--static void writecheck(struct mtd_info *mtd, __u32 ofs)
-+#if CONFIG_JFFS2_FS_DEBUG > 0
-+static void writecheck(struct jffs2_sb_info *c, uint32_t ofs)
- {
- unsigned char buf[16];
-- ssize_t retlen;
-+ size_t retlen;
- int ret, i;
-
-- ret = mtd->read(mtd, ofs, 16, &retlen, buf);
-- if (ret && retlen != 16) {
-- D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %d\n", ret, retlen));
-+ ret = jffs2_flash_read(c, ofs, 16, &retlen, buf);
-+ if (ret || (retlen != 16)) {
-+ D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %zd\n", ret, retlen));
- return;
- }
- ret = 0;
-@@ -157,32 +73,31 @@
- ret = 1;
- }
- if (ret) {
-- printk(KERN_WARNING "ARGH. About to write node to 0x%08x on flash, but there's data already there:\n", ofs);
-+ printk(KERN_WARNING "ARGH. About to write node to 0x%08x on flash, but there are data already there:\n", ofs);
- printk(KERN_WARNING "0x%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- ofs,
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
- buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
- }
- }
--
--
-+#endif
-
-
- /* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it,
- write it to the flash, link it into the existing inode/fragment list */
-
--struct jffs2_full_dnode *jffs2_write_dnode(struct inode *inode, struct jffs2_raw_inode *ri, const unsigned char *data, __u32 datalen, __u32 flash_ofs, __u32 *writelen)
-+struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode)
-
- {
-- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_raw_node_ref *raw;
- struct jffs2_full_dnode *fn;
-- ssize_t retlen;
-- struct iovec vecs[2];
-+ size_t retlen;
-+ struct kvec vecs[2];
- int ret;
-+ int retried = 0;
-+ unsigned long cnt = 2;
-
-- D1(if(ri->hdr_crc != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) {
-+ D1(if(je32_to_cpu(ri->hdr_crc) != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) {
- printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dnode()\n");
- BUG();
- }
-@@ -192,10 +107,10 @@
- vecs[1].iov_base = (unsigned char *)data;
- vecs[1].iov_len = datalen;
-
-- writecheck(c->mtd, flash_ofs);
-+ D1(writecheck(c, flash_ofs));
-
-- if (ri->totlen != sizeof(*ri) + datalen) {
-- printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08x) + datalen (0x%08x)\n", ri->totlen, sizeof(*ri), datalen);
-+ if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) {
-+ printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08zx) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen);
- }
- raw = jffs2_alloc_raw_node_ref();
- if (!raw)
-@@ -206,19 +121,37 @@
- jffs2_free_raw_node_ref(raw);
- return ERR_PTR(-ENOMEM);
- }
-- raw->flash_offset = flash_ofs;
-- raw->totlen = PAD(ri->totlen);
-- raw->next_phys = NULL;
-
-- fn->ofs = ri->offset;
-- fn->size = ri->dsize;
-+ fn->ofs = je32_to_cpu(ri->offset);
-+ fn->size = je32_to_cpu(ri->dsize);
- fn->frags = 0;
-+
-+ /* check number of valid vecs */
-+ if (!datalen || !data)
-+ cnt = 1;
-+ retry:
- fn->raw = raw;
-
-- ret = mtd_writev(c->mtd, vecs, 2, flash_ofs, &retlen);
-+ raw->flash_offset = flash_ofs;
-+ raw->__totlen = PAD(sizeof(*ri)+datalen);
-+ raw->next_phys = NULL;
-+
-+ if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(ri->version) < f->highest_version)) {
-+ BUG_ON(!retried);
-+ D1(printk(KERN_DEBUG "jffs2_write_dnode : dnode_version %d, "
-+ "highest version %d -> updating dnode\n",
-+ je32_to_cpu(ri->version), f->highest_version));
-+ ri->version = cpu_to_je32(++f->highest_version);
-+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-+ }
-+
-+ ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen,
-+ (alloc_mode==ALLOC_GC)?0:f->inocache->ino);
-+
- if (ret || (retlen != sizeof(*ri) + datalen)) {
-- printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n",
-+ printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
- sizeof(*ri)+datalen, flash_ofs, ret, retlen);
-+
- /* Mark the space as dirtied */
- if (retlen) {
- /* Doesn't belong to any inode */
-@@ -229,48 +162,98 @@
- seem corrupted, in which case the scan would skip over
- any node we write before the original intended end of
- this node */
-- jffs2_add_physical_node_ref(c, raw, sizeof(*ri)+datalen, 1);
-+ raw->flash_offset |= REF_OBSOLETE;
-+ jffs2_add_physical_node_ref(c, raw);
- jffs2_mark_node_obsolete(c, raw);
- } else {
- printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
- jffs2_free_raw_node_ref(raw);
- }
-+ if (!retried && alloc_mode != ALLOC_NORETRY && (raw = jffs2_alloc_raw_node_ref())) {
-+ /* Try to reallocate space and retry */
-+ uint32_t dummy;
-+ struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size];
-+
-+ retried = 1;
-+
-+ D1(printk(KERN_DEBUG "Retrying failed write.\n"));
-+
-+ ACCT_SANITY_CHECK(c,jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+
-+ if (alloc_mode == ALLOC_GC) {
-+ ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs, &dummy);
-+ } else {
-+ /* Locking pain */
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+
-+ ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs, &dummy, alloc_mode);
-+ down(&f->sem);
-+ }
-
-+ if (!ret) {
-+ D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs));
-+
-+ ACCT_SANITY_CHECK(c,jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+
-+ goto retry;
-+ }
-+ D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
-+ jffs2_free_raw_node_ref(raw);
-+ }
- /* Release the full_dnode which is now useless, and return */
- jffs2_free_full_dnode(fn);
-- if (writelen)
-- *writelen = retlen;
- return ERR_PTR(ret?ret:-EIO);
- }
- /* Mark the space used */
-- jffs2_add_physical_node_ref(c, raw, retlen, 0);
-+ /* If node covers at least a whole page, or if it starts at the
-+ beginning of a page and runs to the end of the file, or if
-+ it's a hole node, mark it REF_PRISTINE, else REF_NORMAL.
-+ */
-+ if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) ||
-+ ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) &&
-+ (je32_to_cpu(ri->dsize)+je32_to_cpu(ri->offset) == je32_to_cpu(ri->isize)))) {
-+ raw->flash_offset |= REF_PRISTINE;
-+ } else {
-+ raw->flash_offset |= REF_NORMAL;
-+ }
-+ jffs2_add_physical_node_ref(c, raw);
-
- /* Link into per-inode list */
-+ spin_lock(&c->erase_completion_lock);
- raw->next_in_ino = f->inocache->nodes;
- f->inocache->nodes = raw;
-+ spin_unlock(&c->erase_completion_lock);
-
-- D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", flash_ofs, ri->dsize, ri->csize, ri->node_crc, ri->data_crc, ri->totlen));
-- if (writelen)
-- *writelen = retlen;
-+ D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n",
-+ flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize),
-+ je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc),
-+ je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen)));
-+
-+ if (retried) {
-+ ACCT_SANITY_CHECK(c,NULL);
-+ }
-
-- f->inocache->nodes = raw;
- return fn;
- }
-
--struct jffs2_full_dirent *jffs2_write_dirent(struct inode *inode, struct jffs2_raw_dirent *rd, const unsigned char *name, __u32 namelen, __u32 flash_ofs, __u32 *writelen)
-+struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, int alloc_mode)
- {
-- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_raw_node_ref *raw;
- struct jffs2_full_dirent *fd;
-- ssize_t retlen;
-- struct iovec vecs[2];
-+ size_t retlen;
-+ struct kvec vecs[2];
-+ int retried = 0;
- int ret;
-
-- D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", rd->pino, name, name, rd->ino, rd->name_crc));
-- writecheck(c->mtd, flash_ofs);
-+ D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n",
-+ je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino),
-+ je32_to_cpu(rd->name_crc)));
-+ D1(writecheck(c, flash_ofs));
-
-- D1(if(rd->hdr_crc != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) {
-+ D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) {
- printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n");
- BUG();
- }
-@@ -291,44 +274,457 @@
- jffs2_free_raw_node_ref(raw);
- return ERR_PTR(-ENOMEM);
- }
-- raw->flash_offset = flash_ofs;
-- raw->totlen = PAD(rd->totlen);
-- raw->next_in_ino = f->inocache->nodes;
-- f->inocache->nodes = raw;
-- raw->next_phys = NULL;
-
-- fd->version = rd->version;
-- fd->ino = rd->ino;
-+ fd->version = je32_to_cpu(rd->version);
-+ fd->ino = je32_to_cpu(rd->ino);
- fd->nhash = full_name_hash(name, strlen(name));
- fd->type = rd->type;
- memcpy(fd->name, name, namelen);
- fd->name[namelen]=0;
-+
-+ retry:
- fd->raw = raw;
-
-- ret = mtd_writev(c->mtd, vecs, 2, flash_ofs, &retlen);
-+ raw->flash_offset = flash_ofs;
-+ raw->__totlen = PAD(sizeof(*rd)+namelen);
-+ raw->next_phys = NULL;
-+
-+ if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(rd->version) < f->highest_version)) {
-+ BUG_ON(!retried);
-+ D1(printk(KERN_DEBUG "jffs2_write_dirent : dirent_version %d, "
-+ "highest version %d -> updating dirent\n",
-+ je32_to_cpu(rd->version), f->highest_version));
-+ rd->version = cpu_to_je32(++f->highest_version);
-+ fd->version = je32_to_cpu(rd->version);
-+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-+ }
-+
-+ ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen,
-+ (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino));
- if (ret || (retlen != sizeof(*rd) + namelen)) {
-- printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n",
-+ printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
- sizeof(*rd)+namelen, flash_ofs, ret, retlen);
- /* Mark the space as dirtied */
- if (retlen) {
-- jffs2_add_physical_node_ref(c, raw, sizeof(*rd)+namelen, 1);
-+ raw->next_in_ino = NULL;
-+ raw->flash_offset |= REF_OBSOLETE;
-+ jffs2_add_physical_node_ref(c, raw);
- jffs2_mark_node_obsolete(c, raw);
- } else {
- printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
- jffs2_free_raw_node_ref(raw);
- }
-+ if (!retried && (raw = jffs2_alloc_raw_node_ref())) {
-+ /* Try to reallocate space and retry */
-+ uint32_t dummy;
-+ struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size];
-+
-+ retried = 1;
-
-+ D1(printk(KERN_DEBUG "Retrying failed write.\n"));
-+
-+ ACCT_SANITY_CHECK(c,jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+
-+ if (alloc_mode == ALLOC_GC) {
-+ ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs, &dummy);
-+ } else {
-+ /* Locking pain */
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+
-+ ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs, &dummy, alloc_mode);
-+ down(&f->sem);
-+ }
-+
-+ if (!ret) {
-+ D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs));
-+ ACCT_SANITY_CHECK(c,jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+ goto retry;
-+ }
-+ D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
-+ jffs2_free_raw_node_ref(raw);
-+ }
- /* Release the full_dnode which is now useless, and return */
- jffs2_free_full_dirent(fd);
-- if (writelen)
-- *writelen = retlen;
- return ERR_PTR(ret?ret:-EIO);
- }
- /* Mark the space used */
-- jffs2_add_physical_node_ref(c, raw, retlen, 0);
-- if (writelen)
-- *writelen = retlen;
-+ raw->flash_offset |= REF_PRISTINE;
-+ jffs2_add_physical_node_ref(c, raw);
-
-+ spin_lock(&c->erase_completion_lock);
-+ raw->next_in_ino = f->inocache->nodes;
- f->inocache->nodes = raw;
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ if (retried) {
-+ ACCT_SANITY_CHECK(c,NULL);
-+ }
-+
- return fd;
- }
-+
-+/* The OS-specific code fills in the metadata in the jffs2_raw_inode for us, so that
-+ we don't have to go digging in struct inode or its equivalent. It should set:
-+ mode, uid, gid, (starting)isize, atime, ctime, mtime */
-+int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-+ struct jffs2_raw_inode *ri, unsigned char *buf,
-+ uint32_t offset, uint32_t writelen, uint32_t *retlen)
-+{
-+ int ret = 0;
-+ uint32_t writtenlen = 0;
-+
-+ D1(printk(KERN_DEBUG "jffs2_write_inode_range(): Ino #%u, ofs 0x%x, len 0x%x\n",
-+ f->inocache->ino, offset, writelen));
-+
-+ while(writelen) {
-+ struct jffs2_full_dnode *fn;
-+ unsigned char *comprbuf = NULL;
-+ uint16_t comprtype = JFFS2_COMPR_NONE;
-+ uint32_t phys_ofs, alloclen;
-+ uint32_t datalen, cdatalen;
-+ int retried = 0;
-+
-+ retry:
-+ D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset));
-+
-+ ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL);
-+ if (ret) {
-+ D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret));
-+ break;
-+ }
-+ down(&f->sem);
-+ datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1)));
-+ cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen);
-+
-+ comprtype = jffs2_compress(c, f, buf, &comprbuf, &datalen, &cdatalen);
-+
-+ ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-+ ri->totlen = cpu_to_je32(sizeof(*ri) + cdatalen);
-+ ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
-+
-+ ri->ino = cpu_to_je32(f->inocache->ino);
-+ ri->version = cpu_to_je32(++f->highest_version);
-+ ri->isize = cpu_to_je32(max(je32_to_cpu(ri->isize), offset + datalen));
-+ ri->offset = cpu_to_je32(offset);
-+ ri->csize = cpu_to_je32(cdatalen);
-+ ri->dsize = cpu_to_je32(datalen);
-+ ri->compr = comprtype & 0xff;
-+ ri->usercompr = (comprtype >> 8 ) & 0xff;
-+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-+ ri->data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
-+
-+ fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, phys_ofs, ALLOC_NORETRY);
-+
-+ jffs2_free_comprbuf(comprbuf, buf);
-+
-+ if (IS_ERR(fn)) {
-+ ret = PTR_ERR(fn);
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+ if (!retried) {
-+ /* Write error to be retried */
-+ retried = 1;
-+ D1(printk(KERN_DEBUG "Retrying node write in jffs2_write_inode_range()\n"));
-+ goto retry;
-+ }
-+ break;
-+ }
-+ ret = jffs2_add_full_dnode_to_inode(c, f, fn);
-+ if (f->metadata) {
-+ jffs2_mark_node_obsolete(c, f->metadata->raw);
-+ jffs2_free_full_dnode(f->metadata);
-+ f->metadata = NULL;
-+ }
-+ if (ret) {
-+ /* Eep */
-+ D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in commit_write, returned %d\n", ret));
-+ jffs2_mark_node_obsolete(c, fn->raw);
-+ jffs2_free_full_dnode(fn);
-+
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+ break;
-+ }
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+ if (!datalen) {
-+ printk(KERN_WARNING "Eep. We didn't actually write any data in jffs2_write_inode_range()\n");
-+ ret = -EIO;
-+ break;
-+ }
-+ D1(printk(KERN_DEBUG "increasing writtenlen by %d\n", datalen));
-+ writtenlen += datalen;
-+ offset += datalen;
-+ writelen -= datalen;
-+ buf += datalen;
-+ }
-+ *retlen = writtenlen;
-+ return ret;
-+}
-+
-+int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const char *name, int namelen)
-+{
-+ struct jffs2_raw_dirent *rd;
-+ struct jffs2_full_dnode *fn;
-+ struct jffs2_full_dirent *fd;
-+ uint32_t alloclen, phys_ofs;
-+ int ret;
-+
-+ /* Try to reserve enough space for both node and dirent.
-+ * Just the node will do for now, though
-+ */
-+ ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);
-+ D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen));
-+ if (ret) {
-+ up(&f->sem);
-+ return ret;
-+ }
-+
-+ ri->data_crc = cpu_to_je32(0);
-+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-+
-+ fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
-+
-+ D1(printk(KERN_DEBUG "jffs2_do_create created file with mode 0x%x\n",
-+ jemode_to_cpu(ri->mode)));
-+
-+ if (IS_ERR(fn)) {
-+ D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n"));
-+ /* Eeek. Wave bye bye */
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+ return PTR_ERR(fn);
-+ }
-+ /* No data here. Only a metadata node, which will be
-+ obsoleted by the first data write
-+ */
-+ f->metadata = fn;
-+
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
-+
-+ if (ret) {
-+ /* Eep. */
-+ D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n"));
-+ return ret;
-+ }
-+
-+ rd = jffs2_alloc_raw_dirent();
-+ if (!rd) {
-+ /* Argh. Now we treat it like a normal delete */
-+ jffs2_complete_reservation(c);
-+ return -ENOMEM;
-+ }
-+
-+ down(&dir_f->sem);
-+
-+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
-+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
-+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
-+
-+ rd->pino = cpu_to_je32(dir_f->inocache->ino);
-+ rd->version = cpu_to_je32(++dir_f->highest_version);
-+ rd->ino = ri->ino;
-+ rd->mctime = ri->ctime;
-+ rd->nsize = namelen;
-+ rd->type = DT_REG;
-+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-+ rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
-+
-+ fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL);
-+
-+ jffs2_free_raw_dirent(rd);
-+
-+ if (IS_ERR(fd)) {
-+ /* dirent failed to write. Delete the inode normally
-+ as if it were the final unlink() */
-+ jffs2_complete_reservation(c);
-+ up(&dir_f->sem);
-+ return PTR_ERR(fd);
-+ }
-+
-+ /* Link the fd into the inode's list, obsoleting an old
-+ one if necessary. */
-+ jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-+
-+ jffs2_complete_reservation(c);
-+ up(&dir_f->sem);
-+
-+ return 0;
-+}
-+
-+
-+int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
-+ const char *name, int namelen, struct jffs2_inode_info *dead_f)
-+{
-+ struct jffs2_raw_dirent *rd;
-+ struct jffs2_full_dirent *fd;
-+ uint32_t alloclen, phys_ofs;
-+ int ret;
-+
-+ if (1 /* alternative branch needs testing */ ||
-+ !jffs2_can_mark_obsolete(c)) {
-+ /* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */
-+
-+ rd = jffs2_alloc_raw_dirent();
-+ if (!rd)
-+ return -ENOMEM;
-+
-+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION);
-+ if (ret) {
-+ jffs2_free_raw_dirent(rd);
-+ return ret;
-+ }
-+
-+ down(&dir_f->sem);
-+
-+ /* Build a deletion node */
-+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
-+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
-+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
-+
-+ rd->pino = cpu_to_je32(dir_f->inocache->ino);
-+ rd->version = cpu_to_je32(++dir_f->highest_version);
-+ rd->ino = cpu_to_je32(0);
-+ rd->mctime = cpu_to_je32(get_seconds());
-+ rd->nsize = namelen;
-+ rd->type = DT_UNKNOWN;
-+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-+ rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
-+
-+ fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION);
-+
-+ jffs2_free_raw_dirent(rd);
-+
-+ if (IS_ERR(fd)) {
-+ jffs2_complete_reservation(c);
-+ up(&dir_f->sem);
-+ return PTR_ERR(fd);
-+ }
-+
-+ /* File it. This will mark the old one obsolete. */
-+ jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-+ up(&dir_f->sem);
-+ } else {
-+ struct jffs2_full_dirent **prev = &dir_f->dents;
-+ uint32_t nhash = full_name_hash(name, namelen);
-+
-+ down(&dir_f->sem);
-+
-+ while ((*prev) && (*prev)->nhash <= nhash) {
-+ if ((*prev)->nhash == nhash &&
-+ !memcmp((*prev)->name, name, namelen) &&
-+ !(*prev)->name[namelen]) {
-+ struct jffs2_full_dirent *this = *prev;
-+
-+ D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) @%08x obsolete\n",
-+ this->ino, ref_offset(this->raw)));
-+
-+ *prev = this->next;
-+ jffs2_mark_node_obsolete(c, (this->raw));
-+ jffs2_free_full_dirent(this);
-+ break;
-+ }
-+ prev = &((*prev)->next);
-+ }
-+ up(&dir_f->sem);
-+ }
-+
-+ /* dead_f is NULL if this was a rename not a real unlink */
-+ /* Also catch the !f->inocache case, where there was a dirent
-+ pointing to an inode which didn't exist. */
-+ if (dead_f && dead_f->inocache) {
-+
-+ down(&dead_f->sem);
-+
-+ if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) {
-+ while (dead_f->dents) {
-+ /* There can be only deleted ones */
-+ fd = dead_f->dents;
-+
-+ dead_f->dents = fd->next;
-+
-+ if (fd->ino) {
-+ printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
-+ dead_f->inocache->ino, fd->name, fd->ino);
-+ } else {
-+ D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n",
-+ fd->name, dead_f->inocache->ino));
-+ }
-+ jffs2_mark_node_obsolete(c, fd->raw);
-+ jffs2_free_full_dirent(fd);
-+ }
-+ }
-+
-+ dead_f->inocache->nlink--;
-+ /* NB: Caller must set inode nlink if appropriate */
-+ up(&dead_f->sem);
-+ }
-+
-+ jffs2_complete_reservation(c);
-+
-+ return 0;
-+}
-+
-+
-+int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen)
-+{
-+ struct jffs2_raw_dirent *rd;
-+ struct jffs2_full_dirent *fd;
-+ uint32_t alloclen, phys_ofs;
-+ int ret;
-+
-+ rd = jffs2_alloc_raw_dirent();
-+ if (!rd)
-+ return -ENOMEM;
-+
-+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
-+ if (ret) {
-+ jffs2_free_raw_dirent(rd);
-+ return ret;
-+ }
-+
-+ down(&dir_f->sem);
-+
-+ /* Build a deletion node */
-+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
-+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
-+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
-+
-+ rd->pino = cpu_to_je32(dir_f->inocache->ino);
-+ rd->version = cpu_to_je32(++dir_f->highest_version);
-+ rd->ino = cpu_to_je32(ino);
-+ rd->mctime = cpu_to_je32(get_seconds());
-+ rd->nsize = namelen;
-+
-+ rd->type = type;
-+
-+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-+ rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
-+
-+ fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL);
-+
-+ jffs2_free_raw_dirent(rd);
-+
-+ if (IS_ERR(fd)) {
-+ jffs2_complete_reservation(c);
-+ up(&dir_f->sem);
-+ return PTR_ERR(fd);
-+ }
-+
-+ /* File it. This will mark the old one obsolete. */
-+ jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-+
-+ jffs2_complete_reservation(c);
-+ up(&dir_f->sem);
-+
-+ return 0;
-+}
---- /dev/null
-+++ linux-2.4.21/fs/jffs2/writev.c
-@@ -0,0 +1,50 @@
-+/*
-+ * JFFS2 -- Journalling Flash File System, Version 2.
-+ *
-+ * Copyright (C) 2001, 2002 Red Hat, Inc.
-+ *
-+ * Created by David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * For licensing information, see the file 'LICENCE' in this directory.
-+ *
-+ * $Id: writev.c,v 1.6 2004/11/16 20:36:12 dwmw2 Exp $
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/mtd/mtd.h>
-+#include "nodelist.h"
-+
-+/* This ought to be in core MTD code. All registered MTD devices
-+ without writev should have this put in place. Bug the MTD
-+ maintainer */
-+static inline int mtd_fake_writev(struct mtd_info *mtd, const struct kvec *vecs,
-+ unsigned long count, loff_t to, size_t *retlen)
-+{
-+ unsigned long i;
-+ size_t totlen = 0, thislen;
-+ int ret = 0;
-+
-+ for (i=0; i<count; i++) {
-+ if (!vecs[i].iov_len)
-+ continue;
-+ ret = mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base);
-+ totlen += thislen;
-+ if (ret || thislen != vecs[i].iov_len)
-+ break;
-+ to += vecs[i].iov_len;
-+ }
-+ if (retlen)
-+ *retlen = totlen;
-+ return ret;
-+}
-+
-+int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs,
-+ unsigned long count, loff_t to, size_t *retlen)
-+{
-+ if (c->mtd->writev)
-+ return c->mtd->writev(c->mtd, vecs, count, to, retlen);
-+ else
-+ return mtd_fake_writev(c->mtd, vecs, count, to, retlen);
-+}
-+
---- linux-2.4.21/include/asm-arm/arch-pxa/hardware.h~ramses
-+++ linux-2.4.21/include/asm-arm/arch-pxa/hardware.h
-@@ -127,16 +127,20 @@
- * Implementation specifics
- */
-
--//#ifdef CONFIG_ARCH_LUBBOCK
-+#ifdef CONFIG_ARCH_LUBBOCK
- #include "lubbock.h"
--//#endif
-+#endif
-
--//#ifdef CONFIG_ARCH_PXA_IDP
-+#ifdef CONFIG_ARCH_PXA_IDP
- #include "idp.h"
--//#endif
-+#endif
-
--//#ifdef CONFIG_ARCH_PXA_CERF
-+#ifdef CONFIG_ARCH_PXA_CERF
- #include "cerf.h"
--//#endif
-+#endif
-+
-+#ifdef CONFIG_ARCH_RAMSES
-+#include "ramses.h"
-+#endif
-
- #endif /* _ASM_ARCH_HARDWARE_H */
---- linux-2.4.21/include/asm-arm/arch-pxa/irqs.h~ramses
-+++ linux-2.4.21/include/asm-arm/arch-pxa/irqs.h
-@@ -105,14 +105,13 @@
- #define S0_BVD1_STSCHG SA1111_IRQ(53)
- #define S1_BVD1_STSCHG SA1111_IRQ(54)
-
--#define SA1111_IRQ_MAX SA1111_IRQ(54)
-
- #undef NR_IRQS
- #define NR_IRQS (SA1111_IRQ_MAX + 1)
-
- #endif // defined(CONFIG_SA1111)
-
--#if defined(CONFIG_ARCH_LUBBOCK) || defined(CONFIG_ARCH_PXA_IDP)
-+#if defined(CONFIG_ARCH_LUBBOCK) || defined(CONFIG_ARCH_PXA_IDP)
- #if CONFIG_SA1111
- #define LUBBOCK_IRQ(x) (SA1111_IRQ_MAX + 1 + (x))
- #else
-@@ -132,6 +131,3 @@
- #define NR_IRQS (LUBBOCK_LAST_IRQ + 1)
-
- #endif // CONFIG_ARCH_LUBBOCK
--
--
--
---- linux-2.4.21/include/asm-arm/arch-pxa/pxa-regs.h~ramses
-+++ linux-2.4.21/include/asm-arm/arch-pxa/pxa-regs.h
-@@ -1051,6 +1051,7 @@
- #define PGSR1 __REG(0x40F00024) /* Power Manager GPIO Sleep State Register for GP[63-32] */
- #define PGSR2 __REG(0x40F00028) /* Power Manager GPIO Sleep State Register for GP[84-64] */
- #define RCSR __REG(0x40F00030) /* Reset Controller Status Register */
-+#define PMFW __REG(0x40F00034) /* Power Manager Fast-Sleep Wakeup Configuration Register */
-
- #define PSSR_RDH (1 << 5) /* Read Disable Hold */
- #define PSSR_PH (1 << 4) /* Peripheral Control Hold */
---- /dev/null
-+++ linux-2.4.21/include/asm-arm/arch-pxa/ramses.h
-@@ -0,0 +1,364 @@
-+/*
-+ * linux/include/asm-arm/arch-pxa/ramses.h
-+ *
-+ * 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.
-+ *
-+ * Copyright (c) 2002,2003 M&N Logistik-Lösungen Online GmbH
-+ *
-+ * 2001-09-13: Cliff Brake <cbrake@accelent.com>
-+ * Initial code
-+ *
-+ * 2002-10-08: adaption from PXA IDP to Ramses
-+ *
-+ */
-+
-+
-+/*
-+ * Note: this file must be safe to include in assembly files
-+ */
-+
-+#define RAMSES_FLASH_PHYS (PXA_CS0_PHYS)
-+#define RAMSES_ALT_FLASH_PHYS (PXA_CS1_PHYS)
-+#define RAMSES_MEDIAQ_PHYS (PXA_CS3_PHYS)
-+#define RAMSES_CONTROL_PHYS (PXA_CS4_PHYS)
-+#define RAMSES_IDE_PHYS (PXA_CS5_PHYS + 0x03000000)
-+#define RAMSES_ETH_PHYS (PXA_CS5_PHYS + 0x03400000)
-+#define RAMSES_COREVOLT_PHYS (PXA_CS5_PHYS + 0x03800000)
-+#define RAMSES_CPLD_PHYS (PXA_CS5_PHYS + 0x03C00000)
-+
-+/*
-+ * virtual memory map
-+ */
-+
-+#define RAMSES_IDE_BASE (0xf0000000)
-+#define RAMSES_IDE_SIZE (1*1024*1024)
-+#define RAMSES_ETH_BASE (RAMSES_IDE_BASE + RAMSES_IDE_SIZE)
-+#define RAMSES_ETH_SIZE (1*1024*1024)
-+#define RAMSES_COREVOLT_BASE (RAMSES_ETH_BASE + RAMSES_ETH_SIZE)
-+#define RAMSES_COREVOLT_SIZE (1*1024*1024)
-+#define RAMSES_CPLD_BASE (RAMSES_COREVOLT_BASE + RAMSES_COREVOLT_SIZE)
-+#define RAMSES_CPLD_SIZE (1*1024*1024)
-+#define RAMSES_CONTROL_BASE (RAMSES_CPLD_BASE + RAMSES_CPLD_SIZE)
-+#define RAMSES_CONTROL_SIZE (1*1024*1024)
-+
-+#if (RAMSES_CONTROL_BASE + RAMSES_CONTROL_SIZE) > 0xfc000000
-+#error Your custom IO space is getting a bit large !!
-+#endif
-+
-+#define CPLD_P2V(x) ((x) - RAMSES_CPLD_PHYS + RAMSES_CPLD_BASE)
-+#define CPLD_V2P(x) ((x) - RAMSES_CPLD_BASE + RAMSES_CPLD_PHYS)
-+#define CTRL_P2V(x) ((x) - RAMSES_CONTROL_PHYS + RAMSES_CONTROL_BASE)
-+#define CTRL_V2P(x) ((x) - RAMSES_CONTROL_BASE + RAMSES_CONTROL_PHYS)
-+#define CORE_P2V(x) ((x) - RAMSES_COREVOLT_PHYS + RAMSES_COREVOLT_BASE)
-+#define CORE_V2P(x) ((x) - RAMSES_COREVOLT_BASE + RAMSES_COREVOLT_PHYS)
-+
-+//smc91111 driver compatibility issue
-+#define ETH_BASE RAMSES_ETH_BASE
-+
-+#ifndef __ASSEMBLY__
-+# define __CPLD_REG(x) (*((volatile unsigned long *)CPLD_P2V(x)))
-+# define __CTRL_REG(x) (*((volatile unsigned long *)CTRL_P2V(x)))
-+# define __CORE_REG(x) (*((volatile unsigned long *)CORE_P2V(x)))
-+#else
-+# define __CPLD_REG(x) CPLD_P2V(x)
-+# define __CTRL_REG(x) CTRL_P2V(x)
-+# define __CORE_REG(x) CORE_P2V(x)
-+#endif
-+
-+/* CPLD addresses */
-+
-+#define RAMSES_CPLD_PERIPH_PWR_ (RAMSES_CPLD_PHYS + 0x04)
-+#define RAMSES_CPLD_PERIPH_PWR __CPLD_REG(RAMSES_CPLD_PERIPH_PWR_)
-+#define PER_RESET (1 << 4)
-+#define PER_PWR_EN (1 << 3)
-+#define USB_HOST_PWR_EN (1 << 2)
-+#define CORE_VAR_EN (1 << 0)
-+
-+#define RAMSES_CPLD_LED_CONTROL_ (RAMSES_CPLD_PHYS + 0x08)
-+#define RAMSES_CPLD_LED_CONTROL __CPLD_REG(RAMSES_CPLD_LED_CONTROL_)
-+#define CPLD_LED2 (1 << 6)
-+#define CPLD_LED1 (1 << 5)
-+#define GSM_ACTIVE (1 << 4)
-+
-+#define RAMSES_CPLD_KB_COL_HIGH_ (RAMSES_CPLD_PHYS + 0x0C)
-+#define RAMSES_CPLD_KB_COL_HIGH __CPLD_REG(RAMSES_CPLD_KB_COL_HIGH_)
-+// kbch(7)..kbch(13) on bit 0..6
-+
-+#define RAMSES_CPLD_KB_COL_LOW_ (RAMSES_CPLD_PHYS + 0x10)
-+#define RAMSES_CPLD_KB_COL_LOW __CPLD_REG(RAMSES_CPLD_KB_COL_LOW_)
-+// kbcl(0)..kbch(6) on bit 0..6
-+
-+#define RAMSES_CPLD_PCCARD_EN_ (RAMSES_CPLD_PHYS + 0x14)
-+#define RAMSES_CPLD_PCCARD_EN __CPLD_REG(RAMSES_CPLD_PCCARD_EN_)
-+#define PCC1_RESET (1 << 7)
-+#define PCC0_RESET (1 << 6)
-+#define PCC1_ENABLE (1 << 1)
-+#define PCC0_ENABLE (1 << 0)
-+
-+#define RAMSES_CPLD_PCCARD_PWR_ (RAMSES_CPLD_PHYS + 0x28)
-+#define RAMSES_CPLD_PCCARD_PWR __CPLD_REG(RAMSES_CPLD_PCCARD_PWR_)
-+#define PCC1_PWR3 (1 << 7)
-+#define PCC1_PWR2 (1 << 6)
-+#define PCC1_PWR1 (1 << 5)
-+#define PCC1_PWR0 (1 << 4)
-+#define PCC0_PWR3 (1 << 3)
-+#define PCC0_PWR2 (1 << 2)
-+#define PCC0_PWR1 (1 << 1)
-+#define PCC0_PWR0 (1 << 0)
-+
-+#define RAMSES_CPLD_MISC_CTRL_ (RAMSES_CPLD_PHYS + 0x2C)
-+#define RAMSES_CPLD_MISC_CTRL __CPLD_REG(RAMSES_CPLD_MISC_CTRL_)
-+#define RAMSES_IRDA_MD1 (1 << 5)
-+#define RAMSES_IRDA_MD0 (1 << 4)
-+#define RAMSES_FIR (1 << 3)
-+
-+#define RAMSES_CPLD_LCD_ (RAMSES_CPLD_PHYS + 0x30)
-+#define RAMSES_CPLD_LCD __CPLD_REG(RAMSES_CPLD_LCD_)
-+#define RAMSES_LCD_PINC (1 << 7)
-+#define RAMSES_LCD_PUP (1 << 6)
-+#define RAMSES_LCD_PCS (1 << 5)
-+#define RAMSES_LCD_DISPOFF (1 << 2)
-+#define RAMSES_LCD_VCC (1 << 0)
-+
-+#define RAMSES_CPLD_FLASH_WE_ (RAMSES_CPLD_PHYS + 0x34)
-+#define RAMSES_CPLD_FLASH_WE __CPLD_REG(RAMSES_CPLD_FLASH_WE_)
-+#define RAMSES_FLASH_WE (1 << 0)
-+
-+/* Read-Only registers */
-+
-+#define RAMSES_CPLD_KB_ROW_ (RAMSES_CPLD_PHYS + 0x50)
-+#define RAMSES_CPLD_KB_ROW __CPLD_REG(RAMSES_CPLD_KB_ROW_)
-+// kbr(0)..kbr(6) on bits 0..6
-+
-+#define RAMSES_CPLD_PCCARD0_STATUS_ (RAMSES_CPLD_PHYS + 0x54)
-+#define RAMSES_CPLD_PCCARD0_STATUS __CPLD_REG(RAMSES_CPLD_PCCARD0_STATUS_)
-+#define RAMSES_CPLD_PCCARD1_STATUS_ (RAMSES_CPLD_PHYS + 0x58)
-+#define RAMSES_CPLD_PCCARD1_STATUS __CPLD_REG(RAMSES_CPLD_PCCARD1_STATUS_)
-+#define _PCC_WRPROT (1 << 7)
-+#define _PCC_S16 (1 << 7)
-+#define _PCC_RESET (1 << 6)
-+#define _PCC_IRQ (1 << 5)
-+#define _PCC_INPACK (1 << 4)
-+#define PCC_BVD2 (1 << 3)
-+#define PCC_BVD1 (1 << 2)
-+#define PCC_VS2 (1 << 1)
-+#define PCC_VS1 (1 << 0)
-+
-+#define RAMSES_CPLD_MISC_STATUS_ (RAMSES_CPLD_PHYS + 0x5C)
-+#define RAMSES_CPLD_MISC_STATUS __CPLD_REG(RAMSES_CPLD_MISC_STATUS_)
-+#define RAMSES_MMC_WRPROT (1 << 7)
-+#define RAMSES_USB_OVERCURR (1 << 4)
-+#define RAMSES_CHG_STS (1 << 2)
-+#define RAMSES_WALL_IN (1 << 1)
-+#define RAMSES_USB_D_CON (1 << 0)
-+
-+#define RAMSES_CPLD_YEAR_ (RAMSES_CPLD_PHYS + 0x60)
-+#define RAMSES_CPLD_YEAR __CPLD_REG(RAMSES_CPLD_YEAR_)
-+
-+#define RAMSES_CPLD_MONTH_ (RAMSES_CPLD_PHYS + 0x64)
-+#define RAMSES_CPLD_MONTH __CPLD_REG(RAMSES_CPLD_MONTH_)
-+
-+#define RAMSES_CPLD_DAY_ (RAMSES_CPLD_PHYS + 0x68)
-+#define RAMSES_CPLD_DAY __CPLD_REG(RAMSES_CPLD_DAY_)
-+
-+#define RAMSES_CPLD_REV_ (RAMSES_CPLD_PHYS + 0x6C)
-+#define RAMSES_CPLD_REV __CPLD_REG(RAMSES_CPLD_REV_)
-+
-+#define RAMSES_CPLD_VSTAT_ (RAMSES_CPLD_PHYS + 0x7C)
-+#define RAMSES_CPLD_VSTAT __CPLD_REG(RAMSES_CPLD_VSTAT_)
-+#define RAMSES_BWE (1 << 1)
-+
-+
-+/* Flags for ramses_flags */
-+
-+#define RAMSES_FLAGS_LCD_FBTURN (1<<0)
-+/* MUST stay bit 0 */
-+#define RAMSES_FLAGS_SCANNER_BEAM (1<<1)
-+#define RAMSES_FLAGS_KEY_SCAN (1<<2)
-+#define RAMSES_FLAGS_KEY_SUSPEND (1<<3)
-+#define RAMSES_FLAGS_KEY_OFF (1<<4)
-+
-+
-+/* Offset in SMC EEPROM for LCD type */
-+#define RAMSES_LCD_TYPE_OFFSET 0x23
-+
-+
-+/* The control register on the I/O board */
-+
-+#define RAMSES_CONTROL_ (RAMSES_CONTROL_PHYS + 0)
-+#define RAMSES_CONTROL __CTRL_REG(RAMSES_CONTROL_)
-+// 5c00 = 0101 1100 0000 0000
-+#define RAMSES_CONTROL_SCANNER_TRIG_ (1 << 15)
-+#define RAMSES_CONTROL_SCANNER_WAKE_ (1 << 14)
-+#define RAMSES_CONTROL_SCANNER_PWR (1 << 13)
-+#define RAMSES_CONTROL_LED_BLUE_ (1 << 12)
-+
-+#define RAMSES_CONTROL_LED_ORANGE_ (1 << 11)
-+#define RAMSES_CONTROL_GSM_RESET (1 << 10)
-+#define RAMSES_CONTROL_GSM_BOOT (1 << 9)
-+#define RAMSES_CONTROL_GSM_PWR (1 << 8)
-+
-+#define RAMSES_CONTROL_POWEROFF (1 << 7)
-+#define RAMSES_CONTROL_USB_INTERN (1 << 6)
-+#define RAMSES_CONTROL_MMC_PWR (1 << 5)
-+#define RAMSES_CONTROL_UART_PWR (1 << 4)
-+
-+#define RAMSES_CONTROL_LCD_BLIGHT (1 << 3)
-+#define RAMSES_CONTROL_USB (1 << 2)
-+
-+#define RAMSES_POWER_OFF() { ramses_control_shadow |= RAMSES_CONTROL_POWEROFF; RAMSES_CONTROL = ramses_control_shadow; }
-+
-+// Active low
-+#define RAMSES_SCANNER_TRIG_ON() { ramses_control_shadow &= ~RAMSES_CONTROL_SCANNER_TRIG_; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_SCANNER_TRIG_OFF() { ramses_control_shadow |= RAMSES_CONTROL_SCANNER_TRIG_; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_SCANNER_WAKE_ON() { ramses_control_shadow &= ~RAMSES_CONTROL_SCANNER_WAKE_; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_SCANNER_WAKE_OFF() { ramses_control_shadow |= RAMSES_CONTROL_SCANNER_WAKE_; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_LED_BLUE_ON() { ramses_control_shadow &= ~RAMSES_CONTROL_LED_BLUE_; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_LED_BLUE_OFF() { ramses_control_shadow |= RAMSES_CONTROL_LED_BLUE_; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_LED_ORANGE_ON() { ramses_control_shadow &= ~RAMSES_CONTROL_LED_ORANGE_; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_LED_ORANGE_OFF() { ramses_control_shadow |= RAMSES_CONTROL_LED_ORANGE_; RAMSES_CONTROL = ramses_control_shadow; }
-+
-+// Active high
-+#define RAMSES_SCANNER_ON() { ramses_control_shadow |= RAMSES_CONTROL_SCANNER_PWR; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_SCANNER_OFF() { ramses_control_shadow &= ~RAMSES_CONTROL_SCANNER_PWR; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_GSM_RESET_ON() { ramses_control_shadow |= RAMSES_CONTROL_GSM_RESET; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_GSM_RESET_OFF() { ramses_control_shadow &= ~RAMSES_CONTROL_GSM_RESET; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_GSM_BOOT_ON() { ramses_control_shadow |= RAMSES_CONTROL_GSM_BOOT; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_GSM_BOOT_OFF() { ramses_control_shadow &= ~RAMSES_CONTROL_GSM_BOOT; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_GSM_ON() { ramses_control_shadow |= RAMSES_CONTROL_GSM_PWR; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_GSM_OFF() { ramses_control_shadow &= ~RAMSES_CONTROL_GSM_PWR; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_USB_INTERN() { ramses_control_shadow |= RAMSES_CONTROL_USB_INTERN; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_USB_EXTERN() { ramses_control_shadow &= ~RAMSES_CONTROL_USB_INTERN; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_UART_ON() { ramses_control_shadow |= RAMSES_CONTROL_UART_PWR; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_UART_OFF() { ramses_control_shadow &= ~RAMSES_CONTROL_UART_PWR; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_MMC_ON() { ramses_control_shadow |= RAMSES_CONTROL_MMC_PWR; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_MMC_OFF() { ramses_control_shadow &= ~RAMSES_CONTROL_MMC_PWR; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_LCD_BLIGHT_ON() { ramses_control_shadow |= RAMSES_CONTROL_LCD_BLIGHT; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_LCD_BLIGHT_OFF() { ramses_control_shadow &= ~RAMSES_CONTROL_LCD_BLIGHT; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_USB_BUS_ON() { ramses_control_shadow |= RAMSES_CONTROL_USB; RAMSES_CONTROL = ramses_control_shadow; }
-+#define RAMSES_USB_BUS_OFF() { ramses_control_shadow &= ~RAMSES_CONTROL_USB; RAMSES_CONTROL = ramses_control_shadow; }
-+
-+// Corevolt settings
-+#define RAMSES_COREVOLT_ (RAMSES_COREVOLT_PHYS)
-+#define RAMSES_COREVOLT __CORE_REG(RAMSES_COREVOLT_)
-+
-+// Battery protocol
-+#define HDQ_TMP 0x02
-+#define HDQ_LMD 0x05
-+#define HDQ_VSB 0x0b
-+#define HDQ_CACT 0x0d
-+#define HDQ_SAEH 0x0f
-+#define HDQ_SAEL 0x10
-+#define HDQ_RCAC 0x11
-+#define HDQ_DCR 0x18
-+
-+
-+#ifndef __ASSEMBLY__
-+
-+/* Ramses specific functions */
-+void ramses_lcd_power_on(void);
-+void ramses_lcd_power_off(void);
-+void ramses_lcd_backlight_on(void);
-+void ramses_lcd_backlight_off(void);
-+void ramses_lcd_set_intensity(int i);
-+#ifdef OLDCODE
-+void ramses_lcd_set_pwm1(int p);
-+#endif
-+void ramses_lcd_set_brightness(int b);
-+void ramses_lcd_set_contrast(int c);
-+int ramses_lcd_get_intensity(void);
-+int ramses_lcd_get_brightness(void);
-+int ramses_lcd_get_contrast(void);
-+int ramses_hdq_get_reg(unsigned char reg);
-+void ramses_shut_off(void);
-+void ramses_set_corevolt(int volt);
-+
-+
-+/* shadow registers for write only registers */
-+extern u16 ramses_control_shadow;
-+extern int ramses_corevolt_shadow;
-+extern u16 ramses_lcd_type;
-+extern int ramses_lcd_pwm1_shadow;
-+
-+
-+/* flag register for various settings */
-+extern unsigned int ramses_flags;
-+
-+/*
-+ * macros to write to write only register
-+ *
-+ * none of these macros are protected from
-+ * multiple drivers using them in interrupt context.
-+ */
-+
-+#define WRITE_RAMSES_CONTROL(value, mask) \
-+{\
-+ ramses_control_shadow = ((value & mask) | (ramses_control_shadow & ~mask));\
-+ RAMSES_CONTROL = ramses_control_shadow;\
-+}
-+#endif
-+
-+/*
-+ * USB Host
-+ *
-+ * The SL811HS is selected with nCS3 and some address bits:
-+ *
-+ * 12 8 4
-+ * nA14, nCS[3], address mask 1011 1111 1111 0000 = xBf00
-+ */
-+#define SL811HS_PHYS (PXA_CS3_PHYS+0xBFF0)
-+#define SL811HS_DATA (PXA_CS3_PHYS+0xBFF4)
-+
-+
-+
-+
-+
-+
-+
-+#define PCC_DETECT(x) (GPLR(7 + (x)) & GPIO_bit(7 + (x)))
-+
-+
-+
-+
-+
-+/* A listing of interrupts used by external hardware devices */
-+
-+#define TOUCH_PANEL_IRQ IRQ_GPIO(21)
-+#define TOUCH_PANEL_IRQ_EDGE GPIO_FALLING_EDGE
-+
-+#define ETHERNET_IRQ IRQ_GPIO(4)
-+#define ETHERNET_IRQ_EDGE GPIO_RISING_EDGE
-+
-+#define CFCARD_CD_VALID IRQ_GPIO(8)
-+#define CFCARD_CD_VALID_EDGE GPIO_BOTH_EDGES
-+
-+#define CFCARD_RDYINT IRQ_GPIO(22)
-+
-+#define RAMSES_KEYBOARD_IRQ IRQ_GPIO(3)
-+#define RAMSES_KEYBOARD_IRQ_EDGE GPIO_FALLING_EDGE
-+
-+#define SL811HS_IRQ IRQ_GPIO(32)
-+#define SL811HS_IRQ_EDGE GPIO_RISING_EDGE
-+
-+/*
-+ * Macros for LED Driver
-+ */
-+
-+/* leds 0 = ON */
-+#define RAMSES_HB_LED (1<<5)
-+#define RAMSES_BUSY_LED (1<<6)
-+
-+#define RAMSES_LEDS_MASK (RAMSES_HB_LED | RAMSES_BUSY_LED)
-+
-+#define RAMSES_WRITE_LEDS(value) (RAMSES_CPLD_LED_CONTROL = ((RAMSES_CPLD_LED_CONTROL & ~(RAMSES_LEDS_MASK)) | value))
-+
-+/*
-+ * macros for MTD driver
-+ */
-+
-+#define FLASH_WRITE_PROTECT_DISABLE() ((RAMSES_CPLD_FLASH_WE) &= ~(0x1))
-+#define FLASH_WRITE_PROTECT_ENABLE() ((RAMSES_CPLD_FLASH_WE) |= (0x1))
-+
-+
---- linux-2.4.21/include/asm-arm/arch-pxa/time.h~pxa-timerint
-+++ linux-2.4.21/include/asm-arm/arch-pxa/time.h
-@@ -33,7 +33,7 @@
- /* IRQs are disabled before entering here from do_gettimeofday() */
- static unsigned long pxa_gettimeoffset (void)
- {
-- unsigned long ticks_to_match, elapsed, usec;
-+ long ticks_to_match, elapsed, usec;
-
- /* Get ticks before next timer match */
- ticks_to_match = OSMR0 - OSCR;
-@@ -41,6 +41,10 @@
- /* We need elapsed ticks since last match */
- elapsed = LATCH - ticks_to_match;
-
-+ /* don't get fooled by the workaround in pxa_timer_interrupt() */
-+ if (elapsed <= 0)
-+ return 0;
-+
- /* Now convert them to usec */
- usec = (unsigned long)(elapsed*tick)/LATCH;
-
-@@ -59,6 +63,15 @@
- * IRQs are disabled inside the loop to ensure coherence between
- * lost_ticks (updated in do_timer()) and the match reg value, so we
- * can use do_gettimeofday() from interrupt handlers.
-+ *
-+ * HACK ALERT: it seems that the PXA timer regs aren't updated right
-+ * away in all cases when a write occurs. We therefore compare with
-+ * 8 instead of 0 in the while() condition below to avoid missing a
-+ * match if OSCR has already reached the next OSMR value.
-+ * Experience has shown that up to 6 ticks are needed to work around
-+ * this problem, but let's use 8 to be conservative. Note that this
-+ * affect things only when the timer IRQ has been delayed by nearly
-+ * exactly one tick period which should be a pretty rare event.
- */
- do {
- do_leds();
-@@ -68,7 +81,7 @@
- OSSR = OSSR_M0; /* Clear match on timer 0 */
- next_match = (OSMR0 += LATCH);
- restore_flags( flags );
-- } while( (signed long)(next_match - OSCR) <= 0 );
-+ } while( (signed long)(next_match - OSCR) <= 8 );
- }
-
- extern inline void setup_timer (void)
---- /dev/null
-+++ linux-2.4.21/include/asm-arm/bug.h
-@@ -0,0 +1 @@
-+/* dummy */
---- /dev/null
-+++ linux-2.4.21/include/asm-arm/sl811-hw.h
-@@ -0,0 +1,202 @@
-+/*
-+File: include/asm-arm/sl811-hw.h
-+
-+19.09.2003 hne@ist1.de
-+Use Kernel 2.4.20 and this source from 2.4.22
-+Splitt hardware depens into file sl811-x86.h and sl811-arm.h.
-+Functions as inline.
-+
-+23.09.2003 hne
-+Move Hardware depend header sl811-arm.h into include/asm-arm/sl811-hw.h.
-+GPRD as parameter.
-+
-+24.09.2003 hne
-+Use Offset from ADDR to DATA instand of direct io.
-+
-+03.10.2003 hne
-+Low level only for port io into hardware-include.
-+*/
-+
-+#ifndef __LINUX_SL811_HW_H
-+#define __LINUX_SL811_HW_H
-+
-+#ifdef CONFIG_X86
-+#define MAX_CONTROLERS 1 /* Max number of sl811 controllers */
-+ /* Always 1 for this architecture! */
-+
-+#define SIZEOF_IO_REGION 1 /* Size for request/release region */
-+
-+#define OFFSET_DATA_REG data_off /* Offset from ADDR_IO to DATA_IO (future) */
-+ /* Can change by arg */
-+
-+static int io = 0xf100000e; /* Base addr_io */
-+static int data_off = 1; /* Offset from addr_io to addr_io */
-+static int irq = 44; /* also change gprd !!! */
-+static int gprd = 23; /* also change irq !!! */
-+
-+MODULE_PARM(io,"i");
-+MODULE_PARM_DESC(io,"sl811 address io port 0xf100000e");
-+MODULE_PARM(data_off,"i");
-+MODULE_PARM_DESC(data_off,"sl811 data io port offset from address port (default 1)");
-+MODULE_PARM(irq,"i");
-+MODULE_PARM_DESC(irq,"sl811 irq 44(default)");
-+MODULE_PARM(gprd,"i");
-+MODULE_PARM_DESC(gprd,"sl811 GPRD port 23(default)");
-+#endif
-+
-+#ifdef CONFIG_ARCH_RAMSES
-+#define SIZEOF_IO_REGION 8 /* Size for request/release region */
-+static void *ramses_sl811hs; /* dynamically assign virtual address */
-+#endif
-+
-+
-+/*
-+ * Low level: Read from Data port [arm]
-+ */
-+static __u8 inline sl811_read_data (struct sl811_hc *hc)
-+{
-+ __u8 data;
-+ data = readb(hc->data_io);
-+ rmb();
-+//printk("%s: in %08p %02x\n", __FUNCTION__, hc->data_io, data);
-+ return data;
-+}
-+
-+/*
-+ * Low level: Write to index register [arm]
-+ */
-+static void inline sl811_write_index (struct sl811_hc *hc, __u8 index)
-+{
-+//printk("%s: out %08p %02x\n", __FUNCTION__, hc->addr_io, index);
-+ writeb(index, hc->addr_io);
-+ wmb();
-+}
-+
-+/*
-+ * Low level: Write to Data port [arm]
-+ */
-+static void inline sl811_write_data (struct sl811_hc *hc, __u8 data)
-+{
-+//printk("%s: out %08p %02x\n", __FUNCTION__, hc->data_io, data);
-+ writeb(data, hc->data_io);
-+ wmb();
-+}
-+
-+/*
-+ * Low level: Write to index register and data port [arm]
-+ */
-+static void inline sl811_write_index_data (struct sl811_hc *hc, __u8 index, __u8 data)
-+{
-+ writeb(index, hc->addr_io);
-+//printk("%s: out %08p %02x\n", __FUNCTION__, hc->addr_io, index);
-+ writeb(data, hc->data_io);
-+//printk("%s: out %08p %02x\n", __FUNCTION__, hc->data_io, data);
-+ wmb();
-+}
-+
-+
-+/*
-+ * This function is board specific. It sets up the interrupt to
-+ * be an edge trigger and trigger on the rising edge
-+ */
-+static void inline sl811_init_irq(void)
-+{
-+#ifdef CONFIG_X86
-+ GPDR &= ~(1<<gprd);
-+ set_GPIO_IRQ_edge(1<<gprd, GPIO_RISING_EDGE);
-+#endif
-+#ifdef CONFIG_ARCH_PXA
-+ int irq_gpio_pin = IRQ_TO_GPIO_2_80(SL811HS_IRQ);
-+ GPDR(irq_gpio_pin) &= ~GPIO_bit(irq_gpio_pin);
-+ set_GPIO_IRQ_edge(irq_gpio_pin, SL811HS_IRQ_EDGE);
-+#endif
-+}
-+
-+/*****************************************************************
-+ *
-+ * Function Name: release_regions [arm]
-+ *
-+ * This function is board specific. It release all io address
-+ * from memory (if can).
-+ *
-+ * Input: struct sl811_hc * *
-+ *
-+ * Return value : 0 = OK
-+ *
-+ *****************************************************************/
-+static void inline sl811_release_regions(struct sl811_hc *hc)
-+{
-+#ifdef CONFIG_X86
-+ if (hc->addr_io)
-+ release_region(hc->addr_io, SIZEOF_IO_REGION);
-+ hc->addr_io = 0;
-+
-+ if (hc->data_io)
-+ release_region(hc->data_io, SIZEOF_IO_REGION);
-+ hc->data_io = 0;
-+#endif
-+#ifdef CONFIG_ARCH_RAMSES
-+ if (ramses_sl811hs) {
-+ iounmap(ramses_sl811hs);
-+ release_mem_region(SL811HS_PHYS, SIZEOF_IO_REGION);
-+ }
-+ hc->addr_io = 0;
-+ hc->data_io = 0;
-+ RAMSES_CPLD_PERIPH_PWR &= ~USB_HOST_PWR_EN;
-+ RAMSES_USB_BUS_OFF();
-+#endif
-+}
-+
-+/*****************************************************************
-+ *
-+ * Function Name: request_regions [arm]
-+ *
-+ * This function is board specific. It request all io address and
-+ * maps into memory (if can).
-+ *
-+ * Input: struct sl811_hc *
-+ *
-+ * Return value : 0 = OK
-+ *
-+ *****************************************************************/
-+static int inline sl811_request_regions (struct sl811_hc *hc, int addr_io, int data_io, const char *name)
-+{
-+#ifdef CONFIG_X86
-+ if (!request_region(addr_io, SIZEOF_IO_REGION, name)) {
-+ PDEBUG(3, "request address %d failed", addr_io);
-+ return -EBUSY;
-+ }
-+ hc->addr_io = addr_io;
-+
-+ if (!request_region(data_io, SIZEOF_IO_REGION, MODNAME)) {
-+ PDEBUG(3, "request address %d failed", data_io);
-+ /* release_region(hc->addr_io, SIZEOF_IO_REGION); */
-+ return -EBUSY;
-+ }
-+ hc->data_io = data_io;
-+#endif
-+#ifdef CONFIG_ARCH_RAMSES
-+ RAMSES_USB_BUS_ON();
-+ RAMSES_CPLD_PERIPH_PWR |= USB_HOST_PWR_EN;
-+ mdelay(300);
-+
-+ if (!request_mem_region(SL811HS_PHYS, SIZEOF_IO_REGION, name)) {
-+ printk(KERN_ERR "unable to reserve region\n");
-+ return -EBUSY;
-+ } else {
-+ ramses_sl811hs = ioremap_nocache(SL811HS_PHYS, SIZEOF_IO_REGION);
-+ dbg("phys %p -> virt %p\n", SL811HS_PHYS, ramses_sl811hs);
-+ if (!ramses_sl811hs) {
-+ printk(KERN_ERR "unable to map region\n");
-+ release_mem_region(SL811HS_PHYS, SIZEOF_IO_REGION);
-+ return -EBUSY;
-+ }
-+ }
-+ hc->addr_io = (unsigned long) ramses_sl811hs;
-+ hc->data_io = (unsigned long) ramses_sl811hs+4;
-+#endif
-+
-+ return 0;
-+}
-+
-+#endif // __LINUX_SL811_HW_H
---- linux-2.4.21/include/linux/apm_bios.h~pm
-+++ linux-2.4.21/include/linux/apm_bios.h
-@@ -16,6 +16,8 @@
- * General Public License for more details.
- */
-
-+#include <linux/pm-devices.h>
-+
- typedef unsigned short apm_event_t;
- typedef unsigned short apm_eventinfo_t;
-
-@@ -59,6 +61,16 @@
- };
-
- /*
-+ * Allow device specific code to register function which
-+ * gets the battery power status (see arch/arm/mach-pxa/apm.c).
-+ */
-+extern void apm_register_get_power_status( int (*fn)(u_char *ac_line_status,
-+ u_char *battery_status,
-+ u_char *battery_flag,
-+ u_char *battery_percentage,
-+ u_short *battery_life));
-+
-+/*
- * The APM function codes
- */
- #define APM_FUNC_INST_CHECK 0x5300
-@@ -168,6 +180,7 @@
- /*
- * APM Device IDs
- */
-+#ifdef _i386_
- #define APM_DEVICE_BIOS 0x0000
- #define APM_DEVICE_ALL 0x0001
- #define APM_DEVICE_DISPLAY 0x0100
-@@ -181,6 +194,21 @@
- #define APM_DEVICE_OLD_ALL 0xffff
- #define APM_DEVICE_CLASS 0x00ff
- #define APM_DEVICE_MASK 0xff00
-+#endif
-+
-+/*
-+ * APM devices IDs for non-x86
-+ */
-+#define APM_DEVICE_ALL PM_SYS_DEV
-+#define APM_DEVICE_DISPLAY PM_DISPLAY_DEV
-+#define APM_DEVICE_STORAGE PM_STORAGE_DEV
-+#define APM_DEVICE_PARALLEL PM_PARALLEL_DEV
-+#define APM_DEVICE_SERIAL PM_SERIAL_DEV
-+#define APM_DEVICE_NETWORK PM_NETWORK_DEV
-+#define APM_DEVICE_PCMCIA PM_PCMCIA_DEV
-+#define APM_DEVICE_BATTERY PM_BATTERY_DEV
-+#define APM_DEVICE_TPANEL PM_TPANEL_DEV
-+
-
- #ifdef __KERNEL__
- /*
-@@ -214,5 +242,6 @@
-
- #define APM_IOC_STANDBY _IO('A', 1)
- #define APM_IOC_SUSPEND _IO('A', 2)
-+#define APM_IOC_SET_WAKEUP _IO('A', 3)
-
- #endif /* LINUX_APM_H */
---- linux-2.4.21/include/linux/crc32.h~mtd-cvs
-+++ linux-2.4.21/include/linux/crc32.h
-@@ -46,4 +46,25 @@
- return crc;
- }
-
--#endif /* _LINUX_CRC32_H */
-+#ifndef CRC32_H
-+#define CRC32_H
-+
-+/* $Id: crc32.h,v 1.4 2002/01/03 15:20:44 dwmw2 Exp $ */
-+
-+#include <linux/types.h>
-+
-+extern const uint32_t crc32_table[256];
-+
-+/* Return a 32-bit CRC of the contents of the buffer. */
-+
-+static inline uint32_t
-+crc32(uint32_t val, const void *ss, int len)
-+{
-+ const unsigned char *s = ss;
-+ while (--len >= 0)
-+ val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
-+ return val;
-+}
-+
-+#endif
-+#endif
---- /dev/null
-+++ linux-2.4.21/include/linux/firmware.h
-@@ -0,0 +1,20 @@
-+#ifndef _LINUX_FIRMWARE_H
-+#define _LINUX_FIRMWARE_H
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#define FIRMWARE_NAME_MAX 30
-+struct firmware {
-+ size_t size;
-+ u8 *data;
-+};
-+int request_firmware (const struct firmware **fw, const char *name,
-+ const char *device);
-+int request_firmware_nowait (
-+ struct module *module,
-+ const char *name, const char *device, void *context,
-+ void (*cont)(const struct firmware *fw, void *context));
-+/* On 2.5 'device' is 'struct device *' */
-+
-+void release_firmware (const struct firmware *fw);
-+void register_firmware (const char *name, const u8 *data, size_t size);
-+#endif
---- linux-2.4.21/include/linux/fs.h~mtd-cvs
-+++ linux-2.4.21/include/linux/fs.h
-@@ -1376,6 +1376,7 @@
- extern void iput(struct inode *);
- extern void force_delete(struct inode *);
- extern struct inode * igrab(struct inode *);
-+extern struct inode * ilookup(struct super_block *, unsigned long);
- extern ino_t iunique(struct super_block *, ino_t);
-
- typedef int (*find_inode_t)(struct inode *, unsigned long, void *);
---- linux-2.4.21/include/linux/i2c-id.h~i2c-ds1337
-+++ linux-2.4.21/include/linux/i2c-id.h
-@@ -95,13 +95,14 @@
- #define I2C_DRIVERID_ADV717x 48 /* ADV 7175/7176 video encoder */
- #define I2C_DRIVERID_ZR36067 49 /* Zoran 36067 video encoder */
- #define I2C_DRIVERID_ZR36120 50 /* Zoran 36120 video encoder */
--#define I2C_DRIVERID_24LC32A 51 /* Microchip 24LC32A 32k EEPROM */
-+#define I2C_DRIVERID_24LC32A 51 /* Microchip 24LC32A 32k EEPROM */
-+#define I2C_DRIVERID_DS1337 52 /* DS1337 real time clock */
-
-
-
--#define I2C_DRIVERID_DS1307 46 /* real time clock: DS1307 */
--#define I2C_DRIVERID_24LC64 47 /* EEprom 24LC64 */
--#define I2C_DRIVERID_FM24CLB4 48 /* EEprom FM24CLB4 */
-+//#define I2C_DRIVERID_DS1307 46 /* real time clock: DS1307 */
-+//#define I2C_DRIVERID_24LC64 47 /* EEprom 24LC64 */
-+//#define I2C_DRIVERID_FM24CLB4 48 /* EEprom FM24CLB4 */
-
- #define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */
- #define I2C_DRIVERID_EXP1 0xF1
---- linux-2.4.21/include/linux/input.h~bluetooth
-+++ linux-2.4.21/include/linux/input.h
-@@ -472,7 +472,8 @@
- #define BUS_PCI 0x01
- #define BUS_ISAPNP 0x02
- #define BUS_USB 0x03
--#define BUS_HIL 0x04
-+#define BUS_HIL 0x04
-+#define BUS_BLUETOOTH 0x05
-
- #define BUS_ISA 0x10
- #define BUS_I8042 0x11
---- linux-2.4.21/include/linux/jffs2.h~mtd-cvs
-+++ linux-2.4.21/include/linux/jffs2.h
-@@ -1,50 +1,30 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-+ * Created by David Woodhouse <dwmw2@infradead.org>
- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), 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 RHEPL, 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 RHEPL or the GPL.
-+ * For licensing information, see the file 'LICENCE' in the
-+ * jffs2 directory.
- *
-- * $Id: jffs2.h,v 1.19 2001/10/09 13:20:23 dwmw2 Exp $
-+ * $Id: jffs2.h,v 1.34 2004/11/16 20:36:14 dwmw2 Exp $
- *
- */
-
- #ifndef __LINUX_JFFS2_H__
- #define __LINUX_JFFS2_H__
-
--#include <asm/types.h>
-+/* You must include something which defines the C99 uintXX_t types.
-+ We don't do it from here because this file is used in too many
-+ different environments. */
-+
- #define JFFS2_SUPER_MAGIC 0x72b6
-
- /* Values we may expect to find in the 'magic' field */
- #define JFFS2_OLD_MAGIC_BITMASK 0x1984
- #define JFFS2_MAGIC_BITMASK 0x1985
--#define KSAMTIB_CIGAM_2SFFJ 0x5981 /* For detecting wrong-endian fs */
-+#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */
- #define JFFS2_EMPTY_BITMASK 0xffff
- #define JFFS2_DIRTY_BITMASK 0x0000
-
-@@ -63,6 +43,8 @@
- #define JFFS2_COMPR_COPY 0x04
- #define JFFS2_COMPR_DYNRUBIN 0x05
- #define JFFS2_COMPR_ZLIB 0x06
-+#define JFFS2_COMPR_LZO 0x07
-+#define JFFS2_COMPR_LZARI 0x08
- /* Compatibility flags. */
- #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
- #define JFFS2_NODE_ACCURATE 0x2000
-@@ -78,16 +60,12 @@
- #define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
- #define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2)
- #define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
-+#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
-
- // Maybe later...
- //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
- //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
-
--/* Same as the non_ECC versions, but with extra space for real
-- * ECC instead of just the checksum. For use on NAND flash
-- */
--//#define JFFS2_NODETYPE_DIRENT_ECC (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 5)
--//#define JFFS2_NODETYPE_INODE_ECC (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 6)
-
- #define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at
- mount time, don't wait for it to
-@@ -96,31 +74,46 @@
- compression type */
-
-
-+/* These can go once we've made sure we've caught all uses without
-+ byteswapping */
-+
-+typedef struct {
-+ uint32_t v32;
-+} __attribute__((packed)) jint32_t;
-+
-+typedef struct {
-+ uint32_t m;
-+} __attribute__((packed)) jmode_t;
-+
-+typedef struct {
-+ uint16_t v16;
-+} __attribute__((packed)) jint16_t;
-+
- struct jffs2_unknown_node
- {
- /* All start like this */
-- __u16 magic;
-- __u16 nodetype;
-- __u32 totlen; /* So we can skip over nodes we don't grok */
-- __u32 hdr_crc;
-+ jint16_t magic;
-+ jint16_t nodetype;
-+ jint32_t totlen; /* So we can skip over nodes we don't grok */
-+ jint32_t hdr_crc;
- } __attribute__((packed));
-
- struct jffs2_raw_dirent
- {
-- __u16 magic;
-- __u16 nodetype; /* == JFFS_NODETYPE_DIRENT */
-- __u32 totlen;
-- __u32 hdr_crc;
-- __u32 pino;
-- __u32 version;
-- __u32 ino; /* == zero for unlink */
-- __u32 mctime;
-- __u8 nsize;
-- __u8 type;
-- __u8 unused[2];
-- __u32 node_crc;
-- __u32 name_crc;
-- __u8 name[0];
-+ jint16_t magic;
-+ jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */
-+ jint32_t totlen;
-+ jint32_t hdr_crc;
-+ jint32_t pino;
-+ jint32_t version;
-+ jint32_t ino; /* == zero for unlink */
-+ jint32_t mctime;
-+ uint8_t nsize;
-+ uint8_t type;
-+ uint8_t unused[2];
-+ jint32_t node_crc;
-+ jint32_t name_crc;
-+ uint8_t name[0];
- } __attribute__((packed));
-
- /* The JFFS2 raw inode structure: Used for storage on physical media. */
-@@ -131,28 +124,28 @@
- */
- struct jffs2_raw_inode
- {
-- __u16 magic; /* A constant magic number. */
-- __u16 nodetype; /* == JFFS_NODETYPE_INODE */
-- __u32 totlen; /* Total length of this node (inc data, etc.) */
-- __u32 hdr_crc;
-- __u32 ino; /* Inode number. */
-- __u32 version; /* Version number. */
-- __u32 mode; /* The file's type or mode. */
-- __u16 uid; /* The file's owner. */
-- __u16 gid; /* The file's group. */
-- __u32 isize; /* Total resultant size of this inode (used for truncations) */
-- __u32 atime; /* Last access time. */
-- __u32 mtime; /* Last modification time. */
-- __u32 ctime; /* Change time. */
-- __u32 offset; /* Where to begin to write. */
-- __u32 csize; /* (Compressed) data size */
-- __u32 dsize; /* Size of the node's data. (after decompression) */
-- __u8 compr; /* Compression algorithm used */
-- __u8 usercompr; /* Compression algorithm requested by the user */
-- __u16 flags; /* See JFFS2_INO_FLAG_* */
-- __u32 data_crc; /* CRC for the (compressed) data. */
-- __u32 node_crc; /* CRC for the raw inode (excluding data) */
--// __u8 data[dsize];
-+ jint16_t magic; /* A constant magic number. */
-+ jint16_t nodetype; /* == JFFS_NODETYPE_INODE */
-+ jint32_t totlen; /* Total length of this node (inc data, etc.) */
-+ jint32_t hdr_crc;
-+ jint32_t ino; /* Inode number. */
-+ jint32_t version; /* Version number. */
-+ jmode_t mode; /* The file's type or mode. */
-+ jint16_t uid; /* The file's owner. */
-+ jint16_t gid; /* The file's group. */
-+ jint32_t isize; /* Total resultant size of this inode (used for truncations) */
-+ jint32_t atime; /* Last access time. */
-+ jint32_t mtime; /* Last modification time. */
-+ jint32_t ctime; /* Change time. */
-+ jint32_t offset; /* Where to begin to write. */
-+ jint32_t csize; /* (Compressed) data size */
-+ jint32_t dsize; /* Size of the node's data. (after decompression) */
-+ uint8_t compr; /* Compression algorithm used */
-+ uint8_t usercompr; /* Compression algorithm requested by the user */
-+ jint16_t flags; /* See JFFS2_INO_FLAG_* */
-+ jint32_t data_crc; /* CRC for the (compressed) data. */
-+ jint32_t node_crc; /* CRC for the raw inode (excluding data) */
-+ uint8_t data[0];
- } __attribute__((packed));
-
- union jffs2_node_union {
---- linux-2.4.21/include/linux/jffs2_fs_i.h~mtd-cvs
-+++ linux-2.4.21/include/linux/jffs2_fs_i.h
-@@ -1,22 +1,13 @@
--/* $Id: jffs2_fs_i.h,v 1.8 2001/04/18 13:05:28 dwmw2 Exp $ */
-+/* $Id: jffs2_fs_i.h,v 1.17 2004/11/11 23:51:27 dwmw2 Exp $ */
-
- #ifndef _JFFS2_FS_I
- #define _JFFS2_FS_I
-
--/* Include the pipe_inode_info at the beginning so that we can still
-- use the storage space in the inode when we have a pipe inode.
-- This sucks.
--*/
--
--#undef THISSUCKS /* Only for 2.2 */
--#ifdef THISSUCKS
--#include <linux/pipe_fs_i.h>
--#endif
-+#include <linux/version.h>
-+#include <linux/rbtree.h>
-+#include <asm/semaphore.h>
-
- struct jffs2_inode_info {
--#ifdef THISSUCKS
-- struct pipe_inode_info pipecrap;
--#endif
- /* We need an internal semaphore similar to inode->i_sem.
- Unfortunately, we can't used the existing one, because
- either the GC would deadlock, or we'd have to release it
-@@ -26,10 +17,10 @@
- struct semaphore sem;
-
- /* The highest (datanode) version number used for this ino */
-- __u32 highest_version;
-+ uint32_t highest_version;
-
- /* List of data fragments which make up the file */
-- struct jffs2_node_frag *fraglist;
-+ struct rb_root fragtree;
-
- /* There may be one datanode which isn't referenced by any of the
- above fragments, if it contains a metadata update but no actual
-@@ -44,19 +35,13 @@
- /* Some stuff we just have to keep in-core at all times, for each inode. */
- struct jffs2_inode_cache *inocache;
-
-- /* Keep a pointer to the last physical node in the list. We don't
-- use the doubly-linked lists because we don't want to increase
-- the memory usage that much. This is simpler */
-- // struct jffs2_raw_node_ref *lastnode;
-- __u16 flags;
-- __u8 usercompr;
--};
--
--#ifdef JFFS2_OUT_OF_KERNEL
--#define JFFS2_INODE_INFO(i) ((struct jffs2_inode_info *) &(i)->u)
--#else
--#define JFFS2_INODE_INFO(i) (&i->u.jffs2_i)
-+ uint16_t flags;
-+ uint8_t usercompr;
-+#if !defined (__ECOS)
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
-+ struct inode vfs_inode;
-+#endif
- #endif
-+};
-
- #endif /* _JFFS2_FS_I */
--
---- linux-2.4.21/include/linux/jffs2_fs_sb.h~mtd-cvs
-+++ linux-2.4.21/include/linux/jffs2_fs_sb.h
-@@ -1,18 +1,23 @@
--/* $Id: jffs2_fs_sb.h,v 1.16.2.1 2002/02/23 14:13:34 dwmw2 Exp $ */
-+/* $Id: jffs2_fs_sb.h,v 1.51 2005/02/28 08:21:06 dedekind Exp $ */
-
- #ifndef _JFFS2_FS_SB
- #define _JFFS2_FS_SB
-
- #include <linux/types.h>
- #include <linux/spinlock.h>
-+#include <linux/workqueue.h>
- #include <linux/completion.h>
- #include <asm/semaphore.h>
-+#include <linux/timer.h>
-+#include <linux/wait.h>
- #include <linux/list.h>
--
--#define INOCACHE_HASHSIZE 1
-+#include <linux/rwsem.h>
-
- #define JFFS2_SB_FLAG_RO 1
--#define JFFS2_SB_FLAG_MOUNTING 2
-+#define JFFS2_SB_FLAG_SCANNING 2 /* Flash scanning is in progress */
-+#define JFFS2_SB_FLAG_BUILDING 4 /* File system building is in progress */
-+
-+struct jffs2_inodirty;
-
- /* A struct for the overall file system control. Pointers to
- jffs2_sb_info structs are named `c' in the source code.
-@@ -21,36 +26,44 @@
- struct jffs2_sb_info {
- struct mtd_info *mtd;
-
-- __u32 highest_ino;
-+ uint32_t highest_ino;
-+ uint32_t checked_ino;
-+
- unsigned int flags;
-- spinlock_t nodelist_lock;
-
-- // pid_t thread_pid; /* GC thread's PID */
- struct task_struct *gc_task; /* GC task struct */
- struct semaphore gc_thread_start; /* GC thread start mutex */
- struct completion gc_thread_exit; /* GC thread exit completion port */
-- // __u32 gc_minfree_threshold; /* GC trigger thresholds */
-- // __u32 gc_maxdirty_threshold;
-
- struct semaphore alloc_sem; /* Used to protect all the following
- fields, and also to protect against
-- out-of-order writing of nodes.
-- And GC.
-- */
-- __u32 flash_size;
-- __u32 used_size;
-- __u32 dirty_size;
-- __u32 free_size;
-- __u32 erasing_size;
-- __u32 bad_size;
-- __u32 sector_size;
-- // __u32 min_free_size;
-- // __u32 max_chunk_size;
-+ out-of-order writing of nodes. And GC. */
-+ uint32_t cleanmarker_size; /* Size of an _inline_ CLEANMARKER
-+ (i.e. zero for OOB CLEANMARKER */
-
-- __u32 nr_free_blocks;
-- __u32 nr_erasing_blocks;
-+ uint32_t flash_size;
-+ uint32_t used_size;
-+ uint32_t dirty_size;
-+ uint32_t wasted_size;
-+ uint32_t free_size;
-+ uint32_t erasing_size;
-+ uint32_t bad_size;
-+ uint32_t sector_size;
-+ uint32_t unchecked_size;
-
-- __u32 nr_blocks;
-+ uint32_t nr_free_blocks;
-+ uint32_t nr_erasing_blocks;
-+
-+ /* Number of free blocks there must be before we... */
-+ uint8_t resv_blocks_write; /* ... allow a normal filesystem write */
-+ uint8_t resv_blocks_deletion; /* ... allow a normal filesystem deletion */
-+ uint8_t resv_blocks_gctrigger; /* ... wake up the GC thread */
-+ uint8_t resv_blocks_gcbad; /* ... pick a block from the bad_list to GC */
-+ uint8_t resv_blocks_gcmerge; /* ... merge pages when garbage collecting */
-+
-+ uint32_t nospc_dirty_size;
-+
-+ uint32_t nr_blocks;
- struct jffs2_eraseblock *blocks; /* The whole array of blocks. Used for getting blocks
- * from the offset (blocks[ofs / sector_size]) */
- struct jffs2_eraseblock *nextblock; /* The block we're currently filling */
-@@ -58,9 +71,12 @@
- struct jffs2_eraseblock *gcblock; /* The block we're currently garbage-collecting */
-
- struct list_head clean_list; /* Blocks 100% full of clean data */
-+ struct list_head very_dirty_list; /* Blocks with lots of dirty space */
- struct list_head dirty_list; /* Blocks with some dirty space */
-+ struct list_head erasable_list; /* Blocks which are completely dirty, and need erasing */
-+ struct list_head erasable_pending_wbuf_list; /* Blocks which need erasing but only after the current wbuf is flushed */
- struct list_head erasing_list; /* Blocks which are currently erasing */
-- struct list_head erase_pending_list; /* Blocks which need erasing */
-+ struct list_head erase_pending_list; /* Blocks which need erasing now */
- struct list_head erase_complete_list; /* Blocks which are erased and need the clean marker written to them */
- struct list_head free_list; /* Blocks which are free and ready to be used */
- struct list_head bad_list; /* Bad blocks. */
-@@ -69,16 +85,35 @@
- spinlock_t erase_completion_lock; /* Protect free_list and erasing_list
- against erase completion handler */
- wait_queue_head_t erase_wait; /* For waiting for erases to complete */
-- struct jffs2_inode_cache *inocache_list[INOCACHE_HASHSIZE];
-+
-+ wait_queue_head_t inocache_wq;
-+ struct jffs2_inode_cache **inocache_list;
- spinlock_t inocache_lock;
--};
-
--#ifdef JFFS2_OUT_OF_KERNEL
--#define JFFS2_SB_INFO(sb) ((struct jffs2_sb_info *) &(sb)->u)
--#else
--#define JFFS2_SB_INFO(sb) (&sb->u.jffs2_sb)
-+ /* Sem to allow jffs2_garbage_collect_deletion_dirent to
-+ drop the erase_completion_lock while it's holding a pointer
-+ to an obsoleted node. I don't like this. Alternatives welcomed. */
-+ struct semaphore erase_free_sem;
-+
-+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
-+ /* Write-behind buffer for NAND flash */
-+ unsigned char *wbuf;
-+ uint32_t wbuf_ofs;
-+ uint32_t wbuf_len;
-+ uint32_t wbuf_pagesize;
-+ struct jffs2_inodirty *wbuf_inodes;
-+
-+ struct rw_semaphore wbuf_sem; /* Protects the write buffer */
-+
-+ /* Information about out-of-band area usage... */
-+ struct nand_oobinfo *oobinfo;
-+ uint32_t badblock_pos;
-+ uint32_t fsdata_pos;
-+ uint32_t fsdata_len;
- #endif
-
--#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) )
-+ /* OS-private pointer for getting back to master superblock info */
-+ void *os_priv;
-+};
-
- #endif /* _JFFS2_FB_SB */
---- /dev/null
-+++ linux-2.4.21/include/linux/mtd/blktrans.h
-@@ -0,0 +1,72 @@
-+/*
-+ * $Id: blktrans.h,v 1.5 2003/06/23 12:00:08 dwmw2 Exp $
-+ *
-+ * (C) 2003 David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * Interface to Linux block layer for MTD 'translation layers'.
-+ *
-+ */
-+
-+#ifndef __MTD_TRANS_H__
-+#define __MTD_TRANS_H__
-+
-+#include <asm/semaphore.h>
-+
-+struct hd_geometry;
-+struct mtd_info;
-+struct mtd_blktrans_ops;
-+struct file;
-+struct inode;
-+
-+struct mtd_blktrans_dev {
-+ struct mtd_blktrans_ops *tr;
-+ struct list_head list;
-+ struct mtd_info *mtd;
-+ struct semaphore sem;
-+ int devnum;
-+ int blksize;
-+ unsigned long size;
-+ int readonly;
-+ void *blkcore_priv; /* gendisk in 2.5, devfs_handle in 2.4 */
-+};
-+
-+struct blkcore_priv; /* Differs for 2.4 and 2.5 kernels; private */
-+
-+struct mtd_blktrans_ops {
-+ char *name;
-+ int major;
-+ int part_bits;
-+
-+ /* Access functions */
-+ int (*readsect)(struct mtd_blktrans_dev *dev,
-+ unsigned long block, char *buffer);
-+ int (*writesect)(struct mtd_blktrans_dev *dev,
-+ unsigned long block, char *buffer);
-+
-+ /* Block layer ioctls */
-+ int (*getgeo)(struct mtd_blktrans_dev *dev, struct hd_geometry *geo);
-+ int (*flush)(struct mtd_blktrans_dev *dev);
-+
-+ /* Called with mtd_table_mutex held; no race with add/remove */
-+ int (*open)(struct mtd_blktrans_dev *dev);
-+ int (*release)(struct mtd_blktrans_dev *dev);
-+
-+ /* Called on {de,}registration and on subsequent addition/removal
-+ of devices, with mtd_table_mutex held. */
-+ void (*add_mtd)(struct mtd_blktrans_ops *tr, struct mtd_info *mtd);
-+ void (*remove_dev)(struct mtd_blktrans_dev *dev);
-+
-+ struct list_head devs;
-+ struct list_head list;
-+ struct module *owner;
-+
-+ struct mtd_blkcore_priv *blkcore_priv;
-+};
-+
-+extern int register_mtd_blktrans(struct mtd_blktrans_ops *tr);
-+extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr);
-+extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
-+extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
-+
-+
-+#endif /* __MTD_TRANS_H__ */
---- linux-2.4.21/include/linux/mtd/cfi.h~mtd-cvs
-+++ linux-2.4.21/include/linux/mtd/cfi.h
-@@ -1,211 +1,86 @@
-
- /* Common Flash Interface structures
- * See http://support.intel.com/design/flash/technote/index.htm
-- * $Id: cfi.h,v 1.32 2002/09/05 05:15:32 acurtis Exp $
-+ * $Id: cfi.h,v 1.52 2005/02/08 17:11:15 nico Exp $
- */
-
- #ifndef __MTD_CFI_H__
- #define __MTD_CFI_H__
-
- #include <linux/config.h>
-+#include <linux/version.h>
- #include <linux/delay.h>
- #include <linux/types.h>
- #include <linux/interrupt.h>
- #include <linux/mtd/flashchip.h>
-+#include <linux/mtd/map.h>
- #include <linux/mtd/cfi_endian.h>
-
--/*
-- * You can optimize the code size and performance by defining only
-- * the geometry(ies) available on your hardware.
-- * CFIDEV_INTERLEAVE_n, where represents the interleave (number of chips to fill the bus width)
-- * CFIDEV_BUSWIDTH_n, where n is the bus width in bytes (1, 2, 4 or 8 bytes)
-- *
-- * By default, all (known) geometries are supported.
-- */
--
--#ifndef CONFIG_MTD_CFI_GEOMETRY
--
--/* The default case - support all but 64-bit, which has
-- a performance penalty */
--
--#define CFIDEV_INTERLEAVE_1 (1)
--#define CFIDEV_INTERLEAVE_2 (2)
--#define CFIDEV_INTERLEAVE_4 (4)
--
--#define CFIDEV_BUSWIDTH_1 (1)
--#define CFIDEV_BUSWIDTH_2 (2)
--#define CFIDEV_BUSWIDTH_4 (4)
--
--typedef __u32 cfi_word;
--
--#else
--
--/* Explicitly configured buswidth/interleave support */
--
- #ifdef CONFIG_MTD_CFI_I1
--#define CFIDEV_INTERLEAVE_1 (1)
--#endif
--#ifdef CONFIG_MTD_CFI_I2
--#define CFIDEV_INTERLEAVE_2 (2)
--#endif
--#ifdef CONFIG_MTD_CFI_I4
--#define CFIDEV_INTERLEAVE_4 (4)
--#endif
--#ifdef CONFIG_MTD_CFI_I8
--#define CFIDEV_INTERLEAVE_8 (8)
--#endif
--
--#ifdef CONFIG_MTD_CFI_B1
--#define CFIDEV_BUSWIDTH_1 (1)
--#endif
--#ifdef CONFIG_MTD_CFI_B2
--#define CFIDEV_BUSWIDTH_2 (2)
--#endif
--#ifdef CONFIG_MTD_CFI_B4
--#define CFIDEV_BUSWIDTH_4 (4)
--#endif
--#ifdef CONFIG_MTD_CFI_B8
--#define CFIDEV_BUSWIDTH_8 (8)
--#endif
--
--/* pick the largest necessary */
--#ifdef CONFIG_MTD_CFI_B8
--typedef __u64 cfi_word;
--
--/* This only works if asm/io.h is included first */
--#ifndef __raw_readll
--#define __raw_readll(addr) (*(volatile __u64 *)(addr))
--#endif
--#ifndef __raw_writell
--#define __raw_writell(v, addr) (*(volatile __u64 *)(addr) = (v))
--#endif
--#define CFI_WORD_64
--#else /* CONFIG_MTD_CFI_B8 */
--/* All others can use 32-bits. It's probably more efficient than
-- the smaller types anyway */
--typedef __u32 cfi_word;
--#endif /* CONFIG_MTD_CFI_B8 */
--
--#endif
--
--/*
-- * The following macros are used to select the code to execute:
-- * cfi_buswidth_is_*()
-- * cfi_interleave_is_*()
-- * [where * is either 1, 2, 4, or 8]
-- * Those macros should be used with 'if' statements. If only one of few
-- * geometry arrangements are selected, they expand to constants thus allowing
-- * the compiler (most of them being 0) to optimize away all the unneeded code,
-- * while still validating the syntax (which is not possible with embedded
-- * #if ... #endif constructs).
-- * The exception to this is the 64-bit versions, which need an extension
-- * to the cfi_word type, and cause compiler warnings about shifts being
-- * out of range.
-- */
--
--#ifdef CFIDEV_INTERLEAVE_1
--# ifdef CFIDEV_INTERLEAVE
--# undef CFIDEV_INTERLEAVE
--# define CFIDEV_INTERLEAVE (cfi->interleave)
--# else
--# define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_1
--# endif
--# define cfi_interleave_is_1() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_1)
-+#define cfi_interleave(cfi) 1
-+#define cfi_interleave_is_1(cfi) (cfi_interleave(cfi) == 1)
- #else
--# define cfi_interleave_is_1() (0)
-+#define cfi_interleave_is_1(cfi) (0)
- #endif
-
--#ifdef CFIDEV_INTERLEAVE_2
--# ifdef CFIDEV_INTERLEAVE
--# undef CFIDEV_INTERLEAVE
--# define CFIDEV_INTERLEAVE (cfi->interleave)
-+#ifdef CONFIG_MTD_CFI_I2
-+# ifdef cfi_interleave
-+# undef cfi_interleave
-+# define cfi_interleave(cfi) ((cfi)->interleave)
- # else
--# define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_2
-+# define cfi_interleave(cfi) 2
- # endif
--# define cfi_interleave_is_2() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_2)
-+#define cfi_interleave_is_2(cfi) (cfi_interleave(cfi) == 2)
- #else
--# define cfi_interleave_is_2() (0)
-+#define cfi_interleave_is_2(cfi) (0)
- #endif
-
--#ifdef CFIDEV_INTERLEAVE_4
--# ifdef CFIDEV_INTERLEAVE
--# undef CFIDEV_INTERLEAVE
--# define CFIDEV_INTERLEAVE (cfi->interleave)
-+#ifdef CONFIG_MTD_CFI_I4
-+# ifdef cfi_interleave
-+# undef cfi_interleave
-+# define cfi_interleave(cfi) ((cfi)->interleave)
- # else
--# define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_4
-+# define cfi_interleave(cfi) 4
- # endif
--# define cfi_interleave_is_4() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_4)
-+#define cfi_interleave_is_4(cfi) (cfi_interleave(cfi) == 4)
- #else
--# define cfi_interleave_is_4() (0)
-+#define cfi_interleave_is_4(cfi) (0)
- #endif
-
--#ifdef CFIDEV_INTERLEAVE_8
--# ifdef CFIDEV_INTERLEAVE
--# undef CFIDEV_INTERLEAVE
--# define CFIDEV_INTERLEAVE (cfi->interleave)
-+#ifdef CONFIG_MTD_CFI_I8
-+# ifdef cfi_interleave
-+# undef cfi_interleave
-+# define cfi_interleave(cfi) ((cfi)->interleave)
- # else
--# define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_8
-+# define cfi_interleave(cfi) 8
- # endif
--# define cfi_interleave_is_8() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_8)
-+#define cfi_interleave_is_8(cfi) (cfi_interleave(cfi) == 8)
- #else
--# define cfi_interleave_is_8() (0)
-+#define cfi_interleave_is_8(cfi) (0)
- #endif
-
--#ifndef CFIDEV_INTERLEAVE
--#error You must define at least one interleave to support!
-+static inline int cfi_interleave_supported(int i)
-+{
-+ switch (i) {
-+#ifdef CONFIG_MTD_CFI_I1
-+ case 1:
- #endif
--
--#ifdef CFIDEV_BUSWIDTH_1
--# ifdef CFIDEV_BUSWIDTH
--# undef CFIDEV_BUSWIDTH
--# define CFIDEV_BUSWIDTH (map->buswidth)
--# else
--# define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_1
--# endif
--# define cfi_buswidth_is_1() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_1)
--#else
--# define cfi_buswidth_is_1() (0)
-+#ifdef CONFIG_MTD_CFI_I2
-+ case 2:
- #endif
--
--#ifdef CFIDEV_BUSWIDTH_2
--# ifdef CFIDEV_BUSWIDTH
--# undef CFIDEV_BUSWIDTH
--# define CFIDEV_BUSWIDTH (map->buswidth)
--# else
--# define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_2
--# endif
--# define cfi_buswidth_is_2() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_2)
--#else
--# define cfi_buswidth_is_2() (0)
-+#ifdef CONFIG_MTD_CFI_I4
-+ case 4:
- #endif
--
--#ifdef CFIDEV_BUSWIDTH_4
--# ifdef CFIDEV_BUSWIDTH
--# undef CFIDEV_BUSWIDTH
--# define CFIDEV_BUSWIDTH (map->buswidth)
--# else
--# define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_4
--# endif
--# define cfi_buswidth_is_4() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_4)
--#else
--# define cfi_buswidth_is_4() (0)
-+#ifdef CONFIG_MTD_CFI_I8
-+ case 8:
- #endif
-+ return 1;
-
--#ifdef CFIDEV_BUSWIDTH_8
--# ifdef CFIDEV_BUSWIDTH
--# undef CFIDEV_BUSWIDTH
--# define CFIDEV_BUSWIDTH (map->buswidth)
--# else
--# define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_8
--# endif
--# define cfi_buswidth_is_8() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_8)
--#else
--# define cfi_buswidth_is_8() (0)
--#endif
-+ default:
-+ return 0;
-+ }
-+}
-
--#ifndef CFIDEV_BUSWIDTH
--#error You must define at least one bus width to support!
--#endif
-
- /* NB: these values must represents the number of bytes needed to meet the
- * device type (x8, x16, x32). Eg. a 32 bit device is 4 x 8 bytes.
-@@ -222,88 +97,138 @@
-
- /* Basic Query Structure */
- struct cfi_ident {
-- __u8 qry[3];
-- __u16 P_ID;
-- __u16 P_ADR;
-- __u16 A_ID;
-- __u16 A_ADR;
-- __u8 VccMin;
-- __u8 VccMax;
-- __u8 VppMin;
-- __u8 VppMax;
-- __u8 WordWriteTimeoutTyp;
-- __u8 BufWriteTimeoutTyp;
-- __u8 BlockEraseTimeoutTyp;
-- __u8 ChipEraseTimeoutTyp;
-- __u8 WordWriteTimeoutMax;
-- __u8 BufWriteTimeoutMax;
-- __u8 BlockEraseTimeoutMax;
-- __u8 ChipEraseTimeoutMax;
-- __u8 DevSize;
-- __u16 InterfaceDesc;
-- __u16 MaxBufWriteSize;
-- __u8 NumEraseRegions;
-- __u32 EraseRegionInfo[0]; /* Not host ordered */
-+ uint8_t qry[3];
-+ uint16_t P_ID;
-+ uint16_t P_ADR;
-+ uint16_t A_ID;
-+ uint16_t A_ADR;
-+ uint8_t VccMin;
-+ uint8_t VccMax;
-+ uint8_t VppMin;
-+ uint8_t VppMax;
-+ uint8_t WordWriteTimeoutTyp;
-+ uint8_t BufWriteTimeoutTyp;
-+ uint8_t BlockEraseTimeoutTyp;
-+ uint8_t ChipEraseTimeoutTyp;
-+ uint8_t WordWriteTimeoutMax;
-+ uint8_t BufWriteTimeoutMax;
-+ uint8_t BlockEraseTimeoutMax;
-+ uint8_t ChipEraseTimeoutMax;
-+ uint8_t DevSize;
-+ uint16_t InterfaceDesc;
-+ uint16_t MaxBufWriteSize;
-+ uint8_t NumEraseRegions;
-+ uint32_t EraseRegionInfo[0]; /* Not host ordered */
- } __attribute__((packed));
-
- /* Extended Query Structure for both PRI and ALT */
-
- struct cfi_extquery {
-- __u8 pri[3];
-- __u8 MajorVersion;
-- __u8 MinorVersion;
-+ uint8_t pri[3];
-+ uint8_t MajorVersion;
-+ uint8_t MinorVersion;
- } __attribute__((packed));
-
- /* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */
-
- struct cfi_pri_intelext {
-- __u8 pri[3];
-- __u8 MajorVersion;
-- __u8 MinorVersion;
-- __u32 FeatureSupport;
-- __u8 SuspendCmdSupport;
-- __u16 BlkStatusRegMask;
-- __u8 VccOptimal;
-- __u8 VppOptimal;
-- __u8 NumProtectionFields;
-- __u16 ProtRegAddr;
-- __u8 FactProtRegSize;
-- __u8 UserProtRegSize;
-+ uint8_t pri[3];
-+ uint8_t MajorVersion;
-+ uint8_t MinorVersion;
-+ uint32_t FeatureSupport; /* if bit 31 is set then an additional uint32_t feature
-+ block follows - FIXME - not currently supported */
-+ uint8_t SuspendCmdSupport;
-+ uint16_t BlkStatusRegMask;
-+ uint8_t VccOptimal;
-+ uint8_t VppOptimal;
-+ uint8_t NumProtectionFields;
-+ uint16_t ProtRegAddr;
-+ uint8_t FactProtRegSize;
-+ uint8_t UserProtRegSize;
-+ uint8_t extra[0];
-+} __attribute__((packed));
-+
-+struct cfi_intelext_otpinfo {
-+ uint32_t ProtRegAddr;
-+ uint16_t FactGroups;
-+ uint8_t FactProtRegSize;
-+ uint16_t UserGroups;
-+ uint8_t UserProtRegSize;
-+} __attribute__((packed));
-+
-+struct cfi_intelext_blockinfo {
-+ uint16_t NumIdentBlocks;
-+ uint16_t BlockSize;
-+ uint16_t MinBlockEraseCycles;
-+ uint8_t BitsPerCell;
-+ uint8_t BlockCap;
-+} __attribute__((packed));
-+
-+struct cfi_intelext_regioninfo {
-+ uint16_t NumIdentPartitions;
-+ uint8_t NumOpAllowed;
-+ uint8_t NumOpAllowedSimProgMode;
-+ uint8_t NumOpAllowedSimEraMode;
-+ uint8_t NumBlockTypes;
-+ struct cfi_intelext_blockinfo BlockTypes[1];
-+} __attribute__((packed));
-+
-+/* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */
-+
-+struct cfi_pri_amdstd {
-+ uint8_t pri[3];
-+ uint8_t MajorVersion;
-+ uint8_t MinorVersion;
-+ uint8_t SiliconRevision; /* bits 1-0: Address Sensitive Unlock */
-+ uint8_t EraseSuspend;
-+ uint8_t BlkProt;
-+ uint8_t TmpBlkUnprotect;
-+ uint8_t BlkProtUnprot;
-+ uint8_t SimultaneousOps;
-+ uint8_t BurstMode;
-+ uint8_t PageMode;
-+ uint8_t VppMin;
-+ uint8_t VppMax;
-+ uint8_t TopBottom;
- } __attribute__((packed));
-
- struct cfi_pri_query {
-- __u8 NumFields;
-- __u32 ProtField[1]; /* Not host ordered */
-+ uint8_t NumFields;
-+ uint32_t ProtField[1]; /* Not host ordered */
- } __attribute__((packed));
-
- struct cfi_bri_query {
-- __u8 PageModeReadCap;
-- __u8 NumFields;
-- __u32 ConfField[1]; /* Not host ordered */
-+ uint8_t PageModeReadCap;
-+ uint8_t NumFields;
-+ uint32_t ConfField[1]; /* Not host ordered */
- } __attribute__((packed));
-
--#define P_ID_NONE 0
--#define P_ID_INTEL_EXT 1
--#define P_ID_AMD_STD 2
--#define P_ID_INTEL_STD 3
--#define P_ID_AMD_EXT 4
--#define P_ID_MITSUBISHI_STD 256
--#define P_ID_MITSUBISHI_EXT 257
--#define P_ID_RESERVED 65535
-+#define P_ID_NONE 0x0000
-+#define P_ID_INTEL_EXT 0x0001
-+#define P_ID_AMD_STD 0x0002
-+#define P_ID_INTEL_STD 0x0003
-+#define P_ID_AMD_EXT 0x0004
-+#define P_ID_WINBOND 0x0006
-+#define P_ID_ST_ADV 0x0020
-+#define P_ID_MITSUBISHI_STD 0x0100
-+#define P_ID_MITSUBISHI_EXT 0x0101
-+#define P_ID_SST_PAGE 0x0102
-+#define P_ID_INTEL_PERFORMANCE 0x0200
-+#define P_ID_INTEL_DATA 0x0210
-+#define P_ID_RESERVED 0xffff
-
-
- #define CFI_MODE_CFI 1
- #define CFI_MODE_JEDEC 0
-
- struct cfi_private {
-- __u16 cmdset;
-+ uint16_t cmdset;
- void *cmdset_priv;
- int interleave;
- int device_type;
- int cfi_mode; /* Are we a JEDEC device pretending to be CFI? */
- int addr_unlock1;
- int addr_unlock2;
-- int fast_prog;
- struct mtd_info *(*cmdset_setup)(struct map_info *);
- struct cfi_ident *cfiq; /* For now only one. We insist that all devs
- must be of the same type. */
-@@ -314,107 +239,81 @@
- struct flchip chips[0]; /* per-chip data structure for each chip */
- };
-
--#define MAX_CFI_CHIPS 8 /* Entirely arbitrary to avoid realloc() */
--
- /*
- * Returns the command address according to the given geometry.
- */
--static inline __u32 cfi_build_cmd_addr(__u32 cmd_ofs, int interleave, int type)
-+static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int type)
- {
- return (cmd_ofs * type) * interleave;
- }
-
- /*
-- * Transforms the CFI command for the given geometry (bus width & interleave.
-+ * Transforms the CFI command for the given geometry (bus width & interleave).
-+ * It looks too long to be inline, but in the common case it should almost all
-+ * get optimised away.
- */
--static inline cfi_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
-+static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi)
- {
-- cfi_word val = 0;
-+ map_word val = { {0} };
-+ int wordwidth, words_per_bus, chip_mode, chips_per_word;
-+ unsigned long onecmd;
-+ int i;
-
-- if (cfi_buswidth_is_1()) {
-- /* 1 x8 device */
-- val = cmd;
-- } else if (cfi_buswidth_is_2()) {
-- if (cfi_interleave_is_1()) {
-- /* 1 x16 device in x16 mode */
-- val = cpu_to_cfi16(cmd);
-- } else if (cfi_interleave_is_2()) {
-- /* 2 (x8, x16 or x32) devices in x8 mode */
-- val = cpu_to_cfi16((cmd << 8) | cmd);
-- }
-- } else if (cfi_buswidth_is_4()) {
-- if (cfi_interleave_is_1()) {
-- /* 1 x32 device in x32 mode */
-- val = cpu_to_cfi32(cmd);
-- } else if (cfi_interleave_is_2()) {
-- /* 2 x16 device in x16 mode */
-- val = cpu_to_cfi32((cmd << 16) | cmd);
-- } else if (cfi_interleave_is_4()) {
-- /* 4 (x8, x16 or x32) devices in x8 mode */
-- val = (cmd << 16) | cmd;
-- val = cpu_to_cfi32((val << 8) | val);
-- }
--#ifdef CFI_WORD_64
-- } else if (cfi_buswidth_is_8()) {
-- if (cfi_interleave_is_1()) {
-- /* 1 x64 device in x64 mode */
-- val = cpu_to_cfi64(cmd);
-- } else if (cfi_interleave_is_2()) {
-- /* 2 x32 device in x32 mode */
-- val = cmd;
-- val = cpu_to_cfi64((val << 32) | val);
-- } else if (cfi_interleave_is_4()) {
-- /* 4 (x16, x32 or x64) devices in x16 mode */
-- val = (cmd << 16) | cmd;
-- val = cpu_to_cfi64((val << 32) | val);
-- } else if (cfi_interleave_is_8()) {
-- /* 8 (x8, x16 or x32) devices in x8 mode */
-- val = (cmd << 8) | cmd;
-- val = (val << 16) | val;
-- val = (val << 32) | val;
-- val = cpu_to_cfi64(val);
-- }
--#endif /* CFI_WORD_64 */
-+ /* We do it this way to give the compiler a fighting chance
-+ of optimising away all the crap for 'bankwidth' larger than
-+ an unsigned long, in the common case where that support is
-+ disabled */
-+ if (map_bankwidth_is_large(map)) {
-+ wordwidth = sizeof(unsigned long);
-+ words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1
-+ } else {
-+ wordwidth = map_bankwidth(map);
-+ words_per_bus = 1;
- }
-- return val;
--}
--#define CMD(x) cfi_build_cmd((x), map, cfi)
-
--/*
-- * Read a value according to the bus width.
-- */
-+ chip_mode = map_bankwidth(map) / cfi_interleave(cfi);
-+ chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map);
-
--static inline cfi_word cfi_read(struct map_info *map, __u32 addr)
--{
-- if (cfi_buswidth_is_1()) {
-- return map->read8(map, addr);
-- } else if (cfi_buswidth_is_2()) {
-- return map->read16(map, addr);
-- } else if (cfi_buswidth_is_4()) {
-- return map->read32(map, addr);
-- } else if (cfi_buswidth_is_8()) {
-- return map->read64(map, addr);
-- } else {
-- return 0;
-+ /* First, determine what the bit-pattern should be for a single
-+ device, according to chip mode and endianness... */
-+ switch (chip_mode) {
-+ default: BUG();
-+ case 1:
-+ onecmd = cmd;
-+ break;
-+ case 2:
-+ onecmd = cpu_to_cfi16(cmd);
-+ break;
-+ case 4:
-+ onecmd = cpu_to_cfi32(cmd);
-+ break;
- }
--}
-
--/*
-- * Write a value according to the bus width.
-- */
-+ /* Now replicate it across the size of an unsigned long, or
-+ just to the bus width as appropriate */
-+ switch (chips_per_word) {
-+ default: BUG();
-+#if BITS_PER_LONG >= 64
-+ case 8:
-+ onecmd |= (onecmd << (chip_mode * 32));
-+#endif
-+ case 4:
-+ onecmd |= (onecmd << (chip_mode * 16));
-+ case 2:
-+ onecmd |= (onecmd << (chip_mode * 8));
-+ case 1:
-+ ;
-+ }
-
--static inline void cfi_write(struct map_info *map, cfi_word val, __u32 addr)
--{
-- if (cfi_buswidth_is_1()) {
-- map->write8(map, val, addr);
-- } else if (cfi_buswidth_is_2()) {
-- map->write16(map, val, addr);
-- } else if (cfi_buswidth_is_4()) {
-- map->write32(map, val, addr);
-- } else if (cfi_buswidth_is_8()) {
-- map->write64(map, val, addr);
-+ /* And finally, for the multi-word case, replicate it
-+ in all words in the structure */
-+ for (i=0; i < words_per_bus; i++) {
-+ val.x[i] = onecmd;
- }
-+
-+ return val;
- }
-+#define CMD(x) cfi_build_cmd((x), map, cfi)
-
- /*
- * Sends a CFI command to a bank of flash for the given geometry.
-@@ -423,50 +322,47 @@
- * If prev_val is non-null, it will be set to the value at the command address,
- * before the command was written.
- */
--static inline __u32 cfi_send_gen_cmd(u_char cmd, __u32 cmd_addr, __u32 base,
-+static inline uint32_t cfi_send_gen_cmd(u_char cmd, uint32_t cmd_addr, uint32_t base,
- struct map_info *map, struct cfi_private *cfi,
-- int type, cfi_word *prev_val)
-+ int type, map_word *prev_val)
- {
-- cfi_word val;
-- __u32 addr = base + cfi_build_cmd_addr(cmd_addr, CFIDEV_INTERLEAVE, type);
-+ map_word val;
-+ uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, cfi_interleave(cfi), type);
-
- val = cfi_build_cmd(cmd, map, cfi);
-
- if (prev_val)
-- *prev_val = cfi_read(map, addr);
-+ *prev_val = map_read(map, addr);
-
-- cfi_write(map, val, addr);
-+ map_write(map, val, addr);
-
- return addr - base;
- }
-
--static inline __u8 cfi_read_query(struct map_info *map, __u32 addr)
-+static inline uint8_t cfi_read_query(struct map_info *map, uint32_t addr)
- {
-- if (cfi_buswidth_is_1()) {
-- return map->read8(map, addr);
-- } else if (cfi_buswidth_is_2()) {
-- return cfi16_to_cpu(map->read16(map, addr));
-- } else if (cfi_buswidth_is_4()) {
-- return cfi32_to_cpu(map->read32(map, addr));
-- } else if (cfi_buswidth_is_8()) {
-- return cfi64_to_cpu(map->read64(map, addr));
-+ map_word val = map_read(map, addr);
-+
-+ if (map_bankwidth_is_1(map)) {
-+ return val.x[0];
-+ } else if (map_bankwidth_is_2(map)) {
-+ return cfi16_to_cpu(val.x[0]);
- } else {
-- return 0;
-+ /* No point in a 64-bit byteswap since that would just be
-+ swapping the responses from different chips, and we are
-+ only interested in one chip (a representative sample) */
-+ return cfi32_to_cpu(val.x[0]);
- }
- }
-
- static inline void cfi_udelay(int us)
- {
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-- unsigned long t = us * HZ / 1000000;
-- if (t) {
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- schedule_timeout(t);
-- return;
-- }
--#endif
-+ if (us >= 1000) {
-+ msleep((us+999)/1000);
-+ } else {
- udelay(us);
- cond_resched();
-+ }
- }
-
- static inline void cfi_spin_lock(spinlock_t *mutex)
-@@ -479,5 +375,28 @@
- spin_unlock_bh(mutex);
- }
-
-+struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size,
-+ const char* name);
-+struct cfi_fixup {
-+ uint16_t mfr;
-+ uint16_t id;
-+ void (*fixup)(struct mtd_info *mtd, void* param);
-+ void* param;
-+};
-+
-+#define CFI_MFR_ANY 0xffff
-+#define CFI_ID_ANY 0xffff
-+
-+#define CFI_MFR_AMD 0x0001
-+#define CFI_MFR_ST 0x0020 /* STMicroelectronics */
-+
-+void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup* fixups);
-+
-+typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip,
-+ unsigned long adr, int len, void *thunk);
-+
-+int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
-+ loff_t ofs, size_t len, void *thunk);
-+
-
- #endif /* __MTD_CFI_H__ */
---- linux-2.4.21/include/linux/mtd/compatmac.h~mtd-cvs
-+++ linux-2.4.21/include/linux/mtd/compatmac.h
-@@ -1,583 +1,223 @@
--
- /*
-- * mtd/include/compatmac.h
-- *
-- * $Id: compatmac.h,v 1.45 2003/01/24 15:50:57 dwmw2 Exp $
-+ * $Id: compatmac.h,v 1.71 2005/01/12 23:01:17 dmarlin Exp $
- *
- * Extensions and omissions from the normal 'linux/compatmac.h'
- * files. hopefully this will end up empty as the 'real' one
- * becomes fully-featured.
- */
-
--
--/* First, include the parts which the kernel is good enough to provide
-- * to us
-- */
--
- #ifndef __LINUX_MTD_COMPATMAC_H__
- #define __LINUX_MTD_COMPATMAC_H__
-
--#include <linux/config.h>
--#include <linux/module.h>
--#ifndef LINUX_VERSION_CODE
- #include <linux/version.h>
--#endif
--
--#ifndef VERSION_CODE
--# define VERSION_CODE(vers,rel,seq) ( ((vers)<<16) | ((rel)<<8) | (seq) )
--#endif
--#ifndef KERNEL_VERSION
--# define KERNEL_VERSION(a,b,c) VERSION_CODE(a,b,c)
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,0,0)
--# error "This kernel is too old: not supported by this file"
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
--#include <linux/types.h> /* used later in this header */
--
--#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
--#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
--
--typedef struct wait_queue * wait_queue_head_t;
--
--#define DECLARE_WAITQUEUE(x,y) struct wait_queue x = {y,NULL}
--#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL
--#define init_waitqueue_head init_waitqueue
--#define DECLARE_MUTEX(x) struct semaphore x = MUTEX
--#define DECLARE_MUTEX_LOCKED(x) struct semaphore x = MUTEX_LOCKED
--
--/* from sysdep-2.1.h */
--# include <asm/segment.h>
--# define access_ok(t,a,sz) (verify_area((t),(a),(sz)) ? 0 : 1)
--# define verify_area_20 verify_area
--# define copy_to_user(t,f,n) (memcpy_tofs(t,f,n), 0)
--# define __copy_to_user(t,f,n) copy_to_user((t),(f),(n))
--# define copy_to_user_ret(t,f,n,r) copy_to_user((t),(f),(n))
--# define copy_from_user(t,f,n) (memcpy_fromfs((t),(f),(n)), 0)
--# define __copy_from_user(t,f,n) copy_from_user((t),(f),(n))
--# define copy_from_user_ret(t,f,n,r) copy_from_user((t),(f),(n))
--//xxx # define PUT_USER(val,add) (put_user((val),(add)), 0)
--# define Put_user(val,add) (put_user((val),(add)), 0)
--# define __PUT_USER(val,add) PUT_USER((val),(add))
--# define PUT_USER_RET(val,add,ret) PUT_USER((val),(add))
--# define GET_USER(dest,add) ((dest)=get_user((add)), 0)
--# define __GET_USER(dest,add) GET_USER((dest),(add))
--# define GET_USER_RET(dest,add,ret) GET_USER((dest),(add))
--
--#define ioremap(offset,size) vremap(offset,size)
--#define iounmap(adr) /* */
--
--#define EXPORT_SYMBOL(s) /* */
--#define EXPORT_SYMBOL_NOVERS(s) /* */
--
--/* 2.1.10 and 2.1.43 introduced new functions. They are worth using */
--
--#if LINUX_VERSION_CODE < VERSION_CODE(2,1,10)
--
--# include <asm/byteorder.h>
--# ifdef __LITTLE_ENDIAN
--# define cpu_to_le16(x) (x)
--# define cpu_to_le32(x) (x)
--# define cpu_to_be16(x) htons((x))
--# define cpu_to_be32(x) htonl((x))
--# else
--# define cpu_to_be16(x) (x)
--# define cpu_to_be32(x) (x)
-- extern inline __u16 cpu_to_le16(__u16 x) { return (x<<8) | (x>>8);}
-- extern inline __u32 cpu_to_le32(__u32 x) { return((x>>24) |
-- ((x>>8)&0xff00) | ((x<<8)&0xff0000) | (x<<24));}
--# endif
--
--# define le16_to_cpu(x) cpu_to_le16(x)
--# define le32_to_cpu(x) cpu_to_le32(x)
--# define be16_to_cpu(x) cpu_to_be16(x)
--# define be32_to_cpu(x) cpu_to_be32(x)
--
--#endif
--
--#if LINUX_VERSION_CODE < VERSION_CODE(2,1,43)
--# define cpu_to_le16p(addr) (cpu_to_le16(*(addr)))
--# define cpu_to_le32p(addr) (cpu_to_le32(*(addr)))
--# define cpu_to_be16p(addr) (cpu_to_be16(*(addr)))
--# define cpu_to_be32p(addr) (cpu_to_be32(*(addr)))
--
-- extern inline void cpu_to_le16s(__u16 *a) {*a = cpu_to_le16(*a);}
-- extern inline void cpu_to_le32s(__u16 *a) {*a = cpu_to_le32(*a);}
-- extern inline void cpu_to_be16s(__u16 *a) {*a = cpu_to_be16(*a);}
-- extern inline void cpu_to_be32s(__u16 *a) {*a = cpu_to_be32(*a);}
--
--# define le16_to_cpup(x) cpu_to_le16p(x)
--# define le32_to_cpup(x) cpu_to_le32p(x)
--# define be16_to_cpup(x) cpu_to_be16p(x)
--# define be32_to_cpup(x) cpu_to_be32p(x)
--
--# define le16_to_cpus(x) cpu_to_le16s(x)
--# define le32_to_cpus(x) cpu_to_le32s(x)
--# define be16_to_cpus(x) cpu_to_be16s(x)
--# define be32_to_cpus(x) cpu_to_be32s(x)
--#endif
--
--// from 2.2, linux/types.h
--#ifndef __BIT_TYPES_DEFINED__
--#define __BIT_TYPES_DEFINED__
--
--typedef __u8 u_int8_t;
--typedef __s8 int8_t;
--typedef __u16 u_int16_t;
--typedef __s16 int16_t;
--typedef __u32 u_int32_t;
--typedef __s32 int32_t;
--
--#endif /* !(__BIT_TYPES_DEFINED__) */
--
--#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
-- typedef struct { } spinlock_t;
-- #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
--#else
-- typedef struct { int gcc_is_buggy; } spinlock_t;
-- #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
--#endif
--
--#define spin_lock_init(lock) do { } while(0)
--#define spin_lock(lock) (void)(lock) /* Not "unused variable". */
--#define spin_trylock(lock) (1)
--#define spin_unlock_wait(lock) do { } while(0)
--#define spin_unlock(lock) do { } while(0)
--#define spin_lock_irq(lock) cli()
--#define spin_unlock_irq(lock) sti()
--
--#define spin_lock_irqsave(lock, flags) \
-- do { save_flags(flags); cli(); } while (0)
--#define spin_unlock_irqrestore(lock, flags) \
-- restore_flags(flags)
--
--// Doesn't work when tqueue.h is included.
--// #define queue_task queue_task_irq_off
--#define tty_flip_buffer_push(tty) queue_task_irq_off(&tty->flip.tqueue, &tq_timer)
--#define signal_pending(current) (current->signal & ~current->blocked)
--#define schedule_timeout(to) do {current->timeout = jiffies + (to);schedule ();} while (0)
--#define time_after(t1,t2) (((long)t1-t2) > 0)
--
--#else
-- #include <linux/compatmac.h>
--#endif // LINUX_VERSION_CODE < 0x020100
--
--
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
--#include <linux/vmalloc.h>
--#endif
--
--/* Modularization issues */
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,18)
--# define __USE_OLD_SYMTAB__
--# define EXPORT_NO_SYMBOLS register_symtab(NULL);
--# define REGISTER_SYMTAB(tab) register_symtab(tab)
--#else
--# define REGISTER_SYMTAB(tab) /* nothing */
--#endif
-
--#ifdef __USE_OLD_SYMTAB__
--# define __MODULE_STRING(s) /* nothing */
--# define MODULE_PARM(v,t) /* nothing */
--# define MODULE_PARM_DESC(v,t) /* nothing */
--# define MODULE_AUTHOR(n) /* nothing */
--# define MODULE_DESCRIPTION(d) /* nothing */
--# define MODULE_SUPPORTED_DEVICE(n) /* nothing */
--#endif
--
--/*
-- * "select" changed in 2.1.23. The implementation is twin, but this
-- * header is new
-- */
--#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,22)
--# include <linux/poll.h>
--#else
--# define __USE_OLD_SELECT__
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
-+#error "This kernel is too old: not supported by this file"
- #endif
-
--/* Other change in the fops are solved using pseudo-types */
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
--# define lseek_t long long
--# define lseek_off_t long long
--#else
--# define lseek_t int
--# define lseek_off_t off_t
--#endif
-+ /* O(1) scheduler stuff. */
-
--/* changed the prototype of read/write */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5) && !defined(__rh_config_h__)
-+#include <linux/sched.h>
-+static inline void __recalc_sigpending(void)
-+{
-+ recalc_sigpending(current);
-+}
-+#undef recalc_sigpending
-+#define recalc_sigpending() __recalc_sigpending ()
-
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) || defined(__alpha__)
--# define count_t unsigned long
--# define read_write_t long
--#else
--# define count_t int
--# define read_write_t int
-+#define set_user_nice(tsk, n) do { (tsk)->nice = n; } while(0)
- #endif
-
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,31)
--# define release_t void
--# define release_return(x) return
--#else
--# define release_t int
--# define release_return(x) return (x)
--#endif
--
--#if LINUX_VERSION_CODE < 0x20300
--#define __exit
--#endif
--#if LINUX_VERSION_CODE < 0x20200
--#define __init
--#else
--#include <linux/init.h>
--#endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
--#define init_MUTEX(x) do {*(x) = MUTEX;} while (0)
--#define init_MUTEX_LOCKED(x) do {*(x) = MUTEX_LOCKED;} while (0)
--#endif
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20)
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
--#define RQFUNC_ARG void
--#define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0)
--#else
--#define RQFUNC_ARG request_queue_t *q
-+#ifndef yield
-+#define yield() do { set_current_state(TASK_RUNNING); schedule(); } while(0)
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,32)
--#define blk_cleanup_queue(nr) do {blk_dev[nr].request_fn = 0;} while(0)
--#define BLK_DEFAULT_QUEUE(nr) (blk_dev[nr].request_fn)
--#define blk_init_queue(q, rq) do {q = rq;} while(0)
-+#ifndef minor
-+#define major(d) (MAJOR(to_kdev_t(d)))
-+#define minor(d) (MINOR(to_kdev_t(d)))
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
--#ifdef CONFIG_MODULES
--#define __MOD_INC_USE_COUNT(mod) \
-- (atomic_inc(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED|MOD_USED_ONCE)
--#define __MOD_DEC_USE_COUNT(mod) \
-- (atomic_dec(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED)
--#else
--#define __MOD_INC_USE_COUNT(mod)
--#define __MOD_DEC_USE_COUNT(mod)
--#endif
-+#ifndef mk_kdev
-+#define mk_kdev(ma,mi) MKDEV(ma,mi)
-+#define kdev_t_to_nr(x) (x)
- #endif
-
-+#define need_resched() (current->need_resched)
-+#define cond_resched() do { if need_resched() { yield(); } } while(0)
-
--#ifndef HAVE_INTER_MODULE
--static inline void *inter_module_get(char *x) {return NULL;}
--static inline void *inter_module_get_request(char *x, char *y) {return NULL;}
--static inline void inter_module_put(const char *x) {}
--static inline void inter_module_register(const char *x, struct module *y, const void *z) {}
--static inline void inter_module_unregister(const char *x) {}
-+#endif /* < 2.4.20 */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,73)
-+#define iminor(i) minor((i)->i_rdev)
-+#define imajor(i) major((i)->i_rdev)
-+#define old_encode_dev(d) ( (major(d)<<8) | minor(d) )
-+#define old_decode_dev(rdev) (kdev_t_to_nr(mk_kdev((rdev)>>8, (rdev)&0xff)))
-+#define old_valid_dev(d) (1)
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61)
-
--#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL
--#define init_waitqueue_head init_waitqueue
-+#include <linux/sched.h>
-
-+#ifdef __rh_config_h__
-+#define sigmask_lock sighand->siglock
-+#define sig sighand
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
--
--static inline int try_inc_mod_count(struct module *mod)
-+static inline void __daemonize_modvers(void)
- {
--#ifdef CONFIG_MODULES
-- if (mod)
-- __MOD_INC_USE_COUNT(mod);
--#endif
-- return 1;
--}
--#endif
--
--
--/* Yes, I'm aware that it's a fairly ugly hack.
-- Until the __constant_* macros appear in Linus' own kernels, this is
-- the way it has to be done.
-- DW 19/1/00
-- */
--
--#include <asm/byteorder.h>
--
--#ifndef __constant_cpu_to_le16
--
--#ifdef __BIG_ENDIAN
--#define __constant_cpu_to_le64(x) ___swab64((x))
--#define __constant_le64_to_cpu(x) ___swab64((x))
--#define __constant_cpu_to_le32(x) ___swab32((x))
--#define __constant_le32_to_cpu(x) ___swab32((x))
--#define __constant_cpu_to_le16(x) ___swab16((x))
--#define __constant_le16_to_cpu(x) ___swab16((x))
--#define __constant_cpu_to_be64(x) ((__u64)(x))
--#define __constant_be64_to_cpu(x) ((__u64)(x))
--#define __constant_cpu_to_be32(x) ((__u32)(x))
--#define __constant_be32_to_cpu(x) ((__u32)(x))
--#define __constant_cpu_to_be16(x) ((__u16)(x))
--#define __constant_be16_to_cpu(x) ((__u16)(x))
--#else
--#ifdef __LITTLE_ENDIAN
--#define __constant_cpu_to_le64(x) ((__u64)(x))
--#define __constant_le64_to_cpu(x) ((__u64)(x))
--#define __constant_cpu_to_le32(x) ((__u32)(x))
--#define __constant_le32_to_cpu(x) ((__u32)(x))
--#define __constant_cpu_to_le16(x) ((__u16)(x))
--#define __constant_le16_to_cpu(x) ((__u16)(x))
--#define __constant_cpu_to_be64(x) ___swab64((x))
--#define __constant_be64_to_cpu(x) ___swab64((x))
--#define __constant_cpu_to_be32(x) ___swab32((x))
--#define __constant_be32_to_cpu(x) ___swab32((x))
--#define __constant_cpu_to_be16(x) ___swab16((x))
--#define __constant_be16_to_cpu(x) ___swab16((x))
--#else
--#error No (recognised) endianness defined (unless it,s PDP)
--#endif /* __LITTLE_ENDIAN */
--#endif /* __BIG_ENDIAN */
--
--#endif /* ifndef __constant_cpu_to_le16 */
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-- #define mod_init_t int __init
-- #define mod_exit_t void
--#else
-- #define mod_init_t static int __init
-- #define mod_exit_t static void __exit
--#endif
-+ daemonize();
-
--#ifndef THIS_MODULE
--#ifdef MODULE
--#define THIS_MODULE (&__this_module)
--#else
--#define THIS_MODULE (NULL)
--#endif
--#endif
-+ spin_lock_irq(&current->sigmask_lock);
-+ sigfillset(&current->blocked);
-+ recalc_sigpending();
-+ spin_unlock_irq(&current->sigmask_lock);
-+}
-+#undef daemonize
-+#define daemonize(fmt, ...) do { \
-+ snprintf(current->comm, sizeof(current->comm), fmt ,##__VA_ARGS__); \
-+ __daemonize_modvers(); \
-+ } while(0)
-
--#if LINUX_VERSION_CODE < 0x20300
--#include <linux/interrupt.h>
--#define spin_lock_bh(lock) do {start_bh_atomic();spin_lock(lock);}while(0)
--#define spin_unlock_bh(lock) do {spin_unlock(lock);end_bh_atomic();}while(0)
--#else
--#include <asm/softirq.h>
--#include <linux/spinlock.h>
--#endif
-+static inline int dequeue_signal_lock(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
-+{
-+ unsigned long flags;
-+ unsigned long ret;
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
--#define set_current_state(state_value) \
-- do { current->state = (state_value); } while (0)
--#endif
-+ spin_lock_irqsave(&current->sigmask_lock, flags);
-+ ret = dequeue_signal(mask, info);
-+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
--static inline int invalidate_device(kdev_t dev, int do_sync) {
-+ return ret;
-+}
-
-- if (do_sync)
-- fsync_dev(dev);
-+static inline int allow_signal(int sig)
-+{
-+ if (sig < 1 || sig > _NSIG)
-+ return -EINVAL;
-
-- invalidate_buffers(dev);
-+ spin_lock_irq(&current->sigmask_lock);
-+ sigdelset(&current->blocked, sig);
-+ recalc_sigpending();
-+ /* Make sure the kernel neither eats it now converts to SIGKILL */
-+ current->sig->action[sig-1].sa.sa_handler = (void *)2;
-+ spin_unlock_irq(&current->sigmask_lock);
- return 0;
- }
--#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,4,5)
--static inline int invalidate_device(kdev_t dev, int do_sync) {
-- struct super_block *sb = get_super(dev);
-- int res = 0;
--
-- if (do_sync)
-- fsync_dev(dev);
-+static inline int disallow_signal(int sig)
-+{
-+ if (sig < 1 || sig > _NSIG)
-+ return -EINVAL;
-
-- if (sb)
-- res = invalidate_inodes(sb);
-+ spin_lock_irq(&current->sigmask_lock);
-+ sigaddset(&current->blocked, sig);
-+ recalc_sigpending();
-
-- invalidate_buffers(dev);
-- return res;
-+ current->sig->action[sig-1].sa.sa_handler = SIG_DFL;
-+ spin_unlock_irq(&current->sigmask_lock);
-+ return 0;
- }
-+
-+#define PF_FREEZE 0
-+#define refrigerator(x) do { ; } while(0)
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
--#undef min
--#undef max
--#undef min_t
--#undef max_t
--/*
-- * min()/max() macros that also do
-- * strict type-checking.. See the
-- * "unnecessary" pointer comparison.
-- */
--#define min(x,y) ({ \
-- const typeof(x) _x = (x); \
-- const typeof(y) _y = (y); \
-- (void) (&_x == &_y); \
-- _x < _y ? _x : _y; })
-+ /* Module bits */
-
--#define max(x,y) ({ \
-- const typeof(x) _x = (x); \
-- const typeof(y) _y = (y); \
-- (void) (&_x == &_y); \
-- _x > _y ? _x : _y; })
-
--/*
-- * ..and if you can't take the strict
-- * types, you can specify one yourself.
-- *
-- * Or not use min/max at all, of course.
-- */
--#define min_t(type,x,y) \
-- ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
--#define max_t(type,x,y) \
-- ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60)
-+#define try_module_get(m) try_inc_mod_count(m)
-+#define __module_get(m) do { if (!try_inc_mod_count(m)) BUG(); } while(0)
-+#define module_put(m) do { if (m) __MOD_DEC_USE_COUNT((struct module *)(m)); } while(0)
-+#define set_module_owner(x) do { x->owner = THIS_MODULE; } while(0)
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,7)
--struct completion {
-- struct semaphore s;
--};
-
--#define complete(c) up(&(c)->s)
--#define wait_for_completion(c) down(&(c)->s)
--#define init_completion(c) init_MUTEX_LOCKED(&(c)->s);
-+ /* Random filesystem stuff, only for JFFS2 really */
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5)
-+#define parent_ino(d) ((d)->d_parent->d_inode->i_ino)
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9)
--/* This came later */
--#define complete_and_exit(c, r) do { complete(c); do_exit(r); } while(0)
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,12)
-+#define PageUptodate(x) Page_Uptodate(x)
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9) || \
-- (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) && !defined(__rh_config_h__))
--
--#include <linux/genhd.h>
--
--static inline void add_gendisk(struct gendisk *gp)
--{
-- gp->next = gendisk_head;
-- gendisk_head = gp;
--}
--
--static inline void del_gendisk(struct gendisk *gp)
--{
-- struct gendisk *gd, **gdp;
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48)
-+#define get_seconds() CURRENT_TIME
-+#endif
-
-- for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
-- if (*gdp == gp) {
-- gd = *gdp; *gdp = gd->next;
-- break;
-- }
--}
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,53)
-+#define generic_file_readonly_mmap generic_file_mmap
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) && defined(MODULE)
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,70)
-
--#define module_init(func) \
--mod_init_t init_module(void) { \
-- return func(); \
--}
-+#include <linux/kmod.h>
-+#include <linux/string.h>
-
--#define module_exit(func) \
--mod_exit_t cleanup_module(void) { \
-- return func(); \
-+static inline char *strlcpy(char *dest, const char *src, int len)
-+{
-+ dest[len-1] = 0;
-+ return strncpy(dest, src, len-1);
- }
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9) || \
-- (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) && !defined(__rh_config_h__))
--#define MODULE_LICENSE(x) /* */
--#endif
-
--/* Removed for 2.4.21 kernel. This really should have been renamed
-- when it was changed -- this is a PITA */
--#if 0 && LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5)
--#include <linux/sched.h>
--static inline void __recalc_sigpending(void)
-+static inline int do_old_request_module(const char *mod)
- {
-- recalc_sigpending(current);
-+ return request_module(mod);
- }
--#undef recalc_sigpending
--#define recalc_sigpending() __recalc_sigpending ()
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5)
--#define parent_ino(d) ((d)->d_parent->d_inode->i_ino)
--#endif
-+#undef request_module
-+#define request_module(fmt, ...) \
-+ ({ char modname[32]; snprintf(modname, 31, fmt ,##__VA_ARGS__); do_old_request_module(modname); })
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,3)
--#define need_resched() (current->need_resched)
--#define cond_resched() do { if need_resched() schedule(); } while(0)
--#endif
-+#endif /* 2.5.70 */
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
--#ifndef yield
--#define yield() do { set_current_state(TASK_RUNNING); schedule(); } while(0)
--#endif
--#ifndef minor
--#define major(d) (MAJOR(to_kdev_t(d)))
--#define minor(d) (MINOR(to_kdev_t(d)))
--#endif
--#ifndef mk_kdev
--#define mk_kdev(ma,mi) MKDEV(ma,mi)
--#define kdev_t_to_nr(x) (x)
--#endif
-+#ifndef container_of
-+#define container_of(ptr, type, member) ({ \
-+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
-+ (type *)( (char *)__mptr - offsetof(type,member) );})
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
-- /* Is this right? */
--#define set_user_nice(tsk, n) do { (tsk)->priority = 20-(n); } while(0)
--#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21) && !defined(RED_HAT_LINUX_KERNEL)
--#define set_user_nice(tsk, n) do { (tsk)->nice = n; } while(0)
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)
-+#define kvec iovec
-+#define __user
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21)
--#define rq_data_dir(x) ((x)->cmd)
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,28)
-+#define msleep(x) \
-+ set_current_state(TASK_UNINTERRUPTIBLE); \
-+ schedule_timeout((x)*(HZ/1000));
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
--
--#define IS_REQ_CMD(req) (1)
--
--#define QUEUE_LOCK(q) (&io_request_lock)
--
--#define BLK_INIT_QUEUE(q, req, lock) blk_init_queue((q), (req))
--
--#else /* > 2.5.0 */
--
--#define IS_REQ_CMD(req) ((req)->flags & REQ_CMD)
--
--#define QUEUE_LOCK(q) ((q)->queue_lock)
--
--#define BLK_INIT_QUEUE(q, req, lock) blk_init_queue((q), (req), (lock))
--
-+#ifndef __iomem
-+#define __iomem
- #endif
-
--/* Removed cos it broke stuff. Where is this required anyway?
-- * #ifndef QUEUE_EMPTY
-- * #define QUEUE_EMPTY (!CURRENT)
-- * #endif
-+#ifndef list_for_each_entry_safe
-+/**
-+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
-+ * @pos: the type * to use as a loop counter.
-+ * @n: another type * to use as temporary storage
-+ * @head: the head for your list.
-+ * @member: the name of the list_struct within the struct.
- */
--#if LINUX_VERSION_CODE < 0x20300
--#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync)
--#elif LINUX_VERSION_CODE < 0x20500 //FIXME (Si)
--#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged)
--#else
--#define QUEUE_PLUGGED (blk_queue_plugged(QUEUE))
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
--#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
--#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
--#else
--#define BLK_INC_USE_COUNT do {} while(0)
--#define BLK_DEC_USE_COUNT do {} while(0)
--#endif
-+#define list_for_each_entry_safe(pos, n, head, member) \
-+ for (pos = list_entry((head)->next, typeof(*pos), member), \
-+ n = list_entry(pos->member.next, typeof(*pos), member); \
-+ &pos->member != (head); \
-+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,12)
--#define PageUptodate(x) Page_Uptodate(x)
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48)
--#define get_seconds() CURRENT_TIME
-+#ifndef DEFINE_SPINLOCK
-+#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED
- #endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,53)
--#define generic_file_readonly_mmap generic_file_mmap
-+#ifndef DEFINE_RWLOCK
-+#define DEFINE_RWLOCK(x) rwlock_t x = RW_LOCK_UNLOCKED
- #endif
-
- #endif /* __LINUX_MTD_COMPATMAC_H__ */
---- linux-2.4.21/include/linux/mtd/doc2000.h~mtd-cvs
-+++ linux-2.4.21/include/linux/mtd/doc2000.h
-@@ -1,13 +1,21 @@
--
--/* Linux driver for Disk-On-Chip 2000 */
--/* (c) 1999 Machine Vision Holdings, Inc. */
--/* Author: David Woodhouse <dwmw2@mvhi.com> */
--/* $Id: doc2000.h,v 1.15 2001/09/19 00:22:15 dwmw2 Exp $ */
-+/*
-+ * Linux driver for Disk-On-Chip devices
-+ *
-+ * Copyright (C) 1999 Machine Vision Holdings, Inc.
-+ * Copyright (C) 2001-2003 David Woodhouse <dwmw2@infradead.org>
-+ * Copyright (C) 2002-2003 Greg Ungerer <gerg@snapgear.com>
-+ * Copyright (C) 2002-2003 SnapGear Inc
-+ *
-+ * $Id: doc2000.h,v 1.24 2005/01/05 12:40:38 dwmw2 Exp $
-+ *
-+ * Released under GPL
-+ */
-
- #ifndef __MTD_DOC2000_H__
- #define __MTD_DOC2000_H__
-
- #include <linux/mtd/mtd.h>
-+#include <asm/semaphore.h>
-
- #define DoC_Sig1 0
- #define DoC_Sig2 1
-@@ -38,22 +46,51 @@
- #define DoC_Mil_CDSN_IO 0x0800
- #define DoC_2k_CDSN_IO 0x1800
-
-+#define DoC_Mplus_NOP 0x1002
-+#define DoC_Mplus_AliasResolution 0x1004
-+#define DoC_Mplus_DOCControl 0x1006
-+#define DoC_Mplus_AccessStatus 0x1008
-+#define DoC_Mplus_DeviceSelect 0x1008
-+#define DoC_Mplus_Configuration 0x100a
-+#define DoC_Mplus_OutputControl 0x100c
-+#define DoC_Mplus_FlashControl 0x1020
-+#define DoC_Mplus_FlashSelect 0x1022
-+#define DoC_Mplus_FlashCmd 0x1024
-+#define DoC_Mplus_FlashAddress 0x1026
-+#define DoC_Mplus_FlashData0 0x1028
-+#define DoC_Mplus_FlashData1 0x1029
-+#define DoC_Mplus_ReadPipeInit 0x102a
-+#define DoC_Mplus_LastDataRead 0x102c
-+#define DoC_Mplus_LastDataRead1 0x102d
-+#define DoC_Mplus_WritePipeTerm 0x102e
-+#define DoC_Mplus_ECCSyndrome0 0x1040
-+#define DoC_Mplus_ECCSyndrome1 0x1041
-+#define DoC_Mplus_ECCSyndrome2 0x1042
-+#define DoC_Mplus_ECCSyndrome3 0x1043
-+#define DoC_Mplus_ECCSyndrome4 0x1044
-+#define DoC_Mplus_ECCSyndrome5 0x1045
-+#define DoC_Mplus_ECCConf 0x1046
-+#define DoC_Mplus_Toggle 0x1046
-+#define DoC_Mplus_DownloadStatus 0x1074
-+#define DoC_Mplus_CtrlConfirm 0x1076
-+#define DoC_Mplus_Power 0x1fff
-+
- /* How to access the device?
- * On ARM, it'll be mmap'd directly with 32-bit wide accesses.
- * On PPC, it's mmap'd and 16-bit wide.
- * Others use readb/writeb
- */
- #if defined(__arm__)
--#define ReadDOC_(adr, reg) ((unsigned char)(*(__u32 *)(((unsigned long)adr)+((reg)<<2))))
--#define WriteDOC_(d, adr, reg) do{ *(__u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0)
-+#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2))))
-+#define WriteDOC_(d, adr, reg) do{ *(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0)
- #define DOC_IOREMAP_LEN 0x8000
- #elif defined(__ppc__)
--#define ReadDOC_(adr, reg) ((unsigned char)(*(__u16 *)(((unsigned long)adr)+((reg)<<1))))
--#define WriteDOC_(d, adr, reg) do{ *(__u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0)
-+#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u16 *)(((unsigned long)adr)+((reg)<<1))))
-+#define WriteDOC_(d, adr, reg) do{ *(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0)
- #define DOC_IOREMAP_LEN 0x4000
- #else
--#define ReadDOC_(adr, reg) readb(((unsigned long)adr) + (reg))
--#define WriteDOC_(d, adr, reg) writeb(d, ((unsigned long)adr) + (reg))
-+#define ReadDOC_(adr, reg) readb((void __iomem *)(adr) + (reg))
-+#define WriteDOC_(d, adr, reg) writeb(d, (void __iomem *)(adr) + (reg))
- #define DOC_IOREMAP_LEN 0x2000
-
- #endif
-@@ -71,13 +108,21 @@
- #define DOC_MODE_RESERVED1 2
- #define DOC_MODE_RESERVED2 3
-
--#define DOC_MODE_MDWREN 4
- #define DOC_MODE_CLR_ERR 0x80
-+#define DOC_MODE_RST_LAT 0x10
-+#define DOC_MODE_BDECT 0x08
-+#define DOC_MODE_MDWREN 0x04
-
- #define DOC_ChipID_Doc2k 0x20
-+#define DOC_ChipID_Doc2kTSOP 0x21 /* internal number for MTD */
- #define DOC_ChipID_DocMil 0x30
-+#define DOC_ChipID_DocMilPlus32 0x40
-+#define DOC_ChipID_DocMilPlus16 0x41
-
- #define CDSN_CTRL_FR_B 0x80
-+#define CDSN_CTRL_FR_B0 0x40
-+#define CDSN_CTRL_FR_B1 0x80
-+
- #define CDSN_CTRL_ECC_IO 0x20
- #define CDSN_CTRL_FLASH_IO 0x10
- #define CDSN_CTRL_WP 0x08
-@@ -93,6 +138,10 @@
- #define DOC_ECC_RESV 0x02
- #define DOC_ECC_IGNORE 0x01
-
-+#define DOC_FLASH_CE 0x80
-+#define DOC_FLASH_WP 0x40
-+#define DOC_FLASH_BANK 0x02
-+
- /* We have to also set the reserved bit 1 for enable */
- #define DOC_ECC_EN (DOC_ECC__EN | DOC_ECC_RESV)
- #define DOC_ECC_DIS (DOC_ECC_RESV)
-@@ -107,18 +156,21 @@
- #define MAX_FLOORS 4
- #define MAX_CHIPS 4
-
--#define MAX_FLOORS_MIL 4
-+#define MAX_FLOORS_MIL 1
- #define MAX_CHIPS_MIL 1
-
-+#define MAX_FLOORS_MPLUS 2
-+#define MAX_CHIPS_MPLUS 1
-+
- #define ADDR_COLUMN 1
- #define ADDR_PAGE 2
- #define ADDR_COLUMN_PAGE 3
-
- struct DiskOnChip {
- unsigned long physadr;
-- unsigned long virtadr;
-+ void __iomem *virtadr;
- unsigned long totlen;
-- char ChipID; /* Type of DiskOnChip */
-+ unsigned char ChipID; /* Type of DiskOnChip */
- int ioreg;
-
- unsigned long mfr; /* Flash IDs - only one type of flash per device */
-@@ -126,6 +178,7 @@
- int chipshift;
- char page256;
- char pageadrlen;
-+ char interleave; /* Internal interleaving - Millennium Plus style */
- unsigned long erasesize;
-
- int curfloor;
---- linux-2.4.21/include/linux/mtd/flashchip.h~mtd-cvs
-+++ linux-2.4.21/include/linux/mtd/flashchip.h
-@@ -6,7 +6,7 @@
- *
- * (C) 2000 Red Hat. GPLd.
- *
-- * $Id: flashchip.h,v 1.8 2002/10/21 13:20:52 jocke Exp $
-+ * $Id: flashchip.h,v 1.16 2005/02/08 17:11:15 nico Exp $
- *
- */
-
-@@ -29,6 +29,7 @@
- FL_ERASE_SUSPENDED,
- FL_WRITING,
- FL_WRITING_TO_BUFFER,
-+ FL_OTP_WRITE,
- FL_WRITE_SUSPENDING,
- FL_WRITE_SUSPENDED,
- FL_PM_SUSPENDED,
-@@ -37,13 +38,16 @@
- FL_LOCKING,
- FL_UNLOCKING,
- FL_POINT,
-+ FL_XIP_WHILE_ERASING,
-+ FL_XIP_WHILE_WRITING,
- FL_UNKNOWN
- } flstate_t;
-
-
-
- /* NOTE: confusingly, this can be used to refer to more than one chip at a time,
-- if they're interleaved. */
-+ if they're interleaved. This can even refer to individual partitions on
-+ the same physical chip when present. */
-
- struct flchip {
- unsigned long start; /* Offset within the map */
-@@ -58,6 +62,11 @@
- int ref_point_counter;
- flstate_t state;
- flstate_t oldstate;
-+
-+ int write_suspended:1;
-+ int erase_suspended:1;
-+ unsigned long in_progress_block_addr;
-+
- spinlock_t *mutex;
- spinlock_t _spinlock; /* We do it like this because sometimes they'll be shared. */
- wait_queue_head_t wq; /* Wait on here when we're waiting for the chip
-@@ -65,8 +74,17 @@
- int word_write_time;
- int buffer_write_time;
- int erase_time;
-+
-+ void *priv;
- };
-
-+/* This is used to handle contention on write/erase operations
-+ between partitions of the same physical chip. */
-+struct flchip_shared {
-+ spinlock_t lock;
-+ struct flchip *writing;
-+ struct flchip *erasing;
-+};
-
-
- #endif /* __MTD_FLASHCHIP_H__ */
---- linux-2.4.21/include/linux/mtd/gen_probe.h~mtd-cvs
-+++ linux-2.4.21/include/linux/mtd/gen_probe.h
-@@ -1,7 +1,7 @@
- /*
- * (C) 2001, 2001 Red Hat, Inc.
- * GPL'd
-- * $Id: gen_probe.h,v 1.1 2001/09/02 18:50:13 dwmw2 Exp $
-+ * $Id: gen_probe.h,v 1.3 2004/10/20 22:10:33 dwmw2 Exp $
- */
-
- #ifndef __LINUX_MTD_GEN_PROBE_H__
-@@ -10,12 +10,12 @@
- #include <linux/mtd/flashchip.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/cfi.h>
-+#include <linux/bitops.h>
-
- struct chip_probe {
- char *name;
- int (*probe_chip)(struct map_info *map, __u32 base,
-- struct flchip *chips, struct cfi_private *cfi);
--
-+ unsigned long *chip_map, struct cfi_private *cfi);
- };
-
- struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp);
---- /dev/null
-+++ linux-2.4.21/include/linux/mtd/inftl.h
-@@ -0,0 +1,57 @@
-+/*
-+ * inftl.h -- defines to support the Inverse NAND Flash Translation Layer
-+ *
-+ * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
-+ *
-+ * $Id: inftl.h,v 1.6 2004/06/30 14:49:00 dbrown Exp $
-+ */
-+
-+#ifndef __MTD_INFTL_H__
-+#define __MTD_INFTL_H__
-+
-+#ifndef __KERNEL__
-+#error This is a kernel header. Perhaps include nftl-user.h instead?
-+#endif
-+
-+#include <linux/mtd/blktrans.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nftl.h>
-+
-+#include <mtd/inftl-user.h>
-+
-+#ifndef INFTL_MAJOR
-+#define INFTL_MAJOR 94
-+#endif
-+#define INFTL_PARTN_BITS 4
-+
-+#ifdef __KERNEL__
-+
-+struct INFTLrecord {
-+ struct mtd_blktrans_dev mbd;
-+ __u16 MediaUnit;
-+ __u32 EraseSize;
-+ struct INFTLMediaHeader MediaHdr;
-+ int usecount;
-+ unsigned char heads;
-+ unsigned char sectors;
-+ unsigned short cylinders;
-+ __u16 numvunits;
-+ __u16 firstEUN;
-+ __u16 lastEUN;
-+ __u16 numfreeEUNs;
-+ __u16 LastFreeEUN; /* To speed up finding a free EUN */
-+ int head,sect,cyl;
-+ __u16 *PUtable; /* Physical Unit Table */
-+ __u16 *VUtable; /* Virtual Unit Table */
-+ unsigned int nb_blocks; /* number of physical blocks */
-+ unsigned int nb_boot_blocks; /* number of blocks used by the bios */
-+ struct erase_info instr;
-+ struct nand_oobinfo oobinfo;
-+};
-+
-+int INFTL_mount(struct INFTLrecord *s);
-+int INFTL_formatblock(struct INFTLrecord *s, int block);
-+
-+#endif /* __KERNEL__ */
-+
-+#endif /* __MTD_INFTL_H__ */
---- linux-2.4.21/include/linux/mtd/jedec.h~mtd-cvs
-+++ linux-2.4.21/include/linux/mtd/jedec.h
-@@ -7,14 +7,13 @@
- *
- * See the AMD flash databook for information on how to operate the interface.
- *
-- * $Id: jedec.h,v 1.2 2001/11/06 14:37:36 dwmw2 Exp $
-+ * $Id: jedec.h,v 1.3 2003/05/21 11:51:01 dwmw2 Exp $
- */
-
- #ifndef __LINUX_MTD_JEDEC_H__
- #define __LINUX_MTD_JEDEC_H__
-
- #include <linux/types.h>
--#include <linux/mtd/map.h>
-
- #define MAX_JEDEC_CHIPS 16
-
---- linux-2.4.21/include/linux/mtd/map.h~mtd-cvs
-+++ linux-2.4.21/include/linux/mtd/map.h
-@@ -1,23 +1,176 @@
-
- /* Overhauled routines for dealing with different mmap regions of flash */
--/* $Id: map.h,v 1.29 2002/10/21 13:20:52 jocke Exp $ */
-+/* $Id: map.h,v 1.48 2005/02/16 15:54:59 nico Exp $ */
-
- #ifndef __LINUX_MTD_MAP_H__
- #define __LINUX_MTD_MAP_H__
-
- #include <linux/config.h>
- #include <linux/types.h>
--#include <linux/mtd/mtd.h>
--#include <linux/slab.h>
-+#include <linux/list.h>
-+#include <linux/mtd/compatmac.h>
-+#include <asm/unaligned.h>
-+#include <asm/system.h>
-+#include <asm/io.h>
-+#include <asm/bug.h>
-+
-+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1
-+#define map_bankwidth(map) 1
-+#define map_bankwidth_is_1(map) (map_bankwidth(map) == 1)
-+#define map_bankwidth_is_large(map) (0)
-+#define map_words(map) (1)
-+#define MAX_MAP_BANKWIDTH 1
-+#else
-+#define map_bankwidth_is_1(map) (0)
-+#endif
-+
-+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_2
-+# ifdef map_bankwidth
-+# undef map_bankwidth
-+# define map_bankwidth(map) ((map)->bankwidth)
-+# else
-+# define map_bankwidth(map) 2
-+# define map_bankwidth_is_large(map) (0)
-+# define map_words(map) (1)
-+# endif
-+#define map_bankwidth_is_2(map) (map_bankwidth(map) == 2)
-+#undef MAX_MAP_BANKWIDTH
-+#define MAX_MAP_BANKWIDTH 2
-+#else
-+#define map_bankwidth_is_2(map) (0)
-+#endif
-+
-+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_4
-+# ifdef map_bankwidth
-+# undef map_bankwidth
-+# define map_bankwidth(map) ((map)->bankwidth)
-+# else
-+# define map_bankwidth(map) 4
-+# define map_bankwidth_is_large(map) (0)
-+# define map_words(map) (1)
-+# endif
-+#define map_bankwidth_is_4(map) (map_bankwidth(map) == 4)
-+#undef MAX_MAP_BANKWIDTH
-+#define MAX_MAP_BANKWIDTH 4
-+#else
-+#define map_bankwidth_is_4(map) (0)
-+#endif
-+
-+/* ensure we never evaluate anything shorted than an unsigned long
-+ * to zero, and ensure we'll never miss the end of an comparison (bjd) */
-+
-+#define map_calc_words(map) ((map_bankwidth(map) + (sizeof(unsigned long)-1))/ sizeof(unsigned long))
-+
-+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_8
-+# ifdef map_bankwidth
-+# undef map_bankwidth
-+# define map_bankwidth(map) ((map)->bankwidth)
-+# if BITS_PER_LONG < 64
-+# undef map_bankwidth_is_large
-+# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
-+# undef map_words
-+# define map_words(map) map_calc_words(map)
-+# endif
-+# else
-+# define map_bankwidth(map) 8
-+# define map_bankwidth_is_large(map) (BITS_PER_LONG < 64)
-+# define map_words(map) map_calc_words(map)
-+# endif
-+#define map_bankwidth_is_8(map) (map_bankwidth(map) == 8)
-+#undef MAX_MAP_BANKWIDTH
-+#define MAX_MAP_BANKWIDTH 8
-+#else
-+#define map_bankwidth_is_8(map) (0)
-+#endif
-+
-+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_16
-+# ifdef map_bankwidth
-+# undef map_bankwidth
-+# define map_bankwidth(map) ((map)->bankwidth)
-+# undef map_bankwidth_is_large
-+# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
-+# undef map_words
-+# define map_words(map) map_calc_words(map)
-+# else
-+# define map_bankwidth(map) 16
-+# define map_bankwidth_is_large(map) (1)
-+# define map_words(map) map_calc_words(map)
-+# endif
-+#define map_bankwidth_is_16(map) (map_bankwidth(map) == 16)
-+#undef MAX_MAP_BANKWIDTH
-+#define MAX_MAP_BANKWIDTH 16
-+#else
-+#define map_bankwidth_is_16(map) (0)
-+#endif
-+
-+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_32
-+# ifdef map_bankwidth
-+# undef map_bankwidth
-+# define map_bankwidth(map) ((map)->bankwidth)
-+# undef map_bankwidth_is_large
-+# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
-+# undef map_words
-+# define map_words(map) map_calc_words(map)
-+# else
-+# define map_bankwidth(map) 32
-+# define map_bankwidth_is_large(map) (1)
-+# define map_words(map) map_calc_words(map)
-+# endif
-+#define map_bankwidth_is_32(map) (map_bankwidth(map) == 32)
-+#undef MAX_MAP_BANKWIDTH
-+#define MAX_MAP_BANKWIDTH 32
-+#else
-+#define map_bankwidth_is_32(map) (0)
-+#endif
-+
-+#ifndef map_bankwidth
-+#error "No bus width supported. What's the point?"
-+#endif
-+
-+static inline int map_bankwidth_supported(int w)
-+{
-+ switch (w) {
-+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1
-+ case 1:
-+#endif
-+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_2
-+ case 2:
-+#endif
-+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_4
-+ case 4:
-+#endif
-+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_8
-+ case 8:
-+#endif
-+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_16
-+ case 16:
-+#endif
-+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_32
-+ case 32:
-+#endif
-+ return 1;
-+
-+ default:
-+ return 0;
-+ }
-+}
-+
-+#define MAX_MAP_LONGS ( ((MAX_MAP_BANKWIDTH*8) + BITS_PER_LONG - 1) / BITS_PER_LONG )
-+
-+typedef union {
-+ unsigned long x[MAX_MAP_LONGS];
-+} map_word;
-
- /* The map stuff is very simple. You fill in your struct map_info with
- a handful of routines for accessing the device, making sure they handle
- paging etc. correctly if your device needs it. Then you pass it off
-- to a chip driver which deals with a mapped device - generally either
-- do_cfi_probe() or do_ram_probe(), either of which will return a
-- struct mtd_info if they liked what they saw. At which point, you
-- fill in the mtd->module with your own module address, and register
-- it.
-+ to a chip probe routine -- either JEDEC or CFI probe or both -- via
-+ do_map_probe(). If a chip is recognised, the probe code will invoke the
-+ appropriate chip driver (if present) and return a struct mtd_info.
-+ At which point, you fill in the mtd->module with your own module
-+ address, and register it with the MTD core code. Or you could partition
-+ it and register the partitions instead, or keep it for your own private
-+ use; whatever.
-
- The mtd->priv field will point to the struct map_info, and any further
- private data required by the chip driver is linked from the
-@@ -29,39 +182,45 @@
- struct map_info {
- char *name;
- unsigned long size;
-- int buswidth; /* in octets */
-- __u8 (*read8)(struct map_info *, unsigned long);
-- __u16 (*read16)(struct map_info *, unsigned long);
-- __u32 (*read32)(struct map_info *, unsigned long);
-- __u64 (*read64)(struct map_info *, unsigned long);
-- /* If it returned a 'long' I'd call it readl.
-- * It doesn't.
-- * I won't.
-- * dwmw2 */
-+ unsigned long phys;
-+#define NO_XIP (-1UL)
-
-+ void __iomem *virt;
-+ void *cached;
-+
-+ int bankwidth; /* in octets. This isn't necessarily the width
-+ of actual bus cycles -- it's the repeat interval
-+ in bytes, before you are talking to the first chip again.
-+ */
-+
-+#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
-+ map_word (*read)(struct map_info *, unsigned long);
- void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t);
-- void (*write8)(struct map_info *, __u8, unsigned long);
-- void (*write16)(struct map_info *, __u16, unsigned long);
-- void (*write32)(struct map_info *, __u32, unsigned long);
-- void (*write64)(struct map_info *, __u64, unsigned long);
-+
-+ void (*write)(struct map_info *, const map_word, unsigned long);
- void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t);
-
-- u_char * (*point) (struct map_info *, loff_t, size_t);
-- void (*unpoint) (struct map_info *, u_char *, loff_t, size_t);
-+ /* We can perhaps put in 'point' and 'unpoint' methods, if we really
-+ want to enable XIP for non-linear mappings. Not yet though. */
-+#endif
-+ /* It's possible for the map driver to use cached memory in its
-+ copy_from implementation (and _only_ with copy_from). However,
-+ when the chip driver knows some flash area has changed contents,
-+ it will signal it to the map driver through this routine to let
-+ the map driver invalidate the corresponding cache as needed.
-+ If there is no cache to care about this can be set to NULL. */
-+ void (*inval_cache)(struct map_info *, unsigned long, ssize_t);
-
-+ /* set_vpp() must handle being reentered -- enable, enable, disable
-+ must leave it enabled. */
- void (*set_vpp)(struct map_info *, int);
-- /* We put these two here rather than a single void *map_priv,
-- because we want mappers to be able to have quickly-accessible
-- cache for the 'currently-mapped page' without the _extra_
-- redirection that would be necessary. If you need more than
-- two longs, turn the second into a pointer. dwmw2 */
-+
- unsigned long map_priv_1;
- unsigned long map_priv_2;
- void *fldrv_priv;
- struct mtd_chip_driver *fldrv;
- };
-
--
- struct mtd_chip_driver {
- struct mtd_info *(*probe)(struct map_info *map);
- void (*destroy)(struct mtd_info *);
-@@ -74,26 +233,193 @@
- void unregister_mtd_chip_driver(struct mtd_chip_driver *);
-
- struct mtd_info *do_map_probe(const char *name, struct map_info *map);
-+void map_destroy(struct mtd_info *mtd);
-+
-+#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0)
-+#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0)
-
-+#define INVALIDATE_CACHED_RANGE(map, from, size) \
-+ do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0)
-
--/*
-- * Destroy an MTD device which was created for a map device.
-- * Make sure the MTD device is already unregistered before calling this
-- */
--static inline void map_destroy(struct mtd_info *mtd)
-+
-+static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2)
- {
-- struct map_info *map = mtd->priv;
-+ int i;
-+ for (i=0; i<map_words(map); i++) {
-+ if (val1.x[i] != val2.x[i])
-+ return 0;
-+ }
-+ return 1;
-+}
-
-- if (map->fldrv->destroy)
-- map->fldrv->destroy(mtd);
--#ifdef CONFIG_MODULES
-- if (map->fldrv->module)
-- __MOD_DEC_USE_COUNT(map->fldrv->module);
-+static inline map_word map_word_and(struct map_info *map, map_word val1, map_word val2)
-+{
-+ map_word r;
-+ int i;
-+
-+ for (i=0; i<map_words(map); i++) {
-+ r.x[i] = val1.x[i] & val2.x[i];
-+ }
-+ return r;
-+}
-+
-+static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2)
-+{
-+ map_word r;
-+ int i;
-+
-+ for (i=0; i<map_words(map); i++) {
-+ r.x[i] = val1.x[i] & ~val2.x[i];
-+ }
-+ return r;
-+}
-+
-+static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2)
-+{
-+ map_word r;
-+ int i;
-+
-+ for (i=0; i<map_words(map); i++) {
-+ r.x[i] = val1.x[i] | val2.x[i];
-+ }
-+ return r;
-+}
-+
-+#define map_word_andequal(m, a, b, z) map_word_equal(m, z, map_word_and(m, a, b))
-+
-+static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2)
-+{
-+ int i;
-+
-+ for (i=0; i<map_words(map); i++) {
-+ if (val1.x[i] & val2.x[i])
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+static inline map_word map_word_load(struct map_info *map, const void *ptr)
-+{
-+ map_word r;
-+
-+ if (map_bankwidth_is_1(map))
-+ r.x[0] = *(unsigned char *)ptr;
-+ else if (map_bankwidth_is_2(map))
-+ r.x[0] = get_unaligned((uint16_t *)ptr);
-+ else if (map_bankwidth_is_4(map))
-+ r.x[0] = get_unaligned((uint32_t *)ptr);
-+#if BITS_PER_LONG >= 64
-+ else if (map_bankwidth_is_8(map))
-+ r.x[0] = get_unaligned((uint64_t *)ptr);
- #endif
-- kfree(mtd);
-+ else if (map_bankwidth_is_large(map))
-+ memcpy(r.x, ptr, map->bankwidth);
-+
-+ return r;
- }
-
--#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0)
--#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0)
-+static inline map_word map_word_load_partial(struct map_info *map, map_word orig, const unsigned char *buf, int start, int len)
-+{
-+ int i;
-+
-+ if (map_bankwidth_is_large(map)) {
-+ char *dest = (char *)&orig;
-+ memcpy(dest+start, buf, len);
-+ } else {
-+ for (i=start; i < start+len; i++) {
-+ int bitpos;
-+#ifdef __LITTLE_ENDIAN
-+ bitpos = i*8;
-+#else /* __BIG_ENDIAN */
-+ bitpos = (map_bankwidth(map)-1-i)*8;
-+#endif
-+ orig.x[0] &= ~(0xff << bitpos);
-+ orig.x[0] |= buf[i-start] << bitpos;
-+ }
-+ }
-+ return orig;
-+}
-+
-+static inline map_word map_word_ff(struct map_info *map)
-+{
-+ map_word r;
-+ int i;
-+
-+ for (i=0; i<map_words(map); i++) {
-+ r.x[i] = ~0UL;
-+ }
-+ return r;
-+}
-+
-+static inline map_word inline_map_read(struct map_info *map, unsigned long ofs)
-+{
-+ map_word r;
-+
-+ if (map_bankwidth_is_1(map))
-+ r.x[0] = __raw_readb(map->virt + ofs);
-+ else if (map_bankwidth_is_2(map))
-+ r.x[0] = __raw_readw(map->virt + ofs);
-+ else if (map_bankwidth_is_4(map))
-+ r.x[0] = __raw_readl(map->virt + ofs);
-+#if BITS_PER_LONG >= 64
-+ else if (map_bankwidth_is_8(map))
-+ r.x[0] = __raw_readq(map->virt + ofs);
-+#endif
-+ else if (map_bankwidth_is_large(map))
-+ memcpy_fromio(r.x, map->virt+ofs, map->bankwidth);
-+
-+ return r;
-+}
-+
-+static inline void inline_map_write(struct map_info *map, const map_word datum, unsigned long ofs)
-+{
-+ if (map_bankwidth_is_1(map))
-+ __raw_writeb(datum.x[0], map->virt + ofs);
-+ else if (map_bankwidth_is_2(map))
-+ __raw_writew(datum.x[0], map->virt + ofs);
-+ else if (map_bankwidth_is_4(map))
-+ __raw_writel(datum.x[0], map->virt + ofs);
-+#if BITS_PER_LONG >= 64
-+ else if (map_bankwidth_is_8(map))
-+ __raw_writeq(datum.x[0], map->virt + ofs);
-+#endif
-+ else if (map_bankwidth_is_large(map))
-+ memcpy_toio(map->virt+ofs, datum.x, map->bankwidth);
-+ mb();
-+}
-+
-+static inline void inline_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-+{
-+ if (map->cached)
-+ memcpy(to, (char *)map->cached + from, len);
-+ else
-+ memcpy_fromio(to, map->virt + from, len);
-+}
-+
-+static inline void inline_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-+{
-+ memcpy_toio(map->virt + to, from, len);
-+}
-+
-+#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
-+#define map_read(map, ofs) (map)->read(map, ofs)
-+#define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len)
-+#define map_write(map, datum, ofs) (map)->write(map, datum, ofs)
-+#define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len)
-+
-+extern void simple_map_init(struct map_info *);
-+#define map_is_linear(map) (map->phys != NO_XIP)
-+
-+#else
-+#define map_read(map, ofs) inline_map_read(map, ofs)
-+#define map_copy_from(map, to, from, len) inline_map_copy_from(map, to, from, len)
-+#define map_write(map, datum, ofs) inline_map_write(map, datum, ofs)
-+#define map_copy_to(map, to, from, len) inline_map_copy_to(map, to, from, len)
-+
-+
-+#define simple_map_init(map) BUG_ON(!map_bankwidth_supported((map)->bankwidth))
-+#define map_is_linear(map) ({ (void)(map); 1; })
-+
-+#endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */
-
- #endif /* __LINUX_MTD_MAP_H__ */
---- linux-2.4.21/include/linux/mtd/mtd.h~mtd-cvs
-+++ linux-2.4.21/include/linux/mtd/mtd.h
-@@ -1,123 +1,45 @@
--
--/* $Id: mtd.h,v 1.38 2003/01/12 16:30:19 spse Exp $ */
-+/*
-+ * $Id: mtd.h,v 1.57 2005/02/08 17:11:15 nico Exp $
-+ *
-+ * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al.
-+ *
-+ * Released under GPL
-+ */
-
- #ifndef __MTD_MTD_H__
- #define __MTD_MTD_H__
-
--#ifdef __KERNEL__
-+#ifndef __KERNEL__
-+#error This is a kernel header. Perhaps include mtd-user.h instead?
-+#endif
-
- #include <linux/config.h>
- #include <linux/version.h>
- #include <linux/types.h>
--#include <linux/mtd/compatmac.h>
- #include <linux/module.h>
- #include <linux/uio.h>
-
--#endif /* __KERNEL__ */
--
--struct erase_info_user {
-- u_int32_t start;
-- u_int32_t length;
--};
--
--struct mtd_oob_buf {
-- u_int32_t start;
-- u_int32_t length;
-- unsigned char *ptr;
--};
--
-+#include <linux/mtd/compatmac.h>
-+#include <mtd/mtd-abi.h>
-
- #define MTD_CHAR_MAJOR 90
- #define MTD_BLOCK_MAJOR 31
- #define MAX_MTD_DEVICES 16
-
--
--
--#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
--
--struct mtd_info_user {
-- u_char type;
-- u_int32_t flags;
-- u_int32_t size; // Total size of the MTD
-- u_int32_t erasesize;
-- u_int32_t oobblock; // Size of OOB blocks (e.g. 512)
-- u_int32_t oobsize; // Amount of OOB data per block (e.g. 16)
-- u_int32_t ecctype;
-- u_int32_t eccsize;
--};
--
--struct region_info_user {
-- u_int32_t offset; /* At which this region starts,
-- * from the beginning of the MTD */
-- u_int32_t erasesize; /* For this region */
-- u_int32_t numblocks; /* Number of blocks in this region */
-- u_int32_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 MEMREADDATA _IOWR('M', 9, struct mtd_oob_buf)
--#define MEMWRITEDATA _IOWR('M', 10, struct mtd_oob_buf)
--
--#ifndef __KERNEL__
--
--typedef struct mtd_info_user mtd_info_t;
--typedef struct erase_info_user erase_info_t;
--typedef struct region_info_user region_info_t;
--
-- /* User-space ioctl definitions */
--
--
--#else /* __KERNEL__ */
--
--
- #define MTD_ERASE_PENDING 0x01
- #define MTD_ERASING 0x02
- #define MTD_ERASE_SUSPEND 0x04
- #define MTD_ERASE_DONE 0x08
- #define MTD_ERASE_FAILED 0x10
-
-+/* If the erase fails, fail_addr might indicate exactly which block failed. If
-+ fail_addr = 0xffffffff, the failure was not at the device level or was not
-+ specific to any particular block. */
- struct erase_info {
- struct mtd_info *mtd;
- u_int32_t addr;
- u_int32_t len;
-+ u_int32_t fail_addr;
- u_long time;
- u_long retries;
- u_int dev;
-@@ -147,13 +69,18 @@
-
- u_int32_t oobblock; // Size of OOB blocks (e.g. 512)
- u_int32_t oobsize; // Amount of OOB data per block (e.g. 16)
-+ u_int32_t oobavail; // Number of bytes in OOB area available for fs
- u_int32_t ecctype;
- u_int32_t eccsize;
-
-+
- // Kernel-only stuff starts here.
- char *name;
- int index;
-
-+ // oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO)
-+ struct nand_oobinfo oobinfo;
-+
- /* Data for variable erase regions. If numeraseregions is zero,
- * it means that the whole device has erasesize as given above.
- */
-@@ -163,7 +90,6 @@
- /* This really shouldn't be here. It can go away in 2.5 */
- u_int32_t bank_size;
-
-- struct module *module;
- int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
-
- /* This stuff for eXecute-In-Place */
-@@ -176,8 +102,8 @@
- int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
- int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
-
-- int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel);
-- int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
-+ int (*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);
-+ int (*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 (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
- int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
-@@ -187,24 +113,24 @@
- * flash devices. The user data is one time programmable but the
- * factory data is read only.
- */
-- int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
--
-+ int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
- int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
--
-- /* This function is not yet implemented */
-+ int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
-+ int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
- int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
-+ int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);
-
-- /* iovec-based read/write methods. We need these especially for NAND flash,
-+ /* kvec-based read/write methods. We need these especially for NAND flash,
- with its limited number of write cycles per erase.
- NB: The 'count' parameter is the number of _vectors_, each of
- which contains an (ofs, len) tuple.
- */
-- int (*readv) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen);
-- int (*readv_ecc) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from,
-- size_t *retlen, u_char *eccbuf, int oobsel);
-- int (*writev) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen);
-- int (*writev_ecc) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to,
-- size_t *retlen, u_char *eccbuf, int oobsel);
-+ int (*readv) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, size_t *retlen);
-+ int (*readv_ecc) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from,
-+ size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
-+ int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);
-+ int (*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);
-
- /* Sync */
- void (*sync) (struct mtd_info *mtd);
-@@ -217,7 +143,14 @@
- int (*suspend) (struct mtd_info *mtd);
- void (*resume) (struct mtd_info *mtd);
-
-+ /* Bad block management functions */
-+ int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
-+ int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
-+
- void *priv;
-+
-+ struct module *owner;
-+ int usecount;
- };
-
-
-@@ -226,44 +159,27 @@
- extern int add_mtd_device(struct mtd_info *mtd);
- extern int del_mtd_device (struct mtd_info *mtd);
-
--extern struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num);
--
--static inline struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
--{
-- struct mtd_info *ret;
--
-- ret = __get_mtd_device(mtd, num);
--
-- if (ret && ret->module && !try_inc_mod_count(ret->module))
-- return NULL;
--
-- return ret;
--}
-+extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num);
-
--static inline void put_mtd_device(struct mtd_info *mtd)
--{
-- if (mtd->module)
-- __MOD_DEC_USE_COUNT(mtd->module);
--}
-+extern void put_mtd_device(struct mtd_info *mtd);
-
-
- struct mtd_notifier {
- void (*add)(struct mtd_info *mtd);
- void (*remove)(struct mtd_info *mtd);
-- struct mtd_notifier *next;
-+ struct list_head list;
- };
-
-
- extern void register_mtd_user (struct mtd_notifier *new);
- extern int unregister_mtd_user (struct mtd_notifier *old);
-
--int default_mtd_writev(struct mtd_info *mtd, const struct iovec *vecs,
-+int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
- unsigned long count, loff_t to, size_t *retlen);
-
--int default_mtd_readv(struct mtd_info *mtd, struct iovec *vecs,
-+int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,
- unsigned long count, loff_t from, size_t *retlen);
-
--#ifndef MTDC
- #define MTD_ERASE(mtd, args...) (*(mtd->erase))(mtd, args)
- #define MTD_POINT(mtd, a,b,c,d) (*(mtd->point))(mtd, a,b,c, (u_char **)(d))
- #define MTD_UNPOINT(mtd, arg) (*(mtd->unpoint))(mtd, (u_char *)arg)
-@@ -276,7 +192,17 @@
- #define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args)
- #define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args)
- #define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0)
--#endif /* MTDC */
-+
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+void mtd_erase_callback(struct erase_info *instr);
-+#else
-+static inline void mtd_erase_callback(struct erase_info *instr)
-+{
-+ if (instr->callback)
-+ instr->callback(instr);
-+}
-+#endif
-
- /*
- * Debugging macro and defines
-@@ -288,13 +214,13 @@
-
- #ifdef CONFIG_MTD_DEBUG
- #define DEBUG(n, args...) \
-- if (n <= CONFIG_MTD_DEBUG_VERBOSE) { \
-+ do { \
-+ if (n <= CONFIG_MTD_DEBUG_VERBOSE) \
- printk(KERN_INFO args); \
-- }
-+ } while(0)
- #else /* CONFIG_MTD_DEBUG */
--#define DEBUG(n, args...)
--#endif /* CONFIG_MTD_DEBUG */
-+#define DEBUG(n, args...) do { } while(0)
-
--#endif /* __KERNEL__ */
-+#endif /* CONFIG_MTD_DEBUG */
-
- #endif /* __MTD_MTD_H__ */
---- linux-2.4.21/include/linux/mtd/nand.h~mtd-cvs
-+++ linux-2.4.21/include/linux/mtd/nand.h
-@@ -2,10 +2,10 @@
- * linux/include/linux/mtd/nand.h
- *
- * Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com>
-- * Steven J. Hill <sjhill@cotw.com>
-+ * Steven J. Hill <sjhill@realitydiluted.com>
- * Thomas Gleixner <tglx@linutronix.de>
- *
-- * $Id: nand.h,v 1.19 2002/12/02 21:48:17 gleixner Exp $
-+ * $Id: nand.h,v 1.71 2005/02/09 12:12:59 gleixner 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
-@@ -44,27 +44,61 @@
- * NAND_YAFFS_OOB
- * 11-25-2002 tglx Added Manufacturer code FUJITSU, NATIONAL
- * Split manufacturer and device ID structures
-+ *
-+ * 02-08-2004 tglx added option field to nand structure for chip anomalities
-+ * 05-25-2004 tglx added bad block table support, ST-MICRO manufacturer id
-+ * update of nand_chip structure description
-+ * 01-17-2005 dmarlin added extended commands for AG-AND device and added option
-+ * for BBT_AUTO_REFRESH.
-+ * 01-20-2005 dmarlin added optional pointer to hardware specific callback for
-+ * extra error status checks.
- */
- #ifndef __LINUX_MTD_NAND_H
- #define __LINUX_MTD_NAND_H
-
- #include <linux/config.h>
--#include <linux/sched.h>
-+#include <linux/wait.h>
-+#include <linux/spinlock.h>
-+#include <linux/mtd/mtd.h>
-
--/*
-- * Searches for a NAND device
-+struct mtd_info;
-+/* Scan and identify a NAND device */
-+extern int nand_scan (struct mtd_info *mtd, int max_chips);
-+/* Free resources held by the NAND device */
-+extern void nand_release (struct mtd_info *mtd);
-+
-+/* Read raw data from the device without ECC */
-+extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen);
-+
-+
-+/* The maximum number of NAND chips in an array */
-+#define NAND_MAX_CHIPS 8
-+
-+/* This constant declares the max. oobsize / page, which
-+ * is supported now. If you add a chip with bigger oobsize/page
-+ * adjust this accordingly.
- */
--extern int nand_scan (struct mtd_info *mtd);
-+#define NAND_MAX_OOBSIZE 64
-
- /*
- * Constants for hardware specific CLE/ALE/NCE function
- */
-+/* Select the chip by setting nCE to low */
- #define NAND_CTL_SETNCE 1
-+/* Deselect the chip by setting nCE to high */
- #define NAND_CTL_CLRNCE 2
-+/* Select the command latch by setting CLE to high */
- #define NAND_CTL_SETCLE 3
-+/* Deselect the command latch by setting CLE to low */
- #define NAND_CTL_CLRCLE 4
-+/* Select the address latch by setting ALE to high */
- #define NAND_CTL_SETALE 5
-+/* Deselect the address latch by setting ALE to low */
- #define NAND_CTL_CLRALE 6
-+/* Set write protection by setting WP to high. Not used! */
-+#define NAND_CTL_SETWP 7
-+/* Clear write protection by setting WP to low. Not used! */
-+#define NAND_CTL_CLRWP 8
-
- /*
- * Standard NAND flash commands
-@@ -75,35 +109,132 @@
- #define NAND_CMD_READOOB 0x50
- #define NAND_CMD_ERASE1 0x60
- #define NAND_CMD_STATUS 0x70
-+#define NAND_CMD_STATUS_MULTI 0x71
- #define NAND_CMD_SEQIN 0x80
- #define NAND_CMD_READID 0x90
- #define NAND_CMD_ERASE2 0xd0
- #define NAND_CMD_RESET 0xff
-
-+/* Extended commands for large page devices */
-+#define NAND_CMD_READSTART 0x30
-+#define NAND_CMD_CACHEDPROG 0x15
-+
-+/* Extended commands for AG-AND device */
-+/*
-+ * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but
-+ * there is no way to distinguish that from NAND_CMD_READ0
-+ * until the remaining sequence of commands has been completed
-+ * so add a high order bit and mask it off in the command.
-+ */
-+#define NAND_CMD_DEPLETE1 0x100
-+#define NAND_CMD_DEPLETE2 0x38
-+#define NAND_CMD_STATUS_MULTI 0x71
-+#define NAND_CMD_STATUS_ERROR 0x72
-+/* multi-bank error status (banks 0-3) */
-+#define NAND_CMD_STATUS_ERROR0 0x73
-+#define NAND_CMD_STATUS_ERROR1 0x74
-+#define NAND_CMD_STATUS_ERROR2 0x75
-+#define NAND_CMD_STATUS_ERROR3 0x76
-+#define NAND_CMD_STATUS_RESET 0x7f
-+#define NAND_CMD_STATUS_CLEAR 0xff
-+
-+/* Status bits */
-+#define NAND_STATUS_FAIL 0x01
-+#define NAND_STATUS_FAIL_N1 0x02
-+#define NAND_STATUS_TRUE_READY 0x20
-+#define NAND_STATUS_READY 0x40
-+#define NAND_STATUS_WP 0x80
-+
- /*
- * Constants for ECC_MODES
-- *
-- * NONE: No ECC
-- * SOFT: Software ECC 3 byte ECC per 256 Byte data
-- * HW3_256: Hardware ECC 3 byte ECC per 256 Byte data
-- * HW3_512: Hardware ECC 3 byte ECC per 512 Byte data
-- *
-- *
--*/
-+ */
-+
-+/* No ECC. Usage is not recommended ! */
- #define NAND_ECC_NONE 0
-+/* Software ECC 3 byte ECC per 256 Byte data */
- #define NAND_ECC_SOFT 1
-+/* Hardware ECC 3 byte ECC per 256 Byte data */
- #define NAND_ECC_HW3_256 2
-+/* Hardware ECC 3 byte ECC per 512 Byte data */
- #define NAND_ECC_HW3_512 3
-+/* Hardware ECC 3 byte ECC per 512 Byte data */
- #define NAND_ECC_HW6_512 4
--#define NAND_ECC_DISKONCHIP 5
-+/* Hardware ECC 8 byte ECC per 512 Byte data */
-+#define NAND_ECC_HW8_512 6
-+/* Hardware ECC 12 byte ECC per 2048 Byte data */
-+#define NAND_ECC_HW12_2048 7
-
- /*
- * Constants for Hardware ECC
--*/
-+ */
-+/* Reset Hardware ECC for read */
- #define NAND_ECC_READ 0
-+/* Reset Hardware ECC for write */
- #define NAND_ECC_WRITE 1
-+/* Enable Hardware ECC before syndrom is read back from flash */
-+#define NAND_ECC_READSYN 2
-+
-+/* Bit mask for flags passed to do_nand_read_ecc */
-+#define NAND_GET_DEVICE 0x80
-+
-+
-+/* Option constants for bizarre disfunctionality and real
-+* features
-+*/
-+/* Chip can not auto increment pages */
-+#define NAND_NO_AUTOINCR 0x00000001
-+/* Buswitdh is 16 bit */
-+#define NAND_BUSWIDTH_16 0x00000002
-+/* Device supports partial programming without padding */
-+#define NAND_NO_PADDING 0x00000004
-+/* Chip has cache program function */
-+#define NAND_CACHEPRG 0x00000008
-+/* Chip has copy back function */
-+#define NAND_COPYBACK 0x00000010
-+/* AND Chip which has 4 banks and a confusing page / block
-+ * assignment. See Renesas datasheet for further information */
-+#define NAND_IS_AND 0x00000020
-+/* Chip has a array of 4 pages which can be read without
-+ * additional ready /busy waits */
-+#define NAND_4PAGE_ARRAY 0x00000040
-+/* Chip requires that BBT is periodically rewritten to prevent
-+ * bits from adjacent blocks from 'leaking' in altering data.
-+ * This happens with the Renesas AG-AND chips, possibly others. */
-+#define BBT_AUTO_REFRESH 0x00000080
-+
-+/* Options valid for Samsung large page devices */
-+#define NAND_SAMSUNG_LP_OPTIONS \
-+ (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)
-+
-+/* Macros to identify the above */
-+#define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR))
-+#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING))
-+#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
-+#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
-+
-+/* Mask to zero out the chip options, which come from the id table */
-+#define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR)
-+
-+/* Non chip related options */
-+/* Use a flash based bad block table. This option is passed to the
-+ * default bad block table function. */
-+#define NAND_USE_FLASH_BBT 0x00010000
-+/* The hw ecc generator provides a syndrome instead a ecc value on read
-+ * This can only work if we have the ecc bytes directly behind the
-+ * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */
-+#define NAND_HWECC_SYNDROME 0x00020000
-+/* This option skips the bbt scan during initialization. */
-+#define NAND_SKIP_BBTSCAN 0x00040000
-+
-+/* Options set by nand scan */
-+/* Nand scan has allocated oob_buf */
-+#define NAND_OOBBUF_ALLOC 0x40000000
-+/* Nand scan has allocated data_buf */
-+#define NAND_DATABUF_ALLOC 0x80000000
-+
-
- /*
-+ * nand_state_t - chip states
- * Enumeration for NAND flash chip state
- */
- typedef enum {
-@@ -111,73 +242,137 @@
- FL_READING,
- FL_WRITING,
- FL_ERASING,
-- FL_SYNCING
-+ FL_SYNCING,
-+ FL_CACHEDPRG,
- } nand_state_t;
-
-+/* Keep gcc happy */
-+struct nand_chip;
-
--/*
-- * NAND Private Flash Chip Data
-- *
-- * Structure overview:
-- *
-- * IO_ADDR_R - address to read the 8 I/O lines of the flash device
-- *
-- * IO_ADDR_W - address to write the 8 I/O lines of the flash device
-- *
-- * hwcontrol - hardwarespecific function for accesing control-lines
-- *
-- * dev_ready - hardwarespecific function for accesing device ready/busy line
-- *
-- * waitfunc - hardwarespecific function for wait on ready
-- *
-- * calculate_ecc - function for ecc calculation or readback from ecc hardware
-- *
-- * correct_data - function for ecc correction, matching to ecc generator (sw/hw)
-- *
-- * enable_hwecc - function to enable (reset) hardware ecc generator
-- *
-- * eccmod - mode of ecc: see constants
-- *
-- * eccsize - databytes used per ecc-calculation
-- *
-- * chip_delay - chip dependent delay for transfering data from array to read regs (tR)
-- *
-- * chip_lock - spinlock used to protect access to this structure
-- *
-- * wq - wait queue to sleep on if a NAND operation is in progress
-- *
-- * state - give the current state of the NAND device
-- *
-- * page_shift - number of address bits in a page (column address bits)
-- *
-- * data_buf - data buffer passed to/from MTD user modules
-- *
-- * data_cache - data cache for redundant page access and shadow for
-- * ECC failure
-- *
-- * cache_page - number of last valid page in page_cache
-+/**
-+ * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independend devices
-+ * @lock: protection lock
-+ * @active: the mtd device which holds the controller currently
- */
-+struct nand_hw_control {
-+ spinlock_t lock;
-+ struct nand_chip *active;
-+};
-+
-+/**
-+ * struct nand_chip - NAND Private Flash Chip Data
-+ * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device
-+ * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device
-+ * @read_byte: [REPLACEABLE] read one byte from the chip
-+ * @write_byte: [REPLACEABLE] write one byte to the chip
-+ * @read_word: [REPLACEABLE] read one word from the chip
-+ * @write_word: [REPLACEABLE] write one word to the chip
-+ * @write_buf: [REPLACEABLE] write data from the buffer to the chip
-+ * @read_buf: [REPLACEABLE] read data from the chip into the buffer
-+ * @verify_buf: [REPLACEABLE] verify buffer contents against the chip data
-+ * @select_chip: [REPLACEABLE] select chip nr
-+ * @block_bad: [REPLACEABLE] check, if the block is bad
-+ * @block_markbad: [REPLACEABLE] mark the block bad
-+ * @hwcontrol: [BOARDSPECIFIC] hardwarespecific function for accesing control-lines
-+ * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line
-+ * If set to NULL no access to ready/busy is available and the ready/busy information
-+ * is read from the chip status register
-+ * @cmdfunc: [REPLACEABLE] hardwarespecific function for writing commands to the chip
-+ * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on ready
-+ * @calculate_ecc: [REPLACEABLE] function for ecc calculation or readback from ecc hardware
-+ * @correct_data: [REPLACEABLE] function for ecc correction, matching to ecc generator (sw/hw)
-+ * @enable_hwecc: [BOARDSPECIFIC] function to enable (reset) hardware ecc generator. Must only
-+ * be provided if a hardware ECC is available
-+ * @erase_cmd: [INTERN] erase command write function, selectable due to AND support
-+ * @scan_bbt: [REPLACEABLE] function to scan bad block table
-+ * @eccmode: [BOARDSPECIFIC] mode of ecc, see defines
-+ * @eccsize: [INTERN] databytes used per ecc-calculation
-+ * @eccbytes: [INTERN] number of ecc bytes per ecc-calculation step
-+ * @eccsteps: [INTERN] number of ecc calculation steps per page
-+ * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR)
-+ * @chip_lock: [INTERN] spinlock used to protect access to this structure and the chip
-+ * @wq: [INTERN] wait queue to sleep on if a NAND operation is in progress
-+ * @state: [INTERN] the current state of the NAND device
-+ * @page_shift: [INTERN] number of address bits in a page (column address bits)
-+ * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock
-+ * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry
-+ * @chip_shift: [INTERN] number of address bits in one chip
-+ * @data_buf: [INTERN] internal buffer for one page + oob
-+ * @oob_buf: [INTERN] oob buffer for one eraseblock
-+ * @oobdirty: [INTERN] indicates that oob_buf must be reinitialized
-+ * @data_poi: [INTERN] pointer to a data buffer
-+ * @options: [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about
-+ * special functionality. See the defines for further explanation
-+ * @badblockpos: [INTERN] position of the bad block marker in the oob area
-+ * @numchips: [INTERN] number of physical chips
-+ * @chipsize: [INTERN] the size of one chip for multichip arrays
-+ * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
-+ * @pagebuf: [INTERN] holds the pagenumber which is currently in data_buf
-+ * @autooob: [REPLACEABLE] the default (auto)placement scheme
-+ * @bbt: [INTERN] bad block table pointer
-+ * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup
-+ * @bbt_md: [REPLACEABLE] bad block table mirror descriptor
-+ * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan
-+ * @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices
-+ * @priv: [OPTIONAL] pointer to private chip date
-+ * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks
-+ * (determine if errors are correctable)
-+ */
-+
- struct nand_chip {
-- unsigned long IO_ADDR_R;
-- unsigned long IO_ADDR_W;
-- void (*hwcontrol)(int cmd);
-- int (*dev_ready)(void);
-+ void __iomem *IO_ADDR_R;
-+ void __iomem *IO_ADDR_W;
-+
-+ u_char (*read_byte)(struct mtd_info *mtd);
-+ void (*write_byte)(struct mtd_info *mtd, u_char byte);
-+ u16 (*read_word)(struct mtd_info *mtd);
-+ void (*write_word)(struct mtd_info *mtd, u16 word);
-+
-+ void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len);
-+ void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len);
-+ int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len);
-+ void (*select_chip)(struct mtd_info *mtd, int chip);
-+ int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
-+ int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
-+ void (*hwcontrol)(struct mtd_info *mtd, int cmd);
-+ int (*dev_ready)(struct mtd_info *mtd);
- void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
- int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
-- void (*calculate_ecc)(const u_char *dat, u_char *ecc_code);
-- int (*correct_data)(u_char *dat, u_char *read_ecc, u_char *calc_ecc);
-- void (*enable_hwecc)(int mode);
-+ int (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
-+ int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
-+ void (*enable_hwecc)(struct mtd_info *mtd, int mode);
-+ void (*erase_cmd)(struct mtd_info *mtd, int page);
-+ int (*scan_bbt)(struct mtd_info *mtd);
- int eccmode;
- int eccsize;
-+ int eccbytes;
-+ int eccsteps;
- int chip_delay;
- spinlock_t chip_lock;
- wait_queue_head_t wq;
- nand_state_t state;
- int page_shift;
-+ int phys_erase_shift;
-+ int bbt_erase_shift;
-+ int chip_shift;
- u_char *data_buf;
-+ u_char *oob_buf;
-+ int oobdirty;
- u_char *data_poi;
-- u_char *data_cache;
-- int cache_page;
-+ unsigned int options;
-+ int badblockpos;
-+ int numchips;
-+ unsigned long chipsize;
-+ int pagemask;
-+ int pagebuf;
-+ struct nand_oobinfo *autooob;
-+ uint8_t *bbt;
-+ struct nand_bbt_descr *bbt_td;
-+ struct nand_bbt_descr *bbt_md;
-+ struct nand_bbt_descr *badblock_pattern;
-+ struct nand_hw_control *controller;
-+ void *priv;
-+ int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);
- };
-
- /*
-@@ -187,46 +382,35 @@
- #define NAND_MFR_SAMSUNG 0xec
- #define NAND_MFR_FUJITSU 0x04
- #define NAND_MFR_NATIONAL 0x8f
-+#define NAND_MFR_RENESAS 0x07
-+#define NAND_MFR_STMICRO 0x20
-
--/*
-- * NAND Flash Device ID Structure
-- *
-- * Structure overview:
-- *
-- * name - Identify the device type
-- *
-- * id - device ID code
-- *
-- * chipshift - total number of address bits for the device which
-- * is used to calculate address offsets and the total
-- * number of bytes the device is capable of.
-- *
-- * page256 - denotes if flash device has 256 byte pages or not.
-- *
-- * pageadrlen - number of bytes minus one needed to hold the
-- * complete address into the flash array. Keep in
-- * mind that when a read or write is done to a
-- * specific address, the address is input serially
-- * 8 bits at a time. This structure member is used
-- * by the read/write routines as a loop index for
-- * shifting the address out 8 bits at a time.
-+/**
-+ * struct nand_flash_dev - NAND Flash Device ID Structure
- *
-- * erasesize - size of an erase block in the flash device.
-+ * @name: Identify the device type
-+ * @id: device ID code
-+ * @pagesize: Pagesize in bytes. Either 256 or 512 or 0
-+ * If the pagesize is 0, then the real pagesize
-+ * and the eraseize are determined from the
-+ * extended id bytes in the chip
-+ * @erasesize: Size of an erase block in the flash device.
-+ * @chipsize: Total chipsize in Mega Bytes
-+ * @options: Bitfield to store chip relevant options
- */
- struct nand_flash_dev {
-- char * name;
-+ char *name;
- int id;
-- int chipshift;
-+ unsigned long pagesize;
-+ unsigned long chipsize;
- unsigned long erasesize;
-- char page256;
-+ unsigned long options;
- };
-
--/*
-- * NAND Flash Manufacturer ID Structure
-- *
-- * name - Manufacturer name
-- *
-- * id - manufacturer ID code of device.
-+/**
-+ * struct nand_manufacturers - NAND Flash Manufacturer ID Structure
-+ * @name: Manufacturer name
-+ * @id: manufacturer ID code of device.
- */
- struct nand_manufacturers {
- int id;
-@@ -236,39 +420,88 @@
- extern struct nand_flash_dev nand_flash_ids[];
- extern struct nand_manufacturers nand_manuf_ids[];
-
--/*
--* Constants for oob configuration
--*/
--#define NAND_BADBLOCK_POS 5
-+/**
-+ * struct nand_bbt_descr - bad block table descriptor
-+ * @options: options for this descriptor
-+ * @pages: the page(s) where we find the bbt, used with option BBT_ABSPAGE
-+ * when bbt is searched, then we store the found bbts pages here.
-+ * Its an array and supports up to 8 chips now
-+ * @offs: offset of the pattern in the oob area of the page
-+ * @veroffs: offset of the bbt version counter in the oob are of the page
-+ * @version: version read from the bbt page during scan
-+ * @len: length of the pattern, if 0 no pattern check is performed
-+ * @maxblocks: maximum number of blocks to search for a bbt. This number of
-+ * blocks is reserved at the end of the device where the tables are
-+ * written.
-+ * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than
-+ * bad) block in the stored bbt
-+ * @pattern: pattern to identify bad block table or factory marked good /
-+ * bad blocks, can be NULL, if len = 0
-+ *
-+ * Descriptor for the bad block table marker and the descriptor for the
-+ * pattern which identifies good and bad blocks. The assumption is made
-+ * that the pattern and the version count are always located in the oob area
-+ * of the first block.
-+ */
-+struct nand_bbt_descr {
-+ int options;
-+ int pages[NAND_MAX_CHIPS];
-+ int offs;
-+ int veroffs;
-+ uint8_t version[NAND_MAX_CHIPS];
-+ int len;
-+ int maxblocks;
-+ int reserved_block_code;
-+ uint8_t *pattern;
-+};
-
--#define NAND_NONE_OOB 0
--#define NAND_JFFS2_OOB 1
--#define NAND_YAFFS_OOB 2
-+/* Options for the bad block table descriptors */
-
--#define NAND_NOOB_ECCPOS0 0
--#define NAND_NOOB_ECCPOS1 1
--#define NAND_NOOB_ECCPOS2 2
--#define NAND_NOOB_ECCPOS3 3
--#define NAND_NOOB_ECCPOS4 6
--#define NAND_NOOB_ECCPOS5 7
-+/* The number of bits used per block in the bbt on the device */
-+#define NAND_BBT_NRBITS_MSK 0x0000000F
-+#define NAND_BBT_1BIT 0x00000001
-+#define NAND_BBT_2BIT 0x00000002
-+#define NAND_BBT_4BIT 0x00000004
-+#define NAND_BBT_8BIT 0x00000008
-+/* The bad block table is in the last good block of the device */
-+#define NAND_BBT_LASTBLOCK 0x00000010
-+/* The bbt is at the given page, else we must scan for the bbt */
-+#define NAND_BBT_ABSPAGE 0x00000020
-+/* The bbt is at the given page, else we must scan for the bbt */
-+#define NAND_BBT_SEARCH 0x00000040
-+/* bbt is stored per chip on multichip devices */
-+#define NAND_BBT_PERCHIP 0x00000080
-+/* bbt has a version counter at offset veroffs */
-+#define NAND_BBT_VERSION 0x00000100
-+/* Create a bbt if none axists */
-+#define NAND_BBT_CREATE 0x00000200
-+/* Search good / bad pattern through all pages of a block */
-+#define NAND_BBT_SCANALLPAGES 0x00000400
-+/* Scan block empty during good / bad block scan */
-+#define NAND_BBT_SCANEMPTY 0x00000800
-+/* Write bbt if neccecary */
-+#define NAND_BBT_WRITE 0x00001000
-+/* Read and write back block contents when writing bbt */
-+#define NAND_BBT_SAVECONTENT 0x00002000
-+/* Search good / bad pattern on the first and the second page */
-+#define NAND_BBT_SCAN2NDPAGE 0x00004000
-
--#define NAND_JFFS2_OOB_ECCPOS0 0
--#define NAND_JFFS2_OOB_ECCPOS1 1
--#define NAND_JFFS2_OOB_ECCPOS2 2
--#define NAND_JFFS2_OOB_ECCPOS3 3
--#define NAND_JFFS2_OOB_ECCPOS4 6
--#define NAND_JFFS2_OOB_ECCPOS5 7
-+/* The maximum number of blocks to scan for a bbt */
-+#define NAND_BBT_SCAN_MAXBLOCKS 4
-
--#define NAND_YAFFS_OOB_ECCPOS0 8
--#define NAND_YAFFS_OOB_ECCPOS1 9
--#define NAND_YAFFS_OOB_ECCPOS2 10
--#define NAND_YAFFS_OOB_ECCPOS3 13
--#define NAND_YAFFS_OOB_ECCPOS4 14
--#define NAND_YAFFS_OOB_ECCPOS5 15
-+extern int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd);
-+extern int nand_update_bbt (struct mtd_info *mtd, loff_t offs);
-+extern int nand_default_bbt (struct mtd_info *mtd);
-+extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt);
-+extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt);
-+extern int nand_do_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 flags);
-
--#define NAND_JFFS2_OOB8_FSDAPOS 6
--#define NAND_JFFS2_OOB16_FSDAPOS 8
--#define NAND_JFFS2_OOB8_FSDALEN 2
--#define NAND_JFFS2_OOB16_FSDALEN 8
-+/*
-+* Constants for oob configuration
-+*/
-+#define NAND_SMALL_BADBLOCK_POS 5
-+#define NAND_LARGE_BADBLOCK_POS 0
-
- #endif /* __LINUX_MTD_NAND_H */
---- linux-2.4.21/include/linux/mtd/nand_ecc.h~mtd-cvs
-+++ linux-2.4.21/include/linux/mtd/nand_ecc.h
-@@ -1,9 +1,9 @@
- /*
- * drivers/mtd/nand_ecc.h
- *
-- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
-+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
- *
-- * $Id: nand_ecc.h,v 1.1 2000/10/12 00:57:15 sjhill Exp $
-+ * $Id: nand_ecc.h,v 1.4 2004/06/17 02:35:02 dbrown 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
-@@ -12,17 +12,19 @@
- * This file is the header for the ECC algorithm.
- */
-
--/*
-- * Creates non-inverted ECC code from line parity
-- */
--void nand_trans_result(u_char reg2, u_char reg3, u_char *ecc_code);
-+#ifndef __MTD_NAND_ECC_H__
-+#define __MTD_NAND_ECC_H__
-+
-+struct mtd_info;
-
- /*
- * Calculate 3 byte ECC code for 256 byte block
- */
--void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
-+int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
-
- /*
- * Detect and correct a 1 bit error for 256 byte block
- */
--int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
-+int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
-+
-+#endif /* __MTD_NAND_ECC_H__ */
---- linux-2.4.21/include/linux/mtd/nftl.h~mtd-cvs
-+++ linux-2.4.21/include/linux/mtd/nftl.h
-@@ -1,81 +1,16 @@
--
--/* Defines for NAND Flash Translation Layer */
--/* (c) 1999 Machine Vision Holdings, Inc. */
--/* Author: David Woodhouse <dwmw2@mvhi.com> */
--/* $Id: nftl.h,v 1.11 2002/06/18 13:54:24 dwmw2 Exp $ */
-+/*
-+ * $Id: nftl.h,v 1.16 2004/06/30 14:49:00 dbrown Exp $
-+ *
-+ * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
-+ */
-
- #ifndef __MTD_NFTL_H__
- #define __MTD_NFTL_H__
-
--#ifndef __BOOT__
- #include <linux/mtd/mtd.h>
--#endif
--
--/* Block Control Information */
--
--struct nftl_bci {
-- unsigned char ECCSig[6];
-- __u8 Status;
-- __u8 Status1;
--}__attribute__((packed));
--
--/* Unit Control Information */
--
--struct nftl_uci0 {
-- __u16 VirtUnitNum;
-- __u16 ReplUnitNum;
-- __u16 SpareVirtUnitNum;
-- __u16 SpareReplUnitNum;
--} __attribute__((packed));
--
--struct nftl_uci1 {
-- __u32 WearInfo;
-- __u16 EraseMark;
-- __u16 EraseMark1;
--} __attribute__((packed));
--
--struct nftl_uci2 {
-- __u16 FoldMark;
-- __u16 FoldMark1;
-- __u32 unused;
--} __attribute__((packed));
--
--union nftl_uci {
-- struct nftl_uci0 a;
-- struct nftl_uci1 b;
-- struct nftl_uci2 c;
--};
--
--struct nftl_oob {
-- struct nftl_bci b;
-- union nftl_uci u;
--};
--
--/* NFTL Media Header */
--
--struct NFTLMediaHeader {
-- char DataOrgID[6];
-- __u16 NumEraseUnits;
-- __u16 FirstPhysicalEUN;
-- __u32 FormattedSize;
-- unsigned char UnitSizeFactor;
--} __attribute__((packed));
--
--#define MAX_ERASE_ZONES (8192 - 512)
--
--#define ERASE_MARK 0x3c69
--#define SECTOR_FREE 0xff
--#define SECTOR_USED 0x55
--#define SECTOR_IGNORE 0x11
--#define SECTOR_DELETED 0x00
--
--#define FOLD_MARK_IN_PROGRESS 0x5555
--
--#define ZONE_GOOD 0xff
--#define ZONE_BAD_ORIGINAL 0
--#define ZONE_BAD_MARKED 7
-+#include <linux/mtd/blktrans.h>
-
--#ifdef __KERNEL__
-+#include <mtd/nftl-user.h>
-
- /* these info are used in ReplUnitTable */
- #define BLOCK_NIL 0xffff /* last block of a chain */
-@@ -84,8 +19,7 @@
- #define BLOCK_RESERVED 0xfffc /* bios block or bad block */
-
- struct NFTLrecord {
-- struct mtd_info *mtd;
-- struct semaphore mutex;
-+ struct mtd_blktrans_dev mbd;
- __u16 MediaUnit, SpareMediaUnit;
- __u32 EraseSize;
- struct NFTLMediaHeader MediaHdr;
-@@ -97,13 +31,13 @@
- __u16 lastEUN; /* should be suppressed */
- __u16 numfreeEUNs;
- __u16 LastFreeEUN; /* To speed up finding a free EUN */
-- __u32 nr_sects;
- int head,sect,cyl;
- __u16 *EUNtable; /* [numvunits]: First EUN for each virtual unit */
- __u16 *ReplUnitTable; /* [numEUNs]: ReplUnitNumber for each */
- unsigned int nb_blocks; /* number of physical blocks */
- unsigned int nb_boot_blocks; /* number of blocks used by the bios */
- struct erase_info instr;
-+ struct nand_oobinfo oobinfo;
- };
-
- int NFTL_mount(struct NFTLrecord *s);
-@@ -114,9 +48,7 @@
- #endif
-
- #define MAX_NFTLS 16
--#define MAX_SECTORS_PER_UNIT 32
-+#define MAX_SECTORS_PER_UNIT 64
- #define NFTL_PARTN_BITS 4
-
--#endif /* __KERNEL__ */
--
- #endif /* __MTD_NFTL_H__ */
---- linux-2.4.21/include/linux/mtd/partitions.h~mtd-cvs
-+++ linux-2.4.21/include/linux/mtd/partitions.h
-@@ -5,7 +5,7 @@
- *
- * This code is GPL
- *
-- * $Id: partitions.h,v 1.8 2002/03/08 16:34:36 rkaiser Exp $
-+ * $Id: partitions.h,v 1.16 2004/11/16 18:34:40 dwmw2 Exp $
- */
-
- #ifndef MTD_PARTITIONS_H
-@@ -41,6 +41,7 @@
- u_int32_t size; /* partition size */
- u_int32_t offset; /* offset within the master MTD space */
- u_int32_t mask_flags; /* master MTD flags to mask out for this partition */
-+ struct nand_oobinfo *oobsel; /* out of band layout for this partition (NAND only)*/
- struct mtd_info **mtdp; /* pointer to store the MTD object */
- };
-
-@@ -49,8 +50,26 @@
- #define MTDPART_SIZ_FULL (0)
-
-
--int add_mtd_partitions(struct mtd_info *, struct mtd_partition *, int);
-+int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
- int del_mtd_partitions(struct mtd_info *);
-
-+/*
-+ * Functions dealing with the various ways of partitioning the space
-+ */
-+
-+struct mtd_part_parser {
-+ struct list_head list;
-+ struct module *owner;
-+ const char *name;
-+ int (*parse_fn)(struct mtd_info *, struct mtd_partition **, unsigned long);
-+};
-+
-+extern int register_mtd_parser(struct mtd_part_parser *parser);
-+extern int deregister_mtd_parser(struct mtd_part_parser *parser);
-+extern int parse_mtd_partitions(struct mtd_info *master, const char **types,
-+ struct mtd_partition **pparts, unsigned long origin);
-+
-+#define put_partition_parser(p) do { module_put((p)->owner); } while(0)
-+
- #endif
-
---- /dev/null
-+++ linux-2.4.21/include/linux/mtd/physmap.h
-@@ -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__ */
-+
---- /dev/null
-+++ linux-2.4.21/include/linux/mtd/plat-ram.h
-@@ -0,0 +1,35 @@
-+/* linux/include/mtd/plat-ram.h
-+ *
-+ * (c) 2004 Simtec Electronics
-+ * http://www.simtec.co.uk/products/SWLINUX/
-+ * Ben Dooks <ben@simtec.co.uk>
-+ *
-+ * Generic platform device based RAM map
-+ *
-+ * $Id: plat-ram.h,v 1.2 2005/01/24 00:37:40 bjd 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.
-+ *
-+ */
-+
-+#ifndef __LINUX_MTD_PLATRAM_H
-+#define __LINUX_MTD_PLATRAM_H __FILE__
-+
-+#define PLATRAM_RO (0)
-+#define PLATRAM_RW (1)
-+
-+struct platdata_mtd_ram {
-+ char *mapname;
-+ char **probes;
-+ struct mtd_partition *partitions;
-+ int nr_partitions;
-+ int bankwidth;
-+
-+ /* control callbacks */
-+
-+ void (*set_rw)(struct device *dev, int to);
-+};
-+
-+#endif /* __LINUX_MTD_PLATRAM_H */
---- /dev/null
-+++ linux-2.4.21/include/linux/mtd/xip.h
-@@ -0,0 +1,107 @@
-+/*
-+ * MTD primitives for XIP support
-+ *
-+ * Author: Nicolas Pitre
-+ * Created: Nov 2, 2004
-+ * Copyright: (C) 2004 MontaVista Software, Inc.
-+ *
-+ * This XIP support for MTD has been loosely inspired
-+ * by an earlier patch authored by David Woodhouse.
-+ *
-+ * 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.
-+ *
-+ * $Id: xip.h,v 1.2 2004/12/01 15:49:10 nico Exp $
-+ */
-+
-+#ifndef __LINUX_MTD_XIP_H__
-+#define __LINUX_MTD_XIP_H__
-+
-+#include <linux/config.h>
-+
-+#ifdef CONFIG_MTD_XIP
-+
-+/*
-+ * Function that are modifying the flash state away from array mode must
-+ * obviously not be running from flash. The __xipram is therefore marking
-+ * those functions so they get relocated to ram.
-+ */
-+#define __xipram __attribute__ ((__section__ (".data")))
-+
-+/*
-+ * We really don't want gcc to guess anything.
-+ * We absolutely _need_ proper inlining.
-+ */
-+#include <linux/compiler.h>
-+
-+/*
-+ * Each architecture has to provide the following macros. They must access
-+ * the hardware directly and not rely on any other (XIP) functions since they
-+ * won't be available when used (flash not in array mode).
-+ *
-+ * xip_irqpending()
-+ *
-+ * return non zero when any hardware interrupt is pending.
-+ *
-+ * xip_currtime()
-+ *
-+ * return a platform specific time reference to be used with
-+ * xip_elapsed_since().
-+ *
-+ * xip_elapsed_since(x)
-+ *
-+ * return in usecs the elapsed timebetween now and the reference x as
-+ * returned by xip_currtime().
-+ *
-+ * note 1: convertion to usec can be approximated, as long as the
-+ * returned value is <= the real elapsed time.
-+ * note 2: this should be able to cope with a few seconds without
-+ * overflowing.
-+ */
-+
-+#if defined(CONFIG_ARCH_SA1100) || defined(CONFIG_ARCH_PXA)
-+
-+#include <asm/hardware.h>
-+#ifdef CONFIG_ARCH_PXA
-+#include <asm/arch/pxa-regs.h>
-+#endif
-+
-+#define xip_irqpending() (ICIP & ICMR)
-+
-+/* we sample OSCR and convert desired delta to usec (1/4 ~= 1000000/3686400) */
-+#define xip_currtime() (OSCR)
-+#define xip_elapsed_since(x) (signed)((OSCR - (x)) / 4)
-+
-+#else
-+
-+#warning "missing IRQ and timer primitives for XIP MTD support"
-+#warning "some of the XIP MTD support code will be disabled"
-+#warning "your system will therefore be unresponsive when writing or erasing flash"
-+
-+#define xip_irqpending() (0)
-+#define xip_currtime() (0)
-+#define xip_elapsed_since(x) (0)
-+
-+#endif
-+
-+/*
-+ * xip_cpu_idle() is used when waiting for a delay equal or larger than
-+ * the system timer tick period. This should put the CPU into idle mode
-+ * to save power and to be woken up only when some interrupts are pending.
-+ * As above, this should not rely upon standard kernel code.
-+ */
-+
-+#if defined(CONFIG_CPU_XSCALE)
-+#define xip_cpu_idle() asm volatile ("mcr p14, 0, %0, c7, c0, 0" :: "r" (1))
-+#else
-+#define xip_cpu_idle() do { } while (0)
-+#endif
-+
-+#else
-+
-+#define __xipram
-+
-+#endif /* CONFIG_MTD_XIP */
-+
-+#endif /* __LINUX_MTD_XIP_H__ */
---- linux-2.4.21/include/linux/net.h~bluetooth
-+++ linux-2.4.21/include/linux/net.h
-@@ -139,6 +139,7 @@
- extern int sock_recvmsg(struct socket *, struct msghdr *m, int len, int flags);
- extern int sock_readv_writev(int type, struct inode * inode, struct file * file,
- const struct iovec * iov, long count, long size);
-+extern struct socket *sockfd_lookup(int fd, int *err);
-
- extern int net_ratelimit(void);
- extern unsigned long net_random(void);
---- /dev/null
-+++ linux-2.4.21/include/linux/pm-devices.h
-@@ -0,0 +1,41 @@
-+#ifndef _LINUX_PM_DEV_H
-+#define _LINUX_PM_DEV_H
-+
-+/*
-+ * Copyright 2002 Montavista Software (mlocke@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, 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.
-+ */
-+
-+
-+
-+/*
-+ * Device types
-+ */
-+enum
-+{
-+ PM_UNKNOWN_DEV = 0, /* generic */
-+ PM_SYS_DEV, /* system device (fan, KB controller, ...) */
-+ PM_PCI_DEV, /* PCI device */
-+ PM_USB_DEV, /* USB device */
-+ PM_SCSI_DEV, /* SCSI device */
-+ PM_ISA_DEV, /* ISA device */
-+ PM_MTD_DEV, /* Memory Technology Device */
-+ PM_TPANEL_DEV, /* Memory Technology Device */
-+ PM_STORAGE_DEV, /* Memory Technology Device */
-+ PM_NETWORK_DEV, /* Memory Technology Device */
-+ PM_PCMCIA_DEV, /* Memory Technology Device */
-+ PM_DISPLAY_DEV, /* Memory Technology Device */
-+ PM_SERIAL_DEV, /* Memory Technology Device */
-+ PM_BATTERY_DEV, /* Memory Technology Device */
-+};
-+
-+#endif
---- linux-2.4.21/include/linux/pm.h~pm
-+++ linux-2.4.21/include/linux/pm.h
-@@ -24,6 +24,7 @@
- #ifdef __KERNEL__
-
- #include <linux/config.h>
-+#include <linux/pm-devices.h>
- #include <linux/list.h>
-
- /*
-@@ -50,20 +51,6 @@
-
- typedef int pm_request_t;
-
--/*
-- * Device types
-- */
--enum
--{
-- PM_UNKNOWN_DEV = 0, /* generic */
-- PM_SYS_DEV, /* system device (fan, KB controller, ...) */
-- PM_PCI_DEV, /* PCI device */
-- PM_USB_DEV, /* USB device */
-- PM_SCSI_DEV, /* SCSI device */
-- PM_ISA_DEV, /* ISA device */
-- PM_MTD_DEV, /* Memory Technology Device */
--};
--
- typedef int pm_dev_t;
-
- /*
---- /dev/null
-+++ linux-2.4.21/include/linux/rbtree-24.h
-@@ -0,0 +1,133 @@
-+/*
-+ Red Black Trees
-+ (C) 1999 Andrea Arcangeli <andrea@suse.de>
-+
-+ This program is free software; 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
-+
-+ linux/include/linux/rbtree.h
-+
-+ To use rbtrees you'll have to implement your own insert and search cores.
-+ This will avoid us to use callbacks and to drop drammatically performances.
-+ I know it's not the cleaner way, but in C (not in C++) to get
-+ performances and genericity...
-+
-+ Some example of insert and search follows here. The search is a plain
-+ normal search over an ordered tree. The insert instead must be implemented
-+ int two steps: as first thing the code must insert the element in
-+ order as a red leaf in the tree, then the support library function
-+ rb_insert_color() must be called. Such function will do the
-+ not trivial work to rebalance the rbtree if necessary.
-+
-+-----------------------------------------------------------------------
-+static inline struct page * rb_search_page_cache(struct inode * inode,
-+ unsigned long offset)
-+{
-+ rb_node_t * n = inode->i_rb_page_cache.rb_node;
-+ struct page * page;
-+
-+ while (n)
-+ {
-+ page = rb_entry(n, struct page, rb_page_cache);
-+
-+ if (offset < page->offset)
-+ n = n->rb_left;
-+ else if (offset > page->offset)
-+ n = n->rb_right;
-+ else
-+ return page;
-+ }
-+ return NULL;
-+}
-+
-+static inline struct page * __rb_insert_page_cache(struct inode * inode,
-+ unsigned long offset,
-+ rb_node_t * node)
-+{
-+ rb_node_t ** p = &inode->i_rb_page_cache.rb_node;
-+ rb_node_t * parent = NULL;
-+ struct page * page;
-+
-+ while (*p)
-+ {
-+ parent = *p;
-+ page = rb_entry(parent, struct page, rb_page_cache);
-+
-+ if (offset < page->offset)
-+ p = &(*p)->rb_left;
-+ else if (offset > page->offset)
-+ p = &(*p)->rb_right;
-+ else
-+ return page;
-+ }
-+
-+ rb_link_node(node, parent, p);
-+
-+ return NULL;
-+}
-+
-+static inline struct page * rb_insert_page_cache(struct inode * inode,
-+ unsigned long offset,
-+ rb_node_t * node)
-+{
-+ struct page * ret;
-+ if ((ret = __rb_insert_page_cache(inode, offset, node)))
-+ goto out;
-+ rb_insert_color(node, &inode->i_rb_page_cache);
-+ out:
-+ return ret;
-+}
-+-----------------------------------------------------------------------
-+*/
-+
-+#ifndef _LINUX_RBTREE_H
-+#define _LINUX_RBTREE_H
-+
-+#include <linux/kernel.h>
-+#include <linux/stddef.h>
-+
-+typedef struct rb_node_s
-+{
-+ struct rb_node_s * rb_parent;
-+ int rb_color;
-+#define RB_RED 0
-+#define RB_BLACK 1
-+ struct rb_node_s * rb_right;
-+ struct rb_node_s * rb_left;
-+}
-+rb_node_t;
-+
-+typedef struct rb_root_s
-+{
-+ struct rb_node_s * rb_node;
-+}
-+rb_root_t;
-+
-+#define RB_ROOT (rb_root_t) { NULL, }
-+#define rb_entry(ptr, type, member) \
-+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
-+
-+extern void rb_insert_color(rb_node_t *, rb_root_t *);
-+extern void rb_erase(rb_node_t *, rb_root_t *);
-+
-+static inline void rb_link_node(rb_node_t * node, rb_node_t * parent, rb_node_t ** rb_link)
-+{
-+ node->rb_parent = parent;
-+ node->rb_color = RB_RED;
-+ node->rb_left = node->rb_right = NULL;
-+
-+ *rb_link = node;
-+}
-+
-+#endif /* _LINUX_RBTREE_H */
---- linux-2.4.21/include/linux/rbtree.h~mtd-cvs
-+++ linux-2.4.21/include/linux/rbtree.h
-@@ -1,133 +1,25 @@
- /*
-- Red Black Trees
-- (C) 1999 Andrea Arcangeli <andrea@suse.de>
--
-- This program is free software; 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
--
-- linux/include/linux/rbtree.h
--
-- To use rbtrees you'll have to implement your own insert and search cores.
-- This will avoid us to use callbacks and to drop drammatically performances.
-- I know it's not the cleaner way, but in C (not in C++) to get
-- performances and genericity...
--
-- Some example of insert and search follows here. The search is a plain
-- normal search over an ordered tree. The insert instead must be implemented
-- int two steps: as first thing the code must insert the element in
-- order as a red leaf in the tree, then the support library function
-- rb_insert_color() must be called. Such function will do the
-- not trivial work to rebalance the rbtree if necessary.
--
-------------------------------------------------------------------------
--static inline struct page * rb_search_page_cache(struct inode * inode,
-- unsigned long offset)
--{
-- rb_node_t * n = inode->i_rb_page_cache.rb_node;
-- struct page * page;
--
-- while (n)
-- {
-- page = rb_entry(n, struct page, rb_page_cache);
--
-- if (offset < page->offset)
-- n = n->rb_left;
-- else if (offset > page->offset)
-- n = n->rb_right;
-- else
-- return page;
-- }
-- return NULL;
--}
--
--static inline struct page * __rb_insert_page_cache(struct inode * inode,
-- unsigned long offset,
-- rb_node_t * node)
--{
-- rb_node_t ** p = &inode->i_rb_page_cache.rb_node;
-- rb_node_t * parent = NULL;
-- struct page * page;
--
-- while (*p)
-- {
-- parent = *p;
-- page = rb_entry(parent, struct page, rb_page_cache);
--
-- if (offset < page->offset)
-- p = &(*p)->rb_left;
-- else if (offset > page->offset)
-- p = &(*p)->rb_right;
-- else
-- return page;
-- }
--
-- rb_link_node(node, parent, p);
--
-- return NULL;
--}
--
--static inline struct page * rb_insert_page_cache(struct inode * inode,
-- unsigned long offset,
-- rb_node_t * node)
--{
-- struct page * ret;
-- if ((ret = __rb_insert_page_cache(inode, offset, node)))
-- goto out;
-- rb_insert_color(node, &inode->i_rb_page_cache);
-- out:
-- return ret;
--}
-------------------------------------------------------------------------
--*/
--
--#ifndef _LINUX_RBTREE_H
--#define _LINUX_RBTREE_H
--
--#include <linux/kernel.h>
--#include <linux/stddef.h>
--
--typedef struct rb_node_s
--{
-- struct rb_node_s * rb_parent;
-- int rb_color;
--#define RB_RED 0
--#define RB_BLACK 1
-- struct rb_node_s * rb_right;
-- struct rb_node_s * rb_left;
--}
--rb_node_t;
-+ * 2.5 compatibility
-+ * $Id: rbtree.h,v 1.3 2003/01/14 13:56:05 dwmw2 Exp $
-+ */
-
--typedef struct rb_root_s
--{
-- struct rb_node_s * rb_node;
--}
--rb_root_t;
-+#ifndef __MTD_COMPAT_RBTREE_H__
-+#define __MTD_COMPAT_RBTREE_H__
-
--#define RB_ROOT (rb_root_t) { NULL, }
--#define rb_entry(ptr, type, member) \
-- ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
-+#include <linux/version.h>
-
--extern void rb_insert_color(rb_node_t *, rb_root_t *);
--extern void rb_erase(rb_node_t *, rb_root_t *);
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40)
-+#include_next <linux/rbtree.h>
-+#else
-+#define rb_node_s rb_node
-+#define rb_root_s rb_root
-
--static inline void rb_link_node(rb_node_t * node, rb_node_t * parent, rb_node_t ** rb_link)
--{
-- node->rb_parent = parent;
-- node->rb_color = RB_RED;
-- node->rb_left = node->rb_right = NULL;
-+#include <linux/rbtree-24.h>
-
-- *rb_link = node;
--}
-+/* Find logical next and previous nodes in a tree */
-+extern struct rb_node *rb_next(struct rb_node *);
-+extern struct rb_node *rb_prev(struct rb_node *);
-+extern struct rb_node *rb_first(struct rb_root *);
-+#endif
-
--#endif /* _LINUX_RBTREE_H */
-+#endif /* __MTD_COMPAT_RBTREE_H__ */
---- /dev/null
-+++ linux-2.4.21/include/linux/rslib.h
-@@ -0,0 +1,105 @@
-+/*
-+ * include/linux/rslib.h
-+ *
-+ * Overview:
-+ * Generic Reed Solomon encoder / decoder library
-+ *
-+ * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
-+ *
-+ * RS code lifted from reed solomon library written by Phil Karn
-+ * Copyright 2002 Phil Karn, KA9Q
-+ *
-+ * $Id: rslib.h,v 1.3 2004/10/05 22:08:22 gleixner 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.
-+ */
-+
-+#ifndef _RSLIB_H_
-+#define _RSLIB_H_
-+
-+#include <linux/list.h>
-+
-+/**
-+ * struct rs_control - rs control structure
-+ *
-+ * @mm: Bits per symbol
-+ * @nn: Symbols per block (= (1<<mm)-1)
-+ * @alpha_to: log lookup table
-+ * @index_of: Antilog lookup table
-+ * @genpoly: Generator polynomial
-+ * @nroots: Number of generator roots = number of parity symbols
-+ * @fcr: First consecutive root, index form
-+ * @prim: Primitive element, index form
-+ * @iprim: prim-th root of 1, index form
-+ * @gfpoly: The primitive generator polynominal
-+ * @users: Users of this structure
-+ * @list: List entry for the rs control list
-+*/
-+struct rs_control {
-+ int mm;
-+ int nn;
-+ uint16_t *alpha_to;
-+ uint16_t *index_of;
-+ uint16_t *genpoly;
-+ int nroots;
-+ int fcr;
-+ int prim;
-+ int iprim;
-+ int gfpoly;
-+ int users;
-+ struct list_head list;
-+};
-+
-+/* General purpose RS codec, 8-bit data width, symbol width 1-15 bit */
-+#ifdef CONFIG_REED_SOLOMON_ENC8
-+int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par,
-+ uint16_t invmsk);
-+#endif
-+#ifdef CONFIG_REED_SOLOMON_DEC8
-+int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len,
-+ uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
-+ uint16_t *corr);
-+#endif
-+
-+/* General purpose RS codec, 16-bit data width, symbol width 1-15 bit */
-+#ifdef CONFIG_REED_SOLOMON_ENC16
-+int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par,
-+ uint16_t invmsk);
-+#endif
-+#ifdef CONFIG_REED_SOLOMON_DEC16
-+int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len,
-+ uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
-+ uint16_t *corr);
-+#endif
-+
-+/* Create or get a matching rs control structure */
-+struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
-+ int nroots);
-+
-+/* Release a rs control structure */
-+void free_rs(struct rs_control *rs);
-+
-+/** modulo replacement for galois field arithmetics
-+ *
-+ * @rs: the rs control structure
-+ * @x: the value to reduce
-+ *
-+ * where
-+ * rs->mm = number of bits per symbol
-+ * rs->nn = (2^rs->mm) - 1
-+ *
-+ * Simple arithmetic modulo would return a wrong result for values
-+ * >= 3 * rs->nn
-+*/
-+static inline int rs_modnn(struct rs_control *rs, int x)
-+{
-+ while (x >= rs->nn) {
-+ x -= rs->nn;
-+ x = (x >> rs->mm) + (x & rs->nn);
-+ }
-+ return x;
-+}
-+
-+#endif
---- linux-2.4.21/include/linux/soundcard.h~ucb1x00
-+++ linux-2.4.21/include/linux/soundcard.h
-@@ -811,6 +811,7 @@
- #define SOUND_MIXER_STEREODEVS 0xfb /* Mixer channels supporting stereo */
- #define SOUND_MIXER_OUTSRC 0xfa /* Arg contains a bit for each input source to output */
- #define SOUND_MIXER_OUTMASK 0xf9 /* Arg contains a bit for each supported input source to output */
-+#define SOUND_MIXER_AC97 0xf8 /* directly access ac97 registers */
-
- /* Device mask bits */
-
-@@ -874,6 +875,7 @@
- #define SOUND_MIXER_READ_RECMASK MIXER_READ(SOUND_MIXER_RECMASK)
- #define SOUND_MIXER_READ_STEREODEVS MIXER_READ(SOUND_MIXER_STEREODEVS)
- #define SOUND_MIXER_READ_CAPS MIXER_READ(SOUND_MIXER_CAPS)
-+#define SOUND_MIXER_READ_AC97 MIXER_READ(SOUND_MIXER_AC97)
-
- #define MIXER_WRITE(dev) _SIOWR('M', dev, int)
- #define SOUND_MIXER_WRITE_VOLUME MIXER_WRITE(SOUND_MIXER_VOLUME)
-@@ -900,6 +902,7 @@
- #define SOUND_MIXER_WRITE_LOUD MIXER_WRITE(SOUND_MIXER_LOUD)
-
- #define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC)
-+#define SOUND_MIXER_WRITE_AC97 MIXER_WRITE(SOUND_MIXER_AC97)
-
- typedef struct mixer_info
- {
---- /dev/null
-+++ linux-2.4.21/include/linux/suspend.h
-@@ -0,0 +1,10 @@
-+/* $Id: suspend.h,v 1.1 2003/10/13 20:56:47 dwmw2 Exp $ */
-+
-+#ifndef __MTD_COMPAT_VERSION_H__
-+#include <linux/version.h>
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-+#include_next <linux/suspend.h>
-+#endif
-+
-+#endif /* __MTD_COMPAT_VERSION_H__ */
---- linux-2.4.21/include/linux/tty.h~ramses-lcd
-+++ linux-2.4.21/include/linux/tty.h
-@@ -10,8 +10,8 @@
- * resizing).
- */
- #define MIN_NR_CONSOLES 1 /* must be at least 1 */
--#define MAX_NR_CONSOLES 63 /* serial lines start at 64 */
--#define MAX_NR_USER_CONSOLES 63 /* must be root to allocate above this */
-+#define MAX_NR_CONSOLES 3 /* serial lines start at 64 */
-+#define MAX_NR_USER_CONSOLES 3 /* must be root to allocate above this */
- /* Note: the ioctl VT_GETSTATE does not work for
- consoles 16 and higher (since it returns a short) */
-
---- /dev/null
-+++ linux-2.4.21/include/linux/uinput.h
-@@ -0,0 +1,79 @@
-+/*
-+ * User level driver support for input subsystem
-+ *
-+ * Heavily based on evdev.c by Vojtech Pavlik
-+ *
-+ * This program is free software; 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: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
-+ *
-+ * Changes/Revisions:
-+ * 0.1 20/06/2002
-+ * - first public version
-+ */
-+
-+#ifndef __UINPUT_H_
-+#define __UINPUT_H_
-+
-+#ifdef __KERNEL__
-+#define UINPUT_MINOR 223
-+#define UINPUT_NAME "uinput"
-+#define UINPUT_BUFFER_SIZE 16
-+
-+/* state flags => bit index for {set|clear|test}_bit ops */
-+#define UIST_CREATED 0
-+
-+struct uinput_device {
-+ struct input_dev *dev;
-+ unsigned long state;
-+ wait_queue_head_t waitq;
-+ unsigned char ready,
-+ head,
-+ tail;
-+ struct input_event buff[UINPUT_BUFFER_SIZE];
-+};
-+#endif /* __KERNEL__ */
-+
-+/* ioctl */
-+#define UINPUT_IOCTL_BASE 'U'
-+#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
-+#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2)
-+#define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int)
-+#define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int)
-+#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int)
-+#define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int)
-+#define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int)
-+#define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int)
-+#define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int)
-+#define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int)
-+
-+#ifndef NBITS
-+#define NBITS(x) ((((x)-1)/(sizeof(long)*8))+1)
-+#endif /* NBITS */
-+
-+#define UINPUT_MAX_NAME_SIZE 80
-+struct uinput_user_dev {
-+ char name[UINPUT_MAX_NAME_SIZE];
-+ unsigned short idbus;
-+ unsigned short idvendor;
-+ unsigned short idproduct;
-+ unsigned short idversion;
-+ int ff_effects_max;
-+ int absmax[ABS_MAX + 1];
-+ int absmin[ABS_MAX + 1];
-+ int absfuzz[ABS_MAX + 1];
-+ int absflat[ABS_MAX + 1];
-+};
-+#endif /* __UINPUT_H_ */
---- linux-2.4.21/include/linux/usb.h~ramses-usb
-+++ linux-2.4.21/include/linux/usb.h
-@@ -1079,7 +1079,7 @@
- void usb_show_string(struct usb_device *dev, char *id, int index);
-
- #ifdef DEBUG
--#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)
-+#define dbg(format, arg...) printk(__FILE__ ": " format "\n" , ## arg)
- #else
- #define dbg(format, arg...) do {} while (0)
- #endif
---- linux-2.4.21/include/linux/wireless.h~linux-iw241_we16-6
-+++ linux-2.4.21/include/linux/wireless.h
-@@ -1,7 +1,7 @@
- /*
- * This file define a set of standard wireless extensions
- *
-- * Version : 15 12.7.02
-+ * Version : 16 2.4.03
- *
- * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
-@@ -69,6 +69,8 @@
-
- /***************************** INCLUDES *****************************/
-
-+/* To minimise problems in user space, I might remove those headers
-+ * at some point. Jean II */
- #include <linux/types.h> /* for "caddr_t" et al */
- #include <linux/socket.h> /* for "struct sockaddr" et al */
- #include <linux/if.h> /* for IFNAMSIZ and co... */
-@@ -80,7 +82,7 @@
- * (there is some stuff that will be added in the future...)
- * I just plan to increment with each new version.
- */
--#define WIRELESS_EXT 15
-+#define WIRELESS_EXT 16
-
- /*
- * Changes :
-@@ -163,6 +165,16 @@
- * - Add IW_TXPOW_RANGE for range of Tx Powers
- * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
- * - Add IW_MODE_MONITOR for passive monitor
-+ *
-+ * V15 to V16
-+ * ----------
-+ * - Increase the number of bitrates in iw_range to 32 (for 802.11g)
-+ * - Increase the number of frequencies in iw_range to 32 (for 802.11b+a)
-+ * - Reshuffle struct iw_range for increases, add filler
-+ * - Increase IW_MAX_AP to 64 for driver returning a lot of addresses
-+ * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support
-+ * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy"
-+ * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index
- */
-
- /**************************** CONSTANTS ****************************/
-@@ -196,9 +208,11 @@
- /* SIOCGIWSTATS is strictly used between user space and the kernel, and
- * is never passed to the driver (i.e. the driver will never see it). */
-
--/* Mobile IP support (statistics per MAC address) */
-+/* Spy support (statistics per MAC address - used for Mobile IP support) */
- #define SIOCSIWSPY 0x8B10 /* set spy addresses */
- #define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */
-+#define SIOCSIWTHRSPY 0x8B12 /* set spy threshold (spy event) */
-+#define SIOCGIWTHRSPY 0x8B13 /* get spy threshold */
-
- /* Access Point manipulation */
- #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */
-@@ -294,7 +308,7 @@
- #define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */
- #define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */
-
--#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed nuber of args */
-+#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed number of args */
-
- #define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */
-
-@@ -306,13 +320,13 @@
- /* ----------------------- OTHER CONSTANTS ----------------------- */
-
- /* Maximum frequencies in the range struct */
--#define IW_MAX_FREQUENCIES 16
-+#define IW_MAX_FREQUENCIES 32
- /* Note : if you have something like 80 frequencies,
- * don't increase this constant and don't fill the frequency list.
- * The user will be able to set by channel anyway... */
-
- /* Maximum bit rates in the range struct */
--#define IW_MAX_BITRATES 8
-+#define IW_MAX_BITRATES 32
-
- /* Maximum tx powers in the range struct */
- #define IW_MAX_TXPOWER 8
-@@ -320,8 +334,7 @@
- * a few of them in the struct iw_range. */
-
- /* Maximum of address that you may set with SPY */
--#define IW_MAX_SPY 8 /* set */
--#define IW_MAX_GET_SPY 64 /* get */
-+#define IW_MAX_SPY 8
-
- /* Maximum of address that you may get in the
- list of access points in range */
-@@ -354,7 +367,8 @@
- #define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */
- #define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */
- #define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */
--#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */
-+#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */
-+#define IW_ENCODE_TEMP 0x0400 /* Temporary key */
-
- /* Power management flags available (along with the value, if any) */
- #define IW_POWER_ON 0x0000 /* No details... */
-@@ -482,6 +496,17 @@
- __u32 beacon; /* Missed beacons/superframe */
- };
-
-+/*
-+ * Quality range (for spy threshold)
-+ */
-+struct iw_thrspy
-+{
-+ struct sockaddr addr; /* Source address (hw/mac) */
-+ struct iw_quality qual; /* Quality of the link */
-+ struct iw_quality low; /* Low threshold */
-+ struct iw_quality high; /* High threshold */
-+};
-+
- /* ------------------------ WIRELESS STATS ------------------------ */
- /*
- * Wireless statistics (used for /proc/net/wireless)
-@@ -534,7 +559,7 @@
- struct iw_quality qual; /* Quality part of statistics */
-
- struct sockaddr ap_addr; /* Access point address */
-- struct sockaddr addr; /* Destination address (hw) */
-+ struct sockaddr addr; /* Destination address (hw/mac) */
-
- struct iw_param param; /* Other small parameters */
- struct iw_point data; /* Other large parameters */
-@@ -582,17 +607,31 @@
- __u32 min_nwid; /* Minimal NWID we are able to set */
- __u32 max_nwid; /* Maximal NWID we are able to set */
-
-- /* Frequency */
-- __u16 num_channels; /* Number of channels [0; num - 1] */
-- __u8 num_frequency; /* Number of entry in the list */
-- struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */
-- /* Note : this frequency list doesn't need to fit channel numbers */
-+ /* Old Frequency (backward compat - moved lower ) */
-+ __u16 old_num_channels;
-+ __u8 old_num_frequency;
-+ /* Filler to keep "version" at the same offset */
-+ __s32 old_freq[6];
-
- /* signal level threshold range */
- __s32 sensitivity;
-
- /* Quality of link & SNR stuff */
-+ /* Quality range (link, level, noise)
-+ * If the quality is absolute, it will be in the range [0 ; max_qual],
-+ * if the quality is dBm, it will be in the range [max_qual ; 0].
-+ * Don't forget that we use 8 bit arithmetics... */
- struct iw_quality max_qual; /* Quality of the link */
-+ /* This should contain the average/typical values of the quality
-+ * indicator. This should be the threshold between a "good" and
-+ * a "bad" link (example : monitor going from green to orange).
-+ * Currently, user space apps like quality monitors don't have any
-+ * way to calibrate the measurement. With this, they can split
-+ * the range between 0 and max_qual in different quality level
-+ * (using a geometric subdivision centered on the average).
-+ * I expect that people doing the user space apps will feedback
-+ * us on which value we need to put in each driver... */
-+ struct iw_quality avg_qual; /* Quality of the link */
-
- /* Rates */
- __u8 num_bitrates; /* Number of entries in the list */
-@@ -619,6 +658,8 @@
- __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */
- __u8 num_encoding_sizes; /* Number of entry in the list */
- __u8 max_encoding_tokens; /* Max number of tokens */
-+ /* For drivers that need a "login/passwd" form */
-+ __u8 encoding_login_index; /* token index for login token */
-
- /* Transmit power */
- __u16 txpower_capa; /* What options are supported */
-@@ -638,18 +679,12 @@
- __s32 min_r_time; /* Minimal retry lifetime */
- __s32 max_r_time; /* Maximal retry lifetime */
-
-- /* Average quality of link & SNR */
-- struct iw_quality avg_qual; /* Quality of the link */
-- /* This should contain the average/typical values of the quality
-- * indicator. This should be the threshold between a "good" and
-- * a "bad" link (example : monitor going from green to orange).
-- * Currently, user space apps like quality monitors don't have any
-- * way to calibrate the measurement. With this, they can split
-- * the range between 0 and max_qual in different quality level
-- * (using a geometric subdivision centered on the average).
-- * I expect that people doing the user space apps will feedback
-- * us on which value we need to put in each driver...
-- */
-+ /* Frequency */
-+ __u16 num_channels; /* Number of channels [0; num - 1] */
-+ __u8 num_frequency; /* Number of entry in the list */
-+ struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */
-+ /* Note : this frequency list doesn't need to fit channel numbers,
-+ * because each entry contain its channel index */
- };
-
- /*
---- /dev/null
-+++ linux-2.4.21/include/linux/workqueue.h
-@@ -0,0 +1,21 @@
-+/*
-+ * 2.5 compatibility
-+ * $Id: workqueue.h,v 1.1 2002/11/11 16:39:10 dwmw2 Exp $
-+ */
-+
-+#ifndef __MTD_COMPAT_WORKQUEUE_H__
-+#define __MTD_COMPAT_WORKQUEUE_H__
-+
-+#include <linux/version.h>
-+
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,40)
-+#include_next <linux/workqueue.h>
-+#else
-+#include <linux/tqueue.h>
-+#define work_struct tq_struct
-+#define schedule_work(x) schedule_task(x)
-+#define flush_scheduled_work flush_scheduled_tasks
-+#define INIT_WORK(x,y,z) INIT_TQUEUE(x,y,z)
-+#endif
-+
-+#endif /* __MTD_COMPAT_WORKQUEUE_H__ */
---- /dev/null
-+++ linux-2.4.21/include/mtd/inftl-user.h
-@@ -0,0 +1,91 @@
-+/*
-+ * $Id: inftl-user.h,v 1.1 2004/05/05 15:17:00 dwmw2 Exp $
-+ *
-+ * Parts of INFTL headers shared with userspace
-+ *
-+ */
-+
-+#ifndef __MTD_INFTL_USER_H__
-+#define __MTD_INFTL_USER_H__
-+
-+#define OSAK_VERSION 0x5120
-+#define PERCENTUSED 98
-+
-+#define SECTORSIZE 512
-+
-+/* Block Control Information */
-+
-+struct inftl_bci {
-+ uint8_t ECCsig[6];
-+ uint8_t Status;
-+ uint8_t Status1;
-+} __attribute__((packed));
-+
-+struct inftl_unithead1 {
-+ uint16_t virtualUnitNo;
-+ uint16_t prevUnitNo;
-+ uint8_t ANAC;
-+ uint8_t NACs;
-+ uint8_t parityPerField;
-+ uint8_t discarded;
-+} __attribute__((packed));
-+
-+struct inftl_unithead2 {
-+ uint8_t parityPerField;
-+ uint8_t ANAC;
-+ uint16_t prevUnitNo;
-+ uint16_t virtualUnitNo;
-+ uint8_t NACs;
-+ uint8_t discarded;
-+} __attribute__((packed));
-+
-+struct inftl_unittail {
-+ uint8_t Reserved[4];
-+ uint16_t EraseMark;
-+ uint16_t EraseMark1;
-+} __attribute__((packed));
-+
-+union inftl_uci {
-+ struct inftl_unithead1 a;
-+ struct inftl_unithead2 b;
-+ struct inftl_unittail c;
-+};
-+
-+struct inftl_oob {
-+ struct inftl_bci b;
-+ union inftl_uci u;
-+};
-+
-+
-+/* INFTL Media Header */
-+
-+struct INFTLPartition {
-+ __u32 virtualUnits;
-+ __u32 firstUnit;
-+ __u32 lastUnit;
-+ __u32 flags;
-+ __u32 spareUnits;
-+ __u32 Reserved0;
-+ __u32 Reserved1;
-+} __attribute__((packed));
-+
-+struct INFTLMediaHeader {
-+ char bootRecordID[8];
-+ __u32 NoOfBootImageBlocks;
-+ __u32 NoOfBinaryPartitions;
-+ __u32 NoOfBDTLPartitions;
-+ __u32 BlockMultiplierBits;
-+ __u32 FormatFlags;
-+ __u32 OsakVersion;
-+ __u32 PercentUsed;
-+ struct INFTLPartition Partitions[4];
-+} __attribute__((packed));
-+
-+/* Partition flag types */
-+#define INFTL_BINARY 0x20000000
-+#define INFTL_BDTL 0x40000000
-+#define INFTL_LAST 0x80000000
-+
-+#endif /* __MTD_INFTL_USER_H__ */
-+
-+
---- /dev/null
-+++ linux-2.4.21/include/mtd/jffs2-user.h
-@@ -0,0 +1,35 @@
-+/*
-+ * $Id: jffs2-user.h,v 1.1 2004/05/05 11:57:54 dwmw2 Exp $
-+ *
-+ * JFFS2 definitions for use in user space only
-+ */
-+
-+#ifndef __JFFS2_USER_H__
-+#define __JFFS2_USER_H__
-+
-+/* This file is blessed for inclusion by userspace */
-+#include <linux/jffs2.h>
-+#include <endian.h>
-+#include <byteswap.h>
-+
-+#undef cpu_to_je16
-+#undef cpu_to_je32
-+#undef cpu_to_jemode
-+#undef je16_to_cpu
-+#undef je32_to_cpu
-+#undef jemode_to_cpu
-+
-+extern int target_endian;
-+
-+#define t16(x) ({ uint16_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); })
-+#define t32(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); })
-+
-+#define cpu_to_je16(x) ((jint16_t){t16(x)})
-+#define cpu_to_je32(x) ((jint32_t){t32(x)})
-+#define cpu_to_jemode(x) ((jmode_t){t32(x)})
-+
-+#define je16_to_cpu(x) (t16((x).v16))
-+#define je32_to_cpu(x) (t32((x).v32))
-+#define jemode_to_cpu(x) (t32((x).m))
-+
-+#endif /* __JFFS2_USER_H__ */
---- /dev/null
-+++ linux-2.4.21/include/mtd/mtd-abi.h
-@@ -0,0 +1,119 @@
-+/*
-+ * $Id: mtd-abi.h,v 1.10 2005/02/09 09:17:42 pavlov Exp $
-+ *
-+ * Portions of MTD ABI definition which are shared by kernel and user space
-+ */
-+
-+#ifndef __MTD_ABI_H__
-+#define __MTD_ABI_H__
-+
-+#ifndef __KERNEL__ /* Urgh. The whole point of splitting this out into
-+ separate files was to avoid #ifdef __KERNEL__ */
-+#define __user
-+#endif
-+
-+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_DATAFLASH 6
-+#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
-+#define MTD_NO_VIRTBLOCKS 256 // Virtual blocks not allowed
-+
-+// 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)
-+
-+/* OTP mode selection */
-+#define MTD_OTP_OFF 0
-+#define MTD_OTP_FACTORY 1
-+#define MTD_OTP_USER 2
-+
-+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;
-+};
-+
-+struct otp_info {
-+ uint32_t start;
-+ uint32_t length;
-+ uint32_t locked;
-+};
-+
-+#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)
-+#define OTPSELECT _IOR('M', 13, int)
-+#define OTPGETREGIONCOUNT _IOW('M', 14, int)
-+#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info)
-+#define OTPLOCK _IOR('M', 16, struct otp_info)
-+
-+struct nand_oobinfo {
-+ uint32_t useecc;
-+ uint32_t eccbytes;
-+ uint32_t oobfree[8][2];
-+ uint32_t eccpos[32];
-+};
-+
-+#endif /* __MTD_ABI_H__ */
---- /dev/null
-+++ linux-2.4.21/include/mtd/mtd-user.h
-@@ -0,0 +1,20 @@
-+/*
-+ * $Id: mtd-user.h,v 1.2 2004/05/05 14:44:57 dwmw2 Exp $
-+ *
-+ * MTD ABI header for use by user space only.
-+ */
-+
-+#ifndef __MTD_USER_H__
-+#define __MTD_USER_H__
-+
-+#include <stdint.h>
-+
-+/* This file is blessed for inclusion by userspace */
-+#include <mtd/mtd-abi.h>
-+
-+typedef struct mtd_info_user mtd_info_t;
-+typedef struct erase_info_user erase_info_t;
-+typedef struct region_info_user region_info_t;
-+typedef struct nand_oobinfo nand_oobinfo_t;
-+
-+#endif /* __MTD_USER_H__ */
---- /dev/null
-+++ linux-2.4.21/include/mtd/nftl-user.h
-@@ -0,0 +1,76 @@
-+/*
-+ * $Id: nftl-user.h,v 1.1 2004/05/05 14:44:57 dwmw2 Exp $
-+ *
-+ * Parts of NFTL headers shared with userspace
-+ *
-+ */
-+
-+#ifndef __MTD_NFTL_USER_H__
-+#define __MTD_NFTL_USER_H__
-+
-+/* Block Control Information */
-+
-+struct nftl_bci {
-+ unsigned char ECCSig[6];
-+ uint8_t Status;
-+ uint8_t Status1;
-+}__attribute__((packed));
-+
-+/* Unit Control Information */
-+
-+struct nftl_uci0 {
-+ uint16_t VirtUnitNum;
-+ uint16_t ReplUnitNum;
-+ uint16_t SpareVirtUnitNum;
-+ uint16_t SpareReplUnitNum;
-+} __attribute__((packed));
-+
-+struct nftl_uci1 {
-+ uint32_t WearInfo;
-+ uint16_t EraseMark;
-+ uint16_t EraseMark1;
-+} __attribute__((packed));
-+
-+struct nftl_uci2 {
-+ uint16_t FoldMark;
-+ uint16_t FoldMark1;
-+ uint32_t unused;
-+} __attribute__((packed));
-+
-+union nftl_uci {
-+ struct nftl_uci0 a;
-+ struct nftl_uci1 b;
-+ struct nftl_uci2 c;
-+};
-+
-+struct nftl_oob {
-+ struct nftl_bci b;
-+ union nftl_uci u;
-+};
-+
-+/* NFTL Media Header */
-+
-+struct NFTLMediaHeader {
-+ char DataOrgID[6];
-+ uint16_t NumEraseUnits;
-+ uint16_t FirstPhysicalEUN;
-+ uint32_t FormattedSize;
-+ unsigned char UnitSizeFactor;
-+} __attribute__((packed));
-+
-+#define MAX_ERASE_ZONES (8192 - 512)
-+
-+#define ERASE_MARK 0x3c69
-+#define SECTOR_FREE 0xff
-+#define SECTOR_USED 0x55
-+#define SECTOR_IGNORE 0x11
-+#define SECTOR_DELETED 0x00
-+
-+#define FOLD_MARK_IN_PROGRESS 0x5555
-+
-+#define ZONE_GOOD 0xff
-+#define ZONE_BAD_ORIGINAL 0
-+#define ZONE_BAD_MARKED 7
-+
-+
-+#endif /* __MTD_NFTL_USER_H__ */
---- linux-2.4.21/include/net/bluetooth/bluetooth.h~bluetooth
-+++ linux-2.4.21/include/net/bluetooth/bluetooth.h
-@@ -51,6 +51,8 @@
- #define BTPROTO_SCO 2
- #define BTPROTO_RFCOMM 3
- #define BTPROTO_BNEP 4
-+#define BTPROTO_CMTP 5
-+#define BTPROTO_HIDP 6
-
- #define SOL_HCI 0
- #define SOL_L2CAP 6
-@@ -155,7 +157,7 @@
- void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s);
- int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm);
- uint bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
--int bluez_sock_w4_connect(struct sock *sk, int flags);
-+int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
-
- void bluez_accept_enqueue(struct sock *parent, struct sock *sk);
- struct sock * bluez_accept_dequeue(struct sock *parent, struct socket *newsock);
---- linux-2.4.21/include/net/bluetooth/hci.h~bluetooth
-+++ linux-2.4.21/include/net/bluetooth/hci.h
-@@ -50,6 +50,11 @@
- #define HCI_RS232 4
- #define HCI_PCI 5
-
-+/* HCI device quirks */
-+enum {
-+ HCI_QUIRK_RESET_ON_INIT
-+};
-+
- /* HCI device flags */
- enum {
- HCI_UP,
-@@ -160,6 +165,7 @@
- #define HCI_LM_AUTH 0x0002
- #define HCI_LM_ENCRYPT 0x0004
- #define HCI_LM_TRUSTED 0x0008
-+#define HCI_LM_RELIABLE 0x0010
-
- /* ----- HCI Commands ----- */
- /* OGF & OCF values */
-@@ -333,6 +339,8 @@
- } __attribute__ ((packed)) status_bdaddr_rp;
- #define STATUS_BDADDR_RP_SIZE 7
-
-+#define OCF_INQUIRY_CANCEL 0x0002
-+
- #define OCF_LINK_KEY_REPLY 0x000B
- #define OCF_LINK_KEY_NEG_REPLY 0x000C
- typedef struct {
-@@ -459,6 +467,17 @@
- } __attribute__ ((packed)) inquiry_info;
- #define INQUIRY_INFO_SIZE 14
-
-+#define EVT_INQUIRY_RESULT_WITH_RSSI 0x22
-+typedef struct {
-+ bdaddr_t bdaddr;
-+ __u8 pscan_rep_mode;
-+ __u8 pscan_period_mode;
-+ __u8 dev_class[3];
-+ __u16 clock_offset;
-+ __s8 rssi;
-+} __attribute__ ((packed)) inquiry_info_with_rssi;
-+#define INQUIRY_INFO_WITH_RSSI_SIZE 14
-+
- #define EVT_CONN_COMPLETE 0x03
- typedef struct {
- __u8 status;
---- linux-2.4.21/include/net/bluetooth/hci_core.h~bluetooth
-+++ linux-2.4.21/include/net/bluetooth/hci_core.h
-@@ -72,7 +72,9 @@
- __u16 pkt_type;
- __u16 link_policy;
- __u16 link_mode;
--
-+
-+ unsigned long quirks;
-+
- atomic_t cmd_cnt;
- unsigned int acl_cnt;
- unsigned int sco_cnt;
-@@ -167,6 +169,12 @@
- c->list = NULL;
- }
-
-+static inline int inquiry_cache_empty(struct hci_dev *hdev)
-+{
-+ struct inquiry_cache *c = &hdev->inq_cache;
-+ return (c->list == NULL);
-+}
-+
- static inline long inquiry_cache_age(struct hci_dev *hdev)
- {
- struct inquiry_cache *c = &hdev->inq_cache;
-@@ -282,10 +290,12 @@
- static inline void hci_conn_put(struct hci_conn *conn)
- {
- if (atomic_dec_and_test(&conn->refcnt)) {
-- if (conn->type == SCO_LINK)
-+ if (conn->type == ACL_LINK) {
-+ unsigned long timeo = (conn->out) ?
-+ HCI_DISCONN_TIMEOUT : HCI_DISCONN_TIMEOUT * 2;
-+ hci_conn_set_timer(conn, timeo);
-+ } else
- hci_conn_set_timer(conn, HZ / 100);
-- else if (conn->out)
-- hci_conn_set_timer(conn, HCI_DISCONN_TIMEOUT);
- }
- }
-
---- linux-2.4.21/include/net/bluetooth/l2cap.h~bluetooth
-+++ linux-2.4.21/include/net/bluetooth/l2cap.h
-@@ -60,6 +60,7 @@
- #define L2CAP_LM_AUTH 0x0002
- #define L2CAP_LM_ENCRYPT 0x0004
- #define L2CAP_LM_TRUSTED 0x0008
-+#define L2CAP_LM_RELIABLE 0x0010
-
- #define L2CAP_QOS 0x04
- struct l2cap_qos {
-@@ -189,6 +190,14 @@
- } __attribute__ ((packed)) l2cap_info_rsp;
- #define L2CAP_INFO_RSP_SIZE 4
-
-+/* info type */
-+#define L2CAP_IT_CL_MTU 0x0001
-+#define L2CAP_IT_FEAT_MASK 0x0002
-+
-+/* info result */
-+#define L2CAP_IR_SUCCESS 0x0000
-+#define L2CAP_IR_NOTSUPP 0x0001
-+
- /* ----- L2CAP connections ----- */
- struct l2cap_chan_list {
- struct sock *head;
-@@ -229,6 +238,7 @@
- __u32 link_mode;
-
- __u8 conf_state;
-+ __u8 conf_retry;
- __u16 conf_mtu;
-
- __u8 ident;
-@@ -238,8 +248,11 @@
- struct sock *prev_c;
- };
-
--#define CONF_REQ_SENT 0x01
--#define CONF_INPUT_DONE 0x02
--#define CONF_OUTPUT_DONE 0x04
-+#define L2CAP_CONF_REQ_SENT 0x01
-+#define L2CAP_CONF_INPUT_DONE 0x02
-+#define L2CAP_CONF_OUTPUT_DONE 0x04
-+#define L2CAP_CONF_MAX_RETRIES 2
-+
-+void l2cap_load(void);
-
- #endif /* __L2CAP_H */
---- linux-2.4.21/include/net/bluetooth/rfcomm.h~bluetooth
-+++ linux-2.4.21/include/net/bluetooth/rfcomm.h
-@@ -167,8 +167,8 @@
- int initiator;
-
- /* Default DLC parameters */
-+ int cfc;
- uint mtu;
-- uint credits;
-
- struct list_head dlcs;
- };
-@@ -185,11 +185,12 @@
- atomic_t refcnt;
- u8 dlci;
- u8 addr;
--
-- uint mtu;
-+ u8 priority;
- u8 v24_sig;
-+ u8 mscex;
-
-- uint credits;
-+ uint mtu;
-+ uint cfc;
- uint rx_credits;
- uint tx_credits;
-
-@@ -213,6 +214,16 @@
- #define RFCOMM_SCHED_TIMEO 3
- #define RFCOMM_SCHED_WAKEUP 31
-
-+/* MSC exchange flags */
-+#define RFCOMM_MSCEX_TX 1
-+#define RFCOMM_MSCEX_RX 2
-+#define RFCOMM_MSCEX_OK (RFCOMM_MSCEX_TX + RFCOMM_MSCEX_RX)
-+
-+/* CFC states */
-+#define RFCOMM_CFC_UNKNOWN -1
-+#define RFCOMM_CFC_DISABLED 0
-+#define RFCOMM_CFC_ENABLED RFCOMM_MAX_CREDITS
-+
- extern struct task_struct *rfcomm_thread;
- extern unsigned long rfcomm_event;
-
---- linux-2.4.21/include/net/iw_handler.h~linux-iw241_we16-6
-+++ linux-2.4.21/include/net/iw_handler.h
-@@ -1,7 +1,7 @@
- /*
- * This file define the new driver API for Wireless Extensions
- *
-- * Version : 4 21.6.02
-+ * Version : 5 4.12.02
- *
- * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
-@@ -206,7 +206,7 @@
- * will be needed...
- * I just plan to increment with each new version.
- */
--#define IW_HANDLER_VERSION 4
-+#define IW_HANDLER_VERSION 5
-
- /*
- * Changes :
-@@ -220,10 +220,18 @@
- * V3 to V4
- * --------
- * - Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
-+ *
-+ * V4 to V5
-+ * --------
-+ * - Add new spy support : struct iw_spy_data & prototypes
- */
-
- /**************************** CONSTANTS ****************************/
-
-+/* Enable enhanced spy support. Disable to reduce footprint */
-+#define IW_WIRELESS_SPY
-+#define IW_WIRELESS_THRSPY
-+
- /* Special error message for the driver to indicate that we
- * should do a commit after return from the iw_handler */
- #define EIWCOMMIT EINPROGRESS
-@@ -315,6 +323,9 @@
- * We will automatically export that to user space... */
- struct iw_priv_args * private_args;
-
-+ /* Driver enhanced spy support */
-+ long spy_offset; /* Spy data offset */
-+
- /* In the long term, get_wireless_stats will move from
- * 'struct net_device' to here, to minimise bloat. */
- };
-@@ -350,6 +361,33 @@
-
- /* Need to think of short header translation table. Later. */
-
-+/* --------------------- ENHANCED SPY SUPPORT --------------------- */
-+/*
-+ * In the old days, the driver was handling spy support all by itself.
-+ * Now, the driver can delegate this task to Wireless Extensions.
-+ * It needs to include this struct in its private part and use the
-+ * standard spy iw_handler.
-+ */
-+
-+/*
-+ * Instance specific spy data, i.e. addresses spied and quality for them.
-+ */
-+struct iw_spy_data
-+{
-+#ifdef IW_WIRELESS_SPY
-+ /* --- Standard spy support --- */
-+ int spy_number;
-+ u_char spy_address[IW_MAX_SPY][ETH_ALEN];
-+ struct iw_quality spy_stat[IW_MAX_SPY];
-+#ifdef IW_WIRELESS_THRSPY
-+ /* --- Enhanced spy support (event) */
-+ struct iw_quality spy_thr_low; /* Low threshold */
-+ struct iw_quality spy_thr_high; /* High threshold */
-+ u_char spy_thr_under[IW_MAX_SPY];
-+#endif /* IW_WIRELESS_THRSPY */
-+#endif /* IW_WIRELESS_SPY */
-+};
-+
- /**************************** PROTOTYPES ****************************/
- /*
- * Functions part of the Wireless Extensions (defined in net/core/wireless.c).
-@@ -376,6 +414,31 @@
- /* We may need a function to send a stream of events to user space.
- * More on that later... */
-
-+/* Standard handler for SIOCSIWSPY */
-+extern int iw_handler_set_spy(struct net_device * dev,
-+ struct iw_request_info * info,
-+ union iwreq_data * wrqu,
-+ char * extra);
-+/* Standard handler for SIOCGIWSPY */
-+extern int iw_handler_get_spy(struct net_device * dev,
-+ struct iw_request_info * info,
-+ union iwreq_data * wrqu,
-+ char * extra);
-+/* Standard handler for SIOCSIWTHRSPY */
-+extern int iw_handler_set_thrspy(struct net_device * dev,
-+ struct iw_request_info *info,
-+ union iwreq_data * wrqu,
-+ char * extra);
-+/* Standard handler for SIOCGIWTHRSPY */
-+extern int iw_handler_get_thrspy(struct net_device * dev,
-+ struct iw_request_info *info,
-+ union iwreq_data * wrqu,
-+ char * extra);
-+/* Driver call to update spy records */
-+extern void wireless_spy_update(struct net_device * dev,
-+ unsigned char * address,
-+ struct iw_quality * wstats);
-+
- /************************* INLINE FUNTIONS *************************/
- /*
- * Function that are so simple that it's more efficient inlining them
---- linux-2.4.21/init/do_mounts.c~small-nocramdisk
-+++ linux-2.4.21/init/do_mounts.c
-@@ -16,8 +16,6 @@
- #include <linux/ext2_fs.h>
- #include <linux/romfs_fs.h>
-
--#define BUILD_CRAMDISK
--
- extern int get_filesystem_list(char * buf);
-
- extern asmlinkage long sys_mount(char *dev_name, char *dir_name, char *type,
---- linux-2.4.21/kernel/ksyms.c~bluetooth
-+++ linux-2.4.21/kernel/ksyms.c
-@@ -48,6 +48,7 @@
- #include <linux/completion.h>
- #include <linux/seq_file.h>
- #include <linux/dnotify.h>
-+#include <linux/firmware.h>
- #include <asm/checksum.h>
-
- #if defined(CONFIG_PROC_FS)
-@@ -564,6 +565,13 @@
- EXPORT_SYMBOL(strspn);
- EXPORT_SYMBOL(strsep);
-
-+#ifdef CONFIG_FW_LOADER
-+EXPORT_SYMBOL(release_firmware);
-+EXPORT_SYMBOL(request_firmware);
-+EXPORT_SYMBOL(request_firmware_nowait);
-+EXPORT_SYMBOL(register_firmware);
-+#endif
-+
- /* software interrupts */
- EXPORT_SYMBOL(tasklet_hi_vec);
- EXPORT_SYMBOL(tasklet_vec);
-@@ -585,6 +593,11 @@
-
- EXPORT_SYMBOL(tasklist_lock);
- EXPORT_SYMBOL(pidhash);
-+#ifdef CONFIG_ARCH_RAMSES
-+#include <asm/arch/ramses.h>
-+EXPORT_SYMBOL(ramses_control_shadow);
-+EXPORT_SYMBOL(ramses_flags);
-+#endif
-
- /* debug */
- EXPORT_SYMBOL(dump_stack);
---- linux-2.4.21/kernel/pm.c~pm
-+++ linux-2.4.21/kernel/pm.c
-@@ -234,7 +234,7 @@
- struct list_head *entry;
-
- down(&pm_devs_lock);
-- entry = pm_devs.next;
-+ entry = (rqst==PM_RESUME) ? pm_devs.prev : pm_devs.next;
- while (entry != &pm_devs) {
- struct pm_dev *dev = list_entry(entry, struct pm_dev, entry);
- if (dev->callback) {
-@@ -249,7 +249,7 @@
- return status;
- }
- }
-- entry = entry->next;
-+ entry = (rqst==PM_RESUME) ? entry->prev : entry->next;
- }
- up(&pm_devs_lock);
- return 0;
---- linux-2.4.21/lib/Config.in~mtd-cvs
-+++ linux-2.4.21/lib/Config.in
-@@ -35,4 +35,25 @@
- fi
- fi
-
-+if [ "$CONFIG_MTD_DOCPROBE" = "y" -o \
-+ "$CONFIG_MTD_NAND_RTC_FROM4" = "y" -o \
-+ "$CONFIG_MTD_NAND_DISKONCHIP" = "y" ]; then
-+ define_tristate CONFIG_REED_SOLOMON y
-+ define_tristate CONFIG_REED_SOLOMON_DEC16 y
-+else
-+ if [ "$CONFIG_MTD_DOCPROBE" = "m" -o \
-+ "$CONFIG_MTD_NAND_RTC_FROM4" = "m" -o \
-+ "$CONFIG_MTD_NAND_DISKONCHIP" = "m" ]; then
-+ define_tristate CONFIG_REED_SOLOMON m
-+ define_tristate CONFIG_REED_SOLOMON_DEC16 y
-+ else
-+ define_tristate CONFIG_REED_SOLOMON n
-+ fi
-+fi
-+
-+if [ "$CONFIG_EXPERIMENTAL" = "y" -a \
-+ "$CONFIG_HOTPLUG" = "y" ]; then
-+ tristate 'Hotplug firmware loading support (EXPERIMENTAL)' CONFIG_FW_LOADER
-+fi
-+
- endmenu
---- linux-2.4.21/lib/Makefile~mtd-cvs
-+++ linux-2.4.21/lib/Makefile
-@@ -8,11 +8,13 @@
-
- L_TARGET := lib.a
-
--export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o rbtree.o
-+export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o \
-+ rbtree.o firmware_class.o
-
- obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o \
- bust_spinlocks.o rbtree.o dump_stack.o
-
-+obj-$(CONFIG_FW_LOADER) += firmware_class.o
- obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
- obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
-
-@@ -22,6 +24,9 @@
-
- subdir-$(CONFIG_ZLIB_INFLATE) += zlib_inflate
- subdir-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate
-+subdir-$(CONFIG_REED_SOLOMON) += reed_solomon
-+
-+include $(TOPDIR)/drivers/bluetooth/Makefile.lib
-
- # Include the subdirs, if necessary.
- obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
---- /dev/null
-+++ linux-2.4.21/lib/firmware_class.c
-@@ -0,0 +1,573 @@
-+/*
-+ * firmware_class.c - Multi purpose firmware loading support
-+ *
-+ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
-+ *
-+ * Please see Documentation/firmware_class/ for more information.
-+ *
-+ */
-+/*
-+ * Based on kernel/kmod.c and drivers/usb/usb.c
-+ */
-+/*
-+ kernel/kmod.c
-+ Kirk Petersen
-+
-+ Reorganized not to be a daemon by Adam Richter, with guidance
-+ from Greg Zornetzer.
-+
-+ Modified to avoid chroot and file sharing problems.
-+ Mikael Pettersson
-+
-+ Limit the concurrent number of kmod modprobes to catch loops from
-+ "modprobe needs a service that is in a module".
-+ Keith Owens <kaos@ocs.com.au> December 1999
-+
-+ Unblock all signals when we exec a usermode process.
-+ Shuu Yamaguchi <shuu@wondernetworkresources.com> December 2000
-+*/
-+/*
-+ * drivers/usb/usb.c
-+ *
-+ * (C) Copyright Linus Torvalds 1999
-+ * (C) Copyright Johannes Erdfelt 1999-2001
-+ * (C) Copyright Andreas Gal 1999
-+ * (C) Copyright Gregory P. Smith 1999
-+ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
-+ * (C) Copyright Randy Dunlap 2000
-+ * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id)
-+ * (C) Copyright Yggdrasil Computing, Inc. 2000
-+ * (usb_device_id matching changes by Adam J. Richter)
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/kmod.h>
-+#include <linux/proc_fs.h>
-+#include <linux/vmalloc.h>
-+#include <asm/hardirq.h>
-+
-+#include "linux/firmware.h"
-+
-+MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>");
-+MODULE_DESCRIPTION("Multi purpose firmware loading support");
-+MODULE_LICENSE("GPL");
-+
-+#define err(format, arg...) \
-+ printk(KERN_ERR "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
-+#define warn(format, arg...) \
-+ printk(KERN_WARNING "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
-+#define dbg(format, arg...) \
-+ printk(KERN_DEBUG "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
-+
-+static int loading_timeout = 10; /* In seconds */
-+static struct proc_dir_entry *proc_dir_timeout;
-+static struct proc_dir_entry *proc_dir;
-+
-+#ifdef CONFIG_HOTPLUG
-+
-+static int
-+call_helper(char *verb, const char *name, const char *device)
-+{
-+ char *argv[3], **envp, *buf, *scratch;
-+ int i = 0;
-+
-+ int retval = 0;
-+
-+ if (!hotplug_path[0])
-+ return -ENOENT;
-+ if (in_interrupt()) {
-+ err("in_interrupt");
-+ return -EFAULT;
-+ }
-+ if (!current->fs->root) {
-+ warn("call_policy %s -- no FS yet", verb);
-+ return -EPERM;
-+ }
-+
-+ if (!(envp = (char **) kmalloc(20 * sizeof (char *), GFP_KERNEL))) {
-+ err("unable to allocate envp");
-+ return -ENOMEM;
-+ }
-+ if (!(buf = kmalloc(256, GFP_KERNEL))) {
-+ kfree(envp);
-+ err("unable to allocate buf");
-+ return -ENOMEM;
-+ }
-+
-+ /* only one standardized param to hotplug command: type */
-+ argv[0] = hotplug_path;
-+ argv[1] = "firmware";
-+ argv[2] = 0;
-+
-+ /* minimal command environment */
-+ envp[i++] = "HOME=/";
-+ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-+
-+#ifdef DEBUG
-+ /* hint that policy agent should enter no-stdout debug mode */
-+ envp[i++] = "DEBUG=kernel";
-+#endif
-+ scratch = buf;
-+
-+ if (device) {
-+ envp[i++] = scratch;
-+ scratch += snprintf(scratch, FIRMWARE_NAME_MAX+25,
-+ "DEVPATH=/driver/firmware/%s", device) + 1;
-+ }
-+
-+ envp[i++] = scratch;
-+ scratch += sprintf(scratch, "ACTION=%s", verb) + 1;
-+
-+ envp[i++] = scratch;
-+ scratch += snprintf(scratch, FIRMWARE_NAME_MAX,
-+ "FIRMWARE=%s", name) + 1;
-+
-+ envp[i++] = 0;
-+
-+#ifdef DEBUG
-+ dbg("firmware: %s %s %s", argv[0], argv[1], verb);
-+#endif
-+
-+ retval = call_usermodehelper(argv[0], argv, envp);
-+ if (retval) {
-+ printk("call_usermodehelper return %d\n", retval);
-+ }
-+
-+ kfree(buf);
-+ kfree(envp);
-+ return retval;
-+}
-+#else
-+
-+static inline int
-+call_helper(char *verb, const char *name, const char *device)
-+{
-+ return -ENOENT;
-+}
-+
-+#endif /* CONFIG_HOTPLUG */
-+
-+struct firmware_priv {
-+ struct completion completion;
-+ struct proc_dir_entry *proc_dir;
-+ struct proc_dir_entry *attr_data;
-+ struct proc_dir_entry *attr_loading;
-+ struct firmware *fw;
-+ int loading;
-+ int abort;
-+ int alloc_size;
-+ struct timer_list timeout;
-+};
-+
-+static int
-+firmware_timeout_show(char *buf, char **start, off_t off,
-+ int count, int *eof, void *data)
-+{
-+ return sprintf(buf, "%d\n", loading_timeout);
-+}
-+
-+/**
-+ * firmware_timeout_store:
-+ * Description:
-+ * Sets the number of seconds to wait for the firmware. Once
-+ * this expires an error will be return to the driver and no
-+ * firmware will be provided.
-+ *
-+ * Note: zero means 'wait for ever'
-+ *
-+ **/
-+static int
-+firmware_timeout_store(struct file *file, const char *buf,
-+ unsigned long count, void *data)
-+{
-+ loading_timeout = simple_strtol(buf, NULL, 10);
-+ return count;
-+}
-+
-+static int
-+firmware_loading_show(char *buf, char **start, off_t off,
-+ int count, int *eof, void *data)
-+{
-+ struct firmware_priv *fw_priv = data;
-+ return sprintf(buf, "%d\n", fw_priv->loading);
-+}
-+
-+/**
-+ * firmware_loading_store: - loading control file
-+ * Description:
-+ * The relevant values are:
-+ *
-+ * 1: Start a load, discarding any previous partial load.
-+ * 0: Conclude the load and handle the data to the driver code.
-+ * -1: Conclude the load with an error and discard any written data.
-+ **/
-+static int
-+firmware_loading_store(struct file *file, const char *buf,
-+ unsigned long count, void *data)
-+{
-+ struct firmware_priv *fw_priv = data;
-+ int prev_loading = fw_priv->loading;
-+
-+ fw_priv->loading = simple_strtol(buf, NULL, 10);
-+
-+ switch (fw_priv->loading) {
-+ case -1:
-+ fw_priv->abort = 1;
-+ wmb();
-+ complete(&fw_priv->completion);
-+ break;
-+ case 1:
-+ kfree(fw_priv->fw->data);
-+ fw_priv->fw->data = NULL;
-+ fw_priv->fw->size = 0;
-+ fw_priv->alloc_size = 0;
-+ break;
-+ case 0:
-+ if (prev_loading == 1)
-+ complete(&fw_priv->completion);
-+ break;
-+ }
-+
-+ return count;
-+}
-+
-+static int
-+firmware_data_read(char *buffer, char **start, off_t offset,
-+ int count, int *eof, void *data)
-+{
-+ struct firmware_priv *fw_priv = data;
-+ struct firmware *fw = fw_priv->fw;
-+
-+ if (offset > fw->size)
-+ return 0;
-+ if (offset + count > fw->size)
-+ count = fw->size - offset;
-+
-+ memcpy(buffer, fw->data + offset, count);
-+ *start = (void *) ((long) count);
-+ return count;
-+}
-+static int
-+fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
-+{
-+ u8 *new_data;
-+ int new_size;
-+
-+ if (min_size <= fw_priv->alloc_size)
-+ return 0;
-+ if((min_size % PAGE_SIZE) == 0)
-+ new_size = min_size;
-+ else
-+ new_size = (min_size + PAGE_SIZE) & PAGE_MASK;
-+ new_data = vmalloc(new_size);
-+ if (!new_data) {
-+ printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__);
-+ /* Make sure that we don't keep incomplete data */
-+ fw_priv->abort = 1;
-+ return -ENOMEM;
-+ }
-+ fw_priv->alloc_size = new_size;
-+ if (fw_priv->fw->data) {
-+ memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size);
-+ vfree(fw_priv->fw->data);
-+ }
-+ fw_priv->fw->data = new_data;
-+ BUG_ON(min_size > fw_priv->alloc_size);
-+ return 0;
-+}
-+
-+/**
-+ * firmware_data_write:
-+ *
-+ * Description:
-+ *
-+ * Data written to the 'data' attribute will be later handled to
-+ * the driver as a firmware image.
-+ **/
-+static int
-+firmware_data_write(struct file *file, const char *buffer,
-+ unsigned long count, void *data)
-+{
-+ struct firmware_priv *fw_priv = data;
-+ struct firmware *fw = fw_priv->fw;
-+ int offset = file->f_pos;
-+ int retval;
-+
-+ retval = fw_realloc_buffer(fw_priv, offset + count);
-+ if (retval) {
-+ printk("%s: retval:%d\n", __FUNCTION__, retval);
-+ return retval;
-+ }
-+
-+ memcpy(fw->data + offset, buffer, count);
-+
-+ fw->size = max_t(size_t, offset + count, fw->size);
-+ file->f_pos += count;
-+ return count;
-+}
-+
-+static void
-+firmware_class_timeout(u_long data)
-+{
-+ struct firmware_priv *fw_priv = (struct firmware_priv *) data;
-+ fw_priv->abort = 1;
-+ wmb();
-+ complete(&fw_priv->completion);
-+}
-+static int
-+fw_setup_class_device(struct firmware_priv **fw_priv_p,
-+ const char *fw_name, const char *device)
-+{
-+ int retval;
-+ struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv),
-+ GFP_KERNEL);
-+ *fw_priv_p = fw_priv;
-+ if (!fw_priv) {
-+ retval = -ENOMEM;
-+ goto out;
-+ }
-+ memset(fw_priv, 0, sizeof (*fw_priv));
-+
-+ init_completion(&fw_priv->completion);
-+
-+ fw_priv->timeout.function = firmware_class_timeout;
-+ fw_priv->timeout.data = (u_long) fw_priv;
-+ init_timer(&fw_priv->timeout);
-+
-+ retval = -EAGAIN;
-+ fw_priv->proc_dir = create_proc_entry(device, 0644 | S_IFDIR, proc_dir);
-+ if (!fw_priv->proc_dir)
-+ goto err_free_fw_priv;
-+
-+ fw_priv->attr_data = create_proc_entry("data", 0644 | S_IFREG,
-+ fw_priv->proc_dir);
-+ if (!fw_priv->attr_data)
-+ goto err_remove_dir;
-+
-+ fw_priv->attr_data->read_proc = firmware_data_read;
-+ fw_priv->attr_data->write_proc = firmware_data_write;
-+ fw_priv->attr_data->data = fw_priv;
-+
-+ fw_priv->attr_loading = create_proc_entry("loading", 0644 | S_IFREG,
-+ fw_priv->proc_dir);
-+ if (!fw_priv->attr_loading)
-+ goto err_remove_data;
-+
-+ fw_priv->attr_loading->read_proc = firmware_loading_show;
-+ fw_priv->attr_loading->write_proc = firmware_loading_store;
-+ fw_priv->attr_loading->data = fw_priv;
-+
-+ retval = 0;
-+ fw_priv->fw = kmalloc(sizeof (struct firmware), GFP_KERNEL);
-+ if (!fw_priv->fw) {
-+ printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
-+ __FUNCTION__);
-+ retval = -ENOMEM;
-+ goto err_remove_loading;
-+ }
-+ memset(fw_priv->fw, 0, sizeof (*fw_priv->fw));
-+
-+ goto out;
-+
-+err_remove_loading:
-+ remove_proc_entry("loading", fw_priv->proc_dir);
-+err_remove_data:
-+ remove_proc_entry("data", fw_priv->proc_dir);
-+err_remove_dir:
-+ remove_proc_entry(device, proc_dir);
-+err_free_fw_priv:
-+ kfree(fw_priv);
-+out:
-+ return retval;
-+}
-+static void
-+fw_remove_class_device(struct firmware_priv *fw_priv)
-+{
-+ remove_proc_entry("loading", fw_priv->proc_dir);
-+ remove_proc_entry("data", fw_priv->proc_dir);
-+ remove_proc_entry(fw_priv->proc_dir->name, proc_dir);
-+}
-+
-+/**
-+ * request_firmware: - request firmware to hotplug and wait for it
-+ * Description:
-+ * @firmware will be used to return a firmware image by the name
-+ * of @name for device @device.
-+ *
-+ * Should be called from user context where sleeping is allowed.
-+ *
-+ * @name will be use as $FIRMWARE in the hotplug environment and
-+ * should be distinctive enough not to be confused with any other
-+ * firmware image for this or any other device.
-+ **/
-+int
-+request_firmware(const struct firmware **firmware, const char *name,
-+ const char *device)
-+{
-+ struct firmware_priv *fw_priv;
-+ int retval;
-+
-+ if (!firmware) {
-+ retval = -EINVAL;
-+ goto out;
-+ }
-+ *firmware = NULL;
-+
-+ retval = fw_setup_class_device(&fw_priv, name, device);
-+ if (retval)
-+ goto out;
-+
-+ retval = call_helper("add", name, device);
-+ if (retval)
-+ goto out;
-+ if (loading_timeout) {
-+ fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
-+ add_timer(&fw_priv->timeout);
-+ }
-+
-+ wait_for_completion(&fw_priv->completion);
-+
-+ del_timer(&fw_priv->timeout);
-+ fw_remove_class_device(fw_priv);
-+
-+ if (fw_priv->fw->size && !fw_priv->abort) {
-+ *firmware = fw_priv->fw;
-+ } else {
-+ retval = -ENOENT;
-+ vfree(fw_priv->fw->data);
-+ kfree(fw_priv->fw);
-+ }
-+out:
-+ kfree(fw_priv);
-+ return retval;
-+}
-+
-+void
-+release_firmware(const struct firmware *fw)
-+{
-+ if (fw) {
-+ vfree(fw->data);
-+ kfree(fw);
-+ }
-+}
-+
-+/**
-+ * register_firmware: - provide a firmware image for later usage
-+ *
-+ * Description:
-+ * Make sure that @data will be available by requesting firmware @name.
-+ *
-+ * Note: This will not be possible until some kind of persistence
-+ * is available.
-+ **/
-+void
-+register_firmware(const char *name, const u8 *data, size_t size)
-+{
-+ /* This is meaningless without firmware caching, so until we
-+ * decide if firmware caching is reasonable just leave it as a
-+ * noop */
-+}
-+
-+/* Async support */
-+struct firmware_work {
-+ struct tq_struct work;
-+ struct module *module;
-+ const char *name;
-+ const char *device;
-+ void *context;
-+ void (*cont)(const struct firmware *fw, void *context);
-+};
-+
-+static void
-+request_firmware_work_func(void *arg)
-+{
-+ struct firmware_work *fw_work = arg;
-+ const struct firmware *fw;
-+ if (!arg)
-+ return;
-+ request_firmware(&fw, fw_work->name, fw_work->device);
-+ fw_work->cont(fw, fw_work->context);
-+ release_firmware(fw);
-+ __MOD_DEC_USE_COUNT(fw_work->module);
-+ kfree(fw_work);
-+}
-+
-+/**
-+ * request_firmware_nowait:
-+ *
-+ * Description:
-+ * Asynchronous variant of request_firmware() for contexts where
-+ * it is not possible to sleep.
-+ *
-+ * @cont will be called asynchronously when the firmware request is over.
-+ *
-+ * @context will be passed over to @cont.
-+ *
-+ * @fw may be %NULL if firmware request fails.
-+ *
-+ **/
-+int
-+request_firmware_nowait(
-+ struct module *module,
-+ const char *name, const char *device, void *context,
-+ void (*cont)(const struct firmware *fw, void *context))
-+{
-+ struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
-+ GFP_ATOMIC);
-+ if (!fw_work)
-+ return -ENOMEM;
-+ if (!try_inc_mod_count(module)) {
-+ kfree(fw_work);
-+ return -EFAULT;
-+ }
-+
-+ *fw_work = (struct firmware_work) {
-+ .module = module,
-+ .name = name,
-+ .device = device,
-+ .context = context,
-+ .cont = cont,
-+ };
-+ INIT_TQUEUE(&fw_work->work, request_firmware_work_func, fw_work);
-+
-+ schedule_task(&fw_work->work);
-+ return 0;
-+}
-+
-+static int __init
-+firmware_class_init(void)
-+{
-+ proc_dir = create_proc_entry("driver/firmware", 0755 | S_IFDIR, NULL);
-+ if (!proc_dir)
-+ return -EAGAIN;
-+ proc_dir_timeout = create_proc_entry("timeout",
-+ 0644 | S_IFREG, proc_dir);
-+ if (!proc_dir_timeout) {
-+ remove_proc_entry("driver/firmware", NULL);
-+ return -EAGAIN;
-+ }
-+ proc_dir_timeout->read_proc = firmware_timeout_show;
-+ proc_dir_timeout->write_proc = firmware_timeout_store;
-+ return 0;
-+}
-+static void __exit
-+firmware_class_exit(void)
-+{
-+ remove_proc_entry("timeout", proc_dir);
-+ remove_proc_entry("driver/firmware", NULL);
-+}
-+
-+module_init(firmware_class_init);
-+module_exit(firmware_class_exit);
-+
-+#ifndef CONFIG_FW_LOADER
-+EXPORT_SYMBOL(release_firmware);
-+EXPORT_SYMBOL(request_firmware);
-+EXPORT_SYMBOL(request_firmware_nowait);
-+EXPORT_SYMBOL(register_firmware);
-+#endif
---- /dev/null
-+++ linux-2.4.21/lib/reed_solomon/Makefile
-@@ -0,0 +1,12 @@
-+#
-+# This is a modified version of reed solomon lib,
-+#
-+
-+O_TARGET:= reed_solomon.o
-+
-+export-objs := rslib.o
-+
-+obj-y := rslib.o
-+obj-m := $(O_TARGET)
-+
-+include $(TOPDIR)/Rules.make
---- /dev/null
-+++ linux-2.4.21/lib/reed_solomon/decode_rs.c
-@@ -0,0 +1,272 @@
-+/*
-+ * lib/reed_solomon/decode_rs.c
-+ *
-+ * Overview:
-+ * Generic Reed Solomon encoder / decoder library
-+ *
-+ * Copyright 2002, Phil Karn, KA9Q
-+ * May be used under the terms of the GNU General Public License (GPL)
-+ *
-+ * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de)
-+ *
-+ * $Id: decode_rs.c,v 1.6 2004/10/22 15:41:47 gleixner Exp $
-+ *
-+ */
-+
-+/* Generic data width independent code which is included by the
-+ * wrappers.
-+ */
-+{
-+ int deg_lambda, el, deg_omega;
-+ int i, j, r, k, pad;
-+ int nn = rs->nn;
-+ int nroots = rs->nroots;
-+ int fcr = rs->fcr;
-+ int prim = rs->prim;
-+ int iprim = rs->iprim;
-+ uint16_t *alpha_to = rs->alpha_to;
-+ uint16_t *index_of = rs->index_of;
-+ uint16_t u, q, tmp, num1, num2, den, discr_r, syn_error;
-+ /* Err+Eras Locator poly and syndrome poly The maximum value
-+ * of nroots is 8. So the necessary stack size will be about
-+ * 220 bytes max.
-+ */
-+ uint16_t lambda[nroots + 1], syn[nroots];
-+ uint16_t b[nroots + 1], t[nroots + 1], omega[nroots + 1];
-+ uint16_t root[nroots], reg[nroots + 1], loc[nroots];
-+ int count = 0;
-+ uint16_t msk = (uint16_t) rs->nn;
-+
-+ /* Check length parameter for validity */
-+ pad = nn - nroots - len;
-+ if (pad < 0 || pad >= nn)
-+ return -ERANGE;
-+
-+ /* Does the caller provide the syndrome ? */
-+ if (s != NULL)
-+ goto decode;
-+
-+ /* form the syndromes; i.e., evaluate data(x) at roots of
-+ * g(x) */
-+ for (i = 0; i < nroots; i++)
-+ syn[i] = (((uint16_t) data[0]) ^ invmsk) & msk;
-+
-+ for (j = 1; j < len; j++) {
-+ for (i = 0; i < nroots; i++) {
-+ if (syn[i] == 0) {
-+ syn[i] = (((uint16_t) data[j]) ^
-+ invmsk) & msk;
-+ } else {
-+ syn[i] = ((((uint16_t) data[j]) ^
-+ invmsk) & msk) ^
-+ alpha_to[rs_modnn(rs, index_of[syn[i]] +
-+ (fcr + i) * prim)];
-+ }
-+ }
-+ }
-+
-+ for (j = 0; j < nroots; j++) {
-+ for (i = 0; i < nroots; i++) {
-+ if (syn[i] == 0) {
-+ syn[i] = ((uint16_t) par[j]) & msk;
-+ } else {
-+ syn[i] = (((uint16_t) par[j]) & msk) ^
-+ alpha_to[rs_modnn(rs, index_of[syn[i]] +
-+ (fcr+i)*prim)];
-+ }
-+ }
-+ }
-+ s = syn;
-+
-+ /* Convert syndromes to index form, checking for nonzero condition */
-+ syn_error = 0;
-+ for (i = 0; i < nroots; i++) {
-+ syn_error |= s[i];
-+ s[i] = index_of[s[i]];
-+ }
-+
-+ if (!syn_error) {
-+ /* if syndrome is zero, data[] is a codeword and there are no
-+ * errors to correct. So return data[] unmodified
-+ */
-+ count = 0;
-+ goto finish;
-+ }
-+
-+ decode:
-+ memset(&lambda[1], 0, nroots * sizeof(lambda[0]));
-+ lambda[0] = 1;
-+
-+ if (no_eras > 0) {
-+ /* Init lambda to be the erasure locator polynomial */
-+ lambda[1] = alpha_to[rs_modnn(rs,
-+ prim * (nn - 1 - eras_pos[0]))];
-+ for (i = 1; i < no_eras; i++) {
-+ u = rs_modnn(rs, prim * (nn - 1 - eras_pos[i]));
-+ for (j = i + 1; j > 0; j--) {
-+ tmp = index_of[lambda[j - 1]];
-+ if (tmp != nn) {
-+ lambda[j] ^=
-+ alpha_to[rs_modnn(rs, u + tmp)];
-+ }
-+ }
-+ }
-+ }
-+
-+ for (i = 0; i < nroots + 1; i++)
-+ b[i] = index_of[lambda[i]];
-+
-+ /*
-+ * Begin Berlekamp-Massey algorithm to determine error+erasure
-+ * locator polynomial
-+ */
-+ r = no_eras;
-+ el = no_eras;
-+ while (++r <= nroots) { /* r is the step number */
-+ /* Compute discrepancy at the r-th step in poly-form */
-+ discr_r = 0;
-+ for (i = 0; i < r; i++) {
-+ if ((lambda[i] != 0) && (s[r - i - 1] != nn)) {
-+ discr_r ^=
-+ alpha_to[rs_modnn(rs,
-+ index_of[lambda[i]] +
-+ s[r - i - 1])];
-+ }
-+ }
-+ discr_r = index_of[discr_r]; /* Index form */
-+ if (discr_r == nn) {
-+ /* 2 lines below: B(x) <-- x*B(x) */
-+ memmove (&b[1], b, nroots * sizeof (b[0]));
-+ b[0] = nn;
-+ } else {
-+ /* 7 lines below: T(x) <-- lambda(x)-discr_r*x*b(x) */
-+ t[0] = lambda[0];
-+ for (i = 0; i < nroots; i++) {
-+ if (b[i] != nn) {
-+ t[i + 1] = lambda[i + 1] ^
-+ alpha_to[rs_modnn(rs, discr_r +
-+ b[i])];
-+ } else
-+ t[i + 1] = lambda[i + 1];
-+ }
-+ if (2 * el <= r + no_eras - 1) {
-+ el = r + no_eras - el;
-+ /*
-+ * 2 lines below: B(x) <-- inv(discr_r) *
-+ * lambda(x)
-+ */
-+ for (i = 0; i <= nroots; i++) {
-+ b[i] = (lambda[i] == 0) ? nn :
-+ rs_modnn(rs, index_of[lambda[i]]
-+ - discr_r + nn);
-+ }
-+ } else {
-+ /* 2 lines below: B(x) <-- x*B(x) */
-+ memmove(&b[1], b, nroots * sizeof(b[0]));
-+ b[0] = nn;
-+ }
-+ memcpy(lambda, t, (nroots + 1) * sizeof(t[0]));
-+ }
-+ }
-+
-+ /* Convert lambda to index form and compute deg(lambda(x)) */
-+ deg_lambda = 0;
-+ for (i = 0; i < nroots + 1; i++) {
-+ lambda[i] = index_of[lambda[i]];
-+ if (lambda[i] != nn)
-+ deg_lambda = i;
-+ }
-+ /* Find roots of error+erasure locator polynomial by Chien search */
-+ memcpy(&reg[1], &lambda[1], nroots * sizeof(reg[0]));
-+ count = 0; /* Number of roots of lambda(x) */
-+ for (i = 1, k = iprim - 1; i <= nn; i++, k = rs_modnn(rs, k + iprim)) {
-+ q = 1; /* lambda[0] is always 0 */
-+ for (j = deg_lambda; j > 0; j--) {
-+ if (reg[j] != nn) {
-+ reg[j] = rs_modnn(rs, reg[j] + j);
-+ q ^= alpha_to[reg[j]];
-+ }
-+ }
-+ if (q != 0)
-+ continue; /* Not a root */
-+ /* store root (index-form) and error location number */
-+ root[count] = i;
-+ loc[count] = k;
-+ /* If we've already found max possible roots,
-+ * abort the search to save time
-+ */
-+ if (++count == deg_lambda)
-+ break;
-+ }
-+ if (deg_lambda != count) {
-+ /*
-+ * deg(lambda) unequal to number of roots => uncorrectable
-+ * error detected
-+ */
-+ count = -1;
-+ goto finish;
-+ }
-+ /*
-+ * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
-+ * x**nroots). in index form. Also find deg(omega).
-+ */
-+ deg_omega = deg_lambda - 1;
-+ for (i = 0; i <= deg_omega; i++) {
-+ tmp = 0;
-+ for (j = i; j >= 0; j--) {
-+ if ((s[i - j] != nn) && (lambda[j] != nn))
-+ tmp ^=
-+ alpha_to[rs_modnn(rs, s[i - j] + lambda[j])];
-+ }
-+ omega[i] = index_of[tmp];
-+ }
-+
-+ /*
-+ * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
-+ * inv(X(l))**(fcr-1) and den = lambda_pr(inv(X(l))) all in poly-form
-+ */
-+ for (j = count - 1; j >= 0; j--) {
-+ num1 = 0;
-+ for (i = deg_omega; i >= 0; i--) {
-+ if (omega[i] != nn)
-+ num1 ^= alpha_to[rs_modnn(rs, omega[i] +
-+ i * root[j])];
-+ }
-+ num2 = alpha_to[rs_modnn(rs, root[j] * (fcr - 1) + nn)];
-+ den = 0;
-+
-+ /* lambda[i+1] for i even is the formal derivative
-+ * lambda_pr of lambda[i] */
-+ for (i = min(deg_lambda, nroots - 1) & ~1; i >= 0; i -= 2) {
-+ if (lambda[i + 1] != nn) {
-+ den ^= alpha_to[rs_modnn(rs, lambda[i + 1] +
-+ i * root[j])];
-+ }
-+ }
-+ /* Apply error to data */
-+ if (num1 != 0 && loc[j] >= pad) {
-+ uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] +
-+ index_of[num2] +
-+ nn - index_of[den])];
-+ /* Store the error correction pattern, if a
-+ * correction buffer is available */
-+ if (corr) {
-+ corr[j] = cor;
-+ } else {
-+ /* If a data buffer is given and the
-+ * error is inside the message,
-+ * correct it */
-+ if (data && (loc[j] < (nn - nroots)))
-+ data[loc[j] - pad] ^= cor;
-+ }
-+ }
-+ }
-+
-+finish:
-+ if (eras_pos != NULL) {
-+ for (i = 0; i < count; i++)
-+ eras_pos[i] = loc[i] - pad;
-+ }
-+ return count;
-+
-+}
---- /dev/null
-+++ linux-2.4.21/lib/reed_solomon/encode_rs.c
-@@ -0,0 +1,54 @@
-+/*
-+ * lib/reed_solomon/encode_rs.c
-+ *
-+ * Overview:
-+ * Generic Reed Solomon encoder / decoder library
-+ *
-+ * Copyright 2002, Phil Karn, KA9Q
-+ * May be used under the terms of the GNU General Public License (GPL)
-+ *
-+ * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de)
-+ *
-+ * $Id: encode_rs.c,v 1.4 2004/10/22 15:41:47 gleixner Exp $
-+ *
-+ */
-+
-+/* Generic data width independent code which is included by the
-+ * wrappers.
-+ * int encode_rsX (struct rs_control *rs, uintX_t *data, int len, uintY_t *par)
-+ */
-+{
-+ int i, j, pad;
-+ int nn = rs->nn;
-+ int nroots = rs->nroots;
-+ uint16_t *alpha_to = rs->alpha_to;
-+ uint16_t *index_of = rs->index_of;
-+ uint16_t *genpoly = rs->genpoly;
-+ uint16_t fb;
-+ uint16_t msk = (uint16_t) rs->nn;
-+
-+ /* Check length parameter for validity */
-+ pad = nn - nroots - len;
-+ if (pad < 0 || pad >= nn)
-+ return -ERANGE;
-+
-+ for (i = 0; i < len; i++) {
-+ fb = index_of[((((uint16_t) data[i])^invmsk) & msk) ^ par[0]];
-+ /* feedback term is non-zero */
-+ if (fb != nn) {
-+ for (j = 1; j < nroots; j++) {
-+ par[j] ^= alpha_to[rs_modnn(rs, fb +
-+ genpoly[nroots - j])];
-+ }
-+ }
-+ /* Shift */
-+ memmove(&par[0], &par[1], sizeof(uint16_t) * (nroots - 1));
-+ if (fb != nn) {
-+ par[nroots - 1] = alpha_to[rs_modnn(rs,
-+ fb + genpoly[0])];
-+ } else {
-+ par[nroots - 1] = 0;
-+ }
-+ }
-+ return 0;
-+}
---- /dev/null
-+++ linux-2.4.21/lib/reed_solomon/rslib.c
-@@ -0,0 +1,335 @@
-+/*
-+ * lib/reed_solomon/rslib.c
-+ *
-+ * Overview:
-+ * Generic Reed Solomon encoder / decoder library
-+ *
-+ * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
-+ *
-+ * Reed Solomon code lifted from reed solomon library written by Phil Karn
-+ * Copyright 2002 Phil Karn, KA9Q
-+ *
-+ * $Id: rslib.c,v 1.5 2004/10/22 15:41:47 gleixner 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.
-+ *
-+ * Description:
-+ *
-+ * The generic Reed Solomon library provides runtime configurable
-+ * encoding / decoding of RS codes.
-+ * Each user must call init_rs to get a pointer to a rs_control
-+ * structure for the given rs parameters. This structure is either
-+ * generated or a already available matching control structure is used.
-+ * If a structure is generated then the polynomial arrays for
-+ * fast encoding / decoding are built. This can take some time so
-+ * make sure not to call this function from a time critical path.
-+ * Usually a module / driver should initialize the necessary
-+ * rs_control structure on module / driver init and release it
-+ * on exit.
-+ * The encoding puts the calculated syndrome into a given syndrome
-+ * buffer.
-+ * The decoding is a two step process. The first step calculates
-+ * the syndrome over the received (data + syndrome) and calls the
-+ * second stage, which does the decoding / error correction itself.
-+ * Many hw encoders provide a syndrome calculation over the received
-+ * data + syndrome and can call the second stage directly.
-+ *
-+ */
-+
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/rslib.h>
-+#include <linux/slab.h>
-+#include <asm/semaphore.h>
-+
-+/* This list holds all currently allocated rs control structures */
-+static LIST_HEAD (rslist);
-+/* Protection for the list */
-+static DECLARE_MUTEX(rslistlock);
-+
-+/**
-+ * rs_init - Initialize a Reed-Solomon codec
-+ *
-+ * @symsize: symbol size, bits (1-8)
-+ * @gfpoly: Field generator polynomial coefficients
-+ * @fcr: first root of RS code generator polynomial, index form
-+ * @prim: primitive element to generate polynomial roots
-+ * @nroots: RS code generator polynomial degree (number of roots)
-+ *
-+ * Allocate a control structure and the polynom arrays for faster
-+ * en/decoding. Fill the arrays according to the given parameters
-+ */
-+static struct rs_control *rs_init(int symsize, int gfpoly, int fcr,
-+ int prim, int nroots)
-+{
-+ struct rs_control *rs;
-+ int i, j, sr, root, iprim;
-+
-+ /* Allocate the control structure */
-+ rs = kmalloc(sizeof (struct rs_control), GFP_KERNEL);
-+ if (rs == NULL)
-+ return NULL;
-+
-+ INIT_LIST_HEAD(&rs->list);
-+
-+ rs->mm = symsize;
-+ rs->nn = (1 << symsize) - 1;
-+ rs->fcr = fcr;
-+ rs->prim = prim;
-+ rs->nroots = nroots;
-+ rs->gfpoly = gfpoly;
-+
-+ /* Allocate the arrays */
-+ rs->alpha_to = kmalloc(sizeof(uint16_t) * (rs->nn + 1), GFP_KERNEL);
-+ if (rs->alpha_to == NULL)
-+ goto errrs;
-+
-+ rs->index_of = kmalloc(sizeof(uint16_t) * (rs->nn + 1), GFP_KERNEL);
-+ if (rs->index_of == NULL)
-+ goto erralp;
-+
-+ rs->genpoly = kmalloc(sizeof(uint16_t) * (rs->nroots + 1), GFP_KERNEL);
-+ if(rs->genpoly == NULL)
-+ goto erridx;
-+
-+ /* Generate Galois field lookup tables */
-+ rs->index_of[0] = rs->nn; /* log(zero) = -inf */
-+ rs->alpha_to[rs->nn] = 0; /* alpha**-inf = 0 */
-+ sr = 1;
-+ for (i = 0; i < rs->nn; i++) {
-+ rs->index_of[sr] = i;
-+ rs->alpha_to[i] = sr;
-+ sr <<= 1;
-+ if (sr & (1 << symsize))
-+ sr ^= gfpoly;
-+ sr &= rs->nn;
-+ }
-+ /* If it's not primitive, exit */
-+ if(sr != 1)
-+ goto errpol;
-+
-+ /* Find prim-th root of 1, used in decoding */
-+ for(iprim = 1; (iprim % prim) != 0; iprim += rs->nn);
-+ /* prim-th root of 1, index form */
-+ rs->iprim = iprim / prim;
-+
-+ /* Form RS code generator polynomial from its roots */
-+ rs->genpoly[0] = 1;
-+ for (i = 0, root = fcr * prim; i < nroots; i++, root += prim) {
-+ rs->genpoly[i + 1] = 1;
-+ /* Multiply rs->genpoly[] by @**(root + x) */
-+ for (j = i; j > 0; j--) {
-+ if (rs->genpoly[j] != 0) {
-+ rs->genpoly[j] = rs->genpoly[j -1] ^
-+ rs->alpha_to[rs_modnn(rs,
-+ rs->index_of[rs->genpoly[j]] + root)];
-+ } else
-+ rs->genpoly[j] = rs->genpoly[j - 1];
-+ }
-+ /* rs->genpoly[0] can never be zero */
-+ rs->genpoly[0] =
-+ rs->alpha_to[rs_modnn(rs,
-+ rs->index_of[rs->genpoly[0]] + root)];
-+ }
-+ /* convert rs->genpoly[] to index form for quicker encoding */
-+ for (i = 0; i <= nroots; i++)
-+ rs->genpoly[i] = rs->index_of[rs->genpoly[i]];
-+ return rs;
-+
-+ /* Error exit */
-+errpol:
-+ kfree(rs->genpoly);
-+erridx:
-+ kfree(rs->index_of);
-+erralp:
-+ kfree(rs->alpha_to);
-+errrs:
-+ kfree(rs);
-+ return NULL;
-+}
-+
-+
-+/**
-+ * free_rs - Free the rs control structure, if its not longer used
-+ *
-+ * @rs: the control structure which is not longer used by the
-+ * caller
-+ */
-+void free_rs(struct rs_control *rs)
-+{
-+ down(&rslistlock);
-+ rs->users--;
-+ if(!rs->users) {
-+ list_del(&rs->list);
-+ kfree(rs->alpha_to);
-+ kfree(rs->index_of);
-+ kfree(rs->genpoly);
-+ kfree(rs);
-+ }
-+ up(&rslistlock);
-+}
-+
-+/**
-+ * init_rs - Find a matching or allocate a new rs control structure
-+ *
-+ * @symsize: the symbol size (number of bits)
-+ * @gfpoly: the extended Galois field generator polynomial coefficients,
-+ * with the 0th coefficient in the low order bit. The polynomial
-+ * must be primitive;
-+ * @fcr: the first consecutive root of the rs code generator polynomial
-+ * in index form
-+ * @prim: primitive element to generate polynomial roots
-+ * @nroots: RS code generator polynomial degree (number of roots)
-+ */
-+struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
-+ int nroots)
-+{
-+ struct list_head *tmp;
-+ struct rs_control *rs;
-+
-+ /* Sanity checks */
-+ if (symsize < 1)
-+ return NULL;
-+ if (fcr < 0 || fcr >= (1<<symsize))
-+ return NULL;
-+ if (prim <= 0 || prim >= (1<<symsize))
-+ return NULL;
-+ if (nroots < 0 || nroots >= (1<<symsize) || nroots > 8)
-+ return NULL;
-+
-+ down(&rslistlock);
-+
-+ /* Walk through the list and look for a matching entry */
-+ list_for_each(tmp, &rslist) {
-+ rs = list_entry(tmp, struct rs_control, list);
-+ if (symsize != rs->mm)
-+ continue;
-+ if (gfpoly != rs->gfpoly)
-+ continue;
-+ if (fcr != rs->fcr)
-+ continue;
-+ if (prim != rs->prim)
-+ continue;
-+ if (nroots != rs->nroots)
-+ continue;
-+ /* We have a matching one already */
-+ rs->users++;
-+ goto out;
-+ }
-+
-+ /* Create a new one */
-+ rs = rs_init(symsize, gfpoly, fcr, prim, nroots);
-+ if (rs) {
-+ rs->users = 1;
-+ list_add(&rs->list, &rslist);
-+ }
-+out:
-+ up(&rslistlock);
-+ return rs;
-+}
-+
-+#ifdef CONFIG_REED_SOLOMON_ENC8
-+/**
-+ * encode_rs8 - Calculate the parity for data values (8bit data width)
-+ *
-+ * @rs: the rs control structure
-+ * @data: data field of a given type
-+ * @len: data length
-+ * @par: parity data, must be initialized by caller (usually all 0)
-+ * @invmsk: invert data mask (will be xored on data)
-+ *
-+ * The parity uses a uint16_t data type to enable
-+ * symbol size > 8. The calling code must take care of encoding of the
-+ * syndrome result for storage itself.
-+ */
-+int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par,
-+ uint16_t invmsk)
-+{
-+#include "encode_rs.c"
-+}
-+EXPORT_SYMBOL_GPL(encode_rs8);
-+#endif
-+
-+#ifdef CONFIG_REED_SOLOMON_DEC8
-+/**
-+ * decode_rs8 - Decode codeword (8bit data width)
-+ *
-+ * @rs: the rs control structure
-+ * @data: data field of a given type
-+ * @par: received parity data field
-+ * @len: data length
-+ * @s: syndrome data field (if NULL, syndrome is calculated)
-+ * @no_eras: number of erasures
-+ * @eras_pos: position of erasures, can be NULL
-+ * @invmsk: invert data mask (will be xored on data, not on parity!)
-+ * @corr: buffer to store correction bitmask on eras_pos
-+ *
-+ * The syndrome and parity uses a uint16_t data type to enable
-+ * symbol size > 8. The calling code must take care of decoding of the
-+ * syndrome result and the received parity before calling this code.
-+ */
-+int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len,
-+ uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
-+ uint16_t *corr)
-+{
-+#include "decode_rs.c"
-+}
-+EXPORT_SYMBOL_GPL(decode_rs8);
-+#endif
-+
-+#ifdef CONFIG_REED_SOLOMON_ENC16
-+/**
-+ * encode_rs16 - Calculate the parity for data values (16bit data width)
-+ *
-+ * @rs: the rs control structure
-+ * @data: data field of a given type
-+ * @len: data length
-+ * @par: parity data, must be initialized by caller (usually all 0)
-+ * @invmsk: invert data mask (will be xored on data, not on parity!)
-+ *
-+ * Each field in the data array contains up to symbol size bits of valid data.
-+ */
-+int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par,
-+ uint16_t invmsk)
-+{
-+#include "encode_rs.c"
-+}
-+EXPORT_SYMBOL_GPL(encode_rs16);
-+#endif
-+
-+#ifdef CONFIG_REED_SOLOMON_DEC16
-+/**
-+ * decode_rs16 - Decode codeword (16bit data width)
-+ *
-+ * @rs: the rs control structure
-+ * @data: data field of a given type
-+ * @par: received parity data field
-+ * @len: data length
-+ * @s: syndrome data field (if NULL, syndrome is calculated)
-+ * @no_eras: number of erasures
-+ * @eras_pos: position of erasures, can be NULL
-+ * @invmsk: invert data mask (will be xored on data, not on parity!)
-+ * @corr: buffer to store correction bitmask on eras_pos
-+ *
-+ * Each field in the data array contains up to symbol size bits of valid data.
-+ */
-+int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len,
-+ uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
-+ uint16_t *corr)
-+{
-+#include "decode_rs.c"
-+}
-+EXPORT_SYMBOL_GPL(decode_rs16);
-+#endif
-+
-+EXPORT_SYMBOL_GPL(init_rs);
-+EXPORT_SYMBOL_GPL(free_rs);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Reed Solomon encoder/decoder");
-+MODULE_AUTHOR("Phil Karn, Thomas Gleixner");
-+
---- linux-2.4.21/mm/swap.c~swap-performance
-+++ linux-2.4.21/mm/swap.c
-@@ -28,7 +28,7 @@
- int page_cluster;
-
- pager_daemon_t pager_daemon = {
-- 512, /* base number for calculating the number of tries */
-+ 128, /* base number for calculating the number of tries */
- SWAP_CLUSTER_MAX, /* minimum number of tries */
- 8, /* do swap I/O in clusters of this size */
- };
---- linux-2.4.21/mm/vmalloc.c~vmalloc
-+++ linux-2.4.21/mm/vmalloc.c
-@@ -183,6 +183,9 @@
- return NULL;
-
- size += PAGE_SIZE;
-+#ifdef VMALLOC_ALIGN
-+ size = (size + VMALLOC_ALIGN - 1) & ~(VMALLOC_ALIGN - 1);
-+#endif
- if (!size) {
- kfree (area);
- return NULL;
---- linux-2.4.21/net/bluetooth/Config.in~bluetooth
-+++ linux-2.4.21/net/bluetooth/Config.in
-@@ -13,6 +13,8 @@
- dep_tristate 'SCO links support' CONFIG_BLUEZ_SCO $CONFIG_BLUEZ
- source net/bluetooth/rfcomm/Config.in
- source net/bluetooth/bnep/Config.in
-+ source net/bluetooth/cmtp/Config.in
-+ source net/bluetooth/hidp/Config.in
- source drivers/bluetooth/Config.in
- fi
-
---- linux-2.4.21/net/bluetooth/Makefile~bluetooth
-+++ linux-2.4.21/net/bluetooth/Makefile
-@@ -5,7 +5,7 @@
- O_TARGET := bluetooth.o
-
- list-multi := bluez.o
--export-objs := syms.o
-+export-objs := syms.o l2cap.o
-
- bluez-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o
-
-@@ -15,6 +15,8 @@
-
- subdir-$(CONFIG_BLUEZ_RFCOMM) += rfcomm
- subdir-$(CONFIG_BLUEZ_BNEP) += bnep
-+subdir-$(CONFIG_BLUEZ_CMTP) += cmtp
-+subdir-$(CONFIG_BLUEZ_HIDP) += hidp
-
- ifeq ($(CONFIG_BLUEZ_RFCOMM),y)
- obj-y += rfcomm/rfcomm.o
-@@ -24,6 +26,14 @@
- obj-y += bnep/bnep.o
- endif
-
-+ifeq ($(CONFIG_BLUEZ_CMTP),y)
-+obj-y += cmtp/cmtp.o
-+endif
-+
-+ifeq ($(CONFIG_BLUEZ_HIDP),y)
-+obj-y += hidp/hidp.o
-+endif
-+
- include $(TOPDIR)/Rules.make
-
- bluez.o: $(bluez-objs)
---- linux-2.4.21/net/bluetooth/af_bluetooth.c~bluetooth
-+++ linux-2.4.21/net/bluetooth/af_bluetooth.c
-@@ -27,7 +27,7 @@
- *
- * $Id: af_bluetooth.c,v 1.8 2002/07/22 20:32:54 maxk Exp $
- */
--#define VERSION "2.2"
-+#define VERSION "2.4"
-
- #include <linux/config.h>
- #include <linux/module.h>
-@@ -57,7 +57,7 @@
- #endif
-
- /* Bluetooth sockets */
--#define BLUEZ_MAX_PROTO 5
-+#define BLUEZ_MAX_PROTO 7
- static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO];
-
- int bluez_sock_register(int proto, struct net_proto_family *ops)
-@@ -221,12 +221,11 @@
- unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
- {
- struct sock *sk = sock->sk;
-- unsigned int mask;
-+ unsigned int mask = 0;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- poll_wait(file, sk->sleep, wait);
-- mask = 0;
-
- if (sk->err || !skb_queue_empty(&sk->error_queue))
- mask |= POLLERR;
-@@ -242,9 +241,11 @@
- if (sk->state == BT_CLOSED)
- mask |= POLLHUP;
-
-- if (sk->state == BT_CONNECT || sk->state == BT_CONNECT2)
-+ if (sk->state == BT_CONNECT ||
-+ sk->state == BT_CONNECT2 ||
-+ sk->state == BT_CONFIG)
- return mask;
--
-+
- if (sock_writeable(sk))
- mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
- else
-@@ -253,39 +254,35 @@
- return mask;
- }
-
--int bluez_sock_w4_connect(struct sock *sk, int flags)
-+int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
- {
- DECLARE_WAITQUEUE(wait, current);
-- long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
- int err = 0;
-
- BT_DBG("sk %p", sk);
-
- add_wait_queue(sk->sleep, &wait);
-- while (sk->state != BT_CONNECTED) {
-+ while (sk->state != state) {
- set_current_state(TASK_INTERRUPTIBLE);
-+
- if (!timeo) {
- err = -EAGAIN;
- break;
- }
-
-+ if (signal_pending(current)) {
-+ err = sock_intr_errno(timeo);
-+ break;
-+ }
-+
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
-
-- err = 0;
-- if (sk->state == BT_CONNECTED)
-- break;
--
- if (sk->err) {
- err = sock_error(sk);
- break;
- }
--
-- if (signal_pending(current)) {
-- err = sock_intr_errno(timeo);
-- break;
-- }
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(sk->sleep, &wait);
---- linux-2.4.21/net/bluetooth/bnep/core.c~bluetooth
-+++ linux-2.4.21/net/bluetooth/bnep/core.c
-@@ -63,7 +63,7 @@
- #define BT_DBG(D...)
- #endif
-
--#define VERSION "1.1"
-+#define VERSION "1.2"
-
- static LIST_HEAD(bnep_session_list);
- static DECLARE_RWSEM(bnep_session_sem);
-@@ -113,13 +113,28 @@
- return bnep_send(s, &rsp, sizeof(rsp));
- }
-
-+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+static inline void bnep_set_default_proto_filter(struct bnep_session *s)
-+{
-+ /* (IPv4, ARP) */
-+ s->proto_filter[0].start = htons(0x0800);
-+ s->proto_filter[0].end = htons(0x0806);
-+ /* (RARP, AppleTalk) */
-+ s->proto_filter[1].start = htons(0x8035);
-+ s->proto_filter[1].end = htons(0x80F3);
-+ /* (IPX, IPv6) */
-+ s->proto_filter[2].start = htons(0x8137);
-+ s->proto_filter[2].end = htons(0x86DD);
-+}
-+#endif
-+
- static int bnep_ctrl_set_netfilter(struct bnep_session *s, u16 *data, int len)
- {
- int n;
-
- if (len < 2)
- return -EILSEQ;
--
-+
- n = ntohs(get_unaligned(data));
- data++; len -= 2;
-
-@@ -141,9 +156,13 @@
- BT_DBG("proto filter start %d end %d",
- f[i].start, f[i].end);
- }
-+
- if (i < BNEP_MAX_PROTO_FILTERS)
- memset(f + i, 0, sizeof(*f));
-
-+ if (n == 0)
-+ bnep_set_default_proto_filter(s);
-+
- bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
- } else {
- bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
-@@ -160,7 +179,7 @@
-
- if (len < 2)
- return -EILSEQ;
--
-+
- n = ntohs(get_unaligned((u16 *) data));
- data += 2; len -= 2;
-
-@@ -214,7 +233,7 @@
- int err = 0;
-
- data++; len--;
--
-+
- switch (cmd) {
- case BNEP_CMD_NOT_UNDERSTOOD:
- case BNEP_SETUP_CONN_REQ:
-@@ -268,13 +287,13 @@
- /* Unknown extension, skip it. */
- break;
- }
--
-+
- if (!skb_pull(skb, h->len)) {
- err = -EILSEQ;
- break;
- }
- } while (!err && (h->type & BNEP_EXT_HEADER));
--
-+
- return err;
- }
-
-@@ -300,7 +319,7 @@
-
- if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES)
- goto badframe;
--
-+
- if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
- bnep_rx_control(s, skb->data, skb->len);
- kfree_skb(skb);
-@@ -326,7 +345,7 @@
- goto badframe;
- s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
- }
--
-+
- /* We have to alloc new skb and copy data here :(. Because original skb
- * may not be modified and because of the alignment requirements. */
- nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
-@@ -342,7 +361,7 @@
- case BNEP_COMPRESSED:
- memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
- break;
--
-+
- case BNEP_COMPRESSED_SRC_ONLY:
- memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
- memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
-@@ -362,7 +381,7 @@
-
- memcpy(__skb_put(nskb, skb->len), skb->data, skb->len);
- kfree_skb(skb);
--
-+
- s->stats.rx_packets++;
- nskb->dev = dev;
- nskb->ip_summed = CHECKSUM_UNNECESSARY;
-@@ -426,9 +445,9 @@
- send:
- iv[il++] = (struct iovec) { skb->data, skb->len };
- len += skb->len;
--
-+
- /* FIXME: linearize skb */
--
-+
- s->msg.msg_iov = iv;
- s->msg.msg_iovlen = il;
- len = sock->ops->sendmsg(sock, &s->msg, len, NULL);
-@@ -453,16 +472,16 @@
-
- BT_DBG("");
-
-- daemonize(); reparent_to_init();
-+ daemonize(); reparent_to_init();
-
-- sprintf(current->comm, "kbnepd %s", dev->name);
--
-- sigfillset(&current->blocked);
-+ sprintf(current->comm, "kbnepd %s", dev->name);
-+
-+ sigfillset(&current->blocked);
- flush_signals(current);
-
- current->nice = -15;
-
-- set_fs(KERNEL_DS);
-+ set_fs(KERNEL_DS);
-
- init_waitqueue_entry(&wait, current);
- add_wait_queue(sk->sleep, &wait);
-@@ -477,13 +496,13 @@
-
- if (sk->state != BT_CONNECTED)
- break;
--
-+
- // TX
- while ((skb = skb_dequeue(&sk->write_queue)))
- if (bnep_tx_frame(s, skb))
- break;
- netif_wake_queue(dev);
--
-+
- schedule();
- }
- set_current_state(TASK_RUNNING);
-@@ -547,28 +566,19 @@
- s->sock = sock;
- s->role = req->role;
- s->state = BT_CONNECTED;
--
-+
- s->msg.msg_flags = MSG_NOSIGNAL;
-
- #ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
- /* Set default mc filter */
- set_bit(bnep_mc_hash(dev->broadcast), &s->mc_filter);
- #endif
--
-+
- #ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
- /* Set default protocol filter */
--
-- /* (IPv4, ARP) */
-- s->proto_filter[0].start = htons(0x0800);
-- s->proto_filter[0].end = htons(0x0806);
-- /* (RARP, AppleTalk) */
-- s->proto_filter[1].start = htons(0x8035);
-- s->proto_filter[1].end = htons(0x80F3);
-- /* (IPX, IPv6) */
-- s->proto_filter[2].start = htons(0x8137);
-- s->proto_filter[2].end = htons(0x86DD);
-+ bnep_set_default_proto_filter(s);
- #endif
--
-+
- dev->init = bnep_net_init;
- dev->priv = s;
- err = register_netdev(dev);
-@@ -577,7 +587,7 @@
- }
-
- __bnep_link_session(s);
--
-+
- err = kernel_thread(bnep_session, s, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
- if (err < 0) {
- /* Session thread start failed, gotta cleanup. */
-@@ -680,6 +690,8 @@
-
- static int __init bnep_init_module(void)
- {
-+ l2cap_load();
-+
- bnep_crc32_init();
- bnep_sock_init();
-
---- linux-2.4.21/net/bluetooth/bnep/sock.c~bluetooth
-+++ linux-2.4.21/net/bluetooth/bnep/sock.c
-@@ -55,36 +55,6 @@
- #define BT_DBG( A... )
- #endif
-
--static inline struct socket *socki_lookup(struct inode *inode)
--{
-- return &inode->u.socket_i;
--}
--
--static struct socket *sockfd_lookup(int fd, int *err)
--{
-- struct file *file;
-- struct inode *inode;
-- struct socket *sock;
--
-- if (!(file = fget(fd))) {
-- *err = -EBADF;
-- return NULL;
-- }
--
-- inode = file->f_dentry->d_inode;
-- if (!inode->i_sock || !(sock = socki_lookup(inode))) {
-- *err = -ENOTSOCK;
-- fput(file);
-- return NULL;
-- }
--
-- if (sock->file != file) {
-- printk(KERN_ERR "socki_lookup: socket file changed!\n");
-- sock->file = file;
-- }
-- return sock;
--}
--
- static int bnep_sock_release(struct socket *sock)
- {
- struct sock *sk = sock->sk;
-@@ -124,8 +94,10 @@
- if (!nsock)
- return err;
-
-- if (nsock->sk->state != BT_CONNECTED)
-+ if (nsock->sk->state != BT_CONNECTED) {
-+ fput(nsock->file);
- return -EBADFD;
-+ }
-
- err = bnep_add_connection(&ca, nsock);
- if (!err) {
---- /dev/null
-+++ linux-2.4.21/net/bluetooth/cmtp/Config.in
-@@ -0,0 +1,7 @@
-+#
-+# Bluetooth CMTP layer configuration
-+#
-+
-+if [ "$CONFIG_ISDN" = "y" -o "$CONFIG_ISDN" = "m" ]; then
-+ dep_tristate 'CMTP protocol support' CONFIG_BLUEZ_CMTP $CONFIG_ISDN_CAPI $CONFIG_BLUEZ_L2CAP
-+fi
---- /dev/null
-+++ linux-2.4.21/net/bluetooth/cmtp/Makefile
-@@ -0,0 +1,10 @@
-+#
-+# Makefile for the Linux Bluetooth CMTP layer
-+#
-+
-+O_TARGET := cmtp.o
-+
-+obj-y := core.o sock.o capi.o
-+obj-m += $(O_TARGET)
-+
-+include $(TOPDIR)/Rules.make
---- /dev/null
-+++ linux-2.4.21/net/bluetooth/cmtp/capi.c
-@@ -0,0 +1,707 @@
-+/*
-+ CMTP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002-2003 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 <net/sock.h>
-+
-+#include <linux/capi.h>
-+
-+#include "../drivers/isdn/avmb1/capilli.h"
-+#include "../drivers/isdn/avmb1/capicmd.h"
-+#include "../drivers/isdn/avmb1/capiutil.h"
-+
-+#include "cmtp.h"
-+
-+#ifndef CONFIG_BLUEZ_CMTP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define REVISION "1.0"
-+
-+#define CAPI_INTEROPERABILITY 0x20
-+
-+#define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
-+#define CAPI_INTEROPERABILITY_CONF CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
-+#define CAPI_INTEROPERABILITY_IND CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
-+#define CAPI_INTEROPERABILITY_RESP CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
-+
-+#define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2)
-+#define CAPI_INTEROPERABILITY_CONF_LEN (CAPI_MSG_BASELEN + 4)
-+#define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2)
-+#define CAPI_INTEROPERABILITY_RESP_LEN (CAPI_MSG_BASELEN + 2)
-+
-+#define CAPI_FUNCTION_REGISTER 0
-+#define CAPI_FUNCTION_RELEASE 1
-+#define CAPI_FUNCTION_GET_PROFILE 2
-+#define CAPI_FUNCTION_GET_MANUFACTURER 3
-+#define CAPI_FUNCTION_GET_VERSION 4
-+#define CAPI_FUNCTION_GET_SERIAL_NUMBER 5
-+#define CAPI_FUNCTION_MANUFACTURER 6
-+#define CAPI_FUNCTION_LOOPBACK 7
-+
-+static struct capi_driver_interface *di;
-+
-+
-+#define CMTP_MSGNUM 1
-+#define CMTP_APPLID 2
-+#define CMTP_MAPPING 3
-+
-+static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
-+{
-+ struct cmtp_application *app = kmalloc(sizeof(*app), GFP_KERNEL);
-+
-+ BT_DBG("session %p application %p appl %d", session, app, appl);
-+
-+ if (!app)
-+ return NULL;
-+
-+ memset(app, 0, sizeof(*app));
-+
-+ app->state = BT_OPEN;
-+ app->appl = appl;
-+
-+ list_add_tail(&app->list, &session->applications);
-+
-+ return app;
-+}
-+
-+static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
-+{
-+ BT_DBG("session %p application %p", session, app);
-+
-+ if (app) {
-+ list_del(&app->list);
-+ kfree(app);
-+ }
-+}
-+
-+static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
-+{
-+ struct cmtp_application *app;
-+ struct list_head *p, *n;
-+
-+ list_for_each_safe(p, n, &session->applications) {
-+ app = list_entry(p, struct cmtp_application, list);
-+ switch (pattern) {
-+ case CMTP_MSGNUM:
-+ if (app->msgnum == value)
-+ return app;
-+ break;
-+ case CMTP_APPLID:
-+ if (app->appl == value)
-+ return app;
-+ break;
-+ case CMTP_MAPPING:
-+ if (app->mapping == value)
-+ return app;
-+ break;
-+ }
-+ }
-+
-+ return NULL;
-+}
-+
-+static int cmtp_msgnum_get(struct cmtp_session *session)
-+{
-+ session->msgnum++;
-+
-+ if ((session->msgnum & 0xff) > 200)
-+ session->msgnum = CMTP_INITIAL_MSGNUM + 1;
-+
-+ return session->msgnum;
-+}
-+
-+
-+static void cmtp_send_interopmsg(struct cmtp_session *session,
-+ __u8 subcmd, __u16 appl, __u16 msgnum,
-+ __u16 function, unsigned char *buf, int len)
-+{
-+ struct sk_buff *skb;
-+ unsigned char *s;
-+
-+ BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
-+
-+ if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) {
-+ BT_ERR("Can't allocate memory for interoperability packet");
-+ return;
-+ }
-+
-+ s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
-+
-+ capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
-+ capimsg_setu16(s, 2, appl);
-+ capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
-+ capimsg_setu8 (s, 5, subcmd);
-+ capimsg_setu16(s, 6, msgnum);
-+
-+ /* Interoperability selector (Bluetooth Device Management) */
-+ capimsg_setu16(s, 8, 0x0001);
-+
-+ capimsg_setu8 (s, 10, 3 + len);
-+ capimsg_setu16(s, 11, function);
-+ capimsg_setu8 (s, 13, len);
-+
-+ if (len > 0)
-+ memcpy(s + 14, buf, len);
-+
-+ cmtp_send_capimsg(session, skb);
-+}
-+
-+static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
-+{
-+ struct capi_ctr *ctrl = session->ctrl;
-+ struct cmtp_application *application;
-+ __u16 appl, msgnum, func, info;
-+ __u32 controller;
-+
-+ BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+ switch (CAPIMSG_SUBCOMMAND(skb->data)) {
-+ case CAPI_CONF:
-+ func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
-+ info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
-+
-+ switch (func) {
-+ case CAPI_FUNCTION_REGISTER:
-+ msgnum = CAPIMSG_MSGID(skb->data);
-+
-+ application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
-+ if (application) {
-+ application->state = BT_CONNECTED;
-+ application->msgnum = 0;
-+ application->mapping = CAPIMSG_APPID(skb->data);
-+ wake_up_interruptible(&session->wait);
-+ }
-+
-+ break;
-+
-+ case CAPI_FUNCTION_RELEASE:
-+ appl = CAPIMSG_APPID(skb->data);
-+
-+ application = cmtp_application_get(session, CMTP_MAPPING, appl);
-+ if (application) {
-+ application->state = BT_CLOSED;
-+ application->msgnum = 0;
-+ wake_up_interruptible(&session->wait);
-+ }
-+
-+ break;
-+
-+ case CAPI_FUNCTION_GET_PROFILE:
-+ controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
-+ msgnum = CAPIMSG_MSGID(skb->data);
-+
-+ if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
-+ session->ncontroller = controller;
-+ wake_up_interruptible(&session->wait);
-+ break;
-+ }
-+
-+ if (!info && ctrl) {
-+ memcpy(&ctrl->profile,
-+ skb->data + CAPI_MSG_BASELEN + 11,
-+ sizeof(capi_profile));
-+ session->state = BT_CONNECTED;
-+ ctrl->ready(ctrl);
-+ }
-+
-+ break;
-+
-+ case CAPI_FUNCTION_GET_MANUFACTURER:
-+ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
-+
-+ if (!info && ctrl) {
-+ strncpy(ctrl->manu,
-+ skb->data + CAPI_MSG_BASELEN + 15,
-+ skb->data[CAPI_MSG_BASELEN + 14]);
-+ }
-+
-+ break;
-+
-+ case CAPI_FUNCTION_GET_VERSION:
-+ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
-+
-+ if (!info && ctrl) {
-+ ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
-+ ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
-+ ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
-+ ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
-+ }
-+
-+ break;
-+
-+ case CAPI_FUNCTION_GET_SERIAL_NUMBER:
-+ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
-+
-+ if (!info && ctrl) {
-+ memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
-+ strncpy(ctrl->serial,
-+ skb->data + CAPI_MSG_BASELEN + 17,
-+ skb->data[CAPI_MSG_BASELEN + 16]);
-+ }
-+
-+ break;
-+ }
-+
-+ break;
-+
-+ case CAPI_IND:
-+ func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
-+
-+ if (func == CAPI_FUNCTION_LOOPBACK) {
-+ appl = CAPIMSG_APPID(skb->data);
-+ msgnum = CAPIMSG_MSGID(skb->data);
-+ cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
-+ skb->data + CAPI_MSG_BASELEN + 6,
-+ skb->data[CAPI_MSG_BASELEN + 5]);
-+ }
-+
-+ break;
-+ }
-+
-+ kfree_skb(skb);
-+}
-+
-+void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
-+{
-+ struct capi_ctr *ctrl = session->ctrl;
-+ struct cmtp_application *application;
-+ __u16 cmd, appl, info;
-+ __u32 ncci, contr;
-+
-+ BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+ if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
-+ cmtp_recv_interopmsg(session, skb);
-+ return;
-+ }
-+
-+ if (session->flags & (1 << CMTP_LOOPBACK)) {
-+ kfree_skb(skb);
-+ return;
-+ }
-+
-+ cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
-+ appl = CAPIMSG_APPID(skb->data);
-+ contr = CAPIMSG_CONTROL(skb->data);
-+
-+ application = cmtp_application_get(session, CMTP_MAPPING, appl);
-+ if (application) {
-+ appl = application->appl;
-+ CAPIMSG_SETAPPID(skb->data, appl);
-+ } else {
-+ BT_ERR("Can't find application with id %d", appl);
-+ kfree_skb(skb);
-+ return;
-+ }
-+
-+ if ((contr & 0x7f) == 0x01) {
-+ contr = (contr & 0xffffff80) | session->num;
-+ CAPIMSG_SETCONTROL(skb->data, contr);
-+ }
-+
-+ if (!ctrl) {
-+ BT_ERR("Can't find controller %d for message", session->num);
-+ kfree_skb(skb);
-+ return;
-+ }
-+
-+ switch (cmd) {
-+ case CAPI_CONNECT_B3_CONF:
-+ ncci = CAPIMSG_NCCI(skb->data);
-+ info = CAPIMSG_U16(skb->data, 12);
-+
-+ BT_DBG("CONNECT_B3_CONF ncci 0x%02x info 0x%02x", ncci, info);
-+
-+ if (info == 0)
-+ ctrl->new_ncci(ctrl, appl, ncci, 8);
-+
-+ ctrl->handle_capimsg(ctrl, appl, skb);
-+ break;
-+
-+ case CAPI_CONNECT_B3_IND:
-+ ncci = CAPIMSG_NCCI(skb->data);
-+
-+ BT_DBG("CONNECT_B3_IND ncci 0x%02x", ncci);
-+
-+ ctrl->new_ncci(ctrl, appl, ncci, 8);
-+ ctrl->handle_capimsg(ctrl, appl, skb);
-+ break;
-+
-+ case CAPI_DISCONNECT_B3_IND:
-+ ncci = CAPIMSG_NCCI(skb->data);
-+
-+ BT_DBG("DISCONNECT_B3_IND ncci 0x%02x", ncci);
-+
-+ if (ncci == 0xffffffff)
-+ BT_ERR("DISCONNECT_B3_IND with ncci 0xffffffff");
-+
-+ ctrl->handle_capimsg(ctrl, appl, skb);
-+ ctrl->free_ncci(ctrl, appl, ncci);
-+ break;
-+
-+ default:
-+ ctrl->handle_capimsg(ctrl, appl, skb);
-+ break;
-+ }
-+}
-+
-+void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
-+{
-+ struct cmtp_scb *scb = (void *) skb->cb;
-+
-+ BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+ scb->id = -1;
-+ scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
-+
-+ skb_queue_tail(&session->transmit, skb);
-+
-+ cmtp_schedule(session);
-+}
-+
-+
-+static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
-+{
-+ BT_DBG("ctrl %p data %p", ctrl, data);
-+
-+ return -EIO;
-+}
-+
-+static void cmtp_reset_ctr(struct capi_ctr *ctrl)
-+{
-+ BT_DBG("ctrl %p", ctrl);
-+
-+ ctrl->reseted(ctrl);
-+}
-+
-+static void cmtp_remove_ctr(struct capi_ctr *ctrl)
-+{
-+ struct cmtp_session *session = ctrl->driverdata;
-+
-+ BT_DBG("ctrl %p", ctrl);
-+
-+ ctrl->suspend_output(ctrl);
-+
-+ atomic_inc(&session->terminate);
-+ cmtp_schedule(session);
-+}
-+
-+static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct cmtp_session *session = ctrl->driverdata;
-+ struct cmtp_application *application;
-+ unsigned long timeo = CMTP_INTEROP_TIMEOUT;
-+ unsigned char buf[8];
-+ int err = 0, nconn, want = rp->level3cnt;
-+
-+ BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
-+ ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
-+
-+ application = cmtp_application_add(session, appl);
-+ if (!application) {
-+ BT_ERR("Can't allocate memory for new application");
-+ ctrl->appl_released(ctrl, appl);
-+ return;
-+ }
-+
-+ if (want < 0)
-+ nconn = ctrl->profile.nbchannel * -want;
-+ else
-+ nconn = want;
-+
-+ if (nconn == 0)
-+ nconn = ctrl->profile.nbchannel;
-+
-+ capimsg_setu16(buf, 0, nconn);
-+ capimsg_setu16(buf, 2, rp->datablkcnt);
-+ capimsg_setu16(buf, 4, rp->datablklen);
-+
-+ application->state = BT_CONFIG;
-+ application->msgnum = cmtp_msgnum_get(session);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
-+ CAPI_FUNCTION_REGISTER, buf, 6);
-+
-+ add_wait_queue(&session->wait, &wait);
-+ while (1) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (!timeo) {
-+ err = -EAGAIN;
-+ break;
-+ }
-+
-+ if (application->state == BT_CLOSED) {
-+ err = -application->err;
-+ break;
-+ }
-+
-+ if (application->state == BT_CONNECTED)
-+ break;
-+
-+ if (signal_pending(current)) {
-+ err = -EINTR;
-+ break;
-+ }
-+
-+ timeo = schedule_timeout(timeo);
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&session->wait, &wait);
-+
-+ if (err) {
-+ ctrl->appl_released(ctrl, appl);
-+ cmtp_application_del(session, application);
-+ return;
-+ }
-+
-+ ctrl->appl_registered(ctrl, appl);
-+}
-+
-+static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct cmtp_session *session = ctrl->driverdata;
-+ struct cmtp_application *application;
-+ unsigned long timeo = CMTP_INTEROP_TIMEOUT;
-+
-+ BT_DBG("ctrl %p appl %d", ctrl, appl);
-+
-+ application = cmtp_application_get(session, CMTP_APPLID, appl);
-+ if (!application) {
-+ BT_ERR("Can't find application");
-+ return;
-+ }
-+
-+ application->msgnum = cmtp_msgnum_get(session);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
-+ CAPI_FUNCTION_RELEASE, NULL, 0);
-+
-+ add_wait_queue(&session->wait, &wait);
-+ while (timeo) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (application->state == BT_CLOSED)
-+ break;
-+
-+ if (signal_pending(current))
-+ break;
-+
-+ timeo = schedule_timeout(timeo);
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&session->wait, &wait);
-+
-+ cmtp_application_del(session, application);
-+ ctrl->appl_released(ctrl, appl);
-+}
-+
-+static void cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
-+{
-+ struct cmtp_session *session = ctrl->driverdata;
-+ struct cmtp_application *application;
-+ __u16 appl;
-+ __u32 contr;
-+
-+ BT_DBG("ctrl %p skb %p", ctrl, skb);
-+
-+ appl = CAPIMSG_APPID(skb->data);
-+ contr = CAPIMSG_CONTROL(skb->data);
-+
-+ application = cmtp_application_get(session, CMTP_APPLID, appl);
-+ if ((!application) || (application->state != BT_CONNECTED)) {
-+ BT_ERR("Can't find application with id %d", appl);
-+ kfree_skb(skb);
-+ return;
-+ }
-+
-+ CAPIMSG_SETAPPID(skb->data, application->mapping);
-+
-+ if ((contr & 0x7f) == session->num) {
-+ contr = (contr & 0xffffff80) | 0x01;
-+ CAPIMSG_SETCONTROL(skb->data, contr);
-+ }
-+
-+ cmtp_send_capimsg(session, skb);
-+}
-+
-+static char *cmtp_procinfo(struct capi_ctr *ctrl)
-+{
-+ return "CAPI Message Transport Protocol";
-+}
-+
-+static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
-+{
-+ struct cmtp_session *session = ctrl->driverdata;
-+ struct cmtp_application *app;
-+ struct list_head *p, *n;
-+ int len = 0;
-+
-+ len += sprintf(page + len, "%s (Revision %s)\n\n", cmtp_procinfo(ctrl), REVISION);
-+ len += sprintf(page + len, "addr %s\n", session->name);
-+ len += sprintf(page + len, "ctrl %d\n", session->num);
-+
-+ list_for_each_safe(p, n, &session->applications) {
-+ app = list_entry(p, struct cmtp_application, list);
-+ len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping);
-+ }
-+
-+ if (off + count >= len)
-+ *eof = 1;
-+
-+ if (len < off)
-+ return 0;
-+
-+ *start = page + off;
-+
-+ return ((count < len - off) ? count : len - off);
-+}
-+
-+static struct capi_driver cmtp_driver = {
-+ name: "cmtp",
-+ revision: REVISION,
-+ load_firmware: cmtp_load_firmware,
-+ reset_ctr: cmtp_reset_ctr,
-+ remove_ctr: cmtp_remove_ctr,
-+ register_appl: cmtp_register_appl,
-+ release_appl: cmtp_release_appl,
-+ send_message: cmtp_send_message,
-+ procinfo: cmtp_procinfo,
-+ ctr_read_proc: cmtp_ctr_read_proc,
-+
-+ driver_read_proc: 0,
-+ add_card: 0,
-+};
-+
-+
-+int cmtp_attach_device(struct cmtp_session *session)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ unsigned long timeo = CMTP_INTEROP_TIMEOUT;
-+ unsigned char buf[4];
-+
-+ BT_DBG("session %p", session);
-+
-+ capimsg_setu32(buf, 0, 0);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
-+ CAPI_FUNCTION_GET_PROFILE, buf, 4);
-+
-+ add_wait_queue(&session->wait, &wait);
-+ while (timeo) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (session->ncontroller)
-+ break;
-+
-+ if (signal_pending(current))
-+ break;
-+
-+ timeo = schedule_timeout(timeo);
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&session->wait, &wait);
-+
-+ BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
-+
-+ if (!timeo)
-+ return -ETIMEDOUT;
-+
-+ if (!session->ncontroller)
-+ return -ENODEV;
-+
-+
-+ if (session->ncontroller > 1)
-+ BT_INFO("Setting up only CAPI controller 1");
-+
-+ if (!(session->ctrl = di->attach_ctr(&cmtp_driver, session->name, session))) {
-+ BT_ERR("Can't attach new controller");
-+ return -EBUSY;
-+ }
-+
-+ session->num = session->ctrl->cnr;
-+
-+ BT_DBG("session %p ctrl %p num %d", session, session->ctrl, session->num);
-+
-+ capimsg_setu32(buf, 0, 1);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
-+ CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
-+ CAPI_FUNCTION_GET_VERSION, buf, 4);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
-+ CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
-+ CAPI_FUNCTION_GET_PROFILE, buf, 4);
-+
-+ return 0;
-+}
-+
-+void cmtp_detach_device(struct cmtp_session *session)
-+{
-+ struct capi_ctr *ctrl = session->ctrl;
-+
-+ BT_DBG("session %p ctrl %p", session, ctrl);
-+
-+ if (!ctrl)
-+ return;
-+
-+ ctrl->reseted(ctrl);
-+
-+ di->detach_ctr(ctrl);
-+}
-+
-+int cmtp_init_capi(void)
-+{
-+ if (!(di = attach_capi_driver(&cmtp_driver))) {
-+ BT_ERR("Can't attach CAPI driver");
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+void cmtp_cleanup_capi(void)
-+{
-+ detach_capi_driver(&cmtp_driver);
-+}
---- /dev/null
-+++ linux-2.4.21/net/bluetooth/cmtp/cmtp.h
-@@ -0,0 +1,138 @@
-+/*
-+ CMTP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002-2003 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.
-+*/
-+
-+#ifndef __CMTP_H
-+#define __CMTP_H
-+
-+#include <linux/types.h>
-+#include <net/bluetooth/bluetooth.h>
-+
-+#define BTNAMSIZ 18
-+
-+/* CMTP ioctl defines */
-+#define CMTPCONNADD _IOW('C', 200, int)
-+#define CMTPCONNDEL _IOW('C', 201, int)
-+#define CMTPGETCONNLIST _IOR('C', 210, int)
-+#define CMTPGETCONNINFO _IOR('C', 211, int)
-+
-+#define CMTP_LOOPBACK 0
-+
-+struct cmtp_connadd_req {
-+ int sock; // Connected socket
-+ __u32 flags;
-+};
-+
-+struct cmtp_conndel_req {
-+ bdaddr_t bdaddr;
-+ __u32 flags;
-+};
-+
-+struct cmtp_conninfo {
-+ bdaddr_t bdaddr;
-+ __u32 flags;
-+ __u16 state;
-+ int num;
-+};
-+
-+struct cmtp_connlist_req {
-+ __u32 cnum;
-+ struct cmtp_conninfo *ci;
-+};
-+
-+int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock);
-+int cmtp_del_connection(struct cmtp_conndel_req *req);
-+int cmtp_get_connlist(struct cmtp_connlist_req *req);
-+int cmtp_get_conninfo(struct cmtp_conninfo *ci);
-+
-+/* CMTP session defines */
-+#define CMTP_INTEROP_TIMEOUT (HZ * 5)
-+#define CMTP_INITIAL_MSGNUM 0xff00
-+
-+struct cmtp_session {
-+ struct list_head list;
-+
-+ struct socket *sock;
-+
-+ bdaddr_t bdaddr;
-+
-+ unsigned long state;
-+ unsigned long flags;
-+
-+ uint mtu;
-+
-+ char name[BTNAMSIZ];
-+
-+ atomic_t terminate;
-+
-+ wait_queue_head_t wait;
-+
-+ int ncontroller;
-+ int num;
-+ struct capi_ctr *ctrl;
-+
-+ struct list_head applications;
-+
-+ unsigned long blockids;
-+ int msgnum;
-+
-+ struct sk_buff_head transmit;
-+
-+ struct sk_buff *reassembly[16];
-+};
-+
-+struct cmtp_application {
-+ struct list_head list;
-+
-+ unsigned long state;
-+ int err;
-+
-+ __u16 appl;
-+ __u16 mapping;
-+
-+ __u16 msgnum;
-+};
-+
-+struct cmtp_scb {
-+ int id;
-+ int data;
-+};
-+
-+int cmtp_attach_device(struct cmtp_session *session);
-+void cmtp_detach_device(struct cmtp_session *session);
-+
-+void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb);
-+void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb);
-+
-+static inline void cmtp_schedule(struct cmtp_session *session)
-+{
-+ struct sock *sk = session->sock->sk;
-+
-+ wake_up_interruptible(sk->sleep);
-+}
-+
-+/* CMTP init defines */
-+int cmtp_init_capi(void);
-+int cmtp_init_sockets(void);
-+void cmtp_cleanup_capi(void);
-+void cmtp_cleanup_sockets(void);
-+
-+#endif /* __CMTP_H */
---- /dev/null
-+++ linux-2.4.21/net/bluetooth/cmtp/core.c
-@@ -0,0 +1,515 @@
-+/*
-+ CMTP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002-2003 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 <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/l2cap.h>
-+
-+#include "cmtp.h"
-+
-+#ifndef CONFIG_BLUEZ_CMTP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define VERSION "1.0"
-+
-+static DECLARE_RWSEM(cmtp_session_sem);
-+static LIST_HEAD(cmtp_session_list);
-+
-+static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
-+{
-+ struct cmtp_session *session;
-+ struct list_head *p;
-+
-+ BT_DBG("");
-+
-+ list_for_each(p, &cmtp_session_list) {
-+ session = list_entry(p, struct cmtp_session, list);
-+ if (!bacmp(bdaddr, &session->bdaddr))
-+ return session;
-+ }
-+ return NULL;
-+}
-+
-+static void __cmtp_link_session(struct cmtp_session *session)
-+{
-+ MOD_INC_USE_COUNT;
-+ list_add(&session->list, &cmtp_session_list);
-+}
-+
-+static void __cmtp_unlink_session(struct cmtp_session *session)
-+{
-+ list_del(&session->list);
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
-+{
-+ bacpy(&ci->bdaddr, &session->bdaddr);
-+
-+ ci->flags = session->flags;
-+ ci->state = session->state;
-+
-+ ci->num = session->num;
-+}
-+
-+
-+static inline int cmtp_alloc_block_id(struct cmtp_session *session)
-+{
-+ int i, id = -1;
-+
-+ for (i = 0; i < 16; i++)
-+ if (!test_and_set_bit(i, &session->blockids)) {
-+ id = i;
-+ break;
-+ }
-+
-+ return id;
-+}
-+
-+static inline void cmtp_free_block_id(struct cmtp_session *session, int id)
-+{
-+ clear_bit(id, &session->blockids);
-+}
-+
-+static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count)
-+{
-+ struct sk_buff *skb = session->reassembly[id], *nskb;
-+ int size;
-+
-+ BT_DBG("session %p buf %p count %d", session, buf, count);
-+
-+ size = (skb) ? skb->len + count : count;
-+
-+ if (!(nskb = alloc_skb(size, GFP_ATOMIC))) {
-+ BT_ERR("Can't allocate memory for CAPI message");
-+ return;
-+ }
-+
-+ if (skb && (skb->len > 0))
-+ memcpy(skb_put(nskb, skb->len), skb->data, skb->len);
-+
-+ memcpy(skb_put(nskb, count), buf, count);
-+
-+ session->reassembly[id] = nskb;
-+
-+ if (skb)
-+ kfree_skb(skb);
-+}
-+
-+static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
-+{
-+ __u8 hdr, hdrlen, id;
-+ __u16 len;
-+
-+ BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+ while (skb->len > 0) {
-+ hdr = skb->data[0];
-+
-+ switch (hdr & 0xc0) {
-+ case 0x40:
-+ hdrlen = 2;
-+ len = skb->data[1];
-+ break;
-+ case 0x80:
-+ hdrlen = 3;
-+ len = skb->data[1] | (skb->data[2] << 8);
-+ break;
-+ default:
-+ hdrlen = 1;
-+ len = 0;
-+ break;
-+ }
-+
-+ id = (hdr & 0x3c) >> 2;
-+
-+ BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id);
-+
-+ if (hdrlen + len > skb->len) {
-+ BT_ERR("Wrong size or header information in CMTP frame");
-+ break;
-+ }
-+
-+ if (len == 0) {
-+ skb_pull(skb, hdrlen);
-+ continue;
-+ }
-+
-+ switch (hdr & 0x03) {
-+ case 0x00:
-+ cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
-+ cmtp_recv_capimsg(session, session->reassembly[id]);
-+ session->reassembly[id] = NULL;
-+ break;
-+ case 0x01:
-+ cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
-+ break;
-+ default:
-+ if (session->reassembly[id] != NULL)
-+ kfree_skb(session->reassembly[id]);
-+ session->reassembly[id] = NULL;
-+ break;
-+ }
-+
-+ skb_pull(skb, hdrlen + len);
-+ }
-+
-+ kfree_skb(skb);
-+ return 0;
-+}
-+
-+static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len)
-+{
-+ struct socket *sock = session->sock;
-+ struct iovec iv = { data, len };
-+ struct msghdr msg;
-+ int err;
-+
-+ BT_DBG("session %p data %p len %d", session, data, len);
-+
-+ if (!len)
-+ return 0;
-+
-+ memset(&msg, 0, sizeof(msg));
-+ msg.msg_iovlen = 1;
-+ msg.msg_iov = &iv;
-+
-+ err = sock->ops->sendmsg(sock, &msg, len, 0);
-+ return err;
-+}
-+
-+static int cmtp_process_transmit(struct cmtp_session *session)
-+{
-+ struct sk_buff *skb, *nskb;
-+ unsigned char *hdr;
-+ unsigned int size, tail;
-+
-+ BT_DBG("session %p", session);
-+
-+ if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) {
-+ BT_ERR("Can't allocate memory for new frame");
-+ return -ENOMEM;
-+ }
-+
-+ while ((skb = skb_dequeue(&session->transmit))) {
-+ struct cmtp_scb *scb = (void *) skb->cb;
-+
-+ if ((tail = (session->mtu - nskb->len)) < 5) {
-+ cmtp_send_frame(session, nskb->data, nskb->len);
-+ skb_trim(nskb, 0);
-+ tail = session->mtu;
-+ }
-+
-+ size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len);
-+
-+ if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) {
-+ skb_queue_head(&session->transmit, skb);
-+ break;
-+ }
-+
-+ if (size < 256) {
-+ hdr = skb_put(nskb, 2);
-+ hdr[0] = 0x40
-+ | ((scb->id << 2) & 0x3c)
-+ | ((skb->len == size) ? 0x00 : 0x01);
-+ hdr[1] = size;
-+ } else {
-+ hdr = skb_put(nskb, 3);
-+ hdr[0] = 0x80
-+ | ((scb->id << 2) & 0x3c)
-+ | ((skb->len == size) ? 0x00 : 0x01);
-+ hdr[1] = size & 0xff;
-+ hdr[2] = size >> 8;
-+ }
-+
-+ memcpy(skb_put(nskb, size), skb->data, size);
-+ skb_pull(skb, size);
-+
-+ if (skb->len > 0) {
-+ skb_queue_head(&session->transmit, skb);
-+ } else {
-+ cmtp_free_block_id(session, scb->id);
-+ if (scb->data) {
-+ cmtp_send_frame(session, nskb->data, nskb->len);
-+ skb_trim(nskb, 0);
-+ }
-+ kfree_skb(skb);
-+ }
-+ }
-+
-+ cmtp_send_frame(session, nskb->data, nskb->len);
-+
-+ kfree_skb(nskb);
-+
-+ return skb_queue_len(&session->transmit);
-+}
-+
-+static int cmtp_session(void *arg)
-+{
-+ struct cmtp_session *session = arg;
-+ struct sock *sk = session->sock->sk;
-+ struct sk_buff *skb;
-+ wait_queue_t wait;
-+
-+ BT_DBG("session %p", session);
-+
-+ daemonize(); reparent_to_init();
-+
-+ sprintf(current->comm, "kcmtpd_ctr_%d", session->num);
-+
-+ sigfillset(&current->blocked);
-+ flush_signals(current);
-+
-+ current->nice = -15;
-+
-+ set_fs(KERNEL_DS);
-+
-+ init_waitqueue_entry(&wait, current);
-+ add_wait_queue(sk->sleep, &wait);
-+ while (!atomic_read(&session->terminate)) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (sk->state != BT_CONNECTED)
-+ break;
-+
-+ while ((skb = skb_dequeue(&sk->receive_queue))) {
-+ skb_orphan(skb);
-+ cmtp_recv_frame(session, skb);
-+ }
-+
-+ cmtp_process_transmit(session);
-+
-+ schedule();
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(sk->sleep, &wait);
-+
-+ down_write(&cmtp_session_sem);
-+
-+ if (!(session->flags & (1 << CMTP_LOOPBACK)))
-+ cmtp_detach_device(session);
-+
-+ fput(session->sock->file);
-+
-+ __cmtp_unlink_session(session);
-+
-+ up_write(&cmtp_session_sem);
-+
-+ kfree(session);
-+ return 0;
-+}
-+
-+int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
-+{
-+ struct cmtp_session *session, *s;
-+ bdaddr_t src, dst;
-+ int i, err;
-+
-+ BT_DBG("");
-+
-+ baswap(&src, &bluez_pi(sock->sk)->src);
-+ baswap(&dst, &bluez_pi(sock->sk)->dst);
-+
-+ session = kmalloc(sizeof(struct cmtp_session), GFP_KERNEL);
-+ if (!session)
-+ return -ENOMEM;
-+ memset(session, 0, sizeof(struct cmtp_session));
-+
-+ down_write(&cmtp_session_sem);
-+
-+ s = __cmtp_get_session(&bluez_pi(sock->sk)->dst);
-+ if (s && s->state == BT_CONNECTED) {
-+ err = -EEXIST;
-+ goto failed;
-+ }
-+
-+ bacpy(&session->bdaddr, &bluez_pi(sock->sk)->dst);
-+
-+ session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu);
-+
-+ BT_DBG("mtu %d", session->mtu);
-+
-+ sprintf(session->name, "%s", batostr(&dst));
-+
-+ session->sock = sock;
-+ session->state = BT_CONFIG;
-+
-+ init_waitqueue_head(&session->wait);
-+
-+ session->ctrl = NULL;
-+ session->msgnum = CMTP_INITIAL_MSGNUM;
-+
-+ INIT_LIST_HEAD(&session->applications);
-+
-+ skb_queue_head_init(&session->transmit);
-+
-+ for (i = 0; i < 16; i++)
-+ session->reassembly[i] = NULL;
-+
-+ session->flags = req->flags;
-+
-+ __cmtp_link_session(session);
-+
-+ err = kernel_thread(cmtp_session, session, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-+ if (err < 0)
-+ goto unlink;
-+
-+ if (!(session->flags & (1 << CMTP_LOOPBACK))) {
-+ err = cmtp_attach_device(session);
-+ if (err < 0)
-+ goto detach;
-+ }
-+
-+ up_write(&cmtp_session_sem);
-+ return 0;
-+
-+detach:
-+ cmtp_detach_device(session);
-+
-+unlink:
-+ __cmtp_unlink_session(session);
-+
-+failed:
-+ up_write(&cmtp_session_sem);
-+ kfree(session);
-+ return err;
-+}
-+
-+int cmtp_del_connection(struct cmtp_conndel_req *req)
-+{
-+ struct cmtp_session *session;
-+ int err = 0;
-+
-+ BT_DBG("");
-+
-+ down_read(&cmtp_session_sem);
-+
-+ session = __cmtp_get_session(&req->bdaddr);
-+ if (session) {
-+ /* Flush the transmit queue */
-+ skb_queue_purge(&session->transmit);
-+
-+ /* Kill session thread */
-+ atomic_inc(&session->terminate);
-+ cmtp_schedule(session);
-+ } else
-+ err = -ENOENT;
-+
-+ up_read(&cmtp_session_sem);
-+ return err;
-+}
-+
-+int cmtp_get_connlist(struct cmtp_connlist_req *req)
-+{
-+ struct list_head *p;
-+ int err = 0, n = 0;
-+
-+ BT_DBG("");
-+
-+ down_read(&cmtp_session_sem);
-+
-+ list_for_each(p, &cmtp_session_list) {
-+ struct cmtp_session *session;
-+ struct cmtp_conninfo ci;
-+
-+ session = list_entry(p, struct cmtp_session, list);
-+
-+ __cmtp_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(&cmtp_session_sem);
-+ return err;
-+}
-+
-+int cmtp_get_conninfo(struct cmtp_conninfo *ci)
-+{
-+ struct cmtp_session *session;
-+ int err = 0;
-+
-+ down_read(&cmtp_session_sem);
-+
-+ session = __cmtp_get_session(&ci->bdaddr);
-+ if (session)
-+ __cmtp_copy_session(session, ci);
-+ else
-+ err = -ENOENT;
-+
-+ up_read(&cmtp_session_sem);
-+ return err;
-+}
-+
-+
-+int __init init_cmtp(void)
-+{
-+ l2cap_load();
-+
-+ cmtp_init_capi();
-+ cmtp_init_sockets();
-+
-+ BT_INFO("BlueZ CMTP ver %s", VERSION);
-+ BT_INFO("Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>");
-+
-+ return 0;
-+}
-+
-+void __exit exit_cmtp(void)
-+{
-+ cmtp_cleanup_sockets();
-+ cmtp_cleanup_capi();
-+}
-+
-+module_init(init_cmtp);
-+module_exit(exit_cmtp);
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueZ CMTP ver " VERSION);
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ linux-2.4.21/net/bluetooth/cmtp/sock.c
-@@ -0,0 +1,208 @@
-+/*
-+ CMTP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002-2003 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 <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+
-+#include "cmtp.h"
-+
-+#ifndef CONFIG_BLUEZ_CMTP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+static int cmtp_sock_release(struct socket *sock)
-+{
-+ struct sock *sk = sock->sk;
-+
-+ BT_DBG("sock %p sk %p", sock, sk);
-+
-+ if (!sk)
-+ return 0;
-+
-+ sock_orphan(sk);
-+ sock_put(sk);
-+
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+{
-+ struct cmtp_connadd_req ca;
-+ struct cmtp_conndel_req cd;
-+ struct cmtp_connlist_req cl;
-+ struct cmtp_conninfo ci;
-+ struct socket *nsock;
-+ int err;
-+
-+ BT_DBG("cmd %x arg %lx", cmd, arg);
-+
-+ switch (cmd) {
-+ case CMTPCONNADD:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EACCES;
-+
-+ if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
-+ return -EFAULT;
-+
-+ nsock = sockfd_lookup(ca.sock, &err);
-+ if (!nsock)
-+ return err;
-+
-+ if (nsock->sk->state != BT_CONNECTED) {
-+ fput(nsock->file);
-+ return -EBADFD;
-+ }
-+
-+ err = cmtp_add_connection(&ca, nsock);
-+ if (!err) {
-+ if (copy_to_user((void *) arg, &ca, sizeof(ca)))
-+ err = -EFAULT;
-+ } else
-+ fput(nsock->file);
-+
-+ return err;
-+
-+ case CMTPCONNDEL:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EACCES;
-+
-+ if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
-+ return -EFAULT;
-+
-+ return cmtp_del_connection(&cd);
-+
-+ case CMTPGETCONNLIST:
-+ if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
-+ return -EFAULT;
-+
-+ if (cl.cnum <= 0)
-+ return -EINVAL;
-+
-+ err = cmtp_get_connlist(&cl);
-+ if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
-+ return -EFAULT;
-+
-+ return err;
-+
-+ case CMTPGETCONNINFO:
-+ if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
-+ return -EFAULT;
-+
-+ err = cmtp_get_conninfo(&ci);
-+ if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
-+ return -EFAULT;
-+
-+ return err;
-+ }
-+
-+ return -EINVAL;
-+}
-+
-+static struct proto_ops cmtp_sock_ops = {
-+ family: PF_BLUETOOTH,
-+ release: cmtp_sock_release,
-+ ioctl: cmtp_sock_ioctl,
-+ bind: sock_no_bind,
-+ getname: sock_no_getname,
-+ sendmsg: sock_no_sendmsg,
-+ recvmsg: sock_no_recvmsg,
-+ poll: sock_no_poll,
-+ listen: sock_no_listen,
-+ shutdown: sock_no_shutdown,
-+ setsockopt: sock_no_setsockopt,
-+ getsockopt: sock_no_getsockopt,
-+ connect: sock_no_connect,
-+ socketpair: sock_no_socketpair,
-+ accept: sock_no_accept,
-+ mmap: sock_no_mmap
-+};
-+
-+static int cmtp_sock_create(struct socket *sock, int protocol)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("sock %p", sock);
-+
-+ if (sock->type != SOCK_RAW)
-+ return -ESOCKTNOSUPPORT;
-+
-+ sock->ops = &cmtp_sock_ops;
-+
-+ if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1)))
-+ return -ENOMEM;
-+
-+ MOD_INC_USE_COUNT;
-+
-+ sock->state = SS_UNCONNECTED;
-+ sock_init_data(sock, sk);
-+
-+ sk->destruct = NULL;
-+ sk->protocol = protocol;
-+
-+ return 0;
-+}
-+
-+static struct net_proto_family cmtp_sock_family_ops = {
-+ family: PF_BLUETOOTH,
-+ create: cmtp_sock_create
-+};
-+
-+int cmtp_init_sockets(void)
-+{
-+ int err;
-+
-+ if ((err = bluez_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops))) {
-+ BT_ERR("Can't register CMTP socket layer (%d)", err);
-+ return err;
-+ }
-+
-+ return 0;
-+}
-+
-+void cmtp_cleanup_sockets(void)
-+{
-+ int err;
-+
-+ if ((err = bluez_sock_unregister(BTPROTO_CMTP)))
-+ BT_ERR("Can't unregister CMTP socket layer (%d)", err);
-+
-+ return;
-+}
---- linux-2.4.21/net/bluetooth/hci_core.c~bluetooth
-+++ linux-2.4.21/net/bluetooth/hci_core.c
-@@ -218,6 +218,10 @@
-
- /* Mandatory initialization */
-
-+ /* Reset */
-+ if (test_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks))
-+ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
-+
- /* Read Local Supported Features */
- hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES, 0, NULL);
-
-@@ -395,7 +399,7 @@
- {
- struct hci_inquiry_req ir;
- struct hci_dev *hdev;
-- int err = 0, do_inquiry = 0;
-+ int err = 0, do_inquiry = 0, max_rsp;
- long timeo;
- __u8 *buf, *ptr;
-
-@@ -408,6 +412,7 @@
-
- hci_dev_lock_bh(hdev);
- if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
-+ inquiry_cache_empty(hdev) ||
- ir.flags & IREQ_CACHE_FLUSH) {
- inquiry_cache_flush(hdev);
- do_inquiry = 1;
-@@ -418,16 +423,19 @@
- if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
- goto done;
-
-+ /* for unlimited number of responses we will use buffer with 255 entries */
-+ max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;
-+
- /* cache_dump can't sleep. Therefore we allocate temp buffer and then
- * copy it to the user space.
- */
-- if (!(buf = kmalloc(sizeof(inquiry_info) * ir.num_rsp, GFP_KERNEL))) {
-+ if (!(buf = kmalloc(sizeof(inquiry_info) * max_rsp, GFP_KERNEL))) {
- err = -ENOMEM;
- goto done;
- }
-
- hci_dev_lock_bh(hdev);
-- ir.num_rsp = inquiry_cache_dump(hdev, ir.num_rsp, buf);
-+ ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf);
- hci_dev_unlock_bh(hdev);
-
- BT_DBG("num_rsp %d", ir.num_rsp);
-@@ -708,22 +716,20 @@
- struct hci_dev_list_req *dl;
- struct hci_dev_req *dr;
- struct list_head *p;
-- int n = 0, size;
-+ int n = 0, size, err;
- __u16 dev_num;
-
- if (get_user(dev_num, (__u16 *) arg))
- return -EFAULT;
-
-- if (!dev_num)
-+ if (!dev_num || dev_num > (PAGE_SIZE * 2) / sizeof(*dr))
- return -EINVAL;
--
-- size = dev_num * sizeof(*dr) + sizeof(*dl);
-
-- if (verify_area(VERIFY_WRITE, (void *) arg, size))
-- return -EFAULT;
-+ size = sizeof(*dl) + dev_num * sizeof(*dr);
-
- if (!(dl = kmalloc(size, GFP_KERNEL)))
- return -ENOMEM;
-+
- dr = dl->dev_req;
-
- read_lock_bh(&hdev_list_lock);
-@@ -738,12 +744,12 @@
- read_unlock_bh(&hdev_list_lock);
-
- dl->dev_num = n;
-- size = n * sizeof(*dr) + sizeof(*dl);
-+ size = sizeof(*dl) + n * sizeof(*dr);
-
-- copy_to_user((void *) arg, dl, size);
-+ err = copy_to_user((void *) arg, dl, size);
- kfree(dl);
-
-- return 0;
-+ return err ? -EFAULT : 0;
- }
-
- int hci_get_dev_info(unsigned long arg)
---- linux-2.4.21/net/bluetooth/hci_event.c~bluetooth
-+++ linux-2.4.21/net/bluetooth/hci_event.c
-@@ -62,9 +62,22 @@
- /* Command Complete OGF LINK_CTL */
- static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
- {
-+ __u8 status;
-+
- BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-
- switch (ocf) {
-+ case OCF_INQUIRY_CANCEL:
-+ status = *((__u8 *) skb->data);
-+
-+ if (status) {
-+ BT_DBG("%s Inquiry cancel error: status 0x%x", hdev->name, status);
-+ } else {
-+ clear_bit(HCI_INQUIRY, &hdev->flags);
-+ hci_req_complete(hdev, status);
-+ }
-+ break;
-+
- default:
- BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
- break;
-@@ -307,7 +320,7 @@
- status, batostr(&cc->bdaddr), conn);
-
- if (status) {
-- if (conn) {
-+ if (conn && conn->state == BT_CONNECT) {
- conn->state = BT_CLOSED;
- hci_proto_connect_cfm(conn, status);
- hci_conn_del(conn);
-@@ -439,6 +452,29 @@
- hci_dev_unlock(hdev);
- }
-
-+/* Inquiry Result With RSSI */
-+static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ inquiry_info_with_rssi *info = (inquiry_info_with_rssi *) (skb->data + 1);
-+ int num_rsp = *((__u8 *) skb->data);
-+
-+ BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
-+
-+ hci_dev_lock(hdev);
-+ for (; num_rsp; num_rsp--) {
-+ inquiry_info tmp;
-+ bacpy(&tmp.bdaddr, &info->bdaddr);
-+ tmp.pscan_rep_mode = info->pscan_rep_mode;
-+ tmp.pscan_period_mode = info->pscan_period_mode;
-+ tmp.pscan_mode = 0x00;
-+ memcpy(tmp.dev_class, &info->dev_class, 3);
-+ tmp.clock_offset = info->clock_offset;
-+ info++;
-+ inquiry_cache_update(hdev, &tmp);
-+ }
-+ hci_dev_unlock(hdev);
-+}
-+
- /* Connect Request */
- static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
- {
-@@ -735,6 +771,10 @@
- hci_inquiry_result_evt(hdev, skb);
- break;
-
-+ case EVT_INQUIRY_RESULT_WITH_RSSI:
-+ hci_inquiry_result_with_rssi_evt(hdev, skb);
-+ break;
-+
- case EVT_CONN_REQUEST:
- hci_conn_request_evt(hdev, skb);
- break;
---- linux-2.4.21/net/bluetooth/hci_sock.c~bluetooth
-+++ linux-2.4.21/net/bluetooth/hci_sock.c
-@@ -66,20 +66,20 @@
- /* Packet types */
- 0x10,
- /* Events */
-- { 0xd9fe, 0x0 },
-+ { 0x1000d9fe, 0x0000300c },
- /* Commands */
- {
- { 0x0 },
- /* OGF_LINK_CTL */
-- { 0x2a000002, 0x0, 0x0, 0x0 },
-+ { 0xbe000006, 0x00000001, 0x0000, 0x00 },
- /* OGF_LINK_POLICY */
-- { 0x1200, 0x0, 0x0, 0x0 },
-+ { 0x00005200, 0x00000000, 0x0000, 0x00 },
- /* OGF_HOST_CTL */
-- { 0x80100000, 0x2a, 0x0, 0x0 },
-+ { 0xaab00200, 0x2b402aaa, 0x0154, 0x00 },
- /* OGF_INFO_PARAM */
-- { 0x22a, 0x0, 0x0, 0x0 },
-+ { 0x000002be, 0x00000000, 0x0000, 0x00 },
- /* OGF_STATUS_PARAM */
-- { 0x2e, 0x0, 0x0, 0x0 }
-+ { 0x000000ea, 0x00000000, 0x0000, 0x00 }
- }
- };
-
---- /dev/null
-+++ linux-2.4.21/net/bluetooth/hidp/Config.in
-@@ -0,0 +1,5 @@
-+#
-+# Bluetooth HIDP layer configuration
-+#
-+
-+dep_tristate 'HIDP protocol support' CONFIG_BLUEZ_HIDP $CONFIG_INPUT $CONFIG_BLUEZ_L2CAP
---- /dev/null
-+++ linux-2.4.21/net/bluetooth/hidp/Makefile
-@@ -0,0 +1,10 @@
-+#
-+# Makefile for the Linux Bluetooth HIDP layer
-+#
-+
-+O_TARGET := hidp.o
-+
-+obj-y := core.o sock.o
-+obj-m += $(O_TARGET)
-+
-+include $(TOPDIR)/Rules.make
---- /dev/null
-+++ linux-2.4.21/net/bluetooth/hidp/core.c
-@@ -0,0 +1,655 @@
-+/*
-+ 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)
-+{
-+ MOD_INC_USE_COUNT;
-+ list_add(&session->list, &hidp_session_list);
-+}
-+
-+static void __hidp_unlink_session(struct hidp_session *session)
-+{
-+ list_del(&session->list);
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+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->idvendor;
-+ ci->product = session->input->idproduct;
-+ ci->version = session->input->idversion;
-+ 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_event(dev, EV_RST, 0, 0);
-+}
-+
-+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 iovec 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));
-+ msg.msg_iovlen = 1;
-+ msg.msg_iov = &iv;
-+
-+ return sock_sendmsg(sock, &msg, 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->idvendor;
-+ product = session->input->idproduct;
-+ }
-+
-+ daemonize(); reparent_to_init();
-+
-+ sprintf(current->comm, "khidpd_%04x%04x", vendor, product);
-+
-+ sigfillset(&current->blocked);
-+ flush_signals(current);
-+
-+ current->nice = -15;
-+
-+ set_fs(KERNEL_DS);
-+
-+ init_waitqueue_entry(&ctrl_wait, current);
-+ init_waitqueue_entry(&intr_wait, current);
-+ add_wait_queue(ctrl_sk->sleep, &ctrl_wait);
-+ add_wait_queue(intr_sk->sleep, &intr_wait);
-+ while (!atomic_read(&session->terminate)) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (ctrl_sk->state != BT_CONNECTED || intr_sk->state != BT_CONNECTED)
-+ break;
-+
-+ while ((skb = skb_dequeue(&ctrl_sk->receive_queue))) {
-+ skb_orphan(skb);
-+ hidp_recv_frame(session, skb);
-+ }
-+
-+ while ((skb = skb_dequeue(&intr_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->sleep, &intr_wait);
-+ remove_wait_queue(ctrl_sk->sleep, &ctrl_wait);
-+
-+ down_write(&hidp_session_sem);
-+
-+ hidp_del_timer(session);
-+
-+ if (intr_sk->state != BT_CONNECTED) {
-+ init_waitqueue_entry(&ctrl_wait, current);
-+ add_wait_queue(ctrl_sk->sleep, &ctrl_wait);
-+ while (timeo && ctrl_sk->state != BT_CLOSED) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ timeo = schedule_timeout(timeo);
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(ctrl_sk->sleep, &ctrl_wait);
-+ timeo = HZ;
-+ }
-+
-+ fput(session->ctrl_sock->file);
-+
-+ init_waitqueue_entry(&intr_wait, current);
-+ add_wait_queue(intr_sk->sleep, &intr_wait);
-+ while (timeo && intr_sk->state != BT_CLOSED) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ timeo = schedule_timeout(timeo);
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(intr_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->idbus = BUS_BLUETOOTH;
-+ input->idvendor = req->vendor;
-+ input->idproduct = req->product;
-+ input->idversion = 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(&bluez_pi(ctrl_sock->sk)->src, &bluez_pi(intr_sock->sk)->src) ||
-+ bacmp(&bluez_pi(ctrl_sock->sk)->dst, &bluez_pi(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(&bluez_pi(ctrl_sock->sk)->dst);
-+ if (s && s->state == BT_CONNECTED) {
-+ err = -EEXIST;
-+ goto failed;
-+ }
-+
-+ bacpy(&session->bdaddr, &bluez_pi(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_FS | CLONE_FILES | CLONE_SIGHAND);
-+ 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();
-+
-+ hidp_init_sockets();
-+
-+ BT_INFO("BlueZ HIDP ver %s", VERSION);
-+ BT_INFO("Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>");
-+
-+ return 0;
-+}
-+
-+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_LICENSE("GPL");
---- /dev/null
-+++ linux-2.4.21/net/bluetooth/hidp/hidp.h
-@@ -0,0 +1,122 @@
-+/*
-+ 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.
-+*/
-+
-+#ifndef __HIDP_H
-+#define __HIDP_H
-+
-+#include <linux/types.h>
-+#include <net/bluetooth/bluetooth.h>
-+
-+/* HIDP ioctl defines */
-+#define HIDPCONNADD _IOW('H', 200, int)
-+#define HIDPCONNDEL _IOW('H', 201, int)
-+#define HIDPGETCONNLIST _IOR('H', 210, int)
-+#define HIDPGETCONNINFO _IOR('H', 211, int)
-+
-+#define HIDP_VIRTUAL_CABLE_UNPLUG 0
-+#define HIDP_BOOT_PROTOCOL_MODE 1
-+#define HIDP_BLUETOOTH_VENDOR_ID 9
-+
-+struct hidp_connadd_req {
-+ int ctrl_sock; // Connected control socket
-+ int intr_sock; // Connteted interrupt socket
-+ __u16 parser;
-+ __u16 rd_size;
-+ __u8 *rd_data;
-+ __u8 country;
-+ __u8 subclass;
-+ __u16 vendor;
-+ __u16 product;
-+ __u16 version;
-+ __u32 flags;
-+ __u32 idle_to;
-+ char name[128];
-+};
-+
-+struct hidp_conndel_req {
-+ bdaddr_t bdaddr;
-+ __u32 flags;
-+};
-+
-+struct hidp_conninfo {
-+ bdaddr_t bdaddr;
-+ __u32 flags;
-+ __u16 state;
-+ __u16 vendor;
-+ __u16 product;
-+ __u16 version;
-+ char name[128];
-+};
-+
-+struct hidp_connlist_req {
-+ __u32 cnum;
-+ struct hidp_conninfo *ci;
-+};
-+
-+int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock);
-+int hidp_del_connection(struct hidp_conndel_req *req);
-+int hidp_get_connlist(struct hidp_connlist_req *req);
-+int hidp_get_conninfo(struct hidp_conninfo *ci);
-+
-+/* HIDP session defines */
-+struct hidp_session {
-+ struct list_head list;
-+
-+ struct socket *ctrl_sock;
-+ struct socket *intr_sock;
-+
-+ bdaddr_t bdaddr;
-+
-+ unsigned long state;
-+ unsigned long flags;
-+ unsigned long idle_to;
-+
-+ uint ctrl_mtu;
-+ uint intr_mtu;
-+
-+ atomic_t terminate;
-+
-+ unsigned char keys[8];
-+ unsigned char leds;
-+
-+ struct input_dev *input;
-+
-+ struct timer_list timer;
-+
-+ struct sk_buff_head ctrl_transmit;
-+ struct sk_buff_head intr_transmit;
-+};
-+
-+static inline void hidp_schedule(struct hidp_session *session)
-+{
-+ struct sock *ctrl_sk = session->ctrl_sock->sk;
-+ struct sock *intr_sk = session->intr_sock->sk;
-+
-+ wake_up_interruptible(ctrl_sk->sleep);
-+ wake_up_interruptible(intr_sk->sleep);
-+}
-+
-+/* HIDP init defines */
-+extern int __init hidp_init_sockets(void);
-+extern void __exit hidp_cleanup_sockets(void);
-+
-+#endif /* __HIDP_H */
---- /dev/null
-+++ linux-2.4.21/net/bluetooth/hidp/sock.c
-@@ -0,0 +1,212 @@
-+/*
-+ 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 "hidp.h"
-+
-+#ifndef CONFIG_BT_HIDP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+static int hidp_sock_release(struct socket *sock)
-+{
-+ struct sock *sk = sock->sk;
-+
-+ BT_DBG("sock %p sk %p", sock, sk);
-+
-+ if (!sk)
-+ return 0;
-+
-+ sock_orphan(sk);
-+ sock_put(sk);
-+
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+{
-+ struct hidp_connadd_req ca;
-+ struct hidp_conndel_req cd;
-+ struct hidp_connlist_req cl;
-+ struct hidp_conninfo ci;
-+ struct socket *csock;
-+ struct socket *isock;
-+ int err;
-+
-+ BT_DBG("cmd %x arg %lx", cmd, arg);
-+
-+ switch (cmd) {
-+ case HIDPCONNADD:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EACCES;
-+
-+ if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
-+ return -EFAULT;
-+
-+ csock = sockfd_lookup(ca.ctrl_sock, &err);
-+ if (!csock)
-+ return err;
-+
-+ isock = sockfd_lookup(ca.intr_sock, &err);
-+ if (!isock) {
-+ fput(csock->file);
-+ return err;
-+ }
-+
-+ if (csock->sk->state != BT_CONNECTED || isock->sk->state != BT_CONNECTED) {
-+ fput(csock->file);
-+ fput(isock->file);
-+ return -EBADFD;
-+ }
-+
-+ err = hidp_add_connection(&ca, csock, isock);
-+ if (!err) {
-+ if (copy_to_user((void *) arg, &ca, sizeof(ca)))
-+ err = -EFAULT;
-+ } else {
-+ fput(csock->file);
-+ fput(isock->file);
-+ }
-+
-+ return err;
-+
-+ case HIDPCONNDEL:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EACCES;
-+
-+ if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
-+ return -EFAULT;
-+
-+ return hidp_del_connection(&cd);
-+
-+ case HIDPGETCONNLIST:
-+ if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
-+ return -EFAULT;
-+
-+ if (cl.cnum <= 0)
-+ return -EINVAL;
-+
-+ err = hidp_get_connlist(&cl);
-+ if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
-+ return -EFAULT;
-+
-+ return err;
-+
-+ case HIDPGETCONNINFO:
-+ if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
-+ return -EFAULT;
-+
-+ err = hidp_get_conninfo(&ci);
-+ if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
-+ return -EFAULT;
-+
-+ return err;
-+ }
-+
-+ return -EINVAL;
-+}
-+
-+static struct proto_ops hidp_sock_ops = {
-+ family: PF_BLUETOOTH,
-+ release: hidp_sock_release,
-+ ioctl: hidp_sock_ioctl,
-+ bind: sock_no_bind,
-+ getname: sock_no_getname,
-+ sendmsg: sock_no_sendmsg,
-+ recvmsg: sock_no_recvmsg,
-+ poll: sock_no_poll,
-+ listen: sock_no_listen,
-+ shutdown: sock_no_shutdown,
-+ setsockopt: sock_no_setsockopt,
-+ getsockopt: sock_no_getsockopt,
-+ connect: sock_no_connect,
-+ socketpair: sock_no_socketpair,
-+ accept: sock_no_accept,
-+ mmap: sock_no_mmap
-+};
-+
-+static int hidp_sock_create(struct socket *sock, int protocol)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("sock %p", sock);
-+
-+ if (sock->type != SOCK_RAW)
-+ return -ESOCKTNOSUPPORT;
-+
-+ sock->ops = &hidp_sock_ops;
-+
-+ if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1)))
-+ return -ENOMEM;
-+
-+ MOD_INC_USE_COUNT;
-+
-+ sock->state = SS_UNCONNECTED;
-+ sock_init_data(sock, sk);
-+
-+ sk->destruct = NULL;
-+ sk->protocol = protocol;
-+
-+ return 0;
-+}
-+
-+static struct net_proto_family hidp_sock_family_ops = {
-+ family: PF_BLUETOOTH,
-+ create: hidp_sock_create
-+};
-+
-+int __init hidp_init_sockets(void)
-+{
-+ int err;
-+
-+ if ((err = bluez_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops)))
-+ BT_ERR("Can't register HIDP socket layer (%d)", err);
-+
-+ return err;
-+}
-+
-+void __exit hidp_cleanup_sockets(void)
-+{
-+ int err;
-+
-+ if ((err = bluez_sock_unregister(BTPROTO_HIDP)))
-+ BT_ERR("Can't unregister HIDP socket layer (%d)", err);
-+}
---- linux-2.4.21/net/bluetooth/l2cap.c~bluetooth
-+++ linux-2.4.21/net/bluetooth/l2cap.c
-@@ -27,7 +27,7 @@
- *
- * $Id: l2cap.c,v 1.15 2002/09/09 01:14:52 maxk Exp $
- */
--#define VERSION "2.1"
-+#define VERSION "2.3"
-
- #include <linux/config.h>
- #include <linux/module.h>
-@@ -284,7 +284,7 @@
- l2cap_disconn_req req;
-
- sk->state = BT_DISCONN;
-- l2cap_sock_set_timer(sk, HZ * 5);
-+ l2cap_sock_set_timer(sk, sk->sndtimeo);
-
- req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-@@ -309,11 +309,9 @@
- static void l2cap_sock_close(struct sock *sk)
- {
- l2cap_sock_clear_timer(sk);
--
- lock_sock(sk);
- __l2cap_sock_close(sk, ECONNRESET);
- release_sock(sk);
--
- l2cap_sock_kill(sk);
- }
-
-@@ -527,7 +525,8 @@
- goto done;
-
- wait:
-- err = bluez_sock_w4_connect(sk, flags);
-+ err = bluez_sock_wait_state(sk, BT_CONNECTED,
-+ sock_sndtimeo(sk, flags & O_NONBLOCK));
-
- done:
- release_sock(sk);
-@@ -760,32 +759,39 @@
- static int l2cap_sock_shutdown(struct socket *sock, int how)
- {
- struct sock *sk = sock->sk;
-+ int err = 0;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- if (!sk) return 0;
-
-- l2cap_sock_clear_timer(sk);
--
- lock_sock(sk);
-- sk->shutdown = SHUTDOWN_MASK;
-- __l2cap_sock_close(sk, ECONNRESET);
-- release_sock(sk);
-+ if (!sk->shutdown) {
-+ sk->shutdown = SHUTDOWN_MASK;
-+ l2cap_sock_clear_timer(sk);
-+ __l2cap_sock_close(sk, 0);
-
-- return 0;
-+ if (sk->linger)
-+ err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
-+ }
-+ release_sock(sk);
-+ return err;
- }
-
- static int l2cap_sock_release(struct socket *sock)
- {
- struct sock *sk = sock->sk;
-+ int err;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- if (!sk) return 0;
-
-+ err = l2cap_sock_shutdown(sock, 2);
-+
- sock_orphan(sk);
-- l2cap_sock_close(sk);
-- return 0;
-+ l2cap_sock_kill(sk);
-+ return err;
- }
-
- /* --------- L2CAP channels --------- */
-@@ -917,10 +923,12 @@
- hci_conn_put(conn->hcon);
- }
-
-- sk->state = BT_CLOSED;
-- sk->err = err;
-+ sk->state = BT_CLOSED;
- sk->zapped = 1;
-
-+ if (err)
-+ sk->err = err;
-+
- if (parent)
- parent->data_ready(parent, 0);
- else
-@@ -956,6 +964,22 @@
- read_unlock(&l->lock);
- }
-
-+/* Notify sockets that we cannot guaranty reliability anymore */
-+static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
-+{
-+ struct l2cap_chan_list *l = &conn->chan_list;
-+ struct sock *sk;
-+
-+ BT_DBG("conn %p", conn);
-+
-+ read_lock(&l->lock);
-+ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-+ if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
-+ sk->err = err;
-+ }
-+ read_unlock(&l->lock);
-+}
-+
- static void l2cap_chan_ready(struct sock *sk)
- {
- struct sock *parent = bluez_pi(sk)->parent;
-@@ -1320,15 +1344,18 @@
- {
- l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data;
- void *ptr = rsp->data;
-+ u16 flags = 0;
-
- BT_DBG("sk %p complete %d", sk, result ? 1 : 0);
-
- if (result)
- *result = l2cap_conf_output(sk, &ptr);
-+ else
-+ flags |= 0x0001;
-
- rsp->scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
- rsp->result = __cpu_to_le16(result ? *result : 0);
-- rsp->flags = __cpu_to_le16(0);
-+ rsp->flags = __cpu_to_le16(flags);
-
- return ptr - data;
- }
-@@ -1441,7 +1468,7 @@
- case L2CAP_CR_SUCCESS:
- sk->state = BT_CONFIG;
- l2cap_pi(sk)->dcid = dcid;
-- l2cap_pi(sk)->conf_state |= CONF_REQ_SENT;
-+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
-
- l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
- break;
-@@ -1476,7 +1503,7 @@
-
- l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE);
-
-- if (flags & 0x01) {
-+ if (flags & 0x0001) {
- /* Incomplete config. Send empty response. */
- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
- goto unlock;
-@@ -1489,12 +1516,12 @@
- goto unlock;
-
- /* Output config done */
-- l2cap_pi(sk)->conf_state |= CONF_OUTPUT_DONE;
-+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE;
-
-- if (l2cap_pi(sk)->conf_state & CONF_INPUT_DONE) {
-+ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
- sk->state = BT_CONNECTED;
- l2cap_chan_ready(sk);
-- } else if (!(l2cap_pi(sk)->conf_state & CONF_REQ_SENT)) {
-+ } else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
- char req[64];
- l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
- }
-@@ -1520,18 +1547,34 @@
- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
- return -ENOENT;
-
-- if (result) {
-- l2cap_disconn_req req;
-+ switch (result) {
-+ case L2CAP_CONF_SUCCESS:
-+ break;
-
-- /* They didn't like our options. Well... we do not negotiate.
-- * Close channel.
-- */
-+ case L2CAP_CONF_UNACCEPT:
-+ if (++l2cap_pi(sk)->conf_retry < L2CAP_CONF_MAX_RETRIES) {
-+ char req[128];
-+ /*
-+ It does not make sense to adjust L2CAP parameters
-+ that are currently defined in the spec. We simply
-+ resend config request that we sent earlier. It is
-+ stupid :) but it helps qualification testing
-+ which expects at least some response from us.
-+ */
-+ l2cap_send_req(conn, L2CAP_CONF_REQ,
-+ l2cap_build_conf_req(sk, req), req);
-+ goto done;
-+ }
-+ default:
- sk->state = BT_DISCONN;
-+ sk->err = ECONNRESET;
- l2cap_sock_set_timer(sk, HZ * 5);
--
-- req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-- l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
-+ {
-+ l2cap_disconn_req req;
-+ req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+ l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
-+ }
- goto done;
- }
-
-@@ -1539,9 +1582,9 @@
- goto done;
-
- /* Input config done */
-- l2cap_pi(sk)->conf_state |= CONF_INPUT_DONE;
-+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE;
-
-- if (l2cap_pi(sk)->conf_state & CONF_OUTPUT_DONE) {
-+ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) {
- sk->state = BT_CONNECTED;
- l2cap_chan_ready(sk);
- }
-@@ -1592,13 +1635,42 @@
-
- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
- return 0;
-- l2cap_chan_del(sk, ECONNABORTED);
-+ l2cap_chan_del(sk, 0);
- bh_unlock_sock(sk);
-
- l2cap_sock_kill(sk);
- return 0;
- }
-
-+static inline int l2cap_information_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, u8 *data)
-+{
-+ l2cap_info_req *req = (l2cap_info_req *) data;
-+ l2cap_info_rsp rsp;
-+ u16 type;
-+
-+ type = __le16_to_cpu(req->type);
-+
-+ BT_DBG("type 0x%4.4x", type);
-+
-+ rsp.type = __cpu_to_le16(type);
-+ rsp.result = __cpu_to_le16(L2CAP_IR_NOTSUPP);
-+ l2cap_send_rsp(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp), &rsp);
-+ return 0;
-+}
-+
-+static inline int l2cap_information_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, u8 *data)
-+{
-+ l2cap_info_rsp *rsp = (l2cap_info_rsp *) data;
-+ u16 type, result;
-+
-+ type = __le16_to_cpu(rsp->type);
-+ result = __le16_to_cpu(rsp->result);
-+
-+ BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
-+
-+ return 0;
-+}
-+
- static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
- {
- __u8 *data = skb->data;
-@@ -1606,6 +1678,8 @@
- l2cap_cmd_hdr cmd;
- int err = 0;
-
-+ l2cap_raw_recv(conn, skb);
-+
- while (len >= L2CAP_CMD_HDR_SIZE) {
- memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
- data += L2CAP_CMD_HDR_SIZE;
-@@ -1621,6 +1695,10 @@
- }
-
- switch (cmd.code) {
-+ case L2CAP_COMMAND_REJ:
-+ /* FIXME: We should process this */
-+ break;
-+
- case L2CAP_CONN_REQ:
- err = l2cap_connect_req(conn, &cmd, data);
- break;
-@@ -1645,23 +1723,23 @@
- err = l2cap_disconnect_rsp(conn, &cmd, data);
- break;
-
-- case L2CAP_COMMAND_REJ:
-- /* FIXME: We should process this */
-- l2cap_raw_recv(conn, skb);
-- break;
--
- case L2CAP_ECHO_REQ:
- l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
- break;
-
- case L2CAP_ECHO_RSP:
-+ break;
-+
- case L2CAP_INFO_REQ:
-+ err = l2cap_information_req(conn, &cmd, data);
-+ break;
-+
- case L2CAP_INFO_RSP:
-- l2cap_raw_recv(conn, skb);
-+ err = l2cap_information_rsp(conn, &cmd, data);
- break;
-
- default:
-- BT_ERR("Uknown signaling command 0x%2.2x", cmd.code);
-+ BT_ERR("Unknown signaling command 0x%2.2x", cmd.code);
- err = -EINVAL;
- break;
- };
-@@ -1670,7 +1748,7 @@
- l2cap_cmd_rej rej;
- BT_DBG("error %d", err);
-
-- /* FIXME: Map err to a valid reason. */
-+ /* FIXME: Map err to a valid reason */
- rej.reason = __cpu_to_le16(0);
- l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej);
- }
-@@ -1943,26 +2021,36 @@
- kfree_skb(conn->rx_skb);
- conn->rx_skb = NULL;
- conn->rx_len = 0;
-+ l2cap_conn_unreliable(conn, ECOMM);
- }
-
- if (skb->len < 2) {
-- BT_ERR("Frame is too small (len %d)", skb->len);
-+ BT_ERR("Frame is too short (len %d)", skb->len);
-+ l2cap_conn_unreliable(conn, ECOMM);
- goto drop;
- }
-
- hdr = (l2cap_hdr *) skb->data;
- len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
-
-- BT_DBG("Start: total len %d, frag len %d", len, skb->len);
--
- if (len == skb->len) {
- /* Complete frame received */
- l2cap_recv_frame(conn, skb);
- return 0;
- }
-
-- /* Allocate skb for the complete frame (with header) */
-- if (!(conn->rx_skb = bluez_skb_alloc(len, GFP_ATOMIC)))
-+ BT_DBG("Start: total len %d, frag len %d", len, skb->len);
-+
-+ if (skb->len > len) {
-+ BT_ERR("Frame is too long (len %d, expected len %d)",
-+ skb->len, len);
-+ l2cap_conn_unreliable(conn, ECOMM);
-+ goto drop;
-+ }
-+
-+ /* Allocate skb for the complete frame including header */
-+ conn->rx_skb = bluez_skb_alloc(len, GFP_ATOMIC);
-+ if (!conn->rx_skb)
- goto drop;
-
- memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
-@@ -1972,15 +2060,17 @@
-
- if (!conn->rx_len) {
- BT_ERR("Unexpected continuation frame (len %d)", skb->len);
-+ l2cap_conn_unreliable(conn, ECOMM);
- goto drop;
- }
-
- if (skb->len > conn->rx_len) {
-- BT_ERR("Fragment is too large (len %d, expect %d)",
-+ BT_ERR("Fragment is too long (len %d, expected %d)",
- skb->len, conn->rx_len);
- kfree_skb(conn->rx_skb);
- conn->rx_skb = NULL;
- conn->rx_len = 0;
-+ l2cap_conn_unreliable(conn, ECOMM);
- goto drop;
- }
-
-@@ -2114,6 +2204,16 @@
- BT_ERR("Can't unregister L2CAP protocol");
- }
-
-+void l2cap_load(void)
-+{
-+ /* Dummy function to trigger automatic L2CAP module loading by
-+ other modules that use L2CAP sockets but do not use any other
-+ symbols from it. */
-+ return;
-+}
-+
-+EXPORT_SYMBOL(l2cap_load);
-+
- module_init(l2cap_init);
- module_exit(l2cap_cleanup);
-
---- linux-2.4.21/net/bluetooth/rfcomm/core.c~bluetooth
-+++ linux-2.4.21/net/bluetooth/rfcomm/core.c
-@@ -51,7 +51,7 @@
- #include <net/bluetooth/l2cap.h>
- #include <net/bluetooth/rfcomm.h>
-
--#define VERSION "1.0"
-+#define VERSION "1.1"
-
- #ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
- #undef BT_DBG
-@@ -198,10 +198,11 @@
-
- d->state = BT_OPEN;
- d->flags = 0;
-+ d->mscex = 0;
- d->mtu = RFCOMM_DEFAULT_MTU;
- d->v24_sig = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV;
-
-- d->credits = RFCOMM_MAX_CREDITS;
-+ d->cfc = RFCOMM_CFC_DISABLED;
- d->rx_credits = RFCOMM_DEFAULT_CREDITS;
- }
-
-@@ -274,13 +275,13 @@
- static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
- {
- struct rfcomm_session *s;
-- u8 dlci = __dlci(0, channel);
- int err = 0;
-+ u8 dlci;
-
-- BT_DBG("dlc %p state %ld %s %s channel %d dlci %d",
-- d, d->state, batostr(src), batostr(dst), channel, dlci);
-+ BT_DBG("dlc %p state %ld %s %s channel %d",
-+ d, d->state, batostr(src), batostr(dst), channel);
-
-- if (dlci < 1 || dlci > 62)
-+ if (channel < 1 || channel > 30)
- return -EINVAL;
-
- if (d->state != BT_OPEN && d->state != BT_CLOSED)
-@@ -293,20 +294,23 @@
- return err;
- }
-
-+ dlci = __dlci(!s->initiator, channel);
-+
- /* Check if DLCI already exists */
- if (rfcomm_dlc_get(s, dlci))
- return -EBUSY;
-
- rfcomm_dlc_clear_state(d);
-
-- d->dlci = dlci;
-- d->addr = __addr(s->initiator, dlci);
-+ d->dlci = dlci;
-+ d->addr = __addr(s->initiator, dlci);
-+ d->priority = 7;
-
-- d->state = BT_CONFIG;
-+ d->state = BT_CONFIG;
- rfcomm_dlc_link(s, d);
-
-- d->mtu = s->mtu;
-- d->credits = s->credits;
-+ d->mtu = s->mtu;
-+ d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
-
- if (s->state == BT_CONNECTED)
- rfcomm_send_pn(s, 1, d);
-@@ -406,7 +410,7 @@
- {
- BT_DBG("dlc %p state %ld", d, d->state);
-
-- if (!d->credits) {
-+ if (!d->cfc) {
- d->v24_sig |= RFCOMM_V24_FC;
- set_bit(RFCOMM_MSC_PENDING, &d->flags);
- }
-@@ -417,7 +421,7 @@
- {
- BT_DBG("dlc %p state %ld", d, d->state);
-
-- if (!d->credits) {
-+ if (!d->cfc) {
- d->v24_sig &= ~RFCOMM_V24_FC;
- set_bit(RFCOMM_MSC_PENDING, &d->flags);
- }
-@@ -470,8 +474,8 @@
- s->state = state;
- s->sock = sock;
-
-- s->mtu = RFCOMM_DEFAULT_MTU;
-- s->credits = RFCOMM_MAX_CREDITS;
-+ s->mtu = RFCOMM_DEFAULT_MTU;
-+ s->cfc = RFCOMM_CFC_UNKNOWN;
-
- list_add(&s->list, &session_list);
-
-@@ -707,7 +711,7 @@
- hdr->len = __len8(sizeof(*mcc) + 1);
-
- mcc = (void *) ptr; ptr += sizeof(*mcc);
-- mcc->type = __mcc_type(s->initiator, RFCOMM_NSC);
-+ mcc->type = __mcc_type(cr, RFCOMM_NSC);
- mcc->len = __len8(1);
-
- /* Type that we didn't like */
-@@ -733,16 +737,16 @@
- hdr->len = __len8(sizeof(*mcc) + sizeof(*pn));
-
- mcc = (void *) ptr; ptr += sizeof(*mcc);
-- mcc->type = __mcc_type(s->initiator, RFCOMM_PN);
-+ mcc->type = __mcc_type(cr, RFCOMM_PN);
- mcc->len = __len8(sizeof(*pn));
-
- pn = (void *) ptr; ptr += sizeof(*pn);
- pn->dlci = d->dlci;
-- pn->priority = 0;
-+ pn->priority = d->priority;
- pn->ack_timer = 0;
- pn->max_retrans = 0;
-
-- if (d->credits) {
-+ if (s->cfc) {
- pn->flow_ctrl = cr ? 0xf0 : 0xe0;
- pn->credits = RFCOMM_DEFAULT_CREDITS;
- } else {
-@@ -842,7 +846,51 @@
-
- msc = (void *) ptr; ptr += sizeof(*msc);
- msc->dlci = __addr(1, dlci);
-- msc->v24_sig = v24_sig;
-+ msc->v24_sig = v24_sig | 0x01;
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
-+{
-+ struct rfcomm_hdr *hdr;
-+ struct rfcomm_mcc *mcc;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p cr %d", s, cr);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = __addr(s->initiator, 0);
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+ hdr->len = __len8(sizeof(*mcc));
-+
-+ mcc = (void *) ptr; ptr += sizeof(*mcc);
-+ mcc->type = __mcc_type(cr, RFCOMM_FCOFF);
-+ mcc->len = __len8(0);
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
-+{
-+ struct rfcomm_hdr *hdr;
-+ struct rfcomm_mcc *mcc;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p cr %d", s, cr);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = __addr(s->initiator, 0);
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+ hdr->len = __len8(sizeof(*mcc));
-+
-+ mcc = (void *) ptr; ptr += sizeof(*mcc);
-+ mcc->type = __mcc_type(cr, RFCOMM_FCON);
-+ mcc->len = __len8(0);
-
- *ptr = __fcs(buf); ptr++;
-
-@@ -1076,6 +1124,8 @@
- d->state = BT_CONNECTED;
- d->state_change(d, 0);
- rfcomm_dlc_unlock(d);
-+
-+ rfcomm_send_msc(s, 1, dlci, d->v24_sig);
- } else {
- rfcomm_send_dm(s, dlci);
- }
-@@ -1085,29 +1135,23 @@
-
- static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
- {
-+ struct rfcomm_session *s = d->session;
-+
- BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d",
- d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits);
-
-- if (cr) {
-- if (pn->flow_ctrl == 0xf0) {
-- d->tx_credits = pn->credits;
-- } else {
-- set_bit(RFCOMM_TX_THROTTLED, &d->flags);
-- d->credits = 0;
-- }
--
-- d->mtu = btohs(pn->mtu);
-+ if (pn->flow_ctrl == 0xf0 || pn->flow_ctrl == 0xe0) {
-+ d->cfc = s->cfc = RFCOMM_CFC_ENABLED;
-+ d->tx_credits = pn->credits;
- } else {
-- if (pn->flow_ctrl == 0xe0) {
-- d->tx_credits = pn->credits;
-- } else {
-- set_bit(RFCOMM_TX_THROTTLED, &d->flags);
-- d->credits = 0;
-- }
--
-- d->mtu = btohs(pn->mtu);
-+ d->cfc = s->cfc = RFCOMM_CFC_DISABLED;
-+ set_bit(RFCOMM_TX_THROTTLED, &d->flags);
- }
-
-+ d->priority = pn->priority;
-+
-+ d->mtu = s->mtu = btohs(pn->mtu);
-+
- return 0;
- }
-
-@@ -1133,7 +1177,7 @@
- switch (d->state) {
- case BT_CONFIG:
- rfcomm_apply_pn(d, cr, pn);
--
-+
- d->state = BT_CONNECT;
- rfcomm_send_sabm(s, d->dlci);
- break;
-@@ -1144,7 +1188,7 @@
-
- if (!cr)
- return 0;
--
-+
- /* PN request for non existing DLC.
- * Assume incomming connection. */
- if (rfcomm_connect_ind(s, channel, &d)) {
-@@ -1153,7 +1197,7 @@
- rfcomm_dlc_link(s, d);
-
- rfcomm_apply_pn(d, cr, pn);
--
-+
- d->state = BT_OPEN;
- rfcomm_send_pn(s, 0, d);
- } else {
-@@ -1198,6 +1242,14 @@
- }
- /* check for sane values: ignore/accept bit_rate, 8 bits, 1 stop bit, no parity,
- no flow control lines, normal XON/XOFF chars */
-+ if (rpn->param_mask & RFCOMM_RPN_PM_BITRATE) {
-+ bit_rate = rpn->bit_rate;
-+ if (bit_rate != RFCOMM_RPN_BR_115200) {
-+ BT_DBG("RPN bit rate mismatch 0x%x", bit_rate);
-+ bit_rate = RFCOMM_RPN_BR_115200;
-+ rpn_mask ^= RFCOMM_RPN_PM_BITRATE;
-+ }
-+ }
- if (rpn->param_mask & RFCOMM_RPN_PM_DATA) {
- data_bits = __get_rpn_data_bits(rpn->line_settings);
- if (data_bits != RFCOMM_RPN_DATA_8) {
-@@ -1223,23 +1275,26 @@
- }
- }
- if (rpn->param_mask & RFCOMM_RPN_PM_FLOW) {
-- if (rpn->flow_ctrl != RFCOMM_RPN_FLOW_NONE) {
-- BT_DBG("RPN flow ctrl mismatch 0x%x", rpn->flow_ctrl);
-- rpn->flow_ctrl = RFCOMM_RPN_FLOW_NONE;
-+ flow_ctrl = rpn->flow_ctrl;
-+ if (flow_ctrl != RFCOMM_RPN_FLOW_NONE) {
-+ BT_DBG("RPN flow ctrl mismatch 0x%x", flow_ctrl);
-+ flow_ctrl = RFCOMM_RPN_FLOW_NONE;
- rpn_mask ^= RFCOMM_RPN_PM_FLOW;
- }
- }
- if (rpn->param_mask & RFCOMM_RPN_PM_XON) {
-- if (rpn->xon_char != RFCOMM_RPN_XON_CHAR) {
-- BT_DBG("RPN XON char mismatch 0x%x", rpn->xon_char);
-- rpn->xon_char = RFCOMM_RPN_XON_CHAR;
-+ xon_char = rpn->xon_char;
-+ if (xon_char != RFCOMM_RPN_XON_CHAR) {
-+ BT_DBG("RPN XON char mismatch 0x%x", xon_char);
-+ xon_char = RFCOMM_RPN_XON_CHAR;
- rpn_mask ^= RFCOMM_RPN_PM_XON;
- }
- }
- if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) {
-- if (rpn->xoff_char != RFCOMM_RPN_XOFF_CHAR) {
-- BT_DBG("RPN XOFF char mismatch 0x%x", rpn->xoff_char);
-- rpn->xoff_char = RFCOMM_RPN_XOFF_CHAR;
-+ xoff_char = rpn->xoff_char;
-+ if (xoff_char != RFCOMM_RPN_XOFF_CHAR) {
-+ BT_DBG("RPN XOFF char mismatch 0x%x", xoff_char);
-+ xoff_char = RFCOMM_RPN_XOFF_CHAR;
- rpn_mask ^= RFCOMM_RPN_PM_XOFF;
- }
- }
-@@ -1280,12 +1335,12 @@
-
- BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);
-
-- if (!cr)
-+ d = rfcomm_dlc_get(s, dlci);
-+ if (!d)
- return 0;
-
-- d = rfcomm_dlc_get(s, dlci);
-- if (d) {
-- if (msc->v24_sig & RFCOMM_V24_FC && !d->credits)
-+ if (cr) {
-+ if (msc->v24_sig & RFCOMM_V24_FC && !d->cfc)
- set_bit(RFCOMM_TX_THROTTLED, &d->flags);
- else
- clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
-@@ -1296,7 +1351,11 @@
- rfcomm_dlc_unlock(d);
-
- rfcomm_send_msc(s, 0, dlci, msc->v24_sig);
-- }
-+
-+ d->mscex |= RFCOMM_MSCEX_RX;
-+ } else
-+ d->mscex |= RFCOMM_MSCEX_TX;
-+
- return 0;
- }
-
-@@ -1330,6 +1389,20 @@
- rfcomm_recv_msc(s, cr, skb);
- break;
-
-+ case RFCOMM_FCOFF:
-+ if (cr) {
-+ set_bit(RFCOMM_TX_THROTTLED, &s->flags);
-+ rfcomm_send_fcoff(s, 0);
-+ }
-+ break;
-+
-+ case RFCOMM_FCON:
-+ if (cr) {
-+ clear_bit(RFCOMM_TX_THROTTLED, &s->flags);
-+ rfcomm_send_fcon(s, 0);
-+ }
-+ break;
-+
- case RFCOMM_TEST:
- if (cr)
- rfcomm_send_test(s, 0, skb->data, skb->len);
-@@ -1358,7 +1431,7 @@
- goto drop;
- }
-
-- if (pf && d->credits) {
-+ if (pf && d->cfc) {
- u8 credits = *(u8 *) skb->data; skb_pull(skb, 1);
-
- d->tx_credits += credits;
-@@ -1463,20 +1536,20 @@
- struct sk_buff *skb;
- int err;
-
-- BT_DBG("dlc %p state %ld credits %d rx_credits %d tx_credits %d",
-- d, d->state, d->credits, d->rx_credits, d->tx_credits);
-+ BT_DBG("dlc %p state %ld cfc %d rx_credits %d tx_credits %d",
-+ d, d->state, d->cfc, d->rx_credits, d->tx_credits);
-
- /* Send pending MSC */
- if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags))
- rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
-
-- if (d->credits) {
-+ if (d->cfc) {
- /* CFC enabled.
- * Give them some credits */
- if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) &&
-- d->rx_credits <= (d->credits >> 2)) {
-- rfcomm_send_credits(d->session, d->addr, d->credits - d->rx_credits);
-- d->rx_credits = d->credits;
-+ d->rx_credits <= (d->cfc >> 2)) {
-+ rfcomm_send_credits(d->session, d->addr, d->cfc - d->rx_credits);
-+ d->rx_credits = d->cfc;
- }
- } else {
- /* CFC disabled.
-@@ -1497,7 +1570,7 @@
- d->tx_credits--;
- }
-
-- if (d->credits && !d->tx_credits) {
-+ if (d->cfc && !d->tx_credits) {
- /* We're out of TX credits.
- * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */
- set_bit(RFCOMM_TX_THROTTLED, &d->flags);
-@@ -1520,7 +1593,11 @@
- continue;
- }
-
-- if (d->state == BT_CONNECTED || d->state == BT_DISCONN)
-+ if (test_bit(RFCOMM_TX_THROTTLED, &s->flags))
-+ continue;
-+
-+ if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
-+ d->mscex == RFCOMM_MSCEX_OK)
- rfcomm_process_tx(d);
- }
- }
-@@ -1577,9 +1654,10 @@
- nsock->sk->state_change = rfcomm_l2state_change;
-
- s = rfcomm_session_add(nsock, BT_OPEN);
-- if (s)
-+ if (s) {
- rfcomm_session_hold(s);
-- else
-+ rfcomm_schedule(RFCOMM_SCHED_RX);
-+ } else
- sock_release(nsock);
- }
-
-@@ -1815,6 +1893,8 @@
- /* ---- Initialization ---- */
- int __init rfcomm_init(void)
- {
-+ l2cap_load();
-+
- kernel_thread(rfcomm_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-
- rfcomm_init_sockets();
---- linux-2.4.21/net/bluetooth/rfcomm/sock.c~bluetooth
-+++ linux-2.4.21/net/bluetooth/rfcomm/sock.c
-@@ -188,8 +188,10 @@
- BT_DBG("parent %p", parent);
-
- /* Close not yet accepted dlcs */
-- while ((sk = bluez_accept_dequeue(parent, NULL)))
-+ while ((sk = bluez_accept_dequeue(parent, NULL))) {
- rfcomm_sock_close(sk);
-+ rfcomm_sock_kill(sk);
-+ }
-
- parent->state = BT_CLOSED;
- parent->zapped = 1;
-@@ -211,15 +213,10 @@
- sock_put(sk);
- }
-
--/* Close socket.
-- * Must be called on unlocked socket.
-- */
--static void rfcomm_sock_close(struct sock *sk)
-+static void __rfcomm_sock_close(struct sock *sk)
- {
- struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
-
-- lock_sock(sk);
--
- BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket);
-
- switch (sk->state) {
-@@ -236,11 +233,17 @@
- default:
- sk->zapped = 1;
- break;
-- };
-+ }
-+}
-
-+/* Close socket.
-+ * Must be called on unlocked socket.
-+ */
-+static void rfcomm_sock_close(struct sock *sk)
-+{
-+ lock_sock(sk);
-+ __rfcomm_sock_close(sk);
- release_sock(sk);
--
-- rfcomm_sock_kill(sk);
- }
-
- static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
-@@ -374,7 +377,8 @@
-
- err = rfcomm_dlc_open(d, &bluez_pi(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
- if (!err)
-- err = bluez_sock_w4_connect(sk, flags);
-+ err = bluez_sock_wait_state(sk, BT_CONNECTED,
-+ sock_sndtimeo(sk, flags & O_NONBLOCK));
-
- release_sock(sk);
- return err;
-@@ -558,9 +562,6 @@
- int target, err = 0, copied = 0;
- long timeo;
-
-- if (sk->state != BT_CONNECTED)
-- return -EINVAL;
--
- if (flags & MSG_OOB)
- return -EOPNOTSUPP;
-
-@@ -635,23 +636,6 @@
- return copied ? : err;
- }
-
--static int rfcomm_sock_shutdown(struct socket *sock, int how)
--{
-- struct sock *sk = sock->sk;
--
-- BT_DBG("sock %p, sk %p", sock, sk);
--
-- if (!sk) return 0;
--
-- lock_sock(sk);
-- sk->shutdown = SHUTDOWN_MASK;
-- if (sk->state == BT_CONNECTED)
-- rfcomm_dlc_close(rfcomm_pi(sk)->dlc, 0);
-- release_sock(sk);
--
-- return 0;
--}
--
- static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
- {
- struct sock *sk = sock->sk;
-@@ -711,19 +695,42 @@
- return err;
- }
-
-+static int rfcomm_sock_shutdown(struct socket *sock, int how)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ if (!sk) return 0;
-+
-+ lock_sock(sk);
-+ if (!sk->shutdown) {
-+ sk->shutdown = SHUTDOWN_MASK;
-+ __rfcomm_sock_close(sk);
-+
-+ if (sk->linger)
-+ err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
-+ }
-+ release_sock(sk);
-+ return err;
-+}
-+
- static int rfcomm_sock_release(struct socket *sock)
- {
- struct sock *sk = sock->sk;
-+ int err = 0;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
-- sock_orphan(sk);
-- rfcomm_sock_close(sk);
-+ err = rfcomm_sock_shutdown(sock, 2);
-
-- return 0;
-+ sock_orphan(sk);
-+ rfcomm_sock_kill(sk);
-+ return err;
- }
-
- /* ---- RFCOMM core layer callbacks ----
---- linux-2.4.21/net/bluetooth/rfcomm/tty.c~bluetooth
-+++ linux-2.4.21/net/bluetooth/rfcomm/tty.c
-@@ -109,6 +109,13 @@
-
- static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
- {
-+ /* The reason this isn't actually a race, as you no
-+ doubt have a little voice screaming at you in your
-+ head, is that the refcount should never actually
-+ reach zero unless the device has already been taken
-+ off the list, in rfcomm_dev_del(). And if that's not
-+ true, we'll hit the BUG() in rfcomm_dev_destruct()
-+ anyway. */
- if (atomic_dec_and_test(&dev->refcnt))
- rfcomm_dev_destruct(dev);
- }
-@@ -132,10 +139,13 @@
- struct rfcomm_dev *dev;
-
- read_lock(&rfcomm_dev_lock);
-+
- dev = __rfcomm_dev_get(id);
-+ if (dev)
-+ rfcomm_dev_hold(dev);
-+
- read_unlock(&rfcomm_dev_lock);
-
-- if (dev) rfcomm_dev_hold(dev);
- return dev;
- }
-
-@@ -260,9 +270,9 @@
- skb->destructor = rfcomm_wfree;
- }
-
--static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int priority)
-+static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int force, int priority)
- {
-- if (atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) {
-+ if (force || atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) {
- struct sk_buff *skb = alloc_skb(size, priority);
- if (skb) {
- rfcomm_set_owner_w(skb, dev);
-@@ -328,12 +338,14 @@
-
- BT_DBG("dev_id %id flags 0x%x", req.dev_id, req.flags);
-
-- if (!capable(CAP_NET_ADMIN))
-- return -EPERM;
--
- if (!(dev = rfcomm_dev_get(req.dev_id)))
- return -ENODEV;
-
-+ if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) {
-+ rfcomm_dev_put(dev);
-+ return -EPERM;
-+ }
-+
- if (req.flags & (1 << RFCOMM_HANGUP_NOW))
- rfcomm_dlc_close(dev->dlc, 0);
-
-@@ -347,7 +359,7 @@
- struct rfcomm_dev_list_req *dl;
- struct rfcomm_dev_info *di;
- struct list_head *p;
-- int n = 0, size;
-+ int n = 0, size, err;
- u16 dev_num;
-
- BT_DBG("");
-@@ -355,14 +367,11 @@
- if (get_user(dev_num, (u16 *) arg))
- return -EFAULT;
-
-- if (!dev_num)
-+ if (!dev_num || dev_num > (PAGE_SIZE * 4) / sizeof(*di))
- return -EINVAL;
-
- size = sizeof(*dl) + dev_num * sizeof(*di);
-
-- if (verify_area(VERIFY_WRITE, (void *)arg, size))
-- return -EFAULT;
--
- if (!(dl = kmalloc(size, GFP_KERNEL)))
- return -ENOMEM;
-
-@@ -387,9 +396,10 @@
- dl->dev_num = n;
- size = sizeof(*dl) + n * sizeof(*di);
-
-- copy_to_user((void *) arg, dl, size);
-+ err = copy_to_user((void *) arg, dl, size);
- kfree(dl);
-- return 0;
-+
-+ return err ? -EFAULT : 0;
- }
-
- static int rfcomm_get_dev_info(unsigned long arg)
-@@ -486,7 +496,8 @@
- rfcomm_dev_del(dev);
-
- /* We have to drop DLC lock here, otherwise
-- * rfcomm_dev_put() will dead lock if it's the last refference */
-+ rfcomm_dev_put() will dead lock if it's
-+ the last reference. */
- rfcomm_dlc_unlock(dlc);
- rfcomm_dev_put(dev);
- rfcomm_dlc_lock(dlc);
-@@ -541,6 +552,10 @@
-
- BT_DBG("tty %p id %d", tty, id);
-
-+ /* We don't leak this refcount. For reasons which are not entirely
-+ clear, the TTY layer will call our ->close() method even if the
-+ open fails. We decrease the refcount there, and decreasing it
-+ here too would cause breakage. */
- dev = rfcomm_dev_get(id);
- if (!dev)
- return -ENODEV;
-@@ -627,9 +642,9 @@
- size = min_t(uint, count, dlc->mtu);
-
- if (from_user)
-- skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_KERNEL);
-+ skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_KERNEL);
- else
-- skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_ATOMIC);
-+ skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_ATOMIC);
-
- if (!skb)
- break;
-@@ -653,6 +668,27 @@
- return sent ? sent : err;
- }
-
-+static void rfcomm_tty_put_char(struct tty_struct *tty, unsigned char ch)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ struct rfcomm_dlc *dlc = dev->dlc;
-+ struct sk_buff *skb;
-+
-+ BT_DBG("tty %p char %x", tty, ch);
-+
-+ skb = rfcomm_wmalloc(dev, 1 + RFCOMM_SKB_RESERVE, 1, GFP_ATOMIC);
-+
-+ if (!skb)
-+ return;
-+
-+ skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
-+
-+ *(char *)skb_put(skb, 1) = ch;
-+
-+ if ((rfcomm_dlc_send(dlc, skb)) < 0)
-+ kfree_skb(skb);
-+}
-+
- static int rfcomm_tty_write_room(struct tty_struct *tty)
- {
- struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-@@ -879,6 +915,7 @@
-
- open: rfcomm_tty_open,
- close: rfcomm_tty_close,
-+ put_char: rfcomm_tty_put_char,
- write: rfcomm_tty_write,
- write_room: rfcomm_tty_write_room,
- chars_in_buffer: rfcomm_tty_chars_in_buffer,
---- linux-2.4.21/net/bluetooth/sco.c~bluetooth
-+++ linux-2.4.21/net/bluetooth/sco.c
-@@ -332,8 +332,10 @@
- BT_DBG("parent %p", parent);
-
- /* Close not yet accepted channels */
-- while ((sk = bluez_accept_dequeue(parent, NULL)))
-+ while ((sk = bluez_accept_dequeue(parent, NULL))) {
- sco_sock_close(sk);
-+ sco_sock_kill(sk);
-+ }
-
- parent->state = BT_CLOSED;
- parent->zapped = 1;
-@@ -388,8 +390,6 @@
- };
-
- release_sock(sk);
--
-- sco_sock_kill(sk);
- }
-
- static void sco_sock_init(struct sock *sk, struct sock *parent)
-@@ -508,7 +508,8 @@
- if ((err = sco_connect(sk)))
- goto done;
-
-- err = bluez_sock_w4_connect(sk, flags);
-+ err = bluez_sock_wait_state(sk, BT_CONNECTED,
-+ sock_sndtimeo(sk, flags & O_NONBLOCK));
-
- done:
- release_sock(sk);
-@@ -712,16 +713,23 @@
- static int sco_sock_release(struct socket *sock)
- {
- struct sock *sk = sock->sk;
-+ int err = 0;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
-- sock_orphan(sk);
- sco_sock_close(sk);
-+ if (sk->linger) {
-+ lock_sock(sk);
-+ err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
-+ release_sock(sk);
-+ }
-
-- return 0;
-+ sock_orphan(sk);
-+ sco_sock_kill(sk);
-+ return err;
- }
-
- static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
---- linux-2.4.21/net/bluetooth/syms.c~bluetooth
-+++ linux-2.4.21/net/bluetooth/syms.c
-@@ -78,4 +78,4 @@
- EXPORT_SYMBOL(bluez_sock_poll);
- EXPORT_SYMBOL(bluez_accept_enqueue);
- EXPORT_SYMBOL(bluez_accept_dequeue);
--EXPORT_SYMBOL(bluez_sock_w4_connect);
-+EXPORT_SYMBOL(bluez_sock_wait_state);
---- linux-2.4.21/net/core/wireless.c~linux-iw241_we16-6
-+++ linux-2.4.21/net/core/wireless.c
-@@ -2,7 +2,7 @@
- * This file implement the Wireless Extensions APIs.
- *
- * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
-- * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
-+ * Copyright (c) 1997-2003 Jean Tourrilhes, All Rights Reserved.
- *
- * (As all part of the Linux kernel, this file is GPL)
- */
-@@ -43,6 +43,11 @@
- * o Turn on WE_STRICT_WRITE by default + kernel warning
- * o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
- * o Fix off-by-one in test (extra_size <= IFNAMSIZ)
-+ *
-+ * v6 - 9.01.03 - Jean II
-+ * o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
-+ * o Add enhanced spy support : iw_handler_set_thrspy() and event.
-+ * o Add WIRELESS_EXT version display in /proc/net/wireless
- */
-
- /***************************** INCLUDES *****************************/
-@@ -52,6 +57,7 @@
- #include <linux/types.h> /* off_t */
- #include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */
- #include <linux/rtnetlink.h> /* rtnetlink stuff */
-+#include <linux/if_arp.h> /* ARPHRD_ETHER */
-
- #include <linux/wireless.h> /* Pretty obvious */
- #include <net/iw_handler.h> /* New driver API */
-@@ -65,6 +71,7 @@
- /* Debuging stuff */
- #undef WE_IOCTL_DEBUG /* Debug IOCTL API */
- #undef WE_EVENT_DEBUG /* Debug Event dispatcher */
-+#undef WE_SPY_DEBUG /* Debug enhanced spy support */
-
- /* Options */
- #define WE_EVENT_NETLINK /* Propagate events using rtnetlink */
-@@ -72,7 +79,7 @@
-
- /************************* GLOBAL VARIABLES *************************/
- /*
-- * You should not use global variables, because or re-entrancy.
-+ * You should not use global variables, because of re-entrancy.
- * On our case, it's only const, so it's OK...
- */
- /*
-@@ -115,11 +122,11 @@
- /* SIOCSIWSPY */
- { IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
- /* SIOCGIWSPY */
-- { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0},
-- /* -- hole -- */
-- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-- /* -- hole -- */
-- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-+ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
-+ /* SIOCSIWTHRSPY */
-+ { IW_HEADER_TYPE_POINT, 0, sizeof(struct iw_thrspy), 1, 1, 0},
-+ /* SIOCGIWTHRSPY */
-+ { IW_HEADER_TYPE_POINT, 0, sizeof(struct iw_thrspy), 1, 1, 0},
- /* SIOCSIWAP */
- { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
- /* SIOCGIWAP */
-@@ -377,9 +384,9 @@
- struct net_device * dev;
-
- size = sprintf(buffer,
-- "Inter-| sta-| Quality | Discarded packets | Missed\n"
-- " face | tus | link level noise | nwid crypt frag retry misc | beacon\n"
-- );
-+ "Inter-| sta-| Quality | Discarded packets | Missed | WE\n"
-+ " face | tus | link level noise | nwid crypt frag retry misc | beacon | %d\n",
-+ WIRELESS_EXT);
-
- pos += size;
- len += size;
-@@ -1024,3 +1031,252 @@
-
- return; /* Always success, I guess ;-) */
- }
-+
-+/********************** ENHANCED IWSPY SUPPORT **********************/
-+/*
-+ * In the old days, the driver was handling spy support all by itself.
-+ * Now, the driver can delegate this task to Wireless Extensions.
-+ * It needs to use those standard spy iw_handler in struct iw_handler_def,
-+ * push data to us via XXX and include struct iw_spy_data in its
-+ * private part.
-+ * One of the main advantage of centralising spy support here is that
-+ * it becomes much easier to improve and extend it without having to touch
-+ * the drivers. One example is the addition of the Spy-Threshold events.
-+ * Note : IW_WIRELESS_SPY is defined in iw_handler.h
-+ */
-+
-+/*------------------------------------------------------------------*/
-+/*
-+ * Standard Wireless Handler : set Spy List
-+ */
-+int iw_handler_set_spy(struct net_device * dev,
-+ struct iw_request_info * info,
-+ union iwreq_data * wrqu,
-+ char * extra)
-+{
-+#ifdef IW_WIRELESS_SPY
-+ struct iw_spy_data * spydata = (dev->priv +
-+ dev->wireless_handlers->spy_offset);
-+ struct sockaddr * address = (struct sockaddr *) extra;
-+
-+ /* Disable spy collection while we copy the addresses.
-+ * As we don't disable interrupts, we need to do this to avoid races.
-+ * As we are the only writer, this is good enough. */
-+ spydata->spy_number = 0;
-+
-+ /* Are there are addresses to copy? */
-+ if(wrqu->data.length > 0) {
-+ int i;
-+
-+ /* Copy addresses */
-+ for(i = 0; i < wrqu->data.length; i++)
-+ memcpy(spydata->spy_address[i], address[i].sa_data,
-+ ETH_ALEN);
-+ /* Reset stats */
-+ memset(spydata->spy_stat, 0,
-+ sizeof(struct iw_quality) * IW_MAX_SPY);
-+
-+#ifdef WE_SPY_DEBUG
-+ printk(KERN_DEBUG "iw_handler_set_spy() : offset %ld, spydata %p, num %d\n", dev->wireless_handlers->spy_offset, spydata, wrqu->data.length);
-+ for (i = 0; i < wrqu->data.length; i++)
-+ printk(KERN_DEBUG
-+ "%02X:%02X:%02X:%02X:%02X:%02X \n",
-+ spydata->spy_address[i][0],
-+ spydata->spy_address[i][1],
-+ spydata->spy_address[i][2],
-+ spydata->spy_address[i][3],
-+ spydata->spy_address[i][4],
-+ spydata->spy_address[i][5]);
-+#endif /* WE_SPY_DEBUG */
-+ }
-+ /* Enable addresses */
-+ spydata->spy_number = wrqu->data.length;
-+
-+ return 0;
-+#else /* IW_WIRELESS_SPY */
-+ return -EOPNOTSUPP;
-+#endif /* IW_WIRELESS_SPY */
-+}
-+
-+/*------------------------------------------------------------------*/
-+/*
-+ * Standard Wireless Handler : get Spy List
-+ */
-+int iw_handler_get_spy(struct net_device * dev,
-+ struct iw_request_info * info,
-+ union iwreq_data * wrqu,
-+ char * extra)
-+{
-+#ifdef IW_WIRELESS_SPY
-+ struct iw_spy_data * spydata = (dev->priv +
-+ dev->wireless_handlers->spy_offset);
-+ struct sockaddr * address = (struct sockaddr *) extra;
-+ int i;
-+
-+ wrqu->data.length = spydata->spy_number;
-+
-+ /* Copy addresses. */
-+ for(i = 0; i < spydata->spy_number; i++) {
-+ memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
-+ address[i].sa_family = AF_UNIX;
-+ }
-+ /* Copy stats to the user buffer (just after). */
-+ if(spydata->spy_number > 0)
-+ memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number),
-+ spydata->spy_stat,
-+ sizeof(struct iw_quality) * spydata->spy_number);
-+ /* Reset updated flags. */
-+ for(i = 0; i < spydata->spy_number; i++)
-+ spydata->spy_stat[i].updated = 0;
-+ return 0;
-+#else /* IW_WIRELESS_SPY */
-+ return -EOPNOTSUPP;
-+#endif /* IW_WIRELESS_SPY */
-+}
-+
-+/*------------------------------------------------------------------*/
-+/*
-+ * Standard Wireless Handler : set spy threshold
-+ */
-+int iw_handler_set_thrspy(struct net_device * dev,
-+ struct iw_request_info *info,
-+ union iwreq_data * wrqu,
-+ char * extra)
-+{
-+#ifdef IW_WIRELESS_THRSPY
-+ struct iw_spy_data * spydata = (dev->priv +
-+ dev->wireless_handlers->spy_offset);
-+ struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
-+
-+ /* Just do it */
-+ memcpy(&(spydata->spy_thr_low), &(threshold->low),
-+ 2 * sizeof(struct iw_quality));
-+
-+ /* Clear flag */
-+ memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
-+
-+#ifdef WE_SPY_DEBUG
-+ printk(KERN_DEBUG "iw_handler_set_thrspy() : low %d ; high %d\n", spydata->spy_thr_low.level, spydata->spy_thr_high.level);
-+#endif /* WE_SPY_DEBUG */
-+
-+ return 0;
-+#else /* IW_WIRELESS_THRSPY */
-+ return -EOPNOTSUPP;
-+#endif /* IW_WIRELESS_THRSPY */
-+}
-+
-+/*------------------------------------------------------------------*/
-+/*
-+ * Standard Wireless Handler : get spy threshold
-+ */
-+int iw_handler_get_thrspy(struct net_device * dev,
-+ struct iw_request_info *info,
-+ union iwreq_data * wrqu,
-+ char * extra)
-+{
-+#ifdef IW_WIRELESS_THRSPY
-+ struct iw_spy_data * spydata = (dev->priv +
-+ dev->wireless_handlers->spy_offset);
-+ struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
-+
-+ /* Just do it */
-+ memcpy(&(threshold->low), &(spydata->spy_thr_low),
-+ 2 * sizeof(struct iw_quality));
-+
-+ return 0;
-+#else /* IW_WIRELESS_THRSPY */
-+ return -EOPNOTSUPP;
-+#endif /* IW_WIRELESS_THRSPY */
-+}
-+
-+#ifdef IW_WIRELESS_THRSPY
-+/*------------------------------------------------------------------*/
-+/*
-+ * Prepare and send a Spy Threshold event
-+ */
-+static void iw_send_thrspy_event(struct net_device * dev,
-+ struct iw_spy_data * spydata,
-+ unsigned char * address,
-+ struct iw_quality * wstats)
-+{
-+ union iwreq_data wrqu;
-+ struct iw_thrspy threshold;
-+
-+ /* Init */
-+ wrqu.data.length = 1;
-+ wrqu.data.flags = 0;
-+ /* Copy address */
-+ memcpy(threshold.addr.sa_data, address, ETH_ALEN);
-+ threshold.addr.sa_family = ARPHRD_ETHER;
-+ /* Copy stats */
-+ memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
-+ /* Copy also thresholds */
-+ memcpy(&(threshold.low), &(spydata->spy_thr_low),
-+ 2 * sizeof(struct iw_quality));
-+
-+#ifdef WE_SPY_DEBUG
-+ printk(KERN_DEBUG "iw_send_thrspy_event() : address %02X:%02X:%02X:%02X:%02X:%02X, level %d, up = %d\n",
-+ threshold.addr.sa_data[0],
-+ threshold.addr.sa_data[1],
-+ threshold.addr.sa_data[2],
-+ threshold.addr.sa_data[3],
-+ threshold.addr.sa_data[4],
-+ threshold.addr.sa_data[5], threshold.qual.level);
-+#endif /* WE_SPY_DEBUG */
-+
-+ /* Send event to user space */
-+ wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
-+}
-+#endif /* IW_WIRELESS_THRSPY */
-+
-+/* ---------------------------------------------------------------- */
-+/*
-+ * Call for the driver to update the spy data.
-+ * For now, the spy data is a simple array. As the size of the array is
-+ * small, this is good enough. If we wanted to support larger number of
-+ * spy addresses, we should use something more efficient...
-+ */
-+void wireless_spy_update(struct net_device * dev,
-+ unsigned char * address,
-+ struct iw_quality * wstats)
-+{
-+#ifdef IW_WIRELESS_SPY
-+ struct iw_spy_data * spydata = (dev->priv +
-+ dev->wireless_handlers->spy_offset);
-+ int i;
-+ int match = -1;
-+
-+#ifdef WE_SPY_DEBUG
-+ printk(KERN_DEBUG "wireless_spy_update() : offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
-+#endif /* WE_SPY_DEBUG */
-+
-+ /* Update all records that match */
-+ for(i = 0; i < spydata->spy_number; i++)
-+ if(!memcmp(address, spydata->spy_address[i], ETH_ALEN)) {
-+ memcpy(&(spydata->spy_stat[i]), wstats,
-+ sizeof(struct iw_quality));
-+ match = i;
-+ }
-+#ifdef IW_WIRELESS_THRSPY
-+ /* Generate an event if we cross the spy threshold.
-+ * To avoid event storms, we have a simple hysteresis : we generate
-+ * event only when we go under the low threshold or above the
-+ * high threshold. */
-+ if(match >= 0) {
-+ if(spydata->spy_thr_under[match]) {
-+ if(wstats->level > spydata->spy_thr_high.level) {
-+ spydata->spy_thr_under[match] = 0;
-+ iw_send_thrspy_event(dev, spydata,
-+ address, wstats);
-+ }
-+ } else {
-+ if(wstats->level < spydata->spy_thr_low.level) {
-+ spydata->spy_thr_under[match] = 1;
-+ iw_send_thrspy_event(dev, spydata,
-+ address, wstats);
-+ }
-+ }
-+ }
-+#endif /* IW_WIRELESS_THRSPY */
-+#endif /* IW_WIRELESS_SPY */
-+}
---- linux-2.4.21/net/ipv4/ipconfig.c~net-dhcp-timeout
-+++ linux-2.4.21/net/ipv4/ipconfig.c
-@@ -87,7 +87,7 @@
-
- /* Define the timeout for waiting for a DHCP/BOOTP/RARP reply */
- #define CONF_OPEN_RETRIES 2 /* (Re)open devices twice */
--#define CONF_SEND_RETRIES 6 /* Send six requests per open */
-+#define CONF_SEND_RETRIES 4 /* Send six requests per open */
- #define CONF_INTER_TIMEOUT (HZ/2) /* Inter-device timeout: 1/2 second */
- #define CONF_BASE_TIMEOUT (HZ*2) /* Initial timeout: 2 seconds */
- #define CONF_TIMEOUT_RANDOM (HZ) /* Maximum amount of randomization */
-@@ -1238,9 +1238,11 @@
- #endif
-
- if (--retries) {
-+#ifndef CONFIG_ARCH_RAMSES
- printk(KERN_ERR
- "IP-Config: Reopening network devices...\n");
- goto try_try_again;
-+#endif
- }
-
- /* Oh, well. At least we tried. */
---- linux-2.4.21/net/netsyms.c~linux-iw241_we16-6
-+++ linux-2.4.21/net/netsyms.c
-@@ -160,6 +160,7 @@
- EXPORT_SYMBOL(put_cmsg);
- EXPORT_SYMBOL(sock_kmalloc);
- EXPORT_SYMBOL(sock_kfree_s);
-+EXPORT_SYMBOL(sockfd_lookup);
-
- #ifdef CONFIG_FILTER
- EXPORT_SYMBOL(sk_run_filter);
-@@ -601,6 +602,11 @@
- #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
- #include <net/iw_handler.h>
- EXPORT_SYMBOL(wireless_send_event);
-+EXPORT_SYMBOL(iw_handler_set_spy);
-+EXPORT_SYMBOL(iw_handler_get_spy);
-+EXPORT_SYMBOL(iw_handler_set_thrspy);
-+EXPORT_SYMBOL(iw_handler_get_thrspy);
-+EXPORT_SYMBOL(wireless_spy_update);
- #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
-
- #endif /* CONFIG_NET */
diff --git a/recipes/linux/mnci-ramses_2.4.21-rmk2-pxa1.bb b/recipes/linux/mnci-ramses_2.4.21-rmk2-pxa1.bb
deleted file mode 100644
index 3145e9d4fe..0000000000
--- a/recipes/linux/mnci-ramses_2.4.21-rmk2-pxa1.bb
+++ /dev/null
@@ -1,75 +0,0 @@
-SECTION = "kernel"
-DESCRIPTION = "Linux kernel for MNCI device"
-LICENSE = "GPLv2"
-DEPENDS = "modutils-cross virtual/${TARGET_PREFIX}gcc${KERNEL_CCSUFFIX}"
-COMPATIBLE_MACHINE = "mnci"
-KV = "2.4.21"
-RMKV = "2"
-PXAV = "1"
-PR = "r5"
-
-SRC_URI = "${KERNELORG_MIRROR}/pub/linux/kernel/v2.4/linux-${KV}.tar.bz2;name=kernel \
- http://ftp.linux.org.uk/pub/linux/arm/kernel/v2.4/patch-${KV}-rmk${RMKV}.bz2;apply=yes;name=rmkpatch \
- file://diff-${KV}-rmk${RMKV}-pxa${PXAV}.gz;apply=yes \
- file://mnci-combined.patch"
-
-S = "${WORKDIR}/linux-${KV}"
-
-inherit kernel
-
-KERNEL_CCSUFFIX = "-3.3.4"
-
-# Put the zImage into kernel-image
-ALLOW_EMPTY_kernel = "1"
-FILES_kernel = ""
-FILES_kernel-image += "/tmp/zImage"
-
-do_configure_prepend() {
- install -m 0644 ${S}/arch/arm/def-configs/${MACHINE} ${S}/.config || die "No default configuration for ${MACHINE} available."
-}
-
-kernel_do_install() {
- unset CFLAGS CPPFLAGS CXXFLAGS LDFLAGS
- if (grep -q -i -e '^CONFIG_MODULES=y$' .config); then
- oe_runmake DEPMOD=echo INSTALL_MOD_PATH="${D}" modules_install
- else
- oenote "no modules to install"
- fi
- install -d ${D}/tmp
- install -m 0644 ${KERNEL_OUTPUT} ${D}/tmp
- install -d ${D}/boot
- install -m 0644 .config ${D}/boot/config-${PV}
- bzip2 -9 ${D}/boot/*
- install -d ${D}${sysconfdir}/modutils
-}
-
-
-pkg_postinst_kernel-image () {
-test -f /tmp/zImage || exit 0
-cp /tmp/zImage /dev/mtdblock/1
-rm /tmp/zImage
-sync
-cat /dev/mtdblock/1 >/dev/null
-}
-
-pkg_postinst_kernel () {
-}
-
-pkg_postinst_modules () {
-if [ -n "$D" ]; then
- ${HOST_PREFIX}depmod-${KERNEL_MAJOR_VERSION} -A -b $D -F $D/boot/System.map-${PV} ${KERNEL_VERSION}
-else
- depmod -A
-fi
-}
-
-pkg_postrm_modules () {
-}
-
-pkg_postrm_kernel () {
-}
-
-SRC_URI[kernel.md5sum] = "f51e12efa18bb828cf57d9d4a81b2fb1"
-SRC_URI[kernel.sha256sum] = "dd197b9b80535591c0dc0505fae31c8eceeb07a891e85b85396494a0f97688db"
-SRC_URI[rmkpatch.md5sum] = "23169d1265241683bb8c9d0daf22b6b5"
-SRC_URI[rmkpatch.sha256sum] = "1381ef6cfb9460adee987322657fbfcd081e70d7be4255163ed1a2afeb7becfb"