From 1710d7230e1cb23c590533191ddffe2f1de27928 Mon Sep 17 00:00:00 2001 From: Andrea Adami Date: Tue, 26 Apr 2011 00:43:47 +0200 Subject: mnci: move to nonworking, obsolete mnci-ramses 2.4 kernel * machines with 2.4 kernels are not supported Signed-off-by: Andrea Adami --- .../diff-2.4.21-rmk2-pxa1.gz | Bin 248024 -> 0 bytes .../mnci-combined.patch | 108070 ------------------ recipes/linux/mnci-ramses_2.4.21-rmk2-pxa1.bb | 75 - 3 files changed, 108145 deletions(-) delete mode 100644 recipes/linux/mnci-ramses-2.4.21-rmk2-pxa1/diff-2.4.21-rmk2-pxa1.gz delete mode 100644 recipes/linux/mnci-ramses-2.4.21-rmk2-pxa1/mnci-combined.patch delete mode 100644 recipes/linux/mnci-ramses_2.4.21-rmk2-pxa1.bb (limited to 'recipes/linux') 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 Binary files a/recipes/linux/mnci-ramses-2.4.21-rmk2-pxa1/diff-2.4.21-rmk2-pxa1.gz and /dev/null 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 . -+ - 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 . -- -- If you want to compile BlueZ Core as module (bluez.o) say M here. -+ For more information, see . - - 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 . -+ 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 . -- - 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 @@ -+ -+ -+ -+ -+ Reed-Solomon Library Programming Interface -+ -+ -+ -+ Thomas -+ Gleixner -+ -+
-+ tglx@linutronix.de -+
-+
-+
-+
-+ -+ -+ 2004 -+ Thomas Gleixner -+ -+ -+ -+ -+ 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. -+ -+ -+ -+ This program is distributed in the hope that it will be -+ useful, but WITHOUT ANY WARRANTY; without even the implied -+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -+ See the GNU General Public License for more details. -+ -+ -+ -+ You 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 -+ -+ -+ -+ For more details see the file COPYING in the source -+ distribution of Linux. -+ -+ -+
-+ -+ -+ -+ -+ Introduction -+ -+ The generic Reed-Solomon Library provides encoding, decoding -+ and error correction functions. -+ -+ -+ Reed-Solomon codes are used in communication and storage -+ applications to ensure data integrity. -+ -+ -+ This documentation is provided for developers who want to utilize -+ the functions provided by the library. -+ -+ -+ -+ -+ Known Bugs And Assumptions -+ -+ None. -+ -+ -+ -+ -+ Usage -+ -+ This chapter provides examples how to use the library. -+ -+ -+ Initializing -+ -+ 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. -+ -+ -+/* 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); -+ -+ -+ -+ Encoding -+ -+ 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. -+ -+ -+ 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. -+ -+ -+ 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. -+ -+ -+/* 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); -+ -+ -+ -+ Decoding -+ -+ The decoder calculates the syndrome over -+ the given data length and the received parity symbols -+ and corrects errors in the data. -+ -+ -+ If a syndrome is available from a hardware decoder -+ then the syndrome calculation is skipped. -+ -+ -+ 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. -+ -+ -+ 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. -+ -+ -+ -+ -+ Decoding with syndrome calculation, direct data correction -+ -+ -+/* 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); -+ -+ -+ -+ -+ -+ Decoding with syndrome given by hardware decoder, direct data correction -+ -+ -+/* 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); -+ -+ -+ -+ -+ -+ Decoding with syndrome given by hardware decoder, no direct data correction. -+ -+ -+ Note: It's not necessary to give data and received parity to the decoder. -+ -+ -+/* 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]); -+} -+ -+ -+ -+ -+ Cleanup -+ -+ The function free_rs frees the allocated resources, -+ if the caller is the last user of the decoder. -+ -+ -+/* Release resources */ -+free_rs(rs_decoder); -+ -+ -+ -+ -+ -+ -+ Structures -+ -+ This chapter contains the autogenerated documentation of the structures which are -+ used in the Reed-Solomon Library and are relevant for a developer. -+ -+!Iinclude/linux/rslib.h -+ -+ -+ -+ Public Functions Provided -+ -+ This chapter contains the autogenerated documentation of the Reed-Solomon functions -+ which are exported. -+ -+!Elib/reed_solomon/reed_solomon.c -+ -+ -+ -+ Credits -+ -+ The library code for encoding and decoding was written by Phil Karn. -+ -+ -+ Copyright 2002, Phil Karn, KA9Q -+ May be used under the terms of the GNU General Public License (GPL) -+ -+ -+ The wrapper functions and interfaces are written by Thomas Gleixner -+ -+ -+ Many users have provided bugfixes, improvements and helping hands for testing. -+ Thanks a lot. -+ -+ -+ The following people have contributed to this document: -+ -+ -+ Thomas Gleixnertglx@linutronix.de -+ -+ -+
---- /dev/null -+++ linux-2.4.21/Documentation/DocBook/mtdnand.tmpl -@@ -0,0 +1,1318 @@ -+ -+ -+ -+ -+ MTD NAND Driver Programming Interface -+ -+ -+ -+ Thomas -+ Gleixner -+ -+
-+ tglx@linutronix.de -+
-+
-+
-+
-+ -+ -+ 2004 -+ Thomas Gleixner -+ -+ -+ -+ -+ 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. -+ -+ -+ -+ This program is distributed in the hope that it will be -+ useful, but WITHOUT ANY WARRANTY; without even the implied -+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -+ See the GNU General Public License for more details. -+ -+ -+ -+ You 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 -+ -+ -+ -+ For more details see the file COPYING in the source -+ distribution of Linux. -+ -+ -+
-+ -+ -+ -+ -+ Introduction -+ -+ 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. -+ -+ -+ This documentation is provided for developers who want to implement -+ board drivers or filesystem drivers suitable for NAND devices. -+ -+ -+ -+ -+ Known Bugs And Assumptions -+ -+ None. -+ -+ -+ -+ -+ Documentation hints -+ -+ 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. -+ -+ -+ Function identifiers [XXX] -+ -+ 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: -+ -+ -+ -+ [MTD Interface] -+ These functions provide the interface to the MTD kernel API. -+ They are not replacable and provide functionality -+ which is complete hardware independent. -+ -+ -+ [NAND Interface] -+ These functions are exported and provide the interface to the NAND kernel API. -+ -+ -+ [GENERIC] -+ Generic functions are not replacable and provide functionality -+ which is complete hardware independent. -+ -+ -+ [DEFAULT] -+ 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. -+ -+ -+ -+ -+ Struct member identifiers [XXX] -+ -+ 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: -+ -+ -+ -+ [INTERN] -+ 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(). -+ -+ -+ [REPLACEABLE] -+ 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. -+ -+ -+ [BOARDSPECIFIC] -+ 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(). -+ -+ -+ [OPTIONAL] -+ Optional members can hold information relevant for the board driver. The -+ generic NAND driver code does not use this information. -+ -+ -+ -+ -+ -+ -+ Basic board driver -+ -+ 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. -+ -+ -+ Basic defines -+ -+ 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. -+ -+ -+ Kmalloc based example -+ -+ -+static struct mtd_info *board_mtd; -+static unsigned long baseaddr; -+ -+ -+ Static example -+ -+ -+static struct mtd_info board_mtd; -+static struct nand_chip board_chip; -+static unsigned long baseaddr; -+ -+ -+ -+ Partition defines -+ -+ 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. -+ -+ -+#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 }, -+}; -+ -+ -+ -+ Hardware control function -+ -+ 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. -+ -+ -+ GPIO based example -+ -+ -+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; -+ } -+} -+ -+ -+ Address lines based example. It's assumed that the -+ nCE pin is driven by a chip select decoder. -+ -+ -+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; -+ } -+} -+ -+ -+ -+ Device ready function -+ -+ 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. -+ -+ -+ -+ Init function -+ -+ 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. -+ -+ -+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); -+ -+ -+ -+ Exit function -+ -+ 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. -+ -+ -+#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 -+ -+ -+ -+ -+ -+ Advanced board driver functions -+ -+ 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. -+ -+ -+ Multiple chip control -+ -+ 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. -+ -+ -+ The nand driver concatenates the chips to one virtual -+ chip and provides this virtual chip to the MTD layer. -+ -+ -+ Note: The driver can only handle linear chip arrays -+ of equally sized chips. There is no support for -+ parallel arrays which extend the buswidth. -+ -+ -+ GPIO based example -+ -+ -+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); -+} -+ -+ -+ Address lines based example. -+ Its assumed that the nCE pins are connected to an -+ address decoder. -+ -+ -+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; -+ } -+} -+ -+ -+ -+ Hardware ECC support -+ -+ Functions and constants -+ -+ The nand driver supports three different types of -+ hardware ECC. -+ -+ NAND_ECC_HW3_256 -+ Hardware ECC generator providing 3 bytes ECC per -+ 256 byte. -+ -+ NAND_ECC_HW3_512 -+ Hardware ECC generator providing 3 bytes ECC per -+ 512 byte. -+ -+ NAND_ECC_HW6_512 -+ Hardware ECC generator providing 6 bytes ECC per -+ 512 byte. -+ -+ NAND_ECC_HW8_512 -+ Hardware ECC generator providing 6 bytes ECC per -+ 512 byte. -+ -+ -+ If your hardware generator has a different functionality -+ add it at the appropriate place in nand_base.c -+ -+ -+ The board driver must provide following functions: -+ -+ enable_hwecc -+ 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. -+ -+ calculate_ecc -+ 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. -+ -+ correct_data -+ 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. -+ -+ -+ -+ -+ -+ Hardware ECC with syndrome calculation -+ -+ 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. -+ -+ -+ 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. -+ -+ -+ -+ -+ Bad block table support -+ -+ 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. -+ -+ -+ The nand driver supports various types of bad block -+ tables. -+ -+ Per device -+ The bad block table contains all bad block information -+ of the device which can consist of multiple chips. -+ -+ Per chip -+ A bad block table is used per chip and contains the -+ bad block information for this particular chip. -+ -+ Fixed offset -+ The bad block table is located at a fixed offset -+ in the chip (device). This applies to various -+ DiskOnChip devices. -+ -+ Automatic placed -+ The bad block table is automatically placed and -+ detected either at the end or at the beginning -+ of a chip (device) -+ -+ Mirrored tables -+ The bad block table is mirrored on the chip (device) to -+ allow updates of the bad block table without data loss. -+ -+ -+ -+ -+ 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(). -+ -+ -+ 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. -+ -+ -+ Flash based tables -+ -+ 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. -+ -+ -+ 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. -+ -+ -+ 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 -+ -+ Store bad block table per chip -+ Use 2 bits per block -+ Automatic placement at the end of the chip -+ Use mirrored tables with version numbers -+ Reserve 4 blocks at the end of the chip -+ -+ -+ -+ -+ User defined tables -+ -+ 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. -+ -+ -+ 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. -+ -+ Number of bits per block -+ The supported number of bits is 1, 2, 4, 8. -+ Table per chip -+ 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. -+ Table location is absolute -+ 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 -+ Table location is automatically detected -+ 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. -+ Table creation -+ 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. -+ Table write support -+ 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. -+ -+ Note: Write support should only be enabled for mirrored tables with -+ version control. -+ -+ Table version control -+ 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. -+ Save block contents on write -+ -+ 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. -+ -+ Number of reserved blocks -+ -+ 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. -+ -+ -+ -+ -+ -+ -+ Spare area (auto)placement -+ -+ The nand driver implements different possibilities for -+ placement of filesystem data in the spare area, -+ -+ Placement defined by fs driver -+ Automatic placement -+ -+ 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. -+ -+ -+ File system drivers can provide a own placement scheme which -+ is used instead of the default placement scheme. -+ -+ -+ Placement schemes are defined by a nand_oobinfo structure -+ -+struct nand_oobinfo { -+ int useecc; -+ int eccbytes; -+ int eccpos[24]; -+ int oobfree[8][2]; -+}; -+ -+ -+ useecc -+ 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. -+ -+ eccbytes -+ The eccbytes member defines the number of ecc bytes per page. -+ -+ eccpos -+ The eccpos array holds the byte offsets in the spare area where -+ the ecc codes are placed. -+ -+ oobfree -+ 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. -+ -+ -+ -+ -+ Placement defined by fs driver -+ -+ 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 -+ -+ -+ <spare data page 0><ecc result 0>...<ecc result n> -+ -+ -+ ... -+ -+ -+ <spare data page n><ecc result 0>...<ecc result n> -+ -+ -+ This is a legacy mode used by YAFFS1. -+ -+ -+ If the spare area buffer is NULL then only the ECC placement is -+ done according to the given scheme in the nand_oobinfo structure. -+ -+ -+ -+ Automatic placement -+ -+ 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. -+ -+ -+ If the spare area buffer is NULL then only the ECC placement is -+ done according to the default builtin scheme. -+ -+ -+ -+ User space placement selection -+ -+ 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. -+ -+ ioctl (fd, MEMSETOOBSEL, oobsel); -+ -+ 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. -+ -+ -+ -+ -+ Spare area autoplacement default schemes -+ -+ 256 byte pagesize -+ -+ -+Offset -+Content -+Comment -+ -+ -+0x00 -+ECC byte 0 -+Error correction code byte 0 -+ -+ -+0x01 -+ECC byte 1 -+Error correction code byte 1 -+ -+ -+0x02 -+ECC byte 2 -+Error correction code byte 2 -+ -+ -+0x03 -+Autoplace 0 -+ -+ -+ -+0x04 -+Autoplace 1 -+ -+ -+ -+0x05 -+Bad block marker -+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 -+ -+ -+0x06 -+Autoplace 2 -+ -+ -+ -+0x07 -+Autoplace 3 -+ -+ -+ -+ -+ -+ 512 byte pagesize -+ -+ -+Offset -+Content -+Comment -+ -+ -+0x00 -+ECC byte 0 -+Error correction code byte 0 of the lower 256 Byte data in -+this page -+ -+ -+0x01 -+ECC byte 1 -+Error correction code byte 1 of the lower 256 Bytes of data -+in this page -+ -+ -+0x02 -+ECC byte 2 -+Error correction code byte 2 of the lower 256 Bytes of data -+in this page -+ -+ -+0x03 -+ECC byte 3 -+Error correction code byte 0 of the upper 256 Bytes of data -+in this page -+ -+ -+0x04 -+reserved -+reserved -+ -+ -+0x05 -+Bad block marker -+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 -+ -+ -+0x06 -+ECC byte 4 -+Error correction code byte 1 of the upper 256 Bytes of data -+in this page -+ -+ -+0x07 -+ECC byte 5 -+Error correction code byte 2 of the upper 256 Bytes of data -+in this page -+ -+ -+0x08 - 0x0F -+Autoplace 0 - 7 -+ -+ -+ -+ -+ -+ 2048 byte pagesize -+ -+ -+Offset -+Content -+Comment -+ -+ -+0x00 -+Bad block marker -+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 -+ -+ -+0x01 -+Reserved -+Reserved -+ -+ -+0x02-0x27 -+Autoplace 0 - 37 -+ -+ -+ -+0x28 -+ECC byte 0 -+Error correction code byte 0 of the first 256 Byte data in -+this page -+ -+ -+0x29 -+ECC byte 1 -+Error correction code byte 1 of the first 256 Bytes of data -+in this page -+ -+ -+0x2A -+ECC byte 2 -+Error correction code byte 2 of the first 256 Bytes data in -+this page -+ -+ -+0x2B -+ECC byte 3 -+Error correction code byte 0 of the second 256 Bytes of data -+in this page -+ -+ -+0x2C -+ECC byte 4 -+Error correction code byte 1 of the second 256 Bytes of data -+in this page -+ -+ -+0x2D -+ECC byte 5 -+Error correction code byte 2 of the second 256 Bytes of data -+in this page -+ -+ -+0x2E -+ECC byte 6 -+Error correction code byte 0 of the third 256 Bytes of data -+in this page -+ -+ -+0x2F -+ECC byte 7 -+Error correction code byte 1 of the third 256 Bytes of data -+in this page -+ -+ -+0x30 -+ECC byte 8 -+Error correction code byte 2 of the third 256 Bytes of data -+in this page -+ -+ -+0x31 -+ECC byte 9 -+Error correction code byte 0 of the fourth 256 Bytes of data -+in this page -+ -+ -+0x32 -+ECC byte 10 -+Error correction code byte 1 of the fourth 256 Bytes of data -+in this page -+ -+ -+0x33 -+ECC byte 11 -+Error correction code byte 2 of the fourth 256 Bytes of data -+in this page -+ -+ -+0x34 -+ECC byte 12 -+Error correction code byte 0 of the fifth 256 Bytes of data -+in this page -+ -+ -+0x35 -+ECC byte 13 -+Error correction code byte 1 of the fifth 256 Bytes of data -+in this page -+ -+ -+0x36 -+ECC byte 14 -+Error correction code byte 2 of the fifth 256 Bytes of data -+in this page -+ -+ -+0x37 -+ECC byte 15 -+Error correction code byte 0 of the sixt 256 Bytes of data -+in this page -+ -+ -+0x38 -+ECC byte 16 -+Error correction code byte 1 of the sixt 256 Bytes of data -+in this page -+ -+ -+0x39 -+ECC byte 17 -+Error correction code byte 2 of the sixt 256 Bytes of data -+in this page -+ -+ -+0x3A -+ECC byte 18 -+Error correction code byte 0 of the seventh 256 Bytes of -+data in this page -+ -+ -+0x3B -+ECC byte 19 -+Error correction code byte 1 of the seventh 256 Bytes of -+data in this page -+ -+ -+0x3C -+ECC byte 20 -+Error correction code byte 2 of the seventh 256 Bytes of -+data in this page -+ -+ -+0x3D -+ECC byte 21 -+Error correction code byte 0 of the eigth 256 Bytes of data -+in this page -+ -+ -+0x3E -+ECC byte 22 -+Error correction code byte 1 of the eigth 256 Bytes of data -+in this page -+ -+ -+0x3F -+ECC byte 23 -+Error correction code byte 2 of the eigth 256 Bytes of data -+in this page -+ -+ -+ -+ -+ -+ -+ -+ Filesystem support -+ -+ The NAND driver provides all neccecary functions for a -+ filesystem via the MTD interface. -+ -+ -+ 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. -+ -+ -+ 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. -+ -+ -+ 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. -+ -+ -+ -+ Tools -+ -+ The MTD project provides a couple of helpful tools to handle NAND Flash. -+ -+ flasherase, flasheraseall: Erase and format FLASH partitions -+ nandwrite: write filesystem images to NAND FLASH -+ nanddump: dump the contents of a NAND FLASH partitions -+ -+ -+ -+ 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. -+ -+ -+ -+ -+ Constants -+ -+ This chapter describes the constants which might be relevant for a driver developer. -+ -+ -+ Chip option constants -+ -+ Constants for chip id table -+ -+ These constants are defined in nand.h. They are ored together to describe -+ the chip functionality. -+ -+/* 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 -+ -+ -+ -+ -+ Constants for runtime options -+ -+ These constants are defined in nand.h. They are ored together to describe -+ the functionality. -+ -+/* 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 -+ -+ -+ -+ -+ -+ -+ ECC selection constants -+ -+ Use these constants to select the ECC algorithm. -+ -+/* 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 -+ -+ -+ -+ -+ -+ Hardware control related constants -+ -+ These constants describe the requested hardware access function when -+ the boardspecific hardware control function is called -+ -+/* 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 -+ -+ -+ -+ -+ -+ Bad block table related constants -+ -+ These constants describe the options used for bad block -+ table descriptors. -+ -+/* 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 -+ -+ -+ -+ -+ -+ -+ -+ Structures -+ -+ 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. -+ -+!Iinclude/linux/mtd/nand.h -+ -+ -+ -+ Public Functions Provided -+ -+ 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. -+ -+!Edrivers/mtd/nand/nand_base.c -+!Edrivers/mtd/nand/nand_bbt.c -+!Edrivers/mtd/nand/nand_ecc.c -+ -+ -+ -+ Internal Functions Provided -+ -+ 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. -+ -+!Idrivers/mtd/nand/nand_base.c -+!Idrivers/mtd/nand/nand_bbt.c -+!Idrivers/mtd/nand/nand_ecc.c -+ -+ -+ -+ Credits -+ -+ The following people have contributed to the NAND driver: -+ -+ Steven J. Hillsjhill@realitydiluted.com -+ David Woodhousedwmw2@infradead.org -+ Thomas Gleixnertglx@linutronix.de -+ -+ A lot of users have provided bugfixes, improvements and helping hands for testing. -+ Thanks a lot. -+ -+ -+ The following people have contributed to this document: -+ -+ Thomas Gleixnertglx@linutronix.de -+ -+ -+ -+
---- 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 -+ -+ 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 -+ * -+ * Sample code on how to use request_firmware() from drivers. -+ * -+ * Note that register_firmware() is currently useless. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#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 -+ * 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 -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#ifdef CONFIG_SA1100_H3XXX -+#include -+#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 - --#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 - #include - -+#ifdef CONFIG_PXA_RTC_HACK -+#include -+#include -+#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 -+ */ -+ 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 -+ * -+ * 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 & -+ * Chester Kuo -+ * Save more value for the resume function! Support -+ * Bitsy/Assabet/Freebird board -+ * -+ * 2001-08-29: Nicolas Pitre -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+ -+#ifdef CONFIG_IPAQ_HANDHELD -+#include -+#endif -+ -+#define __KERNEL_SYSCALLS__ -+#include -+ -+ -+ -+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 - #include - #include -+#include - - #include - #include -@@ -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 -+ * Initial code -+ * -+ * 2002-10-09: adaptions to ramses -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#ifdef CONFIG_APM -+#include -+#endif -+#define USE_UCB -+//#define PFI_LED -+#define PFI_TURNOFF -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#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 %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 -+ * -+ * -+ * This program is free software; you can redistribute 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 -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+ -+#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 "); -+ -+ 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 "); -+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 - #include - --#define __KERNEL_SYSCALLS__ -- - #include - #include - #include -@@ -48,6 +46,8 @@ - #include - #include - -+#include -+ - #include - #include - #include -@@ -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(¤t->sigmask_lock); -- tmpsig = current->blocked; -- siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)); -- recalc_sigpending(current); -- spin_unlock_irq(¤t->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(¤t->sigmask_lock); -- current->blocked = tmpsig; -- recalc_sigpending(current); -- spin_unlock_irq(¤t->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 - - #include --#include - #include - #include - #include -@@ -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 - - #include --#include - #include - #include - #include ---- 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 - #include -@@ -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 "); -+MODULE_AUTHOR("Maxim Krasnyansky , Marcel Holtmann "); - 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 -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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 -+ * 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 -+#include -+ -+#include -+#include -+ -+/* 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 -- * -- * 03/96: Modularised by Angelo Haritsis -- * -- * 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 -- * -- * 8/97: Fix bug in rs_set_termios with RTS -- * Stanislav V. Voronyi -- * -- * 3/98: Change the IRQ detection, use of probe_irq_o*(), -- * suppress TIOCSERGWILD and TIOCSERSWILD -- * Etienne Lorrain -- * -- * 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 -- * -- * 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 -- * -- * 5/00: Support for the RSA-DV II/S card added. -- * Kiyokazu SUTO -- * -- * 6/00: Remove old-style timer, use timer_list -- * Andrew Morton -- * -- * 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 -- * -- * 10/00: add in optional software flow control for serial console. -- * Kanoj Sarcar (Modified by Theodore Ts'o) -- * -- * 02/02: Fix for AMD Elan bug in transmit irq routine, by -- * Christer Weinigel , -- * Robert Schwebel , -- * Juergen Beisert , -- * Theodore Ts'o -- */ -- --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 - #include - --#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 - #include - #include --#if (LINUX_VERSION_CODE >= 131343) - #include --#endif --#if (LINUX_VERSION_CODE >= 131336) - #include --#endif - #include - #ifdef CONFIG_SERIAL_CONSOLE - #include - #endif --#ifdef ENABLE_SERIAL_PCI --#include --#endif --#ifdef ENABLE_SERIAL_PNP --#include --#endif - #ifdef CONFIG_MAGIC_SYSRQ - #include - #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 - #include - #include - #include - --#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<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<iomem_reg_shift)); -+ if (show_io) printk("in %02x = %02x\n", offset, value); -+ return value; - return readl((unsigned long) info->iomem_base + - (offset<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<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<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 -- X(register_serial), -- X(unregister_serial), --#include --}; --#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 , 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 */ -- { 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#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 "); -+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 -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+// 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 "); -+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 -+ * -+ * Changes/Revisions: -+ * 0.1 20/06/2002 -+ * - first public version -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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 -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+ -+ -+// 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; ibuf); - 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 "); -+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 - #include - #include -+#include - - #include - #include -@@ -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 - #include -+#include - - #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 "); - 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 - * -- * $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 - #include - #include -+#include - #include - #include - #include -@@ -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 -@@ -21,6 +21,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -28,21 +29,39 @@ - #include - #include - #include -+#include - #include --#include -+#include - #include -+#include - --// 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<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; iMajorVersion != '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<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<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)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<FactProtRegSize); -- reg_sz=(1<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<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 (inumeraseregions && (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> (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> (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 && inumchips; 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. -+ * Copyright (C) 2004 Arcom Control Systems Ltd - * - * 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 - #include - #include - #include - #include -+#include - #include - #include - -@@ -23,15 +30,24 @@ - #include - #include - #include -+#include - #include -+#include - #include - - #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<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<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<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<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 (inumeraseregions && (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. 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 - * - completely revamped method functions so they are aware and -@@ -17,10 +18,12 @@ - * - added a writev function - */ - -+#include - #include - #include - #include - #include -+#include - #include - #include - -@@ -30,12 +33,13 @@ - #include - #include - #include -+#include - #include - - - 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; iMajorVersion != '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> (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> (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 - #include - #include - #include -+#include - #include - #include - #include - #include - #include - -+#include - #include - #include - #include -@@ -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; inumchips; 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 -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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; idevice_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 (inumeraseregions && (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 - #include -+#include - #include - #include --#include -+#include - #include -+#include -+#include - --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 "); ---- /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 -+#include -+#include - #include - #include - #include -@@ -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<size; -- base += (1<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 -+#include -+#include - #include -+#include -+#include -+#include - - 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)<addrshift)) -- #define flwrite(v,x) map->write8(map,v,chip->base+((x)<addrshift)) -+ #define flread(x) map_read8(map,chip->base+((x)<addrshift)) -+ #define flwrite(v,x) map_write8(map,v,chip->base+((x)<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<addrshift)-1))+((x)<addrshift)) -- #define flwrite(v,x) map->write8(map,v,base+(off&((1<addrshift)-1))+((x)<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<addrshift)-1))+((x)<addrshift)) -+ #define flwrite(v,x) map_write8(map,v,base+(off&((1<addrshift)-1))+((x)<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 - #include -+#include - #include - #include - #include -@@ -15,7 +18,9 @@ - #include - #include - #include -+#include - -+#include - #include - #include - #include -@@ -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; icfiq->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; imfr == 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; inumchips; 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 -- * $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 - #include - #include -- -+#include -+#include - #include -- -+#include - - 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 -@@ -11,8 +11,10 @@ - #include - #include - #include -- -+#include -+#include - #include -+#include - - - 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; ilen; i++) -- map->write8(map, 0xFF, instr->addr + i); -+ allff = map_word_ff(map); - -- if (instr->callback) -- instr->callback(instr); -+ for (i=0; ilen; 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 - #include - #include - #include -@@ -12,21 +11,23 @@ - #include - #include - #include -- -+#include -+#include - #include -+#include - - 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 - * 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 - #include --#include - #include - #include - #include - #include - #include -+#include - #include - #include -+#include - - #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=[; := :[,] - * := [@offset][][ro] -- * := unique id used in mapping driver/device -+ * := unique name used in mapping driver/device (mtd->name) - * := standard linux memsize OR "-" to denote all remaining space - * := '(' NAME ')' - * -@@ -28,7 +28,6 @@ - - #include - #include --#include - #include - - /* 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 "); ---- 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 -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_MTD_DEBUG -+#ifdef CONFIG_PROC_FS -+# include -+# 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 "); -+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 - #include - #include --#include --#include -+#include - #include - #include -+#include - #include - --#ifdef CONFIG_MTD_DEBUG --#ifdef CONFIG_PROC_FS --# include --# 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 -+ * Copyright (C) 2004,2005 Jörn Engel -+ * -+ * Licence: GPL -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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); ppriv; -+ 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=[,]\""); -+ -+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 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 - * -- * $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 -@@ -19,12 +19,14 @@ - #include - #include - #include -+#include - - #include - #include - #include - - #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 - * -- * $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 -@@ -19,6 +19,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -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 -+ * (c) 2002-2003 SnapGear Inc -+ * (c) 1999 Machine Vision Holdings, Inc. -+ * (c) 1999, 2000 David Woodhouse -+ * -+ * $Id: doc2001plus.c,v 1.13 2005/01/05 18:05:12 dwmw2 Exp $ -+ * -+ * Released under GPL -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+/* #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 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 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 "); - 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 */ - --/* $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 -+ . - */ - #define DOC_SINGLE_DRIVER - -@@ -47,18 +45,15 @@ - #include - #include - #include --#include --#include --#include - #include - #include --#include - #include - #include - - #include - #include - #include -+#include - - /* 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 - * -@@ -42,7 +42,7 @@ - #include - #include - #include --#include -+#include - #include - #include - #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 -@@ -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 "); -+MODULE_AUTHOR("Maciej W. Rozycki "); - 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 - #include - -+/* -+ * 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 - * - * Copyright (c) 1999 Alexander Larsson -@@ -13,6 +13,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - -@@ -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 -+ * Copyright (c) 2003-2004 Jörn Engel -+ * -+ * Usage: -+ * -+ * one commend line parameter per device, each in the form: -+ * phram=,, -+ * may be up to 63 characters. -+ * and 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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=,,\""); -+ -+ -+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 "); -+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 - #include - #include - #include -@@ -108,17 +109,11 @@ - #include - #include - --#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 - - #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 - * - 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 - #include --#include - #include - /*#define PSYCHO_DEBUG */ - -@@ -68,43 +68,13 @@ - #include - #include - #include --#include -+#include - #include -- --#if (LINUX_VERSION_CODE >= 0x20100) - #include --#endif --#if (LINUX_VERSION_CODE >= 0x20303) - #include --#endif -+#include - - #include --/*====================================================================*/ --/* 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 - - /*====================================================================*/ - -@@ -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 = (0x100000mtd->size)?0x100000:part->mtd->size; -+ max_offset = (0x100000mbd.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 -+ * -+ * $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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * 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 , David Woodhouse , Fabrice Bellard 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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 - #include - #include -+#include - #include - #include - #include -+#include -+#include - #include - #include - #include -+#include -+ -+ -+#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 -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+/* -+ * 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 "); -+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 - #include - #include -+#include - #include - #include - #include -@@ -32,80 +33,27 @@ - #include - #include - --__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 -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#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 "); -+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 -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#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 "); -+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 - #include - #include - #include -+#include - #include - #include - #include -@@ -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 - * -- * $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 -@@ -19,6 +19,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -31,62 +32,10 @@ - #include - - /* -- * 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 - * -- * $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 - #include - #include -+#include - #include - #include - #include -@@ -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: -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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(""); -+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 - #include - #include -+#include - #include - #include - #include - #include - #include -- --#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) - #include --#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;imodule = 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 - #include - #include -+#include - #include - #include - #include - #include - #include -+#include - - /* 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 "); --MODULE_DESCRIPTION("MTD map driver for Nokia/Sagem D-Box 2 board"); -+MODULE_AUTHOR("Kári Davíđsson , Bastian Blank , Alexander Wild "); -+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 - #include - #include - #include -+#include -+#include - - #include - #include -@@ -18,143 +20,199 @@ - - #include - #include -+#include - - --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 - #include - #include -+#include - #include - #include - #include -@@ -36,7 +37,7 @@ - #include - - /* --** 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * 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 "); -+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 -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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 "); -+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 - #include - #include -+#include - #include - #include - #include -@@ -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 -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#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; inumeraseregions;i++){ -+ int j; -+ for(j=0;jeraseregions[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 - #include - #include -+#include - #include - #include - #include -@@ -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 -+ * 2003 Thomas Gleixner -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+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 "); -+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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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 "); -+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 - #include - #include -+#include - #include - #include - #include -@@ -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; imodule = 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+// 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 - #include - #include -+#include - #include - - #include - #include - #include - -+#include - #include - #include - #include - --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 -+ * (C) 2002 Hewlett-Packard Company -+ * (C) 2003 Christian Pellegrin , : concatenation of multiple flashes -+ * -+ * $Id: ipaq-flash.c,v 1.4 2005/01/12 22:34:35 gleixner Exp $ -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#ifdef CONFIG_MTD_CONCAT -+#include -+#endif -+ -+#include -+#include -+#include -+ -+ -+#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; isize); -+ -+ /* 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 - #include - #include -+#include -+#include - #include - #include - #include -@@ -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 -+ * Maintainer: Deepak Saxena -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+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 "); -+ ---- /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 -+ * -+ * Copyright (C) 2002 Intel Corporation -+ * Copyright (C) 2003-2004 MontaVista Software, Inc. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#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 - #include - #include -+#include - #include - #include - #include -@@ -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 or whoever he -- * works for. -+ * (C) 2002 Brian Murphy - * - * 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 - #include - #include -+#include - #include - #include - #include - #include - #include - #include --#include -- --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 "); ---- /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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+#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 "); -+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 -+#include -+ -+#include -+ -+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 - #include - #include -+#include - #include - #include - #include -@@ -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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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 "); -+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 -+ */ -+#include -+#include -+#include -+#include -+ -+ -+#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; ivirt) -+ 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"); -+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 - #include - #include -+#include - #include - #include - #include -@@ -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 - #include - #include -+#include - #include - #include - #include -@@ -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 -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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 "); -+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 - - #include -+#include - - #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 -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+ -+#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 - #include - #include -+#include - #include - #include - -@@ -24,6 +25,7 @@ - #include - - #include -+#include - - #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 "); - 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 - #include - #include -+#include -+#include - #include - #include - #include - #include -- --#ifdef CONFIG_MTD_PARTITIONS - #include --#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 -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* 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 "); -+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 - #include - #include -+#include - - #include - #include -@@ -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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#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. - * -+ * 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 - #include - #include - #include -+#include - - #include - #include -@@ -40,96 +25,102 @@ - - #include - -+#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 "); -+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 - #include - #include -+#include - #include - #include - #include -@@ -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 - * -- * $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 -@@ -11,330 +11,212 @@ - #include - #include - #include -+#include -+#include -+#include - - #include - #include - #include -+#include - - #include -+#include - #include -+#include - -+#include - - #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) -+ * -+ * -+ * -+ * 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 -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#ifdef CONFIG_MTD_PARTITIONS -+#include -+#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 "); -+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 - #include - #include -+#include - #include - #include - #include -@@ -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 - * -@@ -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 - #include - #include -+#include - #include - #include - #include -@@ -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 - -- $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 - #include - #include -+#include - #include - #include - #include -@@ -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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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 )"); -+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 - #include - #include -+#include - #include - #include - #include - #include - #include -- -- --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 - - 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 - #include --#include - #include - #include - #include -@@ -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 - #include - #include -+#include - #include - - #include -@@ -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 -+ * -+ * This program is free software; you can redistribute 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_MTD_PARTITIONS -+#include -+#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 "); -+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 - #include -+#include - #include -+#include - - #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 - #include - #include -+#include - #include - #include - #include -@@ -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 - - #include -+#include - - - #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 -+ * -+ * -+ * This program is free software; you can redistribute 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* 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 "); -+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 -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+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 "); -+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 -+ * -+ * Interface to Linux 2.4 block layer for MTD 'translation layers'. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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(¤t->sigmask_lock); -+ sigfillset(¤t->blocked); -+ recalc_sigpending(); -+ spin_unlock_irq(¤t->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<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<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; -+ } -+ -+ /* -+ dwmw2: BLOCK_SIZE_BITS has nothing to do with block devices -+ 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<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; itype != 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 "); -+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 -+ * -+ * Interface to Linux 2.5 block layer for MTD 'translation layers'. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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(¤t->sighand->siglock); -+ sigfillset(¤t->blocked); -+ recalc_sigpending(); -+ spin_unlock_irq(¤t->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; itype != 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 "); -+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 -+ * (C) 1999-2003 David Woodhouse - */ - - #include - #include - #include - #include -+#include -+#include - #include -+#include - #include --#include -- --#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 --/* 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 --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 - - 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(¬ifier); --#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(¬ifier); -- 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 -+ * -+ * Simple read-only (writable only for RAM) mtdblock driver - */ - --#ifdef MTDBLOCK_DEBUG --#define DEBUGLVL debug --#endif -- -- --#include --#include -- -+#include -+#include - #include --#include -- --#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 -- --#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 - --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 et al."); -+MODULE_AUTHOR("David Woodhouse "); - 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 - #include - #include -+#include - #include -+#include -+#include -+#include - - #ifdef CONFIG_DEVFS_FS - #include -+#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(¬ifier); -+#else -+ devfs_dir_handle = devfs_mk_dir(NULL, "mtd", NULL); -+ -+ register_mtd_user(¬ifier); -+#endif -+} -+ -+static inline void mtdchar_devfs_exit(void) -+{ -+ unregister_mtd_user(¬ifier); -+ 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(¬ifier); --#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(¬ifier); -- 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 - * -+ * NAND support by Christian Gan -+ * - * 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 -@@ -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 "); - 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 - #include - #include -+#include - #include - #ifdef CONFIG_PROC_FS - #include -@@ -24,9 +25,15 @@ - - #include - --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 - * added support for read_oob, write_oob -@@ -16,10 +16,11 @@ - #include - #include - #include -- -+#include -+#include - #include - #include -- -+#include - - /* 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 "); ---- 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* fixme: this is ugly */ -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0) -+#include -+#ifdef CONFIG_MIPS_PB1550 -+#include -+#endif -+#ifdef CONFIG_MIPS_DB1550 -+#include -+#endif -+#else -+#include -+#ifdef CONFIG_MIPS_PB1550 -+#include -+#endif -+#ifdef CONFIG_MIPS_DB1550 -+#include -+#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; iIO_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; iIO_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; iIO_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; iIO_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; iIO_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; iIO_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 - * - * 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 - #include -+#include - #include - #include - #include -@@ -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 -+ * (C) 2004 Kalev Lember -+ * -+ * Author: David Woodhouse -+ * Additional Diskonchip 2000 and Millennium support by Dan Brown -+ * Diskonchip Millennium Plus support by Kalev Lember -+ * -+ * 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 -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* 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 "); -+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 - #include -+#include - #include - #include - #include -@@ -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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include /* for CLPS7111_VIRT_BASE */ -+#include -+#include -+#include -+ -+/* -+ * 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 "); -+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 -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_MTD_PARTITIONS -+#include -+#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; iIO_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; iIO_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; iIO_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; iIO_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; iIO_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; iIO_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 , Thomas Gleixner "); -+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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+/** -+ * 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 - #include - #include -+#include - - /* - * 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 "); -+MODULE_AUTHOR("Steven J. Hill "); - 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 - #include -- - /* - * 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 , -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#ifdef CONFIG_NS_ABS_POS -+#include -+#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],
-+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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 "); -+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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * 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 -+ * -+ * 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 -+#include -+ -+#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG -+#define DEBUG -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#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 "); -+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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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 "); -+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 -+#include - #include - #include - #include -@@ -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 -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * 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 "); -+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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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; iIO_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; iIO_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; iIO_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 "); -+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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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; iIO_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; iIO_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; iIO_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 "); -+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 */ --/* $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 - #include - #include --#include -+#include - --#ifdef CONFIG_KMOD - #include --#endif - #include - #include - #include --#include -+#include - - /* 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 --#include -- --/* 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<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<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< 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<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<rq_dev)); -- res = 0; /* fail */ -- goto repeat; -- } -- -- nftl = NFTLs[dev / (1<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 --#include - #include --#include --#include --#include --#include - #include - #include --#include --#include - #include - #include - #include --#include - - #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 - #include -+#include -+#include - - #include - #include -@@ -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 ( ; iimg->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 "); ---- /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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+#if (LINUX_VERSION_CODE >= 0x20100) -+#include -+#endif -+#if (LINUX_VERSION_CODE >= 0x20303) -+#include -+#endif -+ -+#include -+ -+#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 -+ -+#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; iminor[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; zonezoneCount; 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; scmtd->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 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; scmtd, &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; blast_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; scmtd->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; bmtd->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; bsmc_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"); -+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 - #include - -+#include - #include - #include - #include -@@ -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 \n"; -+ DRV_NAME ": v1.1 Aug 20 2003 by Nicolas Pitre \n"; - - /* Debugging level */ - #ifndef SMC_DEBUG -@@ -67,6 +70,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -78,6 +82,7 @@ - #include - #include - #include -+#include - - #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 - #define SMC_IOADDR (RAMSES_ETH_PHYS + 0x300) - #define SMC_IRQ ETHERNET_IRQ -+ -+#elif CONFIG_ARCH_RAMSES -+#include -+#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 "; - MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller"); - MODULE_AUTHOR("David Gibson "); - #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 - - #include - #include - #include --#include - #include - #include - #include - #include - #include --#include --#include --#include - #include - #include - #include - #include - -+#include -+#include -+#include -+ - #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 and others)"; -+static char version[] __initdata = "orinoco.c 0.13e (David Gibson 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 - #include - #include --#include -+#include - #include "hermes.h" - -+/* Workqueue / task queue backwards compatibility stuff */ -+ -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41) -+#include -+#else -+#include -+#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 - #include - #include --#include - #include --#include --#include --#include - #include - #include - #include -@@ -38,7 +34,10 @@ - #include - #include - #include --#include -+ -+#include -+#include -+#include - - #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 and others)"; -+static char version[] __initdata = "orinoco_cs.c 0.13e (David Gibson 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 -+#include -+ -+#include -+ -+#include -+#include -+#include -+#include -+ -+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 - #include - #include -+#include - - #include - #include -@@ -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 -+ * 3.Rewrited as sl811.o by Yin Aihua -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "../hcd.h" -+#include "../hub.h" -+#include "sl811.h" -+ -+#define DRIVER_VERSION "v0.30" -+#define MODNAME "SL811" -+#define DRIVER_AUTHOR "Yin Aihua , Henry Nestler " -+#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 /* 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