diff -u --recursive --new-file v2.4.5/linux/CREDITS linux/CREDITS
--- v2.4.5/linux/CREDITS	Tue May 22 19:54:04 2001
+++ linux/CREDITS	Tue Jun 12 10:57:05 2001
@@ -1356,13 +1356,15 @@
 E: davej@suse.de
 W: http://www.suse.de/~davej
 D: Moved PCI bridge tuning to userspace (Powertweak).
-D: Centaur/IDT Winchip/Winchip 2 tweaks.
+D: Various x86 (& clones) setup code hacking.
 D: AFFS fixes for 2.3.x
-D: Misc clean ups and other random hacking.
-S: 28, Laura Street,
-S: Treforest, Pontypridd,
-S: Mid Glamorgan, CF37 1NW,
-S: Wales, United Kingdom
+D: Various Janitorial hacks. (kernel-janitor.sourceforge.net)
+S: c/o SuSE Linux UK Ltd
+S: The Kinetic Centre
+S: Theobald Street
+S: Borehamwood
+S: Herts, WD6 4PJ
+S: United Kingdom
 
 N: Ani Joshi
 E: ajoshi@shell.unixbox.com
@@ -1518,6 +1520,17 @@
 S: L3R 8B2
 S: Canada
 
+N: Maxim Krasnyansky
+E: maxk@qualcomm.com
+W: http://vtun.sf.net
+W: http://bluez.sf.net
+D: Author of the Universal TUN/TAP driver
+D: Author of the Linux Bluetooth Subsystem (BlueZ)
+D: Various other kernel patches, cleanups and fixes
+S: 2213 La Terrace Circle
+S: San Jose, CA 95123
+S: USA
+
 N: Andreas S. Krebs
 E: akrebs@altavista.net
 D: CYPRESS CY82C693 chipset IDE, Digital's PC-Alpha 164SX boards
@@ -2697,9 +2710,7 @@
 N: Marcelo W. Tosatti
 E: marcelo@conectiva.com.br
 W: http://bazar.conectiva.com.br/~marcelo/
-D: Miscellaneous kernel hacker
-D: Cyclom 2X driver, drbd hacker
-D: linuxconf apache & proftpd module maintainer
+D: Miscellaneous kernel hacker (mostly VM/MM work)
 S: Conectiva S.A.
 S: R. Tocantins, 89 - Cristo Rei
 S: 80050-430 - Curitiba - Paraná
diff -u --recursive --new-file v2.4.5/linux/Documentation/Changes linux/Documentation/Changes
--- v2.4.5/linux/Documentation/Changes	Sat May 19 17:43:05 2001
+++ linux/Documentation/Changes	Mon Jun 11 19:15:27 2001
@@ -320,7 +320,7 @@
 
 LVM toolset
 -----------
-o  <http://linux.msede.com/lvm/>
+o  <http://www.sistina.com/lvm/>
 
 Pcmcia-cs
 ---------
diff -u --recursive --new-file v2.4.5/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.4.5/linux/Documentation/Configure.help	Thu May 24 15:03:06 2001
+++ linux/Documentation/Configure.help	Wed Jun 20 11:10:53 2001
@@ -7537,6 +7537,40 @@
   configure your card and that /etc/pcmcia/wireless.opts works :
     http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html
 
+Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards
+CONFIG_AIRO
+  This is the standard Linux driver to support Cisco/Aironet ISA
+  and PCI 802.11 wireless cards.
+  It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X
+  - with or without encryption) as well as card before the Cisco
+  aquisition (Aironet 4500, Aironet 4800, Aironet 4800B).
+
+  This driver support both the standard Linux Wireless Extensions
+  and Cisco proprietary API, so both the Linux Wireless Tools and the
+  Cisco Linux utilities can be used to configure the card.
+
+  The driver can be compiled as a module and will be named "airo.o".
+
+Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards
+CONFIG_AIRO_CS
+  This is the standard Linux driver to support Cisco/Aironet PCMCIA
+  802.11 wireless cards. This driver is the same as the Aironet
+  driver part of the Linux Pcmcia package.
+  It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X
+  - with or without encryption) as well as card before the Cisco
+  aquisition (Aironet 4500, Aironet 4800, Aironet 4800B). It also
+  supports OEM of Cisco such as the DELL TrueMobile 4800 and Xircom
+  802.11b cards.
+
+  This driver support both the standard Linux Wireless Extensions
+  and Cisco proprietary API, so both the Linux Wireless Tools and the
+  Cisco Linux utilities can be used to configure the card.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file Documentation/Changes for
+  location). You also want to check out the PCMCIA-HOWTO, available
+  from http://www.linuxdoc.org/docs.html#howto .
+
 Aviator/Raytheon 2.4MHz wireless support
 CONFIG_PCMCIA_RAYCS
   Say Y here if you intend to attach an Aviator/Raytheon PCMCIA
@@ -10182,91 +10216,150 @@
 Memory Technology Device (MTD) support
 CONFIG_MTD
   Memory Technology Devices are flash, RAM and similar chips, often
-  used for solid state file systems on embedded devices. This option
+  used for solid state filesystems on embedded devices. This option
   will provide the generic support for MTD drivers to register
   themselves with the kernel and for potential users of MTD devices
   to enumerate the devices which are present and obtain a handle on
   them. It will also allow you to select individual drivers for 
-  particular hardware and users of MTD device. If unsure, say N.
+  particular hardware and users of MTD devices. If unsure, say N.
 
 MTD debugging support
 CONFIG_MTD_DEBUG
   This turns on low-level debugging for the entire MTD sub-system.
+  Normally, you should say 'N'.
+
+MTD partitioning support
+CONFIG_MTD_PARTITIONS
+  If you have a device which needs to divide its flash chip(s) up
+  into multiple 'partitions', each of which appears to the user as
+  a separate MTD device, you require this option to be enabled. If
+  unsure, say 'Y'.
+
+  Note, however, that you don't need this option for the DiskOnChip
+  devices. Partitioning on NFTL 'devices' is a different - that's the
+  'normal' form of partitioning used on a block device.
+
+RedBoot partition table parsing
+CONFIG_MTD_REDBOOT_PARTS
+  RedBoot is a ROM monitor and bootloader which deals with multiple
+  'images' in flash devices by putting a table in the last erase
+  block of the device, similar to a partition table, which gives
+  the offsets, lengths and names of all the images stored in the 
+  flash. 
+
+  If you need code which can detect and parse this table, and register
+  MTD 'partitions' corresponding to each image in the table, enable
+  this option. 
+
+  You will still need the parsing functions to be called by the driver
+  for your particular device. It won't happen automatically. The 
+  SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for 
+  example.
+
+Compaq bootldr partition table parsing
+CONFIG_MTD_BOOTLDR_PARTS
+  The Compaq bootldr deals with multiple 'images' in flash devices
+  by putting a table in one of the first erase blocks of the device,
+  similar to a partition table, which gives the offsets, lengths and
+  names of all the images stored in the flash. 
+
+  If you need code which can detect and parse this table, and register
+  MTD 'partitions' corresponding to each image in the table, enable
+  this option. 
+
+  You will still need the parsing functions to be called by the driver
+  for your particular device. It won't happen automatically. The 
+  SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for 
+  example.
+
+ARM Firmware Suite flash layout / partition parsing
+CONFIG_MTD_AFS_PARTS
+  The ARM Firmware Suite allows the user to divide flash devices into
+  multiple 'images'. Each such image has a header containing its name
+  and offset/size etc. 
+
+  If you need code which can detect and parse these tables, and register
+  MTD 'partitions' corresponding to each image detected, enable
+  this option. 
+
+  You will still need the parsing functions to be called by the driver
+  for your particular device. It won't happen automatically. The 
+  'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example.
 
 MTD debugging verbosity
 CONFIG_MTD_DEBUG_VERBOSE
   Determines the verbosity level of the MTD debugging messages.
 
-M-Systems Disk-On-Chip 1000 support
-CONFIG_MTD_DOC1000
-  This provides an MTD device driver for the M-Systems DiskOnChip
-  1000 devices, which are obsolete so you probably want to say 'N'.
 
-M-Systems Disk-On-Chip 2000 and Millennium support
-CONFIG_MTD_DOC2000
-  This provides an MTD device driver for the M-Systems DiskOnChip
-  2000 and Millennium devices. Originally designed for the DiskOnChip
-  2000, it also now includes support for the DiskOnChip Millennium.
-  If you have problems with this driver and the DiskOnChip Millennium,
-  you may wish to try the alternative Millennium driver below. To use
-  the alternative driver, you will need to undefine DOC_SINGLE_DRIVER
-  in the drivers/mtd/docprobe.c source code.
+Direct chardevice access to MTD devices
+CONFIG_MTD_CHAR
+  This provides a character device for each MTD device present in
+  the system, allowing the user to read and write directly to the
+  memory chips, and also use ioctl() to obtain information about
+  the device, or to erase parts of it.
 
-  If you use this device, you probably also want to enable the NFTL
-  'NAND Flash Translation Layer' option below, which is used to emulate
-  a block device by using a kind of filesystem on the flash chips.
+Caching block device access to MTD devices
+CONFIG_MTD_BLOCK
+  Although most flash chips have an erase size too large to be useful
+  as block devices, it is possible to use MTD devices which are based
+  on RAM chips in this manner. This block device is a user of MTD devices
+  performing that function.
+
+  At the moment, it is also required for the Journalling Flash File
+  System(s) to obtain a handle on the MTD device when it's mounted
+  (although JFFS and JFFS2 don't actually use any of the functionality
+  of the mtdblock device).
 
-Alternative Disk-On-Chip Millennium support
-CONFIG_MTD_DOC2001
-  This provides an alternative MTD device driver for the M-Systems
-  DiskOnChip Millennium devices. Use this if you have problems with
-  the combined DiskOnChip 2000 and Millennium driver above. To get
-  the DiskOnChip probe code to load and use this driver instead of
-  the other one, you will need to undefine DOC_SINGLE_DRIVER near
-  the beginning of drivers/mtd/docprobe.c
+  Later, it may be extended to perform read/erase/modify/write cycles
+  on flash chips to emulate a smaller block size. Needless to say,
+  this is very unsafe, but could be useful for filesystems which are
+  almost never written to.
 
-  If you use this device, you probably also want to enable the NFTL
-  'NAND Flash Translation Layer' option below, which is used to emulate
-  a block device by using a kind of filesystem on the flash chips.
+  You do not need this option for use with the DiskOnChip devices. For
+  those, enable NFTL support (CONFIG_NFTL) instead.
 
-Ramix PMC551 PCI Mezzanine ram card support
-CONFIG_MTD_PMC551
-  This provides a MTD device driver for the Ramix PMC551 RAM PCI card
-  from Ramix Inc. (http://www.ramix.com/products/memory/pmc551.html).
-  These devices come in memory configurations from 32M - 1G.  If you
-  have one, you probably want to enable this.
+Readonly block device access to MTD devices
+CONFIG_MTD_BLOCK_RO
+  This allows you to mount read-only filesystems (such as cramfs) from
+  an MTD device, without the overhead (and danger) of the caching 
+  driver. 
 
-  If this driver is compiled as a module you get the ability to select the
-  size of the aperture window pointing into the devices memory.  What this
-  means is that if you have a 1G card, normally the kernel will use a 1G
-  memory map as it's view of the device.  As a module, you can select a
-  1M window into the memory and the driver will "slide" the window around
-  the PMC551's memory.  This was particularly useful on the 2.2 kernels
-  on PPC architectures as there was limited kernel space to deal with.
+  You do not need this option for use with the DiskOnChip devices. For
+  those, enable NFTL support (CONFIG_NFTL) instead.
 
-Use extra onboard system memory as MTD device
-CONFIG_MTD_SLRAM
-  If your CPU cannot cache all of the physical memory in your machine,
-  you can still use it for storage or swap by using this driver to
-  present it to the system as a Memory Technology Device.
+FTL (Flash Translation Layer) support
+CONFIG_FTL
+  This provides support for the original Flash Translation Layer which
+  is part of the PCMCIA specification. It uses a kind of pseudo-
+  filesystem on a flash device to emulate a block device with 512-byte
+  sectors, on top of which you put a 'normal' filesystem.
 
-PMC551 256M DRAM Bugfix
-CONFIG_MTD_PMC551_BUGFIX
-  Some of Ramix's PMC551 boards with 256M configurations have invalid
-  column and row mux values. This option will fix them, but will break
-  other memory configurations.  If unsure say N.
+  You may find that the algorithms used in this code are patented
+  unless you live in the Free World where software patents aren't
+  legal - in the USA you are only permitted to use this on PCMCIA
+  hardware, although under the terms of the GPL you're obviously
+  permitted to copy, modify and distribute the code as you wish. Just
+  not use it.
 
-PMC551 Debugging
-CONFIG_MTD_PMC551_DEBUG
-  This option makes the PMC551 more verbose during it's operation and is
-  only really useful if you are developing on this driver or suspect a
-  possible hardware or driver bug.  If unsure say N.
+NFTL (NAND Flash Translation Layer) support
+CONFIG_NFTL
+  This provides support for the NAND Flash Translation Layer which is
+  used on M-Systems' DiskOnChip devices. It uses a kind of pseudo-
+  filesystem on a flash device to emulate a block device with 512-byte
+  sectors, on top of which you put a 'normal' filesystem.
 
-Debugging RAM test driver
-CONFIG_MTD_MTDRAM
-  This enables a test MTD device driver which uses vmalloc() to
-  provide storage. You probably want to say 'N' unless you're
-  testing stuff.
+  You may find that the algorithms used in this code are patented
+  unless you live in the Free World where software patents aren't
+  legal - in the USA you are only permitted to use this on DiskOnChip
+  hardware, although under the terms of the GPL you're obviously
+  permitted to copy, modify and distribute the code as you wish. Just
+  not use it.
+
+Write support for NFTL (EXPERIMENTAL)
+CONFIG_NFTL_RW
+  If you're lucky, this will actually work. Don't whinge if it doesn't.
+  Send mail to the MTD mailing list <linux-mtd@lists.infradead.org> if
+  you want to help to make it more reliable.
 
 Common Flash Interface (CFI) support
 CONFIG_MTD_CFI
@@ -10277,12 +10370,135 @@
   option. Visit (http://www.amd.com/products/nvd/overview/cfi.html)
   for more information on CFI.
 
-CFI support for Intel/Sharp Extended Command Set chips
+CFI Advanced configuration options
+CONFIG_MTD_CFI_ADV_OPTIONS
+  If you need to specify a specific endianness for access to flash
+  chips, or if you wish to reduce the size of the kernel by including
+  support for only specific arrangements of flash chips, say 'Y'. This
+  option does not directly affect the code, but will enable other 
+  configuration options which allow you to do so.
+
+  If unsure, say 'N'.
+
+Specific CFI Flash geometry selection
+CONFIG_MTD_CFI_GEOMETRY
+  This option does not affect the code directly, but will enable 
+  some other configuration options which would allow you to reduce
+  the size of the kernel by including support for only certain 
+  arrangements of CFI chips. If unsure, say 'N' and all options 
+  which are supported by the current code will be enabled.
+
+Support 8-bit buswidth
+CONFIG_MTD_CFI_B1
+  If you wish to support CFI devices on a physical bus which is
+  8 bits wide, say 'Y'.
+
+Support 16-bit buswidth
+CONFIG_MTD_CFI_B2
+  If you wish to support CFI devices on a physical bus which is
+  16 bits wide, say 'Y'.
+
+Support 32-bit buswidth
+CONFIG_MTD_CFI_B4
+  If you wish to support CFI devices on a physical bus which is
+  32 bits wide, say 'Y'.
+
+Support 1-chip flash interleave
+CONFIG_MTD_CFI_I1
+  If your flash chips are not interleaved - i.e. you only have one
+  flash chip addressed by each bus cycle, then say 'Y'.
+
+Support 2-chip flash interleave
+CONFIG_MTD_CFI_I2
+  If your flash chips are interleaved in pairs - i.e. you have two
+  flash chips addressed by each bus cycle, then say 'Y'.
+
+Support 4-chip flash interleave
+CONFIG_MTD_CFI_I4
+  If your flash chips are interleaved in fours - i.e. you have four
+  flash chips addressed by each bus cycle, then say 'Y'.
+
+Flash cmd/query data swapping
+CONFIG_MTD_CFI_NOSWAP
+  This option defines the way in which the CPU attempts to arrange
+  data bits when writing the 'magic' commands to the chips. Saying
+  'NO', which is the default when CONFIG_MTD_CFI_ADV_OPTIONS isn't
+  enabled, means that the CPU will not do any swapping; the chips
+  are expected to be wired to the CPU in 'host-endian' form. 
+  Specific arrangements are possible with the BIG_ENDIAN_BYTE and
+  LITTLE_ENDIAN_BYTE, if the bytes are reversed. 
+
+  If you have a LART, on which the data (and address) lines were
+  connected in a fashion which ensured that the nets were as short
+  as possible, resulting in a bit-shuffling which seems utterly
+  random to the untrained eye, you need the LART_ENDIAN_BYTE option.
+
+  Yes, there really exists something sicker than PDP-endian :)
+
+CFI support for Intel/Sharp Extended Commands
 CONFIG_MTD_CFI_INTELEXT
   The Common Flash Interface defines a number of different command
   sets which a CFI-compliant chip may claim to implement. This code
   provides support for one of those command sets, used on Intel
-  Strataflash and other parts.
+  StrataFlash and other parts.
+
+CFI support for AMD/Fujitsu Standard Commands
+CONFIG_MTD_CFI_AMDSTD
+  The Common Flash Interface defines a number of different command
+  sets which a CFI-compliant chip may claim to implement. This code
+  provides support for one of those command sets, used on chips 
+  chips including the AMD Am29LV320.
+
+CFI support for Intel/Sharp Standard Commands
+CONFIG_MTD_CFI_INTELSTD
+  The Common Flash Interface defines a number of different command
+  sets which a CFI-compliant chip may claim to implement. This code
+  provides support for one of those command sets.
+
+pre-CFI Sharp chip support
+CONFIG_MTD_SHARP
+  This option enables support for flash chips using Sharp-compatible
+  commands, including some which are not CFI-compatible and hence 
+  cannot be used with the CONFIG_MTD_CFI_INTELxxx options.
+
+AMD compatible flash chip support (non-CFI)
+CONFIG_MTD_AMDSTD
+  This option enables support for flash chips using AMD-compatible
+  commands, including some which are not CFI-compatible and hence 
+  cannot be used with the CONFIG_MTD_CFI_AMDSTD option.
+
+  It also works on AMD compatible chips that do conform to CFI.
+
+Support for RAM chips in bus mapping
+CONFIG_MTD_RAM
+  This option enables basic support for RAM chips accessed through 
+  a bus mapping driver.
+
+Support for ROM chips in bus mapping
+CONFIG_MTD_ROM
+  This option enables basic support for ROM chips accessed through 
+  a bus mapping driver.
+
+CONFIG_MTD_JEDEC
+  Enable older older JEDEC flash interface devices for self programming
+  flash. It is commonly used in older AMD chips. It is only called
+  JEDEC because the JEDEC association (http://www.jedec.org/)
+  distributes the identification codes for the chips. WARNING!!!! This
+  code does not compile and is incomplete as are the specific JEDEC
+  devices drivers.
+
+CFI Flash device mapped on StrongARM SA11x0
+CONFIG_MTD_SA1100
+  This enables access to the flash chips on most platforms based on the
+  SA1100 and SA1110, including the Assabet and the Compaq iPAQ. If you
+  have such a board, say 'Y'.
+
+CONFIG_MTD_SA1100_REDBOOT_PARTITIONS
+  Enabling this option will cause the kernel to look for a RedBoot 
+  FIS (Flash Image System) table in the last erase block of the flash
+  chips detected. If you are using RedBoot on your SA11x0-based board
+  and want Linux to present 'partitions' matching the images which
+  RedBoot has listed, say 'Y'. 
 
 Flash chip mapping in physical memory
 CONFIG_MTD_PHYSMAP
@@ -10295,18 +10511,18 @@
 Physical start location of flash chip mapping
 CONFIG_MTD_PHYSMAP_START
   This is the physical memory location at which the flash chips
-  are mapped on your particular target board. Refer to the 
+  are mapped on your particular target board. Refer to the
   memory map which should hopefully be in the documentation for
   your board.
 
 Physical length of flash chip mapping
 CONFIG_MTD_PHYSMAP_LEN
   This is the total length of the mapping of the flash chips on
-  your particular board. If there is space, or aliases, in the 
+  your particular board. If there is space, or aliases, in the
   physical memory map between the chips, this could be larger
   than the total amount of flash present. Refer to the memory
   map which should hopefully be in the documentation for your
-  board. 
+  board.
 
 CONFIG_MTD_PHYSMAP_BUSWIDTH
   This is the total width of the data bus of the flash devices
@@ -10314,14 +10530,12 @@
   bits, you would set the bus width octect value to 4. This is
   used internally by the CFI drivers.
 
-Flash chip mapping on Mixcom piggyback card
-CONFIG_MTD_MIXMEM
-  This supports the paging arrangement for access to flash chips
-  on the MixCOM piggyback card, allowing the flash chip drivers
-  to get on with their job of driving the flash chips without
-  having to know about the paging. If you have one of these boards,
-  you probably want to enable this mapping driver. More info is at
-  (http://www.itc.hu/).
+Flash chip mapping on Sun Microsystems boardsets
+CONFIG_MTD_SUN_UFLASH
+  This provides a 'mapping' driver which supports the way in 
+  which user-programmable flash chips are connected on various 
+  Sun Microsystems boardsets.  This driver will require CFI support 
+  in the kernel, so if you did not enable CFI previously, do that now.
 
 Flash chip mapping on Nora
 CONFIG_MTD_NORA
@@ -10332,13 +10546,6 @@
   PNC-2000 is the name of Network Camera product from PHOTRON
   Ltd. in Japan. It uses CFI-compliant flash.
 
-Flash chip mapping on Octagon 5066 SBC
-CONFIG_MTD_OCTAGON
-  This provides a 'mapping' driver which supports the way in which
-  the flash chips are connected in the Octagon-5066 Single Board
-  Computer. More information on the board is available at
-  (http://www.octagonsystems.com/Products/5066/5066.html).
-
 Flash chip mapping on RPXlite PPC board
 CONFIG_MTD_RPXLITE
   The RPXLite PowerPC board has CFI-compliant chips mapped in
@@ -10347,6 +10554,89 @@
   to communicate with the chips on the RPXLite board. More at
   (http://www.embeddedplanet.com/rpx_lite_specification_sheet.htm).
 
+Flash chip mapping on AMD SC520 CDP board
+CONFIG_MTD_SC520CDP
+  The SC520 CDP board has two banks of CFI-compliant chips and one
+  Dual-in-line JEDEC chip. This 'mapping' driver supports that
+  arrangement, implementing three MTD devices.
+
+Flash chip mapping on Arcom Control Systems' SBC-MediaGX
+CONFIG_MTD_SBC_MEDIAGX
+  This provides a driver for the on-board flash of Arcom Control
+  Systems' SBC-MediaGX development board. By default the flash
+  is split into 3 partitions which are accessed as separate MTD
+  devices. This board utilizes Intel StrataFlash. More info at
+  (http://www.arcomcontrols.com/products/icp/pc104/processors/).
+
+Flash chip mapping on Arcom Control Systems' ELAN-104NC
+CONFIG_MTD_ELAN_104NC
+  This provides a driver for the on-board flash of the Arcom Control
+  System's ELAN-104NC development board. By default the flash
+  is split into 3 partitions which are accessed as separate MTD
+  devices. This board utilizes Intel StrataFlash. More info at
+  (http://www.arcomcontrols.com/products/icp/pc104/processors/).
+
+Flash chip mapping on Compaq iPAQ/Bitsy
+CONFIG_MTD_BITSY
+  This provides a driver for the on-board flash found in Compaq's
+  iPAQ Palm PC and their research prototype the Itsy. iPAQ info at
+  (http://www5.compaq.com/products/handhelds/pocketpc/) and the
+  Itsy (http://www.research.digital.com/wrl/projects/Itsy/index.html).
+ 
+Flash chip mapping on Compaq iPAQ/Bitsy
+CONFIG_MTD_DC21285
+  This provides a driver for the flash accessed using Intel's
+  21285 bridge used with Intel's StrongARM processors. More info at
+  (http://developer.intel.com/design/bridge/quicklist/dsc-21285.htm).
+
+Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board
+CONFIG_MTD_CSTM_MIPS_IXX
+  This provides a mapping driver for the Integrated Tecnology
+  Express, Inc (ITE) QED-4N-S01B eval board and the Globespan IVR Reference
+  Board. It provides the necessary addressing, length, buswidth, vpp code 
+  and addition setup of the flash device for these boards. In addition,
+  this mapping driver can be used for other boards via setting of the
+  CONFIG_MTD_CSTM_MIPS_IXX_START/LEN/BUSWIDTH parameters.  This mapping
+  will provide one mtd device using one partition.  The start address can
+  be offset from the beginning of flash and the len can be less than the
+  total flash device size to allow a window into the flash.  Both CFI and 
+  JEDEC probes are called.
+
+Physical start location of flash mapping
+CONFIG_MTD_CSTM_MIPS_IXX_START
+  This is the physical memory location that the MTD driver will
+  use for the flash chips on your particular target board. 
+  Refer to the memory map which should hopefully be in the 
+  documentation for your board.
+
+Physical length of flash mapping
+CONFIG_MTD_CSTM_MIPS_IXX_LEN
+  This is the total length that the MTD driver will use for the 
+  flash chips on your particular board.  Refer to the memory
+  map which should hopefully be in the documentation for your
+  board. 
+
+Physical bus width of flash mapping
+CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH
+  This is the total bus width of the mapping of the flash chips
+  on your particular board.
+
+Flash chip mapping on Mixcom piggyback card
+CONFIG_MTD_MIXMEM
+  This supports the paging arrangement for access to flash chips
+  on the MixCOM piggyback card, allowing the flash chip drivers
+  to get on with their job of driving the flash chips without
+  having to know about the paging. If you have one of these boards,
+  you probably want to enable this mapping driver. More info is at
+  (http://www.itc.hu/).
+
+Flash chip mapping on Octagon 5066 SBC
+CONFIG_MTD_OCTAGON
+  This provides a 'mapping' driver which supports the way in which
+  the flash chips are connected in the Octagon-5066 Single Board
+  Computer. More information on the board is available at
+  (http://www.octagonsystems.com/Products/5066/5066.html).
+
 Flash chip mapping on Tempustech VMAX SBC301
 CONFIG_MTD_VMAX
   This provides a 'mapping' driver which supports the way in which
@@ -10354,57 +10644,168 @@
   Board Computer. More information on the board is available at
   (http://www.tempustech.com/tt301.htm).
 
-Direct chardevice access to MTD devices
-CONFIG_MTD_CHAR
-  This provides a character device for each MTD device present in
-  the system, allowing the user to read and write directly to the
-  memory chips, and also use ioctl() to obtain information about
-  the device, or to erase parts of it.
+Support for NAND flash devices
+CONFIG_MTD_NAND
+  This enables support for accessing all type of NAND flash
+  devices. 
+
+Support for software ECC algorithm
+CONFIG_MTD_NAND_ECC
+  This enables software-based ECC for use with NAND flash chips. It
+  can detect and correct 1 bit errors per 256 byte blocks. This
+  should be used to increase the reliability of the data stored and
+  read on the device.
+
+Support for verify read after write
+CONFIG_MTD_NAND_VERIFY_WRITE
+  This adds an extra check when data is written to the flash. The
+  NAND flash device internally checks only bits transitioning
+  from 1 to 0. There is a rare possibility that even though the
+  device thinks the write was successful, a bit could have been
+  flipped accidentaly due to device wear, gamma rays, whatever.
+  Enable this if you are really paranoid.
 
-Pseudo-blockdevice access to MTD devices
-CONFIG_MTD_BLOCK
-  Although flash chips have an erase size too large to useful as
-  block devices, it is possible to use MTD devices which are based
-  on RAM chips in this manner. This blockdevice user of MTD devices
-  performs that function. At the moment, it is also required for 
-  the Journalling Flash File System to obtain a handle on the MTD 
-  device when it's mounted - although the JFFS doesn't actually use
-  any of the functions of the mtdblock device.
+Support for the SPIA board
+CONFIG_MTD_NAND_SPIA
+  If you had to ask, you don't have one. Say 'N'.
 
-  Later, it may be extended to perform read/erase/modify/write cycles
-  on flash chips to emulate a smaller block size. Needless to say,
-  this is very unsafe, but could be useful for file systems which are
-  almost never written to.
+M-Systems Disk-On-Chip 1000 support
+CONFIG_MTD_DOC1000
+  This provides an MTD device driver for the M-Systems DiskOnChip
+  1000 devices, which are obsolete so you probably want to say 'N'.
 
-FTL (Flash Translation Layer) support
-CONFIG_FTL
-  This provides support for the original Flash Translation Layer which
-  is part of the PCMCIA specification. It uses a kind of pseudo-
-  file system on a flash device to emulate a block device with 512-byte
-  sectors, on top of which you put a 'normal' file system. You may find
-  that the algorithms used in this code are patented unless you live
-  in the Free World where software patents aren't legal - in the USA
-  you are only permitted to use this on PCMCIA hardware, although 
-  under the terms of the GPL you're obviously permitted to copy,
-  modify and distribute the code as you wish. Just not use it.
+M-Systems Disk-On-Chip 2000 and Millennium support
+CONFIG_MTD_DOC2000
+  This provides an MTD device driver for the M-Systems DiskOnChip
+  2000 and Millennium devices. Originally designed for the DiskOnChip 
+  2000, it also now includes support for the DiskOnChip Millennium. 
+  If you have problems with this driver and the DiskOnChip Millennium,
+  you may wish to try the alternative Millennium driver below. To use
+  the alternative driver, you will need to undefine DOC_SINGLE_DRIVER
+  in the drivers/mtd/devices/docprobe.c source code.
 
-NFTL (NAND Flash Translation Layer) support
-CONFIG_NFTL
-  This provides support for the NAND Flash Translation Layer which is
-  used on M-Systems' DiskOnChip devices. It uses a kind of pseudo-
-  file system on a flash device to emulate a block device with 512-byte
-  sectors, on top of which you put a 'normal' file system. You may find
-  that the algorithms used in this code are patented unless you live
-  in the Free World where software patents aren't legal - in the USA
-  you are only permitted to use this on DiskOnChip hardware, although 
-  under the terms of the GPL you're obviously permitted to copy,
-  modify and distribute the code as you wish. Just not use it.
+  If you use this device, you probably also want to enable the NFTL
+  'NAND Flash Translation Layer' option below, which is used to emulate
+  a block device by using a kind of filesystem on the flash chips.
 
-Write support for NFTL (EXPERIMENTAL)
-CONFIG_NFTL_RW
-  If you're lucky, this will actually work. Don't whine if it doesn't.
-  Contact (dwmw2@infradead.org) if you want to help to make it more
-  reliable.
+Alternative Disk-On-Chip Millennium support
+CONFIG_MTD_DOC2001
+  This provides an alternative MTD device driver for the M-Systems 
+  DiskOnChip Millennium devices. Use this if you have problems with
+  the combined DiskOnChip 2000 and Millennium driver above. To get
+  the DiskOnChip probe code to load and use this driver instead of
+  the other one, you will need to undefine DOC_SINGLE_DRIVER near
+  the beginning of drivers/mtd/devices/docprobe.c 
+
+  If you use this device, you probably also want to enable the NFTL
+  'NAND Flash Translation Layer' option below, which is used to emulate
+  a block device by using a kind of filesystem on the flash chips.
+
+Probe for DiskOnChip devices
+CONFIG_MTD_DOCPROBE
+  This isn't a real config option, it's derived. 
+
+Advanced detection options for DiskOnChip
+CONFIG_MTD_DOCPROBE_ADVANCED
+  This option allows you to specify nonstandard address at which to
+  probe for a DiskOnChip, or to change the detection options. You're
+  unlikely to need any of this unless you're using LinuxBIOS. Say 'N'.
+
+Probe for 0x55 0xAA BIOS Extension Signature.
+CONFIG_MTD_DOCPROBE_55AA
+  Check for the 0x55 0xAA signature of a DiskOnChip, and do not continue
+  with probing if it is absent. The signature will always be present for
+  a DiskOnChip 2000 or a normal DiskOnChip Millennium. Only if you have
+  overwritten the first block of a DiskOnChip Millennium will it be 
+  absent. Enable this option if you are using LinuxBIOS or if you need
+  to recover a DiskOnChip Millennium on which you have managed to wipe
+  the first block.
+
+Physical address of DiskOnChip
+CONFIG_MTD_DOCPROBE_ADDRESS
+  By default, the probe for DiskOnChip devices will look for a DiskOnChip
+  at every multiple of 0x2000 between 0xC8000 and 0xEE000. This option 
+  allows you to specify a single address at which to probe for the device,
+  which is useful if you have other devices in that range which get upset
+  when they're probed. 
+
+  (Note that on PowerPC, the normal probe will only check at 0xE4000000.)
+
+  Normally, you should leave this set to zero, to allow the probe at the
+  normal addresses.
+
+Probe high addresses
+CONFIG_MTD_DOCPROBE_HIGH
+  By default, the probe for DiskOnChip devices will look for a DiskOnChip
+  at every multiple of 0x2000 between 0xC8000 and 0xEE000. This option 
+  changes to make it probe between 0xFFFC8000 and 0xFFFEE000. Unless
+  you're using LinuxBIOS, this is unlikely to be useful to you. Say 'N'. 
+
+Ramix PMC551 PCI Mezzanine ram card support
+CONFIG_MTD_PMC551
+  This provides a MTD device driver for the Ramix PMC551 RAM PCI card
+  from Ramix Inc. (http://www.ramix.com/products/memory/pmc551.html).
+  These devices come in memory configurations from 32M - 1G.  If you
+  have one, you probably want to enable this.
+
+  If this driver is compiled as a module you get the ability to select the
+  size of the aperture window pointing into the devices memory.  What this 
+  means is that if you have a 1G card, normally the kernel will use a 1G
+  memory map as it's view of the device.  As a module, you can select a
+  1M window into the memory and the driver will "slide" the window around
+  the PMC551's memory.  This was particularly useful on the 2.2 kernels 
+  on PPC architectures as there was limited kernel space to deal with.
+
+PMC551 256M DRAM Bugfix
+CONFIG_MTD_PMC551_BUGFIX
+  Some of Ramix's PMC551 boards with 256M configurations have invalid column
+  and row mux values. This option will fix them, but will break other memory
+  configurations.  If unsure say N.
+
+PMC551 Debugging
+CONFIG_MTD_PMC551_DEBUG
+  This option makes the PMC551 more verbose during it's operation and is only
+  really usefull if you are developing on this driver or suspect a possible
+  hardware or driver bug.  If unsure say N.
+
+Use extra onboard system memory as MTD device
+CONFIG_MTD_SLRAM
+  If your CPU cannot cache all of the physical memory in your machine,
+  you can still use it for storage or swap by using this driver to
+  present it to the system as a Memory Technology Device.
+
+Debugging RAM test driver
+CONFIG_MTD_MTDRAM
+  This enables a test MTD device driver which uses vmalloc() to
+  provide storage. You probably want to say 'N' unless you're
+  testing stuff.
+
+MTDRAM erase block size in KiB
+CONFIG_MTDRAM_ERASE_SIZE
+  This allows you to configure the size of the erase blocks in the
+  device emulated by the MTDRAM driver. If the MTDRAM driver is built
+  as a module, it is also possible to specify this as a parameter when
+  loading the module.
+
+MTDRAM device size in KiB
+CONFIG_MTDRAM_TOTAL_SIZE
+  This allows you to configure the total size of the MTD device
+  emulated by the MTDRAM driver. If the MTDRAM driver is built
+  as a module, it is also possible to specify this as a parameter when
+  loading the module.
+
+SRAM absolute position
+CONFIG_MTDRAM_ABS_POS
+  If you have system RAM accessible by the CPU but not used by Linux
+  in normal operation, you can give the physical address at which the
+  available RAM starts, and the MTDRAM driver will use it instead of
+  allocating space from Linux's available memory. Otherwise, leave 
+  this set to zero. Most people will want to leave this as zero.
+
+Flash chip mapping on the Flaga Digital Module
+CONFIG_MTD_CFI_FLAGADM
+  Mapping for the Flaga digital module. If you don´t have one, ignore this
+  setting.
 
 Support for USB
 CONFIG_USB
@@ -10709,9 +11110,10 @@
 
 USB Handspring Visor Driver
 CONFIG_USB_SERIAL_VISOR
-  Say Y here if you want to connect to your HandSpring Visor through
-  its USB docking station. See http://usbvisor.sourceforge.net for
-  more information on using this driver.
+  Say Y here if you want to connect to your HandSpring Visor, Palm m500
+  or m505 through its USB docking station.
+  See http://usbvisor.sourceforge.net for more information on using this
+  driver.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -11128,12 +11530,13 @@
 
 Microtek USB scanner support
 CONFIG_USB_MICROTEK
-  Say Y here if you want support for the Microtek X6USB and possibly
-  some other scanners by that vendor. The scanner will appear as a
-  scsi generic device to the rest of the system.
-  A patched version of SANE is necessary to use the
-  scanner. It's available at 
-  http://fachschaft.cup.uni-muenchen.de/~neukum/scanner.html
+  Say Y here if you want support for the Microtek X6USB and
+  possibly the Phantom 336CX, Phantom C6 and ScanMaker V6U(S)L.
+  Support for anything but the X6 is experimetal.
+  Please report failures and successes.
+  The scanner will appear as a scsi generic device to the rest
+  of the system. Scsi support is required for this driver to compile
+  and work. SANE 1.0.4 or newer is needed to make use of your scanner.
   This driver can be compiled as a module.
 
 USB Bluetooth support
@@ -13241,8 +13644,8 @@
 Apple Desktop Bus support
 CONFIG_ADB
   Apple Desktop Bus (ADB) support is for support of devices which
-  are connected to the to an ADB port.  ADB devices tend to have
-  4 pins.  If you have an Apple Macintosh prior to the iMac, or a
+  are connected to an ADB port.  ADB devices tend to have 4 pins.
+  If you have an Apple Macintosh prior to the iMac, or a
   "Blue and White G3", you probably want to say Y here.  Otherwise
   say N.
 
@@ -14883,17 +15286,20 @@
 
   If unsure, say Y.
 
-ACI mixer (miroPCM12/PCM20)
+ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20 radio)
 CONFIG_SOUND_ACI_MIXER
   ACI (Audio Command Interface) is a protocol used to communicate with
-  the microcontroller on some sound cards produced by miro, e.g. the
-  miroSOUND PCM12 and PCM20. The main function of the ACI is to
-  control the mixer and to get a product identification. 
-
-  This Voxware ACI driver currently only supports the ACI functions on
-  the miroSOUND PCM12 and PCM20 cards. On the PCM20, ACI also controls
-  the radio tuner. This is supported in the video4linux
-  radio-miropcm20 driver.
+  the microcontroller on some sound cards produced by miro and Cardinal
+  Technologies. The main function of the ACI is to control the mixer
+  and to get a product identification. 
+
+  This Voxware ACI driver currently supports the ACI functions on the
+  miroSOUND PCM1-pro, PCM12 and PCM20 radio. On the PCM20 radio, ACI
+  also controls the radio tuner. This is supported in the video4linux
+  miropcm20 driver (say M or Y here and go back to "Multimedia devices"
+  -> "Radio Adapters").
+
+  This driver is also available as a module and will be called aci.o.
 
 SB32/AWE support
 CONFIG_SOUND_AWE32_SYNTH
@@ -16711,11 +17117,11 @@
   say M here and read Documentation/modules.txt. The module will be
   called i2c-parport.o.
 
-Miro PCM20 Radio
+miroSOUND PCM20 radio
 CONFIG_RADIO_MIROPCM20
-  Choose Y here if you have this FM radio card. You also need to say Y
-  to "ACI mixer (miroPCM12/PCM20)" (in "additional low level sound
-  drivers") for this to work.
+  Choose Y here if you have this sound card. You also need to say Y
+  to "ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20 radio)" (in "Sound")
+  for this to work.
 
   In order to control your radio card, you will need to use programs
   that are compatible with the Video for Linux API. Information on 
@@ -16725,7 +17131,21 @@
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt. The module will be
-  called radio-miropcm20.o
+  called miropcm20.o
+
+miroSOUND PCM20 radio RDS user interface (EXPERIMENTAL)
+CONFIG_RADIO_MIROPCM20_RDS
+  Choose Y here if you want to see RDS/RBDS information like RadioText,
+  Programme Service name, Clock Time and date, Programme TYpe and
+  Traffic Announcement/Programme identification. You also need to say
+  Y to "miroSOUND PCM20 radio" and devfs!
+
+  It's not possible to read the raw RDS packets from the device, so
+  the driver cant provide an V4L interface for this. But the
+  availability of RDS is reported over V4L by the basic driver already.
+  Here RDS can be read from files in /dev/v4l/rds.
+
+  As module the driver will be called miropcm20-rds.o.
 
 GemTek Radio Card
 CONFIG_RADIO_GEMTEK
diff -u --recursive --new-file v2.4.5/linux/Documentation/filesystems/00-INDEX linux/Documentation/filesystems/00-INDEX
--- v2.4.5/linux/Documentation/filesystems/00-INDEX	Thu Feb  8 16:32:44 2001
+++ linux/Documentation/filesystems/00-INDEX	Wed Jun 20 11:10:27 2001
@@ -33,7 +33,7 @@
 smbfs.txt
 	- info on using filesystems with the SMB protocol (Windows 3.11 and NT)
 sysv-fs.txt
-	- info on the SystemV/Coherent filesystem.
+	- info on the SystemV/V7/Xenix/Coherent filesystem.
 udf.txt
 	- info and mount options for the UDF filesystem.
 ufs.txt
diff -u --recursive --new-file v2.4.5/linux/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog
--- v2.4.5/linux/Documentation/filesystems/devfs/ChangeLog	Fri Apr  6 10:42:48 2001
+++ linux/Documentation/filesystems/devfs/ChangeLog	Wed Jun 20 10:54:31 2001
@@ -1613,3 +1613,51 @@
 - Updated README from master HTML file
 
 - Ported to kernel 2.4.0-test3-pre4 (which had devfs-patch-v174)
+===============================================================================
+Changes for patch v177
+
+- Updated README from master HTML file
+
+- Documentation cleanups
+
+- Ensure <devfs_generate_path> terminates string for root entry
+  Thanks to Tim Jansen <tim@tjansen.de>
+
+- Exported <devfs_get_name> to modules
+
+- Make <devfs_mk_symlink> send events to devfsd
+
+- Cleaned up option processing in <devfs_setup>
+
+- Fixed bugs in handling symlinks: could leak or cause Oops
+
+- Cleaned up directory handling by separating fops
+  Thanks to Alexander Viro <viro@math.psu.edu>
+===============================================================================
+Changes for patch v178
+
+- Fixed handling of inverted options in <devfs_setup>
+===============================================================================
+Changes for patch v179
+
+- Adjusted <try_modload> to account for <devfs_generate_path> fix
+===============================================================================
+Changes for patch v180
+
+- Fixed !CONFIG_DEVFS_FS stub declaration of <devfs_get_info>
+===============================================================================
+Changes for patch v181
+
+- Answered question posed by Al Viro and removed his comments from <devfs_open>
+
+- Moved setting of registered flag after other fields are changed
+
+- Fixed race between <devfsd_close> and <devfsd_notify_one>
+
+- Global VFS changes added bogus BKL to devfsd_close(): removed
+
+- Widened locking in <devfs_readlink> and <devfs_follow_link>
+
+- Replaced <devfsd_read> stack usage with <devfsd_ioctl> kmalloc
+
+- Simplified locking in <devfsd_ioctl> and fixed memory leak
diff -u --recursive --new-file v2.4.5/linux/Documentation/filesystems/devfs/README linux/Documentation/filesystems/devfs/README
--- v2.4.5/linux/Documentation/filesystems/devfs/README	Wed Nov 29 10:11:38 2000
+++ linux/Documentation/filesystems/devfs/README	Tue Jun 12 10:57:46 2001
@@ -3,7 +3,7 @@
 
 Linux Devfs (Device File System) FAQ
 Richard Gooch
-3-JUL-2000
+26-APR-2001
 
 -----------------------------------------------------------------------------
 
@@ -18,7 +18,7 @@
 
 http://www.atnf.csiro.au/~rgooch/linux/
 
-NEWFLASH: The official 2.3.46 kernel has
+NEWSFLASH: The official 2.3.46 kernel has
 included the devfs patch. Future patches will be released which
 build on this. These patches are rolled into Linus' tree from time to
 time.
@@ -54,6 +54,7 @@
 Other Issues
 Kernel Naming Scheme
 Devfsd Naming Scheme
+Old Compatibility Names
 SCSI Host Probing Issues
 
 
@@ -99,6 +100,7 @@
 can easily mount the root filesystem by referring to an entry in the
 devfs namespace.
 
+
 The cost of devfs is a small increase in kernel code size and memory
 usage. About 7 pages of code (some of that in __init sections) and 72
 bytes for each entry in the namespace. A modest system has only a
@@ -157,6 +159,7 @@
 of nodes. This means that changes in the kernel must be reflected by
 changes in the MAKEDEV programme, or else the system administrator
 creates device nodes by hand.
+
 The basic problem is that there are two separate databases of
 major and minor numbers. One is in the kernel and one is in /dev (or
 in a MAKEDEV programme, if you want to look at it that way). This is
@@ -192,6 +195,7 @@
 256 kBytes of /dev inodes, but you could argue that embedded systems
 would have hand-tuned /dev directories. I've had to do just that on my
 embedded systems, but I would rather just leave it to devfs.
+
 Another issue is the time taken to lookup an inode when first
 referenced. Not only does this take time in scanning through a list in
 memory, but also the seek times to read the inodes off disc.
@@ -212,7 +216,7 @@
 likely be implemented in an ad-hoc fashion, as different drivers will
 provide their information in different ways.
 
-Devfs is much cleaner, because it (natually) has a uniform mechanism
+Devfs is much cleaner, because it (naturally) has a uniform mechanism
 to provide this information: the device nodes themselves!
 
 
@@ -253,7 +257,7 @@
 But why do that search at all if you don't have to? Once again, it
 seems pointless.
 
-Note thate devfs doesn't use the major&minor system. For devfs
+Note that devfs doesn't use the major&minor system. For devfs
 entries, the connection is done when you lookup the /dev entry. When
 devfs_register() is called, an internal table is appended which has
 the entry name and the file_operations. If the dentry cache doesn't
@@ -274,9 +278,9 @@
 /dev as a system administration tool
 
 Right now /dev contains a list of conceivable devices, most of which I
-don't have. A devfs would only show those devices available on my
-system. This means that listing /dev would be a handy way of checking
-what devices were available.
+don't have. Devfs only shows those devices available on my
+system. This means that listing /dev is a handy way of checking what
+devices are available.
 
 Major&minor size
 
@@ -289,9 +293,9 @@
 each device entry, which can be used to give an effective 32 bit
 device identifier (i.e. that's like having a 32 bit minor
 number). Since this is private to the kernel, there are no C library
-compatibility which you would have with increasing major and minor
-number sizes. See the section on "Allocation of Device Numbers" for
-details on maintaining compatibility with userspace.
+compatibility issues which you would have with increasing major and
+minor number sizes. See the section on "Allocation of Device Numbers"
+for details on maintaining compatibility with userspace.
 
 Solving this requires a kernel change.
 
@@ -375,9 +379,9 @@
 devfsd on any event, such as registration/unregistration of device
 entries, opening and closing devices, looking up inodes, scanning
 directories and more. This has many possibilities. Some of these are
-already implemented.
+already implemented. See:
+
 
-See: 
 http://www.atnf.csiro.au/~rgooch/linux/
 
 Device entry registration events can be used by devfsd to change
@@ -414,6 +418,7 @@
 requests. Instead of using kmod directly, the event is sent to
 devfsd which can implement an arbitrary authentication before loading
 the module itself.
+
 Inode lookup events can also be used to construct arbitrary
 namespaces, without having to resort to populating devfs with symlinks
 to devices that don't exist.
@@ -447,10 +452,10 @@
 
 Who else does it?
 
-FreeBSD has a devfs implementation. Solaris 2 has a pseudo-devfs
-(something akin to scsidev but for all devices, with some unspecified
-kernel support). BeOS, Plan9 and QNX also have it. SGI's IRIX 6.4 and
-above also have a device filesystem.
+FreeBSD has a devfs implementation. Solaris and AIX each have a
+pseudo-devfs (something akin to scsidev but for all devices, with some
+unspecified kernel support). BeOS, Plan9 and QNX also have it. SGI's
+IRIX 6.4 and above also have a device filesystem.
 
 While we shouldn't just automatically do something because others do
 it, we should not ignore the work of others either. FreeBSD has a lot
@@ -613,6 +618,21 @@
 are problems with dealing with symlinks, I'm suspicious of the level
 of security offered in any case.
 
+A better solution is to install util-linux-2.10.h or later, which
+fixes a bug with ttyname handling in the login programme. Then append
+the following lines to your /etc/securetty file:
+
+vc/1
+vc/2
+vc/3
+vc/4
+vc/5
+vc/6
+vc/7
+vc/8
+
+This will not weaken security.
+
 XFree86
 While not essential, it's probably a good idea to upgrade to XFree86
 4.0, as patches went in to make it more devfs-friendly. If you don't,
@@ -627,17 +647,25 @@
 
  # file classes -- these are regular expressions 
 -<console>=tty[0-9][0-9]* :[0-9]\.[0-9] :[0-9] 
-+<console>=tty[0-9][0-9]* [0-9][0-9]* :[0-9]\.[0-9] :[0-9] 
++<console>=tty[0-9][0-9]* vc/[0-9][0-9]* :[0-9]\.[0-9] :[0-9] 
 
  # device classes -- these are shell-style globs 
  <floppy>=/dev/fd[0-1]* 
 
+If the patch does not apply, then change the line:
+
+<console>=tty[0-9][0-9]* :[0-9]\.[0-9] :[0-9]
+
+with:
+
+<console>=tty[0-9][0-9]* vc/[0-9][0-9]* :[0-9]\.[0-9] :[0-9]
+
 
 Disable devpts
 I've had a report of devpts mounted on /dev/pts not working
 correctly. Since devfs will also manage /dev/pts, there is no
 need to mount devpts as well. You should either edit your
-/etc/fstab so devpts is not mounted, or disable devfs from
+/etc/fstab so devpts is not mounted, or disable devpts from
 your kernel configuration.
 
 Unsupported drivers
@@ -664,15 +692,23 @@
 
 The Kernel
 Finally, you need to make sure devfs is compiled into your
-kernel. Set CONFIG_DEVFS_FS=y and recompile your kernel. Next, you
-need to make sure devfs is mounted. The best solution is to pass
-devfs=mount at the kernel boot command line. You can edit
-/etc/lilo.conf and add the line:
-
-append = "devfs=mount"
+kernel. Set CONFIG_DEVFS_FS=y and CONFIG_DEVFS_MOUNT=y and recompile
+your kernel. At boot, devfs will be mounted onto /dev.
 
-
-This will make the kernel mount devfs at boot time onto /dev.
+If you encounter problems booting (for example if you forgot a
+configuration step), you can pass devfs=nomount at the kernel
+boot command line. This will prevent the kernel from mounting devfs at
+boot time onto /dev.
+
+In general, a kernel built with CONFIG_DEVFS_FS=y but without mounting
+devfs onto /dev is completely safe, and requires no
+configuration changes. One exception to take note of is when
+LABEL= directives are used in /etc/fstab. In this
+case you will be unable to boot properly. This is because the
+mount(8) programme uses /proc/partitions as part of
+the volume label search process, and the device names it finds are not
+available, because setting CONFIG_DEVFS_FS=y changes the names in
+/proc/partitions, irrespective of whether devfs is mounted.
 
 Now you've finished all the steps required. You're now ready to boot
 your shiny new kernel. Enjoy.
@@ -701,7 +737,7 @@
 permissions. It may be configured to record changes in permissions and
 will save them in a database (in fact a directory tree), and restore
 these upon boot. This is an efficient method and results in immediate
-saving of current permissions (unlike the tar approach, which save
+saving of current permissions (unlike the tar approach, which saves
 permissions at some unspecified future time).
 
 The default configuration file supplied with devfsd has config entries
@@ -745,8 +781,11 @@
 
 
 
+
 add the following lines to your /etc/devfsd.conf file:
 
+REGISTER	^pt[sy]/.*	IGNORE
+CHANGE		^pt[sy]/.*	IGNORE
 REGISTER	.*		COPY	/dev-state/$devname $devpath
 CHANGE		.*		COPY	$devpath /dev-state/$devname
 CREATE		.*		COPY	$devpath /dev-state/$devname
@@ -758,6 +797,17 @@
 
 
 
+Permissions database stored in normal directory
+
+If you are using an older kernel which doesn't support VFS binding,
+then you won't be able to have the permissions database in a
+mounted-over /dev. However, you can still use a regular
+directory to store the database. The sample /etc/devfsd.conf
+file above may still be used. You will need to create the
+/dev-state directory prior to installing devfsd. If you have
+old permissions in /dev, then just copy the device nodes over
+to the new directory.
+
 
 Dealing with drivers without devfs support
 
@@ -910,13 +960,48 @@
 configuration file is installed, which is used by the MODLOAD
 action. This should be sufficient for most configurations. If you
 require further configuration, edit your /etc/modules.conf
-file.
+file. The way module autoloading work with devfs is:
+
+
+a process attempts to lookup a device node (e.g. /dev/fred)
+
+
+if that device node does not exist, the full pathname is passed to
+devfsd as a string
+
+
+devfsd will pass the string to the modprobe programme (provided the
+configuration line shown above is present), and specifies that
+/etc/modules.devfs is the configuration file
+
+
+/etc/modules.devfs includes /etc/modules.conf to
+access local configurations
+
+modprobe will search it's configuration files, looking for an alias
+that translates the pathname into a module name
+
+
+the translated pathname is then used to load the module.
+
+
+If you wanted a lookup of /dev/fred to load the
+mymod module, you would require the following configuration
+line in /etc/modules.conf:
+
+alias    /dev/fred    mymod
+
+The /etc/modules.devfs configuration file provides many such
+aliases for standard device names. If you look closely at this file,
+you will note that some modules require multiple alias configuration
+lines. This is required to support module autoloading for old and new
+device names.
 
 Mounting root off a devfs device
 If you wish to mount root off a devfs device when you pass the
-"devfs=only" boot option, then you need to pass in the "root="
-option to the kernel when booting. If you use LILO, then you must have
-this in lilo.conf:
+"devfs=only" boot option, then you need to pass in the
+"root=<device>" option to the kernel when booting. If you use
+LILO, then you must have this in lilo.conf:
 
 append = "root=<device>"
 
@@ -926,12 +1011,12 @@
 root = <device>
 
 
-then LILO will determine the device number of  and will write
-that device number into a special place in the kernel image before
-starting the kernel, and the kernel will use that device number to
-mount the root filesystem. So, using the "append" variety ensures that
-LILO passes the root filesystem device as a string, which devfs can
-then use.
+then LILO will determine the device number of <device> and will
+write that device number into a special place in the kernel image
+before starting the kernel, and the kernel will use that device number
+to mount the root filesystem. So, using the "append" variety ensures
+that LILO passes the root filesystem device as a string, which devfs
+can then use.
 
 Note that this isn't an issue if you don't pass "devfs=only".
 
@@ -1067,7 +1152,8 @@
   --------                   --------                   -----------
   /dev/tts/{0,1,...}         /dev/ttyS{0,1,...}         Serial ports
   /dev/cua/{0,1,...}         /dev/cua{0,1,...}          Call out devices
-  /dev/vc/{0,1,...}          /dev/tty{1...63}           Virtual consoles
+  /dev/vc/0                  /dev/tty                   Current virtual console
+  /dev/vc/{1,2,...}          /dev/tty{1...63}           Virtual consoles
   /dev/vcc/{0,1,...}         /dev/vcs{1...63}           Virtual consoles
   /dev/pty/m{0,1,...}        /dev/ptyp??                PTY masters
   /dev/pty/s{0,1,...}        /dev/ttyp??                PTY slaves
@@ -1109,7 +1195,8 @@
 cases, the kernel-supplied naming scheme is quite convenient, so
 devfsd does not provide another naming scheme. The convenience names
 that devfsd creates are in fact the same names as the original devfs
-kernel patch created (before Linus mandated the Big Name Change).
+kernel patch created (before Linus mandated the Big Name
+Change). These are referred to as "new compatibility entries".
 
 In order to configure devfsd to create these convenience names, the
 following lines should be placed in your /etc/devfsd.conf:
@@ -1198,6 +1285,24 @@
 would appear as /dev/xd/c0t0.
 
 
+Old Compatibility Names
+
+The old compatibility names are the legacy device names, such as
+/dev/hda, /dev/sda, /dev/rtc and so on.
+Devfsd can be configured to create compatibility symlinks so that you
+may continue to use the old names in your configuration files and so
+that old applications will continue to function correctly.
+
+In order to configure devfsd to create these legacy names, the
+following lines should be placed in your /etc/devfsd.conf:
+
+REGISTER	.*		MKOLDCOMPAT
+UNREGISTER	.*		RMOLDCOMPAT
+
+This will cause devfsd to create (and destroy) symbolic links which
+point to the kernel-supplied names.
+
+
 SCSI Host Probing Issues
 
 Devfs allows you to identify SCSI discs based in part on SCSI host
@@ -1220,14 +1325,15 @@
 
 means that devices connected to
 
-- first aha1542 controller   - will be c0b#t#u#
-- first parallel port ZIP    - will be c1b#t#u#
-- second aha1542 controller  - will be c2b#t#u#
-- first NCR53C7xx controller - will be c4b#t#u#
-- any extra controller       - will be c5b#t#u#, c6b#t#u#, etc
+- first aha1542 controller   - will be /dev/scsi/host0/bus#/target#/lun#
+- first parallel port ZIP    - will be /dev/scsi/host1/bus#/target#/lun#
+- second aha1542 controller  - will be /dev/scsi/host2/bus#/target#/lun#
+- first NCR53C7xx controller - will be /dev/scsi/host4/bus#/target#/lun#
+- any extra controller       - will be /dev/scsi/host5/bus#/target#/lun#,
+                                       /dev/scsi/host6/bus#/target#/lun#, etc
 - if any of above controllers will not be found - the reserved names will
   not be used by any other device.
-- c3b#t#u# names will never be used
+- /dev/scsi/host3/bus#/target#/lun# names will never be used
 
 
 You can use ',' instead of ':' as the separator character if you
@@ -1343,6 +1449,7 @@
 
 Making things work
 Alternatives to devfs
+What I don't like about devfs
 
 
 
@@ -1518,6 +1625,54 @@
 
 
 
+
+What I don't like about devfs
+
+Here are some common complaints about devfs, and some suggestions and
+solutions that may make it more palatable for you. I can't please
+everybody, but I do try :-)
+
+I hate the naming scheme
+
+First, remember that no naming scheme will please everybody. You hate
+the scheme, others love it. Who's to say who's right and who's wrong?
+Ultimately, the person who writes the code gets to choose, and what
+exists now is a combination of the the choices made by the
+devfs author and the
+kernel maintainer (Linus).
+
+However, not all is lost. If you want to create your own naming
+scheme, it is a simple matter to write a standalone script, hack
+devfsd, or write a script called by devfsd. You can create whatever
+naming scheme you like.
+
+Further, if you want to remove all traces of the devfs naming scheme
+from /dev, you can mount devfs elsewhere (say
+/devfs) and populate /dev with links into
+/devfs. This population can be automated using devfsd if you
+wish.
+
+You can even use the VFS binding facility to make the links, rather
+than using symbolic links. This way, you don't even have to see the
+"destination" of these symbolic links.
+
+Devfs puts policy into the kernel
+
+There's already policy in the kernel. Device numbers are in fact
+policy (why should the kernel dictate what device numbers I use?).
+Face it, some policy has to be in the kernel. The real difference
+between device names as policy and device numbers as policy is that
+no one will use device numbers directly, because device
+numbers are devoid of meaning to humans and are ugly. At least with
+the devfs device names, (even though you can add your own naming
+scheme) some people will use the devfs-supplied names directly. This
+offends some people :-)
+
+Devfs is bloatware
+
+This is not even remotely true. As shown above,
+both code and data size are quite modest.
+
 -----------------------------------------------------------------------------
 
 
@@ -1550,6 +1705,14 @@
 
 http://johannes.erdfelt.com/hotswap.txt.
 Johannes has promised a HTML version will follow.
+
+
+I presented an invited 
+paper
+at the
+
+2nd Annual Storage Management Workshop held in Miamia, Florida,
+U.S.A. in October 2000.
 
 
 
diff -u --recursive --new-file v2.4.5/linux/Documentation/filesystems/hpfs.txt linux/Documentation/filesystems/hpfs.txt
--- v2.4.5/linux/Documentation/filesystems/hpfs.txt	Fri Jul 28 12:50:51 2000
+++ linux/Documentation/filesystems/hpfs.txt	Mon Jun 11 19:15:27 2001
@@ -1,5 +1,5 @@
-Read/Write HPFS 2.00
-1998-1999, Mikulas Patocka
+Read/Write HPFS 2.05
+1998-2001, Mikulas Patocka
 
 email: mikulas@artax.karlin.mff.cuni.cz
 homepage: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
@@ -269,6 +269,20 @@
      Removed a lot of redundant code
 2.00 Fixed a bug in rename (it was there since 1.96)
      Better anti-fragmentation strategy
+2.01 Fixed problem with directory listing over NFS
+     Directory lseek now checks for proper parameters
+     Fixed race-condition in buffer code - it is in all filesystems in Linux;
+        when reading device (cat /dev/hda) while creating files on it, files
+        could be damaged
+2.02 Woraround for bug in breada in Linux. breada could cause accesses beyond
+        end of partition
+2.03 Char, block devices and pipes are correctly created
+     Fixed non-crashing race in unlink (Alexander Viro)
+     Now it works with Japanese version of OS/2
+2.04 Fixed error when ftruncate used to extend file
+2.05 Fixed crash when got mount parameters without =
+     Fixed crash when allocation of anode failed due to full disk
+     Fixed some crashes when block io or inode allocation failed
 
 
  vim: set textwidth=80:
diff -u --recursive --new-file v2.4.5/linux/Documentation/filesystems/udf.txt linux/Documentation/filesystems/udf.txt
--- v2.4.5/linux/Documentation/filesystems/udf.txt	Thu Mar  2 11:17:32 2000
+++ linux/Documentation/filesystems/udf.txt	Mon Jun 11 19:15:27 2001
@@ -1,10 +1,10 @@
 *
 * ./Documentation/filesystems/udf.txt
 *
-UDF Filesystem version 0.9.1
+UDF Filesystem version 0.9.4
 
 If you encounter problems with reading UDF discs using this driver,
-please report them to linux_udf@hootie.lvld.hp.com, which is the
+please report them to linux_udf@hpesjro.fc.hp.com, which is the
 developer's list.
 
 Write support requires a block driver which supports writing. The current
@@ -23,7 +23,8 @@
 	noadinicb	Don't embed data in the inode
 	shortad		Use short ad's
 	longad		Use long ad's (default)
-	strict		Set strict conformance (unused)
+	strict		Set strict conformance
+	iocharset=	Set the NLS character set
 
 The remaining are for debugging and disaster recovery:
 
diff -u --recursive --new-file v2.4.5/linux/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt
--- v2.4.5/linux/Documentation/kernel-parameters.txt	Wed Apr 18 11:49:11 2001
+++ linux/Documentation/kernel-parameters.txt	Wed Jun 20 11:21:33 2001
@@ -455,6 +455,10 @@
 		lastbus=N		[IA-32] Scan all buses till bus #N. Can be useful
 					if the kernel is unable to find your secondary buses
 					and you want to tell it explicitly which ones they are.
+		assign-busses		[IA-32] Always assign all PCI bus
+					numbers ourselves, overriding
+					whatever the firmware may have
+					done.
 
 	pd.		[PARIDE]
 
diff -u --recursive --new-file v2.4.5/linux/Documentation/networking/TODO linux/Documentation/networking/TODO
--- v2.4.5/linux/Documentation/networking/TODO	Thu Apr 19 13:43:40 2001
+++ linux/Documentation/networking/TODO	Wed Jun 20 11:15:44 2001
@@ -14,12 +14,3 @@
 
 * Add ETHTOOL_GDRVINFO ioctl support to all ethernet drivers.
 
-
-
-To-do items to consider for network drivers
--------------------------------------------
-* Make a single function which handles the ethtool ioctl for
-  most MII-compatible devices?  Ideally the driver would pass function
-  pointers to its existing mdio_{read,write} functions when calling the
-  generic ioctl handler.
-
diff -u --recursive --new-file v2.4.5/linux/Documentation/networking/vortex.txt linux/Documentation/networking/vortex.txt
--- v2.4.5/linux/Documentation/networking/vortex.txt	Tue Mar  6 19:13:51 2001
+++ linux/Documentation/networking/vortex.txt	Wed Jun 20 11:15:44 2001
@@ -230,6 +230,23 @@
 other media types does not occur.
 
 
+Transmit error, Tx status register 82
+-------------------------------------
+
+This is a common error which is almost always caused by another host on
+the same network being in full-duplex mode, while this host is in
+half-duplex mode.  You need to find that other host and make it run in
+half-duplex mode or fix this host to run in full-duplex mode.
+
+As a last resort, you can force the 3c59x driver into full-duplex mode
+with
+
+	options 3c59x full_duplex=1
+
+but this has to be viewed as a workaround for broken network gear and
+should only really be used for equipment which cannot autonegotiate.
+
+
 Additional resources
 --------------------
 
diff -u --recursive --new-file v2.4.5/linux/Documentation/sound/README.OSS linux/Documentation/sound/README.OSS
--- v2.4.5/linux/Documentation/sound/README.OSS	Wed Apr 11 19:02:27 2001
+++ linux/Documentation/sound/README.OSS	Tue Jun 12 10:56:11 2001
@@ -17,7 +17,7 @@
 document can be still interesting and very helpful.
 
 [ File edited 17.01.1999 - Riccardo Facchetti ]
-[ Edited miroSOUND section 17.09.2000 - Robert Siemer ]
+[ Edited miroSOUND section 19.04.2001 - Robert Siemer ]
 
 OSS/Free version 3.8 release notes
 ----------------------------------
@@ -1327,7 +1327,7 @@
 ---------
 
 The miroSOUND PCM1-pro, PCM12 and PCM20 radio has been used
-successfully. This card is based on the MAD16, OPL4, and CS4231A chips
+successfully. These cards are based on the MAD16, OPL4, and CS4231A chips
 and everything said in the section about MAD16 cards applies here,
 too. The only major difference between the PCMxx and other MAD16 cards
 is that instead of the mixer in the CS4231 codec a separate mixer
@@ -1337,8 +1337,8 @@
 you compile this ACI driver together with the normal MAD16 support
 when you use a miroSOUND PCMxx card. The ACI mixer is controlled by
 /dev/mixer and the CS4231 mixer by /dev/mixer1 (depends on load
-time). Only in special cases you want to change something on the CS4231
-mixer.
+time). Only in special cases you want to change something regularly on
+the CS4231 mixer.
 
 The miroSOUND PCM12 and PCM20 radio is capable of full duplex
 operation (simultaneous PCM replay and recording), which allows you to
@@ -1354,10 +1354,9 @@
 miropcm20.o module. Also the 7-band equalizer is integrated
 (limited by the OSS-design). Developement has started and maybe
 finished for the RDS decoder on this card, too. You will be able to
-read radio text, the program service name, program type and
+read RadioText, the Programme Service name, Programme TYpe and
 others. Even the v4l radio module benefits from it with a refined
-strength value. See aci.c, radio-miropcm20.c and rds-miropcm20.c for
-more details.
+strength value. See aci.[ch] and miropcm20*.[ch] for more details.
 
 The following configuration parameters have worked fine for the PCM12
 in Markus Kuhn's system, many other configurations might work, too:
diff -u --recursive --new-file v2.4.5/linux/MAINTAINERS linux/MAINTAINERS
--- v2.4.5/linux/MAINTAINERS	Sun May 20 12:11:38 2001
+++ linux/MAINTAINERS	Thu Jun 14 17:30:32 2001
@@ -231,7 +231,7 @@
 CIRRUS LOGIC GENERIC FBDEV DRIVER
 P:	Jeff Garzik
 M:	jgarzik@mandrakesoft.com
-L:	linux-fbdev@vuser.vu.union.edu
+L:	linux-fbdev-devel@lists.sourceforge.net
 S:	Odd Fixes
 
 CIRRUS LOGIC CS4280/CS461x SOUNDDRIVER
@@ -712,16 +712,11 @@
 M:	perex@suse.cz
 S:	Maintained
 
-ISDN SUBSYSTEM (general)
-P:	Fritz Elfert
-M:	fritz@isdn4linux.de
-L:	isdn4linux@listserv.isdn4linux.de
-W:	http://www.isdn4linux.de
-S:	Maintained
-
-ISDN SUBSYSTEM (card drivers)
+ISDN SUBSYSTEM
 P:	Karsten Keil
 M:	kkeil@suse.de
+P:	Kai Germaschewski
+M:	kai.germaschewski@gmx.de
 L:	isdn4linux@listserv.isdn4linux.de
 W:	http://www.isdn4linux.de
 S:	Maintained
@@ -804,9 +799,9 @@
 
 LOGICAL VOLUME MANAGER
 P:     Heinz Mauelshagen
-M:     linux-LVM@EZ-Darmstadt.Telekom.de
-L:     linux-LVM@msede.com
-W:     http://linux.msede.com/lvm
+M:     mge@sistina.de
+L:     linux-LVM@sistina.com
+W:     http://www.sistina.com/lvm
 S:     Maintained 
 
 M68K
@@ -1087,9 +1082,9 @@
 S:	Maintained
 
 RAGE128 FRAMEBUFFER DISPLAY DRIVER
-P:	Brad Douglas
-M:	brad@neruo.com
-L:	linux-fbdev@vuser.vu.union.edu
+P:	Ani Joshi
+M:	ajoshi@shell.unixbox.com
+L:	linux-fbdev-devel@lists.sourceforge.net
 S:	Maintained
 
 RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
@@ -1169,7 +1164,7 @@
 S:	Unmaintained
 
 SCSI TAPE DRIVER
-P:	Kai Mdkisara
+P:	Kai Mäkisara
 M:	Kai.Makisara@metla.fi
 L:	linux-scsi@vger.kernel.org
 S:	Maintained
@@ -1194,12 +1189,6 @@
 L:	samba@samba.org
 S:	Maintained
 
-SMP: (except SPARC)
-P:	Linus Torvalds
-M:	torvalds@transmeta.com
-L:	linux-smp@vger.kernel.org
-S:	Maintained
-
 SOFTWARE RAID (Multiple Disks) SUPPORT
 P:	Ingo Molnar
 M:	mingo@redhat.com
@@ -1347,8 +1336,8 @@
 M:	bfennema@falcon.csc.calpoly.edu
 P:	Dave Boynton
 M:	dave@trylinux.com
-L:	linux_udf@hootie.lvld.hp.com
-W:	http://www.trylinux.com/projects/udf/index.html
+L:	linux_udf@hpesjro.fc.hp.com
+W:	http://linux-udf.sourceforge.net
 S:	Maintained
 
 UMSDOS FILESYSTEM
@@ -1571,6 +1560,12 @@
 M:	middelin@polyware.nl
 W:	http://www.polyware.nl/~middelin/En/hobbies.html
 W:	http://www.polyware.nl/~middelin/hobbies.html
+S:	Maintained
+
+Bluetooth Subsystem (BlueZ)
+P:	Maxim Krasnyansky
+M:	maxk@qualcomm.com
+W:	http://bluez.sf.net
 S:	Maintained
 
 THE REST
diff -u --recursive --new-file v2.4.5/linux/Makefile linux/Makefile
--- v2.4.5/linux/Makefile	Fri May 25 09:51:33 2001
+++ linux/Makefile	Wed Jun 20 11:13:18 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 5
-EXTRAVERSION =
+SUBLEVEL = 6
+EXTRAVERSION =-pre4
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -87,7 +87,8 @@
 
 CPPFLAGS := -D__KERNEL__ -I$(HPATH)
 
-CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing
+CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
+          -fomit-frame-pointer -fno-strict-aliasing
 AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
 
 #
@@ -155,7 +156,8 @@
 DRIVERS-$(CONFIG_PCI) += drivers/pci/driver.o
 DRIVERS-$(CONFIG_MTD) += drivers/mtd/mtdlink.o
 DRIVERS-$(CONFIG_PCMCIA) += drivers/pcmcia/pcmcia.o
-DRIVERS-$(CONFIG_PCMCIA_NETCARD) += drivers/net/pcmcia/pcmcia_net.o
+DRIVERS-$(CONFIG_NET_PCMCIA) += drivers/net/pcmcia/pcmcia_net.o
+DRIVERS-$(CONFIG_NET_WIRELESS) += drivers/net/wireless/wireless_net.o
 DRIVERS-$(CONFIG_PCMCIA_CHRDEV) += drivers/char/pcmcia/pcmcia_char.o
 DRIVERS-$(CONFIG_DIO) += drivers/dio/dio.a
 DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus_all.o
@@ -177,6 +179,7 @@
 DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o
 DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o
 DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o
+DRIVERS-$(CONFIG_BLUEZ) += drivers/bluetooth/bluetooth.o
 
 DRIVERS := $(DRIVERS-y)
 
diff -u --recursive --new-file v2.4.5/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.4.5/linux/arch/alpha/config.in	Fri May 25 09:55:36 2001
+++ linux/arch/alpha/config.in	Mon Jun 11 19:15:27 2001
@@ -348,6 +348,10 @@
 source drivers/usb/Config.in
 source drivers/input/Config.in
 
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   source net/bluetooth/Config.in
+fi
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -u --recursive --new-file v2.4.5/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.4.5/linux/arch/alpha/kernel/alpha_ksyms.c	Fri May 25 09:54:50 2001
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Wed Jun 20 11:10:27 2001
@@ -16,6 +16,7 @@
 #include <linux/pci.h>
 #include <linux/tty.h>
 #include <linux/mm.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/hwrpb.h>
@@ -100,6 +101,10 @@
 EXPORT_SYMBOL(__constant_c_memset);
 EXPORT_SYMBOL(copy_page);
 EXPORT_SYMBOL(clear_page);
+
+EXPORT_SYMBOL(__delay);
+EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(udelay);
 
 EXPORT_SYMBOL(__direct_map_base);
 EXPORT_SYMBOL(__direct_map_size);
diff -u --recursive --new-file v2.4.5/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c
--- v2.4.5/linux/arch/alpha/kernel/core_tsunami.c	Thu May 24 15:24:37 2001
+++ linux/arch/alpha/kernel/core_tsunami.c	Mon Jun 11 19:15:27 2001
@@ -11,7 +11,6 @@
 #include <linux/pci.h>
 #include <linux/sched.h>
 #include <linux/init.h>
-#include <linux/bootmem.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
@@ -21,6 +20,8 @@
 #include <asm/io.h>
 #include <asm/core_tsunami.h>
 #undef __EXTERN_INLINE
+
+#include <linux/bootmem.h>
 
 #include "proto.h"
 #include "pci_impl.h"
diff -u --recursive --new-file v2.4.5/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.4.5/linux/arch/alpha/kernel/entry.S	Thu May 24 15:20:18 2001
+++ linux/arch/alpha/kernel/entry.S	Mon Jun 11 19:15:27 2001
@@ -31,7 +31,7 @@
 #define TASK_STATE		0
 #define TASK_FLAGS		8
 #define TASK_SIGPENDING		16
-#define TASK_ADDR_LIMIT		24	
+#define TASK_ADDR_LIMIT		24
 #define TASK_EXEC_DOMAIN	32
 #define TASK_NEED_RESCHED	40
 #define TASK_PTRACE		48
@@ -576,13 +576,15 @@
 .align 3
 ret_from_sys_call:
 	cmovne	$26,0,$19		/* $19 = 0 => non-restartable */
+#ifdef CONFIG_SMP
 	ldl	$3,TASK_PROCESSOR($8)
-	lda	$4,irq_stat		/* softirq_active */
 	sll	$3,L1_CACHE_SHIFT,$3
+#endif
+	lda	$4,irq_stat
+#ifdef CONFIG_SMP
 	addq	$3,$4,$4
-	ldq	$4,0($4)		/* softirq_active[32] + softirq_mask[32] */
-	sll	$4,32,$3
-	and	$4,$3,$4
+#endif
+	ldq	$4,0($4)		/* __softirq_pending */
 	bne	$4,handle_softirq
 ret_from_softirq:
 	ldq	$0,SP_OFF($30)
diff -u --recursive --new-file v2.4.5/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v2.4.5/linux/arch/alpha/kernel/irq.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/alpha/kernel/irq.c	Wed Jun 20 11:10:27 2001
@@ -359,7 +359,9 @@
 static void
 register_irq_proc (unsigned int irq)
 {
+#ifdef CONFIG_SMP
 	struct proc_dir_entry *entry;
+#endif
 	char name [MAX_NAMELEN];
 
 	if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type))
@@ -389,7 +391,9 @@
 void
 init_irq_proc (void)
 {
+#ifdef CONFIG_SMP
 	struct proc_dir_entry *entry;
+#endif
 	int i;
 
 	/* create /proc/irq */
@@ -512,7 +516,10 @@
 int
 get_irq_list(char *buf)
 {
-	int i, j;
+#ifdef CONFIG_SMP
+	int j;
+#endif
+	int i;
 	struct irqaction * action;
 	char *p = buf;
 
@@ -569,7 +576,7 @@
 
 
 /*
- * do_IRQ handles all normal device IRQ's (the special
+ * handle_irq handles all normal device IRQ's (the special
  * SMP cross-CPU interrupts have their own specific
  * handlers).
  */
@@ -632,7 +639,7 @@
 	/*
 	 * Edge triggered interrupts need to remember pending events.
 	 * This applies to any hw interrupts that allow a second
-	 * instance of the same irq to arrive while we are in do_IRQ
+	 * instance of the same irq to arrive while we are in handle_irq
 	 * or in the handler. But the code here only handles the _second_
 	 * instance of the irq, not the third or fourth. So it is mostly
 	 * useful for irq hardware that does not mask cleanly in an
@@ -656,6 +663,9 @@
 	 */
 	desc->handler->end(irq);
 	spin_unlock(&desc->lock);
+
+	if (softirq_pending(cpu))
+		do_softirq();
 }
 
 /*
diff -u --recursive --new-file v2.4.5/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.4.5/linux/arch/alpha/kernel/osf_sys.c	Mon Mar 19 12:35:09 2001
+++ linux/arch/alpha/kernel/osf_sys.c	Tue Jun 12 10:26:14 2001
@@ -44,7 +44,6 @@
 
 extern int do_pipe(int *);
 
-extern asmlinkage int sys_swapon(const char *specialfile, int swap_flags);
 extern asmlinkage unsigned long sys_brk(unsigned long);
 
 /*
diff -u --recursive --new-file v2.4.5/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.4.5/linux/arch/alpha/kernel/process.c	Thu May 24 15:20:18 2001
+++ linux/arch/alpha/kernel/process.c	Wed Jun 20 11:10:27 2001
@@ -28,6 +28,7 @@
 #include <linux/mman.h>
 #include <linux/elfcore.h>
 #include <linux/reboot.h>
+#include <linux/tty.h>
 #include <linux/console.h>
 
 #include <asm/reg.h>
diff -u --recursive --new-file v2.4.5/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
--- v2.4.5/linux/arch/alpha/kernel/smp.c	Thu May 24 15:24:37 2001
+++ linux/arch/alpha/kernel/smp.c	Mon Jun 11 19:15:27 2001
@@ -682,6 +682,9 @@
 
 		data->prof_counter = data->prof_multiplier;
 		irq_exit(cpu, RTC_IRQ);
+
+		if (softirq_pending(cpu))
+			do_softirq();
 	}
 }
 
diff -u --recursive --new-file v2.4.5/linux/arch/alpha/kernel/sys_dp264.c linux/arch/alpha/kernel/sys_dp264.c
--- v2.4.5/linux/arch/alpha/kernel/sys_dp264.c	Fri May 25 09:54:50 2001
+++ linux/arch/alpha/kernel/sys_dp264.c	Mon Jun 11 19:15:27 2001
@@ -16,18 +16,15 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 
-#define __EXTERN_INLINE inline
-#include <asm/io.h>
-#include <asm/core_tsunami.h>
-#undef  __EXTERN_INLINE
-
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/bitops.h>
 #include <asm/mmu_context.h>
+#include <asm/io.h>
 #include <asm/pgtable.h>
+#include <asm/core_tsunami.h>
 #include <asm/hwrpb.h>
 
 #include "proto.h"
diff -u --recursive --new-file v2.4.5/linux/arch/alpha/kernel/sys_rawhide.c linux/arch/alpha/kernel/sys_rawhide.c
--- v2.4.5/linux/arch/alpha/kernel/sys_rawhide.c	Fri Mar  2 11:12:07 2001
+++ linux/arch/alpha/kernel/sys_rawhide.c	Mon Jun 11 19:15:27 2001
@@ -59,10 +59,11 @@
 	irq -= 16;
 	hose = irq / 24;
 	irq -= hose * 24;
+	mask = 1 << irq;
 
 	spin_lock(&rawhide_irq_lock);
-	mask = cached_irq_masks[hose] |= 1 << irq;
-	mask |= hose_irq_masks[hose];
+	mask |= cached_irq_masks[hose];
+	cached_irq_masks[hose] = mask;
 	rawhide_update_irq_hw(hose, mask);
 	spin_unlock(&rawhide_irq_lock);
 }
@@ -75,14 +76,37 @@
 	irq -= 16;
 	hose = irq / 24;
 	irq -= hose * 24;
+	mask = ~(1 << irq) | hose_irq_masks[hose];
 
 	spin_lock(&rawhide_irq_lock);
-	mask = cached_irq_masks[hose] &= ~(1 << irq);
-	mask |= hose_irq_masks[hose];
+	mask &= cached_irq_masks[hose];
+	cached_irq_masks[hose] = mask;
 	rawhide_update_irq_hw(hose, mask);
 	spin_unlock(&rawhide_irq_lock);
 }
 
+static void
+rawhide_mask_and_ack_irq(unsigned int irq)
+{
+	unsigned int mask, mask1, hose;
+
+	irq -= 16;
+	hose = irq / 24;
+	irq -= hose * 24;
+	mask1 = 1 << irq;
+	mask = ~mask1 | hose_irq_masks[hose];
+
+	spin_lock(&rawhide_irq_lock);
+
+	mask &= cached_irq_masks[hose];
+	cached_irq_masks[hose] = mask;
+	rawhide_update_irq_hw(hose, mask);
+
+	/* Clear the interrupt.  */
+	*(vuip)MCPCIA_INT_REQ(MCPCIA_HOSE2MID(hose)) = mask1;
+
+	spin_unlock(&rawhide_irq_lock);
+}
 
 static unsigned int
 rawhide_startup_irq(unsigned int irq)
@@ -104,7 +128,7 @@
 	shutdown:	rawhide_disable_irq,
 	enable:		rawhide_enable_irq,
 	disable:	rawhide_disable_irq,
-	ack:		rawhide_disable_irq,
+	ack:		rawhide_mask_and_ack_irq,
 	end:		rawhide_end_irq,
 };
 
@@ -145,8 +169,12 @@
 	mcpcia_init_hoses();
 
 	for (hose = hose_head; hose; hose = hose->next) {
-		int h = hose->index;
-		rawhide_update_irq_hw(h, hose_irq_masks[h]);
+		unsigned int h = hose->index;
+		unsigned int mask = hose_irq_masks[h];
+
+		cached_irq_masks[h] = mask;
+		*(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(h)) = mask;
+		*(vuip)MCPCIA_INT_MASK1(MCPCIA_HOSE2MID(h)) = 0;
 	}
 
 	for (i = 16; i < 128; ++i) {
diff -u --recursive --new-file v2.4.5/linux/arch/alpha/kernel/sys_sable.c linux/arch/alpha/kernel/sys_sable.c
--- v2.4.5/linux/arch/alpha/kernel/sys_sable.c	Fri Oct 27 10:55:01 2000
+++ linux/arch/alpha/kernel/sys_sable.c	Tue Jun 12 11:44:59 2001
@@ -96,7 +96,7 @@
 static inline void
 sable_update_irq_hw(unsigned long bit, unsigned long mask)
 {
-	int port = 0x536;
+	int port = 0x537;
 
 	if (bit >= 16) {
 		port = 0x53d;
@@ -121,7 +121,7 @@
 	} else if (bit >= 8) {
 		port = 0x53a;
 		val1 = 0xE0 | (bit - 8);
-		val2 = 0xE0 | 2;
+		val2 = 0xE0 | 3;
 	} else {
 		port = 0x536;
 		val1 = 0xE0 | (bit - 0);
diff -u --recursive --new-file v2.4.5/linux/arch/alpha/kernel/sys_sio.c linux/arch/alpha/kernel/sys_sio.c
--- v2.4.5/linux/arch/alpha/kernel/sys_sio.c	Fri Oct 27 10:55:01 2000
+++ linux/arch/alpha/kernel/sys_sio.c	Wed Jun 20 11:10:27 2001
@@ -17,6 +17,7 @@
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/tty.h>
 
 #include <asm/compiler.h>
 #include <asm/ptrace.h>
diff -u --recursive --new-file v2.4.5/linux/arch/alpha/lib/Makefile linux/arch/alpha/lib/Makefile
--- v2.4.5/linux/arch/alpha/lib/Makefile	Thu Feb  8 12:56:29 2001
+++ linux/arch/alpha/lib/Makefile	Wed Jun 20 11:10:27 2001
@@ -21,6 +21,7 @@
 endif
 
 OBJS =	__divqu.o __remqu.o __divlu.o __remlu.o \
+	udelay.o \
 	$(ev6)memset.o \
 	$(ev6)memcpy.o \
 	memmove.o \
diff -u --recursive --new-file v2.4.5/linux/arch/alpha/lib/udelay.c linux/arch/alpha/lib/udelay.c
--- v2.4.5/linux/arch/alpha/lib/udelay.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/alpha/lib/udelay.c	Wed Jun 20 11:10:27 2001
@@ -0,0 +1,47 @@
+#include <linux/config.h>
+#include <linux/sched.h> /* for udelay's use of smp_processor_id */
+#include <asm/param.h>
+#include <asm/smp.h>
+#include <linux/delay.h>
+
+/*
+ * Copyright (C) 1993, 2000 Linus Torvalds
+ *
+ * Delay routines, using a pre-computed "loops_per_jiffy" value.
+ */
+
+/*
+ * Use only for very small delays (< 1 msec). 
+ *
+ * The active part of our cycle counter is only 32-bits wide, and
+ * we're treating the difference between two marks as signed.  On
+ * a 1GHz box, that's about 2 seconds.
+ */
+
+void __delay(int loops)
+{
+	int tmp;
+	__asm__ __volatile__(
+		"	rpcc %0\n"
+		"	addl %1,%0,%1\n"
+		"1:	rpcc %0\n"
+		"	subl %1,%0,%0\n"
+		"	bgt %0,1b"
+		: "=&r" (tmp), "=r" (loops) : "1"(loops));
+}
+
+void __udelay(unsigned long usecs, unsigned long lpj)
+{
+	usecs *= (((unsigned long)HZ << 32) / 1000000) * lpj;
+	__delay((long)usecs >> 32);
+}
+
+void udelay(unsigned long usecs)
+{
+#ifdef CONFIG_SMP
+	__udelay(usecs, cpu_data[smp_processor_id()].loops_per_jiffy);
+#else
+	__udelay(usecs, loops_per_jiffy);
+#endif
+}
+
diff -u --recursive --new-file v2.4.5/linux/arch/arm/config.in linux/arch/arm/config.in
--- v2.4.5/linux/arch/arm/config.in	Tue Apr 17 17:19:24 2001
+++ linux/arch/arm/config.in	Mon Jun 11 19:15:27 2001
@@ -482,6 +482,9 @@
 
 source drivers/usb/Config.in
 
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   source net/bluetooth/Config.in
+fi
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -u --recursive --new-file v2.4.5/linux/arch/cris/drivers/ide.c linux/arch/cris/drivers/ide.c
--- v2.4.5/linux/arch/cris/drivers/ide.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/drivers/ide.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: ide.c,v 1.9 2001/03/01 13:11:18 bjornw Exp $
+/* $Id: ide.c,v 1.16 2001/04/05 08:30:07 matsfg Exp $
  *
  * Etrax specific IDE functions, like init and PIO-mode setting etc.
  * Almost the entire ide.c is used for the rest of the Etrax ATA driver.
@@ -8,6 +8,28 @@
  *             Mikael Starvik     (pio setup stuff)
  *
  * $Log: ide.c,v $
+ * Revision 1.16  2001/04/05 08:30:07  matsfg
+ * Corrected cse1 and csp0 reset.
+ *
+ * Revision 1.15  2001/04/04 14:34:06  bjornw
+ * Re-instated code that mysteriously disappeared during review updates.
+ *
+ * Revision 1.14  2001/04/04 13:45:12  matsfg
+ * Calls REG_SHADOW_SET for cse1 reset so only the resetbit is affected
+ *
+ * Revision 1.13  2001/04/04 13:26:40  matsfg
+ * memmapping is done in init.c
+ *
+ * Revision 1.12  2001/04/04 11:37:56  markusl
+ * Updated according to review remarks
+ *
+ * Revision 1.11  2001/03/29 12:49:14  matsfg
+ * Changed check for ata_tot_size from >= to >.
+ * Sets sw_len to 0 if size is exactly 65536.
+ *
+ * Revision 1.10  2001/03/16 09:39:30  matsfg
+ * Support for reset on port CSP0
+ *
  * Revision 1.9  2001/03/01 13:11:18  bjornw
  * 100 -> HZ
  *
@@ -158,6 +180,10 @@
 #define ATA_PIO0_STROBE 19
 #define ATA_PIO0_HOLD    4
 
+static int e100_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
+static void e100_ideproc (ide_ide_action_t func, ide_drive_t *drive,
+			  void *buffer, unsigned int length);
+
 /*
  * good_dma_drives() lists the model names (from "hdparm -i")
  * of drives which do not support mword2 DMA but which are
@@ -174,7 +200,7 @@
 	unsigned long flags;
 	
 	pio = 4;
-	//pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	/* pio = ide_get_best_pio_mode(drive, pio, 4, NULL); */
 	
 	save_flags(flags);
 	cli();
@@ -226,10 +252,6 @@
 	restore_flags(flags);
 }
 
-static int e100_dmaproc (ide_dma_action_t func, ide_drive_t *drive); /* defined below */
-static void e100_ideproc (ide_ide_action_t func, ide_drive_t *drive,
-			  void *buffer, unsigned int length);        /* defined below */
-
 void __init 
 init_e100_ide (void)
 {
@@ -277,26 +299,23 @@
 	*R_GEN_CONFIG = genconfig_shadow;
 
 #ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
-#ifndef CONFIG_CRIS_LOW_MAP
-	/* remap the I/O-mapped reset-bit from CSE1 to something inside our kernel space */
-	reset_addr = (unsigned long *)ioremap((unsigned long)(MEM_CSE1_START |
-							      MEM_NON_CACHEABLE), 16);
-	*reset_addr = 0;
-#else
-	/* LOW_MAP, can't do the ioremap, but it's already mapped straight over */
-	reset_addr = (unsigned long *)(MEM_CSE1_START | MEM_NON_CACHEABLE);
-	*reset_addr = 0;
+        init_ioremap();
+        REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 0);
 #endif
+
+#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
+        init_ioremap();
+        REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 0);
 #endif
 
 	/* wait some */
-
-	dummy = 1;
-	dummy = 2;
-	dummy = 3;
+	udelay(25);
 
 #ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
-	*reset_addr = 1 << 16;
+	REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 1);
+#endif
+#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
+	REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 1);
 #endif
 #ifdef CONFIG_ETRAX_IDE_G27_RESET
 	*R_PORT_G_DATA = 0; /* de-assert bus-reset */
@@ -349,7 +368,6 @@
 e100_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
 {
 	ide_ioreg_t data_reg = IDE_DATA_REG;
-	unsigned long status;
 
 	D(printk("atapi_input_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
 		 data_reg, buffer, bytecount));
@@ -376,7 +394,7 @@
 	
 	/* initiate a multi word dma read using PIO handshaking */
 	
-	*R_ATA_TRANSFER_CNT = bytecount >> 1;
+	*R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1);
 	
 	*R_ATA_CTRL_DATA = data_reg |
 		IO_STATE(R_ATA_CTRL_DATA, rw,       read) |
@@ -390,35 +408,38 @@
 	LED_DISK_READ(1);
 	WAIT_DMA(3);
 	LED_DISK_READ(0);
-	
+
 #if 0
-	/* old polled transfer code */
-	
-	/* initiate a multi word read */
-	
-	*R_ATA_TRANSFER_CNT = wcount << 1;
-	
-	*R_ATA_CTRL_DATA = data_reg |
-		IO_STATE(R_ATA_CTRL_DATA, rw,       read) |
-		IO_STATE(R_ATA_CTRL_DATA, src_dst,  register) |
-		IO_STATE(R_ATA_CTRL_DATA, handsh,   pio) |
-		IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
-		IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
-	
-	/* svinto has a latency until the busy bit actually is set */
-	
-	nop(); nop();
-	nop(); nop();
-	nop(); nop();
-	nop(); nop();
-	nop(); nop();
-	
-	/* unit should be busy during multi transfer */
-	while((status = *R_ATA_STATUS_DATA) & IO_MASK(R_ATA_STATUS_DATA, busy)) {
-		while(!(status & IO_MASK(R_ATA_STATUS_DATA, dav)))
-			status = *R_ATA_STATUS_DATA;
-		*ptr++ = (unsigned short)(status & 0xffff);
-	}
+        /* old polled transfer code
+	 * this should be moved into a new function that can do polled
+	 * transfers if DMA is not available
+	 */
+        
+        /* initiate a multi word read */
+        
+        *R_ATA_TRANSFER_CNT = wcount << 1;
+        
+        *R_ATA_CTRL_DATA = data_reg |
+                IO_STATE(R_ATA_CTRL_DATA, rw,       read) |
+                IO_STATE(R_ATA_CTRL_DATA, src_dst,  register) |
+                IO_STATE(R_ATA_CTRL_DATA, handsh,   pio) |
+                IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
+                IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+        
+        /* svinto has a latency until the busy bit actually is set */
+        
+        nop(); nop();
+        nop(); nop();
+        nop(); nop();
+        nop(); nop();
+        nop(); nop();
+        
+        /* unit should be busy during multi transfer */
+        while((status = *R_ATA_STATUS_DATA) & IO_MASK(R_ATA_STATUS_DATA, busy)) {
+                while(!(status & IO_MASK(R_ATA_STATUS_DATA, dav)))
+                        status = *R_ATA_STATUS_DATA;
+                *ptr++ = (unsigned short)(status & 0xffff);
+        }
 #endif
 }
 
@@ -426,8 +447,6 @@
 e100_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
 {
 	ide_ioreg_t data_reg = IDE_DATA_REG;
-	unsigned short *ptr = (unsigned short *)buffer;
-	unsigned long ctrl;
 	
 	D(printk("atapi_output_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
 		 data_reg, buffer, bytecount));
@@ -454,7 +473,7 @@
 	
 	/* initiate a multi word dma write using PIO handshaking */
 	
-	*R_ATA_TRANSFER_CNT = bytecount >> 1;
+	*R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1);
 	
 	*R_ATA_CTRL_DATA = data_reg |
 		IO_STATE(R_ATA_CTRL_DATA, rw,       write) |
@@ -470,40 +489,42 @@
 	LED_DISK_WRITE(0);
 
 #if 0
-	/* old polled write code */
+        /* old polled write code - see comment in input_bytes */
 
-	while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag */
+	/* wait for busy flag */
+        while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); 
 
-	/* initiate a multi word write */
+        /* initiate a multi word write */
 
-	*R_ATA_TRANSFER_CNT = bytecount >> 1;
+        *R_ATA_TRANSFER_CNT = bytecount >> 1;
 
-	ctrl = data_reg |
-		IO_STATE(R_ATA_CTRL_DATA, rw,       write) |
-		IO_STATE(R_ATA_CTRL_DATA, src_dst,  register) |
-		IO_STATE(R_ATA_CTRL_DATA, handsh,   pio) |
-		IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
-		IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
-	
-	LED_DISK_WRITE(1);
-	
-	/* Etrax will set busy = 1 until the multi pio transfer has finished
-	 * and tr_rdy = 1 after each succesful word transfer. 
-	 * When the last byte has been transferred Etrax will first set tr_tdy = 1 
-	 * and then busy = 0 (not in the same cycle). If we read busy before it
-	 * has been set to 0 we will think that we should transfer more bytes 
-	 * and then tr_rdy would be 0 forever. This is solved by checking busy
-	 * in the inner loop.
-	 */
-	
-	do {
-		*R_ATA_CTRL_DATA = ctrl | *ptr++;
-		while(!(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy)) &&
-		      (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)));
-	} while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy));
+        ctrl = data_reg |
+                IO_STATE(R_ATA_CTRL_DATA, rw,       write) |
+                IO_STATE(R_ATA_CTRL_DATA, src_dst,  register) |
+                IO_STATE(R_ATA_CTRL_DATA, handsh,   pio) |
+                IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
+                IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+        
+        LED_DISK_WRITE(1);
+        
+        /* Etrax will set busy = 1 until the multi pio transfer has finished
+         * and tr_rdy = 1 after each succesful word transfer. 
+         * When the last byte has been transferred Etrax will first set tr_tdy = 1 
+         * and then busy = 0 (not in the same cycle). If we read busy before it
+         * has been set to 0 we will think that we should transfer more bytes 
+         * and then tr_rdy would be 0 forever. This is solved by checking busy
+         * in the inner loop.
+         */
+        
+        do {
+                *R_ATA_CTRL_DATA = ctrl | *ptr++;
+                while(!(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy)) &&
+                      (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)));
+        } while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy));
+
+        LED_DISK_WRITE(0);
+#endif  
 
-	LED_DISK_WRITE(0);
-#endif	
 }
 
 /*
@@ -604,7 +625,7 @@
 		      those blocks that were actually set-up for transfer.
 		*/
 
-		if(ata_tot_size + size >= 131072) {
+		if(ata_tot_size + size > 131072) {
 			printk("too large total ATA DMA request, %d + %d!\n", ata_tot_size, size);
 			return 1;
 		}
@@ -625,7 +646,12 @@
                         addr += 65536;
                 }
 		/* ok we want to do IO at addr, size bytes. set up a new descriptor entry */
-		ata_descrs[count].sw_len = size;
+                if(size == 65536) {
+                  ata_descrs[count].sw_len = 0;  /* 0 means 65536, this is a 16-bit field */
+                }
+                else {
+                  ata_descrs[count].sw_len = size;
+                }
 		ata_descrs[count].ctrl = 0;
 		ata_descrs[count].buf = addr;
 		ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]);
@@ -793,9 +819,11 @@
 		
 		/* initiate a multi word dma read using DMA handshaking */
 		
-		*R_ATA_TRANSFER_CNT = ata_tot_size >> 1;
+		*R_ATA_TRANSFER_CNT =
+			IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1);
 		
-		*R_ATA_CTRL_DATA = IDE_DATA_REG  |
+		*R_ATA_CTRL_DATA =
+			IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) |
 			IO_STATE(R_ATA_CTRL_DATA, rw,       read) |
 			IO_STATE(R_ATA_CTRL_DATA, src_dst,  dma)  |
 			IO_STATE(R_ATA_CTRL_DATA, handsh,   dma)  |
@@ -834,9 +862,11 @@
 		
 		/* initiate a multi word dma write using DMA handshaking */
 		
-		*R_ATA_TRANSFER_CNT = ata_tot_size >> 1;
+		*R_ATA_TRANSFER_CNT =
+			IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1);
 		
-		*R_ATA_CTRL_DATA = IDE_DATA_REG |
+		*R_ATA_CTRL_DATA =
+			IO_FIELD(R_ATA_CTRL_DATA, data,     IDE_DATA_REG) |
 			IO_STATE(R_ATA_CTRL_DATA, rw,       write) |
 			IO_STATE(R_ATA_CTRL_DATA, src_dst,  dma) |
 			IO_STATE(R_ATA_CTRL_DATA, handsh,   dma) |
diff -u --recursive --new-file v2.4.5/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.4.5/linux/arch/i386/config.in	Thu May 24 15:14:08 2001
+++ linux/arch/i386/config.in	Mon Jun 11 19:15:27 2001
@@ -375,6 +375,10 @@
 
 source drivers/usb/Config.in
 
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   source net/bluetooth/Config.in
+fi
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -u --recursive --new-file v2.4.5/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.4.5/linux/arch/i386/defconfig	Tue May 22 10:53:06 2001
+++ linux/arch/i386/defconfig	Wed Jun 20 11:30:44 2001
@@ -103,6 +103,64 @@
 # CONFIG_MTD is not set
 
 #
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_SUN_UFLASH is not set
+# CONFIG_MTD_NORA is not set
+# CONFIG_MTD_PNC2000 is not set
+# CONFIG_MTD_RPXLITE is not set
+# CONFIG_MTD_SC520CDP is not set
+# CONFIG_MTD_NETSC520 is not set
+# CONFIG_MTD_SBC_GXX is not set
+# CONFIG_MTD_ELAN_104NC is not set
+# CONFIG_MTD_SA1100 is not set
+# CONFIG_MTD_SA1100_REDBOOT_PARTITIONS is not set
+# CONFIG_MTD_SA1100_BOOTLDR_PARTITIONS is not set
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_DBOX2 is not set
+# CONFIG_MTD_CSTM_MIPS_IXX is not set
+# CONFIG_MTD_CFI_FLAGADM is not set
+# CONFIG_MTD_MIXMEM is not set
+# CONFIG_MTD_OCTAGON is not set
+# CONFIG_MTD_VMAX is not set
+# CONFIG_MTD_OCELOT 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
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_NAND_SPIA is not set
+
+#
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
@@ -192,7 +250,7 @@
 # CONFIG_BLK_DEV_HD_IDE is not set
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_IDEDISK_MULTI_MODE=y
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -217,10 +275,10 @@
 CONFIG_BLK_DEV_RZ1000=y
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
-# CONFIG_BLK_DEV_IDEDMA_PCI is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
@@ -235,8 +293,8 @@
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_PIIX_TUNING is not set
+CONFIG_BLK_DEV_PIIX=y
+CONFIG_PIIX_TUNING=y
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
@@ -247,7 +305,8 @@
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
 # CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
 CONFIG_BLK_DEV_IDE_MODES=y
 
@@ -445,7 +504,6 @@
 # CONFIG_PCMCIA_NETWAVE is not set
 # CONFIG_PCMCIA_WAVELAN is not set
 # CONFIG_AIRONET4500_CS is not set
-CONFIG_PCMCIA_NETCARD=y
 
 #
 # Amateur Radio support
diff -u --recursive --new-file v2.4.5/linux/arch/i386/kernel/apic.c linux/arch/i386/kernel/apic.c
--- v2.4.5/linux/arch/i386/kernel/apic.c	Tue Dec  5 12:43:48 2000
+++ linux/arch/i386/kernel/apic.c	Wed Jun 20 11:06:38 2001
@@ -23,6 +23,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/kernel_stat.h>
 
+#include <asm/atomic.h>
 #include <asm/smp.h>
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
@@ -270,7 +271,13 @@
 	 *   PCI Ne2000 networking cards and PII/PIII processors, dual
 	 *   BX chipset. ]
 	 */
-#if 0
+	/*
+	 * Actually disabling the focus CPU check just makes the hang less
+	 * frequent as it makes the interrupt distributon model be more
+	 * like LRU than MRU (the short-term load is more even across CPUs).
+	 * See also the comment in end_level_ioapic_irq().  --macro
+	 */
+#if 1
 	/* Enable focus processor (bit==0) */
 	value &= ~(1<<9);
 #else
@@ -728,6 +735,9 @@
 	irq_enter(cpu, 0);
 	smp_local_timer_interrupt(regs);
 	irq_exit(cpu, 0);
+
+	if (softirq_pending(cpu))
+		do_softirq();
 }
 
 /*
@@ -764,7 +774,7 @@
 	apic_write(APIC_ESR, 0);
 	v1 = apic_read(APIC_ESR);
 	ack_APIC_irq();
-	irq_err_count++;
+	atomic_inc(&irq_err_count);
 
 	/* Here is what the APIC error bits mean:
 	   0: Send CS error
diff -u --recursive --new-file v2.4.5/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.4.5/linux/arch/i386/kernel/entry.S	Wed Nov  8 17:09:50 2000
+++ linux/arch/i386/kernel/entry.S	Tue Jun 12 11:47:28 2001
@@ -203,18 +203,7 @@
 	call *SYMBOL_NAME(sys_call_table)(,%eax,4)
 	movl %eax,EAX(%esp)		# save the return value
 ENTRY(ret_from_sys_call)
-#ifdef CONFIG_SMP
-	movl processor(%ebx),%eax
-	shll $CONFIG_X86_L1_CACHE_SHIFT,%eax
-	movl SYMBOL_NAME(irq_stat)(,%eax),%ecx		# softirq_active
-	testl SYMBOL_NAME(irq_stat)+4(,%eax),%ecx	# softirq_mask
-#else
-	movl SYMBOL_NAME(irq_stat),%ecx		# softirq_active
-	testl SYMBOL_NAME(irq_stat)+4,%ecx	# softirq_mask
-#endif
-	jne   handle_softirq
-	
-ret_with_reschedule:
+	cli				# need_resched and signals atomic test
 	cmpl $0,need_resched(%ebx)
 	jne reschedule
 	cmpl $0,sigpending(%ebx)
@@ -257,33 +246,16 @@
 	jmp ret_from_sys_call
 
 	ALIGN
-ret_from_exception:
-#ifdef CONFIG_SMP
-	GET_CURRENT(%ebx)
-	movl processor(%ebx),%eax
-	shll $CONFIG_X86_L1_CACHE_SHIFT,%eax
-	movl SYMBOL_NAME(irq_stat)(,%eax),%ecx		# softirq_active
-	testl SYMBOL_NAME(irq_stat)+4(,%eax),%ecx	# softirq_mask
-#else
-	movl SYMBOL_NAME(irq_stat),%ecx		# softirq_active
-	testl SYMBOL_NAME(irq_stat)+4,%ecx	# softirq_mask
-#endif
-	jne   handle_softirq
-
 ENTRY(ret_from_intr)
 	GET_CURRENT(%ebx)
+ret_from_exception:
 	movl EFLAGS(%esp),%eax		# mix EFLAGS and CS
 	movb CS(%esp),%al
 	testl $(VM_MASK | 3),%eax	# return to VM86 mode or non-supervisor?
-	jne ret_with_reschedule
+	jne ret_from_sys_call
 	jmp restore_all
 
 	ALIGN
-handle_softirq:
-	call SYMBOL_NAME(do_softirq)
-	jmp ret_from_intr
-	
-	ALIGN
 reschedule:
 	call SYMBOL_NAME(schedule)    # test
 	jmp ret_from_sys_call
@@ -334,14 +306,16 @@
 	pushl $-1		# mark this as an int
 	SAVE_ALL
 	GET_CURRENT(%ebx)
-	pushl $ret_from_exception
 	movl %cr0,%eax
 	testl $0x4,%eax			# EM (math emulation bit)
-	je SYMBOL_NAME(math_state_restore)
+	jne device_not_available_emulate
+	call SYMBOL_NAME(math_state_restore)
+	jmp ret_from_exception
+device_not_available_emulate:
 	pushl $0		# temporary storage for ORIG_EIP
 	call  SYMBOL_NAME(math_emulate)
 	addl $4,%esp
-	ret
+	jmp ret_from_exception
 
 ENTRY(debug)
 	pushl $0
diff -u --recursive --new-file v2.4.5/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v2.4.5/linux/arch/i386/kernel/head.S	Fri Apr 20 16:23:30 2001
+++ linux/arch/i386/kernel/head.S	Wed Jun 20 11:00:53 2001
@@ -41,8 +41,6 @@
  *
  * On entry, %esi points to the real-mode code as a 32-bit pointer.
  */
-ENTRY(stext)
-ENTRY(_stext)
 startup_32:
 /*
  * Set segments to known values
@@ -409,6 +407,12 @@
 ENTRY(empty_zero_page)
 
 .org 0x5000
+
+/*
+ * Real beginning of normal "text" segment
+ */
+ENTRY(stext)
+ENTRY(_stext)
 
 /*
  * This starts the data section. Note that the above is all
diff -u --recursive --new-file v2.4.5/linux/arch/i386/kernel/i8259.c linux/arch/i386/kernel/i8259.c
--- v2.4.5/linux/arch/i386/kernel/i8259.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/i386/kernel/i8259.c	Wed Jun 20 11:06:38 2001
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/kernel_stat.h>
 
+#include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -321,7 +322,7 @@
 			printk("spurious 8259A interrupt: IRQ%d.\n", irq);
 			spurious_irq_mask |= irqmask;
 		}
-		irq_err_count++;
+		atomic_inc(&irq_err_count);
 		/*
 		 * Theoretically we do not have to handle this IRQ,
 		 * but in Linux this does not cause problems and is
diff -u --recursive --new-file v2.4.5/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
--- v2.4.5/linux/arch/i386/kernel/io_apic.c	Fri Feb  9 11:28:31 2001
+++ linux/arch/i386/kernel/io_apic.c	Wed Jun 20 11:06:38 2001
@@ -33,6 +33,8 @@
 #include <asm/smp.h>
 #include <asm/desc.h>
 
+#define APIC_LOCKUP_DEBUG
+
 static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED;
 
 /*
@@ -122,8 +124,14 @@
 	static void name##_IO_APIC_irq (unsigned int irq)		\
 	__DO_ACTION(R, ACTION, FINAL)
 
-DO_ACTION( __mask,    0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */
-DO_ACTION( __unmask,  0, &= 0xfffeffff, )				/* mask = 0 */
+DO_ACTION( __mask,             0, |= 0x00010000, io_apic_sync(entry->apic) )
+						/* mask = 1 */
+DO_ACTION( __unmask,           0, &= 0xfffeffff, )
+						/* mask = 0 */
+DO_ACTION( __mask_and_edge,    0, = (reg & 0xffff7fff) | 0x00010000, )
+						/* mask = 1, trigger = 0 */
+DO_ACTION( __unmask_and_level, 0, = (reg & 0xfffeffff) | 0x00008000, )
+						/* mask = 0, trigger = 1 */
 
 static void mask_IO_APIC_irq (unsigned int irq)
 {
@@ -255,10 +263,16 @@
  */
 static int pin_2_irq(int idx, int apic, int pin);
 
-int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pci_pin)
+int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
 {
 	int apic, i, best_guess = -1;
 
+	Dprintk("querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
+		bus, slot, pin);
+	if (mp_bus_id_to_pci_bus[bus] == -1) {
+		printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
+		return -1;
+	}
 	for (i = 0; i < mp_irq_entries; i++) {
 		int lbus = mp_irqs[i].mpc_srcbus;
 
@@ -269,14 +283,14 @@
 
 		if ((mp_bus_id_to_type[lbus] == MP_BUS_PCI) &&
 		    !mp_irqs[i].mpc_irqtype &&
-		    (bus == mp_bus_id_to_pci_bus[mp_irqs[i].mpc_srcbus]) &&
+		    (bus == lbus) &&
 		    (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) {
 			int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq);
 
 			if (!(apic || IO_APIC_IRQ(irq)))
 				continue;
 
-			if (pci_pin == (mp_irqs[i].mpc_srcbusirq & 3))
+			if (pin == (mp_irqs[i].mpc_srcbusirq & 3))
 				return irq;
 			/*
 			 * Use the first all-but-pin matching entry as a
@@ -728,9 +742,11 @@
 	printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)&reg_01);
 	printk(KERN_DEBUG ".......     : max redirection entries: %04X\n", reg_01.entries);
 	if (	(reg_01.entries != 0x0f) && /* older (Neptune) boards */
+		(reg_01.entries != 0x11) &&
 		(reg_01.entries != 0x17) && /* typical ISA+PCI boards */
 		(reg_01.entries != 0x1b) && /* Compaq Proliant boards */
 		(reg_01.entries != 0x1f) && /* dual Xeon boards */
+		(reg_01.entries != 0x20) &&
 		(reg_01.entries != 0x22) && /* bigger Xeon boards */
 		(reg_01.entries != 0x2E) &&
 		(reg_01.entries != 0x3F)
@@ -847,6 +863,8 @@
 
 	v = apic_read(APIC_EOI);
 	printk(KERN_DEBUG "... APIC EOI: %08x\n", v);
+	v = apic_read(APIC_RRR);
+	printk(KERN_DEBUG "... APIC RRR: %08x\n", v);
 	v = apic_read(APIC_LDR);
 	printk(KERN_DEBUG "... APIC LDR: %08x\n", v);
 	v = apic_read(APIC_DFR);
@@ -1191,12 +1209,61 @@
 #define enable_level_ioapic_irq		unmask_IO_APIC_irq
 #define disable_level_ioapic_irq	mask_IO_APIC_irq
 
-static void end_level_ioapic_irq (unsigned int i)
+static void end_level_ioapic_irq (unsigned int irq)
 {
+	unsigned long v;
+
+/*
+ * It appears there is an erratum which affects at least version 0x11
+ * of I/O APIC (that's the 82093AA and cores integrated into various
+ * chipsets).  Under certain conditions a level-triggered interrupt is
+ * erroneously delivered as edge-triggered one but the respective IRR
+ * bit gets set nevertheless.  As a result the I/O unit expects an EOI
+ * message but it will never arrive and further interrupts are blocked
+ * from the source.  The exact reason is so far unknown, but the
+ * phenomenon was observed when two consecutive interrupt requests
+ * from a given source get delivered to the same CPU and the source is
+ * temporarily disabled in between.
+ *
+ * A workaround is to simulate an EOI message manually.  We achieve it
+ * by setting the trigger mode to edge and then to level when the edge
+ * trigger mode gets detected in the TMR of a local APIC for a
+ * level-triggered interrupt.  We mask the source for the time of the
+ * operation to prevent an edge-triggered interrupt escaping meanwhile.
+ * The idea is from Manfred Spraul.  --macro
+ */
+	v = apic_read(APIC_TMR + ((IO_APIC_VECTOR(irq) & ~0x1f) >> 1));
+
 	ack_APIC_irq();
+
+	if (!(v & (1 << (IO_APIC_VECTOR(irq) & 0x1f)))) {
+#ifdef APIC_MISMATCH_DEBUG
+		atomic_inc(&irq_mis_count);
+#endif
+		spin_lock(&ioapic_lock);
+		__mask_and_edge_IO_APIC_irq(irq);
+#ifdef APIC_LOCKUP_DEBUG
+		for (;;) {
+			struct irq_pin_list *entry = irq_2_pin + irq;
+			unsigned int reg;
+
+			if (entry->pin == -1)
+				break;
+			reg = io_apic_read(entry->apic, 0x10 + entry->pin * 2);
+			if (reg & 0x00004000)
+				printk(KERN_CRIT "Aieee!!!  Remote IRR"
+					" still set after unlock!\n");
+			if (!entry->next)
+				break;
+			entry = irq_2_pin + entry->next;
+		}
+#endif
+		__unmask_and_level_IO_APIC_irq(irq);
+		spin_unlock(&ioapic_lock);
+	}
 }
 
-static void mask_and_ack_level_ioapic_irq (unsigned int i) { /* nothing */ }
+static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ }
 
 static void set_ioapic_affinity (unsigned int irq, unsigned long mask)
 {
@@ -1426,7 +1493,7 @@
 	pin1 = find_isa_irq_pin(0, mp_INT);
 	pin2 = find_isa_irq_pin(0, mp_ExtINT);
 
-	printk(KERN_INFO "..TIMER: vector=%d pin1=%d pin2=%d\n", vector, pin1, pin2);
+	printk(KERN_INFO "..TIMER: vector=%02X pin1=%d pin2=%d\n", vector, pin1, pin2);
 
 	if (pin1 != -1) {
 		/*
diff -u --recursive --new-file v2.4.5/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.4.5/linux/arch/i386/kernel/irq.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/i386/kernel/irq.c	Wed Jun 20 11:06:38 2001
@@ -33,6 +33,7 @@
 #include <linux/irq.h>
 #include <linux/proc_fs.h>
 
+#include <asm/atomic.h>
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/system.h>
@@ -119,7 +120,12 @@
 	end_none
 };
 
-volatile unsigned long irq_err_count;
+atomic_t irq_err_count;
+#ifdef CONFIG_X86_IO_APIC
+#ifdef APIC_MISMATCH_DEBUG
+atomic_t irq_mis_count;
+#endif
+#endif
 
 /*
  * Generic, controller-independent functions:
@@ -167,7 +173,12 @@
 			apic_timer_irqs[cpu_logical_map(j)]);
 	p += sprintf(p, "\n");
 #endif
-	p += sprintf(p, "ERR: %10lu\n", irq_err_count);
+	p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
+#ifdef CONFIG_X86_IO_APIC
+#ifdef APIC_MISMATCH_DEBUG
+	p += sprintf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
+#endif
+#endif
 	return p - buf;
 }
 
@@ -623,7 +634,7 @@
 	desc->handler->end(irq);
 	spin_unlock(&desc->lock);
 
-	if (softirq_active(cpu) & softirq_mask(cpu))
+	if (softirq_pending(cpu))
 		do_softirq();
 	return 1;
 }
diff -u --recursive --new-file v2.4.5/linux/arch/i386/kernel/mpparse.c linux/arch/i386/kernel/mpparse.c
--- v2.4.5/linux/arch/i386/kernel/mpparse.c	Tue Nov 14 21:25:34 2000
+++ linux/arch/i386/kernel/mpparse.c	Mon Jun 11 19:15:27 2001
@@ -36,7 +36,7 @@
  */
 int apic_version [MAX_APICS];
 int mp_bus_id_to_type [MAX_MP_BUSSES];
-int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, };
+int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
 int mp_current_pci_id;
 int pic_mode;
 unsigned long mp_lapic_addr;
diff -u --recursive --new-file v2.4.5/linux/arch/i386/kernel/pci-i386.h linux/arch/i386/kernel/pci-i386.h
--- v2.4.5/linux/arch/i386/kernel/pci-i386.h	Thu Jun 22 07:17:16 2000
+++ linux/arch/i386/kernel/pci-i386.h	Wed Jun 20 11:21:33 2001
@@ -12,14 +12,15 @@
 #define DBG(x...)
 #endif
 
-#define PCI_PROBE_BIOS 1
-#define PCI_PROBE_CONF1 2
-#define PCI_PROBE_CONF2 4
-#define PCI_NO_SORT 0x100
-#define PCI_BIOS_SORT 0x200
-#define PCI_NO_CHECKS 0x400
-#define PCI_ASSIGN_ROMS 0x1000
-#define PCI_BIOS_IRQ_SCAN 0x2000
+#define PCI_PROBE_BIOS		0x0001
+#define PCI_PROBE_CONF1		0x0002
+#define PCI_PROBE_CONF2		0x0004
+#define PCI_NO_SORT		0x0100
+#define PCI_BIOS_SORT		0x0200
+#define PCI_NO_CHECKS		0x0400
+#define PCI_ASSIGN_ROMS		0x1000
+#define PCI_BIOS_IRQ_SCAN	0x2000
+#define PCI_ASSIGN_ALL_BUSSES	0x4000
 
 extern unsigned int pci_probe;
 
diff -u --recursive --new-file v2.4.5/linux/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c
--- v2.4.5/linux/arch/i386/kernel/pci-irq.c	Wed May 16 10:25:39 2001
+++ linux/arch/i386/kernel/pci-irq.c	Wed Jun 20 11:16:01 2001
@@ -411,7 +411,7 @@
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set },
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX,   pirq_piix_get, pirq_piix_set },
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82820FW_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, pirq_piix_get, pirq_piix_set },
 
 	{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
 
@@ -587,13 +587,14 @@
 		if (info->irq[pin].link == pirq) {
 			/* We refuse to override the dev->irq information. Give a warning! */
 		    	if (dev2->irq && dev2->irq != irq) {
-		    		printk(KERN_INFO "IRQ routing conflict in pirq table for device %s\n", dev2->slot_name);
+		    		printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n",
+				       dev2->slot_name, dev2->irq, irq);
 		    		continue;
 		    	}
 			dev2->irq = irq;
 			pirq_penalty[irq]++;
 			if (dev != dev2)
-				printk(KERN_INFO "PCI: The same IRQ used for device %s\n", dev2->slot_name);
+				printk(KERN_INFO "PCI: Sharing IRQ %d with %s\n", irq, dev2->slot_name);
 		}
 	}
 	return 1;
@@ -656,10 +657,12 @@
 			if (pin) {
 				pin--;		/* interrupt pins are numbered starting from 1 */
 				irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
-/*
- * Will be removed completely if things work out well with fuzzy parsing
- */
-#if 0
+	/*
+	 * Busses behind bridges are typically not listed in the MP-table.
+	 * In this case we have to look up the IRQ based on the parent bus,
+	 * parent slot, and pin number. The SMP code detects such bridged
+	 * busses itself so we should get into this branch reliably.
+	 */
 				if (irq < 0 && dev->bus->parent) { /* go back to the bridge */
 					struct pci_dev * bridge = dev->bus->self;
 
@@ -670,7 +673,6 @@
 						printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", 
 							bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq);
 				}
-#endif
 				if (irq >= 0) {
 					printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
 						dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
diff -u --recursive --new-file v2.4.5/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c
--- v2.4.5/linux/arch/i386/kernel/pci-pc.c	Thu Apr 19 22:57:06 2001
+++ linux/arch/i386/kernel/pci-pc.c	Wed Jun 20 11:21:33 2001
@@ -940,18 +940,6 @@
 	pcibios_max_latency = 32;
 }
 
-static void __init pci_fixup_via_acpi(struct pci_dev *d)
-{
-	/*
-	 * VIA ACPI device: IRQ line in PCI config byte 0x42
-	 */
-	u8 irq;
-	pci_read_config_byte(d, 0x42, &irq);
-	irq &= 0x0f;
-	if (irq && (irq != 2))
-		d->irq = irq;
-}
-
 static void __init pci_fixup_piix4_acpi(struct pci_dev *d)
 {
 	/*
@@ -1006,8 +994,6 @@
 	{ PCI_FIXUP_HEADER,	PCI_ANY_ID,		PCI_ANY_ID,			pci_fixup_ide_bases },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		pci_fixup_latency },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5598,		pci_fixup_latency },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_3,	pci_fixup_via_acpi },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_4,	pci_fixup_via_acpi },
  	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C691,	pci_fixup_via691 },
  	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C598_1,	pci_fixup_via691_2 },
  	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371AB_3,	pci_fixup_piix4_acpi },
@@ -1104,6 +1090,9 @@
 	else if (!strcmp(str, "rom")) {
 		pci_probe |= PCI_ASSIGN_ROMS;
 		return NULL;
+	} else if (!strcmp(str, "assign-busses")) {
+		pci_probe |= PCI_ASSIGN_ALL_BUSSES;
+		return NULL;
 	} else if (!strncmp(str, "irqmask=", 8)) {
 		pcibios_irq_mask = simple_strtol(str+8, NULL, 0);
 		return NULL;
@@ -1112,6 +1101,11 @@
 		return NULL;
 	}
 	return str;
+}
+
+unsigned int pcibios_assign_all_busses(void)
+{
+	return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
 }
 
 int pcibios_enable_device(struct pci_dev *dev)
diff -u --recursive --new-file v2.4.5/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.4.5/linux/arch/i386/kernel/traps.c	Mon May  7 14:15:21 2001
+++ linux/arch/i386/kernel/traps.c	Wed Jun 20 13:59:44 2001
@@ -105,6 +105,7 @@
 	i = 1;
 	module_start = VMALLOC_START;
 	module_end = VMALLOC_END;
+	module_end = 0;
 	while (((long) stack & (THREAD_SIZE-1)) != 0) {
 		addr = *stack++;
 		/*
@@ -129,7 +130,12 @@
 
 void show_trace_task(struct task_struct *tsk)
 {
-	show_trace(&tsk->thread.esp);
+	unsigned long esp = tsk->thread.esp;
+
+	/* User space on another CPU? */
+	if ((esp ^ (unsigned long)tsk) & (PAGE_MASK<<1))
+		return;
+	show_trace((unsigned long *)esp);
 }
 
 void show_stack(unsigned long * esp)
diff -u --recursive --new-file v2.4.5/linux/arch/i386/math-emu/fpu_trig.c linux/arch/i386/math-emu/fpu_trig.c
--- v2.4.5/linux/arch/i386/math-emu/fpu_trig.c	Fri Apr  6 10:42:47 2001
+++ linux/arch/i386/math-emu/fpu_trig.c	Tue Jun 12 11:06:54 2001
@@ -1543,6 +1543,7 @@
 	  EXCEPTION(EX_INTERNAL | 0x116);
 	  return;
 #endif /* PARANOID */
+	  break;
 	}
     }
   else if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) )
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/Makefile linux/arch/m68k/Makefile
--- v2.4.5/linux/arch/m68k/Makefile	Thu Jan  4 13:00:55 2001
+++ linux/arch/m68k/Makefile	Mon Jun 11 19:15:27 2001
@@ -110,8 +110,8 @@
 endif
 
 ifdef CONFIG_SUN3X
-CORE_FILES := $(CORE_FILES) arch/m68k/sun3x/sun3x.o
-SUBDIRS := $(SUBDIRS) arch/m68k/sun3x
+CORE_FILES := $(CORE_FILES) arch/m68k/sun3x/sun3x.o arch/m68k/sun3/sun3.o
+SUBDIRS := $(SUBDIRS) arch/m68k/sun3x arch/m68k/sun3
 endif
 
 ifdef CONFIG_SUN3
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/amiga/amisound.c linux/arch/m68k/amiga/amisound.c
--- v2.4.5/linux/arch/m68k/amiga/amisound.c	Thu Jan  4 13:00:55 2001
+++ linux/arch/m68k/amiga/amisound.c	Mon Jun 11 19:15:27 2001
@@ -16,7 +16,7 @@
 #include <asm/system.h>
 #include <asm/amigahw.h>
 
-static u_short *snd_data = NULL;
+static unsigned short *snd_data = NULL;
 static const signed char sine_data[] = {
 	0,  39,  75,  103,  121,  127,  121,  103,  75,  39,
 	0, -39, -75, -103, -121, -127, -121, -103, -75, -39
@@ -28,7 +28,7 @@
      * device since it depends on htotal (for OCS/ECS/AGA)
      */
 
-volatile u_short amiga_audio_min_period = 124;	/* Default for pre-OCS */
+volatile unsigned short amiga_audio_min_period = 124; /* Default for pre-OCS */
 
 #define MAX_PERIOD	(65535)
 
@@ -37,9 +37,9 @@
      *	Current period (set by dmasound.c)
      */
 
-u_short amiga_audio_period = MAX_PERIOD;
+unsigned short amiga_audio_period = MAX_PERIOD;
 
-static u_long clock_constant;
+static unsigned long clock_constant;
 
 void __init amiga_init_sound(void)
 {
@@ -76,7 +76,7 @@
 	del_timer( &sound_timer );
 
 	if (hz > 20 && hz < 32767) {
-		u_long period = (clock_constant / hz);
+		unsigned long period = (clock_constant / hz);
 
 		if (period < amiga_audio_min_period)
 			period = amiga_audio_min_period;
@@ -86,7 +86,7 @@
 		/* setup pointer to data, period, length and volume */
 		custom.aud[2].audlc = snd_data;
 		custom.aud[2].audlen = sizeof(sine_data)/2;
-		custom.aud[2].audper = (u_short)period;
+		custom.aud[2].audper = (unsigned short)period;
 		custom.aud[2].audvol = 32; /* 50% of maxvol */
 	
 		if (ticks) {
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/amiga/cia.c linux/arch/m68k/amiga/cia.c
--- v2.4.5/linux/arch/m68k/amiga/cia.c	Mon Nov 27 17:57:34 2000
+++ linux/arch/m68k/amiga/cia.c	Mon Jun 11 19:15:27 2001
@@ -23,8 +23,8 @@
 
 struct ciabase {
 	volatile struct CIA *cia;
-	u_char icr_mask, icr_data;
-	u_short int_mask;
+	unsigned char icr_mask, icr_data;
+	unsigned short int_mask;
 	int handler_irq, cia_irq, server_irq;
 	char *name;
 	irq_handler_t irq_list[CIA_IRQS];
@@ -46,7 +46,7 @@
 
 unsigned char cia_set_irq(struct ciabase *base, unsigned char mask)
 {
-	u_char old;
+	unsigned char old;
 
 	old = (base->icr_data |= base->cia->icr);
 	if (mask & CIA_ICR_SETCLR)
@@ -65,7 +65,7 @@
 
 unsigned char cia_able_irq(struct ciabase *base, unsigned char mask)
 {
-	u_char old, tmp;
+	unsigned char old, tmp;
 	int i;
 
 	old = base->icr_mask;
@@ -91,7 +91,7 @@
                     void (*handler)(int, void *, struct pt_regs *),
                     unsigned long flags, const char *devname, void *dev_id)
 {
-	u_char mask;
+	unsigned char mask;
 
 	base->irq_list[irq].handler = handler;
 	base->irq_list[irq].flags   = flags;
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c
--- v2.4.5/linux/arch/m68k/amiga/config.c	Fri Apr 13 20:26:07 2001
+++ linux/arch/m68k/amiga/config.c	Mon Jun 11 19:15:27 2001
@@ -16,7 +16,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/kd.h>
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/init.h>
@@ -31,6 +30,7 @@
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #include <asm/irq.h>
+#include <asm/rtc.h>
 #include <asm/keyboard.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/amiga/pcmcia.c linux/arch/m68k/amiga/pcmcia.c
--- v2.4.5/linux/arch/m68k/amiga/pcmcia.c	Thu Dec 17 09:06:25 1998
+++ linux/arch/m68k/amiga/pcmcia.c	Mon Jun 11 19:15:27 2001
@@ -19,7 +19,7 @@
 #include <asm/amipcmcia.h>
 
 /* gayle config byte for program voltage and access speed */
-static u_char cfg_byte = GAYLE_CFG_0V|GAYLE_CFG_150NS;
+static unsigned char cfg_byte = GAYLE_CFG_0V|GAYLE_CFG_150NS;
 
 void pcmcia_reset(void)
 {
@@ -64,7 +64,7 @@
 
 void pcmcia_program_voltage(int voltage)
 {
-	u_char v;
+	unsigned char v;
 
 	switch (voltage) {
 	case PCMCIA_0V:
@@ -87,7 +87,7 @@
 
 void pcmcia_access_speed(int speed)
 {
-	u_char s;
+	unsigned char s;
 
 	if (speed <= PCMCIA_SPEED_100NS)
 		s = GAYLE_CFG_100NS;
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/apollo/config.c linux/arch/m68k/apollo/config.c
--- v2.4.5/linux/arch/m68k/apollo/config.c	Wed Jan 26 12:44:20 2000
+++ linux/arch/m68k/apollo/config.c	Mon Jun 11 19:15:27 2001
@@ -2,7 +2,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/kd.h>
 #include <linux/tty.h>
 #include <linux/console.h>
 
@@ -12,6 +11,7 @@
 #include <asm/pgtable.h>
 #include <asm/apollohw.h>
 #include <asm/irq.h>
+#include <asm/rtc.h>
 #include <asm/machdep.h>
 
 u_long sio01_physaddr;
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/atari/time.c linux/arch/m68k/atari/time.c
--- v2.4.5/linux/arch/m68k/atari/time.c	Thu Aug 26 12:42:31 1999
+++ linux/arch/m68k/atari/time.c	Mon Jun 11 19:15:27 2001
@@ -12,10 +12,10 @@
 
 #include <linux/types.h>
 #include <linux/mc146818rtc.h>
-#include <linux/kd.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 
+#include <asm/rtc.h>
 
 void __init
 atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/bvme6000/config.c linux/arch/m68k/bvme6000/config.c
--- v2.4.5/linux/arch/m68k/bvme6000/config.c	Mon Jan 31 10:32:53 2000
+++ linux/arch/m68k/bvme6000/config.c	Mon Jun 11 19:15:27 2001
@@ -17,7 +17,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/kd.h>
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/linkage.h>
@@ -30,6 +29,7 @@
 #include <asm/setup.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
+#include <asm/rtc.h>
 #include <asm/machdep.h>
 #include <asm/bvme6000hw.h>
 
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/bvme6000/rtc.c linux/arch/m68k/bvme6000/rtc.c
--- v2.4.5/linux/arch/m68k/bvme6000/rtc.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/m68k/bvme6000/rtc.c	Mon Jun 11 19:15:27 2001
@@ -76,7 +76,7 @@
 		unsigned char mon, day, hrs, min, sec, leap_yr;
 		unsigned int yrs;
 
-		if (!suser())
+		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
 
 		if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- v2.4.5/linux/arch/m68k/config.in	Mon May 21 18:12:09 2001
+++ linux/arch/m68k/config.in	Mon Jun 11 19:15:27 2001
@@ -55,8 +55,8 @@
 if [ "$CONFIG_HP300" = "y" ]; then
    bool '  DIO bus support' CONFIG_DIO
 fi
-bool 'Sun3 support' CONFIG_SUN3
 bool 'Sun3x support' CONFIG_SUN3X
+bool 'Sun3 support' CONFIG_SUN3
   
 bool 'Q40/Q60 support' CONFIG_Q40
 
@@ -112,7 +112,7 @@
    bool 'Support for ST-RAM as swap space' CONFIG_STRAM_SWAP
    bool 'ST-RAM statistics in /proc' CONFIG_STRAM_PROC
 fi
-if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then
+if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o "$CONFIG_Q40" = "y" ]; then
    bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT
 else
   if [ "$CONFIG_HP300" = "y" ]; then
@@ -142,13 +142,17 @@
    fi
    dep_tristate '  Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
    if [ "$CONFIG_PRINTER" != "n" ]; then
-      bool '    Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
+      bool '    Support IEEE1284 status readback' CONFIG_PARPORT_1284
    fi
 fi
 
 source drivers/pci/Config.in
 source drivers/zorro/Config.in
 
+if [ "$CONFIG_Q40" = "y" ]; then
+source drivers/pnp/Config.in
+fi
+
 endmenu
 
 source drivers/mtd/Config.in
@@ -264,11 +268,11 @@
    fi
 
    if [ "$CONFIG_SUN3" = "y" ]; then
-	dep_tristate 'Sun3 NCR5380 SCSI' CONFIG_SUN3_SCSI $CONFIG_SCSI
+	dep_tristate 'Sun3 NCR5380 OBIO SCSI' CONFIG_SUN3_SCSI $CONFIG_SCSI
    fi
 
    if [ "$CONFIG_SUN3X" = "y" ]; then
-      bool 'ESP SCSI driver' CONFIG_SUN3X_ESP
+      bool 'Sun3x ESP SCSI' CONFIG_SUN3X_ESP
    fi
 
    endmenu
@@ -338,6 +342,9 @@
       if [ "$CONFIG_SUN3" = "y" -o "$CONFIG_SUN3X" = "y" ]; then
 	tristate '  Sun3/Sun3x on-board LANCE support' CONFIG_SUN3LANCE
       fi
+      if [ "$CONFIG_SUN3" = "y" ]; then
+	tristate '  Sun3 on-board Intel 82586 support' CONFIG_SUN3_82586
+      fi
       if [ "$CONFIG_HP300" = "y" ]; then
 	 bool '  HP on-board LANCE support' CONFIG_HPLANCE
       fi
@@ -367,7 +374,6 @@
 if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
    bool '    Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
    bool '    Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ
-#   bool '    Autodetect IRQ - do not yet enable !!' CONFIG_SERIAL_DETECT_IRQ
    bool '    Support special multiport boards' CONFIG_SERIAL_MULTIPORT
    bool '    Support the Bell Technologies HUB6 card' CONFIG_HUB6
 fi
@@ -451,16 +457,16 @@
 else
    define_bool CONFIG_SUN3X_ZS n
 fi
-dep_bool '  Sun keyboard support' CONFIG_SUN_KEYBOARD $CONFIG_SUN3X_ZS
-dep_bool '  Sun mouse support' CONFIG_SUN_MOUSE $CONFIG_SUN3X_ZS
-if [ "$CONFIG_SUN_MOUSE" = "y" ]; then
-   define_bool CONFIG_BUSMOUSE y
-fi
 if [ "$CONFIG_SUN3X_ZS" = "y" ]; then
+   define_bool CONFIG_SUN_KEYBOARD y
+   define_bool CONFIG_SUN_MOUSE y
+   define_bool CONFIG_BUSMOUSE y
    define_bool CONFIG_SBUS y
    define_bool CONFIG_SBUSCHAR y
    define_bool CONFIG_SUN_SERIAL y
 else
+   define_bool CONFIG_SUN_KEYBOARD n
+   define_bool CONFIG_SUN_MOUSE n
    define_bool CONFIG_SBUS n
 fi
 
@@ -508,9 +514,6 @@
    else
       bool 'Generic /dev/rtc emulation' CONFIG_GEN_RTC
    fi
-fi
-if [ "$CONFIG_Q40" = "y" ]; then
-  bool 'Q40 Real Time Clock Support' CONFIG_Q40RTC
 fi
 bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
 if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S
--- v2.4.5/linux/arch/m68k/kernel/head.S	Tue Mar  6 19:44:36 2001
+++ linux/arch/m68k/kernel/head.S	Mon Jun 11 19:15:27 2001
@@ -1178,8 +1178,45 @@
 #ifdef CONFIG_SUN3X
 	is_not_sun3x(L(notsun3x))
 
+	/* oh, the pain..  We're gonna want the prom code after
+	 * starting the MMU, so we copy the mappings, translating
+	 * from 8k -> 4k pages as we go.
+	 */
+
+	/* copy maps from 0xfee00000 to 0xff000000 */
+	movel	#0xfee00000, %d0
+	moveq	#ROOT_INDEX_SHIFT, %d1
+	lsrl	%d1,%d0
+	mmu_get_root_table_entry	%d0
+
+	movel	#0xfee00000, %d0
+	moveq	#PTR_INDEX_SHIFT, %d1
+	lsrl	%d1,%d0
+	andl	#PTR_TABLE_SIZE-1, %d0
+	mmu_get_ptr_table_entry		%a0,%d0
+
+	movel	#0xfee00000, %d0
+	moveq	#PAGE_INDEX_SHIFT, %d1
+	lsrl	%d1,%d0
+	andl	#PAGE_TABLE_SIZE-1, %d0
+	mmu_get_page_table_entry	%a0,%d0
+
+	/* this is where the prom page table lives */	
+	movel	0xfefe00d4, %a1
+	movel	%a1@, %a1
+
+	movel	#((0x200000 >> 13)-1), %d1
+
+1:
+	movel	%a1@+, %d3
+	movel	%d3,%a0@+
+	addl	#0x1000,%d3
+	movel	%d3,%a0@+
+	
+	dbra	%d1,1b	
+		
 	/* setup tt1 for I/O */
-	mmu_map_tt	#1,#0x40000000,#0x40000000,#_PAGE_NOCACHE_S
+	mmu_map_tt	#1,#0x40000000,#0x40000000,#_PAGE_NOCACHE_S 
 	jbra	L(mmu_init_done)
 
 L(notsun3x):
@@ -1363,7 +1400,7 @@
 	is_not_sun3x(1f)
 
 	/* enable copro */
-	oriw	#0x4000,0x61000000
+	oriw	#0x4000,0x61000000 
 1:
 #endif
 
@@ -3061,6 +3098,16 @@
 2:
 #endif
 
+#ifdef CONFIG_SUN3X
+	is_not_sun3x(2f) 
+	movel	%d0,-(%sp)
+	movel	0xFEFE0018,%a1
+	jbsr	(%a1)
+	addq	#4,%sp
+	jbra	L(serial_putc_done)
+2:	
+#endif
+	
 #ifdef CONFIG_Q40
 	is_not_q40(2f)
 	tst.l	%pc@(L(q40_do_debug))	/* only debug if requested */
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c
--- v2.4.5/linux/arch/m68k/kernel/ptrace.c	Mon Nov 27 18:02:06 2000
+++ linux/arch/m68k/kernel/ptrace.c	Mon Jun 11 19:15:27 2001
@@ -107,15 +107,19 @@
 	ret = -ESRCH;
 	read_lock(&tasklist_lock);
 	child = find_task_by_pid(pid);
-	read_unlock(&tasklist_lock);	/* FIXME!!! */
+	if (child)
+		get_task_struct(child);
+	read_unlock(&tasklist_lock);
 	if (!child)
 		goto out;
+
 	ret = -EPERM;
 	if (pid == 1)		/* you may not mess with init */
-		goto out;
+		goto out_tsk;
+
 	if (request == PTRACE_ATTACH) {
 		if (child == current)
-			goto out;
+			goto out_tsk;
 		if ((!child->dumpable ||
 		    (current->uid != child->euid) ||
 		    (current->uid != child->suid) ||
@@ -124,10 +128,10 @@
 		    (current->gid != child->sgid) ||
 	 	    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
 	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
-			goto out;
+			goto out_tsk;
 		/* the same process cannot be attached many times */
 		if (child->ptrace & PT_PTRACED)
-			goto out;
+			goto out_tsk;
 		child->ptrace |= PT_PTRACED;
 
 		write_lock_irqsave(&tasklist_lock, flags);
@@ -140,17 +144,17 @@
 
 		send_sig(SIGSTOP, child, 1);
 		ret = 0;
-		goto out;
+		goto out_tsk;
 	}
 	ret = -ESRCH;
 	if (!(child->ptrace & PT_PTRACED))
-		goto out;
+		goto out_tsk;
 	if (child->state != TASK_STOPPED) {
 		if (request != PTRACE_KILL)
-			goto out;
+			goto out_tsk;
 	}
 	if (child->p_pptr != current)
-		goto out;
+		goto out_tsk;
 
 	switch (request) {
 	/* when I and D space are separate, these will need to be fixed. */
@@ -162,9 +166,9 @@
 			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
 			ret = -EIO;
 			if (copied != sizeof(tmp))
-				goto out;
+				break;
 			ret = put_user(tmp,(unsigned long *) data);
-			goto out;
+			break;
 		}
 
 	/* read the word at location addr in the USER area. */
@@ -172,8 +176,9 @@
 			unsigned long tmp;
 			
 			ret = -EIO;
-			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
-				goto out;
+			if ((addr & 3) || addr < 0 ||
+			    addr > sizeof(struct user) - 3)
+				break;
 			
 			tmp = 0;  /* Default return condition */
 			addr = addr >> 2; /* temporary hack. */
@@ -193,9 +198,9 @@
 					      ((tmp & 0x0000ffff) << 16);
 #endif
 			} else
-				goto out;
+				break;
 			ret = put_user(tmp,(unsigned long *) data);
-			goto out;
+			break;
 		}
 
       /* when I and D space are separate, this will have to be fixed. */
@@ -203,14 +208,15 @@
 		case PTRACE_POKEDATA:
 			ret = 0;
 			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
-				goto out;
+				break;
 			ret = -EIO;
-			goto out;
+			break;
 
 		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
 			ret = -EIO;
-			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
-				goto out;
+			if ((addr & 3) || addr < 0 ||
+			    addr > sizeof(struct user) - 3)
+				break;
 
 			addr = addr >> 2; /* temporary hack. */
 			    
@@ -221,9 +227,9 @@
 			}
 			if (addr < 19) {
 				if (put_reg(child, addr, data))
-					goto out;
+					break;
 				ret = 0;
-				goto out;
+				break;
 			}
 			if (addr >= 21 && addr < 48)
 			{
@@ -240,7 +246,7 @@
 				child->thread.fp[addr - 21] = data;
 				ret = 0;
 			}
-			goto out;
+			break;
 
 		case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 		case PTRACE_CONT: { /* restart after signal. */
@@ -248,7 +254,7 @@
 
 			ret = -EIO;
 			if ((unsigned long) data > _NSIG)
-				goto out;
+				break;
 			if (request == PTRACE_SYSCALL)
 				child->ptrace |= PT_TRACESYS;
 			else
@@ -259,7 +265,7 @@
 			put_reg(child, PT_SR, tmp);
 			wake_up_process(child);
 			ret = 0;
-			goto out;
+			break;
 		}
 
 /*
@@ -272,13 +278,13 @@
 
 			ret = 0;
 			if (child->state == TASK_ZOMBIE) /* already dead */
-				goto out;
+				break;
 			child->exit_code = SIGKILL;
 	/* make sure the single step bit is not set. */
 			tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
 			put_reg(child, PT_SR, tmp);
 			wake_up_process(child);
-			goto out;
+			break;
 		}
 
 		case PTRACE_SINGLESTEP: {  /* set the trap flag. */
@@ -286,7 +292,7 @@
 
 			ret = -EIO;
 			if ((unsigned long) data > _NSIG)
-				goto out;
+				break;
 			child->ptrace &= ~PT_TRACESYS;
 			tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
 			put_reg(child, PT_SR, tmp);
@@ -295,7 +301,7 @@
 	/* give it a chance to run. */
 			wake_up_process(child);
 			ret = 0;
-			goto out;
+			break;
 		}
 
 		case PTRACE_DETACH: { /* detach a process that was attached. */
@@ -303,7 +309,7 @@
 
 			ret = -EIO;
 			if ((unsigned long) data > _NSIG)
-				goto out;
+				break;
 			child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
 			child->exit_code = data;
 			write_lock_irqsave(&tasklist_lock, flags);
@@ -316,7 +322,7 @@
 			put_reg(child, PT_SR, tmp);
 			wake_up_process(child);
 			ret = 0;
-			goto out;
+			break;
 		}
 
 		case PTRACE_GETREGS: { /* Get all gp regs from the child. */
@@ -328,12 +334,12 @@
 				tmp >>= 16;
 			    if (put_user(tmp, (unsigned long *) data)) {
 				ret = -EFAULT;
-				goto out;
+				break;
 			    }
 			    data += sizeof(long);
 			}
 			ret = 0;
-			goto out;
+			break;
 		}
 
 		case PTRACE_SETREGS: { /* Set all gp regs in the child. */
@@ -342,7 +348,7 @@
 			for (i = 0; i < 19; i++) {
 			    if (get_user(tmp, (unsigned long *) data)) {
 				ret = -EFAULT;
-				goto out;
+				break;
 			    }
 			    if (i == PT_SR) {
 				tmp &= SR_MASK;
@@ -353,7 +359,7 @@
 			    data += sizeof(long);
 			}
 			ret = 0;
-			goto out;
+			break;
 		}
 
 		case PTRACE_GETFPREGS: { /* Get the child FPU state. */
@@ -361,7 +367,7 @@
 			if (copy_to_user((void *)data, &child->thread.fp,
 					 sizeof(struct user_m68kfp_struct)))
 				ret = -EFAULT;
-			goto out;
+			break;
 		}
 
 		case PTRACE_SETFPREGS: { /* Set the child FPU state. */
@@ -369,13 +375,15 @@
 			if (copy_from_user(&child->thread.fp, (void *)data,
 					   sizeof(struct user_m68kfp_struct)))
 				ret = -EFAULT;
-			goto out;
+			break;
 		}
 
 		default:
 			ret = -EIO;
-			goto out;
+			break;
 	}
+out_tsk:
+	free_task_struct(child);
 out:
 	unlock_kernel();
 	return ret;
@@ -383,10 +391,9 @@
 
 asmlinkage void syscall_trace(void)
 {
-	lock_kernel();
 	if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
 			!= (PT_PTRACED|PT_TRACESYS))
-		goto out;
+		return;
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
 	notify_parent(current, SIGCHLD);
@@ -400,6 +407,4 @@
 		send_sig(current->exit_code, current, 1);
 		current->exit_code = 0;
 	}
-out:
-	unlock_kernel();
 }
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c
--- v2.4.5/linux/arch/m68k/kernel/setup.c	Fri Apr 13 20:26:07 2001
+++ linux/arch/m68k/kernel/setup.c	Mon Jun 11 19:15:27 2001
@@ -34,6 +34,10 @@
 #ifdef CONFIG_ATARI
 #include <asm/atarihw.h>
 #endif
+#ifdef CONFIG_SUN3X
+#include <asm/dvma.h>
+extern void sun_serial_setup(void);
+#endif
 
 #ifdef CONFIG_BLK_DEV_INITRD
 #include <linux/blk.h>
@@ -106,6 +110,11 @@
 char *mach_sysrq_xlate = NULL;
 #endif
 
+#if defined(CONFIG_ISA)
+int isa_type;
+int isa_sex;
+#endif
+
 extern int amiga_parse_bootinfo(const struct bi_record *);
 extern int atari_parse_bootinfo(const struct bi_record *);
 extern int mac_parse_bootinfo(const struct bi_record *);
@@ -137,7 +146,7 @@
 {
     while (record->tag != BI_LAST) {
 	int unknown = 0;
-	const u_long *data = record->data;
+	const unsigned long *data = record->data;
 	switch (record->tag) {
 	    case BI_MACHTYPE:
 	    case BI_CPUTYPE:
@@ -186,7 +195,7 @@
 	if (unknown)
 	    printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n",
 		   record->tag);
-	record = (struct bi_record *)((u_long)record+record->size);
+	record = (struct bi_record *)((unsigned long)record+record->size);
     }
 
     m68k_realnum_memory = m68k_num_memory;
@@ -365,14 +374,44 @@
 	if (MACH_IS_ATARI)
 		atari_stram_reserve_pages(availmem);
 #endif
+#ifdef CONFIG_SUN3X
+	if (MACH_IS_SUN3X) {
+		dvma_init();
+#ifdef CONFIG_SUN3X_ZS
+		sun_serial_setup();
+#endif
+	}
+#endif
+
 #endif /* !CONFIG_SUN3 */
+
 	paging_init();
+
+/* set ISA defs early as possible */
+#if defined(CONFIG_ISA)
+#if defined(CONFIG_Q40) 
+	if (MACH_IS_Q40) {
+	    isa_type = Q40_ISA;
+	    isa_sex = 0;
+	} 
+#elif defined(CONFIG_GG2)
+	if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)){
+	    isa_type = GG2_ISA;
+	    isa_sex = 0;
+	}
+#elif defined(CONFIG_AMIGA_PCMCIA)
+	if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)){
+	    isa_type = AG_ISA;
+	    isa_sex = 1;
+	}
+#endif
+#endif
 }
 
 int get_cpuinfo(char * buffer)
 {
     const char *cpu, *mmu, *fpu;
-    u_long clockfreq, clockfactor;
+    unsigned long clockfreq, clockfactor;
 
 #define LOOP_CYCLES_68020	(8)
 #define LOOP_CYCLES_68030	(8)
@@ -447,7 +486,7 @@
 {
     int len = 0;
     char model[80];
-    u_long mem;
+    unsigned long mem;
     int i;
 
     if (mach_get_model)
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/kernel/sys_m68k.c linux/arch/m68k/kernel/sys_m68k.c
--- v2.4.5/linux/arch/m68k/kernel/sys_m68k.c	Mon Mar 19 12:35:09 2001
+++ linux/arch/m68k/kernel/sys_m68k.c	Mon Jun 11 19:15:27 2001
@@ -267,7 +267,8 @@
   return -ENOSYS;
 }
 
-/* Convert virtual address VADDR to physical address PADDR */
+
+/* Convert virtual (user) address VADDR to physical address PADDR */
 #define virt_to_phys_040(vaddr)						\
 ({									\
   unsigned long _mmusr, _paddr;						\
@@ -447,6 +448,12 @@
 {
   unsigned long paddr, i;
 
+  /*
+   * 68060 manual says: 
+   *  cpush %dc : flush DC, remains valid (with our %cacr setup)
+   *  cpush %ic : invalidate IC
+   *  cpush %bc : flush DC + invalidate IC
+   */
   switch (scope)
     {
     case FLUSH_SCOPE_ALL:
@@ -455,20 +462,17 @@
 	case FLUSH_CACHE_DATA:
 	  __asm__ __volatile__ (".chip 68060\n\t"
 				"cpusha %dc\n\t"
-				"cinva %dc\n\t"
 				".chip 68k");
 	  break;
 	case FLUSH_CACHE_INSN:
 	  __asm__ __volatile__ (".chip 68060\n\t"
 				"cpusha %ic\n\t"
-				"cinva %ic\n\t"
 				".chip 68k");
 	  break;
 	default:
 	case FLUSH_CACHE_BOTH:
 	  __asm__ __volatile__ (".chip 68060\n\t"
 				"cpusha %bc\n\t"
-				"cinva %bc\n\t"
 				".chip 68k");
 	  break;
 	}
@@ -506,14 +510,12 @@
 	    case FLUSH_CACHE_DATA:
 	      __asm__ __volatile__ (".chip 68060\n\t"
 				    "cpushl %%dc,(%0)\n\t"
-				    "cinvl %%dc,(%0)\n\t"
 				    ".chip 68k"
 				    : : "a" (paddr));
 	      break;
 	    case FLUSH_CACHE_INSN:
 	      __asm__ __volatile__ (".chip 68060\n\t"
 				    "cpushl %%ic,(%0)\n\t"
-				    "cinvl %%ic,(%0)\n\t"
 				    ".chip 68k"
 				    : : "a" (paddr));
 	      break;
@@ -521,7 +523,6 @@
 	    case FLUSH_CACHE_BOTH:
 	      __asm__ __volatile__ (".chip 68060\n\t"
 				    "cpushl %%bc,(%0)\n\t"
-				    "cinvl %%bc,(%0)\n\t"
 				    ".chip 68k"
 				    : : "a" (paddr));
 	      break;
@@ -568,14 +569,12 @@
 	    case FLUSH_CACHE_DATA:
 	      __asm__ __volatile__ (".chip 68060\n\t"
 				    "cpushp %%dc,(%0)\n\t"
-				    "cinvp %%dc,(%0)\n\t"
 				    ".chip 68k"
 				    : : "a" (paddr));
 	      break;
 	    case FLUSH_CACHE_INSN:
 	      __asm__ __volatile__ (".chip 68060\n\t"
 				    "cpushp %%ic,(%0)\n\t"
-				    "cinvp %%ic,(%0)\n\t"
 				    ".chip 68k"
 				    : : "a" (paddr));
 	      break;
@@ -583,7 +582,6 @@
 	    case FLUSH_CACHE_BOTH:
 	      __asm__ __volatile__ (".chip 68060\n\t"
 				    "cpushp %%bc,(%0)\n\t"
-				    "cinvp %%bc,(%0)\n\t"
 				    ".chip 68k"
 				    : : "a" (paddr));
 	      break;
@@ -607,13 +605,14 @@
 		goto out;
 
 	if (scope == FLUSH_SCOPE_ALL) {
-		/* Only the superuser may flush the whole cache. */
+		/* Only the superuser may explicitly flush the whole cache. */
 		ret = -EPERM;
 		if (!capable(CAP_SYS_ADMIN))
 			goto out;
 	} else {
-		/* Verify that the specified address region actually belongs to
-		 * this process.
+		/*
+		 * Verify that the specified address region actually belongs
+		 * to this process.
 		 */
 		vma = find_vma (current->mm, addr);
 		ret = -EINVAL;
@@ -652,10 +651,21 @@
 		}
 		ret = 0;
 		goto out;
-	} else if (CPU_IS_040) {
+	} else {
+	    /*
+	     * 040 or 060: don't blindly trust 'scope', someone could
+	     * try to flush a few megs of memory.
+	     */
+
+	    if (len>=3*PAGE_SIZE && scope<FLUSH_SCOPE_PAGE)
+	        scope=FLUSH_SCOPE_PAGE;
+	    if (len>=10*PAGE_SIZE && scope<FLUSH_SCOPE_ALL)
+	        scope=FLUSH_SCOPE_ALL;
+	    if (CPU_IS_040) {
 		ret = cache_flush_040 (addr, scope, cache, len);
-	} else if (CPU_IS_060) {
+	    } else if (CPU_IS_060) {
 		ret = cache_flush_060 (addr, scope, cache, len);
+	    }
 	}
 out:
 	unlock_kernel();
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c
--- v2.4.5/linux/arch/m68k/kernel/traps.c	Thu Jan  4 13:00:55 2001
+++ linux/arch/m68k/kernel/traps.c	Mon Jun 11 19:15:27 2001
@@ -72,6 +72,12 @@
  */
 void __init base_trap_init(void)
 {
+	if(MACH_IS_SUN3X) {
+		extern e_vector *sun3x_prom_vbr;
+
+		__asm__ volatile ("movec %%vbr, %0" : "=r" ((void*)sun3x_prom_vbr));
+	}
+	
 	/* setup the exception vector table */
 	__asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
 
@@ -245,9 +251,12 @@
 #endif /* CONFIG_M68060 */
 
 #if defined (CONFIG_M68040)
-static inline unsigned long probe040(int iswrite, unsigned long addr)
+static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs)
 {
 	unsigned long mmusr;
+	mm_segment_t old_fs = get_fs();
+
+	set_fs(MAKE_MM_SEG(wbs));
 
 	asm volatile (".chip 68040");
 
@@ -260,6 +269,8 @@
 
 	asm volatile (".chip 68k");
 
+	set_fs(old_fs); 
+
 	return mmusr;
 }
 
@@ -267,7 +278,9 @@
 				   unsigned long wbd)
 {
 	int res = 0;
+	mm_segment_t old_fs = get_fs();
 
+	/* set_fs can not be moved, otherwise put_user() may oops */
 	set_fs(MAKE_MM_SEG(wbs));
 
 	switch (wbs & WBSIZ_040) {
@@ -282,6 +295,10 @@
 		break;
 	}
 
+	/* set_fs can not be moved, otherwise put_user() may oops */
+	set_fs(old_fs); 
+	
+
 #ifdef DEBUG
 	printk("do_040writeback1, res=%d\n",res);
 #endif
@@ -293,10 +310,12 @@
  * to that exception is discarded, set a few bits in the old frame 
  * to simulate what it should look like
  */
-static inline void fix_xframe040(struct frame *fp, unsigned short wbs)
+static inline void fix_xframe040(struct frame *fp, unsigned long wba, unsigned short wbs)
 {
-	fp->un.fmt7.faddr = current->thread.faddr;
+	fp->un.fmt7.faddr = wba;
 	fp->un.fmt7.ssw = wbs & 0xff;
+	if (wba != current->thread.faddr)
+	    fp->un.fmt7.ssw |= MA_040;
 }
 
 static inline void do_040writebacks(struct frame *fp)
@@ -312,7 +331,7 @@
 		res = do_040writeback1(fp->un.fmt7.wb2s, fp->un.fmt7.wb2a,
 				       fp->un.fmt7.wb2d);
 		if (res)
-			fix_xframe040(fp, fp->un.fmt7.wb2s);
+			fix_xframe040(fp, fp->un.fmt7.wb2a, fp->un.fmt7.wb2s);
 		else 
 			fp->un.fmt7.wb2s = 0;
 	}
@@ -322,7 +341,14 @@
 		res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a,
 				       fp->un.fmt7.wb3d);
 		if (res)
-			fix_xframe040(fp, fp->un.fmt7.wb3s);
+		    {
+			fix_xframe040(fp, fp->un.fmt7.wb3a, fp->un.fmt7.wb3s);
+
+			fp->un.fmt7.wb2s = fp->un.fmt7.wb3s;
+			fp->un.fmt7.wb3s &= (~WBV_040);
+			fp->un.fmt7.wb2a = fp->un.fmt7.wb3a;
+			fp->un.fmt7.wb2d = fp->un.fmt7.wb3d;
+		    }
 		else
 			fp->un.fmt7.wb3s = 0;
 	}
@@ -339,19 +365,15 @@
  */
 asmlinkage void berr_040cleanup(struct frame *fp)
 {
-	mm_segment_t old_fs = get_fs();
-
 	fp->un.fmt7.wb2s &= ~4;
 	fp->un.fmt7.wb3s &= ~4;
 
 	do_040writebacks(fp);
-	set_fs(old_fs);
 }
 
 static inline void access_error040(struct frame *fp)
 {
 	unsigned short ssw = fp->un.fmt7.ssw;
-	mm_segment_t old_fs = get_fs();
 	unsigned long mmusr;
 
 #ifdef DEBUG
@@ -374,9 +396,8 @@
 		if (ssw & MA_040)
 			addr = (addr + 7) & -8;
 
-		set_fs(MAKE_MM_SEG(ssw));
 		/* MMU error, get the MMUSR info for this access */
-		mmusr = probe040(!(ssw & RW_040), addr);
+		mmusr = probe040(!(ssw & RW_040), addr, ssw);
 #ifdef DEBUG
 		printk("mmusr = %lx\n", mmusr);
 #endif
@@ -386,8 +407,12 @@
 			__flush_tlb040_one(addr);
 			errorcode = 0;
 		}
-		if (!(ssw & RW_040))
+
+		/* despite what documentation seems to say, RMW 
+		 * accesses have always both the LK and RW bits set */
+		if (!(ssw & RW_040) || (ssw & LK_040))
 			errorcode |= 2;
+
 		if (do_page_fault(&fp->ptregs, addr, errorcode)) {
 #ifdef DEBUG
 		        printk("do_page_fault() !=0 \n");
@@ -415,7 +440,6 @@
 	}
 
 	do_040writebacks(fp);
-	set_fs(old_fs);
 }
 #endif /* CONFIG_M68040 */
 
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/mac/config.c linux/arch/m68k/mac/config.c
--- v2.4.5/linux/arch/m68k/mac/config.c	Sun Dec  3 17:48:19 2000
+++ linux/arch/m68k/mac/config.c	Mon Jun 11 19:15:27 2001
@@ -13,7 +13,6 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/mm.h>
-#include <linux/kd.h>
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/interrupt.h>
@@ -31,6 +30,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
+#include <asm/rtc.h>
 #include <asm/machdep.h>
 
 #include <asm/macintosh.h>
@@ -78,8 +78,6 @@
 
 extern void (*kd_mksound)(unsigned int, unsigned int);
 extern void mac_mksound(unsigned int, unsigned int);
-extern int mac_floppy_init(void);
-extern void mac_floppy_setup(char *,int *);
 
 extern void nubus_sweep_video(void);
 
@@ -122,8 +120,6 @@
 }
 #endif
 
-extern struct fb_info *mac_fb_init(long *);
-
 extern void mac_default_handler(int, void *, struct pt_regs *);
 
 void (*mac_handlers[8])(int, void *, struct pt_regs *)=
@@ -387,8 +383,7 @@
 	{	MAC_MODEL_P460,  "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD, 	MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_P475,  "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
 	{	MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
-	{	MAC_MODEL_P520,  "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-
+	{	MAC_MODEL_P520,  "Performa 520", MAC_ADB_CUDA, MAC_VIA_IIci,   MAC_SCSI_OLD,    MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_P550,  "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci,   MAC_SCSI_OLD,    MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_P575,  "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
 	/* These have the comm slot, and therefore the possibility of SONIC ethernet */
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/mac/debug.c linux/arch/m68k/mac/debug.c
--- v2.4.5/linux/arch/m68k/mac/debug.c	Thu Oct 12 14:20:48 2000
+++ linux/arch/m68k/mac/debug.c	Mon Jun 11 19:15:27 2001
@@ -187,7 +187,7 @@
 
 
 
-/* Mac: loops_per_sec min. 1900000 ^= .5 us; MFPDELAY was 0.6 us*/
+/* Mac: loops_per_jiffy min. 19000 ^= .5 us; MFPDELAY was 0.6 us*/
 
 #define uSEC 1
 
@@ -286,9 +286,9 @@
 		barrier();				\
     } while(0)
 
-/* loops_per_sec isn't initialized yet, so we can't use udelay(). This does a
+/* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a
  * delay of ~ 60us. */
-/* Mac: loops_per_sec min. 1900000 ^= .5 us; MFPDELAY was 0.6 us*/
+/* Mac: loops_per_jiffy min. 19000 ^= .5 us; MFPDELAY was 0.6 us*/
 #define LONG_DELAY()				\
     do {					\
 	int i;					\
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/mac/iop.c linux/arch/m68k/mac/iop.c
--- v2.4.5/linux/arch/m68k/mac/iop.c	Sun Feb 13 11:21:42 2000
+++ linux/arch/m68k/mac/iop.c	Mon Jun 11 19:15:27 2001
@@ -51,9 +51,6 @@
  *   IOP hasn't died.
  * o Some of the IOP manager routines need better error checking and
  *   return codes. Nothing major, just prettying up.
- *
- * + share the stuff you were smoking when you wrote the iop_get_proc_info()
- *   for case when CONFIG_PROC_FS is undefined.
  */
 
 /*
@@ -129,9 +126,6 @@
 
 #ifdef CONFIG_PROC_FS
 static int iop_get_proc_info(char *, char **, off_t, int);
-#else
-/* What the bloody hell is THAT ??? */
-static int iop_get_proc_info(char *, char **, off_t, int) {}
 #endif /* CONFIG_PROC_FS */
 
 /* structure for tracking channel listeners */
@@ -307,7 +301,11 @@
 		iop_listeners[IOP_NUM_ISM][i].handler = NULL;
 	}
 
-	create_proc_info_entry("mac_iop",0,0,iop_get_proc_info);
+#if 0	/* Crashing in 2.4 now, not yet sure why.   --jmt */
+#ifdef CONFIG_PROC_FS
+	create_proc_info_entry("mac_iop", 0, &proc_root, iop_get_proc_info);
+#endif
+#endif
 }
 
 /*
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/mac/macints.c linux/arch/m68k/mac/macints.c
--- v2.4.5/linux/arch/m68k/mac/macints.c	Sun Dec  3 17:48:19 2000
+++ linux/arch/m68k/mac/macints.c	Mon Jun 11 19:15:27 2001
@@ -129,9 +129,13 @@
 #include <asm/macintosh.h>
 #include <asm/mac_via.h>
 #include <asm/mac_psc.h>
+#include <asm/hwtest.h>
 
 #include <asm/macints.h>
 
+#define DEBUG_SPURIOUS
+#define SHUTUP_SONIC
+
 /*
  * The mac_irq_list array is an array of linked lists of irq_node_t nodes.
  * Each node contains one handler to be called whenever the interrupt
@@ -233,6 +237,17 @@
 
 	scc_mask = 0;
 
+	/* Make sure the SONIC interrupt is cleared or things get ugly */
+#ifdef SHUTUP_SONIC
+	printk("Killing onboard sonic... ");
+	/* This address should hopefully be mapped already */
+	if (hwreg_present((void*)(0x50f0a000))) {
+		*(long *)(0x50f0a014) = 0x7fffL;
+		*(long *)(0x50f0a010) = 0L;
+	}
+	printk("Done.\n");
+#endif /* SHUTUP_SONIC */
+
 	/* 
 	 * Now register the handlers for the the master IRQ handlers
 	 * at levels 1-7. Most of the work is done elsewhere.
@@ -627,9 +642,7 @@
 void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
 #ifdef DEBUG_SPURIOUS
-	if (console_loglevel > 6) {
-		printk("Unexpected IRQ %d on device %p\n", irq, dev_id);
-	}
+	printk("Unexpected IRQ %d on device %p\n", irq, dev_id);
 #endif
 }
 
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/mac/misc.c linux/arch/m68k/mac/misc.c
--- v2.4.5/linux/arch/m68k/mac/misc.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/m68k/mac/misc.c	Mon Jun 11 19:15:27 2001
@@ -2,7 +2,6 @@
  * Miscellaneous Mac68K-specific stuff 
  */
 
-#include <stdarg.h>
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -12,7 +11,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/time.h>
-#include <linux/kd.h>
+
 #include <linux/mm.h>
 
 #include <linux/adb.h>
@@ -21,6 +20,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
+#include <asm/rtc.h>
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/setup.h>
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/mac/psc.c linux/arch/m68k/mac/psc.c
--- v2.4.5/linux/arch/m68k/mac/psc.c	Sun Dec  3 17:48:19 2000
+++ linux/arch/m68k/mac/psc.c	Mon Jun 11 19:15:27 2001
@@ -139,7 +139,6 @@
 	int irq_bit,i;
 	unsigned char events;
 
-	irq -= VEC_SPUR;
 	base_irq = irq << 3;
 
 #ifdef DEBUG_IRQS
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/mac/via.c linux/arch/m68k/mac/via.c
--- v2.4.5/linux/arch/m68k/mac/via.c	Sun Dec  3 17:45:20 2000
+++ linux/arch/m68k/mac/via.c	Mon Jun 11 19:15:27 2001
@@ -410,8 +410,6 @@
 	int irq_bit, i;
 	unsigned char events, mask;
 
-	irq -= VEC_SPUR;
-
 	mask = via1[vIER] & 0x7F;
 	if (!(events = via1[vIFR] & mask)) return;
 
@@ -423,6 +421,7 @@
 			via1[vIER] = irq_bit | 0x80;
 		}
 
+#if 0 /* freakin' pmu is doing weird stuff */
 	if (!oss_present) {
 		/* This (still) seems to be necessary to get IDE
 		   working.  However, if you enable VBL interrupts,
@@ -435,14 +434,13 @@
 		mac_do_irq_list(IRQ_MAC_NUBUS, regs);
 		via_irq_enable(IRQ_MAC_NUBUS);
 	}
+#endif
 }
 
 void via2_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
 	int irq_bit, i;
 	unsigned char events, mask;
-
-	irq -= VEC_SPUR;
 
 	mask = via2[gIER] & 0x7F;
 	if (!(events = via2[gIFR] & mask)) return;
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/math-emu/multi_arith.h linux/arch/m68k/math-emu/multi_arith.h
--- v2.4.5/linux/arch/m68k/math-emu/multi_arith.h	Sun Aug 15 11:47:29 1999
+++ linux/arch/m68k/math-emu/multi_arith.h	Mon Jun 11 19:15:27 2001
@@ -329,7 +329,7 @@
 	int carry;
 
 	/* we assume here, gcc only insert move and a clr instr */
-	asm volatile ("add.b %1,%0" : "=d,=g" (dest->lowmant)
+	asm volatile ("add.b %1,%0" : "=d,g" (dest->lowmant)
 		: "g,d" (src->lowmant), "0,0" (dest->lowmant));
 	asm volatile ("addx.l %1,%0" : "=d" (dest->mant.m32[1])
 		: "d" (src->mant.m32[1]), "0" (dest->mant.m32[1]));
@@ -360,7 +360,7 @@
 extern inline void fp_submant(struct fp_ext *dest, struct fp_ext *src1, struct fp_ext *src2)
 {
 	/* we assume here, gcc only insert move and a clr instr */
-	asm volatile ("sub.b %1,%0" : "=d,=g" (dest->lowmant)
+	asm volatile ("sub.b %1,%0" : "=d,g" (dest->lowmant)
 		: "g,d" (src2->lowmant), "0,0" (src1->lowmant));
 	asm volatile ("subx.l %1,%0" : "=d" (dest->mant.m32[1])
 		: "d" (src2->mant.m32[1]), "0" (src1->mant.m32[1]));
@@ -383,7 +383,7 @@
 })
 #define fp_addx96(dest, src) ({						\
 	/* we assume here, gcc only insert move and a clr instr */	\
-	asm volatile ("add.l %1,%0" : "=d,=g" (dest->m32[2])		\
+	asm volatile ("add.l %1,%0" : "=d,g" (dest->m32[2])		\
 		: "g,d" (temp.m32[1]), "0,0" (dest->m32[2]));		\
 	asm volatile ("addx.l %1,%0" : "=d" (dest->m32[1])		\
 		: "d" (temp.m32[0]), "0" (dest->m32[1]));		\
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- v2.4.5/linux/arch/m68k/mm/init.c	Mon Oct 16 12:58:51 2000
+++ linux/arch/m68k/mm/init.c	Mon Jun 11 19:15:27 2001
@@ -32,11 +32,7 @@
 #include <asm/atari_stram.h>
 #endif
 
-static unsigned long totalram_pages;
-
-#ifdef CONFIG_SUN3
-void mmu_emu_reserve_pages(unsigned long max_page);
-#endif
+unsigned long totalram_pages = 0;
 
 int do_check_pgt_cache(int low, int high)
 {
@@ -86,7 +82,7 @@
 void show_mem(void)
 {
     unsigned long i;
-    int free = 0, total = 0, reserved = 0, nonshared = 0, shared = 0;
+    int free = 0, total = 0, reserved = 0, shared = 0;
     int cached = 0;
 
     printk("\nMem-info:\n");
@@ -101,15 +97,12 @@
 	    cached++;
 	else if (!page_count(mem_map+i))
 	    free++;
-	else if (page_count(mem_map+i) == 1)
-	    nonshared++;
 	else
 	    shared += page_count(mem_map+i) - 1;
     }
     printk("%d pages of RAM\n",total);
     printk("%d free pages\n",free);
     printk("%d reserved pages\n",reserved);
-    printk("%d pages nonshared\n",nonshared);
     printk("%d pages shared\n",shared);
     printk("%d pages swap cached\n",cached);
     printk("%ld pages in page table cache\n",pgtable_cache_size);
@@ -137,17 +130,11 @@
 
 #ifdef CONFIG_ATARI
 	if (MACH_IS_ATARI)
-		atari_stram_reserve_pages( start_mem );
-#endif
-
-#ifdef CONFIG_SUN3
-	/* reserve rom pages */
-	mmu_emu_reserve_pages(max_mapnr);
+		atari_stram_mem_init_hook();
 #endif
 
 	/* this will put all memory onto the freelists */
 	totalram_pages = free_all_bootmem();
-	printk("tp:%ld\n", totalram_pages);
 
 	for (tmp = PAGE_OFFSET ; tmp < (unsigned long)high_memory; tmp += PAGE_SIZE) {
 #if 0
@@ -201,13 +188,15 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
+	int pages = 0;
 	for (; start < end; start += PAGE_SIZE) {
 		ClearPageReserved(virt_to_page(start));
 		set_page_count(virt_to_page(start), 1);
 		free_page(start);
 		totalram_pages++;
+		pages++;
 	}
-	printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+	printk ("Freeing initrd memory: %dk freed\n", pages);
 }
 #endif
 
@@ -220,15 +209,8 @@
     val->sharedram = 0;
     val->freeram = nr_free_pages();
     val->bufferram = atomic_read(&buffermem_pages);
-    while (i-- > 0) {
-	if (PageReserved(mem_map+i))
-	    continue;
-	val->totalram++;
-	if (!page_count(mem_map+i))
-	    continue;
-	val->sharedram += page_count(mem_map+i) - 1;
-    }
     val->totalhigh = 0;
     val->freehigh = 0;
+    val->mem_unit = PAGE_SIZE;
     return;
 }
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c
--- v2.4.5/linux/arch/m68k/mm/memory.c	Sat May 19 17:43:05 2001
+++ linux/arch/m68k/mm/memory.c	Mon Jun 11 19:15:27 2001
@@ -39,6 +39,7 @@
 	pgd_set(pgd, (pmd_t *)BAD_PAGETABLE);
 }
 
+#if 0
 pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
 {
 	pte_t *pte;
@@ -63,7 +64,9 @@
 	}
 	return (pte_t *)__pmd_page(*pmd) + offset;
 }
+#endif
 
+#if 0
 pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
 {
 	pmd_t *pmd;
@@ -84,7 +87,7 @@
 	}
 	return (pmd_t *)__pgd_page(*pgd) + offset;
 }
-
+#endif
 
 /* ++andreas: {get,free}_pointer_table rewritten to use unused fields from
    struct page instead of separately kmalloced struct.  Stolen from
@@ -250,6 +253,10 @@
 	if (voff == 0)
 		return m68k_memory[i-1].addr + m68k_memory[i-1].size;
 
+	/* As a special case allow `__pa(high_memory)'.  */
+	if (voff == 0)
+		return m68k_memory[i-1].addr + m68k_memory[i-1].size;
+
 	return mm_vtop_fallback(vaddr);
 }
 #endif
@@ -454,16 +461,21 @@
 			      ".chip 68k"		\
 			      : : "a" (paddr))
 
-/* push and invalidate page in both caches */
+/* push and invalidate page in both caches, must disable ints
+ * to avoid invalidating valid data */
 #define	pushcl040(paddr)			\
-	do { push040(paddr);			\
+	do { unsigned long flags;               \
+             save_flags(flags);                 \
+	     cli();                             \
+             push040(paddr);			\
 	     if (CPU_IS_060) clear040(paddr);	\
+	     restore_flags(flags);              \
 	} while(0)
 
 /* push page in both caches, invalidate in i-cache */
+/* RZ: cpush %bc DOES invalidate %ic, regardless of DPI */
 #define	pushcli040(paddr)			\
 	do { push040(paddr);			\
-	     if (CPU_IS_060) cleari040(paddr);	\
 	} while(0)
 
 
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/mvme147/config.c linux/arch/m68k/mvme147/config.c
--- v2.4.5/linux/arch/m68k/mvme147/config.c	Mon Nov 27 17:11:26 2000
+++ linux/arch/m68k/mvme147/config.c	Mon Jun 11 19:15:27 2001
@@ -16,7 +16,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/kd.h>
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/linkage.h>
@@ -29,6 +28,7 @@
 #include <asm/setup.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
+#include <asm/rtc.h>
 #include <asm/machdep.h>
 #include <asm/mvme147hw.h>
 
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/mvme16x/config.c linux/arch/m68k/mvme16x/config.c
--- v2.4.5/linux/arch/m68k/mvme16x/config.c	Mon Jan 31 10:32:53 2000
+++ linux/arch/m68k/mvme16x/config.c	Mon Jun 11 19:15:27 2001
@@ -17,7 +17,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/kd.h>
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/linkage.h>
@@ -30,11 +29,10 @@
 #include <asm/setup.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
+#include <asm/rtc.h>
 #include <asm/machdep.h>
 #include <asm/mvme16xhw.h>
 
-int atari_SCC_reset_done = 1;		/* So SCC doesn't get reset */
-u_long atari_mch_cookie = 0;
 extern t_bdid mvme_bdid;
 
 static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE;
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/mvme16x/rtc.c linux/arch/m68k/mvme16x/rtc.c
--- v2.4.5/linux/arch/m68k/mvme16x/rtc.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/m68k/mvme16x/rtc.c	Mon Jun 11 19:15:27 2001
@@ -72,7 +72,7 @@
 		unsigned char mon, day, hrs, min, sec, leap_yr;
 		unsigned int yrs;
 
-		if (!suser())
+		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
 
 		if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/q40/README linux/arch/m68k/q40/README
--- v2.4.5/linux/arch/m68k/q40/README	Tue Mar  6 19:44:36 2001
+++ linux/arch/m68k/q40/README	Mon Jun 11 19:15:27 2001
@@ -3,43 +3,48 @@
 
 You may try http://www.geocities.com/SiliconValley/Bay/2602/ for
 some up to date information. Booter and other tools will be also
-available from this place and ftp.uni-erlangen.de/linux/680x0/q40/
+available from this place or ftp.uni-erlangen.de/linux/680x0/q40/
 and mirrors.
 
 Hints to documentation usually refer to the linux source tree in
 /usr/src/linux/Documentation unless URL given.
 
-It seems IRQ unmasking can't be safely done on a Q40. Autoprobing is 
-not yet implemented - do not try it! (See below)
+It seems IRQ unmasking can't be safely done on a Q40. IRQ probing 
+is not implemented - do not try it! (See below)
 
-For a list of kernel commandline options read the documentation for the
+For a list of kernel command-line options read the documentation for the
 particular device drivers.
 
 The floppy imposes a very high interrupt load on the CPU, approx 30K/s.
 When something blocks interrupts (HD) it will loose some of them, so far 
-this is not known to have caused any data loss. On hihgly loaded systems
-it can make the floppy very slow or practicaly stop. Other Q40 OS' simply 
+this is not known to have caused any data loss. On highly loaded systems
+it can make the floppy very slow or practically stop. Other Q40 OS' simply 
 poll the floppy for this reason - something that can't be done in Linux.
-Only possible cure is getting a 82072 contoler with fifo instead of 
-the 8272A
+Only possible cure is getting a 82072 controller with fifo instead of 
+the 8272A.
 
-drivers used by the Q40, appart from the very obvious (console etc.):
+drivers used by the Q40, apart from the very obvious (console etc.):
 	drivers/char/q40_keyb.c		# use PC keymaps for national keyboards
 		     serial.c		# normal PC driver - any speed
 	             lp.c		# printer driver
-		char/joystick/*		# most of this should work
+		     genrtc.c		# RTC
+		char/joystick/*		# most of this should work, not 
+				        # in default config.in
 	        block/q40ide.c		# startup for ide
 		      ide*		# see Documentation/ide.txt
 		      floppy.c		# normal PC driver, DMA emu in asm/floppy.h
 					# and arch/m68k/kernel/entry.S
 					# see drivers/block/README.fd
+		net/ne.c
 		video/q40fb.c
-		misc/parport_pc.c
+		parport/*
+		sound/dmasound_core.c
+		      dmasound_q40.c
 
 Various other PC drivers can be enabled simply by adding them to 
 arch/m68k/config.in, especially 8 bit devices should be without any
 problems. For cards using 16bit io/mem more care is required, like 
-checking byteorder issues, hacking memcpy_*_io etc.
+checking byte order issues, hacking memcpy_*_io etc.
 
 
 Debugging
@@ -47,7 +52,7 @@
 
 Upon startup the kernel will usually output "ABCQGHIJ" into the SRAM, 
 preceded by the booter signature. This is a trace just in case something 
-went wrong during earliest setup stages. 
+went wrong during earliest setup stages of head.S. 
 **Changed** to preserve SRAM contents by default, this is only done when 
 requested - SRAM must start with '%LX$' signature to do this. '-d' option 
 to 'lxx' loader enables this.
@@ -55,13 +60,15 @@
 SRAM can also be used as additional console device, use debug=mem.
 This will save kernel startup msgs into SRAM, the screen will display 
 only the penguin - and shell prompt if it gets that far..
+Unfortunately only 2000 bytes are available.
 
 Serial console works and can also be used for debugging, see loader_txt
 
 Most problems seem to be caused by fawlty or badly configured io-cards or 
-harddrives anyway..there are so many things that can go wrong here.
-Make sure to configure the parallel port as SPP for first testing..the
-Q40 may have trouble with parallel interrupts.
+hard drives anyway.
+Make sure to configure the parallel port as SPP and remove IRQ/DMA jumpers
+for first testing. The Q40 does not support DMA and may have trouble with
+parallel ports version of interrupts.
 
 
 Q40 Hardware Description
@@ -71,30 +78,27 @@
 questions.
 
 The Q40 consists of a 68040@40 MHz, 1MB video RAM, up to 32MB RAM, AT-style
-keyboard interface, 1 Programmable LED, 2 8bit DACs and up to 1MB ROM, 1MB
+keyboard interface, 1 Programmable LED, 2x8bit DACs and up to 1MB ROM, 1MB
 shadow ROM.
+The Q60 has any of 68060 or 68LC060 and up to 128 MB RAM.
 
-Most interfacing like floppy, hd, serial, parallel ports is done via ISA 
+Most interfacing like floppy, IDE, serial and parallel ports is done via ISA 
 slots. The ISA io and mem range is mapped (sparse&byteswapped!) into separate 
 regions of the memory.
 The main interrupt register IIRQ_REG will indicate whether an IRQ was internal 
 or from some ISA devices, EIRQ_REG can distinguish up to 8 ISA IRQs.
 
 The Q40 custom chip is programmable to provide 2 periodic timers:
-	- 50 or 200 Hz - level 2,
-	- 10 or 20 KHz - level 4 
-  !!THIS CANT BE DISABLED!!
-
+	- 50 or 200 Hz - level 2, !!THIS CANT BE DISABLED!!
+	- 10 or 20 KHz - level 4, used for dma-sound 
+  
 Linux uses the 200 Hz interrupt for timer and beep by default.
 
 
 Interrupts
 ==========
 
-q40 master chip handles only level triggered interrupts :-((
-
-IRQ sharing is not yet implemented but this should be only a minor
-problem..
+q40 master chip handles only a subset of level triggered interrupts.
 
 Linux has some requirements wrt interrupt architecture, these are
 to my knowledge:
@@ -103,27 +107,28 @@
 	(b) working enable/disable_irq
 
 Luckily these requirements are only important for drivers shared
-with other architectures - ide,serial,parallel, ethernet..
+with other architectures - ide,serial,parallel, ethernet.
 q40ints.c now contains a trivial hack for (a), (b) is more difficult
-because only irq's 4-15 can be disabled - and only all o them at once.
+because only irq's 4-15 can be disabled - and only all of them at once.
 Thus disable_irq() can effectively block the machine if the driver goes
 asleep.
-One thing to keep in minde when hacking around the interrupt code is 
-that there is no way to find out which IRQ caused a request.
+One thing to keep in mind when hacking around the interrupt code is 
+that there is no way to find out which IRQ caused a request, [EI]IRQ_REG
+displays current state of the various IRQ lines.
 
 Keyboard
 ========
 
 q40 receives AT make/break codes from the keyboard, these are translated to
 the PC scancodes x86 Linux uses. So by theory every national keyboard should
-work just by loading the apropriate x86 keytable - see any national-HOWTO.
+work just by loading the appropriate x86 keytable - see any national-HOWTO.
 
 Unfortunately the AT->PC translation isn't quite trivial and even worse, my 
 documentation of it is absolutely minimal - thus some exotic keys may not 
 behave exactly as expected.
 
 There is still hope that it can be fixed completely though. If you encounter 
-problems, email me idealy this:
+problems, email me ideally this:
 	- exact keypress/release sequence
 	- 'showkey -s' run on q40, non-X session
 	- 'showkey -s' run on a PC, non-X session
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/q40/config.c linux/arch/m68k/q40/config.c
--- v2.4.5/linux/arch/m68k/q40/config.c	Fri Apr  6 10:42:48 2001
+++ linux/arch/m68k/q40/config.c	Mon Jun 11 19:15:27 2001
@@ -13,11 +13,9 @@
  */
 
 #include <linux/config.h>
-#include <stdarg.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/kd.h>
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/linkage.h>
@@ -25,6 +23,7 @@
 #include <linux/major.h>
 #include <linux/serial_reg.h>
 
+#include <asm/io.h>
 #include <asm/rtc.h>
 #include <asm/bootinfo.h>
 #include <asm/system.h>
@@ -32,6 +31,7 @@
 #include <asm/setup.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
+#include <asm/rtc.h>
 #include <asm/machdep.h>
 #include <asm/q40_master.h>
 #include <asm/keyboard.h>
@@ -39,6 +39,8 @@
 extern void floppy_eject(void);
 extern void floppy_setup(char *str, int *ints);
 
+extern int q40kbd_translate(unsigned char scancode, unsigned char *keycode,
+			    char raw_mode);
 extern void q40_process_int (int level, struct pt_regs *regs);
 extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *);  /* added just for debugging */
 extern void q40_init_IRQ (void);
@@ -50,16 +52,17 @@
 static int  q40_get_hardware_list(char *buffer);
 extern int  q40_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
 extern void q40_sched_init(void (*handler)(int, void *, struct pt_regs *));
-extern int  q40_keyb_init(void);
-extern int  q40_kbdrate (struct kbd_repeat *);
+
 extern unsigned long q40_gettimeoffset (void);
 extern void q40_gettod (int *year, int *mon, int *day, int *hour,
                            int *min, int *sec);
 extern int q40_hwclk (int, struct hwclk_time *);
 extern int q40_set_clock_mmss (unsigned long);
 extern void q40_reset (void);
+void q40_halt(void);
 extern void q40_waitbut(void);
 void q40_set_vectors (void);
+
 extern void (*kd_mksound)(unsigned int, unsigned int);
 void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ );
 
@@ -67,16 +70,9 @@
 extern char m68k_debug_device[];
 static void q40_mem_console_write(struct console *co, const char *b,
 				    unsigned int count);
-#if 0
-extern int ql_ticks=0;
-extern int sound_ticks=0;
-#endif
 
 extern int ql_ticks;
 
-static unsigned char bcd2bin (unsigned char b);
-static unsigned char bin2bcd (unsigned char b);
-
 static int q40_wait_key(struct console *co){return 0;}
 static struct console q40_console_driver = {
 	name:		"debug",
@@ -90,11 +86,13 @@
 extern char *q40_mem_cptr; /*=(char *)0xff020000;*/
 static int _cpleft;
 
+#if 0
 int q40_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
 {
         *keycodep = keycode;
         return 1;
 }
+#endif
 
 static void q40_mem_console_write(struct console *co, const char *s,
 				  unsigned int count)
@@ -130,13 +128,36 @@
 }
 #endif
 
-void q40_reset()
+static int halted=0;
+
+#ifdef CONFIG_HEARTBEAT
+static void q40_heartbeat(int on)
 {
+  if (halted) return;
 
+  if (on)
+    Q40_LED_ON();
+  else
+    Q40_LED_OFF();
+}
+#endif
+
+void q40_reset()
+{
+        halted=1;
         printk ("\n\n*******************************************\n"
 		"Called q40_reset : press the RESET button!! \n"
 		"*******************************************\n");
-	
+	Q40_LED_ON();
+	while(1) ;
+}
+void q40_halt()
+{
+        halted=1;
+        printk ("\n\n*******************\n"
+		    "  Called q40_halt\n"
+		    "*******************\n");
+	Q40_LED_ON();
 	while(1) ;
 }
 
@@ -202,17 +223,17 @@
 
 void __init config_q40(void)
 {
-    mach_sched_init      = q40_sched_init;           /* ok */
-    /*mach_kbdrate         = q40_kbdrate;*/          /* unneeded ?*/
-    mach_keyb_init       = q40_keyb_init;            /* OK */
-    mach_kbd_translate   = q40_kbd_translate;
+    mach_sched_init      = q40_sched_init;
+
+    mach_keyb_init       = q40kbd_init_hw;
+    mach_kbd_translate   = q40kbd_translate;
     mach_init_IRQ        = q40_init_IRQ;   
     mach_gettimeoffset   = q40_gettimeoffset; 
     mach_gettod  	 = q40_gettod;
     mach_hwclk           = q40_hwclk; 
     mach_set_clock_mmss	 = q40_set_clock_mmss;
-/*  mach_mksound         = q40_mksound; */
-    mach_reset		 = q40_reset;           /* use reset button instead !*/
+
+    mach_reset		 = q40_reset;
     mach_free_irq	 = q40_free_irq; 
     mach_process_int	 = q40_process_int;
     mach_get_irq_list	 = q40_get_irq_list;
@@ -220,26 +241,28 @@
     enable_irq		 = q40_enable_irq;
     disable_irq          = q40_disable_irq;
     mach_default_handler = &q40_sys_default_handler;
-    mach_get_model       = q40_get_model; /* no use..*/
-    mach_get_hardware_list = q40_get_hardware_list; /* no use */
+    mach_get_model       = q40_get_model;
+    mach_get_hardware_list = q40_get_hardware_list;
     kd_mksound             = q40_mksound;
-    /*mach_kbd_leds        = q40kbd_leds;*/
+
 #ifdef CONFIG_MAGIC_SYSRQ
     mach_sysrq_key       = 0x54;
 #endif
-    conswitchp = &dummy_con;
-#if 0 /*def CONFIG_BLK_DEV_FD*/
-    mach_floppy_setup    = floppy_setup;
-    mach_floppy_eject    = floppy_eject;
-    /**/
+#ifdef CONFIG_HEARTBEAT
+    mach_heartbeat = q40_heartbeat;
 #endif
+    mach_halt = q40_halt;
+    conswitchp = &dummy_con;
 
+    /* disable a few things that SMSQ might have left enabled */
     q40_disable_irqs();
-    mach_max_dma_address = 32*1024*1024;   /* no DMA at all, but ide-scsi requires it.. */
 
+    /* no DMA at all, but ide-scsi requires it.. make sure
+     * all physical RAM fits into the boundary - otherwise 
+     * allocator may play costly and useless tricks */
+    mach_max_dma_address = 1024*1024*1024;   
 
-/* useful for early debugging stages - writes kernel messages into SRAM */
-
+    /* useful for early debugging stages - writes kernel messages into SRAM */
     if (!strncmp( m68k_debug_device,"mem",3 ))
       {
 	/*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/
@@ -252,109 +275,24 @@
 
 int q40_parse_bootinfo(const struct bi_record *rec)
 {
-  return 1;  /* unknown */
+  return 1;
 }
 
-#if 0
-#define DAC_LEFT  ((unsigned char *)0xff008000)
-#define DAC_RIGHT ((unsigned char *)0xff008004)
-void q40_mksound(unsigned int hz, unsigned int ticks)
-{
-  /* for now ignore hz, except that hz==0 switches off sound */
-  /* simply alternate the ampl 0-255-0-.. at 200Hz */
-  if (hz==0)
-    {
-      if (sound_ticks)
-	sound_ticks=1; /* atomic - no irq spinlock used */
-
-      *DAC_LEFT=0;
-      *DAC_RIGHT=0;
 
-      return;
-    }
-  /* sound itself is done in q40_timer_int */
-  if (sound_ticks == 0) sound_ticks=1000; /* pretty long beep */
-  sound_ticks=ticks<<1;
-}
-
-static void (*q40_timer_routine)(int, void *, struct pt_regs *);
-static short rtc_oldsecs=0;
-unsigned rtc_irq_flags=0;
-unsigned rtc_irq_ctrl=0;
-
-static void q40_timer_int (int irq, void *dev_id, struct pt_regs *fp)
-{
-#if (HZ==10000)
-    master_outb(-1,SAMPLE_CLEAR_REG);
-#else /* must be 50 or 100 */
-    master_outb(-1,FRAME_CLEAR_REG);
-#endif
-
-#if (HZ==100)
-    ql_ticks = ql_ticks ? 0 : 1;
-    if (sound_ticks)
-      {
-	unsigned char sval=(sound_ticks & 1) ? 0 : 255;
-	sound_ticks--;
-	*DAC_LEFT=sval;
-	*DAC_RIGHT=sval;
-      }
-#ifdef CONFIG_Q40RTC
-    if (rtc_irq_ctrl && (rtc_oldsecs != RTC_SECS))
-      {
-	rtc_oldsecs = RTC_SECS;
-	rtc_irq_flags = RTC_UIE;
-	rtc_interrupt();
-      }
-#endif
-    if (ql_ticks) return;
-#endif
-    q40_timer_routine(irq, dev_id, fp);
+static inline unsigned char bcd2bin (unsigned char b)
+{
+	return ((b>>4)*10 + (b&15));
 }
-#endif
 
-#if 0
-extern void (*q40_timer_routine)(int, void *, struct pt_regs *);
-extern void q40_timer_int();
-
-void q40_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
+static inline unsigned char bin2bcd (unsigned char b)
 {
-    int timer_irq;
-
-    q40_timer_routine = timer_routine;
-
-#if (HZ==10000)
-    timer_irq=Q40_IRQ_TIMER;
-#else
-    timer_irq=Q40_IRQ_FRAME;
-#endif
-
-    /*printk("registering sched/timer IRQ %d\n", timer_irq);*/
-
-    if (request_irq(timer_irq, q40_timer_int, 0,
-				"timer", q40_timer_int))
-	panic ("Couldn't register timer int");
-
-#if (HZ==10000)
-    master_outb(SAMPLE_LOW,SAMPLE_RATE_REG);
-    master_outb(-1,SAMPLE_CLEAR_REG);
-    master_outb(1,SAMPLE_ENABLE_REG);
-#else
-    master_outb(-1,FRAME_CLEAR_REG);   /* not necessary ? */
-#if (HZ==100)
-    master_outb( 1,FRAME_RATE_REG);
-#endif
-#endif
+	return (((b/10)*16) + (b%10));
 }
-#endif
+
 
 unsigned long q40_gettimeoffset (void)
 {
-#if (HZ==100)
     return 5000*(ql_ticks!=0);
-#else
-    return 0;
-#endif
 }
 
 extern void q40_gettod (int *year, int *mon, int *day, int *hour,
@@ -362,7 +300,7 @@
 {
 	RTC_CTRL |= RTC_READ;
 	*year = bcd2bin (RTC_YEAR);
-	*mon = bcd2bin (RTC_MNTH)-1;
+	*mon = bcd2bin (RTC_MNTH);
 	*day = bcd2bin (RTC_DATE);
 	*hour = bcd2bin (RTC_HOUR);
 	*min = bcd2bin (RTC_MINS);
@@ -371,15 +309,6 @@
 
 }
 
-static unsigned char bcd2bin (unsigned char b)
-{
-	return ((b>>4)*10 + (b&15));
-}
-
-static unsigned char bin2bcd (unsigned char b)
-{
-	return (((b/10)*16) + (b%10));
-}
 
 
 /*
@@ -439,8 +368,6 @@
 /*
  * Set the minutes and seconds from seconds value 'nowtime'.  Fail if
  * clock is out by > 30 minutes.  Logic lifted from atari code.
- * Algorithm is to wait for the 10ms register to change, and then to
- * wait a short while, and then set it.
  */
 
 int q40_set_clock_mmss (unsigned long nowtime)
@@ -469,18 +396,3 @@
 	return retval;
 }
 
-extern void q40kbd_init_hw(void);
-
-int q40_keyb_init (void)
-{
-        q40kbd_init_hw();
-	return 0;
-}
-
-#if 0
-/* dummy to cause */
-void q40_slow_io()
-{
-  return;
-}
-#endif
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/q40/q40ints.c linux/arch/m68k/q40/q40ints.c
--- v2.4.5/linux/arch/m68k/q40/q40ints.c	Mon Nov 27 17:11:26 2000
+++ linux/arch/m68k/q40/q40ints.c	Mon Jun 11 19:15:27 2001
@@ -1,7 +1,7 @@
 /*
  * arch/m68k/q40/q40ints.c
  *
- * Copyright (C) 1999 Richard Zidlicky
+ * Copyright (C) 1999,2001 Richard Zidlicky
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file COPYING in the main directory of this archive
@@ -44,7 +44,7 @@
 void q40_irq2_handler (int, void *, struct pt_regs *fp);
 
 
-extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *);  /* added just for debugging */
+extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *);
 
 static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp);
 static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs);
@@ -97,9 +97,9 @@
 	sys_request_irq(IRQ2,q40_irq2_handler, 0, "q40 ISA and master chip", NULL);
 
 	/* now enable some ints.. */
-	master_outb(1,EXT_ENABLE_REG);  /* hm, aint that too early? */
+	master_outb(1,EXT_ENABLE_REG);  /* ISA IRQ 5-15 */
 
-	/* would be spurious ints by now, q40kbd_init_hw() does that */
+	/* make sure keyboard IRQ is disabled */
 	master_outb(0,KEY_IRQ_ENABLE_REG);
 }
 
@@ -139,7 +139,7 @@
 	    if (dev_id==NULL)
 		  {
 		printk("WARNING: dev_id == NULL in request_irq\n");
-		dev_id=1;
+		dev_id=(void*)1;
 	      }
 	    irq_tab[irq].handler = handler;
 	    irq_tab[irq].flags   = flags;
@@ -202,7 +202,8 @@
 /* 
  * this stuff doesn't really belong here..
 */
-int ql_ticks=0;
+
+int ql_ticks=0;              /* 200Hz ticks since last jiffie */
 static int sound_ticks=0;
 
 #define SVOL 45
@@ -214,7 +215,7 @@
   if (hz==0)
     {
       if (sound_ticks)
-	sound_ticks=1; /* atomic - no irq spinlock used */
+	sound_ticks=1;
 
       *DAC_LEFT=128;
       *DAC_RIGHT=128;
@@ -227,14 +228,9 @@
 }
 
 static void (*q40_timer_routine)(int, void *, struct pt_regs *);
-static short rtc_oldsecs=0;
-unsigned rtc_irq_flags=0;
-unsigned rtc_irq_ctrl=0;
 
 static void q40_timer_int (int irq, void * dev, struct pt_regs * regs)
 {
-
-  
 #if (HZ==100)
     ql_ticks = ql_ticks ? 0 : 1;
     if (sound_ticks)
@@ -244,12 +240,12 @@
 	*DAC_LEFT=sval;
 	*DAC_RIGHT=sval;
       }
-#ifdef CONFIG_Q40RTC
-    if (rtc_irq_ctrl && (rtc_oldsecs != RTC_SECS))
+#if defined(CONFIG_Q40RTC) || defined(CONFIG_GEN_RTC)
+    if (gen_rtc_irq_ctrl && (q40rtc_oldsecs != RTC_SECS))
       {
-	rtc_oldsecs = RTC_SECS;
-	rtc_irq_flags = RTC_UIE;
-	rtc_interrupt();
+	q40rtc_oldsecs = RTC_SECS;
+	gen_rtc_irq_flags = RTC_UIE;
+	gen_rtc_interrupt(0);
       }
 #endif
     if (ql_ticks) return;
@@ -322,16 +318,14 @@
 static int ccleirq=60;    /* ISA dev IRQ's*/
 /*static int cclirq=60;*/     /* internal */
 
-/* FIX: add shared ints,mask,unmask,probing.... */
-
+/* FIXME: add shared ints,mask,unmask,probing.... */
 
 #define IRQ_INPROGRESS 1
 /*static unsigned short saved_mask;*/
 static int do_tint=0;
 
 #define DEBUG_Q40INT
-#define IP_USE_DISABLE /* would be nice, but crashes ???? */
-/*static int dd_count=0;*/
+/*#define IP_USE_DISABLE *//* would be nice, but crashes ???? */
 
 static int mext_disabled=0;  /* ext irq disabled by master chip? */
 static int aliased_irq=0;  /* how many times inside handler ?*/
@@ -404,40 +398,36 @@
 		    if ( disabled ) 
 		      {
 #ifdef IP_USE_DISABLE
-		  if (irq>4){
-		    disabled=0;
-		    /*dd_count--;*/
-		    enable_irq(irq);}
+			if (irq>4){
+			  disabled=0;
+			  enable_irq(irq);}
 #else
-		  disabled=0;
+			disabled=0;
 			/*printk("reenabling irq %d\n",irq); */
-#if 0
-		  fp->sr = ((fp->sr) & (~0x700)); /* unneeded ?! */
-#endif
 #endif
 		      }
 	      goto repeat;  /* return;  */
 		  }
 	      }
-      if (mer && ccleirq>0 && !aliased_irq) 
+	    if (mer && ccleirq>0 && !aliased_irq) 
 	      printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer),ccleirq--;
 	  } 
  iirq:
-  mir=master_inb(IIRQ_REG);
-  if (mir&IRQ_FRAME_MASK) 
+	mir=master_inb(IIRQ_REG);
+	if (mir&IRQ_FRAME_MASK) 
 	  {
-      do_tint++;
-      master_outb(-1,FRAME_CLEAR_REG);
-    }
-  for(;do_tint>0;do_tint--) 
-	      {
-      irq_tab[Q40_IRQ_FRAME].count++;
-      irq_tab[Q40_IRQ_FRAME].handler(Q40_IRQ_FRAME,irq_tab[Q40_IRQ_FRAME].dev_id,fp);    
-    }
-  if (mir&IRQ_KEYB_MASK) /* may handle it even if actually disabled*/
-		      {
-      irq_tab[Q40_IRQ_KEYBOARD].count++;
-      irq_tab[Q40_IRQ_KEYBOARD].handler(Q40_IRQ_KEYBOARD,irq_tab[Q40_IRQ_KEYBOARD].dev_id,fp);
+	    do_tint++;
+	    master_outb(-1,FRAME_CLEAR_REG);
+	  }
+	for(;do_tint>0;do_tint--) 
+	  {
+	    irq_tab[Q40_IRQ_FRAME].count++;
+	    irq_tab[Q40_IRQ_FRAME].handler(Q40_IRQ_FRAME,irq_tab[Q40_IRQ_FRAME].dev_id,fp);    
+	  }
+	if (mir&IRQ_KEYB_MASK) /* may handle it even if actually disabled*/
+	  {
+	    irq_tab[Q40_IRQ_KEYBOARD].count++;
+	    irq_tab[Q40_IRQ_KEYBOARD].handler(Q40_IRQ_KEYBOARD,irq_tab[Q40_IRQ_KEYBOARD].dev_id,fp);
 	  }
 }
 
@@ -499,7 +489,7 @@
 void q40_disable_irq (unsigned int irq)
 {
   /* disable ISA iqs : only do something if the driver has been
-  * verified to be Q40 "compatible" - right now only IDE
+  * verified to be Q40 "compatible" - right now IDE, NE2K
   * Any driver should not attempt to sleep accross disable_irq !!
   */
 
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3/Makefile linux/arch/m68k/sun3/Makefile
--- v2.4.5/linux/arch/m68k/sun3/Makefile	Fri Dec 29 14:07:20 2000
+++ linux/arch/m68k/sun3/Makefile	Mon Jun 11 19:15:27 2001
@@ -14,7 +14,9 @@
 
 export-objs	:= sun3_ksyms.o
 
-obj-y		:= config.o idprom.o mmu_emu.o sun3ints.o leds.o dvma.o \
-			sbus.o intersil.o sun3_ksyms.o
+obj-y	:= sun3_ksyms.o sun3ints.o sun3dvma.o sbus.o
+
+obj-$(CONFIG_SUN3) += config.o idprom.o mmu_emu.o leds.o dvma.o \
+			intersil.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3/config.c linux/arch/m68k/sun3/config.c
--- v2.4.5/linux/arch/m68k/sun3/config.c	Fri Dec 29 14:07:20 2000
+++ linux/arch/m68k/sun3/config.c	Mon Jun 11 19:15:27 2001
@@ -8,13 +8,10 @@
  * for more details.
  */
 
-#include <stdarg.h>
-
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/kd.h>
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/init.h>
@@ -27,10 +24,12 @@
 #include <asm/pgtable.h>
 #include <asm/sun3-head.h>
 #include <asm/sun3mmu.h>
+#include <asm/rtc.h>
 #include <asm/machdep.h>
 #include <asm/intersil.h>
 #include <asm/irq.h>
 #include <asm/segment.h>
+#include <asm/sun3ints.h>
 
 extern char _text, _end;
 
@@ -39,15 +38,6 @@
 extern unsigned long sun3_gettimeoffset(void);
 extern int sun3_get_irq_list (char *);
 extern void sun3_sched_init(void (*handler)(int, void *, struct pt_regs *));
-extern void sun3_init_IRQ (void);
-extern void (*sun3_default_handler[]) (int, void *, struct pt_regs *);
-extern int sun3_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-                              unsigned long flags, const char *devname, void *dev_id);
-extern void sun3_free_irq (unsigned int irq, void *dev_id);
-extern void sun3_enable_irq (unsigned int);
-extern void sun3_disable_irq (unsigned int);
-extern void sun3_enable_interrupts (void);
-extern void sun3_disable_interrupts (void);
 extern void sun3_get_model (char* model);
 extern void idprom_init (void);
 extern void sun3_gettod (int *yearp, int *monp, int *dayp,
@@ -56,7 +46,7 @@
 
 extern void sun_serial_setup(void);
 volatile char* clock_va; 
-extern unsigned char* sun3_intreg;
+extern volatile unsigned char* sun3_intreg;
 extern unsigned long availmem;
 unsigned long num_pages;
 
@@ -76,7 +66,7 @@
 	prom_init((void *)LINUX_OPPROM_BEGVM);
 		
 	GET_CONTROL_BYTE(AC_SENABLE,enable_register);
-	enable_register |= 0x40; /* Enable FPU */	
+	enable_register |= 0x50; /* Enable FPU */	
 	SET_CONTROL_BYTE(AC_SENABLE,enable_register);
 	GET_CONTROL_BYTE(AC_SENABLE,enable_register);
 	
@@ -154,6 +144,7 @@
 //	mach_keyb_init       =  sun3_keyb_init;
 	enable_irq     	     =  sun3_enable_irq;
         disable_irq  	     =  sun3_disable_irq;
+	mach_process_int     =  sun3_process_int;
         mach_get_irq_list    =  sun3_get_irq_list;
         mach_gettod          =  sun3_gettod;	
         mach_reset           =  sun3_reboot;
@@ -161,7 +152,7 @@
 	mach_get_model	     =  sun3_get_model;
 	mach_hwclk           =  sun3_hwclk;
 	mach_halt	     =  sun3_halt;
-#ifndef CONFIG_SERIAL_CONSOLE
+#if !defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_FB)
 	conswitchp 	     = &dummy_con;
 #endif
 
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3/dvma.c linux/arch/m68k/sun3/dvma.c
--- v2.4.5/linux/arch/m68k/sun3/dvma.c	Fri Dec 29 14:07:20 2000
+++ linux/arch/m68k/sun3/dvma.c	Mon Jun 11 19:15:27 2001
@@ -4,42 +4,62 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/bootmem.h>
+#include <linux/list.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/sun3mmu.h>
 #include <asm/dvma.h>
 
-unsigned long dvma_next_free = DVMA_START;
-unsigned long dvma_region_end = DVMA_START + (DVMA_RESERVED_PMEGS * SUN3_PMEG_SIZE);
 
+static unsigned long ptelist[120];
 
-/* reserve such dma memory as we see fit */
-void sun3_dvma_init(void)
+inline unsigned long dvma_page(unsigned long kaddr, unsigned long vaddr)
 {
-	unsigned long dvma_phys_start;
-	
-	dvma_phys_start = (sun3_get_pte(DVMA_START) & 
-			   SUN3_PAGE_PGNUM_MASK);
-	dvma_phys_start <<= PAGE_SHIFT;
+	unsigned long pte;
+	unsigned long j;
+	pte_t ptep;
 	
-	reserve_bootmem(dvma_phys_start,
-			(DVMA_RESERVED_PMEGS * SUN3_PMEG_SIZE));
+	j = *(volatile unsigned long *)kaddr;
+	*(volatile unsigned long *)kaddr = j;
 
-}
+	ptep = __mk_pte(kaddr, PAGE_KERNEL);
+	pte = pte_val(ptep);
+//		printk("dvma_remap: addr %lx -> %lx pte %08lx len %x\n", 
+//		       kaddr, vaddr, pte, len);
+	if(ptelist[(vaddr & 0xff000) >> PAGE_SHIFT] != pte) {
+		sun3_put_pte(vaddr, pte);
+		ptelist[(vaddr & 0xff000) >> PAGE_SHIFT] = pte;
+	}
 
-/* get needed number of free dma pages, or panic if not enough */
+	return (vaddr + (kaddr & ~PAGE_MASK));
 
-void *sun3_dvma_malloc(int len)
+}
+
+int dvma_map_iommu(unsigned long kaddr, unsigned long baddr, 
+			      int len)
 {
+
+	unsigned long end;
 	unsigned long vaddr;
 
-       	if((dvma_next_free + len) > dvma_region_end) 
-		panic("sun3_dvma_malloc: out of dvma pages");
+	vaddr = dvma_btov(baddr);
+
+	end = vaddr + len;
 	
-	vaddr = dvma_next_free;
-	dvma_next_free = DVMA_ALIGN(dvma_next_free + len);
+	while(vaddr < end) {
+		dvma_page(kaddr, vaddr);
+		kaddr += PAGE_SIZE;
+		vaddr += PAGE_SIZE;
+	}
+
+	return 0;
 
-	return (void *)vaddr;
 }
-     
 
+void sun3_dvma_init(void)
+{
+
+	memset(ptelist, 0, sizeof(ptelist));
+
+
+}
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3/intersil.c linux/arch/m68k/sun3/intersil.c
--- v2.4.5/linux/arch/m68k/sun3/intersil.c	Wed Jan 26 12:44:21 2000
+++ linux/arch/m68k/sun3/intersil.c	Mon Jun 11 19:15:27 2001
@@ -11,9 +11,9 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/kd.h>
 
 #include <asm/system.h>
+#include <asm/rtc.h>
 #include <asm/intersil.h>
 
 
@@ -30,7 +30,7 @@
 void sun3_gettod (int *yearp, int *monp, int *dayp,
                    int *hourp, int *minp, int *secp)
 {
-	u_char wday;
+	unsigned char wday;
 	volatile struct intersil_dt* todintersil;
 	unsigned long flags;
 
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3/mmu_emu.c linux/arch/m68k/sun3/mmu_emu.c
--- v2.4.5/linux/arch/m68k/sun3/mmu_emu.c	Fri Dec 29 14:07:20 2000
+++ linux/arch/m68k/sun3/mmu_emu.c	Mon Jun 11 19:15:27 2001
@@ -29,6 +29,7 @@
 extern void prom_reboot (char *) __attribute__ ((__noreturn__));
 
 #undef DEBUG_MMU_EMU
+#define DEBUG_PROM_MAPS
 
 /*
 ** Defines
@@ -157,9 +158,12 @@
 	j = 0;
 	for (num=0, seg=0x0F800000; seg<0x10000000; seg+=16*PAGE_SIZE) {
 		if (sun3_get_segmap (seg) != SUN3_INVALID_PMEG) {
-#ifdef DEBUG_MMU_EMU
-			printk ("mapped:");
-			print_pte_vaddr (seg);
+#ifdef DEBUG_PROM_MAPS
+			for(i = 0; i < 16; i++) {
+				printk ("mapped:");
+				print_pte_vaddr (seg + (i*PAGE_SIZE));
+				break;
+			}
 #endif
 			// the lowest mapping here is the end of our
 			// vmalloc region
@@ -174,7 +178,7 @@
 	}
 
 	
-	sun3_dvma_init();
+	dvma_init();
 	
 	
 	/* blank everything below the kernel, and we've got the base
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3/sbus.c linux/arch/m68k/sun3/sbus.c
--- v2.4.5/linux/arch/m68k/sun3/sbus.c	Wed Sep  8 11:20:42 1999
+++ linux/arch/m68k/sun3/sbus.c	Mon Jun 11 19:15:27 2001
@@ -12,8 +12,12 @@
 #include <linux/types.h>
 #include <linux/init.h>
 
+extern void rs_init(void);
+
 void __init sbus_init(void)
 {
+
+	rs_init();
 
 }
 
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3/sun3_ksyms.c linux/arch/m68k/sun3/sun3_ksyms.c
--- v2.4.5/linux/arch/m68k/sun3/sun3_ksyms.c	Fri Jan 28 08:04:58 2000
+++ linux/arch/m68k/sun3/sun3_ksyms.c	Mon Jun 11 19:15:27 2001
@@ -6,5 +6,8 @@
 /*
  * Add things here when you find the need for it.
  */
-EXPORT_SYMBOL(sun3_dvma_malloc);
+EXPORT_SYMBOL(dvma_map_align);
+EXPORT_SYMBOL(dvma_unmap);
+EXPORT_SYMBOL(dvma_malloc_align);
+EXPORT_SYMBOL(dvma_free);
 EXPORT_SYMBOL(idprom);
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3/sun3dvma.c linux/arch/m68k/sun3/sun3dvma.c
--- v2.4.5/linux/arch/m68k/sun3/sun3dvma.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3/sun3dvma.c	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,295 @@
+/*
+ * linux/arch/m68k/mm/sun3dvma.c
+ *
+ * Copyright (C) 2000 Sam Creasey
+ *
+ * Contains common routines for sun3/sun3x DVMA management.
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/dvma.h>
+
+#ifdef CONFIG_SUN3X
+extern void dvma_unmap_iommu(unsigned long baddr, int len);
+#else
+static inline void dvma_unmap_iommu(unsigned long a, int b)
+{
+}
+#endif
+
+unsigned long iommu_use[IOMMU_TOTAL_ENTRIES];
+
+#define dvma_index(baddr) ((baddr - DVMA_START) >> DVMA_PAGE_SHIFT)
+
+#define dvma_entry_use(baddr)		(iommu_use[dvma_index(baddr)])
+
+struct hole {
+	unsigned long start;
+	unsigned long end;
+	unsigned long size;
+	struct list_head list;
+};
+
+static struct list_head hole_list;
+static struct list_head hole_cache;
+static struct hole initholes[64];
+
+static inline int refill(void)
+{
+
+	struct hole *hole;
+	struct hole *prev = NULL;
+	struct list_head *cur;
+	int ret = 0;
+	
+	list_for_each(cur, &hole_list) {
+		hole = list_entry(cur, struct hole, list);
+
+		if(!prev) {
+			prev = hole;
+			continue;
+		}
+		
+		if(hole->end == prev->start) {
+			hole->size += prev->size;
+			hole->end = prev->end;
+			list_del(&(prev->list));
+			list_add(&(prev->list), &hole_cache);
+			ret++;
+		}
+		
+	}
+
+	return ret;
+}
+	
+static inline struct hole *rmcache(void)
+{
+	struct hole *ret;
+
+	if(list_empty(&hole_cache)) {
+		if(!refill()) {
+			printk("out of dvma hole cache!\n");
+			BUG();
+		}
+	}
+
+	ret = list_entry(hole_cache.next, struct hole, list);
+	list_del(&(ret->list));
+
+	return ret;
+
+}
+
+static inline unsigned long get_baddr(int len, unsigned long align)
+{
+	
+	struct list_head *cur;
+	struct hole *hole;
+
+	if(list_empty(&hole_list)) {
+		printk("out of dvma holes!\n");
+		BUG();
+	}
+
+	list_for_each(cur, &hole_list) {
+		unsigned long newlen;
+
+		hole = list_entry(cur, struct hole, list);
+
+		if(align > DVMA_PAGE_SIZE) 
+			newlen = len + ((hole->end - len) & (align-1));
+		else
+			newlen = len;
+		
+		if(hole->size > newlen) {
+			hole->end -= newlen;
+			hole->size -= newlen;
+			dvma_entry_use(hole->end) = newlen;
+			return hole->end;
+		} else if(hole->size == newlen) {
+			list_del(&(hole->list));
+			list_add(&(hole->list), &hole_cache);
+			dvma_entry_use(hole->start) = newlen;
+			return hole->start;
+		}
+
+	}
+
+	printk("unable to find dvma hole!\n");
+	BUG();
+	return 0;
+}
+
+static inline int free_baddr(unsigned long baddr)
+{
+	
+	unsigned long len;
+	struct hole *hole;
+	struct list_head *cur;
+	unsigned long orig_baddr;
+
+	orig_baddr = baddr;
+	len = dvma_entry_use(baddr);
+	dvma_entry_use(baddr) = 0;
+	baddr &= DVMA_PAGE_MASK;
+	dvma_unmap_iommu(baddr, len);
+
+	list_for_each(cur, &hole_list) {
+		hole = list_entry(cur, struct hole, list);
+		
+		if(hole->end == baddr) {
+			hole->end += len;
+			hole->size += len;
+			return 0;
+		} else if(hole->start == (baddr + len)) {
+			hole->start = baddr;
+			hole->size += len;
+			return 0;
+		}
+
+	}
+
+	hole = rmcache();
+	
+	hole->start = baddr;
+	hole->end = baddr + len;
+	hole->size = len;
+	
+//	list_add_tail(&(hole->list), cur);
+	list_add(&(hole->list), cur);
+	
+	return 0;
+	
+}
+
+void dvma_init(void)
+{
+	
+	struct hole *hole;
+	int i;
+
+	INIT_LIST_HEAD(&hole_list);
+	INIT_LIST_HEAD(&hole_cache);
+
+	/* prepare the hole cache */
+	for(i = 0; i < 64; i++) 
+		list_add(&(initholes[i].list), &hole_cache);
+		
+	hole = rmcache();
+	hole->start = DVMA_START;
+	hole->end = DVMA_END;
+	hole->size = DVMA_SIZE;
+	
+	list_add(&(hole->list), &hole_list);
+
+	memset(iommu_use, 0, sizeof(iommu_use));
+
+	dvma_unmap_iommu(DVMA_START, DVMA_SIZE);
+
+#ifdef CONFIG_SUN3
+	sun3_dvma_init();
+#endif
+
+}
+
+inline unsigned long dvma_map_align(unsigned long kaddr, int len, int align)
+{
+
+	unsigned long baddr;
+	unsigned long off;
+
+	if(!len)
+		len = 0x800;
+
+	if(!kaddr || !len) {
+//		printk("error: kaddr %lx len %x\n", kaddr, len);
+//		*(int *)4 = 0;
+		return 0;
+	}
+
+#ifdef DEBUG
+	printk("dvma_map request %08lx bytes from %08lx\n", 
+	       len, kaddr);
+#endif
+	off = kaddr & ~DVMA_PAGE_MASK;
+	kaddr &= PAGE_MASK;
+	len += off;
+	len = ((len + (DVMA_PAGE_SIZE-1)) & DVMA_PAGE_MASK);
+
+	if(align == 0)
+		align = DVMA_PAGE_SIZE;
+	else
+		align = ((align + (DVMA_PAGE_SIZE-1)) & DVMA_PAGE_MASK);
+
+	baddr = get_baddr(len, align);
+//	printk("using baddr %lx\n", baddr);
+
+	if(!dvma_map_iommu(kaddr, baddr, len))
+		return (baddr + off);
+	
+	printk("dvma_map failed kaddr %lx baddr %lx len %x\n", kaddr, baddr, len);
+	BUG();
+	return 0;
+}
+
+void dvma_unmap(void *baddr)
+{
+
+	free_baddr((unsigned long)baddr);
+	
+	return;
+
+}
+
+
+void *dvma_malloc_align(unsigned long len, unsigned long align)
+{
+	unsigned long kaddr;
+	unsigned long baddr;
+	unsigned long vaddr;
+
+	if(!len)
+		return NULL;
+
+#ifdef DEBUG
+	printk("dvma_malloc request %lx bytes\n", len);
+#endif
+	len = ((len + (DVMA_PAGE_SIZE-1)) & DVMA_PAGE_MASK);
+
+        if((kaddr = __get_free_pages(GFP_ATOMIC, get_order(len))) == 0)
+		return NULL;
+
+	if((baddr = (unsigned long)dvma_map_align(kaddr, len, align)) == 0) {
+		free_pages(kaddr, get_order(len));
+		return NULL;
+	}
+
+	vaddr = dvma_btov(baddr);
+
+	if(dvma_map_cpu(kaddr, vaddr, len) < 0) {
+		dvma_unmap((void *)baddr);
+		free_pages(kaddr, get_order(len));
+		return NULL;
+	}
+
+#ifdef DEBUG
+	printk("mapped %08lx bytes %08lx kern -> %08lx bus\n",
+	       len, kaddr, baddr);
+#endif
+
+	return (void *)vaddr;
+
+}
+
+void dvma_free(void *vaddr)
+{
+
+	return;
+
+}
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3/sun3ints.c linux/arch/m68k/sun3/sun3ints.c
--- v2.4.5/linux/arch/m68k/sun3/sun3ints.c	Fri Dec 29 14:07:20 2000
+++ linux/arch/m68k/sun3/sun3ints.c	Mon Jun 11 19:15:27 2001
@@ -1,5 +1,5 @@
  /*
- * linux/arch/m68k/sun3/sun3ints.c -- Sun-3 Linux interrupt handling code
+ * linux/arch/m68k/sun3/sun3ints.c -- Sun-3(x) Linux interrupt handling code
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file COPYING in the main directory of this archive
@@ -35,7 +35,7 @@
        ~(0x10), ~(0x08)
 };
 
-unsigned char* sun3_intreg;
+volatile unsigned char* sun3_intreg;
 
 void sun3_insert_irq(irq_node_t **list, irq_node_t *node)
 {
@@ -45,10 +45,6 @@
 {
 }
 
-void sun3_free_irq(unsigned int irq, void *dev_id)
-{
-}
-
 void sun3_enable_irq(unsigned int irq)
 {
 	*sun3_intreg |=  (1<<irq);
@@ -71,41 +67,54 @@
 	return 0;
 }
 
+static void sun3_int7(int irq, void *dev_id, struct pt_regs *fp)
+{
+	sun3_do_irq(irq,fp);
+	if(!(kstat.irqs[0][SYS_IRQS + irq] % 2000)) 
+		sun3_leds(led_pattern[(kstat.irqs[0][SYS_IRQS+irq]%16000)/2000]);
+}
+
 static void sun3_int5(int irq, void *dev_id, struct pt_regs *fp)
 {
         kstat.irqs[0][SYS_IRQS + irq]++;
-        *sun3_intreg &= ~(1<<irq);
+#ifdef CONFIG_SUN3
 	intersil_clear();
+#endif
+        *sun3_intreg &= ~(1<<irq);
         *sun3_intreg |=  (1<<irq);
+#ifdef CONFIG_SUN3
+	intersil_clear();
+#endif
         do_timer(fp);
         if(!(kstat.irqs[0][SYS_IRQS + irq] % 20))
                 sun3_leds(led_pattern[(kstat.irqs[0][SYS_IRQS+irq]%160)
                 /20]);
 }
 
-static void sun3_int7(int irq, void *dev_id, struct pt_regs *fp)
-{
-	sun3_do_irq(irq,fp);
-	if(!(kstat.irqs[0][SYS_IRQS + irq] % 2000)) 
-		sun3_leds(led_pattern[(kstat.irqs[0][SYS_IRQS+irq]%16000)/2000]);
-}
-
 /* handle requested ints, excepting 5 and 7, which always do the same
    thing */
 static void *dev_ids[SYS_IRQS];
-static void (*inthandler[SYS_IRQS])(int, void *, struct pt_regs *) = {
+static void (*sun3_inthandler[SYS_IRQS])(int, void *, struct pt_regs *) = {
 	NULL, NULL, NULL, NULL, NULL, sun3_int5, NULL, sun3_int7
 };
+static void (*sun3_vechandler[192])(int, void *, struct pt_regs *);
+static void *vec_ids[192];
+static char *vec_names[192];
 
 static void sun3_inthandle(int irq, void *dev_id, struct pt_regs *fp)
 {
-	if(inthandler[irq] == NULL)
+	if(sun3_inthandler[irq] == NULL)
 		panic ("bad interrupt %d received (id %p)\n",irq, dev_id);
 
         kstat.irqs[0][SYS_IRQS + irq]++;
         *sun3_intreg &= ~(1<<irq);
 
-	inthandler[irq](irq, dev_ids[irq], fp);
+	sun3_inthandler[irq](irq, dev_ids[irq], fp);
+}
+
+static void sun3_vec255(int irq, void *dev_id, struct pt_regs *fp)
+{
+//	intersil_clear();
 }
 
 void (*sun3_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
@@ -120,6 +129,8 @@
 {
 	int i;
 
+	*sun3_intreg = 1;
+
 	for(i = 0; i < SYS_IRQS; i++)
 	{
 		if(dev_names[i])
@@ -127,25 +138,94 @@
 					0, dev_names[i], NULL);
 	}
 
+	for(i = 0; i < 192; i++) 
+		sun3_vechandler[i] = NULL;
+	
+	sun3_vechandler[191] = sun3_vec255;
 }
                                 
 int sun3_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
                       unsigned long flags, const char *devname, void *dev_id)
 {
-	if(inthandler[irq] != NULL) {
-		printk("sun3_request_irq: request for irq %d -- already taken!\n", irq);
-		return -1;
-	}
 
-	inthandler[irq] = handler;
-	dev_ids[irq] = dev_id;
-	dev_names[irq] = devname;
+	if(irq < SYS_IRQS) {
+		if(sun3_inthandler[irq] != NULL) {
+			printk("sun3_request_irq: request for irq %d -- already taken!\n", irq);
+			return 1;
+		}
+		
+		sun3_inthandler[irq] = handler;
+		dev_ids[irq] = dev_id;
+		dev_names[irq] = devname;
+		
+		/* setting devname would be nice */
+		sys_request_irq(irq, sun3_default_handler[irq], 0, devname, NULL);
+
+		return 0;
+	} else {
+		if((irq >= 64) && (irq <= 255)) {
+		        int vec;
+
+			vec = irq - 64;
+			if(sun3_vechandler[vec] != NULL) {
+				printk("sun3_request_irq: request for vec %d -- already taken!\n", irq);
+				return 1;
+			}
+
+			sun3_vechandler[vec] = handler;
+			vec_ids[vec] = dev_id;
+			vec_names[vec] = devname;
+			
+			return 0;
+		}
+	}
 
-	/* setting devname would be nice */
-	
-	sys_request_irq(irq, sun3_default_handler[irq], 0, devname, NULL);
-	
+	printk("sun3_request_irq: invalid irq %d\n", irq);
+	return 1;
 
-	return 0;
 }
                         
+void sun3_free_irq(unsigned int irq, void *dev_id)
+{
+
+	if(irq < SYS_IRQS) {
+		if(sun3_inthandler[irq] == NULL) 
+			panic("sun3_free_int: attempt to free unused irq %d\n", irq);
+		if(dev_ids[irq] != dev_id)
+			panic("sun3_free_int: incorrect dev_id for irq %d\n", irq);
+		
+		sun3_inthandler[irq] = NULL;
+		return;
+	} else if((irq >= 64) && (irq <= 255)) {
+		int vec;
+
+		vec = irq - 64;
+		if(sun3_vechandler[vec] == NULL)
+			panic("sun3_free_int: attempt to free unused vector %d\n", irq);
+		if(vec_ids[irq] != dev_id)
+			panic("sun3_free_int: incorrect dev_id for vec %d\n", irq);
+		
+		sun3_vechandler[vec] = NULL;
+		return;
+	} else {
+		panic("sun3_free_irq: invalid irq %d\n", irq);
+	}		
+}
+
+void sun3_process_int(int irq, struct pt_regs *regs)
+{
+
+	if((irq >= 64) && (irq <= 255)) {
+		int vec;
+
+		vec = irq - 64;
+		if(sun3_vechandler[vec] == NULL) 
+			panic ("bad interrupt vector %d received\n",irq);
+			
+		sun3_vechandler[vec](irq, vec_ids[vec], regs);
+		return;
+	} else {
+		panic("sun3_process_int: unable to handle interrupt vector %d\n",
+		      irq);
+	}
+}
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3x/Makefile linux/arch/m68k/sun3x/Makefile
--- v2.4.5/linux/arch/m68k/sun3x/Makefile	Fri Dec 29 14:07:20 2000
+++ linux/arch/m68k/sun3x/Makefile	Mon Jun 11 19:15:27 2001
@@ -9,6 +9,6 @@
 
 O_TARGET := sun3x.o
 
-obj-y		:= config.o time.o dvma.o sbus.o
+obj-y		:= config.o time.o dvma.o prom.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3x/config.c linux/arch/m68k/sun3x/config.c
--- v2.4.5/linux/arch/m68k/sun3x/config.c	Thu Aug 26 12:42:31 1999
+++ linux/arch/m68k/sun3x/config.c	Mon Jun 11 19:15:27 2001
@@ -14,39 +14,24 @@
 #include <asm/system.h>
 #include <asm/machdep.h>
 #include <asm/irq.h>
-#include <asm/sun3x.h>
+#include <asm/sun3xprom.h>
+#include <asm/sun3ints.h>
+#include <asm/setup.h>
 
 #include "time.h"
 
-static volatile unsigned char *sun3x_intreg = (unsigned char *)SUN3X_INTREG;
-extern int serial_console;
+volatile char *clock_va;
+extern volatile unsigned char *sun3_intreg;
 
-void sun3x_halt(void)
-{
-    /* Disable interrupts */
-    cli();
-
-    /* we can't drop back to PROM, so we loop here */
-    for (;;);
-}
-
-void sun3x_reboot(void)
-{
-    /* This never returns, don't bother saving things */
-    cli();
-
-    /* no idea, whether this works */
-    asm ("reset");
-}
 
 int __init sun3x_keyb_init(void)
 {
-    return 0;
+	return 0;
 }
 
 int sun3x_kbdrate(struct kbd_repeat *r)
 {
-    return 0;
+	return 0;
 }
 
 void sun3x_kbd_leds(unsigned int i)
@@ -54,36 +39,15 @@
 
 }
 
-static void sun3x_badint (int irq, void *dev_id, struct pt_regs *fp)
+void sun3_leds(unsigned int i)
 {
-    printk ("received spurious interrupt %d\n",irq);
-    num_spurious += 1;
-}
 
-void (*sun3x_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-    sun3x_badint, sun3x_badint, sun3x_badint, sun3x_badint,
-    sun3x_badint, sun3x_badint, sun3x_badint, sun3x_badint
-};
-
-void sun3x_enable_irq(unsigned int irq)
-{
-    *sun3x_intreg |= (1 << irq);
 }
 
-void sun3x_disable_irq(unsigned int irq)
+/* should probably detect types of these eventually. */
+static void sun3x_get_model(char *model)
 {
-    *sun3x_intreg &= ~(1 << irq);
-}
-
-void __init sun3x_init_IRQ(void)
-{
-    /* disable all interrupts initially */
-    *sun3x_intreg = 1;  /* master enable only */
-}
-
-int sun3x_get_irq_list(char *buf)
-{
-    return 0;
+	sprintf(model, "Sun3x");
 }
 
 /*
@@ -91,38 +55,51 @@
  */
 void __init config_sun3x(void)
 {
-    mach_get_irq_list	 = sun3x_get_irq_list;
-    mach_max_dma_address = 0xffffffff; /* we can DMA anywhere, whee */
 
-    mach_keyb_init       = sun3x_keyb_init;
-    mach_kbdrate         = sun3x_kbdrate;
-    mach_kbd_leds        = sun3x_kbd_leds;
-
-    mach_sched_init      = sun3x_sched_init;
-    mach_init_IRQ        = sun3x_init_IRQ;
-    enable_irq           = sun3x_enable_irq;
-    disable_irq          = sun3x_disable_irq;
-    mach_request_irq     = sys_request_irq;
-    mach_free_irq        = sys_free_irq;
-    mach_default_handler = &sun3x_default_handler;
-    mach_gettimeoffset   = sun3x_gettimeoffset;
-    mach_reset           = sun3x_reboot;
+	sun3x_prom_init();
+
+	mach_get_irq_list	 = sun3_get_irq_list;
+	mach_max_dma_address = 0xffffffff; /* we can DMA anywhere, whee */
 
-    mach_gettod          = sun3x_gettod;
+	mach_keyb_init       = sun3x_keyb_init;
+	mach_kbdrate         = sun3x_kbdrate;
+	mach_kbd_leds        = sun3x_kbd_leds;
+
+	mach_default_handler = &sun3_default_handler;
+	mach_sched_init      = sun3x_sched_init;
+	mach_init_IRQ        = sun3_init_IRQ;
+	enable_irq           = sun3_enable_irq;
+	disable_irq          = sun3_disable_irq;
+	mach_request_irq     = sun3_request_irq;
+	mach_free_irq        = sun3_free_irq;
+	mach_process_int     = sun3_process_int;
     
-    switch (*(unsigned char *)SUN3X_EEPROM_CONS) {
+	mach_gettimeoffset   = sun3x_gettimeoffset;
+	mach_reset           = sun3x_reboot;
+
+	mach_gettod          = sun3x_gettod;
+	mach_hwclk           = sun3x_hwclk;
+	mach_get_model       = sun3x_get_model;
+
+	sun3_intreg = (unsigned char *)SUN3X_INTREG;
+
+	/* only the serial console is known to work anyway... */
+#if 0    
+	switch (*(unsigned char *)SUN3X_EEPROM_CONS) {
 	case 0x10:
-	    serial_console = 1;
-	    conswitchp = NULL;
-	    break;
+		serial_console = 1;
+		conswitchp = NULL;
+		break;
 	case 0x11:
-	    serial_console = 2;
-	    conswitchp = NULL;
-	    break;
+		serial_console = 2;
+		conswitchp = NULL;
+		break;
 	default:
-	    serial_console = 0;
-	    conswitchp = &dummy_con;
-	    break;
-    }
+		serial_console = 0;
+		conswitchp = &dummy_con;
+		break;
+	}
+#endif
 
 }
+
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3x/dvma.c linux/arch/m68k/sun3x/dvma.c
--- v2.4.5/linux/arch/m68k/sun3x/dvma.c	Tue May 11 09:57:14 1999
+++ linux/arch/m68k/sun3x/dvma.c	Mon Jun 11 19:15:27 2001
@@ -2,21 +2,31 @@
  * Virtual DMA allocation
  *
  * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de) 
+ *
+ * 11/26/2000 -- disabled the existing code because it didn't work for 
+ * me in 2.4.  Replaced with a significantly more primitive version 
+ * similar to the sun3 code.  the old functionality was probably more 
+ * desirable, but....   -- Sam Creasey (sammy@oh.verio.com)
+ *
  */
 
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
 #include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
 
 #include <asm/sun3x.h>
 #include <asm/dvma.h>
 #include <asm/io.h>
 #include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
 
 /* IOMMU support */
 
-#define IOMMU_ENTRIES		   2048
 #define IOMMU_ADDR_MASK            0x03ffe000
 #define IOMMU_CACHE_INHIBIT        0x00000040
 #define IOMMU_FULL_BLOCK           0x00000020
@@ -28,135 +38,170 @@
 #define IOMMU_DT_VALID             0x00000001
 #define IOMMU_DT_BAD               0x00000002
 
-#define DVMA_PAGE_SHIFT	13
-#define DVMA_PAGE_SIZE	(1UL << DVMA_PAGE_SHIFT)
-#define DVMA_PAGE_MASK	(~(DVMA_PAGE_SIZE-1))
-
 
 static volatile unsigned long *iommu_pte = (unsigned long *)SUN3X_IOMMU;
-static unsigned long iommu_use[IOMMU_ENTRIES];
-static unsigned long iommu_bitmap[IOMMU_ENTRIES/32];
 
 
 #define dvma_entry_paddr(index) 	(iommu_pte[index] & IOMMU_ADDR_MASK)
 #define dvma_entry_vaddr(index,paddr) 	((index << DVMA_PAGE_SHIFT) |  \
 					 (paddr & (DVMA_PAGE_SIZE-1)))
+#if 0
+#define dvma_entry_set(index,addr)	(iommu_pte[index] =            \
+					    (addr & IOMMU_ADDR_MASK) | \
+				             IOMMU_DT_VALID | IOMMU_CACHE_INHIBIT)
+#else
 #define dvma_entry_set(index,addr)	(iommu_pte[index] =            \
 					    (addr & IOMMU_ADDR_MASK) | \
 				             IOMMU_DT_VALID)
+#endif
 #define dvma_entry_clr(index)		(iommu_pte[index] = IOMMU_DT_INVALID)
-#define dvma_entry_use(index)		(iommu_use[index])
-#define dvma_entry_inc(index)		(iommu_use[index]++)
-#define dvma_entry_dec(index)		(iommu_use[index]--)
 #define dvma_entry_hash(addr)		((addr >> DVMA_PAGE_SHIFT) ^ \
 					 ((addr & 0x03c00000) >>     \
 						(DVMA_PAGE_SHIFT+4)))
-#define dvma_map			iommu_bitmap
-#define dvma_map_size			(IOMMU_ENTRIES/2)
-#define dvma_slow_offset		(IOMMU_ENTRIES/2)
-#define dvma_is_slow(addr)		((addr) & 		      \
-					 (dvma_slow_offset << DVMA_PAGE_SHIFT))
 
-static int fixed_dvma;
+#undef DEBUG
 
-void __init dvma_init(void)
+#ifdef DEBUG
+/* code to print out a dvma mapping for debugging purposes */
+void dvma_print (unsigned long dvma_addr)
 {
-    unsigned long tmp;
 
-    if ((unsigned long)high_memory < (IOMMU_ENTRIES << DVMA_PAGE_SHIFT)) {
-	printk ("Sun3x fixed DVMA mapping\n");
-	fixed_dvma = 1;
-	for (tmp = 0; tmp < (unsigned long)high_memory; tmp += DVMA_PAGE_SIZE)
-	dvma_entry_set (tmp >> DVMA_PAGE_SHIFT, virt_to_phys((void *)tmp));
-	fixed_dvma = 1;
-    } else {
-	printk ("Sun3x variable DVMA mapping\n");
-	for (tmp = 0; tmp < IOMMU_ENTRIES; tmp++)
-	    dvma_entry_clr (tmp);
-	fixed_dvma = 0;
-    }
+        unsigned long index;
+
+        index = dvma_addr >> DVMA_PAGE_SHIFT;
+
+        printk("idx %lx dvma_addr %08lx paddr %08lx\n", index, dvma_addr,
+               dvma_entry_paddr(index));
+
+
 }
+#endif
 
-unsigned long dvma_slow_alloc (unsigned long paddr, int npages)
+
+/* create a virtual mapping for a page assigned within the IOMMU
+   so that the cpu can reach it easily */
+inline int dvma_map_cpu(unsigned long kaddr, 
+			       unsigned long vaddr, int len)
 {
-    int scan, base;
-    
-    scan = 0;
-    for (;;) {
-	scan = find_next_zero_bit(dvma_map, dvma_map_size, scan);
-	if ((base = scan) + npages > dvma_map_size) {
-	    printk ("dvma_slow_alloc failed for %d pages\n",npages);
-	    return 0;
-	}
-	for  (;;) {
-	    if (scan >= base + npages) goto found;
-	    if (test_bit(scan, dvma_map)) break;
-	    scan++;
-	}
-    }
+	pgd_t *pgd;
+	unsigned long end;
+	int ret = 0;
+
+	kaddr &= PAGE_MASK;
+	vaddr &= PAGE_MASK;
+
+	end = PAGE_ALIGN(vaddr + len);
+
+#ifdef DEBUG
+	printk("dvma: mapping kern %08lx to virt %08lx\n",
+	       kaddr, vaddr);
+#endif
+	pgd = pgd_offset_k(vaddr);
+	
+	do {
+		pmd_t *pmd;
+		unsigned long end2;
+
+		if((pmd = pmd_alloc_kernel(pgd, vaddr)) == NULL) {
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		if((end & PGDIR_MASK) > (vaddr & PGDIR_MASK)) 
+			end2 = (vaddr + (PGDIR_SIZE-1)) & PGDIR_MASK;
+		else
+			end2 = end;
+
+		do {
+			pte_t *pte;
+			unsigned long end3;
+
+			if((pte = pte_alloc_kernel(pmd, vaddr)) == NULL) {
+				ret = -ENOMEM;
+				goto out;
+			}
+
+			if((end2 & PMD_MASK) > (vaddr & PMD_MASK)) 
+				end3 = (vaddr + (PMD_SIZE-1)) & PMD_MASK;
+			else
+				end3 = end2;
+
+			do {
+#ifdef DEBUG
+				printk("mapping %08lx phys to %08lx\n",
+				       __pa(kaddr), vaddr);
+#endif
+				set_pte(pte, __mk_pte(kaddr, PAGE_KERNEL));
+				pte++;
+				kaddr += PAGE_SIZE;
+				vaddr += PAGE_SIZE;
+			} while(vaddr < end3);
+			
+		} while(vaddr < end2);
+
+	} while(vaddr < end);
+	
+	flush_tlb_all();
 
-found:
-    for (scan = base; scan < base+npages; scan++) {
-	dvma_entry_set(scan+dvma_slow_offset, paddr);
-	paddr += DVMA_PAGE_SIZE;
-	set_bit(scan, dvma_map);
-    }
-    return (dvma_entry_vaddr((base+dvma_slow_offset),paddr));
+ out:
+	return ret;
 }
 
-unsigned long dvma_alloc (unsigned long paddr, unsigned long size)
+
+inline int dvma_map_iommu(unsigned long kaddr, unsigned long baddr,
+				 int len) 
 {
-    int index;
-    int pages = ((paddr & ~DVMA_PAGE_MASK) + size + (DVMA_PAGE_SIZE-1)) >>
-		DVMA_PAGE_SHIFT;
-
-    if (fixed_dvma)
-	return ((unsigned long)phys_to_virt (paddr));
-
-    if (pages > 1) /* multi page, allocate from slow pool */
-	return dvma_slow_alloc (paddr, pages);
-    
-    index = dvma_entry_hash (paddr);
-
-    if (dvma_entry_use(index)) {
-	if (dvma_entry_paddr(index) == (paddr & DVMA_PAGE_MASK)) {
-	    dvma_entry_inc(index);
-	    return dvma_entry_vaddr(index,paddr);
+	unsigned long end, index;
+
+	index = baddr >> DVMA_PAGE_SHIFT;
+	end = ((baddr+len) >> DVMA_PAGE_SHIFT);
+	
+	if(len & ~DVMA_PAGE_MASK)
+		end++;
+
+	for(; index < end ; index++) {
+//		if(dvma_entry_use(index))
+//			BUG();
+//		printk("mapping pa %lx to ba %lx\n", __pa(kaddr), index << DVMA_PAGE_SHIFT);
+
+		dvma_entry_set(index, __pa(kaddr));
+
+		iommu_pte[index] |= IOMMU_FULL_BLOCK;
+//		dvma_entry_inc(index);
+		
+		kaddr += DVMA_PAGE_SIZE;
 	}
-	/* collision, allocate from slow pool */
-	return dvma_slow_alloc (paddr, pages);
-    }
-    
-    dvma_entry_set(index,paddr); 
-    dvma_entry_inc(index);
-    return dvma_entry_vaddr(index,paddr);
+
+#ifdef DEBUG	
+	for(index = (baddr >> DVMA_PAGE_SHIFT); index < end; index++) 
+		dvma_print(index << DVMA_PAGE_SHIFT);
+#endif
+	return 0;
+
 }
 
-void dvma_free (unsigned long dvma_addr, unsigned long size)
+void dvma_unmap_iommu(unsigned long baddr, int len)
 {
-    int npages;
-    int index;
-    
-    if (fixed_dvma)
-	return;
-
-    if (!dvma_is_slow(dvma_addr)) {
-	index = (dvma_addr >> DVMA_PAGE_SHIFT);
-	if (dvma_entry_use(index) == 0) {
-	    printk ("dvma_free: %lx entry already free\n",dvma_addr);
-	    return;
+
+	int index, end;
+	
+	
+	index = baddr >> DVMA_PAGE_SHIFT;
+	end = (DVMA_PAGE_ALIGN(baddr+len) >> DVMA_PAGE_SHIFT);
+	
+	for(; index < end ; index++) {
+#ifdef DEBUG
+		printk("freeing bus mapping %08x\n", index << DVMA_PAGE_SHIFT);
+#endif
+#if 0
+		if(!dvma_entry_use(index)) 
+			printk("dvma_unmap freeing unused entry %04x\n",
+			       index);
+		else
+			dvma_entry_dec(index);
+#endif
+		dvma_entry_clr(index);
 	}
-        dvma_entry_dec(index);
-	if (dvma_entry_use(index) == 0)
-	    dvma_entry_clr(index);
-	return;
-    }
-
-    /* free in slow pool */
-    npages = ((dvma_addr & ~DVMA_PAGE_MASK) + size + (DVMA_PAGE_SIZE-1)) >>
-	    DVMA_PAGE_SHIFT;
-    for (index = (dvma_addr >> DVMA_PAGE_SHIFT); npages--; index++) {
-	dvma_entry_clr(index);
-	clear_bit (index,dvma_map);
-    }
+
 }
+
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3x/prom.c linux/arch/m68k/sun3x/prom.c
--- v2.4.5/linux/arch/m68k/sun3x/prom.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3x/prom.c	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,165 @@
+/* Prom access routines for the sun3x */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/bootinfo.h>
+#include <asm/setup.h>
+#include <asm/traps.h>
+#include <asm/sun3xprom.h>
+#include <asm/idprom.h>
+#include <asm/segment.h>
+#include <asm/sun3ints.h>
+#include <asm/openprom.h>
+#include <asm/machines.h>
+
+void (*sun3x_putchar)(int);
+int (*sun3x_getchar)(void);
+int (*sun3x_mayget)(void);
+int (*sun3x_mayput)(int);
+void (*sun3x_prom_reboot)(void);
+e_vector sun3x_prom_abort;
+struct idprom *idprom;
+static struct idprom idprom_buffer;
+struct linux_romvec *romvec;
+
+/* prom vector table */
+e_vector *sun3x_prom_vbr;
+
+extern e_vector vectors[256];  /* arch/m68k/kernel/traps.c */
+
+/* Handle returning to the prom */
+void sun3x_halt(void)
+{
+    unsigned long flags;
+    
+    /* Disable interrupts while we mess with things */
+    save_flags(flags); cli();
+
+    /* Restore prom vbr */
+    __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
+
+    /* Restore prom NMI clock */
+//    sun3x_disable_intreg(5);
+    sun3_enable_irq(7);
+
+    /* Let 'er rip */
+    __asm__ volatile ("trap #14" : : );
+
+    /* Restore everything */
+    sun3_disable_irq(7);
+    sun3_enable_irq(5);
+
+    __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
+    restore_flags(flags);
+}
+
+void sun3x_reboot(void)
+{
+    /* This never returns, don't bother saving things */
+    cli();
+
+    /* Restore prom vbr */
+    __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
+
+    /* Restore prom NMI clock */
+    sun3_disable_irq(5);
+    sun3_enable_irq(7);
+
+    /* Let 'er rip */
+    (*romvec->pv_reboot)("vmlinux");
+}
+
+extern char m68k_debug_device[];
+
+static void sun3x_prom_write(struct console *co, const char *s,
+                             unsigned int count)
+{
+    while (count--) {
+        if (*s == '\n')
+            sun3x_putchar('\r');
+        sun3x_putchar(*s++);
+    }
+}
+
+/* debug console - write-only */
+
+static struct console sun3x_debug = {
+	"debug",
+	sun3x_prom_write,  	/* write */
+	NULL,			/* read */
+	NULL,			/* device */
+	NULL,			/* wait_key */
+	NULL,			/* unblank */
+	NULL,			/* setup */
+	CON_PRINTBUFFER,
+	-1,
+	0,
+	NULL
+};
+
+void sun3x_prom_init(void)
+{
+    /* Read the vector table */
+	int i;
+
+
+    sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR);
+    sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR);
+    sun3x_mayget = *(int (**)(void))  (SUN3X_P_MAYGET);
+    sun3x_mayput = *(int (**)(int))   (SUN3X_P_MAYPUT);
+    sun3x_prom_reboot = *(void (**)(void)) (SUN3X_P_REBOOT);
+    sun3x_prom_abort = *(e_vector *)  (SUN3X_P_ABORT);
+    romvec = (struct linux_romvec *)SUN3X_PROM_BASE;
+
+    /* make a copy of the idprom structure */
+    for(i = 0; i < sizeof(struct idprom); i++) 
+	    ((unsigned char *)(&idprom_buffer))[i] = ((unsigned char *)SUN3X_IDPROM)[i];
+    idprom = &idprom_buffer;
+
+    if((idprom->id_machtype & SM_ARCH_MASK) != SM_SUN3X) {
+	    printk("Warning: machine reports strange type %02x\n");
+	    printk("Pretending it's a 3/80, but very afraid...\n");
+	    idprom->id_machtype = SM_SUN3X | SM_3_80;
+    }
+
+    /* point trap #14 at abort.
+     * XXX this is futile since we restore the vbr first - oops
+     */
+    vectors[VEC_TRAP14] = sun3x_prom_abort;
+    
+    /* If debug=prom was specified, start the debug console */
+
+    if (!strcmp(m68k_debug_device, "prom"))
+        register_console(&sun3x_debug);
+
+    
+}
+
+/* some prom functions to export */
+int prom_getintdefault(int node, char *property, int deflt)
+{
+	return deflt;
+}
+
+int prom_getbool (int node, char *prop)
+{
+	return 1;
+}
+
+void prom_printf(char *fmt, ...)
+{
+
+}
+
+void prom_halt (void)
+{
+	sun3x_halt();
+}
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3x/sbus.c linux/arch/m68k/sun3x/sbus.c
--- v2.4.5/linux/arch/m68k/sun3x/sbus.c	Thu Aug 26 12:42:31 1999
+++ linux/arch/m68k/sun3x/sbus.c	Wed Dec 31 16:00:00 1969
@@ -1,44 +0,0 @@
-/*
- * SBus helper functions
- *
- * Sun3x don't have a sbus, but many of the used devices are also
- * used on Sparc machines with sbus. To avoid having a lot of
- * duplicate code, we provide necessary glue stuff to make using
- * of the sbus driver code possible.
- *
- * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-
-void __init sbus_init(void)
-{
-
-}
-
-void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
-                      u32 bus_type, int rdonly)
-{
-	return (void *)address;
-}
-
-int prom_getintdefault(int node, char *property, int deflt)
-{
-	return deflt;
-}
-
-int prom_getbool (int node, char *prop)
-{
-	return 1;
-}
-
-void prom_printf(char *fmt, ...)
-{
-
-}
-
-void prom_halt (void)
-{
-
-}
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3x/sun3x_ksyms.c linux/arch/m68k/sun3x/sun3x_ksyms.c
--- v2.4.5/linux/arch/m68k/sun3x/sun3x_ksyms.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3x/sun3x_ksyms.c	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,13 @@
+#include <linux/module.h>
+#include <linux/types.h>
+#include <asm/dvma.h>
+#include <asm/idprom.h>
+
+/*
+ * Add things here when you find the need for it.
+ */
+EXPORT_SYMBOL(dvma_map_align);
+EXPORT_SYMBOL(dvma_unmap);
+EXPORT_SYMBOL(dvma_malloc_align);
+EXPORT_SYMBOL(dvma_free);
+EXPORT_SYMBOL(idprom);
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3x/time.c linux/arch/m68k/sun3x/time.c
--- v2.4.5/linux/arch/m68k/sun3x/time.c	Thu Aug 26 12:42:31 1999
+++ linux/arch/m68k/sun3x/time.c	Mon Jun 11 19:15:27 2001
@@ -5,6 +5,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/kd.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/kernel_stat.h>
@@ -15,6 +16,8 @@
 #include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/sun3x.h>
+#include <asm/sun3ints.h>
+#include <asm/rtc.h>
 
 #include "time.h"
 
@@ -33,6 +36,7 @@
 #define C_CALIB   0x1f
 
 #define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
+#define BIN_TO_BCD(val) (((val/10) << 4) | (val % 10))
 
 /* Read the Mostek */
 void sun3x_gettod (int *yearp, int *monp, int *dayp,
@@ -45,7 +49,7 @@
 
     /* Read values */
     *yearp = BCD_TO_BIN(*(eeprom + M_YEAR));
-    *monp  = BCD_TO_BIN(*(eeprom + M_MONTH));
+    *monp  = BCD_TO_BIN(*(eeprom + M_MONTH)) +1;
     *dayp  = BCD_TO_BIN(*(eeprom + M_DATE));
     *hourp = BCD_TO_BIN(*(eeprom + M_HOUR));
     *minp  = BCD_TO_BIN(*(eeprom + M_MIN));
@@ -55,6 +59,40 @@
     *(eeprom + M_CONTROL) &= ~C_READ;
 }
 
+int sun3x_hwclk(int set, struct hwclk_time *t)
+{
+	volatile struct mostek_dt *h = 
+		(unsigned char *)(SUN3X_EEPROM+M_CONTROL);
+	unsigned long flags;
+
+	save_and_cli(flags);
+	
+	if(set) {
+		h->csr |= C_WRITE;
+		h->sec = BIN_TO_BCD(t->sec);
+		h->min = BIN_TO_BCD(t->min);
+		h->hour = BIN_TO_BCD(t->hour);
+		h->wday = BIN_TO_BCD(t->wday);
+		h->mday = BIN_TO_BCD(t->day);
+		h->month = BIN_TO_BCD(t->mon);
+		h->year = BIN_TO_BCD(t->year);
+		h->csr &= ~C_WRITE;
+	} else {
+		h->csr |= C_READ;
+		t->sec = BCD_TO_BIN(h->sec);
+		t->min = BCD_TO_BIN(h->min);
+		t->hour = BCD_TO_BIN(h->hour);
+		t->wday = BCD_TO_BIN(h->wday);
+		t->day = BCD_TO_BIN(h->mday);
+		t->mon = BCD_TO_BIN(h->month);
+		t->year = BCD_TO_BIN(h->year);
+		h->csr &= ~C_READ;
+	}
+
+	restore_flags(flags);
+
+	return 0;
+}
 /* Not much we can do here */
 unsigned long sun3x_gettimeoffset (void)
 {
@@ -74,9 +112,12 @@
 
 void __init sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *))
 {
-    sys_request_irq(5, sun3x_timer_tick, IRQ_FLG_STD, "timer tick", vector);
+	
+	sun3_disable_interrupts();
+	
 
     /* Pulse enable low to get the clock started */
-    disable_irq(5);
-    enable_irq(5);
+	sun3_disable_irq(5);
+	sun3_enable_irq(5);
+	sun3_enable_interrupts();
 }
diff -u --recursive --new-file v2.4.5/linux/arch/m68k/sun3x/time.h linux/arch/m68k/sun3x/time.h
--- v2.4.5/linux/arch/m68k/sun3x/time.h	Tue May 11 09:57:14 1999
+++ linux/arch/m68k/sun3x/time.h	Mon Jun 11 19:15:27 2001
@@ -1,9 +1,21 @@
 #ifndef SUN3X_TIME_H
 #define SUN3X_TIME_H
 
-void sun3x_gettod (int *yearp, int *monp, int *dayp,
+extern void sun3x_gettod (int *yearp, int *monp, int *dayp,
                    int *hourp, int *minp, int *secp);
+extern int sun3x_hwclk(int set, struct hwclk_time *t);
 unsigned long sun3x_gettimeoffset (void);
 void sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *));
+
+struct mostek_dt {
+	volatile unsigned char csr;
+	volatile unsigned char sec;
+	volatile unsigned char min;
+	volatile unsigned char hour;
+	volatile unsigned char wday;
+	volatile unsigned char mday;
+	volatile unsigned char month;
+	volatile unsigned char year;
+};
 
 #endif
diff -u --recursive --new-file v2.4.5/linux/arch/ppc/boot/common/misc-common.c linux/arch/ppc/boot/common/misc-common.c
--- v2.4.5/linux/arch/ppc/boot/common/misc-common.c	Thu May 24 15:02:06 2001
+++ linux/arch/ppc/boot/common/misc-common.c	Mon Jun 11 19:15:27 2001
@@ -268,7 +268,7 @@
 	s.zfree = zfree;
 	r = inflateInit2(&s, -MAX_WBITS);
 	if (r != Z_OK) {
-		puts("inflateInit2 returned %d\n");
+		puts("inflateInit2 returned "); puthex(r); puts("\n");
 		exit();
 	}
 	s.next_in = src + i;
@@ -277,7 +277,7 @@
 	s.avail_out = dstlen;
 	r = inflate(&s, Z_FINISH);
 	if (r != Z_OK && r != Z_STREAM_END) {
-		puts("inflate returned %d\n");
+		puts("inflate returned "); puthex(r); puts("\n");
 		exit();
 	}
 	*lenp = s.next_out - (unsigned char *) dst;
diff -u --recursive --new-file v2.4.5/linux/arch/ppc/boot/mbx/Makefile linux/arch/ppc/boot/mbx/Makefile
--- v2.4.5/linux/arch/ppc/boot/mbx/Makefile	Thu May 24 15:02:06 2001
+++ linux/arch/ppc/boot/mbx/Makefile	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.Makefile 1.5 05/18/01 06:20:29 patch
+# BK Id: SCCS/s.Makefile 1.7 06/05/01 20:20:05 paulus
 #
 #
 # arch/ppc/mbxboot/Makefile
@@ -87,13 +87,21 @@
 	$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
 		--add-section=initrd=../images/ramdisk.image.gz \
 		--add-section=image=../images/vmlinux.gz \
-		$@.tmp ../images/$@.mbx
+		$@.tmp ../images/$@.embedded
 
 zImage: zvmlinux
-	ln -sf zvmlinux.mbx ../images/zImage.mbx
+ifeq ($(CONFIG_RPXCLASSIC),y)
+	dd if=../images/zvmlinux.embedded of=../images/zImage.embedded bs=65536 skip=1
+else
+	ln -sf ../images/zvmlinux.embedded ../images/zImage.embedded
+endif
 
 zImage.initrd: zvmlinux.initrd
-	ln -sf zvmlinux.initrd.mbx ../images/zImage.initrd.mbx
+ifeq ($(CONFIG_RPXCLASSIC),y)
+	dd if=../images/zvmlinux.initrd.embedded of=../images/zImage.initrd.embedded bs=65536 skip=1
+else
+	ln -sf ../images/zvmlinux.initrd.embedded ../images/zImage.initrd.embedded
+endif
 
 zvmlinux: $(OBJECTS) $(LIBS) ../images/vmlinux.gz
 #
@@ -114,14 +122,14 @@
 	$(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS)
 	$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
 		--add-section=image=../images/vmlinux.gz \
-		$@.tmp ../images/$@.mbx
-# Remove zvmlinux and zvmlinux.temp, we have ../images/zvmlinux.mbx
+		$@.tmp ../images/$@.embedded
+# Remove zvmlinux and zvmlinux.temp, we have ../images/zvmlinux.embedded
 	rm -f $@.tmp $@
 
 znetboot : zImage
-	cp ../images/zImage.mbx $(TFTPIMAGE)
+	cp ../images/zImage.embedded $(TFTPIMAGE)
 
 znetboot.initrd : zImage.initrd
-	cp ../images/zImage.initrd.mbx $(TFTPIMAGE)
+	cp ../images/zImage.initrd.embedded $(TFTPIMAGE)
 
 include $(TOPDIR)/Rules.make 
diff -u --recursive --new-file v2.4.5/linux/arch/ppc/boot/pmac/Makefile linux/arch/ppc/boot/pmac/Makefile
--- v2.4.5/linux/arch/ppc/boot/pmac/Makefile	Thu May 24 15:02:07 2001
+++ linux/arch/ppc/boot/pmac/Makefile	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.Makefile 1.8 05/21/01 09:10:38 trini
+# BK Id: SCCS/s.Makefile 1.10 06/05/01 20:22:51 paulus
 #
 # Makefile for making XCOFF bootable images for booting on PowerMacs
 # using Open Firmware.
@@ -7,7 +7,7 @@
 #
 # Cleaned up, moved into arch/ppc/boot/pmac
 # Tom Rini		January 2001
- 
+
 OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
 COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
 CHRP_LD_ARGS = -Ttext 0x01000000
diff -u --recursive --new-file v2.4.5/linux/arch/ppc/boot/prep/misc.c linux/arch/ppc/boot/prep/misc.c
--- v2.4.5/linux/arch/ppc/boot/prep/misc.c	Thu May 24 15:02:07 2001
+++ linux/arch/ppc/boot/prep/misc.c	Mon Jun 11 19:15:27 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.misc.c 1.8 05/18/01 06:20:29 patch
+ * BK Id: SCCS/s.misc.c 1.10 06/05/01 20:20:05 paulus
  */
 /*
  * misc.c
@@ -393,7 +393,7 @@
 	{
 		struct bi_record *rec;
 	    
-		rec = (struct bi_record *)PAGE_ALIGN(zimage_size);
+		rec = (struct bi_record *)_ALIGN((unsigned long)(zimage_size)+(1<<20)-1,(1<<20));
 	    
 		rec->tag = BI_FIRST;
 		rec->size = sizeof(struct bi_record);
@@ -406,8 +406,8 @@
 	    
 		rec->tag = BI_MACHTYPE;
 		rec->data[0] = _MACH_prep;
-		rec->data[1] = 1;
-		rec->size = sizeof(struct bi_record) + sizeof(unsigned long);
+		rec->data[1] = 0;
+		rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long);
 		rec = (struct bi_record *)((unsigned long)rec + rec->size);
 	    
 		rec->tag = BI_CMD_LINE;
diff -u --recursive --new-file v2.4.5/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.4.5/linux/arch/ppc/config.in	Tue May 22 10:23:16 2001
+++ linux/arch/ppc/config.in	Mon Jun 11 19:15:27 2001
@@ -365,6 +365,10 @@
 
 source drivers/usb/Config.in
 
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   source net/bluetooth/Config.in
+fi
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -u --recursive --new-file v2.4.5/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.4.5/linux/arch/ppc/kernel/Makefile	Mon May 21 17:04:46 2001
+++ linux/arch/ppc/kernel/Makefile	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.Makefile 1.17 05/21/01 00:48:24 cort
+# BK Id: SCCS/s.Makefile 1.19 05/26/01 14:48:14 paulus
 #
 #
 # Makefile for the linux kernel.
@@ -32,7 +32,7 @@
 export-objs			:= ppc_ksyms.o prep_setup.o 
 
 obj-y				:= entry.o traps.o irq.o idle.o time.o misc.o \
-					process.o signal.o bitops.o ptrace.o \
+					process.o signal.o ptrace.o \
 					ppc_htab.o semaphore.o syscalls.o  \
 					align.o setup.o
 obj-$(CONFIG_MODULES)		+= ppc_ksyms.o
diff -u --recursive --new-file v2.4.5/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- v2.4.5/linux/arch/ppc/kernel/chrp_setup.c	Mon May 21 17:04:46 2001
+++ linux/arch/ppc/kernel/chrp_setup.c	Mon Jun 11 19:15:27 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.chrp_setup.c 1.17 05/17/01 18:14:21 cort
+ * BK Id: SCCS/s.chrp_setup.c 1.20 06/05/01 21:22:02 paulus
  */
 /*
  *  linux/arch/ppc/kernel/setup.c
@@ -204,13 +204,10 @@
 	active = sio_read(0x30);
 	level0 = sio_read(0x70);
 	type0 = sio_read(0x71);
-	printk("sio: %s irq level %d, type %d, %sactive: ", name, level0,
-	       type0, !active ? "in" : "");
-	if (level0 == level && type0 == type && active)
-		printk("OK\n");
-	else {
-		printk("remapping to level %d, type %d, active\n", level,
-		       type);
+	if (level0 != level || type0 != type || !active) {
+		printk(KERN_WARNING "sio: %s irq level %d, type %d, %sactive: "
+		       "remapping to level %d, type %d, active\n",
+		       name, level0, type0, !active ? "in" : "", level, type);
 		sio_write(0x01, 0x30);
 		sio_write(level, 0x70);
 		sio_write(type, 0x71);
diff -u --recursive --new-file v2.4.5/linux/arch/ppc/kernel/entry.S linux/arch/ppc/kernel/entry.S
--- v2.4.5/linux/arch/ppc/kernel/entry.S	Mon May 21 17:04:46 2001
+++ linux/arch/ppc/kernel/entry.S	Tue Jun 12 11:07:16 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.entry.S 1.12 05/21/01 11:49:59 paulus
+ * BK Id: SCCS/s.entry.S 1.15 06/09/01 22:16:38 paulus
  */
 /*
  *  PowerPC version 
@@ -310,25 +310,7 @@
 	beq	restore
 	.globl	ret_from_except
 ret_from_except:
-	lwz	r5,_MSR(r1)
-	andi.	r5,r5,MSR_EE
-	beq	2f
-	lis	r4,irq_stat@ha		/* &softirq_active for cpu 0 */
-	addi	r4,r4,irq_stat@l
-#ifdef CONFIG_SMP
-	/* get processor # */
-	lwz	r3,PROCESSOR(r2)
-	slwi	r3,r3,LG_CACHE_LINE_SIZE
-	add	r4,r4,r3
-#endif /* CONFIG_SMP */
-	lwz	r5,0(r4)		/* softirq_active */
-	lwz	r4,4(r4)		/* softirq_mask */
-	and.	r5,r5,r4
-	beq+	2f
-	bl	do_softirq
-	.globl	do_bottom_half_ret
-do_bottom_half_ret:
-2:	lwz	r3,_MSR(r1)	/* Returning to user mode? */
+	lwz	r3,_MSR(r1)	/* Returning to user mode? */
 	andi.	r3,r3,MSR_PR
 	beq+	do_signal_ret	/* if so, check need_resched and signals */
 	lwz	r3,NEED_RESCHED(r2)
diff -u --recursive --new-file v2.4.5/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.4.5/linux/arch/ppc/kernel/irq.c	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/kernel/irq.c	Mon Jun 11 19:15:27 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.irq.c 1.23 05/17/01 18:14:21 cort
+ * BK Id: SCCS/s.irq.c 1.26 06/06/01 22:33:09 paulus
  */
 /*
  *  arch/ppc/kernel/irq.c
@@ -551,6 +551,9 @@
 	ppc_irq_dispatch_handler( regs, irq );
 out:	
         hardirq_exit( cpu );
+
+	if (softirq_pending(cpu))
+		do_softirq();
 	return 1; /* lets ret_from_int know we can do checks */
 }
 
diff -u --recursive --new-file v2.4.5/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- v2.4.5/linux/arch/ppc/kernel/ppc_ksyms.c	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Tue Jun 12 11:07:16 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.ppc_ksyms.c 1.31 05/18/01 08:18:10 patch
+ * BK Id: SCCS/s.ppc_ksyms.c 1.34 06/09/01 22:38:13 paulus
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -357,7 +357,6 @@
 #endif /* CONFIG_8xx */
 
 EXPORT_SYMBOL(ret_to_user_hook);
-EXPORT_SYMBOL(do_softirq);
 EXPORT_SYMBOL(next_mmu_context);
 EXPORT_SYMBOL(set_context);
 EXPORT_SYMBOL(mmu_context_overflow);
diff -u --recursive --new-file v2.4.5/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c
--- v2.4.5/linux/arch/ppc/kernel/prep_pci.c	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/kernel/prep_pci.c	Wed Jun 20 11:16:01 2001
@@ -939,17 +939,6 @@
 				pci_write_config_byte(dev, 0x44, reg);
 			}
 		}
-		if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
-						PCI_DEVICE_ID_VIA_82C586_2,
-						dev)))
-		{
-			/* Force correct USB function interrupt */
-			dev->irq = 11;
-			pcibios_write_config_byte(dev->bus->number,
-					dev->devfn,
-					PCI_INTERRUPT_LINE,
-					dev->irq);
-		}
 	}
 	if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
 				   PCI_DEVICE_ID_WINBOND_82C105, dev))){
diff -u --recursive --new-file v2.4.5/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.4.5/linux/arch/ppc/kernel/prom.c	Thu May 24 15:03:05 2001
+++ linux/arch/ppc/kernel/prom.c	Mon Jun 11 19:15:27 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.prom.c 1.20 05/23/01 00:38:42 cort
+ * BK Id: SCCS/s.prom.c 1.23 06/06/01 22:49:01 paulus
  */
 /*
  * Procedures for interfacing to the Open Firmware PROM on
@@ -42,9 +42,11 @@
 /*
  * Properties whose value is longer than this get excluded from our
  * copy of the device tree.  This way we don't waste space storing
- * things like "driver,AAPL,MacOS,PowerPC" properties.
+ * things like "driver,AAPL,MacOS,PowerPC" properties.  But this value
+ * does need to be big enough to ensure that we don't lose things
+ * like the interrupt-map property on a PCI-PCI bridge.
  */
-#define MAX_PROPERTY_LENGTH	1024
+#define MAX_PROPERTY_LENGTH	4096
 
 struct prom_args {
 	const char *service;
@@ -670,16 +672,16 @@
 	prom_alloc_htab();
 #endif
 
-#ifdef CONFIG_SMP
-	prom_hold_cpus(mem);
-#endif
-
 	mem = check_display(mem);
 
 	prom_print(RELOC("copying OF device tree..."));
 	mem = copy_device_tree(mem, mem + (1<<20));
 	prom_print(RELOC("done\n"));
 
+#ifdef CONFIG_SMP
+	prom_hold_cpus(mem);
+#endif
+
 	RELOC(klimit) = (char *) (mem - offset);
 
 	/* If we are already running at 0xc0000000, we assume we were loaded by
@@ -1190,7 +1192,7 @@
 	if ((_machine == _MACH_chrp) || (boot_infos == 0 && pmac_newworld))
 		use_of_interrupt_tree = 1;
 
-	mem = finish_node(allnodes, mem, NULL, 0, 0);
+	mem = finish_node(allnodes, mem, NULL, 1, 1);
 	dev_tree_size = mem - (unsigned long) allnodes;
 	klimit = (char *) mem;
 }
@@ -1225,10 +1227,7 @@
 
 	np->name = get_property(np, "name", 0);
 	np->type = get_property(np, "device_type", 0);
-#if 0
-	np->n_addr_cells = naddrc;
-	np->n_size_cells = nsizec;
-#endif
+
 	/* get the device addresses and interrupts */
 	if (ifunc != NULL) {
 		mem_start = ifunc(np, mem_start, naddrc, nsizec);
@@ -1244,16 +1243,6 @@
 	ip = (int *) get_property(np, "#size-cells", 0);
 	if (ip != NULL)
 		nsizec = *ip;
-#if 0
-	if (np->parent == NULL) {
-		/*
-		 * Set the n_addr/size_cells on the root to its
-		 * own values, rather than 0.
-		 */
-		np->n_addr_cells = naddrc;
-		np->n_size_cells = nsizec;
-	}
-#endif	
 
 	/* the f50 sets the name to 'display' and 'compatible' to what we
 	 * expect for the name -- Cort
@@ -1479,7 +1468,8 @@
 		if (ip != NULL)
 			return *ip;
 	} while(np->parent);
-	return 0;
+	/* No #address-cells property for the root node, default to 1 */
+	return 1;
 }
 
 int
@@ -1493,7 +1483,8 @@
 		if (ip != NULL)
 			return *ip;
 	} while(np->parent);
-	return 0;
+	/* No #size-cells property for the root node, default to 1 */
+	return 1;
 }
 
 __init
@@ -1980,7 +1971,7 @@
 	struct property *pp;
 
 	for (pp = np->properties; pp != 0; pp = pp->next) {
-		if (name && strcmp(pp->name, name) == 0) {
+		if (pp->name != NULL && strcmp(pp->name, name) == 0) {
 			if (lenp != 0)
 				*lenp = pp->length;
 			return pp->value;
diff -u --recursive --new-file v2.4.5/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.4.5/linux/arch/ppc/kernel/smp.c	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/kernel/smp.c	Mon Jun 11 19:15:27 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.smp.c 1.23 05/17/01 18:14:22 cort
+ * BK Id: SCCS/s.smp.c 1.25 05/23/01 00:38:42 cort
  */
 /*
  * Smp support for ppc.
@@ -670,12 +670,12 @@
 static void
 smp_gemini_kick_cpu(int nr)
 {
-	openpic_init_processor( 1<<i );
+	openpic_init_processor( 1<<nr );
 	openpic_init_processor( 0 );
 }
 
 static void
-smp_gemini_setup_cpu(void)
+smp_gemini_setup_cpu(int cpu_nr)
 {
 	if (OpenPIC_Addr)
 		do_openpic_setup_cpu();
diff -u --recursive --new-file v2.4.5/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- v2.4.5/linux/arch/ppc/kernel/time.c	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/kernel/time.c	Mon Jun 11 19:15:27 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.time.c 1.15 05/17/01 18:14:22 cort
+ * BK Id: SCCS/s.time.c 1.18 06/06/01 22:33:09 paulus
  */
 /*
  * Common time routines among all ppc machines.
@@ -210,6 +210,10 @@
 		ppc_md.heartbeat();
 	
 	hardirq_exit(cpu);
+
+	if (softirq_pending(cpu))
+		do_softirq();
+
 	return 1; /* lets ret_from_int know we can do checks */
 }
 
diff -u --recursive --new-file v2.4.5/linux/arch/ppc/xmon/xmon.c linux/arch/ppc/xmon/xmon.c
--- v2.4.5/linux/arch/ppc/xmon/xmon.c	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/xmon/xmon.c	Tue Jun 12 11:07:16 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.xmon.c 1.9 05/17/01 18:14:24 cort
+ * BK Id: SCCS/s.xmon.c 1.12 06/09/01 22:18:05 paulus
  */
 /*
  * Routines providing a simple monitor for use on the PowerMac.
@@ -661,8 +661,7 @@
 	unsigned stack[2];
 	struct pt_regs regs;
 	extern char ret_from_intercept, ret_from_syscall_1, ret_from_syscall_2;
-	extern char do_bottom_half_ret, do_signal_ret;
-	extern char ret_from_except;
+	extern char do_signal_ret, ret_from_except;
 
 	printf("backtrace:\n");
 	
@@ -680,7 +679,6 @@
 		    || stack[1] == (unsigned) &ret_from_except
 		    || stack[1] == (unsigned) &ret_from_syscall_1
 		    || stack[1] == (unsigned) &ret_from_syscall_2
-		    || stack[1] == (unsigned) &do_bottom_half_ret
 		    || stack[1] == (unsigned) &do_signal_ret) {
 			if (mread(sp+16, &regs, sizeof(regs)) != sizeof(regs))
 				break;
diff -u --recursive --new-file v2.4.5/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v2.4.5/linux/arch/sparc/config.in	Mon May 21 18:12:09 2001
+++ linux/arch/sparc/config.in	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.110 2001/05/20 05:14:46 davem Exp $
+# $Id: config.in,v 1.111 2001/06/01 08:12:10 davem Exp $
 # For a description of the syntax of this configuration file,
 # see Documentation/kbuild/config-language.txt.
 #
@@ -250,6 +250,10 @@
 endmenu
 
 source fs/Config.in
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   source net/bluetooth/Config.in
+fi
 
 mainmenu_option next_comment
 comment 'Watchdog'
diff -u --recursive --new-file v2.4.5/linux/arch/sparc/kernel/rtrap.S linux/arch/sparc/kernel/rtrap.S
--- v2.4.5/linux/arch/sparc/kernel/rtrap.S	Sun Aug  6 11:43:17 2000
+++ linux/arch/sparc/kernel/rtrap.S	Tue Jun 12 11:08:46 2001
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.55 2000/08/05 10:48:40 davem Exp $
+/* $Id: rtrap.S,v 1.56 2001/06/05 09:56:06 davem Exp $
  * rtrap.S: Return from Sparc trap low-level code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -52,9 +52,8 @@
 	sll	%l3, 5, %l3
 	sethi	%hi(C_LABEL(irq_stat)), %l4		! &softirq_active
 	add	%l4, %l3, %l4
-	ld	[%l4 + %lo(C_LABEL(irq_stat))], %g5	! softirq_active
-	ld	[%l4 + %lo(C_LABEL(irq_stat) + 4)], %g4	! softirq_mask
-	andcc	%g4, %g5, %g0
+	ld	[%l4 + %lo(C_LABEL(irq_stat))], %g5	! softirq_pending
+	cmp	%g5, 0
 	be	C_LABEL(ret_trap_lockless_ipi)
 	 nop
 	call	C_LABEL(do_softirq)
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.4.5/linux/arch/sparc64/config.in	Sun May 20 11:32:07 2001
+++ linux/arch/sparc64/config.in	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.143 2001/05/20 05:14:46 davem Exp $
+# $Id: config.in,v 1.144 2001/06/01 08:12:10 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -346,6 +346,10 @@
 endmenu
 
 source drivers/usb/Config.in
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   source net/bluetooth/Config.in
+fi
 
 mainmenu_option next_comment
 comment 'Watchdog'
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.4.5/linux/arch/sparc64/defconfig	Thu May 24 15:00:58 2001
+++ linux/arch/sparc64/defconfig	Mon Jun 11 19:15:27 2001
@@ -663,6 +663,19 @@
 CONFIG_USB_RIO500=m
 
 #
+# Bluetooth support
+#
+CONFIG_BLUEZ=m
+CONFIG_BLUEZ_L2CAP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BLUEZ_HCIUSB=m
+CONFIG_BLUEZ_HCIUART=m
+CONFIG_BLUEZ_HCIEMU=m
+
+#
 # Watchdog
 #
 # CONFIG_SOFT_WATCHDOG is not set
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/kernel/devices.c linux/arch/sparc64/kernel/devices.c
--- v2.4.5/linux/arch/sparc64/kernel/devices.c	Sun May 20 12:11:38 2001
+++ linux/arch/sparc64/kernel/devices.c	Tue Jun 12 11:08:46 2001
@@ -9,6 +9,7 @@
 #include <linux/threads.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/string.h>
 
 #include <asm/page.h>
 #include <asm/oplib.h>
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/kernel/ebus.c linux/arch/sparc64/kernel/ebus.c
--- v2.4.5/linux/arch/sparc64/kernel/ebus.c	Thu Apr 26 22:17:25 2001
+++ linux/arch/sparc64/kernel/ebus.c	Tue Jun 12 11:08:46 2001
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.61 2001/04/24 05:13:25 davem Exp $
+/* $Id: ebus.c,v 1.63 2001/06/08 02:27:16 davem Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -25,7 +25,6 @@
 #ifdef CONFIG_SUN_AUXIO
 extern void auxio_probe(void);
 #endif
-extern void rs_init(void);
 
 static inline void *ebus_alloc(size_t size)
 {
@@ -269,8 +268,6 @@
 	printk("]");
 }
 
-extern void clock_probe(void);
-extern void power_init(void);
 
 void __init ebus_init(void)
 {
@@ -395,10 +392,7 @@
 		++num_ebus;
 	}
 
-	rs_init();
 #ifdef CONFIG_SUN_AUXIO
 	auxio_probe();
 #endif
-	clock_probe();
-	power_init();
 }
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.4.5/linux/arch/sparc64/kernel/ioctl32.c	Wed May 16 10:31:27 2001
+++ linux/arch/sparc64/kernel/ioctl32.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.115 2001/05/12 06:41:58 davem Exp $
+/* $Id: ioctl32.c,v 1.117 2001/06/02 21:39:55 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -90,6 +90,9 @@
 #include <linux/sonet.h>
 #include <linux/atm_suni.h>
 
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci.h>
+
 /* Use this to get at 32-bit user passed pointers. 
    See sys_sparc32.c for description about these. */
 #define A(__x) ((unsigned long)(__x))
@@ -3469,6 +3472,10 @@
 COMPATIBLE_IOCTL(CDROM_LOCKDOOR)
 COMPATIBLE_IOCTL(CDROM_DEBUG)
 COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY)
+/* DVD ioctls */
+COMPATIBLE_IOCTL(DVD_READ_STRUCT)
+COMPATIBLE_IOCTL(DVD_WRITE_STRUCT)
+COMPATIBLE_IOCTL(DVD_AUTH)
 /* Big L */
 COMPATIBLE_IOCTL(LOOP_SET_FD)
 COMPATIBLE_IOCTL(LOOP_CLR_FD)
@@ -3719,6 +3726,17 @@
 COMPATIBLE_IOCTL(WIOCSTART)
 COMPATIBLE_IOCTL(WIOCSTOP)
 COMPATIBLE_IOCTL(WIOCGSTAT)
+/* Bluetooth ioctls */
+COMPATIBLE_IOCTL(HCIDEVUP)
+COMPATIBLE_IOCTL(HCIDEVDOWN)
+COMPATIBLE_IOCTL(HCIDEVRESET)
+COMPATIBLE_IOCTL(HCIRESETSTAT)
+COMPATIBLE_IOCTL(HCIGETINFO)
+COMPATIBLE_IOCTL(HCIGETDEVLIST)
+COMPATIBLE_IOCTL(HCISETRAW)
+COMPATIBLE_IOCTL(HCISETSCAN)
+COMPATIBLE_IOCTL(HCISETAUTH)
+COMPATIBLE_IOCTL(HCIINQUIRY)
 /* Misc. */
 COMPATIBLE_IOCTL(0x41545900)		/* ATYIO_CLKR */
 COMPATIBLE_IOCTL(0x41545901)		/* ATYIO_CLKW */
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c
--- v2.4.5/linux/arch/sparc64/kernel/irq.c	Thu Apr 26 22:17:25 2001
+++ linux/arch/sparc64/kernel/irq.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.100 2001/04/24 01:09:12 davem Exp $
+/* $Id: irq.c,v 1.101 2001/06/04 06:50:18 ecd Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997  David S. Miller  (davem@caip.rutgers.edu)
@@ -783,6 +783,8 @@
 		unsigned char flags = bp->flags;
 
 		nbp = __bucket(bp->irq_chain);
+		bp->irq_chain = 0;
+
 		if ((flags & IBF_ACTIVE) != 0) {
 #ifdef CONFIG_PCI
 			if ((flags & IBF_DMA_SYNC) != 0) {
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c
--- v2.4.5/linux/arch/sparc64/kernel/pci.c	Wed May 16 10:31:27 2001
+++ linux/arch/sparc64/kernel/pci.c	Tue Jun 12 11:08:46 2001
@@ -1,4 +1,4 @@
-/* $Id: pci.c,v 1.29 2001/05/15 08:54:30 davem Exp $
+/* $Id: pci.c,v 1.32 2001/06/08 06:25:41 davem Exp $
  * pci.c: UltraSparc PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -177,6 +177,10 @@
 	}
 }
 
+extern void rs_init(void);
+extern void clock_probe(void);
+extern void power_init(void);
+
 void __init pcibios_init(void)
 {
 	pci_controller_probe();
@@ -190,6 +194,9 @@
 
 	isa_init();
 	ebus_init();
+	rs_init();
+	clock_probe();
+	power_init();
 }
 
 struct pci_fixup pcibios_fixups[] = {
@@ -198,6 +205,66 @@
 
 void pcibios_fixup_bus(struct pci_bus *pbus)
 {
+	struct pci_pbm_info *pbm = pbus->sysdata;
+
+	/* Generic PCI bus probing sets these to point at
+	 * &io{port,mem}_resouce which is wrong for us.
+	 */
+	pbus->resource[0] = &pbm->io_space;
+	pbus->resource[1] = &pbm->mem_space;
+}
+
+/* NOTE: This can get called before we've fixed up pdev->sysdata. */
+int pci_claim_resource(struct pci_dev *pdev, int resource)
+{
+	struct pci_pbm_info *pbm = pci_bus2pbm[pdev->bus->number];
+	struct resource *res = &pdev->resource[resource];
+	struct resource *root;
+
+	if (!pbm)
+		return -EINVAL;
+
+	if (res->flags & IORESOURCE_IO)
+		root = &pbm->io_space;
+	else
+		root = &pbm->mem_space;
+
+	pbm->parent->resource_adjust(pdev, res, root);
+
+	return request_resource(root, res);
+}
+
+int pci_assign_resource(struct pci_dev *pdev, int resource)
+{
+	struct pcidev_cookie *pcp = pdev->sysdata;
+	struct pci_pbm_info *pbm = pcp->pbm;
+	struct resource *res = &pdev->resource[resource];
+	struct resource *root;
+	unsigned long min, max, size, align;
+	int err;
+
+	if (res->flags & IORESOURCE_IO) {
+		root = &pbm->io_space;
+		min = root->start + 0x400UL;
+		max = root->end;
+	} else {
+		root = &pbm->mem_space;
+		min = root->start;
+		max = min + 0x80000000UL;
+	}
+
+	size = res->end - res->start;
+	align = size + 1;
+
+	err = allocate_resource(root, res, size + 1, min, max, align, NULL, NULL);
+	if (err < 0) {
+		printk("PCI: Failed to allocate resource %d for %s\n",
+		       resource, pdev->name);
+	} else {
+		pbm->parent->base_address_update(pdev, resource);
+	}
+
+	return err;
 }
 
 void pcibios_update_resource(struct pci_dev *pdev, struct resource *res1,
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/kernel/pci_common.c linux/arch/sparc64/kernel/pci_common.c
--- v2.4.5/linux/arch/sparc64/kernel/pci_common.c	Sat May 19 18:13:15 2001
+++ linux/arch/sparc64/kernel/pci_common.c	Tue Jun 12 11:08:46 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_common.c,v 1.18 2001/05/18 23:06:35 davem Exp $
+/* $Id: pci_common.c,v 1.21 2001/06/08 06:57:19 davem Exp $
  * pci_common.c: PCI controller common support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -93,12 +93,38 @@
 }
 
 /* Older versions of OBP on PCI systems encode 64-bit MEM
- * space assignments incorrectly, this fixes them up.
+ * space assignments incorrectly, this fixes them up.  We also
+ * take the opportunity here to hide other kinds of bogus
+ * assignments.
  */
-static void __init fixup_obp_assignments(struct pcidev_cookie *pcp)
+static void __init fixup_obp_assignments(struct pci_dev *pdev,
+					 struct pcidev_cookie *pcp)
 {
 	int i;
 
+	if (pdev->vendor == PCI_VENDOR_ID_AL &&
+	    (pdev->device == PCI_DEVICE_ID_AL_M7101 ||
+	     pdev->device == PCI_DEVICE_ID_AL_M1533)) {
+		int i;
+
+		/* Zap all of the normal resources, they are
+		 * meaningless and generate bogus resource collision
+		 * messages.  This is OpenBoot's ill-fated attempt to
+		 * represent the implicit resources that these devices
+		 * have.
+		 */
+		pcp->num_prom_assignments = 0;
+		for (i = 0; i < 6; i++) {
+			pdev->resource[i].start =
+				pdev->resource[i].end =
+				pdev->resource[i].flags = 0;
+		}
+		pdev->resource[PCI_ROM_RESOURCE].start =
+			pdev->resource[PCI_ROM_RESOURCE].end =
+			pdev->resource[PCI_ROM_RESOURCE].flags = 0;
+		return;
+	}
+
 	for (i = 0; i < pcp->num_prom_assignments; i++) {
 		struct linux_prom_pci_registers *ap;
 		int space;
@@ -194,7 +220,7 @@
 				(err / sizeof(pcp->prom_assignments[0]));
 	}
 
-	fixup_obp_assignments(pcp);
+	fixup_obp_assignments(pdev, pcp);
 
 	pdev->sysdata = pcp;
 }
@@ -316,6 +342,19 @@
 	return res;
 }
 
+static int __init pdev_resource_collisions_expected(struct pci_dev *pdev)
+{
+	if (pdev->vendor != PCI_VENDOR_ID_SUN)
+		return 0;
+
+	if (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS ||
+	    pdev->device == PCI_DEVICE_ID_SUN_RIO_1394 ||
+	    pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)
+		return 1;
+
+	return 0;
+}
+
 static void __init pdev_record_assignments(struct pci_pbm_info *pbm,
 					   struct pci_dev *pdev)
 {
@@ -374,12 +413,17 @@
 		if (request_resource(root, res) < 0) {
 			/* OK, there is some conflict.  But this is fine
 			 * since we'll reassign it in the fixup pass.
-			 * Nevertheless notify the user that OBP made
-			 * an error.
+			 *
+			 * We notify the user that OBP made an error if it
+			 * is a case we don't expect.
 			 */
-			printk(KERN_ERR "PCI: Address space collision on region %ld "
-			       "of device %s\n",
-			       (res - &pdev->resource[0]), pdev->name);
+			if (!pdev_resource_collisions_expected(pdev)) {
+				printk(KERN_ERR "PCI: Address space collision on region %ld "
+				       "[%016lx:%016lx] of device %s\n",
+				       (res - &pdev->resource[0]),
+				       res->start, res->end,
+				       pdev->name);
+			}
 		}
 	}
 }
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- v2.4.5/linux/arch/sparc64/kernel/pci_psycho.c	Wed May 16 10:31:27 2001
+++ linux/arch/sparc64/kernel/pci_psycho.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.24 2001/05/15 08:54:30 davem Exp $
+/* $Id: pci_psycho.c,v 1.25 2001/06/04 23:20:32 ecd Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -353,23 +353,28 @@
 	if (ret == 0 && pdev == NULL) {
 		ret = 1;
 	} else if (ret == 0) {
-		switch ((pdev->class >> 16) & 0x0f) {
+		switch ((pdev->class >> 16) & 0xff) {
 		case PCI_BASE_CLASS_STORAGE:
 			ret = 4;
+			break;
 
 		case PCI_BASE_CLASS_NETWORK:
 			ret = 6;
+			break;
 
 		case PCI_BASE_CLASS_DISPLAY:
 			ret = 9;
+			break;
 
 		case PCI_BASE_CLASS_MULTIMEDIA:
 		case PCI_BASE_CLASS_MEMORY:
 		case PCI_BASE_CLASS_BRIDGE:
 			ret = 10;
+			break;
 
 		default:
 			ret = 1;
+			break;
 		};
 	}
 
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- v2.4.5/linux/arch/sparc64/kernel/pci_sabre.c	Wed May 16 10:31:27 2001
+++ linux/arch/sparc64/kernel/pci_sabre.c	Tue Jun 12 11:08:46 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.32 2001/05/15 11:10:01 davem Exp $
+/* $Id: pci_sabre.c,v 1.36 2001/06/08 06:25:41 davem Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -16,6 +16,7 @@
 #include <asm/pbm.h>
 #include <asm/iommu.h>
 #include <asm/irq.h>
+#include <asm/smp.h>
 
 #include "pci_impl.h"
 
@@ -196,7 +197,7 @@
 
 #define SABRE_CONFIGSPACE	0x001000000UL
 #define SABRE_IOSPACE		0x002000000UL
-#define SABRE_IOSPACE_SIZE	0x00000ffffUL
+#define SABRE_IOSPACE_SIZE	0x000ffffffUL
 #define SABRE_MEMSPACE		0x100000000UL
 #define SABRE_MEMSPACE_SIZE	0x07fffffffUL
 
@@ -590,23 +591,28 @@
 	if (ret == 0 && pdev == NULL) {
 		ret = 1;
 	} else if (ret == 0) {
-		switch ((pdev->class >> 16) & 0x0f) {
+		switch ((pdev->class >> 16) & 0xff) {
 		case PCI_BASE_CLASS_STORAGE:
 			ret = 4;
+			break;
 
 		case PCI_BASE_CLASS_NETWORK:
 			ret = 6;
+			break;
 
 		case PCI_BASE_CLASS_DISPLAY:
 			ret = 9;
+			break;
 
 		case PCI_BASE_CLASS_MULTIMEDIA:
 		case PCI_BASE_CLASS_MEMORY:
 		case PCI_BASE_CLASS_BRIDGE:
 			ret = 10;
+			break;
 
 		default:
 			ret = 1;
+			break;
 		};
 	}
 	return ret;
@@ -1025,8 +1031,8 @@
 					 struct resource *res,
 					 struct resource *root)
 {
-	struct pcidev_cookie *pcp = pdev->sysdata;
-	struct pci_controller_info *p = pcp->pbm->parent;
+	struct pci_pbm_info *pbm = pci_bus2pbm[pdev->bus->number];
+	struct pci_controller_info *p = pbm->parent;
 	unsigned long base;
 
 	if (res->flags & IORESOURCE_IO)
@@ -1476,7 +1482,7 @@
 
 		/* Hack up top-level resources. */
 		pbm->io_space.start = p->controller_regs + SABRE_IOSPACE;
-		pbm->io_space.end   = pbm->io_space.start + (1UL << 16) - 1UL;
+		pbm->io_space.end   = pbm->io_space.start + (1UL << 24) - 1UL;
 		pbm->io_space.flags = IORESOURCE_IO;
 
 		pbm->mem_space.start = p->controller_regs + SABRE_MEMSPACE;
@@ -1514,8 +1520,19 @@
 
 		if (prom_getproperty(pnode, "compatible",
 				     compat, sizeof(compat)) > 0 &&
-		    !strcmp(compat, "pci108e,a001"))
+		    !strcmp(compat, "pci108e,a001")) {
 			hummingbird_p = 1;
+		} else {
+			int cpu_node = linux_cpus[0].prom_node;
+
+			/* Of course, Sun has to encode things a thousand
+			 * different ways, inconsistently.
+			 */
+			if (prom_getproperty(cpu_node, "name",
+					     compat, sizeof(compat)) > 0 &&
+			    !strcmp(compat, "SUNW,UltraSPARC-IIe"))
+				hummingbird_p = 1;
+		}
 	}
 
 	p = kmalloc(sizeof(*p), GFP_ATOMIC);
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/kernel/pci_schizo.c linux/arch/sparc64/kernel/pci_schizo.c
--- v2.4.5/linux/arch/sparc64/kernel/pci_schizo.c	Wed May 16 10:31:27 2001
+++ linux/arch/sparc64/kernel/pci_schizo.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_schizo.c,v 1.16 2001/05/15 08:54:30 davem Exp $
+/* $Id: pci_schizo.c,v 1.17 2001/06/04 23:20:32 ecd Exp $
  * pci_schizo.c: SCHIZO specific PCI controller support.
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -339,23 +339,28 @@
 	if (ret == 0 && pdev == NULL) {
 		ret = 1;
 	} else if (ret == 0) {
-		switch ((pdev->class >> 16) & 0x0f) {
+		switch ((pdev->class >> 16) & 0xff) {
 		case PCI_BASE_CLASS_STORAGE:
 			ret = 4;
+			break;
 
 		case PCI_BASE_CLASS_NETWORK:
 			ret = 6;
+			break;
 
 		case PCI_BASE_CLASS_DISPLAY:
 			ret = 9;
+			break;
 
 		case PCI_BASE_CLASS_MULTIMEDIA:
 		case PCI_BASE_CLASS_MEMORY:
 		case PCI_BASE_CLASS_BRIDGE:
 			ret = 10;
+			break;
 
 		default:
 			ret = 1;
+			break;
 		};
 	}
 
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/kernel/power.c linux/arch/sparc64/kernel/power.c
--- v2.4.5/linux/arch/sparc64/kernel/power.c	Tue Jul 11 15:46:08 2000
+++ linux/arch/sparc64/kernel/power.c	Tue Jun 12 11:08:46 2001
@@ -1,4 +1,4 @@
-/* $Id: power.c,v 1.8 2000/07/11 22:41:33 davem Exp $
+/* $Id: power.c,v 1.9 2001/06/08 02:28:22 davem Exp $
  * power.c: Power management driver.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -81,6 +81,11 @@
 {
 	struct linux_ebus *ebus;
 	struct linux_ebus_device *edev;
+	static int invoked = 0;
+
+	if (invoked)
+		return;
+	invoked = 1;
 
 	for_each_ebus(ebus) {
 		for_each_ebusdev(edev, ebus) {
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.4.5/linux/arch/sparc64/kernel/process.c	Thu Apr 12 12:10:25 2001
+++ linux/arch/sparc64/kernel/process.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.117 2001/03/30 07:10:41 davem Exp $
+/*  $Id: process.c,v 1.118 2001/06/03 13:41:13 ecd Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -111,6 +111,7 @@
 extern void (*prom_palette)(int);
 extern int serial_console;
 #endif
+extern void (*prom_keyboard)(void);
 
 void machine_halt(void)
 {
@@ -121,6 +122,8 @@
 	if (!serial_console && prom_palette)
 		prom_palette (1);
 #endif
+	if (prom_keyboard)
+		prom_keyboard();
 	prom_halt();
 	panic("Halt failed!");
 }
@@ -139,6 +142,8 @@
 	if (!serial_console && prom_palette)
 		prom_palette (1);
 #endif
+	if (prom_keyboard)
+		prom_keyboard();
 	if (cmd)
 		prom_reboot(cmd);
 	if (*reboot_command)
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S
--- v2.4.5/linux/arch/sparc64/kernel/rtrap.S	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/kernel/rtrap.S	Tue Jun 12 11:08:46 2001
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.54 2001/03/08 22:08:51 davem Exp $
+/* $Id: rtrap.S,v 1.55 2001/06/05 09:56:06 davem Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -88,9 +88,8 @@
 		sethi			%hi(irq_stat), %l2	! &softirq_active
 		or			%l2, %lo(irq_stat), %l2	! &softirq_active
 		sllx			%l0, 6, %l0
-		ldx			[%l2 + %l0], %l1	! softirq_active + softirq_mask
-		srlx			%l1, 32, %l2
-		andcc			%l1, %l2, %g0
+		lduw			[%l2 + %l0], %l1	! softirq_pending
+		cmp			%l1, 0
 
 		bne,pn			%icc, __handle_softirq
 		 ldx			[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c
--- v2.4.5/linux/arch/sparc64/kernel/setup.c	Thu Apr 26 22:17:25 2001
+++ linux/arch/sparc64/kernel/setup.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.64 2001/04/24 21:10:05 davem Exp $
+/*  $Id: setup.c,v 1.65 2001/06/03 13:41:13 ecd Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -64,6 +64,7 @@
 #if CONFIG_SUN_CONSOLE
 void (*prom_palette)(int);
 #endif
+void (*prom_keyboard)(void);
 asmlinkage void sys_sync(void);	/* it's really int */
 
 static void
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.4.5/linux/arch/sparc64/kernel/sparc64_ksyms.c	Sun May 20 11:32:07 2001
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.107 2001/05/18 08:01:35 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.108 2001/06/05 03:39:50 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -24,6 +24,7 @@
 #include <asm/oplib.h>
 #include <asm/delay.h>
 #include <asm/system.h>
+#include <asm/auxio.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -184,6 +185,9 @@
 EXPORT_SYMBOL(mostek_lock);
 EXPORT_SYMBOL(mstk48t02_regs);
 EXPORT_SYMBOL(request_fast_irq);
+#if CONFIG_SUN_AUXIO
+EXPORT_SYMBOL(auxio_register);
+#endif
 #if CONFIG_SBUS
 EXPORT_SYMBOL(sbus_root);
 EXPORT_SYMBOL(dma_chain);
diff -u --recursive --new-file v2.4.5/linux/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c
--- v2.4.5/linux/arch/sparc64/kernel/time.c	Thu Apr 26 22:17:25 2001
+++ linux/arch/sparc64/kernel/time.c	Tue Jun 12 11:08:46 2001
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.37 2001/04/24 01:09:12 davem Exp $
+/* $Id: time.c,v 1.39 2001/06/08 02:33:37 davem Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -32,6 +32,7 @@
 #include <asm/fhc.h>
 #include <asm/pbm.h>
 #include <asm/ebus.h>
+#include <asm/isa.h>
 #include <asm/starfire.h>
 
 extern rwlock_t xtime_lock;
@@ -408,7 +409,13 @@
 	unsigned long flags;
 #ifdef CONFIG_PCI
 	struct linux_ebus *ebus = NULL;
+	struct isa_bridge *isa_br = NULL;
 #endif
+	static int invoked = 0;
+
+	if (invoked)
+		return;
+	invoked = 1;
 
 
 	if (this_is_starfire) {
@@ -433,6 +440,9 @@
 	else if (ebus_chain != NULL) {
 		ebus = ebus_chain;
 		busnd = ebus->prom_node;
+	} else if (isa_chain != NULL) {
+		isa_br = isa_chain;
+		busnd = isa_br->prom_node;
 	}
 #endif
 	else if (sbus_root != NULL) {
@@ -465,6 +475,13 @@
 					node = prom_getchild(busnd);
 				}
 			}
+			while ((node == 0) && isa_br != NULL) {
+				isa_br = isa_br->next;
+				if (isa_br != NULL) {
+					busnd = isa_br->prom_node;
+					node = prom_getchild(busnd);
+				}
+			}
 #endif
 			if (node == 0) {
 				prom_printf("clock_probe: Cannot find timer chip\n");
@@ -504,6 +521,22 @@
 				mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
 			}
 			break;
+		} else if (isa_chain != NULL) {
+			struct isa_device *isadev;
+
+			for_each_isadev(isadev, isa_br)
+				if (isadev->prom_node == node)
+					break;
+			if (isadev == NULL) {
+				prom_printf("%s: Mostek not probed by ISA\n");
+				prom_halt();
+			}
+			if (!strcmp(model, "ds1287")) {
+				ds1287_regs = isadev->resource.start;
+			} else {
+				mstk48t59_regs = isadev->resource.start;
+				mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
+			}
 		}
 #endif
 		else {
diff -u --recursive --new-file v2.4.5/linux/drivers/Makefile linux/drivers/Makefile
--- v2.4.5/linux/drivers/Makefile	Wed May 16 10:27:02 2001
+++ linux/drivers/Makefile	Mon Jun 11 19:15:27 2001
@@ -7,7 +7,8 @@
 
 
 mod-subdirs :=	dio mtd sbus video macintosh usb input telephony sgi i2o ide \
-		scsi md ieee1394 pnp isdn atm fc4 net/hamradio i2c acpi
+		scsi md ieee1394 pnp isdn atm fc4 net/hamradio i2c acpi \
+		bluetooth
 
 subdir-y :=	parport char block net sound misc media cdrom
 subdir-m :=	$(subdir-y)
@@ -42,6 +43,8 @@
 subdir-$(CONFIG_HAMRADIO)	+= net/hamradio
 subdir-$(CONFIG_I2C)		+= i2c
 subdir-$(CONFIG_ACPI)		+= acpi
+
+subdir-$(CONFIG_BLUEZ)		+= bluetooth
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v2.4.5/linux/drivers/atm/fore200e.c linux/drivers/atm/fore200e.c
--- v2.4.5/linux/drivers/atm/fore200e.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/atm/fore200e.c	Tue Jun 12 11:06:54 2001
@@ -439,6 +439,7 @@
 
     case FORE200E_STATE_BLANK:
 	/* nothing to do for that state */
+	break;
     }
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/atm/fore200e_mkfirm.c linux/drivers/atm/fore200e_mkfirm.c
--- v2.4.5/linux/drivers/atm/fore200e_mkfirm.c	Mon Feb 21 16:32:27 2000
+++ linux/drivers/atm/fore200e_mkfirm.c	Wed Jun 20 11:10:27 2001
@@ -10,8 +10,9 @@
 */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <sys/types.h>
-#include <sys/time.h>
+#include <time.h>
 
 char* default_basename = "pca200e"; /* was initially written for the PCA-200E firmware */
 char* default_infname  = "<stdin>";
diff -u --recursive --new-file v2.4.5/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.4.5/linux/drivers/block/ll_rw_blk.c	Thu Apr 12 12:15:52 2001
+++ linux/drivers/block/ll_rw_blk.c	Tue Jun 12 11:17:17 2001
@@ -859,30 +859,34 @@
 void generic_make_request (int rw, struct buffer_head * bh)
 {
 	int major = MAJOR(bh->b_rdev);
+	int minorsize = 0;
 	request_queue_t *q;
 
 	if (!bh->b_end_io)
 		BUG();
 
-	if (blk_size[major]) {
-		unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1;
+	/* Test device size, when known. */
+	if (blk_size[major])
+		minorsize = blk_size[major][MINOR(bh->b_rdev)];
+	if (minorsize) {
+		unsigned long maxsector = (minorsize << 1) + 1;
 		unsigned long sector = bh->b_rsector;
 		unsigned int count = bh->b_size >> 9;
 
 		if (maxsector < count || maxsector - count < sector) {
+			/* Yecch */
 			bh->b_state &= (1 << BH_Lock) | (1 << BH_Mapped);
-			if (blk_size[major][MINOR(bh->b_rdev)]) {
-				
-				/* This may well happen - the kernel calls bread()
-				   without checking the size of the device, e.g.,
-				   when mounting a device. */
-				printk(KERN_INFO
-				       "attempt to access beyond end of device\n");
-				printk(KERN_INFO "%s: rw=%d, want=%ld, limit=%d\n",
-				       kdevname(bh->b_rdev), rw,
-				       (sector + count)>>1,
-				       blk_size[major][MINOR(bh->b_rdev)]);
-			}
+
+			/* This may well happen - the kernel calls bread()
+			   without checking the size of the device, e.g.,
+			   when mounting a device. */
+			printk(KERN_INFO
+			       "attempt to access beyond end of device\n");
+			printk(KERN_INFO "%s: rw=%d, want=%ld, limit=%d\n",
+			       kdevname(bh->b_rdev), rw,
+			       (sector + count)>>1, minorsize);
+
+			/* Yecch again */
 			bh->b_end_io(bh, 0);
 			return;
 		}
@@ -900,7 +904,8 @@
 		q = blk_get_queue(bh->b_rdev);
 		if (!q) {
 			printk(KERN_ERR
-			       "generic_make_request: Trying to access nonexistent block-device %s (%ld)\n",
+			       "generic_make_request: Trying to access "
+			       "nonexistent block-device %s (%ld)\n",
 			       kdevname(bh->b_rdev), bh->b_rsector);
 			buffer_IO_error(bh);
 			break;
diff -u --recursive --new-file v2.4.5/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.4.5/linux/drivers/block/loop.c	Wed Apr 11 19:05:14 2001
+++ linux/drivers/block/loop.c	Mon Jun 11 19:15:27 2001
@@ -651,8 +651,8 @@
 	inode->i_mapping->gfp_mask = GFP_BUFFER;
 
 	bs = 0;
-	if (blksize_size[MAJOR(inode->i_rdev)])
-		bs = blksize_size[MAJOR(inode->i_rdev)][MINOR(inode->i_rdev)];
+	if (blksize_size[MAJOR(lo_device)])
+		bs = blksize_size[MAJOR(lo_device)][MINOR(lo_device)];
 	if (!bs)
 		bs = BLOCK_SIZE;
 
diff -u --recursive --new-file v2.4.5/linux/drivers/bluetooth/Config.in linux/drivers/bluetooth/Config.in
--- v2.4.5/linux/drivers/bluetooth/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/bluetooth/Config.in	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,8 @@
+mainmenu_option next_comment
+comment 'Bluetooth device drivers'
+
+dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB
+dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ
+dep_tristate 'HCI EMU (virtual device) driver' CONFIG_BLUEZ_HCIEMU $CONFIG_BLUEZ
+
+endmenu
diff -u --recursive --new-file v2.4.5/linux/drivers/bluetooth/Makefile linux/drivers/bluetooth/Makefile
--- v2.4.5/linux/drivers/bluetooth/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/bluetooth/Makefile	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,11 @@
+#
+# Makefile for Bluetooth HCI device drivers.
+#
+
+O_TARGET	:= bluetooth.o
+
+obj-$(CONFIG_BLUEZ_HCIUSB)	+= hci_usb.o
+obj-$(CONFIG_BLUEZ_HCIUART)	+= hci_uart.o
+obj-$(CONFIG_BLUEZ_HCIEMU)	+= hci_emu.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.5/linux/drivers/bluetooth/hci_emu.c linux/drivers/bluetooth/hci_emu.c
--- v2.4.5/linux/drivers/bluetooth/hci_emu.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/bluetooth/hci_emu.c	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,335 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * BlueZ HCI virtual device driver.
+ *
+ * $Id: hci_emu.c,v 1.1 2001/06/01 08:12:10 davem Exp $ 
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/random.h>
+
+#include <linux/skbuff.h>
+#include <linux/miscdevice.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/bluez.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci_emu.h>
+
+/* HCI device part */
+
+int hci_emu_open(struct hci_dev *hdev)
+{
+	hdev->flags |= HCI_RUNNING;
+	return 0;
+}
+
+int hci_emu_flush(struct hci_dev *hdev)
+{
+	struct hci_emu_struct *hci_emu = (struct hci_emu_struct *) hdev->driver_data;
+	bluez_skb_queue_purge(&hci_emu->readq);
+	return 0;
+}
+
+int hci_emu_close(struct hci_dev *hdev)
+{
+	hdev->flags &= ~HCI_RUNNING;
+	hci_emu_flush(hdev);
+	return 0;
+}
+
+int hci_emu_send_frame(struct sk_buff *skb)
+{
+	struct hci_dev* hdev = (struct hci_dev *) skb->dev;
+	struct hci_emu_struct *hci_emu;
+
+	if (!hdev) {
+		ERR("Frame for uknown device (hdev=NULL)");
+		return -ENODEV;
+	}
+
+	if (!(hdev->flags & HCI_RUNNING))
+		return -EBUSY;
+
+	hci_emu = (struct hci_emu_struct *) hdev->driver_data;
+
+	memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
+	skb_queue_tail(&hci_emu->readq, skb);
+
+	if (hci_emu->flags & HCI_EMU_FASYNC)
+		kill_fasync(&hci_emu->fasync, SIGIO, POLL_IN);
+	wake_up_interruptible(&hci_emu->read_wait);
+
+	return 0;
+}
+
+/* Character device part */
+
+/* Poll */
+static unsigned int hci_emu_chr_poll(struct file *file, poll_table * wait)
+{  
+	struct hci_emu_struct *hci_emu = (struct hci_emu_struct *) file->private_data;
+
+	poll_wait(file, &hci_emu->read_wait, wait);
+ 
+	if (skb_queue_len(&hci_emu->readq))
+		return POLLIN | POLLRDNORM;
+
+	return POLLOUT | POLLWRNORM;
+}
+
+/* Get packet from user space buffer(already verified) */
+static __inline__ ssize_t hci_emu_get_user(struct hci_emu_struct *hci_emu, const char *buf, size_t count)
+{
+	struct sk_buff *skb;
+
+	if (count > HCI_EMU_MAX_FRAME)
+		return -EINVAL;
+
+	if (!(skb = bluez_skb_alloc(count, GFP_KERNEL)))
+		return -ENOMEM;
+	
+	copy_from_user(skb_put(skb, count), buf, count); 
+
+	skb->dev = (void *) &hci_emu->hdev;
+	skb->pkt_type = *((__u8 *) skb->data);
+	skb_pull(skb, 1);
+
+	hci_recv_frame(skb);
+
+	return count;
+} 
+
+/* Write */
+static ssize_t hci_emu_chr_write(struct file * file, const char * buf, 
+			     size_t count, loff_t *pos)
+{
+	struct hci_emu_struct *hci_emu = (struct hci_emu_struct *) file->private_data;
+
+	if (verify_area(VERIFY_READ, buf, count))
+		return -EFAULT;
+
+	return hci_emu_get_user(hci_emu, buf, count);
+}
+
+/* Put packet to user space buffer(already verified) */
+static __inline__ ssize_t hci_emu_put_user(struct hci_emu_struct *hci_emu,
+				       struct sk_buff *skb, char *buf, int count)
+{
+	int len = count, total = 0;
+	char *ptr = buf;
+
+	len = MIN(skb->len, len); 
+	copy_to_user(ptr, skb->data, len); 
+	total += len;
+
+	hci_emu->hdev.stat.byte_tx += len;
+	switch (skb->pkt_type) {
+		case HCI_COMMAND_PKT:
+			hci_emu->hdev.stat.cmd_tx++;
+			break;
+
+		case HCI_ACLDATA_PKT:
+			hci_emu->hdev.stat.acl_tx++;
+			break;
+
+		case HCI_SCODATA_PKT:
+			hci_emu->hdev.stat.cmd_tx++;
+			break;
+	};
+
+	return total;
+}
+
+/* Read */
+static ssize_t hci_emu_chr_read(struct file * file, char * buf, size_t count, loff_t *pos)
+{
+	struct hci_emu_struct *hci_emu = (struct hci_emu_struct *) file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
+	struct sk_buff *skb;
+	ssize_t ret = 0;
+
+	add_wait_queue(&hci_emu->read_wait, &wait);
+	while (count) {
+		current->state = TASK_INTERRUPTIBLE;
+
+		/* Read frames from device queue */
+		if (!(skb = skb_dequeue(&hci_emu->readq))) {
+			if (file->f_flags & O_NONBLOCK) {
+				ret = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				break;
+			}
+
+			/* Nothing to read, let's sleep */
+			schedule();
+			continue;
+		}
+
+		if (!verify_area(VERIFY_WRITE, buf, count))
+			ret = hci_emu_put_user(hci_emu, skb, buf, count);
+		else
+			ret = -EFAULT;
+
+		bluez_skb_free(skb);
+		break;
+	}
+
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&hci_emu->read_wait, &wait);
+
+	return ret;
+}
+
+static loff_t hci_emu_chr_lseek(struct file * file, loff_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static int hci_emu_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	return -EINVAL;
+}
+
+static int hci_emu_chr_fasync(int fd, struct file *file, int on)
+{
+	struct hci_emu_struct *hci_emu = (struct hci_emu_struct *) file->private_data;
+	int ret;
+
+	if ((ret = fasync_helper(fd, file, on, &hci_emu->fasync)) < 0)
+		return ret; 
+ 
+	if (on)
+		hci_emu->flags |= HCI_EMU_FASYNC;
+	else 
+		hci_emu->flags &= ~HCI_EMU_FASYNC;
+
+	return 0;
+}
+
+static int hci_emu_chr_open(struct inode *inode, struct file * file)
+{
+	struct hci_emu_struct *hci_emu = NULL; 
+	struct hci_dev *hdev;
+
+	if (!(hci_emu = kmalloc(sizeof(struct hci_emu_struct), GFP_KERNEL)))
+		return -ENOMEM;
+
+	memset(hci_emu, 0, sizeof(struct hci_emu_struct));
+
+	skb_queue_head_init(&hci_emu->readq);
+	init_waitqueue_head(&hci_emu->read_wait);
+
+	/* Initialize and register HCI device */
+	hdev = &hci_emu->hdev;
+
+	hdev->type = HCI_EMU;
+	hdev->driver_data = hci_emu;
+
+	hdev->open  = hci_emu_open;
+	hdev->close = hci_emu_close;
+	hdev->flush = hci_emu_flush;
+	hdev->send  = hci_emu_send_frame;
+
+	if (hci_register_dev(hdev) < 0) {
+		kfree(hci_emu);
+		return -EBUSY;
+	}
+
+	file->private_data = hci_emu;
+	return 0;   
+}
+
+static int hci_emu_chr_close(struct inode *inode, struct file *file)
+{
+	struct hci_emu_struct *hci_emu = (struct hci_emu_struct *) file->private_data;
+
+	if (hci_unregister_dev(&hci_emu->hdev) < 0) {
+		ERR("Can't unregister HCI device %s", hci_emu->hdev.name);
+	}
+
+	kfree(hci_emu);
+	file->private_data = NULL;
+
+	return 0;
+}
+
+static struct file_operations hci_emu_fops = {
+	owner:	THIS_MODULE,	
+	llseek:	hci_emu_chr_lseek,
+	read:	hci_emu_chr_read,
+	write:	hci_emu_chr_write,
+	poll:	hci_emu_chr_poll,
+	ioctl:	hci_emu_chr_ioctl,
+	open:	hci_emu_chr_open,
+	release:hci_emu_chr_close,
+	fasync:	hci_emu_chr_fasync		
+};
+
+static struct miscdevice hci_emu_miscdev=
+{
+        HCI_EMU_MINOR,
+        "hci_emu",
+        &hci_emu_fops
+};
+
+int __init hci_emu_init(void)
+{
+	INF("BlueZ HCI EMU driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
+		BLUEZ_VER);
+	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+
+	if (misc_register(&hci_emu_miscdev)) {
+		ERR("Can't register misc device %d\n", HCI_EMU_MINOR);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+void hci_emu_cleanup(void)
+{
+	misc_deregister(&hci_emu_miscdev);
+}
+
+module_init(hci_emu_init);
+module_exit(hci_emu_cleanup);
diff -u --recursive --new-file v2.4.5/linux/drivers/bluetooth/hci_uart.c linux/drivers/bluetooth/hci_uart.c
--- v2.4.5/linux/drivers/bluetooth/hci_uart.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/bluetooth/hci_uart.c	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,575 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * BlueZ HCI UART driver.
+ *
+ * $Id: hci_uart.c,v 1.1 2001/06/01 08:12:10 davem Exp $    
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/poll.h>
+
+#include <linux/malloc.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/bluez.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci_uart.h>
+
+#ifndef HCI_UART_DEBUG
+#undef  DBG
+#define DBG( A... )
+#undef  DMP
+#define DMP( A... )
+#endif
+
+/* ------- Interface to HCI layer ------ */
+/* Initialize device */
+int n_hci_open(struct hci_dev *hdev)
+{
+	DBG("%s %p", hdev->name, hdev);
+
+	/* Nothing to do for UART driver */
+
+	hdev->flags |= HCI_RUNNING;
+
+	return 0;
+}
+
+/* Reset device */
+int n_hci_flush(struct hci_dev *hdev)
+{
+	struct n_hci *n_hci  = (struct n_hci *) hdev->driver_data;
+	struct tty_struct *tty = n_hci->tty;
+
+	DBG("hdev %p tty %p", hdev, tty);
+
+	/* Drop TX queue */
+	bluez_skb_queue_purge(&n_hci->txq);
+
+	/* Flush any pending characters in the driver and discipline. */
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+
+	return 0;
+}
+
+/* Close device */
+int n_hci_close(struct hci_dev *hdev)
+{
+	DBG("hdev %p", hdev);
+
+	hdev->flags &= ~HCI_RUNNING;
+
+	n_hci_flush(hdev);
+
+	return 0;
+}
+
+int n_hci_tx_wakeup(struct n_hci *n_hci)
+{
+	register struct tty_struct *tty = n_hci->tty;
+
+	if (test_and_set_bit(TRANS_SENDING, &n_hci->tx_state)) {
+		set_bit(TRANS_WAKEUP, &n_hci->tx_state);
+		return 0;
+	}
+
+	DBG("");
+	do {
+		register struct sk_buff *skb;
+		register int len;
+
+		clear_bit(TRANS_WAKEUP, &n_hci->tx_state);
+
+		if (!(skb = skb_dequeue(&n_hci->txq)))
+			break;
+
+		DMP(skb->data, skb->len);
+
+		/* Send frame to TTY driver */
+		tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+		len = tty->driver.write(tty, 0, skb->data, skb->len);
+
+		n_hci->hdev.stat.byte_tx += len;
+
+		DBG("sent %d", len);
+
+		if (len == skb->len) {
+			/* Full frame was sent */
+			bluez_skb_free(skb);
+		} else {
+			/* Subtract sent part and requeue  */
+			skb_pull(skb, len);
+			skb_queue_head(&n_hci->txq, skb);
+		}
+	} while (test_bit(TRANS_WAKEUP, &n_hci->tx_state));
+	clear_bit(TRANS_SENDING, &n_hci->tx_state);
+
+	return 0;
+}
+
+/* Send frames from HCI layer */
+int n_hci_send_frame(struct sk_buff *skb)
+{
+	struct hci_dev* hdev = (struct hci_dev *) skb->dev;
+	struct tty_struct *tty;
+	struct n_hci *n_hci;
+
+	if (!hdev) {
+		ERR("Frame for uknown device (hdev=NULL)");
+		return -ENODEV;
+	}
+
+	if (!(hdev->flags & HCI_RUNNING))
+		return -EBUSY;
+
+	n_hci = (struct n_hci *) hdev->driver_data;
+	tty = n_hci2tty(n_hci);
+
+	DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
+
+	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.cmd_tx++;
+                        break;
+	};
+
+	/* Prepend skb with frame type and queue */
+	memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
+	skb_queue_tail(&n_hci->txq, skb);
+
+	n_hci_tx_wakeup(n_hci);
+
+	return 0;
+}
+
+/* ------ LDISC part ------ */
+
+/* n_hci_tty_open
+ * 
+ *     Called when line discipline changed to N_HCI.
+ *     
+ * Arguments:    
+ *     tty    pointer to tty info structure
+ * Return Value:    
+ *     0 if success, otherwise error code
+ */
+static int n_hci_tty_open(struct tty_struct *tty)
+{
+	struct n_hci *n_hci = tty2n_hci(tty);
+	struct hci_dev *hdev;
+
+	DBG("tty %p", tty);
+
+	if (n_hci)
+		return -EEXIST;
+
+	if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) {
+		ERR("Can't allocate controll structure");
+		return -ENFILE;
+	}
+	memset(n_hci, 0, sizeof(struct n_hci));
+
+	/* Initialize and register HCI device */
+	hdev = &n_hci->hdev;
+
+	hdev->type = HCI_UART;
+	hdev->driver_data = n_hci;
+
+	hdev->open  = n_hci_open;
+	hdev->close = n_hci_close;
+	hdev->flush = n_hci_flush;
+	hdev->send  = n_hci_send_frame;
+
+	if (hci_register_dev(hdev) < 0) {
+		ERR("Can't register HCI device %s", hdev->name);
+		kfree(n_hci);
+		return -ENODEV;
+	}
+
+	tty->disc_data = n_hci;
+	n_hci->tty = tty;
+
+	spin_lock_init(&n_hci->rx_lock);
+	n_hci->rx_state = WAIT_PACKET_TYPE;
+
+	skb_queue_head_init(&n_hci->txq);
+
+	MOD_INC_USE_COUNT;
+
+	/* Flush any pending characters in the driver and discipline. */
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+
+	return 0;
+}
+
+/* n_hci_tty_close()
+ *
+ *    Called when the line discipline is changed to something
+ *    else, the tty is closed, or the tty detects a hangup.
+ */
+static void n_hci_tty_close(struct tty_struct *tty)
+{
+	struct n_hci *n_hci = tty2n_hci(tty);
+	struct hci_dev *hdev = &n_hci->hdev;
+
+	DBG("tty %p hdev %p", tty, hdev);
+
+	if (n_hci != NULL) {
+		n_hci_close(hdev);
+
+		if (hci_unregister_dev(hdev) < 0) {
+			ERR("Can't unregister HCI device %s",hdev->name);
+		}
+
+		hdev->driver_data = NULL;
+		tty->disc_data = NULL;
+		kfree(n_hci);
+
+		MOD_DEC_USE_COUNT;
+	}
+}
+
+/* n_hci_tty_wakeup()
+ *
+ *    Callback for transmit wakeup. Called when low level
+ *    device driver can accept more send data.
+ *
+ * Arguments:        tty    pointer to associated tty instance data
+ * Return Value:    None
+ */
+static void n_hci_tty_wakeup( struct tty_struct *tty )
+{
+	struct n_hci *n_hci = tty2n_hci(tty);
+
+	DBG("");
+
+	if (!n_hci)
+		return;
+
+	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+
+	if (tty != n_hci->tty)
+		return;
+
+	n_hci_tx_wakeup(n_hci);
+}
+
+/* n_hci_tty_room()
+ * 
+ *    Callback function from tty driver. Return the amount of 
+ *    space left in the receiver's buffer to decide if remote
+ *    transmitter is to be throttled.
+ *
+ * Arguments:        tty    pointer to associated tty instance data
+ * Return Value:    number of bytes left in receive buffer
+ */
+static int n_hci_tty_room (struct tty_struct *tty)
+{
+	return 65536;
+}
+
+static inline int n_hci_check_data_len(struct n_hci *n_hci, int len)
+{
+	register int room = skb_tailroom(n_hci->rx_skb);
+
+	DBG("len %d room %d", len, room);
+	if (!len) {
+		DMP(n_hci->rx_skb->data, n_hci->rx_skb->len);
+		hci_recv_frame(n_hci->rx_skb);
+	} else if (len > room) {
+		ERR("Data length is to large");
+		bluez_skb_free(n_hci->rx_skb);
+		n_hci->hdev.stat.err_rx++;
+	} else {
+		n_hci->rx_state = WAIT_DATA;
+		n_hci->rx_count = len;
+		return len;
+	}
+
+	n_hci->rx_state = WAIT_PACKET_TYPE;
+	n_hci->rx_skb   = NULL;
+	n_hci->rx_count = 0;
+	return 0;
+}
+
+static inline void n_hci_rx(struct n_hci *n_hci, const __u8 * data, char *flags, int count)
+{
+	register const char *ptr;
+	hci_event_hdr *eh;
+	hci_acl_hdr   *ah;
+	hci_sco_hdr   *sh;
+	register int len, type, dlen;
+
+	DBG("count %d state %d rx_count %d", count, n_hci->rx_state, n_hci->rx_count);
+
+	n_hci->hdev.stat.byte_rx += count;
+
+	ptr = data;
+	while (count) {
+		if (n_hci->rx_count) {
+			len = MIN(n_hci->rx_count, count);
+			memcpy(skb_put(n_hci->rx_skb, len), ptr, len);
+			n_hci->rx_count -= len; count -= len; ptr += len;
+
+			if (n_hci->rx_count)
+				continue;
+
+			switch (n_hci->rx_state) {
+				case WAIT_DATA:
+					DBG("Complete data");
+
+					DMP(n_hci->rx_skb->data, n_hci->rx_skb->len);
+
+					hci_recv_frame(n_hci->rx_skb);
+
+					n_hci->rx_state = WAIT_PACKET_TYPE;
+					n_hci->rx_skb = NULL;
+					continue;
+
+				case WAIT_EVENT_HDR:
+					eh = (hci_event_hdr *) n_hci->rx_skb->data;
+
+					DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
+
+					n_hci_check_data_len(n_hci, eh->plen);
+					continue;
+
+				case WAIT_ACL_HDR:
+					ah = (hci_acl_hdr *) n_hci->rx_skb->data;
+					dlen = __le16_to_cpu(ah->dlen);
+
+					DBG("ACL header: dlen %d", dlen);
+
+					n_hci_check_data_len(n_hci, dlen);
+					continue;
+
+				case WAIT_SCO_HDR:
+					sh = (hci_sco_hdr *) n_hci->rx_skb->data;
+
+					DBG("SCO header: dlen %d", sh->dlen);
+
+					n_hci_check_data_len(n_hci, sh->dlen);
+					continue;
+			};
+		}
+
+		/* WAIT_PACKET_TYPE */
+		switch (*ptr) {
+			case HCI_EVENT_PKT:
+				DBG("Event packet");
+				n_hci->rx_state = WAIT_EVENT_HDR;
+				n_hci->rx_count = HCI_EVENT_HDR_SIZE;
+				type = HCI_EVENT_PKT;
+				break;
+
+			case HCI_ACLDATA_PKT:
+				DBG("ACL packet");
+				n_hci->rx_state = WAIT_ACL_HDR;
+				n_hci->rx_count = HCI_ACL_HDR_SIZE;
+				type = HCI_ACLDATA_PKT;
+				break;
+
+			case HCI_SCODATA_PKT:
+				DBG("SCO packet");
+				n_hci->rx_state = WAIT_SCO_HDR;
+				n_hci->rx_count = HCI_SCO_HDR_SIZE;
+				type = HCI_SCODATA_PKT;
+				break;
+
+			default:
+				ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
+				n_hci->hdev.stat.err_rx++;
+				ptr++; count--;
+				continue;
+		};
+		ptr++; count--;
+
+		/* Allocate packet */
+		if (!(n_hci->rx_skb = bluez_skb_alloc(HCI_MAX_READ, GFP_ATOMIC))) {
+			ERR("Can't allocate mem for new packet");
+
+			n_hci->rx_state = WAIT_PACKET_TYPE;
+			n_hci->rx_count = 0;
+			return;
+		}
+		n_hci->rx_skb->dev = (void *) &n_hci->hdev;
+		n_hci->rx_skb->pkt_type = type;
+	}
+}
+
+/* n_hci_tty_receive()
+ * 
+ *     Called by tty low level driver when receive data is
+ *     available.
+ *     
+ * Arguments:  tty          pointer to tty isntance data
+ *             data         pointer to received data
+ *             flags        pointer to flags for data
+ *             count        count of received data in bytes
+ *     
+ * Return Value:    None
+ */
+static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count)
+{
+	struct n_hci *n_hci = tty2n_hci(tty);
+
+	if (!n_hci || tty != n_hci->tty)
+		return;
+
+	spin_lock(&n_hci->rx_lock);
+	n_hci_rx(n_hci, data, flags, count);
+	spin_unlock(&n_hci->rx_lock);
+
+	if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle)
+		tty->driver.unthrottle(tty);
+}
+
+/* n_hci_tty_ioctl()
+ *
+ *    Process IOCTL system call for the tty device.
+ *
+ * Arguments:
+ *
+ *    tty        pointer to tty instance data
+ *    file       pointer to open file object for device
+ *    cmd        IOCTL command code
+ *    arg        argument for IOCTL call (cmd dependent)
+ *
+ * Return Value:    Command dependent
+ */
+static int n_hci_tty_ioctl (struct tty_struct *tty, struct file * file,
+                            unsigned int cmd, unsigned long arg)
+{
+	struct n_hci *n_hci = tty2n_hci(tty);
+	int error = 0;
+
+	DBG("");
+
+	/* Verify the status of the device */
+	if (!n_hci)
+		return -EBADF;
+
+	switch (cmd) {
+		default:
+			error = n_tty_ioctl(tty, file, cmd, arg);
+			break;
+	};
+
+	return error;
+}
+
+/*
+ * We don't provide read/write/poll interface for user space.
+ */
+static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
+{
+	return 0;
+}
+static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
+{
+	return 0;
+}
+static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
+{
+	return 0;
+}
+
+int __init n_hci_init(void)
+{
+	static struct tty_ldisc n_hci_ldisc;
+	int err;
+
+	INF("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", 
+		BLUEZ_VER);
+	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+
+	/* Register the tty discipline */
+
+	memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc));
+	n_hci_ldisc.magic       = TTY_LDISC_MAGIC;
+	n_hci_ldisc.name        = "n_hci";
+	n_hci_ldisc.open        = n_hci_tty_open;
+	n_hci_ldisc.close       = n_hci_tty_close;
+	n_hci_ldisc.read        = n_hci_tty_read;
+	n_hci_ldisc.write       = n_hci_tty_write;
+	n_hci_ldisc.ioctl       = n_hci_tty_ioctl;
+	n_hci_ldisc.poll        = n_hci_tty_poll;
+	n_hci_ldisc.receive_room= n_hci_tty_room;
+	n_hci_ldisc.receive_buf = n_hci_tty_receive;
+	n_hci_ldisc.write_wakeup= n_hci_tty_wakeup;
+
+	if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) {
+		ERR("Can't register HCI line discipline (%d)", err);
+		return err;
+	}
+
+	return 0;
+}
+
+void n_hci_cleanup(void)
+{
+	int err;
+
+	/* Release tty registration of line discipline */
+	if ((err = tty_register_ldisc(N_HCI, NULL)))
+		ERR("Can't unregister HCI line discipline (%d)", err);
+}
+
+module_init(n_hci_init);
+module_exit(n_hci_cleanup);
diff -u --recursive --new-file v2.4.5/linux/drivers/bluetooth/hci_usb.c linux/drivers/bluetooth/hci_usb.c
--- v2.4.5/linux/drivers/bluetooth/hci_usb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/bluetooth/hci_usb.c	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,670 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * BlueZ HCI USB driver.
+ * Based on original USB Bluetooth driver for Linux kernel
+ *    Copyright (c) 2000 Greg Kroah-Hartman        <greg@kroah.com>
+ *    Copyright (c) 2000 Mark Douglas Corner       <mcorner@umich.edu>
+ *
+ * $Id: hci_usb.c,v 1.1 2001/06/01 08:12:10 davem Exp $    
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/poll.h>
+
+#include <linux/malloc.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+
+#include <linux/usb.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/bluez.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci_usb.h>
+
+#ifndef HCI_USB_DEBUG
+#undef  DBG
+#define DBG( A... )
+#undef  DMP
+#define DMP( A... )
+#endif
+
+static struct usb_device_id usb_bluetooth_ids [] = {
+	{ USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) },
+	{ }	/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids);
+
+static int hci_usb_ctrl_msg(struct hci_usb *husb,  struct sk_buff *skb);
+static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb);
+
+static void hci_usb_unlink_urbs(struct hci_usb *husb)
+{
+	usb_unlink_urb(husb->read_urb);
+	usb_unlink_urb(husb->intr_urb);
+	usb_unlink_urb(husb->ctrl_urb);
+	usb_unlink_urb(husb->write_urb);
+}
+
+static void hci_usb_free_bufs(struct hci_usb *husb)
+{
+	if (husb->read_urb) {
+		if (husb->read_urb->transfer_buffer)
+			kfree(husb->read_urb->transfer_buffer);
+		usb_free_urb(husb->read_urb);
+	}
+
+	if (husb->intr_urb) {
+		if (husb->intr_urb->transfer_buffer)
+			kfree(husb->intr_urb->transfer_buffer);
+		usb_free_urb(husb->intr_urb);
+	}
+
+	if (husb->ctrl_urb)
+		usb_free_urb(husb->ctrl_urb);
+
+	if (husb->write_urb)
+		usb_free_urb(husb->write_urb);
+
+	if (husb->intr_skb)
+		bluez_skb_free(husb->intr_skb);
+}
+
+/* ------- Interface to HCI layer ------ */
+/* Initialize device */
+int hci_usb_open(struct hci_dev *hdev)
+{
+	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
+	int status;
+
+	DBG("%s", hdev->name);
+
+	husb->read_urb->dev = husb->udev;
+	if ((status = usb_submit_urb(husb->read_urb)))
+		DBG("read submit failed. %d", status);
+
+	husb->intr_urb->dev = husb->udev;
+	if ((status = usb_submit_urb(husb->intr_urb)))
+		DBG("interrupt submit failed. %d", status);
+
+	hdev->flags |= HCI_RUNNING;
+
+	return 0;
+}
+
+/* Reset device */
+int hci_usb_flush(struct hci_dev *hdev)
+{
+	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
+
+	DBG("%s", hdev->name);
+
+	/* Drop TX queues */
+	bluez_skb_queue_purge(&husb->tx_ctrl_q);
+	bluez_skb_queue_purge(&husb->tx_write_q);
+
+	return 0;
+}
+
+/* Close device */
+int hci_usb_close(struct hci_dev *hdev)
+{
+	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
+
+	DBG("%s", hdev->name);
+
+	hdev->flags &= ~HCI_RUNNING;
+	hci_usb_unlink_urbs(husb);
+
+	hci_usb_flush(hdev);
+
+	return 0;
+}
+
+void hci_usb_ctrl_wakeup(struct hci_usb *husb)
+{
+	struct sk_buff *skb;
+
+	if (test_and_set_bit(HCI_TX_CTRL, &husb->tx_state))
+		return;
+
+	DBG("%s", husb->hdev.name);
+
+	if (!(skb = skb_dequeue(&husb->tx_ctrl_q)))
+		goto done;
+
+	if (hci_usb_ctrl_msg(husb, skb)){
+		bluez_skb_free(skb);
+		goto done;
+	}
+
+	DMP(skb->data, skb->len);
+
+	husb->hdev.stat.byte_tx += skb->len;
+	return;
+
+done:
+	clear_bit(HCI_TX_CTRL, &husb->tx_state);
+	return;
+}
+
+void hci_usb_write_wakeup(struct hci_usb *husb)
+{
+	struct sk_buff *skb;
+
+	if (test_and_set_bit(HCI_TX_WRITE, &husb->tx_state))
+		return;
+
+	DBG("%s", husb->hdev.name);
+
+	if (!(skb = skb_dequeue(&husb->tx_write_q)))
+		goto done;
+
+	if (hci_usb_write_msg(husb, skb)) {
+		skb_queue_head(&husb->tx_write_q, skb);
+		goto done;
+	}
+
+	DMP(skb->data, skb->len);
+
+	husb->hdev.stat.byte_tx += skb->len;
+	return;
+
+done:
+	clear_bit(HCI_TX_WRITE, &husb->tx_state);
+	return;
+}
+
+/* Send frames from HCI layer */
+int hci_usb_send_frame(struct sk_buff *skb)
+{
+	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+	struct hci_usb *husb;
+
+	if (!hdev) {
+		ERR("frame for uknown device (hdev=NULL)");
+		return -ENODEV;
+	}
+
+	if (!(hdev->flags & HCI_RUNNING))
+		return 0;
+
+	husb = (struct hci_usb *) hdev->driver_data;
+
+	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
+
+	switch (skb->pkt_type) {
+		case HCI_COMMAND_PKT:
+			skb_queue_tail(&husb->tx_ctrl_q, skb);
+			hci_usb_ctrl_wakeup(husb);
+			hdev->stat.cmd_tx++;
+			return 0;
+
+		case HCI_ACLDATA_PKT:
+			skb_queue_tail(&husb->tx_write_q, skb);
+			hci_usb_write_wakeup(husb);
+			hdev->stat.acl_tx++;
+			return 0;
+
+		case HCI_SCODATA_PKT:
+			return -EOPNOTSUPP;
+	};
+
+	return 0;
+}
+
+/* ---------- USB ------------- */
+
+static void hci_usb_ctrl(struct urb *urb)
+{
+	struct sk_buff *skb = (struct sk_buff *) urb->context;
+	struct hci_dev *hdev;
+	struct hci_usb *husb;
+
+	if (!skb)
+		return;
+	hdev = (struct hci_dev *) skb->dev;
+	husb = (struct hci_usb *) hdev->driver_data;
+
+	DBG("%s", hdev->name);
+
+	if (urb->status)
+		DBG("%s ctrl status: %d", hdev->name, urb->status);
+
+	clear_bit(HCI_TX_CTRL, &husb->tx_state);
+	bluez_skb_free(skb);
+
+	/* Wake up device */
+	hci_usb_ctrl_wakeup(husb);
+}
+
+static void hci_usb_bulk_write(struct urb *urb)
+{
+	struct sk_buff *skb = (struct sk_buff *) urb->context;
+	struct hci_dev *hdev;
+	struct hci_usb *husb;
+
+	if (!skb)
+		return;
+	hdev = (struct hci_dev *) skb->dev;
+	husb = (struct hci_usb *) hdev->driver_data;
+
+	DBG("%s", hdev->name);
+
+	if (urb->status)
+		DBG("%s bulk write status: %d", hdev->name, urb->status);
+
+	clear_bit(HCI_TX_WRITE, &husb->tx_state);
+	bluez_skb_free(skb);
+
+	/* Wake up device */
+	hci_usb_write_wakeup(husb);
+
+	return;
+}
+
+static void hci_usb_intr(struct urb *urb)
+{
+	struct hci_usb *husb = (struct hci_usb *) urb->context;
+	unsigned char *data = urb->transfer_buffer;
+	register int count  = urb->actual_length;
+	register struct sk_buff *skb = husb->intr_skb;
+	hci_event_hdr *eh;
+	register int len;
+
+	if (!husb)
+		return;
+
+	DBG("%s count %d", husb->hdev.name, count);
+
+	if (urb->status || !count) {
+		DBG("%s intr status %d, count %d", husb->hdev.name, urb->status, count);
+		return;
+	}
+
+	/* Do we really have to handle continuations here ? */
+	if (!skb) {
+		/* New frame */
+		if (count < HCI_EVENT_HDR_SIZE) {
+			DBG("%s bad frame len %d", husb->hdev.name, count);
+			return;
+		}
+
+		eh = (hci_event_hdr *) data;
+		len = eh->plen + HCI_EVENT_HDR_SIZE;
+
+		if (count > len) {
+			DBG("%s corrupted frame, len %d", husb->hdev.name, count);
+			return;
+		}
+
+		/* Allocate skb */
+		if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) {
+			ERR("Can't allocate mem for new packet");
+			return;
+		}
+		skb->dev = (void *) &husb->hdev;
+		skb->pkt_type = HCI_EVENT_PKT;
+
+		husb->intr_skb = skb;
+		husb->intr_count = len;
+	} else {
+		/* Continuation */
+		if (count > husb->intr_count) {
+			ERR("%s bad frame len %d (expected %d)", husb->hdev.name, count, husb->intr_count);
+
+			bluez_skb_free(skb);
+			husb->intr_skb = NULL;
+			husb->intr_count = 0;
+			return;
+		}
+	}
+
+	memcpy(skb_put(skb, count), data, count);
+	husb->intr_count -= count;
+
+	DMP(data, count);
+
+	if (!husb->intr_count) {
+		/* Got complete frame */
+
+		husb->hdev.stat.byte_rx += skb->len;
+		hci_recv_frame(skb);
+
+		husb->intr_skb = NULL;
+	}
+}
+
+static void hci_usb_bulk_read(struct urb *urb)
+{
+	struct hci_usb *husb = (struct hci_usb *) urb->context;
+	unsigned char *data = urb->transfer_buffer;
+	int count = urb->actual_length, status;
+	struct sk_buff *skb;
+	hci_acl_hdr *ah;
+	register __u16 dlen;
+
+	if (!husb)
+		return;
+
+	DBG("%s status %d, count %d, flags %x", husb->hdev.name, urb->status, count, urb->transfer_flags);
+
+	if (urb->status) {
+		/* Do not re-submit URB on critical errors */
+		switch (urb->status) {
+			case -ENOENT:
+				return;
+			default:
+				goto resubmit;
+		};
+	}
+	if (!count)
+		goto resubmit;
+
+	DMP(data, count);
+
+	ah = (hci_acl_hdr *) data;
+	dlen = le16_to_cpu(ah->dlen);
+
+	/* Verify frame len and completeness */
+	if ((count - HCI_ACL_HDR_SIZE) != dlen) {
+		ERR("%s corrupted ACL packet: count %d, plen %d", husb->hdev.name, count, dlen);
+		goto resubmit;
+	}
+
+	/* Allocate packet */
+	if (!(skb = bluez_skb_alloc(count, GFP_ATOMIC))) {
+		ERR("Can't allocate mem for new packet");
+		goto resubmit;
+	}
+
+	memcpy(skb_put(skb, count), data, count);
+	skb->dev = (void *) &husb->hdev;
+	skb->pkt_type = HCI_ACLDATA_PKT;
+
+	husb->hdev.stat.byte_rx += skb->len;
+
+	hci_recv_frame(skb);
+
+resubmit:
+	husb->read_urb->dev = husb->udev;
+	if ((status = usb_submit_urb(husb->read_urb)))
+		DBG("%s read URB submit failed %d", husb->hdev.name, status);
+
+	DBG("%s read URB re-submited", husb->hdev.name);
+}
+
+static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb)
+{
+	struct urb *urb = husb->ctrl_urb;
+	devrequest *dr  = &husb->dev_req;
+	int pipe, status;
+
+	DBG("%s len %d", husb->hdev.name, skb->len);
+
+	pipe = usb_sndctrlpipe(husb->udev, 0);
+
+	dr->requesttype = HCI_CTRL_REQ;
+	dr->request = 0;
+	dr->index   = 0;
+	dr->value   = 0;
+	dr->length  = cpu_to_le16(skb->len);
+
+	FILL_CONTROL_URB(urb, husb->udev, pipe, (void*)dr, skb->data, skb->len,
+	                 hci_usb_ctrl, skb);
+
+	if ((status = usb_submit_urb(urb))) {
+		DBG("%s control URB submit failed %d", husb->hdev.name, status);
+		return status;
+	}
+
+	return 0;
+}
+
+static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb)
+{
+	struct urb *urb = husb->write_urb;
+	int pipe, status;
+
+	DBG("%s len %d", husb->hdev.name, skb->len);
+
+	pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep_addr);
+
+	FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len,
+	              hci_usb_bulk_write, skb);
+	urb->transfer_flags |= USB_QUEUE_BULK;
+
+	if ((status = usb_submit_urb(urb))) {
+		DBG("%s write URB submit failed %d", husb->hdev.name, status);
+		return status;
+	}
+
+	return 0;
+}
+
+static void * hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
+{
+	struct usb_endpoint_descriptor *bulk_out_ep, *intr_in_ep, *bulk_in_ep;
+	struct usb_interface_descriptor *uif;
+	struct usb_endpoint_descriptor *ep;
+	struct hci_usb *husb;
+	struct hci_dev *hdev;
+	int i, size, pipe;
+	__u8 * buf;
+
+	DBG("udev %p ifnum %d", udev, ifnum);
+
+	/* Check device signature */
+	if ((udev->descriptor.bDeviceClass    != HCI_DEV_CLASS)   ||
+	    (udev->descriptor.bDeviceSubClass != HCI_DEV_SUBCLASS)||
+	    (udev->descriptor.bDeviceProtocol != HCI_DEV_PROTOCOL) )
+		return NULL;
+
+	MOD_INC_USE_COUNT;
+
+	uif = &udev->actconfig->interface[ifnum].altsetting[0];
+
+	if (uif->bNumEndpoints != 3) {
+		DBG("Wrong number of endpoints %d", uif->bNumEndpoints);
+		MOD_DEC_USE_COUNT;
+		return NULL;
+	}
+
+	bulk_out_ep = intr_in_ep = bulk_in_ep = NULL;
+
+	/* Find endpoints that we need */
+	for ( i = 0; i < uif->bNumEndpoints; ++i) {
+		ep = &uif->endpoint[i];
+
+		switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+			case USB_ENDPOINT_XFER_BULK:
+				if (ep->bEndpointAddress & USB_DIR_IN)
+					bulk_in_ep  = ep;
+				else
+					bulk_out_ep = ep;
+				break;
+
+			case USB_ENDPOINT_XFER_INT:
+				intr_in_ep = ep;
+				break;
+		};
+	}
+
+	if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) {
+		DBG("Endpoints not found: %p %p %p", bulk_in_ep, bulk_out_ep, intr_in_ep);
+		MOD_DEC_USE_COUNT;
+		return NULL;
+	}
+
+	if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) {
+		ERR("Can't allocate: control structure");
+		MOD_DEC_USE_COUNT;
+		return NULL;
+	}
+
+	memset(husb, 0, sizeof(struct hci_usb));
+
+	husb->udev = udev;
+	husb->bulk_out_ep_addr = bulk_out_ep->bEndpointAddress;
+
+	if (!(husb->ctrl_urb = usb_alloc_urb(0))) {
+		ERR("Can't allocate: control URB");
+		goto probe_error;
+	}
+
+	if (!(husb->write_urb = usb_alloc_urb(0))) {
+		ERR("Can't allocate: write URB");
+		goto probe_error;
+	}
+
+	if (!(husb->read_urb = usb_alloc_urb(0))) {
+		ERR("Can't allocate: read URB");
+		goto probe_error;
+	}
+
+	ep = bulk_in_ep;
+	pipe = usb_rcvbulkpipe(udev, ep->bEndpointAddress);
+	size = HCI_USB_MAX_READ;
+
+	if (!(buf = kmalloc(size, GFP_KERNEL))) {
+		ERR("Can't allocate: read buffer");
+		goto probe_error;
+	}
+
+	FILL_BULK_URB(husb->read_urb, udev, pipe, buf, size, hci_usb_bulk_read, husb);
+	husb->read_urb->transfer_flags |= USB_QUEUE_BULK;
+
+	ep = intr_in_ep;
+	pipe = usb_rcvintpipe(udev, ep->bEndpointAddress);
+	size = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+
+	if (!(husb->intr_urb = usb_alloc_urb(0))) {
+		ERR("Can't allocate: interrupt URB");
+		goto probe_error;
+	}
+
+	if (!(buf = kmalloc(size, GFP_KERNEL))) {
+		ERR("Can't allocate: interrupt buffer");
+		goto probe_error;
+	}
+
+	FILL_INT_URB(husb->intr_urb, udev, pipe, buf, size, hci_usb_intr, husb, ep->bInterval);
+
+	skb_queue_head_init(&husb->tx_ctrl_q);
+	skb_queue_head_init(&husb->tx_write_q);
+
+	/* Initialize and register HCI device */
+	hdev = &husb->hdev;
+
+	hdev->type = HCI_USB;
+	hdev->driver_data = husb;
+
+	hdev->open  = hci_usb_open;
+	hdev->close = hci_usb_close;
+	hdev->flush = hci_usb_flush;
+	hdev->send	= hci_usb_send_frame;
+
+	if (hci_register_dev(hdev) < 0) {
+		ERR("Can't register HCI device %s", hdev->name);
+		goto probe_error;
+	}
+
+	return husb;
+
+probe_error:
+	hci_usb_free_bufs(husb);
+	kfree(husb);
+	MOD_DEC_USE_COUNT;
+	return NULL;
+}
+
+static void hci_usb_disconnect(struct usb_device *udev, void *ptr)
+{
+	struct hci_usb *husb = (struct hci_usb *) ptr;
+	struct hci_dev *hdev = &husb->hdev;
+
+	if (!husb)
+		return;
+
+	DBG("%s", hdev->name);
+
+	hci_usb_close(hdev);
+
+	if (hci_unregister_dev(hdev) < 0) {
+		ERR("Can't unregister HCI device %s", hdev->name);
+	}
+
+	hci_usb_free_bufs(husb);
+	kfree(husb);
+
+	MOD_DEC_USE_COUNT;
+}
+
+static struct usb_driver hci_usb_driver =
+{
+	name:           "hci_usb",
+	probe:          hci_usb_probe,
+	disconnect:     hci_usb_disconnect,
+	id_table:       usb_bluetooth_ids,
+};
+
+int hci_usb_init(void)
+{
+	int err;
+
+	INF("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
+		BLUEZ_VER);
+	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+
+	if ((err = usb_register(&hci_usb_driver)) < 0)
+		ERR("Failed to register HCI USB driver");
+
+	return err;
+}
+
+void hci_usb_cleanup(void)
+{
+	usb_deregister(&hci_usb_driver);
+}
+
+module_init(hci_usb_init);
+module_exit(hci_usb_cleanup);
diff -u --recursive --new-file v2.4.5/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.4.5/linux/drivers/char/console.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/console.c	Tue Jun 12 11:17:17 2001
@@ -103,8 +103,6 @@
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
 
-#include <asm/linux_logo.h>
-
 #include "console_macros.h"
 
 
@@ -2684,7 +2682,7 @@
 void poke_blanked_console(void)
 {
 	del_timer(&console_timer);	/* Can't use _sync here: called from tasklet */
-	if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+	if (!vt_cons[fg_console] || vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
 		return;
 	if (console_blanked) {
 		console_timer.function = unblank_screen_t;
diff -u --recursive --new-file v2.4.5/linux/drivers/char/drm/ffb_drv.c linux/drivers/char/drm/ffb_drv.c
--- v2.4.5/linux/drivers/char/drm/ffb_drv.c	Sun May 20 12:11:38 2001
+++ linux/drivers/char/drm/ffb_drv.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: ffb_drv.c,v 1.12 2001/04/14 01:12:03 davem Exp $
+/* $Id: ffb_drv.c,v 1.14 2001/05/24 12:01:47 davem Exp $
  * ffb_drv.c: Creator/Creator3D direct rendering driver.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -719,9 +719,19 @@
 	current->state = TASK_RUNNING;
 	remove_wait_queue(&dev->lock.lock_queue, &entry);
 
-        if (!ret &&
-	    (dev->last_context != lock.context))
-		ffb_context_switch(dev, dev->last_context, lock.context);
+        if (!ret) {
+		sigemptyset(&dev->sigmask);
+		sigaddset(&dev->sigmask, SIGSTOP);
+		sigaddset(&dev->sigmask, SIGTSTP);
+		sigaddset(&dev->sigmask, SIGTTIN);
+		sigaddset(&dev->sigmask, SIGTTOU);
+		dev->sigdata.context = lock.context;
+		dev->sigdata.lock = dev->lock.hw_lock;
+		block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
+
+		if (dev->last_context != lock.context)
+			ffb_context_switch(dev, dev->last_context, lock.context);
+	}
 
         DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
 
@@ -770,6 +780,7 @@
 
 	wake_up_interruptible(&dev->lock.lock_queue);
 	
+	unblock_all_signals();
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/char/random.c linux/drivers/char/random.c
--- v2.4.5/linux/drivers/char/random.c	Tue May  1 16:05:00 2001
+++ linux/drivers/char/random.c	Tue Jun 12 11:49:36 2001
@@ -1793,7 +1793,7 @@
 			 void *newval, size_t newlen, void **context)
 {
 	unsigned char	tmp_uuid[16], *uuid;
-	int	len;
+	unsigned int	len;
 
 	if (!oldval || !oldlenp)
 		return 1;
@@ -1810,7 +1810,7 @@
 	if (len) {
 		if (len > 16)
 			len = 16;
-		if (copy_to_user(oldval, table->data, len))
+		if (copy_to_user(oldval, uuid, len))
 			return -EFAULT;
 		if (put_user(len, oldlenp))
 			return -EFAULT;
diff -u --recursive --new-file v2.4.5/linux/drivers/char/rio/rioroute.c linux/drivers/char/rio/rioroute.c
--- v2.4.5/linux/drivers/char/rio/rioroute.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/rio/rioroute.c	Mon Jun 11 19:15:27 2001
@@ -657,6 +657,7 @@
 			*/
 			if (PortP->TxStart == 0) {
 					rio_dprintk (RIO_DEBUG_ROUTE, "Tx pkts not set up yet\n");
+					rio_spin_unlock_irqrestore(&PortP->portSem, flags);
 					break;
 			}
 
diff -u --recursive --new-file v2.4.5/linux/drivers/char/rtc.c linux/drivers/char/rtc.c
--- v2.4.5/linux/drivers/char/rtc.c	Thu Jan  4 12:50:17 2001
+++ linux/drivers/char/rtc.c	Tue Jun 12 11:08:46 2001
@@ -73,6 +73,9 @@
 
 #ifdef __sparc__
 #include <asm/ebus.h>
+#ifdef __sparc_v9__
+#include <asm/isa.h>
+#endif
 
 static unsigned long rtc_port;
 static int rtc_irq;
@@ -622,22 +625,37 @@
 #ifdef __sparc__
 	struct linux_ebus *ebus;
 	struct linux_ebus_device *edev;
+#ifdef __sparc_v9__
+	struct isa_bridge *isa_br;
+	struct isa_device *isa_dev;
+#endif
 #endif
 
 #ifdef __sparc__
 	for_each_ebus(ebus) {
 		for_each_ebusdev(edev, ebus) {
 			if(strcmp(edev->prom_name, "rtc") == 0) {
+				rtc_port = edev->resource[0].start;
+				rtc_irq = edev->irqs[0];
 				goto found;
 			}
 		}
 	}
+#ifdef __sparc_v9__
+	for_each_isa(isa_br) {
+		for_each_isadev(isa_dev, isa_br) {
+			if (strcmp(isa_dev->prom_name, "rtc") == 0) {
+				rtc_port = isa_dev->resource.start;
+				rtc_irq = isa_dev->irq;
+				goto found;
+			}
+		}
+	}
+#endif
 	printk(KERN_ERR "rtc_init: no PC rtc found\n");
 	return -EIO;
 
 found:
-	rtc_port = edev->resource[0].start;
-	rtc_irq = edev->irqs[0];
 	/*
 	 * XXX Interrupt pin #7 in Espresso is shared between RTC and
 	 * PCI Slot 2 INTA# (and some INTx# in Slot 1). SA_INTERRUPT here
diff -u --recursive --new-file v2.4.5/linux/drivers/i2o/i2o_lan.c linux/drivers/i2o/i2o_lan.c
--- v2.4.5/linux/drivers/i2o/i2o_lan.c	Sun May 20 12:11:38 2001
+++ linux/drivers/i2o/i2o_lan.c	Mon Jun 11 19:15:27 2001
@@ -984,7 +984,7 @@
 		__raw_writel(priv->unit << 16 | lan_send_context, msg+2); // InitiatorContext
 		__raw_writel(1 << 30 | 1 << 3, msg+3); 		 	  // TransmitControlWord
 			// bit 30: reply as soon as transmission attempt is complete
-			// bit 3: Supress CRC generation
+			// bit 3: Suppress CRC generation
 		__raw_writel(0xD5000000 | skb->len, msg+4);  	     // MAC hdr included
 		__raw_writel((u32)skb, msg+5);  		     // TransactionContext
 		__raw_writel(virt_to_bus(skb->data), msg+6);
diff -u --recursive --new-file v2.4.5/linux/drivers/ide/ide-floppy.c linux/drivers/ide/ide-floppy.c
--- v2.4.5/linux/drivers/ide/ide-floppy.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/ide/ide-floppy.c	Thu Jun 14 14:16:58 2001
@@ -237,7 +237,7 @@
 	idefloppy_flexible_disk_page_t flexible_disk_page;	/* Copy of the flexible disk page */
 	int wp;							/* Write protect */
 
-	unsigned int flags;			/* Status/Action flags */
+	unsigned long flags;			/* Status/Action flags */
 } idefloppy_floppy_t;
 
 /*
diff -u --recursive --new-file v2.4.5/linux/drivers/ide/ide-pci.c linux/drivers/ide/ide-pci.c
--- v2.4.5/linux/drivers/ide/ide-pci.c	Sun May 20 11:32:11 2001
+++ linux/drivers/ide/ide-pci.c	Wed Jun 20 11:16:01 2001
@@ -34,7 +34,8 @@
 #define DEVID_PIIX4U	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801AA_1})
 #define DEVID_PIIX4U2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82372FB_1})
 #define DEVID_PIIX4NX	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82451NX})
-#define DEVID_PIIX4U3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82820FW_5})
+#define DEVID_PIIX4U3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_9})
+#define DEVID_PIIX4U4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_8})
 #define DEVID_VIA_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C561})
 #define DEVID_VP_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_1})
 #define DEVID_PDC20246	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
@@ -343,6 +344,7 @@
 	{DEVID_PIIX4U2,	"PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
 	{DEVID_PIIX4NX,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
 	{DEVID_PIIX4U3,	"PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
+	{DEVID_PIIX4U4, "PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
 	{DEVID_VIA_IDE,	"VIA_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_VP_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
 	{DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
diff -u --recursive --new-file v2.4.5/linux/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c
--- v2.4.5/linux/drivers/ide/ide-tape.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/ide/ide-tape.c	Tue Jun 12 11:09:03 2001
@@ -1,8 +1,10 @@
 /*
- * linux/drivers/ide/ide-tape.c		Version 1.16f	Dec  15, 1999
+ * linux/drivers/ide/ide-tape.c		Version 1.17a	Jan, 2001
  *
  * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
  *
+ * $Header$
+ *
  * This driver was constructed as a student project in the software laboratory
  * of the faculty of electrical engineering in the Technion - Israel's
  * Institute Of Technology, with the guide of Avner Lottem and Dr. Ilana David.
@@ -274,7 +276,21 @@
  *			this section correctly, a hypothetical and unwanted situation
  *			 is being described)
  * Ver 1.16f Dec 15 99   Change place of the secondary OnStream header frames.
- *
+ * Ver 1.17  Nov 2000 / Jan 2001  Marcel Mol, marcel@mesa.nl
+ *			- Add idetape_onstream_mode_sense_tape_parameter_page
+ *			  function to get tape capacity in frames: tape->capacity.
+ *			- Add support for DI-50 drives( or any DI- drive).
+ *			- 'workaround' for read error/blank block arround block 3000.
+ *			- Implement Early warning for end of media for Onstream.
+ *			- Cosmetic code changes for readability.
+ *			- Idetape_position_tape should not use SKIP bit during
+ *			  Onstream read recovery.
+ *			- Add capacity, logical_blk_num and first/last_frame_position
+ *			  to /proc/ide/hd?/settings.
+ *			- Module use count was gone in the Linux 2.4 driver.
+ * Ver 1.17a Apr 2001 Willem Riede osst@riede.org
+ * 			- Get drive's actual block size from mode sense block descriptor
+ * 			- Limit size of pipeline
  *
  * Here are some words from the first releases of hd.c, which are quoted
  * in ide.c and apply here as well:
@@ -384,7 +400,7 @@
  *		sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
  */
 
-#define IDETAPE_VERSION "1.16f"
+#define IDETAPE_VERSION "1.17a"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -421,7 +437,11 @@
 #define OS_CONFIG_PARTITION	(0xff)
 #define OS_DATA_PARTITION	(0)
 #define OS_PARTITION_VERSION	(1)
+#define OS_EW			300
+#define OS_ADR_MINREV		2
 
+#define OS_DATA_STARTFRAME1	20
+#define OS_DATA_ENDFRAME1	2980
 /*
  * partition
  */
@@ -512,12 +532,33 @@
 } os_header_t;
 
 /*
+ *	OnStream Tape Parameters Page
+ */
+typedef struct {
+	unsigned	page_code	:6;	/* Page code - Should be 0x2b */
+	unsigned	reserved1_6	:1;
+	unsigned	ps		:1;
+	__u8		reserved2;
+	__u8		density;		/* kbpi */
+	__u8		reserved3,reserved4;
+	__u16		segtrk;                 /* segment of per track */
+	__u16		trks;                   /* tracks per tape */
+	__u8		reserved5,reserved6,reserved7,reserved8,reserved9,reserved10;
+} onstream_tape_paramtr_page_t;
+
+/*
  * OnStream ADRL frame
  */
 #define OS_FRAME_SIZE	(32 * 1024 + 512)
 #define OS_DATA_SIZE	(32 * 1024)
 #define OS_AUX_SIZE	(512)
 
+/*
+ * internal error codes for onstream
+ */
+#define OS_PART_ERROR    2
+#define OS_WRITE_ERROR   1
+
 #include <linux/mtio.h>
 
 /**************************** Tunable parameters *****************************/
@@ -559,7 +600,7 @@
  *	is verified to be stable enough. This will make it much more
  *	esthetic.
  */
-#define IDETAPE_DEBUG_INFO		0
+#define IDETAPE_DEBUG_INFO		1
 #define IDETAPE_DEBUG_LOG		1
 #define IDETAPE_DEBUG_LOG_VERBOSE	0
 #define IDETAPE_DEBUG_BUGS		1
@@ -949,6 +990,7 @@
 	int eod_frame_addr;
 	unsigned long cmd_start_time;
 	unsigned long max_cmd_time;
+	unsigned capacity;
 
 	/*
 	 * Optimize the number of "buffer filling"
@@ -1157,7 +1199,7 @@
 typedef union {
 	unsigned all			:8;
 	struct {
-		unsigned dma		:1;	/* Using DMA of PIO */
+		unsigned dma		:1;	/* Using DMA or PIO */
 		unsigned reserved321	:3;	/* Reserved */
 		unsigned reserved654	:3;	/* Reserved (Tag Type) */
 		unsigned reserved7	:1;	/* Reserved */
@@ -1286,8 +1328,11 @@
  *	packet commands. Those packet commands are still not supported
  *	by ide-tape.
  */
+#define IDETAPE_BLOCK_DESCRIPTOR	0
 #define	IDETAPE_CAPABILITIES_PAGE	0x2a
+#define IDETAPE_PARAMTR_PAGE		0x2b   /* Onstream DI-x0 only */
 #define IDETAPE_BLOCK_SIZE_PAGE		0x30
+#define IDETAPE_BUFFER_FILLING_PAGE	0x33
 
 /*
  *	Mode Parameter Header for the MODE SENSE packet command
@@ -1428,6 +1473,14 @@
 #endif /* IDETAPE_DEBUG_LOG_VERBOSE */
 
 /*
+ *      Function declarations
+ *
+ */
+static void idetape_onstream_mode_sense_tape_parameter_page(ide_drive_t *drive, int debug);
+static int idetape_chrdev_release (struct inode *inode, struct file *filp);
+static void idetape_write_release (struct inode *inode);
+
+/*
  *	Too bad. The drive wants to send us data which we are not ready to accept.
  *	Just throw it away.
  */
@@ -1452,7 +1505,8 @@
 #endif /* IDETAPE_DEBUG_BUGS */
 		count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), bcount);
 		atapi_input_bytes (drive, bh->b_data + atomic_read(&bh->b_count), count);
-		bcount -= count; atomic_add(count, &bh->b_count);
+		bcount -= count;
+		atomic_add(count, &bh->b_count);
 		if (atomic_read(&bh->b_count) == bh->b_size) {
 			bh = bh->b_reqnext;
 			if (bh)
@@ -1476,7 +1530,9 @@
 #endif /* IDETAPE_DEBUG_BUGS */
 		count = IDE_MIN (pc->b_count, bcount);
 		atapi_output_bytes (drive, pc->b_data, count);
-		bcount -= count; pc->b_data += count; pc->b_count -= count;
+		bcount -= count;
+		pc->b_data += count;
+		pc->b_count -= count;
 		if (!pc->b_count) {
 			pc->bh = bh = bh->b_reqnext;
 			if (bh) {
@@ -1577,20 +1633,23 @@
  *	to analyze the request sense. We currently do not utilize this
  *	information.
  */
-static void idetape_analyze_error (ide_drive_t *drive,idetape_request_sense_result_t *result)
+static void idetape_analyze_error (ide_drive_t *drive, idetape_request_sense_result_t *result)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->failed_pc;
 
-	tape->sense = *result;
-	tape->sense_key = result->sense_key; tape->asc = result->asc; tape->ascq = result->ascq;
+	tape->sense     = *result;
+	tape->sense_key = result->sense_key;
+	tape->asc       = result->asc;
+	tape->ascq      = result->ascq;
 #if IDETAPE_DEBUG_LOG
 	/*
 	 *	Without debugging, we only log an error if we decided to
 	 *	give up retrying.
 	 */
 	if (tape->debug_level >= 1)
-		printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",pc->c[0],result->sense_key,result->asc,result->ascq);
+		printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",
+				pc->c[0], result->sense_key, result->asc, result->ascq);
 #if IDETAPE_DEBUG_LOG_VERBOSE
 	if (tape->debug_level >= 1)
 		printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, asc = %x, ascq = %x\n",
@@ -1660,7 +1719,7 @@
 static void idetape_active_next_stage (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	idetape_stage_t *stage=tape->next_stage;
+	idetape_stage_t *stage = tape->next_stage;
 	struct request *rq = &stage->rq;
 
 #if IDETAPE_DEBUG_LOG
@@ -1676,9 +1735,9 @@
 
 	rq->buffer = NULL;
 	rq->bh = stage->bh;
-	tape->active_data_request=rq;
-	tape->active_stage=stage;
-	tape->next_stage=stage->next;
+	tape->active_data_request = rq;
+	tape->active_stage = stage;
+	tape->next_stage = stage->next;
 }
 
 /*
@@ -1756,12 +1815,12 @@
 		return;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
-	stage=tape->first_stage;
-	tape->first_stage=stage->next;
+	stage = tape->first_stage;
+	tape->first_stage = stage->next;
 	idetape_kfree_stage (tape, stage);
 	tape->nr_stages--;
 	if (tape->first_stage == NULL) {
-		tape->last_stage=NULL;
+		tape->last_stage = NULL;
 #if IDETAPE_DEBUG_BUGS
 		if (tape->next_stage != NULL)
 			printk (KERN_ERR "ide-tape: bug: tape->next_stage != NULL\n");
@@ -1821,12 +1880,12 @@
 			}
 #endif
 			if (tape->onstream && !tape->raw) {
-				if (tape->first_frame_position == 0xba4) {
+				if (tape->first_frame_position == OS_DATA_ENDFRAME1) { 
 #if ONSTREAM_DEBUG
-				if (tape->debug_level >= 2)
-					printk("ide-tape: %s: skipping over config parition..\n", tape->name);
+					if (tape->debug_level >= 2)
+						printk("ide-tape: %s: skipping over config parition..\n", tape->name);
 #endif
-					tape->onstream_write_error = 2;
+					tape->onstream_write_error = OS_PART_ERROR;
 					if (tape->sem)
 						up(tape->sem);
 				}
@@ -1839,7 +1898,7 @@
 				if (tape->onstream && !tape->raw && error == IDETAPE_ERROR_GENERAL && tape->sense.sense_key == 3) {
 					clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
 					printk(KERN_ERR "ide-tape: %s: write error, enabling error recovery\n", tape->name);
-					tape->onstream_write_error = 1;
+					tape->onstream_write_error = OS_WRITE_ERROR;
 					remove_stage = 0;
 					tape->nr_pending_stages++;
 					tape->next_stage = tape->first_stage;
@@ -1883,11 +1942,11 @@
 		printk (KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n");
 #endif /* IDETAPE_DEBUG_LOG */
 	if (!tape->pc->error) {
-		idetape_analyze_error (drive,(idetape_request_sense_result_t *) tape->pc->buffer);
-		idetape_end_request (1,HWGROUP (drive));
+		idetape_analyze_error (drive, (idetape_request_sense_result_t *) tape->pc->buffer);
+		idetape_end_request (1, HWGROUP (drive));
 	} else {
 		printk (KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n");
-		idetape_end_request (0,HWGROUP (drive));
+		idetape_end_request (0, HWGROUP (drive));
 	}
 	return ide_stopped;
 }
@@ -1980,7 +2039,7 @@
 	idetape_status_reg_t status;
 	idetape_bcount_reg_t bcount;
 	idetape_ireason_reg_t ireason;
-	idetape_pc_t *pc=tape->pc;
+	idetape_pc_t *pc = tape->pc;
 
 	unsigned int temp;
 	unsigned long cmd_time;
@@ -2011,7 +2070,7 @@
 			 */
 			set_bit (PC_DMA_ERROR, &pc->flags);
 		} else if (!status.b.check) {
-			pc->actually_transferred=pc->request_transfer;
+			pc->actually_transferred = pc->request_transfer;
 			idetape_update_buffers (pc);
 		}
 #if IDETAPE_DEBUG_LOG
@@ -2064,7 +2123,7 @@
 			return ide_stopped;
 		}
 		if (tape->failed_pc == pc)
-			tape->failed_pc=NULL;
+			tape->failed_pc = NULL;
 		return pc->callback(drive);			/* Command finished - Call the callback function */
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -2075,9 +2134,9 @@
 		return ide_do_reset (drive);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-	bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
-	bcount.b.low=IN_BYTE (IDE_BCOUNTL_REG);				/* on this interrupt */
-	ireason.all=IN_BYTE (IDE_IREASON_REG);
+	bcount.b.high = IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
+	bcount.b.low  = IN_BYTE (IDE_BCOUNTL_REG);			/* on this interrupt */
+	ireason.all   = IN_BYTE (IDE_IREASON_REG);
 
 	if (ireason.b.cod) {
 		printk (KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
@@ -2093,8 +2152,8 @@
 		if ( temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
 				printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
-				idetape_discard_data (drive,bcount.all);
-				ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD,NULL);
+				idetape_discard_data (drive, bcount.all);
+				ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
 				return ide_started;
 			}
 #if IDETAPE_DEBUG_LOG
@@ -2114,13 +2173,13 @@
 		else
 			atapi_input_bytes (drive,pc->current_position,bcount.all);	/* Read the current buffer */
 	}
-	pc->actually_transferred+=bcount.all;					/* Update the current position */
+	pc->actually_transferred += bcount.all;					/* Update the current position */
 	pc->current_position+=bcount.all;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
 		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
 #endif
-	ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD,NULL);		/* And set the interrupt handler again */
+	ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* And set the interrupt handler again */
 	return ide_started;
 }
 
@@ -2178,7 +2237,7 @@
 		printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason.all=IN_BYTE (IDE_IREASON_REG);
+	ireason.all = IN_BYTE (IDE_IREASON_REG);
 	while (retries-- && (!ireason.b.cod || ireason.b.io)) {
 		printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, retrying\n");
 		udelay(100);
@@ -2203,7 +2262,7 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_bcount_reg_t bcount;
-	int dma_ok=0;
+	int dma_ok = 0;
 
 #if IDETAPE_DEBUG_BUGS
 	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
@@ -2212,8 +2271,8 @@
 #endif /* IDETAPE_DEBUG_BUGS */
 
 	if (tape->failed_pc == NULL && pc->c[0] != IDETAPE_REQUEST_SENSE_CMD)
-		tape->failed_pc=pc;
-	tape->pc=pc;							/* Set the current packet command */
+		tape->failed_pc = pc;
+	tape->pc = pc;							/* Set the current packet command */
 
 	if (pc->retries > IDETAPE_MAX_PC_RETRIES || test_bit (PC_ABORT, &pc->flags)) {
 		/*
@@ -2223,24 +2282,25 @@
 		 *	example).
 		 */
 		if (!test_bit (PC_ABORT, &pc->flags)) {
-			if (!(pc->c[0] == 0 && tape->sense_key == 2 && tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8))) {
+			if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD && tape->sense_key == 2 &&
+			      tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8))) {
 				printk (KERN_ERR "ide-tape: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
 					tape->name, pc->c[0], tape->sense_key, tape->asc, tape->ascq);
-				if (tape->onstream && pc->c[0] == 8 && tape->sense_key == 3 && tape->asc == 0x11)  /* AJN-1: 11 should be 0x11 */
+				if (tape->onstream && pc->c[0] == IDETAPE_READ_CMD && tape->sense_key == 3 && tape->asc == 0x11)  /* AJN-1: 11 should be 0x11 */
 					printk(KERN_ERR "ide-tape: %s: enabling read error recovery\n", tape->name);
 			}
 			pc->error = IDETAPE_ERROR_GENERAL;		/* Giving up */
 		}
-		tape->failed_pc=NULL;
+		tape->failed_pc = NULL;
 		return pc->callback(drive);
 	}
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: Retry number - %d\n",pc->retries);
+		printk (KERN_INFO "ide-tape: Retry number - %d\n", pc->retries);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	pc->retries++;
-	pc->actually_transferred=0;					/* We haven't transferred any data yet */
+	pc->actually_transferred = 0;					/* We haven't transferred any data yet */
 	pc->current_position=pc->buffer;
 	bcount.all=pc->request_transfer;				/* Request to transfer the entire buffer at once */
 
@@ -2250,15 +2310,15 @@
 		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
 	}
 	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+		dma_ok = !HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);			/* Use PIO/DMA */
-	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
-	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
+		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
+	OUT_BYTE (dma_ok ? 1 : 0,    IDE_FEATURE_REG);			/* Use PIO/DMA */
+	OUT_BYTE (bcount.b.high,     IDE_BCOUNTH_REG);
+	OUT_BYTE (bcount.b.low,      IDE_BCOUNTL_REG);
+	OUT_BYTE (drive->select.all, IDE_SELECT_REG);
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (dma_ok) {						/* Begin DMA, if necessary */
 		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
@@ -2287,7 +2347,7 @@
 		printk (KERN_INFO "ide-tape: Reached idetape_pc_callback\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
-	idetape_end_request (tape->pc->error ? 0:1, HWGROUP(drive));
+	idetape_end_request (tape->pc->error ? 0 : 1, HWGROUP(drive));
 	return ide_stopped;
 }
 
@@ -2298,11 +2358,14 @@
 {
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_MODE_SENSE_CMD;
-	pc->c[1] = 8;				/* DBD = 1 - Don't return block descriptors for now */
+	if (page_code != IDETAPE_BLOCK_DESCRIPTOR)
+		pc->c[1] = 8;			/* DBD = 1 - Don't return block descriptors */
 	pc->c[2] = page_code;
 	pc->c[3] = 255;				/* Don't limit the returned information */
 	pc->c[4] = 255;				/* (We will just discard data in that case) */
-	if (page_code == IDETAPE_CAPABILITIES_PAGE)
+	if (page_code == IDETAPE_BLOCK_DESCRIPTOR)
+		pc->request_transfer = 12;
+	else if (page_code == IDETAPE_CAPABILITIES_PAGE)
 		pc->request_transfer = 24;
 	else
 		pc->request_transfer = 50;
@@ -2333,7 +2396,7 @@
 	if (tape->debug_level >= 1)
 		printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n", tape->cur_frames, tape->max_frames);
 #endif
-	idetape_end_request (tape->pc->error ? 0:1, HWGROUP(drive));
+	idetape_end_request (tape->pc->error ? 0 : 1, HWGROUP(drive));
 	return ide_stopped;
 }
 
@@ -2344,7 +2407,7 @@
 
 	pc = idetape_next_pc_storage (drive);
 	rq = idetape_next_rq_storage (drive);
-	idetape_create_mode_sense_cmd (pc, 0x33);
+	idetape_create_mode_sense_cmd (pc, IDETAPE_BUFFER_FILLING_PAGE);
 	pc->callback = idetape_onstream_buffer_fill_callback;
 	idetape_queue_pc_head (drive, pc, rq);
 }
@@ -2564,7 +2627,7 @@
 		 *	We do not support buffer cache originated requests.
 		 */
 		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%d)\n", drive->name, rq->cmd);
-		ide_end_request (0,HWGROUP (drive));			/* Let the common code handle it */
+		ide_end_request (0, HWGROUP (drive));			/* Let the common code handle it */
 		return ide_stopped;
 	}
 
@@ -2578,7 +2641,7 @@
 	if (postponed_rq != NULL)
 		if (rq != postponed_rq) {
 			printk (KERN_ERR "ide-tape: ide-tape.c bug - Two DSC requests were queued\n");
-			idetape_end_request (0,HWGROUP (drive));
+			idetape_end_request (0, HWGROUP (drive));
 			return ide_stopped;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -2624,8 +2687,15 @@
 		tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
 	calculate_speeds(drive);
 	if (tape->onstream && tape->max_frames &&
-	   ((rq->cmd == IDETAPE_WRITE_RQ && (tape->cur_frames == tape->max_frames || (tape->speed_control && tape->cur_frames > 5 && (tape->insert_speed > tape->max_insert_speed || (0 /* tape->cur_frames > 30 && tape->tape_still_time > 200 */))))) ||
-	    (rq->cmd == IDETAPE_READ_RQ && (tape->cur_frames == 0 || (tape->speed_control && (tape->cur_frames < tape->max_frames - 5) && tape->insert_speed > tape->max_insert_speed)) && rq->nr_sectors))) {
+	    ((rq->cmd == IDETAPE_WRITE_RQ &&
+              ( tape->cur_frames == tape->max_frames ||
+                ( tape->speed_control && tape->cur_frames > 5 &&
+                       (tape->insert_speed > tape->max_insert_speed ||
+                        (0 /* tape->cur_frames > 30 && tape->tape_still_time > 200 */) ) ) ) ) ||
+	     (rq->cmd == IDETAPE_READ_RQ &&
+	      ( tape->cur_frames == 0 ||
+		( tape->speed_control && (tape->cur_frames < tape->max_frames - 5) &&
+			tape->insert_speed > tape->max_insert_speed ) ) && rq->nr_sectors) ) ) {
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 4)
 			printk(KERN_INFO "ide-tape: postponing request, cmd %d, cur %d, max %d\n",
@@ -2672,7 +2742,7 @@
 				if (jiffies > tape->last_buffer_fill + 5 * HZ / 100)
 					tape->req_buffer_fill = 1;
 			}
-			pc=idetape_next_pc_storage (drive);
+			pc = idetape_next_pc_storage (drive);
 			idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
 			break;
 		case IDETAPE_WRITE_RQ:
@@ -2689,12 +2759,12 @@
 					tape->req_buffer_fill = 1;
 				calculate_speeds(drive);
 			}
-			pc=idetape_next_pc_storage (drive);
+			pc = idetape_next_pc_storage (drive);
 			idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
 			break;
 		case IDETAPE_READ_BUFFER_RQ:
 			tape->postpone_cnt = 0;
-			pc=idetape_next_pc_storage (drive);
+			pc = idetape_next_pc_storage (drive);
 			idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
 			break;
 		case IDETAPE_ABORTED_WRITE_RQ:
@@ -2710,7 +2780,7 @@
 			idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
 			return ide_stopped;
 		case IDETAPE_PC_RQ1:
-			pc=(idetape_pc_t *) rq->buffer;
+			pc = (idetape_pc_t *) rq->buffer;
 			rq->cmd = IDETAPE_PC_RQ2;
 			break;
 		case IDETAPE_PC_RQ2:
@@ -2718,7 +2788,7 @@
 			return ide_stopped;
 		default:
 			printk (KERN_ERR "ide-tape: bug in IDETAPE_RQ_CMD macro\n");
-			idetape_end_request (0,HWGROUP (drive));
+			idetape_end_request (0, HWGROUP (drive));
 			return ide_stopped;
 	}
 	return idetape_issue_packet_command (drive, pc);
@@ -2844,7 +2914,9 @@
 #endif /* IDETAPE_DEBUG_BUGS */
 		count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), n);
 		copy_from_user (bh->b_data + atomic_read(&bh->b_count), buf, count);
-		n -= count; atomic_add(count, &bh->b_count); buf += count;
+		n -= count;
+		atomic_add(count, &bh->b_count);
+		buf += count;
 		if (atomic_read(&bh->b_count) == bh->b_size) {
 			bh = bh->b_reqnext;
 			if (bh)
@@ -2868,7 +2940,10 @@
 #endif /* IDETAPE_DEBUG_BUGS */
 		count = IDE_MIN (tape->b_count, n);
 		copy_to_user (buf, tape->b_data, count);
-		n -= count; tape->b_data += count; tape->b_count -= count; buf += count;
+		n -= count;
+		tape->b_data += count;
+		tape->b_count -= count;
+		buf += count;
 		if (!tape->b_count) {
 			tape->bh = bh = bh->b_reqnext;
 			if (bh) {
@@ -2920,10 +2995,10 @@
 	if (tape->last_stage != NULL)
 		tape->last_stage->next=stage;
 	else
-		tape->first_stage=tape->next_stage=stage;
-	tape->last_stage=stage;
+		tape->first_stage = tape->next_stage=stage;
+	tape->last_stage = stage;
 	if (tape->next_stage == NULL)
-		tape->next_stage=tape->last_stage;
+		tape->next_stage = tape->last_stage;
 	tape->nr_stages++;
 	tape->nr_pending_stages++;
 	spin_unlock_irqrestore(&tape->spinlock, flags);
@@ -2953,26 +3028,21 @@
 		par->par_desc_ver = OS_PARTITION_VERSION;
 		par->wrt_pass_cntr = htons(0xffff);
 		par->first_frame_addr = htonl(0);
-		par->last_frame_addr = htonl(0xbb7);
+		par->last_frame_addr = htonl(0xbb7); /* 2999 */
+		aux->frame_seq_num = htonl(0);
+		aux->logical_blk_num_high = htonl(0);
+		aux->logical_blk_num = htonl(0);
+		aux->next_mark_addr = htonl(tape->first_mark_addr);
 	} else {
 		aux->update_frame_cntr = htonl(0);
 		par->partition_num = OS_DATA_PARTITION;
 		par->par_desc_ver = OS_PARTITION_VERSION;
 		par->wrt_pass_cntr = htons(tape->wrt_pass_cntr);
-		par->first_frame_addr = htonl(0x14);
-		par->last_frame_addr = htonl(19239 * 24);
-	}
-	if (frame_type != OS_FRAME_TYPE_HEADER) {
+		par->first_frame_addr = htonl(OS_DATA_STARTFRAME1);
+		par->last_frame_addr = htonl(tape->capacity);
 		aux->frame_seq_num = htonl(logical_blk_num);
 		aux->logical_blk_num_high = htonl(0);
 		aux->logical_blk_num = htonl(logical_blk_num);
-	} else {
-		aux->frame_seq_num = htonl(0);
-		aux->logical_blk_num_high = htonl(0);
-		aux->logical_blk_num = htonl(0);
-	}
-
-	if (frame_type != OS_FRAME_TYPE_HEADER) {
 		dat->dat_sz = 8;
 		dat->reserved1 = 0;
 		dat->entry_cnt = 1;
@@ -2987,11 +3057,10 @@
 		else
 			dat->dat_list[0].flags = OS_DAT_FLAGS_DATA;
 		dat->dat_list[0].reserved = 0;
-	} else
-		aux->next_mark_addr = htonl(tape->first_mark_addr);
-	aux->filemark_cnt = ntohl(tape->filemark_cnt);
-	aux->phys_fm = ntohl(0xffffffff);
-	aux->last_mark_addr = ntohl(tape->last_mark_addr);
+	} 
+	aux->filemark_cnt = ntohl(tape->filemark_cnt);		/* shouldn't this be htonl ?? */
+	aux->phys_fm = ntohl(0xffffffff);			/* shouldn't this be htonl ?? */
+	aux->last_mark_addr = ntohl(tape->last_mark_addr);	/* shouldn't this be htonl ?? */
 }
 
 /*
@@ -3026,10 +3095,10 @@
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_read_position_result_t *result;
 	
-#if IDETAPE_DEBUG_LOG
-	if (tape->debug_level >= 4)
+//#if IDETAPE_DEBUG_LOG
+//	if (tape->debug_level >= 4)
 		printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
+//#endif /* IDETAPE_DEBUG_LOG */
 
 	if (!tape->pc->error) {
 		result = (idetape_read_position_result_t *) tape->pc->buffer;
@@ -3042,7 +3111,7 @@
 		if (result->bpu) {
 			printk (KERN_INFO "ide-tape: Block location is unknown to the tape\n");
 			clear_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
-			idetape_end_request (0,HWGROUP (drive));
+			idetape_end_request (0, HWGROUP (drive));
 		} else {
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
@@ -3053,10 +3122,10 @@
 			tape->last_frame_position = ntohl (result->last_block);
 			tape->blocks_in_buffer = result->blocks_in_buffer[2];
 			set_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
-			idetape_end_request (1,HWGROUP (drive));
+			idetape_end_request (1, HWGROUP (drive));
 		}
 	} else {
-		idetape_end_request (0,HWGROUP (drive));
+		idetape_end_request (0, HWGROUP (drive));
 	}
 	return ide_stopped;
 }
@@ -3076,8 +3145,8 @@
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_WRITE_FILEMARK_CMD;
 	if (tape->onstream)
-		pc->c[1] = 1;
-	pc->c[4] = write_filemark;
+		pc->c[1] = 1; /* Immed bit */
+	pc->c[4] = write_filemark;  /* not used for OnStream ?? */
 	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
@@ -3109,7 +3178,7 @@
  *	the request to the request list without waiting for it to be serviced !
  *	In that case, we usually use idetape_queue_pc_head.
  */
-static int __idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc)
+static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc)
 {
 	struct request rq;
 
@@ -3150,7 +3219,7 @@
 			return 0;
 		if (tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2) {
 			idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK);
-			__idetape_queue_pc_tail(drive,&pc);
+			__idetape_queue_pc_tail(drive, &pc);
 			idetape_create_test_unit_ready_cmd(&pc);
 			if (!__idetape_queue_pc_tail(drive, &pc))
 				return 0;
@@ -3169,7 +3238,8 @@
 	int rc;
 
 	rc = __idetape_queue_pc_tail(drive, pc);
-	if (rc)	return rc;
+	if (rc)
+		return rc;
 	if (tape->onstream && test_bit(PC_WAIT_FOR_DSC, &pc->flags))
 		rc = idetape_wait_ready(drive, 60 * 10 * HZ);   /* AJN-4: Changed from 5 to 10 minutes;
                           because retension takes approx. 8:20 with Onstream 30GB tape */
@@ -3182,7 +3252,7 @@
 	int rc;
 
 	idetape_create_write_filemark_cmd(drive, &pc, 0);
-	if ((rc = idetape_queue_pc_tail (drive,&pc)))
+	if ((rc = idetape_queue_pc_tail (drive, &pc)))
 		return rc;
 	idetape_wait_ready(drive, 60 * 5 * HZ);
 	return 0;
@@ -3202,11 +3272,16 @@
 	idetape_pc_t pc;
 	int position;
 
+//#if IDETAPE_DEBUG_LOG
+//        if (tape->debug_level >= 4)
+	printk (KERN_INFO "ide-tape: Reached idetape_read_position\n");
+//#endif /* IDETAPE_DEBUG_LOG */
+
 #ifdef NO_LONGER_REQUIRED
 	idetape_flush_tape_buffers(drive);
 #endif
 	idetape_create_read_position_cmd(&pc);
-	if (idetape_queue_pc_tail (drive,&pc))
+	if (idetape_queue_pc_tail (drive, &pc))
 		return -1;
 	position = tape->first_frame_position;
 #ifdef NO_LONGER_REQUIRED
@@ -3231,12 +3306,17 @@
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_LOCATE_CMD;
 	if (tape->onstream)
-		pc->c[1] = 1;
+		pc->c[1] = 1; /* Immediate bit */
 	else
 		pc->c[1] = 2;
 	put_unaligned (htonl (block), (unsigned int *) &pc->c[3]);
 	pc->c[8] = partition;
 	if (tape->onstream)
+                /*
+                 * Set SKIP bit.
+                 * In case of write error this will write buffered
+                 * data in the drive to this new position!
+                 */
 		pc->c[9] = skip << 7;
 	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
@@ -3307,11 +3387,12 @@
 		__idetape_discard_read_pipeline(drive);
 	idetape_wait_ready(drive, 60 * 5 * HZ);
 	idetape_create_locate_cmd (drive, &pc, block, partition, skip);
-	retval=idetape_queue_pc_tail (drive,&pc);
-	if (retval) return (retval);
+	retval = idetape_queue_pc_tail (drive, &pc);
+	if (retval)
+		return (retval);
 
 	idetape_create_read_position_cmd (&pc);
-	return (idetape_queue_pc_tail (drive,&pc));
+	return (idetape_queue_pc_tail (drive, &pc));
 }
 
 static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_position)
@@ -3339,7 +3420,7 @@
 {
 	idetape_pc_t pc;
 
-	idetape_create_mode_sense_cmd (&pc, 0x33);
+	idetape_create_mode_sense_cmd (&pc, IDETAPE_BUFFER_FILLING_PAGE);
 	pc.callback = idetape_onstream_buffer_fill_callback;
 	(void) idetape_queue_pc_tail(drive, &pc);
 }
@@ -3447,33 +3528,41 @@
 	idetape_tape_t *tape = drive->driver_data;
 	unsigned int block;
 
-	if (tape->onstream_write_error == 1) {
-		printk(KERN_ERR "ide-tape: %s: detected physical bad block at %u\n", tape->name, ntohl(tape->sense.information));
-		block = ntohl(tape->sense.information) + 80;
+	if (tape->onstream_write_error == OS_WRITE_ERROR) {
+		printk(KERN_ERR "ide-tape: %s: onstream_write_error_recovery: detected physical bad block at %u, logical %u first frame %u last_frame %u bufblocks %u stages %u skipping %u frames\n",
+			tape->name, ntohl(tape->sense.information), tape->logical_blk_num,
+			tape->first_frame_position, tape->last_frame_position,
+			tape->blocks_in_buffer, tape->nr_stages,
+ 			(ntohl(tape->sense.command_specific) >> 16) & 0xff );
+		block = ntohl(tape->sense.information) + ((ntohl(tape->sense.command_specific) >> 16) & 0xff);
 		idetape_update_stats(drive);
 		printk(KERN_ERR "ide-tape: %s: relocating %d buffered logical blocks to physical block %u\n", tape->name, tape->cur_frames, block);
+#if 0  /* isn't once enough ??? MM */
 		idetape_update_stats(drive);
+#endif
 		if (tape->firmware_revision_num >= 106)
 			idetape_position_tape(drive, block, 0, 1);
 		else {
 			idetape_onstream_read_back_buffer(drive);
 			idetape_position_tape(drive, block, 0, 0);
 		}
+#if 0     /* already done in idetape_position_tape MM */
 		idetape_read_position(drive);
+#endif
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 1)
 			printk(KERN_ERR "ide-tape: %s: positioning complete, cur_frames %d, pos %d, tape pos %d\n", tape->name, tape->cur_frames, tape->first_frame_position, tape->last_frame_position);
 #endif
-	} else if (tape->onstream_write_error == 2) {
+	} else if (tape->onstream_write_error == OS_PART_ERROR) {
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 1)
 			printk(KERN_INFO "ide-tape: %s: skipping over config partition\n", tape->name);
 #endif
 		idetape_flush_tape_buffers(drive);
 		block = idetape_read_position(drive);
-		if (block != 0xba4) 
-			printk(KERN_ERR "ide-tape: warning, current position %d, expected %d\n", block, 0xba4);
-		idetape_position_tape(drive, 0xbb8, 0, 0);
+		if (block != OS_DATA_ENDFRAME1)  
+			printk(KERN_ERR "ide-tape: warning, current position %d, expected %d\n", block, OS_DATA_ENDFRAME1);
+		idetape_position_tape(drive, 0xbb8, 0, 0); /* 3000 */
 	}
 	tape->onstream_write_error = 0;
 }
@@ -3572,48 +3661,48 @@
 		return 1;
 	}
 	if (rq->errors == IDETAPE_ERROR_GENERAL) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame, read error\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, read error\n", tape->name, tape->first_frame_position);
 		return 0;
 	}
 	if (rq->errors == IDETAPE_ERROR_EOD) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame, eod\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, eod\n", tape->name, tape->first_frame_position);
 		return 0;
 	}
 	if (ntohl(aux->format_id) != 0) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame, format_id %u\n", tape->name, ntohl(aux->format_id));
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, format_id %u\n", tape->name, tape->first_frame_position, ntohl(aux->format_id));
 		return 0;
 	}
 	if (memcmp(aux->application_sig, tape->application_sig, 4) != 0) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame, incorrect application signature\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, incorrect application signature\n", tape->name, tape->first_frame_position);
 		return 0;
 	}
 	if (aux->frame_type != OS_FRAME_TYPE_DATA &&
 	    aux->frame_type != OS_FRAME_TYPE_EOD &&
 	    aux->frame_type != OS_FRAME_TYPE_MARKER) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame, frame type %x\n", tape->name, aux->frame_type);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, frame type %x\n", tape->name, tape->first_frame_position, aux->frame_type);
 		return 0;
 	}
 	if (par->partition_num != OS_DATA_PARTITION) {
 		if (!tape->linux_media || tape->linux_media_version != 2) {
-			printk(KERN_INFO "ide-tape: %s: skipping frame, partition num %d\n", tape->name, par->partition_num);
+			printk(KERN_INFO "ide-tape: %s: skipping frame %d, partition num %d\n", tape->name, tape->first_frame_position, par->partition_num);
 			return 0;
 		}
 	}
 	if (par->par_desc_ver != OS_PARTITION_VERSION) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame, partition version %d\n", tape->name, par->par_desc_ver);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, partition version %d\n", tape->name, tape->first_frame_position, par->par_desc_ver);
 		return 0;
 	}
 	if (ntohs(par->wrt_pass_cntr) != tape->wrt_pass_cntr) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame, wrt_pass_cntr %d (expected %d)(logical_blk_num %u)\n", tape->name, ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr, ntohl(aux->logical_blk_num));
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, wrt_pass_cntr %d (expected %d)(logical_blk_num %u)\n", tape->name, tape->first_frame_position, ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr, ntohl(aux->logical_blk_num));
 		return 0;
 	}
 	if (aux->frame_seq_num != aux->logical_blk_num) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame, seq != logical\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, seq != logical\n", tape->name, tape->first_frame_position);
 		return 0;
 	}
 	if (logical_blk_num != -1 && ntohl(aux->logical_blk_num) != logical_blk_num) {
 		if (!quiet)
-			printk(KERN_INFO "ide-tape: %s: skipping frame, logical_blk_num %u (expected %d)\n", tape->name, ntohl(aux->logical_blk_num), logical_blk_num);
+			printk(KERN_INFO "ide-tape: %s: skipping frame %d, logical_blk_num %u (expected %d)\n", tape->name, tape->first_frame_position, ntohl(aux->logical_blk_num), logical_blk_num);
 		return 0;
 	}
 	if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
@@ -3689,7 +3778,7 @@
 	idetape_switch_buffers (tape, new_stage);
 	idetape_init_stage(drive, new_stage, OS_FRAME_TYPE_DATA, tape->logical_blk_num);
 	tape->logical_blk_num++;
-	idetape_add_stage_tail (drive,new_stage);
+	idetape_add_stage_tail (drive, new_stage);
 	tape->pipeline_head++;
 #if USE_IOTRACE
 	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
@@ -3766,7 +3855,7 @@
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 	if (tape->merge_stage_size) {
-		blocks=tape->merge_stage_size/tape->tape_block_size;
+		blocks = tape->merge_stage_size / tape->tape_block_size;
 		if (tape->merge_stage_size % tape->tape_block_size) {
 			blocks++;
 			i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size;
@@ -3797,7 +3886,7 @@
 		tape->merge_stage = NULL;
 	}
 	clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
-	tape->chrdev_direction=idetape_direction_none;
+	tape->chrdev_direction = idetape_direction_none;
 
 	/*
 	 *	On the next backup, perform the feedback loop again.
@@ -3874,13 +3963,13 @@
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && tape->nr_stages <= max_stages) {
-		new_stage=idetape_kmalloc_stage (tape);
+		new_stage = idetape_kmalloc_stage (tape);
 		while (new_stage != NULL) {
-			new_stage->rq=rq;
-			idetape_add_stage_tail (drive,new_stage);
+			new_stage->rq = rq;
+			idetape_add_stage_tail (drive, new_stage);
 			if (tape->nr_stages >= max_stages)
 				break;
-			new_stage=idetape_kmalloc_stage (tape);
+			new_stage = idetape_kmalloc_stage (tape);
 		}
 	}
 	if (!idetape_pipeline_active(tape)) {
@@ -3922,16 +4011,23 @@
 #endif
 				clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				position = idetape_read_position(drive);
+				printk(KERN_INFO "ide-tape: %s: blank block detected at %d\n", tape->name, position);
 				if (position >= 3000 && position < 3080)
-					position += 32;
-				if (position >= 2980 && position < 3000)
+					position += 32;  /* Why is this check and number ??? MM */
+				if (position >= OS_DATA_ENDFRAME1 && position < 3000)
 					position = 3000;
 				else
+					/*
+					 * compensate for write errors that generally skip 80 frames,
+					 * expect around 20 read errors in a row...
+					 */
 					position += 60;
-				if (position >= 2980 && position < 3000)
+				if (position >= OS_DATA_ENDFRAME1 && position < 3000)
 					position = 3000;
-				printk(KERN_INFO "ide-tape: %s: blank block detected, positioning tape to block %d\n", tape->name, position);
-				idetape_position_tape(drive, position, 0, 1);
+				printk(KERN_INFO "ide-tape: %s: positioning tape to block %d\n", tape->name, position);
+				if (position == 3000)  /* seems to be needed to correctly position at block 3000 MM */
+					idetape_position_tape(drive, 0, 0, 0);
+				idetape_position_tape(drive, position, 0, 0);
 				cnt += 40;
 				continue;
 			} else
@@ -4089,12 +4185,14 @@
 #endif /* IDETAPE_DEBUG_LOG */	
 	
 	idetape_create_rewind_cmd (drive, &pc);
-	retval=idetape_queue_pc_tail (drive,&pc);
-	if (retval) return retval;
+	retval = idetape_queue_pc_tail (drive, &pc);
+	if (retval)
+		return retval;
 
 	idetape_create_read_position_cmd (&pc);
-	retval = idetape_queue_pc_tail (drive,&pc);
-	if (retval) return retval;
+	retval = idetape_queue_pc_tail (drive, &pc);
+	if (retval)
+		return retval;
 	tape->logical_blk_num = 0;
 	return 0;
 }
@@ -4412,7 +4510,7 @@
 	switch (mt_op) {
 		case MTFSF:
 			idetape_create_space_cmd (&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
-			return (idetape_queue_pc_tail (drive,&pc));
+			return (idetape_queue_pc_tail (drive, &pc));
 		case MTFSFM:
 			if (!tape->capabilities.sprev)
 				return (-EIO);
@@ -4423,7 +4521,7 @@
 			if (!tape->capabilities.sprev)
 				return (-EIO);
 			idetape_create_space_cmd (&pc,-(mt_count+count),IDETAPE_SPACE_OVER_FILEMARK);
-			return (idetape_queue_pc_tail (drive,&pc));
+			return (idetape_queue_pc_tail (drive, &pc));
 		case MTBSFM:
 			if (!tape->capabilities.sprev)
 				return (-EIO);
@@ -4460,7 +4558,7 @@
 	struct inode *inode = file->f_dentry->d_inode;
 	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
-	ssize_t bytes_read,temp,actually_read=0, rc;
+	ssize_t bytes_read,temp, actually_read = 0, rc;
 
 	if (ppos != &file->f_pos) {
 		/* "A request was outside the capabilities of the device." */
@@ -4482,28 +4580,32 @@
 	}
 	if ((rc = idetape_initiate_read(drive, tape->max_stages)) < 0)
 		return rc;
-	if (count==0)
+	if (count == 0)
 		return (0);
 	if (tape->merge_stage_size) {
-		actually_read=IDE_MIN (tape->merge_stage_size,count);
+		actually_read = IDE_MIN (tape->merge_stage_size, count);
 		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, actually_read);
-		buf += actually_read; tape->merge_stage_size -= actually_read; count-=actually_read;
+		buf += actually_read;
+		tape->merge_stage_size -= actually_read;
+		count -= actually_read;
 	}
 	while (count >= tape->stage_size) {
-		bytes_read=idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
+		bytes_read = idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
 		if (bytes_read <= 0)
 			goto finish;
 		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, bytes_read);
-		buf += bytes_read; count -= bytes_read; actually_read += bytes_read;
+		buf += bytes_read;
+		count -= bytes_read;
+		actually_read += bytes_read;
 	}
 	if (count) {
 		bytes_read=idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
 		if (bytes_read <= 0)
 			goto finish;
-		temp=IDE_MIN (count,bytes_read);
+		temp = IDE_MIN (count, bytes_read);
 		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, temp);
-		actually_read+=temp;
-		tape->merge_stage_size=bytes_read-temp;
+		actually_read += temp;
+		tape->merge_stage_size = bytes_read-temp;
 	}
 finish:
 	if (!actually_read && test_bit (IDETAPE_FILEMARK, &tape->flags)) {
@@ -4515,7 +4617,8 @@
 		return 0;
 	}
 	if (tape->onstream && !actually_read && test_and_clear_bit(IDETAPE_READ_ERROR, &tape->flags)) {
-		printk(KERN_ERR "ide-tape: %s: unrecovered read error on logical block number %d, skipping\n", tape->name, tape->logical_blk_num);
+		printk(KERN_ERR "ide-tape: %s: unrecovered read error on logical block number %d, skipping\n",
+					tape->name, tape->logical_blk_num);
 		tape->logical_blk_num++;
 		return -EIO;
 	}
@@ -4576,6 +4679,37 @@
 	return;
 }
 
+static void idetape_write_filler (ide_drive_t *drive, int block, int cnt)
+{
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_stage_t *stage;
+	int rc;
+
+	if (!tape->onstream || tape->raw)
+		return;
+	stage = __idetape_kmalloc_stage(tape, 1, 1);
+	if (stage == NULL)
+		return;
+	idetape_init_stage(drive, stage, OS_FRAME_TYPE_FILL, 0);
+	idetape_wait_ready(drive, 60 * 5 * HZ);
+	rc = idetape_position_tape(drive, block, 0, 0);
+#if ONSTREAM_DEBUG
+	printk(KERN_INFO "write_filler: positioning failed it returned %d\n", rc);
+#endif
+	if (rc != 0) 
+		return;	/* don't write fillers if we cannot position the tape. */
+
+	strcpy(stage->bh->b_data, "Filler");
+	while (cnt--) {
+		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+			printk(KERN_INFO "ide-tape: %s: write_filler: couldn't write header frame\n", tape->name);
+			__idetape_kfree_stage (stage);
+			return;
+		}
+	}
+	__idetape_kfree_stage (stage);
+}
+
 static void __idetape_write_header (ide_drive_t *drive, int block, int cnt)
 {
 	idetape_tape_t *tape = drive->driver_data;
@@ -4591,12 +4725,12 @@
 	memset(&header, 0, sizeof(header));
 	strcpy(header.ident_str, "ADR_SEQ");
 	header.major_rev = 1;
-	header.minor_rev = 2;
+	header.minor_rev = OS_ADR_MINREV;
 	header.par_num = 1;
 	header.partition.partition_num = OS_DATA_PARTITION;
 	header.partition.par_desc_ver = OS_PARTITION_VERSION;
-	header.partition.first_frame_addr = htonl(0x14);
-	header.partition.last_frame_addr = htonl(19239 * 24);
+	header.partition.first_frame_addr = htonl(OS_DATA_STARTFRAME1);
+	header.partition.last_frame_addr = htonl(tape->capacity);
 	header.partition.wrt_pass_cntr = htons(tape->wrt_pass_cntr);
 	header.partition.eod_frame_addr = htonl(tape->eod_frame_addr);
 	memcpy(stage->bh->b_data, &header, sizeof(header));
@@ -4623,7 +4757,7 @@
 		return;
 	tape->update_frame_cntr++;
 	__idetape_write_header(drive, 5, 5);
-	__idetape_write_header(drive, 0xbae, 5);
+	__idetape_write_header(drive, 0xbae, 5); /* 2990 */
 	if (locate_eod) {
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
@@ -4639,22 +4773,39 @@
 	struct inode *inode = file->f_dentry->d_inode;
 	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
-	ssize_t retval,actually_written=0;
+	ssize_t retval, actually_written = 0;
 	int position;
 
 	if (ppos != &file->f_pos) {
 		/* "A request was outside the capabilities of the device." */
 		return -ENXIO;
 	}
-	if (tape->onstream && (count != tape->tape_block_size)) {
-		printk(KERN_ERR "ide-tape: %s: use %d bytes as block size (%Zd used)\n", tape->name, tape->tape_block_size, count);
-		return -EINVAL;
-	}
+
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
 		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_write, count %Zd\n", count);
 #endif /* IDETAPE_DEBUG_LOG */
 
+	if (tape->onstream) {
+		if (count != tape->tape_block_size) {
+			printk(KERN_ERR "ide-tape: %s: chrdev_write: use %d bytes as block size (%Zd used)\n",
+					tape->name, tape->tape_block_size, count);
+			return -EINVAL;
+		}
+		/*
+		 * Check if we reach the end of the tape. Just assume the whole pipeline
+		 * is filled with write requests!
+		 */
+		if (tape->first_frame_position + tape->nr_stages >= tape->capacity - OS_EW)  {
+#if ONSTREAM_DEBUG
+			printk(KERN_INFO, "chrdev_write: Write truncated at EOM early warning");
+#endif
+			if (tape->chrdev_direction == idetape_direction_write)
+				idetape_write_release(inode);
+			return -ENOSPC;
+		}
+	}
+
 	if (tape->chrdev_direction != idetape_direction_write) {	/* Initialize write operation */
 		if (tape->chrdev_direction == idetape_direction_read)
 			idetape_discard_read_pipeline (drive, 1);
@@ -4671,17 +4822,17 @@
 
 		if (tape->onstream) {
 			position = idetape_read_position(drive);
-			if (position <= 20) {
+			if (position <= OS_DATA_STARTFRAME1) {
 				tape->logical_blk_num = 0;
 				tape->wrt_pass_cntr++;
 #if ONSTREAM_DEBUG
 				if (tape->debug_level >= 2)
-					printk(KERN_INFO "ide-tape: %s: logical block num 0, setting eod to 20\n", tape->name);
+					printk(KERN_INFO "ide-tape: %s: logical block num 0, setting eod to %d\n", tape->name, OS_DATA_STARTFRAME1);
 				if (tape->debug_level >= 2)
 					printk(KERN_INFO "ide-tape: %s: allocating new write pass counter %d\n", tape->name, tape->wrt_pass_cntr);
 #endif
 				tape->filemark_cnt = 0;
-				tape->eod_frame_addr = 20;
+				tape->eod_frame_addr = OS_DATA_STARTFRAME1;
 				tape->first_mark_addr = tape->last_mark_addr = -1;
 				idetape_write_header(drive, 1);
 			}
@@ -4715,7 +4866,7 @@
 			printk("ide-tape: first_frame_position %d\n", tape->first_frame_position);
 #endif
 	}
-	if (count==0)
+	if (count == 0)
 		return (0);
 	if (tape->restart_speed_control_req)
 		idetape_restart_speed_control(drive);
@@ -4723,32 +4874,35 @@
 #if IDETAPE_DEBUG_BUGS
 		if (tape->merge_stage_size >= tape->stage_size) {
 			printk (KERN_ERR "ide-tape: bug: merge buffer too big\n");
-			tape->merge_stage_size=0;
+			tape->merge_stage_size = 0;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		actually_written=IDE_MIN (tape->stage_size-tape->merge_stage_size,count);
+		actually_written = IDE_MIN (tape->stage_size - tape->merge_stage_size, count);
 		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, actually_written);
-		buf+=actually_written;tape->merge_stage_size+=actually_written;count-=actually_written;
+		buf += actually_written;
+		tape->merge_stage_size += actually_written;
+		count -= actually_written;
 
 		if (tape->merge_stage_size == tape->stage_size) {
 			tape->merge_stage_size = 0;
-			retval=idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
+			retval = idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
 			if (retval <= 0)
 				return (retval);
 		}
 	}
 	while (count >= tape->stage_size) {
 		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, tape->stage_size);
-		buf+=tape->stage_size;count-=tape->stage_size;
-		retval=idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
-		actually_written+=tape->stage_size;
+		buf += tape->stage_size;
+		count -= tape->stage_size;
+		retval = idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
+		actually_written += tape->stage_size;
 		if (retval <= 0)
 			return (retval);
 	}
 	if (count) {
 		actually_written+=count;
 		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, count);
-		tape->merge_stage_size+=count;
+		tape->merge_stage_size += count;
 	}
 	return (actually_written);
 }
@@ -4760,8 +4914,8 @@
 	idetape_pc_t pc;
 
 	if (!tape->onstream) {
-		idetape_create_write_filemark_cmd(drive, &pc,1);	/* Write a filemark */
-		if (idetape_queue_pc_tail (drive,&pc)) {
+		idetape_create_write_filemark_cmd(drive, &pc, 1);	/* Write a filemark */
+		if (idetape_queue_pc_tail (drive, &pc)) {
 			printk (KERN_ERR "ide-tape: Couldn't write a filemark\n");
 			return -EIO;
 		}
@@ -4937,24 +5091,24 @@
 			if (idetape_rewind_tape(drive))
 				return -EIO;
 			if (tape->onstream && !tape->raw)
-				return idetape_position_tape(drive, 20, 0, 0);
+				return idetape_position_tape(drive, OS_DATA_STARTFRAME1, 0, 0);
 			return 0;
 		case MTLOAD:
 			idetape_discard_read_pipeline (drive, 0);
 			idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive,&pc));
+			return (idetape_queue_pc_tail (drive, &pc));
 		case MTUNLOAD:
 		case MTOFFL:
 			idetape_discard_read_pipeline (drive, 0);
 			idetape_create_load_unload_cmd (drive, &pc,!IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive,&pc));
+			return (idetape_queue_pc_tail (drive, &pc));
 		case MTNOP:
 			idetape_discard_read_pipeline (drive, 0);
 			return (idetape_flush_tape_buffers (drive));
 		case MTRETEN:
 			idetape_discard_read_pipeline (drive, 0);
 			idetape_create_load_unload_cmd (drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive,&pc));
+			return (idetape_queue_pc_tail (drive, &pc));
 		case MTEOM:
 			if (tape->onstream) {
 #if ONSTREAM_DEBUG
@@ -4968,24 +5122,30 @@
 					return -EIO;
 				return 0;
 			}
-			idetape_create_space_cmd (&pc,0,IDETAPE_SPACE_TO_EOD);
-			return (idetape_queue_pc_tail (drive,&pc));
+			idetape_create_space_cmd (&pc, 0, IDETAPE_SPACE_TO_EOD);
+			return (idetape_queue_pc_tail (drive, &pc));
 		case MTERASE:
 			if (tape->onstream) {
-				tape->eod_frame_addr = 20;
+				tape->eod_frame_addr = OS_DATA_STARTFRAME1;
 				tape->logical_blk_num = 0;
 				tape->first_mark_addr = tape->last_mark_addr = -1;
 				idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
 				idetape_write_eod(drive);
 				idetape_flush_tape_buffers (drive);
 				idetape_write_header(drive, 0);
+				/*
+				 * write filler frames to the unused frames...
+				 * REMOVE WHEN going to LIN4 application type...
+				 */
+				idetape_write_filler(drive, OS_DATA_STARTFRAME1 - 10, 10);
+				idetape_write_filler(drive, OS_DATA_ENDFRAME1, 10);
 				idetape_flush_tape_buffers (drive);
 				(void) idetape_rewind_tape (drive);
 				return 0;
 			}
 			(void) idetape_rewind_tape (drive);
 			idetape_create_erase_cmd (&pc);
-			return (idetape_queue_pc_tail (drive,&pc));
+			return (idetape_queue_pc_tail (drive, &pc));
 		case MTSETBLK:
 			if (tape->onstream) {
 				if (mt_count != tape->tape_block_size) {
@@ -5028,14 +5188,14 @@
 		case MTLOCK:
 			if (!idetape_create_prevent_cmd(drive, &pc, 1))
 				return 0;
-			retval = idetape_queue_pc_tail (drive,&pc);
+			retval = idetape_queue_pc_tail (drive, &pc);
 			if (retval) return retval;
 			tape->door_locked = DOOR_EXPLICITLY_LOCKED;
 			return 0;
 		case MTUNLOCK:
 			if (!idetape_create_prevent_cmd(drive, &pc, 0))
 				return 0;
-			retval = idetape_queue_pc_tail (drive,&pc);
+			retval = idetape_queue_pc_tail (drive, &pc);
 			if (retval) return retval;
 			tape->door_locked = DOOR_UNLOCKED;
 			return 0;
@@ -5113,7 +5273,7 @@
 				mtget.mt_gstat |= GMT_ONLINE(0xffffffff);
 				if (tape->first_stage && tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD)
 					mtget.mt_gstat |= GMT_EOD(0xffffffff);
-				if (position <= 20)
+				if (position <= OS_DATA_STARTFRAME1)
 					mtget.mt_gstat |= GMT_BOT(0xffffffff);
 			}
 			if (copy_to_user ((char *) arg,(char *) &mtget, sizeof (struct mtget)))
@@ -5150,7 +5310,7 @@
 	tape->header_ok = tape->linux_media = 0;
 	tape->update_frame_cntr = 0;
 	tape->wrt_pass_cntr = 0;
-	tape->eod_frame_addr = 20;
+	tape->eod_frame_addr = OS_DATA_STARTFRAME1;
 	tape->first_mark_addr = tape->last_mark_addr = -1;
 	stage = __idetape_kmalloc_stage (tape, 0, 0);
 	if (stage == NULL)
@@ -5172,8 +5332,8 @@
 		__idetape_kfree_stage (stage);
 		return 0;
 	}
-	if (header->major_rev != 1 || (header->minor_rev != 1 && header->minor_rev != 2))
-		printk(KERN_INFO "ide-tape: warning: revision %d.%d detected (1.1/1.2 supported)\n", header->major_rev, header->minor_rev);
+	if (header->major_rev != 1 || (header->minor_rev > OS_ADR_MINREV))
+		printk(KERN_INFO "ide-tape: warning: revision %d.%d detected (up to 1.%d supported)\n", header->major_rev, header->minor_rev, OS_ADR_MINREV);
 	if (header->par_num != 1)
 		printk(KERN_INFO "ide-tape: warning: %d partitions defined, only one supported\n", header->par_num);
 	tape->wrt_pass_cntr = ntohs(header->partition.wrt_pass_cntr);
@@ -5182,12 +5342,14 @@
 	tape->first_mark_addr = ntohl(aux->next_mark_addr);
 	tape->last_mark_addr = ntohl(aux->last_mark_addr);
 	tape->update_frame_cntr = ntohl(aux->update_frame_cntr);
-	memcpy(tape->application_sig, aux->application_sig, 4); tape->application_sig[4] = 0;
+	memcpy(tape->application_sig, aux->application_sig, 4);
+	tape->application_sig[4] = 0;
 	if (memcmp(tape->application_sig, "LIN", 3) == 0) {
 		tape->linux_media = 1;
 		tape->linux_media_version = tape->application_sig[3] - '0';
 		if (tape->linux_media_version != 3)
-			printk(KERN_INFO "ide-tape: %s: Linux media version %d detected (current 3)\n", tape->name, tape->linux_media_version);
+			printk(KERN_INFO "ide-tape: %s: Linux media version %d detected (current 3)\n",
+					 tape->name, tape->linux_media_version);
 	} else {
 		printk(KERN_INFO "ide-tape: %s: non Linux media detected (%s)\n", tape->name, tape->application_sig);
 		tape->linux_media = 0;
@@ -5214,18 +5376,14 @@
 	for (block = 5; block < 10; block++)
 		if (__idetape_analyze_headers(drive, block))
 			goto ok;
-#if 0
-	for (block = 0xbae; block < 0xbb8; block++)
-#else
-	for (block = 0xbae; block < 0xbb3; block++)
-#endif
+	for (block = 0xbae; block < 0xbb3; block++) /* 2990 - 2994 */
 		if (__idetape_analyze_headers(drive, block))
 			goto ok;
 	printk(KERN_ERR "ide-tape: %s: failed to find valid ADRL header\n", tape->name);
 	return 0;
 ok:
-	if (position < 20)
-		position = 20;
+	if (position < OS_DATA_STARTFRAME1)
+		position = OS_DATA_STARTFRAME1;
 	idetape_position_tape(drive, position, 0, 0);
 	tape->header_ok = 1;
 	return 1;
@@ -5251,7 +5409,8 @@
 
 	if (test_and_set_bit (IDETAPE_BUSY, &tape->flags))
 		return -EBUSY;
-	if (!tape->onstream) {
+	MOD_INC_USE_COUNT;
+	if (!tape->onstream) {	
 		idetape_read_position(drive);
 		if (!test_bit (IDETAPE_ADDRESS_VALID, &tape->flags))
 			(void) idetape_rewind_tape (drive);
@@ -5263,18 +5422,22 @@
 			tape->tape_block_size = tape->stage_size = 32768;
 			tape->raw = 0;
 		}
+                idetape_onstream_mode_sense_tape_parameter_page(drive, tape->debug_level);
 	}
 	if (idetape_wait_ready(drive, 60 * HZ)) {
 		clear_bit(IDETAPE_BUSY, &tape->flags);
 		printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
+		MOD_DEC_USE_COUNT;
 		return -EBUSY;
 	}
 	idetape_read_position(drive);
+	MOD_DEC_USE_COUNT;
 	clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
 
 	if (tape->chrdev_direction == idetape_direction_none) {
+		MOD_INC_USE_COUNT;
 		if (idetape_create_prevent_cmd(drive, &pc, 1)) {
-			if (!idetape_queue_pc_tail (drive,&pc)) {
+			if (!idetape_queue_pc_tail (drive, &pc)) {
 				if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
 					tape->door_locked = DOOR_LOCKED;
 			}
@@ -5287,6 +5450,28 @@
 	return 0;
 }
 
+static void idetape_write_release (struct inode *inode)
+{
+	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	idetape_tape_t *tape = drive->driver_data;
+	unsigned int minor=MINOR (inode->i_rdev);
+
+	idetape_empty_write_pipeline (drive);
+	tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
+	if (tape->merge_stage != NULL) {
+		idetape_pad_zeros (drive, tape->tape_block_size * (tape->user_bs_factor - 1));
+		__idetape_kfree_stage (tape->merge_stage);
+		tape->merge_stage = NULL;
+	}
+	idetape_write_filemark(drive);
+	idetape_write_eod(drive);
+	idetape_flush_tape_buffers (drive);
+	idetape_write_header(drive, minor >= 128);
+	idetape_flush_tape_buffers (drive);
+
+	return;
+}
+
 /*
  *	Our character device release function.
  */
@@ -5305,18 +5490,7 @@
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->chrdev_direction == idetape_direction_write) {
-		idetape_empty_write_pipeline (drive);
-		tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
-		if (tape->merge_stage != NULL) {
-			idetape_pad_zeros (drive, tape->tape_block_size * (tape->user_bs_factor - 1));
-			__idetape_kfree_stage (tape->merge_stage);
-			tape->merge_stage = NULL;
-		}
-		idetape_write_filemark(drive);
-		idetape_write_eod(drive);
-		idetape_flush_tape_buffers (drive);
-		idetape_write_header(drive, minor >= 128);
-		idetape_flush_tape_buffers (drive);
+		idetape_write_release(inode);
 	}
 	if (tape->chrdev_direction == idetape_direction_read) {
 		if (minor < 128)
@@ -5333,9 +5507,10 @@
 	if (tape->chrdev_direction == idetape_direction_none) {
 		if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) {
 			if (idetape_create_prevent_cmd(drive, &pc, 0))
-				if (!idetape_queue_pc_tail (drive,&pc))
+				if (!idetape_queue_pc_tail (drive, &pc))
 					tape->door_locked = DOOR_UNLOCKED;
 		}
+		MOD_DEC_USE_COUNT;
 	}
 	clear_bit (IDETAPE_BUSY, &tape->flags);
 	unlock_kernel();
@@ -5491,7 +5666,7 @@
 	pc.buffer[4 + 5] = vendor[3];
 	pc.buffer[4 + 6] = 0;
 	pc.buffer[4 + 7] = 0;
-	if (idetape_queue_pc_tail (drive,&pc))
+	if (idetape_queue_pc_tail (drive, &pc))
 		printk (KERN_ERR "ide-tape: Couldn't set vendor name to %s\n", vendor);
 
 }
@@ -5513,7 +5688,7 @@
 	pc.buffer[4 + 1] = 2;
 	pc.buffer[4 + 2] = 4;
 	pc.buffer[4 + 3] = retries;
-	if (idetape_queue_pc_tail (drive,&pc))
+	if (idetape_queue_pc_tail (drive, &pc))
 		printk (KERN_ERR "ide-tape: Couldn't set retries to %d\n", retries);
 }
 #endif
@@ -5530,8 +5705,8 @@
 	/*
 	 * Get the current block size from the block size mode page
 	 */
-	idetape_create_mode_sense_cmd (&pc,IDETAPE_BLOCK_SIZE_PAGE);
-	if (idetape_queue_pc_tail (drive,&pc))
+	idetape_create_mode_sense_cmd (&pc, IDETAPE_BLOCK_SIZE_PAGE);
+	if (idetape_queue_pc_tail (drive, &pc))
 		printk (KERN_ERR "ide-tape: can't get tape block size mode page\n");
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
 	bs = (idetape_block_size_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
@@ -5552,7 +5727,7 @@
 	bs->record32 = 0;
 	bs->record32_5 = 1;
 	idetape_create_mode_select_cmd(&pc, sizeof(*header) + sizeof(*bs));
-	if (idetape_queue_pc_tail (drive,&pc))
+	if (idetape_queue_pc_tail (drive, &pc))
 		printk (KERN_ERR "ide-tape: Couldn't set tape block size mode page\n");
 
 #if ONSTREAM_DEBUG
@@ -5575,7 +5750,7 @@
 	idetape_inquiry_result_t *inquiry;
 	
 	idetape_create_inquiry_cmd(&pc);
-	if (idetape_queue_pc_tail (drive,&pc)) {
+	if (idetape_queue_pc_tail (drive, &pc)) {
 		printk (KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name);
 		return;
 	}
@@ -5618,6 +5793,34 @@
 }
 
 /*
+ *	idetape_get_mode_sense_parameters asks the tape about its various
+ *	parameters. This may work for other drives to???
+ */
+static void idetape_onstream_mode_sense_tape_parameter_page(ide_drive_t *drive, int debug)
+{
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_pc_t pc;
+	idetape_mode_parameter_header_t *header;
+	onstream_tape_paramtr_page_t *prm;
+	
+	idetape_create_mode_sense_cmd (&pc, IDETAPE_PARAMTR_PAGE);
+	if (idetape_queue_pc_tail (drive, &pc)) {
+		printk (KERN_ERR "ide-tape: Can't get tape parameters page - probably no tape inserted in onstream drive\n");
+		return;
+	}
+	header = (idetape_mode_parameter_header_t *) pc.buffer;
+	prm = (onstream_tape_paramtr_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
+
+        tape->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
+        if (debug) {
+	    printk (KERN_INFO "ide-tape: %s <-> %s: Tape length %dMB (%d frames/track, %d tracks = %d blocks, density: %dKbpi)\n",
+               drive->name, tape->name, tape->capacity/32, ntohs(prm->segtrk), ntohs(prm->trks), tape->capacity, prm->density);
+        }
+
+        return;
+}
+
+/*
  *	idetape_get_mode_sense_results asks the tape about its various
  *	parameters. In particular, we will adjust our data transfer buffer
  *	size to the recommended value as returned by the tape.
@@ -5629,8 +5832,8 @@
 	idetape_mode_parameter_header_t *header;
 	idetape_capabilities_page_t *capabilities;
 	
-	idetape_create_mode_sense_cmd (&pc,IDETAPE_CAPABILITIES_PAGE);
-	if (idetape_queue_pc_tail (drive,&pc)) {
+	idetape_create_mode_sense_cmd (&pc, IDETAPE_CAPABILITIES_PAGE);
+	if (idetape_queue_pc_tail (drive, &pc)) {
 		printk (KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n");
 		tape->tape_block_size = 512; tape->capabilities.ctl = 52;
 		tape->capabilities.speed = 450; tape->capabilities.buffer_size = 6 * 52;
@@ -5692,6 +5895,34 @@
 #endif /* IDETAPE_DEBUG_INFO */
 }
 
+/*
+ *	ide_get_blocksize_from_block_descriptor does a mode sense page 0 with block descriptor
+ *	and if it succeeds sets the tape block size with the reported value
+ */
+static void idetape_get_blocksize_from_block_descriptor(ide_drive_t *drive)
+{
+
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_pc_t pc;
+	idetape_mode_parameter_header_t *header;
+	idetape_parameter_block_descriptor_t *block_descrp;
+	
+	idetape_create_mode_sense_cmd (&pc, IDETAPE_BLOCK_DESCRIPTOR);
+	if (idetape_queue_pc_tail (drive, &pc)) {
+		printk (KERN_ERR "ide-tape: Can't get block descriptor\n");
+		if (tape->tape_block_size == 0) {
+			printk(KERN_WARNING "ide-tape: Cannot deal with zero block size, assume 32k\n");
+			tape->tape_block_size =  32768;
+		}
+		return;
+	}
+	header = (idetape_mode_parameter_header_t *) pc.buffer;
+	block_descrp = (idetape_parameter_block_descriptor_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t));
+	tape->tape_block_size =( block_descrp->length[0]<<16) + (block_descrp->length[1]<<8) + block_descrp->length[2];
+#if IDETAPE_DEBUG_INFO
+	printk (KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
+#endif /* IDETAPE_DEBUG_INFO */
+}
 static void idetape_add_settings (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
@@ -5712,15 +5943,18 @@
 	ide_add_setting(drive,	"pipeline_head_speed_c",SETTING_READ,	-1,	-1,	TYPE_INT,	0,			0xffff,			1,				1,				&tape->controlled_pipeline_head_speed,	NULL);
 	ide_add_setting(drive,	"pipeline_head_speed_u",SETTING_READ,	-1,	-1,	TYPE_INT,	0,			0xffff,			1,				1,				&tape->uncontrolled_pipeline_head_speed,	NULL);
 	ide_add_setting(drive,	"avg_speed",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->avg_speed,		NULL);
+	ide_add_setting(drive,	"debug_level",SETTING_RW,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->debug_level,		NULL);
 	if (tape->onstream) {
 		ide_add_setting(drive,	"cur_frames",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				1,				&tape->cur_frames,		NULL);
 		ide_add_setting(drive,	"max_frames",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				1,				&tape->max_frames,		NULL);
 		ide_add_setting(drive,	"insert_speed",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->insert_speed,		NULL);
 		ide_add_setting(drive,	"speed_control",SETTING_RW,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->speed_control,		NULL);
-		ide_add_setting(drive,	"debug_level",SETTING_RW,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->debug_level,		NULL);
 		ide_add_setting(drive,	"tape_still_time",SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->tape_still_time,		NULL);
 		ide_add_setting(drive,	"max_insert_speed",SETTING_RW,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->max_insert_speed,	NULL);
 		ide_add_setting(drive,	"insert_size",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->insert_size,		NULL);
+		ide_add_setting(drive,	"capacity",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->capacity,		NULL);
+		ide_add_setting(drive,	"first_frame",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->first_frame_position,		NULL);
+		ide_add_setting(drive,	"logical_blk",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->logical_blk_num,		NULL);
 	}
 }
 
@@ -5742,12 +5976,13 @@
 	int speed;
 	struct idetape_id_gcw gcw;
 	int stage_size;
+	struct sysinfo si;
 
 	memset (tape, 0, sizeof (idetape_tape_t));
 	spin_lock_init(&tape->spinlock);
 	drive->driver_data = tape;
 	drive->ready_stat = 0;			/* An ATAPI device ignores DRDY */
-	if (strstr(drive->id->model, "OnStream DI-30"))
+	if (strstr(drive->id->model, "OnStream DI-"))
 		tape->onstream = 1;
 	drive->dsc_overlap = 1;
 #ifdef CONFIG_BLK_DEV_IDEPCI
@@ -5778,9 +6013,11 @@
 	
 	idetape_get_inquiry_results(drive);
 	idetape_get_mode_sense_results(drive);
-	if (tape->onstream)
+	idetape_get_blocksize_from_block_descriptor(drive);
+	if (tape->onstream) {
+		idetape_onstream_mode_sense_tape_parameter_page(drive, 1);
 		idetape_configure_onstream(drive);
-
+	}
 	tape->user_bs_factor = 1;
 	tape->stage_size = tape->capabilities.ctl * tape->tape_block_size;
 	while (tape->stage_size > 0xffff) {
@@ -5804,6 +6041,13 @@
 	speed = IDE_MAX (tape->capabilities.speed, tape->capabilities.max_speed);
 
 	tape->max_stages = speed * 1000 * 10 / tape->stage_size;
+
+	/*
+	 * 	Limit memory use for pipeline to 10% of physical memory
+	 */
+	si_meminfo(&si);
+	if ( tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
+		tape->max_stages = si.totalram * si.mem_unit / (10 * tape->stage_size);
 	tape->min_pipeline = tape->max_stages;
 	tape->max_pipeline = tape->max_stages * 2;
 
@@ -5867,8 +6111,8 @@
 	char		*out = page;
 	int		len;
 
-	len = sprintf(out,"%s\n", tape->name);
-	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+	len = sprintf(out, "%s\n", tape->name);
+	PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
 }
 
 static ide_proc_entry_t idetape_proc[] = {
@@ -5962,7 +6206,7 @@
 			continue;
 		}
 		if (drive->scsi) {
-			if (strstr(drive->id->model, "OnStream DI-30")) {
+			if (strstr(drive->id->model, "OnStream DI-")) {
 				printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
 			} else {
 				printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
diff -u --recursive --new-file v2.4.5/linux/drivers/ide/piix.c linux/drivers/ide/piix.c
--- v2.4.5/linux/drivers/ide/piix.c	Tue Mar  6 19:44:34 2001
+++ linux/drivers/ide/piix.c	Wed Jun 20 11:16:01 2001
@@ -108,7 +108,8 @@
 	c1 = inb_p((unsigned short)bibma + 0x0a);
 
 	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_INTEL_82820FW_5:
+		case PCI_DEVICE_ID_INTEL_82801BA_8:
+		case PCI_DEVICE_ID_INTEL_82801BA_9:
 			p += sprintf(p, "\n                                Intel PIIX4 Ultra 100 Chipset.\n");
 			break;
 		case PCI_DEVICE_ID_INTEL_82372FB_1:
@@ -358,7 +359,8 @@
 	byte			speed;
 
 	byte udma_66		= eighty_ninty_three(drive);
-	int ultra100		= ((dev->device == PCI_DEVICE_ID_INTEL_82820FW_5)) ? 1 : 0;
+	int ultra100		= ((dev->device == PCI_DEVICE_ID_INTEL_82801BA_8) ||
+				   (dev->device == PCI_DEVICE_ID_INTEL_82801BA_9)) ? 1 : 0;
 	int ultra66		= ((ultra100) ||
 				   (dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) ||
 				   (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0;
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/avmb1/b1.c linux/drivers/isdn/avmb1/b1.c
--- v2.4.5/linux/drivers/isdn/avmb1/b1.c	Sat May 19 17:54:14 2001
+++ linux/drivers/isdn/avmb1/b1.c	Tue Jun 12 13:03:18 2001
@@ -1,114 +1,9 @@
 /*
- * $Id: b1.c,v 1.20.6.4 2001/04/20 02:41:59 keil Exp $
+ * $Id: b1.c,v 1.20.6.6 2001/05/17 21:15:33 kai Exp $
  * 
  * Common module for AVM B1 cards.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
- * 
- * $Log: b1.c,v $
- * Revision 1.20.6.4  2001/04/20 02:41:59  keil
- * changes from mainstream
- *
- * Revision 1.20.6.3  2001/03/21 08:52:20  kai
- * merge from main branch: fix buffer for revision string (calle)
- *
- * Revision 1.20.6.2  2001/03/15 15:11:23  kai
- * *** empty log message ***
- *
- * Revision 1.20.6.1  2001/02/13 11:43:29  kai
- * more compatility changes for 2.2.19
- *
- * Revision 1.20  2000/11/23 20:45:14  kai
- * fixed module_init/exit stuff
- * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
- *
- * Revision 1.19  2000/11/19 17:02:47  kai
- * compatibility cleanup - part 3
- *
- * Revision 1.18  2000/11/19 17:01:53  kai
- * compatibility cleanup - part 2
- *
- * Revision 1.17  2000/11/01 14:05:02  calle
- * - use module_init/module_exit from linux/init.h.
- * - all static struct variables are initialized with "membername:" now.
- * - avm_cs.c, let it work with newer pcmcia-cs.
- *
- * Revision 1.16  2000/08/04 15:36:31  calle
- * copied wrong from file to file :-(
- *
- * Revision 1.15  2000/08/04 12:20:08  calle
- * - Fix unsigned/signed warning in the right way ...
- *
- * Revision 1.14  2000/06/19 16:51:53  keil
- * don't free skb in irq context
- *
- * Revision 1.13  2000/01/25 14:33:38  calle
- * - Added Support AVM B1 PCI V4.0 (tested with prototype)
- *   - splitted up t1pci.c into b1dma.c for common function with b1pciv4
- *   - support for revision register
- *
- * Revision 1.12  1999/11/05 16:38:01  calle
- * Cleanups before kernel 2.4:
- * - Changed all messages to use card->name or driver->name instead of
- *   constant string.
- * - Moved some data from struct avmcard into new struct avmctrl_info.
- *   Changed all lowlevel capi driver to match the new structur.
- *
- * Revision 1.11  1999/10/11 22:04:12  keil
- * COMPAT_NEED_UACCESS (no include in isdn_compat.h)
- *
- * Revision 1.10  1999/09/15 08:16:03  calle
- * Implementation of 64Bit extention complete.
- *
- * Revision 1.9  1999/09/07 09:02:53  calle
- * SETDATA removed. Now inside the kernel the datapart of DATA_B3_REQ and
- * DATA_B3_IND is always directly after the CAPI message. The "Data" member
- * ist never used inside the kernel.
- *
- * Revision 1.8  1999/08/22 20:26:22  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.7  1999/08/04 10:10:09  calle
- * Bugfix: corrected /proc functions, added structure for new AVM cards.
- *
- * Revision 1.6  1999/07/23 08:51:04  calle
- * small fix and typo in checkin before.
- *
- * Revision 1.5  1999/07/23 08:41:48  calle
- * prepared for new AVM cards.
- *
- * Revision 1.4  1999/07/09 15:05:38  keil
- * compat.h is now isdn_compat.h
- *
- * Revision 1.3  1999/07/06 07:41:59  calle
- * - changes in /proc interface
- * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb.
- *
- * Revision 1.2  1999/07/05 15:09:47  calle
- * - renamed "appl_release" to "appl_released".
- * - version und profile data now cleared on controller reset
- * - extended /proc interface, to allow driver and controller specific
- *   informations to include by driver hackers.
- *
- * Revision 1.1  1999/07/01 15:26:23  calle
- * complete new version (I love it):
- * + new hardware independed "capi_driver" interface that will make it easy to:
- *   - support other controllers with CAPI-2.0 (i.e. USB Controller)
- *   - write a CAPI-2.0 for the passive cards
- *   - support serial link CAPI-2.0 boxes.
- * + wrote "capi_driver" for all supported cards.
- * + "capi_driver" (supported cards) now have to be configured with
- *   make menuconfig, in the past all supported cards where included
- *   at once.
- * + new and better informations in /proc/capi/
- * + new ioctl to switch trace of capi messages per controller
- *   using "avmcapictrl trace [contr] on|off|...."
- * + complete testcircle with all supported cards and also the
- *   PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
- *
  *
  */
 
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c
--- v2.4.5/linux/drivers/isdn/avmb1/b1dma.c	Sat May 19 17:54:14 2001
+++ linux/drivers/isdn/avmb1/b1dma.c	Tue Jun 12 13:03:18 2001
@@ -1,59 +1,10 @@
 /*
- * $Id: b1dma.c,v 1.11.6.4 2001/04/20 02:41:59 keil Exp $
+ * $Id: b1dma.c,v 1.11.6.6 2001/05/17 21:15:33 kai Exp $
  * 
  * Common module for AVM B1 cards that support dma with AMCC
  * 
  * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
- * $Log: b1dma.c,v $
- * Revision 1.11.6.4  2001/04/20 02:41:59  keil
- * changes from mainstream
- *
- * Revision 1.11.6.3  2001/03/21 08:52:21  kai
- * merge from main branch: fix buffer for revision string (calle)
- *
- * Revision 1.11.6.2  2001/03/15 15:11:23  kai
- * *** empty log message ***
- *
- * Revision 1.11.6.1  2001/02/13 11:43:29  kai
- * more compatility changes for 2.2.19
- *
- * Revision 1.11  2000/11/19 17:02:47  kai
- * compatibility cleanup - part 3
- *
- * Revision 1.10  2000/11/19 17:01:53  kai
- * compatibility cleanup - part 2
- *
- * Revision 1.9  2000/11/01 14:05:02  calle
- * - use module_init/module_exit from linux/init.h.
- * - all static struct variables are initialized with "membername:" now.
- * - avm_cs.c, let it work with newer pcmcia-cs.
- *
- * Revision 1.8  2000/10/10 17:44:19  kai
- * changes from/for 2.2.18
- *
- * Revision 1.7  2000/08/04 12:20:08  calle
- * - Fix unsigned/signed warning in the right way ...
- *
- * Revision 1.6  2000/06/29 13:59:06  calle
- * Bugfix: reinit txdma without interrupt will confuse some AMCC chips.
- *
- * Revision 1.5  2000/06/19 16:51:53  keil
- * don't free skb in irq context
- *
- * Revision 1.4  2000/04/03 16:38:05  calle
- * made suppress_pollack static.
- *
- * Revision 1.3  2000/02/26 01:00:53  keil
- * changes from 2.3.47
- *
- * Revision 1.2  2000/01/25 14:44:47  calle
- * typo in b1pciv4_detect().
- *
- * Revision 1.1  2000/01/25 14:36:43  calle
- * common function for  T1 PCI and B1 PCI V4.
- *
- *
  */
 
 #include <linux/config.h>
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/avmb1/b1isa.c linux/drivers/isdn/avmb1/b1isa.c
--- v2.4.5/linux/drivers/isdn/avmb1/b1isa.c	Sat May 19 17:54:14 2001
+++ linux/drivers/isdn/avmb1/b1isa.c	Tue Jun 12 13:03:18 2001
@@ -1,83 +1,10 @@
 /*
- * $Id: b1isa.c,v 1.10.6.4 2001/03/21 08:52:21 kai Exp $
+ * $Id: b1isa.c,v 1.10.6.5 2001/05/17 20:41:51 kai Exp $
  * 
  * Module for AVM B1 ISA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
- * $Log: b1isa.c,v $
- * Revision 1.10.6.4  2001/03/21 08:52:21  kai
- * merge from main branch: fix buffer for revision string (calle)
- *
- * Revision 1.10.6.3  2001/03/15 15:11:23  kai
- * *** empty log message ***
- *
- * Revision 1.10.6.2  2001/02/16 16:43:23  kai
- * Changes from -ac16, little bug fixes, typos and the like
- *
- * Revision 1.10.6.1  2001/02/13 11:43:29  kai
- * more compatility changes for 2.2.19
- *
- * Revision 1.10  2000/11/23 20:45:14  kai
- * fixed module_init/exit stuff
- * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
- *
- * Revision 1.9  2000/11/01 14:05:02  calle
- * - use module_init/module_exit from linux/init.h.
- * - all static struct variables are initialized with "membername:" now.
- * - avm_cs.c, let it work with newer pcmcia-cs.
- *
- * Revision 1.8  2000/04/03 13:29:24  calle
- * make Tim Waugh happy (module unload races in 2.3.99-pre3).
- * no real problem there, but now it is much cleaner ...
- *
- * Revision 1.7  2000/02/02 18:36:03  calle
- * - Modules are now locked while init_module is running
- * - fixed problem with memory mapping if address is not aligned
- *
- * Revision 1.6  2000/01/25 14:37:39  calle
- * new message after successful detection including card revision and
- * used resources.
- *
- * Revision 1.5  1999/11/05 16:38:01  calle
- * Cleanups before kernel 2.4:
- * - Changed all messages to use card->name or driver->name instead of
- *   constant string.
- * - Moved some data from struct avmcard into new struct avmctrl_info.
- *   Changed all lowlevel capi driver to match the new structur.
- *
- * Revision 1.4  1999/08/22 20:26:24  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.3  1999/07/09 15:05:40  keil
- * compat.h is now isdn_compat.h
- *
- * Revision 1.2  1999/07/05 15:09:49  calle
- * - renamed "appl_release" to "appl_released".
- * - version und profile data now cleared on controller reset
- * - extended /proc interface, to allow driver and controller specific
- *   informations to include by driver hackers.
- *
- * Revision 1.1  1999/07/01 15:26:27  calle
- * complete new version (I love it):
- * + new hardware independed "capi_driver" interface that will make it easy to:
- *   - support other controllers with CAPI-2.0 (i.e. USB Controller)
- *   - write a CAPI-2.0 for the passive cards
- *   - support serial link CAPI-2.0 boxes.
- * + wrote "capi_driver" for all supported cards.
- * + "capi_driver" (supported cards) now have to be configured with
- *   make menuconfig, in the past all supported cards where included
- *   at once.
- * + new and better informations in /proc/capi/
- * + new ioctl to switch trace of capi messages per controller
- *   using "avmcapictrl trace [contr] on|off|...."
- * + complete testcircle with all supported cards and also the
- *   PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
- *
- *
  */
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c
--- v2.4.5/linux/drivers/isdn/avmb1/b1pci.c	Sat May 19 17:54:14 2001
+++ linux/drivers/isdn/avmb1/b1pci.c	Tue Jun 12 13:03:18 2001
@@ -1,111 +1,10 @@
 /*
- * $Id: b1pci.c,v 1.29.6.3 2001/04/20 02:41:59 keil Exp $
+ * $Id: b1pci.c,v 1.29.6.4 2001/05/17 20:41:51 kai Exp $
  * 
  * Module for AVM B1 PCI-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
- * $Log: b1pci.c,v $
- * Revision 1.29.6.3  2001/04/20 02:41:59  keil
- * changes from mainstream
- *
- * Revision 1.29.6.2  2001/03/21 08:52:21  kai
- * merge from main branch: fix buffer for revision string (calle)
- *
- * Revision 1.29.6.1  2000/11/28 12:02:45  kai
- * MODULE_DEVICE_TABLE for 2.4
- *
- * Revision 1.29.2.2  2000/11/26 17:47:53  kai
- * added PCI_DEV_TABLE for 2.4
- *
- * Revision 1.29.2.1  2000/11/26 17:14:19  kai
- * fix device ids
- * also needs patches to include/linux/pci_ids.h
- *
- * Revision 1.29  2000/11/23 20:45:14  kai
- * fixed module_init/exit stuff
- * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
- *
- * Revision 1.28  2000/11/01 14:05:02  calle
- * - use module_init/module_exit from linux/init.h.
- * - all static struct variables are initialized with "membername:" now.
- * - avm_cs.c, let it work with newer pcmcia-cs.
- *
- * Revision 1.27  2000/08/08 09:24:19  calle
- * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI
- *
- * Revision 1.26  2000/07/20 10:21:21  calle
- * Bugfix: driver will not be unregistered, if not cards were detected.
- *         this result in an oops in kcapi.c
- *
- * Revision 1.25  2000/05/29 12:29:18  keil
- * make pci_enable_dev compatible to 2.2 kernel versions
- *
- * Revision 1.24  2000/05/19 15:43:22  calle
- * added calls to pci_device_start().
- *
- * Revision 1.23  2000/05/06 00:52:36  kai
- * merged changes from kernel tree
- * fixed timer and net_device->name breakage
- *
- * Revision 1.22  2000/04/21 13:01:33  calle
- * Revision in b1pciv4 driver was missing.
- *
- * Revision 1.21  2000/04/03 13:29:24  calle
- * make Tim Waugh happy (module unload races in 2.3.99-pre3).
- * no real problem there, but now it is much cleaner ...
- *
- * Revision 1.20  2000/02/02 18:36:03  calle
- * - Modules are now locked while init_module is running
- * - fixed problem with memory mapping if address is not aligned
- *
- * Revision 1.19  2000/01/25 14:33:38  calle
- * - Added Support AVM B1 PCI V4.0 (tested with prototype)
- *   - splitted up t1pci.c into b1dma.c for common function with b1pciv4
- *   - support for revision register
- *
- * Revision 1.18  1999/11/05 16:38:01  calle
- * Cleanups before kernel 2.4:
- * - Changed all messages to use card->name or driver->name instead of
- *   constant string.
- * - Moved some data from struct avmcard into new struct avmctrl_info.
- *   Changed all lowlevel capi driver to match the new structur.
- *
- * Revision 1.17  1999/10/05 06:50:07  calle
- * Forgot SA_SHIRQ as argument to request_irq.
- *
- * Revision 1.16  1999/08/11 21:01:07  keil
- * new PCI codefix
- *
- * Revision 1.15  1999/08/10 16:02:27  calle
- * struct pci_dev changed in 2.3.13. Made the necessary changes.
- *
- * Revision 1.14  1999/07/09 15:05:41  keil
- * compat.h is now isdn_compat.h
- *
- * Revision 1.13  1999/07/05 15:09:50  calle
- * - renamed "appl_release" to "appl_released".
- * - version und profile data now cleared on controller reset
- * - extended /proc interface, to allow driver and controller specific
- *   informations to include by driver hackers.
- *
- * Revision 1.12  1999/07/01 15:26:29  calle
- * complete new version (I love it):
- * + new hardware independed "capi_driver" interface that will make it easy to:
- *   - support other controllers with CAPI-2.0 (i.e. USB Controller)
- *   - write a CAPI-2.0 for the passive cards
- *   - support serial link CAPI-2.0 boxes.
- * + wrote "capi_driver" for all supported cards.
- * + "capi_driver" (supported cards) now have to be configured with
- *   make menuconfig, in the past all supported cards where included
- *   at once.
- * + new and better informations in /proc/capi/
- * + new ioctl to switch trace of capi messages per controller
- *   using "avmcapictrl trace [contr] on|off|...."
- * + complete testcircle with all supported cards and also the
- *   PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
- *
- *
  */
 
 #include <linux/config.h>
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/avmb1/b1pcmcia.c linux/drivers/isdn/avmb1/b1pcmcia.c
--- v2.4.5/linux/drivers/isdn/avmb1/b1pcmcia.c	Sat May 19 17:54:14 2001
+++ linux/drivers/isdn/avmb1/b1pcmcia.c	Tue Jun 12 13:03:18 2001
@@ -1,89 +1,10 @@
 /*
- * $Id: b1pcmcia.c,v 1.12.6.3 2001/03/21 08:52:21 kai Exp $
+ * $Id: b1pcmcia.c,v 1.12.6.4 2001/05/17 20:41:51 kai Exp $
  * 
  * Module for AVM B1/M1/M2 PCMCIA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
- * $Log: b1pcmcia.c,v $
- * Revision 1.12.6.3  2001/03/21 08:52:21  kai
- * merge from main branch: fix buffer for revision string (calle)
- *
- * Revision 1.12.6.2  2001/02/16 16:43:23  kai
- * Changes from -ac16, little bug fixes, typos and the like
- *
- * Revision 1.12.6.1  2001/02/13 11:43:29  kai
- * more compatility changes for 2.2.19
- *
- * Revision 1.12  2000/11/23 20:45:14  kai
- * fixed module_init/exit stuff
- * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
- *
- * Revision 1.11  2000/11/01 14:05:02  calle
- * - use module_init/module_exit from linux/init.h.
- * - all static struct variables are initialized with "membername:" now.
- * - avm_cs.c, let it work with newer pcmcia-cs.
- *
- * Revision 1.10  2000/05/06 00:52:36  kai
- * merged changes from kernel tree
- * fixed timer and net_device->name breakage
- *
- * Revision 1.9  2000/04/03 13:29:24  calle
- * make Tim Waugh happy (module unload races in 2.3.99-pre3).
- * no real problem there, but now it is much cleaner ...
- *
- * Revision 1.8  2000/03/06 18:00:23  calle
- * - Middleware extention now working with 2.3.49 (capifs).
- * - Fixed typos in debug section of capi.c
- * - Bugfix: Makefile corrected for b1pcmcia.c
- *
- * Revision 1.7  2000/02/02 18:36:03  calle
- * - Modules are now locked while init_module is running
- * - fixed problem with memory mapping if address is not aligned
- *
- * Revision 1.6  2000/01/25 14:37:39  calle
- * new message after successful detection including card revision and
- * used resources.
- *
- * Revision 1.5  1999/11/05 16:38:01  calle
- * Cleanups before kernel 2.4:
- * - Changed all messages to use card->name or driver->name instead of
- *   constant string.
- * - Moved some data from struct avmcard into new struct avmctrl_info.
- *   Changed all lowlevel capi driver to match the new structur.
- *
- * Revision 1.4  1999/08/22 20:26:26  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.3  1999/07/09 15:05:41  keil
- * compat.h is now isdn_compat.h
- *
- * Revision 1.2  1999/07/05 15:09:51  calle
- * - renamed "appl_release" to "appl_released".
- * - version und profile data now cleared on controller reset
- * - extended /proc interface, to allow driver and controller specific
- *   informations to include by driver hackers.
- *
- * Revision 1.1  1999/07/01 15:26:30  calle
- * complete new version (I love it):
- * + new hardware independed "capi_driver" interface that will make it easy to:
- *   - support other controllers with CAPI-2.0 (i.e. USB Controller)
- *   - write a CAPI-2.0 for the passive cards
- *   - support serial link CAPI-2.0 boxes.
- * + wrote "capi_driver" for all supported cards.
- * + "capi_driver" (supported cards) now have to be configured with
- *   make menuconfig, in the past all supported cards where included
- *   at once.
- * + new and better informations in /proc/capi/
- * + new ioctl to switch trace of capi messages per controller
- *   using "avmcapictrl trace [contr] on|off|...."
- * + complete testcircle with all supported cards and also the
- *   PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
- *
- *
  */
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c
--- v2.4.5/linux/drivers/isdn/avmb1/c4.c	Sat May 19 17:54:14 2001
+++ linux/drivers/isdn/avmb1/c4.c	Tue Jun 12 10:35:21 2001
@@ -1,104 +1,9 @@
 /*
- * $Id: c4.c,v 1.20.6.6 2001/04/20 02:41:59 keil Exp $
+ * $Id: c4.c,v 1.20.6.8 2001/05/17 21:15:33 kai Exp $
  * 
- * Module for AVM C4 card.
+ * Module for AVM C4 & C2 card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
- * 
- * $Log: c4.c,v $
- * Revision 1.20.6.6  2001/04/20 02:41:59  keil
- * changes from mainstream
- *
- * Revision 1.20.6.5  2001/03/21 08:52:21  kai
- * merge from main branch: fix buffer for revision string (calle)
- *
- * Revision 1.20.6.4  2001/03/15 15:11:23  kai
- * *** empty log message ***
- *
- * Revision 1.20.6.3  2001/02/16 16:43:23  kai
- * Changes from -ac16, little bug fixes, typos and the like
- *
- * Revision 1.20.6.2  2001/02/13 11:43:29  kai
- * more compatility changes for 2.2.19
- *
- * Revision 1.20.6.1  2000/11/28 12:02:45  kai
- * MODULE_DEVICE_TABLE for 2.4
- *
- * Revision 1.20.2.2  2000/11/26 17:47:53  kai
- * added PCI_DEV_TABLE for 2.4
- *
- * Revision 1.20.2.1  2000/11/26 17:14:19  kai
- * fix device ids
- * also needs patches to include/linux/pci_ids.h
- *
- * Revision 1.20  2000/11/23 20:45:14  kai
- * fixed module_init/exit stuff
- * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
- *
- * Revision 1.19  2000/11/19 17:02:47  kai
- * compatibility cleanup - part 3
- *
- * Revision 1.18  2000/11/01 14:05:02  calle
- * - use module_init/module_exit from linux/init.h.
- * - all static struct variables are initialized with "membername:" now.
- * - avm_cs.c, let it work with newer pcmcia-cs.
- *
- * Revision 1.17  2000/10/10 17:44:19  kai
- * changes from/for 2.2.18
- *
- * Revision 1.16  2000/08/20 07:30:13  keil
- * changes for 2.4
- *
- * Revision 1.15  2000/08/08 09:24:19  calle
- * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI
- *
- * Revision 1.14  2000/08/04 12:20:08  calle
- * - Fix unsigned/signed warning in the right way ...
- *
- * Revision 1.13  2000/07/20 10:21:21  calle
- * Bugfix: driver will not be unregistered, if not cards were detected.
- *         this result in an oops in kcapi.c
- *
- * Revision 1.12  2000/06/19 16:51:53  keil
- * don't free skb in irq context
- *
- * Revision 1.11  2000/06/19 15:11:24  keil
- * avoid use of freed structs
- * changes from 2.4.0-ac21
- *
- * Revision 1.10  2000/05/29 12:29:18  keil
- * make pci_enable_dev compatible to 2.2 kernel versions
- *
- * Revision 1.9  2000/05/19 15:43:22  calle
- * added calls to pci_device_start().
- *
- * Revision 1.8  2000/04/03 16:38:05  calle
- * made suppress_pollack static.
- *
- * Revision 1.7  2000/04/03 13:29:24  calle
- * make Tim Waugh happy (module unload races in 2.3.99-pre3).
- * no real problem there, but now it is much cleaner ...
- *
- * Revision 1.6  2000/03/17 12:21:08  calle
- * send patchvalues now working.
- *
- * Revision 1.5  2000/03/16 15:21:03  calle
- * Bugfix in c4_remove: loop 5 times instead of 4 :-(
- *
- * Revision 1.4  2000/02/02 18:36:03  calle
- * - Modules are now locked while init_module is running
- * - fixed problem with memory mapping if address is not aligned
- *
- * Revision 1.3  2000/01/25 14:37:39  calle
- * new message after successful detection including card revision and
- * used resources.
- *
- * Revision 1.2  2000/01/21 20:52:58  keil
- * pci_find_subsys as local function for 2.2.X kernel
- *
- * Revision 1.1  2000/01/20 10:51:37  calle
- * Added driver for C4.
- *
  *
  */
 
@@ -122,15 +27,11 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.20.6.8 $";
+static char *revision = "$Revision: 1.20.6.9 $";
 
 #undef CONFIG_C4_DEBUG
 #undef CONFIG_C4_POLLDEBUG
 
-/* ------------------------------------------------------------- */
-#ifndef PCI_DEVICE_ID_AVM_C2
-#define PCI_DEVICE_ID_AVM_C2	0x1100
-#endif
 /* ------------------------------------------------------------- */
 
 static int suppress_pollack;
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/avmb1/capicmd.h linux/drivers/isdn/avmb1/capicmd.h
--- v2.4.5/linux/drivers/isdn/avmb1/capicmd.h	Sat May 19 17:54:14 2001
+++ linux/drivers/isdn/avmb1/capicmd.h	Tue Jun 12 13:03:18 2001
@@ -1,31 +1,9 @@
 /*
- * $Id: capicmd.h,v 1.2 2000/03/03 15:50:42 calle Exp $
+ * $Id: capicmd.h,v 1.2.6.1 2001/05/17 20:41:51 kai Exp $
  * 
  * CAPI 2.0 Interface for Linux
  * 
  * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
- * 
- * $Log: capicmd.h,v $
- * Revision 1.2  2000/03/03 15:50:42  calle
- * - kernel CAPI:
- *   - Changed parameter "param" in capi_signal from __u32 to void *.
- *   - rewrote notifier handling in kcapi.c
- *   - new notifier NCCI_UP and NCCI_DOWN
- * - User CAPI:
- *   - /dev/capi20 is now a cloning device.
- *   - middleware extentions prepared.
- * - capidrv.c
- *   - locking of list operations and module count updates.
- *
- * Revision 1.1  1997/03/04 21:50:30  calle
- * Frirst version in isdn4linux
- *
- * Revision 2.2  1997/02/12 09:31:39  calle
- * new version
- *
- * Revision 1.1  1997/01/31 10:32:20  calle
- * Initial revision
- *
  * 
  */
 #ifndef __CAPICMD_H__
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/avmb1/capifs.c linux/drivers/isdn/avmb1/capifs.c
--- v2.4.5/linux/drivers/isdn/avmb1/capifs.c	Thu May 24 15:42:58 2001
+++ linux/drivers/isdn/avmb1/capifs.c	Tue Jun 12 13:03:18 2001
@@ -1,10 +1,10 @@
 /*
  * $Id: capifs.c,v 1.14.6.7 2001/05/24 08:29:08 kai Exp $
- *
+ * 
  * (c) Copyright 2000 by Carsten Paeth (calle@calle.de)
  *
  * Heavily based on devpts filesystem from H. Peter Anvin
- *
+ * 
  */
 
 #include <linux/version.h>
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/avmb1/capifs.h linux/drivers/isdn/avmb1/capifs.h
--- v2.4.5/linux/drivers/isdn/avmb1/capifs.h	Sat May 19 17:54:14 2001
+++ linux/drivers/isdn/avmb1/capifs.h	Tue Jun 12 13:03:18 2001
@@ -1,23 +1,7 @@
 /*
- * $Id: capifs.h,v 1.2 2000/03/08 17:06:33 calle Exp $
+ * $Id: capifs.h,v 1.2.6.1 2001/05/17 20:41:51 kai Exp $
  * 
  * (c) Copyright 2000 by Carsten Paeth (calle@calle.de)
- *
- * $Log: capifs.h,v $
- * Revision 1.2  2000/03/08 17:06:33  calle
- * - changes for devfs and 2.3.49
- * - capifs now configurable (no need with devfs)
- * - New Middleware ioctl CAPI_NCCI_GETUNIT
- * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
- *
- * Revision 1.1  2000/03/03 16:48:38  calle
- * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
- *   It is now possible to create a connection with a CAPI2.0 applikation
- *   and than to handle the data connection from /dev/capi/ (capifs) and also
- *   using async or sync PPP on this connection.
- *   The two major device number 190 and 191 are not confirmed yet,
- *   but I want to save the code in cvs, before I go on.
- *
  *
  */
 
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/avmb1/capiutil.h linux/drivers/isdn/avmb1/capiutil.h
--- v2.4.5/linux/drivers/isdn/avmb1/capiutil.h	Sat May 19 17:54:14 2001
+++ linux/drivers/isdn/avmb1/capiutil.h	Tue Jun 12 13:03:18 2001
@@ -1,45 +1,10 @@
 /*
- * $Id: capiutil.h,v 1.5 2000/03/03 15:50:42 calle Exp $
+ * $Id: capiutil.h,v 1.5.6.1 2001/05/17 20:41:51 kai Exp $
  * 
  * CAPI 2.0 defines & types
  * 
  * From CAPI 2.0 Development Kit AVM 1995 (capi20.h)
  * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
- * 
- * $Log: capiutil.h,v $
- * Revision 1.5  2000/03/03 15:50:42  calle
- * - kernel CAPI:
- *   - Changed parameter "param" in capi_signal from __u32 to void *.
- *   - rewrote notifier handling in kcapi.c
- *   - new notifier NCCI_UP and NCCI_DOWN
- * - User CAPI:
- *   - /dev/capi20 is now a cloning device.
- *   - middleware extentions prepared.
- * - capidrv.c
- *   - locking of list operations and module count updates.
- *
- * Revision 1.4  1999/09/15 08:16:03  calle
- * Implementation of 64Bit extention complete.
- *
- * Revision 1.3  1999/09/07 09:02:53  calle
- * SETDATA removed. Now inside the kernel the datapart of DATA_B3_REQ and
- * DATA_B3_IND is always directly after the CAPI message. The "Data" member
- * ist never used inside the kernel.
- *
- * Revision 1.2  1997/05/18 09:24:19  calle
- * added verbose disconnect reason reporting to avmb1.
- * some fixes in capi20 interface.
- * changed info messages for B1-PCI
- *
- * Revision 1.1  1997/03/04 21:50:35  calle
- * Frirst version in isdn4linux
- *
- * Revision 2.2  1997/02/12 09:31:39  calle
- * new version
- *
- * Revision 1.1  1997/01/31 10:32:20  calle
- * Initial revision
- *
  * 
  */
 #ifndef __CAPIUTIL_H__
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/avmb1/kcapi.c linux/drivers/isdn/avmb1/kcapi.c
--- v2.4.5/linux/drivers/isdn/avmb1/kcapi.c	Sat May 19 17:54:14 2001
+++ linux/drivers/isdn/avmb1/kcapi.c	Tue Jun 12 13:03:18 2001
@@ -1,128 +1,10 @@
 /*
- * $Id: kcapi.c,v 1.21.6.5 2001/03/21 08:52:21 kai Exp $
+ * $Id: kcapi.c,v 1.21.6.6 2001/05/17 20:41:51 kai Exp $
  * 
  * Kernel CAPI 2.0 Module
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
- * $Log: kcapi.c,v $
- * Revision 1.21.6.5  2001/03/21 08:52:21  kai
- * merge from main branch: fix buffer for revision string (calle)
- *
- * Revision 1.21.6.4  2001/03/15 15:11:24  kai
- * *** empty log message ***
- *
- * Revision 1.21.6.3  2001/03/13 16:17:08  kai
- * spelling fixes from 2.4.3-pre
- *
- * Revision 1.21.6.2  2001/02/13 11:43:29  kai
- * more compatility changes for 2.2.19
- *
- * Revision 1.21.6.1  2000/12/10 23:39:19  kai
- * in 2.4 we don't have tq_scheduler anymore.
- * also add one supported card to hfc_pci.c
- * (from main branch)
- *
- * Revision 1.21  2000/11/23 20:45:14  kai
- * fixed module_init/exit stuff
- * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
- *
- * Revision 1.20  2000/11/19 17:01:53  kai
- * compatibility cleanup - part 2
- *
- * Revision 1.19  2000/11/01 14:05:02  calle
- * - use module_init/module_exit from linux/init.h.
- * - all static struct variables are initialized with "membername:" now.
- * - avm_cs.c, let it work with newer pcmcia-cs.
- *
- * Revision 1.18  2000/07/20 10:22:27  calle
- * - Made procfs function cleaner and removed variable "begin".
- *
- * Revision 1.17  2000/04/21 13:00:56  calle
- * Bugfix: driver_proc_info was also wrong.
- *
- * Revision 1.16  2000/04/21 12:38:42  calle
- * Bugfix: error in proc_ functions, begin-off => off-begin
- *
- * Revision 1.15  2000/04/06 15:01:25  calle
- * Bugfix: crash in capidrv.c when reseting a capi controller.
- * - changed code order on remove of controller.
- * - using tq_schedule for notifier in kcapi.c.
- * - now using spin_lock_irqsave() and spin_unlock_irqrestore().
- * strange: sometimes even MP hang on unload of isdn.o ...
- *
- * Revision 1.14  2000/04/03 13:29:25  calle
- * make Tim Waugh happy (module unload races in 2.3.99-pre3).
- * no real problem there, but now it is much cleaner ...
- *
- * Revision 1.13  2000/03/03 15:50:42  calle
- * - kernel CAPI:
- *   - Changed parameter "param" in capi_signal from __u32 to void *.
- *   - rewrote notifier handling in kcapi.c
- *   - new notifier NCCI_UP and NCCI_DOWN
- * - User CAPI:
- *   - /dev/capi20 is now a cloning device.
- *   - middleware extentions prepared.
- * - capidrv.c
- *   - locking of list operations and module count updates.
- *
- * Revision 1.12  2000/01/28 16:45:39  calle
- * new manufacturer command KCAPI_CMD_ADDCARD (generic addcard),
- * will search named driver and call the add_card function if one exist.
- *
- * Revision 1.11  1999/11/23 13:29:29  calle
- * Bugfix: incoming capi message were never traced.
- *
- * Revision 1.10  1999/10/26 15:30:32  calle
- * Generate error message if user want to add card, but driver module is
- * not loaded.
- *
- * Revision 1.9  1999/10/11 22:04:12  keil
- * COMPAT_NEED_UACCESS (no include in isdn_compat.h)
- *
- * Revision 1.8  1999/09/10 17:24:18  calle
- * Changes for proposed standard for CAPI2.0:
- * - AK148 "Linux Exention"
- *
- * Revision 1.7  1999/09/04 06:20:05  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.6  1999/07/20 06:41:49  calle
- * Bugfix: After the redesign of the AVM B1 driver, the driver didn't even
- *         compile, if not selected as modules.
- *
- * Revision 1.5  1999/07/09 15:05:48  keil
- * compat.h is now isdn_compat.h
- *
- * Revision 1.4  1999/07/08 14:15:17  calle
- * Forgot to count down ncards in drivercb_detach_ctr.
- *
- * Revision 1.3  1999/07/06 07:42:02  calle
- * - changes in /proc interface
- * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb.
- *
- * Revision 1.2  1999/07/05 15:09:52  calle
- * - renamed "appl_release" to "appl_released".
- * - version und profile data now cleared on controller reset
- * - extended /proc interface, to allow driver and controller specific
- *   informations to include by driver hackers.
- *
- * Revision 1.1  1999/07/01 15:26:42  calle
- * complete new version (I love it):
- * + new hardware independed "capi_driver" interface that will make it easy to:
- *   - support other controllers with CAPI-2.0 (i.e. USB Controller)
- *   - write a CAPI-2.0 for the passive cards
- *   - support serial link CAPI-2.0 boxes.
- * + wrote "capi_driver" for all supported cards.
- * + "capi_driver" (supported cards) now have to be configured with
- *   make menuconfig, in the past all supported cards where included
- *   at once.
- * + new and better informations in /proc/capi/
- * + new ioctl to switch trace of capi messages per controller
- *   using "avmcapictrl trace [contr] on|off|...."
- * + complete testcircle with all supported cards and also the
- *   PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
- *
  */
 #define CONFIG_AVMB1_COMPAT
 
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/avmb1/t1isa.c linux/drivers/isdn/avmb1/t1isa.c
--- v2.4.5/linux/drivers/isdn/avmb1/t1isa.c	Sat May 19 17:54:14 2001
+++ linux/drivers/isdn/avmb1/t1isa.c	Tue Jun 12 13:03:18 2001
@@ -1,104 +1,10 @@
 /*
- * $Id: t1isa.c,v 1.16.6.4 2001/03/21 08:52:21 kai Exp $
+ * $Id: t1isa.c,v 1.16.6.6 2001/05/17 21:15:33 kai Exp $
  * 
  * Module for AVM T1 HEMA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
- * $Log: t1isa.c,v $
- * Revision 1.16.6.4  2001/03/21 08:52:21  kai
- * merge from main branch: fix buffer for revision string (calle)
- *
- * Revision 1.16.6.3  2001/03/15 15:11:24  kai
- * *** empty log message ***
- *
- * Revision 1.16.6.2  2001/02/16 16:43:24  kai
- * Changes from -ac16, little bug fixes, typos and the like
- *
- * Revision 1.16.6.1  2001/02/13 11:43:29  kai
- * more compatility changes for 2.2.19
- *
- * Revision 1.16  2000/11/23 20:45:14  kai
- * fixed module_init/exit stuff
- * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
- *
- * Revision 1.15  2000/11/01 14:05:02  calle
- * - use module_init/module_exit from linux/init.h.
- * - all static struct variables are initialized with "membername:" now.
- * - avm_cs.c, let it work with newer pcmcia-cs.
- *
- * Revision 1.14  2000/10/10 17:44:19  kai
- * changes from/for 2.2.18
- *
- * Revision 1.13  2000/08/04 15:36:31  calle
- * copied wrong from file to file :-(
- *
- * Revision 1.12  2000/08/04 12:20:08  calle
- * - Fix unsigned/signed warning in the right way ...
- *
- * Revision 1.11  2000/04/03 13:29:25  calle
- * make Tim Waugh happy (module unload races in 2.3.99-pre3).
- * no real problem there, but now it is much cleaner ...
- *
- * Revision 1.10  2000/02/02 18:36:04  calle
- * - Modules are now locked while init_module is running
- * - fixed problem with memory mapping if address is not aligned
- *
- * Revision 1.9  2000/01/25 14:37:39  calle
- * new message after successful detection including card revision and
- * used resources.
- *
- * Revision 1.8  1999/11/05 16:38:01  calle
- * Cleanups before kernel 2.4:
- * - Changed all messages to use card->name or driver->name instead of
- *   constant string.
- * - Moved some data from struct avmcard into new struct avmctrl_info.
- *   Changed all lowlevel capi driver to match the new structur.
- *
- * Revision 1.7  1999/09/15 08:16:03  calle
- * Implementation of 64Bit extention complete.
- *
- * Revision 1.6  1999/09/07 09:02:53  calle
- * SETDATA removed. Now inside the kernel the datapart of DATA_B3_REQ and
- * DATA_B3_IND is always directly after the CAPI message. The "Data" member
- * ist never used inside the kernel.
- *
- * Revision 1.5  1999/08/22 20:26:28  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.4  1999/07/09 15:05:50  keil
- * compat.h is now isdn_compat.h
- *
- * Revision 1.3  1999/07/06 07:42:04  calle
- * - changes in /proc interface
- * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb.
- *
- * Revision 1.2  1999/07/05 15:09:54  calle
- * - renamed "appl_release" to "appl_released".
- * - version und profile data now cleared on controller reset
- * - extended /proc interface, to allow driver and controller specific
- *   informations to include by driver hackers.
- *
- * Revision 1.1  1999/07/01 15:26:44  calle
- * complete new version (I love it):
- * + new hardware independed "capi_driver" interface that will make it easy to:
- *   - support other controllers with CAPI-2.0 (i.e. USB Controller)
- *   - write a CAPI-2.0 for the passive cards
- *   - support serial link CAPI-2.0 boxes.
- * + wrote "capi_driver" for all supported cards.
- * + "capi_driver" (supported cards) now have to be configured with
- *   make menuconfig, in the past all supported cards where included
- *   at once.
- * + new and better informations in /proc/capi/
- * + new ioctl to switch trace of capi messages per controller
- *   using "avmcapictrl trace [contr] on|off|...."
- * + complete testcircle with all supported cards and also the
- *   PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
- *
- *
  */
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c
--- v2.4.5/linux/drivers/isdn/avmb1/t1pci.c	Sat May 19 17:54:14 2001
+++ linux/drivers/isdn/avmb1/t1pci.c	Tue Jun 12 13:03:18 2001
@@ -1,80 +1,10 @@
 /*
- * $Id: t1pci.c,v 1.13.6.3 2001/03/21 08:52:21 kai Exp $
+ * $Id: t1pci.c,v 1.13.6.5 2001/05/17 20:41:51 kai Exp $
  * 
  * Module for AVM T1 PCI-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
- * $Log: t1pci.c,v $
- * Revision 1.13.6.3  2001/03/21 08:52:21  kai
- * merge from main branch: fix buffer for revision string (calle)
- *
- * Revision 1.13.6.2  2001/02/13 11:43:29  kai
- * more compatility changes for 2.2.19
- *
- * Revision 1.13.6.1  2000/11/28 12:02:45  kai
- * MODULE_DEVICE_TABLE for 2.4
- *
- * Revision 1.13.2.2  2000/11/26 17:47:53  kai
- * added PCI_DEV_TABLE for 2.4
- *
- * Revision 1.13.2.1  2000/11/26 17:14:19  kai
- * fix device ids
- * also needs patches to include/linux/pci_ids.h
- *
- * Revision 1.13  2000/11/23 20:45:14  kai
- * fixed module_init/exit stuff
- * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
- *
- * Revision 1.12  2000/11/01 14:05:02  calle
- * - use module_init/module_exit from linux/init.h.
- * - all static struct variables are initialized with "membername:" now.
- * - avm_cs.c, let it work with newer pcmcia-cs.
- *
- * Revision 1.11  2000/08/08 09:24:19  calle
- * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI
- *
- * Revision 1.10  2000/07/20 10:21:21  calle
- * Bugfix: driver will not be unregistered, if not cards were detected.
- *         this result in an oops in kcapi.c
- *
- * Revision 1.9  2000/05/19 15:43:22  calle
- * added calls to pci_device_start().
- *
- * Revision 1.8  2000/05/06 00:52:36  kai
- * merged changes from kernel tree
- * fixed timer and net_device->name breakage
- *
- * Revision 1.7  2000/04/07 15:26:55  calle
- * better error message if cabel not connected or T1 has no power.
- *
- * Revision 1.6  2000/04/03 13:29:25  calle
- * make Tim Waugh happy (module unload races in 2.3.99-pre3).
- * no real problem there, but now it is much cleaner ...
- *
- * Revision 1.5  2000/02/02 18:36:04  calle
- * - Modules are now locked while init_module is running
- * - fixed problem with memory mapping if address is not aligned
- *
- * Revision 1.4  2000/01/25 14:33:38  calle
- * - Added Support AVM B1 PCI V4.0 (tested with prototype)
- *   - splitted up t1pci.c into b1dma.c for common function with b1pciv4
- *   - support for revision register
- *
- * Revision 1.3  1999/11/13 21:27:16  keil
- * remove KERNELVERSION
- *
- * Revision 1.2  1999/11/05 16:38:02  calle
- * Cleanups before kernel 2.4:
- * - Changed all messages to use card->name or driver->name instead of
- *   constant string.
- * - Moved some data from struct avmcard into new struct avmctrl_info.
- *   Changed all lowlevel capi driver to match the new structur.
- *
- * Revision 1.1  1999/10/26 15:31:42  calle
- * Added driver for T1-PCI card.
- *
- *
  */
 
 #include <linux/config.h>
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c
--- v2.4.5/linux/drivers/isdn/hisax/callc.c	Mon Mar 26 15:38:19 2001
+++ linux/drivers/isdn/hisax/callc.c	Tue Jun 12 10:34:48 2001
@@ -1,4 +1,4 @@
-/* $Id: callc.c,v 2.51.6.2 2001/03/13 16:17:08 kai Exp $
+/* $Id: callc.c,v 2.51.6.3 2001/05/26 15:19:57 kai Exp $
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
@@ -20,7 +20,7 @@
 #define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module))
 #endif	/* MODULE */
 
-const char *lli_revision = "$Revision: 2.51.6.2 $";
+const char *lli_revision = "$Revision: 2.51.6.3 $";
 
 extern struct IsdnCard cards[];
 extern int nrcards;
@@ -850,14 +850,14 @@
 
 #define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
 
-void __init
+int __init
 CallcNew(void)
 {
 	callcfsm.state_count = STATE_COUNT;
 	callcfsm.event_count = EVENT_COUNT;
 	callcfsm.strEvent = strEvent;
 	callcfsm.strState = strState;
-	FsmNew(&callcfsm, fnlist, FNCOUNT);
+	return FsmNew(&callcfsm, fnlist, FNCOUNT);
 }
 
 void
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c
--- v2.4.5/linux/drivers/isdn/hisax/config.c	Wed Apr 18 11:49:13 2001
+++ linux/drivers/isdn/hisax/config.c	Tue Jun 12 10:34:48 2001
@@ -1,4 +1,4 @@
-/* $Id: config.c,v 2.57.6.13 2001/04/08 19:41:28 kai Exp $
+/* $Id: config.c,v 2.57.6.14 2001/05/26 15:19:57 kai Exp $
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
@@ -1332,15 +1332,28 @@
 
 static int __init HiSax_init(void)
 {
-	int i,j;
+	int i, retval;
+#ifdef MODULE
+	int j;
 	int nzproto = 0;
+#endif
 
 	HiSaxVersion();
-	CallcNew();
-	Isdnl3New();
-	Isdnl2New();
-	TeiNew();
-	Isdnl1New();
+	retval = CallcNew();
+	if (retval)
+		goto out;
+	retval = Isdnl3New();
+	if (retval)
+		goto out_callc;
+	retval = Isdnl2New();
+	if (retval)
+		goto out_isdnl3;
+	retval = TeiNew();
+	if (retval)
+		goto out_isdnl2;
+	retval = Isdnl1New();
+	if (retval)
+		goto out_tei;
 
 #ifdef MODULE
 	if (!type[0]) {
@@ -1487,17 +1500,26 @@
 	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
 	       nrcards, (nrcards > 1) ? "s" : "");
 
-	if (HiSax_inithardware(NULL)) {
-		/* Install only, if at least one card found */
-		return (0);
-	} else {
-		Isdnl1Free();
-		TeiFree();
-		Isdnl2Free();
-		Isdnl3Free();
-		CallcFree();
-		return -EIO;
+	/* Install only, if at least one card found */
+	if (!HiSax_inithardware(NULL)) {
+		retval = -EIO;
+		goto out_isdnl1;
 	}
+
+	return 0;
+
+ out_isdnl1:
+	Isdnl1Free();
+ out_tei:
+	TeiFree();
+ out_isdnl2:
+	Isdnl2Free();
+ out_isdnl3:
+	Isdnl3Free();
+ out_callc:
+	CallcFree();
+ out:
+	return retval;
 }
 
 static void __exit HiSax_exit(void)
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/hisax/fsm.c linux/drivers/isdn/hisax/fsm.c
--- v2.4.5/linux/drivers/isdn/hisax/fsm.c	Fri Mar  2 11:12:08 2001
+++ linux/drivers/isdn/hisax/fsm.c	Tue Jun 12 10:34:48 2001
@@ -1,4 +1,4 @@
-/* $Id: fsm.c,v 1.14.6.1 2001/02/16 16:43:26 kai Exp $
+/* $Id: fsm.c,v 1.14.6.2 2001/05/26 15:19:57 kai Exp $
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
@@ -15,13 +15,16 @@
 
 #define FSM_TIMER_DEBUG 0
 
-void __init
+int __init
 FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount)
 {
 	int i;
 
 	fsm->jumpmatrix = (FSMFNPTR *)
 		kmalloc(sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count, GFP_KERNEL);
+	if (!fsm->jumpmatrix)
+		return -ENOMEM;
+
 	memset(fsm->jumpmatrix, 0, sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count);
 
 	for (i = 0; i < fncount; i++) 
@@ -32,6 +35,7 @@
 		} else		
 			fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
 				fnlist[i].state] = (FSMFNPTR) fnlist[i].routine;
+	return 0;
 }
 
 void
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/hisax/gazel.c linux/drivers/isdn/hisax/gazel.c
--- v2.4.5/linux/drivers/isdn/hisax/gazel.c	Fri Mar  2 11:12:08 2001
+++ linux/drivers/isdn/hisax/gazel.c	Tue Jun 12 10:34:48 2001
@@ -1,4 +1,4 @@
-/* $Id: gazel.c,v 2.11.6.4 2001/02/16 16:43:26 kai Exp $
+/* $Id: gazel.c,v 2.11.6.6 2001/06/08 08:48:46 kai Exp $
  *
  * gazel.c     low level stuff for Gazel isdn cards
  *
@@ -19,7 +19,7 @@
 #include <linux/pci.h>
 
 extern const char *CardType[];
-const char *gazel_revision = "$Revision: 2.11.6.4 $";
+const char *gazel_revision = "$Revision: 2.11.6.6 $";
 
 #define R647      1
 #define R685      2
@@ -439,10 +439,6 @@
 reserve_regions(struct IsdnCard *card, struct IsdnCardState *cs)
 {
 	unsigned int i, base = 0, adr = 0, len = 0;
-	long flags;
-
-	save_flags(flags);
-	cli();
 
 	switch (cs->subtyp) {
 		case R647:
@@ -487,17 +483,15 @@
 			break;
 	}
 
-	restore_flags(flags);
 	return 0;
 
       error:
-	restore_flags(flags);
 	printk(KERN_WARNING "Gazel: %s io ports 0x%x-0x%x already in use\n",
 	       CardType[cs->typ], adr, adr + len);
 	return 1;
 }
 
-static int
+static int __init
 setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
 {
 	printk(KERN_INFO "Gazel: ISA PnP card automatic recognition\n");
@@ -546,7 +540,7 @@
 
 static struct pci_dev *dev_tel __initdata = NULL;
 
-static int
+static int __init
 setup_gazelpci(struct IsdnCardState *cs)
 {
 	u_int pci_ioaddr0 = 0, pci_ioaddr1 = 0;
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h
--- v2.4.5/linux/drivers/isdn/hisax/hisax.h	Wed Apr 18 11:49:14 2001
+++ linux/drivers/isdn/hisax/hisax.h	Tue Jun 12 10:34:48 2001
@@ -1,4 +1,4 @@
-/* $Id: hisax.h,v 2.52.6.4 2001/04/08 19:32:26 kai Exp $
+/* $Id: hisax.h,v 2.52.6.5 2001/05/26 15:19:57 kai Exp $
  *
  *   Basic declarations, defines and prototypes
  *
@@ -1304,7 +1304,7 @@
 int getcallref(u_char * p);
 int newcallref(void);
 
-void FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount);
+int FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount);
 void FsmFree(struct Fsm *fsm);
 int FsmEvent(struct FsmInst *fi, int event, void *arg);
 void FsmChangeState(struct FsmInst *fi, int newstate);
@@ -1335,19 +1335,19 @@
 
 int ll_run(struct IsdnCardState *cs, int addfeatures);
 void ll_stop(struct IsdnCardState *cs);
-void CallcNew(void);
+int CallcNew(void);
 void CallcFree(void);
 int CallcNewChan(struct IsdnCardState *cs);
 void CallcFreeChan(struct IsdnCardState *cs);
-void Isdnl1New(void);
+int Isdnl1New(void);
 void Isdnl1Free(void);
-void Isdnl2New(void);
+int Isdnl2New(void);
 void Isdnl2Free(void);
-void Isdnl3New(void);
+int Isdnl3New(void);
 void Isdnl3Free(void);
 void init_tei(struct IsdnCardState *cs, int protocol);
 void release_tei(struct IsdnCardState *cs);
 char *HiSax_getrev(const char *revision);
-void TeiNew(void);
+int TeiNew(void);
 void TeiFree(void);
 int certification_check(int output);
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c
--- v2.4.5/linux/drivers/isdn/hisax/isdnl1.c	Fri Mar  2 11:12:09 2001
+++ linux/drivers/isdn/hisax/isdnl1.c	Tue Jun 12 10:36:21 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnl1.c,v 2.41.6.2 2001/02/16 16:43:27 kai Exp $
+/* $Id: isdnl1.c,v 2.41.6.3 2001/05/26 15:19:57 kai Exp $
  *
  * isdnl1.c     common low level stuff for Siemens Chipsetbased isdn cards
  *              based on the teles driver from Jan den Ouden
@@ -15,7 +15,7 @@
  *
  */
 
-const char *l1_revision = "$Revision: 2.41.6.2 $";
+const char *l1_revision = "$Revision: 2.41.6.3 $";
 
 #define __NO_VERSION__
 #include <linux/init.h>
@@ -736,26 +736,41 @@
 
 #define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode))
 
-void __init 
+int __init
 Isdnl1New(void)
 {
-#ifdef HISAX_UINTERFACE
-	l1fsm_u.state_count = L1U_STATE_COUNT;
-	l1fsm_u.event_count = L1_EVENT_COUNT;
-	l1fsm_u.strEvent = strL1Event;
-	l1fsm_u.strState = strL1UState;
-	FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT);
-#endif
+	int retval;
+
 	l1fsm_s.state_count = L1S_STATE_COUNT;
 	l1fsm_s.event_count = L1_EVENT_COUNT;
 	l1fsm_s.strEvent = strL1Event;
 	l1fsm_s.strState = strL1SState;
-	FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT);
+	retval = FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT);
+	if (retval)
+		return retval;
+
 	l1fsm_b.state_count = L1B_STATE_COUNT;
 	l1fsm_b.event_count = L1_EVENT_COUNT;
 	l1fsm_b.strEvent = strL1Event;
 	l1fsm_b.strState = strL1BState;
-	FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT);
+	retval = FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT);
+	if (retval) {
+		FsmFree(&l1fsm_s);
+		return retval;
+	}
+#ifdef HISAX_UINTERFACE
+	l1fsm_u.state_count = L1U_STATE_COUNT;
+	l1fsm_u.event_count = L1_EVENT_COUNT;
+	l1fsm_u.strEvent = strL1Event;
+	l1fsm_u.strState = strL1UState;
+	retval = FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT);
+	if (retval) {
+		FsmFree(&l1fsm_s);
+		FsmFree(&l1fsm_b);
+		return retval;
+	}
+#endif
+	return 0;
 }
 
 void Isdnl1Free(void)
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/hisax/isdnl2.c linux/drivers/isdn/hisax/isdnl2.c
--- v2.4.5/linux/drivers/isdn/hisax/isdnl2.c	Fri Mar  2 11:12:09 2001
+++ linux/drivers/isdn/hisax/isdnl2.c	Tue Jun 12 10:34:48 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnl2.c,v 2.25.6.1 2001/02/16 16:43:27 kai Exp $
+/* $Id: isdnl2.c,v 2.25.6.2 2001/05/26 15:19:57 kai Exp $
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
@@ -16,7 +16,7 @@
 #include "hisax.h"
 #include "isdnl2.h"
 
-const char *l2_revision = "$Revision: 2.25.6.1 $";
+const char *l2_revision = "$Revision: 2.25.6.2 $";
 
 static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
 
@@ -1831,14 +1831,14 @@
 {
 }
 
-void __init
+int __init
 Isdnl2New(void)
 {
 	l2fsm.state_count = L2_STATE_COUNT;
 	l2fsm.event_count = L2_EVENT_COUNT;
 	l2fsm.strEvent = strL2Event;
 	l2fsm.strState = strL2State;
-	FsmNew(&l2fsm, L2FnList, L2_FN_COUNT);
+	return FsmNew(&l2fsm, L2FnList, L2_FN_COUNT);
 }
 
 void
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c
--- v2.4.5/linux/drivers/isdn/hisax/isdnl3.c	Fri Mar  2 11:12:09 2001
+++ linux/drivers/isdn/hisax/isdnl3.c	Tue Jun 12 10:34:48 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnl3.c,v 2.17.6.2 2001/02/16 16:43:27 kai Exp $
+/* $Id: isdnl3.c,v 2.17.6.3 2001/05/26 15:19:57 kai Exp $
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
@@ -18,7 +18,7 @@
 #include "isdnl3.h"
 #include <linux/config.h>
 
-const char *l3_revision = "$Revision: 2.17.6.2 $";
+const char *l3_revision = "$Revision: 2.17.6.3 $";
 
 static struct Fsm l3fsm;
 
@@ -591,14 +591,14 @@
 	}
 }
 
-void __init
+int __init
 Isdnl3New(void)
 {
 	l3fsm.state_count = L3_STATE_COUNT;
 	l3fsm.event_count = L3_EVENT_COUNT;
 	l3fsm.strEvent = strL3Event;
 	l3fsm.strState = strL3State;
-	FsmNew(&l3fsm, L3FnList, L3_FN_COUNT);
+	return FsmNew(&l3fsm, L3FnList, L3_FN_COUNT);
 }
 
 void
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/hisax/md5sums.asc linux/drivers/isdn/hisax/md5sums.asc
--- v2.4.5/linux/drivers/isdn/hisax/md5sums.asc	Thu Apr 19 22:30:09 2001
+++ linux/drivers/isdn/hisax/md5sums.asc	Tue Jun 12 10:34:48 2001
@@ -8,11 +8,11 @@
 # Read ../../../Documentation/isdn/HiSax.cert for more informations.
 # 
 9663cc9f4374c361197d394f6d27c459  isac.c
-9666c672c0fa0e65d5cc5b322f10a18c  isdnl1.c
-9250f15b932dfc36855aa120b896ed0b  isdnl2.c
-0cc2ef892bdb4a2be473e00eb1398950  isdnl3.c
-cac9c32fff889c57ff50d59823053019  tei.c
-665044a72334336533ac79da1a831b17  callc.c
+13c3eed869f5139f44c563e3a8fea1f5  isdnl1.c
+64dcc220ae42fe9e4bbc664c9525bd0a  isdnl2.c
+700aa997e04f5e7e0d32f0d60c8e7fa9  isdnl3.c
+51c603829b6cc4f8421f744ad657ceff  tei.c
+144d646162d83bb5b99095917d131865  callc.c
 e592db58630c1f1029cc064110108156  cert.c
 fadeb3b85bb23bc1ac48470c0848d6fa  l3dss1.c
 cf7dec9fac6283716904d26b99188476  l3_1tr6.c
@@ -22,12 +22,12 @@
 # end of md5sums
 
 -----BEGIN PGP SIGNATURE-----
-Version: 2.6.3i
+Version: 2.6.3in
 Charset: noconv
 
-iQCVAwUBOt+j/jpxHvX/mS9tAQGXwAP/U4voKzXAcTfo9CqJhHN92GRxunj6mlvn
-H+1pxSe0GdtC7BlrPhrokB5dNSwewk89Z5t7kTD76kx2FFuTcXBJxbgH7LZVF3ga
-JX92bOWQekHMH7Hk12Qc7zpeTmPzY02pvVc37Eo614BCvJMCk02cpQyo8a5wWRKH
-8vpQkQKiSyY=
-=FFLG
+iQCVAwUBOxFX6zpxHvX/mS9tAQE+bgP7B5FFxU+RQ3l8fBvZoMbu/Mslo9+XgtLg
+gK8Xwnp4Ij909fa2i6i2bvFPkzHULMqp2PRdtxBTn9CdhwSZyRByhCvZvDHitsv2
+ZEIRn2Bd1jhhgWcr5KCbjKUaIwcFY7RdSQJw/yCyGsodg1fLI+g+QrnMkICI/RTa
+AtYLLWgwEqo=
+=3IMV
 -----END PGP SIGNATURE-----
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/hisax/tei.c linux/drivers/isdn/hisax/tei.c
--- v2.4.5/linux/drivers/isdn/hisax/tei.c	Fri Mar  2 11:12:09 2001
+++ linux/drivers/isdn/hisax/tei.c	Tue Jun 12 10:34:48 2001
@@ -1,4 +1,4 @@
-/* $Id: tei.c,v 2.17.6.1 2001/02/16 16:43:29 kai Exp $
+/* $Id: tei.c,v 2.17.6.2 2001/05/26 15:19:57 kai Exp $
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
@@ -17,7 +17,7 @@
 #include <linux/init.h>
 #include <linux/random.h>
 
-const char *tei_revision = "$Revision: 2.17.6.1 $";
+const char *tei_revision = "$Revision: 2.17.6.2 $";
 
 #define ID_REQUEST	1
 #define ID_ASSIGNED	2
@@ -446,14 +446,14 @@
 
 #define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode))
 
-void __init
+int __init
 TeiNew(void)
 {
 	teifsm.state_count = TEI_STATE_COUNT;
 	teifsm.event_count = TEI_EVENT_COUNT;
 	teifsm.strEvent = strTeiEvent;
 	teifsm.strState = strTeiState;
-	FsmNew(&teifsm, TeiFnList, TEI_FN_COUNT);
+	return FsmNew(&teifsm, TeiFnList, TEI_FN_COUNT);
 }
 
 void
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/hysdn/hycapi.c linux/drivers/isdn/hysdn/hycapi.c
--- v2.4.5/linux/drivers/isdn/hysdn/hycapi.c	Sat May 19 17:54:14 2001
+++ linux/drivers/isdn/hysdn/hycapi.c	Tue Jun 12 10:34:48 2001
@@ -1,4 +1,4 @@
-/* $Id: hycapi.c,v 1.8.6.2 2001/04/20 02:42:00 keil Exp $
+/* $Id: hycapi.c,v 1.8.6.3 2001/05/26 15:19:58 kai Exp $
  *
  * Linux driver for HYSDN cards, CAPI2.0-Interface.
  * written by Ulrich Albrecht (u.albrecht@hypercope.de) for Hypercope GmbH
@@ -41,7 +41,7 @@
 #include "hysdn_defs.h"
 #include <linux/kernelcapi.h>
 
-static char hycapi_revision[]="$Revision: 1.8.6.2 $";
+static char hycapi_revision[]="$Revision: 1.8.6.3 $";
 
 unsigned int hycapi_enable = 0xffffffff; 
 MODULE_PARM(hycapi_enable, "i");
@@ -734,7 +734,7 @@
 	struct capi_driver *driver;
 	driver = &hycapi_driver;
 	if (!hy_di) {
-		printk(KERN_ERR "HYSDN: no capi-driver to detach (???)\n");
+		printk(KERN_ERR "HYSDN: no capi-driver to detach (?)\n");
 		return;
 	}
 	printk(KERN_NOTICE "HYSDN: Detaching capi-driver\n");
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/hysdn/hysdn_net.c linux/drivers/isdn/hysdn/hysdn_net.c
--- v2.4.5/linux/drivers/isdn/hysdn/hysdn_net.c	Sat May 19 17:54:14 2001
+++ linux/drivers/isdn/hysdn/hysdn_net.c	Tue Jun 12 10:34:48 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_net.c,v 1.8.6.2 2001/04/20 02:42:00 keil Exp $
+/* $Id: hysdn_net.c,v 1.8.6.3 2001/06/05 19:45:37 kai Exp $
 
  * Linux driver for HYSDN cards, net (ethernet type) handling routines.
  *
@@ -41,7 +41,7 @@
 MODULE_PARM(hynet_enable, "i");
 
 /* store the actual version for log reporting */
-char *hysdn_net_revision = "$Revision: 1.8.6.2 $";
+char *hysdn_net_revision = "$Revision: 1.8.6.3 $";
 
 #define MAX_SKB_BUFFERS 20	/* number of buffers for keeping TX-data */
 
@@ -304,8 +304,7 @@
 	hysdn_net_release(card);	/* release an existing net device */
 	if ((dev = kmalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) {
 		printk(KERN_WARNING "HYSDN: unable to allocate mem\n");
-		if (card->debug_flags & LOG_NET_INIT)
-			return (-ENOMEM);
+		return (-ENOMEM);
 	}
 	memset(dev, 0, sizeof(struct net_local));	/* clean the structure */
 
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/hysdn/hysdn_proclog.c linux/drivers/isdn/hysdn/hysdn_proclog.c
--- v2.4.5/linux/drivers/isdn/hysdn/hysdn_proclog.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hysdn/hysdn_proclog.c	Tue Jun 12 10:34:48 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_proclog.c,v 1.9 2000/11/25 17:01:01 kai Exp $
+/* $Id: hysdn_proclog.c,v 1.9.6.1 2001/05/26 15:19:58 kai Exp $
 
  * Linux driver for HYSDN cards, /proc/net filesystem log functions.
  * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -228,7 +228,7 @@
 	struct log_data *inf;
 	int len;
 	word ino;
-	struct procdata *pd;
+	struct procdata *pd = NULL;
 	hysdn_card *card;
 
 	if (!*((struct log_data **) file->private_data)) {
@@ -271,7 +271,7 @@
 hysdn_log_open(struct inode *ino, struct file *filep)
 {
 	hysdn_card *card;
-	struct procdata *pd;
+	struct procdata *pd = NULL;
 	ulong flags;
 
 	lock_kernel();
@@ -381,7 +381,7 @@
 	unsigned int mask = 0;
 	word ino;
 	hysdn_card *card;
-	struct procdata *pd;
+	struct procdata *pd = NULL;
 
 	if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE)
 		return (mask);	/* no polling for write supported */
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
--- v2.4.5/linux/drivers/isdn/isdn_ppp.c	Tue May 22 10:23:16 2001
+++ linux/drivers/isdn/isdn_ppp.c	Tue Jun 12 10:35:44 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.85.6.4 2001/04/08 18:53:07 kai Exp $
+/* $Id: isdn_ppp.c,v 1.85.6.5 2001/05/26 15:19:56 kai Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
@@ -83,7 +83,7 @@
 static int isdn_ppp_bundle(struct ippp_struct *, int unit);
 #endif	/* CONFIG_ISDN_MPP */
   
-char *isdn_ppp_revision = "$Revision: 1.85.6.4 $";
+char *isdn_ppp_revision = "$Revision: 1.85.6.5 $";
 
 static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
 
@@ -785,7 +785,10 @@
 			}
 			skb_reserve(skb, hl);
 			if (copy_from_user(skb_put(skb, count), buf, count))
+			{
+				kfree_skb(skb);
 				return -EFAULT;
+			}
 			if (is->debug & 0x40) {
 				printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
 				isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
diff -u --recursive --new-file v2.4.5/linux/drivers/media/radio/Config.in linux/drivers/media/radio/Config.in
--- v2.4.5/linux/drivers/media/radio/Config.in	Fri Apr 13 20:26:07 2001
+++ linux/drivers/media/radio/Config.in	Tue Jun 12 10:56:11 2001
@@ -24,6 +24,7 @@
 dep_tristate '  Guillemot MAXI Radio FM 2000 radio' CONFIG_RADIO_MAXIRADIO $CONFIG_VIDEO_DEV
 dep_tristate '  Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV
 dep_tristate '  miroSOUND PCM20 radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV $CONFIG_SOUND_ACI_MIXER
+dep_tristate '    miroSOUND PCM20 radio RDS user interface (EXPERIMENTAL)' CONFIG_RADIO_MIROPCM20_RDS $CONFIG_RADIO_MIROPCM20 $CONFIG_EXPERIMENTAL
 dep_tristate '  SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
 if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then
    hex '    SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284
diff -u --recursive --new-file v2.4.5/linux/drivers/media/radio/Makefile linux/drivers/media/radio/Makefile
--- v2.4.5/linux/drivers/media/radio/Makefile	Fri Apr 13 20:26:07 2001
+++ linux/drivers/media/radio/Makefile	Tue Jun 12 10:56:11 2001
@@ -21,11 +21,11 @@
 # All of the (potential) objects that export symbols.
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
 
-export-objs     :=	
+export-objs     := miropcm20-rds-core.o
 
 list-multi	:= miropcm20.o
 
-miropcm20-objs	:= radio-miropcm20.o rds-miropcm20.o
+miropcm20-objs	:= miropcm20-rds-core.o miropcm20-radio.o
 
 obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o
 obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o
@@ -37,6 +37,7 @@
 obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o
 obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
 obj-$(CONFIG_RADIO_MIROPCM20) += miropcm20.o
+obj-$(CONFIG_RADIO_MIROPCM20_RDS) += miropcm20-rds.o
 obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
diff -u --recursive --new-file v2.4.5/linux/drivers/media/radio/miropcm20-radio.c linux/drivers/media/radio/miropcm20-radio.c
--- v2.4.5/linux/drivers/media/radio/miropcm20-radio.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/radio/miropcm20-radio.c	Tue Jun 12 10:56:11 2001
@@ -0,0 +1,286 @@
+/* Miro PCM20 radio driver for Linux radio support
+ * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
+ * Thanks to Norberto Pellici for the ACI device interface specification
+ * The API part is based on the radiotrack driver by M. Kirkwood
+ * This driver relies on the aci mixer (drivers/sound/aci.c)
+ * Look there for further info...
+ */
+
+/* Revision history:
+ *
+ *   1998        Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
+ *   2000-09-05  Robert Siemer <Robert.Siemer@gmx.de>
+ *        removed unfinished volume control (maybe adding it later again)
+ *        use OSS-mixer; added stereo control
+ */
+
+/* What ever you think about the ACI, version 0x07 is not very well!
+ * I cant get frequency, 'tuner status', 'tuner flags' or mute/mono
+ * conditions...                Robert 
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/videodev.h>
+#include "../../sound/aci.h"
+#include "miropcm20-rds-core.h"
+
+static int users = 0;
+static int radio_nr = -1;
+MODULE_PARM(radio_nr, "i");
+
+struct pcm20_device {
+	unsigned long freq;
+	int muted;
+	int stereo;
+};
+
+
+static int pcm20_mute(struct pcm20_device *dev, unsigned char mute)
+{
+	dev->muted = mute;
+	return aci_write_cmd(ACI_SET_TUNERMUTE, mute);
+}
+
+static int pcm20_stereo(struct pcm20_device *dev, unsigned char stereo)
+{
+	dev->stereo = stereo;
+	return aci_write_cmd(ACI_SET_TUNERMONO, !stereo);
+}
+
+static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq)
+{
+	unsigned char freql;
+	unsigned char freqh;
+
+	dev->freq=freq;
+
+	freq /= 160;
+	if (!(aci_version==0x07 || aci_version>=0xb0))
+		freq /= 10;  /* I don't know exactly which version
+			      * needs this hack */
+	freql = freq & 0xff;
+	freqh = freq >> 8;
+
+	aci_rds_cmd(RDS_RESET, 0, 0);
+	pcm20_stereo(dev, 1);
+
+	return aci_rw_cmd(ACI_WRITE_TUNE, freql, freqh);
+}
+
+static int pcm20_getflags(struct pcm20_device *dev, __u32 *flags, __u16 *signal)
+{
+	/* okay, check for signal, stereo and rds here... */
+	int i;
+	unsigned char buf;
+
+	if ((i=aci_rw_cmd(ACI_READ_TUNERSTATION, -1, -1))<0)
+		return i;
+#if DEBUG
+	printk("check_sig: 0x%x\n", i);
+#endif
+	if (i & 0x80) {
+		/* no signal from tuner */
+		*flags=0;
+		*signal=0;
+		return 0;
+	} else
+		*signal=0xffff;
+
+	if ((i=aci_rw_cmd(ACI_READ_TUNERSTEREO, -1, -1))<0)
+		return i;
+	if (i & 0x40) {
+		*flags=0;
+	} else {
+		/* stereo */
+		*flags=VIDEO_TUNER_STEREO_ON;
+		/* I cant see stereo, when forced to mono */
+		dev->stereo=1;
+	}
+
+	if ((i=aci_rds_cmd(RDS_STATUS, &buf, 1))<0)
+		return i;
+	if (buf & 1)
+		/* RDS available */
+		*flags|=VIDEO_TUNER_RDS_ON;
+	else
+		return 0;
+
+	if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0)
+		return i;
+#if DEBUG
+	printk("rds-signal: %d\n", buf);
+#endif
+	if (buf > 15) {
+		printk("miropcm20-radio: RX strengths unexpected high...\n");
+		buf=15;
+	}
+	/* refine signal */
+	if ((*signal=SCALE(15, 0xffff, buf))==0)
+		*signal = 1;
+
+	return 0;
+}
+
+static int pcm20_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+	struct pcm20_device *pcm20=dev->priv;
+	int i;
+	
+	switch(cmd)
+	{
+		case VIDIOCGCAP:
+		{
+			struct video_capability v;
+			v.type=VID_TYPE_TUNER;
+			strcpy(v.name, "Miro PCM20");
+			v.channels=1;
+			v.audios=1;
+			/* No we don't do pictures */
+			v.maxwidth=0;
+			v.maxheight=0;
+			v.minwidth=0;
+			v.minheight=0;
+			if(copy_to_user(arg,&v,sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCGTUNER:
+		{
+			struct video_tuner v;
+			if(copy_from_user(&v, arg,sizeof(v))!=0) 
+				return -EFAULT;
+			if(v.tuner)	/* Only 1 tuner */ 
+				return -EINVAL;
+			v.rangelow=87*16000;
+			v.rangehigh=108*16000;
+			pcm20_getflags(pcm20, &v.flags, &v.signal);
+			v.flags|=VIDEO_TUNER_LOW;
+			v.mode=VIDEO_MODE_AUTO;
+			strcpy(v.name, "FM");
+			if(copy_to_user(arg,&v, sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSTUNER:
+		{
+			struct video_tuner v;
+			if(copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			if(v.tuner!=0)
+				return -EINVAL;
+			/* Only 1 tuner so no setting needed ! */
+			return 0;
+		}
+		case VIDIOCGFREQ:
+			if(copy_to_user(arg, &pcm20->freq, sizeof(pcm20->freq)))
+				return -EFAULT;
+			return 0;
+		case VIDIOCSFREQ:
+			if(copy_from_user(&pcm20->freq, arg, sizeof(pcm20->freq)))
+				return -EFAULT;
+			i=pcm20_setfreq(pcm20, pcm20->freq);
+#if DEBUG
+			printk("First view (setfreq): 0x%x\n", i);
+#endif
+			return i;
+		case VIDIOCGAUDIO:
+		{	
+			struct video_audio v;
+			memset(&v,0, sizeof(v));
+			v.flags=VIDEO_AUDIO_MUTABLE;
+			if (pcm20->muted)
+				v.flags|=VIDEO_AUDIO_MUTE;
+			v.mode=VIDEO_SOUND_STEREO;
+			if (pcm20->stereo)
+				v.mode|=VIDEO_SOUND_MONO;
+			/* v.step=2048; */
+			strcpy(v.name, "Radio");
+			if(copy_to_user(arg,&v, sizeof(v)))
+				return -EFAULT;
+			return 0;			
+		}
+		case VIDIOCSAUDIO:
+		{
+			struct video_audio v;
+			if(copy_from_user(&v, arg, sizeof(v))) 
+				return -EFAULT;
+			if(v.audio) 
+				return -EINVAL;
+
+			pcm20_mute(pcm20, !!(v.flags&VIDEO_AUDIO_MUTE));
+			if(v.flags&VIDEO_SOUND_MONO)
+				pcm20_stereo(pcm20, 0);
+			if(v.flags&VIDEO_SOUND_STEREO)
+				pcm20_stereo(pcm20, 1);
+
+			return 0;
+		}
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+static int pcm20_open(struct video_device *dev, int flags)
+{
+	if(users)
+		return -EBUSY;
+	users++;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static void pcm20_close(struct video_device *dev)
+{
+	users--;
+	MOD_DEC_USE_COUNT;
+}
+
+static struct pcm20_device pcm20_unit = {
+	freq:   87*16000,
+	muted:  1,
+	stereo: 0
+};
+
+static struct video_device pcm20_radio = {
+	owner:		THIS_MODULE,
+	name:		"Miro PCM 20 radio",
+	type:		VID_TYPE_TUNER,
+	hardware:	VID_HARDWARE_RTRACK,
+	open:		pcm20_open,
+	close:		pcm20_close,
+	ioctl:		pcm20_ioctl,
+	priv:		&pcm20_unit
+};
+
+static int __init pcm20_init(void)
+{
+	if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1)
+		goto video_register_device;
+		
+	if(attach_aci_rds()<0)
+		goto attach_aci_rds;
+
+	printk(KERN_INFO "Miro PCM20 radio card driver.\n");
+
+	return 0;
+
+ attach_aci_rds:
+	video_unregister_device(&pcm20_radio);
+ video_register_device:
+	return -EINVAL;
+}
+
+MODULE_AUTHOR("Ruurd Reitsma");
+MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card.");
+
+EXPORT_NO_SYMBOLS;
+
+static void __exit pcm20_cleanup(void)
+{
+	unload_aci_rds();
+	video_unregister_device(&pcm20_radio);
+}
+
+module_init(pcm20_init);
+module_exit(pcm20_cleanup);
diff -u --recursive --new-file v2.4.5/linux/drivers/media/radio/miropcm20-rds-core.c linux/drivers/media/radio/miropcm20-rds-core.c
--- v2.4.5/linux/drivers/media/radio/miropcm20-rds-core.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/radio/miropcm20-rds-core.c	Tue Jun 12 10:56:11 2001
@@ -0,0 +1,210 @@
+/*
+ *  Many thanks to Fred Seidel <seidel@metabox.de>, the
+ *  designer of the RDS decoder hardware. With his help
+ *  I was able to code this driver.
+ *  Thanks also to Norberto Pellicci, Dominic Mounteney
+ *  <DMounteney@pinnaclesys.com> and www.teleauskunft.de
+ *  for good hints on finding Fred. It was somewhat hard
+ *  to locate him here in Germany... [:
+ *
+ * Revision history:
+ *
+ *   2000-08-09  Robert Siemer <Robert.Siemer@gmx.de>
+ *        RDS support for MiroSound PCM20 radio
+ */
+
+#define _NO_VERSION_
+
+/* #include <linux/kernel.h> */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/semaphore.h>
+#include <asm/io.h>
+#include "../../sound/aci.h"
+#include "miropcm20-rds-core.h"
+
+#define DEBUG 0
+
+static struct semaphore aci_rds_sem;
+
+#define RDS_DATASHIFT          2   /* Bit 2 */
+#define RDS_DATAMASK        (1 << RDS_DATASHIFT)
+#define RDS_BUSYMASK        0x10   /* Bit 4 */
+#define RDS_CLOCKMASK       0x08   /* Bit 3 */
+
+#define RDS_DATA(x)         (((x) >> RDS_DATASHIFT) & 1) 
+
+
+#if DEBUG
+static void print_matrix(char array[], unsigned int length)
+{
+        int i, j;
+
+        for (i=0; i<length; i++) {
+                printk(KERN_DEBUG "aci-rds: ");
+                for (j=7; j>=0; j--) {
+                        printk("%d", (array[i] >> j) & 0x1);
+                }
+                if (i%8 == 0)
+                        printk(" byte-border\n");
+                else
+                        printk("\n");
+        }
+}
+#endif /* DEBUG */
+
+static int byte2trans(unsigned char byte, unsigned char sendbuffer[], int size)
+{
+	int i;
+
+	if (size != 8)
+		return -1;
+	for (i = 7; i >= 0; i--)
+		sendbuffer[7-i] = (byte & (1 << i)) ? RDS_DATAMASK : 0;
+	sendbuffer[0] |= RDS_CLOCKMASK;
+
+	return 0;
+}
+
+static int rds_waitread(void)
+{
+	unsigned char byte;
+	int i=2000;
+
+	do {
+		byte=inb(RDS_REGISTER);
+		i--;
+	}
+	while ((byte & RDS_BUSYMASK) && i);
+
+	if (i) {
+		#if DEBUG
+		printk(KERN_DEBUG "rds_waitread()");
+		print_matrix(&byte, 1);
+		#endif
+		return (byte);
+	} else {
+		printk(KERN_WARNING "aci-rds: rds_waitread() timeout...\n");
+		return -1;
+	}
+}
+
+/* dont use any ..._nowait() function if you are not sure what you do... */
+
+static inline void rds_rawwrite_nowait(unsigned char byte)
+{
+	#if DEBUG
+	printk(KERN_DEBUG "rds_rawwrite()");
+	print_matrix(&byte, 1);
+	#endif
+	outb(byte, RDS_REGISTER);
+}
+
+static int rds_rawwrite(unsigned char byte)
+{
+	if (rds_waitread() >= 0) {
+		rds_rawwrite_nowait(byte);
+		return 0;
+	} else
+		return -1;
+}
+
+static int rds_write(unsigned char cmd)
+{
+	unsigned char sendbuffer[8];
+	int i;
+	
+	if (byte2trans(cmd, sendbuffer, 8) != 0){
+		return -1;
+	} else {
+		for (i=0; i<8; i++) {
+			rds_rawwrite(sendbuffer[i]);
+		}
+	}
+	return 0;
+}
+
+static int rds_readcycle_nowait(void)
+{
+	rds_rawwrite_nowait(0);
+	return rds_waitread();
+}
+
+static int rds_readcycle(void)
+{
+	if (rds_rawwrite(0) < 0)
+		return -1;
+	return rds_waitread();
+}
+
+static int rds_read(unsigned char databuffer[], int datasize)
+{
+	#define READSIZE (8*datasize)
+
+	int i,j;
+
+	if (datasize < 1)  /* nothing to read */
+		return 0;
+
+	/* to be able to use rds_readcycle_nowait()
+	   I have to waitread() here */
+	if (rds_waitread() < 0)
+		return -1;
+	
+	memset(databuffer, 0, datasize);
+
+	for (i=0; i< READSIZE; i++)
+		if((j=rds_readcycle_nowait()) < 0) {
+			return -1;
+		} else {
+			databuffer[i/8]|=(RDS_DATA(j) << (7-(i%8)));
+		}
+
+	return 0;
+}
+
+static int rds_ack(void)
+{
+	int i=rds_readcycle();
+
+	if (i < 0)
+		return -1;
+	if (i & RDS_DATAMASK) {
+		return 0;  /* ACK  */
+	} else {
+		printk(KERN_DEBUG "aci-rds: NACK\n");
+		return 1;  /* NACK */
+	}
+}
+
+int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
+{
+	int ret;
+
+	if (down_interruptible(&aci_rds_sem))
+		return -EINTR;
+
+	rds_write(cmd);
+
+	/* RDS_RESET doesn't need further processing */
+	if (cmd!=RDS_RESET && (rds_ack() || rds_read(databuffer, datasize)))
+		ret = -1;
+	else
+		ret = 0;
+
+	up(&aci_rds_sem);
+	
+	return ret;
+}
+EXPORT_SYMBOL(aci_rds_cmd);
+
+int __init attach_aci_rds(void)
+{
+	init_MUTEX(&aci_rds_sem);
+	return 0;
+}
+
+void __exit unload_aci_rds(void)
+{
+}
diff -u --recursive --new-file v2.4.5/linux/drivers/media/radio/miropcm20-rds-core.h linux/drivers/media/radio/miropcm20-rds-core.h
--- v2.4.5/linux/drivers/media/radio/miropcm20-rds-core.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/radio/miropcm20-rds-core.h	Tue Jun 12 10:56:11 2001
@@ -0,0 +1,19 @@
+#ifndef _MIROPCM20_RDS_CORE_H_
+#define _MIROPCM20_RDS_CORE_H_
+
+extern int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize);
+
+#define RDS_STATUS      0x01
+#define RDS_STATIONNAME 0x02
+#define RDS_TEXT        0x03
+#define RDS_ALTFREQ     0x04
+#define RDS_TIMEDATE    0x05
+#define RDS_PI_CODE     0x06
+#define RDS_PTYTATP     0x07
+#define RDS_RESET       0x08
+#define RDS_RXVALUE     0x09
+
+extern void __exit unload_aci_rds(void);
+extern int __init attach_aci_rds(void);
+
+#endif /* _MIROPCM20_RDS_CORE_H_ */
diff -u --recursive --new-file v2.4.5/linux/drivers/media/radio/miropcm20-rds.c linux/drivers/media/radio/miropcm20-rds.c
--- v2.4.5/linux/drivers/media/radio/miropcm20-rds.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/radio/miropcm20-rds.c	Tue Jun 12 10:56:11 2001
@@ -0,0 +1,140 @@
+/* MiroSOUND PCM20 radio rds interface driver
+ * (c) 2001 Robert Siemer <Robert.Siemer@gmx.de>
+ * Thanks to Fred Seidel. See miropcm20-rds-core.c for further information.
+ */
+
+/* Revision history:
+ *
+ *   2001-04-18  Robert Siemer <Robert.Siemer@gmx.de>
+ *        separate file for user interface driver
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <linux/devfs_fs_kernel.h>
+#include "miropcm20-rds-core.h"
+
+devfs_handle_t dfsh;
+char * text_buffer;
+static int rds_users = 0;
+
+
+static int rds_f_open(struct inode *in, struct file *fi)
+{
+	if(rds_users)
+		return -EBUSY;
+
+	if ((text_buffer=kmalloc(66, GFP_KERNEL)) == 0) {
+		printk(KERN_NOTICE "aci-rds: Out of memory by open()...\n");
+		return -ENOMEM;
+	}
+
+	rds_users++;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int rds_f_release(struct inode *in, struct file *fi)
+{
+	kfree(text_buffer);
+
+	rds_users--;
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static void print_matrix(char *ch, char out[])
+{
+        int j;
+
+	for (j=7; j>=0; j--) {
+		 out[7-j] = ((*ch >> j) & 0x1) + '0';
+	}
+}
+
+static ssize_t rds_f_read(struct file *file, char *buffer, size_t length, loff_t *offset)
+{
+//	i = sprintf(text_buffer, "length: %d, offset: %d\n", length, *offset);
+
+	char c;
+	char bits[8];
+
+	current->state=TASK_UNINTERRUPTIBLE;
+	schedule_timeout(2*HZ);
+	aci_rds_cmd(RDS_STATUS, &c, 1);
+	print_matrix(&c, bits);
+	if (copy_to_user(buffer, bits, 8))
+		return -EFAULT;
+
+/*	if ((c >> 3) & 1) {
+		aci_rds_cmd(RDS_STATIONNAME, text_buffer+1, 8);
+		text_buffer[0]  = ' ' ;
+		text_buffer[9]  = '\n';
+		return copy_to_user(buffer+8, text_buffer, 10) ? -EFAULT: 18;
+	}
+*/
+/*	if ((c >> 6) & 1) {
+		aci_rds_cmd(RDS_PTYTATP, &c, 1);
+		if ( c & 1)
+			sprintf(text_buffer, " M");
+		else
+			sprintf(text_buffer, " S");
+		if ((c >> 1) & 1)
+			sprintf(text_buffer+2, " TA");
+		else
+			sprintf(text_buffer+2, " --");
+		if ((c >> 7) & 1)
+			sprintf(text_buffer+5, " TP");
+		else
+			sprintf(text_buffer+5, " --");
+		sprintf(text_buffer+8, " %2d\n", (c >> 2) & 0x1f);
+		return copy_to_user(buffer+8, text_buffer, 12) ? -EFAULT: 20;
+	}
+*/
+
+	if ((c >> 4) & 1) {
+		aci_rds_cmd(RDS_TEXT, text_buffer, 65);
+		text_buffer[0]  = ' ' ;
+		text_buffer[65] = '\n';
+		return copy_to_user(buffer+8, text_buffer,66) ? -EFAULT : 66+8;
+	} else {
+		put_user('\n', buffer+8);
+		return 9;
+	}
+}
+
+static struct file_operations rds_f_ops = {
+	read:    rds_f_read,
+	open:    rds_f_open,
+	release: rds_f_release
+};
+
+
+static int __init miropcm20_rds_init(void)
+{
+	if ((dfsh = devfs_register(NULL, "v4l/rds/radiotext", 
+				   DEVFS_FL_DEFAULT | DEVFS_FL_AUTO_DEVNUM,
+				   0, 0, S_IRUGO | S_IFCHR, &rds_f_ops, NULL))
+	    == NULL)
+		goto devfs_register;
+
+	printk("miropcm20-rds: userinterface driver loaded.\n");
+#if DEBUG
+	printk("v4l-name: %s\n", devfs_get_name(pcm20_radio.devfs_handle, 0));
+#endif
+
+	return 0;
+
+ devfs_register:
+	return -EINVAL;
+}
+
+static void __exit miropcm20_rds_cleanup(void)
+{
+	devfs_unregister(dfsh);
+}
+
+module_init(miropcm20_rds_init);
+module_exit(miropcm20_rds_cleanup);
diff -u --recursive --new-file v2.4.5/linux/drivers/media/radio/radio-miropcm20.c linux/drivers/media/radio/radio-miropcm20.c
--- v2.4.5/linux/drivers/media/radio/radio-miropcm20.c	Sat May 19 17:43:06 2001
+++ linux/drivers/media/radio/radio-miropcm20.c	Wed Dec 31 16:00:00 1969
@@ -1,290 +0,0 @@
-/* Miro PCM20 radio driver for Linux radio support
- * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
- * Thanks to Norberto Pellici for the ACI device interface specification
- * The API part is based on the radiotrack driver by M. Kirkwood
- * This driver relies on the aci mixer (drivers/sound/aci.c)
- * Look there for further info...
- */
-
-/* Revision history:
- *
- *   1998        Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
- *   2000-09-05  Robert Siemer <Robert.Siemer@gmx.de>
- *        removed unfinished volume control (maybe adding it later again)
- *        use OSS-mixer; added stereo control
- */
-
-/* What ever you think about the ACI, version 0x07 is not very well!
- * I cant get frequency, 'tuner status', 'tuner flags' or mute/mono
- * conditions...                Robert 
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/videodev.h>
-#include <linux/devfs_fs_kernel.h>
-#include <asm/uaccess.h>
-
-char * aci_radio_name;
-
-#include "../../sound/aci.h"
-
-static int users = 0;
-static int radio_nr = -1;
-MODULE_PARM(radio_nr, "i");
-
-struct pcm20_device
-{
-	unsigned long freq;
-	int muted;
-	int stereo;
-};
-
-
-static int pcm20_mute(struct pcm20_device *dev, unsigned char mute)
-{
-	dev->muted = mute;
-	return aci_write_cmd(0xa3, mute);
-}
-
-static int pcm20_stereo(struct pcm20_device *dev, unsigned char stereo)
-{
-	dev->stereo = stereo;
-	return aci_write_cmd(0xa4, !stereo);
-}
-
-static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq)
-{
-	unsigned char freql;
-	unsigned char freqh;
-
-	dev->freq=freq;
-
-	freq /= 160;
-	if (!(aci_version==0x07 || aci_version>=0xb0))
-		freq /= 10;  /* I don't know exactly which version
-			      * needs this hack */
-	freql = freq & 0xff;
-	freqh = freq >> 8;
-
-	aci_rds_cmd(RDS_RESET, 0, 0);
-	pcm20_stereo(dev, 1);
-
-	return aci_rw_cmd(0xa7, freql, freqh);	/*  Tune to frequency	*/
-}
-
-static int pcm20_getflags(struct pcm20_device *dev, __u32 *flags, __u16 *signal)
-{
-	/* okay, check for signal, stereo and rds here... */
-	int i;
-	unsigned char buf;
-
-	if ((i=aci_rw_cmd(0xa9, -1, -1))<0)
-		return i;
-#if DEBUG
-	printk("check_sig: 0x%x\n", i);
-#endif
-	if (i & 0x80) {
-		/* no signal from tuner */
-		*flags=0;
-		*signal=0;
-		return 0;
-	} else
-		*signal=0xffff;
-
-	if ((i=aci_rw_cmd(0xa8, -1, -1))<0)
-		return i;
-	if (i & 0x40) {
-		*flags=0;
-	} else {
-		/* stereo */
-		*flags=VIDEO_TUNER_STEREO_ON;
-		/* I cant see stereo, when forced to mono */
-		dev->stereo=1;
-	}
-
-	if ((i=aci_rds_cmd(RDS_STATUS, &buf, 1))<0)
-		return i;
-	if (buf & 1)
-		/* RDS available */
-		*flags|=VIDEO_TUNER_RDS_ON;
-	else
-		return 0;
-
-	if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0)
-		return i;
-#if DEBUG
-	printk("rds-signal: %d\n", buf);
-#endif
-	if (buf > 15) {
-		printk("rds-miropcm20: RX strengths unexpected high...\n");
-		buf=15;
-	}
-	/* refine signal */
-	if ((*signal=SCALE(15, 0xffff, buf))==0)
-		*signal = 1;
-
-	return 0;
-}
-
-static int pcm20_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
-{
-	struct pcm20_device *pcm20=dev->priv;
-	int i;
-	
-	switch(cmd)
-	{
-		case VIDIOCGCAP:
-		{
-			struct video_capability v;
-			v.type=VID_TYPE_TUNER;
-			strcpy(v.name, "Miro PCM20");
-			v.channels=1;
-			v.audios=1;
-			/* No we don't do pictures */
-			v.maxwidth=0;
-			v.maxheight=0;
-			v.minwidth=0;
-			v.minheight=0;
-			if(copy_to_user(arg,&v,sizeof(v)))
-				return -EFAULT;
-			return 0;
-		}
-		case VIDIOCGTUNER:
-		{
-			struct video_tuner v;
-			if(copy_from_user(&v, arg,sizeof(v))!=0) 
-				return -EFAULT;
-			if(v.tuner)	/* Only 1 tuner */ 
-				return -EINVAL;
-			v.rangelow=87*16000;
-			v.rangehigh=108*16000;
-			pcm20_getflags(pcm20, &v.flags, &v.signal);
-			v.flags|=VIDEO_TUNER_LOW;
-			v.mode=VIDEO_MODE_AUTO;
-			strcpy(v.name, "FM");
-			if(copy_to_user(arg,&v, sizeof(v)))
-				return -EFAULT;
-			return 0;
-		}
-		case VIDIOCSTUNER:
-		{
-			struct video_tuner v;
-			if(copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
-			if(v.tuner!=0)
-				return -EINVAL;
-			/* Only 1 tuner so no setting needed ! */
-			return 0;
-		}
-		case VIDIOCGFREQ:
-			if(copy_to_user(arg, &pcm20->freq, sizeof(pcm20->freq)))
-				return -EFAULT;
-			return 0;
-		case VIDIOCSFREQ:
-			if(copy_from_user(&pcm20->freq, arg, sizeof(pcm20->freq)))
-				return -EFAULT;
-			i=pcm20_setfreq(pcm20, pcm20->freq);
-#if DEBUG
-			printk("First view (setfreq): 0x%x\n", i);
-#endif
-			return i;
-		case VIDIOCGAUDIO:
-		{	
-			struct video_audio v;
-			memset(&v,0, sizeof(v));
-			v.flags=VIDEO_AUDIO_MUTABLE;
-			if (pcm20->muted)
-				v.flags|=VIDEO_AUDIO_MUTE;
-			v.mode=VIDEO_SOUND_STEREO;
-			if (pcm20->stereo)
-				v.mode|=VIDEO_SOUND_MONO;
-			/* v.step=2048; */
-			strcpy(v.name, "Radio");
-			if(copy_to_user(arg,&v, sizeof(v)))
-				return -EFAULT;
-			return 0;			
-		}
-		case VIDIOCSAUDIO:
-		{
-			struct video_audio v;
-			if(copy_from_user(&v, arg, sizeof(v))) 
-				return -EFAULT;
-			if(v.audio) 
-				return -EINVAL;
-
-			pcm20_mute(pcm20, !!(v.flags&VIDEO_AUDIO_MUTE));
-			if(v.flags&VIDEO_SOUND_MONO)
-				pcm20_stereo(pcm20, 0);
-			if(v.flags&VIDEO_SOUND_STEREO)
-				pcm20_stereo(pcm20, 1);
-
-			return 0;
-		}
-		default:
-			return -ENOIOCTLCMD;
-	}
-}
-
-static int pcm20_open(struct video_device *dev, int flags)
-{
-	if(users)
-		return -EBUSY;
-	users++;
-	return 0;
-}
-
-static void pcm20_close(struct video_device *dev)
-{
-	users--;
-}
-
-static struct pcm20_device pcm20_unit=
-{
-	freq:   87*16000,
-	muted:  1,
-	stereo: 0
-};
-
-static struct video_device pcm20_radio=
-{
-	owner:		THIS_MODULE,
-	name:		"Miro PCM 20 radio",
-	type:		VID_TYPE_TUNER,
-	hardware:	VID_HARDWARE_RTRACK,
-	open:		pcm20_open,
-	close:		pcm20_close,
-	ioctl:		pcm20_ioctl,
-	priv:		&pcm20_unit
-};
-
-static int __init pcm20_init(void)
-{
-	if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-		return -EINVAL;
-		
-	if(attach_aci_rds()<0) {
-		video_unregister_device(&pcm20_radio);
-		return -EINVAL;
-	}
-#if DEBUG
-	printk("v4l-name: %s\n", devfs_get_name(pcm20_radio.devfs_handle, 0));
-#endif
-	printk(KERN_INFO "Miro PCM20 radio card driver.\n");
-
-	return 0;
-}
-
-MODULE_AUTHOR("Ruurd Reitsma");
-MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card.");
-
-EXPORT_NO_SYMBOLS;
-
-static void __exit pcm20_cleanup(void)
-{
-	unload_aci_rds();
-	video_unregister_device(&pcm20_radio);
-}
-
-module_init(pcm20_init);
-module_exit(pcm20_cleanup);
diff -u --recursive --new-file v2.4.5/linux/drivers/media/radio/rds-miropcm20.c linux/drivers/media/radio/rds-miropcm20.c
--- v2.4.5/linux/drivers/media/radio/rds-miropcm20.c	Fri Apr 13 20:26:07 2001
+++ linux/drivers/media/radio/rds-miropcm20.c	Wed Dec 31 16:00:00 1969
@@ -1,249 +0,0 @@
-/*
- *  Many thanks to Fred Seidel <seidel@metabox.de>, the
- *  designer of the RDS decoder hardware. With his help
- *  I was able to code this driver.
- *  Thanks also to Norberto Pellicci, Dominic Mounteney
- *  <DMounteney@pinnaclesys.com> and www.teleauskunft.de
- *  for good hints on finding Fred. It was somewhat hard
- *  to locate him here in Germany... [:
- *
- * Revision history:
- *
- *   2000-08-09  Robert Siemer <Robert.Siemer@gmx.de>
- *        RDS support for MiroSound PCM20 radio
- */
-
-#define _NO_VERSION_
-
-/* #include <linux/kernel.h> */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <asm/semaphore.h>
-#include <asm/io.h>
-#include "../../sound/aci.h"
-
-#define WATCHMASK       0352 /* 11101010 */
-
-#define DEBUG 0
-
-static struct semaphore aci_rds_sem;
-
-
-#define RDS_BUSYMASK        0x10   /* Bit 4 */
-#define RDS_CLOCKMASK       0x08   /* Bit 3 */
-#define RDS_DATAMASK        0x04   /* Bit 2 */
-
-
-static void print_matrix(char array[], unsigned int length)
-{
-        int i, j;
-
-        for (i=0; i<length; i++) {
-                printk("aci-rds: ");
-                for (j=7; j>=0; j--) {
-                        printk("%d", (array[i] >> j) & 0x1);
-                }
-                if (i%8 == 0)
-                        printk(" byte-border\n");
-                else
-                        printk("\n");
-        }
-}
-
-static int byte2trans(unsigned char byte, unsigned char sendbuffer[], int size)
-{
-	int i;
-
-	if (size != 8)
-		return -1;
-	for (i = 7; i >= 0; i--)
-		sendbuffer[7-i] = (byte & (1 << i)) ? RDS_DATAMASK : 0;
-	sendbuffer[0] |= RDS_CLOCKMASK;
-
-	return 0;
-}
-
-static int trans2byte(unsigned char buffer[], int size)
-{
-	int i;
-	unsigned char byte=0;
-
-	if (size != 8)
-		return -1;
-	for (i = 7; i >= 0; i--)
-		byte |= ((buffer[7-i] & RDS_DATAMASK) ? 1 : 0) << i;
-
-	return byte;
-}
-
-static int trans2data(unsigned char readbuffer[], int readsize, unsigned char data[], int datasize)
-{
-	int i,j;
-
-	if (readsize != datasize*8)
-		return -1;
-	for (i = 0; i < datasize; i++)
-		if ((j=trans2byte(&readbuffer[i*8], 8)) < 0)
-			return -1;
-		else
-			data[i]=j;
-	return 0;
-}
-
-static int rds_waitread(void)
-{
-	unsigned char byte;
-	int i=2000;
-
-	do {
-		byte=inb(RDS_REGISTER);
-		if ((byte & WATCHMASK) != WATCHMASK)
-			printk("aci-rds: Hidden information discoverd!\n");
-		i--;
-	}
-	while ((byte & RDS_BUSYMASK) && i);
-
-	if (i) {
-#if DEBUG
-		printk("rds_waitread()");
-		print_matrix(&byte, 1);
-#endif
-		return (byte);
-	} else {
-		printk("aci-rds: rds_waitread() timeout...\n");
-		return -1;
-	}
-}
-
-/* dont use any ..._nowait() function if you are not sure what you do... */
-
-static inline void rds_rawwrite_nowait(unsigned char byte)
-{
-#if DEBUG
-	printk("rds_rawwrite()");
-	print_matrix(&byte, 1);
-#endif
-	outb(byte, RDS_REGISTER);
-}
-
-static int rds_rawwrite(unsigned char byte)
-{
-	if (rds_waitread() >= 0) {
-		rds_rawwrite_nowait(byte);
-		return 0;
-	} else
-		return -1;
-}
-
-static int rds_write(unsigned char cmd)
-{
-	unsigned char sendbuffer[8];
-	int i;
-	
-	if (byte2trans(cmd, sendbuffer, 8) != 0){
-		return -1;
-	} else {
-		for (i=0; i<8; i++) {
-			rds_rawwrite(sendbuffer[i]);
-		}
-	}
-	return 0;
-}
-
-static int rds_readcycle_nowait(void)
-{
-	rds_rawwrite_nowait(0);
-	return rds_waitread();
-}
-
-static int rds_readcycle(void)
-{
-	if (rds_rawwrite(0) < 0)
-		return -1;
-	return rds_waitread();
-}
-
-static int rds_read(unsigned char databuffer[], int datasize)
-{
-
-#define READSIZE (8*datasize)
-
-	int i,j;
-	unsigned char* readbuffer;
-
-	if (!datasize)  /* nothing to read */
-		return 0;
-
-	/* to be able to use rds_readcycle_nowait()
-	   I have to readwait() here */
-	if (rds_waitread() < 0)
-		return -1;
-	
-	if ((readbuffer=kmalloc(READSIZE, GFP_KERNEL)) == 0) {
-		printk("aci-rds: Out of memory...\n");
-		return -ENOMEM;
-	} else {
-		if (signal_pending(current)) {
-			kfree(readbuffer);
-			return -EINTR;
-		}
-	}
-	
-	for (i=0; i< READSIZE; i++)
-		if((j=rds_readcycle_nowait()) < 0) {
-			kfree(readbuffer);
-			return -1;
-		} else
-			readbuffer[i]=j;
-	if (trans2data(readbuffer, READSIZE, databuffer, datasize) < 0) {
-		kfree(readbuffer);
-		return -1;
-	}
-	kfree(readbuffer);
-	return 0;
-}
-
-static int rds_ack(void)
-{
-	int i=rds_readcycle();
-
-	if (i < 0)
-		return -1;
-	if (i & RDS_DATAMASK) {
-		return 0;  /* ACK  */
-	} else {
-		return 1;  /* NACK */
-	}
-}
-
-int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
-{
-	int ret;
-
-	if (down_interruptible(&aci_rds_sem))
-		return -EINTR;
-
-	if (rds_write(cmd))
-		ret = -2;
-
-	/* RDS_RESET doesn't need further processing */
-	if (cmd!=RDS_RESET && (rds_ack() || rds_read(databuffer, datasize)))
-		ret = -1;
-	else
-		ret = 0;
-
-	up(&aci_rds_sem);
-	
-	return ret;
-}
-
-int __init attach_aci_rds(void)
-{
-	init_MUTEX(&aci_rds_sem);
-	return 0;
-}
-
-void __exit unload_aci_rds(void)
-{
-}
diff -u --recursive --new-file v2.4.5/linux/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c
--- v2.4.5/linux/drivers/media/video/bttv-driver.c	Sat May 19 17:43:06 2001
+++ linux/drivers/media/video/bttv-driver.c	Wed Jun 20 11:10:27 2001
@@ -2812,8 +2812,7 @@
 
         /* disable PCI bus-mastering */
         pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
-        /* Should this be &=~ ?? */
-        command&=~PCI_COMMAND_MASTER;
+        command &= ~PCI_COMMAND_MASTER;
         pci_write_config_byte(btv->dev, PCI_COMMAND, command);
 
         /* unmap and free memory */
diff -u --recursive --new-file v2.4.5/linux/drivers/media/video/tuner.c linux/drivers/media/video/tuner.c
--- v2.4.5/linux/drivers/media/video/tuner.c	Mon Feb 19 14:43:36 2001
+++ linux/drivers/media/video/tuner.c	Tue Jun 12 11:06:54 2001
@@ -558,6 +558,7 @@
 #endif
 	default:
 		/* nothing */
+		break;
 	}
 	
 	return 0;
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/Config.in linux/drivers/mtd/Config.in
--- v2.4.5/linux/drivers/mtd/Config.in	Mon Dec 11 14:57:58 2000
+++ linux/drivers/mtd/Config.in	Tue Jun 12 10:30:27 2001
@@ -1,5 +1,5 @@
 
-# $Id: No. :) $
+# $Id: Config.in,v 1.66 2001/05/07 21:00:43 dwmw2 Exp $
 
 mainmenu_option next_comment
 comment 'Memory Technology Devices (MTD)'
@@ -11,72 +11,29 @@
    if [ "$CONFIG_MTD_DEBUG" = "y" ]; then
       int '  Debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_MTD_DEBUG_VERBOSE 0
    fi
-
-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' CONFIG_MTD_DOC2001 $CONFIG_MTD
-   if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" ]; then
-      define_tristate CONFIG_MTD_DOCPROBE y
-   else
-      if [ "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" ]; then
-	 define_tristate CONFIG_MTD_DOCPROBE m
-      else
-	 define_tristate CONFIG_MTD_DOCPROBE n
-      fi
-   fi
-   if [ "$CONFIG_MTD_DOCPROBE" = "y" -o "$CONFIG_MTD_DOCPROBE" = "m" ]; then
-      hex  '    Physical address of DiskOnChip' CONFIG_MTD_DOCPROBE_ADDRESS 0x0000
-      bool '    Probe high addresses' CONFIG_MTD_DOCPROBE_HIGH
-      bool '    Probe for 0x55 0xAA BIOS Extension Signature' CONFIG_MTD_DOCPROBE_55AA
-   fi
-
-comment 'RAM/ROM Device Drivers'
-   dep_tristate '  Use extra onboard system memory as MTD device' CONFIG_MTD_SLRAM $CONFIG_MTD
-   dep_tristate '  Ramix PMC551 PCI Mezzanine ram card support' CONFIG_MTD_PMC551 $CONFIG_MTD $CONFIG_PCI
-   if [ "$CONFIG_MTD_PMC551" != "n" ]; then
-      bool '    PMC551 256M DRAM Bugfix' CONFIG_MTD_PMC551_BUGFIX
-      bool '    PMC551 Debugging' CONFIG_MTD_PMC551_DEBUG
-   fi
-   dep_tristate '  Debugging RAM test driver' CONFIG_MTD_MTDRAM $CONFIG_MTD
-   if [ "$CONFIG_MTD_MTDRAM" != "n" ]; then
-      int 'Device size in kB' CONFIG_MTDRAM_TOTAL_SIZE 4096
-      int 'Size of the erase sectors in kB' CONFIG_MTDRAM_ERASE_SIZE 128
-   fi
-
-comment 'Linearly Mapped Flash Device Drivers'
-   dep_tristate '  Common Flash Interface (CFI) support' CONFIG_MTD_CFI $CONFIG_MTD
-   dep_tristate '    CFI support for Intel/Sharp Extended Command Set chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_CFI
-   dep_tristate '    CFI support for AMD/Fujitsu Standard Command Set chips' CONFIG_MTD_CFI_AMDSTD $CONFIG_MTD_CFI
-   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
-
-# These will later become config-options
-define_bool CONFIG_MTD_JEDEC n
-
-   dep_tristate '  Flash chip mapping in physical memory' CONFIG_MTD_PHYSMAP $CONFIG_MTD_CFI
-   if [ "$CONFIG_MTD_PHYSMAP" = "y" -o "$CONFIG_MTD_PHYSMAP" = "m" ]; then
-      hex '    Physical start location of flash chip mapping' CONFIG_MTD_PHYSMAP_START 0x8000000
-      hex '    Physical length of flash chip mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000
-      int '    Bus width in octets' CONFIG_MTD_PHYSMAP_BUSWIDTH 2
+   dep_tristate '  MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD
+   dep_tristate '  RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS
+   dep_tristate '  Compaq bootldr partition table parsing' CONFIG_MTD_BOOTLDR_PARTS $CONFIG_MTD_PARTITIONS
+
+comment 'User Modules And Translation Layers'
+   dep_tristate '  Direct char device access to MTD devices' CONFIG_MTD_CHAR $CONFIG_MTD
+   dep_tristate '  Caching block device access to MTD devices' CONFIG_MTD_BLOCK $CONFIG_MTD
+   if [ "$CONFIG_MTD_BLOCK" = "n" -o "$CONFIG_MTD_BLOCK" = "m" ]; then
+   	dep_tristate '  Readonly block device access to MTD devices' CONFIG_MTD_BLOCK_RO $CONFIG_MTD
    fi
-
-comment 'Drivers for chip mappings'
-   dep_tristate '  Flash chip mapping on Mixcom piggyback card' CONFIG_MTD_MIXMEM $CONFIG_MTD_JEDEC
-   dep_tristate '  Flash chip mapping on Nora' CONFIG_MTD_NORA $CONFIG_MTD_CFI
-   dep_tristate '  Flash chip mapping on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC
-   dep_tristate '  Flash chip mapping on Photron PNC-2000' CONFIG_MTD_PNC2000 $CONFIG_MTD_CFI
-   dep_tristate '  Flash chip mapping on RPXLite PPC board' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI
-   dep_tristate '  Flash chip mapping on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC
-
-comment 'User modules and translation layers for MTD devices'
-   dep_tristate '  Direct chardevice access to MTD devices' CONFIG_MTD_CHAR $CONFIG_MTD
-   dep_tristate '  Caching blockdevice access to MTD devices' CONFIG_MTD_BLOCK $CONFIG_MTD
    dep_tristate '  FTL (Flash Translation Layer) support' CONFIG_FTL $CONFIG_MTD
    dep_tristate '  NFTL (NAND Flash Translation Layer) support' CONFIG_NFTL $CONFIG_MTD
    if [ "$CONFIG_NFTL" = "y" -o "$CONFIG_NFTL" = "m" ]; then
       bool '    Write support for NFTL (BETA)' CONFIG_NFTL_RW
    fi
 fi
+
+source drivers/mtd/chips/Config.in
+
+source drivers/mtd/maps/Config.in
+
+source drivers/mtd/devices/Config.in
+
+source drivers/mtd/nand/Config.in
 
 endmenu
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/Makefile linux/drivers/mtd/Makefile
--- v2.4.5/linux/drivers/mtd/Makefile	Fri Dec 29 14:07:22 2000
+++ linux/drivers/mtd/Makefile	Tue Jun 12 10:30:27 2001
@@ -8,54 +8,57 @@
 # Note 2! The CFLAGS definitions are now inherited from the
 # parent makes..
 #
-# $Id: Makefile,v 1.22 2000/07/14 08:10:52 dwmw2 Exp $
+# $Id: Makefile,v 1.60 2001/05/31 20:43:18 dwmw2 Exp $
 
-# Object file lists.
 
-obj-y           :=
+obj-y           += chips/chipslink.o maps/mapslink.o \
+			devices/devlink.o nand/nandlink.o
 obj-m           :=
 obj-n           :=
 obj-            :=
 
 O_TARGET	:= mtdlink.o
-SUB_DIRS	:=
-ALL_SUB_DIRS 	:=
-MOD_SUB_DIRS	:=
 
-export-objs	:=	mtdcore.o mtdpart.o jedec.o
-list-multi	:=
+export-objs	:= mtdcore.o mtdpart.o redboot.o bootldr.o
+list-multi	:= nftl.o
 
-# MTD devices
+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.
+# 
+# dwmw2 21/11/0
+
+# Core functionality.
 obj-$(CONFIG_MTD)		+= mtdcore.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_SLRAM)		+= slram.o
-obj-$(CONFIG_MTD_PMC551)	+= pmc551.o
-obj-$(CONFIG_MTD_MTDRAM)	+= mtdram.o
-
-# Chip drivers
-obj-$(CONFIG_MTD_JEDEC)		+= jedec.o
-obj-$(CONFIG_MTD_RAM)		+= map_ram.o
-obj-$(CONFIG_MTD_ROM)		+= map_rom.o
-obj-$(CONFIG_MTD_CFI)		+= cfi_probe.o
-obj-$(CONFIG_MTD_CFI_INTELEXT)	+= cfi_cmdset_0001.o
-obj-$(CONFIG_MTD_CFI_AMDSTD)	+= cfi_cmdset_0002.o
-
-# Chip mappings
-obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o
-obj-$(CONFIG_MTD_MIXMEM)	+= mixmem.o
-obj-$(CONFIG_MTD_NORA)		+= nora.o
-obj-$(CONFIG_MTD_OCTAGON)	+= octagon-5066.o
-obj-$(CONFIG_MTD_PNC2000)	+= pnc2000.o mtdpart.o
-obj-$(CONFIG_MTD_RPXLITE)	+= rpxlite.o
-obj-$(CONFIG_MTD_VMAX)		+= vmax301.o
+obj-$(CONFIG_MTD_PARTITIONS)	+= mtdpart.o
+obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
+obj-$(CONFIG_MTD_BOOTLDR_PARTS) += bootldr.o
 
-# Users
+# '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 nftlmount.o
+obj-$(CONFIG_NFTL)		+= nftl.o
+
+nftl-objs	:= nftlcore.o nftlmount.o
 
 include $(TOPDIR)/Rules.make
+
+nftl.o: $(nftl-objs)
+	$(LD) -r -o $@ $(nftl-objs)
+
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/bootldr.c linux/drivers/mtd/bootldr.c
--- v2.4.5/linux/drivers/mtd/bootldr.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/bootldr.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,149 @@
+/*
+ * Read flash partition table from Compaq Bootloader
+ *
+ * Copyright 2001 Compaq Computer Corporation.
+ *
+ * $Id: bootldr.c,v 1.4 2001/06/02 18:24:27 nico Exp $
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ */
+
+/*
+ * Maintainer: Jamey Hicks (jamey.hicks@compaq.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#define FLASH_PARTITION_NAMELEN 32
+enum LFR_FLAGS {
+   LFR_SIZE_PREFIX = 1,		/* prefix data with 4-byte size */
+   LFR_PATCH_BOOTLDR = 2,	/* patch bootloader's 0th instruction */
+   LFR_KERNEL = 4,		/* add BOOTIMG_MAGIC, imgsize and VKERNEL_BASE to head of programmed region (see bootldr.c) */
+   LFR_EXPAND = 8               /* expand partition size to fit rest of flash */
+};
+
+typedef struct FlashRegion {
+   char name[FLASH_PARTITION_NAMELEN];
+   unsigned long base;
+   unsigned long size;
+   enum LFR_FLAGS flags;
+} FlashRegion;
+
+typedef struct BootldrFlashPartitionTable {
+  int magic; /* should be filled with 0x646c7470 (btlp) BOOTLDR_PARTITION_MAGIC */
+  int npartitions;
+  struct FlashRegion partition[0];
+} BootldrFlashPartitionTable;
+
+#define BOOTLDR_MAGIC      0x646c7462        /* btld: marks a valid bootldr image */
+#define BOOTLDR_PARTITION_MAGIC  0x646c7470  /* btlp: marks a valid bootldr partition table in params sector */
+
+#define BOOTLDR_MAGIC_OFFSET 0x20 /* offset 0x20 into the bootldr */
+#define BOOTCAP_OFFSET 0X30 /* offset 0x30 into the bootldr */
+
+#define BOOTCAP_WAKEUP	(1<<0)
+#define BOOTCAP_PARTITIONS (1<<1) /* partition table stored in params sector */
+#define BOOTCAP_PARAMS_AFTER_BOOTLDR (1<<2) /* params sector right after bootldr sector(s), else in last sector */
+
+int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts)
+{
+	struct mtd_partition *parts;
+	int ret, retlen, i;
+	int npartitions = 0;
+	long partition_table_offset;
+	long bootmagic = 0;
+	long bootcap = 0;
+	int namelen = 0;
+	struct BootldrFlashPartitionTable *partition_table = NULL; 
+	char *names; 
+
+	/* verify bootldr magic */
+	ret = master->read(master, BOOTLDR_MAGIC_OFFSET, sizeof(long), &retlen, (void *)&bootmagic);
+	if (ret) 
+		goto out;
+        if (bootmagic != BOOTLDR_MAGIC)
+                goto out;
+	/* see if bootldr supports partition tables and where to find the partition table */
+	ret = master->read(master, BOOTCAP_OFFSET, sizeof(long), &retlen, (void *)&bootcap);
+	if (ret) 
+		goto out;
+
+	if (!(bootcap & BOOTCAP_PARTITIONS))
+		goto out;
+	if (bootcap & BOOTCAP_PARAMS_AFTER_BOOTLDR)
+		partition_table_offset = master->erasesize;
+	else
+		partition_table_offset = master->size - master->erasesize;
+
+	printk(__FUNCTION__ ": partition_table_offset=%#lx\n", partition_table_offset);
+
+	/* Read the partition table */
+	partition_table = (struct BootldrFlashPartitionTable *)kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!partition_table)
+		return -ENOMEM;
+	ret = master->read(master, partition_table_offset,
+			   PAGE_SIZE, &retlen, (void *)partition_table);
+	if (ret)
+		goto out;
+
+	printk(__FUNCTION__ ": magic=%#x\n", partition_table->magic);
+
+	/* check for partition table magic number */
+	if (partition_table->magic != BOOTLDR_PARTITION_MAGIC) 
+		goto out;
+	npartitions = partition_table->npartitions;
+
+	printk(__FUNCTION__ ": npartitions=%#x\n", npartitions);
+
+	for (i = 0; i < npartitions; i++) {
+		namelen += strlen(partition_table->partition[i].name) + 1;
+	}
+
+	parts = kmalloc(sizeof(*parts)*npartitions + namelen, GFP_KERNEL);
+	if (!parts) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	names = (char *)&parts[npartitions];
+	memset(parts, 0, sizeof(*parts)*npartitions + namelen);
+
+	for (i = 0; i < npartitions; i++) {
+                struct FlashRegion *partition = &partition_table->partition[i];
+		const char *name = partition->name;
+		parts[i].name = names;
+		names += strlen(name) + 1;
+		strcpy(parts[i].name, name);
+
+                if (partition->flags & LFR_EXPAND)
+                        parts[i].size = MTDPART_SIZ_FULL;
+                else
+                        parts[i].size = partition->size;
+		parts[i].offset = partition->base;
+		parts[i].mask_flags = 0;
+		
+		printk("        partition %s o=%x s=%x\n", 
+		       parts[i].name, parts[i].offset, parts[i].size);
+
+	}
+
+	ret = npartitions;
+	*pparts = parts;
+
+ out:
+	if (partition_table)
+		kfree(partition_table);
+	return ret;
+}
+
+EXPORT_SYMBOL(parse_bootldr_partitions);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/cfi_cmdset_0001.c linux/drivers/mtd/cfi_cmdset_0001.c
--- v2.4.5/linux/drivers/mtd/cfi_cmdset_0001.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/cfi_cmdset_0001.c	Wed Dec 31 16:00:00 1969
@@ -1,891 +0,0 @@
-/*
- * Common Flash Interface support:
- *   Intel Extended Vendor Command Set (ID 0x0001)
- *
- * (C) 2000 Red Hat. GPL'd
- *
- * $Id: cfi_cmdset_0001.c,v 1.21 2000/07/13 10:36:14 dwmw2 Exp $
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <asm/io.h>
-#include <asm/byteorder.h>
-
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/cfi.h>
-
-#if LINUX_VERSION_CODE < 0x20300
-#define set_current_state(x) current->state = (x);
-#endif
-static int cfi_intelext_read_1_by_16 (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-static int cfi_intelext_write_1_by_16(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
-static int cfi_intelext_erase_1_by_16 (struct mtd_info *, struct erase_info *);
-static void cfi_intelext_sync (struct mtd_info *);
-static int cfi_intelext_suspend (struct mtd_info *);
-static void cfi_intelext_resume (struct mtd_info *);
-
-static void cfi_intelext_destroy(struct mtd_info *);
-
-static void cfi_cmdset_0001(struct map_info *, int, unsigned long);
-
-static struct mtd_info *cfi_intelext_setup (struct map_info *);
-
-static const char im_name[] = "cfi_cmdset_0001";
-
-/* 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 cfi are valid as long as the use count of
- * this module is non-zero, i.e. between inter_module_get and
- * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
- */
-static void cfi_cmdset_0001(struct map_info *map, int primary, unsigned long base)
-{
-	struct cfi_private *cfi = map->fldrv_priv;
-	int i;
-	struct cfi_pri_intelext *extp;
-
-	__u16 adr = primary?cfi->cfiq.P_ADR:cfi->cfiq.A_ADR;
-
-	printk(" Intel/Sharp Extended Query Table at 0x%4.4X\n", adr);
-
-	if (!adr)
-		return;
-
-	/* Switch it into Query Mode */
-	switch(map->buswidth) {
-	case 1:
-		map->write8(map, 0x98, 0x55);
-		break;
-	case 2:
-		map->write16(map, 0x9898, 0xaa);
-		break;
-	case 4:
-		map->write32(map, 0x98989898, 0x154);
-		break;
-	}
-
-	extp = kmalloc(sizeof(*extp), GFP_KERNEL);
-	if (!extp) {
-		printk("Failed to allocate memory\n");
-		return;
-	}
-
-	/* Read in the Extended Query Table */
-	for (i=0; i<sizeof(*extp); i++) {
-		((unsigned char *)extp)[i] = 
-			map->read8(map, (base+((adr+i)*map->buswidth)));
-	}
-
-	if (extp->MajorVersion != '1' || 
-	    (extp->MinorVersion < '0' || extp->MinorVersion > '2')) {
-		printk("  Unknown IntelExt Extended Query version %c.%c.\n",
-		       extp->MajorVersion, extp->MinorVersion);
-		kfree(extp);
-		return;
-	}
-
-	/* Do some byteswapping if necessary */
-	extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
-	extp->BlkStatusRegMask = le32_to_cpu(extp->BlkStatusRegMask);
-
-	
-	/* Tell the user about it in lots of lovely detail */
-#if 0  
-	printk("  Feature/Command Support: %4.4X\n", extp->FeatureSupport);
-	printk("     - Chip Erase:         %s\n", extp->FeatureSupport&1?"supported":"unsupported");
-	printk("     - Suspend Erase:      %s\n", extp->FeatureSupport&2?"supported":"unsupported");
-	printk("     - Suspend Program:    %s\n", extp->FeatureSupport&4?"supported":"unsupported");
-	printk("     - Legacy Lock/Unlock: %s\n", extp->FeatureSupport&8?"supported":"unsupported");
-	printk("     - Queued Erase:       %s\n", extp->FeatureSupport&16?"supported":"unsupported");
-	printk("     - Instant block lock: %s\n", extp->FeatureSupport&32?"supported":"unsupported");
-	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++) {
-		if (extp->FeatureSupport & (1<<i)) 
-			printk("     - Unknown Bit %X:      supported\n", i);
-	}
-	
-	printk("  Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport);
-	printk("     - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported");
-	for (i=1; i<8; i++) {
-		if (extp->SuspendCmdSupport & (1<<i))
-			printk("     - Unknown Bit %X:               supported\n", i);
-	}
-	
-	printk("  Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask);
-	printk("     - Lock Bit Active:      %s\n", extp->BlkStatusRegMask&1?"yes":"no");
-	printk("     - Valid Bit Active:     %s\n", extp->BlkStatusRegMask&2?"yes":"no");
-	for (i=2; i<16; i++) {
-		if (extp->BlkStatusRegMask & (1<<i))
-			printk("     - Unknown Bit %X Active: yes\n",i);
-	}
-	
-	printk("  Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", 
-	       extp->VccOptimal >> 8, extp->VccOptimal & 0xf);
-	if (extp->VppOptimal)
-		printk("  Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", 
-		       extp->VppOptimal >> 8, extp->VppOptimal & 0xf);
-#endif	
-	/* OK. We like it. Take over the control of it. */
-
-	/* Switch it into Read Mode */
-	switch(map->buswidth) {
-	case 1:
-		map->write8(map, 0xff, 0x55);
-		break;
-	case 2:
-		map->write16(map, 0xffff, 0xaa);
-		break;
-	case 4:
-		map->write32(map, 0xffffffff, 0x154);
-		break;
-	}
-
-
-	/* If there was an old setup function, decrease its use count */
-	if (cfi->cmdset_setup)
-		inter_module_put(cfi->im_name);
-	if (cfi->cmdset_priv)
-		kfree(cfi->cmdset_priv);
-
-	for (i=0; i< cfi->numchips; i++) {
-		cfi->chips[i].word_write_time = 128;
-		cfi->chips[i].buffer_write_time = 128;
-		cfi->chips[i].erase_time = 1024;
-	}		
-		
-
-	cfi->cmdset_setup = cfi_intelext_setup;
-	cfi->im_name = im_name;
-	cfi->cmdset_priv = extp;
-	
-	return;
-}
-
-static struct mtd_info *cfi_intelext_setup(struct map_info *map)
-{
-	struct cfi_private *cfi = map->fldrv_priv;
-	struct mtd_info *mtd;
-
-	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
-	printk("number of CFI chips: %d\n", cfi->numchips);
-
-	if (!mtd) {
-	  printk("Failed to allocate memory for MTD device\n");
-	  kfree(cfi->cmdset_priv);
-	  return NULL;
-	}
-
-	memset(mtd, 0, sizeof(*mtd));
-	mtd->priv = map;
-	mtd->type = MTD_NORFLASH;
-	mtd->erasesize = 0x20000; /* FIXME */
-	/* Also select the correct geometry setup too */ 
-	mtd->size = (1 << cfi->cfiq.DevSize) * cfi->numchips;
-	mtd->erase = cfi_intelext_erase_1_by_16;
-	mtd->read = cfi_intelext_read_1_by_16;
-	mtd->write = cfi_intelext_write_1_by_16;
-	mtd->sync = cfi_intelext_sync;
-	mtd->suspend = cfi_intelext_suspend;
-	mtd->resume = cfi_intelext_resume;
-	mtd->flags = MTD_CAP_NORFLASH;
-	map->fldrv_destroy = cfi_intelext_destroy;
-	mtd->name = map->name;
-	return mtd;
-}
-
-static inline int do_read_1_by_16_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
-{
-	__u16 status;
-	unsigned long timeo = jiffies + HZ;
-	DECLARE_WAITQUEUE(wait, current);
-
-	adr += chip->start;
-
- retry:
-	spin_lock_bh(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 or FL_WRITING state.
-	 * Not just yet, though.
-	 */
-	switch (chip->state) {
-#if 0
-	case FL_ERASING:
-	case FL_WRITING:
-		/* Suspend the operation, set state to FL_xxx_SUSPENDED */
-#endif
-
-	case FL_CFI_QUERY:
-	case FL_JEDEC_QUERY:
-	case FL_READY:
-		map->write16(map, cpu_to_le16(0x0070), adr);
-		chip->state = FL_STATUS;
-
-	case FL_STATUS:
-		status = le16_to_cpu(map->read16(map, adr));
-
-		if (!(status & (1<<7))) {
-			static int z=0;
-			/* Urgh. Chip not yet ready to talk to us. */
-			if (time_after(jiffies, timeo)) {
-				spin_unlock_bh(chip->mutex);
-				printk("waiting for chip to be ready timed out in read");
-				return -EIO;
-			}
-
-			/* Latency issues. Drop the lock, wait a while and retry */
-			spin_unlock_bh(chip->mutex);
-
-			z++;
-			if ( 0 && !(z % 100 )) 
-				printk("chip not ready yet before read. looping\n");
-
-			udelay(1);
-
-			goto retry;
-		}
-		break;
-
-	default:
-		printk("Waiting for chip, status = %d\n", chip->state);
-
-		/* Stick ourselves on a wait queue to be woken when
-		   someone changes the status */
-
-		set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-		
-		spin_unlock_bh(chip->mutex);
-
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-
-		if(signal_pending(current))
-			return -EINTR;
-
-
-		timeo = jiffies + HZ;
-
-		goto retry;
-	}
-
-	map->write16(map, cpu_to_le16(0x00ff), adr);
-	chip->state = FL_READY;
-
-	map->copy_from(map, buf, adr, len);
-
-	if (chip->state == FL_ERASE_SUSPENDED || 
-	    chip->state == FL_WRITE_SUSPENDED) {
-		printk("Who in hell suspended the pending operation? I didn't write that code yet!\n");
-		/* Restart it and set the state accordingly */
-	}
-
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-
-	return 0;
-}
-
-static int cfi_intelext_read_1_by_16 (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;
-	unsigned long ofs;
-	int chipnum;
-	int ret = 0;
-
-	/* ofs: offset within the first chip that the first read should start */
-	chipnum = (from >> cfi->chipshift);
-	ofs = from - (chipnum <<  cfi->chipshift);
-
-	*retlen = 0;
-
-	while (len) {
-		unsigned long thislen;
-
-		if (chipnum >= cfi->numchips)
-			break;
-
-		if ((len + ofs -1) >> cfi->chipshift)
-			thislen = (1<<cfi->chipshift) - ofs;
-		else
-			thislen = len;
-
-		ret = do_read_1_by_16_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
-		if (ret)
-			break;
-
-		*retlen += thislen;
-		len -= thislen;
-		buf += thislen;
-		
-		ofs = 0;
-		chipnum++;
-	}
-	return ret;
-}
-
-static inline int do_write_1_by_16_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u16 datum)
-{
-	__u16 status;
-	unsigned long timeo = jiffies + HZ;
-	DECLARE_WAITQUEUE(wait, current);
-	int z = 0;
-	adr += chip->start;
-
- retry:
-	spin_lock_bh(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_CFI_QUERY:
-	case FL_JEDEC_QUERY:
-	case FL_READY:
-		map->write16(map, cpu_to_le16(0x0070), adr);
-		chip->state = FL_STATUS;
-		timeo = jiffies + HZ;
-
-	case FL_STATUS:
-		status = le16_to_cpu(map->read16(map, adr));
-
-		if (!(status & (1<<7))) {
-
-			/* Urgh. Chip not yet ready to talk to us. */
-			if (time_after(jiffies, timeo)) {
-				spin_unlock_bh(chip->mutex);
-				printk("waiting for chip to be ready timed out in read");
-				return -EIO;
-			}
-
-			/* Latency issues. Drop the lock, wait a while and retry */
-			spin_unlock_bh(chip->mutex);
-
-			z++;
-			if ( 0 && !(z % 100 ))
-				printk("chip not ready yet before write. looping\n");
-			
-			udelay(1);
-
-			goto retry;
-		}
-		break;
-
-	default:
-		printk("Waiting for chip, status = %d\n", chip->state);
-
-		/* Stick ourselves on a wait queue to be woken when
-		   someone changes the status */
-
-		set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-		
-		spin_unlock_bh(chip->mutex);
-
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-
-		if(signal_pending(current))
-			return -EINTR;
-
-		timeo = jiffies + HZ;
-
-		goto retry;
-	}
-	
-	map->write16(map, cpu_to_le16(0x0040), adr);
-	map->write16(map, datum, adr);
-	chip->state = FL_WRITING;
-
-	timeo = jiffies + (HZ/2);
-
-	spin_unlock_bh(chip->mutex);
-	udelay(chip->word_write_time);
-	spin_lock_bh(chip->mutex);
-
-	z = 0;
-	while ( !( (status = le16_to_cpu(map->read16(map, adr)))  & 0x80 ) ) {
-
-		if (chip->state != FL_WRITING) {
-			/* Someone's suspended the write. Sleep */
-			set_current_state(TASK_INTERRUPTIBLE);
-			add_wait_queue(&chip->wq, &wait);
-			
-			spin_unlock_bh(chip->mutex);
-			
-			schedule();
-			remove_wait_queue(&chip->wq, &wait);
-			
-			if (signal_pending(current))
-				return -EINTR;
-			
-			timeo = jiffies + (HZ / 2); /* FIXME */
-
-			spin_lock_bh(chip->mutex);
-			continue;
-		}
-
-		/* OK Still waiting */
-		if (time_after(jiffies, timeo)) {
-			chip->state = FL_STATUS;
-			spin_unlock_bh(chip->mutex);
-			printk("waiting for chip to be ready timed out in read");
-			return -EIO;
-		}
-		
-		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-		
-		z++;
-		if ( 0 && !(z % 100 )) 
-		  printk("chip not ready yet after write. looping\n");
-		
-		udelay(1);
-		
-		spin_lock_bh(chip->mutex);
-		continue;
-	}
-	if (!z) {
-		chip->word_write_time--;
-		if (!chip->word_write_time)
-			chip->word_write_time++;
-	}
-	if (z > 1) 
-		chip->word_write_time++;
-
-	/* Done and happy. */
-	chip->state = FL_STATUS;
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-	//	printk("write ret OK at %lx\n", adr);
-	return 0;
-}
-
-
-/* This version only uses the 'word write' instruction. We should update it
- * to write using 'buffer write' if it's available 
- */
-static int cfi_intelext_write_1_by_16 (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;
-
-	*retlen = 0;
-	chipnum = to >> cfi->chipshift;
-	ofs = to  - (chipnum << cfi->chipshift);
-
-	/* If it's not word-aligned, do the first byte write */
-	if (ofs & 1) {
-#if defined(__LITTLE_ENDIAN)
-		ret = do_write_1_by_16_oneword(map, &cfi->chips[chipnum],
-					       ofs, 0xFF | (*buf << 8));
-#elif defined(__BIG_ENDIAN) 
-		ret = do_write_1_by_16_oneword(map, &cfi->chips[chipnum],
-					       ofs, 0xFF00 | (*buf));
-#else
-#error define a sensible endianness
-#endif
-		if (ret) 
-			return ret;
-		
-		ofs++;
-		buf++;
-		(*retlen)++;
-		len--;
-
-		if (ofs >> cfi->chipshift) {
-			chipnum ++; 
-			ofs = 0;
-			if (chipnum == cfi->numchips)
-				return 0;
-		}
-	}
-	
-	while(len > 1) {
-		ret = do_write_1_by_16_oneword(map, &cfi->chips[chipnum],
-					       ofs, *(__u16 *)buf);
-		if (ret)
-			return ret;
-
-		ofs += 2;
-		buf += 2;
-		(*retlen) += 2;
-		len -= 2;
-
-		if (ofs >> cfi->chipshift) {
-			chipnum ++; 
-			ofs = 0;
-			if (chipnum == cfi->numchips)
-				return 0;
-		}
-	}
-
-	if (len) {
-		/* Final byte to write */
-#if defined(__LITTLE_ENDIAN)
-		ret = do_write_1_by_16_oneword(map, &cfi->chips[chipnum],
-					       ofs, 0xFF00 | (*buf));
-#elif defined(__BIG_ENDIAN) 
-		ret = do_write_1_by_16_oneword(map, &cfi->chips[chipnum],
-					       ofs, 0xFF | (*buf << 8));
-#else
-#error define a sensible endianness
-#endif
-		if (ret) 
-			return ret;
-		
-		(*retlen)++;
-	}
-
-	return 0;
-}
-
-
-static inline int do_erase_1_by_16_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
-{
-	__u16 status;
-	unsigned long timeo = jiffies + HZ;
-	DECLARE_WAITQUEUE(wait, current);
-
-	adr += chip->start;
-
- retry:
-	spin_lock_bh(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:
-		map->write16(map, cpu_to_le16(0x0070), adr);
-		chip->state = FL_STATUS;
-		timeo = jiffies + HZ;
-
-	case FL_STATUS:
-		status = le16_to_cpu(map->read16(map, adr));
-
-		if (!(status & (1<<7))) {
-			static int z=0;
-			/* Urgh. Chip not yet ready to talk to us. */
-			if (time_after(jiffies, timeo)) {
-				spin_unlock_bh(chip->mutex);
-				printk("waiting for chip to be ready timed out in erase");
-				return -EIO;
-			}
-
-			/* Latency issues. Drop the lock, wait a while and retry */
-			spin_unlock_bh(chip->mutex);
-
-			z++;
-			if ( 0 && !(z % 100 )) 
-				printk("chip not ready yet before erase. looping\n");
-
-			udelay(1);
-
-			goto retry;
-		}
-		break;
-
-	default:
-		printk("Waiting for chip, status = %d\n", chip->state);
-
-		/* Stick ourselves on a wait queue to be woken when
-		   someone changes the status */
-
-		set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-		
-		spin_unlock_bh(chip->mutex);
-
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-
-		if(signal_pending(current))
-			return -EINTR;
-
-		timeo = jiffies + HZ;
-
-		goto retry;
-	}
-	
-	map->write16(map, cpu_to_le16(0x0020), adr);
-	map->write16(map, cpu_to_le16(0x00D0), adr);
-
-	chip->state = FL_ERASING;
-	
-	timeo = jiffies + (HZ*2);
-	spin_unlock_bh(chip->mutex);
-	schedule_timeout(HZ);
-	spin_lock_bh(chip->mutex);
-
-	/* FIXME. Use a timer to check this, and return immediately. */
-	/* Once the state machine's known to be working I'll do that */
-
-	while ( !( (status = le16_to_cpu(map->read16(map, adr)))  & 0x80 ) ) {
-		static int z=0;
-
-		if (chip->state != FL_ERASING) {
-			/* Someone's suspended the erase. Sleep */
-			set_current_state(TASK_INTERRUPTIBLE);
-			add_wait_queue(&chip->wq, &wait);
-			
-			spin_unlock_bh(chip->mutex);
-			printk("erase suspended. Sleeping\n");
-			
-			schedule();
-			remove_wait_queue(&chip->wq, &wait);
-			
-			if (signal_pending(current))
-				return -EINTR;
-			
-			timeo = jiffies + (HZ*2); /* FIXME */
-			spin_lock_bh(chip->mutex);
-			continue;
-		}
-
-		/* OK Still waiting */
-		if (time_after(jiffies, timeo)) {
-			chip->state = FL_STATUS;
-			spin_unlock_bh(chip->mutex);
-			printk("waiting for erase to complete timed out.");
-			return -EIO;
-		}
-		
-		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-
-		z++;
-		if ( 0 && !(z % 100 )) 
-			printk("chip not ready yet after erase. looping\n");
-
-		udelay(1);
-		
-		spin_lock_bh(chip->mutex);
-		continue;
-	}
-	
-	/* Done and happy. */
-	chip->state = FL_STATUS;
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-	//printk("erase ret OK\n");
-	return 0;
-}
-
-static int cfi_intelext_erase_1_by_16 (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;
-
-	chipnum = instr->addr >> cfi->chipshift;
-	adr = instr->addr - (chipnum << cfi->chipshift);
-	len = instr->len;
-
-	while(len) {
-		ret = do_erase_1_by_16_oneblock(map, &cfi->chips[chipnum], adr);
-		
-		if (ret)
-			return ret;
-
-		adr += mtd->erasesize;
-		len -= mtd->erasesize;
-
-		if (adr >> cfi->chipshift) {
-			adr = 0;
-			chipnum++;
-			
-			if (chipnum >= cfi->numchips)
-			break;
-		}
-	}
-		
-	if (instr->callback)
-		instr->callback(instr);
-	
-	return 0;
-}
-
-
-
-static void cfi_intelext_sync (struct mtd_info *mtd)
-{
-	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	int i;
-	struct flchip *chip;
-	int ret = 0;
-	DECLARE_WAITQUEUE(wait, current);
-
-	for (i=0; !ret && i<cfi->numchips; i++) {
-		chip = &cfi->chips[i];
-
-	retry:
-		spin_lock_bh(chip->mutex);
-
-		switch(chip->state) {
-		case FL_READY:
-		case FL_STATUS:
-		case FL_CFI_QUERY:
-		case FL_JEDEC_QUERY:
-			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.
-			 */
-			spin_unlock_bh(chip->mutex);
-			break;
-
-		default:
-			/* Not an idle state */
-			add_wait_queue(&chip->wq, &wait);
-			
-			spin_unlock_bh(chip->mutex);
-			schedule();
-			
-			remove_wait_queue(&chip->wq, &wait);
-
-			goto retry;
-		}
-	}
-
-	/* Unlock the chips again */
-
-	for (i--; i >=0; i--) {
-		chip = &cfi->chips[i];
-
-		spin_lock_bh(chip->mutex);
-		
-		if (chip->state == FL_SYNCING) {
-			chip->state = chip->oldstate;
-			wake_up(&chip->wq);
-		}
-		spin_unlock_bh(chip->mutex);
-	}
-}
-
-
-static int cfi_intelext_suspend(struct mtd_info *mtd)
-{
-	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	int i;
-	struct flchip *chip;
-	int ret = 0;
-
-	for (i=0; !ret && i<cfi->numchips; i++) {
-		chip = &cfi->chips[i];
-
-		spin_lock_bh(chip->mutex);
-
-		switch(chip->state) {
-		case FL_READY:
-		case FL_STATUS:
-		case FL_CFI_QUERY:
-		case FL_JEDEC_QUERY:
-			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.
-			 */
-			break;
-
-		default:
-			ret = -EAGAIN;
-			break;
-		}
-		spin_unlock_bh(chip->mutex);
-	}
-
-	/* Unlock the chips again */
-
-	for (i--; i >=0; i--) {
-		chip = &cfi->chips[i];
-
-		spin_lock_bh(chip->mutex);
-		
-		if (chip->state == FL_PM_SUSPENDED) {
-			chip->state = chip->oldstate;
-			wake_up(&chip->wq);
-		}
-		spin_unlock_bh(chip->mutex);
-	}
-	
-	return ret;
-}
-
-static void cfi_intelext_resume(struct mtd_info *mtd)
-{
-	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	int i;
-	struct flchip *chip;
-
-	for (i=0; i<cfi->numchips; i++) {
-	
-		chip = &cfi->chips[i];
-
-		spin_lock_bh(chip->mutex);
-		
-		if (chip->state == FL_PM_SUSPENDED) {
-			chip->state = chip->oldstate;
-			wake_up(&chip->wq);
-		}
-		else
-			printk("Argh. Chip not in PM_SUSPENDED state upon resume()\n");
-
-		spin_unlock_bh(chip->mutex);
-	}
-}
-
-static void cfi_intelext_destroy(struct mtd_info *mtd)
-{
-	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	kfree(cfi->cmdset_priv);
-	inter_module_put(cfi->im_name);
-	kfree(cfi);
-}
-
-
-static int __init cfi_intelext_init(void)
-{
-	inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0001);
-	return 0;
-}
-
-static void __exit cfi_intelext_exit(void)
-{
-	inter_module_unregister(im_name);
-}
-
-module_init(cfi_intelext_init);
-module_exit(cfi_intelext_exit);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/cfi_cmdset_0002.c linux/drivers/mtd/cfi_cmdset_0002.c
--- v2.4.5/linux/drivers/mtd/cfi_cmdset_0002.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/cfi_cmdset_0002.c	Wed Dec 31 16:00:00 1969
@@ -1,628 +0,0 @@
-/*
- * Common Flash Interface support:
- *   AMD & Fujitsu Extended Vendor Command Set (ID 0x0002)
- *
- * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp>
- *
- * This code is GPL
- *
- * $Id: cfi_cmdset_0002.c,v 1.1 2000/07/11 12:32:09 dwmw2 Exp $
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <asm/io.h>
-#include <asm/byteorder.h>
-
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/cfi.h>
-
-#if LINUX_VERSION_CODE < 0x20300
-#define set_current_state(x) current->state = (x);
-#endif
-
-static int cfi_amdext_read_2_by_16 (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-static int cfi_amdext_write_2_by_16(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
-static int cfi_amdext_erase_2_by_16 (struct mtd_info *, struct erase_info *);
-static void cfi_amdext_sync (struct mtd_info *);
-static int cfi_amdext_suspend (struct mtd_info *);
-static void cfi_amdext_resume (struct mtd_info *);
-
-static void cfi_amdext_destroy(struct mtd_info *);
-
-static void cfi_cmdset_0002(struct map_info *, int, unsigned long);
-
-static struct mtd_info *cfi_amdext_setup (struct map_info *);
-
-static const char im_name[] = "cfi_cmdset_0002";
-
-static void cfi_cmdset_0002(struct map_info *map, int primary, unsigned long base)
-{
-	struct cfi_private *cfi = map->fldrv_priv;
-	int i;
-//	struct cfi_pri_intelext *extp;
-
-	__u16 adr = primary?cfi->cfiq.P_ADR:cfi->cfiq.A_ADR;
-
-	printk(" Amd/Fujitsu Extended Query Table at 0x%4.4X\n", adr);
-
-
-	/* If there was an old setup function, decrease its use count */
-	if (cfi->cmdset_setup)
-		inter_module_put(cfi->im_name);
-	if (cfi->cmdset_priv)
-		kfree(cfi->cmdset_priv);
-
-	for (i=0; i< cfi->numchips; i++) {
-		cfi->chips[i].word_write_time = 128;
-		cfi->chips[i].buffer_write_time = 128;
-		cfi->chips[i].erase_time = 1024;
-	}		
-		
-
-	cfi->cmdset_setup = cfi_amdext_setup;
-	cfi->im_name = im_name;
-//	cfi->cmdset_priv = extp;
-	
-	return;
-}
-
-static struct mtd_info *cfi_amdext_setup(struct map_info *map)
-{
-	struct cfi_private *cfi = map->fldrv_priv;
-	struct mtd_info *mtd;
-
-	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
-	printk("number of CFI chips: %d\n", cfi->numchips);
-
-	if (!mtd) {
-	  printk("Failed to allocate memory for MTD device\n");
-	  kfree(cfi->cmdset_priv);
-	  return NULL;
-	}
-
-	memset(mtd, 0, sizeof(*mtd));
-	mtd->priv = map;
-	mtd->type = MTD_NORFLASH;
-	mtd->erasesize = 0x20000; /* FIXME */
-	/* Also select the correct geometry setup too */ 
-	mtd->size = (1 << cfi->cfiq.DevSize) * cfi->numchips * cfi->interleave;
-	mtd->erase = cfi_amdext_erase_2_by_16;
-	mtd->read = cfi_amdext_read_2_by_16;
-	mtd->write = cfi_amdext_write_2_by_16;
-	mtd->sync = cfi_amdext_sync;
-	mtd->suspend = cfi_amdext_suspend;
-	mtd->resume = cfi_amdext_resume;
-	mtd->flags = MTD_CAP_NORFLASH;
-	map->fldrv_destroy = cfi_amdext_destroy;
-	mtd->name = map->name;
-	return mtd;
-}
-
-static inline int do_read_2_by_16_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long timeo = jiffies + HZ;
-
- retry:
-	spin_lock_bh(chip->mutex);
-
-	if (chip->state != FL_READY){
-printk("Waiting for chip to read, status = %d\n", chip->state);
-		set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-                
-		spin_unlock_bh(chip->mutex);
-
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-
-		if(signal_pending(current))
-			return -EINTR;
-
-		timeo = jiffies + HZ;
-
-		goto retry;
-	}	
-
-	adr += chip->start;
-
-//     	map->write32(map, cpu_to_le32(0x00F000F0), adr);
-
-	chip->state = FL_READY;
-
-	map->copy_from(map, buf, adr, len);
-
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-
-	return 0;
-}
-
-static int cfi_amdext_read_2_by_16 (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;
-	unsigned long ofs;
-	int chipnum;
-	int ret = 0;
-
-	/* ofs: offset within the first chip that the first read should start */
-
-	chipnum = (from >> cfi->chipshift);
-	chipnum /= (cfi->interleave);
-	ofs = from - (chipnum <<  cfi->chipshift) * (cfi->interleave);
-
-	*retlen = 0;
-
-	while (len) {
-		unsigned long thislen;
-
-		if (chipnum >= cfi->numchips)
-			break;
-
-		if (((len + ofs -1) >> cfi->chipshift) / (cfi->interleave))
-			thislen = (1<<cfi->chipshift) * (cfi->interleave) - ofs;
-		else
-			thislen = len;
-
-		ret = do_read_2_by_16_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
-		if (ret)
-			break;
-
-		*retlen += thislen;
-		len -= thislen;
-		buf += thislen;
-
-		ofs = 0;
-		chipnum++;
-	}
-	return ret;
-}
-
-static inline int do_write_2_by_16_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum)
-{
-	unsigned long timeo = jiffies + HZ;
-	unsigned int Last[4];
-	unsigned long Count = 0;
-	DECLARE_WAITQUEUE(wait, current);
-	int ret = 0;
-
- retry:
-	spin_lock_bh(chip->mutex);
-
-	if (chip->state != FL_READY){
-printk("Waiting for chip to write, status = %d\n", chip->state);
-		set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-                
-		spin_unlock_bh(chip->mutex);
-
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-printk("Wake up to write:\n");
-		if(signal_pending(current))
-			return -EINTR;
-
-		timeo = jiffies + HZ;
-
-		goto retry;
-	}	
-
-	chip->state = FL_WRITING;
-
-	adr += chip->start;
-
-	map->write32(map, cpu_to_le32(0x00AA00AA), 0x555 *4);
-	map->write32(map, cpu_to_le32(0x00550055), 0x2AA *4);
-	map->write32(map, cpu_to_le32(0x00A000A0), 0x555 *4);
-	map->write32(map, cpu_to_le32(datum), adr);
-
-	spin_unlock_bh(chip->mutex);
-	udelay(chip->word_write_time);
-	spin_lock_bh(chip->mutex);
-
-	Last[0] = map->read32(map, adr);
-	Last[1] = map->read32(map, adr);
-	Last[2] = map->read32(map, adr);
-
-	for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && Count < 10000; Count++){
-		udelay(10);
-
-		Last[Count % 4] = map->read32(map, adr);
-	}
-
-	if (Last[(Count - 1) % 4] != datum){
-	     	map->write32(map, cpu_to_le32(0x00F000F0), adr);
-		ret = -EIO;
-	}       
-
-	chip->state = FL_READY;
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-
-	return ret;
-}
-
-
-static int cfi_amdext_write_2_by_16 (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;
-
-	*retlen = 0;
-
-	chipnum = (to >> cfi->chipshift);
-	chipnum /= cfi->interleave;
-	ofs = to  - (chipnum << cfi->chipshift) * cfi->interleave;
-
-	while(len > 3) {
-
-		ret = do_write_2_by_16_oneword(map, &cfi->chips[chipnum],
-					       ofs, *(__u32 *)buf);
-		if (ret)
-			return ret;
-
-		ofs += 4;
-		buf += 4;
-		(*retlen) += 4;
-		len -= 4;
-
-		if ((ofs >> cfi->chipshift) / cfi->interleave) {
-			chipnum ++; 
-			ofs = 0;
-			if (chipnum == cfi->numchips)
-				return 0;
-		}
-	}
-
-	if (len) {
-		unsigned int tmp;
-
-		/* Final byte to write */
-#if defined(__LITTLE_ENDIAN)
-		tmp = map->read32(map, ofs);
-
-		tmp = 0xffffffff >> (len*8);
-		tmp = tmp << (len*8);
-
-		tmp |= *(__u32 *)(buf);
-
-		ret = do_write_2_by_16_oneword(map, &cfi->chips[chipnum],
-					       ofs, tmp);
-
-#elif defined(__BIG_ENDIAN) 
-#error not support big endian yet
-#else
-#error define a sensible endianness
-#endif
-
-		if (ret) 
-			return ret;
-		
-		(*retlen)+=len;
-	}
-
-	return 0;
-}
-
-
-static inline int do_erase_2_by_16_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
-{
-	unsigned int status;
-	unsigned long timeo = jiffies + HZ;
-	DECLARE_WAITQUEUE(wait, current);
-
- retry:
-	spin_lock_bh(chip->mutex);
-
-	if (chip->state != FL_READY){
-		set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-                
-		spin_unlock_bh(chip->mutex);
-
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-
-		if(signal_pending(current))
-			return -EINTR;
-
-		timeo = jiffies + HZ;
-
-		goto retry;
-	}	
-
-	chip->state = FL_ERASING;
-
-	adr += chip->start;
-
-	map->write32(map, cpu_to_le32(0x00AA00AA), 0x555 *4);
-	map->write32(map, cpu_to_le32(0x00550055), 0x2AA *4);
-	map->write32(map, cpu_to_le32(0x00800080), 0x555 *4);
-	map->write32(map, cpu_to_le32(0x00AA00AA), 0x555 *4);
-	map->write32(map, cpu_to_le32(0x00550055), 0x2AA *4);
-	map->write32(map, cpu_to_le32(0x00300030), adr);
-
-	
-	timeo = jiffies + (HZ*20);
-
-	spin_unlock_bh(chip->mutex);
-	schedule_timeout(HZ);
-	spin_lock_bh(chip->mutex);
-
-	/* FIXME. Use a timer to check this, and return immediately. */
-	/* Once the state machine's known to be working I'll do that */
-
-	while ( ( (status = le32_to_cpu(map->read32(map, 0x00))) & 0x80808080 ) != 0x80808080 ) {
-		static int z=0;
-
-		if (chip->state != FL_ERASING) {
-			/* Someone's suspended the erase. Sleep */
-			set_current_state(TASK_INTERRUPTIBLE);
-			add_wait_queue(&chip->wq, &wait);
-			
-			spin_unlock_bh(chip->mutex);
-			printk("erase suspended. Sleeping\n");
-			
-			schedule();
-			remove_wait_queue(&chip->wq, &wait);
-			
-			if (signal_pending(current))
-				return -EINTR;
-			
-			timeo = jiffies + (HZ*2); /* FIXME */
-			spin_lock_bh(chip->mutex);
-			continue;
-		}
-
-		/* OK Still waiting */
-		if (time_after(jiffies, timeo)) {
-			chip->state = FL_READY;
-			spin_unlock_bh(chip->mutex);
-			printk("waiting for erase to complete timed out.");
-			return -EIO;
-		}
-		
-		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-
-		z++;
-		if ( 0 && !(z % 100 )) 
-			printk("chip not ready yet after erase. looping\n");
-
-		udelay(1);
-		
-		spin_lock_bh(chip->mutex);
-		continue;
-	}
-	
-	/* Done and happy. */
-	chip->state = FL_READY;
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-	printk("erase ret OK\n");
-	return 0;
-}
-
-static int cfi_amdext_erase_2_by_16 (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;
-
-//printk("erase : 0x%x 0x%x 0x%x\n", instr->addr, instr->len, mtd->size);
-
-	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;
-
-	chipnum = instr->addr >> cfi->chipshift;
-	chipnum /= cfi->interleave;
-	adr = instr->addr - (chipnum << cfi->chipshift) * (cfi->interleave);
-	len = instr->len;
-
-	printk("erase : 0x%lx 0x%lx 0x%x 0x%lx\n", adr, len, chipnum, mtd->size);
-
-	while(len) {
-//printk("erase : 0x%x 0x%x 0x%x 0x%x\n", chipnum, adr, len, cfi->chipshift);
-		ret = do_erase_2_by_16_oneblock(map, &cfi->chips[chipnum], adr);
-
-		if (ret)
-			return ret;
-
-		adr += mtd->erasesize;
-		len -= mtd->erasesize;
-
-		if ((adr >> cfi->chipshift) / (cfi->interleave)) {
-			adr = 0;
-			chipnum++;
-			
-			if (chipnum >= cfi->numchips)
-			break;
-		}
-	}
-		
-	if (instr->callback)
-		instr->callback(instr);
-	
-	return 0;
-}
-
-
-
-static void cfi_amdext_sync (struct mtd_info *mtd)
-{
-	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	int i;
-	struct flchip *chip;
-	int ret = 0;
-	DECLARE_WAITQUEUE(wait, current);
-printk("sync\n");
-
-	for (i=0; !ret && i<cfi->numchips; i++) {
-		chip = &cfi->chips[i];
-
-	retry:
-		spin_lock_bh(chip->mutex);
-
-		switch(chip->state) {
-		case FL_READY:
-		case FL_STATUS:
-		case FL_CFI_QUERY:
-		case FL_JEDEC_QUERY:
-			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.
-			 */
-			spin_unlock_bh(chip->mutex);
-			break;
-
-		default:
-			/* Not an idle state */
-			add_wait_queue(&chip->wq, &wait);
-			
-			spin_unlock_bh(chip->mutex);
-
-			schedule();
-			
-			remove_wait_queue(&chip->wq, &wait);
-
-			goto retry;
-		}
-	}
-
-	/* Unlock the chips again */
-
-	for (i--; i >=0; i--) {
-		chip = &cfi->chips[i];
-
-		spin_lock_bh(chip->mutex);
-		
-		if (chip->state == FL_SYNCING) {
-			chip->state = chip->oldstate;
-			wake_up(&chip->wq);
-		}
-		spin_unlock_bh(chip->mutex);
-	}
-printk("sync end\n");
-}
-
-
-static int cfi_amdext_suspend(struct mtd_info *mtd)
-{
-	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	int i;
-	struct flchip *chip;
-	int ret = 0;
-//printk("suspend\n");
-
-	for (i=0; !ret && i<cfi->numchips; i++) {
-		chip = &cfi->chips[i];
-
-		spin_lock_bh(chip->mutex);
-
-		switch(chip->state) {
-		case FL_READY:
-		case FL_STATUS:
-		case FL_CFI_QUERY:
-		case FL_JEDEC_QUERY:
-			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.
-			 */
-			break;
-
-		default:
-			ret = -EAGAIN;
-			break;
-		}
-		spin_unlock_bh(chip->mutex);
-	}
-
-	/* Unlock the chips again */
-
-	for (i--; i >=0; i--) {
-		chip = &cfi->chips[i];
-
-		spin_lock_bh(chip->mutex);
-		
-		if (chip->state == FL_PM_SUSPENDED) {
-			chip->state = chip->oldstate;
-			wake_up(&chip->wq);
-		}
-		spin_unlock_bh(chip->mutex);
-	}
-	
-	return ret;
-}
-
-static void cfi_amdext_resume(struct mtd_info *mtd)
-{
-	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	int i;
-	struct flchip *chip;
-//printk("resume\n");
-
-	for (i=0; i<cfi->numchips; i++) {
-	
-		chip = &cfi->chips[i];
-
-		spin_lock_bh(chip->mutex);
-		
-		if (chip->state == FL_PM_SUSPENDED) {
-			chip->state = chip->oldstate;
-			wake_up(&chip->wq);
-		}
-		else
-			printk("Argh. Chip not in PM_SUSPENDED state upon resume()\n");
-
-		spin_unlock_bh(chip->mutex);
-	}
-}
-
-static void cfi_amdext_destroy(struct mtd_info *mtd)
-{
-	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	kfree(cfi->cmdset_priv);
-	inter_module_put(cfi->im_name);
-	kfree(cfi);
-}
-
-
-static int __init cfi_amdext_init(void)
-{
-	inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0002);
-	return 0;
-}
-
-static void __exit cfi_amdext_exit(void)
-{
-	inter_module_unregister(im_name);
-}
-
-module_init(cfi_amdext_init);
-module_exit(cfi_amdext_exit);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/cfi_probe.c linux/drivers/mtd/cfi_probe.c
--- v2.4.5/linux/drivers/mtd/cfi_probe.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/cfi_probe.c	Wed Dec 31 16:00:00 1969
@@ -1,517 +0,0 @@
-/* 
-   Common Flash Interface probe code.
-   (C) 2000 Red Hat. GPL'd.
-   $Id: cfi_probe.c,v 1.12 2000/07/03 13:29:16 dwmw2 Exp $
-*/
-
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <asm/io.h>
-#include <asm/byteorder.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-
-#include <linux/mtd/map.h>
-#include <linux/mtd/cfi.h>
-
-
-struct mtd_info *cfi_probe(struct map_info *);
-
-static void print_cfi_ident(struct cfi_ident *);
-static void check_cmd_set(struct map_info *, int, unsigned long);
-static struct cfi_private *cfi_cfi_probe(struct map_info *);
-
-static const char im_name[] = "cfi_probe";
-
-/* This routine is made available to other mtd code via
- * inter_module_register.  It must only be accessed through
- * inter_module_get which will bump the use count of this module.  The
- * addresses passed back in mtd are valid as long as the use count of
- * this module is non-zero, i.e. between inter_module_get and
- * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
- */
-struct mtd_info *cfi_probe(struct map_info *map)
-{
-	struct mtd_info *mtd = NULL;
-	struct cfi_private *cfi;
-	/* First probe the map to see if we have CFI stuff there. */
-	cfi = cfi_cfi_probe(map);
-	
-	if (!cfi)
-		return NULL;
-
-	map->fldrv_priv = cfi;
-	map->im_name = im_name;
-
-	/* OK we liked it. Now find a driver for the command set it talks */
-
-	check_cmd_set(map, 1, cfi->chips[0].start); /* First the primary cmdset */
-	check_cmd_set(map, 0, cfi->chips[0].start); /* Then the secondary */
-	
-	/* check_cmd_set() will have used inter_module_get to increase
-	   the use count of the module which provides the command set 
-	   driver. If we're quitting, we have to decrease it again.
-	*/
-
-	if(cfi->cmdset_setup) {
-		mtd = cfi->cmdset_setup(map);
-		
-		if (mtd)
-			return mtd;
-		inter_module_put(cfi->im_name);
-	}
-	printk("No supported Vendor Command Set found\n");
-	
-	kfree(cfi);
-	map->fldrv_priv = NULL;
-	return NULL;
-
-}
-
-static int cfi_probe_new_chip(struct map_info *map, unsigned long base,
-			      struct flchip *chips, struct cfi_private *cfi)
-{
-	switch (map->buswidth) {
-		
-	case 1: {
-		unsigned char tmp = map->read8(map, base + 0x55);
-
-		/* If there's a device there, put it in Query Mode */
-		map->write8(map, 0x98, base+0x55);
-		
-		if (map->read8(map,base+0x10) == 'Q' &&
-		    map->read8(map,base+0x11) == 'R' &&
-		    map->read8(map,base+0x12) == 'Y') {
-			printk("%s: Found a CFI device at 0x%lx in 8 bit mode\n", map->name, base);
-			if (chips) {
-				/* Check previous chips for aliases */
-				printk("FIXME: Do alias check at line %d of cfi_probe.c\n", __LINE__);
-				/* Put it back into Read Mode */
-				map->write8(map, 0x98, base+0x55);
-			}
-			return 1;
-		} else {
-			if (map->read8(map, base + 0x55) == 0x98) {
-				/* It looks like RAM. Put back the stuff we overwrote */
-				map->write8(map, tmp, base+0x55);
-			}
-			return 0;
-		}
-	}
-	
-	case 2: {
-		__u16 tmp = map->read16(map, base + 0xaa);
-		
-		/* If there's a device there, put it into Query Mode */
-		map->write16(map, 0x9898, base+0xAA);
-		
-		if (map->read16(map, base+0x20) == cpu_to_le16(0x0051) &&
-		    map->read16(map, base+0x22) == cpu_to_le16(0x0052) &&
-		    map->read16(map, base+0x24) == cpu_to_le16(0x0059)) {
-			printk("%s: Found a CFI device at 0x%lx in 16 bit mode\n", map->name, base);
-			if (chips) {
-				/* Check previous chips for aliases */
-				int i;
-
-				for (i=0; i < cfi->numchips; i++) {
-					/* This chip should be in read mode if it's one 
-					   we've already touched. */
-					if (map->read16(map, chips[i].start+0x20) == cpu_to_le16(0x0051) &&
-					    map->read16(map, chips[i].start+0x22) == cpu_to_le16(0x0052) &&
-					    map->read16(map, chips[i].start+0x24) == cpu_to_le16(0x0059)){
-						/* Either the old chip has got 'Q''R''Y' in a most
-						   unfortunate place, or it's an alias of the new
-						   chip. Double-check that it's in read mode, and check. */
-						map->write16(map, 0xffff, chips[i].start+0x20);
-						if (map->read16(map, chips[i].start+0x20) == cpu_to_le16(0x0051) &&
-						    map->read16(map, chips[i].start+0x22) == cpu_to_le16(0x0052) &&
-						    map->read16(map, chips[i].start+0x24) == cpu_to_le16(0x0059)) {
-							/* Yes it's got QRY for data. Most unfortunate. 
-							   Stick the old one in read mode too. */
-							map->write16(map, 0xffff, base);
-							if (map->read16(map, base+0x20) == cpu_to_le16(0x0051) &&
-							    map->read16(map, base+0x22) == cpu_to_le16(0x0052) &&
-							    map->read16(map, base+0x24) == cpu_to_le16(0x0059)) {
-								/* OK, so has the new one. Assume it's an alias */
-								printk("T'was probably an alias for the chip at 0x%lx\n", chips[i].start);
-								return 1;
-							} /* else no, they're different, fall through. */
-						} else {
-							/* No the old one hasn't got QRY for data. Therefore,
-							   it's an alias of the new one. */
-							map->write16(map, 0xffff, base+0xaa);
-							/* Just to be paranoid. */
-							map->write16(map, 0xffff, chips[i].start+0xaa);
-							printk("T'was an alias for the chip at 0x%lx\n", chips[i].start);
-							return 1;
-						}
-					} 
-					/* No, the old one didn't look like it's in query mode. Next. */
-				}
-				
-				/* 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("%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;
-				}
-				printk("Not an alias. Adding\n");
-				chips[cfi->numchips].start = base;
-				chips[cfi->numchips].state = FL_READY;
-				chips[cfi->numchips].mutex = &chips[cfi->numchips]._spinlock;
-				cfi->numchips++;
-
-				/* Put it back into Read Mode */
-				map->write16(map, 0xffff, base+0xaa);
-			}
-			
-			return 1;
-		}	
-		else if (map->read16(map, base+0x20) == 0x5151 &&
-			 map->read16(map, base+0x22) == 0x5252 &&
-			 map->read16(map, base+0x24) == 0x5959) {
-			printk("%s: Found a coupled pair of CFI devices at %lx in 8 bit mode\n",
-			       map->name, base);
-			if (chips) {
-				/* Check previous chips for aliases */
-				printk("FIXME: Do alias check at line %d of cfi_probe.c\n", __LINE__);
-
-				/* Put it back into Read Mode */
-				map->write16(map, 0xffff, base+0xaa);
-			}
-
-			return 2;
-		} else {
-			if (map->read16(map, base+0xaa) == 0x9898) {
-				/* It looks like RAM. Put back the stuff we overwrote */
-				map->write16(map, tmp, base+0xaa);
-			}
-			return 0;
-		}
-	}
-
-		
-	case 4: {
-		__u32 tmp = map->read32(map, base+0x154);
-		
-		/* If there's a device there, put it into Query Mode */
-		map->write32(map, 0x98989898, base+0x154);
-		
-		if (map->read32(map, base+0x40) == cpu_to_le32(0x00000051) &&
-		    map->read32(map, base+0x44) == cpu_to_le32(0x00000052) &&
-		    map->read32(map, base+0x48) == cpu_to_le32(0x00000059)) {
-				/* This isn't actually in the CFI spec - only x8 and x16 are. */
-			printk("%s: Found a CFI device at %lx in 32 bit mode\n", map->name, base);
-			if (chips) {
-				/* Check previous chips for aliases */
-				printk("FIXME: Do alias check at line %d of cfi_probe.c\n", __LINE__);
-
-				/* Put it back into read mode */
-				map->write32(map, 0xffffffff, base+0x154);
-			}
-			return 1;
-		} 
-		else if (map->read32(map, base+0x40) == cpu_to_le32(0x00510051) &&
-			 map->read32(map, base+0x44) == cpu_to_le32(0x00520052) &&
-			 map->read32(map, base+0x48) == cpu_to_le32(0x00590059)) {
-			printk("%s: Found a coupled pair of CFI devices at location %lx in 16 bit mode\n", map->name, base);
-			if (chips) {
-				/* Check previous chips for aliases */
-				printk("FIXME: Do alias check at line %d of cfi_probe.c\n", __LINE__);
-
-				/* Put it back into read mode */
-				map->write32(map, 0xffffffff, base+0x154);
-			}
-			return 2;
-		}
-		else if (map->read32(map, base+0x40) == 0x51515151 &&
-			 map->read32(map, base+0x44) == 0x52525252 &&
-			 map->read32(map, base+0x48) == 0x59595959) {
-			printk("%s: Found four side-by-side CFI devices at location %lx in 8 bit mode\n", map->name, base);
-			if (chips) {
-				/* Check previous chips for aliases */
-				printk("FIXME: Do alias check at line %d of cfi_probe.c\n", __LINE__);
-
-				/* Put it back into read mode */
-				map->write32(map, 0xffffffff, base+0x154);
-			}
-			return 4;
-		} else {
-			if (map->read32(map, base+0x154) == 0x98989898) {
-				/* It looks like RAM. Put back the stuff we overwrote */
-				map->write32(map, tmp, base+0x154);
-			}
-			return 0;
-		}
-	}	
-	default:
-		printk(KERN_WARNING "cfi_probe called with strange buswidth %d\n", map->buswidth);
-		return 0;
-	}
-}
-
-static struct cfi_private *cfi_cfi_probe(struct map_info *map)
-{
-	unsigned long base=0;
-	struct cfi_private cfi;
-	struct cfi_private *retcfi;
-	struct flchip chip[MAX_CFI_CHIPS];
-	int i;
-
-	memset(&cfi, 0, sizeof(cfi));
-
-	/* The first invocation (with chips == NULL) leaves the device in Query Mode */
-	cfi.interleave = cfi_probe_new_chip(map, 0, NULL, NULL);
-
-	if (!cfi.interleave) {
-		printk("%s: Found no CFI device at location zero\n", map->name);
-		/* Doesn't appear to be CFI-compliant at all */
-		return NULL;
-	}
-
-	/* Read the Basic Query Structure from the device */
-
-	for (i=0; i<sizeof(struct cfi_ident); i++) {
-		((unsigned char *)&cfi.cfiq)[i] = map->read8(map,base + ((0x10 + i)*map->buswidth));
-	}
-
-	/* Do any necessary byteswapping */
-	cfi.cfiq.P_ID = le16_to_cpu(cfi.cfiq.P_ID);
-	cfi.cfiq.P_ADR = le16_to_cpu(cfi.cfiq.P_ADR);
-	cfi.cfiq.A_ID = le16_to_cpu(cfi.cfiq.A_ID);
-	cfi.cfiq.A_ADR = le16_to_cpu(cfi.cfiq.A_ADR);
-	cfi.cfiq.InterfaceDesc = le16_to_cpu(cfi.cfiq.InterfaceDesc);
-	cfi.cfiq.MaxBufWriteSize = le16_to_cpu(cfi.cfiq.MaxBufWriteSize);
-	
-#if 1
-	/* Dump the information therein */
-	print_cfi_ident(&cfi.cfiq);
-
-	for (i=0; i<cfi.cfiq.NumEraseRegions; i++) {
-		__u16 EraseRegionInfoNum = (map->read8(map,base + ((0x2d + (4*i))*map->buswidth))) + 
-			(((map->read8(map,(0x2e + (4*i))*map->buswidth)) << 8));
-		__u16 EraseRegionInfoSize = (map->read8(map, base + ((0x2f + (4*i))*map->buswidth))) + 
-			(map->read8(map, base + ((0x30 + (4*i))*map->buswidth)) << 8);
-		
-		printk("  Erase Region #%d: BlockSize 0x%4.4X bytes, %d blocks\n",
-		       i, EraseRegionInfoSize * 256, EraseRegionInfoNum+1);
-	}
-	
-	printk("\n");
-#endif	
-
-	/* Switch the chip back into Read Mode, to make the alias detection work */
-	switch(map->buswidth) {
-	case 1:
-		map->write8(map, 0xff, 0x55);
-		break;
-	case 2:
-		map->write16(map, 0xffff, 0xaa);
-		break;
-	case 4:
-		map->write32(map, 0xffffffff, 0x154);
-		break;
-	}
-
-	/* OK. We've worked out what it is and we're happy with it. Now see if there are others */
-
-	chip[0].start = 0;
-	chip[0].state = FL_READY;
-	chip[0].mutex = &chip[0]._spinlock;
-
-	cfi.chipshift =  cfi.cfiq.DevSize;
-	cfi.numchips = 1;
-
-	if (!cfi.chipshift) {
-		printk("cfi.chipsize is zero. This is bad. cfi.cfiq.DevSize is %d\n", cfi.cfiq.DevSize);
-		return NULL;
-	}
-
-	for (base = (1<<cfi.chipshift); base < map->size; base += (1<<cfi.chipshift))
-		cfi_probe_new_chip(map, base, &chip[0], &cfi);
-
-	retcfi = kmalloc(sizeof(struct cfi_private) + cfi.numchips * sizeof(struct flchip), GFP_KERNEL);
-
-	if (!retcfi)
-		return NULL;
-
-	memcpy(retcfi, &cfi, sizeof(cfi));
-	memcpy(&retcfi->chips[0], chip, sizeof(struct flchip) * cfi.numchips);
-	for (i=0; i< retcfi->numchips; i++) {
-		init_waitqueue_head(&retcfi->chips[i].wq);
-		spin_lock_init(&retcfi->chips[i]._spinlock);
-	}
-	return retcfi;
-}
-
-static char *vendorname(__u16 vendor) 
-{
-	switch (vendor) {
-	case P_ID_NONE:
-		return "None";
-		
-	case P_ID_INTEL_EXT:
-		return "Intel/Sharp Extended";
-		
-	case P_ID_AMD_STD:
-		return "AMD/Fujitsu Standard";
-		
-	case P_ID_INTEL_STD:
-		return "Intel/Sharp Standard";
-		
-	case P_ID_AMD_EXT:
-		return "AMD/Fujitsu Extended";
-		
-	case P_ID_MITSUBISHI_STD:
-		return "Mitsubishi Standard";
-		
-	case P_ID_MITSUBISHI_EXT:
-		return "Mitsubishi Extended";
-		
-	case P_ID_RESERVED:
-		return "Not Allowed / Reserved for Future Use";
-		
-	default:
-		return "Unknown";
-	}
-}
-
-		
-static void print_cfi_ident(struct cfi_ident *cfip)
-{
-	if (cfip->qry[0] != 'Q' || cfip->qry[1] != 'R' || cfip->qry[2] != 'Y') {
-		printk("Invalid CFI ident structure.\n");
-		return;
-	}	
-		
-	printk("Primary Vendor Command Set: %4.4X (%s)\n", cfip->P_ID, vendorname(cfip->P_ID));
-	if (cfip->P_ADR)
-		printk("Primary Algorithm Table at %4.4X\n", cfip->P_ADR);
-	else
-		printk("No Primary Algorithm Table\n");
-	
-	printk("Alternative Vendor Command Set: %4.4X (%s)\n", cfip->A_ID, vendorname(cfip->A_ID));
-	if (cfip->A_ADR)
-		printk("Alternate Algorithm Table at %4.4X\n", cfip->A_ADR);
-	else
-		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);
-	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);
-	}
-	else
-		printk("No Vpp line\n");
-	
-	printk("Typical byte/word write timeout: %d µs\n", 1<<cfip->WordWriteTimeoutTyp);
-	printk("Maximum byte/word write timeout: %d µs\n", (1<<cfip->WordWriteTimeoutMax) * (1<<cfip->WordWriteTimeoutTyp));
-	
-	if (cfip->BufWriteTimeoutTyp || cfip->BufWriteTimeoutMax) {
-		printk("Typical full buffer write timeout: %d µs\n", 1<<cfip->BufWriteTimeoutTyp);
-		printk("Maximum full buffer write timeout: %d µs\n", (1<<cfip->BufWriteTimeoutMax) * (1<<cfip->BufWriteTimeoutTyp));
-	}
-	else
-		printk("Full buffer write not supported\n");
-	
-	printk("Typical block erase timeout: %d µs\n", 1<<cfip->BlockEraseTimeoutTyp);
-	printk("Maximum block erase timeout: %d µs\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp));
-	if (cfip->ChipEraseTimeoutTyp || cfip->ChipEraseTimeoutMax) {
-		printk("Typical chip erase timeout: %d µs\n", 1<<cfip->ChipEraseTimeoutTyp); 
-		printk("Maximum chip erase timeout: %d µs\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp));
-	}
-	else
-		printk("Chip erase not supported\n");
-	
-	printk("Device size: 0x%X bytes (%d Mb)\n", 1 << cfip->DevSize, 1<< (cfip->DevSize - 20));
-	printk("Flash Device Interface description: 0x%4.4X\n", cfip->InterfaceDesc);
-	switch(cfip->InterfaceDesc) {
-	case 0:
-		printk("  - x8-only asynchronous interface\n");
-		break;
-		
-	case 1:
-		printk("  - x16-only asynchronous interface\n");
-		break;
-		
-	case 2:
-		printk("  - supports x8 and x16 via BYTE# with asynchronous interface\n");
-		break;
-		
-	case 3:
-		printk("  - x32-only asynchronous interface\n");
-		break;
-		
-	case 65535:
-		printk("  - Not Allowed / Reserved\n");
-		break;
-		
-	default:
-		printk("  - Unknown\n");
-		break;
-	}
-	
-	printk("Max. bytes in buffer write: 0x%x\n", 1<< cfip->MaxBufWriteSize);
-	printk("Number of Erase Block Regions: %d\n", cfip->NumEraseRegions);
-	
-}
-
-static void check_cmd_set(struct map_info *map, int primary, unsigned long base)
-{
-	__u16 adr;
-	struct cfi_private *cfi = map->fldrv_priv;
-	__u16 type = primary?cfi->cfiq.P_ID:cfi->cfiq.A_ID;
-	char probename[32];
-	void (*probe_function)(struct map_info *, int, unsigned long);
-	
-	if (type == P_ID_NONE || type == P_ID_RESERVED)
-		return;
-	
-	sprintf(probename, "cfi_cmdset_%4.4X", type);
-	
-	probe_function = inter_module_get_request(probename, probename);
-	if (probe_function) {
-		(*probe_function)(map, primary, base);
-		return;
-	}
-
-	/* This was a command set we don't know about. Print only the basic info */
-	adr = primary?cfi->cfiq.P_ADR:cfi->cfiq.A_ADR;
-	
-	if (!adr) {
-		printk(" No Extended Query Table\n");
-	}
-	else if (map->read8(map,base+(adr*map->buswidth)) != (primary?'P':'A') ||
-		 map->read8(map,base+((adr+1)*map->buswidth)) != (primary?'R':'L') ||
-		 map->read8(map,base+((adr+2)*map->buswidth)) != (primary?'I':'T')) {
-		printk ("Invalid Extended Query Table at %4.4X: %2.2X %2.2X %2.2X\n",
-			adr,
-			map->read8(map,base+(adr*map->buswidth)),
-			map->read8(map,base+((adr+1)*map->buswidth)),
-			map->read8(map,base+((adr+2)*map->buswidth)));
-	}
-	else {
-		printk(" Extended Query Table version %c.%c\n",
-		       map->read8(map,base+((adr+3)*map->buswidth)), 
-		       map->read8(map,base+((adr+4)*map->buswidth)));
-	}
-}
-
-static int __init cfi_probe_init(void)
-{
-	inter_module_register(im_name, THIS_MODULE, &cfi_probe);
-	return 0;
-}
-
-static void __exit cfi_probe_exit(void)
-{
-	inter_module_unregister(im_name);
-}
-
-module_init(cfi_probe_init);
-module_exit(cfi_probe_exit);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/chips/Config.in linux/drivers/mtd/chips/Config.in
--- v2.4.5/linux/drivers/mtd/chips/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/chips/Config.in	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,42 @@
+# drivers/mtd/chips/Config.in
+
+# $Id: Config.in,v 1.4 2001/05/14 09:48:12 dwmw2 Exp $
+
+mainmenu_option next_comment
+
+comment 'RAM/ROM/Flash chip drivers'
+
+dep_tristate '  Common Flash Interface (CFI) support' CONFIG_MTD_CFI $CONFIG_MTD
+if [ "$CONFIG_MTD_CFI" = "y" -o "$CONFIG_MTD_CFI" = "m" ]; then
+   bool '  CFI Virtual erase regions (EXPERIMENTAL)' CONFIG_MTD_CFI_VIRTUAL_ER 
+   bool '  CFI Advanced configuration options' CONFIG_MTD_CFI_ADV_OPTIONS
+   if [ "$CONFIG_MTD_CFI_ADV_OPTIONS" = "y" ]; then
+     choice 'Flash cmd/query data swapping'			\
+	"NO			CONFIG_MTD_CFI_NOSWAP		\
+	 BIG_ENDIAN_BYTE	CONFIG_MTD_CFI_BE_BYTE_SWAP	\
+	 LITTLE_ENDIAN_BYTE	CONFIG_MTD_CFI_LE_BYTE_SWAP	\
+	 LART_ENDIAN_BYTE	CONFIG_MTD_CFI_LART_BIT_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
+	 if [ "$CONFIG_MTD_CFI_B1" = "y" ]; then
+	   define_bool CONFIG_MTD_CFI_I1 y
+         else
+           bool '    Support 1-chip flash interleave' CONFIG_MTD_CFI_I1
+	 fi
+       bool '    Support 2-chip flash interleave' CONFIG_MTD_CFI_I2
+       bool '    Support 4-chip flash interleave' CONFIG_MTD_CFI_I4
+     fi
+  fi
+fi
+dep_tristate '    CFI support for Intel/Sharp Basic/Extended Commands' CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_CFI
+dep_tristate '    CFI support for AMD/Fujitsu Standard Commands' CONFIG_MTD_CFI_AMDSTD $CONFIG_MTD_CFI
+dep_tristate '  AMD compatible flash chip support (non-CFI)' CONFIG_MTD_AMDSTD $CONFIG_MTD
+dep_tristate '  pre-CFI Sharp chip support' CONFIG_MTD_SHARP $CONFIG_MTD
+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 '  JEDEC device support' CONFIG_MTD_JEDEC $CONFIG_MTD
+
+endmenu
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/chips/Makefile linux/drivers/mtd/chips/Makefile
--- v2.4.5/linux/drivers/mtd/chips/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/chips/Makefile	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,27 @@
+#
+# linux/drivers/chips/Makefile
+#
+# $Id: Makefile,v 1.4 2001/06/09 19:57:57 dwmw2 Exp $
+
+O_TARGET	:= chipslink.o
+
+export-objs	:= chipreg.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 cfi_jedec.o
+obj-$(CONFIG_MTD_CFI_AMDSTD)	+= cfi_cmdset_0002.o
+obj-$(CONFIG_MTD_CFI_INTELEXT)	+= cfi_cmdset_0001.o
+obj-$(CONFIG_MTD_JEDEC)		+= jedec.o
+obj-$(CONFIG_MTD_RAM)		+= map_ram.o
+obj-$(CONFIG_MTD_ROM)		+= map_rom.o
+obj-$(CONFIG_MTD_SHARP)		+= sharp.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/chips/amd_flash.c linux/drivers/mtd/chips/amd_flash.c
--- v2.4.5/linux/drivers/mtd/chips/amd_flash.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/chips/amd_flash.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,1251 @@
+/*
+ * MTD map driver for AMD compatible flash chips (non-CFI)
+ *
+ * Author: Jonas Holmberg <jonas.holmberg@axis.com>
+ *
+ * $Id: amd_flash.c,v 1.8 2001/06/02 14:47:16 dwmw2 Exp $
+ *
+ * Copyright (c) 2001 Axis Communications AB
+ *
+ * This file is under GPL.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/flashchip.h>
+
+/* There's no limit. It exists only to avoid realloc. */
+#define MAX_AMD_CHIPS 8
+
+#define DEVICE_TYPE_X8	(8 / 8)
+#define DEVICE_TYPE_X16	(16 / 8)
+#define DEVICE_TYPE_X32	(32 / 8)
+
+/* Addresses */
+#define ADDR_MANUFACTURER		0x0000
+#define ADDR_DEVICE_ID			0x0001
+#define ADDR_UNLOCK_1			0x0555
+#define ADDR_UNLOCK_2			0x02AA
+
+/* Commands */
+#define CMD_UNLOCK_DATA_1		0x00AA
+#define CMD_UNLOCK_DATA_2		0x0055
+#define CMD_MANUFACTURER_UNLOCK_DATA	0x0090
+#define CMD_UNLOCK_BYPASS_MODE		0x0020
+#define CMD_PROGRAM_UNLOCK_DATA		0x00A0
+#define CMD_RESET_DATA			0x00F0
+#define CMD_SECTOR_ERASE_UNLOCK_DATA	0x0080
+#define CMD_SECTOR_ERASE_UNLOCK_DATA_2	0x0030
+
+/* Manufacturers */
+#define MANUFACTURER_AMD	0x0001
+#define MANUFACTURER_FUJITSU	0x0004
+#define MANUFACTURER_ST		0x0020
+#define MANUFACTURER_SST	0x00BF
+#define MANUFACTURER_TOSHIBA	0x0098
+
+/* AMD */
+#define AM29F800BB	0x2258
+#define AM29F800BT	0x22D6
+#define AM29LV800BB	0x225B
+#define AM29LV800BT	0x22DA
+#define AM29LV160DT	0x22C4
+#define AM29LV160DB	0x2249
+
+/* Fujitsu */
+#define MBM29LV160TE	0x22C4
+#define MBM29LV160BE	0x2249
+
+/* ST - www.st.com */
+#define M29W800T	0x00D7
+#define M29W160DT	0x22C4
+#define M29W160DB	0x2249
+
+/* SST */
+#define SST39LF800	0x2781
+#define SST39LF160	0x2782
+
+/* Toshiba */
+#define TC58FVT160	0x00C2
+#define TC58FVB160	0x0043
+
+#define D6_MASK	0x40
+
+struct amd_flash_private {
+	int device_type;	
+	int interleave;	
+	int numchips;	
+	unsigned long chipshift;
+//	const char *im_name;
+	struct flchip chips[0];
+};
+
+struct amd_flash_info {
+	const __u16 mfr_id;
+	const __u16 dev_id;
+	const char *name;
+	const u_long size;
+	const int numeraseregions;
+	const struct mtd_erase_region_info regions[4];
+};
+
+
+
+static int amd_flash_read(struct mtd_info *, loff_t, size_t, size_t *,
+			  u_char *);
+static int amd_flash_write(struct mtd_info *, loff_t, size_t, size_t *,
+			   const u_char *);
+static int amd_flash_erase(struct mtd_info *, struct erase_info *);
+static void amd_flash_sync(struct mtd_info *);
+static int amd_flash_suspend(struct mtd_info *);
+static void amd_flash_resume(struct mtd_info *);
+static void amd_flash_destroy(struct mtd_info *);
+static struct mtd_info *amd_flash_probe(struct map_info *map);
+
+
+static struct mtd_chip_driver amd_flash_chipdrv = {
+	probe: amd_flash_probe,
+	destroy: amd_flash_destroy,
+	name: "amd_flash",
+	module: THIS_MODULE
+};
+
+
+
+static const char im_name[] = "amd_flash";
+
+
+
+static inline __u32 wide_read(struct map_info *map, __u32 addr)
+{
+	if (map->buswidth == 1) {
+		return map->read8(map, addr);
+	} else if (map->buswidth == 2) {
+		return map->read16(map, addr);
+	} else if (map->buswidth == 4) {
+		return map->read32(map, addr);
+        }
+
+	return 0;
+}
+
+static inline void wide_write(struct map_info *map, __u32 val, __u32 addr)
+{
+	if (map->buswidth == 1) {
+		map->write8(map, val, addr);
+	} else if (map->buswidth == 2) {
+		map->write16(map, val, addr);
+	} else if (map->buswidth == 4) {
+		map->write32(map, val, addr);
+	}
+}
+
+static inline __u32 make_cmd(struct map_info *map, __u32 cmd)
+{
+	const struct amd_flash_private *private = map->fldrv_priv;
+	if ((private->interleave == 2) &&
+	    (private->device_type == DEVICE_TYPE_X16)) {
+		cmd |= (cmd << 16);
+	}
+
+	return cmd;
+}
+
+static inline void send_unlock(struct map_info *map, unsigned long base)
+{
+	wide_write(map, (CMD_UNLOCK_DATA_1 << 16) | CMD_UNLOCK_DATA_1,
+		   base + (map->buswidth * ADDR_UNLOCK_1));
+	wide_write(map, (CMD_UNLOCK_DATA_2 << 16) | CMD_UNLOCK_DATA_2,
+		   base + (map->buswidth * ADDR_UNLOCK_2));
+}
+
+static inline void send_cmd(struct map_info *map, unsigned long base, __u32 cmd)
+{
+	send_unlock(map, base);
+	wide_write(map, make_cmd(map, cmd),
+		   base + (map->buswidth * ADDR_UNLOCK_1));
+}
+
+static inline void send_cmd_to_addr(struct map_info *map, unsigned long base,
+				    __u32 cmd, unsigned long addr)
+{
+	send_unlock(map, base);
+	wide_write(map, make_cmd(map, cmd), addr);
+}
+
+static inline int flash_is_busy(struct map_info *map, unsigned long addr,
+				int interleave)
+{
+
+	if ((interleave == 2) && (map->buswidth == 4)) {
+		__u32 read1, read2;
+
+		read1 = wide_read(map, addr);
+		read2 = wide_read(map, addr);
+
+		return (((read1 >> 16) & D6_MASK) !=
+			((read2 >> 16) & D6_MASK)) ||
+		       (((read1 & 0xffff) & D6_MASK) !=
+			((read2 & 0xffff) & D6_MASK));
+	}
+
+	return ((wide_read(map, addr) & D6_MASK) !=
+		(wide_read(map, addr) & D6_MASK));
+}
+
+
+
+/*
+ * Reads JEDEC manufacturer ID and device ID and returns the index of the first
+ * matching table entry (-1 if not found or alias for already found chip).
+ */ 
+static int probe_new_chip(struct mtd_info *mtd, __u32 base,
+			  struct flchip *chips,
+			  struct amd_flash_private *private,
+			  const struct amd_flash_info *table, int table_size)
+{
+	__u32 mfr_id, dev_id;
+	struct map_info *map = mtd->priv;
+	struct amd_flash_private temp;
+	int i;
+
+	temp.device_type = DEVICE_TYPE_X16;	// Assume X16 (FIXME)
+	temp.interleave = 2;
+	map->fldrv_priv = &temp;
+
+	/* Enter autoselect mode. */
+	send_cmd(map, base, CMD_RESET_DATA);
+	send_cmd(map, base, CMD_MANUFACTURER_UNLOCK_DATA);
+
+	mfr_id = wide_read(map, base + (map->buswidth * ADDR_MANUFACTURER));
+	dev_id = wide_read(map, base + (map->buswidth * ADDR_DEVICE_ID));
+
+	if ((map->buswidth == 4) && ((mfr_id >> 16) == (mfr_id & 0xffff)) &&
+	    ((dev_id >> 16) == (dev_id & 0xffff))) {
+		mfr_id = mfr_id & 0xffff;
+		dev_id = dev_id & 0xffff;
+	} else {
+		temp.interleave = 1;
+	}
+
+	for (i = 0; i < table_size; i++) {
+		if ((mfr_id == table[i].mfr_id) &&
+		    (dev_id == table[i].dev_id)) {
+			if (chips) {
+				int j;
+
+				/* Is this an alias for an already found chip?
+				 * In that case that chip should be in
+				 * autoselect mode now.
+				 */
+				for (j = 0; j < private->numchips; j++) {
+					if ((wide_read(map, chips[j].start +
+							    (map->buswidth *
+							     ADDR_MANUFACTURER))
+					     == mfr_id)
+					    &&
+					    (wide_read(map, chips[j].start +
+					    		    (map->buswidth *
+							     ADDR_DEVICE_ID))
+					     == dev_id)) {
+
+						/* Exit autoselect mode. */
+						send_cmd(map, base,
+							 CMD_RESET_DATA);
+
+						return -1;
+					}
+				}
+
+				if (private->numchips == MAX_AMD_CHIPS) {
+					printk(KERN_WARNING
+					       "%s: Too many flash chips "
+					       "detected. Increase "
+					       "MAX_AMD_CHIPS from %d.\n",
+					       map->name, MAX_AMD_CHIPS);
+
+					return -1;
+				}
+
+				chips[private->numchips].start = base;
+				chips[private->numchips].state = FL_READY;
+				chips[private->numchips].mutex =
+					&chips[private->numchips]._spinlock;
+				private->numchips++;
+			}
+
+			printk("%s: Found %d x %ldMiB %s at 0x%x\n", map->name,
+			       temp.interleave, (table[i].size)/(1024*1024),
+			       table[i].name, base);
+
+			mtd->size += table[i].size * temp.interleave;
+			mtd->numeraseregions += table[i].numeraseregions;
+
+			break;
+		}
+	}
+
+	/* Exit autoselect mode. */
+	send_cmd(map, base, CMD_RESET_DATA);
+
+	if (i == table_size) {
+		printk(KERN_DEBUG "%s: unknown flash device at 0x%x, "
+		       "mfr id 0x%x, dev id 0x%x\n", map->name,
+		       base, mfr_id, dev_id);
+		map->fldrv_priv = NULL;
+
+		return -1;
+	}
+
+	private->device_type = temp.device_type;
+	private->interleave = temp.interleave;
+
+	return i;
+}
+
+
+
+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[] = {
+	{
+		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_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_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: 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: 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: 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: 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: 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: 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: 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_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: 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 }
+		}
+	} 
+	};
+
+	struct mtd_info *mtd;
+	struct flchip chips[MAX_AMD_CHIPS];
+	int table_pos[MAX_AMD_CHIPS];
+	struct amd_flash_private temp;
+	struct amd_flash_private *private;
+	u_long size;
+	unsigned long base;
+	int i;
+	int reg_idx;
+	int offset;
+
+	mtd = (struct mtd_info*)kmalloc(sizeof(*mtd), GFP_KERNEL);
+	if (!mtd) {
+		printk(KERN_WARNING
+		       "%s: kmalloc failed for info structure\n", map->name);
+		return NULL;
+	}
+	memset(mtd, 0, sizeof(*mtd));
+	mtd->priv = map;
+
+	memset(&temp, 0, sizeof(temp));
+
+	printk("%s: Probing for AMD compatible flash...\n", map->name);
+
+	if ((table_pos[0] = probe_new_chip(mtd, 0, NULL, &temp, table,
+					   sizeof(table)/sizeof(table[0])))
+	    == -1) {
+		printk(KERN_WARNING
+		       "%s: Found no AMD compatible device at location zero\n",
+		       map->name);
+		kfree(mtd);
+
+		return NULL;
+	}
+
+	chips[0].start = 0;
+	chips[0].state = FL_READY;
+	chips[0].mutex = &chips[0]._spinlock;
+	temp.numchips = 1;
+	for (size = mtd->size; size > 1; size >>= 1) {
+		temp.chipshift++;
+	}
+	switch (temp.interleave) {
+		case 2:
+			temp.chipshift += 1;
+			break;
+		case 4:
+			temp.chipshift += 2;
+			break;
+	}
+
+	/* Find out if there are any more chips in the map. */
+	for (base = (1 << temp.chipshift);
+	     base < map->size;
+	     base += (1 << temp.chipshift)) {
+	     	int numchips = temp.numchips;
+		table_pos[numchips] = probe_new_chip(mtd, base, chips,
+			&temp, table, sizeof(table)/sizeof(table[0]));
+	}
+
+	mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) *
+				    mtd->numeraseregions, GFP_KERNEL);
+	if (!mtd->eraseregions) { 
+		printk(KERN_WARNING "%s: Failed to allocate "
+		       "memory for MTD erase region info\n", map->name);
+		kfree(mtd);
+		map->fldrv_priv = NULL;
+		return 0;
+	}
+
+	reg_idx = 0;
+	offset = 0;
+	for (i = 0; i < temp.numchips; i++) {
+		int dev_size;
+		int j;
+
+		dev_size = 0;
+		for (j = 0; j < table[table_pos[i]].numeraseregions; j++) {
+			mtd->eraseregions[reg_idx].offset = offset +
+				(table[table_pos[i]].regions[j].offset *
+				 temp.interleave);
+			mtd->eraseregions[reg_idx].erasesize =
+				table[table_pos[i]].regions[j].erasesize *
+				temp.interleave;
+			mtd->eraseregions[reg_idx].numblocks =
+				table[table_pos[i]].regions[j].numblocks;
+			if (mtd->erasesize <
+			    mtd->eraseregions[reg_idx].erasesize) {
+				mtd->erasesize =
+					mtd->eraseregions[reg_idx].erasesize;
+			}
+			dev_size += mtd->eraseregions[reg_idx].erasesize *
+				    mtd->eraseregions[reg_idx].numblocks;
+			reg_idx++;
+		}
+		offset += dev_size;
+	}
+	mtd->type = MTD_NORFLASH;
+	mtd->flags = MTD_CAP_NORFLASH;
+	mtd->name = map->name;
+	mtd->erase = amd_flash_erase;	
+	mtd->read = amd_flash_read;	
+	mtd->write = amd_flash_write;	
+	mtd->sync = amd_flash_sync;	
+	mtd->suspend = amd_flash_suspend;	
+	mtd->resume = amd_flash_resume;	
+
+	private = kmalloc(sizeof(*private) + (sizeof(struct flchip) *
+					      temp.numchips), GFP_KERNEL);
+	if (!private) {
+		printk(KERN_WARNING
+		       "%s: kmalloc failed for private structure\n", map->name);
+		kfree(mtd);
+		map->fldrv_priv = NULL;
+		return NULL;
+	}
+	memcpy(private, &temp, sizeof(temp));
+	memcpy(private->chips, chips,
+	       sizeof(struct flchip) * private->numchips);
+	for (i = 0; i < private->numchips; i++) {
+		init_waitqueue_head(&private->chips[i].wq);
+		spin_lock_init(&private->chips[i]._spinlock);
+	}
+
+	map->fldrv_priv = private;
+
+	map->fldrv = &amd_flash_chipdrv;
+	MOD_INC_USE_COUNT;
+
+	return mtd;
+}
+
+
+
+static inline int read_one_chip(struct map_info *map, struct flchip *chip,
+			       loff_t adr, size_t len, u_char *buf)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long timeo = jiffies + HZ;
+
+retry:
+	spin_lock_bh(chip->mutex);
+
+	if (chip->state != FL_READY){
+		printk(KERN_INFO "%s: waiting for chip to read, state = %d\n",
+		       map->name, chip->state);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+                
+		spin_unlock_bh(chip->mutex);
+
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+
+		if(signal_pending(current)) {
+			return -EINTR;
+		}
+
+		timeo = jiffies + HZ;
+
+		goto retry;
+	}	
+
+	adr += chip->start;
+
+	chip->state = FL_READY;
+
+	map->copy_from(map, buf, adr, len);
+
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+
+	return 0;
+}
+
+
+
+static int amd_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
+			  size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct amd_flash_private *private = map->fldrv_priv;
+	unsigned long ofs;
+	int chipnum;
+	int ret = 0;
+
+	if ((from + len) > mtd->size) {
+		printk(KERN_WARNING "%s: read request past end of device "
+		       "(0x%lx)\n", map->name, (unsigned long)from + len);
+
+		return -EINVAL;
+	}
+
+	/* Offset within the first chip that the first read should start. */
+	chipnum = (from >> private->chipshift);
+	ofs = from - (chipnum <<  private->chipshift);
+
+	*retlen = 0;
+
+	while (len) {
+		unsigned long this_len;
+
+		if (chipnum >= private->numchips) {
+			break;
+		}
+
+		if ((len + ofs - 1) >> private->chipshift) {
+			this_len = (1 << private->chipshift) - ofs;
+		} else {
+			this_len = len;
+		}
+
+		ret = read_one_chip(map, &private->chips[chipnum], ofs,
+				    this_len, buf);
+		if (ret) {
+			break;
+		}
+
+		*retlen += this_len;
+		len -= this_len;
+		buf += this_len;
+
+		ofs = 0;
+		chipnum++;
+	}
+
+	return ret;
+}
+
+
+
+static int write_one_word(struct map_info *map, struct flchip *chip,
+			  unsigned long adr, __u32 datum)
+{
+	unsigned long timeo = jiffies + HZ;
+	struct amd_flash_private *private = map->fldrv_priv;
+	DECLARE_WAITQUEUE(wait, current);
+	int ret = 0;
+	int times_left;
+
+retry:
+	spin_lock_bh(chip->mutex);
+
+	if (chip->state != FL_READY){
+		printk("%s: waiting for chip to write, state = %d\n",
+		       map->name, chip->state);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+                
+		spin_unlock_bh(chip->mutex);
+
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		printk(KERN_INFO "%s: woke up to write\n", map->name);
+		if(signal_pending(current))
+			return -EINTR;
+
+		timeo = jiffies + HZ;
+
+		goto retry;
+	}	
+
+	chip->state = FL_WRITING;
+
+	adr += chip->start;
+	ENABLE_VPP(map);
+	send_cmd(map, chip->start, CMD_PROGRAM_UNLOCK_DATA);
+	wide_write(map, datum, adr);
+
+	times_left = 500000;
+	while (times_left-- && flash_is_busy(map, chip->start,
+					     private->interleave)) {
+		if (current->need_resched) {
+			spin_unlock_bh(chip->mutex);
+			schedule();
+			spin_lock_bh(chip->mutex);
+		}
+	}
+
+	if (!times_left) {
+		printk(KERN_WARNING "%s: write to 0x%lx timed out!\n",
+		       map->name, adr);
+		ret = -EIO;
+	} else {
+		__u32 verify;
+		if ((verify = wide_read(map, adr)) != datum) {
+			printk(KERN_WARNING "%s: write to 0x%lx failed. "
+			       "datum = %x, verify = %x\n",
+			       map->name, adr, datum, verify);
+			ret = -EIO;
+		}
+	}
+
+	DISABLE_VPP(map);
+	chip->state = FL_READY;
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+
+	return ret;
+}
+
+
+
+static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len,
+			   size_t *retlen, const u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct amd_flash_private *private = map->fldrv_priv;
+	int ret = 0;
+	int chipnum;
+	unsigned long ofs;
+	unsigned long chipstart;
+
+	*retlen = 0;
+	if (!len) {
+		return 0;
+	}
+
+	chipnum = to >> private->chipshift;
+	ofs = to  - (chipnum << private->chipshift);
+	chipstart = private->chips[chipnum].start;
+
+	/* If it's not bus-aligned, do the first byte write. */
+	if (ofs & (map->buswidth - 1)) {
+		unsigned long bus_ofs = ofs & ~(map->buswidth - 1);
+		int i = ofs - bus_ofs;
+		int n = 0;
+		u_char tmp_buf[4];
+		__u32 datum;
+
+		map->copy_from(map, tmp_buf,
+			       bus_ofs + private->chips[chipnum].start,
+			       map->buswidth);
+		while (len && i < map->buswidth)
+			tmp_buf[i++] = buf[n++], len--;
+
+		if (map->buswidth == 2) {
+			datum = *(__u16*)tmp_buf;
+		} else if (map->buswidth == 4) {
+			datum = *(__u32*)tmp_buf;
+		} else {
+			return -EINVAL;  /* should never happen, but be safe */
+		}
+
+		ret = write_one_word(map, &private->chips[chipnum], bus_ofs,
+				     datum);
+		if (ret) {
+			return ret;
+		}
+		
+		ofs += n;
+		buf += n;
+		(*retlen) += n;
+
+		if (ofs >> private->chipshift) {
+			chipnum++;
+			ofs = 0;
+			if (chipnum == private->numchips) {
+				return 0;
+			}
+		}
+	}
+	
+	/* We are now aligned, write as much as possible. */
+	while(len >= map->buswidth) {
+		__u32 datum;
+
+		if (map->buswidth == 1) {
+			datum = *(__u8*)buf;
+		} else if (map->buswidth == 2) {
+			datum = *(__u16*)buf;
+		} else if (map->buswidth == 4) {
+			datum = *(__u32*)buf;
+		} else {
+			return -EINVAL;
+		}
+
+		ret = write_one_word(map, &private->chips[chipnum], ofs, datum);
+
+		if (ret) {
+			return ret;
+		}
+
+		ofs += map->buswidth;
+		buf += map->buswidth;
+		(*retlen) += map->buswidth;
+		len -= map->buswidth;
+
+		if (ofs >> private->chipshift) {
+			chipnum++;
+			ofs = 0;
+			if (chipnum == private->numchips) {
+				return 0;
+			}
+			chipstart = private->chips[chipnum].start;
+		}
+	}
+
+	if (len & (map->buswidth - 1)) {
+		int i = 0, n = 0;
+		u_char tmp_buf[2];
+		__u32 datum;
+
+		map->copy_from(map, tmp_buf,
+			       ofs + private->chips[chipnum].start,
+			       map->buswidth);
+		while (len--) {
+			tmp_buf[i++] = buf[n++];
+		}
+
+		if (map->buswidth == 2) {
+			datum = *(__u16*)tmp_buf;
+		} else if (map->buswidth == 4) {
+			datum = *(__u32*)tmp_buf;
+		} else {
+			return -EINVAL;  /* should never happen, but be safe */
+		}
+
+		ret = write_one_word(map, &private->chips[chipnum], ofs, datum);
+
+		if (ret) {
+			return ret;
+		}
+		
+		(*retlen) += n;
+	}
+
+	return 0;
+}
+
+
+
+static inline int erase_one_block(struct map_info *map, struct flchip *chip,
+				  unsigned long adr, u_long size)
+{
+	unsigned long timeo = jiffies + HZ;
+	struct amd_flash_private *private = map->fldrv_priv;
+	DECLARE_WAITQUEUE(wait, current);
+
+retry:
+	spin_lock_bh(chip->mutex);
+
+	if (chip->state != FL_READY){
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+                
+		spin_unlock_bh(chip->mutex);
+
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+
+		if (signal_pending(current)) {
+			return -EINTR;
+		}
+
+		timeo = jiffies + HZ;
+
+		goto retry;
+	}	
+
+	chip->state = FL_ERASING;
+
+	adr += chip->start;
+	ENABLE_VPP(map);
+	send_cmd(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA);
+	send_cmd_to_addr(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA_2, adr);
+	
+	timeo = jiffies + (HZ * 20);
+
+	spin_unlock_bh(chip->mutex);
+	schedule_timeout(HZ);
+	spin_lock_bh(chip->mutex);
+	
+	while (flash_is_busy(map, chip->start, private->interleave)) {
+
+		if (chip->state != FL_ERASING) {
+			/* Someone's suspended the erase. Sleep */
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			add_wait_queue(&chip->wq, &wait);
+			
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_INFO "%s: erase suspended. Sleeping\n",
+			       map->name);
+			schedule();
+			remove_wait_queue(&chip->wq, &wait);
+			
+			if (signal_pending(current)) {
+				return -EINTR;
+			}
+			
+			timeo = jiffies + (HZ*2); /* FIXME */
+			spin_lock_bh(chip->mutex);
+			continue;
+		}
+
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+			chip->state = FL_READY;
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_WARNING "%s: waiting for erase to complete "
+			       "timed out.\n", map->name);
+			DISABLE_VPP(map);
+
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+
+		if (current->need_resched)
+			schedule();
+		else
+			udelay(1);
+		
+		spin_lock_bh(chip->mutex);
+	}
+
+	/* Verify every single word */
+	{
+		int address;
+		int error = 0;
+		__u8 verify;
+
+		for (address = adr; address < (adr + size); address++) {
+			if ((verify = map->read8(map, address)) != 0xFF) {
+				error = 1;
+				break;
+			}
+		}
+		if (error) {
+			chip->state = FL_READY;
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_WARNING
+			       "%s: verify error at 0x%x, size %ld.\n",
+			       map->name, address, size);
+			DISABLE_VPP(map);
+
+			return -EIO;
+		}
+	}
+	
+	DISABLE_VPP(map);
+	chip->state = FL_READY;
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+
+	return 0;
+}
+
+
+
+static int amd_flash_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct map_info *map = mtd->priv;
+	struct amd_flash_private *private = map->fldrv_priv;
+	unsigned long adr, len;
+	int chipnum;
+	int ret = 0;
+	int i;
+	int 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.
+	 */
+
+	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) &&
+	       (instr->addr >= 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 (instr->addr & (regions[i].erasesize-1)) {
+		return -EINVAL;
+	}
+
+	/* Remember the erase region we start on. */
+
+	first = i;
+
+	/* Next, check that the end of the requested erase is aligned
+	 * with the erase region at that address.
+	 */
+
+	while ((i < mtd->numeraseregions) && 
+	       ((instr->addr + instr->len) >= regions[i].offset)) {
+                i++;
+	}
+
+	/* As before, drop back one to point at the region in which
+	 * the address actually falls.
+	 */
+
+	i--;
+
+	if ((instr->addr + instr->len) & (regions[i].erasesize-1)) {
+                return -EINVAL;
+	}
+
+	chipnum = instr->addr >> private->chipshift;
+	adr = instr->addr - (chipnum << private->chipshift);
+	len = instr->len;
+
+	i = first;
+
+	while (len) {
+		ret = erase_one_block(map, &private->chips[chipnum], adr,
+				      regions[i].erasesize);
+
+		if (ret) {
+			return ret;
+		}
+
+		adr += regions[i].erasesize;
+		len -= regions[i].erasesize;
+
+		if ((adr % (1 << private->chipshift)) ==
+		    ((regions[i].offset + (regions[i].erasesize *
+		    			   regions[i].numblocks))
+		     % (1 << private->chipshift))) {
+			i++;
+		}
+
+		if (adr >> private->chipshift) {
+			adr = 0;
+			chipnum++;
+			if (chipnum >= private->numchips) {
+				break;
+			}
+		}
+	}
+		
+	instr->state = MTD_ERASE_DONE;
+	if (instr->callback) {
+		instr->callback(instr);
+	}
+	
+	return 0;
+}
+
+
+
+static void amd_flash_sync(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct amd_flash_private *private = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+	int ret = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	for (i = 0; !ret && (i < private->numchips); i++) {
+		chip = &private->chips[i];
+
+	retry:
+		spin_lock_bh(chip->mutex);
+
+		switch(chip->state) {
+		case FL_READY:
+		case FL_STATUS:
+		case FL_CFI_QUERY:
+		case FL_JEDEC_QUERY:
+			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_bh(chip->mutex);
+			break;
+
+		default:
+			/* Not an idle state */
+			add_wait_queue(&chip->wq, &wait);
+			
+			spin_unlock_bh(chip->mutex);
+
+			schedule();
+
+		        remove_wait_queue(&chip->wq, &wait);
+			
+			goto retry;
+		}
+	}
+
+	/* Unlock the chips again */
+	for (i--; i >= 0; i--) {
+		chip = &private->chips[i];
+
+		spin_lock_bh(chip->mutex);
+		
+		if (chip->state == FL_SYNCING) {
+			chip->state = chip->oldstate;
+			wake_up(&chip->wq);
+		}
+		spin_unlock_bh(chip->mutex);
+	}
+}
+
+
+
+static int amd_flash_suspend(struct mtd_info *mtd)
+{
+printk("amd_flash_suspend(): not implemented!\n");
+	return -EINVAL;
+}
+
+
+
+static void amd_flash_resume(struct mtd_info *mtd)
+{
+printk("amd_flash_resume(): not implemented!\n");
+}
+
+
+
+static void amd_flash_destroy(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct amd_flash_private *private = map->fldrv_priv;
+	kfree(private);
+}
+
+int __init amd_flash_init(void)
+{
+	register_mtd_chip_driver(&amd_flash_chipdrv);
+	return 0;
+}
+
+void __exit amd_flash_exit(void)
+{
+	unregister_mtd_chip_driver(&amd_flash_chipdrv);
+}
+
+module_init(amd_flash_init);
+module_exit(amd_flash_exit);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/chips/cfi_cmdset_0001.c linux/drivers/mtd/chips/cfi_cmdset_0001.c
--- v2.4.5/linux/drivers/mtd/chips/cfi_cmdset_0001.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/chips/cfi_cmdset_0001.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,1636 @@
+/*
+ * Common Flash Interface support:
+ *   Intel Extended Vendor Command Set (ID 0x0001)
+ *
+ * (C) 2000 Red Hat. GPL'd
+ *
+ * $Id: cfi_cmdset_0001.c,v 1.80 2001/06/03 01:32:57 nico Exp $
+ *
+ * 
+ * 10/10/2000	Nicolas Pitre <nico@cam.org>
+ * 	- completely revamped method functions so they are aware and
+ * 	  independent of the flash geometry (buswidth, interleave, etc.)
+ * 	- scalability vs code size is completely set at compile-time
+ * 	  (see include/linux/mtd/cfi.h for selection)
+ *	- optimized write buffer method
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+#include <linux/mtd/compatmac.h>
+
+static int cfi_intelext_read (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_suspend (struct mtd_info *);
+static void cfi_intelext_resume (struct mtd_info *);
+
+static void cfi_intelext_destroy(struct mtd_info *);
+
+void cfi_cmdset_0001(struct map_info *, int, unsigned long);
+
+static struct mtd_info *cfi_intelext_setup (struct map_info *);
+
+static struct mtd_chip_driver cfi_intelext_chipdrv = {
+	probe: cfi_intelext_setup,
+	destroy: cfi_intelext_destroy,
+	name: "cfi_intel",
+	module: THIS_MODULE
+};
+
+/* #define DEBUG_LOCK_BITS */
+
+/* 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 cfi are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
+void cfi_cmdset_0001(struct map_info *map, int primary, unsigned long base)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	struct cfi_pri_intelext *extp;
+	int ofs_factor = cfi->interleave * cfi->device_type;
+
+	__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
+
+	//printk(" Intel/Sharp Extended Query Table at 0x%4.4X\n", adr);
+
+	if (!adr)
+		return;
+
+	/* Switch it into Query Mode */
+	switch(CFIDEV_BUSWIDTH) {
+	case 1:
+		map->write8(map, 0x98, 0x55);
+		break;
+	case 2:
+		map->write16(map, 0x9898, 0xaa);
+		break;
+	case 4:
+		map->write32(map, 0x98989898, 0x154);
+		break;
+	}
+
+	extp = kmalloc(sizeof(*extp), GFP_KERNEL);
+	if (!extp) {
+		printk("Failed to allocate memory\n");
+		return;
+	}
+
+	/* Read in the Extended Query Table */
+	for (i=0; i<sizeof(*extp); i++) {
+		((unsigned char *)extp)[i] = 
+		    cfi_read_query(map, (base+((adr+i)*cfi->interleave*cfi->device_type)));
+	}
+
+	if (extp->MajorVersion != '1' || 
+	    (extp->MinorVersion < '0' || extp->MinorVersion > '2')) {
+		printk("  Unknown IntelExt Extended Query version %c.%c.\n",
+		       extp->MajorVersion, extp->MinorVersion);
+		kfree(extp);
+		return;
+	}
+
+	/* Do some byteswapping if necessary */
+	extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport);
+	extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask);
+
+	
+	/* Tell the user about it in lots of lovely detail */
+#if 0  
+	printk("  Feature/Command Support: %4.4X\n", extp->FeatureSupport);
+	printk("     - Chip Erase:         %s\n", extp->FeatureSupport&1?"supported":"unsupported");
+	printk("     - Suspend Erase:      %s\n", extp->FeatureSupport&2?"supported":"unsupported");
+	printk("     - Suspend Program:    %s\n", extp->FeatureSupport&4?"supported":"unsupported");
+	printk("     - Legacy Lock/Unlock: %s\n", extp->FeatureSupport&8?"supported":"unsupported");
+	printk("     - Queued Erase:       %s\n", extp->FeatureSupport&16?"supported":"unsupported");
+	printk("     - Instant block lock: %s\n", extp->FeatureSupport&32?"supported":"unsupported");
+	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++) {
+		if (extp->FeatureSupport & (1<<i)) 
+			printk("     - Unknown Bit %X:      supported\n", i);
+	}
+	
+	printk("  Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport);
+	printk("     - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported");
+	for (i=1; i<8; i++) {
+		if (extp->SuspendCmdSupport & (1<<i))
+			printk("     - Unknown Bit %X:               supported\n", i);
+	}
+	
+	printk("  Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask);
+	printk("     - Lock Bit Active:      %s\n", extp->BlkStatusRegMask&1?"yes":"no");
+	printk("     - Valid Bit Active:     %s\n", extp->BlkStatusRegMask&2?"yes":"no");
+	for (i=2; i<16; i++) {
+		if (extp->BlkStatusRegMask & (1<<i))
+			printk("     - Unknown Bit %X Active: yes\n",i);
+	}
+	
+	printk("  Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", 
+	       extp->VccOptimal >> 8, extp->VccOptimal & 0xf);
+	if (extp->VppOptimal)
+		printk("  Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", 
+		       extp->VppOptimal >> 8, extp->VppOptimal & 0xf);
+#endif	
+	/* OK. We like it. Take over the control of it. */
+
+	/* Switch it into Read Mode */
+	switch(CFIDEV_BUSWIDTH) {
+	case 1:
+		map->write8(map, 0xff, 0x55);
+		break;
+	case 2:
+		map->write16(map, 0xffff, 0xaa);
+		break;
+	case 4:
+		map->write32(map, 0xffffffff, 0x154);
+		break;
+	}
+
+
+	/* If there was an old setup function, decrease its use count */
+	if (map->fldrv)
+	  if(map->fldrv->module)
+	    __MOD_DEC_USE_COUNT(map->fldrv->module);
+	
+	if (cfi->cmdset_priv)
+		kfree(cfi->cmdset_priv);
+
+	for (i=0; i< cfi->numchips; i++) {
+		cfi->chips[i].word_write_time = 128;
+		cfi->chips[i].buffer_write_time = 128;
+		cfi->chips[i].erase_time = 1024;
+	}		
+		
+
+	map->fldrv = &cfi_intelext_chipdrv;
+	MOD_INC_USE_COUNT;
+
+	cfi->cmdset_priv = extp;
+
+#if 1 /* Does this work? */
+	cfi_send_gen_cmd(0x90, 0x55, base, map, cfi, cfi->device_type, NULL);
+
+	cfi->mfr = cfi_read_query(map, base);
+	cfi->id = cfi_read_query(map, base + ofs_factor);
+
+	printk("JEDEC ID: %2.2X %2.2X\n", cfi->mfr, cfi->id);
+#endif
+
+        cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+	return;
+}
+
+static struct mtd_info *cfi_intelext_setup(struct map_info *map)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct mtd_info *mtd;
+	unsigned long offset = 0;
+	int i,j;
+	unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
+
+	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+	//printk("number of CFI chips: %d\n", cfi->numchips);
+
+	if (!mtd) {
+	  printk("Failed to allocate memory for MTD device\n");
+	  kfree(cfi->cmdset_priv);
+	  return NULL;
+	}
+
+	memset(mtd, 0, sizeof(*mtd));
+	mtd->priv = map;
+	mtd->type = MTD_NORFLASH;
+	mtd->size = devsize * cfi->numchips;
+
+	mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
+	mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) 
+			* mtd->numeraseregions, GFP_KERNEL);
+	if (!mtd->eraseregions) { 
+			printk("Failed to allocate memory for MTD erase region info\n");
+			kfree(cfi->cmdset_priv);
+			return NULL;
+	}
+	
+	for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
+		unsigned long ernum, ersize;
+		ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
+		ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
+
+		if (mtd->erasesize < ersize) {
+			mtd->erasesize = ersize;
+		}
+		for (j=0; j<cfi->numchips; j++) {
+			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
+			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
+			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
+		}
+		offset += (ersize * ernum);
+		}
+
+		if (offset != devsize) {
+			/* Argh */
+			printk("Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
+			kfree(mtd->eraseregions);
+			kfree(cfi->cmdset_priv);
+			return NULL;
+		}
+
+		for (i=0; i<mtd->numeraseregions;i++){
+			printk("%d: offset=0x%x,size=0x%x,blocks=%d\n",
+			       i,mtd->eraseregions[i].offset,
+			       mtd->eraseregions[i].erasesize,
+			       mtd->eraseregions[i].numblocks);
+		}
+
+	/* Also select the correct geometry setup too */ 
+		mtd->erase = cfi_intelext_erase_varsize;
+	mtd->read = cfi_intelext_read;
+	if ( cfi->cfiq->BufWriteTimeoutTyp ) {
+		//printk( KERN_INFO"Using buffer write method\n" );
+		mtd->write = cfi_intelext_write_buffers;
+	} else {
+		//printk( KERN_INFO"Using word write method\n" );
+		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;
+	map->fldrv = &cfi_intelext_chipdrv;
+	MOD_INC_USE_COUNT;
+	mtd->name = map->name;
+	return mtd;
+}
+
+
+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;
+	unsigned long timeo;
+	DECLARE_WAITQUEUE(wait, current);
+	int suspended = 0;
+	unsigned long cmd_addr;
+	struct cfi_private *cfi = map->fldrv_priv;
+
+	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);
+
+	timeo = jiffies + HZ;
+ retry:
+	spin_lock_bh(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:
+		cfi_write (map, CMD(0xb0), 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);
+				chip->state = FL_ERASING;
+				spin_unlock_bh(chip->mutex);
+				printk("Chip not ready after erase suspended\n");
+				return -EIO;
+			}
+
+			spin_unlock_bh(chip->mutex);
+			cfi_udelay(1);
+			spin_lock_bh(chip->mutex);
+		}
+
+		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:
+		break;
+
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+		cfi_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);
+			chip->state = FL_READY;
+			break;
+		}
+		
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock_bh(chip->mutex);
+			printk("waiting for chip to be ready timed out in read. WSM status = %x\n", status);
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(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);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	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);		
+	}
+
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return 0;
+}
+
+static int cfi_intelext_read (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;
+	unsigned long ofs;
+	int chipnum;
+	int ret = 0;
+
+	/* ofs: offset within the first chip that the first read should start */
+	chipnum = (from >> cfi->chipshift);
+	ofs = from - (chipnum <<  cfi->chipshift);
+
+	*retlen = 0;
+
+	while (len) {
+		unsigned long thislen;
+
+		if (chipnum >= cfi->numchips)
+			break;
+
+		if ((len + ofs -1) >> cfi->chipshift)
+			thislen = (1<<cfi->chipshift) - ofs;
+		else
+			thislen = len;
+
+		ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
+		if (ret)
+			break;
+
+		*retlen += thislen;
+		len -= thislen;
+		buf += thislen;
+		
+		ofs = 0;
+		chipnum++;
+	}
+	return ret;
+}
+
+static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	__u32 status, status_OK;
+	unsigned long timeo;
+	DECLARE_WAITQUEUE(wait, current);
+	int z;
+
+	adr += chip->start;
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+ retry:
+	spin_lock_bh(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_bh(chip->mutex);
+			printk("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_bh(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);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	cfi_write(map, CMD(0x40), adr);
+	cfi_write(map, datum, adr);
+	chip->state = FL_WRITING;
+
+	spin_unlock_bh(chip->mutex);
+	cfi_udelay(chip->word_write_time);
+	spin_lock_bh(chip->mutex);
+
+	timeo = jiffies + (HZ/2);
+	z = 0;
+	for (;;) {
+		if (chip->state != FL_WRITING) {
+			/* Someone's suspended the write. Sleep */
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			add_wait_queue(&chip->wq, &wait);
+			spin_unlock_bh(chip->mutex);
+			schedule();
+			remove_wait_queue(&chip->wq, &wait);
+			timeo = jiffies + (HZ / 2); /* FIXME */
+			spin_lock_bh(chip->mutex);
+			continue;
+		}
+
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+			chip->state = FL_STATUS;
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			printk("waiting for chip to be ready timed out in word write\n");
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		z++;
+		cfi_udelay(1);
+		spin_lock_bh(chip->mutex);
+	}
+	if (!z) {
+		chip->word_write_time--;
+		if (!chip->word_write_time)
+			chip->word_write_time++;
+	}
+	if (z > 1) 
+		chip->word_write_time++;
+
+	/* Done and happy. */
+	DISABLE_VPP(map);
+	chip->state = FL_STATUS;
+	/* check for lock bit */
+	if (status & CMD(0x02)) {
+		/* clear status */
+		cfi_write(map, CMD(0x50), adr);
+		/* put back into read status register mode */
+		cfi_write(map, CMD(0x70), adr);
+		wake_up(&chip->wq);
+		spin_unlock_bh(chip->mutex);
+		return -EROFS;
+	}
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return 0;
+}
+
+
+static int cfi_intelext_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;
+
+	*retlen = 0;
+	if (!len)
+		return 0;
+
+	chipnum = to >> cfi->chipshift;
+	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);
+		int gap = ofs - bus_ofs;
+		int i = 0, n = 0;
+		u_char tmp_buf[4];
+		__u32 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;
+
+		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 */
+		}
+
+		ret = do_write_oneword(map, &cfi->chips[chipnum],
+					       bus_ofs, datum);
+		if (ret) 
+			return ret;
+		
+		ofs += n;
+		buf += n;
+		(*retlen) += n;
+
+		if (ofs >> cfi->chipshift) {
+			chipnum ++; 
+			ofs = 0;
+			if (chipnum == cfi->numchips)
+				return 0;
+		}
+	}
+	
+	while(len >= CFIDEV_BUSWIDTH) {
+		__u32 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 {
+			return -EINVAL;
+		}
+
+		ret = do_write_oneword(map, &cfi->chips[chipnum],
+				ofs, datum);
+		if (ret)
+			return ret;
+
+		ofs += CFIDEV_BUSWIDTH;
+		buf += CFIDEV_BUSWIDTH;
+		(*retlen) += CFIDEV_BUSWIDTH;
+		len -= CFIDEV_BUSWIDTH;
+
+		if (ofs >> cfi->chipshift) {
+			chipnum ++; 
+			ofs = 0;
+			if (chipnum == cfi->numchips)
+				return 0;
+		}
+	}
+
+	if (len & (CFIDEV_BUSWIDTH-1)) {
+		int i = 0, n = 0;
+		u_char tmp_buf[4];
+		__u32 datum;
+
+		while (len--)
+			tmp_buf[i++] = buf[n++];
+		while (i < CFIDEV_BUSWIDTH)
+			tmp_buf[i++] = 0xff;
+
+		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 */
+		}
+
+		ret = do_write_oneword(map, &cfi->chips[chipnum],
+					       ofs, datum);
+		if (ret) 
+			return ret;
+		
+		(*retlen) += n;
+	}
+
+	return 0;
+}
+
+
+static inline int 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;
+	__u32 status, status_OK;
+	unsigned long cmd_adr, timeo;
+	DECLARE_WAITQUEUE(wait, current);
+	int wbufsize, z;
+
+	wbufsize = CFIDEV_INTERLEAVE << 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_bh(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), 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_bh(chip->mutex);
+			printk("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_bh(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);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	cfi_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)
+			break;
+
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		spin_lock_bh(chip->mutex);
+
+		if (++z > 20) {
+			/* Argh. Not ready for write to buffer */
+			cfi_write(map, CMD(0x70), cmd_adr);
+			chip->state = FL_STATUS;
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			printk("Chip not ready for buffer write. Xstatus = %x, status = %x\n", status, cfi_read(map, cmd_adr));
+			return -EIO;
+		}
+	}
+
+	/* Write length of data to come */
+	cfi_write(map, CMD(len/CFIDEV_BUSWIDTH-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;
+		}
+	}
+	/* GO GO GO */
+	cfi_write(map, CMD(0xd0), cmd_adr);
+	chip->state = FL_WRITING;
+
+	spin_unlock_bh(chip->mutex);
+	cfi_udelay(chip->buffer_write_time);
+	spin_lock_bh(chip->mutex);
+
+	timeo = jiffies + (HZ/2);
+	z = 0;
+	for (;;) {
+		if (chip->state != FL_WRITING) {
+			/* Someone's suspended the write. Sleep */
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			add_wait_queue(&chip->wq, &wait);
+			spin_unlock_bh(chip->mutex);
+			schedule();
+			remove_wait_queue(&chip->wq, &wait);
+			timeo = jiffies + (HZ / 2); /* FIXME */
+			spin_lock_bh(chip->mutex);
+			continue;
+		}
+
+		status = cfi_read(map, cmd_adr);
+		if ((status & status_OK) == status_OK)
+			break;
+
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+			chip->state = FL_STATUS;
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			printk("waiting for chip to be ready timed out in bufwrite\n");
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		z++;
+		spin_lock_bh(chip->mutex);
+	}
+	if (!z) {
+		chip->buffer_write_time--;
+		if (!chip->buffer_write_time)
+			chip->buffer_write_time++;
+	}
+	if (z > 1) 
+		chip->buffer_write_time++;
+
+	/* Done and happy. */
+	DISABLE_VPP(map);
+	chip->state = FL_STATUS;
+	/* check for lock bit */
+	if (status & CMD(0x02)) {
+		/* clear status */
+		cfi_write(map, CMD(0x50), cmd_adr);
+		/* put back into read status register mode */
+		cfi_write(map, CMD(0x70), adr);
+		wake_up(&chip->wq);
+		spin_unlock_bh(chip->mutex);
+		return -EROFS;
+	}
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return 0;
+}
+
+static int cfi_intelext_write_buffers (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 wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
+	int ret = 0;
+	int chipnum;
+	unsigned long ofs;
+
+	*retlen = 0;
+	if (!len)
+		return 0;
+
+	chipnum = to >> cfi->chipshift;
+	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 (local_len > len)
+			local_len = len;
+		ret = cfi_intelext_write_words(mtd, to, local_len,
+					       retlen, buf);
+		if (ret)
+			return ret;
+		ofs += local_len;
+		buf += local_len;
+		len -= local_len;
+
+		if (ofs >> cfi->chipshift) {
+			chipnum ++;
+			ofs = 0;
+			if (chipnum == cfi->numchips)
+				return 0;
+		}
+	}
+
+	/* Write buffer is worth it only if more than one word to write... */
+	while(len > CFIDEV_BUSWIDTH) {
+		/* We must not cross write block boundaries */
+		int size = wbufsize - (ofs & (wbufsize-1));
+
+		if (size > len)
+			size = len & ~(CFIDEV_BUSWIDTH-1);
+		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;
+		}
+	}
+
+	/* ... 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;
+}
+
+
+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;
+	unsigned long timeo;
+	int retries = 3;
+	DECLARE_WAITQUEUE(wait, current);
+	int 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_bh(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_bh(chip->mutex);
+			printk("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_bh(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);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	/* Clear the status register first */
+	cfi_write(map, CMD(0x50), adr);
+
+	/* Now erase */
+	cfi_write(map, CMD(0x20), adr);
+	cfi_write(map, CMD(0xD0), adr);
+	chip->state = FL_ERASING;
+	
+	spin_unlock_bh(chip->mutex);
+	schedule_timeout(HZ);
+	spin_lock_bh(chip->mutex);
+
+	/* FIXME. Use a timer to check this, and return immediately. */
+	/* Once the state machine's known to be working I'll do that */
+
+	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);
+			spin_unlock_bh(chip->mutex);
+			schedule();
+			remove_wait_queue(&chip->wq, &wait);
+			timeo = jiffies + (HZ*2); /* FIXME */
+			spin_lock_bh(chip->mutex);
+			continue;
+		}
+
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+			cfi_write(map, CMD(0x70), adr);
+			chip->state = FL_STATUS;
+			printk("waiting for erase to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		spin_lock_bh(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);
+	chip->state = FL_STATUS;
+	status = cfi_read(map, adr);
+
+	/* check for lock bit */
+	if (status & CMD(0x3a)) {
+		unsigned char chipstatus = status;
+		if (status != CMD(status & 0xff)) {
+			int i;
+			for (i = 1; i<CFIDEV_INTERLEAVE; i++) {
+				      chipstatus |= status >> (cfi->device_type * 8);
+			}
+			printk(KERN_WARNING "Status is not identical for all chips: 0x%x. Merging to give 0x%02x\n", status, chipstatus);
+		}
+		/* Reset the error bits */
+		cfi_write(map, CMD(0x50), adr);
+		cfi_write(map, CMD(0x70), adr);
+		
+		if ((chipstatus & 0x30) == 0x30) {
+			printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", status);
+			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);
+			ret = -EIO;
+		} else if (chipstatus & 0x20) {
+			if (retries--) {
+				printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, status);
+				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);
+			ret = -EIO;
+		}
+	}
+
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return ret;
+}
+
+int cfi_intelext_erase_varsize(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;
+	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.
+	 */
+
+	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 && instr->addr >= 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 (instr->addr & (regions[i].erasesize-1))
+		return -EINVAL;
+
+	/* Remember the erase region we start on */
+	first = i;
+
+	/* Next, check that the end of the requested erase is aligned
+	 * with the erase region at that address.
+	 */
+
+	while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset)
+		i++;
+
+	/* As before, drop back one to point at the region in which
+	   the address actually falls
+	*/
+	i--;
+	
+	if ((instr->addr + instr->len) & (regions[i].erasesize-1))
+		return -EINVAL;
+
+	chipnum = instr->addr >> cfi->chipshift;
+	adr = instr->addr - (chipnum << cfi->chipshift);
+	len = instr->len;
+
+	i=first;
+
+	while(len) {
+		ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
+		
+		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;
+		}
+	}
+		
+	instr->state = MTD_ERASE_DONE;
+	if (instr->callback)
+		instr->callback(instr);
+	
+	return 0;
+}
+
+static void cfi_intelext_sync (struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+	int ret = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	for (i=0; !ret && i<cfi->numchips; i++) {
+		chip = &cfi->chips[i];
+
+	retry:
+		spin_lock_bh(chip->mutex);
+
+		switch(chip->state) {
+		case FL_READY:
+		case FL_STATUS:
+		case FL_CFI_QUERY:
+		case FL_JEDEC_QUERY:
+			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_bh(chip->mutex);
+			break;
+
+		default:
+			/* Not an idle state */
+			add_wait_queue(&chip->wq, &wait);
+			
+			spin_unlock_bh(chip->mutex);
+			schedule();
+		        remove_wait_queue(&chip->wq, &wait);
+			
+			goto retry;
+		}
+	}
+
+	/* Unlock the chips again */
+
+	for (i--; i >=0; i--) {
+		chip = &cfi->chips[i];
+
+		spin_lock_bh(chip->mutex);
+		
+		if (chip->state == FL_SYNCING) {
+			chip->state = chip->oldstate;
+			wake_up(&chip->wq);
+		}
+		spin_unlock_bh(chip->mutex);
+	}
+}
+
+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;
+	unsigned long timeo = jiffies + HZ;
+	DECLARE_WAITQUEUE(wait, current);
+
+	adr += chip->start;
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+retry:
+	spin_lock_bh(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_bh(chip->mutex);
+			printk("waiting for chip to be ready timed out in lock\n");
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(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);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	cfi_write(map, CMD(0x60), adr);
+	cfi_write(map, CMD(0x01), adr);
+	chip->state = FL_LOCKING;
+	
+	spin_unlock_bh(chip->mutex);
+	schedule_timeout(HZ);
+	spin_lock_bh(chip->mutex);
+
+	/* FIXME. Use a timer to check this, and return immediately. */
+	/* Once the state machine's known to be working I'll do that */
+
+	timeo = jiffies + (HZ*2);
+	for (;;) {
+
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+			cfi_write(map, CMD(0x70), adr);
+			chip->state = FL_STATUS;
+			printk("waiting for lock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		spin_lock_bh(chip->mutex);
+	}
+	
+	/* Done and happy. */
+	chip->state = FL_STATUS;
+	DISABLE_VPP(map);
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return 0;
+}
+static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long adr;
+	int chipnum, ret = 0;
+#ifdef DEBUG_LOCK_BITS
+	int ofs_factor = cfi->interleave * cfi->device_type;
+#endif
+
+	if (ofs & (mtd->erasesize - 1))
+		return -EINVAL;
+
+	if (len & (mtd->erasesize -1))
+		return -EINVAL;
+
+	if ((len + ofs) > mtd->size)
+		return -EINVAL;
+
+	chipnum = ofs >> cfi->chipshift;
+	adr = ofs - (chipnum << cfi->chipshift);
+
+	while(len) {
+
+#ifdef DEBUG_LOCK_BITS
+		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+		printk("before lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
+		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+#endif
+
+		ret = do_lock_oneblock(map, &cfi->chips[chipnum], adr);
+
+#ifdef DEBUG_LOCK_BITS
+		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+		printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
+		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+#endif	
+		
+		if (ret)
+			return ret;
+
+		adr += mtd->erasesize;
+		len -= mtd->erasesize;
+
+		if (adr >> cfi->chipshift) {
+			adr = 0;
+			chipnum++;
+			
+			if (chipnum >= cfi->numchips)
+			break;
+		}
+	}
+	return 0;
+}
+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;
+	unsigned long timeo = jiffies + HZ;
+	DECLARE_WAITQUEUE(wait, current);
+
+	adr += chip->start;
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+retry:
+	spin_lock_bh(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_bh(chip->mutex);
+			printk("waiting for chip to be ready timed out in unlock\n");
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(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);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	cfi_write(map, CMD(0x60), adr);
+	cfi_write(map, CMD(0xD0), adr);
+	chip->state = FL_UNLOCKING;
+	
+	spin_unlock_bh(chip->mutex);
+	schedule_timeout(HZ);
+	spin_lock_bh(chip->mutex);
+
+	/* FIXME. Use a timer to check this, and return immediately. */
+	/* Once the state machine's known to be working I'll do that */
+
+	timeo = jiffies + (HZ*2);
+	for (;;) {
+
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+			cfi_write(map, CMD(0x70), adr);
+			chip->state = FL_STATUS;
+			printk("waiting for unlock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the unlock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		spin_lock_bh(chip->mutex);
+	}
+	
+	/* Done and happy. */
+	chip->state = FL_STATUS;
+	DISABLE_VPP(map);
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return 0;
+}
+static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long adr;
+	int chipnum, ret = 0;
+#ifdef DEBUG_LOCK_BITS
+	int ofs_factor = cfi->interleave * cfi->device_type;
+#endif
+
+	chipnum = ofs >> cfi->chipshift;
+	adr = ofs - (chipnum << cfi->chipshift);
+
+#ifdef DEBUG_LOCK_BITS
+	{
+		unsigned long temp_adr = adr;
+		unsigned long temp_len = len;
+                 
+		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+                while (temp_len) {
+			printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor)));
+			temp_adr += mtd->erasesize;
+			temp_len -= mtd->erasesize;
+		}
+		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+	}
+#endif
+
+	ret = do_unlock_oneblock(map, &cfi->chips[chipnum], adr);
+
+#ifdef DEBUG_LOCK_BITS
+	cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+	printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
+	cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+#endif
+	
+	return ret;
+}
+
+static int cfi_intelext_suspend(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+	int ret = 0;
+
+	for (i=0; !ret && i<cfi->numchips; i++) {
+		chip = &cfi->chips[i];
+
+		spin_lock_bh(chip->mutex);
+
+		switch(chip->state) {
+		case FL_READY:
+		case FL_STATUS:
+		case FL_CFI_QUERY:
+		case FL_JEDEC_QUERY:
+			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:
+			break;
+
+		default:
+			ret = -EAGAIN;
+			break;
+		}
+		spin_unlock_bh(chip->mutex);
+	}
+
+	/* Unlock the chips again */
+
+	if (ret) {
+		for (i--; i >=0; i--) {
+			chip = &cfi->chips[i];
+			
+			spin_lock_bh(chip->mutex);
+			
+			if (chip->state == FL_PM_SUSPENDED) {
+				chip->state = chip->oldstate;
+				wake_up(&chip->wq);
+			}
+			spin_unlock_bh(chip->mutex);
+		}
+	} 
+	
+	return ret;
+}
+
+static void cfi_intelext_resume(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+
+	for (i=0; i<cfi->numchips; i++) {
+	
+		chip = &cfi->chips[i];
+
+		spin_lock_bh(chip->mutex);
+		
+		if (chip->state == FL_PM_SUSPENDED) {
+			/* We need to force it back to a known state. */
+			cfi_write(map, CMD(0xff), 0);
+			chip->state = FL_READY;
+			wake_up(&chip->wq);
+		}
+
+		spin_unlock_bh(chip->mutex);
+	}
+}
+
+static void cfi_intelext_destroy(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	kfree(cfi->cmdset_priv);
+	kfree(cfi);
+}
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define cfi_intelext_init init_module
+#define cfi_intelext_exit cleanup_module
+#endif
+
+static char im_name_1[]="cfi_cmdset_0001";
+static char im_name_3[]="cfi_cmdset_0003";
+
+
+mod_init_t 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);
+	return 0;
+}
+
+mod_exit_t cfi_intelext_exit(void)
+{
+	inter_module_unregister(im_name_1);
+	inter_module_unregister(im_name_3);
+}
+
+module_init(cfi_intelext_init);
+module_exit(cfi_intelext_exit);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/chips/cfi_cmdset_0002.c linux/drivers/mtd/chips/cfi_cmdset_0002.c
--- v2.4.5/linux/drivers/mtd/chips/cfi_cmdset_0002.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/chips/cfi_cmdset_0002.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,936 @@
+/*
+ * Common Flash Interface support:
+ *   AMD & Fujitsu Standard Vendor Command Set (ID 0x0002)
+ *
+ * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp>
+ *
+ * 2_by_8 routines added by Simon Munton
+ *
+ * This code is GPL
+ *
+ * $Id: cfi_cmdset_0002.c,v 1.48 2001/06/03 01:32:57 nico Exp $
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+
+#define AMD_BOOTLOC_BUG
+
+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_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 *);
+static void cfi_amdstd_resume (struct mtd_info *);
+
+static void cfi_amdstd_destroy(struct mtd_info *);
+
+void cfi_cmdset_0002(struct map_info *, int, unsigned long);
+static struct mtd_info *cfi_amdstd_setup (struct map_info *);
+
+
+static struct mtd_chip_driver cfi_amdstd_chipdrv = {
+	probe: cfi_amdstd_setup,
+	destroy: cfi_amdstd_destroy,
+	name: "cfi_cmdset_0002",
+	module: THIS_MODULE
+};
+
+void cfi_cmdset_0002(struct map_info *map, int primary, unsigned long base)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned char bootloc;
+	int ofs_factor = cfi->interleave * cfi->device_type;
+	int i;
+	__u8 major, minor;
+//	struct cfi_pri_intelext *extp;
+
+    if (cfi->cfi_mode==0){
+	__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
+
+	cfi_send_gen_cmd(0x98, 0x55, 0, map, cfi, cfi->device_type, NULL);
+
+	major = cfi_read_query(map, (adr+3)*ofs_factor);
+	minor = cfi_read_query(map, (adr+4)*ofs_factor);
+
+	printk(" Amd/Fujitsu Extended Query Table v%c.%c at 0x%4.4X\n",
+	       major, minor, adr);
+
+	cfi_send_gen_cmd(0xf0, 0x55, 0, 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);
+
+	/* Wheee. Bring me the head of someone at AMD. */
+#ifdef AMD_BOOTLOC_BUG
+	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 */
+		} else {
+			bootloc = 2;	/* bottom boot */
+		}
+	} else
+#endif
+	{
+		cfi_send_gen_cmd(0x98, 0x55, 0, map, cfi, cfi->device_type, NULL);
+		bootloc = cfi_read_query(map, (adr+15)*ofs_factor);
+	}
+	if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) {
+		printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name);
+
+		for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) {
+			int j = (cfi->cfiq->NumEraseRegions-1)-i;
+			__u32 swap;
+
+			swap = cfi->cfiq->EraseRegionInfo[i];
+			cfi->cfiq->EraseRegionInfo[i] = cfi->cfiq->EraseRegionInfo[j];
+			cfi->cfiq->EraseRegionInfo[j] = swap;
+		}
+	}
+    }
+
+    /* If there was an old setup function, decrease its use count */
+    if (map->fldrv)
+      if(map->fldrv->module)
+	__MOD_DEC_USE_COUNT(map->fldrv->module);
+    
+    if (cfi->cmdset_priv)
+		kfree(cfi->cmdset_priv);
+
+    for (i=0; i< cfi->numchips; i++) {
+		cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
+		cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
+		cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
+    }		
+
+    map->fldrv = &cfi_amdstd_chipdrv;
+    MOD_INC_USE_COUNT;
+    cfi_send_gen_cmd(0xf0, 0x55, 0, map, cfi, cfi->device_type, NULL);
+    return;
+}
+
+static struct mtd_info *cfi_amdstd_setup(struct map_info *map)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct mtd_info *mtd;
+	unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
+
+	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+	printk("number of %s chips: %d\n", (cfi->cfi_mode)?"JEDEC":"CFI",cfi->numchips);
+
+	if (!mtd) {
+	  printk("Failed to allocate memory for MTD device\n");
+	  kfree(cfi->cmdset_priv);
+	  return NULL;
+	}
+
+	memset(mtd, 0, sizeof(*mtd));
+	mtd->priv = map;
+	mtd->type = MTD_NORFLASH;
+	/* Also select the correct geometry setup too */ 
+	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);
+		if (!mtd->eraseregions) { 
+			printk("Failed to allocate memory for MTD erase region info\n");
+			kfree(cfi->cmdset_priv);
+			return NULL;
+		}
+			
+		for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
+			unsigned long ernum, ersize;
+			ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
+			ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
+			
+			if (mtd->erasesize < ersize) {
+				mtd->erasesize = ersize;
+			}
+			for (j=0; j<cfi->numchips; j++) {
+				mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
+				mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
+				mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
+			}
+			offset += (ersize * ernum);
+		}
+		if (offset != devsize) {
+			/* Argh */
+			printk("Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
+			kfree(mtd->eraseregions);
+			kfree(cfi->cmdset_priv);
+			return NULL;
+		}
+		// debug
+		for (i=0; i<mtd->numeraseregions;i++){
+			printk("%d: offset=0x%x,size=0x%x,blocks=%d\n",
+			       i,mtd->eraseregions[i].offset,
+			       mtd->eraseregions[i].erasesize,
+			       mtd->eraseregions[i].numblocks);
+		}
+	}
+
+	switch (CFIDEV_BUSWIDTH)
+	{
+	case 1:
+	case 2:
+	case 4:
+#if 1
+		if (mtd->numeraseregions > 1)
+			mtd->erase = cfi_amdstd_erase_varsize;
+		else
+#endif
+			mtd->erase = cfi_amdstd_erase_onesize;
+		mtd->read = cfi_amdstd_read;
+		mtd->write = cfi_amdstd_write;
+		break;
+
+	default:
+	        printk("Unsupported buswidth\n");
+		kfree(mtd);
+		kfree(cfi->cmdset_priv);
+		return NULL;
+		break;
+	}
+	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;
+	return mtd;
+}
+
+static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long timeo = jiffies + HZ;
+
+ retry:
+	cfi_spin_lock(chip->mutex);
+
+	if (chip->state != FL_READY){
+	        printk("Waiting for chip to read, status = %d\n", chip->state);
+		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;
+
+		goto retry;
+	}	
+
+	adr += chip->start;
+
+	chip->state = FL_READY;
+
+	map->copy_from(map, buf, adr, len);
+
+	wake_up(&chip->wq);
+	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;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long ofs;
+	int chipnum;
+	int ret = 0;
+
+	/* ofs: offset within the first chip that the first read should start */
+
+	chipnum = (from >> cfi->chipshift);
+	ofs = from - (chipnum <<  cfi->chipshift);
+
+
+	*retlen = 0;
+
+	while (len) {
+		unsigned long thislen;
+
+		if (chipnum >= cfi->numchips)
+			break;
+
+		if ((len + ofs -1) >> cfi->chipshift)
+			thislen = (1<<cfi->chipshift) - ofs;
+		else
+			thislen = len;
+
+		ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
+		if (ret)
+			break;
+
+		*retlen += thislen;
+		len -= thislen;
+		buf += thislen;
+
+		ofs = 0;
+		chipnum++;
+	}
+	return ret;
+}
+
+static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum, int fast)
+{
+	unsigned long timeo = jiffies + HZ;
+	unsigned int Last[4];
+	unsigned long Count = 0;
+	struct cfi_private *cfi = map->fldrv_priv;
+	DECLARE_WAITQUEUE(wait, current);
+	int ret = 0;
+
+ retry:
+	cfi_spin_lock(chip->mutex);
+
+	if (chip->state != FL_READY){
+	        printk("Waiting for chip to write, status = %d\n", chip->state);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+                
+		cfi_spin_unlock(chip->mutex);
+
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		printk("Wake up to write:\n");
+#if 0
+		if(signal_pending(current))
+			return -EINTR;
+#endif
+		timeo = jiffies + HZ;
+
+		goto retry;
+	}	
+
+	chip->state = FL_WRITING;
+
+	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);
+	}
+
+	cfi_write(map, datum, adr);
+
+	cfi_spin_unlock(chip->mutex);
+	cfi_udelay(chip->word_write_time);
+	cfi_spin_lock(chip->mutex);
+
+	Last[0] = cfi_read(map, adr);
+	//	printk("Last[0] is %x\n", Last[0]);
+	Last[1] = cfi_read(map, adr);
+	//	printk("Last[1] is %x\n", Last[1]);
+	Last[2] = cfi_read(map, adr);
+	//	printk("Last[2] is %x\n", Last[2]);
+
+	for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && Count < 10000; Count++){
+		cfi_spin_unlock(chip->mutex);
+		cfi_udelay(10);
+		cfi_spin_lock(chip->mutex);
+		
+	        Last[Count % 4] = cfi_read(map, adr);
+		//		printk("Last[%d%%4] is %x\n", Count, Last[Count%4]);
+	}
+	
+	if (Last[(Count - 1) % 4] != datum){
+		printk("Last[%ld] is %x, datum is %x\n",(Count - 1) % 4,Last[(Count - 1) % 4],datum);
+	        cfi_send_gen_cmd(0xF0, 0, chip->start, map, cfi, cfi->device_type, NULL);
+		DISABLE_VPP(map);
+		ret = -EIO;
+	}       
+	DISABLE_VPP(map);
+	chip->state = FL_READY;
+	wake_up(&chip->wq);
+	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)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int ret = 0;
+	int chipnum;
+	unsigned long ofs, chipstart;
+
+	*retlen = 0;
+	if (!len)
+		return 0;
+
+	chipnum = to >> cfi->chipshift;
+	ofs = to  - (chipnum << cfi->chipshift);
+	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);
+		int i = ofs - bus_ofs;
+		int n = 0;
+		u_char tmp_buf[4];
+		__u32 datum;
+
+		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--;
+
+		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 */
+		}
+
+		ret = do_write_oneword(map, &cfi->chips[chipnum], 
+				bus_ofs, datum, 0);
+		if (ret) 
+			return ret;
+		
+		ofs += n;
+		buf += n;
+		(*retlen) += n;
+
+		if (ofs >> cfi->chipshift) {
+			chipnum ++; 
+			ofs = 0;
+			if (chipnum == cfi->numchips)
+				return 0;
+		}
+	}
+	
+	/* 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;
+
+		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);
+			}
+			return ret;
+		}
+
+		ofs += CFIDEV_BUSWIDTH;
+		buf += CFIDEV_BUSWIDTH;
+		(*retlen) += CFIDEV_BUSWIDTH;
+		len -= CFIDEV_BUSWIDTH;
+
+		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);
+	}
+
+	if (len & (CFIDEV_BUSWIDTH-1)) {
+		int i = 0, n = 0;
+		u_char tmp_buf[4];
+		__u32 datum;
+
+		map->copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
+		while (len--)
+			tmp_buf[i++] = buf[n++];
+
+		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 */
+		}
+
+		ret = do_write_oneword(map, &cfi->chips[chipnum], 
+				ofs, datum, 0);
+		if (ret) 
+			return ret;
+		
+		(*retlen) += n;
+	}
+
+	return 0;
+}
+
+static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+	unsigned int status;
+	unsigned long timeo = jiffies + HZ;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned int rdy_mask;
+	DECLARE_WAITQUEUE(wait, current);
+
+ retry:
+	cfi_spin_lock(chip->mutex);
+
+	if (chip->state != FL_READY){
+		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;
+
+		goto retry;
+	}	
+
+	chip->state = FL_ERASING;
+
+	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);
+	
+	timeo = jiffies + (HZ*20);
+
+	cfi_spin_unlock(chip->mutex);
+	schedule_timeout(HZ);
+	cfi_spin_lock(chip->mutex);
+	
+	rdy_mask = CMD(0x80);
+
+	/* FIXME. Use a timer to check this, and return immediately. */
+	/* Once the state machine's known to be working I'll do that */
+
+	while ( ( (status = cfi_read(map,adr)) & rdy_mask ) != rdy_mask ) {
+		static int z=0;
+
+		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("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;
+		}
+
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+			chip->state = FL_READY;
+			cfi_spin_unlock(chip->mutex);
+			printk("waiting for erase to complete timed out.");
+			DISABLE_VPP(map);
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the lock, wait a while and retry */
+		cfi_spin_unlock(chip->mutex);
+
+		z++;
+		if ( 0 && !(z % 100 )) 
+			printk("chip not ready yet after erase. looping\n");
+
+		cfi_udelay(1);
+		
+		cfi_spin_lock(chip->mutex);
+		continue;
+	}
+	
+	/* Done and happy. */
+	DISABLE_VPP(map);
+	chip->state = FL_READY;
+	wake_up(&chip->wq);
+	cfi_spin_unlock(chip->mutex);
+	return 0;
+}
+
+static int cfi_amdstd_erase_varsize(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;
+	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.
+	 */
+
+	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 && instr->addr >= 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 (instr->addr & (regions[i].erasesize-1))
+		return -EINVAL;
+
+	/* Remember the erase region we start on */
+	first = i;
+
+	/* Next, check that the end of the requested erase is aligned
+	 * with the erase region at that address.
+	 */
+
+	while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset)
+		i++;
+
+	/* As before, drop back one to point at the region in which
+	   the address actually falls
+	*/
+	i--;
+	
+	if ((instr->addr + instr->len) & (regions[i].erasesize-1))
+		return -EINVAL;
+	
+	chipnum = instr->addr >> cfi->chipshift;
+	adr = instr->addr - (chipnum << cfi->chipshift);
+	len = instr->len;
+
+	i=first;
+
+	while(len) {
+		ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
+
+		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;
+		}
+	}
+
+	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;
+
+	chipnum = instr->addr >> cfi->chipshift;
+	adr = instr->addr - (chipnum << cfi->chipshift);
+	len = instr->len;
+
+	while(len) {
+		ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
+
+		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);
+	
+	return 0;
+}
+
+static void cfi_amdstd_sync (struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+	int ret = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	for (i=0; !ret && i<cfi->numchips; i++) {
+		chip = &cfi->chips[i];
+
+	retry:
+		cfi_spin_lock(chip->mutex);
+
+		switch(chip->state) {
+		case FL_READY:
+		case FL_STATUS:
+		case FL_CFI_QUERY:
+		case FL_JEDEC_QUERY:
+			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:
+			cfi_spin_unlock(chip->mutex);
+			break;
+
+		default:
+			/* Not an idle state */
+			add_wait_queue(&chip->wq, &wait);
+			
+			cfi_spin_unlock(chip->mutex);
+
+			schedule();
+
+		        remove_wait_queue(&chip->wq, &wait);
+			
+			goto retry;
+		}
+	}
+
+	/* Unlock the chips again */
+
+	for (i--; i >=0; i--) {
+		chip = &cfi->chips[i];
+
+		cfi_spin_lock(chip->mutex);
+		
+		if (chip->state == FL_SYNCING) {
+			chip->state = chip->oldstate;
+			wake_up(&chip->wq);
+		}
+		cfi_spin_unlock(chip->mutex);
+	}
+}
+
+
+static int cfi_amdstd_suspend(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+	int ret = 0;
+//printk("suspend\n");
+
+	for (i=0; !ret && i<cfi->numchips; i++) {
+		chip = &cfi->chips[i];
+
+		cfi_spin_lock(chip->mutex);
+
+		switch(chip->state) {
+		case FL_READY:
+		case FL_STATUS:
+		case FL_CFI_QUERY:
+		case FL_JEDEC_QUERY:
+			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:
+			break;
+
+		default:
+			ret = -EAGAIN;
+			break;
+		}
+		cfi_spin_unlock(chip->mutex);
+	}
+
+	/* Unlock the chips again */
+
+	if (ret) {
+    		for (i--; i >=0; i--) {
+			chip = &cfi->chips[i];
+
+			cfi_spin_lock(chip->mutex);
+		
+			if (chip->state == FL_PM_SUSPENDED) {
+				chip->state = chip->oldstate;
+				wake_up(&chip->wq);
+			}
+			cfi_spin_unlock(chip->mutex);
+		}
+	}
+	
+	return ret;
+}
+
+static void cfi_amdstd_resume(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+//printk("resume\n");
+
+	for (i=0; i<cfi->numchips; i++) {
+	
+		chip = &cfi->chips[i];
+
+		cfi_spin_lock(chip->mutex);
+		
+		if (chip->state == FL_PM_SUSPENDED) {
+			chip->state = FL_READY;
+			cfi_write(map, CMD(0xF0), chip->start);
+			wake_up(&chip->wq);
+		}
+		else
+			printk("Argh. Chip not in PM_SUSPENDED state upon resume()\n");
+
+		cfi_spin_unlock(chip->mutex);
+	}
+}
+
+static void cfi_amdstd_destroy(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	kfree(cfi->cmdset_priv);
+	kfree(cfi);
+}
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define cfi_amdstd_init init_module
+#define cfi_amdstd_exit cleanup_module
+#endif
+
+static char im_name[]="cfi_cmdset_0002";
+
+mod_init_t cfi_amdstd_init(void)
+{
+	inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0002);
+	return 0;
+}
+
+mod_exit_t cfi_amdstd_exit(void)
+{
+	inter_module_unregister(im_name);
+}
+
+module_init(cfi_amdstd_init);
+module_exit(cfi_amdstd_exit);
+
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/chips/cfi_jedec.c linux/drivers/mtd/chips/cfi_jedec.c
--- v2.4.5/linux/drivers/mtd/chips/cfi_jedec.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/chips/cfi_jedec.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,289 @@
+/* $Id: cfi_jedec.c,v 1.5 2001/06/02 14:52:23 dwmw2 Exp $ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+
+/* Manufacturers */
+#define MANUFACTURER_AMD	0x0001
+#define MANUFACTURER_FUJITSU	0x0004
+#define MANUFACTURER_ATMEL	0x001f
+#define MANUFACTURER_ST		0x0020
+#define MANUFACTURER_SST	0x00BF
+#define MANUFACTURER_TOSHIBA	0x0098
+
+/* AMD */
+#define AM29F800BB	0x2258
+#define AM29F800BT	0x22D6
+#define AM29LV800BB	0x225B
+#define AM29LV800BT	0x22DA
+#define AM29LV160DT	0x22C4
+#define AM29LV160DB	0x2249
+
+/* Atmel */
+#define AT49BV16X4	0x00c0
+#define AT49BV16X4T	0x00c2
+
+/* Fujitsu */
+#define MBM29LV160TE	0x22C4
+#define MBM29LV160BE	0x2249
+
+/* ST - www.st.com */
+#define M29W800T	0x00D7
+#define M29W160DT	0x22C4
+#define M29W160DB	0x2249
+
+/* SST */
+#define SST39LF800	0x2781
+#define SST39LF160	0x2782
+
+/* Toshiba */
+#define TC58FVT160	0x00C2
+#define TC58FVB160	0x0043
+
+
+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 ulong regions[4];
+};
+
+#define ERASEINFO(size,blocks) (size<<8)|(blocks-1)
+
+#define SIZE_1MiB 20
+#define SIZE_2MiB 21
+#define SIZE_4MiB 22
+
+static const struct amd_flash_info jedec_table[] = {
+	{
+		mfr_id: MANUFACTURER_AMD,
+		dev_id: AM29LV160DT,
+		name: "AMD AM29LV160DT",
+		DevSize: SIZE_2MiB,
+		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,
+		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,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x10000,31),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x04000,1)
+		}
+	}, {
+		mfr_id: MANUFACTURER_FUJITSU,
+		dev_id: MBM29LV160TE,
+		name: "Fujitsu MBM29LV160TE",
+		DevSize: SIZE_2MiB,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x10000,31),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x04000,1)
+		}
+	}, {
+		mfr_id: MANUFACTURER_TOSHIBA,
+		dev_id: TC58FVB160,
+		name: "Toshiba TC58FVB160",
+		DevSize: SIZE_2MiB,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x04000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x10000,31)
+		}
+	}, {
+		mfr_id: MANUFACTURER_FUJITSU,
+		dev_id: MBM29LV160BE,
+		name: "Fujitsu MBM29LV160BE",
+		DevSize: SIZE_2MiB,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x04000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x10000,31)
+		}
+	}, {
+		mfr_id: MANUFACTURER_AMD,
+		dev_id: AM29LV800BB,
+		name: "AMD AM29LV800BB",
+		DevSize: SIZE_1MiB,
+		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,
+		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,
+		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",
+		DevSize: SIZE_1MiB,
+		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,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x10000,15),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x04000,1)
+		}
+	}, {
+		mfr_id: MANUFACTURER_ST,
+		dev_id: M29W800T,
+		name: "ST M29W800T",
+		DevSize: SIZE_1MiB,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x10000,15),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x04000,1)
+		}
+	}, {
+		mfr_id: MANUFACTURER_ST,
+		dev_id: M29W160DT,
+		name: "ST M29W160DT",
+		DevSize: SIZE_2MiB,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x10000,31),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x04000,1)
+		}
+	}, {
+		mfr_id: MANUFACTURER_ST,
+		dev_id: M29W160DB,
+		name: "ST M29W160DB",
+		DevSize: SIZE_2MiB,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x04000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x10000,31)
+		}
+	}, {
+		mfr_id: MANUFACTURER_ATMEL,
+		dev_id: AT49BV16X4,
+		name: "Atmel AT49BV16X4",
+		DevSize: SIZE_2MiB,
+		NumEraseRegions: 3,
+		regions: {ERASEINFO(0x02000,8),
+			  ERASEINFO(0x08000,2),
+			  ERASEINFO(0x10000,30)
+		}
+	}, {
+                mfr_id: MANUFACTURER_ATMEL,
+                dev_id: AT49BV16X4T,
+                name: "Atmel AT49BV16X4T",
+                DevSize: SIZE_2MiB,
+                NumEraseRegions: 3,
+                regions: {ERASEINFO(0x10000,30),
+                          ERASEINFO(0x08000,2),
+			  ERASEINFO(0x02000,8)
+                }
+        }, {
+		0
+	} 
+};
+
+int cfi_jedec_lookup(int index, int mfr_id, int dev_id)
+{
+  	if (index>=0){
+		if (jedec_table[index].mfr_id == mfr_id &&
+		    jedec_table[index].dev_id == dev_id) return index;
+  	}
+  	else{
+		for (index=0; jedec_table[index].mfr_id; index++){
+		    if (jedec_table[index].mfr_id == mfr_id &&
+		        jedec_table[index].dev_id == dev_id) return index;
+		}
+  	}
+	return -1;
+}
+
+int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
+{
+int i,num_erase_regions;
+
+	printk("Found: %s\n",jedec_table[index].name);
+
+	num_erase_regions = jedec_table[index].NumEraseRegions;
+	
+	p_cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL);
+	if (!p_cfi->cfiq) {
+		//xx printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name);
+		return -1;
+	}
+
+	memset(p_cfi->cfiq,0,sizeof(struct cfi_ident));	
+	
+	p_cfi->cfiq->P_ID = P_ID_AMD_STD;
+	p_cfi->cfiq->NumEraseRegions = jedec_table[index].NumEraseRegions;
+	p_cfi->cfiq->DevSize = jedec_table[index].DevSize;
+
+	for (i=0; i<num_erase_regions; i++){
+		p_cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i];
+	}	
+	return 0; 	/* ok */
+}
+
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/chips/cfi_probe.c linux/drivers/mtd/chips/cfi_probe.c
--- v2.4.5/linux/drivers/mtd/chips/cfi_probe.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/chips/cfi_probe.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,671 @@
+/* 
+   Common Flash Interface probe code.
+   (C) 2000 Red Hat. GPL'd.
+   $Id: cfi_probe.c,v 1.60 2001/06/03 01:32:57 nico Exp $
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+
+/* #define DEBUG_CFI */
+
+#ifdef DEBUG_CFI
+static void print_cfi_ident(struct cfi_ident *);
+#endif
+
+int cfi_jedec_setup(struct cfi_private *p_cfi, int index);
+int cfi_jedec_lookup(int index, int mfr_id, int dev_id);
+
+static void check_cmd_set(struct map_info *, int, unsigned long);
+static struct cfi_private *cfi_cfi_probe(struct map_info *);
+struct mtd_info *cfi_probe(struct map_info *map);
+
+
+static struct mtd_chip_driver cfi_chipdrv = {
+	probe: cfi_probe,
+	name: "cfi",
+	module: THIS_MODULE
+};
+
+
+struct mtd_info *cfi_probe(struct map_info *map)
+{
+	struct mtd_info *mtd = NULL;
+	struct cfi_private *cfi;
+
+	/* First probe the map to see if we have CFI stuff there. */
+	cfi = cfi_cfi_probe(map);
+	
+	if (!cfi)
+		return NULL;
+
+	map->fldrv_priv = cfi;
+	/* OK we liked it. Now find a driver for the command set it talks */
+
+	check_cmd_set(map, 1, cfi->chips[0].start); /* First the primary cmdset */
+	if (!map->fldrv)
+		check_cmd_set(map, 0, cfi->chips[0].start); /* Then the secondary */
+	
+	/* check_cmd_set() will have used inter_module_get to increase
+	   the use count of the module which provides the command set 
+	   driver. If we're quitting, we have to decrease it again.
+	*/
+
+	if(map->fldrv) {
+		mtd = map->fldrv->probe(map);
+		/* Undo the use count we held onto from inter_module_get */
+#ifdef MODULE
+		if(map->fldrv->module)
+		  __MOD_DEC_USE_COUNT(map->fldrv->module);
+#endif
+		if (mtd)
+			return mtd;
+	}
+	printk(KERN_WARNING"cfi_probe: No supported Vendor Command Set found\n");
+	
+	kfree(cfi->cfiq);
+	kfree(cfi);
+	map->fldrv_priv = NULL;
+	return NULL;
+}
+
+static __u32 cfi_send_cmd(u_char cmd, __u32 base, struct map_info *map, struct cfi_private *cfi)
+{
+	return cfi_send_gen_cmd(cmd, 0x55, base, map, cfi, cfi->device_type, NULL);
+}
+
+/* check for QRY, or search for jedec id.
+   in: interleave,type,mode
+   ret: table index, <0 for error
+ */
+static int cfi_check_qry_or_id(struct map_info *map, __u32 base, int index,
+				struct cfi_private *cfi)
+{
+	__u32 manufacturer_id, device_id;
+	int osf = cfi->interleave * cfi->device_type;	// scale factor
+
+	//printk("cfi_check_qry_or_id: base=0x%08lx interl=%d type=%d index=%d\n",base,cfi->interleave,cfi->device_type,index);
+
+	switch(cfi->cfi_mode){
+	case 0:
+		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 0;	// ok !
+		break;
+		
+	case 1:
+		manufacturer_id = cfi_read(map,base+0*osf);
+		device_id 	= cfi_read(map,base+1*osf);
+		//printk("cfi_check_qry_or_id: man=0x%lx,id=0x%lx\n",manufacturer_id, device_id);
+		
+		return cfi_jedec_lookup(index,manufacturer_id,device_id);	
+	}
+	
+	return -1; 	// nothing found
+}
+
+static void cfi_qry_mode(struct map_info *map, __u32 base, struct cfi_private *cfi)
+{
+	switch(cfi->cfi_mode){
+	case 0:
+		/* Query */
+		cfi_send_cmd(0x98, base, map, cfi);
+		break;
+		
+	case 1:
+		
+		/* Autoselect */
+		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(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+		break;
+	}
+}
+
+static int cfi_probe_chip_1(struct map_info *map, __u32 base,
+			  struct flchip *chips, struct cfi_private *cfi)
+{
+	int index;
+	__u32 tmp,ofs;
+	
+	ofs = cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, &tmp);
+	
+	cfi_qry_mode(map,base,cfi);
+	
+	index=cfi_check_qry_or_id(map,base,-1,cfi);
+	if (index<0) return -1;
+	
+	if (chips){
+		int i;
+
+		for (i=0; i<cfi->numchips; i++){
+			/* This chip should be in read mode if it's one
+			   we've already touched. */
+			if (cfi_check_qry_or_id(map,chips[i].start,index,cfi) >= 0){
+				cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL);
+				if (cfi_check_qry_or_id(map,chips[i].start,index,cfi) >= 0){
+					/* Yes it's got QRY for data. Most unfortunate.
+					   Stick the old one in read mode too. */
+					cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+					if (cfi_check_qry_or_id(map,base,index,cfi) >= 0){
+						/* OK, so has the new one. Assume it's an alias */
+						printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
+						       map->name, base, chips[i].start);
+						return -1;
+					}
+				} else {
+					/* 
+					 * FIXME: Is this supposed to work?
+					 * The third argument is already
+					 * multiplied as this within the
+					 * function definition. (Nicolas Pitre)
+					 */
+					cfi_send_gen_cmd(0xF0, 0, base+0xaa*cfi->interleave * cfi->device_type, map, cfi, cfi->device_type, NULL);
+					cfi_send_gen_cmd(0xF0, 0, chips[i].start+0xaa*cfi->interleave * cfi->device_type, map, cfi, cfi->device_type, NULL);
+					return -1;
+				}
+			}
+		} /* for i */
+		
+		/* 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;
+		chips[cfi->numchips].mutex = &chips[cfi->numchips]._spinlock;
+		cfi->numchips++;
+		
+		/* Put it back into Read Mode */
+		cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+	}
+	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);
+	
+	return index;
+}
+
+/*  put dev into qry mode, and try cfi and jedec modes for the given type/interleave
+ */
+static int cfi_probe_chip(struct map_info *map, __u32 base,
+			  struct flchip *chips, struct cfi_private *cfi)
+{
+	int index;
+	cfi->cfi_mode=0;	/* cfi mode */
+	
+	switch (cfi->device_type) {
+	case CFI_DEVICETYPE_X8:
+		cfi->addr_unlock1 = 0x555; 
+		cfi->addr_unlock2 = 0x2aa; 
+		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;
+		}
+		break;
+	case CFI_DEVICETYPE_X32:
+		cfi->addr_unlock1 = 0x1555; 
+		cfi->addr_unlock2 = 0xaaa; 
+		break;
+	default:
+		return 0;
+	}
+	index = cfi_probe_chip_1(map,base,chips,cfi);
+	if (index>=0) return index;
+	
+	cfi->cfi_mode=1;	/* jedec mode */
+	index = cfi_probe_chip_1(map,base,chips,cfi);
+	if (index>=0) return index;
+	
+	cfi->addr_unlock1 = 0x5555;
+	cfi->addr_unlock2 = 0x2aaa; 
+	index = cfi_probe_chip_1(map,base,chips,cfi);
+	
+	return index;
+}
+
+/*
+ * Since probeing for CFI chips requires writing to the device problems may
+ * occur if the flash is not present and RAM is accessed instead.  For now we
+ * assume that the flash is present so we don't check for RAM or replace
+ * possibly overwritten data.
+ */
+static int cfi_probe_new_chip(struct map_info *map, unsigned long base,
+			      struct flchip *chips, struct cfi_private *cfi)
+{
+int index;
+	switch (map->buswidth) {
+#ifdef CFIDEV_BUSWIDTH_1		
+	case CFIDEV_BUSWIDTH_1:
+		cfi->interleave = CFIDEV_INTERLEAVE_1;
+		cfi->device_type = CFI_DEVICETYPE_X8;
+		index = cfi_probe_chip(map,base,chips,cfi);
+		if (index>=0) return index;
+
+		cfi->device_type = CFI_DEVICETYPE_X16;
+		index = cfi_probe_chip(map,base,chips,cfi);
+		if (index>=0) return index;
+		break;			
+#endif
+
+#ifdef CFIDEV_BUSWIDTH_2		
+	case CFIDEV_BUSWIDTH_2:
+#ifdef CFIDEV_INTERLEAVE_1
+		cfi->interleave = CFIDEV_INTERLEAVE_1;
+		cfi->device_type = CFI_DEVICETYPE_X16;
+		index = cfi_probe_chip(map,base,chips,cfi);
+		if (index>=0) return index;
+#endif
+#ifdef CFIDEV_INTERLEAVE_2
+		cfi->interleave = CFIDEV_INTERLEAVE_2;
+		cfi->device_type = CFI_DEVICETYPE_X8;
+		index = cfi_probe_chip(map,base,chips,cfi);
+		if (index>=0) return index;
+
+		cfi->device_type = CFI_DEVICETYPE_X16;
+		index = cfi_probe_chip(map,base,chips,cfi);
+		if (index>=0) return index;
+
+#endif
+		break;			
+#endif
+
+#ifdef CFIDEV_BUSWIDTH_4
+	case CFIDEV_BUSWIDTH_4:
+#ifdef CFIDEV_INTERLEAVE_4
+		cfi->interleave = CFIDEV_INTERLEAVE_4;
+		cfi->device_type = CFI_DEVICETYPE_X16;
+		index = cfi_probe_chip(map,base,chips,cfi);
+		if (index>=0) return index;
+
+		cfi->device_type = CFI_DEVICETYPE_X32;
+		index = cfi_probe_chip(map,base,chips,cfi);
+		if (index>=0) return index;
+
+		cfi->device_type = CFI_DEVICETYPE_X8;
+		index = cfi_probe_chip(map,base,chips,cfi);
+		if (index>=0) return index;
+#endif
+#ifdef CFIDEV_INTERLEAVE_2
+		cfi->interleave = CFIDEV_INTERLEAVE_2;
+		cfi->device_type = CFI_DEVICETYPE_X16;
+		index = cfi_probe_chip(map,base,chips,cfi);
+		if (index>=0) return index;
+#endif
+#ifdef CFIDEV_INTERLEAVE_1
+                cfi->interleave = CFIDEV_INTERLEAVE_1;
+                cfi->device_type = CFI_DEVICETYPE_X32;
+                index = cfi_probe_chip(map,base,chips,cfi);
+                if (index>=0) return index;
+#endif
+		break;
+#endif
+	default:
+		printk(KERN_WARNING "cfi_probe called with unsupported buswidth %d\n", map->buswidth);
+		return -1;
+	} // switch
+	return -1;
+}
+
+static struct cfi_private *cfi_cfi_probe(struct map_info *map)
+{
+	unsigned long base=0;
+	struct cfi_private cfi;
+	struct cfi_private *retcfi;
+	struct flchip chip[MAX_CFI_CHIPS];
+	int i,index; 
+	char num_erase_regions;
+ 	int ofs_factor;
+
+	memset(&cfi, 0, sizeof(cfi));
+
+	/* The first invocation (with chips == NULL) leaves the device in Query Mode */
+	index = cfi_probe_new_chip(map, 0, NULL, &cfi);
+
+	if (index<0) {
+		printk(KERN_WARNING"%s: Found no CFI device at location zero\n", map->name);
+		/* Doesn't appear to be CFI-compliant at all */
+		return NULL;
+	}
+
+	/* Read the Basic Query Structure from the device */
+
+ 	ofs_factor = cfi.interleave*cfi.device_type;
+
+	/* First, work out the amount of space to allocate */
+	if (cfi.cfi_mode==0){
+		num_erase_regions = cfi_read_query(map, base + (0x10 + 28)*ofs_factor);
+
+#ifdef DEBUG_CFI
+		printk("Number of erase regions: %d\n", num_erase_regions);
+#endif
+
+		cfi.cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL);
+		if (!cfi.cfiq) {
+			printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name);
+			return NULL;
+		}
+
+		memset(cfi.cfiq,0,sizeof(struct cfi_ident));	
+
+		cfi.fast_prog=1;		/* CFI supports fast programming */
+
+			/* CFI flash */
+		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);
+		}
+
+		/* Do any necessary byteswapping */
+		cfi.cfiq->P_ID = le16_to_cpu(cfi.cfiq->P_ID);
+
+		cfi.cfiq->P_ADR = le16_to_cpu(cfi.cfiq->P_ADR);
+		cfi.cfiq->A_ID = le16_to_cpu(cfi.cfiq->A_ID);
+		cfi.cfiq->A_ADR = le16_to_cpu(cfi.cfiq->A_ADR);
+		cfi.cfiq->InterfaceDesc = le16_to_cpu(cfi.cfiq->InterfaceDesc);
+		cfi.cfiq->MaxBufWriteSize = le16_to_cpu(cfi.cfiq->MaxBufWriteSize);
+
+		for (i=0; i<cfi.cfiq->NumEraseRegions; i++) {
+			cfi.cfiq->EraseRegionInfo[i] = le32_to_cpu(cfi.cfiq->EraseRegionInfo[i]);
+
+#ifdef DEBUG_CFI		
+			printk("  Erase Region #%d: BlockSize 0x%4.4X bytes, %d blocks\n",
+		       		i, (cfi.cfiq->EraseRegionInfo[i] >> 8) & ~0xff, 
+		       		(cfi.cfiq->EraseRegionInfo[i] & 0xffff) + 1);
+#endif
+		}
+	}
+	else{
+		/* JEDEC flash */
+		if (cfi_jedec_setup(&cfi,index)<0){
+			printk(KERN_WARNING "cfi_jedec_setup failed\n");
+			return NULL;
+		}
+	}
+
+	if (cfi.cfiq->NumEraseRegions == 0) {
+		printk(KERN_WARNING "Number of erase regions is zero\n");
+		kfree(cfi.cfiq);
+		return NULL;
+	}
+
+#ifdef DEBUG_CFI
+	/* Dump the information therein */
+	print_cfi_ident(cfi.cfiq);
+#endif
+
+	cfi_send_cmd(0xFF, base, map, &cfi);
+
+	/* OK. We've worked out what it is and we're happy with it. Now see if there are others */
+
+	chip[0].start = 0;
+	chip[0].state = FL_READY;
+	chip[0].mutex = &chip[0]._spinlock;
+
+	cfi.chipshift = cfi.cfiq->DevSize;
+	cfi.numchips = 1;
+
+	if (!cfi.chipshift) {
+		printk(KERN_ERR"cfi.chipsize is zero. This is bad. cfi.cfiq->DevSize is %d\n", cfi.cfiq->DevSize);
+		kfree(cfi.cfiq);
+		return NULL;
+	}
+	switch (cfi.interleave) {
+	    case 2: cfi.chipshift += 1; break;
+	    case 4: cfi.chipshift += 2; break;
+	}
+
+	for (base = (1<<cfi.chipshift); base < map->size; base += (1<<cfi.chipshift))
+		cfi_probe_chip_1(map, base, &chip[0], &cfi);
+
+	retcfi = kmalloc(sizeof(struct cfi_private) + cfi.numchips * sizeof(struct flchip), GFP_KERNEL);
+
+	if (!retcfi) {
+		printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name);
+		kfree(cfi.cfiq);
+		return NULL;
+	}
+	memcpy(retcfi, &cfi, sizeof(cfi));
+	memcpy(&retcfi->chips[0], chip, sizeof(struct flchip) * cfi.numchips);
+	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;
+	}
+	return retcfi;
+}
+
+#ifdef DEBUG_CFI
+static char *vendorname(__u16 vendor) 
+{
+	switch (vendor) {
+	case P_ID_NONE:
+		return "None";
+		
+	case P_ID_INTEL_EXT:
+		return "Intel/Sharp Extended";
+		
+	case P_ID_AMD_STD:
+		return "AMD/Fujitsu Standard";
+		
+	case P_ID_INTEL_STD:
+		return "Intel/Sharp Standard";
+		
+	case P_ID_AMD_EXT:
+		return "AMD/Fujitsu Extended";
+		
+	case P_ID_MITSUBISHI_STD:
+		return "Mitsubishi Standard";
+		
+	case P_ID_MITSUBISHI_EXT:
+		return "Mitsubishi Extended";
+		
+	case P_ID_RESERVED:
+		return "Not Allowed / Reserved for Future Use";
+		
+	default:
+		return "Unknown";
+	}
+}
+
+
+static void print_cfi_ident(struct cfi_ident *cfip)
+{
+#if 0
+	if (cfip->qry[0] != 'Q' || cfip->qry[1] != 'R' || cfip->qry[2] != 'Y') {
+		printk("Invalid CFI ident structure.\n");
+		return;
+	}	
+#endif		
+	printk("Primary Vendor Command Set: %4.4X (%s)\n", cfip->P_ID, vendorname(cfip->P_ID));
+	if (cfip->P_ADR)
+		printk("Primary Algorithm Table at %4.4X\n", cfip->P_ADR);
+	else
+		printk("No Primary Algorithm Table\n");
+	
+	printk("Alternative Vendor Command Set: %4.4X (%s)\n", cfip->A_ID, vendorname(cfip->A_ID));
+	if (cfip->A_ADR)
+		printk("Alternate Algorithm Table at %4.4X\n", cfip->A_ADR);
+	else
+		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);
+	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);
+	}
+	else
+		printk("No Vpp line\n");
+	
+	printk("Typical byte/word write timeout: %d µs\n", 1<<cfip->WordWriteTimeoutTyp);
+	printk("Maximum byte/word write timeout: %d µs\n", (1<<cfip->WordWriteTimeoutMax) * (1<<cfip->WordWriteTimeoutTyp));
+	
+	if (cfip->BufWriteTimeoutTyp || cfip->BufWriteTimeoutMax) {
+		printk("Typical full buffer write timeout: %d µs\n", 1<<cfip->BufWriteTimeoutTyp);
+		printk("Maximum full buffer write timeout: %d µs\n", (1<<cfip->BufWriteTimeoutMax) * (1<<cfip->BufWriteTimeoutTyp));
+	}
+	else
+		printk("Full buffer write not supported\n");
+	
+	printk("Typical block erase timeout: %d µs\n", 1<<cfip->BlockEraseTimeoutTyp);
+	printk("Maximum block erase timeout: %d µs\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp));
+	if (cfip->ChipEraseTimeoutTyp || cfip->ChipEraseTimeoutMax) {
+		printk("Typical chip erase timeout: %d µs\n", 1<<cfip->ChipEraseTimeoutTyp); 
+		printk("Maximum chip erase timeout: %d µs\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp));
+	}
+	else
+		printk("Chip erase not supported\n");
+	
+	printk("Device size: 0x%X bytes (%d MiB)\n", 1 << cfip->DevSize, 1<< (cfip->DevSize - 20));
+	printk("Flash Device Interface description: 0x%4.4X\n", cfip->InterfaceDesc);
+	switch(cfip->InterfaceDesc) {
+	case 0:
+		printk("  - x8-only asynchronous interface\n");
+		break;
+		
+	case 1:
+		printk("  - x16-only asynchronous interface\n");
+		break;
+		
+	case 2:
+		printk("  - supports x8 and x16 via BYTE# with asynchronous interface\n");
+		break;
+		
+	case 3:
+		printk("  - x32-only asynchronous interface\n");
+		break;
+		
+	case 65535:
+		printk("  - Not Allowed / Reserved\n");
+		break;
+		
+	default:
+		printk("  - Unknown\n");
+		break;
+	}
+	
+	printk("Max. bytes in buffer write: 0x%x\n", 1<< cfip->MaxBufWriteSize);
+	printk("Number of Erase Block Regions: %d\n", cfip->NumEraseRegions);
+	
+}
+#endif /* DEBUG_CFI */
+
+typedef void cfi_cmdset_fn_t(struct map_info *, int, unsigned long);
+
+extern cfi_cmdset_fn_t cfi_cmdset_0001;
+extern cfi_cmdset_fn_t cfi_cmdset_0002;
+
+static void cfi_cmdset_unknown(struct map_info *map, int primary, unsigned long base)
+{
+	__u16 adr;
+	struct cfi_private *cfi = map->fldrv_priv;
+	__u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;
+#ifdef HAVE_INTER_MODULE
+	char probename[32];
+	cfi_cmdset_fn_t *probe_function;
+
+	sprintf(probename, "cfi_cmdset_%4.4X", type);
+		
+	probe_function = inter_module_get_request(probename, probename);
+
+	if (probe_function) {
+		(*probe_function)(map, primary, base);
+		return;
+	}	
+#endif
+	printk(KERN_NOTICE "Support for command set %04X not present\n", type);
+	/* This was a command set we don't know about. Print only the basic info */
+	adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
+	
+	if (!adr) {
+		printk(" No Extended Query Table\n");
+	}
+	else {
+ 		int ofs_factor = cfi->interleave * cfi->device_type;
+
+		if (cfi_read_query(map,base + adr*ofs_factor) != (primary?'P':'A') ||
+		    cfi_read_query(map,base + (adr+1)*ofs_factor) != (primary?'R':'L') ||
+		    cfi_read_query(map,base + (adr+2)*ofs_factor) != (primary?'I':'T')) {
+			printk ("Invalid Extended Query Table at %4.4X: %2.2X %2.2X %2.2X\n",
+				adr,
+				cfi_read_query(map,base + adr*ofs_factor),
+				cfi_read_query(map,base + (adr+1)*ofs_factor),
+				cfi_read_query(map,base + (adr+2)*ofs_factor));
+		}
+		else {
+			printk(" Extended Query Table version %c.%c\n",
+			       cfi_read_query(map,base + (adr+3)*ofs_factor), 
+			       cfi_read_query(map,base + (adr+4)*ofs_factor));
+		}
+	}
+	cfi_send_cmd(0xff, base, map, cfi);
+}
+
+static void check_cmd_set(struct map_info *map, int primary, unsigned long base)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	__u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;
+	
+	if (type == P_ID_NONE || type == P_ID_RESERVED)
+		return;
+	/* Put it in query mode */
+	cfi_qry_mode(map,base,cfi);
+
+	switch(type){
+		/* Urgh. Ifdefs. The version with weak symbols was
+		 * _much_ nicer. Shame it didn't seem to work on
+		 * anything but x86, really.
+		 * But we can't rely in inter_module_get() because
+		 * that'd mean we depend on link order.
+		 */
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	case 0x0001:
+	case 0x0003:
+		return cfi_cmdset_0001(map, primary, base);
+#endif
+#ifdef CONFIG_MTD_CFI_AMDSTD
+	case 0x0002:
+		return cfi_cmdset_0002(map, primary, base);
+#endif
+	}
+
+	return cfi_cmdset_unknown(map, primary, base);
+}
+
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define cfi_probe_init init_module
+#define cfi_probe_exit cleanup_module
+#endif
+
+mod_init_t cfi_probe_init(void)
+{
+	register_mtd_chip_driver(&cfi_chipdrv);
+	return 0;
+}
+
+mod_exit_t cfi_probe_exit(void)
+{
+	unregister_mtd_chip_driver(&cfi_chipdrv);
+}
+
+module_init(cfi_probe_init);
+module_exit(cfi_probe_exit);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/chips/chipreg.c linux/drivers/mtd/chips/chipreg.c
--- v2.4.5/linux/drivers/mtd/chips/chipreg.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/chips/chipreg.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,92 @@
+/*
+ * $Id: chipreg.c,v 1.8 2001/06/09 19:58:19 dwmw2 Exp $
+ *
+ * Registration for chip drivers
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/kmod.h>
+#include <linux/spinlock.h>
+#include <linux/mtd/compatmac.h>
+#include <linux/mtd/map.h>
+
+spinlock_t chip_drvs_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(chip_drvs_list);
+
+void register_mtd_chip_driver(struct mtd_chip_driver *drv)
+{
+	spin_lock(&chip_drvs_lock);
+	list_add(&drv->list, &chip_drvs_list);
+	spin_unlock(&chip_drvs_lock);
+}
+
+void unregister_mtd_chip_driver(struct mtd_chip_driver *drv)
+{
+	spin_lock(&chip_drvs_lock);
+	list_del(&drv->list);
+	spin_unlock(&chip_drvs_lock);
+}
+
+static struct mtd_chip_driver *get_mtd_chip_driver (char *name)
+{
+	struct list_head *pos;
+	struct mtd_chip_driver *ret = NULL, *this;
+
+	spin_lock(&chip_drvs_lock);
+
+	list_for_each(pos, &chip_drvs_list) {
+		this = list_entry(pos, typeof(*this), list);
+		
+		if (!strcmp(this->name, name)) {
+			ret = this;
+			break;
+		}
+	}
+	if (ret && !try_inc_mod_count(ret->module)) {
+		/* Eep. Failed. */
+		ret = NULL;
+	}
+
+	spin_unlock(&chip_drvs_lock);
+
+	return ret;
+}
+
+	/* Hide all the horrid details, like some silly person taking
+	   get_module_symbol() away from us, from the caller. */
+
+struct mtd_info *do_map_probe(char *name, struct map_info *map)
+{
+	struct mtd_chip_driver *drv;
+	struct mtd_info *ret;
+
+	drv = get_mtd_chip_driver(name);
+
+	if (!drv && !request_module(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
+
+	if (ret)
+		return ret;
+	
+	return NULL;
+}
+
+EXPORT_SYMBOL(register_mtd_chip_driver);
+EXPORT_SYMBOL(unregister_mtd_chip_driver);
+EXPORT_SYMBOL(do_map_probe);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/chips/jedec.c linux/drivers/mtd/chips/jedec.c
--- v2.4.5/linux/drivers/mtd/chips/jedec.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/chips/jedec.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,880 @@
+
+/* JEDEC Flash Interface.
+ * This is an older type of interface for self programming flash. It is 
+ * commonly use in older AMD chips and is obsolete compared with CFI.
+ * It is called JEDEC because the JEDEC association distributes the ID codes
+ * for the chips.
+ *
+ * See the AMD flash databook for information on how to operate the interface.
+ *
+ * This code does not support anything wider than 8 bit flash chips, I am
+ * not going to guess how to send commands to them, plus I expect they will
+ * all speak CFI..
+ *
+ * $Id: jedec.c,v 1.8 2001/06/09 23:56:57 dwmw2 Exp $
+ */
+
+#include <linux/mtd/jedec.h>
+
+struct mtd_info *jedec_probe(struct map_info *);
+int jedec_probe8(struct map_info *map,unsigned long base,
+		  struct jedec_private *priv);
+int jedec_probe16(struct map_info *map,unsigned long base,
+		  struct jedec_private *priv);
+int jedec_probe32(struct map_info *map,unsigned long base,
+		  struct jedec_private *priv);
+static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
+			    unsigned long len);
+static int flash_erase(struct mtd_info *mtd, struct erase_info *instr);
+static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
+		       size_t *retlen, const u_char *buf);
+
+static unsigned long my_bank_size;
+
+/* 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 void jedec_sync(struct mtd_info *mtd) {};
+static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, 
+		      size_t *retlen, u_char *buf);
+static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, 
+			     size_t *retlen, u_char *buf);
+
+struct mtd_info *jedec_probe(struct map_info *map);
+
+
+
+static struct mtd_chip_driver jedec_chipdrv = {
+	probe: jedec_probe,
+	name: "jedec",
+	module: THIS_MODULE
+};
+
+/* Probe entry point */
+struct jedec_private priv;
+struct mtd_info __MTD;
+struct mtd_info *jedec_probe(struct map_info *map)
+{
+   struct mtd_info *MTD = &__MTD;
+   unsigned long Base;
+   unsigned long SectorSize;
+   unsigned count;
+   unsigned I,Uniq;
+   char Part[200];
+   memset(&priv,0,sizeof(priv));
+   
+   my_bank_size = map->size;
+
+   if (map->size/my_bank_size > MAX_JEDEC_CHIPS)
+   {
+      printk("mtd: Increase MAX_JEDEC_CHIPS, too many banks.\n");
+      return 0;
+   }
+   
+   for (Base = 0; Base < map->size; Base += my_bank_size)
+   {
+      // Perhaps zero could designate all tests?
+      if (map->buswidth == 0)
+	 map->buswidth = 1;
+      
+      if (map->buswidth == 1){
+	 if (jedec_probe8(map,Base,&priv) == 0) {
+		 printk("did recognize jedec chip\n");
+	         return 0;
+	 }
+      }
+      if (map->buswidth == 2)
+	 jedec_probe16(map,Base,&priv);
+      if (map->buswidth == 4)
+	 jedec_probe32(map,Base,&priv);
+   }
+   
+   // Get the biggest sector size
+   SectorSize = 0;
+   for (I = 0; priv.chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
+   {
+	   //	   printk("priv.chips[%d].jedec is %x\n",I,priv.chips[I].jedec);
+	   //	   printk("priv.chips[%d].sectorsize is %lx\n",I,priv.chips[I].sectorsize);
+      if (priv.chips[I].sectorsize > SectorSize)
+	 SectorSize = priv.chips[I].sectorsize;
+   }
+   
+   // Quickly ensure that the other sector sizes are factors of the largest
+   for (I = 0; priv.chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
+   {
+      if ((SectorSize/priv.chips[I].sectorsize)*priv.chips[I].sectorsize != SectorSize)
+      {
+	 printk("mtd: Failed. Device has incompatible mixed sector sizes\n");
+	 return 0;
+      }      
+   }
+   
+   /* 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;
+   strcat(Part," ");
+   Uniq = 0;
+   for (I = 0; priv.chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
+   {
+      const struct JEDECTable *JEDEC;
+      
+      if (priv.chips[I+1].jedec == priv.chips[I].jedec)
+      {
+	 count++;
+	 continue;
+      }
+      
+      // Locate the chip in the jedec table
+      JEDEC = jedec_idtoinf(priv.chips[I].jedec >> 8,priv.chips[I].jedec);
+      if (JEDEC == 0)
+      {
+	 printk("mtd: Internal Error, JEDEC not set\n");
+	 return 0;
+      }
+      
+      if (Uniq != 0)
+	 strcat(Part,",");
+      Uniq++;
+      
+      if (count != 1)
+	 sprintf(Part+strlen(Part),"%x*[%s]",count,JEDEC->name);
+      else
+	 sprintf(Part+strlen(Part),"%s",JEDEC->name);
+      if (strlen(Part) > sizeof(Part)*2/3)
+	 break;
+      count = 1;
+   }   
+
+   /* Determine if the chips are organized in a linear fashion, or if there
+      are empty banks. Note, the last bank does not count here, only the
+      first banks are important. Holes on non-bank boundaries can not exist
+      due to the way the detection algorithm works. */
+   if (priv.size < my_bank_size)
+      my_bank_size = priv.size;
+   priv.is_banked = 0;
+   //printk("priv.size is %x, my_bank_size is %x\n",priv.size,my_bank_size);
+   //printk("priv.bank_fill[0] is %x\n",priv.bank_fill[0]);
+   if (!priv.size) {
+	   printk("priv.size is zero\n");
+	   return 0;
+   }
+   if (priv.size/my_bank_size) {
+	   if (priv.size/my_bank_size == 1) {
+		   priv.size = my_bank_size;
+	   }
+	   else {
+		   for (I = 0; I != priv.size/my_bank_size - 1; I++)
+		   {
+		      if (priv.bank_fill[I] != my_bank_size)
+			 priv.is_banked = 1;
+		      
+		      /* This even could be eliminated, but new de-optimized read/write
+			 functions have to be written */
+		      printk("priv.bank_fill[%d] is %lx, priv.bank_fill[0] is %lx\n",I,priv.bank_fill[I],priv.bank_fill[0]);
+		      if (priv.bank_fill[I] != priv.bank_fill[0])
+		      {
+			 printk("mtd: Failed. Cannot handle unsymetric banking\n");
+			 return 0;
+		      }      
+		   }
+	   }
+   }
+   if (priv.is_banked == 1)
+      strcat(Part,", banked");
+
+   //   printk("Part: '%s'\n",Part);
+   
+   memset(MTD,0,sizeof(*MTD));
+  // strncpy(MTD->name,Part,sizeof(MTD->name));
+  // MTD->name[sizeof(MTD->name)-1] = 0;
+   MTD->name = map->name;
+   MTD->type = MTD_NORFLASH;
+   MTD->flags = MTD_CAP_NORFLASH;
+   MTD->erasesize = SectorSize*(map->buswidth);
+   //   printk("MTD->erasesize is %x\n",(unsigned int)MTD->erasesize);
+   MTD->size = priv.size;
+   //   printk("MTD->size is %x\n",(unsigned int)MTD->size);
+   //MTD->module = THIS_MODULE; // ? Maybe this should be the low level module?
+   MTD->erase = flash_erase;
+   if (priv.is_banked == 1)
+      MTD->read = jedec_read_banked;
+   else
+      MTD->read = jedec_read;
+   MTD->write = flash_write;
+   MTD->sync = jedec_sync;
+   MTD->priv = map;
+   map->fldrv_priv = &priv;
+   map->fldrv = &jedec_chipdrv;
+   MOD_INC_USE_COUNT;
+   return MTD;
+}
+
+/* Helper for the JEDEC function, JEDEC numbers all have odd parity */
+static int checkparity(u_char C)
+{
+   u_char parity = 0;
+   while (C != 0)
+   {
+      parity ^= C & 1;
+      C >>= 1;
+   }
+
+   return parity == 1;
+}
+
+
+/* Take an array of JEDEC numbers that represent interleved flash chips
+   and process them. Check to make sure they are good JEDEC numbers, look
+   them up and then add them to the chip list */   
+int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count,
+		  unsigned long base,struct jedec_private *priv)
+{
+   unsigned I,J;
+   unsigned long Size;
+   unsigned long SectorSize;
+   const struct JEDECTable *JEDEC;
+
+   // Test #2 JEDEC numbers exhibit odd parity
+   for (I = 0; I != Count; I++)
+   {
+      if (checkparity(Mfg[I]) == 0 || checkparity(Id[I]) == 0)
+	 return 0;
+   }
+   
+   // Finally, just make sure all the chip sizes are the same
+   JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
+   
+   if (JEDEC == 0)
+   {
+      printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
+      return 0;
+   }
+   
+   Size = JEDEC->size;
+   SectorSize = JEDEC->sectorsize;
+   for (I = 0; I != Count; I++)
+   {
+      JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
+      if (JEDEC == 0)
+      {
+	 printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
+	 return 0;
+      }
+
+      if (Size != JEDEC->size || SectorSize != JEDEC->sectorsize)
+      {
+	 printk("mtd: Failed. Interleved flash does not have matching characteristics\n");
+	 return 0;
+      }      
+   }
+
+   // Load the Chips
+   for (I = 0; I != MAX_JEDEC_CHIPS; I++)
+   {
+      if (priv->chips[I].jedec == 0)
+	 break;
+   }
+
+   if (I + Count > MAX_JEDEC_CHIPS)
+   {
+      printk("mtd: Device has too many chips. Increase MAX_JEDEC_CHIPS\n");
+      return 0;
+   }      
+   
+   // Add them to the table
+   for (J = 0; J != Count; J++)
+   {
+      unsigned long Bank;
+	 
+      JEDEC = jedec_idtoinf(Mfg[J],Id[J]);
+      priv->chips[I].jedec = (Mfg[J] << 8) | Id[J];
+      priv->chips[I].size = JEDEC->size;
+      priv->chips[I].sectorsize = JEDEC->sectorsize;
+      priv->chips[I].base = base + J;
+      priv->chips[I].datashift = J*8;
+      priv->chips[I].capabilities = JEDEC->capabilities;
+      priv->chips[I].offset = priv->size + J;
+
+      // log2 n :|
+      priv->chips[I].addrshift = 0;
+      for (Bank = Count; Bank != 1; Bank >>= 1, priv->chips[I].addrshift++);
+      
+      // Determine how filled this bank is.
+      Bank = base & (~(my_bank_size-1));
+      if (priv->bank_fill[Bank/my_bank_size] < base + 
+	  (JEDEC->size << priv->chips[I].addrshift) - Bank)
+	 priv->bank_fill[Bank/my_bank_size] =  base + (JEDEC->size << priv->chips[I].addrshift) - Bank;
+      I++;
+   }
+
+   priv->size += priv->chips[I-1].size*Count;
+	 
+   return priv->chips[I-1].size;
+}
+
+/* Lookup the chip information from the JEDEC ID table. */
+const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id)
+{
+   __u16 Id = (mfr << 8) | id;
+   unsigned long I = 0;
+   for (I = 0; JEDEC_table[I].jedec != 0; I++)
+      if (JEDEC_table[I].jedec == Id)
+	 return JEDEC_table + I;
+   return 0;
+}
+
+// Look for flash using an 8 bit bus interface
+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)
+
+   const unsigned long AutoSel1 = 0xAA;
+   const unsigned long AutoSel2 = 0x55;
+   const unsigned long AutoSel3 = 0x90;
+   const unsigned long Reset = 0xF0;
+   __u32 OldVal;
+   __u8 Mfg[1];
+   __u8 Id[1];
+   unsigned I;
+   unsigned long Size;
+
+   // Wait for any write/erase operation to settle
+   OldVal = flread(base);
+   for (I = 0; OldVal != flread(base) && I < 10000; I++)
+      OldVal = flread(base);
+   
+   // Reset the chip
+   flwrite(Reset,0x555); 
+   
+   // Send the sequence
+   flwrite(AutoSel1,0x555);
+   flwrite(AutoSel2,0x2AA);
+   flwrite(AutoSel3,0x555);
+   
+   //  Get the JEDEC numbers
+   Mfg[0] = flread(0);
+   Id[0] = flread(1);
+   //   printk("Mfg is %x, Id is %x\n",Mfg[0],Id[0]);
+      
+   Size = handle_jedecs(map,Mfg,Id,1,base,priv);
+   //   printk("handle_jedecs Size is %x\n",(unsigned int)Size);
+   if (Size == 0)
+   {
+      flwrite(Reset,0x555);
+      return 0;
+   }
+   
+
+   // Reset.
+   flwrite(Reset,0x555);
+   
+   return 1;
+   
+   #undef flread
+   #undef flwrite
+}
+
+// Look for flash using a 16 bit bus interface (ie 2 8-bit chips)
+int jedec_probe16(struct map_info *map,unsigned long base,
+		  struct jedec_private *priv)
+{
+   return 0;
+}
+
+// Look for flash using a 32 bit bus interface (ie 4 8-bit chips)
+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))
+
+   const unsigned long AutoSel1 = 0xAAAAAAAA;
+   const unsigned long AutoSel2 = 0x55555555;
+   const unsigned long AutoSel3 = 0x90909090;
+   const unsigned long Reset = 0xF0F0F0F0;
+   __u32 OldVal;
+   __u8 Mfg[4];
+   __u8 Id[4];
+   unsigned I;
+   unsigned long Size;
+
+   // Wait for any write/erase operation to settle
+   OldVal = flread(base);
+   for (I = 0; OldVal != flread(base) && I < 10000; I++)
+      OldVal = flread(base);
+   
+   // Reset the chip
+   flwrite(Reset,0x555); 
+   
+   // Send the sequence
+   flwrite(AutoSel1,0x555);
+   flwrite(AutoSel2,0x2AA);
+   flwrite(AutoSel3,0x555);
+   
+   // Test #1, JEDEC numbers are readable from 0x??00/0x??01
+   if (flread(0) != flread(0x100) || 
+       flread(1) != flread(0x101))
+   {
+      flwrite(Reset,0x555);
+      return 0;
+   }
+
+   // Split up the JEDEC numbers
+   OldVal = flread(0);
+   for (I = 0; I != 4; I++)
+      Mfg[I] = (OldVal >> (I*8));
+   OldVal = flread(1);
+   for (I = 0; I != 4; I++)
+      Id[I] = (OldVal >> (I*8));
+      
+   Size = handle_jedecs(map,Mfg,Id,4,base,priv);
+   if (Size == 0)
+   {
+      flwrite(Reset,0x555);
+      return 0;
+   }
+   
+   /* Check if there is address wrap around within a single bank, if this
+      returns JEDEC numbers then we assume that it is wrap around. Notice
+      we call this routine with the JEDEC return still enabled, if two or
+      more flashes have a truncated address space the probe test will still
+      work */
+   if (base + Size+0x555 < map->size &&
+       base + Size+0x555 < (base & (~(my_bank_size-1))) + my_bank_size)
+   {
+      if (flread(base+Size) != flread(base+Size + 0x100) ||
+	  flread(base+Size + 1) != flread(base+Size + 0x101))
+      {
+	 jedec_probe32(map,base+Size,priv);
+      }
+   }
+
+   // Reset.
+   flwrite(0xF0F0F0F0,0x555);
+   
+   return 1;
+   
+   #undef flread
+   #undef flwrite
+}
+
+/* Linear read. */
+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;
+   
+   map->copy_from(map, buf, from, len);
+   *retlen = len;
+   return 0;   
+}
+
+/* Banked read. Take special care to jump past the holes in the bank
+   mapping. This version assumes symetry in the holes.. */
+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;
+
+   *retlen = 0;
+   while (len > 0)
+   {
+      // Determine what bank and offset into that bank the first byte is
+      unsigned long bank = from & (~(priv->bank_fill[0]-1));
+      unsigned long offset = from & (priv->bank_fill[0]-1);
+      unsigned long get = len;
+      if (priv->bank_fill[0] - offset < len)
+	 get = priv->bank_fill[0] - offset;
+
+      bank /= priv->bank_fill[0];      
+      map->copy_from(map,buf + *retlen,bank*my_bank_size + offset,get);
+      
+      len -= get;
+      *retlen += get;
+      from += get;
+   }   
+   return 0;   
+}
+
+/* Pass the flags value that the flash return before it re-entered read 
+   mode. */
+static void jedec_flash_failed(unsigned char code)
+{
+   /* Bit 5 being high indicates that there was an internal device
+      failure, erasure time limits exceeded or something */
+   if ((code & (1 << 5)) != 0)
+   {
+      printk("mtd: Internal Flash failure\n");
+      return;
+   }
+   printk("mtd: Programming didn't take\n");
+}
+
+/* This uses the erasure function described in the AMD Flash Handbook, 
+   it will work for flashes with a fixed sector size only. Flashes with
+   a selection of sector sizes (ie the AMD Am29F800B) will need a different
+   routine. This routine tries to parallize erasing multiple chips/sectors 
+   where possible */
+static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+   // Does IO to the currently selected chip
+   #define flread(x) map->read8(map,chip->base+((x)<<chip->addrshift))
+   #define flwrite(v,x) map->write8(map,v,chip->base+((x)<<chip->addrshift))
+   
+   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;
+
+   // Verify the arguments..
+   if (start + len > mtd->size ||
+       (start % mtd->erasesize) != 0 ||
+       (len % mtd->erasesize) != 0 ||
+       (len/mtd->erasesize) == 0)
+      return -EINVAL;
+   
+   jedec_flash_chip_scan(priv,start,len);
+
+   // Start the erase sequence on each chip
+   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
+   {
+      unsigned long off;
+      struct jedec_flash_chip *chip = priv->chips + I;
+      
+      if (chip->length == 0)
+	 continue;
+      
+      if (chip->start + chip->length > chip->size)
+      {
+	 printk("DIE\n");
+	 return -EIO;
+      }     
+      
+      flwrite(0xF0,chip->start + 0x555);
+      flwrite(0xAA,chip->start + 0x555);
+      flwrite(0x55,chip->start + 0x2AA);
+      flwrite(0x80,chip->start + 0x555);
+      flwrite(0xAA,chip->start + 0x555);
+      flwrite(0x55,chip->start + 0x2AA);
+
+      /* Once we start selecting the erase sectors the delay between each 
+         command must not exceed 50us or it will immediately start erasing 
+         and ignore the other sectors */
+      for (off = 0; off < len; off += chip->sectorsize)
+      {
+	 // Check to make sure we didn't timeout
+	 flwrite(0x30,chip->start + off);
+	 if (off == 0)
+	    continue;
+	 if ((flread(chip->start + off) & (1 << 3)) != 0)
+	 {
+	    printk("mtd: Ack! We timed out the erase timer!\n");
+	    return -EIO;
+	 }       	 
+      }
+   }   
+
+   /* We could split this into a timer routine and return early, performing
+      background erasure.. Maybe later if the need warrents */
+
+   /* 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.. */
+   
+   /* This being a generic routine assumes a 32 bit bus. It does read32s
+      and bundles interleved chips into the same grouping. This will work 
+      for all bus widths */
+   Time = 0;
+   NoTime = 0;
+   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
+   {
+      struct jedec_flash_chip *chip = priv->chips + I;
+      unsigned long off = 0;
+      unsigned todo[4] = {0,0,0,0};
+      unsigned todo_left = 0;
+      unsigned J;
+      
+      if (chip->length == 0)
+	 continue;
+
+      /* Find all chips in this data line, realistically this is all 
+         or nothing up to the interleve count */
+      for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
+      {
+	 if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) == 
+	     (chip->base & (~((1<<chip->addrshift)-1))))
+	 {
+	    todo_left++;
+	    todo[priv->chips[J].base & ((1<<chip->addrshift)-1)] = 1;
+	 }	 
+      }
+
+      /*      printk("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1],
+	      (short)todo[2],(short)todo[3]);
+      */
+      while (1)
+      {
+	 __u32 Last[4];
+	 unsigned long Count = 0;
+	 
+	 /* During erase bit 7 is held low and bit 6 toggles, we watch this,
+	    should it stop toggling or go high then the erase is completed,
+  	    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);
+	    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);
+	    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);
+	    break;
+	 }
+	 Count = 3;
+	 while (todo_left != 0)
+	 {
+	    for (J = 0; J != 4; J++)
+	    {
+	       __u8 Byte1 = (Last[(Count-1)%4] >> (J*8)) & 0xFF;
+	       __u8 Byte2 = (Last[(Count-2)%4] >> (J*8)) & 0xFF;
+	       __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF;
+	       if (todo[J] == 0)
+		  continue;
+	       
+	       if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2)
+	       {
+//		  printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2);
+		  continue;
+	       }
+	       
+	       if (Byte1 == Byte2)
+	       {
+		  jedec_flash_failed(Byte3);
+		  return -EIO;
+	       }
+	       
+	       todo[J] = 0;
+	       todo_left--;
+	    }
+	    
+/*	    if (NoTime == 0)
+	       Time += HZ/10 - schedule_timeout(HZ/10);*/
+	    NoTime = 0;
+
+	    switch (map->buswidth) {
+	    case 1:
+	       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);
+	      break;
+	    case 4:
+	       Last[Count % 4] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
+	      break;
+	    }
+	    Count++;
+	    
+/*	    // Count time, max of 15s per sector (according to AMD)
+	    if (Time > 15*len/mtd->erasesize*HZ)
+	    {
+	       printk("mtd: Flash Erase Timed out\n");
+	       return -EIO;
+	    }	    */
+	 }
+	 	 
+	 // Skip to the next chip if we used chip erase
+	 if (chip->length == chip->size)
+	    off = chip->size;
+	 else
+	    off += chip->sectorsize;
+	 
+	 if (off >= chip->length)
+	    break;
+	 NoTime = 1;
+      }
+      
+      for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
+      {
+	 if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
+	     (chip->base & (~((1<<chip->addrshift)-1))))
+	    priv->chips[J].length = 0;
+      }      
+   }
+       	    
+   //printk("done\n");
+   if (instr->callback)
+	instr->callback(instr);
+   return 0;
+   
+   #undef flread
+   #undef flwrite
+}
+
+/* This is the simple flash writing function. It writes to every byte, in
+   sequence. It takes care of how to properly address the flash if
+   the flash is interleved. It can only be used if all the chips in the 
+   array are identical!*/
+static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
+		       size_t *retlen, const u_char *buf)
+{
+   /* Does IO to the currently selected chip. It takes the bank addressing
+      base (which is divisable by the chip size) adds the necesary lower bits
+      of addrshift (interleve index) and then adds the control register index. */
+   #define flread(x) map->read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
+   #define flwrite(v,x) map->write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
+   
+   struct map_info *map = (struct map_info *)mtd->priv;
+   struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv;
+   unsigned long base;
+   unsigned long off;
+   size_t save_len = len;
+   
+   if (start + len > mtd->size)
+      return -EIO;
+   
+   //printk("Here");
+   
+   //printk("flash_write: start is %x, len is %x\n",start,(unsigned long)len);
+   while (len != 0)
+   {
+      struct jedec_flash_chip *chip = priv->chips;
+      unsigned long bank;
+      unsigned long boffset;
+	 
+      // Compute the base of the flash.
+      off = ((unsigned long)start) % (chip->size << chip->addrshift);
+      base = start - off;
+
+      // Perform banked addressing translation.
+      bank = base & (~(priv->bank_fill[0]-1));
+      boffset = base & (priv->bank_fill[0]-1);
+      bank = (bank/priv->bank_fill[0])*my_bank_size;
+      base = bank + boffset;
+      
+    //  printk("Flasing %X %X %X\n",base,chip->size,len);
+     // printk("off is %x, compare with %x\n",off,chip->size << chip->addrshift);
+      
+      // 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 Last[4];
+	 unsigned long Count = 0;
+
+	 if (oldbyte == *buf) {
+	//	 printk("oldbyte and *buf is %x,len is %x\n",oldbyte,len);
+	    continue;
+	 }
+	 if (((~oldbyte) & *buf) != 0)
+	    printk("mtd: warn: Trying to set a 0 to a 1\n");
+	     
+	 // Write
+	 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);
+	 
+	 /* Wait for the flash to finish the operation. We store the last 4
+	    status bytes that have been retrieved so we can determine why
+	    it failed. The toggle bits keep toggling when there is a 
+	    failure */
+	 for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] &&
+	      Count < 10000; Count++)
+	    Last[Count % 4] = map->read8(map,base + off);
+	 if (Last[(Count - 1) % 4] != *buf)
+	 {
+	    jedec_flash_failed(Last[(Count - 3) % 4]);
+	    return -EIO;
+	 }	 
+      }
+   }
+   *retlen = save_len;
+   return 0;
+}
+
+/* This is used to enhance the speed of the erase routine,
+   when things are being done to multiple chips it is possible to
+   parallize the operations, particularly full memory erases of multi
+   chip memories benifit */
+static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
+		     unsigned long len)
+{
+   unsigned int I;
+
+   // Zero the records
+   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
+      priv->chips[I].start = priv->chips[I].length = 0;
+   
+   // Intersect the region with each chip
+   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
+   {
+      struct jedec_flash_chip *chip = priv->chips + I;
+      unsigned long ByteStart;
+      unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift);
+      
+      // End is before this chip or the start is after it
+      if (start+len < chip->offset ||
+	  ChipEndByte - (1 << chip->addrshift) < start)
+	 continue;
+      
+      if (start < chip->offset)
+      {
+	 ByteStart = chip->offset;
+	 chip->start = 0;
+      }      
+      else
+      {
+	 chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift;
+	 ByteStart = start;
+      }
+
+      if (start + len >= ChipEndByte)
+	 chip->length = (ChipEndByte - ByteStart) >> chip->addrshift;
+      else
+	 chip->length = (start + len - ByteStart + (1 << chip->addrshift)-1) >> chip->addrshift;
+   }
+}
+									/*}}}*/
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define jedec_probe_init init_module
+#define jedec_probe_exit cleanup_module
+#endif
+
+int __init jedec_probe_init(void)
+{
+	register_mtd_chip_driver(&jedec_chipdrv);
+	return 0;
+}
+
+static void __exit jedec_probe_exit(void)
+{
+	unregister_mtd_chip_driver(&jedec_chipdrv);
+}
+
+module_init(jedec_probe_init);
+module_exit(jedec_probe_exit);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/chips/map_ram.c linux/drivers/mtd/chips/map_ram.c
--- v2.4.5/linux/drivers/mtd/chips/map_ram.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/chips/map_ram.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,136 @@
+/*
+ * Common code to handle map devices which are simple RAM
+ * (C) 2000 Red Hat. GPL'd.
+ * $Id: map_ram.c,v 1.11 2001/06/08 15:34:04 dwmw2 Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/map.h>
+
+
+static int mapram_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int mapram_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+static int mapram_erase (struct mtd_info *, struct erase_info *);
+static void mapram_nop (struct mtd_info *);
+static struct mtd_info *map_ram_probe(struct map_info *map);
+
+
+static struct mtd_chip_driver mapram_chipdrv = {
+	probe: map_ram_probe,
+	name: "ram",
+	module: THIS_MODULE
+};
+
+static struct mtd_info *map_ram_probe(struct map_info *map)
+{
+	struct mtd_info *mtd;
+
+	/* Check the first byte is RAM */
+#if 0
+	map->write8(map, 0x55, 0);
+	if (map->read8(map, 0) != 0x55)
+		return NULL;
+
+	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)
+		return NULL;
+
+	map->write8(map, 0xAA, map->size-1);
+	if (map->read8(map, map->size-1) != 0xAA)
+		return NULL;
+#endif
+	/* OK. It seems to be RAM. */
+
+	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+	if (!mtd)
+		return NULL;
+
+	memset(mtd, 0, sizeof(*mtd));
+
+	map->fldrv = &mapram_chipdrv;
+	mtd->priv = map;
+	mtd->name = map->name;
+	mtd->type = MTD_RAM;
+	mtd->erasesize = 0x10000;
+	mtd->size = map->size;
+	mtd->erase = mapram_erase;
+	mtd->read = mapram_read;
+	mtd->write = mapram_write;
+	mtd->sync = mapram_nop;
+	mtd->flags = MTD_CAP_RAM | MTD_VOLATILE;
+	mtd->erasesize = PAGE_SIZE;
+
+	MOD_INC_USE_COUNT;
+	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;
+
+	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;
+
+	map->copy_to(map, to, buf, len);
+	*retlen = len;
+	return 0;
+}
+
+static int mapram_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+	/* Yeah, it's inefficient. Who cares? It's faster than a _real_
+	   flash erase. */
+	struct map_info *map = (struct map_info *)mtd->priv;
+	unsigned long i;
+
+	for (i=0; i<instr->len; i++)
+		map->write8(map, 0xFF, instr->addr + i);
+
+	if (instr->callback)
+		instr->callback(instr);
+
+	return 0;
+}
+
+static void mapram_nop(struct mtd_info *mtd)
+{
+	/* Nothing to see here */
+}
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define map_ram_init init_module
+#define map_ram_exit cleanup_module
+#endif
+
+static int __init map_ram_init(void)
+{
+	register_mtd_chip_driver(&mapram_chipdrv);
+	return 0;
+}
+
+static void __exit map_ram_exit(void)
+{
+	unregister_mtd_chip_driver(&mapram_chipdrv);
+}
+
+module_init(map_ram_init);
+module_exit(map_ram_exit);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/chips/map_rom.c linux/drivers/mtd/chips/map_rom.c
--- v2.4.5/linux/drivers/mtd/chips/map_rom.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/chips/map_rom.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,91 @@
+/*
+ * Common code to handle map devices which are simple ROM
+ * (C) 2000 Red Hat. GPL'd.
+ * $Id: map_rom.c,v 1.14 2001/06/02 14:30:43 dwmw2 Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/map.h>
+
+static int maprom_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int maprom_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+static void maprom_nop (struct mtd_info *);
+struct mtd_info *map_rom_probe(struct map_info *map);
+
+static struct mtd_chip_driver maprom_chipdrv = {
+	probe: map_rom_probe,
+	name: "rom",
+	module: THIS_MODULE
+};
+
+struct mtd_info *map_rom_probe(struct map_info *map)
+{
+	struct mtd_info *mtd;
+
+	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+	if (!mtd)
+		return NULL;
+
+	memset(mtd, 0, sizeof(*mtd));
+
+	map->fldrv = &maprom_chipdrv;
+	mtd->priv = map;
+	mtd->name = map->name;
+	mtd->type = MTD_ROM;
+	mtd->size = map->size;
+	mtd->read = maprom_read;
+	mtd->write = maprom_write;
+	mtd->sync = maprom_nop;
+	mtd->flags = MTD_CAP_ROM;
+	mtd->erasesize = 131072;
+
+	MOD_INC_USE_COUNT;
+	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;
+
+	map->copy_from(map, buf, from, len);
+	*retlen = len;
+	return 0;
+}
+
+static void maprom_nop(struct mtd_info *mtd)
+{
+	/* Nothing to see here */
+}
+
+static int maprom_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
+{
+	printk(KERN_NOTICE "maprom_write called\n");
+	return -EIO;
+}
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define map_rom_init init_module
+#define map_rom_exit cleanup_module
+#endif
+
+mod_init_t map_rom_init(void)
+{
+	register_mtd_chip_driver(&maprom_chipdrv);
+	return 0;
+}
+
+mod_exit_t map_rom_exit(void)
+{
+	unregister_mtd_chip_driver(&maprom_chipdrv);
+}
+
+module_init(map_rom_init);
+module_exit(map_rom_exit);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/chips/sharp.c linux/drivers/mtd/chips/sharp.c
--- v2.4.5/linux/drivers/mtd/chips/sharp.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/chips/sharp.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,593 @@
+/*
+ * MTD chip driver for pre-CFI Sharp flash chips
+ *
+ * Copyright 2000,2001 David A. Schleef <ds@schleef.org>
+ *           2000,2001 Lineo, Inc.
+ *
+ * $Id: sharp.c,v 1.4 2001/04/29 16:21:17 dwmw2 Exp $
+ *
+ * Devices supported:
+ *   LH28F016SCT Symmetrical block flash memory, 2Mx8
+ *   LH28F008SCT Symmetrical block flash memory, 1Mx8
+ *
+ * Documentation:
+ *   http://www.sharpmeg.com/datasheets/memic/flashcmp/
+ *   http://www.sharpmeg.com/datasheets/memic/flashcmp/01symf/16m/016sctl9.pdf
+ *   016sctl9.pdf
+ *
+ * Limitations:
+ *   This driver only supports 4x1 arrangement of chips.
+ *   Not tested on anything but PowerPC.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+#include <linux/delay.h>
+
+#define CMD_RESET		0xffffffff
+#define CMD_READ_ID		0x90909090
+#define CMD_READ_STATUS		0x70707070
+#define CMD_CLEAR_STATUS	0x50505050
+#define CMD_BLOCK_ERASE_1	0x20202020
+#define CMD_BLOCK_ERASE_2	0xd0d0d0d0
+#define CMD_BYTE_WRITE		0x40404040
+#define CMD_SUSPEND		0xb0b0b0b0
+#define CMD_RESUME		0xd0d0d0d0
+#define CMD_SET_BLOCK_LOCK_1	0x60606060
+#define CMD_SET_BLOCK_LOCK_2	0x01010101
+#define CMD_SET_MASTER_LOCK_1	0x60606060
+#define CMD_SET_MASTER_LOCK_2	0xf1f1f1f1
+#define CMD_CLEAR_BLOCK_LOCKS_1	0x60606060
+#define CMD_CLEAR_BLOCK_LOCKS_2	0xd0d0d0d0
+
+#define SR_READY		0x80808080 // 1 = ready
+#define SR_ERASE_SUSPEND	0x40404040 // 1 = block erase suspended
+#define SR_ERROR_ERASE		0x20202020 // 1 = error in block erase or clear lock bits
+#define SR_ERROR_WRITE		0x10101010 // 1 = error in byte write or set lock bit
+#define	SR_VPP			0x08080808 // 1 = Vpp is low
+#define SR_WRITE_SUSPEND	0x04040404 // 1 = byte write suspended
+#define SR_PROTECT		0x02020202 // 1 = lock bit set
+#define SR_RESERVED		0x01010101
+
+#define SR_ERRORS (SR_ERROR_ERASE|SR_ERROR_WRITE|SR_VPP|SR_PROTECT)
+
+/* Configuration options */
+
+#undef AUTOUNLOCK  /* automatically unlocks blocks before erasing */
+
+struct mtd_info *sharp_probe(struct map_info *);
+
+static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd);
+
+static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len,
+	size_t *retlen, u_char *buf);
+static int sharp_write(struct mtd_info *mtd, loff_t from, size_t len,
+	size_t *retlen, const u_char *buf);
+static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr);
+static void sharp_sync(struct mtd_info *mtd);
+static int sharp_suspend(struct mtd_info *mtd);
+static void sharp_resume(struct mtd_info *mtd);
+static void sharp_destroy(struct mtd_info *mtd);
+
+static int sharp_write_oneword(struct map_info *map, struct flchip *chip,
+	unsigned long adr, __u32 datum);
+static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip,
+	unsigned long adr);
+#ifdef AUTOUNLOCK
+static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
+	unsigned long adr);
+#endif
+
+
+struct sharp_info{
+	struct flchip *chip;
+	int bogus;
+	int chipshift;
+	int numchips;
+	struct flchip chips[1];
+};
+
+struct mtd_info *sharp_probe(struct map_info *map);
+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
+};
+
+
+struct mtd_info *sharp_probe(struct map_info *map)
+{
+	struct mtd_info *mtd = NULL;
+	struct sharp_info *sharp = NULL;
+	int width;
+
+	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+	if(!mtd)
+		return NULL;
+
+	sharp = kmalloc(sizeof(*sharp), GFP_KERNEL);
+	if(!sharp)
+		return NULL;
+
+	memset(mtd, 0, sizeof(*mtd));
+
+	width = sharp_probe_map(map,mtd);
+	if(!width){
+		kfree(mtd);
+		kfree(sharp);
+		return NULL;
+	}
+
+	mtd->priv = map;
+	mtd->type = MTD_NORFLASH;
+	mtd->erase = sharp_erase;
+	mtd->read = sharp_read;
+	mtd->write = sharp_write;
+	mtd->sync = sharp_sync;
+	mtd->suspend = sharp_suspend;
+	mtd->resume = sharp_resume;
+	mtd->flags = MTD_CAP_NORFLASH;
+	mtd->name = map->name;
+
+	memset(sharp, 0, sizeof(*sharp));
+	sharp->chipshift = 23;
+	sharp->numchips = 1;
+	sharp->chips[0].start = 0;
+	sharp->chips[0].state = FL_READY;
+	sharp->chips[0].mutex = &sharp->chips[0]._spinlock;
+	sharp->chips[0].word_write_time = 0;
+	init_waitqueue_head(&sharp->chips[0].wq);
+	spin_lock_init(&sharp->chips[0]._spinlock);
+
+	map->fldrv = &sharp_chipdrv;
+	map->fldrv_priv = sharp;
+
+	MOD_INC_USE_COUNT;
+	return mtd;
+}
+
+static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd)
+{
+	unsigned long tmp;
+	unsigned long base = 0;
+	u32 read0, read4;
+	int width = 4;
+
+	tmp = map->read32(map, base+0);
+
+	map->write32(map, CMD_READ_ID, base+0);
+
+	read0=map->read32(map, base+0);
+	read4=map->read32(map, base+4);
+	if(read0 == 0x89898989){
+		printk("Looks like sharp flash\n");
+		switch(read4){
+		case 0xaaaaaaaa:
+		case 0xa0a0a0a0:
+			/* aa - LH28F016SCT-L95 2Mx8, 32 64k blocks*/
+			/* a0 - LH28F016SCT-Z4  2Mx8, 32 64k blocks*/
+			mtd->erasesize = 0x10000 * width;
+			mtd->size = 0x200000 * width;
+			return width;
+		case 0xa6a6a6a6:
+			/* a6 - LH28F008SCT-L12 1Mx8, 16 64k blocks*/
+			/* a6 - LH28F008SCR-L85 1Mx8, 16 64k blocks*/
+			mtd->erasesize = 0x10000 * width;
+			mtd->size = 0x100000 * width;
+			return width;
+#if 0
+		case 0x00000000: /* unknown */
+			/* XX - LH28F004SCT 512kx8, 8 64k blocks*/
+			mtd->erasesize = 0x10000 * width;
+			mtd->size = 0x80000 * width;
+			return width;
+#endif
+		default:
+			printk("Sort-of looks like sharp flash, 0x%08x 0x%08x\n",
+				read0,read4);
+		}
+	}else if((map->read32(map, base+0) == CMD_READ_ID)){
+		/* RAM, probably */
+		printk("Looks like RAM\n");
+		map->write32(map, tmp, base+0);
+	}else{
+		printk("Doesn't look like sharp flash, 0x%08x 0x%08x\n",
+			read0,read4);
+	}
+
+	return 0;
+}
+
+/* This function returns with the chip->mutex lock held. */
+static int sharp_wait(struct map_info *map, struct flchip *chip)
+{
+	__u16 status;
+	unsigned long timeo = jiffies + HZ;
+	DECLARE_WAITQUEUE(wait, current);
+	int adr = 0;
+
+retry:
+	spin_lock_bh(chip->mutex);
+
+	switch(chip->state){
+	case FL_READY:
+		map->write32(map,CMD_READ_STATUS,adr);
+		chip->state = FL_STATUS;
+	case FL_STATUS:
+		status = map->read32(map,adr);
+//printk("status=%08x\n",status);
+
+		udelay(100);
+		if((status & SR_READY)!=SR_READY){
+//printk(".status=%08x\n",status);
+			udelay(100);
+		}
+		break;
+	default:
+		printk("Waiting for chip\n");
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+
+		spin_unlock_bh(chip->mutex);
+
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+
+		if(signal_pending(current))
+			return -EINTR;
+
+		timeo = jiffies + HZ;
+
+		goto retry;
+	}
+
+	map->write32(map,CMD_RESET, adr);
+
+	chip->state = FL_READY;
+
+	return 0;
+}
+
+static void sharp_release(struct flchip *chip)
+{
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+}
+
+static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len,
+	size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct sharp_info *sharp = map->fldrv_priv;
+	int chipnum;
+	int ret = 0;
+	int ofs = 0;
+
+	chipnum = (from >> sharp->chipshift);
+	ofs = from & ((1 << sharp->chipshift)-1);
+
+	*retlen = 0;
+
+	while(len){
+		unsigned long thislen;
+
+		if(chipnum>=sharp->numchips)
+			break;
+
+		thislen = len;
+		if(ofs+thislen >= (1<<sharp->chipshift))
+			thislen = (1<<sharp->chipshift) - ofs;
+
+		ret = sharp_wait(map,&sharp->chips[chipnum]);
+		if(ret<0)
+			break;
+
+		map->copy_from(map,buf,ofs,thislen);
+
+		sharp_release(&sharp->chips[chipnum]);
+
+		*retlen += thislen;
+		len -= thislen;
+		buf += thislen;
+
+		ofs = 0;
+		chipnum++;
+	}
+	return ret;
+}
+
+static int sharp_write(struct mtd_info *mtd, loff_t to, size_t len,
+	size_t *retlen, const u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct sharp_info *sharp = map->fldrv_priv;
+	int ret = 0;
+	int i,j;
+	int chipnum;
+	unsigned long ofs;
+	union { u32 l; unsigned char uc[4]; } tbuf;
+
+	*retlen = 0;
+
+	while(len){
+		tbuf.l = 0xffffffff;
+		chipnum = to >> sharp->chipshift;
+		ofs = to & ((1<<sharp->chipshift)-1);
+
+		j=0;
+		for(i=ofs&3;i<4 && len;i++){
+			tbuf.uc[i] = *buf;
+			buf++;
+			to++;
+			len--;
+			j++;
+		}
+		sharp_write_oneword(map, &sharp->chips[chipnum], ofs&~3, tbuf.l);
+		if(ret<0)
+			return ret;
+		(*retlen)+=j;
+	}
+
+	return 0;
+}
+
+static int sharp_write_oneword(struct map_info *map, struct flchip *chip,
+	unsigned long adr, __u32 datum)
+{
+	int ret;
+	int timeo;
+	int try;
+	int i;
+	int status = 0;
+
+	ret = sharp_wait(map,chip);
+
+	for(try=0;try<10;try++){
+		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);
+
+		chip->state = FL_WRITING;
+
+		timeo = jiffies + (HZ/2);
+
+		map->write32(map,CMD_READ_STATUS,adr);
+		for(i=0;i<100;i++){
+			status = map->read32(map,adr);
+			if((status & SR_READY)==SR_READY)
+				break;
+		}
+		if(i==100){
+			printk("sharp: timed out writing\n");
+		}
+
+		if(!(status&SR_ERRORS))
+			break;
+
+		printk("sharp: error writing byte at addr=%08lx status=%08x\n",adr,status);
+
+		map->write32(map,CMD_CLEAR_STATUS,adr);
+	}
+	map->write32(map,CMD_RESET,adr);
+	chip->state = FL_READY;
+
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+
+	return 0;
+}
+
+static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct map_info *map = mtd->priv;
+	struct sharp_info *sharp = map->fldrv_priv;
+	unsigned long adr,len;
+	int chipnum, ret=0;
+
+//printk("sharp_erase()\n");
+	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;
+
+	chipnum = instr->addr >> sharp->chipshift;
+	adr = instr->addr & ((1<<sharp->chipshift)-1);
+	len = instr->len;
+
+	while(len){
+		ret = sharp_erase_oneblock(map, &sharp->chips[chipnum], adr);
+		if(ret)return ret;
+
+		adr += mtd->erasesize;
+		len -= mtd->erasesize;
+		if(adr >> sharp->chipshift){
+			adr = 0;
+			chipnum++;
+			if(chipnum>=sharp->numchips)
+				break;
+		}
+	}
+
+	if(instr->callback)
+		instr->callback(instr);
+
+	return 0;
+}
+
+static int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip,
+	unsigned long adr)
+{
+	int ret;
+	int timeo;
+	int status;
+	DECLARE_WAITQUEUE(wait, current);
+
+	map->write32(map,CMD_READ_STATUS,adr);
+	status = map->read32(map,adr);
+
+	timeo = jiffies + HZ;
+
+	while(jiffies<timeo){
+		map->write32(map,CMD_READ_STATUS,adr);
+		status = map->read32(map,adr);
+		if((status & SR_READY)==SR_READY){
+			ret = 0;
+			goto out;
+		}
+		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+
+		//spin_unlock_bh(chip->mutex);
+
+		schedule_timeout(1);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+
+		//spin_lock_bh(chip->mutex);
+		
+		if (signal_pending(current)){
+			ret = -EINTR;
+			goto out;
+		}
+		
+	}
+	ret = -ETIME;
+out:
+	return ret;
+}
+
+static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip,
+	unsigned long adr)
+{
+	int ret;
+	//int timeo;
+	int status;
+	//int i;
+
+//printk("sharp_erase_oneblock()\n");
+
+#ifdef AUTOUNLOCK
+	/* This seems like a good place to do an unlock */
+	sharp_unlock_oneblock(map,chip,adr);
+#endif
+
+	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);
+
+	if(!(status&SR_ERRORS)){
+		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);
+
+	//spin_unlock_bh(chip->mutex);
+
+	return -EIO;
+}
+
+#ifdef AUTOUNLOCK
+static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
+	unsigned long adr)
+{
+	int i;
+	int status;
+
+	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);
+	printk("status=%08x\n",status);
+
+	for(i=0;i<1000;i++){
+		//map->write32(map,CMD_READ_STATUS,adr);
+		status = map->read32(map,adr);
+		if((status & SR_READY)==SR_READY)
+			break;
+		udelay(100);
+	}
+	if(i==1000){
+		printk("sharp: timed out unlocking block\n");
+	}
+
+	if(!(status&SR_ERRORS)){
+		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);
+}
+#endif
+
+static void sharp_sync(struct mtd_info *mtd)
+{
+	//printk("sharp_sync()\n");
+}
+
+static int sharp_suspend(struct mtd_info *mtd)
+{
+	printk("sharp_suspend()\n");
+	return -EINVAL;
+}
+
+static void sharp_resume(struct mtd_info *mtd)
+{
+	printk("sharp_resume()\n");
+	
+}
+
+static void sharp_destroy(struct mtd_info *mtd)
+{
+	printk("sharp_destroy()\n");
+
+}
+
+#if LINUX_VERSION_CODE < 0x020212 && defined(MODULE)
+#define sharp_probe_init init_module
+#define sharp_probe_exit cleanup_module
+#endif
+
+int __init sharp_probe_init(void)
+{
+	printk("MTD Sharp chip driver <ds@lineo.com>\n");
+
+	register_mtd_chip_driver(&sharp_chipdrv);
+
+	return 0;
+}
+
+static void __exit sharp_probe_exit(void)
+{
+	unregister_mtd_chip_driver(&sharp_chipdrv);
+}
+
+module_init(sharp_probe_init);
+module_exit(sharp_probe_exit);
+
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/devices/Config.in linux/drivers/mtd/devices/Config.in
--- v2.4.5/linux/drivers/mtd/devices/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/devices/Config.in	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,51 @@
+# drivers/mtd/maps/Config.in
+
+# $Id: Config.in,v 1.2 2001/04/29 16:24:34 dwmw2 Exp $
+
+mainmenu_option next_comment
+
+comment 'Self-contained MTD device drivers'
+dep_tristate '  Ramix PMC551 PCI Mezzanine RAM card support' CONFIG_MTD_PMC551 $CONFIG_MTD $CONFIG_PCI
+if [ "$CONFIG_MTD_PMC551" = "y" -o  "$CONFIG_MTD_PMC551" = "m" ]; then
+   bool '    PMC551 256M DRAM Bugfix' CONFIG_MTD_PMC551_BUGFIX
+   bool '    PMC551 Debugging' CONFIG_MTD_PMC551_DEBUG
+fi
+dep_tristate '  Uncached system RAM' CONFIG_MTD_SLRAM $CONFIG_MTD
+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
+   int 'MTDRAM erase block size in KiB' CONFIG_MTDRAM_ERASE_SIZE 128
+   if [ "$CONFIG_MTD_MTDRAM" = "y" ]; then #If not a module (I don't want to test it as a module)
+      hex 'SRAM Hexadecimal Absolute position or 0' CONFIG_MTDRAM_ABS_POS 0
+   fi
+fi
+
+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
+      define_bool CONFIG_MTD_DOCPROBE y
+   else
+      if [ "$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" -o "$CONFIG_MTD_DOCPROBE" = "m" ]; then
+      bool '    Advanced detection options for DiskOnChip' CONFIG_MTD_DOCPROBE_ADVANCED
+      if [ "$CONFIG_MTD_DOCPROBE_ADVANCED" = "n" ]; then
+         define_hex CONFIG_MTD_DOCPROBE_ADDRESS 0
+         define_bool CONFIG_MTD_DOCPROBE_HIGH n
+         define_bool CONFIG_MTD_DOCPROBE_55AA n
+      else
+         hex  '    Physical address of DiskOnChip' CONFIG_MTD_DOCPROBE_ADDRESS 0x0000
+         bool '    Probe high addresses' CONFIG_MTD_DOCPROBE_HIGH
+         bool '    Probe for 0x55 0xAA BIOS Extension Signature' CONFIG_MTD_DOCPROBE_55AA
+      fi
+   fi
+
+
+endmenu
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/devices/Makefile linux/drivers/mtd/devices/Makefile
--- v2.4.5/linux/drivers/mtd/devices/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/devices/Makefile	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,23 @@
+#
+# linux/drivers/devices/Makefile
+#
+# $Id: Makefile,v 1.2 2001/04/19 22:12:36 dwmw2 Exp $
+
+O_TARGET	:= devlink.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_SLRAM)		+= slram.o
+obj-$(CONFIG_MTD_PMC551)	+= pmc551.o
+obj-$(CONFIG_MTD_MTDRAM)	+= mtdram.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/devices/doc1000.c linux/drivers/mtd/devices/doc1000.c
--- v2.4.5/linux/drivers/mtd/devices/doc1000.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/devices/doc1000.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,597 @@
+/*======================================================================
+
+  $Id: doc1000.c,v 1.11 2000/11/24 13:43:16 dwmw2 Exp $
+
+======================================================================*/
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <stdarg.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/iflash.h>
+
+/* Parameters that can be set with 'insmod' */
+
+static u_long base              = 0xe0000;
+static int erase_timeout	= 10*HZ;	/* in ticks */
+static int retry_limit		= 4;		/* write retries */
+static u_long max_tries       	= 4096;		/* status polling */
+
+MODULE_PARM(base,"l");
+MODULE_PARM(erase_timeout, "i");
+MODULE_PARM(retry_limit, "i");
+MODULE_PARM(max_tries, "i");
+
+#define WINDOW_SIZE 0x2000
+#define WINDOW_MASK (WINDOW_SIZE - 1)
+#define PAGEREG_LO (WINDOW_SIZE)
+#define PAGEREG_HI (WINDOW_SIZE + 2)
+
+static struct mtd_info *mymtd;
+static struct timer_list flashcard_timer;
+
+#define MAX_CELLS		32
+#define MAX_FLASH_DEVICES       8
+
+/* A flash region is composed of one or more "cells", where we allow
+   simultaneous erases if they are in different cells */
+
+
+
+struct mypriv {
+	u_char *baseaddr;
+	u_short curpage;
+	u_char locked;
+	u_short numdevices;
+	u_char interleave;
+	struct erase_info *cur_erases;
+	wait_queue_head_t wq;
+	u_char devstat[MAX_FLASH_DEVICES];
+	u_long devshift;
+};
+
+
+static void flashcard_periodic(u_long data);
+static int flashcard_erase (struct mtd_info *mtd, struct erase_info *instr);
+static int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+static int flashcard_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
+static void flashcard_sync (struct mtd_info *mtd);
+
+static inline void resume_erase(volatile u_char *addr);
+static inline int suspend_erase(volatile u_char *addr);
+static inline int byte_write (volatile u_char *addr, u_char byte);
+static inline int word_write (volatile u_char *addr, __u16 word);
+static inline int check_write(volatile u_char *addr);
+static inline void block_erase (volatile u_char *addr);
+static inline int check_erase(volatile u_char *addr);
+
+#ifdef CONFIG_SMP
+#warning This is definitely not SMP safe. Lock the paging mechanism.
+#endif
+
+static u_char *pagein(struct mtd_info *mtd, u_long addr)
+{
+  struct mypriv *priv=mtd->priv;
+  u_short page = addr >> 13;
+
+  priv->baseaddr[PAGEREG_LO] = page & 0xff;
+  priv->baseaddr[PAGEREG_HI] = page >> 8;
+  priv->curpage = page;
+  
+  return &priv->baseaddr[addr & WINDOW_MASK];
+}
+
+
+void flashcard_sync (struct mtd_info *mtd)
+{
+	struct mypriv *priv=mtd->priv;
+
+	flashcard_periodic((u_long) mtd);
+	printk("sync...");
+	if (priv->cur_erases)
+		interruptible_sleep_on(&priv->wq);
+	printk("Done.\n");
+}
+
+int flashcard_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+	u_char *pageaddr;
+	struct mypriv *priv=mtd->priv;
+	struct erase_info **tmp=&priv->cur_erases;
+	
+	if (instr->len != mtd->erasesize)
+		return -EINVAL;
+	if (instr->addr + instr->len > mtd->size)
+		return -EINVAL;
+
+	pageaddr=pagein(mtd,instr->addr);
+	instr->mtd = mtd;
+	instr->dev = instr->addr >> priv->devshift;
+	instr->cell = (instr->addr - (instr->dev << priv->devshift)) / mtd->erasesize;
+	instr->next = NULL;
+	instr->state = MTD_ERASE_PENDING;
+	
+	while (*tmp)
+	{
+		tmp = &((*tmp) -> next);
+	}
+	
+	*tmp = instr;
+	flashcard_periodic((u_long)mtd);
+	return 0;
+}
+
+
+int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+ 	u_char *pageaddr=pagein(mtd,from);
+	struct mypriv *priv=mtd->priv;
+	u_char device = from >> priv->devshift;
+	u_char cell = (int) (from - (device << priv->devshift)) / mtd->erasesize;
+	int ret = 0, timeron = 0;
+
+	if ((from & WINDOW_MASK) + len <= WINDOW_SIZE)
+		*retlen = len;
+	else
+		*retlen = WINDOW_SIZE - (from & WINDOW_MASK);
+
+	if (priv->devstat[device])
+	{
+		
+		/* There is an erase in progress or pending for this device. Stop it */
+		timeron = del_timer(&flashcard_timer);
+		
+		if (priv->cur_erases && priv->cur_erases->cell == cell) 
+			
+		{
+			/* The erase is on the current cell. Just return all 0xff */ 
+			add_timer(&flashcard_timer);
+			
+			
+			printk("Cell %d currently erasing. Setting to all 0xff\n",cell);
+			memset(buf, 0xff, *retlen);
+			return 0;
+		}
+		if (priv->devstat[device] == MTD_ERASING)
+		{
+			ret = suspend_erase(pageaddr);
+			priv->devstat[device] = MTD_ERASE_SUSPEND;
+		       
+			if (ret) 
+			{
+				printk("flashcard: failed to suspend erase\n");
+				add_timer (&flashcard_timer);
+				return ret;
+			}
+		}
+
+	}
+
+	writew(IF_READ_ARRAY, (u_long)pageaddr & ~1);
+	
+	ret = 0;
+	memcpy (buf, pageaddr, *retlen);
+	
+	writew(IF_READ_CSR, (u_long)pageaddr & ~1);
+	
+	
+	if (priv->devstat[device] & MTD_ERASE_SUSPEND)
+	{
+		resume_erase(pageaddr);
+		priv->devstat[device]=MTD_ERASING;
+	}
+
+
+	if (timeron) add_timer (&flashcard_timer);
+		
+	return ret;
+}
+
+
+int flashcard_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;
+ 	u_char *endaddr, *startaddr;
+	register u_char *pageaddr;
+	u_char device = to >> priv->devshift;
+/*	jiffies_t oldj=jiffies;*/
+	int ret;
+
+	while (priv->devstat[device])
+	{
+		flashcard_sync(mtd);
+	}
+
+	if ((to & WINDOW_MASK) + len <= WINDOW_SIZE)
+		*retlen = len;
+	else
+		*retlen = WINDOW_SIZE - (to & WINDOW_MASK);
+	
+	pageaddr = pagein(mtd, to);
+	startaddr = (u_char *)((u_long) pageaddr & ~1);
+	endaddr = pageaddr+(*retlen);
+
+
+
+	/* Set up to read */
+	writew(IF_READ_CSR, startaddr);
+	
+	/* Make sure it's aligned by reading the first byte if necessary */
+	if (to & 1)
+	{
+		/* Unaligned access */
+
+		u_char cbuf;
+
+		cbuf = *buf;
+
+		if (!((u_long)pageaddr & 0xf))
+			schedule();
+			
+		ret = byte_write(pageaddr, cbuf);
+		if (ret) return ret;
+
+		pageaddr++; buf++;
+	}
+
+
+	for ( ; pageaddr + 1 < endaddr; buf += 2, pageaddr += 2)
+		{
+			/* if ((u_long)pageaddr & 0xf) schedule();*/
+			
+			ret = word_write(pageaddr, *(__u16 *)buf);
+			if (ret) 
+				return ret;
+		}
+	
+	if (pageaddr != endaddr)
+	{
+		/* One more byte to write at the end. */
+		u_char cbuf;
+
+		cbuf = *buf;
+
+		ret = byte_write(pageaddr, cbuf);
+
+		if (ret) return ret;
+	}
+
+	return check_write(startaddr);
+/*	printk("Time taken in flashcard_write: %lx jiffies\n",jiffies - oldj);*/
+}
+
+
+
+
+/*====================================================================*/
+
+static inline int byte_write (volatile u_char *addr, u_char byte)
+{
+	register u_char status;
+ 	register u_short i = 0;
+  	
+ 	do {
+		status = readb(addr);
+		if (status & CSR_WR_READY)
+		{
+			writeb(IF_WRITE & 0xff, addr);
+			writeb(byte, addr);
+			return 0;
+		}
+		i++;
+	} while(i < max_tries);
+
+		
+	printk(KERN_NOTICE "flashcard: byte_write timed out, status 0x%x\n",status);
+	return -EIO;
+}
+
+static inline int word_write (volatile u_char *addr, __u16 word)
+{
+	register u_short status;
+	register u_short i = 0;
+	
+	do {
+		status = readw(addr);
+		if ((status & CSR_WR_READY) == CSR_WR_READY)
+		{
+			writew(IF_WRITE, addr);
+			writew(word, addr);
+			return 0;
+		}
+		i++;
+	} while(i < max_tries);
+		
+	printk(KERN_NOTICE "flashcard: word_write timed out at %p, status 0x%x\n", addr, status);
+	return -EIO;
+}
+
+static inline void block_erase (volatile u_char *addr)
+{
+	writew(IF_BLOCK_ERASE, addr);
+	writew(IF_CONFIRM, addr);
+}
+
+
+static inline int check_erase(volatile u_char *addr)
+{
+	__u16 status;
+	
+/*	writew(IF_READ_CSR, addr);*/
+	status = readw(addr);
+	
+
+	if ((status & CSR_WR_READY) != CSR_WR_READY)
+		return -EBUSY;
+	
+	if (status & (CSR_ERA_ERR | CSR_VPP_LOW | CSR_WR_ERR)) 
+	{
+		printk(KERN_NOTICE "flashcard: erase failed, status 0x%x\n",
+		       status);
+		return -EIO;
+	}
+	
+	return 0;
+}
+
+static inline int suspend_erase(volatile u_char *addr)
+{
+	__u16 status;
+	u_long i = 0;
+	
+	writew(IF_ERASE_SUSPEND, addr);
+	writew(IF_READ_CSR, addr);
+	
+	do {
+		status = readw(addr);
+		if ((status & CSR_WR_READY) == CSR_WR_READY)
+			return 0;
+		i++;
+	} while(i < max_tries);
+
+	printk(KERN_NOTICE "flashcard: suspend_erase timed out, status 0x%x\n", status);
+	return -EIO;
+
+}
+
+static inline void resume_erase(volatile u_char *addr)
+{
+	__u16 status;
+	
+	writew(IF_READ_CSR, addr);
+	status = readw(addr);
+	
+	/* Only give resume signal if the erase is really suspended */
+	if (status & CSR_ERA_SUSPEND)
+		writew(IF_CONFIRM, addr);
+}
+
+static inline void reset_block(volatile u_char *addr)
+{
+	u_short i;
+	__u16 status;
+
+	writew(IF_CLEAR_CSR, addr);
+
+	for (i = 0; i < 100; i++) {
+		writew(IF_READ_CSR, addr);
+		status = readw(addr);
+		if (status != 0xffff) break;
+		udelay(1000);
+	}
+
+	writew(IF_READ_CSR, addr);
+}
+
+static inline int check_write(volatile u_char *addr)
+{
+	u_short status, i = 0;
+	
+	writew(IF_READ_CSR, addr);
+	
+	do {
+		status = readw(addr);
+		if (status & (CSR_WR_ERR | CSR_VPP_LOW))
+		{
+			printk(KERN_NOTICE "flashcard: write failure at %p, status 0x%x\n", addr, status);
+			reset_block(addr);
+			return -EIO;
+		}
+		if ((status & CSR_WR_READY) == CSR_WR_READY)
+			return 0;
+		i++;
+	} while (i < max_tries);
+
+	printk(KERN_NOTICE "flashcard: write timed out at %p, status 0x%x\n", addr, status);
+	return -EIO;
+}
+
+
+/*====================================================================*/
+
+
+
+static void flashcard_periodic(unsigned long data)
+{
+	register struct mtd_info *mtd = (struct mtd_info *)data;
+	register struct mypriv *priv = mtd->priv;
+	struct erase_info *erase = priv->cur_erases;
+	u_char *pageaddr;
+
+	del_timer (&flashcard_timer);
+
+	if (!erase)
+		return;
+
+	pageaddr = pagein(mtd, erase->addr);
+	
+	if (erase->state == MTD_ERASE_PENDING)
+	{
+		block_erase(pageaddr);
+		priv->devstat[erase->dev] = erase->state = MTD_ERASING;
+		erase->time = jiffies;
+		erase->retries = 0;
+	}
+	else if (erase->state == MTD_ERASING)
+	{
+		/* It's trying to erase. Check whether it's finished */
+
+		int ret = check_erase(pageaddr);
+
+		if (!ret)
+		{
+			/* It's finished OK */
+			priv->devstat[erase->dev] = 0;
+			priv->cur_erases = erase->next;
+			erase->state = MTD_ERASE_DONE;
+			if (erase->callback)
+				(*(erase->callback))(erase);
+			else
+				kfree(erase);
+		}
+		else if (ret == -EIO)
+		{
+			if (++erase->retries > retry_limit)
+			{
+				printk("Failed too many times. Giving up\n");
+				priv->cur_erases = erase->next;
+				priv->devstat[erase->dev] = 0;
+				erase->state = MTD_ERASE_FAILED;
+				if (erase->callback)
+					(*(erase->callback))(erase);
+				else
+					kfree(erase);
+			}
+			else
+				priv->devstat[erase->dev] = erase->state = MTD_ERASE_PENDING;
+		}
+		else if (erase->time + erase_timeout < jiffies)
+		{
+			printk("Flash erase timed out. The world is broken.\n");
+
+			/* Just ignore and hope it goes away. For a while, read ops will give the CSR
+			   and writes won't work. */
+
+			priv->cur_erases = erase->next;
+			priv->devstat[erase->dev] = 0;
+			erase->state = MTD_ERASE_FAILED;
+			if (erase->callback)
+					(*(erase->callback))(erase);
+				else
+					kfree(erase);
+		}
+	}
+
+	if (priv->cur_erases)
+	{
+		flashcard_timer.expires = jiffies + HZ;
+		add_timer (&flashcard_timer);
+	}
+	else 
+		wake_up_interruptible(&priv->wq);
+
+}
+
+#if defined (MODULE) && LINUX_VERSION_CODE < 0x20211
+#define init_doc1000 init_module
+#define cleanup_doc1000 cleanup_module
+#endif
+
+int __init init_doc1000(void)
+{
+	struct mypriv *priv;
+
+	if (!base)
+	{
+		printk(KERN_NOTICE "flashcard: No start address for memory device.\n");
+		return -EINVAL;
+	}
+
+	mymtd  = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+
+	if (!mymtd)
+	{
+		printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device.\n");
+		return -ENOMEM;
+	}
+
+	memset(mymtd,0,sizeof(struct mtd_info));
+
+	mymtd->priv = (void *) kmalloc (sizeof(struct mypriv), GFP_KERNEL);
+	if (!mymtd->priv)
+	  {
+	    kfree(mymtd);
+	    printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device's private data.\n");
+	    return -ENOMEM;
+	  }
+	
+
+
+
+	priv=mymtd->priv;
+	init_waitqueue_head(&priv->wq);
+
+	memset (priv,0,sizeof(struct mypriv));
+
+	priv->baseaddr = phys_to_virt(base);
+	priv->numdevices = 4;
+	
+	mymtd->name = "M-Systems DiskOnChip 1000";
+
+	mymtd->size = 0x100000;
+	mymtd->flags = MTD_CLEAR_BITS | MTD_ERASEABLE;
+        mymtd->erase = flashcard_erase;
+	mymtd->point = NULL;
+	mymtd->unpoint = NULL;
+	mymtd->read = flashcard_read;
+	mymtd->write = flashcard_write;
+
+	mymtd->sync = flashcard_sync;
+	mymtd->erasesize = 0x10000;
+	//	mymtd->interleave = 2;
+	priv->devshift =  24;
+	mymtd->type = MTD_NORFLASH;
+	
+	if (add_mtd_device(mymtd))
+	{
+		printk(KERN_NOTICE "MTD device registration failed!\n");
+		kfree(mymtd->priv);
+		kfree(mymtd);
+		return -EAGAIN;
+	}
+	
+	init_timer(&flashcard_timer);
+	flashcard_timer.function = flashcard_periodic;
+	flashcard_timer.data = (u_long)mymtd;
+	return 0;
+}
+
+static void __init cleanup_doc1000(void)
+{
+	kfree (mymtd->priv);
+	del_mtd_device(mymtd);
+	kfree(mymtd);
+}
+
+#if LINUX_VERSION_CODE >= 0x20211
+module_init(init_doc1000);
+module_exit(cleanup_doc1000);
+#endif
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/devices/doc2000.c linux/drivers/mtd/devices/doc2000.c
--- v2.4.5/linux/drivers/mtd/devices/doc2000.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/devices/doc2000.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,1121 @@
+
+/*
+ * Linux driver for Disk-On-Chip 2000 and Millennium
+ * (c) 1999 Machine Vision Holdings, Inc.
+ * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
+ *
+ * $Id: doc2000.c,v 1.43 2001/06/02 14:30:43 dwmw2 Exp $
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ids.h>
+#include <linux/mtd/doc2000.h>
+
+#define DOC_SUPPORT_2000
+#define DOC_SUPPORT_MILLENNIUM
+
+#ifdef DOC_SUPPORT_2000
+#define DoC_is_2000(doc) (doc->ChipID == DOC_ChipID_Doc2k)
+#else
+#define DoC_is_2000(doc) (0)
+#endif
+
+#ifdef DOC_SUPPORT_MILLENNIUM
+#define DoC_is_Millennium(doc) (doc->ChipID == DOC_ChipID_DocMil)
+#else
+#define DoC_is_Millennium(doc) (0)
+#endif
+
+/* #define ECC_DEBUG */
+
+/* I have no idea why some DoC chips can not use memcpy_from|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);
+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);
+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 *doc2klist = NULL;
+
+/* Perform the required delay cycles by reading from the appropriate register */
+static void DoC_Delay(struct DiskOnChip *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
+			dummy = ReadDOC(doc->virtadr, DOCStatus);
+	}
+	
+}
+
+/* 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;
+	unsigned short 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, CDSNControl) & CDSN_CTRL_FR_B) && --c)
+		;
+
+	if (c == 0)
+		DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
+
+	return (c == 0);
+}
+
+static inline int DoC_WaitReady(struct DiskOnChip *doc)
+{
+	unsigned long docptr = doc->virtadr;
+	/* This is inline, to optimise the common case, where it's ready instantly */
+	int ret = 0;
+
+	/* 4 read form NOP register should be issued in prior to the read from CDSNControl
+	   see Software Requirement 11.4 item 2. */
+	DoC_Delay(doc, 4);
+
+	if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
+		/* Call the out-of-line routine to wait */
+		ret = _DoC_WaitReady(doc);
+
+	/* issue 2 read from NOP register after reading from CDSNControl register
+	   see Software Requirement 11.4 item 2. */
+	DoC_Delay(doc, 2);
+
+	return ret;
+}
+
+/* DoC_Command: Send a flash command to the flash chip through the CDSN Slow IO register to
+   bypass 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 int DoC_Command(struct DiskOnChip *doc, unsigned char command,
+			      unsigned char xtraflags)
+{
+	unsigned long docptr = doc->virtadr;
+
+	if (DoC_is_2000(doc))
+		xtraflags |= CDSN_CTRL_FLASH_IO;
+
+	/* Assert the CLE (Command Latch Enable) line to the flash chip */
+	WriteDOC(xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, docptr, CDSNControl);
+	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
+
+	if (DoC_is_Millennium(doc))
+		WriteDOC(command, docptr, CDSNSlowIO);
+
+	/* Send the command */
+	WriteDOC_(command, docptr, doc->ioreg);
+
+	/* Lower the CLE line */
+	WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
+	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
+
+	/* Wait for the chip to respond - Software requirement 11.4.1 (extended for any command) */
+	return DoC_WaitReady(doc);
+}
+
+/* DoC_Address: Set the current address for the flash chip through the CDSN Slow IO register to
+   bypass 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 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;
+
+	if (DoC_is_2000(doc))
+		xtraflags1 |= CDSN_CTRL_FLASH_IO;
+
+	/* Assert the ALE (Address Latch Enable) line to the flash chip */
+	WriteDOC(xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, docptr, CDSNControl);
+
+	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
+
+	/* Send the address */
+	/* Devices with 256-byte page are addressed as:
+	   Column (bits 0-7), Page (bits 8-15, 16-23, 24-31)
+	   * there is no device on the market with page256
+	   and more than 24 bits.
+	   Devices with 512-byte page are addressed as:
+	   Column (bits 0-7), Page (bits 9-16, 17-24, 25-31)
+	   * 25-31 is sent only if the chip support it.
+	   * bit 8 changes the read command to be sent
+	   (NAND_CMD_READ0 or NAND_CMD_READ1).
+	 */
+
+	if (numbytes == ADDR_COLUMN || numbytes == ADDR_COLUMN_PAGE) {
+		if (DoC_is_Millennium(doc))
+			WriteDOC(ofs & 0xff, docptr, CDSNSlowIO);
+		WriteDOC_(ofs & 0xff, docptr, doc->ioreg);
+	}
+
+	if (doc->page256) {
+		ofs = ofs >> 8;
+	} else {
+		ofs = ofs >> 9;
+	}
+
+	if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE) {
+		for (i = 0; i < doc->pageadrlen; i++, ofs = ofs >> 8) {
+			if (DoC_is_Millennium(doc))
+				WriteDOC(ofs & 0xff, docptr, CDSNSlowIO);
+			WriteDOC_(ofs & 0xff, docptr, doc->ioreg);
+		}
+	}
+
+	DoC_Delay(doc, 2);	/* Needed for some slow flash chips. mf. */
+	
+	/* FIXME: The SlowIO's for millennium could be replaced by 
+	   a single WritePipeTerm here. mf. */
+
+	/* Lower the ALE line */
+	WriteDOC(xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr,
+		 CDSNControl);
+
+	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
+
+	/* Wait for the chip to respond - Software requirement 11.4.1 */
+	return DoC_WaitReady(doc);
+}
+
+/* Read a buffer from DoC, taking care of Millennium odditys */
+static void DoC_ReadBuf(struct DiskOnChip *doc, u_char * buf, int len)
+{
+	int dummy;
+	int modulus = 0xffff;
+	unsigned long docptr;
+	int i;
+
+	docptr = doc->virtadr;
+
+	if (len <= 0)
+		return;
+
+	if (DoC_is_Millennium(doc)) {
+		/* Read the data via the internal pipeline through CDSN IO register,
+		   see Pipelined Read Operations 11.3 */
+		dummy = ReadDOC(docptr, ReadPipeInit);
+
+		/* Millennium should use the LastDataRead register - Pipeline Reads */
+		len--;
+
+		/* This is needed for correctly ECC calculation */
+		modulus = 0xff;
+	}
+
+	for (i = 0; i < len; i++)
+		buf[i] = ReadDOC_(docptr, doc->ioreg + (i & modulus));
+
+	if (DoC_is_Millennium(doc)) {
+		buf[i] = ReadDOC(docptr, LastDataRead);
+	}
+}
+
+/* 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;
+	int i;
+
+	docptr = doc->virtadr;
+
+	if (len <= 0)
+		return;
+
+	for (i = 0; i < len; i++)
+		WriteDOC_(buf[i], docptr, doc->ioreg + i);
+
+	if (DoC_is_Millennium(doc)) {
+		WriteDOC(0x00, docptr, WritePipeTerm);
+	}
+}
+
+
+/* DoC_SelectChip: Select a given flash chip within the current floor */
+
+static inline int DoC_SelectChip(struct DiskOnChip *doc, int chip)
+{
+	unsigned long docptr = doc->virtadr;
+
+	/* Software requirement 11.4.4 before writing DeviceSelect */
+	/* Deassert the CE line to eliminate glitches on the FCE# outputs */
+	WriteDOC(CDSN_CTRL_WP, docptr, CDSNControl);
+	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
+
+	/* Select the individual flash chip requested */
+	WriteDOC(chip, docptr, CDSNDeviceSelect);
+	DoC_Delay(doc, 4);
+
+	/* Reassert the CE line */
+	WriteDOC(CDSN_CTRL_CE | CDSN_CTRL_FLASH_IO | CDSN_CTRL_WP, docptr,
+		 CDSNControl);
+	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
+
+	/* Wait for it to be ready */
+	return DoC_WaitReady(doc);
+}
+
+/* DoC_SelectFloor: Select a given floor (bank of flash chips) */
+
+static inline int DoC_SelectFloor(struct DiskOnChip *doc, int floor)
+{
+	unsigned long docptr = doc->virtadr;
+
+	/* Select the floor (bank) of chips required */
+	WriteDOC(floor, docptr, FloorSelect);
+
+	/* Wait for the chip to be ready */
+	return DoC_WaitReady(doc);
+}
+
+/* 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;
+	volatile char dummy;
+
+	/* Page in the required floor/chip */
+	DoC_SelectFloor(doc, floor);
+	DoC_SelectChip(doc, chip);
+
+	/* Reset the chip */
+	if (DoC_Command(doc, NAND_CMD_RESET, CDSN_CTRL_WP)) {
+		DEBUG(MTD_DEBUG_LEVEL2,
+		      "DoC_Command (reset) for %d,%d returned true\n",
+		      floor, chip);
+		return 0;
+	}
+
+
+	/* Read the NAND chip ID: 1. Send ReadID command */
+	if (DoC_Command(doc, NAND_CMD_READID, CDSN_CTRL_WP)) {
+		DEBUG(MTD_DEBUG_LEVEL2,
+		      "DoC_Command (ReadID) for %d,%d returned true\n",
+		      floor, chip);
+		return 0;
+	}
+
+	/* Read the NAND chip ID: 2. Send address byte zero */
+	DoC_Address(doc, ADDR_COLUMN, 0, CDSN_CTRL_WP, 0);
+
+	/* Read the manufacturer and device id codes from the device */
+
+	/* CDSN Slow IO register see Software Requirement 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. */
+	dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
+	DoC_Delay(doc, 2);
+	id = ReadDOC_(doc->virtadr, doc->ioreg);
+
+	/* No response - return failure */
+	if (mfr == 0xff || mfr == 0)
+		return 0;
+
+	/* Check it's the same as the first chip we identified. 
+	 * M-Systems say that any given DiskOnChip device should only
+	 * contain _one_ type of flash part, although that's not a 
+	 * hardware restriction. */
+	if (doc->mfr) {
+		if (doc->mfr == mfr && doc->id == id)
+			return 1;	/* This is another the same the first */
+		else
+			printk(KERN_WARNING
+			       "Flash chip at floor %d, chip %d is different:\n",
+			       floor, chip);
+	}
+
+	/* Print and store the manufacturer and ID codes. */
+	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
+		if (mfr == nand_flash_ids[i].manufacture_id &&
+		    id == nand_flash_ids[i].model_id) {
+			printk(KERN_INFO
+			       "Flash chip found: Manufacturer ID: %2.2X, "
+			       "Chip ID: %2.2X (%s)\n", mfr, id,
+			       nand_flash_ids[i].name);
+			if (!doc->mfr) {
+				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].pageadrlen;
+				doc->erasesize =
+				    nand_flash_ids[i].erasesize;
+				return 1;
+			}
+			return 0;
+		}
+	}
+
+
+	/* We haven't fully identified the chip. Print as much as we know. */
+	printk(KERN_WARNING "Unknown flash chip found: %2.2X %2.2X\n",
+	       id, mfr);
+
+	printk(KERN_WARNING "Please report to dwmw2@infradead.org\n");
+	return 0;
+}
+
+/* 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];
+	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;
+		numchips[floor] = 0;
+		for (chip = 0; chip < maxchips && 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("No memory for allocating chip info structures\n");
+		return;
+	}
+
+	ret = 0;
+
+	/* Fill out the chip array with {floor, chipno} for each 
+	 * detected chip in the device. */
+	for (floor = 0; floor < MAX_FLOORS; 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 DoC2k_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, AliasResolution);
+	tmp2 = ReadDOC(doc2->virtadr, AliasResolution);
+	if (tmp1 != tmp2)
+		return 0;
+
+	WriteDOC((tmp1 + 1) % 0xff, doc1->virtadr, AliasResolution);
+	tmp2 = ReadDOC(doc2->virtadr, 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, AliasResolution);
+
+	return retval;
+}
+
+static const char im_name[] = "DoC2k_init";
+
+/* This routine is made available to other mtd code via
+ * inter_module_register.  It must only be accessed through
+ * inter_module_get which will bump the use count of this module.  The
+ * addresses passed back in mtd are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
+static void DoC2k_init(struct mtd_info *mtd)
+{
+	struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
+	struct DiskOnChip *old = NULL;
+
+	/* We must avoid being called twice for the same device. */
+
+	if (doc2klist)
+		old = (struct DiskOnChip *) 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);
+			kfree(mtd);
+			return;
+		}
+		if (old->nextdoc)
+			old = (struct DiskOnChip *) old->nextdoc->priv;
+		else
+			old = NULL;
+	}
+
+
+	switch (this->ChipID) {
+	case DOC_ChipID_Doc2k:
+		mtd->name = "DiskOnChip 2000";
+		this->ioreg = DoC_2k_CDSN_IO;
+		break;
+	case DOC_ChipID_DocMil:
+		mtd->name = "DiskOnChip Millennium";
+		this->ioreg = DoC_Mil_CDSN_IO;
+		break;
+	}
+
+	printk(KERN_NOTICE "%s found at address 0x%lX\n", mtd->name,
+	       this->physadr);
+
+	mtd->type = MTD_NANDFLASH;
+	mtd->flags = MTD_CAP_NANDFLASH;
+	mtd->size = 0;
+	mtd->erasesize = 0;
+	mtd->oobblock = 512;
+	mtd->oobsize = 16;
+	mtd->module = 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((void *) this->virtadr);
+	} else {
+		this->nextdoc = doc2klist;
+		doc2klist = mtd;
+		mtd->size = this->totlen;
+		mtd->erasesize = this->erasesize;
+		add_mtd_device(mtd);
+		return;
+	}
+}
+
+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);
+}
+
+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 DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
+	unsigned long docptr;
+	struct Nand *mychip;
+	unsigned char syndrome[6];
+	volatile char dummy;
+	int i, len256 = 0, ret=0;
+
+	docptr = this->virtadr;
+
+	/* 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;
+
+	/* The ECC will not be calculated correctly if less than 512 is read */
+	if (len != 0x200 && eccbuf)
+		printk(KERN_WARNING
+		       "ECC needs a full sector read (adr: %lx size %lx)\n",
+		       (long) from, (long) len);
+
+	/* printk("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len); */
+
+
+	/* Find the chip which is to be used and select it */
+	mychip = &this->chips[from >> (this->chipshift)];
+
+	if (this->curfloor != mychip->floor) {
+		DoC_SelectFloor(this, mychip->floor);
+		DoC_SelectChip(this, mychip->chip);
+	} else if (this->curchip != mychip->chip) {
+		DoC_SelectChip(this, mychip->chip);
+	}
+
+	this->curfloor = mychip->floor;
+	this->curchip = mychip->chip;
+
+	DoC_Command(this,
+		    (!this->page256
+		     && (from & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
+		    CDSN_CTRL_WP);
+	DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP,
+		    CDSN_CTRL_ECC_IO);
+
+	if (eccbuf) {
+		/* Prime the ECC engine */
+		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+		WriteDOC(DOC_ECC_EN, docptr, ECCConf);
+	} else {
+		/* disable the ECC engine */
+		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+	}
+
+	/* treat crossing 256-byte sector for 2M x 8bits devices */
+	if (this->page256 && from + len > (from | 0xff) + 1) {
+		len256 = (from | 0xff) + 1 - from;
+		DoC_ReadBuf(this, buf, len256);
+
+		DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP);
+		DoC_Address(this, ADDR_COLUMN_PAGE, from + len256,
+			    CDSN_CTRL_WP, CDSN_CTRL_ECC_IO);
+	}
+
+	DoC_ReadBuf(this, &buf[len256], len - len256);
+
+	/* Let the caller know we completed it */
+	*retlen = len;
+
+	if (eccbuf) {
+		/* Read the ECC data through the DiskOnChip ECC logic */
+		/* Note: this will work even with 2M x 8bit devices as   */
+		/*       they have 8 bytes of OOB per 256 page. mf.      */
+		DoC_ReadBuf(this, eccbuf, 6);
+
+		/* Flush the pipeline */
+		if (DoC_is_Millennium(this)) {
+			dummy = ReadDOC(docptr, ECCConf);
+			dummy = ReadDOC(docptr, ECCConf);
+			i = ReadDOC(docptr, ECCConf);
+		} else {
+			dummy = ReadDOC(docptr, 2k_ECCStatus);
+			dummy = ReadDOC(docptr, 2k_ECCStatus);
+			i = ReadDOC(docptr, 2k_ECCStatus);
+		}
+
+		/* Check the ECC Status */
+		if (i & 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, ECCSyndrome0 + i);
+			}
+                        nb_errors = doc_decode_ecc(buf, syndrome);
+
+#ifdef ECC_DEBUG
+			printk("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 */
+				ret = -EIO;
+                        }
+		}
+
+#ifdef PSYCHO_DEBUG
+		printk("ECC DATA at %lxB: %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 , ECCConf);
+	}
+
+	/* 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))
+	{
+	    DoC_WaitReady(this);
+	}
+
+	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);
+}
+
+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 DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
+	int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
+	unsigned long docptr;
+	volatile char dummy;
+	int len256 = 0;
+	struct Nand *mychip;
+
+	docptr = this->virtadr;
+
+	/* Don't allow write past end of device */
+	if (to >= this->totlen)
+		return -EINVAL;
+
+	/* 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 */
+	if (len != 0x200 && eccbuf)
+		printk(KERN_WARNING
+		       "ECC needs a full sector write (adr: %lx size %lx)\n",
+		       (long) to, (long) len);
+
+	/* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
+
+	/* Find the chip which is to be used and select it */
+	mychip = &this->chips[to >> (this->chipshift)];
+
+	if (this->curfloor != mychip->floor) {
+		DoC_SelectFloor(this, mychip->floor);
+		DoC_SelectChip(this, mychip->chip);
+	} else if (this->curchip != mychip->chip) {
+		DoC_SelectChip(this, mychip->chip);
+	}
+
+	this->curfloor = mychip->floor;
+	this->curchip = mychip->chip;
+
+	/* Set device to main plane of flash */
+	DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
+	DoC_Command(this,
+		    (!this->page256
+		     && (to & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
+		    CDSN_CTRL_WP);
+
+	DoC_Command(this, NAND_CMD_SEQIN, 0);
+	DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
+
+	if (eccbuf) {
+		/* Prime the ECC engine */
+		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
+	} else {
+		/* disable the ECC engine */
+		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+	}
+
+	/* treat crossing 256-byte sector for 2M x 8bits devices */
+	if (this->page256 && to + len > (to | 0xff) + 1) {
+		len256 = (to | 0xff) + 1 - to;
+		DoC_WriteBuf(this, buf, len256);
+
+		DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+
+		DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
+		/* There's an implicit DoC_WaitReady() in DoC_Command */
+
+		dummy = ReadDOC(docptr, CDSNSlowIO);
+		DoC_Delay(this, 2);
+
+		if (ReadDOC_(docptr, this->ioreg) & 1) {
+			printk("Error programming flash\n");
+			/* Error in programming */
+			*retlen = 0;
+			return -EIO;
+		}
+
+		DoC_Command(this, NAND_CMD_SEQIN, 0);
+		DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0,
+			    CDSN_CTRL_ECC_IO);
+	}
+
+	DoC_WriteBuf(this, &buf[len256], len - len256);
+
+	if (eccbuf) {
+		WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr,
+			 CDSNControl);
+
+		if (DoC_is_Millennium(this)) {
+			WriteDOC(0, docptr, NOP);
+			WriteDOC(0, docptr, NOP);
+			WriteDOC(0, docptr, NOP);
+		} else {
+			WriteDOC_(0, docptr, this->ioreg);
+			WriteDOC_(0, docptr, this->ioreg);
+			WriteDOC_(0, docptr, this->ioreg);
+		}
+
+		/* Read the ECC data through the DiskOnChip ECC logic */
+		for (di = 0; di < 6; di++) {
+			eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
+		}
+
+		/* Reset the ECC engine */
+		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+
+#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
+	}
+
+	DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+
+	DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
+	/* There's an implicit DoC_WaitReady() in DoC_Command */
+
+	dummy = ReadDOC(docptr, CDSNSlowIO);
+	DoC_Delay(this, 2);
+
+	if (ReadDOC_(docptr, this->ioreg) & 1) {
+		printk("Error programming flash\n");
+		/* Error in programming */
+		*retlen = 0;
+		return -EIO;
+	}
+
+	/* Let the caller know we completed it */
+	*retlen = len;
+		
+	if (eccbuf) {
+		unsigned char x[8];
+		size_t dummy;
+
+		/* Write the ECC data to flash */
+		for (di=0; di<6; di++)
+			x[di] = eccbuf[di];
+		
+		x[6]=0x55;
+		x[7]=0x55;
+		
+		return doc_write_oob(mtd, to, 8, &dummy, x);
+	}
+
+	return 0;
+}
+
+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;
+	int len256 = 0;
+	unsigned long docptr;
+	struct Nand *mychip;
+
+	docptr = this->virtadr;
+
+	mychip = &this->chips[ofs >> this->chipshift];
+
+	if (this->curfloor != mychip->floor) {
+		DoC_SelectFloor(this, mychip->floor);
+		DoC_SelectChip(this, mychip->chip);
+	} else if (this->curchip != mychip->chip) {
+		DoC_SelectChip(this, mychip->chip);
+	}
+	this->curfloor = mychip->floor;
+	this->curchip = mychip->chip;
+
+	/* update address for 2M x 8bit devices. OOB starts on the second */
+	/* page to maintain compatibility with doc_read_ecc. */
+	if (this->page256) {
+		if (!(ofs & 0x8))
+			ofs += 0x100;
+		else
+			ofs -= 0x8;
+	}
+
+	DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
+	DoC_Address(this, ADDR_COLUMN_PAGE, ofs, CDSN_CTRL_WP, 0);
+
+	/* treat crossing 8-byte OOB data for 2M x 8bit devices */
+	/* Note: datasheet says it should automaticaly wrap to the */
+	/*       next OOB block, but it didn't work here. mf.      */
+	if (this->page256 && ofs + len > (ofs | 0x7) + 1) {
+		len256 = (ofs | 0x7) + 1 - ofs;
+		DoC_ReadBuf(this, buf, len256);
+
+		DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
+		DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff),
+			    CDSN_CTRL_WP, 0);
+	}
+
+	DoC_ReadBuf(this, &buf[len256], len - len256);
+
+	*retlen = len;
+	/* Reading the full OOB data drops us off of the end of the page,
+         * causing the flash device to go into busy mode, so we need
+         * to wait until ready 11.4.1 and Toshiba TC58256FT docs */
+	return DoC_WaitReady(this);
+
+}
+
+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;
+	int len256 = 0;
+	unsigned long docptr = this->virtadr;
+	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
+	int dummy;
+
+	//      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]);
+
+	/* Find the chip which is to be used and select it */
+	if (this->curfloor != mychip->floor) {
+		DoC_SelectFloor(this, mychip->floor);
+		DoC_SelectChip(this, mychip->chip);
+	} else if (this->curchip != mychip->chip) {
+		DoC_SelectChip(this, mychip->chip);
+	}
+	this->curfloor = mychip->floor;
+	this->curchip = mychip->chip;
+
+	/* disable the ECC engine */
+	WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
+	WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
+
+	/* Reset the chip, see Software Requirement 11.4 item 1. */
+	DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
+
+	/* issue the Read2 command to set the pointer to the Spare Data Area. */
+	DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
+
+	/* update address for 2M x 8bit devices. OOB starts on the second */
+	/* page to maintain compatibility with doc_read_ecc. */
+	if (this->page256) {
+		if (!(ofs & 0x8))
+			ofs += 0x100;
+		else
+			ofs -= 0x8;
+	}
+
+	/* issue the Serial Data In command to initial the Page Program process */
+	DoC_Command(this, NAND_CMD_SEQIN, 0);
+	DoC_Address(this, ADDR_COLUMN_PAGE, ofs, 0, 0);
+
+	/* treat crossing 8-byte OOB data for 2M x 8bit devices */
+	/* Note: datasheet says it should automaticaly wrap to the */
+	/*       next OOB block, but it didn't work here. mf.      */
+	if (this->page256 && ofs + len > (ofs | 0x7) + 1) {
+		len256 = (ofs | 0x7) + 1 - ofs;
+		DoC_WriteBuf(this, buf, len256);
+
+		DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+		DoC_Command(this, NAND_CMD_STATUS, 0);
+		/* DoC_WaitReady() is implicit in DoC_Command */
+
+		dummy = ReadDOC(docptr, CDSNSlowIO);
+		DoC_Delay(this, 2);
+
+		if (ReadDOC_(docptr, this->ioreg) & 1) {
+			printk("Error programming oob data\n");
+			/* There was an error */
+			*retlen = 0;
+			return -EIO;
+		}
+		DoC_Command(this, NAND_CMD_SEQIN, 0);
+		DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff), 0, 0);
+	}
+
+	DoC_WriteBuf(this, &buf[len256], len - len256);
+
+	DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+	DoC_Command(this, NAND_CMD_STATUS, 0);
+	/* DoC_WaitReady() is implicit in DoC_Command */
+
+	dummy = ReadDOC(docptr, CDSNSlowIO);
+	DoC_Delay(this, 2);
+
+	if (ReadDOC_(docptr, this->ioreg) & 1) {
+		printk("Error programming oob data\n");
+		/* There was an error */
+		*retlen = 0;
+		return -EIO;
+	}
+
+	*retlen = len;
+	return 0;
+
+}
+
+int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
+	__u32 ofs = instr->addr;
+	__u32 len = instr->len;
+	unsigned long docptr;
+	struct Nand *mychip;
+
+	if (len != mtd->erasesize)
+		printk(KERN_WARNING "Erase not right size (%x != %x)n",
+		       len, mtd->erasesize);
+
+	docptr = this->virtadr;
+
+	mychip = &this->chips[ofs >> this->chipshift];
+
+	if (this->curfloor != mychip->floor) {
+		DoC_SelectFloor(this, mychip->floor);
+		DoC_SelectChip(this, mychip->chip);
+	} else if (this->curchip != mychip->chip) {
+		DoC_SelectChip(this, mychip->chip);
+	}
+	this->curfloor = mychip->floor;
+	this->curchip = mychip->chip;
+
+	instr->state = MTD_ERASE_PENDING;
+
+	DoC_Command(this, NAND_CMD_ERASE1, 0);
+	DoC_Address(this, ADDR_PAGE, ofs, 0, 0);
+	DoC_Command(this, NAND_CMD_ERASE2, 0);
+
+	instr->state = MTD_ERASING;
+
+	DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
+
+	if (ReadDOC_(docptr, this->ioreg) & 1) {
+		printk("Error writing\n");
+		/* There was an error */
+		instr->state = MTD_ERASE_FAILED;
+	} else
+		instr->state = MTD_ERASE_DONE;
+
+	if (instr->callback)
+		instr->callback(instr);
+
+	return 0;
+}
+
+
+/****************************************************************************
+ *
+ * Module stuff
+ *
+ ****************************************************************************/
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define cleanup_doc2000 cleanup_module
+#define init_doc2000 init_module
+#endif
+
+int __init init_doc2000(void)
+{
+       inter_module_register(im_name, THIS_MODULE, &DoC2k_init);
+       return 0;
+}
+
+static void __exit cleanup_doc2000(void)
+{
+	struct mtd_info *mtd;
+	struct DiskOnChip *this;
+
+	while ((mtd = doc2klist)) {
+		this = (struct DiskOnChip *) mtd->priv;
+		doc2klist = this->nextdoc;
+
+		del_mtd_device(mtd);
+
+		iounmap((void *) this->virtadr);
+		kfree(this->chips);
+		kfree(mtd);
+	}
+	inter_module_unregister(im_name);
+}
+
+module_exit(cleanup_doc2000);
+module_init(init_doc2000);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/devices/doc2001.c linux/drivers/mtd/devices/doc2001.c
--- v2.4.5/linux/drivers/mtd/devices/doc2001.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/devices/doc2001.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,883 @@
+
+/*
+ * Linux driver for Disk-On-Chip Millennium
+ * (c) 1999 Machine Vision Holdings, Inc.
+ * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
+ *
+ * $Id: doc2001.c,v 1.34 2001/06/02 14:30:43 dwmw2 Exp $
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ids.h>
+#include <linux/mtd/doc2000.h>
+
+/* #define ECC_DEBUG */
+
+/* I have no idea why some DoC chips can not use memcop_form|to_io().
+ * This may be due to the different revisions of the ASIC controller built-in or
+ * simplily a QA/Bug issue. Who knows ?? If you have trouble, please uncomment
+ * this:*/
+#undef USE_MEMCPY
+
+static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
+		    size_t *retlen, u_char *buf);
+static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
+		     size_t *retlen, const u_char *buf);
+static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
+			size_t *retlen, u_char *buf, u_char *eccbuf);
+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);
+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 *docmillist = NULL;
+
+/* Perform the required delay cycles by reading from the NOP register */
+static void DoC_Delay(unsigned long docptr, unsigned short cycles)
+{
+	volatile char dummy;
+	int i;
+
+	for (i = 0; i < cycles; i++)
+		dummy = ReadDOC(docptr, NOP);
+}
+
+/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
+static int _DoC_WaitReady(unsigned long docptr)
+{
+	unsigned short 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, CDSNControl) & CDSN_CTRL_FR_B) && --c)
+		;
+
+	if (c == 0)
+		DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
+
+	return (c == 0);
+}
+
+static inline int DoC_WaitReady(unsigned long docptr)
+{
+	/* This is inline, to optimise the common case, where it's ready instantly */
+	int ret = 0;
+
+	/* 4 read form NOP register should be issued in prior to the read from CDSNControl
+	   see Software Requirement 11.4 item 2. */
+	DoC_Delay(docptr, 4);
+
+	if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
+		/* Call the out-of-line routine to wait */
+		ret = _DoC_WaitReady(docptr);
+
+	/* issue 2 read from NOP register after reading from CDSNControl register
+	   see Software Requirement 11.4 item 2. */
+	DoC_Delay(docptr, 2);
+
+	return ret;
+}
+
+/* DoC_Command: Send a flash command to the flash chip through the CDSN IO register
+   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,
+			       unsigned char xtraflags)
+{
+	/* Assert the CLE (Command Latch Enable) line to the flash chip */
+	WriteDOC(xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, docptr, CDSNControl);
+	DoC_Delay(docptr, 4);
+
+	/* Send the command */
+	WriteDOC(command, docptr, Mil_CDSN_IO);
+	WriteDOC(0x00, docptr, WritePipeTerm);
+
+	/* Lower the CLE line */
+	WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
+	DoC_Delay(docptr, 4);
+}
+
+/* DoC_Address: Set the current address for the flash chip through the CDSN IO register
+   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,
+			       unsigned char xtraflags1, unsigned char xtraflags2)
+{
+	/* Assert the ALE (Address Latch Enable) line to the flash chip */
+	WriteDOC(xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, docptr, CDSNControl);
+	DoC_Delay(docptr, 4);
+
+	/* Send the address */
+	switch (numbytes)
+	    {
+	    case 1:
+		    /* Send single byte, bits 0-7. */
+		    WriteDOC(ofs & 0xff, docptr, Mil_CDSN_IO);
+		    WriteDOC(0x00, docptr, WritePipeTerm);
+		    break;
+	    case 2:
+		    /* Send bits 9-16 followed by 17-23 */
+		    WriteDOC((ofs >> 9)  & 0xff, docptr, Mil_CDSN_IO);
+		    WriteDOC((ofs >> 17) & 0xff, docptr, Mil_CDSN_IO);
+		    WriteDOC(0x00, docptr, WritePipeTerm);
+		break;
+	    case 3:
+		    /* Send 0-7, 9-16, then 17-23 */
+		    WriteDOC(ofs & 0xff, docptr, Mil_CDSN_IO);
+		    WriteDOC((ofs >> 9)  & 0xff, docptr, Mil_CDSN_IO);
+		    WriteDOC((ofs >> 17) & 0xff, docptr, Mil_CDSN_IO);
+		    WriteDOC(0x00, docptr, WritePipeTerm);
+		break;
+	    default:
+		return;
+	    }
+
+	/* Lower the ALE line */
+	WriteDOC(xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr, CDSNControl);
+	DoC_Delay(docptr, 4);
+}
+
+/* DoC_SelectChip: Select a given flash chip within the current floor */
+static int DoC_SelectChip(unsigned long docptr, int chip)
+{
+	/* Select the individual flash chip requested */
+	WriteDOC(chip, docptr, CDSNDeviceSelect);
+	DoC_Delay(docptr, 4);
+
+	/* Wait for it to be ready */
+	return DoC_WaitReady(docptr);
+}
+
+/* DoC_SelectFloor: Select a given floor (bank of flash chips) */
+static int DoC_SelectFloor(unsigned long docptr, int floor)
+{
+	/* Select the floor (bank) of chips required */
+	WriteDOC(floor, docptr, FloorSelect);
+
+	/* Wait for the chip to be ready */
+	return DoC_WaitReady(docptr);
+}
+
+/* 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;
+	volatile char dummy;
+
+	/* Page in the required floor/chip
+	   FIXME: is this supported by Millennium ?? */
+	DoC_SelectFloor(doc->virtadr, floor);
+	DoC_SelectChip(doc->virtadr, chip);
+
+	/* Reset the chip, see Software Requirement 11.4 item 1. */
+	DoC_Command(doc->virtadr, NAND_CMD_RESET, CDSN_CTRL_WP);
+	DoC_WaitReady(doc->virtadr);
+
+	/* Read the NAND chip ID: 1. Send ReadID command */ 
+	DoC_Command(doc->virtadr, NAND_CMD_READID, CDSN_CTRL_WP);
+
+	/* Read the NAND chip ID: 2. Send address byte zero */ 
+	DoC_Address(doc->virtadr, 1, 0x00, CDSN_CTRL_WP, 0x00);
+
+	/* Read the manufacturer and device id codes of the flash device through
+	   CDSN IO register see Software Requirement 11.4 item 5.*/
+	dummy = ReadDOC(doc->virtadr, ReadPipeInit);
+	DoC_Delay(doc->virtadr, 2);
+	mfr = ReadDOC(doc->virtadr, Mil_CDSN_IO);
+
+	DoC_Delay(doc->virtadr, 2);
+	id  = ReadDOC(doc->virtadr, Mil_CDSN_IO);
+	dummy = ReadDOC(doc->virtadr, LastDataRead);
+
+	/* No response - return failure */
+	if (mfr == 0xff || mfr == 0)
+		return 0;
+
+	/* FIXME: to deal with multi-flash on multi-Millennium case more carefully */
+	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
+		if (mfr == nand_flash_ids[i].manufacture_id &&
+		    id == nand_flash_ids[i].model_id) {
+			printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, "
+			       "Chip ID: %2.2X (%s)\n",
+			       mfr, id, nand_flash_ids[i].name);
+			doc->mfr = mfr;
+			doc->id = id;
+			doc->chipshift = nand_flash_ids[i].chipshift;
+			break;
+		}
+	}
+
+	if (nand_flash_ids[i].name == NULL)
+		return 0;
+	else
+		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_MIL];
+	int ret;
+
+	this->numchips = 0;
+	this->mfr = 0;
+	this->id = 0;
+
+	/* For each floor, find the number of valid chips it contains */
+	for (floor = 0,ret = 1; floor < MAX_FLOORS_MIL; floor++) {
+		numchips[floor] = 0;
+		for (chip = 0; chip < MAX_CHIPS_MIL && 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("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_MIL; 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 DoCMil_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 Millenium docs), but it seems to work. */
+	tmp1 = ReadDOC(doc1->virtadr, AliasResolution);
+	tmp2 = ReadDOC(doc2->virtadr, AliasResolution);
+	if (tmp1 != tmp2)
+		return 0;
+	
+	WriteDOC((tmp1+1) % 0xff, doc1->virtadr, AliasResolution);
+	tmp2 = ReadDOC(doc2->virtadr, 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, AliasResolution);
+
+	return retval;
+}
+
+static const char im_name[] = "DoCMil_init";
+
+/* This routine is made available to other mtd code via
+ * inter_module_register.  It must only be accessed through
+ * inter_module_get which will bump the use count of this module.  The
+ * addresses passed back in mtd are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
+static void DoCMil_init(struct mtd_info *mtd)
+{
+	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+	struct DiskOnChip *old = NULL;
+
+	/* We must avoid being called twice for the same device. */
+	if (docmillist)
+		old = (struct DiskOnChip *)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);
+			kfree(mtd);
+			return;
+		}
+		if (old->nextdoc)
+			old = (struct DiskOnChip *)old->nextdoc->priv;
+		else
+			old = NULL;
+	}
+
+	mtd->name = "DiskOnChip Millennium";
+	printk(KERN_NOTICE "DiskOnChip Millennium found at address 0x%lX\n",
+	       this->physadr);
+
+	mtd->type = MTD_NANDFLASH;
+	mtd->flags = MTD_CAP_NANDFLASH;
+	mtd->size = 0;
+
+	/* FIXME: erase size is not always 8kB */
+	mtd->erasesize = 0x2000;
+
+	mtd->oobblock = 512;
+	mtd->oobsize = 16;
+	mtd->module = 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((void *)this->virtadr);
+	} else {
+		this->nextdoc = docmillist;
+		docmillist = mtd;
+		mtd->size  = this->totlen;
+		add_mtd_device(mtd);
+		return;
+	}
+}
+
+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);
+}
+
+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 i, ret;
+	volatile char dummy;
+	unsigned char syndrome[6];
+	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+	unsigned long 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;
+
+	/* 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;
+
+	/* issue the Read0 or Read1 command depend on which half of the page
+	   we are accessing. Polling the Flash Ready bit after issue 3 bytes
+	   address in Sequence Read Mode, see Software Requirement 11.4 item 1.*/
+	DoC_Command(docptr, (from >> 8) & 1, CDSN_CTRL_WP);
+	DoC_Address(docptr, 3, from, CDSN_CTRL_WP, 0x00);
+	DoC_WaitReady(docptr);
+
+	if (eccbuf) {
+		/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
+		WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
+		WriteDOC (DOC_ECC_EN, docptr, ECCConf);
+	} else {
+		/* disable the ECC engine */
+		WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
+		WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
+	}
+
+	/* Read the data via the internal pipeline through CDSN IO register,
+	   see Pipelined Read Operations 11.3 */
+	dummy = ReadDOC(docptr, ReadPipeInit);
+#ifndef USE_MEMCPY
+	for (i = 0; i < len-1; i++) {
+		/* N.B. you have to increase the source address in this way or the
+		   ECC logic will not work properly */
+		buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));
+	}
+#else
+	memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len - 1);
+#endif
+	buf[len - 1] = ReadDOC(docptr, LastDataRead);
+
+	/* Let the caller know we completed it */
+	*retlen = len;
+        ret = 0;
+
+	if (eccbuf) {
+		/* Read the ECC data from Spare Data Area,
+		   see Reed-Solomon EDC/ECC 11.1 */
+		dummy = ReadDOC(docptr, ReadPipeInit);
+#ifndef USE_MEMCPY
+		for (i = 0; i < 5; i++) {
+			/* N.B. you have to increase the source address in this way or the
+			   ECC logic will not work properly */
+			eccbuf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
+		}
+#else
+		memcpy_fromio(eccbuf, docptr + DoC_Mil_CDSN_IO, 5);
+#endif
+		eccbuf[5] = ReadDOC(docptr, LastDataRead);
+
+		/* Flush the pipeline */
+		dummy = ReadDOC(docptr, ECCConf);
+		dummy = ReadDOC(docptr, ECCConf);
+
+		/* Check the ECC Status */
+		if (ReadDOC(docptr, 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, 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 */
+				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 , ECCConf);
+	}
+
+	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);
+}
+
+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 i,ret = 0;
+	volatile char dummy;
+	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+	unsigned long 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;
+
+#if 0
+	/* Don't allow a single write to cross a 512-byte block boundary */
+	if (to + len > ( (to | 0x1ff) + 1)) 
+		len = ((to | 0x1ff) + 1) - to;
+#else
+	/* Don't allow writes which aren't exactly one block */
+	if (to & 0x1ff || len != 0x200)
+		return -EINVAL;
+#endif
+
+	/* 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;
+
+	/* Reset the chip, see Software Requirement 11.4 item 1. */
+	DoC_Command(docptr, NAND_CMD_RESET, 0x00);
+	DoC_WaitReady(docptr);
+	/* Set device to main plane of flash */
+	DoC_Command(docptr, NAND_CMD_READ0, 0x00);
+
+	/* issue the Serial Data In command to initial the Page Program process */
+	DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
+	DoC_Address(docptr, 3, to, 0x00, 0x00);
+	DoC_WaitReady(docptr);
+
+	if (eccbuf) {
+		/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
+		WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
+		WriteDOC (DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
+	} else {
+		/* disable the ECC engine */
+		WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
+		WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
+	}
+
+	/* Write the data via the internal pipeline through CDSN IO register,
+	   see Pipelined Write Operations 11.2 */
+#ifndef USE_MEMCPY
+	for (i = 0; i < len; i++) {
+		/* N.B. you have to increase the source address in this way or the
+		   ECC logic will not work properly */
+		WriteDOC(buf[i], docptr, Mil_CDSN_IO + i);
+	}
+#else
+	memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len);
+#endif
+	WriteDOC(0x00, docptr, WritePipeTerm);
+
+	if (eccbuf) {
+		/* Write ECC data to flash, the ECC info is generated by the DiskOnChip ECC logic
+		   see Reed-Solomon EDC/ECC 11.1 */
+		WriteDOC(0, docptr, NOP);
+		WriteDOC(0, docptr, NOP);
+		WriteDOC(0, docptr, NOP);
+
+		/* Read the ECC data through the DiskOnChip ECC logic */
+		for (i = 0; i < 6; i++) {
+			eccbuf[i] = ReadDOC(docptr, ECCSyndrome0 + i);
+		}
+
+		/* ignore the ECC engine */
+		WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
+
+#ifndef USE_MEMCPY
+		/* Write the ECC data to flash */
+		for (i = 0; i < 6; i++) {
+			/* N.B. you have to increase the source address in this way or the
+			   ECC logic will not work properly */
+			WriteDOC(eccbuf[i], docptr, Mil_CDSN_IO + i);
+		}
+#else
+		memcpy_toio(docptr + DoC_Mil_CDSN_IO, eccbuf, 6);
+#endif
+
+		/* write the block status BLOCK_USED (0x5555) at the end of ECC data
+		   FIXME: this is only a hack for programming the IPL area for LinuxBIOS
+		   and should be replace with proper codes in user space utilities */ 
+		WriteDOC(0x55, docptr, Mil_CDSN_IO);
+		WriteDOC(0x55, docptr, Mil_CDSN_IO + 1);
+
+		WriteDOC(0x00, docptr, WritePipeTerm);
+
+#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
+	}
+
+	/* 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, CDSN_CTRL_WP);
+	dummy = ReadDOC(docptr, ReadPipeInit);
+	DoC_Delay(docptr, 2);
+	if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
+		printk("Error programming flash\n");
+		/* Error in programming
+		   FIXME: implement Bad Block Replacement (in nftl.c ??) */
+		*retlen = 0;
+		ret = -EIO;
+	}
+	dummy = ReadDOC(docptr, LastDataRead);
+
+	/* 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)
+{
+#ifndef USE_MEMCPY
+	int i;
+#endif
+	volatile char dummy;
+	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+	unsigned long docptr = this->virtadr;
+	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
+
+	/* 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;
+
+	/* disable the ECC engine */
+	WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
+	WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
+
+	/* issue the Read2 command to set the pointer to the Spare Data Area.
+	   Polling the Flash Ready bit after issue 3 bytes address in
+	   Sequence Read Mode, see Software Requirement 11.4 item 1.*/
+	DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP);
+	DoC_Address(docptr, 3, ofs, CDSN_CTRL_WP, 0x00);
+	DoC_WaitReady(docptr);
+
+	/* Read the data out via the internal pipeline through CDSN IO register,
+	   see Pipelined Read Operations 11.3 */
+	dummy = ReadDOC(docptr, ReadPipeInit);
+#ifndef USE_MEMCPY
+	for (i = 0; i < len-1; i++) {
+		/* N.B. you have to increase the source address in this way or the
+		   ECC logic will not work properly */
+		buf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
+	}
+#else
+	memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len - 1);
+#endif
+	buf[len - 1] = ReadDOC(docptr, LastDataRead);
+
+	*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)
+{
+#ifndef USE_MEMCPY
+	int i;
+#endif
+	volatile char dummy;
+	int ret = 0;
+	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+	unsigned long docptr = this->virtadr;
+	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
+
+	/* 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;
+
+	/* disable the ECC engine */
+	WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
+	WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
+
+	/* Reset the chip, see Software Requirement 11.4 item 1. */
+	DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP);
+	DoC_WaitReady(docptr);
+	/* issue the Read2 command to set the pointer to the Spare Data Area. */
+	DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP);
+
+	/* issue the Serial Data In command to initial the Page Program process */
+	DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
+	DoC_Address(docptr, 3, ofs, 0x00, 0x00);
+
+	/* Write the data via the internal pipeline through CDSN IO register,
+	   see Pipelined Write Operations 11.2 */
+#ifndef USE_MEMCPY
+	for (i = 0; i < len; i++) {
+		/* N.B. you have to increase the source address in this way or the
+		   ECC logic will not work properly */
+		WriteDOC(buf[i], docptr, Mil_CDSN_IO + i);
+	}
+#else
+	memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len);
+#endif
+	WriteDOC(0x00, docptr, 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, ReadPipeInit);
+	DoC_Delay(docptr, 2);
+	if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
+		printk("Error programming oob data\n");
+		/* FIXME: implement Bad Block Replacement (in nftl.c ??) */
+		*retlen = 0;
+		ret = -EIO;
+	}
+	dummy = ReadDOC(docptr, LastDataRead);
+
+	*retlen = len;
+
+	return ret;
+}
+
+int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+	volatile char dummy;
+	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+	__u32 ofs = instr->addr;
+	__u32 len = instr->len;
+	unsigned long docptr = this->virtadr;
+	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
+
+	if (len != mtd->erasesize) 
+		printk(KERN_WARNING "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;
+
+	/* issue the Erase Setup command */
+	DoC_Command(docptr, NAND_CMD_ERASE1, 0x00);
+	DoC_Address(docptr, 2, ofs, 0x00, 0x00);
+
+	/* Commit the Erase Start command and wait for ready
+	   see Software Requirement 11.4 item 1.*/
+	DoC_Command(docptr, NAND_CMD_ERASE2, 0x00);
+	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.
+	   FIXME: it seems that we are not wait long enough, some blocks are not
+	   erased fully */
+	DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP);
+	dummy = ReadDOC(docptr, ReadPipeInit);
+	DoC_Delay(docptr, 2);
+	if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
+		printk("Error Erasing at 0x%x\n", ofs);
+		/* There was an error
+		   FIXME: implement Bad Block Replacement (in nftl.c ??) */
+		instr->state = MTD_ERASE_FAILED;
+	} else
+		instr->state = MTD_ERASE_DONE;
+	dummy = ReadDOC(docptr, LastDataRead);
+
+	if (instr->callback) 
+		instr->callback(instr);
+
+	return 0;
+}
+
+/****************************************************************************
+ *
+ * Module stuff
+ *
+ ****************************************************************************/
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define cleanup_doc2001 cleanup_module
+#define init_doc2001 init_module
+#endif
+
+int __init init_doc2001(void)
+{
+	inter_module_register(im_name, THIS_MODULE, &DoCMil_init);
+	return 0;
+}
+
+static void __exit cleanup_doc2001(void)
+{
+	struct mtd_info *mtd;
+	struct DiskOnChip *this;
+
+	while ((mtd=docmillist)) {
+		this = (struct DiskOnChip *)mtd->priv;
+		docmillist = this->nextdoc;
+			
+		del_mtd_device(mtd);
+			
+		iounmap((void *)this->virtadr);
+		kfree(this->chips);
+		kfree(mtd);
+	}
+	inter_module_unregister(im_name);
+}
+
+module_exit(cleanup_doc2001);
+module_init(init_doc2001);
+
+
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/devices/docecc.c linux/drivers/mtd/devices/docecc.c
--- v2.4.5/linux/drivers/mtd/devices/docecc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/devices/docecc.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,522 @@
+/*
+ * ECC algorithm for M-systems disk on chip. We use the excellent Reed
+ * Solmon code of Phil Karn (karn@ka9q.ampr.org) available under the
+ * GNU GPL License. The rest is simply to convert the disk on chip
+ * syndrom into a standard syndom.
+ *
+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
+ * Copyright (C) 2000 Netgem S.A.
+ *
+ * $Id: docecc.c,v 1.1 2000/11/03 12:43:43 dwmw2 Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/doc2000.h>
+
+/* need to undef it (from asm/termbits.h) */
+#undef B0
+
+#define MM 10 /* Symbol size in bits */
+#define KK (1023-4) /* Number of data symbols per block */
+#define B0 510 /* First root of generator polynomial, alpha form */
+#define PRIM 1 /* power of alpha used to generate roots of generator poly */
+#define	NN ((1 << MM) - 1)
+
+typedef unsigned short dtype;
+
+/* 1+x^3+x^10 */
+static const int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 };
+
+/* This defines the type used to store an element of the Galois Field
+ * used by the code. Make sure this is something larger than a char if
+ * if anything larger than GF(256) is used.
+ *
+ * Note: unsigned char will work up to GF(256) but int seems to run
+ * faster on the Pentium.
+ */
+typedef int gf;
+
+/* No legal value in index form represents zero, so
+ * we need a special value for this purpose
+ */
+#define A0	(NN)
+
+/* Compute x % NN, where NN is 2**MM - 1,
+ * without a slow divide
+ */
+static inline gf
+modnn(int x)
+{
+  while (x >= NN) {
+    x -= NN;
+    x = (x >> MM) + (x & NN);
+  }
+  return x;
+}
+
+#define	min(a,b)	((a) < (b) ? (a) : (b))
+
+#define	CLEAR(a,n) {\
+int ci;\
+for(ci=(n)-1;ci >=0;ci--)\
+(a)[ci] = 0;\
+}
+
+#define	COPY(a,b,n) {\
+int ci;\
+for(ci=(n)-1;ci >=0;ci--)\
+(a)[ci] = (b)[ci];\
+}
+
+#define	COPYDOWN(a,b,n) {\
+int ci;\
+for(ci=(n)-1;ci >=0;ci--)\
+(a)[ci] = (b)[ci];\
+}
+
+#define Ldec 1
+
+/* generate GF(2**m) from the irreducible polynomial p(X) in Pp[0]..Pp[m]
+   lookup tables:  index->polynomial form   alpha_to[] contains j=alpha**i;
+                   polynomial form -> index form  index_of[j=alpha**i] = i
+   alpha=2 is the primitive element of GF(2**m)
+   HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows:
+        Let @ represent the primitive element commonly called "alpha" that
+   is the root of the primitive polynomial p(x). Then in GF(2^m), for any
+   0 <= i <= 2^m-2,
+        @^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
+   where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation
+   of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for
+   example the polynomial representation of @^5 would be given by the binary
+   representation of the integer "alpha_to[5]".
+                   Similarily, index_of[] can be used as follows:
+        As above, let @ represent the primitive element of GF(2^m) that is
+   the root of the primitive polynomial p(x). In order to find the power
+   of @ (alpha) that has the polynomial representation
+        a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
+   we consider the integer "i" whose binary representation with a(0) being LSB
+   and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry
+   "index_of[i]". Now, @^index_of[i] is that element whose polynomial 
+    representation is (a(0),a(1),a(2),...,a(m-1)).
+   NOTE:
+        The element alpha_to[2^m-1] = 0 always signifying that the
+   representation of "@^infinity" = 0 is (0,0,0,...,0).
+        Similarily, the element index_of[0] = A0 always signifying
+   that the power of alpha which has the polynomial representation
+   (0,0,...,0) is "infinity".
+ 
+*/
+
+static void
+generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1])
+{
+  register int i, mask;
+
+  mask = 1;
+  Alpha_to[MM] = 0;
+  for (i = 0; i < MM; i++) {
+    Alpha_to[i] = mask;
+    Index_of[Alpha_to[i]] = i;
+    /* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */
+    if (Pp[i] != 0)
+      Alpha_to[MM] ^= mask;	/* Bit-wise EXOR operation */
+    mask <<= 1;	/* single left-shift */
+  }
+  Index_of[Alpha_to[MM]] = MM;
+  /*
+   * Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by
+   * poly-repr of @^i shifted left one-bit and accounting for any @^MM
+   * term that may occur when poly-repr of @^i is shifted.
+   */
+  mask >>= 1;
+  for (i = MM + 1; i < NN; i++) {
+    if (Alpha_to[i - 1] >= mask)
+      Alpha_to[i] = Alpha_to[MM] ^ ((Alpha_to[i - 1] ^ mask) << 1);
+    else
+      Alpha_to[i] = Alpha_to[i - 1] << 1;
+    Index_of[Alpha_to[i]] = i;
+  }
+  Index_of[0] = A0;
+  Alpha_to[NN] = 0;
+}
+
+/*
+ * Performs ERRORS+ERASURES decoding of RS codes. bb[] is the content
+ * of the feedback shift register after having processed the data and
+ * the ECC.
+ *
+ * Return number of symbols corrected, or -1 if codeword is illegal
+ * or uncorrectable. If eras_pos is non-null, the detected error locations
+ * are written back. NOTE! This array must be at least NN-KK elements long.
+ * The corrected data are written in eras_val[]. They must be xor with the data
+ * to retrieve the correct data : data[erase_pos[i]] ^= erase_val[i] .
+ * 
+ * First "no_eras" erasures are declared by the calling program. Then, the
+ * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2).
+ * If the number of channel errors is not greater than "t_after_eras" the
+ * transmitted codeword will be recovered. Details of algorithm can be found
+ * in R. Blahut's "Theory ... of Error-Correcting Codes".
+
+ * Warning: the eras_pos[] array must not contain duplicate entries; decoder failure
+ * will result. The decoder *could* check for this condition, but it would involve
+ * extra time on every decoding operation.
+ * */
+static int
+eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
+            gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK], 
+            int no_eras)
+{
+  int deg_lambda, el, deg_omega;
+  int i, j, r,k;
+  gf u,q,tmp,num1,num2,den,discr_r;
+  gf lambda[NN-KK + 1], s[NN-KK + 1];	/* Err+Eras Locator poly
+					 * and syndrome poly */
+  gf b[NN-KK + 1], t[NN-KK + 1], omega[NN-KK + 1];
+  gf root[NN-KK], reg[NN-KK + 1], loc[NN-KK];
+  int syn_error, count;
+
+  syn_error = 0;
+  for(i=0;i<NN-KK;i++)
+      syn_error |= bb[i];
+
+  if (!syn_error) {
+    /* if remainder is zero, data[] is a codeword and there are no
+     * errors to correct. So return data[] unmodified
+     */
+    count = 0;
+    goto finish;
+  }
+  
+  for(i=1;i<=NN-KK;i++){
+    s[i] = bb[0];
+  }
+  for(j=1;j<NN-KK;j++){
+    if(bb[j] == 0)
+      continue;
+    tmp = Index_of[bb[j]];
+    
+    for(i=1;i<=NN-KK;i++)
+      s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*PRIM*j)];
+  }
+
+  /* undo the feedback register implicit multiplication and convert
+     syndromes to index form */
+
+  for(i=1;i<=NN-KK;i++) {
+      tmp = Index_of[s[i]];
+      if (tmp != A0)
+          tmp = modnn(tmp + 2 * KK * (B0+i-1)*PRIM);
+      s[i] = tmp;
+  }
+  
+  CLEAR(&lambda[1],NN-KK);
+  lambda[0] = 1;
+
+  if (no_eras > 0) {
+    /* Init lambda to be the erasure locator polynomial */
+    lambda[1] = Alpha_to[modnn(PRIM * eras_pos[0])];
+    for (i = 1; i < no_eras; i++) {
+      u = modnn(PRIM*eras_pos[i]);
+      for (j = i+1; j > 0; j--) {
+	tmp = Index_of[lambda[j - 1]];
+	if(tmp != A0)
+	  lambda[j] ^= Alpha_to[modnn(u + tmp)];
+      }
+    }
+#if DEBUG >= 1
+    /* Test code that verifies the erasure locator polynomial just constructed
+       Needed only for decoder debugging. */
+    
+    /* find roots of the erasure location polynomial */
+    for(i=1;i<=no_eras;i++)
+      reg[i] = Index_of[lambda[i]];
+    count = 0;
+    for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
+      q = 1;
+      for (j = 1; j <= no_eras; j++)
+	if (reg[j] != A0) {
+	  reg[j] = modnn(reg[j] + j);
+	  q ^= Alpha_to[reg[j]];
+	}
+      if (q != 0)
+	continue;
+      /* store root and error location number indices */
+      root[count] = i;
+      loc[count] = k;
+      count++;
+    }
+    if (count != no_eras) {
+      printf("\n lambda(x) is WRONG\n");
+      count = -1;
+      goto finish;
+    }
+#if DEBUG >= 2
+    printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n");
+    for (i = 0; i < count; i++)
+      printf("%d ", loc[i]);
+    printf("\n");
+#endif
+#endif
+  }
+  for(i=0;i<NN-KK+1;i++)
+    b[i] = Index_of[lambda[i]];
+  
+  /*
+   * Begin Berlekamp-Massey algorithm to determine error+erasure
+   * locator polynomial
+   */
+  r = no_eras;
+  el = no_eras;
+  while (++r <= NN-KK) {	/* r is the step number */
+    /* Compute discrepancy at the r-th step in poly-form */
+    discr_r = 0;
+    for (i = 0; i < r; i++){
+      if ((lambda[i] != 0) && (s[r - i] != A0)) {
+	discr_r ^= Alpha_to[modnn(Index_of[lambda[i]] + s[r - i])];
+      }
+    }
+    discr_r = Index_of[discr_r];	/* Index form */
+    if (discr_r == A0) {
+      /* 2 lines below: B(x) <-- x*B(x) */
+      COPYDOWN(&b[1],b,NN-KK);
+      b[0] = A0;
+    } else {
+      /* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
+      t[0] = lambda[0];
+      for (i = 0 ; i < NN-KK; i++) {
+	if(b[i] != A0)
+	  t[i+1] = lambda[i+1] ^ Alpha_to[modnn(discr_r + b[i])];
+	else
+	  t[i+1] = lambda[i+1];
+      }
+      if (2 * el <= r + no_eras - 1) {
+	el = r + no_eras - el;
+	/*
+	 * 2 lines below: B(x) <-- inv(discr_r) *
+	 * lambda(x)
+	 */
+	for (i = 0; i <= NN-KK; i++)
+	  b[i] = (lambda[i] == 0) ? A0 : modnn(Index_of[lambda[i]] - discr_r + NN);
+      } else {
+	/* 2 lines below: B(x) <-- x*B(x) */
+	COPYDOWN(&b[1],b,NN-KK);
+	b[0] = A0;
+      }
+      COPY(lambda,t,NN-KK+1);
+    }
+  }
+
+  /* Convert lambda to index form and compute deg(lambda(x)) */
+  deg_lambda = 0;
+  for(i=0;i<NN-KK+1;i++){
+    lambda[i] = Index_of[lambda[i]];
+    if(lambda[i] != A0)
+      deg_lambda = i;
+  }
+  /*
+   * Find roots of the error+erasure locator polynomial by Chien
+   * Search
+   */
+  COPY(&reg[1],&lambda[1],NN-KK);
+  count = 0;		/* Number of roots of lambda(x) */
+  for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
+    q = 1;
+    for (j = deg_lambda; j > 0; j--){
+      if (reg[j] != A0) {
+	reg[j] = modnn(reg[j] + j);
+	q ^= Alpha_to[reg[j]];
+      }
+    }
+    if (q != 0)
+      continue;
+    /* store root (index-form) and error location number */
+    root[count] = i;
+    loc[count] = k;
+    /* If we've already found max possible roots,
+     * abort the search to save time
+     */
+    if(++count == deg_lambda)
+      break;
+  }
+  if (deg_lambda != count) {
+    /*
+     * deg(lambda) unequal to number of roots => uncorrectable
+     * error detected
+     */
+    count = -1;
+    goto finish;
+  }
+  /*
+   * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
+   * x**(NN-KK)). in index form. Also find deg(omega).
+   */
+  deg_omega = 0;
+  for (i = 0; i < NN-KK;i++){
+    tmp = 0;
+    j = (deg_lambda < i) ? deg_lambda : i;
+    for(;j >= 0; j--){
+      if ((s[i + 1 - j] != A0) && (lambda[j] != A0))
+	tmp ^= Alpha_to[modnn(s[i + 1 - j] + lambda[j])];
+    }
+    if(tmp != 0)
+      deg_omega = i;
+    omega[i] = Index_of[tmp];
+  }
+  omega[NN-KK] = A0;
+  
+  /*
+   * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
+   * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form
+   */
+  for (j = count-1; j >=0; j--) {
+    num1 = 0;
+    for (i = deg_omega; i >= 0; i--) {
+      if (omega[i] != A0)
+	num1  ^= Alpha_to[modnn(omega[i] + i * root[j])];
+    }
+    num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)];
+    den = 0;
+    
+    /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
+    for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) {
+      if(lambda[i+1] != A0)
+	den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])];
+    }
+    if (den == 0) {
+#if DEBUG >= 1
+      printf("\n ERROR: denominator = 0\n");
+#endif
+      /* Convert to dual- basis */
+      count = -1;
+      goto finish;
+    }
+    /* Apply error to data */
+    if (num1 != 0) {
+        eras_val[j] = Alpha_to[modnn(Index_of[num1] + Index_of[num2] + NN - Index_of[den])];
+    } else {
+        eras_val[j] = 0;
+    }
+  }
+ finish:
+  for(i=0;i<count;i++)
+      eras_pos[i] = loc[i];
+  return count;
+}
+
+/***************************************************************************/
+/* The DOC specific code begins here */
+
+#define SECTOR_SIZE 512
+/* The sector bytes are packed into NB_DATA MM bits words */
+#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / MM)
+
+/* 
+ * Correct the errors in 'sector[]' by using 'ecc1[]' which is the
+ * content of the feedback shift register applyied to the sector and
+ * the ECC. Return the number of errors corrected (and correct them in
+ * sector), or -1 if error 
+ */
+int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6])
+{
+    int parity, i, nb_errors;
+    gf bb[NN - KK + 1];
+    gf error_val[NN-KK];
+    int error_pos[NN-KK], pos, bitpos, index, val;
+    dtype *Alpha_to, *Index_of;
+
+    /* init log and exp tables here to save memory. However, it is slower */
+    Alpha_to = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL);
+    if (!Alpha_to)
+        return -1;
+    
+    Index_of = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL);
+    if (!Index_of) {
+        kfree(Alpha_to);
+        return -1;
+    }
+
+    generate_gf(Alpha_to, Index_of);
+
+    parity = ecc1[1];
+
+    bb[0] =  (ecc1[4] & 0xff) | ((ecc1[5] & 0x03) << 8);
+    bb[1] = ((ecc1[5] & 0xfc) >> 2) | ((ecc1[2] & 0x0f) << 6);
+    bb[2] = ((ecc1[2] & 0xf0) >> 4) | ((ecc1[3] & 0x3f) << 4);
+    bb[3] = ((ecc1[3] & 0xc0) >> 6) | ((ecc1[0] & 0xff) << 2);
+
+    nb_errors = eras_dec_rs(Alpha_to, Index_of, bb, 
+                            error_val, error_pos, 0);
+    if (nb_errors <= 0)
+        goto the_end;
+
+    /* correct the errors */
+    for(i=0;i<nb_errors;i++) {
+        pos = error_pos[i];
+        if (pos >= NB_DATA && pos < KK) {
+            nb_errors = -1;
+            goto the_end;
+        }
+        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 = error_val[i] >> (2 + bitpos);
+                parity ^= val;
+                if (index < SECTOR_SIZE)
+                    sector[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 = error_val[i] << (8 - bitpos);
+                parity ^= val;
+                if (index < SECTOR_SIZE)
+                    sector[index] ^= val;
+            }
+        }
+    }
+    
+    /* use parity to test extra errors */
+    if ((parity & 0xff) != 0)
+        nb_errors = -1;
+
+ the_end:
+    kfree(Alpha_to);
+    kfree(Index_of);
+    return nb_errors;
+}
+
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/devices/docprobe.c linux/drivers/mtd/devices/docprobe.c
--- v2.4.5/linux/drivers/mtd/devices/docprobe.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/devices/docprobe.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,285 @@
+
+/* Linux driver for Disk-On-Chip devices			*/
+/* Probe routines common to all DoC devices			*/
+/* (c) 1999 Machine Vision Holdings, Inc.			*/
+/* Author: David Woodhouse <dwmw2@infradead.org>		*/
+/* $Id: docprobe.c,v 1.27 2001/06/03 19:06:09 dwmw2 Exp $	*/
+
+
+
+/* DOC_PASSIVE_PROBE:
+   In order to ensure that the BIOS checksum is correct at boot time, and 
+   hence that the onboard BIOS extension gets executed, the DiskOnChip 
+   goes into reset mode when it is read sequentially: all registers 
+   return 0xff until the chip is woken up again by writing to the 
+   DOCControl register. 
+
+   Unfortunately, this means that the probe for the DiskOnChip is unsafe, 
+   because one of the first things it does is write to where it thinks 
+   the DOCControl register should be - which may well be shared memory 
+   for another device. I've had machines which lock up when this is 
+   attempted. Hence the possibility to do a passive probe, which will fail 
+   to detect a chip in reset mode, but is at least guaranteed not to lock
+   the machine.
+
+   If you have this problem, uncomment the following line:
+#define DOC_PASSIVE_PROBE
+*/
+
+
+/* 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 :)
+*/
+#define DOC_SINGLE_DRIVER
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/doc2000.h>
+
+/* Where to look for the devices? */
+#ifndef CONFIG_MTD_DOCPROBE_ADDRESS
+#define CONFIG_MTD_DOCPROBE_ADDRESS 0
+#endif
+
+
+static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS;
+MODULE_PARM(doc_config_location, "l");
+
+
+static unsigned long __initdata doc_locations[] = {
+#if defined (__alpha__) || defined(__i386__)
+#ifdef CONFIG_MTD_DOCPROBE_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,
+#else
+#warning Unknown architecture for DiskOnChip. No default probe locations defined
+#endif
+	0 };
+
+/* 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)
+{
+	unsigned long window=potential;
+	unsigned char tmp, ChipID;
+#ifndef DOC_PASSIVE_PROBE
+	unsigned char tmp2;
+#endif
+
+	/* Routine copied from the Linux DOC driver */
+
+#ifdef CONFIG_MTD_DOCPROBE_55AA
+	/* Check for 0x55 0xAA signature at beginning of window,
+	   this is no longer true once we remove the IPL (for Millennium */
+	if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa)
+		return 0;
+#endif /* CONFIG_MTD_DOCPROBE_55AA */
+
+#ifndef DOC_PASSIVE_PROBE	
+	/* 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. 
+	 */
+	tmp2 = ReadDOC(window, DOCControl);
+	
+	/* Reset the DiskOnChip ASIC */
+	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
+		 window, DOCControl);
+	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
+		 window, DOCControl);
+	
+	/* Enable the DiskOnChip ASIC */
+	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
+		 window, DOCControl);
+	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
+		 window, DOCControl);
+#endif /* !DOC_PASSIVE_PROBE */	
+
+	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)
+				return ChipID;
+		break;
+		
+	case DOC_ChipID_DocMil:
+		/* Check the TOGGLE bit in the ECC register */
+		tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
+		if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp)
+				return ChipID;
+		break;
+		
+	default:
+#ifndef CONFIG_MTD_DOCPROBE_55AA
+		printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
+		       ChipID, physadr);
+#endif
+#ifndef DOC_PASSIVE_PROBE
+		/* Put back the contents of the DOCControl register, in case it's not
+		 * actually a DiskOnChip.
+		 */
+		WriteDOC(tmp2, window, DOCControl);
+#endif
+		return 0;
+	}
+
+	printk(KERN_WARNING "DiskOnChip failed TOGGLE test, dropping.\n");
+
+#ifndef DOC_PASSIVE_PROBE
+	/* Put back the contents of the DOCControl register: it's not a DiskOnChip */
+	WriteDOC(tmp2, window, DOCControl);
+#endif
+	return 0;
+}   
+
+
+static void __init DoC_Probe(unsigned long physadr)
+{
+	unsigned long docptr;
+	struct DiskOnChip *this;
+	struct mtd_info *mtd;
+	int ChipID;
+	char namebuf[15];
+	char *name = namebuf;
+	char *im_funcname = NULL;
+	char *im_modname = NULL;
+	void (*initroutine)(struct mtd_info *) = NULL;
+
+	docptr = (unsigned long)ioremap(physadr, DOC_IOREMAP_LEN);
+	
+	if (!docptr)
+		return;
+	
+	if ((ChipID = doccheck(docptr, physadr))) {
+		
+		mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL);
+
+		if (!mtd) {
+			printk("Cannot allocate memory for data structures. Dropping.\n");
+			iounmap((void *)docptr);
+			return;
+		}
+		
+		this = (struct DiskOnChip *)(&mtd[1]);
+		
+		memset((char *)mtd,0, sizeof(struct mtd_info));
+		memset((char *)this, 0, sizeof(struct DiskOnChip));
+
+		mtd->priv = this;
+		this->virtadr = docptr;
+		this->physadr = physadr;
+		this->ChipID = ChipID;
+		sprintf(namebuf, "with ChipID %2.2X", ChipID);
+
+		switch(ChipID) {
+		case DOC_ChipID_Doc2k:
+			name="2000";
+			im_funcname = "DoC2k_init";
+			im_modname = "doc2000";
+			break;
+			
+		case DOC_ChipID_DocMil:
+			name="Millennium";
+#ifdef DOC_SINGLE_DRIVER
+			im_funcname = "DoC2k_init";
+			im_modname = "doc2000";
+#else
+			im_funcname = "DoCMil_init";
+			im_modname = "doc2001";
+#endif /* DOC_SINGLE_DRIVER */
+			break;
+		}
+
+		if (im_funcname)
+			initroutine = inter_module_get_request(im_funcname, im_modname);
+
+		if (initroutine) {
+			(*initroutine)(mtd);
+			inter_module_put(im_funcname);
+			return;
+		}
+		printk("Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr);
+	}
+	iounmap((void *)docptr);
+}
+
+
+/****************************************************************************
+ *
+ * Module stuff
+ *
+ ****************************************************************************/
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_doc init_module
+#endif
+
+int __init init_doc(void)
+{
+	int i;
+	
+	printk(KERN_NOTICE "M-Systems DiskOnChip driver. (C) 1999 Machine Vision Holdings, Inc.\n");
+#ifdef PRERELEASE
+	printk(KERN_INFO "$Id: docprobe.c,v 1.27 2001/06/03 19:06:09 dwmw2 Exp $\n");
+#endif
+	if (doc_config_location) {
+		printk("Using configured probe address 0x%lx\n", doc_config_location);
+		DoC_Probe(doc_config_location);
+	} else {
+		for (i=0; doc_locations[i]; i++) {
+			DoC_Probe(doc_locations[i]);
+		}
+	}
+	/* So it looks like we've been used and we get unloaded */
+	MOD_INC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
+	return 0;
+	
+}
+
+module_init(init_doc);
+
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/devices/mtdram.c linux/drivers/mtd/devices/mtdram.c
--- v2.4.5/linux/drivers/mtd/devices/mtdram.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/devices/mtdram.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,178 @@
+/*
+ * mtdram - a test mtd device
+ * $Id: mtdram.c,v 1.24 2001/06/09 23:09:23 dwmw2 Exp $
+ * Author: Alexander Larsson <alex@cendio.se>
+ *
+ * Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
+ *
+ * This code is GPL
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/mtd/compatmac.h>
+#include <linux/mtd/mtd.h>
+
+#ifndef CONFIG_MTDRAM_ABS_POS
+  #define CONFIG_MTDRAM_ABS_POS 0
+#endif
+
+#if CONFIG_MTDRAM_ABS_POS > 0
+  #include <asm/io.h>
+#endif
+
+#ifdef MODULE
+static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE;
+static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE;
+MODULE_PARM(total_size,"l");
+MODULE_PARM(erase_size,"l");
+#define MTDRAM_TOTAL_SIZE (total_size * 1024)
+#define MTDRAM_ERASE_SIZE (erase_size * 1024)
+#else
+#define MTDRAM_TOTAL_SIZE (CONFIG_MTDRAM_TOTAL_SIZE * 1024)
+#define MTDRAM_ERASE_SIZE (CONFIG_MTDRAM_ERASE_SIZE * 1024)
+#endif
+
+
+// We could store these in the mtd structure, but we only support 1 device..
+static struct mtd_info *mtd_info;
+
+
+static int
+ram_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+  DEBUG(MTD_DEBUG_LEVEL2, "ram_erase(pos:%ld, len:%ld)\n", (long)instr->addr, (long)instr->len);
+  if (instr->addr + instr->len > mtd->size) {
+    DEBUG(MTD_DEBUG_LEVEL1, "ram_erase() out of bounds (%ld > %ld)\n", (long)(instr->addr + instr->len), (long)mtd->size);
+    return -EINVAL;
+  }
+	
+  memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
+	
+  instr->state = MTD_ERASE_DONE;
+
+  if (instr->callback)
+    (*(instr->callback))(instr);
+  return 0;
+}
+
+static int ram_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+{
+  if (from + len > mtd->size)
+    return -EINVAL;
+	
+  *mtdbuf = mtd->priv + from;
+  *retlen = len;
+  return 0;
+}
+
+static void ram_unpoint (struct mtd_info *mtd, u_char *addr)
+{
+  DEBUG(MTD_DEBUG_LEVEL2, "ram_unpoint\n");
+}
+
+static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
+	     size_t *retlen, u_char *buf)
+{
+  DEBUG(MTD_DEBUG_LEVEL2, "ram_read(pos:%ld, len:%ld)\n", (long)from, (long)len);
+  if (from + len > mtd->size) {
+    DEBUG(MTD_DEBUG_LEVEL1, "ram_read() out of bounds (%ld > %ld)\n", (long)(from + len), (long)mtd->size);
+    return -EINVAL;
+  }
+
+  memcpy(buf, mtd->priv + from, len);
+
+  *retlen=len;
+  return 0;
+}
+
+static int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
+	      size_t *retlen, const u_char *buf)
+{
+  DEBUG(MTD_DEBUG_LEVEL2, "ram_write(pos:%ld, len:%ld)\n", (long)to, (long)len);
+  if (to + len > mtd->size) {
+    DEBUG(MTD_DEBUG_LEVEL1, "ram_write() out of bounds (%ld > %ld)\n", (long)(to + len), (long)mtd->size);
+    return -EINVAL;
+  }
+
+  memcpy ((char *)mtd->priv + to, buf, len);
+
+  *retlen=len;
+  return 0;
+}
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_mtdram init_module
+#define cleanup_mtdram cleanup_module
+#endif
+
+//static void __exit cleanup_mtdram(void)
+mod_exit_t cleanup_mtdram(void)
+{
+  if (mtd_info) {
+    del_mtd_device(mtd_info);
+    if (mtd_info->priv)
+#if CONFIG_MTDRAM_ABS_POS > 0
+      iounmap(mtd_info->priv);
+#else
+      vfree(mtd_info->priv);
+#endif	
+    kfree(mtd_info);
+  }
+}
+
+mod_init_t init_mtdram(void)
+{
+   // Allocate some memory
+   mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+   if (!mtd_info)
+      return 0;
+   
+   memset(mtd_info, 0, sizeof(*mtd_info));
+
+   // Setup the MTD structure
+   mtd_info->name = "mtdram test device";
+   mtd_info->type = MTD_RAM;
+   mtd_info->flags = MTD_CAP_RAM;
+   mtd_info->size = MTDRAM_TOTAL_SIZE;
+   mtd_info->erasesize = MTDRAM_ERASE_SIZE;
+#if CONFIG_MTDRAM_ABS_POS > 0
+   mtd_info->priv = ioremap(CONFIG_MTDRAM_ABS_POS, MTDRAM_TOTAL_SIZE);
+#else
+   mtd_info->priv = vmalloc(MTDRAM_TOTAL_SIZE);
+#endif
+
+   if (!mtd_info->priv) {
+     DEBUG(MTD_DEBUG_LEVEL1, "Failed to vmalloc(/ioremap) memory region of size %ld (ABS_POS:%ld)\n", (long)MTDRAM_TOTAL_SIZE, (long)CONFIG_MTDRAM_ABS_POS);
+     kfree(mtd_info);
+     mtd_info = NULL;
+     return -ENOMEM;
+   }
+   memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
+
+   mtd_info->module = THIS_MODULE;			
+   mtd_info->erase = ram_erase;
+   mtd_info->point = ram_point;
+   mtd_info->unpoint = ram_unpoint;
+   mtd_info->read = ram_read;
+   mtd_info->write = ram_write;
+
+   if (add_mtd_device(mtd_info)) {
+#if CONFIG_MTDRAM_ABS_POS > 0
+     iounmap(mtd_info->priv);
+#else
+     vfree(mtd_info->priv);
+#endif	
+     kfree(mtd_info);
+     mtd_info = NULL;
+     return -EIO;
+   }
+   
+   return 0;
+}
+
+module_init(init_mtdram);
+module_exit(cleanup_mtdram);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/devices/pmc551.c linux/drivers/mtd/devices/pmc551.c
--- v2.4.5/linux/drivers/mtd/devices/pmc551.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/devices/pmc551.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,872 @@
+/*
+ * $Id: pmc551.c,v 1.17 2001/05/22 13:56:46 dwmw2 Exp $
+ *
+ * PMC551 PCI Mezzanine Ram Device
+ *
+ * Author:
+ *       Mark Ferrell <mferrell@mvista.com>
+ *       Copyright 1999,2000 Nortel Networks
+ *
+ * License:
+ *	 As part of this driver was derived from the slram.c driver it
+ *	 falls under the same license, which is GNU General Public
+ *	 License v2
+ *
+ * Description:
+ *	 This driver is intended to support the PMC551 PCI Ram device
+ *	 from Ramix Inc.  The PMC551 is a PMC Mezzanine module for
+ *	 cPCI embedded systems.  The device contains a single SROM
+ *	 that initially programs the V370PDC chipset onboard the
+ *	 device, and various banks of DRAM/SDRAM onboard.  This driver
+ *	 implements this PCI Ram device as an MTD (Memory Technology
+ *	 Device) so that it can be used to hold a file system, or for
+ *	 added swap space in embedded systems.  Since the memory on
+ *	 this board isn't as fast as main memory we do not try to hook
+ *	 it into main memory as that would simply reduce performance
+ *	 on the system.  Using it as a block device allows us to use
+ *	 it as high speed swap or for a high speed disk device of some
+ *	 sort.  Which becomes very useful on diskless systems in the
+ *	 embedded market I might add.
+ *	 
+ * Notes:
+ *	 Due to what I assume is more buggy SROM, the 64M PMC551 I
+ *	 have available claims that all 4 of it's DRAM banks have 64M
+ *	 of ram configured (making a grand total of 256M onboard).
+ *	 This is slightly annoying since the BAR0 size reflects the
+ *	 aperture size, not the dram size, and the V370PDC supplies no
+ *	 other method for memory size discovery.  This problem is
+ *	 mostly only relevant when compiled as a module, as the
+ *	 unloading of the module with an aperture size smaller then
+ *	 the ram will cause the driver to detect the onboard memory
+ *	 size to be equal to the aperture size when the module is
+ *	 reloaded.  Soooo, to help, the module supports an msize
+ *	 option to allow the specification of the onboard memory, and
+ *	 an asize option, to allow the specification of the aperture
+ *	 size.  The aperture must be equal to or less then the memory
+ *	 size, the driver will correct this if you screw it up.  This
+ *	 problem is not relevant for compiled in drivers as compiled
+ *	 in drivers only init once.
+ *
+ * Credits:
+ *       Saeed Karamooz <saeed@ramix.com> of Ramix INC. for the
+ *       initial example code of how to initialize this device and for
+ *       help with questions I had concerning operation of the device.
+ *
+ *       Most of the MTD code for this driver was originally written
+ *       for the slram.o module in the MTD drivers package which
+ *       allows the mapping of system memory into an MTD device.
+ *       Since the PMC551 memory module is accessed in the same
+ *       fashion as system memory, the slram.c code became a very nice
+ *       fit to the needs of this driver.  All we added was PCI
+ *       detection/initialization to the driver and automatically figure
+ *       out the size via the PCI detection.o, later changes by Corey
+ *       Minyard set up the card to utilize a 1M sliding apature.
+ *
+ *	 Corey Minyard <minyard@nortelnetworks.com>
+ *       * Modified driver to utilize a sliding aperture instead of 
+ *         mapping all memory into kernel space which turned out to
+ *         be very wasteful.
+ *       * Located a bug in the SROM's initialization sequence that 
+ *         made the memory unusable, added a fix to code to touch up
+ *         the DRAM some.
+ *
+ * Bugs/FIXME's:
+ *       * MUST fix the init function to not spin on a register
+ *       waiting for it to set .. this does not safely handle busted
+ *       devices that never reset the register correctly which will
+ *       cause the system to hang w/ a reboot being the only chance at
+ *       recover.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <stdarg.h>
+#include <linux/pci.h>
+
+#ifndef CONFIG_PCI
+#error Enable PCI in your kernel config
+#endif
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/pmc551.h>
+#include <linux/mtd/compatmac.h>
+
+#if LINUX_VERSION_CODE > 0x20300
+#define PCI_BASE_ADDRESS(dev) (dev->resource[0].start)
+#else
+#define PCI_BASE_ADDRESS(dev) (dev->base_address[0])
+#endif
+
+static struct mtd_info *pmc551list;
+
+static int pmc551_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+        struct mypriv *priv = mtd->priv;
+        u32 start_addr_highbits;
+        u32 end_addr_highbits;
+        u32 start_addr_lowbits;
+        u32 end_addr_lowbits;
+        unsigned long end;
+
+        end = instr->addr + instr->len;
+
+        /* Is it too much memory?  The second check find if we wrap around
+           past the end of a u32. */
+        if ((end > mtd->size) || (end < instr->addr)) {
+                return -EINVAL;
+        }
+
+        start_addr_highbits = instr->addr & PMC551_ADDR_HIGH_MASK;
+        end_addr_highbits = end & PMC551_ADDR_HIGH_MASK;
+        start_addr_lowbits = instr->addr & PMC551_ADDR_LOW_MASK;
+        end_addr_lowbits = end & PMC551_ADDR_LOW_MASK;
+
+        pci_write_config_dword ( priv->dev,
+                                 PMC551_PCI_MEM_MAP0,
+                                 (priv->mem_map0_base_val
+                                  | start_addr_highbits));
+        if (start_addr_highbits == end_addr_highbits) {
+                /* The whole thing fits within one access, so just one shot
+                   will do it. */
+                memset(priv->start + start_addr_lowbits,
+                       0xff,
+                       instr->len);
+        } else {
+                /* We have to do multiple writes to get all the data
+                   written. */
+                memset(priv->start + start_addr_lowbits,
+                       0xff,
+                       priv->aperture_size - start_addr_lowbits);
+                start_addr_highbits += priv->aperture_size;
+                while (start_addr_highbits != end_addr_highbits) {
+                        pci_write_config_dword ( priv->dev,
+                                                 PMC551_PCI_MEM_MAP0,
+                                                 (priv->mem_map0_base_val
+                                                  | start_addr_highbits));
+                        memset(priv->start,
+                               0xff,
+                               priv->aperture_size);
+                        start_addr_highbits += priv->aperture_size;
+                }
+                priv->curr_mem_map0_val = (priv->mem_map0_base_val
+                                           | start_addr_highbits);
+                pci_write_config_dword ( priv->dev,
+                                         PMC551_PCI_MEM_MAP0,
+                                         priv->curr_mem_map0_val);
+                memset(priv->start,
+                       0xff,
+                       end_addr_lowbits);
+        }
+
+	instr->state = MTD_ERASE_DONE;
+
+        if (instr->callback) {
+                (*(instr->callback))(instr);
+	}
+
+        return 0;
+}
+
+
+static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr)
+{}
+
+
+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;
+        u32 start_addr_highbits;
+        u32 end_addr_highbits;
+        u32 start_addr_lowbits;
+        u32 end_addr_lowbits;
+        unsigned long end;
+        u_char *copyto = buf;
+
+
+        /* Is it past the end? */
+        if (from > mtd->size) {
+                return -EINVAL;
+        }
+
+        end = from + len;
+        start_addr_highbits = from & PMC551_ADDR_HIGH_MASK;
+        end_addr_highbits = end & PMC551_ADDR_HIGH_MASK;
+        start_addr_lowbits = from & PMC551_ADDR_LOW_MASK;
+        end_addr_lowbits = end & PMC551_ADDR_LOW_MASK;
+
+
+        /* Only rewrite the first value if it doesn't match our current
+           values.  Most operations are on the same page as the previous
+           value, so this is a pretty good optimization. */
+        if (priv->curr_mem_map0_val !=
+                        (priv->mem_map0_base_val | start_addr_highbits)) {
+                priv->curr_mem_map0_val = (priv->mem_map0_base_val
+                                           | start_addr_highbits);
+                pci_write_config_dword ( priv->dev,
+                                         PMC551_PCI_MEM_MAP0,
+                                         priv->curr_mem_map0_val);
+        }
+
+        if (start_addr_highbits == end_addr_highbits) {
+                /* The whole thing fits within one access, so just one shot
+                   will do it. */
+                memcpy(copyto,
+                       priv->start + start_addr_lowbits,
+                       len);
+                copyto += len;
+        } else {
+                /* We have to do multiple writes to get all the data
+                   written. */
+                memcpy(copyto,
+                       priv->start + start_addr_lowbits,
+                       priv->aperture_size - start_addr_lowbits);
+                copyto += priv->aperture_size - start_addr_lowbits;
+                start_addr_highbits += priv->aperture_size;
+                while (start_addr_highbits != end_addr_highbits) {
+                        pci_write_config_dword ( priv->dev,
+                                                 PMC551_PCI_MEM_MAP0,
+                                                 (priv->mem_map0_base_val
+                                                  | start_addr_highbits));
+                        memcpy(copyto,
+                               priv->start,
+                               priv->aperture_size);
+                        copyto += priv->aperture_size;
+                        start_addr_highbits += priv->aperture_size;
+                        if (start_addr_highbits >= mtd->size) {
+                                /* Make sure we have the right value here. */
+                                priv->curr_mem_map0_val
+                                = (priv->mem_map0_base_val
+                                   | start_addr_highbits);
+                                goto out;
+                        }
+                }
+                priv->curr_mem_map0_val = (priv->mem_map0_base_val
+                                           | start_addr_highbits);
+                pci_write_config_dword ( priv->dev,
+                                         PMC551_PCI_MEM_MAP0,
+                                         priv->curr_mem_map0_val);
+                memcpy(copyto,
+                       priv->start,
+                       end_addr_lowbits);
+                copyto += end_addr_lowbits;
+        }
+
+out:
+        *retlen = copyto - buf;
+        return 0;
+}
+
+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;
+        u32 start_addr_highbits;
+        u32 end_addr_highbits;
+        u32 start_addr_lowbits;
+        u32 end_addr_lowbits;
+        unsigned long end;
+        const u_char *copyfrom = buf;
+
+
+        /* Is it past the end? */
+        if (to > mtd->size) {
+                return -EINVAL;
+        }
+
+        end = to + len;
+        start_addr_highbits = to & PMC551_ADDR_HIGH_MASK;
+        end_addr_highbits = end & PMC551_ADDR_HIGH_MASK;
+        start_addr_lowbits = to & PMC551_ADDR_LOW_MASK;
+        end_addr_lowbits = end & PMC551_ADDR_LOW_MASK;
+
+
+        /* Only rewrite the first value if it doesn't match our current
+           values.  Most operations are on the same page as the previous
+           value, so this is a pretty good optimization. */
+        if (priv->curr_mem_map0_val !=
+                        (priv->mem_map0_base_val | start_addr_highbits)) {
+                priv->curr_mem_map0_val = (priv->mem_map0_base_val
+                                           | start_addr_highbits);
+                pci_write_config_dword ( priv->dev,
+                                         PMC551_PCI_MEM_MAP0,
+                                         priv->curr_mem_map0_val);
+        }
+
+        if (start_addr_highbits == end_addr_highbits) {
+                /* The whole thing fits within one access, so just one shot
+                   will do it. */
+                memcpy(priv->start + start_addr_lowbits,
+                       copyfrom,
+                       len);
+                copyfrom += len;
+        } else {
+                /* We have to do multiple writes to get all the data
+                   written. */
+                memcpy(priv->start + start_addr_lowbits,
+                       copyfrom,
+                       priv->aperture_size - start_addr_lowbits);
+                copyfrom += priv->aperture_size - start_addr_lowbits;
+                start_addr_highbits += priv->aperture_size;
+                while (start_addr_highbits != end_addr_highbits) {
+                        pci_write_config_dword ( priv->dev,
+                                                 PMC551_PCI_MEM_MAP0,
+                                                 (priv->mem_map0_base_val
+                                                  | start_addr_highbits));
+                        memcpy(priv->start,
+                               copyfrom,
+                               priv->aperture_size);
+                        copyfrom += priv->aperture_size;
+                        start_addr_highbits += priv->aperture_size;
+                        if (start_addr_highbits >= mtd->size) {
+                                /* Make sure we have the right value here. */
+                                priv->curr_mem_map0_val
+                                = (priv->mem_map0_base_val
+                                   | start_addr_highbits);
+                                goto out;
+                        }
+                }
+                priv->curr_mem_map0_val = (priv->mem_map0_base_val
+                                           | start_addr_highbits);
+                pci_write_config_dword ( priv->dev,
+                                         PMC551_PCI_MEM_MAP0,
+                                         priv->curr_mem_map0_val);
+                memcpy(priv->start,
+                       copyfrom,
+                       end_addr_lowbits);
+                copyfrom += end_addr_lowbits;
+        }
+
+out:
+        *retlen = copyfrom - buf;
+        return 0;
+}
+
+/*
+ * Fixup routines for the V370PDC
+ * PCI device ID 0x020011b0
+ *
+ * This function basicly kick starts the DRAM oboard the card and gets it
+ * ready to be used.  Before this is done the device reads VERY erratic, so
+ * much that it can crash the Linux 2.2.x series kernels when a user cat's
+ * /proc/pci .. though that is mainly a kernel bug in handling the PCI DEVSEL
+ * register.  FIXME: stop spinning on registers .. must implement a timeout
+ * mechanism
+ * returns the size of the memory region found.
+ */
+static u32 fixup_pmc551 (struct pci_dev *dev)
+{
+#ifdef CONFIG_MTD_PMC551_BUGFIX
+        u32 dram_data;
+#endif
+        u32 size, dcmd, cfg, dtmp;
+        u16 cmd, tmp, i;
+	u8 bcmd, counter;
+
+        /* Sanity Check */
+        if(!dev) {
+                return -ENODEV;
+        }
+
+	/*
+	 * Attempt to reset the card
+	 * FIXME: Stop Spinning registers
+	 */
+	counter=0;
+	/* unlock registers */
+	pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, 0xA5 );
+	/* read in old data */
+	pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd );
+	/* bang the reset line up and down for a few */
+	for(i=0;i<10;i++) {
+		counter=0;
+		bcmd &= ~0x80;
+		while(counter++ < 100) {
+			pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
+		}
+		counter=0;
+		bcmd |= 0x80;
+		while(counter++ < 100) {
+			pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
+		}
+	}
+	bcmd |= (0x40|0x20);
+	pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
+
+        /* 
+	 * Take care and turn off the memory on the device while we
+	 * tweak the configurations
+	 */
+        pci_read_config_word(dev, PCI_COMMAND, &cmd);
+        tmp = cmd & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY);
+        pci_write_config_word(dev, PCI_COMMAND, tmp);
+
+	/*
+	 * Disable existing aperture before probing memory size
+	 */
+	pci_read_config_dword(dev, PMC551_PCI_MEM_MAP0, &dcmd);
+        dtmp=(dcmd|PMC551_PCI_MEM_MAP_ENABLE|PMC551_PCI_MEM_MAP_REG_EN);
+	pci_write_config_dword(dev, PMC551_PCI_MEM_MAP0, dtmp);
+	/*
+	 * Grab old BAR0 config so that we can figure out memory size
+	 * This is another bit of kludge going on.  The reason for the
+	 * redundancy is I am hoping to retain the original configuration
+	 * previously assigned to the card by the BIOS or some previous 
+	 * fixup routine in the kernel.  So we read the old config into cfg,
+	 * then write all 1's to the memory space, read back the result into
+	 * "size", and then write back all the old config.
+	 */
+	pci_read_config_dword( dev, PCI_BASE_ADDRESS_0, &cfg );
+#ifndef CONFIG_MTD_PMC551_BUGFIX
+	pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, ~0 );
+	pci_read_config_dword( dev, PCI_BASE_ADDRESS_0, &size );
+	pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
+	size=~(size&PCI_BASE_ADDRESS_MEM_MASK)+1;
+#else
+        /*
+         * Get the size of the memory by reading all the DRAM size values
+         * and adding them up.
+         *
+         * KLUDGE ALERT: the boards we are using have invalid column and
+         * row mux values.  We fix them here, but this will break other
+         * memory configurations.
+         */
+        pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dram_data);
+        size = PMC551_DRAM_BLK_GET_SIZE(dram_data);
+        dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
+        dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
+        pci_write_config_dword(dev, PMC551_DRAM_BLK0, dram_data);
+
+        pci_read_config_dword(dev, PMC551_DRAM_BLK1, &dram_data);
+        size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
+        dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
+        dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
+        pci_write_config_dword(dev, PMC551_DRAM_BLK1, dram_data);
+
+        pci_read_config_dword(dev, PMC551_DRAM_BLK2, &dram_data);
+        size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
+        dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
+        dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
+        pci_write_config_dword(dev, PMC551_DRAM_BLK2, dram_data);
+
+        pci_read_config_dword(dev, PMC551_DRAM_BLK3, &dram_data);
+        size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
+        dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
+        dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
+        pci_write_config_dword(dev, PMC551_DRAM_BLK3, dram_data);
+
+        /*
+         * Oops .. something went wrong
+         */
+        if( (size &= PCI_BASE_ADDRESS_MEM_MASK) == 0) {
+                return -ENODEV;
+        }
+#endif /* CONFIG_MTD_PMC551_BUGFIX */
+
+	if ((cfg&PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
+                return -ENODEV;
+	}
+
+        /*
+         * Precharge Dram
+         */
+        pci_write_config_word( dev, PMC551_SDRAM_MA, 0x0400 );
+        pci_write_config_word( dev, PMC551_SDRAM_CMD, 0x00bf );
+
+        /*
+         * Wait until command has gone through
+         * FIXME: register spinning issue
+         */
+        do {	pci_read_config_word( dev, PMC551_SDRAM_CMD, &cmd );
+		if(counter++ > 100)break;
+        } while ( (PCI_COMMAND_IO) & cmd );
+
+        /*
+	 * Turn on auto refresh 
+	 * The loop is taken directly from Ramix's example code.  I assume that
+	 * this must be held high for some duration of time, but I can find no
+	 * documentation refrencing the reasons why.
+	 * 
+         */
+        for ( i = 1; i<=8 ; i++) {
+                pci_write_config_word (dev, PMC551_SDRAM_CMD, 0x0df);
+
+                /*
+                 * Make certain command has gone through
+                 * FIXME: register spinning issue
+                 */
+		counter=0;
+                do {	pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
+			if(counter++ > 100)break;
+                } while ( (PCI_COMMAND_IO) & cmd );
+        }
+
+        pci_write_config_word ( dev, PMC551_SDRAM_MA, 0x0020);
+        pci_write_config_word ( dev, PMC551_SDRAM_CMD, 0x0ff);
+
+        /*
+         * Wait until command completes
+         * FIXME: register spinning issue
+         */
+	counter=0;
+        do {	pci_read_config_word ( dev, PMC551_SDRAM_CMD, &cmd);
+		if(counter++ > 100)break;
+        } while ( (PCI_COMMAND_IO) & cmd );
+
+        pci_read_config_dword ( dev, PMC551_DRAM_CFG, &dcmd);
+        dcmd |= 0x02000000;
+        pci_write_config_dword ( dev, PMC551_DRAM_CFG, dcmd);
+
+        /*
+         * Check to make certain fast back-to-back, if not
+         * then set it so
+         */
+        pci_read_config_word( dev, PCI_STATUS, &cmd);
+        if((cmd&PCI_COMMAND_FAST_BACK) == 0) {
+                cmd |= PCI_COMMAND_FAST_BACK;
+                pci_write_config_word( dev, PCI_STATUS, cmd);
+        }
+
+        /*
+         * Check to make certain the DEVSEL is set correctly, this device
+         * has a tendancy to assert DEVSEL and TRDY when a write is performed
+         * to the memory when memory is read-only
+         */
+        if((cmd&PCI_STATUS_DEVSEL_MASK) != 0x0) {
+                cmd &= ~PCI_STATUS_DEVSEL_MASK;
+                pci_write_config_word( dev, PCI_STATUS, cmd );
+        }
+        /*
+         * Set to be prefetchable and put everything back based on old cfg.
+	 * it's possible that the reset of the V370PDC nuked the original
+	 * setup
+         */
+        cfg |= PCI_BASE_ADDRESS_MEM_PREFETCH;
+	pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
+
+        /*
+         * Turn PCI memory and I/O bus access back on
+         */
+        pci_write_config_word( dev, PCI_COMMAND,
+                               PCI_COMMAND_MEMORY | PCI_COMMAND_IO );
+#ifdef CONFIG_MTD_PMC551_DEBUG
+        /*
+         * Some screen fun
+         */
+        printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at 0x%lx\n",
+	       (size<1024)?size:(size<1048576)?size/1024:size/1024/1024,
+               (size<1024)?'B':(size<1048576)?'K':'M',
+	       size, ((dcmd&(0x1<<3)) == 0)?"non-":"",
+               PCI_BASE_ADDRESS(dev)&PCI_BASE_ADDRESS_MEM_MASK );
+
+        /*
+         * Check to see the state of the memory
+         */
+        pci_read_config_dword( dev, PMC551_DRAM_BLK0, &dcmd );
+        printk(KERN_DEBUG "pmc551: DRAM_BLK0 Flags: %s,%s\n"
+			  "pmc551: DRAM_BLK0 Size: %d at %d\n"
+			  "pmc551: DRAM_BLK0 Row MUX: %d, Col MUX: %d\n",
+               (((0x1<<1)&dcmd) == 0)?"RW":"RO",
+               (((0x1<<0)&dcmd) == 0)?"Off":"On",
+	       PMC551_DRAM_BLK_GET_SIZE(dcmd),
+	       ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
+
+        pci_read_config_dword( dev, PMC551_DRAM_BLK1, &dcmd );
+        printk(KERN_DEBUG "pmc551: DRAM_BLK1 Flags: %s,%s\n"
+			  "pmc551: DRAM_BLK1 Size: %d at %d\n"
+			  "pmc551: DRAM_BLK1 Row MUX: %d, Col MUX: %d\n",
+               (((0x1<<1)&dcmd) == 0)?"RW":"RO",
+               (((0x1<<0)&dcmd) == 0)?"Off":"On",
+	       PMC551_DRAM_BLK_GET_SIZE(dcmd),
+	       ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
+
+        pci_read_config_dword( dev, PMC551_DRAM_BLK2, &dcmd );
+        printk(KERN_DEBUG "pmc551: DRAM_BLK2 Flags: %s,%s\n"
+			  "pmc551: DRAM_BLK2 Size: %d at %d\n"
+			  "pmc551: DRAM_BLK2 Row MUX: %d, Col MUX: %d\n",
+               (((0x1<<1)&dcmd) == 0)?"RW":"RO",
+               (((0x1<<0)&dcmd) == 0)?"Off":"On",
+	       PMC551_DRAM_BLK_GET_SIZE(dcmd),
+	       ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
+
+        pci_read_config_dword( dev, PMC551_DRAM_BLK3, &dcmd );
+        printk(KERN_DEBUG "pmc551: DRAM_BLK3 Flags: %s,%s\n"
+			  "pmc551: DRAM_BLK3 Size: %d at %d\n"
+			  "pmc551: DRAM_BLK3 Row MUX: %d, Col MUX: %d\n",
+               (((0x1<<1)&dcmd) == 0)?"RW":"RO",
+               (((0x1<<0)&dcmd) == 0)?"Off":"On",
+	       PMC551_DRAM_BLK_GET_SIZE(dcmd),
+	       ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
+
+        pci_read_config_word( dev, PCI_COMMAND, &cmd );
+        printk( KERN_DEBUG "pmc551: Memory Access %s\n",
+                (((0x1<<1)&cmd) == 0)?"off":"on" );
+        printk( KERN_DEBUG "pmc551: I/O Access %s\n",
+                (((0x1<<0)&cmd) == 0)?"off":"on" );
+
+        pci_read_config_word( dev, PCI_STATUS, &cmd );
+        printk( KERN_DEBUG "pmc551: Devsel %s\n",
+                ((PCI_STATUS_DEVSEL_MASK&cmd)==0x000)?"Fast":
+                ((PCI_STATUS_DEVSEL_MASK&cmd)==0x200)?"Medium":
+                ((PCI_STATUS_DEVSEL_MASK&cmd)==0x400)?"Slow":"Invalid" );
+
+        printk( KERN_DEBUG "pmc551: %sFast Back-to-Back\n",
+                ((PCI_COMMAND_FAST_BACK&cmd) == 0)?"Not ":"" );
+
+	pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd );
+	printk( KERN_DEBUG "pmc551: EEPROM is under %s control\n"
+			   "pmc551: System Control Register is %slocked to PCI access\n"
+			   "pmc551: System Control Register is %slocked to EEPROM access\n", 
+		(bcmd&0x1)?"software":"hardware",
+		(bcmd&0x20)?"":"un", (bcmd&0x40)?"":"un");
+#endif
+        return size;
+}
+
+/*
+ * Kernel version specific module stuffages
+ */
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_pmc551 init_module
+#define cleanup_pmc551 cleanup_module
+#endif
+
+#if defined(MODULE)
+MODULE_AUTHOR("Mark Ferrell <mferrell@mvista.com>");
+MODULE_DESCRIPTION(PMC551_VERSION);
+MODULE_PARM(msize, "i");
+MODULE_PARM_DESC(msize, "memory size, 6=32M, 7=64M, 8=128M, etc.. [32M-1024M]");
+MODULE_PARM(asize, "i");
+MODULE_PARM_DESC(asize, "aperture size, must be <= memsize [1M-1024M]");
+#endif
+/*
+ * Stuff these outside the ifdef so as to not bust compiled in driver support
+ */
+static int msize=0;
+#if defined(CONFIG_MTD_PMC551_APERTURE_SIZE)
+static int asize=CONFIG_MTD_PMC551_APERTURE_SIZE
+#else
+static int asize=0;
+#endif
+
+/*
+ * PMC551 Card Initialization
+ */
+int __init init_pmc551(void)
+{
+        struct pci_dev *PCI_Device = NULL;
+        struct mypriv *priv;
+        int count, found=0;
+        struct mtd_info *mtd;
+        u32 length = 0;
+
+	if(msize) {
+		if (msize < 6 || msize > 11 ) {
+			printk(KERN_NOTICE "pmc551: Invalid memory size\n");
+			return -ENODEV;
+		}
+		msize = (512*1024)<<msize;
+	}
+
+	if(asize) {
+		if (asize < 1 || asize > 11 ) {
+			printk(KERN_NOTICE "pmc551: Invalid aperture size\n");
+			return -ENODEV;
+		}
+		asize = (512*1024)<<asize;
+	}
+
+        printk(KERN_INFO PMC551_VERSION);
+
+        if(!pci_present()) {
+                printk(KERN_NOTICE "pmc551: PCI not enabled.\n");
+                return -ENODEV;
+        }
+
+        /*
+         * PCU-bus chipset probe.
+         */
+        for( count = 0; count < MAX_MTD_DEVICES; count++ ) {
+
+                if ( (PCI_Device = pci_find_device( PCI_VENDOR_ID_V3_SEMI,
+                                                    PCI_DEVICE_ID_V3_SEMI_V370PDC, PCI_Device ) ) == NULL) {
+                        break;
+                }
+
+                printk(KERN_NOTICE "pmc551: Found PCI V370PDC IRQ:%d\n",
+                       PCI_Device->irq);
+
+                /*
+                 * The PMC551 device acts VERY weird if you don't init it
+                 * first.  i.e. it will not correctly report devsel.  If for
+                 * some reason the sdram is in a wrote-protected state the
+                 * device will DEVSEL when it is written to causing problems
+                 * with the oldproc.c driver in
+                 * some kernels (2.2.*)
+                 */
+                if((length = fixup_pmc551(PCI_Device)) <= 0) {
+                        printk(KERN_NOTICE "pmc551: Cannot init SDRAM\n");
+                        break;
+                }
+		if(msize) {
+			length = msize;
+			printk(KERN_NOTICE "pmc551: Using specified memory size 0x%x\n", length);
+		}
+
+                mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+                if (!mtd) {
+                        printk(KERN_NOTICE "pmc551: Cannot allocate new MTD device.\n");
+                        break;
+                }
+
+                memset(mtd, 0, sizeof(struct mtd_info));
+
+                priv = kmalloc (sizeof(struct mypriv), GFP_KERNEL);
+                if (!priv) {
+                        printk(KERN_NOTICE "pmc551: Cannot allocate new MTD device.\n");
+                        kfree(mtd);
+                        break;
+                }
+                memset(priv, 0, sizeof(*priv));
+                mtd->priv = priv;
+
+                priv->dev = PCI_Device;
+		if(asize) {
+			if(asize > length) {
+				asize=length;
+				printk(KERN_NOTICE "pmc551: reducing aperture size to fit memory [0x%x]\n",asize);
+			} else {
+				printk(KERN_NOTICE "pmc551: Using specified aperture size 0x%x\n", asize);
+			}
+			priv->aperture_size = asize;
+		} else {
+                	priv->aperture_size = length;
+		}
+                priv->start = ioremap((PCI_BASE_ADDRESS(PCI_Device)
+                                       & PCI_BASE_ADDRESS_MEM_MASK),
+                                      priv->aperture_size);
+		
+		if (!priv->start) {
+                        kfree(mtd->priv);
+                        kfree(mtd);
+			break;
+		}
+		/*
+		 * Due to the dynamic nature of the code, we need to figure
+		 * this out in order to stuff the register to set the proper
+		 * aperture size.  If you know of an easier way to do this then
+		 * PLEASE help yourself.
+		 *
+		 * Not with bloody floating point, you don't. Consider yourself
+		 * duly LARTed. dwmw2.
+		 */
+		{
+			u32 size;
+			u16 bits;
+			size = priv->aperture_size>>20;
+			for(bits=0;!(size&0x01)&&size>0;bits++,size=size>>1);
+			//size=((u32)((log10(priv->aperture_size)/.30103)-19)<<4);
+                	priv->mem_map0_base_val = (PMC551_PCI_MEM_MAP_REG_EN
+						| PMC551_PCI_MEM_MAP_ENABLE
+						| size);
+#ifdef CONFIG_MTD_PMC551_DEBUG
+			printk(KERN_NOTICE "pmc551: aperture set to %d[%d]\n", 
+					size, size>>4);
+#endif
+		}
+                priv->curr_mem_map0_val = priv->mem_map0_base_val;
+
+                pci_write_config_dword ( priv->dev,
+                                         PMC551_PCI_MEM_MAP0,
+                                         priv->curr_mem_map0_val);
+
+                mtd->size 		= length;
+                mtd->flags 		= (MTD_CLEAR_BITS
+                                | MTD_SET_BITS
+                                | MTD_WRITEB_WRITEABLE
+                                | MTD_VOLATILE);
+                mtd->erase 		= pmc551_erase;
+                mtd->point 		= NULL;
+                mtd->unpoint 		= pmc551_unpoint;
+                mtd->read 		= pmc551_read;
+                mtd->write 		= pmc551_write;
+                mtd->module 		= THIS_MODULE;
+                mtd->type 		= MTD_RAM;
+                mtd->name 		= "PMC551 RAM board";
+                mtd->erasesize 		= 0x10000;
+
+                if (add_mtd_device(mtd)) {
+                        printk(KERN_NOTICE "pmc551: Failed to register new device\n");
+			iounmap(priv->start);
+                        kfree(mtd->priv);
+                        kfree(mtd);
+                        break;
+                }
+                printk(KERN_NOTICE "Registered pmc551 memory device.\n");
+                printk(KERN_NOTICE "Mapped %dM of memory from 0x%p to 0x%p\n",
+                       priv->aperture_size/1024/1024,
+                       priv->start,
+                       priv->start + priv->aperture_size);
+                printk(KERN_NOTICE "Total memory is %d%c\n",
+	       		(length<1024)?length:
+				(length<1048576)?length/1024:length/1024/1024,
+               		(length<1024)?'B':(length<1048576)?'K':'M');
+		priv->nextpmc551 = pmc551list;
+		pmc551list = mtd;
+		found++;
+        }
+
+        if( !pmc551list ) {
+                printk(KERN_NOTICE "pmc551: not detected,\n");
+                return -ENODEV;
+        } else {
+		printk(KERN_NOTICE "pmc551: %d pmc551 devices loaded\n", found);
+                return 0;
+	}
+}
+
+/*
+ * PMC551 Card Cleanup
+ */
+static void __exit cleanup_pmc551(void)
+{
+        int found=0;
+        struct mtd_info *mtd;
+	struct mypriv *priv;
+
+	while((mtd=pmc551list)) {
+		priv = (struct mypriv *)mtd->priv;
+		pmc551list = priv->nextpmc551;
+		
+		if(priv->start)
+			iounmap(priv->start);
+		
+		kfree (mtd->priv);
+		del_mtd_device(mtd);
+		kfree(mtd);
+		found++;
+	}
+
+	printk(KERN_NOTICE "pmc551: %d pmc551 devices unloaded\n", found);
+}
+
+module_init(init_pmc551);
+module_exit(cleanup_pmc551);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/devices/slram.c linux/drivers/mtd/devices/slram.c
--- v2.4.5/linux/drivers/mtd/devices/slram.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/devices/slram.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,341 @@
+/*======================================================================
+
+  $Id: slram.c,v 1.19 2001/06/02 20:33:20 dwmw2 Exp $
+
+======================================================================*/
+
+
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <stdarg.h>
+
+#include <linux/mtd/mtd.h>
+
+#define SLRAM_MAX_DEVICES_PARAMS 6		/* 3 parameters / device */
+
+#define T(fmt, args...) printk(KERN_DEBUG fmt, ## args)
+#define E(fmt, args...) printk(KERN_NOTICE fmt, ## args)
+
+typedef struct slram_priv {
+	u_char *start;
+	u_char *end;
+} slram_priv_t;
+
+typedef struct slram_mtd_list {
+	struct mtd_info *mtdinfo;
+	struct slram_mtd_list *next;
+} slram_mtd_list_t;
+
+#ifdef MODULE
+static char *map[SLRAM_MAX_DEVICES_PARAMS];
+#else
+static char *map;
+#endif
+
+#ifdef MODULE
+#if LINUX_VERSION_CODE < 0x20212
+#define init_slram init_module
+#define cleanup_slram cleanup_module
+#endif
+
+MODULE_PARM(map, "3-" __MODULE_STRING(SLRAM_MAX_DEVICES_PARAMS) "s");
+MODULE_PARM_DESC(map, "List of memory regions to map. \"map=<name>, <start>, <length / end>\"");
+#endif
+
+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 *);
+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 *);
+
+int slram_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	slram_priv_t *priv = mtd->priv;
+
+	if (instr->addr + instr->len > mtd->size) {
+		return(-EINVAL);
+	}
+	
+	memset(priv->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;
+
+	if (instr->callback) {
+		(*(instr->callback))(instr);
+	}
+	else {
+		kfree(instr);
+	}
+
+	return(0);
+}
+
+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;
+
+	*mtdbuf = priv->start + from;
+	*retlen = len;
+	return(0);
+}
+
+void slram_unpoint(struct mtd_info *mtd, u_char *addr)
+{
+}
+
+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;
+	
+	memcpy(buf, priv->start + from, len);
+
+	*retlen = len;
+	return(0);
+}
+
+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;
+
+	memcpy(priv->start + to, buf, len);
+
+	*retlen = len;
+	return(0);
+}
+
+/*====================================================================*/
+
+int register_device(char *name, long start, long length)
+{
+	slram_mtd_list_t **curmtd;
+
+	curmtd = &slram_mtdlist;
+	while (*curmtd) {
+		curmtd = &(*curmtd)->next;
+	}
+
+	*curmtd = kmalloc(sizeof(slram_mtd_list_t), GFP_KERNEL);
+	if (!curmtd) {
+		E("slram: Cannot allocate new MTD device.\n");
+		return(-ENOMEM);
+	}
+	(*curmtd)->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+	(*curmtd)->next = NULL;
+	
+	if ((*curmtd)->mtdinfo)	{
+		memset((char *)(*curmtd)->mtdinfo, 0, sizeof(struct mtd_info));
+		(*curmtd)->mtdinfo->priv =
+			(void *)kmalloc(sizeof(slram_priv_t), GFP_KERNEL);
+		
+		if (!(*curmtd)->mtdinfo->priv) {
+			kfree((*curmtd)->mtdinfo);
+			(*curmtd)->mtdinfo = NULL;
+		} else {
+			memset((*curmtd)->mtdinfo->priv,0,sizeof(slram_priv_t));
+		}
+	}
+
+	if (!(*curmtd)->mtdinfo) {
+		E("slram: Cannot allocate new MTD device.\n");
+		return(-ENOMEM);
+	}
+	
+	if (!(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start =
+				ioremap(start, length))) {
+		E("slram: ioremap failed\n");
+		return -EIO;
+	}
+	((slram_priv_t *)(*curmtd)->mtdinfo->priv)->end =
+		((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start + length;
+
+
+	(*curmtd)->mtdinfo->name = name;
+	(*curmtd)->mtdinfo->size = length;
+	(*curmtd)->mtdinfo->flags = MTD_CLEAR_BITS | MTD_SET_BITS |
+					MTD_WRITEB_WRITEABLE | MTD_VOLATILE;
+        (*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->type = MTD_RAM;
+	(*curmtd)->mtdinfo->erasesize = 0x10000;
+
+	if (add_mtd_device((*curmtd)->mtdinfo))	{
+		E("slram: Failed to register new device\n");
+		iounmap(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start);
+		kfree((*curmtd)->mtdinfo->priv);
+		kfree((*curmtd)->mtdinfo);
+		return(-EAGAIN);
+	}
+	T("slram: Registered device %s from %dKiB to %dKiB\n", name,
+			(int)(start / 1024), (int)((start + length) / 1024));
+	T("slram: Mapped from 0x%p to 0x%p\n",
+			((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start,
+			((slram_priv_t *)(*curmtd)->mtdinfo->priv)->end);
+	return(0);	
+}
+
+void unregister_devices(void)
+{
+	slram_mtd_list_t *nextitem;
+
+	while (slram_mtdlist) {
+		nextitem = slram_mtdlist->next;
+		del_mtd_device(slram_mtdlist->mtdinfo);
+		iounmap(((slram_priv_t *)slram_mtdlist->mtdinfo->priv)->start);
+		kfree(slram_mtdlist->mtdinfo->priv);
+		kfree(slram_mtdlist->mtdinfo);
+		kfree(slram_mtdlist);
+		slram_mtdlist = nextitem;
+	}
+}
+
+int handle_unit(long value, char *unit)
+{
+	if ((*unit == 'M') || (*unit == 'm')) {
+		return(value * 1024 * 1024);
+	} else if ((*unit == 'K') || (*unit == 'k')) {
+		return(value * 1024);
+	}
+	return(value);
+}
+
+int parse_cmdline(char *devname, char *szstart, char *szlength)
+{
+	char *buffer;
+	long devstart;
+	long devlength;
+	
+	if ((!devname) || (!szstart) || (!szlength)) {
+		unregister_devices();
+		return(-EINVAL);
+	}
+
+	devstart = simple_strtoul(szstart, &buffer, 0);
+	devstart = handle_unit(devstart, buffer);
+	
+	if (*(szlength) != '+') {
+		devlength = simple_strtoul(szlength, &buffer, 0);
+		devlength = handle_unit(devlength, buffer) - devstart;
+	} else {
+		devlength = simple_strtoul(szlength + 1, &buffer, 0);
+		devlength = handle_unit(devlength, buffer);
+	}
+	T("slram: devname=%s, devstart=%li, devlength=%li\n",
+			devname, devstart, devlength);
+	if ((devstart < 0) || (devlength < 0)) {
+		E("slram: Illegal start / length parameter.\n");
+		return(-EINVAL);
+	}
+	
+	if ((devstart = register_device(devname, devstart, devlength))){
+		unregister_devices();
+		return((int)devstart);
+	}
+	return(0);
+}
+
+#ifndef MODULE
+
+static int __init mtd_slram_setup(char *str)
+{
+	map = str;
+	return(1);
+}
+
+__setup("slram=", mtd_slram_setup);
+
+#endif
+
+int init_slram(void)
+{
+	char *devname;
+	int i;
+
+#ifndef MODULE
+	char *devstart;
+	char *devlength;
+
+	i = 0;
+
+	if (!map) {
+		E("slram: not enough parameters.\n");
+		return(-EINVAL);
+	}
+	while (map) {
+		devname = devstart = devlength = NULL;
+
+		if (!(devname = strsep(&map, ","))) {
+			E("slram: No devicename specified.\n");
+			break;
+		}
+		T("slram: devname = %s\n", devname);
+		if ((!map) || (!(devstart = strsep(&map, ",")))) {
+			E("slram: No devicestart specified.\n");
+		}
+		T("slram: devstart = %s\n", devstart);
+		if ((!map) || (!(devlength = strsep(&map, ",")))) {
+			E("slram: No devicelength / -end specified.\n");
+		}
+		T("slram: devlength = %s\n", devlength);
+		if (parse_cmdline(devname, devstart, devlength) != 0) {
+			return(-EINVAL);
+		}
+	}
+#else
+	int count;
+	
+	for (count = 0; (map[count]) && (count < SLRAM_MAX_DEVICES_PARAMS);
+			count++) {
+	}
+
+	if ((count % 3 != 0) || (count == 0)) {
+		E("slram: not enough parameters.\n");
+		return(-EINVAL);
+	}
+	for (i = 0; i < (count / 3); i++) {
+		devname = map[i * 3];
+
+		if (parse_cmdline(devname, map[i * 3 + 1], map[i * 3 + 2])!=0) {
+			return(-EINVAL);
+		}
+		
+	}
+#endif /* !MODULE */
+	
+	return(0);
+}
+
+static void __exit cleanup_slram(void)
+{
+	unregister_devices();
+}
+
+module_init(init_slram);
+module_exit(cleanup_slram);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/doc1000.c linux/drivers/mtd/doc1000.c
--- v2.4.5/linux/drivers/mtd/doc1000.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/doc1000.c	Wed Dec 31 16:00:00 1969
@@ -1,597 +0,0 @@
-/*======================================================================
-
-  $Id: doc1000.c,v 1.11 2000/11/24 13:43:16 dwmw2 Exp $
-
-======================================================================*/
-
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/major.h>
-#include <linux/fs.h>
-#include <linux/ioctl.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <stdarg.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/iflash.h>
-
-/* Parameters that can be set with 'insmod' */
-
-static u_long base              = 0xe0000;
-static int erase_timeout	= 10*HZ;	/* in ticks */
-static int retry_limit		= 4;		/* write retries */
-static u_long max_tries       	= 4096;		/* status polling */
-
-MODULE_PARM(base,"l");
-MODULE_PARM(erase_timeout, "i");
-MODULE_PARM(retry_limit, "i");
-MODULE_PARM(max_tries, "i");
-
-#define WINDOW_SIZE 0x2000
-#define WINDOW_MASK (WINDOW_SIZE - 1)
-#define PAGEREG_LO (WINDOW_SIZE)
-#define PAGEREG_HI (WINDOW_SIZE + 2)
-
-static struct mtd_info *mymtd;
-static struct timer_list flashcard_timer;
-
-#define MAX_CELLS		32
-#define MAX_FLASH_DEVICES       8
-
-/* A flash region is composed of one or more "cells", where we allow
-   simultaneous erases if they are in different cells */
-
-
-
-struct mypriv {
-	u_char *baseaddr;
-	u_short curpage;
-	u_char locked;
-	u_short numdevices;
-	u_char interleave;
-	struct erase_info *cur_erases;
-	wait_queue_head_t wq;
-	u_char devstat[MAX_FLASH_DEVICES];
-	u_long devshift;
-};
-
-
-static void flashcard_periodic(u_long data);
-static int flashcard_erase (struct mtd_info *mtd, struct erase_info *instr);
-static int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
-static int flashcard_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
-static void flashcard_sync (struct mtd_info *mtd);
-
-static inline void resume_erase(volatile u_char *addr);
-static inline int suspend_erase(volatile u_char *addr);
-static inline int byte_write (volatile u_char *addr, u_char byte);
-static inline int word_write (volatile u_char *addr, __u16 word);
-static inline int check_write(volatile u_char *addr);
-static inline void block_erase (volatile u_char *addr);
-static inline int check_erase(volatile u_char *addr);
-
-#ifdef CONFIG_SMP
-#warning This is definitely not SMP safe. Lock the paging mechanism.
-#endif
-
-static u_char *pagein(struct mtd_info *mtd, u_long addr)
-{
-  struct mypriv *priv=mtd->priv;
-  u_short page = addr >> 13;
-
-  priv->baseaddr[PAGEREG_LO] = page & 0xff;
-  priv->baseaddr[PAGEREG_HI] = page >> 8;
-  priv->curpage = page;
-  
-  return &priv->baseaddr[addr & WINDOW_MASK];
-}
-
-
-void flashcard_sync (struct mtd_info *mtd)
-{
-	struct mypriv *priv=mtd->priv;
-
-	flashcard_periodic((u_long) mtd);
-	printk("sync...");
-	if (priv->cur_erases)
-		interruptible_sleep_on(&priv->wq);
-	printk("Done.\n");
-}
-
-int flashcard_erase (struct mtd_info *mtd, struct erase_info *instr)
-{
-	u_char *pageaddr;
-	struct mypriv *priv=mtd->priv;
-	struct erase_info **tmp=&priv->cur_erases;
-	
-	if (instr->len != mtd->erasesize)
-		return -EINVAL;
-	if (instr->addr + instr->len > mtd->size)
-		return -EINVAL;
-
-	pageaddr=pagein(mtd,instr->addr);
-	instr->mtd = mtd;
-	instr->dev = instr->addr >> priv->devshift;
-	instr->cell = (instr->addr - (instr->dev << priv->devshift)) / mtd->erasesize;
-	instr->next = NULL;
-	instr->state = MTD_ERASE_PENDING;
-	
-	while (*tmp)
-	{
-		tmp = &((*tmp) -> next);
-	}
-	
-	*tmp = instr;
-	flashcard_periodic((u_long)mtd);
-	return 0;
-}
-
-
-int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-{
- 	u_char *pageaddr=pagein(mtd,from);
-	struct mypriv *priv=mtd->priv;
-	u_char device = from >> priv->devshift;
-	u_char cell = (int) (from - (device << priv->devshift)) / mtd->erasesize;
-	int ret = 0, timeron = 0;
-
-	if ((from & WINDOW_MASK) + len <= WINDOW_SIZE)
-		*retlen = len;
-	else
-		*retlen = WINDOW_SIZE - (from & WINDOW_MASK);
-
-	if (priv->devstat[device])
-	{
-		
-		/* There is an erase in progress or pending for this device. Stop it */
-		timeron = del_timer(&flashcard_timer);
-		
-		if (priv->cur_erases && priv->cur_erases->cell == cell) 
-			
-		{
-			/* The erase is on the current cell. Just return all 0xff */ 
-			add_timer(&flashcard_timer);
-			
-			
-			printk("Cell %d currently erasing. Setting to all 0xff\n",cell);
-			memset(buf, 0xff, *retlen);
-			return 0;
-		}
-		if (priv->devstat[device] == MTD_ERASING)
-		{
-			ret = suspend_erase(pageaddr);
-			priv->devstat[device] = MTD_ERASE_SUSPEND;
-		       
-			if (ret) 
-			{
-				printk("flashcard: failed to suspend erase\n");
-				add_timer (&flashcard_timer);
-				return ret;
-			}
-		}
-
-	}
-
-	writew(IF_READ_ARRAY, (u_long)pageaddr & ~1);
-	
-	ret = 0;
-	memcpy (buf, pageaddr, *retlen);
-	
-	writew(IF_READ_CSR, (u_long)pageaddr & ~1);
-	
-	
-	if (priv->devstat[device] & MTD_ERASE_SUSPEND)
-	{
-		resume_erase(pageaddr);
-		priv->devstat[device]=MTD_ERASING;
-	}
-
-
-	if (timeron) add_timer (&flashcard_timer);
-		
-	return ret;
-}
-
-
-int flashcard_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;
- 	u_char *endaddr, *startaddr;
-	register u_char *pageaddr;
-	u_char device = to >> priv->devshift;
-/*	jiffies_t oldj=jiffies;*/
-	int ret;
-
-	while (priv->devstat[device])
-	{
-		flashcard_sync(mtd);
-	}
-
-	if ((to & WINDOW_MASK) + len <= WINDOW_SIZE)
-		*retlen = len;
-	else
-		*retlen = WINDOW_SIZE - (to & WINDOW_MASK);
-	
-	pageaddr = pagein(mtd, to);
-	startaddr = (u_char *)((u_long) pageaddr & ~1);
-	endaddr = pageaddr+(*retlen);
-
-
-
-	/* Set up to read */
-	writew(IF_READ_CSR, startaddr);
-	
-	/* Make sure it's aligned by reading the first byte if necessary */
-	if (to & 1)
-	{
-		/* Unaligned access */
-
-		u_char cbuf;
-
-		cbuf = *buf;
-
-		if (!((u_long)pageaddr & 0xf))
-			schedule();
-			
-		ret = byte_write(pageaddr, cbuf);
-		if (ret) return ret;
-
-		pageaddr++; buf++;
-	}
-
-
-	for ( ; pageaddr + 1 < endaddr; buf += 2, pageaddr += 2)
-		{
-			/* if ((u_long)pageaddr & 0xf) schedule();*/
-			
-			ret = word_write(pageaddr, *(__u16 *)buf);
-			if (ret) 
-				return ret;
-		}
-	
-	if (pageaddr != endaddr)
-	{
-		/* One more byte to write at the end. */
-		u_char cbuf;
-
-		cbuf = *buf;
-
-		ret = byte_write(pageaddr, cbuf);
-
-		if (ret) return ret;
-	}
-
-	return check_write(startaddr);
-/*	printk("Time taken in flashcard_write: %lx jiffies\n",jiffies - oldj);*/
-}
-
-
-
-
-/*====================================================================*/
-
-static inline int byte_write (volatile u_char *addr, u_char byte)
-{
-	register u_char status;
- 	register u_short i = 0;
-  	
- 	do {
-		status = readb(addr);
-		if (status & CSR_WR_READY)
-		{
-			writeb(IF_WRITE & 0xff, addr);
-			writeb(byte, addr);
-			return 0;
-		}
-		i++;
-	} while(i < max_tries);
-
-		
-	printk(KERN_NOTICE "flashcard: byte_write timed out, status 0x%x\n",status);
-	return -EIO;
-}
-
-static inline int word_write (volatile u_char *addr, __u16 word)
-{
-	register u_short status;
-	register u_short i = 0;
-	
-	do {
-		status = readw(addr);
-		if ((status & CSR_WR_READY) == CSR_WR_READY)
-		{
-			writew(IF_WRITE, addr);
-			writew(word, addr);
-			return 0;
-		}
-		i++;
-	} while(i < max_tries);
-		
-	printk(KERN_NOTICE "flashcard: word_write timed out at %p, status 0x%x\n", addr, status);
-	return -EIO;
-}
-
-static inline void block_erase (volatile u_char *addr)
-{
-	writew(IF_BLOCK_ERASE, addr);
-	writew(IF_CONFIRM, addr);
-}
-
-
-static inline int check_erase(volatile u_char *addr)
-{
-	__u16 status;
-	
-/*	writew(IF_READ_CSR, addr);*/
-	status = readw(addr);
-	
-
-	if ((status & CSR_WR_READY) != CSR_WR_READY)
-		return -EBUSY;
-	
-	if (status & (CSR_ERA_ERR | CSR_VPP_LOW | CSR_WR_ERR)) 
-	{
-		printk(KERN_NOTICE "flashcard: erase failed, status 0x%x\n",
-		       status);
-		return -EIO;
-	}
-	
-	return 0;
-}
-
-static inline int suspend_erase(volatile u_char *addr)
-{
-	__u16 status;
-	u_long i = 0;
-	
-	writew(IF_ERASE_SUSPEND, addr);
-	writew(IF_READ_CSR, addr);
-	
-	do {
-		status = readw(addr);
-		if ((status & CSR_WR_READY) == CSR_WR_READY)
-			return 0;
-		i++;
-	} while(i < max_tries);
-
-	printk(KERN_NOTICE "flashcard: suspend_erase timed out, status 0x%x\n", status);
-	return -EIO;
-
-}
-
-static inline void resume_erase(volatile u_char *addr)
-{
-	__u16 status;
-	
-	writew(IF_READ_CSR, addr);
-	status = readw(addr);
-	
-	/* Only give resume signal if the erase is really suspended */
-	if (status & CSR_ERA_SUSPEND)
-		writew(IF_CONFIRM, addr);
-}
-
-static inline void reset_block(volatile u_char *addr)
-{
-	u_short i;
-	__u16 status;
-
-	writew(IF_CLEAR_CSR, addr);
-
-	for (i = 0; i < 100; i++) {
-		writew(IF_READ_CSR, addr);
-		status = readw(addr);
-		if (status != 0xffff) break;
-		udelay(1000);
-	}
-
-	writew(IF_READ_CSR, addr);
-}
-
-static inline int check_write(volatile u_char *addr)
-{
-	u_short status, i = 0;
-	
-	writew(IF_READ_CSR, addr);
-	
-	do {
-		status = readw(addr);
-		if (status & (CSR_WR_ERR | CSR_VPP_LOW))
-		{
-			printk(KERN_NOTICE "flashcard: write failure at %p, status 0x%x\n", addr, status);
-			reset_block(addr);
-			return -EIO;
-		}
-		if ((status & CSR_WR_READY) == CSR_WR_READY)
-			return 0;
-		i++;
-	} while (i < max_tries);
-
-	printk(KERN_NOTICE "flashcard: write timed out at %p, status 0x%x\n", addr, status);
-	return -EIO;
-}
-
-
-/*====================================================================*/
-
-
-
-static void flashcard_periodic(unsigned long data)
-{
-	register struct mtd_info *mtd = (struct mtd_info *)data;
-	register struct mypriv *priv = mtd->priv;
-	struct erase_info *erase = priv->cur_erases;
-	u_char *pageaddr;
-
-	del_timer (&flashcard_timer);
-
-	if (!erase)
-		return;
-
-	pageaddr = pagein(mtd, erase->addr);
-	
-	if (erase->state == MTD_ERASE_PENDING)
-	{
-		block_erase(pageaddr);
-		priv->devstat[erase->dev] = erase->state = MTD_ERASING;
-		erase->time = jiffies;
-		erase->retries = 0;
-	}
-	else if (erase->state == MTD_ERASING)
-	{
-		/* It's trying to erase. Check whether it's finished */
-
-		int ret = check_erase(pageaddr);
-
-		if (!ret)
-		{
-			/* It's finished OK */
-			priv->devstat[erase->dev] = 0;
-			priv->cur_erases = erase->next;
-			erase->state = MTD_ERASE_DONE;
-			if (erase->callback)
-				(*(erase->callback))(erase);
-			else
-				kfree(erase);
-		}
-		else if (ret == -EIO)
-		{
-			if (++erase->retries > retry_limit)
-			{
-				printk("Failed too many times. Giving up\n");
-				priv->cur_erases = erase->next;
-				priv->devstat[erase->dev] = 0;
-				erase->state = MTD_ERASE_FAILED;
-				if (erase->callback)
-					(*(erase->callback))(erase);
-				else
-					kfree(erase);
-			}
-			else
-				priv->devstat[erase->dev] = erase->state = MTD_ERASE_PENDING;
-		}
-		else if (erase->time + erase_timeout < jiffies)
-		{
-			printk("Flash erase timed out. The world is broken.\n");
-
-			/* Just ignore and hope it goes away. For a while, read ops will give the CSR
-			   and writes won't work. */
-
-			priv->cur_erases = erase->next;
-			priv->devstat[erase->dev] = 0;
-			erase->state = MTD_ERASE_FAILED;
-			if (erase->callback)
-					(*(erase->callback))(erase);
-				else
-					kfree(erase);
-		}
-	}
-
-	if (priv->cur_erases)
-	{
-		flashcard_timer.expires = jiffies + HZ;
-		add_timer (&flashcard_timer);
-	}
-	else 
-		wake_up_interruptible(&priv->wq);
-
-}
-
-#if defined (MODULE) && LINUX_VERSION_CODE < 0x20211
-#define init_doc1000 init_module
-#define cleanup_doc1000 cleanup_module
-#endif
-
-int __init init_doc1000(void)
-{
-	struct mypriv *priv;
-
-	if (!base)
-	{
-		printk(KERN_NOTICE "flashcard: No start address for memory device.\n");
-		return -EINVAL;
-	}
-
-	mymtd  = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-
-	if (!mymtd)
-	{
-		printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device.\n");
-		return -ENOMEM;
-	}
-
-	memset(mymtd,0,sizeof(struct mtd_info));
-
-	mymtd->priv = (void *) kmalloc (sizeof(struct mypriv), GFP_KERNEL);
-	if (!mymtd->priv)
-	  {
-	    kfree(mymtd);
-	    printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device's private data.\n");
-	    return -ENOMEM;
-	  }
-	
-
-
-
-	priv=mymtd->priv;
-	init_waitqueue_head(&priv->wq);
-
-	memset (priv,0,sizeof(struct mypriv));
-
-	priv->baseaddr = phys_to_virt(base);
-	priv->numdevices = 4;
-	
-	mymtd->name = "M-Systems DiskOnChip 1000";
-
-	mymtd->size = 0x100000;
-	mymtd->flags = MTD_CLEAR_BITS | MTD_ERASEABLE;
-        mymtd->erase = flashcard_erase;
-	mymtd->point = NULL;
-	mymtd->unpoint = NULL;
-	mymtd->read = flashcard_read;
-	mymtd->write = flashcard_write;
-
-	mymtd->sync = flashcard_sync;
-	mymtd->erasesize = 0x10000;
-	//	mymtd->interleave = 2;
-	priv->devshift =  24;
-	mymtd->type = MTD_NORFLASH;
-	
-	if (add_mtd_device(mymtd))
-	{
-		printk(KERN_NOTICE "MTD device registration failed!\n");
-		kfree(mymtd->priv);
-		kfree(mymtd);
-		return -EAGAIN;
-	}
-	
-	init_timer(&flashcard_timer);
-	flashcard_timer.function = flashcard_periodic;
-	flashcard_timer.data = (u_long)mymtd;
-	return 0;
-}
-
-static void __init cleanup_doc1000(void)
-{
-	kfree (mymtd->priv);
-	del_mtd_device(mymtd);
-	kfree(mymtd);
-}
-
-#if LINUX_VERSION_CODE >= 0x20211
-module_init(init_doc1000);
-module_exit(cleanup_doc1000);
-#endif
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/doc2000.c linux/drivers/mtd/doc2000.c
--- v2.4.5/linux/drivers/mtd/doc2000.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/doc2000.c	Wed Dec 31 16:00:00 1969
@@ -1,1113 +0,0 @@
-
-/*
- * Linux driver for Disk-On-Chip 2000 and Millennium
- * (c) 1999 Machine Vision Holdings, Inc.
- * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
- *
- * $Id: doc2000.c,v 1.39 2000/12/01 17:34:29 dwmw2 Exp $
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/miscdevice.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/types.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ids.h>
-#include <linux/mtd/doc2000.h>
-
-#define DOC_SUPPORT_2000
-#define DOC_SUPPORT_MILLENNIUM
-
-#ifdef DOC_SUPPORT_2000
-#define DoC_is_2000(doc) (doc->ChipID == DOC_ChipID_Doc2k)
-#else
-#define DoC_is_2000(doc) (0)
-#endif
-
-#ifdef DOC_SUPPORT_MILLENNIUM
-#define DoC_is_Millennium(doc) (doc->ChipID == DOC_ChipID_DocMil)
-#else
-#define DoC_is_Millennium(doc) (0)
-#endif
-
-/* #define ECC_DEBUG */
-
-/* I have no idea why some DoC chips can not use memcpy_from|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);
-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);
-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 *doc2klist = NULL;
-
-/* Perform the required delay cycles by reading from the appropriate register */
-static void DoC_Delay(struct DiskOnChip *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
-			dummy = ReadDOC(doc->virtadr, DOCStatus);
-	}
-	
-}
-
-/* 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;
-	unsigned short 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, CDSNControl) & CDSN_CTRL_FR_B) && --c)
-		;
-
-	if (c == 0)
-		DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
-
-	return (c == 0);
-}
-
-static inline int DoC_WaitReady(struct DiskOnChip *doc)
-{
-	unsigned long docptr = doc->virtadr;
-	/* This is inline, to optimise the common case, where it's ready instantly */
-	int ret = 0;
-
-	/* 4 read form NOP register should be issued in prior to the read from CDSNControl
-	   see Software Requirement 11.4 item 2. */
-	DoC_Delay(doc, 4);
-
-	if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
-		/* Call the out-of-line routine to wait */
-		ret = _DoC_WaitReady(doc);
-
-	/* issue 2 read from NOP register after reading from CDSNControl register
-	   see Software Requirement 11.4 item 2. */
-	DoC_Delay(doc, 2);
-
-	return ret;
-}
-
-/* DoC_Command: Send a flash command to the flash chip through the CDSN Slow IO register to
-   bypass 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 int DoC_Command(struct DiskOnChip *doc, unsigned char command,
-			      unsigned char xtraflags)
-{
-	unsigned long docptr = doc->virtadr;
-
-	if (DoC_is_2000(doc))
-		xtraflags |= CDSN_CTRL_FLASH_IO;
-
-	/* Assert the CLE (Command Latch Enable) line to the flash chip */
-	WriteDOC(xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, docptr, CDSNControl);
-	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
-
-	if (DoC_is_Millennium(doc))
-		WriteDOC(command, docptr, CDSNSlowIO);
-
-	/* Send the command */
-	WriteDOC_(command, docptr, doc->ioreg);
-
-	/* Lower the CLE line */
-	WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
-	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
-
-	/* Wait for the chip to respond - Software requirement 11.4.1 (extended for any command) */
-	return DoC_WaitReady(doc);
-}
-
-/* DoC_Address: Set the current address for the flash chip through the CDSN Slow IO register to
-   bypass 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 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;
-
-	if (DoC_is_2000(doc))
-		xtraflags1 |= CDSN_CTRL_FLASH_IO;
-
-	/* Assert the ALE (Address Latch Enable) line to the flash chip */
-	WriteDOC(xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, docptr, CDSNControl);
-
-	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
-
-	/* Send the address */
-	/* Devices with 256-byte page are addressed as:
-	   Column (bits 0-7), Page (bits 8-15, 16-23, 24-31)
-	   * there is no device on the market with page256
-	   and more than 24 bits.
-	   Devices with 512-byte page are addressed as:
-	   Column (bits 0-7), Page (bits 9-16, 17-24, 25-31)
-	   * 25-31 is sent only if the chip support it.
-	   * bit 8 changes the read command to be sent
-	   (NAND_CMD_READ0 or NAND_CMD_READ1).
-	 */
-
-	if (numbytes == ADDR_COLUMN || numbytes == ADDR_COLUMN_PAGE) {
-		if (DoC_is_Millennium(doc))
-			WriteDOC(ofs & 0xff, docptr, CDSNSlowIO);
-		WriteDOC_(ofs & 0xff, docptr, doc->ioreg);
-	}
-
-	if (doc->page256) {
-		ofs = ofs >> 8;
-	} else {
-		ofs = ofs >> 9;
-	}
-
-	if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE) {
-		for (i = 0; i < doc->pageadrlen; i++, ofs = ofs >> 8) {
-			if (DoC_is_Millennium(doc))
-				WriteDOC(ofs & 0xff, docptr, CDSNSlowIO);
-			WriteDOC_(ofs & 0xff, docptr, doc->ioreg);
-		}
-	}
-
-	DoC_Delay(doc, 2);	/* Needed for some slow flash chips. mf. */
-	
-	/* FIXME: The SlowIO's for millennium could be replaced by 
-	   a single WritePipeTerm here. mf. */
-
-	/* Lower the ALE line */
-	WriteDOC(xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr,
-		 CDSNControl);
-
-	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
-
-	/* Wait for the chip to respond - Software requirement 11.4.1 */
-	return DoC_WaitReady(doc);
-}
-
-/* Read a buffer from DoC, taking care of Millennium odditys */
-static void DoC_ReadBuf(struct DiskOnChip *doc, u_char * buf, int len)
-{
-	int dummy;
-	int modulus = 0xffff;
-	unsigned long docptr;
-	int i;
-
-	docptr = doc->virtadr;
-
-	if (len <= 0)
-		return;
-
-	if (DoC_is_Millennium(doc)) {
-		/* Read the data via the internal pipeline through CDSN IO register,
-		   see Pipelined Read Operations 11.3 */
-		dummy = ReadDOC(docptr, ReadPipeInit);
-
-		/* Millennium should use the LastDataRead register - Pipeline Reads */
-		len--;
-
-		/* This is needed for correctly ECC calculation */
-		modulus = 0xff;
-	}
-
-	for (i = 0; i < len; i++)
-		buf[i] = ReadDOC_(docptr, doc->ioreg + (i & modulus));
-
-	if (DoC_is_Millennium(doc)) {
-		buf[i] = ReadDOC(docptr, LastDataRead);
-	}
-}
-
-/* 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;
-	int i;
-
-	docptr = doc->virtadr;
-
-	if (len <= 0)
-		return;
-
-	for (i = 0; i < len; i++)
-		WriteDOC_(buf[i], docptr, doc->ioreg + i);
-
-	if (DoC_is_Millennium(doc)) {
-		WriteDOC(0x00, docptr, WritePipeTerm);
-	}
-}
-
-
-/* DoC_SelectChip: Select a given flash chip within the current floor */
-
-static inline int DoC_SelectChip(struct DiskOnChip *doc, int chip)
-{
-	unsigned long docptr = doc->virtadr;
-
-	/* Software requirement 11.4.4 before writing DeviceSelect */
-	/* Deassert the CE line to eliminate glitches on the FCE# outputs */
-	WriteDOC(CDSN_CTRL_WP, docptr, CDSNControl);
-	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
-
-	/* Select the individual flash chip requested */
-	WriteDOC(chip, docptr, CDSNDeviceSelect);
-	DoC_Delay(doc, 4);
-
-	/* Reassert the CE line */
-	WriteDOC(CDSN_CTRL_CE | CDSN_CTRL_FLASH_IO | CDSN_CTRL_WP, docptr,
-		 CDSNControl);
-	DoC_Delay(doc, 4);	/* Software requirement 11.4.3 for Millennium */
-
-	/* Wait for it to be ready */
-	return DoC_WaitReady(doc);
-}
-
-/* DoC_SelectFloor: Select a given floor (bank of flash chips) */
-
-static inline int DoC_SelectFloor(struct DiskOnChip *doc, int floor)
-{
-	unsigned long docptr = doc->virtadr;
-
-	/* Select the floor (bank) of chips required */
-	WriteDOC(floor, docptr, FloorSelect);
-
-	/* Wait for the chip to be ready */
-	return DoC_WaitReady(doc);
-}
-
-/* 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;
-	volatile char dummy;
-
-	/* Page in the required floor/chip */
-	DoC_SelectFloor(doc, floor);
-	DoC_SelectChip(doc, chip);
-
-	/* Reset the chip */
-	if (DoC_Command(doc, NAND_CMD_RESET, CDSN_CTRL_WP)) {
-		DEBUG(MTD_DEBUG_LEVEL2,
-		      "DoC_Command (reset) for %d,%d returned true\n",
-		      floor, chip);
-		return 0;
-	}
-
-
-	/* Read the NAND chip ID: 1. Send ReadID command */
-	if (DoC_Command(doc, NAND_CMD_READID, CDSN_CTRL_WP)) {
-		DEBUG(MTD_DEBUG_LEVEL2,
-		      "DoC_Command (ReadID) for %d,%d returned true\n",
-		      floor, chip);
-		return 0;
-	}
-
-	/* Read the NAND chip ID: 2. Send address byte zero */
-	DoC_Address(doc, ADDR_COLUMN, 0, CDSN_CTRL_WP, 0);
-
-	/* Read the manufacturer and device id codes from the device */
-
-	/* CDSN Slow IO register see Software Requirement 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. */
-	dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
-	DoC_Delay(doc, 2);
-	id = ReadDOC_(doc->virtadr, doc->ioreg);
-
-	/* No response - return failure */
-	if (mfr == 0xff || mfr == 0)
-		return 0;
-
-	/* Check it's the same as the first chip we identified. 
-	 * M-Systems say that any given DiskOnChip device should only
-	 * contain _one_ type of flash part, although that's not a 
-	 * hardware restriction. */
-	if (doc->mfr) {
-		if (doc->mfr == mfr && doc->id == id)
-			return 1;	/* This is another the same the first */
-		else
-			printk(KERN_WARNING
-			       "Flash chip at floor %d, chip %d is different:\n",
-			       floor, chip);
-	}
-
-	/* Print and store the manufacturer and ID codes. */
-	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-		if (mfr == nand_flash_ids[i].manufacture_id &&
-		    id == nand_flash_ids[i].model_id) {
-			printk(KERN_INFO
-			       "Flash chip found: Manufacturer ID: %2.2X, "
-			       "Chip ID: %2.2X (%s)\n", mfr, id,
-			       nand_flash_ids[i].name);
-			if (!doc->mfr) {
-				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].pageadrlen;
-				doc->erasesize =
-				    nand_flash_ids[i].erasesize;
-				return 1;
-			}
-			return 0;
-		}
-	}
-
-
-	/* We haven't fully identified the chip. Print as much as we know. */
-	printk(KERN_WARNING "Unknown flash chip found: %2.2X %2.2X\n",
-	       id, mfr);
-
-	printk(KERN_WARNING "Please report to dwmw2@infradead.org\n");
-	return 0;
-}
-
-/* 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];
-	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;
-		numchips[floor] = 0;
-		for (chip = 0; chip < maxchips && 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("No memory for allocating chip info structures\n");
-		return;
-	}
-
-	ret = 0;
-
-	/* Fill out the chip array with {floor, chipno} for each 
-	 * detected chip in the device. */
-	for (floor = 0; floor < MAX_FLOORS; 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 Mb\n",
-	       this->numchips, this->totlen >> 20);
-}
-
-
-static int DoC2k_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, AliasResolution);
-	tmp2 = ReadDOC(doc2->virtadr, AliasResolution);
-	if (tmp1 != tmp2)
-		return 0;
-
-	WriteDOC((tmp1 + 1) % 0xff, doc1->virtadr, AliasResolution);
-	tmp2 = ReadDOC(doc2->virtadr, 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, AliasResolution);
-
-	return retval;
-}
-
-static const char im_name[] = "DoC2k_init";
-
-/* This routine is made available to other mtd code via
- * inter_module_register.  It must only be accessed through
- * inter_module_get which will bump the use count of this module.  The
- * addresses passed back in mtd are valid as long as the use count of
- * this module is non-zero, i.e. between inter_module_get and
- * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
- */
-static void DoC2k_init(struct mtd_info *mtd)
-{
-	struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
-	struct DiskOnChip *old = NULL;
-
-	/* We must avoid being called twice for the same device. */
-
-	if (doc2klist)
-		old = (struct DiskOnChip *) 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);
-			kfree(mtd);
-			return;
-		}
-		if (old->nextdoc)
-			old = (struct DiskOnChip *) old->nextdoc->priv;
-		else
-			old = NULL;
-	}
-
-
-	switch (this->ChipID) {
-	case DOC_ChipID_Doc2k:
-		mtd->name = "DiskOnChip 2000";
-		this->ioreg = DoC_2k_CDSN_IO;
-		break;
-	case DOC_ChipID_DocMil:
-		mtd->name = "DiskOnChip Millennium";
-		this->ioreg = DoC_Mil_CDSN_IO;
-		break;
-	}
-
-	printk(KERN_NOTICE "%s found at address 0x%lX\n", mtd->name,
-	       this->physadr);
-
-	mtd->type = MTD_NANDFLASH;
-	mtd->flags = MTD_CAP_NANDFLASH;
-	mtd->size = 0;
-	mtd->erasesize = 0;
-	mtd->oobblock = 512;
-	mtd->oobsize = 16;
-	mtd->module = 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((void *) this->virtadr);
-	} else {
-		this->nextdoc = doc2klist;
-		doc2klist = mtd;
-		mtd->size = this->totlen;
-		mtd->erasesize = this->erasesize;
-		add_mtd_device(mtd);
-		return;
-	}
-}
-
-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);
-}
-
-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 DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
-	unsigned long docptr;
-	struct Nand *mychip;
-	unsigned char syndrome[6];
-	volatile char dummy;
-	int i, len256 = 0, ret=0;
-
-	docptr = this->virtadr;
-
-	/* 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;
-
-	/* The ECC will not be calculated correctly if less than 512 is read */
-	if (len != 0x200 && eccbuf)
-		printk(KERN_WARNING
-		       "ECC needs a full sector read (adr: %lx size %lx)\n",
-		       (long) from, (long) len);
-
-	/* printk("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len); */
-
-
-	/* Find the chip which is to be used and select it */
-	mychip = &this->chips[from >> (this->chipshift)];
-
-	if (this->curfloor != mychip->floor) {
-		DoC_SelectFloor(this, mychip->floor);
-		DoC_SelectChip(this, mychip->chip);
-	} else if (this->curchip != mychip->chip) {
-		DoC_SelectChip(this, mychip->chip);
-	}
-
-	this->curfloor = mychip->floor;
-	this->curchip = mychip->chip;
-
-	DoC_Command(this,
-		    (!this->page256
-		     && (from & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
-		    CDSN_CTRL_WP);
-	DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP,
-		    CDSN_CTRL_ECC_IO);
-
-	if (eccbuf) {
-		/* Prime the ECC engine */
-		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-		WriteDOC(DOC_ECC_EN, docptr, ECCConf);
-	} else {
-		/* disable the ECC engine */
-		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
-	}
-
-	/* treat crossing 256-byte sector for 2M x 8bits devices */
-	if (this->page256 && from + len > (from | 0xff) + 1) {
-		len256 = (from | 0xff) + 1 - from;
-		DoC_ReadBuf(this, buf, len256);
-
-		DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP);
-		DoC_Address(this, ADDR_COLUMN_PAGE, from + len256,
-			    CDSN_CTRL_WP, CDSN_CTRL_ECC_IO);
-	}
-
-	DoC_ReadBuf(this, &buf[len256], len - len256);
-
-	/* Let the caller know we completed it */
-	*retlen = len;
-
-	if (eccbuf) {
-		/* Read the ECC data through the DiskOnChip ECC logic */
-		/* Note: this will work even with 2M x 8bit devices as   */
-		/*       they have 8 bytes of OOB per 256 page. mf.      */
-		DoC_ReadBuf(this, eccbuf, 6);
-
-		/* Flush the pipeline */
-		if (DoC_is_Millennium(this)) {
-			dummy = ReadDOC(docptr, ECCConf);
-			dummy = ReadDOC(docptr, ECCConf);
-			i = ReadDOC(docptr, ECCConf);
-		} else {
-			dummy = ReadDOC(docptr, 2k_ECCStatus);
-			dummy = ReadDOC(docptr, 2k_ECCStatus);
-			i = ReadDOC(docptr, 2k_ECCStatus);
-		}
-
-		/* Check the ECC Status */
-		if (i & 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, ECCSyndrome0 + i);
-			}
-                        nb_errors = doc_decode_ecc(buf, syndrome);
-
-#ifdef ECC_DEBUG
-			printk("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 */
-				ret = -EIO;
-                        }
-		}
-
-#ifdef PSYCHO_DEBUG
-		printk("ECC DATA at %lxB: %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 , ECCConf);
-	}
-
-	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);
-}
-
-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 DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
-	int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
-	unsigned long docptr;
-	volatile char dummy;
-	int len256 = 0;
-	struct Nand *mychip;
-
-	docptr = this->virtadr;
-
-	/* Don't allow write past end of device */
-	if (to >= this->totlen)
-		return -EINVAL;
-
-	/* 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 */
-	if (len != 0x200 && eccbuf)
-		printk(KERN_WARNING
-		       "ECC needs a full sector write (adr: %lx size %lx)\n",
-		       (long) to, (long) len);
-
-	/* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
-
-	/* Find the chip which is to be used and select it */
-	mychip = &this->chips[to >> (this->chipshift)];
-
-	if (this->curfloor != mychip->floor) {
-		DoC_SelectFloor(this, mychip->floor);
-		DoC_SelectChip(this, mychip->chip);
-	} else if (this->curchip != mychip->chip) {
-		DoC_SelectChip(this, mychip->chip);
-	}
-
-	this->curfloor = mychip->floor;
-	this->curchip = mychip->chip;
-
-	/* Set device to main plane of flash */
-	DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
-	DoC_Command(this,
-		    (!this->page256
-		     && (to & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
-		    CDSN_CTRL_WP);
-
-	DoC_Command(this, NAND_CMD_SEQIN, 0);
-	DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
-
-	if (eccbuf) {
-		/* Prime the ECC engine */
-		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
-	} else {
-		/* disable the ECC engine */
-		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
-	}
-
-	/* treat crossing 256-byte sector for 2M x 8bits devices */
-	if (this->page256 && to + len > (to | 0xff) + 1) {
-		len256 = (to | 0xff) + 1 - to;
-		DoC_WriteBuf(this, buf, len256);
-
-		DoC_Command(this, NAND_CMD_PAGEPROG, 0);
-
-		DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
-		/* There's an implicit DoC_WaitReady() in DoC_Command */
-
-		dummy = ReadDOC(docptr, CDSNSlowIO);
-		DoC_Delay(this, 2);
-
-		if (ReadDOC_(docptr, this->ioreg) & 1) {
-			printk("Error programming flash\n");
-			/* Error in programming */
-			*retlen = 0;
-			return -EIO;
-		}
-
-		DoC_Command(this, NAND_CMD_SEQIN, 0);
-		DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0,
-			    CDSN_CTRL_ECC_IO);
-	}
-
-	DoC_WriteBuf(this, &buf[len256], len - len256);
-
-	if (eccbuf) {
-		WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr,
-			 CDSNControl);
-
-		if (DoC_is_Millennium(this)) {
-			WriteDOC(0, docptr, NOP);
-			WriteDOC(0, docptr, NOP);
-			WriteDOC(0, docptr, NOP);
-		} else {
-			WriteDOC_(0, docptr, this->ioreg);
-			WriteDOC_(0, docptr, this->ioreg);
-			WriteDOC_(0, docptr, this->ioreg);
-		}
-
-		/* Read the ECC data through the DiskOnChip ECC logic */
-		for (di = 0; di < 6; di++) {
-			eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
-		}
-
-		/* Reset the ECC engine */
-		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
-
-#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
-	}
-
-	DoC_Command(this, NAND_CMD_PAGEPROG, 0);
-
-	DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
-	/* There's an implicit DoC_WaitReady() in DoC_Command */
-
-	dummy = ReadDOC(docptr, CDSNSlowIO);
-	DoC_Delay(this, 2);
-
-	if (ReadDOC_(docptr, this->ioreg) & 1) {
-		printk("Error programming flash\n");
-		/* Error in programming */
-		*retlen = 0;
-		return -EIO;
-	}
-
-	/* Let the caller know we completed it */
-	*retlen = len;
-		
-	if (eccbuf) {
-		unsigned char x[8];
-		size_t dummy;
-
-		/* Write the ECC data to flash */
-		for (di=0; di<6; di++)
-			x[di] = eccbuf[di];
-		
-		x[6]=0x55;
-		x[7]=0x55;
-		
-		return doc_write_oob(mtd, to, 8, &dummy, x);
-	}
-
-	return 0;
-}
-
-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;
-	int len256 = 0;
-	unsigned long docptr;
-	struct Nand *mychip;
-
-	docptr = this->virtadr;
-
-	mychip = &this->chips[ofs >> this->chipshift];
-
-	if (this->curfloor != mychip->floor) {
-		DoC_SelectFloor(this, mychip->floor);
-		DoC_SelectChip(this, mychip->chip);
-	} else if (this->curchip != mychip->chip) {
-		DoC_SelectChip(this, mychip->chip);
-	}
-	this->curfloor = mychip->floor;
-	this->curchip = mychip->chip;
-
-	/* update address for 2M x 8bit devices. OOB starts on the second */
-	/* page to maintain compatibility with doc_read_ecc. */
-	if (this->page256) {
-		if (!(ofs & 0x8))
-			ofs += 0x100;
-		else
-			ofs -= 0x8;
-	}
-
-	DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
-	DoC_Address(this, ADDR_COLUMN_PAGE, ofs, CDSN_CTRL_WP, 0);
-
-	/* treat crossing 8-byte OOB data for 2M x 8bit devices */
-	/* Note: datasheet says it should automaticaly wrap to the */
-	/*       next OOB block, but it didn't work here. mf.      */
-	if (this->page256 && ofs + len > (ofs | 0x7) + 1) {
-		len256 = (ofs | 0x7) + 1 - ofs;
-		DoC_ReadBuf(this, buf, len256);
-
-		DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
-		DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff),
-			    CDSN_CTRL_WP, 0);
-	}
-
-	DoC_ReadBuf(this, &buf[len256], len - len256);
-
-	*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)
-{
-	struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
-	int len256 = 0;
-	unsigned long docptr = this->virtadr;
-	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
-	int dummy;
-
-	//      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]);
-
-	/* Find the chip which is to be used and select it */
-	if (this->curfloor != mychip->floor) {
-		DoC_SelectFloor(this, mychip->floor);
-		DoC_SelectChip(this, mychip->chip);
-	} else if (this->curchip != mychip->chip) {
-		DoC_SelectChip(this, mychip->chip);
-	}
-	this->curfloor = mychip->floor;
-	this->curchip = mychip->chip;
-
-	/* disable the ECC engine */
-	WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
-	WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
-
-	/* Reset the chip, see Software Requirement 11.4 item 1. */
-	DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
-
-	/* issue the Read2 command to set the pointer to the Spare Data Area. */
-	DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
-
-	/* update address for 2M x 8bit devices. OOB starts on the second */
-	/* page to maintain compatibility with doc_read_ecc. */
-	if (this->page256) {
-		if (!(ofs & 0x8))
-			ofs += 0x100;
-		else
-			ofs -= 0x8;
-	}
-
-	/* issue the Serial Data In command to initial the Page Program process */
-	DoC_Command(this, NAND_CMD_SEQIN, 0);
-	DoC_Address(this, ADDR_COLUMN_PAGE, ofs, 0, 0);
-
-	/* treat crossing 8-byte OOB data for 2M x 8bit devices */
-	/* Note: datasheet says it should automaticaly wrap to the */
-	/*       next OOB block, but it didn't work here. mf.      */
-	if (this->page256 && ofs + len > (ofs | 0x7) + 1) {
-		len256 = (ofs | 0x7) + 1 - ofs;
-		DoC_WriteBuf(this, buf, len256);
-
-		DoC_Command(this, NAND_CMD_PAGEPROG, 0);
-		DoC_Command(this, NAND_CMD_STATUS, 0);
-		/* DoC_WaitReady() is implicit in DoC_Command */
-
-		dummy = ReadDOC(docptr, CDSNSlowIO);
-		DoC_Delay(this, 2);
-
-		if (ReadDOC_(docptr, this->ioreg) & 1) {
-			printk("Error programming oob data\n");
-			/* There was an error */
-			*retlen = 0;
-			return -EIO;
-		}
-		DoC_Command(this, NAND_CMD_SEQIN, 0);
-		DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff), 0, 0);
-	}
-
-	DoC_WriteBuf(this, &buf[len256], len - len256);
-
-	DoC_Command(this, NAND_CMD_PAGEPROG, 0);
-	DoC_Command(this, NAND_CMD_STATUS, 0);
-	/* DoC_WaitReady() is implicit in DoC_Command */
-
-	dummy = ReadDOC(docptr, CDSNSlowIO);
-	DoC_Delay(this, 2);
-
-	if (ReadDOC_(docptr, this->ioreg) & 1) {
-		printk("Error programming oob data\n");
-		/* There was an error */
-		*retlen = 0;
-		return -EIO;
-	}
-
-	*retlen = len;
-	return 0;
-
-}
-
-int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-	struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
-	unsigned long ofs = instr->addr;
-	unsigned long len = instr->len;
-	unsigned long docptr;
-	struct Nand *mychip;
-
-	if (len != mtd->erasesize)
-		printk(KERN_WARNING "Erase not right size (%lx != %lx)n",
-		       len, mtd->erasesize);
-
-	docptr = this->virtadr;
-
-	mychip = &this->chips[ofs >> this->chipshift];
-
-	if (this->curfloor != mychip->floor) {
-		DoC_SelectFloor(this, mychip->floor);
-		DoC_SelectChip(this, mychip->chip);
-	} else if (this->curchip != mychip->chip) {
-		DoC_SelectChip(this, mychip->chip);
-	}
-	this->curfloor = mychip->floor;
-	this->curchip = mychip->chip;
-
-	instr->state = MTD_ERASE_PENDING;
-
-	DoC_Command(this, NAND_CMD_ERASE1, 0);
-	DoC_Address(this, ADDR_PAGE, ofs, 0, 0);
-	DoC_Command(this, NAND_CMD_ERASE2, 0);
-
-	instr->state = MTD_ERASING;
-
-	DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
-
-	if (ReadDOC_(docptr, this->ioreg) & 1) {
-		printk("Error writing\n");
-		/* There was an error */
-		instr->state = MTD_ERASE_FAILED;
-	} else
-		instr->state = MTD_ERASE_DONE;
-
-	if (instr->callback)
-		instr->callback(instr);
-
-	return 0;
-}
-
-
-/****************************************************************************
- *
- * Module stuff
- *
- ****************************************************************************/
-
-#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
-#define cleanup_doc2000 cleanup_module
-#define init_doc2000 init_module
-#endif
-
-int __init init_doc2000(void)
-{
-       inter_module_register(im_name, THIS_MODULE, &DoC2k_init);
-       return 0;
-}
-
-static void __exit cleanup_doc2000(void)
-{
-	struct mtd_info *mtd;
-	struct DiskOnChip *this;
-
-	while ((mtd = doc2klist)) {
-		this = (struct DiskOnChip *) mtd->priv;
-		doc2klist = this->nextdoc;
-
-		del_mtd_device(mtd);
-
-		iounmap((void *) this->virtadr);
-		kfree(this->chips);
-		kfree(mtd);
-	}
-	inter_module_unregister(im_name);
-}
-
-module_exit(cleanup_doc2000);
-module_init(init_doc2000);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/doc2001.c linux/drivers/mtd/doc2001.c
--- v2.4.5/linux/drivers/mtd/doc2001.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/doc2001.c	Wed Dec 31 16:00:00 1969
@@ -1,883 +0,0 @@
-
-/*
- * Linux driver for Disk-On-Chip Millennium
- * (c) 1999 Machine Vision Holdings, Inc.
- * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
- *
- * $Id: doc2001.c,v 1.24 2000/12/01 13:11:02 dwmw2 Exp $
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/miscdevice.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/types.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ids.h>
-#include <linux/mtd/doc2000.h>
-
-/* #define ECC_DEBUG */
-
-/* I have no idea why some DoC chips can not use memcop_form|to_io().
- * This may be due to the different revisions of the ASIC controller built-in or
- * simplily a QA/Bug issue. Who knows ?? If you have trouble, please uncomment
- * this:
- #undef USE_MEMCPY
-*/
-
-static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
-		    size_t *retlen, u_char *buf);
-static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
-		     size_t *retlen, const u_char *buf);
-static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf, u_char *eccbuf);
-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);
-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 *docmillist = NULL;
-
-/* Perform the required delay cycles by reading from the NOP register */
-static void DoC_Delay(unsigned long docptr, unsigned short cycles)
-{
-	volatile char dummy;
-	int i;
-
-	for (i = 0; i < cycles; i++)
-		dummy = ReadDOC(docptr, NOP);
-}
-
-/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
-static int _DoC_WaitReady(unsigned long docptr)
-{
-	unsigned short 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, CDSNControl) & CDSN_CTRL_FR_B) && --c)
-		;
-
-	if (c == 0)
-		DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
-
-	return (c == 0);
-}
-
-static inline int DoC_WaitReady(unsigned long docptr)
-{
-	/* This is inline, to optimise the common case, where it's ready instantly */
-	int ret = 0;
-
-	/* 4 read form NOP register should be issued in prior to the read from CDSNControl
-	   see Software Requirement 11.4 item 2. */
-	DoC_Delay(docptr, 4);
-
-	if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
-		/* Call the out-of-line routine to wait */
-		ret = _DoC_WaitReady(docptr);
-
-	/* issue 2 read from NOP register after reading from CDSNControl register
-	   see Software Requirement 11.4 item 2. */
-	DoC_Delay(docptr, 2);
-
-	return ret;
-}
-
-/* DoC_Command: Send a flash command to the flash chip through the CDSN Slow IO register to
-   bypass 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,
-			       unsigned char xtraflags)
-{
-	/* Assert the CLE (Command Latch Enable) line to the flash chip */
-	WriteDOC(xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, docptr, CDSNControl);
-	DoC_Delay(docptr, 4);
-
-	/* Send the command */
-	WriteDOC(command, docptr, CDSNSlowIO);
-	WriteDOC(command, docptr, Mil_CDSN_IO);
-
-	/* Lower the CLE line */
-	WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
-	DoC_Delay(docptr, 4);
-}
-
-/* DoC_Address: Set the current address for the flash chip through the CDSN Slow IO register to
-   bypass 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,
-			       unsigned char xtraflags1, unsigned char xtraflags2)
-{
-	/* Assert the ALE (Address Latch Enable) line to the flash chip */
-	WriteDOC(xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, docptr, CDSNControl);
-	DoC_Delay(docptr, 4);
-
-	/* Send the address */
-	switch (numbytes)
-	    {
-	    case 1:
-		/* Send single byte, bits 0-7. */
-		WriteDOC(ofs & 0xff, docptr, CDSNSlowIO);
-		WriteDOC(ofs & 0xff, docptr, Mil_CDSN_IO);
-		break;
-	    case 2:
-		/* Send bits 9-16 followed by 17-23 */
-		WriteDOC((ofs >> 9)  & 0xff, docptr, CDSNSlowIO);
-		WriteDOC((ofs >> 9)  & 0xff, docptr, Mil_CDSN_IO);
-		WriteDOC((ofs >> 17) & 0xff, docptr, CDSNSlowIO);
-		WriteDOC((ofs >> 17) & 0xff, docptr, Mil_CDSN_IO);
-		break;
-	    case 3:
-		/* Send 0-7, 9-16, then 17-23 */
-		WriteDOC(ofs & 0xff, docptr, CDSNSlowIO);
-		WriteDOC(ofs & 0xff, docptr, Mil_CDSN_IO);
-		WriteDOC((ofs >> 9)  & 0xff, docptr, CDSNSlowIO);
-		WriteDOC((ofs >> 9)  & 0xff, docptr, Mil_CDSN_IO);
-		WriteDOC((ofs >> 17) & 0xff, docptr, CDSNSlowIO);
-		WriteDOC((ofs >> 17) & 0xff, docptr, Mil_CDSN_IO);
-		break;
-	    default:
-		return;
-	    }
-
-	/* Lower the ALE line */
-	WriteDOC(xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr, CDSNControl);
-	DoC_Delay(docptr, 4);
-}
-
-/* DoC_SelectChip: Select a given flash chip within the current floor */
-static int DoC_SelectChip(unsigned long docptr, int chip)
-{
-	/* Select the individual flash chip requested */
-	WriteDOC(chip, docptr, CDSNDeviceSelect);
-	DoC_Delay(docptr, 4);
-
-	/* Wait for it to be ready */
-	return DoC_WaitReady(docptr);
-}
-
-/* DoC_SelectFloor: Select a given floor (bank of flash chips) */
-static int DoC_SelectFloor(unsigned long docptr, int floor)
-{
-	/* Select the floor (bank) of chips required */
-	WriteDOC(floor, docptr, FloorSelect);
-
-	/* Wait for the chip to be ready */
-	return DoC_WaitReady(docptr);
-}
-
-/* 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;
-	volatile char dummy;
-
-	/* Page in the required floor/chip
-	   FIXME: is this supported by Millennium ?? */
-	DoC_SelectFloor(doc->virtadr, floor);
-	DoC_SelectChip(doc->virtadr, chip);
-
-	/* Reset the chip, see Software Requirement 11.4 item 1. */
-	DoC_Command(doc->virtadr, NAND_CMD_RESET, CDSN_CTRL_WP);
-	DoC_WaitReady(doc->virtadr);
-
-	/* Read the NAND chip ID: 1. Send ReadID command */ 
-	DoC_Command(doc->virtadr, NAND_CMD_READID, CDSN_CTRL_WP);
-
-	/* Read the NAND chip ID: 2. Send address byte zero */ 
-	DoC_Address(doc->virtadr, 1, 0x00, CDSN_CTRL_WP, 0x00);
-
-	/* Read the manufacturer and device id codes of the flash device through
-	   CDSN Slow IO register see Software Requirement 11.4 item 5.*/
-	dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
-	DoC_Delay(doc->virtadr, 2);
-	mfr = ReadDOC(doc->virtadr, Mil_CDSN_IO);
-
-	dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
-	DoC_Delay(doc->virtadr, 2);
-	id  = ReadDOC(doc->virtadr, Mil_CDSN_IO);
-
-	/* No response - return failure */
-	if (mfr == 0xff || mfr == 0)
-		return 0;
-
-	/* FIXME: to deal with multi-flash on multi-Millennium case more carefully */
-	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-		if (mfr == nand_flash_ids[i].manufacture_id &&
-		    id == nand_flash_ids[i].model_id) {
-			printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, "
-			       "Chip ID: %2.2X (%s)\n",
-			       mfr, id, nand_flash_ids[i].name);
-			doc->mfr = mfr;
-			doc->id = id;
-			doc->chipshift = nand_flash_ids[i].chipshift;
-			break;
-		}
-	}
-
-	if (nand_flash_ids[i].name == NULL)
-		return 0;
-	else
-		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_MIL];
-	int ret;
-
-	this->numchips = 0;
-	this->mfr = 0;
-	this->id = 0;
-
-	/* For each floor, find the number of valid chips it contains */
-	for (floor = 0,ret = 1; floor < MAX_FLOORS_MIL; floor++) {
-		numchips[floor] = 0;
-		for (chip = 0; chip < MAX_CHIPS_MIL && 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("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_MIL; 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_NOTICE "%d flash chips found. Total DiskOnChip size: %ld Mbytes\n",
-	       this->numchips ,this->totlen >> 20);
-}
-
-static int DoCMil_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 Millenium docs), but it seems to work. */
-	tmp1 = ReadDOC(doc1->virtadr, AliasResolution);
-	tmp2 = ReadDOC(doc2->virtadr, AliasResolution);
-	if (tmp1 != tmp2)
-		return 0;
-	
-	WriteDOC((tmp1+1) % 0xff, doc1->virtadr, AliasResolution);
-	tmp2 = ReadDOC(doc2->virtadr, 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, AliasResolution);
-
-	return retval;
-}
-
-static const char im_name[] = "DoCMil_init";
-
-/* This routine is made available to other mtd code via
- * inter_module_register.  It must only be accessed through
- * inter_module_get which will bump the use count of this module.  The
- * addresses passed back in mtd are valid as long as the use count of
- * this module is non-zero, i.e. between inter_module_get and
- * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
- */
-static void DoCMil_init(struct mtd_info *mtd)
-{
-	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-	struct DiskOnChip *old = NULL;
-
-	/* We must avoid being called twice for the same device. */
-	if (docmillist)
-		old = (struct DiskOnChip *)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);
-			kfree(mtd);
-			return;
-		}
-		if (old->nextdoc)
-			old = (struct DiskOnChip *)old->nextdoc->priv;
-		else
-			old = NULL;
-	}
-
-	mtd->name = "DiskOnChip Millennium";
-	printk(KERN_NOTICE "DiskOnChip Millennium found at address 0x%lX\n",
-	       this->physadr);
-
-	mtd->type = MTD_NANDFLASH;
-	mtd->flags = MTD_CAP_NANDFLASH;
-	mtd->size = 0;
-
-	/* FIXME: erase size is not always 8kB */
-	mtd->erasesize = 0x2000;
-
-	mtd->oobblock = 512;
-	mtd->oobsize = 16;
-	mtd->module = 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((void *)this->virtadr);
-	} else {
-		this->nextdoc = docmillist;
-		docmillist = mtd;
-		mtd->size  = this->totlen;
-		add_mtd_device(mtd);
-		return;
-	}
-}
-
-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);
-}
-
-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 i, ret;
-	volatile char dummy;
-	unsigned char syndrome[6];
-	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-	unsigned long 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;
-
-	/* 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;
-
-	/* issue the Read0 or Read1 command depend on which half of the page
-	   we are accessing. Polling the Flash Ready bit after issue 3 bytes
-	   address in Sequence Read Mode, see Software Requirement 11.4 item 1.*/
-	DoC_Command(docptr, (from >> 8) & 1, CDSN_CTRL_WP);
-	DoC_Address(docptr, 3, from, CDSN_CTRL_WP, 0x00);
-	DoC_WaitReady(docptr);
-
-	if (eccbuf) {
-		/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
-		WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
-		WriteDOC (DOC_ECC_EN, docptr, ECCConf);
-	} else {
-		/* disable the ECC engine */
-		WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
-		WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
-	}
-
-	/* Read the data via the internal pipeline through CDSN IO register,
-	   see Pipelined Read Operations 11.3 */
-	dummy = ReadDOC(docptr, ReadPipeInit);
-#ifndef USE_MEMCPY
-	for (i = 0; i < len-1; i++) {
-		/* N.B. you have to increase the source address in this way or the
-		   ECC logic will not work properly */
-		buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));
-	}
-#else
-	memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len - 1);
-#endif
-	buf[len - 1] = ReadDOC(docptr, LastDataRead);
-
-	/* Let the caller know we completed it */
-	*retlen = len;
-        ret = 0;
-
-	if (eccbuf) {
-		/* Read the ECC data from Spare Data Area,
-		   see Reed-Solomon EDC/ECC 11.1 */
-		dummy = ReadDOC(docptr, ReadPipeInit);
-#ifndef USE_MEMCPY
-		for (i = 0; i < 5; i++) {
-			/* N.B. you have to increase the source address in this way or the
-			   ECC logic will not work properly */
-			eccbuf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
-		}
-#else
-		memcpy_fromio(eccbuf, docptr + DoC_Mil_CDSN_IO, 5);
-#endif
-		eccbuf[5] = ReadDOC(docptr, LastDataRead);
-
-		/* Flush the pipeline */
-		dummy = ReadDOC(docptr, ECCConf);
-		dummy = ReadDOC(docptr, ECCConf);
-
-		/* Check the ECC Status */
-		if (ReadDOC(docptr, 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, ECCSyndrome0 + i);
-			}
-                        nb_errors = doc_decode_ecc(buf, syndrome);
-#ifdef ECC_DEBUG
-			printk("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 */
-				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 , ECCConf);
-	}
-
-	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);
-}
-
-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 i;
-	volatile char dummy;
-	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-	unsigned long 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;
-
-#if 0
-	/* Don't allow a single write to cross a 512-byte block boundary */
-	if (to + len > ( (to | 0x1ff) + 1)) 
-		len = ((to | 0x1ff) + 1) - to;
-#else
-	/* Don't allow writes which aren't exactly one block */
-	if (to & 0x1ff || len != 0x200)
-		return -EINVAL;
-#endif
-
-	/* 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;
-
-	/* Reset the chip, see Software Requirement 11.4 item 1. */
-	DoC_Command(docptr, NAND_CMD_RESET, 0x00);
-	DoC_WaitReady(docptr);
-	/* Set device to main plane of flash */
-	DoC_Command(docptr, NAND_CMD_READ0, 0x00);
-
-	/* issue the Serial Data In command to initial the Page Program process */
-	DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
-	DoC_Address(docptr, 3, to, 0x00, 0x00);
-	DoC_WaitReady(docptr);
-
-	if (eccbuf) {
-		/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
-		WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
-		WriteDOC (DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
-	} else {
-		/* disable the ECC engine */
-		WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
-		WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
-	}
-
-	/* Write the data via the internal pipeline through CDSN IO register,
-	   see Pipelined Write Operations 11.2 */
-#ifndef USE_MEMCPY
-	for (i = 0; i < len; i++) {
-		/* N.B. you have to increase the source address in this way or the
-		   ECC logic will not work properly */
-		WriteDOC(buf[i], docptr, Mil_CDSN_IO + i);
-	}
-#else
-	memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len);
-#endif
-	WriteDOC(0x00, docptr, WritePipeTerm);
-
-	if (eccbuf) {
-		/* Write ECC data to flash, the ECC info is generated by the DiskOnChip ECC logic
-		   see Reed-Solomon EDC/ECC 11.1 */
-		WriteDOC(0, docptr, NOP);
-		WriteDOC(0, docptr, NOP);
-		WriteDOC(0, docptr, NOP);
-
-		/* Read the ECC data through the DiskOnChip ECC logic */
-		for (i = 0; i < 6; i++) {
-			eccbuf[i] = ReadDOC(docptr, ECCSyndrome0 + i);
-		}
-
-		/* ignore the ECC engine */
-		WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
-
-#ifndef USE_MEMCPY
-		/* Write the ECC data to flash */
-		for (i = 0; i < 6; i++) {
-			/* N.B. you have to increase the source address in this way or the
-			   ECC logic will not work properly */
-			WriteDOC(eccbuf[i], docptr, Mil_CDSN_IO + i);
-		}
-#else
-		memcpy_toio(docptr + DoC_Mil_CDSN_IO, eccbuf, 6);
-#endif
-
-		/* write the block status BLOCK_USED (0x5555) at the end of ECC data
-		   FIXME: this is only a hack for programming the IPL area for LinuxBIOS
-		   and should be replace with proper codes in user space utilities */ 
-		WriteDOC(0x55, docptr, Mil_CDSN_IO);
-		WriteDOC(0x55, docptr, Mil_CDSN_IO + 1);
-
-		WriteDOC(0x00, docptr, WritePipeTerm);
-
-#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
-	}
-
-	/* 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 Slow IO register
-	   see Software Requirement 11.4 item 5.*/
-	DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP);
-	dummy = ReadDOC(docptr, CDSNSlowIO);
-	DoC_Delay(docptr, 2);
-	if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
-		printk("Error programming flash\n");
-		/* Error in programming
-		   FIXME: implement Bad Block Replacement (in nftl.c ??) */
-		*retlen = 0;
-		return -EIO;
-	}
-
-	/* Let the caller know we completed it */
-	*retlen = len;
-
-	return 0;
-}
-
-static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
-			size_t *retlen, u_char *buf)
-{
-#ifndef USE_MEMCPY
-	int i;
-#endif
-	volatile char dummy;
-	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-	unsigned long docptr = this->virtadr;
-	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
-
-	/* 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;
-
-	/* disable the ECC engine */
-	WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
-	WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
-
-	/* issue the Read2 command to set the pointer to the Spare Data Area.
-	   Polling the Flash Ready bit after issue 3 bytes address in
-	   Sequence Read Mode, see Software Requirement 11.4 item 1.*/
-	DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP);
-	DoC_Address(docptr, 3, ofs, CDSN_CTRL_WP, 0x00);
-	DoC_WaitReady(docptr);
-
-	/* Read the data out via the internal pipeline through CDSN IO register,
-	   see Pipelined Read Operations 11.3 */
-	dummy = ReadDOC(docptr, ReadPipeInit);
-#ifndef USE_MEMCPY
-	for (i = 0; i < len-1; i++) {
-		/* N.B. you have to increase the source address in this way or the
-		   ECC logic will not work properly */
-		buf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
-	}
-	buf[i] = ReadDOC(docptr, LastDataRead);
-#else
-	memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len - 1);
-#endif
-	buf[len - 1] = ReadDOC(docptr, LastDataRead);
-
-	*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)
-{
-#ifndef USE_MEMCPY
-	int i;
-#endif
-	volatile char dummy;
-	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-	unsigned long docptr = this->virtadr;
-	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
-
-	/* 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;
-
-	/* disable the ECC engine */
-	WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
-	WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
-
-	/* Reset the chip, see Software Requirement 11.4 item 1. */
-	DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP);
-	DoC_WaitReady(docptr);
-	/* issue the Read2 command to set the pointer to the Spare Data Area. */
-	DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP);
-
-	/* issue the Serial Data In command to initial the Page Program process */
-	DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
-	DoC_Address(docptr, 3, ofs, 0x00, 0x00);
-
-	/* Write the data via the internal pipeline through CDSN IO register,
-	   see Pipelined Write Operations 11.2 */
-#ifndef USE_MEMCPY
-	for (i = 0; i < len; i++) {
-		/* N.B. you have to increase the source address in this way or the
-		   ECC logic will not work properly */
-		WriteDOC(buf[i], docptr, Mil_CDSN_IO + i);
-	}
-#else
-	memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len);
-#endif
-	WriteDOC(0x00, docptr, 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 Slow IO register
-	   see Software Requirement 11.4 item 5.*/
-	DoC_Command(docptr, NAND_CMD_STATUS, 0x00);
-	dummy = ReadDOC(docptr, CDSNSlowIO);
-	DoC_Delay(docptr, 2);
-	if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
-		printk("Error programming oob data\n");
-		/* FIXME: implement Bad Block Replacement (in nftl.c ??) */
-		*retlen = 0;
-		return -EIO;
-	}
-
-	*retlen = len;
-
-	return 0;
-}
-
-int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
-{
-	volatile char dummy;
-	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-	unsigned long ofs = instr->addr;
-	unsigned long len = instr->len;
-	unsigned long docptr = this->virtadr;
-	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
-
-	if (len != mtd->erasesize) 
-		printk(KERN_WARNING "Erase not right size (%lx != %lx)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;
-
-	/* issue the Erase Setup command */
-	DoC_Command(docptr, NAND_CMD_ERASE1, 0x00);
-	DoC_Address(docptr, 2, ofs, 0x00, 0x00);
-
-	/* Commit the Erase Start command and wait for ready
-	   see Software Requirement 11.4 item 1.*/
-	DoC_Command(docptr, NAND_CMD_ERASE2, 0x00);
-	DoC_WaitReady(docptr);
-
-	instr->state = MTD_ERASING;
-
-	/* Read the status of the flash device through CDSN Slow IO register
-	   see Software Requirement 11.4 item 5.
-	   FIXME: it seems that we are not wait long enough, some blocks are not
-	   erased fully */
-	DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP);
-	dummy = ReadDOC(docptr, CDSNSlowIO);
-	DoC_Delay(docptr, 2);
-	if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
-		printk("Error Erasing at 0x%lx\n", ofs);
-		/* There was an error
-		   FIXME: implement Bad Block Replacement (in nftl.c ??) */
-		instr->state = MTD_ERASE_FAILED;
-	} else
-		instr->state = MTD_ERASE_DONE;
-
-	if (instr->callback) 
-		instr->callback(instr);
-
-	return 0;
-}
-
-/****************************************************************************
- *
- * Module stuff
- *
- ****************************************************************************/
-
-#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
-#define cleanup_doc2001 cleanup_module
-#define init_doc2001 init_module
-#endif
-
-int __init init_doc2001(void)
-{
-	inter_module_register(im_name, THIS_MODULE, &DoCMil_init);
-	return 0;
-}
-
-static void __exit cleanup_doc2001(void)
-{
-	struct mtd_info *mtd;
-	struct DiskOnChip *this;
-
-	while((mtd=docmillist)) {
-		this = (struct DiskOnChip *)mtd->priv;
-		docmillist = this->nextdoc;
-			
-		del_mtd_device(mtd);
-			
-		iounmap((void *)this->virtadr);
-		kfree(this->chips);
-		kfree(mtd);
-	}
-	inter_module_unregister(im_name);
-}
-
-module_exit(cleanup_doc2001);
-module_init(init_doc2001);
-
-
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/docecc.c linux/drivers/mtd/docecc.c
--- v2.4.5/linux/drivers/mtd/docecc.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/docecc.c	Wed Dec 31 16:00:00 1969
@@ -1,522 +0,0 @@
-/*
- * ECC algorithm for M-systems disk on chip. We use the excellent Reed
- * Solmon code of Phil Karn (karn@ka9q.ampr.org) available under the
- * GNU GPL License. The rest is simply to convert the disk on chip
- * syndrom into a standard syndom.
- *
- * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
- * Copyright (C) 2000 Netgem S.A.
- *
- * $Id: docecc.c,v 1.1 2000/11/03 12:43:43 dwmw2 Exp $
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/miscdevice.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/types.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/doc2000.h>
-
-/* need to undef it (from asm/termbits.h) */
-#undef B0
-
-#define MM 10 /* Symbol size in bits */
-#define KK (1023-4) /* Number of data symbols per block */
-#define B0 510 /* First root of generator polynomial, alpha form */
-#define PRIM 1 /* power of alpha used to generate roots of generator poly */
-#define	NN ((1 << MM) - 1)
-
-typedef unsigned short dtype;
-
-/* 1+x^3+x^10 */
-static const int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 };
-
-/* This defines the type used to store an element of the Galois Field
- * used by the code. Make sure this is something larger than a char if
- * if anything larger than GF(256) is used.
- *
- * Note: unsigned char will work up to GF(256) but int seems to run
- * faster on the Pentium.
- */
-typedef int gf;
-
-/* No legal value in index form represents zero, so
- * we need a special value for this purpose
- */
-#define A0	(NN)
-
-/* Compute x % NN, where NN is 2**MM - 1,
- * without a slow divide
- */
-static inline gf
-modnn(int x)
-{
-  while (x >= NN) {
-    x -= NN;
-    x = (x >> MM) + (x & NN);
-  }
-  return x;
-}
-
-#define	min(a,b)	((a) < (b) ? (a) : (b))
-
-#define	CLEAR(a,n) {\
-int ci;\
-for(ci=(n)-1;ci >=0;ci--)\
-(a)[ci] = 0;\
-}
-
-#define	COPY(a,b,n) {\
-int ci;\
-for(ci=(n)-1;ci >=0;ci--)\
-(a)[ci] = (b)[ci];\
-}
-
-#define	COPYDOWN(a,b,n) {\
-int ci;\
-for(ci=(n)-1;ci >=0;ci--)\
-(a)[ci] = (b)[ci];\
-}
-
-#define Ldec 1
-
-/* generate GF(2**m) from the irreducible polynomial p(X) in Pp[0]..Pp[m]
-   lookup tables:  index->polynomial form   alpha_to[] contains j=alpha**i;
-                   polynomial form -> index form  index_of[j=alpha**i] = i
-   alpha=2 is the primitive element of GF(2**m)
-   HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows:
-        Let @ represent the primitive element commonly called "alpha" that
-   is the root of the primitive polynomial p(x). Then in GF(2^m), for any
-   0 <= i <= 2^m-2,
-        @^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
-   where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation
-   of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for
-   example the polynomial representation of @^5 would be given by the binary
-   representation of the integer "alpha_to[5]".
-                   Similarily, index_of[] can be used as follows:
-        As above, let @ represent the primitive element of GF(2^m) that is
-   the root of the primitive polynomial p(x). In order to find the power
-   of @ (alpha) that has the polynomial representation
-        a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
-   we consider the integer "i" whose binary representation with a(0) being LSB
-   and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry
-   "index_of[i]". Now, @^index_of[i] is that element whose polynomial 
-    representation is (a(0),a(1),a(2),...,a(m-1)).
-   NOTE:
-        The element alpha_to[2^m-1] = 0 always signifying that the
-   representation of "@^infinity" = 0 is (0,0,0,...,0).
-        Similarily, the element index_of[0] = A0 always signifying
-   that the power of alpha which has the polynomial representation
-   (0,0,...,0) is "infinity".
- 
-*/
-
-static void
-generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1])
-{
-  register int i, mask;
-
-  mask = 1;
-  Alpha_to[MM] = 0;
-  for (i = 0; i < MM; i++) {
-    Alpha_to[i] = mask;
-    Index_of[Alpha_to[i]] = i;
-    /* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */
-    if (Pp[i] != 0)
-      Alpha_to[MM] ^= mask;	/* Bit-wise EXOR operation */
-    mask <<= 1;	/* single left-shift */
-  }
-  Index_of[Alpha_to[MM]] = MM;
-  /*
-   * Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by
-   * poly-repr of @^i shifted left one-bit and accounting for any @^MM
-   * term that may occur when poly-repr of @^i is shifted.
-   */
-  mask >>= 1;
-  for (i = MM + 1; i < NN; i++) {
-    if (Alpha_to[i - 1] >= mask)
-      Alpha_to[i] = Alpha_to[MM] ^ ((Alpha_to[i - 1] ^ mask) << 1);
-    else
-      Alpha_to[i] = Alpha_to[i - 1] << 1;
-    Index_of[Alpha_to[i]] = i;
-  }
-  Index_of[0] = A0;
-  Alpha_to[NN] = 0;
-}
-
-/*
- * Performs ERRORS+ERASURES decoding of RS codes. bb[] is the content
- * of the feedback shift register after having processed the data and
- * the ECC.
- *
- * Return number of symbols corrected, or -1 if codeword is illegal
- * or uncorrectable. If eras_pos is non-null, the detected error locations
- * are written back. NOTE! This array must be at least NN-KK elements long.
- * The corrected data are written in eras_val[]. They must be xor with the data
- * to retrieve the correct data : data[erase_pos[i]] ^= erase_val[i] .
- * 
- * First "no_eras" erasures are declared by the calling program. Then, the
- * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2).
- * If the number of channel errors is not greater than "t_after_eras" the
- * transmitted codeword will be recovered. Details of algorithm can be found
- * in R. Blahut's "Theory ... of Error-Correcting Codes".
-
- * Warning: the eras_pos[] array must not contain duplicate entries; decoder failure
- * will result. The decoder *could* check for this condition, but it would involve
- * extra time on every decoding operation.
- * */
-static int
-eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
-            gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK], 
-            int no_eras)
-{
-  int deg_lambda, el, deg_omega;
-  int i, j, r,k;
-  gf u,q,tmp,num1,num2,den,discr_r;
-  gf lambda[NN-KK + 1], s[NN-KK + 1];	/* Err+Eras Locator poly
-					 * and syndrome poly */
-  gf b[NN-KK + 1], t[NN-KK + 1], omega[NN-KK + 1];
-  gf root[NN-KK], reg[NN-KK + 1], loc[NN-KK];
-  int syn_error, count;
-
-  syn_error = 0;
-  for(i=0;i<NN-KK;i++)
-      syn_error |= bb[i];
-
-  if (!syn_error) {
-    /* if remainder is zero, data[] is a codeword and there are no
-     * errors to correct. So return data[] unmodified
-     */
-    count = 0;
-    goto finish;
-  }
-  
-  for(i=1;i<=NN-KK;i++){
-    s[i] = bb[0];
-  }
-  for(j=1;j<NN-KK;j++){
-    if(bb[j] == 0)
-      continue;
-    tmp = Index_of[bb[j]];
-    
-    for(i=1;i<=NN-KK;i++)
-      s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*PRIM*j)];
-  }
-
-  /* undo the feedback register implicit multiplication and convert
-     syndromes to index form */
-
-  for(i=1;i<=NN-KK;i++) {
-      tmp = Index_of[s[i]];
-      if (tmp != A0)
-          tmp = modnn(tmp + 2 * KK * (B0+i-1)*PRIM);
-      s[i] = tmp;
-  }
-  
-  CLEAR(&lambda[1],NN-KK);
-  lambda[0] = 1;
-
-  if (no_eras > 0) {
-    /* Init lambda to be the erasure locator polynomial */
-    lambda[1] = Alpha_to[modnn(PRIM * eras_pos[0])];
-    for (i = 1; i < no_eras; i++) {
-      u = modnn(PRIM*eras_pos[i]);
-      for (j = i+1; j > 0; j--) {
-	tmp = Index_of[lambda[j - 1]];
-	if(tmp != A0)
-	  lambda[j] ^= Alpha_to[modnn(u + tmp)];
-      }
-    }
-#if DEBUG >= 1
-    /* Test code that verifies the erasure locator polynomial just constructed
-       Needed only for decoder debugging. */
-    
-    /* find roots of the erasure location polynomial */
-    for(i=1;i<=no_eras;i++)
-      reg[i] = Index_of[lambda[i]];
-    count = 0;
-    for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
-      q = 1;
-      for (j = 1; j <= no_eras; j++)
-	if (reg[j] != A0) {
-	  reg[j] = modnn(reg[j] + j);
-	  q ^= Alpha_to[reg[j]];
-	}
-      if (q != 0)
-	continue;
-      /* store root and error location number indices */
-      root[count] = i;
-      loc[count] = k;
-      count++;
-    }
-    if (count != no_eras) {
-      printf("\n lambda(x) is WRONG\n");
-      count = -1;
-      goto finish;
-    }
-#if DEBUG >= 2
-    printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n");
-    for (i = 0; i < count; i++)
-      printf("%d ", loc[i]);
-    printf("\n");
-#endif
-#endif
-  }
-  for(i=0;i<NN-KK+1;i++)
-    b[i] = Index_of[lambda[i]];
-  
-  /*
-   * Begin Berlekamp-Massey algorithm to determine error+erasure
-   * locator polynomial
-   */
-  r = no_eras;
-  el = no_eras;
-  while (++r <= NN-KK) {	/* r is the step number */
-    /* Compute discrepancy at the r-th step in poly-form */
-    discr_r = 0;
-    for (i = 0; i < r; i++){
-      if ((lambda[i] != 0) && (s[r - i] != A0)) {
-	discr_r ^= Alpha_to[modnn(Index_of[lambda[i]] + s[r - i])];
-      }
-    }
-    discr_r = Index_of[discr_r];	/* Index form */
-    if (discr_r == A0) {
-      /* 2 lines below: B(x) <-- x*B(x) */
-      COPYDOWN(&b[1],b,NN-KK);
-      b[0] = A0;
-    } else {
-      /* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
-      t[0] = lambda[0];
-      for (i = 0 ; i < NN-KK; i++) {
-	if(b[i] != A0)
-	  t[i+1] = lambda[i+1] ^ Alpha_to[modnn(discr_r + b[i])];
-	else
-	  t[i+1] = lambda[i+1];
-      }
-      if (2 * el <= r + no_eras - 1) {
-	el = r + no_eras - el;
-	/*
-	 * 2 lines below: B(x) <-- inv(discr_r) *
-	 * lambda(x)
-	 */
-	for (i = 0; i <= NN-KK; i++)
-	  b[i] = (lambda[i] == 0) ? A0 : modnn(Index_of[lambda[i]] - discr_r + NN);
-      } else {
-	/* 2 lines below: B(x) <-- x*B(x) */
-	COPYDOWN(&b[1],b,NN-KK);
-	b[0] = A0;
-      }
-      COPY(lambda,t,NN-KK+1);
-    }
-  }
-
-  /* Convert lambda to index form and compute deg(lambda(x)) */
-  deg_lambda = 0;
-  for(i=0;i<NN-KK+1;i++){
-    lambda[i] = Index_of[lambda[i]];
-    if(lambda[i] != A0)
-      deg_lambda = i;
-  }
-  /*
-   * Find roots of the error+erasure locator polynomial by Chien
-   * Search
-   */
-  COPY(&reg[1],&lambda[1],NN-KK);
-  count = 0;		/* Number of roots of lambda(x) */
-  for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
-    q = 1;
-    for (j = deg_lambda; j > 0; j--){
-      if (reg[j] != A0) {
-	reg[j] = modnn(reg[j] + j);
-	q ^= Alpha_to[reg[j]];
-      }
-    }
-    if (q != 0)
-      continue;
-    /* store root (index-form) and error location number */
-    root[count] = i;
-    loc[count] = k;
-    /* If we've already found max possible roots,
-     * abort the search to save time
-     */
-    if(++count == deg_lambda)
-      break;
-  }
-  if (deg_lambda != count) {
-    /*
-     * deg(lambda) unequal to number of roots => uncorrectable
-     * error detected
-     */
-    count = -1;
-    goto finish;
-  }
-  /*
-   * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
-   * x**(NN-KK)). in index form. Also find deg(omega).
-   */
-  deg_omega = 0;
-  for (i = 0; i < NN-KK;i++){
-    tmp = 0;
-    j = (deg_lambda < i) ? deg_lambda : i;
-    for(;j >= 0; j--){
-      if ((s[i + 1 - j] != A0) && (lambda[j] != A0))
-	tmp ^= Alpha_to[modnn(s[i + 1 - j] + lambda[j])];
-    }
-    if(tmp != 0)
-      deg_omega = i;
-    omega[i] = Index_of[tmp];
-  }
-  omega[NN-KK] = A0;
-  
-  /*
-   * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
-   * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form
-   */
-  for (j = count-1; j >=0; j--) {
-    num1 = 0;
-    for (i = deg_omega; i >= 0; i--) {
-      if (omega[i] != A0)
-	num1  ^= Alpha_to[modnn(omega[i] + i * root[j])];
-    }
-    num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)];
-    den = 0;
-    
-    /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
-    for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) {
-      if(lambda[i+1] != A0)
-	den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])];
-    }
-    if (den == 0) {
-#if DEBUG >= 1
-      printf("\n ERROR: denominator = 0\n");
-#endif
-      /* Convert to dual- basis */
-      count = -1;
-      goto finish;
-    }
-    /* Apply error to data */
-    if (num1 != 0) {
-        eras_val[j] = Alpha_to[modnn(Index_of[num1] + Index_of[num2] + NN - Index_of[den])];
-    } else {
-        eras_val[j] = 0;
-    }
-  }
- finish:
-  for(i=0;i<count;i++)
-      eras_pos[i] = loc[i];
-  return count;
-}
-
-/***************************************************************************/
-/* The DOC specific code begins here */
-
-#define SECTOR_SIZE 512
-/* The sector bytes are packed into NB_DATA MM bits words */
-#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / MM)
-
-/* 
- * Correct the errors in 'sector[]' by using 'ecc1[]' which is the
- * content of the feedback shift register applyied to the sector and
- * the ECC. Return the number of errors corrected (and correct them in
- * sector), or -1 if error 
- */
-int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6])
-{
-    int parity, i, nb_errors;
-    gf bb[NN - KK + 1];
-    gf error_val[NN-KK];
-    int error_pos[NN-KK], pos, bitpos, index, val;
-    dtype *Alpha_to, *Index_of;
-
-    /* init log and exp tables here to save memory. However, it is slower */
-    Alpha_to = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL);
-    if (!Alpha_to)
-        return -1;
-    
-    Index_of = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL);
-    if (!Index_of) {
-        kfree(Alpha_to);
-        return -1;
-    }
-
-    generate_gf(Alpha_to, Index_of);
-
-    parity = ecc1[1];
-
-    bb[0] =  (ecc1[4] & 0xff) | ((ecc1[5] & 0x03) << 8);
-    bb[1] = ((ecc1[5] & 0xfc) >> 2) | ((ecc1[2] & 0x0f) << 6);
-    bb[2] = ((ecc1[2] & 0xf0) >> 4) | ((ecc1[3] & 0x3f) << 4);
-    bb[3] = ((ecc1[3] & 0xc0) >> 6) | ((ecc1[0] & 0xff) << 2);
-
-    nb_errors = eras_dec_rs(Alpha_to, Index_of, bb, 
-                            error_val, error_pos, 0);
-    if (nb_errors <= 0)
-        goto the_end;
-
-    /* correct the errors */
-    for(i=0;i<nb_errors;i++) {
-        pos = error_pos[i];
-        if (pos >= NB_DATA && pos < KK) {
-            nb_errors = -1;
-            goto the_end;
-        }
-        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 = error_val[i] >> (2 + bitpos);
-                parity ^= val;
-                if (index < SECTOR_SIZE)
-                    sector[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 = error_val[i] << (8 - bitpos);
-                parity ^= val;
-                if (index < SECTOR_SIZE)
-                    sector[index] ^= val;
-            }
-        }
-    }
-    
-    /* use parity to test extra errors */
-    if ((parity & 0xff) != 0)
-        nb_errors = -1;
-
- the_end:
-    kfree(Alpha_to);
-    kfree(Index_of);
-    return nb_errors;
-}
-
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/docprobe.c linux/drivers/mtd/docprobe.c
--- v2.4.5/linux/drivers/mtd/docprobe.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/docprobe.c	Wed Dec 31 16:00:00 1969
@@ -1,283 +0,0 @@
-
-/* Linux driver for Disk-On-Chip devices    */
-/* Probe routines common to all DoC devices */
-/* (c) 1999 Machine Vision Holdings, Inc.   */
-/* Author: David Woodhouse <dwmw2@mvhi.com> */
-/* $Id: docprobe.c,v 1.21 2000/12/03 19:32:34 dwmw2 Exp $ */
-
-
-
-/* DOC_PASSIVE_PROBE:
-   In order to ensure that the BIOS checksum is correct at boot time, and 
-   hence that the onboard BIOS extension gets executed, the DiskOnChip 
-   goes into reset mode when it is read sequentially: all registers 
-   return 0xff until the chip is woken up again by writing to the 
-   DOCControl register. 
-
-   Unfortunately, this means that the probe for the DiskOnChip is unsafe, 
-   because one of the first things it does is write to where it thinks 
-   the DOCControl register should be - which may well be shared memory 
-   for another device. I've had machines which lock up when this is 
-   attempted. Hence the possibility to do a passive probe, which will fail 
-   to detect a chip in reset mode, but is at least guaranteed not to lock
-   the machine.
-
-   If you have this problem, uncomment the following line:
-#define DOC_PASSIVE_PROBE
-*/
-
-
-/* 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 :)
-*/
-#define DOC_SINGLE_DRIVER
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/miscdevice.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/types.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/doc2000.h>
-
-/* Where to look for the devices? */
-#ifndef CONFIG_MTD_DOCPROBE_ADDRESS
-#define CONFIG_MTD_DOCPROBE_ADDRESS 0
-#endif
-
-
-static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS;
-MODULE_PARM(doc_config_location, "l");
-
-
-static unsigned long __initdata doc_locations[] = {
-#if defined (__alpha__) || defined(__i386__)
-#ifdef CONFIG_MTD_DOCPROBE_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,
-#else 
-#warning Unknown architecture for DiskOnChip. No default probe locations defined
-#endif
-	0 };
-
-/* 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)
-{
-	unsigned long window=potential;
-	unsigned char tmp, ChipID;
-#ifndef DOC_PASSIVE_PROBE
-	unsigned char tmp2;
-#endif
-
-	/* Routine copied from the Linux DOC driver */
-
-#ifdef CONFIG_MTD_DOCPROBE_55AA
-	/* Check for 0x55 0xAA signature at beginning of window,
-	   this is no longer true once we remove the IPL (for Millennium */
-	if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa)
-		return 0;
-#endif /* CONFIG_MTD_DOCPROBE_55AA */
-
-#ifndef DOC_PASSIVE_PROBE	
-	/* 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. 
-	 */
-	tmp2 = ReadDOC(window, DOCControl);
-	
-	/* Reset the DiskOnChip ASIC */
-	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
-		 window, DOCControl);
-	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
-		 window, DOCControl);
-	
-	/* Enable the DiskOnChip ASIC */
-	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
-		 window, DOCControl);
-	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
-		 window, DOCControl);
-#endif /* !DOC_PASSIVE_PROBE */	
-
-	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)
-				return ChipID;
-		break;
-		
-	case DOC_ChipID_DocMil:
-		/* Check the TOGGLE bit in the ECC register */
-		tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
-		if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp)
-				return ChipID;
-		break;
-		
-	default:
-#ifndef CONFIG_MTD_DOCPROBE_55AA
-		printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
-		       ChipID, physadr);
-#endif
-#ifndef DOC_PASSIVE_PROBE
-		/* Put back the contents of the DOCControl register, in case it's not
-		 * actually a DiskOnChip.
-		 */
-		WriteDOC(tmp2, window, DOCControl);
-#endif
-		return 0;
-	}
-
-	printk(KERN_WARNING "DiskOnChip failed TOGGLE test, dropping.\n");
-
-#ifndef DOC_PASSIVE_PROBE
-	/* Put back the contents of the DOCControl register: it's not a DiskOnChip */
-	WriteDOC(tmp2, window, DOCControl);
-#endif
-	return 0;
-}   
-
-
-static void DoC_Probe(unsigned long physadr)
-{
-	unsigned long docptr;
-	struct DiskOnChip *this;
-	struct mtd_info *mtd;
-	int ChipID;
-	char namebuf[15];
-	char *name = namebuf;
-	char *im_funcname = NULL;
-	char *im_modname = NULL;
-	void (*initroutine)(struct mtd_info *) = NULL;
-
-	docptr = (unsigned long)ioremap(physadr, 0x2000);
-	
-	if (!docptr)
-		return;
-	
-	if ((ChipID = doccheck(docptr, physadr))) {
-		
-		mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL);
-
-		if (!mtd) {
-			printk("Cannot allocate memory for data structures. Dropping.\n");
-			iounmap((void *)docptr);
-			return;
-		}
-		
-		this = (struct DiskOnChip *)(&mtd[1]);
-		
-		memset((char *)mtd,0, sizeof(struct mtd_info));
-		memset((char *)this, 0, sizeof(struct DiskOnChip));
-
-		mtd->priv = this;
-		this->virtadr = docptr;
-		this->physadr = physadr;
-		this->ChipID = ChipID;
-		sprintf(namebuf, "with ChipID %2.2X", ChipID);
-
-		switch(ChipID) {
-		case DOC_ChipID_Doc2k:
-			name="2000";
-			im_funcname = "DoC2k_init";
-			im_modname = "doc2000";
-			break;
-			
-		case DOC_ChipID_DocMil:
-			name="Millennium";
-#ifdef DOC_SINGLE_DRIVER
-			im_funcname = "DoC2k_init";
-			im_modname = "doc2000";
-#else
-			im_funcname = "DoCMil_init";
-			im_modname = "doc2001";
-#endif /* DOC_SINGLE_DRIVER */
-			break;
-		}
-
-		if (im_funcname)
-			initroutine = inter_module_get_request(im_funcname, im_modname);
-
-		if (initroutine) {
-			(*initroutine)(mtd);
-			inter_module_put(im_funcname);
-			return;
-		}
-		printk("Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr);
-	}
-	iounmap((void *)docptr);
-}
-
-
-/****************************************************************************
- *
- * Module stuff
- *
- ****************************************************************************/
-
-#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
-#define init_doc init_module
-#endif
-
-int __init init_doc(void)
-{
-	int i;
-	
-	printk(KERN_NOTICE "M-Systems DiskOnChip driver. (C) 1999 Machine Vision Holdings, Inc.\n");
-#ifdef PRERELEASE
-	printk(KERN_INFO "$Id: docprobe.c,v 1.21 2000/12/03 19:32:34 dwmw2 Exp $\n");
-#endif
-	if (doc_config_location) {
-		printk("Using configured probe address 0x%lx\n", doc_config_location);
-		DoC_Probe(doc_config_location);
-	} else {
-		for (i=0; doc_locations[i]; i++) {
-			DoC_Probe(doc_locations[i]);
-		}
-	}
-	/* So it looks like we've been used and we get unloaded */
-	MOD_INC_USE_COUNT;
-	MOD_DEC_USE_COUNT;
-	return 0;
-	
-}
-
-module_init(init_doc);
-
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/ftl.c linux/drivers/mtd/ftl.c
--- v2.4.5/linux/drivers/mtd/ftl.c	Sat Apr 28 11:27:54 2001
+++ linux/drivers/mtd/ftl.c	Tue Jun 12 10:30:27 2001
@@ -1,10 +1,10 @@
 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
+ * $Id: ftl.c,v 1.35 2001/06/09 00:40:17 dwmw2 Exp $
  *
- * - Based on Id: ftl.c,v 1.21 2000/08/01 13:07:49 dwmw2 Exp
- * - With the Franz Galiana's set_bam_entry fix from v1.23
- * - Perhaps it's about time I made a branch for the 2.4 series.
-
- * Originally based on:
+ * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
+ *
+ * Based on:
  */
 /*======================================================================
 
@@ -30,8 +30,8 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in which
-    case the provisions of the GPL are applicable instead of the
+    terms of the GNU General Public License version 2 (the "GPL"), in
+    which case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
     your version of this file under the MPL, indicate your decision
@@ -55,11 +55,6 @@
     contact M-Systems (http://www.m-sys.com) directly.
       
 ======================================================================*/
-#define FTL_DEBUG 5
-#ifdef FTL_DEBUG
-#define DEBUGLVL debug
-#endif
-
 #include <linux/module.h>
 #include <linux/mtd/compatmac.h>
 #include <linux/mtd/mtd.h>
@@ -108,19 +103,16 @@
 /*====================================================================*/
 
 /* Parameters that can be set with 'insmod' */
-
-/* Major device # for FTL device */
 static int shuffle_freq = 50;
-
 MODULE_PARM(shuffle_freq, "i");
 
 /*====================================================================*/
 
+/* Major device # for FTL device */
 #ifndef FTL_MAJOR
 #define FTL_MAJOR	44
 #endif
 
-
 /* Funky stuff for setting up a block device */
 #define MAJOR_NR		FTL_MAJOR
 #define DEVICE_NAME		"ftl"
@@ -135,17 +127,8 @@
 
 #include <linux/blk.h>
 
-#ifdef FTL_DEBUG
-static int debug = FTL_DEBUG;
-MODULE_PARM(debug, "i");
-#endif
-
 /*====================================================================*/
 
-#ifndef FTL_MAJOR
-#define FTL_MAJOR	44
-#endif
-
 /* Maximum number of separate memory devices we'll allow */
 #define MAX_DEV		4
 
@@ -200,7 +183,10 @@
 
 void ftl_freepart(partition_t *part);
 
-static struct mtd_notifier ftl_notifier={ftl_notify_add, ftl_notify_remove, NULL};
+static struct mtd_notifier ftl_notifier = {
+	add:	ftl_notify_add,
+	remove:	ftl_notify_remove,
+};
 
 /* Partition state flags */
 #define FTL_FORMATTED	0x01
@@ -226,7 +212,6 @@
 #endif
     part:		ftl_hd,
     sizes:		ftl_sizes,
-    nr_real:		0
 };
 
 /*====================================================================*/
@@ -274,7 +259,7 @@
     /* Search first megabyte for a valid FTL header */
     for (offset = 0;
 	 offset < max_offset;
-	 offset += part->mtd->erasesize?part->mtd->erasesize:0x2000) {
+	 offset += part->mtd->erasesize ? : 0x2000) {
 
 	ret = part->mtd->read(part->mtd, offset, sizeof(header), &ret, 
 			      (unsigned char *)&header);
@@ -296,7 +281,7 @@
 	return -1;
     }
     if ((1 << header.EraseUnitSize) != part->mtd->erasesize) {
-	printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %lx\n",
+	printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
 	       1 << header.EraseUnitSize,part->mtd->erasesize);
 	return -1;
     }
@@ -309,7 +294,7 @@
     erase_unit_header_t header;
     u_int16_t xvalid, xtrans, i;
     u_int blocks, j;
-    int hdr_ok, ret;
+    int hdr_ok, ret = -1;
     ssize_t retval;
     loff_t offset;
 
@@ -318,13 +303,15 @@
 	part->header.NumTransferUnits;
     part->EUNInfo = kmalloc(part->DataUnits * sizeof(struct eun_info_t),
 			    GFP_KERNEL);
-    if (!part->EUNInfo) return -1;
+    if (!part->EUNInfo)
+	    goto out;
     for (i = 0; i < part->DataUnits; i++)
 	part->EUNInfo[i].Offset = 0xffffffff;
     part->XferInfo =
 	kmalloc(part->header.NumTransferUnits * sizeof(struct xfer_info_t),
 		GFP_KERNEL);
-    if (!part->XferInfo) return -1;
+    if (!part->XferInfo)
+	    goto out_EUNInfo;
 
     xvalid = xtrans = 0;
     for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
@@ -334,8 +321,9 @@
 			      (unsigned char *)&header);
 	
 	if (ret) 
-	    return ret;
+	    goto out_XferInfo;
 
+	ret = -1;
 	/* Is this a transfer partition? */
 	hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);
 	if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) &&
@@ -348,7 +336,7 @@
 	    if (xtrans == part->header.NumTransferUnits) {
 		printk(KERN_NOTICE "ftl_cs: format error: too many "
 		       "transfer units!\n");
-		return -1;
+		goto out_XferInfo;
 	    }
 	    if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) {
 		part->XferInfo[xtrans].state = XFER_PREPARED;
@@ -369,18 +357,22 @@
 	(xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) {
 	printk(KERN_NOTICE "ftl_cs: format error: erase units "
 	       "don't add up!\n");
-	return -1;
+	goto out_XferInfo;
     }
     
     /* Set up virtual page map */
     blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
     part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
+    if (!part->VirtualBlockMap)
+	    goto out_XferInfo;
+
     memset(part->VirtualBlockMap, 0xff, blocks * sizeof(u_int32_t));
     part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
 
     part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(u_int32_t),
 			      GFP_KERNEL);
-    if (!part->bam_cache) return -1;
+    if (!part->bam_cache)
+	    goto out_VirtualBlockMap;
 
     part->bam_index = 0xffff;
     part->FreeTotal = 0;
@@ -395,7 +387,7 @@
 			      (unsigned char *)part->bam_cache);
 	
 	if (ret) 
-	    return ret;
+		goto out_bam_cache;
 
 	for (j = 0; j < part->BlocksPerUnit; j++) {
 	    if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) {
@@ -410,8 +402,19 @@
 	}
     }
     
-    return 0;
-    
+    ret = 0;
+    goto out;
+
+out_bam_cache:
+    kfree(part->bam_cache);
+out_VirtualBlockMap:
+    vfree(part->VirtualBlockMap);
+out_XferInfo:
+    kfree(part->XferInfo);
+out_EUNInfo:
+    kfree(part->EUNInfo);
+out:
+    return ret;
 } /* build_maps */
 
 /*======================================================================
@@ -699,7 +702,7 @@
     int queued, ret;
 
     DEBUG(0, "ftl_cs: reclaiming space...\n");
-    DEBUG(4, "NumTransferUnits == %x\n", part->header.NumTransferUnits);
+    DEBUG(3, "NumTransferUnits == %x\n", part->header.NumTransferUnits);
     /* Pick the least erased transfer unit */
     best = 0xffffffff; xfer = 0xffff;
     do {
@@ -707,22 +710,22 @@
 	for (i = 0; i < part->header.NumTransferUnits; i++) {
 	    int n=0;
 	    if (part->XferInfo[i].state == XFER_UNKNOWN) {
-		DEBUG(4,"XferInfo[%d].state == XFER_UNKNOWN\n",i);
+		DEBUG(3,"XferInfo[%d].state == XFER_UNKNOWN\n",i);
 		n=1;
 		erase_xfer(part, i);
 	    }
 	    if (part->XferInfo[i].state == XFER_ERASING) {
-		DEBUG(4,"XferInfo[%d].state == XFER_ERASING\n",i);
+		DEBUG(3,"XferInfo[%d].state == XFER_ERASING\n",i);
 		n=1;
 		queued = 1;
 	    }
 	    else if (part->XferInfo[i].state == XFER_ERASED) {
-		DEBUG(4,"XferInfo[%d].state == XFER_ERASED\n",i);
+		DEBUG(3,"XferInfo[%d].state == XFER_ERASED\n",i);
 		n=1;
 		prepare_xfer(part, i);
 	    }
 	    if (part->XferInfo[i].state == XFER_PREPARED) {
-		DEBUG(4,"XferInfo[%d].state == XFER_PREPARED\n",i);
+		DEBUG(3,"XferInfo[%d].state == XFER_PREPARED\n",i);
 		n=1;
 		if (part->XferInfo[i].EraseCount <= best) {
 		    best = part->XferInfo[i].EraseCount;
@@ -730,7 +733,7 @@
 		}
 	    }
 		if (!n)
-		    DEBUG(4,"XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
+		    DEBUG(3,"XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
 
 	}
 	if (xfer == 0xffff) {
@@ -1219,11 +1222,12 @@
     }
     whole = minor & ~(MAX_PART-1);
 
-    for (i = 0; i < MAX_PART; i++) {
+    i = MAX_PART - 1;
+    while (i-- > 0) {
 	if (ftl_hd[whole+i].nr_sects > 0) {
 	    kdev_t rdev = MKDEV(FTL_MAJOR, whole+i);
-	    sync_dev(rdev);
-	    invalidate_buffers(rdev);
+
+	    invalidate_device(rdev, 1);
 	}
 	ftl_hd[whole+i].start_sect = 0;
 	ftl_hd[whole+i].nr_sects = 0;
@@ -1362,7 +1366,8 @@
 		printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n",
 		       le32_to_cpu(partition->header.FormattedSize) >> 10);
 #endif
-	}
+	} else
+		kfree(partition);
 }
 
 static void ftl_notify_remove(struct mtd_info *mtd)
@@ -1395,13 +1400,10 @@
 		}
 }
 
-
-#if LINUX_VERSION_CODE < 0x20300
-#ifdef MODULE
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
 #define init_ftl init_module
 #define cleanup_ftl cleanup_module
 #endif
-#endif
 
 mod_init_t init_ftl(void)
 {
@@ -1409,6 +1411,8 @@
 
     memset(myparts, 0, sizeof(myparts));
     
+    DEBUG(0, "$Id: ftl.c,v 1.35 2001/06/09 00:40:17 dwmw2 Exp $\n");
+    
     if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) {
 	printk(KERN_NOTICE "ftl_cs: unable to grab major "
 	       "device number!\n");
@@ -1449,7 +1453,5 @@
 	}
 }
 
-#if LINUX_VERSION_CODE > 0x20300
 module_init(init_ftl);
 module_exit(cleanup_ftl);
-#endif
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/jedec.c linux/drivers/mtd/jedec.c
--- v2.4.5/linux/drivers/mtd/jedec.c	Tue Jul  4 10:10:05 2000
+++ linux/drivers/mtd/jedec.c	Wed Dec 31 16:00:00 1969
@@ -1,773 +0,0 @@
-
-/* JEDEC Flash Interface.
- * This is an older type of interface for self programming flash. It is 
- * commonly use in older AMD chips and is obsolete compared with CFI.
- * It is called JEDEC because the JEDEC association distributes the ID codes
- * for the chips.
- *
- * See the AMD flash databook for information on how to operate the interface.
- *
- * This code does not support anything wider than 8 bit flash chips, I am
- * not going to guess how to send commands to them, plus I expect they will
- * all speak CFI..
- *
- * $Id: jedec.c,v 1.1 2000/07/04 07:21:57 jgg Exp $
- */
-
-#include <linux/mtd/jedec.h>
-
-struct mtd_info *jedec_probe(struct map_info *);
-int jedec_probe8(struct map_info *map,unsigned long base,
-		  struct jedec_private *priv);
-int jedec_probe16(struct map_info *map,unsigned long base,
-		  struct jedec_private *priv);
-int jedec_probe32(struct map_info *map,unsigned long base,
-		  struct jedec_private *priv);
-static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
-			    unsigned long len);
-static int flash_erase(struct mtd_info *mtd, struct erase_info *instr);
-static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
-		       size_t *retlen, const u_char *buf);
-   
-EXPORT_SYMBOL(jedec_probe);
-
-/* 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[] = 
-  {{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},
-   {}};
-
-static void jedec_sync(struct mtd_info *mtd) {};
-static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, 
-		      size_t *retlen, u_char *buf);
-static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, 
-			     size_t *retlen, u_char *buf);
-
-/* Probe entry point */
-   struct jedec_private priv;
-   struct mtd_info __MTD;
-struct mtd_info *jedec_probe(struct map_info *map)
-{
-   struct mtd_info *MTD = &__MTD;
-   unsigned long Base;
-   unsigned long SectorSize;
-   unsigned count;
-   unsigned I,Uniq;
-   char Part[200];
-   memset(&priv,0,sizeof(priv));
-   
-   if (map->bank_size == 0)
-      map->bank_size = map->size;
-
-   if (map->size/map->bank_size > MAX_JEDEC_CHIPS)
-   {
-      printk("mtd: Increase MAX_JEDEC_CHIPS, too many banks.\n");
-      return 0;
-   }
-   
-   for (Base = 0; Base < map->size; Base += map->bank_size)
-   {
-      // Perhaps zero could designate all tests?
-      if (map->bus_width == 0)
-	 map->bus_width = 8;
-      
-      if (map->bus_width == 8)
-	 jedec_probe8(map,Base,&priv);
-      if (map->bus_width == 16)
-	 jedec_probe16(map,Base,&priv);
-      if (map->bus_width == 32)
-	 jedec_probe32(map,Base,&priv);
-   }
-   
-   // Get the biggest sector size
-   SectorSize = 0;
-   for (I = 0; priv.chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      if (priv.chips[I].sectorsize > SectorSize)
-	 SectorSize = priv.chips[I].sectorsize;
-   }
-   
-   // Quickly ensure that the other sector sizes are factors of the largest
-   for (I = 0; priv.chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      if ((SectorSize/priv.chips[I].sectorsize)*priv.chips[I].sectorsize != SectorSize)
-      {
-	 printk("mtd: Failed. Device has incompatible mixed sector sizes\n");
-	 return 0;
-      }      
-   }
-   
-   /* 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;
-   strcat(Part," ");
-   Uniq = 0;
-   for (I = 0; priv.chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      const struct JEDECTable *JEDEC;
-      
-      if (priv.chips[I+1].jedec == priv.chips[I].jedec)
-      {
-	 count++;
-	 continue;
-      }
-      
-      // Locate the chip in the jedec table
-      JEDEC = jedec_idtoinf(priv.chips[I].jedec >> 8,priv.chips[I].jedec);
-      if (JEDEC == 0)
-      {
-	 printk("mtd: Internal Error, JEDEC not set\n");
-	 return 0;
-      }
-      
-      if (Uniq != 0)
-	 strcat(Part,",");
-      Uniq++;
-      
-      if (count != 1)
-	 sprintf(Part+strlen(Part),"%x*[%s]",count,JEDEC->name);
-      else
-	 sprintf(Part+strlen(Part),"%s",JEDEC->name);
-      if (strlen(Part) > sizeof(Part)*2/3)
-	 break;
-      count = 1;
-   }   
-
-   /* Determine if the chips are organized in a linear fashion, or if there
-      are empty banks. Note, the last bank does not count here, only the
-      first banks are important. Holes on non-bank boundaries can not exist
-      due to the way the detection algorithm works. */
-   if (priv.size < map->bank_size)
-      map->bank_size = priv.size;
-   priv.is_banked = 0;
-   for (I = 0; I != priv.size/map->bank_size - 1; I++)
-   {
-      if (priv.bank_fill[I] != map->bank_size)
-	 priv.is_banked = 1;
-      
-      /* This even could be eliminated, but new de-optimized read/write
-         functions have to be written */
-      if (priv.bank_fill[I] != priv.bank_fill[0])
-      {
-	 printk("mtd: Failed. Cannot handle unsymetric banking\n");
-	 return 0;
-      }      
-   }
-   if (priv.is_banked == 1)
-      strcat(Part,", banked");
-
-   xprintf("Part: '%s'\n",Part);
-   
-   memset(MTD,0,sizeof(*MTD));
-   strncpy(MTD->name,Part,sizeof(MTD->name));
-   MTD->name[sizeof(MTD->name)-1] = 0;
-   MTD->type = MTD_NORFLASH;
-   MTD->flags = MTD_CAP_NORFLASH;
-   MTD->erasesize = SectorSize*(map->bus_width/8);
-   MTD->size = priv.size;
-   //MTD->module = THIS_MODULE; // ? Maybe this should be the low level module?
-   MTD->erase = flash_erase;
-   if (priv.is_banked == 1)
-      MTD->read = jedec_read_banked;
-   else
-      MTD->read = jedec_read;
-   MTD->write = flash_write;
-   MTD->sync = jedec_sync;
-   MTD->priv = map;
-   map->fldrv_priv = &priv;
-   
-   return MTD;
-}
-
-/* Helper for the JEDEC function, JEDEC numbers all have odd parity */
-static int checkparity(u_char C)
-{
-   u_char parity = 0;
-   while (C != 0)
-   {
-      parity ^= C & 1;
-      C >>= 1;
-   }
-
-   return parity == 1;
-}
-
-
-/* Take an array of JEDEC numbers that represent interleved flash chips
-   and process them. Check to make sure they are good JEDEC numbers, look
-   them up and then add them to the chip list */   
-int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count,
-		  unsigned long base,struct jedec_private *priv)
-{
-   unsigned I,J;
-   unsigned long Size;
-   unsigned long SectorSize;
-   const struct JEDECTable *JEDEC;
-
-   // Test #2 JEDEC numbers exhibit odd parity
-   for (I = 0; I != Count; I++)
-   {
-      if (checkparity(Mfg[I]) == 0 || checkparity(Id[I]) == 0)
-	 return 0;
-   }
-   
-   // Finally, just make sure all the chip sizes are the same
-   JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
-   
-   if (JEDEC == 0)
-   {
-      printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
-      return 0;
-   }
-   
-   Size = JEDEC->size;
-   SectorSize = JEDEC->sectorsize;
-   for (I = 0; I != Count; I++)
-   {
-      JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
-      if (JEDEC == 0)
-      {
-	 printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
-	 return 0;
-      }
-
-      if (Size != JEDEC->size || SectorSize != JEDEC->sectorsize)
-      {
-	 printk("mtd: Failed. Interleved flash does not have matching characteristics\n");
-	 return 0;
-      }      
-   }
-
-   // Load the Chips
-   for (I = 0; I != MAX_JEDEC_CHIPS; I++)
-   {
-      if (priv->chips[I].jedec == 0)
-	 break;
-   }
-
-   if (I + Count > MAX_JEDEC_CHIPS)
-   {
-      printk("mtd: Device has too many chips. Increase MAX_JEDEC_CHIPS\n");
-      return 0;
-   }      
-   
-   // Add them to the table
-   for (J = 0; J != Count; J++)
-   {
-      unsigned long Bank;
-	 
-      JEDEC = jedec_idtoinf(Mfg[J],Id[J]);
-      priv->chips[I].jedec = (Mfg[J] << 8) | Id[J];
-      priv->chips[I].size = JEDEC->size;
-      priv->chips[I].sectorsize = JEDEC->sectorsize;
-      priv->chips[I].base = base + J;
-      priv->chips[I].datashift = J*8;
-      priv->chips[I].capabilities = JEDEC->capabilities;
-      priv->chips[I].offset = priv->size + J;
-
-      // log2 n :|
-      priv->chips[I].addrshift = 0;
-      for (Bank = Count; Bank != 1; Bank >>= 1, priv->chips[I].addrshift++);
-      
-      // Determine how filled this bank is.
-      Bank = base & (~(map->bank_size-1));
-      if (priv->bank_fill[Bank/map->bank_size] < base + 
-	  (JEDEC->size << priv->chips[I].addrshift) - Bank)
-	 priv->bank_fill[Bank/map->bank_size] =  base + (JEDEC->size << priv->chips[I].addrshift) - Bank;
-      I++;
-   }
-
-   priv->size += priv->chips[I-1].size*Count;
-	 
-   return priv->chips[I-1].size;
-}
-
-/* Lookup the chip information from the JEDEC ID table. */
-const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id)
-{
-   __u16 Id = (mfr << 8) | id;
-   unsigned long I = 0;
-   for (I = 0; JEDEC_table[I].jedec != 0; I++)
-      if (JEDEC_table[I].jedec == Id)
-	 return JEDEC_table + I;
-   return 0;
-}
-
-// Look for flash using an 8 bit bus interface
-int jedec_probe8(struct map_info *map,unsigned long base,
-		  struct jedec_private *priv)
-{ 
-   return 0;
-}
-
-// Look for flash using a 16 bit bus interface (ie 2 8-bit chips)
-int jedec_probe16(struct map_info *map,unsigned long base,
-		  struct jedec_private *priv)
-{
-   return 0;
-}
-
-// Look for flash using a 32 bit bus interface (ie 4 8-bit chips)
-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))
-
-   const unsigned long AutoSel1 = 0xAAAAAAAA;
-   const unsigned long AutoSel2 = 0x55555555;
-   const unsigned long AutoSel3 = 0x90909090;
-   const unsigned long Reset = 0x90909090;
-   __u32 OldVal;
-   __u8 Mfg[4];
-   __u8 Id[4];
-   unsigned I;
-   unsigned long Size;
-
-   // Wait for any write/erase operation to settle
-   OldVal = flread(base);
-   for (I = 0; OldVal != flread(base) && I < 10000; I++)
-      OldVal = flread(base);
-   
-   // Reset the chip
-   flwrite(Reset,0x555); 
-   
-   // Send the sequence
-   flwrite(AutoSel1,0x555);
-   flwrite(AutoSel2,0x2AA);
-   flwrite(AutoSel3,0x555);
-   
-   // Test #1, JEDEC numbers are readable from 0x??00/0x??01
-   if (flread(0) != flread(0x100) || 
-       flread(1) != flread(0x101))
-   {
-      flwrite(Reset,0x555);
-      return 0;
-   }
-
-   // Split up the JEDEC numbers
-   OldVal = flread(0);
-   for (I = 0; I != 4; I++)
-      Mfg[I] = (OldVal >> (I*8));
-   OldVal = flread(1);
-   for (I = 0; I != 4; I++)
-      Id[I] = (OldVal >> (I*8));
-      
-   Size = handle_jedecs(map,Mfg,Id,4,base,priv);
-   if (Size == 0)
-   {
-      flwrite(Reset,0x555);
-      return 0;
-   }
-   
-   /* Check if there is address wrap around within a single bank, if this
-      returns JEDEC numbers then we assume that it is wrap around. Notice
-      we call this routine with the JEDEC return still enabled, if two or
-      more flashes have a truncated address space the probe test will still
-      work */
-   if (base + Size+0x555 < map->size &&
-       base + Size+0x555 < (base & (~(map->bank_size-1))) + map->bank_size)
-   {
-      if (flread(base+Size) != flread(base+Size + 0x100) ||
-	  flread(base+Size + 1) != flread(base+Size + 0x101))
-      {
-	 jedec_probe32(map,base+Size,priv);
-      }
-   }
-
-   // Reset.
-   flwrite(0xF0F0F0F0,0x555);
-   
-   return 1;
-   
-   #undef flread
-   #undef flwrite
-}
-
-/* Linear read. */
-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;
-   
-   map->copy_from(map, buf, from, len);
-   *retlen = len;
-   return 0;   
-}
-
-/* Banked read. Take special care to jump past the holes in the bank
-   mapping. This version assumes symetry in the holes.. */
-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;
-
-   *retlen = 0;
-   while (len > 0)
-   {
-      // Determine what bank and offset into that bank the first byte is
-      unsigned long bank = from & (~(priv->bank_fill[0]-1));
-      unsigned long offset = from & (priv->bank_fill[0]-1);
-      unsigned long get = len;
-      if (priv->bank_fill[0] - offset < len)
-	 get = priv->bank_fill[0] - offset;
-
-      bank /= priv->bank_fill[0];      
-      map->copy_from(map,buf + *retlen,bank*map->bank_size + offset,get);
-      
-      len -= get;
-      *retlen += get;
-      from += get;
-   }   
-   return 0;   
-}
-
-/* Pass the flags value that the flash return before it re-entered read 
-   mode. */
-static void jedec_flash_failed(unsigned char code)
-{
-   /* Bit 5 being high indicates that there was an internal device
-      failure, erasure time limits exceeded or something */
-   if ((code & (1 << 5)) != 0)
-   {
-      printk("mtd: Internal Flash failure\n");
-      return;
-   }
-   printk("mtd: Programming didn't take\n");
-}
-
-/* This uses the erasure function described in the AMD Flash Handbook, 
-   it will work for flashes with a fixed sector size only. Flashes with
-   a selection of sector sizes (ie the AMD Am29F800B) will need a different
-   routine. This routine tries to parallize erasing multiple chips/sectors 
-   where possible */
-static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-   // Does IO to the currently selected chip
-   #define flread(x) map->read8(map,chip->base+((x)<<chip->addrshift))
-   #define flwrite(v,x) map->write8(map,v,chip->base+((x)<<chip->addrshift))
-   
-   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;
-
-   // Verify the arguments..
-   if (start + len > mtd->size ||
-       (start % mtd->erasesize) != 0 ||
-       (len % mtd->erasesize) != 0 ||
-       (len/mtd->erasesize) == 0)
-      return -EINVAL;
-   
-   jedec_flash_chip_scan(priv,start,len);
-
-   // Start the erase sequence on each chip
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      unsigned long off;
-      struct jedec_flash_chip *chip = priv->chips + I;
-      
-      if (chip->length == 0)
-	 continue;
-      
-      // Send the erase setup code
-      xprintf("Erase: ");
-      puth(chip->start); putc(' ');
-      puth(chip->base); putc(' ');
-      puth(chip->length); putc(' ');
-      puth(chip->sectorsize); putc('\n');
-      
-      if (chip->start + chip->length > chip->size)
-      {
-	 xprintf("DIE\n");
-	 return -EIO;
-      }     
-      
-      flwrite(0xF0,chip->start + 0x555);
-      flwrite(0xAA,chip->start + 0x555);
-      flwrite(0x55,chip->start + 0x2AA);
-      flwrite(0x80,chip->start + 0x555);
-      flwrite(0xAA,chip->start + 0x555);
-      flwrite(0x55,chip->start + 0x2AA);
-
-      // Use chip erase if possible
-      if (chip->start == 0 && chip->length == chip->size)
-      {
-	 flwrite(0x10,0x555);
-	 continue;
-      }
-            
-      /* Once we start selecting the erase sectors the delay between each 
-         command must not exceed 50us or it will immediately start erasing 
-         and ignore the other sectors */
-/*    how do you portably turn off interrupts?
-      save_flags(flags);
-      cli();*/
-      for (off = 0; off < chip->length; off += chip->sectorsize)
-      {
-	 // Check to make sure we didn't timeout
-	 flwrite(0x30,chip->start + off);
-	 if (off == 0)
-	    continue;
-	 if ((flread(chip->start + off) & (1 << 3)) != 0)
-	 {
-	    printk("mtd: Ack! We timed out the erase timer!\n");
-	    return -EIO;
-	 }       	 
-      }
-//      restore_flags(flags);
-   }   
-
-   /* We could split this into a timer routine and return early, performing
-      background erasure.. Maybe later if the need warrents */
-
-   /* 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.. */
-   
-   /* This being a generic routine assumes a 32 bit bus. It does read32s
-      and bundles interleved chips into the same grouping. This will work 
-      for all bus widths */
-   Time = 0;
-   NoTime = 0;
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      struct jedec_flash_chip *chip = priv->chips + I;
-      unsigned long off = 0;
-      unsigned todo[4] = {0,0,0,0};
-      unsigned todo_left = 0;
-      unsigned J;
-      
-      if (chip->length == 0)
-	 continue;
-
-      /* Find all chips in this data line, realistically this is all 
-         or nothing up to the interleve count */
-      for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
-      {
-	 if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) == 
-	     (chip->base & (~((1<<chip->addrshift)-1))))
-	 {
-	    todo_left++;
-	    todo[priv->chips[J].base & ((1<<chip->addrshift)-1)] = 1;
-	 }	 
-      }
-
-      xprintf("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1],
-	      (short)todo[2],(short)todo[3]);
-      
-      while (1)
-      {
-	 __u32 Last[4];
-	 unsigned long Count = 0;
-	 
-	 /* During erase bit 7 is held low and bit 6 toggles, we watch this,
-	    should it stop toggling or go high then the erase is completed,
-  	    or this is not really flash ;> */
-	 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);
-	 Count = 3;
-	 while (todo_left != 0)
-	 {
-	    for (J = 0; J != 4; J++)
-	    {
-	       __u8 Byte1 = (Last[(Count-1)%4] >> (J*8)) & 0xFF;
-	       __u8 Byte2 = (Last[(Count-2)%4] >> (J*8)) & 0xFF;
-	       __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF;
-	       if (todo[J] == 0)
-		  continue;
-	       
-	       if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2)
-	       {
-//		  printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2);
-		  continue;
-	       }
-	       
-	       if (Byte1 == Byte2)
-	       {
-		  jedec_flash_failed(Byte3);
-		  return -EIO;
-	       }
-	       
-	       todo[J] = 0;
-	       todo_left--;
-	    }
-	    
-/*	    if (NoTime == 0)
-	       Time += HZ/10 - schedule_timeout(HZ/10);*/
-	    NoTime = 0;
-	    
-	    Last[Count % 4] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-	    Count++;
-	    
-	    putc('.');
-	    
-/*	    // Count time, max of 15s per sector (according to AMD)
-	    if (Time > 15*len/mtd->erasesize*HZ)
-	    {
-	       printk("mtd: Flash Erase Timed out\n");
-	       return -EIO;
-	    }	    */
-	 }
-	 	 
-	 puts("out\n");
-	    
-	 // Skip to the next chip if we used chip erase
-	 if (chip->length == chip->size)
-	    off = chip->size;
-	 else
-	    off += chip->sectorsize;
-	 
-	 if (off >= chip->length)
-	    break;
-	 NoTime = 1;
-      }
-      
-      for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
-      {
-	 if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
-	     (chip->base & (~((1<<chip->addrshift)-1))))
-	    priv->chips[J].length = 0;
-      }      
-   }
-       	    
-   puts("done\n");
-   return 0;
-   
-   #undef flread
-   #undef flwrite
-}
-
-/* This is the simple flash writing function. It writes to every byte, in
-   sequence. It takes care of how to properly address the flash if
-   the flash is interleved. It can only be used if all the chips in the 
-   array are identical!*/
-static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
-		       size_t *retlen, const u_char *buf)
-{
-   /* Does IO to the currently selected chip. It takes the bank addressing
-      base (which is divisable by the chip size) adds the necesary lower bits
-      of addrshift (interleve index) and then adds the control register index. */
-   #define flread(x) map->read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-   #define flwrite(v,x) map->write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-   
-   struct map_info *map = (struct map_info *)mtd->priv;
-   struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv;
-   unsigned long base;
-   unsigned long off;
-   
-   if (start + len > mtd->size)
-      return -EIO;
-   
-   puts("Here");
-   
-   while (len != 0)
-   {
-      struct jedec_flash_chip *chip = priv->chips;
-      unsigned long bank;
-      unsigned long boffset;
-	 
-      // Compute the base of the flash.
-      off = start % (chip->size << chip->addrshift);
-      base = start - off;
-
-      // Perform banked addressing translation.
-      bank = base & (~(priv->bank_fill[0]-1));
-      boffset = base & (priv->bank_fill[0]-1);
-      bank = (bank/priv->bank_fill[0])*map->bank_size;
-      base = bank + boffset;
-      
-      xprintf("Flasing %X %X %X\n",base,chip->size,len);
-      
-      // 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 Last[4];
-	 unsigned long Count = 0;
-
-//	 putc('.');
-	 
-	 if (oldbyte == *buf)
-	    continue;
-	 if (((~oldbyte) & *buf) != 0)
-	    printk("mtd: warn: Trying to set a 0 to a 1\n");
-	     
-	 // Write
-	 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);
-	 
-	 /* Wait for the flash to finish the operation. We store the last 4
-	    status bytes that have been retrieved so we can determine why
-	    it failed. The toggle bits keep toggling when there is a 
-	    failure */
-	 for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] &&
-	      Count < 10000; Count++)
-	    Last[Count % 4] = map->read8(map,base + off);
-	 if (Last[(Count - 1) % 4] != *buf)
-	 {
-	    jedec_flash_failed(Last[(Count - 3) % 4]);
-	    return -EIO;
-	 }	 
-      }
-   }
-   *retlen = len;
-   return 0;
-}
-
-/* This is used to enhance the speed of the erase routine,
-   when things are being done to multiple chips it is possible to
-   parallize the operations, particularly full memory erases of multi
-   chip memories benifit */
-static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
-		     unsigned long len)
-{
-   unsigned int I;
-
-   // Zero the records
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-      priv->chips[I].start = priv->chips[I].length = 0;
-   
-   // Intersect the region with each chip
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      struct jedec_flash_chip *chip = priv->chips + I;
-      unsigned long ByteStart;
-      unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift);
-      
-      // End is before this chip or the start is after it
-      if (start+len < chip->offset ||
-	  ChipEndByte - (1 << chip->addrshift) < start)
-	 continue;
-      
-      if (start < chip->offset)
-      {
-	 ByteStart = chip->offset;
-	 chip->start = 0;
-      }      
-      else
-      {
-	 chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift;
-	 ByteStart = start;
-      }
-
-      if (start + len >= ChipEndByte)
-	 chip->length = (ChipEndByte - ByteStart) >> chip->addrshift;
-      else
-	 chip->length = (start + len - ByteStart + (1 << chip->addrshift)-1) >> chip->addrshift;
-   }
-}
-									/*}}}*/
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/map_ram.c linux/drivers/mtd/map_ram.c
--- v2.4.5/linux/drivers/mtd/map_ram.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/map_ram.c	Wed Dec 31 16:00:00 1969
@@ -1,137 +0,0 @@
-/*
- * Common code to handle map devices which are simple RAM
- * (C) 2000 Red Hat. GPL'd.
- * $Id: map_ram.c,v 1.7 2000/12/10 01:39:13 dwmw2 Exp $
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <asm/io.h>
-#include <asm/byteorder.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-
-#include <linux/mtd/map.h>
-
-
-static int mapram_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-static int mapram_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
-static int mapram_erase (struct mtd_info *, struct erase_info *);
-static void mapram_nop (struct mtd_info *);
-
-static const char im_name[] = "map_ram_probe";
-
-/* This routine is made available to other mtd code via
- * inter_module_register.  It must only be accessed through
- * inter_module_get which will bump the use count of this module.  The
- * addresses passed back in mtd are valid as long as the use count of
- * this module is non-zero, i.e. between inter_module_get and
- * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
- */
-
-static struct mtd_info *map_ram_probe(struct map_info *map)
-{
-	struct mtd_info *mtd;
-
-	/* Check the first byte is RAM */
-	map->write8(map, 0x55, 0);
-	if (map->read8(map, 0) != 0x55)
-		return NULL;
-
-	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)
-		return NULL;
-
-	map->write8(map, 0xAA, map->size-1);
-	if (map->read8(map, map->size-1) != 0xAA)
-		return NULL;
-
-	/* OK. It seems to be RAM. */
-
-	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
-	if (!mtd)
-		return NULL;
-
-	memset(mtd, 0, sizeof(*mtd));
-
-	map->im_name = im_name;
-	map->fldrv_destroy = mapram_nop;
-	mtd->priv = map;
-	mtd->name = map->name;
-	mtd->type = MTD_RAM;
-	mtd->erasesize = 0x10000;
-	mtd->size = map->size;
-	mtd->erase = mapram_erase;
-	mtd->read = mapram_read;
-	mtd->write = mapram_write;
-	mtd->sync = mapram_nop;
-	mtd->flags = MTD_CAP_RAM | MTD_VOLATILE;
-	mtd->erasesize = PAGE_SIZE;
-
-	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;
-
-	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;
-
-	map->copy_to(map, to, buf, len);
-	*retlen = len;
-	return 0;
-}
-
-static int mapram_erase (struct mtd_info *mtd, struct erase_info *instr)
-{
-	/* Yeah, it's inefficient. Who cares? It's faster than a _real_
-	   flash erase. */
-	struct map_info *map = (struct map_info *)mtd->priv;
-	unsigned long i;
-
-	for (i=0; i<instr->len; i++)
-		map->write8(map, 0xFF, instr->addr + i);
-
-	if (instr->callback)
-		instr->callback(instr);
-
-	return 0;
-}
-
-static void mapram_nop(struct mtd_info *mtd)
-{
-	/* Nothing to see here */
-}
-
-#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
-#define map_ram_init init_module
-#define map_ram_exit cleanup_module
-#endif
-
-static int __init map_ram_init(void)
-{
-	inter_module_register(im_name, THIS_MODULE, &map_ram_probe);
-	return 0;
-}
-
-static void __exit map_ram_exit(void)
-{
-	inter_module_unregister(im_name);
-}
-
-module_init(map_ram_init);
-module_exit(map_ram_exit);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/map_rom.c linux/drivers/mtd/map_rom.c
--- v2.4.5/linux/drivers/mtd/map_rom.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/map_rom.c	Wed Dec 31 16:00:00 1969
@@ -1,94 +0,0 @@
-/*
- * Common code to handle map devices which are simple ROM
- * (C) 2000 Red Hat. GPL'd.
- * $Id: map_rom.c,v 1.10 2000/12/10 01:39:13 dwmw2 Exp $
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <asm/io.h>
-#include <asm/byteorder.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-
-#include <linux/mtd/map.h>
-
-static int maprom_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-static int maprom_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
-static void maprom_nop (struct mtd_info *);
-
-static const char im_name[] = "map_rom_probe";
-
-/* This routine is made available to other mtd code via
- * inter_module_register.  It must only be accessed through
- * inter_module_get which will bump the use count of this module.  The
- * addresses passed back in mtd are valid as long as the use count of
- * this module is non-zero, i.e. between inter_module_get and
- * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
- */
-
-struct mtd_info *map_rom_probe(struct map_info *map)
-{
-	struct mtd_info *mtd;
-
-	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
-	if (!mtd)
-		return NULL;
-
-	memset(mtd, 0, sizeof(*mtd));
-
-	map->im_name = im_name;
-	map->fldrv_destroy = maprom_nop;
-	mtd->priv = map;
-	mtd->name = map->name;
-	mtd->type = MTD_ROM;
-	mtd->size = map->size;
-	mtd->read = maprom_read;
-	mtd->write = maprom_write;
-	mtd->sync = maprom_nop;
-	mtd->flags = MTD_CAP_ROM;
-	mtd->erasesize = 131072;
-
-	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;
-
-	map->copy_from(map, buf, from, len);
-	*retlen = len;
-	return 0;
-}
-
-static void maprom_nop(struct mtd_info *mtd)
-{
-	/* Nothing to see here */
-}
-
-static int maprom_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
-{
-	printk(KERN_NOTICE "maprom_write called\n");
-	return -EIO;
-}
-
-#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
-#define map_rom_init init_module
-#define map_rom_exit cleanup_module
-#endif
-
-static int __init map_rom_init(void)
-{
-	inter_module_register(im_name, THIS_MODULE, &map_rom_probe);
-	return 0;
-}
-
-static void __exit map_rom_exit(void)
-{
-	inter_module_unregister(im_name);
-}
-
-module_init(map_rom_init);
-module_exit(map_rom_exit);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/Config.in linux/drivers/mtd/maps/Config.in
--- v2.4.5/linux/drivers/mtd/maps/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/Config.in	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,41 @@
+# drivers/mtd/maps/Config.in
+
+# $Id: Config.in,v 1.9.2.1 2001/06/09 19:43:49 dwmw2 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_CFI
+if [ "$CONFIG_MTD_PHYSMAP" = "y" -o "$CONFIG_MTD_PHYSMAP" = "m" ]; 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
+fi
+
+dep_tristate '  Sun Microsystems userflash support' CONFIG_MTD_SUN_UFLASH $CONFIG_SPARC64
+dep_tristate '  CFI Flash device mapped on Nora' CONFIG_MTD_NORA $CONFIG_MTD_CFI
+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 RPX Lite or CLLF' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI 
+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 StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS
+   dep_bool '    Support for RedBoot partition tables on SA11x0' CONFIG_MTD_SA1100_REDBOOT_PARTITIONS $CONFIG_MTD_SA1100 $CONFIG_MTD_REDBOOT_PARTS
+   dep_bool '    Support for Compaq bootldr partition tables on SA11x0' CONFIG_MTD_SA1100_BOOTLDR_PARTITIONS $CONFIG_MTD_SA1100 $CONFIG_MTD_BOOTLDR_PARTS
+dep_tristate '  CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE $CONFIG_MTD_PARTITIONS
+dep_tristate '  CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_XSCALE_IQ80310
+dep_tristate '  CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI_INTELSTD $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_CFI_AMDSTD
+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
+   hex '    Physical length of flash mapping' CONFIG_MTD_CSTM_MIPS_IXX_LEN 0x4000000
+   int '    Bus width in octets' CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH 2
+fi
+dep_tristate '  CFI Flash device mapping on FlagaDM' CONFIG_MTD_CFI_FLAGADM $CONFIG_MTD_CFI
+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 '  Momenco Ocelot boot flash device' CONFIG_MTD_OCELOT $CONFIG_MOMENCO_OCELOT
+endmenu
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/Makefile linux/drivers/mtd/maps/Makefile
--- v2.4.5/linux/drivers/mtd/maps/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/Makefile	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,29 @@
+#
+# linux/drivers/maps/Makefile
+#
+# $Id: Makefile,v 1.9.2.1 2001/06/09 19:43:49 dwmw2 Exp $
+
+O_TARGET	:= mapslink.o
+
+# Chip mappings
+
+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_ELAN_104NC)    += elan-104nc.o
+obj-$(CONFIG_MTD_IQ80310)	+= iq80310.o
+obj-$(CONFIG_MTD_NORA)		+= nora.o
+obj-$(CONFIG_MTD_OCTAGON)	+= octagon-5066.o
+obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o 
+obj-$(CONFIG_MTD_PNC2000)	+= pnc2000.o
+obj-$(CONFIG_MTD_RPXLITE)	+= rpxlite.o
+obj-$(CONFIG_MTD_SA1100)        += sa1100-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_SUN_UFLASH)    += sun_uflash.o
+obj-$(CONFIG_MTD_VMAX)		+= vmax301.o
+obj-$(CONFIG_MTD_DBOX2)		+= dbox2-flash.o
+obj-$(CONFIG_MTD_OCELOT)	+= ocelot.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/cfi_flagadm.c linux/drivers/mtd/maps/cfi_flagadm.c
--- v2.4.5/linux/drivers/mtd/maps/cfi_flagadm.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/cfi_flagadm.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,184 @@
+/*
+ *  Copyright © 2001 Flaga hf. Medical Devices, Kári Davíđsson <kd@flaga.is>
+ *
+ *  $Id: cfi_flagadm.c,v 1.5 2001/05/29 15:47:49 kd 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  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.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+
+/* We split the flash chip up into four parts.
+ * 1: bootloader firts 128k			(0x00000000 - 0x0001FFFF) size 0x020000
+ * 2: kernel 640k					(0x00020000 - 0x000BFFFF) size 0x0A0000
+ * 3: compressed 1536k root ramdisk	(0x000C0000 - 0x0023FFFF) size 0x180000
+ * 4: writeable diskpartition (jffs)(0x00240000 - 0x003FFFFF) size 0x1C0000
+ */
+
+#define FLASH_PHYS_ADDR 0x40000000
+#define FLASH_SIZE 0x400000  
+
+#define FLASH_PARTITION0_ADDR 0x00000000
+#define FLASH_PARTITION0_SIZE 0x00020000
+
+#define FLASH_PARTITION1_ADDR 0x00020000
+#define FLASH_PARTITION1_SIZE 0x000A0000
+
+#define FLASH_PARTITION2_ADDR 0x000C0000
+#define FLASH_PARTITION2_SIZE 0x00180000
+
+#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
+};
+
+struct mtd_partition flagadm_parts[] = {
+	{
+		name	: "Bootloader",
+		offset	: FLASH_PARTITION0_ADDR,
+		size	: FLASH_PARTITION0_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	: "Persistant storage",
+		offset	: FLASH_PARTITION3_ADDR,
+		size	: FLASH_PARTITION3_SIZE
+	}
+};
+
+#define PARTITION_COUNT (sizeof(flagadm_parts)/sizeof(struct mtd_partition))
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_flagadm init_module
+#define cleanup_flagadm cleanup_module
+#endif
+
+static struct mtd_info *mymtd;
+
+int __init init_flagadm(void)
+{	
+	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,
+					FLASH_SIZE);
+
+	if (!flagadm_map.map_priv_1) {
+		printk("Failed to ioremap\n");
+		return -EIO;
+	}
+	mymtd = do_map_probe("cfi", &flagadm_map);
+	if (mymtd) {
+		mymtd->module = 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);
+	return -ENXIO;
+}
+
+static void __exit cleanup_flagadm(void)
+{
+	if (mymtd) {
+		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;
+	}
+}
+
+module_init(init_flagadm);
+module_exit(cleanup_flagadm);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/cstm_mips_ixx.c linux/drivers/mtd/maps/cstm_mips_ixx.c
--- v2.4.5/linux/drivers/mtd/maps/cstm_mips_ixx.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/cstm_mips_ixx.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,314 @@
+/*
+ * $Id: cstm_mips_ixx.c,v 1.3 2001/06/02 14:52:23 dwmw2 Exp $
+ *
+ * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions.
+ * Config with both CFI and JEDEC device support.
+ *
+ * Basically physmap.c with the addition of partitions and 
+ * an array of mapping info to accomodate more than one flash type per board.
+ *
+ * Copyright 2000 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.
+ *
+ *  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.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/config.h>
+
+#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
+#include <linux/delay.h>
+#endif
+
+__u8 cstm_mips_ixx_read8(struct map_info *map, unsigned long ofs)
+{
+	return *(__u8 *)(map->map_priv_1 + ofs);
+}
+
+__u16 cstm_mips_ixx_read16(struct map_info *map, unsigned long ofs)
+{
+	return *(__u16 *)(map->map_priv_1 + ofs);
+}
+
+__u32 cstm_mips_ixx_read32(struct map_info *map, unsigned long ofs)
+{
+	return *(__u32 *)(map->map_priv_1 + ofs);
+}
+
+void cstm_mips_ixx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void cstm_mips_ixx_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	*(__u8 *)(map->map_priv_1 + adr) = d;
+}
+
+void cstm_mips_ixx_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	*(__u16 *)(map->map_priv_1 + adr) = d;
+}
+
+void cstm_mips_ixx_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	*(__u32 *)(map->map_priv_1 + adr) = d;
+}
+
+void cstm_mips_ixx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
+#define CC_GCR             0xB4013818
+#define CC_GPBCR           0xB401380A
+#define CC_GPBDR           0xB4013808
+#define CC_M68K_DEVICE     1
+#define CC_M68K_FUNCTION   6
+#define CC_CONFADDR        0xB8004000
+#define CC_CONFDATA        0xB8004004
+#define CC_FC_FCR          0xB8002004
+#define CC_FC_DCR          0xB8002008
+#define CC_GPACR           0xB4013802
+#define CC_GPAICR          0xB4013804
+#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
+
+void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp)
+{
+  if (vpp) {
+#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
+        __u16	data;
+        __u8	data1;
+	static u8 first = 1;
+
+	// Set GPIO port B pin3 to high
+	data = *(__u16 *)(CC_GPBCR);
+	data = (data & 0xff0f) | 0x0040;
+	*(__u16 *)CC_GPBCR = data;
+	*(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) | 0x08;
+	if (first) {
+		first = 0;
+		/* need to have this delay for first
+		   enabling vpp after powerup */
+		udelay(40);
+	}
+#endif /* CONFIG_MIPS_ITE8172 */
+  }
+  else {
+#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
+        __u16	data;
+
+	// Set GPIO port B pin3 to high
+	data = *(__u16 *)(CC_GPBCR);
+	data = (data & 0xff3f) | 0x0040;
+	*(__u16 *)CC_GPBCR = data;
+	*(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) & 0xf7;
+#endif /* CONFIG_MIPS_ITE8172 */
+  }
+}
+
+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
+};
+
+/* board and partition description */
+
+#define MAX_PHYSMAP_PARTITIONS    8
+struct cstm_mips_ixx_info {
+	char *name;
+	unsigned long window_addr;
+	unsigned long window_size;
+	int buswidth;
+	int num_partitions;
+};
+
+#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
+#define PHYSMAP_NUMBER  1  // number of board desc structs needed, one per contiguous flash type 
+const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = 
+{
+    {   // 28F128J3A in 2x16 configuration
+        "big flash",     // name
+	0x08000000,      // window_addr
+	0x02000000,      // window_size
+        4,               // buswidth
+	1,               // num_partitions
+    }
+
+};
+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,
+	},
+},
+};
+#else /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
+#define PHYSMAP_NUMBER  1  // number of board desc structs needed, one per contiguous flash type 
+const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = 
+{
+    {  
+        "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
+	1,                             // num_partitions
+    },
+
+};
+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,
+	},
+},
+};
+#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
+
+struct map_info cstm_mips_ixx_map[PHYSMAP_NUMBER];
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_cstm_mips_ixx init_module
+#define cleanup_cstm_mips_ixx cleanup_module
+#endif
+
+int __init init_cstm_mips_ixx(void)
+{
+	int i;
+	int jedec;
+        struct mtd_info *mymtd;
+        struct mtd_partition *parts;
+
+	/* Initialize mapping */
+	for (i=0;i<PHYSMAP_NUMBER;i++) {
+		printk(KERN_NOTICE "cstm_mips_ixx flash device: %lx at %lx\n", cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr);
+                memcpy((char *)&cstm_mips_ixx_map[i],(char *)&basic_cstm_mips_ixx_map,sizeof(struct map_info));
+		cstm_mips_ixx_map[i].map_priv_1 = (unsigned long)ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size);
+		if (!cstm_mips_ixx_map[i].map_priv_1) {
+			printk(KERN_WARNING "Failed to ioremap\n");
+			return -EIO;
+	        }
+		cstm_mips_ixx_map[i].name = cstm_mips_ixx_board_desc[i].name;
+		cstm_mips_ixx_map[i].size = cstm_mips_ixx_board_desc[i].window_size;
+		cstm_mips_ixx_map[i].buswidth = cstm_mips_ixx_board_desc[i].buswidth;
+		//printk(KERN_NOTICE "cstm_mips_ixx: ioremap is %x\n",(unsigned int)(cstm_mips_ixx_map[i].map_priv_1));
+	}
+
+#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
+        setup_ITE_IVR_flash();
+#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
+
+	for (i=0;i<PHYSMAP_NUMBER;i++) {
+                parts = &cstm_mips_ixx_partitions[i][0];
+		jedec = 0;
+		mymtd = (struct mtd_info *)do_map_probe("cfi", &cstm_mips_ixx_map[i]);
+		//printk(KERN_NOTICE "phymap %d cfi_probe: mymtd is %x\n",i,(unsigned int)mymtd);
+		if (!mymtd) {
+			jedec = 1;
+			mymtd = (struct mtd_info *)do_map_probe("jedec", &cstm_mips_ixx_map[i]);
+		        printk(KERN_NOTICE "cstm_mips_ixx %d jedec: mymtd is %x\n",i,(unsigned int)mymtd);
+		}
+		if (mymtd) {
+			mymtd->module = 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);
+		}
+		else
+	           return -ENXIO;
+	}
+	return 0;
+}
+
+static void __exit cleanup_cstm_mips_ixx(void)
+{
+	int i;
+        struct mtd_info *mymtd;
+
+	for (i=0;i<PHYSMAP_NUMBER;i++) {
+	        mymtd = (struct mtd_info *)cstm_mips_ixx_map[i].map_priv_2;
+		if (mymtd) {
+			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 defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
+void PCISetULongByOffset(__u32 DevNumber, __u32 FuncNumber, __u32 Offset, __u32 data)
+{
+	__u32	offset;
+
+	offset = ( unsigned long )( 0x80000000 | ( DevNumber << 11 ) + ( FuncNumber << 8 ) + Offset) ;
+
+	*(__u32 *)CC_CONFADDR = offset;	
+	*(__u32 *)CC_CONFDATA = data;
+}
+void setup_ITE_IVR_flash()
+{
+		__u32	size, base;
+
+		size = 0x0e000000;		// 32MiB
+		base = (0x08000000) >> 8 >>1; // Bug: we must shift one more bit
+
+		/* need to set ITE flash to 32 bits instead of default 8 */
+#ifdef CONFIG_MIPS_IVR
+		*(__u32 *)CC_FC_FCR = 0x55;
+		*(__u32 *)CC_GPACR = 0xfffc;
+#else
+		*(__u32 *)CC_FC_FCR = 0x77;
+#endif
+		/* turn bursting off */
+		*(__u32 *)CC_FC_DCR = 0x0;
+
+		/* setup for one chip 4 byte PCI access */
+		PCISetULongByOffset(CC_M68K_DEVICE, CC_M68K_FUNCTION, 0x60, size | base);
+		PCISetULongByOffset(CC_M68K_DEVICE, CC_M68K_FUNCTION, 0x64, 0x02);
+}
+#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
+
+module_init(init_cstm_mips_ixx);
+module_exit(cleanup_cstm_mips_ixx);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/dbox2-flash.c linux/drivers/mtd/maps/dbox2-flash.c
--- v2.4.5/linux/drivers/mtd/maps/dbox2-flash.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/dbox2-flash.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,151 @@
+/*
+ * $Id: dbox2-flash.c,v 1.2 2001/04/26 15:42:43 dwmw2 Exp $
+ *
+ * Nokia / Sagem D-Box 2 flash driver
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/config.h>
+
+/* 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}};
+
+#define NUM_PARTITIONS (sizeof(partition_info) / sizeof(partition_info[0]))
+
+#define WINDOW_ADDR 0x10000000
+#define WINDOW_SIZE 0x800000
+
+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
+};
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_dbox2_flash init_module
+#define cleanup_dbox2_flash cleanup_module
+#endif
+
+mod_init_t 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);
+
+	if (!dbox2_flash_map.map_priv_1) {
+		printk("Failed to ioremap\n");
+		return -EIO;
+	}
+
+	// Probe for dual Intel 28F320 or dual AMD
+	mymtd = do_map_probe("cfi", &dbox2_flash_map);
+	if (!mymtd) {
+	    // Probe for single Intel 28F640
+	    dbox2_flash_map.buswidth = 2;
+	
+	    mymtd = do_map_probe("cfi", &dbox2_flash_map);
+	}
+	    
+	if (mymtd) {
+		mymtd->module = THIS_MODULE;
+
+                /* Create MTD devices for each partition. */
+	        add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
+		
+		return 0;
+	}
+
+	iounmap((void *)dbox2_flash_map.map_priv_1);
+	return -ENXIO;
+}
+
+mod_exit_t cleanup_dbox2_flash(void)
+{
+	if (mymtd) {
+		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;
+	}
+}
+
+module_init(init_dbox2_flash);
+module_exit(cleanup_dbox2_flash);
+
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/dc21285.c linux/drivers/mtd/maps/dc21285.c
--- v2.4.5/linux/drivers/mtd/maps/dc21285.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/dc21285.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,193 @@
+/*
+ * MTD map driver for flash on the DC21285 (the StrongARM-110 companion chip)
+ *
+ * (C) 2000  Nicolas Pitre <nico@cam.org>
+ *
+ * This code is GPL
+ * 
+ * $Id: dc21285.c,v 1.4 2001/04/26 15:40:23 dwmw2 Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/hardware/dec21285.h>
+
+
+static struct mtd_info *mymtd;
+
+__u8 dc21285_read8(struct map_info *map, unsigned long ofs)
+{
+	return *(__u8*)(map->map_priv_1 + ofs);
+}
+
+__u16 dc21285_read16(struct map_info *map, unsigned long ofs)
+{
+	return *(__u16*)(map->map_priv_1 + ofs);
+}
+
+__u32 dc21285_read32(struct map_info *map, unsigned long ofs)
+{
+	return *(__u32*)(map->map_priv_1 + ofs);
+}
+
+void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy(to, (void*)(map->map_priv_1 + from), len);
+}
+
+void dc21285_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	*CSR_ROMWRITEREG = adr;
+	adr &= ~3;
+	*(__u8*)(map->map_priv_1 + adr) = d;
+}
+
+void dc21285_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	*CSR_ROMWRITEREG = adr;
+	adr &= ~1;
+	*(__u16*)(map->map_priv_1 + adr) = d;
+}
+
+void dc21285_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	*(__u32*)(map->map_priv_1 + adr) = d;
+}
+
+void dc21285_copy_to(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)++;
+				dc21285_write32(map, d, to);
+				to += 4;
+				len -= 4;
+			}
+			break;
+		case 2:
+			while (len > 0) {
+				__u16 d = *((__u16*)from)++;
+				dc21285_write16(map, d, to);
+				to += 2;
+				len -= 2;
+			}
+			break;
+		case 1:
+			while (len > 0) {
+				__u8 d = *((__u8*)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
+};
+
+
+/* Partition stuff */
+static struct mtd_partition *dc21285_parts;
+		      
+extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **);
+
+int __init init_dc21285(void)
+{
+	/* Determine buswidth */
+	switch (*CSR_SA110_CNTL & (3<<14)) {
+		case SA110_CNTL_ROMWIDTH_8: 
+			dc21285_map.buswidth = 1;
+			break;
+		case SA110_CNTL_ROMWIDTH_16: 
+			dc21285_map.buswidth = 2; 
+			break;
+		case SA110_CNTL_ROMWIDTH_32: 
+			dc21285_map.buswidth = 4; 
+			break;
+		default:
+			printk (KERN_ERR "DC21285 flash: undefined buswidth\n");
+			return -ENXIO;
+	}
+	printk (KERN_NOTICE "DC21285 flash support (%d-bit buswidth)\n",
+		dc21285_map.buswidth*8);
+
+	/* Let's map the flash area */
+	dc21285_map.map_priv_1 = (unsigned long)__ioremap(DC21285_FLASH, 16*1024*1024, 0);
+	if (!dc21285_map.map_priv_1) {
+		printk("Failed to ioremap\n");
+		return -EIO;
+	}
+
+	mymtd = do_map_probe("cfi", &dc21285_map);
+	if (mymtd) {
+		int nrparts;
+
+		mymtd->module = THIS_MODULE;
+			
+		/* partition fixup */
+
+		nrparts = parse_redboot_partitions(mymtd, &dc21285_parts);
+		if (nrparts <=0) {
+			printk(KERN_NOTICE "RedBoot partition table failed\n");
+			iounmap((void *)dc21285_map.map_priv_1);
+			return -ENXIO;
+		}
+
+		add_mtd_partitions(mymtd, dc21285_parts, nrparts);
+
+		/* 
+		 * Flash timing is determined with bits 19-16 of the
+		 * CSR_SA110_CNTL.  The value is the number of wait cycles, or
+		 * 0 for 16 cycles (the default).  Cycles are 20 ns.
+		 * Here we use 7 for 140 ns flash chips.
+		 */
+		/* access time */
+		*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16));
+		/* burst time */
+		*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;
+}
+
+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)
+		kfree(dc21285_parts);
+}
+
+module_init(init_dc21285);
+module_exit(cleanup_dc21285);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/elan-104nc.c linux/drivers/mtd/maps/elan-104nc.c
--- v2.4.5/linux/drivers/mtd/maps/elan-104nc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/elan-104nc.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,277 @@
+/* elan-104nc.c -- MTD map driver for Arcom Control Systems ELAN-104NC
+ 
+   Copyright (C) 2000 Arcom Control System 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
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+ 
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+ 
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+   $Id: elan-104nc.c,v 1.10 2001/06/02 14:30:44 dwmw2 Exp $
+
+The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16
+mode.  This drivers uses the CFI probe and Intel Extended Command Set drivers.
+
+The flash is accessed as follows:
+
+   32 kbyte memory window at 0xb0000-0xb7fff
+   
+   16 bit I/O port (0x22) for some sort of paging.
+
+The single flash device is divided into 3 partition which appear as seperate
+MTD devices.
+
+Linux thinks that the I/O port is used by the PIC and hence check_region() will
+always fail.  So we don't do it.  I just hope it doesn't break anything.
+*/
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <asm/io.h>
+
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#define WINDOW_START 0xb0000
+/* Number of bits in offset. */
+#define WINDOW_SHIFT 15
+#define WINDOW_LENGTH (1 << WINDOW_SHIFT)
+/* The bits for the offset into the window. */
+#define WINDOW_MASK (WINDOW_LENGTH-1)
+#define PAGE_IO 0x22
+#define PAGE_IO_SIZE 2
+
+static volatile int page_in_window = -1; // Current page in window.
+static unsigned long iomapadr;
+static spinlock_t elan_104nc_spin = SPIN_LOCK_UNLOCKED;
+
+/* 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: "ELAN-104NC flash boot partition", 
+      offset: 0, 
+      size: 640*1024 },
+    { name: "ELAN-104NC flash partition 1", 
+      offset: 640*1024, 
+      size: 896*1024 },
+    { name: "ELAN-104NC flash partition 2", 
+      offset: (640+896)*1024 }
+};
+#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
+
+static inline void elan_104nc_setup(void)
+{
+    u16 t;
+
+    outw( 0x0023 + ROMCS*2, PAGE_IO );
+    t=inb( PAGE_IO+1 );
+
+    t=(t & 0xf9) | 0x04;
+
+    outw( ((0x0023 + ROMCS*2) | (t << 8)), PAGE_IO );
+}
+
+static inline void elan_104nc_page(struct map_info *map, unsigned long ofs)
+{
+	unsigned long page = ofs >> WINDOW_SHIFT;
+       
+	if( page!=page_in_window ) {
+		int cmd1;
+		int cmd2;
+
+		cmd1=(page & 0x700) + 0x0833 + ROMCS*0x4000;
+		cmd2=((page & 0xff) << 8) + 0x0032;
+
+		outw( cmd1, PAGE_IO );
+		outw( cmd2, PAGE_IO );
+
+		page_in_window = page;
+	}
+}
+
+
+static __u8 elan_104nc_read8(struct map_info *map, unsigned long ofs)
+{
+	__u8 ret;
+	spin_lock(&elan_104nc_spin);
+	elan_104nc_page(map, ofs);
+	ret = readb(iomapadr + (ofs & WINDOW_MASK));
+	spin_unlock(&elan_104nc_spin);
+	return ret;
+}
+
+static __u16 elan_104nc_read16(struct map_info *map, unsigned long ofs)
+{
+	__u16 ret;
+	spin_lock(&elan_104nc_spin);
+	elan_104nc_page(map, ofs);
+	ret = readw(iomapadr + (ofs & WINDOW_MASK));
+	spin_unlock(&elan_104nc_spin);
+	return ret;
+}
+
+static __u32 elan_104nc_read32(struct map_info *map, unsigned long ofs)
+{
+	__u32 ret;
+	spin_lock(&elan_104nc_spin);
+	elan_104nc_page(map, ofs);
+	ret = readl(iomapadr + (ofs & WINDOW_MASK));
+	spin_unlock(&elan_104nc_spin);
+	return ret;
+}
+
+static void elan_104nc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	while(len) {
+		unsigned long thislen = len;
+		if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
+			thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
+		
+		spin_lock(&elan_104nc_spin);
+		elan_104nc_page(map, from);
+		memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen);
+		spin_unlock(&elan_104nc_spin);
+		(__u8*)to += thislen;
+		from += thislen;
+		len -= thislen;
+	}
+}
+
+static void elan_104nc_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	spin_lock(&elan_104nc_spin);
+	elan_104nc_page(map, adr);
+	writeb(d, iomapadr + (adr & WINDOW_MASK));
+	spin_unlock(&elan_104nc_spin);
+}
+
+static void elan_104nc_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	spin_lock(&elan_104nc_spin);
+	elan_104nc_page(map, adr);
+	writew(d, iomapadr + (adr & WINDOW_MASK));
+	spin_unlock(&elan_104nc_spin);
+}
+
+static void elan_104nc_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	spin_lock(&elan_104nc_spin);
+	elan_104nc_page(map, adr);
+	writel(d, iomapadr + (adr & WINDOW_MASK));
+	spin_unlock(&elan_104nc_spin);
+}
+
+static void elan_104nc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{	
+	while(len) {
+		unsigned long thislen = len;
+		if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
+			thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
+		
+		spin_lock(&elan_104nc_spin);
+		elan_104nc_page(map, to);
+		memcpy_toio(iomapadr + (to & WINDOW_MASK), from, thislen);
+		spin_unlock(&elan_104nc_spin);
+		to += thislen;
+		from += thislen;
+		len -= thislen;
+	}
+}
+
+static struct map_info elan_104nc_map = {
+	name: "ELAN-104NC flash",
+	size: 8*1024*1024, /* this must be set to a maximum possible amount
+			of flash so the cfi probe routines find all
+			the chips */
+	buswidth: 2,
+	read8: elan_104nc_read8,
+	read16: elan_104nc_read16,
+	read32: elan_104nc_read32,
+	copy_from: elan_104nc_copy_from,
+	write8: elan_104nc_write8,
+	write16: elan_104nc_write16,
+	write32: elan_104nc_write32,
+	copy_to: elan_104nc_copy_to
+};
+
+/* MTD device for all of the flash. */
+static struct mtd_info *all_mtd;
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_elan_104nc init_module
+#define cleanup_elan_104nc cleanup_module
+#endif
+
+mod_exit_t cleanup_elan_104nc(void)
+{
+	if( all_mtd ) {
+		del_mtd_partitions( all_mtd );
+		map_destroy( all_mtd );
+	}
+
+	iounmap((void *)iomapadr);
+	release_region(PAGE_IO,PAGE_IO_SIZE);
+}
+
+mod_init_t init_elan_104nc(void)
+{
+	/* Urg! We use I/O port 0x22 without request_region()ing it */
+	/*
+	if (check_region(PAGE_IO,PAGE_IO_SIZE) != 0) {
+		printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n",
+			elan_104nc_map.name,
+			PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 );
+		return -EAGAIN;
+	}
+	*/
+  	iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
+	if (!iomapadr) {
+		printk( KERN_ERR"%s: failed to ioremap memory region\n",
+			elan_104nc_map.name );
+		return -EIO;
+	}
+
+	/*
+	request_region( PAGE_IO, PAGE_IO_SIZE, "ELAN-104NC flash" );
+	*/
+
+	printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n",
+		elan_104nc_map.name,
+		PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1,
+		WINDOW_START, WINDOW_START+WINDOW_LENGTH-1 );
+
+	elan_104nc_setup();
+
+	/* Probe for chip. */
+	all_mtd = do_map_probe("cfi",  &elan_104nc_map );
+	if( !all_mtd ) {
+		cleanup_elan_104nc();
+		return -ENXIO;
+	}
+	
+	all_mtd->module=THIS_MODULE;
+
+	/* Create MTD devices for each partition. */
+	add_mtd_partitions( all_mtd, partition_info, NUM_PARTITIONS );
+
+	return 0;
+}
+
+module_init(init_elan_104nc);
+module_exit(cleanup_elan_104nc);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/iq80310.c linux/drivers/mtd/maps/iq80310.c
--- v2.4.5/linux/drivers/mtd/maps/iq80310.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/iq80310.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,133 @@
+/*
+ * $Id: iq80310.c,v 1.3 2001/04/26 15:40:23 dwmw2 Exp $
+ *
+ * Mapping for the Intel XScale IQ80310 evaluation board
+ *
+ * Author:	Nicolas Pitre
+ * Copyright:	(C) 2001 MontaVista Software Inc.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+
+#define WINDOW_ADDR 	0
+#define WINDOW_SIZE 	8*1024*1024
+#define BUSWIDTH 	1
+
+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
+};
+
+static struct mtd_partition iq80310_partitions[3] = {
+	{
+		name:		"firmware",
+		size:		0x00080000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE  /* force read-only */
+	},{
+		name:		"kernel",
+		size:		0x00080000,
+		offset:		0x00080000,
+	},{
+		name:		"filesystem",
+		size:		0x00700000,
+		offset:		0x00100000
+	}
+};
+
+static int __init init_iq80310(void)
+{
+	iq80310_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0);
+
+	if (!iq80310_map.map_priv_1) {
+		printk("Failed to ioremap\n");
+		return -EIO;
+	}
+	mymtd = do_map_probe("cfi", &iq80310_map);
+	if (mymtd) {
+		mymtd->module = THIS_MODULE;
+		add_mtd_partitions(mymtd, iq80310_partitions, 3);
+		return 0;
+	}
+
+	iounmap((void *)iq80310_map.map_priv_1);
+	return -ENXIO;
+}
+
+static void __exit cleanup_iq80310(void)
+{
+	if (mymtd) {
+		del_mtd_partitions(mymtd);
+		map_destroy(mymtd);
+	}
+	if (iq80310_map.map_priv_1) {
+		iounmap((void *)iq80310_map.map_priv_1);
+		iq80310_map.map_priv_1 = 0;
+	}
+}
+
+module_init(init_iq80310);
+module_exit(cleanup_iq80310);
+
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/netsc520.c linux/drivers/mtd/maps/netsc520.c
--- v2.4.5/linux/drivers/mtd/maps/netsc520.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/netsc520.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,192 @@
+/* netsc520.c -- MTD map driver for AMD NetSc520 Demonstration Board
+ *
+ * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com)
+ *	based on sc520cdp.c by Sysgo Real-Time Solutions GmbH
+ *
+ * $Id: netsc520.c,v 1.3 2001/06/02 14:52:23 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
+ *
+ * The NetSc520 is a demonstration board for the Elan Sc520 processor available
+ * from AMD.  It has a single back of 16 megs of 32-bit Flash ROM and another
+ * 16 megs of SDRAM.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+
+/*
+** The single, 16 megabyte flash bank is divided into four virtual
+** partitions.  The first partition is 768 KiB and is intended to
+** store the kernel image loaded by the bootstrap loader.  The second
+** partition is 256 KiB and holds the BIOS image.  The third 
+** partition is 14.5 MiB and is intended for the flash file system
+** image.  The last partition is 512 KiB and contains another copy
+** of the BIOS image and the reset vector.
+**
+** Only the third partition should be mounted.  The first partition
+** should not be mounted, but it can erased and written to using the
+** MTD character routines.  The second and fourth partitions should
+** not be touched - it is possible to corrupt the BIOS image by
+** mounting these partitions, and potentially the board will not be
+** 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 Low BIOS", 
+	    offset: 0xc0000, 
+	    size: 	0x40000
+    },
+    { 
+	    name: "NetSc520 file system", 
+	    offset: 0x100000, 
+	    size: 	0xe80000
+    },
+    { 
+	    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
+};
+
+#define NUM_FLASH_BANKS	(sizeof(netsc520_map)/sizeof(struct map_info))
+
+static struct mtd_info *mymtd;
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_netsc520 init_module
+#define cleanup_netsc520 cleanup_module
+#endif
+
+
+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);
+
+	if (!netsc520_map.map_priv_1) {
+		printk("Failed to ioremap_nocache\n");
+		return -EIO;
+	}
+	mymtd = do_map_probe("cfi", &netsc520_map);
+	if(!mymtd)
+		mymtd = do_map_probe("ram", &netsc520_map);
+	if(!mymtd)
+		mymtd = do_map_probe("rom", &netsc520_map);
+
+	if (!mymtd) {
+		iounmap((void *)netsc520_map.map_priv_1);
+		return -ENXIO;
+	}
+		
+	mymtd->module = THIS_MODULE;
+	add_mtd_partitions( mymtd, partition_info, NUM_PARTITIONS );
+	return 0;
+}
+
+static void __exit cleanup_netsc520(void)
+{
+	if (mymtd) {
+		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;
+	}
+}
+
+module_init(init_netsc520);
+module_exit(cleanup_netsc520);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/nora.c linux/drivers/mtd/maps/nora.c
--- v2.4.5/linux/drivers/mtd/maps/nora.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/nora.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,206 @@
+/*
+ * $Id: nora.c,v 1.19 2001/04/26 15:40:23 dwmw2 Exp $
+ *
+ * This is so simple I love it.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+
+
+#define WINDOW_ADDR 0xd0000000
+#define WINDOW_SIZE 0x04000000
+
+static struct mtd_info *mymtd;
+
+__u8 nora_read8(struct map_info *map, unsigned long ofs)
+{
+  return *(__u8 *)(WINDOW_ADDR + ofs);
+}
+
+__u16 nora_read16(struct map_info *map, unsigned long ofs)
+{
+  return *(__u16 *)(WINDOW_ADDR + ofs);
+}
+
+__u32 nora_read32(struct map_info *map, unsigned long ofs)
+{
+  return *(__u32 *)(WINDOW_ADDR + ofs);
+}
+
+void nora_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+  memcpy(to, (void *)(WINDOW_ADDR + from), len);
+}
+
+void nora_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+  *(__u8 *)(WINDOW_ADDR + adr) = d;
+}
+
+void nora_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+  *(__u16 *)(WINDOW_ADDR + adr) = d;
+}
+
+void nora_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+  *(__u32 *)(WINDOW_ADDR + adr) = d;
+}
+
+void nora_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 nora_map = {
+	name: "NORA",
+	size: WINDOW_SIZE,
+	buswidth: 2,
+	read8: nora_read8,
+	read16: nora_read16,
+	read32: nora_read32,
+	copy_from: nora_copy_from,
+	write8: nora_write8,
+	write16: nora_write16,
+	write32: nora_write32,
+	copy_to: nora_copy_to
+};
+
+
+static int nora_mtd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	return mymtd->read(mymtd, from + (unsigned long)mtd->priv, len, retlen, buf);
+}
+
+static int nora_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
+{
+	return mymtd->write(mymtd, to + (unsigned long)mtd->priv, len, retlen, buf);
+}
+
+static int nora_mtd_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+	instr->addr += (unsigned long)mtd->priv;
+	return mymtd->erase(mymtd, instr);
+}
+
+static void nora_mtd_sync (struct mtd_info *mtd)
+{
+	mymtd->sync(mymtd);
+}
+
+static int nora_mtd_suspend (struct mtd_info *mtd)
+{
+	return mymtd->suspend(mymtd);
+}
+
+static void nora_mtd_resume (struct mtd_info *mtd)
+{
+	mymtd->resume(mymtd);
+}
+
+
+static struct mtd_info nora_mtds[4] = {  /* boot, kernel, ramdisk, fs */
+	{
+		type: MTD_NORFLASH,
+		flags: MTD_CAP_NORFLASH,
+		size: 0x60000,
+		erasesize: 0x20000,
+		name: "NORA boot firmware",
+		module: THIS_MODULE,
+		erase: nora_mtd_erase,
+		read: nora_mtd_read,
+		write: nora_mtd_write,
+		suspend: nora_mtd_suspend,
+		resume: nora_mtd_resume,
+		sync: nora_mtd_sync,
+		priv: (void *)0
+	},
+	{
+		type: MTD_NORFLASH,
+		flags: MTD_CAP_NORFLASH,
+		size: 0x0a0000,
+		erasesize: 0x20000,
+		name: "NORA kernel",
+		module: THIS_MODULE,
+		erase: nora_mtd_erase,
+		read: nora_mtd_read,
+		write: nora_mtd_write,
+		suspend: nora_mtd_suspend,
+		resume: nora_mtd_resume,
+		sync: nora_mtd_sync,
+		priv: (void *)0x60000
+	},
+	{
+		type: MTD_NORFLASH,
+		flags: MTD_CAP_NORFLASH,
+		size: 0x900000,
+		erasesize: 0x20000,
+		name: "NORA root filesystem",
+		module: THIS_MODULE,
+		erase: nora_mtd_erase,
+		read: nora_mtd_read,
+		write: nora_mtd_write,
+		suspend: nora_mtd_suspend,
+		resume: nora_mtd_resume,
+		sync: nora_mtd_sync,
+		priv: (void *)0x100000
+	},
+	{
+		type: MTD_NORFLASH,
+		flags: MTD_CAP_NORFLASH,
+		size: 0x1600000,
+		erasesize: 0x20000,
+		name: "NORA second filesystem",
+		module: THIS_MODULE,
+		erase: nora_mtd_erase,
+		read: nora_mtd_read,
+		write: nora_mtd_write,
+		suspend: nora_mtd_suspend,
+		resume: nora_mtd_resume,
+		sync: nora_mtd_sync,
+		priv: (void *)0xa00000
+	}
+};
+
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_nora init_module
+#define cleanup_nora cleanup_module
+#endif
+
+int __init init_nora(void)
+{
+       	printk(KERN_NOTICE "nora flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
+
+	mymtd = do_map_probe("cfi", &nora_map);
+	if (mymtd) {
+		mymtd->module = THIS_MODULE;
+		
+		add_mtd_device(&nora_mtds[2]);
+		add_mtd_device(&nora_mtds[0]);
+		add_mtd_device(&nora_mtds[1]);
+		add_mtd_device(&nora_mtds[3]);
+		return 0;
+	}
+
+	return -ENXIO;
+}
+
+static void __exit cleanup_nora(void)
+{
+	if (mymtd) {
+		del_mtd_device(&nora_mtds[3]);
+		del_mtd_device(&nora_mtds[1]);
+		del_mtd_device(&nora_mtds[0]);
+		del_mtd_device(&nora_mtds[2]);
+		map_destroy(mymtd);
+	}
+}
+
+module_init(init_nora);
+module_exit(cleanup_nora);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/ocelot.c linux/drivers/mtd/maps/ocelot.c
--- v2.4.5/linux/drivers/mtd/maps/ocelot.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/ocelot.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,199 @@
+/*
+ * $Id: ocelot.c,v 1.4 2001/06/08 15:36:27 dwmw2 Exp $
+ *
+ * Flash on Momenco Ocelot
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#define OCELOT_PLD 0x2c000000
+#define FLASH_WINDOW_ADDR 0x2fc00000
+#define FLASH_WINDOW_SIZE 0x00080000
+#define FLASH_BUSWIDTH 1
+#define NVRAM_WINDOW_ADDR 0x2c800000
+#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)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+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 */
+	while(len) {
+		__raw_writeb(*(unsigned char *) from, map->map_priv_1 + to);
+		from++;
+		to++;
+		len--;
+	}
+}
+
+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,
+};
+
+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
+};
+
+static int __init init_ocelot_maps(void)
+{
+	void *pld;
+	int nr_parts;
+	unsigned char brd_status;
+
+       	printk(KERN_INFO "Momenco Ocelot MTD mappings: Flash 0x%x at 0x%x, NVRAM 0x%x at 0x%x\n", 
+	       FLASH_WINDOW_SIZE, FLASH_WINDOW_ADDR, NVRAM_WINDOW_SIZE, NVRAM_WINDOW_ADDR);
+
+	/* First check whether the flash jumper is present */
+	pld = ioremap(OCELOT_PLD, 0x10);
+	if (!pld) {
+		printk(KERN_NOTICE "Failed to ioremap Ocelot PLD\n");
+		return -EIO;
+	}
+	brd_status = readb(pld+4);
+	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) {
+		printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n");
+		return -EIO;
+	}
+	//	ocelot_nvram_map.map_priv_2 = ocelot_nvram_map.map_priv_1;
+
+	/* And do the RAM probe on it to get an MTD device */
+	nvram_mtd = do_map_probe("ram", &ocelot_nvram_map);
+	if (!nvram_mtd) {
+		printk("NVRAM probe failed\n");
+		goto fail_1;
+	}
+	nvram_mtd->module = THIS_MODULE;
+	nvram_mtd->erasesize = 16;
+
+	/* 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) {
+		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);
+
+	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;
+	}
+
+	/* Only probe for flash if the write jumper is present */
+	if (brd_status & 0x40) {
+		flash_mtd = do_map_probe("jedec", &ocelot_flash_map);
+	} else {
+		printk(KERN_NOTICE "Ocelot flash write jumper not present. Treating as ROM\n");
+	}
+	/* If that failed or the jumper's absent, pretend it's ROM */
+	if (!flash_mtd) {
+		flash_mtd = do_map_probe("rom", &ocelot_flash_map);
+		/* If we're treating it as ROM, set the erase size */
+		if (flash_mtd)
+			flash_mtd->erasesize = 0x10000;
+	}
+	if (!flash_mtd)
+		goto fail3;
+
+	add_mtd_device(nvram_mtd);
+
+	flash_mtd->module = THIS_MODULE;
+	nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts);
+
+	if (nr_parts)
+		add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
+	else
+		add_mtd_device(flash_mtd);
+
+	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);
+ fail_2:
+	map_destroy(nvram_mtd);
+ fail_1:
+	iounmap((void *)ocelot_nvram_map.map_priv_1);
+
+	return -ENXIO;
+}
+
+static void __exit cleanup_ocelot_maps(void)
+{
+	del_mtd_device(nvram_mtd);
+	map_destroy(nvram_mtd);
+	iounmap((void *)ocelot_nvram_map.map_priv_1);
+
+	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);
+}
+
+module_init(init_ocelot_maps);
+module_exit(cleanup_ocelot_maps);
+
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/octagon-5066.c linux/drivers/mtd/maps/octagon-5066.c
--- v2.4.5/linux/drivers/mtd/maps/octagon-5066.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/octagon-5066.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,285 @@
+// $Id: octagon-5066.c,v 1.17 2001/06/02 14:30:44 dwmw2 Exp $
+/* ######################################################################
+
+   Octagon 5066 MTD Driver. 
+  
+   The Octagon 5066 is a SBC based on AMD's 586-WB running at 133 MHZ. It
+   comes with a builtin AMD 29F016 flash chip and a socketed EEPROM that
+   is replacable by flash. Both units are mapped through a multiplexer
+   into a 32k memory window at 0xe8000. The control register for the 
+   multiplexing unit is located at IO 0x208 with a bit map of
+     0-5 Page Selection in 32k increments
+     6-7 Device selection:
+        00 SSD off
+        01 SSD 0 (Socket)
+        10 SSD 1 (Flash chip)
+        11 undefined
+  
+   On each SSD, the first 128k is reserved for use by the bios
+   (actually it IS the bios..) This only matters if you are booting off the 
+   flash, you must not put a file system starting there.
+   
+   The driver tries to do a detection algorithm to guess what sort of devices
+   are plugged into the sockets.
+   
+   ##################################################################### */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <asm/io.h>
+
+#include <linux/mtd/map.h>
+
+#define WINDOW_START 0xe8000
+#define WINDOW_LENGTH 0x8000
+#define WINDOW_SHIFT 27
+#define WINDOW_MASK 0x7FFF
+#define PAGE_IO 0x208
+
+static volatile char page_n_dev = 0;
+static unsigned long iomapadr;
+static spinlock_t oct5066_spin = SPIN_LOCK_UNLOCKED;
+
+/*
+ * We use map_priv_1 to identify which device we are.
+ */
+
+static void __oct5066_page(struct map_info *map, __u8 byte)
+{
+	outb(byte,PAGE_IO);
+	page_n_dev = byte;
+}
+
+static inline void oct5066_page(struct map_info *map, unsigned long ofs)
+{
+	__u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT);
+	
+	if (page_n_dev != byte)
+		__oct5066_page(map, byte);
+}
+
+
+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)
+{
+	__u32 ret;
+	spin_lock(&oct5066_spin);
+	oct5066_page(map, ofs);
+	ret = readl(iomapadr + (ofs & WINDOW_MASK));
+	spin_unlock(&oct5066_spin);
+	return ret;
+}
+
+static void oct5066_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	while(len) {
+		unsigned long thislen = len;
+		if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
+			thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
+		
+		spin_lock(&oct5066_spin);
+		oct5066_page(map, from);
+		memcpy_fromio(to, iomapadr + from, thislen);
+		spin_unlock(&oct5066_spin);
+		to += thislen;
+		from += thislen;
+		len -= thislen;
+	}
+}
+
+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)
+{
+	spin_lock(&oct5066_spin);
+	oct5066_page(map, adr);
+	writel(d, iomapadr + (adr & WINDOW_MASK));
+	spin_unlock(&oct5066_spin);
+}
+
+static void oct5066_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	while(len) {
+		unsigned long thislen = len;
+		if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
+			thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
+		
+		spin_lock(&oct5066_spin);
+		oct5066_page(map, to);
+		memcpy_toio(iomapadr + to, from, thislen);
+		spin_unlock(&oct5066_spin);
+		to += thislen;
+		from += thislen;
+		len -= thislen;
+	}
+}
+
+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 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
+	}
+};
+
+static struct mtd_info *oct5066_mtd[2] = {NULL, NULL};
+
+// OctProbe - Sense if this is an octagon card
+// ---------------------------------------------------------------------
+/* Perform a simple validity test, we map the window select SSD0 and
+   change pages while monitoring the window. A change in the window, 
+   controlled by the PAGE_IO port is a functioning 5066 board. This will
+   fail if the thing in the socket is set to a uniform value. */
+static int __init OctProbe(void)
+{
+   unsigned int Base = (1 << 6);
+   unsigned long I;
+   unsigned long Values[10];
+   for (I = 0; I != 20; I++)
+   {
+      outb(Base + (I%10),PAGE_IO);
+      if (I < 10)
+      {
+	 // Record the value and check for uniqueness
+	 Values[I%10] = readl(iomapadr);
+	 if (I > 0 && Values[I%10] == Values[0])
+	    return -EAGAIN;
+      }      
+      else
+      {
+	 // Make sure we get the same values on the second pass
+	 if (Values[I%10] != readl(iomapadr))
+	    return -EAGAIN;
+      }      
+   }
+   return 0;
+}
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_oct5066 init_module
+#define cleanup_oct5066 cleanup_module
+#endif
+
+void cleanup_oct5066(void)
+{
+	int i;
+	for (i=0; i<2; i++) {
+		if (oct5066_mtd[i]) {
+			del_mtd_device(oct5066_mtd[i]);
+			map_destroy(oct5066_mtd[i]);
+		}
+	}
+	iounmap((void *)iomapadr);
+	release_region(PAGE_IO,1);
+}
+
+int __init init_oct5066(void)
+{
+	int i;
+	
+	// Do an autoprobe sequence
+	if (check_region(PAGE_IO,1) != 0)
+		{
+			printk("5066: Page Register in Use\n");
+			return -EAGAIN;
+		}
+	iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
+	if (!iomapadr) {
+		printk("Failed to ioremap memory region\n");
+		return -EIO;
+	}
+	if (OctProbe() != 0)
+		{
+			printk("5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
+			iounmap((void *)iomapadr);
+			return -EAGAIN;
+		}
+	
+	request_region(PAGE_IO,1,"Octagon SSD");
+	
+	// Print out our little header..
+	printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START,
+	       WINDOW_START+WINDOW_LENGTH);
+	
+	for (i=0; i<2; i++) {
+		oct5066_mtd[i] = do_map_probe("cfi", &oct5066_map[i]);
+		if (!oct5066_mtd[i])
+			oct5066_mtd[i] = do_map_probe("jedec", &oct5066_map[i]);
+		if (!oct5066_mtd[i])
+			oct5066_mtd[i] = do_map_probe("ram", &oct5066_map[i]);
+		if (!oct5066_mtd[i])
+			oct5066_mtd[i] = do_map_probe("rom", &oct5066_map[i]);
+		if (oct5066_mtd[i]) {
+			oct5066_mtd[i]->module = THIS_MODULE;
+			add_mtd_device(oct5066_mtd[i]);
+		}
+	}
+	
+	if (!oct5066_mtd[0] && !oct5066_mtd[1]) {
+		cleanup_oct5066();
+		return -ENXIO;
+	}	  
+	
+	return 0;
+}
+
+module_init(init_oct5066);
+module_exit(cleanup_oct5066);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/physmap.c linux/drivers/mtd/maps/physmap.c
--- v2.4.5/linux/drivers/mtd/maps/physmap.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/physmap.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,119 @@
+/*
+ * $Id: physmap.c,v 1.13 2001/06/10 00:14:55 dwmw2 Exp $
+ *
+ * Normal mappings of chips in physical memory
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+
+
+#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
+};
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_physmap init_module
+#define cleanup_physmap cleanup_module
+#endif
+
+int __init init_physmap(void)
+{
+       	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);
+
+	if (!physmap_map.map_priv_1) {
+		printk("Failed to ioremap\n");
+		return -EIO;
+	}
+	mymtd = do_map_probe("cfi", &physmap_map);
+	if (mymtd) {
+		mymtd->module = THIS_MODULE;
+
+		add_mtd_device(mymtd);
+		return 0;
+	}
+
+	iounmap((void *)physmap_map.map_priv_1);
+	return -ENXIO;
+}
+
+static void __exit cleanup_physmap(void)
+{
+	if (mymtd) {
+		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;
+	}
+}
+
+module_init(init_physmap);
+module_exit(cleanup_physmap);
+
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/pnc2000.c linux/drivers/mtd/maps/pnc2000.c
--- v2.4.5/linux/drivers/mtd/maps/pnc2000.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/pnc2000.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,136 @@
+/*
+ *	pnc2000.c - mapper for Photron PNC-2000 board.
+ *
+ * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp>
+ *
+ * This code is GPL
+ *
+ * $Id: pnc2000.c,v 1.8 2001/06/10 00:09:45 dwmw2 Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+
+#define WINDOW_ADDR 0xbf000000
+#define WINDOW_SIZE 0x00400000
+
+/* 
+ * 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
+};
+
+
+/*
+ * MTD 'PARTITIONING' STUFF 
+ */
+static struct mtd_partition pnc_partitions[3] = {
+	{
+		name: "PNC-2000 boot firmware",
+		size: 0x20000,
+		offset: 0
+	},
+	{
+		name: "PNC-2000 kernel",
+		size: 0x1a0000,
+		offset: 0x20000
+	},
+	{
+		name: "PNC-2000 filesystem",
+		size: 0x240000,
+		offset: 0x1c0000
+	}
+};
+
+/* 
+ * This is the master MTD device for which all the others are just
+ * auto-relocating aliases.
+ */
+static struct mtd_info *mymtd;
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_pnc2000 init_module
+#define cleanup_pnc2000 cleanup_module
+#endif
+
+int __init init_pnc2000(void)
+{
+	printk(KERN_NOTICE "Photron PNC-2000 flash mapping: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
+
+	mymtd = do_map_probe("cfi", &pnc_map);
+	if (mymtd) {
+		mymtd->module = THIS_MODULE;
+		return add_mtd_partitions(mymtd, pnc_partitions, 3);
+	}
+
+	return -ENXIO;
+}
+
+static void __exit cleanup_pnc2000(void)
+{
+	if (mymtd) {
+		del_mtd_partitions(mymtd);
+		map_destroy(mymtd);
+	}
+}
+
+module_init(init_pnc2000);
+module_exit(cleanup_pnc2000);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/rpxlite.c linux/drivers/mtd/maps/rpxlite.c
--- v2.4.5/linux/drivers/mtd/maps/rpxlite.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/rpxlite.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,112 @@
+/*
+ * $Id: rpxlite.c,v 1.12 2001/04/26 15:40:23 dwmw2 Exp $
+ *
+ * Handle mapping of the flash on the RPX Lite and CLLF boards
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+
+
+#define WINDOW_ADDR 0xfe000000
+#define WINDOW_SIZE 0x800000
+
+static struct mtd_info *mymtd;
+
+__u8 rpxlite_read8(struct map_info *map, unsigned long ofs)
+{
+	return readb(map->map_priv_1 + ofs);
+}
+
+__u16 rpxlite_read16(struct map_info *map, unsigned long ofs)
+{
+	return readw(map->map_priv_1 + ofs);
+}
+
+__u32 rpxlite_read32(struct map_info *map, unsigned long ofs)
+{
+	return 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)
+{
+	writeb(d, map->map_priv_1 + adr);
+}
+
+void rpxlite_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	writew(d, map->map_priv_1 + adr);
+}
+
+void rpxlite_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	writel(d, map->map_priv_1 + adr);
+}
+
+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
+};
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_rpxlite init_module
+#define cleanup_rpxlite cleanup_module
+#endif
+
+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);
+
+	if (!rpxlite_map.map_priv_1) {
+		printk("Failed to ioremap\n");
+		return -EIO;
+	}
+	mymtd = do_map_probe("cfi", &rpxlite_map);
+	if (mymtd) {
+		mymtd->module = THIS_MODULE;
+		add_mtd_device(mymtd);
+		return 0;
+	}
+
+	iounmap((void *)rpxlite_map.map_priv_1);
+	return -ENXIO;
+}
+
+static void __exit cleanup_rpxlite(void)
+{
+	if (mymtd) {
+		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;
+	}
+}
+
+module_init(init_rpxlite);
+module_exit(cleanup_rpxlite);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/sa1100-flash.c linux/drivers/mtd/maps/sa1100-flash.c
--- v2.4.5/linux/drivers/mtd/maps/sa1100-flash.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/sa1100-flash.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,644 @@
+/*
+ * Flash memory access on SA11x0 based devices
+ * 
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ * 
+ * $Id: sa1100-flash.c,v 1.15 2001/06/02 18:29:22 nico Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/hardware.h>
+
+
+#ifndef CONFIG_ARCH_SA1100
+#error This is for SA1100 architecture only
+#endif
+
+
+#define WINDOW_ADDR 0xe8000000
+
+static __u8 sa1100_read8(struct map_info *map, unsigned long ofs)
+{
+	return *(__u8 *)(WINDOW_ADDR + ofs);
+}
+
+static __u16 sa1100_read16(struct map_info *map, unsigned long ofs)
+{
+	return *(__u16 *)(WINDOW_ADDR + ofs);
+}
+
+static __u32 sa1100_read32(struct map_info *map, unsigned long ofs)
+{
+	return *(__u32 *)(WINDOW_ADDR + ofs);
+}
+
+static void sa1100_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy(to, (void *)(WINDOW_ADDR + from), len);
+}
+
+static void sa1100_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	*(__u8 *)(WINDOW_ADDR + adr) = d;
+}
+
+static void sa1100_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	*(__u16 *)(WINDOW_ADDR + adr) = d;
+}
+
+static void sa1100_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	*(__u32 *)(WINDOW_ADDR + adr) = d;
+}
+
+static void sa1100_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy((void *)(WINDOW_ADDR + to), from, len);
+}
+
+
+#ifdef CONFIG_SA1100_BITSY
+
+static void bitsy_set_vpp(struct map_info *map, int vpp)
+{
+	if (vpp)
+		set_bitsy_egpio(EGPIO_BITSY_VPP_ON);
+	else
+		clr_bitsy_egpio(EGPIO_BITSY_VPP_ON);
+}
+
+#endif
+
+#ifdef CONFIG_SA1100_JORNADA720
+
+static void jornada720_set_vpp(int vpp)
+{
+  if (vpp)
+      PPSR |= 0x80;
+  else
+      PPSR &= ~0x80;
+  PPDR |= 0x80;
+}
+
+#endif
+
+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
+};
+
+
+/*
+ * 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 correspond to the 
+ * value specified in the mapping definition defined by the
+ * "struct map_desc *_io_desc" for the corresponding machine.
+ */
+
+#ifdef CONFIG_SA1100_ASSABET
+
+/* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */
+static unsigned long assabet4_max_flash_size = 0x00400000;
+static struct mtd_partition assabet4_partitions[] = {
+        {
+                name: "bootloader",
+                size: 0x00020000,
+                offset: 0,
+                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
+        }
+};
+
+/* Phase 5 Assabet has two 28F128J3A flash parts in bank 0: */
+static unsigned long assabet5_max_flash_size = 0x02000000;
+static struct mtd_partition assabet5_partitions[] = {
+        {
+                name: "bootloader",
+                size: 0x00040000,
+                offset: 0,
+                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
+        }
+};
+
+#define assabet_max_flash_size assabet5_max_flash_size
+#define assabet_partitions     assabet5_partitions
+
+#endif
+
+#ifdef CONFIG_SA1100_FLEXANET
+
+/* Flexanet has two 28F128J3A flash parts in bank 0: */
+static unsigned long flexanet_max_flash_size = 0x02000000;
+static struct mtd_partition flexanet_partitions[] = {
+        {
+                name: "bootloader",
+                size: 0x00040000,
+                offset: 0,
+                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: "altkernel",
+                size: 0x000C0000,
+                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: "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
+        }
+};
+
+#endif
+
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+static unsigned long huw_webpanel_max_flash_size = 0x01000000;
+static struct mtd_partition huw_webpanel_partitions[] = {
+	{ 
+	  name: "Loader",
+	  size: 0x00040000,
+	  offset: 0,
+	},{
+	  name: "Sector 1",
+	  size: 0x00040000,
+	  offset: MTDPART_OFS_APPEND,
+	},{
+	  size: MTDPART_SIZ_FULL,
+	  offset: MTDPART_OFS_APPEND,
+	}
+};
+#endif /* CONFIG_SA1100_HUW_WEBPANEL */
+
+
+#ifdef CONFIG_SA1100_BITSY
+
+static unsigned long bitsy_max_flash_size = 0x02000000;
+static struct mtd_partition bitsy_partitions[] = {
+	{
+		name: "BITSY boot firmware",
+		size: 0x00040000,
+		offset: 0,
+		mask_flags: MTD_WRITEABLE  /* force read-only */
+	},{
+		name: "BITSY kernel",
+		size: 0x00080000,
+		offset: 0x40000
+	},{
+		name: "BITSY params",
+		size: 0x00040000,
+		offset: 0xC0000
+	},{
+#ifdef CONFIG_JFFS2_FS
+		name: "BITSY root jffs2",
+		offset: 0x00100000,
+		size: MTDPART_SIZ_FULL
+#else
+		name: "BITSY initrd",
+		size: 0x00100000,
+		offset: 0x00100000
+	},{
+		name: "BITSY root cramfs",
+		size: 0x00300000,
+		offset: 0x00200000
+	},{
+		name: "BITSY usr cramfs",
+		size: 0x00800000,
+		offset: 0x00500000
+	},{
+		name: "BITSY usr local",
+		offset: 0x00d00000,
+		size: MTDPART_SIZ_FULL
+#endif
+	}
+};
+
+#endif
+#ifdef CONFIG_SA1100_FREEBIRD
+static unsigned long freebird_max_flash_size = 0x02000000;
+static struct mtd_partition freebird_partitions[] = {
+#if CONFIG_SA1100_FREEBIRD_NEW
+    {
+     name: "firmware",
+     size: 0x00040000,
+     offset: 0,
+     mask_flags: MTD_WRITEABLE  /* force read-only */
+    },{
+     name: "kernel",
+     size: 0x00080000,
+     offset: 0x40000
+    },{
+     name: "params",
+     size: 0x00040000,
+     offset: 0xC0000
+    },{
+     name: "initrd",
+     size: 0x00100000,
+     offset: 0x00100000
+    },{
+     name: "root cramfs",
+     size: 0x00300000,
+     offset: 0x00200000
+    },{
+     name: "usr cramfs",
+     size: 0x00C00000,
+     offset: 0x00500000
+    },{
+	 name: "local",
+	 offset: 0x01100000,
+	 size: MTDPART_SIZ_FULL 
+	}
+#else
+	{ offset: 0,            		size: 0x00040000,   },
+	{ offset: MTDPART_OFS_APPEND,   size: 0x000c0000,   },
+	{ offset: MTDPART_OFS_APPEND,	size: 0x00400000,	},
+	{ offset: MTDPART_OFS_APPEND,   size: MTDPART_SIZ_FULL  }
+#endif
+	};
+#endif
+																									
+
+#ifdef CONFIG_SA1100_CERF
+
+static unsigned long cerf_max_flash_size = 0x01000000;
+static struct mtd_partition cerf_partitions[] = {
+	{ offset: 0,			size: 0x00800000 	},
+	{ offset: MTDPART_OFS_APPEND,	size: 0x00800000 	}
+};
+
+#endif
+
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+
+static unsigned long graphicsclient_max_flash_size = 0x01000000;
+static struct mtd_partition graphicsclient_partitions[] = {
+	{ 
+	 name: "Bootloader + zImage",
+	 offset: 0,
+	 size: 0x100000
+	},
+	{ 
+         name: "ramdisk.gz",
+         offset: MTDPART_OFS_APPEND,
+         size: 0x300000 		
+	},
+	{ 
+	  name: "User FS",
+          offset: MTDPART_OFS_APPEND,	
+          size: MTDPART_SIZ_FULL
+	}
+};
+
+#endif
+
+#ifdef CONFIG_SA1100_LART
+
+static unsigned long lart_max_flash_size = 0x00400000;
+static struct mtd_partition lart_partitions[] = {
+	{ offset: 0,			size: 0x020000 		},
+	{ offset: MTDPART_OFS_APPEND,	size: 0x0e0000 		},
+	{ offset: MTDPART_OFS_APPEND,	size: MTDPART_SIZ_FULL 	}
+};
+
+#endif
+
+#ifdef CONFIG_SA1100_PANGOLIN
+
+static unsigned long pangolin_max_flash_size = 0x04000000;
+static struct mtd_partition pangolin_partitions[] = {
+	{
+	  name: "boot firmware",
+	  offset: 0x00000000,
+	  size: 0x00080000,
+	  mask_flags: MTD_WRITEABLE,  /* force read-only */
+	},
+	{
+	  name: "kernel",
+	  offset: 0x00080000,
+	  size: 0x00100000,
+	},
+	{
+	  name: "initrd",
+	  offset: 0x00180000,
+	  size: 0x00200000,
+	},
+	{
+	  name: "initrd-test",
+	  offset: 0x00400000,
+	  size: 0x03C00000,
+	}
+};
+
+#endif
+
+#ifdef CONFIG_SA1100_YOPY
+
+static unsigned long yopy_max_flash_size = 0x08000000;
+static struct mtd_partition yopy_partitions[] = {
+	{
+		name: "boot firmware",
+		offset: 0x00000000,
+		size: 0x00040000,
+		mask_flags: MTD_WRITEABLE,  /* force read-only */
+	},
+	{
+		name: "kernel",
+		offset: 0x00080000,
+		size: 0x00080000,
+	},
+	{
+		name: "initrd",
+		offset: 0x00100000,
+		size: 0x00300000,
+	},
+	{
+		name: "root",
+		offset: 0x00400000,
+		size: 0x01000000,
+	},
+};
+
+#endif
+
+#ifdef CONFIG_SA1100_JORNADA720
+
+static unsigned long jornada720_max_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 kernel",
+		size: 0x000c0000,
+		offset: 0x40000
+	},{
+		name: "JORNADA720 params",
+		size: 0x00040000,
+		offset: 0x100000
+	},{
+		name: "JORNADA720 initrd",
+		size: 0x00100000,
+		offset: 0x00140000
+	},{
+		name: "JORNADA720 root cramfs",
+		size: 0x00300000,
+		offset: 0x00240000
+	},{
+		name: "JORNADA720 usr cramfs",
+		size: 0x00800000,
+		offset: 0x00540000
+	},{
+		name: "JORNADA720 usr local",
+		offset: 0x00d00000,
+		size: 0  /* will expand to the end of the flash */
+	}
+};
+#endif
+
+#ifdef CONFIG_SA1100_SHERMAN
+
+static unsigned long sherman_max_flash_size = 0x02000000;
+static struct mtd_partition sherman_partitions[] = {
+	{ offset: 0,			size: 0x50000 	},
+	{ offset: MTDPART_OFS_APPEND,	size: 0x70000 	},
+	{ offset: MTDPART_OFS_APPEND,	size: 0x600000 	},
+	{ offset: MTDPART_OFS_APPEND,	size: 0xA0000 	}
+};
+
+#endif
+
+#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
+
+
+extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+extern int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+
+static struct mtd_partition *parsed_parts;
+static struct mtd_info *mymtd;
+
+int __init sa1100_mtd_init(void)
+{
+	struct mtd_partition *parts;
+	int nb_parts = 0;
+	int parsed_nr_parts = 0;
+	char *part_type;
+	
+	sa1100_map.buswidth = (MSC0 & MSC_RBW) ? 2 : 4;
+	printk(KERN_NOTICE "SA1100 flash: probing %d-bit flash bus\n", sa1100_map.buswidth*8);
+	mymtd = do_map_probe("cfi", &sa1100_map);
+	if (!mymtd)
+		return -ENXIO;
+	mymtd->module = THIS_MODULE;
+
+	/*
+	 * Static partition definition selection
+	 */
+	part_type = "static";
+#ifdef CONFIG_SA1100_ASSABET
+	if (machine_is_assabet()) {
+		parts = assabet_partitions;
+		nb_parts = NB_OF(assabet_partitions);
+		sa1100_map.size = assabet_max_flash_size;
+	}
+#endif
+
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+	if (machine_is_huw_webpanel()) {
+		parts = huw_webpanel_partitions;
+		nb_parts = NB_OF(huw_webpanel_partitions);
+		sa1100_map.size = huw_webpanel_max_flash_size;
+	}
+#endif
+
+#ifdef CONFIG_SA1100_BITSY
+	if (machine_is_bitsy()) {
+		parts = bitsy_partitions;
+		nb_parts = NB_OF(bitsy_partitions);
+		sa1100_map.size = bitsy_max_flash_size;
+		sa1100_map.set_vpp = bitsy_set_vpp;
+	}
+#endif
+#ifdef CONFIG_SA1100_FREEBIRD
+	if (machine_is_freebird()) {
+		parts = freebird_partitions;
+		nb_parts = NB_OF(freebird_partitions);
+		sa1100_map.size = freebird_max_flash_size;
+	}
+#endif
+#ifdef CONFIG_SA1100_CERF
+	if (machine_is_cerf()) {
+		parts = cerf_partitions;
+		nb_parts = NB_OF(cerf_partitions);
+		sa1100_map.size = cerf_max_flash_size;
+	}
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+	if (machine_is_graphicsclient()) {
+		parts = graphicsclient_partitions;
+		nb_parts = NB_OF(graphicsclient_partitions);
+		sa1100_map.size = graphicsclient_max_flash_size;
+	}
+#endif
+#ifdef CONFIG_SA1100_LART
+	if (machine_is_lart()) {
+		parts = lart_partitions;
+		nb_parts = NB_OF(lart_partitions);
+		sa1100_map.size = lart_max_flash_size;
+	}
+#endif
+#ifdef CONFIG_SA1100_PANGOLIN
+	if (machine_is_pangolin()) {
+		parts = pangolin_partitions;
+		nb_parts = NB_OF(pangolin_partitions);
+		sa1100_map.size = pangolin_max_flash_size;
+	}
+#endif
+#ifdef CONFIG_SA1100_JORNADA720
+	if (machine_is_jornada720()) {
+		parts = jornada720_partitions;
+		nb_parts = NB_OF(jornada720_partitions);
+		sa1100_map.size = jornada720_max_flash_size;
+		sa1100_map.set_vpp = jornada720_set_vpp;
+	}
+#endif
+#ifdef CONFIG_SA1100_YOPY
+	if (machine_is_yopy()) {
+		parts = yopy_partitions;
+		nb_parts = NB_OF(yopy_partitions);
+		sa1100_map.size = yopy_max_flash_size;
+	}
+#endif
+#ifdef CONFIG_SA1100_SHERMAN
+	if (machine_is_sherman()) {
+		parts = sherman_partitions;
+		nb_parts = NB_OF(sherman_partitions);
+		sa1100_map.size = sherman_max_flash_size;
+	}
+#endif
+#ifdef CONFIG_SA1100_FLEXANET
+	if (machine_is_flexanet()) {
+		parts = flexanet_partitions;
+		nb_parts = NB_OF(flexanet_partitions);
+		sa1100_map.size = flexanet_max_flash_size;
+	}
+#endif
+
+
+	if (!nb_parts) {
+		printk(KERN_WARNING "MTD: no known flash definition for this SA1100 machine\n");
+		return -ENXIO;
+	}
+
+
+	/*
+	 * Dynamic partition selection stuff (might override the static ones)
+	 */
+#ifdef CONFIG_MTD_SA1100_REDBOOT_PARTITIONS
+	if (parsed_nr_parts == 0) {
+		int ret = parse_redboot_partitions(mymtd, &parsed_parts);
+		
+		if (ret > 0) {
+			part_type = "RedBoot";
+			parsed_nr_parts = ret;
+		}
+	}
+#endif
+#ifdef CONFIG_MTD_SA1100_BOOTLDR_PARTITIONS
+	if (parsed_nr_parts == 0) {
+		int ret = parse_bootldr_partitions(mymtd, &parsed_parts);
+		if (ret > 0) {
+			part_type = "Compaq bootldr";
+			parsed_nr_parts = ret;
+		}
+	}
+#endif
+
+	if (parsed_nr_parts > 0) {
+		parts = parsed_parts;
+		nb_parts = parsed_nr_parts;
+	}
+
+	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);
+	}
+	return 0;
+}
+
+static void __exit sa1100_mtd_cleanup(void)
+{
+	if (mymtd) {
+		del_mtd_partitions(mymtd);
+		map_destroy(mymtd);
+		if (parsed_parts)
+			kfree(parsed_parts);
+	}
+}
+
+module_init(sa1100_mtd_init);
+module_exit(sa1100_mtd_cleanup);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/sbc_gxx.c linux/drivers/mtd/maps/sbc_gxx.c
--- v2.4.5/linux/drivers/mtd/maps/sbc_gxx.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/sbc_gxx.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,278 @@
+/* sbc_gxx.c -- MTD map driver for Arcom Control Systems SBC-MediaGX,
+                SBC-GXm and SBC-GX1 series boards.
+ 
+   Copyright (C) 2001 Arcom Control System 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
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+ 
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+ 
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+   $Id: sbc_gxx.c,v 1.17 2001/06/02 14:52:23 dwmw2 Exp $
+
+The SBC-MediaGX / SBC-GXx has up to 16 MiB of 
+Intel StrataFlash (28F320/28F640) in x8 mode.  
+
+This driver uses the CFI probe and Intel Extended Command Set drivers.
+
+The flash is accessed as follows:
+
+   16 kbyte memory window at 0xdc000-0xdffff
+   
+   Two IO address locations for paging
+   
+   0x258
+       bit 0-7: address bit 14-21
+   0x259
+       bit 0-1: address bit 22-23
+       bit 7:   0 - reset/powered down
+                1 - device enabled
+
+The single flash device is divided into 3 partition which appear as 
+separate MTD devices.
+
+25/04/2001 AJL (Arcom)  Modified signon strings and partition sizes
+                        (to support bzImages up to 638KiB-ish)
+*/
+
+// Includes
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <asm/io.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+// Defines
+
+// - Hardware specific
+
+#define WINDOW_START 0xdc000
+
+/* Number of bits in offset. */
+#define WINDOW_SHIFT 14
+#define WINDOW_LENGTH (1 << WINDOW_SHIFT)
+
+/* The bits for the offset into the window. */
+#define WINDOW_MASK (WINDOW_LENGTH-1)
+#define PAGE_IO 0x258
+#define PAGE_IO_SIZE 2
+
+/* bit 7 of 0x259 must be 1 to enable device. */
+#define DEVICE_ENABLE 0x8000
+
+// - Flash / Partition sizing
+
+#define MAX_SIZE_KiB             16384
+#define BOOT_PARTITION_SIZE_KiB  768
+#define DATA_PARTITION_SIZE_KiB  1280
+#define APP_PARTITION_SIZE_KiB   6144
+
+// 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;
+
+/* 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 }
+};
+
+#define NUM_PARTITIONS 3
+
+static inline void sbc_gxx_page(struct map_info *map, unsigned long ofs)
+{
+	unsigned long page = ofs >> WINDOW_SHIFT;
+
+	if( page!=page_in_window ) {
+		outw( page | DEVICE_ENABLE, PAGE_IO );
+		page_in_window = page;
+	}
+}
+
+
+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)
+{
+	__u32 ret;
+	spin_lock(&sbc_gxx_spin);
+	sbc_gxx_page(map, ofs);
+	ret = readl(iomapadr + (ofs & WINDOW_MASK));
+	spin_unlock(&sbc_gxx_spin);
+	return ret;
+}
+
+static void sbc_gxx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	while(len) {
+		unsigned long thislen = len;
+		if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
+			thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
+		
+		spin_lock(&sbc_gxx_spin);
+		sbc_gxx_page(map, from);
+		memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen);
+		spin_unlock(&sbc_gxx_spin);
+		(__u8*)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)
+{
+	spin_lock(&sbc_gxx_spin);
+	sbc_gxx_page(map, adr);
+	writel(d, iomapadr + (adr & WINDOW_MASK));
+	spin_unlock(&sbc_gxx_spin);
+}
+
+static void sbc_gxx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{	
+	while(len) {
+		unsigned long thislen = len;
+		if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
+			thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
+		
+		spin_lock(&sbc_gxx_spin);
+		sbc_gxx_page(map, to);
+		memcpy_toio(iomapadr + (to & WINDOW_MASK), from, thislen);
+		spin_unlock(&sbc_gxx_spin);
+		to += thislen;
+		from += thislen;
+		len -= thislen;
+	}
+}
+
+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
+			 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
+};
+
+/* MTD device for all of the flash. */
+static struct mtd_info *all_mtd;
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_sbc_gxx init_module
+#define cleanup_sbc_gxx cleanup_module
+#endif
+
+mod_exit_t cleanup_sbc_gxx(void)
+{
+	if( all_mtd ) {
+		del_mtd_partitions( all_mtd );
+		map_destroy( all_mtd );
+	}
+
+	iounmap((void *)iomapadr);
+	release_region(PAGE_IO,PAGE_IO_SIZE);
+}
+
+mod_init_t 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);
+	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" );
+	
+	printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n",
+		sbc_gxx_map.name,
+		PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1,
+		WINDOW_START, WINDOW_START+WINDOW_LENGTH-1 );
+
+	/* Probe for chip. */
+	all_mtd = do_map_probe( "cfi", &sbc_gxx_map );
+	if( !all_mtd ) {
+		cleanup_sbc_gxx();
+		return -ENXIO;
+	}
+	
+	all_mtd->module=THIS_MODULE;
+
+	/* Create MTD devices for each partition. */
+	add_mtd_partitions(all_mtd, partition_info, NUM_PARTITIONS );
+
+	return 0;
+}
+
+module_init(init_sbc_gxx);
+module_exit(cleanup_sbc_gxx);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/sc520cdp.c linux/drivers/mtd/maps/sc520cdp.c
--- v2.4.5/linux/drivers/mtd/maps/sc520cdp.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/sc520cdp.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,348 @@
+/* sc520cdp.c -- MTD map driver for AMD SC520 Customer Development Platform
+ *
+ * Copyright (C) 2001 Sysgo Real-Time Solutions GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: sc520cdp.c,v 1.7 2001/06/02 14:52:23 dwmw2 Exp $
+ *
+ *
+ * The SC520CDP is an evaluation board for the Elan SC520 processor available
+ * from AMD. It has two banks of 32-bit Flash ROM, each 8 Megabytes in size,
+ * and up to 512 KiB of 8-bit DIL Flash ROM.
+ * For details see http://www.amd.com/products/epd/desiging/evalboards/18.elansc520/520_cdp_brief/index.html
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+
+
+/*
+** The Embedded Systems BIOS decodes the first FLASH starting at
+** 0x8400000. This is a *terrible* place for it because accessing
+** the flash at this location causes the A22 address line to be high
+** (that's what 0x8400000 binary's ought to be). But this is the highest
+** order address line on the raw flash devices themselves!!
+** This causes the top HALF of the flash to be accessed first. Beyond
+** the physical limits of the flash, the flash chip aliases over (to
+** 0x880000 which causes the bottom half to be accessed. This splits the
+** flash into two and inverts it! If you then try to access this from another
+** program that does NOT do this insanity, then you *will* access the
+** first half of the flash, but not find what you expect there. That
+** stuff is in the *second* half! Similarly, the address used by the
+** BIOS for the second FLASH bank is also quite a bad choice.
+** If REPROGRAM_PAR is defined below (the default), then this driver will
+** choose more useful addresses for the FLASH banks by reprogramming the
+** responsible PARxx registers in the SC520's MMCR region. This will
+** cause the settings to be incompatible with the BIOS's settings, which
+** shouldn't be a problem since you are running Linux, (i.e. the BIOS is
+** not much use anyway). However, if you need to be compatible with
+** the BIOS for some reason, just undefine REPROGRAM_PAR.
+*/
+#define REPROGRAM_PAR
+
+
+
+#ifdef REPROGRAM_PAR
+
+/* These are the addresses we want.. */
+#define WINDOW_ADDR_0	0x08800000
+#define WINDOW_ADDR_1	0x09000000
+#define WINDOW_ADDR_2	0x09800000
+
+/* .. and these are the addresses the BIOS gives us */
+#define WINDOW_ADDR_0_BIOS	0x08400000
+#define WINDOW_ADDR_1_BIOS	0x08c00000
+#define WINDOW_ADDR_2_BIOS	0x09400000
+
+#else
+
+#define WINDOW_ADDR_0	0x08400000
+#define WINDOW_ADDR_1	0x08C00000
+#define WINDOW_ADDR_2	0x09400000
+
+#endif
+
+#define WINDOW_SIZE_0	0x00800000
+#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 #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 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
+	},
+};
+
+#define NUM_FLASH_BANKS	(sizeof(sc520cdp_map)/sizeof(struct map_info))
+
+static struct mtd_info *mymtd[NUM_FLASH_BANKS];
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_sc520cdp init_module
+#define cleanup_sc520cdp cleanup_module
+#endif
+
+#ifdef REPROGRAM_PAR
+
+/*
+** The SC520 MMCR (memory mapped control register) region resides
+** at 0xFFFEF000. The 16 Programmable Address Region (PAR) registers
+** are at offset 0x88 in the MMCR:
+*/
+#define SC520_MMCR_BASE		0xFFFEF000
+#define SC520_MMCR_EXTENT	0x1000
+#define SC520_PAR(x)		((0x88/sizeof(unsigned long)) + (x))
+#define NUM_SC520_PAR		16	/* total number of PAR registers */
+
+/*
+** The highest three bits in a PAR register determine what target
+** device is controlled by this PAR. Here, only ROMCS? and BOOTCS
+** devices are of interest.
+*/
+#define SC520_PAR_BOOTCS	(0x4<<29)
+#define SC520_PAR_ROMCS0	(0x5<<29)
+#define SC520_PAR_ROMCS1	(0x6<<29)
+#define SC520_PAR_TRGDEV	(0x7<<29)
+
+/*
+** Bits 28 thru 26 determine some attributes for the
+** region controlled by the PAR. (We only use non-cacheable)
+*/
+#define SC520_PAR_WRPROT	(1<<26)	/* write protected       */
+#define SC520_PAR_NOCACHE	(1<<27)	/* non-cacheable         */
+#define SC520_PAR_NOEXEC	(1<<28)	/* code execution denied */
+
+
+/*
+** Bit 25 determines the granularity: 4K or 64K
+*/
+#define SC520_PAR_PG_SIZ4	(0<<25)
+#define SC520_PAR_PG_SIZ64	(1<<25)
+
+/*
+** Build a value to be written into a PAR register.
+** We only need ROM entries, 64K page size:
+*/
+#define SC520_PAR_ENTRY(trgdev, address, size) \
+	((trgdev) | SC520_PAR_NOCACHE | SC520_PAR_PG_SIZ64 | \
+	(address) >> 16 | (((size) >> 16) - 1) << 14)
+
+struct sc520_par_table
+{
+	unsigned long trgdev;
+	unsigned long new_par;
+	unsigned long default_address;
+};
+
+static struct sc520_par_table par_table[NUM_FLASH_BANKS] =
+{
+	{	/* Flash Bank #0: selected by ROMCS0 */
+		SC520_PAR_ROMCS0,
+		SC520_PAR_ENTRY(SC520_PAR_ROMCS0, WINDOW_ADDR_0, WINDOW_SIZE_0),
+		WINDOW_ADDR_0_BIOS
+	},
+	{	/* Flash Bank #1: selected by ROMCS1 */
+		SC520_PAR_ROMCS1,
+		SC520_PAR_ENTRY(SC520_PAR_ROMCS1, WINDOW_ADDR_1, WINDOW_SIZE_1),
+		WINDOW_ADDR_1_BIOS
+	},
+	{	/* DIL (BIOS) Flash: selected by BOOTCS */
+		SC520_PAR_BOOTCS,
+		SC520_PAR_ENTRY(SC520_PAR_BOOTCS, WINDOW_ADDR_2, WINDOW_SIZE_2),
+		WINDOW_ADDR_2_BIOS
+	}
+};
+
+
+static void sc520cdp_setup_par(void)
+{
+	volatile unsigned long *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);
+	if(!mmcr) { /* ioremap_nocache failed: skip the PAR reprogramming */
+		/* force map_priv_2 fields to BIOS defaults: */
+		for(i = 0; i < NUM_FLASH_BANKS; i++)
+			sc520cdp_map[i].map_priv_2 = par_table[i].default_address;
+		return;
+	}
+
+	/*
+	** Find the PARxx registers that are reponsible for activating
+	** ROMCS0, ROMCS1 and BOOTCS. Reprogram each of these with a
+	** new value from the table.
+	*/
+	for(i = 0; i < NUM_FLASH_BANKS; i++) {		/* for each par_table entry  */
+		for(j = 0; j < NUM_SC520_PAR; j++) {	/* for each PAR register     */
+			mmcr_val = mmcr[SC520_PAR(j)];
+			/* if target device field matches, reprogram the PAR */
+			if((mmcr_val & SC520_PAR_TRGDEV) == par_table[i].trgdev)
+			{
+				mmcr[SC520_PAR(j)] = par_table[i].new_par;
+				break;
+			}
+		}
+		if(j == NUM_SC520_PAR)
+		{	/* no matching PAR found: try default BIOS address */
+			printk(KERN_NOTICE "Could not find PAR responsible for %s\n",
+				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;
+		}
+	}
+	iounmap((void *)mmcr);
+}
+#endif
+
+
+static int __init init_sc520cdp(void)
+{
+	int i, devices_found = 0;
+	
+#ifdef REPROGRAM_PAR
+	/* reprogram PAR registers so flash appears at the desired addresses */
+	sc520cdp_setup_par();
+#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);
+
+		if (!sc520cdp_map[i].map_priv_1) {
+			printk("Failed to ioremap_nocache\n");
+			return -EIO;
+		}
+		mymtd[i] = do_map_probe("cfi", &sc520cdp_map[i]);
+		if(!mymtd[i])
+			mymtd[i] = do_map_probe("jedec", &sc520cdp_map[i]);
+		if(!mymtd[i])
+			mymtd[i] = do_map_probe("rom", &sc520cdp_map[i]);
+
+		if (mymtd[i]) {
+			mymtd[i]->module = THIS_MODULE;
+			add_mtd_device(mymtd[i]);
+			++devices_found;
+		}
+		else {
+			iounmap((void *)sc520cdp_map[i].map_priv_1);
+		}
+	}
+	return(devices_found ? 0 : -ENXIO);
+}
+
+static void __exit cleanup_sc520cdp(void)
+{
+	int i;
+	
+	for (i = 0; i < NUM_FLASH_BANKS; i++) {
+		if (mymtd[i]) {
+			del_mtd_device(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;
+		}
+	}
+}
+
+module_init(init_sc520cdp);
+module_exit(cleanup_sc520cdp);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/sun_uflash.c linux/drivers/mtd/maps/sun_uflash.c
--- v2.4.5/linux/drivers/mtd/maps/sun_uflash.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/sun_uflash.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,224 @@
+/* $Id: sun_uflash.c,v 1.2 2001/04/26 15:40:23 dwmw2 Exp $
+ *
+ * sun_uflash - Driver implementation for user-programmable flash
+ * present on many Sun Microsystems SME boardsets.
+ *
+ * This driver does NOT provide access to the OBP-flash for
+ * safety reasons-- use <linux>/drivers/sbus/char/flash.c instead.
+ *
+ * Copyright (c) 2001 Eric Brower (ebrower@usa.net)
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <asm/ebus.h>
+#include <asm/oplib.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+
+#define UFLASH_OBPNAME	"flashprom"
+#define UFLASH_DEVNAME 	"userflash"
+
+#define UFLASH_WINDOW_SIZE	0x200000
+#define UFLASH_BUSWIDTH		1			/* EBus is 8-bit */
+
+MODULE_AUTHOR
+	("Eric Brower <ebrower@usa.net>");
+MODULE_DESCRIPTION
+	("User-programmable flash device on Sun Microsystems boardsets");
+MODULE_SUPPORTED_DEVICE
+	("userflash");
+
+static LIST_HEAD(device_list);
+struct uflash_dev {
+	char *			name;	/* device name */
+	struct map_info 	map;	/* mtd map info */
+	struct mtd_info *	mtd;	/* mtd info */
+	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
+};
+
+int uflash_devinit(struct linux_ebus_device* edev)
+{
+	int iTmp, nregs;
+	struct linux_prom_registers regs[2];
+	struct uflash_dev *pdev;
+
+	iTmp = prom_getproperty(
+		edev->prom_node, "reg", (void *)regs, sizeof(regs));
+	if ((iTmp % sizeof(regs[0])) != 0) {
+		printk("%s: Strange reg property size %d\n", 
+			UFLASH_DEVNAME, iTmp);
+		return -ENODEV;
+	}
+
+	nregs = iTmp / sizeof(regs[0]);
+
+	if (nregs != 1) {
+		/* Non-CFI userflash device-- once I find one we
+		 * can work on supporting it.
+		 */
+		printk("%s: unsupported device at 0x%lx (%d regs): " \
+			"email ebrower@usa.net\n", 
+			UFLASH_DEVNAME, edev->resource[0].start, nregs);
+		return -ENODEV;
+	}
+
+	if(0 == (pdev = kmalloc(sizeof(struct uflash_dev), GFP_KERNEL))) {
+		printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME);
+		return(-ENOMEM);
+	}
+	
+	/* copy defaults and tweak parameters */
+	memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ));
+	pdev->map.size = regs[0].reg_size;
+
+	iTmp = prom_getproplen(edev->prom_node, "model");
+	pdev->name = kmalloc(iTmp, GFP_KERNEL);
+	prom_getstring(edev->prom_node, "model", pdev->name, iTmp);
+	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) {
+		printk("%s: failed to map device\n", __FUNCTION__);
+		kfree(pdev->name);
+		kfree(pdev);
+		return(-1);
+	}
+
+	/* MTD registration */
+	pdev->mtd = do_map_probe("cfi", &pdev->map);
+	if(0 == pdev->mtd) {
+		iounmap((void *)pdev->map.map_priv_1);
+		kfree(pdev->name);
+		kfree(pdev);
+		return(-ENXIO);
+	}
+
+	list_add(&pdev->list, &device_list);
+
+	pdev->mtd->module = THIS_MODULE;
+
+	add_mtd_device(pdev->mtd);
+	return(0);
+}
+
+static int __init uflash_init(void)
+{
+	struct linux_ebus *ebus = NULL;
+	struct linux_ebus_device *edev = NULL;
+
+	for_each_ebus(ebus) {
+		for_each_ebusdev(edev, ebus) {
+			if (!strcmp(edev->prom_name, UFLASH_OBPNAME)) {
+				if(0 > prom_getproplen(edev->prom_node, "user")) {
+					DEBUG(2, "%s: ignoring device at 0x%lx\n",
+							UFLASH_DEVNAME, edev->resource[0].start);
+				} else {
+					uflash_devinit(edev);
+				}
+			}
+		}
+	}
+
+	if(list_empty(&device_list)) {
+		printk("%s: unable to locate device\n", UFLASH_DEVNAME);
+		return -ENODEV;
+	}
+	return(0);
+}
+
+static void __exit uflash_cleanup(void)
+{
+	struct list_head *udevlist;
+	struct uflash_dev *udev;
+
+	list_for_each(udevlist, &device_list) {
+		udev = list_entry(udevlist, struct uflash_dev, list);
+		DEBUG(2, "%s: removing device %s\n", 
+			UFLASH_DEVNAME, udev->name);
+
+		if(0 != udev->mtd) {
+			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->name) {
+			kfree(udev->name);
+		}
+		kfree(udev);
+	}	
+}
+
+module_init(uflash_init);
+module_exit(uflash_cleanup);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/maps/vmax301.c linux/drivers/mtd/maps/vmax301.c
--- v2.4.5/linux/drivers/mtd/maps/vmax301.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/vmax301.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,240 @@
+// $Id: vmax301.c,v 1.22 2001/06/02 14:30:44 dwmw2 Exp $
+/* ######################################################################
+
+   Tempustech VMAX SBC301 MTD Driver.
+  
+   The VMAx 301 is a SBC based on . It
+   comes with three builtin AMD 29F016B flash chips and a socket for SRAM or
+   more flash. Each unit has it's own 8k mapping into a settable region 
+   (0xD8000). There are two 8k mappings for each MTD, the first is always set
+   to the lower 8k of the device the second is paged. Writing a 16 bit page
+   value to anywhere in the first 8k will cause the second 8k to page around.
+
+   To boot the device a bios extension must be installed into the first 8k 
+   of flash that is smart enough to copy itself down, page in the rest of 
+   itself and begin executing.
+   
+   ##################################################################### */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+
+#include <linux/mtd/map.h>
+
+
+#define WINDOW_START 0xd8000
+#define WINDOW_LENGTH 0x2000
+#define WINDOW_SHIFT 25
+#define WINDOW_MASK 0x1FFF
+
+/* Actually we could use two spinlocks, but we'd have to have
+   more private space in the struct map_info. We lose a little
+   performance like this, but we'd probably lose more by having
+   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 void __vmax301_page(struct map_info *map, unsigned long page)
+{
+	writew(page, map->map_priv_2 - WINDOW_LENGTH);
+	map->map_priv_1 = page;
+}
+
+static inline void vmax301_page(struct map_info *map,
+				  unsigned long ofs)
+{
+	unsigned long page = (ofs >> WINDOW_SHIFT);
+	if (map->map_priv_1 != page)
+		__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)
+{
+	__u32 ret;
+	spin_lock(&vmax301_spin);
+	vmax301_page(map, ofs);
+	ret =  readl(map->map_priv_2 + (ofs & WINDOW_MASK));
+	spin_unlock(&vmax301_spin);
+	return ret;
+}
+
+static void vmax301_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	while(len) {
+		unsigned long thislen = len;
+		if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
+			thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
+		spin_lock(&vmax301_spin);
+		vmax301_page(map, from);
+		memcpy_fromio(to, map->map_priv_2 + from, thislen);
+		spin_unlock(&vmax301_spin);
+		to += thislen;
+		from += thislen;
+		len -= thislen;
+	}
+}
+
+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)
+{
+	spin_lock(&vmax301_spin);
+	vmax301_page(map, adr);
+	writel(d, map->map_priv_2 + (adr & WINDOW_MASK));
+	spin_unlock(&vmax301_spin);
+}
+
+static void vmax301_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	while(len) {
+		unsigned long thislen = len;
+		if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
+			thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
+
+		spin_lock(&vmax301_spin);
+		vmax301_page(map, to);
+		memcpy_toio(map->map_priv_2 + to, from, thislen);
+		spin_unlock(&vmax301_spin);		
+		to += thislen;
+		from += thislen;
+		len -= thislen;
+	}
+}
+
+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 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
+	}
+};
+
+static struct mtd_info *vmax_mtd[2] = {NULL, NULL};
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_vmax301 init_module
+#define cleanup_vmax301 cleanup_module
+#endif
+
+static void __exit cleanup_vmax301(void)
+{
+	int i;
+	
+	for (i=0; i<2; i++) {
+		if (vmax_mtd[i]) {
+			del_mtd_device(vmax_mtd[i]);
+			map_destroy(vmax_mtd[i]);
+		}
+	}
+	iounmap((void *)vmax_map[0].map_priv_1 - WINDOW_START);
+}
+
+int __init init_vmax301(void)
+{
+	int i;
+	unsigned long iomapadr;
+	// Print out our little header..
+	printk("Tempustech VMAX 301 MEM:0x%x-0x%x\n",WINDOW_START,
+	       WINDOW_START+4*WINDOW_LENGTH);
+
+	iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH*4);
+	if (!iomapadr) {
+		printk("Failed to ioremap memory region\n");
+		return -EIO;
+	}
+	/* Put the address in the map's private data area.
+	   We store the actual MTD IO address rather than the 
+	   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);
+	
+	for (i=0; i<2; i++) {
+		vmax_mtd[i] = do_map_probe("cfi", &vmax_map[i]);
+		if (!vmax_mtd[i])
+			vmax_mtd[i] = do_map_probe("jedec", &vmax_map[i]);
+		if (!vmax_mtd[i])
+			vmax_mtd[i] = do_map_probe("ram", &vmax_map[i]);
+		if (!vmax_mtd[i])
+			vmax_mtd[i] = do_map_probe("rom", &vmax_map[i]);
+		if (vmax_mtd[i]) {
+			vmax_mtd[i]->module = THIS_MODULE;
+			add_mtd_device(vmax_mtd[i]);
+		}
+	}
+
+	if (!vmax_mtd[1] && !vmax_mtd[2]) {
+		iounmap((void *)iomapadr);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+module_init(init_vmax301);
+module_exit(cleanup_vmax301);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/mixmem.c linux/drivers/mtd/mixmem.c
--- v2.4.5/linux/drivers/mtd/mixmem.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/mixmem.c	Wed Dec 31 16:00:00 1969
@@ -1,151 +0,0 @@
-/* 
- * mixmem - a block device driver for flash rom found on the 
- *          piggyback board of the multi-purpose mixcom card
- *
- * Author: Gergely Madarasz <gorgo@itc.hu> 
- *
- * Copyright (c) 1999 ITConsult-Pro Co. <info@itc.hu>
- *
- * This code is GPL
- *
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <asm/io.h>
-#include <linux/init.h>
-#include <linux/mtd/mapped.h>
-
-#define MIXCOM_ID_OFFSET 0xc10
-#define MIXCOM_PAGE_OFFSET 0xc11
-#define MIXCOM_ID_1 0x11
-#define MIXCOM_ID_2 0x13
-#define MIXMEM_PAGESIZE 4096
-#define FIRST_BLOCK_OFFSET 0x1000
-
-#if LINUX_VERSION_CODE < 0x20300
-#define __exit
-#endif
-
-static unsigned int mixmem_addrs[] = { 0xc8000, 0xd8000, 0 };
-static unsigned int mixcom_ports[] = { 0x180, 0x280, 0x380, 0 };
-
-// We could store these in the mtd structure, but we only support 1 device..
-static unsigned long base_io = 0;
-static unsigned long base_addr = 0;
-static struct mapped_mtd_info *SSD;
-
-static unsigned long mixmem_page(struct mapped_mtd_info *map,
-				 unsigned long page)
-{
-	outb((char)(page & 0xff), base_io+MIXCOM_PAGE_OFFSET);
-	outb((char)((page >> 8) & 0x7), base_io+MIXCOM_PAGE_OFFSET+1);
-   	return base_addr;
-}
-
-static int flash_probe(int base)
-{
-	int prev,curr;
-	unsigned long flags;
-
-	writeb(0xf0, base);
-	save_flags(flags); cli();
-	
-	prev=readw(base);
-
-	writeb(0xaa, base+0x555);
-	writeb(0x55, base+0x2AA);
-	writeb(0x90, base+0x555);
-	
-	curr=readw(base);
-	
-	restore_flags(flags);
-	writeb(0xf0, base);
-	return(prev==curr?0:curr);
-}
-
-static int mixmem_probe(void) 
-{
-	int i;
-	int id;
-	int chip;
-	
-        /* This should really check to see if the io ports are in use before
-           writing to them */
-	for(i=0;mixcom_ports[i]!=0;i++) {
-		id=inb(mixcom_ports[i]+MIXCOM_ID_OFFSET);
-		if(id==MIXCOM_ID_1 || id==MIXCOM_ID_2) {
-			printk("mixmem: mixcom board found at 0x%3x\n",mixcom_ports[i]);
-			break;
-		}
-	}
-	
-	if(mixcom_ports[i]==0) {
-		printk("mixmem: no mixcom board found\n");
-		return -ENODEV;
-	}
-	
-	if (check_region(mixcom_ports[i]+MIXCOM_PAGE_OFFSET, 2)) return -EAGAIN;
-
-	
-	
-	// What is the deal with first_block_offset?
-	for(i=0;mixmem_addrs[i]!=0;i++) {
-		chip=flash_probe(mixmem_addrs[i]+FIRST_BLOCK_OFFSET);
-		if(chip)break;
-	}
-	
-	if(mixmem_addrs[i]==0) {
-		printk("mixmem: no flash available\n");
-		return -ENODEV;
-	}
-        base_io = mixcom_ports[i];
-        base_addr = mixmem_addrs[i];
-	request_region(mixcom_ports[i]+MIXCOM_PAGE_OFFSET, 2, "mixmem");
-        return 0;
-}
-
-
-static void __exit cleanup_mixmem()
-{
-	mtd_mapped_remove(SSD);
-	kfree(SSD);
-	SSD = 0;
-	release_region(base_io+MIXCOM_PAGE_OFFSET, 2);
-}
-
-//static int __init init_mixmem(void)
-int __init init_mixmem(void)
-{   
-   if (mixmem_probe() != 0)
-      return -EAGAIN;
-
-   // Print out our little header..
-   printk("mixcom MTD IO:0x%lx MEM:0x%lx-0x%lx\n",base_io,base_addr,
-	  base_addr+MIXMEM_PAGESIZE);
-   
-   // Allocate some memory
-   SSD = (struct mapped_mtd_info *)kmalloc(sizeof(*SSD),GFP_KERNEL);
-   if (SSD == 0)
-      return 0;   
-   memset(SSD,0,sizeof(*SSD));
-
-   // Setup the MTD structure
-   SSD->page = mixmem_page;
-   SSD->pagesize = MIXMEM_PAGESIZE;
-   SSD->maxsize = 0x7FF;
-   SSD->mtd.name = "mixcom piggyback";
-
-   // Setup the MTD, this will sense the flash parameters and so on..
-   if (mtd_mapped_setup(SSD) != 0)
-   {
-      printk("Failed to register new device\n");
-      cleanup_module();
-      return -EAGAIN;
-   }
-
-   return 0;
-}
-module_init(init_mixmem);
-module_exit(cleanup_mixmem);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/mtdblock_ro.c linux/drivers/mtd/mtdblock_ro.c
--- v2.4.5/linux/drivers/mtd/mtdblock_ro.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/mtdblock_ro.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,289 @@
+/*
+ * $Id: mtdblock_ro.c,v 1.5 2001/06/10 01:41:53 dwmw2 Exp $
+ *
+ * Read-only version of the mtdblock device, without the 
+ * read/erase/modify/writeback stuff
+ */
+
+#ifdef MTDBLOCK_DEBUG
+#define DEBUGLVL debug
+#endif							       
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include <linux/mtd/mtd.h>
+
+#define MAJOR_NR MTD_BLOCK_MAJOR
+#define DEVICE_NAME "mtdblock"
+#define DEVICE_REQUEST mtdblock_request
+#define DEVICE_NR(device) (device)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+#define DEVICE_NO_RANDOM
+#include <linux/blk.h>
+
+#if LINUX_VERSION_CODE < 0x20300
+#define RQFUNC_ARG void
+#define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0)
+#else
+#define RQFUNC_ARG request_queue_t *q
+#endif
+
+#ifdef MTDBLOCK_DEBUG
+static int debug = MTDBLOCK_DEBUG;
+MODULE_PARM(debug, "i");
+#endif
+
+
+static int mtd_sizes[MAX_MTD_DEVICES];
+
+
+static int mtdblock_open(struct inode *inode, struct file *file)
+{
+	struct mtd_info *mtd = NULL;
+
+	int dev;
+
+	DEBUG(1,"mtdblock_open\n");
+	
+	if (inode == 0)
+		return -EINVAL;
+	
+	dev = MINOR(inode->i_rdev);
+	
+	MOD_INC_USE_COUNT;
+
+	mtd = get_mtd_device(NULL, dev);
+
+	if (!mtd) {
+		MOD_DEC_USE_COUNT;
+		return -ENODEV;
+	}
+
+	mtd_sizes[dev] = mtd->size>>9;
+
+	DEBUG(1, "ok\n");
+
+	return 0;
+}
+
+static release_t mtdblock_release(struct inode *inode, struct file *file)
+{
+	int dev;
+	struct mtd_info *mtd;
+
+   	DEBUG(1, "mtdblock_release\n");
+
+	if (inode == NULL)
+		release_return(-ENODEV);
+   
+	invalidate_device(inode->i_rdev, 1);
+
+	dev = MINOR(inode->i_rdev);
+	mtd = __get_mtd_device(NULL, dev);
+
+	if (!mtd) {
+		printk(KERN_WARNING "MTD device is absent on mtd_release!\n");
+		MOD_DEC_USE_COUNT;
+		release_return(-ENODEV);
+	}
+	
+	if (mtd->sync)
+		mtd->sync(mtd);
+
+	put_mtd_device(mtd);
+
+	DEBUG(1, "ok\n");
+
+	MOD_DEC_USE_COUNT;
+	release_return(0);
+}  
+
+
+static void mtdblock_request(RQFUNC_ARG)
+{
+   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->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->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->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->nr_sectors);
+	 */
+
+	 // Read only device
+	 if ((mtd->flags & MTD_CAP_RAM) == 0)
+	 {
+	    res = 0;
+	    break;
+	 }
+
+	 // Do the write
+	 if (MTD_WRITE(mtd,current_request->sector<<9, 
+		       current_request->nr_sectors << 9, 
+		       &retlen, current_request->buffer) == 0)
+	    res = 1;
+	 else
+	    res = 0;
+	 break;
+	 
+	 // Shouldn't happen
+	 default:
+	 printk("mtd: unknown request\n");
+	 break;
+      }
+
+      // 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);
+   }
+}
+
+
+
+static int mtdblock_ioctl(struct inode * inode, struct file * file,
+		      unsigned int cmd, unsigned long arg)
+{
+	struct mtd_info *mtd;
+
+	mtd = __get_mtd_device(NULL, MINOR(inode->i_rdev));
+
+	if (!mtd) return -EINVAL;
+
+	switch (cmd) {
+	case BLKGETSIZE:   /* Return device size */
+		if (!arg)  return -EFAULT;
+		return Put_user((mtd->size >> 9),
+                                (long *) arg);
+		
+	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;
+	}
+}
+
+#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 = 
+{
+	open: mtdblock_open,
+	release: mtdblock_release,
+	ioctl: mtdblock_ioctl
+};
+#endif
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_mtdblock init_module
+#define cleanup_mtdblock cleanup_module
+#endif
+
+int __init init_mtdblock(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;
+	
+#if LINUX_VERSION_CODE < 0x20320
+	blk_dev[MAJOR_NR].request_fn = mtdblock_request;
+#else
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request);
+#endif
+	return 0;
+}
+
+static void __exit cleanup_mtdblock(void)
+{
+	unregister_blkdev(MAJOR_NR,DEVICE_NAME);
+}
+
+module_init(init_mtdblock);
+module_exit(cleanup_mtdblock);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/mtdchar.c linux/drivers/mtd/mtdchar.c
--- v2.4.5/linux/drivers/mtd/mtdchar.c	Mon May 21 17:06:29 2001
+++ linux/drivers/mtd/mtdchar.c	Tue Jun 12 10:30:27 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdchar.c,v 1.21.2.3 2001/01/09 00:18:31 dwmw2 Exp $
+ * $Id: mtdchar.c,v 1.38.2.1 2001/06/09 17:31:16 dwmw2 Exp $
  *
  * Character-device access to raw MTD devices.
  *
@@ -7,7 +7,6 @@
 
 
 #include <linux/mtd/compatmac.h>
-
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -18,21 +17,18 @@
 #include <linux/devfs_fs_kernel.h>
 static void mtd_notify_add(struct mtd_info* mtd);
 static void mtd_notify_remove(struct mtd_info* mtd);
+
 static struct mtd_notifier notifier = {
-	mtd_notify_add,
-	mtd_notify_remove,
-	NULL
+	add:	mtd_notify_add,
+	remove:	mtd_notify_remove,
 };
-static devfs_handle_t devfs_dir_handle = NULL;
+
+static devfs_handle_t devfs_dir_handle;
 static devfs_handle_t devfs_rw_handle[MAX_MTD_DEVICES];
 static devfs_handle_t devfs_ro_handle[MAX_MTD_DEVICES];
 #endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
 static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
-#else
-static int mtd_lseek (struct inode *inode, struct file *file, off_t offset, int orig)
-#endif
 {
 	struct mtd_info *mtd=(struct mtd_info *)file->private_data;
 
@@ -119,15 +115,18 @@
 #define FILE_POS file->f_pos
 #endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+/* FIXME: This _really_ needs to die. In 2.5, we should lock the
+   userspace buffer down and use it directly with readv/writev.
+*/
+#define MAX_KMALLOC_SIZE 0x20000
+
 static ssize_t mtd_read(struct file *file, char *buf, size_t count,loff_t *ppos)
-#else
-static int mtd_read(struct inode *inode,struct file *file, char *buf, int count)
-#endif
 {
 	struct mtd_info *mtd = (struct mtd_info *)file->private_data;
 	size_t retlen=0;
+	size_t total_retlen=0;
 	int ret=0;
+	int len;
 	char *kbuf;
 	
 	DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n");
@@ -138,39 +137,50 @@
 	if (!count)
 		return 0;
 	
-	/* FIXME: Use kiovec in 2.3 or 2.2+rawio, or at
-	 * least split the IO into smaller chunks.
-	 */
-	
-	kbuf = vmalloc(count);
-	if (!kbuf)
-		return -ENOMEM;
-	
-	ret = MTD_READ(mtd, FILE_POS, count, &retlen, kbuf);
-	if (!ret) {
-		FILE_POS += retlen;
-		if (copy_to_user(buf, kbuf, retlen))
-			ret = -EFAULT;
+	/* FIXME: Use kiovec in 2.5 to lock down the user's buffers
+	   and pass them directly to the MTD functions */
+	while (count) {
+		if (count > MAX_KMALLOC_SIZE) 
+			len = MAX_KMALLOC_SIZE;
 		else
-			ret = retlen;
+			len = count;
 
+		kbuf=kmalloc(len,GFP_KERNEL);
+		if (!kbuf)
+			return -ENOMEM;
+		
+		ret = MTD_READ(mtd, FILE_POS, len, &retlen, kbuf);
+		if (!ret) {
+			FILE_POS += retlen;
+			if (copy_to_user(buf, kbuf, retlen)) {
+			        kfree(kbuf);
+				return -EFAULT;
+			}
+			else
+				total_retlen += retlen;
+
+			count -= retlen;
+			buf += retlen;
+		}
+		else {
+			kfree(kbuf);
+			return ret;
+		}
+		
+		kfree(kbuf);
 	}
 	
-	vfree(kbuf);
-	
-	return ret;
+	return total_retlen;
 } /* mtd_read */
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
 static ssize_t mtd_write(struct file *file, const char *buf, size_t count,loff_t *ppos)
-#else
-static read_write_t mtd_write(struct inode *inode,struct file *file, const char *buf, count_t count)
-#endif
 {
 	struct mtd_info *mtd = (struct mtd_info *)file->private_data;
 	char *kbuf;
 	size_t retlen;
+	size_t total_retlen=0;
 	int ret=0;
+	int len;
 
 	DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n");
 	
@@ -183,27 +193,39 @@
 	if (!count)
 		return 0;
 
-	kbuf=vmalloc(count);
+	while (count) {
+		if (count > MAX_KMALLOC_SIZE) 
+			len = MAX_KMALLOC_SIZE;
+		else
+			len = count;
 
-	if (!kbuf)
-		return -ENOMEM;
-	
-	if (copy_from_user(kbuf, buf, count)) {
-		vfree(kbuf);
-		return -EFAULT;
-	}
-		
+		kbuf=kmalloc(len,GFP_KERNEL);
+		if (!kbuf) {
+			printk("kmalloc is null\n");
+			return -ENOMEM;
+		}
 
-	ret = (*(mtd->write))(mtd, FILE_POS, count, &retlen, buf);
+		if (copy_from_user(kbuf, buf, len)) {
+			kfree(kbuf);
+			return -EFAULT;
+		}
 		
-	if (!ret) {
-		FILE_POS += retlen;
-		ret = retlen;
+	        ret = (*(mtd->write))(mtd, FILE_POS, len, &retlen, kbuf);
+		if (!ret) {
+			FILE_POS += retlen;
+			total_retlen += retlen;
+			count -= retlen;
+			buf += retlen;
+		}
+		else {
+			kfree(kbuf);
+			return ret;
+		}
+		
+		kfree(kbuf);
 	}
 
-	vfree(kbuf);
-
-	return ret;
+	return total_retlen;
 } /* mtd_write */
 
 /*======================================================================
@@ -236,6 +258,30 @@
 	}
 	
 	switch (cmd) {
+	case MEMGETREGIONCOUNT:
+		if (copy_to_user((int *) arg, &(mtd->numeraseregions), sizeof(int)))
+			return -EFAULT;
+		break;
+
+	case MEMGETREGIONINFO:
+	{
+		struct region_info_user ur;
+
+		if (copy_from_user(	&ur, 
+					(struct region_info_user *)arg, 
+					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]),
+				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)))
@@ -317,7 +363,7 @@
 
 		ret = (mtd->write_oob)(mtd, buf.start, buf.length, &retlen, databuf);
 
-		if (copy_to_user((void *)arg + sizeof(loff_t), &retlen, sizeof(ssize_t)))
+		if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
 			ret = -EFAULT;
 
 		kfree(databuf);
@@ -351,7 +397,7 @@
 		
 		ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf);
 
-		if (copy_to_user((void *)arg + sizeof(loff_t), &retlen, sizeof(ssize_t)))
+		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 = -EFAULT;
@@ -371,6 +417,7 @@
 			ret = -EOPNOTSUPP;
 		else
 			ret = mtd->lock(mtd, adrs[0], adrs[1]);
+		break;
 	}
 
 	case MEMUNLOCK:
@@ -384,14 +431,15 @@
 			ret = -EOPNOTSUPP;
 		else
 			ret = mtd->unlock(mtd, adrs[0], adrs[1]);
+		break;
 	}
 
 		
 	default:
-	  printk("Invalid ioctl %x (MEMGETINFO = %x)\n",cmd, MEMGETINFO);
-		ret = -EINVAL;
+		DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %x)\n", cmd, MEMGETINFO);
+		ret = -ENOTTY;
 	}
-	
+
 	return ret;
 } /* memory_ioctl */
 
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/mtdcore.c linux/drivers/mtd/mtdcore.c
--- v2.4.5/linux/drivers/mtd/mtdcore.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/mtdcore.c	Tue Jun 12 10:30:27 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdcore.c,v 1.27 2000/12/10 01:10:09 dwmw2 Exp $
+ * $Id: mtdcore.c,v 1.30 2001/06/02 14:30:42 dwmw2 Exp $
  *
  * Core registration and callback routines for MTD
  * drivers and users.
@@ -258,8 +258,8 @@
 	if (!this)
 		return 0;
 
-	return sprintf(buf, "mtd%d: %8.8lx \"%s\"\n", i, this->size,
-		       this->name);
+	return sprintf(buf, "mtd%d: %8.8x %8.8x \"%s\"\n", i, this->size,
+		       this->erasesize, this->name);
 }
 
 static int mtd_read_proc ( char *page, char **start, off_t off,int count
@@ -270,11 +270,12 @@
 #endif
 			)
 {
-	int len = 0, l, i;
+	int len, l, i;
         off_t   begin = 0;
 
 	down(&mtd_table_mutex);
 
+	len = sprintf(page, "dev:    size   erasesize  name\n");
         for (i=0; i< MAX_MTD_DEVICES; i++) {
 
                 l = mtd_proc_info(page + len, i);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/mtdpart.c linux/drivers/mtd/mtdpart.c
--- v2.4.5/linux/drivers/mtd/mtdpart.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/mtdpart.c	Tue Jun 12 10:30:27 2001
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: mtdpart.c,v 1.7 2000/12/09 23:29:47 dwmw2 Exp $
+ * $Id: mtdpart.c,v 1.21 2001/06/09 16:33:32 dwmw2 Exp $
  */
 
 #include <linux/module.h>
@@ -25,7 +25,7 @@
 struct mtd_part {
 	struct mtd_info mtd;
 	struct mtd_info *master;
-	loff_t offset;
+	u_int32_t offset;
 	int index;
 	struct list_head list;
 };
@@ -100,15 +100,36 @@
 static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
 {
 	struct mtd_part *part = PART(mtd);
+	if ((len + ofs) > mtd->size) 
+		return -EINVAL;
 	return part->master->lock(part->master, ofs + part->offset, len);
 }
 
 static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
 {
 	struct mtd_part *part = PART(mtd);
+	if ((len + ofs) > mtd->size) 
+		return -EINVAL;
 	return part->master->unlock(part->master, ofs + part->offset, len);
 }
 
+static void part_sync(struct mtd_info *mtd)
+{
+	struct mtd_part *part = PART(mtd);
+	part->master->sync(part->master);
+}
+
+static int part_suspend(struct mtd_info *mtd)
+{
+	struct mtd_part *part = PART(mtd);
+	return part->master->suspend(part->master);
+}
+
+static void part_resume(struct mtd_info *mtd)
+{
+	struct mtd_part *part = PART(mtd);
+	part->master->resume(part->master);
+}
 
 /* 
  * This function unregisters and destroy all slave MTD objects which are 
@@ -130,14 +151,12 @@
 			del_mtd_device(&slave->mtd);
 			kfree(slave);
 			node = prev;
-			MOD_DEC_USE_COUNT;
 		}
 	}
 
 	return 0;
 }
 
-
 /*
  * This function, given a master MTD object and a partition table, creates
  * and registers slave MTD objects which are bound to the master according to
@@ -150,10 +169,13 @@
 		       int nbparts)
 {
 	struct mtd_part *slave;
-	u_long cur_offset = 0;
+	u_int32_t cur_offset = 0;
 	int i;
 
+	printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
+
 	for (i = 0; i < nbparts; i++) {
+
 		/* allocate the partition structure */
 		slave = kmalloc (sizeof(*slave), GFP_KERNEL);
 		if (!slave) {
@@ -162,63 +184,102 @@
 			del_mtd_partitions(master);
 			return -ENOMEM;
 		}
+		memset(slave, 0, sizeof(*slave));
 		list_add(&slave->list, &mtd_partitions);
 
 		/* set up the MTD object for this partition */
-		slave->mtd = *master;
-		slave->mtd.name = parts[i].name;
+		slave->mtd.type = master->type;
+		slave->mtd.flags = master->flags & ~parts[i].mask_flags;
 		slave->mtd.size = parts[i].size;
-		slave->mtd.flags &= ~parts[i].mask_flags;
+		slave->mtd.oobblock = master->oobblock;
+		slave->mtd.oobsize = master->oobsize;
+		slave->mtd.ecctype = master->ecctype;
+		slave->mtd.eccsize = master->eccsize;
+
+		slave->mtd.name = parts[i].name;
+		slave->mtd.bank_size = master->bank_size;
+
+		slave->mtd.module = master->module;
+
 		slave->mtd.read = part_read;
 		slave->mtd.write = part_write;
-		if (slave->mtd.writev)
+		slave->mtd.sync = part_sync;
+		if (!i && master->suspend && master->resume) {
+				slave->mtd.suspend = part_suspend;
+				slave->mtd.resume = part_resume;
+		}
+
+		if (master->writev)
 			slave->mtd.writev = part_writev;
-		if (slave->mtd.readv)
+		if (master->readv)
 			slave->mtd.readv = part_readv;
-		if (slave->mtd.lock)
+		if (master->lock)
 			slave->mtd.lock = part_lock;
-		if (slave->mtd.unlock)
+		if (master->unlock)
 			slave->mtd.unlock = part_unlock;
 		slave->mtd.erase = part_erase;
 		slave->master = master;
 		slave->offset = parts[i].offset;
 		slave->index = i;
 
-		if (slave->offset == 0)
+		if (slave->offset == MTDPART_OFS_APPEND)
 			slave->offset = cur_offset;
-		if (slave->mtd.size == 0)
+		if (slave->mtd.size == MTDPART_SIZ_FULL)
 			slave->mtd.size = master->size - slave->offset;
 		cur_offset = slave->offset + slave->mtd.size;
+	
+		printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, 
+			slave->offset + slave->mtd.size, slave->mtd.name);
 
 		/* let's do some sanity checks */
+		if (slave->offset >= master->size) {
+				/* let's register it anyway to preserve ordering */
+			slave->offset = 0;
+			slave->mtd.size = 0;
+			printk ("mtd: partition \"%s\" is out of reach -- disabled\n",
+				parts[i].name);
+		}
+		if (slave->offset + slave->mtd.size > master->size) {
+			slave->mtd.size = master->size - slave->offset;
+			printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n",
+				parts[i].name, master->name, slave->mtd.size);
+		}
+		if (master->numeraseregions>1) {
+			/* Deal with variable erase size stuff */
+			int i;
+			struct mtd_erase_region_info *regions = master->eraseregions;
+			
+			/* Find the first erase regions which is part of this partition. */
+			for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++)
+				;
+
+			for (i--; i < master->numeraseregions && slave->offset + slave->mtd.size > regions[i].offset; i++) {
+				if (slave->mtd.erasesize < regions[i].erasesize) {
+					slave->mtd.erasesize = regions[i].erasesize;
+				}
+			}
+		} else {
+			/* Single erase size */
+			slave->mtd.erasesize = master->erasesize;
+		}
+
 		if ((slave->mtd.flags & MTD_WRITEABLE) && 
-		    (parts[i].offset % master->erasesize)) {
+		    (slave->offset % slave->mtd.erasesize)) {
+			/* Doesn't start on a boundary of major erase size */
+			/* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
 			slave->mtd.flags &= ~MTD_WRITEABLE;
 			printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
-					parts[i].name);
+				parts[i].name);
 		}
 		if ((slave->mtd.flags & MTD_WRITEABLE) && 
-		    (parts[i].size % master->erasesize)) {
+		    (slave->mtd.size % slave->mtd.erasesize)) {
 			slave->mtd.flags &= ~MTD_WRITEABLE;
 			printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
-					parts[i].name);
-		}
-		if (parts[i].offset >= master->size) {
-			/* let's register it anyway to preserve ordering */
-			slave->offset = 0;
-			slave->mtd.size = 0;
-			printk ("mtd: partition \"%s\" is out of reach -- disabled\n",
-					parts[i].name);
-		}
-		if (parts[i].offset + parts[i].size > master->size) {
-			slave->mtd.size = master->size - parts[i].offset;
-			printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#lx\n",
-					parts[i].name, master->name, slave->mtd.size);
+				parts[i].name);
 		}
 
 		/* register our partition */
 		add_mtd_device(&slave->mtd);
-		MOD_INC_USE_COUNT;
 	}
 
 	return 0;
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/mtdram.c linux/drivers/mtd/mtdram.c
--- v2.4.5/linux/drivers/mtd/mtdram.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/mtdram.c	Wed Dec 31 16:00:00 1969
@@ -1,148 +0,0 @@
-/* 
- * mtdram - a test mtd device
- * $Id: mtdram.c,v 1.15 2000/07/13 12:40:46 scote1 Exp $
- * Author: Alexander Larsson <alex@cendio.se> 
- *
- * Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
- *
- * This code is GPL
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/mtd/compatmac.h>
-#include <linux/mtd/mtd.h>
-
-
-#define MTDRAM_TOTAL_SIZE (CONFIG_MTDRAM_TOTAL_SIZE * 1024)
-#define MTDRAM_ERASE_SIZE (CONFIG_MTDRAM_ERASE_SIZE * 1024)
-
-
-// We could store these in the mtd structure, but we only support 1 device..
-static struct mtd_info *mtd_info;
-
-
-static int
-ram_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-  if (instr->addr + instr->len > mtd->size)
-    return -EINVAL;
-	
-  memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
-  
-  instr->state = MTD_ERASE_DONE;
-
-  if (instr->callback)
-    (*(instr->callback))(instr);
-  return 0;
-}
-
-static int ram_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
-{
-  if (from + len > mtd->size)
-    return -EINVAL;
-  
-  *mtdbuf = mtd->priv + from;
-  *retlen = len;
-  return 0;
-}
-
-static void ram_unpoint (struct mtd_info *mtd, u_char *addr)
-{
-}
-
-static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
-	     size_t *retlen, u_char *buf)
-{
-  if (from + len > mtd->size)
-    return -EINVAL;
-
-  memcpy(buf, mtd->priv + from, len);
-
-  *retlen=len;
-  return 0;
-}
-
-static int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
-	      size_t *retlen, const u_char *buf)
-{
-  if (to + len > mtd->size)
-    return -EINVAL;
-  
-  memcpy ((char *)mtd->priv + to, buf, len);
-
-  *retlen=len;
-  return 0;
-}
-
-#if LINUX_VERSION_CODE < 0x20300
-#ifdef MODULE
-#define init_mtdram init_module
-#define cleanup_mtdram cleanup_module
-#endif
-#endif
-
-//static void __exit cleanup_mtdram(void)
-mod_exit_t cleanup_mtdram(void)
-{
-  if (mtd_info) {
-    del_mtd_device(mtd_info);
-    if (mtd_info->priv)
-      vfree(mtd_info->priv);
-    kfree(mtd_info);
-  }
-}
-
-extern struct module __this_module;
-
-mod_init_t init_mtdram(void)
-{
-   // Allocate some memory
-   mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-   if (mtd_info == 0)
-      return 0;
-   
-   memset(mtd_info, 0, sizeof(*mtd_info));
-
-   // Setup the MTD structure
-   mtd_info->name = "mtdram test device";
-   mtd_info->type = MTD_RAM;
-   mtd_info->flags = MTD_CAP_RAM;
-   mtd_info->size = MTDRAM_TOTAL_SIZE;
-   mtd_info->erasesize = MTDRAM_ERASE_SIZE;
-   mtd_info->priv = vmalloc(MTDRAM_TOTAL_SIZE);
-   memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-   mtd_info->module = THIS_MODULE;			
-#endif
-
-   if (!mtd_info->priv) {
-     kfree(mtd_info);
-     mtd_info = NULL;
-     return -ENOMEM;
-   }
-   mtd_info->erase = ram_erase;
-   mtd_info->point = ram_point;
-   mtd_info->unpoint = ram_unpoint;
-   mtd_info->read = ram_read;
-   mtd_info->write = ram_write;
-
-   if (add_mtd_device(mtd_info)) {
-     vfree(mtd_info->priv);
-     kfree(mtd_info);
-     mtd_info = NULL;
-     return -EIO;
-   }
-   
-   return 0;
-}
-
-#if LINUX_VERSION_CODE > 0x20300
-module_init(init_mtdram);
-module_exit(cleanup_mtdram);
-#endif
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/nand/Config.in linux/drivers/mtd/nand/Config.in
--- v2.4.5/linux/drivers/mtd/nand/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/nand/Config.in	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,16 @@
+# drivers/mtd/nand/Config.in
+
+# $Id: Config.in,v 1.1 2001/04/20 15:27:38 dwmw2 Exp $
+
+mainmenu_option next_comment
+
+comment 'NAND Flash Device Drivers'
+
+dep_tristate '  NAND Device Support' CONFIG_MTD_NAND $CONFIG_MTD
+if [ "$CONFIG_MTD_NAND" = "y" -o "$CONFIG_MTD_NAND" = "m" ]; then
+   bool '    Enable ECC correction algorithm'  CONFIG_MTD_NAND_ECC y
+   bool '    Verify NAND page writes' CONFIG_MTD_NAND_VERIFY_WRITE y
+fi
+dep_tristate '  NAND Flash device on SPIA board' CONFIG_MTD_NAND_SPIA $CONFIG_MTD_NAND
+
+endmenu
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/nand/Makefile linux/drivers/mtd/nand/Makefile
--- v2.4.5/linux/drivers/mtd/nand/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/nand/Makefile	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,14 @@
+#
+# linux/drivers/nand/Makefile
+#
+# $Id: Makefile,v 1.3 2001/04/19 23:54:48 dwmw2 Exp $
+
+O_TARGET	:= nandlink.o
+
+export-objs	:= nand.o
+
+obj-$(CONFIG_MTD_NAND)		+= nand.o
+obj-$(CONFIG_MTD_NAND_ECC)	+= nand_ecc.o
+obj-$(CONFIG_MTD_NAND_SPIA)	+= spia.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/nand/nand.c linux/drivers/mtd/nand/nand.c
--- v2.4.5/linux/drivers/mtd/nand/nand.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/nand/nand.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,1369 @@
+/*
+ *  drivers/mtd/nand.c
+ *
+ *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ *
+ * $Id: nand.c,v 1.10 2001/03/20 07:26:01 dwmw2 Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Overview:
+ *   This is the generic MTD driver for NAND flash devices. It should be
+ *   capable of working with almost all NAND chips currently available.
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ids.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_MTD_NAND_ECC
+#include <linux/mtd/nand_ecc.h>
+#endif
+
+/*
+ * Macros for low-level register control
+ */
+#define NAND_CTRL (*(volatile unsigned char *) \
+			((struct nand_chip *) mtd->priv)->CTRL_ADDR)
+#define nand_select()	NAND_CTRL &= ~this->NCE; \
+			nand_command(mtd, NAND_CMD_RESET, -1, -1); \
+			udelay (10);
+#define nand_deselect() NAND_CTRL |= ~this->NCE;
+
+/*
+ * NAND low-level MTD interface functions
+ */
+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 *ecc_code);
+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 *ecc_code);
+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 iovec *vecs,
+				unsigned long count, loff_t to, size_t *retlen);
+static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
+static void nand_sync (struct mtd_info *mtd);
+
+/*
+ * Send command to NAND device
+ */
+static void nand_command (struct mtd_info *mtd, unsigned command,
+				int column, int page_addr)
+{
+	register struct nand_chip *this = mtd->priv;
+	register unsigned long NAND_IO_ADDR = this->IO_ADDR;
+
+	/* Begin command latch cycle */
+	NAND_CTRL |= this->CLE;
+
+	/*
+	 * Write out the command to the device.
+	 */
+	if (command != NAND_CMD_SEQIN)	
+		writeb (command, NAND_IO_ADDR);
+	else {
+		if (mtd->oobblock == 256 && column >= 256) {
+			column -= 256;
+			writeb(NAND_CMD_RESET, NAND_IO_ADDR);
+			writeb(NAND_CMD_READOOB, NAND_IO_ADDR);
+			writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
+		}
+		else if (mtd->oobblock == 512 && column >= 256) {
+			if (column < 512) {
+				column -= 256;
+				writeb(NAND_CMD_READ1, NAND_IO_ADDR);
+				writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
+			}
+			else {
+				column -= 512;
+				writeb(NAND_CMD_READOOB, NAND_IO_ADDR);
+				writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
+			}
+		}
+		else {
+			writeb(NAND_CMD_READ0, NAND_IO_ADDR);
+			writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
+		}
+	}
+
+	/* Set ALE and clear CLE to start address cycle */
+	NAND_CTRL &= ~this->CLE;
+	NAND_CTRL |= this->ALE;
+
+	/* Serially input address */
+	if (column != -1)
+		writeb (column, NAND_IO_ADDR);
+	if (page_addr != -1) {
+		writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR);
+		writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR);
+		/* One more address cycle for higher density devices */
+		if (mtd->size & 0x0c000000) {
+			writeb ((unsigned char) ((page_addr >> 16) & 0x0f),
+					NAND_IO_ADDR);
+		}
+	}
+
+	/* Latch in address */
+	NAND_CTRL &= ~this->ALE;
+
+	/* Pause for 15us */
+	udelay (15);
+}
+
+/*
+ * NAND read
+ */
+static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
+			size_t *retlen, u_char *buf)
+{
+#ifdef CONFIG_MTD_NAND_ECC
+	struct nand_chip *this = mtd->priv;
+	
+	return nand_read_ecc (mtd, from, len, retlen, buf, this->ecc_code_buf);
+#else
+	return nand_read_ecc (mtd, from, len, retlen, buf, NULL);
+#endif
+}
+
+/*
+ * NAND read with ECC
+ */
+static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+				size_t *retlen, u_char *buf, u_char *ecc_code)
+{
+	int j, col, page, state;
+	int erase_state = 0;
+	struct nand_chip *this = mtd->priv;
+	DECLARE_WAITQUEUE(wait, current);
+#ifdef CONFIG_MTD_NAND_ECC
+	int ecc_result;
+	u_char ecc_calc[6];
+#endif
+
+	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 */
+retry:
+	spin_lock_bh (&this->chip_lock);
+
+	switch (this->state) {
+	case FL_READY:
+		this->state = FL_READING;
+		spin_unlock_bh (&this->chip_lock);
+		break;
+
+	case FL_ERASING:
+		this->state = FL_READING;
+		erase_state = 1;
+		spin_unlock_bh (&this->chip_lock);
+		break;
+
+	default:
+		set_current_state (TASK_UNINTERRUPTIBLE);
+		add_wait_queue (&this->wq, &wait);
+		spin_unlock_bh (&this->chip_lock);
+		schedule();
+
+		remove_wait_queue (&this->wq, &wait);
+		goto retry;
+	};
+
+	/* First we calculate the starting page */
+	page = from >> this->page_shift;
+
+	/* Get raw starting column */
+	col = from & (mtd->oobblock - 1);
+
+	/* State machine for devices having pages larger than 256 bytes */
+	state = (col < mtd->eccsize) ? 0 : 1;
+
+	/* Calculate column address within ECC block context */
+	col = (col >= mtd->eccsize) ? (col - mtd->eccsize) : col;
+
+	/* Initialize return value */
+	*retlen = 0;
+
+	/* Select the NAND device */
+	nand_select ();
+
+	/* Loop until all data read */
+	while (*retlen < len) {
+
+#ifdef CONFIG_MTD_NAND_ECC
+		/* Send the read command */
+		if (!state)
+			nand_command (mtd, NAND_CMD_READ0, 0x00, page);
+		else 
+			nand_command (mtd, NAND_CMD_READ1, 0x00, page);
+
+		/* Read in a block big enough for ECC */
+		for (j=0 ; j < mtd->eccsize ; j++)
+			this->data_buf[j] = readb (this->IO_ADDR);
+
+		/* Read in the out-of-band data */
+		if (!state) {
+			nand_command (mtd, NAND_CMD_READOOB, 0x00, page);
+			for (j=0 ; j<3 ; j++)
+				ecc_code[j] = readb(this->IO_ADDR);
+			nand_command (mtd, NAND_CMD_READ0, 0x00, page);
+		}
+		else {
+			nand_command (mtd, NAND_CMD_READOOB, 0x03, page);
+			for (j=3 ; j<6 ; j++)
+				ecc_code[j] = readb(this->IO_ADDR);
+			nand_command (mtd, NAND_CMD_READ0, 0x00, page);
+		}
+
+		/* Calculate the ECC and verify it */
+		if (!state) {
+			nand_calculate_ecc (&this->data_buf[0],
+						&ecc_calc[0]);
+			ecc_result = nand_correct_data (&this->data_buf[0],
+						&ecc_code[0], &ecc_calc[0]);
+		}
+		else {
+			nand_calculate_ecc (&this->data_buf[0],
+						&ecc_calc[3]);
+			ecc_result = nand_correct_data (&this->data_buf[0],
+						&ecc_code[3], &ecc_calc[3]);
+		}
+		if (ecc_result == -1) {
+			DEBUG (MTD_DEBUG_LEVEL0,
+				"nand_read_ecc: " \
+				"Failed ECC read, page 0x%08x\n", page);
+			nand_deselect ();
+			spin_lock_bh (&this->chip_lock);
+			if (erase_state)
+				this->state = FL_ERASING;
+			else
+				this->state = FL_READY;
+			wake_up (&this->wq);
+			spin_unlock_bh (&this->chip_lock);
+			return -EIO;
+		}
+
+		/* Read the data from ECC data buffer into return buffer */
+		if ((*retlen + (mtd->eccsize - col)) >= len) {
+			while (*retlen < len)
+				buf[(*retlen)++] = this->data_buf[col++];
+			/* We're done */
+			continue;
+		}
+		else
+			for (j=col ; j < mtd->eccsize ; j++)
+				buf[(*retlen)++] = this->data_buf[j];
+#else
+		/* Send the read command */
+		if (!state)
+			nand_command (mtd, NAND_CMD_READ0, col, page);
+		else 
+			nand_command (mtd, NAND_CMD_READ1, col, page);
+
+		/* Read the data directly into the return buffer */ 
+		if ((*retlen + (mtd->eccsize - col)) >= len) {
+			while (*retlen < len)
+				buf[(*retlen)++] = readb (this->IO_ADDR);
+			/* We're done */
+			continue;
+		}
+		else
+			for (j=col ; j < mtd->eccsize ; j++)
+				buf[(*retlen)++] = readb (this->IO_ADDR);
+#endif
+
+		/*
+		 * If the amount of data to be read is greater than
+		 * (256 - col), then all subsequent reads will take
+		 * place on page or half-page (in the case of 512 byte
+		 * page devices) aligned boundaries and the column
+		 * address will be zero. Setting the column address to
+		 * to zero after the first read allows us to simplify
+		 * the reading of data and the if/else statements above.
+		 */
+		if (col)
+			col = 0x00;
+
+		/* Increment page address */
+		if ((mtd->oobblock == 256) || state)
+			page++;
+
+		/* Toggle state machine */
+		if (mtd->oobblock == 512)
+			state = state ? 0 : 1;
+	}
+
+	/* De-select the NAND device */
+	nand_deselect ();
+
+	/* Wake up anyone waiting on the device */
+	spin_lock_bh (&this->chip_lock);
+	if (erase_state)
+		this->state = FL_ERASING;
+	else
+		this->state = FL_READY;
+	wake_up (&this->wq);
+	spin_unlock_bh (&this->chip_lock);
+	
+	/* Return happy */
+	return 0;
+}
+
+/*
+ * NAND read out-of-band
+ */
+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;
+	int erase_state = 0;
+	struct nand_chip *this = mtd->priv;
+	DECLARE_WAITQUEUE(wait, current);
+	
+	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;
+
+	/* Mask to get column */
+	col = from & 0x0f;
+
+	/* Initialize return length value */
+	*retlen = 0;
+
+	/* Do not allow read past end of page */
+	if ((col + len) > mtd->oobsize) {
+		DEBUG (MTD_DEBUG_LEVEL0,
+			"nand_read_oob: Attempt read past end of page " \
+			"0x%08x, column %i, length %i\n", page, col, len);
+		return -EINVAL;
+	}
+
+retry:
+	/* Grab the lock and see if the device is available */
+	spin_lock_bh (&this->chip_lock);
+
+	switch (this->state) {
+	case FL_READY:
+		this->state = FL_READING;
+		spin_unlock_bh (&this->chip_lock);
+		break;
+
+	case FL_ERASING:
+		this->state = FL_READING;
+		erase_state = 1;
+		spin_unlock_bh (&this->chip_lock);
+		break;
+
+	default:
+		set_current_state (TASK_UNINTERRUPTIBLE);
+		add_wait_queue (&this->wq, &wait);
+		spin_unlock_bh (&this->chip_lock);
+		schedule();
+
+		remove_wait_queue (&this->wq, &wait);
+		goto retry;
+	};
+
+	/* Select the NAND device */
+	nand_select ();
+
+	/* Send the read command */
+	nand_command (mtd, NAND_CMD_READOOB, col, page);	
+
+	/* Read the data */
+	for (i = 0 ; i < len ; i++)
+		buf[i] = readb (this->IO_ADDR);
+
+	/* De-select the NAND device */
+	nand_deselect ();
+
+	/* Wake up anyone waiting on the device */
+	spin_lock_bh (&this->chip_lock);
+	if (erase_state)
+		this->state = FL_ERASING;
+	else
+		this->state = FL_READY;
+	wake_up (&this->wq);
+	spin_unlock_bh (&this->chip_lock);
+
+	/* Return happy */
+	*retlen = len;
+	return 0;
+}
+
+/*
+ * NAND write
+ */
+static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
+			size_t *retlen, const u_char *buf)
+{
+#ifdef CONFIG_MTD_NAND_ECC
+	struct nand_chip *this = mtd->priv;
+	
+	return nand_write_ecc (mtd, to, len, retlen, buf, this->ecc_code_buf);
+#else
+	return nand_write_ecc (mtd, to, len, retlen, buf, NULL);
+#endif
+}
+
+/*
+ * 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 *ecc_code)
+{
+	int i, page, col, cnt, status;
+	struct nand_chip *this = mtd->priv;
+	DECLARE_WAITQUEUE(wait, current);
+#ifdef CONFIG_MTD_NAND_ECC
+	int ecc_bytes = (mtd->oobblock == 512) ? 6 : 3;
+#endif
+
+	DEBUG (MTD_DEBUG_LEVEL3,
+		"nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to,
+		(int) len);
+
+	/* Do not allow write past end of page */
+	if ((to + len) > mtd->size) {
+		DEBUG (MTD_DEBUG_LEVEL0,
+			"nand_write_ecc: Attempted write past end of device\n");
+		return -EINVAL;
+	}
+
+retry:
+	/* Grab the lock and see if the device is available */
+	spin_lock_bh (&this->chip_lock);
+
+	switch (this->state) {
+	case FL_READY:
+		this->state = FL_WRITING;
+		spin_unlock_bh (&this->chip_lock);
+		break;
+
+	default:
+		set_current_state (TASK_UNINTERRUPTIBLE);
+		add_wait_queue (&this->wq, &wait);
+		spin_unlock_bh (&this->chip_lock);
+		schedule();
+
+		remove_wait_queue (&this->wq, &wait);
+		goto retry;
+	};
+
+	/* Shift to get page */
+	page = ((int) to) >> this->page_shift;
+
+	/* Get the starting column */
+	col = to & (mtd->oobblock - 1);
+
+	/* Initialize return length value */
+	*retlen = 0;
+
+	/* Select the NAND device */
+	nand_select ();
+
+	/* Check the WP bit */
+	nand_command (mtd, NAND_CMD_STATUS, -1, -1);
+	if (!(readb (this->IO_ADDR) & 0x80)) {
+		DEBUG (MTD_DEBUG_LEVEL0,
+			"nand_write_ecc: Device is write protected!!!\n");
+		nand_deselect ();
+		spin_lock_bh (&this->chip_lock);
+		this->state = FL_READY;
+		wake_up (&this->wq);
+		spin_unlock_bh (&this->chip_lock);
+		return -EIO;
+	}
+
+	/* Loop until all data is written */
+	while (*retlen < len) {
+		/* Write data into buffer */
+		if ((col + len) >= mtd->oobblock)
+			for(i=col, cnt=0 ; i < mtd->oobblock ; i++, cnt++)
+				this->data_buf[i] = buf[(*retlen + cnt)];
+		else
+			for(i=col, cnt=0 ; cnt < (len - *retlen) ; i++, cnt++)
+				this->data_buf[i] = buf[(*retlen + cnt)];
+		
+#ifdef CONFIG_MTD_NAND_ECC
+		/* Zero out the ECC array */
+		for (i=0 ; i < 6 ; i++)
+			ecc_code[i] = 0x00;
+
+		/* Calculate and write the ECC if we have enough data */
+		if ((col < mtd->eccsize) &&
+			((col + (len - *retlen)) >= mtd->eccsize)) {
+			nand_command (mtd, NAND_CMD_READ0, col, page);
+			for (i=0 ; i < col ; i++)
+				this->data_buf[i] = readb (this->IO_ADDR); 
+			nand_calculate_ecc (&this->data_buf[0], &ecc_code[0]);
+			for (i=0 ; i<3 ; i++)
+				this->data_buf[(mtd->oobblock + i)] =
+					ecc_code[i];
+		}
+
+		/* Calculate and write the second ECC if we have enough data */
+		if ((mtd->oobblock == 512) &&
+			((col + (len - *retlen)) >= mtd->oobblock)) {
+			nand_calculate_ecc (&this->data_buf[256], &ecc_code[3]);
+			for (i=3 ; i<6 ; i++)
+				this->data_buf[(mtd->oobblock + i)] =
+					ecc_code[i];
+		}
+
+		/* Write ones for partial page programming */
+		for (i=ecc_bytes ; i < mtd->oobsize ; i++)
+			this->data_buf[(mtd->oobblock + i)] = 0xff;
+#else
+		/* Write ones for partial page programming */
+		for (i=mtd->oobblock ; i < (mtd->oobblock + mtd->oobsize) ; i++)
+			this->data_buf[i] = 0xff;
+#endif
+
+		/* Write pre-padding bytes into buffer */
+		for (i=0 ; i < col ; i++)
+			this->data_buf[i] = 0xff;
+
+		/* Write post-padding bytes into buffer */
+		if ((col + (len - *retlen)) < mtd->oobblock) {
+			for(i=(col + cnt) ; i < mtd->oobblock ; i++)
+				this->data_buf[i] = 0xff;
+		}
+
+		/* Send command to begin auto page programming */
+		nand_command (mtd, NAND_CMD_SEQIN, 0x00, page);
+
+		/* Write out complete page of data */
+		for (i=0 ; i < (mtd->oobblock + mtd->oobsize) ; i++)
+			writeb (this->data_buf[i], this->IO_ADDR);
+
+		/* Send command to actually program the data */
+		nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+		/*
+		 * Wait for program operation to complete. This could
+		 * take up to 3000us (3ms) on some devices, so we try
+		 * and exit as quickly as possible.
+		 */
+		status = 0;
+		for (i=0 ; i<24 ; i++) {
+			/* Delay for 125us */
+			udelay (125);
+
+			/* Check the status */
+			nand_command (mtd, NAND_CMD_STATUS, -1, -1);
+			status = (int) readb (this->IO_ADDR);
+			if (status & 0x40)
+				break;
+		}
+
+		/* See if device thinks it succeeded */
+		if (status & 0x01) {
+			DEBUG (MTD_DEBUG_LEVEL0,
+				"nand_write_ecc: " \
+				"Failed write, page 0x%08x, " \
+				"%6i bytes were succesful\n", page, *retlen);
+			nand_deselect ();
+			spin_lock_bh (&this->chip_lock);
+			this->state = FL_READY;
+			wake_up (&this->wq);
+			spin_unlock_bh (&this->chip_lock);
+			return -EIO;
+		}
+
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+		/*
+		 * 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.
+		 */
+		
+		/* Send command to read back the page */
+		if (col < mtd->eccsize)
+			nand_command (mtd, NAND_CMD_READ0, col, page);
+		else
+			nand_command (mtd, NAND_CMD_READ1, col - 256, page);
+
+		/* Loop through and verify the data */
+		for (i=col ; i < cnt ; i++) {
+			if (this->data_buf[i] != readb (this->IO_ADDR)) {
+				DEBUG (MTD_DEBUG_LEVEL0,
+					"nand_write_ecc: " \
+					"Failed write verify, page 0x%08x, " \
+					"%6i bytes were succesful\n",
+					page, *retlen);
+				nand_deselect ();
+				spin_lock_bh (&this->chip_lock);
+				this->state = FL_READY;
+				wake_up (&this->wq);
+				spin_unlock_bh (&this->chip_lock);
+				return -EIO;
+			}
+		}
+
+#ifdef CONFIG_MTD_NAND_ECC
+		/*
+		 * We also want to check that the ECC bytes wrote
+		 * correctly for the same reasons stated above.
+		 */
+		nand_command (mtd, NAND_CMD_READOOB, 0x00, page);
+		for (i=0 ; i < ecc_bytes ; i++) {
+			if ((readb (this->IO_ADDR) != ecc_code[i]) &&
+					ecc_code[i]) {
+				DEBUG (MTD_DEBUG_LEVEL0,
+					"nand_write_ecc: Failed ECC write " \
+					"verify, page 0x%08x, " \
+					"%6i bytes were succesful\n",
+					page, i);
+				nand_deselect ();
+				spin_lock_bh (&this->chip_lock);
+				this->state = FL_READY;
+				wake_up (&this->wq);
+				spin_unlock_bh (&this->chip_lock);
+				return -EIO;
+			}
+		}
+#endif
+
+#endif
+
+		/*
+		 * If we are writing a large amount of data and/or it
+		 * crosses page or half-page boundaries, we set the
+		 * the column to zero. It simplifies the program logic.
+		 */
+		if (col)
+			col = 0x00;
+
+		/* Update written bytes count */
+		*retlen += cnt;
+
+		/* Increment page address */
+		page++;
+	}
+
+	/* De-select the NAND device */
+	nand_deselect ();
+
+	/* Wake up anyone waiting on the device */
+	spin_lock_bh (&this->chip_lock);
+	this->state = FL_READY;
+	wake_up (&this->wq);
+	spin_unlock_bh (&this->chip_lock);
+
+	/* Return happy */
+	*retlen = len;
+	return 0;
+}
+
+/*
+ * 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 i, column, page, status;
+	struct nand_chip *this = mtd->priv;
+	DECLARE_WAITQUEUE(wait, current);
+	
+	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;
+
+	/* Mask to get column */
+	column = to & 0x1f;
+
+	/* 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;
+	}
+
+retry:
+	/* Grab the lock and see if the device is available */
+	spin_lock_bh (&this->chip_lock);
+
+	switch (this->state) {
+	case FL_READY:
+		this->state = FL_WRITING;
+		spin_unlock_bh (&this->chip_lock);
+		break;
+
+	default:
+		set_current_state (TASK_UNINTERRUPTIBLE);
+		add_wait_queue (&this->wq, &wait);
+		spin_unlock_bh (&this->chip_lock);
+		schedule();
+
+		remove_wait_queue (&this->wq, &wait);
+		goto retry;
+	};
+
+	/* Select the NAND device */
+	nand_select ();
+
+	/* Check the WP bit */
+	nand_command (mtd, NAND_CMD_STATUS, -1, -1);
+	if (!(readb (this->IO_ADDR) & 0x80)) {
+		DEBUG (MTD_DEBUG_LEVEL0,
+			"nand_write_oob: Device is write protected!!!\n");
+		nand_deselect ();
+		spin_lock_bh (&this->chip_lock);
+		this->state = FL_READY;
+		wake_up (&this->wq);
+		spin_unlock_bh (&this->chip_lock);
+		return -EIO;
+	}
+
+	/* Write out desired data */
+	nand_command (mtd, NAND_CMD_SEQIN, column + 512, page);
+	for (i=0 ; i<len ; i++)
+		writeb (buf[i], this->IO_ADDR);
+
+	/* Send command to program the OOB data */
+	nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+	/*
+	 * Wait for program operation to complete. This could
+	 * take up to 3000us (3ms) on some devices, so we try
+	 * and exit as quickly as possible.
+	 */
+	status = 0;
+	for (i=0 ; i<24 ; i++) {
+		/* Delay for 125us */
+		udelay (125);
+
+		/* Check the status */
+		nand_command (mtd, NAND_CMD_STATUS, -1, -1);
+		status = (int) readb (this->IO_ADDR);
+		if (status & 0x40)
+			break;
+	}
+
+	/* See if device thinks it succeeded */
+	if (status & 0x01) {
+		DEBUG (MTD_DEBUG_LEVEL0,
+			"nand_write_oob: " \
+			"Failed write, page 0x%08x\n", page);
+		nand_deselect ();
+		spin_lock_bh (&this->chip_lock);
+		this->state = FL_READY;
+		wake_up (&this->wq);
+		spin_unlock_bh (&this->chip_lock);
+		return -EIO;
+	}
+
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+	/* Send command to read back the data */
+	nand_command (mtd, NAND_CMD_READOOB, column, page);
+
+	/* Loop through and verify the data */
+	for (i=0 ; i<len ; i++) {
+		if (buf[i] != readb (this->IO_ADDR)) {
+			DEBUG (MTD_DEBUG_LEVEL0,
+				"nand_write_oob: " \
+				"Failed write verify, page 0x%08x\n", page);
+			nand_deselect ();
+			spin_lock_bh (&this->chip_lock);
+			this->state = FL_READY;
+			wake_up (&this->wq);
+			spin_unlock_bh (&this->chip_lock);
+			return -EIO;
+		}
+	}
+#endif
+
+	/* De-select the NAND device */
+	nand_deselect ();
+
+	/* Wake up anyone waiting on the device */
+	spin_lock_bh (&this->chip_lock);
+	this->state = FL_READY;
+	wake_up (&this->wq);
+	spin_unlock_bh (&this->chip_lock);
+
+	/* Return happy */
+	*retlen = len;
+	return 0;
+}
+
+/*
+ * NAND write with iovec
+ */
+static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
+				unsigned long count, loff_t to, size_t *retlen)
+{
+	int i, page, col, cnt, len, total_len, status;
+	struct nand_chip *this = mtd->priv;
+	DECLARE_WAITQUEUE(wait, current);
+#ifdef CONFIG_MTD_NAND_ECC
+	int ecc_bytes = (mtd->oobblock == 512) ? 6 : 3;
+#endif
+
+	/* 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\n", (unsigned int) to,
+			(unsigned int) total_len);
+
+	/* 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;
+	}
+
+retry:
+	/* Grab the lock and see if the device is available */
+	spin_lock_bh (&this->chip_lock);
+
+	switch (this->state) {
+	case FL_READY:
+		this->state = FL_WRITING;
+		spin_unlock_bh (&this->chip_lock);
+		break;
+
+	default:
+		set_current_state (TASK_UNINTERRUPTIBLE);
+		add_wait_queue (&this->wq, &wait);
+		spin_unlock_bh (&this->chip_lock);
+		schedule();
+
+		remove_wait_queue (&this->wq, &wait);
+		goto retry;
+	};
+
+	/* Shift to get page */
+	page = ((int) to) >> this->page_shift;
+
+	/* Get the starting column */
+	col = to & (mtd->oobblock - 1);
+
+	/* Initialize return length value */
+	*retlen = 0;
+
+	/* Select the NAND device */
+	nand_select ();
+
+	/* Check the WP bit */
+	nand_command (mtd, NAND_CMD_STATUS, -1, -1);
+	if (!(readb (this->IO_ADDR) & 0x80)) {
+		DEBUG (MTD_DEBUG_LEVEL0,
+			"nand_writev: Device is write protected!!!\n");
+		nand_deselect ();
+		spin_lock_bh (&this->chip_lock);
+		this->state = FL_READY;
+		wake_up (&this->wq);
+		spin_unlock_bh (&this->chip_lock);
+		return -EIO;
+	}
+
+	/* Loop until all iovecs' data has been written */
+	cnt = col;
+	len = 0;
+	while (count) {
+		/* Do any need pre-fill for partial page programming */
+		for (i=0 ; i < cnt ; i++)
+			this->data_buf[i] = 0xff;
+
+		/*
+		 * Read data out of each tuple until we have a full page
+		 * to write or we've read all the tuples.
+		 */
+		while ((cnt < mtd->oobblock) && count) {
+			this->data_buf[cnt++] =
+				((u_char *) vecs->iov_base)[len++];
+			if (len >= (int) vecs->iov_len) {
+				vecs++;
+				len = 0;
+				count--;
+			}
+		}
+		
+		/* Do any need post-fill for partial page programming */
+		for (i=cnt ; i < mtd->oobblock ; i++)
+			this->data_buf[i] = 0xff;
+
+#ifdef CONFIG_MTD_NAND_ECC
+		/* Zero out the ECC array */
+		for (i=0 ; i < 6 ; i++)
+			this->ecc_code_buf[i] = 0x00;
+
+		/* Calculate and write the first ECC */
+		if (col >= mtd->eccsize) {
+			nand_command (mtd, NAND_CMD_READ0, col, page);
+			for (i=0 ; i < col ; i++)
+				this->data_buf[i] = readb (this->IO_ADDR); 
+			nand_calculate_ecc (&this->data_buf[0],
+				&(this->ecc_code_buf[0]));
+			for (i=0 ; i<3 ; i++)
+				this->data_buf[(mtd->oobblock + i)] =
+					this->ecc_code_buf[i];
+		}
+
+		/* Calculate and write the second ECC */
+		if ((mtd->oobblock == 512) && (cnt == mtd->oobblock)) {
+			nand_calculate_ecc (&this->data_buf[256],
+				&(this->ecc_code_buf[3]));
+			for (i=3 ; i<6 ; i++)
+				this->data_buf[(mtd->oobblock + i)] =
+					this->ecc_code_buf[i];
+		}
+
+		/* Write ones for partial page programming */
+		for (i=ecc_bytes ; i < mtd->oobsize ; i++)
+			this->data_buf[(mtd->oobblock + i)] = 0xff;
+#else
+		/* Write ones for partial page programming */
+		for (i=mtd->oobblock ; i < (mtd->oobblock + mtd->oobsize) ; i++)
+			this->data_buf[i] = 0xff;
+#endif
+		/* Send command to begin auto page programming */
+		nand_command (mtd, NAND_CMD_SEQIN, 0x00, page);
+
+		/* Write out complete page of data */
+		for (i=0 ; i < (mtd->oobblock + mtd->oobsize) ; i++)
+			writeb (this->data_buf[i], this->IO_ADDR);
+
+		/* Send command to actually program the data */
+		nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+		/*
+		 * Wait for program operation to complete. This could
+		 * take up to 3000us (3ms) on some devices, so we try
+		 * and exit as quickly as possible.
+		 */
+		status = 0;
+		for (i=0 ; i<24 ; i++) {
+			/* Delay for 125us */
+			udelay (125);
+
+			/* Check the status */
+			nand_command (mtd, NAND_CMD_STATUS, -1, -1);
+			status = (int) readb (this->IO_ADDR);
+			if (status & 0x40)
+				break;
+		}
+
+		/* See if device thinks it succeeded */
+		if (status & 0x01) {
+			DEBUG (MTD_DEBUG_LEVEL0,
+				"nand_writev: " \
+				"Failed write, page 0x%08x, " \
+				"%6i bytes were succesful\n", page, *retlen);
+			nand_deselect ();
+			spin_lock_bh (&this->chip_lock);
+			this->state = FL_READY;
+			wake_up (&this->wq);
+			spin_unlock_bh (&this->chip_lock);
+			return -EIO;
+		}
+
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+		/*
+		 * 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.
+		 */
+		
+		/* Send command to read back the page */
+		if (col < mtd->eccsize)
+			nand_command (mtd, NAND_CMD_READ0, col, page);
+		else
+			nand_command (mtd, NAND_CMD_READ1, col - 256, page);
+
+		/* Loop through and verify the data */
+		for (i=col ; i < cnt ; i++) {
+			if (this->data_buf[i] != readb (this->IO_ADDR)) {
+				DEBUG (MTD_DEBUG_LEVEL0,
+					"nand_writev: " \
+					"Failed write verify, page 0x%08x, " \
+					"%6i bytes were succesful\n",
+					page, *retlen);
+				nand_deselect ();
+				spin_lock_bh (&this->chip_lock);
+				this->state = FL_READY;
+				wake_up (&this->wq);
+				spin_unlock_bh (&this->chip_lock);
+				return -EIO;
+			}
+		}
+
+#ifdef CONFIG_MTD_NAND_ECC
+		/*
+		 * We also want to check that the ECC bytes wrote
+		 * correctly for the same reasons stated above.
+		 */
+		nand_command (mtd, NAND_CMD_READOOB, 0x00, page);
+		for (i=0 ; i < ecc_bytes ; i++) {
+			if ((readb (this->IO_ADDR) != this->ecc_code_buf[i]) &&
+					this->ecc_code_buf[i]) {
+				DEBUG (MTD_DEBUG_LEVEL0,
+					"nand_writev: Failed ECC write " \
+					"verify, page 0x%08x, " \
+					"%6i bytes were succesful\n",
+					page, i);
+				nand_deselect ();
+				spin_lock_bh (&this->chip_lock);
+				this->state = FL_READY;
+				wake_up (&this->wq);
+				spin_unlock_bh (&this->chip_lock);
+				return -EIO;
+			}
+		}
+#endif
+
+#endif
+		/* Update written bytes count */
+		*retlen += (cnt - col);
+
+		/* Reset written byte counter and column */
+		col = cnt = 0;
+
+		/* Increment page address */
+		page++;
+	}
+
+	/* De-select the NAND device */
+	nand_deselect ();
+
+	/* Wake up anyone waiting on the device */
+	spin_lock_bh (&this->chip_lock);
+	this->state = FL_READY;
+	wake_up (&this->wq);
+	spin_unlock_bh (&this->chip_lock);
+
+	/* Return happy */
+	return 0;
+}
+
+/*
+ * NAND erase a block
+ */
+static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+	int i, page, len, status, pages_per_block;
+	struct nand_chip *this = mtd->priv;
+	DECLARE_WAITQUEUE(wait, current);
+
+	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 & (mtd->erasesize - 1)) {
+		DEBUG (MTD_DEBUG_LEVEL0,
+			"nand_erase: Unaligned address\n");
+		return -EINVAL;
+	}
+
+	/* Length must align on block boundary */
+	if (instr->len & (mtd->erasesize - 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;
+	}
+
+retry:
+	/* Grab the lock and see if the device is available */
+	spin_lock_bh (&this->chip_lock);
+
+	switch (this->state) {
+	case FL_READY:
+		this->state = FL_ERASING;
+		break;
+
+	default:
+		set_current_state (TASK_UNINTERRUPTIBLE);
+		add_wait_queue (&this->wq, &wait);
+		spin_unlock_bh (&this->chip_lock);
+		schedule();
+
+		remove_wait_queue (&this->wq, &wait);
+		goto retry;
+	};
+
+	/* Shift to get first page */
+	page = (int) (instr->addr >> this->page_shift);
+
+	/* Calculate pages in each block */
+	pages_per_block = mtd->erasesize / mtd->oobblock;
+
+	/* Select the NAND device */
+	nand_select ();
+
+	/* Check the WP bit */
+	nand_command (mtd, NAND_CMD_STATUS, -1, -1);
+	if (!(readb (this->IO_ADDR) & 0x80)) {
+		DEBUG (MTD_DEBUG_LEVEL0,
+			"nand_erase: Device is write protected!!!\n");
+		nand_deselect ();
+		this->state = FL_READY;
+		spin_unlock_bh (&this->chip_lock);
+		return -EIO;
+	}
+
+	/* Loop through the pages */
+	len = instr->len;
+	while (len) {
+		/* Send commands to erase a page */
+		nand_command(mtd, NAND_CMD_ERASE1, -1, page);
+		nand_command(mtd, NAND_CMD_ERASE2, -1, -1);
+
+		/*
+		 * Wait for program operation to complete. This could
+		 * take up to 4000us (4ms) on some devices, so we try
+		 * and exit as quickly as possible.
+		 */
+		status = 0;
+		for (i=0 ; i<32 ; i++) {
+			/* Delay for 125us */
+			udelay (125);
+
+			/* Check the status */
+			nand_command (mtd, NAND_CMD_STATUS, -1, -1);
+			status = (int) readb (this->IO_ADDR);
+			if (status & 0x40)
+				break;
+		}
+
+		/* See if block erase succeeded */
+		if (status & 0x01) {
+			DEBUG (MTD_DEBUG_LEVEL0,
+				"nand_erase: " \
+				"Failed erase, page 0x%08x\n", page);
+			nand_deselect ();
+			this->state = FL_READY;
+			spin_unlock_bh (&this->chip_lock);
+			return -EIO;
+		}
+
+		/* Increment page address and decrement length */
+		len -= mtd->erasesize;
+		page += pages_per_block;
+
+		/* Release the spin lock */
+		spin_unlock_bh (&this->chip_lock);
+
+erase_retry:
+		/* Check the state and sleep if it changed */
+		spin_lock_bh (&this->chip_lock);
+		if (this->state == FL_ERASING) {
+			continue;
+		}
+		else {
+			set_current_state (TASK_UNINTERRUPTIBLE);
+			add_wait_queue (&this->wq, &wait);
+			spin_unlock_bh (&this->chip_lock);
+			schedule();
+
+			remove_wait_queue (&this->wq, &wait);
+			goto erase_retry;
+		}
+	}
+	spin_unlock_bh (&this->chip_lock);
+
+	/* De-select the NAND device */
+	nand_deselect ();
+
+	/* Do call back function */
+	if (instr->callback)
+		instr->callback (instr);
+
+	/* The device is ready */
+	spin_lock_bh (&this->chip_lock);
+	this->state = FL_READY;
+	spin_unlock_bh (&this->chip_lock);
+
+	/* Return happy */
+	return 0;
+}
+
+/*
+ * NAND sync
+ */
+static void nand_sync (struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd->priv;
+	DECLARE_WAITQUEUE(wait, current);
+
+	DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");
+
+retry:
+	/* Grab the spinlock */
+	spin_lock_bh(&this->chip_lock);
+
+	/* See what's going on */
+	switch(this->state) {
+	case FL_READY:
+	case FL_SYNCING:
+		this->state = FL_SYNCING;
+		spin_unlock_bh (&this->chip_lock);
+		break;
+
+	default:
+		/* Not an idle state */
+		add_wait_queue (&this->wq, &wait);
+		spin_unlock_bh (&this->chip_lock);
+		schedule ();
+
+		remove_wait_queue (&this->wq, &wait);
+		goto retry;
+	}
+
+        /* Lock the device */
+	spin_lock_bh (&this->chip_lock);
+
+	/* Set the device to be ready again */
+	if (this->state == FL_SYNCING) {
+		this->state = FL_READY;
+		wake_up (&this->wq);
+	}
+
+        /* Unlock the device */
+	spin_unlock_bh (&this->chip_lock);
+}
+
+/*
+ * Scan for the NAND device
+ */
+int nand_scan (struct mtd_info *mtd)
+{
+	int i, nand_maf_id, nand_dev_id;
+	struct nand_chip *this = mtd->priv;
+
+	/* Select the device */
+	nand_select ();
+
+	/* Send the command for reading device ID */
+	nand_command (mtd, NAND_CMD_READID, 0x00, -1);
+
+	/* Read manufacturer and device IDs */
+	nand_maf_id = readb (this->IO_ADDR);
+	nand_dev_id = readb (this->IO_ADDR);
+
+	/* Print and store flash device information */
+	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
+		if (nand_maf_id == nand_flash_ids[i].manufacture_id &&
+		    nand_dev_id == nand_flash_ids[i].model_id) {
+			if (!mtd->size) {
+				mtd->name = nand_flash_ids[i].name;
+				mtd->erasesize = nand_flash_ids[i].erasesize;
+				mtd->size = (1 << nand_flash_ids[i].chipshift);
+				mtd->eccsize = 256;
+				if (nand_flash_ids[i].page256) {
+					mtd->oobblock = 256;
+					mtd->oobsize = 8;
+					this->page_shift = 8;
+				}
+				else {
+					mtd->oobblock = 512;
+					mtd->oobsize = 16;
+					this->page_shift = 9;
+				}
+			}
+			printk (KERN_INFO "NAND device: Manufacture ID:" \
+				" 0x%02x, Chip ID: 0x%02x (%s)\n",
+			       nand_maf_id, nand_dev_id, mtd->name);
+			break;
+		}
+	}
+
+	/* Initialize state and spinlock */
+	this->state = FL_READY;
+	spin_lock_init(&this->chip_lock);
+
+	/* De-select the device */
+	nand_deselect ();
+
+	/* Print warning message for no device */
+	if (!mtd->size) {
+		printk (KERN_WARNING "No NAND device found!!!\n");
+		return 1;
+	}
+
+	/* Fill in remaining MTD driver data */
+	mtd->type = MTD_NANDFLASH;
+	mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
+	mtd->module = THIS_MODULE;
+	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->sync = nand_sync;
+	mtd->lock = NULL;
+	mtd->unlock = NULL;
+	mtd->suspend = NULL;
+	mtd->resume = NULL;
+
+	/* Return happy */
+	return 0;
+}
+
+EXPORT_SYMBOL(nand_scan);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/nand/nand_ecc.c linux/drivers/mtd/nand/nand_ecc.c
--- v2.4.5/linux/drivers/mtd/nand/nand_ecc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/nand/nand_ecc.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,204 @@
+/*
+ *  drivers/mtd/nand_ecc.c
+ *
+ *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ *                     Toshiba America Electronics Components, Inc.
+ *
+ * $Id: nand_ecc.c,v 1.4 2001/01/03 20:02:20 mgadbois 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.
+ *
+ * This file contains an ECC algorithm from Toshiba that detects and
+ * corrects 1 bit errors in a 256 byte block of data.
+ */
+
+#include <linux/types.h>
+
+/*
+ * Pre-calculated 256-way 1 byte column parity
+ */
+const u_char nand_ecc_precalc_table[] = {
+	0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+	0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+	0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+	0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+	0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+	0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+	0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+	0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+	0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+	0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+	0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+	0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+	0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+	0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+	0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+	0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
+};
+
+
+/*
+ * Creates non-inverted ECC code from line parity
+ */
+void nand_trans_result(u_char reg2, u_char reg3,
+	u_char *ecc_code)
+{
+	u_char a, b, i, tmp1, tmp2;
+	
+	/* Initialize variables */
+	a = b = 0x80;
+	tmp1 = tmp2 = 0;
+	
+	/* Calculate first ECC byte */
+	for (i = 0; i < 4; i++) {
+		if (reg3 & a)		/* LP15,13,11,9 --> ecc_code[0] */
+			tmp1 |= b;
+		b >>= 1;
+		if (reg2 & a)		/* LP14,12,10,8 --> ecc_code[0] */
+			tmp1 |= b;
+		b >>= 1;
+		a >>= 1;
+	}
+	
+	/* Calculate second ECC byte */
+	b = 0x80;
+	for (i = 0; i < 4; i++) {
+		if (reg3 & a)		/* LP7,5,3,1 --> ecc_code[1] */
+			tmp2 |= b;
+		b >>= 1;
+		if (reg2 & a)		/* LP6,4,2,0 --> ecc_code[1] */
+			tmp2 |= b;
+		b >>= 1;
+		a >>= 1;
+	}
+	
+	/* Store two of the ECC bytes */
+	ecc_code[0] = tmp1;
+	ecc_code[1] = tmp2;
+}
+
+/*
+ * Calculate 3 byte ECC code for 256 byte block
+ */
+void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
+{
+	u_char idx, reg1, reg2, reg3;
+	int j;
+	
+	/* Initialize variables */
+	reg1 = reg2 = reg3 = 0;
+	ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
+	
+	/* Build up column parity */ 
+	for(j = 0; j < 256; j++) {
+		
+		/* Get CP0 - CP5 from table */
+		idx = nand_ecc_precalc_table[dat[j]];
+		reg1 ^= (idx & 0x3f);
+		
+		/* All bit XOR = 1 ? */
+		if (idx & 0x40) {
+			reg3 ^= (u_char) j;
+			reg2 ^= ~((u_char) j);
+		}
+	}
+	
+	/* Create non-inverted ECC code from line parity */
+	nand_trans_result(reg2, reg3, ecc_code);
+	
+	/* Calculate final ECC code */
+	ecc_code[0] = ~ecc_code[0];
+	ecc_code[1] = ~ecc_code[1];
+	ecc_code[2] = ((~reg1) << 2) | 0x03;
+}
+
+/*
+ * 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)
+{
+	u_char a, b, c, d1, d2, d3, add, bit, i;
+	
+	/* Do error detection */ 
+	d1 = calc_ecc[0] ^ read_ecc[0];
+	d2 = calc_ecc[1] ^ read_ecc[1];
+	d3 = calc_ecc[2] ^ read_ecc[2];
+	
+	if ((d1 | d2 | d3) == 0) {
+		/* No errors */
+		return 0;
+	}
+	else {
+		a = (d1 ^ (d1 >> 1)) & 0x55;
+		b = (d2 ^ (d2 >> 1)) & 0x55;
+		c = (d3 ^ (d3 >> 1)) & 0x54;
+		
+		/* Found and will correct single bit error in the data */
+		if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
+			c = 0x80;
+			add = 0;
+			a = 0x80;
+			for (i=0; i<4; i++) {
+				if (d1 & c)
+					add |= a;
+				c >>= 2;
+				a >>= 1;
+			}
+			c = 0x80;
+			for (i=0; i<4; i++) {
+				if (d2 & c)
+					add |= a;
+				c >>= 2;
+				a >>= 1;
+			}
+			bit = 0;
+			b = 0x04;
+			c = 0x80;
+			for (i=0; i<3; i++) {
+				if (d3 & c)
+					bit |= b;
+				c >>= 2;
+				b >>= 1;
+			}
+			b = 0x01;
+			a = dat[add];
+			a ^= (b << bit);
+			dat[add] = a;
+			return 1;
+		}
+		else {
+			i = 0;
+			while (d1) {
+				if (d1 & 0x01)
+					++i;
+				d1 >>= 1;
+			}
+			while (d2) {
+				if (d2 & 0x01)
+					++i;
+				d2 >>= 1;
+			}
+			while (d3) {
+				if (d3 & 0x01)
+					++i;
+				d3 >>= 1;
+			}
+			if (i == 1) {
+				/* ECC Code Error Correction */
+				read_ecc[0] = calc_ecc[0];
+				read_ecc[1] = calc_ecc[1];
+				read_ecc[2] = calc_ecc[2];
+				return 2;
+			}
+			else {
+				/* Uncorrectable Error */
+				return -1;
+			}
+		}
+	}
+	
+	/* Should never happen */
+	return -1;
+}
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/nand/spia.c linux/drivers/mtd/nand/spia.c
--- v2.4.5/linux/drivers/mtd/nand/spia.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/nand/spia.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,129 @@
+/*
+ *  drivers/mtd/spia.c
+ *
+ *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ *
+ * $Id: spia.c,v 1.9 2001/06/02 14:47:16 dwmw2 Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Overview:
+ *   This is a device driver for the NAND flash device found on the
+ *   SPIA board which utilizes the Toshiba TC58V64AFT part. This is
+ *   a 64Mibit (8MiB x 8 bits) NAND flash device.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+
+/*
+ * MTD structure for SPIA board
+ */
+static struct mtd_info *spia_mtd = NULL;
+
+/*
+ * Module stuff
+ */
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+  #define spia_init init_module
+  #define spia_cleanup cleanup_module
+#endif
+
+/*
+ * 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 }
+};
+#define NUM_PARTITIONS 2
+
+/*
+ * Main initialization routine
+ */
+int __init spia_init (void)
+{
+	struct nand_chip *this;
+
+	/* Allocate memory for MTD device structure and private data */
+	spia_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
+				GFP_KERNEL);
+	if (!spia_mtd) {
+		printk ("Unable to allocate SPIA NAND MTD device structure.\n");
+		return -ENOMEM;
+	}
+
+	/* Get pointer to private data */
+	this = (struct nand_chip *) (&spia_mtd[1]);
+
+	/* Initialize structures */
+	memset((char *) spia_mtd, 0, sizeof(struct mtd_info));
+	memset((char *) this, 0, sizeof(struct nand_chip));
+
+	/* Link the private data with the MTD structure */
+	spia_mtd->priv = this;
+
+	/*
+	 * Set GPIO Port E control register so that the pins are configured
+	 * to be outputs for controlling the NAND flash.
+	 */
+	(*(volatile unsigned char *) (IO_BASE + PEDDR)) = 0x07;
+
+	/* Set address of NAND IO lines */
+	this->IO_ADDR = FIO_BASE;
+	this->CTRL_ADDR = IO_BASE + PEDR;
+	this->CLE = 0x01;
+	this->ALE = 0x02;
+	this->NCE = 0x04;
+
+	/* Scan to find existance of the device */
+	if (nand_scan (spia_mtd)) {
+		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;
+	}
+
+	/* Register the partitions */
+	add_mtd_partitions(spia_mtd, partition_info, NUM_PARTITIONS);
+
+	/* Return happy */
+	return 0;
+}
+module_init(spia_init);
+
+/*
+ * Clean up routine
+ */
+#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);
+
+	/* Free the MTD device structure */
+	kfree (spia_mtd);
+}
+module_exit(spia_cleanup);
+#endif
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/nftl.c linux/drivers/mtd/nftl.c
--- v2.4.5/linux/drivers/mtd/nftl.c	Sat Apr 28 11:27:54 2001
+++ linux/drivers/mtd/nftl.c	Wed Dec 31 16:00:00 1969
@@ -1,1108 +0,0 @@
-/* Linux driver for NAND Flash Translation Layer      */
-/* (c) 1999 Machine Vision Holdings, Inc.             */
-/* Author: David Woodhouse <dwmw2@infradead.org>      */
-/* $Id: nftl.c,v 1.57 2000/12/01 17:51:54 dwmw2 Exp $ */
-
-/*
-  The contents of this file are distributed under the GNU General
-  Public License version 2 ("GPL"). The author places no additional
-  restrictions of any kind on it. However, local legislation in some
-  countries may restrict the use of the algorithms implemented by this
-  code in certain circumstances.
-
-  The legal note below refers only to the _use_ of the code in the 
-  affected jurisdictions, and does not in any way affect the copying,
-  distribution and modification of this code, which are permitted, and
-  indeed required, under the terms of the GPL.
-
-  Section 0 of the GPL says:
- "Activities other than copying, distribution and modification are not
-  covered by this License; they are outside its scope."
-
-  You may copy, distribute and modify this code to your hearts'
-  content - it's just that in some jurisdictions, you may only _use_
-  it under the terms of the patent grant below. This puts it in a
-  similar situation to the ISDN code, which you may need telco
-  approval to use, and indeed any code which has uses that may be
-  restricted in law. For example, certain malicious uses of the
-  networking stack may be illegal, but that doesn't prevent the
-  networking code from being under GPL.
-
-  In fact the ISDN case is worse than this, because modification of
-  the code automatically invalidates its approval. Modification,
-  unlike usage, _is_ one of the rights which is protected by the
-  GPL. Happily, the law in those places where approval is required
-  doesn't actually prevent you from modifying the code - it's just
-  that you may not be allowed to _use_ it once you've done so - and
-  because usage isn't addressed by the GPL, that's just fine.
-
-  dwmw2@infradead.org
-  30/10/0
-
-  LEGAL NOTE: The NFTL format is patented by M-Systems.  They have
-  granted a licence for its use with their DiskOnChip products:
-
-    "M-Systems grants a royalty-free, non-exclusive license under
-    any presently existing M-Systems intellectual property rights
-    necessary for the design and development of NFTL-compatible
-    drivers, file systems and utilities to use the data formats with, 
-    and solely to support, M-Systems' DiskOnChip products"
-
-  A signed copy of this agreement from M-Systems is kept on file by
-  Red Hat UK Limited. In the unlikely event that you need access to it,
-  please contact dwmw2@redhat.com for assistance.  */
-
-#define PRERELEASE
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/miscdevice.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/blkpg.h>
-#ifdef CONFIG_KMOD
-#include <linux/kmod.h>
-#endif
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nftl.h>
-#include <linux/mtd/compatmac.h>
-
-/* maximum number of loops while examining next block, to have a
-   chance to detect consistency problems (they should never happen
-   because of the checks done in the mounting */
-
-#define MAX_LOOPS 10000
-
-/* NFTL block device stuff */
-#define MAJOR_NR NFTL_MAJOR
-#define DEVICE_REQUEST nftl_request
-#define DEVICE_OFF(device)
-
-
-#include <linux/blk.h>
-#include <linux/hdreg.h>
-
-/* Linux-specific block device functions */
-
-/* I _HATE_ the Linux block device setup more than anything else I've ever
- *  encountered, except ...
- */
-
-static int nftl_sizes[256] = {0,};
-static int nftl_blocksizes[256] = {0,};
-
-/* .. for the Linux partition table handling. */
-struct hd_struct part_table[256] = {{0,0},};
-
-#if LINUX_VERSION_CODE < 0x20328
-static void dummy_init (struct gendisk *crap)
-{}
-#endif
-
-static struct gendisk nftl_gendisk = {
-        MAJOR_NR,     /* Major number */      
-        "nftl",          /* Major name */
-        4,              /* Bits to shift to get real from partition */
-        15,             /* Number of partitions per real */
-#if LINUX_VERSION_CODE < 0x20328
-        MAX_NFTLS,      /* maximum number of real */
-        dummy_init,     /* init function */
-#endif
-        part_table,     /* hd struct */
-        nftl_sizes,     /* block sizes */
-        0,              /* number */
-        NULL,           /* internal use, not presently used */
-        NULL            /* next */
-};
-
-struct NFTLrecord *NFTLs[MAX_NFTLS] = {NULL};
-
-static void NFTL_setup(struct mtd_info *mtd)
-{
-	int i;
-	struct NFTLrecord *nftl;
-	unsigned long temp;
-	int firstfree = -1;
-
-	DEBUG(MTD_DEBUG_LEVEL1,"NFTL_setup\n");
-
-	for (i = 0; i < MAX_NFTLS; i++) {
-		if (!NFTLs[i] && firstfree == -1)
-			firstfree = i;
-		else if (NFTLs[i] && NFTLs[i]->mtd == mtd) {
-			/* This is a Spare Media Header for an NFTL we've already found */
-			DEBUG(MTD_DEBUG_LEVEL1, "MTD already mounted as NFTL\n");
-			return;
-		}
-	}
-        if (firstfree == -1) {
-		printk(KERN_WARNING "No more NFTL slot available\n");
-		return;
-        }
-
-	nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
-	if (!nftl) {
-		printk(KERN_WARNING "Out of memory for NFTL data structures\n");
-		return;
-	}
-
-	init_MUTEX(&nftl->mutex);
-
-        /* get physical parameters */
-	nftl->EraseSize = mtd->erasesize;
-        nftl->nb_blocks = mtd->size / mtd->erasesize;
-	nftl->mtd = mtd;
-
-        if (NFTL_mount(nftl) < 0) {
-		printk(KERN_WARNING "Could not mount NFTL 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;
-	nftl->cylinders = 1024;
-	nftl->heads = 16;
-
-	temp = nftl->cylinders * nftl->heads;
-	nftl->sectors = nftl->nr_sects / temp;
-	if (nftl->nr_sects % temp) {
-		nftl->sectors++;
-		temp = nftl->cylinders * nftl->sectors;
-		nftl->heads = nftl->nr_sects / temp;
-
-		if (nftl->nr_sects % temp) {
-			nftl->heads++;
-			temp = nftl->heads * nftl->sectors;
-			nftl->cylinders = nftl->nr_sects / temp;
-		}
-	}
-
-	if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) {
-		printk(KERN_WARNING "Cannot calculate an NFTL geometry to "
-		       "match size of 0x%lx.\n", nftl->nr_sects);
-		printk(KERN_WARNING "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; */
-	}
-	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;
-
-	/* partition check ... */
-#if LINUX_VERSION_CODE < 0x20328
-	resetup_one_dev(&nftl_gendisk, firstfree);
-#else
-	grok_partitions(&nftl_gendisk, firstfree, 1<<4, nftl->nr_sects);
-#endif
-}
-
-static void NFTL_unsetup(int i)
-{
-	struct NFTLrecord *nftl = NFTLs[i];
-
-	DEBUG(MTD_DEBUG_LEVEL1, "NFTL_unsetup %d\n", i);
-	
-	NFTLs[i] = NULL;
-	
-	if (nftl->ReplUnitTable)
-		kfree(nftl->ReplUnitTable);
-	if (nftl->EUNtable)
-		kfree(nftl->EUNtable);
-		      
-	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);
-	}
-}
-
-static void NFTL_notify_remove(struct mtd_info *mtd)
-{
-	int i;
-
-	for (i = 0; i < MAX_NFTLS; i++) {
-		if (NFTLs[i] && NFTLs[i]->mtd == mtd)
-			NFTL_unsetup(i);
-	}
-}
-
-#ifdef CONFIG_NFTL_RW
-
-/* Actual NFTL access routines */
-/* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used
- *	when the give Virtual Unit Chain
- */
-static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
-{
-	/* For a given Virtual Unit Chain: find or create a free block and
-	   add it to the chain */
-	/* We're passed the number of the last EUN in the chain, to save us from
-	   having to look it up again */
-	u16 pot = nftl->LastFreeEUN;
-	int silly = -1;
-
-	/* Normally, we force a fold to happen before we run out of free blocks completely */
-	if (!desperate && nftl->numfreeEUNs < 2) {
-		DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n");
-		return 0xffff;
-	}
-
-	/* Scan for a free block */
-	do {
-		if (nftl->ReplUnitTable[pot] == BLOCK_FREE) {
-			nftl->LastFreeEUN = pot;
-			nftl->numfreeEUNs--;
-			return pot;
-		}
-
-		/* This will probably point to the MediaHdr unit itself,
-		   right at the beginning of the partition. But that unit
-		   (and the backup unit too) should have the UCI set
-		   up so that it's not selected for overwriting */
-		if (++pot > nftl->lastEUN)
-			pot = le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN);
-
-		if (!silly--) {
-			printk("Argh! No free blocks found! LastFreeEUN = %d, "
-			       "FirstEUN = %d\n", nftl->LastFreeEUN, 
-			       le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
-			return 0xffff;
-		}
-	} while (pot != nftl->LastFreeEUN);
-
-	return 0xffff;
-}
-
-static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
-{
-	u16 BlockMap[MAX_SECTORS_PER_UNIT];
-	unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];
-	unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];
-	unsigned int thisEUN;
-	int block;
-	int silly;
-	unsigned int targetEUN;
-	struct nftl_oob oob;
-	int inplace = 1;
-        size_t retlen;
-
-	memset(BlockMap, 0xff, sizeof(BlockMap));
-	memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
-
-	thisEUN = nftl->EUNtable[thisVUC];
-
-	if (thisEUN == BLOCK_NIL) {
-		printk(KERN_WARNING "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;
-	targetEUN = BLOCK_NIL;
-	while (thisEUN <= nftl->lastEUN ) {
-                unsigned int status, foldmark;
-
-		targetEUN = thisEUN;
-		for (block = 0; block < nftl->EraseSize / 512; block ++) {
-			MTD_READOOB(nftl->mtd,
-				    (thisEUN * nftl->EraseSize) + (block * 512),
-				    16 , &retlen, (char *)&oob);
-			if (block == 2) {
-                                foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
-                                if (foldmark == FOLD_MARK_IN_PROGRESS) {
-                                        DEBUG(MTD_DEBUG_LEVEL1, 
-                                              "Write Inhibited on EUN %d\n", thisEUN);
-					inplace = 0;
-				} else {
-					/* There's no other reason not to do inplace,
-					   except ones that come later. So we don't need
-					   to preserve inplace */
-					inplace = 1;
-				}
-			}
-                        status = oob.b.Status | oob.b.Status1;
-			BlockLastState[block] = status;
-
-			switch(status) {
-			case SECTOR_FREE:
-				BlockFreeFound[block] = 1;
-				break;
-
-			case SECTOR_USED:
-				if (!BlockFreeFound[block])
-					BlockMap[block] = thisEUN;
-				else
-					printk(KERN_WARNING 
-					       "SECTOR_USED found after SECTOR_FREE "
-					       "in Virtual Unit Chain %d for block %d\n",
-					       thisVUC, block);
-				break;
-			case SECTOR_IGNORE:
-			case SECTOR_DELETED:
-				break;
-			default:
-				printk("Unknown status for block %d in EUN %d: %x\n",
-				       block, thisEUN, status);
-			}
-		}
-
-		if (!silly--) {
-			printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
-			       thisVUC);
-			return BLOCK_NIL;
-		}
-		
-		thisEUN = nftl->ReplUnitTable[thisEUN];
-	}
-
-	if (inplace) {
-		/* We're being asked to be a fold-in-place. Check
-		   that all blocks are either present or SECTOR_FREE
-		   in the target block. If not, we're going to have
-		   to fold out-of-place anyway.
-		*/
-		for (block = 0; block < nftl->EraseSize / 512 ; block++) {
-			if (BlockLastState[block] != SECTOR_FREE &&
-			    BlockMap[block] != targetEUN) {
-				DEBUG(MTD_DEBUG_LEVEL1, "Setting inplace to 0. VUC %d, "
-				      "block %d was %x lastEUN, "
-				      "and is in EUN %d (%s) %d\n",
-				      thisVUC, block, BlockLastState[block],
-				      BlockMap[block], 
-				      BlockMap[block]== targetEUN ? "==" : "!=",
-				      targetEUN);
-				inplace = 0;
-				break;
-			}
-		}
-
-		if (pendingblock >= (thisVUC * (nftl->EraseSize / 512)) &&
-		    pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) &&
-		    BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] !=
-		    SECTOR_FREE) {
-			DEBUG(MTD_DEBUG_LEVEL1, "Pending write not free in EUN %d. "
-			      "Folding out of place.\n", targetEUN);
-			inplace = 0;
-		}
-	}
-	
-	if (!inplace) {
-		DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. "
-		      "Trying out-of-place\n", thisVUC);
-		/* We need to find a targetEUN to fold into. */
-		targetEUN = NFTL_findfreeblock(nftl, 1);
-		if (targetEUN == BLOCK_NIL) {
-			/* Ouch. Now we're screwed. We need to do a 
-			   fold-in-place of another chain to make room
-			   for this one. We need a better way of selecting
-			   which chain to fold, because makefreeblock will 
-			   only ask us to fold the same one again.
-			*/
-			printk(KERN_WARNING
-			       "NFTL_findfreeblock(desperate) returns 0xffff.\n");
-			return BLOCK_NIL;
-		}
-	} else {
-            /* We put a fold mark in the chain we are folding only if
-               we fold in place to help the mount check code. If we do
-               not fold in place, it is possible to find the valid
-               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, 
-                         8, &retlen, (char *)&oob.u);
-        }
-
-	/* 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,"Folding chain %d into unit %d\n", thisVUC, targetEUN);
-	for (block = 0; block < nftl->EraseSize / 512 ; block++) {
-		unsigned char movebuf[512];
-		int ret;
-
-		/* If it's in the target EUN already, or if it's pending write, do nothing */
-		if (BlockMap[block] == targetEUN ||
-		    (pendingblock == (thisVUC * (nftl->EraseSize / 512) + 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_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
-                                  + (block * 512), 512, &retlen, movebuf, (char *)&oob); 
-                if (ret < 0) {
-                    ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
-                                      + (block * 512), 512, &retlen,
-                                      movebuf, (char *)&oob); 
-                    if (ret != -EIO) 
-                        printk("Error went away on retry.\n");
-                }
-                MTD_WRITEECC(nftl->mtd, (nftl->EraseSize * targetEUN) + (block * 512),
-                             512, &retlen, movebuf, (char *)&oob);
-	}
-        
-        /* add the header so that it is now a valid chain */
-        oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum
-                = cpu_to_le16(thisVUC);
-        oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
-        
-        MTD_WRITEOOB(nftl->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. */
-
-	/* At this point, we have two different chains for this Virtual Unit, and no way to tell 
-	   them apart. If we crash now, we get confused. However, both contain the same data, so we
-	   shouldn't actually lose data in this case. It's just that when we load up on a medium which
-	   has duplicate chains, we need to free one of the chains because it's not necessary any more.
-	*/
-	thisEUN = nftl->EUNtable[thisVUC];
-	DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
-
-	/* For each block in the old chain (except the targetEUN of course), 
-	   free it and make it available for future use */
-	while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
-		unsigned int EUNtmp;
-
-                EUNtmp = nftl->ReplUnitTable[thisEUN];
-
-                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 {
-			/* correctly erased : mark it as free */
-			nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
-			nftl->numfreeEUNs++;
-                }
-                thisEUN = EUNtmp;
-	}
-	
-	/* Make this the new start of chain for thisVUC */
-	nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
-	nftl->EUNtable[thisVUC] = targetEUN;
-
-	return targetEUN;
-}
-
-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
-	   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;
-
-	for (chain = 0; chain < nftl->MediaHdr.FormattedSize / nftl->EraseSize; chain++) {
-		EUN = nftl->EUNtable[chain];
-		thislen = 0;
-
-		while (EUN <= nftl->lastEUN) {
-			thislen++;
-			//printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);
-			EUN = nftl->ReplUnitTable[EUN] & 0x7fff;
-			if (thislen > 0xff00) {
-				printk("Endless loop in Virtual Chain %d: Unit %x\n",
-				       chain, EUN);
-			}
-			if (thislen > 0xff10) {
-				/* Actually, don't return failure. Just ignore this chain and
-				   get on with it. */
-				thislen = 0;
-				break;
-			}
-		}
-
-		if (thislen > ChainLength) {
-			//printk("New longest chain is %d with length %d\n", chain, thislen);
-			ChainLength = thislen;
-			LongestChain = chain;
-		}
-	}
-
-	if (ChainLength < 2) {
-		printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
-		       "Failing request\n");
-		return 0xffff;
-	}
-
-	return NFTL_foldchain (nftl, LongestChain, pendingblock);
-}
-
-/* NFTL_findwriteunit: Return the unit number into which we can write 
-                       for this block. Make it available if it isn't already
-*/
-static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
-{
-	u16 lastEUN;
-	u16 thisVUC = block / (nftl->EraseSize / 512);
-	unsigned int writeEUN;
-	unsigned long blockofs = (block * 512) & (nftl->EraseSize -1);
-	size_t retlen;
-	int silly, silly2 = 3;
-	struct nftl_oob oob;
-
-	do {
-		/* Scan the media to find a unit in the VUC which has
-		   a free space for the block in question.
-		*/
-
-		/* This condition catches the 0x[7f]fff cases, as well as 
-		   being a sanity check for past-end-of-media access
-		*/
-		lastEUN = BLOCK_NIL;
-		writeEUN = nftl->EUNtable[thisVUC];
-                silly = MAX_LOOPS;
-		while (writeEUN <= nftl->lastEUN) {
-			struct nftl_bci bci;
-			size_t retlen;
-                        unsigned int status;
-
-			lastEUN = writeEUN;
-
-			MTD_READOOB(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
-				    8, &retlen, (char *)&bci);
-			
-			DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
-			      block , writeEUN, le16_to_cpu(bci.Status));
-
-                        status = bci.Status | bci.Status1;
-			switch(status) {
-			case SECTOR_FREE:
-				return writeEUN;
-
-			case SECTOR_DELETED:
-			case SECTOR_USED:
-			case SECTOR_IGNORE:
-				break;
-			default:
-				// Invalid block. Don't use it any more. Must implement.
-				break;			
-			}
-			
-			if (!silly--) { 
-				printk(KERN_WARNING
-				       "Infinite loop in Virtual Unit Chain 0x%x\n",
-				       thisVUC);
-				return 0xffff;
-			}
-
-			/* Skip to next block in chain */
-			writeEUN = nftl->ReplUnitTable[writeEUN];
-		}
-
-		/* OK. We didn't find one in the existing chain, or there 
-		   is no existing chain. */
-
-		/* Try to find an already-free block */
-		writeEUN = NFTL_findfreeblock(nftl, 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.
-			*/
-
-			/* First remember the start of this chain */
-			//u16 startEUN = nftl->EUNtable[thisVUC];
-			
-			//printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
-			writeEUN = NFTL_makefreeblock(nftl, 0xffff);
-			
-			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 "Cannot make free space.\n");
-				return BLOCK_NIL;
-			}			
-			//printk("Restarting scan\n");
-			lastEUN = BLOCK_NIL;
-			continue;
-		}
-
-		/* We've found a free block. Insert it into the chain. */
-		
-		if (lastEUN != BLOCK_NIL) {
-                    thisVUC |= 0x8000; /* It's a replacement block */
-		} else {
-                    /* The first block in a new chain */
-                    nftl->EUNtable[thisVUC] = writeEUN;
-		}
-
-		/* set up the actual EUN we're writing into */
-		/* Both in our cache... */
-		nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
-
-		/* ... and on the flash itself */
-		MTD_READOOB(nftl->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,
-                             &retlen, (char *)&oob.u);
-
-                /* we link the new block to the chain only after the
-                   block is ready. It avoids the case where the chain
-                   could point to a free block */
-                if (lastEUN != BLOCK_NIL) {
-			/* Both in our cache... */
-			nftl->ReplUnitTable[lastEUN] = writeEUN;
-			/* ... and on the flash itself */
-			MTD_READOOB(nftl->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,
-				     8, &retlen, (char *)&oob.u);
-		}
-
-		return writeEUN;
-
-	} while (silly2--);
-
-	printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
-	       thisVUC);
-	return 0xffff;
-}
-
-static int NFTL_writeblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
-{
-	u16 writeEUN;
-	unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
-	size_t retlen;
-	u8 eccbuf[6];
-
-	writeEUN = NFTL_findwriteunit(nftl, block);
-
-	if (writeEUN == BLOCK_NIL) {
-		printk(KERN_WARNING
-		       "NFTL_writeblock(): Cannot find block to write to\n");
-		/* If we _still_ haven't got a block to use, we're screwed */
-		return 1;
-	}
-
-	MTD_WRITEECC(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
-		     512, &retlen, (char *)buffer, (char *)eccbuf);
-        /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */
-
-	return 0;
-}
-#endif /* CONFIG_NFTL_RW */
-
-static int NFTL_readblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
-{
-	u16 lastgoodEUN;
-	u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
-	unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
-        unsigned int status;
-	int silly = MAX_LOOPS;
-        size_t retlen;
-        struct nftl_bci bci;
-
-	lastgoodEUN = BLOCK_NIL;
-
-        if (thisEUN != BLOCK_NIL) {
-		while (thisEUN < nftl->nb_blocks) {
-			if (MTD_READOOB(nftl->mtd, (thisEUN * nftl->EraseSize) + blockofs,
-					8, &retlen, (char *)&bci) < 0)
-				status = SECTOR_IGNORE;
-			else
-				status = bci.Status | bci.Status1;
-
-			switch (status) {
-			case SECTOR_FREE:
-				/* no modification of a sector should follow a free sector */
-				goto the_end;
-			case SECTOR_DELETED:
-				lastgoodEUN = BLOCK_NIL;
-				break;
-			case SECTOR_USED:
-				lastgoodEUN = thisEUN;
-				break;
-			case SECTOR_IGNORE:
-				break;
-			default:
-				printk("Unknown status for block %d in EUN %d: %x\n",
-				       block, thisEUN, status);
-				break;
-			}
-
-			if (!silly--) {
-				printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
-				       block / (nftl->EraseSize / 512));
-				return 1;
-			}
-			thisEUN = nftl->ReplUnitTable[thisEUN];
-		}
-        }
-
- the_end:
-	if (lastgoodEUN == BLOCK_NIL) {
-		/* the requested block is not on the media, return all 0x00 */
-		memset(buffer, 0, 512);
-	} 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))
-			return -EIO;
-	}
-	return 0;
-}
-
-static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
-{
-	struct NFTLrecord *nftl;
-
-	nftl = NFTLs[MINOR(inode->i_rdev) / 16];
-
-	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 */
-		if (!arg) return -EINVAL;
-		return put_user(part_table[MINOR(inode->i_rdev)].nr_sects,
-                                (long *) arg);
-		
-	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;
-#if LINUX_VERSION_CODE < 0x20328
-		resetup_one_dev(&nftl_gendisk, MINOR(inode->i_rdev) / 16);
-#else
-		grok_partitions(&nftl_gendisk, MINOR(inode->i_rdev) / 16,
-				1<<4, nftl->nr_sects);
-#endif
-		return 0;
-
-#if (LINUX_VERSION_CODE < 0x20303)		
-	RO_IOCTLS(inode->i_rdev, arg);  /* ref. linux/blk.h */
-#else
-	case BLKROSET:
-	case BLKROGET:
-	case BLKSSZGET:
-		return blk_ioctl(inode->i_rdev, cmd, arg);
-#endif
-
-	default:
-		return -EINVAL;
-	}
-}
-
-void nftl_request(RQFUNC_ARG)
-{
-	unsigned int dev, block, nsect;
-	struct NFTLrecord *nftl;
-	char *buffer;
-	struct request *req;
-	int res;
-
-	while (1) {
-		INIT_REQUEST;	/* blk.h */
-		req = CURRENT;
-		
-		/* We can do this because the generic code knows not to
-		   touch the request at the head of the queue */
-		spin_unlock_irq(&io_request_lock);
-
-		DEBUG(MTD_DEBUG_LEVEL2, "NFTL_request\n");
-		DEBUG(MTD_DEBUG_LEVEL3, "NFTL %s request, from sector 0x%04lx for 0x%04lx sectors\n",
-		      (req->cmd == READ) ? "Read " : "Write",
-		      req->sector, req->current_nr_sectors);
-
-		dev = MINOR(req->rq_dev);
-		block = req->sector;
-		nsect = req->current_nr_sectors;
-		buffer = req->buffer;
-		res = 1; /* succeed */
-
-		if (dev >= MAX_NFTLS * 16) {
-			/* there is no such partition */
-			printk("nftl: bad minor number: device = %s\n",
-			       kdevname(req->rq_dev));
-			res = 0; /* fail */
-			goto repeat;
-		}
-		
-		nftl = NFTLs[dev / 16];
-		DEBUG(MTD_DEBUG_LEVEL3, "Waiting for mutex\n");
-		down(&nftl->mutex);
-		DEBUG(MTD_DEBUG_LEVEL3, "Got mutex\n");
-
-		if (block + nsect > part_table[dev].nr_sects) {
-			/* access past the end of device */
-			printk("nftl%c%d: bad access: block = %d, count = %d\n",
-			       (MINOR(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect);
-			up(&nftl->mutex);
-			res = 0; /* fail */
-			goto repeat;
-		}
-		
-		block += part_table[dev].start_sect;
-		
-		if (req->cmd == READ) {
-			DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request of 0x%x sectors @ %x "
-			      "(req->nr_sectors == %lx)\n", nsect, block, req->nr_sectors);
-	
-			for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
-				/* Read a single sector to req->buffer + (512 * i) */
-				if (NFTL_readblock(nftl, block, buffer)) {
-					DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request failed\n");
-					up(&nftl->mutex);
-					res = 0;
-					goto repeat;
-				}
-			}
-
-			DEBUG(MTD_DEBUG_LEVEL2,"NFTL read request completed OK\n");
-			up(&nftl->mutex);
-			goto repeat;
-		} else if (req->cmd == WRITE) {
-			DEBUG(MTD_DEBUG_LEVEL2, "NFTL write request of 0x%x sectors @ %x "
-			      "(req->nr_sectors == %lx)\n", nsect, block,
-			      req->nr_sectors);
-#ifdef CONFIG_NFTL_RW
-			for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
-				/* Read a single sector to req->buffer + (512 * i) */
-				if (NFTL_writeblock(nftl, block, buffer)) {
-					DEBUG(MTD_DEBUG_LEVEL1,"NFTL write request failed\n");
-					up(&nftl->mutex);
-					res = 0;
-					goto repeat;
-				}
-			}
-			DEBUG(MTD_DEBUG_LEVEL2,"NFTL write request completed OK\n");
-#else
-			res = 0; /* Writes always fail */
-#endif /* CONFIG_NFTL_RW */
-			up(&nftl->mutex);
-			goto repeat;
-		} else {
-			DEBUG(MTD_DEBUG_LEVEL0, "NFTL unknown request\n");
-			up(&nftl->mutex);
-			res = 0;
-			goto repeat;
-		}
-	repeat: 
-		DEBUG(MTD_DEBUG_LEVEL3, "end_request(%d)\n", res);
-		spin_lock_irq(&io_request_lock);
-		end_request(res);
-	}
-}
-
-static int nftl_open(struct inode *ip, struct file *fp)
-{
-	int nftlnum = MINOR(ip->i_rdev) / 16;
-	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++;
-	MOD_INC_USE_COUNT;
-	if (!get_mtd_device(thisNFTL->mtd, -1)) {
-		MOD_DEC_USE_COUNT;
-		return /* -E'SBUGGEREDOFF */ -ENXIO;
-	}
-
-	return 0;
-}
-
-static int nftl_release(struct inode *inode, struct file *fp)
-{
-	struct NFTLrecord *thisNFTL;
-
-	thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16];
-
-	DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n");
-
-	invalidate_device(inode->i_rdev, 1);
-
-	if (thisNFTL->mtd->sync)
-		thisNFTL->mtd->sync(thisNFTL->mtd);
-	thisNFTL->usecount--;
-	MOD_DEC_USE_COUNT;
-
-	put_mtd_device(thisNFTL->mtd);
-
-	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 = 
-{
-	open:		nftl_open,
-	release:	nftl_release,
-	ioctl: 		nftl_ioctl
-};
-#endif
-
-
-
-/****************************************************************************
- *
- * Module stuff
- *
- ****************************************************************************/
-
-#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
-#define init_nftl init_module
-#define cleanup_nftl cleanup_module
-#endif
-
-static struct mtd_notifier nftl_notifier = {NFTL_notify_add, NFTL_notify_remove, NULL};
-
-/* static int __init init_nftl(void) */
-int __init init_nftl(void)
-{
-	int i;
-
-	printk(KERN_NOTICE
-	       "M-Systems NAND Flash Translation Layer driver. (C) 1999 MVHI\n");
-#ifdef PRERELEASE 
-	printk(KERN_INFO"$Id: nftl.c,v 1.57 2000/12/01 17:51:54 dwmw2 Exp $\n");
-#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 {
-#if LINUX_VERSION_CODE < 0x20320
-		blk_dev[MAJOR_NR].request_fn = nftl_request;
-#else
-		blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &nftl_request);
-#endif
-		/* set block size to 1kB each */
-		for (i = 0; i < 256; i++) {
-			nftl_blocksizes[i] = 1024;
-		}
-		blksize_size[MAJOR_NR] = nftl_blocksizes;
-
-		nftl_gendisk.next = gendisk_head;
-		gendisk_head = &nftl_gendisk;
-	}
-	
-	register_mtd_user(&nftl_notifier);
-
-	return 0;
-}
-
-static void __exit cleanup_nftl(void)
-{
-	struct gendisk *gd, **gdp;
-
-  	unregister_mtd_user(&nftl_notifier);
-  	unregister_blkdev(MAJOR_NR, "nftl");
-  	
-#if LINUX_VERSION_CODE < 0x20320
-  	blk_dev[MAJOR_NR].request_fn = 0;
-#else
-  	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-#endif	
-
-	/* remove ourself from generic harddisk list
-	   FIXME: why can't I found this partition on /proc/partition */
-  	for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
-    		if (*gdp == &nftl_gendisk) {
-      			gd = *gdp; *gdp = gd->next;
-      			break;
-    	}
-}
-
-module_init(init_nftl);
-module_exit(cleanup_nftl);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/nftlcore.c linux/drivers/mtd/nftlcore.c
--- v2.4.5/linux/drivers/mtd/nftlcore.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/nftlcore.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,1094 @@
+/* Linux driver for NAND Flash Translation Layer      */
+/* (c) 1999 Machine Vision Holdings, Inc.             */
+/* Author: David Woodhouse <dwmw2@infradead.org>      */
+/* $Id: nftlcore.c,v 1.73 2001/06/09 01:09:43 dwmw2 Exp $ */
+
+/*
+  The contents of this file are distributed under the GNU General
+  Public License version 2. The author places no additional
+  restrictions of any kind on it.
+ */
+
+#define PRERELEASE
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/blkpg.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nftl.h>
+#include <linux/mtd/compatmac.h>
+
+/* maximum number of loops while examining next block, to have a
+   chance to detect consistency problems (they should never happen
+   because of the checks done in the mounting */
+
+#define MAX_LOOPS 10000
+
+/* NFTL block device stuff */
+#define MAJOR_NR NFTL_MAJOR
+#define DEVICE_REQUEST nftl_request
+#define DEVICE_OFF(device)
+
+
+#include <linux/blk.h>
+#include <linux/hdreg.h>
+
+/* Linux-specific block device functions */
+
+/* I _HATE_ the Linux block device setup more than anything else I've ever
+ *  encountered, except ...
+ */
+
+static int nftl_sizes[256];
+static int nftl_blocksizes[256];
+
+/* .. for the Linux partition table handling. */
+struct hd_struct part_table[256];
+
+#if LINUX_VERSION_CODE < 0x20328
+static void dummy_init (struct gendisk *crap)
+{}
+#endif
+
+static struct gendisk nftl_gendisk = {
+	major:		MAJOR_NR,
+	major_name:	"nftl",
+	minor_shift:	NFTL_PARTN_BITS,	/* Bits to shift to get real from partition */
+	max_p:		(1<<NFTL_PARTN_BITS)-1,	/* Number of partitions per real */
+#if LINUX_VERSION_CODE < 0x20328
+	max_nr:		MAX_NFTLS,      /* maximum number of real */
+	init:		dummy_init,     /* init function */
+#endif
+	part:		part_table,     /* hd struct */
+	sizes:		nftl_sizes,     /* block sizes */
+};
+
+struct NFTLrecord *NFTLs[MAX_NFTLS];
+
+static void NFTL_setup(struct mtd_info *mtd)
+{
+	int i;
+	struct NFTLrecord *nftl;
+	unsigned long temp;
+	int firstfree = -1;
+
+	DEBUG(MTD_DEBUG_LEVEL1,"NFTL_setup\n");
+
+	for (i = 0; i < MAX_NFTLS; i++) {
+		if (!NFTLs[i] && firstfree == -1)
+			firstfree = i;
+		else if (NFTLs[i] && NFTLs[i]->mtd == mtd) {
+			/* This is a Spare Media Header for an NFTL we've already found */
+			DEBUG(MTD_DEBUG_LEVEL1, "MTD already mounted as NFTL\n");
+			return;
+		}
+	}
+        if (firstfree == -1) {
+		printk(KERN_WARNING "No more NFTL slot available\n");
+		return;
+        }
+
+	nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
+	if (!nftl) {
+		printk(KERN_WARNING "Out of memory for NFTL data structures\n");
+		return;
+	}
+
+	init_MUTEX(&nftl->mutex);
+
+        /* get physical parameters */
+	nftl->EraseSize = mtd->erasesize;
+        nftl->nb_blocks = mtd->size / mtd->erasesize;
+	nftl->mtd = mtd;
+
+        if (NFTL_mount(nftl) < 0) {
+		printk(KERN_WARNING "Could not mount NFTL 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;
+	nftl->cylinders = 1024;
+	nftl->heads = 16;
+
+	temp = nftl->cylinders * nftl->heads;
+	nftl->sectors = nftl->nr_sects / temp;
+	if (nftl->nr_sects % temp) {
+		nftl->sectors++;
+		temp = nftl->cylinders * nftl->sectors;
+		nftl->heads = nftl->nr_sects / temp;
+
+		if (nftl->nr_sects % temp) {
+			nftl->heads++;
+			temp = nftl->heads * nftl->sectors;
+			nftl->cylinders = nftl->nr_sects / temp;
+		}
+	}
+
+	if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) {
+		printk(KERN_WARNING "Cannot calculate an NFTL geometry to "
+		       "match size of 0x%lx.\n", nftl->nr_sects);
+		printk(KERN_WARNING "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; */
+	}
+	NFTLs[firstfree] = nftl;
+	/* Finally, set up the block device sizes */
+	nftl_sizes[firstfree * 16] = nftl->nr_sects;
+	//nftl_blocksizes[firstfree*16] = 512;
+	part_table[firstfree * 16].nr_sects = nftl->nr_sects;
+
+	nftl_gendisk.nr_real++;
+
+	/* partition check ... */
+#if LINUX_VERSION_CODE < 0x20328
+	resetup_one_dev(&nftl_gendisk, firstfree);
+#else
+	grok_partitions(&nftl_gendisk, firstfree, 1<<NFTL_PARTN_BITS, nftl->nr_sects);
+#endif
+}
+
+static void NFTL_unsetup(int i)
+{
+	struct NFTLrecord *nftl = NFTLs[i];
+
+	DEBUG(MTD_DEBUG_LEVEL1, "NFTL_unsetup %d\n", i);
+	
+	NFTLs[i] = NULL;
+	
+	if (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);
+	}
+}
+
+static void NFTL_notify_remove(struct mtd_info *mtd)
+{
+	int i;
+
+	for (i = 0; i < MAX_NFTLS; i++) {
+		if (NFTLs[i] && NFTLs[i]->mtd == mtd)
+			NFTL_unsetup(i);
+	}
+}
+
+#ifdef CONFIG_NFTL_RW
+
+/* Actual NFTL access routines */
+/* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used
+ *	when the give Virtual Unit Chain
+ */
+static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
+{
+	/* For a given Virtual Unit Chain: find or create a free block and
+	   add it to the chain */
+	/* We're passed the number of the last EUN in the chain, to save us from
+	   having to look it up again */
+	u16 pot = nftl->LastFreeEUN;
+	int silly = -1;
+
+	/* Normally, we force a fold to happen before we run out of free blocks completely */
+	if (!desperate && nftl->numfreeEUNs < 2) {
+		DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n");
+		return 0xffff;
+	}
+
+	/* Scan for a free block */
+	do {
+		if (nftl->ReplUnitTable[pot] == BLOCK_FREE) {
+			nftl->LastFreeEUN = pot;
+			nftl->numfreeEUNs--;
+			return pot;
+		}
+
+		/* This will probably point to the MediaHdr unit itself,
+		   right at the beginning of the partition. But that unit
+		   (and the backup unit too) should have the UCI set
+		   up so that it's not selected for overwriting */
+		if (++pot > nftl->lastEUN)
+			pot = le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN);
+
+		if (!silly--) {
+			printk("Argh! No free blocks found! LastFreeEUN = %d, "
+			       "FirstEUN = %d\n", nftl->LastFreeEUN, 
+			       le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
+			return 0xffff;
+		}
+	} while (pot != nftl->LastFreeEUN);
+
+	return 0xffff;
+}
+
+static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
+{
+	u16 BlockMap[MAX_SECTORS_PER_UNIT];
+	unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];
+	unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];
+	unsigned int thisEUN;
+	int block;
+	int silly;
+	unsigned int targetEUN;
+	struct nftl_oob oob;
+	int inplace = 1;
+        size_t retlen;
+
+	memset(BlockMap, 0xff, sizeof(BlockMap));
+	memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
+
+	thisEUN = nftl->EUNtable[thisVUC];
+
+	if (thisEUN == BLOCK_NIL) {
+		printk(KERN_WARNING "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;
+	targetEUN = BLOCK_NIL;
+	while (thisEUN <= nftl->lastEUN ) {
+                unsigned int status, foldmark;
+
+		targetEUN = thisEUN;
+		for (block = 0; block < nftl->EraseSize / 512; block ++) {
+			MTD_READOOB(nftl->mtd,
+				    (thisEUN * nftl->EraseSize) + (block * 512),
+				    16 , &retlen, (char *)&oob);
+			if (block == 2) {
+                                foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
+                                if (foldmark == FOLD_MARK_IN_PROGRESS) {
+                                        DEBUG(MTD_DEBUG_LEVEL1, 
+                                              "Write Inhibited on EUN %d\n", thisEUN);
+					inplace = 0;
+				} else {
+					/* There's no other reason not to do inplace,
+					   except ones that come later. So we don't need
+					   to preserve inplace */
+					inplace = 1;
+				}
+			}
+                        status = oob.b.Status | oob.b.Status1;
+			BlockLastState[block] = status;
+
+			switch(status) {
+			case SECTOR_FREE:
+				BlockFreeFound[block] = 1;
+				break;
+
+			case SECTOR_USED:
+				if (!BlockFreeFound[block])
+					BlockMap[block] = thisEUN;
+				else
+					printk(KERN_WARNING 
+					       "SECTOR_USED found after SECTOR_FREE "
+					       "in Virtual Unit Chain %d for block %d\n",
+					       thisVUC, block);
+				break;
+			case SECTOR_IGNORE:
+			case SECTOR_DELETED:
+				break;
+			default:
+				printk("Unknown status for block %d in EUN %d: %x\n",
+				       block, thisEUN, status);
+			}
+		}
+
+		if (!silly--) {
+			printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
+			       thisVUC);
+			return BLOCK_NIL;
+		}
+		
+		thisEUN = nftl->ReplUnitTable[thisEUN];
+	}
+
+	if (inplace) {
+		/* We're being asked to be a fold-in-place. Check
+		   that all blocks are either present or SECTOR_FREE
+		   in the target block. If not, we're going to have
+		   to fold out-of-place anyway.
+		*/
+		for (block = 0; block < nftl->EraseSize / 512 ; block++) {
+			if (BlockLastState[block] != SECTOR_FREE &&
+			    BlockMap[block] != targetEUN) {
+				DEBUG(MTD_DEBUG_LEVEL1, "Setting inplace to 0. VUC %d, "
+				      "block %d was %x lastEUN, "
+				      "and is in EUN %d (%s) %d\n",
+				      thisVUC, block, BlockLastState[block],
+				      BlockMap[block], 
+				      BlockMap[block]== targetEUN ? "==" : "!=",
+				      targetEUN);
+				inplace = 0;
+				break;
+			}
+		}
+
+		if (pendingblock >= (thisVUC * (nftl->EraseSize / 512)) &&
+		    pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) &&
+		    BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] !=
+		    SECTOR_FREE) {
+			DEBUG(MTD_DEBUG_LEVEL1, "Pending write not free in EUN %d. "
+			      "Folding out of place.\n", targetEUN);
+			inplace = 0;
+		}
+	}
+	
+	if (!inplace) {
+		DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. "
+		      "Trying out-of-place\n", thisVUC);
+		/* We need to find a targetEUN to fold into. */
+		targetEUN = NFTL_findfreeblock(nftl, 1);
+		if (targetEUN == BLOCK_NIL) {
+			/* Ouch. Now we're screwed. We need to do a 
+			   fold-in-place of another chain to make room
+			   for this one. We need a better way of selecting
+			   which chain to fold, because makefreeblock will 
+			   only ask us to fold the same one again.
+			*/
+			printk(KERN_WARNING
+			       "NFTL_findfreeblock(desperate) returns 0xffff.\n");
+			return BLOCK_NIL;
+		}
+	} else {
+            /* We put a fold mark in the chain we are folding only if
+               we fold in place to help the mount check code. If we do
+               not fold in place, it is possible to find the valid
+               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, 
+                         8, &retlen, (char *)&oob.u);
+        }
+
+	/* 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,"Folding chain %d into unit %d\n", thisVUC, targetEUN);
+	for (block = 0; block < nftl->EraseSize / 512 ; block++) {
+		unsigned char movebuf[512];
+		int ret;
+
+		/* If it's in the target EUN already, or if it's pending write, do nothing */
+		if (BlockMap[block] == targetEUN ||
+		    (pendingblock == (thisVUC * (nftl->EraseSize / 512) + 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_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
+                                  + (block * 512), 512, &retlen, movebuf, (char *)&oob); 
+                if (ret < 0) {
+                    ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
+                                      + (block * 512), 512, &retlen,
+                                      movebuf, (char *)&oob); 
+                    if (ret != -EIO) 
+                        printk("Error went away on retry.\n");
+                }
+                MTD_WRITEECC(nftl->mtd, (nftl->EraseSize * targetEUN) + (block * 512),
+                             512, &retlen, movebuf, (char *)&oob);
+	}
+        
+        /* add the header so that it is now a valid chain */
+        oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum
+                = cpu_to_le16(thisVUC);
+        oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
+        
+        MTD_WRITEOOB(nftl->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. */
+
+	/* At this point, we have two different chains for this Virtual Unit, and no way to tell 
+	   them apart. If we crash now, we get confused. However, both contain the same data, so we
+	   shouldn't actually lose data in this case. It's just that when we load up on a medium which
+	   has duplicate chains, we need to free one of the chains because it's not necessary any more.
+	*/
+	thisEUN = nftl->EUNtable[thisVUC];
+	DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
+
+	/* For each block in the old chain (except the targetEUN of course), 
+	   free it and make it available for future use */
+	while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
+		unsigned int EUNtmp;
+
+                EUNtmp = nftl->ReplUnitTable[thisEUN];
+
+                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 {
+			/* correctly erased : mark it as free */
+			nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
+			nftl->numfreeEUNs++;
+                }
+                thisEUN = EUNtmp;
+	}
+	
+	/* Make this the new start of chain for thisVUC */
+	nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
+	nftl->EUNtable[thisVUC] = targetEUN;
+
+	return targetEUN;
+}
+
+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
+	   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;
+
+	for (chain = 0; chain < nftl->MediaHdr.FormattedSize / nftl->EraseSize; chain++) {
+		EUN = nftl->EUNtable[chain];
+		thislen = 0;
+
+		while (EUN <= nftl->lastEUN) {
+			thislen++;
+			//printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);
+			EUN = nftl->ReplUnitTable[EUN] & 0x7fff;
+			if (thislen > 0xff00) {
+				printk("Endless loop in Virtual Chain %d: Unit %x\n",
+				       chain, EUN);
+			}
+			if (thislen > 0xff10) {
+				/* Actually, don't return failure. Just ignore this chain and
+				   get on with it. */
+				thislen = 0;
+				break;
+			}
+		}
+
+		if (thislen > ChainLength) {
+			//printk("New longest chain is %d with length %d\n", chain, thislen);
+			ChainLength = thislen;
+			LongestChain = chain;
+		}
+	}
+
+	if (ChainLength < 2) {
+		printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
+		       "Failing request\n");
+		return 0xffff;
+	}
+
+	return NFTL_foldchain (nftl, LongestChain, pendingblock);
+}
+
+/* NFTL_findwriteunit: Return the unit number into which we can write 
+                       for this block. Make it available if it isn't already
+*/
+static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
+{
+	u16 lastEUN;
+	u16 thisVUC = block / (nftl->EraseSize / 512);
+	unsigned int writeEUN;
+	unsigned long blockofs = (block * 512) & (nftl->EraseSize -1);
+	size_t retlen;
+	int silly, silly2 = 3;
+	struct nftl_oob oob;
+
+	do {
+		/* Scan the media to find a unit in the VUC which has
+		   a free space for the block in question.
+		*/
+
+		/* This condition catches the 0x[7f]fff cases, as well as 
+		   being a sanity check for past-end-of-media access
+		*/
+		lastEUN = BLOCK_NIL;
+		writeEUN = nftl->EUNtable[thisVUC];
+                silly = MAX_LOOPS;
+		while (writeEUN <= nftl->lastEUN) {
+			struct nftl_bci bci;
+			size_t retlen;
+                        unsigned int status;
+
+			lastEUN = writeEUN;
+
+			MTD_READOOB(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
+				    8, &retlen, (char *)&bci);
+			
+			DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
+			      block , writeEUN, le16_to_cpu(bci.Status));
+
+                        status = bci.Status | bci.Status1;
+			switch(status) {
+			case SECTOR_FREE:
+				return writeEUN;
+
+			case SECTOR_DELETED:
+			case SECTOR_USED:
+			case SECTOR_IGNORE:
+				break;
+			default:
+				// Invalid block. Don't use it any more. Must implement.
+				break;			
+			}
+			
+			if (!silly--) { 
+				printk(KERN_WARNING
+				       "Infinite loop in Virtual Unit Chain 0x%x\n",
+				       thisVUC);
+				return 0xffff;
+			}
+
+			/* Skip to next block in chain */
+			writeEUN = nftl->ReplUnitTable[writeEUN];
+		}
+
+		/* OK. We didn't find one in the existing chain, or there 
+		   is no existing chain. */
+
+		/* Try to find an already-free block */
+		writeEUN = NFTL_findfreeblock(nftl, 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.
+			*/
+
+			/* First remember the start of this chain */
+			//u16 startEUN = nftl->EUNtable[thisVUC];
+			
+			//printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
+			writeEUN = NFTL_makefreeblock(nftl, 0xffff);
+
+			if (writeEUN == BLOCK_NIL) {
+				/* OK, we accept that the above comment is 
+				   lying - there may have been free blocks
+				   last time we called NFTL_findfreeblock(),
+				   but they are reserved for when we're
+				   desperate. Well, now we're desperate.
+				*/
+				DEBUG(MTD_DEBUG_LEVEL1, "Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC);
+				writeEUN = NFTL_findfreeblock(nftl, 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 "Cannot make free space.\n");
+				return BLOCK_NIL;
+			}			
+			//printk("Restarting scan\n");
+			lastEUN = BLOCK_NIL;
+			continue;
+		}
+
+		/* We've found a free block. Insert it into the chain. */
+		
+		if (lastEUN != BLOCK_NIL) {
+                    thisVUC |= 0x8000; /* It's a replacement block */
+		} else {
+                    /* The first block in a new chain */
+                    nftl->EUNtable[thisVUC] = writeEUN;
+		}
+
+		/* set up the actual EUN we're writing into */
+		/* Both in our cache... */
+		nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
+
+		/* ... and on the flash itself */
+		MTD_READOOB(nftl->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,
+                             &retlen, (char *)&oob.u);
+
+                /* we link the new block to the chain only after the
+                   block is ready. It avoids the case where the chain
+                   could point to a free block */
+                if (lastEUN != BLOCK_NIL) {
+			/* Both in our cache... */
+			nftl->ReplUnitTable[lastEUN] = writeEUN;
+			/* ... and on the flash itself */
+			MTD_READOOB(nftl->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,
+				     8, &retlen, (char *)&oob.u);
+		}
+
+		return writeEUN;
+
+	} while (silly2--);
+
+	printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
+	       thisVUC);
+	return 0xffff;
+}
+
+static int NFTL_writeblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
+{
+	u16 writeEUN;
+	unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
+	size_t retlen;
+	u8 eccbuf[6];
+
+	writeEUN = NFTL_findwriteunit(nftl, block);
+
+	if (writeEUN == BLOCK_NIL) {
+		printk(KERN_WARNING
+		       "NFTL_writeblock(): Cannot find block to write to\n");
+		/* If we _still_ haven't got a block to use, we're screwed */
+		return 1;
+	}
+
+	MTD_WRITEECC(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
+		     512, &retlen, (char *)buffer, (char *)eccbuf);
+        /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */
+
+	return 0;
+}
+#endif /* CONFIG_NFTL_RW */
+
+static int NFTL_readblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
+{
+	u16 lastgoodEUN;
+	u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
+	unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
+        unsigned int status;
+	int silly = MAX_LOOPS;
+        size_t retlen;
+        struct nftl_bci bci;
+
+	lastgoodEUN = BLOCK_NIL;
+
+        if (thisEUN != BLOCK_NIL) {
+		while (thisEUN < nftl->nb_blocks) {
+			if (MTD_READOOB(nftl->mtd, (thisEUN * nftl->EraseSize) + blockofs,
+					8, &retlen, (char *)&bci) < 0)
+				status = SECTOR_IGNORE;
+			else
+				status = bci.Status | bci.Status1;
+
+			switch (status) {
+			case SECTOR_FREE:
+				/* no modification of a sector should follow a free sector */
+				goto the_end;
+			case SECTOR_DELETED:
+				lastgoodEUN = BLOCK_NIL;
+				break;
+			case SECTOR_USED:
+				lastgoodEUN = thisEUN;
+				break;
+			case SECTOR_IGNORE:
+				break;
+			default:
+				printk("Unknown status for block %d in EUN %d: %x\n",
+				       block, thisEUN, status);
+				break;
+			}
+
+			if (!silly--) {
+				printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
+				       block / (nftl->EraseSize / 512));
+				return 1;
+			}
+			thisEUN = nftl->ReplUnitTable[thisEUN];
+		}
+        }
+
+ the_end:
+	if (lastgoodEUN == BLOCK_NIL) {
+		/* the requested block is not on the media, return all 0x00 */
+		memset(buffer, 0, 512);
+	} 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))
+			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 */
+		if (!arg) return -EINVAL;
+		return put_user(part_table[MINOR(inode->i_rdev)].nr_sects,
+                                (long *) arg);
+		
+	case BLKFLSBUF:
+		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+		fsync_dev(inode->i_rdev);
+		invalidate_buffers(inode->i_rdev);
+		if (nftl->mtd->sync)
+			nftl->mtd->sync(nftl->mtd);
+		return 0;
+
+	case BLKRRPART:
+		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+		if (nftl->usecount > 1) return -EBUSY;
+		/* 
+		 * We have to flush all buffers and invalidate caches,
+		 * or we won't be able to re-use the partitions,
+		 * if there was a change and we don't want to reboot
+		 */
+		p = (1<<NFTL_PARTN_BITS) - 1;
+		while (p-- > 0) {
+			kdev_t devp = MKDEV(MAJOR(inode->i_dev), MINOR(inode->i_dev)+p);
+			if (part_table[p].nr_sects > 0)
+				invalidate_device (devp, 1);
+
+			part_table[MINOR(inode->i_dev)+p].start_sect = 0;
+			part_table[MINOR(inode->i_dev)+p].nr_sects = 0;
+		}
+		
+#if LINUX_VERSION_CODE < 0x20328
+		resetup_one_dev(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS);
+#else
+		grok_partitions(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS,
+				1<<NFTL_PARTN_BITS, nftl->nr_sects);
+#endif
+		return 0;
+
+#if (LINUX_VERSION_CODE < 0x20303)		
+	RO_IOCTLS(inode->i_rdev, arg);  /* ref. linux/blk.h */
+#else
+	case BLKROSET:
+	case BLKROGET:
+	case BLKSSZGET:
+		return blk_ioctl(inode->i_rdev, cmd, arg);
+#endif
+
+	default:
+		return -EINVAL;
+	}
+}
+
+void nftl_request(RQFUNC_ARG)
+{
+	unsigned int dev, block, nsect;
+	struct NFTLrecord *nftl;
+	char *buffer;
+	struct request *req;
+	int res;
+
+	while (1) {
+		INIT_REQUEST;	/* blk.h */
+		req = CURRENT;
+		
+		/* We can do this because the generic code knows not to
+		   touch the request at the head of the queue */
+		spin_unlock_irq(&io_request_lock);
+
+		DEBUG(MTD_DEBUG_LEVEL2, "NFTL_request\n");
+		DEBUG(MTD_DEBUG_LEVEL3, "NFTL %s request, from sector 0x%04lx for 0x%04lx sectors\n",
+		      (req->cmd == READ) ? "Read " : "Write",
+		      req->sector, req->current_nr_sectors);
+
+		dev = MINOR(req->rq_dev);
+		block = req->sector;
+		nsect = req->current_nr_sectors;
+		buffer = req->buffer;
+		res = 1; /* succeed */
+
+		if (dev >= MAX_NFTLS * (1<<NFTL_PARTN_BITS)) {
+			/* there is no such partition */
+			printk("nftl: bad minor number: device = %s\n",
+			       kdevname(req->rq_dev));
+			res = 0; /* fail */
+			goto repeat;
+		}
+		
+		nftl = NFTLs[dev / (1<<NFTL_PARTN_BITS)];
+		DEBUG(MTD_DEBUG_LEVEL3, "Waiting for mutex\n");
+		down(&nftl->mutex);
+		DEBUG(MTD_DEBUG_LEVEL3, "Got mutex\n");
+
+		if (block + nsect > part_table[dev].nr_sects) {
+			/* access past the end of device */
+			printk("nftl%c%d: bad access: block = %d, count = %d\n",
+			       (MINOR(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect);
+			up(&nftl->mutex);
+			res = 0; /* fail */
+			goto repeat;
+		}
+		
+		block += part_table[dev].start_sect;
+		
+		if (req->cmd == READ) {
+			DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request of 0x%x sectors @ %x "
+			      "(req->nr_sectors == %lx)\n", nsect, block, req->nr_sectors);
+	
+			for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
+				/* Read a single sector to req->buffer + (512 * i) */
+				if (NFTL_readblock(nftl, block, buffer)) {
+					DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request failed\n");
+					up(&nftl->mutex);
+					res = 0;
+					goto repeat;
+				}
+			}
+
+			DEBUG(MTD_DEBUG_LEVEL2,"NFTL read request completed OK\n");
+			up(&nftl->mutex);
+			goto repeat;
+		} else if (req->cmd == WRITE) {
+			DEBUG(MTD_DEBUG_LEVEL2, "NFTL write request of 0x%x sectors @ %x "
+			      "(req->nr_sectors == %lx)\n", nsect, block,
+			      req->nr_sectors);
+#ifdef CONFIG_NFTL_RW
+			for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
+				/* Read a single sector to req->buffer + (512 * i) */
+				if (NFTL_writeblock(nftl, block, buffer)) {
+					DEBUG(MTD_DEBUG_LEVEL1,"NFTL write request failed\n");
+					up(&nftl->mutex);
+					res = 0;
+					goto repeat;
+				}
+			}
+			DEBUG(MTD_DEBUG_LEVEL2,"NFTL write request completed OK\n");
+#else
+			res = 0; /* Writes always fail */
+#endif /* CONFIG_NFTL_RW */
+			up(&nftl->mutex);
+			goto repeat;
+		} else {
+			DEBUG(MTD_DEBUG_LEVEL0, "NFTL unknown request\n");
+			up(&nftl->mutex);
+			res = 0;
+			goto repeat;
+		}
+	repeat: 
+		DEBUG(MTD_DEBUG_LEVEL3, "end_request(%d)\n", res);
+		spin_lock_irq(&io_request_lock);
+		end_request(res);
+	}
+}
+
+static int nftl_open(struct inode *ip, struct file *fp)
+{
+	int nftlnum = MINOR(ip->i_rdev) >> NFTL_PARTN_BITS;
+	struct NFTLrecord *thisNFTL;
+	thisNFTL = NFTLs[nftlnum];
+
+	DEBUG(MTD_DEBUG_LEVEL2,"NFTL_open\n");
+
+#ifdef CONFIG_KMOD
+	if (!thisNFTL && nftlnum == 0) {
+		request_module("docprobe");
+		thisNFTL = NFTLs[nftlnum];
+	}
+#endif
+	if (!thisNFTL) {
+		DEBUG(MTD_DEBUG_LEVEL2,"ENODEV: thisNFTL = %d, minor = %d, ip = %p, fp = %p\n", 
+		      nftlnum, ip->i_rdev, ip, fp);
+		return -ENODEV;
+	}
+
+#ifndef CONFIG_NFTL_RW
+	if (fp->f_mode & FMODE_WRITE)
+		return -EROFS;
+#endif /* !CONFIG_NFTL_RW */
+
+	thisNFTL->usecount++;
+	MOD_INC_USE_COUNT;
+	if (!get_mtd_device(thisNFTL->mtd, -1)) {
+		MOD_DEC_USE_COUNT;
+		return /* -E'SBUGGEREDOFF */ -ENXIO;
+	}
+
+	return 0;
+}
+
+static int nftl_release(struct inode *inode, struct file *fp)
+{
+	struct NFTLrecord *thisNFTL;
+
+	thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16];
+
+	DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n");
+
+	invalidate_device(inode->i_rdev, 1);
+
+	if (thisNFTL->mtd->sync)
+		thisNFTL->mtd->sync(thisNFTL->mtd);
+	thisNFTL->usecount--;
+	MOD_DEC_USE_COUNT;
+
+	put_mtd_device(thisNFTL->mtd);
+
+	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 = 
+{
+	open:		nftl_open,
+	release:	nftl_release,
+	ioctl: 		nftl_ioctl
+};
+#endif
+
+
+
+/****************************************************************************
+ *
+ * Module stuff
+ *
+ ****************************************************************************/
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define init_nftl init_module
+#define cleanup_nftl cleanup_module
+#endif
+
+static struct mtd_notifier nftl_notifier = {
+	add:	NFTL_notify_add,
+	remove:	NFTL_notify_remove
+};
+
+static int __init init_nftl(void)
+{
+	int i;
+
+	printk(KERN_NOTICE
+	       "M-Systems NAND Flash Translation Layer driver. (C) 1999 MVHI\n");
+#ifdef PRERELEASE 
+	printk(KERN_INFO"$Id: nftlcore.c,v 1.73 2001/06/09 01:09:43 dwmw2 Exp $\n");
+#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 {
+#if LINUX_VERSION_CODE < 0x20320
+		blk_dev[MAJOR_NR].request_fn = nftl_request;
+#else
+		blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &nftl_request);
+#endif
+		/* set block size to 1kB each */
+		for (i = 0; i < 256; i++) {
+			nftl_blocksizes[i] = 1024;
+		}
+		blksize_size[MAJOR_NR] = nftl_blocksizes;
+
+		nftl_gendisk.next = gendisk_head;
+		gendisk_head = &nftl_gendisk;
+	}
+	
+	register_mtd_user(&nftl_notifier);
+
+	return 0;
+}
+
+static void __exit cleanup_nftl(void)
+{
+	struct gendisk *gd, **gdp;
+
+  	unregister_mtd_user(&nftl_notifier);
+  	unregister_blkdev(MAJOR_NR, "nftl");
+  	
+#if LINUX_VERSION_CODE < 0x20320
+  	blk_dev[MAJOR_NR].request_fn = 0;
+#else
+  	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+#endif	
+
+	/* remove ourself from generic harddisk list
+	   FIXME: why can't I found this partition on /proc/partition */
+  	for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
+    		if (*gdp == &nftl_gendisk) {
+      			gd = *gdp; *gdp = gd->next;
+      			break;
+		}
+}
+
+module_init(init_nftl);
+module_exit(cleanup_nftl);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/nftlmount.c linux/drivers/mtd/nftlmount.c
--- v2.4.5/linux/drivers/mtd/nftlmount.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/nftlmount.c	Tue Jun 12 10:30:27 2001
@@ -4,7 +4,7 @@
  * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
  * Copyright (C) 2000 Netgem S.A.
  *
- * $Id: nftlmount.c,v 1.11 2000/11/17 12:24:09 ollie Exp $
+ * $Id: nftlmount.c,v 1.17 2001/06/02 20:33:20 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
@@ -20,6 +20,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+
+#define __NO_VERSION__
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <asm/errno.h>
@@ -85,13 +87,20 @@
 				}
 
 				nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
-				if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks)
+				if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
+					printk(KERN_NOTICE "Potential NFTL Media Header found, but sanity check failed:\n");
+					printk(KERN_NOTICE "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n", 
+					       nftl->nb_boot_blocks, nftl->nb_blocks);
 					goto ReplUnitTable; /* small consistency check */
+				}
 
 				nftl->numvunits = le32_to_cpu(mh->FormattedSize) / nftl->EraseSize;
-				if (nftl->numvunits > (nftl->nb_blocks - nftl->nb_boot_blocks - 2))
+				if (nftl->numvunits > (nftl->nb_blocks - nftl->nb_boot_blocks - 2)) {
+					printk(KERN_NOTICE "Potential NFTL Media Header found, but sanity check failed:\n");
+					printk(KERN_NOTICE "numvunits (%d) > nb_blocks (%d) - nb_boot_blocks(%d) - 2\n",
+					       nftl->numvunits, nftl->nb_blocks, nftl->nb_boot_blocks);
 					goto ReplUnitTable; /* small consistency check */
-
+				}
 				/* FixMe: with bad blocks, the total size available is not FormattedSize any
 				   more !!! */
 				nftl->nr_sects  = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
@@ -359,8 +368,7 @@
 {
 	struct nftl_uci1 h1;
 	unsigned int erase_mark;
-	int i, retlen;
-	unsigned char buf[SECTORSIZE];
+	int retlen;
 
 	/* check erase mark. */
 	if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, 
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/nora.c linux/drivers/mtd/nora.c
--- v2.4.5/linux/drivers/mtd/nora.c	Mon Dec 11 14:57:58 2000
+++ linux/drivers/mtd/nora.c	Wed Dec 31 16:00:00 1969
@@ -1,208 +0,0 @@
-/*
- * $Id: nora.c,v 1.17 2000/12/03 19:32:21 dwmw2 Exp $
- *
- * This is so simple I love it.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-
-
-#define WINDOW_ADDR 0xd0000000
-#define WINDOW_SIZE 0x04000000
-
-static struct mtd_info *mymtd;
-
-__u8 nora_read8(struct map_info *map, unsigned long ofs)
-{
-  return *(__u8 *)(WINDOW_ADDR + ofs);
-}
-
-__u16 nora_read16(struct map_info *map, unsigned long ofs)
-{
-  return *(__u16 *)(WINDOW_ADDR + ofs);
-}
-
-__u32 nora_read32(struct map_info *map, unsigned long ofs)
-{
-  return *(__u32 *)(WINDOW_ADDR + ofs);
-}
-
-void nora_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-  memcpy(to, (void *)(WINDOW_ADDR + from), len);
-}
-
-void nora_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-  *(__u8 *)(WINDOW_ADDR + adr) = d;
-}
-
-void nora_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-  *(__u16 *)(WINDOW_ADDR + adr) = d;
-}
-
-void nora_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-  *(__u32 *)(WINDOW_ADDR + adr) = d;
-}
-
-void nora_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 nora_map = {
-	name: "NORA",
-	size: WINDOW_SIZE,
-	buswidth: 2,
-	read8: nora_read8,
-	read16: nora_read16,
-	read32: nora_read32,
-	copy_from: nora_copy_from,
-	write8: nora_write8,
-	write16: nora_write16,
-	write32: nora_write32,
-	copy_to: nora_copy_to
-};
-
-
-static int nora_mtd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-{
-	return mymtd->read(mymtd, from + (unsigned long)mtd->priv, len, retlen, buf);
-}
-
-static int nora_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
-{
-	return mymtd->write(mymtd, to + (unsigned long)mtd->priv, len, retlen, buf);
-}
-
-static int nora_mtd_erase (struct mtd_info *mtd, struct erase_info *instr)
-{
-	instr->addr += (unsigned long)mtd->priv;
-	return mymtd->erase(mymtd, instr);
-}
-
-static void nora_mtd_sync (struct mtd_info *mtd)
-{
-	mymtd->sync(mymtd);
-}
-
-static int nora_mtd_suspend (struct mtd_info *mtd)
-{
-	return mymtd->suspend(mymtd);
-}
-
-static void nora_mtd_resume (struct mtd_info *mtd)
-{
-	mymtd->resume(mymtd);
-}
-
-
-static struct mtd_info nora_mtds[4] = {  /* boot, kernel, ramdisk, fs */
-	{
-		type: MTD_NORFLASH,
-		flags: MTD_CAP_NORFLASH,
-		size: 0x60000,
-		erasesize: 0x20000,
-		name: "NORA boot firmware",
-		module: THIS_MODULE,
-		erase: nora_mtd_erase,
-		read: nora_mtd_read,
-		write: nora_mtd_write,
-		suspend: nora_mtd_suspend,
-		resume: nora_mtd_resume,
-		sync: nora_mtd_sync,
-		priv: (void *)0
-	},
-	{
-		type: MTD_NORFLASH,
-		flags: MTD_CAP_NORFLASH,
-		size: 0x0a0000,
-		erasesize: 0x20000,
-		name: "NORA kernel",
-		module: THIS_MODULE,
-		erase: nora_mtd_erase,
-		read: nora_mtd_read,
-		write: nora_mtd_write,
-		suspend: nora_mtd_suspend,
-		resume: nora_mtd_resume,
-		sync: nora_mtd_sync,
-		priv: (void *)0x60000
-	},
-	{
-		type: MTD_NORFLASH,
-		flags: MTD_CAP_NORFLASH,
-		size: 0x900000,
-		erasesize: 0x20000,
-		name: "NORA root filesystem",
-		module: THIS_MODULE,
-		erase: nora_mtd_erase,
-		read: nora_mtd_read,
-		write: nora_mtd_write,
-		suspend: nora_mtd_suspend,
-		resume: nora_mtd_resume,
-		sync: nora_mtd_sync,
-		priv: (void *)0x100000
-	},
-	{
-		type: MTD_NORFLASH,
-		flags: MTD_CAP_NORFLASH,
-		size: 0x1600000,
-		erasesize: 0x20000,
-		name: "NORA second filesystem",
-		module: THIS_MODULE,
-		erase: nora_mtd_erase,
-		read: nora_mtd_read,
-		write: nora_mtd_write,
-		suspend: nora_mtd_suspend,
-		resume: nora_mtd_resume,
-		sync: nora_mtd_sync,
-		priv: (void *)0xa00000
-	}
-};
-
-
-#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
-#define init_nora init_module
-#define cleanup_nora cleanup_module
-#endif
-
-int __init init_nora(void)
-{
-       	printk(KERN_NOTICE "nora flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
-
-	mymtd = do_cfi_probe(&nora_map);
-	if (mymtd) {
-#ifdef MODULE
-		mymtd->module = &__this_module;
-#endif
-		
-		add_mtd_device(&nora_mtds[2]);
-		add_mtd_device(&nora_mtds[0]);
-		add_mtd_device(&nora_mtds[1]);
-		add_mtd_device(&nora_mtds[3]);
-		return 0;
-	}
-
-	return -ENXIO;
-}
-
-static void __exit cleanup_nora(void)
-{
-	if (mymtd) {
-		del_mtd_device(&nora_mtds[3]);
-		del_mtd_device(&nora_mtds[1]);
-		del_mtd_device(&nora_mtds[0]);
-		del_mtd_device(&nora_mtds[2]);
-		map_destroy(mymtd);
-	}
-}
-
-module_init(init_nora);
-module_exit(cleanup_nora);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/octagon-5066.c linux/drivers/mtd/octagon-5066.c
--- v2.4.5/linux/drivers/mtd/octagon-5066.c	Fri Feb 16 16:02:36 2001
+++ linux/drivers/mtd/octagon-5066.c	Wed Dec 31 16:00:00 1969
@@ -1,285 +0,0 @@
-// $Id: octagon-5066.c,v 1.12.2.1 2001/02/15 10:12:48 dwmw2 Exp $
-/* ######################################################################
-
-   Octagon 5066 MTD Driver. 
-  
-   The Octagon 5066 is a SBC based on AMD's 586-WB running at 133 MHZ. It
-   comes with a builtin AMD 29F016 flash chip and a socketed EEPROM that
-   is replacable by flash. Both units are mapped through a multiplexer
-   into a 32k memory window at 0xe8000. The control register for the 
-   multiplexing unit is located at IO 0x208 with a bit map of
-     0-5 Page Selection in 32k increments
-     6-7 Device selection:
-        00 SSD off
-        01 SSD 0 (Socket)
-        10 SSD 1 (Flash chip)
-        11 undefined
-  
-   On each SSD, the first 128k is reserved for use by the bios
-   (actually it IS the bios..) This only matters if you are booting off the 
-   flash, you must not put a file system starting there.
-   
-   The driver tries to do a detection algorithm to guess what sort of devices
-   are plugged into the sockets.
-   
-   ##################################################################### */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <asm/io.h>
-
-#include <linux/mtd/map.h>
-
-#define WINDOW_START 0xe8000
-#define WINDOW_LENGTH 0x8000
-#define WINDOW_SHIFT 27
-#define WINDOW_MASK 0x7FFF
-#define PAGE_IO 0x208
-
-static volatile char page_n_dev = 0;
-static unsigned long iomapadr;
-static spinlock_t oct5066_spin = SPIN_LOCK_UNLOCKED;
-
-/*
- * We use map_priv_1 to identify which device we are.
- */
-
-static void __oct5066_page(struct map_info *map, __u8 byte)
-{
-	outb(byte,PAGE_IO);
-	page_n_dev = byte;
-}
-
-static inline void oct5066_page(struct map_info *map, unsigned long ofs)
-{
-	__u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT);
-	
-	if (page_n_dev != byte)
-		__oct5066_page(map, byte);
-}
-
-
-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)
-{
-	__u32 ret;
-	spin_lock(&oct5066_spin);
-	oct5066_page(map, ofs);
-	ret = readl(iomapadr + (ofs & WINDOW_MASK));
-	spin_unlock(&oct5066_spin);
-	return ret;
-}
-
-static void oct5066_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	while(len) {
-		unsigned long thislen = len;
-		if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
-			thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
-		
-		spin_lock(&oct5066_spin);
-		oct5066_page(map, from);
-		memcpy_fromio(to, iomapadr + from, thislen);
-		spin_unlock(&oct5066_spin);
-		to += thislen;
-		from += thislen;
-		len -= thislen;
-	}
-}
-
-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)
-{
-	spin_lock(&oct5066_spin);
-	oct5066_page(map, adr);
-	writel(d, iomapadr + (adr & WINDOW_MASK));
-	spin_unlock(&oct5066_spin);
-}
-
-static void oct5066_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	while(len) {
-		unsigned long thislen = len;
-		if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
-			thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
-		
-		spin_lock(&oct5066_spin);
-		oct5066_page(map, to);
-		memcpy_toio(iomapadr + to, from, thislen);
-		spin_unlock(&oct5066_spin);
-		to += thislen;
-		from += thislen;
-		len -= thislen;
-	}
-}
-
-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 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
-	}
-};
-
-static struct mtd_info *oct5066_mtd[2] = {NULL, NULL};
-
-// OctProbe - Sense if this is an octagon card
-// ---------------------------------------------------------------------
-/* Perform a simple validity test, we map the window select SSD0 and
-   change pages while monitoring the window. A change in the window, 
-   controlled by the PAGE_IO port is a functioning 5066 board. This will
-   fail if the thing in the socket is set to a uniform value. */
-static int __init OctProbe()
-{
-   unsigned int Base = (1 << 6);
-   unsigned long I;
-   unsigned long Values[10];
-   for (I = 0; I != 20; I++)
-   {
-      outb(Base + (I%10),PAGE_IO);
-      if (I < 10)
-      {
-	 // Record the value and check for uniqueness
-	 Values[I%10] = readl(iomapadr);
-	 if (I > 0 && Values[I%10] == Values[0])
-	    return -EAGAIN;
-      }      
-      else
-      {
-	 // Make sure we get the same values on the second pass
-	 if (Values[I%10] != readl(iomapadr))
-	    return -EAGAIN;
-      }      
-   }
-   return 0;
-}
-
-#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
-#define init_oct5066 init_module
-#define cleanup_oct5066 cleanup_module
-#endif
-
-void cleanup_oct5066(void)
-{
-	int i;
-	for (i=0; i<2; i++) {
-		if (oct5066_mtd[i]) {
-			del_mtd_device(oct5066_mtd[i]);
-			map_destroy(oct5066_mtd[i]);
-		}
-	}
-	iounmap((void *)iomapadr);
-	release_region(PAGE_IO,1);
-}
-
-int __init init_oct5066(void)
-{
-	int i;
-	
-	// Do an autoprobe sequence
-	if (check_region(PAGE_IO,1) != 0)
-		{
-			printk("5066: Page Register in Use\n");
-			return -EAGAIN;
-		}
-	iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
-	if (!iomapadr) {
-		printk("Failed to ioremap memory region\n");
-		return -EIO;
-	}
-	if (OctProbe() != 0)
-		{
-			printk("5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
-			iounmap((void *)iomapadr);
-			return -EAGAIN;
-		}
-	
-	request_region(PAGE_IO,1,"Octagon SSD");
-	
-	// Print out our little header..
-	printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START,
-	       WINDOW_START+WINDOW_LENGTH);
-	
-	for (i=0; i<2; i++) {
-		oct5066_mtd[i] = do_cfi_probe(&oct5066_map[i]);
-		if (!oct5066_mtd[i])
-			oct5066_mtd[i] = do_jedec_probe(&oct5066_map[i]);
-		if (!oct5066_mtd[i])
-			oct5066_mtd[i] = do_ram_probe(&oct5066_map[i]);
-		if (!oct5066_mtd[i])
-			oct5066_mtd[i] = do_rom_probe(&oct5066_map[i]);
-		if (oct5066_mtd[i]) {
-			oct5066_mtd[i]->module = THIS_MODULE;
-			add_mtd_device(oct5066_mtd[i]);
-		}
-	}
-	
-	if (!oct5066_mtd[0] && !oct5066_mtd[1]) {
-		cleanup_oct5066();
-		return -ENXIO;
-	}	  
-	
-	return 0;
-}
-
-module_init(init_oct5066);
-module_exit(cleanup_oct5066);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/physmap.c linux/drivers/mtd/physmap.c
--- v2.4.5/linux/drivers/mtd/physmap.c	Mon Dec 11 14:57:58 2000
+++ linux/drivers/mtd/physmap.c	Wed Dec 31 16:00:00 1969
@@ -1,117 +0,0 @@
-/*
- * $Id: physmap.c,v 1.8 2000/11/27 08:50:22 dwmw2 Exp $
- *
- * Normal mappings of chips in physical memory
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <asm/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/config.h>
-
-
-#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 readb(map->map_priv_1 + ofs);
-}
-
-__u16 physmap_read16(struct map_info *map, unsigned long ofs)
-{
-	return readw(map->map_priv_1 + ofs);
-}
-
-__u32 physmap_read32(struct map_info *map, unsigned long ofs)
-{
-	return 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)
-{
-	writeb(d, map->map_priv_1 + adr);
-}
-
-void physmap_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	writew(d, map->map_priv_1 + adr);
-}
-
-void physmap_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	writel(d, map->map_priv_1 + adr);
-}
-
-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
-};
-
-#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
-#define init_physmap init_module
-#define cleanup_physmap cleanup_module
-#endif
-
-int __init init_physmap(void)
-{
-       	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);
-
-	if (!physmap_map.map_priv_1) {
-		printk("Failed to ioremap\n");
-		return -EIO;
-	}
-	mymtd = do_cfi_probe(&physmap_map);
-	if (mymtd) {
-#ifdef MODULE
-		mymtd->module = &__this_module;
-#endif
-		add_mtd_device(mymtd);
-		return 0;
-	}
-
-	iounmap((void *)physmap_map.map_priv_1);
-	return -ENXIO;
-}
-
-static void __exit cleanup_physmap(void)
-{
-	if (mymtd) {
-		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;
-	}
-}
-
-module_init(init_physmap);
-module_exit(cleanup_physmap);
-
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/pmc551.c linux/drivers/mtd/pmc551.c
--- v2.4.5/linux/drivers/mtd/pmc551.c	Fri Apr  6 10:42:55 2001
+++ linux/drivers/mtd/pmc551.c	Wed Dec 31 16:00:00 1969
@@ -1,863 +0,0 @@
-/*
- * $Id: pmc551.c,v 1.11 2000/11/23 13:40:12 dwmw2 Exp $
- *
- * PMC551 PCI Mezzanine Ram Device
- *
- * Author:
- *       Mark Ferrell <mferrell@mvista.com>
- *       Copyright 1999,2000 Nortel Networks
- *
- * License:
- *	 As part of this driver was derrived from the slram.c driver it falls
- *	 under the same license, which is GNU General Public License v2
- *
- * Description:
- *	 This driver is intended to support the PMC551 PCI Ram device from
- *	 Ramix Inc.  The PMC551 is a PMC Mezzanine module for cPCI embedded
- *	 systems.  The device contains a single SROM that initally programs the
- *	 V370PDC chipset onboard the device, and various banks of DRAM/SDRAM
- *	 onboard.  This driver implements this PCI Ram device as an MTD (Memory
- *	 Technologies Device) so that it can be used to hold a filesystem, or
- *	 for added swap space in embedded systems.  Since the memory on this
- *	 board isn't as fast as main memory we do not try to hook it into main
- *	 memeory as that would simply reduce performance on the system.  Using
- *	 it as a block device allows us to use it as high speed swap or for a
- *	 high speed disk device of some sort.  Which becomes very useful on
- *	 diskless systems in the embedded market I might add.
- *	 
- * Notes:
- *	 Due to what I assume is more buggy SROM, the 64M PMC551 I have
- *	 available claims that all 4 of it's DRAM banks have 64M of ram 
- *	 configured (making a grand total of 256M onboard).  This is slightly
- *	 annoying since the BAR0 size reflects the aperture size, not the dram
- *	 size, and the V370PDC supplies no other method for memory size
- *	 discovery.  This problem is mostly only relivant when compiled as a
- *	 module, as the unloading of the module with an aperture size  smaller
- *	 then the ram will cause the driver to detect the onboard memory size
- *	 to be equal to the aperture size when the module is reloaded.  Soooo,
- *	 to help, the module supports an msize option to allow the
- *	 specification of the onboard memory, and an asize option, to allow the
- *	 specification of the aperture size.  The aperture must be equal to or
- *	 less then the memory size, the driver will correct this if you screw
- *	 it up.  This problem is not relivant for compiled in drivers as
- *	 compiled in drivers only init once.
- *
- * Credits:
- *       Saeed Karamooz <saeed@ramix.com> of Ramix INC. for the initial
- *       example code of how to initialize this device and for help with
- *       questions I had concerning operation of the device.
- *
- *       Most of the MTD code for this driver was originally written for the
- *       slram.o module in the MTD drivers package written by David Hinds
- *       <dhinds@allegro.stanford.edu> which allows the mapping of system
- *       memory into an mtd device.  Since the PMC551 memory module is
- *       accessed in the same fashion as system memory, the slram.c code
- *       became a very nice fit to the needs of this driver.  All we added was
- *       PCI detection/initialization to the driver and automaticly figure out
- *       the size via the PCI detection.o, later changes by Corey Minyard
- *       settup the card to utilize a 1M sliding apature.
- *
- *	 Corey Minyard <minyard@nortelnetworks.com>
- *       * Modified driver to utilize a sliding apature instead of mapping all
- *       memory into kernel space which turned out to be very wastefull.
- *       * Located a bug in the SROM's initialization sequence that made the
- *       memory unusable, added a fix to code to touch up the DRAM some.
- *
- * Bugs/FIXME's:
- *       * MUST fix the init function to not spin on a register
- *       waiting for it to set .. this does not safely handle busted devices
- *       that never reset the register correctly which will cause the system to
- *       hang w/ a reboot beeing the only chance at recover.
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/major.h>
-#include <linux/fs.h>
-#include <linux/ioctl.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <stdarg.h>
-#include <linux/pci.h>
-
-#ifndef CONFIG_PCI
-#error Enable PCI in your kernel config
-#endif
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/pmc551.h>
-#include <linux/mtd/compatmac.h>
-
-#if LINUX_VERSION_CODE > 0x20300
-#define PCI_BASE_ADDRESS(dev) (dev->resource[0].start)
-#else
-#define PCI_BASE_ADDRESS(dev) (dev->base_address[0])
-#endif
-
-static struct mtd_info *pmc551list = NULL;
-
-static int pmc551_erase (struct mtd_info *mtd, struct erase_info *instr)
-{
-        struct mypriv *priv = mtd->priv;
-        u32 start_addr_highbits;
-        u32 end_addr_highbits;
-        u32 start_addr_lowbits;
-        u32 end_addr_lowbits;
-        unsigned long end;
-
-        end = instr->addr + instr->len;
-
-        /* Is it too much memory?  The second check find if we wrap around
-           past the end of a u32. */
-        if ((end > mtd->size) || (end < instr->addr)) {
-                return -EINVAL;
-        }
-
-        start_addr_highbits = instr->addr & PMC551_ADDR_HIGH_MASK;
-        end_addr_highbits = end & PMC551_ADDR_HIGH_MASK;
-        start_addr_lowbits = instr->addr & PMC551_ADDR_LOW_MASK;
-        end_addr_lowbits = end & PMC551_ADDR_LOW_MASK;
-
-        pci_write_config_dword ( priv->dev,
-                                 PMC551_PCI_MEM_MAP0,
-                                 (priv->mem_map0_base_val
-                                  | start_addr_highbits));
-        if (start_addr_highbits == end_addr_highbits) {
-                /* The whole thing fits within one access, so just one shot
-                   will do it. */
-                memset(priv->start + start_addr_lowbits,
-                       0xff,
-                       instr->len);
-        } else {
-                /* We have to do multiple writes to get all the data
-                   written. */
-                memset(priv->start + start_addr_lowbits,
-                       0xff,
-                       priv->aperture_size - start_addr_lowbits);
-                start_addr_highbits += priv->aperture_size;
-                while (start_addr_highbits != end_addr_highbits) {
-                        pci_write_config_dword ( priv->dev,
-                                                 PMC551_PCI_MEM_MAP0,
-                                                 (priv->mem_map0_base_val
-                                                  | start_addr_highbits));
-                        memset(priv->start,
-                               0xff,
-                               priv->aperture_size);
-                        start_addr_highbits += priv->aperture_size;
-                }
-                priv->curr_mem_map0_val = (priv->mem_map0_base_val
-                                           | start_addr_highbits);
-                pci_write_config_dword ( priv->dev,
-                                         PMC551_PCI_MEM_MAP0,
-                                         priv->curr_mem_map0_val);
-                memset(priv->start,
-                       0xff,
-                       end_addr_lowbits);
-        }
-
-	instr->state = MTD_ERASE_DONE;
-
-        if (instr->callback) {
-                (*(instr->callback))(instr);
-	}
-
-        return 0;
-}
-
-
-static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr)
-{}
-
-
-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;
-        u32 start_addr_highbits;
-        u32 end_addr_highbits;
-        u32 start_addr_lowbits;
-        u32 end_addr_lowbits;
-        unsigned long end;
-        u_char *copyto = buf;
-
-
-        /* Is it past the end? */
-        if (from > mtd->size) {
-                return -EINVAL;
-        }
-
-        end = from + len;
-        start_addr_highbits = from & PMC551_ADDR_HIGH_MASK;
-        end_addr_highbits = end & PMC551_ADDR_HIGH_MASK;
-        start_addr_lowbits = from & PMC551_ADDR_LOW_MASK;
-        end_addr_lowbits = end & PMC551_ADDR_LOW_MASK;
-
-
-        /* Only rewrite the first value if it doesn't match our current
-           values.  Most operations are on the same page as the previous
-           value, so this is a pretty good optimization. */
-        if (priv->curr_mem_map0_val !=
-                        (priv->mem_map0_base_val | start_addr_highbits)) {
-                priv->curr_mem_map0_val = (priv->mem_map0_base_val
-                                           | start_addr_highbits);
-                pci_write_config_dword ( priv->dev,
-                                         PMC551_PCI_MEM_MAP0,
-                                         priv->curr_mem_map0_val);
-        }
-
-        if (start_addr_highbits == end_addr_highbits) {
-                /* The whole thing fits within one access, so just one shot
-                   will do it. */
-                memcpy(copyto,
-                       priv->start + start_addr_lowbits,
-                       len);
-                copyto += len;
-        } else {
-                /* We have to do multiple writes to get all the data
-                   written. */
-                memcpy(copyto,
-                       priv->start + start_addr_lowbits,
-                       priv->aperture_size - start_addr_lowbits);
-                copyto += priv->aperture_size - start_addr_lowbits;
-                start_addr_highbits += priv->aperture_size;
-                while (start_addr_highbits != end_addr_highbits) {
-                        pci_write_config_dword ( priv->dev,
-                                                 PMC551_PCI_MEM_MAP0,
-                                                 (priv->mem_map0_base_val
-                                                  | start_addr_highbits));
-                        memcpy(copyto,
-                               priv->start,
-                               priv->aperture_size);
-                        copyto += priv->aperture_size;
-                        start_addr_highbits += priv->aperture_size;
-                        if (start_addr_highbits >= mtd->size) {
-                                /* Make sure we have the right value here. */
-                                priv->curr_mem_map0_val
-                                = (priv->mem_map0_base_val
-                                   | start_addr_highbits);
-                                goto out;
-                        }
-                }
-                priv->curr_mem_map0_val = (priv->mem_map0_base_val
-                                           | start_addr_highbits);
-                pci_write_config_dword ( priv->dev,
-                                         PMC551_PCI_MEM_MAP0,
-                                         priv->curr_mem_map0_val);
-                memcpy(copyto,
-                       priv->start,
-                       end_addr_lowbits);
-                copyto += end_addr_lowbits;
-        }
-
-out:
-        *retlen = copyto - buf;
-        return 0;
-}
-
-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;
-        u32 start_addr_highbits;
-        u32 end_addr_highbits;
-        u32 start_addr_lowbits;
-        u32 end_addr_lowbits;
-        unsigned long end;
-        const u_char *copyfrom = buf;
-
-
-        /* Is it past the end? */
-        if (to > mtd->size) {
-                return -EINVAL;
-        }
-
-        end = to + len;
-        start_addr_highbits = to & PMC551_ADDR_HIGH_MASK;
-        end_addr_highbits = end & PMC551_ADDR_HIGH_MASK;
-        start_addr_lowbits = to & PMC551_ADDR_LOW_MASK;
-        end_addr_lowbits = end & PMC551_ADDR_LOW_MASK;
-
-
-        /* Only rewrite the first value if it doesn't match our current
-           values.  Most operations are on the same page as the previous
-           value, so this is a pretty good optimization. */
-        if (priv->curr_mem_map0_val !=
-                        (priv->mem_map0_base_val | start_addr_highbits)) {
-                priv->curr_mem_map0_val = (priv->mem_map0_base_val
-                                           | start_addr_highbits);
-                pci_write_config_dword ( priv->dev,
-                                         PMC551_PCI_MEM_MAP0,
-                                         priv->curr_mem_map0_val);
-        }
-
-        if (start_addr_highbits == end_addr_highbits) {
-                /* The whole thing fits within one access, so just one shot
-                   will do it. */
-                memcpy(priv->start + start_addr_lowbits,
-                       copyfrom,
-                       len);
-                copyfrom += len;
-        } else {
-                /* We have to do multiple writes to get all the data
-                   written. */
-                memcpy(priv->start + start_addr_lowbits,
-                       copyfrom,
-                       priv->aperture_size - start_addr_lowbits);
-                copyfrom += priv->aperture_size - start_addr_lowbits;
-                start_addr_highbits += priv->aperture_size;
-                while (start_addr_highbits != end_addr_highbits) {
-                        pci_write_config_dword ( priv->dev,
-                                                 PMC551_PCI_MEM_MAP0,
-                                                 (priv->mem_map0_base_val
-                                                  | start_addr_highbits));
-                        memcpy(priv->start,
-                               copyfrom,
-                               priv->aperture_size);
-                        copyfrom += priv->aperture_size;
-                        start_addr_highbits += priv->aperture_size;
-                        if (start_addr_highbits >= mtd->size) {
-                                /* Make sure we have the right value here. */
-                                priv->curr_mem_map0_val
-                                = (priv->mem_map0_base_val
-                                   | start_addr_highbits);
-                                goto out;
-                        }
-                }
-                priv->curr_mem_map0_val = (priv->mem_map0_base_val
-                                           | start_addr_highbits);
-                pci_write_config_dword ( priv->dev,
-                                         PMC551_PCI_MEM_MAP0,
-                                         priv->curr_mem_map0_val);
-                memcpy(priv->start,
-                       copyfrom,
-                       end_addr_lowbits);
-                copyfrom += end_addr_lowbits;
-        }
-
-out:
-        *retlen = copyfrom - buf;
-        return 0;
-}
-
-/*
- * Fixup routines for the V370PDC
- * PCI device ID 0x020011b0
- *
- * This function basicly kick starts the DRAM oboard the card and gets it
- * ready to be used.  Before this is done the device reads VERY erratic, so
- * much that it can crash the Linux 2.2.x series kernels when a user cat's
- * /proc/pci .. though that is mainly a kernel bug in handling the PCI DEVSEL
- * register.  FIXME: stop spinning on registers .. must implement a timeout
- * mechanism
- * returns the size of the memory region found.
- */
-static u32 fixup_pmc551 (struct pci_dev *dev)
-{
-#ifdef CONFIG_MTD_PMC551_BUGFIX
-        u32 dram_data;
-#endif
-        u32 size, dcmd, cfg, dtmp;
-        u16 cmd, tmp, i;
-	u8 bcmd, counter;
-
-        /* Sanity Check */
-        if(!dev) {
-                return -ENODEV;
-        }
-
-	/*
-	 * Attempt to reset the card
-	 * FIXME: Stop Spinning registers
-	 */
-	counter=0;
-	/* unlock registers */
-	pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, 0xA5 );
-	/* read in old data */
-	pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd );
-	/* bang the reset line up and down for a few */
-	for(i=0;i<10;i++) {
-		counter=0;
-		bcmd &= ~0x80;
-		while(counter++ < 100) {
-			pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
-		}
-		counter=0;
-		bcmd |= 0x80;
-		while(counter++ < 100) {
-			pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
-		}
-	}
-	bcmd |= (0x40|0x20);
-	pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
-
-        /* 
-	 * Take care and turn off the memory on the device while we
-	 * tweak the configurations
-	 */
-        pci_read_config_word(dev, PCI_COMMAND, &cmd);
-        tmp = cmd & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY);
-        pci_write_config_word(dev, PCI_COMMAND, tmp);
-
-	/*
-	 * Disable existing aperture before probing memory size
-	 */
-	pci_read_config_dword(dev, PMC551_PCI_MEM_MAP0, &dcmd);
-        dtmp=(dcmd|PMC551_PCI_MEM_MAP_ENABLE|PMC551_PCI_MEM_MAP_REG_EN);
-	pci_write_config_dword(dev, PMC551_PCI_MEM_MAP0, dtmp);
-	/*
-	 * Grab old BAR0 config so that we can figure out memory size
-	 * This is another bit of kludge going on.  The reason for the
-	 * redundancy is I am hoping to retain the original configuration
-	 * previously assigned to the card by the BIOS or some previous 
-	 * fixup routine in the kernel.  So we read the old config into cfg,
-	 * then write all 1's to the memory space, read back the result into
-	 * "size", and then write back all the old config.
-	 */
-	pci_read_config_dword( dev, PCI_BASE_ADDRESS_0, &cfg );
-#ifndef CONFIG_MTD_PMC551_BUGFIX
-	pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, ~0 );
-	pci_read_config_dword( dev, PCI_BASE_ADDRESS_0, &size );
-	pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
-	size=~(size&PCI_BASE_ADDRESS_MEM_MASK)+1;
-#else
-        /*
-         * Get the size of the memory by reading all the DRAM size values
-         * and adding them up.
-         *
-         * KLUDGE ALERT: the boards we are using have invalid column and
-         * row mux values.  We fix them here, but this will break other
-         * memory configurations.
-         */
-        pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dram_data);
-        size = PMC551_DRAM_BLK_GET_SIZE(dram_data);
-        dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
-        dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
-        pci_write_config_dword(dev, PMC551_DRAM_BLK0, dram_data);
-
-        pci_read_config_dword(dev, PMC551_DRAM_BLK1, &dram_data);
-        size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
-        dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
-        dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
-        pci_write_config_dword(dev, PMC551_DRAM_BLK1, dram_data);
-
-        pci_read_config_dword(dev, PMC551_DRAM_BLK2, &dram_data);
-        size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
-        dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
-        dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
-        pci_write_config_dword(dev, PMC551_DRAM_BLK2, dram_data);
-
-        pci_read_config_dword(dev, PMC551_DRAM_BLK3, &dram_data);
-        size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
-        dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
-        dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
-        pci_write_config_dword(dev, PMC551_DRAM_BLK3, dram_data);
-
-        /*
-         * Oops .. something went wrong
-         */
-        if( (size &= PCI_BASE_ADDRESS_MEM_MASK) == 0) {
-                return -ENODEV;
-        }
-#endif /* CONFIG_MTD_PMC551_BUGFIX */
-
-	if ((cfg&PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
-                return -ENODEV;
-	}
-
-        /*
-         * Precharge Dram
-         */
-        pci_write_config_word( dev, PMC551_SDRAM_MA, 0x0400 );
-        pci_write_config_word( dev, PMC551_SDRAM_CMD, 0x00bf );
-
-        /*
-         * Wait until command has gone through
-         * FIXME: register spinning issue
-         */
-        do {	pci_read_config_word( dev, PMC551_SDRAM_CMD, &cmd );
-		if(counter++ > 100)break;
-        } while ( (PCI_COMMAND_IO) & cmd );
-
-        /*
-	 * Turn on auto refresh 
-	 * The loop is taken directly from Ramix's example code.  I assume that
-	 * this must be held high for some duration of time, but I can find no
-	 * documentation refrencing the reasons why.
-	 * 
-         */
-        for ( i = 1; i<=8 ; i++) {
-                pci_write_config_word (dev, PMC551_SDRAM_CMD, 0x0df);
-
-                /*
-                 * Make certain command has gone through
-                 * FIXME: register spinning issue
-                 */
-		counter=0;
-                do {	pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
-			if(counter++ > 100)break;
-                } while ( (PCI_COMMAND_IO) & cmd );
-        }
-
-        pci_write_config_word ( dev, PMC551_SDRAM_MA, 0x0020);
-        pci_write_config_word ( dev, PMC551_SDRAM_CMD, 0x0ff);
-
-        /*
-         * Wait until command completes
-         * FIXME: register spinning issue
-         */
-	counter=0;
-        do {	pci_read_config_word ( dev, PMC551_SDRAM_CMD, &cmd);
-		if(counter++ > 100)break;
-        } while ( (PCI_COMMAND_IO) & cmd );
-
-        pci_read_config_dword ( dev, PMC551_DRAM_CFG, &dcmd);
-        dcmd |= 0x02000000;
-        pci_write_config_dword ( dev, PMC551_DRAM_CFG, dcmd);
-
-        /*
-         * Check to make certain fast back-to-back, if not
-         * then set it so
-         */
-        pci_read_config_word( dev, PCI_STATUS, &cmd);
-        if((cmd&PCI_COMMAND_FAST_BACK) == 0) {
-                cmd |= PCI_COMMAND_FAST_BACK;
-                pci_write_config_word( dev, PCI_STATUS, cmd);
-        }
-
-        /*
-         * Check to make certain the DEVSEL is set correctly, this device
-         * has a tendancy to assert DEVSEL and TRDY when a write is performed
-         * to the memory when memory is read-only
-         */
-        if((cmd&PCI_STATUS_DEVSEL_MASK) != 0x0) {
-                cmd &= ~PCI_STATUS_DEVSEL_MASK;
-                pci_write_config_word( dev, PCI_STATUS, cmd );
-        }
-        /*
-         * Set to be prefetchable and put everything back based on old cfg.
-	 * it's possible that the reset of the V370PDC nuked the original
-	 * settup
-         */
-        cfg |= PCI_BASE_ADDRESS_MEM_PREFETCH;
-	pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
-
-        /*
-         * Turn PCI memory and I/O bus access back on
-         */
-        pci_write_config_word( dev, PCI_COMMAND,
-                               PCI_COMMAND_MEMORY | PCI_COMMAND_IO );
-#ifdef CONFIG_MTD_PMC551_DEBUG
-        /*
-         * Some screen fun
-         */
-        printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at 0x%lx\n",
-	       (size<1024)?size:(size<1048576)?size/1024:size/1024/1024,
-               (size<1024)?'B':(size<1048576)?'K':'M',
-	       size, ((dcmd&(0x1<<3)) == 0)?"non-":"",
-               PCI_BASE_ADDRESS(dev)&PCI_BASE_ADDRESS_MEM_MASK );
-
-        /*
-         * Check to see the state of the memory
-         */
-        pci_read_config_dword( dev, PMC551_DRAM_BLK0, &dcmd );
-        printk(KERN_DEBUG "pmc551: DRAM_BLK0 Flags: %s,%s\n"
-			  "pmc551: DRAM_BLK0 Size: %d at %d\n"
-			  "pmc551: DRAM_BLK0 Row MUX: %d, Col MUX: %d\n",
-               (((0x1<<1)&dcmd) == 0)?"RW":"RO",
-               (((0x1<<0)&dcmd) == 0)?"Off":"On",
-	       PMC551_DRAM_BLK_GET_SIZE(dcmd),
-	       ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
-
-        pci_read_config_dword( dev, PMC551_DRAM_BLK1, &dcmd );
-        printk(KERN_DEBUG "pmc551: DRAM_BLK1 Flags: %s,%s\n"
-			  "pmc551: DRAM_BLK1 Size: %d at %d\n"
-			  "pmc551: DRAM_BLK1 Row MUX: %d, Col MUX: %d\n",
-               (((0x1<<1)&dcmd) == 0)?"RW":"RO",
-               (((0x1<<0)&dcmd) == 0)?"Off":"On",
-	       PMC551_DRAM_BLK_GET_SIZE(dcmd),
-	       ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
-
-        pci_read_config_dword( dev, PMC551_DRAM_BLK2, &dcmd );
-        printk(KERN_DEBUG "pmc551: DRAM_BLK2 Flags: %s,%s\n"
-			  "pmc551: DRAM_BLK2 Size: %d at %d\n"
-			  "pmc551: DRAM_BLK2 Row MUX: %d, Col MUX: %d\n",
-               (((0x1<<1)&dcmd) == 0)?"RW":"RO",
-               (((0x1<<0)&dcmd) == 0)?"Off":"On",
-	       PMC551_DRAM_BLK_GET_SIZE(dcmd),
-	       ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
-
-        pci_read_config_dword( dev, PMC551_DRAM_BLK3, &dcmd );
-        printk(KERN_DEBUG "pmc551: DRAM_BLK3 Flags: %s,%s\n"
-			  "pmc551: DRAM_BLK3 Size: %d at %d\n"
-			  "pmc551: DRAM_BLK3 Row MUX: %d, Col MUX: %d\n",
-               (((0x1<<1)&dcmd) == 0)?"RW":"RO",
-               (((0x1<<0)&dcmd) == 0)?"Off":"On",
-	       PMC551_DRAM_BLK_GET_SIZE(dcmd),
-	       ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
-
-        pci_read_config_word( dev, PCI_COMMAND, &cmd );
-        printk( KERN_DEBUG "pmc551: Memory Access %s\n",
-                (((0x1<<1)&cmd) == 0)?"off":"on" );
-        printk( KERN_DEBUG "pmc551: I/O Access %s\n",
-                (((0x1<<0)&cmd) == 0)?"off":"on" );
-
-        pci_read_config_word( dev, PCI_STATUS, &cmd );
-        printk( KERN_DEBUG "pmc551: Devsel %s\n",
-                ((PCI_STATUS_DEVSEL_MASK&cmd)==0x000)?"Fast":
-                ((PCI_STATUS_DEVSEL_MASK&cmd)==0x200)?"Medium":
-                ((PCI_STATUS_DEVSEL_MASK&cmd)==0x400)?"Slow":"Invalid" );
-
-        printk( KERN_DEBUG "pmc551: %sFast Back-to-Back\n",
-                ((PCI_COMMAND_FAST_BACK&cmd) == 0)?"Not ":"" );
-
-	pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd );
-	printk( KERN_DEBUG "pmc551: EEPROM is under %s control\n"
-			   "pmc551: System Control Register is %slocked to PCI access\n"
-			   "pmc551: System Control Register is %slocked to EEPROM access\n", 
-		(bcmd&0x1)?"software":"hardware",
-		(bcmd&0x20)?"":"un", (bcmd&0x40)?"":"un");
-#endif
-        return size;
-}
-
-/*
- * Kernel version specific module stuffages
- */
-#if LINUX_VERSION_CODE < 0x20211
-#ifdef MODULE
-#define init_pmc551 init_module
-#define cleanup_pmc551 cleanup_module
-#endif
-#define __exit
-#endif
-
-#if defined(MODULE)
-MODULE_AUTHOR("Mark Ferrell <mferrell@mvista.com>");
-MODULE_DESCRIPTION(PMC551_VERSION);
-MODULE_PARM(msize, "i");
-MODULE_PARM_DESC(msize, "memory size, 6=32M, 7=64M, 8=128M, ect.. [32M-1024M]");
-MODULE_PARM(asize, "i");
-MODULE_PARM_DESC(asize, "aperture size, must be <= memsize [1M-1024M]");
-#endif
-/*
- * Stuff these outside the ifdef so as to not bust compiled in driver support
- */
-static int msize=0;
-#if defined(CONFIG_MTD_PMC551_APERTURE_SIZE)
-static int asize=CONFIG_MTD_PMC551_APERTURE_SIZE
-#else
-static int asize=0;
-#endif
-
-/*
- * PMC551 Card Initialization
- */
-int __init init_pmc551(void)
-{
-        struct pci_dev *PCI_Device = NULL;
-        struct mypriv *priv;
-        int count, found=0;
-        struct mtd_info *mtd;
-        u32 length = 0;
-
-	if(msize) {
-		if (msize < 6 || msize > 11 ) {
-			printk(KERN_NOTICE "pmc551: Invalid memory size\n");
-			return -ENODEV;
-		}
-		msize = (512*1024)<<msize;
-	}
-
-	if(asize) {
-		if (asize < 1 || asize > 11 ) {
-			printk(KERN_NOTICE "pmc551: Invalid aperture size\n");
-			return -ENODEV;
-		}
-		asize = (512*1024)<<asize;
-	}
-
-        printk(KERN_INFO PMC551_VERSION);
-
-        if(!pci_present()) {
-                printk(KERN_NOTICE "pmc551: PCI not enabled.\n");
-                return -ENODEV;
-        }
-
-        /*
-         * PCU-bus chipset probe.
-         */
-        for( count = 0; count < MAX_MTD_DEVICES; count++ ) {
-
-                if ( (PCI_Device = pci_find_device( PCI_VENDOR_ID_V3_SEMI,
-                                                    PCI_DEVICE_ID_V3_SEMI_V370PDC, PCI_Device ) ) == NULL) {
-                        break;
-                }
-
-                printk(KERN_NOTICE "pmc551: Found PCI V370PDC IRQ:%d\n",
-                       PCI_Device->irq);
-
-                /*
-                 * The PMC551 device acts VERY weird if you don't init it
-                 * first.  i.e. it will not correctly report devsel.  If for
-                 * some reason the sdram is in a wrote-protected state the
-                 * device will DEVSEL when it is written to causing problems
-                 * with the oldproc.c driver in
-                 * some kernels (2.2.*)
-                 */
-                if((length = fixup_pmc551(PCI_Device)) <= 0) {
-                        printk(KERN_NOTICE "pmc551: Cannot init SDRAM\n");
-                        break;
-                }
-		if(msize) {
-			length = msize;
-			printk(KERN_NOTICE "pmc551: Using specified memory size 0x%x\n", length);
-		}
-
-                mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-                if (!mtd) {
-                        printk(KERN_NOTICE "pmc551: Cannot allocate new MTD device.\n");
-                        break;
-                }
-
-                memset(mtd, 0, sizeof(struct mtd_info));
-
-                priv = kmalloc (sizeof(struct mypriv), GFP_KERNEL);
-                if (!priv) {
-                        printk(KERN_NOTICE "pmc551: Cannot allocate new MTD device.\n");
-                        kfree(mtd);
-                        break;
-                }
-                memset(priv, 0, sizeof(*priv));
-                mtd->priv = priv;
-
-                priv->dev = PCI_Device;
-		if(asize) {
-			if(asize > length) {
-				asize=length;
-				printk(KERN_NOTICE "pmc551: reducing aperture size to fit memory [0x%x]\n",asize);
-			} else {
-				printk(KERN_NOTICE "pmc551: Using specified aperture size 0x%x\n", asize);
-			}
-			priv->aperture_size = asize;
-		} else {
-                	priv->aperture_size = length;
-		}
-                priv->start = ioremap((PCI_BASE_ADDRESS(PCI_Device)
-                                       & PCI_BASE_ADDRESS_MEM_MASK),
-                                      priv->aperture_size);
-		
-		/*
-		 * Due to the dynamic nature of the code, we need to figure
-		 * this out in order to stuff the register to set the proper
-		 * aperture size.  If you know of an easier way to do this then
-		 * PLEASE help yourself.
-		 *
-		 * Not with bloody floating point, you don't. Consider yourself
-		 * duly LARTed. dwmw2.
-		 */
-		{
-			u32 size;
-			u16 bits;
-			size = priv->aperture_size>>20;
-			for(bits=0;!(size&0x01)&&size>0;bits++,size=size>>1);
-			//size=((u32)((log10(priv->aperture_size)/.30103)-19)<<4);
-                	priv->mem_map0_base_val = (PMC551_PCI_MEM_MAP_REG_EN
-						| PMC551_PCI_MEM_MAP_ENABLE
-						| size);
-#ifdef CONFIG_MTD_PMC551_DEBUG
-			printk(KERN_NOTICE "pmc551: aperture set to %d[%d]\n", 
-					size, size>>4);
-#endif
-		}
-                priv->curr_mem_map0_val = priv->mem_map0_base_val;
-
-                pci_write_config_dword ( priv->dev,
-                                         PMC551_PCI_MEM_MAP0,
-                                         priv->curr_mem_map0_val);
-
-                mtd->size 		= length;
-                mtd->flags 		= (MTD_CLEAR_BITS
-                                | MTD_SET_BITS
-                                | MTD_WRITEB_WRITEABLE
-                                | MTD_VOLATILE);
-                mtd->erase 		= pmc551_erase;
-                mtd->point 		= NULL;
-                mtd->unpoint 		= pmc551_unpoint;
-                mtd->read 		= pmc551_read;
-                mtd->write 		= pmc551_write;
-                mtd->module 		= THIS_MODULE;
-                mtd->type 		= MTD_RAM;
-                mtd->name 		= "PMC551 RAM board";
-                mtd->erasesize 		= 0x10000;
-
-                if (add_mtd_device(mtd)) {
-                        printk(KERN_NOTICE "pmc551: Failed to register new device\n");
-			iounmap(priv->start);
-                        kfree(mtd->priv);
-                        kfree(mtd);
-                        break;
-                }
-                printk(KERN_NOTICE "Registered pmc551 memory device.\n");
-                printk(KERN_NOTICE "Mapped %dM of memory from 0x%p to 0x%p\n",
-                       priv->aperture_size/1024/1024,
-                       priv->start,
-                       priv->start + priv->aperture_size);
-                printk(KERN_NOTICE "Total memory is %d%c\n",
-	       		(length<1024)?length:
-				(length<1048576)?length/1024:length/1024/1024,
-               		(length<1024)?'B':(length<1048576)?'K':'M');
-		priv->nextpmc551 = pmc551list;
-		pmc551list = mtd;
-		found++;
-        }
-
-        if( !pmc551list ) {
-                printk(KERN_NOTICE "pmc551: not detected,\n");
-                return -ENODEV;
-        } else {
-		printk(KERN_NOTICE "pmc551: %d pmc551 devices loaded\n", found);
-                return 0;
-	}
-}
-
-/*
- * PMC551 Card Cleanup
- */
-static void __exit cleanup_pmc551(void)
-{
-        int found=0;
-        struct mtd_info *mtd;
-	struct mypriv *priv;
-
-	while((mtd=pmc551list)) {
-		priv = (struct mypriv *)mtd->priv;
-		pmc551list = priv->nextpmc551;
-		
-		if(priv->start)
-			iounmap(((struct mypriv *)mtd->priv)->start);
-		
-		kfree (mtd->priv);
-		del_mtd_device(mtd);
-		kfree(mtd);
-		found++;
-	}
-
-	printk(KERN_NOTICE "pmc551: %d pmc551 devices unloaded\n", found);
-}
-
-#if LINUX_VERSION_CODE >= 0x20211
-module_init(init_pmc551);
-module_exit(cleanup_pmc551);
-#endif
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/pnc2000.c linux/drivers/mtd/pnc2000.c
--- v2.4.5/linux/drivers/mtd/pnc2000.c	Mon Dec 11 14:57:58 2000
+++ linux/drivers/mtd/pnc2000.c	Wed Dec 31 16:00:00 1969
@@ -1,136 +0,0 @@
-/*
- *	pnc2000.c - mapper for Photron PNC-2000 board.
- *
- * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp>
- *
- * This code is GPL
- *
- * $Id: pnc2000.c,v 1.4 2000/11/27 08:50:22 dwmw2 Exp $
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-
-#define WINDOW_ADDR 0xbf000000
-#define WINDOW_SIZE 0x00400000
-
-/* 
- * 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
-};
-
-
-/*
- * MTD 'PARTITIONING' STUFF 
- */
-static struct mtd_partition pnc_partitions[3] = {
-	{
-		name: "PNC-2000 boot firmware",
-		size: 0x20000,
-		offset: 0
-	},
-	{
-		name: "PNC-2000 kernel",
-		size: 0x1a0000,
-		offset: 0x20000
-	},
-	{
-		name: "PNC-2000 filesystem",
-		size: 0x240000,
-		offset: 0x1c0000
-	}
-};
-
-/* 
- * This is the master MTD device for which all the others are just
- * auto-relocating aliases.
- */
-static struct mtd_info *mymtd;
-
-#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
-#define init_pnc init_module
-#define cleanup_pnc cleanup_module
-#endif
-
-int __init init_pnc(void)
-{
-	printk(KERN_NOTICE "Photron PNC-2000 flash mapping: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
-
-	mymtd = do_cfi_probe(&pnc_map);
-	if (mymtd) {
-		mymtd->module = THIS_MODULE;
-		return add_mtd_partitions(mymtd, pnc_partitions, 3);
-	}
-
-	return -ENXIO;
-}
-
-static void __exit cleanup_pnc(void)
-{
-	if (mymtd) {
-		del_mtd_partitions(mymtd);
-		map_destroy(mymtd);
-	}
-}
-
-module_init(init_pnc);
-module_exit(cleanup_pnc);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/redboot.c linux/drivers/mtd/redboot.c
--- v2.4.5/linux/drivers/mtd/redboot.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/redboot.c	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,150 @@
+/*
+ * $Id: redboot.c,v 1.4 2001/05/31 20:43:18 dwmw2 Exp $
+ *
+ * Parse RedBoot-style Flash Image System (FIS) tables and
+ * produce a Linux partition array to match.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+struct fis_image_desc {
+    unsigned char name[16];      // Null terminated name
+    unsigned long flash_base;    // Address within FLASH of image
+    unsigned long mem_base;      // Address in memory where it executes
+    unsigned long size;          // Length of image
+    unsigned long entry_point;   // Execution entry point
+    unsigned long data_length;   // Length of actual data
+    unsigned char _pad[256-(16+7*sizeof(unsigned long))];
+    unsigned long desc_cksum;    // Checksum over image descriptor
+    unsigned long file_cksum;    // Checksum over image data
+};
+
+struct fis_list {
+	struct fis_image_desc *img;
+	struct fis_list *next;
+};
+
+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)
+{
+	int nrparts = 0;
+	struct fis_image_desc *buf;
+	struct mtd_partition *parts;
+	struct fis_list *fl = NULL, *tmp_fl;
+	int ret, i;
+	size_t retlen;
+	char *names;
+	int namelen = 0;
+
+	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+
+	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 (ret)
+		goto out;
+
+	if (retlen != PAGE_SIZE) {
+		ret = -EIO;
+		goto out;
+	}
+
+	if (memcmp(buf, "RedBoot", 8)) {
+		ret = 0;
+		goto out;
+	}
+
+	for (i = 0; i < PAGE_SIZE / sizeof(struct fis_image_desc); i++) {
+		struct fis_list *new_fl, **prev;
+
+		if (buf[i].name[0] == 0xff)
+			break;
+		if (!redboot_checksum(&buf[i]))
+			break;
+
+		new_fl = kmalloc(sizeof(struct fis_list), GFP_KERNEL);
+		namelen += strlen(buf[i].name)+1;
+		if (!new_fl) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		new_fl->img = &buf[i];
+		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_
+		 */
+		prev = &fl;
+		while(*prev && (*prev)->img->flash_base < new_fl->img->flash_base)
+			prev = &(*prev)->next;
+		new_fl->next = *prev;
+		*prev = new_fl;
+
+		nrparts++;
+	}
+	if (fl->img->flash_base)
+		nrparts++;
+
+	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)
+			nrparts++;
+	}
+	parts = kmalloc(sizeof(*parts)*nrparts + namelen, GFP_KERNEL);
+
+	if (!parts) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	names = (char *)&parts[nrparts];
+	memset(parts, 0, sizeof(*parts)*nrparts + namelen);
+	i=0;
+
+	if (fl->img->flash_base) {
+	       parts[0].name = "unallocated space";
+	       parts[0].size = fl->img->flash_base;
+	       parts[0].offset = 0;
+	}
+	for ( ; i<nrparts; i++) {
+		parts[i].size = fl->img->size;
+		parts[i].offset = fl->img->flash_base;
+		parts[i].name = names;
+
+		strcpy(names, fl->img->name);
+		names += strlen(names)+1;
+
+		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";
+		}
+		tmp_fl = fl;
+		fl = fl->next;
+		kfree(tmp_fl);
+	}
+	ret = nrparts;
+	*pparts = parts;
+ out:
+	while (fl) {
+		struct fis_list *old = fl;
+		fl = fl->next;
+		kfree(old);
+	}
+	kfree(buf);
+	return ret;
+}
+
+EXPORT_SYMBOL(parse_redboot_partitions);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/rpxlite.c linux/drivers/mtd/rpxlite.c
--- v2.4.5/linux/drivers/mtd/rpxlite.c	Sun Feb  4 10:05:30 2001
+++ linux/drivers/mtd/rpxlite.c	Wed Dec 31 16:00:00 1969
@@ -1,114 +0,0 @@
-/*
- * $Id: rpxlite.c,v 1.8 2000/12/09 22:00:31 dwmw2 Exp $
- *
- * Handle mapping of the flash on the RPX Lite and CLLF boards
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <asm/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-
-
-#define WINDOW_ADDR 0xfe000000
-#define WINDOW_SIZE 0x800000
-
-static struct mtd_info *mymtd;
-
-__u8 rpxlite_read8(struct map_info *map, unsigned long ofs)
-{
-	return readb(map->map_priv_1 * ofs);
-}
-
-__u16 rpxlite_read16(struct map_info *map, unsigned long ofs)
-{
-	return readw(map->map_priv_1 + ofs);
-}
-
-__u32 rpxlite_read32(struct map_info *map, unsigned long ofs)
-{
-	return 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)
-{
-	writeb(d, map->map_priv_1 + adr);
-}
-
-void rpxlite_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	writew(d, map->map_priv_1 + adr);
-}
-
-void rpxlite_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	writel(d, map->map_priv_1 + adr);
-}
-
-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
-};
-
-#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
-#define init_rpxlite init_module
-#define cleanup_rpxlite cleanup_module
-#endif
-
-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);
-
-	if (!rpxlite_map.map_priv_1) {
-		printk("Failed to ioremap\n");
-		return -EIO;
-	}
-	mymtd = do_cfi_probe(&rpxlite_map);
-	if (mymtd) {
-#ifdef MODULE
-		mymtd->module = &__this_module;
-#endif
-		add_mtd_device(mymtd);
-		return 0;
-	}
-
-	iounmap((void *)rpxlite_map.map_priv_1);
-	return -ENXIO;
-}
-
-static void __exit cleanup_rpxlite(void)
-{
-	if (mymtd) {
-		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;
-	}
-}
-
-module_init(init_rpxlite);
-module_exit(cleanup_rpxlite);
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/slram.c linux/drivers/mtd/slram.c
--- v2.4.5/linux/drivers/mtd/slram.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/slram.c	Wed Dec 31 16:00:00 1969
@@ -1,227 +0,0 @@
-/*======================================================================
-
-  $Id: slram.c,v 1.10 2000/07/03 10:01:38 dwmw2 Exp $
-
-======================================================================*/
-
-
-#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/major.h>
-#include <linux/fs.h>
-#include <linux/ioctl.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <stdarg.h>
-
-#include <linux/mtd/mtd.h>
-
-struct mypriv {
-	u_char *start;
-	u_char *end;
-};
-
-int physmem_erase (struct mtd_info *mtd, struct erase_info *instr);
-int physmem_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
-void physmem_unpoint (struct mtd_info *mtd, u_char *addr);
-int physmem_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
-int physmem_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
-	
-
-int physmem_erase (struct mtd_info *mtd, struct erase_info *instr)
-{
-	struct mypriv *priv = mtd->priv;
-
-	if (instr->addr + instr->len > mtd->size)
-		return -EINVAL;
-	
-	memset(priv->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;
-
-	if (instr->callback)
-		(*(instr->callback))(instr);
-	else
-		kfree(instr);
-
-	return 0;
-}
-
-
-int physmem_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
-{
-	struct mypriv *priv = (struct mypriv *)mtd->priv;
-
-	*mtdbuf = priv->start + from;
-	*retlen = len;
-	return 0;
-}
-
-void physmem_unpoint (struct mtd_info *mtd, u_char *addr)
-{
-}
-
-int physmem_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-{
-	struct mypriv *priv = (struct mypriv *)mtd->priv;
-	
-	memcpy (buf, priv->start + from, len);
-
-	*retlen=len;
-	return 0;
-}
-
-int physmem_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;
-
-	memcpy (priv->start + to, buf, len);
-
-	*retlen=len;
-	return 0;
-}
-
-
-
-
-/*====================================================================*/
-
-/* Place your defaults here */
-
-static u_long start = 100663296;
-static u_long length = 33554432;
-static u_long end = 0;
-
-#if LINUX_VERSION_CODE < 0x20300
-#ifdef MODULE
-#define init_slram init_module
-#define cleanup_slram cleanup_module
-#endif
-#define __exit
-#endif
-
-#ifdef MODULE
-MODULE_PARM(start,"l");
-MODULE_PARM(length,"l");
-MODULE_PARM(end,"l");
-#endif
-
-struct mtd_info *mymtd;
-
-void __init mtd_slram_setup(char *str, int *ints)
-{
-	if (ints[0] > 0)
-		start=ints[1];
-	if (ints[0] > 1)
-		length=ints[2];
-}
-
-int init_slram(void)
-{
-	if (!start)
-	{
-		printk(KERN_NOTICE "physmem: No start address for memory device.\n");
-		return -EINVAL;
-	}
-	
-	if (!length && !end)
-	{
-		printk(KERN_NOTICE "physmem: No length or endpointer given.\n");
-		return -EINVAL;
-	}
-	
-	if (!end)
-		end = start + length;
-	
-	if (!length)
-	  length = end - start;
-
-	if (start + length != end)
-	  {
-	    printk(KERN_NOTICE "physmem: start(%lx) + length(%lx) != end(%lx) !\n",
-		   start, length, end);
-	    return -EINVAL;
-	  }
-
-	mymtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-	
-	memset(mymtd, 0, sizeof(*mymtd));
-	
-	if (mymtd)
-	{
-		memset((char *)mymtd, 0, sizeof(struct mtd_info));
-		mymtd->priv = (void *) kmalloc (sizeof(struct mypriv), GFP_KERNEL);
-		if (!mymtd->priv)
-		{
-			kfree(mymtd);
-			mymtd = NULL;
-		}
-		memset(mymtd->priv, 0, sizeof(struct mypriv));
-	}
-
-	if (!mymtd)
-	{
-		printk(KERN_NOTICE "physmem: Cannot allocate new MTD device.\n");
-		return -ENOMEM;
-	}
-	
-	
-	((struct mypriv *)mymtd->priv)->start = ioremap(start, length);
-	((struct mypriv *)mymtd->priv)->end = ((struct mypriv *)mymtd->priv)->start + length;
-
-
-	mymtd->name = "Raw memory";
-
-	mymtd->size = length;
-	mymtd->flags = MTD_CLEAR_BITS | MTD_SET_BITS | MTD_WRITEB_WRITEABLE | MTD_VOLATILE;
-        mymtd->erase = physmem_erase;
-	mymtd->point = physmem_point;
-	mymtd->unpoint = physmem_unpoint;
-	mymtd->read = physmem_read;
-	mymtd->write = physmem_write;
-	mymtd->module = THIS_MODULE;
-	mymtd->type = MTD_RAM;
-	mymtd->erasesize = 0x10000;
-
-	if (add_mtd_device(mymtd))
-	{
-		printk("Failed to register new device\n");
-	        iounmap(((struct mypriv *)mymtd->priv)->start);
-		kfree(mymtd->priv);
-		kfree(mymtd);
-		return -EAGAIN;
-	}
-	printk("Registered physmem device from %dKb to %dKb\n",
-	       (int)(start / 1024), (int)(end / 1024));
-	printk("Mapped from 0x%p to 0x%p\n",((struct mypriv *)mymtd->priv)->start,
-((struct mypriv *)mymtd->priv)->end);
-
-	return 0;
-}
-
-static void __exit cleanup_slram(void)
-{
-	iounmap(((struct mypriv *)mymtd->priv)->start);
-	kfree (mymtd->priv);
-	del_mtd_device(mymtd);
-	kfree(mymtd);
-}
-
-#if LINUX_VERSION_CODE > 0x20300
-module_init(init_slram);
-module_exit(cleanup_slram);
-#endif
diff -u --recursive --new-file v2.4.5/linux/drivers/mtd/vmax301.c linux/drivers/mtd/vmax301.c
--- v2.4.5/linux/drivers/mtd/vmax301.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/vmax301.c	Wed Dec 31 16:00:00 1969
@@ -1,240 +0,0 @@
-// $Id: vmax301.c,v 1.15 2000/11/27 08:50:22 dwmw2 Exp $
-/* ######################################################################
-
-   Tempustech VMAX SBC301 MTD Driver.
-  
-   The VMAx 301 is a SBC based on . It
-   comes with three builtin AMD 29F016B flash chips and a socket for SRAM or
-   more flash. Each unit has it's own 8k mapping into a settable region 
-   (0xD8000). There are two 8k mappings for each MTD, the first is always set
-   to the lower 8k of the device the second is paged. Writing a 16 bit page
-   value to anywhere in the first 8k will cause the second 8k to page around.
-
-   To boot the device a bios extension must be installed into the first 8k 
-   of flash that is smart enough to copy itself down, page in the rest of 
-   itself and begin executing.
-   
-   ##################################################################### */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <asm/spinlock.h>
-#include <asm/io.h>
-
-#include <linux/mtd/map.h>
-
-
-#define WINDOW_START 0xd8000
-#define WINDOW_LENGTH 0x2000
-#define WINDOW_SHIFT 25
-#define WINDOW_MASK 0x1FFF
-
-/* Actually we could use two spinlocks, but we'd have to have
-   more private space in the struct map_info. We lose a little
-   performance like this, but we'd probably lose more by having
-   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 void __vmax301_page(struct map_info *map, unsigned long page)
-{
-	writew(page, map->map_priv_2 - WINDOW_LENGTH);
-	map->map_priv_1 = page;
-}
-
-static inline void vmax301_page(struct map_info *map,
-				  unsigned long ofs)
-{
-	unsigned long page = (ofs >> WINDOW_SHIFT);
-	if (map->map_priv_1 != page)
-		__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)
-{
-	__u32 ret;
-	spin_lock(&vmax301_spin);
-	vmax301_page(map, ofs);
-	ret =  readl(map->map_priv_2 + (ofs & WINDOW_MASK));
-	spin_unlock(&vmax301_spin);
-	return ret;
-}
-
-static void vmax301_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	while(len) {
-		unsigned long thislen = len;
-		if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
-			thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
-		spin_lock(&vmax301_spin);
-		vmax301_page(map, from);
-		memcpy_fromio(to, map->map_priv_2 + from, thislen);
-		spin_unlock(&vmax301_spin);
-		to += thislen;
-		from += thislen;
-		len -= thislen;
-	}
-}
-
-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)
-{
-	spin_lock(&vmax301_spin);
-	vmax301_page(map, adr);
-	writel(d, map->map_priv_2 + (adr & WINDOW_MASK));
-	spin_unlock(&vmax301_spin);
-}
-
-static void vmax301_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	while(len) {
-		unsigned long thislen = len;
-		if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
-			thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
-
-		spin_lock(&vmax301_spin);
-		vmax301_page(map, to);
-		memcpy_toio(map->map_priv_2 + to, from, thislen);
-		spin_unlock(&vmax301_spin);		
-		to += thislen;
-		from += thislen;
-		len -= thislen;
-	}
-}
-
-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 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
-	}
-};
-
-static struct mtd_info *vmax_mtd[2] = {NULL, NULL};
-
-#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
-#define init_vmax301 init_module
-#define cleanup_vmax301 cleanup_module
-#endif
-
-static void __exit cleanup_vmax301(void)
-{
-	int i;
-	
-	for (i=0; i<2; i++) {
-		if (vmax_mtd[i]) {
-			del_mtd_device(vmax_mtd[i]);
-			map_destroy(vmax_mtd[i]);
-		}
-	}
-	iounmap((void *)vmax_map[0].map_priv_1 - WINDOW_START);
-}
-
-int __init init_vmax301(void)
-{
-	int i;
-	unsigned long iomapadr;
-	// Print out our little header..
-	printk("Tempustech VMAX 301 MEM:0x%x-0x%x\n",WINDOW_START,
-	       WINDOW_START+4*WINDOW_LENGTH);
-
-	iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH*4);
-	if (!iomapadr) {
-		printk("Failed to ioremap memory region\n");
-		return -EIO;
-	}
-	/* Put the address in the map's private data area.
-	   We store the actual MTD IO address rather than the 
-	   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);
-	
-	for (i=0; i<2; i++) {
-		vmax_mtd[i] = do_cfi_probe(&vmax_map[i]);
-		if (!vmax_mtd[i])
-			vmax_mtd[i] = do_jedec_probe(&vmax_map[i]);
-		if (!vmax_mtd[i])
-			vmax_mtd[i] = do_ram_probe(&vmax_map[i]);
-		if (!vmax_mtd[i])
-			vmax_mtd[i] = do_rom_probe(&vmax_map[i]);
-		if (vmax_mtd[i]) {
-			vmax_mtd[i]->module = THIS_MODULE;
-			add_mtd_device(vmax_mtd[i]);
-		}
-	}
-
-	if (!vmax_mtd[1] && !vmax_mtd[2]) {
-		iounmap(iomapadr);
-		return -ENXIO;
-	}
-
-	return 0;
-}
-
-module_init(init_vmax301);
-module_exit(cleanup_vmax301);
diff -u --recursive --new-file v2.4.5/linux/drivers/net/3c501.c linux/drivers/net/3c501.c
--- v2.4.5/linux/drivers/net/3c501.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/3c501.c	Wed Jun 20 11:10:53 2001
@@ -251,7 +251,7 @@
 }
 
 /**
- *	el1_probe: 
+ *	el1_probe1: 
  *	@dev: The device structure to use
  *	@ioaddr: An I/O address to probe at.
  *
@@ -925,6 +925,8 @@
 static int irq=5;
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
+MODULE_PARM_DESC(io, "EtherLink I/O base address");
+MODULE_PARM_DESC(irq, "EtherLink IRQ number");
 
 /**
  * init_module:
diff -u --recursive --new-file v2.4.5/linux/drivers/net/3c503.c linux/drivers/net/3c503.c
--- v2.4.5/linux/drivers/net/3c503.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/3c503.c	Wed Jun 20 11:10:53 2001
@@ -615,6 +615,9 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i");
 MODULE_PARM(xcvr, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i");
+MODULE_PARM_DESC(io, "EtherLink II I/O base address(es)");
+MODULE_PARM_DESC(irq, "EtherLink II IRQ number(s) (assigned)");
+MODULE_PARM_DESC(xcvr, "EtherLink II tranceiver(s) (0=internal, 1=external)");
 
 /* This is set up so that only a single autoprobe takes place per call.
 ISA device autoprobes on a running machine are not recommended. */
diff -u --recursive --new-file v2.4.5/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v2.4.5/linux/drivers/net/3c505.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/3c505.c	Wed Jun 20 11:10:53 2001
@@ -1621,6 +1621,9 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(ELP_MAX_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(ELP_MAX_CARDS) "i");
 MODULE_PARM(dma, "1-" __MODULE_STRING(ELP_MAX_CARDS) "i");
+MODULE_PARM_DESC(io, "EtherLink Plus I/O base address(es)");
+MODULE_PARM_DESC(irq, "EtherLink Plus IRQ number(s) (assigned)");
+MODULE_PARM_DESC(dma, "EtherLink Plus DMA channel(s)");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/3c507.c linux/drivers/net/3c507.c
--- v2.4.5/linux/drivers/net/3c507.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/3c507.c	Wed Jun 20 11:10:53 2001
@@ -861,6 +861,8 @@
 static int irq;
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
+MODULE_PARM_DESC(io, "EtherLink16 I/O base address");
+MODULE_PARM_DESC(irq, "(ignored)");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.4.5/linux/drivers/net/3c509.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/3c509.c	Wed Jun 20 11:10:53 2001
@@ -1007,9 +1007,12 @@
 MODULE_PARM(irq,"1-8i");
 MODULE_PARM(xcvr,"1-8i");
 MODULE_PARM(max_interrupt_work, "i");
-#ifdef CONFIG_ISAPNP
+MODULE_PARM_DESC(debug, "EtherLink III debug level (0-6)");
+MODULE_PARM_DESC(irq, "EtherLink III IRQ number(s) (assigned)");
+MODULE_PARM_DESC(xcvr,"EtherLink III tranceiver(s) (0=internal, 1=external)");
+MODULE_PARM_DESC(max_interrupt_work, "EtherLink III maximum events handled per interrupt");
 MODULE_PARM(nopnp, "i");
-#endif
+MODULE_PARM_DESC(nopnp, "EtherLink III disable ISA PnP support (0-1)");
 
 int
 init_module(void)
diff -u --recursive --new-file v2.4.5/linux/drivers/net/3c515.c linux/drivers/net/3c515.c
--- v2.4.5/linux/drivers/net/3c515.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/3c515.c	Wed Jun 20 11:10:53 2001
@@ -85,6 +85,11 @@
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM_DESC(debug, "3c515 debug level (0-6)");
+MODULE_PARM_DESC(options, "3c515: Bits 0-2: media type, bit 3: full duplex, bit 4: bus mastering");
+MODULE_PARM_DESC(full_duplex, "(ignored)");
+MODULE_PARM_DESC(rx_copybreak, "3c515 copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(max_interrupt_work, "3c515 maximum events handled per interrupt");
 
 /* "Knobs" for adjusting internal parameters. */
 /* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
diff -u --recursive --new-file v2.4.5/linux/drivers/net/3c523.c linux/drivers/net/3c523.c
--- v2.4.5/linux/drivers/net/3c523.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/3c523.c	Wed Jun 20 11:10:53 2001
@@ -1226,6 +1226,8 @@
 static int io[MAX_3C523_CARDS];
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i");
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i");
+MODULE_PARM_DESC(io, "EtherLink/MC I/O base address(es)");
+MODULE_PARM_DESC(irq, "EtherLink/MC IRQ number(s)");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.4.5/linux/drivers/net/3c59x.c	Thu Apr 12 12:16:35 2001
+++ linux/drivers/net/3c59x.c	Wed Jun 20 11:15:44 2001
@@ -142,6 +142,13 @@
     - If a device's internalconfig register reports it has NWAY,
       use it, even if autoselect is enabled.
 
+   LK1.1.15 6 June 2001 akpm
+    - Prevent double counting of received bytes (Lars Christensen)
+    - Add ethtool support (jgarzik)
+    - Add module parm descriptions (Andrzej M. Krzysztofowicz)
+    - Implemented alloc_etherdev() API
+    - Special-case the 'Tx error 82' message.
+
     - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details.
     - Also see Documentation/networking/vortex.txt
 */
@@ -155,6 +162,13 @@
  * elimination of all the tests and reduced cache footprint.
  */
 
+
+#define DRV_NAME	"3c59x"
+#define DRV_VERSION	"LK1.1.15"
+#define DRV_RELDATE	"6 June 2001"
+
+
+
 /* A few values that may be tweaked. */
 /* Keep the ring sizes a power of two for efficiency. */
 #define TX_RING_SIZE	16
@@ -208,9 +222,11 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/ethtool.h>
 #include <asm/irq.h>			/* For NR_IRQS only. */
 #include <asm/bitops.h>
 #include <asm/io.h>
+#include <asm/uaccess.h>
 
 /* Kernel compatibility defines, some common to David Hinds' PCMCIA package.
    This is only in the support-all-kernels source code. */
@@ -219,8 +235,9 @@
 
 #include <linux/delay.h>
 
+
 static char version[] __devinitdata =
-"3c59x.c:LK1.1.13 27 Jan 2001  Donald Becker and others. http://www.scyld.com/network/vortex.html\n";
+DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE "  Donald Becker and others. http://www.scyld.com/network/vortex.html\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver");
@@ -236,6 +253,18 @@
 MODULE_PARM(compaq_irq, "i");
 MODULE_PARM(compaq_device_id, "i");
 MODULE_PARM(watchdog, "i");
+MODULE_PARM_DESC(debug, "3c59x debug level (0-6)");
+MODULE_PARM_DESC(options, "3c59x: Bits 0-3: media type, bit 4: bus mastering, bit 9: full duplex");
+MODULE_PARM_DESC(full_duplex, "3c59x full duplex setting(s) (1)");
+MODULE_PARM_DESC(hw_checksums, "3c59x Hardware checksum checking by adapter(s) (0-1)");
+MODULE_PARM_DESC(flow_ctrl, "3c59x 802.3x flow control usage (PAUSE only) (0-1)");
+MODULE_PARM_DESC(enable_wol, "3c59x: Turn on Wake-on-LAN for adapter(s) (0-1)");
+MODULE_PARM_DESC(rx_copybreak, "3c59x copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(max_interrupt_work, "3c59x maximum events handled per interrupt");
+MODULE_PARM_DESC(compaq_ioaddr, "3c59x PCI I/O base address (Compaq BIOS problem workaround)");
+MODULE_PARM_DESC(compaq_irq, "3c59x PCI IRQ number (Compaq BIOS problem workaround)");
+MODULE_PARM_DESC(compaq_device_id, "3c59x PCI device ID (Compaq BIOS problem workaround)");
+MODULE_PARM_DESC(watchdog, "3c59x transmit timeout in milliseconds");
 
 /* Operational parameter that usually are not changed. */
 
@@ -251,7 +280,7 @@
    code size of a per-interface flag is not worthwhile. */
 static char mii_preamble_required;
 
-#define PFX "3c59x: "
+#define PFX DRV_NAME ": "
 
 
 
@@ -805,7 +834,9 @@
 
 static int vortex_cards_found;
 
-static void vortex_suspend (struct pci_dev *pdev)
+#ifdef CONFIG_PM
+
+static int vortex_suspend (struct pci_dev *pdev, u32 state)
 {
 	struct net_device *dev = pdev->driver_data;
 
@@ -818,9 +849,10 @@
 			vortex_down(dev);
 		}
 	}
+	return 0;
 }
 
-static void vortex_resume (struct pci_dev *pdev)
+static int vortex_resume (struct pci_dev *pdev)
 {
 	struct net_device *dev = pdev->driver_data;
 
@@ -833,8 +865,11 @@
 			netif_device_attach(dev);
 		}
 	}
+	return 0;
 }
 
+#endif /* CONFIG_PM */
+
 /* returns count found (>= 0), or negative on error */
 static int __init vortex_eisa_init (void)
 {
@@ -849,7 +884,7 @@
 	for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
 		int device_id;
 
-		if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "3c59x") == NULL)
+		if (request_region(ioaddr, VORTEX_TOTAL_SIZE, DRV_NAME) == NULL)
 			continue;
 
 		/* Check the standard EISA ID register for an encoded '3Com'. */
@@ -918,6 +953,7 @@
 	static int printed_version;
 	int retval;
 	struct vortex_chip_info * const vci = &vortex_info_tbl[chip_idx];
+	char *print_name;
 
 	if (!printed_version) {
 		printk (KERN_INFO "%s", version);
@@ -925,7 +961,9 @@
 		printed_version = 1;
 	}
 
-	dev = init_etherdev(NULL, sizeof(*vp));
+	print_name = pdev ? pdev->slot_name : "3c59x";
+
+	dev = alloc_etherdev(sizeof(*vp));
 	retval = -ENOMEM;
 	if (!dev) {
 		printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n");
@@ -934,7 +972,7 @@
 	SET_MODULE_OWNER(dev);
 
 	printk(KERN_INFO "%s: 3Com %s %s at 0x%lx, ",
-	       dev->name,
+	       print_name,
 	       pdev ? "PCI" : "EISA",
 	       vci->name,
 	       ioaddr);
@@ -958,7 +996,7 @@
 	if (pdev) {
 		/* EISA resources already marked, so only PCI needs to do this here */
 		/* Ignore return value, because Cardbus drivers already allocate for us */
-		if (request_region(ioaddr, vci->io_size, dev->name) != NULL)
+		if (request_region(ioaddr, vci->io_size, print_name) != NULL)
 			vp->must_free_region = 1;
 
 		/* enable bus-mastering if necessary */		
@@ -977,7 +1015,7 @@
 			if (pci_latency < new_latency) {
 				printk(KERN_INFO "%s: Overriding PCI latency"
 					" timer (CFLT) setting of %d, new value is %d.\n",
-					dev->name, pci_latency, new_latency);
+					print_name, pci_latency, new_latency);
 					pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency);
 			}
 		}
@@ -1107,7 +1145,7 @@
 				goto free_ring;
 		}
 		printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n",
-			   dev->name, fn_st_addr, vp->cb_fn_base);
+			   print_name, fn_st_addr, vp->cb_fn_base);
 		EL3WINDOW(2);
 
 		n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010;
@@ -1230,7 +1268,7 @@
 
 	if (vortex_debug > 0) {
 		printk(KERN_INFO "%s: scatter/gather %sabled. h/w checksums %sabled\n",
-				dev->name,
+				print_name,
 				(dev->features & NETIF_F_SG) ? "en":"dis",
 				(dev->features & NETIF_F_IP_CSUM) ? "en":"dis");
 	}
@@ -1241,7 +1279,9 @@
 	dev->set_multicast_list = set_rx_mode;
 	dev->tx_timeout = vortex_tx_timeout;
 	dev->watchdog_timeo = (watchdog * HZ) / 1000;
-	return 0;
+	retval = register_netdev(dev);
+	if (retval == 0)
+		return 0;
 
 free_ring:
 	pci_free_consistent(pdev,
@@ -1252,7 +1292,6 @@
 free_region:
 	if (vp->must_free_region)
 		release_region(ioaddr, vci->io_size);
-	unregister_netdev(dev);
 	kfree (dev);
 	printk(KERN_ERR PFX "vortex_probe1 fails.  Returns %d\n", retval);
 out:
@@ -1725,7 +1764,7 @@
 	unsigned char tx_status = 0;
 
 	if (vortex_debug > 2) {
-		printk(KERN_DEBUG "%s: vortex_error(), status=0x%x\n", dev->name, status);
+		printk(KERN_ERR "%s: vortex_error(), status=0x%x\n", dev->name, status);
 	}
 
 	if (status & TxComplete) {			/* Really "TxError" for us. */
@@ -1733,8 +1772,12 @@
 		/* Presumably a tx-timeout. We must merely re-enable. */
 		if (vortex_debug > 2
 			|| (tx_status != 0x88 && vortex_debug > 0)) {
-			printk(KERN_DEBUG"%s: Transmit error, Tx status register %2.2x.\n",
+			printk(KERN_ERR "%s: Transmit error, Tx status register %2.2x.\n",
 				   dev->name, tx_status);
+			if (tx_status == 0x82) {
+				printk(KERN_ERR "Probably a duplex mismatch.  See "
+						"Documentation/networking/vortex.txt\n");
+			}
 			dump_tx_ring(dev);
 		}
 		if (tx_status & 0x14)  vp->stats.tx_fifo_errors++;
@@ -2293,7 +2336,6 @@
 			struct sk_buff *skb;
 			dma_addr_t dma = le32_to_cpu(vp->rx_ring[entry].addr);
 
-			vp->stats.rx_bytes += pkt_len;
 			if (vortex_debug > 4)
 				printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
 					   pkt_len, rx_status);
@@ -2571,6 +2613,35 @@
 	return;
 }
 
+
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct vortex_private *vp = dev->priv;
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+
+        switch (ethcmd) {
+        case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strcpy(info.driver, DRV_NAME);
+		strcpy(info.version, DRV_VERSION);
+		if (vp->pdev)
+			strcpy(info.bus_info, vp->pdev->slot_name);
+		else
+			sprintf(info.bus_info, "EISA 0x%lx %d",
+				dev->base_addr, dev->irq);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+
+        }
+	
+	return -EOPNOTSUPP;
+}
+
 static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
@@ -2580,6 +2651,8 @@
 	int retval;
 
 	switch(cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 		data[0] = phy;
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
@@ -2774,9 +2847,11 @@
 	name:		"3c59x",
 	probe:		vortex_init_one,
 	remove:		vortex_remove_one,
+	id_table:	vortex_pci_tbl,
+#ifdef CONFIG_PM
 	suspend:	vortex_suspend,
 	resume:		vortex_resume,
-	id_table:	vortex_pci_tbl,
+#endif
 };
 
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/8139too.c linux/drivers/net/8139too.c
--- v2.4.5/linux/drivers/net/8139too.c	Mon May  7 14:13:19 2001
+++ linux/drivers/net/8139too.c	Wed Jun 20 11:10:52 2001
@@ -136,6 +136,10 @@
 
 */
 
+#define DRV_NAME	"8139too"
+#define DRV_VERSION	"0.9.18-pre3"
+
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -146,13 +150,14 @@
 #include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
 #include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
 #include <asm/io.h>
+#include <asm/uaccess.h>
 
 
-#define RTL8139_VERSION "0.9.17"
-#define MODNAME "8139too"
-#define RTL8139_DRIVER_NAME   MODNAME " Fast Ethernet driver " RTL8139_VERSION
-#define PFX MODNAME ": "
+#define RTL8139_DRIVER_NAME   DRV_NAME " Fast Ethernet driver " DRV_VERSION
+#define PFX DRV_NAME ": "
 
 
 /* enable PIO instead of MMIO, if CONFIG_8139TOO_PIO is selected */
@@ -363,7 +368,10 @@
 	TxOK = 0x04,
 	RxErr = 0x02,
 	RxOK = 0x01,
+
+	RxAckBits = RxFIFOOver | RxOverflow | RxOK,
 };
+
 enum TxStatusBits {
 	TxHostOwns = 0x2000,
 	TxUnderrun = 0x4000,
@@ -542,6 +550,11 @@
 
 };
 
+struct rtl_extra_stats {
+	unsigned long early_rx;
+	unsigned long tx_buf_mapped;
+	unsigned long tx_timeouts;
+};
 
 struct rtl8139_private {
 	void *mmio_addr;
@@ -560,7 +573,6 @@
 	dma_addr_t rx_ring_dma;
 	dma_addr_t tx_bufs_dma;
 	signed char phys[4];		/* MII device addresses. */
-	u16 advertising;		/* NWay media advertisement */
 	char twistie, twist_row, twist_col;	/* Twister tune state. */
 	unsigned int full_duplex:1;	/* Full-duplex operation requested. */
 	unsigned int duplex_lock:1;
@@ -574,6 +586,7 @@
 	wait_queue_head_t thr_wait;
 	struct semaphore thr_exited;
 	u32 rx_config;
+	struct rtl_extra_stats xstats;
 };
 
 MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
@@ -582,6 +595,10 @@
 MODULE_PARM (max_interrupt_work, "i");
 MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM (full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM_DESC (multicast_filter_limit, "8139too maximum number of filtered multicast addresses");
+MODULE_PARM_DESC (max_interrupt_work, "8139too maximum events handled per interrupt");
+MODULE_PARM_DESC (media, "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps");
+MODULE_PARM_DESC (full_duplex, "8139too: Force full duplex for board(s) (1)");
 
 static int read_eeprom (void *ioaddr, int location, int addr_len);
 static int rtl8139_open (struct net_device *dev);
@@ -984,11 +1001,11 @@
 		for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) {
 			int mii_status = mdio_read(dev, phy, 1);
 			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+				u16 advertising = mdio_read(dev, phy, 4);
 				tp->phys[phy_idx++] = phy;
-				tp->advertising = mdio_read(dev, phy, 4);
 				printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x "
 					   "advertising %4.4x.\n",
-					   dev->name, phy, mii_status, tp->advertising);
+					   dev->name, phy, mii_status, advertising);
 			}
 		}
 		if (phy_idx == 0) {
@@ -1314,6 +1331,28 @@
 }
 
 
+static void rtl_check_media (struct net_device *dev)
+{
+	struct rtl8139_private *tp = dev->priv;
+
+	DPRINTK("ENTER\n");
+	
+	if (tp->phys[0] >= 0) {
+		u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5);
+		if (mii_reg5 == 0xffff)
+			;					/* Not there */
+		else if ((mii_reg5 & 0x0100) == 0x0100
+				 || (mii_reg5 & 0x00C0) == 0x0040)
+			tp->full_duplex = 1;
+
+		printk (KERN_INFO"%s: Setting %s%s-duplex based on"
+				" auto-negotiated partner ability %4.4x.\n",
+		        dev->name, mii_reg5 == 0 ? "" :
+				(mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
+			tp->full_duplex ? "full" : "half", mii_reg5);
+	}
+}
+
 /* Start the hardware at open or resume. */
 static void rtl8139_hw_start (struct net_device *dev)
 {
@@ -1331,50 +1370,25 @@
 	rtl8139_chip_reset (ioaddr);
 
 	/* unlock Config[01234] and BMCR register writes */
-	RTL_W8 (Cfg9346, Cfg9346_Unlock);
+	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
 	/* Restore our idea of the MAC address. */
 	RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
-	RTL_W32 (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
+	RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
 
 	/* Must enable Tx/Rx before setting transfer thresholds! */
 	RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
 
 	tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
-	RTL_W32 (RxConfig, rtl8139_rx_config);
+	RTL_W32 (RxConfig, tp->rx_config);
 
 	/* Check this value: the documentation for IFG contradicts ifself. */
 	RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift));
 
 	tp->cur_rx = 0;
 	
-	DPRINTK("check_duplex");
-
-	/* This is check_duplex() */
-	if (tp->phys[0] >= 0  ||  (tp->drv_flags & HAS_MII_XCVR)) {
-		u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5);
-		if (mii_reg5 == 0xffff)
-			;					/* Not there */
-		else if ((mii_reg5 & 0x0100) == 0x0100
-				 || (mii_reg5 & 0x00C0) == 0x0040)
-			tp->full_duplex = 1;
-		if (mii_reg5) {
-			printk(KERN_INFO"%s: Setting %s%s-duplex based on"
-			   " auto-negotiated partner ability %4.4x.\n", dev->name,
-			   mii_reg5 == 0 ? "" :
-			   (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
-			   tp->full_duplex ? "full" : "half", mii_reg5);
-		} else {
-			printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n",
-			       dev->name);
-		}
-	}
+	rtl_check_media (dev);
 
 	if (tp->chipset >= CH_8139B) {
-		tmp = RTL_R8 (Config4) & ~(1<<2);
-		/* chip will clear Rx FIFO overflow automatically */
-		tmp |= (1<<7);
-		RTL_W8 (Config4, tmp);
-
 		/* disable magic packet scanning, which is enabled
 		 * when PM is enabled in Config1 */
 		RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5));
@@ -1654,6 +1668,8 @@
 		 RTL_R16 (IntrStatus),
 		 RTL_R8 (MediaStatus));
 
+	tp->xstats.tx_timeouts++;
+
 	/* disable Tx ASAP, if not already */
 	tmp8 = RTL_R8 (ChipCmd);
 	if (tmp8 & CmdTxEnb)
@@ -1691,6 +1707,10 @@
 	unsigned int entry;
 	unsigned long flags;
 
+	/* XXX paranoid + sledgehammer == temporary system crash fix */
+	wmb();
+	spin_lock_irqsave (&tp->lock, flags);
+
 	/* Calculate the next Tx descriptor entry. */
 	entry = tp->cur_tx % NUM_TX_DESC;
 
@@ -1701,13 +1721,14 @@
 	if ((long) skb->data & 3) {	/* Must use alignment buffer. */
 		/* tp->tx_info[entry].mapping = 0; */
 		memcpy (tp->tx_buf[entry], skb->data, skb->len);
-		RTL_W32 (TxAddr0 + (entry * 4),
-			 tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs));
+		RTL_W32_F (TxAddr0 + (entry * 4),
+			   tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs));
 	} else {
+		tp->xstats.tx_buf_mapped++;
 		tp->tx_info[entry].mapping =
 		    pci_map_single (tp->pci_dev, skb->data, skb->len,
 				    PCI_DMA_TODEVICE);
-		RTL_W32 (TxAddr0 + (entry * 4), tp->tx_info[entry].mapping);
+		RTL_W32_F (TxAddr0 + (entry * 4), tp->tx_info[entry].mapping);
 	}
 
 	/* Note: the chip doesn't have auto-pad! */
@@ -1716,8 +1737,6 @@
 
 	dev->trans_start = jiffies;
 
-	spin_lock_irqsave (&tp->lock, flags);
-
 	tp->cur_tx++;
 	if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
 		netif_stop_queue (dev);
@@ -1760,7 +1779,7 @@
 			tp->stats.tx_errors++;
 			if (txstatus & TxAborted) {
 				tp->stats.tx_aborted_errors++;
-				RTL_W32 (TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift));
+				RTL_W32_F (TxConfig, TxClearAbt);
 			}
 			if (txstatus & TxCarrierLost)
 				tp->stats.tx_carrier_errors++;
@@ -1865,11 +1884,10 @@
 
 
 static void rtl8139_rx_interrupt (struct net_device *dev,
-				  struct rtl8139_private *tp, void *ioaddr,
-				  u16 status)
+				  struct rtl8139_private *tp, void *ioaddr)
 {
 	unsigned char *rx_ring;
-	u16 cur_rx, ackstat;
+	u16 cur_rx;
 
 	assert (dev != NULL);
 	assert (tp != NULL);
@@ -1883,11 +1901,6 @@
 		 RTL_R16 (RxBufAddr),
 		 RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
 
-	if (status & RxFIFOOver)
-		status = RxOverflow | RxOK;
-	else
-		status = RxOK;
-
 	while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
 		int ring_offset = cur_rx % RX_BUF_LEN;
 		u32 rx_status;
@@ -1895,8 +1908,6 @@
 		unsigned int pkt_size;
 		struct sk_buff *skb;
 
-		mb();
-
 		/* read size+status of next frame from DMA ring buffer */
 		rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
 		rx_size = rx_status >> 16;
@@ -1916,8 +1927,10 @@
 		}
 #endif
 
-		if (rx_size == 0xfff0) /* Early Rx in progress */
+		if (rx_size == 0xfff0) { /* Early Rx in progress */
+			tp->xstats.early_rx++;
 			break;
+		}
 
 		/* If Rx err or invalid rx_size/rx_status received
 		 * (which happens if we get lost in the ring),
@@ -1963,9 +1976,8 @@
 		cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
 		RTL_W16 (RxBufPtr, cur_rx - 16);
 
-		ackstat = RTL_R16 (IntrStatus) & status;
-		if (ackstat)
-			RTL_W16 (IntrStatus, ackstat);
+		if (RTL_R16 (IntrStatus) & RxAckBits)
+			RTL_W16_F (IntrStatus, RxAckBits);
 	}
 
 	DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x,"
@@ -1975,11 +1987,9 @@
 
 	tp->cur_rx = cur_rx;
 
-	if (RTL_R8 (ChipCmd) & RxBufEmpty) {
-		ackstat = RTL_R16 (IntrStatus) & status;
-		if (ackstat)
-			RTL_W16_F (IntrStatus, ackstat);
-	}
+	if ((RTL_R8 (ChipCmd) & RxBufEmpty) &&
+	    (RTL_R16 (IntrStatus) & RxAckBits))
+		RTL_W16_F (IntrStatus, RxAckBits);
 }
 
 
@@ -2059,26 +2069,10 @@
 		if (status & RxUnderrun)
 			link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;
 
-		/* E. Gill */
-		/* In case of an RxFIFOOver we must also clear the RxOverflow
-		   bit to avoid dropping frames for ever. Believe me, I got a
-		   lot of troubles copying huge data (approximately 2 RxFIFOOver
-		   errors per 1GB data transfer).
-		   The following is written in the 'p-guide.pdf' file (RTL8139(A/B)
-		   Programming guide V0.1, from 1999/1/15) on page 9 from REALTEC.
-		   -----------------------------------------------------------
-		   2. RxFIFOOvw handling:
-		     When RxFIFOOvw occurs, all incoming packets are discarded.
-		     Clear ISR(RxFIFOOvw) doesn't dismiss RxFIFOOvw event. To
-		     dismiss RxFIFOOvw event, the ISR(RxBufOvw) must be written
-		     with a '1'.
-		   -----------------------------------------------------------
-		   Unfortunately I was not able to find any reason for the
-		   RxFIFOOver error (I got the feeling this depends on the
-		   CPU speed, lower CPU speed --> more errors).
-		   After clearing the RxOverflow bit the transfer of the
-		   packet was repeated and all data are error free transferred */
-		ackstat = status & ~(RxFIFOOver | RxOverflow | RxOK);
+		/* The chip takes special action when we clear RxAckBits,
+		 * so we clear them later in rtl8139_rx_interrupt
+		 */
+		ackstat = status & ~RxAckBits;
 		RTL_W16 (IntrStatus, ackstat);
 
 		DPRINTK ("%s: interrupt  status=%#4.4x ackstat=%#4.4x new intstat=%#4.4x.\n",
@@ -2089,9 +2083,8 @@
 		      RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0)
 			break;
 
-		if (netif_running (dev) &&
-		    status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver))	/* Rx interrupt */
-			rtl8139_rx_interrupt (dev, tp, ioaddr, status);
+		if (netif_running (dev) && (status & RxAckBits))
+			rtl8139_rx_interrupt (dev, tp, ioaddr);
 
 		/* Check uncommon events with one test. */
 		if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
@@ -2099,8 +2092,7 @@
 			rtl8139_weird_interrupt (dev, tp, ioaddr,
 						 status, link_changed);
 
-		if (netif_running (dev) &&
-		    status & (TxOK | TxErr)) {
+		if (netif_running (dev) && (status & (TxOK | TxErr))) {
 			spin_lock (&tp->lock);
 			rtl8139_tx_interrupt (dev, tp, ioaddr);
 			spin_unlock (&tp->lock);
@@ -2110,10 +2102,8 @@
 	} while (boguscnt > 0);
 
 	if (boguscnt <= 0) {
-		printk (KERN_WARNING
-			"%s: Too much work at interrupt, "
-			"IntrStatus=0x%4.4x.\n", dev->name,
-			status);
+		printk (KERN_WARNING "%s: Too much work at interrupt, "
+			"IntrStatus=0x%4.4x.\n", dev->name, status);
 
 		/* Clear all interrupt sources. */
 		RTL_W16 (IntrStatus, 0xffff);
@@ -2216,7 +2206,7 @@
 				if (tp->medialock)
 					tp->full_duplex = (value & 0x0100) ? 1 : 0;
 				break;
-			case 4: tp->advertising = value; break;
+			case 4: /* tp->advertising = value; */ break;
 			}
 		}
 		mdio_write(dev, data[0], data[1] & 0x1f, data[2]);
@@ -2308,8 +2298,9 @@
 		mc_filter[1] = mc_filter[0] = 0;
 		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
 		     i++, mclist = mclist->next) {
-			set_bit (ether_crc (ETH_ALEN, mclist->dmi_addr) >> 26,
-				 mc_filter);
+			int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+			mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
 			rx_mode |= AcceptMulticast;
 		}
 	}
@@ -2323,7 +2314,7 @@
 		tp->rx_config = tmp;
 	}
 	RTL_W32_F (MAR0 + 0, mc_filter[0]);
-	RTL_W32 (MAR0 + 4, mc_filter[1]);
+	RTL_W32_F (MAR0 + 4, mc_filter[1]);
 
 	spin_unlock_irqrestore (&tp->lock, flags);
 
@@ -2331,7 +2322,9 @@
 }
 
 
-static void rtl8139_suspend (struct pci_dev *pdev)
+#ifdef CONFIG_PM
+
+static int rtl8139_suspend (struct pci_dev *pdev, u32 state)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
 	struct rtl8139_private *tp = dev->priv;
@@ -2339,7 +2332,7 @@
 	unsigned long flags;
 
 	if (!netif_running (dev))
-		return;
+		return 0;
 
 	netif_device_detach (dev);
 
@@ -2354,27 +2347,33 @@
 	RTL_W32 (RxMissed, 0);
 
 	spin_unlock_irqrestore (&tp->lock, flags);
+	return 0;
 }
 
 
-static void rtl8139_resume (struct pci_dev *pdev)
+static int rtl8139_resume (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
 
 	if (!netif_running (dev))
-		return;
+		return 0;
 	netif_device_attach (dev);
 	rtl8139_hw_start (dev);
+	return 0;
 }
 
+#endif /* CONFIG_PM */
+
 
 static struct pci_driver rtl8139_pci_driver = {
-	name:		MODNAME,
+	name:		DRV_NAME,
 	id_table:	rtl8139_pci_tbl,
 	probe:		rtl8139_init_one,
 	remove:		rtl8139_remove_one,
+#ifdef CONFIG_PM
 	suspend:	rtl8139_suspend,
 	resume:		rtl8139_resume,
+#endif /* CONFIG_PM */
 };
 
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/82596.c linux/drivers/net/82596.c
--- v2.4.5/linux/drivers/net/82596.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/82596.c	Wed Jun 20 11:10:53 2001
@@ -151,6 +151,7 @@
 MODULE_AUTHOR("Richard Hirst");
 MODULE_DESCRIPTION("i82596 driver");
 MODULE_PARM(i596_debug, "i");
+MODULE_PARM_DESC(i596_debug, "i82596 debug mask");
 
 
 /* Copy frames shorter than rx_copybreak, otherwise pass on up in
@@ -1493,9 +1494,11 @@
 static int io = 0x300;
 static int irq = 10;
 MODULE_PARM(irq, "i");
+MODULE_PARM_DESC(irq, "Apricot IRQ number");
 #endif
 
 MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "i82596 debug mask");
 static int debug = -1;
 
 int init_module(void)
diff -u --recursive --new-file v2.4.5/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.4.5/linux/drivers/net/Config.in	Sat May 19 17:55:11 2001
+++ linux/drivers/net/Config.in	Wed Jun 20 11:10:52 2001
@@ -177,7 +177,9 @@
    fi
    bool '  Pocket and portable adapters' CONFIG_NET_POCKET
    if [ "$CONFIG_NET_POCKET" = "y" ]; then
-      dep_tristate '    AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP $CONFIG_ISA
+      if [ "$CONFIG_ISA" = "y" -a "$CONFIG_X86" = "y" ]; then
+         tristate '    AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
+      fi
       tristate '    D-Link DE600 pocket adapter support' CONFIG_DE600
       tristate '    D-Link DE620 pocket adapter support' CONFIG_DE620
    fi
diff -u --recursive --new-file v2.4.5/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.4.5/linux/drivers/net/Makefile	Wed May 16 10:25:38 2001
+++ linux/drivers/net/Makefile	Wed Jun 20 11:13:18 2001
@@ -30,7 +30,7 @@
 endif
 
 subdir-$(CONFIG_NET_PCMCIA) += pcmcia
-subdir-$(CONFIG_NET_RADIO) += wireless
+subdir-$(CONFIG_NET_WIRELESS) += wireless
 subdir-$(CONFIG_TULIP) += tulip
 subdir-$(CONFIG_IRDA) += irda
 subdir-$(CONFIG_TR) += tokenring
diff -u --recursive --new-file v2.4.5/linux/drivers/net/ac3200.c linux/drivers/net/ac3200.c
--- v2.4.5/linux/drivers/net/ac3200.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/ac3200.c	Wed Jun 20 11:10:53 2001
@@ -344,6 +344,9 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_AC32_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_AC32_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_AC32_CARDS) "i");
+MODULE_PARM_DESC(io, "ac3200 I/O base adress(es)");
+MODULE_PARM_DESC(irq, "ac3200 IRQ number(s)");
+MODULE_PARM_DESC(mem, "ac3200 Memory base address(es)");
 
 int
 init_module(void)
diff -u --recursive --new-file v2.4.5/linux/drivers/net/acenic.c linux/drivers/net/acenic.c
--- v2.4.5/linux/drivers/net/acenic.c	Fri Apr 13 20:26:07 2001
+++ linux/drivers/net/acenic.c	Wed Jun 20 11:10:53 2001
@@ -740,7 +740,6 @@
 }
 
 
-#ifdef MODULE
 MODULE_AUTHOR("Jes Sorensen <jes@linuxcare.com>");
 MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver");
 MODULE_PARM(link, "1-" __MODULE_STRING(8) "i");
@@ -749,7 +748,12 @@
 MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i");
-#endif
+MODULE_PARM_DESC(link, "Acenic/3C985/NetGear link state");
+MODULE_PARM_DESC(trace, "Acenic/3C985/NetGear firmware trace level");
+MODULE_PARM_DESC(tx_coal_tick, "Acenic/3C985/NetGear maximum clock ticks to wait for packets");
+MODULE_PARM_DESC(max_tx_desc, "Acenic/3C985/NetGear maximum number of transmit descriptors");
+MODULE_PARM_DESC(rx_coal_tick, "Acenic/3C985/NetGear maximum clock ticks to wait for packets");
+MODULE_PARM_DESC(max_rx_desc, "Acenic/3C985/NetGear maximum number of receive descriptors");
 
 
 static void __exit ace_module_cleanup(void)
diff -u --recursive --new-file v2.4.5/linux/drivers/net/aironet4500_card.c linux/drivers/net/aironet4500_card.c
--- v2.4.5/linux/drivers/net/aironet4500_card.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/aironet4500_card.c	Wed Jun 20 11:10:53 2001
@@ -707,14 +707,14 @@
 	awc_i365_card_release(s);
 
 
-	udelay(100000);
+	mdelay(100);
 	
 	i365_out(s, 0x2, 0x10 ); 	// power enable
-	udelay(200000);
+	mdelay(200);
 	
 	i365_out(s, 0x2, 0x10 | 0x01 | 0x04 | 0x80);	//power enable
 	
-	udelay(250000);
+	mdelay(250);
 	
 	if (!s->irq)
 		s->irq = 11;
@@ -740,7 +740,7 @@
 	i365_out(s,0x15,0x3f | 0x40);		// enab mem reg bit
 	i365_out(s,0x06,0x01);			// enab mem 
 	
-	udelay(10000);
+	mdelay(10);
 	
 	cis[0] = 0x45;
 	
@@ -751,7 +751,7 @@
 
 	mem[0x3e0] = 0x45;
 
-	udelay(10000);
+	mdelay(10);
 	
 	memcpy_fromio(cis,0xD000, 0x3e0);
 	
@@ -779,7 +779,7 @@
 		s->socket, s->manufacturer,s->product);
 
 	i365_out(s,0x07, 0x1 | 0x2); 		// enable io 16bit
-	udelay(1000);
+	mdelay(1);
 	port = s->io;
 	i365_out(s,0x08, port & 0xff);
 	i365_out(s,0x09, (port & 0xff00)/ 0x100);
@@ -788,7 +788,7 @@
 
 	i365_out(s,0x06, 0x40); 		// enable io window
 
-	udelay(1000);
+	mdelay(1);
 
 	i365_out(s,0x3e0,0x45);
 	
@@ -806,13 +806,10 @@
 
 	
 	outw(0x10, s->io + 0x34);
-	udelay(10000);
+	mdelay(10);
 	
 	return 0;
-	
-	
 
-		
 };
 
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/aironet4500_core.c linux/drivers/net/aironet4500_core.c
--- v2.4.5/linux/drivers/net/aironet4500_core.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/aironet4500_core.c	Wed Jun 20 11:10:53 2001
@@ -2567,7 +2567,7 @@
 MODULE_PARM(rx_queue_len,"i");
 MODULE_PARM(tx_rate,"i");
 MODULE_PARM(channel,"i");
-MODULE_PARM(tx_full_rate,"i");
+//MODULE_PARM(tx_full_rate,"i");
 MODULE_PARM(adhoc,"i");
 MODULE_PARM(master,"i");
 MODULE_PARM(slave,"i");
@@ -2576,6 +2576,12 @@
 MODULE_PARM(large_buff_mem,"i");
 MODULE_PARM(small_buff_no,"i");
 MODULE_PARM(SSID,"c33");
+MODULE_PARM_DESC(awc_debug,"Aironet debug mask");
+MODULE_PARM_DESC(channel,"Aironet ");
+MODULE_PARM_DESC(adhoc,"Aironet Access Points not available (0-1)");
+MODULE_PARM_DESC(master,"Aironet is Adhoc master (creates network sync) (0-1)");
+MODULE_PARM_DESC(slave,"Aironet is Adhoc slave (0-1)");
+MODULE_PARM_DESC(max_mtu,"Aironet MTU limit (256-2312)");
 #endif
 
 /*EXPORT_SYMBOL(tx_queue_len);
diff -u --recursive --new-file v2.4.5/linux/drivers/net/arlan.c linux/drivers/net/arlan.c
--- v2.4.5/linux/drivers/net/arlan.c	Tue Mar  6 19:28:33 2001
+++ linux/drivers/net/arlan.c	Wed Jun 20 11:10:53 2001
@@ -68,6 +68,23 @@
 MODULE_PARM(arlan_exit_debug, "i");
 MODULE_PARM(arlan_entry_and_exit_debug, "i");
 MODULE_PARM(arlan_EEPROM_bad, "i");
+MODULE_PARM_DESC(irq, "(unused)");
+MODULE_PARM_DESC(mem, "Arlan memory address for single device probing");
+MODULE_PARM_DESC(probe, "Arlan probe at initialization (0-1)");
+MODULE_PARM_DESC(arlan_debug, "Arlan debug enable (0-1)");
+MODULE_PARM_DESC(numDevices, "Number of Arlan devices; ignored if >1");
+MODULE_PARM_DESC(testMemory, "(unused)");
+MODULE_PARM_DESC(mdebug, "Arlan multicast debugging (0-1)");
+MODULE_PARM_DESC(retries, "Arlan maximum packet retransmisions");
+#ifdef ARLAN_ENTRY_EXIT_DEBUGGING
+MODULE_PARM_DESC(arlan_entry_debug, "Arlan driver function entry debugging");
+MODULE_PARM_DESC(arlan_exit_debug, "Arlan driver function exit debugging");
+MODULE_PARM_DESC(arlan_entry_and_exit_debug, "Arlan driver function entry and exit debugging");
+#else
+MODULE_PARM_DESC(arlan_entry_debug, "(ignored)");
+MODULE_PARM_DESC(arlan_exit_debug, "(ignored)");
+MODULE_PARM_DESC(arlan_entry_and_exit_debug, "(ignored)");
+#endif
 
 EXPORT_SYMBOL(arlan_device);
 EXPORT_SYMBOL(arlan_conf);
diff -u --recursive --new-file v2.4.5/linux/drivers/net/at1700.c linux/drivers/net/at1700.c
--- v2.4.5/linux/drivers/net/at1700.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/at1700.c	Wed Jun 20 11:13:18 2001
@@ -70,7 +70,7 @@
 
 /* These unusual address orders are used to verify the CONFIG register. */
 
-static int fmv18x_probe_list[] = {
+static int fmv18x_probe_list[] __initdata = {
 	0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0
 };
 
@@ -78,7 +78,7 @@
  *	ISA
  */
 
-static int at1700_probe_list[] = {
+static int at1700_probe_list[] __initdata = {
 	0x260, 0x280, 0x2a0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
 };
 
@@ -86,15 +86,15 @@
  *	MCA
  */
 #ifdef CONFIG_MCA	
-static int at1700_ioaddr_pattern[] = {
+static int at1700_ioaddr_pattern[] __initdata = {
 	0x00, 0x04, 0x01, 0x05, 0x02, 0x06, 0x03, 0x07
 };
 
-static int at1700_mca_probe_list[] = {
+static int at1700_mca_probe_list[] __initdata = {
 	0x400, 0x1400, 0x2400, 0x3400, 0x4400, 0x5400, 0x6400, 0x7400, 0
 };
 
-static int at1700_irq_pattern[] = {
+static int at1700_irq_pattern[] __initdata = {
 	0x00, 0x00, 0x00, 0x30, 0x70, 0xb0, 0x00, 0x00,
 	0x00, 0xf0, 0x34, 0x74, 0xb4, 0x00, 0x00, 0xf4, 0x00
 };
@@ -175,10 +175,10 @@
 };
 /* rEnE : maybe there are others I don't know off... */
 
-static struct at1720_mca_adapters_struct at1720_mca_adapters[] = {
+static struct at1720_mca_adapters_struct at1720_mca_adapters[] __initdata = {
 	{ "Allied Telesys AT1720AT",	0x6410 },
 	{ "Allied Telesys AT1720BT", 	0x6413 },
-	{ "Allied Telesys AT1720T",		0x6416 },
+	{ "Allied Telesys AT1720T",	0x6416 },
 	{ NULL, 0 },
 };
 #endif
@@ -470,7 +470,7 @@
 #define EE_READ_CMD		(6 << 6)
 #define EE_ERASE_CMD	(7 << 6)
 
-static int read_eeprom(int ioaddr, int location)
+static int __init read_eeprom(int ioaddr, int location)
 {
 	int i;
 	unsigned short retval = 0;
@@ -880,6 +880,9 @@
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
 MODULE_PARM(net_debug, "i");
+MODULE_PARM_DESC(io, "AT1700/FMV18X I/O base address");
+MODULE_PARM_DESC(irq, "AT1700/FMV18X IRQ number");
+MODULE_PARM_DESC(net_debug, "AT1700/FMV18X debug level (0-6)");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/atari_bionet.c linux/drivers/net/atari_bionet.c
--- v2.4.5/linux/drivers/net/atari_bionet.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/atari_bionet.c	Wed Jun 20 11:10:53 2001
@@ -127,6 +127,7 @@
  */
 unsigned int bionet_debug = NET_DEBUG;
 MODULE_PARM(bionet_debug, "i");
+MODULE_PARM_DESC(bionet_debug, "bionet debug level (0-2)");
 
 static unsigned int bionet_min_poll_time = 2;
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/atari_pamsnet.c linux/drivers/net/atari_pamsnet.c
--- v2.4.5/linux/drivers/net/atari_pamsnet.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/atari_pamsnet.c	Wed Jun 20 11:10:53 2001
@@ -123,6 +123,7 @@
  */
 unsigned int pamsnet_debug = NET_DEBUG;
 MODULE_PARM(pamsnet_debug, "i");
+MODULE_PARM_DESC(pamsnet_debug, "pamsnet debug enable (0-1)");
 
 static unsigned int pamsnet_min_poll_time = 2;
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/atarilance.c linux/drivers/net/atarilance.c
--- v2.4.5/linux/drivers/net/atarilance.c	Fri Apr 20 11:54:22 2001
+++ linux/drivers/net/atarilance.c	Wed Jun 20 11:10:53 2001
@@ -83,6 +83,7 @@
 static int lance_debug = 1;
 #endif
 MODULE_PARM(lance_debug, "i");
+MODULE_PARM_DESC(lance_debug, "atarilance debug level (0-3)");
 
 /* Print debug messages on probing? */
 #undef LANCE_DEBUG_PROBE
diff -u --recursive --new-file v2.4.5/linux/drivers/net/atp.c linux/drivers/net/atp.c
--- v2.4.5/linux/drivers/net/atp.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/atp.c	Wed Jun 20 11:10:53 2001
@@ -153,9 +153,14 @@
 MODULE_DESCRIPTION("RealTek RTL8002/8012 parallel port Ethernet driver");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(debug, "i");
-MODULE_PARM(io, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(xcvr, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(io, "1-" __MODULE_STRING(NUM_UNITS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(NUM_UNITS) "i");
+MODULE_PARM(xcvr, "1-" __MODULE_STRING(NUM_UNITS) "i");
+MODULE_PARM_DESC(max_interrupt_work, "ATP maximum events handled per interrupt");
+MODULE_PARM_DESC(debug, "ATP debug level (0-7)");
+MODULE_PARM_DESC(io, "ATP I/O base address(es)");
+MODULE_PARM_DESC(irq, "ATP IRQ number(s)");
+MODULE_PARM_DESC(xcvr, "ATP tranceiver(s) (0=internal, 1=external)");
 
 #define RUN_AT(x) (jiffies + (x))
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/bagetlance.c linux/drivers/net/bagetlance.c
--- v2.4.5/linux/drivers/net/bagetlance.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/bagetlance.c	Wed Jun 20 11:10:53 2001
@@ -1,5 +1,5 @@
 /* $Id$
- * vmelance.c: Ethernet driver for VME Lance cards on Baget/MIPS
+ * bagetlance.c: Ethernet driver for VME Lance cards on Baget/MIPS
  *      This code stealed and adopted from linux/drivers/net/atarilance.c
  *      See that for author info
  *
@@ -59,6 +59,7 @@
 static int lance_debug = 1;
 #endif
 MODULE_PARM(lance_debug, "i");
+MODULE_PARM_DESC(lance_debug, "Lance debug level (0-3)");
 
 /* Print debug messages on probing? */
 #undef LANCE_DEBUG_PROBE
diff -u --recursive --new-file v2.4.5/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c
--- v2.4.5/linux/drivers/net/cs89x0.c	Thu Apr 12 12:16:35 2001
+++ linux/drivers/net/cs89x0.c	Wed Jun 20 11:10:53 2001
@@ -1607,6 +1607,25 @@
 MODULE_PARM(dma , "i");
 MODULE_PARM(dmasize , "i");
 MODULE_PARM(use_dma , "i");
+MODULE_PARM_DESC(io, "cs89x0 I/O base address");
+MODULE_PARM_DESC(irq, "cs89x0 IRQ number");
+#if DEBUGGING
+MODULE_PARM_DESC(debug, "cs89x0 debug level (0-6)");
+#else
+MODULE_PARM_DESC(debug, "(ignored)");
+#endif
+MODULE_PARM_DESC(media, "Set cs89x0 adapter(s) media type(s) (rj45,bnc,aui)");
+/* No other value than -1 for duplex seems to be currently interpreted */
+MODULE_PARM_DESC(duplex, "(ignored)");
+#if ALLOW_DMA
+MODULE_PARM_DESC(dma , "cs89x0 ISA DMA channel; ignored if use_dma=0");
+MODULE_PARM_DESC(dmasize , "cs89x0 DMA size in kB (16,64); ignored if use_dma=0");
+MODULE_PARM_DESC(use_dma , "cs89x0 using DMA (0-1)");
+#else
+MODULE_PARM_DESC(dma , "(ignored)");
+MODULE_PARM_DESC(dmasize , "(ignored)");
+MODULE_PARM_DESC(use_dma , "(ignored)");
+#endif
 
 MODULE_AUTHOR("Mike Cruse, Russwll Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>");
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.4.5/linux/drivers/net/de4x5.c	Fri Apr 13 20:26:07 2001
+++ linux/drivers/net/de4x5.c	Wed Jun 20 11:10:53 2001
@@ -1044,6 +1044,9 @@
 MODULE_PARM(de4x5_debug, "i");
 MODULE_PARM(dec_only, "i");
 MODULE_PARM(args, "s");
+MODULE_PARM_DESC(de4x5_debug, "de4x5 debug mask");
+MODULE_PARM_DESC(dec_only, "de4x5 probe only for Digital boards (0-1)");
+MODULE_PARM_DESC(args, "de4x5 full duplex and media type settings; see de4x5.c for details");
 # else
 static int loading_module;
 #endif /* MODULE */
@@ -5784,6 +5787,7 @@
 static struct net_device *mdev = NULL;
 static int io=0x0;/* EDIT THIS LINE FOR YOUR CONFIGURATION IF NEEDED        */
 MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "de4x5 I/O base address");
 
 int
 init_module(void)
diff -u --recursive --new-file v2.4.5/linux/drivers/net/de600.c linux/drivers/net/de600.c
--- v2.4.5/linux/drivers/net/de600.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/de600.c	Wed Jun 20 11:10:53 2001
@@ -113,9 +113,11 @@
 
 static unsigned int de600_debug = DE600_DEBUG;
 MODULE_PARM(de600_debug, "i");
+MODULE_PARM_DESC(de600_debug, "DE-600 debug level (0-2)");
 
 static unsigned int delay_time = 10;
 MODULE_PARM(delay_time, "i");
+MODULE_PARM_DESC(delay_time, "DE-600 deley on I/O in microseconds");
 
 #ifdef FAKE_SMALL_MAX
 static unsigned long de600_rspace(struct sock *sk);
diff -u --recursive --new-file v2.4.5/linux/drivers/net/de620.c linux/drivers/net/de620.c
--- v2.4.5/linux/drivers/net/de620.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/de620.c	Wed Jun 20 11:10:53 2001
@@ -197,6 +197,12 @@
 MODULE_PARM(irq, "i");
 MODULE_PARM(clone, "i");
 MODULE_PARM(de620_debug, "i");
+MODULE_PARM_DESC(bnc, "DE-620 set BNC medium (0-1)");
+MODULE_PARM_DESC(utp, "DE-620 set UTP medium (0-1)");
+MODULE_PARM_DESC(io, "DE-620 I/O base address,required");
+MODULE_PARM_DESC(irq, "DE-620 IRQ number,required");
+MODULE_PARM_DESC(clone, "Check also for non-D-Link DE-620 clones (0-1)");
+MODULE_PARM_DESC(de620_debug, "DE-620 debug level (0-2)");
 
 /***********************************************
  *                                             *
diff -u --recursive --new-file v2.4.5/linux/drivers/net/depca.c linux/drivers/net/depca.c
--- v2.4.5/linux/drivers/net/depca.c	Fri Apr 13 20:26:07 2001
+++ linux/drivers/net/depca.c	Wed Jun 20 11:10:53 2001
@@ -2039,6 +2039,8 @@
 static int io=0x200;    /* Or use the irq= io= options to insmod */
 MODULE_PARM(irq, "i");
 MODULE_PARM(io, "i");
+MODULE_PARM_DESC(irq, "DEPCA IRQ number");
+MODULE_PARM_DESC(io, "DEPCA I/O base address");
 
 /* See depca_probe() for autoprobe messages when a module */	
 int
diff -u --recursive --new-file v2.4.5/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c
--- v2.4.5/linux/drivers/net/dgrs.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/dgrs.c	Wed Jun 20 11:10:53 2001
@@ -1441,6 +1441,9 @@
 MODULE_PARM(iptrap, "1-4i");
 MODULE_PARM(ipxnet, "i");
 MODULE_PARM(nicmode, "i");
+MODULE_PARM_DESC(debug, "Digi RightSwitch enable debugging (0-1)");
+MODULE_PARM_DESC(dma, "Digi RightSwitch enable BM DMA (0-1)");
+MODULE_PARM_DESC(nicmode, "Digi RightSwitch operating mode (1: switch, 2: multi-NIC)");
 
 static int __init dgrs_init_module (void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/dmfe.c linux/drivers/net/dmfe.c
--- v2.4.5/linux/drivers/net/dmfe.c	Sat May 19 18:05:23 2001
+++ linux/drivers/net/dmfe.c	Wed Jun 20 11:10:53 2001
@@ -2014,7 +2014,10 @@
 MODULE_PARM(HPNA_tx_cmd, "i");
 MODULE_PARM(HPNA_NoiseFloor, "i");
 MODULE_PARM(SF_mode, "i");
-
+MODULE_PARM_DESC(debug, "Davicom DM9xxx enable debugging (0-1)");
+MODULE_PARM_DESC(mode, "Davicom DM9xxx: Bit 0: 10/100Mbps, bit 2: duplex, bit 8: HomePNA");
+MODULE_PARM_DESC(SF_mode, "Davicom DM9xxx special function (bit 0: VLAN, bit 1 Flow Control, bit 2: TX pause packet)");
+                                                                                                                                
 /*	Description:
  *	when user used insmod to add module, system invoked init_module()
  *	to initilize and register.
diff -u --recursive --new-file v2.4.5/linux/drivers/net/e2100.c linux/drivers/net/e2100.c
--- v2.4.5/linux/drivers/net/e2100.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/e2100.c	Wed Jun 20 11:10:53 2001
@@ -386,6 +386,10 @@
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_E21_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_E21_CARDS) "i");
 MODULE_PARM(xcvr, "1-" __MODULE_STRING(MAX_E21_CARDS) "i");
+MODULE_PARM_DESC(io, "E2100 I/O base address(es)");
+MODULE_PARM_DESC(irq, "E2100 IRQ number(s)");
+MODULE_PARM_DESC(mem, " E2100 memory base address(es)");
+MODULE_PARM_DESC(xcvr, "E2100 tranceiver(s) (0=internal, 1=external)");
 
 /* This is set up so that only a single autoprobe takes place per call.
 ISA device autoprobes on a running machine are not recommended. */
diff -u --recursive --new-file v2.4.5/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
--- v2.4.5/linux/drivers/net/eepro.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/eepro.c	Wed Jun 20 11:10:53 2001
@@ -1771,6 +1771,10 @@
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_EEPRO) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_EEPRO) "i");
 MODULE_PARM(autodetect, "1-" __MODULE_STRING(1) "i");
+MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base addres(es)");
+MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)");
+MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)");
+MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)");
 
 int 
 init_module(void)
diff -u --recursive --new-file v2.4.5/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.4.5/linux/drivers/net/eepro100.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/eepro100.c	Wed Jun 20 11:16:01 2001
@@ -124,18 +124,29 @@
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(multicast_filter_limit, "i");
+MODULE_PARM_DESC(debug, "eepro100 debug level (0-6)");
+MODULE_PARM_DESC(options, "epro100: Bits 0-3: tranceiver type, bit 4: full duplex, bit 5: 100Mbps");
+MODULE_PARM_DESC(full_duplex, "epro100 full duplex setting(s) (1)");
+MODULE_PARM_DESC(congenb, "epro100  Enable congestion control (1)");
+MODULE_PARM_DESC(txfifo, "epro100 Tx FIFO threshold in 4 byte units, (0-15)");
+MODULE_PARM_DESC(rxfifo, "epro100 Rx FIFO threshold in 4 byte units, (0-15)");
+MODULE_PARM_DESC(txdmaccount, "epro100 Tx DMA burst length; 128 - disable (0-128)");
+MODULE_PARM_DESC(rxdmaccount, "epro100 Rx DMA burst length; 128 - disable (0-128)");
+MODULE_PARM_DESC(rx_copybreak, "epro100 copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(max_interrupt_work, "epro100 maximum events handled per interrupt");
+MODULE_PARM_DESC(multicast_filter_limit, "epro100 maximum number of filtered multicast addresses");
 
 #define RUN_AT(x) (jiffies + (x))
 
 /* ACPI power states don't universally work (yet) */
-#ifndef CONFIG_EEPRO100_PM
+#ifndef CONFIG_PM
 #undef pci_set_power_state
 #define pci_set_power_state null_set_power_state
 static inline int null_set_power_state(struct pci_dev *dev, int state)
 {
 	return 0;
 }
-#endif /* CONFIG_EEPRO100_PM */
+#endif /* CONFIG_PM */
 
 #define netdevice_start(dev)
 #define netdevice_stop(dev)
@@ -470,7 +481,7 @@
 	struct timer_list timer;			/* Media selection timer. */
 	struct speedo_mc_block *mc_setup_head;/* Multicast setup frame list head. */
 	struct speedo_mc_block *mc_setup_tail;/* Multicast setup frame list tail. */
-	int in_interrupt;					/* Word-aligned dev->interrupt */
+	long in_interrupt;					/* Word-aligned dev->interrupt */
 	unsigned char acpi_pwr;
 	signed char rx_mode;					/* Current PROMISC/ALLMULTI setting. */
 	unsigned int tx_full:1;				/* The Tx queue is full. */
@@ -512,9 +523,9 @@
 static int eepro100_init_one(struct pci_dev *pdev,
 		const struct pci_device_id *ent);
 static void eepro100_remove_one (struct pci_dev *pdev);
-#ifdef CONFIG_EEPRO100_PM
-static void eepro100_suspend (struct pci_dev *pdev);
-static void eepro100_resume (struct pci_dev *pdev);
+#ifdef CONFIG_PM
+static int eepro100_suspend (struct pci_dev *pdev, u32 state);
+static int eepro100_resume (struct pci_dev *pdev);
 #endif
 
 static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len);
@@ -1910,7 +1921,7 @@
 		   timer routine.  2000/05/09 SAW */
 		saved_acpi = pci_set_power_state(sp->pdev, 0);
 		t = del_timer_sync(&sp->timer);
-		data[3] = mdio_read(ioaddr, data[0], data[1]);
+		data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
 		if (t)
 			add_timer(&sp->timer); /* may be set to the past  --SAW */
 		pci_set_power_state(sp->pdev, saved_acpi);
@@ -2129,8 +2140,8 @@
 	sp->rx_mode = new_rx_mode;
 }
 
-#ifdef CONFIG_EEPRO100_PM
-static void eepro100_suspend(struct pci_dev *pdev)
+#ifdef CONFIG_PM
+static int eepro100_suspend(struct pci_dev *pdev, u32 state)
 {
 	struct net_device *dev = pdev->driver_data;
 	long ioaddr = dev->base_addr;
@@ -2139,9 +2150,10 @@
 	outl(PortPartialReset, ioaddr + SCBPort);
 	
 	/* XXX call pci_set_power_state ()? */
+	return 0;
 }
 
-static void eepro100_resume(struct pci_dev *pdev)
+static int eepro100_resume(struct pci_dev *pdev)
 {
 	struct net_device *dev = pdev->driver_data;
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
@@ -2160,8 +2172,9 @@
 	sp->rx_mode = -1;
 	sp->flow_ctrl = sp->partner = 0;
 	set_rx_mode(dev);
+	return 0;
 }
-#endif /* CONFIG_EEPRO100_PM */
+#endif /* CONFIG_PM */
 
 static void __devexit eepro100_remove_one (struct pci_dev *pdev)
 {
@@ -2192,7 +2205,7 @@
 		PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030,
 		PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82820FW_4,
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_7,
 		PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0,}
 };
@@ -2203,10 +2216,10 @@
 	id_table:	eepro100_pci_tbl,
 	probe:		eepro100_init_one,
 	remove:		eepro100_remove_one,
-#ifdef CONFIG_EEPRO100_PM
+#ifdef CONFIG_PM
 	suspend:	eepro100_suspend,
 	resume:		eepro100_resume,
-#endif
+#endif /* CONFIG_PM */
 };
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,48)
diff -u --recursive --new-file v2.4.5/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v2.4.5/linux/drivers/net/eexpress.c	Tue Mar 20 12:05:01 2001
+++ linux/drivers/net/eexpress.c	Wed Jun 20 11:10:53 2001
@@ -1632,6 +1632,8 @@
 
 MODULE_PARM(io, "1-" __MODULE_STRING(EEXP_MAX_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(EEXP_MAX_CARDS) "i");
+MODULE_PARM_DESC(io, "EtherExpress 16 I/O base address(es)");
+MODULE_PARM_DESC(irq, "EtherExpress 16 IRQ number(s)");
 
 /* Ideally the user would give us io=, irq= for every card.  If any parameters
  * are specified, we verify and then use them.  If no parameters are given, we
diff -u --recursive --new-file v2.4.5/linux/drivers/net/epic100.c linux/drivers/net/epic100.c
--- v2.4.5/linux/drivers/net/epic100.c	Sat May 19 18:02:45 2001
+++ linux/drivers/net/epic100.c	Wed Jun 20 11:13:18 2001
@@ -100,6 +100,7 @@
 #error You must compile this driver with "-O".
 #endif
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -116,6 +117,7 @@
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
+#include <linux/mii.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -135,6 +137,11 @@
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM_DESC(debug, "EPIC/100 debug level (0-5)");
+MODULE_PARM_DESC(max_interrupt_work, "EPIC/100 maximum events handled per interrupt");
+MODULE_PARM_DESC(options, "EPIC/100: Bits 0-3: media type, bit 4: full duplex");
+MODULE_PARM_DESC(rx_copybreak, "EPIC/100 copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(full_duplex, "EPIC/100 full duplex setting(s) (1)");
 
 /*
 				Theory of Operation
@@ -1169,7 +1176,7 @@
 			if (pkt_len > PKT_BUF_SZ - 4) {
 				printk(KERN_ERR "%s: Oversized Ethernet frame, status %x "
 					   "%d bytes.\n",
-					   dev->name, pkt_len, status);
+					   dev->name, status, pkt_len);
 				pkt_len = 1514;
 			}
 			/* Check if the packet is long enough to accept without copying
@@ -1445,38 +1452,46 @@
 }
 
 
-static void epic_suspend (struct pci_dev *pdev)
+#ifdef CONFIG_PM
+
+static int epic_suspend (struct pci_dev *pdev, u32 state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	long ioaddr = dev->base_addr;
 
 	if (!netif_running(dev))
-		return;
+		return 0;
 	epic_pause(dev);
 	/* Put the chip into low-power mode. */
 	outl(0x0008, ioaddr + GENCTL);
 	/* pci_power_off(pdev, -1); */
+	return 0;
 }
 
 
-static void epic_resume (struct pci_dev *pdev)
+static int epic_resume (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 
 	if (!netif_running(dev))
-		return;
+		return 0;
 	epic_restart(dev);
 	/* pci_power_on(pdev); */
+	return 0;
 }
 
+#endif /* CONFIG_PM */
+
 
 static struct pci_driver epic_driver = {
 	name:		DRV_NAME,
 	id_table:	epic_pci_tbl,
 	probe:		epic_init_one,
 	remove:		epic_remove_one,
+#ifdef CONFIG_PM
 	suspend:	epic_suspend,
 	resume:		epic_resume,
+#endif /* CONFIG_PM */
 };
 
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/es3210.c linux/drivers/net/es3210.c
--- v2.4.5/linux/drivers/net/es3210.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/es3210.c	Wed Jun 20 11:10:53 2001
@@ -383,6 +383,9 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ES_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ES_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_ES_CARDS) "i");
+MODULE_PARM_DESC(io, "ES3210 I/O base address(es)");
+MODULE_PARM_DESC(irq, "ES3210 IRQ number(s)");
+MODULE_PARM_DESC(mem, "ES3210 memory base address(es)");
 
 int
 init_module(void)
diff -u --recursive --new-file v2.4.5/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c
--- v2.4.5/linux/drivers/net/eth16i.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/eth16i.c	Wed Jun 20 11:10:53 2001
@@ -1407,7 +1407,7 @@
 MODULE_DESCRIPTION("ICL EtherTeam 16i/32 driver");
 
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i");
-MODULE_PARM_DESC(io, "eth16i io base address");
+MODULE_PARM_DESC(io, "eth16i I/O base address(es)");
 
 #if 0
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i");
@@ -1415,10 +1415,10 @@
 #endif
 
 MODULE_PARM(mediatype, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "s");
-MODULE_PARM_DESC(mediatype, "eth16i interfaceport mediatype");
+MODULE_PARM_DESC(mediatype, "eth16i media type of interface(s) (bnc,tp,dix,auto,eprom)");
 
 MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "eth16i debug level (0-4)");
+MODULE_PARM_DESC(debug, "eth16i debug level (0-6)");
 #endif
 
 int init_module(void)
diff -u --recursive --new-file v2.4.5/linux/drivers/net/ethertap.c linux/drivers/net/ethertap.c
--- v2.4.5/linux/drivers/net/ethertap.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/ethertap.c	Wed Jun 20 11:10:53 2001
@@ -336,6 +336,7 @@
 
 static int unit;
 MODULE_PARM(unit,"i");
+MODULE_PARM_DESC(unit,"Ethertap device number");
 
 static struct net_device dev_ethertap =
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- v2.4.5/linux/drivers/net/ewrk3.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/ewrk3.c	Wed Jun 20 11:10:53 2001
@@ -1849,6 +1849,8 @@
 
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
+MODULE_PARM_DESC(io, "EtherWORKS 3 I/O base address");
+MODULE_PARM_DESC(irq, "EtherWORKS 3 IRQ number");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/fc/iph5526.c linux/drivers/net/fc/iph5526.c
--- v2.4.5/linux/drivers/net/fc/iph5526.c	Wed Apr 18 14:40:05 2001
+++ linux/drivers/net/fc/iph5526.c	Wed Jun 20 11:19:02 2001
@@ -222,7 +222,7 @@
 static int get_scsi_oxid(struct fc_info *fi);
 static void update_scsi_oxid(struct fc_info *fi);
 
-Scsi_Host_Template driver_template = IPH5526_SCSI_FC;
+static Scsi_Host_Template driver_template = IPH5526_SCSI_FC;
 
 static void iph5526_timeout(struct net_device *dev);
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/fealnx.c linux/drivers/net/fealnx.c
--- v2.4.5/linux/drivers/net/fealnx.c	Thu May 24 15:37:37 2001
+++ linux/drivers/net/fealnx.c	Wed Jun 20 11:13:18 2001
@@ -46,6 +46,8 @@
 // #define RX_RING_SIZE    32
 #define TX_RING_SIZE    6
 #define RX_RING_SIZE    12
+#define TX_TOTAL_SIZE	TX_RING_SIZE*sizeof(struct fealnx_desc)
+#define RX_TOTAL_SIZE	RX_RING_SIZE*sizeof(struct fealnx_desc)
 
 /* Operational parameters that usually are not changed. */
 /* Time in jiffies before concluding the transmitter is hung. */
@@ -107,12 +109,18 @@
 MODULE_AUTHOR("Myson or whoever");
 MODULE_DESCRIPTION("Myson MTD-8xx 100/10M Ethernet PCI Adapter Driver");
 MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(min_pci_latency, "i");
+//MODULE_PARM(min_pci_latency, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(multicast_filter_limit, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM_DESC(max_interrupt_work, "fealnx maximum events handled per interrupt");
+MODULE_PARM_DESC(debug, "fealnx enable debugging (0-1)");
+MODULE_PARM_DESC(rx_copybreak, "fealnx copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(multicast_filter_limit, "fealnx maximum number of filtered multicast addresses");
+MODULE_PARM_DESC(options, "fealnx: Bits 0-3: media type, bit 17: full duplex");
+MODULE_PARM_DESC(full_duplex, "fealnx full duplex setting(s) (1)");
 
 #define MIN_REGION_SIZE 136
 
@@ -363,8 +371,11 @@
 
 struct netdev_private {
 	/* Descriptor rings first for alignment. */
-	struct fealnx_desc rx_ring[RX_RING_SIZE];
-	struct fealnx_desc tx_ring[TX_RING_SIZE];
+	struct fealnx_desc *rx_ring;
+	struct fealnx_desc *tx_ring;
+
+	dma_addr_t rx_ring_dma;
+	dma_addr_t tx_ring_dma;
 
 	struct net_device_stats stats;
 
@@ -461,6 +472,8 @@
 	long ioaddr;
 	unsigned int chip_id = ent->driver_data;
 	struct net_device *dev;
+	void *ring_space;
+	dma_addr_t ring_dma;
 	
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -528,6 +541,22 @@
 	np->flags = skel_netdrv_tbl[chip_id].flags;
 	pci_set_drvdata(pdev, dev);
 
+	ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);
+	if (!ring_space) {
+		err = -ENOMEM;
+		goto err_out_free_dev;
+	}
+	np->rx_ring = (struct fealnx_desc *)ring_space;
+	np->rx_ring_dma = ring_dma;
+
+	ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
+	if (!ring_space) {
+		err = -ENOMEM;
+		goto err_out_free_rx;
+	}
+	np->tx_ring = (struct fealnx_desc *)ring_space;
+	np->tx_ring_dma = ring_dma;
+
 	/* find the connected MII xcvrs */
 	if (np->flags == HAS_MII_XCVR) {
 		int phy, phy_idx = 0;
@@ -623,7 +652,7 @@
 	
 	err = register_netdev(dev);
 	if (err)
-		goto err_out_free;
+		goto err_out_free_tx;
 
 	printk(KERN_INFO "%s: %s at 0x%lx, ",
 	       dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr);
@@ -633,7 +662,11 @@
 
 	return 0;
 
-err_out_free:
+err_out_free_tx:
+	pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma);
+err_out_free_rx:
+	pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);
+err_out_free_dev:
 	kfree(dev);
 err_out_unmap:
 #ifndef USE_IO_OPS
@@ -647,7 +680,14 @@
 static void __devexit fealnx_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
+
 	if (dev) {
+		struct netdev_private *np = dev->priv;
+
+		pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring,
+			np->tx_ring_dma);
+		pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring,
+			np->rx_ring_dma);
 		unregister_netdev(dev);
 #ifndef USE_IO_OPS
 		iounmap((void *)dev->base_addr);
@@ -828,8 +868,8 @@
 
 	init_ring(dev);
 
-	writel(virt_to_bus(np->rx_ring), ioaddr + RXLBA);
-	writel(virt_to_bus(np->tx_ring), ioaddr + TXLBA);
+	writel(np->rx_ring_dma, ioaddr + RXLBA);
+	writel(np->tx_ring_dma, ioaddr + TXLBA);
 
 	/* Initialize other registers. */
 	/* Configure the PCI bus bursts and FIFO thresholds.
@@ -1077,7 +1117,8 @@
 			break;	/* Better luck next round. */
 
 		skb->dev = dev;	/* Mark as being used by this device. */
-		np->lack_rxbuf->buffer = virt_to_bus(skb->tail);
+		np->lack_rxbuf->buffer = pci_map_single(np->pci_dev, skb->tail,
+			np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 		np->lack_rxbuf = np->lack_rxbuf->next_desc_logical;
 		++np->really_rx_count;
 	}
@@ -1168,14 +1209,15 @@
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		np->rx_ring[i].status = 0;
 		np->rx_ring[i].control = np->rx_buf_sz << RBSShift;
-		np->rx_ring[i].next_desc = virt_to_bus(&np->rx_ring[i + 1]);
+		np->rx_ring[i].next_desc = np->rx_ring_dma +
+			(i + 1)*sizeof(struct fealnx_desc);
 		np->rx_ring[i].next_desc_logical = &np->rx_ring[i + 1];
 		np->rx_ring[i].skbuff = NULL;
 	}
 
 	/* for the last rx descriptor */
-	np->rx_ring[i - 1].next_desc = virt_to_bus(&np->rx_ring[0]);
-	np->rx_ring[i - 1].next_desc_logical = &np->rx_ring[0];
+	np->rx_ring[i - 1].next_desc = np->rx_ring_dma;
+	np->rx_ring[i - 1].next_desc_logical = np->rx_ring;
 
 	/* allocate skb for rx buffers */
 	for (i = 0; i < RX_RING_SIZE; i++) {
@@ -1189,7 +1231,8 @@
 		++np->really_rx_count;
 		np->rx_ring[i].skbuff = skb;
 		skb->dev = dev;	/* Mark as being used by this device. */
-		np->rx_ring[i].buffer = virt_to_bus(skb->tail);
+		np->rx_ring[i].buffer = pci_map_single(np->pci_dev, skb->tail,
+			np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 		np->rx_ring[i].status = RXOWN;
 		np->rx_ring[i].control |= RXIC;
 	}
@@ -1202,13 +1245,14 @@
 
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		np->tx_ring[i].status = 0;
-		np->tx_ring[i].next_desc = virt_to_bus(&np->tx_ring[i + 1]);
+		np->tx_ring[i].next_desc = np->tx_ring_dma +
+			(i + 1)*sizeof(struct fealnx_desc);
 		np->tx_ring[i].next_desc_logical = &np->tx_ring[i + 1];
 		np->tx_ring[i].skbuff = NULL;
 	}
 
 	/* for the last tx descriptor */
-	np->tx_ring[i - 1].next_desc = virt_to_bus(&np->tx_ring[0]);
+	np->tx_ring[i - 1].next_desc = np->tx_ring_dma;
 	np->tx_ring[i - 1].next_desc_logical = &np->tx_ring[0];
 
 	return;
@@ -1220,11 +1264,12 @@
 	struct netdev_private *np = dev->priv;
 
 	np->cur_tx_copy->skbuff = skb;
-	np->cur_tx_copy->buffer = virt_to_bus(skb->data);
 
 #define one_buffer
 #define BPT 1022
 #if defined(one_buffer)
+	np->cur_tx_copy->buffer = pci_map_single(np->pci_dev, skb->data,
+		skb->len, PCI_DMA_TODEVICE);
 	np->cur_tx_copy->control = TXIC | TXLD | TXFD | CRCEnable | PADEnable;
 	np->cur_tx_copy->control |= (skb->len << PKTSShift);	/* pkt size */
 	np->cur_tx_copy->control |= (skb->len << TBSShift);	/* buffer size */
@@ -1239,6 +1284,8 @@
 		struct fealnx_desc *next;
 
 		/* for the first descriptor */
+		np->cur_tx_copy->buffer = pci_map_single(np->pci_dev, skb->data,
+			BPT, PCI_DMA_TODEVICE);
 		np->cur_tx_copy->control = TXIC | TXFD | CRCEnable | PADEnable;
 		np->cur_tx_copy->control |= (skb->len << PKTSShift);	/* pkt size */
 		np->cur_tx_copy->control |= (BPT << TBSShift);	/* buffer size */
@@ -1252,7 +1299,8 @@
 // 89/12/29 add,
 		if (np->pci_dev->device == 0x891)
 			np->cur_tx_copy->control |= ETIControl | RetryTxLC;
-		next->buffer = virt_to_bus(skb->data) + BPT;
+		next->buffer = pci_map_single(ep->pci_dev, skb->data + BPT,
+                                skb->len - BPT, PCI_DMA_TODEVICE);
 
 		next->status = TXOWN;
 		np->cur_tx_copy->status = TXOWN;
@@ -1260,6 +1308,8 @@
 		np->cur_tx_copy = next->next_desc_logical;
 		np->free_tx_count -= 2;
 	} else {
+		np->cur_tx_copy->buffer = pci_map_single(np->pci_dev, skb->data,
+			skb->len, PCI_DMA_TODEVICE);
 		np->cur_tx_copy->control = TXIC | TXLD | TXFD | CRCEnable | PADEnable;
 		np->cur_tx_copy->control |= (skb->len << PKTSShift);	/* pkt size */
 		np->cur_tx_copy->control |= (skb->len << TBSShift);	/* buffer size */
@@ -1308,7 +1358,8 @@
 
 	allocate_rx_buffers(dev);
 
-	writel(virt_to_bus(np->cur_rx), dev->base_addr + RXLBA);
+	writel(np->rx_ring_dma + (np->cur_rx - np->rx_ring),
+		dev->base_addr + RXLBA);
 	writel(np->crvalue, dev->base_addr + TCRRCR);
 }
 
@@ -1421,6 +1472,8 @@
 			}
 
 			/* Free the original skb. */
+			pci_unmap_single(np->pci_dev, np->cur_tx->buffer,
+				np->cur_tx->skbuff->len, PCI_DMA_TODEVICE);
 			dev_kfree_skb_irq(np->cur_tx->skbuff);
 			np->cur_tx->skbuff = NULL;
 			--np->really_tx_count;
@@ -1554,6 +1607,10 @@
 				printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d"
 				       " status %x.\n", pkt_len, rx_status);
 #endif
+			pci_dma_sync_single(np->pci_dev, np->cur_rx->buffer,
+				np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			pci_unmap_single(np->pci_dev, np->cur_rx->buffer,
+				np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 
 			/* Check if the packet is long enough to accept without copying
 			   to a minimally-sized skbuff. */
@@ -1564,12 +1621,12 @@
 				/* Call copy + cksum if available. */
 
 #if ! defined(__alpha__)
-				eth_copy_and_sum(skb, bus_to_virt(np->cur_rx->buffer),
-						 pkt_len, 0);
+				eth_copy_and_sum(skb, 
+					np->cur_rx->skbuff->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
 #else
 				memcpy(skb_put(skb, pkt_len),
-				       bus_to_virt(np->cur_rx->buffer), pkt_len);
+					np->cur_rx->skbuff->tail, pkt_len);
 #endif
 			} else {
 				skb_put(skb = np->cur_rx->skbuff, pkt_len);
@@ -1592,7 +1649,8 @@
 
 			if (skb != NULL) {
 				skb->dev = dev;	/* Mark as being used by this device. */
-				np->cur_rx->buffer = virt_to_bus(skb->tail);
+				np->cur_rx->buffer = pci_map_single(np->pci_dev, skb->tail,
+					np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 				np->cur_rx->skbuff = skb;
 				++np->really_rx_count;
 			}
@@ -1727,16 +1785,26 @@
 
 	/* Free all the skbuffs in the Rx queue. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb = np->rx_ring[i].skbuff;
+
 		np->rx_ring[i].status = 0;
-		if (np->rx_ring[i].skbuff)
-			dev_kfree_skb(np->rx_ring[i].skbuff);
-		np->rx_ring[i].skbuff = NULL;
+		if (skb) {
+			pci_unmap_single(np->pci_dev, np->rx_ring[i].buffer,
+				np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(skb);
+			np->rx_ring[i].skbuff = NULL;
+		}
 	}
 
 	for (i = 0; i < TX_RING_SIZE; i++) {
-		if (np->tx_ring[i].skbuff)
-			dev_kfree_skb(np->tx_ring[i].skbuff);
-		np->tx_ring[i].skbuff = NULL;
+		struct sk_buff *skb = np->tx_ring[i].skbuff;
+
+		if (skb) {
+			pci_unmap_single(np->pci_dev, np->tx_ring[i].buffer,
+				skb->len, PCI_DMA_TODEVICE);
+			dev_kfree_skb(skb);
+			np->tx_ring[i].skbuff = NULL;
+		}
 	}
 
 	return 0;
diff -u --recursive --new-file v2.4.5/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c
--- v2.4.5/linux/drivers/net/fmv18x.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/fmv18x.c	Wed Jun 20 11:10:53 2001
@@ -628,6 +628,9 @@
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
 MODULE_PARM(net_debug, "i");
+MODULE_PARM_DESC(io, "FMV-18X I/O address");
+MODULE_PARM_DESC(irq, "FMV-18X IRQ number");
+MODULE_PARM_DESC(net_debug, "FMV-18X debug level (0-1,5-6)");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/hamachi.c linux/drivers/net/hamachi.c
--- v2.4.5/linux/drivers/net/hamachi.c	Sat May 19 18:02:45 2001
+++ linux/drivers/net/hamachi.c	Wed Jun 20 11:10:53 2001
@@ -535,7 +535,22 @@
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(force32, "i");
-
+MODULE_PARM_DESC(max_interrupt_work, "GNIC-II maximum events handled per interrupt");
+MODULE_PARM_DESC(mtu, "GNIC-II MTU (all boards)");
+MODULE_PARM_DESC(debug, "GNIC-II debug level (0-7)");
+MODULE_PARM_DESC(min_rx_pkt, "GNIC-II minimum Rx packets processed between interrupts");
+MODULE_PARM_DESC(max_rx_gap, "GNIC-II maximum Rx inter-packet gap in 8.192 microsecond units");
+MODULE_PARM_DESC(max_rx_latency, "GNIC-II time between Rx interrupts in 8.192 microsecond units");
+MODULE_PARM_DESC(min_tx_pkt, "GNIC-II minimum Tx packets processed between interrupts");
+MODULE_PARM_DESC(max_tx_gap, "GNIC-II maximum Tx inter-packet gap in 8.192 microsecond units");
+MODULE_PARM_DESC(max_tx_latency, "GNIC-II time between Tx interrupts in 8.192 microsecond units");
+MODULE_PARM_DESC(rx_copybreak, "GNIC-II copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(rx_params, "GNIC-II min_rx_pkt+max_rx_gap+max_rx_latency");
+MODULE_PARM_DESC(tx_params, "GNIC-II min_tx_pkt+max_tx_gap+max_tx_latency");
+MODULE_PARM_DESC(options, "GNIC-II Bits 0-3: media type, bits 4-6: as force32, bit 7: half duplex, bit 9 full duplex");
+MODULE_PARM_DESC(full_duplex, "GNIC-II full duplex setting(s) (1)");
+MODULE_PARM_DESC(force32, "GNIC-II: Bit 0: 32 bit PCI, bit 1: disable parity, bit 2: 64 bit PCI (all boards)");
+                                                                        
 static int read_eeprom(long ioaddr, int location);
 static int mdio_read(long ioaddr, int phy_id, int location);
 static void mdio_write(long ioaddr, int phy_id, int location, int value);
diff -u --recursive --new-file v2.4.5/linux/drivers/net/hp-plus.c linux/drivers/net/hp-plus.c
--- v2.4.5/linux/drivers/net/hp-plus.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/hp-plus.c	Wed Jun 20 11:10:53 2001
@@ -408,6 +408,8 @@
 
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_HPP_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_HPP_CARDS) "i");
+MODULE_PARM_DESC(io, "HP PC-LAN+ I/O port address(es)");
+MODULE_PARM_DESC(irq, "HP PC-LAN+ IRQ number(s); ignored if properly detected");
 
 /* This is set up so that only a single autoprobe takes place per call.
 ISA device autoprobes on a running machine are not recommended. */
diff -u --recursive --new-file v2.4.5/linux/drivers/net/hp.c linux/drivers/net/hp.c
--- v2.4.5/linux/drivers/net/hp.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/hp.c	Wed Jun 20 11:10:53 2001
@@ -379,6 +379,8 @@
 
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_HP_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_HP_CARDS) "i");
+MODULE_PARM_DESC(io, "HP PC-LAN I/O base address(es)");
+MODULE_PARM_DESC(irq, "HP PC-LAN IRQ number(s) (assigned)");
 
 /* This is set up so that only a single autoprobe takes place per call.
 ISA device autoprobes on a running machine are not recommended. */
diff -u --recursive --new-file v2.4.5/linux/drivers/net/ibmlana.c linux/drivers/net/ibmlana.c
--- v2.4.5/linux/drivers/net/ibmlana.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/ibmlana.c	Wed Jun 20 11:10:53 2001
@@ -1197,6 +1197,8 @@
 static int io;
 MODULE_PARM(irq, "i");
 MODULE_PARM(io, "i");
+MODULE_PARM_DESC(irq, "IBM LAN/A IRQ number");
+MODULE_PARM_DESC(io, "IBM LAN/A I/O base address");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v2.4.5/linux/drivers/net/lance.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/lance.c	Wed Jun 20 11:10:53 2001
@@ -299,6 +299,10 @@
 MODULE_PARM(dma, "1-" __MODULE_STRING(MAX_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i");
 MODULE_PARM(lance_debug, "i");
+MODULE_PARM_DESC(io, "LANCE/PCnet I/O base address(es),required");
+MODULE_PARM_DESC(dma, "LANCE/PCnet ISA DMA channel (ignored for some devices)");
+MODULE_PARM_DESC(irq, "LANCE/PCnet IRQ number (ignored for some devices)");
+MODULE_PARM_DESC(lance_debug, "LANCE/PCnet debug level (0-7)");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/lasi_82596.c linux/drivers/net/lasi_82596.c
--- v2.4.5/linux/drivers/net/lasi_82596.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/lasi_82596.c	Wed Jun 20 11:10:53 2001
@@ -181,7 +181,7 @@
 MODULE_AUTHOR("Richard Hirst");
 MODULE_DESCRIPTION("i82596 driver");
 MODULE_PARM(i596_debug, "i");
-
+MODULE_PARM_DESC(i596_debug, "lasi_82596 debug mask");
 
 /* Copy frames shorter than rx_copybreak, otherwise pass on up in
  * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
diff -u --recursive --new-file v2.4.5/linux/drivers/net/lne390.c linux/drivers/net/lne390.c
--- v2.4.5/linux/drivers/net/lne390.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/lne390.c	Wed Jun 20 11:10:53 2001
@@ -381,6 +381,9 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i");
+MODULE_PARM_DESC(io, "LNE390 I/O base address(es)");
+MODULE_PARM_DESC(irq, "LNE390 IRQ number(s)");
+MODULE_PARM_DESC(mem, "LNE390 memory base address(es)");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/mac89x0.c linux/drivers/net/mac89x0.c
--- v2.4.5/linux/drivers/net/mac89x0.c	Tue Mar  6 19:28:35 2001
+++ linux/drivers/net/mac89x0.c	Wed Jun 20 11:10:53 2001
@@ -626,6 +626,7 @@
 static int debug;
 
 MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "CS89[02]0 debug level (0-5)");
 
 EXPORT_NO_SYMBOLS;
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/mace.c linux/drivers/net/mace.c
--- v2.4.5/linux/drivers/net/mace.c	Sun May 20 12:11:38 2001
+++ linux/drivers/net/mace.c	Wed Jun 20 11:10:53 2001
@@ -25,6 +25,7 @@
 static int port_aaui = -1;
 
 MODULE_PARM(port_aaui, "i");
+MODULE_PARM_DESC(port_aaui, "MACE uses AAUI port (0-1)");
 
 #define N_RX_RING	8
 #define N_TX_RING	6
diff -u --recursive --new-file v2.4.5/linux/drivers/net/macsonic.c linux/drivers/net/macsonic.c
--- v2.4.5/linux/drivers/net/macsonic.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/macsonic.c	Wed Jun 20 11:10:53 2001
@@ -575,6 +575,7 @@
 static struct net_device dev_macsonic;
 
 MODULE_PARM(sonic_debug, "i");
+MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)");
 
 EXPORT_NO_SYMBOLS;
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/natsemi.c linux/drivers/net/natsemi.c
--- v2.4.5/linux/drivers/net/natsemi.c	Sat May 19 18:02:45 2001
+++ linux/drivers/net/natsemi.c	Wed Jun 20 11:13:18 2001
@@ -51,10 +51,24 @@
 		* One-liner removal of a duplicate declaration of
 		netdev_error(). (uzi)
 
+	Version 1.0.7: (Manfred Spraul)
+		* pci dma
+		* SMP locking update
+		* full reset added into tx_timeout
+		* correct multicast hash generation (both big and little endian)
+			[copied from a natsemi driver version
+			 from Myrio Corporation, Greg Smith]
+		* suspend/resume
+
+	TODO:
+	* big endian support with CFG:BEM instead of cpu_to_le32
+	* support for an external PHY
+	* flow control
+	* Wake-On-LAN
 */
 
 #define DRV_NAME	"natsemi"
-#define DRV_VERSION	"1.07+LK1.0.6"
+#define DRV_VERSION	"1.07+LK1.0.7"
 #define DRV_RELDATE	"May 18, 2001"
 
 
@@ -111,6 +125,8 @@
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT  (2*HZ)
 
+#define NATSEMI_HW_TIMEOUT	200
+
 #define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
 
 #if !defined(__OPTIMIZE__)
@@ -119,6 +135,7 @@
 #error You must compile this driver with "-O".
 #endif
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -134,6 +151,8 @@
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/rtnetlink.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -145,10 +164,6 @@
 KERN_INFO "  http://www.scyld.com/network/natsemi.html\n"
 KERN_INFO "  (unofficial 2.4.x kernel port, version " DRV_VERSION ", " DRV_RELDATE "  Jeff Garzik, Tjeerd Mulder)\n";
 
-/* Condensed operations for readability. */
-#define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
-#define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
-
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("National Semiconductor DP8381x series PCI Ethernet driver");
 MODULE_PARM(max_interrupt_work, "i");
@@ -157,6 +172,12 @@
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM_DESC(max_interrupt_work, "DP8381x maximum events handled per interrupt");
+MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)");
+MODULE_PARM_DESC(debug, "DP8381x debug level (0-5)");
+MODULE_PARM_DESC(rx_copybreak, "DP8381x copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(options, "DP8381x: Bits 0-3: media type, bit 17: full duplex");
+MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)");
 
 /*
 				Theory of Operation
@@ -330,15 +351,17 @@
 	DescPktOK=0x08000000, RxTooLong=0x00400000,
 };
 
-#define PRIV_ALIGN	15 	/* Required alignment mask */
 struct netdev_private {
 	/* Descriptor rings first for alignment. */
-	struct netdev_desc rx_ring[RX_RING_SIZE];
-	struct netdev_desc tx_ring[TX_RING_SIZE];
+	dma_addr_t ring_dma;
+	struct netdev_desc* rx_ring;
+	struct netdev_desc* tx_ring;
 	/* The addresses of receive-in-place skbuffs. */
 	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+	dma_addr_t rx_dma[RX_RING_SIZE];
 	/* The saved address of a sent-in-place packet/buffer, for later free(). */
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+	dma_addr_t tx_dma[TX_RING_SIZE];
 	struct net_device_stats stats;
 	struct timer_list timer;	/* Media monitoring timer. */
 	/* Frequently used values: keep some adjacent for cache effect. */
@@ -348,10 +371,7 @@
 	unsigned int cur_tx, dirty_tx;
 	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
 	/* These values are keep track of the transceiver/media in use. */
-	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
-	unsigned int duplex_lock:1;
-	unsigned int medialock:1;			/* Do not sense media. */
-	unsigned int default_port:4;		/* Last dev->if_port value. */
+	unsigned int full_duplex;
 	/* Rx filter. */
 	u32 cur_rx_mode;
 	u32 rx_filter[16];
@@ -360,24 +380,31 @@
 	/* original contents of ClkRun register */
 	u32 SavedClkRun;
 	/* MII transceiver section. */
-	u16 advertising;					/* NWay media advertisement */
-	
+	u16 advertising;			/* NWay media advertisement */
 	unsigned int iosize;
 	spinlock_t lock;
 };
 
 static int  eeprom_read(long ioaddr, int location);
 static int  mdio_read(struct net_device *dev, int phy_id, int location);
+static void natsemi_reset(struct net_device *dev);
 static int  netdev_open(struct net_device *dev);
-static void check_duplex(struct net_device *dev);
+static void check_link(struct net_device *dev);
 static void netdev_timer(unsigned long data);
 static void tx_timeout(struct net_device *dev);
+static int alloc_ring(struct net_device *dev);
 static void init_ring(struct net_device *dev);
+static void drain_ring(struct net_device *dev);
+static void free_ring(struct net_device *dev);
+static void init_registers(struct net_device *dev);
 static int  start_tx(struct sk_buff *skb, struct net_device *dev);
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
 static void netdev_error(struct net_device *dev, int intr_status);
-static int  netdev_rx(struct net_device *dev);
+static void netdev_rx(struct net_device *dev);
+static void netdev_tx_done(struct net_device *dev);
+static void __set_rx_mode(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
+static void __get_stats(struct net_device *dev);
 static struct net_device_stats *get_stats(struct net_device *dev);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int  netdev_close(struct net_device *dev);
@@ -417,7 +444,6 @@
 	}
 
 	find_cnt++;
-	option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
 	ioaddr = pci_resource_start(pdev, pcibar);
 	iosize = pci_resource_len(pdev, pcibar);
 	irq = pdev->irq;
@@ -455,9 +481,6 @@
 		prev_eedata = eedata;
 	}
 
-	/* Reset the chip to erase previous misconfiguration. */
-	writel(ChipReset, ioaddr + ChipCmd);
-
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 
@@ -468,6 +491,9 @@
 	np->iosize = iosize;
 	spin_lock_init(&np->lock);
 
+	/* Reset the chip to erase previous misconfiguration. */
+	natsemi_reset(dev);
+	option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
 	if (dev->mem_start)
 		option = dev->mem_start;
 
@@ -475,16 +501,13 @@
 	if (option > 0) {
 		if (option & 0x200)
 			np->full_duplex = 1;
-		np->default_port = option & 15;
-		if (np->default_port)
-			np->medialock = 1;
+		if (option & 15)
+			printk(KERN_INFO "%s: ignoring user supplied media type %d",
+				dev->name, option & 15);
 	}
 	if (find_cnt < MAX_UNITS  &&  full_duplex[find_cnt] > 0)
 		np->full_duplex = 1;
 
-	if (np->full_duplex)
-		np->duplex_lock = 1;
-
 	/* The chip-specific entries in the device structure. */
 	dev->open = &netdev_open;
 	dev->hard_start_xmit = &start_tx;
@@ -598,6 +621,25 @@
 		return 0xffff;
 }
 
+static void natsemi_reset(struct net_device *dev)
+{
+	int i;
+
+	writel(ChipReset, dev->base_addr + ChipCmd);
+	for (i=0;i<NATSEMI_HW_TIMEOUT;i++) {
+		if (!(readl(dev->base_addr + ChipCmd) & ChipReset))
+			break;
+		udelay(5);
+	}
+	if (i==NATSEMI_HW_TIMEOUT && debug) {
+		printk(KERN_INFO "%s: reset did not complete in %d usec.\n",
+		   dev->name, i*5);
+	} else if (debug > 2) {
+		printk(KERN_DEBUG "%s: reset completed in %d usec.\n",
+		   dev->name, i*5);
+	}
+}
+
 
 static int netdev_open(struct net_device *dev)
 {
@@ -606,25 +648,7 @@
 	int i;
 
 	/* Reset the chip, just in case. */
-	writel(ChipReset, ioaddr + ChipCmd);
-
-	/* On page 78 of the spec, they recommend some settings for "optimum
-	   performance" to be done in sequence.  These settings optimize some
-	   of the 100Mbit autodetection circuitry.  Also, we only want to do
-	   this for rev C of the chip.
-	*/
-	if (readl(ioaddr + SiliconRev) == 0x302) {
-		writew(0x0001, ioaddr + PGSEL);
-		writew(0x189C, ioaddr + PMDCSR);
-		writew(0x0000, ioaddr + TSTDAT);
-		writew(0x5040, ioaddr + DSPCFG);
-		writew(0x008C, ioaddr + SDCFG);
-	}
-
-	/* Enable PHY Specific event based interrupts.  Link state change
-	   and Auto-Negotiation Completion are among the affected.
-	*/
-	writew(0x0002, ioaddr + MIntrCtrl);
+	natsemi_reset(dev);
 
 	i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
 	if (i) return i;
@@ -632,56 +656,16 @@
 	if (debug > 1)
 		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
 			   dev->name, dev->irq);
-
-	init_ring(dev);
-
-	writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
-	writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
-
-	for (i = 0; i < ETH_ALEN; i += 2) {
-		writel(i, ioaddr + RxFilterAddr);
-		writew(dev->dev_addr[i] + (dev->dev_addr[i+1] << 8),
-			   ioaddr + RxFilterData);
-	}
-
-	/* Initialize other registers. */
-	/* Configure the PCI bus bursts and FIFO thresholds. */
-	/* Configure for standard, in-spec Ethernet. */
-
-	if (readl(ioaddr + ChipConfig) & 0x20000000) {	/* Full duplex */
-		np->tx_config = 0xD0801002;
-		np->rx_config = 0x10000020;
-	} else {
-		np->tx_config = 0x10801002;
-		np->rx_config = 0x0020;
+	i = alloc_ring(dev);
+	if (i < 0) {
+		free_irq(dev->irq, dev);
+		return i;
 	}
-	writel(np->tx_config, ioaddr + TxConfig);
-	writel(np->rx_config, ioaddr + RxConfig);
-
-	if (dev->if_port == 0)
-		dev->if_port = np->default_port;
-
-	/* Disable PME:
-	 * The PME bit is initialized from the EEPROM contents.
-	 * PCI cards probably have PME disabled, but motherboard
-	 * implementations may have PME set to enable WakeOnLan. 
-	 * With PME set the chip will scan incoming packets but
-	 * nothing will be written to memory. */
-	np->SavedClkRun = readl(ioaddr + ClkRun);
-	writel(np->SavedClkRun & ~0x100, ioaddr + ClkRun);
+	init_ring(dev);
+	init_registers(dev);
 
 	netif_start_queue(dev);
 
-	check_duplex(dev);
-	set_rx_mode(dev);
-
-	/* Enable interrupts by setting the interrupt mask. */
-	writel(IntrNormalSummary | IntrAbnormalSummary | 0x1f, ioaddr + IntrMask);
-	writel(1, ioaddr + IntrEnable);
-
-	writel(RxOn | TxOn, ioaddr + ChipCmd);
-	writel(4, ioaddr + StatsCtrl); 					/* Clear Stats */
-
 	if (debug > 2)
 		printk(KERN_DEBUG "%s: Done netdev_open(), status: %x.\n",
 			   dev->name, (int)readl(ioaddr + ChipCmd));
@@ -696,17 +680,33 @@
 	return 0;
 }
 
-static void check_duplex(struct net_device *dev)
+static void check_link(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int duplex;
+	int chipcfg = readl(ioaddr + ChipConfig);
 
-	if (np->duplex_lock)
+	if(!(chipcfg & 0x80000000)) {
+		if (netif_carrier_ok(dev)) {
+			if (debug)
+				printk(KERN_INFO "%s: no link. Disabling watchdog.\n",
+					dev->name);
+			netif_carrier_off(dev);
+		}
 		return;
-	duplex = readl(ioaddr + ChipConfig) & 0x20000000 ? 1 : 0;
-	if (np->full_duplex != duplex) {
-		np->full_duplex = duplex;
+	}
+	if (!netif_carrier_ok(dev)) {
+		if (debug)
+			printk(KERN_INFO "%s: link is back. Enabling watchdog.\n",
+					dev->name);
+		netif_carrier_on(dev);
+	}
+
+	duplex = np->full_duplex || (chipcfg & 0x20000000 ? 1 : 0);
+
+	/* if duplex is set then bit 28 must be set, too */
+	if (duplex ^ !!(np->rx_config & 0x10000000)) {
 		if (debug)
 			printk(KERN_INFO "%s: Setting %s-duplex based on negotiated link"
 				   " capability.\n", dev->name,
@@ -723,17 +723,104 @@
 	}
 }
 
+static void init_registers(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+	int i;
+
+	if (debug > 4)
+		printk(KERN_DEBUG "%s: found silicon revision %xh.\n",
+				dev->name, readl(ioaddr + SiliconRev));
+	/* On page 78 of the spec, they recommend some settings for "optimum
+	   performance" to be done in sequence.  These settings optimize some
+	   of the 100Mbit autodetection circuitry.  Also, we only want to do
+	   this for rev C of the chip.
+
+	   There seems to be a typo on page 78: the fixup should be performed
+	   for "DP83815CVNG (SRR = 203h)", but the description of the
+	   SiliconRev regsiters says "DP83815CVNG: 00000302h"
+	*/
+	if (readl(ioaddr + SiliconRev) == 0x302) {
+		writew(0x0001, ioaddr + PGSEL);
+		writew(0x189C, ioaddr + PMDCSR);
+		writew(0x0000, ioaddr + TSTDAT);
+		writew(0x5040, ioaddr + DSPCFG);
+		writew(0x008C, ioaddr + SDCFG);
+	}
+
+	/* Enable PHY Specific event based interrupts.  Link state change
+	   and Auto-Negotiation Completion are among the affected.
+	*/
+	writew(0x0002, ioaddr + MIntrCtrl);
+
+	writel(np->ring_dma, ioaddr + RxRingPtr);
+	writel(np->ring_dma + RX_RING_SIZE * sizeof(struct netdev_desc), ioaddr + TxRingPtr);
+
+	for (i = 0; i < ETH_ALEN; i += 2) {
+		writel(i, ioaddr + RxFilterAddr);
+		writew(dev->dev_addr[i] + (dev->dev_addr[i+1] << 8),
+			   ioaddr + RxFilterData);
+	}
+
+	/* Initialize other registers.
+	 * Configure the PCI bus bursts and FIFO thresholds.
+	 * Configure for standard, in-spec Ethernet.
+	 * Start with half-duplex. check_link will update
+	 * to the correct settings. 
+	 */
+
+	/* DRTH: 2: start tx if 64 bytes are in the fifo
+	 * FLTH: 0x10: refill with next packet if 512 bytes are free
+	 * MXDMA: 0: up to 512 byte bursts.
+	 * 	MXDMA must be <= FLTH
+	 * ECRETRY=1
+	 * ATP=1
+	 */
+	np->tx_config = 0x10801002;
+	/* DRTH 0x10: start copying to memory if 128 bytes are in the fifo
+	 * MXDMA 0: up to 512 byte bursts
+	 */
+	np->rx_config = 0x0020;
+	writel(np->tx_config, ioaddr + TxConfig);
+	writel(np->rx_config, ioaddr + RxConfig);
+
+	/* Disable PME:
+	 * The PME bit is initialized from the EEPROM contents.
+	 * PCI cards probably have PME disabled, but motherboard
+	 * implementations may have PME set to enable WakeOnLan. 
+	 * With PME set the chip will scan incoming packets but
+	 * nothing will be written to memory. */
+	np->SavedClkRun = readl(ioaddr + ClkRun);
+	writel(np->SavedClkRun & ~0x100, ioaddr + ClkRun);
+
+	check_link(dev);
+	__set_rx_mode(dev);
+
+	/* Enable interrupts by setting the interrupt mask. */
+	writel(IntrNormalSummary | IntrAbnormalSummary | 0x1f, ioaddr + IntrMask);
+	writel(1, ioaddr + IntrEnable);
+
+	writel(RxOn | TxOn, ioaddr + ChipCmd);
+	writel(4, ioaddr + StatsCtrl); 					/* Clear Stats */
+}
+
 static void netdev_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
 	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
 	int next_tick = 60*HZ;
 
-	if (debug > 3)
-		printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n",
-			   dev->name, (int)readl(ioaddr + IntrStatus));
-	check_duplex(dev);
+	if (debug > 3) {
+		/* DO NOT read the IntrStatus register, 
+		 * a read clears any pending interrupts.
+		 */
+		printk(KERN_DEBUG "%s: Media selection timer tick.\n",
+			   dev->name);
+	}
+	spin_lock_irq(&np->lock);
+	check_link(dev);
+	spin_unlock_irq(&np->lock);
 	np->timer.expires = jiffies + next_tick;
 	add_timer(&np->timer);
 }
@@ -758,18 +845,29 @@
 		printk("\n");
 	}
 #endif
-
-	/* Perhaps we should reinitialize the hardware here. */
-	dev->if_port = 0;
-	/* Stop and restart the chip's Tx processes . */
-
-	/* Trigger an immediate transmit demand. */
+	spin_lock_irq(&np->lock);
+	natsemi_reset(dev);
+	drain_ring(dev);
+	init_ring(dev);
+	init_registers(dev);
+	spin_unlock_irq(&np->lock);
 
 	dev->trans_start = jiffies;
 	np->stats.tx_errors++;
 	netif_wake_queue(dev);
 }
 
+static int alloc_ring(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	np->rx_ring = pci_alloc_consistent(np->pci_dev,
+				sizeof(struct netdev_desc) * (RX_RING_SIZE+TX_RING_SIZE),
+				&np->ring_dma);
+	if (!np->rx_ring)
+		return -ENOMEM;
+	np->tx_ring = &np->rx_ring[RX_RING_SIZE];
+	return 0;
+}
 
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void init_ring(struct net_device *dev)
@@ -785,12 +883,12 @@
 
 	/* Initialize all Rx descriptors. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]);
-		np->rx_ring[i].cmd_status = DescOwn;
-		np->rx_skbuff[i] = 0;
+		np->rx_ring[i].next_desc = cpu_to_le32(np->ring_dma+sizeof(struct netdev_desc)*(i+1));
+		np->rx_ring[i].cmd_status = cpu_to_le32(DescOwn);
+		np->rx_skbuff[i] = NULL;
 	}
 	/* Mark the last entry as wrapping the ring. */
-	np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]);
+	np->rx_ring[i-1].next_desc = cpu_to_le32(np->ring_dma);
 
 	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
@@ -799,19 +897,59 @@
 		if (skb == NULL)
 			break;
 		skb->dev = dev;			/* Mark as being used by this device. */
-		np->rx_ring[i].addr = virt_to_le32desc(skb->tail);
-		np->rx_ring[i].cmd_status =
-			cpu_to_le32(DescIntr | np->rx_buf_sz);
+		np->rx_dma[i] = pci_map_single(np->pci_dev,
+						skb->data, skb->len, PCI_DMA_FROMDEVICE);
+		np->rx_ring[i].addr = cpu_to_le32(np->rx_dma[i]);
+		np->rx_ring[i].cmd_status = cpu_to_le32(DescIntr | np->rx_buf_sz);
 	}
 	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 
 	for (i = 0; i < TX_RING_SIZE; i++) {
-		np->tx_skbuff[i] = 0;
-		np->tx_ring[i].next_desc = virt_to_le32desc(&np->tx_ring[i+1]);
+		np->tx_skbuff[i] = NULL;
+		np->tx_ring[i].next_desc = cpu_to_le32(np->ring_dma
+					+sizeof(struct netdev_desc)*(i+1+RX_RING_SIZE));
 		np->tx_ring[i].cmd_status = 0;
 	}
-	np->tx_ring[i-1].next_desc = virt_to_le32desc(&np->tx_ring[0]);
-	return;
+	np->tx_ring[i-1].next_desc = cpu_to_le32(np->ring_dma
+					+sizeof(struct netdev_desc)*(RX_RING_SIZE));
+}
+
+static void drain_ring(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	int i;
+
+	/* Free all the skbuffs in the Rx queue. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		np->rx_ring[i].cmd_status = 0;
+		np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
+		if (np->rx_skbuff[i]) {
+			pci_unmap_single(np->pci_dev,
+						np->rx_dma[i],
+						np->rx_skbuff[i]->len,
+						PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(np->rx_skbuff[i]);
+		}
+		np->rx_skbuff[i] = NULL;
+	}
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (np->tx_skbuff[i]) {
+			pci_unmap_single(np->pci_dev,
+						np->rx_dma[i],
+						np->rx_skbuff[i]->len,
+						PCI_DMA_TODEVICE);
+			dev_kfree_skb(np->tx_skbuff[i]);
+		}
+		np->tx_skbuff[i] = NULL;
+	}
+}
+
+static void free_ring(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	pci_free_consistent(np->pci_dev,
+				sizeof(struct netdev_desc) * (RX_RING_SIZE+TX_RING_SIZE),
+				np->rx_ring, np->ring_dma);
 }
 
 static int start_tx(struct sk_buff *skb, struct net_device *dev)
@@ -826,17 +964,26 @@
 	entry = np->cur_tx % TX_RING_SIZE;
 
 	np->tx_skbuff[entry] = skb;
+	np->tx_dma[entry] = pci_map_single(np->pci_dev,
+				skb->data,skb->len, PCI_DMA_TODEVICE);
 
-	np->tx_ring[entry].addr = virt_to_le32desc(skb->data);
-	np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn|DescIntr | skb->len);
-	np->cur_tx++;
+	np->tx_ring[entry].addr = cpu_to_le32(np->tx_dma[entry]);
+
+	spin_lock_irq(&np->lock);
 
+#if 0
+	np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | DescIntr | skb->len);
+#else
+	np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len);
+#endif
 	/* StrongARM: Explicitly cache flush np->tx_ring and skb->data,skb->len. */
 	wmb();
-
-	spin_lock_irq(&np->lock);
-	if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1)
-		netif_stop_queue(dev);
+	np->cur_tx++;
+	if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) {
+		netdev_tx_done(dev);
+		if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1)
+			netif_stop_queue(dev);
+	}
 	spin_unlock_irq(&np->lock);
 
 	/* Wake the potentially-idle transmit channel. */
@@ -851,6 +998,48 @@
 	return 0;
 }
 
+static void netdev_tx_done(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+
+	for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
+		int entry = np->dirty_tx % TX_RING_SIZE;
+		if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn)) {
+			if (debug > 4)
+				printk(KERN_DEBUG "%s: tx frame #%d is busy.\n",
+						dev->name, np->dirty_tx);
+			break;
+		}
+		if (debug > 4)
+			printk(KERN_DEBUG "%s: tx frame #%d finished with status %8.8xh.\n",
+					dev->name, np->dirty_tx,
+					le32_to_cpu(np->tx_ring[entry].cmd_status));
+		if (np->tx_ring[entry].cmd_status & cpu_to_le32(0x08000000)) {
+			np->stats.tx_packets++;
+			np->stats.tx_bytes += np->tx_skbuff[entry]->len;
+		} else {			/* Various Tx errors */
+			int tx_status = le32_to_cpu(np->tx_ring[entry].cmd_status);
+			if (tx_status & 0x04010000) np->stats.tx_aborted_errors++;
+			if (tx_status & 0x02000000) np->stats.tx_fifo_errors++;
+			if (tx_status & 0x01000000) np->stats.tx_carrier_errors++;
+			if (tx_status & 0x00200000) np->stats.tx_window_errors++;
+			np->stats.tx_errors++;
+		}
+		pci_unmap_single(np->pci_dev,np->tx_dma[entry],
+					np->tx_skbuff[entry]->len,
+					PCI_DMA_TODEVICE);
+		/* Free the original skb. */
+		dev_kfree_skb_irq(np->tx_skbuff[entry]);
+		np->tx_skbuff[entry] = NULL;
+	}
+	if (netif_queue_stopped(dev)
+		&& np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
+		/* The ring is no longer full, wake queue. */
+		netif_wake_queue(dev);
+	}
+	spin_unlock(&np->lock);
+
+}
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
@@ -864,11 +1053,9 @@
 	np = dev->priv;
 
 	do {
+		/* Reading automatically acknowledges all int sources. */
 		u32 intr_status = readl(ioaddr + IntrStatus);
 
-		/* Acknowledge all of the current interrupt sources ASAP. */
-		writel(intr_status & 0x000ffff, ioaddr + IntrStatus);
-
 		if (debug > 4)
 			printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
 				   dev->name, intr_status);
@@ -879,35 +1066,12 @@
 		if (intr_status & (IntrRxDone | IntrRxIntr))
 			netdev_rx(dev);
 
-		spin_lock(&np->lock);
-
-		for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
-			int entry = np->dirty_tx % TX_RING_SIZE;
-			if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn))
-				break;
-			if (np->tx_ring[entry].cmd_status & cpu_to_le32(0x08000000)) {
-				np->stats.tx_packets++;
-				np->stats.tx_bytes += np->tx_skbuff[entry]->len;
-			} else {			/* Various Tx errors */
-				int tx_status = le32_to_cpu(np->tx_ring[entry].cmd_status);
-				if (tx_status & 0x04010000) np->stats.tx_aborted_errors++;
-				if (tx_status & 0x02000000) np->stats.tx_fifo_errors++;
-				if (tx_status & 0x01000000) np->stats.tx_carrier_errors++;
-				if (tx_status & 0x00200000) np->stats.tx_window_errors++;
-				np->stats.tx_errors++;
-			}
-			/* Free the original skb. */
-			dev_kfree_skb_irq(np->tx_skbuff[entry]);
-			np->tx_skbuff[entry] = 0;
-		}
-		if (netif_queue_stopped(dev)
-			&& np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
-			/* The ring is no longer full, wake queue. */
-			netif_wake_queue(dev);
+		if (intr_status & (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr) ) {
+			spin_lock(&np->lock);
+			netdev_tx_done(dev);
+			spin_unlock(&np->lock);
 		}
 
-		spin_unlock(&np->lock);
-
 		/* Abnormal error summary/uncommon events handlers. */
 		if (intr_status & IntrAbnormalSummary)
 			netdev_error(dev, intr_status);
@@ -921,13 +1085,13 @@
 	} while (1);
 
 	if (debug > 3)
-		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-			   dev->name, (int)readl(ioaddr + IntrStatus));
+		printk(KERN_DEBUG "%s: exiting interrupt.\n",
+			   dev->name);
 }
 
 /* This routine is logically part of the interrupt handler, but separated
    for clarity and better register allocation. */
-static int netdev_rx(struct net_device *dev)
+static void netdev_rx(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
 	int entry = np->cur_rx % RX_RING_SIZE;
@@ -967,6 +1131,9 @@
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
+				pci_dma_sync_single(np->pci_dev, np->rx_dma[entry],
+							np->rx_skbuff[entry]->len,
+							PCI_DMA_FROMDEVICE);
 #if HAS_IP_COPYSUM
 				eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
@@ -975,16 +1142,11 @@
 					   pkt_len);
 #endif
 			} else {
-				char *temp = skb_put(skb = np->rx_skbuff[entry], pkt_len);
+				pci_unmap_single(np->pci_dev, np->rx_dma[entry],
+							np->rx_skbuff[entry]->len,
+							PCI_DMA_FROMDEVICE);
+				skb_put(skb = np->rx_skbuff[entry], pkt_len);
 				np->rx_skbuff[entry] = NULL;
-#ifndef final_version				/* Remove after testing. */
-				if (le32desc_to_virt(np->rx_ring[entry].addr) != temp)
-					printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
-						   "do not match in netdev_rx: %p vs. %p / %p.\n",
-						   dev->name,
-						   le32desc_to_virt(np->rx_ring[entry].addr),
-						   skb->head, temp);
-#endif
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			/* W/ hardware checksum: skb->ip_summed = CHECKSUM_UNNECESSARY; */
@@ -1008,7 +1170,9 @@
 			if (skb == NULL)
 				break;				/* Better luck next round. */
 			skb->dev = dev;			/* Mark as being used by this device. */
-			np->rx_ring[entry].addr = virt_to_le32desc(skb->tail);
+			np->rx_dma[entry] = pci_map_single(np->pci_dev,
+							skb->data, skb->len, PCI_DMA_FROMDEVICE);
+			np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]);
 		}
 		np->rx_ring[entry].cmd_status =
 			cpu_to_le32(DescIntr | np->rx_buf_sz);
@@ -1016,7 +1180,6 @@
 
 	/* Restart Rx engine if stopped. */
 	writel(RxOn, dev->base_addr + ChipCmd);
-	return 0;
 }
 
 static void netdev_error(struct net_device *dev, int intr_status)
@@ -1024,20 +1187,24 @@
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 
+	spin_lock(&np->lock);
 	if (intr_status & LinkChange) {
 		printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising"
 			   " %4.4x  partner %4.4x.\n", dev->name,
 			   (int)readl(ioaddr + 0x90), (int)readl(ioaddr + 0x94));
 		/* read MII int status to clear the flag */
 		readw(ioaddr + MIntrStatus);
-		check_duplex(dev);
+		check_link(dev);
 	}
 	if (intr_status & StatsMax) {
-		get_stats(dev);
+		__get_stats(dev);
 	}
 	if (intr_status & IntrTxUnderrun) {
 		if ((np->tx_config & 0x3f) < 62)
 			np->tx_config += 2;
+		if (debug > 2)
+			printk(KERN_NOTICE "%s: increasing Tx theshold, new tx cfg %8.8xh.\n",
+					dev->name, np->tx_config);
 		writel(np->tx_config, ioaddr + TxConfig);
 	}
 	if (intr_status & WOLPkt) {
@@ -1054,23 +1221,30 @@
 		np->stats.tx_fifo_errors++;
 		np->stats.rx_fifo_errors++;
 	}
+	spin_unlock(&np->lock);
 }
 
-static struct net_device_stats *get_stats(struct net_device *dev)
+static void __get_stats(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
 	struct netdev_private *np = dev->priv;
 
-	/* We should lock this segment of code for SMP eventually, although
-	   the vulnerability window is very small and statistics are
-	   non-critical. */
 	/* The chip only need report frame silently dropped. */
 	np->stats.rx_crc_errors	+= readl(ioaddr + RxCRCErrs);
 	np->stats.rx_missed_errors	+= readl(ioaddr + RxMissed);
+}
+
+static struct net_device_stats *get_stats(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+
+	/* The chip only need report frame silently dropped. */
+	spin_lock_irq(&np->lock);
+	__get_stats(dev);
+	spin_unlock_irq(&np->lock);
 
 	return &np->stats;
 }
-
 /* The little-endian AUTODIN II ethernet CRC calculations.
    A big-endian version is also available.
    This is slow but compact code.  Do not use this routine for bulk data,
@@ -1079,6 +1253,7 @@
    Chips may use the upper or lower CRC bits, and may reverse and/or invert
    them.  Select the endian-ness that results in minimal calculations.
 */
+#if 0
 static unsigned const ethernet_polynomial_le = 0xedb88320U;
 static inline unsigned ether_crc_le(int length, unsigned char *data)
 {
@@ -1096,8 +1271,41 @@
 	}
 	return crc;
 }
+#else
+#define DP_POLYNOMIAL			0x04C11DB7
+/* dp83815_crc - computer CRC for hash table entries */
+static unsigned ether_crc_le(int length, unsigned char *data)
+{
+    u32 crc;
+    u8 cur_byte;
+    u8 msb;
+    u8 byte, bit;
+
+    crc = ~0;
+    for (byte=0; byte<length; byte++) {
+        cur_byte = *data++;
+        for (bit=0; bit<8; bit++) {
+            msb = crc >> 31;
+            crc <<= 1;
+            if (msb ^ (cur_byte & 1)) {
+                crc ^= DP_POLYNOMIAL;
+                crc |= 1;
+            }
+            cur_byte >>= 1;
+        }
+    }
+    crc >>= 23;
 
-static void set_rx_mode(struct net_device *dev)
+    return (crc);
+}
+#endif
+
+void set_bit_le(int offset, unsigned char * data)
+{
+	data[offset >> 3] |= (1 << (offset & 0x07));
+}
+#define HASH_TABLE	0x200
+static void __set_rx_mode(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
 	struct netdev_private *np = dev->priv;
@@ -1118,17 +1326,25 @@
 		memset(mc_filter, 0, sizeof(mc_filter));
 		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
 			 i++, mclist = mclist->next) {
-			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
+			set_bit_le(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
 					mc_filter);
 		}
 		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
 		for (i = 0; i < 64; i += 2) {
-			writew(0x200 + i, ioaddr + RxFilterAddr);
+			writew(HASH_TABLE + i, ioaddr + RxFilterAddr);
 			writew((mc_filter[i+1]<<8) + mc_filter[i], ioaddr + RxFilterData);
 		}
 	}
 	writel(rx_mode, ioaddr + RxFilterAddr);
 	np->cur_rx_mode = rx_mode;
+	spin_unlock_irq(&np->lock);
+}
+static void set_rx_mode(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	spin_lock_irq(&np->lock);
+	__set_rx_mode(dev);
+	spin_unlock_irq(&np->lock);
 }
 
 static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
@@ -1177,12 +1393,6 @@
 			u16 value = data[2];
 			writew(value, dev->base_addr + 0x80 + (miireg << 2));
 			switch (miireg) {
-			case 0:
-				/* Check for autonegotiation on or reset. */
-				np->duplex_lock = (value & 0x9000) ? 0 : 1;
-				if (np->duplex_lock)
-					np->full_duplex = (value & 0x0100) ? 1 : 0;
-				break;
 			case 4: np->advertising = value; break;
 			}
 		}
@@ -1196,15 +1406,12 @@
 {
 	long ioaddr = dev->base_addr;
 	struct netdev_private *np = dev->priv;
-	int i;
 
 	netif_stop_queue(dev);
 
 	if (debug > 1) {
-		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x "
-			   "Int %2.2x.\n",
-			   dev->name, (int)readl(ioaddr + ChipCmd),
-			   (int)readl(ioaddr + IntrStatus));
+		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.",
+			   dev->name, (int)readl(ioaddr + ChipCmd));
 		printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
 			   dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
 	}
@@ -1221,13 +1428,14 @@
 
 #ifdef __i386__
 	if (debug > 2) {
+		int i;
 		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
-			   (int)virt_to_bus(np->tx_ring));
+			   (int)np->tx_ring);
 		for (i = 0; i < TX_RING_SIZE; i++)
 			printk(" #%d desc. %8.8x %8.8x.\n",
 				   i, np->tx_ring[i].cmd_status, np->tx_ring[i].addr);
 		printk("\n"KERN_DEBUG "  Rx ring %8.8x:\n",
-			   (int)virt_to_bus(np->rx_ring));
+			   (int)np->rx_ring);
 		for (i = 0; i < RX_RING_SIZE; i++) {
 			printk(KERN_DEBUG " #%d desc. %8.8x %8.8x\n",
 				   i, np->rx_ring[i].cmd_status, np->rx_ring[i].addr);
@@ -1236,21 +1444,9 @@
 #endif /* __i386__ debugging only */
 
 	free_irq(dev->irq, dev);
+	drain_ring(dev);
+	free_ring(dev);
 
-	/* Free all the skbuffs in the Rx queue. */
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		np->rx_ring[i].cmd_status = 0;
-		np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
-		if (np->rx_skbuff[i]) {
-			dev_kfree_skb(np->rx_skbuff[i]);
-		}
-		np->rx_skbuff[i] = 0;
-	}
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		if (np->tx_skbuff[i])
-			dev_kfree_skb(np->tx_skbuff[i]);
-		np->tx_skbuff[i] = 0;
-	}
 	/* Restore PME enable bit */
 	writel(np->SavedClkRun, ioaddr + ClkRun);
 #if 0
@@ -1272,11 +1468,86 @@
 	pci_set_drvdata(pdev, NULL);
 }
 
+#ifdef CONFIG_PM
+
+static int natsemi_suspend (struct pci_dev *pdev, u32 state)
+{
+	struct net_device *dev = pci_get_drvdata (pdev);
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+
+	netif_device_detach(dev);
+	/* no more calls to tx_timeout, hard_start_xmit, set_rx_mode */
+	rtnl_lock();
+	rtnl_unlock();
+	/* noone within ->open */
+	if (netif_running (dev)) {
+		int i;
+		del_timer_sync(&np->timer);
+		/* no more link beat timer calls */
+		spin_lock_irq(&np->lock);
+		writel(RxOff | TxOff, ioaddr + ChipCmd);
+		for(i=0;i< NATSEMI_HW_TIMEOUT;i++) {
+			if ((readl(ioaddr + ChipCmd) & (TxOn|RxOn)) == 0)
+				break;
+			udelay(5);
+		}
+		if (i==NATSEMI_HW_TIMEOUT && debug) {
+			printk(KERN_INFO "%s: Tx/Rx process did not stop in %d usec.\n",
+					dev->name, i*5);
+		} else if (debug > 2) {
+			printk(KERN_DEBUG "%s: Tx/Rx process stopped in %d usec.\n",
+					dev->name, i*5);
+		}
+		/* Tx and Rx processes stopped */
+
+		writel(0, ioaddr + IntrEnable);
+		/* all irq events disabled. */
+		spin_unlock_irq(&np->lock);
+
+		synchronize_irq();
+
+		/* Update the error counts. */
+		__get_stats(dev);
+
+		/* pci_power_off(pdev, -1); */
+		drain_ring(dev);
+	}
+	return 0;
+}
+
+
+static int natsemi_resume (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata (pdev);
+	struct netdev_private *np = dev->priv;
+
+	if (netif_running (dev)) {
+		pci_enable_device(pdev);
+	/*	pci_power_on(pdev); */
+		
+		natsemi_reset(dev);
+		init_ring(dev);
+		init_registers(dev);
+
+		np->timer.expires = jiffies + 1*HZ;
+		add_timer(&np->timer);
+	}
+	netif_device_attach(dev);
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
 static struct pci_driver natsemi_driver = {
 	name:		DRV_NAME,
 	id_table:	natsemi_pci_tbl,
 	probe:		natsemi_probe1,
 	remove:		natsemi_remove1,
+#ifdef CONFIG_PM
+	suspend:	natsemi_suspend,
+	resume:		natsemi_resume,
+#endif
 };
 
 static int __init natsemi_init_mod (void)
diff -u --recursive --new-file v2.4.5/linux/drivers/net/ne.c linux/drivers/net/ne.c
--- v2.4.5/linux/drivers/net/ne.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/ne.c	Wed Jun 20 11:10:53 2001
@@ -735,6 +735,9 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
 MODULE_PARM(bad, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
+MODULE_PARM_DESC(io, "NEx000 I/O base address(es),required");
+MODULE_PARM_DESC(irq, "NEx000 IRQ number(s)");
+MODULE_PARM_DESC(bad, "NEx000 accept bad clone(s)");
 
 /* This is set up so that no ISA autoprobe takes place. We can't guarantee
 that the ne2k probe is the last 8390 based probe to take place (as it
diff -u --recursive --new-file v2.4.5/linux/drivers/net/ne2.c linux/drivers/net/ne2.c
--- v2.4.5/linux/drivers/net/ne2.c	Fri Feb  9 11:40:02 2001
+++ linux/drivers/net/ne2.c	Wed Jun 20 11:10:53 2001
@@ -749,6 +749,9 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
 MODULE_PARM(bad, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
+MODULE_PARM_DESC(io, "(ignored)");
+MODULE_PARM_DESC(irq, "(ignored)");
+MODULE_PARM_DESC(bad, "(ignored)");
 #endif
 
 /* Module code fixed by David Weinehall */
diff -u --recursive --new-file v2.4.5/linux/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c
--- v2.4.5/linux/drivers/net/ne2k-pci.c	Fri Apr 20 11:54:23 2001
+++ linux/drivers/net/ne2k-pci.c	Wed Jun 20 11:13:18 2001
@@ -25,6 +25,11 @@
 	Limited full-duplex support.
 */
 
+#define DRV_NAME	"ne2k-pci"
+#define DRV_VERSION	"1.02"
+#define DRV_RELDATE	"10/19/2000"
+
+
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
@@ -45,10 +50,12 @@
 #include <linux/errno.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/ethtool.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/uaccess.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -56,7 +63,7 @@
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
-KERN_INFO "ne2k-pci.c:v1.02 10/19/2000 D. Becker/P. Gortmaker\n"
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " D. Becker/P. Gortmaker\n"
 KERN_INFO "  http://www.scyld.com/network/ne2k-pci.html\n";
 
 #if defined(__powerpc__)
@@ -66,11 +73,16 @@
 #define outsl outsl_ns
 #endif
 
+#define PFX DRV_NAME ": "
+
 MODULE_AUTHOR("Donald Becker / Paul Gortmaker");
 MODULE_DESCRIPTION("PCI NE2000 clone driver");
 MODULE_PARM(debug, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM_DESC(debug, "PCI NE2000 debug level (1-2)");
+MODULE_PARM_DESC(options, "PCI NE2000: Bit 5: full duplex");
+MODULE_PARM_DESC(full_duplex, "PCI NE2000 full duplex setting(s) (1)");
 
 /* Some defines that people can play with if so inclined. */
 
@@ -160,6 +172,7 @@
 			  struct sk_buff *skb, int ring_offset);
 static void ne2k_pci_block_output(struct net_device *dev, const int count,
 		const unsigned char *buf, const int start_page);
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 
 
 
@@ -215,12 +228,12 @@
 	irq = pdev->irq;
 
 	if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) {
-		printk (KERN_ERR "ne2k-pci: no I/O resource at PCI BAR #0\n");
+		printk (KERN_ERR PFX "no I/O resource at PCI BAR #0\n");
 		return -ENODEV;
 	}
 
-	if (request_region (ioaddr, NE_IO_EXTENT, "ne2k-pci") == NULL) {
-		printk (KERN_ERR "ne2k-pci: I/O resource 0x%x @ 0x%lx busy\n",
+	if (request_region (ioaddr, NE_IO_EXTENT, DRV_NAME) == NULL) {
+		printk (KERN_ERR PFX "I/O resource 0x%x @ 0x%lx busy\n",
 			NE_IO_EXTENT, ioaddr);
 		return -EBUSY;
 	}
@@ -246,7 +259,7 @@
 
 	dev = alloc_etherdev(0);
 	if (!dev) {
-		printk (KERN_ERR "ne2k-pci: cannot allocate ethernet device\n");
+		printk (KERN_ERR PFX "cannot allocate ethernet device\n");
 		goto err_out_free_res;
 	}
 	SET_MODULE_OWNER(dev);
@@ -263,7 +276,7 @@
 		while ((inb(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
 			/* Limit wait: '2' avoids jiffy roll-over. */
 			if (jiffies - reset_start_time > 2) {
-				printk("ne2k-pci: Card failure (no reset ack).\n");
+				printk(KERN_ERR PFX "Card failure (no reset ack).\n");
 				goto err_out_free_netdev;
 			}
 
@@ -342,8 +355,10 @@
 	ei_status.block_input = &ne2k_pci_block_input;
 	ei_status.block_output = &ne2k_pci_block_output;
 	ei_status.get_8390_hdr = &ne2k_pci_get_8390_hdr;
+	ei_status.priv = (unsigned long) pdev;
 	dev->open = &ne2k_pci_open;
 	dev->stop = &ne2k_pci_close;
+	dev->do_ioctl = &netdev_ioctl;
 	NS8390_init(dev, 0);
 
 	i = register_netdev(dev);
@@ -573,6 +588,40 @@
 	return;
 }
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct ei_device *ei = dev->priv;
+	struct pci_dev *pci_dev = (struct pci_dev *) ei->priv;
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+
+        switch (ethcmd) {
+        case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strcpy(info.driver, DRV_NAME);
+		strcpy(info.version, DRV_VERSION);
+		strcpy(info.bus_info, pci_dev->slot_name);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+
+        }
+	
+	return -EOPNOTSUPP;
+}
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	switch(cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
 
 static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev)
 {
@@ -589,7 +638,7 @@
 
 
 static struct pci_driver ne2k_driver = {
-	name:		"ne2k-pci",
+	name:		DRV_NAME,
 	probe:		ne2k_pci_init_one,
 	remove:		ne2k_pci_remove_one,
 	id_table:	ne2k_pci_tbl,
diff -u --recursive --new-file v2.4.5/linux/drivers/net/ne3210.c linux/drivers/net/ne3210.c
--- v2.4.5/linux/drivers/net/ne3210.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/ne3210.c	Wed Jun 20 11:10:53 2001
@@ -370,6 +370,9 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i");
+MODULE_PARM_DESC(io, "NE3210 I/O base address(es)");
+MODULE_PARM_DESC(irq, "NE3210 IRQ number(s)");
+MODULE_PARM_DESC(mem, "NE3210 memory base address(es)");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/ni5010.c linux/drivers/net/ni5010.c
--- v2.4.5/linux/drivers/net/ni5010.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/ni5010.c	Wed Jun 20 11:10:53 2001
@@ -739,6 +739,8 @@
 
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
+MODULE_PARM_DESC(io, "ni5010 I/O base address");
+MODULE_PARM_DESC(irq, "ni5010 IRQ number");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/ni52.c linux/drivers/net/ni52.c
--- v2.4.5/linux/drivers/net/ni52.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/ni52.c	Wed Jun 20 11:10:53 2001
@@ -1296,6 +1296,10 @@
 MODULE_PARM(irq, "i");
 MODULE_PARM(memstart, "l");
 MODULE_PARM(memend, "l");
+MODULE_PARM_DESC(io, "NI5210 I/O base address,required");
+MODULE_PARM_DESC(irq, "NI5210 IRQ number,required");
+MODULE_PARM_DESC(memstart, "NI5210 memory base address,required");
+MODULE_PARM_DESC(memend, "NI5210 memory end address,required");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/ni65.c linux/drivers/net/ni65.c
--- v2.4.5/linux/drivers/net/ni65.c	Wed Apr 18 14:40:04 2001
+++ linux/drivers/net/ni65.c	Wed Jun 20 11:10:53 2001
@@ -1184,6 +1184,9 @@
 MODULE_PARM(irq, "i");
 MODULE_PARM(io, "i");
 MODULE_PARM(dma, "i");
+MODULE_PARM_DESC(irq, "ni6510 IRQ number (ignored for some cards)");
+MODULE_PARM_DESC(io, "ni6510 I/O base address");
+MODULE_PARM_DESC(dma, "ni6510 ISA DMA channel (ignored for some cards)");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/pci-skeleton.c linux/drivers/net/pci-skeleton.c
--- v2.4.5/linux/drivers/net/pci-skeleton.c	Fri Apr 20 11:54:23 2001
+++ linux/drivers/net/pci-skeleton.c	Wed Jun 20 11:13:18 2001
@@ -85,6 +85,7 @@
 
 */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
@@ -480,11 +481,15 @@
 };
 
 MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
-MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver");
+MODULE_DESCRIPTION ("Skeleton for a PCI Fast Ethernet driver");
 MODULE_PARM (multicast_filter_limit, "i");
 MODULE_PARM (max_interrupt_work, "i");
 MODULE_PARM (debug, "i");
 MODULE_PARM (media, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM_DESC (multicast_filter_limit, "pci-skeleton maximum number of filtered multicast addresses");
+MODULE_PARM_DESC (max_interrupt_work, "pci-skeleton maximum events handled per interrupt");
+MODULE_PARM_DESC (media, "pci-skeleton: Bits 0-3: media type, bit 17: full duplex");
+MODULE_PARM_DESC (debug, "(unused)");
 
 static int read_eeprom (void *ioaddr, int location, int addr_len);
 static int netdrv_open (struct net_device *dev);
@@ -1790,7 +1795,7 @@
 
 	case SIOCDEVPRIVATE + 1:	/* Read the specified MII register. */
 		spin_lock_irqsave (&tp->lock, flags);
-		data[3] = mdio_read (dev, data[0], data[1] & 0x1f);
+		data[3] = mdio_read (dev, data[0] & 0x1f, data[1] & 0x1f);
 		spin_unlock_irqrestore (&tp->lock, flags);
 		break;
 
@@ -1801,7 +1806,7 @@
 		}
 
 		spin_lock_irqsave (&tp->lock, flags);
-		mdio_write (dev, data[0], data[1] & 0x1f, data[2]);
+		mdio_write (dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
 		spin_unlock_irqrestore (&tp->lock, flags);
 		break;
 
@@ -1918,7 +1923,9 @@
 }
 
 
-static void netdrv_suspend (struct pci_dev *pdev)
+#ifdef CONFIG_PM
+
+static int netdrv_suspend (struct pci_dev *pdev, u32 state)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
 	struct netdrv_private *tp = dev->priv;
@@ -1942,10 +1949,12 @@
 	spin_unlock_irqrestore (&tp->lock, flags);
 
 	pci_power_off (pdev, -1);
+
+	return 0;
 }
 
 
-static void netdrv_resume (struct pci_dev *pdev)
+static int netdrv_resume (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
 
@@ -1954,16 +1963,22 @@
 	pci_power_on (pdev);
 	netif_device_attach (dev);
 	netdrv_hw_start (dev);
+
+	return 0;
 }
 
+#endif /* CONFIG_PM */
+
 
 static struct pci_driver netdrv_pci_driver = {
 	name:		MODNAME,
 	id_table:	netdrv_pci_tbl,
 	probe:		netdrv_init_one,
 	remove:		netdrv_remove_one,
+#ifdef CONFIG_PM
 	suspend:	netdrv_suspend,
 	resume:		netdrv_resume,
+#endif /* CONFIG_PM */
 };
 
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in
--- v2.4.5/linux/drivers/net/pcmcia/Config.in	Mon May  7 19:42:14 2001
+++ linux/drivers/net/pcmcia/Config.in	Wed Jun 20 11:13:18 2001
@@ -32,13 +32,4 @@
    fi
 fi
 
-if [ "$CONFIG_PCMCIA_3C589" = "y" -o "$CONFIG_PCMCIA_3C574" = "y" -o \
-     "$CONFIG_PCMCIA_FMVJ18X" = "y" -o "$CONFIG_PCMCIA_PCNET" = "y" -o \
-     "$CONFIG_PCMCIA_NMCLAN" = "y" -o "$CONFIG_PCMCIA_SMC91C92" = "y" -o \
-     "$CONFIG_PCMCIA_XIRC2PS" = "y" -o "$CONFIG_PCMCIA_RAYCS" = "y" -o \
-     "$CONFIG_PCMCIA_NETWAVE" = "y" -o "$CONFIG_PCMCIA_WAVELAN" = "y" -o \
-     "$CONFIG_PCMCIA_XIRTULIP" = "y" ]; then
-   define_bool CONFIG_PCMCIA_NETCARD y
-fi
-
 endmenu
diff -u --recursive --new-file v2.4.5/linux/drivers/net/pcmcia/Makefile linux/drivers/net/pcmcia/Makefile
--- v2.4.5/linux/drivers/net/pcmcia/Makefile	Mon May  7 19:42:14 2001
+++ linux/drivers/net/pcmcia/Makefile	Wed Jun 20 11:13:18 2001
@@ -36,10 +36,3 @@
 obj-$(CONFIG_PCMCIA_IBMTR)	+= ibmtr_cs.o
 
 include $(TOPDIR)/Rules.make
-
-tmp-ibmtr.o: ../tokenring/ibmtr.c
-	$(CC) $(CFLAGS) -D__NO_VERSION__ -DPCMCIA -c -o $@ ../tokenring/ibmtr.c
-
-ibmtr_cs.o: tmp-ibmtr.o ibmtr_cs.c
-	$(CC) $(CFLAGS) -DPCMCIA -c -o tmp-$@ ibmtr_cs.c
-	$(LD) -r -o $@ tmp-$@ tmp-ibmtr.o
diff -u --recursive --new-file v2.4.5/linux/drivers/net/pcmcia/ibmtr_cs.c linux/drivers/net/pcmcia/ibmtr_cs.c
--- v2.4.5/linux/drivers/net/pcmcia/ibmtr_cs.c	Wed Apr 18 14:40:05 2001
+++ linux/drivers/net/pcmcia/ibmtr_cs.c	Wed Jun 20 11:13:18 2001
@@ -73,6 +73,9 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
+#define PCMCIA
+#include "../tokenring/ibmtr.c"
+
 #ifdef PCMCIA_DEBUG
 static int pc_debug = PCMCIA_DEBUG;
 MODULE_PARM(pc_debug, "i");
@@ -130,7 +133,7 @@
 unsigned char pcmcia_reality_check(unsigned char gss);
 
 extern int trdev_init(struct net_device *dev);
-extern void tok_interrupt(int irq, struct pt_regs *regs);
+extern void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs);
 extern int tok_init_card(struct net_device *dev);
 extern unsigned char get_sram_size(struct tok_info *ti);
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/pcmcia/xircom_tulip_cb.c linux/drivers/net/pcmcia/xircom_tulip_cb.c
--- v2.4.5/linux/drivers/net/pcmcia/xircom_tulip_cb.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/pcmcia/xircom_tulip_cb.c	Wed Jun 20 11:16:01 2001
@@ -245,10 +245,6 @@
 /* This table use during operation for capabilities and media timer. */
 
 static void tulip_timer(unsigned long data);
-static void t21142_timer(unsigned long data);
-static void mxic_timer(unsigned long data);
-static void pnic_timer(unsigned long data);
-static void comet_timer(unsigned long data);
 
 enum tbl_flag {
 	HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8,
@@ -262,37 +258,15 @@
 	int flags;
 	void (*media_timer)(unsigned long data);
 } tulip_tbl[] = {
-  { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
-  { "Digital DC21041 Tulip", 128, 0x0001ebef, HAS_MEDIA_TABLE, tulip_timer },
-  { "Digital DS21140 Tulip", 128, 0x0001ebef,
-	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
-  { "Digital DS21143 Tulip", 128, 0x0801fbff,
-	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, t21142_timer },
-  { "Lite-On 82c168 PNIC", 256, 0x0001ebef,
-	HAS_MII, pnic_timer },
-  { "Macronix 98713 PMAC", 128, 0x0001ebef,
-	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
-  { "Macronix 98715 PMAC", 256, 0x0001ebef,
-	HAS_MEDIA_TABLE, mxic_timer },
-  { "Macronix 98725 PMAC", 256, 0x0001ebef,
-	HAS_MEDIA_TABLE, mxic_timer },
-  { "ASIX AX88140", 128, 0x0001fbff,
-	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer },
-  { "Lite-On PNIC-II", 256, 0x0001ebef,
-	HAS_MII | HAS_NWAY143, pnic_timer },
-  { "ADMtek Comet", 256, 0x0001abef,
-	MC_HASH_ONLY, comet_timer },
-  { "Compex 9881 PMAC", 128, 0x0001ebef,
-	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
   { "Xircom Cardbus Adapter (DEC 21143 compatible mode)", 128, 0x0801fbff,
        HAS_MII | HAS_ACPI, tulip_timer }, 
   {0},
 };
 /* This matches the table above.  Note 21142 == 21143. */
 enum chips {
-	DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
-	LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMPEX9881,
 	X3201_3,
+	DC21040, DC21041, DC21140, DC21142=4, DC21143=4,
+	LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMPEX9881,
 };
 
 /* A full-duplex map for media types. */
@@ -307,9 +281,7 @@
 static u16 t21041_csr14[] = { 0x7F3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
 static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
 
-static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };
 static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, };
-static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
 
 /* Offsets to the Command and Status Registers, "CSRs".  All accesses
    must be longword instructions and quadword aligned. */
@@ -1272,7 +1244,7 @@
 		*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
 		*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
 		/* Put the setup frame on the Tx list. */
-		tp->tx_ring[0].length = 0x08000000 | 192;
+		tp->tx_ring[0].length = 0x68000000 | 192;
 		tp->tx_ring[0].buffer1 = virt_to_bus(tp->setup_frame);
 		tp->tx_ring[0].status = DescOwned;
 
@@ -1291,7 +1263,7 @@
 		}
 
 		/* Put the setup frame on the Tx list. */
-		tp->tx_ring[tp->cur_tx].length = 0x08000000 | 192;
+		tp->tx_ring[tp->cur_tx].length = 0x68000000 | 192;
 		/* Lie about the address of our setup frame to make the */
 		/* chip happy */
 		tp->tx_ring[tp->cur_tx].buffer1 = virt_to_bus(tp->setup_frame);
@@ -1862,83 +1834,6 @@
 	add_timer(&tp->timer);
 }
 
-/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
-   of available transceivers.  */
-static void t21142_timer(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *)data;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	int csr12 = inl(ioaddr + CSR12);
-	int next_tick = 60*HZ;
-	int new_csr6 = 0;
-
-	if ((tulip_debug > 2) && !(media_cap[dev->if_port] & MediaIsMII))
-		printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n",
-			   dev->name, csr12, medianame[dev->if_port]);
-	if (media_cap[dev->if_port] & MediaIsMII) {
-		check_duplex(dev);
-		next_tick = 60*HZ;
-	} else if (tp->nwayset) {
-		/* Don't screw up a negotiated session! */
-		if (tulip_debug > 1)
-			printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n",
-				   dev->name, medianame[dev->if_port], csr12);
-	} else if (tp->medialock) {
-			;
-	} else if (dev->if_port == 3) {
-		if (csr12 & 2) {	/* No 100mbps link beat, revert to 10mbps. */
-			if (tulip_debug > 1)
-				printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, "
-					   "trying NWay.\n", dev->name, csr12);
-			t21142_start_nway(dev);
-			next_tick = 3*HZ;
-		}
-	} else if (((csr12 & 0x7000) != 0x5000)
-			   && tp->chip_id != X3201_3) {
-		/* Negotiation failed.  Search media types. */
-		if (tulip_debug > 1)
-			printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n",
-				   dev->name, csr12);
-		if (!(csr12 & 4)) {		/* 10mbps link beat good. */
-			new_csr6 = 0x82420000;
-			dev->if_port = 0;
-			outl(0, ioaddr + CSR13);
-			outl(0x0003FFFF, ioaddr + CSR14);
-			outw(t21142_csr15[dev->if_port], ioaddr + CSR15);
-			outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
-		} else {
-			/* Select 100mbps port to check for link beat. */
-			new_csr6 = 0x83860000;
-			dev->if_port = 3;
-			outl(0, ioaddr + CSR13);
-			outl(0x0003FF7F, ioaddr + CSR14);
-			outw(8, ioaddr + CSR15);
-			outl(1, ioaddr + CSR13);
-		}
-		if (tulip_debug > 1)
-			printk(KERN_INFO"%s: Testing new 21143 media %s.\n",
-				   dev->name, medianame[dev->if_port]);
-		if (new_csr6 != (tp->csr6 & ~0x00D5)) {
-			tp->csr6 &= 0x00D5;
-			tp->csr6 |= new_csr6;
-			outl(0x0301, ioaddr + CSR12);
-			outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
-			outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
-		}
-		next_tick = 3*HZ;
-	}
-	if (tp->cur_tx - tp->dirty_tx > 0  &&
-		jiffies - dev->trans_start > TX_TIMEOUT) {
-		printk(KERN_WARNING "%s: Tx hung, %d vs. %d.\n",
-			   dev->name, tp->cur_tx, tp->dirty_tx);
-		tulip_tx_timeout(dev);
-	}
-
-	tp->timer.expires = RUN_AT(next_tick);
-	add_timer(&tp->timer);
-}
-
 static void t21142_start_nway(struct net_device *dev)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
@@ -2069,123 +1964,6 @@
 	}
 }
 
-static void mxic_timer(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *)data;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	int next_tick = 60*HZ;
-
-	if (tulip_debug > 3) {
-		printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name,
-			   inl(ioaddr + CSR12));
-	}
-	if (next_tick) {
-		tp->timer.expires = RUN_AT(next_tick);
-		add_timer(&tp->timer);
-	}
-}
-
-static void pnic_timer(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *)data;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	int csr12 = inl(ioaddr + CSR12);
-	int next_tick = 60*HZ;
-	int new_csr6 = tp->csr6 & ~0x40C40200;
-
-	if (media_cap[dev->if_port] & MediaIsMII) {
-		int negotiated = mdio_read(dev, tp->phys[0], 5) & tp->advertising[0];
-
-		if (tulip_debug > 1)
-			printk(KERN_DEBUG "%s: PNIC negotiated capability %8.8x, "
-				   "CSR5 %8.8x.\n",
-				   dev->name, negotiated, inl(ioaddr + CSR5));
-
-		if (negotiated & 0x0380) 				/* 10 vs 100mbps */
-			new_csr6 |= 0x810E0000;
-		else
-			new_csr6 |= 0x814E0000;
-		if (((negotiated & 0x0300) == 0x0100)			/* Duplex */
-			|| (negotiated & 0x00C0) == 0x0040
-			|| tp->full_duplex_lock) {
-			tp->full_duplex = 1;
-			new_csr6 |= 0x0200;
-		}
-		if (tulip_debug > 1)
-			printk(KERN_DEBUG "%s: PNIC MII PHY status %4.4x, Link "
-				   "partner report %4.4x, csr6 %8.8x/%8.8x.\n",
-			   dev->name, mdio_read(dev, tp->phys[0], 1), negotiated,
-				   tp->csr6, inl(ioaddr + CSR6));
-	} else {
-		int phy_reg = inl(ioaddr + 0xB8);
-		int csr5 = inl(ioaddr + CSR5);
-
-		if (tulip_debug > 1)
-			printk(KERN_DEBUG "%s: PNIC PHY status %8.8x, CSR5 %8.8x.\n",
-				   dev->name, phy_reg, csr5);
-
-		if (phy_reg & 0x04000000) {	/* Remote link fault */
-			/*outl(0x0201F078, ioaddr + 0xB8);*/
-			next_tick = 3*HZ;
-		}
-		if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */
-			if (tulip_debug > 1)
-				printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
-					   "CSR5 %8.8x, PHY %3.3x.\n",
-					   dev->name, medianame[dev->if_port], csr12,
-					   inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
-			if (tp->medialock) {
-			} else if (dev->if_port == 0) {
-				dev->if_port = 3;
-				outl(0x33, ioaddr + CSR12);
-				new_csr6 = 0x01860000;
-				outl(0x1F868, ioaddr + 0xB8);
-			} else {
-				dev->if_port = 0;
-				outl(0x32, ioaddr + CSR12);
-				new_csr6 = 0x00420000;
-				outl(0x1F078, ioaddr + 0xB8);
-			}
-			new_csr6 |= (tp->csr6 & 0xfdff);
-			next_tick = 3*HZ;
-		} else
-			new_csr6 = tp->csr6;
-		if (tp->full_duplex_lock  ||  (phy_reg & 0x30000000) != 0) {
-			tp->full_duplex = 1;
-			new_csr6 |= 0x00000200;
-		}
-	}
-	if (tp->csr6 != new_csr6) {
-		tp->csr6 = new_csr6;
-		outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);	/* Restart Tx */
-		outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
-		dev->trans_start = jiffies;
-		if (tulip_debug > 1)
-			printk(KERN_INFO "%s: Changing PNIC configuration to %s-duplex, "
-				   "CSR6 %8.8x.\n",
-				   dev->name, tp->full_duplex ? "full" : "half", new_csr6);
-	}
-	tp->timer.expires = RUN_AT(next_tick);
-	add_timer(&tp->timer);
-}
-
-static void comet_timer(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *)data;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	int next_tick = 60*HZ;
-
-	if (tulip_debug > 1)
-		printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability "
-			   "%4.4x.\n",
-			   dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8));
-	tp->timer.expires = RUN_AT(next_tick);
-	add_timer(&tp->timer);
-}
-
 static void tulip_tx_timeout(struct net_device *dev)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
@@ -2741,12 +2519,6 @@
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 		if (tp->mii_cnt)
 			data[0] = phy;
-		else if (tp->chip_id == DC21142)	/* 21142 pseudo-MII */
-			data[0] = 32;
-		else if (tp->chip_id == PNIC2)
-			data[0] = 32;
-		else if (tp->chip_id == COMET)
-			data[0] = 1;
 		else
 			return -ENODEV;
 		return 0;
@@ -2874,27 +2646,18 @@
 			for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
 				 i++, mclist = mclist->next)
 				set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter);
-			if (tp->chip_id == AX88140) {
-				outl(2, ioaddr + CSR13);
-				outl(mc_filter[0], ioaddr + CSR14);
-				outl(3, ioaddr + CSR13);
-				outl(mc_filter[1], ioaddr + CSR14);
-			} else if (tp->chip_id == COMET) { /* Has a simple hash filter. */
-				outl(mc_filter[0], ioaddr + 0xAC);
-				outl(mc_filter[1], ioaddr + 0xB0);
-			}
 		}
 	} else {
 		u16 *eaddrs, *setup_frm = tp->setup_frame;
 		struct dev_mc_list *mclist;
-		u32 tx_flags = 0x08000000 | 192;
+		u32 tx_flags = 0x68000000 | 192;
 		int i;
 
 		/* Note that only the low-address shortword of setup_frame is valid!
 		   The values are doubled for big-endian architectures. */
-		if ((dev->mc_count > 14) || ((dev->mc_count > 6) && (tp->chip_id == X3201_3))) { /* Must use a multicast hash table. */
+		if (dev->mc_count > 14) { /* Must use a multicast hash table. */
 			u16 hash_table[32];
-			tx_flags = 0x08400000 | 192;		/* Use hash filter. */
+			tx_flags = 0x68400000 | 192;		/* Use hash filter. */
 			memset(hash_table, 0, sizeof(hash_table));
 			set_bit(255, hash_table); 			/* Broadcast entry */
 			/* This should work on big-endian machines as well. */
@@ -2907,7 +2670,7 @@
 				*setup_frm++ = hash_table[i];
 			}
 			setup_frm = &tp->setup_frame[13*6];
-		} else if(tp->chip_id != X3201_3) {
+		} else {
 			/* We have <= 14 addresses so we can use the wonderful
 			   16 address perfect filtering of the Tulip. */
 			for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
@@ -2920,30 +2683,6 @@
 			/* Fill the unused entries with the broadcast address. */
 			memset(setup_frm, 0xff, (15-i)*12);
 			setup_frm = &tp->setup_frame[15*6];
-		} else {
-			/* fill the first two table entries with our address */
-			eaddrs = (u16 *)dev->dev_addr;
-			for(i=0; i<2; i++) {
-				*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
-				*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
-				*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
-			}
-			/* Double fill each entry to accomodate chips that */
-			/* don't like to parse these correctly */
-			for (i=0, mclist=dev->mc_list; i<dev->mc_count;
-				 i++, mclist=mclist->next) {
-				eaddrs = (u16 *)mclist->dmi_addr;
-				*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
-				*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
-				*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
-				*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
-				*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
-				*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
-			}
-			i=((i+1)*2);
-			/* Fill the unused entries with the broadcast address. */
-			memset(setup_frm, 0xff, (15-i)*12);
-			setup_frm = &tp->setup_frame[15*6];
 		}
 
 		/* Fill the final entry with our physical address. */
@@ -2995,20 +2734,6 @@
 }
 
 static  struct pci_device_id tulip_pci_table[] __devinitdata = {
-#if 0 /* these entries conflict with regular tulip driver */
-  { 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 },
-  { 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 },
-  { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 },
-  { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21142 },
-  { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 },
-  { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 },
-  { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
-  { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 },
-  { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 },
-  { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 },
-  { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
-  { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 },
-#endif
   { 0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 },
   {0},
 };
@@ -3034,20 +2759,22 @@
 	return -ENODEV;
 }
 
-static void tulip_suspend(struct pci_dev *pdev)
+static int tulip_suspend(struct pci_dev *pdev, u32 state)
 {
 	struct net_device *dev = pdev->driver_data;
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	printk(KERN_INFO "tulip_suspend(%s)\n", dev->name);
 	if (tp->open) tulip_down(dev);
+	return 0;
 }
 
-static void tulip_resume(struct pci_dev *pdev)
+static int tulip_resume(struct pci_dev *pdev)
 {
 	struct net_device *dev = pdev->driver_data;
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	printk(KERN_INFO "tulip_resume(%s)\n", dev->name);
 	if (tp->open) tulip_up(dev);
+	return 0;
 }
 
 static void __devexit tulip_remove(struct pci_dev *pdev)
diff -u --recursive --new-file v2.4.5/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v2.4.5/linux/drivers/net/plip.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/plip.c	Wed Jun 20 11:10:53 2001
@@ -1297,6 +1297,7 @@
 
 MODULE_PARM(parport, "1-" __MODULE_STRING(PLIP_MAX) "i");
 MODULE_PARM(timid, "1i");
+MODULE_PARM_DESC(parport, "List of parport device numbers to use by plip");
 
 static struct net_device *dev_plip[PLIP_MAX] = { NULL, };
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/ppp_async.c linux/drivers/net/ppp_async.c
--- v2.4.5/linux/drivers/net/ppp_async.c	Fri Apr 20 11:54:24 2001
+++ linux/drivers/net/ppp_async.c	Wed Jun 20 11:10:53 2001
@@ -80,6 +80,7 @@
 
 static int flag_time = HZ;
 MODULE_PARM(flag_time, "i");
+MODULE_PARM_DESC(flag_time, "ppp_async: interval between flagged packets (in clock ticks)");
 
 /*
  * Prototypes.
diff -u --recursive --new-file v2.4.5/linux/drivers/net/saa9730.c linux/drivers/net/saa9730.c
--- v2.4.5/linux/drivers/net/saa9730.c	Fri Apr 13 20:26:07 2001
+++ linux/drivers/net/saa9730.c	Wed Jun 20 11:10:53 2001
@@ -335,7 +335,7 @@
 			printk("Error: lan_saa9730_mii_init: timeout\n");
 			return -1;
 		}
-		udelay(1000);	/* wait 1 ms. */
+		mdelay(1);	/* wait 1 ms. */
 	}
 
 	/* Now set the control and address register. */
@@ -350,11 +350,11 @@
 			printk("Error: lan_saa9730_mii_init: timeout\n");
 			return -1;
 		}
-		udelay(1000);	/* wait 1 ms. */
+		mdelay(1);	/* wait 1 ms. */
 	}
 
 	/* Wait for 1 ms. */
-	udelay(1000);
+	mdelay(1);
 
 	/* Check the link status. */
 	if (INL(&lp->lan_saa9730_regs->StationMgmtData) &
@@ -369,7 +369,7 @@
 		     &lp->lan_saa9730_regs->StationMgmtCtl);
 
 		/* Wait for 1 ms. */
-		udelay(1000);
+		mdelay(1);
 
 		/* set 'CONTROL' = force reset and renegotiate */
 		OUTL(PHY_CONTROL_RESET | PHY_CONTROL_AUTO_NEG |
@@ -377,7 +377,7 @@
 		     &lp->lan_saa9730_regs->StationMgmtData);
 
 		/* Wait for 50 ms. */
-		udelay(50 * 1000);
+		mdelay(50);
 
 		/* set 'BUSY' to start operation */
 		OUTL(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR |
@@ -393,11 +393,11 @@
 				    ("Error: lan_saa9730_mii_init: timeout\n");
 				return -1;
 			}
-			udelay(1000);	/* wait 1 ms. */
+			mdelay(1);	/* wait 1 ms. */
 		}
 
 		/* Wait for 1 ms. */
-		udelay(1000);
+		mdelay(1);
 
 		for (l = 0; l < 2; l++) {
 			/* set PHY address = 'STATUS' */
@@ -415,11 +415,11 @@
 					    ("Error: lan_saa9730_mii_init: timeout\n");
 					return -1;
 				}
-				udelay(1000);	/* wait 1 ms. */
+				mdelay(1);	/* wait 1 ms. */
 			}
 
 			/* wait for 3 sec. */
-			udelay(3000 * 1000);
+			mdelay(3000);
 
 			/* check the link status */
 			if (INL(&lp->lan_saa9730_regs->StationMgmtData) &
@@ -495,7 +495,7 @@
 			    ("Error: lan_sa9730_stop: MAC reset timeout\n");
 			return -1;
 		}
-		udelay(1000);	/* wait 1 ms. */
+		mdelay(1);	/* wait 1 ms. */
 	}
 
 	return 0;
diff -u --recursive --new-file v2.4.5/linux/drivers/net/sb1000.c linux/drivers/net/sb1000.c
--- v2.4.5/linux/drivers/net/sb1000.c	Wed Apr 18 11:49:14 2001
+++ linux/drivers/net/sb1000.c	Wed Jun 20 11:10:53 2001
@@ -1211,6 +1211,8 @@
 MODULE_DESCRIPTION("General Instruments SB1000 driver");
 MODULE_PARM(io, "1-2i");
 MODULE_PARM(irq, "i");
+MODULE_PARM_DESC(io, "SB1000 I/O base addresses");
+MODULE_PARM_DESC(irq, "SB1000 IRQ number");
 
 static struct net_device dev_sb1000;
 static int io[2];
diff -u --recursive --new-file v2.4.5/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c
--- v2.4.5/linux/drivers/net/seeq8005.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/seeq8005.c	Wed Jun 20 11:10:53 2001
@@ -101,8 +101,6 @@
 /* Check for a network adaptor of this type, and return '0' iff one exists.
    If dev->base_addr == 0, probe all likely locations.
    If dev->base_addr == 1, always return failure.
-   If dev->base_addr == 2, allocate space for the device and return success
-   (detachable devices only).
    */
 
 int __init 
@@ -715,6 +713,8 @@
 static int irq = 10;
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
+MODULE_PARM_DESC(io, "SEEQ 8005 I/O base address");
+MODULE_PARM_DESC(irq, "SEEQ 8005 IRQ number");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/shaper.c linux/drivers/net/shaper.c
--- v2.4.5/linux/drivers/net/shaper.c	Wed Apr 18 14:40:06 2001
+++ linux/drivers/net/shaper.c	Wed Jun 20 11:10:53 2001
@@ -682,6 +682,7 @@
 #ifdef MODULE
 
 MODULE_PARM(shapers, "i");
+MODULE_PARM_DESC(shapers, "Traffic shaper: maximum nuber of shapers");
 
 #else /* MODULE */
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/sis900.c linux/drivers/net/sis900.c
--- v2.4.5/linux/drivers/net/sis900.c	Fri Apr 20 11:54:23 2001
+++ linux/drivers/net/sis900.c	Wed Jun 20 11:13:18 2001
@@ -1,6 +1,6 @@
 /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
    Copyright 1999 Silicon Integrated System Corporation 
-   Revision:	1.07.11	Apr. 10 2001
+   Revision:	1.08.00	Jun. 11 2001
    
    Modified from the driver which is originally written by Donald Becker.
    
@@ -18,6 +18,7 @@
    preliminary Rev. 1.0 Jan. 18, 1998
    http://www.sis.com.tw/support/databook.htm
 
+   Rev 1.08.00 Jun. 11 2001 Hui-Fen Hsu workaround for RTL8201 PHY and some bug fix
    Rev 1.07.11 Apr.  2 2001 Hui-Fen Hsu  updates PCI drivers to use the new pci_set_dma_mask for kernel 2.4.3
    Rev 1.07.10 Mar.  1 2001 Hui-Fen Hsu <hfhsu@sis.com.tw> some bug fix & 635M/B support 
    Rev 1.07.09 Feb.  9 2001 Dave Jones <davej@suse.de> PCI enable cleanup
@@ -63,7 +64,7 @@
 #include "sis900.h"
 
 static char version[] __devinitdata =
-KERN_INFO "sis900.c: v1.07.11  4/10/2001\n";
+KERN_INFO "sis900.c: v1.08.00  6/11/2001\n";
 
 static int max_interrupt_work = 40;
 static int multicast_filter_limit = 128;
@@ -110,6 +111,7 @@
 	{ "AMD 79C901 HomePNA PHY",		0x0000, 0x6B90, HOME},
 	{ "ICS LAN PHY",			0x0015, 0xF440, LAN },
 	{ "NS 83851 PHY",			0x2000, 0x5C20, MIX },
+	{ "Realtek RTL8201 PHY",		0x0000, 0x8200, LAN },
 	{0,},
 };
 
@@ -158,6 +160,9 @@
 MODULE_PARM(multicast_filter_limit, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(multicast_filter_limit, "SiS 900/7016 maximum number of filtered multicast addresses");
+MODULE_PARM_DESC(max_interrupt_work, "SiS 900/7016 maximum events handled per interrupt");
+MODULE_PARM_DESC(debug, "SiS 900/7016 debug level (2-4)");
 
 static int sis900_open(struct net_device *net_dev);
 static int sis900_mii_probe (struct net_device * net_dev);
@@ -375,13 +380,13 @@
 
 	if (ret == 0) {
 		ret = -ENODEV;
-		goto err_out_region;
+		goto err_out_unregister;
 	}
 
 	/* probe for mii transciver */
 	if (sis900_mii_probe(net_dev) == 0) {
 		ret = -ENODEV;
-		goto err_out_region;
+		goto err_out_unregister;
 	}
 
 	/* print some information about our NIC */
@@ -393,9 +398,10 @@
 
 	return 0;
 
+ err_out_unregister:
+ 	unregister_netdev(net_dev);
  err_out_cleardev:
  	pci_set_drvdata(pci_dev, NULL);
- err_out_region:
 	pci_release_regions(pci_dev);
  err_out:
 	kfree(net_dev);
@@ -1243,6 +1249,7 @@
 static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex)
 {
 	struct sis900_private *sis_priv = net_dev->priv;
+	struct mii_phy *phy = sis_priv->mii;
 	int phy_addr = sis_priv->cur_phy;
 	u32 status;
 	u16 autoadv, autorec;
@@ -1258,18 +1265,25 @@
 	autoadv = mdio_read(net_dev, phy_addr, MII_ANADV);
 	autorec = mdio_read(net_dev, phy_addr, MII_ANLPAR);
 	status = autoadv & autorec;
+	
+	*speed = HW_SPEED_10_MBPS;
+	*duplex = FDX_CAPABLE_HALF_SELECTED;
 
 	if (status & (MII_NWAY_TX | MII_NWAY_TX_FDX))
 		*speed = HW_SPEED_100_MBPS;
-	else
-		*speed = HW_SPEED_10_MBPS;
 	if (status & ( MII_NWAY_TX_FDX | MII_NWAY_T_FDX))
 		*duplex = FDX_CAPABLE_FULL_SELECTED;
-	else
-		*duplex = FDX_CAPABLE_HALF_SELECTED;
-
-	sis_priv->autong_complete = 1;
 	
+	sis_priv->autong_complete = 1;
+
+	/* Workaround for Realtek RTL8201 PHY issue */
+	if((phy->phy_id0 == 0x0000) && ((phy->phy_id1 & 0xFFF0) == 0x8200)){
+		if(mdio_read(net_dev, phy_addr, MII_CONTROL) & MII_CNTL_FDX)
+			*duplex = FDX_CAPABLE_FULL_SELECTED;
+		if(mdio_read(net_dev, phy_addr, 0x0019) & 0x01)
+			*speed = HW_SPEED_100_MBPS;
+	}
+
 	printk(KERN_INFO "%s: Media Link On %s %s-duplex \n",
 	       net_dev->name,
 	       *speed == HW_SPEED_100_MBPS ?
diff -u --recursive --new-file v2.4.5/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- v2.4.5/linux/drivers/net/slip.c	Wed Apr 18 14:40:06 2001
+++ linux/drivers/net/slip.c	Wed Jun 20 11:10:53 2001
@@ -96,6 +96,7 @@
 
 int slip_maxdev = SL_NRUNIT;		/* Can be overridden with insmod! */
 MODULE_PARM(slip_maxdev, "i");
+MODULE_PARM_DESC(slip_maxdev, "Maximum number of slip devices");
 
 static struct tty_ldisc	sl_ldisc;
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/smc-mca.c linux/drivers/net/smc-mca.c
--- v2.4.5/linux/drivers/net/smc-mca.c	Sun Mar  4 14:05:04 2001
+++ linux/drivers/net/smc-mca.c	Wed Jun 20 11:10:53 2001
@@ -440,6 +440,8 @@
 
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
+MODULE_PARM_DESC(io, "SMC Ultra/EtherEZ MCA I/O base address(es)");
+MODULE_PARM_DESC(irq, "SMC Ultra/EtherEZ MCA IRQ number(s)");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c
--- v2.4.5/linux/drivers/net/smc-ultra.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/smc-ultra.c	Wed Jun 20 11:10:53 2001
@@ -500,6 +500,8 @@
 
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ULTRA_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ULTRA_CARDS) "i");
+MODULE_PARM_DESC(io, "SMC Ultra I/O base address(es)");
+MODULE_PARM_DESC(irq, "SMC Ultra IRQ number(s) (assigned)");
 
 EXPORT_NO_SYMBOLS;
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c
--- v2.4.5/linux/drivers/net/smc9194.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/smc9194.c	Wed Jun 20 11:10:53 2001
@@ -1566,6 +1566,9 @@
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
 MODULE_PARM(ifport, "i");
+MODULE_PARM_DESC(io, "SMC 99194 I/O base address");
+MODULE_PARM_DESC(irq, "SMC 99194 IRQ number");
+MODULE_PARM_DESC(ifport, "SMC 99194 interface port (0-default, 1-TP, 2-AUI)");
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/starfire.c linux/drivers/net/starfire.c
--- v2.4.5/linux/drivers/net/starfire.c	Fri Apr 20 11:54:23 2001
+++ linux/drivers/net/starfire.c	Wed Jun 20 11:13:18 2001
@@ -2,6 +2,10 @@
 /*
 	Written 1998-2000 by Donald Becker.
 
+	Current maintainer is Ion Badulescu <ionut@cs.columbia.edu>. Please
+	send all bug reports to me, and not to Donald Becker, as this code
+	has been modified quite a bit from Donald's original version.
+
 	This software may be used and distributed according to the terms of
 	the GNU General Public License (GPL), incorporated herein by reference.
 	Drivers based on or derived from this code fall under the GPL and must
@@ -20,7 +24,7 @@
 	-----------------------------------------------------------
 
 	Linux kernel-specific changes:
-	
+
 	LK1.1.1 (jgarzik):
 	- Use PCI driver interface
 	- Fix MOD_xxx races
@@ -31,35 +35,130 @@
 
 	LK1.1.3 (Andrew Morton)
 	- Timer cleanups
-	
+
 	LK1.1.4 (jgarzik):
 	- Merge Becker version 1.03
+
+	LK1.2.1 (Ion Badulescu <ionut@cs.columbia.edu>)
+	- Support hardware Rx/Tx checksumming
+	- Use the GFP firmware taken from Adaptec's Netware driver
+
+	LK1.2.2 (Ion Badulescu)
+	- Backported to 2.2.x
+
+	LK1.2.3 (Ion Badulescu)
+	- Fix the flaky mdio interface
+	- More compat clean-ups
+
+	LK1.2.4 (Ion Badulescu)
+	- More 2.2.x initialization fixes
+
+	LK1.2.5 (Ion Badulescu)
+	- Several fixes from Manfred Spraul
+
+	LK1.2.6 (Ion Badulescu)
+	- Fixed ifup/ifdown/ifup problem in 2.4.x
+
+	LK1.2.7 (Ion Badulescu)
+	- Removed unused code
+	- Made more functions static and __init
+
+	LK1.2.8 (Ion Badulescu)
+	- Quell bogus error messages, inform about the Tx threshold
+	- Removed #ifdef CONFIG_PCI, this driver is PCI only
+
+	LK1.2.9 (Ion Badulescu)
+	- Merged Jeff Garzik's changes from 2.4.4-pre5
+	- Added 2.2.x compatibility stuff required by the above changes
+
+	LK1.2.9a (Ion Badulescu)
+	- More updates from Jeff Garzik
+
+	LK1.3.0 (Ion Badulescu)
+	- Merged zerocopy support
+
+	LK1.3.1 (Ion Badulescu)
+	- Added ethtool support
+	- Added GPIO (media change) interrupt support
+
+	LK1.3.2 (Ion Badulescu)
+	- Fixed 2.2.x compatibility issues introduced in 1.3.1
+	- Fixed ethtool ioctl returning uninitialized memory
+
+TODO:
+	- implement tx_timeout() properly
 */
 
+#define DRV_NAME	"starfire"
+#define DRV_VERSION	"1.03+LK1.3.2"
+#define DRV_RELDATE	"June 04, 2001"
+
+/*
+ * Adaptec's license for their Novell drivers (which is where I got the
+ * firmware files) does not allow one to redistribute them. Thus, we can't
+ * include the firmware with this driver.
+ *
+ * However, an end-user is allowed to download and use it, after
+ * converting it to C header files using starfire_firmware.pl.
+ * Once that's done, the #undef below must be changed into a #define
+ * for this driver to really use the firmware. Note that Rx/Tx
+ * hardware TCP checksumming is not possible without the firmware.
+ *
+ * I'm currently [Feb 2001] talking to Adaptec about this redistribution
+ * issue. Stay tuned...
+ */
+#undef HAS_FIRMWARE
+/*
+ * The current frame processor firmware fails to checksum a fragment
+ * of length 1. If and when this is fixed, the #define below can be removed.
+ */
+#define HAS_BROKEN_FIRMWARE
+/*
+ * Define this if using the driver with the zero-copy patch
+ */
+#if defined(HAS_FIRMWARE) && defined(MAX_SKB_FRAGS)
+#define ZEROCOPY
+#endif
+
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
 /* Used for tuning interrupt latency vs. overhead. */
-static int interrupt_mitigation = 0x0;
+static int interrupt_mitigation;
 
 static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
 static int max_interrupt_work = 20;
 static int mtu;
 /* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
-   The Starfire has a 512 element hash table based on the Ethernet CRC.  */
-static int multicast_filter_limit = 32;
+   The Starfire has a 512 element hash table based on the Ethernet CRC. */
+static int multicast_filter_limit = 512;
 
-/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-   Setting to > 1518 effectively disables this feature. */
+#define PKT_BUF_SZ	1536		/* Size of each temporary Rx buffer.*/
+/*
+ * Set the copy breakpoint for the copy-only-tiny-frames scheme.
+ * Setting to > 1518 effectively disables this feature.
+ *
+ * NOTE:
+ * The ia64 doesn't allow for unaligned loads even of integers being
+ * misaligned on a 2 byte boundary. Thus always force copying of
+ * packets as the starfire doesn't allow for misaligned DMAs ;-(
+ * 23/10/2000 - Jes
+ *
+ * The Alpha and the Sparc don't allow unaligned loads, either. -Ion
+ */
+#if defined(__ia64__) || defined(__alpha__) || defined(__sparc__)
+static int rx_copybreak = PKT_BUF_SZ;
+#else
 static int rx_copybreak = 0;
+#endif
 
 /* Used to pass the media type, etc.
    Both 'options[]' and 'full_duplex[]' exist for driver interoperability.
    The media type is usually passed in 'options[]'.
 */
 #define MAX_UNITS 8		/* More are supported, limit only on options */
-static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int options[MAX_UNITS] = {0, };
+static int full_duplex[MAX_UNITS] = {0, };
 
 /* Operational parameters that are set at compile time. */
 
@@ -75,21 +174,23 @@
 
 /* Operational parameters that usually are not changed. */
 /* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (2*HZ)
+#define TX_TIMEOUT	(2 * HZ)
 
-#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
-
-/*
- * The ia64 doesn't allow for unaligned loads even of integers being
- * misaligned on a 2 byte boundary. Thus always force copying of
- * packets as the starfire doesn't allow for misaligned DMAs ;-(
- * 23/10/2000 - Jes
- */
-#ifdef __ia64__
-#define PKT_SHOULD_COPY(pkt_len)	1
-#else
-#define PKT_SHOULD_COPY(pkt_len)	(pkt_len < rx_copybreak)
-#endif
+#ifdef ZEROCOPY
+#if MAX_SKB_FRAGS <= 6
+#define MAX_STARFIRE_FRAGS 6
+#else  /* MAX_STARFIRE_FRAGS > 6 */
+#warning This driver will not work with more than 6 skb fragments.
+#warning Turning off zerocopy support.
+#undef ZEROCOPY
+#endif /* MAX_STARFIRE_FRAGS > 6 */
+#endif /* ZEROCOPY */
+
+#ifdef ZEROCOPY
+#define skb_first_frag_len(skb)	skb_headlen(skb)
+#else  /* not ZEROCOPY */
+#define skb_first_frag_len(skb)	(skb->len)
+#endif /* not ZEROCOPY */
 
 #if !defined(__OPTIMIZE__)
 #warning  You must compile this file with the correct options!
@@ -97,28 +198,53 @@
 #error You must compile this driver with "-O".
 #endif
 
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/skbuff.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
-#include <asm/bitops.h>
-#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#ifdef HAS_FIRMWARE
+#include "starfire_firmware.h"
+#endif /* HAS_FIRMWARE */
+
+/* 2.2.x compatibility code */
+#if LINUX_VERSION_CODE < 0x20300
+
+#include "starfire-kcomp22.h"
+
+#else  /* LINUX_VERSION_CODE > 0x20300 */
+
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+
+#define COMPAT_MOD_INC_USE_COUNT
+#define COMPAT_MOD_DEC_USE_COUNT
+
+#define init_tx_timer(dev, func, timeout) \
+	dev->tx_timeout = func; \
+	dev->watchdog_timeo = timeout;
+#define kick_tx_timer(dev, func, timeout)
+
+#define netif_start_if(dev)
+#define netif_stop_if(dev)
+
+#define PCI_SLOT_NAME(pci_dev)	(pci_dev)->slot_name
+
+#endif /* LINUX_VERSION_CODE > 0x20300 */
+/* end of compatibility code */
+
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
 KERN_INFO "starfire.c:v1.03 7/26/2000  Written by Donald Becker <becker@scyld.com>\n"
 KERN_INFO " Updates and info at http://www.scyld.com/network/starfire.html\n"
-KERN_INFO " (unofficial 2.4.x kernel port, version 1.1.4a, April 17, 2001)\n";
+KERN_INFO " (unofficial 2.2/2.4 kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");
@@ -126,8 +252,15 @@
 MODULE_PARM(mtu, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(interrupt_mitigation, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM_DESC(max_interrupt_work, "Starfire maximum events handled per interrupt");
+MODULE_PARM_DESC(mtu, "Starfire MTU (all boards)");
+MODULE_PARM_DESC(debug, "Starfire debug level (0-6)");
+MODULE_PARM_DESC(rx_copybreak, "Starfire copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(options, "Starfire: Bits 0-3: media type, bit 17: full duplex");
+MODULE_PARM_DESC(full_duplex, "Starfire full duplex setting(s) (1)");
 
 /*
 				Theory of Operation
@@ -158,8 +291,9 @@
 See the Adaptec manual for the many possible structures, and options for
 each structure.  There are far too many to document here.
 
-For transmit this driver uses type 1 transmit descriptors, and relies on
-automatic minimum-length padding.  It does not use the completion queue
+For transmit this driver uses type 0/1 transmit descriptors (depending
+on the presence of the zerocopy infrastructure), and relies on automatic
+minimum-length padding.  It does not use the completion queue
 consumer index, but instead checks for non-zero status entries.
 
 For receive this driver uses type 0 receive descriptors.  The driver
@@ -174,10 +308,11 @@
 phase of receive.
 
 A notable aspect of operation is that unaligned buffers are not permitted by
-the Starfire hardware.  The IP header at offset 14 in an ethernet frame thus
+the Starfire hardware.  Thus the IP header at offset 14 in an ethernet frame
 isn't longword aligned, which may cause problems on some machine
-e.g. Alphas.  Copied frames are put into the skbuff at an offset of "+2",
-16-byte aligning the IP header.
+e.g. Alphas and IA64. For these architectures, the driver is forced to copy
+the frame into a new skbuff unconditionally. Copied frames are put into the
+skbuff at an offset of "+2", thus 16-byte aligning the IP header.
 
 IIId. Synchronization
 
@@ -212,7 +347,6 @@
 
 enum chip_capability_flags {CanHaveMII=1, };
 #define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR0)
-#define MEM_ADDR_SZ 0x80000		/* And maps in 0.5MB(!).  */
 
 #if 0
 #define ADDR_64BITS 1			/* This chip uses 64 bit addresses. */
@@ -233,10 +367,9 @@
 /* A chip capabilities table, matching the CH_xxx entries in xxx_pci_tbl[] above. */
 static struct chip_info {
 	const char *name;
-	int io_size;
 	int drv_flags;
 } netdrv_tbl[] __devinitdata = {
-	{ "Adaptec Starfire 6915", MEM_ADDR_SZ, CanHaveMII },
+	{ "Adaptec Starfire 6915", CanHaveMII },
 };
 
 
@@ -252,26 +385,40 @@
 	PCIDeviceConfig=0x50040, GenCtrl=0x50070, IntrTimerCtrl=0x50074,
 	IntrClear=0x50080, IntrStatus=0x50084, IntrEnable=0x50088,
 	MIICtrl=0x52000, StationAddr=0x50120, EEPROMCtrl=0x51000,
-	TxDescCtrl=0x50090,
+	GPIOCtrl=0x5008C, TxDescCtrl=0x50090,
 	TxRingPtr=0x50098, HiPriTxRingPtr=0x50094, /* Low and High priority. */
 	TxRingHiAddr=0x5009C,		/* 64 bit address extension. */
 	TxProducerIdx=0x500A0, TxConsumerIdx=0x500A4,
 	TxThreshold=0x500B0,
 	CompletionHiAddr=0x500B4, TxCompletionAddr=0x500B8,
 	RxCompletionAddr=0x500BC, RxCompletionQ2Addr=0x500C0,
-	CompletionQConsumerIdx=0x500C4,
+	CompletionQConsumerIdx=0x500C4, RxDMACtrl=0x500D0,
 	RxDescQCtrl=0x500D4, RxDescQHiAddr=0x500DC, RxDescQAddr=0x500E0,
 	RxDescQIdx=0x500E8, RxDMAStatus=0x500F0, RxFilterMode=0x500F4,
-	TxMode=0x55000,
+	TxMode=0x55000, PerfFilterTable=0x56000, HashTable=0x56100,
+	TxGfpMem=0x58000, RxGfpMem=0x5a000,
 };
 
 /* Bits in the interrupt status/mask registers. */
 enum intr_status_bits {
-	IntrNormalSummary=0x8000,	IntrAbnormalSummary=0x02000000,
-	IntrRxDone=0x0300, IntrRxEmpty=0x10040, IntrRxPCIErr=0x80000,
-	IntrTxDone=0x4000, IntrTxEmpty=0x1000, IntrTxPCIErr=0x80000,
-	StatsMax=0x08000000, LinkChange=0xf0000000,
-	IntrTxDataLow=0x00040000,
+	IntrLinkChange=0xf0000000, IntrStatsMax=0x08000000,
+	IntrAbnormalSummary=0x02000000, IntrGeneralTimer=0x01000000,
+	IntrSoftware=0x800000, IntrRxComplQ1Low=0x400000,
+	IntrTxComplQLow=0x200000, IntrPCI=0x100000,
+	IntrDMAErr=0x080000, IntrTxDataLow=0x040000,
+	IntrRxComplQ2Low=0x020000, IntrRxDescQ1Low=0x010000,
+	IntrNormalSummary=0x8000, IntrTxDone=0x4000,
+	IntrTxDMADone=0x2000, IntrTxEmpty=0x1000,
+	IntrEarlyRxQ2=0x0800, IntrEarlyRxQ1=0x0400,
+	IntrRxQ2Done=0x0200, IntrRxQ1Done=0x0100,
+	IntrRxGFPDead=0x80, IntrRxDescQ2Low=0x40,
+	IntrNoTxCsum=0x20, IntrTxBadID=0x10,
+	IntrHiPriTxBadID=0x08, IntrRxGfp=0x04,
+	IntrTxGfp=0x02, IntrPCIPad=0x01,
+	/* not quite bits */
+	IntrRxDone=IntrRxQ2Done | IntrRxQ1Done,
+	IntrRxEmpty=IntrRxDescQ1Low | IntrRxDescQ2Low,
+	IntrNormalMask=0xf0, IntrAbnormalMask=0x3f0e,
 };
 
 /* Bits in the RxFilterMode register. */
@@ -280,9 +427,40 @@
 	AcceptMulticast=0x10, AcceptMyPhys=0xE040,
 };
 
+/* Bits in the TxDescCtrl register. */
+enum tx_ctrl_bits {
+	TxDescSpaceUnlim=0x00, TxDescSpace32=0x10, TxDescSpace64=0x20,
+	TxDescSpace128=0x30, TxDescSpace256=0x40,
+	TxDescType0=0x00, TxDescType1=0x01, TxDescType2=0x02,
+	TxDescType3=0x03, TxDescType4=0x04,
+	TxNoDMACompletion=0x08, TxDescQ64bit=0x80,
+	TxHiPriFIFOThreshShift=24, TxPadLenShift=16,
+	TxDMABurstSizeShift=8,
+};
+
+/* Bits in the RxDescQCtrl register. */
+enum rx_ctrl_bits {
+	RxBufferLenShift=16, RxMinDescrThreshShift=0,
+	RxPrefetchMode=0x8000, Rx2048QEntries=0x4000,
+	RxVariableQ=0x2000, RxDesc64bit=0x1000,
+	RxDescQAddr64bit=0x0100,
+	RxDescSpace4=0x000, RxDescSpace8=0x100,
+	RxDescSpace16=0x200, RxDescSpace32=0x300,
+	RxDescSpace64=0x400, RxDescSpace128=0x500,
+	RxConsumerWrEn=0x80,
+};
+
+/* Bits in the RxCompletionAddr register */
+enum rx_compl_bits {
+	RxComplQAddr64bit=0x80, TxComplProducerWrEn=0x40,
+	RxComplType0=0x00, RxComplType1=0x10,
+	RxComplType2=0x20, RxComplType3=0x30,
+	RxComplThreshShift=0,
+};
+
 /* The Rx and Tx buffer descriptors. */
 struct starfire_rx_desc {
-	u32 rxaddr;					/* Optionally 64 bits. */
+	u32 rxaddr;			/* Optionally 64 bits. */
 };
 enum rx_desc_bits {
 	RxDescValid=1, RxDescEndRing=2,
@@ -291,42 +469,72 @@
 /* Completion queue entry.
    You must update the page allocation, init_ring and the shift count in rx()
    if using a larger format. */
+#ifdef HAS_FIRMWARE
+#define csum_rx_status
+#endif /* HAS_FIRMWARE */
 struct rx_done_desc {
-	u32 status;					/* Low 16 bits is length. */
+	u32 status;			/* Low 16 bits is length. */
+#ifdef csum_rx_status
+	u32 status2;			/* Low 16 bits is csum */
+#endif /* csum_rx_status */
 #ifdef full_rx_status
 	u32 status2;
 	u16 vlanid;
-	u16 csum; 			/* partial checksum */
+	u16 csum;			/* partial checksum */
 	u32 timestamp;
-#endif
+#endif /* full_rx_status */
 };
 enum rx_done_bits {
 	RxOK=0x20000000, RxFIFOErr=0x10000000, RxBufQ2=0x08000000,
 };
 
+#ifdef ZEROCOPY
+/* Type 0 Tx descriptor. */
+/* If more fragments are needed, don't forget to change the
+   descriptor spacing as well! */
+struct starfire_tx_desc {
+	u32 status;
+	u32 nbufs;
+	u32 first_addr;
+	u16 first_len;
+	u16 total_len;
+	struct {
+		u32 addr;
+		u32 len;
+	} frag[MAX_STARFIRE_FRAGS];
+};
+#else  /* not ZEROCOPY */
 /* Type 1 Tx descriptor. */
 struct starfire_tx_desc {
-	u32 status;					/* Upper bits are status, lower 16 length. */
-	u32 addr;
+	u32 status;			/* Upper bits are status, lower 16 length. */
+	u32 first_addr;
 };
+#endif /* not ZEROCOPY */
 enum tx_desc_bits {
-	TxDescID=0xB1010000,		/* Also marks single fragment, add CRC.  */
-	TxDescIntr=0x08000000, TxRingWrap=0x04000000,
+	TxDescID=0xB0000000,
+	TxCRCEn=0x01000000, TxDescIntr=0x08000000,
+	TxRingWrap=0x04000000, TxCalTCP=0x02000000,
 };
 struct tx_done_report {
-	u32 status;					/* timestamp, index. */
+	u32 status;			/* timestamp, index. */
 #if 0
-	u32 intrstatus;				/* interrupt status */
+	u32 intrstatus;			/* interrupt status */
 #endif
 };
 
-#define PRIV_ALIGN	15 	/* Required alignment mask */
-struct ring_info {
+struct rx_ring_info {
 	struct sk_buff *skb;
 	dma_addr_t mapping;
 };
+struct tx_ring_info {
+	struct sk_buff *skb;
+	dma_addr_t first_mapping;
+#ifdef ZEROCOPY
+	dma_addr_t frag_mapping[MAX_STARFIRE_FRAGS];
+#endif /* ZEROCOPY */
+};
 
-#define MII_CNT		4
+#define PHY_CNT		2
 struct netdev_private {
 	/* Descriptor rings first for alignment. */
 	struct starfire_rx_desc *rx_ring;
@@ -334,66 +542,65 @@
 	dma_addr_t rx_ring_dma;
 	dma_addr_t tx_ring_dma;
 	/* The addresses of rx/tx-in-place skbuffs. */
-	struct ring_info rx_info[RX_RING_SIZE];
-	struct ring_info tx_info[TX_RING_SIZE];
-	/* Pointers to completion queues (full pages).  I should cache line pad..*/
-	u8 pad0[100];
+	struct rx_ring_info rx_info[RX_RING_SIZE];
+	struct tx_ring_info tx_info[TX_RING_SIZE];
+	/* Pointers to completion queues (full pages). */
 	struct rx_done_desc *rx_done_q;
 	dma_addr_t rx_done_q_dma;
 	unsigned int rx_done;
 	struct tx_done_report *tx_done_q;
-	unsigned int tx_done;
 	dma_addr_t tx_done_q_dma;
+	unsigned int tx_done;
 	struct net_device_stats stats;
-	struct timer_list timer;	/* Media monitoring timer. */
 	struct pci_dev *pci_dev;
 	/* Frequently used values: keep some adjacent for cache effect. */
-	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
+	unsigned int cur_rx, dirty_rx;	/* Producer/consumer ring indices */
 	unsigned int cur_tx, dirty_tx;
-	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
-	unsigned int tx_full:1;				/* The Tx queue is full. */
+	unsigned int rx_buf_sz;		/* Based on MTU+slack. */
+	unsigned int tx_full:1,		/* The Tx queue is full. */
 	/* These values are keep track of the transceiver/media in use. */
-	unsigned int full_duplex:1,			/* Full-duplex operation requested. */
-		medialock:1,					/* Xcvr set to fixed speed/duplex. */
-		rx_flowctrl:1,
-		tx_flowctrl:1;					/* Use 802.3x flow control. */
-	unsigned int default_port:4;		/* Last dev->if_port value. */
+		autoneg:1,		/* Autonegotiation allowed. */
+		full_duplex:1,		/* Full-duplex operation. */
+		speed100:1;		/* Set if speed == 100MBit. */
+	unsigned int intr_mitigation;
 	u32 tx_mode;
 	u8 tx_threshold;
 	/* MII transceiver section. */
-	int mii_cnt;						/* MII device addresses. */
-	u16 advertising;					/* NWay media advertisement */
-	unsigned char phys[MII_CNT];		/* MII device addresses, only first one used. */
-};
-
-static int  mdio_read(struct net_device *dev, int phy_id, int location);
-static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
-static int  netdev_open(struct net_device *dev);
-static void check_duplex(struct net_device *dev, int startup);
-static void netdev_timer(unsigned long data);
-static void tx_timeout(struct net_device *dev);
-static void init_ring(struct net_device *dev);
-static int  start_tx(struct sk_buff *skb, struct net_device *dev);
-static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
-static void netdev_error(struct net_device *dev, int intr_status);
-static int  netdev_rx(struct net_device *dev);
-static void netdev_error(struct net_device *dev, int intr_status);
-static void set_rx_mode(struct net_device *dev);
+	u16 advertising;		/* NWay media advertisement */
+	int phy_cnt;			/* MII device addresses. */
+	unsigned char phys[PHY_CNT];	/* MII device addresses. */
+};
+
+static int	mdio_read(struct net_device *dev, int phy_id, int location);
+static void	mdio_write(struct net_device *dev, int phy_id, int location, int value);
+static int	netdev_open(struct net_device *dev);
+static void	check_duplex(struct net_device *dev);
+static void	tx_timeout(struct net_device *dev);
+static void	init_ring(struct net_device *dev);
+static int	start_tx(struct sk_buff *skb, struct net_device *dev);
+static void	intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
+static void	netdev_error(struct net_device *dev, int intr_status);
+static int	netdev_rx(struct net_device *dev);
+static void	netdev_error(struct net_device *dev, int intr_status);
+static void	set_rx_mode(struct net_device *dev);
 static struct net_device_stats *get_stats(struct net_device *dev);
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static int  netdev_close(struct net_device *dev);
+static int	netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int	netdev_close(struct net_device *dev);
+static void	netdev_media_change(struct net_device *dev);
 
 
 
-static int __devinit starfire_init_one (struct pci_dev *pdev,
-					const struct pci_device_id *ent)
+static int __devinit starfire_init_one(struct pci_dev *pdev,
+				       const struct pci_device_id *ent)
 {
 	struct netdev_private *np;
 	int i, irq, option, chip_idx = ent->driver_data;
 	struct net_device *dev;
 	static int card_idx = -1;
 	long ioaddr;
-	int drv_flags, io_size = netdrv_tbl[chip_idx].io_size;
+	int drv_flags, io_size;
+	int boguscnt;
+	u8 cache;
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -403,38 +610,58 @@
 #endif
 
 	card_idx++;
-	option = card_idx < MAX_UNITS ? options[card_idx] : 0;
 
 	if (pci_enable_device (pdev))
 		return -EIO;
 
 	ioaddr = pci_resource_start (pdev, 0);
+	io_size = pci_resource_len (pdev, 0);
 	if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) {
-		printk (KERN_ERR "starfire %d: no PCI MEM resources, aborting\n", card_idx);
+		printk (KERN_ERR DRV_NAME " %d: no PCI MEM resources, aborting\n", card_idx);
 		return -ENODEV;
 	}
-	
+
 	dev = alloc_etherdev(sizeof(*np));
 	if (!dev) {
-		printk (KERN_ERR "starfire %d: cannot alloc etherdev, aborting\n", card_idx);
+		printk (KERN_ERR DRV_NAME " %d: cannot alloc etherdev, aborting\n", card_idx);
 		return -ENOMEM;
 	}
 	SET_MODULE_OWNER(dev);
-	
-	irq = pdev->irq; 
 
-	if (pci_request_regions (pdev, "starfire"))
+	irq = pdev->irq;
+
+	if (pci_request_regions (pdev, dev->name)) {
+		printk (KERN_ERR DRV_NAME " %d: cannot reserve PCI resources, aborting\n", card_idx);
 		goto err_out_free_netdev;
+	}
 
 	ioaddr = (long) ioremap (ioaddr, io_size);
 	if (!ioaddr) {
-		printk (KERN_ERR "starfire %d: cannot remap 0x%x @ 0x%lx, aborting\n",
+		printk (KERN_ERR DRV_NAME " %d: cannot remap 0x%x @ 0x%lx, aborting\n",
 			card_idx, io_size, ioaddr);
 		goto err_out_free_res;
 	}
 
 	pci_set_master (pdev);
-	
+
+	/* set PCI cache size */
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache);
+	if ((cache << 2) != SMP_CACHE_BYTES) {
+		printk(KERN_INFO "  PCI cache line size set incorrectly "
+		       "(%i bytes) by BIOS/FW, correcting to %i\n",
+		       (cache << 2), SMP_CACHE_BYTES);
+		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+				      SMP_CACHE_BYTES >> 2);
+	}
+
+#ifdef ZEROCOPY
+	/* Starfire can do SG and TCP/UDP checksumming */
+	dev->features |= NETIF_F_SG;
+#ifdef HAS_FIRMWARE
+	dev->features |= NETIF_F_IP_CSUM;
+#endif /* HAS_FIRMWARE */
+#endif /* ZEROCOPY */
+
 	/* Serial EEPROM reads are hidden by the hardware. */
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = readb(ioaddr + EEPROMCtrl + 20-i);
@@ -442,12 +669,28 @@
 #if ! defined(final_version) /* Dump the EEPROM contents during development. */
 	if (debug > 4)
 		for (i = 0; i < 0x20; i++)
-			printk("%2.2x%s", (unsigned int)readb(ioaddr + EEPROMCtrl + i),
-				   i % 16 != 15 ? " " : "\n");
+			printk("%2.2x%s",
+			       (unsigned int)readb(ioaddr + EEPROMCtrl + i),
+			       i % 16 != 15 ? " " : "\n");
 #endif
 
+	/* Issue soft reset */
+	writel(0x8000, ioaddr + TxMode);
+	udelay(1000);
+	writel(0, ioaddr + TxMode);
+
 	/* Reset the chip to erase previous misconfiguration. */
 	writel(1, ioaddr + PCIDeviceConfig);
+	boguscnt = 1000;
+	while (--boguscnt > 0) {
+		udelay(10);
+		if ((readl(ioaddr + PCIDeviceConfig) & 1) == 0)
+			break;
+	}
+	if (boguscnt == 0)
+		printk("%s: chipset reset never completed!\n", dev->name);
+	/* wait a little longer */
+	udelay(1000);
 
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
@@ -458,32 +701,31 @@
 	np->pci_dev = pdev;
 	drv_flags = netdrv_tbl[chip_idx].drv_flags;
 
+	option = card_idx < MAX_UNITS ? options[card_idx] : 0;
 	if (dev->mem_start)
 		option = dev->mem_start;
 
 	/* The lower four bits are the media type. */
-	if (option > 0) {
-		if (option & 0x200)
-			np->full_duplex = 1;
-		np->default_port = option & 15;
-		if (np->default_port)
-			np->medialock = 1;
-	}
-	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
+	if (option & 0x200)
+		np->full_duplex = 1;
+
+	if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
 		np->full_duplex = 1;
 
 	if (np->full_duplex)
-		np->medialock = 1;
+		np->autoneg = 0;
+	else
+		np->autoneg = 1;
+	np->speed100 = 1;
 
 	/* The chip-specific entries in the device structure. */
 	dev->open = &netdev_open;
 	dev->hard_start_xmit = &start_tx;
-	dev->tx_timeout = &tx_timeout;
-	dev->watchdog_timeo = TX_TIMEOUT;
+	init_tx_timer(dev, tx_timeout, TX_TIMEOUT);
 	dev->stop = &netdev_close;
 	dev->get_stats = &get_stats;
 	dev->set_multicast_list = &set_rx_mode;
-	dev->do_ioctl = &mii_ioctl;
+	dev->do_ioctl = &netdev_ioctl;
 
 	if (mtu)
 		dev->mtu = mtu;
@@ -495,22 +737,35 @@
 	printk(KERN_INFO "%s: %s at 0x%lx, ",
 		   dev->name, netdrv_tbl[chip_idx].name, ioaddr);
 	for (i = 0; i < 5; i++)
-			printk("%2.2x:", dev->dev_addr[i]);
+		printk("%2.2x:", dev->dev_addr[i]);
 	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
 
 	if (drv_flags & CanHaveMII) {
 		int phy, phy_idx = 0;
-		for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) {
-			int mii_status = mdio_read(dev, phy, 1);
-			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+		int mii_status;
+		for (phy = 0; phy < 32 && phy_idx < PHY_CNT; phy++) {
+			mdio_write(dev, phy, MII_BMCR, BMCR_RESET);
+			udelay(500);
+			boguscnt = 1000;
+			while (--boguscnt > 0)
+				if ((mdio_read(dev, phy, MII_BMCR) & BMCR_RESET) == 0)
+					break;
+			if (boguscnt == 0) {
+				printk("%s: PHY reset never completed!\n", dev->name);
+				continue;
+			}
+			mii_status = mdio_read(dev, phy, MII_BMSR);
+			if (mii_status != 0) {
 				np->phys[phy_idx++] = phy;
-				np->advertising = mdio_read(dev, phy, 4);
+				np->advertising = mdio_read(dev, phy, MII_ADVERTISE);
 				printk(KERN_INFO "%s: MII PHY found at address %d, status "
 					   "0x%4.4x advertising %4.4x.\n",
 					   dev->name, phy, mii_status, np->advertising);
+				/* there can be only one PHY on-board */
+				break;
 			}
 		}
-		np->mii_cnt = phy_idx;
+		np->phy_cnt = phy_idx;
 	}
 
 	return 0;
@@ -536,7 +791,11 @@
 	/* ??? Should we add a busy-wait here? */
 	do
 		result = readl(mdio_addr);
-	while ((result & 0xC0000000) != 0x80000000 && --boguscnt >= 0);
+	while ((result & 0xC0000000) != 0x80000000 && --boguscnt > 0);
+	if (boguscnt == 0)
+		return 0;
+	if ((result & 0xffff) == 0xffff)
+		return 0;
 	return result & 0xffff;
 }
 
@@ -557,48 +816,70 @@
 
 	/* Do we ever need to reset the chip??? */
 
+	COMPAT_MOD_INC_USE_COUNT;
+
 	retval = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
-	if (retval)
+	if (retval) {
+		COMPAT_MOD_DEC_USE_COUNT;
 		return retval;
+	}
 
 	/* Disable the Rx and Tx, and reset the chip. */
 	writel(0, ioaddr + GenCtrl);
 	writel(1, ioaddr + PCIDeviceConfig);
 	if (debug > 1)
 		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
-			   dev->name, dev->irq);
+		       dev->name, dev->irq);
 	/* Allocate the various queues, failing gracefully. */
 	if (np->tx_done_q == 0)
 		np->tx_done_q = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->tx_done_q_dma);
 	if (np->rx_done_q == 0)
-		np->rx_done_q = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->rx_done_q_dma);
+		np->rx_done_q = pci_alloc_consistent(np->pci_dev, sizeof(struct rx_done_desc) * DONE_Q_SIZE, &np->rx_done_q_dma);
 	if (np->tx_ring == 0)
 		np->tx_ring = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->tx_ring_dma);
 	if (np->rx_ring == 0)
 		np->rx_ring = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->rx_ring_dma);
-	if (np->tx_done_q == 0  ||  np->rx_done_q == 0
-		|| np->rx_ring == 0 ||  np->tx_ring == 0) {
+	if (np->tx_done_q == 0 || np->rx_done_q == 0
+		|| np->rx_ring == 0 || np->tx_ring == 0) {
 		if (np->tx_done_q)
 			pci_free_consistent(np->pci_dev, PAGE_SIZE,
-								np->tx_done_q, np->tx_done_q_dma);
+					    np->tx_done_q, np->tx_done_q_dma);
 		if (np->rx_done_q)
-			pci_free_consistent(np->pci_dev, PAGE_SIZE,
-								np->rx_done_q, np->rx_done_q_dma);
+			pci_free_consistent(np->pci_dev, sizeof(struct rx_done_desc) * DONE_Q_SIZE,
+					    np->rx_done_q, np->rx_done_q_dma);
 		if (np->tx_ring)
 			pci_free_consistent(np->pci_dev, PAGE_SIZE,
-								np->tx_ring, np->tx_ring_dma);
+					    np->tx_ring, np->tx_ring_dma);
 		if (np->rx_ring)
 			pci_free_consistent(np->pci_dev, PAGE_SIZE,
-								np->rx_ring, np->rx_ring_dma);
+					    np->rx_ring, np->rx_ring_dma);
+		COMPAT_MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
 
 	init_ring(dev);
 	/* Set the size of the Rx buffers. */
-	writel((np->rx_buf_sz<<16) | 0xA000, ioaddr + RxDescQCtrl);
-
+	writel((np->rx_buf_sz << RxBufferLenShift) |
+	       (0 << RxMinDescrThreshShift) |
+	       RxPrefetchMode | RxVariableQ |
+	       RxDescSpace4,
+	       ioaddr + RxDescQCtrl);
+
+#ifdef ZEROCOPY
+	/* Set Tx descriptor to type 0 and spacing to 64 bytes. */
+	writel((2 << TxHiPriFIFOThreshShift) |
+	       (0 << TxPadLenShift) |
+	       (4 << TxDMABurstSizeShift) |
+	       TxDescSpace64 | TxDescType0,
+	       ioaddr + TxDescCtrl);
+#else  /* not ZEROCOPY */
 	/* Set Tx descriptor to type 1 and padding to 0 bytes. */
-	writel(0x02000401, ioaddr + TxDescCtrl);
+	writel((2 << TxHiPriFIFOThreshShift) |
+	       (0 << TxPadLenShift) |
+	       (4 << TxDMABurstSizeShift) |
+	       TxDescSpaceUnlim | TxDescType1,
+	       ioaddr + TxDescCtrl);
+#endif /* not ZEROCOPY */
 
 #if defined(ADDR_64BITS) && defined(__alpha__)
 	/* XXX We really need a 64-bit PCI dma interfaces too... -DaveM */
@@ -613,17 +894,34 @@
 	writel(np->tx_ring_dma, ioaddr + TxRingPtr);
 
 	writel(np->tx_done_q_dma, ioaddr + TxCompletionAddr);
-	writel(np->rx_done_q_dma, ioaddr + RxCompletionAddr);
+#ifdef full_rx_status
+	writel(np->rx_done_q_dma |
+	       RxComplType3 |
+	       (0 << RxComplThreshShift),
+	       ioaddr + RxCompletionAddr);
+#else  /* not full_rx_status */
+#ifdef csum_rx_status
+	writel(np->rx_done_q_dma |
+	       RxComplType2 |
+	       (0 << RxComplThreshShift),
+	       ioaddr + RxCompletionAddr);
+#else  /* not csum_rx_status */
+	writel(np->rx_done_q_dma |
+	       RxComplType0 |
+	       (0 << RxComplThreshShift),
+	       ioaddr + RxCompletionAddr);
+#endif /* not csum_rx_status */
+#endif /* not full_rx_status */
 
 	if (debug > 1)
-		printk(KERN_DEBUG "%s:  Filling in the station address.\n", dev->name);
+		printk(KERN_DEBUG "%s: Filling in the station address.\n", dev->name);
 
 	/* Fill both the unused Tx SA register and the Rx perfect filter. */
 	for (i = 0; i < 6; i++)
 		writeb(dev->dev_addr[i], ioaddr + StationAddr + 5-i);
 	for (i = 0; i < 16; i++) {
 		u16 *eaddrs = (u16 *)dev->dev_addr;
-		long setup_frm = ioaddr + 0x56000 + i*16;
+		long setup_frm = ioaddr + PerfFilterTable + i * 16;
 		writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4;
 		writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4;
 		writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8;
@@ -631,116 +929,93 @@
 
 	/* Initialize other registers. */
 	/* Configure the PCI bus bursts and FIFO thresholds. */
-	np->tx_mode = 0;			/* Initialized when TxMode set. */
+	np->tx_mode = 0x0C04;		/* modified when link is up. */
 	np->tx_threshold = 4;
 	writel(np->tx_threshold, ioaddr + TxThreshold);
-	writel(interrupt_mitigation, ioaddr + IntrTimerCtrl);
 
-	if (dev->if_port == 0)
-		dev->if_port = np->default_port;
+	interrupt_mitigation &= 0x1f;
+	np->intr_mitigation = interrupt_mitigation;
+	writel(np->intr_mitigation, ioaddr + IntrTimerCtrl);
 
+	netif_start_if(dev);
 	netif_start_queue(dev);
 
 	if (debug > 1)
-		printk(KERN_DEBUG "%s:  Setting the Rx and Tx modes.\n", dev->name);
+		printk(KERN_DEBUG "%s: Setting the Rx and Tx modes.\n", dev->name);
 	set_rx_mode(dev);
 
-	np->advertising = mdio_read(dev, np->phys[0], 4);
-	check_duplex(dev, 1);
+	np->advertising = mdio_read(dev, np->phys[0], MII_ADVERTISE);
+	check_duplex(dev);
+
+	/* Enable GPIO interrupts on link change */
+	writel(0x0f00ff00, ioaddr + GPIOCtrl);
 
 	/* Set the interrupt mask and enable PCI interrupts. */
-	writel(IntrRxDone | IntrRxEmpty | IntrRxPCIErr |
-		   IntrTxDone | IntrTxEmpty | IntrTxPCIErr |
-		   StatsMax | LinkChange | IntrNormalSummary | IntrAbnormalSummary
-		   | 0x0010 , ioaddr + IntrEnable);
+	writel(IntrRxDone | IntrRxEmpty | IntrDMAErr |
+	       IntrTxDone | IntrStatsMax | IntrLinkChange |
+	       IntrNormalSummary | IntrAbnormalSummary |
+	       IntrRxGFPDead | IntrNoTxCsum | IntrTxBadID,
+	       ioaddr + IntrEnable);
 	writel(0x00800000 | readl(ioaddr + PCIDeviceConfig),
-		   ioaddr + PCIDeviceConfig);
+	       ioaddr + PCIDeviceConfig);
 
-	/* Enable the Rx and Tx units. */
+#ifdef HAS_FIRMWARE
+	/* Load Rx/Tx firmware into the frame processors */
+	for (i = 0; i < FIRMWARE_RX_SIZE * 2; i++)
+		writel(cpu_to_le32(firmware_rx[i]), ioaddr + RxGfpMem + i * 4);
+	for (i = 0; i < FIRMWARE_TX_SIZE * 2; i++)
+		writel(cpu_to_le32(firmware_tx[i]), ioaddr + TxGfpMem + i * 4);
+	/* Enable the Rx and Tx units, and the Rx/Tx frame processors. */
+	writel(0x003F, ioaddr + GenCtrl);
+#else  /* not HAS_FIRMWARE */
+	/* Enable the Rx and Tx units only. */
 	writel(0x000F, ioaddr + GenCtrl);
+#endif /* not HAS_FIRMWARE */
 
 	if (debug > 2)
 		printk(KERN_DEBUG "%s: Done netdev_open().\n",
-			   dev->name);
-
-	/* Set the timer to check for link beat. */
-	init_timer(&np->timer);
-	np->timer.expires = jiffies + 3*HZ;
-	np->timer.data = (unsigned long)dev;
-	np->timer.function = &netdev_timer;				/* timer handler */
-	add_timer(&np->timer);
+		       dev->name);
 
 	return 0;
 }
 
-static void check_duplex(struct net_device *dev, int startup)
+
+static void check_duplex(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
-	int new_tx_mode ;
+	u16 reg0;
 
-	new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0)
-		| (np->rx_flowctrl ? 0x0400:0);
-	if (np->medialock) {
-		if (np->full_duplex)
-			new_tx_mode |= 2;
-	} else {
-		int mii_reg5 = mdio_read(dev, np->phys[0], 5);
-		int negotiated =  mii_reg5 & np->advertising;
-		int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
-		if (duplex)
-			new_tx_mode |= 2;
-		if (np->full_duplex != duplex) {
-			np->full_duplex = duplex;
-			if (debug > 1)
-				printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d"
-					   " negotiated capability %4.4x.\n", dev->name,
-					   duplex ? "full" : "half", np->phys[0], negotiated);
-		}
-	}
-	if (new_tx_mode != np->tx_mode) {
-		np->tx_mode = new_tx_mode;
-		writel(np->tx_mode | 0x8000, ioaddr + TxMode);
-		writel(np->tx_mode, ioaddr + TxMode);
-	}
-}
+	mdio_write(dev, np->phys[0], MII_ADVERTISE, np->advertising);
+	mdio_write(dev, np->phys[0], MII_BMCR, BMCR_RESET);
+	udelay(500);
+	while (mdio_read(dev, np->phys[0], MII_BMCR) & BMCR_RESET);
 
-static void netdev_timer(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *)data;
-	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
-	int next_tick = 60*HZ;		/* Check before driver release. */
+	reg0 = mdio_read(dev, np->phys[0], MII_BMCR);
 
-	if (debug > 3) {
-		printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n",
-			   dev->name, (int)readl(ioaddr + IntrStatus));
-	}
-	check_duplex(dev, 0);
-#if ! defined(final_version)
-	/* This is often falsely triggered. */
-	if (readl(ioaddr + IntrStatus) & 1) {
-		int new_status = readl(ioaddr + IntrStatus);
-		/* Bogus hardware IRQ: Fake an interrupt handler call. */
-		if (new_status & 1) {
-			printk(KERN_ERR "%s: Interrupt blocked, status %8.8x/%8.8x.\n",
-				   dev->name, new_status, (int)readl(ioaddr + IntrStatus));
-			intr_handler(dev->irq, dev, 0);
-		}
+	if (np->autoneg) {
+		reg0 |= BMCR_ANENABLE | BMCR_ANRESTART;
+	} else {
+		reg0 &= ~(BMCR_ANENABLE | BMCR_ANRESTART);
+		if (np->speed100)
+			reg0 |= BMCR_SPEED100;
+		if (np->full_duplex)
+			reg0 |= BMCR_FULLDPLX;
+		printk(KERN_DEBUG "%s: Link forced to %sMbit %s-duplex\n",
+		       dev->name,
+		       np->speed100 ? "100" : "10",
+		       np->full_duplex ? "full" : "half");
 	}
-#endif
-
-	np->timer.expires = jiffies + next_tick;
-	add_timer(&np->timer);
+	mdio_write(dev, np->phys[0], MII_BMCR, reg0);
 }
 
+
 static void tx_timeout(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 
 	printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
-		   " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus));
+	       " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus));
 
 #ifndef __alpha__
 	{
@@ -756,21 +1031,20 @@
 #endif
 
 	/* Perhaps we should reinitialize the hardware here. */
-	dev->if_port = 0;
 	/* Stop and restart the chip's Tx processes . */
 
 	/* Trigger an immediate transmit demand. */
 
 	dev->trans_start = jiffies;
 	np->stats.tx_errors++;
-	return;
+	netif_wake_queue(dev);
 }
 
 
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void init_ring(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	int i;
 
 	np->tx_full = 0;
@@ -810,7 +1084,14 @@
 
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		np->tx_info[i].skb = NULL;
-		np->tx_info[i].mapping = 0;
+		np->tx_info[i].first_mapping = 0;
+#ifdef ZEROCOPY
+		{
+			int j;
+			for (j = 0; j < MAX_STARFIRE_FRAGS; j++)
+				np->tx_info[i].frag_mapping[j] = 0;
+		}
+#endif /* ZEROCOPY */
 		np->tx_ring[i].status = 0;
 	}
 	return;
@@ -820,6 +1101,11 @@
 {
 	struct netdev_private *np = dev->priv;
 	unsigned int entry;
+#ifdef ZEROCOPY
+	int i;
+#endif
+
+	kick_tx_timer(dev, tx_timeout, TX_TIMEOUT);
 
 	/* Caution: the write order is important here, set the field
 	   with the "ownership" bits last. */
@@ -827,26 +1113,87 @@
 	/* Calculate the next Tx descriptor entry. */
 	entry = np->cur_tx % TX_RING_SIZE;
 
+#if defined(ZEROCOPY) && defined(HAS_FIRMWARE) && defined(HAS_BROKEN_FIRMWARE)
+	{
+		int has_bad_length = 0;
+
+		if (skb_first_frag_len(skb) == 1)
+			has_bad_length = 1;
+		else {
+			for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+				if (skb_shinfo(skb)->frags[i].size == 1) {
+					has_bad_length = 1;
+					break;
+				}
+		}
+
+		if (has_bad_length)
+			skb_checksum_help(skb);
+	}
+#endif /* ZEROCOPY && HAS_FIRMWARE && HAS_BROKEN_FIRMWARE */
+
 	np->tx_info[entry].skb = skb;
-	np->tx_info[entry].mapping =
-		pci_map_single(np->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+	np->tx_info[entry].first_mapping =
+		pci_map_single(np->pci_dev, skb->data, skb_first_frag_len(skb), PCI_DMA_TODEVICE);
+
+	np->tx_ring[entry].first_addr = cpu_to_le32(np->tx_info[entry].first_mapping);
+#ifdef ZEROCOPY
+	np->tx_ring[entry].first_len = cpu_to_le32(skb_first_frag_len(skb));
+	np->tx_ring[entry].total_len = cpu_to_le32(skb->len);
+	/* Add "| TxDescIntr" to generate Tx-done interrupts. */
+	np->tx_ring[entry].status = cpu_to_le32(TxDescID | TxCRCEn);
+	np->tx_ring[entry].nbufs = cpu_to_le32(skb_shinfo(skb)->nr_frags + 1);
+#else  /* not ZEROCOPY */
+	/* Add "| TxDescIntr" to generate Tx-done interrupts. */
+	np->tx_ring[entry].status = cpu_to_le32(skb->len | TxDescID | TxCRCEn | 1 << 16);
+#endif /* not ZEROCOPY */
+
+	if (entry >= TX_RING_SIZE-1)		 /* Wrap ring */
+		np->tx_ring[entry].status |= cpu_to_le32(TxRingWrap | TxDescIntr);
+
+#ifdef ZEROCOPY
+	if (skb->ip_summed == CHECKSUM_HW)
+		np->tx_ring[entry].status |= cpu_to_le32(TxCalTCP);
+#endif /* ZEROCOPY */
 
-	np->tx_ring[entry].addr = cpu_to_le32(np->tx_info[entry].mapping);
-	/* Add  "| TxDescIntr" to generate Tx-done interrupts. */
-	np->tx_ring[entry].status = cpu_to_le32(skb->len | TxDescID);
 	if (debug > 5) {
-		printk(KERN_DEBUG "%s: Tx #%d slot %d  %8.8x %8.8x.\n",
-			   dev->name, np->cur_tx, entry,
-			   le32_to_cpu(np->tx_ring[entry].status),
-			   le32_to_cpu(np->tx_ring[entry].addr));
+#ifdef ZEROCOPY
+		printk(KERN_DEBUG "%s: Tx #%d slot %d status %8.8x nbufs %d len %4.4x/%4.4x.\n",
+		       dev->name, np->cur_tx, entry,
+		       le32_to_cpu(np->tx_ring[entry].status),
+		       le32_to_cpu(np->tx_ring[entry].nbufs),
+		       le32_to_cpu(np->tx_ring[entry].first_len),
+		       le32_to_cpu(np->tx_ring[entry].total_len));
+#else  /* not ZEROCOPY */
+		printk(KERN_DEBUG "%s: Tx #%d slot %d status %8.8x.\n",
+		       dev->name, np->cur_tx, entry,
+		       le32_to_cpu(np->tx_ring[entry].status));
+#endif /* not ZEROCOPY */
+	}
+
+#ifdef ZEROCOPY
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+		skb_frag_t *this_frag = &skb_shinfo(skb)->frags[i];
+
+		/* we already have the proper value in entry */
+		np->tx_info[entry].frag_mapping[i] =
+			pci_map_single(np->pci_dev, page_address(this_frag->page) + this_frag->page_offset, this_frag->size, PCI_DMA_TODEVICE);
+
+		np->tx_ring[entry].frag[i].addr = cpu_to_le32(np->tx_info[entry].frag_mapping[i]);
+		np->tx_ring[entry].frag[i].len = cpu_to_le32(this_frag->size);
+		if (debug > 5) {
+			printk(KERN_DEBUG "%s: Tx #%d frag %d len %4.4x.\n",
+			       dev->name, np->cur_tx, i,
+			       le32_to_cpu(np->tx_ring[entry].frag[i].len));
+		}
 	}
+#endif /* ZEROCOPY */
+
 	np->cur_tx++;
-#if 1
-	if (entry >= TX_RING_SIZE-1) {		 /* Wrap ring */
-		np->tx_ring[entry].status |= cpu_to_le32(TxRingWrap | TxDescIntr);
+
+	if (entry >= TX_RING_SIZE-1)		 /* Wrap ring */
 		entry = -1;
-	}
-#endif
+	entry++;
 
 	/* Non-x86: explicitly flush descriptor cache lines here. */
 	/* Ensure everything is written back above before the transmit is
@@ -854,18 +1201,15 @@
 	wmb();
 
 	/* Update the producer index. */
-	writel(++entry, dev->base_addr + TxProducerIdx);
+	writel(entry * (sizeof(struct starfire_tx_desc) / 8), dev->base_addr + TxProducerIdx);
 
 	if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1) {
 		np->tx_full = 1;
 		netif_stop_queue(dev);
 	}
+
 	dev->trans_start = jiffies;
 
-	if (debug > 4) {
-		printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
-			   dev->name, np->cur_tx, entry);
-	}
 	return 0;
 }
 
@@ -877,24 +1221,25 @@
 	struct netdev_private *np;
 	long ioaddr;
 	int boguscnt = max_interrupt_work;
+	int consumer;
+	int tx_status;
 
 #ifndef final_version			/* Can never occur. */
 	if (dev == NULL) {
-		printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown "
-				"device.\n", irq);
+		printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown device.\n", irq);
 		return;
 	}
 #endif
 
 	ioaddr = dev->base_addr;
-	np = (struct netdev_private *)dev->priv;
+	np = dev->priv;
 
 	do {
 		u32 intr_status = readl(ioaddr + IntrClear);
 
 		if (debug > 4)
 			printk(KERN_DEBUG "%s: Interrupt status %4.4x.\n",
-				   dev->name, intr_status);
+			       dev->name, intr_status);
 
 		if (intr_status == 0)
 			break;
@@ -905,77 +1250,99 @@
 		/* Scavenge the skbuff list based on the Tx-done queue.
 		   There are redundant checks here that may be cleaned up
 		   after the driver has proven to be reliable. */
-		{
-			int consumer = readl(ioaddr + TxConsumerIdx);
-			int tx_status;
-			if (debug > 4)
-				printk(KERN_DEBUG "%s: Tx Consumer index is %d.\n",
-					   dev->name, consumer);
+		consumer = readl(ioaddr + TxConsumerIdx);
+		if (debug > 4)
+			printk(KERN_DEBUG "%s: Tx Consumer index is %d.\n",
+			       dev->name, consumer);
 #if 0
-			if (np->tx_done >= 250  || np->tx_done == 0)
-				printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x, "
-					   "%d is %8.8x.\n", dev->name,
-					   np->tx_done, le32_to_cpu(np->tx_done_q[np->tx_done].status),
-					   (np->tx_done+1) & (DONE_Q_SIZE-1),
-					   le32_to_cpu(np->tx_done_q[(np->tx_done+1)&(DONE_Q_SIZE-1)].status));
+		if (np->tx_done >= 250 || np->tx_done == 0)
+			printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x, %d is %8.8x.\n",
+			       dev->name, np->tx_done,
+			       le32_to_cpu(np->tx_done_q[np->tx_done].status),
+			       (np->tx_done+1) & (DONE_Q_SIZE-1),
+			       le32_to_cpu(np->tx_done_q[(np->tx_done+1)&(DONE_Q_SIZE-1)].status));
 #endif
-			while ((tx_status = le32_to_cpu(np->tx_done_q[np->tx_done].status))
-				   != 0) {
-				if (debug > 4)
-					printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x.\n",
-						   dev->name, np->tx_done, tx_status);
-				if ((tx_status & 0xe0000000) == 0xa0000000) {
-					np->stats.tx_packets++;
-				} else if ((tx_status & 0xe0000000) == 0x80000000) {
-					struct sk_buff *skb;
-					u16 entry = tx_status; 		/* Implicit truncate */
-					entry >>= 3;
 
-					skb = np->tx_info[entry].skb;
-					pci_unmap_single(np->pci_dev,
-							 np->tx_info[entry].mapping,
-							 skb->len, PCI_DMA_TODEVICE);
+		while ((tx_status = le32_to_cpu(np->tx_done_q[np->tx_done].status)) != 0) {
+			if (debug > 4)
+				printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x.\n",
+				       dev->name, np->tx_done, tx_status);
+			if ((tx_status & 0xe0000000) == 0xa0000000) {
+				np->stats.tx_packets++;
+			} else if ((tx_status & 0xe0000000) == 0x80000000) {
+				struct sk_buff *skb;
+#ifdef ZEROCOPY
+				int i;
+#endif /* ZEROCOPY */
+				u16 entry = tx_status;		/* Implicit truncate */
+				entry /= sizeof(struct starfire_tx_desc);
+
+				skb = np->tx_info[entry].skb;
+				np->tx_info[entry].skb = NULL;
+				pci_unmap_single(np->pci_dev,
+						 np->tx_info[entry].first_mapping,
+						 skb_first_frag_len(skb),
+						 PCI_DMA_TODEVICE);
+				np->tx_info[entry].first_mapping = 0;
 
-					/* Scavenge the descriptor. */
-					dev_kfree_skb_irq(skb);
-					np->tx_info[entry].skb = NULL;
-					np->tx_info[entry].mapping = 0;
-					np->dirty_tx++;
+#ifdef ZEROCOPY
+				for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+					pci_unmap_single(np->pci_dev,
+							 np->tx_info[entry].frag_mapping[i],
+							 skb_shinfo(skb)->frags[i].size,
+							 PCI_DMA_TODEVICE);
+					np->tx_info[entry].frag_mapping[i] = 0;
 				}
-				np->tx_done_q[np->tx_done].status = 0;
-				np->tx_done = (np->tx_done+1) & (DONE_Q_SIZE-1);
+#endif /* ZEROCOPY */
+
+				/* Scavenge the descriptor. */
+				dev_kfree_skb_irq(skb);
+
+				np->dirty_tx++;
 			}
-			writew(np->tx_done, ioaddr + CompletionQConsumerIdx + 2);
+			np->tx_done_q[np->tx_done].status = 0;
+			np->tx_done = (np->tx_done+1) & (DONE_Q_SIZE-1);
 		}
+		writew(np->tx_done, ioaddr + CompletionQConsumerIdx + 2);
+
 		if (np->tx_full && np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) {
 			/* The ring is no longer full, wake the queue. */
 			np->tx_full = 0;
 			netif_wake_queue(dev);
 		}
 
+		/* Stats overflow */
+		if (intr_status & IntrStatsMax) {
+			get_stats(dev);
+		}
+
+		/* Media change interrupt. */
+		if (intr_status & IntrLinkChange)
+			netdev_media_change(dev);
+
 		/* Abnormal error summary/uncommon events handlers. */
 		if (intr_status & IntrAbnormalSummary)
 			netdev_error(dev, intr_status);
 
 		if (--boguscnt < 0) {
 			printk(KERN_WARNING "%s: Too much work at interrupt, "
-				   "status=0x%4.4x.\n",
-				   dev->name, intr_status);
+			       "status=0x%4.4x.\n",
+			       dev->name, intr_status);
 			break;
 		}
 	} while (1);
 
 	if (debug > 4)
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-			   dev->name, (int)readl(ioaddr + IntrStatus));
+		       dev->name, (int)readl(ioaddr + IntrStatus));
 
 #ifndef final_version
 	/* Code that should never be run!  Remove after testing.. */
 	{
 		static int stopit = 10;
-		if (!netif_running(dev)  &&  --stopit < 0) {
+		if (!netif_running(dev) && --stopit < 0) {
 			printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n",
-				   dev->name);
+			       dev->name);
 			free_irq(irq, dev);
 		}
 	}
@@ -992,83 +1359,99 @@
 
 	if (np->rx_done_q == 0) {
 		printk(KERN_ERR "%s:  rx_done_q is NULL!  rx_done is %d. %p.\n",
-			   dev->name, np->rx_done, np->tx_done_q);
+		       dev->name, np->rx_done, np->tx_done_q);
 		return 0;
 	}
 
 	/* If EOP is set on the next entry, it's a new packet. Send it up. */
 	while ((desc_status = le32_to_cpu(np->rx_done_q[np->rx_done].status)) != 0) {
+		struct sk_buff *skb;
+		u16 pkt_len;
+		int entry;
+
 		if (debug > 4)
-			printk(KERN_DEBUG "  netdev_rx() status of %d was %8.8x.\n",
-				   np->rx_done, desc_status);
+			printk(KERN_DEBUG "  netdev_rx() status of %d was %8.8x.\n", np->rx_done, desc_status);
 		if (--boguscnt < 0)
 			break;
 		if ( ! (desc_status & RxOK)) {
 			/* There was a error. */
 			if (debug > 2)
-				printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",
-					   desc_status);
+				printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n", desc_status);
 			np->stats.rx_errors++;
 			if (desc_status & RxFIFOErr)
 				np->stats.rx_fifo_errors++;
-		} else {
-			struct sk_buff *skb;
-			u16 pkt_len = desc_status;			/* Implicitly Truncate */
-			int entry = (desc_status >> 16) & 0x7ff;
+			goto next_rx;
+		}
+
+		pkt_len = desc_status;	/* Implicitly Truncate */
+		entry = (desc_status >> 16) & 0x7ff;
 
 #ifndef final_version
-			if (debug > 4)
-				printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d"
-					   ", bogus_cnt %d.\n",
-					   pkt_len, boguscnt);
+		if (debug > 4)
+			printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d, bogus_cnt %d.\n", pkt_len, boguscnt);
 #endif
-			/* Check if the packet is long enough to accept without copying
-			   to a minimally-sized skbuff. */
-			if (PKT_SHOULD_COPY(pkt_len)
-				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-				skb->dev = dev;
-				skb_reserve(skb, 2);	/* 16 byte align the IP header */
-				pci_dma_sync_single(np->pci_dev,
-						    np->rx_info[entry].mapping,
-						    pkt_len, PCI_DMA_FROMDEVICE);
+		/* Check if the packet is long enough to accept without copying
+		   to a minimally-sized skbuff. */
+		if (pkt_len < rx_copybreak
+		    && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+			skb->dev = dev;
+			skb_reserve(skb, 2);	/* 16 byte align the IP header */
+			pci_dma_sync_single(np->pci_dev,
+					    np->rx_info[entry].mapping,
+					    pkt_len, PCI_DMA_FROMDEVICE);
 #if HAS_IP_COPYSUM			/* Call copy + cksum if available. */
-				eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0);
-				skb_put(skb, pkt_len);
+			eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0);
+			skb_put(skb, pkt_len);
 #else
-				memcpy(skb_put(skb, pkt_len), np->rx_info[entry].skb->tail,
-					   pkt_len);
+			memcpy(skb_put(skb, pkt_len), np->rx_info[entry].skb->tail, pkt_len);
 #endif
-			} else {
-				char *temp;
+		} else {
+			char *temp;
 
-				pci_unmap_single(np->pci_dev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
-				skb = np->rx_info[entry].skb;
-				temp = skb_put(skb, pkt_len);
-				np->rx_info[entry].skb = NULL;
-				np->rx_info[entry].mapping = 0;
-			}
-#ifndef final_version				/* Remove after testing. */
-			/* You will want this info for the initial debug. */
-			if (debug > 5)
-				printk(KERN_DEBUG "  Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
-					   "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
-					   "%d.%d.%d.%d.\n",
-					   skb->data[0], skb->data[1], skb->data[2], skb->data[3],
-					   skb->data[4], skb->data[5], skb->data[6], skb->data[7],
-					   skb->data[8], skb->data[9], skb->data[10],
-					   skb->data[11], skb->data[12], skb->data[13],
-					   skb->data[14], skb->data[15], skb->data[16],
-					   skb->data[17]);
-#endif
-			skb->protocol = eth_type_trans(skb, dev);
-#ifdef full_rx_status
-			if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x01000000)
-				skb->ip_summed = CHECKSUM_UNNECESSARY;
+			pci_unmap_single(np->pci_dev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			skb = np->rx_info[entry].skb;
+			temp = skb_put(skb, pkt_len);
+			np->rx_info[entry].skb = NULL;
+			np->rx_info[entry].mapping = 0;
+		}
+#ifndef final_version			/* Remove after testing. */
+		/* You will want this info for the initial debug. */
+		if (debug > 5)
+			printk(KERN_DEBUG "  Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
+			       "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
+			       "%d.%d.%d.%d.\n",
+			       skb->data[0], skb->data[1], skb->data[2], skb->data[3],
+			       skb->data[4], skb->data[5], skb->data[6], skb->data[7],
+			       skb->data[8], skb->data[9], skb->data[10],
+			       skb->data[11], skb->data[12], skb->data[13],
+			       skb->data[14], skb->data[15], skb->data[16],
+			       skb->data[17]);
 #endif
-			netif_rx(skb);
-			dev->last_rx = jiffies;
-			np->stats.rx_packets++;
+		skb->protocol = eth_type_trans(skb, dev);
+#if defined(full_rx_status) || defined(csum_rx_status)
+		if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x01000000) {
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		}
+		/*
+		 * This feature doesn't seem to be working, at least
+		 * with the two firmware versions I have. If the GFP sees
+		 * a fragment, it either ignores it completely, or reports
+		 * "bad checksum" on it.
+		 *
+		 * Maybe I missed something -- corrections are welcome.
+		 * Until then, the printk stays. :-) -Ion
+		 */
+		else if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x00400000) {
+			skb->ip_summed = CHECKSUM_HW;
+			skb->csum = le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0xffff;
+			printk(KERN_DEBUG "%s: checksum_hw, status2 = %x\n", dev->name, np->rx_done_q[np->rx_done].status2);
 		}
+#endif
+		netif_rx(skb);
+		dev->last_rx = jiffies;
+		np->stats.rx_packets++;
+
+next_rx:
 		np->cur_rx++;
 		np->rx_done_q[np->rx_done].status = 0;
 		np->rx_done = (np->rx_done + 1) & (DONE_Q_SIZE-1);
@@ -1083,10 +1466,10 @@
 			skb = dev_alloc_skb(np->rx_buf_sz);
 			np->rx_info[entry].skb = skb;
 			if (skb == NULL)
-				break;			/* Better luck next round. */
+				break;	/* Better luck next round. */
 			np->rx_info[entry].mapping =
 				pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
-			skb->dev = dev;			/* Mark as being used by this device. */
+			skb->dev = dev;	/* Mark as being used by this device. */
 			np->rx_ring[entry].rxaddr =
 				cpu_to_le32(np->rx_info[entry].mapping | RxDescValid);
 		}
@@ -1096,42 +1479,94 @@
 		writew(entry, dev->base_addr + RxDescQIdx);
 	}
 
-	if (debug > 5
-		|| memcmp(np->pad0, np->pad0 + 1, sizeof(np->pad0) -1))
-		printk(KERN_DEBUG "  exiting netdev_rx() status of %d was %8.8x %d.\n",
-			   np->rx_done, desc_status,
-			   memcmp(np->pad0, np->pad0 + 1, sizeof(np->pad0) -1));
+	if (debug > 5)
+		printk(KERN_DEBUG "  exiting netdev_rx() status of %d was %8.8x.\n",
+		       np->rx_done, desc_status);
 
 	/* Restart Rx engine if stopped. */
 	return 0;
 }
 
-static void netdev_error(struct net_device *dev, int intr_status)
+
+static void netdev_media_change(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+	u16 reg0, reg1, reg4, reg5;
+	u32 new_tx_mode;
 
-	if (intr_status & LinkChange) {
-		printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising"
-			   " %4.4x  partner %4.4x.\n", dev->name,
-			   mdio_read(dev, np->phys[0], 4),
-			   mdio_read(dev, np->phys[0], 5));
-		check_duplex(dev, 0);
-	}
-	if (intr_status & StatsMax) {
-		get_stats(dev);
+	/* reset status first */
+	mdio_read(dev, np->phys[0], MII_BMCR);
+	mdio_read(dev, np->phys[0], MII_BMSR);
+
+	reg0 = mdio_read(dev, np->phys[0], MII_BMCR);
+	reg1 = mdio_read(dev, np->phys[0], MII_BMSR);
+
+	if (reg1 & BMSR_LSTATUS) {
+		/* link is up */
+		if (reg0 & BMCR_ANENABLE) {
+			/* autonegotiation is enabled */
+			reg4 = mdio_read(dev, np->phys[0], MII_ADVERTISE);
+			reg5 = mdio_read(dev, np->phys[0], MII_LPA);
+			if (reg4 & ADVERTISE_100FULL && reg5 & LPA_100FULL) {
+				np->speed100 = 1;
+				np->full_duplex = 1;
+			} else if (reg4 & ADVERTISE_100HALF && reg5 & LPA_100HALF) {
+				np->speed100 = 1;
+				np->full_duplex = 0;
+			} else if (reg4 & ADVERTISE_10FULL && reg5 & LPA_10FULL) {
+				np->speed100 = 0;
+				np->full_duplex = 1;
+			} else {
+				np->speed100 = 0;
+				np->full_duplex = 0;
+			}
+		} else {
+			/* autonegotiation is disabled */
+			if (reg0 & BMCR_SPEED100)
+				np->speed100 = 1;
+			else
+				np->speed100 = 0;
+			if (reg0 & BMCR_FULLDPLX)
+				np->full_duplex = 1;
+			else
+				np->full_duplex = 0;
+		}
+		printk(KERN_DEBUG "%s: Link is up, running at %sMbit %s-duplex\n",
+		       dev->name,
+		       np->speed100 ? "100" : "10",
+		       np->full_duplex ? "full" : "half");
+
+		new_tx_mode = np->tx_mode & ~0x2;	/* duplex setting */
+		if (np->full_duplex)
+			new_tx_mode |= 2;
+		if (np->tx_mode != new_tx_mode) {
+			np->tx_mode = new_tx_mode;
+			writel(np->tx_mode | 0x8000, ioaddr + TxMode);
+			writel(np->tx_mode, ioaddr + TxMode);
+		}
+	} else {
+		printk(KERN_DEBUG "%s: Link is down\n", dev->name);
 	}
+}
+
+
+static void netdev_error(struct net_device *dev, int intr_status)
+{
+	struct netdev_private *np = dev->priv;
+
 	/* Came close to underrunning the Tx FIFO, increase threshold. */
-	if (intr_status & IntrTxDataLow)
+	if (intr_status & IntrTxDataLow) {
 		writel(++np->tx_threshold, dev->base_addr + TxThreshold);
-	if ((intr_status &
-		 ~(IntrAbnormalSummary|LinkChange|StatsMax|IntrTxDataLow|1)) && debug)
+		printk(KERN_NOTICE "%s: Increasing Tx FIFO threshold to %d bytes\n",
+		       dev->name, np->tx_threshold * 16);
+	}
+	if ((intr_status & ~(IntrNormalMask | IntrAbnormalSummary | IntrLinkChange | IntrStatsMax | IntrTxDataLow | IntrPCIPad)) && debug)
 		printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
-			   dev->name, intr_status);
-	/* Hmmmmm, it's not clear how to recover from PCI faults. */
-	if (intr_status & IntrTxPCIErr)
+		       dev->name, intr_status);
+	/* Hmmmmm, it's not clear how to recover from DMA faults. */
+	if (intr_status & IntrDMAErr)
 		np->stats.tx_fifo_errors++;
-	if (intr_status & IntrRxPCIErr)
-		np->stats.rx_fifo_errors++;
 }
 
 static struct net_device_stats *get_stats(struct net_device *dev)
@@ -1146,12 +1581,13 @@
 	np->stats.tx_aborted_errors =
 		readl(ioaddr + 0x57024) + readl(ioaddr + 0x57028);
 	np->stats.tx_window_errors = readl(ioaddr + 0x57018);
-	np->stats.collisions = readl(ioaddr + 0x57004) + readl(ioaddr + 0x57008);
+	np->stats.collisions =
+		readl(ioaddr + 0x57004) + readl(ioaddr + 0x57008);
 
 	/* The chip only need report frame silently dropped. */
-	np->stats.rx_dropped	   += readw(ioaddr + RxDMAStatus);
+	np->stats.rx_dropped += readw(ioaddr + RxDMAStatus);
 	writew(0, ioaddr + RxDMAStatus);
-	np->stats.rx_crc_errors	   = readl(ioaddr + 0x5703C);
+	np->stats.rx_crc_errors = readl(ioaddr + 0x5703C);
 	np->stats.rx_frame_errors = readl(ioaddr + 0x57040);
 	np->stats.rx_length_errors = readl(ioaddr + 0x57058);
 	np->stats.rx_missed_errors = readl(ioaddr + 0x5707C);
@@ -1192,19 +1628,17 @@
 	struct dev_mc_list *mclist;
 	int i;
 
-	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
-		/* Unconditionally log net taps. */
-		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+	if (dev->flags & IFF_PROMISC) {	/* Set promiscuous. */
 		rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptAll|AcceptMyPhys;
 	} else if ((dev->mc_count > multicast_filter_limit)
-			   ||  (dev->flags & IFF_ALLMULTI)) {
+		   || (dev->flags & IFF_ALLMULTI)) {
 		/* Too many to match, or accept all multicasts. */
 		rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys;
 	} else if (dev->mc_count <= 15) {
-		/* Use the 16 element perfect filter. */
-		long filter_addr = ioaddr + 0x56000 + 1*16;
-		for (i = 1, mclist = dev->mc_list; mclist  &&  i <= dev->mc_count;
-			 i++, mclist = mclist->next) {
+		/* Use the 16 element perfect filter, skip first entry. */
+		long filter_addr = ioaddr + PerfFilterTable + 1 * 16;
+		for (i = 1, mclist = dev->mc_list; mclist && i <= dev->mc_count;
+		     i++, mclist = mclist->next) {
 			u16 *eaddrs = (u16 *)mclist->dmi_addr;
 			writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4;
 			writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;
@@ -1224,7 +1658,10 @@
 		memset(mc_filter, 0, sizeof(mc_filter));
 		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
 			 i++, mclist = mclist->next) {
-			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23, mc_filter);
+			int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23;
+			__u32 *fptr = (__u32 *) &mc_filter[(bit_nr >> 4) & ~1];
+
+			*fptr |= cpu_to_le32(1 << (bit_nr & 31));
 		}
 		/* Clear the perfect filter list. */
 		filter_addr = ioaddr + 0x56000 + 1*16;
@@ -1260,15 +1697,17 @@
 			switch (data[1]) {
 			case 0:
 				if (value & 0x9000)	/* Autonegotiation. */
-					np->medialock = 0;
+					np->autoneg = 1;
 				else {
 					np->full_duplex = (value & 0x0100) ? 1 : 0;
-					np->medialock = 1;
+					np->autoneg = 0;
 				}
 				break;
-			case 4: np->advertising = value; break;
+			case 4:
+				np->advertising = value;
+				break;
 			}
-			check_duplex(dev, 0);
+			check_duplex(dev);
 		}
 		mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
 		return 0;
@@ -1284,8 +1723,7 @@
 	int i;
 
 	netif_stop_queue(dev);
-
-	del_timer_sync(&np->timer);
+	netif_stop_if(dev);
 
 	if (debug > 1) {
 		printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %4.4x.\n",
@@ -1305,15 +1743,15 @@
 			   np->tx_ring_dma);
 		for (i = 0; i < 8 /* TX_RING_SIZE is huge! */; i++)
 			printk(KERN_DEBUG " #%d desc. %8.8x %8.8x -> %8.8x.\n",
-				   i, le32_to_cpu(np->tx_ring[i].status),
-				   le32_to_cpu(np->tx_ring[i].addr),
-				   le32_to_cpu(np->tx_done_q[i].status));
+			       i, le32_to_cpu(np->tx_ring[i].status),
+			       le32_to_cpu(np->tx_ring[i].first_addr),
+			       le32_to_cpu(np->tx_done_q[i].status));
 		printk(KERN_DEBUG "  Rx ring at %8.8x -> %p:\n",
-			   np->rx_ring_dma, np->rx_done_q);
+		       np->rx_ring_dma, np->rx_done_q);
 		if (np->rx_done_q)
 			for (i = 0; i < 8 /* RX_RING_SIZE */; i++) {
 				printk(KERN_DEBUG " #%d desc. %8.8x -> %8.8x\n",
-					   i, le32_to_cpu(np->rx_ring[i].rxaddr), le32_to_cpu(np->rx_done_q[i].status));
+				       i, le32_to_cpu(np->rx_ring[i].rxaddr), le32_to_cpu(np->rx_done_q[i].status));
 		}
 	}
 #endif /* __i386__ debugging only */
@@ -1332,16 +1770,32 @@
 	}
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		struct sk_buff *skb = np->tx_info[i].skb;
-		if (skb != NULL) {
-			pci_unmap_single(np->pci_dev,
-					 np->tx_info[i].mapping,
-					 skb->len, PCI_DMA_TODEVICE);
-			dev_kfree_skb(skb);
-		}
+#ifdef ZEROCOPY
+		int j;
+#endif /* ZEROCOPY */
+		if (skb == NULL)
+			continue;
+		pci_unmap_single(np->pci_dev,
+				 np->tx_info[i].first_mapping,
+				 skb_first_frag_len(skb), PCI_DMA_TODEVICE);
+		np->tx_info[i].first_mapping = 0;
+		dev_kfree_skb(skb);
 		np->tx_info[i].skb = NULL;
-		np->tx_info[i].mapping = 0;
+#ifdef ZEROCOPY
+		for (j = 0; j < MAX_STARFIRE_FRAGS; j++)
+			if (np->tx_info[i].frag_mapping[j]) {
+				pci_unmap_single(np->pci_dev,
+						 np->tx_info[i].frag_mapping[j],
+						 skb_shinfo(skb)->frags[j].size,
+						 PCI_DMA_TODEVICE);
+				np->tx_info[i].frag_mapping[j] = 0;
+			} else
+				break;
+#endif /* ZEROCOPY */
 	}
 
+	COMPAT_MOD_DEC_USE_COUNT;
+
 	return 0;
 }
 
@@ -1350,7 +1804,7 @@
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct netdev_private *np;
-	
+
 	if (!dev)
 		BUG();
 
@@ -1358,7 +1812,7 @@
 
 	unregister_netdev(dev);
 	iounmap((char *)dev->base_addr);
-	pci_release_regions (pdev);
+	pci_release_regions(pdev);
 
 	if (np->tx_done_q)
 		pci_free_consistent(np->pci_dev, PAGE_SIZE,
@@ -1380,7 +1834,7 @@
 
 
 static struct pci_driver starfire_driver = {
-	name:		"starfire",
+	name:		DRV_NAME,
 	probe:		starfire_init_one,
 	remove:		starfire_remove_one,
 	id_table:	starfire_pci_tbl,
@@ -1409,10 +1863,9 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c starfire.c"
- *  simple-compile-command: "gcc -DMODULE -O6 -c starfire.c"
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
+ *  compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O2 -c starfire.c"
+ *  simple-compile-command: "gcc -DMODULE -O2 -c starfire.c"
+ *  c-basic-offset: 8
+ *  tab-width: 8
  * End:
  */
diff -u --recursive --new-file v2.4.5/linux/drivers/net/sun3lance.c linux/drivers/net/sun3lance.c
--- v2.4.5/linux/drivers/net/sun3lance.c	Wed Apr 18 14:40:04 2001
+++ linux/drivers/net/sun3lance.c	Wed Jun 20 11:10:53 2001
@@ -70,6 +70,7 @@
 static int lance_debug = 1;
 #endif
 MODULE_PARM(lance_debug, "i");
+MODULE_PARM_DESC(lance_debug, "SUN3 Lance debug level (0-3)");
 
 #define	DPRINTK(n,a) \
 	do {  \
diff -u --recursive --new-file v2.4.5/linux/drivers/net/sundance.c linux/drivers/net/sundance.c
--- v2.4.5/linux/drivers/net/sundance.c	Fri Apr 20 11:54:22 2001
+++ linux/drivers/net/sundance.c	Wed Jun 20 11:13:18 2001
@@ -18,6 +18,11 @@
 	http://www.scyld.com/network/sundance.html
 */
 
+#define DRV_NAME	"sundance"
+#define DRV_VERSION	"1.01"
+#define DRV_RELDATE	"4/09/00"
+
+
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
@@ -85,6 +90,8 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/init.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -93,7 +100,7 @@
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
-KERN_INFO "sundance.c:v1.01 4/09/00  Written by Donald Becker\n"
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "  Written by Donald Becker\n"
 KERN_INFO "  http://www.scyld.com/network/sundance.html\n";
 
 /* Condensed operations for readability. */
@@ -109,6 +116,12 @@
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM_DESC(max_interrupt_work, "Sundance Alta maximum events handled per interrupt");
+MODULE_PARM_DESC(mtu, "Sundance Alta MTU (all boards)");
+MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)");
+MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(options, "Sundance Alta: Bits 0-3: media type, bit 17: full duplex");
+MODULE_PARM_DESC(full_duplex, "Sundance Alta full duplex setting(s) (1)");
 
 /*
 				Theory of Operation
@@ -346,6 +359,7 @@
 	int mii_cnt;						/* MII device addresses. */
 	u16 advertising;					/* NWay media advertisement */
 	unsigned char phys[MII_CNT];		/* MII device addresses, only first one used. */
+	struct pci_dev *pci_dev;
 };
 
 /* The station address location in the EEPROM. */
@@ -366,7 +380,7 @@
 static void netdev_error(struct net_device *dev, int intr_status);
 static void set_rx_mode(struct net_device *dev);
 static struct net_device_stats *get_stats(struct net_device *dev);
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int  netdev_close(struct net_device *dev);
 
 
@@ -400,7 +414,7 @@
 		return -ENOMEM;
 	SET_MODULE_OWNER(dev);
 
-	if (pci_request_regions(pdev, "sundance"))
+	if (pci_request_regions(pdev, DRV_NAME))
 		goto err_out_netdev;
 
 #ifdef USE_IO_OPS
@@ -422,6 +436,7 @@
 	np = dev->priv;
 	np->chip_id = chip_idx;
 	np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
+	np->pci_dev = pdev;
 	spin_lock_init(&np->lock);
 
 	if (dev->mem_start)
@@ -447,7 +462,7 @@
 	dev->stop = &netdev_close;
 	dev->get_stats = &get_stats;
 	dev->set_multicast_list = &set_rx_mode;
-	dev->do_ioctl = &mii_ioctl;
+	dev->do_ioctl = &netdev_ioctl;
 	dev->tx_timeout = &tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	pci_set_drvdata(pdev, dev);
@@ -1156,11 +1171,37 @@
 	writeb(rx_mode, ioaddr + RxMode);
 }
 
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct netdev_private *np = dev->priv;
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+
+        switch (ethcmd) {
+        case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strcpy(info.driver, DRV_NAME);
+		strcpy(info.version, DRV_VERSION);
+		strcpy(info.bus_info, np->pci_dev->slot_name);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+
+        }
+	
+	return -EOPNOTSUPP;
+}
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	u16 *data = (u16 *)&rq->ifr_data;
 
 	switch(cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 		data[0] = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f;
 		/* Fall Through */
@@ -1258,7 +1299,7 @@
 }
 
 static struct pci_driver sundance_driver = {
-	name:		"sundance",
+	name:		DRV_NAME,
 	id_table:	sundance_pci_tbl,
 	probe:		sundance_probe1,
 	remove:		sundance_remove1,
diff -u --recursive --new-file v2.4.5/linux/drivers/net/sungem.c linux/drivers/net/sungem.c
--- v2.4.5/linux/drivers/net/sungem.c	Thu Apr 26 22:17:25 2001
+++ linux/drivers/net/sungem.c	Wed Jun 20 11:13:18 2001
@@ -49,6 +49,7 @@
 MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
 MODULE_DESCRIPTION("Sun GEM Gbit ethernet driver");
 MODULE_PARM(gem_debug, "i");
+MODULE_PARM_DESC(gem_debug, "(ignored)");
 
 #define GEM_MODULE_NAME	"gem"
 #define PFX GEM_MODULE_NAME ": "
@@ -1732,14 +1733,6 @@
 
 }
 
-static void gem_suspend(struct pci_dev *pdev)
-{
-}
-
-static void gem_resume(struct pci_dev *pdev)
-{
-}
-
 static void __devexit gem_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
@@ -1767,8 +1760,6 @@
 	id_table:	gem_pci_tbl,
 	probe:		gem_init_one,
 	remove:		gem_remove_one,
-	suspend:	gem_suspend,
-	resume:		gem_resume,
 };
 
 static int __init gem_init(void)
diff -u --recursive --new-file v2.4.5/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.4.5/linux/drivers/net/sunhme.c	Sun May 20 11:32:07 2001
+++ linux/drivers/net/sunhme.c	Wed Jun 20 11:10:53 2001
@@ -72,6 +72,7 @@
 
 /* accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */
 MODULE_PARM(macaddr, "6i");
+MODULE_PARM_DESC(macaddr, "Happy Meal MAC address to set");
 
 static struct happy_meal *root_happy_dev;
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/tlan.c linux/drivers/net/tlan.c
--- v2.4.5/linux/drivers/net/tlan.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/tlan.c	Wed Jun 20 11:13:18 2001
@@ -194,6 +194,11 @@
 MODULE_PARM(speed, "1-" __MODULE_STRING(MAX_TLAN_BOARDS) "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(bbuf, "i");
+MODULE_PARM_DESC(aui, "ThunderLAN use AUI port(s) (0-1)");
+MODULE_PARM_DESC(duplex, "ThunderLAN duplex setting(s) (0-default, 1-half, 2-full)");
+MODULE_PARM_DESC(speed, "ThunderLAN port speen setting(s) (0,10,100)");
+MODULE_PARM_DESC(debug, "ThunderLAN debug mask");
+MODULE_PARM_DESC(bbuf, "ThunderLAN use big buffer (0-1)");
 EXPORT_NO_SYMBOLS;
 
 /* Define this to enable Link beat monitoring */
@@ -917,13 +922,13 @@
 			data[0] = phy;
 
 		case SIOCDEVPRIVATE+1: /* Read MII register */
-			TLan_MiiReadReg(dev, data[0], data[1], &data[3]);
+			TLan_MiiReadReg(dev, data[0] & 0x1f, data[1] & 0x1f, &data[3]);
 			return 0;
 		
 		case SIOCDEVPRIVATE+2: /* Write MII register */
 			if (!capable(CAP_NET_ADMIN))
 				return -EPERM;
-			TLan_MiiWriteReg(dev, data[0], data[1], data[2]);
+			TLan_MiiWriteReg(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
 			return 0;
 		default:
 			return -EOPNOTSUPP;
diff -u --recursive --new-file v2.4.5/linux/drivers/net/tokenring/ibmtr.c linux/drivers/net/tokenring/ibmtr.c
--- v2.4.5/linux/drivers/net/tokenring/ibmtr.c	Tue Mar 20 12:05:00 2001
+++ linux/drivers/net/tokenring/ibmtr.c	Tue Jun 12 11:06:54 2001
@@ -1185,7 +1185,7 @@
 				isa_writeb(~CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD);
 				isa_writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
 
-			  skip_reset:
+			  skip_reset:;
 			} /* SRB response */
 
 			if (status & ASB_FREE_INT) { /* ASB response */
diff -u --recursive --new-file v2.4.5/linux/drivers/net/tokenring/lanstreamer.c linux/drivers/net/tokenring/lanstreamer.c
--- v2.4.5/linux/drivers/net/tokenring/lanstreamer.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/tokenring/lanstreamer.c	Wed Jun 20 11:13:18 2001
@@ -1808,25 +1808,11 @@
 #endif
 #endif
 
-static void streamer_suspend(struct pci_dev *pdev) {
-#if STREAMER_DEBUG
-  printk("lanstreamer::streamer_suspend entry pdev %p\n",pdev);
-#endif
-}
-
-static void streamer_resume(struct pci_dev *pdev) {
-#if STREAMER_DEBUG
-  printk("lanstreamer::streamer_resume entry pdev %p\n",pdev);
-#endif
-}
-
 static struct pci_driver streamer_pci_driver = {
   name:       "lanstreamer",
   id_table:   streamer_pci_tbl,
   probe:      streamer_init_one,
   remove:     streamer_remove_one,
-  suspend:    streamer_suspend,
-  resume:     streamer_resume,
 };
 
 static int __init streamer_init_module(void) {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/tokenring/olympic.c linux/drivers/net/tokenring/olympic.c
--- v2.4.5/linux/drivers/net/tokenring/olympic.c	Sun May 20 12:11:38 2001
+++ linux/drivers/net/tokenring/olympic.c	Wed Jun 20 11:13:18 2001
@@ -49,6 +49,8 @@
  * 04/09/01 - Couple of bug fixes to the dma unmaps and ejecting the
  *	      adapter when live does not take the system down with it.
  * 
+ * 06/02/01 - Clean up, copy skb for small packets
+ *
  *  To Do:
  *
  *	     Complete full Cardbus / hot-swap support.
@@ -64,7 +66,10 @@
 
 #define OLYMPIC_DEBUG 0
 
+
+#include <linux/config.h>
 #include <linux/module.h>
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
@@ -99,8 +104,8 @@
  * Official releases will only have an a.b.c version number format. 
  */
 
-static char *version = 
-"Olympic.c v0.9.C 4/18/01 - Peter De Schrijver & Mike Phillips" ; 
+static char version[] __devinitdata = 
+"Olympic.c v0.9.7 6/02/01 - Peter De Schrijver & Mike Phillips" ; 
 
 static char *open_maj_error[]  = {"No error", "Lobe Media Test", "Physical Insertion",
 				   "Address Verification", "Neighbor Notification (Ring Poll)",
@@ -116,6 +121,9 @@
 
 /* Module paramters */
 
+MODULE_AUTHOR("Mike Phillips <mikep@linuxtr.net>") ; 
+MODULE_DESCRIPTION("Olympic PCI/Cardbus Chipset Driver \n") ; 
+
 /* Ring Speed 0,4,16,100 
  * 0 = Autosense         
  * 4,16 = Selected speed only, no autosense
@@ -157,7 +165,8 @@
 };
 MODULE_DEVICE_TABLE(pci,olympic_pci_tbl) ; 
 
-static int __init olympic_probe(struct pci_dev *pdev, const struct pci_device_id *ent); 
+
+static int olympic_probe(struct pci_dev *pdev, const struct pci_device_id *ent); 
 static int olympic_init(struct net_device *dev);
 static int olympic_open(struct net_device *dev);
 static int olympic_xmit(struct sk_buff *skb, struct net_device *dev);
@@ -172,7 +181,7 @@
 static void olympic_asb_bh(struct net_device *dev) ; 
 static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) ; 
 
-static int __init olympic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	struct net_device *dev ; 
 	struct olympic_private *olympic_priv;
@@ -239,6 +248,7 @@
 	dev->set_multicast_list=&olympic_set_rx_mode;
 	dev->get_stats=&olympic_get_stats ;
 	dev->set_mac_address=&olympic_set_mac_address ;  
+	SET_MODULE_OWNER(dev) ; 
 
 	pci_set_drvdata(pdev,dev) ; 
 	register_netdev(dev) ; 
@@ -253,10 +263,10 @@
 	return  0 ;
 }
 
-static int __init olympic_init(struct net_device *dev)
+static int __devinit olympic_init(struct net_device *dev)
 {
     	struct olympic_private *olympic_priv;
-	__u8 *olympic_mmio, *init_srb,*adapter_addr;
+	u8 *olympic_mmio, *init_srb,*adapter_addr;
 	unsigned long t; 
 	unsigned int uaa_addr;
 
@@ -268,7 +278,7 @@
 
 	writel(readl(olympic_mmio+BCTL) | BCTL_SOFTRESET,olympic_mmio+BCTL);
 	t=jiffies;
-	while((readl(olympic_priv->olympic_mmio+BCTL)) & BCTL_SOFTRESET) {
+	while((readl(olympic_mmio+BCTL)) & BCTL_SOFTRESET) {
 		schedule();		
 		if(jiffies-t > 40*HZ) {
 			printk(KERN_ERR "IBM PCI tokenring card not responding.\n");
@@ -381,7 +391,7 @@
 static int olympic_open(struct net_device *dev) 
 {
 	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
-	__u8 *olympic_mmio=olympic_priv->olympic_mmio,*init_srb;
+	u8 *olympic_mmio=olympic_priv->olympic_mmio,*init_srb;
 	unsigned long flags, t;
 	char open_error[255] ; 
 	int i, open_finished = 1 ;
@@ -632,10 +642,10 @@
 #endif
 
 	if (olympic_priv->olympic_network_monitor) { 
-		__u8 *oat ; 
-		__u8 *opt ; 
-		oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
-		opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
+		u8 *oat ; 
+		u8 *opt ; 
+		oat = (u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
+		opt = (u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
 
 		printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, 
 			readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), 
@@ -659,7 +669,6 @@
 	}
 	
 	netif_start_queue(dev);
-	MOD_INC_USE_COUNT ;
 	return 0;
 	
 }	
@@ -673,12 +682,16 @@
  *	This means that we may process the frame before we receive the end
  *	of frame interrupt. This is why we always test the status instead
  *	of blindly processing the next frame.
+ *
+ *	We also remove the last 4 bytes from the packet as well, these are
+ *	just token ring trailer info and upset protocols that don't check 
+ *	their own length, i.e. SNA. 
  *	
  */
 static void olympic_rx(struct net_device *dev)
 {
 	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
-	__u8 *olympic_mmio=olympic_priv->olympic_mmio;
+	u8 *olympic_mmio=olympic_priv->olympic_mmio;
 	struct olympic_rx_status *rx_status;
 	struct olympic_rx_desc *rx_desc ; 
 	int rx_ring_last_received,length, buffer_cnt, cpy_length, frag_len;
@@ -688,7 +701,7 @@
 	rx_status=&(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received + 1) & (OLYMPIC_RX_RING_SIZE - 1)]) ; 
  
 	while (rx_status->status_buffercnt) { 
-                __u32 l_status_buffercnt;
+                u32 l_status_buffercnt;
 
 		olympic_priv->rx_status_last_received++ ;
 		olympic_priv->rx_status_last_received &= (OLYMPIC_RX_RING_SIZE -1);
@@ -742,36 +755,50 @@
 			   	   	   If only one buffer is used we can simply swap the buffers around.
 			   	   	   If more than one then we must use the new buffer and copy the information
 			   	   	   first. Ideally all frames would be in a single buffer, this can be tuned by
-                               	   	   altering the buffer size. */
+                               	   	   altering the buffer size. If the length of the packet is less than
+					   1500 bytes we're going to copy it over anyway to stop packets getting
+					   dropped from sockets with buffers small than our pkt_buf_sz. */
 				
  					if (buffer_cnt==1) {
 						olympic_priv->rx_ring_last_received++ ; 
 						olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1);
 						rx_ring_last_received = olympic_priv->rx_ring_last_received ;
-						skb2=olympic_priv->rx_ring_skb[rx_ring_last_received] ; 
-						/* unmap buffer */
-						pci_unmap_single(olympic_priv->pdev,
-							le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), 
-							olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; 
-						skb_put(skb2,length);
-						skb2->protocol = tr_type_trans(skb2,dev);
-						olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer = 
-							cpu_to_le32(pci_map_single(olympic_priv->pdev, skb->data, 
-							olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE));
-						olympic_priv->olympic_rx_ring[rx_ring_last_received].res_length = 
-							cpu_to_le32(olympic_priv->pkt_buf_sz); 
-						olympic_priv->rx_ring_skb[rx_ring_last_received] = skb ; 
-						netif_rx(skb2) ; 
+						if (length > 1500) { 
+							skb2=olympic_priv->rx_ring_skb[rx_ring_last_received] ; 
+							/* unmap buffer */
+							pci_unmap_single(olympic_priv->pdev,
+								le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), 
+								olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; 
+							skb_put(skb2,length-4);
+							skb2->protocol = tr_type_trans(skb2,dev);
+							olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer = 
+								cpu_to_le32(pci_map_single(olympic_priv->pdev, skb->data, 
+								olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE));
+							olympic_priv->olympic_rx_ring[rx_ring_last_received].res_length = 
+								cpu_to_le32(olympic_priv->pkt_buf_sz); 
+							olympic_priv->rx_ring_skb[rx_ring_last_received] = skb ; 
+							netif_rx(skb2) ; 
+						} else { 
+							pci_dma_sync_single(olympic_priv->pdev,
+								le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer),
+								olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; 
+							memcpy(skb_put(skb,length-4),olympic_priv->rx_ring_skb[rx_ring_last_received]->data,length-4) ; 
+							skb->protocol = tr_type_trans(skb,dev) ; 
+							netif_rx(skb) ; 
+						} 
 					} else {
 						do { /* Walk the buffers */ 
 							olympic_priv->rx_ring_last_received++ ; 
 							olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1);
 							rx_ring_last_received = olympic_priv->rx_ring_last_received ; 
+							pci_dma_sync_single(olympic_priv->pdev,
+								le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer),
+								olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; 
 							rx_desc = &(olympic_priv->olympic_rx_ring[rx_ring_last_received]);
 							cpy_length = (i == 1 ? frag_len : le32_to_cpu(rx_desc->res_length)); 
 							memcpy(skb_put(skb, cpy_length), olympic_priv->rx_ring_skb[rx_ring_last_received]->data, cpy_length) ;
 						} while (--i) ; 
-		
+						skb_trim(skb,skb->len-4) ; 
 						skb->protocol = tr_type_trans(skb,dev);
 						netif_rx(skb) ; 
 					} 
@@ -799,9 +826,9 @@
 {
 	struct net_device *dev= (struct net_device *)dev_id;
 	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
-	__u8 *olympic_mmio=olympic_priv->olympic_mmio;
-	__u32 sisr;
-	__u8 *adapter_check_area ; 
+	u8 *olympic_mmio=olympic_priv->olympic_mmio;
+	u32 sisr;
+	u8 *adapter_check_area ; 
 	
 	/* 
 	 *  Read sisr but don't reset it yet. 
@@ -855,7 +882,7 @@
 			netif_stop_queue(dev);
 			printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name);
 			writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
-			adapter_check_area = (__u8 *)(olympic_mmio+LAPWWO) ; 
+			adapter_check_area = (u8 *)(olympic_mmio+LAPWWO) ; 
 			printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ; 
 			/* The adapter is effectively dead, clean up and exit */
 			for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
@@ -880,7 +907,6 @@
 				sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE, PCI_DMA_TODEVICE);
 
 			free_irq(dev->irq, dev) ;
-			MOD_DEC_USE_COUNT ;
 			dev->stop = NULL ;  
 			spin_unlock(&olympic_priv->olympic_lock) ; 
 			return ; 
@@ -921,7 +947,7 @@
 static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) 
 {
 	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
-	__u8 *olympic_mmio=olympic_priv->olympic_mmio;
+	u8 *olympic_mmio=olympic_priv->olympic_mmio;
 	unsigned long flags ; 
 
 	spin_lock_irqsave(&olympic_priv->olympic_lock, flags);
@@ -952,7 +978,7 @@
 static int olympic_close(struct net_device *dev) 
 {
 	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
-    	__u8 *olympic_mmio=olympic_priv->olympic_mmio,*srb;
+    	u8 *olympic_mmio=olympic_priv->olympic_mmio,*srb;
 	unsigned long t,flags;
 	int i;
 
@@ -1027,7 +1053,6 @@
 #endif
 	free_irq(dev->irq,dev);
 
-	MOD_DEC_USE_COUNT ; 
 	return 0;
 	
 }
@@ -1035,9 +1060,9 @@
 static void olympic_set_rx_mode(struct net_device *dev) 
 {
 	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
-   	__u8 *olympic_mmio = olympic_priv->olympic_mmio ; 
-	__u8 options = 0; 
-	__u8 *srb;
+   	u8 *olympic_mmio = olympic_priv->olympic_mmio ; 
+	u8 options = 0; 
+	u8 *srb;
 	struct dev_mc_list *dmi ; 
 	unsigned char dev_mc_address[4] ; 
 	int i ; 
@@ -1103,8 +1128,8 @@
 static void olympic_srb_bh(struct net_device *dev) 
 { 
 	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
-   	__u8 *olympic_mmio = olympic_priv->olympic_mmio ; 
-	__u8 *srb;
+   	u8 *olympic_mmio = olympic_priv->olympic_mmio ; 
+	u8 *srb;
 
 	writel(olympic_priv->srb,olympic_mmio+LAPA);
 	srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
@@ -1277,22 +1302,22 @@
 static void olympic_arb_cmd(struct net_device *dev)
 {
 	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv;
-    	__u8 *olympic_mmio=olympic_priv->olympic_mmio;
-	__u8 *arb_block, *asb_block, *srb  ; 
-	__u8 header_len ; 
-	__u16 frame_len, buffer_len ;
+    	u8 *olympic_mmio=olympic_priv->olympic_mmio;
+	u8 *arb_block, *asb_block, *srb  ; 
+	u8 header_len ; 
+	u16 frame_len, buffer_len ;
 	struct sk_buff *mac_frame ;  
-	__u8 *buf_ptr ;
-	__u8 *frame_data ;  
-	__u16 buff_off ; 
-	__u16 lan_status = 0, lan_status_diff  ; /* Initialize to stop compiler warning */
-	__u8 fdx_prot_error ; 
-	__u16 next_ptr;
+	u8 *buf_ptr ;
+	u8 *frame_data ;  
+	u16 buff_off ; 
+	u16 lan_status = 0, lan_status_diff  ; /* Initialize to stop compiler warning */
+	u8 fdx_prot_error ; 
+	u16 next_ptr;
 	int i ; 
 
-	arb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; 
-	asb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; 
-	srb = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->srb) ; 
+	arb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; 
+	asb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; 
+	srb = (u8 *)(olympic_priv->olympic_lap + olympic_priv->srb) ; 
 	writel(readl(olympic_mmio+LAPA),olympic_mmio+LAPWWO);
 
 	if (readb(arb_block+0) == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */
@@ -1421,7 +1446,6 @@
 			free_irq(dev->irq,dev);
 			dev->stop=NULL;
 			printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name) ; 
-			MOD_DEC_USE_COUNT ; 
 		} /* If serious error */
 		
 		if (olympic_priv->olympic_message_level) { 
@@ -1489,10 +1513,10 @@
 static void olympic_asb_bh(struct net_device *dev) 
 {
 	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
-	__u8 *arb_block, *asb_block ; 
+	u8 *arb_block, *asb_block ; 
 
-	arb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; 
-	asb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; 
+	arb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; 
+	asb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; 
 
 	if (olympic_priv->asb_queued == 1) {   /* Dropped through the first time */
 
@@ -1529,7 +1553,7 @@
 static int olympic_change_mtu(struct net_device *dev, int mtu) 
 {
 	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv;
-	__u16 max_mtu ; 
+	u16 max_mtu ; 
 
 	if (olympic_priv->olympic_ring_speed == 4)
 		max_mtu = 4500 ; 
@@ -1551,8 +1575,8 @@
 {
 	struct net_device *dev = (struct net_device *)data ; 
 	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
-	__u8 *oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
-	__u8 *opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
+	u8 *oat = (u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
+	u8 *opt = (u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
 	int size = 0 ; 
 	int len=0;
 	off_t begin=0;
@@ -1672,7 +1696,8 @@
 	unregister_trdev(dev) ; 
 	iounmap(olympic_priv->olympic_mmio) ; 
 	iounmap(olympic_priv->olympic_lap) ; 
-	pci_release_regions(pdev) ; 	
+	pci_release_regions(pdev) ;
+	pci_set_drvdata(pdev,NULL) ;  	
 	kfree(dev) ; 
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/tokenring/olympic.h linux/drivers/net/tokenring/olympic.h
--- v2.4.5/linux/drivers/net/tokenring/olympic.h	Wed Apr 18 11:39:21 2001
+++ linux/drivers/net/tokenring/olympic.h	Wed Jun 20 11:13:18 2001
@@ -214,43 +214,43 @@
 /* xxxx These structures are all little endian in hardware. */
 
 struct olympic_tx_desc {
-	__u32 buffer;
-	__u32 status_length;
+	u32 buffer;
+	u32 status_length;
 };
 
 struct olympic_tx_status {
-	__u32 status;
+	u32 status;
 };
 
 struct olympic_rx_desc {
-	__u32 buffer;
-	__u32 res_length; 
+	u32 buffer;
+	u32 res_length; 
 };
 
 struct olympic_rx_status {
-	__u32 fragmentcnt_framelen;
-	__u32 status_buffercnt;
+	u32 fragmentcnt_framelen;
+	u32 status_buffercnt;
 };
 /* xxxx END These structures are all little endian in hardware. */
 /* xxxx There may be more, but I'm pretty sure about these */
 
 struct mac_receive_buffer {
-	__u16 next ; 
-	__u8 padding ; 
-	__u8 frame_status ;
-	__u16 buffer_length ; 
-	__u8 frame_data ; 
+	u16 next ; 
+	u8 padding ; 
+	u8 frame_status ;
+	u16 buffer_length ; 
+	u8 frame_data ; 
 };
 
 struct olympic_private {
 	
-	__u16 srb;      /* be16 */
-	__u16 trb;      /* be16 */
-	__u16 arb;      /* be16 */
-	__u16 asb;      /* be16 */
+	u16 srb;      /* be16 */
+	u16 trb;      /* be16 */
+	u16 arb;      /* be16 */
+	u16 asb;      /* be16 */
 
-	__u8 *olympic_mmio;
-	__u8 *olympic_lap;
+	u8 *olympic_mmio;
+	u8 *olympic_lap;
 	struct pci_dev *pdev ; 
 	char *olympic_card_name ; 
 
@@ -274,47 +274,47 @@
 	int tx_ring_free, tx_ring_last_status, rx_ring_last_received,rx_status_last_received, free_tx_ring_entries;
 
 	struct net_device_stats olympic_stats ;
-	__u16 olympic_lan_status ;
-	__u8 olympic_ring_speed ;
-	__u16 pkt_buf_sz ; 
-	__u8 olympic_receive_options, olympic_copy_all_options,olympic_message_level, olympic_network_monitor;  
-	__u16 olympic_addr_table_addr, olympic_parms_addr ; 
-	__u8 olympic_laa[6] ; 
-	__u32 rx_ring_dma_addr;
-	__u32 rx_status_ring_dma_addr;
-	__u32 tx_ring_dma_addr;
-	__u32 tx_status_ring_dma_addr;
+	u16 olympic_lan_status ;
+	u8 olympic_ring_speed ;
+	u16 pkt_buf_sz ; 
+	u8 olympic_receive_options, olympic_copy_all_options,olympic_message_level, olympic_network_monitor;  
+	u16 olympic_addr_table_addr, olympic_parms_addr ; 
+	u8 olympic_laa[6] ; 
+	u32 rx_ring_dma_addr;
+	u32 rx_status_ring_dma_addr;
+	u32 tx_ring_dma_addr;
+	u32 tx_status_ring_dma_addr;
 };
 
 struct olympic_adapter_addr_table {
 
-	__u8 node_addr[6] ; 
-	__u8 reserved[4] ; 
-	__u8 func_addr[4] ; 
+	u8 node_addr[6] ; 
+	u8 reserved[4] ; 
+	u8 func_addr[4] ; 
 } ; 
 
 struct olympic_parameters_table { 
 	
-	__u8  phys_addr[4] ; 
-	__u8  up_node_addr[6] ; 
-	__u8  up_phys_addr[4] ; 
-	__u8  poll_addr[6] ; 
-	__u16 reserved ; 
-	__u16 acc_priority ; 
-	__u16 auth_source_class ; 
-	__u16 att_code ; 
-	__u8  source_addr[6] ; 
-	__u16 beacon_type ; 
-	__u16 major_vector ; 
-	__u16 lan_status ; 
-	__u16 soft_error_time ; 
- 	__u16 reserved1 ; 
-	__u16 local_ring ; 
-	__u16 mon_error ; 
-	__u16 beacon_transmit ; 
-	__u16 beacon_receive ; 
-	__u16 frame_correl ; 
-	__u8  beacon_naun[6] ; 
-	__u32 reserved2 ; 
-	__u8  beacon_phys[4] ; 	
+	u8  phys_addr[4] ; 
+	u8  up_node_addr[6] ; 
+	u8  up_phys_addr[4] ; 
+	u8  poll_addr[6] ; 
+	u16 reserved ; 
+	u16 acc_priority ; 
+	u16 auth_source_class ; 
+	u16 att_code ; 
+	u8  source_addr[6] ; 
+	u16 beacon_type ; 
+	u16 major_vector ; 
+	u16 lan_status ; 
+	u16 soft_error_time ; 
+ 	u16 reserved1 ; 
+	u16 local_ring ; 
+	u16 mon_error ; 
+	u16 beacon_transmit ; 
+	u16 beacon_receive ; 
+	u16 frame_correl ; 
+	u8  beacon_naun[6] ; 
+	u32 reserved2 ; 
+	u8  beacon_phys[4] ; 	
 }; 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/tokenring/smctr.c linux/drivers/net/tokenring/smctr.c
--- v2.4.5/linux/drivers/net/tokenring/smctr.c	Wed May 16 10:31:27 2001
+++ linux/drivers/net/tokenring/smctr.c	Wed Jun 20 11:13:18 2001
@@ -26,6 +26,10 @@
  *    1. Multicast support.
  */
 
+#if defined(__alpha__) || defined(__ia64__)
+#error FIXME: driver does not support 64-bit platforms
+#endif
+
 #ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
diff -u --recursive --new-file v2.4.5/linux/drivers/net/tulip/21142.c linux/drivers/net/tulip/21142.c
--- v2.4.5/linux/drivers/net/tulip/21142.c	Wed May 16 10:25:39 2001
+++ linux/drivers/net/tulip/21142.c	Wed Jun 20 11:15:44 2001
@@ -84,7 +84,7 @@
 			tp->csr6 &= 0x00D5;
 			tp->csr6 |= new_csr6;
 			outl(0x0301, ioaddr + CSR12);
-			tulip_restart_rxtx(tp, tp->csr6);
+			tulip_restart_rxtx(tp);
 		}
 		next_tick = 3*HZ;
 	}
@@ -117,7 +117,7 @@
 	udelay(100);
 	outl(csr14, ioaddr + CSR14);
 	tp->csr6 = 0x82420000 | (tp->sym_advertise & 0x0040 ? FullDuplex : 0);
-	tulip_outl_csr(tp, tp->csr6, CSR6);
+	outl(tp->csr6, ioaddr + CSR6);
 	if (tp->mtable  &&  tp->mtable->csr15dir) {
 		outl(tp->mtable->csr15dir, ioaddr + CSR15);
 		outl(tp->mtable->csr15val, ioaddr + CSR15);
@@ -201,12 +201,12 @@
 			outl(1, ioaddr + CSR13);
 		}
 #if 0							/* Restart shouldn't be needed. */
-		tulip_outl_csr(tp, tp->csr6 | csr6_sr, CSR6);
+		outl(tp->csr6 | RxOn, ioaddr + CSR6);
 		if (tulip_debug > 2)
 			printk(KERN_DEBUG "%s:  Restarting Tx and Rx, CSR5 is %8.8x.\n",
 				   dev->name, inl(ioaddr + CSR5));
 #endif
-		tulip_outl_csr(tp, tp->csr6 | csr6_st | csr6_sr, CSR6);
+		tulip_start_rxtx(tp);
 		if (tulip_debug > 2)
 			printk(KERN_DEBUG "%s:  Setting CSR6 %8.8x/%x CSR12 %8.8x.\n",
 				   dev->name, tp->csr6, inl(ioaddr + CSR6),
@@ -252,7 +252,7 @@
 		tp->csr6 = 0x83860000;
 		outl(0x0003FF7F, ioaddr + CSR14);
 		outl(0x0301, ioaddr + CSR12);
-		tulip_restart_rxtx(tp, tp->csr6);
+		tulip_restart_rxtx(tp);
 	}
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/tulip/ChangeLog linux/drivers/net/tulip/ChangeLog
--- v2.4.5/linux/drivers/net/tulip/ChangeLog	Sat May 19 18:02:45 2001
+++ linux/drivers/net/tulip/ChangeLog	Wed Jun 20 11:19:02 2001
@@ -1,3 +1,70 @@
+2001-06-16  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* tulip.h, tulip_core.c:
+	Integrate MMIO support from devel branch, but default
+	it to off for stable kernel and driver series.
+
+2001-06-16  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* tulip_core.c (tulip_init_one):
+	Free descriptor rings on error.
+
+2001-06-16  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* tulip_core.c (tulip_mwi_config, tulip_init_one):
+	Large update to csr0 bus configuration code.  This is not stable
+	yet, so it is only conditionally enabled, via CONFIG_TULIP_MWI.
+
+2001-06-16  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* tulip_core.c:
+	Initialize timer in tulip_init_one and tulip_down,
+	not in tulip_up.
+
+2001-06-14  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* tulip_core.c:
+	- Update tulip_suspend, tulip_resume for new PCI PM API.
+	- Surround suspend/resume code with CONFIG_PM.
+
+2001-06-12  Jeff Golds  <jgolds@resilience.com>
+
+	* tulip_core.c:
+	- Reset sw ring ptrs in tulip_up.  Fixes PM resume case.
+	- Clean rx and tx rings on device down.
+
+2001-06-05  David Miller  <davem@redhat.com>
+
+	* tulip_core (set_rx_mode):  Do not use set_bit
+	on an integer variable.  Also fix endianness issue.
+
+2001-06-04  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* interrupt.c:
+	Simplify rx processing when CONFIG_NET_HW_FLOWCONTROL is
+	active, and in the process fix a bug where flow control
+	and low load caused rx not to be acknowledged properly.
+
+2001-06-01  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* tulip.h:
+	- Remove tulip_outl_csr helper, redundant.
+	- Add tulip_start_rxtx inline helper.
+	- tulip_stop_rxtx helper: Add synchronization. Always use current
+	  csr6 value, instead of tp->csr6 value or value passed as arg.
+	- tulip_restart_rxtx helper: Add synchronization. Always
+	  use tp->csr6 for desired mode, not value passed as arg.
+	- New RxOn, TxOn, RxTx constants for csr6 modes.
+	- Remove now-redundant constants csr6_st, csr6_sr.
+
+	* 21142.c, interrupt.c, media.c, pnic.c, tulip_core.c:
+	Update for above rxtx helper changes.
+
+	* interrupt.c:
+	- whitespace cleanup around #ifdef CONFIG_NET_HW_FLOWCONTROL,
+	  convert tabs to spaces.
+	- Move tp->stats.rx_missed_errors update outside the ifdef.
+
 2001-05-18  Jeff Garzik  <jgarzik@mandrakesoft.com>
 
 	* tulip_core.c: Added ethtool support.
diff -u --recursive --new-file v2.4.5/linux/drivers/net/tulip/interrupt.c linux/drivers/net/tulip/interrupt.c
--- v2.4.5/linux/drivers/net/tulip/interrupt.c	Sun May 20 12:11:38 2001
+++ linux/drivers/net/tulip/interrupt.c	Wed Jun 20 11:15:44 2001
@@ -328,21 +328,11 @@
 
 		if (csr5 & (RxIntr | RxNoBuf)) {
 #ifdef CONFIG_NET_HW_FLOWCONTROL
-                        if (tp->fc_bit) {
-                                if (test_bit(tp->fc_bit, &netdev_fc_xoff)) {
-                                        tulip_refill_rx(dev);
-                                } else {
-                                        tulip_refill_rx(dev);
-                                        rx += tulip_rx(dev);
-                                }
-                        } else {        /* not in fc mode */
-                                rx += tulip_rx(dev);
-                                tulip_refill_rx(dev);
-                        }
-#else
-			rx += tulip_rx(dev);
-			tulip_refill_rx(dev);
+                        if ((!tp->fc_bit) ||
+			    (!test_bit(tp->fc_bit, &netdev_fc_xoff)))
 #endif
+				rx += tulip_rx(dev);
+			tulip_refill_rx(dev);
 		}
 
 		if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) {
@@ -418,7 +408,7 @@
 					printk(KERN_WARNING "%s: The transmitter stopped."
 						   "  CSR5 is %x, CSR6 %x, new CSR6 %x.\n",
 						   dev->name, csr5, inl(ioaddr + CSR6), tp->csr6);
-				tulip_restart_rxtx(tp, tp->csr6);
+				tulip_restart_rxtx(tp);
 			}
 			spin_unlock(&tp->lock);
 		}
@@ -434,7 +424,7 @@
 				else
 					tp->csr6 |= 0x00200000;  /* Store-n-forward. */
 				/* Restart the transmit process. */
-				tulip_restart_rxtx(tp, tp->csr6);
+				tulip_restart_rxtx(tp);
 				outl(0, ioaddr + CSR1);
 			}
 			if (csr5 & (RxDied | RxNoBuf)) {
@@ -444,16 +434,15 @@
 				}
 			}
 			if (csr5 & RxDied) {		/* Missed a Rx frame. */
-#ifdef CONFIG_NET_HW_FLOWCONTROL
-                                if (tp->fc_bit && !test_bit(tp->fc_bit, &netdev_fc_xoff)) {
-                                        tp->stats.rx_errors++;
-                                        tulip_outl_csr(tp, tp->csr6 | csr6_st | csr6_sr, CSR6);
-                                }
                                 tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+				if (tp->fc_bit && !test_bit(tp->fc_bit, &netdev_fc_xoff)) {
+					tp->stats.rx_errors++;
+					tulip_start_rxtx(tp);
+				}
 #else
 				tp->stats.rx_errors++;
-				tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
-				tulip_outl_csr(tp, tp->csr6 | csr6_st | csr6_sr, CSR6);
+				tulip_start_rxtx(tp);
 #endif
 			}
 			/*
diff -u --recursive --new-file v2.4.5/linux/drivers/net/tulip/media.c linux/drivers/net/tulip/media.c
--- v2.4.5/linux/drivers/net/tulip/media.c	Wed May 16 10:25:39 2001
+++ linux/drivers/net/tulip/media.c	Wed Jun 20 11:15:44 2001
@@ -411,7 +411,6 @@
   */
 int tulip_check_duplex(struct net_device *dev)
 {
-	long ioaddr = dev->base_addr;
 	struct tulip_private *tp = dev->priv;
 	unsigned int bmsr, lpa, negotiated, new_csr6;
 
@@ -442,11 +441,8 @@
 	else		     new_csr6 &= ~FullDuplex;
 
 	if (new_csr6 != tp->csr6) {
-		if (inl(ioaddr + CSR6) & (csr6_st | csr6_sr))
-			tulip_restart_rxtx(tp, new_csr6);
-		else
-			outl(new_csr6, ioaddr + CSR6);
 		tp->csr6 = new_csr6;
+		tulip_restart_rxtx(tp);
 
 		if (tulip_debug > 0)
 			printk(KERN_INFO "%s: Setting %s-duplex based on MII"
diff -u --recursive --new-file v2.4.5/linux/drivers/net/tulip/pnic.c linux/drivers/net/tulip/pnic.c
--- v2.4.5/linux/drivers/net/tulip/pnic.c	Sat May 19 18:02:45 2001
+++ linux/drivers/net/tulip/pnic.c	Wed Jun 20 11:15:44 2001
@@ -45,7 +45,7 @@
 		if (tp->csr6 != new_csr6) {
 			tp->csr6 = new_csr6;
 			/* Restart Tx */
-			tulip_restart_rxtx(tp, tp->csr6);
+			tulip_restart_rxtx(tp);
 			dev->trans_start = jiffies;
 		}
 	}
@@ -69,7 +69,7 @@
 			return;
 		if (! tp->nwayset  ||  jiffies - dev->trans_start > 1*HZ) {
 			tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff);
-			tulip_outl_csr(tp, tp->csr6, CSR6);
+			outl(tp->csr6, ioaddr + CSR6);
 			outl(0x30, ioaddr + CSR12);
 			outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
 			dev->trans_start = jiffies;
@@ -148,7 +148,7 @@
 			if (tp->csr6 != new_csr6) {
 				tp->csr6 = new_csr6;
 				/* Restart Tx */
-				tulip_restart_rxtx(tp, tp->csr6);
+				tulip_restart_rxtx(tp);
 				dev->trans_start = jiffies;
 				if (tulip_debug > 1)
 					printk(KERN_INFO "%s: Changing PNIC configuration to %s "
diff -u --recursive --new-file v2.4.5/linux/drivers/net/tulip/timer.c linux/drivers/net/tulip/timer.c
--- v2.4.5/linux/drivers/net/tulip/timer.c	Tue Apr  3 10:19:43 2001
+++ linux/drivers/net/tulip/timer.c	Wed Jun 20 11:15:44 2001
@@ -158,7 +158,7 @@
 				       medianame[tp->mtable->mleaf[tp->cur_index].media]);
 			tulip_select_media(dev, 0);
 			/* Restart the transmit process. */
-			tulip_restart_rxtx(tp, tp->csr6);
+			tulip_restart_rxtx(tp);
 			next_tick = (24*HZ)/10;
 			break;
 		}
diff -u --recursive --new-file v2.4.5/linux/drivers/net/tulip/tulip.h linux/drivers/net/tulip/tulip.h
--- v2.4.5/linux/drivers/net/tulip/tulip.h	Sun May 20 12:11:38 2001
+++ linux/drivers/net/tulip/tulip.h	Wed Jun 20 11:19:02 2001
@@ -22,6 +22,7 @@
 #include <linux/spinlock.h>
 #include <linux/netdevice.h>
 #include <linux/timer.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
@@ -30,6 +31,14 @@
 /* undefine, or define to various debugging levels (>4 == obscene levels) */
 #define TULIP_DEBUG 1
 
+/* undefine USE_IO_OPS for MMIO, define for PIO */
+#ifdef CONFIG_TULIP_MMIO
+# undef USE_IO_OPS
+#else
+# define USE_IO_OPS 1
+#endif
+
+
 
 struct tulip_chip_table {
 	char *chip_name;
@@ -139,10 +148,13 @@
 enum tulip_mode_bits {
 	TxThreshold		= (1 << 22),
 	FullDuplex		= (1 << 9),
+	TxOn			= 0x2000,
 	AcceptBroadcast		= 0x0100,
 	AcceptAllMulticast	= 0x0080,
 	AcceptAllPhys		= 0x0040,
 	AcceptRunt		= 0x0008,
+	RxOn			= 0x0002,
+	RxTx			= (TxOn | RxOn),
 };
 
 
@@ -219,7 +231,6 @@
 	 *   (1,1)   *    1024   *   160   *
 	 ***********************************/
 
-	csr6_st = (1<<13),   /* Transmit conrol: 1 = transmit, 0 = stop */
 	csr6_fc = (1<<12),   /* Forces a collision in next transmission (for testing in loopback mode) */
 	csr6_om_int_loop = (1<<10), /* internal (FIFO) loopback flag */
 	csr6_om_ext_loop = (1<<11), /* external (PMD) loopback flag */
@@ -231,7 +242,6 @@
 	csr6_if = (1<<4),    /* Inverse Filtering, rejects only addresses in address table: can't be set */
 	csr6_pb = (1<<3),    /* Pass Bad Frames, (1) causes even bad frames to be passed on */
 	csr6_ho = (1<<2),    /* Hash-only filtering mode: can't be set */
-	csr6_sr = (1<<1),    /* Start(1)/Stop(0) Receive */
 	csr6_hp = (1<<0),    /* Hash/Perfect Receive Filtering Mode: can't be set */
 
 	csr6_mask_capture = (csr6_sc | csr6_ca),
@@ -434,21 +444,48 @@
 extern u16 t21041_csr14[];
 extern u16 t21041_csr15[];
 
+#ifndef USE_IO_OPS
+#undef inb
+#undef inw
+#undef inl
+#undef outb
+#undef outw
+#undef outl
+#define inb(addr) readb((void*)(addr))
+#define inw(addr) readw((void*)(addr))
+#define inl(addr) readl((void*)(addr))
+#define outb(val,addr) writeb((val), (void*)(addr))
+#define outw(val,addr) writew((val), (void*)(addr))
+#define outl(val,addr) writel((val), (void*)(addr))
+#endif /* !USE_IO_OPS */
 
-static inline void tulip_outl_csr (struct tulip_private *tp, u32 newValue, enum tulip_offsets offset)
+
+
+static inline void tulip_start_rxtx(struct tulip_private *tp)
 {
-	outl (newValue, tp->base_addr + offset);
+	long ioaddr = tp->base_addr;
+	outl(tp->csr6 | RxTx, ioaddr + CSR6);
+	barrier();
+	(void) inl(ioaddr + CSR6); /* mmio sync */
 }
 
-static inline void tulip_stop_rxtx(struct tulip_private *tp, u32 csr6mask)
+static inline void tulip_stop_rxtx(struct tulip_private *tp)
 {
-	tulip_outl_csr(tp, csr6mask & ~(csr6_st | csr6_sr), CSR6);
+	long ioaddr = tp->base_addr;
+	u32 csr6 = inl(ioaddr + CSR6);
+
+	if (csr6 & RxTx) {
+		outl(csr6 & ~RxTx, ioaddr + CSR6);
+		barrier();
+		(void) inl(ioaddr + CSR6); /* mmio sync */
+	}
 }
 
-static inline void tulip_restart_rxtx(struct tulip_private *tp, u32 csr6mask)
+static inline void tulip_restart_rxtx(struct tulip_private *tp)
 {
-	tulip_outl_csr(tp, csr6mask | csr6_sr, CSR6);
-	tulip_outl_csr(tp, csr6mask | csr6_st | csr6_sr, CSR6);
+	tulip_stop_rxtx(tp);
+	udelay(5);
+	tulip_start_rxtx(tp);
 }
 
 #endif /* __NET_TULIP_H__ */
diff -u --recursive --new-file v2.4.5/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c
--- v2.4.5/linux/drivers/net/tulip/tulip_core.c	Sun May 20 12:11:38 2001
+++ linux/drivers/net/tulip/tulip_core.c	Wed Jun 20 11:19:02 2001
@@ -1,4 +1,4 @@
-/* tulip_core.c: A DEC 21040-family ethernet driver for Linux. */
+/* tulip_core.c: A DEC 21x4x-family ethernet driver for Linux. */
 
 /*
 	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
@@ -15,8 +15,8 @@
 */
 
 #define DRV_NAME	"tulip"
-#define DRV_VERSION	"0.9.15-pre2"
-#define DRV_RELDATE	"May 16, 2001"
+#define DRV_VERSION	"0.9.15-pre5"
+#define DRV_RELDATE	"June 16, 2001"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -276,7 +276,7 @@
 
 	/* On some chip revs we must set the MII/SYM port before the reset!? */
 	if (tp->mii_cnt  ||  (tp->mtable  &&  tp->mtable->has_mii))
-		tulip_outl_csr (tp, 0x00040000, CSR6);
+		outl(0x00040000, ioaddr + CSR6);
 
 	/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
 	outl(0x00000001, ioaddr + CSR0);
@@ -291,6 +291,11 @@
 	if (tulip_debug > 1)
 		printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq);
 
+	outl(tp->rx_ring_dma, ioaddr + CSR3);
+	outl(tp->tx_ring_dma, ioaddr + CSR4);
+	tp->cur_rx = tp->cur_tx = 0;
+	tp->dirty_rx = tp->dirty_tx = 0;
+
 	if (tp->chip_id == PNIC2) {
 		u32 addr_high = (dev->dev_addr[1]<<8) + (dev->dev_addr[0]<<0);
 		/* This address setting does not appear to impact chip operation?? */
@@ -340,9 +345,6 @@
 		tp->cur_tx++;
 	}
 
-	outl(tp->rx_ring_dma, ioaddr + CSR3);
-	outl(tp->tx_ring_dma, ioaddr + CSR4);
-
 	tp->saved_if_port = dev->if_port;
 	if (dev->if_port == 0)
 		dev->if_port = tp->default_port;
@@ -409,7 +411,7 @@
 				printk(KERN_INFO "%s: Using MII transceiver %d, status "
 					   "%4.4x.\n",
 					   dev->name, tp->phys[0], tulip_mdio_read(dev, tp->phys[0], 1));
-			tulip_outl_csr(tp, csr6_mask_defstate, CSR6);
+			outl(csr6_mask_defstate, ioaddr + CSR6);
 			tp->csr6 = csr6_mask_hdcap;
 			dev->if_port = 11;
 			outl(0x0000, ioaddr + CSR13);
@@ -455,26 +457,26 @@
 		tulip_select_media(dev, 1);
 
 	/* Start the chip's Tx to process setup frame. */
-	tulip_outl_csr(tp, tp->csr6, CSR6);
-	tulip_outl_csr(tp, tp->csr6 | csr6_st, CSR6);
+	tulip_stop_rxtx(tp);
+	barrier();
+	udelay(5);
+	outl(tp->csr6 | TxOn, ioaddr + CSR6);
 
 	/* Enable interrupts by setting the interrupt mask. */
 	outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
 	outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
-	tulip_outl_csr(tp, tp->csr6 | csr6_st | csr6_sr, CSR6);
+	tulip_start_rxtx(tp);
 	outl(0, ioaddr + CSR2);		/* Rx poll demand */
 
 	if (tulip_debug > 2) {
-		printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
+		printk(KERN_DEBUG "%s: Done tulip_up(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
 			   dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5),
 			   inl(ioaddr + CSR6));
 	}
+
 	/* Set the timer to switch to check for link beat and perhaps switch
 	   to an alternate media type. */
-	init_timer(&tp->timer);
 	tp->timer.expires = RUN_AT(next_tick);
-	tp->timer.data = (unsigned long)dev;
-	tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
 	add_timer(&tp->timer);
 }
 
@@ -626,7 +628,7 @@
         if (tp->fc_bit && test_bit(tp->fc_bit,&netdev_fc_xoff))
                 printk("BUG tx_timeout restarting rx when fc on\n");
 #endif
-	tulip_restart_rxtx(tp, tp->csr6);
+	tulip_restart_rxtx(tp);
 	/* Trigger an immediate transmit demand. */
 	outl(0, ioaddr + CSR1);
 
@@ -645,8 +647,6 @@
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	int i;
 
-	tp->cur_rx = tp->cur_tx = 0;
-	tp->dirty_rx = tp->dirty_tx = 0;
 	tp->susp_rx = 0;
 	tp->ttimer = 0;
 	tp->nir = 0;
@@ -742,6 +742,41 @@
 	return 0;
 }
 
+static void tulip_release_unconsumed_tx_buffers(struct tulip_private *tp)
+{
+	unsigned int dirty_tx;
+
+	for (dirty_tx = tp->dirty_tx ; tp->cur_tx - dirty_tx > 0;
+		dirty_tx++) {
+		int entry = dirty_tx % TX_RING_SIZE;
+		int status = le32_to_cpu(tp->tx_ring[entry].status);
+
+		if (status > 0)
+			break;		/* It has been Txed */
+
+		/* Check for Rx filter setup frames. */
+		if (tp->tx_buffers[entry].skb == NULL) {
+			/* test because dummy frames not mapped */
+			if (tp->tx_buffers[entry].mapping)
+				pci_unmap_single(tp->pdev,
+					tp->tx_buffers[entry].mapping,
+					sizeof(tp->setup_frame),
+					PCI_DMA_TODEVICE);
+			continue;
+		}
+		tp->stats.tx_errors++;
+
+		pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping,
+				tp->tx_buffers[entry].skb->len,
+				PCI_DMA_TODEVICE);
+
+		/* Free the original skb. */
+		dev_kfree_skb_irq(tp->tx_buffers[entry].skb);
+		tp->tx_buffers[entry].skb = NULL;
+		tp->tx_buffers[entry].mapping = 0;
+	}
+}
+
 static void tulip_down (struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
@@ -756,7 +791,13 @@
 	outl (0x00000000, ioaddr + CSR7);
 
 	/* Stop the Tx and Rx processes. */
-	tulip_stop_rxtx(tp, inl(ioaddr + CSR6));
+	tulip_stop_rxtx(tp);
+
+	/* prepare receive buffers */
+	tulip_refill_rx(dev);
+
+	/* release any unconsumed transmit buffers */
+	tulip_release_unconsumed_tx_buffers(tp);
 
 	/* 21040 -- Leave the card in 10baseT state. */
 	if (tp->chip_id == DC21040)
@@ -767,6 +808,10 @@
 
 	spin_unlock_irqrestore (&tp->lock, flags);
 
+	init_timer(&tp->timer);
+	tp->timer.data = (unsigned long)dev;
+	tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
+
 	dev->if_port = tp->saved_if_port;
 
 	/* Leave the driver in snooze, not sleep, mode. */
@@ -1108,7 +1153,7 @@
 				else
 					filterbit = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
 				filterbit &= 0x3f;
-				set_bit(filterbit, mc_filter);
+				mc_filter[filterbit >> 5] |= cpu_to_le32(1 << (filterbit & 31));
 				if (tulip_debug > 2) {
 					printk(KERN_INFO "%s: Added filter for %2.2x:%2.2x:%2.2x:"
 						   "%2.2x:%2.2x:%2.2x  %8.8x bit %d.\n", dev->name,
@@ -1193,95 +1238,96 @@
 		spin_unlock_irqrestore(&tp->lock, flags);
 	}
 
-	/* Can someone explain to me what the OR here is supposed to accomplish???? */
-	tulip_outl_csr(tp, csr6 | 0x0000, CSR6);
+	outl(csr6, ioaddr + CSR6);
 }
 
+#ifdef CONFIG_TULIP_MWI
 static void __devinit tulip_mwi_config (struct pci_dev *pdev,
 					struct net_device *dev)
 {
 	struct tulip_private *tp = dev->priv;
-	u8 pci_cacheline;
+	u8 cache;
 	u16 pci_command, new_command;
-	unsigned mwi = 1;
+	u32 csr0;
 	
 	if (tulip_debug > 3)
 		printk(KERN_DEBUG "%s: tulip_mwi_config()\n", pdev->slot_name);
 
-	/* get a sane cache line size, if possible */
-	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline);
-	if (pci_cacheline < (SMP_CACHE_BYTES / 4))
-		pci_cacheline = SMP_CACHE_BYTES / 4;
-	if (pci_cacheline > TULIP_MAX_CACHE_LINE)
-		pci_cacheline = TULIP_MAX_CACHE_LINE;
-	switch (pci_cacheline) {
-	case 8:
-	case 16:
-	case 32: break;
-	default: pci_cacheline = TULIP_MIN_CACHE_LINE; break;
+	tp->csr0 = 0;
+
+	/* check for sane cache line size. from acenic.c. */
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache);
+	if ((cache << 2) != SMP_CACHE_BYTES) {
+		printk(KERN_WARNING "%s: PCI cache line size set incorrectly "
+		       "(%i bytes) by BIOS/FW, correcting to %i\n",
+		       pdev->slot_name, (cache << 2), SMP_CACHE_BYTES);
+		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+				      SMP_CACHE_BYTES >> 2);
+		udelay(5);
 	}
-	pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, pci_cacheline);
 
-	/* read back the result.  if zero, or if a buggy chip rev,
-	 * disable MWI
+	/* read cache line size again, hardware may not have accepted
+	 * our cache line size change
 	 */
-	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline);
-	if (!pci_cacheline || (tp->chip_id == DC21143 && tp->revision == 65))
-		mwi = 0;
-
-	/* re-clamp cache line values to ones supported by tulip */
-	/* From this point forward, 'pci_cacheline' is really
-	 * the value used for csr0 cache alignment and
-	 * csr0 programmable burst length
-	 */
-	switch (pci_cacheline) {
-	case 0:
-	case 8:
-	case 16:
-	case 32: break;
-	default: pci_cacheline = TULIP_MIN_CACHE_LINE; break;
-	}
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache);
+	if (!cache)
+		goto out;
+
+	/* if we have any cache line size at all, we can do MRM */
+	csr0 |= MRM;
+	
+	/* ...and barring hardware bugs, MWI */
+	if (!(tp->chip_id == DC21143 && tp->revision == 65))
+		csr0 |= MWI;
 
 	/* set or disable MWI in the standard PCI command bit.
 	 * Check for the case where  mwi is desired but not available
 	 */
 	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-	if (mwi)	new_command = pci_command | PCI_COMMAND_INVALIDATE;
+	if (csr0 & MWI)	new_command = pci_command | PCI_COMMAND_INVALIDATE;
 	else		new_command = pci_command & ~PCI_COMMAND_INVALIDATE;
 	if (new_command != pci_command) {
 		pci_write_config_word(pdev, PCI_COMMAND, new_command);
+		udelay(5);
 		pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-		if ((new_command != pci_command) && mwi &&
-		    ((pci_command & PCI_COMMAND_INVALIDATE) == 0))
-			mwi = 0;
+		if ((csr0 & MWI) && (!(pci_command & PCI_COMMAND_INVALIDATE)))
+			csr0 &= ~MWI;
 	}
 
-	tp->csr0 = MRL | MRM;	
-
-	/* if no PCI cache line size, bail out with minimal
-	 * burst size and cache alignment of 8 dwords.
-	 * We always want to have some sort of limit.
+	/* assign per-cacheline-size cache alignment and
+	 * burst length values
 	 */
-	if (!pci_cacheline) {
-		tp->csr0 |= (8 << BurstLenShift) | (1 << CALShift);
+	switch (cache) {
+	case 8:
+		csr0 |= MRL | (1 << CALShift) | (16 << BurstLenShift);
+		break;
+	case 16:
+		csr0 |= MRL | (2 << CALShift) | (16 << BurstLenShift);
+		break;
+	case 32:
+		csr0 |= MRL | (3 << CALShift) | (32 << BurstLenShift);
+		break;
+	default:
 		goto out;
 	}
+
+	tp->csr0 = csr0;
+	goto out;
 	
-	/* finally, build the csr0 value */
-	if (mwi)
-		tp->csr0 |= MWI;
-	tp->csr0 |= (pci_cacheline << BurstLenShift);
-	switch (pci_cacheline) {
-	case 8:  tp->csr0 |= (1 << CALShift);
-	case 16: tp->csr0 |= (2 << CALShift);
-	case 32: tp->csr0 |= (3 << CALShift);
+early_out:
+	if (csr0 & MWI) {
+		pci_command &= ~PCI_COMMAND_INVALIDATE;
+		pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+		csr0 &= ~MWI;
 	}
+	tp->csr0 = csr0 | (8 << BurstLenShift) | (1 << CALShift);
 
 out:
 	if (tulip_debug > 2)
-		printk(KERN_DEBUG "%s: MWI config mwi=%d, cacheline=%d, csr0=%08x\n",
-		       pdev->slot_name, mwi, pci_cacheline, tp->csr0);
+		printk(KERN_DEBUG "%s: MWI config cacheline=%d, csr0=%08x\n",
+		       pdev->slot_name, cache, csr0);
 }
+#endif
 
 static int __devinit tulip_init_one (struct pci_dev *pdev,
 				     const struct pci_device_id *ent)
@@ -1402,6 +1448,13 @@
 	if (pci_request_regions (pdev, "tulip"))
 		goto err_out_free_netdev;
 
+#ifndef USE_IO_OPS
+	ioaddr = (unsigned long) ioremap (pci_resource_start (pdev, 1),
+					  tulip_tbl[chip_idx].io_size);
+	if (!ioaddr)
+		goto err_out_free_res;
+#endif
+
 	pci_set_master(pdev);
 
 	pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev);
@@ -1417,7 +1470,7 @@
 					   sizeof(struct tulip_tx_desc) * TX_RING_SIZE,
 					   &tp->rx_ring_dma);
 	if (!tp->rx_ring)
-		goto err_out_free_res;
+		goto err_out_mtable;
 	tp->tx_ring = (struct tulip_tx_desc *)(tp->rx_ring + RX_RING_SIZE);
 	tp->tx_ring_dma = tp->rx_ring_dma + sizeof(struct tulip_rx_desc) * RX_RING_SIZE;
 
@@ -1429,15 +1482,20 @@
 	tp->csr0 = csr0;
 	spin_lock_init(&tp->lock);
 	spin_lock_init(&tp->mii_lock);
+	init_timer(&tp->timer);
+	tp->timer.data = (unsigned long)dev;
+	tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
 
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 
+#ifdef CONFIG_TULIP_MWI
 	if (!force_csr0 && (tp->flags & HAS_PCI_MWI))
 		tulip_mwi_config (pdev, dev);
+#endif
 
 	/* Stop the chip's Tx and Rx processes. */
-	tulip_stop_rxtx(tp, inl(ioaddr + CSR6));
+	tulip_stop_rxtx(tp);
 
 	/* Clear the missed-packet counter. */
 	inl(ioaddr + CSR8);
@@ -1600,7 +1658,7 @@
 	dev->set_multicast_list = set_rx_mode;
 
 	if (register_netdev(dev))
-		goto err_out_mtable;
+		goto err_out_free_ring;
 
 	printk(KERN_INFO "%s: %s rev %d at %#3lx,",
 	       dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
@@ -1631,7 +1689,7 @@
 		outl(0x00000000, ioaddr + CSR13);
 		outl(0xFFFFFFFF, ioaddr + CSR14);
 		outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
-		tulip_outl_csr(tp, inl(ioaddr + CSR6) | csr6_fd, CSR6);
+		outl(inl(ioaddr + CSR6) | csr6_fd, ioaddr + CSR6);
 		outl(0x0000EF01, ioaddr + CSR13);
 		break;
 	case DC21040:
@@ -1647,10 +1705,10 @@
 	case DC21142:
 	case PNIC2:
 		if (tp->mii_cnt  ||  tulip_media_cap[dev->if_port] & MediaIsMII) {
-			tulip_outl_csr(tp, csr6_mask_defstate, CSR6);
+			outl(csr6_mask_defstate, ioaddr + CSR6);
 			outl(0x0000, ioaddr + CSR13);
 			outl(0x0000, ioaddr + CSR14);
-			tulip_outl_csr(tp, csr6_mask_hdcap, CSR6);
+			outl(csr6_mask_hdcap, ioaddr + CSR6);
 		} else
 			t21142_start_nway(dev);
 		break;
@@ -1658,21 +1716,21 @@
 		if ( ! tp->mii_cnt) {
 			tp->nway = 1;
 			tp->nwayset = 0;
-			tulip_outl_csr(tp, csr6_ttm | csr6_ca, CSR6);
+			outl(csr6_ttm | csr6_ca, ioaddr + CSR6);
 			outl(0x30, ioaddr + CSR12);
-			tulip_outl_csr(tp, 0x0001F078, CSR6);
-			tulip_outl_csr(tp, 0x0201F078, CSR6); /* Turn on autonegotiation. */
+			outl(0x0001F078, ioaddr + CSR6);
+			outl(0x0201F078, ioaddr + CSR6); /* Turn on autonegotiation. */
 		}
 		break;
 	case MX98713:
 	case COMPEX9881:
-		tulip_outl_csr(tp, 0x00000000, CSR6);
+		outl(0x00000000, ioaddr + CSR6);
 		outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
 		outl(0x00000001, ioaddr + CSR13);
 		break;
 	case MX98715:
 	case MX98725:
-		tulip_outl_csr(tp, 0x01a80000, CSR6);
+		outl(0x01a80000, ioaddr + CSR6);
 		outl(0xFFFFFFFF, ioaddr + CSR14);
 		outl(0x00001000, ioaddr + CSR12);
 		break;
@@ -1686,18 +1744,31 @@
 
 	return 0;
 
+err_out_free_ring:
+	pci_free_consistent (pdev,
+			     sizeof (struct tulip_rx_desc) * RX_RING_SIZE +
+			     sizeof (struct tulip_tx_desc) * TX_RING_SIZE,
+			     tp->rx_ring, tp->rx_ring_dma);
+
 err_out_mtable:
 	if (tp->mtable)
 		kfree (tp->mtable);
+#ifndef USE_IO_OPS
+	iounmap((void *)ioaddr);
+#endif
+
 err_out_free_res:
 	pci_release_regions (pdev);
+
 err_out_free_netdev:
 	kfree (dev);
 	return -ENODEV;
 }
 
 
-static void tulip_suspend (struct pci_dev *pdev)
+#ifdef CONFIG_PM
+
+static int tulip_suspend (struct pci_dev *pdev, u32 state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 
@@ -1706,10 +1777,11 @@
 		tulip_down (dev);
 		/* pci_power_off(pdev, -1); */
 	}
+	return 0;
 }
 
 
-static void tulip_resume(struct pci_dev *pdev)
+static int tulip_resume(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 
@@ -1721,8 +1793,11 @@
 		tulip_up (dev);
 		netif_device_attach (dev);
 	}
+	return 0;
 }
 
+#endif /* CONFIG_PM */
+
 
 static void __devexit tulip_remove_one (struct pci_dev *pdev)
 {
@@ -1740,6 +1815,9 @@
 	unregister_netdev (dev);
 	if (tp->mtable)
 		kfree (tp->mtable);
+#ifndef USE_IO_OPS
+	iounmap((void *)dev->base_addr);
+#endif
 	kfree (dev);
 	pci_release_regions (pdev);
 	pci_set_drvdata (pdev, NULL);
@@ -1753,8 +1831,10 @@
 	id_table:	tulip_pci_tbl,
 	probe:		tulip_init_one,
 	remove:		tulip_remove_one,
+#ifdef CONFIG_PM
 	suspend:	tulip_suspend,
 	resume:		tulip_resume,
+#endif /* CONFIG_PM */
 };
 
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/tun.c linux/drivers/net/tun.c
--- v2.4.5/linux/drivers/net/tun.c	Wed Apr 18 14:40:06 2001
+++ linux/drivers/net/tun.c	Mon Jun 11 19:15:27 2001
@@ -12,7 +12,7 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  *  GNU General Public License for more details.
  *
- *  $Id: tun.c,v 1.3 2000/10/23 10:01:25 maxk Exp $
+ *  $Id: tun.c,v 1.12 2001/03/08 03:29:27 maxk Exp $
  */
 
 /*
@@ -20,15 +20,16 @@
  *    Modifications for 2.3.99-pre5 kernel.
  */
 
-#define TUN_VER "1.3"
+#define TUN_VER "1.4"
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/sched.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
 #include <linux/poll.h>
 #include <linux/fcntl.h>
 #include <linux/init.h>
@@ -56,28 +57,14 @@
 /* Net device open. */
 static int tun_net_open(struct net_device *dev)
 {
-#ifdef TUN_DEBUG  
-	struct tun_struct *tun = (struct tun_struct *)dev->priv;
-
-	DBG(KERN_INFO "%s: tun_net_open\n", tun->name);
-#endif
-
 	netif_start_queue(dev);
-
 	return 0;
 }
 
 /* Net device close. */
 static int tun_net_close(struct net_device *dev)
 {
-#ifdef TUN_DEBUG  
-	struct tun_struct *tun = (struct tun_struct *)dev->priv;
-
-	DBG(KERN_INFO "%s: tun_net_close\n", tun->name);
-#endif
-
 	netif_stop_queue(dev);
-
 	return 0;
 }
 
@@ -88,38 +75,46 @@
 
 	DBG(KERN_INFO "%s: tun_net_xmit %d\n", tun->name, skb->len);
 
-	/* Queue frame */
-	skb_queue_tail(&tun->txq, skb);
-	if (skb_queue_len(&tun->txq) >= TUN_TXQ_SIZE)
-		netif_stop_queue(dev);
+	/* Drop packet if interface is not attached */
+	if (!tun->attached)
+		goto drop;
+
+	/* Queue packet */
+	if (!(tun->flags & TUN_ONE_QUEUE)) {
+		/* Normal queueing mode.
+		 * Packet scheduler handles dropping. */
+		if (skb_queue_len(&tun->readq) >= TUN_READQ_SIZE)
+			netif_stop_queue(dev);
+	} else {
+		/* Single queue mode.
+		 * Driver handles dropping itself. */
+		if (skb_queue_len(&tun->readq) >= dev->tx_queue_len)
+			goto drop;
+	}
+	skb_queue_tail(&tun->readq, skb);
 
+	/* Notify and wake up reader process */
 	if (tun->flags & TUN_FASYNC)
 		kill_fasync(&tun->fasync, SIGIO, POLL_IN);
-
-	/* Wake up process */ 
 	wake_up_interruptible(&tun->read_wait);
+	return 0;
 
+drop:
+	tun->stats.tx_dropped++;
+	kfree_skb(skb);
 	return 0;
 }
 
 static void tun_net_mclist(struct net_device *dev)
 {
-#ifdef TUN_DEBUG
-	struct tun_struct *tun = (struct tun_struct *)dev->priv;
-
-	DBG(KERN_INFO "%s: tun_net_mclist\n", tun->name);
-#endif
-
 	/* Nothing to do for multicast filters. 
-	 * We always accept all frames.
-	 */
+	 * We always accept all frames. */
 	return;
 }
 
 static struct net_device_stats *tun_net_stats(struct net_device *dev)
 {
 	struct tun_struct *tun = (struct tun_struct *)dev->priv;
-
 	return &tun->stats;
 }
 
@@ -170,15 +165,19 @@
 static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
 {  
 	struct tun_struct *tun = (struct tun_struct *)file->private_data;
+	unsigned int mask = POLLOUT | POLLWRNORM;
+
+	if (!tun)
+		return -EBADFD;
 
 	DBG(KERN_INFO "%s: tun_chr_poll\n", tun->name);
 
 	poll_wait(file, &tun->read_wait, wait);
  
-	if (skb_queue_len(&tun->txq))
-		return POLLIN | POLLRDNORM;
+	if (skb_queue_len(&tun->readq))
+		mask |= POLLIN | POLLRDNORM;
 
-	return POLLOUT | POLLWRNORM;
+	return mask;
 }
 
 /* Get packet from user space buffer(already verified) */
@@ -189,9 +188,6 @@
 	register int len = count;
 	struct sk_buff *skb;
 
-	if (len > TUN_MAX_FRAME)
-		return -EINVAL;
-
 	if (!(tun->flags & TUN_NO_PI)) {
 		if ((len -= sizeof(pi)) < 0)
 			return -EINVAL;
@@ -222,7 +218,6 @@
 	if (tun->flags & TUN_NOCHECKSUM)
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
  
-	skb->dev->last_rx = jiffies;
 	netif_rx(skb);
    
 	tun->stats.rx_packets++;
@@ -237,10 +232,10 @@
 {
 	struct tun_struct *tun = (struct tun_struct *)file->private_data;
 
-	DBG(KERN_INFO "%s: tun_chr_write %d\n", tun->name, count);
+	if (!tun)
+		return -EBADFD;
 
-	if (!(tun->flags & TUN_IFF_SET))
-		return -EBUSY;
+	DBG(KERN_INFO "%s: tun_chr_write %d\n", tun->name, count);
 
 	if (verify_area(VERIFY_READ, buf, count))
 		return -EFAULT;
@@ -291,14 +286,17 @@
 	struct sk_buff *skb;
 	ssize_t ret = 0;
 
+	if (!tun)
+		return -EBADFD;
+
 	DBG(KERN_INFO "%s: tun_chr_read\n", tun->name);
 
 	add_wait_queue(&tun->read_wait, &wait);
 	while (count) {
 		current->state = TASK_INTERRUPTIBLE;
 
-		/* Read frames from device queue */
-		if (!(skb=skb_dequeue(&tun->txq))) {
+		/* Read frames from the queue */
+		if (!(skb=skb_dequeue(&tun->readq))) {
 			if (file->f_flags & O_NONBLOCK) {
 				ret = -EAGAIN;
 				break;
@@ -334,50 +332,83 @@
 	return -ESPIPE;
 }
 
-static int tun_set_iff(struct tun_struct *tun, unsigned long arg)
+static int tun_set_iff(struct file *file, struct ifreq *ifr)
 {
-	struct ifreq ifr;
-	char *mask;
+	struct tun_struct *tun;
+	struct net_device *dev;
+	int err;
+
+	dev = __dev_get_by_name(ifr->ifr_name);
+	if (dev) {
+		/* Device exist */
+		tun = dev->priv;
+
+		if (dev->init != tun_net_init || tun->attached)
+			return -EBUSY;
+
+		/* Check permissions */
+		if (tun->owner != -1)
+			if (current->euid != tun->owner && !capable(CAP_NET_ADMIN))
+				return -EPERM;
+	} else {
+		char *name;
+
+		/* Allocate new device */
+		if (!(tun = kmalloc(sizeof(struct tun_struct), GFP_KERNEL)) )
+			return -ENOMEM;
+		memset(tun, 0, sizeof(struct tun_struct));
+
+		skb_queue_head_init(&tun->readq);
+		init_waitqueue_head(&tun->read_wait);
+
+		tun->owner = -1;
+		tun->dev.init = tun_net_init;
+		tun->dev.priv = tun;
+
+		err = -EINVAL;
+
+		/* Set dev type */
+		if (ifr->ifr_flags & IFF_TUN) {
+			/* TUN device */
+			tun->flags |= TUN_TUN_DEV;
+			name = "tun%d";
+		} else if (ifr->ifr_flags & IFF_TAP) {
+			/* TAP device */
+			tun->flags |= TUN_TAP_DEV;
+			name = "tap%d";
+		} else 
+			goto failed;
+   
+		if (*ifr->ifr_name)
+			name = ifr->ifr_name;
 
-	if (copy_from_user(&ifr, (void *)arg, sizeof(ifr)))
-		return -EFAULT;
-	ifr.ifr_name[IFNAMSIZ-1] = '\0';
+		if ((err = dev_alloc_name(&tun->dev, name)) < 0)
+			goto failed;
+		if ((err = register_netdevice(&tun->dev)))
+			goto failed;
+	
+		MOD_INC_USE_COUNT;
 
-	if (tun->flags & TUN_IFF_SET)
-		return -EEXIST;
+		tun->name = tun->dev.name;
+	}
 
-	/* Set dev type */
-	if (ifr.ifr_flags & IFF_TUN) {
-		/* TUN device */
-		tun->flags |= TUN_TUN_DEV;
-		mask = "tun%d";
-	} else if (ifr.ifr_flags & IFF_TAP) {
-		/* TAP device */
-		tun->flags |= TUN_TAP_DEV;
-		mask = "tap%d";
-	} else 
-		return -EINVAL;
-   
-	if (ifr.ifr_flags & IFF_NO_PI)
+	DBG(KERN_INFO "%s: tun_set_iff\n", tun->name);
+
+	if (ifr->ifr_flags & IFF_NO_PI)
 		tun->flags |= TUN_NO_PI;
 
-	if (*ifr.ifr_name)
-		strcpy(tun->dev.name, ifr.ifr_name);
-	else
-		strcpy(tun->dev.name, mask);
-
-	/* Register net device */
-	if (register_netdev(&tun->dev))
-		return -EBUSY;
-
-	tun->flags |= TUN_IFF_SET;
-	strcpy(tun->name, tun->dev.name);
-
-	/* Return iface info to the user space */
-	strcpy(ifr.ifr_name, tun->dev.name);
-	copy_to_user((void *)arg, &ifr, sizeof(ifr));
+	if (ifr->ifr_flags & IFF_ONE_QUEUE)
+		tun->flags |= TUN_ONE_QUEUE;
+
+	file->private_data = tun;
+	tun->attached = 1;
+
+	strcpy(ifr->ifr_name, tun->name);
+	return 0;
 
-	return 0;   
+failed:
+	kfree(tun);
+	return err;
 }
 
 static int tun_chr_ioctl(struct inode *inode, struct file *file, 
@@ -385,14 +416,33 @@
 {
 	struct tun_struct *tun = (struct tun_struct *)file->private_data;
 
-	DBG(KERN_INFO "%s: tun_chr_ioctl\n", tun->name);
+	if (cmd == TUNSETIFF && !tun) {
+		struct ifreq ifr;
+		int err;
+
+		if (copy_from_user(&ifr, (void *)arg, sizeof(ifr)))
+			return -EFAULT;
+		ifr.ifr_name[IFNAMSIZ-1] = '\0';
 
-	switch (cmd) {
-	case TUNSETIFF:
-		return tun_set_iff(tun, arg); 
+		rtnl_lock();
+		err = tun_set_iff(file, &ifr);
+		rtnl_unlock();
 
+		if (err)
+			return err;
+
+		copy_to_user((void *)arg, &ifr, sizeof(ifr));
+		return 0;
+	}
+
+	if (!tun)
+		return -EBADFD;
+
+	DBG(KERN_INFO "%s: tun_chr_ioctl cmd %d\n", tun->name, cmd);
+
+	switch (cmd) {
 	case TUNSETNOCSUM:
-		/* Disable/Enable checksum on net iface */
+		/* Disable/Enable checksum */
 		if (arg)
 			tun->flags |= TUN_NOCHECKSUM;
 		else
@@ -402,6 +452,24 @@
 		    tun->name, arg ? "disabled" : "enabled");
 		break;
 
+	case TUNSETPERSIST:
+		/* Disable/Enable persist mode */
+		if (arg)
+			tun->flags |= TUN_PERSIST;
+		else
+			tun->flags &= ~TUN_PERSIST;
+
+		DBG(KERN_INFO "%s: persist %s\n",
+		    tun->name, arg ? "disabled" : "enabled");
+		break;
+
+	case TUNSETOWNER:
+		/* Set owner of the device */
+		tun->owner = (uid_t) arg;
+
+		DBG(KERN_INFO "%s: owner set to %d\n", tun->owner);
+		break;
+
 #ifdef TUN_DEBUG
 	case TUNSETDEBUG:
 		tun->debug = arg;
@@ -420,14 +488,22 @@
 	struct tun_struct *tun = (struct tun_struct *)file->private_data;
 	int ret;
 
+	if (!tun)
+		return -EBADFD;
+
 	DBG(KERN_INFO "%s: tun_chr_fasync %d\n", tun->name, on);
 
 	if ((ret = fasync_helper(fd, file, on, &tun->fasync)) < 0)
 		return ret; 
  
-	if (on)
+	if (on) {
 		tun->flags |= TUN_FASYNC;
-	else 
+		if (!file->f_owner.pid) {
+			file->f_owner.pid  = current->pid;
+			file->f_owner.uid  = current->uid;
+			file->f_owner.euid = current->euid;
+		}
+	} else 
 		tun->flags &= ~TUN_FASYNC;
 
 	return 0;
@@ -435,25 +511,8 @@
 
 static int tun_chr_open(struct inode *inode, struct file * file)
 {
-	struct tun_struct *tun = NULL; 
-
 	DBG1(KERN_INFO "tunX: tun_chr_open\n");
-
-	tun = kmalloc(sizeof(struct tun_struct), GFP_KERNEL);
-	if (tun == NULL)
-		return -ENOMEM;
-
-	memset(tun, 0, sizeof(struct tun_struct));
-	file->private_data = tun;
-
-	skb_queue_head_init(&tun->txq);
-	init_waitqueue_head(&tun->read_wait);
-
-	sprintf(tun->name, "tunX");
-
-	tun->dev.init = tun_net_init;
-	tun->dev.priv = tun;
-
+	file->private_data = NULL;
 	return 0;
 }
 
@@ -461,22 +520,30 @@
 {
 	struct tun_struct *tun = (struct tun_struct *)file->private_data;
 
-	DBG(KERN_INFO "%s: tun_chr_close\n", tun->name);
+	if (!tun)
+		return 0;
 
-	if (tun->flags & TUN_IFF_SET) {
-		rtnl_lock();
-		dev_close(&tun->dev);
-		rtnl_unlock();
+	DBG(KERN_INFO "%s: tun_chr_close\n", tun->name);
 
-		/* Drop TX queue */
-		skb_queue_purge(&tun->txq);
+	tun_chr_fasync(-1, file, 0);
 
-		unregister_netdev(&tun->dev);
-	}
+	rtnl_lock();
 
-	kfree(tun);
+	/* Detach from net device */
 	file->private_data = NULL;
+	tun->attached = 0;
+
+	/* Drop read queue */
+	skb_queue_purge(&tun->readq);
+
+	if (!(tun->flags & TUN_PERSIST)) {
+		dev_close(&tun->dev);
+		unregister_netdevice(&tun->dev);
+		kfree(tun);
+		MOD_DEC_USE_COUNT;
+	}
 
+	rtnl_unlock();
 	return 0;
 }
 
@@ -494,15 +561,15 @@
 
 static struct miscdevice tun_miscdev=
 {
-        TUN_MINOR,
-        "net/tun",
-        &tun_fops
+	TUN_MINOR,
+	"net/tun",
+	&tun_fops
 };
 
 int __init tun_init(void)
 {
 	printk(KERN_INFO "Universal TUN/TAP device driver %s " 
-	       "(C)1999-2000 Maxim Krasnyansky\n", TUN_VER);
+	       "(C)1999-2001 Maxim Krasnyansky\n", TUN_VER);
 
 	if (misc_register(&tun_miscdev)) {
 		printk(KERN_ERR "tun: Can't register misc device %d\n", TUN_MINOR);
diff -u --recursive --new-file v2.4.5/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- v2.4.5/linux/drivers/net/via-rhine.c	Fri Apr 20 11:54:23 2001
+++ linux/drivers/net/via-rhine.c	Wed Jun 20 11:15:44 2001
@@ -1,6 +1,6 @@
 /* via-rhine.c: A Linux Ethernet device driver for VIA Rhine family chips. */
 /*
-	Written 1998-2000 by Donald Becker.
+	Written 1998-2001 by Donald Becker.
 
 	This software may be used and distributed according to the terms of
 	the GNU General Public License (GPL), incorporated herein by reference.
@@ -58,6 +58,12 @@
 	
 	LK1.1.7:
 	- Manfred Spraul: added reset into tx_timeout
+
+	LK1.1.9:
+	- Urban Widmark: merges from Beckers 1.10 version
+	                 (media selection + eeprom reload)
+	- David Vrabel:  merges from D-Link "1.11" version
+	                 (disable WOL and PME on startup)
 */
 
 
@@ -75,6 +81,11 @@
    Both 'options[]' and 'full_duplex[]' should exist for driver
    interoperability.
    The media type is usually passed in 'options[]'.
+   The default is autonegotation for speed and duplex.
+     This should rarely be overridden.
+   Use option values 0x10/0x20 for 10Mbps, 0x100,0x200 for 100Mbps.
+   Use option values 0x10 and 0x100 for forcing half duplex fixed speed.
+   Use option values 0x20 and 0x200 for forcing full duplex operation.
 */
 #define MAX_UNITS 8		/* More are supported, limit only on options */
 static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
@@ -104,6 +115,9 @@
 
 #define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
 
+/* max time out delay time */
+#define W_MAX_TIMEOUT	0x0FFFU
+
 
 #if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
 #warning  You must compile this file with the correct options!
@@ -132,9 +146,10 @@
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
-KERN_INFO "via-rhine.c:v1.08b-LK1.1.8  4/17/2000  Written by Donald Becker\n"
+KERN_INFO "via-rhine.c:v1.10-LK1.1.9  05/31/2001  Written by Donald Becker\n"
 KERN_INFO "  http://www.scyld.com/network/via-rhine.html\n";
 
+static char shortname[] __devinitdata = "via-rhine";
 
 
 /* This driver was written to use PCI memory space, however most versions
@@ -165,7 +180,11 @@
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-
+MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt");
+MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)");
+MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(options, "VIA Rhine: Bits 0-3: media type, bit 17: full duplex");
+MODULE_PARM_DESC(full_duplex, "VIA Rhine full duplex setting(s) (1)");
 
 /*
 				Theory of Operation
@@ -244,6 +263,9 @@
 Preliminary VT86C100A manual from http://www.via.com.tw/
 http://www.scyld.com/expert/100mbps.html
 http://www.scyld.com/expert/NWay.html
+ftp://ftp.via.com.tw/public/lan/Products/NIC/VT86C100A/Datasheet/VT86C100A03.pdf
+ftp://ftp.via.com.tw/public/lan/Products/NIC/VT6102/Datasheet/VT6102_021.PDF
+
 
 IVc. Errata
 
@@ -256,7 +278,6 @@
 */
 
 
-
 /* This table drives the PCI probe routines.  It's mostly boilerplate in all
    of the drivers, and will likely be provided by some future kernel.
    Note the matching code -- the first table entry matchs all 56** cards but
@@ -320,9 +341,9 @@
 	StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08,
 	IntrStatus=0x0C, IntrEnable=0x0E,
 	MulticastFilter0=0x10, MulticastFilter1=0x14,
-	RxRingPtr=0x18, TxRingPtr=0x1C,
+	RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54,
 	MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E,
-	MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72,
+	MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74,
 	Config=0x78, ConfigA=0x7A, RxMissed=0x7C, RxCRCErrs=0x7E,
 	StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC,
 };
@@ -448,24 +469,29 @@
 static int  via_rhine_close(struct net_device *dev);
 static inline void clear_tally_counters(long ioaddr);
 
-static void wait_for_reset(struct net_device *dev)
+static void wait_for_reset(struct net_device *dev, char *name)
 {
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
+	int chip_id = np->chip_id;
 	int i;
 
+	/* 3043 may need long delay after reset (dlink) */
+	if (chip_id == VT3043 || chip_id == VT86C100A)
+		udelay(100);
+
 	i = 0;
 	do {
 		udelay(5);
 		i++;
 		if(i > 2000) {
-			printk(KERN_ERR "%s: reset did not complete in 10 ms.\n",
-					dev->name);
+			printk(KERN_ERR "%s: reset did not complete in 10 ms.\n", name);
 			break;
 		}
 	} while(readw(ioaddr + ChipCmd) & CmdReset);
 	if (debug > 1)
 		printk(KERN_INFO "%s: reset finished after %d microseconds.\n",
-				dev->name, 5*i);
+			   name, 5*i);
 }
 
 static int __devinit via_rhine_init_one (struct pci_dev *pdev,
@@ -515,13 +541,12 @@
 
 	dev = alloc_etherdev(sizeof(*np));
 	if (dev == NULL) {
-		printk (KERN_ERR "init_ethernet failed for card #%d\n",
-			card_idx);
+		printk (KERN_ERR "init_ethernet failed for card #%d\n", card_idx);
 		goto err_out;
 	}
 	SET_MODULE_OWNER(dev);
 	
-	if (pci_request_regions(pdev, "via-rhine"))
+	if (pci_request_regions(pdev, shortname))
 		goto err_out_free_netdev;
 
 #ifndef USE_IO
@@ -534,13 +559,50 @@
 	}
 #endif
 
-	/* Ideally we would read the EEPROM but access may be locked. */
-	for (i = 0; i < 6; i++)
-		dev->dev_addr[i] = readb(ioaddr + StationAddr + i);
+	/* D-Link provided reset code (with comment additions) */
+	if (via_rhine_chip_info[chip_id].drv_flags & HasWOL) {
+		unsigned char byOrgValue;
+
+		/* clear sticky bit before reset & read ethernet address */
+		byOrgValue = readb(ioaddr + StickyHW);
+		byOrgValue = byOrgValue & 0xFC;
+		writeb(byOrgValue, ioaddr + StickyHW);
+
+		/* (bits written are cleared?) */
+		/* disable force PME-enable */
+		writeb(0x80, ioaddr + WOLcgClr);
+		/* disable power-event config bit */
+		writeb(0xFF, ioaddr + WOLcrClr);
+		/* clear power status (undocumented in vt6102 docs?) */
+		writeb(0xFF, ioaddr + PwrcsrClr);
+	}
 
 	/* Reset the chip to erase previous misconfiguration. */
 	writew(CmdReset, ioaddr + ChipCmd);
-	wait_for_reset(dev);
+	wait_for_reset(dev, shortname);
+
+	/* Reload the station address from the EEPROM. */
+	writeb(0x20, ioaddr + MACRegEEcsr);
+	/* Typically 2 cycles to reload. */
+	for (i = 0; i < 150; i++)
+		if (! (readb(ioaddr + MACRegEEcsr) & 0x20))
+			break;
+	for (i = 0; i < 6; i++)
+		dev->dev_addr[i] = readb(ioaddr + StationAddr + i);
+
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		printk(KERN_ERR "Invalid MAC address for card #%d\n", card_idx);
+		goto err_out_unmap;
+	}
+
+	if (chip_id == VT6102) {
+		/*
+		 * for 3065D, EEPROM reloaded will cause bit 0 in MAC_REG_CFGA
+		 * turned on.  it makes MAC receive magic packet
+		 * automatically. So, we turn it off. (D-Link)
+		 */
+		writeb(readb(ioaddr + ConfigA) & 0xFE, ioaddr + ConfigA);
+	}
 
 	dev->base_addr = ioaddr;
 	dev->irq = pdev->irq;
@@ -563,8 +625,11 @@
 	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
 		np->full_duplex = 1;
 
-	if (np->full_duplex)
+	if (np->full_duplex) {
+		printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
+			   " disabled.\n", dev->name);
 		np->duplex_lock = 1;
+	}
 
 	/* The chip-specific entries in the device structure. */
 	dev->open = via_rhine_open;
@@ -611,6 +676,24 @@
 		np->mii_cnt = phy_idx;
 	}
 
+	/* Allow forcing the media type. */
+	if (option > 0) {
+		if (option & 0x220)
+			np->full_duplex = 1;
+		np->default_port = option & 0x3ff;
+		if (np->default_port & 0x330) {
+			/* FIXME: shouldn't someone check this variable? */
+			/* np->medialock = 1; */
+			printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",
+				   (option & 0x300 ? 100 : 10),
+				   (option & 0x220 ? "full" : "half"));
+			if (np->mii_cnt)
+				mdio_write(dev, np->phys[0], 0,
+						   ((option & 0x300) ? 0x2000 : 0) |  /* 100mbps? */
+						   ((option & 0x220) ? 0x0100 : 0));  /* Full duplex? */
+		}
+	}
+
 	return 0;
 
 err_out_unmap:
@@ -890,7 +973,7 @@
 		return i;
 	alloc_rbufs(dev);
 	alloc_tbufs(dev);
-	wait_for_reset(dev);
+	wait_for_reset(dev, dev->name);
 	init_registers(dev);
 	if (debug > 2)
 		printk(KERN_DEBUG "%s: Done via_rhine_open(), status %4.4x "
@@ -997,7 +1080,7 @@
 	alloc_rbufs(dev);
 
 	/* Reinitialize the hardware. */
-	wait_for_reset(dev);
+	wait_for_reset(dev, dev->name);
 	init_registers(dev);
 	
 	spin_unlock(&np->lock);
@@ -1388,7 +1471,9 @@
 		memset(mc_filter, 0, sizeof(mc_filter));
 		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
 			 i++, mclist = mclist->next) {
-			set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter);
+			int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+			mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
 		}
 		writel(mc_filter[0], ioaddr + MulticastFilter0);
 		writel(mc_filter[1], ioaddr + MulticastFilter1);
@@ -1445,7 +1530,7 @@
 			   dev->name, readw(ioaddr + ChipCmd));
 
 	/* Switch to loopback mode to avoid hardware races. */
-	writeb(np->tx_thresh | 0x01, ioaddr + TxConfig);
+	writeb(np->tx_thresh | 0x02, ioaddr + TxConfig);
 
 	/* Disable interrupts by clearing the interrupt mask. */
 	writew(0x0000, ioaddr + IntrEnable);
diff -u --recursive --new-file v2.4.5/linux/drivers/net/wan/hdlc.c linux/drivers/net/wan/hdlc.c
--- v2.4.5/linux/drivers/net/wan/hdlc.c	Wed Apr 18 14:40:07 2001
+++ linux/drivers/net/wan/hdlc.c	Tue Jun 12 11:06:54 2001
@@ -1082,7 +1082,9 @@
 			}
 			break;
 
-		default:		/* to be defined */
+		default:
+			/* to be defined */
+			break;
 		}
 
 		dev_kfree_skb(skb);
diff -u --recursive --new-file v2.4.5/linux/drivers/net/wan/sdla_fr.c linux/drivers/net/wan/sdla_fr.c
--- v2.4.5/linux/drivers/net/wan/sdla_fr.c	Fri Apr 20 11:54:22 2001
+++ linux/drivers/net/wan/sdla_fr.c	Tue Jun 12 11:06:54 2001
@@ -4435,7 +4435,8 @@
 		trigger_fr_poll(dev);
 		
 		break;
-	default:  // ARP's and RARP's -- Shouldn't happen.
+	default:
+		break; // ARP's and RARP's -- Shouldn't happen.
 	}
 
 	return 0;	
diff -u --recursive --new-file v2.4.5/linux/drivers/net/wan/sdla_x25.c linux/drivers/net/wan/sdla_x25.c
--- v2.4.5/linux/drivers/net/wan/sdla_x25.c	Fri Apr 20 11:54:22 2001
+++ linux/drivers/net/wan/sdla_x25.c	Tue Jun 12 11:06:54 2001
@@ -3108,7 +3108,7 @@
 	case 0x08:	/* modem failure */
 #ifndef MODEM_NOT_LOG
 		printk(KERN_INFO "%s: modem failure!\n", card->devname);
-#endif MODEM_NOT_LOG
+#endif /* MODEM_NOT_LOG */
 		api_oob_event(card,mb);
 		break;
 
diff -u --recursive --new-file v2.4.5/linux/drivers/net/wd.c linux/drivers/net/wd.c
--- v2.4.5/linux/drivers/net/wd.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/wd.c	Wed Jun 20 11:10:53 2001
@@ -449,6 +449,10 @@
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_WD_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_WD_CARDS) "i");
 MODULE_PARM(mem_end, "1-" __MODULE_STRING(MAX_WD_CARDS) "i");
+MODULE_PARM_DESC(io, "WD80x3 I/O base address(es)");
+MODULE_PARM_DESC(irq, "WD80x3 IRQ number(s) (ignored for PureData boards)");
+MODULE_PARM_DESC(mem, "WD80x3 memory base address(es)(ignored for PureData boards)");
+MODULE_PARM_DESC(mem_end, "WD80x3 memory end address(es)");
 
 /* This is set up so that only a single autoprobe takes place per call.
 ISA device autoprobes on a running machine are not recommended. */
diff -u --recursive --new-file v2.4.5/linux/drivers/net/winbond-840.c linux/drivers/net/winbond-840.c
--- v2.4.5/linux/drivers/net/winbond-840.c	Fri Apr 20 11:54:23 2001
+++ linux/drivers/net/winbond-840.c	Wed Jun 20 11:13:18 2001
@@ -1,4 +1,4 @@
-/* winbond-840.c: A Linux PCI network adapter skeleton device driver. */
+/* winbond-840.c: A Linux PCI network adapter device driver. */
 /*
 	Written 1998-2001 by Donald Becker.
 
@@ -38,6 +38,11 @@
 		descriptors. Remove cpu_to_le32, enable BE descriptors.
 */
 
+#define DRV_NAME	"winbond-840"
+#define DRV_VERSION	"1.01"
+#define DRV_RELDATE	"5/15/2000"
+
+
 /* Automatically extracted configuration info:
 probe-func: winbond840_probe
 config-in: tristate 'Winbond W89c840 Ethernet support' CONFIG_WINBOND_840
@@ -122,13 +127,15 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
-KERN_INFO "winbond-840.c:v1.01 (2.4 port) 5/15/2000  Donald Becker <becker@scyld.com>\n"
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " (2.4 port) " DRV_RELDATE "  Donald Becker <becker@scyld.com>\n"
 KERN_INFO "  http://www.scyld.com/network/drivers.html\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
@@ -139,6 +146,12 @@
 MODULE_PARM(multicast_filter_limit, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM_DESC(max_interrupt_work, "winbond-840 maximum events handled per interrupt");
+MODULE_PARM_DESC(debug, "winbond-840 debug level (0-6)");
+MODULE_PARM_DESC(rx_copybreak, "winbond-840 copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(multicast_filter_limit, "winbond-840 maximum number of filtered multicast addresses");
+MODULE_PARM_DESC(options, "winbond-840: Bits 0-3: media type, bit 17: full duplex");
+MODULE_PARM_DESC(full_duplex, "winbond-840 full duplex setting(s) (1)");
 
 /*
 				Theory of Operation
@@ -366,7 +379,7 @@
 static inline unsigned ether_crc(int length, unsigned char *data);
 static void set_rx_mode(struct net_device *dev);
 static struct net_device_stats *get_stats(struct net_device *dev);
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int  netdev_close(struct net_device *dev);
 
 
@@ -399,7 +412,7 @@
 		return -ENOMEM;
 	SET_MODULE_OWNER(dev);
 
-	if (pci_request_regions(pdev, "winbond-840"))
+	if (pci_request_regions(pdev, DRV_NAME))
 		goto err_out_netdev;
 
 #ifdef USE_IO_OPS
@@ -453,7 +466,7 @@
 	dev->stop = &netdev_close;
 	dev->get_stats = &get_stats;
 	dev->set_multicast_list = &set_rx_mode;
-	dev->do_ioctl = &mii_ioctl;
+	dev->do_ioctl = &netdev_ioctl;
 	dev->tx_timeout = &tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
@@ -1312,11 +1325,37 @@
 	writel(np->csr6, ioaddr + NetworkConfig);
 }
 
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct netdev_private *np = dev->priv;
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+
+        switch (ethcmd) {
+        case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strcpy(info.driver, DRV_NAME);
+		strcpy(info.version, DRV_VERSION);
+		strcpy(info.bus_info, np->pci_dev->slot_name);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+
+        }
+	
+	return -EOPNOTSUPP;
+}
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	u16 *data = (u16 *)&rq->ifr_data;
 
 	switch(cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 		data[0] = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f;
 		/* Fall Through */
@@ -1403,7 +1442,7 @@
 }
 
 static struct pci_driver w840_driver = {
-	name:		"winbond-840",
+	name:		DRV_NAME,
 	id_table:	w840_pci_tbl,
 	probe:		w840_probe1,
 	remove:		w840_remove1,
diff -u --recursive --new-file v2.4.5/linux/drivers/net/wireless/Config.in linux/drivers/net/wireless/Config.in
--- v2.4.5/linux/drivers/net/wireless/Config.in	Mon May  7 19:42:14 2001
+++ linux/drivers/net/wireless/Config.in	Wed Jun 20 11:13:18 2001
@@ -2,21 +2,26 @@
 # Wireless LAN device configuration
 #
 
-###tristate '  Hermes chipset support' CONFIG_NET_ORINOCO
-###dep_tristate '    PCMCIA Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES $CONFIG_NET_ORINOCO $CONFIG_PCMCIA
+if [ "$CONFIG_ISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
+   tristate '  Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards' CONFIG_AIRO
+fi
 
 if [ "$CONFIG_ALL_PPC" = "y" ]; then
    tristate '  Apple Airport support (built-in)' CONFIG_APPLE_AIRPORT
 fi
 
 # If Pcmcia is compiled in, offer Pcmcia cards...
-if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
+if [ "$CONFIG_PCMCIA" != "n" ]; then
    comment 'Wireless Pcmcia cards support' 
 
-   dep_tristate '  Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES $CONFIG_PCMCIA
+   tristate '  Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES
+   tristate '  Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards' CONFIG_AIRO_CS
+fi
 
-# If one of the Pcmcia cards above is enabled, activate Pcmcia network support
-   if [ "$CONFIG_PCMCIA_HERMES" = "y" ]; then
-      define_bool CONFIG_PCMCIA_NETCARD y
-   fi
+# yes, this works even when no drivers are selected
+if [ "$CONFIG_ISA" = "y" -o "$CONFIG_PCI" = "y" -o \
+     "$CONFIG_ALL_PPC" = "y" -o "$CONFIG_PCMCIA" != "n" ]; then
+   define_bool CONFIG_NET_WIRELESS y
+else
+   define_bool CONFIG_NET_WIRELESS n
 fi
diff -u --recursive --new-file v2.4.5/linux/drivers/net/wireless/Makefile linux/drivers/net/wireless/Makefile
--- v2.4.5/linux/drivers/net/wireless/Makefile	Mon May  7 19:42:14 2001
+++ linux/drivers/net/wireless/Makefile	Wed Jun 20 11:13:18 2001
@@ -4,7 +4,7 @@
 # Makefile for the Linux Wireless network device drivers.
 #
 
-O_TARGET := orinoco_drvs.o
+O_TARGET := wireless_net.o
 
 obj-y		:=
 obj-m		:=
@@ -12,16 +12,12 @@
 obj-		:=
 
 # Things that need to export symbols
-export-objs	:= orinoco.o hermes.o
+export-objs	:= airo.o orinoco.o hermes.o
 
-# ISA Bus cards
-
-# PCI bus cards
-
-# Other cards
+obj-$(CONFIG_PCMCIA_HERMES)	+= orinoco_cs.o orinoco.o hermes.o
 obj-$(CONFIG_APPLE_AIRPORT)	+= airport.o orinoco.o hermes.o
 
-# 16-bit Pcmcia wireless client drivers
-obj-$(CONFIG_PCMCIA_HERMES)	+= orinoco_cs.o orinoco.o hermes.o
+obj-$(CONFIG_AIRO)		+= airo.o
+obj-$(CONFIG_AIRO_CS)		+= airo_cs.o airo.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.5/linux/drivers/net/wireless/airo.c linux/drivers/net/wireless/airo.c
--- v2.4.5/linux/drivers/net/wireless/airo.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/airo.c	Wed Jun 20 11:10:53 2001
@@ -0,0 +1,4321 @@
+/*======================================================================
+
+    Aironet driver for 4500 and 4800 series cards
+
+    This code is released under both the GPL version 2 and BSD licenses.
+    Either license may be used.  The respective licenses are found at
+    the end of this file.
+
+    This code was developed by Benjamin Reed <breed@users.sourceforge.net>
+    including portions of which come from the Aironet PC4500
+    Developer's Reference Manual and used with permission.  Copyright
+    (C) 1999 Benjamin Reed.  All Rights Reserved.  Permission to use
+    code in the Developer's manual was granted for this driver by
+    Aironet.  Major code contributions were received from Javier Achirica
+    and Jean Tourrilhes <jt@hpl.hp.com>.  Code was also integrated from
+    the Cisco Aironet driver for Linux.
+    
+======================================================================*/
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <asm/segment.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/pci.h>
+
+#ifdef CONFIG_PCI
+static struct pci_device_id card_ids[] = __devinitdata {
+	{ 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID },
+	{ 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0x14b9, 0x0340, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0x14b9, 0x0350, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, } 
+};
+MODULE_DEVICE_TABLE(pci, card_ids);
+
+static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *);
+static void airo_pci_remove(struct pci_dev *);
+
+static struct pci_driver airo_driver = {
+	name:     "airo",
+	id_table: card_ids,
+	probe:    airo_pci_probe,
+	remove:   airo_pci_remove,
+};
+#endif /* CONFIG_PCI */
+
+/* Include Wireless Extension definition and check version - Jean II */
+#include <linux/wireless.h>
+#if WIRELESS_EXT < 9
+#warning "Wireless extension v9 or newer required - please upgrade your kernel"
+#undef WIRELESS_EXT
+#endif
+#define WIRELESS_SPY		// enable iwspy support
+#define CISCO_EXT		// enable Cisco extensions
+
+#ifdef CISCO_EXT
+#include <linux/delay.h>
+#endif
+
+/* As you can see this list is HUGH!
+   I really don't know what a lot of these counts are about, but they
+   are all here for completeness.  If the IGNLABEL macro is put in
+   infront of the label, that statistic will not be included in the list
+   of statistics in the /proc filesystem */
+
+#define IGNLABEL 0&(int)
+static char *statsLabels[] = {
+	"RxOverrun",
+	IGNLABEL "RxPlcpCrcErr",
+	IGNLABEL "RxPlcpFormatErr",
+	IGNLABEL "RxPlcpLengthErr",
+	"RxMacCrcErr",
+	"RxMacCrcOk",
+	"RxWepErr",
+	"RxWepOk",
+	"RetryLong",
+	"RetryShort",
+	"MaxRetries",
+	"NoAck",
+	"NoCts",
+	"RxAck",
+	"RxCts",
+	"TxAck",
+	"TxRts",
+	"TxCts",
+	"TxMc",
+	"TxBc",
+	"TxUcFrags",
+	"TxUcPackets",
+	"TxBeacon",
+	"RxBeacon",
+	"TxSinColl",
+	"TxMulColl",
+	"DefersNo",
+	"DefersProt",
+	"DefersEngy",
+	"DupFram",
+	"RxFragDisc",
+	"TxAged",
+	"RxAged",
+	"LostSync-MaxRetry",
+	"LostSync-MissedBeacons",
+	"LostSync-ArlExceeded",
+	"LostSync-Deauth",
+	"LostSync-Disassoced",
+	"LostSync-TsfTiming",
+	"HostTxMc",
+	"HostTxBc",
+	"HostTxUc",
+	"HostTxFail",
+	"HostRxMc",
+	"HostRxBc",
+	"HostRxUc",
+	"HostRxDiscard",
+	IGNLABEL "HmacTxMc",
+	IGNLABEL "HmacTxBc",
+	IGNLABEL "HmacTxUc",
+	IGNLABEL "HmacTxFail",
+	IGNLABEL "HmacRxMc",
+	IGNLABEL "HmacRxBc",
+	IGNLABEL "HmacRxUc",
+	IGNLABEL "HmacRxDiscard",
+	IGNLABEL "HmacRxAccepted",
+	"SsidMismatch",
+	"ApMismatch",
+	"RatesMismatch",
+	"AuthReject",
+	"AuthTimeout",
+	"AssocReject",
+	"AssocTimeout",
+	IGNLABEL "ReasonOutsideTable",
+	IGNLABEL "ReasonStatus1",
+	IGNLABEL "ReasonStatus2",
+	IGNLABEL "ReasonStatus3",
+	IGNLABEL "ReasonStatus4",
+	IGNLABEL "ReasonStatus5",
+	IGNLABEL "ReasonStatus6",
+	IGNLABEL "ReasonStatus7",
+	IGNLABEL "ReasonStatus8",
+	IGNLABEL "ReasonStatus9",
+	IGNLABEL "ReasonStatus10",
+	IGNLABEL "ReasonStatus11",
+	IGNLABEL "ReasonStatus12",
+	IGNLABEL "ReasonStatus13",
+	IGNLABEL "ReasonStatus14",
+	IGNLABEL "ReasonStatus15",
+	IGNLABEL "ReasonStatus16",
+	IGNLABEL "ReasonStatus17",
+	IGNLABEL "ReasonStatus18",
+	IGNLABEL "ReasonStatus19",
+	"RxMan",
+	"TxMan",
+	"RxRefresh",
+	"TxRefresh",
+	"RxPoll",
+	"TxPoll",
+	"HostRetries",
+	"LostSync-HostReq",
+	"HostTxBytes",
+	"HostRxBytes",
+	"ElapsedUsec",
+	"ElapsedSec",
+	"LostSyncBetterAP",
+	"PrivacyMismatch",
+	"Jammed",
+	"DiscRxNotWepped",
+	"PhyEleMismatch",
+	(char*)-1 };
+#ifndef RUN_AT
+#define RUN_AT(x) (jiffies+(x))
+#endif
+
+
+/* These variables are for insmod, since it seems that the rates
+   can only be set in setup_card.  Rates should be a comma separated
+   (no spaces) list of rates (up to 8). */
+
+static int rates[8];
+static int basic_rate;
+static char *ssids[3];
+
+static int io[4];
+static int irq[4];
+
+static
+int maxencrypt /* = 0 */; /* The highest rate that the card can encrypt at.
+		       0 means no limit.  For old cards this was 4 */
+
+static int auto_wep /* = 0 */; /* If set, it tries to figure out the wep mode */
+static int aux_bap /* = 0 */; /* Checks to see if the aux ports are needed to read
+		    the bap, needed on some older cards and buses. */   
+static int adhoc;
+
+static int proc_uid /* = 0 */;
+
+static int proc_gid /* = 0 */;
+
+static int airo_perm = 0555;
+
+static int proc_perm = 0644;
+
+MODULE_AUTHOR("Benjamin Reed");
+MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \
+                   cards.  Direct support for ISA/PCI cards and support \
+		   for PCMCIA when used with airo_cs.");
+MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340");
+MODULE_PARM(io,"1-4i");
+MODULE_PARM(irq,"1-4i");
+MODULE_PARM(basic_rate,"i");
+MODULE_PARM(rates,"1-8i");
+MODULE_PARM(ssids,"1-3s");
+MODULE_PARM(auto_wep,"i");
+MODULE_PARM_DESC(auto_wep, "If non-zero, the driver will keep looping through \
+the authentication options until an association is made.  The value of \
+auto_wep is number of the wep keys to check.  A value of 2 will try using \
+the key at index 0 and index 1.");
+MODULE_PARM(aux_bap,"i");
+MODULE_PARM_DESC(aux_bap, "If non-zero, the driver will switch into a mode \
+than seems to work better for older cards with some older buses.  Before \
+switching it checks that the switch is needed.");
+MODULE_PARM(maxencrypt, "i");
+MODULE_PARM_DESC(maxencrypt, "The maximum speed that the card can do \
+encryption.  Units are in 512kbs.  Zero (default) means there is no limit. \
+Older cards used to be limited to 2mbs (4).");
+MODULE_PARM(adhoc, "i");
+MODULE_PARM_DESC(adhoc, "If non-zero, the card will start in adhoc mode.");
+
+MODULE_PARM(proc_uid, "i");
+MODULE_PARM_DESC(proc_uid, "The uid that the /proc files will belong to.");
+MODULE_PARM(proc_gid, "i");
+MODULE_PARM_DESC(proc_gid, "The gid that the /proc files will belong to.");
+MODULE_PARM(airo_perm, "i");
+MODULE_PARM_DESC(airo_perm, "The permission bits of /proc/[driver/]aironet.");
+MODULE_PARM(proc_perm, "i");
+MODULE_PARM_DESC(proc_perm, "The permission bits of the files in /proc");
+
+#include <asm/uaccess.h>
+
+#define min(x,y) ((x<y)?x:y)
+
+/* This is a kind of sloppy hack to get this information to OUT4500 and
+   IN4500.  I would be extremely interested in the situation where this
+   doesnt work though!!! */
+static int do8bitIO = 0;
+
+/* Return codes */
+#define SUCCESS 0
+#define ERROR -1
+#define NO_PACKET -2
+
+/* Commands */
+#define NOP 0x0010
+#define MAC_ENABLE 0x0001
+#define MAC_DISABLE 0x0002
+#define CMD_ACCESS 0x0021
+#define CMD_ALLOCATETX 0x000a
+#define CMD_TRANSMIT 0x000b
+#define HOSTSLEEP 0x85
+#define CMD_SETMODE 0x0009
+#define CMD_ENABLEAUX 0x0111
+#define CMD_SOFTRESET 0x0004
+
+/* Registers */
+#define COMMAND 0x00
+#define PARAM0 0x02
+#define PARAM1 0x04
+#define PARAM2 0x06
+#define STATUS 0x08
+#define RESP0 0x0a
+#define RESP1 0x0c
+#define RESP2 0x0e
+#define LINKSTAT 0x10
+#define SELECT0 0x18
+#define OFFSET0 0x1c
+#define RXFID 0x20
+#define TXALLOCFID 0x22
+#define TXCOMPLFID 0x24
+#define DATA0 0x36
+#define EVSTAT 0x30
+#define EVINTEN 0x32
+#define EVACK 0x34
+#define SWS0 0x28
+#define SWS1 0x2a
+#define SWS2 0x2c
+#define SWS3 0x2e
+#define AUXPAGE 0x3A
+#define AUXOFF 0x3C
+#define AUXDATA 0x3E
+
+/* BAP selectors */
+#define BAP0 0 // Used for receiving packets
+#define BAP1 2 // Used for xmiting packets and working with RIDS
+
+/* Flags */
+#define COMMAND_BUSY 0x8000
+
+#define BAP_BUSY 0x8000
+#define BAP_ERR 0x4000
+#define BAP_DONE 0x2000
+
+#define PROMISC 0xffff
+#define NOPROMISC 0x0000
+
+#define EV_CMD 0x10
+#define EV_CLEARCOMMANDBUSY 0x4000
+#define EV_RX 0x01
+#define EV_TX 0x02
+#define EV_TXEXC 0x04
+#define EV_ALLOC 0x08
+#define EV_LINK 0x80
+#define EV_AWAKE 0x100
+#define EV_UNKNOWN 0x800
+#define STATUS_INTS ( EV_AWAKE | EV_LINK | EV_TXEXC | EV_TX | EV_RX | EV_UNKNOWN)
+
+/* The RIDs */
+#define RID_CAPABILITIES 0xFF00
+#define RID_CONFIG     0xFF10
+#define RID_SSID       0xFF11
+#define RID_APLIST     0xFF12
+#define RID_DRVNAME    0xFF13
+#define RID_ETHERENCAP 0xFF14
+#define RID_WEP_TEMP   0xFF15
+#define RID_WEP_PERM   0xFF16
+#define RID_MODULATION 0xFF17
+#define RID_ACTUALCONFIG 0xFF20 /*readonly*/
+#define RID_LEAPUSERNAME 0xFF23
+#define RID_LEAPPASSWORD 0xFF24
+#define RID_STATUS     0xFF50
+#define RID_STATS      0xFF68
+#define RID_STATSDELTA 0xFF69
+#define RID_STATSDELTACLEAR 0xFF6A
+
+/*
+ * Rids and endian-ness:  The Rids will always be in cpu endian, since
+ * this all the patches from the big-endian guys end up doing that.
+ * so all rid access should use the read/writeXXXRid routines.
+ */
+
+/* This structure came from an email sent to me from an engineer at
+   aironet for inclusion into this driver */
+typedef struct {
+	u16 len;
+	u16 kindex;
+	u8 mac[6];
+	u16 klen;
+	u8 key[16];
+} WepKeyRid;
+
+/* These structures are from the Aironet's PC4500 Developers Manual */
+typedef struct {
+	u16 len;
+	u8 ssid[32];
+} Ssid;
+
+typedef struct {
+	u16 len;
+	Ssid ssids[3];
+} SsidRid;
+
+typedef struct {
+        u16 len;
+        u16 modulation;
+#define MOD_DEFAULT 0
+#define MOD_CCK 1
+#define MOD_MOK 2
+} ModulationRid;
+
+typedef struct {
+	u16 cmd;
+	u16 parm0;
+	u16 parm1;
+	u16 parm2;
+} Cmd;
+
+typedef struct {
+	u16 status;
+	u16 rsp0;
+	u16 rsp1;
+	u16 rsp2;
+} Resp;
+
+typedef struct {
+	u16 len; /* sizeof(ConfigRid) */
+	u16 opmode; /* operating mode */
+#define MODE_STA_IBSS 0
+#define MODE_STA_ESS 1
+#define MODE_AP 2
+#define MODE_AP_RPTR 3
+#define MODE_ETHERNET_HOST (0<<8) /* rx payloads converted */
+#define MODE_LLC_HOST (1<<8) /* rx payloads left as is */
+#define MODE_AIRONET_EXTEND (1<<9) /* enable Aironet extenstions */
+#define MODE_AP_INTERFACE (1<<10) /* enable ap interface extensions */
+#define MODE_ANTENNA_ALIGN (1<<11) /* enable antenna alignment */
+#define MODE_ETHER_LLC (1<<12) /* enable ethernet LLC */
+#define MODE_LEAF_NODE (1<<13) /* enable leaf node bridge */
+#define MODE_CF_POLLABLE (1<<14) /* enable CF pollable */
+	u16 rmode; /* receive mode */
+#define RXMODE_BC_MC_ADDR 0
+#define RXMODE_BC_ADDR 1 /* ignore multicasts */
+#define RXMODE_ADDR 2 /* ignore multicast and broadcast */
+#define RXMODE_RFMON 3 /* wireless monitor mode */
+#define RXMODE_RFMON_ANYBSS 4
+#define RXMODE_LANMON 5 /* lan style monitor -- data packets only */
+#define RXMODE_DISABLE_802_3_HEADER (1<<8) /* disables 802.3 header on rx */
+#define RXMODE_NORMALIZED_RSSI (1<<9) /* return normalized RSSI */
+	u16 fragThresh;
+	u16 rtsThres;
+	u8 macAddr[6];
+	u8 rates[8];
+	u16 shortRetryLimit;
+	u16 longRetryLimit;
+	u16 txLifetime; /* in kusec */
+	u16 rxLifetime; /* in kusec */
+	u16 stationary;
+	u16 ordering;
+	u16 u16deviceType; /* for overriding device type */
+	u16 cfpRate;
+	u16 cfpDuration;
+	u16 _reserved1[3];
+	/*---------- Scanning/Associating ----------*/
+	u16 scanMode;
+#define SCANMODE_ACTIVE 0
+#define SCANMODE_PASSIVE 1
+#define SCANMODE_AIROSCAN 2
+	u16 probeDelay; /* in kusec */
+	u16 probeEnergyTimeout; /* in kusec */
+        u16 probeResponseTimeout;
+	u16 beaconListenTimeout;
+	u16 joinNetTimeout;
+	u16 authTimeout;
+	u16 authType;
+#define AUTH_OPEN 0x1
+#define AUTH_ENCRYPT 0x101
+#define AUTH_SHAREDKEY 0x102
+#define AUTH_ALLOW_UNENCRYPTED 0x200
+	u16 associationTimeout;
+	u16 specifiedApTimeout;
+	u16 offlineScanInterval;
+	u16 offlineScanDuration;
+	u16 linkLossDelay;
+	u16 maxBeaconLostTime;
+	u16 refreshInterval;
+#define DISABLE_REFRESH 0xFFFF
+	u16 _reserved1a[1];
+	/*---------- Power save operation ----------*/
+	u16 powerSaveMode;
+#define POWERSAVE_CAM 0
+#define POWERSAVE_PSP 1
+#define POWERSAVE_PSPCAM 2
+	u16 sleepForDtims;
+	u16 listenInterval;
+	u16 fastListenInterval;
+	u16 listenDecay;
+	u16 fastListenDelay;
+	u16 _reserved2[2];
+	/*---------- Ap/Ibss config items ----------*/
+	u16 beaconPeriod;
+	u16 atimDuration;
+	u16 hopPeriod;
+	u16 channelSet;
+	u16 channel;
+	u16 dtimPeriod;
+	u16 bridgeDistance;
+	u16 radioID;
+	/*---------- Radio configuration ----------*/
+	u16 radioType;
+#define RADIOTYPE_DEFAULT 0
+#define RADIOTYPE_802_11 1
+#define RADIOTYPE_LEGACY 2
+	u8 rxDiversity;
+	u8 txDiversity;
+	u16 txPower;
+#define TXPOWER_DEFAULT 0
+	u16 rssiThreshold;
+#define RSSI_DEFAULT 0
+        u16 modulation;
+	u16 shortPreamble;
+	u16 homeProduct;
+	u16 radioSpecific;
+	/*---------- Aironet Extensions ----------*/
+	u8 nodeName[16];
+	u16 arlThreshold;
+	u16 arlDecay;
+	u16 arlDelay;
+	u16 _reserved4[1];
+	/*---------- Aironet Extensions ----------*/
+	u16 magicAction;
+#define MAGIC_ACTION_STSCHG 1
+#define MACIC_ACTION_RESUME 2
+#define MAGIC_IGNORE_MCAST (1<<8)
+#define MAGIC_IGNORE_BCAST (1<<9)
+#define MAGIC_SWITCH_TO_PSP (0<<10)
+#define MAGIC_STAY_IN_CAM (1<<10)
+	u16 magicControl;
+	u16 autoWake;
+} ConfigRid;
+
+typedef struct {
+	u16 len;
+	u8 mac[6];
+	u16 mode;
+	u16 errorCode;
+	u16 sigQuality;
+	u16 SSIDlen;
+	char SSID[32];
+	char apName[16];
+	char bssid[4][6];
+	u16 beaconPeriod;
+	u16 dimPeriod;
+	u16 atimDuration;
+	u16 hopPeriod;
+	u16 channelSet;
+	u16 channel;
+	u16 hopsToBackbone;
+	u16 apTotalLoad;
+	u16 generatedLoad;
+	u16 accumulatedArl;
+	u16 signalQuality;
+	u16 currentXmitRate;
+	u16 apDevExtensions;
+	u16 normalizedSignalStrength;
+	u16 _reserved[10];
+} StatusRid;
+
+typedef struct {
+	u16 len;
+	u16 spacer;
+	u32 vals[100];
+} StatsRid;
+	
+
+typedef struct {
+	u16 len;
+	u8 ap[4][6];
+} APListRid;
+
+typedef struct {
+	u16 len;
+	char oui[3];
+	u16 prodNum;
+	char manName[32];
+	char prodName[16];
+	char prodVer[8];
+	char factoryAddr[6];
+	char aironetAddr[6];
+	u16 radioType;
+	u16 country;
+	char callid[6];
+	char supportedRates[8];
+	char rxDiversity;
+	char txDiversity;
+	u16 txPowerLevels[8];
+	u16 hardVer;
+	u16 hardCap;
+	u16 tempRange;
+	u16 softVer;
+	u16 softSubVer;
+	u16 interfaceVer;
+	u16 softCap;
+	u16 bootBlockVer;
+	u16 requiredHard;
+} CapabilityRid;
+
+#define TXCTL_TXOK (1<<1) /* report if tx is ok */
+#define TXCTL_TXEX (1<<2) /* report if tx fails */
+#define TXCTL_802_3 (0<<3) /* 802.3 packet */
+#define TXCTL_802_11 (1<<3) /* 802.11 mac packet */
+#define TXCTL_ETHERNET (0<<4) /* payload has ethertype */
+#define TXCTL_LLC (1<<4) /* payload is llc */
+#define TXCTL_RELEASE (0<<5) /* release after completion */
+#define TXCTL_NORELEASE (1<<5) /* on completion returns to host */
+
+#define BUSY_FID 0x10000
+
+#ifdef CISCO_EXT
+#define AIROMAGIC	0xa55a
+#define AIROIOCTL	SIOCDEVPRIVATE
+#define AIROIDIFC 	AIROIOCTL + 1
+
+/* Ioctl constants to be used in airo_ioctl.command */
+
+#define	AIROGCAP  		0	// Capability rid
+#define AIROGCFG		1       // USED A LOT 
+#define AIROGSLIST		2	// System ID list 
+#define AIROGVLIST		3       // List of specified AP's
+#define AIROGDRVNAM		4	//  NOTUSED
+#define AIROGEHTENC		5	// NOTUSED
+#define AIROGWEPKTMP		6
+#define AIROGWEPKNV		7
+#define AIROGSTAT		8
+#define AIROGSTATSC32		9
+#define AIROGSTATSD32		10
+
+/* Leave gap of 40 commands after AIROGSTATSD32 for future */
+
+#define AIROPCAP               	AIROGSTATSD32 + 40
+#define AIROPVLIST              AIROPCAP      + 1
+#define AIROPSLIST		AIROPVLIST    + 1
+#define AIROPCFG		AIROPSLIST    + 1
+#define AIROPSIDS		AIROPCFG      + 1
+#define AIROPAPLIST		AIROPSIDS     + 1
+#define AIROPMACON		AIROPAPLIST   + 1	/* Enable mac  */
+#define AIROPMACOFF		AIROPMACON    + 1 	/* Disable mac */
+#define AIROPSTCLR		AIROPMACOFF   + 1
+#define AIROPWEPKEY		AIROPSTCLR    + 1
+#define AIROPWEPKEYNV		AIROPWEPKEY   + 1
+#define AIROPLEAPPWD            AIROPWEPKEYNV + 1
+#define AIROPLEAPUSR            AIROPLEAPPWD  + 1
+
+/* Flash codes */
+
+#define AIROFLSHRST	       AIROPWEPKEYNV  + 40
+#define AIROFLSHGCHR           AIROFLSHRST    + 1
+#define AIROFLSHSTFL           AIROFLSHGCHR   + 1
+#define AIROFLSHPCHR           AIROFLSHSTFL   + 1
+#define AIROFLPUTBUF           AIROFLSHPCHR   + 1
+#define AIRORESTART            AIROFLPUTBUF   + 1
+
+#define FLASHSIZE	32768
+
+typedef struct aironet_ioctl {
+	unsigned short command;	// What to do
+	unsigned short len;		// Len of data
+	unsigned char *data;		// d-data
+} aironet_ioctl;
+#endif /* CISCO_EXT */
+
+#ifdef WIRELESS_EXT
+// Frequency list (map channels to frequencies)
+const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+				2447, 2452, 2457, 2462, 2467, 2472, 2484 };
+
+// A few details needed for WEP (Wireless Equivalent Privacy)
+#define MAX_KEY_SIZE 13			// 128 (?) bits
+#define MIN_KEY_SIZE  5			// 40 bits RC4 - WEP
+#define MAX_KEYS      4			// 4 different keys
+typedef struct wep_key_t {
+	u16	len;
+	u8	key[16];	/* 40-bit and 104-bit keys */
+} wep_key_t;
+#endif /* WIRELESS_EXT */
+
+static const char version[] = "airo.c 0.2 (Ben Reed & Javier Achirica)";
+
+struct airo_info;
+
+static int get_dec_u16( char *buffer, int *start, int limit );
+static void OUT4500( struct airo_info *, u16 register, u16 value );
+static unsigned short IN4500( struct airo_info *, u16 register );
+static u16 setup_card(struct airo_info*, u8 *mac, ConfigRid *);
+static void enable_interrupts(struct airo_info*);
+static void disable_interrupts(struct airo_info*);
+static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
+static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap);
+static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen, 
+			int whichbap);
+static int fast_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen, 
+			 int whichbap);
+static int bap_write(struct airo_info*, const u16 *pu16Src, int bytelen,
+		     int whichbap);
+static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd);
+static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len);
+static int PC4500_writerid(struct airo_info*, u16 rid, const void
+			   *pBuf, int len);
+static int do_writerid( struct airo_info*, u16 rid, const void *rid_data, 
+			int len );
+static u16 transmit_allocate(struct airo_info*, int lenPayload);
+static int transmit_802_3_packet(struct airo_info*, u16 TxFid, char
+				 *pPacket, int len);
+
+static void airo_interrupt( int irq, void* dev_id, struct pt_regs
+			    *regs);
+static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+#ifdef WIRELESS_EXT
+struct iw_statistics *airo_get_wireless_stats (struct net_device *dev);
+#endif /* WIRELESS_EXT */
+#ifdef CISCO_EXT
+static int readrids(struct net_device *dev, aironet_ioctl *comp);
+static int writerids(struct net_device *dev, aironet_ioctl *comp);
+int flashcard(struct net_device *dev, aironet_ioctl *comp);
+#endif /* CISCO_EXT */
+
+struct airo_info {
+	struct net_device_stats	stats;
+	int open;
+	struct net_device             *dev;
+	/* Note, we can have MAX_FIDS outstanding.  FIDs are 16-bits, so we
+	   use the high bit to mark wether it is in use. */
+#define MAX_FIDS 6
+	int                           fids[MAX_FIDS];
+	int registered;
+	ConfigRid config;
+	u16 authtype; // Used with auto_wep 
+	char keyindex; // Used with auto wep
+	char defindex; // Used with auto wep
+	struct timer_list timer;
+	struct proc_dir_entry *proc_entry;
+	struct airo_info *next;
+        spinlock_t bap0_lock;
+        spinlock_t bap1_lock;
+        spinlock_t aux_lock;
+        spinlock_t cmd_lock;
+        int flags;
+#define FLAG_PROMISC   0x01
+#define FLAG_RADIO_OFF 0x02
+	int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen, 
+			int whichbap);
+	int (*header_parse)(struct sk_buff*, unsigned char *);
+#ifdef WIRELESS_EXT
+	int			need_commit;	// Need to set config
+	struct iw_statistics	wstats;		// wireless stats
+#ifdef WIRELESS_SPY
+	int			spy_number;
+	u_char			spy_address[IW_MAX_SPY][6];
+	struct iw_quality	spy_stat[IW_MAX_SPY];
+#endif /* WIRELESS_SPY */
+#endif /* WIRELESS_EXT */
+};
+
+static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen, 
+			   int whichbap) {
+	return ai->bap_read(ai, pu16Dst, bytelen, whichbap);
+}
+
+static int setup_proc_entry( struct net_device *dev,
+			     struct airo_info *apriv );
+static int takedown_proc_entry( struct net_device *dev,
+				struct airo_info *apriv );
+
+static int readWepKeyRid(struct airo_info*ai, WepKeyRid *wkr, int temp) {
+	int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM, 
+				wkr, sizeof(*wkr));
+	
+	wkr->len = le16_to_cpu(wkr->len);
+	wkr->kindex = le16_to_cpu(wkr->kindex);
+	wkr->klen = le16_to_cpu(wkr->klen);
+	return rc;
+}
+/* In the writeXXXRid routines we copy the rids so that we don't screwup
+ * the originals when we endian them... */
+static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm) {
+	int rc;
+	WepKeyRid wkr = *pwkr;
+
+	wkr.len = cpu_to_le16(wkr.len);
+	wkr.kindex = cpu_to_le16(wkr.kindex);
+	wkr.klen = cpu_to_le16(wkr.klen);
+	rc = do_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr));
+	if (rc!=SUCCESS) printk(KERN_ERR "airo:  WEP_TEMP set %x\n", rc); 
+	if (perm) {
+		rc = do_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr));
+		if (rc!=SUCCESS) {
+			printk(KERN_ERR "airo:  WEP_PERM set %x\n", rc);
+		}
+	}
+	return rc;
+}
+
+static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) {
+	int i;
+	int rc = PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr));
+
+	ssidr->len = le16_to_cpu(ssidr->len);
+	for(i = 0; i < 3; i++) {
+		ssidr->ssids[i].len = le16_to_cpu(ssidr->ssids[i].len);
+	}
+	return rc;
+}
+static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr) {
+	int rc;
+	int i;
+	SsidRid ssidr = *pssidr;
+
+	ssidr.len = cpu_to_le16(ssidr.len);
+	for(i = 0; i < 3; i++) {
+		ssidr.ssids[i].len = cpu_to_le16(ssidr.ssids[i].len);
+	}
+	rc = do_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr));
+	return rc;
+}
+static int readConfigRid(struct airo_info*ai, ConfigRid *cfgr) {
+	int rc = PC4500_readrid(ai, RID_ACTUALCONFIG, cfgr, sizeof(*cfgr));
+	u16 *s;
+	
+	for(s = &cfgr->len; s <= &cfgr->rtsThres; s++) *s = le16_to_cpu(*s);
+
+	for(s = &cfgr->shortRetryLimit; s <= &cfgr->radioType; s++)
+		*s = le16_to_cpu(*s);
+
+	for(s = &cfgr->txPower; s <= &cfgr->radioSpecific; s++)
+		*s = le16_to_cpu(*s);
+	
+	for(s = &cfgr->arlThreshold; s <= &cfgr->autoWake; s++)
+		*s = le16_to_cpu(*s);
+	
+	return rc;
+}
+static int writeConfigRid(struct airo_info*ai, ConfigRid *pcfgr) {
+	u16 *s;
+	ConfigRid cfgr = *pcfgr;
+	
+	for(s = &cfgr.len; s <= &cfgr.rtsThres; s++) *s = cpu_to_le16(*s);
+
+	for(s = &cfgr.shortRetryLimit; s <= &cfgr.radioType; s++)
+		*s = cpu_to_le16(*s);
+
+	for(s = &cfgr.txPower; s <= &cfgr.radioSpecific; s++)
+		*s = cpu_to_le16(*s);
+	
+	for(s = &cfgr.arlThreshold; s <= &cfgr.autoWake; s++)
+		*s = cpu_to_le16(*s);
+	
+	return do_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr));
+}
+static int readStatusRid(struct airo_info*ai, StatusRid *statr) {
+	int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr));
+	u16 *s;
+
+	statr->len = le16_to_cpu(statr->len);
+	for(s = &statr->mode; s <= &statr->SSIDlen; s++) *s = le16_to_cpu(*s);
+
+	for(s = &statr->beaconPeriod; s <= &statr->_reserved[9]; s++)
+		*s = le16_to_cpu(*s);
+
+	return rc;
+}
+static int readAPListRid(struct airo_info*ai, APListRid *aplr) {
+	int rc =  PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr));
+	aplr->len = le16_to_cpu(aplr->len);
+	return rc;
+}
+static int writeAPListRid(struct airo_info*ai, APListRid *aplr) {
+	int rc;
+	aplr->len = cpu_to_le16(aplr->len);
+	rc = do_writerid(ai, RID_APLIST, aplr, sizeof(*aplr));
+	return rc;
+}
+static int readCapabilityRid(struct airo_info*ai, CapabilityRid *capr) {
+	int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr));
+	u16 *s;
+	
+	capr->len = le16_to_cpu(capr->len);
+	capr->prodNum = le16_to_cpu(capr->prodNum);
+	capr->radioType = le16_to_cpu(capr->radioType);
+	capr->country = le16_to_cpu(capr->country);
+	for(s = &capr->txPowerLevels[0]; s <= &capr->requiredHard; s++)
+		*s = le16_to_cpu(*s);
+	return rc;
+}
+static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid) {
+	int rc = PC4500_readrid(ai, rid, sr, sizeof(*sr));
+	u32 *i;
+
+	sr->len = le16_to_cpu(sr->len);
+	for(i = &sr->vals[0]; i <= &sr->vals[99]; i++) *i = le32_to_cpu(*i);
+	return rc;
+}
+
+static int airo_open(struct net_device *dev) {
+	struct airo_info *info = dev->priv;
+
+	enable_interrupts(info);
+
+	netif_start_queue(dev);
+	return 0;
+}
+
+static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+	s16 len;
+	s16 retval = 0;
+	u16 status;
+	u32 flags;
+	s8 *buffer;
+	int i,j;
+	struct airo_info *priv = (struct airo_info*)dev->priv;
+	u32 *fids = priv->fids;
+	
+	if ( skb == NULL ) {
+		printk( KERN_ERR "airo:  skb == NULL!!!\n" );
+		return 0;
+	}
+	
+	/* Find a vacant FID */
+	spin_lock_irqsave(&priv->bap1_lock, flags);
+	for( j = 0, i = -1; j < MAX_FIDS; j++ ) {
+		if ( !( fids[j] & 0xffff0000 ) ) {
+			if ( i == -1 ) i = j;
+			else break;
+		}
+	}
+	if ( j == MAX_FIDS ) netif_stop_queue(dev);
+	if ( i == -1 ) {
+		retval = -EBUSY;
+		goto tx_done;
+	}
+	
+	len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; /* check min length*/
+	buffer = skb->data;
+	
+	status = transmit_802_3_packet( priv, 
+					fids[i],
+					skb->data, len );
+	
+	if ( status == SUCCESS ) {
+                /* Mark fid as used & save length for later */
+		fids[i] |= (len << 16); 
+		dev->trans_start = jiffies;
+	} else {
+		priv->stats.tx_errors++;
+	}
+ tx_done:
+	spin_unlock_irqrestore(&priv->bap1_lock, flags);
+	dev_kfree_skb(skb);
+	return 0;
+}
+
+static struct net_device_stats *airo_get_stats(struct net_device *dev) {
+	return &(((struct airo_info*)dev->priv)->stats);
+}
+
+static int enable_MAC( struct airo_info *ai, Resp *rsp );
+static void disable_MAC(struct airo_info *ai);
+
+static void airo_set_multicast_list(struct net_device *dev) {
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	Cmd cmd;
+	Resp rsp;
+	  
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd=CMD_SETMODE;
+	cmd.parm0=(dev->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
+	issuecommand(ai, &cmd, &rsp);
+
+	if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) {
+		/* Turn on multicast.  (Should be already setup...) */
+	}
+}
+
+static int airo_set_mac_address(struct net_device *dev, void *p)
+{
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	struct sockaddr *addr = p;
+	ConfigRid cfg;
+
+	readConfigRid (ai, &cfg);
+	memcpy (cfg.macAddr, addr->sa_data, dev->addr_len);
+	writeConfigRid (ai, &cfg);
+	memcpy (dev->dev_addr, addr->sa_data, dev->addr_len);
+	return 0;
+}
+
+static int airo_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > 2400))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+
+static int airo_close(struct net_device *dev) { 
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+
+	netif_stop_queue(dev);
+	disable_interrupts( ai );
+	return 0;
+}
+
+static void del_airo_dev( struct net_device *dev );
+
+void stop_airo_card( struct net_device *dev, int freeres ) 
+{
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	takedown_proc_entry( dev, ai );
+	if (ai->registered) {
+		unregister_netdev( dev );
+		ai->registered = 0;
+	}
+	disable_interrupts(ai);
+	free_irq( dev->irq, dev );
+	if (auto_wep) del_timer_sync(&ai->timer);
+	if (freeres) {
+		/* PCMCIA frees this stuff, so only for PCI and ISA */
+	        release_region( dev->base_addr, 64 );
+        }
+	del_airo_dev( dev );
+	kfree( dev );
+}
+
+static int add_airo_dev( struct net_device *dev ); 
+
+struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
+{
+	struct net_device *dev;
+	struct airo_info *ai;
+	int i, rc;
+	
+	/* Create the network device object. */
+        dev = alloc_etherdev(sizeof(*ai));
+        if (!dev) {
+		printk(KERN_ERR "airo:  Couldn't alloc_etherdev\n");
+		return NULL;
+        }
+	ai = dev->priv;
+	ai->registered = 1;
+        ai->dev = dev;
+	ai->bap0_lock = SPIN_LOCK_UNLOCKED;
+	ai->bap1_lock = SPIN_LOCK_UNLOCKED;
+	ai->aux_lock = SPIN_LOCK_UNLOCKED;
+	ai->cmd_lock = SPIN_LOCK_UNLOCKED;
+	ai->header_parse = dev->hard_header_parse;
+	rc = add_airo_dev( dev );
+	if (rc)
+		goto err_out_free;
+	
+	/* The Airo-specific entries in the device structure. */
+	dev->hard_start_xmit = &airo_start_xmit;
+	dev->get_stats = &airo_get_stats;
+	dev->set_multicast_list = &airo_set_multicast_list;
+	dev->set_mac_address = &airo_set_mac_address;
+	dev->do_ioctl = &airo_ioctl;
+#ifdef WIRELESS_EXT
+	dev->get_wireless_stats = airo_get_wireless_stats;
+#endif /* WIRELESS_EXT */
+	dev->change_mtu = &airo_change_mtu;
+	dev->open = &airo_open;
+	dev->stop = &airo_close;
+	dev->irq = irq;
+	dev->base_addr = port;
+	
+	rc = register_netdev(dev);
+	if (rc)
+		goto err_out_unlink;
+	
+	rc = request_irq( dev->irq, airo_interrupt, 
+			  SA_SHIRQ | SA_INTERRUPT, dev->name, dev );
+	if (rc) {
+		printk(KERN_ERR "airo: register interrupt %d failed, rc %d\n", irq, rc );
+		goto err_out_unregister;
+	}
+	if (!is_pcmcia) {
+		if (!request_region( dev->base_addr, 64, dev->name )) {
+			rc = -EBUSY;
+			goto err_out_irq;
+		}
+	}
+	
+	if ( setup_card( ai, dev->dev_addr, &ai->config) != SUCCESS ) {
+		printk( KERN_ERR "airo: MAC could not be enabled\n" );
+		rc = -EIO;
+		goto err_out_res;
+	}
+
+	printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n",
+		dev->name,
+		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
+
+	/* Allocate the transmit buffers */
+	for( i = 0; i < MAX_FIDS; i++ )
+		ai->fids[i] = transmit_allocate( ai, 2312 );
+
+	setup_proc_entry( dev, dev->priv ); /* XXX check for failure */
+	netif_start_queue(dev);
+	SET_MODULE_OWNER(dev);
+	return dev;
+
+err_out_res:
+	if (!is_pcmcia)
+	        release_region( dev->base_addr, 64 );
+err_out_irq:
+	free_irq(dev->irq, dev);
+err_out_unregister:
+	unregister_netdev(dev);
+err_out_unlink:
+	del_airo_dev(dev);
+err_out_free:
+	kfree(dev);
+	return NULL;
+}
+
+int waitbusy (struct airo_info *ai) {
+	int delay = 0;
+	while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) & (delay < 10000)) {
+		udelay (10);
+		if (++delay % 20)
+			OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
+	}  
+	return delay < 10000;
+}
+
+int reset_airo_card( struct net_device *dev ) {
+	int i, flags;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+
+	disable_MAC(ai);
+	spin_lock_irqsave(&ai->cmd_lock, flags);
+	waitbusy (ai);
+	OUT4500(ai,COMMAND,CMD_SOFTRESET);
+	set_current_state (TASK_UNINTERRUPTIBLE);
+	schedule_timeout (HZ/5);
+	waitbusy (ai);
+	set_current_state (TASK_UNINTERRUPTIBLE);
+	schedule_timeout (HZ/5);
+	spin_unlock_irqrestore(&ai->cmd_lock, flags);
+	if ( setup_card(ai, dev->dev_addr, &(ai)->config) != SUCCESS ) {
+		printk( KERN_ERR "airo: MAC could not be enabled\n" );
+		return -1;
+	} else {
+		printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n",
+			dev->name,
+			dev->dev_addr[0],
+			dev->dev_addr[1],
+			dev->dev_addr[2],
+			dev->dev_addr[3],
+			dev->dev_addr[4],
+			dev->dev_addr[5]
+			);
+		/* Allocate the transmit buffers */
+		for( i = 0; i < MAX_FIDS; i++ )
+			ai->fids[i] = transmit_allocate( ai, 2312 );
+	}
+	enable_interrupts( ai );
+	netif_wake_queue(dev);
+	return 0;
+}
+
+int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
+{
+	memcpy(haddr, skb->mac.raw + 10, ETH_ALEN);
+	return ETH_ALEN;
+}
+
+static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
+	struct net_device *dev = (struct net_device *)dev_id;
+	u16 status;
+	u16 fid;
+	struct airo_info *apriv = (struct airo_info *)dev->priv;
+	u16 savedInterrupts;
+	
+
+	if (!netif_device_present(dev))
+		return;
+	
+	status = IN4500( apriv, EVSTAT );
+	if ( !status || status == 0xffff ) return;
+	
+	if ( status & EV_AWAKE ) {
+		OUT4500( apriv, EVACK, EV_AWAKE );
+		OUT4500( apriv, EVACK, EV_AWAKE );
+	}
+	
+	savedInterrupts = IN4500( apriv, EVINTEN );
+	OUT4500( apriv, EVINTEN, 0 );
+	
+	if ( status & EV_LINK ) {
+		/* The link status has changed, if you want to put a
+		   monitor hook in, do it here.  (Remember that
+		   interrupts are still disabled!)
+		*/
+		u16 newStatus = IN4500(apriv, LINKSTAT);
+		/* Here is what newStatus means: */
+#define NOBEACON 0x8000 /* Loss of sync - missed beacons */
+#define MAXRETRIES 0x8001 /* Loss of sync - max retries */
+#define MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/
+#define FORCELOSS 0x8003 /* Loss of sync - host request */
+#define TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */
+#define DEAUTH 0x8100 /* Deauthentication (low byte is reason code) */
+#define DISASS 0x8200 /* Disassociation (low byte is reason code) */
+#define ASSFAIL 0x8400 /* Association failure (low byte is reason
+			  code) */
+#define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason
+			   code) */
+#define ASSOCIATED 0x0400 /* Assocatied */
+#define RC_RESERVED 0 /* Reserved return code */
+#define RC_NOREASON 1 /* Unspecified reason */
+#define RC_AUTHINV 2 /* Previous authentication invalid */
+#define RC_DEAUTH 3 /* Deauthenticated because sending station is
+		       leaving */
+#define RC_NOACT 4 /* Disassociated due to inactivity */
+#define RC_MAXLOAD 5 /* Disassociated because AP is unable to handle
+			all currently associated stations */
+#define RC_BADCLASS2 6 /* Class 2 frame received from
+			  non-Authenticated station */
+#define RC_BADCLASS3 7 /* Class 3 frame received from
+			  non-Associated station */
+#define RC_STATLEAVE 8 /* Disassociated because sending station is
+			  leaving BSS */
+#define RC_NOAUTH 9 /* Station requesting (Re)Association is not
+		       Authenticated with the responding station */
+		if (newStatus != ASSOCIATED) {
+			if (auto_wep && !timer_pending(&apriv->timer)) {
+				apriv->timer.expires = RUN_AT(HZ*3);
+	      			add_timer(&apriv->timer);
+			}
+		}
+	}
+	
+	/* Check to see if there is something to receive */
+	if ( status & EV_RX  ) {
+		struct sk_buff *skb = NULL;
+		int flags;
+		u16 fc, len, hdrlen = 0;
+		struct {
+			u16 status, len;
+			u8 rssi[2];
+		} hdr;
+
+		fid = IN4500( apriv, RXFID );
+
+		/* Get the packet length */
+	        spin_lock_irqsave(&apriv->bap0_lock, flags);
+		if (dev->type == ARPHRD_IEEE80211) {
+			bap_setup (apriv, fid, 4, BAP0);
+			bap_read (apriv, (u16*)&hdr, sizeof(hdr), BAP0);
+			/* Bad CRC. Ignore packet */
+			if (le16_to_cpu(hdr.status) == 2) {
+				apriv->stats.rx_crc_errors++;
+				apriv->stats.rx_errors++;
+				hdr.len = 0;
+			}
+		} else {
+			bap_setup (apriv, fid, 6, BAP0);
+			bap_read (apriv, (u16*)&hdr.len, 4, BAP0);
+		}
+		len = le16_to_cpu(hdr.len);
+
+		if (len > 2312) {
+			apriv->stats.rx_length_errors++;
+			apriv->stats.rx_errors++;
+			printk( KERN_ERR 
+				"airo: Bad size %d\n", len );
+			len = 0;
+		}
+		if (len) {
+			if (dev->type == ARPHRD_IEEE80211) {
+				bap_setup (apriv, fid, 0x14, BAP0);
+				bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0);
+				if ((le16_to_cpu(fc) & 0x300) == 0x300)
+					hdrlen = 30;
+				else
+					hdrlen = 24;
+			} else
+				hdrlen = 12;
+
+			skb = dev_alloc_skb( len + hdrlen + 2 );
+			if ( !skb ) {
+				apriv->stats.rx_dropped++;
+				len = 0;
+			}
+		}
+		if (len) {
+			u16 *buffer;
+			buffer = (u16*)skb_put (skb, len + hdrlen);
+			if (dev->type == ARPHRD_IEEE80211) {
+				u16 gap, tmpbuf[4];
+				buffer[0] = fc;
+				bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
+				if (hdrlen == 24)
+					bap_read (apriv, tmpbuf, 6, BAP0);
+
+				bap_read (apriv, &gap, sizeof(gap), BAP0);
+				gap = le16_to_cpu(gap);
+				if (gap && gap <= 8)
+					bap_read (apriv, tmpbuf, gap, BAP0);
+
+				bap_read (apriv, buffer + hdrlen/2, len, BAP0);
+			} else {
+		                bap_setup (apriv, fid, 0x38, BAP0);
+				bap_read (apriv, buffer,len + hdrlen,BAP0);
+			}
+#ifdef WIRELESS_SPY
+			if (apriv->spy_number > 0) {
+				int i;
+				char *sa;
+
+				sa = (char*)buffer + ((dev->type == ARPHRD_IEEE80211) ? 10 : 6);
+
+				for (i=0; i<apriv->spy_number; i++)
+					if (!memcmp(sa,apriv->spy_address[i],6))
+					{
+						apriv->spy_stat[i].qual = hdr.rssi[0];
+						apriv->spy_stat[i].level = hdr.rssi[1];
+						apriv->spy_stat[i].noise = 0;
+						apriv->spy_stat[i].updated = 3;
+						break;
+					}
+			}
+#endif /* WIRELESS_SPY  */
+			apriv->stats.rx_packets++;
+			apriv->stats.rx_bytes += len + hdrlen;
+			dev->last_rx = jiffies;
+			skb->dev = dev;
+			skb->ip_summed = CHECKSUM_NONE;
+			if (dev->type == ARPHRD_IEEE80211) {
+				skb->mac.raw = skb->data;
+				skb_pull (skb, hdrlen);
+				skb->pkt_type = PACKET_OTHERHOST;
+				skb->protocol = htons(ETH_P_802_2);
+			} else
+				skb->protocol = eth_type_trans( skb, dev );
+
+			netif_rx( skb );
+		}
+		spin_unlock_irqrestore(&apriv->bap0_lock, flags);
+	}
+
+	/* Check to see if a packet has been transmitted */
+	if (  status & ( EV_TX|EV_TXEXC ) ) {
+		int i;
+		int len = 0;
+		int full = 1;
+		int index = -1;
+		
+		fid = IN4500(apriv, TXCOMPLFID);
+		
+		for( i = 0; i < MAX_FIDS; i++ ) {
+			if (!(apriv->fids[i] & 0xffff0000)) full = 0;
+			if ( ( apriv->fids[i] & 0xffff ) == fid ) {
+				len = apriv->fids[i] >> 16;
+				index = i;
+				/* Set up to be used again */
+				apriv->fids[i] &= 0xffff; 
+			}
+		}
+		if (full) netif_wake_queue(dev);
+		if (index==-1) {
+			printk( KERN_ERR
+				"airo: Unallocated FID was used to xmit\n" );
+		}
+		if ( status & EV_TX ) {
+			apriv->stats.tx_packets++;
+			if(index!=-1)
+				apriv->stats.tx_bytes += len;
+		} else {
+			apriv->stats.tx_errors++;
+		}
+	}
+	if ( status & ~STATUS_INTS ) 
+		printk( KERN_WARNING 
+			"airo: Got weird status %x\n", 
+			status & ~STATUS_INTS );
+	OUT4500( apriv, EVACK, status & STATUS_INTS );
+	OUT4500( apriv, EVINTEN, savedInterrupts );
+	
+	/* done.. */
+	return;     
+}
+
+/*
+ *  Routines to talk to the card
+ */
+
+/*
+ *  This was originally written for the 4500, hence the name
+ *  NOTE:  If use with 8bit mode and SMP bad things will happen!
+ *         Why would some one do 8 bit IO in an SMP machine?!?
+ */
+static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) {
+	if ( !do8bitIO )
+		outw( val, ai->dev->base_addr + reg );
+	else {
+		outb( val & 0xff, ai->dev->base_addr + reg );
+		outb( val >> 8, ai->dev->base_addr + reg + 1 );
+	}
+}
+
+static u16 IN4500( struct airo_info *ai, u16 reg ) {
+	unsigned short rc;
+	
+	if ( !do8bitIO )
+		rc = inw( ai->dev->base_addr + reg );
+	else {
+		rc = inb( ai->dev->base_addr + reg );
+		rc += ((int)inb( ai->dev->base_addr + reg + 1 )) << 8;
+	}
+	return rc;
+}
+
+static int enable_MAC( struct airo_info *ai, Resp *rsp ) {
+        Cmd cmd;
+
+        if (ai->flags&FLAG_RADIO_OFF) return SUCCESS;
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd = MAC_ENABLE;
+	return issuecommand(ai, &cmd, rsp);
+}
+
+static void disable_MAC( struct airo_info *ai ) {
+        Cmd cmd;
+	Resp rsp;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd = MAC_DISABLE; // disable in case already enabled
+	issuecommand(ai, &cmd, &rsp);
+}
+
+static void enable_interrupts( struct airo_info *ai ) {
+	/* Reset the status register */
+	u16 status = IN4500( ai, EVSTAT );
+	OUT4500( ai, EVACK, status );
+	/* Enable the interrupts */
+	OUT4500( ai, EVINTEN, STATUS_INTS );
+	/* Note there is a race condition between the last two lines that
+	   I dont know how to get rid of right now... */
+}
+
+static void disable_interrupts( struct airo_info *ai ) {
+	OUT4500( ai, EVINTEN, 0 );
+}
+
+static u16 setup_card(struct airo_info *ai, u8 *mac, 
+		      ConfigRid *config)
+{
+	Cmd cmd; 
+	Resp rsp;
+	ConfigRid cfg;
+	int status;
+	int i;
+	SsidRid mySsid;
+	u16 lastindex;
+	WepKeyRid wkr;
+	int rc;
+
+	memset( &mySsid, 0, sizeof( mySsid ) );
+
+	/* The NOP is the first step in getting the card going */
+	cmd.cmd = NOP;
+	cmd.parm0 = cmd.parm1 = cmd.parm2 = 0;
+	if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
+		return ERROR;
+	}
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd = MAC_DISABLE; // disable in case already enabled
+	if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
+		return ERROR;
+	}
+	
+	// Let's figure out if we need to use the AUX port
+	cmd.cmd = CMD_ENABLEAUX;
+	if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
+		printk(KERN_ERR "airo: Error checking for AUX port\n");
+		return ERROR;
+	}
+	if (!aux_bap || rsp.status & 0xff00) {
+		ai->bap_read = fast_bap_read;
+		printk(KERN_DEBUG "airo: Doing fast bap_reads\n");
+	} else {
+		ai->bap_read = aux_bap_read;
+		printk(KERN_DEBUG "airo: Doing AUX bap_reads\n");
+	}
+	if ( config->len ) {
+		cfg = *config;
+	} else {
+		// general configuration (read/modify/write)
+		status = readConfigRid(ai, &cfg);
+		if ( status != SUCCESS ) return ERROR;
+		cfg.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
+    
+		/* Save off the MAC */
+		for( i = 0; i < 6; i++ ) {
+			mac[i] = cfg.macAddr[i];
+		}
+
+		/* Check to see if there are any insmod configured 
+		   rates to add */
+		if ( rates ) {
+			int i = 0;
+			if ( rates[0] ) memset(cfg.rates,0,sizeof(cfg.rates));
+			for( i = 0; i < 8 && rates[i]; i++ ) {
+				cfg.rates[i] = rates[i];
+			}    
+		}
+		if ( basic_rate > 0 ) {
+			int i;
+			for( i = 0; i < 8; i++ ) {
+				if ( cfg.rates[i] == basic_rate ||
+				     !cfg.rates ) {
+					cfg.rates[i] = basic_rate | 0x80;
+					break;
+				}
+			}
+		}
+		cfg.authType = ai->authtype;
+		*config = cfg;
+	}
+	
+	/* Setup the SSIDs if present */
+	if ( ssids[0] ) {
+		int i = 0;
+		for( i = 0; i < 3 && ssids[i]; i++ ) {
+			mySsid.ssids[i].len = strlen(ssids[i]);
+			if ( mySsid.ssids[i].len > 32 ) 
+				mySsid.ssids[i].len = 32;
+			memcpy(mySsid.ssids[i].ssid, ssids[i],
+			       mySsid.ssids[i].len);
+			mySsid.ssids[i].len = mySsid.ssids[i].len;
+		}
+	}
+	
+	status = writeConfigRid(ai, &cfg);
+	if ( status != SUCCESS ) return ERROR;
+	
+	/* Set up the SSID list */
+	status = writeSsidRid(ai, &mySsid);
+	if ( status != SUCCESS ) return ERROR;
+	
+	/* Grab the initial wep key, we gotta save it for auto_wep */
+	rc = readWepKeyRid(ai, &wkr, 1);
+	if (rc == SUCCESS) do {
+		lastindex = wkr.kindex;
+		if (wkr.kindex == 0xffff) {
+			ai->defindex = wkr.mac[0];
+		}
+		rc = readWepKeyRid(ai, &wkr, 0);
+	} while(lastindex != wkr.kindex);
+	
+	if (auto_wep && !timer_pending(&ai->timer)) {
+		ai->timer.expires = RUN_AT(HZ*3);
+		add_timer(&ai->timer);
+	}
+	return SUCCESS;
+}
+
+static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
+        // Im really paranoid about letting it run forever!
+	int max_tries = 600000;  
+        int rc = SUCCESS;
+	int flags;
+
+	spin_lock_irqsave(&ai->cmd_lock, flags);
+	OUT4500(ai, PARAM0, pCmd->parm0);
+	OUT4500(ai, PARAM1, pCmd->parm1);
+	OUT4500(ai, PARAM2, pCmd->parm2);
+	OUT4500(ai, COMMAND, pCmd->cmd);
+	while ( max_tries-- &&
+		(IN4500(ai, EVSTAT) & EV_CMD) == 0) {
+		if ( IN4500(ai, COMMAND) == pCmd->cmd) { 
+			// PC4500 didn't notice command, try again
+			OUT4500(ai, COMMAND, pCmd->cmd);
+		}
+	}
+	if ( max_tries == -1 ) {
+		printk( KERN_ERR 
+			"airo: Max tries exceeded when issueing command\n" );
+                rc = ERROR;
+                goto done;
+	}
+	// command completed
+	pRsp->status = IN4500(ai, STATUS);
+	pRsp->rsp0 = IN4500(ai, RESP0);
+	pRsp->rsp1 = IN4500(ai, RESP1);
+	pRsp->rsp2 = IN4500(ai, RESP2);
+	
+	// clear stuck command busy if necessary
+	if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
+		OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
+	}
+	// acknowledge processing the status/response
+	OUT4500(ai, EVACK, EV_CMD);
+ done:
+	spin_unlock_irqrestore(&ai->cmd_lock, flags);
+	return rc;
+}
+
+/* Sets up the bap to start exchange data.  whichbap should
+ * be one of the BAP0 or BAP1 defines.  Locks should be held before
+ * calling! */
+static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap )
+{
+	int timeout = 50;
+	int max_tries = 3;
+	
+	OUT4500(ai, SELECT0+whichbap, rid);
+	OUT4500(ai, OFFSET0+whichbap, offset);
+	while (1) {
+		int status = IN4500(ai, OFFSET0+whichbap);
+		if (status & BAP_BUSY) {
+                        /* This isn't really a timeout, but its kinda
+			   close */
+			if (timeout--) { 
+				continue;
+			}
+		} else if ( status & BAP_ERR ) {
+			/* invalid rid or offset */
+			printk( KERN_ERR "airo: BAP error %x %d\n", 
+				status, whichbap );
+			return ERROR;
+		} else if (status & BAP_DONE) { // success
+			return SUCCESS;
+		}
+		if ( !(max_tries--) ) {
+			printk( KERN_ERR 
+				"airo: BAP setup error too many retries\n" );
+			return ERROR;
+		}
+		// -- PC4500 missed it, try again
+		OUT4500(ai, SELECT0+whichbap, rid);
+		OUT4500(ai, OFFSET0+whichbap, offset);
+		timeout = 50;
+	}
+}
+
+/* should only be called by aux_bap_read.  This aux function and the
+   following use concepts not documented in the developers guide.  I
+   got them from a patch given to my by Aironet */
+static u16 aux_setup(struct airo_info *ai, u16 page,
+		     u16 offset, u16 *len)
+{
+	u16 next;
+
+	OUT4500(ai, AUXPAGE, page);
+	OUT4500(ai, AUXOFF, 0);
+	next = IN4500(ai, AUXDATA);
+	*len = IN4500(ai, AUXDATA)&0xff;
+	if (offset != 4) OUT4500(ai, AUXOFF, offset);
+	return next;
+}
+
+/* requires call to bap_setup() first */
+static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst,
+			int bytelen, int whichbap) 
+{
+	u16 len;
+	u16 page;
+	u16 offset;
+	u16 next;
+	int words;
+	int i;
+	int flags;
+
+	spin_lock_irqsave(&ai->aux_lock, flags);
+	page = IN4500(ai, SWS0+whichbap);
+	offset = IN4500(ai, SWS2+whichbap);
+	next = aux_setup(ai, page, offset, &len);
+	words = (bytelen+1)>>1;
+
+	for (i=0; i<words;) {
+		int count;
+		count = (len>>1) < (words-i) ? (len>>1) : (words-i);
+		if ( !do8bitIO ) 
+			insw( ai->dev->base_addr+DATA0+whichbap, 
+			      pu16Dst+i,count );
+		else
+			insb( ai->dev->base_addr+DATA0+whichbap, 
+			      pu16Dst+i, count << 1 );
+		i += count;
+		if (i<words) {
+			next = aux_setup(ai, next, 4, &len);
+		}
+	}
+	spin_unlock_irqrestore(&ai->aux_lock, flags);
+	return SUCCESS;
+}
+
+
+/* requires call to bap_setup() first */
+static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst, 
+			 int bytelen, int whichbap)
+{
+	bytelen = (bytelen + 1) & (~1); // round up to even value
+	if ( !do8bitIO ) 
+		insw( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1 );
+	else
+		insb( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen );
+	return SUCCESS;
+}
+
+/* requires call to bap_setup() first */
+static int bap_write(struct airo_info *ai, const u16 *pu16Src, 
+		     int bytelen, int whichbap)
+{
+	bytelen = (bytelen + 1) & (~1); // round up to even value
+	if ( !do8bitIO ) 
+		outsw( ai->dev->base_addr+DATA0+whichbap, 
+		       pu16Src, bytelen>>1 );
+	else
+		outsb( ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen );
+	return SUCCESS;
+}
+
+static int PC4500_accessrid(struct airo_info *ai, u16 rid, u16 accmd)
+{
+	Cmd cmd; /* for issuing commands */
+	Resp rsp; /* response from commands */
+	u16 status;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd = accmd;
+	cmd.parm0 = rid;
+	status = issuecommand(ai, &cmd, &rsp);
+	if (status != 0) return status;
+	if ( (rsp.status & 0x7F00) != 0) {
+		return (accmd << 8) + (rsp.rsp0 & 0xFF);
+	}
+	return 0;
+}
+
+/*  Note, that we are using BAP1 which is also used by transmit, so
+ *  we must get a lock. */
+static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len)
+{
+	u16 status;
+        int flags;
+        int rc = SUCCESS;
+
+	spin_lock_irqsave(&ai->bap1_lock, flags);
+	if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != SUCCESS) {
+                rc = status;
+                goto done;
+        }
+	if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
+		rc = ERROR;
+                goto done;
+        }
+	// read the rid length field
+	bap_read(ai, pBuf, 2, BAP1);
+	// length for remaining part of rid
+	len = min(len, le16_to_cpu(*(u16*)pBuf)) - 2;
+	
+	if ( len <= 2 ) {
+		printk( KERN_ERR 
+			"airo: Rid %x has a length of %d which is too short\n",
+			(int)rid,
+			(int)len );
+		rc = ERROR;
+                goto done;
+	}
+	// read remainder of the rid
+	if (bap_setup(ai, rid, 2, BAP1) != SUCCESS) {
+                rc = ERROR;
+                goto done;
+        }
+	rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
+ done:
+	spin_unlock_irqrestore(&ai->bap1_lock, flags);
+	return rc;
+}
+
+/*  Note, that we are using BAP1 which is also used by transmit, so
+ *  make sure this isnt called when a transmit is happening */
+static int PC4500_writerid(struct airo_info *ai, u16 rid, 
+			   const void *pBuf, int len)
+{
+	u16 status;
+        int flags;
+	int rc = SUCCESS;
+
+	spin_lock_irqsave(&ai->bap1_lock, flags);
+	// --- first access so that we can write the rid data
+	if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
+                rc = status;
+                goto done;
+        }
+	// --- now write the rid data
+	if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
+                rc = ERROR;
+                goto done;
+        }
+	bap_write(ai, pBuf, len, BAP1);
+	// ---now commit the rid data
+	rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
+ done:
+	spin_unlock_irqrestore(&ai->bap1_lock, flags);
+        return rc;
+}
+
+/* Allocates a FID to be used for transmitting packets.  We only use
+   one for now. */
+static u16 transmit_allocate(struct airo_info *ai, int lenPayload)
+{
+	Cmd cmd;
+	Resp rsp;
+	u16 txFid;
+	u16 txControl;
+        int flags;
+
+	cmd.cmd = CMD_ALLOCATETX;
+	cmd.parm0 = lenPayload;
+	if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return 0;
+	if ( (rsp.status & 0xFF00) != 0) return 0;
+	/* wait for the allocate event/indication
+	 * It makes me kind of nervous that this can just sit here and spin,
+	 * but in practice it only loops like four times. */
+	while ( (IN4500(ai, EVSTAT) & EV_ALLOC) == 0) ;
+	// get the allocated fid and acknowledge
+	txFid = IN4500(ai, TXALLOCFID);
+	OUT4500(ai, EVACK, EV_ALLOC);
+  
+	/*  The CARD is pretty cool since it converts the ethernet packet
+	 *  into 802.11.  Also note that we don't release the FID since we
+	 *  will be using the same one over and over again. */
+	/*  We only have to setup the control once since we are not
+	 *  releasing the fid. */
+	txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3
+		| TXCTL_ETHERNET | TXCTL_NORELEASE);
+	spin_lock_irqsave(&ai->bap1_lock, flags);
+	if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS) {
+		spin_unlock_irqrestore(&ai->bap1_lock, flags);
+		return ERROR;
+	}
+	bap_write(ai, &txControl, sizeof(txControl), BAP1);
+	spin_unlock_irqrestore(&ai->bap1_lock, flags);
+
+	return txFid;
+}
+
+/* In general BAP1 is dedicated to transmiting packets.  However,
+   since we need a BAP when accessing RIDs, we also use BAP1 for that.
+   Make sure the BAP1 spinlock is held when this is called. */
+static int transmit_802_3_packet(struct airo_info *ai, u16 txFid, 
+				 char *pPacket, int len)
+{
+	u16 payloadLen;
+	Cmd cmd;
+	Resp rsp;
+	
+	if (len < 12) {
+		printk( KERN_WARNING "Short packet %d\n", len );
+		return ERROR;
+	}
+	
+	// packet is destination[6], source[6], payload[len-12]
+	// write the payload length and dst/src/payload
+	if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR;
+	/* The hardware addresses aren't counted as part of the payload, so
+	 * we have to subtract the 12 bytes for the addresses off */
+	payloadLen = cpu_to_le16(len-12);
+	bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
+	bap_write(ai, (const u16*)pPacket, len, BAP1);
+	// issue the transmit command
+	memset( &cmd, 0, sizeof( cmd ) );
+	cmd.cmd = CMD_TRANSMIT;
+	cmd.parm0 = txFid;
+	if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
+	if ( (rsp.status & 0xFF00) != 0) return ERROR;
+	return SUCCESS;
+}
+
+/*
+ *  This is the proc_fs routines.  It is a bit messier than I would
+ *  like!  Feel free to clean it up!
+ */
+
+/*
+ *  Unfortunately sometime between 2.0 and 2.2 the proc interface changed...
+ *  Unfortunately I dont know when it was...
+ *  Im guessing it is sometime around 0x20155...  Anybody know?
+ */
+
+static ssize_t proc_read( struct file *file,
+			  char *buffer,
+			  size_t len,
+			  loff_t *offset);
+
+static ssize_t proc_write( struct file *file,
+			   const char *buffer,
+			   size_t len,
+			   loff_t *offset );
+static int proc_close( struct inode *inode, struct file *file );
+
+static int proc_stats_open( struct inode *inode, struct file *file );
+static int proc_statsdelta_open( struct inode *inode, struct file *file );
+static int proc_status_open( struct inode *inode, struct file *file );
+static int proc_SSID_open( struct inode *inode, struct file *file );
+static int proc_APList_open( struct inode *inode, struct file *file );
+static int proc_config_open( struct inode *inode, struct file *file );
+static int proc_wepkey_open( struct inode *inode, struct file *file );
+
+static struct file_operations proc_statsdelta_ops = {
+	read:           proc_read,
+	open:           proc_statsdelta_open,
+	release:        proc_close
+};
+
+static struct file_operations proc_stats_ops = {
+	read:           proc_read,
+	open:           proc_stats_open,
+	release:        proc_close
+};
+
+static struct file_operations proc_status_ops = {
+	read:            proc_read,
+	open:            proc_status_open,
+	release:         proc_close
+};
+
+static struct file_operations proc_SSID_ops = {
+	read:          proc_read,
+	write:         proc_write,
+	open:          proc_SSID_open,
+	release:       proc_close
+};
+
+static struct file_operations proc_APList_ops = {
+	read:          proc_read,
+	write:         proc_write,
+	open:          proc_APList_open,
+	release:       proc_close
+};
+
+static struct file_operations proc_config_ops = {
+	read:          proc_read,
+	write:         proc_write,
+	open:          proc_config_open,
+	release:       proc_close
+};
+
+static struct file_operations proc_wepkey_ops = {
+	read:          proc_read,
+	write:         proc_write,
+	open:          proc_wepkey_open,
+	release:       proc_close
+};
+
+static struct proc_dir_entry *airo_entry = 0;
+
+struct proc_data {
+	int release_buffer;
+	int readlen;
+	char *rbuffer;
+	int writelen;
+	int maxwritelen;
+	char *wbuffer;
+	void (*on_close) (struct inode *, struct file *);
+};
+
+static int setup_proc_entry( struct net_device *dev,
+			     struct airo_info *apriv ) {
+	struct proc_dir_entry *entry;
+	/* First setup the device directory */
+	apriv->proc_entry = create_proc_entry(dev->name,
+					      S_IFDIR|airo_perm,
+					      airo_entry);
+        apriv->proc_entry->uid = proc_uid;
+        apriv->proc_entry->gid = proc_gid;
+
+	/* Setup the StatsDelta */
+	entry = create_proc_entry("StatsDelta",
+				  S_IFREG | (S_IRUGO&proc_perm),
+				  apriv->proc_entry);
+        entry->uid = proc_uid;
+        entry->gid = proc_gid;
+	entry->data = dev;
+/*	This is what was needed right up to the last few versions
+        of 2.3:
+	entry->ops = &proc_inode_statsdelta_ops;
+*/
+	entry->proc_fops = &proc_statsdelta_ops;
+	
+	/* Setup the Stats */
+	entry = create_proc_entry("Stats",
+				  S_IFREG | (S_IRUGO&proc_perm),
+				  apriv->proc_entry);
+        entry->uid = proc_uid;
+        entry->gid = proc_gid;
+	entry->data = dev;
+	entry->proc_fops = &proc_stats_ops;
+	
+	/* Setup the Status */
+	entry = create_proc_entry("Status",
+				  S_IFREG | (S_IRUGO&proc_perm),
+				  apriv->proc_entry);
+        entry->uid = proc_uid;
+        entry->gid = proc_gid;
+	entry->data = dev;
+	entry->proc_fops = &proc_status_ops;
+	
+	/* Setup the Config */
+	entry = create_proc_entry("Config",
+				  S_IFREG | proc_perm,
+				  apriv->proc_entry);
+        entry->uid = proc_uid;
+        entry->gid = proc_gid;
+	entry->data = dev;
+	entry->proc_fops = &proc_config_ops;
+
+	/* Setup the SSID */
+	entry = create_proc_entry("SSID",
+				  S_IFREG | proc_perm,
+				  apriv->proc_entry);
+        entry->uid = proc_uid;
+        entry->gid = proc_gid;
+	entry->data = dev;
+	entry->proc_fops = &proc_SSID_ops;
+
+	/* Setup the APList */
+	entry = create_proc_entry("APList",
+				  S_IFREG | proc_perm,
+				  apriv->proc_entry);
+        entry->uid = proc_uid;
+        entry->gid = proc_gid;
+	entry->data = dev;
+	entry->proc_fops = &proc_APList_ops;
+
+	/* Setup the WepKey */
+	entry = create_proc_entry("WepKey",
+				  S_IFREG | proc_perm,
+				  apriv->proc_entry);
+        entry->uid = proc_uid;
+        entry->gid = proc_gid;
+	entry->data = dev;
+	entry->proc_fops = &proc_wepkey_ops;
+
+	return 0;
+}
+
+static int takedown_proc_entry( struct net_device *dev,
+				struct airo_info *apriv ) {
+	if ( !apriv->proc_entry->namelen ) return 0;
+	remove_proc_entry("Stats",apriv->proc_entry);
+	remove_proc_entry("StatsDelta",apriv->proc_entry);
+	remove_proc_entry("Status",apriv->proc_entry);
+	remove_proc_entry("Config",apriv->proc_entry);
+	remove_proc_entry("SSID",apriv->proc_entry);
+	remove_proc_entry("APList",apriv->proc_entry);
+	remove_proc_entry("WepKey",apriv->proc_entry);
+	remove_proc_entry(dev->name,airo_entry);
+	return 0;
+}
+
+/*
+ *  What we want from the proc_fs is to be able to efficiently read
+ *  and write the configuration.  To do this, we want to read the
+ *  configuration when the file is opened and write it when the file is
+ *  closed.  So basically we allocate a read buffer at open and fill it
+ *  with data, and allocate a write buffer and read it at close.
+ */
+
+/*
+ *  The read routine is generic, it relies on the preallocated rbuffer
+ *  to supply the data.
+ */
+static ssize_t proc_read( struct file *file,
+			  char *buffer,
+			  size_t len,
+			  loff_t *offset )
+{
+	int i;
+	int pos;
+	struct proc_data *priv = (struct proc_data*)file->private_data;
+	
+	if( !priv->rbuffer ) return -EINVAL;
+	
+	pos = *offset;
+	for( i = 0; i+pos < priv->readlen && i < len; i++ ) {
+		if (put_user( priv->rbuffer[i+pos], buffer+i ))
+			return -EFAULT;
+	}
+	*offset += i;
+	return i;
+}
+
+/*
+ *  The write routine is generic, it fills in a preallocated rbuffer
+ *  to supply the data.
+ */
+static ssize_t proc_write( struct file *file,
+			   const char *buffer,
+			   size_t len,
+			   loff_t *offset ) 
+{
+	int i;
+	int pos;
+	struct proc_data *priv = (struct proc_data*)file->private_data;
+	
+	if ( !priv->wbuffer ) {
+		return -EINVAL;
+	}
+	
+	pos = *offset;
+	
+	for( i = 0; i + pos <  priv->maxwritelen &&
+		     i < len; i++ ) {
+		if (get_user( priv->wbuffer[i+pos], buffer + i ))
+			return -EFAULT;
+	}
+	if ( i+pos > priv->writelen ) priv->writelen = i+file->f_pos;
+	*offset += i;
+	return i;
+}
+
+static int proc_status_open( struct inode *inode, struct file *file ) {
+	struct proc_data *data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *apriv = (struct airo_info *)dev->priv;
+	CapabilityRid cap_rid;
+	StatusRid status_rid;
+	
+	MOD_INC_USE_COUNT;
+	
+	dp = inode->u.generic_ip;
+	
+	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+	memset(file->private_data, 0, sizeof(struct proc_data));
+	data = (struct proc_data *)file->private_data;
+	if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
+		kfree (file->private_data);
+		return -ENOMEM;
+	}
+	
+	readStatusRid(apriv, &status_rid);
+	readCapabilityRid(apriv, &cap_rid);
+	
+	sprintf( data->rbuffer, "Mode: %x\n"
+		 "Signal Strength: %d\n"
+		 "Signal Quality: %d\n"
+		 "SSID: %-.*s\n"
+		 "AP: %-.16s\n"
+		 "Freq: %d\n"
+		 "BitRate: %dmbs\n"
+		 "Driver Version: %s\n"
+		 "Device: %s\nManufacturer: %s\nFirmware Version: %s\n"
+		 "Radio type: %x\nCountry: %x\nHardware Version: %x\n"
+		 "Software Version: %x\nSoftware Subversion: %x\n"
+		 "Boot block version: %x\n",
+		 (int)status_rid.mode,
+		 (int)status_rid.normalizedSignalStrength,
+		 (int)status_rid.signalQuality,
+		 (int)status_rid.SSIDlen,
+		 status_rid.SSID,
+		 status_rid.apName,
+		 (int)status_rid.channel,
+		 (int)status_rid.currentXmitRate/2,
+		 version,
+		 cap_rid.prodName,
+		 cap_rid.manName,
+		 cap_rid.prodVer,
+		 cap_rid.radioType,
+		 cap_rid.country,
+		 cap_rid.hardVer,
+		 (int)cap_rid.softVer,
+		 (int)cap_rid.softSubVer,
+		 (int)cap_rid.bootBlockVer );
+	data->readlen = strlen( data->rbuffer );
+	return 0;
+}
+
+static int proc_stats_rid_open(struct inode*, struct file*, u16);
+static int proc_statsdelta_open( struct inode *inode, 
+				 struct file *file ) {
+	if (file->f_mode&FMODE_WRITE) {
+		return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR);
+	}
+	return proc_stats_rid_open(inode, file, RID_STATSDELTA);
+}
+
+static int proc_stats_open( struct inode *inode, struct file *file ) {
+	return proc_stats_rid_open(inode, file, RID_STATS);
+}
+
+static int proc_stats_rid_open( struct inode *inode, 
+				struct file *file,
+				u16 rid ) {
+	struct proc_data *data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *apriv = (struct airo_info *)dev->priv;
+	StatsRid stats;
+	int i, j;
+	int *vals = stats.vals;
+	MOD_INC_USE_COUNT;
+	
+	
+	dp = inode->u.generic_ip;
+	
+	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+	memset(file->private_data, 0, sizeof(struct proc_data));
+	data = (struct proc_data *)file->private_data;
+	if ((data->rbuffer = kmalloc( 4096, GFP_KERNEL )) == NULL) {
+		kfree (file->private_data);
+		return -ENOMEM;
+	}
+	
+	readStatsRid(apriv, &stats, rid);
+	
+        j = 0;
+	for(i=0; (int)statsLabels[i]!=-1 && 
+		    i*4<stats.len; i++){
+		if (!statsLabels[i]) continue;
+		if (j+strlen(statsLabels[i])+16>4096) {
+			printk(KERN_WARNING
+			       "airo: Potentially disasterous buffer overflow averted!\n");
+			break;
+		}
+		j+=sprintf(data->rbuffer+j, "%s: %d\n", statsLabels[i], vals[i]);
+	}
+	if (i*4>=stats.len){
+		printk(KERN_WARNING
+		       "airo: Got a short rid\n");
+	}
+	data->readlen = j;
+	return 0;
+}
+
+static int get_dec_u16( char *buffer, int *start, int limit ) {
+	u16 value;
+	int valid = 0;
+	for( value = 0; buffer[*start] >= '0' &&
+		     buffer[*start] <= '9' &&
+		     *start < limit; (*start)++ ) {
+		valid = 1;
+		value *= 10;
+		value += buffer[*start] - '0';
+	}
+	if ( !valid ) return -1;
+	return value;
+}
+
+static void checkThrottle(ConfigRid *config) {
+	int i;
+/* Old hardware had a limit on encryption speed */
+	if (config->authType != AUTH_OPEN && maxencrypt) {
+		for(i=0; i<8; i++) {
+			if (config->rates[i] > maxencrypt) {
+				config->rates[i] = 0;
+			}
+		}
+	}
+}
+
+static void proc_config_on_close( struct inode *inode, struct file *file ) {
+	struct proc_data *data = file->private_data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	ConfigRid config;
+	Resp rsp;
+	char *line;
+	int need_reset = 0;
+	
+	if ( !data->writelen ) return;
+	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	
+	disable_MAC(ai);
+	readConfigRid(ai, &config);
+
+	line = data->wbuffer;
+	while( line[0] ) {
+/*** Mode processing */
+		if ( !strncmp( line, "Mode: ", 6 ) ) {
+			line += 6;
+			config.rmode &= 0xfe00;
+			if ( line[0] == 'a' ) {
+				config.opmode = 0;
+			} else {
+				config.opmode = 1;
+				if ( line[0] == 'r' )
+					config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
+				else if ( line[0] == 'y' )
+					config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER;
+			}
+			if (config.rmode & RXMODE_DISABLE_802_3_HEADER) {
+				dev->type = ARPHRD_IEEE80211;
+				dev->hard_header_parse = wll_header_parse;
+			} else if (dev->type == ARPHRD_IEEE80211) {
+				dev->type = ARPHRD_ETHER;
+				dev->hard_header_parse = ai->header_parse;
+				need_reset = 1;
+			}
+		}
+		
+/*** Radio status */
+		else if (!strncmp(line,"Radio: ", 7)) {
+			line += 7;
+			if (!strncmp(line,"off",3)) {
+				ai->flags |= FLAG_RADIO_OFF;
+			} else {
+				ai->flags &= ~FLAG_RADIO_OFF;
+			}
+		}
+/*** NodeName processing */
+		else if ( !strncmp( line, "NodeName: ", 10 ) ) {
+			int j;
+			
+			line += 10;
+			memset( config.nodeName, 0, 16 );
+/* Do the name, assume a space between the mode and node name */
+			for( j = 0; j < 16 && line[j] != '\n'; j++ ) {
+				config.nodeName[j] = line[j];
+			}
+		} 
+		
+/*** PowerMode processing */
+		else if ( !strncmp( line, "PowerMode: ", 11 ) ) {
+			line += 11;
+			if ( !strncmp( line, "PSPCAM", 6 ) ) {
+				config.powerSaveMode = POWERSAVE_PSPCAM;
+			} else if ( !strncmp( line, "PSP", 3 ) ) {
+				config.powerSaveMode = POWERSAVE_PSP;
+			} else {
+				config.powerSaveMode = POWERSAVE_CAM;
+			}	
+		} else if ( !strncmp( line, "DataRates: ", 11 ) ) {
+			int v, i = 0, k = 0; /* i is index into line, 
+						k is index to rates */
+			
+			line += 11;
+			while((v = get_dec_u16(line, &i, 3))!=-1) {
+				config.rates[k++] = (u8)v;
+				line += i + 1;
+				i = 0;
+			}
+		} else if ( !strncmp( line, "Channel: ", 9 ) ) {
+			int v, i = 0;
+			line += 9;
+			v = get_dec_u16(line, &i, i+3);
+			if ( v != -1 ) 
+				config.channelSet = (u16)v;
+		} else if ( !strncmp( line, "XmitPower: ", 11 ) ) {
+			int v, i = 0;
+			line += 11;
+			v = get_dec_u16(line, &i, i+3);
+			if ( v != -1 ) config.txPower = (u16)v;
+		} else if ( !strncmp( line, "WEP: ", 5 ) ) {
+			line += 5;
+			switch( line[0] ) {
+			case 's':
+				config.authType = (u16)AUTH_SHAREDKEY;
+				break;
+			case 'e':
+				config.authType = (u16)AUTH_ENCRYPT;
+				break;
+			default:
+				config.authType = (u16)AUTH_OPEN;
+				break;
+			}
+		} else if ( !strncmp( line, "LongRetryLimit: ", 16 ) ) {
+			int v, i = 0;
+			
+			line += 16;
+			v = get_dec_u16(line, &i, 3);
+			v = (v<0) ? 0 : ((v>255) ? 255 : v);
+			config.longRetryLimit = (u16)v;
+		} else if ( !strncmp( line, "ShortRetryLimit: ", 17 ) ) {
+			int v, i = 0;
+			
+			line += 17;
+			v = get_dec_u16(line, &i, 3);
+			v = (v<0) ? 0 : ((v>255) ? 255 : v);
+			config.shortRetryLimit = (u16)v;
+		} else if ( !strncmp( line, "RTSThreshold: ", 14 ) ) {
+			int v, i = 0;
+			
+			line += 14;
+			v = get_dec_u16(line, &i, 4);
+			v = (v<0) ? 0 : ((v>2312) ? 2312 : v);
+			config.rtsThres = (u16)v;
+		} else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) {
+			int v, i = 0;
+			
+			line += 16;
+			v = get_dec_u16(line, &i, 5);
+			v = (v<0) ? 0 : v;
+			config.txLifetime = (u16)v;
+		} else if ( !strncmp( line, "RXMSDULifetime: ", 16 ) ) {
+			int v, i = 0;
+			
+			line += 16;
+			v = get_dec_u16(line, &i, 5);
+			v = (v<0) ? 0 : v;
+			config.rxLifetime = (u16)v;
+		} else if ( !strncmp( line, "TXDiversity: ", 13 ) ) {
+			config.txDiversity = 
+				(line[13]=='l') ? 1 :
+				((line[13]=='r')? 2: 3);
+		} else if ( !strncmp( line, "RXDiversity: ", 13 ) ) {
+			config.rxDiversity = 
+				(line[13]=='l') ? 1 :
+				((line[13]=='r')? 2: 3);
+		} else if ( !strncmp( line, "FragThreshold: ", 15 ) ) {
+			int v, i = 0;
+			
+			line += 15;
+			v = get_dec_u16(line, &i, 4);
+			v = (v<256) ? 256 : ((v>2312) ? 2312 : v);
+			v = v & 0xfffe; /* Make sure its even */
+			config.fragThresh = (u16)v;
+		} else if (!strncmp(line, "Modulation: ", 12)) {
+			line += 12;
+			switch(*line) {
+			case 'd':  config.modulation=MOD_DEFAULT; break;
+			case 'c':  config.modulation=MOD_CCK; break;
+			case 'm':  config.modulation=MOD_MOK; break;
+			default:
+				printk( KERN_WARNING "airo: Unknown modulation\n" );
+			}
+		} else {
+			printk( KERN_WARNING "Couldn't figure out %s\n", line );
+		}
+		while( line[0] && line[0] != '\n' ) line++;
+		if ( line[0] ) line++;
+	}
+	checkThrottle(&config);
+	ai->config = config;
+	if (need_reset) {
+		APListRid APList_rid;
+		SsidRid SSID_rid;
+
+		readAPListRid(ai, &APList_rid);
+		readSsidRid(ai, &SSID_rid);
+		reset_airo_card(dev);
+		writeSsidRid(ai, &SSID_rid);
+		writeAPListRid(ai, &APList_rid);
+	}
+	writeConfigRid(ai, &config);
+	enable_MAC(ai, &rsp);
+}
+
+static int proc_config_open( struct inode *inode, struct file *file ) {
+	struct proc_data *data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	ConfigRid config;
+	int i;
+	
+	MOD_INC_USE_COUNT;
+	
+	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	
+	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+	memset(file->private_data, 0, sizeof(struct proc_data));
+	data = (struct proc_data *)file->private_data;
+	if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
+		kfree (file->private_data);
+		return -ENOMEM;
+	}
+	if ((data->wbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
+		kfree (data->rbuffer);
+		kfree (file->private_data);
+		return -ENOMEM;
+	}
+	memset( data->wbuffer, 0, 2048 );
+	data->maxwritelen = 2048;
+	data->on_close = proc_config_on_close;
+	
+	readConfigRid(ai, &config);
+	
+	i = sprintf( data->rbuffer, 
+		     "Mode: %s\n"
+		     "Radio: %s\n"
+		     "NodeName: %-16s\n"
+		     "PowerMode: %s\n"
+		     "DataRates: %d %d %d %d %d %d %d %d\n"
+		     "Channel: %d\n"
+		     "XmitPower: %d\n",
+		     config.opmode == 0 ? "adhoc" : 
+		     config.opmode == 1 ? "ESS" :
+		     config.opmode == 2 ? "AP" : 
+		     config.opmode == 3 ? "AP RPTR" : "Error",
+		     ai->flags&FLAG_RADIO_OFF ? "off" : "on",
+		     config.nodeName,
+		     config.powerSaveMode == 0 ? "CAM" :
+		     config.powerSaveMode == 1 ? "PSP" :
+		     config.powerSaveMode == 2 ? "PSPCAM" : "Error",
+		     (int)config.rates[0],
+		     (int)config.rates[1],
+		     (int)config.rates[2],
+		     (int)config.rates[3],
+		     (int)config.rates[4],
+		     (int)config.rates[5],
+		     (int)config.rates[6],
+		     (int)config.rates[7],
+		     (int)config.channelSet,
+		     (int)config.txPower
+		);
+	sprintf( data->rbuffer + i,
+		 "LongRetryLimit: %d\n"
+		 "ShortRetryLimit: %d\n"
+		 "RTSThreshold: %d\n"
+		 "TXMSDULifetime: %d\n"
+		 "RXMSDULifetime: %d\n"
+		 "TXDiversity: %s\n"
+		 "RXDiversity: %s\n"
+		 "FragThreshold: %d\n"
+		 "WEP: %s\n"
+		 "Modulation: %s\n",
+		 (int)config.longRetryLimit,
+		 (int)config.shortRetryLimit,
+		 (int)config.rtsThres,
+		 (int)config.txLifetime,
+		 (int)config.rxLifetime,
+		 config.txDiversity == 1 ? "left" :
+		 config.txDiversity == 2 ? "right" : "both",
+		 config.rxDiversity == 1 ? "left" :
+		 config.rxDiversity == 2 ? "right" : "both",
+		 (int)config.fragThresh,
+		 config.authType == AUTH_ENCRYPT ? "encrypt" :
+		 config.authType == AUTH_SHAREDKEY ? "shared" : "open",
+		 config.modulation == 0 ? "default" :
+		 config.modulation == MOD_CCK ? "cck" :
+		 config.modulation == MOD_MOK ? "mok" : "error"
+		);
+	data->readlen = strlen( data->rbuffer );
+	return 0;
+}
+
+static void proc_SSID_on_close( struct inode *inode, struct file *file ) {
+	struct proc_data *data = (struct proc_data *)file->private_data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	SsidRid SSID_rid;
+	int i;
+	int offset = 0;
+	
+	if ( !data->writelen ) return;
+	
+	memset( &SSID_rid, 0, sizeof( SSID_rid ) );
+	
+	for( i = 0; i < 3; i++ ) {
+		int j;
+		for( j = 0; j+offset < data->writelen && j < 32 &&
+			     data->wbuffer[offset+j] != '\n'; j++ ) {
+			SSID_rid.ssids[i].ssid[j] = data->wbuffer[offset+j];
+		}
+		if ( j == 0 ) break;
+		SSID_rid.ssids[i].len = j;
+		offset += j;
+		while( data->wbuffer[offset] != '\n' && 
+		       offset < data->writelen ) offset++;
+		offset++;
+	}
+	writeSsidRid(ai, &SSID_rid);
+}
+
+inline static u8 hexVal(char c) {
+	if (c>='0' && c<='9') return c -= '0';
+	if (c>='a' && c<='f') return c -= 'a'-10;
+	if (c>='A' && c<='F') return c -= 'A'-10;
+	return 0;
+}
+
+static void proc_APList_on_close( struct inode *inode, struct file *file ) {
+	struct proc_data *data = (struct proc_data *)file->private_data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	APListRid APList_rid;
+	int i;
+	
+	if ( !data->writelen ) return;
+	
+	memset( &APList_rid, 0, sizeof(APList_rid) );
+	APList_rid.len = sizeof(APList_rid);
+	
+	for( i = 0; i < 4 && data->writelen >= (i+1)*6*3; i++ ) {
+		int j;
+		for( j = 0; j < 6*3 && data->wbuffer[j+i*6*3]; j++ ) {
+			switch(j%3) {
+			case 0:
+				APList_rid.ap[i][j/3]=
+					hexVal(data->wbuffer[j+i*6*3])<<4;
+				break;
+			case 1:
+				APList_rid.ap[i][j/3]|=
+					hexVal(data->wbuffer[j+i*6*3]);
+				break;
+			}
+		}
+	}
+	writeAPListRid(ai, &APList_rid);
+}
+
+/* This function wraps PC4500_writerid with a MAC disable */
+static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data,
+			int len ) {
+	int rc;
+	Resp rsp;
+	
+	disable_MAC(ai);
+	rc = PC4500_writerid(ai, rid, rid_data, len);
+	enable_MAC(ai, &rsp);
+	return rc;
+}
+
+/* Returns the length of the key at the index.  If index == 0xffff
+ * the index of the transmit key is returned.  If the key doesn't exist,
+ * -1 will be returned.
+ */
+static int get_wep_key(struct airo_info *ai, u16 index) {
+	WepKeyRid wkr;
+	int rc;
+	u16 lastindex;
+
+	rc = readWepKeyRid(ai, &wkr, 1);
+	if (rc == SUCCESS) do {
+		lastindex = wkr.kindex;
+		if (wkr.kindex == index) {
+			if (index == 0xffff) {
+				return wkr.mac[0];
+			}
+			return wkr.klen;
+		}
+		readWepKeyRid(ai, &wkr, 0);
+	} while(lastindex != wkr.kindex);
+	return -1;
+}
+
+static int set_wep_key(struct airo_info *ai, u16 index,
+		       const char *key, u16 keylen, int perm ) {
+	static const unsigned char macaddr[6] = { 0x01, 0, 0, 0, 0, 0 };
+	WepKeyRid wkr;
+
+	memset(&wkr, 0, sizeof(wkr));
+	if (keylen == 0) {
+// We are selecting which key to use
+		wkr.len = sizeof(wkr);
+		wkr.kindex = 0xffff;
+		wkr.mac[0] = (char)index;
+		if (perm) printk(KERN_INFO "Setting transmit key to %d\n", index);
+		if (perm) ai->defindex = (char)index;
+	} else {
+// We are actually setting the key
+		wkr.len = sizeof(wkr);
+		wkr.kindex = index;
+		wkr.klen = keylen;
+		memcpy( wkr.key, key, keylen );
+		memcpy( wkr.mac, macaddr, 6 );
+		printk(KERN_INFO "Setting key %d\n", index);
+	}
+	
+	writeWepKeyRid(ai, &wkr, perm);
+	return 0;
+}
+
+static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
+	struct proc_data *data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	int i;
+	char key[16];
+	u16 index = 0;
+	int j = 0;
+
+	memset(key, 0, sizeof(key));
+	
+	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	data = (struct proc_data *)file->private_data;
+	if ( !data->writelen ) return;
+	
+	if (data->wbuffer[0] >= '0' && data->wbuffer[0] <= '3' &&
+	    (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) {
+		index = data->wbuffer[0] - '0';
+		if (data->wbuffer[1] == '\n') {
+			set_wep_key(ai, index, 0, 0, 1);
+			return;
+		}
+		j = 2;
+	} else {
+		printk(KERN_ERR "airo:  WepKey passed invalid key index\n");
+		return;
+	}
+
+	for( i = 0; i < 16*3 && data->wbuffer[i+j]; i++ ) {
+		switch(i%3) {
+		case 0:
+			key[i/3] = hexVal(data->wbuffer[i+j])<<4;
+			break;
+		case 1:
+			key[i/3] |= hexVal(data->wbuffer[i+j]);
+			break;
+		}
+	}
+	set_wep_key(ai, index, key, i/3, 1);
+}
+
+static int proc_wepkey_open( struct inode *inode, struct file *file ) {
+	struct proc_data *data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	char *ptr;
+	WepKeyRid wkr;
+	u16 lastindex;
+	int j=0;
+	int rc;
+	
+	MOD_INC_USE_COUNT;
+	
+	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	
+	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+	memset(file->private_data, 0, sizeof(struct proc_data));
+	memset(&wkr, 0, sizeof(wkr));
+	data = (struct proc_data *)file->private_data;
+	if ((data->rbuffer = kmalloc( 180, GFP_KERNEL )) == NULL) {
+		kfree (file->private_data);
+		return -ENOMEM;
+	}
+	memset(data->rbuffer, 0, 180);
+	data->writelen = 0;
+	data->maxwritelen = 80;
+	if ((data->wbuffer = kmalloc( 80, GFP_KERNEL )) == NULL) {
+		kfree (data->rbuffer);
+		kfree (file->private_data);
+		return -ENOMEM;
+	}
+	memset( data->wbuffer, 0, 80 );
+	data->on_close = proc_wepkey_on_close;
+	
+	ptr = data->rbuffer;
+	strcpy(ptr, "No wep keys\n");
+	rc = readWepKeyRid(ai, &wkr, 1);
+	if (rc == SUCCESS) do {
+		lastindex = wkr.kindex;
+		if (wkr.kindex == 0xffff) {
+			j += sprintf(ptr+j, "Tx key = %d\n",
+				     (int)wkr.mac[0]);
+		} else {
+			j += sprintf(ptr+j, "Key %d set with length = %d\n",
+				     (int)wkr.kindex, (int)wkr.klen);
+		}
+		readWepKeyRid(ai, &wkr, 0);
+	} while((lastindex != wkr.kindex) && (j < 180-30));
+
+	data->readlen = strlen( data->rbuffer );
+	return 0;
+}
+
+static int proc_SSID_open( struct inode *inode, struct file *file ) {
+	struct proc_data *data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	int i;
+	char *ptr;
+	SsidRid SSID_rid;
+
+	MOD_INC_USE_COUNT;
+	
+	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	
+	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+	memset(file->private_data, 0, sizeof(struct proc_data));
+	data = (struct proc_data *)file->private_data;
+	if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
+		kfree (file->private_data);
+		return -ENOMEM;
+	}
+	data->writelen = 0;
+	data->maxwritelen = 33*3;
+	if ((data->wbuffer = kmalloc( 33*3, GFP_KERNEL )) == NULL) {
+		kfree (data->rbuffer);
+		kfree (file->private_data);
+		return -ENOMEM;
+	}
+	memset( data->wbuffer, 0, 33*3 );
+	data->on_close = proc_SSID_on_close;
+	
+	readSsidRid(ai, &SSID_rid);
+	ptr = data->rbuffer;
+	for( i = 0; i < 3; i++ ) {
+		int j;
+		if ( !SSID_rid.ssids[i].len ) break;
+		for( j = 0; j < 32 && 
+			     j < SSID_rid.ssids[i].len && 
+			     SSID_rid.ssids[i].ssid[j]; j++ ) {
+			*ptr++ = SSID_rid.ssids[i].ssid[j]; 
+		}
+		*ptr++ = '\n';
+	}
+	*ptr = '\0';
+	data->readlen = strlen( data->rbuffer );
+	return 0;
+}
+
+static int proc_APList_open( struct inode *inode, struct file *file ) {
+	struct proc_data *data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	int i;
+	char *ptr;
+	APListRid APList_rid;
+
+	MOD_INC_USE_COUNT;
+	
+	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	
+	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+	memset(file->private_data, 0, sizeof(struct proc_data));
+	data = (struct proc_data *)file->private_data;
+	if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
+		kfree (file->private_data);
+		return -ENOMEM;
+	}
+	data->writelen = 0;
+	data->maxwritelen = 4*6*3;
+	if ((data->wbuffer = kmalloc( data->maxwritelen, GFP_KERNEL )) == NULL) {
+		kfree (data->rbuffer);
+		kfree (file->private_data);
+		return -ENOMEM;
+	}
+	memset( data->wbuffer, 0, data->maxwritelen );
+	data->on_close = proc_APList_on_close;
+	
+	readAPListRid(ai, &APList_rid);
+	ptr = data->rbuffer;
+	for( i = 0; i < 4; i++ ) {
+// We end when we find a zero MAC
+		if ( !*(int*)APList_rid.ap[i] &&
+		     !*(int*)&APList_rid.ap[i][2]) break;
+		ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+			       (int)APList_rid.ap[i][0],
+			       (int)APList_rid.ap[i][1],
+			       (int)APList_rid.ap[i][2],
+			       (int)APList_rid.ap[i][3],
+			       (int)APList_rid.ap[i][4],
+			       (int)APList_rid.ap[i][5]);
+	}
+	if (i==0) ptr += sprintf(ptr, "Not using specific APs\n");
+
+	*ptr = '\0';
+	data->readlen = strlen( data->rbuffer );
+	return 0;
+}
+
+static int proc_close( struct inode *inode, struct file *file ) 
+{
+	struct proc_data *data = (struct proc_data *)file->private_data;
+	if ( data->on_close != NULL ) data->on_close( inode, file );
+	MOD_DEC_USE_COUNT;
+	if ( data->rbuffer ) kfree( data->rbuffer );
+	if ( data->wbuffer ) kfree( data->wbuffer );
+	kfree( data );
+	return 0;
+}
+
+static struct net_device_list {
+	struct net_device *dev;
+	struct net_device_list *next;
+} *airo_devices = 0;
+
+/* Since the card doesnt automatically switch to the right WEP mode,
+   we will make it do it.  If the card isn't associated, every secs we
+   will switch WEP modes to see if that will help.  If the card is
+   associated we will check every minute to see if anything has
+   changed. */
+static void timer_func( u_long data ) {
+	struct net_device *dev = (struct net_device*)data;
+	struct airo_info *apriv = (struct airo_info *)dev->priv;
+	u16 linkstat = IN4500(apriv, LINKSTAT);
+	
+	if (linkstat != 0x400 ) {
+/* We don't have a link so try changing the authtype */
+		ConfigRid config = apriv->config;
+
+		switch(apriv->authtype) {
+		case AUTH_ENCRYPT:
+/* So drop to OPEN */
+			config.authType = AUTH_OPEN;
+			apriv->authtype = AUTH_OPEN;
+			break;
+		case AUTH_SHAREDKEY:
+			if (apriv->keyindex < auto_wep) {
+				set_wep_key(apriv, apriv->keyindex, 0, 0, 0);
+				config.authType = AUTH_SHAREDKEY;
+				apriv->authtype = AUTH_SHAREDKEY;
+				apriv->keyindex++;
+			} else {
+			        /* Drop to ENCRYPT */
+				apriv->keyindex = 0;
+				set_wep_key(apriv, apriv->defindex, 0, 0, 0);
+				config.authType = AUTH_ENCRYPT;
+				apriv->authtype = AUTH_ENCRYPT;
+			}
+			break;
+		default:  /* We'll escalate to SHAREDKEY */
+			config.authType = AUTH_SHAREDKEY;
+			apriv->authtype = AUTH_SHAREDKEY;
+		}
+		checkThrottle(&config);
+		writeConfigRid(apriv, &config);
+
+/* Schedule check to see if the change worked */
+		apriv->timer.expires = RUN_AT(HZ*3);
+		add_timer(&apriv->timer);
+	}
+}
+
+static int add_airo_dev( struct net_device *dev ) {
+	struct net_device_list *node = kmalloc( sizeof( *node ), GFP_KERNEL );
+	if ( !node )
+		return -ENOMEM;
+
+	if ( auto_wep ) {
+		struct airo_info *apriv=dev->priv;
+		struct timer_list *timer = &apriv->timer;
+			
+		timer->function = timer_func;
+		timer->data = (u_long)dev;
+		init_timer(timer);
+		apriv->authtype = AUTH_SHAREDKEY;
+	}
+		
+	node->dev = dev;
+	node->next = airo_devices;
+	airo_devices = node;
+
+	return 0;
+}
+
+static void del_airo_dev( struct net_device *dev ) {
+	struct net_device_list **p = &airo_devices;
+	while( *p && ( (*p)->dev != dev ) )
+		p = &(*p)->next;
+	if ( *p && (*p)->dev == dev )
+		*p = (*p)->next; 
+}
+
+#ifdef CONFIG_PCI
+static int __devinit airo_pci_probe(struct pci_dev *pdev, 
+				    const struct pci_device_id *pent)
+{
+	pdev->driver_data = init_airo_card(pdev->irq, 
+					   pdev->resource[2].start, 0);
+	if (!pdev->driver_data) {
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void __devexit airo_pci_remove(struct pci_dev *pdev)
+{
+	stop_airo_card(pdev->driver_data, 1);
+}
+
+#endif
+
+static int __init airo_init_module( void )
+{
+	int i, rc = 0, have_isa_dev = 0;
+	
+	airo_entry = create_proc_entry("aironet",
+				       S_IFDIR | airo_perm,
+				       proc_root_driver);
+        airo_entry->uid = proc_uid;
+        airo_entry->gid = proc_gid;
+	
+	for( i = 0; i < 4 && io[i] && irq[i]; i++ ) {
+		printk( KERN_INFO 
+			"airo:  Trying to configure ISA adapter at irq=%d io=0x%x\n",
+			irq[i], io[i] );
+		if (init_airo_card( irq[i], io[i], 0 ))
+			have_isa_dev = 1;
+	}
+	
+#ifdef CONFIG_PCI
+	printk( KERN_INFO "airo:  Probing for PCI adapters\n" );
+	rc = pci_module_init(&airo_driver);
+	printk( KERN_INFO "airo:  Finished probing for PCI adapters\n" );
+#endif
+
+	/* arguably, we should clean up and error exit if pci_module_init
+	 * fails with an error other than -ENODEV, instead of proceeding,
+	 * if ISA devs are present.
+	 */
+	if (have_isa_dev)
+		return 0;
+	if (rc && (rc != -ENODEV))
+		return rc;
+	return 0;
+}
+
+static void __exit airo_cleanup_module( void )
+{
+	while( airo_devices ) {
+		printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name );
+		stop_airo_card( airo_devices->dev, 1 );
+	}
+	remove_proc_entry("aironet", proc_root_driver);
+}
+
+#ifdef WIRELESS_EXT
+/*
+ * Initial Wireless Extension code for Aironet driver by :
+ *	Jean Tourrilhes <jt@hpl.hp.com> - HPL - 17 November 00
+ */
+#ifndef IW_ENCODE_NOKEY
+#define IW_ENCODE_NOKEY         0x0800  /* Key is write only, so not present */
+#define IW_ENCODE_MODE  (IW_ENCODE_DISABLED | IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)
+#endif /* IW_ENCODE_NOKEY */
+#endif /* WIRELESS_EXT */
+
+/*
+ * This defines the configuration part of the Wireless Extensions
+ * Note : irq and spinlock protection will occur in the subroutines
+ *
+ * TODO :
+ *	o Check input value more carefully and fill correct values in range
+ *	o Implement : POWER, SPY, APLIST
+ *	o Optimise when adapter is closed (aggregate changes, commit later)
+ *	o Test and shakeout the bugs (if any)
+ *
+ * Jean II
+ *
+ * Javier Achirica did a great job of merging code from the unnamed CISCO
+ * developer that added support for flashing the card.
+ */
+static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	int rc = 0;
+#ifdef WIRELESS_EXT
+	struct airo_info *local = (struct airo_info*) dev->priv;
+	struct iwreq *wrq = (struct iwreq *) rq;
+	ConfigRid config;		/* Configuration info */
+	CapabilityRid cap_rid;		/* Card capability info */
+	StatusRid status_rid;		/* Card status info */
+	int i;
+
+#ifdef CISCO_EXT
+	if (cmd != SIOCGIWPRIV && cmd != AIROIOCTL && cmd != AIROIDIFC)
+#endif /* CISCO_EXT */
+	{
+		/* If the command read some stuff, we better get it out of
+		 * the card first... */
+		if(IW_IS_GET(cmd))
+			readStatusRid(local, &status_rid);
+		if(IW_IS_GET(cmd) || (cmd == SIOCSIWRATE) || (cmd == SIOCSIWENCODE))
+			readCapabilityRid(local, &cap_rid);
+		/* Get config in all cases, because SET will just modify it */
+		readConfigRid(local, &config);
+	}
+#endif /* WIRELESS_EXT */
+
+	switch (cmd) {
+#ifdef WIRELESS_EXT
+		// Get name
+	case SIOCGIWNAME:
+		strcpy(wrq->u.name, "IEEE 802.11-DS");
+		break;
+
+		// Set frequency/channel
+	case SIOCSIWFREQ:
+		/* If setting by frequency, convert to a channel */
+		if((wrq->u.freq.e == 1) &&
+		   (wrq->u.freq.m >= (int) 2.412e8) &&
+		   (wrq->u.freq.m <= (int) 2.487e8)) {
+			int f = wrq->u.freq.m / 100000;
+			int c = 0;
+			while((c < 14) && (f != frequency_list[c]))
+				c++;
+			/* Hack to fall through... */
+			wrq->u.freq.e = 0;
+			wrq->u.freq.m = c + 1;
+		}
+		/* Setting by channel number */
+		if((wrq->u.freq.m > 1000) || (wrq->u.freq.e > 0))
+			rc = -EOPNOTSUPP;
+		else {
+			int channel = wrq->u.freq.m;
+			/* We should do a better check than that,
+			 * based on the card capability !!! */
+			if((channel < 1) || (channel > 16)) {
+				printk(KERN_DEBUG "%s: New channel value of %d is invalid!\n", dev->name, wrq->u.freq.m);
+				rc = -EINVAL;
+			} else {
+				/* Yes ! We can set it !!! */
+				config.channelSet = (u16)(channel - 1);
+				local->need_commit = 1;
+			}
+		}
+		break;
+
+		// Get frequency/channel
+	case SIOCGIWFREQ:
+#ifdef WEXT_USECHANNELS
+		wrq->u.freq.m = ((int)status_rid.channel) + 1;
+		wrq->u.freq.e = 0;
+#else
+		{
+			int f = (int)status_rid.channel;
+			wrq->u.freq.m = frequency_list[f] * 100000;
+			wrq->u.freq.e = 1;
+		}
+#endif
+		break;
+
+		// Set desired network name (ESSID)
+	case SIOCSIWESSID:
+		if (wrq->u.data.pointer) {
+			char	essid[IW_ESSID_MAX_SIZE + 1];
+			SsidRid SSID_rid;		/* SSIDs */
+
+			/* Reload the list of current SSID */
+			readSsidRid(local, &SSID_rid);
+
+			/* Check if we asked for `any' */
+			if(wrq->u.data.flags == 0) {
+				/* Just send an empty SSID list */
+				memset(&SSID_rid, 0, sizeof(SSID_rid));
+			} else {
+				int	index = (wrq->u.data.flags &
+						 IW_ENCODE_INDEX) - 1;
+
+				/* Check the size of the string */
+				if(wrq->u.data.length > IW_ESSID_MAX_SIZE+1) {
+					rc = -E2BIG;
+					break;
+				}
+				/* Check if index is valid */
+				if((index < 0) || (index >= 4)) {
+					rc = -EINVAL;
+					break;
+				}
+
+				/* Set the SSID */
+				memset(essid, 0, sizeof(essid));
+				copy_from_user(essid,
+					       wrq->u.data.pointer,
+					       wrq->u.data.length);
+				memcpy(SSID_rid.ssids[index].ssid, essid,
+				       sizeof(essid) - 1);
+				SSID_rid.ssids[index].len = wrq->u.data.length - 1;
+			}
+			/* Write it to the card */
+			writeSsidRid(local, &SSID_rid);
+		}
+		break;
+
+		// Get current network name (ESSID)
+	case SIOCGIWESSID:
+		if (wrq->u.data.pointer) {
+			char essid[IW_ESSID_MAX_SIZE + 1];
+
+			/* Note : if wrq->u.data.flags != 0, we should
+			 * get the relevant SSID from the SSID list... */
+
+			/* Get the current SSID */
+			memcpy(essid, status_rid.SSID, status_rid.SSIDlen);
+			essid[status_rid.SSIDlen] = '\0';
+			/* If none, we may want to get the one that was set */
+
+			/* Push it out ! */
+			wrq->u.data.length = strlen(essid) + 1;
+			wrq->u.data.flags = 1; /* active */
+			if (copy_to_user(wrq->u.data.pointer, essid, sizeof(essid)))
+				rc = -EFAULT;
+		}
+		break;
+
+	case SIOCSIWAP:
+		if (wrq->u.ap_addr.sa_family != ARPHRD_ETHER)
+			rc = -EINVAL;
+		else {
+			APListRid APList_rid;
+
+			memset(&APList_rid, 0, sizeof(APList_rid));
+			APList_rid.len = sizeof(APList_rid);
+			memcpy(APList_rid.ap[0], wrq->u.ap_addr.sa_data, 6);
+			writeAPListRid(local, &APList_rid);
+			local->need_commit = 1;
+		}
+		break;
+
+		// Get current Access Point (BSSID)
+	case SIOCGIWAP:
+		/* Tentative. This seems to work, wow, I'm lucky !!! */
+		memcpy(wrq->u.ap_addr.sa_data, status_rid.bssid[0], 6);
+		wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
+		break;
+
+		// Set desired station name
+	case SIOCSIWNICKN:
+		if (wrq->u.data.pointer) {
+			char	name[16 + 1];
+
+			/* Check the size of the string */
+			if(wrq->u.data.length > 16 + 1) {
+				rc = -E2BIG;
+				break;
+			}
+			memset(name, 0, sizeof(name));
+			copy_from_user(name, wrq->u.data.pointer, wrq->u.data.length);
+			memcpy(config.nodeName, name, 16);
+			local->need_commit = 1;
+		}
+		break;
+
+		// Get current station name
+	case SIOCGIWNICKN:
+		if (wrq->u.data.pointer) {
+			char name[IW_ESSID_MAX_SIZE + 1];
+
+			strncpy(name, config.nodeName, 16);
+			name[16] = '\0';
+			wrq->u.data.length = strlen(name) + 1;
+			if (copy_to_user(wrq->u.data.pointer, name, sizeof(name)))
+				rc = -EFAULT;
+		}
+		break;
+
+		// Set the desired bit-rate
+	case SIOCSIWRATE:
+	{
+		/* First : get a valid bit rate value */
+		u8	brate = 0;
+		int	i;
+
+		/* Which type of value ? */
+		if((wrq->u.bitrate.value < 8) &&
+		   (wrq->u.bitrate.value >= 0)) {
+			/* Setting by rate index */
+			/* Find value in the magic rate table */
+			brate = cap_rid.supportedRates[wrq->u.bitrate.value];
+		} else {
+			/* Setting by frequency value */
+			u8	normvalue = (u8) (wrq->u.bitrate.value/500000);
+
+			/* Check if rate is valid */
+			for(i = 0 ; i < 8 ; i++) {
+				if(normvalue == cap_rid.supportedRates[i]) {
+					brate = normvalue;
+					break;
+				}
+			}
+		}
+		/* -1 designed the max rate (mostly auto mode) */
+		if(wrq->u.bitrate.value == -1) {
+			/* Get the highest available rate */
+			for(i = 0 ; i < 8 ; i++) {
+				if(cap_rid.supportedRates[i] == 0)
+					break;
+			}
+			if(i != 0)
+				brate = cap_rid.supportedRates[i - 1];
+		}
+		/* Check that it is valid */
+		if(brate == 0) {
+			rc = -EINVAL;
+			break;
+		}
+
+		/* Now, check if we want a fixed or auto value */
+		if(wrq->u.bitrate.fixed == 0) {
+			/* Fill all the rates up to this max rate */
+			memset(config.rates, 0, 8);
+			for(i = 0 ; i < 8 ; i++) {
+				config.rates[i] = cap_rid.supportedRates[i];
+				if(config.rates[i] == brate)
+					break;
+			}
+			local->need_commit = 1;
+		} else {
+			/* Fixed mode */
+			/* One rate, fixed */
+			memset(config.rates, 0, 8);
+			config.rates[0] = brate;
+			local->need_commit = 1;
+		}
+		break;
+	}
+
+	// Get the current bit-rate
+	case SIOCGIWRATE:
+	{
+		int brate = status_rid.currentXmitRate;
+		wrq->u.bitrate.value = brate * 500000;
+		/* If more than one rate, set auto */
+		wrq->u.rts.fixed = (config.rates[1] == 0);
+	}
+	break;
+
+	// Set the desired RTS threshold
+	case SIOCSIWRTS:
+	{
+		int rthr = wrq->u.rts.value;
+		if(wrq->u.rts.disabled)
+			rthr = 2312;
+		if((rthr < 0) || (rthr > 2312)) {
+			rc = -EINVAL;
+		} else {
+			config.rtsThres = rthr;
+			local->need_commit = 1;
+		}
+	}
+	break;
+
+	// Get the current RTS threshold
+	case SIOCGIWRTS:
+		wrq->u.rts.value = config.rtsThres;
+		wrq->u.rts.disabled = (wrq->u.rts.value >= 2312);
+		wrq->u.rts.fixed = 1;
+		break;
+
+		// Set the desired fragmentation threshold
+	case SIOCSIWFRAG:
+	{
+		int fthr = wrq->u.frag.value;
+		if(wrq->u.frag.disabled)
+			fthr = 2312;
+		if((fthr < 256) || (fthr > 2312)) {
+			rc = -EINVAL;
+		} else {
+			fthr &= ~0x1;	/* Get an even value */
+			config.fragThresh = (u16)fthr;
+			local->need_commit = 1;
+		}
+	}
+	break;
+
+	// Get the current fragmentation threshold
+	case SIOCGIWFRAG:
+		wrq->u.frag.value = config.fragThresh;
+		wrq->u.frag.disabled = (wrq->u.frag.value >= 2312);
+		wrq->u.frag.fixed = 1;
+		break;
+
+		// Set mode of operation
+	case SIOCSIWMODE:
+		switch(wrq->u.mode) {
+		case IW_MODE_ADHOC:
+			config.opmode = MODE_STA_IBSS;
+			local->need_commit = 1;
+			break;
+		case IW_MODE_INFRA:
+			config.opmode = MODE_STA_ESS;
+			local->need_commit = 1;
+			break;
+		case IW_MODE_MASTER:
+			config.opmode = MODE_AP;
+			local->need_commit = 1;
+			break;
+		case IW_MODE_REPEAT:
+			config.opmode = MODE_AP_RPTR;
+			local->need_commit = 1;
+			break;
+		default:
+			rc = -EINVAL;
+		}
+		break;
+
+		// Get mode of operation
+	case SIOCGIWMODE:
+		/* If not managed, assume it's ad-hoc */
+		switch (config.opmode & 0xFF) {
+		case MODE_STA_ESS:
+			wrq->u.mode = IW_MODE_INFRA;
+			break;
+		case MODE_AP:
+			wrq->u.mode = IW_MODE_MASTER;
+			break;
+		case MODE_AP_RPTR:
+			wrq->u.mode = IW_MODE_REPEAT;
+			break;
+		default:
+			wrq->u.mode = IW_MODE_ADHOC;
+		}
+		break;
+
+		// Set WEP keys and mode
+	case SIOCSIWENCODE:
+		/* Is WEP supported ? */
+		/* Older firmware doesn't support this...
+		if(!(cap_rid.softCap & 2)) {
+			rc = -EOPNOTSUPP;
+			break;
+		} */
+		/* Basic checking: do we have a key to set ? */
+		if (wrq->u.encoding.pointer != (caddr_t) 0) {
+			wep_key_t key;
+			int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1;
+			int current_index = get_wep_key(local, 0xffff);
+			/* Check the size of the key */
+			if (wrq->u.encoding.length > MAX_KEY_SIZE) {
+				rc = -EINVAL;
+				break;
+			}
+			/* Check the index (none -> use current) */
+			if ((index < 0) || (index >= MAX_KEYS))
+				index = current_index;
+			/* Set the length */
+			if (wrq->u.encoding.length > MIN_KEY_SIZE)
+				key.len = MAX_KEY_SIZE;
+			else
+				if (wrq->u.encoding.length > 0)
+					key.len = MIN_KEY_SIZE;
+				else
+					/* Disable the key */
+					key.len = 0;
+			/* Check if the key is not marked as invalid */
+			if(!(wrq->u.encoding.flags & IW_ENCODE_NOKEY)) {
+				/* Cleanup */
+				memset(key.key, 0, MAX_KEY_SIZE);
+				/* Copy the key in the driver */
+				if(copy_from_user(key.key,
+						  wrq->u.encoding.pointer,
+						  wrq->u.encoding.length)) {
+					key.len = 0;
+					rc = -EFAULT;
+					break;
+				}
+				/* Send the key to the card */
+				set_wep_key(local, index, key.key,
+					    key.len, 1);
+			}
+			/* WE specify that if a valid key is set, encryption
+			 * should be enabled (user may turn it off later)
+			 * This is also how "iwconfig ethX key on" works */
+			if((index == current_index) && (key.len > 0) &&
+			   (config.authType == AUTH_OPEN)) {
+				config.authType = AUTH_ENCRYPT;
+				local->need_commit = 1;
+			}
+		} else {
+			/* Do we want to just set the transmit key index ? */
+			int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1;
+			if ((index >= 0) && (index < MAX_KEYS)) {
+				set_wep_key(local, index, 0, 0, 1);
+			} else
+				/* Don't complain if only change the mode */
+				if(!wrq->u.encoding.flags & IW_ENCODE_MODE) {
+					rc = -EINVAL;
+					break;
+				}
+		}
+		/* Read the flags */
+		if(wrq->u.encoding.flags & IW_ENCODE_DISABLED)
+			config.authType = AUTH_OPEN;	// disable encryption
+		if(wrq->u.encoding.flags & IW_ENCODE_RESTRICTED)
+			config.authType = AUTH_SHAREDKEY;	// Only Both
+		if(wrq->u.encoding.flags & IW_ENCODE_OPEN)
+			config.authType = AUTH_ENCRYPT;	// Only Wep
+		/* Commit the changes if needed */
+		if(wrq->u.encoding.flags & IW_ENCODE_MODE)
+			local->need_commit = 1;
+		break;
+
+		// Get the WEP keys and mode
+	case SIOCGIWENCODE:
+		/* Is it supported ? */
+		if(!(cap_rid.softCap & 2)) {
+			rc = -EOPNOTSUPP;
+			break;
+		}
+		// Only super-user can see WEP key
+		if (!capable(CAP_NET_ADMIN)) {
+			rc = -EPERM;
+			break;
+		}
+
+		// Basic checking...
+		if (wrq->u.encoding.pointer != (caddr_t) 0) {
+			char zeros[16];
+			int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1;
+
+			memset(zeros,0, sizeof(zeros));
+			/* Check encryption mode */
+			wrq->u.encoding.flags = IW_ENCODE_NOKEY;
+			/* Is WEP enabled ??? */
+			switch(config.authType)	{
+			case AUTH_ENCRYPT:
+				wrq->u.encoding.flags |= IW_ENCODE_OPEN;
+				break;
+			case AUTH_SHAREDKEY:
+				wrq->u.encoding.flags |= IW_ENCODE_RESTRICTED;
+				break;
+			default:
+			case AUTH_OPEN:
+				wrq->u.encoding.flags |= IW_ENCODE_DISABLED;
+				break;
+			}
+
+			/* Which key do we want ? -1 -> tx index */
+			if((index < 0) || (index >= MAX_KEYS))
+				index = get_wep_key(local, 0xffff);
+			wrq->u.encoding.flags |= index + 1;
+			/* Copy the key to the user buffer */
+			wrq->u.encoding.length = get_wep_key(local, index);
+			if (wrq->u.encoding.length > 16) {
+				wrq->u.encoding.length=0;
+			}
+
+			if(copy_to_user(wrq->u.encoding.pointer, zeros,
+					wrq->u.encoding.length))
+				rc = -EFAULT;
+		}
+		break;
+
+#if WIRELESS_EXT > 9
+		// Get the current Tx-Power
+	case SIOCGIWTXPOW:
+		wrq->u.txpower.value = config.txPower;
+		wrq->u.txpower.fixed = 1;	/* No power control */
+		wrq->u.txpower.disabled = (local->flags & FLAG_RADIO_OFF);
+		wrq->u.txpower.flags = IW_TXPOW_MWATT;
+		break;
+	case SIOCSIWTXPOW:
+		if (wrq->u.txpower.disabled) {
+			local->flags |= FLAG_RADIO_OFF;
+			local->need_commit = 1;
+			break;
+		}
+		if (wrq->u.txpower.flags != IW_TXPOW_MWATT) {
+			rc = -EINVAL;
+			break;
+		}
+		local->flags &= ~FLAG_RADIO_OFF;
+		rc = -EINVAL;
+		for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
+			if ((wrq->u.txpower.value==cap_rid.txPowerLevels[i])) {
+				config.txPower = wrq->u.txpower.value;
+				local->need_commit = 1;
+				rc = 0;
+				break;
+			}
+		break;
+#endif /* WIRELESS_EXT > 9 */
+
+#if WIRELESS_EXT > 10
+	case SIOCGIWRETRY:
+		wrq->u.retry.disabled = 0;
+		if ((wrq->u.retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
+			wrq->u.retry.value = (int)config.txLifetime * 1024;
+		else {
+			wrq->u.retry.value = (int)config.shortRetryLimit;
+			wrq->u.retry.flags = IW_RETRY_LIMIT;
+		}
+		break;
+
+	case SIOCSIWRETRY: 
+		if (wrq->u.retry.disabled) {
+			config.shortRetryLimit = 0;
+			config.longRetryLimit = 0;
+			config.txLifetime = 0;
+			local->need_commit = 1;
+			break;
+		}
+		if ((wrq->u.retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+			config.txLifetime = (wrq->u.retry.value + 500) / 1024;
+			local->need_commit = 1;
+		} else if ((wrq->u.retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIMIT) {
+			config.shortRetryLimit = config.longRetryLimit = wrq->u.retry.value;
+			local->need_commit = 1;
+		}
+		break;
+#endif /* WIRELESS_EXT > 10 */
+
+		// Get range of parameters
+	case SIOCGIWRANGE:
+		if (wrq->u.data.pointer) {
+			struct iw_range range;
+			int		i;
+			int		k;
+
+			wrq->u.data.length = sizeof(range);
+			/* Should adapt depending on max rate */
+			range.throughput = 1.6 * 1024 * 1024;
+			range.min_nwid = 0x0000;
+			range.max_nwid = 0x0000;
+			range.num_channels = 14;
+			/* Should be based on cap_rid.country to give only
+			 * what the current card support */
+			k = 0;
+			for(i = 0; i < 14; i++) {
+				range.freq[k].i = i + 1; /* List index */
+				range.freq[k].m = frequency_list[i] * 100000;
+				range.freq[k++].e = 1;	/* Values in table in MHz -> * 10^5 * 10 */
+			}
+			range.num_frequency = k;
+
+			/* Hum... Should put the right values there */
+			range.max_qual.qual = 10;
+			range.max_qual.level = 100;
+			range.max_qual.noise = 0;
+			range.sensitivity = 65535;
+
+			for(i = 0 ; i < 8 ; i++) {
+				range.bitrate[i] = cap_rid.supportedRates[i] * 500000;
+				if(range.bitrate[i] == 0)
+					break;
+			}
+			range.num_bitrates = i;
+
+			range.min_rts = 0;
+			range.max_rts = 2312;
+			range.min_frag = 256;
+			range.max_frag = 2312;
+
+			if(cap_rid.softCap & 2) {
+				// WEP: RC4 40 bits
+				range.encoding_size[0] = 5;
+				// RC4 ~128 bits
+				if (cap_rid.softCap & 0x100) {
+					range.encoding_size[1] = 13;
+					range.num_encoding_sizes = 2;
+				} else
+					range.num_encoding_sizes = 1;
+				range.max_encoding_tokens = 4;	// 4 keys
+			} else {
+				range.num_encoding_sizes = 0;
+				range.max_encoding_tokens = 0;
+			}
+#if WIRELESS_EXT > 9
+			range.min_pmp = 0;
+			range.max_pmp = 5000000;	/* 5 secs */
+			range.min_pmt = 0;
+			range.max_pmt = 65535 * 1024;	/* ??? */
+			range.pmp_flags = IW_POWER_PERIOD;
+			range.pmt_flags = IW_POWER_TIMEOUT;
+			range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
+
+			/* Transmit Power - values are in mW */
+			for(i = 0 ; i < 8 ; i++) {
+				range.txpower[i] = cap_rid.txPowerLevels[i];
+				if(range.txpower[i] == 0)
+					break;
+			}
+			range.num_txpower = i;
+			range.txpower_capa = IW_TXPOW_MWATT;
+#endif /* WIRELESS_EXT > 9 */
+#if WIRELESS_EXT > 10
+			range.we_version_source = 11;
+			range.we_version_compiled = WIRELESS_EXT;
+			range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
+			range.retry_flags = IW_RETRY_LIMIT;
+			range.r_time_flags = IW_RETRY_LIFETIME;
+			range.min_retry = 1;
+			range.max_retry = 65535;
+			range.min_r_time = 1024;
+			range.max_r_time = 65535 * 1024;
+#endif /* WIRELESS_EXT > 10 */
+
+			if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range)))
+				rc = -EFAULT;
+		}
+		break;
+
+	case SIOCGIWPOWER:
+	{
+		int mode = config.powerSaveMode;
+		if ((wrq->u.power.disabled = (mode == POWERSAVE_CAM)))
+			break;
+		if ((wrq->u.power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+			wrq->u.power.value = (int)config.fastListenDelay * 1024;
+			wrq->u.power.flags = IW_POWER_TIMEOUT;
+		} else {
+			wrq->u.power.value = (int)config.fastListenInterval * 1024;
+			wrq->u.power.flags = IW_POWER_PERIOD;
+		}
+		if ((config.rmode & 0xFF) == RXMODE_ADDR)
+			wrq->u.power.flags |= IW_POWER_UNICAST_R;
+		else
+			wrq->u.power.flags |= IW_POWER_ALL_R;
+	}
+	break;
+
+	case SIOCSIWPOWER: 
+		if (wrq->u.power.disabled) {
+			if ((config.rmode & 0xFF) >= RXMODE_RFMON) {
+				rc = -EINVAL;
+				break;
+			}
+			config.powerSaveMode = POWERSAVE_CAM;
+			config.rmode &= 0xFF00;
+			config.rmode |= RXMODE_BC_MC_ADDR;
+			local->need_commit = 1;
+			break;
+		}
+		if ((wrq->u.power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+			config.fastListenDelay = (wrq->u.power.value + 500) / 1024;
+			config.powerSaveMode = POWERSAVE_PSPCAM;
+			local->need_commit = 1;
+		} else if ((wrq->u.power.flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
+			config.fastListenInterval = config.listenInterval = (wrq->u.power.value + 500) / 1024;
+			config.powerSaveMode = POWERSAVE_PSPCAM;
+			local->need_commit = 1;
+		}
+		switch (wrq->u.power.flags & IW_POWER_MODE) {
+		case IW_POWER_UNICAST_R:
+			if ((config.rmode & 0xFF) >= RXMODE_RFMON) {
+				rc = -EINVAL;
+				break;
+			}
+			config.rmode &= 0xFF00;
+			config.rmode |= RXMODE_ADDR;
+			local->need_commit = 1;
+			break;
+		case IW_POWER_ALL_R:
+			if ((config.rmode & 0xFF) >= RXMODE_RFMON) {
+				rc = -EINVAL;
+				break;
+			}
+			config.rmode &= 0xFF00;
+			config.rmode |= RXMODE_BC_MC_ADDR;
+			local->need_commit = 1;
+		case IW_POWER_ON:
+			break;
+		default:
+			rc = -EINVAL;
+		}
+		break;
+
+	case SIOCGIWSENS:
+		wrq->u.sens.value = config.rssiThreshold;
+		wrq->u.sens.disabled = (wrq->u.sens.value == 0);
+		wrq->u.sens.fixed = 1;
+		break;
+
+	case SIOCSIWSENS:
+		config.rssiThreshold = wrq->u.sens.disabled ? RSSI_DEFAULT : wrq->u.sens.value;
+		local->need_commit = 1;
+		break;
+
+	case SIOCGIWAPLIST:
+		if (wrq->u.data.pointer) {
+			int i;
+			struct sockaddr s[4];
+
+			for (i = 0; i < 4; i++) {
+				memcpy(s[i].sa_data, status_rid.bssid[i], 6);
+				s[i].sa_family = ARPHRD_ETHER;
+			}
+			wrq->u.data.length = 4;
+			if (copy_to_user(wrq->u.data.pointer, &s, sizeof(s)))
+				rc = -EFAULT;
+		}
+		break;
+
+#ifdef WIRELESS_SPY
+		// Set the spy list
+	case SIOCSIWSPY:
+		if (wrq->u.data.length > IW_MAX_SPY)
+		{
+			rc = -E2BIG;
+			break;
+		}
+		local->spy_number = wrq->u.data.length;
+		if (local->spy_number > 0)
+		{
+			struct sockaddr address[IW_MAX_SPY];
+			int i;
+
+			if (copy_from_user(address, wrq->u.data.pointer,
+					   sizeof(struct sockaddr) * local->spy_number)) {
+				rc = -EFAULT;
+				break;
+			}
+			for (i=0; i<local->spy_number; i++)
+				memcpy(local->spy_address[i], address[i].sa_data, 6);
+			memset(local->spy_stat, 0, sizeof(struct iw_quality) * IW_MAX_SPY);
+		}
+		break;
+
+		// Get the spy list
+	case SIOCGIWSPY:
+		wrq->u.data.length = local->spy_number;
+		if ((local->spy_number > 0) && (wrq->u.data.pointer))
+		{
+			struct sockaddr address[IW_MAX_SPY];
+			int i;
+			rc = verify_area(VERIFY_WRITE, wrq->u.data.pointer, (sizeof(struct iw_quality)+sizeof(struct sockaddr)) * IW_MAX_SPY);
+			if (rc)
+				break;
+			for (i=0; i<local->spy_number; i++)
+			{
+				memcpy(address[i].sa_data, local->spy_address[i], 6);
+				address[i].sa_family = AF_UNIX;
+			}
+			copy_to_user(wrq->u.data.pointer, address, sizeof(struct sockaddr) * local->spy_number);
+			copy_to_user(wrq->u.data.pointer + (sizeof(struct sockaddr)*local->spy_number), local->spy_stat, sizeof(struct iw_quality) * local->spy_number);
+			for (i=0; i<local->spy_number; i++)
+				local->spy_stat[i].updated = 0;
+		}
+		break;
+#endif /* WIRELESS_SPY */
+
+#ifdef CISCO_EXT
+	case SIOCGIWPRIV:
+		if(wrq->u.data.pointer)
+		{
+			struct iw_priv_args   priv[] =
+			{ /* cmd, set_args, get_args, name */
+				{ AIROIOCTL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl), IW_PRIV_TYPE_BYTE | 2047, "airoioctl" },
+				{ AIROIDIFC, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl), IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" },
+			};
+
+			/* Set the number of ioctl available */
+			wrq->u.data.length = 2;
+
+			/* Copy structure to the user buffer */
+			if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
+					sizeof(priv)))
+				rc = -EFAULT;
+		}
+		break;
+#endif /* CISCO_EXT */
+#endif /* WIRELESS_EXT */
+
+#ifdef CISCO_EXT
+	case AIROIDIFC:
+	{
+		int val = AIROMAGIC;
+		aironet_ioctl com;
+		if (copy_from_user(&com,rq->ifr_data,sizeof(com)))
+			rc = -EFAULT;
+		else if (copy_to_user(com.data,(char *)&val,sizeof(val)))
+			rc = -EFAULT;
+	}
+	break;
+  
+	case AIROIOCTL:
+		/* Get the command struct and hand it off for evaluation by 
+		 * the proper subfunction
+		 */
+	{
+		aironet_ioctl com;
+		copy_from_user(&com,rq->ifr_data,sizeof(com));
+
+		/* Seperate R/W functions bracket legality here
+		 */
+		if ( com.command <= AIROGSTATSD32 )
+			rc = readrids(dev,&com);
+		else if ( com.command >= AIROPCAP && com.command <= AIROPLEAPUSR )
+			rc = writerids(dev,&com);
+		else if ( com.command >= AIROFLSHRST && com.command <= AIRORESTART )
+			rc = flashcard(dev,&com);
+		else
+			rc = -EINVAL;      /* Bad command in ioctl */
+	}
+	break;
+#endif /* CISCO_EXT */
+
+	// All other calls are currently unsupported
+	default:
+		rc = -EOPNOTSUPP;
+	}
+
+#ifdef WIRELESS_EXT
+	/* Some of the "SET" function may have modified some of the
+	 * parameters. It's now time to commit them in the card */
+	if(local->need_commit) {
+		/* A classical optimisation here is to not commit any change
+		 * if the card is not "opened". This is what we do in
+		 * wvlan_cs (see for details).
+		 * For that, we would need to have the config RID saved in
+		 * the airo_info struct and make sure to not re-read it if
+		 * local->need_commit != 0. Then, you need to patch "open"
+		 * to do the final commit of all parameters...
+		 * Jean II */
+		Resp rsp;
+
+		disable_MAC(local);
+		local->config = config;	/* ???? config is local !!! */
+		checkThrottle(&config);
+		writeConfigRid(local, &config);
+		enable_MAC(local, &rsp);
+
+		local->need_commit = 0;
+	}
+#endif /* WIRELESS_EXT */
+
+	return(rc);
+}
+
+#ifdef WIRELESS_EXT
+/*
+ * Get the Wireless stats out of the driver
+ * Note : irq and spinlock protection will occur in the subroutines
+ *
+ * TODO :
+ *	o Check if work in Ad-Hoc mode (otherwise, use SPY, as in wvlan_cs)
+ *	o Find the noise level
+ *	o Convert values to dBm
+ *	o Fill out discard.misc with something interesting
+ *
+ * Jean
+ */
+struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
+{
+	struct airo_info *local = (struct airo_info*) dev->priv;
+	StatusRid status_rid;
+	StatsRid stats_rid;
+	int *vals = stats_rid.vals;
+
+	/* Get stats out of the card */
+	readStatusRid(local, &status_rid);
+	readStatsRid(local, &stats_rid, RID_STATS);
+
+	/* The status */
+	local->wstats.status = status_rid.mode;
+
+	/* Signal quality and co. But where is the noise level ??? */
+	local->wstats.qual.qual = status_rid.signalQuality;
+	local->wstats.qual.level = status_rid.normalizedSignalStrength;
+	local->wstats.qual.noise = 0;
+	local->wstats.qual.updated = 3;
+
+	/* Packets discarded in the wireless adapter due to wireless
+	 * specific problems */
+	local->wstats.discard.nwid = vals[56] + vals[57] + vals[58];/* SSID Mismatch */
+	local->wstats.discard.code = vals[6];/* RxWepErr */
+	local->wstats.discard.misc = vals[1] + vals[2] + vals[3] + vals[4] + vals[30] + vals[32];
+	return (&local->wstats);
+}
+#endif /* WIRELESS_EXT */
+
+#ifdef CISCO_EXT
+/*
+ * This just translates from driver IOCTL codes to the command codes to 
+ * feed to the radio's host interface. Things can be added/deleted 
+ * as needed.  This represents the READ side of control I/O to 
+ * the card
+ */
+static int readrids(struct net_device *dev, aironet_ioctl *comp) {
+	unsigned short ridcode;
+	unsigned char iobuf[2048]; 
+
+	switch(comp->command)
+	{
+	case AIROGCAP:      ridcode = RID_CAPABILITIES; break;
+	case AIROGCFG:      ridcode = RID_CONFIG;       break;
+	case AIROGSLIST:    ridcode = RID_SSID;         break;
+	case AIROGVLIST:    ridcode = RID_APLIST;       break;
+	case AIROGDRVNAM:   ridcode = RID_DRVNAME;      break;
+	case AIROGEHTENC:   ridcode = RID_ETHERENCAP;   break;
+	case AIROGWEPKTMP:  ridcode = RID_WEP_TEMP;
+		/* Only super-user can read WEP keys */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		break;
+	case AIROGWEPKNV:   ridcode = RID_WEP_PERM;
+		/* Only super-user can read WEP keys */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		break;
+	case AIROGSTAT:     ridcode = RID_STATUS;       break;
+	case AIROGSTATSD32: ridcode = RID_STATSDELTA;   break;
+	case AIROGSTATSC32: ridcode = RID_STATS;        break;
+	default:
+		return -EINVAL;  
+		break;
+	}
+
+	PC4500_readrid((struct airo_info *)dev->priv,ridcode,iobuf,sizeof(iobuf));
+	/* get the count of bytes in the rid  docs say 1st 2 bytes is it.
+	 * then return it to the user 
+	 * 9/22/2000 Honor user given length
+	 */
+
+	if (copy_to_user(comp->data, iobuf, min (comp->len, sizeof(iobuf))))
+		return -EFAULT;
+	return 0;
+}
+
+/*
+ * Danger Will Robinson write the rids here
+ */
+
+static int writerids(struct net_device *dev, aironet_ioctl *comp) {
+	int  ridcode;
+	Resp      rsp;
+	static int (* writer)(struct airo_info *, u16 rid, const void *, int);
+	unsigned char iobuf[2048]; 
+
+	/* Only super-user can write RIDs */
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	ridcode = 0;
+	writer = do_writerid;
+
+	switch(comp->command)
+	{
+	case AIROPSIDS:     ridcode = RID_SSID;         break;
+	case AIROPCAP:      ridcode = RID_CAPABILITIES; break;
+	case AIROPAPLIST:   ridcode = RID_APLIST;       break;
+	case AIROPCFG:      ridcode = RID_CONFIG;       break;
+	case AIROPWEPKEYNV: ridcode = RID_WEP_PERM;     break;
+	case AIROPLEAPUSR:  ridcode = RID_LEAPUSERNAME; break;
+	case AIROPLEAPPWD:  ridcode = RID_LEAPPASSWORD; break;
+	case AIROPWEPKEY:   ridcode = RID_WEP_TEMP; writer = PC4500_writerid;
+		break;
+
+		/* this is not really a rid but a command given to the card 
+		 * same with MAC off
+		 */
+	case AIROPMACON:
+		if (enable_MAC(dev->priv, &rsp) != 0)
+			return -EIO;
+		return 0;
+
+		/* 
+		 * Evidently this code in the airo driver does not get a symbol
+		 * as disable_MAC. it's probably so short the compiler does not gen one.
+		 */
+	case AIROPMACOFF:
+		disable_MAC(dev->priv);
+		return 0;
+
+		/* This command merely clears the counts does not actually store any data
+		 * only reads rid. But as it changes the cards state, I put it in the
+		 * writerid routines.
+		 */
+	case AIROPSTCLR:
+		ridcode = RID_STATSDELTACLEAR;
+
+		PC4500_readrid(dev->priv,ridcode,iobuf,sizeof(iobuf));
+
+		if (copy_to_user(comp->data,iobuf,min(comp->len,sizeof(iobuf))))
+			return -EFAULT;
+		return 0;
+
+	default:
+		return -EOPNOTSUPP;	/* Blarg! */
+	}
+	if(comp->len > sizeof(iobuf))
+		return -EINVAL;
+
+	copy_from_user(iobuf,comp->data,comp->len);
+	if((*writer)((struct airo_info *)dev->priv, ridcode, iobuf,comp->len))
+		return -EIO;
+	return 0;
+}
+
+/*****************************************************************************
+ * Ancillary flash / mod functions much black magic lurkes here              *
+ *****************************************************************************
+ */
+
+/* 
+ * Flash command switch table
+ */
+
+int flashcard(struct net_device *dev, aironet_ioctl *comp) {
+	int z;
+	int cmdreset(struct airo_info *);
+	int setflashmode(struct airo_info *);
+	int flashgchar(struct airo_info *,int,int);
+	int flashpchar(struct airo_info *,int,int);
+	int flashputbuf(struct airo_info *, unsigned short *);
+	int flashrestart(struct airo_info *,struct net_device *);
+	unsigned short * flashbuffer;
+
+	/* Only super-user can modify flash */
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	switch(comp->command)
+	{
+	case AIROFLSHRST:
+		return cmdreset((struct airo_info *)dev->priv);
+
+	case AIROFLSHSTFL:
+		return setflashmode((struct airo_info *)dev->priv);
+
+	case AIROFLSHGCHR: /* Get char from aux */
+		if(comp->len != sizeof(int))
+			return -EINVAL;
+		copy_from_user(&z,comp->data,comp->len);
+		return flashgchar((struct airo_info *)dev->priv,z,8000);
+
+	case AIROFLSHPCHR: /* Send char to card. */
+		if(comp->len != sizeof(int))
+			return -EINVAL;
+		copy_from_user(&z,comp->data,comp->len);
+		return flashpchar((struct airo_info *)dev->priv,z,8000);
+
+	case AIROFLPUTBUF: /* Send 32k to card */
+		if(comp->len > FLASHSIZE)
+			return -EINVAL;
+		if ((flashbuffer = kmalloc (FLASHSIZE, GFP_KERNEL)) == NULL)
+			return -ENOMEM;
+		if(copy_from_user(flashbuffer,comp->data,comp->len)) {
+			kfree (flashbuffer);
+			return -EINVAL;
+		}
+
+		flashputbuf((struct airo_info *)dev->priv,flashbuffer);
+		kfree (flashbuffer);
+		return 0;
+
+	case AIRORESTART:
+		if(flashrestart((struct airo_info *)dev->priv,dev))
+			return -EIO;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+#define FLASH_COMMAND  0x7e7e
+
+/* 
+ * STEP 1)
+ * Disable MAC and do soft reset on 
+ * card. 
+ */
+
+int cmdreset(struct airo_info *ai) {
+	int flags;
+
+	disable_MAC(ai);
+
+	spin_lock_irqsave(&ai->cmd_lock, flags);
+	if(!waitbusy (ai)){
+		printk(KERN_INFO "Waitbusy hang before RESET\n");
+		return -EBUSY;
+	}
+    
+	OUT4500(ai,COMMAND,CMD_SOFTRESET);
+
+	set_current_state (TASK_UNINTERRUPTIBLE);
+	schedule_timeout (HZ);          /* WAS 600 12/7/00 */
+
+	if(!waitbusy (ai)){
+		printk(KERN_INFO "Waitbusy hang AFTER RESET\n");
+		return -EBUSY;
+	}
+	spin_unlock_irqrestore(&ai->cmd_lock, flags);
+	return 0;
+}
+
+/* STEP 2)
+ * Put the card in legendary flash 
+ * mode
+ */
+
+int setflashmode (struct airo_info *ai) {
+	int flags;
+
+	spin_lock_irqsave(&ai->cmd_lock, flags);
+	OUT4500(ai, SWS0, FLASH_COMMAND);
+	OUT4500(ai, SWS1, FLASH_COMMAND);
+	OUT4500(ai, SWS0, FLASH_COMMAND);
+	OUT4500(ai, COMMAND,0x10);
+	set_current_state (TASK_UNINTERRUPTIBLE);
+	schedule_timeout (HZ/2); /* 500ms delay */
+	spin_unlock_irqrestore(&ai->cmd_lock, flags);
+  
+	if(!waitbusy(ai)) {
+		printk(KERN_INFO "Waitbusy hang after setflash mode\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+/* Put character to SWS0 wait for dwelltime 
+ * x 50us for  echo . 
+ */
+
+int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
+	int echo;
+	int waittime;
+
+	byte |= 0x8000;
+
+	if(dwelltime == 0 )
+		dwelltime = 200;
+  
+	waittime=dwelltime;
+
+	/* Wait for busy bit d15 to go false indicating buffer empty */
+	while ((IN4500 (ai, SWS0) & 0x8000) && waittime > 0) {
+		udelay (50);
+		waittime -= 50;
+	}
+
+	/* timeout for busy clear wait */
+	if(waittime <= 0 ){
+		printk(KERN_INFO "flash putchar busywait timeout! \n");
+		return -EBUSY;
+	}
+
+	/* Port is clear now write byte and wait for it to echo back */
+	do {
+		OUT4500(ai,SWS0,byte);
+		udelay(50);
+		dwelltime -= 50;
+		echo = IN4500(ai,SWS1);
+	} while (dwelltime >= 0 && echo != byte);
+
+	OUT4500(ai,SWS1,0);
+
+	return (echo == byte) ? 0 : -EIO;
+}
+
+/*
+ * Get a character from the card matching matchbyte
+ * Step 3)
+ */
+int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){
+	int           rchar;
+	unsigned char rbyte=0;
+
+	do {
+		rchar = IN4500(ai,SWS1);
+    
+		if(dwelltime && !(0x8000 & rchar)){
+			dwelltime -= 10;
+			mdelay(10);
+			continue;
+		}
+		rbyte = 0xff & rchar;
+
+		if( (rbyte == matchbyte) && (0x8000 & rchar) ){
+			OUT4500(ai,SWS1,0);
+			return 0;
+		}
+		if( rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar)
+			break;
+		OUT4500(ai,SWS1,0);
+
+	}while(dwelltime > 0);
+	return -EIO;
+}
+
+/* 
+ * Transfer 32k of firmware data from user buffer to our buffer and 
+ * send to the card 
+ */
+
+int flashputbuf(struct airo_info *ai, unsigned short *bufp){
+	int            nwords;
+
+	/* Write stuff */
+	OUT4500(ai,AUXPAGE,0x100);
+	OUT4500(ai,AUXOFF,0);
+
+	for(nwords=0;nwords != FLASHSIZE / 2;nwords++){
+		OUT4500(ai,AUXDATA,bufp[nwords] & 0xffff);
+	}
+  
+	OUT4500(ai,SWS0,0x8000);
+
+	return 0;
+}
+
+/*
+ *
+ */
+int flashrestart(struct airo_info *ai,struct net_device *dev){
+	int    i,status;
+
+	set_current_state (TASK_UNINTERRUPTIBLE);
+	schedule_timeout (HZ);          /* Added 12/7/00 */
+	status = setup_card(ai, dev->dev_addr,&((struct airo_info*)dev->priv)->config);
+
+	for( i = 0; i < MAX_FIDS; i++ ) {
+		ai->fids[i] = transmit_allocate( ai, 2312 );
+	}
+
+	set_current_state (TASK_UNINTERRUPTIBLE);
+	schedule_timeout (HZ);          /* Added 12/7/00 */
+	return status;
+}
+#endif /* CISCO_EXT */
+
+/*
+    This program is free software; 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.
+
+    In addition:
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+    3. The name of the author may not be used to endorse or promote
+       products derived from this software without specific prior written
+       permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.    
+*/
+
+module_init(airo_init_module);
+module_exit(airo_cleanup_module);
diff -u --recursive --new-file v2.4.5/linux/drivers/net/wireless/airo_cs.c linux/drivers/net/wireless/airo_cs.c
--- v2.4.5/linux/drivers/net/wireless/airo_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/airo_cs.c	Wed Jun 20 11:10:53 2001
@@ -0,0 +1,691 @@
+/*======================================================================
+
+    Aironet driver for 4500 and 4800 series cards
+
+    This code is released under both the GPL version 2 and BSD licenses.
+    Either license may be used.  The respective licenses are found at
+    the end of this file.
+
+    This code was developed by Benjamin Reed <breed@users.sourceforge.net>
+    including portions of which come from the Aironet PC4500
+    Developer's Reference Manual and used with permission.  Copyright
+    (C) 1999 Benjamin Reed.  All Rights Reserved.  Permission to use
+    code in the Developer's manual was granted for this driver by
+    Aironet.
+
+    In addition this module was derived from dummy_cs.
+    The initial developer of dummy_cs is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.    
+    
+======================================================================*/
+
+#include <linux/config.h>
+#ifdef __IN_PCMCIA_PACKAGE__
+#include <pcmcia/k_compat.h>
+#endif
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/netdevice.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+/*
+   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
+   you do not define PCMCIA_DEBUG at all, all the debug code will be
+   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
+   be present but disabled -- but it can then be enabled for specific
+   modules at load time with a 'pc_debug=#' option to insmod.
+*/
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+static char *version = "$Revision: 1.1.18.1 $";
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* The old way: bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static u_int irq_mask = 0xdeb8;
+/* Newer, simpler way of listing specific interrupts */
+static int irq_list[4] = { -1 };
+
+MODULE_AUTHOR("Benjamin Reed");
+MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \
+                   cards.  This is the module that links the PCMCIA card \
+		   with the airo module.");
+MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340 PCMCIA cards");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+/*
+   The event() function is this driver's Card Services event handler.
+   It will be called by Card Services when an appropriate card status
+   event is received.  The config() and release() entry points are
+   used to configure or release a socket, in response to card
+   insertion and ejection events.  They are invoked from the airo_cs
+   event handler. 
+*/
+
+struct net_device *init_airo_card( int, int, int );
+void stop_airo_card( struct net_device *, int );
+int reset_airo_card( struct net_device * );
+
+static void airo_config(dev_link_t *link);
+static void airo_release(u_long arg);
+static int airo_event(event_t event, int priority,
+		       event_callback_args_t *args);
+
+/*
+   The attach() and detach() entry points are used to create and destroy
+   "instances" of the driver, where each instance represents everything
+   needed to manage one actual PCMCIA card.
+*/
+
+static dev_link_t *airo_attach(void);
+static void airo_detach(dev_link_t *);
+
+/*
+   You'll also need to prototype all the functions that will actually
+   be used to talk to your device.  See 'pcmem_cs' for a good example
+   of a fully self-sufficient driver; the other drivers rely more or
+   less on other parts of the kernel.
+*/
+
+/*
+   The dev_info variable is the "key" that is used to match up this
+   device driver with appropriate cards, through the card configuration
+   database.
+*/
+
+static dev_info_t dev_info = "airo_cs";
+
+/*
+   A linked list of "instances" of the  aironet device.  Each actual
+   PCMCIA card corresponds to one device instance, and is described
+   by one dev_link_t structure (defined in ds.h).
+
+   You may not want to use a linked list for this -- for example, the
+   memory card driver uses an array of dev_link_t pointers, where minor
+   device numbers are used to derive the corresponding array index.
+*/
+
+static dev_link_t *dev_list = NULL;
+
+/*
+   A dev_link_t structure has fields for most things that are needed
+   to keep track of a socket, but there will usually be some device
+   specific information that also needs to be kept track of.  The
+   'priv' pointer in a dev_link_t structure can be used to point to
+   a device-specific private data structure, like this.
+
+   A driver needs to provide a dev_node_t structure for each device
+   on a card.  In some cases, there is only one device per card (for
+   example, ethernet cards, modems).  In other cases, there may be
+   many actual or logical devices (SCSI adapters, memory cards with
+   multiple partitions).  The dev_node_t structures need to be kept
+   in a linked list starting at the 'dev' field of a dev_link_t
+   structure.  We allocate them in the card's private data structure,
+   because they generally shouldn't be allocated dynamically.
+
+   In this case, we also provide a flag to indicate if a device is
+   "stopped" due to a power management event, or card ejection.  The
+   device IO routines can use a flag like this to throttle IO to a
+   card that is not ready to accept it.
+*/
+   
+typedef struct local_info_t {
+	dev_node_t	node;
+	struct net_device *eth_dev;
+} local_info_t;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+	CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+  
+  This bit of code is used to avoid unregistering network devices
+  at inappropriate times.  2.2 and later kernels are fairly picky
+  about when this can happen.
+  
+  ======================================================================*/
+
+static void flush_stale_links(void)
+{
+	dev_link_t *link, *next;
+	for (link = dev_list; link; link = next) {
+		next = link->next;
+		if (link->state & DEV_STALE_LINK)
+			airo_detach(link);
+	}
+}
+ 
+/*======================================================================
+  
+  airo_attach() creates an "instance" of the driver, allocating
+  local data structures for one device.  The device is registered
+  with Card Services.
+  
+  The dev_link structure is initialized, but we don't actually
+  configure the card at this point -- we wait until we receive a
+  card insertion event.
+  
+  ======================================================================*/
+
+static dev_link_t *airo_attach(void)
+{
+	client_reg_t client_reg;
+	dev_link_t *link;
+	local_info_t *local;
+	int ret, i;
+	
+	DEBUG(0, "airo_attach()\n");
+	flush_stale_links();
+	
+	/* Initialize the dev_link_t structure */
+	link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+	if (!link) {
+		printk(KERN_ERR "airo_cs: no memory for new device\n");
+		return NULL;
+	}
+	memset(link, 0, sizeof(struct dev_link_t));
+	link->release.function = &airo_release;
+	link->release.data = (u_long)link;
+	
+	/* Interrupt setup */
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+	link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+	if (irq_list[0] == -1)
+		link->irq.IRQInfo2 = irq_mask;
+	else
+		for (i = 0; i < 4; i++)
+			link->irq.IRQInfo2 |= 1 << irq_list[i];
+	link->irq.Handler = NULL;
+	
+	/*
+	  General socket configuration defaults can go here.  In this
+	  client, we assume very little, and rely on the CIS for almost
+	  everything.  In most clients, many details (i.e., number, sizes,
+	  and attributes of IO windows) are fixed by the nature of the
+	  device, and can be hard-wired here.
+	*/
+	link->conf.Attributes = 0;
+	link->conf.Vcc = 50;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+	
+	/* Allocate space for private device-specific data */
+	local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+	memset(local, 0, sizeof(local_info_t));
+	link->priv = local;
+	
+	/* Register with Card Services */
+	link->next = dev_list;
+	dev_list = link;
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask =
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.event_handler = &airo_event;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+	ret = CardServices(RegisterClient, &link->handle, &client_reg);
+	if (ret != 0) {
+		cs_error(link->handle, RegisterClient, ret);
+		airo_detach(link);
+		return NULL;
+	}
+	
+	return link;
+} /* airo_attach */
+
+/*======================================================================
+  
+  This deletes a driver "instance".  The device is de-registered
+  with Card Services.  If it has been released, all local data
+  structures are freed.  Otherwise, the structures will be freed
+  when the device is released.
+  
+  ======================================================================*/
+
+static void airo_detach(dev_link_t *link)
+{
+	dev_link_t **linkp;
+	
+	DEBUG(0, "airo_detach(0x%p)\n", link);
+	
+	/* Locate device structure */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+		if (*linkp == link) break;
+	if (*linkp == NULL)
+		return;
+	
+	del_timer(&link->release);
+	if ( link->state & DEV_CONFIG ) {
+		airo_release( (int)link );
+		if ( link->state & DEV_STALE_CONFIG ) {
+			link->state |= DEV_STALE_LINK;
+			return;
+		}
+	}
+	
+	if ( ((local_info_t*)link->priv)->eth_dev ) {
+		stop_airo_card( ((local_info_t*)link->priv)->eth_dev, 0 );
+	}
+	((local_info_t*)link->priv)->eth_dev = 0;   
+	
+	/* Break the link with Card Services */
+	if (link->handle)
+		CardServices(DeregisterClient, link->handle);
+	
+	
+	
+	/* Unlink device structure, free pieces */
+	*linkp = link->next;
+	if (link->priv) {
+		kfree(link->priv);
+	}
+	kfree(link);
+	
+} /* airo_detach */
+
+/*======================================================================
+  
+  airo_config() is scheduled to run after a CARD_INSERTION event
+  is received, to configure the PCMCIA socket, and to make the
+  device available to the system.
+  
+  ======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static void airo_config(dev_link_t *link)
+{
+	client_handle_t handle;
+	tuple_t tuple;
+	cisparse_t parse;
+	local_info_t *dev;
+	int last_fn, last_ret;
+	u_char buf[64];
+	win_req_t req;
+	memreq_t map;
+	
+	handle = link->handle;
+	dev = link->priv;
+
+	DEBUG(0, "airo_config(0x%p)\n", link);
+	
+	/*
+	  This reads the card's CONFIG tuple to find its configuration
+	  registers.
+	*/
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	tuple.Attributes = 0;
+	tuple.TupleData = buf;
+	tuple.TupleDataMax = sizeof(buf);
+	tuple.TupleOffset = 0;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	CS_CHECK(GetTupleData, handle, &tuple);
+	CS_CHECK(ParseTuple, handle, &tuple, &parse);
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.Present = parse.config.rmask[0];
+	
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+	
+	/*
+	  In this loop, we scan the CIS for configuration table entries,
+	  each of which describes a valid card configuration, including
+	  voltage, IO window, memory window, and interrupt settings.
+	  
+	  We make no assumptions about the card to be configured: we use
+	  just the information available in the CIS.  In an ideal world,
+	  this would work for any PCMCIA card, but it requires a complete
+	  and accurate CIS.  In practice, a driver usually "knows" most of
+	  these things without consulting the CIS, and most client drivers
+	  will only use the CIS to fill in implementation-defined details.
+	*/
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	while (1) {
+		cistpl_cftable_entry_t dflt = { 0 };
+		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+		CFG_CHECK(GetTupleData, handle, &tuple);
+		CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+		
+		if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
+		if (cfg->index == 0) goto next_entry;
+		link->conf.ConfigIndex = cfg->index;
+		
+		/* Does this card need audio output? */
+		if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+			link->conf.Attributes |= CONF_ENABLE_SPKR;
+			link->conf.Status = CCSR_AUDIO_ENA;
+		}
+		
+		/* Use power settings for Vcc and Vpp if present */
+		/*  Note that the CIS values need to be rescaled */
+		if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM))
+			link->conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000;
+		else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM))
+			link->conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000;
+		
+		if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+			link->conf.Vpp1 = link->conf.Vpp2 =
+				cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+		else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
+			link->conf.Vpp1 = link->conf.Vpp2 =
+				dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
+		
+		/* Do we need to allocate an interrupt? */
+		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
+			link->conf.Attributes |= CONF_ENABLE_IRQ;
+		
+		/* IO window settings */
+		link->io.NumPorts1 = link->io.NumPorts2 = 0;
+		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+			if (!(io->flags & CISTPL_IO_8BIT))
+				link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+			if (!(io->flags & CISTPL_IO_16BIT))
+				link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+			link->io.BasePort1 = io->win[0].base;
+			link->io.NumPorts1 = io->win[0].len;
+			if (io->nwin > 1) {
+				link->io.Attributes2 = link->io.Attributes1;
+				link->io.BasePort2 = io->win[1].base;
+				link->io.NumPorts2 = io->win[1].len;
+			}
+		}
+		
+		/* This reserves IO space but doesn't actually enable it */
+		CFG_CHECK(RequestIO, link->handle, &link->io); 
+		
+		/*
+		  Now set up a common memory window, if needed.  There is room
+		  in the dev_link_t structure for one memory window handle,
+		  but if the base addresses need to be saved, or if multiple
+		  windows are needed, the info should go in the private data
+		  structure for this device.
+		  
+		  Note that the memory window base is a physical address, and
+		  needs to be mapped to virtual space with ioremap() before it
+		  is used.
+		*/
+		if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
+			cistpl_mem_t *mem =
+				(cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
+			req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
+			req.Base = mem->win[0].host_addr;
+			req.Size = mem->win[0].len;
+			req.AccessSpeed = 0;
+			link->win = (window_handle_t)link->handle;
+			CFG_CHECK(RequestWindow, &link->win, &req);
+			map.Page = 0; map.CardOffset = mem->win[0].card_addr;
+			CFG_CHECK(MapMemPage, link->win, &map);
+		}
+		/* If we got this far, we're cool! */
+		break;
+		
+	next_entry:
+		CS_CHECK(GetNextTuple, handle, &tuple);
+	}
+	
+    /*
+      Allocate an interrupt line.  Note that this does not assign a
+      handler to the interrupt, unless the 'Handler' member of the
+      irq structure is initialized.
+    */
+	if (link->conf.Attributes & CONF_ENABLE_IRQ)
+		CS_CHECK(RequestIRQ, link->handle, &link->irq);
+	
+	/*
+	  This actually configures the PCMCIA socket -- setting up
+	  the I/O windows and the interrupt mapping, and putting the
+	  card and host interface into "Memory and IO" mode.
+	*/
+	CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+	((local_info_t*)link->priv)->eth_dev = 
+		init_airo_card( link->irq.AssignedIRQ,
+				link->io.BasePort1, 1 );
+	if (!((local_info_t*)link->priv)->eth_dev) goto cs_failed;
+	
+	/*
+	  At this point, the dev_node_t structure(s) need to be
+	  initialized and arranged in a linked list at link->dev.
+	*/
+	strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name );
+	dev->node.major = dev->node.minor = 0;
+	link->dev = &dev->node;
+	
+	/* Finally, report what we've done */
+	printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
+	       dev->node.dev_name, link->conf.ConfigIndex,
+	       link->conf.Vcc/10, link->conf.Vcc%10);
+	if (link->conf.Vpp1)
+		printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+	if (link->conf.Attributes & CONF_ENABLE_IRQ)
+		printk(", irq %d", link->irq.AssignedIRQ);
+	if (link->io.NumPorts1)
+		printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+		       link->io.BasePort1+link->io.NumPorts1-1);
+	if (link->io.NumPorts2)
+		printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+		       link->io.BasePort2+link->io.NumPorts2-1);
+	if (link->win)
+		printk(", mem 0x%06lx-0x%06lx", req.Base,
+		       req.Base+req.Size-1);
+	printk("\n");
+	
+	link->state &= ~DEV_CONFIG_PENDING;
+	return;
+	
+ cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+	airo_release((u_long)link);
+	
+} /* airo_config */
+
+/*======================================================================
+  
+  After a card is removed, airo_release() will unregister the
+  device, and release the PCMCIA configuration.  If the device is
+  still open, this will be postponed until it is closed.
+  
+  ======================================================================*/
+
+static void airo_release(u_long arg)
+{
+	dev_link_t *link = (dev_link_t *)arg;
+	
+	DEBUG(0, "airo_release(0x%p)\n", link);
+	
+	/*
+	  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 (link->open) {
+		DEBUG(1, "airo_cs: release postponed, '%s' still open\n",
+		      link->dev->dev_name);
+		link->state |= DEV_STALE_CONFIG;
+		return;
+	}
+	
+	/* Unlink the device chain */
+	link->dev = NULL;
+	
+	/*
+	  In a normal driver, additional code may be needed to release
+	  other kernel data structures associated with this device. 
+	*/
+	
+	/* Don't bother checking to see if these succeed or not */
+	if (link->win)
+		CardServices(ReleaseWindow, link->win);
+	CardServices(ReleaseConfiguration, link->handle);
+	if (link->io.NumPorts1)
+		CardServices(ReleaseIO, link->handle, &link->io);
+	if (link->irq.AssignedIRQ)
+		CardServices(ReleaseIRQ, link->handle, &link->irq);
+	link->state &= ~DEV_CONFIG;
+	
+} /* airo_release */
+
+/*======================================================================
+  
+  The card status event handler.  Mostly, this schedules other
+  stuff to run after an event is received.
+
+  When a CARD_REMOVAL event is received, we immediately set a
+  private flag to block future accesses to this device.  All the
+  functions that actually access the device should check this flag
+  to make sure the card is still present.
+  
+  ======================================================================*/
+
+static int airo_event(event_t event, int priority,
+		      event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+	local_info_t *local = link->priv;
+	
+	DEBUG(1, "airo_event(0x%06x)\n", event);
+	
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			netif_device_detach(local->eth_dev);
+			mod_timer(&link->release, jiffies + HZ/20);
+		}
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		airo_config(link);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		if (link->state & DEV_CONFIG) {
+			netif_device_detach(local->eth_dev);
+			CardServices(ReleaseConfiguration, link->handle);
+		}
+		break;
+	case CS_EVENT_PM_RESUME:
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		if (link->state & DEV_CONFIG) {
+			CardServices(RequestConfiguration, link->handle, &link->conf);
+			reset_airo_card(local->eth_dev);
+			netif_device_attach(local->eth_dev);
+		}
+		break;
+	}
+	return 0;
+} /* airo_event */
+
+/*====================================================================*/
+
+static int airo_cs_init(void)
+{
+	servinfo_t serv;
+	DEBUG(0, "%s\n", version);
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		printk(KERN_NOTICE "airo_cs: Card Services release "
+		       "does not match!\n");
+		return -1;
+	}
+	register_pcmcia_driver(&dev_info, &airo_attach, &airo_detach);
+	return 0;
+}
+
+static void airo_cs_cleanup(void)
+{
+	DEBUG(0, "airo_cs: unloading\n");
+	unregister_pcmcia_driver(&dev_info);
+	while (dev_list != NULL) {
+		if (dev_list->state & DEV_CONFIG)
+			airo_release((u_long)dev_list);
+		airo_detach(dev_list);
+	}
+}
+
+/*
+    This program is free software; 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.
+
+    In addition:
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+    3. The name of the author may not be used to endorse or promote
+       products derived from this software without specific prior written
+       permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.    
+*/
+
+module_init(airo_cs_init);
+module_exit(airo_cs_cleanup);
diff -u --recursive --new-file v2.4.5/linux/drivers/net/wireless/hermes.c linux/drivers/net/wireless/hermes.c
--- v2.4.5/linux/drivers/net/wireless/hermes.c	Mon May  7 19:42:14 2001
+++ linux/drivers/net/wireless/hermes.c	Mon Jun 11 19:15:27 2001
@@ -32,9 +32,10 @@
 
 #include "hermes.h"
 
+/* These are maximum timeouts. Most often, card wil react much faster */
 #define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
 #define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
-#define CMD_COMPL_TIMEOUT (10000) /* in iterations of ~10us */
+#define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
 #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
 #define BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */
 #define BAP_ERROR_RETRY (10) /* How many times to retry a BAP seek when there is an error */
@@ -141,6 +142,12 @@
 	/* No need to explicitly handle the timeout - hermes_issue_cmd() will
 	   probably return -EBUSY */
 
+	/* According to the documentation, EVSTAT may contain
+	   obsolete event occurrence information.  We have to acknowledge
+	   it by writing EVACK. */
+	reg = hermes_read_regn(hw, EVSTAT);
+	hermes_write_regn(hw, EVACK, reg);
+
 	/* We don't use hermes_docmd_wait here, because the reset wipes
 	   the magic constant in SWSUPPORT0 away, and it gets confused */
 	err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0);
@@ -323,8 +330,10 @@
 		reg = hermes_read_reg(hw, oreg);
 	}
 
-	if (reg & HERMES_OFFSET_BUSY)
+	if (reg & HERMES_OFFSET_BUSY) {
+		DEBUG(0,"hermes_bap_seek: returning ETIMEDOUT...\n");
 		return -ETIMEDOUT;
+	}
 
 	/* For some reason, seeking the BAP seems to randomly fail somewhere
 	   (firmware bug?). We retry a few times before giving up. */
diff -u --recursive --new-file v2.4.5/linux/drivers/net/wireless/hermes.h linux/drivers/net/wireless/hermes.h
--- v2.4.5/linux/drivers/net/wireless/hermes.h	Mon May  7 19:42:14 2001
+++ linux/drivers/net/wireless/hermes.h	Mon Jun 11 19:15:27 2001
@@ -166,7 +166,6 @@
 #define		HERMES_RID_CNF_NICKNAME		(0xfc0e)
 #define		HERMES_RID_CNF_WEP_ON		(0xfc20)
 #define		HERMES_RID_CNF_MWO_ROBUST	(0xfc25)
-#define		HERMES_RID_CNF_PRISM2_WEP_ON	(0xfc28)
 #define		HERMES_RID_CNF_MULTICAST_LIST	(0xfc80)
 #define		HERMES_RID_CNF_CREATEIBSS	(0xfc81)
 #define		HERMES_RID_CNF_FRAG_THRESH	(0xfc82)
@@ -177,6 +176,7 @@
 #define		HERMES_RID_CNF_TX_KEY		(0xfcb1)
 #define		HERMES_RID_CNF_TICKTIME		(0xfce0)
 
+#define		HERMES_RID_CNF_PRISM2_WEP_ON	(0xfc28)
 #define		HERMES_RID_CNF_PRISM2_TX_KEY	(0xfc23)
 #define		HERMES_RID_CNF_PRISM2_KEY0	(0xfc24)
 #define		HERMES_RID_CNF_PRISM2_KEY1	(0xfc25)
diff -u --recursive --new-file v2.4.5/linux/drivers/net/wireless/orinoco.c linux/drivers/net/wireless/orinoco.c
--- v2.4.5/linux/drivers/net/wireless/orinoco.c	Mon May  7 19:42:14 2001
+++ linux/drivers/net/wireless/orinoco.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* orinoco.c 0.05	- (formerly known as dldwd_cs.c and orinoco_cs.c)
+/* orinoco.c 0.06	- (formerly known as dldwd_cs.c and orinoco_cs.c)
  *
  * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
  * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
@@ -144,10 +144,32 @@
  *	  (note : the memcmp bug was mine - fixed)
  *	o Remove set_retry stuff, no firmware support it (bloat--).
  *
+ * v0.05d -> v0.06 - 25/5/2001 - Jean II
+ *		Original patch from "Hong Lin" <alin@redhat.com>,
+ *		"Ian Kinner" <ikinner@redhat.com>
+ *		and "David Smith" <dsmith@redhat.com>
+ *	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 flush_stale_links to remove zombie Pcmcia instances
+ *	o Ack previous hermes event before reset
+ *		Me (with my little hands)
+ *	o Allow orinoco.c to call cor_reset via priv->card_reset_handler
+ *	o Add priv->need_card_reset to toggle this feature
+ *	o Fix various buglets when setting WEP in Symbol firmware
+ *	  Now, encryption is fully functional on Symbol cards. Youpi !
+ *
+ * v0.06 -> v0.06b - 25/5/2001 - Jean II
+ *	o IBSS on Symbol use port_mode = 4. Please don't ask...
+ *
+ * v0.06b -> v0.06c - 29/5/2001 - Jean II
+ *	o Show first spy address in /proc/net/wireless for IBSS mode as well
+ *
  * TODO - Jean II
  *	o inline functions (lot's of candidate, need to reorder code)
  *	o Test PrismII/Symbol cards & firmware versions
- *	o Mini-PCI support
+ *	o Mini-PCI support (some people have reported success - JII)
  */
 
 #include <linux/module.h>
@@ -180,7 +202,7 @@
 #include "hermes.h"
 #include "orinoco.h"
 
-static char *version = "orinoco.c 0.05d (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+static char *version = "orinoco.c 0.06c (David Gibson <hermes@gibson.dropbear.id.au> and others)";
 
 /* Level of debugging. Used in the macros in orinoco.h */
 #ifdef ORINOCO_DEBUG
@@ -369,7 +391,11 @@
 			priv->port_type = 3;
 			priv->allow_ibss = 0;
 		} else {
-			priv->port_type = 1;
+			/* Symbol is different here */
+			if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
+				priv->port_type = 4;
+			else
+				priv->port_type = 1;
 			priv->allow_ibss = 1;
 		}
 		break;
@@ -441,10 +467,15 @@
 
 	TRACE_ENTER(priv->ndev.name);
 
+	/* Stop other people bothering us */
 	dldwd_lock(priv);
-
 	__dldwd_stop_irqs(priv);
 
+	/* Check if we need a card reset */
+	if((priv->need_card_reset) && (priv->card_reset_handler != NULL))
+		priv->card_reset_handler(priv);
+
+	/* Do standard firmware reset if we can */
 	err = __dldwd_hw_reset(priv);
 	if (err)
 		goto out;
@@ -594,7 +625,8 @@
 {
 	hermes_t *hw = &priv->hw;
 	int err = 0;
-	int	extra_wep_flag = 0;
+	int	master_wep_flag;
+	int	auth_flag;
 
 	switch (priv->firmware_type) {
 	case FIRMWARE_TYPE_LUCENT: /* Lucent style WEP */
@@ -614,24 +646,29 @@
 
 	case FIRMWARE_TYPE_PRISM2: /* Prism II style WEP */
 	case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
+		master_wep_flag = 0;		/* Off */
 		if (priv->wep_on) {
 			char keybuf[LARGE_KEY_SIZE+1];
 			int keylen;
 			int i;
-			
+
+			/* Fudge around firmware weirdness */
+			keylen = priv->keys[priv->tx_key].len;
+
 			/* Write all 4 keys */
 			for(i = 0; i < MAX_KEYS; i++) {
-				keylen = priv->keys[i].len;
-				keybuf[keylen] = '\0';
-				memcpy(keybuf, priv->keys[i].data, keylen);
+				memset(keybuf, 0, sizeof(keybuf));
+				memcpy(keybuf, priv->keys[i].data,
+				       priv->keys[i].len);
 				err = hermes_write_ltv(hw, USER_BAP,
 						       HERMES_RID_CNF_PRISM2_KEY0 + i,
-						       HERMES_BYTES_TO_RECLEN(keylen + 1),
-						       &keybuf);
+						       HERMES_BYTES_TO_RECLEN(keylen),
+						       keybuf);
 				if (err)
 					return err;
 			}
 
+			/* Write the index of the key used in transmission */
 			err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_TX_KEY,
 						   priv->tx_key);
 			if (err)
@@ -642,30 +679,29 @@
 			if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) {
 				/* Symbol cards : set the authentication :
 				 * 0 -> no encryption, 1 -> open,
-				 * 2 -> shared key, 3 -> shared key 128bit */
-				if(priv->wep_restrict) {
-					if(priv->keys[priv->tx_key].len >
-					   SMALL_KEY_SIZE)
-						extra_wep_flag = 3;
-					else
-						extra_wep_flag = 2;
-				} else
-					extra_wep_flag = 1;
-				err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, priv->wep_restrict);
+				 * 2 -> shared key
+				 * 3 -> shared key 128 -> AP only */
+				if(priv->wep_restrict)
+					auth_flag = 2;
+				else
+					auth_flag = 1;
+				err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, auth_flag);
 				if (err)
 					return err;
+				/* Master WEP setting is always 3 */
+				master_wep_flag = 3;
 			} else {
 				/* Prism2 card : we need to modify master
 				 * WEP setting */
 				if(priv->wep_restrict)
-					extra_wep_flag = 2;
+					master_wep_flag = 3;
 				else
-					extra_wep_flag = 0;
+					master_wep_flag = 1;
 			}
 		}
 		
 		/* Master WEP setting : on/off */
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_WEP_ON, (priv->wep_on | extra_wep_flag));
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_WEP_ON, master_wep_flag);
 		if (err)
 			return err;	
 		break;
@@ -1182,9 +1218,11 @@
 	
 	dldwd_lock(priv);
 
+	/* Do standard firmware reset */
 	err = hermes_reset(hw);
 	if (err != 0) {
-		printk(KERN_ERR "%s: failed to reset hardware\n", dev->name);
+		printk(KERN_ERR "%s: failed to reset hardware (err = %d)\n",
+		       dev->name, err);
 		goto out;
 	}
 	
@@ -1209,6 +1247,8 @@
 		/* Lucent MAC : 00:60:1D:* & 00:02:2D:* */
 
 		priv->firmware_type = FIRMWARE_TYPE_LUCENT;
+		priv->tx_rate_ctrl = 0x3;	/* 11 Mb/s auto */
+		priv->need_card_reset = 0;
 		priv->broken_reset = 0;
 		priv->broken_allocate = 0;
 		priv->has_port3 = 1;		/* Still works in 7.28 */
@@ -1229,6 +1269,8 @@
 		/* Some D-Link cards report vendor 0x02... */
 
 		priv->firmware_type = FIRMWARE_TYPE_PRISM2;
+		priv->tx_rate_ctrl = 0xF;	/* 11 Mb/s auto */
+		priv->need_card_reset = 0;
 		priv->broken_reset = 0;
 		priv->broken_allocate = 0;
 		priv->has_port3 = 1;
@@ -1248,9 +1290,12 @@
 			/* Intel MAC : 00:02:B3:* */
 			/* 3Com MAC : 00:50:DA:* */
 
-			/* FIXME : probably need to use SYMBOL_***ARY_VER
-			 * to get proper firmware version */
+			/* FIXME : we need to get Symbol firmware revision.
+			 * I tried to use SYMBOL_***ARY_VER, but it didn't
+			 * returned anything proper... */
 			priv->firmware_type = FIRMWARE_TYPE_SYMBOL;
+			priv->tx_rate_ctrl = 0xF;	/* 11 Mb/s auto */
+			priv->need_card_reset = 1;
 			priv->broken_reset = 0;
 			priv->broken_allocate = 1;
 			priv->has_port3 = 1;
@@ -1268,6 +1313,8 @@
 		/* To check - Should cover Samsung & Compaq */
 
 		priv->firmware_type = FIRMWARE_TYPE_PRISM2;
+		priv->tx_rate_ctrl = 0xF;	/* 11 Mb/s auto */
+		priv->need_card_reset = 0;
 		priv->broken_reset = 0;
 		priv->broken_allocate = 0;
 		priv->has_port3 = 1;
@@ -1284,6 +1331,8 @@
 		/* D-Link MAC : 00:40:05:* */
 
 		priv->firmware_type = FIRMWARE_TYPE_PRISM2;
+		priv->tx_rate_ctrl = 0xF;	/* 11 Mb/s auto */
+		priv->need_card_reset = 0;
 		priv->broken_reset = 0;
 		priv->broken_allocate = 0;
 		priv->has_port3 = 1;
@@ -1300,6 +1349,8 @@
 		vendor_str = "UNKNOWN";
 
 		priv->firmware_type = 0;
+		priv->tx_rate_ctrl = 0x3;		/* Hum... */
+		priv->need_card_reset = 0;
 		priv->broken_reset = 0;
 		priv->broken_allocate = 0;
 		priv->has_port3 = 0;
@@ -1314,7 +1365,7 @@
 	printk(KERN_INFO "%s: Firmware ID %02X vendor 0x%x (%s) version %d.%02d\n",
 	       dev->name, priv->firmware_info.id, priv->firmware_info.vendor,
 	       vendor_str, priv->firmware_info.major, priv->firmware_info.minor);
-	
+
 	if (priv->has_port3)
 		printk(KERN_INFO "%s: Ad-hoc demo mode supported.\n", dev->name);
 	if (priv->has_ibss)
@@ -1393,9 +1444,6 @@
 		goto out;
 	}
 
-	/* Set initial bitrate control*/
-	priv->tx_rate_ctrl = 3;
-
 	/* Power management setup */
 	if (priv->has_pm) {
 		priv->pm_on = 0;
@@ -1466,7 +1514,7 @@
 
 	dldwd_lock(priv);
 
-	if (priv->port_type == 3) {
+	if (priv->iw_mode == IW_MODE_ADHOC) {
 		memset(&wstats->qual, 0, sizeof(wstats->qual));
 #ifdef WIRELESS_SPY
 		/* If a spy address is defined, we report stats of the
@@ -1709,7 +1757,7 @@
 {
 	dldwd_priv_t *priv = dev->priv;
 	int err = 0;
-	int ptype;
+	int mode;
 	struct iw_range range;
 	int numrates;
 	int i, k;
@@ -1723,7 +1771,7 @@
 	rrq->length = sizeof(range);
 
 	dldwd_lock(priv);
-	ptype = priv->port_type;
+	mode = priv->iw_mode;
 	dldwd_unlock(priv);
 
 	memset(&range, 0, sizeof(range));
@@ -1755,7 +1803,7 @@
 
 	range.sensitivity = 3;
 
-	if ((ptype == 3) && (priv->spy_number == 0)){
+	if ((mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){
 		/* Quality stats meaningless in ad-hoc mode */
 		range.max_qual.qual = 0;
 		range.max_qual.level = 0;
@@ -2253,7 +2301,7 @@
 		switch(brate) {
 		case 0:
 			fixed = 0x0;
-			upto = 0x15;
+			upto = 0xF;
 			break;
 		case 2:
 			fixed = 0x1;
@@ -2269,7 +2317,7 @@
 			break;
 		case 22:
 			fixed = 0x8;
-			upto = 0x15;
+			upto = 0xF;
 			break;
 		default:
 			fixed = 0x0;
@@ -2881,6 +2929,7 @@
 		if (wrq->u.data.pointer) {
 			struct iw_priv_args privtab[] = {
 				{ SIOCDEVPRIVATE + 0x0, 0, 0, "force_reset" },
+				{ SIOCDEVPRIVATE + 0x1, 0, 0, "card_reset" },
 				{ SIOCDEVPRIVATE + 0x2,
 				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 				  0, "set_port3" },
@@ -2917,6 +2966,20 @@
 		dldwd_reset(priv);
 		break;
 
+	case SIOCDEVPRIVATE + 0x1: /* card_reset */
+		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x1 (card_reset)\n",
+		      dev->name);
+		if (! capable(CAP_NET_ADMIN)) {
+			err = -EPERM;
+			break;
+		}
+		
+		printk(KERN_DEBUG "%s: Forcing card reset!\n", dev->name);
+		if(priv->card_reset_handler != NULL)
+			priv->card_reset_handler(priv);
+		dldwd_reset(priv);
+		break;
+
 	case SIOCDEVPRIVATE + 0x2: /* set_port3 */
 		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x2 (set_port3)\n",
 		      dev->name);
@@ -3495,6 +3558,7 @@
 	ndev->priv = priv;
 
 	/* Setup up default routines */
+	priv->card_reset_handler = NULL;	/* Caller may override */
 	ndev->init = dldwd_init;
 	ndev->open = NULL;		/* Caller *must* override */
 	ndev->stop = NULL;
diff -u --recursive --new-file v2.4.5/linux/drivers/net/wireless/orinoco.h linux/drivers/net/wireless/orinoco.h
--- v2.4.5/linux/drivers/net/wireless/orinoco.h	Mon May  7 19:42:14 2001
+++ linux/drivers/net/wireless/orinoco.h	Mon Jun 11 19:15:27 2001
@@ -44,6 +44,8 @@
 
 typedef struct dldwd_priv {
 	void* card;	/* Pointer to card dependant structure */
+	/* card dependant extra reset code (i.e. bus/interface specific */
+	int (*card_reset_handler)(struct dldwd_priv *);
 
 	spinlock_t lock;
 	long state;
@@ -72,7 +74,7 @@
 	int has_mwo;
 	int has_pm;
 	int has_preamble;
-	int broken_reset, broken_allocate;
+	int need_card_reset, broken_reset, broken_allocate;
 	uint16_t channel_mask;
 
 	/* Current configuration */
diff -u --recursive --new-file v2.4.5/linux/drivers/net/wireless/orinoco_cs.c linux/drivers/net/wireless/orinoco_cs.c
--- v2.4.5/linux/drivers/net/wireless/orinoco_cs.c	Mon May  7 19:42:14 2001
+++ linux/drivers/net/wireless/orinoco_cs.c	Wed Jun 20 11:13:18 2001
@@ -1,4 +1,4 @@
-/* orinoco_cs.c 0.05	- (formerly known as dldwd_cs.c)
+/* orinoco_cs.c 0.06	- (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/
@@ -50,7 +50,8 @@
 	struct dldwd_priv  priv;
 } dldwd_card_t;
 
-static char *version = "orinoco_cs.c 0.05 (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+static char version[] __initdata =
+"orinoco_cs.c 0.06 (David Gibson <hermes@gibson.dropbear.id.au> and others)";
 
 /*====================================================================*/
 
@@ -166,6 +167,70 @@
 	return 0;
 }
 
+/*
+ * Do a soft reset of the Pcmcia card using the Configuration Option Register
+ * Can't do any harm, and actually may do some good on some cards...
+ * In fact, this seem necessary for Spectrum cards...
+ */
+static int
+dldwd_cs_cor_reset(dldwd_priv_t *priv)
+{
+	dldwd_card_t* card = (dldwd_card_t *)priv->card;
+	dev_link_t *link = &card->link;
+	conf_reg_t reg;
+	u_long default_cor; 
+
+	TRACE_ENTER(priv->ndev.name);
+
+	/* Doing it if hardware is gone is guaranteed crash */
+	if(!priv->hw_ready)
+		return(0);
+
+	/* Save original COR value */
+	reg.Function = 0;
+	reg.Action = CS_READ;
+	reg.Offset = CISREG_COR;
+	reg.Value = 0;
+	CardServices(AccessConfigurationRegister, link->handle, &reg);
+	default_cor = reg.Value;
+
+	DEBUG(2, "dldwd : dldwd_cs_cor_reset() : cor=0x%lX\n", default_cor);
+
+	/* Soft-Reset card */
+	reg.Action = CS_WRITE;
+	reg.Offset = CISREG_COR;
+	reg.Value = (default_cor | COR_SOFT_RESET);
+	CardServices(AccessConfigurationRegister, link->handle, &reg);
+
+	/* Wait until the card has acknowledged our reset */
+	mdelay(1);
+
+	/* Restore original COR configuration index */
+	reg.Value = (default_cor & ~COR_SOFT_RESET);
+	CardServices(AccessConfigurationRegister, link->handle, &reg);
+
+	/* Wait until the card has finished restarting */
+	mdelay(1);
+
+	TRACE_EXIT(priv->ndev.name);
+
+	return(0);
+}
+
+/* Remove zombie instances (card removed, detach pending) */
+static void
+flush_stale_links(void)
+{
+	dev_link_t *link, *next;
+	TRACE_ENTER("dldwd");
+	for (link = dev_list; link; link = next) {
+		next = link->next;
+		if (link->state & DEV_STALE_LINK)
+			dldwd_cs_detach(link);
+	}
+	TRACE_EXIT("dldwd");
+}
+
 /*======================================================================
   dldwd_cs_attach() creates an "instance" of the driver, allocating
   local data structures for one device.  The device is registered
@@ -187,6 +252,8 @@
 	int ret, i;
 
 	TRACE_ENTER("dldwd");
+	/* A bit of cleanup */
+	flush_stale_links();
 
 	/* Allocate space for private device-specific data */
 	card = kmalloc(sizeof(*card), GFP_KERNEL);
@@ -237,6 +304,7 @@
 	/* Overrides */
 	ndev->open = dldwd_cs_open;
 	ndev->stop = dldwd_cs_stop;
+	priv->card_reset_handler = dldwd_cs_cor_reset;
 
 	/* Register with Card Services */
 	link->next = dev_list;
@@ -320,45 +388,6 @@
 	TRACE_EXIT("dldwd");
 }				/* dldwd_cs_detach */
 
-/*
- * Do a soft reset of the Pcmcia card using the Configuration Option Register
- * Can't do any harm, and actually may do some good on some cards...
- */
-static int
-dldwd_cs_cor_reset(dev_link_t *link)
-{
-	conf_reg_t reg;
-	u_long default_cor; 
-
-	/* Save original COR value */
-	reg.Function = 0;
-	reg.Action = CS_READ;
-	reg.Offset = CISREG_COR;
-	reg.Value = 0;
-	CardServices(AccessConfigurationRegister, link->handle, &reg);
-	default_cor = reg.Value;
-
-	DEBUG(2, "dldwd : dldwd_cs_cor_reset() : cor=0x%lX\n", default_cor);
-
-	/* Soft-Reset card */
-	reg.Action = CS_WRITE;
-	reg.Offset = CISREG_COR;
-	reg.Value = (default_cor | COR_SOFT_RESET);
-	CardServices(AccessConfigurationRegister, link->handle, &reg);
-
-	/* Wait until the card has acknowledged our reset */
-	mdelay(1);
-
-	/* Restore original COR configuration index */
-	reg.Value = (default_cor & COR_CONFIG_MASK);
-	CardServices(AccessConfigurationRegister, link->handle, &reg);
-
-	/* Wait until the card has finished restarting */
-	mdelay(1);
-
-	return(0);
-}
-
 /*======================================================================
   dldwd_cs_config() is scheduled to run after a CARD_INSERTION event
   is received, to configure the PCMCIA socket, and to make the
@@ -556,10 +585,6 @@
 	ndev->base_addr = link->io.BasePort1;
 	ndev->irq = link->irq.AssignedIRQ;
 
-	/* Do a Pcmcia soft reset of the card (optional) */
-	if(reset_cor)
-		dldwd_cs_cor_reset(link);
-
 	/* register_netdev will give us an ethX name */
 	ndev->name[0] = '\0';
 	/* Tell the stack we exist */
@@ -586,9 +611,6 @@
 		       link->io.BasePort2 + link->io.NumPorts2 - 1);
 	printk("\n");
 
-	/* Allow /proc & ioctls to act */
-	priv->hw_ready = 1;
-	
 	/* And give us the proc nodes for debugging */
 	if (dldwd_proc_dev_init(priv) != 0) {
 		printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n",
@@ -599,6 +621,13 @@
 	/* Note to myself : this replace MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT */
 	SET_MODULE_OWNER(ndev);
 	
+	/* Allow cor_reset, /proc & ioctls to act */
+	priv->hw_ready = 1;
+	
+	/* Do a Pcmcia soft reset of the card (optional) */
+	if(reset_cor)
+		dldwd_cs_cor_reset(priv);
+
 	/*
 	   At this point, the dev_node_t structure(s) need to be
 	   initialized and arranged in a linked list at link->dev.
@@ -748,9 +777,8 @@
 
 	TRACE_ENTER("dldwd");
 
-	printk(KERN_INFO "dldwd: David's Less Dodgy WaveLAN/IEEE Driver\n");
-
-	DEBUG(0, "%s\n", version);
+	printk(KERN_INFO "dldwd: David's Less Dodgy WaveLAN/IEEE Driver\n"
+	       KERN_INFO "%s\n", version);
 
 	CardServices(GetCardServicesInfo, &serv);
 	if (serv.Revision != CS_RELEASE_CODE) {
diff -u --recursive --new-file v2.4.5/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c
--- v2.4.5/linux/drivers/net/yellowfin.c	Wed May 16 10:25:39 2001
+++ linux/drivers/net/yellowfin.c	Wed Jun 20 11:13:18 2001
@@ -36,6 +36,12 @@
 	
 */
 
+#define DRV_NAME	"yellowfin"
+#define DRV_VERSION	"1.05+LK1.1.3"
+#define DRV_RELDATE	"May 10, 2001"
+
+#define PFX DRV_NAME ": "
+
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
@@ -108,6 +114,8 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/unaligned.h>
 #include <asm/bitops.h>
@@ -115,9 +123,9 @@
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
-KERN_INFO "yellowfin.c:v1.05  1/09/2001  Written by Donald Becker <becker@scyld.com>\n"
+KERN_INFO DRV_NAME ".c:v1.05  1/09/2001  Written by Donald Becker <becker@scyld.com>\n"
 KERN_INFO "  http://www.scyld.com/network/yellowfin.html\n"
-KERN_INFO "  (unofficial 2.4.x port, LK1.1.3, May 10, 2001)\n";
+KERN_INFO "  (unofficial 2.4.x port, " DRV_VERSION ", " DRV_RELDATE ")\n";
 
 /* Condensed operations for readability. */
 #define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
@@ -146,6 +154,13 @@
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(gx_fix, "i");
+MODULE_PARM_DESC(max_interrupt_work, "G-NIC maximum events handled per interrupt");
+MODULE_PARM_DESC(mtu, "G-NIC MTU (all boards)");
+MODULE_PARM_DESC(debug, "G-NIC debug level (0-7)");
+MODULE_PARM_DESC(rx_copybreak, "G-NIC copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(options, "G-NIC: Bits 0-3: media type, bit 17: full duplex");
+MODULE_PARM_DESC(full_duplex, "G-NIC full duplex setting(s) (1)");
+MODULE_PARM_DESC(gx_fix, "G-NIC: enable GX server chipset bug workaround (0-1)");
 
 /*
 				Theory of Operation
@@ -369,7 +384,7 @@
 static int read_eeprom(long ioaddr, int location);
 static int mdio_read(long ioaddr, int phy_id, int location);
 static void mdio_write(long ioaddr, int phy_id, int location, int value);
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int yellowfin_open(struct net_device *dev);
 static void yellowfin_timer(unsigned long data);
 static void yellowfin_tx_timeout(struct net_device *dev);
@@ -407,7 +422,7 @@
 
 	dev = alloc_etherdev(sizeof(*np));
 	if (!dev) {
-		printk (KERN_ERR "yellowfin: cannot allocate ethernet device\n");
+		printk (KERN_ERR PFX "cannot allocate ethernet device\n");
 		return -ENOMEM;
 	}
 	SET_MODULE_OWNER(dev);
@@ -474,7 +489,7 @@
 	dev->stop = &yellowfin_close;
 	dev->get_stats = &yellowfin_get_stats;
 	dev->set_multicast_list = &set_rx_mode;
-	dev->do_ioctl = &mii_ioctl;
+	dev->do_ioctl = &netdev_ioctl;
 	dev->tx_timeout = yellowfin_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
@@ -1330,13 +1345,39 @@
 	outw(cfg_value | 0x1000, ioaddr + Cnfg);
 }
 
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct yellowfin_private *np = dev->priv;
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+
+        switch (ethcmd) {
+        case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strcpy(info.driver, DRV_NAME);
+		strcpy(info.version, DRV_VERSION);
+		strcpy(info.bus_info, np->pci_dev->slot_name);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+
+        }
+	
+	return -EOPNOTSUPP;
+}
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct yellowfin_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	u16 *data = (u16 *)&rq->ifr_data;
 
 	switch(cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 		data[0] = np->phys[0] & 0x1f;
 		/* Fall Through */
@@ -1390,7 +1431,7 @@
 
 
 static struct pci_driver yellowfin_driver = {
-	name:		"yellowfin",
+	name:		DRV_NAME,
 	id_table:	yellowfin_pci_tbl,
 	probe:		yellowfin_init_one,
 	remove:		yellowfin_remove_one,
diff -u --recursive --new-file v2.4.5/linux/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog
--- v2.4.5/linux/drivers/parport/ChangeLog	Tue May 22 19:54:04 2001
+++ linux/drivers/parport/ChangeLog	Mon Jun 11 19:15:27 2001
@@ -1,3 +1,9 @@
+2001-06-05  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c (parport_pc_unregister_port): New exported function.
+	Do the opposite of parport_pc_probe_port.
+	(cleanup_module): Use it.
+
 2001-05-22  Juan Quintela  <quintela@mandrakesoft.com>
 
 	* parport_amiga.c: Set printk levels.
diff -u --recursive --new-file v2.4.5/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- v2.4.5/linux/drivers/parport/parport_pc.c	Tue May 22 19:54:04 2001
+++ linux/drivers/parport/parport_pc.c	Mon Jun 11 19:15:27 2001
@@ -2349,6 +2349,28 @@
 	return p;
 }
 
+void parport_pc_unregister_port (struct parport *p)
+{
+	struct parport_pc_private *priv = p->private_data;
+	struct parport_operations *ops = p->ops;
+	if (p->dma != PARPORT_DMA_NONE)
+		free_dma(p->dma);
+	if (p->irq != PARPORT_IRQ_NONE)
+		free_irq(p->irq, p);
+	release_region(p->base, 3);
+	if (p->size > 3)
+		release_region(p->base + 3, p->size - 3);
+	if (p->modes & PARPORT_MODE_ECP)
+		release_region(p->base_hi, 3);
+	parport_proc_unregister(p);
+	if (priv->dma_buf)
+		pci_free_consistent(priv->dev, PAGE_SIZE,
+				    priv->dma_buf,
+				    priv->dma_handle);
+	kfree (p->private_data);
+	parport_unregister_port(p);
+	kfree (ops); /* hope no-one cached it */
+}
 
 #ifdef CONFIG_PCI
 /* Via support maintained by Jeff Garzik <jgarzik@mandrakesoft.com> */
@@ -2816,6 +2838,7 @@
 
 /* Exported symbols. */
 EXPORT_SYMBOL (parport_pc_probe_port);
+EXPORT_SYMBOL (parport_pc_unregister_port);
 
 #ifdef MODULE
 static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
@@ -2883,27 +2906,9 @@
 
 	while (p) {
 		tmp = p->next;
-		if (p->modes & PARPORT_MODE_PCSPP) { 
-			struct parport_pc_private *priv = p->private_data;
-			struct parport_operations *ops = p->ops;
-			if (p->dma != PARPORT_DMA_NONE)
-				free_dma(p->dma);
-			if (p->irq != PARPORT_IRQ_NONE)
-				free_irq(p->irq, p);
-			release_region(p->base, 3);
-			if (p->size > 3)
-				release_region(p->base + 3, p->size - 3);
-			if (p->modes & PARPORT_MODE_ECP)
-				release_region(p->base_hi, 3);
-			parport_proc_unregister(p);
-			if (priv->dma_buf)
-				pci_free_consistent(priv->dev, PAGE_SIZE,
-						    priv->dma_buf,
-						    priv->dma_handle);
-			kfree (p->private_data);
-			parport_unregister_port(p);
-			kfree (ops); /* hope no-one cached it */
-		}
+		if (p->modes & PARPORT_MODE_PCSPP)
+			parport_pc_unregister_port (p);
+
 		p = tmp;
 	}
 }
diff -u --recursive --new-file v2.4.5/linux/drivers/parport/parport_sunbpp.c linux/drivers/parport/parport_sunbpp.c
--- v2.4.5/linux/drivers/parport/parport_sunbpp.c	Tue May 22 19:54:04 2001
+++ linux/drivers/parport/parport_sunbpp.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: parport_sunbpp.c,v 1.11 2001/02/13 01:16:58 davem Exp $
+/* $Id: parport_sunbpp.c,v 1.12 2001/05/26 03:01:42 davem Exp $
  * Parallel-port routines for Sun architecture
  * 
  * Author: Derrick J. Brashear <shadow@dementia.org>
diff -u --recursive --new-file v2.4.5/linux/drivers/pci/Makefile linux/drivers/pci/Makefile
--- v2.4.5/linux/drivers/pci/Makefile	Sat May 19 17:49:14 2001
+++ linux/drivers/pci/Makefile	Tue Jun 12 11:08:46 2001
@@ -13,8 +13,12 @@
 
 export-objs := pci.o
 
-obj-$(CONFIG_PCI) += pci.o quirks.o compat.o names.o setup-res.o
+obj-$(CONFIG_PCI) += pci.o quirks.o compat.o names.o
 obj-$(CONFIG_PROC_FS) += proc.o
+
+ifndef CONFIG_SPARC64
+obj-$(CONFIG_PCI) += setup-res.o
+endif
 
 #
 # Some architectures use the generic PCI setup functions
diff -u --recursive --new-file v2.4.5/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.4.5/linux/drivers/pci/pci.c	Sat May 19 17:43:06 2001
+++ linux/drivers/pci/pci.c	Tue Jun 12 16:47:56 2001
@@ -229,49 +229,120 @@
 }
 
 /**
- * pci_set_power_state - Set power management state of a device.
- * @dev: PCI device for which PM is set
- * @new_state: new power management statement (0 == D0, 3 == D3, etc.)
- *
- *  Set power management state of a device.  For transitions from state D3
- *  it isn't as straightforward as one could assume since many devices forget
- *  their configuration space during wakeup.  Returns old power state.
+ * pci_set_power_state - Set the power state of a PCI device
+ * @dev: PCI device to be suspended
+ * @state: Power state we're entering
+ *
+ * Transition a device to a new power state, using the Power Management 
+ * Capabilities in the device's config space.
+ *
+ * RETURN VALUE: 
+ * -EINVAL if trying to enter a lower state than we're already in.
+ * 0 if we're already in the requested state.
+ * -EIO if device does not support PCI PM.
+ * 0 if we can successfully change the power state.
  */
+
 int
-pci_set_power_state(struct pci_dev *dev, int new_state)
+pci_set_power_state(struct pci_dev *dev, int state)
 {
-	u32 base[5], romaddr;
-	u16 pci_command, pwr_command;
-	u8  pci_latency, pci_cacheline;
-	int i, old_state;
-	int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+	int pm;
+	u16 pmcsr;
 
-	if (!pm)
-		return 0;
-	pci_read_config_word(dev, pm + PCI_PM_CTRL, &pwr_command);
-	old_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
-	if (old_state == new_state)
-		return old_state;
-	DBG("PCI: %s goes from D%d to D%d\n", dev->slot_name, old_state, new_state);
-	if (old_state == 3) {
-		pci_read_config_word(dev, PCI_COMMAND, &pci_command);
-		pci_write_config_word(dev, PCI_COMMAND, pci_command & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY));
-		for (i = 0; i < 5; i++)
-			pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + i*4, &base[i]);
-		pci_read_config_dword(dev, PCI_ROM_ADDRESS, &romaddr);
-		pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
-		pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &pci_cacheline);
-		pci_write_config_word(dev, pm + PCI_PM_CTRL, new_state);
-		for (i = 0; i < 5; i++)
-			pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + i*4, base[i]);
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS, romaddr);
+	/* bound the state we're entering */
+	if (state > 3) state = 3;
+
+	/* Validate current state:
+	 * Can enter D0 from any state, but if we can only go deeper 
+	 * to sleep if we're already in a low power state
+	 */
+	if (state > 0 && dev->current_state > state)
+		return -EINVAL;
+	else if (dev->current_state == state) 
+		return 0;        /* we're already there */
+
+	/* find PCI PM capability in list */
+	pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+	
+	/* abort if the device doesn't support PM capabilities */
+	if (!pm) return -EIO; 
+
+	/* check if this device supports the desired state */
+	if (state == 1 || state == 2) {
+		u16 pmc;
+		pci_read_config_word(dev,pm + PCI_PM_PMC,&pmc);
+		if (state == 1 && !(pmc & PCI_PM_CAP_D1)) return -EIO;
+		else if (state == 2 && !(pmc & PCI_PM_CAP_D2)) return -EIO;
+	}
+
+	/* If we're in D3, force entire word to 0, since we can't access the
+	 * PCI config space for the device
+	 */
+	if (dev->current_state == 3)
+		pmcsr = 0;
+	else {
+		pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
+		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+		pmcsr |= state;
+	}
+
+	/* enter specified state */
+	pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr);
+
+	dev->current_state = state;
+
+	return 0;
+}
+
+/**
+ * pci_save_state - save the PCI configuration space of a device before suspending
+ * @dev - PCI device that we're dealing with
+ * @buffer - buffer to hold config space context
+ *
+ * @buffer must be large enough to hold the entire PCI 2.2 config space 
+ * (>= 64 bytes).
+ */
+int
+pci_save_state(struct pci_dev *dev, u32 *buffer)
+{
+	int i;
+	if (buffer) {
+		/* XXX: 100% dword access ok here? */
+		for (i = 0; i < 16; i++)
+			pci_read_config_dword(dev, i * 4,&buffer[i]);
+	}
+	return 0;
+}
+
+/** 
+ * pci_restore_state - Restore the saved state of a PCI device
+ * @dev - PCI device that we're dealing with
+ * @buffer - saved PCI config space
+ *
+ */
+int 
+pci_restore_state(struct pci_dev *dev, u32 *buffer)
+{
+	int i;
+
+	if (buffer) {
+		for (i = 0; i < 16; i++)
+			pci_write_config_dword(dev,i * 4, buffer[i]);
+	}
+	/*
+	 * otherwise, write the context information we know from bootup.
+	 * This works around a problem where warm-booting from Windows
+	 * combined with a D3(hot)->D0 transition causes PCI config
+	 * header data to be forgotten.
+	 */	
+	else {
+		for (i = 0; i < 6; i ++)
+			pci_write_config_dword(dev,
+					       PCI_BASE_ADDRESS_0 + (i * 4),
+					       dev->resource[i].start);
 		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
-		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cacheline);
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, pci_latency);
-		pci_write_config_word(dev, PCI_COMMAND, pci_command);
-	} else
-		pci_write_config_word(dev, pm + PCI_PM_CTRL, (pwr_command & ~PCI_PM_CTRL_STATE_MASK) | new_state);
-	return old_state;
+	}
+	return 0;
 }
 
 /**
@@ -314,6 +385,48 @@
 	}
 }
 
+/**
+ * pci_enable_wake - enable device to generate PME# when suspended
+ * @dev - PCI device to operate on
+ * @enable - Flag to enable or disable generation
+ * 
+ * Set the bits in the device's PM Capabilities to generate PME# when
+ * the system is suspended. 
+ *
+ * -EIO is returned if device doesn't have PM Capabilities. 
+ * -EINVAL is returned if device supports it, but can't generate wake events.
+ * 0 if operation is successful.
+ * 
+ */
+int pci_enable_wake(struct pci_dev *dev, u32 state, int enable)
+{
+	int pm;
+	u16 value;
+
+	/* find PCI PM capability in list */
+	pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+	if (!pm) return -EIO; /* this device cannot poweroff - up to bridge to cut power */
+
+	/* make sure device supports wake events (from any state) */
+	pci_read_config_word(dev,pm+PCI_PM_PMC,&value);
+
+	if (!(value & PCI_PM_CAP_PME_MASK)) return -EINVAL; /* doesn't support wake events */
+
+	/* 
+	 * XXX - We're assuming that device can generate wake events from whatever 
+	 * state it may be entering. 
+	 * We're not actually checking what state we're going into to.
+	 */
+	pci_read_config_word(dev, pm + PCI_PM_CTRL, &value);
+
+	if (enable) value |= PCI_PM_CTRL_PME_STATUS;
+	else value &= ~PCI_PM_CTRL_PME_STATUS;
+
+	pci_write_config_word(dev, pm + PCI_PM_CTRL, value);
+	
+	return 0;
+}
+
 int
 pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
 {
@@ -1272,40 +1385,41 @@
  * easily implement them (ie just have a suspend function that calls
  * the pci_set_power_state() function).
  */
-static int pci_pm_suspend_device(struct pci_dev *dev)
+static int pci_pm_suspend_device(struct pci_dev *dev, u32 state)
 {
+	int error = 0;
 	if (dev) {
 		struct pci_driver *driver = dev->driver;
 		if (driver && driver->suspend)
-			driver->suspend(dev);
+			error = driver->suspend(dev,state);
 	}
-	return 0;
+	return error;
 }
 
 static int pci_pm_resume_device(struct pci_dev *dev)
 {
+	int error = 0;
 	if (dev) {
 		struct pci_driver *driver = dev->driver;
 		if (driver && driver->resume)
-			driver->resume(dev);
+			error = driver->resume(dev);
 	}
-	return 0;
+	return error;
 }
 
-
 /* take care to suspend/resume bridges only once */
 
-static int pci_pm_suspend_bus(struct pci_bus *bus)
+static int pci_pm_suspend_bus(struct pci_bus *bus, u32 state)
 {
 	struct list_head *list;
 
 	/* Walk the bus children list */
 	list_for_each(list, &bus->children) 
-		pci_pm_suspend_bus(pci_bus_b(list));
+		pci_pm_suspend_bus(pci_bus_b(list),state);
 
 	/* Walk the device children list */
 	list_for_each(list, &bus->devices)
-		pci_pm_suspend_device(pci_dev_b(list));
+		pci_pm_suspend_device(pci_dev_b(list),state);
 	return 0;
 }
 
@@ -1323,15 +1437,15 @@
 	return 0;
 }
 
-static int pci_pm_suspend(void)
+static int pci_pm_suspend(u32 state)
 {
 	struct list_head *list;
 	struct pci_bus *bus;
 
 	list_for_each(list, &pci_root_buses) {
 		bus = pci_bus_b(list);
-		pci_pm_suspend_bus(bus);
-		pci_pm_suspend_device(bus->self);
+		pci_pm_suspend_bus(bus,state);
+		pci_pm_suspend_device(bus->self,state);
 	}
 	return 0;
 }
@@ -1349,14 +1463,16 @@
 	return 0;
 }
 
-static int pci_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+static int 
+pci_pm_callback(struct pm_dev *pm_device, pm_request_t rqst, void *data)
 {
 	switch (rqst) {
 	case PM_SUSPEND:
-		return pci_pm_suspend();
+		return pci_pm_suspend((u32)data);
 	case PM_RESUME:
 		return pci_pm_resume();
-	}	
+	default: break;
+	}
 	return 0;
 }
 #endif
@@ -1741,7 +1857,6 @@
 
 __setup("pci=", pci_setup);
 
-
 EXPORT_SYMBOL(pci_read_config_byte);
 EXPORT_SYMBOL(pci_read_config_word);
 EXPORT_SYMBOL(pci_read_config_dword);
@@ -1761,7 +1876,6 @@
 EXPORT_SYMBOL(pci_find_subsys);
 EXPORT_SYMBOL(pci_set_master);
 EXPORT_SYMBOL(pci_set_dma_mask);
-EXPORT_SYMBOL(pci_set_power_state);
 EXPORT_SYMBOL(pci_assign_resource);
 EXPORT_SYMBOL(pci_register_driver);
 EXPORT_SYMBOL(pci_unregister_driver);
@@ -1774,6 +1888,11 @@
 EXPORT_SYMBOL(pci_insert_device);
 EXPORT_SYMBOL(pci_remove_device);
 #endif
+
+EXPORT_SYMBOL(pci_set_power_state);
+EXPORT_SYMBOL(pci_save_state);
+EXPORT_SYMBOL(pci_restore_state);
+EXPORT_SYMBOL(pci_enable_wake);
 
 /* Obsolete functions */
 
diff -u --recursive --new-file v2.4.5/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids
--- v2.4.5/linux/drivers/pci/pci.ids	Sat May 19 17:49:14 2001
+++ linux/drivers/pci/pci.ids	Wed Jun 20 11:16:01 2001
@@ -4599,13 +4599,18 @@
 		11d4 0048  SoundMAX Integrated Digital Audio
 	2426  82801AB AC'97 Modem
 	2428  82801AB PCI Bridge
-	2440  82820 820 (Camino 2) Chipset ISA Bridge (ICH2)
-	2442  82820 820 (Camino 2) Chipset USB (Hub A)
-	2443  82820 820 (Camino 2) Chipset SMBus
-	2444  82820 820 (Camino 2) Chipset USB (Hub B)
-	2449  82820 820 (Camino 2) Chipset Ethernet
-	244b  82820 820 (Camino 2) Chipset IDE U100
-	244e  82820 820 (Camino 2) Chipset PCI
+	2440  82801BA ISA Bridge (ICH2)
+	2442  82801BA(M) USB (Hub A)
+	2443  82801BA(M) SMBus
+	2444  82801BA(M) USB (Hub B)
+	2445  82801BA(M) AC'97 Audio
+	2446  82801BA(M) AC'97 Modem
+	2448  82801BA PCI
+	2449  82801BA(M) Ethernet
+	244a  82801BAM IDE U100
+	244b  82801BA IDE U100
+	244c  82801BAM ISA Bridge (ICH2)
+	244e  82801BAM PCI
 	2500  82820 820 (Camino) Chipset Host Bridge (MCH)
 		1043 801c  P3C-2000 system chipset
 	2501  82820 820 (Camino) Chipset Host Bridge (MCH)
diff -u --recursive --new-file v2.4.5/linux/drivers/pci/quirks.c linux/drivers/pci/quirks.c
--- v2.4.5/linux/drivers/pci/quirks.c	Sat May 19 17:43:06 2001
+++ linux/drivers/pci/quirks.c	Wed Jun 20 11:16:01 2001
@@ -17,6 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 
 #undef DEBUG
 
@@ -267,6 +268,9 @@
 /*
  * VIA 686A/B: If an IO-APIC is active, we need to route all on-chip
  * devices to the external APIC.
+ *
+ * TODO: When we have device-specific interrupt routers,
+ * this code will go away from quirks.
  */
 static void __init quirk_via_ioapic(struct pci_dev *dev)
 {
@@ -277,6 +281,9 @@
 	else
 		tmp = 0x1f; /* all known bits (4-0) routed to external APIC */
 		
+	printk(KERN_INFO "PCI: %sbling Via external APIC routing\n",
+	       tmp == 0 ? "Disa" : "Ena");
+
 	/* Offset 0x58: External APIC IRQ output control */
 	pci_write_config_byte (dev, 0x58, tmp);
 }
@@ -285,6 +292,56 @@
 
 
 /*
+ * Via 686A/B:  The PCI_INTERRUPT_LINE register for the on-chip
+ * devices, USB0/1, AC97, MC97, and ACPI, has an unusual feature:
+ * when written, it makes an internal connection to the PIC.
+ * For these devices, this register is defined to be 4 bits wide.
+ * Normally this is fine.  However for IO-APIC motherboards, or
+ * non-x86 architectures (yes Via exists on PPC among other places),
+ * we must mask the PCI_INTERRUPT_LINE value versus 0xf to get
+ * interrupts delivered properly.
+ *
+ * TODO: When we have device-specific interrupt routers,
+ * quirk_via_irqpic will go away from quirks.
+ */
+
+/*
+ * FIXME: it is questionable that quirk_via_acpi
+ * is needed.  It shows up as an ISA bridge, and does not
+ * support the PCI_INTERRUPT_LINE register at all.  Therefore
+ * it seems like setting the pci_dev's 'irq' to the
+ * value of the ACPI SCI interrupt is only done for convenience.
+ *	-jgarzik
+ */
+static void __init quirk_via_acpi(struct pci_dev *d)
+{
+	/*
+	 * VIA ACPI device: SCI IRQ line in PCI config byte 0x42
+	 */
+	u8 irq;
+	pci_read_config_byte(d, 0x42, &irq);
+	irq &= 0xf;
+	if (irq && (irq != 2))
+		d->irq = irq;
+}
+
+static void __init quirk_via_irqpic(struct pci_dev *dev)
+{
+	u8 irq, new_irq = dev->irq & 0xf;
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+
+	if (new_irq != irq) {
+		printk(KERN_INFO "PCI: Via IRQ fixup for %s, from %d to %d\n",
+		       dev->slot_name, irq, new_irq);
+
+		udelay(15);
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
+	}
+}
+
+
+/*
  * PIIX3 USB: We have to disable USB interrupts that are
  * hardwired to PIRQD# and may be shared with an
  * external device.
@@ -372,6 +429,11 @@
 #ifdef CONFIG_X86_IO_APIC 
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686,	quirk_via_ioapic },
 #endif
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_3,	quirk_via_acpi },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_4,	quirk_via_acpi },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_2,	quirk_via_irqpic },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_5,	quirk_via_irqpic },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_6,	quirk_via_irqpic },
 
 	{ 0 }
 };
diff -u --recursive --new-file v2.4.5/linux/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- v2.4.5/linux/drivers/pcmcia/cs.c	Fri Feb 16 16:02:36 2001
+++ linux/drivers/pcmcia/cs.c	Wed Jun 20 11:19:02 2001
@@ -1,6 +1,6 @@
 /*======================================================================
 
-    PCMCIA Card Services -- core services
+    Kernel Card Services -- core services
 
     cs.c 1.271 2000/10/02 20:27:49
     
@@ -90,11 +90,11 @@
 #define OPTIONS PCI_OPT CB_OPT PM_OPT
 #endif
 
-static const char *release = "Linux PCMCIA Card Services " CS_RELEASE;
+static const char *release = "Linux Kernel Card Services " CS_RELEASE;
 static const char *options = "options: " OPTIONS;
 
 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("Linux PCMCIA Card Services " CS_RELEASE
+MODULE_DESCRIPTION("Linux Kernel Card Services " CS_RELEASE
 		   "\n  options:" OPTIONS);
 
 /*====================================================================*/
@@ -2416,7 +2416,7 @@
 
 static void __exit exit_pcmcia_cs(void)
 {
-    printk(KERN_INFO "unloading PCMCIA Card Services\n");
+    printk(KERN_INFO "unloading Kernel Card Services\n");
 #ifdef CONFIG_PROC_FS
     if (proc_pccard) {
 	remove_proc_entry("pccard", proc_bus);
diff -u --recursive --new-file v2.4.5/linux/drivers/pcmcia/pci_socket.c linux/drivers/pcmcia/pci_socket.c
--- v2.4.5/linux/drivers/pcmcia/pci_socket.c	Fri Apr  6 10:51:19 2001
+++ linux/drivers/pcmcia/pci_socket.c	Tue Jun 12 16:52:14 2001
@@ -218,16 +218,18 @@
 	dev->driver_data = 0;
 }
 
-static void cardbus_suspend (struct pci_dev *dev)
+static int cardbus_suspend (struct pci_dev *dev, u32 state)
 {
 	pci_socket_t *socket = (pci_socket_t *) dev->driver_data;
 	pcmcia_suspend_socket (socket->pcmcia_socket);
+	return 0;
 }
 
-static void cardbus_resume (struct pci_dev *dev)
+static int cardbus_resume (struct pci_dev *dev)
 {
 	pci_socket_t *socket = (pci_socket_t *) dev->driver_data;
 	pcmcia_resume_socket (socket->pcmcia_socket);
+	return 0;
 }
 
 
diff -u --recursive --new-file v2.4.5/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c
--- v2.4.5/linux/drivers/pcmcia/yenta.c	Fri Apr  6 10:51:19 2001
+++ linux/drivers/pcmcia/yenta.c	Wed Jun 20 11:21:33 2001
@@ -642,10 +642,11 @@
 	/* MAGIC NUMBERS! Fixme */
 	config_writeb(socket, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4);
 	config_writeb(socket, PCI_LATENCY_TIMER, 168);
-	config_writeb(socket, PCI_SEC_LATENCY_TIMER, 176);
-	config_writeb(socket, PCI_PRIMARY_BUS, dev->bus->number);
-	config_writeb(socket, PCI_SECONDARY_BUS, dev->subordinate->number);
-	config_writeb(socket, PCI_SUBORDINATE_BUS, dev->subordinate->number);
+	config_writel(socket, PCI_PRIMARY_BUS,
+		(176 << 24) |			   /* sec. latency timer */
+		(dev->subordinate->subordinate << 16) | /* subordinate bus */
+		(dev->subordinate->secondary << 8) |  /* secondary bus */
+		dev->subordinate->primary);		   /* primary bus */
 
 	/*
 	 * Set up the bridging state:
diff -u --recursive --new-file v2.4.5/linux/drivers/sbus/audio/Makefile linux/drivers/sbus/audio/Makefile
--- v2.4.5/linux/drivers/sbus/audio/Makefile	Fri Dec 29 14:07:22 2000
+++ linux/drivers/sbus/audio/Makefile	Mon Jun 11 19:15:27 2001
@@ -11,8 +11,8 @@
 
 obj-$(CONFIG_SPARCAUDIO)		+= audio.o
 obj-$(CONFIG_SPARCAUDIO_AMD7930)	+= amd7930.o
-obj-$(CONFIG_SPARCAUDIO_CS4231)		+= cs4231.o
 obj-$(CONFIG_SPARCAUDIO_DBRI)		+= dbri.o
+obj-$(CONFIG_SPARCAUDIO_CS4231)		+= cs4231.o
 obj-$(CONFIG_SPARCAUDIO_DUMMY)		+= dmy.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.5/linux/drivers/sbus/audio/amd7930.c linux/drivers/sbus/audio/amd7930.c
--- v2.4.5/linux/drivers/sbus/audio/amd7930.c	Sun Feb 18 19:49:54 2001
+++ linux/drivers/sbus/audio/amd7930.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: amd7930.c,v 1.26 2001/02/13 01:16:59 davem Exp $
+/* $Id: amd7930.c,v 1.27 2001/05/21 01:25:22 davem Exp $
  * drivers/sbus/audio/amd7930.c
  *
  * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu)
@@ -107,7 +107,7 @@
 static __u8  linear2mulaw(__u16 data);
 static __u16 mulaw2linear(__u8 data);
 
-#if defined (AMD79C30_ISDN) && defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff 
+#if defined (AMD79C30_ISDN)
 #include "../../isdn/hisax/hisax.h"
 #include "../../isdn/hisax/isdnl1.h"
 #include "../../isdn/hisax/foreign.h"
@@ -1131,7 +1131,7 @@
  *
  */
 
-#if defined (AMD79C30_ISDN) && defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff 
+#if defined (AMD79C30_ISDN)
 static int amd7930_get_irqnum(int dev)
 {
 	struct amd7930_info *info;
@@ -1659,9 +1659,8 @@
 	return 0;
 }
 
-#ifdef MODULE
 /* Detach from an amd7930 chip given the device structure. */
-static void amd7930_detach(struct sparcaudio_driver *drv)
+static void __exit amd7930_detach(struct sparcaudio_driver *drv)
 {
 	struct amd7930_info *info = (struct amd7930_info *)drv->private;
 
@@ -1672,14 +1671,9 @@
 	sbus_iounmap(info->regs, info->regs_size);
 	kfree(drv->private);
 }
-#endif
 
 /* Probe for the amd7930 chip and then attach the driver. */
-#ifdef MODULE
-int init_module(void)
-#else
-int __init amd7930_init(void)
-#endif
+static int __init amd7930_init(void)
 {
 	struct sbus_bus *sbus;
 	struct sbus_dev *sdev;
@@ -1710,8 +1704,7 @@
 	return (num_drivers > 0) ? 0 : -EIO;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit amd7930_exit(void)
 {
 	register int i;
 
@@ -1720,8 +1713,9 @@
 		num_drivers--;
 	}
 }
-#endif
 
+module_init(amd7930_init);
+module_exit(amd7930_exit);
 
 /*************************************************************/
 /*                 Audio format conversion                   */
diff -u --recursive --new-file v2.4.5/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c
--- v2.4.5/linux/drivers/sbus/audio/audio.c	Sun Feb 18 19:49:54 2001
+++ linux/drivers/sbus/audio/audio.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: audio.c,v 1.58 2001/02/13 01:16:59 davem Exp $
+/* $Id: audio.c,v 1.60 2001/05/21 09:05:05 davem Exp $
  * drivers/sbus/audio/audio.c
  *
  * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
@@ -32,10 +32,11 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/soundcard.h>
-#include <linux/version.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/delay.h>
+#include <linux/poll.h>
 #include <asm/pgtable.h>
+#include <asm/uaccess.h>
 
 #include <asm/audioio.h>
 
@@ -73,24 +74,6 @@
 static struct sparcaudio_driver *drivers[SPARCAUDIO_MAX_DEVICES];
 static devfs_handle_t devfs_handle;
  
-/* This crap to be pulled off into a local include file */
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
-
-#define COPY_IN(arg, get) verify_area(VERIFY_READ, (void *)arg, sizeof(long)); memcpy_fromfs(&get, (long *)arg, sizeof(get));
-#define COPY_OUT(arg, ret) verify_area(VERIFY_WRITE, (void *)arg, sizeof(long)); memcpy_tofs((long *)arg, &ret, sizeof(ret));
-#define copy_to_user memcpy_tofs
-#define copy_from_user memcpy_fromfs
-#define signal_pending(x) (((x)->signal) & ~((x)->blocked))
-
-#else
-
-#include <asm/uaccess.h>
-#include <linux/poll.h>
-#define COPY_IN(arg, get) get_user(get, (int *)arg)
-#define COPY_OUT(arg, ret) put_user(ret, (int *)arg)
-#define sparcaudio_select sparcaudio_poll
-
-#endif
 
 void sparcaudio_output_done(struct sparcaudio_driver * drv, int status)
 {
@@ -215,37 +198,6 @@
  *	VFS layer interface
  */
 
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
-static int sparcaudio_select(struct inode * inode, struct file * file,
-			    int sel_type, select_table * wait)
-{
-        struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
-                                                 SPARCAUDIO_DEVICE_SHIFT)];
-  
-        switch (sel_type) {
-        case SEL_IN:
-                if (((!file->f_flags & O_NONBLOCK) && drv->input_count) ||
-                    (drv->input_size > drv->buffer_size)) {
-                        dprintk(("read ready: c%d o%d\n",
-                                 drv->input_count, drv->input_offset));
-                        return 1;
-                }
-                select_wait(&drv->input_read_wait, wait);
-                break;
-        case SEL_OUT:
-                dprintk(("sel out: c%d o%d p%d\n",
-                         drv->output_count, drv->output_offset, drv->playing_count));
-                if ((drv->output_count + drv->playing_count) < (drv->num_output_buffers))
-                        return 1;
-                select_wait(&drv->output_write_wait, wait);
-                break;
-        case SEL_EX:
-                break;
-        };
-
-        return 0;
-}
-#else
 static unsigned int sparcaudio_poll(struct file *file, poll_table * wait)
 {
         unsigned int mask = 0;
@@ -264,29 +216,16 @@
         }
         return mask;
 }
-#endif
 
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
-static int sparcaudio_lseek(struct inode * inode, struct file * file,
-			    off_t offset, int origin)
-#else
-static loff_t sparcaudio_lseek(struct file * file, loff_t offset, int origin)
-#endif
+static loff_t sparcaudio_llseek(struct file * file, loff_t offset, int origin)
 {
 	return -ESPIPE;
 }
 
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
-static int sparcaudio_read(struct inode * inode, struct file * file,
-			   char *buf, int count)
-#else
 static ssize_t sparcaudio_read(struct file * file, char *buf, 
                                size_t count, loff_t *ppos)
-#endif
 {
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff
         struct inode *inode = file->f_dentry->d_inode;
-#endif
         struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
                                                  SPARCAUDIO_DEVICE_SHIFT)];
         int bytes_to_copy, bytes_read = 0, err;
@@ -358,17 +297,10 @@
         restore_flags(flags);
 }
 
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
-static int sparcaudio_write(struct inode * inode, struct file * file,
-			    const char *buf, int count)
-#else
 static ssize_t sparcaudio_write(struct file * file, const char *buf,
                                 size_t count, loff_t *ppos)
-#endif
 {
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff
         struct inode *inode = file->f_dentry->d_inode;
-#endif
         struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
                                                  SPARCAUDIO_DEVICE_SHIFT)];
         int bytes_written = 0, bytes_to_copy, err;
@@ -499,7 +431,7 @@
 
         switch (cmd) {
         case SOUND_MIXER_WRITE_RECLEV:
-                if(COPY_IN(arg, k))
+                if (get_user(k, (int *)arg))
                         return -EFAULT;
         iretry:
                 oprintk(("setting input volume (0x%x)", k));
@@ -531,9 +463,9 @@
                         oprintk((" try 0x%x\n", k));
                         goto iretry;
                 }
-                return COPY_OUT(arg, i);
+                return put_user(i, (int *)arg);
         case SOUND_MIXER_WRITE_VOLUME:
-                if(COPY_IN(arg, k))
+                if (get_user(k, (int *)arg))
                         return -EFAULT;
                 if (drv->ops->get_output_muted && drv->ops->set_output_muted) {
                         i = drv->ops->get_output_muted(drv);
@@ -546,9 +478,9 @@
                 if (drv->ops->get_output_muted) 
                         i = drv->ops->get_output_muted(drv);
                 k = 0x6464 * (1 - i);
-                return COPY_OUT(arg, k);
+                return put_user(k, (int *)arg);
         case SOUND_MIXER_WRITE_PCM:
-                if(COPY_IN(arg, k))
+                if (get_user(k, (int *)arg))
                         return -EFAULT;
         oretry:
                 oprintk(("setting output volume (0x%x)\n", k));
@@ -582,25 +514,25 @@
                         oprintk((" try 0x%x\n", k));
                         goto oretry;
                 }
-                return COPY_OUT(arg, i);
+                return put_user(i, (int *)arg);
         case SOUND_MIXER_READ_SPEAKER:
                 k = OSS_PORT_AUDIO(drv, AUDIO_SPEAKER);
-                return COPY_OUT(arg, k);
+                return put_user(k, (int *)arg);
         case SOUND_MIXER_READ_MIC:
                 k = OSS_IPORT_AUDIO(drv, AUDIO_MICROPHONE);
-                return COPY_OUT(arg, k);
+                return put_user(k, (int *)arg);
         case SOUND_MIXER_READ_CD:
                 k = OSS_IPORT_AUDIO(drv, AUDIO_CD);
-                return COPY_OUT(arg, k);
+                return put_user(k, (int *)arg);
         case SOUND_MIXER_READ_LINE:
                 k = OSS_IPORT_AUDIO(drv, AUDIO_LINE_IN);
-                return COPY_OUT(arg, k);
+                return put_user(k, (int *)arg);
         case SOUND_MIXER_READ_LINE1:
                 k = OSS_PORT_AUDIO(drv, AUDIO_HEADPHONE);
-                return COPY_OUT(arg, k);
+                return put_user(k, (int *)arg);
         case SOUND_MIXER_READ_LINE2:
                 k = OSS_PORT_AUDIO(drv, AUDIO_LINE_OUT);
-                return COPY_OUT(arg, k);
+                return put_user(k, (int *)arg);
 
         case SOUND_MIXER_WRITE_MIC:
         case SOUND_MIXER_WRITE_CD:
@@ -608,7 +540,7 @@
         case SOUND_MIXER_WRITE_LINE1:
         case SOUND_MIXER_WRITE_LINE2:
         case SOUND_MIXER_WRITE_SPEAKER:
-                if(COPY_IN(arg, k))
+                if (get_user(k, (int *)arg))
                         return -EFAULT;
                 OSS_TWIDDLE_IPORT(drv, cmd, SOUND_MIXER_WRITE_LINE, AUDIO_LINE_IN, k);
                 OSS_TWIDDLE_IPORT(drv, cmd, SOUND_MIXER_WRITE_MIC, AUDIO_MICROPHONE, k);
@@ -617,7 +549,7 @@
                 OSS_TWIDDLE_PORT(drv, cmd, SOUND_MIXER_WRITE_SPEAKER, AUDIO_SPEAKER, k);
                 OSS_TWIDDLE_PORT(drv, cmd, SOUND_MIXER_WRITE_LINE1, AUDIO_HEADPHONE, k);
                 OSS_TWIDDLE_PORT(drv, cmd, SOUND_MIXER_WRITE_LINE2, AUDIO_LINE_OUT, k);
-                return COPY_OUT(arg, k);
+                return put_user(k, (int *)arg);
         case SOUND_MIXER_READ_RECSRC: 
                 if (drv->ops->get_input_port)
                         i = drv->ops->get_input_port(drv);
@@ -627,11 +559,11 @@
                 if (i & AUDIO_LINE_IN) j = SOUND_MASK_LINE;
                 if (i & AUDIO_MICROPHONE) j = SOUND_MASK_MIC;
     
-                return COPY_OUT(arg, j);
+                return put_user(j, (int *)arg);
   case SOUND_MIXER_WRITE_RECSRC: 
           if (!drv->ops->set_input_port)
                   return -EINVAL;
-          if(COPY_IN(arg, k))
+          if (get_user(k, (int *)arg))
                   return -EFAULT;
 
           /* only one should ever be selected */
@@ -641,7 +573,7 @@
           oprintk(("setting inport to %d\n", j));
           i = drv->ops->set_input_port(drv, j);
     
-          return COPY_OUT(arg, i);
+          return put_user(i, (int *)arg);
         case SOUND_MIXER_READ_RECMASK: 
                 if (drv->ops->get_input_ports)
                         i = drv->ops->get_input_ports(drv);
@@ -650,10 +582,10 @@
                 if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE;
                 if (i & AUDIO_CD) j |= SOUND_MASK_CD;
     
-                return COPY_OUT(arg, j);
+                return put_user(j, (int *)arg);
         case SOUND_MIXER_READ_CAPS: /* mixer capabilities */
                 i = SOUND_CAP_EXCL_INPUT;
-                return COPY_OUT(arg, i);
+                return put_user(i, (int *)arg);
 
         case SOUND_MIXER_READ_DEVMASK: /* all supported devices */
                 if (drv->ops->get_input_ports)
@@ -676,7 +608,7 @@
 
                 if (cmd == SOUND_MIXER_READ_STEREODEVS)
                         j &= ~(MONO_DEVICES);
-                return COPY_OUT(arg, j);
+                return put_user(j, (int *)arg);
         default:
                 return -EINVAL;
         };
@@ -742,7 +674,7 @@
                 case I_GETSIG:
                 case I_GETSIG_SOLARIS:
                         j = (int) lis_get_elist_ent(drv->sd_siglist,current->pid);
-                        COPY_OUT(arg, j);
+                        put_user(j, (int *)arg);
                         retval = drv->input_count;
                         break;
 
@@ -773,7 +705,7 @@
                          * as its retval. (streamio(7I)) This should work.
                          */
                         j = (drv->input_count > 0) ? drv->input_buffer_size : 0;
-                        COPY_OUT(arg, j);
+                        put_user(j, (int *)arg);
                         retval = drv->input_count;
                         break;
 
@@ -859,11 +791,11 @@
                                 if (drv->ops->get_output_pause(drv))
                                         j |= PCM_ENABLE_OUTPUT;
                         }
-                        COPY_OUT(arg, j);
+                        put_user(j, (int *)arg);
                         break;
                 case SNDCTL_DSP_GETBLKSIZE:
                         j = drv->input_buffer_size;
-                        COPY_OUT(arg, j);
+                        put_user(j, (int *)arg);
                         break;
                 case SNDCTL_DSP_SPEED:
                         if ((!drv->ops->set_output_rate) && 
@@ -871,12 +803,12 @@
                                 retval = -EINVAL;
                                 break;
                         }
-                        COPY_IN(arg, i);
+                        get_user(i, (int *)arg)
                         tprintk(("setting speed to %d\n", i));
                         drv->ops->set_input_rate(drv, i);
                         drv->ops->set_output_rate(drv, i);
                         j = drv->ops->get_output_rate(drv);
-                        COPY_OUT(arg, j);
+                        put_user(j, (int *)arg);
                         break;
                 case SNDCTL_DSP_GETCAPS:
                         /* All Sparc audio hardware is full duplex.
@@ -884,19 +816,19 @@
                          * Pause functionality emulates trigger
                          */
                         j = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER | DSP_CAP_REALTIME;
-                        COPY_OUT(arg, j);
+                        put_user(j, (int *)arg);
                         break;
                 case SNDCTL_DSP_GETFMTS:
                         if (drv->ops->get_formats) {
                                 j = drv->ops->get_formats(drv);
-                                COPY_OUT(arg, j);
+                                put_user(j, (int *)arg);
                         } else {
                                 retval = -EINVAL;
                         }
                         break;
                 case SNDCTL_DSP_SETFMT:
                         /* need to decode into encoding, precision */
-                        COPY_IN(arg, i);
+                        get_user(i, (int *)arg);
 	    
                         /* handle special case here */
                         if (i == AFMT_QUERY) {
@@ -926,7 +858,7 @@
                                                 break;
                                         };
                                 } 
-                                COPY_OUT(arg, i);
+                                put_user(i, (int *)arg);
                                 break;
                         }
 
@@ -991,7 +923,7 @@
                                 dprintk(("setting format: failed\n"));
                                 return -EINVAL;
                         }
-                        COPY_OUT(arg, i);
+                        put_user(i, (int *)arg);
                         break;
                 case SNDCTL_DSP_CHANNELS:
                         if ((!drv->ops->set_output_channels) && 
@@ -999,11 +931,11 @@
                                 retval = -EINVAL;
                                 break;
                         }
-                        COPY_IN(arg, i);
+                        get_user(i, (int *)arg);
                         drv->ops->set_input_channels(drv, i);
                         drv->ops->set_output_channels(drv, i);
                         i = drv->ops->get_output_channels(drv);
-                        COPY_OUT(arg, i);
+                        put_user(i, (int *)arg);
                         break;
                 case SNDCTL_DSP_STEREO:
                         if ((!drv->ops->set_output_channels) && 
@@ -1011,11 +943,11 @@
                                 retval = -EINVAL;
                                 break;
                         }
-                        COPY_IN(arg, i);
+                        get_user(i, (int *)arg);
                         drv->ops->set_input_channels(drv, (i + 1));
                         drv->ops->set_output_channels(drv, (i + 1));
                         i = ((drv->ops->get_output_channels(drv)) - 1);
-                        COPY_OUT(arg, i);
+                        put_user(i, (int *)arg);
                         break;
                 case SNDCTL_DSP_POST:
                 case SNDCTL_DSP_SYNC:
@@ -1761,14 +1693,14 @@
 	default:
                 eprintk(("unknown minor device number\n"));
                 retval = -EINVAL;
-	};
+	}
 	
 	return retval;
 }
 
 static struct file_operations sparcaudioctl_fops = {
 	owner:		THIS_MODULE,
-	poll:		sparcaudio_select,
+	poll:		sparcaudio_poll,
 	ioctl:		sparcaudio_ioctl,
 };
 
@@ -1960,10 +1892,10 @@
 
 static struct file_operations sparcaudio_fops = {
 	owner:		THIS_MODULE,
-	llseek:		sparcaudio_lseek,
+	llseek:		sparcaudio_llseek,
 	read:		sparcaudio_read,
 	write:		sparcaudio_write,
-	poll:		sparcaudio_select,
+	poll:		sparcaudio_poll,
 	ioctl:		sparcaudio_ioctl,
 	open:		sparcaudio_open,
 	release:	sparcaudio_release,
@@ -2032,12 +1964,10 @@
          * TODO: Make number of input/output buffers tunable parameters
          */
 
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x202ff
         init_waitqueue_head(&drv->open_wait);
         init_waitqueue_head(&drv->output_write_wait);
         init_waitqueue_head(&drv->output_drain_wait);
         init_waitqueue_head(&drv->input_read_wait);
-#endif
 
         drv->num_output_buffers = 8;
 	drv->output_buffer_size = (4096 * 2);
@@ -2204,20 +2134,6 @@
 		return -EIO;
 
 	devfs_handle = devfs_mk_dir (NULL, "sound", NULL);
-	
-#ifdef CONFIG_SPARCAUDIO_AMD7930
-	amd7930_init();
-#endif
-#ifdef CONFIG_SPARCAUDIO_DBRI
-        dbri_init();
-#endif
-#ifdef CONFIG_SPARCAUDIO_CS4231
-	cs4231_init();
-#endif
-#ifdef CONFIG_SPARCAUDIO_DUMMY
-	dummy_init();
-#endif
-
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c
--- v2.4.5/linux/drivers/sbus/audio/cs4231.c	Sun Mar 25 18:14:20 2001
+++ linux/drivers/sbus/audio/cs4231.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: cs4231.c,v 1.45 2001/03/23 08:16:13 davem Exp $
+/* $Id: cs4231.c,v 1.46 2001/05/21 01:25:22 davem Exp $
  * drivers/sbus/audio/cs4231.c
  *
  * Copyright 1996, 1997, 1998, 1999 Derrick J Brashear (shadow@andrew.cmu.edu)
@@ -35,7 +35,7 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/sbus.h>
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff && defined(CONFIG_PCI)
+#ifdef CONFIG_PCI
 #define EB4231_SUPPORT
 #include <asm/ebus.h>
 #include <asm/pbm.h>
@@ -2178,9 +2178,6 @@
 static int cs4231_attach(struct sparcaudio_driver *drv, 
 			 struct sbus_dev *sdev)
 {
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
-        struct linux_prom_irqs irq;
-#endif
         struct cs4231_chip *cs4231_chip;
         int err;
 
@@ -2367,12 +2364,32 @@
 }
 #endif
 
-/* Probe for the cs4231 chip and then attach the driver. */
-#ifdef MODULE
-int init_module(void)
-#else
-int __init cs4231_init(void)
+/* Detach from an cs4231 chip given the device structure. */
+static void __exit cs4231_detach(struct sparcaudio_driver *drv)
+{
+	struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
+
+	cs4231_disable_interrupts(drv);
+	unregister_sparcaudio_driver(drv, 1);
+	disable_irq(cs4231_chip->irq);
+	free_irq(cs4231_chip->irq, drv);
+	if (!(cs4231_chip->status & CS_STATUS_IS_EBUS)) {
+		sbus_iounmap(cs4231_chip->regs, cs4231_chip->regs_size);
+	} else {
+#ifdef EB4231_SUPPORT
+		iounmap(cs4231_chip->regs);
+		iounmap(cs4231_chip->eb2p);
+		iounmap(cs4231_chip->eb2c);
+		disable_irq(cs4231_chip->irq2);
+		free_irq(cs4231_chip->irq2, drv);
 #endif
+	}
+	kfree(drv->private);
+}
+
+
+/* Probe for the cs4231 chip and then attach the driver. */
+static int __init cs4231_init(void)
 {
         struct sbus_bus *sbus;
         struct sbus_dev *sdev;
@@ -2414,31 +2431,7 @@
         return (num_drivers > 0) ? 0 : -EIO;
 }
 
-#ifdef MODULE
-/* Detach from an cs4231 chip given the device structure. */
-static void cs4231_detach(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-	cs4231_disable_interrupts(drv);
-        unregister_sparcaudio_driver(drv, 1);
-        disable_irq(cs4231_chip->irq);
-        free_irq(cs4231_chip->irq, drv);
-        if (!(cs4231_chip->status & CS_STATUS_IS_EBUS)) {
-                sbus_iounmap(cs4231_chip->regs, cs4231_chip->regs_size);
-        } else {
-#ifdef EB4231_SUPPORT
-                iounmap(cs4231_chip->regs);
-                iounmap(cs4231_chip->eb2p);
-                iounmap(cs4231_chip->eb2c);
-                disable_irq(cs4231_chip->irq2);
-                free_irq(cs4231_chip->irq2, drv);
-#endif
-        }
-        kfree(drv->private);
-}
-
-void cleanup_module(void)
+static void __exit cs4231_exit(void)
 {
         register int i;
 
@@ -2447,8 +2440,9 @@
                 num_drivers--;
         }
 }
-#endif
 
+module_init(cs4231_init);
+module_exit(cs4231_exit);
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff -u --recursive --new-file v2.4.5/linux/drivers/sbus/audio/dbri.c linux/drivers/sbus/audio/dbri.c
--- v2.4.5/linux/drivers/sbus/audio/dbri.c	Sun Feb 18 19:49:55 2001
+++ linux/drivers/sbus/audio/dbri.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: dbri.c,v 1.25 2001/02/13 01:16:59 davem Exp $
+/* $Id: dbri.c,v 1.26 2001/05/21 01:25:22 davem Exp $
  * drivers/sbus/audio/dbri.c
  *
  * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
@@ -61,7 +61,7 @@
 #include <asm/audioio.h>
 #include "dbri.h"
 
-#if defined(DBRI_ISDN) && defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff
+#if defined(DBRI_ISDN)
 #include "../../isdn/hisax/hisax.h"
 #include "../../isdn/hisax/isdnl1.h"
 #include "../../isdn/hisax/foreign.h"
@@ -2227,7 +2227,7 @@
        recv_on_pipe(dbri, 8+chan, buffer, size, callback, callback_arg);
 }
 
-#if defined(DBRI_ISDN) && defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff
+#if defined(DBRI_ISDN)
 struct foreign_interface dbri_foreign_interface = {
         dbri_get_irqnum,
         dbri_get_liu_state,
@@ -2336,11 +2336,7 @@
 }
 
 /* Probe for the dbri chip and then attach the driver. */
-#ifdef MODULE
-int init_module(void)
-#else
-int __init dbri_init(void)
-#endif
+static int __init dbri_init(void)
 {
 	struct sbus_bus *sbus;
 	struct sbus_dev *sdev;
@@ -2368,8 +2364,7 @@
 	return (num_drivers > 0) ? 0 : -EIO;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit dbri_exit(void)
 {
         register int i;
 
@@ -2379,8 +2374,9 @@
                 num_drivers--;
         }
 }
-#endif
 
+module_init(dbri_init);
+module_exit(dbri_exit);
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff -u --recursive --new-file v2.4.5/linux/drivers/sbus/audio/dmy.c linux/drivers/sbus/audio/dmy.c
--- v2.4.5/linux/drivers/sbus/audio/dmy.c	Sun Feb 18 19:49:55 2001
+++ linux/drivers/sbus/audio/dmy.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: dmy.c,v 1.7 2001/02/13 01:16:59 davem Exp $
+/* $Id: dmy.c,v 1.9 2001/05/22 23:16:10 davem Exp $
  * drivers/sbus/audio/dummy.c
  *
  * Copyright 1998 Derrick J Brashear (shadow@andrew.cmu.edu)
@@ -36,7 +36,7 @@
 static int dummy_record_gain(struct sparcaudio_driver *drv, int value, 
                             unsigned char balance);
 static int dummy_output_muted(struct sparcaudio_driver *drv, int value);
-static int dummy_attach(struct sparcaudio_driver *drv);
+static int dummy_attach(struct sparcaudio_driver *drv) __init;
 
 static int
 dummy_set_output_encoding(struct sparcaudio_driver *drv, int value)
@@ -710,25 +710,8 @@
         dummy_get_formats,
 };
 
-/* Probe for the dummy chip and then attach the driver. */
-#ifdef MODULE
-int init_module(void)
-#else
-int __init dummy_init(void)
-#endif
-{
-        num_drivers = 0;
-      
-        /* Add support here for specifying multiple dummies to attach at once. */
-        if (dummy_attach(&drivers[num_drivers]) == 0)
-                num_drivers++;
-  
-        /* Only return success if we found some dummy chips. */
-        return (num_drivers > 0) ? 0 : -EIO;
-}
-
 /* Attach to an dummy chip given its PROM node. */
-static int dummy_attach(struct sparcaudio_driver *drv)
+static int __init dummy_attach(struct sparcaudio_driver *drv)
 {
         struct dummy_chip *dummy_chip;
         int err;
@@ -768,15 +751,27 @@
         return 0;
 }
 
-#ifdef MODULE
 /* Detach from an dummy chip given the device structure. */
-static void dummy_detach(struct sparcaudio_driver *drv)
+static void __exit dummy_detach(struct sparcaudio_driver *drv)
 {
         unregister_sparcaudio_driver(drv, 2);
         kfree(drv->private);
 }
 
-void cleanup_module(void)
+/* Probe for the dummy chip and then attach the driver. */
+static int __init dummy_init(void)
+{
+	num_drivers = 0;
+      
+	/* Add support here for specifying multiple dummies to attach at once. */
+	if (dummy_attach(&drivers[num_drivers]) == 0)
+		num_drivers++;
+  
+	/* Only return success if we found some dummy chips. */
+	return (num_drivers > 0) ? 0 : -EIO;
+}
+
+static void __exit dummy_exit(void)
 {
         int i;
 
@@ -785,8 +780,9 @@
                 num_drivers--;
         }
 }
-#endif
 
+module_init(dummy_init);
+module_exit(dummy_exit);
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff -u --recursive --new-file v2.4.5/linux/drivers/sbus/char/aurora.h linux/drivers/sbus/char/aurora.h
--- v2.4.5/linux/drivers/sbus/char/aurora.h	Mon Dec 20 22:06:42 1999
+++ linux/drivers/sbus/char/aurora.h	Thu Jun 14 14:16:58 2001
@@ -1,4 +1,4 @@
-/*	$Id: aurora.h,v 1.5 1999/12/02 09:55:16 davem Exp $
+/*	$Id: aurora.h,v 1.6 2001/06/05 12:23:38 davem Exp $
  *	linux/drivers/sbus/char/aurora.h -- Aurora multiport driver
  *
  *	Copyright (c) 1999 by Oliver Aldulea (oli@bv.ro)
@@ -244,7 +244,7 @@
 	struct tty_struct 	* tty;
 	int			count;
 	int			blocked_open;
-	int			event;
+	long			event;
 	int			timeout;
 	int			close_delay;
 	long			session;
diff -u --recursive --new-file v2.4.5/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c
--- v2.4.5/linux/drivers/sbus/char/pcikbd.c	Wed May 16 10:31:27 2001
+++ linux/drivers/sbus/char/pcikbd.c	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.54 2001/05/11 07:46:28 davem Exp $
+/* $Id: pcikbd.c,v 1.57 2001/06/03 13:41:13 ecd Exp $
  * pcikbd.c: Ultra/AX PC keyboard support.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -54,6 +54,7 @@
 static int pcikbd_mrcoffee = 0;
 #else
 #define pcikbd_mrcoffee 0
+extern void (*prom_keyboard)(void);
 #endif
 
 static unsigned long pcikbd_iobase = 0;
@@ -66,6 +67,9 @@
 
 static spinlock_t pcikbd_lock = SPIN_LOCK_UNLOCKED;
 
+static void pcikbd_write(int address, int data);
+static int pcikbd_wait_for_input(void);
+
 unsigned char pckbd_read_mask = KBD_STAT_OBF;
 
 extern int pcikbd_init(void);
@@ -239,7 +243,7 @@
 		e0_keys[scancode - 128];
 }
 
-int do_acknowledge(unsigned char scancode)
+static int do_acknowledge(unsigned char scancode)
 {
 	if(reply_expected) {
 		if(scancode == KBD_REPLY_ACK) {
@@ -255,10 +259,87 @@
 	return 1;
 }
 
+#ifdef __sparc_v9__
+static void pcikbd_enter_prom(void)
+{
+	pcikbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);
+	if(pcikbd_wait_for_input() != KBD_REPLY_ACK)
+		printk("Prom Enter: Disable keyboard: no ACK\n");
+
+	/* Disable PC scancode translation */
+	pcikbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE);
+	pcikbd_write(KBD_DATA_REG, KBD_MODE_SYS);
+	pcikbd_write(KBD_DATA_REG, KBD_CMD_ENABLE);
+	if (pcikbd_wait_for_input() != KBD_REPLY_ACK)
+		printk("Prom Enter: Enable Keyboard: no ACK\n");
+}
+#endif
+
+static void ctrl_break(void)
+{
+	extern int stop_a_enabled;
+	unsigned long timeout;
+	int status, data;
+	int mode;
+
+	if (!stop_a_enabled)
+		return;
+
+	pcikbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);
+	if(pcikbd_wait_for_input() != KBD_REPLY_ACK)
+		printk("Prom Enter: Disable keyboard: no ACK\n");
+
+	/* Save current mode register settings */
+	pcikbd_write(KBD_CNTL_REG, KBD_CCMD_READ_MODE);
+	if ((mode = pcikbd_wait_for_input()) == -1)
+		printk("Prom Enter: Read Mode: no ACK\n");
+
+	/* Disable PC scancode translation */
+	pcikbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE);
+	pcikbd_write(KBD_DATA_REG, mode & ~(KBD_MODE_KCC));
+	pcikbd_write(KBD_DATA_REG, KBD_CMD_ENABLE);
+	if (pcikbd_wait_for_input() != KBD_REPLY_ACK)
+		printk("Prom Enter: Enable Keyboard: no ACK\n");
+
+	/* Drop into OBP.
+	 * Note that we must flush the user windows
+	 * first before giving up control.
+	 */
+        flush_user_windows();
+	prom_cmdline();
+
+	/* Read prom's key up event (use short timeout) */
+	do {
+		timeout = 10;
+		do {
+			mdelay(1);
+			status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG);
+			if (!(status & KBD_STAT_OBF))
+				continue;
+			data = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG);
+			if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
+				continue;
+			break;
+		} while (--timeout > 0);
+	} while (timeout > 0);
+
+	/* Reenable PC scancode translation */
+	pcikbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);
+	if(pcikbd_wait_for_input() != KBD_REPLY_ACK)
+		printk("Prom Leave: Disable keyboard: no ACK\n");
+
+	pcikbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE);
+	pcikbd_write(KBD_DATA_REG, mode);
+	pcikbd_write(KBD_DATA_REG, KBD_CMD_ENABLE);
+	if (pcikbd_wait_for_input() != KBD_REPLY_ACK)
+		printk("Prom Enter: Enable Keyboard: no ACK\n");
+}
+
 int pcikbd_translate(unsigned char scancode, unsigned char *keycode,
 		     char raw_mode)
 {
 	static int prev_scancode = 0;
+	int down = scancode & 0x80 ? 0 : 1;
 
 	if (scancode == 0xe0 || scancode == 0xe1) {
 		prev_scancode = scancode;
@@ -297,6 +378,18 @@
 
 	} else
 		*keycode = scancode;
+
+	if (*keycode == E0_BREAK) {
+		if (down)
+			return 0;
+
+		/* Handle ctrl-break event */
+		ctrl_break();
+
+		/* Send ctrl up event to the keyboard driver */
+		*keycode = 0x1d;
+	}
+
 	return 1;
 }
 
@@ -338,11 +431,11 @@
 	int retries = 3;
 	unsigned long flags;
 
-	spin_lock_irqsave(&pcikbd_lock, flags);
-
 	do {
 		unsigned long timeout = 1000;
 
+		spin_lock_irqsave(&pcikbd_lock, flags);
+
 		kb_wait();
 
 		acknowledge = 0;
@@ -350,24 +443,23 @@
 		reply_expected = 1;
 
 		pcikbd_outb(data, pcikbd_iobase + KBD_DATA_REG);
+
+		spin_unlock_irqrestore(&pcikbd_lock, flags);
+
 		do {
 			if (acknowledge)
-				goto out_ack;
+				return 1;
 			if (resend)
 				break;
 			mdelay(1);
 		} while (--timeout);
+
 		if (timeout == 0)
-			goto out_timeout;
+			break;
+
 	} while (retries-- > 0);
 
-out_timeout:
-	spin_unlock_irqrestore(&pcikbd_lock, flags);
 	return 0;
-
-out_ack:
-	spin_unlock_irqrestore(&pcikbd_lock, flags);
-	return 1;
 }
 
 void pcikbd_leds(unsigned char leds)
@@ -378,7 +470,7 @@
 		send_data(KBD_CMD_ENABLE);
 }
 
-static int __init pcikbd_wait_for_input(void)
+static int pcikbd_wait_for_input(void)
 {
 	int status, data;
 	unsigned long timeout = 1000;
@@ -401,7 +493,7 @@
 	return -1;
 }
 
-static void __init pcikbd_write(int address, int data)
+static void pcikbd_write(int address, int data)
 {
 	int status;
 
@@ -664,6 +756,8 @@
 	kd_mksound = pcikbd_kd_mksound;
 	printk("8042(speaker): iobase[%016lx]%s\n", pcibeep_iobase,
 	       edev ? "" : " (forced)");
+
+	prom_keyboard = pcikbd_enter_prom;
 #endif
 
 	disable_irq(pcikbd_irq);
diff -u --recursive --new-file v2.4.5/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c
--- v2.4.5/linux/drivers/sbus/char/sab82532.c	Thu Apr 19 08:38:49 2001
+++ linux/drivers/sbus/char/sab82532.c	Mon Jun 11 19:15:27 2001
@@ -1,8 +1,11 @@
-/* $Id: sab82532.c,v 1.58 2001/04/17 06:30:36 davem Exp $
+/* $Id: sab82532.c,v 1.60 2001/05/29 05:56:06 ecd Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
  *
+ * Rewrote buffer handling to use CIRC(Circular Buffer) macros.
+ *   Maxim Krasnyanskiy <maxk@qualcomm.com>
+ *
  */
 
 #include <linux/config.h>
@@ -59,6 +62,7 @@
 #undef SERIAL_DEBUG_WAIT_UNTIL_SENT
 #undef SERIAL_DEBUG_SEND_BREAK
 #undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_FIFO
 #define SERIAL_DEBUG_OVERFLOW 1
 
 /* Trace things on serial device, useful for console debugging: */
@@ -209,22 +213,23 @@
 
 	save_flags(flags); cli();
 
-	if (info->xmit_cnt <= 0)
+	if (info->xmit.head == info->xmit.tail)
 		goto out;
 
-	if (!(readb(&info->regs->r.star) & SAB82532_STAR_XFW))
+	if (!test_bit(SAB82532_XPR, &info->irqflags))
 		goto out;
 
 	info->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS);
 	writeb(info->interrupt_mask1, &info->regs->w.imr1);
-	info->all_sent = 0;
+	clear_bit(SAB82532_ALLS, &info->irqflags);
 
+	clear_bit(SAB82532_XPR, &info->irqflags);
 	for (i = 0; i < info->xmit_fifo_size; i++) {
-		u8 val = info->xmit_buf[info->xmit_tail++];
-		writeb(val, &info->regs->w.xfifo[i]);
-		info->xmit_tail &= (SERIAL_XMIT_SIZE - 1);
+		writeb(info->xmit.buf[info->xmit.tail],
+		       &info->regs->w.xfifo[i]);
+		info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
 		info->icount.tx++;
-		if (--info->xmit_cnt <= 0)
+		if (info->xmit.head == info->xmit.tail)
 			break;
 	}
 
@@ -397,20 +402,29 @@
 	if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) {
 		info->interrupt_mask1 |= SAB82532_IMR1_ALLS;
 		writeb(info->interrupt_mask1, &info->regs->w.imr1);
-		info->all_sent = 1;
+		set_bit(SAB82532_ALLS, &info->irqflags);
 	}
 
 	if (!(stat->sreg.isr1 & SAB82532_ISR1_XPR))
 		return;
 
+	if (!(readb(&info->regs->r.star) & SAB82532_STAR_XFW)) {
+#ifdef SERIAL_DEBUG_FIFO
+		printk("%s: XPR, but no XFW (???)\n", __FUNCTION__);
+#endif
+		return;
+	}
+
+	set_bit(SAB82532_XPR, &info->irqflags);
+
 	if (!info->tty) {
 		info->interrupt_mask1 |= SAB82532_IMR1_XPR;
 		writeb(info->interrupt_mask1, &info->regs->w.imr1);
 		return;
 	}
 
-	if ((info->xmit_cnt <= 0) || info->tty->stopped ||
-	    info->tty->hw_stopped) {
+	if ((info->xmit.head == info->xmit.tail) ||
+	    info->tty->stopped || info->tty->hw_stopped) {
 		info->interrupt_mask1 |= SAB82532_IMR1_XPR;
 		writeb(info->interrupt_mask1, &info->regs->w.imr1);
 		return;
@@ -418,15 +432,16 @@
 
 	info->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS);
 	writeb(info->interrupt_mask1, &info->regs->w.imr1);
-	info->all_sent = 0;
+	clear_bit(SAB82532_ALLS, &info->irqflags);
 
 	/* Stuff 32 bytes into Transmit FIFO. */
+	clear_bit(SAB82532_XPR, &info->irqflags);
 	for (i = 0; i < info->xmit_fifo_size; i++) {
-		u8 val = info->xmit_buf[info->xmit_tail++];
-		writeb(val, &info->regs->w.xfifo[i]);
-		info->xmit_tail &= (SERIAL_XMIT_SIZE - 1);
+		writeb(info->xmit.buf[info->xmit.tail],
+		       &info->regs->w.xfifo[i]);
+		info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
 		info->icount.tx++;
-		if (--info->xmit_cnt <= 0)
+		if (info->xmit.head == info->xmit.tail)
 			break;
 	}
 
@@ -434,16 +449,12 @@
 	sab82532_cec_wait(info);
 	writeb(SAB82532_CMDR_XF, &info->regs->w.cmdr);
 
-	if (info->xmit_cnt < WAKEUP_CHARS)
+	if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
 		sab82532_sched_event(info, RS_EVENT_WRITE_WAKEUP);
 
 #ifdef SERIAL_DEBUG_INTR
 	printk("THRE...");
 #endif
-	if (info->xmit_cnt <= 0) {
-		info->interrupt_mask1 |= SAB82532_IMR1_XPR;
-		writeb(info->interrupt_mask1, &info->regs->w.imr1);
-	}
 }
 
 static void check_status(struct sab82532 *info,
@@ -774,10 +785,10 @@
 		retval = -ENODEV;
 		goto errout;
 	}
-	if (info->xmit_buf)
+	if (info->xmit.buf)
 		free_page(page);
 	else
-		info->xmit_buf = (unsigned char *)page;
+		info->xmit.buf = (unsigned char *)page;
 
 #ifdef SERIAL_DEBUG_OPEN
 	printk("starting up serial port %d...", info->line);
@@ -812,11 +823,13 @@
 				SAB82532_IMR1_CSC | SAB82532_IMR1_XON |
 				SAB82532_IMR1_XPR;
 	writeb(info->interrupt_mask1, &info->regs->w.imr1);
-	info->all_sent = 1;
+	set_bit(SAB82532_ALLS, &info->irqflags);
 
 	if (info->tty)
 		clear_bit(TTY_IO_ERROR, &info->tty->flags);
-	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+	info->xmit.head = info->xmit.tail = 0;
+
+	set_bit(SAB82532_XPR, &info->irqflags);
 
 	/*
 	 * and set the speed of the serial port
@@ -856,9 +869,9 @@
 	 */
 	wake_up_interruptible(&info->delta_msr_wait);
 
-	if (info->xmit_buf) {
-		free_page((unsigned long)info->xmit_buf);
-		info->xmit_buf = 0;
+	if (info->xmit.buf) {
+		free_page((unsigned long)info->xmit.buf);
+		info->xmit.buf = 0;
 	}
 
 #ifdef CONFIG_SERIAL_CONSOLE
@@ -886,9 +899,11 @@
 	writeb(info->interrupt_mask1, &info->regs->w.imr1);
 
 	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
-		writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode);
-		writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode);
-		writeb(readb(&info->regs->rw.pvr) | info->pvr_dtr_bit, &info->regs->rw.pvr);
+		tmp = readb(&info->regs->r.mode);
+		tmp |= (SAB82532_MODE_FRTS | SAB82532_MODE_RTS);
+		writeb(tmp, &info->regs->rw.mode);
+		writeb(readb(&info->regs->rw.pvr) | info->pvr_dtr_bit,
+		       &info->regs->rw.pvr);
 	}
 
 	/* Disable break condition */
@@ -1054,18 +1069,17 @@
 	if (serial_paranoia_check(info, tty->device, "sab82532_put_char"))
 		return;
 
-	if (!tty || !info->xmit_buf)
+	if (!tty || !info->xmit.buf)
 		return;
 
 	save_flags(flags); cli();
-	if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+	if (!CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE)) {
 		restore_flags(flags);
 		return;
 	}
 
-	info->xmit_buf[info->xmit_head++] = ch;
-	info->xmit_head &= SERIAL_XMIT_SIZE-1;
-	info->xmit_cnt++;
+	info->xmit.buf[info->xmit.head] = ch;
+	info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
 	restore_flags(flags);
 }
 
@@ -1077,8 +1091,8 @@
 	if (serial_paranoia_check(info, tty->device, "sab82532_flush_chars"))
 		return;
 
-	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
-	    !info->xmit_buf)
+	if ((info->xmit.head == info->xmit.tail) ||
+	    tty->stopped || tty->hw_stopped || !info->xmit.buf)
 		return;
 
 	save_flags(flags); cli();
@@ -1098,42 +1112,63 @@
 	if (serial_paranoia_check(info, tty->device, "sab82532_write"))
 		return 0;
 
-	if (!tty || !info->xmit_buf || !tmp_buf)
+	if (!tty || !info->xmit.buf || !tmp_buf)
 		return 0;
 	    
-	if (from_user)
-		down(&tmp_buf_sem);
 	save_flags(flags);
-	while (1) {
-		cli();		
-		c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-				   SERIAL_XMIT_SIZE - info->xmit_head));
-		if (c <= 0)
-			break;
+	if (from_user) {
+		down(&tmp_buf_sem);
+		while (1) {
+			int c1;
+			c = CIRC_SPACE_TO_END(info->xmit.head,
+					      info->xmit.tail,
+					      SERIAL_XMIT_SIZE);
+			if (count < c)
+				c = count;
+			if (c <= 0)
+				break;
 
-		if (from_user) {
 			c -= copy_from_user(tmp_buf, buf, c);
 			if (!c) {
 				if (!ret)
 					ret = -EFAULT;
 				break;
 			}
-			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-				       SERIAL_XMIT_SIZE - info->xmit_head));
-			memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
-		} else
-			memcpy(info->xmit_buf + info->xmit_head, buf, c);
-		info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-		info->xmit_cnt += c;
+			cli();
+			c1 = CIRC_SPACE_TO_END(info->xmit.head,
+					       info->xmit.tail,
+					       SERIAL_XMIT_SIZE);
+			if (c1 < c)
+				c = c1;
+			memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+			info->xmit.head = (info->xmit.head + c) & (SERIAL_XMIT_SIZE-1);
+			restore_flags(flags);
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+		up(&tmp_buf_sem);
+	} else {
+		cli();
+		while (1) {
+			c = CIRC_SPACE_TO_END(info->xmit.head,
+					      info->xmit.tail,
+					      SERIAL_XMIT_SIZE);
+			if (count < c)
+				c = count;
+			if (c <= 0)
+				break;
+			memcpy(info->xmit.buf + info->xmit.head, buf, c);
+			info->xmit.head = (info->xmit.head + c) & (SERIAL_XMIT_SIZE-1);
+			buf += c;
+			count -= c;
+			ret += c;
+		}
 		restore_flags(flags);
-		buf += c;
-		count -= c;
-		ret += c;
 	}
-	if (from_user)
-		up(&tmp_buf_sem);
 
-	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
+	if ((info->xmit.head != info->xmit.tail) &&
+	    !tty->stopped && !tty->hw_stopped) {
 		info->interrupt_mask1 &= ~(SAB82532_IMR1_XPR);
 		writeb(info->interrupt_mask1, &info->regs->w.imr1);
 		sab82532_start_tx(info);
@@ -1146,14 +1181,11 @@
 static int sab82532_write_room(struct tty_struct *tty)
 {
 	struct sab82532 *info = (struct sab82532 *)tty->driver_data;
-	int ret;
 
 	if (serial_paranoia_check(info, tty->device, "sab82532_write_room"))
 		return 0;
-	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
-	if (ret < 0)
-		ret = 0;
-	return ret;
+
+	return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
 }
 
 static int sab82532_chars_in_buffer(struct tty_struct *tty)
@@ -1162,18 +1194,22 @@
 				
 	if (serial_paranoia_check(info, tty->device, "sab82532_chars_in_buffer"))
 		return 0;
-	return info->xmit_cnt;
+
+	return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
 }
 
 static void sab82532_flush_buffer(struct tty_struct *tty)
 {
 	struct sab82532 *info = (struct sab82532 *)tty->driver_data;
+	unsigned long flags;
 
 	if (serial_paranoia_check(info, tty->device, "sab82532_flush_buffer"))
 		return;
-	cli();
-	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-	sti();
+
+	save_flags(flags); cli();
+	info->xmit.head = info->xmit.tail = 0;
+	restore_flags(flags);
+
 	wake_up_interruptible(&tty->write_wait);
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 	    tty->ldisc.write_wakeup)
@@ -1221,6 +1257,12 @@
 	
 	if (I_IXOFF(tty))
 		sab82532_send_xchar(tty, STOP_CHAR(tty));
+
+	if (tty->termios->c_cflag & CRTSCTS) {
+		u8 mode = readb(&info->regs->r.mode);
+		mode &= ~(SAB82532_MODE_FRTS | SAB82532_MODE_RTS);
+		writeb(mode, &info->regs->w.mode);
+	}
 }
 
 static void sab82532_unthrottle(struct tty_struct * tty)
@@ -1242,6 +1284,13 @@
 		else
 			sab82532_send_xchar(tty, START_CHAR(tty));
 	}
+
+	if (tty->termios->c_cflag & CRTSCTS) {
+		u8 mode = readb(&info->regs->r.mode);
+		mode &= ~(SAB82532_MODE_RTS);
+		mode |= SAB82532_MODE_FRTS;
+		writeb(mode, &info->regs->w.mode);
+	}
 }
 
 /*
@@ -1295,7 +1344,8 @@
 {
 	unsigned int result;
 
-	result = (!info->xmit_buf && info->all_sent) ? TIOCSER_TEMT : 0;
+	result = (!info->xmit.buf && test_bit(SAB82532_ALLS, &info->irqflags))
+							? TIOCSER_TEMT : 0;
 	return put_user(result, value);
 }
 
@@ -1523,8 +1573,12 @@
 	if (!(old_termios->c_cflag & CBAUD) &&
 	    (tty->termios->c_cflag & CBAUD)) {
 		writeb(readb(&info->regs->w.pvr) & ~(info->pvr_dtr_bit), &info->regs->w.pvr);
-		if (!tty->hw_stopped ||
-		    !(tty->termios->c_cflag & CRTSCTS)) {
+		if (tty->termios->c_cflag & CRTSCTS) {
+			writeb(readb(&info->regs->w.mode) & ~(SAB82532_MODE_RTS), &info->regs->w.mode);
+			writeb(readb(&info->regs->w.mode) | SAB82532_MODE_FRTS, &info->regs->w.mode);
+		} else if (test_bit(TTY_THROTTLED, &tty->flags)) {
+			writeb(readb(&info->regs->w.mode) & ~(SAB82532_MODE_FRTS | SAB82532_MODE_RTS), &info->regs->w.mode);
+		} else {
 			writeb(readb(&info->regs->w.mode) & ~(SAB82532_MODE_FRTS), &info->regs->w.mode);
 			writeb(readb(&info->regs->w.mode) | SAB82532_MODE_RTS, &info->regs->w.mode);
 		}
@@ -1654,7 +1708,6 @@
 	if (serial_paranoia_check(info,tty->device,"sab82532_wait_until_sent"))
 		return;
 
-	orig_jiffies = jiffies;
 	/*
 	 * Set the check interval to be 1/5 of the estimated time to
 	 * send a single character, and make it at least 1.  The check
@@ -1670,10 +1723,15 @@
 	if (timeout)
 	  char_time = MIN(char_time, timeout);
 #ifdef SERIAL_DEBUG_WAIT_UNTIL_SENT
-	printk("In sab82532_wait_until_sent(%d) check=%lu...", timeout, char_time);
-	printk("jiff=%lu...", jiffies);
+	printk("In sab82532_wait_until_sent(%d) check=%lu "
+	       "xmit_cnt = %ld, alls = %d (jiff=%lu)...\n",
+	       timeout, char_time,
+	       CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE),
+	       test_bit(SAB82532_ALLS, &info->irqflags), jiffies);
 #endif
-	while (info->xmit_cnt || !info->all_sent) {
+	orig_jiffies = jiffies;
+	while ((info->xmit.head != info->xmit.tail) ||
+	       !test_bit(SAB82532_ALLS, &info->irqflags)) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule_timeout(char_time);
 		if (signal_pending(current))
@@ -1682,7 +1740,9 @@
 			break;
 	}
 #ifdef SERIAL_DEBUG_WAIT_UNTIL_SENT
-	printk("xmit_cnt = %d, alls = %d (jiff=%lu)...done\n", info->xmit_cnt, info->all_sent, jiffies);
+	printk("xmit_cnt = %ld, alls = %d (jiff=%lu)...done\n",
+	       CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE),
+	       test_bit(SAB82532_ALLS, &info->irqflags), jiffies);
 #endif
 }
 
@@ -2151,7 +2211,7 @@
 
 static inline void __init show_serial_version(void)
 {
-	char *revision = "$Revision: 1.58 $";
+	char *revision = "$Revision: 1.60 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -u --recursive --new-file v2.4.5/linux/drivers/scsi/NCR53c406a.c linux/drivers/scsi/NCR53c406a.c
--- v2.4.5/linux/drivers/scsi/NCR53c406a.c	Tue May 22 10:23:16 2001
+++ linux/drivers/scsi/NCR53c406a.c	Tue Jun 12 11:06:54 2001
@@ -221,7 +221,7 @@
     (void *)0xc8000
 };
 #define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned ))
-#endif USE_BIOS
+#endif /* USE_BIOS */
 		       
 /* possible i/o port addresses */
 static unsigned short ports[] =
@@ -244,7 +244,7 @@
     { "Copyright (C) Acculogic, Inc.\r\n2.8M Diskette Extension Bios ver 4.04.03 03/01/1993", 61, 82 },
 };
 #define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
-#endif USE_BIOS
+#endif /* USE_BIOS */
 
 /* ============================================================ */
 
@@ -347,7 +347,7 @@
     
     return tmp;
 }
-#endif USE_DMA
+#endif /* USE_DMA */
 
 #if USE_PIO
 static __inline__ int NCR53c406a_pio_read(unsigned char *request, 
@@ -455,7 +455,7 @@
     }
     return 0;
 }
-#endif USE_PIO
+#endif /* USE_PIO */
 
 int  __init 
 NCR53c406a_detect(Scsi_Host_Template * tpnt){
@@ -481,7 +481,7 @@
     }
     
     DEB(printk("NCR53c406a BIOS found at %X\n", (unsigned int) bios_base););
-#endif USE_BIOS
+#endif /* USE_BIOS */
     
 #ifdef PORT_BASE
     if (!request_region(port_base, 0x10, "NCR53c406a")) /* ports already snatched */
@@ -512,7 +512,7 @@
             }
         }
     }
-#endif PORT_BASE
+#endif /* PORT_BASE */
     
     if(!port_base){		/* no ports found */
         printk("NCR53c406a: no available ports found\n");
@@ -550,7 +550,7 @@
 #if USE_DMA
         printk("NCR53c406a: No interrupts found and DMA mode defined. Giving up.\n");
         goto err_release;
-#endif USE_DMA
+#endif /* USE_DMA */
     }
     else {
         DEB(printk("NCR53c406a: Shouldn't get here!\n"));
@@ -565,7 +565,7 @@
     }
     
     DEB(printk("Allocated DMA channel %d\n", dma_chan));
-#endif USE_DMA 
+#endif /* USE_DMA */
     
     tpnt->present = 1;
     tpnt->proc_name = "NCR53c406a";
@@ -820,8 +820,8 @@
     printk("\n");
 #else
     printk(", pio=%02x\n", pio_status);
-#endif USE_DMA
-#endif NCR53C406A_DEBUG
+#endif /* USE_DMA */
+#endif /* NCR53C406A_DEBUG */
     
     if(int_reg & 0x80){         /* SCSI reset intr */
         rtrc(3);
@@ -840,7 +840,7 @@
         current_SC->scsi_done(current_SC);
         return;
     }
-#endif USE_PIO
+#endif /* USE_PIO */
     
     if(status & 0x20) {		/* Parity error */
         printk("NCR53c406a: Warning: parity error!\n");
@@ -885,7 +885,7 @@
 #if USE_DMA			/* No s/g support for DMA */
             NCR53c406a_dma_write(current_SC->request_buffer, 
                                  current_SC->request_bufflen);
-#endif USE_DMA
+#endif /* USE_DMA */
             outb(TRANSFER_INFO | DMA_OP, CMD_REG); 
 #if USE_PIO
             if (!current_SC->use_sg) /* Don't use scatter-gather */
@@ -900,7 +900,7 @@
                 }
             }
             REG0;
-#endif USE_PIO
+#endif /* USE_PIO */
         }
         break;
         
@@ -914,7 +914,7 @@
 #if USE_DMA			/* No s/g support for DMA */
             NCR53c406a_dma_read(current_SC->request_buffer, 
                                 current_SC->request_bufflen);
-#endif USE_DMA
+#endif /* USE_DMA */
             outb(TRANSFER_INFO | DMA_OP, CMD_REG); 
 #if USE_PIO
             if (!current_SC->use_sg) /* Don't use scatter-gather */
@@ -929,7 +929,7 @@
                 }
             }
             REG0;
-#endif USE_PIO
+#endif /* USE_PIO */
         }
         break;
         
@@ -1011,7 +1011,7 @@
     
     return irq;
 }
-#endif IRQ_LEV
+#endif /* IRQ_LEV */
 
 static void chip_init()
 {
diff -u --recursive --new-file v2.4.5/linux/drivers/scsi/aic7xxx_old.c linux/drivers/scsi/aic7xxx_old.c
--- v2.4.5/linux/drivers/scsi/aic7xxx_old.c	Fri Apr 27 13:59:18 2001
+++ linux/drivers/scsi/aic7xxx_old.c	Tue Jun 12 11:06:54 2001
@@ -10100,7 +10100,7 @@
       } /* while(pdev=....) */
     } /* for PCI_DEVICES */
   } /* PCI BIOS present */
-#endif CONFIG_PCI
+#endif /* CONFIG_PCI */
 
 #if defined(__i386__) || defined(__alpha__)
   /*
diff -u --recursive --new-file v2.4.5/linux/drivers/scsi/constants.c linux/drivers/scsi/constants.c
--- v2.4.5/linux/drivers/scsi/constants.c	Mon Jan 15 13:08:15 2001
+++ linux/drivers/scsi/constants.c	Tue Jun 12 11:17:17 2001
@@ -689,7 +689,7 @@
 			  kdev_t dev)
 {
     int i, s;
-    int sense_class, valid, code;
+    int sense_class, valid, code, info;
     const char * error = NULL;
     
     sense_class = (sense_buffer[0] >> 4) & 0x07;
@@ -701,11 +701,14 @@
 	if(s > SCSI_SENSE_BUFFERSIZE)
 	   s = SCSI_SENSE_BUFFERSIZE;
 	
-	if (!valid)
-	    printk("[valid=0] ");
-	printk("Info fld=0x%x, ", (int)((sense_buffer[3] << 24) |
-	       (sense_buffer[4] << 16) | (sense_buffer[5] << 8) |
-	       sense_buffer[6]));
+	info = ((sense_buffer[3] << 24) | (sense_buffer[4] << 16) |
+		(sense_buffer[5] << 8) | sense_buffer[6]);
+	if (info || valid) {
+		printk("Info fld=0x%x", info);
+		if (!valid)	/* info data not according to standard */
+			printk(" (nonstd)");
+		printk(", ");
+	}
 	if (sense_buffer[2] & 0x80)
            printk( "FMK ");	/* current command has read a filemark */
 	if (sense_buffer[2] & 0x40)
diff -u --recursive --new-file v2.4.5/linux/drivers/scsi/cpqfcTSinit.c linux/drivers/scsi/cpqfcTSinit.c
--- v2.4.5/linux/drivers/scsi/cpqfcTSinit.c	Fri Apr 27 14:05:28 2001
+++ linux/drivers/scsi/cpqfcTSinit.c	Wed Jun 20 11:19:02 2001
@@ -1808,7 +1808,7 @@
 
 #ifdef MODULE
 
-Scsi_Host_Template driver_template = CPQFCTS;
+static Scsi_Host_Template driver_template = CPQFCTS;
 
 #include "scsi_module.c"
 
diff -u --recursive --new-file v2.4.5/linux/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c
--- v2.4.5/linux/drivers/scsi/gdth.c	Sat May 19 17:43:06 2001
+++ linux/drivers/scsi/gdth.c	Wed Jun 20 11:19:02 2001
@@ -4639,7 +4639,7 @@
 
 #else
 
-Scsi_Host_Template driver_template = GDTH;
+static Scsi_Host_Template driver_template = GDTH;
 #include "scsi_module.c"
 #ifndef MODULE
 __setup("gdth=", option_setup);
diff -u --recursive --new-file v2.4.5/linux/drivers/scsi/osst.c linux/drivers/scsi/osst.c
--- v2.4.5/linux/drivers/scsi/osst.c	Thu Jan  4 13:00:55 2001
+++ linux/drivers/scsi/osst.c	Tue Jun 12 11:09:03 2001
@@ -16,22 +16,21 @@
   Copyright 1992 - 2000 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  $Header: /home/cvsroot/Driver/osst.c,v 1.51 2000/12/22 20:48:27 garloff Exp $
+  $Header: /home/cvsroot/Driver/osst.c,v 1.61 2001/06/03 21:55:12 riede Exp $
 
   Microscopic alterations - Rik Ling, 2000/12/21
   Last modified: Wed Feb  2 22:04:05 2000 by makisara@kai.makisara.local
   Some small formal changes - aeb, 950809
 */
 
-static const char * cvsid = "$Id: osst.c,v 1.51 2000/12/22 20:48:27 garloff Exp $";
-const char * osst_version = "0.9.4.3";
+static const char * cvsid = "$Id: osst.c,v 1.61 2001/06/03 21:55:12 riede Exp $";
+const char * osst_version = "0.9.8";
 
 /* The "failure to reconnect" firmware bug */
-#define OSST_FW_NEED_POLL_MIN 10602 /*(107A)*/
-#define OSST_FW_NEED_POLL_MAX 10708 /*(108D)*/
+#define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/
+#define OSST_FW_NEED_POLL_MAX 10704 /*(108D)*/
 #define OSST_FW_NEED_POLL(x,d) ((x) >= OSST_FW_NEED_POLL_MIN && (x) <= OSST_FW_NEED_POLL_MAX && d->host->this_id != 7)
 
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/fs.h>
@@ -112,6 +111,8 @@
 
 #if DEBUG
 static int debugging = 1;
+/* uncomment define below to test error recovery */
+// #define OSST_INJECT_ERRORS 1 
 #endif
 
 #define MAX_RETRIES 0
@@ -172,7 +173,7 @@
 
 static int osst_get_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt);
 
-static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, int file_blk);
+static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt);
 
 static int osst_write_error_recovery(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int pending);
 
@@ -202,7 +203,7 @@
 
 #if DEBUG
 	if (debugging) {
-		printk(OSST_DEB_MSG "osst%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
+		printk(OSST_DEB_MSG "osst%d:D: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
 		   dev, result,
 		   SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2],
 		   SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5],
@@ -222,16 +223,25 @@
 		 SRpnt->sr_cmnd[0] != MODE_SENSE &&
 		 SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
 		if (driver_byte(result) & DRIVER_SENSE) {
-			printk(KERN_WARNING "osst%d: Error with sense data: ", dev);
+			printk(KERN_WARNING "osst%d:W: Error with sense data: ", dev);
 			print_req_sense("osst", SRpnt);
 		}
-		else
+		else {
+			static	int	notyetprinted = 1;
+
 			printk(KERN_WARNING
-			     "osst%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
+			     "osst%d:W: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
 			     dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
 			     host_byte(result));
+			if (notyetprinted) {
+				notyetprinted = 0;
+				printk(KERN_INFO
+					"osst%d:I: This error may be caused by your scsi controller,\n", dev);
+				printk(KERN_INFO
+					"osst%d:I: it has been reported with some Buslogic cards.\n", dev);
+			}
+		}
 	}
-
 	if ((sense[0] & 0x70) == 0x70 &&
 	     scode == RECOVERED_ERROR) {
 		STp->recover_count++;
@@ -244,7 +254,7 @@
 				stp = "write";
 			else
 				stp = "ioctl";
-			printk(OSST_DEB_MSG "osst%d: Recovered %s error (%d).\n", dev, stp,
+			printk(OSST_DEB_MSG "osst%d:D: Recovered %s error (%d).\n", dev, stp,
 					     os_scsi_tapes[dev]->recover_count);
 		}
 #endif
@@ -259,7 +269,6 @@
 static void osst_sleep_done (Scsi_Cmnd * SCpnt)
 {
 	unsigned int dev;
-	int remainder;
 	OS_Scsi_Tape * STp;
 
 	if ((dev = TAPE_NR(SCpnt->request.rq_dev)) < osst_template.nr_dev) {
@@ -268,15 +277,7 @@
 		    (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
 		    (SCpnt->sense_buffer[2] & 0x40)) {
 			/* EOM at write-behind, has all been written? */
-			if ((SCpnt->sense_buffer[0] & 0x80) != 0)
-				remainder = (SCpnt->sense_buffer[3] << 24) |
-					    (SCpnt->sense_buffer[4] << 16) |
-					    (SCpnt->sense_buffer[5] << 8 ) |
-					     SCpnt->sense_buffer[6];
-			else
-				remainder = 0;
-			if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW ||
-			    remainder > 0)
+			if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
 				(STp->buffer)->midlevel_result = SCpnt->result; /* Error */
 			else
 				(STp->buffer)->midlevel_result = INT_MAX;       /* OK */
@@ -293,7 +294,7 @@
 	}
 #if DEBUG
 	else if (debugging)
-		printk(KERN_ERR "osst?: Illegal interrupt device %x\n", dev);
+		printk(OSST_DEB_MSG "osst?:D: Illegal interrupt device %x\n", dev);
 #endif
 }
 
@@ -305,11 +306,13 @@
 	unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait)
 {
 	unsigned char *bp;
-//static int inject = 0; /* FIXME - take out inject occasional read errors */
-//static int repeat = 0;
+#ifdef OSST_INJECT_ERRORS
+	static   int   inject = 0;
+	static   int   repeat = 0;
+#endif
 	if (SRpnt == NULL) {
 		if ((SRpnt = scsi_allocate_request(STp->device)) == NULL) {
-			printk(KERN_ERR "osst%d: Can't get SCSI request.\n", TAPE_NR(STp->devt));
+			printk(KERN_ERR "osst%d:E: Can't get SCSI request.\n", TAPE_NR(STp->devt));
 			if (signal_pending(current))
 				(STp->buffer)->syscall_result = (-EINTR);
 			else
@@ -341,12 +344,18 @@
 		down(SRpnt->sr_request.sem);
 		SRpnt->sr_request.sem = NULL;
 		STp->buffer->syscall_result = osst_chk_result(STp, SRpnt);
-//if ((STp->buffer)->syscall_result == 0 &&
-//    cmd[0] == READ_6 && cmd[4] && ( /* (++ inject % 83) == 29  || */
-//     (STp->first_frame_position == 240 /* or STp->read_error_frame to fail again on the block calculated above */ && ++repeat < 3))) {
-//	printk(OSST_DEB_MSG "osst%d: injecting read error\n", TAPE_NR(STp->devt));
-//	STp->buffer->last_result_fatal = 1; /* FIXME - take out inject occasional read errors */
-//}
+#ifdef OSST_INJECT_ERRORS
+		if (STp->buffer->syscall_result == 0 &&
+		    cmd[0] == READ_6 &&
+		    cmd[4] && 
+		    ( (++ inject % 83) == 29  ||
+		      (STp->first_frame_position == 240 
+			         /* or STp->read_error_frame to fail again on the block calculated above */ &&
+				 ++repeat < 3))) {
+			printk(OSST_DEB_MSG "osst%d:D: Injecting read error\n", TAPE_NR(STp->devt));
+			STp->buffer->last_result_fatal = 1;
+		}
+#endif
 	}
 	return SRpnt;
 }
@@ -356,7 +365,6 @@
 static void osst_write_behind_check(OS_Scsi_Tape *STp)
 {
 	OSST_buffer * STbuffer;
-	ST_partstat * STps;
 
 	STbuffer = STp->buffer;
 
@@ -366,7 +374,6 @@
 	else
 		STp->nbr_finished++;
 #endif
-
 	down(&(STp->sem));
 	(STp->buffer)->last_SRpnt->sr_request.sem = NULL;
 
@@ -381,21 +388,9 @@
 	scsi_release_request((STp->buffer)->last_SRpnt);
 
 	if (STbuffer->writing < STbuffer->buffer_bytes)
-#if 0
-	memcpy(STbuffer->b_data,
-	   STbuffer->b_data + STbuffer->writing,
-	   STbuffer->buffer_bytes - STbuffer->writing);
-#else
-	printk(KERN_WARNING "osst: write_behind_check: something left in buffer!\n");
-#endif
+		printk(KERN_WARNING "osst:A: write_behind_check: something left in buffer!\n");
+
 	STbuffer->buffer_bytes -= STbuffer->writing;
-	STps = &(STp->ps[STp->partition]);
-	if (STps->drv_block >= 0) {
-		if (STp->block_size == 0)
-			STps->drv_block++;
-		else
-			STps->drv_block += STbuffer->writing / STp->block_size;
-	}
 	STbuffer->writing = 0;
 
 	return;
@@ -407,7 +402,8 @@
 /*
  * Initialize the OnStream AUX
  */
-static void osst_init_aux(OS_Scsi_Tape * STp, int frame_type, int logical_blk_num)
+static void osst_init_aux(OS_Scsi_Tape * STp, int frame_type, int frame_seq_number,
+					 int logical_blk_num, int blk_sz, int blk_cnt)
 {
 	os_aux_t       *aux = STp->buffer->aux;
 	os_partition_t *par = &aux->partition;
@@ -441,9 +437,10 @@
 		dat->reserved1 = 0;
 		dat->entry_cnt = 1;
 		dat->reserved3 = 0;
-		dat->dat_list[0].blk_sz   = htonl(frame_type==OS_FRAME_TYPE_DATA?STp->block_size:0);
-		dat->dat_list[0].blk_cnt  = htons(1);
-		dat->dat_list[0].flags    = frame_type==OS_FRAME_TYPE_MARKER?OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA;
+		dat->dat_list[0].blk_sz   = htonl(blk_sz);
+		dat->dat_list[0].blk_cnt  = htons(blk_cnt);
+		dat->dat_list[0].flags    = frame_type==OS_FRAME_TYPE_MARKER?
+							OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA;
 		dat->dat_list[0].reserved = 0;
 	  case	OS_FRAME_TYPE_EOD:
 		aux->update_frame_cntr    = htonl(0);
@@ -452,27 +449,28 @@
 		par->wrt_pass_cntr        = htons(STp->wrt_pass_cntr);
 		par->first_frame_ppos     = htonl(STp->first_data_ppos);
 		par->last_frame_ppos      = htonl(STp->capacity);
-		aux->frame_seq_num        = htonl(logical_blk_num);
+		aux->frame_seq_num        = htonl(frame_seq_number);
 		aux->logical_blk_num_high = htonl(0);
 		aux->logical_blk_num      = htonl(logical_blk_num);
 		break;
 	  default: ; /* probably FILL */
 	}
-	aux->filemark_cnt = ntohl(STp->filemark_cnt);        /* FIXME -- violates ADR spec */
+	aux->filemark_cnt = ntohl(STp->filemark_cnt);
 	aux->phys_fm = ntohl(0xffffffff);
 	aux->last_mark_ppos = ntohl(STp->last_mark_ppos);
+	aux->last_mark_lbn  = ntohl(STp->last_mark_lbn);
 }
 
 /*
  * Verify that we have the correct tape frame
  */
-static int osst_verify_frame(OS_Scsi_Tape * STp, int logical_blk_num, int quiet)
+static int osst_verify_frame(OS_Scsi_Tape * STp, int frame_seq_number, int quiet)
 {
 	os_aux_t       * aux  = STp->buffer->aux;
 	os_partition_t * par  = &(aux->partition);
 	ST_partstat    * STps = &(STp->ps[STp->partition]);
-	int              i;
 	int		 dev  = TAPE_NR(STp->devt);
+	int		 blk_cnt, blk_sz, i;
 
 	if (STp->raw) {
 		if (STp->buffer->syscall_result) {
@@ -483,55 +481,70 @@
 		return 1;
 	}
 	if (STp->buffer->syscall_result) {
-		printk(KERN_INFO "osst%d: Skipping frame, read error\n", dev);
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d:D: Skipping frame, read error\n", dev);
+#endif
 		return 0;
 	}
 	if (ntohl(aux->format_id) != 0) {
-		printk(KERN_INFO "osst%d: Skipping frame, format_id %u\n", dev, ntohl(aux->format_id));
-		return 0;
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d:D: Skipping frame, format_id %u\n", dev, ntohl(aux->format_id));
+#endif
+		goto err_out;
 	}
 	if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 &&
 	    (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) {
-		printk(KERN_INFO "osst%d: Skipping frame, incorrect application signature\n", dev);
-		return 0;
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d:D: Skipping frame, incorrect application signature\n", dev);
+#endif
+		goto err_out;
 	}
 	if (par->partition_num != OS_DATA_PARTITION) {
 		if (!STp->linux_media || STp->linux_media_version != 2) {
-			printk(KERN_INFO "osst%d: Skipping frame, partition num %d\n", dev, par->partition_num);              		    return 0;
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%d:D: Skipping frame, partition num %d\n",
+					    dev, par->partition_num);
+#endif
+			goto err_out;
 		}
 	}
 	if (par->par_desc_ver != OS_PARTITION_VERSION) {
-		printk(KERN_INFO "osst%d: Skipping frame, partition version %d\n", dev, par->par_desc_ver);
-		return 0;
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d:D: Skipping frame, partition version %d\n", dev, par->par_desc_ver);
+#endif
+		goto err_out;
 	}
 	if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) {
-		printk(KERN_INFO "osst%d: Skipping frame, wrt_pass_cntr %d (expected %d)\n", 
-				 dev, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr);
-		return 0;
-	}
-	if (aux->frame_seq_num != aux->logical_blk_num) {
-		printk(KERN_INFO "osst%d: Skipping frame, seq != logical\n", dev);
-		return 0;
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n", 
+				    dev, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr);
+#endif
+		goto err_out;
 	}
 	if (aux->frame_type != OS_FRAME_TYPE_DATA &&
 	    aux->frame_type != OS_FRAME_TYPE_EOD &&
 	    aux->frame_type != OS_FRAME_TYPE_MARKER) {
 		if (!quiet)
-			printk(KERN_INFO "osst%d: Skipping frame, frame type %x\n", dev, aux->frame_type);
-		return 0;
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%d:D: Skipping frame, frame type %x\n", dev, aux->frame_type);
+#endif
+		goto err_out;
 	}
 	if (aux->frame_type == OS_FRAME_TYPE_EOD &&
 	    STp->first_frame_position < STp->eod_frame_ppos) {
-		printk(KERN_INFO "osst%d: Skipping premature EOD frame %d\n", dev, STp->first_frame_position);
-		return 0;
+		printk(KERN_INFO "osst%d:I: Skipping premature EOD frame %d\n", dev,
+				 STp->first_frame_position);
+		goto err_out;
 	}
-	STp->logical_blk_in_buffer = 1;
+	STp->frame_in_buffer = 1;
 
-	if (logical_blk_num != -1 && ntohl(aux->logical_blk_num) != logical_blk_num) {
+        if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) {
 		if (!quiet)
-			printk(KERN_INFO "osst%d: Skipping frame, logical_blk_num %u (expected %d)\n", 
-					 dev, ntohl(aux->logical_blk_num), logical_blk_num);
-		return 0;
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%d:D: Skipping frame, sequence number %u (expected %d)\n", 
+					    dev, ntohl(aux->frame_seq_num), frame_seq_number);
+#endif
+		goto err_out;
 	}
 	if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
 		STps->eof = ST_FM_HIT;
@@ -539,8 +552,8 @@
 		i = ntohl(aux->filemark_cnt);
 		if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt ||
 		    STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) {
-#if 1 //DEBUG
-			printk(OSST_DEB_MSG "osst%i: %s filemark %d at frame %d\n", dev,
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%d:D: %s filemark %d at frame pos %d\n", dev,
 				  STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected",
 				  i, STp->first_frame_position - 1);
 #endif
@@ -553,9 +566,31 @@
 		STps->eof = ST_EOD_1;
 	}
 	if (aux->frame_type == OS_FRAME_TYPE_DATA) {
+                blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt);
+		blk_sz  = ntohl(aux->dat.dat_list[0].blk_sz);
+		STp->buffer->buffer_bytes = blk_cnt * blk_sz;
+		STp->buffer->read_pointer = 0;
+
+		/* See what block size was used to write file */
+		if (STp->block_size != blk_sz && blk_sz > 0) {
+			printk(KERN_INFO
+	    	"osst%d:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n",
+       				dev, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k',
+				STp->block_size<1024?STp->block_size:STp->block_size/1024,
+				STp->block_size<1024?'b':'k');
+			STp->block_size            = blk_sz;
+			STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz;
+		}
 		STps->eof = ST_NOEOF;
 	}
+        STp->frame_seq_number = ntohl(aux->frame_seq_num);
+	STp->logical_blk_num  = ntohl(aux->logical_blk_num);
 	return 1;
+
+err_out:
+	if (STp->read_error_frame == 0)
+		STp->read_error_frame = STp->first_frame_position - 1;
+	return 0;
 }
 
 /*
@@ -570,7 +605,7 @@
 	int		dbg = debugging;
 	int		dev  = TAPE_NR(STp->devt);
 
-	printk(OSST_DEB_MSG "osst%d: Reached onstream wait ready\n", dev);
+	printk(OSST_DEB_MSG "osst%d:D: Reached onstream wait ready\n", dev);
 #endif
 
 	memset(cmd, 0, MAX_COMMAND_SIZE);
@@ -585,8 +620,8 @@
 	       (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)         ) {
 #if DEBUG
 	    if (debugging) {
-		printk(OSST_DEB_MSG "osst%d: Sleeping in onstream wait ready\n", dev);
-		printk(OSST_DEB_MSG "osst%d: Turning off debugging for a while\n", dev);
+		printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait ready\n", dev);
+		printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev);
 		debugging = 0;
 	    }
 #endif
@@ -605,15 +640,15 @@
 	if ( STp->buffer->syscall_result &&
 	     osst_write_error_recovery(STp, aSRpnt, 0) ) {
 #if DEBUG
-	    printk(OSST_DEB_MSG "osst%d: Abnormal exit from onstream wait ready\n", dev);
-printk(OSST_DEB_MSG "osst%d: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", dev,
-STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
-SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
+	    printk(OSST_DEB_MSG "osst%d:D: Abnormal exit from onstream wait ready\n", dev);
+	    printk(OSST_DEB_MSG "osst%d:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", dev,
+			STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
+			SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
 #endif
 	    return (-EIO);
 	}
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%d: Normal exit from onstream wait ready\n", dev);
+	printk(OSST_DEB_MSG "osst%d:D: Normal exit from onstream wait ready\n", dev);
 #endif
 	return 0;
 }
@@ -641,7 +676,7 @@
 #if DEBUG
 	int		dev  = TAPE_NR(STp->devt);
 
-	printk(OSST_DEB_MSG "osst%d: Reached onstream flush drive buffer (write filemark)\n", dev);
+	printk(OSST_DEB_MSG "osst%d:D: Reached onstream flush drive buffer (write filemark)\n", dev);
 #endif
 
 	memset(cmd, 0, MAX_COMMAND_SIZE);
@@ -668,10 +703,8 @@
 #if DEBUG
 	char	notyetprinted = 1;
 #endif
-	if ((minlast >= 0 && STp->ps[STp->partition].rw != ST_READING) ||
-	    (minlast <  0 && STp->ps[STp->partition].rw != ST_WRITING) )
-		printk(KERN_ERR "osst%i: waiting for frame without having initialized %s!\n",
-			       	dev, minlast<0?"write":"read");
+	if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING)
+		printk(KERN_ERR "osst%i:A: Waiting for frame without having initialized read!\n", dev);
 
 	while (time_before (jiffies, startwait + to*HZ))
 	{ 
@@ -690,7 +723,7 @@
 #if DEBUG			
 			if (debugging || jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC)
 				printk (OSST_DEB_MSG
-					"osst%i: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
+					"osst%d:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
 					dev, curr, curr+minlast, STp->first_frame_position,
 					STp->last_frame_position, STp->cur_frames,
 					result, (jiffies-startwait)/HZ, 
@@ -701,7 +734,7 @@
 #if DEBUG
 		if (jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC && notyetprinted)
 		{
-			printk (OSST_DEB_MSG "osst%i: Wait for frame %i (>%i): %i-%i %i (%i)\n",
+			printk (OSST_DEB_MSG "osst%d:D: Wait for frame %i (>%i): %i-%i %i (%i)\n",
 				dev, curr, curr+minlast, STp->first_frame_position,
 				STp->last_frame_position, STp->cur_frames, result);
 			notyetprinted--;
@@ -711,7 +744,7 @@
 		schedule_timeout (HZ / OSST_POLL_PER_SEC);
 	}
 #if DEBUG
-	printk (OSST_DEB_MSG "osst%i: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n",
+	printk (OSST_DEB_MSG "osst%d:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n",
 		dev, curr, curr+minlast, STp->first_frame_position,
 		STp->last_frame_position, STp->cur_frames,
 		(jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ);
@@ -720,9 +753,9 @@
 }
 
 /*
- * Read the next OnStream tape block at the current location
+ * Read the next OnStream tape frame at the current location
  */
-static int osst_read_block(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int timeout)
+static int osst_read_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int timeout)
 {
 	unsigned char	cmd[MAX_COMMAND_SIZE];
 	Scsi_Request  * SRpnt;
@@ -746,7 +779,7 @@
 
 #if DEBUG
 	if (debugging)
-	    printk(OSST_DEB_MSG "osst%i: Reading block from OnStream tape\n", dev);
+	    printk(OSST_DEB_MSG "osst%d:D: Reading frame from OnStream tape\n", dev);
 #endif
 	SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_READ,
 				      STp->timeout, MAX_RETRIES, TRUE);
@@ -758,11 +791,13 @@
 	    retval = 1;
 	    if (STp->read_error_frame == 0) {
 		STp->read_error_frame = STp->first_frame_position;
-		printk(OSST_DEB_MSG "osst: recording read error at %d\n", STp->read_error_frame);/*FIXME*/
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d:D: Recording read error at %d\n", dev, STp->read_error_frame);
+#endif
 	    }
 #if DEBUG
 	    if (debugging)
-		printk(OSST_DEB_MSG "osst%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
+		printk(OSST_DEB_MSG "osst%d:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
 		   dev,
 		   SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[1],
 		   SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[3],
@@ -774,16 +809,19 @@
 	    STp->first_frame_position++;
 #if DEBUG
 	if (debugging) {
-	   printk(OSST_DEB_MSG "osst%i: AUX: %c%c%c%c UpdFrCt#%d %s FrSeq#%d LogBlk#%d\n", dev,
+	   printk(OSST_DEB_MSG 
+		"osst%d:D: AUX: %c%c%c%c UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", dev,
 			aux->application_sig[0], aux->application_sig[1],
-			aux->application_sig[2], aux->application_sig[3], ntohl(aux->update_frame_cntr),
+			aux->application_sig[2], aux->application_sig[3], 
+			ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr),
 			aux->frame_type==1?"EOD":aux->frame_type==2?"MARK":
 			aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL", 
-			ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num) );
+			ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
+			ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) );
 	   if (aux->frame_type==2)
-		printk(OSST_DEB_MSG "osst%i: mark_cnt=%d, last_mark=%d, next_mark=%d\n", dev,
-			ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->next_mark_ppos));
-	   printk(OSST_DEB_MSG "osst%i: Exit read block from OnStream tape with code %d\n", dev, retval);
+		printk(OSST_DEB_MSG "osst%d:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", dev,
+			ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn));
+	   printk(OSST_DEB_MSG "osst%d:D: Exit read frame from OnStream tape with code %d\n", dev, retval);
 	}
 #endif
 	return (retval);
@@ -801,22 +839,22 @@
 
 	if (STps->rw != ST_READING) {         /* Initialize read operation */
 		if (STps->rw == ST_WRITING) {
-			osst_flush_write_buffer(STp, aSRpnt, 1);
+                        osst_flush_write_buffer(STp, aSRpnt);
 			osst_flush_drive_buffer(STp, aSRpnt);
 		}
 		STps->rw = ST_READING;
-		STp->logical_blk_in_buffer = 0;
+		STp->frame_in_buffer = 0;
 
 		/*
 		 *      Issue a read 0 command to get the OnStream drive
-		 *      read blocks into its buffer.
+                 *      read frames into its buffer.
 		 */
 		memset(cmd, 0, MAX_COMMAND_SIZE);
 		cmd[0] = READ_6;
 		cmd[1] = 1;
 
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%i: Start Read Ahead on OnStream tape\n", dev);
+		printk(OSST_DEB_MSG "osst%d:D: Start Read Ahead on OnStream tape\n", dev);
 #endif
 		SRpnt   = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_RETRIES, TRUE);
 		*aSRpnt = SRpnt;
@@ -826,7 +864,7 @@
 	return retval;
 }
 
-static int osst_get_logical_blk(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int logical_blk_num, int quiet)
+static int osst_get_logical_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int frame_seq_number, int quiet)
 {
 	ST_partstat * STps  = &(STp->ps[STp->partition]);
 	int           dev   = TAPE_NR(STp->devt);
@@ -837,16 +875,16 @@
 		      position;
 
 	/*
-	 * Search and wait for the next logical tape block
+         * Search and wait for the next logical tape frame
 	 */
 	while (1) {
 		if (cnt++ > 400) {
-			printk(KERN_WARNING "osst%d: Couldn't find logical block %d, aborting\n",
-					    dev, logical_blk_num);
+                        printk(KERN_ERR "osst%d:E: Couldn't find logical frame %d, aborting\n",
+					    dev, frame_seq_number);
 			if (STp->read_error_frame) {
 				osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0);
-#if 1 //DEBUG
-                        	printk(OSST_DEB_MSG "osst%d: Repositioning tape to bad block %d\n",
+#if DEBUG
+                        	printk(OSST_DEB_MSG "osst%d:D: Repositioning tape to bad frame %d\n",
 						    dev, STp->read_error_frame);
 #endif
 				STp->read_error_frame = 0;
@@ -855,16 +893,15 @@
 		}
 #if DEBUG
 		if (debugging)
-			printk(OSST_DEB_MSG "osst%d: Looking for block %d, attempt %d\n",
-					  dev, logical_blk_num, cnt);
+			printk(OSST_DEB_MSG "osst%d:D: Looking for frame %d, attempt %d\n",
+					  dev, frame_seq_number, cnt);
 #endif
 		if ( osst_initiate_read(STp, aSRpnt)
-		|| ( (!STp->logical_blk_in_buffer) && osst_read_block(STp, aSRpnt, 30) ) ) {
+                || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) {
 			position = osst_get_frame_position(STp, aSRpnt);
 			if (position >= 0xbae && position < 0xbb8)
 				position = 0xbb8;
 			else if (position > STp->eod_frame_ppos || ++bad == 10) {
-printk(OSST_DEB_MSG "osst%d: start again from pos %d, eod %d, bad %d\n", dev, position, STp->eod_frame_ppos, bad); /*FIXME*/
 				position = STp->read_error_frame - 1;
 			}
 			else {
@@ -872,38 +909,40 @@
 				cnt += 20;
 			}
 #if DEBUG
-			printk(OSST_DEB_MSG "osst%d: Bad block detected, positioning tape to block %d\n",
+			printk(OSST_DEB_MSG "osst%d:D: Bad frame detected, positioning tape to block %d\n",
 					 dev, position);
 #endif
 			osst_set_frame_position(STp, aSRpnt, position, 0);
 			continue;
 		}
-		if (osst_verify_frame(STp, logical_blk_num, quiet))
+		if (osst_verify_frame(STp, frame_seq_number, quiet))
 			break;
 		if (osst_verify_frame(STp, -1, quiet)) {
-			x = ntohl(STp->buffer->aux->logical_blk_num);
+			x = ntohl(STp->buffer->aux->frame_seq_num);
 			if (STp->fast_open) {
-#if 1 //DEBUG
-				printk(OSST_DEB_MSG
-				       "osst%d: Found logical block %d instead of %d after fast open\n",
-				       dev, x, logical_blk_num);
-#endif
+				printk(KERN_WARNING
+				       "osst%d:W: Found logical frame %d instead of %d after fast open\n",
+				       dev, x, frame_seq_number);
 				STp->header_ok = 0;
 				STp->read_error_frame = 0;
 				return (-EIO);
 			}
-			if (x > logical_blk_num) {
+			if (x > frame_seq_number) {
 				if (++past > 3) {
-					/* positioning backwards did not bring us to the desired block */
+					/* positioning backwards did not bring us to the desired frame */
 					position = STp->read_error_frame - 1;
 				}
-				else
+				else {
 			        	position = osst_get_frame_position(STp, aSRpnt)
-					         + logical_blk_num - x - 1;
-#if 1 //DEBUG
+					         + frame_seq_number - x - 1;
+
+					if (STp->first_frame_position >= 3000 && position < 3000)
+						position -= 10;
+				}
+#if DEBUG
                                 printk(OSST_DEB_MSG
-				       "osst%d: Found logical block %d while looking for %d: back up %d\n",
-						dev, x, logical_blk_num,
+				       "osst%d:D: Found logical frame %d while looking for %d: back up %d\n",
+						dev, x, frame_seq_number,
 					       	STp->first_frame_position - position);
 #endif
                         	osst_set_frame_position(STp, aSRpnt, position, 0);
@@ -914,22 +953,26 @@
 		}
 		if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) {
 #if DEBUG
-			printk(OSST_DEB_MSG "osst%d: Skipping config partition\n", dev);
+			printk(OSST_DEB_MSG "osst%d:D: Skipping config partition\n", dev);
 #endif
 			osst_set_frame_position(STp, aSRpnt, 0xbb8, 0);
 			cnt--;
 		}
-		STp->logical_blk_in_buffer = 0;
+		STp->frame_in_buffer = 0;
 	}
 	if (cnt > 1) {
 		STp->recover_count++;
 		STp->recover_erreg++;
+		printk(KERN_WARNING "osst%d:I: Read error at position %d recovered\n", 
+					dev, STp->read_error_frame);
  	}
-	STp->logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num);
+	STp->read_count++;
 
 #if DEBUG
 	if (debugging || STps->eof)
-		printk(OSST_DEB_MSG "osst%i: Exit get logical block (%d=>%d) from OnStream tape with code %d\n",							 dev, logical_blk_num, STp->logical_blk_num, STps->eof);
+		printk(OSST_DEB_MSG
+			"osst%d:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n",
+			dev, frame_seq_number, STp->frame_seq_number, STps->eof);
 #endif
 	STp->fast_open = FALSE;
 	STp->read_error_frame = 0;
@@ -938,60 +981,195 @@
 
 static int osst_seek_logical_blk(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int logical_blk_num)
 {
-	int  estimate;
-	int  retries = 0;
-	int  dev     = TAPE_NR(STp->devt);
-
+        ST_partstat * STps = &(STp->ps[STp->partition]);
+	int	dev        = TAPE_NR(STp->devt);
+	int	retries    = 0;
+	int	frame_seq_estimate, ppos_estimate, move;
+	
 	if (logical_blk_num < 0) logical_blk_num = 0;
-	/* FIXME -- this may not be valid for foreign formats */
-	if (logical_blk_num < 2980) estimate  = logical_blk_num + 10;
-	else			    estimate  = logical_blk_num + 20;
-
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%d: Seeking logical block %d (now at %d)\n",
-			  dev, logical_blk_num, STp->logical_blk_num);
+	printk(OSST_DEB_MSG "osst%d:D: Seeking logical block %d (now at %d, size %d%c)\n",
+				dev, logical_blk_num, STp->logical_blk_num, 
+				STp->block_size<1024?STp->block_size:STp->block_size/1024,
+				STp->block_size<1024?'b':'k');
 #endif
+	/* Do we know where we are? */
+	if (STps->drv_block >= 0) {
+		move                = logical_blk_num - STp->logical_blk_num;
+		if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
+		move               /= (OS_DATA_SIZE / STp->block_size);
+		frame_seq_estimate  = STp->frame_seq_number + move;
+	} else
+		frame_seq_estimate  = logical_blk_num * STp->block_size / OS_DATA_SIZE;
+
+	if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10;
+	else			       ppos_estimate = frame_seq_estimate + 20;
 	while (++retries < 10) {
-	   osst_set_frame_position(STp, aSRpnt, estimate, 0);
-	   if (osst_get_logical_blk(STp, aSRpnt, logical_blk_num, 1) >= 0)
-	      return 0;
-	   if (osst_get_logical_blk(STp, aSRpnt, -1, 1) < 0)
+	   if (ppos_estimate > STp->eod_frame_ppos-2) {
+	       frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate;
+	       ppos_estimate       = STp->eod_frame_ppos - 2;
+	   }
+	   if (frame_seq_estimate < 0) {
+	       frame_seq_estimate = 0;
+	       ppos_estimate      = 10;
+	   }
+	   osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0);
+	   if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) {
+	      /* we've located the estimated frame, now does it have our block? */
+	      if (logical_blk_num <  STp->logical_blk_num ||
+	          logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) {
+		 if (STps->eof == ST_FM_HIT)
+		    move = logical_blk_num < STp->logical_blk_num? -2 : 1;
+		 else {
+		    move                = logical_blk_num - STp->logical_blk_num;
+		    if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
+		    move               /= (OS_DATA_SIZE / STp->block_size);
+		 }
+#if DEBUG
+		 printk(OSST_DEB_MSG
+			"osst%d:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n",
+				dev, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, 
+				STp->logical_blk_num, logical_blk_num, move);
+#endif
+		 frame_seq_estimate += move;
+		 ppos_estimate      += move;
+		 continue;
+	      } else {
+		 STp->buffer->read_pointer  = (logical_blk_num - STp->logical_blk_num) * STp->block_size;
+		 STp->buffer->buffer_bytes -= STp->buffer->read_pointer;
+		 STp->logical_blk_num       =  logical_blk_num;
+#if DEBUG
+		 printk(OSST_DEB_MSG 
+			"osst%d:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n",
+				dev, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer, 
+				STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size, 
+				STp->block_size);
+#endif
+		 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
+		 if (STps->eof == ST_FM_HIT) {
+		     STps->drv_file++;
+		     STps->drv_block = 0;
+		 } else {
+		     STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
+					  STp->logical_blk_num -
+					     (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
+					-1;
+		 }
+		 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
+		 return 0;
+	      }
+	   }
+	   if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0)
 	      goto error;
-	   if (STp->logical_blk_num != logical_blk_num)
-	      estimate += logical_blk_num - STp->logical_blk_num;
+	   /* we are not yet at the estimated frame, adjust our estimate of its physical position */
+#if DEBUG
+	   printk(OSST_DEB_MSG "osst%d:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n", 
+			   dev, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, 
+			   STp->logical_blk_num, logical_blk_num);
+#endif
+	   if (frame_seq_estimate != STp->frame_seq_number)
+	      ppos_estimate += frame_seq_estimate - STp->frame_seq_number;
 	   else
 	      break;
 	}
 error:
-	printk(KERN_WARNING "osst%d: Couldn't seek to logical block %d (at %d), %d retries\n", 
+	printk(KERN_ERR "osst%d:E: Couldn't seek to logical block %d (at %d), %d retries\n", 
 			    dev, logical_blk_num, STp->logical_blk_num, retries);
 	return (-EIO);
 }
 
-static int osst_seek_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int frame)
+/* The values below are based on the OnStream frame payload size of 32K == 2**15,
+ * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block
+ * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions
+ * inside each frame. Finaly, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1.
+ */
+#define OSST_FRAME_SHIFT  6
+#define OSST_SECTOR_SHIFT 9
+#define OSST_SECTOR_MASK  0x03F
+
+static int osst_get_sector(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
+{
+	int	sector;
+#if DEBUG
+	int	dev = TAPE_NR(STp->devt);
+	
+	printk(OSST_DEB_MSG 
+		"osst%d:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n",
+		dev, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
+		STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block, 
+		STp->ps[STp->partition].rw == ST_WRITING?'w':'r',
+		STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes:
+		STp->buffer->read_pointer, STp->ps[STp->partition].eof);
+#endif
+	/* do we know where we are inside a file? */
+	if (STp->ps[STp->partition].drv_block >= 0) {
+		sector = (STp->frame_in_buffer ? STp->first_frame_position-1 :
+				STp->first_frame_position) << OSST_FRAME_SHIFT;
+		if (STp->ps[STp->partition].rw == ST_WRITING)
+		       	sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
+		else
+	       		sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
+	} else {
+		sector = osst_get_frame_position(STp, aSRpnt);
+		if (sector > 0)
+			sector <<= OSST_FRAME_SHIFT;
+	}
+	return sector;
+}
+
+static int osst_seek_sector(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int sector)
 {
-	ST_partstat   * STps = &(STp->ps[STp->partition]);
-	int		r;
+        ST_partstat   * STps   = &(STp->ps[STp->partition]);
+	int		frame  = sector >> OSST_FRAME_SHIFT,
+			offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT, 
+			r;
+#if DEBUG
+	int		dev    = TAPE_NR(STp->devt);
 
+	printk(OSST_DEB_MSG "osst%d:D: Seeking sector %d in frame %d at offset %d\n",
+				dev, sector, frame, offset);
+#endif
 	if (frame < 0 || frame >= STp->capacity) return (-ENXIO);
 
 	if (frame <= STp->first_data_ppos) {
-		STp->logical_blk_num = STps->drv_file = STps->drv_block = 0;
+		STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0;
 		return (osst_set_frame_position(STp, aSRpnt, frame, 0));
 	}
-	r = osst_set_frame_position(STp, aSRpnt, frame-1, 0);
+	r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0);
 	if (r < 0) return r;
 
-	r = osst_get_logical_blk(STp, aSRpnt, -1, 1);
+	r = osst_get_logical_frame(STp, aSRpnt, -1, 1);
 	if (r < 0) return r;
 
-	if (osst_get_frame_position(STp, aSRpnt) != frame) return (-EIO);
+	if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO);
 
-	STp->logical_blk_num++;
-	STp->logical_blk_in_buffer = 0;
-	STps->drv_file  = htonl(STp->buffer->aux->filemark_cnt);
-	STps->drv_block = -1;
-	STps->eof       = ST_NOEOF;
+	if (offset) {
+		STp->logical_blk_num      += offset / STp->block_size;
+		STp->buffer->read_pointer  = offset;
+		STp->buffer->buffer_bytes -= offset;
+	} else {
+		STp->frame_seq_number++;
+		STp->frame_in_buffer       = 0;
+		STp->logical_blk_num      += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
+		STp->buffer->buffer_bytes  = STp->buffer->read_pointer = 0;
+	}
+	STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
+	if (STps->eof == ST_FM_HIT) {
+		STps->drv_file++;
+		STps->drv_block = 0;
+	} else {
+		STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
+				    STp->logical_blk_num -
+					(STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
+				  -1;
+	}
+	STps->eof       = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
+#if DEBUG
+	printk(OSST_DEB_MSG 
+		"osst%d:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n",
+		dev, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
+		STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof);
+#endif
 	return 0;
 }
 
@@ -999,38 +1177,43 @@
  * Read back the drive's internal buffer contents, as a part
  * of the write error recovery mechanism for old OnStream
  * firmware revisions.
+ * Precondition for this function to work: all frames in the
+ * drive's buffer must be of one type (DATA, MARK or EOD)!
  */
 static int osst_read_back_buffer_and_rewrite(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
-					unsigned int block, unsigned int skip, int pending)
+					unsigned int frame, unsigned int skip, int pending)
 {
 	Scsi_Request  * SRpnt = * aSRpnt;
 	unsigned char * buffer, * p;
 	unsigned char	cmd[MAX_COMMAND_SIZE];
-	int             frames, flag, new_block, i, logical_blk_num;
-	int		dev  = TAPE_NR(STp->devt);
-	long		startwait = jiffies;
+	int             flag, new_frame, i;
+	int             nframes          = STp->cur_frames;
+	int             blks_per_frame   = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
+	int             frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num)
+						- (nframes + pending - 1);
+	int             logical_blk_num  = ntohl(STp->buffer->aux->logical_blk_num) 
+						- (nframes + pending - 1) * blks_per_frame;
+	int		dev              = TAPE_NR(STp->devt);
+	long		startwait        = jiffies;
 #if DEBUG
-	int		dbg = debugging;
+	int		dbg              = debugging;
 #endif
 
-	frames = STp->cur_frames;
-	if ((buffer = (unsigned char *)vmalloc((frames + pending) * OS_DATA_SIZE)) == NULL)
+	if ((buffer = (unsigned char *)vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL)
 		return (-EIO);
 
-	logical_blk_num = STp->logical_blk_num - frames - pending;
-	printk(KERN_INFO "osst%d: Reading back %d frames from drive buffer%s\n",
-			 dev, frames, pending?" and one that was pending":"");
-
-	if (pending) {
-		osst_copy_from_buffer(STp->buffer, (p = &buffer[frames * OS_DATA_SIZE]));
-//		memcpy((p = &buffer[frames * OS_DATA_SIZE]), STp->buffer->b_data, OS_DATA_SIZE);
+	printk(KERN_INFO "osst%d:I: Reading back %d frames from drive buffer%s\n",
+			 dev, nframes, pending?" and one that was pending":"");
+
+	osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE]));
 #if DEBUG
-		if (debugging)
-			printk(OSST_DEB_MSG "osst%d: Pending logical block %d, data %x %x %x %x\n",
-					  dev, logical_blk_num + frames, p[0], p[1], p[2], p[3]);
+	if (pending && debugging)
+		printk(OSST_DEB_MSG "osst%d:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n",
+				dev, frame_seq_number + nframes,
+			       	logical_blk_num + nframes * blks_per_frame,
+			       	p[0], p[1], p[2], p[3]);
 #endif
-	}
-	for (i = 0, p = buffer; i < frames; i++, p += OS_DATA_SIZE) {
+	for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) {
 
 		memset(cmd, 0, MAX_COMMAND_SIZE);
 		cmd[0] = 0x3C;		/* Buffer Read           */
@@ -1041,63 +1224,63 @@
 		SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_READ,
 					    STp->timeout, MAX_RETRIES, TRUE);
 	
-		if ((STp->buffer)->syscall_result) {
-			printk(KERN_ERR "osst%d: Failed to read block back from OnStream buffer\n", dev);
+		if ((STp->buffer)->syscall_result || !SRpnt) {
+			printk(KERN_ERR "osst%d:E: Failed to read frame back from OnStream buffer\n", dev);
 			vfree((void *)buffer);
 			*aSRpnt = SRpnt;
 			return (-EIO);
 		}
 		osst_copy_from_buffer(STp->buffer, p);
-//		memcpy(p, STp->buffer->b_data, OS_DATA_SIZE);
 #if DEBUG
 		if (debugging)
-			printk(OSST_DEB_MSG "osst%d: Read back logical block %d, data %x %x %x %x\n",
-					  dev, logical_blk_num + i, p[0], p[1], p[2], p[3]);
+			printk(OSST_DEB_MSG "osst%d:D: Read back logical frame %d, data %02x %02x %02x %02x\n",
+					  dev, frame_seq_number + i, p[0], p[1], p[2], p[3]);
 #endif
 	}
 	*aSRpnt = SRpnt;
 	osst_get_frame_position(STp, aSRpnt);
 
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%d: Frames left in buffer: %d\n", dev, STp->cur_frames);
+	printk(OSST_DEB_MSG "osst%d:D: Frames left in buffer: %d\n", dev, STp->cur_frames);
 #endif
 	/* Write synchronously so we can be sure we're OK again and don't have to recover recursively */
-	/* In the header we don't actually re-write the blocks that fail, just the ones after them */
+	/* In the header we don't actually re-write the frames that fail, just the ones after them */
 
-	for (flag=1, new_block=block, p=buffer, i=0; i < frames + pending; ) {
+	for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) {
 
 		if (flag) {
 			if (STp->write_type == OS_WRITE_HEADER) {
 				i += skip;
 				p += skip * OS_DATA_SIZE;
 			}
-			else if (new_block < 2990 && new_block+skip+frames+pending >= 2990)
-				new_block = 3000-i;
+			else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990)
+				new_frame = 3000-i;
 			else
-				new_block += skip;
+				new_frame += skip;
 #if DEBUG
-			printk(OSST_DEB_MSG "osst%d: Position to frame %d, write lblk %d\n",
-						dev, new_block+i, logical_blk_num+i); /* FIXME var blk sz */
+			printk(OSST_DEB_MSG "osst%d:D: Position to frame %d, write fseq %d\n",
+						dev, new_frame+i, frame_seq_number+i);
 #endif
-			osst_set_frame_position(STp, aSRpnt, new_block + i, 0);
+			osst_set_frame_position(STp, aSRpnt, new_frame + i, 0);
 			osst_wait_ready(STp, aSRpnt, 60);
 			osst_get_frame_position(STp, aSRpnt);
 			SRpnt = * aSRpnt;
 
-			if (new_block > block + 1000) {
-				printk(KERN_ERR "osst%d: Failed to find valid tape media\n", dev);
+			if (new_frame > frame + 1000) {
+				printk(KERN_ERR "osst%d:E: Failed to find writable tape media\n", dev);
 				vfree((void *)buffer);
 				return (-EIO);
 			}
 			flag = 0;
-			if ( i >= frames + pending ) break;
+			if ( i >= nframes + pending ) break;
 		}
 		osst_copy_to_buffer(STp->buffer, p);
-//		memcpy(STp->buffer->b_data, p, OS_DATA_SIZE);
 		/*
 		 * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type!
 		 */
-		osst_init_aux(STp, STp->buffer->aux->frame_type, logical_blk_num+i );
+		osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i,
+			       	logical_blk_num + i*blks_per_frame,
+			       	ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame);
 		memset(cmd, 0, MAX_COMMAND_SIZE);
 		cmd[0] = WRITE_6;
 		cmd[1] = 1;
@@ -1105,7 +1288,10 @@
 
 #if DEBUG
 		if (debugging)
-			printk(OSST_DEB_MSG "osst%d: About to attempt to write to frame %d\n", dev, new_block+i);
+			printk(OSST_DEB_MSG
+				"osst%d:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n",
+				dev, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame,
+				p[0], p[1], p[2], p[3]);
 #endif
 		SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE,
 					    STp->timeout, MAX_WRITE_RETRIES, TRUE);
@@ -1116,9 +1302,9 @@
 			p += OS_DATA_SIZE; i++;
 
 			/* if we just sent the last frame, wait till all successfully written */
-			if ( i == frames + pending ) {
+			if ( i == nframes + pending ) {
 #if DEBUG
-				printk(OSST_DEB_MSG "osst%d: Check re-write successful\n", dev);
+				printk(OSST_DEB_MSG "osst%d:D: Check re-write successful\n", dev);
 #endif
 				memset(cmd, 0, MAX_COMMAND_SIZE);
 				cmd[0] = WRITE_FILEMARKS;
@@ -1127,8 +1313,8 @@
 							    STp->timeout, MAX_WRITE_RETRIES, TRUE);
 #if DEBUG
 				if (debugging) {
-					printk(OSST_DEB_MSG "osst%d: Sleeping in re-write wait ready\n", dev);
-					printk(OSST_DEB_MSG "osst%d: Turning off debugging for a while\n", dev);
+					printk(OSST_DEB_MSG "osst%d:D: Sleeping in re-write wait ready\n", dev);
+					printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev);
 					debugging = 0;
 				}
 #endif
@@ -1153,44 +1339,47 @@
 				}
 #if DEBUG
 				debugging = dbg;
-				printk(OSST_DEB_MSG "osst%d: Wait re-write finished\n", dev);
+				printk(OSST_DEB_MSG "osst%d:D: Wait re-write finished\n", dev);
 #endif
 			}
 		}
+		*aSRpnt = SRpnt;
 		if (flag) {
 			if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) == 13 &&
 			     SRpnt->sr_sense_buffer[12]         ==  0 &&
 			     SRpnt->sr_sense_buffer[13]         ==  2) {
-				printk(KERN_ERR "osst%d: Volume overflow in write error recovery\n", dev);
+				printk(KERN_ERR "osst%d:E: Volume overflow in write error recovery\n", dev);
 				vfree((void *)buffer);
 				return (-EIO);			/* hit end of tape = fail */
 			}
 			i = ((SRpnt->sr_sense_buffer[3] << 24) |
 			     (SRpnt->sr_sense_buffer[4] << 16) |
 			     (SRpnt->sr_sense_buffer[5] <<  8) |
-			      SRpnt->sr_sense_buffer[6]        ) - new_block;
+			      SRpnt->sr_sense_buffer[6]        ) - new_frame;
 			p = &buffer[i * OS_DATA_SIZE];
 #if DEBUG
-			printk(OSST_DEB_MSG "osst%d: Additional write error at %d\n", dev, new_block+i);
+			printk(OSST_DEB_MSG "osst%d:D: Additional write error at %d\n", dev, new_frame+i);
 #endif
 			osst_get_frame_position(STp, aSRpnt);
 #if DEBUG
-			printk(OSST_DEB_MSG "osst%d: reported frame positions: host = %d, tape = %d\n",
+			printk(OSST_DEB_MSG "osst%d:D: reported frame positions: host = %d, tape = %d\n",
 					  dev, STp->first_frame_position, STp->last_frame_position);
 #endif
 		}
-		*aSRpnt = SRpnt;
 	}    
+	if (!pending)
+		osst_copy_to_buffer(STp->buffer, p);	/* so buffer content == at entry in all cases */
 	vfree((void *)buffer);
 	return 0;
 }
 
 static int osst_reposition_and_retry(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
-					unsigned int block, unsigned int skip, int pending)
+					unsigned int frame, unsigned int skip, int pending)
 {
 	unsigned char	cmd[MAX_COMMAND_SIZE];
-	Scsi_Request  * SRpnt     = * aSRpnt;
+	Scsi_Request  * SRpnt;
 	int		dev       = TAPE_NR(STp->devt);
+	int		expected  = 0;
 	int		attempts  = 1000 / skip;
 	int		flag      = 1;
 	long		startwait = jiffies;
@@ -1203,23 +1392,24 @@
 #if DEBUG
 			debugging = dbg;
 #endif
-			if (block < 2990 && block+skip+STp->cur_frames+pending >= 2990)
-				block = 3000-skip;
+			if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990)
+				frame = 3000-skip;
+			expected = frame+skip+STp->cur_frames+pending;
 #if DEBUG
-			printk(OSST_DEB_MSG "osst%d: Position to frame %d, re-write from lblk %d\n",
-					  dev, block+skip, STp->logical_blk_num-STp->cur_frames-pending);
+			printk(OSST_DEB_MSG "osst%d:D: Position to fppos %d, re-write from fseq %d\n",
+					  dev, frame+skip, STp->frame_seq_number-STp->cur_frames-pending);
 #endif
-			osst_set_frame_position(STp, aSRpnt, block + skip, 1);
+			osst_set_frame_position(STp, aSRpnt, frame + skip, 1);
 			flag = 0;
 			attempts--;
 		}
 		if (osst_get_frame_position(STp, aSRpnt) < 0) {		/* additional write error */
 #if DEBUG
-			printk(OSST_DEB_MSG "osst%d: Addl error, host %d, tape %d, buffer %d\n",
+			printk(OSST_DEB_MSG "osst%d:D: Addl error, host %d, tape %d, buffer %d\n",
 					  dev, STp->first_frame_position,
 					  STp->last_frame_position, STp->cur_frames);
 #endif
-			block = STp->last_frame_position;
+			frame = STp->last_frame_position;
 			flag = 1;
 			continue;
 		}
@@ -1230,19 +1420,19 @@
 			cmd[1] = 1;
 			cmd[4] = 1;
 #if DEBUG
-			printk(OSST_DEB_MSG "osst%d: About to write pending lblk %d at frame %d\n",
-					  dev, STp->logical_blk_num-1, STp->first_frame_position);
+			printk(OSST_DEB_MSG "osst%d:D: About to write pending fseq %d at fppos %d\n",
+					  dev, STp->frame_seq_number-1, STp->first_frame_position);
 #endif
-			SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE,
-						    STp->timeout, MAX_WRITE_RETRIES, TRUE);
+			SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE,
+						      STp->timeout, MAX_WRITE_RETRIES, TRUE);
 			*aSRpnt = SRpnt;
 
 			if (STp->buffer->syscall_result) {		/* additional write error */
 				if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) == 13 &&
 				     SRpnt->sr_sense_buffer[12]         ==  0 &&
 				     SRpnt->sr_sense_buffer[13]         ==  2) {
-					printk(OSST_DEB_MSG
-					       "osst%d: Volume overflow in write error recovery\n",
+					printk(KERN_ERR
+					       "osst%d:E: Volume overflow in write error recovery\n",
 					       dev);
 					break;				/* hit end of tape = fail */
 				}
@@ -1256,20 +1446,25 @@
 		if (STp->cur_frames == 0) {
 #if DEBUG
 			debugging = dbg;
-			printk(OSST_DEB_MSG "osst%d: Wait re-write finished\n", dev);
+			printk(OSST_DEB_MSG "osst%d:D: Wait re-write finished\n", dev);
 #endif
+			if (STp->first_frame_position != expected) {
+				printk(KERN_ERR "osst%d:A: Actual position %d - expected %d\n", 
+						dev, STp->first_frame_position, expected);
+				return (-EIO);
+			}
 			return 0;
 		}
 #if DEBUG
 		if (debugging) {
-			printk(OSST_DEB_MSG "osst%d: Sleeping in re-write wait ready\n", dev);
-			printk(OSST_DEB_MSG "osst%d: Turning off debugging for a while\n", dev);
+			printk(OSST_DEB_MSG "osst%d:D: Sleeping in re-write wait ready\n", dev);
+			printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev);
 			debugging = 0;
 		}
 #endif
 		schedule_timeout(HZ / 10);
 	}
-	printk(KERN_ERR "osst%d: Failed to find valid tape media\n", dev);
+	printk(KERN_ERR "osst%d:E: Failed to find valid tape media\n", dev);
 #if DEBUG
 	debugging = dbg;
 #endif
@@ -1287,7 +1482,7 @@
 	int            dev    = TAPE_NR(STp->devt);
 	int            retval = 0;
 	int            rw_state;
-	unsigned int   block, skip;
+	unsigned int  frame, skip;
 
 	rw_state = STps->rw;
 
@@ -1295,54 +1490,56 @@
 	  || SRpnt->sr_sense_buffer[12]         != 12
 	  || SRpnt->sr_sense_buffer[13]         != 0) {
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%d: Write error recovery cannot handle %02x:%02x:%02x\n",
-			dev, SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
+		printk(OSST_DEB_MSG "osst%d:D: Write error recovery cannot handle %02x:%02x:%02x\n", dev,
+			SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
 #endif
 		return (-EIO);
 	}
-	block =	(SRpnt->sr_sense_buffer[3] << 24) |
+	frame =	(SRpnt->sr_sense_buffer[3] << 24) |
 		(SRpnt->sr_sense_buffer[4] << 16) |
 		(SRpnt->sr_sense_buffer[5] <<  8) |
 		 SRpnt->sr_sense_buffer[6];
 	skip  =  SRpnt->sr_sense_buffer[9];
  
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%d: Detected physical bad block at %u, advised to skip %d\n", dev, block, skip);
+	printk(OSST_DEB_MSG "osst%d:D: Detected physical bad frame at %u, advised to skip %d\n", dev, frame, skip);
 #endif
 	osst_get_frame_position(STp, aSRpnt);
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%d: reported frame positions: host = %d, tape = %d\n",
+	printk(OSST_DEB_MSG "osst%d:D: reported frame positions: host = %d, tape = %d\n",
 			dev, STp->first_frame_position, STp->last_frame_position);
 #endif
 	switch (STp->write_type) {
 	   case OS_WRITE_DATA:
 	   case OS_WRITE_EOD:
 	   case OS_WRITE_NEW_MARK:
-		printk(KERN_WARNING "osst%d: Relocating %d buffered logical blocks to physical block %u\n",
-			dev, STp->cur_frames, block + skip);
+		printk(KERN_WARNING 
+			"osst%d:I: Relocating %d buffered logical frames from position %u to %u\n",
+			dev, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip);
 		if (STp->os_fw_rev >= 10600)
-			retval = osst_reposition_and_retry(STp, aSRpnt, block, skip, pending);
+			retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending);
 		else
-			retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, block, skip, pending);
+			retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending);
+		printk(KERN_WARNING "osst%d:I: Write error%srecovered\n", dev, retval?" not ":" ");
 		break;
 	   case OS_WRITE_LAST_MARK:
-		printk(KERN_ERR "osst%d: Bad block in update last marker, fatal\n", dev);
-		osst_set_frame_position(STp, aSRpnt, block + STp->cur_frames + pending, 0);
+		printk(KERN_ERR "osst%d:E: Bad frame in update last marker, fatal\n", dev);
+		osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
 		retval = -EIO;
 		break;
 	   case OS_WRITE_HEADER:
-		printk(KERN_WARNING "osst%d: Bad block in header partition, skipped\n", dev);
-		retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, block, 1, pending);
+		printk(KERN_WARNING "osst%d:I: Bad frame in header partition, skipped\n", dev);
+		retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending);
 		break;
 	   default:
-		printk(KERN_WARNING "osst%d: Bad block in filler, ignored\n", dev);
-		osst_set_frame_position(STp, aSRpnt, block + STp->cur_frames + pending, 0);
+		printk(KERN_INFO "osst%d:I: Bad frame in filler, ignored\n", dev);
+		osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
 	}
 	osst_get_frame_position(STp, aSRpnt);
 #if DEBUG
-	printk(KERN_ERR "osst%d: Positioning complete, cur_frames %d, pos %d, tape pos %d\n", 
+	printk(OSST_DEB_MSG "osst%d:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n", 
 			dev, STp->cur_frames, STp->first_frame_position, STp->last_frame_position);
-	printk(OSST_DEB_MSG "osst%d: next logical block to write: %d\n", dev, STp->logical_blk_num);
+	printk(OSST_DEB_MSG "osst%d:D: next logical frame to write: %d\n", dev, STp->logical_blk_num);
 #endif
 	if (retval == 0) {
 		STp->recover_count++;
@@ -1360,10 +1557,12 @@
 	int     last_mark_ppos = -1;
 
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%d: Reached space_over_filemarks_backwards %d %d\n", dev, mt_op, mt_count);
+	printk(OSST_DEB_MSG "osst%d:D: Reached space_over_filemarks_backwards %d %d\n", dev, mt_op, mt_count);
+#endif
+	if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks_bwd\n", dev);
 #endif
-	if (osst_get_logical_blk(STp, aSRpnt, -1, 0) < 0) {
-		printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks_bwd\n", dev);
 		return -EIO;
 	}
 	if (STp->linux_media_version >= 4) {
@@ -1379,12 +1578,12 @@
 		    STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos)
 
 			last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]);
-#if 1 //DEBUG
+#if DEBUG
 		if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX)
-			printk(OSST_DEB_MSG "osst%i: Filemark lookup fail due to %s\n", dev,
+			printk(OSST_DEB_MSG "osst%d:D: Filemark lookup fail due to %s\n", dev,
 			       STp->header_cache == NULL?"lack of header cache":"count out of range");
 		else
-			printk(OSST_DEB_MSG "osst%i: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
+			printk(OSST_DEB_MSG "osst%d:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
 				dev, cnt,
 				((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
 				 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] ==
@@ -1393,22 +1592,28 @@
 #endif
 		if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
 			osst_set_frame_position(STp, aSRpnt, last_mark_ppos, 0);
-			if (osst_get_logical_blk(STp, aSRpnt, -1, 0) < 0) {
-				printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks\n", dev);
+			if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+				printk(OSST_DEB_MSG 
+					"osst%d:D: Couldn't get logical blk num in space_filemarks\n", dev);
+#endif
 				return (-EIO);
 			}
 			if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-				printk(KERN_INFO "osst%i: Expected to find marker at block %d, not found\n",
+				printk(KERN_WARNING "osst%d:W: Expected to find marker at ppos %d, not found\n",
 						 dev, last_mark_ppos);
 				return (-EIO);
 			}
 			if (mt_op == MTBSFM) {
-				STp->logical_blk_num++;
-				STp->logical_blk_in_buffer = 0;
+				STp->frame_seq_number++;
+				STp->frame_in_buffer  = 0;
+				STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
 			}
 			return 0;
 		}
-		printk(KERN_INFO "osst%i: Reverting to scan filemark backwards\n", dev);
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d:D: Reverting to scan filemark backwards\n", dev);
+#endif
 	}
 	cnt = 0;
 	while (cnt != mt_count) {
@@ -1416,22 +1621,26 @@
 		if (last_mark_ppos == -1)
 			return (-EIO);
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%i: Positioning to last mark at %d\n", dev, last_mark_ppos);
+		printk(OSST_DEB_MSG "osst%d:D: Positioning to last mark at %d\n", dev, last_mark_ppos);
 #endif
 		osst_set_frame_position(STp, aSRpnt, last_mark_ppos, 0);
 		cnt++;
-		if (osst_get_logical_blk(STp, aSRpnt, -1, 0) < 0) {
-			printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks\n", dev);
+		if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n", dev);
+#endif
 			return (-EIO);
 		}
 		if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-			printk(KERN_INFO "osst%i: Expected to find marker at block %d, not found\n", dev, last_mark_ppos);
+			printk(KERN_WARNING "osst%d:W: Expected to find marker at ppos %d, not found\n",
+					 dev, last_mark_ppos);
 			return (-EIO);
 		}
 	}
 	if (mt_op == MTBSFM) {
-		STp->logical_blk_num++;
-		STp->logical_blk_in_buffer = 0;
+		STp->frame_seq_number++;
+		STp->frame_in_buffer  = 0;
+		STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
 	}
 	return 0;
 }
@@ -1444,30 +1653,34 @@
 static int osst_space_over_filemarks_forward_slow(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
 								     int mt_op, int mt_count)
 {
-	int	dev = TAPE_NR(STp->devt);
 	int	cnt = 0;
+#if DEBUG
+	int	dev = TAPE_NR(STp->devt);
 
+	printk(OSST_DEB_MSG "osst%d:D: Reached space_over_filemarks_forward_slow %d %d\n", dev, mt_op, mt_count);
+#endif
+	if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%d: Reached space_over_filemarks_forward_slow %d %d\n", dev, mt_op, mt_count);
+		printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks_fwd\n", dev);
 #endif
-	if (osst_get_logical_blk(STp, aSRpnt, -1, 0) < 0) {
-		printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks_fwd\n", dev);
 		return (-EIO);
 	}
 	while (1) {
-		if (osst_get_logical_blk(STp, aSRpnt, -1, 0) < 0) {
-			printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks\n", dev);
+		if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n", dev);
+#endif
 			return (-EIO);
 		}
 		if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
 			cnt++;
 		if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
 #if DEBUG
-			printk(OSST_DEB_MSG "osst%i: space_fwd: EOD reached\n", dev);
+			printk(OSST_DEB_MSG "osst%d:D: space_fwd: EOD reached\n", dev);
 #endif
 			if (STp->first_frame_position > STp->eod_frame_ppos+1) {
 #if DEBUG
-				printk(OSST_DEB_MSG "osst%i: EOD position corrected (%d=>%d)\n",
+				printk(OSST_DEB_MSG "osst%d:D: EOD position corrected (%d=>%d)\n",
 					       	dev, STp->eod_frame_ppos, STp->first_frame_position-1);
 #endif
 				STp->eod_frame_ppos = STp->first_frame_position-1;
@@ -1476,11 +1689,12 @@
 		}
 		if (cnt == mt_count)
 			break;
-		STp->logical_blk_in_buffer = 0;
+		STp->frame_in_buffer = 0;
 	}
 	if (mt_op == MTFSF) {
-		STp->logical_blk_num++;
-		STp->logical_blk_in_buffer = 0;
+		STp->frame_seq_number++;
+		STp->frame_in_buffer  = 0;
+		STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
 	}
 	return 0;
 }
@@ -1496,10 +1710,12 @@
 		next_mark_ppos = -1;
 
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%d: Reached space_over_filemarks_forward_fast %d %d\n", dev, mt_op, mt_count);
+	printk(OSST_DEB_MSG "osst%d:D: Reached space_over_filemarks_forward_fast %d %d\n", dev, mt_op, mt_count);
+#endif
+	if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks_fwd\n", dev);
 #endif
-	if (osst_get_logical_blk(STp, aSRpnt, -1, 0) < 0) {
-		printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks_fwd\n", dev);
 		return (-EIO);
 	}
 
@@ -1516,33 +1732,39 @@
 		     (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos)))
 
 			next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]);
-#if 1 //DEBUG
+#if DEBUG
 		if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX)
-			printk(OSST_DEB_MSG "osst%i: Filemark lookup fail due to %s\n", dev,
+			printk(OSST_DEB_MSG "osst%d:D: Filemark lookup fail due to %s\n", dev,
 			       STp->header_cache == NULL?"lack of header cache":"count out of range");
 		else
-			printk(OSST_DEB_MSG "osst%i: Filemark lookup: prev mark %d (%s), skip %d to %d\n", dev, cnt,
+			printk(OSST_DEB_MSG "osst%d:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
+			       dev, cnt,
 			       ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
 				(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] ==
 					 STp->buffer->aux->last_mark_ppos))?"match":"error",
 			       mt_count, next_mark_ppos);
 #endif
 		if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) {
-			printk(KERN_INFO "osst%i: Reverting to slow filemark space\n", dev);
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%d:D: Reverting to slow filemark space\n", dev);
+#endif
 			return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
 		} else {
 			osst_set_frame_position(STp, aSRpnt, next_mark_ppos, 0);
-			if (osst_get_logical_blk(STp, aSRpnt, -1, 0) < 0) {
-				printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks\n", dev);
+			if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+				printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n",
+						 dev);
+#endif
 				return (-EIO);
 			}
 			if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-				printk(KERN_INFO "osst%i: Expected to find marker at block %d, not found\n",
+				printk(KERN_WARNING "osst%d:W: Expected to find marker at ppos %d, not found\n",
 						 dev, next_mark_ppos);
 				return (-EIO);
 			}
 			if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) {
-				printk(KERN_INFO "osst%i: Expected to find marker %d at block %d, not %d\n",
+				printk(KERN_WARNING "osst%d:W: Expected to find marker %d at ppos %d, not %d\n",
 						 dev, cnt+mt_count, next_mark_ppos,
 						 ntohl(STp->buffer->aux->filemark_cnt));
        				return (-EIO);
@@ -1557,24 +1779,28 @@
 				break;
 			if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
 #if DEBUG
-				printk(OSST_DEB_MSG "osst%i: space_fwd: EOD reached\n", dev);
+				printk(OSST_DEB_MSG "osst%d:D: space_fwd: EOD reached\n", dev);
 #endif
 				return (-EIO);
 			}
 			if (ntohl(STp->buffer->aux->filemark_cnt) == 0) {
 				if (STp->first_mark_ppos == -1) {
-					printk(KERN_INFO "osst%i: Reverting to slow filemark space\n", dev);
+#if DEBUG
+					printk(OSST_DEB_MSG "osst%d:D: Reverting to slow filemark space\n", dev);
+#endif
 					return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
 				}
 				osst_set_frame_position(STp, aSRpnt, STp->first_mark_ppos, 0);
-				if (osst_get_logical_blk(STp, aSRpnt, -1, 0) < 0) {
-					printk(KERN_INFO
-					       "osst%i: Couldn't get logical blk num in space_filemarks_fwd_fast\n",
+				if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+					printk(OSST_DEB_MSG
+					       "osst%d:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n",
 					       dev);
+#endif
 					return (-EIO);
 				}
 				if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-					printk(KERN_INFO "osst%i: Expected to find filemark at %d\n",
+					printk(KERN_WARNING "osst%d:W: Expected to find filemark at %d\n",
 							 dev, STp->first_mark_ppos);
 					return (-EIO);
 				}
@@ -1588,28 +1814,35 @@
 		while (cnt != mt_count) {
 			next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos);
 			if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) {
-				printk(KERN_INFO "osst%i: Reverting to slow filemark space\n", dev);
+#if DEBUG
+				printk(OSST_DEB_MSG "osst%d:D: Reverting to slow filemark space\n", dev);
+#endif
 				return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt);
 			}
 #if DEBUG
-			else printk(OSST_DEB_MSG "osst%i: Positioning to next mark at %d\n", dev, next_mark_ppos);
+			else printk(OSST_DEB_MSG "osst%d:D: Positioning to next mark at %d\n", dev, next_mark_ppos);
 #endif
 			osst_set_frame_position(STp, aSRpnt, next_mark_ppos, 0);
 			cnt++;
-			if (osst_get_logical_blk(STp, aSRpnt, -1, 0) < 0) {
-				printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks\n", dev);
+			if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+				printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n",
+						 dev);
+#endif
 				return (-EIO);
 			}
 			if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-				printk(KERN_INFO "osst%i: Expected to find marker at block %d, not found\n",
+				printk(KERN_WARNING "osst%d:W: Expected to find marker at ppos %d, not found\n",
 						 dev, next_mark_ppos);
 				return (-EIO);
 			}
 		}
 	}
-	if (mt_op == MTFSF) 
-		STp->logical_blk_num++;
-		STp->logical_blk_in_buffer = 0;
+	if (mt_op == MTFSF) {
+		STp->frame_seq_number++;
+		STp->frame_in_buffer  = 0;
+		STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
+	}
 	return 0;
 }
 
@@ -1639,75 +1872,22 @@
 	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries;
 
 	if (debugging)
-	    printk(OSST_DEB_MSG "osst%i: Setting number of retries on OnStream tape to %d\n", dev, retries);
+	    printk(OSST_DEB_MSG "osst%d:D: Setting number of retries on OnStream tape to %d\n", dev, retries);
 
 	SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE);
 	*aSRpnt = SRpnt;
 
 	if ((STp->buffer)->syscall_result)
-	    printk (KERN_ERR "osst%d: Couldn't set retries to %d\n", dev, retries);
+	    printk (KERN_ERR "osst%d:D: Couldn't set retries to %d\n", dev, retries);
 }
 #endif
 
-#if 0
-static void osst_update_markers(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int last_mark_ppos, int this_mark_ppos)
-{
-	int           dev = TAPE_NR(STp->devt);
-	int	      frame,
-		      reslt;
-
-	if (STp->raw) return;
-
-	STp->last_mark_ppos = this_mark_ppos;
-	if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX)
-		STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos);
-	if (STp->filemark_cnt++ == 0)
-		STp->first_mark_ppos = this_mark_ppos;
-
-	if (STp->linux_media_version >= 4) return;
-	if (last_mark_ppos == -1)          return;
-
-	STp->write_type = OS_WRITE_LAST_MARK;
-	frame = osst_get_frame_position(STp, aSRpnt);
-#if DEBUG
-	printk(OSST_DEB_MSG "osst%i: Update last_marker at frame %d\n", dev, last_mark_addr);
-	printk(OSST_DEB_MSG "osst%i: current position %d, lblk %d, tape blk %d\n",
-			  dev, frame, STp->logical_blk_num, STp->last_frame_position);
-#endif
-	osst_set_frame_position(STp, aSRpnt, last_mark_ppos, 0);
-	osst_initiate_read (STp, aSRpnt);
-	reslt = osst_read_block(STp, aSRpnt, 180);
-
-	if (reslt) {
-		printk(KERN_WARNING "osst%i: couldn't read last marker\n", dev);
-		osst_set_frame_position(STp, aSRpnt, frame, 0);
-		return;
-	}
-	if (STp->buffer->aux->frame_type  != OS_FRAME_TYPE_MARKER) {
-		printk(KERN_WARNING "osst%i: expected marker at addr %d\n", dev, last_mark_ppos);
-		osst_set_frame_position(STp, aSRpnt, frame, 0);
-		return;
-	}
-#if DEBUG
-	printk(OSST_DEB_MSG "osst%i: writing back marker\n", dev);
-#endif
-	STp->buffer->aux->next_mark_ppos = htonl(this_mark_ppos);
-	osst_set_frame_position(STp, aSRpnt, last_mark_ppos, 0);
-	STp->dirty = 1;
-	if (osst_flush_write_buffer(STp, aSRpnt, 0) ||
-	    osst_flush_drive_buffer(STp, aSRpnt)     ) {
-		printk(KERN_WARNING "osst%i: couldn't write marker back at addr %d\n", dev, last_mark_ppos);
-	}
-	osst_set_frame_position(STp, aSRpnt, frame, 0);	
-
-	return; /* FIXME -- errors should go back to user space */
-}
-#endif
 
 static int osst_write_filemark(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
 {
 	int	result;
-	int	this_mark_ppos;
+	int	this_mark_ppos = STp->first_frame_position;
+	int	this_mark_lbn  = STp->logical_blk_num;
 #if DEBUG
 	int	dev = TAPE_NR(STp->devt);
 #endif
@@ -1715,22 +1895,19 @@
 	if (STp->raw) return 0;
 
 	STp->write_type = OS_WRITE_NEW_MARK;
-	this_mark_ppos = osst_get_frame_position(STp, aSRpnt);
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%i: Writing Filemark %i at frame %d (lblk %d)\n", 
-	       dev, STp->filemark_cnt, this_mark_ppos, STp->logical_blk_num);
+	printk(OSST_DEB_MSG "osst%d:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n", 
+	       dev, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn);
 #endif
-	osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->logical_blk_num++);
-	STp->ps[STp->partition].rw = ST_WRITING;
 	STp->dirty = 1;
-	result  = osst_flush_write_buffer(STp, aSRpnt, 0);
+	result  = osst_flush_write_buffer(STp, aSRpnt);
 	result |= osst_flush_drive_buffer(STp, aSRpnt);
 	STp->last_mark_ppos = this_mark_ppos;
+	STp->last_mark_lbn  = this_mark_lbn;
 	if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX)
 		STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos);
 	if (STp->filemark_cnt++ == 0)
 		STp->first_mark_ppos = this_mark_ppos;
-//	osst_update_markers(STp, aSRpnt, STp->last_mark_addr, this_mark_addr);
 	return result;
 }
 
@@ -1744,71 +1921,67 @@
 	if (STp->raw) return 0;
 
 	STp->write_type = OS_WRITE_EOD;
-	STp->eod_frame_ppos = osst_get_frame_position(STp, aSRpnt);
+	STp->eod_frame_ppos = STp->first_frame_position;
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%i: Writing EOD at %d=>%d\n", dev, STp->logical_blk_num, STp->eod_frame_ppos);
+	printk(OSST_DEB_MSG "osst%d:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", dev,
+			STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num);
 #endif
-	osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->logical_blk_num++);
-	STp->ps[STp->partition].rw = ST_WRITING;
 	STp->dirty = 1;
 
-	result  = osst_flush_write_buffer(STp, aSRpnt, 0);	
+	result  = osst_flush_write_buffer(STp, aSRpnt);	
 	result |= osst_flush_drive_buffer(STp, aSRpnt);
-	STp->eod_frame_lfa = --(STp->logical_blk_num);
+	STp->eod_frame_lfa = --(STp->frame_seq_number);
 	return result;
 }
 
-static int osst_write_filler(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int block, int count)
+static int osst_write_filler(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int where, int count)
 {
 	int	dev = TAPE_NR(STp->devt);
 
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%i: Reached onstream write filler group %d\n", dev, block);
+	printk(OSST_DEB_MSG "osst%d:D: Reached onstream write filler group %d\n", dev, where);
 #endif
 	osst_wait_ready(STp, aSRpnt, 60 * 5);
-	osst_set_frame_position(STp, aSRpnt, block, 0);
+	osst_set_frame_position(STp, aSRpnt, where, 0);
 	STp->write_type = OS_WRITE_FILLER;
-	osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0);
 	while (count--) {
 		memcpy(STp->buffer->b_data, "Filler", 6);
 		STp->buffer->buffer_bytes = 6;
 		STp->dirty = 1;
-		if (osst_flush_write_buffer(STp, aSRpnt, 0)) {
-			printk(KERN_INFO "osst%i: Couldn't write filler frame\n", dev);
+		if (osst_flush_write_buffer(STp, aSRpnt)) {
+			printk(KERN_INFO "osst%i:I: Couldn't write filler frame\n", dev);
 			return (-EIO);
 		}
 	}
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%i: Exiting onstream write filler group\n", dev);
+	printk(OSST_DEB_MSG "osst%d:D: Exiting onstream write filler group\n", dev);
 #endif
 	return osst_flush_drive_buffer(STp, aSRpnt);
 }
 
-static int __osst_write_header(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int block, int count)
+static int __osst_write_header(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int where, int count)
 {
 	int	dev   = TAPE_NR(STp->devt);
 	int     result;
 
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%i: Reached onstream write header group %d\n", dev, block);
+	printk(OSST_DEB_MSG "osst%d:D: Reached onstream write header group %d\n", dev, where);
 #endif
 	osst_wait_ready(STp, aSRpnt, 60 * 5);
-	osst_set_frame_position(STp, aSRpnt, block, 0);
+	osst_set_frame_position(STp, aSRpnt, where, 0);
 	STp->write_type = OS_WRITE_HEADER;
-	STp->ps[STp->partition].rw = ST_WRITING;
-	osst_init_aux(STp, OS_FRAME_TYPE_HEADER, STp->logical_blk_num);
 	while (count--) {
 		osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache);
 		STp->buffer->buffer_bytes = sizeof(os_header_t);
 		STp->dirty = 1;
-		if (osst_flush_write_buffer(STp, aSRpnt, 0)) {
-			printk(KERN_INFO "osst%i: Couldn't write header frame\n", dev);
+		if (osst_flush_write_buffer(STp, aSRpnt)) {
+			printk(KERN_INFO "osst%i:I: Couldn't write header frame\n", dev);
 			return (-EIO);
 		}
 	}
 	result = osst_flush_drive_buffer(STp, aSRpnt);
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%i: Write onstream header group %s\n", dev, result?"failed":"done");
+	printk(OSST_DEB_MSG "osst%d:D: Write onstream header group %s\n", dev, result?"failed":"done");
 #endif
 	return result;
 }
@@ -1820,18 +1993,18 @@
 	int	      dev   = TAPE_NR(STp->devt);
 
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%i: Writing tape header\n", dev);
+	printk(OSST_DEB_MSG "osst%d:D: Writing tape header\n", dev);
 #endif
 	if (STp->raw) return 0;
 
 	if (STp->header_cache == NULL) {
 		if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
-			printk(KERN_ERR "osst%i: Failed to allocate header cache\n", dev);
+			printk(KERN_ERR "osst%i:E: Failed to allocate header cache\n", dev);
 			return (-ENOMEM);
 		}
 		memset(STp->header_cache, 0, sizeof(os_header_t));
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%d: Allocated and cleared memory for header cache\n", dev);
+		printk(OSST_DEB_MSG "osst%d:D: Allocated and cleared memory for header cache\n", dev);
 #endif
 	}
 	if (STp->header_ok) STp->update_frame_cntr++;
@@ -1872,12 +2045,12 @@
 
 	if (locate_eod) {
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%i: locating back to eod frame addr %d\n", dev, STp->eod_frame_ppos);
+		printk(OSST_DEB_MSG "osst%d:D: Locating back to eod frame addr %d\n", dev, STp->eod_frame_ppos);
 #endif
 		osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0);
 	}
 	if (result)
-		printk(KERN_WARNING "osst%i: write header failed\n", dev);
+		printk(KERN_ERR "osst%i:E: Write header failed\n", dev);
 	else {
 		memcpy(STp->application_sig, "LIN4", 4);
 		STp->linux_media         = 1;
@@ -1892,15 +2065,15 @@
 	if (STp->header_cache != NULL)
 		memset(STp->header_cache, 0, sizeof(os_header_t));
 
-	STp->logical_blk_num = 0;
-	STp->logical_blk_in_buffer = 0;
+	STp->logical_blk_num = STp->frame_seq_number = 0;
+	STp->frame_in_buffer = 0;
 	STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A;
 	STp->filemark_cnt = 0;
-	STp->first_mark_ppos = STp->last_mark_ppos = -1;
+	STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
 	return osst_write_header(STp, aSRpnt, 1);
 }
 
-static int __osst_analyze_headers(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int block)
+static int __osst_analyze_headers(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int ppos)
 {
 	int           dev = TAPE_NR(STp->devt);
 	os_header_t * header;
@@ -1912,17 +2085,17 @@
 	if (STp->raw)
 		return 1;
 
-	if (block == 5 || block == 0xbae || STp->buffer->syscall_result) {
-		if (osst_set_frame_position(STp, aSRpnt, block, 0))
-			printk(KERN_WARNING "osst%i: Couldn't position tape\n", dev);
+	if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) {
+		if (osst_set_frame_position(STp, aSRpnt, ppos, 0))
+			printk(KERN_WARNING "osst%i:W: Couldn't position tape\n", dev);
 		if (osst_initiate_read (STp, aSRpnt)) {
-			printk(KERN_WARNING "osst%i: Couldn't initiate read\n", dev);
+			printk(KERN_WARNING "osst%i:W: Couldn't initiate read\n", dev);
 			return 0;
 		}
 	}
-	if (osst_read_block(STp, aSRpnt, 180)) {
+	if (osst_read_frame(STp, aSRpnt, 180)) {
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%i: Couldn't read header frame\n", dev);
+		printk(OSST_DEB_MSG "osst%d:D: Couldn't read header frame\n", dev);
 #endif
 		return 0;
 	}
@@ -1930,7 +2103,20 @@
 	aux = STp->buffer->aux;
 	if (aux->frame_type != OS_FRAME_TYPE_HEADER) {
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%i: Skipping non-header frame (%d)\n", dev, block);
+		printk(OSST_DEB_MSG "osst%d:D: Skipping non-header frame (%d)\n", dev, ppos);
+#endif
+		return 0;
+	}
+	if (ntohl(aux->frame_seq_num)              != 0                   ||
+	    ntohl(aux->logical_blk_num)            != 0                   ||
+	          aux->partition.partition_num     != OS_CONFIG_PARTITION ||
+	    ntohl(aux->partition.first_frame_ppos) != 0                   ||
+	    ntohl(aux->partition.last_frame_ppos)  != 0xbb7               ) {
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d:D: Invalid header frame (%d,%d,%d,%d,%d)\n", dev,
+				ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
+			       	aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos),
+			       	ntohl(aux->partition.last_frame_ppos));
 #endif
 		return 0;
 	}
@@ -1938,51 +2124,57 @@
 	    strncmp(header->ident_str, "ADR-SEQ", 7) != 0) {
 		strncpy(id_string, header->ident_str, 7);
 		id_string[7] = 0;
-		printk(KERN_INFO "osst%i: Invalid header identification string %s\n", dev, id_string);
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d:D: Invalid header identification string %s\n", dev, id_string);
+#endif
 		return 0;
 	}
 	update_frame_cntr = ntohl(aux->update_frame_cntr);
 	if (update_frame_cntr < STp->update_frame_cntr) {
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%i: Skipping frame %d with update_frame_counter %d<%d\n",
-				   dev, block, update_frame_cntr, STp->update_frame_cntr);
+		printk(OSST_DEB_MSG "osst%d:D: Skipping frame %d with update_frame_counter %d<%d\n",
+				   dev, ppos, update_frame_cntr, STp->update_frame_cntr);
 #endif
 		return 0;
 	}
 	if (header->major_rev != 1 || header->minor_rev != 4 ) {
-		printk(KERN_INFO "osst%i: %s revision %d.%d detected (1.4 supported)\n", 
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d:D: %s revision %d.%d detected (1.4 supported)\n", 
 				 dev, (header->major_rev != 1 || header->minor_rev < 2 || 
 				       header->minor_rev  > 4 )? "Invalid" : "Warning:",
 				 header->major_rev, header->minor_rev);
+#endif
 		if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4)
 			return 0;
 	}
+#if DEBUG
 	if (header->pt_par_num != 1)
-		printk(KERN_INFO "osst%i: Warning: %d partitions defined, only one supported\n", 
+		printk(KERN_INFO "osst%i:W: %d partitions defined, only one supported\n", 
 				 dev, header->pt_par_num);
+#endif
 	memcpy(id_string, aux->application_sig, 4);
 	id_string[4] = 0;
 	if (memcmp(id_string, "LIN", 3) == 0) {
 		STp->linux_media = 1;
 		linux_media_version = id_string[3] - '0';
 		if (linux_media_version != 4)
-			printk(KERN_INFO "osst%i: Linux media version %d detected (current 4)\n",
+			printk(KERN_INFO "osst%i:I: Linux media version %d detected (current 4)\n",
 					 dev, linux_media_version);
 	} else {
-		printk(KERN_WARNING "osst%i: non Linux media detected (%s)\n", dev, id_string);
+		printk(KERN_WARNING "osst%i:W: Non Linux media detected (%s)\n", dev, id_string);
 		return 0;
 	}
 	if (linux_media_version < STp->linux_media_version) {
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%i: Skipping frame %d with linux_media_version %d\n",
-				  dev, block, linux_media_version);
+		printk(OSST_DEB_MSG "osst%d:D: Skipping frame %d with linux_media_version %d\n",
+				  dev, ppos, linux_media_version);
 #endif
 		return 0;
 	}
 	if (linux_media_version > STp->linux_media_version) {
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%i: Frame %d sets linux_media_version to %d\n",
-				   dev, block, linux_media_version);
+		printk(OSST_DEB_MSG "osst%d:D: Frame %d sets linux_media_version to %d\n",
+				   dev, ppos, linux_media_version);
 #endif
 		memcpy(STp->application_sig, id_string, 5);
 		STp->linux_media_version = linux_media_version;
@@ -1990,16 +2182,16 @@
 	}
 	if (update_frame_cntr > STp->update_frame_cntr) {
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%i: Frame %d sets update_frame_counter to %d\n",
-				   dev, block, update_frame_cntr);
+		printk(OSST_DEB_MSG "osst%d:D: Frame %d sets update_frame_counter to %d\n",
+				   dev, ppos, update_frame_cntr);
 #endif
 		if (STp->header_cache == NULL) {
 			if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
-				printk(KERN_ERR "osst%i: Failed to allocate header cache\n", dev);
+				printk(KERN_ERR "osst%i:E: Failed to allocate header cache\n", dev);
 				return 0;
 			}
 #if DEBUG
-			printk(OSST_DEB_MSG "osst%d: Allocated memory for header cache\n", dev);
+			printk(OSST_DEB_MSG "osst%d:D: Allocated memory for header cache\n", dev);
 #endif
 		}
 		osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache);
@@ -2012,19 +2204,22 @@
 		STp->filemark_cnt      = ntohl(aux->filemark_cnt);
 		STp->first_mark_ppos   = ntohl(aux->next_mark_ppos);
 		STp->last_mark_ppos    = ntohl(aux->last_mark_ppos);
+		STp->last_mark_lbn     = ntohl(aux->last_mark_lbn);
 		STp->update_frame_cntr = update_frame_cntr;
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%i: detected write pass %d, update frame counter %d, filemark counter %d\n",
+	printk(OSST_DEB_MSG "osst%d:D: Detected write pass %d, update frame counter %d, filemark counter %d\n",
 			  dev, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt);
-	printk(OSST_DEB_MSG "osst%i: first data frame on tape = %d, last = %d, eod frame = %d\n", dev,
+	printk(OSST_DEB_MSG "osst%d:D: first data frame on tape = %d, last = %d, eod frame = %d\n", dev,
 			  STp->first_data_ppos,
 			  ntohl(header->partition[0].last_frame_ppos),
 			  ntohl(header->partition[0].eod_frame_ppos));
-	printk(OSST_DEB_MSG "osst%i: first mark on tape = %d, last = %d, eod frame = %d\n", 
+	printk(OSST_DEB_MSG "osst%d:D: first mark on tape = %d, last = %d, eod frame = %d\n", 
 			  dev, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos);
 #endif
 		if (header->minor_rev < 4 && STp->linux_media_version == 4) {
-			printk(OSST_DEB_MSG "osst%i: Moving filemark list to ADR 1.4 location\n", dev);
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%i:D: Moving filemark list to ADR 1.4 location\n", dev);
+#endif
 			memcpy((void *)header->dat_fm_tab.fm_tab_ent, 
 			       (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent));
 			memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list));
@@ -2048,9 +2243,8 @@
 		     header->dat_fm_tab.fm_tab_ent_sz                != 4                          ||
 		     header->dat_fm_tab.fm_tab_ent_cnt               !=
 			     htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX)))
-			printk(KERN_WARNING "osst%i: Failed consistency check ADR 1.4 format\n", dev);
+			printk(KERN_WARNING "osst%i:W: Failed consistency check ADR 1.4 format\n", dev);
 
-//		memcpy(STp->header_cache, header, sizeof(os_header_t));
 	}
 
 	return 1;
@@ -2058,7 +2252,7 @@
 
 static int osst_analyze_headers(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
 {
-	int	position, block;
+	int position, ppos;
 	int	first, last;
 	int	valid = 0;
 	int	dev = TAPE_NR(STp->devt);
@@ -2073,37 +2267,37 @@
 	STp->header_ok = STp->linux_media = STp->linux_media_version = 0;
 	STp->wrt_pass_cntr = STp->update_frame_cntr = -1;
 	STp->eod_frame_ppos = STp->first_data_ppos = -1;
-	STp->first_mark_ppos = STp->last_mark_ppos = -1;
+	STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%i: Reading header\n", dev);
+	printk(OSST_DEB_MSG "osst%d:D: Reading header\n", dev);
 #endif
 
-	/* optimization for speed - if we are positioned at block 10, read second group first */	
+	/* optimization for speed - if we are positioned at ppos 10, read second group first  */	
 	/* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */
 
 	first = position==10?0xbae: 5;
 	last  = position==10?0xbb3:10;
 
-	for (block = first; block < last; block++)
-		if (__osst_analyze_headers(STp, aSRpnt, block))
+	for (ppos = first; ppos < last; ppos++)
+		if (__osst_analyze_headers(STp, aSRpnt, ppos))
 			valid = 1;
 
 	first = position==10? 5:0xbae;
 	last  = position==10?10:0xbb3;
 
-	for (block = first; block < last; block++)
-		if (__osst_analyze_headers(STp, aSRpnt, block))
+	for (ppos = first; ppos < last; ppos++)
+		if (__osst_analyze_headers(STp, aSRpnt, ppos))
 			valid = 1;
 
 	if (!valid) {
-		printk(KERN_ERR "osst%i: Failed to find valid ADRL header, new media?\n", dev);
+		printk(KERN_ERR "osst%i:E: Failed to find valid ADRL header, new media?\n", dev);
 		STp->eod_frame_ppos = STp->first_data_ppos = 0;
 		osst_set_frame_position(STp, aSRpnt, 10, 0);
 		return 0;
 	}
 	if (position <= STp->first_data_ppos) {
 		position = STp->first_data_ppos;
-		STp->ps[0].drv_file = STp->ps[0].drv_block = STp->logical_blk_num = 0;
+		STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
 	}
 	osst_set_frame_position(STp, aSRpnt, position, 0);
 	STp->header_ok = 1;
@@ -2114,18 +2308,21 @@
 static int osst_verify_position(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
 {
 	int	frame_position  = STp->first_frame_position;
+	int frame_seq_numbr = STp->frame_seq_number;
 	int	logical_blk_num = STp->logical_blk_num;
+       	int halfway_frame   = STp->frame_in_buffer;
+	int read_pointer    = STp->buffer->read_pointer;
 	int	prev_mark_ppos  = -1;
 	int	actual_mark_ppos, i, n;
-#if 1 //DEBUG
+#if DEBUG
 	int	dev = TAPE_NR(STp->devt);
 
-	printk(OSST_DEB_MSG "osst%i: Verify that the tape is really the one we think before writing\n", dev);
+	printk(OSST_DEB_MSG "osst%d:D: Verify that the tape is really the one we think before writing\n", dev);
 #endif
 	osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
-	if (osst_get_logical_blk(STp, aSRpnt, -1, 0) < 0) {
+	if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%i: Couldn't get logical blk num in verify_position\n", dev);
+		printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in verify_position\n", dev);
 #endif
 		return (-EIO);
 	}
@@ -2137,42 +2334,48 @@
 		prev_mark_ppos = frame_position - 1;  /* usually - we don't really know */
 	actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ?
 				frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos);
-	if (frame_position  != STp->first_frame_position ||
-	    logical_blk_num != STp->logical_blk_num + 1  ||
-	    prev_mark_ppos  != actual_mark_ppos           ) {
-#if 1 //DEBUG
-		printk(OSST_DEB_MSG "osst%i: Block mismatch: frame %d-%d, lblk %d-%d, mark %d-%d\n", dev,
-				  STp->first_frame_position, frame_position, STp->logical_blk_num + 1,
-				  logical_blk_num, actual_mark_ppos, prev_mark_ppos);
+	if (frame_position  != STp->first_frame_position                   ||
+	    frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) ||
+	    prev_mark_ppos  != actual_mark_ppos                            ) {
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", dev,
+				  STp->first_frame_position, frame_position, 
+				  STp->frame_seq_number + (halfway_frame?0:1),
+				  frame_seq_numbr, actual_mark_ppos, prev_mark_ppos);
 #endif
 		return (-EIO);
 	}
-	STp->logical_blk_in_buffer = 0;
-	STp->logical_blk_num = logical_blk_num;
+	if (halfway_frame) {
+		/* prepare buffer for append and rewrite on top of original */
+		osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
+		STp->buffer->buffer_bytes  = read_pointer;
+		STp->ps[STp->partition].rw = ST_WRITING;
+		STp->dirty                 = 1;
+	}
+	STp->frame_in_buffer  = halfway_frame;
+	STp->frame_seq_number = frame_seq_numbr;
+	STp->logical_blk_num  = logical_blk_num;
 	return 0;
 }
 
 /* Acc. to OnStream, the vers. numbering is the following:
  * X.XX for released versions (X=digit), 
  * XXXY for unreleased versions (Y=letter)
- * Ordering 1.05 < 106A < 106a < 106B < ... < 1.06
+ * Ordering 1.05 < 106A < 106B < ...  < 106a < ... < 1.06
  * This fn makes monoton numbers out of this scheme ...
  */
 static unsigned int osst_parse_firmware_rev (const char * str)
 {
-	unsigned int rev;
 	if (str[1] == '.') {
-		rev = (str[0]-0x30)*10000
-			+(str[2]-0x30)*1000
-			+(str[3]-0x30)*100;
+		return (str[0]-'0')*10000
+			+(str[2]-'0')*1000
+			+(str[3]-'0')*100;
 	} else {
-		rev = (str[0]-0x30)*10000
-			+(str[1]-0x30)*1000
-			+(str[2]-0x30)*100 - 100;
-		rev += 2*(str[3] & 0x1f)
-			+(str[3] >= 0x60? 1: 0);
+		return (str[0]-'0')*10000
+			+(str[1]-'0')*1000
+			+(str[2]-'0')*100 - 100
+			+(str[3]-'@');
 	}
-	return rev;
 }
 
 /*
@@ -2180,9 +2383,9 @@
  */
 static int osst_configure_onstream(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt)
 {
-	int                            dev   = TAPE_NR(STp->devt);
 	unsigned char                  cmd[MAX_COMMAND_SIZE];
-	Scsi_Request                 * SRpnt = * aSRpnt;
+	int                            dev   = TAPE_NR(STp->devt);
+	Scsi_Request                    * SRpnt = * aSRpnt;
 	osst_mode_parameter_header_t * header;
 	osst_block_size_page_t       * bs;
 	osst_capabilities_page_t     * cp;
@@ -2191,21 +2394,19 @@
 
 	if (STp->ready != ST_READY) {
 #if DEBUG
-	    printk(OSST_DEB_MSG "osst%i: Not Ready\n", dev);
+	    printk(OSST_DEB_MSG "osst%d:D: Not Ready\n", dev);
 #endif
 	    return (-EIO);
 	}
 	
 	if (STp->os_fw_rev < 10600) {
-	    printk("osst%i: Old OnStream firmware revision detected (%s)\n", 
-		       dev, STp->device->rev);
-	    printk("osst%i: An upgrade to version 1.06 or above is recommended\n",
-		       dev);
+	    printk(KERN_INFO "osst%i:I: Old OnStream firmware revision detected (%s),\n", dev, STp->device->rev);
+	    printk(KERN_INFO "osst%d:I: an upgrade to version 1.06 or above is recommended\n", dev);
 	}
 
 	/*
 	 * Configure 32.5KB (data+aux) frame size.
-	 * Get the current block size from the block size mode page
+         * Get the current frame size from the block size mode page
 	 */
 	memset(cmd, 0, MAX_COMMAND_SIZE);
 	cmd[0] = MODE_SENSE;
@@ -2216,13 +2417,13 @@
 	SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ, STp->timeout, 0, TRUE);
 	if (SRpnt == NULL) {
 #if DEBUG
- 	    printk(OSST_DEB_MSG "osst: Busy\n");
+ 	    printk(OSST_DEB_MSG "osst :D: Busy\n");
 #endif
 	    return (-EBUSY);
 	}
 	*aSRpnt = SRpnt;
 	if ((STp->buffer)->syscall_result != 0) {
-	    printk (KERN_ERR "osst%i: Can't get tape block size mode page\n", dev);
+	    printk (KERN_ERR "osst%i:E: Can't get tape block size mode page\n", dev);
 	    return (-EIO);
 	}
 
@@ -2230,10 +2431,10 @@
 	bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl);
 
 #if DEBUG
-	printk(KERN_INFO "osst%i: 32KB play back: %s\n",   dev, bs->play32     ? "Yes" : "No");
-	printk(KERN_INFO "osst%i: 32.5KB play back: %s\n", dev, bs->play32_5   ? "Yes" : "No");
-	printk(KERN_INFO "osst%i: 32KB record: %s\n",      dev, bs->record32   ? "Yes" : "No");
-	printk(KERN_INFO "osst%i: 32.5KB record: %s\n",    dev, bs->record32_5 ? "Yes" : "No");
+	printk(OSST_DEB_MSG "osst%d:D: 32KB play back: %s\n",   dev, bs->play32     ? "Yes" : "No");
+	printk(OSST_DEB_MSG "osst%d:D: 32.5KB play back: %s\n", dev, bs->play32_5   ? "Yes" : "No");
+	printk(OSST_DEB_MSG "osst%d:D: 32KB record: %s\n",      dev, bs->record32   ? "Yes" : "No");
+	printk(OSST_DEB_MSG "osst%d:D: 32.5KB record: %s\n",    dev, bs->record32_5 ? "Yes" : "No");
 #endif
 
 	/*
@@ -2253,16 +2454,12 @@
 	SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE);
 	*aSRpnt = SRpnt;
 	if ((STp->buffer)->syscall_result != 0) {
-	    printk (KERN_ERR "osst%i: Couldn't set tape block size mode page\n", dev);
+	    printk (KERN_ERR "osst%i:E: Couldn't set tape block size mode page\n", dev);
 	    return (-EIO);
 	}
 
-	STp->block_size = (STp->raw) ? OS_FRAME_SIZE : OS_DATA_SIZE;
-	STp->min_block  = OS_FRAME_SIZE; /* FIXME */
-	STp->max_block  = STp->block_size;
-
 #if DEBUG
-	printk(KERN_INFO "osst%i: Block Size changed to 32.5K\n", dev);
+	printk(KERN_INFO "osst%d:D: Block Size changed to 32.5K\n", dev);
 	 /*
 	 * In debug mode, we want to see as many errors as possible
 	 * to test the error recovery mechanism.
@@ -2298,7 +2495,7 @@
 	*aSRpnt = SRpnt;
 
 	if ((STp->buffer)->syscall_result != 0) {
-	    printk (KERN_ERR "osst%i: Couldn't set vendor name to %s\n", dev, 
+	    printk (KERN_ERR "osst%i:E: Couldn't set vendor name to %s\n", dev, 
 			(char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2));
 	    return (-EIO);
 	}
@@ -2313,7 +2510,7 @@
 	*aSRpnt = SRpnt;
 
 	if ((STp->buffer)->syscall_result != 0) {
-	    printk (KERN_ERR "osst%i: can't get capabilities page\n", dev);
+	    printk (KERN_ERR "osst%i:E: Can't get capabilities page\n", dev);
 	    return (-EIO);
 	}
 
@@ -2333,7 +2530,7 @@
 	*aSRpnt = SRpnt;
 
 	if ((STp->buffer)->syscall_result != 0) {
-	    printk (KERN_ERR "osst%i: can't get tape parameter page\n", dev);
+	    printk (KERN_ERR "osst%i:E: Can't get tape parameter page\n", dev);
 	    return (-EIO);
 	}
 
@@ -2344,7 +2541,7 @@
 	STp->density  = prm->density;
 	STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%d: Density %d, tape length: %dMB, drive buffer size: %dKB\n",
+	printk(OSST_DEB_MSG "osst%d:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n",
 			  dev, STp->density, STp->capacity / 32, drive_buffer_size);
 #endif
 
@@ -2362,7 +2559,7 @@
 
 #if DEBUG
 	if (debugging)
-		printk(OSST_DEB_MSG "osst%d: Stepping over filemark %s.\n",
+		printk(OSST_DEB_MSG "osst%d:D: Stepping over filemark %s.\n",
 	   			  dev, forward ? "forward" : "backward");
 #endif
 
@@ -2375,7 +2572,7 @@
 	   result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1);
 
 	if (result < 0)
-	   printk(KERN_ERR "osst%d: Stepping over filemark %s failed.\n",
+	   printk(KERN_WARNING "osst%d:W: Stepping over filemark %s failed.\n",
 				dev, forward ? "forward" : "backward");
 
 	return result;
@@ -2415,7 +2612,7 @@
 		result = ((SRpnt->sr_sense_buffer[2] & 0x0f) == 3) ? -EIO : -EINVAL;
 
 	if (result == -EINVAL)
-		printk(KERN_ERR "osst%d: Can't read tape position.\n", dev);
+		printk(KERN_ERR "osst%d:E: Can't read tape position.\n", dev);
 	else {
 
 		if (result == -EIO) {	/* re-read position */
@@ -2440,7 +2637,7 @@
 		STp->cur_frames           =  (STp->buffer)->b_data[15];
 #if DEBUG
 		if (debugging) {
-			printk(OSST_DEB_MSG "osst%d: Drive Positions: host %d, tape %d%s, buffer %d\n", dev,
+			printk(OSST_DEB_MSG "osst%d:D: Drive Positions: host %d, tape %d%s, buffer %d\n", dev,
 					    STp->first_frame_position, STp->last_frame_position,
 					    ((STp->buffer)->b_data[0]&0x80)?" (BOP)":
 					    ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"",
@@ -2449,7 +2646,7 @@
 #endif
 		if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) {
 #if DEBUG
-			printk(KERN_WARNING "osst%d: Correcting read position %d, %d, %d\n", dev,
+			printk(KERN_WARNING "osst%d:D: Correcting read position %d, %d, %d\n", dev,
 					STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
 #endif
 			STp->first_frame_position = STp->last_frame_position;
@@ -2462,55 +2659,61 @@
 
 
 /* Set the tape block */
-static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, int block, int skip)
+static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, int ppos, int skip)
 {
 	unsigned char	scmd[MAX_COMMAND_SIZE];
 	Scsi_Request  * SRpnt;
 	ST_partstat   * STps;
 	int		result = 0;
-	int		timeout;
+	int		pp  = (ppos == 3000 && !skip)? 0 : ppos;
 	int		dev = TAPE_NR(STp->devt);
 
 	if (STp->ready != ST_READY) return (-EIO);
 
-	timeout = STp->long_timeout;
 	STps = &(STp->ps[STp->partition]);
 
-	if (block < 0 || block > STp->capacity) {
-		printk(KERN_ERR "osst%d: Reposition request %d out of range\n", dev, block);
-		block = block < 0 ? 0 : (STp->capacity - 1);
+	if (ppos < 0 || ppos > STp->capacity) {
+		printk(KERN_WARNING "osst%d:W: Reposition request %d out of range\n", dev, ppos);
+		pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1);
 		result = (-EINVAL);
 	}
+
+	do {
 #if DEBUG
-	if (debugging)
-		printk(OSST_DEB_MSG "osst%d: Setting block to %d.\n", dev, block);
+		if (debugging)
+			printk(OSST_DEB_MSG "osst%d:D: Setting ppos to %d.\n", dev, pp);
 #endif
-	memset (scmd, 0, MAX_COMMAND_SIZE);
-	scmd[0] = SEEK_10;
-	scmd[1] = 1;
-	scmd[3] = (block >> 24);
-	scmd[4] = (block >> 16);
-	scmd[5] = (block >> 8);
-	scmd[6] = block;
-	if (skip)
-		scmd[9] = 0x80;
+		memset (scmd, 0, MAX_COMMAND_SIZE);
+		scmd[0] = SEEK_10;
+		scmd[1] = 1;
+		scmd[3] = (pp >> 24);
+		scmd[4] = (pp >> 16);
+		scmd[5] = (pp >> 8);
+		scmd[6] =  pp;
+		if (skip)
+			scmd[9] = 0x80;
 
-	SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, SCSI_DATA_NONE, timeout, MAX_READY_RETRIES, TRUE);
-	if (!SRpnt)
-		return (-EBUSY);
-	*aSRpnt  = SRpnt;
+		SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, SCSI_DATA_NONE, STp->long_timeout,
+								MAX_READY_RETRIES, TRUE);
+		if (!SRpnt)
+			return (-EBUSY);
+		*aSRpnt  = SRpnt;
 
-	STp->first_frame_position = STp->last_frame_position = block;
-	STps->eof = ST_NOEOF;
-	if ((STp->buffer)->syscall_result != 0) {
+		if ((STp->buffer)->syscall_result != 0) {
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%d: SEEK command failed.\n", dev);
+			printk(OSST_DEB_MSG "osst%d:D: SEEK command from %d to %d failed.\n",
+					dev, STp->first_frame_position, pp);
 #endif
-		result = (-EIO);
-	}
+			result = (-EIO);
+		}
+		if (pp != ppos)
+			osst_wait_ready(STp, aSRpnt, 5 * 60);
+	} while ((pp != ppos) && (pp = ppos));
+	STp->first_frame_position = STp->last_frame_position = ppos;
+	STps->eof = ST_NOEOF;
 	STps->at_sm = 0;
 	STps->rw = ST_IDLE;
-	STp->logical_blk_in_buffer = 0;
+	STp->frame_in_buffer = 0;
 	return result;
 }
 
@@ -2519,7 +2722,7 @@
 /* osst versions of st functions - augmented and stripped to suit OnStream only */
 
 /* Flush the write buffer (never need to write if variable blocksize). */
-static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, int file_blk)
+static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt)
 {
 	int offset, transfer, blks = 0;
 	int result = 0;
@@ -2532,19 +2735,19 @@
 		if (SRpnt == (STp->buffer)->last_SRpnt)
 #if DEBUG
 			{ printk(OSST_DEB_MSG
-	 "osst%d: aSRpnt points to Scsi_Request that write_behind_check will release -- cleared\n", dev);
+	 "osst%d:D: aSRpnt points to Scsi_Request that write_behind_check will release -- cleared\n", dev);
 #endif
 			*aSRpnt = SRpnt = NULL;
 #if DEBUG
 			} else if (SRpnt)
 				printk(OSST_DEB_MSG
-	 "osst%d: aSRpnt does not point to Scsi_Request that write_behind_check will release -- strange\n", dev);
+	 "osst%d:D: aSRpnt does not point to Scsi_Request that write_behind_check will release -- strange\n", dev);
 #endif	
 		osst_write_behind_check(STp);
 		if ((STp->buffer)->syscall_result) {
 #if DEBUG
 			if (debugging)
-				printk(OSST_DEB_MSG "osst%d: Async write error (flush) %x.\n",
+				printk(OSST_DEB_MSG "osst%d:D: Async write error (flush) %x.\n",
 				       dev, (STp->buffer)->midlevel_result);
 #endif
 			if ((STp->buffer)->midlevel_result == INT_MAX)
@@ -2556,15 +2759,13 @@
 	result = 0;
 	if (STp->dirty == 1) {
 
+		STp->write_count++;
+		STps     = &(STp->ps[STp->partition]);
+		STps->rw = ST_WRITING;
 		offset   = STp->buffer->buffer_bytes;
+		blks     = (offset + STp->block_size - 1) / STp->block_size;
 		transfer = OS_FRAME_SIZE;
-		blks     = 1;
 		
-#if DEBUG
-		if (debugging)
-			printk(OSST_DEB_MSG "osst%d: Flushing %d bytes, Tranfering %d bytes in %d blocks.\n",
-				 dev, offset, transfer, blks);
-#endif
 		if (offset < OS_DATA_SIZE)
 			osst_zero_buffer_tail(STp->buffer);
 
@@ -2575,7 +2776,38 @@
 		memset(cmd, 0, MAX_COMMAND_SIZE);
 		cmd[0] = WRITE_6;
 		cmd[1] = 1;
-		cmd[4] = blks;
+		cmd[4] = 1;
+
+		switch	(STp->write_type) {
+		   case OS_WRITE_DATA:
+#if DEBUG
+   			if (debugging)
+				printk(OSST_DEB_MSG "osst%d:D: Writing %d blocks to frame %d, lblks %d-%d\n",
+					dev, blks, STp->frame_seq_number, 
+					STp->logical_blk_num - blks, STp->logical_blk_num - 1);
+#endif
+			osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
+				      STp->logical_blk_num - blks, STp->block_size, blks);
+			break;
+		   case OS_WRITE_EOD:
+			osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++,
+				      STp->logical_blk_num, 0, 0);
+			break;
+		   case OS_WRITE_NEW_MARK:
+			osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++,
+				      STp->logical_blk_num++, 0, blks=1);
+			break;
+		   case OS_WRITE_HEADER:
+			osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0);
+			break;
+		default: /* probably FILLER */
+			osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0);
+		}
+#if DEBUG
+		if (debugging)
+			printk(OSST_DEB_MSG "osst%d:D: Flushing %d bytes, Transfering %d bytes in %d lblocks.\n",
+			  			 dev, offset, transfer, blks);
+#endif
 
 		SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, SCSI_DATA_WRITE,
 					  STp->timeout, MAX_WRITE_RETRIES, TRUE);
@@ -2583,12 +2815,13 @@
 		if (!SRpnt)
 			return (-EBUSY);
 
-		STps = &(STp->ps[STp->partition]);
 		if ((STp->buffer)->syscall_result != 0) {
+#if DEBUG
 			printk(OSST_DEB_MSG
-				"osst%d: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n",
+				"osst%d:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n",
 				dev, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
 				SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
+#endif
 			if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
 			    (SRpnt->sr_sense_buffer[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */
 			    (SRpnt->sr_sense_buffer[2] & 0x0f) == NO_SENSE) {
@@ -2598,22 +2831,20 @@
 			}
 			else {
 				if (osst_write_error_recovery(STp, aSRpnt, 1)) {
-					printk(KERN_ERR "osst%d: Error on flush.\n", dev);
+					printk(KERN_ERR "osst%d:E: Error on flush write.\n", dev);
 					result = (-EIO);
 				}
 			}
 			STps->drv_block = (-1);
 		}
 		else {
-			if (file_blk && STps->drv_block >= 0)
-				STps->drv_block += blks;
-			STp->first_frame_position += blks;
+			STp->first_frame_position++;
 			STp->dirty = 0;
 			(STp->buffer)->buffer_bytes = 0;
 		}
 	}
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%d: Exit flush write buffer with code %d\n", dev, result);
+	printk(OSST_DEB_MSG "osst%d:D: Exit flush write buffer with code %d\n", dev, result);
 #endif
 	return result;
 }
@@ -2623,15 +2854,12 @@
    seek_next is true. */
 static int osst_flush_buffer(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int seek_next)
 {
-	int backspace, result;
-	OSST_buffer    * STbuffer;
-	ST_partstat  * STps;
+	ST_partstat   * STps;
+	int backspace = 0, result = 0;
 #if DEBUG
 	int dev = TAPE_NR(STp->devt);
 #endif
 
-	STbuffer = STp->buffer;
-
 	/*
 	 * If there was a bus reset, block further access
 	 * to this device.
@@ -2644,19 +2872,23 @@
 
 	STps = &(STp->ps[STp->partition]);
 	if (STps->rw == ST_WRITING)  /* Writing */
-		return osst_flush_write_buffer(STp, aSRpnt, 1);
+		return osst_flush_write_buffer(STp, aSRpnt);
 
 	if (STp->block_size == 0)
 		return 0;
 
 #if DEBUG
-	printk(OSST_DEB_MSG "osst%i: Reached flush (read) buffer\n", dev);
+	printk(OSST_DEB_MSG "osst%d:D: Reached flush (read) buffer\n", dev);
 #endif
-	backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size -
-		    ((STp->buffer)->read_pointer + STp->block_size - 1        ) / STp->block_size ;
-	(STp->buffer)->buffer_bytes = 0;
-	(STp->buffer)->read_pointer = 0;
-	result = 0;
+
+	if (!STp->can_bsr) {
+		backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size -
+			    ((STp->buffer)->read_pointer + STp->block_size - 1        ) / STp->block_size ;
+		(STp->buffer)->buffer_bytes = 0;
+		(STp->buffer)->read_pointer = 0;
+		STp->frame_in_buffer = 0;		/* FIXME is this relevant w. OSST? */
+	}
+
 	if (!seek_next) {
 		if (STps->eof == ST_FM_HIT) {
 			result = cross_eof(STp, aSRpnt, FALSE); /* Back over the EOF hit */
@@ -2681,6 +2913,88 @@
 	return result;
 }
 
+static int osst_write_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int synchronous)
+{
+	unsigned char	cmd[MAX_COMMAND_SIZE];
+	Scsi_Request     * SRpnt;
+	int		blks;
+#if DEBUG
+	int		dev = TAPE_NR(STp->devt);
+#endif
+
+	if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d:D: Reaching config partition.\n", dev);
+#endif
+		if (osst_flush_drive_buffer(STp, aSRpnt) < 0) {
+			return (-EIO);
+		}
+		/* error recovery may have bumped us past the header partition */
+		if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) {
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%d:D: Skipping over config partition.\n", dev);
+#endif
+		osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8);
+		}
+	}
+
+	if (STp->poll)
+		osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 60);
+	/* TODO: Check for an error ! */
+
+//	osst_build_stats(STp, &SRpnt);
+
+	STp->ps[STp->partition].rw = ST_WRITING;
+	STp->write_type            = OS_WRITE_DATA;
+			
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0]   = WRITE_6;
+	cmd[1]   = 1;
+	cmd[4]   = 1;						/* one frame at a time... */
+	blks     = STp->buffer->buffer_bytes / STp->block_size;
+#if DEBUG
+	if (debugging)
+		printk(OSST_DEB_MSG "osst%d:D: Writing %d blocks to frame %d, lblks %d-%d\n", dev, blks, 
+			STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1);
+#endif
+	osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
+		      STp->logical_blk_num - blks, STp->block_size, blks);
+
+#if DEBUG
+	if (!synchronous)
+		STp->write_pending = 1;
+#endif
+	SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE, STp->timeout,
+							MAX_WRITE_RETRIES, synchronous);
+	if (!SRpnt)
+		return (-EBUSY);
+	*aSRpnt = SRpnt;
+
+	if (synchronous) {
+		if (STp->buffer->syscall_result != 0) {
+#if DEBUG
+			if (debugging)
+				printk(OSST_DEB_MSG "osst%d:D: Error on write:\n", dev);
+#endif
+			if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+			    (SRpnt->sr_sense_buffer[2] & 0x40)) {
+				if ((SRpnt->sr_sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
+					return (-ENOSPC);
+			}
+			else {
+				if (osst_write_error_recovery(STp, aSRpnt, 1))
+					return (-EIO);
+			}
+		}
+		else
+			STp->first_frame_position++;
+	}
+
+	STp->write_count++;
+
+	return 0;
+}
+
 
 /* Entry points to osst */
 
@@ -2692,7 +3006,6 @@
 	ssize_t i, do_count, blks, transfer;
 	int write_threshold;
 	int doing_write = 0;
-	unsigned char cmd[MAX_COMMAND_SIZE];
 	const char *b_point;
 	Scsi_Request * SRpnt = NULL;
 	OS_Scsi_Tape * STp;
@@ -2748,7 +3061,7 @@
 
 #if DEBUG
 	if (!STp->in_use) {
-		printk(OSST_DEB_MSG "osst%d: Incorrect device.\n", dev);
+		printk(OSST_DEB_MSG "osst%d:D: Incorrect device.\n", dev);
 		retval = (-EIO);
 		goto out;
 	}
@@ -2761,14 +3074,15 @@
 
 	/* Write must be integral number of blocks */
 	if (STp->block_size != 0 && (count % STp->block_size) != 0) {
-		printk(KERN_WARNING "osst%d: Write (%ld bytes) not multiple of tape block size (32k).\n",
-				       dev, (unsigned long)count);
+		printk(KERN_ERR "osst%d:E: Write (%ld bytes) not multiple of tape block size (%d%c).\n",
+				       dev, (unsigned long)count, STp->block_size<1024?
+				       STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
 		retval = (-EINVAL);
 		goto out;
 	}
 
-	if (STp->first_frame_position >= STp->capacity - 164) {
-		printk(KERN_WARNING "osst%d: Write truncated at EOM early warning (frame %d).\n",
+	if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) {
+		printk(KERN_ERR "osst%d:E: Write truncated at EOM early warning (frame %d).\n",
 				       dev, STp->first_frame_position);
 		retval = (-ENOSPC);
 		goto out;
@@ -2789,46 +3103,49 @@
 	}
 	else if (STps->rw != ST_WRITING) {
 		/* Are we totally rewriting this tape? */
-		if (!STp->header_ok || STp->first_frame_position == STp->first_data_ppos ||
-      		            (STps->drv_file == 0 && STps->drv_block == 0)) {
+		if (!STp->header_ok ||
+		    (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) ||
+		    (STps->drv_file == 0 && STps->drv_block == 0)) {
 			STp->wrt_pass_cntr++;
 #if DEBUG
-			printk(OSST_DEB_MSG "osst%d: Allocating next write pass counter: %d\n",
+			printk(OSST_DEB_MSG "osst%d:D: Allocating next write pass counter: %d\n",
 						  dev, STp->wrt_pass_cntr);
 #endif
 			osst_reset_header(STp, &SRpnt);
-			STps->drv_file = STps->drv_block = STp->logical_blk_num = 0;
+			STps->drv_file = STps->drv_block = 0;
 		}
 		/* Do we know where we'll be writing on the tape? */
 		else {
 			if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) ||
 			  		STps->drv_file < 0 || STps->drv_block < 0) {
-				if (STp->first_frame_position == STp->eod_frame_ppos) {
+				if (STp->first_frame_position == STp->eod_frame_ppos) {	/* at EOD */
 			  		STps->drv_file = STp->filemark_cnt;
 			  		STps->drv_block = 0;
 				}
 				else {
 					/* We have no idea where the tape is positioned - give up */
 #if DEBUG
-					printk(OSST_DEB_MSG "osst%d: Cannot write at indeterminate position.\n", dev);
+					printk(OSST_DEB_MSG
+						"osst%d:D: Cannot write at indeterminate position.\n", dev);
 #endif
 					retval = (-EIO);
 					goto out;
 				}
       			}	  
-			if (STps->drv_file > 0 && STps->drv_file < STp->filemark_cnt) {
+			if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) {
 				STp->filemark_cnt = STps->drv_file;
-				STp->last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]);
+				STp->last_mark_ppos =
+				       	ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]);
 				printk(KERN_WARNING
-					"osst%d: Overwriting file %d with old write pass counter %d\n",
+					"osst%d:W: Overwriting file %d with old write pass counter %d\n",
 						dev, STps->drv_file, STp->wrt_pass_cntr);
 				printk(KERN_WARNING
-					"osst%d: may lead to stale data being accepted on reading back!\n",
+					"osst%d:W: may lead to stale data being accepted on reading back!\n",
 						dev);
 #if DEBUG
 				printk(OSST_DEB_MSG
-					"osst%d: resetting filemark count to %d and last mark ppos to %d\n",
-						dev, STp->filemark_cnt, STp->last_mark_ppos);
+				  "osst%d:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n",
+					dev, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn);
 #endif
 			}
 		}
@@ -2836,19 +3153,19 @@
 	}
 	if (!STp->header_ok) {
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%d: Write cannot proceed without valid headers\n", dev);
+		printk(OSST_DEB_MSG "osst%d:D: Write cannot proceed without valid headers\n", dev);
 #endif
 		retval = (-EIO);
 		goto out;
 	}
 
 	if ((STp->buffer)->writing) {
-if (SRpnt) printk(KERN_ERR "osst%d: Not supposed to have SRpnt at line %d\n", dev, __LINE__);
+if (SRpnt) printk(KERN_ERR "osst%d:A: Not supposed to have SRpnt at line %d\n", dev, __LINE__);
 		osst_write_behind_check(STp);
 		if ((STp->buffer)->syscall_result) {
 #if DEBUG
 		if (debugging)
-			printk(OSST_DEB_MSG "osst%d: Async write error (write) %x.\n", dev,
+			printk(OSST_DEB_MSG "osst%d:D: Async write error (write) %x.\n", dev,
 						 (STp->buffer)->midlevel_result);
 #endif
 		if ((STp->buffer)->midlevel_result == INT_MAX)
@@ -2875,10 +3192,6 @@
 	}
 
 	if (!STm->do_buffer_writes) {
-#if 0
-		if (STp->block_size != 0 && (count % STp->block_size) != 0)
-			{retval=(-EIO);goto out;}   /* Write must be integral number of blocks */
-#endif
 		write_threshold = 1;
 	}
 	else
@@ -2887,37 +3200,12 @@
 		write_threshold--;
 
 	total = count;
-
-	if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) {
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%d: Skipping over config partition.\n", dev);
-#endif
-		if (osst_flush_drive_buffer(STp, &SRpnt) < 0) {
-			retval = (-EIO);
-			goto out;
-		}
-		/* error recovery may have bumped us past the header partition */
-		if (osst_get_frame_position(STp, &SRpnt) < 0xbb8)
-			osst_position_tape_and_confirm(STp, &SRpnt, 0xbb8);
-	}
-	
-	if (STp->poll)
-		retval = osst_wait_frame (STp, &SRpnt, STp->first_frame_position, -50, 60);
-	/* TODO: Check for an error ! */
-	
-	memset(cmd, 0, MAX_COMMAND_SIZE);
-	cmd[0] = WRITE_6;
-	cmd[1] = 1;
-
-	STps->rw = ST_WRITING;
-	STp->write_type = OS_WRITE_DATA;
-
-#if DEBUG
-	printk(OSST_DEB_MSG "osst%d: Writing %d bytes to file %d block %d lblk %d frame %d\n",
-			  dev, count, STps->drv_file, STps->drv_block,
-			  STp->logical_blk_num, STp->first_frame_position);
+	if (debugging)
+		printk(OSST_DEB_MSG "osst%d:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %d\n",
+				dev, count, STps->drv_file, STps->drv_block,
+				STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position);
 #endif
-
 	b_point = buf;
 	while ((STp->buffer)->buffer_bytes + count > write_threshold)
 	{
@@ -2933,85 +3221,62 @@
 			goto out;
 		}
 
-		transfer = OS_FRAME_SIZE;
-		blks     = 1;
-
-		osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->logical_blk_num++ );
-
-		cmd[2] = blks >> 16;
-		cmd[3] = blks >> 8;
-		cmd[4] = blks;
-
-		SRpnt = osst_do_scsi(SRpnt, STp, cmd, transfer, SCSI_DATA_WRITE,
-				  STp->timeout, MAX_WRITE_RETRIES, TRUE);
-		if (!SRpnt) {
-			retval = (STp->buffer)->syscall_result;
-			goto out;
-		}
+		blks = do_count / STp->block_size;
+		STp->logical_blk_num += blks;  /* logical_blk_num is incremented as data is moved from user */
+  
+		i = osst_write_frame(STp, &SRpnt, TRUE);
 
-		if ((STp->buffer)->syscall_result != 0) {
-#if DEBUG
-			if (debugging)
-				printk(OSST_DEB_MSG "osst%d: Error on write:\n", dev);
-#endif
-			if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
-			    (SRpnt->sr_sense_buffer[2] & 0x40)) {
-				if ((SRpnt->sr_sense_buffer[0] & 0x80) != 0)
-					transfer = (SRpnt->sr_sense_buffer[3] << 24) |
-						   (SRpnt->sr_sense_buffer[4] << 16) |
-						   (SRpnt->sr_sense_buffer[5] <<  8) |
-						    SRpnt->sr_sense_buffer[6];
-				else
-					transfer = 0;
-				transfer *= STp->block_size;
-				if (transfer <= do_count) {
-					filp->f_pos += do_count - transfer;
-					count -= do_count - transfer;
-					if (STps->drv_block >= 0) {
-						STps->drv_block += (do_count - transfer) / STp->block_size;
-					}
-					STps->eof = ST_EOM_OK;
-					retval = (-ENOSPC); /* EOM within current request */
-#if DEBUG
-					if (debugging)
-					      printk(OSST_DEB_MSG "osst%d: EOM with %d bytes unwritten.\n",
-								     dev, transfer);
-#endif
+		if (i == (-ENOSPC)) {
+			transfer = STp->buffer->writing;	/* FIXME -- check this logic */
+			if (transfer <= do_count) {
+				filp->f_pos += do_count - transfer;
+				count -= do_count - transfer;
+				if (STps->drv_block >= 0) {
+					STps->drv_block += (do_count - transfer) / STp->block_size;
 				}
-				else {
-					STps->eof = ST_EOM_ERROR;
-					STps->drv_block = (-1);    /* Too cautious? */
-					retval = (-EIO); /* EOM for old data */
+				STps->eof = ST_EOM_OK;
+				retval = (-ENOSPC);		/* EOM within current request */
 #if DEBUG
-					if (debugging)
-					      printk(OSST_DEB_MSG "osst%d: EOM with lost data.\n", dev);
+				if (debugging)
+				      printk(OSST_DEB_MSG "osst%d:D: EOM with %d bytes unwritten.\n",
+							     dev, transfer);
 #endif
-				}
 			}
 			else {
-				if (osst_write_error_recovery(STp, &SRpnt, 1) == 0) goto ok;
-				STps->drv_block = (-1);    /* Too cautious? */
-				retval = (-EIO);
+				STps->eof = ST_EOM_ERROR;
+				STps->drv_block = (-1);		/* Too cautious? */
+				retval = (-EIO);		/* EOM for old data */
+#if DEBUG
+				if (debugging)
+				      printk(OSST_DEB_MSG "osst%d:D: EOM with lost data.\n", dev);
+#endif
 			}
-
-			(STp->buffer)->buffer_bytes = 0;
+		}
+		else
+			retval = i;
+			
+		if (retval < 0) {
+			if (SRpnt != NULL) {
+				scsi_release_request(SRpnt);
+				SRpnt = NULL;
+			}
+			STp->buffer->buffer_bytes = 0;
 			STp->dirty = 0;
 			if (count < total)
 				retval = total - count;
 			goto out;
 		}
-		STp->first_frame_position++;
-ok:
+
 		filp->f_pos += do_count;
 		b_point += do_count;
 		count -= do_count;
 		if (STps->drv_block >= 0) {
 			STps->drv_block += blks;
 		}
-		STp->first_frame_position += blks;
-		(STp->buffer)->buffer_bytes = 0;
+		STp->buffer->buffer_bytes = 0;
 		STp->dirty = 0;
-	}
+	}  /* end while write threshold exceeded */
+
 	if (count != 0) {
 		STp->dirty = 1;
 		i = append_to_buffer(b_point, STp->buffer, count);
@@ -3019,6 +3284,11 @@
 			retval = i;
 			goto out;
 		}
+		blks = count / STp->block_size;
+		STp->logical_blk_num += blks;
+		if (STps->drv_block >= 0) {
+			STps->drv_block += blks;
+		}
 		filp->f_pos += count;
 		count = 0;
 	}
@@ -3028,41 +3298,23 @@
 		goto out;
 	}
 
-	if (STm->do_async_writes &&
-	    ((STp->buffer)->buffer_bytes >= STp->write_threshold &&
-	     (STp->buffer)->buffer_bytes >= OS_DATA_SIZE)      ) { 
+	if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) { 
 		/* Schedule an asynchronous write */
 		(STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
 					   STp->block_size) * STp->block_size;
 		STp->dirty = !((STp->buffer)->writing ==
 				          (STp->buffer)->buffer_bytes);
 
-		transfer = OS_FRAME_SIZE;
-		blks     = 1;
-
-		osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->logical_blk_num++ );
-
-		cmd[2] = blks >> 16;
-		cmd[3] = blks >> 8;
-		cmd[4] = blks;
-#if DEBUG
-		STp->write_pending = 1;
-#endif
-
-		SRpnt = osst_do_scsi(SRpnt, STp, cmd, transfer, SCSI_DATA_WRITE,
-				  STp->timeout, MAX_WRITE_RETRIES, FALSE);
-		if (SRpnt == NULL) {
-			retval = (STp->buffer)->syscall_result;
+		i = osst_write_frame(STp, &SRpnt, FALSE);
+		if (i < 0) {
+			retval = (-EIO);
 			goto out;
 		}
+		SRpnt = NULL;			/* Prevent releasing this request! */
 	}
-//    else if (SRpnt != NULL) {
-//	scsi_release_request(SRpnt);	/* FIXME -- this relesae no longer in st - why? */
-	SRpnt = NULL;			/* Prevent releasing this request! */
-//    }
 	STps->at_sm &= (total == 0);
 	if (total > 0)
-	STps->eof = ST_NOEOF;
+		STps->eof = ST_NOEOF;
 
 	retval = total;
 
@@ -3124,7 +3376,7 @@
 	}
 #if DEBUG
 	if (!STp->in_use) {
-		printk(OSST_DEB_MSG "osst%d: Incorrect device.\n", dev);
+		printk(OSST_DEB_MSG "osst%d:D: Incorrect device.\n", dev);
 		retval = (-EIO);
 		goto out;
 	}
@@ -3135,13 +3387,6 @@
 		goto out;
 	}
 
-	if ((count % STp->block_size) != 0) {
-		printk(KERN_WARNING "osst%d: Use multiple of %d bytes as block size (%ld requested)\n",
-			  dev, STp->block_size, (unsigned long) count);
-		retval = (-EINVAL);	/* Read must be integral number of blocks */
-		goto out;
-	}
-
 	if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
 	!osst_int_ioctl(STp, &SRpnt, MTLOCK, 0))
 		STp->door_locked = ST_LOCKED_AUTO;
@@ -3154,9 +3399,15 @@
 		STps->rw = ST_IDLE;
 	}
 
+	if ((count % STp->block_size) != 0) {
+		printk(KERN_WARNING
+		    "osst%d:W: Read (%Zd bytes) not multiple of tape block size (%d%c).\n", dev, count,
+		    STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
+	}
+
 #if DEBUG
 	if (debugging && STps->eof != ST_NOEOF)
-		printk(OSST_DEB_MSG "osst%d: EOF/EOM flag up (%d). Bytes %d\n", dev,
+		printk(OSST_DEB_MSG "osst%d:D: EOF/EOM flag up (%d). Bytes %d\n", dev,
 				     STps->eof, (STp->buffer)->buffer_bytes);
 #endif
 	if ((STp->buffer)->buffer_bytes == 0 &&
@@ -3181,41 +3432,51 @@
 	}
 
 	/* Loop until enough data in buffer or a special condition found */
-	for (total = 0, special = 0; total < count && !special; ) {
+	for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) {
 
 		/* Get new data if the buffer is empty */
 		if ((STp->buffer)->buffer_bytes == 0) {
-			special = osst_get_logical_blk(STp, &SRpnt, STp->logical_blk_num, 0);
-			STp->buffer->buffer_bytes = special ? 0 : OS_DATA_SIZE; 
-			STp->buffer->read_pointer = 0;
-			STp->logical_blk_num++;		/* block to look for next time */
-			STp->logical_blk_in_buffer = 0;
+			if (STps->eof == ST_FM_HIT)
+				break;
+			special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0);
 			if (special < 0) { 			/* No need to continue read */
+				STp->frame_in_buffer = 0;
 				retval = special;
 				goto out;
 			}
-			STps->drv_block++;
 		}
 
 		/* Move the data from driver buffer to user buffer */
 		if ((STp->buffer)->buffer_bytes > 0) {
 #if DEBUG
 			if (debugging && STps->eof != ST_NOEOF)
-			    printk(OSST_DEB_MSG "osst%d: EOF up (%d). Left %d, needed %d.\n", dev,
+			    printk(OSST_DEB_MSG "osst%d:D: EOF up (%d). Left %d, needed %d.\n", dev,
 						 STps->eof, (STp->buffer)->buffer_bytes, count - total);
 #endif
-			transfer = (STp->buffer)->buffer_bytes < count - total ?
-				   (STp->buffer)->buffer_bytes : count - total;
+			transfer = (((STp->buffer)->buffer_bytes < count - total ?
+				     (STp->buffer)->buffer_bytes : count - total)/
+					STp->block_size) * STp->block_size; /* force multiple of block size */
 			i = from_buffer(STp->buffer, buf, transfer);
 			if (i)  {
 				retval = i;
 				goto out;
 			}
-			filp->f_pos += transfer;
-			buf += transfer;
-			total += transfer;
+			STp->logical_blk_num += transfer / STp->block_size;
+			STps->drv_block      += transfer / STp->block_size;
+			filp->f_pos          += transfer;
+			buf                  += transfer;
+			total                += transfer;
+		}
+ 
+		if ((STp->buffer)->buffer_bytes == 0) {
+#if DEBUG
+			if (debugging)
+				printk(OSST_DEB_MSG "osst%d:D: Finished with frame %d\n",
+					       	dev, STp->frame_seq_number);
+#endif
+			STp->frame_in_buffer = 0;
+			STp->frame_seq_number++;              /* frame to look for next time */
 		}
-
 	} /* for (total = 0, special = 0; total < count && !special; ) */
 
 	/* Change the eof state if no data from tape or buffer */
@@ -3253,21 +3514,21 @@
 static void osst_log_options(OS_Scsi_Tape *STp, ST_mode *STm, int dev)
 {
   printk(KERN_INFO
-"osst%d: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
+"osst%d:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
 	 dev, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
 	 STm->do_read_ahead);
   printk(KERN_INFO
-"osst%d:    can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
+"osst%d:I:    can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
 	 dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
   printk(KERN_INFO
-"osst%d:    defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
+"osst%d:I:    defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
 	 dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
 	 STp->scsi2_logical);
   printk(KERN_INFO
-"osst%d:    sysv: %d\n", dev, STm->sysv);
+"osst%d:I:    sysv: %d\n", dev, STm->sysv);
 #if DEBUG
   printk(KERN_INFO
-	 "osst%d:    debugging: %d\n",
+	 "osst%d:D:    debugging: %d\n",
 	 dev, debugging);
 #endif
 }
@@ -3286,7 +3547,7 @@
 		modes_defined = TRUE;
 #if DEBUG
 		if (debugging)
-			printk(OSST_DEB_MSG "osst%d: Initialized mode %d definition from mode 0\n",
+			printk(OSST_DEB_MSG "osst%d:D: Initialized mode %d definition from mode 0\n",
 					     dev, STp->current_mode);
 #endif
 	}
@@ -3347,23 +3608,28 @@
 	else if (code == MT_ST_WRITE_THRESHOLD) {
 		value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
 		if (value < 1 || value > osst_buffer_size) {
-			printk(KERN_WARNING "osst%d: Write threshold %d too small or too large.\n",
+			printk(KERN_WARNING "osst%d:W: Write threshold %d too small or too large.\n",
 					     dev, value);
 			return (-EIO);
 		}
 		STp->write_threshold = value;
-		printk(KERN_INFO "osst%d: Write threshold set to %d bytes.\n",
+		printk(KERN_INFO "osst%d:I: Write threshold set to %d bytes.\n",
 				  dev, value);
 	}
 	else if (code == MT_ST_DEF_BLKSIZE) {
 		value = (options & ~MT_ST_OPTIONS);
 		if (value == ~MT_ST_OPTIONS) {
 			STm->default_blksize = (-1);
-			printk(KERN_INFO "osst%d: Default block size disabled.\n", dev);
+			printk(KERN_INFO "osst%d:I: Default block size disabled.\n", dev);
 		}
 		else {
+			if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) {
+				printk(KERN_WARNING "osst%d:W: Default block size cannot be set to %d.\n",
+							 dev, value);
+				return (-EINVAL);
+			}
 			STm->default_blksize = value;
-			printk(KERN_INFO "osst%d: Default block size set to %d bytes.\n",
+			printk(KERN_INFO "osst%d:I: Default block size set to %d bytes.\n",
 					  dev, STm->default_blksize);
 		}
 	}
@@ -3371,12 +3637,12 @@
 		value = (options & ~MT_ST_OPTIONS);
 		if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
 			STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
-			printk(KERN_INFO "osst%d: Long timeout set to %d seconds.\n", dev,
+			printk(KERN_INFO "osst%d:I: Long timeout set to %d seconds.\n", dev,
 					     (value & ~MT_ST_SET_LONG_TIMEOUT));
 		}
 		else {
 			STp->timeout = value * HZ;
-			printk(KERN_INFO "osst%d: Normal timeout set to %d seconds.\n", dev, value);
+			printk(KERN_INFO "osst%d:I: Normal timeout set to %d seconds.\n", dev, value);
 		}
 	}
 	else if (code == MT_ST_DEF_OPTIONS) {
@@ -3385,33 +3651,33 @@
 		if (code == MT_ST_DEF_DENSITY) {
 			if (value == MT_ST_CLEAR_DEFAULT) {
 				STm->default_density = (-1);
-				printk(KERN_INFO "osst%d: Density default disabled.\n", dev);
+				printk(KERN_INFO "osst%d:I: Density default disabled.\n", dev);
 			}
 			else {
 				STm->default_density = value & 0xff;
-				printk(KERN_INFO "osst%d: Density default set to %x\n",
+				printk(KERN_INFO "osst%d:I: Density default set to %x\n",
 						  dev, STm->default_density);
 			}
 		}
 		else if (code == MT_ST_DEF_DRVBUFFER) {
 			if (value == MT_ST_CLEAR_DEFAULT) {
 				STp->default_drvbuffer = 0xff;
-				printk(KERN_INFO "osst%d: Drive buffer default disabled.\n", dev);
+				printk(KERN_INFO "osst%d:I: Drive buffer default disabled.\n", dev);
 			}
 			else {
 				STp->default_drvbuffer = value & 7;
-				printk(KERN_INFO "osst%d: Drive buffer default set to %x\n",
+				printk(KERN_INFO "osst%d:I: Drive buffer default set to %x\n",
 						  dev, STp->default_drvbuffer);
 			}
 		}
 		else if (code == MT_ST_DEF_COMPRESSION) {
 			if (value == MT_ST_CLEAR_DEFAULT) {
 				STm->default_compression = ST_DONT_TOUCH;
-				printk(KERN_INFO "osst%d: Compression default disabled.\n", dev);
+				printk(KERN_INFO "osst%d:I: Compression default disabled.\n", dev);
 			}
 			else {
 				STm->default_compression = (value & 1 ? ST_YES : ST_NO);
-				printk(KERN_INFO "osst%d: Compression default set to %x\n",
+				printk(KERN_INFO "osst%d:I: Compression default set to %x\n",
 						  dev, (value & 1));
 			}
 		}
@@ -3433,7 +3699,7 @@
 	unsigned char cmd[MAX_COMMAND_SIZE];
 	Scsi_Request * SRpnt = * aSRpnt;
 	ST_partstat * STps;
-	int fileno, blkno, at_sm, logical_blk_num;
+	int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num;
 	int datalen = 0, direction = SCSI_DATA_NONE;
 	int dev = TAPE_NR(STp->devt);
 
@@ -3448,6 +3714,7 @@
 	fileno = STps->drv_file;
 	blkno = STps->drv_block;
 	at_sm = STps->at_sm;
+	frame_seq_numbr = STp->frame_seq_number;
 	logical_blk_num = STp->logical_blk_num;
 
 	memset(cmd, 0, MAX_COMMAND_SIZE);
@@ -3461,7 +3728,6 @@
 		   ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg);
 		else
 		   ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg);
-		logical_blk_num = STp->logical_blk_num;
 		if (fileno >= 0)
 		   fileno += arg;
 		blkno = 0;
@@ -3474,7 +3740,6 @@
 		if (STp->raw)
 		   return (-EIO);
 		ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg);
-		logical_blk_num = STp->logical_blk_num;
 		if (fileno >= 0)
 		   fileno -= arg;
 		blkno = (-1);  /* We can't know the block number */
@@ -3485,7 +3750,7 @@
 	 case MTBSR:
 #if DEBUG
 		if (debugging)
-		   printk(OSST_DEB_MSG "osst%i: Skipping %lu blocks %s from logical block %d\n",
+		   printk(OSST_DEB_MSG "osst%d:D: Skipping %lu blocks %s from logical block %d\n",
 				dev, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num);
 #endif
 		if (cmd_in == MTFSR) {
@@ -3496,8 +3761,9 @@
 		   logical_blk_num -= arg;
 		   if (blkno >= 0) blkno -= arg;
 		}
-		ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num-1);
-		STp->logical_blk_in_buffer = 0;
+		ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num);
+		fileno = STps->drv_file;
+		blkno  = STps->drv_block;
 		at_sm &= (arg == 0);
 		goto os_bypass;
 
@@ -3509,7 +3775,7 @@
 		cmd[4] = arg;
 #if DEBUG
 		if (debugging)
-			printk(OSST_DEB_MSG "osst%d: Spacing tape forward %d setmarks.\n", dev,
+			printk(OSST_DEB_MSG "osst%d:D: Spacing tape forward %d setmarks.\n", dev,
 		cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
 #endif
 		if (arg != 0) {
@@ -3528,33 +3794,32 @@
 		if (debugging) {
 			if (cmd[2] & 0x80)
 			   ltmp = 0xff000000;
-			 ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
-			 printk(OSST_DEB_MSG "osst%d: Spacing tape backward %ld setmarks.\n",
+			ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
+			printk(OSST_DEB_MSG "osst%d:D: Spacing tape backward %ld setmarks.\n",
 						dev, (-ltmp));
 		 }
 #endif
 		 if (arg != 0) {
 			blkno = fileno = (-1);
-			 at_sm = 1;
+			at_sm = 1;
 		 }
 		 break;
 	 case MTWEOF:
 		 if ( STps->rw == ST_WRITING && !(STp->device)->was_reset)
-			 ioctl_result = osst_flush_write_buffer(STp, &SRpnt, 1);
+			ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
 		 else
-			 ioctl_result = 0;
+			ioctl_result = 0;
 		 for (i=0; i<arg; i++)
-			 ioctl_result |= osst_write_filemark(STp, &SRpnt);
-		 logical_blk_num = STp->logical_blk_num;
+			ioctl_result |= osst_write_filemark(STp, &SRpnt);
 		 if (fileno >= 0) fileno += arg;
 		 if (blkno  >= 0) blkno   = 0;
 		 goto os_bypass;
 
 	 case MTWSM:
 		 if (STp->write_prot)
-			 return (-EACCES);
+			return (-EACCES);
 		 if (!STp->raw)
-			 return 0;
+			return 0;
 		 cmd[0] = WRITE_FILEMARKS;   /* FIXME -- need OS version */
 		 if (cmd_in == MTWSM)
 			 cmd[1] = 2;
@@ -3564,16 +3829,16 @@
 		 timeout = STp->timeout;
 #if DEBUG
 		 if (debugging) {
-			 if (cmd_in == MTWEOF)
-			   printk(OSST_DEB_MSG "osst%d: Writing %d filemarks.\n", dev,
+			if (cmd_in == MTWEOF)
+			   printk(OSST_DEB_MSG "osst%d:D: Writing %d filemarks.\n", dev,
 				  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-			 else
-			   printk(OSST_DEB_MSG "osst%d: Writing %d setmarks.\n", dev,
+			else
+			   printk(OSST_DEB_MSG "osst%d:D: Writing %d setmarks.\n", dev,
 				  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
 		 }
 #endif
 		 if (fileno >= 0)
-			 fileno += arg;
+			fileno += arg;
 		 blkno = 0;
 		 at_sm = (cmd_in == MTWSM);
 		 break;
@@ -3594,50 +3859,49 @@
 		 if (debugging) {
 			 switch (cmd_in) {
 				 case MTUNLOAD:
-					 printk(OSST_DEB_MSG "osst%d: Unloading tape.\n", dev);
+					 printk(OSST_DEB_MSG "osst%d:D: Unloading tape.\n", dev);
 					 break;
 				 case MTLOAD:
-					 printk(OSST_DEB_MSG "osst%d: Loading tape.\n", dev);
+					 printk(OSST_DEB_MSG "osst%d:D: Loading tape.\n", dev);
 					 break;
 				 case MTRETEN:
-					 printk(OSST_DEB_MSG "osst%d: Retensioning tape.\n", dev);
+					 printk(OSST_DEB_MSG "osst%d:D: Retensioning tape.\n", dev);
 					 break;
 				 case MTOFFL:
-					 printk(OSST_DEB_MSG "osst%d: Ejecting tape.\n", dev);
+					 printk(OSST_DEB_MSG "osst%d:D: Ejecting tape.\n", dev);
 					 break;
 			 }
 		 }
 #endif
-		 fileno = blkno = at_sm = logical_blk_num = 0 ;
+       fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
 		 break;
 	 case MTNOP:
 #if DEBUG
 		 if (debugging)
-			 printk(OSST_DEB_MSG "osst%d: No op on tape.\n", dev);
+			 printk(OSST_DEB_MSG "osst%d:D: No-op on tape.\n", dev);
 #endif
 		 return 0;  /* Should do something ? */
 		 break;
 	 case MTEOM:
 #if DEBUG
 		if (debugging)
-		   printk(OSST_DEB_MSG "osst%d: Spacing to end of recorded medium.\n", dev);
+		   printk(OSST_DEB_MSG "osst%d:D: Spacing to end of recorded medium.\n", dev);
 #endif
 		osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
-		if (osst_get_logical_blk(STp, &SRpnt, -1, 0) < 0) {
+	if (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0) {
 		   ioctl_result = -EIO;
 		   goto os_bypass;
 		}
 		if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) {
 #if DEBUG
-		   printk(OSST_DEB_MSG "osst%d: No EOD frame found where expected.\n", dev);
+		   printk(OSST_DEB_MSG "osst%d:D: No EOD frame found where expected.\n", dev);
 #endif
 		   ioctl_result = -EIO;
 		   goto os_bypass;
 		}
 		ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
-		logical_blk_num = STp->logical_blk_num;
-		fileno          = STp->filemark_cnt;
-		blkno  = at_sm  = 0;
+		fileno = STp->filemark_cnt;
+		blkno  = at_sm = 0;
 		goto os_bypass;
 
 	 case MTERASE:
@@ -3648,7 +3912,7 @@
 		if (i < ioctl_result) ioctl_result = i;
 		i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos);
 		if (i < ioctl_result) ioctl_result = i;
-		fileno = blkno = at_sm = logical_blk_num = 0 ;
+		fileno = blkno = at_sm = 0 ;
 		goto os_bypass;
 
 	 case MTREW:
@@ -3656,9 +3920,9 @@
 		cmd[1] = 1;
 #if DEBUG
 		if (debugging)
-		   printk(OSST_DEB_MSG "osst%d: Rewinding tape, Immed=%d.\n", dev, cmd[1]);
+		   printk(OSST_DEB_MSG "osst%d:D: Rewinding tape, Immed=%d.\n", dev, cmd[1]);
 #endif
-		fileno = blkno = at_sm = logical_blk_num = 0 ;
+		fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
 		break;
 
 	 case MTLOCK:
@@ -3667,8 +3931,8 @@
 		cmd[4] = SCSI_REMOVAL_PREVENT;
 #if DEBUG
 		if (debugging)
-		    printk(OSST_DEB_MSG "osst%d: Locking drive door.\n", dev);
-#endif;
+		    printk(OSST_DEB_MSG "osst%d:D: Locking drive door.\n", dev);
+#endif
 		break;
 
 	 case MTUNLOCK:
@@ -3677,8 +3941,8 @@
 		cmd[4] = SCSI_REMOVAL_ALLOW;
 #if DEBUG
 		if (debugging)
-		   printk(OSST_DEB_MSG "osst%d: Unlocking drive door.\n", dev);
-#endif;
+		   printk(OSST_DEB_MSG "osst%d:D: Unlocking drive door.\n", dev);
+#endif
 	break;
 
 	 case MTSETBLK:           /* Set block length */
@@ -3693,10 +3957,10 @@
 		   ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block ||
 		    (arg & MT_ST_BLKSIZE_MASK) > STp->max_block ||
 		    (arg & MT_ST_BLKSIZE_MASK) > osst_buffer_size)) {
-			 printk(KERN_WARNING "osst%d: Illegal block size.\n", dev);
+			 printk(KERN_WARNING "osst%d:W: Illegal block size.\n", dev);
 			 return (-EINVAL);
 		 }
-		 return 0;  /* silently ignore if block size didn't change */
+		 return 0;  /* FIXME silently ignore if block size didn't change */
 
 	 default:
 		return (-ENOSYS);
@@ -3708,18 +3972,23 @@
 
 	if (!SRpnt) {
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%d: Couldn't exec scsi cmd for IOCTL\n", dev);
+		printk(OSST_DEB_MSG "osst%d:D: Couldn't exec scsi cmd for IOCTL\n", dev);
 #endif
 		return ioctl_result;
 	}
 
+	if (!ioctl_result) {  /* SCSI command successful */
+		STp->frame_seq_number = frame_seq_numbr;
+		STp->logical_blk_num  = logical_blk_num;
+	}
+
 os_bypass:
 #if DEBUG
 	if (debugging)
-		printk(OSST_DEB_MSG "osst%d: IOCTL (%d) Result=%d\n", dev, cmd_in, ioctl_result);
+		printk(OSST_DEB_MSG "osst%d:D: IOCTL (%d) Result=%d\n", dev, cmd_in, ioctl_result);
 #endif
 
-	if (!ioctl_result) {  /* SCSI command successful */
+	if (!ioctl_result) {
 
 		if (cmd_in == MTFSFM) {
 			 fileno--;
@@ -3732,7 +4001,6 @@
 		STps->drv_block = blkno;
 		STps->drv_file = fileno;
 		STps->at_sm = at_sm;
-		STp->logical_blk_num = logical_blk_num;
 
 		if (cmd_in == MTLOCK)
 			 STp->door_locked = ST_LOCKED_EXPLICIT;
@@ -3752,7 +4020,7 @@
 /*      		STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;  FIXME */
 			for (i=0; i < ST_NBR_PARTITIONS; i++) {
 			    STp->ps[i].rw = ST_IDLE;
-			    STp->ps[i].last_block_valid = FALSE;
+			    STp->ps[i].last_block_valid = FALSE;/* FIXME - where else is this field maintained? */
 			}
 			STp->partition = 0;
 		}
@@ -3826,7 +4094,7 @@
 
 	if (STp->in_use) {
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%d: Device already in use.\n", dev);
+		printk(OSST_DEB_MSG "osst%d:D: Device already in use.\n", dev);
 #endif
 		return (-EBUSY);
 	}
@@ -3841,7 +4109,7 @@
 	if (mode != STp->current_mode) {
 #if DEBUG
 		if (debugging)
-			printk(OSST_DEB_MSG "osst%d: Mode change from %d to %d.\n",
+			printk(OSST_DEB_MSG "osst%d:D: Mode change from %d to %d.\n",
 					       dev, STp->current_mode, mode);
 #endif
 		new_session = TRUE;
@@ -3863,7 +4131,7 @@
 	if (i >= osst_nbr_buffers) {
 		STp->buffer = new_tape_buffer(FALSE, need_dma_buffer);
 		if (STp->buffer == NULL) {
-			printk(KERN_WARNING "osst%d: Can't allocate tape buffer.\n", dev);
+			printk(KERN_WARNING "osst%d:W: Can't allocate tape buffer.\n", dev);
 			retval = (-EBUSY);
 			goto err_out;
 		}
@@ -3890,7 +4158,6 @@
 		STps->rw = ST_IDLE;
 	}
 	STp->ready = ST_READY;
-	STp->recover_count = 0;
 #if DEBUG
 	STp->nbr_waits = STp->nbr_finished = 0;
 #endif
@@ -3907,7 +4174,7 @@
 	    (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
 	     SRpnt->sr_sense_buffer[12]        == 4         ) {
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%d: Unit not ready, cause %x\n", dev, SRpnt->sr_sense_buffer[13]);
+		printk(OSST_DEB_MSG "osst%d:D: Unit not ready, cause %x\n", dev, SRpnt->sr_sense_buffer[13]);
 #endif
 		if (SRpnt->sr_sense_buffer[13] == 2) {	/* initialize command required (LOAD) */
 			memset (cmd, 0, MAX_COMMAND_SIZE);
@@ -3922,7 +4189,7 @@
 	if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
 	    (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%d: Unit wants attention\n", dev);
+		printk(OSST_DEB_MSG "osst%d:D: Unit wants attention\n", dev);
 #endif
 		STp->header_ok = 0;
 
@@ -3944,7 +4211,7 @@
 			STp->nbr_partitions = 1;  /* This guess will be updated later if necessary */
 		for (i=0; i < ST_NBR_PARTITIONS; i++) {
 			STps = &(STp->ps[i]);
-			STps->rw = ST_IDLE;
+			STps->rw = ST_IDLE;			/* FIXME - seems to be redundant... */
 			STps->eof = ST_NOEOF;
 			STps->at_sm = 0;
 			STps->last_block_valid = FALSE;
@@ -3952,6 +4219,7 @@
 			STps->drv_file = 0 ;
 		}
 		new_session = TRUE;
+		STp->recover_count = 0;
 	}
 	/*
 	 * if we have valid headers from before, and the drive/tape seem untouched,
@@ -3974,7 +4242,7 @@
 		    STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' ||
 		    STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4'  ) {
 #if DEBUG
-			printk(OSST_DEB_MSG "osst%d: signature was changed to %c%c%c%c\n", dev,
+			printk(OSST_DEB_MSG "osst%d:D: Signature was changed to %c%c%c%c\n", dev,
 			  STp->buffer->b_data[MODE_HEADER_LENGTH + 2],
 			  STp->buffer->b_data[MODE_HEADER_LENGTH + 3],
 			  STp->buffer->b_data[MODE_HEADER_LENGTH + 4],
@@ -3986,17 +4254,23 @@
 		if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) {
 			if (STp->door_locked == ST_UNLOCKED) {
 				if (osst_int_ioctl(STp, &SRpnt, MTLOCK, 0))
-					printk(KERN_WARNING "osst%d: Can't lock drive door\n", dev);
+					printk(KERN_INFO "osst%d:I: Can't lock drive door\n", dev);
 				else
 					STp->door_locked = ST_LOCKED_AUTO;
 			}
+			if (!STp->frame_in_buffer) {
+				STp->block_size = (STp->raw) ? OS_FRAME_SIZE : (
+					    (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
+				STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
+			}
+			STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
 			STp->fast_open = TRUE;
 			scsi_release_request(SRpnt);
 			return 0;
 		}
 #if DEBUG
 		if (i != STp->first_frame_position)
-			printk(OSST_DEB_MSG "osst%d: tape position changed from %d to %d\n",
+			printk(OSST_DEB_MSG "osst%d:D: Tape position changed from %d to %d\n",
 						dev, i, STp->first_frame_position);
 #endif
 		STp->header_ok = 0;
@@ -4020,8 +4294,8 @@
 		(STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2;
 		(STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3;
 
-#if 1 //DEBUG
-		printk(OSST_DEB_MSG "osst%i: Applying soft reset\n", dev);
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d:D: Applying soft reset\n", dev);
 #endif
 		SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE);
 
@@ -4058,7 +4332,7 @@
 	}
 
 	if (osst_wait_ready(STp, &SRpnt, 15 * 60))		/* FIXME - not allowed with NOBLOCK */
-		 printk(KERN_WARNING "osst%i: Device did not become Ready in open\n",dev);
+		 printk(KERN_INFO "osst%i:I: Device did not become Ready in open\n",dev);
 
 	if ((STp->buffer)->syscall_result != 0) {
 		if ((STp->device)->scsi_level >= SCSI_2 &&
@@ -4087,7 +4361,7 @@
 
 	if (OS_FRAME_SIZE > (STp->buffer)->buffer_size &&
 	    !enlarge_buffer(STp->buffer, OS_FRAME_SIZE, STp->restr_dma)) {
-		printk(KERN_NOTICE "osst%d: Framesize %d too large for buffer.\n", dev,
+		printk(KERN_NOTICE "osst%d:A: Framesize %d too large for buffer.\n", dev,
 				     OS_FRAME_SIZE);
 		retval = (-EIO);
 		goto err_out;
@@ -4099,22 +4373,26 @@
 		     b_size += STp->buffer->sg[i++].length);
 		STp->buffer->aux = (os_aux_t *) (STp->buffer->sg[i].address + OS_DATA_SIZE - b_size);
 #if DEBUG
-		printk(OSST_DEB_MSG "osst%d: b_data points to %p in segment 0 at %p\n", dev,
+		printk(OSST_DEB_MSG "osst%d:D: b_data points to %p in segment 0 at %p\n", dev,
 			STp->buffer->b_data, STp->buffer->sg[0].address);
-		printk(OSST_DEB_MSG "osst%d: AUX points to %p in segment %d at %p\n", dev,
+		printk(OSST_DEB_MSG "osst%d:D: AUX points to %p in segment %d at %p\n", dev,
 			 STp->buffer->aux, i, STp->buffer->sg[i].address);
 #endif
 	} else
 		STp->buffer->aux = NULL; /* this had better never happen! */
 
-	(STp->buffer)->buffer_blocks = 1;
-	(STp->buffer)->buffer_bytes  =
-	(STp->buffer)->read_pointer  =
-	STp->logical_blk_in_buffer   = 0;
+	STp->block_size = (STp->raw) ? OS_FRAME_SIZE : (
+			     (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
+	STp->min_block  = 512;
+	STp->max_block  = OS_DATA_SIZE;
+	STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
+	STp->buffer->buffer_bytes  =
+	STp->buffer->read_pointer  =
+	STp->frame_in_buffer       = 0;
 
 #if DEBUG
 	if (debugging)
-		printk(OSST_DEB_MSG "osst%d: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n",
+		printk(OSST_DEB_MSG "osst%d:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n",
 		     dev, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size,
 		     (STp->buffer)->buffer_blocks);
 #endif
@@ -4123,7 +4401,7 @@
 		STp->write_prot = 1;
 #if DEBUG
 		if (debugging)
-			printk(OSST_DEB_MSG "osst%d: Write protected\n", dev);
+			printk(OSST_DEB_MSG "osst%d:D: Write protected\n", dev);
 #endif
 		if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
 			retval = (-EROFS);
@@ -4134,7 +4412,7 @@
 	if (new_session) {  /* Change the drive parameters for the new mode */
 #if DEBUG
 		if (debugging)
-	printk(OSST_DEB_MSG "osst%d: New Session\n", dev);
+	printk(OSST_DEB_MSG "osst%d:D: New Session\n", dev);
 #endif
 		STp->density_changed = STp->blksize_changed = FALSE;
 		STp->compression_changed = FALSE;
@@ -4145,7 +4423,7 @@
 	 */
 	if (STp->door_locked == ST_UNLOCKED) {
 		 if (osst_int_ioctl(STp, &SRpnt, MTLOCK, 0))
-			printk(KERN_WARNING "osst%d: Can't lock drive door\n", dev);
+			printk(KERN_INFO "osst%d:I: Can't lock drive door\n", dev);
 		 else
 			STp->door_locked = ST_LOCKED_AUTO;
 	}
@@ -4197,18 +4475,17 @@
 	STps = &(STp->ps[STp->partition]);
 
 	if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) {
-		result = osst_flush_write_buffer(STp, &SRpnt, 1);
+		result = osst_flush_write_buffer(STp, &SRpnt);
 		if (result != 0 && result != (-ENOSPC))
-	  goto out;
+			goto out;
 	}
-
 	if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) {
 
 #if DEBUG
 		if (debugging) {
-			printk(OSST_DEB_MSG "osst%d: File length %ld bytes.\n",
+			printk(OSST_DEB_MSG "osst%d:D: File length %ld bytes.\n",
 					       dev, (long)(filp->f_pos));
-			printk(OSST_DEB_MSG "osst%d: Async write waits %d, finished %d.\n",
+			printk(OSST_DEB_MSG "osst%d:D: Async write waits %d, finished %d.\n",
 					       dev, STp->nbr_waits, STp->nbr_finished);
 		}
 #endif
@@ -4229,7 +4506,7 @@
 
 #if DEBUG
 		if (debugging)
-			printk(OSST_DEB_MSG "osst%d: Buffer flushed, %d EOF(s) written\n",
+			printk(OSST_DEB_MSG "osst%d:D: Buffer flushed, %d EOF(s) written\n",
 					       dev, 1+STp->two_fm);
 #endif
 	}
@@ -4237,7 +4514,7 @@
 		STps = &(STp->ps[STp->partition]);
 		if (!STm->sysv || STps->rw != ST_READING) {
 			if (STp->can_bsr)
-				result = osst_flush_buffer(STp, &SRpnt, 0);
+		result = osst_flush_buffer(STp, &SRpnt, 0);	/* this is the default path */
 			else if (STps->eof == ST_FM_HIT) {
 				result = cross_eof(STp, &SRpnt, FALSE);
 					if (result) {
@@ -4263,12 +4540,24 @@
 out:
 	if (STp->rew_at_close) {
 		result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
-		STps->drv_file = STps->drv_block = STp->logical_blk_num = 0;
-		if (result == 0)
+		STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
+		if (result == 0 && result2 < 0)
 			result = result2;
 	}
 	if (SRpnt) scsi_release_request(SRpnt);
 
+	if (STp->recover_count) {
+		printk(KERN_INFO "osst%d:I: %d recovered errors in", dev, STp->recover_count);
+		if (STp->write_count)
+			printk(" %d frames written", STp->write_count);
+		if (STp->read_count)
+			printk(" %d frames read", STp->read_count);
+		printk("\n");
+		STp->recover_count = 0;
+	}
+	STp->write_count = 0;
+	STp->read_count  = 0;
+
 	return result;
 }
 
@@ -4322,7 +4611,7 @@
 
 #if DEBUG
 	if (debugging && !STp->in_use) {
-		printk(OSST_DEB_MSG "osst%d: Incorrect device.\n", dev);
+		printk(OSST_DEB_MSG "osst%d:D: Incorrect device.\n", dev);
 		retval = (-EIO);
 		goto out;
 	}
@@ -4359,7 +4648,7 @@
 		}
 
 		if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
-			printk(KERN_WARNING "osst%d: MTSETDRVBUFFER only allowed for root.\n", dev);
+			printk(KERN_WARNING "osst%d:W: MTSETDRVBUFFER only allowed for root.\n", dev);
 			retval = (-EPERM);
 			goto out;
 		}
@@ -4419,7 +4708,7 @@
 			if (STp->door_locked != ST_UNLOCKED &&
 			    STp->door_locked != ST_LOCK_FAILS) {
 				if (osst_int_ioctl(STp, &SRpnt, MTLOCK, 0)) {
-					printk(KERN_NOTICE "osst%d: Could not relock door after bus reset.\n",
+					printk(KERN_NOTICE "osst%d:I: Could not relock door after bus reset.\n",
 								  dev);
 					STp->door_locked = ST_UNLOCKED;
 				}
@@ -4479,7 +4768,7 @@
 	 	}
 
 		if (mtc.mt_op == MTSEEK) {
-			i = osst_seek_frame(STp, &SRpnt, mtc.mt_count);
+			i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
 			if (!STp->can_partitions)
 				STp->ps[0].rw = ST_IDLE;
 			retval = i;
@@ -4584,7 +4873,7 @@
 			retval = (-EINVAL);
 			goto out;
 		}
-		blk = osst_get_frame_position(STp, &SRpnt);
+		blk = osst_get_sector(STp, &SRpnt);
 		if (blk < 0) {
 			retval = blk;
 			goto out;
@@ -4687,7 +4976,7 @@
 		}
 	}
 	if (!tb) {
-		printk(KERN_NOTICE "osst: Can't allocate new tape buffer (nbr %d).\n",
+		printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer (nbr %d).\n",
 				   osst_nbr_buffers);
 		return NULL;
 	}
@@ -4697,10 +4986,10 @@
 #if DEBUG
 	if (debugging) {
 		printk(OSST_DEB_MSG
-			"osst: Allocated tape buffer %d (%d bytes, %d segments, dma: %d, a: %p).\n",
+			"osst :D: Allocated tape buffer %d (%d bytes, %d segments, dma: %d, a: %p).\n",
 			   osst_nbr_buffers, got, tb->sg_segs, need_dma, tb->b_data);
 		printk(OSST_DEB_MSG
-			"osst: segment sizes: first %d, last %d bytes.\n",
+			"osst :D: segment sizes: first %d, last %d bytes.\n",
 			   tb->sg[0].length, tb->sg[segs-1].length);
 	}
 #endif
@@ -4745,7 +5034,7 @@
 				order--;
 				continue;
 			}
-			printk(KERN_NOTICE "osst: Failed to enlarge buffer to %d bytes.\n",
+			printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
 						new_size);
 #if DEBUG
 			STbuffer->buffer_size = got;
@@ -4764,10 +5053,10 @@
 	if (debugging) {
 		for (nbr=0; osst_buffers[nbr] != STbuffer && nbr < osst_nbr_buffers; nbr++);
 			printk(OSST_DEB_MSG
-	"osst: Expanded tape buffer %d (%d bytes, %d->%d segments, dma: %d, a: %p).\n",
+			   "osst :D: Expanded tape buffer %d (%d bytes, %d->%d segments, dma: %d, a: %p).\n",
 			   nbr, got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
 			printk(OSST_DEB_MSG
-			   "osst: segment sizes: first %d, last %d bytes.\n",
+			   "osst :D: segment sizes: first %d, last %d bytes.\n",
 			   STbuffer->sg[0].length, STbuffer->sg[segs-1].length);
 	}
 #endif
@@ -4792,7 +5081,7 @@
 	}
 #if DEBUG
 	if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
-		printk(OSST_DEB_MSG "osst: Buffer at %p normalized to %d bytes (segs %d).\n",
+		printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n",
 			     STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
 #endif
 	STbuffer->sg_segs = STbuffer->orig_sg_segs;
@@ -4809,7 +5098,7 @@
 	     i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
 	offset -= st_bp->sg[i].length;
 	if (i == st_bp->sg_segs) {  /* Should never happen */
-		printk(KERN_WARNING "osst: Append_to_buffer offset overflow.\n");
+		printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n");
 		return (-EIO);
 	}
 	for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
@@ -4824,7 +5113,7 @@
 		offset = 0;
 	}
 	if (do_count) {  /* Should never happen */
-		printk(KERN_WARNING "osst: Append_to_buffer overflow (left %d).\n",
+		printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n",
 		       do_count);
 		return (-EIO);
 	}
@@ -4842,7 +5131,7 @@
 	     i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
 		offset -= st_bp->sg[i].length;
 	if (i == st_bp->sg_segs) {  /* Should never happen */
-		printk(KERN_WARNING "osst: From_buffer offset overflow.\n");
+		printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n");
 		return (-EIO);
 	}
 	for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
@@ -4858,7 +5147,7 @@
 		offset = 0;
 	}
 	if (do_count) {  /* Should never happen */
-		printk(KERN_WARNING "osst: From_buffer overflow (left %d).\n", do_count);
+		printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count);
 		return (-EIO);
 	}
 	return 0;
@@ -4874,10 +5163,10 @@
 	     i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
 		offset -= st_bp->sg[i].length;
 	if (i == st_bp->sg_segs) {  /* Should never happen */
-		printk(KERN_WARNING "osst: Zero_buffer offset overflow.\n");
+		printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n");
 		return (-EIO);
 	}
-	for (do_count = OS_DATA_SIZE - st_bp->read_pointer;
+	for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes;
 	     i < st_bp->sg_segs && do_count > 0; i++) {
 		cnt = st_bp->sg[i].length - offset < do_count ?
 		      st_bp->sg[i].length - offset : do_count ;
@@ -4886,13 +5175,13 @@
 		offset = 0;
 	}
 	if (do_count) {  /* Should never happen */
-		printk(KERN_WARNING "osst: Zero_buffer overflow (left %d).\n", do_count);
+		printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count);
 		return (-EIO);
 	}
 	return 0;
 }
 
-/* Copy a osst 32K block of memory into the buffer.
+/* Copy a osst 32K chunk of memory into the buffer.
    Returns zero (success) or negative error code.  */
 static int osst_copy_to_buffer(OSST_buffer *st_bp, unsigned char *ptr)
 {
@@ -4906,14 +5195,14 @@
 		ptr      += cnt;
 	}
 	if (do_count || i != st_bp->sg_segs-1) {  /* Should never happen */
-		printk(KERN_WARNING "osst: Copy_to_buffer overflow (left %d at sg %d).\n",
+		printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n",
 					 do_count, i);
 		return (-EIO);
 	}
 	return 0;
 }
 
-/* Copy a osst 32K block of memory from the buffer.
+/* Copy a osst 32K chunk of memory from the buffer.
    Returns zero (success) or negative error code.  */
 static int osst_copy_from_buffer(OSST_buffer *st_bp, unsigned char *ptr)
 {
@@ -4927,7 +5216,7 @@
 		ptr      += cnt;
 	}
 	if (do_count || i != st_bp->sg_segs-1) {  /* Should never happen */
-		printk(KERN_WARNING "osst: Copy_from_buffer overflow (left %d at sg %d).\n",
+		printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n",
 					 do_count, i);
 		return (-EIO);
 	}
@@ -4949,9 +5238,12 @@
 		osst_max_buffers = max_buffers;
   if (max_sg_segs >= OSST_FIRST_SG)
 		osst_max_sg_segs = max_sg_segs;
-  printk(KERN_INFO "osst: bufsize %d, wrt %d, max buffers %d, s/g segs %d.\n",
+#if DEBUG
+  printk(OSST_DEB_MSG "osst :D: bufsize %d, wrt %d, max buffers %d, s/g segs %d.\n",
 	 osst_buffer_size, osst_write_threshold, osst_max_buffers, osst_max_sg_segs);
-//printk(OSST_DEB_MSG "osst: sizeof(header) = %d (%s)\n",sizeof(os_header_t),sizeof(os_header_t)==OS_DATA_SIZE?"ok":"error");
+//printk(OSST_DEB_MSG "osst :D: sizeof(header) = %d (%s)\n",
+//		sizeof(os_header_t),sizeof(os_header_t)==OS_DATA_SIZE?"ok":"error");
+#endif
 }
 	
 #ifndef MODULE
@@ -4980,7 +5272,7 @@
 			}
 		}
 		if (i >= sizeof(parms) / sizeof(struct osst_dev_parm))
-			printk(KERN_WARNING "osst: illegal parameter in '%s'\n",
+			printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n",
 			       stp);
 		stp = strchr(stp, ',');
 		if (stp)
@@ -5038,7 +5330,7 @@
 	OS_Scsi_Tape * tpnt;
 	ST_mode * STm;
 	ST_partstat * STps;
-	int i;
+	int i, dev;
 #ifdef CONFIG_DEVFS_FS
 	int mode;
 #endif
@@ -5059,16 +5351,17 @@
 	tpnt = (OS_Scsi_Tape *)kmalloc(sizeof(OS_Scsi_Tape), GFP_ATOMIC);
 	if (tpnt == NULL) {
 		 SDp->attached--;
-		 printk(KERN_ERR "osst: Can't allocate device descriptor.\n");
+		 printk(KERN_WARNING "osst :W: Can't allocate device descriptor.\n");
 		 return 1;
 	}
 	memset(tpnt, 0, sizeof(OS_Scsi_Tape));
 	os_scsi_tapes[i] = tpnt;
+	dev = i;
 	tpnt->capacity = 0xfffff;
 
 	/* allocate a buffer for this device */
 	if (!new_tape_buffer(TRUE, TRUE)) 
-		 printk(KERN_ERR "osst: Unable to allocate a tape buffer.\n");
+		 printk(KERN_ERR "osst :W: Unable to allocate a tape buffer.\n");
 
 #ifdef CONFIG_DEVFS_FS
 	for (mode = 0; mode < ST_NBR_MODES; ++mode) {
@@ -5131,17 +5424,12 @@
 	tpnt->long_timeout = OSST_LONG_TIMEOUT;
 
 	/* Recognize OnStream tapes */
-	printk ("osst%i: Tape driver with OnStream support osst %s\nosst%i: %s\n",
-	       i, osst_version, i, cvsid);
 	/* We don't need to test for OnStream, as this has been done in detect () */
 	tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
-#if DEBUG
-	printk ("osst%i: OnStream tape drive recognized, Model %s\n", i, SDp->model);
-#endif
 	tpnt->omit_blklims = 1;
 
 	tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp);
-	tpnt->logical_blk_in_buffer = 0;
+	tpnt->frame_in_buffer = 0;
 	tpnt->header_ok = 0;
 	tpnt->linux_media = 0;
 	tpnt->header_cache = NULL;
@@ -5155,7 +5443,7 @@
 		STm->do_buffer_writes = OSST_BUFFER_WRITES;
 		STm->do_read_ahead = OSST_READ_AHEAD;
 		STm->default_compression = ST_DONT_TOUCH;
-		STm->default_blksize = 32 * ST_KILOBYTE;  /* No forced size */
+		STm->default_blksize = 512;
 		STm->default_density = (-1);  /* No forced density */
 	}
 
@@ -5175,6 +5463,11 @@
 	init_MUTEX(&tpnt->lock);
 
 	osst_template.nr_dev++;
+
+	printk(KERN_INFO
+		"osst :I: Attached OnStream %.5s tape at scsi%d, channel %d, id %d, lun %d as osst%d\n",
+		SDp->model, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun, dev);
+
 	return 0;
 };
 
@@ -5183,10 +5476,7 @@
 	if (SDp->type != TYPE_TAPE) return 0;
 	if ( ! osst_supports(SDp) ) return 0;
 	
-	printk(KERN_WARNING
-		"Detected OnStream scsi tape osst%d at scsi%d, channel %d, id %d, lun %d\n",
-		osst_template.dev_noticed++,
-		SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+	osst_template.dev_noticed++;
 	return 1;
 }
 
@@ -5205,7 +5495,7 @@
 #else
 	if (register_chrdev(MAJOR_NR,"osst",&osst_fops)) {
 #endif
-		printk(KERN_ERR "osst: Unable to get major %d for OnStream tapes\n",MAJOR_NR);
+		printk(KERN_ERR "osst :W: Unable to get major %d for OnStream tapes\n",MAJOR_NR);
 		return 1;
 	}
 	osst_registered++;
@@ -5214,12 +5504,12 @@
   if (os_scsi_tapes) return 0;
   osst_template.dev_max = OSST_MAX_TAPES;
   if (osst_template.dev_max > 128 / ST_NBR_MODES)
-	printk(KERN_INFO "osst: Only %d tapes accessible.\n", 128 / ST_NBR_MODES);
+	printk(KERN_INFO "osst :I: Only %d tapes accessible.\n", 128 / ST_NBR_MODES);
   os_scsi_tapes =
 	(OS_Scsi_Tape **)kmalloc(osst_template.dev_max * sizeof(OS_Scsi_Tape *),
 				   GFP_ATOMIC);
   if (os_scsi_tapes == NULL) {
-	printk(KERN_ERR "osst: Unable to allocate array for OnStream SCSI tapes.\n");
+	printk(KERN_ERR "osst :W: Unable to allocate array for OnStream SCSI tapes.\n");
 #ifdef CONFIG_DEVFS_FS
 	devfs_unregister_chrdev(MAJOR_NR, "osst");
 #else
@@ -5235,7 +5525,7 @@
 	(OSST_buffer **)kmalloc(osst_template.dev_max * sizeof(OSST_buffer *),
 				    GFP_ATOMIC);
   if (osst_buffers == NULL) {
-	printk(KERN_ERR "osst: Unable to allocate tape buffer pointers.\n");
+	printk(KERN_ERR "osst :W: Unable to allocate tape buffer pointers.\n");
 #ifdef CONFIG_DEVFS_FS
 	devfs_unregister_chrdev(MAJOR_NR, "osst");
 #else
@@ -5246,8 +5536,10 @@
   }
   osst_nbr_buffers = 0;
 
+  printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
+
 #if DEBUG
-  printk(OSST_DEB_MSG "osst: Buffer size %d bytes, write threshold %d bytes.\n",
+  printk(OSST_DEB_MSG "osst :D: Buffer size %d bytes, write threshold %d bytes.\n",
 	 osst_buffer_size, osst_write_threshold);
 #endif
   return 0;
@@ -5287,9 +5579,9 @@
 
 static int __init init_osst(void) 
 {
-  validate_options();
-  osst_template.module = THIS_MODULE;
-  return scsi_register_module(MODULE_SCSI_DEV, &osst_template);
+	validate_options();
+	osst_template.module = THIS_MODULE;
+	return scsi_register_module(MODULE_SCSI_DEV, &osst_template);
 }
 
 static void __exit exit_osst (void)
@@ -5325,7 +5617,7 @@
 	}
   }
   osst_template.dev_max = 0;
-  printk(KERN_INFO "osst: Unloaded.\n");
+  printk(KERN_INFO "osst :I: Unloaded.\n");
 }
 
 module_init(init_osst);
diff -u --recursive --new-file v2.4.5/linux/drivers/scsi/osst.h linux/drivers/scsi/osst.h
--- v2.4.5/linux/drivers/scsi/osst.h	Sat Dec 30 11:23:14 2000
+++ linux/drivers/scsi/osst.h	Mon Jun 11 19:15:27 2001
@@ -1,5 +1,5 @@
 /*
- *	$Header: /home/cvsroot/Driver/osst.h,v 1.9 2000/10/08 03:09:43 riede Exp $
+ *	$Header: /home/cvsroot/Driver/osst.h,v 1.11 2001/01/26 01:54:49 riede Exp $
  */
 
 #include <asm/byteorder.h>
@@ -440,7 +440,8 @@
          * Linux specific fields:
          */
          __u32          next_mark_ppos;         /* when known, points to next marker */
-         __u8           linux_specific[28];
+	 __u32		last_mark_lbn;		/* storing log_blk_num of last mark is extends ADR spec */
+         __u8           linux_specific[24];
 
         __u8            reserved_256_511[256];
 } os_aux_t;
@@ -581,6 +582,8 @@
   int min_block;
   int max_block;
   int recover_count;            /* from tape opening */
+  int write_count;
+  int read_count;
   int recover_erreg;            /* from last status call */
   /*
    * OnStream specific data
@@ -588,8 +591,9 @@
   int	   os_fw_rev;			       /* the firmware revision * 10000 */
   unsigned char  raw;                          /* flag OnStream raw access (32.5KB block size) */
   unsigned char  poll;                         /* flag that this drive needs polling (IDE|firmware) */
-  unsigned char  logical_blk_in_buffer;	       /* flag that the block as per logical_blk_num
+  unsigned char  frame_in_buffer;	       /* flag that the frame as per frame_seq_number
 						* has been read into STp->buffer and is valid */
+  int      frame_seq_number;                   /* logical frame number */
   int      logical_blk_num;                    /* logical block number */
   unsigned first_frame_position;               /* physical frame to be transfered to/from host */
   unsigned last_frame_position;                /* physical frame to be transferd to/from tape */
@@ -607,6 +611,7 @@
   int      filemark_cnt;
   int      first_mark_ppos;
   int      last_mark_ppos;
+  int      last_mark_lbn;			/* storing log_blk_num of last mark is extends ADR spec */
   int      first_data_ppos;
   int      eod_frame_ppos;
   int      eod_frame_lfa;
diff -u --recursive --new-file v2.4.5/linux/drivers/scsi/osst_options.h linux/drivers/scsi/osst_options.h
--- v2.4.5/linux/drivers/scsi/osst_options.h	Sat Dec 30 11:23:14 2000
+++ linux/drivers/scsi/osst_options.h	Mon Jun 11 19:15:27 2001
@@ -8,7 +8,7 @@
    Changed (and renamed) for OnStream SCSI drives garloff@suse.de
    2000-06-21
 
-   $Header: /home/cvsroot/Driver/osst_options.h,v 1.4 2000/06/26 01:44:01 riede Exp $
+   $Header: /home/cvsroot/Driver/osst_options.h,v 1.5 2001/01/07 22:19:15 riede Exp $
 */
 
 #ifndef _OSST_OPTIONS_H
@@ -24,7 +24,7 @@
    because of buffered reads. Should be set to zero to support also drives
    that can't space backwards over records. NOTE: The tape will be
    spaced backwards over an "accidentally" crossed filemark in any case. */
-#define OSST_IN_FILE_POS 0
+#define OSST_IN_FILE_POS 1
 
 /* The tape driver buffer size in kilobytes. */
 /* Don't change, as this is the HW blocksize */
@@ -33,7 +33,13 @@
 /* The number of kilobytes of data in the buffer that triggers an
    asynchronous write in fixed block mode. See also OSST_ASYNC_WRITES
    below. */
-#define OSST_WRITE_THRESHOLD_BLOCKS 30
+#define OSST_WRITE_THRESHOLD_BLOCKS 32
+
+/* OSST_EOM_RESERVE defines the number of frames are kept in reserve for
+ *  * write error recovery when writing near end of medium. ENOSPC is returned
+ *   * when write() is called and the tape write position is within this number
+ *    * of blocks from the tape capacity. */
+#define OSST_EOM_RESERVE 300
 
 /* The maximum number of tape buffers the driver allocates. The number
    is also constrained by the number of drives detected. Determines the
@@ -64,7 +70,7 @@
 
 /* If OSST_BUFFER_WRITES is non-zero, writes in fixed block mode are
    buffered until the driver buffer is full or asynchronous write is
-   triggered. May make detection of End-Of-Medium early enough fail. */
+   triggered. */
 #define OSST_BUFFER_WRITES 1
 
 /* If OSST_ASYNC_WRITES is non-zero, the SCSI write command may be started
diff -u --recursive --new-file v2.4.5/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.4.5/linux/drivers/scsi/qlogicisp.c	Fri Apr 27 13:59:19 2001
+++ linux/drivers/scsi/qlogicisp.c	Wed Jun 20 11:10:27 2001
@@ -62,8 +62,6 @@
 
 #define DEFAULT_LOOP_COUNT	1000000
 
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
 /* End Configuration section *************************************************/
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.4.5/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c
--- v2.4.5/linux/drivers/scsi/qlogicpti.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/scsi/qlogicpti.c	Mon Jun 11 19:15:27 2001
@@ -819,7 +819,8 @@
 			/* Is this a red snapper? */
 			if (strcmp(sdev->prom_name, "ptisp") &&
 			    strcmp(sdev->prom_name, "PTI,ptisp") &&
-			    strcmp(sdev->prom_name, "QLGC,isp"))
+			    strcmp(sdev->prom_name, "QLGC,isp") &&
+			    strcmp(sdev->prom_name, "SUNW,isp"))
 				continue;
 
 			/* Sometimes Antares cards come up not completely
diff -u --recursive --new-file v2.4.5/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.4.5/linux/drivers/scsi/scsi.c	Thu May 24 15:34:14 2001
+++ linux/drivers/scsi/scsi.c	Tue Jun 12 11:06:54 2001
@@ -2356,8 +2356,8 @@
 		/* The rest of these are not yet implemented. */
 	case MODULE_SCSI_CONST:
 	case MODULE_SCSI_IOCTL:
-		break;
 	default:
+		break;
 	}
 	return;
 }
diff -u --recursive --new-file v2.4.5/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- v2.4.5/linux/drivers/scsi/scsi_ioctl.c	Fri Apr 27 13:59:19 2001
+++ linux/drivers/scsi/scsi_ioctl.c	Mon Jun 11 19:15:27 2001
@@ -312,17 +312,17 @@
 	/* 
 	 * If there was an error condition, pass the info back to the user. 
 	 */
+	result = SRpnt->sr_result;
 	if (SRpnt->sr_result) {
 		int sb_len = sizeof(SRpnt->sr_sense_buffer);
 
 		sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len;
 		if (copy_to_user(cmd_in, SRpnt->sr_sense_buffer, sb_len))
-			return -EFAULT;
-	} else
+			result = -EFAULT;
+	} else {
 		if (copy_to_user(cmd_in, buf, outlen))
-			return -EFAULT;
-
-	result = SRpnt->sr_result;
+			result = -EFAULT;
+	}
 
 	SDpnt = SRpnt->sr_device;
 	scsi_release_request(SRpnt);
diff -u --recursive --new-file v2.4.5/linux/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c
--- v2.4.5/linux/drivers/scsi/scsi_scan.c	Sun Apr  8 10:10:01 2001
+++ linux/drivers/scsi/scsi_scan.c	Tue Jun 12 11:17:17 2001
@@ -328,8 +328,8 @@
 	}
 
 	/*
-	 * We need to increment the counter for this one device so we can track when
-	 * things are quiet.
+	 * We need to increment the counter for this one device so we can track
+	 * when things are quiet.
 	 */
 	if (hardcoded == 1) {
 		Scsi_Device *oldSDpnt = SDpnt;
@@ -485,8 +485,8 @@
 	SDpnt->type = -1;
 
 	/*
-	 * Assume that the device will have handshaking problems, and then fix this
-	 * field later if it turns out it doesn't
+	 * Assume that the device will have handshaking problems, and then fix
+	 * this field later if it turns out it doesn't
 	 */
 	SDpnt->borken = 1;
 	SDpnt->was_reset = 0;
@@ -524,9 +524,21 @@
 	SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n",
 		SRpnt->sr_result ? "failed" : "successful", SRpnt->sr_result));
 
+	/*
+	 * Now that we don't do TEST_UNIT_READY anymore, we must be prepared
+	 * for media change conditions here, so cannot require zero result.
+	 */
 	if (SRpnt->sr_result) {
-		scsi_release_request(SRpnt);
-		return 0;	/* assume no peripheral if any sort of error */
+		if ((driver_byte(SRpnt->sr_result) & DRIVER_SENSE) != 0 &&
+		    (SRpnt->sr_sense_buffer[2] & 0xf) == UNIT_ATTENTION &&
+		    SRpnt->sr_sense_buffer[12] == 0x28 &&
+		    SRpnt->sr_sense_buffer[13] == 0) {
+			/* not-ready to ready transition - good */
+		} else {
+			/* assume no peripheral if any other sort of error */
+			scsi_release_request(SRpnt);
+			return 0;
+		}
 	}
 
 	/*
diff -u --recursive --new-file v2.4.5/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.4.5/linux/drivers/scsi/sd.c	Fri May 25 09:54:50 2001
+++ linux/drivers/scsi/sd.c	Tue Jun 12 11:17:17 2001
@@ -861,8 +861,7 @@
 		       driver_byte(the_result)
 		    );
 		if (driver_byte(the_result) & DRIVER_SENSE)
-			printk("%s : extended sense code = %1x \n",
-			       nbuff, SRpnt->sr_sense_buffer[2] & 0xf);
+			print_req_sense("sd", SRpnt);
 		else
 			printk("%s : sense not available. \n", nbuff);
 
diff -u --recursive --new-file v2.4.5/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
--- v2.4.5/linux/drivers/scsi/sym53c8xx.c	Fri Apr 27 13:59:19 2001
+++ linux/drivers/scsi/sym53c8xx.c	Tue Jun 12 11:06:54 2001
@@ -11564,6 +11564,7 @@
 	OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
 	return;
 out_stuck:
+	return;
 }
 
 
diff -u --recursive --new-file v2.4.5/linux/drivers/sgi/char/linux_logo.h linux/drivers/sgi/char/linux_logo.h
--- v2.4.5/linux/drivers/sgi/char/linux_logo.h	Wed Dec 10 10:31:11 1997
+++ linux/drivers/sgi/char/linux_logo.h	Wed Dec 31 16:00:00 1969
@@ -1,909 +0,0 @@
-/* This is a linux logo to be displayed on boot.
- *
- * You can put anything here, but:
- * LINUX_LOGO_COLORS has to be less than 224
- * image size has to be 80x80
- * values have to start from0x20
- * (i.e. RGB(linux_logo_red[0],
- *	     linux_logo_green[0],
- *	     linux_logo_blue[0]) is color0x20)
- */
-
-#define LINUX_LOGO_COLORS 221
-
-unsigned char linux_logo_red[] = {
-  0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xE7, 0xE5, 0xE3,
-  0xCA, 0xD4, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xE5,
-  0xF1, 0xED, 0xEE, 0xE6, 0xC6, 0xDA, 0xDD, 0xE5,
-  0xD9, 0xC6, 0xE3, 0xD0, 0xC6, 0xBA, 0xB0, 0xB6,
-  0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xB0, 0xAD,
-  0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA0, 0x9D,
-  0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x99, 0x9A, 0x99,
-  0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
-  0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0x0D, 0x03,
-  0x66, 0x44, 0x24, 0x08, 0xD6, 0xE6, 0xE9, 0xE6,
-  0xE7, 0xCA, 0xDC, 0xDB, 0xD5, 0xD0, 0xC9, 0xE2,
-  0xD5, 0xC6, 0xC4, 0xB3, 0xB2, 0xB9, 0xA9, 0x9A,
-  0xB2, 0x9D, 0xE8, 0xEC, 0xF5, 0xF5, 0xF4, 0xF4,
-  0xEC, 0xEE, 0xF0, 0xF5, 0xE0, 0xD6, 0xC5, 0xC2,
-  0xD9, 0xD5, 0xD8, 0xD6, 0xF6, 0xF4, 0xED, 0xEC,
-  0xEB, 0xF1, 0xF6, 0xF5, 0xF5, 0xEE, 0xEF, 0xEC,
-  0xE7, 0xE3, 0xE6, 0xD6, 0xDD, 0xC3, 0xD6, 0xD7,
-  0xCD, 0xCA, 0xC3, 0xAC, 0x95, 0x99, 0xB7, 0xA3,
-  0x8B, 0x88, 0x95, 0x8A, 0x94, 0xD2, 0xCC, 0xC4,
-  0xA8, 0x8E, 0x8F, 0xAE, 0xB8, 0xAC, 0xB6, 0xB4,
-  0xAD, 0xA5, 0xA0, 0x9B, 0x8B, 0xA3, 0x94, 0x87,
-  0x85, 0x89, 0x53, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
-  0x76, 0x71, 0x73, 0x6E, 0x6B, 0x67, 0x65, 0x62,
-  0x4B, 0x5B, 0x5F, 0x53, 0x56, 0x52, 0x4F, 0x46,
-  0x42, 0x0F, 0x75, 0x78, 0x7D, 0x72, 0x5F, 0x6E,
-  0x7A, 0x75, 0x6A, 0x58, 0x48, 0x4F, 0x00, 0x2B,
-  0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x3B, 0x11,
-  0x1D, 0x14, 0x06, 0x02, 0x00
-};
-
-unsigned char linux_logo_green[] = {
-  0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xE7, 0xE5, 0xE3,
-  0xCA, 0xD4, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xD3,
-  0xDA, 0xD4, 0xD7, 0xCC, 0xC1, 0xCC, 0xCB, 0xC9,
-  0xC5, 0xBC, 0xBC, 0xBB, 0xB7, 0xA5, 0xB0, 0xB6,
-  0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xAD, 0xAD,
-  0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA0, 0x95,
-  0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x99, 0x9A, 0x99,
-  0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
-  0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0x08, 0x02,
-  0x53, 0x2E, 0x19, 0x06, 0xC6, 0xC8, 0xCF, 0xBD,
-  0xB3, 0xB6, 0xB4, 0xAB, 0xA5, 0xA3, 0x9B, 0xB6,
-  0xA7, 0x99, 0x92, 0xA4, 0x9E, 0x9D, 0x98, 0x8C,
-  0x8A, 0x86, 0xCD, 0xCC, 0xC9, 0xD7, 0xCA, 0xC4,
-  0xCA, 0xC3, 0xC7, 0xC3, 0xC8, 0xB4, 0x91, 0x8E,
-  0x8A, 0x82, 0x87, 0x85, 0xBD, 0xBF, 0xB6, 0xBC,
-  0xAE, 0xB7, 0xBC, 0xB8, 0xBF, 0xB6, 0xBC, 0xB5,
-  0xAB, 0xA6, 0xAD, 0xB2, 0xA5, 0x87, 0x9C, 0x96,
-  0x95, 0x8E, 0x87, 0x8F, 0x86, 0x86, 0x8E, 0x80,
-  0x7A, 0x70, 0x7B, 0x78, 0x78, 0x7F, 0x77, 0x6F,
-  0x70, 0x76, 0x59, 0x77, 0x68, 0x64, 0x7B, 0x7C,
-  0x75, 0x6D, 0x77, 0x69, 0x65, 0x5F, 0x5B, 0x54,
-  0x4F, 0x5B, 0x39, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
-  0x76, 0x71, 0x73, 0x6E, 0x6B, 0x67, 0x65, 0x62,
-  0x4B, 0x5B, 0x5F, 0x53, 0x56, 0x52, 0x4F, 0x46,
-  0x42, 0x0B, 0x69, 0x66, 0x64, 0x57, 0x4A, 0x4E,
-  0x55, 0x4B, 0x46, 0x3B, 0x30, 0x33, 0x00, 0x2B,
-  0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x29, 0x0D,
-  0x1D, 0x14, 0x06, 0x02, 0x00
-};
-
-unsigned char linux_logo_blue[] = {
-  0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xEE, 0xE5, 0xDE,
-  0xD7, 0xD3, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xB5,
-  0xB0, 0xA6, 0xAC, 0x9B, 0xB5, 0xB5, 0xAE, 0x84,
-  0x90, 0xA9, 0x81, 0x8D, 0x96, 0x86, 0xB0, 0xB6,
-  0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xA7, 0xAD,
-  0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA5, 0x87,
-  0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x9A, 0x9A, 0x99,
-  0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
-  0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0xC8, 0xD7,
-  0x9B, 0x8E, 0x8C, 0xB2, 0x77, 0x77, 0x4E, 0x77,
-  0x69, 0x71, 0x78, 0x6B, 0x65, 0x66, 0x64, 0x59,
-  0x5C, 0x5A, 0x48, 0x72, 0x7B, 0x6B, 0x67, 0x6E,
-  0x42, 0x5B, 0x29, 0x36, 0x25, 0x10, 0x17, 0x14,
-  0x19, 0x16, 0x13, 0x0E, 0x08, 0x2E, 0x2E, 0x3D,
-  0x24, 0x24, 0x24, 0x24, 0x13, 0x12, 0x14, 0x14,
-  0x0E, 0x08, 0x0D, 0x0F, 0x08, 0x0D, 0x0E, 0x08,
-  0x08, 0x0C, 0x06, 0x06, 0x07, 0x16, 0x07, 0x0E,
-  0x08, 0x0A, 0x07, 0x0D, 0x2D, 0x3E, 0x09, 0x4E,
-  0x68, 0x52, 0x56, 0x58, 0x4B, 0x22, 0x20, 0x20,
-  0x27, 0x39, 0x28, 0x19, 0x1E, 0x1E, 0x08, 0x06,
-  0x07, 0x09, 0x08, 0x08, 0x05, 0x1D, 0x1F, 0x17,
-  0x18, 0x06, 0x79, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
-  0x76, 0x71, 0x73, 0x6E, 0x6B, 0x68, 0x65, 0x62,
-  0x4B, 0x5B, 0x5F, 0x55, 0x56, 0x52, 0x4F, 0x46,
-  0x42, 0x5A, 0x14, 0x23, 0x3D, 0x2B, 0x21, 0x14,
-  0x06, 0x04, 0x03, 0x07, 0x09, 0x13, 0x2A, 0x3A,
-  0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x07, 0x09,
-  0x1D, 0x14, 0x06, 0x02, 0x00
-};
-
-unsigned char linux_logo[] = {
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x57,
-  0x58, 0x58, 0x59, 0x5C, 0x5D, 0x5F, 0x60, 0x61,
-  0x62, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63,
-  0x61, 0x61, 0x61, 0x61, 0x61, 0x60, 0x5E, 0x5E,
-  0x5E, 0x5D, 0x5D, 0x5C, 0x5D, 0x5B, 0x58, 0x58,
-  0x58, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x58,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x57,
-  0x54, 0x56, 0x57, 0x67, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x67, 0x4C,
-  0x4A, 0x49, 0x4A, 0x49, 0x4A, 0x49, 0x49, 0x4A,
-  0x4A, 0x4B, 0x4B, 0x4B, 0x4C, 0x50, 0x51, 0x52,
-  0x54, 0x54, 0x56, 0x57, 0x57, 0x57, 0x57, 0x58,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x58, 0x56, 0x56, 0x53,
-  0x52, 0x53, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB,
-  0x4B, 0x4B, 0x4B, 0x4A, 0x49, 0x4A, 0x4A, 0x49,
-  0x49, 0x49, 0x48, 0x49, 0x49, 0x4A, 0x4A, 0x4B,
-  0x4C, 0x4D, 0x52, 0x54, 0x56, 0x55, 0x57, 0x58,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
-  0x50, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF0, 0xF4, 0xFB,
-  0xFC, 0x67, 0x53, 0x50, 0x4D, 0x4C, 0x4C, 0x4C,
-  0x4B, 0x4A, 0x4A, 0x48, 0x49, 0x48, 0x48, 0x49,
-  0x49, 0x49, 0x4B, 0x4C, 0x50, 0x52, 0x53, 0x56,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x55, 0x54, 0x53, 0x51, 0x51, 0x50, 0x4C, 0x4D,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0xD2, 0xD7, 0xF5,
-  0xFC, 0xFC, 0x5D, 0x5D, 0x5C, 0x5C, 0x59, 0x58,
-  0x58, 0x56, 0x52, 0x4C, 0x4B, 0x4A, 0x4A, 0x48,
-  0x48, 0x48, 0x48, 0x48, 0x49, 0x4B, 0x4D, 0x51,
-  0x54, 0x56, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x55, 0x54,
-  0x53, 0x52, 0x51, 0x4D, 0x4D, 0x4D, 0x50, 0x50,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0x64, 0xD9, 0xF5,
-  0xF9, 0xFC, 0xFC, 0x64, 0x63, 0x62, 0x61, 0x61,
-  0x61, 0x60, 0x5E, 0x5B, 0x5A, 0x54, 0x52, 0x4C,
-  0x4B, 0x49, 0x49, 0x47, 0x47, 0x48, 0x49, 0x4B,
-  0x4C, 0x51, 0x53, 0x56, 0x57, 0x58, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x55, 0x53, 0x53,
-  0x51, 0x50, 0x50, 0x50, 0x50, 0x50, 0x53, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0xF5, 0xF9, 0xFC,
-  0xFC, 0xFC, 0xFC, 0x64, 0x64, 0x64, 0x64, 0x64,
-  0x64, 0x64, 0x64, 0x63, 0x61, 0x61, 0x5E, 0x59,
-  0x55, 0x52, 0x4C, 0x4A, 0x49, 0x47, 0x48, 0x48,
-  0x49, 0x4B, 0x4D, 0x51, 0x54, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x58, 0x55, 0x54, 0x54, 0x52, 0x51,
-  0x51, 0x51, 0x51, 0x51, 0x53, 0x54, 0x59, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xF7, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0x60, 0x60, 0x60, 0x61,
-  0x62, 0x63, 0x64, 0x64, 0x65, 0x65, 0x64, 0x63,
-  0x61, 0x5E, 0x59, 0x56, 0x4D, 0x4B, 0x48, 0x48,
-  0x48, 0x48, 0x49, 0x4B, 0x50, 0x53, 0x56, 0x56,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x56, 0x54, 0x53, 0x52, 0x51, 0x51,
-  0x51, 0x52, 0x53, 0x55, 0x59, 0x5D, 0x5E, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0x4C, 0x4E, 0x51, 0x52,
-  0x57, 0x5A, 0x5E, 0x60, 0x61, 0x63, 0x65, 0xCB,
-  0x64, 0x64, 0x63, 0x60, 0x5C, 0x57, 0x50, 0x4B,
-  0x48, 0x47, 0x47, 0x47, 0x4A, 0x4C, 0x52, 0x53,
-  0x54, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x55, 0x54, 0x53, 0x53, 0x51, 0x52, 0x52, 0x53,
-  0x53, 0x57, 0x5A, 0x5D, 0x5E, 0x5E, 0x60, 0xFC,
-  0xFC, 0xFC, 0xFB, 0xF9, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFA, 0xF9, 0xF5, 0xFB, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0x45, 0x3F, 0x3F,
-  0x45, 0x48, 0x4B, 0x4D, 0x54, 0x5A, 0x5E, 0x61,
-  0x63, 0xCB, 0xCB, 0x65, 0x64, 0x62, 0x5E, 0x57,
-  0x50, 0x4B, 0x48, 0x47, 0x47, 0x48, 0x4B, 0x4D,
-  0x51, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55,
-  0x54, 0x54, 0x53, 0x53, 0x52, 0x53, 0x54, 0x57,
-  0x59, 0x5C, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0xFC,
-  0xFC, 0xFA, 0xFC, 0xFA, 0xE0, 0xFC, 0xFC, 0xFC,
-  0xFB, 0xFB, 0xFB, 0xDF, 0xD8, 0xF9, 0xE0, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0x4C, 0x4A, 0x48,
-  0x48, 0x3E, 0x44, 0x43, 0x3F, 0x47, 0x4B, 0x52,
-  0x5A, 0x5E, 0x62, 0x64, 0xCB, 0xCB, 0x64, 0x61,
-  0x5E, 0x57, 0x4D, 0x49, 0x47, 0x47, 0x48, 0x4A,
-  0x4C, 0x52, 0x54, 0x56, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55,
-  0x54, 0x53, 0x53, 0x54, 0x54, 0x55, 0x58, 0x5B,
-  0x5C, 0x5D, 0x5E, 0x5D, 0x5D, 0x5B, 0x58, 0xFC,
-  0xFC, 0xD8, 0x4C, 0x60, 0xFC, 0xF5, 0xFC, 0xFC,
-  0xFC, 0xF7, 0x5F, 0x48, 0x48, 0x2C, 0xF8, 0xF9,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x4B, 0x4A, 0x49,
-  0x49, 0x49, 0x49, 0x47, 0x3E, 0x44, 0x42, 0x3F,
-  0x3E, 0x4B, 0x54, 0x5C, 0x61, 0x64, 0xCB, 0xCB,
-  0x64, 0x61, 0x5D, 0x53, 0x4B, 0x49, 0x47, 0x47,
-  0x49, 0x4B, 0x50, 0x53, 0x56, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x55, 0x55, 0x54,
-  0x53, 0x53, 0x54, 0x56, 0x58, 0x5A, 0x5B, 0x5D,
-  0x5D, 0x5D, 0x5C, 0x5A, 0x54, 0x52, 0x4C, 0xFC,
-  0xF7, 0x4E, 0x2D, 0x29, 0x4E, 0xFC, 0xFC, 0xFC,
-  0xFB, 0x5F, 0x26, 0x24, 0x20, 0x2E, 0x65, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x45, 0x3F, 0x45,
-  0x3E, 0x47, 0x47, 0x47, 0x47, 0x47, 0x3E, 0x44,
-  0x43, 0x40, 0x44, 0x49, 0x51, 0x5C, 0x62, 0x64,
-  0xCB, 0xCB, 0x63, 0x60, 0x58, 0x50, 0x49, 0x48,
-  0x48, 0x48, 0x4A, 0x4D, 0x53, 0x54, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54, 0x54,
-  0x54, 0x54, 0x55, 0x57, 0x59, 0x5B, 0x5C, 0x5D,
-  0x5C, 0x5A, 0x54, 0x51, 0x4C, 0x4C, 0x54, 0xFC,
-  0xF9, 0x23, 0xDB, 0x2D, 0x23, 0xFA, 0xFB, 0xFA,
-  0xF5, 0x27, 0x21, 0xD9, 0xF8, 0x20, 0x21, 0xFB,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x5D, 0x58, 0x55,
-  0x50, 0x48, 0x45, 0x43, 0x44, 0x44, 0x45, 0x45,
-  0x3E, 0x3F, 0x43, 0x41, 0x3F, 0x48, 0x52, 0x5D,
-  0x63, 0x65, 0xCB, 0x65, 0x61, 0x5D, 0x52, 0x4B,
-  0x48, 0x47, 0x47, 0x49, 0x4C, 0x51, 0x54, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54, 0x54,
-  0x54, 0x58, 0x5A, 0x59, 0x5B, 0x5B, 0x5B, 0x5A,
-  0x55, 0x52, 0x4D, 0x4D, 0x55, 0x5B, 0x5D, 0xFC,
-  0xF1, 0xF9, 0xFC, 0xD4, 0x21, 0xCC, 0xF7, 0xF8,
-  0xF2, 0x21, 0xD9, 0xFC, 0xF2, 0xFB, 0x21, 0x45,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xD1, 0xD0, 0xCD,
-  0xCC, 0x63, 0x5E, 0x58, 0x50, 0x47, 0x43, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x40, 0x41, 0x3F, 0x4A,
-  0x56, 0x5E, 0x64, 0xCB, 0x65, 0x63, 0x5E, 0x56,
-  0x4C, 0x48, 0x47, 0x47, 0x49, 0x4C, 0x51, 0x54,
-  0x58, 0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54,
-  0x57, 0x5A, 0x5A, 0x5C, 0x5B, 0x5A, 0x58, 0x54,
-  0x51, 0x4C, 0x55, 0x5D, 0x5D, 0x5B, 0x54, 0xFC,
-  0xF0, 0xF9, 0xFC, 0x65, 0x45, 0xCD, 0xFB, 0xFB,
-  0xF8, 0x26, 0xFB, 0xFC, 0xFC, 0xFC, 0x21, 0x27,
-  0xFB, 0xFC, 0xFC, 0xFC, 0xFB, 0xD7, 0x35, 0x34,
-  0x2F, 0x35, 0x36, 0x2F, 0x2F, 0x36, 0x2F, 0x2F,
-  0x36, 0x36, 0x35, 0x35, 0x43, 0x42, 0x41, 0x2E,
-  0x45, 0x4C, 0x5B, 0x62, 0x65, 0xCC, 0x64, 0x60,
-  0x58, 0x4D, 0x49, 0x47, 0x47, 0x49, 0x4C, 0x51,
-  0x58, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55, 0x57,
-  0x58, 0x5A, 0x5A, 0x5B, 0x5A, 0x55, 0x54, 0x51,
-  0x53, 0x5C, 0x5D, 0x5D, 0x54, 0x4B, 0x4D, 0xFC,
-  0xFC, 0x44, 0xFC, 0xFB, 0x7B, 0xAB, 0xA8, 0xAE,
-  0xAB, 0x7F, 0xFC, 0xFC, 0xFB, 0xFB, 0x22, 0x2A,
-  0xFC, 0xFC, 0xFC, 0xFC, 0x36, 0x2F, 0x30, 0x30,
-  0x32, 0x30, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30,
-  0x30, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x40, 0x41,
-  0x2E, 0x40, 0x48, 0x56, 0x5F, 0x64, 0xCC, 0x65,
-  0x61, 0x59, 0x50, 0x49, 0x47, 0x47, 0x49, 0x4C,
-  0x5A, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58,
-  0x5A, 0x5A, 0x5A, 0x58, 0x55, 0x52, 0x51, 0x5A,
-  0x5D, 0x5D, 0x57, 0x4C, 0x51, 0x54, 0x5D, 0xFC,
-  0xFC, 0x2A, 0xFC, 0xC9, 0xAA, 0x8B, 0x8A, 0x8C,
-  0xAB, 0x8C, 0x8C, 0xFB, 0xFB, 0x23, 0x20, 0xF1,
-  0xFC, 0xFC, 0xFC, 0x3B, 0x33, 0x33, 0x32, 0x32,
-  0x31, 0x32, 0x30, 0x32, 0x32, 0x32, 0x32, 0x30,
-  0x31, 0x31, 0x31, 0x32, 0x33, 0x33, 0x3C, 0x41,
-  0x41, 0x2E, 0x2D, 0x45, 0x4D, 0x5D, 0x63, 0xCC,
-  0x65, 0x62, 0x5D, 0x51, 0x49, 0x47, 0x47, 0x4A,
-  0x59, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58,
-  0x5A, 0x5A, 0x58, 0x55, 0x53, 0x53, 0x5C, 0x5E,
-  0x59, 0x51, 0x4E, 0x54, 0x59, 0x5E, 0x62, 0xFC,
-  0xFC, 0xDB, 0xAA, 0xA1, 0x95, 0x9C, 0x8C, 0x88,
-  0x82, 0x83, 0x83, 0x8C, 0x88, 0xAE, 0xB9, 0xFB,
-  0xFC, 0xFC, 0xFC, 0x3C, 0x3B, 0x72, 0x38, 0x33,
-  0x33, 0x33, 0x31, 0x33, 0x31, 0x31, 0x31, 0x31,
-  0x33, 0x33, 0x38, 0x33, 0x72, 0x3B, 0x44, 0x2E,
-  0x41, 0x2E, 0x2E, 0x2D, 0x43, 0x4B, 0x5B, 0x63,
-  0xCB, 0xCC, 0x63, 0x5D, 0x51, 0x49, 0x47, 0x49,
-  0x5C, 0x58, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58,
-  0x58, 0x58, 0x57, 0x53, 0x58, 0x5D, 0x5E, 0x55,
-  0x51, 0x53, 0x58, 0x5E, 0x60, 0x63, 0x64, 0xFC,
-  0xFC, 0xC0, 0xA6, 0x9D, 0x8B, 0x9C, 0x8C, 0x8C,
-  0x6E, 0x83, 0x88, 0x8C, 0x8C, 0x8C, 0x83, 0xE8,
-  0xFB, 0xFC, 0xFC, 0xFC, 0x33, 0x70, 0x70, 0x6F,
-  0x6F, 0x6F, 0x6F, 0x3A, 0x6F, 0x6D, 0x6F, 0x6F,
-  0x70, 0x6F, 0x6F, 0x70, 0x6F, 0x32, 0x5A, 0x48,
-  0x41, 0x2D, 0x2D, 0x2D, 0x2C, 0x41, 0x49, 0x5A,
-  0x62, 0xCB, 0xCB, 0x63, 0x5D, 0x50, 0x49, 0x4A,
-  0x5C, 0x58, 0x58, 0x57, 0x55, 0x57, 0x57, 0x57,
-  0x57, 0x55, 0x56, 0x59, 0x5E, 0x5C, 0x52, 0x53,
-  0x55, 0x5B, 0x5E, 0x61, 0x63, 0x64, 0x63, 0xFC,
-  0xE8, 0xBF, 0xA4, 0x99, 0x9C, 0x8C, 0x88, 0x88,
-  0x6E, 0x88, 0x8C, 0x8C, 0x8C, 0xC2, 0xA6, 0xC4,
-  0xFC, 0xFC, 0xFC, 0xFC, 0x36, 0x3A, 0x6F, 0x70,
-  0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
-  0x70, 0x70, 0x70, 0x70, 0x37, 0x32, 0xCD, 0x5E,
-  0x4C, 0x43, 0x2C, 0x2D, 0x2D, 0x2C, 0x2E, 0x47,
-  0x57, 0x61, 0x65, 0xCC, 0x63, 0x5C, 0x50, 0x4D,
-  0x5C, 0x5A, 0x57, 0x55, 0x55, 0x55, 0x58, 0x58,
-  0x55, 0x54, 0x5B, 0x5E, 0x5D, 0x53, 0x53, 0x55,
-  0x5D, 0x5E, 0x61, 0x61, 0x61, 0x61, 0x5E, 0xFC,
-  0xEA, 0xBE, 0xA4, 0x9B, 0x8B, 0x85, 0x8C, 0x6E,
-  0x8C, 0x8C, 0x8C, 0xA3, 0xAA, 0xA4, 0xA4, 0xE9,
-  0xFB, 0xFC, 0xFC, 0xFC, 0x36, 0x6D, 0x70, 0x73,
-  0x70, 0x70, 0x70, 0x73, 0x73, 0x73, 0x73, 0x70,
-  0x70, 0x70, 0x73, 0x70, 0x37, 0x38, 0xD1, 0xCF,
-  0x61, 0x4D, 0x44, 0x2C, 0x2D, 0x2E, 0x2C, 0x2E,
-  0x3E, 0x56, 0x61, 0xCB, 0xCC, 0x62, 0x5B, 0x57,
-  0x59, 0x58, 0x55, 0x54, 0x54, 0x55, 0x58, 0x58,
-  0x58, 0x5B, 0x5E, 0x5B, 0x53, 0x55, 0x55, 0x5C,
-  0x5E, 0x61, 0x61, 0x60, 0x5D, 0x5A, 0x4E, 0xFC,
-  0xFC, 0xEA, 0xAA, 0x9C, 0x8A, 0x85, 0x82, 0x8C,
-  0x8C, 0xA8, 0xEB, 0xA8, 0xA4, 0xA4, 0xAA, 0xFC,
-  0xFC, 0xFC, 0x64, 0xFB, 0x39, 0x31, 0x72, 0x78,
-  0x73, 0x78, 0x73, 0x74, 0x74, 0x74, 0x74, 0x73,
-  0x78, 0x70, 0x73, 0x73, 0x33, 0xCC, 0xD2, 0xD1,
-  0xCE, 0x62, 0x53, 0x3F, 0x2D, 0x2D, 0x41, 0x2C,
-  0x2E, 0x3E, 0x56, 0x62, 0xCB, 0xCB, 0x61, 0x5D,
-  0x54, 0x54, 0x54, 0x54, 0x56, 0x58, 0x58, 0x58,
-  0x5C, 0x5E, 0x5A, 0x55, 0x58, 0x58, 0x5B, 0x5E,
-  0x61, 0x5E, 0x5D, 0x5A, 0x52, 0x55, 0xCD, 0xFC,
-  0xFC, 0x34, 0xC9, 0xE8, 0xA8, 0xAE, 0xC2, 0xE8,
-  0xC3, 0xA6, 0xA7, 0xA6, 0xAA, 0x78, 0x2E, 0x42,
-  0xFC, 0xFC, 0xD2, 0x64, 0xF8, 0x31, 0x72, 0x73,
-  0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x74, 0x73,
-  0x73, 0x73, 0x73, 0x72, 0x33, 0x5C, 0x64, 0xD2,
-  0xD1, 0xCF, 0x63, 0x54, 0x3F, 0x2C, 0x41, 0x41,
-  0x2C, 0x2E, 0x47, 0x58, 0x63, 0xCB, 0xCB, 0x62,
-  0x52, 0x53, 0x53, 0x56, 0x58, 0x58, 0x5A, 0x5B,
-  0x5E, 0x5A, 0x57, 0x58, 0x58, 0x58, 0x60, 0x60,
-  0x5D, 0x5A, 0x55, 0x4E, 0x64, 0xD2, 0xD1, 0xFC,
-  0xFC, 0x41, 0x3E, 0xC1, 0xC0, 0xA3, 0xA6, 0xA7,
-  0xA7, 0xA9, 0xAA, 0xB8, 0x2E, 0x3F, 0x2C, 0x41,
-  0xFC, 0xFC, 0xF7, 0xCE, 0xCD, 0x36, 0x72, 0x73,
-  0x74, 0x75, 0x78, 0x75, 0x75, 0x75, 0x74, 0x74,
-  0x74, 0x74, 0x78, 0x72, 0x6D, 0x49, 0x59, 0xCB,
-  0xD1, 0xD1, 0xD2, 0xCB, 0x56, 0x3F, 0x2C, 0x41,
-  0x40, 0x2D, 0x2E, 0x49, 0x5B, 0x64, 0xCC, 0x64,
-  0x51, 0x53, 0x53, 0x55, 0x58, 0x59, 0x5B, 0x5E,
-  0x59, 0x58, 0x58, 0x58, 0x55, 0x60, 0x60, 0x5C,
-  0x5A, 0x53, 0x5B, 0xD0, 0xD3, 0xD3, 0xD3, 0xFB,
-  0xFC, 0x40, 0x41, 0x45, 0xC4, 0xC0, 0xBE, 0xBE,
-  0xC1, 0xC0, 0x3C, 0x47, 0x2E, 0x21, 0x22, 0x20,
-  0x65, 0xFC, 0xFC, 0xFC, 0xFC, 0x6D, 0x72, 0x75,
-  0x78, 0x76, 0x75, 0x79, 0x76, 0x76, 0x76, 0x76,
-  0x75, 0x75, 0x75, 0x72, 0x6D, 0x2E, 0x48, 0x5D,
-  0xCE, 0xD1, 0xD4, 0xD3, 0xCB, 0x56, 0x43, 0x2C,
-  0x42, 0x43, 0x2E, 0x2E, 0x4A, 0x5D, 0x64, 0x64,
-  0x50, 0x52, 0x56, 0x58, 0x5C, 0x5D, 0x5E, 0x5D,
-  0x5A, 0x58, 0x58, 0x55, 0x61, 0x60, 0x58, 0x58,
-  0x4E, 0x61, 0xD1, 0xD4, 0xD4, 0xD1, 0xEE, 0xFC,
-  0xFC, 0x2B, 0x29, 0x2E, 0x3F, 0xB0, 0xAD, 0x81,
-  0x46, 0x2D, 0x46, 0x2C, 0x24, 0x22, 0x22, 0x23,
-  0x25, 0xFC, 0xFC, 0xFC, 0xFC, 0x6E, 0x73, 0x76,
-  0x76, 0x79, 0x79, 0x79, 0x76, 0x76, 0x79, 0x76,
-  0x79, 0x79, 0x79, 0x74, 0x3F, 0x41, 0x2C, 0x48,
-  0x5F, 0xCF, 0xD5, 0xD7, 0xD6, 0xCD, 0x57, 0x40,
-  0x2E, 0x3F, 0x44, 0x2E, 0x41, 0x4C, 0x60, 0x61,
-  0x51, 0x53, 0x58, 0x5C, 0x5D, 0x5E, 0x5D, 0x5C,
-  0x58, 0x57, 0x54, 0x5F, 0x5E, 0x55, 0x55, 0x52,
-  0x64, 0xD4, 0xD5, 0xD4, 0xD1, 0x5D, 0xFA, 0xFB,
-  0xF4, 0x21, 0x24, 0x41, 0x40, 0x44, 0x2E, 0x2E,
-  0x42, 0x41, 0x2A, 0x24, 0x22, 0x22, 0x22, 0x22,
-  0x23, 0xD9, 0xFC, 0xFC, 0xFC, 0xFC, 0xE5, 0xB8,
-  0x8F, 0x8F, 0x7A, 0x8F, 0x7A, 0x8F, 0x7A, 0x8F,
-  0x8F, 0x8F, 0xB8, 0xE5, 0x3F, 0x3E, 0x43, 0x2C,
-  0x48, 0x61, 0xD1, 0xD7, 0xD9, 0xD7, 0xD0, 0x57,
-  0x41, 0x2E, 0x3E, 0x44, 0x2D, 0x40, 0x52, 0x5D,
-  0x53, 0x55, 0x59, 0x5D, 0x5E, 0x5E, 0x5D, 0x5A,
-  0x57, 0x53, 0x5E, 0x5E, 0x54, 0x53, 0x54, 0x65,
-  0xD5, 0xD6, 0xD4, 0xCE, 0x53, 0xFB, 0xF9, 0xFC,
-  0x24, 0x22, 0x23, 0x23, 0x41, 0x42, 0x2E, 0x40,
-  0x2B, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
-  0x23, 0x23, 0xFC, 0xFC, 0xFC, 0xFC, 0xE7, 0xBD,
-  0xB5, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
-  0x93, 0xB5, 0xC6, 0xEB, 0x2D, 0x47, 0x4A, 0x47,
-  0x2C, 0x3E, 0x61, 0xD4, 0xDC, 0xDC, 0xDA, 0xCF,
-  0x54, 0x41, 0x41, 0x3E, 0x45, 0x2C, 0x3F, 0x4A,
-  0x58, 0x5A, 0x5C, 0x5F, 0x60, 0x5E, 0x5D, 0x57,
-  0x51, 0x5D, 0x5D, 0x51, 0x53, 0x53, 0xCB, 0xD5,
-  0xD6, 0xD5, 0x63, 0x55, 0xFC, 0xFC, 0xFC, 0x2C,
-  0x23, 0x22, 0x23, 0x22, 0x20, 0x2D, 0x2C, 0x26,
-  0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
-  0x22, 0x21, 0xF0, 0xFC, 0xFC, 0xFC, 0xE2, 0xC6,
-  0xB5, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
-  0x93, 0x93, 0xC7, 0xE3, 0x3E, 0x2E, 0x49, 0x52,
-  0x4C, 0x41, 0x44, 0x62, 0xD6, 0xDE, 0xDE, 0xD9,
-  0xD0, 0x51, 0x2E, 0x40, 0x47, 0x44, 0x2C, 0x42,
-  0x5D, 0x5D, 0x5F, 0x60, 0x60, 0x5D, 0x57, 0x51,
-  0x58, 0x5D, 0x4E, 0x52, 0x55, 0x64, 0xD5, 0xD6,
-  0xD4, 0x61, 0x59, 0x6B, 0xFC, 0xFC, 0xFC, 0x21,
-  0x23, 0x22, 0x23, 0x22, 0x23, 0x21, 0x23, 0x22,
-  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
-  0x22, 0x21, 0x24, 0xFC, 0xFC, 0xFC, 0xE2, 0xC7,
-  0xB5, 0x90, 0x93, 0x93, 0x93, 0x90, 0x93, 0x93,
-  0x90, 0xB5, 0xC8, 0xE4, 0x5F, 0x45, 0x2E, 0x4D,
-  0x57, 0x57, 0x44, 0x43, 0x63, 0xDA, 0xDF, 0xDF,
-  0xD9, 0xCE, 0x4C, 0x2C, 0x3F, 0x3E, 0x40, 0x40,
-  0x60, 0x5E, 0x61, 0x61, 0x5E, 0x5B, 0x53, 0x52,
-  0x5C, 0x52, 0x52, 0x55, 0x61, 0xD4, 0xD5, 0xD1,
-  0x5E, 0x5B, 0x5C, 0xFB, 0xFC, 0xFC, 0x2A, 0x21,
-  0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
-  0x22, 0x22, 0x22, 0xFB, 0xFC, 0xFC, 0xB3, 0xC8,
-  0xB5, 0x90, 0x92, 0xB5, 0x93, 0x93, 0xB5, 0x93,
-  0x92, 0xB5, 0xC8, 0xB9, 0xD0, 0x5E, 0x44, 0x40,
-  0x52, 0x58, 0x57, 0x48, 0x40, 0x63, 0xD9, 0xE0,
-  0xE0, 0xD9, 0xCB, 0x49, 0x2D, 0x3F, 0x45, 0x3F,
-  0x63, 0x61, 0x62, 0x60, 0x5E, 0x55, 0x4D, 0x59,
-  0x53, 0x4E, 0x54, 0x5D, 0xD2, 0xD4, 0xD2, 0x5E,
-  0x5C, 0x5D, 0xFC, 0xFC, 0xFC, 0xF8, 0x29, 0x23,
-  0x23, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
-  0x23, 0x22, 0x22, 0x23, 0x23, 0x23, 0x22, 0x22,
-  0x22, 0x22, 0x22, 0xF0, 0xFC, 0xFC, 0xB3, 0xC7,
-  0xB5, 0x93, 0xB5, 0x93, 0x93, 0x91, 0x93, 0x93,
-  0x91, 0xB5, 0xC7, 0xAD, 0xD6, 0xD2, 0x5E, 0x3F,
-  0x3F, 0x57, 0x57, 0x58, 0x4A, 0x41, 0x64, 0xDC,
-  0xF1, 0xDF, 0xDA, 0x61, 0x45, 0x2E, 0x43, 0x47,
-  0xCB, 0x63, 0x62, 0x5F, 0x58, 0x51, 0x53, 0x54,
-  0x4C, 0x52, 0x5C, 0xCD, 0xD3, 0xD2, 0x60, 0x5D,
-  0x5D, 0xFB, 0xFC, 0xFC, 0xFC, 0xDB, 0x49, 0x24,
-  0x21, 0x23, 0x23, 0x22, 0x26, 0x26, 0x2A, 0x24,
-  0x22, 0x23, 0x22, 0x21, 0x24, 0x26, 0x26, 0x2A,
-  0x29, 0x2B, 0x24, 0x25, 0xFC, 0xFC, 0xB3, 0xC5,
-  0x91, 0x91, 0x92, 0x91, 0x92, 0x92, 0x93, 0x93,
-  0x91, 0x93, 0xC6, 0xAD, 0xDC, 0xD9, 0xD4, 0x60,
-  0x43, 0x45, 0x58, 0x58, 0x57, 0x4B, 0x43, 0xCC,
-  0xDD, 0xF1, 0xD8, 0xD5, 0x5D, 0x43, 0x41, 0x47,
-  0xCD, 0x63, 0x62, 0x5D, 0x54, 0x4C, 0x55, 0x4B,
-  0x51, 0x58, 0x62, 0xD0, 0xD0, 0x62, 0x5D, 0x5D,
-  0x67, 0xFC, 0xFC, 0xFC, 0xFC, 0x58, 0x4E, 0x28,
-  0x2A, 0x20, 0x23, 0x22, 0x23, 0x2A, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x23, 0x25, 0x2A, 0x2E, 0x2D,
-  0x2E, 0x2E, 0x2E, 0x23, 0xFA, 0xFC, 0xB2, 0xBD,
-  0xB5, 0x90, 0x91, 0x93, 0x92, 0x90, 0x91, 0x93,
-  0x92, 0x91, 0xBD, 0xAD, 0xDE, 0xE0, 0xD8, 0xD7,
-  0x61, 0x40, 0x48, 0x58, 0x58, 0x58, 0x48, 0x44,
-  0xCF, 0xDE, 0xE0, 0xDD, 0xD0, 0x52, 0x41, 0x45,
-  0xCD, 0x63, 0x61, 0x58, 0x4D, 0x51, 0x4C, 0x4B,
-  0x54, 0x5D, 0xCC, 0xCE, 0x63, 0x61, 0x5D, 0x5D,
-  0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0x4B, 0x27, 0x21,
-  0x22, 0x22, 0x23, 0x22, 0x22, 0x24, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x20,
-  0x27, 0x2B, 0x41, 0x2B, 0x23, 0xFC, 0xB2, 0xB6,
-  0x93, 0x90, 0x92, 0xB5, 0x92, 0x90, 0xB5, 0x90,
-  0x92, 0x93, 0xBC, 0xAD, 0xDC, 0xF1, 0xF3, 0xF0,
-  0xD9, 0x61, 0x41, 0x4A, 0x58, 0x57, 0x57, 0x44,
-  0x49, 0xD2, 0xDD, 0xD8, 0xDA, 0x63, 0x4A, 0x45,
-  0xCC, 0x63, 0x5E, 0x52, 0x4B, 0x4C, 0x49, 0x51,
-  0x5C, 0x61, 0xCD, 0x65, 0x63, 0x5E, 0x4E, 0xCF,
-  0xFB, 0xFB, 0xF0, 0xFC, 0xD2, 0x2A, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x26, 0x41, 0x27, 0xF9, 0x81, 0xB7,
-  0xB5, 0x91, 0x92, 0xB5, 0x91, 0xB5, 0x93, 0xB5,
-  0x93, 0xB6, 0xB7, 0xB9, 0xCB, 0xD8, 0xF3, 0xF2,
-  0xF2, 0xDB, 0x61, 0x2D, 0x51, 0x58, 0x57, 0x58,
-  0x41, 0x51, 0xD4, 0xDB, 0xDC, 0xD1, 0x5B, 0x4C,
-  0xCB, 0x62, 0x59, 0x4C, 0x4A, 0x49, 0x4B, 0x55,
-  0x60, 0x64, 0xCC, 0x64, 0x5E, 0x55, 0x60, 0xE1,
-  0xFB, 0xF8, 0xFC, 0xFC, 0x21, 0x22, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x21, 0x24, 0x2D, 0x21, 0xB4, 0xBB,
-  0xB6, 0xB5, 0xB6, 0xB7, 0xB7, 0xB7, 0xB7, 0xB6,
-  0xB6, 0xB6, 0xBB, 0xB9, 0x45, 0xCB, 0xDF, 0xF3,
-  0xF3, 0xF3, 0xDB, 0x5E, 0x2C, 0x51, 0x58, 0x58,
-  0x52, 0x2D, 0x5C, 0xD4, 0xD9, 0xD5, 0x63, 0x58,
-  0x64, 0x60, 0x53, 0x49, 0x4A, 0x49, 0x52, 0x5C,
-  0x63, 0xCD, 0xCD, 0x63, 0x5C, 0x4E, 0x65, 0xFC,
-  0xFC, 0xF5, 0xFC, 0xD2, 0x23, 0x22, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x21, 0x22, 0x25, 0x29, 0xB3, 0xC7,
-  0xB5, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
-  0xB6, 0xB5, 0xC7, 0xAD, 0x57, 0x3F, 0xCB, 0xF0,
-  0xF3, 0xF3, 0xF2, 0xD9, 0x58, 0x41, 0x4C, 0x58,
-  0x57, 0x47, 0x42, 0x62, 0xD4, 0xD4, 0xCC, 0x60,
-  0x63, 0x5D, 0x50, 0x47, 0x48, 0x4B, 0x58, 0x60,
-  0xCC, 0xCE, 0xCD, 0x60, 0x53, 0x5C, 0x62, 0xFB,
-  0xF9, 0xFC, 0xFC, 0x21, 0x23, 0x22, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x23, 0x23, 0x21, 0x22, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x23, 0x23, 0x22, 0x23, 0x81, 0xC7,
-  0xB7, 0xB7, 0xBC, 0xB7, 0xBC, 0xBC, 0xBC, 0xB7,
-  0xB7, 0xB7, 0xC8, 0x80, 0x58, 0x57, 0x40, 0xCE,
-  0xF3, 0xF2, 0xF2, 0xF0, 0xD5, 0x4C, 0x3F, 0x4B,
-  0x52, 0x50, 0x2D, 0x4B, 0x64, 0xD2, 0xCC, 0x61,
-  0x60, 0x58, 0x4A, 0x47, 0x47, 0x4C, 0x59, 0x64,
-  0xD0, 0xD0, 0x64, 0x59, 0x49, 0x5D, 0xFB, 0xFC,
-  0xD9, 0xFC, 0xD6, 0x23, 0x22, 0x22, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x23, 0x21, 0x21, 0x22, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x23, 0x23, 0x22, 0x23, 0xB4, 0xC8,
-  0xBD, 0xB7, 0xBD, 0xBC, 0xBD, 0xC5, 0xBC, 0xC5,
-  0xBC, 0xBD, 0xC7, 0xAC, 0x58, 0x57, 0x58, 0x2C,
-  0xD1, 0xF0, 0xF3, 0xF3, 0xE0, 0xCD, 0x45, 0x3E,
-  0x48, 0x4B, 0x3F, 0x41, 0x56, 0x64, 0x65, 0x62,
-  0x5D, 0x52, 0x47, 0x48, 0x48, 0x53, 0x60, 0xCC,
-  0xD2, 0xD0, 0x63, 0x52, 0x4E, 0x53, 0xFB, 0xFB,
-  0xFC, 0xFC, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x23, 0x20, 0x21, 0x22, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0xB4, 0xC7,
-  0xC5, 0xBC, 0xC5, 0xBD, 0xC5, 0xC5, 0xBD, 0xC5,
-  0xBC, 0xC6, 0xC7, 0xB9, 0x58, 0x57, 0x58, 0x57,
-  0x2D, 0xD4, 0xF1, 0xF2, 0xF0, 0xD9, 0x5D, 0x47,
-  0x48, 0x3F, 0x42, 0x2C, 0x48, 0x5C, 0x5F, 0x60,
-  0x58, 0x50, 0x47, 0x4A, 0x49, 0x55, 0x63, 0xD0,
-  0xD2, 0xCD, 0x5D, 0x49, 0x4E, 0xE1, 0xFC, 0xF0,
-  0xFC, 0xF8, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x20, 0x21, 0x21, 0x22, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x22,
-  0x23, 0x22, 0x23, 0x23, 0x23, 0x22, 0xC4, 0xC8,
-  0xBD, 0xBD, 0xC6, 0xBD, 0xC6, 0xC6, 0xC5, 0xC6,
-  0xBD, 0xC6, 0xC7, 0xE4, 0x54, 0x57, 0x58, 0x57,
-  0x57, 0x43, 0xD7, 0xE0, 0xF1, 0xD8, 0xCD, 0x4B,
-  0x4A, 0x47, 0x42, 0x2C, 0x3F, 0x4D, 0x58, 0x5C,
-  0x52, 0x4B, 0x48, 0x4B, 0x4A, 0x58, 0xCB, 0xD3,
-  0xD2, 0xCD, 0x58, 0x47, 0x4A, 0xFC, 0xFC, 0xFB,
-  0xFC, 0x2B, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x26, 0x21, 0x21, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
-  0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0xE5, 0xC8,
-  0xBA, 0xC5, 0xC6, 0xC6, 0xC6, 0xC7, 0xC6, 0xC7,
-  0xC5, 0xC6, 0xC8, 0xE5, 0x2E, 0x54, 0x58, 0x57,
-  0x57, 0x4C, 0x4D, 0xDA, 0xD8, 0xD8, 0xD4, 0x5C,
-  0x4B, 0x4B, 0x3F, 0x42, 0x44, 0x4A, 0x51, 0x58,
-  0x4B, 0x48, 0x4B, 0x51, 0x4D, 0x5F, 0xD0, 0xD1,
-  0xD0, 0x64, 0x51, 0x44, 0x6B, 0xFC, 0xFB, 0xFC,
-  0xFC, 0x21, 0x23, 0x22, 0x22, 0x23, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x26, 0x21, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
-  0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0xE5, 0xED,
-  0xE7, 0xBA, 0xC8, 0xC6, 0xC6, 0xC6, 0xC6, 0xC7,
-  0xC7, 0xE5, 0xED, 0xE6, 0x61, 0x41, 0x52, 0x58,
-  0x58, 0x57, 0x45, 0x5E, 0xD7, 0xDD, 0xD5, 0x60,
-  0x4B, 0x4C, 0x48, 0x4D, 0x4D, 0x50, 0x4D, 0x56,
-  0x4A, 0x3E, 0x53, 0x53, 0x52, 0x63, 0xD3, 0xD0,
-  0xCE, 0x60, 0x4A, 0x45, 0xFC, 0xFC, 0xF7, 0xFC,
-  0xFC, 0x21, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23,
-  0x22, 0x23, 0x21, 0x2A, 0x20, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x23, 0x22, 0x21, 0x23, 0xEB, 0xF6,
-  0xF6, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED,
-  0xF6, 0xF6, 0xF6, 0xE6, 0xDB, 0x58, 0x45, 0x4B,
-  0x58, 0x57, 0x4D, 0x4B, 0x64, 0xD4, 0xD0, 0x5C,
-  0x48, 0x51, 0x4C, 0x5D, 0x5E, 0x5C, 0x56, 0x59,
-  0x3E, 0x4A, 0x58, 0x54, 0x52, 0x65, 0xD3, 0xD0,
-  0xCF, 0x5D, 0x48, 0xFC, 0xFC, 0xFC, 0xFA, 0xFC,
-  0xFC, 0x21, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23,
-  0x22, 0x23, 0x21, 0x2A, 0x21, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x23, 0x22, 0x21, 0x4F, 0xE6, 0xC6,
-  0xC6, 0xBD, 0xC6, 0xBD, 0xBD, 0xBD, 0xBD, 0xC6,
-  0xC5, 0xBA, 0xC7, 0xE6, 0xF2, 0xD4, 0x49, 0x4B,
-  0x3E, 0x4D, 0x52, 0x3E, 0x52, 0x63, 0x64, 0x56,
-  0x48, 0x54, 0x4D, 0x61, 0xCC, 0xCC, 0x60, 0x60,
-  0x47, 0x4D, 0x5C, 0x53, 0x58, 0xCF, 0xD1, 0xCF,
-  0xD0, 0x59, 0x45, 0xFC, 0xFC, 0xFC, 0xEF, 0xF9,
-  0xFC, 0x21, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
-  0x23, 0x22, 0x23, 0x2A, 0x21, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x23, 0x22, 0x23, 0x4F, 0xE4, 0xB9,
-  0xAF, 0x80, 0x80, 0x8E, 0x8E, 0x8E, 0x8E, 0x8F,
-  0x80, 0xB4, 0xB9, 0xE4, 0x7F, 0xDE, 0x61, 0x52,
-  0x54, 0x48, 0x3F, 0x43, 0x4D, 0x56, 0x59, 0x4B,
-  0x3E, 0x58, 0x53, 0x61, 0xD3, 0xD4, 0xCF, 0xCD,
-  0x4C, 0x58, 0x5F, 0x53, 0x5E, 0xD3, 0xD0, 0xCE,
-  0xCE, 0x52, 0x3F, 0xFC, 0xFC, 0xFC, 0xF7, 0x65,
-  0xFA, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
-  0x23, 0x22, 0x21, 0x2A, 0x23, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x23, 0x22, 0x21, 0xB1, 0xE4, 0xE6,
-  0x7C, 0xB1, 0x7C, 0xB1, 0xB2, 0xB2, 0xB3, 0x3D,
-  0xB3, 0x3C, 0xE5, 0xB3, 0xB0, 0xF1, 0xD0, 0x58,
-  0x5D, 0x4D, 0x40, 0x41, 0x48, 0x51, 0x4C, 0x3F,
-  0x3F, 0x4D, 0x5A, 0x5A, 0xD5, 0xD9, 0xD7, 0xD4,
-  0x57, 0x5E, 0x61, 0x4C, 0x63, 0xD4, 0xCF, 0xCE,
-  0xCB, 0x4D, 0x4A, 0xFC, 0xFC, 0xFC, 0xFC, 0xF0,
-  0xFB, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
-  0x23, 0x22, 0x23, 0x2A, 0x21, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x22, 0x23, 0x22, 0x23, 0x23, 0xB1, 0x81, 0x7D,
-  0x39, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36,
-  0x36, 0x36, 0x7C, 0xB2, 0xB0, 0xDF, 0xD2, 0x57,
-  0x60, 0x59, 0x5B, 0x59, 0x52, 0x4C, 0x4A, 0x40,
-  0x42, 0x4A, 0x53, 0x4D, 0xD2, 0xDE, 0xDE, 0xD9,
-  0x5E, 0x5E, 0x60, 0x4A, 0xCD, 0xD1, 0xCF, 0xCE,
-  0x63, 0x49, 0x5C, 0xFB, 0xE8, 0x89, 0x9F, 0xFC,
-  0xD6, 0x21, 0x21, 0x23, 0x22, 0x22, 0x23, 0x22,
-  0x23, 0x22, 0x21, 0x2A, 0x22, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x7F, 0xB9,
-  0x71, 0x6C, 0x38, 0x38, 0x33, 0x33, 0x33, 0x38,
-  0x38, 0x71, 0xAD, 0xE4, 0xD3, 0xDA, 0xCC, 0x52,
-  0x63, 0x60, 0xCE, 0xD4, 0xCF, 0x60, 0x4C, 0x40,
-  0x3F, 0x45, 0x4B, 0x5A, 0xCB, 0xD8, 0xDE, 0xDC,
-  0x5E, 0x5E, 0x5F, 0x4C, 0xD2, 0xD2, 0xCF, 0xCF,
-  0x61, 0x45, 0x5E, 0xA7, 0x9D, 0x95, 0x8B, 0x99,
-  0xFC, 0x41, 0x21, 0x23, 0x23, 0x22, 0x23, 0x22,
-  0x23, 0x22, 0x23, 0x2A, 0x23, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x77, 0x77, 0xF6,
-  0xFC, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7D,
-  0x7D, 0xFC, 0x47, 0x64, 0xD0, 0xD0, 0x5D, 0x4B,
-  0x62, 0xCC, 0xD1, 0xDE, 0xDE, 0xD4, 0x5E, 0x43,
-  0x3F, 0x3E, 0x48, 0x53, 0x58, 0xDB, 0xD8, 0xDC,
-  0x5E, 0x5E, 0x5E, 0x53, 0xD4, 0xD2, 0xD0, 0xD0,
-  0x5E, 0x49, 0xA7, 0xA6, 0x89, 0x95, 0x8B, 0x9C,
-  0x9C, 0xFB, 0xD4, 0x22, 0x22, 0x22, 0x22, 0x23,
-  0x22, 0x23, 0x23, 0x2A, 0x22, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
-  0x23, 0x22, 0x23, 0x23, 0x98, 0x8C, 0x8C, 0x88,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8,
-  0xE9, 0x9C, 0x48, 0x5C, 0xD0, 0xCB, 0x48, 0x49,
-  0x5B, 0xCB, 0xCD, 0xE0, 0xF1, 0xDD, 0xD0, 0x4A,
-  0x41, 0x47, 0x45, 0x4C, 0x48, 0xD7, 0xDE, 0xDC,
-  0x5E, 0x5E, 0x5A, 0x58, 0xD1, 0xD0, 0xD0, 0xD2,
-  0x5C, 0x55, 0xA7, 0xA6, 0x87, 0x86, 0x89, 0x94,
-  0x9C, 0xA9, 0xFC, 0xF4, 0x22, 0x23, 0x22, 0x23,
-  0x22, 0x23, 0x22, 0x2A, 0x21, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
-  0x22, 0x23, 0x22, 0x23, 0xA4, 0x89, 0x8C, 0xAA,
-  0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF7,
-  0x85, 0x88, 0x8D, 0x59, 0x64, 0x63, 0x47, 0x3E,
-  0x4C, 0x60, 0x61, 0xE0, 0xF0, 0xDF, 0xD9, 0x5D,
-  0x2E, 0x3E, 0x3E, 0x47, 0x4D, 0xCD, 0xDE, 0xDC,
-  0x5D, 0x5C, 0x51, 0x5D, 0xD1, 0xD2, 0xD2, 0xD4,
-  0x5A, 0xBE, 0xA7, 0x98, 0x8A, 0x8A, 0xA0, 0x8B,
-  0x86, 0x86, 0xF7, 0xFC, 0xF7, 0x26, 0x23, 0x23,
-  0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
-  0x22, 0x21, 0x21, 0x21, 0xA1, 0x98, 0x9F, 0xBF,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xA7,
-  0x8C, 0x86, 0x8D, 0x59, 0x5E, 0x5D, 0x3F, 0x3E,
-  0x47, 0x53, 0x63, 0xD9, 0xF0, 0xF1, 0xDE, 0xD0,
-  0x43, 0x3E, 0x47, 0x45, 0x4A, 0x5B, 0xDC, 0xDA,
-  0x5D, 0x59, 0x49, 0x5F, 0xD1, 0xD2, 0xD3, 0xB9,
-  0xA5, 0xA7, 0x98, 0x9B, 0x96, 0x9D, 0x89, 0x89,
-  0x8B, 0x9C, 0x9D, 0xFC, 0xFC, 0xFC, 0x26, 0x22,
-  0x23, 0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
-  0x22, 0x22, 0x29, 0x2D, 0x99, 0x99, 0xA2, 0xAA,
-  0xC4, 0xFB, 0xFC, 0xFC, 0xFC, 0xF6, 0xBF, 0xA2,
-  0x9C, 0x9C, 0x8E, 0xDC, 0xCD, 0x51, 0x41, 0x3E,
-  0x45, 0x49, 0x58, 0xCD, 0xE0, 0xE0, 0xD8, 0xDA,
-  0x4C, 0x4A, 0x45, 0x45, 0x48, 0x47, 0xDA, 0xDA,
-  0x5C, 0x58, 0x44, 0x69, 0xA9, 0x98, 0xA4, 0xA6,
-  0xA1, 0xA4, 0x99, 0x9E, 0x9D, 0x8B, 0x8A, 0x97,
-  0x87, 0x9A, 0x8A, 0xC2, 0xFC, 0xFC, 0xFC, 0x4D,
-  0x21, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x22,
-  0x21, 0x22, 0x2D, 0x34, 0xA4, 0xA2, 0xA2, 0xA9,
-  0xBF, 0xC0, 0xC3, 0xC1, 0xC0, 0xBE, 0xA6, 0x9D,
-  0x99, 0x87, 0xA2, 0xF1, 0xDC, 0x64, 0x42, 0x45,
-  0x47, 0x3E, 0x49, 0x4C, 0xDD, 0xDF, 0xD8, 0xDB,
-  0x5E, 0x4C, 0x48, 0x45, 0x45, 0x41, 0xD1, 0xD6,
-  0x5A, 0x55, 0x3F, 0xA7, 0xA1, 0x98, 0x9F, 0x99,
-  0x9F, 0x9D, 0x9A, 0x95, 0x8B, 0x97, 0x89, 0x8A,
-  0x88, 0x94, 0x9C, 0x8C, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xF4, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
-  0x23, 0x23, 0x2C, 0x2C, 0xA8, 0xA2, 0xA4, 0xA4,
-  0xA9, 0xAA, 0xAA, 0xAA, 0xA9, 0xA6, 0x98, 0x9C,
-  0x8B, 0x88, 0x98, 0x8D, 0xD8, 0xD6, 0x4E, 0x47,
-  0x47, 0x49, 0x47, 0x3F, 0xDA, 0xDD, 0xDE, 0xDD,
-  0xCC, 0x4A, 0x4B, 0x3E, 0x45, 0x43, 0x61, 0xD4,
-  0x56, 0x51, 0x44, 0xA4, 0x9B, 0x8B, 0x9C, 0x9A,
-  0xA0, 0xA2, 0x98, 0x98, 0x8B, 0x8B, 0x98, 0x98,
-  0x84, 0x8B, 0x94, 0x8A, 0xA4, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xF2, 0x21, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x23,
-  0x23, 0x22, 0x2C, 0x2D, 0xC0, 0xA4, 0xA2, 0xA4,
-  0xA4, 0xA6, 0xA6, 0xA6, 0xA4, 0xA2, 0x9F, 0x89,
-  0x8B, 0x9C, 0x9C, 0x8B, 0x68, 0xDB, 0x5F, 0x4B,
-  0x3E, 0x49, 0x4B, 0x3E, 0xCC, 0xDA, 0xDC, 0xDD,
-  0xD3, 0x49, 0x52, 0x48, 0x45, 0x45, 0x53, 0xD0,
-  0x51, 0x4A, 0x44, 0xA4, 0x9B, 0x8B, 0x9C, 0xA0,
-  0x9B, 0x86, 0x89, 0x98, 0x89, 0x8A, 0x96, 0x8A,
-  0x9C, 0x89, 0x89, 0x9C, 0x8C, 0xF6, 0xFC, 0xFC,
-  0xFC, 0xFC, 0x21, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x23,
-  0x22, 0x21, 0x2B, 0x34, 0xC0, 0xA8, 0xA4, 0xA2,
-  0xA2, 0x98, 0xA1, 0xA0, 0x98, 0x9F, 0x95, 0x8A,
-  0x94, 0xA1, 0x8A, 0x84, 0x9B, 0x68, 0xCC, 0x49,
-  0x4A, 0x47, 0x4C, 0x4B, 0x51, 0xD3, 0xDA, 0xDC,
-  0xD5, 0x56, 0x56, 0x4A, 0x3E, 0x45, 0x48, 0x63,
-  0x4A, 0x47, 0x3E, 0xA7, 0x98, 0x9D, 0x9E, 0x8B,
-  0x95, 0x9B, 0x89, 0x86, 0x9B, 0x8B, 0x89, 0x84,
-  0x9A, 0xA1, 0x95, 0x9A, 0x8C, 0xA4, 0xFC, 0xFC,
-  0xFC, 0xFA, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x23,
-  0x21, 0x23, 0x2C, 0xF6, 0xBF, 0xA9, 0xA2, 0x99,
-  0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9B, 0x87, 0x8B,
-  0x9C, 0x86, 0x9C, 0x8A, 0x87, 0x87, 0x89, 0x51,
-  0x54, 0x47, 0x4B, 0x50, 0x4B, 0xCF, 0xD6, 0xDC,
-  0xD5, 0x60, 0x54, 0x52, 0x48, 0x45, 0x40, 0x5A,
-  0x45, 0x43, 0x47, 0xA7, 0x98, 0x9B, 0x95, 0x95,
-  0x9A, 0x87, 0x98, 0x98, 0x8A, 0x86, 0x87, 0x9E,
-  0x9B, 0x95, 0x9D, 0x9D, 0x99, 0x85, 0xA6, 0xFA,
-  0xF2, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x22,
-  0x21, 0x24, 0xFB, 0xF7, 0xBF, 0xA6, 0xA2, 0x99,
-  0x97, 0x89, 0x86, 0x89, 0x9C, 0x96, 0x9E, 0x94,
-  0x89, 0x99, 0x98, 0x89, 0x9E, 0x9B, 0x89, 0x8B,
-  0x58, 0x4B, 0x4A, 0x52, 0x48, 0xCC, 0xD3, 0xDA,
-  0xD3, 0x65, 0x4C, 0x58, 0x49, 0x3E, 0x2E, 0x4D,
-  0x40, 0x41, 0x45, 0xA9, 0xA1, 0x9B, 0x9E, 0x9C,
-  0x95, 0x8A, 0x94, 0x89, 0x96, 0x87, 0x9C, 0x9A,
-  0x84, 0x9D, 0x9C, 0x9E, 0x9A, 0x9C, 0x9D, 0xBB,
-  0x23, 0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x23, 0x23,
-  0x24, 0xFC, 0xFC, 0xF6, 0xBF, 0xA6, 0x9F, 0x99,
-  0x89, 0x95, 0x87, 0x94, 0x9D, 0x9E, 0x97, 0x9E,
-  0x95, 0x9B, 0x89, 0x95, 0x95, 0x9B, 0x89, 0x87,
-  0x5D, 0x56, 0x3E, 0x51, 0x3E, 0x60, 0xCF, 0xD3,
-  0xD2, 0xCD, 0x5C, 0x49, 0x4B, 0x3E, 0x2C, 0x48,
-  0x3E, 0x43, 0x3E, 0xA9, 0xA1, 0x9B, 0x97, 0x94,
-  0x95, 0x9A, 0x9C, 0x87, 0x87, 0x9B, 0x9C, 0x95,
-  0x9D, 0x89, 0x9A, 0x89, 0x9E, 0x9E, 0x8C, 0xA6,
-  0x20, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x22, 0x22, 0x21, 0x21, 0x20, 0x40,
-  0xFC, 0xFC, 0xFC, 0xEC, 0xBE, 0xA4, 0x9F, 0x99,
-  0x95, 0x9F, 0xA0, 0x88, 0x9D, 0x8B, 0x97, 0x95,
-  0x87, 0x95, 0x96, 0x95, 0x97, 0x94, 0x94, 0x98,
-  0xD3, 0x4C, 0x47, 0x4D, 0x42, 0x4C, 0x60, 0xCC,
-  0xCE, 0xD0, 0x65, 0x4B, 0x47, 0x44, 0x2B, 0x45,
-  0x4B, 0x47, 0x49, 0xA7, 0xA1, 0x9A, 0x97, 0x89,
-  0x95, 0x97, 0x97, 0x9E, 0x89, 0x95, 0x89, 0x9C,
-  0x87, 0x95, 0x97, 0x99, 0x95, 0x99, 0x9F, 0xA4,
-  0xC4, 0x21, 0x21, 0x23, 0x21, 0x23, 0x23, 0x23,
-  0x23, 0x23, 0x23, 0x23, 0x21, 0x20, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xEA, 0xAA, 0xA6, 0xA2, 0x99,
-  0x8B, 0x9A, 0x95, 0x9E, 0x9E, 0x9A, 0x94, 0x87,
-  0x94, 0x94, 0x89, 0x94, 0x9B, 0x9B, 0xA7, 0xDC,
-  0xDB, 0x65, 0x2E, 0x3E, 0x43, 0x44, 0x49, 0x58,
-  0x63, 0xD3, 0xD3, 0x5E, 0x42, 0x42, 0x2D, 0x40,
-  0x54, 0x4C, 0x4A, 0xA7, 0xA0, 0x99, 0x9B, 0x94,
-  0xA0, 0x8A, 0x9B, 0x9D, 0x87, 0x95, 0x94, 0x8B,
-  0x8A, 0x98, 0x9C, 0x8A, 0x9B, 0x99, 0xA2, 0xA6,
-  0xBF, 0xEC, 0x2A, 0x20, 0x21, 0x23, 0x21, 0x20,
-  0x20, 0x20, 0x20, 0x4C, 0xF9, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xEB, 0xAA, 0xA4, 0x9F, 0x9C,
-  0x8B, 0x9B, 0x88, 0x84, 0x9E, 0x9D, 0x96, 0x94,
-  0x94, 0x9A, 0x9B, 0x9B, 0xA4, 0xD5, 0xCD, 0xDE,
-  0xF1, 0xDA, 0x4C, 0x2D, 0x41, 0x2B, 0x42, 0x4C,
-  0x5E, 0xD4, 0xD7, 0xCD, 0x49, 0x2E, 0x2E, 0x41,
-  0x5E, 0x57, 0xA7, 0xA6, 0xA7, 0xA4, 0xA2, 0x98,
-  0x9D, 0x9C, 0xA1, 0x99, 0x9D, 0x88, 0x8B, 0x9C,
-  0x8A, 0x9C, 0x9C, 0x94, 0x9C, 0x89, 0xA0, 0xA6,
-  0xAA, 0xEB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFB, 0xE9, 0xAA, 0xA6, 0xA2, 0x8B,
-  0x8B, 0x8A, 0x86, 0x9B, 0x9C, 0x98, 0xA0, 0x9B,
-  0x9B, 0x84, 0xA7, 0xB4, 0x61, 0xD1, 0xD2, 0xE0,
-  0xF1, 0xDC, 0x61, 0x2D, 0x2E, 0x3F, 0x56, 0x62,
-  0x5D, 0xD4, 0xD9, 0xD3, 0x54, 0x41, 0x41, 0x44,
-  0xCB, 0x60, 0x52, 0xA9, 0xA9, 0xA9, 0xA7, 0xA6,
-  0xA6, 0xA4, 0xA4, 0xA2, 0xA2, 0x9D, 0x95, 0x89,
-  0x9C, 0x8A, 0x9E, 0x9C, 0x8A, 0x9E, 0xA0, 0xA8,
-  0xC0, 0xE9, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xE9, 0xAA, 0xA6, 0xA0, 0x99,
-  0x9C, 0x8B, 0x9A, 0x84, 0x9B, 0x9B, 0x98, 0x98,
-  0xA9, 0xB9, 0x49, 0x57, 0xCB, 0xD4, 0xD3, 0xF1,
-  0xD8, 0xDA, 0xCE, 0x3F, 0x41, 0x4B, 0x5D, 0xCB,
-  0x5E, 0xD6, 0xDB, 0xD6, 0x5D, 0x43, 0x3F, 0x49,
-  0xD1, 0xCC, 0x4F, 0xDD, 0xC3, 0xBB, 0xBF, 0xAA,
-  0xAA, 0xA9, 0xAA, 0xA8, 0xA8, 0xA6, 0xA6, 0xA2,
-  0x9C, 0x9F, 0x9B, 0x9A, 0x9D, 0xA2, 0xA8, 0xAA,
-  0xC1, 0xEA, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xEA, 0xC0, 0xAA, 0xA6, 0xA2,
-  0xA2, 0x99, 0xA0, 0xA0, 0xA4, 0xA7, 0xA9, 0xC0,
-  0x67, 0x49, 0x54, 0x60, 0xD0, 0xD4, 0xCC, 0xDF,
-  0xD9, 0xD5, 0xD2, 0x3E, 0x47, 0x56, 0x60, 0xCD,
-  0x5D, 0xD9, 0xD9, 0xD6, 0x61, 0x3F, 0x47, 0x52,
-  0xD6, 0xD3, 0x62, 0x4D, 0x40, 0x4A, 0x57, 0xCA,
-  0xC3, 0xC1, 0xC1, 0xC0, 0xBF, 0xBF, 0xAA, 0xAA,
-  0xA6, 0xA4, 0xA4, 0xA4, 0xA6, 0xA8, 0xBE, 0xC1,
-  0xC9, 0xEB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xEB, 0xC3, 0xC0, 0xAA, 0xA8,
-  0xA6, 0xA6, 0xA6, 0xA9, 0xAA, 0xC0, 0xE8, 0xD0,
-  0xD2, 0x4C, 0x5E, 0x64, 0xD0, 0xD1, 0x5F, 0xD9,
-  0xD5, 0xD1, 0xD0, 0x48, 0x52, 0x5C, 0x64, 0xCD,
-  0x5C, 0xDC, 0xD7, 0xD5, 0x62, 0x3F, 0x4C, 0x53,
-  0xDA, 0xD7, 0xCE, 0x56, 0x40, 0x4B, 0x52, 0x56,
-  0xCE, 0xDF, 0x6A, 0xEB, 0xE9, 0xC9, 0xC3, 0xC0,
-  0xC0, 0xBF, 0xBE, 0xAA, 0xBF, 0xC0, 0xC3, 0xC9,
-  0xEA, 0xF6, 0xEE, 0x58, 0x57, 0x5E, 0xD6, 0xD0,
-  0xD2, 0x61, 0xCB, 0xD6, 0xD6, 0xD4, 0xDF, 0xF3,
-  0xF2, 0xDD, 0xD7, 0xEB, 0xC9, 0xC1, 0xC0, 0xBF,
-  0xAA, 0xAA, 0xAA, 0xBE, 0xC3, 0xF0, 0xD2, 0xD2,
-  0xD2, 0x51, 0x62, 0xCC, 0xD0, 0xCC, 0x61, 0xD3,
-  0xCF, 0xCE, 0xD2, 0x48, 0x5A, 0x61, 0xCC, 0xCE,
-  0x5F, 0xD9, 0xD5, 0xD1, 0x63, 0x44, 0x56, 0x56,
-  0xDC, 0xD9, 0xD4, 0x5E, 0x42, 0x4A, 0x4C, 0x57,
-  0x5D, 0xD8, 0xE0, 0xD8, 0xDC, 0xCB, 0x66, 0xEC,
-  0xE8, 0xC3, 0xC3, 0xC3, 0xC3, 0xC9, 0xE8, 0xEA,
-  0xF6, 0x50, 0x3E, 0x58, 0x57, 0x5A, 0xD6, 0xD4,
-  0xCC, 0x4B, 0x53, 0x5C, 0x64, 0xD1, 0xDF, 0xF3,
-  0xF1, 0xDE, 0xD9, 0xF6, 0xEB, 0xC9, 0xC1, 0xC1,
-  0xC0, 0xC0, 0xC1, 0xC9, 0xF0, 0xD6, 0xCD, 0xD6,
-  0xD3, 0x53, 0xCB, 0xCF, 0xCD, 0x5F, 0x5F, 0xCE,
-  0xCF, 0xCD, 0xD0, 0x47, 0x5F, 0xCB, 0xCE, 0xCD,
-  0x63, 0xD6, 0xD3, 0xD1, 0x63, 0x3F, 0x58, 0x58,
-  0xDB, 0xDC, 0xDA, 0x65, 0x3E, 0x49, 0x49, 0x4D,
-  0x49, 0xDC, 0xDF, 0xE0, 0xDE, 0xD5, 0x47, 0x47,
-  0x46, 0x6B, 0xEB, 0xEA, 0xE9, 0xEA, 0xEB, 0xF6,
-  0xD0, 0x57, 0x57, 0x47, 0x47, 0x5B, 0xD4, 0xD4,
-  0xCD, 0x44, 0x3E, 0x4B, 0x50, 0x4B, 0x51, 0xD5,
-  0xDB, 0xD8, 0xDE, 0x4B, 0xF6, 0xF6, 0xEA, 0xE9,
-  0xE8, 0xEA, 0xEB, 0x67, 0x5E, 0xCC, 0xD6, 0xDC,
-  0xD5, 0x58, 0xCE, 0xCE, 0x62, 0x50, 0xCC, 0xD3,
-  0xD2, 0xCD, 0xCD, 0x4B, 0x64, 0xCE, 0xCE, 0x64,
-  0xCC, 0xD3, 0xD2, 0xD2, 0x61, 0x47, 0x5D, 0x5C,
-  0xDD, 0xDD, 0xD9, 0xD1, 0x4C, 0x47, 0x49, 0x4A,
-  0x4B, 0xD1, 0xD8, 0xE0, 0xDF, 0xDD, 0x5D, 0x4A,
-  0x48, 0x52, 0x51, 0x3F, 0xF6, 0xEC, 0xE0, 0xE0,
-  0xD3, 0x5E, 0x5F, 0x50, 0x4B, 0x50, 0xCB, 0xCE,
-  0x64, 0x45, 0x4C, 0x57, 0x57, 0x58, 0x52, 0xD6,
-  0xD3, 0xDE, 0xDF, 0xD1, 0x3E, 0x4B, 0xF6, 0xF6,
-  0xEC, 0x66, 0x53, 0x43, 0x56, 0xD1, 0xD9, 0xDE,
-  0xD4, 0x5E, 0xCE, 0xCC, 0x5B, 0x2C, 0xD4, 0xD5,
-  0xD2, 0xD0, 0x63, 0x5D, 0xCD, 0xD0, 0xCD, 0x5E,
-  0xD0, 0xCF, 0xCE, 0xD2, 0x5E, 0x50, 0x60, 0x5D,
-  0xDE, 0xDD, 0xDC, 0xD7, 0x5D, 0x45, 0x47, 0x3E,
-  0x4B, 0x5E, 0xDE, 0xDF, 0xE0, 0xD8, 0xCF, 0x3E,
-  0x45, 0x51, 0x58, 0x42, 0xCB, 0xDA, 0xDE, 0xD8,
-  0xD2, 0x61, 0xCC, 0xCF, 0xD6, 0xDA, 0xDA, 0xD5,
-  0xD0, 0x50, 0x44, 0x57, 0x57, 0x58, 0x45, 0xD1,
-  0xD1, 0xD7, 0xDF, 0xDF, 0xD7, 0xCF, 0x64, 0x60,
-  0xCE, 0xCE, 0xCE, 0x63, 0xCF, 0xDA, 0xDE, 0xD9,
-  0xCF, 0x63, 0xCD, 0x63, 0x4D, 0x4B, 0xD6, 0xD5,
-  0xCE, 0xD3, 0x60, 0xCB, 0xD0, 0xD0, 0x65, 0x47,
-  0xD0, 0xCC, 0xCC, 0xD1, 0x59, 0x5D, 0x63, 0x5E,
-  0xDD, 0xDD, 0xDE, 0xDC, 0xCB, 0x40, 0x48, 0x45,
-  0x3E, 0x3E, 0xD9, 0xDF, 0xE0, 0xDF, 0xDA, 0x51,
-  0x4C, 0x48, 0x56, 0x4C, 0x5B, 0xD2, 0xDA, 0xDB,
-  0xCB, 0x5F, 0xD0, 0xCC, 0xDC, 0xF0, 0xF3, 0xE0,
-  0xDD, 0xCC, 0x41, 0x50, 0x57, 0x57, 0x4B, 0x5D,
-  0xD3, 0xD1, 0xDE, 0xDF, 0xDE, 0xD7, 0xD0, 0xD0,
-  0xD5, 0xD6, 0xD6, 0xCE, 0xD7, 0xDC, 0xDA, 0xD5,
-  0x60, 0x63, 0x64, 0x5E, 0x47, 0x61, 0xD5, 0xD2,
-  0xCF, 0xD0, 0x59, 0xCD, 0xD1, 0xCF, 0x61, 0x4D,
-  0xCC, 0xCE, 0xCD, 0xD0, 0x52, 0x61, 0x64, 0x60,
-  0xDA, 0xDE, 0xDE, 0xDD, 0xD1, 0x4B, 0x4A, 0x45,
-  0x3E, 0x41, 0xCD, 0xDE, 0xE0, 0xF1, 0xDE, 0x63,
-  0x4A, 0x4A, 0x4A, 0x4B, 0x50, 0xCB, 0xD4, 0xD7,
-  0x5E, 0x54, 0x62, 0xD3, 0xD4, 0xF0, 0xF3, 0xF3,
-  0xF2, 0xDE, 0x61, 0x40, 0x49, 0x56, 0x4D, 0x3E,
-  0x4B, 0xCE, 0xD9, 0xD8, 0xD9, 0xD5, 0xCF, 0xD2,
-  0xD6, 0xD6, 0xD1, 0xD1, 0xD7, 0xD5, 0xCF, 0xD0,
-  0x54, 0x64, 0x63, 0x56, 0x2C, 0xCB, 0xD1, 0xCC,
-  0xD3, 0xCD, 0x54, 0xCF, 0xD1, 0xCE, 0x5E, 0x5C,
-  0xCE, 0xCE, 0xCE, 0xCB, 0x4B, 0x63, 0xCC, 0x61,
-  0xD4, 0xDC, 0xDE, 0xDE, 0xDA, 0x5D, 0x45, 0x45,
-  0x48, 0x3F, 0x52, 0xD9, 0xD8, 0xDF, 0xDF, 0xD2,
-  0x52, 0x4B, 0x3E, 0x2E, 0x47, 0x60, 0xCF, 0xD3,
-  0x59, 0x48, 0x50, 0x5E, 0xCC, 0xDE, 0xF2, 0xF2,
-  0xF3, 0xF3, 0xDD, 0x5D, 0x3E, 0x48, 0x47, 0x47,
-  0x58, 0xD1, 0xDA, 0xDA, 0xD5, 0xD1, 0xCD, 0xD2,
-  0xD3, 0xCF, 0xD3, 0xD1, 0xCD, 0xD3, 0xD2, 0x5E,
-  0x52, 0x64, 0x60, 0x4B, 0x45, 0x61, 0xCD, 0xD3,
-  0xD3, 0x64, 0x61, 0xD0, 0xD0, 0x64, 0x45, 0x63,
-  0xD0, 0xCE, 0xD0, 0x60, 0x56, 0xCB, 0xCC, 0x62,
-  0xCE, 0xDA, 0xDE, 0xD8, 0xDD, 0xCC, 0x45, 0x49,
-  0x3E, 0x47, 0x42, 0xD1, 0xDC, 0xD8, 0xD8, 0xD3,
-  0x5D, 0x4C, 0x49, 0x3F, 0x47, 0x59, 0xCD, 0xCF,
-  0x59, 0x2E, 0x48, 0x47, 0x52, 0x63, 0xF0, 0xF2,
-  0xF3, 0xF3, 0xF2, 0xDA, 0x52, 0x4B, 0x52, 0x58,
-  0x5E, 0x63, 0xD0, 0xD0, 0xD0, 0xCF, 0xCE, 0xCE,
-  0xCF, 0x65, 0x61, 0xD6, 0xD6, 0xD6, 0xCB, 0x4B,
-  0x61, 0x62, 0x5D, 0x43, 0x4B, 0x61, 0xD0, 0xD4,
-  0xD1, 0x61, 0xCE, 0xD2, 0xCD, 0x5E, 0x4A, 0xCE,
-  0xD0, 0xCC, 0xD0, 0x59, 0x61, 0xCC, 0xCC, 0x62,
-  0xD1, 0xD5, 0xDE, 0xD8, 0xDD, 0xCF, 0x4B, 0x4A,
-  0x45, 0x3E, 0x2D, 0xCB, 0xDC, 0xDE, 0xD8, 0xD5,
-  0x60, 0x54, 0x51, 0x4C, 0x4D, 0x5C, 0xCC, 0xCE,
-  0x5A, 0x2C, 0x50, 0x53, 0x3E, 0x59, 0xD8, 0xF3,
-  0xF2, 0xF3, 0xF3, 0xE0, 0x5E, 0x4A, 0x4C, 0x53,
-  0x5E, 0x63, 0xCC, 0xCC, 0xCC, 0xCD, 0xCF, 0xD3,
-  0x62, 0x53, 0xD6, 0xD6, 0xD6, 0xD6, 0x5B, 0x48,
-  0x64, 0x63, 0x59, 0x44, 0x57, 0x63, 0xD2, 0xD3,
-  0xD0, 0x5E, 0xD0, 0xD1, 0xCB, 0x58, 0x4C, 0xCF,
-  0xCF, 0xCE, 0xCE, 0x57, 0x63, 0xCC, 0xCD, 0x57,
-};
-
diff -u --recursive --new-file v2.4.5/linux/drivers/sound/aci.c linux/drivers/sound/aci.c
--- v2.4.5/linux/drivers/sound/aci.c	Fri Apr 13 20:26:07 2001
+++ linux/drivers/sound/aci.c	Tue Jun 12 10:56:11 2001
@@ -45,6 +45,8 @@
  *        ioctl bugfix, and integration of solo-mode into OSS-API,
  *        added (OSS-limited) equalizer support, return value bugfix,
  *        changed param aci_reset to reset, new params: ide, wss.
+ *   2001-04-20  Robert Siemer
+ *        even more cleanups...
  */
 
 #include <linux/kernel.h>
@@ -95,17 +97,19 @@
 MODULE_PARM_DESC(wss,"change between ACI/WSS-mixer; use 0 and 1 - untested"
 		 " default: do nothing; for PCM1-pro only");
 
+#if DEBUG
 static void print_bits(unsigned char c)
 {
 	int j;
 	printk(KERN_DEBUG "aci: ");
 
 	for (j=7; j>=0; j--) {
-		printk(KERN_DEBUG "%d", (c >> j) & 0x1);
+		printk("%d", (c >> j) & 0x1);
 	}
 
-	printk(KERN_DEBUG "\n");
+	printk("\n");
 }
+#endif
 
 /*
  * This busy wait code normally requires less than 15 loops and
@@ -269,12 +273,12 @@
 	int buf;
 
 	/* left channel */
-	if ((buf=aci_indexed_cmd(0xf0, left_index))<0)
+	if ((buf=aci_indexed_cmd(ACI_STATUS, left_index))<0)
 		return buf;
 	vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0);
 	
 	/* right channel */
-	if ((buf=aci_indexed_cmd(0xf0, right_index))<0)
+	if ((buf=aci_indexed_cmd(ACI_STATUS, right_index))<0)
 		return buf;
 	vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8;
 
@@ -342,12 +346,12 @@
 	unsigned int vol;
 
 	/* left channel */
-	if ((buf=aci_indexed_cmd(0xf0, left_index))<0)
+	if ((buf=aci_indexed_cmd(ACI_STATUS, left_index))<0)
 		return buf;
 	vol = eq_aci2oss(buf);
 	
 	/* right channel */
-	if ((buf=aci_indexed_cmd(0xf0, right_index))<0)
+	if ((buf=aci_indexed_cmd(ACI_STATUS, right_index))<0)
 		return buf;
 	vol |= eq_aci2oss(buf) << 8;
 
@@ -399,7 +403,7 @@
 			if (vol > 100)
 				vol = 100;
 			vol = SCALE(100, 3, vol);
-			if ((buf=aci_write_cmd(0x03, vol))<0)
+			if ((buf=aci_write_cmd(ACI_WRITE_IGAIN, vol))<0)
 				return buf;
 			aci_micpreamp = vol;
 			vol = SCALE(3, 100, vol);
@@ -416,7 +420,7 @@
 				vol = 1;
 			else
 				vol = 0;
-			if ((buf=aci_write_cmd(0x0f, vol))<0)
+			if ((buf=aci_write_cmd(ACI_SET_POWERAMP, vol))<0)
 				return buf;
 			aci_amp = vol;
 			if (aci_amp)
@@ -433,7 +437,7 @@
 		/* unset solo when RECSRC for PCM is requested */
 		if (aci_idcode[1]=='B' || aci_idcode[1]=='C') {
 			vol = !(buf & SOUND_MASK_PCM);
-			if ((buf=aci_write_cmd(0xd2, vol))<0)
+			if ((buf=aci_write_cmd(ACI_SET_SOLOMODE, vol))<0)
 				return buf;
 			aci_solo = vol;
 		}
@@ -502,7 +506,8 @@
 		case 'B': /* PCM12 */
 		case 'C': /* PCM20 radio */
 			if (aci_version >= 0xb0) {
-				if ((vol=aci_rw_cmd(0xf0, 0x00, -1))<0)
+				if ((vol=aci_rw_cmd(ACI_STATUS,
+						    ACI_S_GENERAL, -1))<0)
 					return vol;
 				if (vol & 0x20)
 					buf |= SOUND_MASK_PCM;
@@ -555,7 +560,8 @@
 		if (aci_idcode[1]=='B' || aci_idcode[1]=='C') {
 			/* aci_micpreamp or ACI? */
 			if (aci_version >= 0xb0) {
-				if ((buf=aci_indexed_cmd(0xf0, 0x21))<0)
+				if ((buf=aci_indexed_cmd(ACI_STATUS,
+							 ACI_S_READ_IGAIN))<0)
 					return buf;
 			}
 			else
@@ -612,17 +618,17 @@
 
 	/* force ACI into a known state */
 	for (i=0; i<3; i++)
-		if (aci_rw_cmd(0xdf, -1, -1)<0)
+		if (aci_rw_cmd(ACI_ERROR_OP, -1, -1)<0)
 			return -EFAULT;
 
 	/* official this is one aci read call: */
-	if ((aci_idcode[0]=aci_rw_cmd(0xf2, -1, -1))<0 ||
-	    (aci_idcode[1]=aci_rw_cmd(0xf2, -1, -1))<0) {
+	if ((aci_idcode[0]=aci_rw_cmd(ACI_READ_IDCODE, -1, -1))<0 ||
+	    (aci_idcode[1]=aci_rw_cmd(ACI_READ_IDCODE, -1, -1))<0) {
 		printk(KERN_ERR "aci: Failed to read idcode on 0x%03x.\n", aci_port);
 		return -EFAULT;
 	}
 
-	if ((aci_version=aci_rw_cmd(0xf1, -1, -1))<0) {
+	if ((aci_version=aci_rw_cmd(ACI_READ_VERSION, -1, -1))<0) {
 		printk(KERN_ERR "aci: Failed to read version on 0x%03x.\n", aci_port);
 		return -EFAULT;
 	}
@@ -656,22 +662,22 @@
 
 	if (reset) {
 		/* first write()s after reset fail with my PCM20 */
-		if (aci_rw_cmd(0xff, -1, -1)<0 ||
-		    aci_rw_cmd(0xdf, 0xdf, 0xdf)<0 ||
-		    aci_rw_cmd(0xdf, 0xdf, 0xdf)<0)
+		if (aci_rw_cmd(ACI_INIT, -1, -1)<0 ||
+		    aci_rw_cmd(ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP)<0 ||
+		    aci_rw_cmd(ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP)<0)
 			return -EBUSY;
 	}
 
 	/* the PCM20 is muted after reset (and reboot) */
-	if (aci_rw_cmd(0x0d, 0x00, -1)<0)
+	if (aci_rw_cmd(ACI_SET_MUTE, 0x00, -1)<0)
 		return -EBUSY;
 
 	if (ide>=0)
-		if (aci_rw_cmd(0xd0, !ide, -1)<0)
+		if (aci_rw_cmd(ACI_SET_IDE, !ide, -1)<0)
 			return -EBUSY;
 	
 	if (wss>=0 && aci_idcode[1]=='A')
-		if (aci_rw_cmd(0xd1, !!wss, -1)<0)
+		if (aci_rw_cmd(ACI_SET_WSS, !!wss, -1)<0)
 			return -EBUSY;
 
 	if (!request_region(aci_port, 3, "sound mixer (ACI)"))
diff -u --recursive --new-file v2.4.5/linux/drivers/sound/aci.h linux/drivers/sound/aci.h
--- v2.4.5/linux/drivers/sound/aci.h	Fri Apr 13 20:26:07 2001
+++ linux/drivers/sound/aci.h	Tue Jun 12 10:56:11 2001
@@ -6,9 +6,6 @@
 extern int aci_version;		/* ACI firmware version	*/
 extern int aci_rw_cmd(int write1, int write2, int write3);
 
-extern char * aci_radio_name;
-extern int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize);
-
 #define aci_indexed_cmd(a, b) aci_rw_cmd(a, b, -1)
 #define aci_write_cmd(a, b)   aci_rw_cmd(a, b, -1)
 #define aci_read_cmd(a)       aci_rw_cmd(a,-1, -1)
@@ -19,15 +16,24 @@
 
 #define RDS_REGISTER        BUSY_REGISTER
 
-#define RDS_STATUS      0x01
-#define RDS_STATIONNAME 0x02
-#define RDS_TEXT        0x03
-#define RDS_ALTFREQ     0x04
-#define RDS_TIMEDATE    0x05
-#define RDS_PI_CODE     0x06
-#define RDS_PTYTATP     0x07
-#define RDS_RESET       0x08
-#define RDS_RXVALUE     0x09
+#define ACI_SET_MUTE          0x0d
+#define ACI_SET_POWERAMP      0x0f
+#define ACI_SET_TUNERMUTE     0xa3
+#define ACI_SET_TUNERMONO     0xa4
+#define ACI_SET_IDE           0xd0
+#define ACI_SET_WSS           0xd1
+#define ACI_SET_SOLOMODE      0xd2
+#define ACI_WRITE_IGAIN       0x03
+#define ACI_WRITE_TUNE        0xa7
+#define ACI_READ_TUNERSTEREO  0xa8
+#define ACI_READ_TUNERSTATION 0xa9
+#define ACI_READ_VERSION      0xf1
+#define ACI_READ_IDCODE       0xf2
+#define ACI_INIT              0xff
+#define ACI_STATUS            0xf0
+#define     ACI_S_GENERAL     0x00
+#define     ACI_S_READ_IGAIN  0x21
+#define ACI_ERROR_OP          0xdf
 
 /*
  * The following macro SCALE can be used to scale one integer volume
@@ -47,9 +53,6 @@
  */
 
 #define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax))
-
-extern void __exit unload_aci_rds(void);
-extern int __init attach_aci_rds(void);
 
 
 #endif  /* _ACI_H_ */
diff -u --recursive --new-file v2.4.5/linux/drivers/sound/cs4281/cs4281m.c linux/drivers/sound/cs4281/cs4281m.c
--- v2.4.5/linux/drivers/sound/cs4281/cs4281m.c	Tue May  1 16:05:00 2001
+++ linux/drivers/sound/cs4281/cs4281m.c	Wed Jun 20 11:19:02 2001
@@ -946,7 +946,7 @@
 }
 
 #ifndef NOT_CS4281_PM
-void printpm(struct cs4281_state *s)
+static void printpm(struct cs4281_state *s)
 {
 	CS_DBGOUT(CS_PM, 9, printk("pm struct:\n"));
 	CS_DBGOUT(CS_PM, 9, printk("flags:0x%x u32CLKCR1_SAVE: 0%x u32SSPMValue: 0x%x\n",
@@ -967,7 +967,7 @@
 		s->pm.u32MIDCR_Save));
 
 }
-void printpipe(struct cs4281_pipeline *pl)
+static void printpipe(struct cs4281_pipeline *pl)
 {
 
 	CS_DBGOUT(CS_PM, 9, printk("pm struct:\n"));
@@ -1000,7 +1000,7 @@
 	CS_DBGOUT(CS_PM, 9, printk("u32FPDRnValue: 0x%x u32FPDRnAddress: 0x%x\n",
 		pl->u32FPDRnValue,pl->u32FPDRnAddress));
 }
-void printpipelines(struct cs4281_state *s)
+static void printpipelines(struct cs4281_state *s)
 {
 	int i;
 	for(i=0;i<CS4281_NUMBER_OF_PIPELINES;i++)
diff -u --recursive --new-file v2.4.5/linux/drivers/sound/cs46xx.c linux/drivers/sound/cs46xx.c
--- v2.4.5/linux/drivers/sound/cs46xx.c	Thu May 24 15:14:08 2001
+++ linux/drivers/sound/cs46xx.c	Wed Jun 20 11:19:02 2001
@@ -3375,7 +3375,7 @@
 	return 0;
 }
 
-void printpm(struct cs_card *s)
+static void printpm(struct cs_card *s)
 {
 	CS_DBGOUT(CS_PM, 9, printk("pm struct:\n"));
 	CS_DBGOUT(CS_PM, 9, printk("flags:0x%x u32CLKCR1_SAVE: 0%x u32SSPMValue: 0x%x\n",
@@ -3588,7 +3588,7 @@
 
 static void cs461x_reset(struct cs_card *card);
 static void cs461x_proc_stop(struct cs_card *card);
-int cs46xx_suspend(struct cs_card *card)
+static int cs46xx_suspend(struct cs_card *card)
 {
 	unsigned int tmp;
 	CS_DBGOUT(CS_PM | CS_FUNCTION, 4, 
@@ -3680,7 +3680,7 @@
 	return 0;
 }
 
-int cs46xx_resume(struct cs_card *card)
+static int cs46xx_resume(struct cs_card *card)
 {
 	int i;
 
diff -u --recursive --new-file v2.4.5/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c
--- v2.4.5/linux/drivers/sound/gus_wave.c	Sun Nov 12 20:35:35 2000
+++ linux/drivers/sound/gus_wave.c	Tue Jun 12 11:06:54 2001
@@ -2102,6 +2102,7 @@
 			break;
 
 		default:
+			break;
 	}
 }
 
@@ -3282,6 +3283,7 @@
 		break;
 
 		default:
+			break;
 	}
 	restore_flags(flags);
 }
@@ -3423,6 +3425,7 @@
 				break;
 
 			default:
+				break;
 	}
 	status = gus_look8(0x49);	/*
 					 * Get Sampling IRQ Status
diff -u --recursive --new-file v2.4.5/linux/drivers/sound/pss.c linux/drivers/sound/pss.c
--- v2.4.5/linux/drivers/sound/pss.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/sound/pss.c	Tue Jun 12 11:06:54 2001
@@ -766,6 +766,7 @@
 			break;
 
 		default:
+			break;
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.4.5/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c
--- v2.4.5/linux/drivers/sound/via82cxxx_audio.c	Tue May  1 16:05:00 2001
+++ linux/drivers/sound/via82cxxx_audio.c	Wed Jun 20 11:16:01 2001
@@ -3012,7 +3012,6 @@
 {
 	int rc;
 	struct via_info *card;
-	u8 tmp;
 	static int printed_version = 0;
 
 	DPRINTK ("ENTER\n");
@@ -3107,19 +3106,6 @@
 	if (rc) {
 		printk (KERN_ERR PFX "interrupt init failed, aborting\n");
 		goto err_out_have_proc;
-	}
-
-	pci_read_config_byte (pdev, 0x3C, &tmp);
-	if ((tmp & 0x0F) != pdev->irq) {
-		printk (KERN_WARNING PFX "IRQ fixup, 0x3C==0x%02X\n", tmp);
-		udelay (15);
-		tmp &= 0xF0;
-		tmp |= pdev->irq;
-		pci_write_config_byte (pdev, 0x3C, tmp);
-		DPRINTK ("new 0x3c==0x%02x\n", tmp);
-	} else {
-		DPRINTK ("IRQ reg 0x3c==0x%02x, irq==%d\n",
-			tmp, tmp & 0x0F);
 	}
 
 	printk (KERN_INFO PFX "board #%d at 0x%04lX, IRQ %d\n",
diff -u --recursive --new-file v2.4.5/linux/drivers/sound/wf_midi.c linux/drivers/sound/wf_midi.c
--- v2.4.5/linux/drivers/sound/wf_midi.c	Sun Sep 17 09:45:07 2000
+++ linux/drivers/sound/wf_midi.c	Tue Jun 12 11:06:54 2001
@@ -231,6 +231,7 @@
 				break;
 		    
 			default:
+				break;
 			}
 		} else {
 			mi->m_prev_status = midic;
diff -u --recursive --new-file v2.4.5/linux/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c
--- v2.4.5/linux/drivers/sound/ymfpci.c	Sat May 19 17:47:55 2001
+++ linux/drivers/sound/ymfpci.c	Tue Jun 12 11:06:54 2001
@@ -1829,6 +1829,7 @@
 		 * for instance we get SNDCTL_TMR_CONTINUE here.
 		 * XXX Is there sound_generic_ioctl() around?
 		 */
+		 break;
 	}
 	return -ENOTTY;
 }
diff -u --recursive --new-file v2.4.5/linux/drivers/telephony/ixj.c linux/drivers/telephony/ixj.c
--- v2.4.5/linux/drivers/telephony/ixj.c	Sat May 19 17:47:55 2001
+++ linux/drivers/telephony/ixj.c	Wed Jun 20 11:10:27 2001
@@ -6261,20 +6261,12 @@
 	return (((DWORD) wHi << 16) | wLo);
 }
 
-#ifndef CONFIG_PCMCIA
 #ifndef CONFIG_ISAPNP
-static int dspio[IXJMAX + 1] =
-{
-	0,
-};
-static int xio[IXJMAX + 1] =
-{
-	0,
-};
+static int dspio[IXJMAX + 1];
+static int xio[IXJMAX + 1];
 
 MODULE_PARM(dspio, "1-" __MODULE_STRING(IXJMAX) "i");
 MODULE_PARM(xio, "1-" __MODULE_STRING(IXJMAX) "i");
-#endif
 #endif
 
 void ixj_exit(void)
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.4.5/linux/drivers/usb/Config.in	Tue May 22 10:25:36 2001
+++ linux/drivers/usb/Config.in	Mon Jun 11 19:15:27 2001
@@ -53,7 +53,7 @@
    dep_tristate '  USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
    dep_tristate '  USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL
    dep_tristate '  USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
-   dep_tristate '  Microtek X6USB scanner support (EXPERIMENTAL)' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL
+   dep_tristate '  Microtek X6USB scanner support' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI
 
    comment 'USB Multimedia devices'
    dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- v2.4.5/linux/drivers/usb/acm.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/acm.c	Tue Jun 12 15:53:37 2001
@@ -709,8 +709,7 @@
 		return -1;
 	}
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 
 	return 0;
 }
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/audio.c linux/drivers/usb/audio.c
--- v2.4.5/linux/drivers/usb/audio.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/audio.c	Tue Jun 12 15:53:37 2001
@@ -3755,8 +3755,7 @@
 static int __init usb_audio_init(void)
 {
 	usb_register(&usb_audio_driver);
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/bluetooth.c linux/drivers/usb/bluetooth.c
--- v2.4.5/linux/drivers/usb/bluetooth.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/bluetooth.c	Tue Jun 12 15:53:37 2001
@@ -1,11 +1,24 @@
 /*
- * bluetooth.c   Version 0.8
+ * bluetooth.c   Version 0.10
  *
- * Copyright (c) 2000 Greg Kroah-Hartman	<greg@kroah.com>
+ * Copyright (c) 2000, 2001 Greg Kroah-Hartman	<greg@kroah.com>
  * Copyright (c) 2000 Mark Douglas Corner	<mcorner@umich.edu>
  *
  * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B
  * 
+ * (2001/05/28) Version 0.10 gkh
+ *	- Fixed problem with using data from userspace in the bluetooth_write
+ *	  function as found by the CHECKER project.
+ *	- Added a buffer to the write_urb_pool which reduces the number of
+ *	  buffers being created and destroyed for ever write.  Also cleans
+ *	  up the logic a bit.
+ *	- Added a buffer to the control_urb_pool which fixes a memory leak
+ *	  when the device is removed from the system.
+ *
+ * (2001/05/28) Version 0.9 gkh
+ *	Fixed problem with bluetooth==NULL for bluetooth_read_bulk_callback
+ *	which was found by both the CHECKER project and Mikko Rahkonen.
+ *
  * (08/04/2001) gb
  *	Identify version on module load.
  *
@@ -97,7 +110,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.8"
+#define DRIVER_VERSION "v0.10"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman, Mark Douglas Corner"
 #define DRIVER_DESC "USB Bluetooth driver"
 
@@ -260,7 +273,7 @@
 }
 
 
-static int bluetooth_ctrl_msg (struct usb_bluetooth *bluetooth, int request, int value, void *buf, int len)
+static int bluetooth_ctrl_msg (struct usb_bluetooth *bluetooth, int request, int value, const unsigned char *buf, int len)
 {
 	struct urb *urb = NULL;
 	devrequest *dr = NULL;
@@ -282,11 +295,23 @@
 		return -ENOMEM;
 	}
 
-	/* free up the last buffer that this urb used */
-	if (urb->transfer_buffer != NULL) {
-		kfree(urb->transfer_buffer);
-		urb->transfer_buffer = NULL;
+	/* keep increasing the urb transfer buffer to fit the size of the message */
+	if (urb->transfer_buffer == NULL) {
+		urb->transfer_buffer = kmalloc (len, GFP_KERNEL);
+		if (urb->transfer_buffer == NULL) {
+			err (__FUNCTION__" - out of memory");
+			return -ENOMEM;
+		}
 	}
+	if (urb->transfer_buffer_length < len) {
+		kfree (urb->transfer_buffer);
+		urb->transfer_buffer = kmalloc (len, GFP_KERNEL);
+		if (urb->transfer_buffer == NULL) {
+			err (__FUNCTION__" - out of memory");
+			return -ENOMEM;
+		}
+	}
+	memcpy (urb->transfer_buffer, buf, len);
 
 	dr->requesttype = BLUETOOTH_CONTROL_REQUEST_TYPE;
 	dr->request = request;
@@ -295,14 +320,14 @@
 	dr->length = cpu_to_le16p(&len);
 	
 	FILL_CONTROL_URB (urb, bluetooth->dev, usb_sndctrlpipe(bluetooth->dev, 0),
-			  (unsigned char*)dr, buf, len, bluetooth_ctrl_callback, bluetooth);
+			  (unsigned char*)dr, urb->transfer_buffer, len, bluetooth_ctrl_callback, bluetooth);
 
 	/* send it down the pipe */
 	status = usb_submit_urb(urb);
 	if (status)
 		dbg(__FUNCTION__ " - usb_submit_urb(control) failed with status = %d", status);
 	
-	return 0;
+	return status;
 }
 
 
@@ -401,12 +426,13 @@
 {
 	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
 	struct urb *urb = NULL;
-	unsigned char *new_buffer;
+	unsigned char *temp_buffer = NULL;
+	const unsigned char *current_buffer;
 	const unsigned char *current_position;
-	int status;
 	int bytes_sent;
 	int buffer_size;
 	int i;
+	int retval = 0;
 
 	if (!bluetooth) {
 		return -ENODEV;
@@ -436,38 +462,39 @@
 	printk ("\n");
 #endif
 
-	switch (*buf) {
+	if (from_user) {
+		temp_buffer = kmalloc (count, GFP_KERNEL);
+		if (temp_buffer == NULL) {
+			err (__FUNCTION__ "- out of memory.");
+			retval = -ENOMEM;
+			goto exit;
+		}
+		copy_from_user (temp_buffer, buf, count);
+		current_buffer = temp_buffer;
+	} else {
+		current_buffer = buf;
+	}
+
+	switch (*current_buffer) {
 		/* First byte indicates the type of packet */
 		case CMD_PKT:
 			/* dbg(__FUNCTION__ "- Send cmd_pkt len:%d", count);*/
 
 			if (in_interrupt()){
 				printk("cmd_pkt from interrupt!\n");
-				return count;
+				retval = count;
+				goto exit;
 			}
 
-			new_buffer = kmalloc (count-1, GFP_KERNEL);
-
-			if (!new_buffer) {
-				err (__FUNCTION__ "- out of memory.");
-				return -ENOMEM;
-			}
-
-			if (from_user)
-				copy_from_user (new_buffer, buf+1, count-1);
-			else
-				memcpy (new_buffer, buf+1, count-1);
-
-			if (bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, new_buffer, count-1) != 0) {
-				kfree (new_buffer);
-				return 0;
+			retval = bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, &current_buffer[1], count-1);
+			if (retval) {
+				goto exit;
 			}
-
-			/* need to free new_buffer somehow... FIXME */
-			return count;
+			retval = count;
+			break;
 
 		case ACL_PKT:
-			current_position = buf;
+			current_position = current_buffer;
 			++current_position;
 			--count;
 			bytes_sent = 0;
@@ -484,37 +511,25 @@
 				}
 				if (urb == NULL) {
 					dbg (__FUNCTION__ " - no free urbs");
-					return bytes_sent;
+					retval = bytes_sent;
+					goto exit;
 				}
 				
-				/* free up the last buffer that this urb used */
-				if (urb->transfer_buffer != NULL) {
-					kfree(urb->transfer_buffer);
-					urb->transfer_buffer = NULL;
-				}
 
 				buffer_size = MIN (count, bluetooth->bulk_out_buffer_size);
-				
-				new_buffer = kmalloc (buffer_size, GFP_KERNEL);
-				if (new_buffer == NULL) {
-					err(__FUNCTION__" no more kernel memory...");
-					return bytes_sent;
-				}
-
-				if (from_user)
-					copy_from_user(new_buffer, current_position, buffer_size);
-				else
-					memcpy (new_buffer, current_position, buffer_size);
+				memcpy (urb->transfer_buffer, current_position, buffer_size);
 
 				/* build up our urb */
 				FILL_BULK_URB (urb, bluetooth->dev, usb_sndbulkpipe(bluetooth->dev, bluetooth->bulk_out_endpointAddress),
-						new_buffer, buffer_size, bluetooth_write_bulk_callback, bluetooth);
+						urb->transfer_buffer, buffer_size, bluetooth_write_bulk_callback, bluetooth);
 				urb->transfer_flags |= USB_QUEUE_BULK;
 
 				/* send it down the pipe */
-				status = usb_submit_urb(urb);
-				if (status)
-					dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
+				retval = usb_submit_urb(urb);
+				if (retval) {
+					dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with error = %d", retval);
+					goto exit;
+				}
 #ifdef BTBUGGYHARDWARE
 				/* A workaround for the stalled data bug */
 				/* May or may not be needed...*/
@@ -527,13 +542,20 @@
 				count -= buffer_size;
 			}
 
-			return bytes_sent + 1;
+			retval = bytes_sent + 1;
+			break;
 		
 		default :
 			dbg(__FUNCTION__" - unsupported (at this time) write type");
+			retval = -EINVAL;
+			break;
 	}
 
-	return 0;
+exit:
+	if (temp_buffer != NULL)
+		kfree (temp_buffer);
+
+	return retval;
 } 
 
 
@@ -845,21 +867,6 @@
 	unsigned int packet_size;
 	int result;
 
-#ifdef BTBUGGYHARDWARE
-	if ((count == 4) && (data[0] == 0x00) && (data[1] == 0x00)
-	    && (data[2] == 0x00) && (data[3] == 0x00)) {
-		urb->actual_length = 0;
-		FILL_BULK_URB(bluetooth->read_urb, bluetooth->dev, 
-			      usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
-			      bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, 
-			      bluetooth_read_bulk_callback, bluetooth);
-		result = usb_submit_urb(bluetooth->read_urb);
-		if (result)
-			err (__FUNCTION__ " - failed resubmitting read urb, error %d", result);
-
-		return;
-	}
-#endif
 
 	dbg(__FUNCTION__);
 
@@ -887,6 +894,21 @@
 		printk ("\n");
 	}
 #endif
+#ifdef BTBUGGYHARDWARE
+	if ((count == 4) && (data[0] == 0x00) && (data[1] == 0x00)
+	    && (data[2] == 0x00) && (data[3] == 0x00)) {
+		urb->actual_length = 0;
+		FILL_BULK_URB(bluetooth->read_urb, bluetooth->dev, 
+			      usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
+			      bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, 
+			      bluetooth_read_bulk_callback, bluetooth);
+		result = usb_submit_urb(bluetooth->read_urb);
+		if (result)
+			err (__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+
+		return;
+	}
+#endif
 	/* We add  a packet type identifier to the beginning of each
 	   HCI frame.  This makes the data in the tty look like a
 	   serial USB devices.  Each HCI frame can be broken across
@@ -934,6 +956,9 @@
 	}	
 
 exit:
+	if (!bluetooth || !bluetooth->active)
+		return;
+
 	FILL_BULK_URB(bluetooth->read_urb, bluetooth->dev, 
 		      usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
 		      bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, 
@@ -1114,7 +1139,11 @@
 			err("No free urbs available");
 			goto probe_error;
 		}
-		urb->transfer_buffer = NULL;
+		urb->transfer_buffer = kmalloc (bluetooth->bulk_out_buffer_size, GFP_KERNEL);
+		if (urb->transfer_buffer == NULL) {
+			err("out of memory");
+			goto probe_error;
+		}
 		bluetooth->write_urb_pool[i] = urb;
 	}
 	
@@ -1156,11 +1185,17 @@
 	if (bluetooth->interrupt_in_buffer)
 		kfree (bluetooth->interrupt_in_buffer);
 	for (i = 0; i < NUM_BULK_URBS; ++i)
-		if (bluetooth->write_urb_pool[i])
+		if (bluetooth->write_urb_pool[i]) {
+			if (bluetooth->write_urb_pool[i]->transfer_buffer)
+				kfree (bluetooth->write_urb_pool[i]->transfer_buffer);
 			usb_free_urb (bluetooth->write_urb_pool[i]);
+		}
 	for (i = 0; i < NUM_CONTROL_URBS; ++i) 
-		if (bluetooth->control_urb_pool[i])
+		if (bluetooth->control_urb_pool[i]) {
+			if (bluetooth->control_urb_pool[i]->transfer_buffer)
+				kfree (bluetooth->control_urb_pool[i]->transfer_buffer);
 			usb_free_urb (bluetooth->control_urb_pool[i]);
+		}
 
 	bluetooth_table[minor] = NULL;
 
@@ -1286,8 +1321,7 @@
 		return -1;
 	}
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 
 	return 0;
 }
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/dabusb.c linux/drivers/usb/dabusb.c
--- v2.4.5/linux/drivers/usb/dabusb.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/dabusb.c	Tue Jun 12 15:53:37 2001
@@ -837,8 +837,7 @@
 
 	dbg("dabusb_init: driver registered");
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 
 	return 0;
 }
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/dc2xx.c linux/drivers/usb/dc2xx.c
--- v2.4.5/linux/drivers/usb/dc2xx.c	Thu May 24 14:55:51 2001
+++ linux/drivers/usb/dc2xx.c	Tue Jun 12 15:53:37 2001
@@ -499,8 +499,7 @@
 {
  	if (usb_register (&camera_driver) < 0)
  		return -1;
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/dsbr100.c linux/drivers/usb/dsbr100.c
--- v2.4.5/linux/drivers/usb/dsbr100.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/dsbr100.c	Tue Jun 12 15:53:37 2001
@@ -342,8 +342,7 @@
 		warn("couldn't register video device");
 		return -EINVAL;
 	}
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/hid.c linux/drivers/usb/hid.c
--- v2.4.5/linux/drivers/usb/hid.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/hid.c	Tue Jun 12 15:53:37 2001
@@ -1559,8 +1559,7 @@
 static int __init hid_init(void)
 {
 	usb_register(&hid_driver);
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/ibmcam.c linux/drivers/usb/ibmcam.c
--- v2.4.5/linux/drivers/usb/ibmcam.c	Thu May 24 14:55:51 2001
+++ linux/drivers/usb/ibmcam.c	Tue Jun 12 15:53:37 2001
@@ -3147,8 +3147,7 @@
 		struct usb_ibmcam *ibmcam = &cams[u];
 		memset (ibmcam, 0, sizeof(struct usb_ibmcam));
 	}
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return usb_register(&ibmcam_driver);
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/mdc800.c linux/drivers/usb/mdc800.c
--- v2.4.5/linux/drivers/usb/mdc800.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/mdc800.c	Tue Jun 12 15:53:37 2001
@@ -932,8 +932,7 @@
 	if (usb_register (&mdc800_usb_driver) < 0)
 		goto cleanup_on_fail;
 
-	info (DRIVER_VERSION " " DRIVER_AUTHOR);
-	info (DRIVER_DESC);
+	info (DRIVER_VERSION ":" DRIVER_DESC);
 
 	return 0;
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/microtek.c linux/drivers/usb/microtek.c
--- v2.4.5/linux/drivers/usb/microtek.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/microtek.c	Tue Jun 12 15:53:37 2001
@@ -1029,8 +1029,7 @@
 		MTS_DEBUG("driver registered.\n");
 	}
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 
 	return 0;
 }
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/net1080.c linux/drivers/usb/net1080.c
--- v2.4.5/linux/drivers/usb/net1080.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/net1080.c	Tue Jun 12 15:53:37 2001
@@ -599,7 +599,7 @@
 	}
 #ifdef	VERBOSE
 	dbg ("no read resubmitted");
-#endif	VERBOSE
+#endif	/* VERBOSE */
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1111,8 +1111,7 @@
 	get_random_bytes (node_id, sizeof node_id);
 	node_id [0] &= 0x7f;
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 
 	return 0;
 }
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c
--- v2.4.5/linux/drivers/usb/ov511.c	Thu May 24 15:24:37 2001
+++ linux/drivers/usb/ov511.c	Tue Jun 12 15:53:37 2001
@@ -337,7 +337,7 @@
 	/* IMPORTANT: This output MUST be kept under PAGE_SIZE
 	 *            or we need to get more sophisticated. */
 
-	out += sprintf (out, "driver_version  : %s\n", version);
+	out += sprintf (out, "driver_version  : %s\n", DRIVER_VERSION);
 	out += sprintf (out, "custom_id       : %d\n", ov511->customid);
 	out += sprintf (out, "model           : %s\n", ov511->desc ?
 		clist[ov511->desc].description : "unknown");
@@ -3426,8 +3426,7 @@
 	if (usb_register(&ov511_driver) < 0)
 		return -1;
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 
 	return 0;
 }
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c
--- v2.4.5/linux/drivers/usb/pegasus.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/pegasus.c	Tue Jun 12 15:53:37 2001
@@ -127,8 +127,16 @@
 static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
 {
 	int	ret;
+	unsigned char *buffer;
 	DECLARE_WAITQUEUE(wait, current);
 
+	buffer = kmalloc(size,GFP_KERNEL);
+	if (!buffer) {
+		err("unable to allocate memory for configuration descriptors");
+		return 0;
+	}
+	memcpy(buffer,data,size);
+	
 	while ( pegasus->flags & ETH_REGS_CHANGED ) {
 		pegasus->flags |= CTRL_URB_SLEEP;
 		interruptible_sleep_on( &pegasus->ctrl_wait );
@@ -143,7 +151,7 @@
 	FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
 			  usb_rcvctrlpipe(pegasus->usb,0),
 			  (char *)&pegasus->dr,
-			  data, size, ctrl_callback, pegasus );
+			  buffer, size, ctrl_callback, pegasus );
 
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
 	set_current_state( TASK_INTERRUPTIBLE );
@@ -157,6 +165,8 @@
 	schedule();
 	remove_wait_queue( &pegasus->ctrl_wait, &wait );
 out:
+	memcpy(data,buffer,size);
+	kfree(buffer);
 	return	ret;
 }
 
@@ -164,8 +174,16 @@
 static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
 {
 	int	ret;
+	unsigned char *buffer;
 	DECLARE_WAITQUEUE(wait, current);
 
+	buffer = kmalloc(size, GFP_KERNEL);
+	if (!buffer) {
+		err("unable to allocate memory for configuration descriptors");
+		return 0;
+	}
+	memcpy(buffer, data, size);
+
 	while ( pegasus->flags & ETH_REGS_CHANGED ) {
 		pegasus->flags |= CTRL_URB_SLEEP ;
 		interruptible_sleep_on( &pegasus->ctrl_wait );
@@ -180,7 +198,7 @@
 	FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
 			  usb_sndctrlpipe(pegasus->usb,0),
 			  (char *)&pegasus->dr,
-			  data, size, ctrl_callback, pegasus );
+			  buffer, size, ctrl_callback, pegasus );
 			  
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
 	set_current_state( TASK_INTERRUPTIBLE );
@@ -188,12 +206,14 @@
 
 	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRL %d", ret);
+		kfree(buffer);
 		return	ret;
 	}
 
 	schedule();
 	remove_wait_queue( &pegasus->ctrl_wait, &wait );
 
+	kfree(buffer);
 	return	ret;
 }
 
@@ -201,9 +221,17 @@
 static int set_register( pegasus_t *pegasus, __u16 indx, __u8 data )
 {
 	int	ret;
+	unsigned char *buffer;
 	__u16 dat = data;
 	DECLARE_WAITQUEUE(wait, current);
 	
+	buffer = kmalloc(1, GFP_KERNEL);
+	if (!buffer) {
+		err("unable to allocate memory for configuration descriptors");
+		return 0;
+	}
+	memcpy(buffer, &data, 1);
+
 	while ( pegasus->flags & ETH_REGS_CHANGED ) {
 		pegasus->flags |= CTRL_URB_SLEEP;
 		interruptible_sleep_on( &pegasus->ctrl_wait );
@@ -218,7 +246,7 @@
 	FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
 			  usb_sndctrlpipe(pegasus->usb,0),
 			  (char *)&pegasus->dr,
-			  &data, 1, ctrl_callback, pegasus );
+			  buffer, 1, ctrl_callback, pegasus );
 
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
 	set_current_state( TASK_INTERRUPTIBLE );
@@ -226,12 +254,14 @@
 
 	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRL %d", ret);
+		kfree(buffer);
 		return	ret;
 	}
 
 	schedule();
 	remove_wait_queue( &pegasus->ctrl_wait, &wait );
 
+	kfree(buffer);
 	return	ret;
 }
 
@@ -905,8 +935,7 @@
 
 int __init pegasus_init(void)
 {
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return usb_register( &pegasus_driver );
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/plusb.c linux/drivers/usb/plusb.c
--- v2.4.5/linux/drivers/usb/plusb.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/plusb.c	Tue Jun 12 15:53:37 2001
@@ -1014,8 +1014,7 @@
 
 	dbg("plusb_init: driver registered");
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 
 	return 0;
 }
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.4.5/linux/drivers/usb/printer.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/printer.c	Tue Jun 12 15:53:37 2001
@@ -662,8 +662,7 @@
 {
 	if (usb_register(&usblp_driver))
 		return -1;
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/rio500.c linux/drivers/usb/rio500.c
--- v2.4.5/linux/drivers/usb/rio500.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/rio500.c	Tue Jun 12 15:53:37 2001
@@ -492,8 +492,7 @@
 	if (usb_register(&rio_driver) < 0)
 		return -1;
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 
 	return 0;
 }
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/serial/belkin_sa.c linux/drivers/usb/serial/belkin_sa.c
--- v2.4.5/linux/drivers/usb/serial/belkin_sa.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/serial/belkin_sa.c	Tue Jun 12 15:53:37 2001
@@ -600,8 +600,7 @@
 	usb_serial_register (&belkin_old_device);
 	usb_serial_register (&peracom_device);
 	usb_serial_register (&gocom232_device);
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/serial/digi_acceleport.c linux/drivers/usb/serial/digi_acceleport.c
--- v2.4.5/linux/drivers/usb/serial/digi_acceleport.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/serial/digi_acceleport.c	Tue Jun 12 15:53:37 2001
@@ -2078,8 +2078,7 @@
 {
 	usb_serial_register (&digi_acceleport_2_device);
 	usb_serial_register (&digi_acceleport_4_device);
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/serial/empeg.c linux/drivers/usb/serial/empeg.c
--- v2.4.5/linux/drivers/usb/serial/empeg.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/serial/empeg.c	Tue Jun 12 15:53:37 2001
@@ -680,8 +680,7 @@
 		}
 	}
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 
 	return 0;
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c
--- v2.4.5/linux/drivers/usb/serial/ftdi_sio.c	Thu May 24 14:55:51 2001
+++ linux/drivers/usb/serial/ftdi_sio.c	Tue Jun 12 15:53:37 2001
@@ -253,7 +253,7 @@
 	
 	priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
 	if (!priv){
-		err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private));
+		err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct ftdi_private));
 		return -ENOMEM;
 	}
 
@@ -271,7 +271,7 @@
 
 	priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
 	if (!priv){
-		err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private));
+		err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct ftdi_private));
 		return -ENOMEM;
 	}
 
@@ -985,8 +985,7 @@
 	dbg(__FUNCTION__);
 	usb_serial_register (&ftdi_sio_device);
 	usb_serial_register (&ftdi_8U232AM_device);
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/serial/io_edgeport.c linux/drivers/usb/serial/io_edgeport.c
--- v2.4.5/linux/drivers/usb/serial/io_edgeport.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/serial/io_edgeport.c	Tue Jun 12 15:53:37 2001
@@ -944,7 +944,7 @@
 	}
 
 	if (status) {
-		dbg(__FUNCTION__" - nonzero write bulk status received: %d", urb->status);
+		dbg(__FUNCTION__" - nonzero write bulk status received: %d", status);
 		return;
 	}
 
@@ -3037,8 +3037,7 @@
 	usb_serial_register (&edgeport_16dual_device);
 	usb_serial_register (&edgeport_compat_id_device);
 	usb_serial_register (&edgeport_8i_device);
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c
--- v2.4.5/linux/drivers/usb/serial/keyspan.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/serial/keyspan.c	Tue Jun 12 15:53:37 2001
@@ -177,8 +177,7 @@
 	usb_serial_register (&keyspan_usa28x_device);
 	usb_serial_register (&keyspan_usa49w_device);
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 
 	return 0;
 }
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/serial/keyspan_pda.c linux/drivers/usb/serial/keyspan_pda.c
--- v2.4.5/linux/drivers/usb/serial/keyspan_pda.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/serial/keyspan_pda.c	Tue Jun 12 15:53:37 2001
@@ -817,8 +817,7 @@
 {
 	usb_serial_register (&keyspan_pda_fake_device);
 	usb_serial_register (&keyspan_pda_device);
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/serial/mct_u232.c linux/drivers/usb/serial/mct_u232.c
--- v2.4.5/linux/drivers/usb/serial/mct_u232.c	Thu May 24 14:55:51 2001
+++ linux/drivers/usb/serial/mct_u232.c	Tue Jun 12 15:53:37 2001
@@ -870,8 +870,7 @@
 	usb_serial_register (&mct_u232_device);
 	usb_serial_register (&mct_u232_sitecom_device);
 	usb_serial_register (&mct_u232_du_h3sp_device);
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/serial/omninet.c linux/drivers/usb/serial/omninet.c
--- v2.4.5/linux/drivers/usb/serial/omninet.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/serial/omninet.c	Tue Jun 12 15:53:37 2001
@@ -406,8 +406,7 @@
 static int __init omninet_init (void)
 {
 	usb_serial_register (&zyxel_omninet_device);
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c
--- v2.4.5/linux/drivers/usb/serial/usbserial.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/serial/usbserial.c	Tue Jun 12 15:53:37 2001
@@ -1395,8 +1395,7 @@
 		return -1;
 	}
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 
 	return 0;
 }
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c
--- v2.4.5/linux/drivers/usb/serial/visor.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/serial/visor.c	Tue Jun 12 15:53:37 2001
@@ -1,7 +1,7 @@
 /*
  * USB HandSpring Visor driver
  *
- *	Copyright (C) 1999, 2000
+ *	Copyright (C) 1999 - 2001
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -11,6 +11,9 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (05/28/2000) gkh
+ *	Added initial support for the Palm m500 and Palm m505 devices.
+ *
  * (04/08/2001) gb
  *	Identify version on module load.
  *
@@ -109,7 +112,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.0.0"
+#define DRIVER_VERSION "v1.1"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC "USB HandSpring Visor driver"
 
@@ -131,8 +134,26 @@
 static void visor_read_bulk_callback	(struct urb *urb);
 
 
+static __devinitdata struct usb_device_id visor_id_table [] = {
+	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
+	{ }					/* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id palm_m500_id_table [] = {
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
+	{ }					/* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id palm_m505_id_table [] = {
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
+	{ }					/* Terminating entry */
+};
+
+
 static __devinitdata struct usb_device_id id_table [] = {
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -143,7 +164,33 @@
 /* All of the device info needed for the Handspring Visor */
 struct usb_serial_device_type handspring_device = {
 	name:			"Handspring Visor",
-	id_table:		id_table,
+	id_table:		visor_id_table,
+	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
+	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
+	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
+	num_interrupt_in:	0,
+	num_bulk_in:		2,
+	num_bulk_out:		2,
+	num_ports:		2,
+	open:			visor_open,
+	close:			visor_close,
+	throttle:		visor_throttle,
+	unthrottle:		visor_unthrottle,
+	startup:		visor_startup,
+	shutdown:		visor_shutdown,
+	ioctl:			visor_ioctl,
+	set_termios:		visor_set_termios,
+	write:			visor_write,
+	write_room:		visor_write_room,
+	chars_in_buffer:	visor_chars_in_buffer,
+	write_bulk_callback:	visor_write_bulk_callback,
+	read_bulk_callback:	visor_read_bulk_callback,
+};
+
+/* device info for the Palm M500 */
+struct usb_serial_device_type palm_m500_device = {
+	name:			"Palm M500",
+	id_table:		palm_m500_id_table,
 	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
 	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
 	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
@@ -166,6 +213,31 @@
 	read_bulk_callback:	visor_read_bulk_callback,
 };
 
+/* device info for the Palm M505 */
+struct usb_serial_device_type palm_m505_device = {
+	name:			"Palm M505",
+	id_table:		palm_m505_id_table,
+	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
+	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
+	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
+	num_interrupt_in:	0,
+	num_bulk_in:		2,
+	num_bulk_out:		2,
+	num_ports:		2,
+	open:			visor_open,
+	close:			visor_close,
+	throttle:		visor_throttle,
+	unthrottle:		visor_unthrottle,
+	startup:		visor_startup,
+	shutdown:		visor_shutdown,
+	ioctl:			visor_ioctl,
+	set_termios:		visor_set_termios,
+	write:			visor_write,
+	write_room:		visor_write_room,
+	chars_in_buffer:	visor_chars_in_buffer,
+	write_bulk_callback:	visor_write_bulk_callback,
+	read_bulk_callback:	visor_read_bulk_callback,
+};
 
 #define NUM_URBS			24
 #define URB_TRANSFER_BUFFER_SIZE	768
@@ -496,6 +568,10 @@
 		return -ENOMEM;
 	}
 
+	/* force debugging on for the palm devices for now */
+	if (serial->dev->descriptor.idVendor == PALM_VENDOR_ID)
+		debug = 1;
+
 	dbg(__FUNCTION__);
 
 	dbg(__FUNCTION__ " - Set config to 1");
@@ -537,6 +613,28 @@
 		}
 	}
 
+	if (serial->dev->descriptor.idVendor == PALM_VENDOR_ID) {
+		/* Palm USB Hack */
+		response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), 
+					    PALM_GET_SOME_UNKNOWN_INFORMATION,
+					    0xc2, 0x0000, 0x0000, transfer_buffer, 
+					    0x14, 300);
+		if (response < 0) {
+			err(__FUNCTION__ " - error getting first unknown palm command");
+		} else {
+			usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, transfer_buffer);
+		}
+		response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), 
+					    PALM_GET_SOME_UNKNOWN_INFORMATION,
+					    0xc2, 0x0000, 0x0000, transfer_buffer, 
+					    0x14, 300);
+		if (response < 0) {
+			err(__FUNCTION__ " - error getting second unknown palm command");
+		} else {
+			usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, transfer_buffer);
+		}
+	}
+
 	/* ask for the number of bytes available, but ignore the response as it is broken */
 	response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE,
 					0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300);
@@ -645,6 +743,8 @@
 	int i;
 
 	usb_serial_register (&handspring_device);
+	usb_serial_register (&palm_m500_device);
+	usb_serial_register (&palm_m505_device);
 	
 	/* create our write urb pool and transfer buffers */ 
 	spin_lock_init (&write_urb_pool_lock);
@@ -664,8 +764,7 @@
 		}
 	}
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 
 	return 0;
 }
@@ -677,6 +776,8 @@
 	unsigned long flags;
 
 	usb_serial_deregister (&handspring_device);
+	usb_serial_deregister (&palm_m500_device);
+	usb_serial_deregister (&palm_m505_device);
 
 	spin_lock_irqsave (&write_urb_pool_lock, flags);
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/serial/visor.h linux/drivers/usb/serial/visor.h
--- v2.4.5/linux/drivers/usb/serial/visor.h	Wed Apr 18 11:49:12 2001
+++ linux/drivers/usb/serial/visor.h	Mon Jun 11 19:15:27 2001
@@ -1,7 +1,7 @@
 /*
  * USB HandSpring Visor driver
  *
- *	Copyright (C) 1999, 2000
+ *	Copyright (C) 1999 - 2001
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,10 @@
 #define HANDSPRING_VENDOR_ID		0x082d
 #define HANDSPRING_VISOR_ID		0x0100
 
+#define PALM_VENDOR_ID			0x0830
+#define PALM_M500_ID			0x0001
+#define PALM_M505_ID			0x0002
+
 /****************************************************************************
  * Handspring Visor Vendor specific request codes (bRequest values)
  * A big thank you to Handspring for providing the following information.
@@ -69,6 +73,13 @@
 #define VISOR_FUNCTION_HOTSYNC		0x02
 #define VISOR_FUNCTION_CONSOLE		0x03
 #define VISOR_FUNCTION_REMOTE_FILE_SYS	0x04
+
+
+/****************************************************************************
+ * PALM_GET_SOME_UNKNOWN_INFORMATION is sent by the host during enumeration to
+ * get some information from the M series devices, that is currently unknown.
+ ****************************************************************************/
+#define PALM_GET_SOME_UNKNOWN_INFORMATION	0x04
 
 #endif
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/serial/whiteheat.c linux/drivers/usb/serial/whiteheat.c
--- v2.4.5/linux/drivers/usb/serial/whiteheat.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/serial/whiteheat.c	Tue Jun 12 15:53:37 2001
@@ -626,8 +626,7 @@
 {
 	usb_serial_register (&whiteheat_fake_device);
 	usb_serial_register (&whiteheat_device);
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/storage/debug.c linux/drivers/usb/storage/debug.c
--- v2.4.5/linux/drivers/usb/storage/debug.c	Fri Sep  8 16:39:12 2000
+++ linux/drivers/usb/storage/debug.c	Tue Jun 12 11:17:17 2001
@@ -302,6 +302,8 @@
 	case 0x1C00: what="defect list not found"; break;
 	case 0x2400: what="invalid field in CDB"; break;
 	case 0x2703: what="associated write protect"; break;
+	case 0x2800: what="not ready to ready transition (media change?)";
+		break;
 	case 0x2903: what="bus device reset function occurred"; break;
 	case 0x2904: what="device internal reset"; break;
 	case 0x2B00: what="copy can't execute since host can't disconnect"; 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.4.5/linux/drivers/usb/uhci.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/uhci.c	Tue Jun 12 17:03:01 2001
@@ -425,8 +425,7 @@
 
 	/* Only go through the hoops if it's actually linked in */
 	if (list_empty(&qh->list)) {
-		uhci_free_qh(uhci, qh);
-		return;
+		goto list;
 	}
 
 	qh->urbp = NULL;
@@ -444,6 +443,7 @@
 
 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 
+list:
 	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
 
 	/* Check to see if the remove list is empty. Set the IOC bit */
@@ -2922,15 +2922,17 @@
 }
 
 #ifdef CONFIG_PM
-static void uhci_pci_suspend(struct pci_dev *dev)
+static int uhci_pci_suspend(struct pci_dev *dev, u32 state)
 {
 	reset_hc((struct uhci *) dev->driver_data);
+	return 0;
 }
 
-static void uhci_pci_resume(struct pci_dev *dev)
+static int uhci_pci_resume(struct pci_dev *dev)
 {
 	reset_hc((struct uhci *) dev->driver_data);
 	start_hc((struct uhci *) dev->driver_data);
+	return 0;
 }
 #endif
 
@@ -2990,8 +2992,7 @@
 	if (retval)
 		goto init_failed;
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 
 	return 0;
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
--- v2.4.5/linux/drivers/usb/usb-ohci.c	Tue May 22 13:55:49 2001
+++ linux/drivers/usb/usb-ohci.c	Tue Jun 12 15:53:37 2001
@@ -2774,8 +2774,7 @@
 #ifdef CONFIG_PMAC_PBOOK
 	pmu_register_sleep_notifier (&ohci_sleep_notifier);
 #endif  
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return ret;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/usb-ohci.h linux/drivers/usb/usb-ohci.h
--- v2.4.5/linux/drivers/usb/usb-ohci.h	Sun May 20 12:11:39 2001
+++ linux/drivers/usb/usb-ohci.h	Tue Jun 12 15:53:37 2001
@@ -116,7 +116,7 @@
 	dma_addr_t td_dma;
 	dma_addr_t data_dma;
 	__u32 unused2[2];
-} __attribute((aligned(16)));
+} __attribute((aligned(32)));	/* normally 16, iso needs 32 */
 typedef struct td td_t;
 
 #define OHCI_ED_SKIP	(1 << 14)
@@ -562,7 +562,7 @@
 {
 	ohci->td_cache = pci_pool_create ("ohci_td", ohci->ohci_dev,
 		sizeof (struct td),
-		16 /* byte alignment */,
+		32 /* byte alignment */,
 		0 /* no page-crossing issues */,
 		GFP_KERNEL | OHCI_MEM_FLAGS);
 	if (!ohci->td_cache)
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c
--- v2.4.5/linux/drivers/usb/usb-uhci.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/usb-uhci.c	Tue Jun 12 15:53:37 2001
@@ -3108,8 +3108,7 @@
 	}
 #endif
 	
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 
 	return retval;
 }
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.4.5/linux/drivers/usb/usb.c	Sat Apr 28 11:28:09 2001
+++ linux/drivers/usb/usb.c	Tue Jun 12 15:53:37 2001
@@ -449,7 +449,7 @@
 	 */
 	list_del(&bus->bus_list);
 
-        usbdevfs_remove_bus(bus);
+	usbdevfs_remove_bus(bus);
 
 	clear_bit(bus->busnum, busmap.busmap);
 
@@ -1869,6 +1869,7 @@
 {
 	int result;
 	__u16 status;
+	unsigned char *buffer;
 	int endp=usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7);
 
 /*
@@ -1883,9 +1884,19 @@
 	if (result < 0)
 		return result;
 
+	buffer = kmalloc(sizeof(status), GFP_KERNEL);
+	if (!buffer) {
+		err("unable to allocate memory for configuration descriptors");
+		return -ENOMEM;
+	}
+
 	result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
 		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_ENDPOINT, 0, endp,
-		&status, sizeof(status), HZ * SET_TIMEOUT);
+		buffer, sizeof(status), HZ * SET_TIMEOUT);
+
+	memcpy(&status, buffer, sizeof(status));
+	kfree(buffer);
+
 	if (result < 0)
 		return result;
 
@@ -1970,10 +1981,9 @@
 {
 	int result;
 	unsigned int cfgno, length;
-	unsigned char buffer[8];
+	unsigned char *buffer;
 	unsigned char *bigbuffer;
-	struct usb_config_descriptor *desc =
-		(struct usb_config_descriptor *)buffer;
+ 	struct usb_config_descriptor *desc;
 
 	if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
 		warn("too many configurations");
@@ -2002,6 +2012,13 @@
 		return -ENOMEM;
 	}
 
+	buffer = kmalloc(8, GFP_KERNEL);
+	if (!buffer) {
+		err("unable to allocate memory for configuration descriptors");
+		return -ENOMEM;
+	}
+	desc = (struct usb_config_descriptor *)buffer;
+
 	for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) {
 		/* We grab the first 8 bytes so we know how long the whole */
 		/*  configuration is */
@@ -2052,8 +2069,10 @@
 		}
 	}
 
+	kfree(buffer);
 	return 0;
 err:
+	kfree(buffer);
 	dev->descriptor.bNumConfigurations = cfgno;
 	return result;
 }
@@ -2162,7 +2181,7 @@
 	dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
 
 	err = usb_get_device_descriptor(dev);
-	if (err < sizeof(dev->descriptor)) {
+	if (err < (signed)sizeof(dev->descriptor)) {
 		if (err < 0)
 			err("unable to get device descriptor (error=%d)", err);
 		else
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/usbkbd.c linux/drivers/usb/usbkbd.c
--- v2.4.5/linux/drivers/usb/usbkbd.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/usbkbd.c	Tue Jun 12 15:53:37 2001
@@ -280,8 +280,7 @@
 static int __init usb_kbd_init(void)
 {
 	usb_register(&usb_kbd_driver);
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/usbmouse.c linux/drivers/usb/usbmouse.c
--- v2.4.5/linux/drivers/usb/usbmouse.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/usbmouse.c	Tue Jun 12 15:53:37 2001
@@ -194,8 +194,7 @@
 static int __init usb_mouse_init(void)
 {
 	usb_register(&usb_mouse_driver);
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/uss720.c linux/drivers/usb/uss720.c
--- v2.4.5/linux/drivers/usb/uss720.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/uss720.c	Tue Jun 12 15:53:37 2001
@@ -659,8 +659,7 @@
 	if (usb_register(&uss720_driver) < 0)
 		return -1;
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/usb/wacom.c linux/drivers/usb/wacom.c
--- v2.4.5/linux/drivers/usb/wacom.c	Mon May 21 15:02:06 2001
+++ linux/drivers/usb/wacom.c	Tue Jun 12 15:53:37 2001
@@ -415,8 +415,7 @@
 static int __init wacom_init(void)
 {
 	usb_register(&wacom_driver);
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
--- v2.4.5/linux/drivers/video/atyfb.c	Wed May 16 10:31:23 2001
+++ linux/drivers/video/atyfb.c	Mon Jun 11 19:15:27 2001
@@ -3213,7 +3213,7 @@
 static void atyfb_save_palette(struct fb_info *fb, int enter)
 {
 	struct fb_info_aty *info = (struct fb_info_aty *)fb;
-	int i, tmp, scale;
+	int i, tmp;
 
 	for (i = 0; i < 256; i++) {
 		tmp = aty_ld_8(DAC_CNTL, info) & 0xfc;
@@ -3225,14 +3225,11 @@
 		aty_st_8(DAC_CNTL, tmp, info);
 		aty_st_8(DAC_MASK, 0xff, info);
 
-		scale = ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID) &&
-			(info->current_par.crtc.bpp == 16)) ? 3 : 0;
-		writeb(i << scale, &info->aty_cmap_regs->rindex);
-
+		writeb(i, &info->aty_cmap_regs->rindex);
 		atyfb_save.r[enter][i] = readb(&info->aty_cmap_regs->lut);
 		atyfb_save.g[enter][i] = readb(&info->aty_cmap_regs->lut);
 		atyfb_save.b[enter][i] = readb(&info->aty_cmap_regs->lut);
-		writeb(i << scale, &info->aty_cmap_regs->windex);
+		writeb(i, &info->aty_cmap_regs->windex);
 		writeb(atyfb_save.r[1-enter][i], &info->aty_cmap_regs->lut);
 		writeb(atyfb_save.g[1-enter][i], &info->aty_cmap_regs->lut);
 		writeb(atyfb_save.b[1-enter][i], &info->aty_cmap_regs->lut);
diff -u --recursive --new-file v2.4.5/linux/drivers/video/creatorfb.c linux/drivers/video/creatorfb.c
--- v2.4.5/linux/drivers/video/creatorfb.c	Sun Mar 25 18:14:20 2001
+++ linux/drivers/video/creatorfb.c	Tue Jun 12 11:08:46 2001
@@ -1,4 +1,4 @@
-/* $Id: creatorfb.c,v 1.34 2001/03/16 10:22:02 davem Exp $
+/* $Id: creatorfb.c,v 1.35 2001/06/08 21:48:37 davem Exp $
  * creatorfb.c: Creator/Creator3D frame buffer driver
  *
  * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
@@ -69,6 +69,15 @@
 #define	FFB_DAC_POFF		0x00400000UL
 #define	FFB_PROM_POFF		0x00000000UL
 #define	FFB_EXP_POFF		0x00200000UL
+#define FFB_DFB422A_POFF	0x09000000UL
+#define FFB_DFB422AD_POFF	0x09800000UL
+#define FFB_DFB24B_POFF		0x0a000000UL
+#define FFB_DFB422B_POFF	0x0b000000UL
+#define FFB_DFB422BD_POFF	0x0b800000UL
+#define FFB_SFB16Z_POFF		0x0c800000UL
+#define FFB_SFB8Z_POFF		0x0c000000UL
+#define FFB_SFB422_POFF		0x0d000000UL
+#define FFB_SFB422D_POFF	0x0d800000UL
 
 /* Draw operations */
 #define FFB_DRAWOP_DOT		0x00
@@ -330,6 +339,15 @@
 	{ FFB_DAC_VOFF,		FFB_DAC_POFF,		0x0002000 },
 	{ FFB_PROM_VOFF,	FFB_PROM_POFF,		0x0010000 },
 	{ FFB_EXP_VOFF,		FFB_EXP_POFF,		0x0002000 },
+	{ FFB_DFB422A_VOFF,	FFB_DFB422A_POFF,	0x0800000 },
+	{ FFB_DFB422AD_VOFF,	FFB_DFB422AD_POFF,	0x0800000 },
+	{ FFB_DFB24B_VOFF,	FFB_DFB24B_POFF,	0x1000000 },
+	{ FFB_DFB422B_VOFF,	FFB_DFB422B_POFF,	0x0800000 },
+	{ FFB_DFB422BD_VOFF,	FFB_DFB422BD_POFF,	0x0800000 },
+	{ FFB_SFB16Z_VOFF,	FFB_SFB16Z_POFF,	0x0800000 },
+	{ FFB_SFB8Z_VOFF,	FFB_SFB8Z_POFF,		0x0800000 },
+	{ FFB_SFB422_VOFF,	FFB_SFB422_POFF,	0x0800000 },
+	{ FFB_SFB422D_VOFF,	FFB_SFB422D_POFF,	0x0800000 },
 	{ 0,			0,			0	  }
 };
 
diff -u --recursive --new-file v2.4.5/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c
--- v2.4.5/linux/drivers/video/fbcon.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/fbcon.c	Mon Jun 11 19:15:27 2001
@@ -2060,44 +2060,32 @@
     if (!fb)
 	return 0;
 	
-    /* Set colors if visual is PSEUDOCOLOR and we have enough colors, or for
-     * DIRECTCOLOR */
-    if ((p->visual == FB_VISUAL_PSEUDOCOLOR && depth >= 4) ||
-	p->visual == FB_VISUAL_DIRECTCOLOR) {
-	int is_truecolor = (p->visual == FB_VISUAL_DIRECTCOLOR);
-	int use_256 = (!is_truecolor && depth >= 8) ||
-		      (is_truecolor && depth >= 24);
-	int first_col = use_256 ? 32 : depth > 4 ? 16 : 0;
-	int num_cols = use_256 ? LINUX_LOGO_COLORS : 16;
-	unsigned char *red, *green, *blue;
-	
-	if (use_256) {
-	    red   = linux_logo_red;
-	    green = linux_logo_green;
-	    blue  = linux_logo_blue;
-	}
-	else {
-	    red   = linux_logo16_red;
-	    green = linux_logo16_green;
-	    blue  = linux_logo16_blue;
-	}
-
-	for( i = 0; i < num_cols; i += n ) {
-	    n = num_cols - i;
+    /*
+     * Set colors if visual is PSEUDOCOLOR and we have enough colors, or for
+     * DIRECTCOLOR
+     * We don't have to set the colors for the 16-color logo, since that logo
+     * uses the standard VGA text console palette
+     */
+    if ((p->visual == FB_VISUAL_PSEUDOCOLOR && depth >= 8) ||
+	(p->visual == FB_VISUAL_DIRECTCOLOR && depth >= 24))
+	for (i = 0; i < LINUX_LOGO_COLORS; i += n) {
+	    n = LINUX_LOGO_COLORS - i;
 	    if (n > 16)
 		/* palette_cmap provides space for only 16 colors at once */
 		n = 16;
-	    palette_cmap.start = first_col + i;
+	    palette_cmap.start = 32 + i;
 	    palette_cmap.len   = n;
 	    for( j = 0; j < n; ++j ) {
-		palette_cmap.red[j]   = (red[i+j] << 8) | red[i+j];
-		palette_cmap.green[j] = (green[i+j] << 8) | green[i+j];
-		palette_cmap.blue[j]  = (blue[i+j] << 8) | blue[i+j];
+		palette_cmap.red[j]   = (linux_logo_red[i+j] << 8) |
+					linux_logo_red[i+j];
+		palette_cmap.green[j] = (linux_logo_green[i+j] << 8) |
+					linux_logo_green[i+j];
+		palette_cmap.blue[j]  = (linux_logo_blue[i+j] << 8) |
+					linux_logo_blue[i+j];
 	    }
 	    p->fb_info->fbops->fb_set_cmap(&palette_cmap, 1, fg_console,
 					   p->fb_info);
 	}
-    }
 	
     if (depth >= 8) {
 	logo = linux_logo;
@@ -2155,15 +2143,15 @@
 		    }
 		}
 	    }
-	    else if (depth >= 15 && depth <= 23) {
-	        /* have 5..7 bits per color, using 16 color image */
+	    else if (depth >= 12 && depth <= 23) {
+	        /* have 4..7 bits per color, using 16 color image */
 		unsigned int pix;
 		src = linux_logo16;
 		bdepth = (depth+7)/8;
 		for( y1 = 0; y1 < LOGO_H; y1++ ) {
 		    dst = fb + y1*line + x*bdepth;
 		    for( x1 = 0; x1 < LOGO_W/2; x1++, src++ ) {
-			pix = (*src >> 4) | 0x10; /* upper nibble */
+			pix = *src >> 4; /* upper nibble */
 			val = (pix << redshift) |
 			      (pix << greenshift) |
 			      (pix << blueshift);
@@ -2173,7 +2161,7 @@
 			for( i = bdepth-1; i >= 0; --i )
 #endif
 			    fb_writeb (val >> (i*8), dst++);
-			pix = (*src & 0x0f) | 0x10; /* lower nibble */
+			pix = *src & 0x0f; /* lower nibble */
 			val = (pix << redshift) |
 			      (pix << greenshift) |
 			      (pix << blueshift);
@@ -2297,16 +2285,13 @@
 		}
 	    }
 	
-	    /* fill remaining planes
-	     * special case for logo_depth == 4: we used color registers 16..31,
-	     * so fill plane 4 with 1 bits instead of 0 */
+	    /* fill remaining planes */
 	    if (depth > logo_depth) {
 		for( y1 = 0; y1 < LOGO_H; y1++ ) {
 		    for( x1 = 0; x1 < LOGO_LINE; x1++ ) {
 			dst = fb + y1*line + MAP_X(x/8+x1) + logo_depth*plane;
 			for( i = logo_depth; i < depth; i++, dst += plane )
-			    *dst = (i == logo_depth && logo_depth == 4)
-				   ? 0xff : 0x00;
+			    *dst = 0x00;
 		    }
 		}
 	    }
diff -u --recursive --new-file v2.4.5/linux/drivers/video/matrox/matroxfb_base.c linux/drivers/video/matrox/matroxfb_base.c
--- v2.4.5/linux/drivers/video/matrox/matroxfb_base.c	Sun Feb  4 10:05:30 2001
+++ linux/drivers/video/matrox/matroxfb_base.c	Mon Jun 11 19:15:27 2001
@@ -2483,7 +2483,7 @@
 	return 0;
 }
 
-static int __init initialized = 0;
+static int initialized __initdata = 0;
 
 int __init matroxfb_init(void)
 {
diff -u --recursive --new-file v2.4.5/linux/fs/Config.in linux/fs/Config.in
--- v2.4.5/linux/fs/Config.in	Sun May 20 12:11:38 2001
+++ linux/fs/Config.in	Wed Jun 20 11:10:27 2001
@@ -104,9 +104,9 @@
 
    dep_tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS $CONFIG_INET
    if [ "$CONFIG_SMB_FS" != "n" ]; then
-      bool '   Use a default NLS' CONFIG_SMB_NLS_DEFAULT
+      bool '  Use a default NLS' CONFIG_SMB_NLS_DEFAULT
       if [ "$CONFIG_SMB_NLS_DEFAULT" = "y" ]; then
-         string '  Default Remote NLS Option' CONFIG_SMB_NLS_REMOTE "cp437"
+         string '    Default Remote NLS Option' CONFIG_SMB_NLS_REMOTE "cp437"
       fi
    fi
    if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then
diff -u --recursive --new-file v2.4.5/linux/fs/autofs/autofs_i.h linux/fs/autofs/autofs_i.h
--- v2.4.5/linux/fs/autofs/autofs_i.h	Fri Feb  9 11:29:44 2001
+++ linux/fs/autofs/autofs_i.h	Thu Jun 14 14:16:58 2001
@@ -89,7 +89,8 @@
 #define AUTOFS_FIRST_SYMLINK 2
 #define AUTOFS_FIRST_DIR_INO (AUTOFS_FIRST_SYMLINK+AUTOFS_MAX_SYMLINKS)
 
-#define AUTOFS_SYMLINK_BITMAP_LEN ((AUTOFS_MAX_SYMLINKS+31)/32)
+#define AUTOFS_SYMLINK_BITMAP_LEN \
+	((AUTOFS_MAX_SYMLINKS+((sizeof(long)*1)-1))/(sizeof(long)*8))
 
 #define AUTOFS_SBI_MAGIC 0x6d4a556d
 
@@ -103,7 +104,7 @@
 	struct autofs_wait_queue *queues; /* Wait queue pointer */
 	struct autofs_dirhash dirhash; /* Root directory hash */
 	struct autofs_symlink symlink[AUTOFS_MAX_SYMLINKS];
-	u32 symlink_bitmap[AUTOFS_SYMLINK_BITMAP_LEN];
+	unsigned long symlink_bitmap[AUTOFS_SYMLINK_BITMAP_LEN];
 };
 
 extern inline struct autofs_sb_info *autofs_sbi(struct super_block *sb)
diff -u --recursive --new-file v2.4.5/linux/fs/autofs/inode.c linux/fs/autofs/inode.c
--- v2.4.5/linux/fs/autofs/inode.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/autofs/inode.c	Thu Jun 14 14:16:58 2001
@@ -132,7 +132,7 @@
 	sbi->oz_pgrp = current->pgrp;
 	autofs_initialize_hash(&sbi->dirhash);
 	sbi->queues = NULL;
-	memset(sbi->symlink_bitmap, 0, sizeof(u32)*AUTOFS_SYMLINK_BITMAP_LEN);
+	memset(sbi->symlink_bitmap, 0, sizeof(long)*AUTOFS_SYMLINK_BITMAP_LEN);
 	sbi->next_dir_ino = AUTOFS_FIRST_DIR_INO;
 	s->s_blocksize = 1024;
 	s->s_blocksize_bits = 10;
diff -u --recursive --new-file v2.4.5/linux/fs/autofs4/expire.c linux/fs/autofs4/expire.c
--- v2.4.5/linux/fs/autofs4/expire.c	Fri Apr 20 22:57:51 2001
+++ linux/fs/autofs4/expire.c	Mon Jun 11 19:15:27 2001
@@ -66,19 +66,11 @@
    non-busy mounts */
 static int check_vfsmnt(struct vfsmount *mnt, struct dentry *dentry)
 {
-	int ret = 0;
-	struct list_head *tmp;
-
-	list_for_each(tmp, &dentry->d_vfsmnt) {
-		struct vfsmount *vfs = list_entry(tmp, struct vfsmount, 
-						  mnt_clash);
-		DPRINTK(("check_vfsmnt: mnt=%p, dentry=%p, tmp=%p, vfs=%p\n",
-			 mnt, dentry, tmp, vfs));
-		if (vfs->mnt_parent != mnt || /* don't care about busy-ness of other namespaces */
-		    !is_vfsmnt_tree_busy(vfs))
-			ret++;
-	}
+	int ret = dentry->d_mounted;
+	struct vfsmount *vfs = lookup_mnt(mnt, dentry);
 
+	if (vfs && is_vfsmnt_tree_busy(vfs))
+		ret--;
 	DPRINTK(("check_vfsmnt: ret=%d\n", ret));
 	return ret;
 }
diff -u --recursive --new-file v2.4.5/linux/fs/block_dev.c linux/fs/block_dev.c
--- v2.4.5/linux/fs/block_dev.c	Tue May 22 09:35:42 2001
+++ linux/fs/block_dev.c	Mon Jun 11 19:15:27 2001
@@ -595,14 +595,15 @@
 
 int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg)
 {
-	kdev_t rdev = to_kdev_t(bdev->bd_dev);
 	struct inode inode_fake;
 	int res;
 	mm_segment_t old_fs = get_fs();
 
 	if (!bdev->bd_op->ioctl)
 		return -EINVAL;
-	inode_fake.i_rdev=rdev;
+	memset(&inode_fake, 0, sizeof(inode_fake));
+	inode_fake.i_rdev = to_kdev_t(bdev->bd_dev);
+	inode_fake.i_bdev = bdev;
 	init_waitqueue_head(&inode_fake.i_wait);
 	set_fs(KERNEL_DS);
 	res = bdev->bd_op->ioctl(&inode_fake, NULL, cmd, arg);
diff -u --recursive --new-file v2.4.5/linux/fs/buffer.c linux/fs/buffer.c
--- v2.4.5/linux/fs/buffer.c	Fri May 25 17:57:46 2001
+++ linux/fs/buffer.c	Tue Jun 12 10:21:14 2001
@@ -61,7 +61,7 @@
 
 #define BUFSIZE_INDEX(X) ((int) buffersize_index[(X)>>9])
 #define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)
-#define NR_RESERVED (2*MAX_BUF_PER_PAGE)
+#define NR_RESERVED (10*MAX_BUF_PER_PAGE)
 #define MAX_UNUSED_BUFFERS NR_RESERVED+20 /* don't ever have more than this 
 					     number of unused buffer heads */
 
@@ -646,8 +646,8 @@
 			/* Another device? */
 			if (bh->b_dev != dev)
 				continue;
-			/* Part of a mapping? */
-			if (bh->b_page->mapping)
+			/* Not hashed? */
+			if (!bh->b_pprev)
 				continue;
 			if (buffer_locked(bh)) {
 				atomic_inc(&bh->b_count);
@@ -711,6 +711,9 @@
 			bh_next = bh->b_next_free;
 			if (bh->b_dev != dev || bh->b_size == size)
 				continue;
+			/* Unhashed? */
+			if (!bh->b_pprev)
+				continue;
 			if (buffer_locked(bh)) {
 				atomic_inc(&bh->b_count);
 				spin_unlock(&lru_list_lock);
@@ -1348,11 +1351,9 @@
 	 */
 	run_task_queue(&tq_disk);
 
-	/* 
-	 * Set our state for sleeping, then check again for buffer heads.
-	 * This ensures we won't miss a wake_up from an interrupt.
-	 */
-	wait_event(buffer_wait, nr_unused_buffer_heads >= MAX_BUF_PER_PAGE);
+	current->policy |= SCHED_YIELD;
+	__set_current_state(TASK_RUNNING);
+	schedule();
 	goto try_again;
 }
 
diff -u --recursive --new-file v2.4.5/linux/fs/dcache.c linux/fs/dcache.c
--- v2.4.5/linux/fs/dcache.c	Tue May 22 09:35:42 2001
+++ linux/fs/dcache.c	Mon Jun 11 19:15:27 2001
@@ -616,7 +616,7 @@
 	dentry->d_name.hash = name->hash;
 	dentry->d_op = NULL;
 	dentry->d_fsdata = NULL;
-	INIT_LIST_HEAD(&dentry->d_vfsmnt);
+	dentry->d_mounted = 0;
 	INIT_LIST_HEAD(&dentry->d_hash);
 	INIT_LIST_HEAD(&dentry->d_lru);
 	INIT_LIST_HEAD(&dentry->d_subdirs);
@@ -1283,6 +1283,7 @@
 
 	dcache_init(mempages);
 	inode_init(mempages);
+	mnt_init(mempages);
 	bdev_cache_init();
 	cdev_cache_init();
 }
diff -u --recursive --new-file v2.4.5/linux/fs/devfs/base.c linux/fs/devfs/base.c
--- v2.4.5/linux/fs/devfs/base.c	Tue May 22 09:35:42 2001
+++ linux/fs/devfs/base.c	Wed Jun 20 10:54:31 2001
@@ -1,6 +1,6 @@
 /*  devfs (Device FileSystem) driver.
 
-    Copyright (C) 1998-2000  Richard Gooch
+    Copyright (C) 1998-2001  Richard Gooch
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -481,6 +481,32 @@
 	       Simplified interface to <devfs_find_handle>.
 	       Work sponsored by SGI.
   v0.102
+    20010519   Richard Gooch <rgooch@atnf.csiro.au>
+	       Ensure <devfs_generate_path> terminates string for root entry.
+	       Exported <devfs_get_name> to modules.
+    20010520   Richard Gooch <rgooch@atnf.csiro.au>
+	       Make <devfs_mk_symlink> send events to devfsd.
+	       Cleaned up option processing in <devfs_setup>.
+    20010521   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed bugs in handling symlinks: could leak or cause Oops.
+    20010522   Richard Gooch <rgooch@atnf.csiro.au>
+	       Cleaned up directory handling by separating fops.
+  v0.103
+    20010601   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed handling of inverted options in <devfs_setup>.
+  v0.104
+    20010604   Richard Gooch <rgooch@atnf.csiro.au>
+	       Adjusted <try_modload> to account for <devfs_generate_path> fix.
+  v0.105
+    20010617   Richard Gooch <rgooch@atnf.csiro.au>
+	       Answered question posed by Al Viro and removed his comments.
+	       Moved setting of registered flag after other fields are changed.
+	       Fixed race between <devfsd_close> and <devfsd_notify_one>.
+	       Global VFS changes added bogus BKL to <devfsd_close>: removed.
+	       Widened locking in <devfs_readlink> and <devfs_follow_link>.
+	       Replaced <devfsd_read> stack usage with <devfsd_ioctl> kmalloc.
+	       Simplified locking in <devfsd_ioctl> and fixed memory leak.
+  v0.106
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -515,7 +541,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
-#define DEVFS_VERSION            "0.102 (20000622)"
+#define DEVFS_VERSION            "0.106 (20010617)"
 
 #define DEVFS_NAME "devfs"
 
@@ -560,7 +586,7 @@
 
 #define OPTION_NONE             0x00
 #define OPTION_SHOW             0x01
-#define OPTION_NOMOUNT          0x02
+#define OPTION_MOUNT            0x02
 #define OPTION_ONLY             0x04
 
 #define OOPS(format, args...) {printk (format, ## args); \
@@ -665,26 +691,27 @@
     gid_t gid;
 };
 
-struct fs_info      /*  This structure is for each mounted devfs  */
+struct fs_info      /*  This structure is for the mounted devfs  */
 {
     unsigned int num_inodes;    /*  Number of inodes created         */
     unsigned int table_size;    /*  Size of the inode pointer table  */
     struct devfs_entry **table;
     struct super_block *sb;
     volatile struct devfsd_buf_entry *devfsd_buffer;
+    spinlock_t devfsd_buffer_lock;
     volatile unsigned int devfsd_buf_in;
     volatile unsigned int devfsd_buf_out;
     volatile int devfsd_sleeping;
-    volatile int devfsd_buffer_in_use;
     volatile struct task_struct *devfsd_task;
     volatile struct file *devfsd_file;
+    struct devfsd_notify_struct *devfsd_info;
     volatile unsigned long devfsd_event_mask;
     atomic_t devfsd_overrun_count;
     wait_queue_head_t devfsd_wait_queue;
     wait_queue_head_t revalidate_wait_queue;
 };
 
-static struct fs_info fs_info;
+static struct fs_info fs_info = {devfsd_buffer_lock: SPIN_LOCK_UNLOCKED};
 static unsigned int next_devnum_char = MIN_DEVNUM;
 static unsigned int next_devnum_block = MIN_DEVNUM;
 static const int devfsd_buf_size = PAGE_SIZE / sizeof(struct devfsd_buf_entry);
@@ -694,9 +721,9 @@
 #endif
 
 #ifdef CONFIG_DEVFS_MOUNT
-static unsigned int boot_options = OPTION_NONE;
+static unsigned int boot_options = OPTION_MOUNT;
 #else
-static unsigned int boot_options = OPTION_NOMOUNT;
+static unsigned int boot_options = OPTION_NONE;
 #endif
 
 /*  Forward function declarations  */
@@ -851,14 +878,13 @@
     /*  Always ensure the root is created  */
     if (root_entry != NULL) return root_entry;
     if ( ( root_entry = create_entry (NULL, NULL, 0) ) == NULL ) return NULL;
-    root_entry->registered = TRUE;
     root_entry->mode = S_IFDIR;
     /*  Force an inode update, because lookup() is never done for the root  */
     update_devfs_inode_from_entry (root_entry);
+    root_entry->registered = TRUE;
     /*  And create the entry for ".devfsd"  */
     if ( ( new = create_entry (root_entry, ".devfsd", 0) ) == NULL )
 	return NULL;
-    new->registered = TRUE;
     new->u.fcb.u.device.major = next_devnum_char >> 8;
     new->u.fcb.u.device.minor = next_devnum_char & 0xff;
     ++next_devnum_char;
@@ -866,6 +892,7 @@
     new->u.fcb.default_uid = 0;
     new->u.fcb.default_gid = 0;
     new->u.fcb.ops = &devfsd_fops;
+    new->registered = TRUE;
     return root_entry;
 }   /*  End Function get_root_entry  */
 
@@ -943,8 +970,8 @@
 	    return NULL;
 	}
 	/*  Ensure an unregistered entry is re-registered and visible  */
-	entry->registered = TRUE;
 	entry->hide = FALSE;
+	entry->registered = TRUE;
 	subname = ptr + 1;
 	dir = entry;
     }
@@ -1053,8 +1080,10 @@
     return find_by_dev (root_entry, major, minor, type);
 }   /*  End Function find_entry  */
 
-static struct devfs_entry *get_devfs_entry_from_vfs_inode (struct inode *inode)
+static struct devfs_entry *get_devfs_entry_from_vfs_inode (struct inode *inode,
+							   int do_check)
 {
+    struct devfs_entry *de;
     struct fs_info *fs_info;
 
     if (inode == NULL) return NULL;
@@ -1062,7 +1091,9 @@
     fs_info = inode->i_sb->u.generic_sbp;
     if (fs_info == NULL) return NULL;
     if (inode->i_ino - FIRST_INODE >= fs_info->num_inodes) return NULL;
-    return fs_info->table[inode->i_ino - FIRST_INODE];
+    de = fs_info->table[inode->i_ino - FIRST_INODE];
+    if (do_check && de && !de->registered) de = NULL;
+    return de;
 }   /*  End Function get_devfs_entry_from_vfs_inode  */
 
 
@@ -1075,19 +1106,19 @@
 {
     struct dentry *dentry;
 
-    spin_lock(&dcache_lock);
+    spin_lock (&dcache_lock);
     dentry = de->inode.dentry;
     if (dentry != NULL)
     {
 	dget_locked (dentry);
 	de->inode.dentry = NULL;
-	spin_unlock(&dcache_lock);
+	spin_unlock (&dcache_lock);
 	/*  Forcefully remove the inode  */
 	if (dentry->d_inode != NULL) dentry->d_inode->i_nlink = 0;
 	d_drop (dentry);
 	dput (dentry);
-    } else
-	spin_unlock(&dcache_lock);
+    }
+    else spin_unlock (&dcache_lock);
 }   /*  End Function free_dentries  */
 
 
@@ -1140,7 +1171,7 @@
     add_wait_queue (&fs_info->revalidate_wait_queue, &wait);
     current->state = TASK_UNINTERRUPTIBLE;
     if (!devfsd_queue_empty (fs_info) || !fs_info->devfsd_sleeping)
-	if (fs_info->devfsd_task) schedule();
+	if (fs_info->devfsd_task) schedule ();
     remove_wait_queue (&fs_info->revalidate_wait_queue, &wait);
     current->state = TASK_RUNNING;
     return (TRUE);
@@ -1165,7 +1196,6 @@
     unsigned int next_pos;
     unsigned long flags;
     struct devfsd_buf_entry *entry;
-    static spinlock_t lock = SPIN_LOCK_UNLOCKED;
 
     if ( !( fs_info->devfsd_event_mask & (1 << type) ) ) return (FALSE);
     next_pos = fs_info->devfsd_buf_in + 1;
@@ -1176,8 +1206,7 @@
 	atomic_inc (&fs_info->devfsd_overrun_count);
 	return (FALSE);
     }
-    spin_lock_irqsave (&lock, flags);
-    fs_info->devfsd_buffer_in_use = TRUE;
+    spin_lock_irqsave (&fs_info->devfsd_buffer_lock, flags);
     next_pos = fs_info->devfsd_buf_in + 1;
     if (next_pos >= devfsd_buf_size) next_pos = 0;
     entry = (struct devfsd_buf_entry *) fs_info->devfsd_buffer +
@@ -1188,8 +1217,7 @@
     entry->uid = uid;
     entry->gid = gid;
     fs_info->devfsd_buf_in = next_pos;
-    fs_info->devfsd_buffer_in_use = FALSE;
-    spin_unlock_irqrestore (&lock, flags);
+    spin_unlock_irqrestore (&fs_info->devfsd_buffer_lock, flags);
     wake_up_interruptible (&fs_info->devfsd_wait_queue);
     return (TRUE);
 }   /*  End Function devfsd_notify_one  */
@@ -1322,7 +1350,6 @@
 	    return NULL;
 	}
     }
-    de->registered = TRUE;
     if ( S_ISCHR (mode) || S_ISBLK (mode) )
     {
 	de->u.fcb.u.device.major = major;
@@ -1347,7 +1374,6 @@
 	de->u.fcb.default_uid = 0;
 	de->u.fcb.default_gid = 0;
     }
-    de->registered = TRUE;
     de->u.fcb.ops = ops;
     de->u.fcb.auto_owner = (flags & DEVFS_FL_AUTO_OWNER) ? TRUE : FALSE;
     de->u.fcb.aopen_notify = (flags & DEVFS_FL_AOPEN_NOTIFY) ? TRUE : FALSE;
@@ -1361,6 +1387,7 @@
 			|| (flags & DEVFS_FL_SHOW_UNREG) ) ? TRUE : FALSE;
     de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
     de->no_persistence = (flags & DEVFS_FL_NO_PERSISTENCE) ? TRUE : FALSE;
+    de->registered = TRUE;
     devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT);
     return de;
 }   /*  End Function devfs_register  */
@@ -1392,11 +1419,10 @@
 	de->u.fcb.ops = NULL;
 	return;
     }
-    if ( S_ISLNK (de->mode) )
+    if (S_ISLNK (de->mode) && de->registered)
     {
 	de->registered = FALSE;
-	if (de->u.symlink.linkname != NULL) kfree (de->u.symlink.linkname);
-	de->u.symlink.linkname = NULL;
+	kfree (de->u.symlink.linkname);
 	return;
     }
     if ( S_ISFIFO (de->mode) )
@@ -1441,22 +1467,9 @@
     unregister (de);
 }   /*  End Function devfs_unregister  */
 
-
-/**
- *	devfs_mk_symlink Create a symbolic link in the devfs namespace.
- *	@dir: The handle to the parent devfs directory entry. If this is %NULL the
- *		new name is relative to the root of the devfs.
- *	@name: The name of the entry.
- *	@flags: A set of bitwise-ORed flags (DEVFS_FL_*).
- *	@link: The destination name.
- *	@handle: The handle to the symlink entry is written here. This may be %NULL.
- *	@info: An arbitrary pointer which will be associated with the entry.
- *
- *	Returns 0 on success, else a negative error code is returned.
- */
-
-int devfs_mk_symlink (devfs_handle_t dir, const char *name, unsigned int flags,
-		      const char *link, devfs_handle_t *handle, void *info)
+static int devfs_do_symlink (devfs_handle_t dir, const char *name,
+			     unsigned int flags, const char *link,
+			     devfs_handle_t *handle, void *info)
 {
     int is_new;
     unsigned int linklength;
@@ -1466,16 +1479,16 @@
     if (handle != NULL) *handle = NULL;
     if (name == NULL)
     {
-	printk ("%s: devfs_mk_symlink(): NULL name pointer\n", DEVFS_NAME);
+	printk ("%s: devfs_do_symlink(): NULL name pointer\n", DEVFS_NAME);
 	return -EINVAL;
     }
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_REGISTER)
-	printk ("%s: devfs_mk_symlink(%s)\n", DEVFS_NAME, name);
+	printk ("%s: devfs_do_symlink(%s)\n", DEVFS_NAME, name);
 #endif
     if (link == NULL)
     {
-	printk ("%s: devfs_mk_symlink(): NULL link pointer\n", DEVFS_NAME);
+	printk ("%s: devfs_do_symlink(): NULL link pointer\n", DEVFS_NAME);
 	return -EINVAL;
     }
     linklength = strlen (link);
@@ -1484,7 +1497,7 @@
     if (de == NULL) return -ENOMEM;
     if (!S_ISLNK (de->mode) && de->registered)
     {
-	printk ("%s: devfs_mk_symlink(): non-link entry already exists\n",
+	printk ("%s: devfs_do_symlink(): non-link entry already exists\n",
 		DEVFS_NAME);
 	return -EEXIST;
     }
@@ -1504,7 +1517,6 @@
     }
     /*  Have to create/update  */
     if (de->registered) return -EEXIST;
-    de->registered = TRUE;
     if ( ( newname = kmalloc (linklength + 1, GFP_KERNEL) ) == NULL )
     {
 	struct devfs_entry *parent = de->parent;
@@ -1518,11 +1530,39 @@
 	kfree (de);
 	return -ENOMEM;
     }
-    if (de->u.symlink.linkname != NULL) kfree (de->u.symlink.linkname);
     de->u.symlink.linkname = newname;
     memcpy (de->u.symlink.linkname, link, linklength);
     de->u.symlink.linkname[linklength] = '\0';
     de->u.symlink.length = linklength;
+    de->registered = TRUE;
+    return 0;
+}   /*  End Function devfs_do_symlink  */
+
+
+/**
+ *	devfs_mk_symlink Create a symbolic link in the devfs namespace.
+ *	@dir: The handle to the parent devfs directory entry. If this is %NULL the
+ *		new name is relative to the root of the devfs.
+ *	@name: The name of the entry.
+ *	@flags: A set of bitwise-ORed flags (DEVFS_FL_*).
+ *	@link: The destination name.
+ *	@handle: The handle to the symlink entry is written here. This may be %NULL.
+ *	@info: An arbitrary pointer which will be associated with the entry.
+ *
+ *	Returns 0 on success, else a negative error code is returned.
+ */
+
+int devfs_mk_symlink (devfs_handle_t dir, const char *name, unsigned int flags,
+		      const char *link, devfs_handle_t *handle, void *info)
+{
+    int err;
+    devfs_handle_t de;
+
+    if (handle != NULL) *handle = NULL;
+    err = devfs_do_symlink (dir, name, flags, link, &de, info);
+    if (err) return err;
+    if (handle != NULL) *handle = de;
+    devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT);
     return 0;
 }   /*  End Function devfs_mk_symlink  */
 
@@ -1579,9 +1619,9 @@
     de->mode = S_IFDIR | S_IRUGO | S_IXUGO;
     de->info = info;
     if (!de->registered) de->u.dir.num_removable = 0;
-    de->registered = TRUE;
     de->show_unreg = (boot_options & OPTION_SHOW) ? TRUE : FALSE;
     de->hide = FALSE;
+    de->registered = TRUE;
     return de;
 }   /*  End Function devfs_mk_dir  */
 
@@ -1716,7 +1756,7 @@
 {
     if (!inode || !inode->i_sb) return NULL;
     if (inode->i_sb->s_magic != DEVFS_SUPER_MAGIC) return NULL;
-    return get_devfs_entry_from_vfs_inode (inode);
+    return get_devfs_entry_from_vfs_inode (inode, TRUE);
 }   /*  End Function devfs_get_handle_from_inode  */
 
 
@@ -1737,10 +1777,10 @@
 
     if (de == NULL) return -EINVAL;
     if (de->namelen >= buflen) return -ENAMETOOLONG; /*  Must be first       */
-    if (de->parent == NULL) return buflen;           /*  Don't prepend root  */
+    path[buflen - 1] = '\0';
+    if (de->parent == NULL) return buflen - 1;       /*  Don't prepend root  */
     pos = buflen - de->namelen - 1;
     memcpy (path + pos, de->name, de->namelen);
-    path[buflen - 1] = '\0';
     for (de = de->parent; de->parent != NULL; de = de->parent)
     {
 	if (pos - de->namelen - 1 < 0) return -ENAMETOOLONG;
@@ -1999,84 +2039,56 @@
 
 static int __init devfs_setup (char *str)
 {
-    while ( (*str != '\0') && !isspace (*str) )
+    static struct
     {
-#ifdef CONFIG_DEVFS_DEBUG
-	if (strncmp (str, "dall", 4) == 0)
-	{
-	    devfs_debug_init |= DEBUG_ALL;
-	    str += 4;
-	}
-	else if (strncmp (str, "dmod", 4) == 0)
-	{
-	    devfs_debug_init |= DEBUG_MODULE_LOAD;
-	    str += 4;
-	}
-	else if (strncmp (str, "dreg", 4) == 0)
-	{
-	    devfs_debug_init |= DEBUG_REGISTER;
-	    str += 4;
-	}
-	else if (strncmp (str, "dunreg", 6) == 0)
-	{
-	    devfs_debug_init |= DEBUG_UNREGISTER;
-	    str += 6;
-	}
-	else if (strncmp (str, "diread", 6) == 0)
-	{
-	    devfs_debug_init |= DEBUG_I_READ;
-	    str += 6;
-	}
-	else if (strncmp (str, "dchange", 7) == 0)
-	{
-	    devfs_debug_init |= DEBUG_SET_FLAGS;
-	    str += 7;
-	}
-	else if (strncmp (str, "diwrite", 7) == 0)
-	{
-	    devfs_debug_init |= DEBUG_I_WRITE;
-	    str += 7;
-	}
-	else if (strncmp (str, "dimknod", 7) == 0)
-	{
-	    devfs_debug_init |= DEBUG_I_MKNOD;
-	    str += 7;
-	}
-	else if (strncmp (str, "dilookup", 8) == 0)
-	{
-	    devfs_debug_init |= DEBUG_I_LOOKUP;
-	    str += 8;
-	}
-	else if (strncmp (str, "diunlink", 8) == 0)
-	{
-	    devfs_debug_init |= DEBUG_I_UNLINK;
-	    str += 8;
-	}
-	else
+	char *name;
+	unsigned int mask;
+	unsigned int *opt;
+    } devfs_options_tab[] __initdata =
+    {
+#ifdef CONFIG_DEVFS_DEBUG
+	{"dall",      DEBUG_ALL,          &devfs_debug_init},
+	{"dmod",      DEBUG_MODULE_LOAD,  &devfs_debug_init},
+	{"dreg",      DEBUG_REGISTER,     &devfs_debug_init},
+	{"dunreg",    DEBUG_UNREGISTER,   &devfs_debug_init},
+	{"diread",    DEBUG_I_READ,       &devfs_debug_init},
+	{"dchange",   DEBUG_SET_FLAGS,    &devfs_debug_init},
+	{"diwrite",   DEBUG_I_WRITE,      &devfs_debug_init},
+	{"dimknod",   DEBUG_I_MKNOD,      &devfs_debug_init},
+	{"dilookup",  DEBUG_I_LOOKUP,     &devfs_debug_init},
+	{"diunlink",  DEBUG_I_UNLINK,     &devfs_debug_init},
 #endif  /*  CONFIG_DEVFS_DEBUG  */
-	if (strncmp (str, "show", 4) == 0)
-	{
-	    boot_options |= OPTION_SHOW;
-	    str += 4;
-	}
-	else if (strncmp (str, "only", 4) == 0)
-	{
-	    boot_options |= OPTION_ONLY;
-	    str += 4;
-	}
-	else if (strncmp (str, "mount", 5) == 0)
+	{"show",      OPTION_SHOW,        &boot_options},
+	{"only",      OPTION_ONLY,        &boot_options},
+	{"mount",     OPTION_MOUNT,       &boot_options},
+    };
+
+    while ( (*str != '\0') && !isspace (*str) )
+    {
+	int i, found = 0, invert = 0;
+
+	if (strncmp (str, "no", 2) == 0)
 	{
-	    boot_options &= ~OPTION_NOMOUNT;
-	    str += 5;
+	    invert = 1;
+	    str += 2;
 	}
-	else if (strncmp (str, "nomount", 7) == 0)
+	for (i = 0; i < sizeof (devfs_options_tab); i++)
 	{
-	    boot_options |= OPTION_NOMOUNT;
-	    str += 7;
+	    int len = strlen (devfs_options_tab[i].name);
+
+	    if (strncmp (str, devfs_options_tab[i].name, len) == 0)
+	    {
+		if (invert)
+		    *devfs_options_tab[i].opt &= ~devfs_options_tab[i].mask;
+		else
+		    *devfs_options_tab[i].opt |= devfs_options_tab[i].mask;
+		str += len;
+		found = 1;
+		break;
+	    }
 	}
-	else
-	return 0;
-	if (*str != ',') return 0;
+	if (!found) return 0;       /*  No match         */
+	if (*str != ',') return 0;  /*  No more options  */
 	++str;
     }
     return 1;
@@ -2103,6 +2115,7 @@
 EXPORT_SYMBOL(devfs_get_next_sibling);
 EXPORT_SYMBOL(devfs_auto_unregister);
 EXPORT_SYMBOL(devfs_get_unregister_slave);
+EXPORT_SYMBOL(devfs_get_name);
 EXPORT_SYMBOL(devfs_register_chrdev);
 EXPORT_SYMBOL(devfs_register_blkdev);
 EXPORT_SYMBOL(devfs_unregister_chrdev);
@@ -2125,15 +2138,15 @@
 			const char *name, unsigned namelen,
 			char buf[STRING_LENGTH])
 {
-    int pos;
+    int pos = STRING_LENGTH - namelen - 1;
 
     if ( !( fs_info->devfsd_event_mask & (1 << DEVFSD_NOTIFY_LOOKUP) ) )
 	return -ENOENT;
     if ( is_devfsd_or_child (fs_info) ) return -ENOENT;
     if (namelen >= STRING_LENGTH) return -ENAMETOOLONG;
-    memcpy (buf + STRING_LENGTH - namelen - 1, name, namelen);
+    memcpy (buf + pos, name, namelen);
     buf[STRING_LENGTH - 1] = '\0';
-    pos = devfs_generate_path (parent, buf, STRING_LENGTH - namelen - 1);
+    if (parent->parent != NULL) pos = devfs_generate_path (parent, buf, pos);
     if (pos < 0) return pos;
     buf[STRING_LENGTH - namelen - 2] = '/';
     if ( !devfsd_notify_one (buf + pos, DEVFSD_NOTIFY_LOOKUP, 0,
@@ -2229,13 +2242,14 @@
 static struct inode_operations devfs_iops;
 static struct inode_operations devfs_dir_iops;
 static struct file_operations devfs_fops;
+static struct file_operations devfs_dir_fops;
 static struct inode_operations devfs_symlink_iops;
 
 static void devfs_read_inode (struct inode *inode)
 {
     struct devfs_entry *de;
 
-    de = get_devfs_entry_from_vfs_inode (inode);
+    de = get_devfs_entry_from_vfs_inode (inode, TRUE);
     if (de == NULL)
     {
 	printk ("%s: read_inode(%d): VFS inode: %p  NO devfs_entry\n",
@@ -2273,7 +2287,11 @@
     }
     else if ( S_ISFIFO (de->inode.mode) ) inode->i_fop = &def_fifo_fops;
     else if ( S_ISREG (de->inode.mode) ) inode->i_size = de->u.fcb.u.file.size;
-    else if ( S_ISDIR (de->inode.mode) ) inode->i_op = &devfs_dir_iops;
+    else if ( S_ISDIR (de->inode.mode) )
+    {
+	inode->i_op = &devfs_dir_iops;
+    	inode->i_fop = &devfs_dir_fops;
+    }
     else if ( S_ISLNK (de->inode.mode) )
     {
 	inode->i_op = &devfs_symlink_iops;
@@ -2302,12 +2320,12 @@
 
     if (inode->i_ino < FIRST_INODE) return;
     index = inode->i_ino - FIRST_INODE;
-    lock_kernel();
+    lock_kernel ();
     if (index >= fs_info->num_inodes)
     {
 	printk ("%s: writing inode: %lu for which there is no entry!\n",
 		DEVFS_NAME, inode->i_ino);
-        unlock_kernel();
+        unlock_kernel ();
 	return;
     }
     de = fs_info->table[index];
@@ -2327,7 +2345,7 @@
     de->inode.atime = inode->i_atime;
     de->inode.mtime = inode->i_mtime;
     de->inode.ctime = inode->i_ctime;
-    unlock_kernel();
+    unlock_kernel ();
 }   /*  End Function devfs_write_inode  */
 
 static int devfs_notify_change (struct dentry *dentry, struct iattr *iattr)
@@ -2337,7 +2355,7 @@
     struct inode *inode = dentry->d_inode;
     struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
 
-    de = get_devfs_entry_from_vfs_inode (inode);
+    de = get_devfs_entry_from_vfs_inode (inode, TRUE);
     if (de == NULL) return -ENODEV;
     retval = inode_change_ok (inode, iattr);
     if (retval != 0) return retval;
@@ -2399,12 +2417,6 @@
 
 /*  File operations for device entries follow  */
 
-static ssize_t devfs_read (struct file *file, char *buf, size_t len, loff_t *ppos)
-{
-    if ( S_ISDIR (file->f_dentry->d_inode->i_mode) ) return -EISDIR;
-    return -EINVAL;
-}   /*  End Function devfs_read  */
-
 static int devfs_readdir (struct file *file, void *dirent, filldir_t filldir)
 {
     int err, count;
@@ -2413,13 +2425,8 @@
     struct devfs_entry *parent, *de;
     struct inode *inode = file->f_dentry->d_inode;
 
-    if ( !S_ISDIR (inode->i_mode) )
-    {
-	printk ("%s: readdir(): inode is not a directory\n", DEVFS_NAME);
-	return -ENOTDIR;
-    }
     fs_info = inode->i_sb->u.generic_sbp;
-    parent = get_devfs_entry_from_vfs_inode (file->f_dentry->d_inode);
+    parent = get_devfs_entry_from_vfs_inode (file->f_dentry->d_inode, TRUE);
     if ( (long) file->f_pos < 0 ) return -EINVAL;
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_F_READDIR)
@@ -2473,8 +2480,8 @@
     struct devfs_entry *de;
     struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
 
-    lock_kernel();
-    de = get_devfs_entry_from_vfs_inode (inode);
+    lock_kernel ();
+    de = get_devfs_entry_from_vfs_inode (inode, TRUE);
     err = -ENODEV;
     if (de == NULL)
 	goto out;
@@ -2482,34 +2489,18 @@
     if ( S_ISDIR (de->mode) )
 	goto out;
     df = &de->u.fcb;
-    err = -ENODEV;
-    if (!de->registered)
-	goto out;
     file->private_data = de->info;
     if ( S_ISBLK (inode->i_mode) )
     {
 	file->f_op = &def_blk_fops;
 	if (df->ops) inode->i_bdev->bd_op = df->ops;
     }
-    else file->f_op = fops_get((struct file_operations*)df->ops);
+    else file->f_op = fops_get ( (struct file_operations*) df->ops );
     if (file->f_op)
 	err = file->f_op->open ? (*file->f_op->open) (inode, file) : 0;
     else
     {
 	/*  Fallback to legacy scheme  */
-	/*
-	 * Do we need it? Richard, could you verify it?
-	 * It can legitimately happen if
-	 *	it is a character device and 
-	 *	df->ops == NULL and
-	 *	de->registered is true,
-	 * but AFAICS it can't happen - in devfs_register() we never set
-	 * ->ops to NULL, in unregister() we set ->registered to false,
-	 * in devfs_mknod() we set it to NULL only if ->register is false.
-	 *
-	 * Looks like this fallback is not needed at all.
-	 *							AV
-	 */
 	if ( S_ISCHR (inode->i_mode) ) err = chrdev_open (inode, file);
 	else err = -ENODEV;
     }
@@ -2532,13 +2523,18 @@
 	devfsd_notify_one (de, DEVFSD_NOTIFY_ASYNC_OPEN, inode->i_mode,
 			   current->euid, current->egid, fs_info);
 out:
-    unlock_kernel();
+    unlock_kernel ();
     return err;
 }   /*  End Function devfs_open  */
 
 static struct file_operations devfs_fops =
 {
-    read: devfs_read,
+    open: devfs_open,
+};
+
+static struct file_operations devfs_dir_fops =
+{
+    read: generic_read_dir,
     readdir: devfs_readdir,
     open: devfs_open,
 };
@@ -2574,7 +2570,7 @@
     struct devfs_entry *de;
 
     lock_kernel ();
-    de = get_devfs_entry_from_vfs_inode (inode);
+    de = get_devfs_entry_from_vfs_inode (inode, FALSE);
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_D_IPUT)
 	printk ("%s: d_iput(): dentry: %p inode: %p de: %p  de->dentry: %p\n",
@@ -2627,7 +2623,7 @@
 	return 1;
     }
     fs_info = inode->i_sb->u.generic_sbp;
-    de = get_devfs_entry_from_vfs_inode (inode);
+    de = get_devfs_entry_from_vfs_inode (inode, TRUE);
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_D_DELETE)
 	printk ("%s: d_delete(): dentry: %p  inode: %p  devfs_entry: %p\n",
@@ -2682,7 +2678,7 @@
 	    {
 		devfs_handle_t parent;
 
-		parent = get_devfs_entry_from_vfs_inode (dir);
+		parent = get_devfs_entry_from_vfs_inode (dir, TRUE);
 		de = search_for_entry_in_dir (parent, dentry->d_name.name,
 					      dentry->d_name.len, FALSE);
 	    }
@@ -2723,12 +2719,6 @@
     /*  Set up the dentry operations before anything else, to ensure cleaning
 	up on any error  */
     dentry->d_op = &devfs_dops;
-    if (dir == NULL)
-    {
-	printk ("%s: lookup(): NULL directory inode\n", DEVFS_NAME);
-	return ERR_PTR (-ENOTDIR);
-    }
-    if ( !S_ISDIR (dir->i_mode) ) return ERR_PTR (-ENOTDIR);
     memset (txt, 0, STRING_LENGTH);
     memcpy (txt, dentry->d_name.name,
 	    (dentry->d_name.len >= STRING_LENGTH) ?
@@ -2740,9 +2730,8 @@
 #endif
     fs_info = dir->i_sb->u.generic_sbp;
     /*  First try to get the devfs entry for this directory  */
-    parent = get_devfs_entry_from_vfs_inode (dir);
-    if (parent == NULL) return ERR_PTR (-EINVAL);
-    if (!parent->registered) return ERR_PTR (-ENOENT);
+    parent = get_devfs_entry_from_vfs_inode (dir, TRUE);
+    if (parent == NULL) return ERR_PTR (-ENOENT);
     /*  Try to reclaim an existing devfs entry  */
     de = search_for_entry_in_dir (parent,
 				  dentry->d_name.name, dentry->d_name.len,
@@ -2845,13 +2834,11 @@
     }
 #endif
 
-    if ( !dir || !S_ISDIR (dir->i_mode) ) return -ENOTDIR;
-    if (!dentry || !dentry->d_inode) return -ENOENT;
-    de = get_devfs_entry_from_vfs_inode (dentry->d_inode);
+    de = get_devfs_entry_from_vfs_inode (dentry->d_inode, TRUE);
     if (de == NULL) return -ENOENT;
-    if (!de->registered) return -ENOENT;
     de->registered = FALSE;
     de->hide = TRUE;
+    if ( S_ISLNK (de->mode) ) kfree (de->u.symlink.linkname);
     free_dentries (de);
     return 0;
 }   /*  End Function devfs_unlink  */
@@ -2864,17 +2851,15 @@
     struct devfs_entry *parent, *de;
     struct inode *inode;
 
-    if ( !dir || !S_ISDIR (dir->i_mode) ) return -ENOTDIR;
     fs_info = dir->i_sb->u.generic_sbp;
     /*  First try to get the devfs entry for this directory  */
-    parent = get_devfs_entry_from_vfs_inode (dir);
-    if (parent == NULL) return -EINVAL;
-    if (!parent->registered) return -ENOENT;
-    err = devfs_mk_symlink (parent, dentry->d_name.name, DEVFS_FL_NONE,
+    parent = get_devfs_entry_from_vfs_inode (dir, TRUE);
+    if (parent == NULL) return -ENOENT;
+    err = devfs_do_symlink (parent, dentry->d_name.name, DEVFS_FL_NONE,
 			    symname, &de, NULL);
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_DISABLED)
-	printk ("%s: symlink(): errcode from <devfs_mk_symlink>: %d\n",
+	printk ("%s: symlink(): errcode from <devfs_do_symlink>: %d\n",
 		DEVFS_NAME, err);
 #endif
     if (err < 0) return err;
@@ -2904,13 +2889,10 @@
     struct inode *inode;
 
     mode = (mode & ~S_IFMT) | S_IFDIR;
-    if ( !dir || !S_ISDIR (dir->i_mode) ) return -ENOTDIR;
     fs_info = dir->i_sb->u.generic_sbp;
-    /*  We are allowed to create the directory  */
     /*  First try to get the devfs entry for this directory  */
-    parent = get_devfs_entry_from_vfs_inode (dir);
-    if (parent == NULL) return -EINVAL;
-    if (!parent->registered) return -ENOENT;
+    parent = get_devfs_entry_from_vfs_inode (dir, TRUE);
+    if (parent == NULL) return -ENOENT;
     /*  Try to reclaim an existing devfs entry, create if there isn't one  */
     de = search_for_entry (parent, dentry->d_name.name, dentry->d_name.len,
 			   FALSE, TRUE, &is_new, FALSE);
@@ -2920,7 +2902,6 @@
 	printk ("%s: mkdir(): existing entry\n", DEVFS_NAME);
 	return -EEXIST;
     }
-    de->registered = TRUE;
     de->hide = FALSE;
     if (!S_ISDIR (de->mode) && !is_new)
     {
@@ -2936,6 +2917,7 @@
     de->inode.atime = CURRENT_TIME;
     de->inode.mtime = CURRENT_TIME;
     de->inode.ctime = CURRENT_TIME;
+    de->registered = TRUE;
     if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
 	return -ENOMEM;
 #ifdef CONFIG_DEVFS_DEBUG
@@ -2956,13 +2938,10 @@
     struct devfs_entry *de, *child;
     struct inode *inode = dentry->d_inode;
 
-    if ( !dir || !S_ISDIR (dir->i_mode) ) return -ENOTDIR;
     if (dir->i_sb->u.generic_sbp != inode->i_sb->u.generic_sbp) return -EINVAL;
-    if (inode == dir) return -EPERM;
     fs_info = dir->i_sb->u.generic_sbp;
-    de = get_devfs_entry_from_vfs_inode (inode);
+    de = get_devfs_entry_from_vfs_inode (inode, TRUE);
     if (de == NULL) return -ENOENT;
-    if (!de->registered) return -ENOENT;
     if ( !S_ISDIR (de->mode) ) return -ENOTDIR;
     for (child = de->u.dir.first; child != NULL; child = child->next)
     {
@@ -2973,8 +2952,8 @@
 	}
     }
     if (has_children) return -ENOTEMPTY;
-    de->registered = FALSE;
     de->hide = TRUE;
+    de->registered = FALSE;
     free_dentries (de);
     return 0;
 }   /*  End Function devfs_rmdir  */
@@ -3000,15 +2979,10 @@
     }
 #endif
 
-    if ( !dir || !S_ISDIR (dir->i_mode) ) return -ENOTDIR;
     fs_info = dir->i_sb->u.generic_sbp;
-    if ( !S_ISBLK (mode) && !S_ISCHR (mode) && !S_ISFIFO (mode) &&
-	 !S_ISSOCK (mode) ) return -EPERM;
-    /*  We are allowed to create the node  */
     /*  First try to get the devfs entry for this directory  */
-    parent = get_devfs_entry_from_vfs_inode (dir);
-    if (parent == NULL) return -EINVAL;
-    if (!parent->registered) return -ENOENT;
+    parent = get_devfs_entry_from_vfs_inode (dir, TRUE);
+    if (parent == NULL) return -ENOENT;
     /*  Try to reclaim an existing devfs entry, create if there isn't one  */
     de = search_for_entry (parent, dentry->d_name.name, dentry->d_name.len,
 			   FALSE, TRUE, &is_new, FALSE);
@@ -3035,7 +3009,6 @@
 	    de->u.fifo.gid = current->egid;
 	}
     }
-    de->registered = TRUE;
     de->show_unreg = FALSE;
     de->hide = FALSE;
     de->inode.mode = mode;
@@ -3044,6 +3017,7 @@
     de->inode.atime = CURRENT_TIME;
     de->inode.mtime = CURRENT_TIME;
     de->inode.ctime = CURRENT_TIME;
+    de->registered = TRUE;
     if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
 	return -ENOMEM;
 #ifdef CONFIG_DEVFS_DEBUG
@@ -3059,32 +3033,31 @@
 
 static int devfs_readlink (struct dentry *dentry, char *buffer, int buflen)
 {
+    int err;
     struct devfs_entry *de;
 
     lock_kernel ();
-    de = get_devfs_entry_from_vfs_inode (dentry->d_inode);
+    de = get_devfs_entry_from_vfs_inode (dentry->d_inode, TRUE);
+    err = de ? vfs_readlink (dentry, buffer, buflen,
+			     de->u.symlink.linkname) : -ENODEV;
     unlock_kernel ();
-    return vfs_readlink (dentry, buffer, buflen, de->u.symlink.linkname);
+    return err;
 }   /*  End Function devfs_readlink  */
 
 static int devfs_follow_link (struct dentry *dentry, struct nameidata *nd)
 {
+    int err;
     struct devfs_entry *de;
 
     lock_kernel ();
-    de = get_devfs_entry_from_vfs_inode (dentry->d_inode);
+    de = get_devfs_entry_from_vfs_inode (dentry->d_inode, TRUE);
+    err = de ? vfs_follow_link (nd, de->u.symlink.linkname) : -ENODEV;
     unlock_kernel ();
-    return vfs_follow_link (nd, de->u.symlink.linkname);
+    return err;
 }   /*  End Function devfs_follow_link  */
 
 static struct inode_operations devfs_iops =
 {
-    link:           devfs_link,
-    unlink:         devfs_unlink,
-    symlink:        devfs_symlink,
-    mkdir:          devfs_mkdir,
-    rmdir:          devfs_rmdir,
-    mknod:          devfs_mknod,
     setattr:        devfs_notify_change,
 };
 
@@ -3151,17 +3124,17 @@
     int done = FALSE;
     int ival;
     loff_t pos, devname_offset, tlen, rpos;
-    struct devfsd_notify_struct info;
     struct devfsd_buf_entry *entry;
     struct fs_info *fs_info = file->f_dentry->d_inode->i_sb->u.generic_sbp;
+    struct devfsd_notify_struct *info = fs_info->devfsd_info;
     DECLARE_WAITQUEUE (wait, current);
 
     /*  Can't seek (pread) on this device  */
     if (ppos != &file->f_pos) return -ESPIPE;
     /*  Verify the task has grabbed the queue  */
     if (fs_info->devfsd_task != current) return -EPERM;
-    info.major = 0;
-    info.minor = 0;
+    info->major = 0;
+    info->minor = 0;
     /*  Block for a new entry  */
     add_wait_queue (&fs_info->devfsd_wait_queue, &wait);
     current->state = TASK_INTERRUPTIBLE;
@@ -3184,18 +3157,18 @@
     /*  Now play with the data  */
     ival = atomic_read (&fs_info->devfsd_overrun_count);
     if (ival > 0) atomic_sub (ival, &fs_info->devfsd_overrun_count);
-    info.overrun_count = ival;
+    info->overrun_count = ival;
     entry = (struct devfsd_buf_entry *) fs_info->devfsd_buffer +
 	fs_info->devfsd_buf_out;
-    info.type = entry->type;
-    info.mode = entry->mode;
-    info.uid = entry->uid;
-    info.gid = entry->gid;
+    info->type = entry->type;
+    info->mode = entry->mode;
+    info->uid = entry->uid;
+    info->gid = entry->gid;
     if (entry->type == DEVFSD_NOTIFY_LOOKUP)
     {
-	info.namelen = strlen (entry->data);
+	info->namelen = strlen (entry->data);
 	pos = 0;
-	memcpy (info.devname, entry->data, info.namelen + 1);
+	memcpy (info->devname, entry->data, info->namelen + 1);
     }
     else
     {
@@ -3203,22 +3176,22 @@
 
 	if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
 	{
-	    info.major = de->u.fcb.u.device.major;
-	    info.minor = de->u.fcb.u.device.minor;
+	    info->major = de->u.fcb.u.device.major;
+	    info->minor = de->u.fcb.u.device.minor;
 	}
-	pos = devfs_generate_path (de, info.devname, DEVFS_PATHLEN);
+	pos = devfs_generate_path (de, info->devname, DEVFS_PATHLEN);
 	if (pos < 0) return pos;
-	info.namelen = DEVFS_PATHLEN - pos - 1;
-	if (info.mode == 0) info.mode = de->mode;
+	info->namelen = DEVFS_PATHLEN - pos - 1;
+	if (info->mode == 0) info->mode = de->mode;
     }
-    devname_offset = info.devname - (char *) &info;
+    devname_offset = info->devname - (char *) info;
     rpos = *ppos;
     if (rpos < devname_offset)
     {
 	/*  Copy parts of the header  */
 	tlen = devname_offset - rpos;
 	if (tlen > len) tlen = len;
-	if ( copy_to_user (buf, (char *) &info + rpos, tlen) )
+	if ( copy_to_user (buf, (char *) info + rpos, tlen) )
 	{
 	    return -EFAULT;
 	}
@@ -3229,10 +3202,10 @@
     if ( (rpos >= devname_offset) && (len > 0) )
     {
 	/*  Copy the name  */
-	tlen = info.namelen + 1;
+	tlen = info->namelen + 1;
 	if (tlen > len) tlen = len;
 	else done = TRUE;
-	if ( copy_to_user (buf, info.devname + pos + rpos - devname_offset,
+	if ( copy_to_user (buf, info->devname + pos + rpos - devname_offset,
 			   tlen) )
 	{
 	    return -EFAULT;
@@ -3257,6 +3230,7 @@
 {
     int ival;
     struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
+    static spinlock_t lock = SPIN_LOCK_UNLOCKED;
 
     switch (cmd)
     {
@@ -3270,30 +3244,21 @@
 	    doesn't matter who gets in first, as long as only one gets it  */
 	if (fs_info->devfsd_task == NULL)
 	{
-#ifdef CONFIG_SMP
-	    /*  Looks like no-one has it: check again and grab, with interrupts
-		disabled  */
-	    __cli ();
-	    if (fs_info->devfsd_task == NULL)
-#endif
+	    if ( !spin_trylock (&lock) ) return -EBUSY;
+	    fs_info->devfsd_task = current;
+	    spin_unlock (&lock);
+	    fs_info->devfsd_file = file;
+	    fs_info->devfsd_buffer = (void *) __get_free_page (GFP_KERNEL);
+	    fs_info->devfsd_info = kmalloc (sizeof *fs_info->devfsd_info,
+					    GFP_KERNEL);
+	    if (!fs_info->devfsd_buffer || !fs_info->devfsd_info)
 	    {
-		fs_info->devfsd_event_mask = 0;  /*  Temporary disable  */
-		fs_info->devfsd_task = current;
+		devfsd_close (inode, file);
+		return -ENOMEM;
 	    }
-#ifdef CONFIG_SMP
-	    __sti ();
-#endif
-	}
-	/*  Verify the task has grabbed the queue  */
-	if (fs_info->devfsd_task != current) return -EBUSY;
-	fs_info->devfsd_file = file;
-	fs_info->devfsd_buffer = (void *) __get_free_page (GFP_KERNEL);
-	if (fs_info->devfsd_buffer == NULL)
-	{
-	    devfsd_close (inode, file);
-	    return -ENOMEM;
+	    fs_info->devfsd_buf_out = fs_info->devfsd_buf_in;
 	}
-	fs_info->devfsd_buf_out = fs_info->devfsd_buf_in;
+	else if (fs_info->devfsd_task != current) return -EBUSY;
 	fs_info->devfsd_event_mask = arg;  /*  Let the masses come forth  */
 	break;
       case DEVFSDIOC_RELEASE_EVENT_QUEUE:
@@ -3314,25 +3279,26 @@
 
 static int devfsd_close (struct inode *inode, struct file *file)
 {
+    unsigned long flags;
     struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
 
-    lock_kernel();
-    if (fs_info->devfsd_file != file)
-    {
-	unlock_kernel();
-	return 0;
-    }
+    if (fs_info->devfsd_file != file) return 0;
     fs_info->devfsd_event_mask = 0;
     fs_info->devfsd_file = NULL;
+    spin_lock_irqsave (&fs_info->devfsd_buffer_lock, flags);
     if (fs_info->devfsd_buffer)
     {
-	while (fs_info->devfsd_buffer_in_use) schedule ();
 	free_page ( (unsigned long) fs_info->devfsd_buffer );
+	fs_info->devfsd_buffer = NULL;
+    }
+    if (fs_info->devfsd_info)
+    {
+	kfree (fs_info->devfsd_info);
+	fs_info->devfsd_info = NULL;
     }
-    fs_info->devfsd_buffer = NULL;
+    spin_unlock_irqrestore (&fs_info->devfsd_buffer_lock, flags);
     fs_info->devfsd_task = NULL;
     wake_up (&fs_info->revalidate_wait_queue);
-    unlock_kernel();
     return 0;
 }   /*  End Function devfsd_close  */
 
@@ -3362,7 +3328,7 @@
 {
     int err;
 
-    if ( (boot_options & OPTION_NOMOUNT) ) return;
+    if ( !(boot_options & OPTION_MOUNT) ) return;
     err = do_mount ("none", "/dev", "devfs", 0, "");
     if (err == 0) printk ("Mounted devfs on /dev\n");
     else printk ("Warning: unable to mount devfs, err: %d\n", err);
diff -u --recursive --new-file v2.4.5/linux/fs/devfs/util.c linux/fs/devfs/util.c
--- v2.4.5/linux/fs/devfs/util.c	Mon Oct 16 12:58:51 2000
+++ linux/fs/devfs/util.c	Tue Jun 12 10:57:46 2001
@@ -1,6 +1,6 @@
 /*  devfs (Device FileSystem) utilities.
 
-    Copyright (C) 1999-2000  Richard Gooch
+    Copyright (C) 1999-2001  Richard Gooch
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -33,6 +33,8 @@
     20000622   Richard Gooch <rgooch@atnf.csiro.au>
                Took account of interface change to <devfs_mk_symlink>.
                Took account of interface change to <devfs_mk_dir>.
+    20010519   Richard Gooch <rgooch@atnf.csiro.au>
+               Documentation cleanup.
 */
 #include <linux/module.h>
 #include <linux/init.h>
@@ -132,9 +134,10 @@
 
 /**
  *	devfs_register_series - Register a sequence of device entries.
- *	@dir: The handle to the parent devfs directory entry. If this is %NULL the
- *		new names are relative to the root of the devfs.
+ *	@dir: The handle to the parent devfs directory entry. If this is %NULL
+ *		the new names are relative to the root of the devfs.
  *	@format: The printf-style format string. A single "\%u" is allowed.
+ *	@num_entries: The number of entries to register.
  *	@flags: A set of bitwise-ORed flags (DEVFS_FL_*).
  *	@major: The major number. Not needed for regular files.
  *	@minor_start: The starting minor number. Not needed for regular files.
@@ -142,9 +145,9 @@
  *	@ops: The &file_operations or &block_device_operations structure.
  *		This must not be externally deallocated.
  *	@info: An arbitrary pointer which will be written to the private_data
- *		field of the &file structure passed to the device driver. You can set
- *		this to whatever you like, and change it once the file is opened (the next
- *		file opened will not see this change).
+ *		field of the &file structure passed to the device driver. You
+ *		can set this to whatever you like, and change it once the file
+ *		is opened (the next file opened will not see this change).
  */
 
 void devfs_register_series (devfs_handle_t dir, const char *format,
diff -u --recursive --new-file v2.4.5/linux/fs/dquot.c linux/fs/dquot.c
--- v2.4.5/linux/fs/dquot.c	Sun May 20 11:32:11 2001
+++ linux/fs/dquot.c	Tue Jun 12 16:03:27 2001
@@ -325,7 +325,7 @@
         memset(&dquot->dq_dqb, 0, sizeof(struct dqblk));
 }
 
-void invalidate_dquots(kdev_t dev, short type)
+static void invalidate_dquots(kdev_t dev, short type)
 {
 	struct dquot *dquot, *next;
 	int need_restart;
@@ -651,8 +651,6 @@
 {
 	int cnt;
 
-        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)))
-                return 0;
 	if (is_quotafile(inode))
 		return 0;
 	if (type != -1)
@@ -1022,9 +1020,6 @@
 	unsigned int id = 0;
 	short cnt;
 
-	if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) &&
-            !S_ISLNK(inode->i_mode))
-		return;
 	lock_kernel();
 	/* We don't want to have quotas on quota files - nasty deadlocks possible */
 	if (is_quotafile(inode)) {
@@ -1388,7 +1383,7 @@
 }
 
 /* Function in inode.c - remove pointers to dquots in icache */
-extern void remove_dquot_ref(kdev_t, short);
+extern void remove_dquot_ref(struct super_block *, short);
 
 /*
  * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
@@ -1413,7 +1408,7 @@
 		reset_enable_flags(dqopt, cnt);
 
 		/* Note: these are blocking operations */
-		remove_dquot_ref(sb->s_dev, cnt);
+		remove_dquot_ref(sb, cnt);
 		invalidate_dquots(sb->s_dev, cnt);
 
 		/* Wait for any pending IO - remove me as soon as invalidate is more polite */
diff -u --recursive --new-file v2.4.5/linux/fs/ext2/dir.c linux/fs/ext2/dir.c
--- v2.4.5/linux/fs/ext2/dir.c	Fri Dec  8 17:35:54 2000
+++ linux/fs/ext2/dir.c	Wed Jun 20 11:40:14 2001
@@ -16,167 +16,567 @@
  *
  *  Big-endian to little-endian byte-swapping/bitmaps by
  *        David S. Miller (davem@caip.rutgers.edu), 1995
+ *
+ * All code that works with directory layout had been switched to pagecache
+ * and moved here. AV
  */
 
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
+#include <linux/pagemap.h>
 
-static unsigned char ext2_filetype_table[] = {
-	DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
-};
+typedef struct ext2_dir_entry_2 ext2_dirent;
 
-static int ext2_readdir(struct file *, void *, filldir_t);
+/*
+ * ext2 uses block-sized chunks. Arguably, sector-sized ones would be
+ * more robust, but we have what we have
+ */
+static inline unsigned ext2_chunk_size(struct inode *inode)
+{
+	return inode->i_sb->s_blocksize;
+}
 
-struct file_operations ext2_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	ext2_readdir,
-	ioctl:		ext2_ioctl,
-	fsync:		ext2_sync_file,
+static inline void ext2_put_page(struct page *page)
+{
+	kunmap(page);
+	page_cache_release(page);
+}
+
+static inline unsigned long dir_pages(struct inode *inode)
+{
+	return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
+}
+
+static int ext2_commit_chunk(struct page *page, unsigned from, unsigned to)
+{
+	struct inode *dir = page->mapping->host;
+	int err = 0;
+	dir->i_version = ++event;
+	page->mapping->a_ops->commit_write(NULL, page, from, to);
+	if (IS_SYNC(dir))
+		err = waitfor_one_page(page);
+	return err;
+}
+
+static void ext2_check_page(struct page *page)
+{
+	struct inode *dir = page->mapping->host;
+	struct super_block *sb = dir->i_sb;
+	unsigned chunk_size = ext2_chunk_size(dir);
+	char *kaddr = page_address(page);
+	u32 max_inumber = le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count);
+	unsigned offs, rec_len;
+	unsigned limit = PAGE_CACHE_SIZE;
+	ext2_dirent *p;
+	char *error;
+
+	if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) {
+		limit = dir->i_size & ~PAGE_CACHE_MASK;
+		if (limit & (chunk_size - 1))
+			goto Ebadsize;
+		for (offs = limit; offs<PAGE_CACHE_SIZE; offs += chunk_size) {
+			ext2_dirent *p = (ext2_dirent*)(kaddr + offs);
+			p->rec_len = cpu_to_le16(chunk_size);
+		}
+		if (!limit)
+			goto out;
+	}
+	for (offs = 0; offs <= limit - EXT2_DIR_REC_LEN(1); offs += rec_len) {
+		p = (ext2_dirent *)(kaddr + offs);
+		rec_len = le16_to_cpu(p->rec_len);
+
+		if (rec_len < EXT2_DIR_REC_LEN(1))
+			goto Eshort;
+		if (rec_len & 3)
+			goto Ealign;
+		if (rec_len < EXT2_DIR_REC_LEN(p->name_len))
+			goto Enamelen;
+		if (((offs + rec_len - 1) ^ offs) & ~(chunk_size-1))
+			goto Espan;
+		if (le32_to_cpu(p->inode) > max_inumber)
+			goto Einumber;
+	}
+	if (offs != limit)
+		goto Eend;
+out:
+	SetPageChecked(page);
+	return;
+
+	/* Too bad, we had an error */
+
+Ebadsize:
+	ext2_error(sb, "ext2_check_page",
+		"size of directory #%lu is not a multiple of chunk size",
+		dir->i_ino
+	);
+	goto fail;
+Eshort:
+	error = "rec_len is smaller than minimal";
+	goto bad_entry;
+Ealign:
+	error = "unaligned directory entry";
+	goto bad_entry;
+Enamelen:
+	error = "rec_len is too small for name_len";
+	goto bad_entry;
+Espan:
+	error = "directory entry across blocks";
+	goto bad_entry;
+Einumber:
+	error = "inode out of bounds";
+bad_entry:
+	ext2_error (sb, "ext2_check_page", "bad entry in directory #%lu: %s - "
+		"offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
+		dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
+		(unsigned long) le32_to_cpu(p->inode),
+		rec_len, p->name_len);
+	goto fail;
+Eend:
+	p = (ext2_dirent *)(kaddr + offs);
+	ext2_error (sb, "ext2_check_page",
+		"entry in directory #%lu spans the page boundary"
+		"offset=%lu, inode=%lu",
+		dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
+		(unsigned long) le32_to_cpu(p->inode));
+fail:
+	SetPageChecked(page);
+	SetPageError(page);
+}
+
+static struct page * ext2_get_page(struct inode *dir, unsigned long n)
+{
+	struct address_space *mapping = dir->i_mapping;
+	struct page *page = read_cache_page(mapping, n,
+				(filler_t*)mapping->a_ops->readpage, NULL);
+	if (!IS_ERR(page)) {
+		wait_on_page(page);
+		kmap(page);
+		if (!Page_Uptodate(page))
+			goto fail;
+		if (!PageChecked(page))
+			ext2_check_page(page);
+		if (PageError(page))
+			goto fail;
+	}
+	return page;
+
+fail:
+	ext2_put_page(page);
+	return ERR_PTR(-EIO);
+}
+
+/*
+ * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
+ *
+ * len <= EXT2_NAME_LEN and de != NULL are guaranteed by caller.
+ */
+static inline int ext2_match (int len, const char * const name,
+					struct ext2_dir_entry_2 * de)
+{
+	if (len != de->name_len)
+		return 0;
+	if (!de->inode)
+		return 0;
+	return !memcmp(name, de->name, len);
+}
+
+/*
+ * p is at least 6 bytes before the end of page
+ */
+static inline ext2_dirent *ext2_next_entry(ext2_dirent *p)
+{
+	return (ext2_dirent *)((char*)p + le16_to_cpu(p->rec_len));
+}
+
+static inline unsigned 
+ext2_validate_entry(char *base, unsigned offset, unsigned mask)
+{
+	ext2_dirent *de = (ext2_dirent*)(base + offset);
+	ext2_dirent *p = (ext2_dirent*)(base + (offset&mask));
+	while ((char*)p < (char*)de)
+		p = ext2_next_entry(p);
+	return (char *)p - base;
+}
+
+static unsigned char ext2_filetype_table[EXT2_FT_MAX] = {
+	[EXT2_FT_UNKNOWN]	DT_UNKNOWN,
+	[EXT2_FT_REG_FILE]	DT_REG,
+	[EXT2_FT_DIR]		DT_DIR,
+	[EXT2_FT_CHRDEV]	DT_CHR,
+	[EXT2_FT_BLKDEV]	DT_BLK,
+	[EXT2_FT_FIFO]		DT_FIFO,
+	[EXT2_FT_SOCK]		DT_SOCK,
+	[EXT2_FT_SYMLINK]	DT_LNK,
 };
 
-int ext2_check_dir_entry (const char * function, struct inode * dir,
-			  struct ext2_dir_entry_2 * de,
-			  struct buffer_head * bh,
-			  unsigned long offset)
-{
-	const char * error_msg = NULL;
-
-	if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(1))
-		error_msg = "rec_len is smaller than minimal";
-	else if (le16_to_cpu(de->rec_len) % 4 != 0)
-		error_msg = "rec_len % 4 != 0";
-	else if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(de->name_len))
-		error_msg = "rec_len is too small for name_len";
-	else if (dir && ((char *) de - bh->b_data) + le16_to_cpu(de->rec_len) >
-		 dir->i_sb->s_blocksize)
-		error_msg = "directory entry across blocks";
-	else if (dir && le32_to_cpu(de->inode) > le32_to_cpu(dir->i_sb->u.ext2_sb.s_es->s_inodes_count))
-		error_msg = "inode out of bounds";
-
-	if (error_msg != NULL)
-		ext2_error (dir->i_sb, function, "bad entry in directory #%lu: %s - "
-			    "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
-			    dir->i_ino, error_msg, offset,
-			    (unsigned long) le32_to_cpu(de->inode),
-			    le16_to_cpu(de->rec_len), de->name_len);
-	return error_msg == NULL ? 1 : 0;
-}
-
-static int ext2_readdir(struct file * filp,
-			 void * dirent, filldir_t filldir)
-{
-	int error = 0;
-	unsigned long offset, blk;
-	int i, num, stored;
-	struct buffer_head * bh, * tmp, * bha[16];
-	struct ext2_dir_entry_2 * de;
-	struct super_block * sb;
-	int err;
-	struct inode *inode = filp->f_dentry->d_inode;
+#define S_SHIFT 12
+static unsigned char ext2_type_by_mode[S_IFMT >> S_SHIFT] = {
+	[S_IFREG >> S_SHIFT]	EXT2_FT_REG_FILE,
+	[S_IFDIR >> S_SHIFT]	EXT2_FT_DIR,
+	[S_IFCHR >> S_SHIFT]	EXT2_FT_CHRDEV,
+	[S_IFBLK >> S_SHIFT]	EXT2_FT_BLKDEV,
+	[S_IFIFO >> S_SHIFT]	EXT2_FT_FIFO,
+	[S_IFSOCK >> S_SHIFT]	EXT2_FT_SOCK,
+	[S_IFLNK >> S_SHIFT]	EXT2_FT_SYMLINK,
+};
+
+static inline void ext2_set_de_type(ext2_dirent *de, struct inode *inode)
+{
+	mode_t mode = inode->i_mode;
+	if (EXT2_HAS_INCOMPAT_FEATURE(inode->i_sb, EXT2_FEATURE_INCOMPAT_FILETYPE))
+		de->file_type = ext2_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
+	else
+		de->file_type = 0;
+}
 
-	sb = inode->i_sb;
+static int
+ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
+{
+	loff_t pos = filp->f_pos;
+	struct inode *inode = filp->f_dentry->d_inode;
+	struct super_block *sb = inode->i_sb;
+	unsigned offset = pos & ~PAGE_CACHE_MASK;
+	unsigned long n = pos >> PAGE_CACHE_SHIFT;
+	unsigned long npages = dir_pages(inode);
+	unsigned chunk_mask = ~(ext2_chunk_size(inode)-1);
+	unsigned char *types = NULL;
+	int need_revalidate = (filp->f_version != inode->i_version);
+
+	if (pos > inode->i_size - EXT2_DIR_REC_LEN(1))
+		goto done;
+
+	if (EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE))
+		types = ext2_filetype_table;
+
+	for ( ; n < npages; n++, offset = 0) {
+		char *kaddr, *limit;
+		ext2_dirent *de;
+		struct page *page = ext2_get_page(inode, n);
 
-	stored = 0;
-	bh = NULL;
-	offset = filp->f_pos & (sb->s_blocksize - 1);
-
-	while (!error && !stored && filp->f_pos < inode->i_size) {
-		blk = (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb);
-		bh = ext2_bread (inode, blk, 0, &err);
-		if (!bh) {
-			ext2_error (sb, "ext2_readdir",
-				    "directory #%lu contains a hole at offset %lu",
-				    inode->i_ino, (unsigned long)filp->f_pos);
-			filp->f_pos += sb->s_blocksize - offset;
+		if (IS_ERR(page))
 			continue;
+		kaddr = page_address(page);
+		if (need_revalidate) {
+			offset = ext2_validate_entry(kaddr, offset, chunk_mask);
+			need_revalidate = 0;
 		}
+		de = (ext2_dirent *)(kaddr+offset);
+		limit = kaddr + PAGE_CACHE_SIZE - EXT2_DIR_REC_LEN(1);
+		for ( ;(char*)de <= limit; de = ext2_next_entry(de))
+			if (de->inode) {
+				int over;
+				unsigned char d_type = DT_UNKNOWN;
 
-		/*
-		 * Do the readahead
-		 */
-		if (!offset) {
-			for (i = 16 >> (EXT2_BLOCK_SIZE_BITS(sb) - 9), num = 0;
-			     i > 0; i--) {
-				tmp = ext2_getblk (inode, ++blk, 0, &err);
-				if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
-					bha[num++] = tmp;
-				else
-					brelse (tmp);
-			}
-			if (num) {
-				ll_rw_block (READA, num, bha);
-				for (i = 0; i < num; i++)
-					brelse (bha[i]);
-			}
-		}
-		
-revalidate:
-		/* If the dir block has changed since the last call to
-		 * readdir(2), then we might be pointing to an invalid
-		 * dirent right now.  Scan from the start of the block
-		 * to make sure. */
-		if (filp->f_version != inode->i_version) {
-			for (i = 0; i < sb->s_blocksize && i < offset; ) {
-				de = (struct ext2_dir_entry_2 *) 
-					(bh->b_data + i);
-				/* It's too expensive to do a full
-				 * dirent test each time round this
-				 * loop, but we do have to test at
-				 * least that it is non-zero.  A
-				 * failure will be detected in the
-				 * dirent test below. */
-				if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(1))
-					break;
-				i += le16_to_cpu(de->rec_len);
+				if (types && de->file_type < EXT2_FT_MAX)
+					d_type = types[de->file_type];
+
+				offset = (char *)de - kaddr;
+				over = filldir(dirent, de->name, de->name_len,
+						(n<<PAGE_CACHE_SHIFT) | offset,
+						le32_to_cpu(de->inode), d_type);
+				if (over) {
+					ext2_put_page(page);
+					goto done;
+				}
 			}
-			offset = i;
-			filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
-				| offset;
-			filp->f_version = inode->i_version;
+		ext2_put_page(page);
+	}
+
+done:
+	filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
+	filp->f_version = inode->i_version;
+	UPDATE_ATIME(inode);
+	return 0;
+}
+
+/*
+ *	ext2_find_entry()
+ *
+ * finds an entry in the specified directory with the wanted name. It
+ * returns the page in which the entry was found, and the entry itself
+ * (as a parameter - res_dir). Page is returned mapped and unlocked.
+ * Entry is guaranteed to be valid.
+ */
+struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir,
+			struct dentry *dentry, struct page ** res_page)
+{
+	const char *name = dentry->d_name.name;
+	int namelen = dentry->d_name.len;
+	unsigned reclen = EXT2_DIR_REC_LEN(namelen);
+	unsigned long n;
+	unsigned long npages = dir_pages(dir);
+	struct page *page = NULL;
+	ext2_dirent * de;
+
+	/* OFFSET_CACHE */
+	*res_page = NULL;
+
+	for (n = 0; n < npages; n++) {
+		char *kaddr;
+		page = ext2_get_page(dir, n);
+		if (IS_ERR(page))
+			continue;
+
+		kaddr = page_address(page);
+		de = (ext2_dirent *) kaddr;
+		kaddr += PAGE_CACHE_SIZE - reclen;
+		for ( ; (char *) de <= kaddr ; de = ext2_next_entry(de))
+			if (ext2_match (namelen, name, de))
+				goto found;
+		ext2_put_page(page);
+	}
+	return NULL;
+
+found:
+	*res_page = page;
+	return de;
+}
+
+struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p)
+{
+	struct page *page = ext2_get_page(dir, 0);
+	ext2_dirent *de = NULL;
+
+	if (!IS_ERR(page)) {
+		de = ext2_next_entry((ext2_dirent *) page_address(page));
+		*p = page;
+	}
+	return de;
+}
+
+ino_t ext2_inode_by_name(struct inode * dir, struct dentry *dentry)
+{
+	ino_t res = 0;
+	struct ext2_dir_entry_2 * de;
+	struct page *page;
+	
+	de = ext2_find_entry (dir, dentry, &page);
+	if (de) {
+		res = le32_to_cpu(de->inode);
+		kunmap(page);
+		page_cache_release(page);
+	}
+	return res;
+}
+
+/* Releases the page */
+void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
+			struct page *page, struct inode *inode)
+{
+	unsigned from = (char *)de-(char*)page_address(page);
+	unsigned to = from + le16_to_cpu(de->rec_len);
+	int err;
+
+	lock_page(page);
+	err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
+	if (err)
+		BUG();
+	de->inode = cpu_to_le32(inode->i_ino);
+	ext2_set_de_type (de, inode);
+	err = ext2_commit_chunk(page, from, to);
+	UnlockPage(page);
+	ext2_put_page(page);
+	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(dir);
+}
+
+/*
+ *	Parent is locked.
+ */
+int ext2_add_link (struct dentry *dentry, struct inode *inode)
+{
+	struct inode *dir = dentry->d_parent->d_inode;
+	const char *name = dentry->d_name.name;
+	int namelen = dentry->d_name.len;
+	unsigned reclen = EXT2_DIR_REC_LEN(namelen);
+	unsigned short rec_len, name_len;
+	struct page *page = NULL;
+	ext2_dirent * de;
+	unsigned long npages = dir_pages(dir);
+	unsigned long n;
+	char *kaddr;
+	unsigned from, to;
+	int err;
+
+	/* We take care of directory expansion in the same loop */
+	for (n = 0; n <= npages; n++) {
+		page = ext2_get_page(dir, n);
+		err = PTR_ERR(page);
+		if (IS_ERR(page))
+			goto out;
+		kaddr = page_address(page);
+		de = (ext2_dirent *)kaddr;
+		kaddr += PAGE_CACHE_SIZE - reclen;
+		while ((char *)de <= kaddr) {
+			err = -EEXIST;
+			if (ext2_match (namelen, name, de))
+				goto out_page;
+			name_len = EXT2_DIR_REC_LEN(de->name_len);
+			rec_len = le16_to_cpu(de->rec_len);
+			if (!de->inode && rec_len >= reclen)
+				goto got_it;
+			if (rec_len >= name_len + reclen)
+				goto got_it;
+			de = (ext2_dirent *) ((char *) de + rec_len);
 		}
-		
-		while (!error && filp->f_pos < inode->i_size 
-		       && offset < sb->s_blocksize) {
-			de = (struct ext2_dir_entry_2 *) (bh->b_data + offset);
-			if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
-						   bh, offset)) {
-				/* On error, skip the f_pos to the
-                                   next block. */
-				filp->f_pos = (filp->f_pos | (sb->s_blocksize - 1))
-					      + 1;
-				brelse (bh);
-				return stored;
-			}
-			offset += le16_to_cpu(de->rec_len);
-			if (le32_to_cpu(de->inode)) {
-				/* We might block in the next section
-				 * if the data destination is
-				 * currently swapped out.  So, use a
-				 * version stamp to detect whether or
-				 * not the directory has been modified
-				 * during the copy operation.
-				 */
-				unsigned long version = filp->f_version;
-				unsigned char d_type = DT_UNKNOWN;
+		ext2_put_page(page);
+	}
+	BUG();
+	return -EINVAL;
 
-				if (EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE)
-				    && de->file_type < EXT2_FT_MAX)
-					d_type = ext2_filetype_table[de->file_type];
-				error = filldir(dirent, de->name,
-						de->name_len,
-						filp->f_pos, le32_to_cpu(de->inode),
-						d_type);
-				if (error)
-					break;
-				if (version != filp->f_version)
-					goto revalidate;
-				stored ++;
+got_it:
+	from = (char*)de - (char*)page_address(page);
+	to = from + rec_len;
+	lock_page(page);
+	err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
+	if (err)
+		goto out_unlock;
+	if (de->inode) {
+		ext2_dirent *de1 = (ext2_dirent *) ((char *) de + name_len);
+		de1->rec_len = cpu_to_le16(rec_len - name_len);
+		de->rec_len = cpu_to_le16(name_len);
+		de = de1;
+	}
+	de->name_len = namelen;
+	memcpy (de->name, name, namelen);
+	de->inode = cpu_to_le32(inode->i_ino);
+	ext2_set_de_type (de, inode);
+	err = ext2_commit_chunk(page, from, to);
+	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(dir);
+	/* OFFSET_CACHE */
+out_unlock:
+	UnlockPage(page);
+out_page:
+	ext2_put_page(page);
+out:
+	return err;
+}
+
+/*
+ * ext2_delete_entry deletes a directory entry by merging it with the
+ * previous entry. Page is up-to-date. Releases the page.
+ */
+int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
+{
+	struct address_space *mapping = page->mapping;
+	struct inode *inode = mapping->host;
+	char *kaddr = page_address(page);
+	unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1);
+	unsigned to = ((char*)dir - kaddr) + le16_to_cpu(dir->rec_len);
+	ext2_dirent * pde = NULL;
+	ext2_dirent * de = (ext2_dirent *) (kaddr + from);
+	int err;
+
+	while ((char*)de < (char*)dir) {
+		pde = de;
+		de = ext2_next_entry(de);
+	}
+	if (pde)
+		from = (char*)pde - (char*)page_address(page);
+	lock_page(page);
+	err = mapping->a_ops->prepare_write(NULL, page, from, to);
+	if (err)
+		BUG();
+	if (pde)
+		pde->rec_len = cpu_to_le16(to-from);
+	dir->inode = 0;
+	err = ext2_commit_chunk(page, from, to);
+	UnlockPage(page);
+	ext2_put_page(page);
+	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+	mark_inode_dirty(inode);
+	return err;
+}
+
+/*
+ * Set the first fragment of directory.
+ */
+int ext2_make_empty(struct inode *inode, struct inode *parent)
+{
+	struct address_space *mapping = inode->i_mapping;
+	struct page *page = grab_cache_page(mapping, 0);
+	unsigned chunk_size = ext2_chunk_size(inode);
+	struct ext2_dir_entry_2 * de;
+	char *base;
+	int err;
+
+	if (!page)
+		return -ENOMEM;
+	err = mapping->a_ops->prepare_write(NULL, page, 0, chunk_size);
+	if (err)
+		goto fail;
+
+	base = page_address(page);
+
+	de = (struct ext2_dir_entry_2 *) base;
+	de->name_len = 1;
+	de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(1));
+	memcpy (de->name, ".\0\0", 4);
+	de->inode = cpu_to_le32(inode->i_ino);
+	ext2_set_de_type (de, inode);
+
+	de = (struct ext2_dir_entry_2 *) (base + EXT2_DIR_REC_LEN(1));
+	de->name_len = 2;
+	de->rec_len = cpu_to_le16(chunk_size - EXT2_DIR_REC_LEN(1));
+	de->inode = cpu_to_le32(parent->i_ino);
+	memcpy (de->name, "..\0", 4);
+	ext2_set_de_type (de, inode);
+
+	err = ext2_commit_chunk(page, 0, chunk_size);
+fail:
+	UnlockPage(page);
+	page_cache_release(page);
+	return err;
+}
+
+/*
+ * routine to check that the specified directory is empty (for rmdir)
+ */
+int ext2_empty_dir (struct inode * inode)
+{
+	struct page *page = NULL;
+	unsigned long i, npages = dir_pages(inode);
+	
+	for (i = 0; i < npages; i++) {
+		char *kaddr;
+		ext2_dirent * de;
+		page = ext2_get_page(inode, i);
+
+		if (IS_ERR(page))
+			continue;
+
+		kaddr = page_address(page);
+		de = (ext2_dirent *)kaddr;
+		kaddr += PAGE_CACHE_SIZE-EXT2_DIR_REC_LEN(1);
+
+		while ((char *)de <= kaddr) {
+			if (de->inode != 0) {
+				/* check for . and .. */
+				if (de->name[0] != '.')
+					goto not_empty;
+				if (de->name_len > 2)
+					goto not_empty;
+				if (de->name_len < 2) {
+					if (de->inode !=
+					    cpu_to_le32(inode->i_ino))
+						goto not_empty;
+				} else if (de->name[1] != '.')
+					goto not_empty;
 			}
-			filp->f_pos += le16_to_cpu(de->rec_len);
+			de = ext2_next_entry(de);
 		}
-		offset = 0;
-		brelse (bh);
+		ext2_put_page(page);
 	}
-	UPDATE_ATIME(inode);
+	return 1;
+
+not_empty:
+	ext2_put_page(page);
 	return 0;
 }
+
+struct file_operations ext2_dir_operations = {
+	read:		generic_read_dir,
+	readdir:	ext2_readdir,
+	fsync:		ext2_sync_file,
+};
diff -u --recursive --new-file v2.4.5/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c
--- v2.4.5/linux/fs/ext2/ialloc.c	Fri Mar 23 12:15:07 2001
+++ linux/fs/ext2/ialloc.c	Mon Jun 11 19:15:27 2001
@@ -199,10 +199,15 @@
 
 	lock_super (sb);
 	es = sb->u.ext2_sb.s_es;
-	if (ino < EXT2_FIRST_INO(sb) || 
+	is_directory = S_ISDIR(inode->i_mode);
+
+	/* Do this BEFORE marking the inode not in use or returning an error */
+	clear_inode (inode);
+
+	if (ino < EXT2_FIRST_INO(sb) ||
 	    ino > le32_to_cpu(es->s_inodes_count)) {
-		ext2_error (sb, "free_inode",
-			    "reserved inode or nonexistent inode");
+		ext2_error (sb, "ext2_free_inode",
+			    "reserved or nonexistent inode %lu", ino);
 		goto error_return;
 	}
 	block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb);
@@ -210,13 +215,8 @@
 	bitmap_nr = load_inode_bitmap (sb, block_group);
 	if (bitmap_nr < 0)
 		goto error_return;
-	
-	bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
 
-	is_directory = S_ISDIR(inode->i_mode);
-
-	/* Do this BEFORE marking the inode not in use */
-	clear_inode (inode);
+	bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
 
 	/* Ok, now we can actually update the inode bitmaps.. */
 	if (!ext2_clear_bit (bit, bh->b_data))
diff -u --recursive --new-file v2.4.5/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.4.5/linux/fs/ext2/inode.c	Thu Apr 26 10:44:10 2001
+++ linux/fs/ext2/inode.c	Mon Jun 11 19:15:27 2001
@@ -230,11 +230,11 @@
  *	or when it reads all @depth-1 indirect blocks successfully and finds
  *	the whole chain, all way to the data (returns %NULL, *err == 0).
  */
-static inline Indirect *ext2_get_branch(struct inode *inode,
-					int depth,
-					int *offsets,
-					Indirect chain[4],
-					int *err)
+static Indirect *ext2_get_branch(struct inode *inode,
+				 int depth,
+				 int *offsets,
+				 Indirect chain[4],
+				 int *err)
 {
 	kdev_t dev = inode->i_dev;
 	int size = inode->i_sb->s_blocksize;
@@ -574,82 +574,6 @@
 	goto reread;
 }
 
-struct buffer_head * ext2_getblk(struct inode * inode, long block, int create, int * err)
-{
-	struct buffer_head dummy;
-	int error;
-
-	dummy.b_state = 0;
-	dummy.b_blocknr = -1000;
-	error = ext2_get_block(inode, block, &dummy, create);
-	*err = error;
-	if (!error && buffer_mapped(&dummy)) {
-		struct buffer_head *bh;
-		bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
-		if (buffer_new(&dummy)) {
-			lock_buffer(bh);
-			memset(bh->b_data, 0, inode->i_sb->s_blocksize);
-			mark_buffer_uptodate(bh, 1);
-			unlock_buffer(bh);
-			mark_buffer_dirty_inode(bh, inode);
-		}
-		return bh;
-	}
-	return NULL;
-}
-
-struct buffer_head * ext2_bread (struct inode * inode, int block, 
-				 int create, int *err)
-{
-	struct buffer_head * bh;
-	int prev_blocks;
-	
-	prev_blocks = inode->i_blocks;
-	
-	bh = ext2_getblk (inode, block, create, err);
-	if (!bh)
-		return bh;
-	
-	/*
-	 * If the inode has grown, and this is a directory, then perform
-	 * preallocation of a few more blocks to try to keep directory
-	 * fragmentation down.
-	 */
-	if (create && 
-	    S_ISDIR(inode->i_mode) && 
-	    inode->i_blocks > prev_blocks &&
-	    EXT2_HAS_COMPAT_FEATURE(inode->i_sb,
-				    EXT2_FEATURE_COMPAT_DIR_PREALLOC)) {
-		int i;
-		struct buffer_head *tmp_bh;
-		
-		for (i = 1;
-		     i < EXT2_SB(inode->i_sb)->s_es->s_prealloc_dir_blocks;
-		     i++) {
-			/* 
-			 * ext2_getblk will zero out the contents of the
-			 * directory for us
-			 */
-			tmp_bh = ext2_getblk(inode, block+i, create, err);
-			if (!tmp_bh) {
-				brelse (bh);
-				return 0;
-			}
-			brelse (tmp_bh);
-		}
-	}
-	
-	if (buffer_uptodate(bh))
-		return bh;
-	ll_rw_block (READ, 1, &bh);
-	wait_on_buffer (bh);
-	if (buffer_uptodate(bh))
-		return bh;
-	brelse (bh);
-	*err = -EIO;
-	return NULL;
-}
-
 static int ext2_writepage(struct page *page)
 {
 	return block_write_full_page(page,ext2_get_block);
@@ -1067,6 +991,7 @@
 	} else if (S_ISDIR(inode->i_mode)) {
 		inode->i_op = &ext2_dir_inode_operations;
 		inode->i_fop = &ext2_dir_operations;
+		inode->i_mapping->a_ops = &ext2_aops;
 	} else if (S_ISLNK(inode->i_mode)) {
 		if (!inode->i_blocks)
 			inode->i_op = &ext2_fast_symlink_inode_operations;
diff -u --recursive --new-file v2.4.5/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.4.5/linux/fs/ext2/namei.c	Thu Feb 15 12:32:21 2001
+++ linux/fs/ext2/namei.c	Mon Jun 11 19:15:27 2001
@@ -1,5 +1,18 @@
 /*
- *  linux/fs/ext2/namei.c
+ * linux/fs/ext2/namei.c
+ *
+ * Rewrite to pagecache. Almost all code had been changed, so blame me
+ * if the things go wrong. Please, send bug reports to viro@math.psu.edu
+ *
+ * Stuff here is basically a glue between the VFS and generic UNIXish
+ * filesystem that keeps everything in pagecache. All knowledge of the
+ * directory layout is in fs/ext2/dir.c - it turned out to be easily separatable
+ * and it's easier to debug that way. In principle we might want to
+ * generalize that a bit and turn it into a library. Or not.
+ *
+ * The only non-static object here is ext2_dir_inode_operations.
+ *
+ * TODO: get rid of kmap() use, add readahead.
  *
  * Copyright (C) 1992, 1993, 1994, 1995
  * Remy Card (card@masi.ibp.fr)
@@ -14,344 +27,63 @@
  *
  *  Big-endian to little-endian byte-swapping/bitmaps by
  *        David S. Miller (davem@caip.rutgers.edu), 1995
- *  Directory entry file type support and forward compatibility hooks
- *  	for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998
  */
 
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
-#include <linux/locks.h>
-#include <linux/quotaops.h>
-
-
+#include <linux/pagemap.h>
 
 /*
- * define how far ahead to read directories while searching them.
+ * Couple of helper functions - make the code slightly cleaner.
  */
-#define NAMEI_RA_CHUNKS  2
-#define NAMEI_RA_BLOCKS  4
-#define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
-#define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))
 
-/*
- * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
- *
- * `len <= EXT2_NAME_LEN' is guaranteed by caller.
- * `de != NULL' is guaranteed by caller.
- */
-static inline int ext2_match (int len, const char * const name,
-		       struct ext2_dir_entry_2 * de)
+static inline void ext2_inc_count(struct inode *inode)
 {
-	if (len != de->name_len)
-		return 0;
-	if (!de->inode)
-		return 0;
-	return !memcmp(name, de->name, len);
+	inode->i_nlink++;
+	mark_inode_dirty(inode);
 }
 
-/*
- *	ext2_find_entry()
- *
- * finds an entry in the specified directory with the wanted name. It
- * returns the cache buffer in which the entry was found, and the entry
- * itself (as a parameter - res_dir). It does NOT read the inode of the
- * entry - you'll have to do that yourself if you want to.
- */
-static struct buffer_head * ext2_find_entry (struct inode * dir,
-					     const char * const name, int namelen,
-					     struct ext2_dir_entry_2 ** res_dir)
-{
-	struct super_block * sb;
-	struct buffer_head * bh_use[NAMEI_RA_SIZE];
-	struct buffer_head * bh_read[NAMEI_RA_SIZE];
-	unsigned long offset;
-	int block, toread, i, err;
-
-	*res_dir = NULL;
-	sb = dir->i_sb;
-
-	if (namelen > EXT2_NAME_LEN)
-		return NULL;
-
-	memset (bh_use, 0, sizeof (bh_use));
-	toread = 0;
-	for (block = 0; block < NAMEI_RA_SIZE; ++block) {
-		struct buffer_head * bh;
-
-		if ((block << EXT2_BLOCK_SIZE_BITS (sb)) >= dir->i_size)
-			break;
-		bh = ext2_getblk (dir, block, 0, &err);
-		bh_use[block] = bh;
-		if (bh && !buffer_uptodate(bh))
-			bh_read[toread++] = bh;
-	}
-
-	for (block = 0, offset = 0; offset < dir->i_size; block++) {
-		struct buffer_head * bh;
-		struct ext2_dir_entry_2 * de;
-		char * dlimit;
-
-		if ((block % NAMEI_RA_BLOCKS) == 0 && toread) {
-			ll_rw_block (READ, toread, bh_read);
-			toread = 0;
-		}
-		bh = bh_use[block % NAMEI_RA_SIZE];
-		if (!bh) {
-#if 0
-			ext2_error (sb, "ext2_find_entry",
-				    "directory #%lu contains a hole at offset %lu",
-				    dir->i_ino, offset);
-#endif
-			offset += sb->s_blocksize;
-			continue;
-		}
-		wait_on_buffer (bh);
-		if (!buffer_uptodate(bh)) {
-			/*
-			 * read error: all bets are off
-			 */
-			break;
-		}
-
-		de = (struct ext2_dir_entry_2 *) bh->b_data;
-		dlimit = bh->b_data + sb->s_blocksize;
-		while ((char *) de < dlimit) {
-			/* this code is executed quadratically often */
-			/* do minimal checking `by hand' */
-			int de_len;
-
-			if ((char *) de + namelen <= dlimit &&
-			    ext2_match (namelen, name, de)) {
-				/* found a match -
-				   just to be sure, do a full check */
-				if (!ext2_check_dir_entry("ext2_find_entry",
-							  dir, de, bh, offset))
-					goto failure;
-				for (i = 0; i < NAMEI_RA_SIZE; ++i) {
-					if (bh_use[i] != bh)
-						brelse (bh_use[i]);
-				}
-				*res_dir = de;
-				return bh;
-			}
-			/* prevent looping on a bad block */
-			de_len = le16_to_cpu(de->rec_len);
-			if (de_len <= 0)
-				goto failure;
-			offset += de_len;
-			de = (struct ext2_dir_entry_2 *)
-				((char *) de + de_len);
-		}
+static inline void ext2_dec_count(struct inode *inode)
+{
+	inode->i_nlink--;
+	mark_inode_dirty(inode);
+}
 
-		brelse (bh);
-		if (((block + NAMEI_RA_SIZE) << EXT2_BLOCK_SIZE_BITS (sb)) >=
-		    dir->i_size)
-			bh = NULL;
-		else
-			bh = ext2_getblk (dir, block + NAMEI_RA_SIZE, 0, &err);
-		bh_use[block % NAMEI_RA_SIZE] = bh;
-		if (bh && !buffer_uptodate(bh))
-			bh_read[toread++] = bh;
+static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
+{
+	int err = ext2_add_link(dentry, inode);
+	if (!err) {
+		d_instantiate(dentry, inode);
+		return 0;
 	}
-
-failure:
-	for (i = 0; i < NAMEI_RA_SIZE; ++i)
-		brelse (bh_use[i]);
-	return NULL;
+	ext2_dec_count(inode);
+	iput(inode);
+	return err;
 }
 
+/*
+ * Methods themselves.
+ */
+
 static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry)
 {
 	struct inode * inode;
-	struct ext2_dir_entry_2 * de;
-	struct buffer_head * bh;
-
+	ino_t ino;
+	
 	if (dentry->d_name.len > EXT2_NAME_LEN)
 		return ERR_PTR(-ENAMETOOLONG);
 
-	bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+	ino = ext2_inode_by_name(dir, dentry);
 	inode = NULL;
-	if (bh) {
-		unsigned long ino = le32_to_cpu(de->inode);
-		brelse (bh);
+	if (ino) {
 		inode = iget(dir->i_sb, ino);
-
-		if (!inode)
+		if (!inode) 
 			return ERR_PTR(-EACCES);
 	}
 	d_add(dentry, inode);
 	return NULL;
 }
 
-#define S_SHIFT 12
-static unsigned char ext2_type_by_mode[S_IFMT >> S_SHIFT] = {
-	[S_IFREG >> S_SHIFT]	EXT2_FT_REG_FILE,
-	[S_IFDIR >> S_SHIFT]	EXT2_FT_DIR,
-	[S_IFCHR >> S_SHIFT]	EXT2_FT_CHRDEV,
-	[S_IFBLK >> S_SHIFT]	EXT2_FT_BLKDEV,
-	[S_IFIFO >> S_SHIFT]	EXT2_FT_FIFO,
-	[S_IFSOCK >> S_SHIFT]	EXT2_FT_SOCK,
-	[S_IFLNK >> S_SHIFT]	EXT2_FT_SYMLINK,
-};
-
-static inline void ext2_set_de_type(struct super_block *sb,
-				struct ext2_dir_entry_2 *de,
-				umode_t mode) {
-	if (EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE))
-		de->file_type = ext2_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
-}
-
-/*
- *	ext2_add_entry()
- *
- * adds a file entry to the specified directory.
- */
-int ext2_add_entry (struct inode * dir, const char * name, int namelen,
-		    struct inode *inode)
-{
-	unsigned long offset;
-	unsigned short rec_len;
-	struct buffer_head * bh;
-	struct ext2_dir_entry_2 * de, * de1;
-	struct super_block * sb;
-	int	retval;
-
-	sb = dir->i_sb;
-
-	if (!namelen)
-		return -EINVAL;
-	bh = ext2_bread (dir, 0, 0, &retval);
-	if (!bh)
-		return retval;
-	rec_len = EXT2_DIR_REC_LEN(namelen);
-	offset = 0;
-	de = (struct ext2_dir_entry_2 *) bh->b_data;
-	while (1) {
-		if ((char *)de >= sb->s_blocksize + bh->b_data) {
-			brelse (bh);
-			bh = NULL;
-			bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, &retval);
-			if (!bh)
-				return retval;
-			if (dir->i_size <= offset) {
-				if (dir->i_size == 0) {
-					brelse(bh);
-					return -ENOENT;
-				}
-
-				ext2_debug ("creating next block\n");
-
-				de = (struct ext2_dir_entry_2 *) bh->b_data;
-				de->inode = 0;
-				de->rec_len = le16_to_cpu(sb->s_blocksize);
-				dir->i_size = offset + sb->s_blocksize;
-				dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
-				mark_inode_dirty(dir);
-			} else {
-
-				ext2_debug ("skipping to next block\n");
-
-				de = (struct ext2_dir_entry_2 *) bh->b_data;
-			}
-		}
-		if (!ext2_check_dir_entry ("ext2_add_entry", dir, de, bh,
-					   offset)) {
-			brelse (bh);
-			return -ENOENT;
-		}
-		if (ext2_match (namelen, name, de)) {
-				brelse (bh);
-				return -EEXIST;
-		}
-		if ((le32_to_cpu(de->inode) == 0 && le16_to_cpu(de->rec_len) >= rec_len) ||
-		    (le16_to_cpu(de->rec_len) >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) {
-			offset += le16_to_cpu(de->rec_len);
-			if (le32_to_cpu(de->inode)) {
-				de1 = (struct ext2_dir_entry_2 *) ((char *) de +
-					EXT2_DIR_REC_LEN(de->name_len));
-				de1->rec_len = cpu_to_le16(le16_to_cpu(de->rec_len) -
-					EXT2_DIR_REC_LEN(de->name_len));
-				de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
-				de = de1;
-			}
-			de->file_type = EXT2_FT_UNKNOWN;
-			if (inode) {
-				de->inode = cpu_to_le32(inode->i_ino);
-				ext2_set_de_type(dir->i_sb, de, inode->i_mode);
-			} else
-				de->inode = 0;
-			de->name_len = namelen;
-			memcpy (de->name, name, namelen);
-			/*
-			 * XXX shouldn't update any times until successful
-			 * completion of syscall, but too many callers depend
-			 * on this.
-			 *
-			 * XXX similarly, too many callers depend on
-			 * ext2_new_inode() setting the times, but error
-			 * recovery deletes the inode, so the worst that can
-			 * happen is that the times are slightly out of date
-			 * and/or different from the directory change time.
-			 */
-			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-			dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
-			mark_inode_dirty(dir);
-			dir->i_version = ++event;
-			mark_buffer_dirty_inode(bh, dir);
-			if (IS_SYNC(dir)) {
-				ll_rw_block (WRITE, 1, &bh);
-				wait_on_buffer (bh);
-			}
-			brelse(bh);
-			return 0;
-		}
-		offset += le16_to_cpu(de->rec_len);
-		de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
-	}
-	brelse (bh);
-	return -ENOSPC;
-}
-
-/*
- * ext2_delete_entry deletes a directory entry by merging it with the
- * previous entry
- */
-static int ext2_delete_entry (struct inode * dir,
-			      struct ext2_dir_entry_2 * de_del,
-			      struct buffer_head * bh)
-{
-	struct ext2_dir_entry_2 * de, * pde;
-	int i;
-
-	i = 0;
-	pde = NULL;
-	de = (struct ext2_dir_entry_2 *) bh->b_data;
-	while (i < bh->b_size) {
-		if (!ext2_check_dir_entry ("ext2_delete_entry", NULL, 
-					   de, bh, i))
-			return -EIO;
-		if (de == de_del)  {
-			if (pde)
-				pde->rec_len =
-					cpu_to_le16(le16_to_cpu(pde->rec_len) +
-						    le16_to_cpu(de->rec_len));
-			else
-				de->inode = 0;
-			dir->i_version = ++event;
-			mark_buffer_dirty_inode(bh, dir);
-			if (IS_SYNC(dir)) {
-				ll_rw_block (WRITE, 1, &bh);
-				wait_on_buffer (bh);
-			}
-			return 0;
-		}
-		i += le16_to_cpu(de->rec_len);
-		pde = de;
-		de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
-	}
-	return -ENOENT;
-}
-
 /*
  * By the time this is called, we already have created
  * the directory cache entry for the new file, but it
@@ -364,454 +96,245 @@
 {
 	struct inode * inode = ext2_new_inode (dir, mode);
 	int err = PTR_ERR(inode);
-	if (IS_ERR(inode))
-		return err;
-
-	inode->i_op = &ext2_file_inode_operations;
-	inode->i_fop = &ext2_file_operations;
-	inode->i_mapping->a_ops = &ext2_aops;
-	inode->i_mode = mode;
-	mark_inode_dirty(inode);
-	err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, 
-			     inode);
-	if (err) {
-		inode->i_nlink--;
+	if (!IS_ERR(inode)) {
+		inode->i_op = &ext2_file_inode_operations;
+		inode->i_fop = &ext2_file_operations;
+		inode->i_mapping->a_ops = &ext2_aops;
 		mark_inode_dirty(inode);
-		iput (inode);
-		return err;
+		err = ext2_add_nondir(dentry, inode);
 	}
-	d_instantiate(dentry, inode);
-	return 0;
+	return err;
 }
 
 static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
 {
 	struct inode * inode = ext2_new_inode (dir, mode);
 	int err = PTR_ERR(inode);
-
-	if (IS_ERR(inode))
-		return err;
-
-	inode->i_uid = current->fsuid;
-	init_special_inode(inode, mode, rdev);
-	err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, 
-			     inode);
-	if (err)
-		goto out_no_entry;
-	mark_inode_dirty(inode);
-	d_instantiate(dentry, inode);
-	return 0;
-
-out_no_entry:
-	inode->i_nlink--;
-	mark_inode_dirty(inode);
-	iput(inode);
+	if (!IS_ERR(inode)) {
+		init_special_inode(inode, mode, rdev);
+		mark_inode_dirty(inode);
+		err = ext2_add_nondir(dentry, inode);
+	}
 	return err;
 }
 
-static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+static int ext2_symlink (struct inode * dir, struct dentry * dentry,
+	const char * symname)
 {
+	struct super_block * sb = dir->i_sb;
+	int err = -ENAMETOOLONG;
+	unsigned l = strlen(symname)+1;
 	struct inode * inode;
-	struct buffer_head * dir_block;
-	struct ext2_dir_entry_2 * de;
-	int err;
 
-	if (dir->i_nlink >= EXT2_LINK_MAX)
-		return -EMLINK;
+	if (l > sb->s_blocksize)
+		goto out;
 
-	inode = ext2_new_inode (dir, S_IFDIR);
+	inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO);
 	err = PTR_ERR(inode);
 	if (IS_ERR(inode))
-		return err;
+		goto out;
 
-	inode->i_op = &ext2_dir_inode_operations;
-	inode->i_fop = &ext2_dir_operations;
-	inode->i_size = inode->i_sb->s_blocksize;
-	inode->i_blocks = 0;	
-	dir_block = ext2_bread (inode, 0, 1, &err);
-	if (!dir_block) {
-		inode->i_nlink--; /* is this nlink == 0? */
-		mark_inode_dirty(inode);
-		iput (inode);
-		return err;
+	if (l > sizeof (inode->u.ext2_i.i_data)) {
+		/* slow symlink */
+		inode->i_op = &page_symlink_inode_operations;
+		inode->i_mapping->a_ops = &ext2_aops;
+		err = block_symlink(inode, symname, l);
+		if (err)
+			goto out_fail;
+	} else {
+		/* fast symlink */
+		inode->i_op = &ext2_fast_symlink_inode_operations;
+		memcpy((char*)&inode->u.ext2_i.i_data,symname,l);
+		inode->i_size = l-1;
 	}
-	de = (struct ext2_dir_entry_2 *) dir_block->b_data;
-	de->inode = cpu_to_le32(inode->i_ino);
-	de->name_len = 1;
-	de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
-	strcpy (de->name, ".");
-	ext2_set_de_type(dir->i_sb, de, S_IFDIR);
-	de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
-	de->inode = cpu_to_le32(dir->i_ino);
-	de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize - EXT2_DIR_REC_LEN(1));
-	de->name_len = 2;
-	strcpy (de->name, "..");
-	ext2_set_de_type(dir->i_sb, de, S_IFDIR);
-	inode->i_nlink = 2;
-	mark_buffer_dirty_inode(dir_block, dir);
-	brelse (dir_block);
-	inode->i_mode = S_IFDIR | mode;
-	if (dir->i_mode & S_ISGID)
-		inode->i_mode |= S_ISGID;
 	mark_inode_dirty(inode);
-	err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, 
-			     inode);
-	if (err)
-		goto out_no_entry;
-	dir->i_nlink++;
-	dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
-	mark_inode_dirty(dir);
-	d_instantiate(dentry, inode);
-	return 0;
 
-out_no_entry:
-	inode->i_nlink = 0;
-	mark_inode_dirty(inode);
-	iput (inode);
+	err = ext2_add_nondir(dentry, inode);
+out:
 	return err;
-}
 
-/*
- * routine to check that the specified directory is empty (for rmdir)
- */
-static int empty_dir (struct inode * inode)
-{
-	unsigned long offset;
-	struct buffer_head * bh;
-	struct ext2_dir_entry_2 * de, * de1;
-	struct super_block * sb;
-	int err;
-
-	sb = inode->i_sb;
-	if (inode->i_size < EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) ||
-	    !(bh = ext2_bread (inode, 0, 0, &err))) {
-	    	ext2_warning (inode->i_sb, "empty_dir",
-			      "bad directory (dir #%lu) - no data block",
-			      inode->i_ino);
-		return 1;
-	}
-	de = (struct ext2_dir_entry_2 *) bh->b_data;
-	de1 = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
-	if (le32_to_cpu(de->inode) != inode->i_ino || !le32_to_cpu(de1->inode) || 
-	    strcmp (".", de->name) || strcmp ("..", de1->name)) {
-	    	ext2_warning (inode->i_sb, "empty_dir",
-			      "bad directory (dir #%lu) - no `.' or `..'",
-			      inode->i_ino);
-		brelse (bh);
-		return 1;
-	}
-	offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);
-	de = (struct ext2_dir_entry_2 *) ((char *) de1 + le16_to_cpu(de1->rec_len));
-	while (offset < inode->i_size ) {
-		if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
-			brelse (bh);
-			bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 0, &err);
-			if (!bh) {
-#if 0
-				ext2_error (sb, "empty_dir",
-					    "directory #%lu contains a hole at offset %lu",
-					    inode->i_ino, offset);
-#endif
-				offset += sb->s_blocksize;
-				continue;
-			}
-			de = (struct ext2_dir_entry_2 *) bh->b_data;
-		}
-		if (!ext2_check_dir_entry ("empty_dir", inode, de, bh,
-					   offset)) {
-			brelse (bh);
-			return 1;
-		}
-		if (le32_to_cpu(de->inode)) {
-			brelse (bh);
-			return 0;
-		}
-		offset += le16_to_cpu(de->rec_len);
-		de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
-	}
-	brelse (bh);
-	return 1;
+out_fail:
+	ext2_dec_count(inode);
+	iput (inode);
+	goto out;
 }
 
-static int ext2_rmdir (struct inode * dir, struct dentry *dentry)
+static int ext2_link (struct dentry * old_dentry, struct inode * dir,
+	struct dentry *dentry)
 {
-	int retval;
-	struct inode * inode;
-	struct buffer_head * bh;
-	struct ext2_dir_entry_2 * de;
+	struct inode *inode = old_dentry->d_inode;
 
-	retval = -ENOENT;
-	bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
-	if (!bh)
-		goto end_rmdir;
-
-	inode = dentry->d_inode;
-	DQUOT_INIT(inode);
-
-	retval = -EIO;
-	if (le32_to_cpu(de->inode) != inode->i_ino)
-		goto end_rmdir;
-
-	retval = -ENOTEMPTY;
-	if (!empty_dir (inode))
-		goto end_rmdir;
-
-	retval = ext2_delete_entry(dir, de, bh);
-	if (retval)
-		goto end_rmdir;
-	if (inode->i_nlink != 2)
-		ext2_warning (inode->i_sb, "ext2_rmdir",
-			      "empty directory has nlink!=2 (%d)",
-			      inode->i_nlink);
-	inode->i_version = ++event;
-	inode->i_nlink = 0;
-	inode->i_size = 0;
-	mark_inode_dirty(inode);
-	dir->i_nlink--;
-	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
-	mark_inode_dirty(dir);
-
-end_rmdir:
-	brelse (bh);
-	return retval;
-}
+	if (S_ISDIR(inode->i_mode))
+		return -EPERM;
 
-static int ext2_unlink(struct inode * dir, struct dentry *dentry)
-{
-	int retval;
-	struct inode * inode;
-	struct buffer_head * bh;
-	struct ext2_dir_entry_2 * de;
+	if (inode->i_nlink >= EXT2_LINK_MAX)
+		return -EMLINK;
 
-	retval = -ENOENT;
-	bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
-	if (!bh)
-		goto end_unlink;
-
-	inode = dentry->d_inode;
-	DQUOT_INIT(inode);
-
-	retval = -EIO;
-	if (le32_to_cpu(de->inode) != inode->i_ino)
-		goto end_unlink;
-	
-	if (!inode->i_nlink) {
-		ext2_warning (inode->i_sb, "ext2_unlink",
-			      "Deleting nonexistent file (%lu), %d",
-			      inode->i_ino, inode->i_nlink);
-		inode->i_nlink = 1;
-	}
-	retval = ext2_delete_entry(dir, de, bh);
-	if (retval)
-		goto end_unlink;
-	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
-	mark_inode_dirty(dir);
-	inode->i_nlink--;
-	mark_inode_dirty(inode);
-	inode->i_ctime = dir->i_ctime;
-	retval = 0;
+	inode->i_ctime = CURRENT_TIME;
+	ext2_inc_count(inode);
+	atomic_inc(&inode->i_count);
 
-end_unlink:
-	brelse (bh);
-	return retval;
+	return ext2_add_nondir(dentry, inode);
 }
 
-static int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symname)
+static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
 {
 	struct inode * inode;
-	int l, err;
+	int err = -EMLINK;
 
-	l = strlen(symname)+1;
-	if (l > dir->i_sb->s_blocksize)
-		return -ENAMETOOLONG;
+	if (dir->i_nlink >= EXT2_LINK_MAX)
+		goto out;
+
+	ext2_inc_count(dir);
 
-	inode = ext2_new_inode (dir, S_IFLNK);
+	inode = ext2_new_inode (dir, S_IFDIR | mode);
 	err = PTR_ERR(inode);
 	if (IS_ERR(inode))
-		return err;
+		goto out_dir;
 
-	inode->i_mode = S_IFLNK | S_IRWXUGO;
+	inode->i_op = &ext2_dir_inode_operations;
+	inode->i_fop = &ext2_dir_operations;
+	inode->i_mapping->a_ops = &ext2_aops;
 
-	if (l > sizeof (inode->u.ext2_i.i_data)) {
-		inode->i_op = &page_symlink_inode_operations;
-		inode->i_mapping->a_ops = &ext2_aops;
-		err = block_symlink(inode, symname, l);
-		if (err)
-			goto out_no_entry;
-	} else {
-		inode->i_op = &ext2_fast_symlink_inode_operations;
-		memcpy((char*)&inode->u.ext2_i.i_data,symname,l);
-		inode->i_size = l-1;
-	}
-	mark_inode_dirty(inode);
+	ext2_inc_count(inode);
 
-	err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, 
-			     inode);
+	err = ext2_make_empty(inode, dir);
 	if (err)
-		goto out_no_entry;
-	d_instantiate(dentry, inode);
-	return 0;
+		goto out_fail;
 
-out_no_entry:
-	inode->i_nlink--;
-	mark_inode_dirty(inode);
-	iput (inode);
+	err = ext2_add_link(dentry, inode);
+	if (err)
+		goto out_fail;
+
+	d_instantiate(dentry, inode);
+out:
 	return err;
+
+out_fail:
+	ext2_dec_count(inode);
+	ext2_dec_count(inode);
+	iput(inode);
+out_dir:
+	ext2_dec_count(dir);
+	goto out;
 }
 
-static int ext2_link (struct dentry * old_dentry,
-		struct inode * dir, struct dentry *dentry)
+static int ext2_unlink(struct inode * dir, struct dentry *dentry)
 {
-	struct inode *inode = old_dentry->d_inode;
-	int err;
+	struct inode * inode = dentry->d_inode;
+	struct ext2_dir_entry_2 * de;
+	struct page * page;
+	int err = -ENOENT;
 
-	if (S_ISDIR(inode->i_mode))
-		return -EPERM;
+	de = ext2_find_entry (dir, dentry, &page);
+	if (!de)
+		goto out;
 
-	if (inode->i_nlink >= EXT2_LINK_MAX)
-		return -EMLINK;
-	
-	err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, 
-			     inode);
+	err = ext2_delete_entry (de, page);
 	if (err)
-		return err;
+		goto out;
 
-	inode->i_nlink++;
-	inode->i_ctime = CURRENT_TIME;
-	mark_inode_dirty(inode);
-	atomic_inc(&inode->i_count);
-	d_instantiate(dentry, inode);
-	return 0;
+	inode->i_ctime = dir->i_ctime;
+	ext2_dec_count(inode);
+	err = 0;
+out:
+	return err;
 }
 
-#define PARENT_INO(buffer) \
-	((struct ext2_dir_entry_2 *) ((char *) buffer + \
-	le16_to_cpu(((struct ext2_dir_entry_2 *) buffer)->rec_len)))->inode
-
-/*
- * Anybody can rename anything with this: the permission checks are left to the
- * higher-level routines.
- */
-static int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
-			   struct inode * new_dir,struct dentry *new_dentry)
+static int ext2_rmdir (struct inode * dir, struct dentry *dentry)
 {
-	struct inode * old_inode, * new_inode;
-	struct buffer_head * old_bh, * new_bh, * dir_bh;
-	struct ext2_dir_entry_2 * old_de, * new_de;
-	int retval;
-
-	old_bh = new_bh = dir_bh = NULL;
-
-	old_bh = ext2_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
-	/*
-	 *  Check for inode number is _not_ due to possible IO errors.
-	 *  We might rmdir the source, keep it as pwd of some process
-	 *  and merrily kill the link to whatever was created under the
-	 *  same name. Goodbye sticky bit ;-<
-	 */
-	old_inode = old_dentry->d_inode;
-	retval = -ENOENT;
-	if (!old_bh || le32_to_cpu(old_de->inode) != old_inode->i_ino)
-		goto end_rename;
-
-	new_inode = new_dentry->d_inode;
-	new_bh = ext2_find_entry (new_dir, new_dentry->d_name.name,
-				new_dentry->d_name.len, &new_de);
-	if (new_bh) {
-		if (!new_inode) {
-			brelse (new_bh);
-			new_bh = NULL;
-		} else {
-			DQUOT_INIT(new_inode);
+	struct inode * inode = dentry->d_inode;
+	int err = -ENOTEMPTY;
+
+	if (ext2_empty_dir(inode)) {
+		err = ext2_unlink(dir, dentry);
+		if (!err) {
+			inode->i_size = 0;
+			ext2_dec_count(inode);
+			ext2_dec_count(dir);
 		}
 	}
+	return err;
+}
+
+static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
+	struct inode * new_dir,	struct dentry * new_dentry )
+{
+	struct inode * old_inode = old_dentry->d_inode;
+	struct inode * new_inode = new_dentry->d_inode;
+	struct page * dir_page = NULL;
+	struct ext2_dir_entry_2 * dir_de = NULL;
+	struct page * old_page;
+	struct ext2_dir_entry_2 * old_de;
+	int err = -ENOENT;
+
+	old_de = ext2_find_entry (old_dir, old_dentry, &old_page);
+	if (!old_de)
+		goto out;
+
 	if (S_ISDIR(old_inode->i_mode)) {
-		if (new_inode) {
-			retval = -ENOTEMPTY;
-			if (!empty_dir (new_inode))
-				goto end_rename;
-		}
-		retval = -EIO;
-		dir_bh = ext2_bread (old_inode, 0, 0, &retval);
-		if (!dir_bh)
-			goto end_rename;
-		if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)
-			goto end_rename;
-		retval = -EMLINK;
-		if (!new_inode && new_dir!=old_dir &&
-				new_dir->i_nlink >= EXT2_LINK_MAX)
-			goto end_rename;
+		err = -EIO;
+		dir_de = ext2_dotdot(old_inode, &dir_page);
+		if (!dir_de)
+			goto out_old;
 	}
-	if (!new_bh) {
-		retval = ext2_add_entry (new_dir, new_dentry->d_name.name,
-					 new_dentry->d_name.len,
-					 old_inode);
-		if (retval)
-			goto end_rename;
-	} else {
-		new_de->inode = le32_to_cpu(old_inode->i_ino);
-		if (EXT2_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
-					      EXT2_FEATURE_INCOMPAT_FILETYPE))
-			new_de->file_type = old_de->file_type;
-		new_dir->i_version = ++event;
-		mark_buffer_dirty_inode(new_bh, new_dir);
-		if (IS_SYNC(new_dir)) {
-			ll_rw_block (WRITE, 1, &new_bh);
-			wait_on_buffer (new_bh);
-		}
-		brelse(new_bh);
-		new_bh = NULL;
-	}
-	
-	/*
-	 * Like most other Unix systems, set the ctime for inodes on a
-	 * rename.
-	 */
-	old_inode->i_ctime = CURRENT_TIME;
-	mark_inode_dirty(old_inode);
-
-	/*
-	 * ok, that's it
-	 */
-	ext2_delete_entry(old_dir, old_de, old_bh);
 
 	if (new_inode) {
-		new_inode->i_nlink--;
+		struct page *new_page;
+		struct ext2_dir_entry_2 *new_de;
+
+		err = -ENOTEMPTY;
+		if (dir_de && !ext2_empty_dir (new_inode))
+			goto out_dir;
+
+		err = -ENOENT;
+		new_de = ext2_find_entry (new_dir, new_dentry, &new_page);
+		if (!new_de)
+			goto out_dir;
+		ext2_inc_count(old_inode);
+		ext2_set_link(new_dir, new_de, new_page, old_inode);
 		new_inode->i_ctime = CURRENT_TIME;
-		mark_inode_dirty(new_inode);
-	}
-	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
-	old_dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
-	mark_inode_dirty(old_dir);
-	if (dir_bh) {
-		PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);
-		mark_buffer_dirty_inode(dir_bh, old_inode);
-		old_dir->i_nlink--;
-		mark_inode_dirty(old_dir);
-		if (new_inode) {
+		if (dir_de)
 			new_inode->i_nlink--;
-			mark_inode_dirty(new_inode);
-		} else {
-			new_dir->i_nlink++;
-			new_dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
-			mark_inode_dirty(new_dir);
-		}
+		ext2_dec_count(new_inode);
+	} else {
+		if (dir_de) {
+			err = -EMLINK;
+			if (new_dir->i_nlink >= EXT2_LINK_MAX)
+				goto out_dir;
+		}
+		ext2_inc_count(old_inode);
+		err = ext2_add_link(new_dentry, old_inode);
+		if (err) {
+			ext2_dec_count(old_inode);
+			goto out_dir;
+		}
+		if (dir_de)
+			ext2_inc_count(new_dir);
+	}
+
+	ext2_delete_entry (old_de, old_page);
+	ext2_dec_count(old_inode);
+
+	if (dir_de) {
+		ext2_set_link(old_inode, dir_de, dir_page, new_dir);
+		ext2_dec_count(old_dir);
 	}
+	return 0;
 
-	retval = 0;
 
-end_rename:
-	brelse (dir_bh);
-	brelse (old_bh);
-	brelse (new_bh);
-	return retval;
+out_dir:
+	if (dir_de) {
+		kunmap(dir_page);
+		page_cache_release(dir_page);
+	}
+out_old:
+	kunmap(old_page);
+	page_cache_release(old_page);
+out:
+	return err;
 }
 
-/*
- * directories can handle most operations...
- */
 struct inode_operations ext2_dir_inode_operations = {
 	create:		ext2_create,
 	lookup:		ext2_lookup,
diff -u --recursive --new-file v2.4.5/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.4.5/linux/fs/fat/inode.c	Thu May 24 15:36:34 2001
+++ linux/fs/fat/inode.c	Mon Jun 11 19:15:27 2001
@@ -28,6 +28,7 @@
 #include <linux/locks.h>
 #include <linux/fat_cvf.h>
 #include <linux/slab.h>
+#include <linux/bitops.h>
 #include <linux/smp_lock.h>
 
 #include "msbuffer.h"
diff -u --recursive --new-file v2.4.5/linux/fs/hpfs/anode.c linux/fs/hpfs/anode.c
--- v2.4.5/linux/fs/hpfs/anode.c	Tue Sep  5 14:07:29 2000
+++ linux/fs/hpfs/anode.c	Mon Jun 11 19:15:27 2001
@@ -161,6 +161,7 @@
 	if ((a == node && fnod) || na == -1) return se;
 	c2 = 0;
 	while (up != -1) {
+		struct anode *new_anode;
 		if (s->s_hpfs_chk)
 			if (hpfs_stop_cycles(s, up, &c1, &c2, "hpfs_add_sector_to_btree #2")) return -1;
 		if (up != node || !fnod) {
@@ -194,7 +195,8 @@
 		mark_buffer_dirty(bh);
 		brelse(bh);
 		a = na;
-		if ((anode = hpfs_alloc_anode(s, a, &na, &bh))) {
+		if ((new_anode = hpfs_alloc_anode(s, a, &na, &bh))) {
+			anode = new_anode;
 			/*anode->up = up != -1 ? up : ra;*/
 			anode->btree.internal = 1;
 			anode->btree.n_used_nodes = 1;
@@ -282,7 +284,7 @@
 		if (s->s_hpfs_chk)
 			if (hpfs_stop_cycles(s, ano, &d1, &d2, "hpfs_remove_btree #1"))
 				return;
-		anode = hpfs_map_anode(s, ano, &bh);
+		if (!(anode = hpfs_map_anode(s, ano, &bh))) return;
 		btree1 = &anode->btree;
 		level++;
 		pos = 0;
@@ -291,14 +293,14 @@
 		hpfs_free_sectors(s, btree1->u.external[i].disk_secno, btree1->u.external[i].length);
 	go_up:
 	if (!level) return;
+	brelse(bh);
 	if (s->s_hpfs_chk)
 		if (hpfs_stop_cycles(s, ano, &c1, &c2, "hpfs_remove_btree #2")) return;
-	brelse(bh);
 	hpfs_free_sectors(s, ano, 1);
 	oano = ano;
 	ano = anode->up;
 	if (--level) {
-		anode = hpfs_map_anode(s, ano, &bh);
+		if (!(anode = hpfs_map_anode(s, ano, &bh))) return;
 		btree1 = &anode->btree;
 	} else btree1 = btree;
 	for (i = 0; i < btree1->n_used_nodes; i++) {
diff -u --recursive --new-file v2.4.5/linux/fs/hpfs/dir.c linux/fs/hpfs/dir.c
--- v2.4.5/linux/fs/hpfs/dir.c	Fri Aug 11 14:29:01 2000
+++ linux/fs/hpfs/dir.c	Mon Jun 11 19:15:27 2001
@@ -212,7 +212,7 @@
 	hpfs_lock_iget(dir->i_sb, de->directory || (de->ea_size && dir->i_sb->s_hpfs_eas) ? 1 : 2);
 	if (!(result = iget(dir->i_sb, ino))) {
 		hpfs_unlock_iget(dir->i_sb);
-		hpfs_error(result->i_sb, "hpfs_lookup: can't get inode");
+		hpfs_error(dir->i_sb, "hpfs_lookup: can't get inode");
 		goto bail1;
 	}
 	if (!de->directory) result->i_hpfs_parent_dir = dir->i_ino;
diff -u --recursive --new-file v2.4.5/linux/fs/hpfs/super.c linux/fs/hpfs/super.c
--- v2.4.5/linux/fs/hpfs/super.c	Tue Apr 17 23:16:39 2001
+++ linux/fs/hpfs/super.c	Mon Jun 11 19:15:27 2001
@@ -212,6 +212,8 @@
 				return 0;
 		}
 		else if (!strcmp(p, "case")) {
+			if (!rhs || !*rhs)
+				return 0;
 			if (!strcmp(rhs, "lower"))
 				*lowercase = 1;
 			else if (!strcmp(rhs, "asis"))
@@ -220,6 +222,8 @@
 				return 0;
 		}
 		else if (!strcmp(p, "conv")) {
+			if (!rhs || !*rhs)
+				return 0;
 			if (!strcmp(rhs, "binary"))
 				*conv = CONV_BINARY;
 			else if (!strcmp(rhs, "text"))
@@ -230,6 +234,8 @@
 				return 0;
 		}
 		else if (!strcmp(p, "check")) {
+			if (!rhs || !*rhs)
+				return 0;
 			if (!strcmp(rhs, "none"))
 				*chk = 0;
 			else if (!strcmp(rhs, "normal"))
@@ -240,6 +246,8 @@
 				return 0;
 		}
 		else if (!strcmp(p, "errors")) {
+			if (!rhs || !*rhs)
+				return 0;
 			if (!strcmp(rhs, "continue"))
 				*errs = 0;
 			else if (!strcmp(rhs, "remount-ro"))
@@ -250,6 +258,8 @@
 				return 0;
 		}
 		else if (!strcmp(p, "eas")) {
+			if (!rhs || !*rhs)
+				return 0;
 			if (!strcmp(rhs, "no"))
 				*eas = 0;
 			else if (!strcmp(rhs, "ro"))
@@ -260,6 +270,8 @@
 				return 0;
 		}
 		else if (!strcmp(p, "chkdsk")) {
+			if (!rhs || !*rhs)
+				return 0;
 			if (!strcmp(rhs, "no"))
 				*chkdsk = 0;
 			else if (!strcmp(rhs, "errors"))
diff -u --recursive --new-file v2.4.5/linux/fs/inode.c linux/fs/inode.c
--- v2.4.5/linux/fs/inode.c	Tue May 22 09:35:42 2001
+++ linux/fs/inode.c	Tue Jun 12 11:02:44 2001
@@ -1044,6 +1044,8 @@
 				inode->i_state|=I_FREEING;
 				inodes_stat.nr_inodes--;
 				spin_unlock(&inode_lock);
+				if (inode->i_data.nrpages)
+					truncate_inode_pages(&inode->i_data, 0);
 				clear_inode(inode);
 			}
 		}
@@ -1162,14 +1164,13 @@
 void put_dquot_list(struct list_head *);
 int remove_inode_dquot_ref(struct inode *, short, struct list_head *);
 
-void remove_dquot_ref(kdev_t dev, short type)
+void remove_dquot_ref(struct super_block *sb, short type)
 {
-	struct super_block *sb = get_super(dev);
 	struct inode *inode;
 	struct list_head *act_head;
 	LIST_HEAD(tofree_head);
 
-	if (!sb || !sb->dq_op)
+	if (!sb->dq_op)
 		return;	/* nothing to do */
 
 	/* We have to be protected against other CPUs */
diff -u --recursive --new-file v2.4.5/linux/fs/lockd/mon.c linux/fs/lockd/mon.c
--- v2.4.5/linux/fs/lockd/mon.c	Mon Oct 16 12:58:51 2000
+++ linux/fs/lockd/mon.c	Mon Jun 11 19:15:27 2001
@@ -146,7 +146,7 @@
 	u32	addr = ntohl(argp->addr);
 
 	dprintk("nsm: xdr_encode_mon(%08x, %d, %d, %d)\n",
-			htonl(argp->addr), htonl(argp->proc),
+			htonl(argp->addr), htonl(argp->prog),
 			htonl(argp->vers), htonl(argp->proc));
 
 	/*
diff -u --recursive --new-file v2.4.5/linux/fs/locks.c linux/fs/locks.c
--- v2.4.5/linux/fs/locks.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/locks.c	Sat Jun 16 10:42:53 2001
@@ -857,7 +857,7 @@
 	new_fl2 = locks_alloc_lock(0);
 	error = -ENOLCK; /* "no luck" */
 	if (!(new_fl && new_fl2))
-		goto out;
+		goto out_nolock;
 
 	lock_kernel();
 	if (caller->fl_type != F_UNLCK) {
@@ -1005,6 +1005,7 @@
 	}
 out:
 	unlock_kernel();
+out_nolock:
 	/*
 	 * Free any unused locks.
 	 */
diff -u --recursive --new-file v2.4.5/linux/fs/minix/itree_common.c linux/fs/minix/itree_common.c
--- v2.4.5/linux/fs/minix/itree_common.c	Sun Apr  8 12:30:59 2001
+++ linux/fs/minix/itree_common.c	Wed Jun 20 11:10:27 2001
@@ -80,13 +80,13 @@
 			break;
 		branch[n].key = cpu_to_block(nr);
 		bh = getblk(inode->i_dev, parent, BLOCK_SIZE);
-		if (!buffer_uptodate(bh))
-			wait_on_buffer(bh);
+		lock_buffer(bh);
 		memset(bh->b_data, 0, BLOCK_SIZE);
 		branch[n].bh = bh;
 		branch[n].p = (block_t*) bh->b_data + offsets[n];
 		*branch[n].p = branch[n].key;
 		mark_buffer_uptodate(bh, 1);
+		unlock_buffer(bh);
 		mark_buffer_dirty(bh);
 		parent = nr;
 	}
diff -u --recursive --new-file v2.4.5/linux/fs/namei.c linux/fs/namei.c
--- v2.4.5/linux/fs/namei.c	Sat May 19 18:02:45 2001
+++ linux/fs/namei.c	Tue Jun 12 11:09:28 2001
@@ -15,21 +15,15 @@
  */
 
 #include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
 #include <linux/quotaops.h>
 #include <linux/pagemap.h>
-#include <linux/dcache.h>
 #include <linux/dnotify.h>
-
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
-#include <asm/semaphore.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
+#include <linux/smp_lock.h>
 
 #include <asm/namei.h>
+#include <asm/uaccess.h>
 
 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
 
@@ -351,22 +345,17 @@
 
 static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry)
 {
-	struct list_head *p;
+	struct vfsmount *mounted;
+
 	spin_lock(&dcache_lock);
-	p = (*dentry)->d_vfsmnt.next;
-	while (p != &(*dentry)->d_vfsmnt) {
-		struct vfsmount *tmp;
-		tmp = list_entry(p, struct vfsmount, mnt_clash);
-		if (tmp->mnt_parent == *mnt) {
-			*mnt = mntget(tmp);
-			spin_unlock(&dcache_lock);
-			mntput(tmp->mnt_parent);
-			/* tmp holds the mountpoint, so... */
-			dput(*dentry);
-			*dentry = dget(tmp->mnt_root);
-			return 1;
-		}
-		p = p->next;
+	mounted = lookup_mnt(*mnt, *dentry);
+	if (mounted) {
+		*mnt = mntget(mounted);
+		spin_unlock(&dcache_lock);
+		dput(*dentry);
+		mntput(mounted->mnt_parent);
+		*dentry = dget(mounted->mnt_root);
+		return 1;
 	}
 	spin_unlock(&dcache_lock);
 	return 0;
diff -u --recursive --new-file v2.4.5/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.4.5/linux/fs/nfs/dir.c	Sat May 19 18:02:45 2001
+++ linux/fs/nfs/dir.c	Tue Jun 12 11:15:08 2001
@@ -73,7 +73,7 @@
 	struct file	*file;
 	struct page	*page;
 	unsigned long	page_index;
-	unsigned	page_offset;
+	u32		*ptr;
 	u64		target;
 	struct nfs_entry *entry;
 	decode_dirent_t	decode;
@@ -100,18 +100,17 @@
 	struct inode	*inode = file->f_dentry->d_inode;
 	struct rpc_cred	*cred = nfs_file_cred(file);
 	void		*buffer = kmap(page);
-	int		plus = NFS_USE_READDIRPLUS(inode);
 	int		error;
 
 	dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index);
 
  again:
 	error = NFS_PROTO(inode)->readdir(inode, cred, desc->entry->cookie, buffer,
-					  NFS_SERVER(inode)->dtsize, plus);
+					  NFS_SERVER(inode)->dtsize, desc->plus);
 	/* We requested READDIRPLUS, but the server doesn't grok it */
 	if (desc->plus && error == -ENOTSUPP) {
 		NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
-		plus = 0;
+		desc->plus = 0;
 		goto again;
 	}
 	if (error < 0)
@@ -135,6 +134,26 @@
 	return -EIO;
 }
 
+static inline
+int dir_decode(nfs_readdir_descriptor_t *desc)
+{
+	u32	*p = desc->ptr;
+	p = desc->decode(p, desc->entry, desc->plus);
+	if (IS_ERR(p))
+		return PTR_ERR(p);
+	desc->ptr = p;
+	return 0;
+}
+
+static inline
+void dir_page_release(nfs_readdir_descriptor_t *desc)
+{
+	kunmap(desc->page);
+	page_cache_release(desc->page);
+	desc->page = NULL;
+	desc->ptr = NULL;
+}
+
 /*
  * Given a pointer to a buffer that has already been filled by a call
  * to readdir, find the next entry.
@@ -147,18 +166,10 @@
 int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page)
 {
 	struct nfs_entry *entry = desc->entry;
-	char		*start = kmap(page),
-			*p = start;
 	int		loop_count = 0,
-			status = 0;
+			status;
 
-	for(;;) {
-		p = (char *)desc->decode((u32*)p, entry, desc->plus);
-		if (IS_ERR(p)) {
-			status = PTR_ERR(p);
-			break;
-		}
-		desc->page_offset = p - start;
+	while((status = dir_decode(desc)) == 0) {
 		dfprintk(VFS, "NFS: found cookie %Lu\n", (long long)entry->cookie);
 		if (entry->prev_cookie == desc->target)
 			break;
@@ -167,7 +178,6 @@
 			schedule();
 		}
 	}
-	kunmap(page);
 	dfprintk(VFS, "NFS: find_dirent() returns %d\n", status);
 	return status;
 }
@@ -181,17 +191,12 @@
 {
 	struct inode	*inode = desc->file->f_dentry->d_inode;
 	struct page	*page;
-	unsigned long	index = desc->page_index;
 	int		status;
 
 	dfprintk(VFS, "NFS: find_dirent_page() searching directory page %ld\n", desc->page_index);
 
-	if (desc->page) {
-		page_cache_release(desc->page);
-		desc->page = NULL;
-	}
-
-	page = read_cache_page(&inode->i_data, index,
+	desc->plus = NFS_USE_READDIRPLUS(inode);
+	page = read_cache_page(&inode->i_data, desc->page_index,
 			       (filler_t *)nfs_readdir_filler, desc);
 	if (IS_ERR(page)) {
 		status = PTR_ERR(page);
@@ -201,12 +206,11 @@
 		goto read_error;
 
 	/* NOTE: Someone else may have changed the READDIRPLUS flag */
-	desc->plus = NFS_USE_READDIRPLUS(inode);
+	desc->page = page;
+	desc->ptr = kmap(page);
 	status = find_dirent(desc, page);
-	if (status >= 0)
-		desc->page = page;
-	else
-		page_cache_release(page);
+	if (status < 0)
+		dir_page_release(desc);
  out:
 	dfprintk(VFS, "NFS: find_dirent_page() returns %d\n", status);
 	return status;
@@ -224,8 +228,8 @@
 static inline
 int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)
 {
-	int		res = 0;
 	int		loop_count = 0;
+	int		res;
 
 	dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (long long)desc->target);
 	for (;;) {
@@ -233,7 +237,6 @@
 		if (res != -EAGAIN)
 			break;
 		/* Align to beginning of next page */
-		desc->page_offset = 0;
 		desc->page_index ++;
 		if (loop_count++ > 200) {
 			loop_count = 0;
@@ -253,11 +256,9 @@
 {
 	struct file	*file = desc->file;
 	struct nfs_entry *entry = desc->entry;
-	char		*start = kmap(desc->page),
-			*p = start + desc->page_offset;
 	unsigned long	fileid;
 	int		loop_count = 0,
-			res = 0;
+			res;
 
 	dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)desc->target);
 
@@ -270,23 +271,16 @@
 		if (res < 0)
 			break;
 		file->f_pos = desc->target = entry->cookie;
-		p = (char *)desc->decode((u32 *)p, entry, desc->plus);
-		if (IS_ERR(p)) {
-			if (PTR_ERR(p) == -EAGAIN) {
-				desc->page_offset = 0;
-				desc->page_index ++;
-			}
+		if (dir_decode(desc) != 0) {
+			desc->page_index ++;
 			break;
 		}
-		desc->page_offset = p - start;
 		if (loop_count++ > 200) {
 			loop_count = 0;
 			schedule();
 		}
 	}
-	kunmap(desc->page);
-	page_cache_release(desc->page);
-	desc->page = NULL;
+	dir_page_release(desc);
 
 	dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (long long)desc->target, res);
 	return res;
@@ -312,49 +306,40 @@
 	struct inode	*inode = file->f_dentry->d_inode;
 	struct rpc_cred	*cred = nfs_file_cred(file);
 	struct page	*page = NULL;
-	u32		*p;
-	int		status = -EIO;
+	int		status;
 
 	dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (long long)desc->target);
-	if (desc->page) {
-		page_cache_release(desc->page);
-		desc->page = NULL;
-	}
 
 	page = alloc_page(GFP_HIGHUSER);
 	if (!page) {
 		status = -ENOMEM;
 		goto out;
 	}
-	p = kmap(page);
-	status = NFS_PROTO(inode)->readdir(inode, cred, desc->target, p,
-					   NFS_SERVER(inode)->dtsize, 0);
-	if (status >= 0) {
-		p = desc->decode(p, desc->entry, 0);
-		if (IS_ERR(p))
-			status = PTR_ERR(p);
-		else
+	desc->page = page;
+	desc->ptr = kmap(page);
+	desc->error = NFS_PROTO(inode)->readdir(inode, cred, desc->target,
+						desc->ptr,
+						NFS_SERVER(inode)->dtsize,
+						desc->plus);
+	if (desc->error >= 0) {
+		if ((status = dir_decode(desc)) == 0)
 			desc->entry->prev_cookie = desc->target;
-	}
-	kunmap(page);
+	} else
+		status = -EIO;
 	if (status < 0)
 		goto out_release;
 
-	desc->page_index = 0;
-	desc->page_offset = 0;
-	desc->page = page;
 	status = nfs_do_filldir(desc, dirent, filldir);
 
 	/* Reset read descriptor so it searches the page cache from
 	 * the start upon the next call to readdir_search_pagecache() */
 	desc->page_index = 0;
-	desc->page_offset = 0;
 	memset(desc->entry, 0, sizeof(*desc->entry));
  out:
 	dfprintk(VFS, "NFS: uncached_readdir() returns %d\n", status);
 	return status;
  out_release:
-	page_cache_release(page);
+	dir_page_release(desc);
 	goto out;
 }
 
@@ -392,16 +377,15 @@
 		res = readdir_search_pagecache(desc);
 		if (res == -EBADCOOKIE) {
 			/* This means either end of directory */
-			if (desc->entry->cookie == desc->target) {
-				res = 0;
-				break;
+			if (desc->entry->cookie != desc->target) {
+				/* Or that the server has 'lost' a cookie */
+				res = uncached_readdir(desc, dirent, filldir);
+				if (res >= 0)
+					continue;
 			}
-			/* Or that the server has 'lost' a cookie */
-			res = uncached_readdir(desc, dirent, filldir);
-			if (res >= 0)
-				continue;
-		}
-		if (res < 0)
+			res = 0;
+			break;
+		} else if (res < 0)
 			break;
 
 		res = nfs_do_filldir(desc, dirent, filldir);
@@ -410,8 +394,6 @@
 			break;
 		}
 	}
-	if (desc->page)
-		page_cache_release(desc->page);
 	if (desc->error < 0)
 		return desc->error;
 	if (res < 0)
@@ -753,6 +735,8 @@
 
 	nfs_zap_caches(dir);
 	error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
+	if (!error)
+		dentry->d_inode->i_nlink = 0;
 
 	return error;
 }
@@ -870,6 +854,8 @@
 	error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
 	if (error < 0)
 		goto out;
+	if (inode)
+		inode->i_nlink--;
 
  out_delete:
 	/*
diff -u --recursive --new-file v2.4.5/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.4.5/linux/fs/nfs/inode.c	Sat May 19 18:14:38 2001
+++ linux/fs/nfs/inode.c	Tue Jun 12 11:16:41 2001
@@ -100,6 +100,8 @@
 	inode->i_blksize = inode->i_sb->s_blocksize;
 	inode->i_mode = 0;
 	inode->i_rdev = 0;
+	/* We can't support UPDATE_ATIME(), since the server will reset it */
+	inode->i_flags |= S_NOATIME;
 	NFS_FILEID(inode) = 0;
 	NFS_FSID(inode) = 0;
 	NFS_FLAGS(inode) = 0;
@@ -973,12 +975,9 @@
 
 	NFS_CACHE_CTIME(inode) = fattr->ctime;
 	inode->i_ctime = nfs_time_to_secs(fattr->ctime);
-	/* If we've been messing around with atime, don't
-	 * update it. Save the server value in NFS_CACHE_ATIME.
-	 */
+
 	NFS_CACHE_ATIME(inode) = fattr->atime;
-	if (time_before(inode->i_atime, nfs_time_to_secs(fattr->atime)))
-		inode->i_atime = nfs_time_to_secs(fattr->atime);
+	inode->i_atime = nfs_time_to_secs(fattr->atime);
 
 	NFS_CACHE_MTIME(inode) = new_mtime;
 	inode->i_mtime = nfs_time_to_secs(new_mtime);
diff -u --recursive --new-file v2.4.5/linux/fs/nfsd/export.c linux/fs/nfsd/export.c
--- v2.4.5/linux/fs/nfsd/export.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/nfsd/export.c	Tue Jun 12 11:12:47 2001
@@ -213,7 +213,8 @@
 
 	err = -EINVAL;
 	if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) ||
-	    inode->i_sb->s_op->read_inode == NULL) {
+	    (inode->i_sb->s_op->read_inode == NULL
+	     && inode->i_sb->s_op->fh_to_dentry == NULL)) {
 		dprintk("exp_export: export of invalid fs type.\n");
 		goto finish;
 	}
diff -u --recursive --new-file v2.4.5/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c
--- v2.4.5/linux/fs/nfsd/nfsfh.c	Sat May 19 17:47:55 2001
+++ linux/fs/nfsd/nfsfh.c	Tue Jun 12 11:12:47 2001
@@ -134,7 +134,11 @@
 	struct inode *inode;
 	struct list_head *lp;
 	struct dentry *result;
+	if (ino == 0)
+		return ERR_PTR(-ESTALE);
 	inode = iget(sb, ino);
+	if (inode == NULL)
+		return ERR_PTR(-ENOMEM);
 	if (is_bad_inode(inode)
 	    || (generation && inode->i_generation != generation)
 		) {
@@ -169,10 +173,34 @@
 		return ERR_PTR(-ENOMEM);
 	}
 	result->d_flags |= DCACHE_NFSD_DISCONNECTED;
-	d_rehash(result); /* so a dput won't loose it */
 	return result;
 }
 
+static struct dentry *nfsd_get_dentry(struct super_block *sb, __u32 *fh,
+					     int len, int fhtype, int parent)
+{
+	if (sb->s_op->fh_to_dentry)
+		return sb->s_op->fh_to_dentry(sb, fh, len, fhtype, parent);
+	switch (fhtype) {
+	case 1:
+		if (len < 2)
+			break;
+		if (parent)
+			break;
+		return nfsd_iget(sb, fh[0], fh[1]);
+
+	case 2:
+		if (len < 3)
+			break;
+		if (parent)
+			return nfsd_iget(sb,fh[2],0);
+		return nfsd_iget(sb,fh[0],fh[1]);
+	default: break;
+	}
+	return ERR_PTR(-EINVAL);
+}
+
+
 /* this routine links an IS_ROOT dentry into the dcache tree.  It gains "parent"
  * as a parent and "name" as a name
  * It should possibly go in dcache.c
@@ -196,7 +224,7 @@
 	 * make it an IS_ROOT instead
 	 */
 	spin_lock(&dcache_lock);
-	list_del(&tdentry->d_child);
+	list_del_init(&tdentry->d_child);
 	tdentry->d_parent = tdentry;
 	spin_unlock(&dcache_lock);
 	d_rehash(target);
@@ -270,10 +298,10 @@
 		}
 		spin_unlock(&dcache_lock);
 		if (pdentry == NULL) {
-			pdentry = d_alloc_root(igrab(tdentry->d_inode));
+			pdentry = d_alloc_root(tdentry->d_inode);
 			if (pdentry) {
+				igrab(tdentry->d_inode);
 				pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED;
-				d_rehash(pdentry);
 			}
 		}
 		if (pdentry == NULL)
@@ -347,11 +375,10 @@
  * connection if made.
  */
 static struct dentry *
-find_fh_dentry(struct super_block *sb, ino_t ino, int generation, ino_t dirino, int needpath)
+find_fh_dentry(struct super_block *sb, __u32 *datap, int len, int fhtype, int needpath)
 {
 	struct dentry *dentry, *result = NULL;
 	struct dentry *tmp;
-	int  found =0;
 	int err = -ESTALE;
 	/* the sb->s_nfsd_free_path_sem semaphore is needed to make sure that only one unconnected (free)
 	 * dcache path ever exists, as otherwise two partial paths might get
@@ -367,7 +394,7 @@
 	 */
  retry:
 	down(&sb->s_nfsd_free_path_sem);
-	result = nfsd_iget(sb, ino, generation);
+	result = nfsd_get_dentry(sb, datap, len, fhtype, 0);
 	if (IS_ERR(result)
 	    || !(result->d_flags & DCACHE_NFSD_DISCONNECTED)
 	    || (!S_ISDIR(result->d_inode->i_mode) && ! needpath)) {
@@ -384,16 +411,12 @@
 	/* It's a directory, or we are required to confirm the file's
 	 * location in the tree.
 	 */
-	dprintk("nfs_fh: need to look harder for %d/%ld\n",sb->s_dev,ino);
+	dprintk("nfs_fh: need to look harder for %d/%d\n",sb->s_dev,datap[0]);
 
-	found = 0;
 	if (!S_ISDIR(result->d_inode->i_mode)) {
 		nfsdstats.fh_nocache_nondir++;
-		if (dirino == 0)
-			goto err_result; /* don't know how to find parent */
-		else {
 			/* need to iget dirino and make sure this inode is in that directory */
-			dentry = nfsd_iget(sb, dirino, 0);
+			dentry = nfsd_get_dentry(sb, datap, len, fhtype, 1);
 			err = PTR_ERR(dentry);
 			if (IS_ERR(dentry))
 				goto err_result;
@@ -402,8 +425,6 @@
 			    || !S_ISDIR(dentry->d_inode->i_mode)) {
 				goto err_dentry;
 			}
-			if (!(dentry->d_flags & DCACHE_NFSD_DISCONNECTED))
-				found = 1;
 			tmp = splice(result, dentry);
 			err = PTR_ERR(tmp);
 			if (IS_ERR(tmp))
@@ -413,15 +434,13 @@
 				d_drop(result);
 				dput(result);
 				result = tmp;
-				/* If !found, then this is really weird, but it shouldn't hurt */
 			}
-		}
 	} else {
 		nfsdstats.fh_nocache_dir++;
 		dentry = dget(result);
 	}
 
-	while(!found) {
+	while(dentry->d_flags & DCACHE_NFSD_DISCONNECTED) {
 		/* LOOP INVARIANT */
 		/* haven't found a place in the tree yet, but we do have a free path
 		 * from dentry down to result, and dentry is a directory.
@@ -440,12 +459,9 @@
 			goto err_dentry;
 		}
 
-		if (!(dentry->d_flags & DCACHE_NFSD_DISCONNECTED))
-			found = 1;
-
 		tmp = splice(dentry, pdentry);
 		if (tmp != dentry) {
-			/* Something wrong.  We need to drop thw whole dentry->result path
+			/* Something wrong.  We need to drop the whole dentry->result path
 			 * whatever it was
 			 */
 			struct dentry *d;
@@ -580,31 +596,23 @@
 			case 0:
 				dentry = dget(exp->ex_dentry);
 				break;
-			case 1:
-				if ((data_left-=2)<0) goto out;
-				dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
-							datap[0], datap[1],
-							0,
-							!(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
-				break;
-			case 2:
-				if ((data_left-=3)<0) goto out;
+			default:
 				dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
-							datap[0], datap[1],
-							datap[2],
+							datap, data_left, fh->fh_fileid_type,
 							!(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
-				break;
-			default: goto out;
 			}
 		} else {
-
+			__u32 tfh[3];
+			tfh[0] = fh->ofh_ino;
+			tfh[1] = fh->ofh_generation;
+			tfh[2] = fh->ofh_dirino;
 			dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
-						fh->ofh_ino, fh->ofh_generation,
-						fh->ofh_dirino,
+						tfh, 3, fh->ofh_dirino?2:1,
 						!(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
 		}
 		if (IS_ERR(dentry)) {
-			error = nfserrno(PTR_ERR(dentry));
+			if (PTR_ERR(dentry) != EINVAL)
+				error = nfserrno(PTR_ERR(dentry));
 			goto out;
 		}
 #ifdef NFSD_PARANOIA
@@ -709,9 +717,20 @@
 		      __u32 **datapp, int maxsize)
 {
 	__u32 *datap= *datapp;
+	struct super_block *sb = dentry->d_inode->i_sb;
+	
 	if (dentry == exp->ex_dentry)
 		return 0;
-	/* if super_operations provides dentry_to_fh lookup, should use that */
+
+	if (sb->s_op->dentry_to_fh) {
+		int need_parent = !S_ISDIR(dentry->d_inode->i_mode) &&
+			!(exp->ex_flags & NFSEXP_NOSUBTREECHECK);
+		
+		int type = sb->s_op->dentry_to_fh(dentry, datap, &maxsize, need_parent);
+		datap += maxsize;
+		*datapp = datap;
+		return type;
+	}
 	
 	*datap++ = ino_t_to_u32(dentry->d_inode->i_ino);
 	*datap++ = dentry->d_inode->i_generation;
diff -u --recursive --new-file v2.4.5/linux/fs/partitions/check.c linux/fs/partitions/check.c
--- v2.4.5/linux/fs/partitions/check.c	Wed May 16 14:01:32 2001
+++ linux/fs/partitions/check.c	Tue Jun 12 11:17:17 2001
@@ -418,11 +418,10 @@
 		blk_size[dev->major] = NULL;
 
 	dev->part[first_minor].nr_sects = size;
-	/* No Such Agen^Wdevice or no minors to use for partitions */
+	/* No such device or no minors to use for partitions */
 	if (!size || minors == 1)
 		return;
 
-	blk_size[dev->major] = NULL;
 	check_partition(dev, MKDEV(dev->major, first_minor), 1 + first_minor);
 
  	/*
diff -u --recursive --new-file v2.4.5/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.4.5/linux/fs/proc/array.c	Fri May  4 14:44:06 2001
+++ linux/fs/proc/array.c	Tue Jun 12 17:27:29 2001
@@ -421,13 +421,12 @@
 		++*total;
 		if (!pte_present(page))
 			continue;
+		ptpage = pte_page(page);
+		if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage))
+			continue;
 		++*pages;
 		if (pte_dirty(page))
 			++*dirty;
-		ptpage = pte_page(page);
-		if ((!VALID_PAGE(ptpage)) || 
-					PageReserved(ptpage))
-			continue;
 		if (page_count(pte_page(page)) > 1)
 			++*shared;
 	} while (address < end);
diff -u --recursive --new-file v2.4.5/linux/fs/proc/base.c linux/fs/proc/base.c
--- v2.4.5/linux/fs/proc/base.c	Fri May  4 14:44:06 2001
+++ linux/fs/proc/base.c	Mon Jun 11 19:27:15 2001
@@ -635,15 +635,14 @@
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_ino = fake_ino(task->pid, ino);
 
-	inode->u.proc_i.file = NULL;
+	if (!task->pid)
+		goto out_unlock;
+
 	/*
 	 * grab the reference to task.
 	 */
-	inode->u.proc_i.task = task;
 	get_task_struct(task);
-	if (!task->pid)
-		goto out_unlock;
-
+	inode->u.proc_i.task = task;
 	inode->i_uid = 0;
 	inode->i_gid = 0;
 	if (ino == PROC_PID_INO || task->dumpable) {
diff -u --recursive --new-file v2.4.5/linux/fs/reiserfs/fix_node.c linux/fs/reiserfs/fix_node.c
--- v2.4.5/linux/fs/reiserfs/fix_node.c	Fri Apr 13 20:26:07 2001
+++ linux/fs/reiserfs/fix_node.c	Tue Jun 12 10:44:57 2001
@@ -936,6 +936,7 @@
     if (p_s_tb->FEB[p_s_tb->cur_blknum])
       BUG();
 
+    mark_buffer_journal_new(p_s_new_bh) ;
     p_s_tb->FEB[p_s_tb->cur_blknum++] = p_s_new_bh;
   }
 
@@ -2719,12 +2720,6 @@
 {
     int	i;
 
-#ifdef CONFIG_REISERFS_CHECK
-    if ( ! tb->vn_buf )
-	reiserfs_panic (tb->tb_sb,
-			"PAP-16050: unfix_nodes: pointer to the virtual node is NULL");
-#endif
-
     /* Release path buffers. */
     pathrelse_and_restore (tb->tb_sb, tb->tb_path);
 
@@ -2781,7 +2776,8 @@
 	    }
 	}
 #endif /* 0 */
-    reiserfs_kfree (tb->vn_buf, tb->vn_buf_size, tb->tb_sb);
+    if (tb->vn_buf) 
+	reiserfs_kfree (tb->vn_buf, tb->vn_buf_size, tb->tb_sb);
 
 } 
 
diff -u --recursive --new-file v2.4.5/linux/fs/reiserfs/inode.c linux/fs/reiserfs/inode.c
--- v2.4.5/linux/fs/reiserfs/inode.c	Fri Apr 27 14:18:08 2001
+++ linux/fs/reiserfs/inode.c	Thu Jun 14 14:16:58 2001
@@ -21,6 +21,7 @@
 #define GET_BLOCK_CREATE 1    /* add anything you need to find block */
 #define GET_BLOCK_NO_HOLE 2   /* return -ENOENT for file holes */
 #define GET_BLOCK_READ_DIRECT 4  /* read the tail if indirect item not found */
+#define GET_BLOCK_NO_ISEM     8 /* i_sem is not held, don't preallocate */
 
 //
 // initially this function was derived from minix or ext2's analog and
@@ -539,6 +540,19 @@
     return retval ;
 }
 
+static inline int _allocate_block(struct reiserfs_transaction_handle *th,
+                           struct inode *inode, 
+			   b_blocknr_t *allocated_block_nr, 
+			   unsigned long tag,
+			   int flags) {
+  
+#ifdef REISERFS_PREALLOCATE
+    if (!(flags & GET_BLOCK_NO_ISEM)) {
+        return reiserfs_new_unf_blocknrs2(th, inode, allocated_block_nr, tag);
+    }
+#endif
+    return reiserfs_new_unf_blocknrs (th, allocated_block_nr, tag);
+}
 //
 // initially this function was derived from ext2's analog and evolved
 // as the prototype did.  You'll need to look at the ext2 version to
@@ -632,11 +646,7 @@
 	    goto research ;
 	}
 
-#ifdef REISERFS_PREALLOCATE
-	repeat = reiserfs_new_unf_blocknrs2 (&th, inode, &allocated_block_nr, tag);
-#else
-	repeat = reiserfs_new_unf_blocknrs (&th, &allocated_block_nr, tag);
-#endif
+	repeat = _allocate_block(&th, inode, &allocated_block_nr, tag, create);
 
 	if (repeat == NO_DISK_SPACE) {
 	    /* restart the transaction to give the journal a chance to free
@@ -644,11 +654,7 @@
 	    ** research if we succeed on the second try
 	    */
 	    restart_transaction(&th, inode, &path) ; 
-#ifdef REISERFS_PREALLOCATE
-	    repeat = reiserfs_new_unf_blocknrs2 (&th, inode, &allocated_block_nr, tag);
-#else
-	    repeat = reiserfs_new_unf_blocknrs (&th, &allocated_block_nr, tag);
-#endif
+	    repeat = _allocate_block(&th, inode,&allocated_block_nr,tag,create);
 
 	    if (repeat != NO_DISK_SPACE) {
 		goto research ;
@@ -736,10 +742,6 @@
 	    retval = reiserfs_insert_item (&th, &path, &tmp_key, &tmp_ih, (char *)&unp);
 	    if (retval) {
 		reiserfs_free_block (&th, allocated_block_nr);
-
-#ifdef REISERFS_PREALLOCATE
-		reiserfs_discard_prealloc (&th, inode); 
-#endif
 		goto failure; // retval == -ENOSPC or -EIO or -EEXIST
 	    }
 	    if (unp)
@@ -787,10 +789,6 @@
 	    mark_buffer_uptodate (unbh, 1);
 	    if (retval) {
 		reiserfs_free_block (&th, allocated_block_nr);
-
-#ifdef REISERFS_PREALLOCATE
-		reiserfs_discard_prealloc (&th, inode); 
-#endif
 		goto failure;
 	    }
 	    /* we've converted the tail, so we must 
@@ -832,10 +830,6 @@
 	    retval = reiserfs_paste_into_item (&th, &path, &tmp_key, (char *)&un, UNFM_P_SIZE);
 	    if (retval) {
 		reiserfs_free_block (&th, allocated_block_nr);
-
-#ifdef REISERFS_PREALLOCATE
-		reiserfs_discard_prealloc (&th, inode); 
-#endif
 		goto failure;
 	    }
 	    if (un.unfm_nodenum)
@@ -872,6 +866,8 @@
 	    reiserfs_warning ("vs-: reiserfs_get_block: "
 			      "%k should not be found", &key);
 	    retval = -EEXIST;
+	    if (allocated_block_nr)
+	        reiserfs_free_block (&th, allocated_block_nr);
 	    pathrelse(&path) ;
 	    goto failure;
 	}
@@ -921,6 +917,8 @@
     inode->i_generation = INODE_PKEY (inode)->k_dir_id;
     inode->i_blksize = PAGE_SIZE;
 
+    INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
+
     if (stat_data_v1 (ih)) {
 	struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih);
 	unsigned long blocks;
@@ -1163,7 +1161,7 @@
 	return;
     }
     if (retval != ITEM_FOUND) {
-	reiserfs_warning ("vs-13042: reiserfs_read_inode2: %K not found\n", &key);
+	/* a stale NFS handle can trigger this without it being an error */
 	pathrelse (&path_to_sd);
 	make_bad_inode(inode) ;
 	return;
@@ -1185,23 +1183,86 @@
     if (!inode) 
       return inode ;
 
-    if (is_bad_inode (inode)) {
-	reiserfs_warning ("vs-13048: reiserfs_iget: "
-			  "bad_inode. Stat data of (%lu %lu) not found\n",
-			  key->on_disk_key.k_dir_id, key->on_disk_key.k_objectid);
-	iput (inode);
-	inode = 0;
-    } else if (comp_short_keys (INODE_PKEY (inode), key)) {
-	reiserfs_warning ("vs-13049: reiserfs_iget: "
-			  "Looking for (%lu %lu), found inode of (%lu %lu)\n",
-			  key->on_disk_key.k_dir_id, key->on_disk_key.k_objectid,
-			  INODE_PKEY (inode)->k_dir_id, INODE_PKEY (inode)->k_objectid);
+    if (comp_short_keys (INODE_PKEY (inode), key) || is_bad_inode (inode)) {
+	/* either due to i/o error or a stale NFS handle */
 	iput (inode);
 	inode = 0;
     }
     return inode;
 }
 
+struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, __u32 *data,
+                                     int len, int fhtype, int parent) {
+    struct cpu_key key ;
+    struct inode *inode = NULL ;
+    struct list_head *lp;
+    struct dentry *result;
+
+    if (fhtype < 2 || (parent && fhtype < 4)) 
+	goto out ;
+
+    if (! parent) {
+	    /* this works for handles from old kernels because the default
+	    ** reiserfs generation number is the packing locality.
+	    */
+	    key.on_disk_key.k_objectid = data[0] ;
+	    key.on_disk_key.k_dir_id = data[1] ;
+	    inode = reiserfs_iget(sb, &key) ;
+    } else {
+	    key.on_disk_key.k_objectid = data[2] ;
+	    key.on_disk_key.k_dir_id = data[3] ;
+	    inode = reiserfs_iget(sb, &key) ;
+    }
+out:
+    if (!inode)
+        return ERR_PTR(-ESTALE) ;
+
+    /* now to find a dentry.
+     * If possible, get a well-connected one
+     */
+    spin_lock(&dcache_lock);
+    for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) {
+	    result = list_entry(lp,struct dentry, d_alias);
+	    if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) {
+		    dget_locked(result);
+		    result->d_vfs_flags |= DCACHE_REFERENCED;
+		    spin_unlock(&dcache_lock);
+		    iput(inode);
+		    return result;
+	    }
+    }
+    spin_unlock(&dcache_lock);
+    result = d_alloc_root(inode);
+    if (result == NULL) {
+	    iput(inode);
+	    return ERR_PTR(-ENOMEM);
+    }
+    result->d_flags |= DCACHE_NFSD_DISCONNECTED;
+    return result;
+
+}
+
+int reiserfs_dentry_to_fh(struct dentry *dentry, __u32 *data, int *lenp, int need_parent) {
+    struct inode *inode = dentry->d_inode ;
+    int maxlen = *lenp;
+    
+    if (maxlen < 2)
+        return 255 ;
+
+    data[0] = inode->i_ino ;
+    data[1] = le32_to_cpu(INODE_PKEY (inode)->k_dir_id) ;
+    *lenp = 2;
+    /* no room for directory info? return what we've stored so far */
+    if (maxlen < 4 || ! need_parent)
+        return 2 ;
+
+    inode = dentry->d_parent->d_inode ;
+    data[2] = inode->i_ino ;
+    data[3] = le32_to_cpu(INODE_PKEY (inode)->k_dir_id) ;
+    *lenp = 4;
+    return 4; 
+}
+
 
 //
 // initially this function was derived from minix or ext2's analog and
@@ -1421,6 +1482,8 @@
     inode->u.reiserfs_i.i_first_direct_byte = S_ISLNK(mode) ? 1 : 
       U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
 
+    INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
+
     if (old_format_only (sb))
 	inode2sd_v1 (&sd, inode);
     else
@@ -1723,7 +1786,8 @@
     /* this is where we fill in holes in the file. */
     if (use_get_block) {
         kmap(bh_result->b_page) ;
-	retval = reiserfs_get_block(inode, block, bh_result, 1) ;
+	retval = reiserfs_get_block(inode, block, bh_result, 
+	                            GET_BLOCK_CREATE | GET_BLOCK_NO_ISEM) ;
         kunmap(bh_result->b_page) ;
 	if (!retval) {
 	    if (!buffer_mapped(bh_result) || bh_result->b_blocknr == 0) {
diff -u --recursive --new-file v2.4.5/linux/fs/reiserfs/journal.c linux/fs/reiserfs/journal.c
--- v2.4.5/linux/fs/reiserfs/journal.c	Fri Apr 27 14:18:08 2001
+++ linux/fs/reiserfs/journal.c	Tue Jun 12 10:44:57 2001
@@ -2553,6 +2553,7 @@
   bh = get_hash_table(p_s_sb->s_dev, blocknr, p_s_sb->s_blocksize) ;
   /* if it is journal new, we just remove it from this transaction */
   if (bh && buffer_journal_new(bh)) {
+    mark_buffer_notjournal_new(bh) ;
     clear_prepared_bits(bh) ;
     cleaned = remove_from_transaction(p_s_sb, blocknr, cleaned) ;
   } else {
diff -u --recursive --new-file v2.4.5/linux/fs/reiserfs/stree.c linux/fs/reiserfs/stree.c
--- v2.4.5/linux/fs/reiserfs/stree.c	Fri Apr 13 20:26:07 2001
+++ linux/fs/reiserfs/stree.c	Tue Jun 12 10:44:58 2001
@@ -1724,7 +1724,7 @@
 	    continue;
 
 	reiserfs_warning ("PAP-5610: reiserfs_cut_from_item: item %K not found\n", p_s_item_key);
-	pathrelse (p_s_path);
+	unfix_nodes (&s_cut_balance);
 	return (n_ret_value == IO_ERROR) ? -EIO : -ENOENT;
     } /* while */
   
@@ -1994,12 +1994,14 @@
     while ( (retval = fix_nodes(M_PASTE, &s_paste_balance, NULL, p_c_body)) == REPEAT_SEARCH ) {
 	/* file system changed while we were in the fix_nodes */
 	retval = search_for_position_by_key (th->t_super, p_s_key, p_s_search_path);
-	if (retval == IO_ERROR)
-	    return -EIO;
+	if (retval == IO_ERROR) {
+	    retval = -EIO ;
+	    goto error_out ;
+	}
 	if (retval == POSITION_FOUND) {
 	    reiserfs_warning ("PAP-5710: reiserfs_paste_into_item: entry or pasted byte (%K) exists", p_s_key);
-	    pathrelse (p_s_search_path);
-	    return -EEXIST;
+	    retval = -EEXIST ;
+	    goto error_out ;
 	}
 	
 #ifdef CONFIG_REISERFS_CHECK
@@ -2013,9 +2015,11 @@
 	do_balance(&s_paste_balance, NULL/*ih*/, p_c_body, M_PASTE);
 	return 0;
     }
-
+    retval = (retval == NO_DISK_SPACE) ? -ENOSPC : -EIO;
+error_out:
+    /* this also releases the path */
     unfix_nodes(&s_paste_balance);
-    return (retval == NO_DISK_SPACE) ? -ENOSPC : -EIO;
+    return retval ;
 }
 
 
@@ -2040,14 +2044,15 @@
     while ( (retval = fix_nodes(M_INSERT, &s_ins_balance, p_s_ih, p_c_body)) == REPEAT_SEARCH) {
 	/* file system changed while we were in the fix_nodes */
 	retval = search_item (th->t_super, key, p_s_path);
-	if (retval == IO_ERROR)
-	    return -EIO;
-
+	if (retval == IO_ERROR) {
+	    retval = -EIO;
+	    goto error_out ;
+	}
 	if (retval == ITEM_FOUND) {
 	    reiserfs_warning ("PAP-5760: reiserfs_insert_item: "
 			      "key %K already exists in the tree\n", key);
-	    pathrelse (p_s_path);
-	    return -EEXIST;
+	    retval = -EEXIST ;
+	    goto error_out; 
 	}
     }
 
@@ -2057,8 +2062,11 @@
 	return 0;
     }
 
+    retval = (retval == NO_DISK_SPACE) ? -ENOSPC : -EIO;
+error_out:
+    /* also releases the path */
     unfix_nodes(&s_ins_balance);
-    return (retval == NO_DISK_SPACE) ? -ENOSPC : -EIO;
+    return retval; 
 }
 
 
diff -u --recursive --new-file v2.4.5/linux/fs/reiserfs/super.c linux/fs/reiserfs/super.c
--- v2.4.5/linux/fs/reiserfs/super.c	Fri Apr 27 14:18:08 2001
+++ linux/fs/reiserfs/super.c	Tue Jun 12 11:12:47 2001
@@ -149,6 +149,9 @@
   statfs: reiserfs_statfs,
   remount_fs: reiserfs_remount,
 
+  fh_to_dentry: reiserfs_fh_to_dentry,
+  dentry_to_fh: reiserfs_dentry_to_fh,
+
 };
 
 /* this was (ext2)parse_options */
diff -u --recursive --new-file v2.4.5/linux/fs/smbfs/ChangeLog linux/fs/smbfs/ChangeLog
--- v2.4.5/linux/fs/smbfs/ChangeLog	Tue May 15 13:40:55 2001
+++ linux/fs/smbfs/ChangeLog	Wed Jun 20 16:07:57 2001
@@ -1,5 +1,10 @@
 ChangeLog for smbfs.
 
+2001-06-12 Urban Widmark <urban@teststation.com>
+
+	* proc.c: replace the win95-flush fix with smb_seek, when needed.
+	* proc.c: readdir 'lastname' bug (NetApp dir listing fix)
+
 2001-05-08 Urban Widmark <urban@teststation.com>
 
 	* inode.c: Fix for changes on the server side not being detected
diff -u --recursive --new-file v2.4.5/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v2.4.5/linux/fs/smbfs/file.c	Tue May 15 13:40:55 2001
+++ linux/fs/smbfs/file.c	Wed Jun 20 16:07:57 2001
@@ -151,6 +151,7 @@
 		 * Update the inode now rather than waiting for a refresh.
 		 */
 		inode->i_mtime = inode->i_atime = CURRENT_TIME;
+		inode->u.smbfs_i.flags |= SMB_F_LOCALWRITE;
 		if (offset > inode->i_size)
 			inode->i_size = offset;
 	} while (count);
diff -u --recursive --new-file v2.4.5/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.4.5/linux/fs/smbfs/inode.c	Tue May 15 13:40:55 2001
+++ linux/fs/smbfs/inode.c	Wed Jun 20 16:07:57 2001
@@ -141,8 +141,8 @@
 	inode->u.smbfs_i.oldmtime = jiffies;
 
 	if (inode->i_mtime != last_time || inode->i_size != last_sz) {
-		VERBOSE("%s/%s changed, old=%ld, new=%ld, oz=%ld, nz=%ld\n",
-			DENTRY_PATH(dentry),
+		VERBOSE("%ld changed, old=%ld, new=%ld, oz=%ld, nz=%ld\n",
+			inode->i_ino,
 			(long) last_time, (long) inode->i_mtime,
 			(long) last_sz, (long) inode->i_size);
 
diff -u --recursive --new-file v2.4.5/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- v2.4.5/linux/fs/smbfs/proc.c	Tue May 15 13:40:55 2001
+++ linux/fs/smbfs/proc.c	Wed Jun 20 16:07:57 2001
@@ -919,6 +919,31 @@
 }
 
 /*
+ * Called with the server locked
+ */
+static int
+smb_proc_seek(struct smb_sb_info *server, __u16 fileid,
+	      __u16 mode, off_t offset)
+{
+	int result;
+
+	smb_setup_header(server, SMBlseek, 4, 0);
+	WSET(server->packet, smb_vwv0, fileid);
+	WSET(server->packet, smb_vwv1, mode);
+	DSET(server->packet, smb_vwv2, offset);
+
+	result = smb_request_ok(server, SMBlseek, 2, 0);
+	if (result < 0) {
+		result = 0;
+		goto out;
+	}
+
+	result = DVAL(server->packet, smb_vwv0);
+out:
+	return result;
+}
+
+/*
  * We're called with the server locked, and we leave it that way.
  */
 static int
@@ -1210,11 +1235,6 @@
 	if (result >= 0)
 		result = WVAL(server->packet, smb_vwv0);
 
-	/* flush to disk, to trigger win9x to update its filesize */
-	/* FIXME: this will be rather costly, won't it? */
-	if (server->mnt->flags & SMB_MOUNT_WIN95)
-		smb_proc_flush(server, fileid);
-
 	smb_unlock_server(server);
 	return result;
 }
@@ -1858,6 +1878,7 @@
 		result = mask_len;
 		goto unlock_return;
 	}
+	mask_len--;	/* mask_len is strlen, not #bytes */
 	first = 1;
 	VERBOSE("starting mask_len=%d, mask=%s\n", mask_len, mask);
 
@@ -1946,18 +1967,28 @@
 		 * Note that some servers (win95?) point to the filename and
 		 * others (NT4, Samba using NT1) to the dir entry. We assume
 		 * here that those who do not point to a filename do not need
-		 * this info to continue the listing. OS/2 needs this, but it
-		 * talks "infolevel 1"
+		 * this info to continue the listing.
+		 *
+		 * OS/2 needs this and talks infolevel 1
+		 * NetApps want lastname with infolevel 260
+		 *
+		 * Both are happy if we return the data they point to. So we do.
 		 */
 		mask_len = 0;
-		if (info_level == 1 && ff_lastname > 0 &&
-		    ff_lastname < resp_data_len) {
+		if (ff_lastname > 0 && ff_lastname < resp_data_len) {
 			lastname = resp_data + ff_lastname;
 
-			/* lastname points to a length byte */
-			mask_len = *lastname++;
-			if (ff_lastname + 1 + mask_len > resp_data_len)
-				mask_len = resp_data_len-ff_lastname-1;
+			switch (info_level) {
+			case 260:
+				mask_len = resp_data_len - ff_lastname;
+				break;
+			case 1:
+				/* lastname points to a length byte */
+				mask_len = *lastname++;
+				if (ff_lastname + 1 + mask_len > resp_data_len)
+					mask_len = resp_data_len - ff_lastname - 1;
+				break;
+			}
 
 			/*
 			 * Update the mask string for the next message.
@@ -2062,7 +2093,7 @@
 	DSET(param, 8, 0);
 
 	result = smb_trans2_request(server, TRANSACT2_FINDFIRST,
-				    0, NULL, 12 + mask_len + 1, param,
+				    0, NULL, 12 + mask_len, param,
 				    &resp_data_len, &resp_data,
 				    &resp_param_len, &resp_param);
 	if (result < 0)
@@ -2246,6 +2277,7 @@
 		    struct smb_fattr *fattr)
 {
 	int result;
+	struct inode *inode = dir->d_inode;
 
 	smb_init_dirent(server, fattr);
 
@@ -2261,6 +2293,21 @@
 			result = smb_proc_getattr_ff(server, dir, fattr);
 		else
 			result = smb_proc_getattr_trans2(server, dir, fattr);
+	}
+
+	/*
+	 * None of the getattr versions here can make win9x return the right
+	 * filesize if there are changes made to an open file.
+	 * A seek-to-end does return the right size, but we only need to do
+	 * that on files we have written.
+	 */
+	if (server->mnt->flags & SMB_MOUNT_WIN95 &&
+	    inode &&
+	    inode->u.smbfs_i.flags & SMB_F_LOCALWRITE &&
+	    smb_is_open(inode))
+	{
+		__u16 fileid = inode->u.smbfs_i.fileid;
+		fattr->f_size = smb_proc_seek(server, fileid, 2, 0);
 	}
 
 	smb_finish_dirent(server, fattr);
diff -u --recursive --new-file v2.4.5/linux/fs/super.c linux/fs/super.c
--- v2.4.5/linux/fs/super.c	Fri May 25 12:38:52 2001
+++ linux/fs/super.c	Thu Jun 14 14:16:58 2001
@@ -55,7 +55,6 @@
 extern int root_mountflags;
 
 static int do_remount_sb(struct super_block *sb, int flags, char * data);
-static int do_remount(const char *dir, int flags, char * data);
 
 /* this is initialized in init/main.c */
 kdev_t ROOT_DEV;
@@ -282,13 +281,25 @@
 
 static LIST_HEAD(vfsmntlist);
 
+static struct list_head *mount_hashtable;
+static int hash_mask, hash_bits;
+static kmem_cache_t *mnt_cache; 
+
+static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
+{
+	unsigned long tmp = ((unsigned long) mnt / L1_CACHE_BYTES);
+	tmp += ((unsigned long) dentry / L1_CACHE_BYTES);
+	tmp = tmp + (tmp >> hash_mask);
+	return tmp & hash_bits;
+}
+
 struct vfsmount *alloc_vfsmnt(void)
 {
-	struct vfsmount *mnt = kmalloc(sizeof(struct vfsmount), GFP_KERNEL); 
+	struct vfsmount *mnt = kmem_cache_alloc(mnt_cache, GFP_KERNEL); 
 	if (mnt) {
 		memset(mnt, 0, sizeof(struct vfsmount));
 		atomic_set(&mnt->mnt_count,1);
-		INIT_LIST_HEAD(&mnt->mnt_clash);
+		INIT_LIST_HEAD(&mnt->mnt_hash);
 		INIT_LIST_HEAD(&mnt->mnt_child);
 		INIT_LIST_HEAD(&mnt->mnt_mounts);
 		INIT_LIST_HEAD(&mnt->mnt_list);
@@ -297,6 +308,24 @@
 	return mnt;
 }
 
+struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
+{
+	struct list_head * head = mount_hashtable + hash(mnt, dentry);
+	struct list_head * tmp = head;
+	struct vfsmount *p;
+
+	for (;;) {
+		tmp = tmp->next;
+		p = NULL;
+		if (tmp == head)
+			break;
+		p = list_entry(tmp, struct vfsmount, mnt_hash);
+		if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry)
+			break;
+	}
+	return p;
+}
+
 static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd)
 {
 	old_nd->dentry = mnt->mnt_mountpoint;
@@ -304,15 +333,17 @@
 	mnt->mnt_parent = mnt;
 	mnt->mnt_mountpoint = mnt->mnt_root;
 	list_del_init(&mnt->mnt_child);
-	list_del_init(&mnt->mnt_clash);
+	list_del_init(&mnt->mnt_hash);
+	old_nd->dentry->d_mounted--;
 }
 
 static void attach_mnt(struct vfsmount *mnt, struct nameidata *nd)
 {
 	mnt->mnt_parent = mntget(nd->mnt);
 	mnt->mnt_mountpoint = dget(nd->dentry);
-	list_add(&mnt->mnt_clash, &nd->dentry->d_vfsmnt);
+	list_add(&mnt->mnt_hash, mount_hashtable+hash(nd->mnt, nd->dentry));
 	list_add(&mnt->mnt_child, &nd->mnt->mnt_mounts);
+	nd->dentry->d_mounted++;
 }
 
 /**
@@ -331,9 +362,7 @@
  *	dentry (if any).
  */
 
-static struct vfsmount *add_vfsmnt(struct nameidata *nd,
-				struct dentry *root,
-				const char *dev_name)
+static struct vfsmount *add_vfsmnt(struct dentry *root, const char *dev_name)
 {
 	struct vfsmount *mnt;
 	struct super_block *sb = root->d_inode->i_sb;
@@ -352,18 +381,11 @@
 		}
 	}
 	mnt->mnt_sb = sb;
-
-	spin_lock(&dcache_lock);
-	if (nd && !IS_ROOT(nd->dentry) && d_unhashed(nd->dentry))
-		goto fail;
 	mnt->mnt_root = dget(root);
+	mnt->mnt_mountpoint = mnt->mnt_root;
+	mnt->mnt_parent = mnt;
 
-	if (nd) {
-		attach_mnt(mnt, nd);
-	} else {
-		mnt->mnt_mountpoint = mnt->mnt_root;
-		mnt->mnt_parent = mnt;
-	}
+	spin_lock(&dcache_lock);
 	list_add(&mnt->mnt_instances, &sb->s_mounts);
 	list_add(&mnt->mnt_list, vfsmntlist.prev);
 	spin_unlock(&dcache_lock);
@@ -371,14 +393,63 @@
 		get_filesystem(sb->s_type);
 out:
 	return mnt;
+}
+
+static struct vfsmount *clone_mnt(struct vfsmount *old_mnt, struct dentry *root)
+{
+	char *name = old_mnt->mnt_devname;
+	struct vfsmount *mnt = alloc_vfsmnt();
+
+	if (!mnt)
+		goto out;
+
+	if (name) {
+		mnt->mnt_devname = kmalloc(strlen(name)+1, GFP_KERNEL);
+		if (mnt->mnt_devname)
+			strcpy(mnt->mnt_devname, name);
+	}
+	mnt->mnt_sb = old_mnt->mnt_sb;
+	mnt->mnt_root = dget(root);
+	mnt->mnt_mountpoint = mnt->mnt_root;
+	mnt->mnt_parent = mnt;
+
+	spin_lock(&dcache_lock);
+	list_add(&mnt->mnt_instances, &old_mnt->mnt_instances);
+	spin_unlock(&dcache_lock);
+out:
+	return mnt;
+}
+
+static int graft_tree(struct vfsmount *mnt, struct nameidata *nd)
+{
+	if (S_ISDIR(nd->dentry->d_inode->i_mode) !=
+	      S_ISDIR(mnt->mnt_root->d_inode->i_mode))
+		return -ENOTDIR;
+
+	down(&nd->dentry->d_inode->i_zombie);
+	if (IS_DEADDIR(nd->dentry->d_inode))
+		goto fail1;
+
+	spin_lock(&dcache_lock);
+	if (!IS_ROOT(nd->dentry) && d_unhashed(nd->dentry))
+		goto fail;
+
+	attach_mnt(mnt, nd);
+	list_add(&mnt->mnt_list, vfsmntlist.prev);
+	spin_unlock(&dcache_lock);
+	up(&nd->dentry->d_inode->i_zombie);
+	if (mnt->mnt_sb->s_type->fs_flags & FS_SINGLE)
+		get_filesystem(mnt->mnt_sb->s_type);
+	mntget(mnt);
+	return 0;
 fail:
 	spin_unlock(&dcache_lock);
-	if (mnt->mnt_devname)
-		kfree(mnt->mnt_devname);
-	kfree(mnt);
-	return NULL;
+fail1:
+	up(&nd->dentry->d_inode->i_zombie);
+	return -ENOENT;
 }
 
+#ifdef CONFIG_BLK_DEV_INITRD
 static void move_vfsmnt(struct vfsmount *mnt,
 			struct nameidata *nd, 
 			const char *dev_name)
@@ -407,6 +478,7 @@
 	if (parent_nd.mnt != mnt)
 		path_release(&parent_nd);
 }
+#endif
 
 static void kill_super(struct super_block *);
 
@@ -420,7 +492,7 @@
 	spin_unlock(&dcache_lock);
 	if (mnt->mnt_devname)
 		kfree(mnt->mnt_devname);
-	kfree(mnt);
+	kmem_cache_free(mnt_cache, mnt);
 	kill_super(sb);
 }
 
@@ -734,7 +806,7 @@
  * filesystems which don't use real block-devices.  -- jrs
  */
 
-static unsigned int unnamed_dev_in_use[256/(8*sizeof(unsigned int))];
+static unsigned long unnamed_dev_in_use[256/(8*sizeof(unsigned long))];
 
 kdev_t get_unnamed_dev(void)
 {
@@ -873,6 +945,7 @@
 	}
 	spin_unlock(&dcache_lock);
 	down_write(&sb->s_umount);
+	lock_kernel();
 	sb->s_root = NULL;
 	/* Need to clean after the sucker */
 	if (fs->fs_flags & FS_LITTER)
@@ -901,6 +974,7 @@
 	put_filesystem(fs);
 	sb->s_type = NULL;
 	unlock_super(sb);
+	unlock_kernel();
 	up_write(&sb->s_umount);
 	if (bdev) {
 		blkdev_put(bdev, BDEV_FS);
@@ -921,6 +995,10 @@
 	if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev))
 		return -EACCES;
 		/*flags |= MS_RDONLY;*/
+	if (flags & MS_RDONLY)
+		acct_auto_close(sb->s_dev);
+	shrink_dcache_sb(sb);
+	fsync_dev(sb->s_dev);
 	/* If we are remounting RDONLY, make sure there are no rw files open */
 	if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
 		if (!fs_may_remount_ro(sb))
@@ -954,13 +1032,13 @@
 
 	dev = get_unnamed_dev();
 	if (!dev) {
-		kfree(mnt);
+		kmem_cache_free(mnt_cache, mnt);
 		return ERR_PTR(-EMFILE);
 	}
 	sb = read_super(dev, NULL, type, 0, NULL, 0);
 	if (!sb) {
 		put_unnamed_dev(dev);
-		kfree(mnt);
+		kmem_cache_free(mnt_cache, mnt);
 		return ERR_PTR(-EINVAL);
 	}
 	mnt->mnt_sb = sb;
@@ -1002,11 +1080,14 @@
 	 * call reboot(9). Then init(8) could umount root and exec /reboot.
 	 */
 	if (mnt == current->fs->rootmnt) {
+		int retval = 0;
 		/*
 		 * Special case for "unmounting" root ...
 		 * we just try to remount it readonly.
 		 */
-		return do_remount("/", MS_RDONLY, NULL);
+		if (!(sb->s_flags & MS_RDONLY))
+			retval = do_remount_sb(sb, MS_RDONLY, 0);
+		return retval;
 	}
 
 	spin_lock(&dcache_lock);
@@ -1143,44 +1224,33 @@
 /*
  * do loopback mount.
  */
-static int do_loopback(char *old_name, char *new_name)
+static int do_loopback(struct nameidata *nd, char *old_name)
 {
-	struct nameidata old_nd, new_nd;
-	int err = 0;
+	struct nameidata old_nd;
+	struct vfsmount *mnt;
+	int err;
+
+	err = mount_is_safe(nd);
+	if (err)
+		return err;
+
 	if (!old_name || !*old_name)
 		return -EINVAL;
-	if (path_init(old_name, LOOKUP_POSITIVE, &old_nd))
+
+	if (path_init(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd))
 		err = path_walk(old_name, &old_nd);
 	if (err)
-		goto out;
-	if (path_init(new_name, LOOKUP_POSITIVE, &new_nd))
-		err = path_walk(new_name, &new_nd);
-	if (err)
-		goto out1;
-	err = mount_is_safe(&new_nd);
-	if (err)
-		goto out2;
-	err = -EINVAL;
-	if (S_ISDIR(new_nd.dentry->d_inode->i_mode) !=
-	      S_ISDIR(old_nd.dentry->d_inode->i_mode))
-		goto out2;
+		return err;
 
-	err = -ENOMEM;
-		
 	down(&mount_sem);
-	/* there we go */
-	down(&new_nd.dentry->d_inode->i_zombie);
-	if (IS_DEADDIR(new_nd.dentry->d_inode))
-		err = -ENOENT;
-	else if (add_vfsmnt(&new_nd, old_nd.dentry, old_nd.mnt->mnt_devname))
-		err = 0;
-	up(&new_nd.dentry->d_inode->i_zombie);
+	err = -ENOMEM;
+	mnt = clone_mnt(old_nd.mnt, old_nd.dentry);
+	if (mnt) {
+		err = graft_tree(mnt, nd);
+		mntput(mnt);
+	}
 	up(&mount_sem);
-out2:
-	path_release(&new_nd);
-out1:
 	path_release(&old_nd);
-out:
 	return err;
 }
 
@@ -1190,34 +1260,87 @@
  * on it - tough luck.
  */
 
-static int do_remount(const char *dir,int flags,char *data)
+static int do_remount(struct nameidata *nd, int flags, char *data)
 {
-	struct nameidata nd;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (nd->dentry != nd->mnt->mnt_root)
+		return -EINVAL;
+
+	return do_remount_sb(nd->mnt->mnt_sb, flags, data);
+}
+
+static int do_add_mount(struct nameidata *nd, char *type, int flags,
+			char *name, void *data)
+{
+	struct file_system_type * fstype;
+	struct vfsmount *mnt = NULL;
+	struct super_block *sb;
 	int retval = 0;
 
+	if (!type || !memchr(type, 0, PAGE_SIZE))
+		return -EINVAL;
+
+	/* we need capabilities... */
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	if (path_init(dir, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
-		retval = path_walk(dir, &nd);
-	if (!retval) {
-		struct super_block * sb = nd.dentry->d_inode->i_sb;
-		retval = -ENODEV;
-		if (sb) {
-			retval = -EINVAL;
-			if (nd.dentry == sb->s_root) {
-				/*
-				 * Shrink the dcache and sync the device.
-				 */
-				shrink_dcache_sb(sb);
-				fsync_dev(sb->s_dev);
-				if (flags & MS_RDONLY)
-					acct_auto_close(sb->s_dev);
-				retval = do_remount_sb(sb, flags, data);
-			}
-		}
-		path_release(&nd);
+	/* ... filesystem driver... */
+	fstype = get_fs_type(type);
+	if (!fstype)		
+		return -ENODEV;
+
+	/* ... allocated vfsmount... */
+	retval = -ENOMEM;
+	mnt = alloc_vfsmnt();
+	if (!mnt)
+		goto fs_out;
+	if (name) {
+		mnt->mnt_devname = kmalloc(strlen(name)+1, GFP_KERNEL);
+		if (mnt->mnt_devname)
+			strcpy(mnt->mnt_devname, name);
+	}
+
+	/* get superblock, locks mount_sem on success */
+	if (fstype->fs_flags & FS_NOMOUNT)
+		sb = ERR_PTR(-EINVAL);
+	else if (fstype->fs_flags & FS_REQUIRES_DEV)
+		sb = get_sb_bdev(fstype, name, flags, data);
+	else if (fstype->fs_flags & FS_SINGLE)
+		sb = get_sb_single(fstype, flags, data);
+	else
+		sb = get_sb_nodev(fstype, flags, data);
+
+	retval = PTR_ERR(sb);
+	if (IS_ERR(sb)) {
+		if (mnt->mnt_devname)
+			kfree(mnt->mnt_devname);
+		kmem_cache_free(mnt_cache, mnt);
+		goto fs_out;
 	}
+
+	mnt->mnt_sb = sb;
+	mnt->mnt_root = dget(sb->s_root);
+	mnt->mnt_mountpoint = mnt->mnt_root;
+	mnt->mnt_parent = mnt;
+	spin_lock(&dcache_lock);
+	list_add(&mnt->mnt_instances, &sb->s_mounts);
+	spin_unlock(&dcache_lock);
+
+	/* Something was mounted here while we slept */
+	while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
+		;
+
+	/* Refuse the same filesystem on the same mount point */
+	if (nd->mnt->mnt_sb == sb && nd->mnt->mnt_root == nd->dentry)
+		retval = -EBUSY;
+	else
+		retval = graft_tree(mnt, nd);
+	mntput(mnt);
+	up(&mount_sem);
+fs_out:
+	put_filesystem(fstype);
 	return retval;
 }
 
@@ -1271,10 +1394,7 @@
 long do_mount(char * dev_name, char * dir_name, char *type_page,
 		  unsigned long flags, void *data_page)
 {
-	struct file_system_type * fstype;
 	struct nameidata nd;
-	struct vfsmount *mnt = NULL;
-	struct super_block *sb;
 	int retval = 0;
 
 	/* Discard magic */
@@ -1288,86 +1408,22 @@
 	if (dev_name && !memchr(dev_name, 0, PAGE_SIZE))
 		return -EINVAL;
 
-	/* OK, looks good, now let's see what do they want */
-
-	/* just change the flags? - capabilities are checked in do_remount() */
-	if (flags & MS_REMOUNT)
-		return do_remount(dir_name, flags & ~MS_REMOUNT,
-				  (char *) data_page);
-
-	/* "mount --bind"? Equivalent to older "mount -t bind" */
-	/* No capabilities? What if users do thousands of these? */
-	if (flags & MS_BIND)
-		return do_loopback(dev_name, dir_name);
-
-	/* For the rest we need the type */
-
-	if (!type_page || !memchr(type_page, 0, PAGE_SIZE))
-		return -EINVAL;
-
-	/* for the rest we _really_ need capabilities... */
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-
-	/* ... filesystem driver... */
-	fstype = get_fs_type(type_page);
-	if (!fstype)		
-		return -ENODEV;
-
-	/* ... and mountpoint. Do the lookup first to force automounting. */
-	if (path_init(dir_name,
-		      LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd))
+	/* ... and get the mountpoint */
+	if (path_init(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
 		retval = path_walk(dir_name, &nd);
 	if (retval)
-		goto fs_out;
+		return retval;
 
-	/* get superblock, locks mount_sem on success */
-	if (fstype->fs_flags & FS_NOMOUNT)
-		sb = ERR_PTR(-EINVAL);
-	else if (fstype->fs_flags & FS_REQUIRES_DEV)
-		sb = get_sb_bdev(fstype, dev_name, flags, data_page);
-	else if (fstype->fs_flags & FS_SINGLE)
-		sb = get_sb_single(fstype, flags, data_page);
+	if (flags & MS_REMOUNT)
+		retval = do_remount(&nd, flags&~MS_REMOUNT,
+				  (char *)data_page);
+	else if (flags & MS_BIND)
+		retval = do_loopback(&nd, dev_name);
 	else
-		sb = get_sb_nodev(fstype, flags, data_page);
-
-	retval = PTR_ERR(sb);
-	if (IS_ERR(sb))
-		goto dput_out;
-
-	/* Something was mounted here while we slept */
-	while(d_mountpoint(nd.dentry) && follow_down(&nd.mnt, &nd.dentry))
-		;
-
-	/* Refuse the same filesystem on the same mount point */
-	retval = -EBUSY;
-	if (nd.mnt && nd.mnt->mnt_sb == sb
-	    	   && nd.mnt->mnt_root == nd.dentry)
-		goto fail;
-
-	retval = -ENOENT;
-	if (!nd.dentry->d_inode)
-		goto fail;
-	down(&nd.dentry->d_inode->i_zombie);
-	if (!IS_DEADDIR(nd.dentry->d_inode)) {
-		retval = -ENOMEM;
-		mnt = add_vfsmnt(&nd, sb->s_root, dev_name);
-	}
-	up(&nd.dentry->d_inode->i_zombie);
-	if (!mnt)
-		goto fail;
-	retval = 0;
-unlock_out:
-	up(&mount_sem);
-dput_out:
+		retval = do_add_mount(&nd, type_page, flags,
+				      dev_name, data_page);
 	path_release(&nd);
-fs_out:
-	put_filesystem(fstype);
 	return retval;
-
-fail:
-	kill_super(sb);
-	goto unlock_out;
 }
 
 asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
@@ -1555,10 +1611,10 @@
 		devfs_mk_symlink (NULL, "root", DEVFS_FL_DEFAULT,
 				  path + 5 + path_start, NULL, NULL);
 		memcpy (path + path_start, "/dev/", 5);
-		vfsmnt = add_vfsmnt(NULL, sb->s_root, path + path_start);
+		vfsmnt = add_vfsmnt(sb->s_root, path + path_start);
 	}
 	else
-		vfsmnt = add_vfsmnt(NULL, sb->s_root, "/dev/root");
+		vfsmnt = add_vfsmnt(sb->s_root, "/dev/root");
 	/* FIXME: if something will try to umount us right now... */
 	if (vfsmnt) {
 		set_fs_root(current->fs, vfsmnt, sb->s_root);
@@ -1776,3 +1832,51 @@
 }
 
 #endif
+
+void __init mnt_init(unsigned long mempages)
+{
+	struct list_head *d;
+	unsigned long order;
+	unsigned int nr_hash;
+	int i;
+
+	mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount),
+					0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!mnt_cache)
+		panic("Cannot create vfsmount cache");
+
+	mempages >>= (16 - PAGE_SHIFT);
+	mempages *= sizeof(struct list_head);
+	for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++)
+		;
+
+	do {
+		unsigned long tmp;
+
+		nr_hash = (1UL << order) * PAGE_SIZE /
+			sizeof(struct list_head);
+		hash_mask = (nr_hash - 1);
+
+		tmp = nr_hash;
+		hash_bits = 0;
+		while ((tmp >>= 1UL) != 0UL)
+			hash_bits++;
+
+		mount_hashtable = (struct list_head *)
+			__get_free_pages(GFP_ATOMIC, order);
+	} while (mount_hashtable == NULL && --order >= 0);
+
+	printk("Mount-cache hash table entries: %d (order: %ld, %ld bytes)\n",
+			nr_hash, order, (PAGE_SIZE << order));
+
+	if (!mount_hashtable)
+		panic("Failed to allocate mount hash table\n");
+
+	d = mount_hashtable;
+	i = nr_hash;
+	do {
+		INIT_LIST_HEAD(d);
+		d++;
+		i--;
+	} while (i);
+}
diff -u --recursive --new-file v2.4.5/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v2.4.5/linux/fs/sysv/inode.c	Tue Apr 17 23:16:39 2001
+++ linux/fs/sysv/inode.c	Tue Jun 12 11:06:54 2001
@@ -442,7 +442,7 @@
 			brelse(bh);
 			printk("SysV FS: cannot read superblock in %d byte mode\n", sb->sv_block_size);
 			goto failed;
-		superblock_ok:
+		superblock_ok:;
 		}
 	} else {
 		/* Switch to 512 block size. Unfortunately, we have to
diff -u --recursive --new-file v2.4.5/linux/fs/udf/Makefile linux/fs/udf/Makefile
--- v2.4.5/linux/fs/udf/Makefile	Fri Dec 29 14:07:23 2000
+++ linux/fs/udf/Makefile	Mon Jun 11 19:15:27 2001
@@ -9,9 +9,9 @@
 
 O_TARGET := udf.o
 
-obj-y   := balloc.o dir.o file.o ialloc.o inode.o lowlevel.o namei.o \
+obj-y    := balloc.o dir.o file.o ialloc.o inode.o lowlevel.o namei.o \
 		partition.o super.o truncate.o symlink.o fsync.o \
 		crc.o directory.o misc.o udftime.o unicode.o
-obj-m   := $(O_TARGET)
+obj-m    := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.5/linux/fs/udf/balloc.c linux/fs/udf/balloc.c
--- v2.4.5/linux/fs/udf/balloc.c	Tue Sep  5 14:07:30 2000
+++ linux/fs/udf/balloc.c	Mon Jun 11 19:15:27 2001
@@ -7,7 +7,7 @@
  * CONTACTS
  *	E-mail regarding any portion of the Linux UDF file system should be
  *	directed to the development team mailing list (run by majordomo):
- *		linux_udf@hootie.lvld.hp.com
+ *		linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *	This file is distributed under the terms of the GNU General Public
@@ -85,14 +85,14 @@
 #define find_first_one_bit(addr, size)\
 	find_next_one_bit((addr), (size), 0)
 
-static int read_block_bitmap(struct super_block * sb, Uint32 bitmap,
-	unsigned int block, unsigned long bitmap_nr)
+static int read_block_bitmap(struct super_block * sb,
+	struct udf_bitmap *bitmap, unsigned int block, unsigned long bitmap_nr)
 {
 	struct buffer_head *bh = NULL;
 	int retval = 0;
 	lb_addr loc;
 
-	loc.logicalBlockNum = bitmap;
+	loc.logicalBlockNum = bitmap->s_extPosition;
 	loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
 
 	bh = udf_tread(sb, udf_get_lb_pblock(sb, loc, block), sb->s_blocksize);
@@ -100,110 +100,50 @@
 	{
 		retval = -EIO;
 	}
-	UDF_SB_BLOCK_BITMAP_NUMBER(sb, bitmap_nr) = block;
-	UDF_SB_BLOCK_BITMAP(sb, bitmap_nr) = bh;
+	bitmap->s_block_bitmap[bitmap_nr] = bh;
 	return retval;
 }
 
-static int __load_block_bitmap(struct super_block * sb, Uint32 bitmap,
-	unsigned int block_group)
+static int __load_block_bitmap(struct super_block * sb,
+	struct udf_bitmap *bitmap, unsigned int block_group)
 {
-	int i, j, retval = 0;
-	unsigned long block_bitmap_number;
-	struct buffer_head * block_bitmap = NULL;
-	int nr_groups = (UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb)) +
-		(sizeof(struct SpaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
+	int retval = 0;
+	int nr_groups = bitmap->s_nr_groups;
 
 	if (block_group >= nr_groups)
 	{
 		udf_debug("block_group (%d) > nr_groups (%d)\n", block_group, nr_groups);
 	}
 
-	if (nr_groups <= UDF_MAX_BLOCK_LOADED)
+	if (bitmap->s_block_bitmap[block_group])
+		return block_group;
+	else
 	{
-		if (UDF_SB_BLOCK_BITMAP(sb, block_group))
-		{
-			if (UDF_SB_BLOCK_BITMAP_NUMBER(sb, block_group) == block_group)
-				return block_group;
-		}
 		retval = read_block_bitmap(sb, bitmap, block_group, block_group);
 		if (retval < 0)
 			return retval;
 		return block_group;
 	}
-
-	for (i=0; i<UDF_SB_LOADED_BLOCK_BITMAPS(sb) &&
-		UDF_SB_BLOCK_BITMAP_NUMBER(sb, i) != block_group; i++)
-	{
-		;
-	}
-	if (i < UDF_SB_LOADED_BLOCK_BITMAPS(sb) &&
-		UDF_SB_BLOCK_BITMAP_NUMBER(sb, i) == block_group)
-	{
-		block_bitmap_number = UDF_SB_BLOCK_BITMAP_NUMBER(sb, i);
-		block_bitmap = UDF_SB_BLOCK_BITMAP(sb, i);
-		for (j=i; j>0; j--)
-		{
-			UDF_SB_BLOCK_BITMAP_NUMBER(sb, j) = UDF_SB_BLOCK_BITMAP_NUMBER(sb, j-1);
-			UDF_SB_BLOCK_BITMAP(sb, j) = UDF_SB_BLOCK_BITMAP(sb, j-1);
-		}
-		UDF_SB_BLOCK_BITMAP_NUMBER(sb, 0) = block_bitmap_number;
-		UDF_SB_BLOCK_BITMAP(sb, 0) = block_bitmap;
-
-		if (!block_bitmap)
-			retval = read_block_bitmap(sb, bitmap, block_group, 0);
-	}
-	else
-	{
-		if (UDF_SB_LOADED_BLOCK_BITMAPS(sb) < UDF_MAX_BLOCK_LOADED)
-			UDF_SB_LOADED_BLOCK_BITMAPS(sb) ++;
-		else
-			brelse(UDF_SB_BLOCK_BITMAP(sb, UDF_MAX_BLOCK_LOADED-1));
-		for (j=UDF_SB_LOADED_BLOCK_BITMAPS(sb)-1; j>0; j--)
-		{
-			UDF_SB_BLOCK_BITMAP_NUMBER(sb, j) = UDF_SB_BLOCK_BITMAP_NUMBER(sb, j-1);
-			UDF_SB_BLOCK_BITMAP(sb, j) = UDF_SB_BLOCK_BITMAP(sb, j-1);
-		}
-		retval = read_block_bitmap(sb, bitmap, block_group, 0);
-	}
-	return retval;
 }
 
-static inline int load_block_bitmap(struct super_block *sb, Uint32 bitmap,
-	unsigned int block_group)
+static inline int load_block_bitmap(struct super_block *sb,
+	struct udf_bitmap *bitmap, unsigned int block_group)
 {
 	int slot;
-	int nr_groups = (UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb)) +
-		(sizeof(struct SpaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
 
-	if (UDF_SB_LOADED_BLOCK_BITMAPS(sb) > 0 &&
-		UDF_SB_BLOCK_BITMAP_NUMBER(sb, 0) == block_group &&
-		UDF_SB_BLOCK_BITMAP(sb, block_group))
-	{
-		return 0;
-	}
-	else if (nr_groups <= UDF_MAX_BLOCK_LOADED &&
-		UDF_SB_BLOCK_BITMAP_NUMBER(sb, block_group) == block_group &&
-		UDF_SB_BLOCK_BITMAP(sb, block_group))
-	{
-		slot = block_group;
-	}
-	else
-	{
-		slot = __load_block_bitmap(sb, bitmap, block_group);
-	}
+	slot = __load_block_bitmap(sb, bitmap, block_group);
 
 	if (slot < 0)
 		return slot;
 
-	if (!UDF_SB_BLOCK_BITMAP(sb, slot))
+	if (!bitmap->s_block_bitmap[slot])
 		return -EIO;
 
 	return slot;
 }
 
-static void udf_bitmap_free_blocks(const struct inode * inode, Uint32 bitmap,
-	lb_addr bloc, Uint32 offset, Uint32 count)
+static void udf_bitmap_free_blocks(const struct inode * inode,
+	struct udf_bitmap *bitmap, lb_addr bloc, Uint32 offset, Uint32 count)
 {
 	struct buffer_head * bh = NULL;
 	unsigned long block;
@@ -250,7 +190,7 @@
 	if (bitmap_nr < 0)
 		goto error_return;
 
-	bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr);
+	bh = bitmap->s_block_bitmap[bitmap_nr];
 	for (i=0; i < count; i++)
 	{
 		if (udf_set_bit(bit + i, bh->b_data))
@@ -283,8 +223,9 @@
 	return;
 }
 
-static int udf_bitmap_prealloc_blocks(const struct inode * inode, Uint32 bitmap,
-	Uint16 partition, Uint32 first_block, Uint32 block_count)
+static int udf_bitmap_prealloc_blocks(const struct inode * inode,
+	struct udf_bitmap *bitmap, Uint16 partition, Uint32 first_block,
+	Uint32 block_count)
 {
 	int alloc_count = 0;
 	int bit, block, block_group, group_start;
@@ -303,6 +244,9 @@
 	if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition))
 		goto out;
 
+	if (first_block + block_count > UDF_SB_PARTLEN(sb, partition))
+		block_count = UDF_SB_PARTLEN(sb, partition) - first_block;
+
 repeat:
 	nr_groups = (UDF_SB_PARTLEN(sb, partition) +
 		(sizeof(struct SpaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
@@ -313,7 +257,7 @@
 	bitmap_nr = load_block_bitmap(sb, bitmap, block_group);
 	if (bitmap_nr < 0)
 		goto out;
-	bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr);
+	bh = bitmap->s_block_bitmap[bitmap_nr];
 
 	bit = block % (sb->s_blocksize << 3);
 
@@ -349,10 +293,10 @@
 	return alloc_count;
 }
 
-static int udf_bitmap_new_block(const struct inode * inode, Uint32 bitmap,
-	Uint16 partition, Uint32 goal, int *err)
+static int udf_bitmap_new_block(const struct inode * inode,
+	struct udf_bitmap *bitmap, Uint16 partition, Uint32 goal, int *err)
 {
-	int tmp, newbit, bit=0, block, block_group, group_start;
+	int newbit, bit=0, block, block_group, group_start;
 	int end_goal, nr_groups, bitmap_nr, i;
 	struct buffer_head *bh = NULL;
 	struct super_block *sb;
@@ -372,8 +316,7 @@
 	if (goal < 0 || goal >= UDF_SB_PARTLEN(sb, partition))
 		goal = 0;
 
-	nr_groups = (UDF_SB_PARTLEN(sb, partition) +
-		(sizeof(struct SpaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
+	nr_groups = bitmap->s_nr_groups;
 	block = goal + (sizeof(struct SpaceBitmapDesc) << 3);
 	block_group = block >> (sb->s_blocksize_bits + 3);
 	group_start = block_group ? 0 : sizeof(struct SpaceBitmapDesc);
@@ -381,7 +324,7 @@
 	bitmap_nr = load_block_bitmap(sb, bitmap, block_group);
 	if (bitmap_nr < 0)
 		goto error_return;
-	bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr);
+	bh = bitmap->s_block_bitmap[bitmap_nr];
 	ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start);
 
 	if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize)
@@ -421,7 +364,7 @@
 		bitmap_nr = load_block_bitmap(sb, bitmap, block_group);
 		if (bitmap_nr < 0)
 			goto error_return;
-		bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr);
+		bh = bitmap->s_block_bitmap[bitmap_nr];
 		if (i < nr_groups)
 		{
 			ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start);
@@ -471,7 +414,6 @@
 	newblock = bit + (block_group << (sb->s_blocksize_bits + 3)) -
 		(sizeof(struct SpaceBitmapDesc) << 3);
 
-	tmp = udf_get_pblock(sb, newblock, partition, 0);
 	if (!udf_clear_bit(bit, bh->b_data))
 	{
 		udf_debug("bit already cleared for block %d\n", bit);
@@ -497,19 +439,479 @@
 	return 0;
 }
 
+static void udf_table_free_blocks(const struct inode * inode,
+	struct inode * table, lb_addr bloc, Uint32 offset, Uint32 count)
+{
+	struct super_block * sb;
+	Uint32 start, end;
+	Uint32 nextoffset, oextoffset, elen;
+	lb_addr nbloc, obloc, eloc;
+	struct buffer_head *obh, *nbh;
+	char etype;
+	int i;
+
+	udf_debug("ino=%ld, bloc=%d, offset=%d, count=%d\n",
+		inode->i_ino, bloc.logicalBlockNum, offset, count);
+
+	sb = inode->i_sb;
+	if (!sb)
+	{
+		udf_debug("nonexistent device");
+		return;
+	}
+
+	if (table == NULL)
+		return;
+
+	lock_super(sb);
+	if (bloc.logicalBlockNum < 0 ||
+		(bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum))
+	{
+		udf_debug("%d < %d || %d + %d > %d\n",
+			bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
+			UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
+		goto error_return;
+	}
+
+	/* We do this up front - There are some error conditions that could occure,
+	   but.. oh well */
+	DQUOT_FREE_BLOCK(sb, inode, count);
+	if (UDF_SB_LVIDBH(sb))
+	{
+		UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
+			cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)])+count);
+		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
+	}
+
+	start = bloc.logicalBlockNum + offset;
+	end = bloc.logicalBlockNum + offset + count - 1;
+
+	oextoffset = nextoffset = sizeof(struct UnallocatedSpaceEntry);
+	elen = 0;
+	obloc = nbloc = UDF_I_LOCATION(table);
+
+	obh = nbh = udf_tread(sb, udf_get_lb_pblock(sb, nbloc, 0), sb->s_blocksize);
+	atomic_inc(&nbh->b_count);
+
+	while (count && (etype =
+		udf_next_aext(table, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1)
+	{
+		if (((eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) ==
+			start))
+		{
+			if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits))
+			{
+				count -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
+				start += ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
+				elen = (etype << 30) | (0x40000000 - sb->s_blocksize);
+			}
+			else
+			{
+				elen = (etype << 30) |
+					(elen + (count << sb->s_blocksize_bits));
+				start += count;
+				count = 0;
+			}
+			udf_write_aext(table, obloc, &oextoffset, eloc, elen, obh, 1);
+		}
+		else if (eloc.logicalBlockNum == (end + 1))
+		{
+			if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits))
+			{
+				count -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
+				end -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
+				eloc.logicalBlockNum -=
+					((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
+				elen = (etype << 30) | (0x40000000 - sb->s_blocksize);
+			}
+			else
+			{
+				eloc.logicalBlockNum = start;
+				elen = (etype << 30) |
+					(elen + (count << sb->s_blocksize_bits));
+				end -= count;
+				count = 0;
+			}
+			udf_write_aext(table, obloc, &oextoffset, eloc, elen, obh, 1);
+		}
+
+		if (memcmp(&nbloc, &obloc, sizeof(lb_addr)))
+		{
+			i = -1;
+			obloc = nbloc;
+			udf_release_data(obh);
+			atomic_inc(&nbh->b_count);
+			obh = nbh;
+			oextoffset = 0;
+		}
+		else
+			oextoffset = nextoffset;
+	}
+
+	if (count)
+	{
+		/* NOTE: we CANNOT use udf_add_aext here, as it can try to allocate
+				 a new block, and since we hold the super block lock already
+				 very bad things would happen :)
+
+				 We copy the behavior of udf_add_aext, but instead of
+				 trying to allocate a new block close to the existing one,
+				 we just steal a block from the extent we are trying to add.
+
+				 It would be nice if the blocks were close together, but it
+				 isn't required.
+		*/
+
+		int adsize;
+		short_ad *sad = NULL;
+		long_ad *lad = NULL;
+		struct AllocExtDesc *aed;
+
+		eloc.logicalBlockNum = start;
+		elen = (EXTENT_RECORDED_ALLOCATED << 30) |
+			(count << sb->s_blocksize_bits);
+
+		if (UDF_I_ALLOCTYPE(table) == ICB_FLAG_AD_SHORT)
+			adsize = sizeof(short_ad);
+		else if (UDF_I_ALLOCTYPE(table) == ICB_FLAG_AD_LONG)
+			adsize = sizeof(long_ad);
+		else
+		{
+			udf_release_data(obh);
+			udf_release_data(nbh);
+			goto error_return;
+		}
+
+		if (nextoffset + (2 * adsize) > sb->s_blocksize)
+		{
+			char *sptr, *dptr;
+			int loffset;
+	
+			udf_release_data(obh);
+			obh = nbh;
+			obloc = nbloc;
+			oextoffset = nextoffset;
+
+			/* Steal a block from the extent being free'd */
+			nbloc.logicalBlockNum = eloc.logicalBlockNum;
+			eloc.logicalBlockNum ++;
+			elen -= sb->s_blocksize;
+
+			if (!(nbh = udf_tread(sb,
+				udf_get_lb_pblock(sb, nbloc, 0),
+				sb->s_blocksize)))
+			{
+				udf_release_data(obh);
+				goto error_return;
+			}
+			aed = (struct AllocExtDesc *)(nbh->b_data);
+			aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum);
+			if (nextoffset + adsize > sb->s_blocksize)
+			{
+				loffset = nextoffset;
+				aed->lengthAllocDescs = cpu_to_le32(adsize);
+				sptr = (obh)->b_data + nextoffset - adsize;
+				dptr = nbh->b_data + sizeof(struct AllocExtDesc);
+				memcpy(dptr, sptr, adsize);
+				nextoffset = sizeof(struct AllocExtDesc) + adsize;
+			}
+			else
+			{
+				loffset = nextoffset + adsize;
+				aed->lengthAllocDescs = cpu_to_le32(0);
+				sptr = (obh)->b_data + nextoffset;
+				nextoffset = sizeof(struct AllocExtDesc);
+	
+				if (memcmp(&UDF_I_LOCATION(table), &obloc, sizeof(lb_addr)))
+				{
+					aed = (struct AllocExtDesc *)(obh)->b_data;
+					aed->lengthAllocDescs =
+						cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
+				}
+				else
+				{
+					UDF_I_LENALLOC(table) += adsize;
+					mark_inode_dirty(table);
+				}
+			}
+			udf_new_tag(nbh->b_data, TID_ALLOC_EXTENT_DESC, 2, 1,
+				nbloc.logicalBlockNum, sizeof(tag));
+			switch (UDF_I_ALLOCTYPE(table))
+			{
+				case ICB_FLAG_AD_SHORT:
+				{
+					sad = (short_ad *)sptr;
+					sad->extLength = cpu_to_le32(
+						EXTENT_NEXT_EXTENT_ALLOCDECS << 30 |
+						sb->s_blocksize);
+					sad->extPosition = cpu_to_le32(nbloc.logicalBlockNum);
+					break;
+				}
+				case ICB_FLAG_AD_LONG:
+				{
+					lad = (long_ad *)sptr;
+					lad->extLength = cpu_to_le32(
+						EXTENT_NEXT_EXTENT_ALLOCDECS << 30 |
+						sb->s_blocksize);
+					lad->extLocation = cpu_to_lelb(nbloc);
+					break;
+				}
+			}
+			udf_update_tag(obh->b_data, loffset);
+			mark_buffer_dirty(obh);
+		}
+
+		if (elen) /* It's possible that stealing the block emptied the extent */
+		{
+			udf_write_aext(table, nbloc, &nextoffset, eloc, elen, nbh, 1);
+
+			if (!memcmp(&UDF_I_LOCATION(table), &nbloc, sizeof(lb_addr)))
+			{
+				UDF_I_LENALLOC(table) += adsize;
+				mark_inode_dirty(table);
+			}
+			else
+			{
+				aed = (struct AllocExtDesc *)nbh->b_data;
+				aed->lengthAllocDescs =
+					cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
+				udf_update_tag(nbh->b_data, nextoffset);
+				mark_buffer_dirty(nbh);
+			}
+		}
+	}
+
+	udf_release_data(nbh);
+	udf_release_data(obh);
+
+error_return:
+	sb->s_dirt = 1;
+	unlock_super(sb);
+	return;
+}
+
+static int udf_table_prealloc_blocks(const struct inode * inode,
+	struct inode *table, Uint16 partition, Uint32 first_block,
+	Uint32 block_count)
+{
+	struct super_block *sb;
+	int alloc_count = 0;
+	Uint32 extoffset, elen, adsize;
+	lb_addr bloc, eloc;
+	struct buffer_head *bh;
+	char etype = -1;
+
+	udf_debug("ino=%ld, partition=%d, first_block=%d, block_count=%d\n",
+		inode->i_ino, partition, first_block, block_count);
+
+	sb = inode->i_sb;
+	if (!sb)
+	{
+		udf_debug("nonexistent device\n");
+		return 0;
+	}
+
+	if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition))
+		return 0;
+
+	if (table == NULL)
+		return 0;
+
+	if (UDF_I_ALLOCTYPE(table) == ICB_FLAG_AD_SHORT)
+		adsize = sizeof(short_ad);
+	else if (UDF_I_ALLOCTYPE(table) == ICB_FLAG_AD_LONG)
+		adsize = sizeof(long_ad);
+	else
+		return 0;
+
+	lock_super(sb);
+
+	extoffset = sizeof(struct UnallocatedSpaceEntry);
+	bloc = UDF_I_LOCATION(table);
+
+	bh = udf_tread(sb, udf_get_lb_pblock(sb, bloc, 0), sb->s_blocksize);
+	eloc.logicalBlockNum = 0xFFFFFFFF;
+
+	while (first_block != eloc.logicalBlockNum && (etype =
+		udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
+	{
+		udf_debug("eloc=%d, elen=%d, first_block=%d\n",
+			eloc.logicalBlockNum, elen, first_block);
+		; /* empty loop body */
+	}
+
+	if (first_block == eloc.logicalBlockNum)
+	{
+		extoffset -= adsize;
+
+		alloc_count = (elen >> sb->s_blocksize_bits);
+		if (alloc_count > block_count)
+		{
+			alloc_count = block_count;
+			eloc.logicalBlockNum += alloc_count;
+			elen -= (alloc_count << sb->s_blocksize_bits);
+			udf_write_aext(table, bloc, &extoffset, eloc, (etype << 30) | elen, bh, 1);
+		}
+		else
+			udf_delete_aext(table, bloc, extoffset, eloc, (etype << 30) | elen, bh);
+	}
+	else
+		alloc_count = 0;
+
+	udf_release_data(bh);
+
+	if (alloc_count && UDF_SB_LVIDBH(sb))
+	{
+		UDF_SB_LVID(sb)->freeSpaceTable[partition] =
+			cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count);
+		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
+	}
+	sb->s_dirt = 1;
+	unlock_super(sb);
+	udf_debug("alloc_count=%d\n", alloc_count);
+	return alloc_count;
+}
+
+static int udf_table_new_block(const struct inode * inode,
+	struct inode *table, Uint16 partition, Uint32 goal, int *err)
+{
+	struct super_block *sb;
+	Uint32 spread = 0xFFFFFFFF, nspread;
+	Uint32 newblock = 0, adsize;
+	Uint32 extoffset, goal_extoffset, elen, goal_elen = 0;
+	lb_addr bloc, goal_bloc, eloc, goal_eloc;
+	struct buffer_head *bh, *goal_bh;
+	char etype;
+
+	udf_debug("ino=%ld, partition=%d, goal=%d\n",
+		inode->i_ino, partition, goal);
+
+	*err = -ENOSPC;
+	sb = inode->i_sb;
+	if (!sb)
+	{
+		udf_debug("nonexistent device\n");
+		return newblock;
+	}
+
+	if (table == NULL)
+		return newblock;
+
+	if (UDF_I_ALLOCTYPE(table) == ICB_FLAG_AD_SHORT)
+		adsize = sizeof(short_ad);
+	else if (UDF_I_ALLOCTYPE(table) == ICB_FLAG_AD_LONG)
+		adsize = sizeof(long_ad);
+	else
+		return newblock;
+
+	lock_super(sb);
+
+	if (goal < 0 || goal >= UDF_SB_PARTLEN(sb, partition))
+		goal = 0;
+
+	/* We search for the closest matching block to goal. If we find a exact hit,	   we stop. Otherwise we keep going till we run out of extents.
+	   We store the buffer_head, bloc, and extoffset of the current closest
+	   match and use that when we are done.
+	*/
+
+	extoffset = sizeof(struct UnallocatedSpaceEntry);
+	bloc = UDF_I_LOCATION(table);
+
+	goal_bh = bh = udf_tread(sb, udf_get_lb_pblock(sb, bloc, 0), sb->s_blocksize);
+	atomic_inc(&goal_bh->b_count);
+
+	while (spread && (etype =
+		udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
+	{
+		if (goal >= eloc.logicalBlockNum)
+		{
+			if (goal < eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits))
+				nspread = 0;
+			else
+				nspread = goal - eloc.logicalBlockNum -
+					(elen >> sb->s_blocksize_bits);
+		}
+		else
+			nspread = eloc.logicalBlockNum - goal;
+
+		if (nspread < spread)
+		{
+			spread = nspread;
+			if (goal_bh != bh)
+			{
+				udf_release_data(goal_bh);
+				goal_bh = bh;
+				atomic_inc(&goal_bh->b_count);
+			}
+			goal_bloc = bloc;
+			goal_extoffset = extoffset - adsize;
+			goal_eloc = eloc;
+			goal_elen = (etype << 30) | elen;
+		}
+	}
+
+	udf_release_data(bh);
+
+	if (spread == 0xFFFFFFFF)
+	{
+		udf_release_data(goal_bh);
+		unlock_super(sb);
+		return 0;
+	}
+
+	/* Only allocate blocks from the beginning of the extent.
+	   That way, we only delete (empty) extents, never have to insert an
+	   extent because of splitting */
+	/* This works, but very poorly.... */
+
+	newblock = goal_eloc.logicalBlockNum;
+	goal_eloc.logicalBlockNum ++;
+	goal_elen -= sb->s_blocksize;
+
+	if (goal_elen)
+		udf_write_aext(table, goal_bloc, &goal_extoffset, goal_eloc, goal_elen, goal_bh, 1);
+	else
+		udf_delete_aext(table, goal_bloc, goal_extoffset, goal_eloc, goal_elen, goal_bh);
+	udf_release_data(goal_bh);
+
+	if (UDF_SB_LVIDBH(sb))
+	{
+		UDF_SB_LVID(sb)->freeSpaceTable[partition] =
+			cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-1);
+		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
+	}
+
+	sb->s_dirt = 1;
+	unlock_super(sb);
+	*err = 0;
+	return newblock;
+}
+
 inline void udf_free_blocks(const struct inode * inode, lb_addr bloc,
-    Uint32 offset, Uint32 count)
+	Uint32 offset, Uint32 count)
 {
 	if (UDF_SB_PARTFLAGS(inode->i_sb, bloc.partitionReferenceNum) & UDF_PART_FLAG_UNALLOC_BITMAP)
 	{
 		return udf_bitmap_free_blocks(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[bloc.partitionReferenceNum].s_uspace.bitmap,
+			UDF_SB_PARTMAPS(inode->i_sb)[bloc.partitionReferenceNum].s_uspace.s_bitmap,
+			bloc, offset, count);
+	}
+	else if (UDF_SB_PARTFLAGS(inode->i_sb, bloc.partitionReferenceNum) & UDF_PART_FLAG_UNALLOC_TABLE)
+	{
+		return udf_table_free_blocks(inode,
+			UDF_SB_PARTMAPS(inode->i_sb)[bloc.partitionReferenceNum].s_uspace.s_table,
 			bloc, offset, count);
 	}
 	else if (UDF_SB_PARTFLAGS(inode->i_sb, bloc.partitionReferenceNum) & UDF_PART_FLAG_FREED_BITMAP)
 	{
 		return udf_bitmap_free_blocks(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[bloc.partitionReferenceNum].s_fspace.bitmap,
+			UDF_SB_PARTMAPS(inode->i_sb)[bloc.partitionReferenceNum].s_fspace.s_bitmap,
+			bloc, offset, count);
+	}
+	else if (UDF_SB_PARTFLAGS(inode->i_sb, bloc.partitionReferenceNum) & UDF_PART_FLAG_FREED_TABLE)
+	{
+		return udf_table_free_blocks(inode,
+			UDF_SB_PARTMAPS(inode->i_sb)[bloc.partitionReferenceNum].s_fspace.s_table,
 			bloc, offset, count);
 	}
 	else
@@ -522,13 +924,25 @@
 	if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
 	{
 		return udf_bitmap_prealloc_blocks(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_uspace.bitmap,
+			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_uspace.s_bitmap,
+			partition, first_block, block_count);
+	}
+	else if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
+	{
+		return udf_table_prealloc_blocks(inode,
+			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_uspace.s_table,
 			partition, first_block, block_count);
 	}
 	else if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
 	{
 		return udf_bitmap_prealloc_blocks(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_fspace.bitmap,
+			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_fspace.s_bitmap,
+			partition, first_block, block_count);
+	}
+	else if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_FREED_TABLE)
+	{
+		return udf_table_prealloc_blocks(inode,
+			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_fspace.s_table,
 			partition, first_block, block_count);
 	}
 	else
@@ -541,13 +955,25 @@
 	if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
 	{
 		return udf_bitmap_new_block(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_uspace.bitmap,
+			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_uspace.s_bitmap,
+			partition, goal, err);
+	}
+	else if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
+	{
+		return udf_table_new_block(inode,
+			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_uspace.s_table,
 			partition, goal, err);
 	}
 	else if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
 	{
 		return udf_bitmap_new_block(inode,
-			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_fspace.bitmap,
+			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_fspace.s_bitmap,
+			partition, goal, err);
+	}
+	else if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_FREED_TABLE)
+	{
+		return udf_table_new_block(inode,
+			UDF_SB_PARTMAPS(inode->i_sb)[partition].s_fspace.s_table,
 			partition, goal, err);
 	}
 	else
@@ -556,4 +982,3 @@
 		return 0;
 	}
 }
-
diff -u --recursive --new-file v2.4.5/linux/fs/udf/crc.c linux/fs/udf/crc.c
--- v2.4.5/linux/fs/udf/crc.c	Sat Sep  4 12:42:30 1999
+++ linux/fs/udf/crc.c	Mon Jun 11 19:15:27 2001
@@ -17,7 +17,7 @@
  * CONTACTS
  *	E-mail regarding any portion of the Linux UDF file system should be
  *	directed to the development team mailing list (run by majordomo):
- *		linux_udf@hootie.lvld.hp.com
+ *		linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *	This file is distributed under the terms of the GNU General Public
diff -u --recursive --new-file v2.4.5/linux/fs/udf/dir.c linux/fs/udf/dir.c
--- v2.4.5/linux/fs/udf/dir.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/udf/dir.c	Mon Jun 11 19:15:27 2001
@@ -7,7 +7,7 @@
  * CONTACTS
  *	E-mail regarding any portion of the Linux UDF file system should be
  *	directed to the development team mailing list (run by majordomo):
- *		linux_udf@hootie.lvld.hp.com
+ *		linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *	This file is distributed under the terms of the GNU General Public
@@ -49,10 +49,10 @@
 /* readdir and lookup functions */
 
 struct file_operations udf_dir_operations = {
-	read:				generic_read_dir,
-	readdir:			udf_readdir,
-	ioctl:				udf_ioctl,
-	fsync:				udf_sync_file,
+	read:			generic_read_dir,
+	readdir:		udf_readdir,
+	ioctl:			udf_ioctl,
+	fsync:			udf_fsync_file,
 };
 
 /*
@@ -88,8 +88,9 @@
 
 	if ( filp->f_pos == 0 ) 
 	{
-		if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR))
+		if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0)
 			return 0;
+		filp->f_pos ++;
 	}
  
 	result = do_udf_readdir(dir, filp, filldir, dirent);
@@ -104,19 +105,21 @@
 	struct FileIdentDesc *fi=NULL;
 	struct FileIdentDesc cfi;
 	int block, iblock;
-	loff_t nf_pos = filp->f_pos;
+	loff_t nf_pos = filp->f_pos - 1;
 	int flen;
 	char fname[255];
 	char *nameptr;
 	Uint16 liu;
 	Uint8 lfi;
 	loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
-	struct buffer_head * bh = NULL;
+	struct buffer_head * bh = NULL, * tmp, * bha[16];
 	lb_addr bloc, eloc;
 	Uint32 extoffset, elen, offset;
+	int i, num;
+	unsigned int dt_type;
 
 	if (nf_pos >= size)
-		return 1;
+		return 0;
 
 	if (nf_pos == 0)
 		nf_pos = (udf_ext0_offset(dir) >> 2);
@@ -125,6 +128,7 @@
 	if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2),
 		&bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
 	{
+		offset >>= dir->i_sb->s_blocksize_bits;
 		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
 		if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
 		{
@@ -139,18 +143,40 @@
 	else
 	{
 		udf_release_data(bh);
-		return 0;
+		return -ENOENT;
 	}
 
 	if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
 	{
 		udf_release_data(bh);
-		return 0;
+		return -EIO;
+	}
+
+	if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1)))
+	{
+		i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
+		if (i+offset > (elen >> dir->i_sb->s_blocksize_bits))
+			i = (elen >> dir->i_sb->s_blocksize_bits)-offset;
+		for (num=0; i>0; i--)
+		{
+			block = udf_get_lb_pblock(dir->i_sb, eloc, offset+i);
+			tmp = udf_tgetblk(dir->i_sb, block, dir->i_sb->s_blocksize);
+			if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
+				bha[num++] = tmp;
+			else
+				brelse(tmp);
+		}
+		if (num)
+		{
+			ll_rw_block(READA, num, bha);
+			for (i=0; i<num; i++)
+				brelse(bha[i]);
+		}
 	}
 
 	while ( nf_pos < size )
 	{
-		filp->f_pos = nf_pos;
+		filp->f_pos = nf_pos + 1;
 
 		fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
 
@@ -160,7 +186,7 @@
 				udf_release_data(fibh.ebh);
 			udf_release_data(fibh.sbh);
 			udf_release_data(bh);
-			return 1;
+			return -ENOENT;
 		}
 
 		liu = le16_to_cpu(cfi.lengthOfImpUse);
@@ -196,44 +222,39 @@
 				continue;
 		}
 
-		iblock = udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0);
- 
- 		if (!lfi) /* parent directory */
- 		{
-			if (filldir(dirent, "..", 2, filp->f_pos, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR))
+		if ( cfi.fileCharacteristics & FILE_PARENT )
+		{
+			iblock = udf_get_lb_pblock(dir->i_sb, UDF_I_LOCATION(filp->f_dentry->d_parent->d_inode), 0);
+			flen = 2;
+			memcpy(fname, "..", flen);
+			dt_type = DT_DIR;
+		}
+		else
+		{
+			iblock = udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0);
+			flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
+			dt_type = DT_UNKNOWN;
+		}
+
+		if (flen)
+		{
+			if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0)
 			{
 				if (fibh.sbh != fibh.ebh)
 					udf_release_data(fibh.ebh);
 				udf_release_data(fibh.sbh);
 				udf_release_data(bh);
- 				return 1;
-			}
-		}
-		else
-		{
-			if ((flen = udf_get_filename(nameptr, fname, lfi)))
-			{
-				if (filldir(dirent, fname, flen, filp->f_pos, iblock, DT_UNKNOWN))
-				{
-					if (fibh.sbh != fibh.ebh)
-						udf_release_data(fibh.ebh);
-					udf_release_data(fibh.sbh);
-					udf_release_data(bh);
-		 			return 1; /* halt enum */
-				}
+	 			return 0;
 			}
 		}
 	} /* end while */
 
-	filp->f_pos = nf_pos;
+	filp->f_pos = nf_pos + 1;
 
 	if (fibh.sbh != fibh.ebh)
 		udf_release_data(fibh.ebh);
 	udf_release_data(fibh.sbh);
 	udf_release_data(bh);
 
-	if ( filp->f_pos >= size)
-		return 1;
-	else
-		return 0;
+	return 0;
 }
diff -u --recursive --new-file v2.4.5/linux/fs/udf/directory.c linux/fs/udf/directory.c
--- v2.4.5/linux/fs/udf/directory.c	Thu Mar  2 11:17:32 2000
+++ linux/fs/udf/directory.c	Mon Jun 11 19:15:27 2001
@@ -7,7 +7,7 @@
  * CONTACTS
  *	E-mail regarding any portion of the Linux UDF file system should be
  *	directed to the development team mailing list (run by majordomo):
- *		linux_udf@hootie.lvld.hp.com
+ *		linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *	This file is distributed under the terms of the GNU General Public
@@ -92,7 +92,8 @@
 	Uint32 *offset, struct buffer_head **bh)
 {
 	struct FileIdentDesc *fi;
-	int block;
+	int i, num, block;
+	struct buffer_head * tmp, * bha[16];
 
 	fibh->soffset = fibh->eoffset;
 
@@ -119,6 +120,28 @@
 		if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
 			return NULL;
 		fibh->soffset = fibh->eoffset = 0;
+
+		if (!(*offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1)))
+		{
+			i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
+			if (i+*offset > (*elen >> dir->i_sb->s_blocksize_bits))
+				i = (*elen >> dir->i_sb->s_blocksize_bits)-*offset;
+			for (num=0; i>0; i--)
+			{
+				block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset+i);
+				tmp = udf_tgetblk(dir->i_sb, block, dir->i_sb->s_blocksize);
+				if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
+					bha[num++] = tmp;
+				else
+					brelse(tmp);
+			}
+			if (num)
+			{
+				ll_rw_block(READA, num, bha);
+				for (i=0; i<num; i++)
+					brelse(bha[i]);
+			}
+		}
 	}
 	else if (fibh->sbh != fibh->ebh)
 	{
diff -u --recursive --new-file v2.4.5/linux/fs/udf/file.c linux/fs/udf/file.c
--- v2.4.5/linux/fs/udf/file.c	Sun Jan 28 13:28:09 2001
+++ linux/fs/udf/file.c	Mon Jun 11 19:15:27 2001
@@ -7,7 +7,7 @@
  * CONTACTS
  *  E-mail regarding any portion of the Linux UDF file system should be
  *  directed to the development team mailing list (run by majordomo):
- *    linux_udf@hootie.lvld.hp.com
+ *    linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *  This file is distributed under the terms of the GNU General Public
@@ -119,8 +119,8 @@
 }
 
 struct address_space_operations udf_adinicb_aops = {
-	readpage:			udf_adinicb_readpage,
-	writepage:			udf_adinicb_writepage,
+	readpage:		udf_adinicb_readpage,
+	writepage:		udf_adinicb_writepage,
 	sync_page:		block_sync_page,
 	prepare_write:		udf_adinicb_prepare_write,
 	commit_write:		udf_adinicb_commit_write,
@@ -208,7 +208,6 @@
 {
 	int result = -1;
 	struct buffer_head *bh = NULL;
-	Uint16 ident;
 	long_ad eaicb;
 	Uint8 *ea = NULL;
 
@@ -232,17 +231,28 @@
 			if ( (result == verify_area(VERIFY_WRITE, (char *)arg, 32)) == 0)
 				result = copy_to_user((char *)arg, UDF_SB_VOLIDENT(inode->i_sb), 32);
 			return result;
+		case UDF_RELOCATE_BLOCKS:
+		{
+			long old, new;
+
+			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+			get_user(old, (long *)arg);
+			if ((result = udf_relocate_blocks(inode->i_sb, old, &new)) == 0)
+				result = put_user(new, (long *)arg);
 
+			return result;
+		}
 	}
 
 	/* ok, we need to read the inode */
-	bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
+	bh = udf_tread(inode->i_sb,
+		udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0),
+		inode->i_sb->s_blocksize);
 
-	if (!bh || (ident != TID_FILE_ENTRY && ident != TID_EXTENDED_FILE_ENTRY))
+	if (!bh)
 	{
-		udf_debug("bread failed (ino=%ld) or ident (%d) != TID_(EXTENDED_)FILE_ENTRY",
-			inode->i_ino, ident);
-		return -EFAULT;
+		udf_debug("bread failed (inode=%ld)\n", inode->i_ino);
+		return -EIO;
 	}
 
 	if (UDF_I_EXTENDED_FE(inode) == 0)
@@ -277,7 +287,6 @@
 			break;
 
 		default:
-			udf_debug("ino=%ld, cmd=%d\n", inode->i_ino, cmd);
 			break;
 	}
 
@@ -299,7 +308,8 @@
  */
 static int udf_release_file(struct inode * inode, struct file * filp)
 {
-	if (filp->f_mode & FMODE_WRITE) {
+	if (filp->f_mode & FMODE_WRITE)
+	{
 		lock_kernel();
 		udf_discard_prealloc(inode);
 		unlock_kernel();
@@ -322,21 +332,21 @@
  */
 static int udf_open_file(struct inode * inode, struct file * filp)
 {
-	if ((inode->i_size & 0xFFFFFFFF00000000ULL) && !(filp->f_flags & O_LARGEFILE))
+	if ((inode->i_size & 0xFFFFFFFF80000000ULL) && !(filp->f_flags & O_LARGEFILE))
 		return -EFBIG;
 	return 0;
 }
 
 struct file_operations udf_file_operations = {
-	read:				generic_file_read,
-	ioctl:				udf_ioctl,
-	open:				udf_open_file,
-	mmap:				generic_file_mmap,
-	write:				udf_file_write,
-	release:			udf_release_file,
-	fsync:				udf_sync_file,
+	read:			generic_file_read,
+	ioctl:			udf_ioctl,
+	open:			udf_open_file,
+	mmap:			generic_file_mmap,
+	write:			udf_file_write,
+	release:		udf_release_file,
+	fsync:			udf_fsync_file,
 };
 
 struct inode_operations udf_file_inode_operations = {
-	truncate:			udf_truncate,
+	truncate:		udf_truncate,
 };
diff -u --recursive --new-file v2.4.5/linux/fs/udf/fsync.c linux/fs/udf/fsync.c
--- v2.4.5/linux/fs/udf/fsync.c	Thu Jun 29 16:23:11 2000
+++ linux/fs/udf/fsync.c	Mon Jun 11 19:15:27 2001
@@ -7,7 +7,7 @@
  * CONTACTS
  *  E-mail regarding any portion of the Linux UDF file system should be
  *  directed to the development team mailing list (run by majordomo):
- *      linux_udf@hootie.lvld.hp.com
+ *      linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *  This file is distributed under the terms of the GNU General Public
@@ -28,96 +28,28 @@
 #include <linux/fs.h>
 #include <linux/locks.h>
 #include <linux/smp_lock.h>
-#include <linux/udf_fs.h>
-#include "udf_i.h"
-
-static int sync_extent_block (struct inode * inode, Uint32 block, int wait)
-{
-	struct buffer_head * bh;
-	
-	if (!block)
-		return 0;
-	bh = get_hash_table (inode->i_dev, block, inode->i_sb->s_blocksize);
-	if (!bh)
-		return 0;
-	if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
-		/* There can be a parallell read(2) that started read-I/O
-		   on the buffer so we can't assume that there's been
-		   an I/O error without first waiting I/O completation. */
-		wait_on_buffer(bh);
-		if (!buffer_uptodate(bh))
-		{
-			brelse (bh);
-			return -1;
-		}
-	}
-	if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
-		if (wait)
-			/* when we return from fsync all the blocks
-			   must be _just_ stored on disk */
-			wait_on_buffer(bh);
-		brelse (bh);
-		return 0;
-	}
-	ll_rw_block (WRITE, 1, &bh);
-	atomic_dec(&bh->b_count);
-	return 0;
-}
-
-static int sync_all_extents(struct inode * inode, int wait)
-{
-	lb_addr bloc, eloc;
-	Uint32 extoffset, lextoffset, elen, offset, block;
-	int err = 0, etype;
-	struct buffer_head *bh = NULL;
-	
-	if ((etype = inode_bmap(inode, 0, &bloc, &extoffset, &eloc, &elen, &offset, &bh)) != -1)
-	{
-		block = udf_get_lb_pblock(inode->i_sb, bloc, 0);
-		err |= sync_extent_block(inode, block, wait);
-		lextoffset = extoffset;
-
-		while ((etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
-		{
-			if (lextoffset > extoffset)
-			{
-				block = udf_get_lb_pblock(inode->i_sb, bloc, 0);
-				err |= sync_extent_block(inode, block, wait);
-			}
-			lextoffset = extoffset;
-		}
-	}
-	udf_release_data(bh);
-	return err;
-}
 
 /*
  *	File may be NULL when we are called. Perhaps we shouldn't
  *	even pass file to fsync ?
  */
 
-int udf_sync_file(struct file * file, struct dentry *dentry, int datasync)
+int udf_fsync_file(struct file * file, struct dentry *dentry, int datasync)
 {
-	int wait, err = 0;
 	struct inode *inode = dentry->d_inode;
+	return udf_fsync_inode(inode, datasync);
+}
+
+int udf_fsync_inode(struct inode *inode, int datasync)
+{
+	int err;
+
+	err = fsync_inode_buffers(inode);
+	if (!(inode->i_state & I_DIRTY))
+		return err;
+	if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+		return err;
 
-	lock_kernel();
-	if (S_ISLNK(inode->i_mode) && !(inode->i_blocks)) 
-	{
-		/*
-		 * Don't sync fast links! or ICB_FLAG_AD_IN_ICB
-		 */
-		goto skip;
-	}
-
-	err = generic_buffer_fdatasync(inode, 0, ~0UL);
-
-	for (wait=0; wait<=1; wait++)
-	{
-		err |= sync_all_extents (inode, wait);
-	}
-skip:
 	err |= udf_sync_inode (inode);
-	unlock_kernel();
 	return err ? -EIO : 0;
 }
diff -u --recursive --new-file v2.4.5/linux/fs/udf/ialloc.c linux/fs/udf/ialloc.c
--- v2.4.5/linux/fs/udf/ialloc.c	Fri Nov 17 11:35:27 2000
+++ linux/fs/udf/ialloc.c	Mon Jun 11 19:15:27 2001
@@ -7,7 +7,7 @@
  * CONTACTS
  *	E-mail regarding any portion of the Linux UDF file system should be
  *	directed to the development team mailing list (run by majordomo):
- *		linux_udf@hootie.lvld.hp.com
+ *		linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *	This file is distributed under the terms of the GNU General Public
@@ -79,6 +79,7 @@
 
 	sb = dir->i_sb;
 	inode = new_inode(sb);
+
 	if (!inode)
 	{
 		*err = -ENOMEM;
@@ -114,7 +115,8 @@
 	}
 	inode->i_mode = mode;
 	inode->i_uid = current->fsuid;
-	if (dir->i_mode & S_ISGID) {
+	if (dir->i_mode & S_ISGID)
+	{
 		inode->i_gid = dir->i_gid;
 		if (S_ISDIR(mode))
 			mode |= S_ISGID;
diff -u --recursive --new-file v2.4.5/linux/fs/udf/inode.c linux/fs/udf/inode.c
--- v2.4.5/linux/fs/udf/inode.c	Sun Jan 28 13:28:09 2001
+++ linux/fs/udf/inode.c	Mon Jun 11 19:15:27 2001
@@ -7,7 +7,7 @@
  * CONTACTS
  *  E-mail regarding any portion of the Linux UDF file system should be
  *  directed to the development team mailing list (run by majordomo):
- *    linux_udf@hootie.lvld.hp.com
+ *    linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *  This file is distributed under the terms of the GNU General Public
@@ -106,23 +106,27 @@
 	lock_kernel();
 
 	if (is_bad_inode(inode))
-	{
-		clear_inode(inode);
-		goto out;
-	}
+		goto no_delete;
 
 	inode->i_size = 0;
 	udf_truncate(inode);
 	udf_update_inode(inode, IS_SYNC(inode));
 	udf_free_inode(inode);
-out:
+
 	unlock_kernel();
+	return;
+no_delete:
+	unlock_kernel();
+	clear_inode(inode);
 }
 
 void udf_discard_prealloc(struct inode * inode)
 {
-	if (inode->i_size && UDF_I_ALLOCTYPE(inode) != ICB_FLAG_AD_IN_ICB)
-		udf_trunc(inode);
+	if (inode->i_size && inode->i_size != UDF_I_LENEXTENTS(inode) &&
+		UDF_I_ALLOCTYPE(inode) != ICB_FLAG_AD_IN_ICB)
+	{
+		udf_truncate_extents(inode);
+	}
 }
 
 static int udf_writepage(struct page *page)
@@ -146,18 +150,19 @@
 }
 
 struct address_space_operations udf_aops = {
-	readpage:			udf_readpage,
-	writepage:			udf_writepage,
+	readpage:		udf_readpage,
+	writepage:		udf_writepage,
 	sync_page:		block_sync_page,
 	prepare_write:		udf_prepare_write,
 	commit_write:		generic_commit_write,
-	bmap:				udf_bmap,
+	bmap:			udf_bmap,
 };
 
 void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
 {
 	struct buffer_head *bh = NULL;
 	struct page *page;
+	char *kaddr;
 	int block;
 
 	/* from now on we have normal address_space methods */
@@ -182,7 +187,7 @@
 		PAGE_BUG(page);
 	if (!Page_Uptodate(page))
 	{
-		char *kaddr = kmap(page);
+		kaddr = kmap(page);
 		memset(kaddr + UDF_I_LENALLOC(inode), 0x00,
 			PAGE_CACHE_SIZE - UDF_I_LENALLOC(inode));
 		memcpy(kaddr, bh->b_data + udf_file_entry_alloc_offset(inode),
@@ -199,7 +204,7 @@
 	else
 		UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG;
 	inode->i_blocks = inode->i_sb->s_blocksize / 512;
-	mark_buffer_dirty(bh);
+	mark_buffer_dirty_inode(bh, inode);
 	udf_release_data(bh);
 
 	inode->i_data.a_ops->writepage(page);
@@ -245,9 +250,14 @@
 	sbh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
 	if (!sbh)
 		return NULL;
-	dbh = udf_tread(inode->i_sb, newblock, inode->i_sb->s_blocksize);
+	dbh = udf_tgetblk(inode->i_sb, newblock, inode->i_sb->s_blocksize);
 	if (!dbh)
 		return NULL;
+	lock_buffer(dbh);
+	memset(dbh->b_data, 0x00, inode->i_sb->s_blocksize);
+	mark_buffer_uptodate(dbh, 1);
+	unlock_buffer(dbh);
+	mark_buffer_dirty_inode(dbh, inode);
 
 	sfibh.soffset = sfibh.eoffset = (f_pos & ((inode->i_sb->s_blocksize - 1) >> 2)) << 2;
 	sfibh.sbh = sfibh.ebh = sbh;
@@ -266,7 +276,7 @@
 		dfibh.soffset = dfibh.eoffset;
 		dfibh.eoffset += (sfibh.eoffset - sfibh.soffset);
 		dfi = (struct FileIdentDesc *)(dbh->b_data + dfibh.soffset);
-		if (udf_write_fi(sfi, dfi, &dfibh, sfi->impUse,
+		if (udf_write_fi(inode, sfi, dfi, &dfibh, sfi->impUse,
 			sfi->fileIdent + sfi->lengthOfImpUse))
 		{
 			udf_release_data(sbh);
@@ -274,7 +284,7 @@
 			return NULL;
 		}
 	}
-	mark_buffer_dirty(dbh);
+	mark_buffer_dirty_inode(dbh, inode);
 
 	memset(sbh->b_data + udf_file_entry_alloc_offset(inode),
 		0, UDF_I_LENALLOC(inode));
@@ -288,6 +298,7 @@
 	eloc.logicalBlockNum = *block;
 	eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
 	elen = inode->i_size;
+	UDF_I_LENEXTENTS(inode) = elen;
 	extoffset = udf_file_entry_alloc_offset(inode);
 	udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &sbh, 0);
 	/* UniqueID stuff */
@@ -361,23 +372,21 @@
 	int create, int * err)
 {
 	struct buffer_head dummy;
-	int error;
 
 	dummy.b_state = 0;
 	dummy.b_blocknr = -1000;
-	error = udf_get_block(inode, block, &dummy, create);
-	*err = error;
-	if (!error & buffer_mapped(&dummy))
+	*err = udf_get_block(inode, block, &dummy, create);
+	if (!*err && buffer_mapped(&dummy))
 	{
 		struct buffer_head *bh;
 		bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
 		if (buffer_new(&dummy))
 		{
-			if (!buffer_uptodate(bh))
-				wait_on_buffer(bh);
+			lock_buffer(bh);
 			memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
 			mark_buffer_uptodate(bh, 1);
-			mark_buffer_dirty(bh);
+			unlock_buffer(bh);
+			mark_buffer_dirty_inode(bh, inode);
 		}
 		return bh;
 	}
@@ -387,22 +396,22 @@
 static struct buffer_head * inode_getblk(struct inode * inode, long block,
 	int *err, long *phys, int *new)
 {
-	struct buffer_head *pbh = NULL, *cbh = NULL, *result = NULL;
+	struct buffer_head *pbh = NULL, *cbh = NULL, *nbh = NULL, *result = NULL;
 	long_ad laarr[EXTENT_MERGE_SIZE];
 	Uint32 pextoffset = 0, cextoffset = 0, nextoffset = 0;
 	int count = 0, startnum = 0, endnum = 0;
 	Uint32 elen = 0;
-	lb_addr eloc, pbloc = UDF_I_LOCATION(inode), cbloc = UDF_I_LOCATION(inode);
+	lb_addr eloc, pbloc, cbloc, nbloc;
 	int c = 1;
 	int lbcount = 0, b_off = 0, offset = 0;
 	Uint32 newblocknum, newblock;
-	int etype;
+	char etype;
 	int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum;
 	char lastblock = 0;
 
 	pextoffset = cextoffset = nextoffset = udf_file_entry_alloc_offset(inode);
 	b_off = block << inode->i_sb->s_blocksize_bits;
-	pbloc = cbloc = UDF_I_LOCATION(inode);
+	pbloc = cbloc = nbloc = UDF_I_LOCATION(inode);
 
 	/* find the extent which contains the block we are looking for.
        alternate between laarr[0] and laarr[1] for locations of the
@@ -412,17 +421,25 @@
 		if (pbh != cbh)
 		{
 			udf_release_data(pbh);
-			pbh = cbh;
 			atomic_inc(&cbh->b_count);
-			pbloc = cbloc;
+			pbh = cbh;
+		}
+		if (cbh != nbh)
+		{
+			udf_release_data(cbh);
+			atomic_inc(&nbh->b_count);
+			cbh = nbh;
 		}
 
 		lbcount += elen;
 
+		pbloc = cbloc;
+		cbloc = nbloc;
+
 		pextoffset = cextoffset;
 		cextoffset = nextoffset;
 
-		if ((etype = udf_next_aext(inode, &cbloc, &nextoffset, &eloc, &elen, &cbh, 1)) == -1)
+		if ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) == -1)
 			break;
 
 		c = !c;
@@ -433,7 +450,7 @@
 		if (etype != EXTENT_NOT_RECORDED_NOT_ALLOCATED)
 			pgoal = eloc.logicalBlockNum +
 				((elen + inode->i_sb->s_blocksize - 1) >>
-				inode->i_sb->s_blocksize);
+				inode->i_sb->s_blocksize_bits);
 
 		count ++;
 	} while (lbcount + elen <= b_off);
@@ -451,10 +468,11 @@
 			elen = (EXTENT_RECORDED_ALLOCATED << 30) |
 				((elen + inode->i_sb->s_blocksize - 1) &
 				~(inode->i_sb->s_blocksize - 1));
-			etype = udf_write_aext(inode, cbloc, &cextoffset, eloc, elen, &cbh, 1);
+			etype = udf_write_aext(inode, nbloc, &cextoffset, eloc, elen, nbh, 1);
 		}
 		udf_release_data(pbh);
 		udf_release_data(cbh);
+		udf_release_data(nbh);
 		newblock = udf_get_lb_pblock(inode->i_sb, eloc, offset);
 		*phys = newblock;
 		return NULL;
@@ -470,6 +488,9 @@
 				(((laarr[c].extLength & UDF_EXTENT_LENGTH_MASK) +
 					inode->i_sb->s_blocksize - 1) &
 				~(inode->i_sb->s_blocksize - 1));
+			UDF_I_LENEXTENTS(inode) =
+				(UDF_I_LENEXTENTS(inode) + inode->i_sb->s_blocksize - 1) &
+					~(inode->i_sb->s_blocksize - 1);
 		}
 		c = !c;
 		laarr[c].extLength = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) |
@@ -494,7 +515,7 @@
 	/* if the current block is located in a extent, read the next extent */
 	if (etype != -1)
 	{
-		if ((etype = udf_next_aext(inode, &cbloc, &nextoffset, &eloc, &elen, &cbh, 0)) != -1)
+		if ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 0)) != -1)
 		{
 			laarr[c+1].extLength = (etype << 30) | elen;
 			laarr[c+1].extLocation = eloc;
@@ -505,7 +526,11 @@
 		else
 			lastblock = 1;
 	}
-	udf_release_data(cbh);
+	udf_release_data(nbh);
+	if (!pbh)
+		pbh = cbh;
+	else
+		udf_release_data(cbh);
 
 	/* if the current extent is not recorded but allocated, get the
 		block in the extent corresponding to the requested block */
@@ -529,6 +554,7 @@
 			*err = -ENOSPC;
 			return NULL;
 		}
+		UDF_I_LENEXTENTS(inode) += inode->i_sb->s_blocksize;
 	}
 
 	/* if the extent the requsted block is located in contains multiple blocks,
@@ -629,17 +655,24 @@
 {
 	int start, length = 0, currlength = 0, i;
 
-	if (*endnum >= (c+1) && !lastblock)
-		return;
-
-	if ((laarr[c+1].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED)
+	if (*endnum >= (c+1))
 	{
-		start = c+1;
-		length = currlength = (((laarr[c+1].extLength & UDF_EXTENT_LENGTH_MASK) +
-			inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+		if (!lastblock)
+			return;
+		else
+			start = c;
 	}
 	else
-		start = c;
+	{
+		if ((laarr[c+1].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED)
+		{
+			start = c+1;
+			length = currlength = (((laarr[c+1].extLength & UDF_EXTENT_LENGTH_MASK) +
+				inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+		}
+		else
+			start = c;
+	}
 
 	for (i=start+1; i<=*endnum; i++)
 	{
@@ -667,6 +700,7 @@
 
 		if (numalloc)
 		{
+			UDF_I_LENEXTENTS(inode) += numalloc << inode->i_sb->s_blocksize_bits;
 			if (start == (c+1))
 				laarr[start].extLength +=
 					(numalloc << inode->i_sb->s_blocksize_bits);
@@ -784,7 +818,7 @@
 	{
 		udf_next_aext(inode, &pbloc, &pextoffset, &tmploc, &tmplen, pbh, 0);
 		udf_write_aext(inode, pbloc, &pextoffset, laarr[i].extLocation,
-			laarr[i].extLength, pbh, 1);
+			laarr[i].extLength, *pbh, 1);
 	}
 }
 
@@ -800,29 +834,6 @@
 	if (!bh)
 		return NULL;
 
-#if 0
-	if (create &&
-		S_ISDIR(inode->i_mode) &&
-		inode->i_blocks > prev_blocks)
-	{
-		int i;
-		struct buffer_head *tmp_bh = NULL;
-
-		for (i=1;
-			i < UDF_DEFAULT_PREALLOC_DIR_BLOCKS;
-			i++)
-		{
-			tmp_bh = udf_getblk(inode, block+i, create, err);
-			if (!tmp_bh)
-			{
-				udf_release_data(bh);
-				return 0;
-			}
-			udf_release_data(tmp_bh);
-		}
-	}
-#endif
-
 	if (buffer_uptodate(bh))
 		return bh;
 	ll_rw_block(READ, 1, &bh);
@@ -834,6 +845,62 @@
 	return NULL;
 }
 
+void udf_truncate(struct inode * inode)
+{
+	int offset;
+	struct buffer_head *bh;
+	int err;
+
+	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+			S_ISLNK(inode->i_mode)))
+		return;
+	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+		return;
+
+	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+	{
+		if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
+			inode->i_size))
+		{
+			udf_expand_file_adinicb(inode, inode->i_size, &err);
+			if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+			{
+				inode->i_size = UDF_I_LENALLOC(inode);
+				return;
+			}
+			else
+				udf_truncate_extents(inode);
+		}
+		else
+		{
+			offset = (inode->i_size & (inode->i_sb->s_blocksize - 1)) +
+				udf_file_entry_alloc_offset(inode);
+
+			if ((bh = udf_tread(inode->i_sb,
+				udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0),
+				inode->i_sb->s_blocksize)))
+			{
+				memset(bh->b_data + offset, 0x00, inode->i_sb->s_blocksize - offset);
+				mark_buffer_dirty(bh);
+				udf_release_data(bh);
+			}
+			UDF_I_LENALLOC(inode) = inode->i_size;
+		}
+	}
+	else
+	{
+		block_truncate_page(inode->i_mapping, inode->i_size, udf_get_block);
+		udf_truncate_extents(inode);
+	}	
+
+	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	UDF_I_UMTIME(inode) = UDF_I_UCTIME(inode) = CURRENT_UTIME;
+	if (IS_SYNC(inode))
+		udf_sync_inode (inode);
+	else
+		mark_inode_dirty(inode);
+}
+
 /*
  * udf_read_inode
  *
@@ -891,7 +958,8 @@
 		return;
 	}
 
-	if (ident != TID_FILE_ENTRY && ident != TID_EXTENDED_FILE_ENTRY)
+	if (ident != TID_FILE_ENTRY && ident != TID_EXTENDED_FILE_ENTRY &&
+		ident != TID_UNALLOCATED_SPACE_ENTRY)
 	{
 		printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed ident=%d\n",
 			inode->i_ino, ident);
@@ -969,16 +1037,24 @@
 	fe = (struct FileEntry *)bh->b_data;
 	efe = (struct ExtendedFileEntry *)bh->b_data;
 
-	if (fe->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY)
-		UDF_I_EXTENDED_FE(inode) = 1;
-	else /* fe->descTag.tagIdent == TID_FILE_ENTRY */
-		UDF_I_EXTENDED_FE(inode) = 0;
-
 	if (le16_to_cpu(fe->icbTag.strategyType) == 4)
 		UDF_I_STRAT4096(inode) = 0;
 	else /* if (le16_to_cpu(fe->icbTag.strategyType) == 4096) */
 		UDF_I_STRAT4096(inode) = 1;
 
+	UDF_I_ALLOCTYPE(inode) = le16_to_cpu(fe->icbTag.flags) & ICB_FLAG_ALLOC_MASK;
+	if (fe->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY)
+		UDF_I_EXTENDED_FE(inode) = 1;
+	else if (fe->descTag.tagIdent == TID_FILE_ENTRY)
+		UDF_I_EXTENDED_FE(inode) = 0;
+	else if (fe->descTag.tagIdent == TID_UNALLOCATED_SPACE_ENTRY)
+	{
+		UDF_I_LENALLOC(inode) =
+			le32_to_cpu(
+				((struct UnallocatedSpaceEntry *)bh->b_data)->lengthAllocDescs);
+		return;
+	}
+
 	inode->i_uid = le32_to_cpu(fe->uid);
 	if ( inode->i_uid == -1 ) inode->i_uid = UDF_SB(inode->i_sb)->s_uid;
 
@@ -990,6 +1066,7 @@
 		inode->i_nlink = 1;
 	
 	inode->i_size = le64_to_cpu(fe->informationLength);
+	UDF_I_LENEXTENTS(inode) = inode->i_size;
 
 	inode->i_mode = udf_convert_permissions(fe);
 	inode->i_mode &= ~UDF_SB(inode->i_sb)->s_umask;
@@ -997,8 +1074,6 @@
 	UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
 	UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
 
-	UDF_I_ALLOCTYPE(inode) = le16_to_cpu(fe->icbTag.flags) & ICB_FLAG_ALLOC_MASK;
-
 	if (UDF_I_EXTENDED_FE(inode) == 0)
 	{
 		inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) <<
@@ -1171,11 +1246,11 @@
 	flags = le16_to_cpu(fe->icbTag.flags);
 
 	mode =	(( permissions      ) & S_IRWXO) |
-			(( permissions >> 2 ) & S_IRWXG) |
-			(( permissions >> 4 ) & S_IRWXU) |
-			(( flags & ICB_FLAG_SETUID) ? S_ISUID : 0) |
-			(( flags & ICB_FLAG_SETGID) ? S_ISGID : 0) |
-			(( flags & ICB_FLAG_STICKY) ? S_ISVTX : 0);
+		(( permissions >> 2 ) & S_IRWXG) |
+		(( permissions >> 4 ) & S_IRWXU) |
+		(( flags & ICB_FLAG_SETUID) ? S_ISUID : 0) |
+		(( flags & ICB_FLAG_SETGID) ? S_ISGID : 0) |
+		(( flags & ICB_FLAG_STICKY) ? S_ISVTX : 0);
 
 	return mode;
 }
@@ -1221,8 +1296,9 @@
 	int err = 0;
 
 	bh = udf_tread(inode->i_sb,
-			udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0),
-			inode->i_sb->s_blocksize);
+		udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0),
+		inode->i_sb->s_blocksize);
+
 	if (!bh)
 	{
 		udf_debug("bread failure\n");
@@ -1233,7 +1309,7 @@
 	if (UDF_I_NEW_INODE(inode) == 1)
 	{
 		if (UDF_I_EXTENDED_FE(inode) == 0)
-			memset(bh->b_data, 0x0, sizeof(struct FileEntry));
+			memset(bh->b_data, 0x00, sizeof(struct FileEntry));
 		else
 			memset(bh->b_data, 0x00, sizeof(struct ExtendedFileEntry));
 		memset(bh->b_data + udf_file_entry_alloc_offset(inode) +
@@ -1242,20 +1318,41 @@
 		UDF_I_NEW_INODE(inode) = 0;
 	}
 
+	if (fe->descTag.tagIdent == TID_UNALLOCATED_SPACE_ENTRY)
+	{
+		struct UnallocatedSpaceEntry *use =
+			(struct UnallocatedSpaceEntry *)bh->b_data;
+
+		use->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode));
+		crclen = sizeof(struct UnallocatedSpaceEntry) + UDF_I_LENALLOC(inode) -
+			sizeof(tag);
+		use->descTag.descCRCLength = cpu_to_le16(crclen);
+		use->descTag.descCRC = cpu_to_le16(udf_crc((char *)use + sizeof(tag), crclen, 0));
+
+		use->descTag.tagChecksum = 0;
+		for (i=0; i<16; i++)
+			if (i != 4)
+				use->descTag.tagChecksum += ((Uint8 *)&(use->descTag))[i];
+
+		mark_buffer_dirty(bh);
+		udf_release_data(bh);
+		return err;
+	}
+
 	if (inode->i_uid != UDF_SB(inode->i_sb)->s_uid)
 		fe->uid = cpu_to_le32(inode->i_uid);
 
 	if (inode->i_gid != UDF_SB(inode->i_sb)->s_gid)
 		fe->gid = cpu_to_le32(inode->i_gid);
 
-	udfperms =  ((inode->i_mode & S_IRWXO)     ) |
-				((inode->i_mode & S_IRWXG) << 2) |
-				((inode->i_mode & S_IRWXU) << 4);
-
-	udfperms |= (le32_to_cpu(fe->permissions) &
-		(PERM_O_DELETE | PERM_O_CHATTR |
-		 PERM_G_DELETE | PERM_G_CHATTR |
-		 PERM_U_DELETE | PERM_U_CHATTR));
+	udfperms =	((inode->i_mode & S_IRWXO)     ) |
+			((inode->i_mode & S_IRWXG) << 2) |
+			((inode->i_mode & S_IRWXU) << 4);
+
+	udfperms |=	(le32_to_cpu(fe->permissions) &
+			(PERM_O_DELETE | PERM_O_CHATTR |
+			 PERM_G_DELETE | PERM_G_CHATTR |
+			 PERM_U_DELETE | PERM_U_CHATTR));
 	fe->permissions = cpu_to_le32(udfperms);
 
 	if (S_ISDIR(inode->i_mode))
@@ -1292,7 +1389,7 @@
 		eid->identSuffix[1] = UDF_OS_ID_LINUX;
 		dsea->majorDeviceIdent = kdev_t_to_nr(inode->i_rdev) >> 8;
 		dsea->minorDeviceIdent = kdev_t_to_nr(inode->i_rdev) & 0xFF;
-		mark_buffer_dirty(tbh);
+		mark_buffer_dirty_inode(tbh, inode);
 		udf_release_data(tbh);
 	}
 
@@ -1305,7 +1402,10 @@
 		if (udf_time_to_stamp(&cpu_time, inode->i_atime, UDF_I_UATIME(inode)))
 			fe->accessTime = cpu_to_lets(cpu_time);
 		if (udf_time_to_stamp(&cpu_time, inode->i_mtime, UDF_I_UMTIME(inode)))
+		{
 			fe->modificationTime = cpu_to_lets(cpu_time);
+			fe->attrTime = cpu_to_lets(cpu_time);
+		}
 		memset(&(fe->impIdent), 0, sizeof(EntityID));
 		strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER);
 		fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
@@ -1327,7 +1427,10 @@
 		if (udf_time_to_stamp(&cpu_time, inode->i_mtime, UDF_I_UMTIME(inode)))
 			efe->modificationTime = cpu_to_lets(cpu_time);
 		if (udf_time_to_stamp(&cpu_time, inode->i_ctime, UDF_I_UCTIME(inode)))
+		{
 			efe->createTime = cpu_to_lets(cpu_time);
+			efe->attrTime = cpu_to_lets(cpu_time);
+		}
 		memset(&(efe->impIdent), 0, sizeof(EntityID));
 		strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER);
 		efe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
@@ -1363,7 +1466,7 @@
 	else if (S_ISFIFO(inode->i_mode))
 		fe->icbTag.fileType = FILE_TYPE_FIFO;
 
-	icbflags = UDF_I_ALLOCTYPE(inode) |
+	icbflags =	UDF_I_ALLOCTYPE(inode) |
 			((inode->i_mode & S_ISUID) ? ICB_FLAG_SETUID : 0) |
 			((inode->i_mode & S_ISGID) ? ICB_FLAG_SETGID : 0) |
 			((inode->i_mode & S_ISVTX) ? ICB_FLAG_STICKY : 0) |
@@ -1444,12 +1547,19 @@
 	{
 		memcpy(&UDF_I_LOCATION(inode), &ino, sizeof(lb_addr));
 		__udf_read_inode(inode);
+		if (is_bad_inode(inode))
+		{
+			iput(inode);
+			return NULL;
+		}
 	}
 
 	if ( ino.logicalBlockNum >= UDF_SB_PARTLEN(sb, ino.partitionReferenceNum) )
 	{
 		udf_debug("block=%d, partition=%d out of range\n",
 			ino.logicalBlockNum, ino.partitionReferenceNum);
+		make_bad_inode(inode);
+		iput(inode);
 		return NULL;
  	}
 
@@ -1496,13 +1606,20 @@
 		{
 			return -1;
 		}
-		if (!(nbh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
+		if (!(nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
 			*bloc, 0), inode->i_sb->s_blocksize)))
 		{
 			return -1;
 		}
+		lock_buffer(nbh);
+		memset(nbh->b_data, 0x00, inode->i_sb->s_blocksize);
+		mark_buffer_uptodate(nbh, 1);
+		unlock_buffer(nbh);
+		mark_buffer_dirty_inode(nbh, inode);
+
 		aed = (struct AllocExtDesc *)(nbh->b_data);
-		aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum);
+		if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
+			aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum);
 		if (*extoffset + adsize > inode->i_sb->s_blocksize)
 		{
 			loffset = *extoffset;
@@ -1551,16 +1668,20 @@
 					EXTENT_NEXT_EXTENT_ALLOCDECS << 30 |
 					inode->i_sb->s_blocksize);
 				lad->extLocation = cpu_to_lelb(*bloc);
+				memset(lad->impUse, 0x00, sizeof(lad->impUse));
 				break;
 			}
 		}
-		udf_update_tag((*bh)->b_data, loffset);
-		mark_buffer_dirty(*bh);
+		if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+			udf_update_tag((*bh)->b_data, loffset);
+		else
+			udf_update_tag((*bh)->b_data, sizeof(struct AllocExtDesc));
+		mark_buffer_dirty_inode(*bh, inode);
 		udf_release_data(*bh);
 		*bh = nbh;
 	}
 
-	ret = udf_write_aext(inode, *bloc, extoffset, eloc, elen, bh, inc);
+	ret = udf_write_aext(inode, *bloc, extoffset, eloc, elen, *bh, inc);
 
 	if (!memcmp(&UDF_I_LOCATION(inode), bloc, sizeof(lb_addr)))
 	{
@@ -1572,23 +1693,26 @@
 		aed = (struct AllocExtDesc *)(*bh)->b_data;
 		aed->lengthAllocDescs =
 			cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
-		udf_update_tag((*bh)->b_data, *extoffset + (inc ? 0 : adsize));
-		mark_buffer_dirty(*bh);
+		if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+			udf_update_tag((*bh)->b_data, *extoffset + (inc ? 0 : adsize));
+		else
+			udf_update_tag((*bh)->b_data, sizeof(struct AllocExtDesc));
+		mark_buffer_dirty_inode(*bh, inode);
 	}
 
 	return ret;
 }
 
 int udf_write_aext(struct inode *inode, lb_addr bloc, int *extoffset,
-    lb_addr eloc, Uint32 elen, struct buffer_head **bh, int inc)
+    lb_addr eloc, Uint32 elen, struct buffer_head *bh, int inc)
 {
 	int adsize;
 	short_ad *sad = NULL;
 	long_ad *lad = NULL;
 
-	if (!(*bh))
+	if (!(bh))
 	{
-		if (!(*bh = udf_tread(inode->i_sb,
+		if (!(bh = udf_tread(inode->i_sb,
 			udf_get_lb_pblock(inode->i_sb, bloc, 0),
 			inode->i_sb->s_blocksize)))
 		{
@@ -1597,6 +1721,8 @@
 			return -1;
 		}
 	}
+	else
+		atomic_inc(&bh->b_count);
 
 	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
 		adsize = sizeof(short_ad);
@@ -1609,39 +1735,47 @@
 	{
 		case ICB_FLAG_AD_SHORT:
 		{
-			sad = (short_ad *)((*bh)->b_data + *extoffset);
+			sad = (short_ad *)((bh)->b_data + *extoffset);
 			sad->extLength = cpu_to_le32(elen);
 			sad->extPosition = cpu_to_le32(eloc.logicalBlockNum);
 			break;
 		}
 		case ICB_FLAG_AD_LONG:
 		{
-			lad = (long_ad *)((*bh)->b_data + *extoffset);
+			lad = (long_ad *)((bh)->b_data + *extoffset);
 			lad->extLength = cpu_to_le32(elen);
 			lad->extLocation = cpu_to_lelb(eloc);
+			memset(lad->impUse, 0x00, sizeof(lad->impUse));
 			break;
 		}
 	}
 
 	if (memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
 	{
-		struct AllocExtDesc *aed = (struct AllocExtDesc *)(*bh)->b_data;
-		udf_update_tag((*bh)->b_data,
-			le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct AllocExtDesc));
+		if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+		{
+			struct AllocExtDesc *aed = (struct AllocExtDesc *)(bh)->b_data;
+			udf_update_tag((bh)->b_data,
+				le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct AllocExtDesc));
+		}
+		mark_buffer_dirty_inode(bh, inode);
 	}
 	else
+	{
 		mark_inode_dirty(inode);
-
-	mark_buffer_dirty(*bh);
+		mark_buffer_dirty(bh);
+	}
 
 	if (inc)
 		*extoffset += adsize;
+	udf_release_data(bh);
 	return (elen >> 30);
 }
 
 int udf_next_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
 	lb_addr *eloc, Uint32 *elen, struct buffer_head **bh, int inc)
 {
+	Uint16 tagIdent;
 	int pos, alen;
 	Uint8 etype;
 
@@ -1657,18 +1791,33 @@
 		}
 	}
 
+	tagIdent = ((tag *)(*bh)->b_data)->tagIdent;
+
 	if (!memcmp(&UDF_I_LOCATION(inode), bloc, sizeof(lb_addr)))
 	{
-		pos = udf_file_entry_alloc_offset(inode);
-		alen = UDF_I_LENALLOC(inode) + pos;
+		if (tagIdent == TID_FILE_ENTRY || tagIdent == TID_EXTENDED_FILE_ENTRY ||
+			UDF_I_NEW_INODE(inode))
+		{
+			pos = udf_file_entry_alloc_offset(inode);
+			alen = UDF_I_LENALLOC(inode) + pos;
+		}
+		else if (tagIdent == TID_UNALLOCATED_SPACE_ENTRY)
+		{
+			pos = sizeof(struct UnallocatedSpaceEntry);
+			alen = UDF_I_LENALLOC(inode) + pos;
+		}
+		else
+			return -1;
 	}
-	else
+	else if (tagIdent == TID_ALLOC_EXTENT_DESC)
 	{
 		struct AllocExtDesc *aed = (struct AllocExtDesc *)(*bh)->b_data;
 
 		pos = sizeof(struct AllocExtDesc);
 		alen = le32_to_cpu(aed->lengthAllocDescs) + pos;
 	}
+	else
+		return -1;
 
 	if (!(*extoffset))
 		*extoffset = pos;
@@ -1829,7 +1978,7 @@
 }
 
 int udf_insert_aext(struct inode *inode, lb_addr bloc, int extoffset,
-    lb_addr neloc, Uint32 nelen, struct buffer_head *bh)
+	lb_addr neloc, Uint32 nelen, struct buffer_head *bh)
 {
 	lb_addr oeloc;
 	Uint32 oelen;
@@ -1851,7 +2000,7 @@
 
 	while ((type = udf_next_aext(inode, &bloc, &extoffset, &oeloc, &oelen, &bh, 0)) != -1)
 	{
-		udf_write_aext(inode, bloc, &extoffset, neloc, nelen, &bh, 1);
+		udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1);
 
 		neloc = oeloc;
 		nelen = (type << 30) | oelen;
@@ -1867,7 +2016,7 @@
 	struct buffer_head *obh;
 	lb_addr obloc;
 	int oextoffset, adsize;
-	int type;
+	char type;
 	struct AllocExtDesc *aed;
 
 	if (!(nbh))
@@ -1901,7 +2050,7 @@
 
 	while ((type = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1)
 	{
-		udf_write_aext(inode, obloc, &oextoffset, eloc, (type << 30) | elen, &obh, 1);
+		udf_write_aext(inode, obloc, &oextoffset, eloc, (type << 30) | elen, obh, 1);
 		if (memcmp(&nbloc, &obloc, sizeof(lb_addr)))
 		{
 			obloc = nbloc;
@@ -1917,8 +2066,8 @@
 	if (memcmp(&nbloc, &obloc, sizeof(lb_addr)))
 	{
 		udf_free_blocks(inode, nbloc, 0, 1);
-		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, &obh, 1);
-		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, &obh, 1);
+		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1);
+		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1);
 		if (!memcmp(&UDF_I_LOCATION(inode), &obloc, sizeof(lb_addr)))
 		{
 			UDF_I_LENALLOC(inode) -= (adsize * 2);
@@ -1929,13 +2078,16 @@
 			aed = (struct AllocExtDesc *)(obh)->b_data;
 			aed->lengthAllocDescs =
 				cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2*adsize));
-			udf_update_tag((obh)->b_data, oextoffset - (2*adsize));
-			mark_buffer_dirty(obh);
+			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+				udf_update_tag((obh)->b_data, oextoffset - (2*adsize));
+			else
+				udf_update_tag((obh)->b_data, sizeof(struct AllocExtDesc));
+			mark_buffer_dirty_inode(obh, inode);
 		}
 	}
 	else
 	{
-		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, &obh, 1);
+		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1);
 		if (!memcmp(&UDF_I_LOCATION(inode), &obloc, sizeof(lb_addr)))
 		{
 			UDF_I_LENALLOC(inode) -= adsize;
@@ -1946,8 +2098,11 @@
 			aed = (struct AllocExtDesc *)(obh)->b_data;
 			aed->lengthAllocDescs =
 				cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - adsize);
-			udf_update_tag((obh)->b_data, oextoffset - adsize);
-			mark_buffer_dirty(obh);
+			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+				udf_update_tag((obh)->b_data, oextoffset - adsize);
+			else
+				udf_update_tag((obh)->b_data, sizeof(struct AllocExtDesc));
+			mark_buffer_dirty_inode(obh, inode);
 		}
 	}
 	
@@ -1959,7 +2114,8 @@
 int inode_bmap(struct inode *inode, int block, lb_addr *bloc, Uint32 *extoffset,
 	lb_addr *eloc, Uint32 *elen, Uint32 *offset, struct buffer_head **bh)
 {
-	int etype, lbcount = 0;
+	Uint64 lbcount = 0, bcount = block << inode->i_sb->s_blocksize_bits;
+	char etype;
 
 	if (block < 0)
 	{
@@ -1980,31 +2136,34 @@
 	{
 		if ((etype = udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, 1)) == -1)
 		{
-			*offset = block - lbcount;
+			*offset = bcount - lbcount;
+			UDF_I_LENEXTENTS(inode) = lbcount;
 			return -1;
 		}
-		lbcount += ((*elen + inode->i_sb->s_blocksize - 1) >>
-			inode->i_sb->s_blocksize_bits);
-	} while (lbcount <= block);
+		lbcount += *elen;
+	} while (lbcount <= bcount);
 
-	*offset = block + ((*elen + inode->i_sb->s_blocksize - 1) >>
-		inode->i_sb->s_blocksize_bits) - lbcount;
+	*offset = bcount + *elen - lbcount;
 
 	return etype;
 }
 
-long udf_locked_block_map(struct inode *inode, long block)
+long udf_block_map(struct inode *inode, long block)
 {
 	lb_addr eloc, bloc;
 	Uint32 offset, extoffset, elen;
 	struct buffer_head *bh = NULL;
 	int ret;
 
+	lock_kernel();
+
 	if (inode_bmap(inode, block, &bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
-		ret = udf_get_lb_pblock(inode->i_sb, eloc, offset);
+		ret = udf_get_lb_pblock(inode->i_sb, eloc, offset >> inode->i_sb->s_blocksize_bits);
 	else
 		ret = 0;
 
+	unlock_kernel();
+
 	if (bh)
 		udf_release_data(bh);
 
@@ -2012,14 +2171,4 @@
 		return udf_fixed_to_variable(ret);
 	else
 		return ret;
-}
-
-long udf_block_map(struct inode *inode, long block)
-{
-	int ret;
-
-	lock_kernel();
-	ret = udf_locked_block_map(inode, block);
-	unlock_kernel();
-	return ret;
 }
diff -u --recursive --new-file v2.4.5/linux/fs/udf/lowlevel.c linux/fs/udf/lowlevel.c
--- v2.4.5/linux/fs/udf/lowlevel.c	Mon Mar 20 08:17:43 2000
+++ linux/fs/udf/lowlevel.c	Mon Jun 11 19:15:27 2001
@@ -7,7 +7,7 @@
  * CONTACTS
  *	E-mail regarding any portion of the Linux UDF file system should be
  *	directed to the development team mailing list (run by majordomo):
- *		linux_udf@hootie.lvld.hp.com
+ *		linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *	This file is distributed under the terms of the GNU General Public
diff -u --recursive --new-file v2.4.5/linux/fs/udf/misc.c linux/fs/udf/misc.c
--- v2.4.5/linux/fs/udf/misc.c	Mon Mar 20 08:17:43 2000
+++ linux/fs/udf/misc.c	Mon Jun 11 19:15:27 2001
@@ -7,7 +7,7 @@
  * CONTACTS
  *	E-mail regarding any portion of the Linux UDF file system should be
  *	directed to the development team mailing list (run by majordomo):
- *		linux_udf@hootie.lvld.hp.com
+ *		linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *	This file is distributed under the terms of the GNU General Public
@@ -67,6 +67,15 @@
 #if defined(__linux__) && defined(__KERNEL__)
 
 extern struct buffer_head *
+udf_tgetblk(struct super_block *sb, int block, int size)
+{
+	if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
+		return getblk(sb->s_dev, udf_fixed_to_variable(block), size);
+	else
+		return getblk(sb->s_dev, block, size);
+}
+
+extern struct buffer_head *
 udf_tread(struct super_block *sb, int block, int size)
 {
 	if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
@@ -309,7 +318,7 @@
 
 	if ( location != le32_to_cpu(tag_p->tagLocation) )
 	{
-		udf_debug("location mismatch block %d, tag %d != %d\n",
+		udf_debug("location mismatch block %u, tag %u != %u\n",
 			block, le32_to_cpu(tag_p->tagLocation), location);
 		goto error_out;
 	}
@@ -424,32 +433,35 @@
 
 	if ( size < udf_blocksize )
 	{
-		udf_errno=3;
+		udf_errno = 3;
 		return -1;
 	}
-	udf_errno=0;
+	udf_errno = 0;
 	
-	offs=(long)block * udf_blocksize;
-	if ( lseek(fd, offs, SEEK_SET) != offs ) {
-		udf_errno=4;
+	offs = (long)block * udf_blocksize;
+	if ( lseek(fd, offs, SEEK_SET) != offs )
+	{
+		udf_errno = 4;
 		return -1;
 	}
 
-	i=read(fd, buffer, udf_blocksize);
-	if ( i < udf_blocksize ) {
-		udf_errno=5;
+	i = read(fd, buffer, udf_blocksize);
+	if ( i < udf_blocksize )
+	{
+		udf_errno = 5;
 		return -1;
 	}
 
 	tag_p = (tag *)(buffer);
 
 	/* Verify the tag location */
-	if ((block-offset) != tag_p->tagLocation) {
+	if ((block-offset) != tag_p->tagLocation)
+	{
 #ifdef __KERNEL__
 		printk(KERN_ERR "udf: location mismatch block %d, tag %d\n",
 			block, tag_p->tagLocation);
 #else
-		udf_errno=6;
+		udf_errno = 6;
 #endif
 		goto error_out;
 	}
@@ -460,35 +472,38 @@
 		checksum += (Uint8)(buffer[i]);
 	for (i = 5; i < 16; i++)
 		checksum += (Uint8)(buffer[i]);
-	if (checksum != tag_p->tagChecksum) {
+	if (checksum != tag_p->tagChecksum)
+	{
 #ifdef __KERNEL__
 		printk(KERN_ERR "udf: tag checksum failed\n");
 #else
-		udf_errno=7;
+		udf_errno = 7;
 #endif
 		goto error_out;
 	}
 
 	/* Verify the tag version */
-	if (tag_p->descVersion != 0x0002U) {
+	if (tag_p->descVersion != 0x0002U)
+	{
 #ifdef __KERNEL__
 		printk(KERN_ERR "udf: tag version 0x%04x != 0x0002U\n",
 			tag_p->descVersion);
 #else
-		udf_errno=8;
+		udf_errno = 8;
 #endif
 		goto error_out;
 	}
 
 	/* Verify the descriptor CRC */
-	if (tag_p->descCRC == udf_crc(buffer + 16, tag_p->descCRCLength, 0)) {
-		udf_errno=0;
+	if (tag_p->descCRC == udf_crc(buffer + 16, tag_p->descCRCLength, 0))
+	{
+		udf_errno = 0;
 		return 0;
 	}
 #ifdef __KERNEL__
 	printk(KERN_ERR "udf: crc failure in udf_read_tagged\n");
 #else
-	udf_errno=9;
+	udf_errno = 9;
 #endif
 
 error_out:
diff -u --recursive --new-file v2.4.5/linux/fs/udf/namei.c linux/fs/udf/namei.c
--- v2.4.5/linux/fs/udf/namei.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/udf/namei.c	Mon Jun 11 19:15:27 2001
@@ -7,7 +7,7 @@
  * CONTACTS
  *      E-mail regarding any portion of the Linux UDF file system should be
  *      directed to the development team mailing list (run by majordomo):
- *              linux_udf@hootie.lvld.hp.com
+ *              linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *      This file is distributed under the terms of the GNU General Public
@@ -33,6 +33,8 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/quotaops.h>
+#include <linux/locks.h>
+#include <linux/smp_lock.h>
 #include <linux/udf_fs.h>
 
 static inline int udf_match(int len, const char * const name, struct qstr *qs)
@@ -42,8 +44,8 @@
 	return !memcmp(name, qs->name, len);
 }
 
-int udf_write_fi(struct FileIdentDesc *cfi, struct FileIdentDesc *sfi,
-	struct udf_fileident_bh *fibh,
+int udf_write_fi(struct inode *inode, struct FileIdentDesc *cfi,
+	struct FileIdentDesc *sfi, struct udf_fileident_bh *fibh,
 	Uint8 *impuse, Uint8 *fileident)
 {
 	Uint16 crclen = fibh->eoffset - fibh->soffset - sizeof(tag);
@@ -56,7 +58,6 @@
 	int padlen = fibh->eoffset - fibh->soffset - liu - lfi -
 		sizeof(struct FileIdentDesc);
 
-
 	offset = fibh->soffset + sizeof(struct FileIdentDesc);
 
 	if (impuse)
@@ -133,8 +134,8 @@
 	}
 
 	if (fibh->sbh != fibh->ebh)
-		mark_buffer_dirty(fibh->ebh);
-	mark_buffer_dirty(fibh->sbh);
+		mark_buffer_dirty_inode(fibh->ebh, inode);
+	mark_buffer_dirty_inode(fibh->sbh, inode);
 	return 0;
 }
 
@@ -164,6 +165,7 @@
 	if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
 		&bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
 	{
+		offset >>= dir->i_sb->s_blocksize_bits;
 		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
 		if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
 		{
@@ -238,7 +240,7 @@
 		if (!lfi)
 			continue;
 
-		if ((flen = udf_get_filename(nameptr, fname, lfi)))
+		if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)))
 		{
 			if (udf_match(flen, fname, &(dentry->d_name)))
 			{
@@ -348,28 +350,41 @@
 
 	if (dentry)
 	{
-		if ( !(udf_char_to_ustr(&unifilename, dentry->d_name.name, dentry->d_name.len)) )
+		if (!dentry->d_name.len)
 		{
-			*err = -ENAMETOOLONG;
+			*err = -EINVAL;
 			return NULL;
 		}
 
-		if ( !(namelen = udf_UTF8toCS0(name, &unifilename, UDF_NAME_LEN)) )
+		if ( !(udf_char_to_ustr(&unifilename, dentry->d_name.name, dentry->d_name.len)) )
 		{
 			*err = -ENAMETOOLONG;
 			return NULL;
 		}
+
+		if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8))
+		{
+			if ( !(namelen = udf_UTF8toCS0(name, &unifilename, UDF_NAME_LEN)) )
+			{
+				*err = -ENAMETOOLONG;
+				return NULL;
+			}
+		}
+		else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
+		{
+			if ( !(namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, name, &unifilename, UDF_NAME_LEN)) )
+			{
+				*err = -ENAMETOOLONG;
+				return NULL;
+			}
+		}
+		else
+			return NULL;
 	}
-	else if (dir->i_size != 0)
-	{
-		/* WTF??? */
-		*err = -ENOENT;
-		return NULL;
-	}
-	else /* .. */
+	else
 		namelen = 0;
 
-	nfidlen = (sizeof(struct FileIdentDesc) + 0 + namelen + 3) & ~3;
+	nfidlen = (sizeof(struct FileIdentDesc) + namelen + 3) & ~3;
 
 	f_pos = (udf_ext0_offset(dir) >> 2);
 
@@ -377,6 +392,7 @@
 	if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
 		&bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
 	{
+		offset >>= dir->i_sb->s_blocksize_bits;
 		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
 		if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
 		{
@@ -391,6 +407,7 @@
 		if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
 		{
 			udf_release_data(bh);
+			*err = -EIO;
 			return NULL;
 		}
 	
@@ -406,6 +423,7 @@
 					udf_release_data(fibh->ebh);
 				udf_release_data(fibh->sbh);
 				udf_release_data(bh);
+				*err = -EIO;
 				return NULL;
 			}
 	
@@ -440,18 +458,22 @@
 					cfi->fileCharacteristics = 0;
 					cfi->lengthFileIdent = namelen;
 					cfi->lengthOfImpUse = cpu_to_le16(0);
-					if (!udf_write_fi(cfi, fi, fibh, NULL, name))
+					if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name))
 						return fi;
 					else
+					{
+						*err = -EIO;
 						return NULL;
+					}
 				}
 			}
-	
+
 			if (!lfi || !dentry)
 				continue;
-	
-			if ((flen = udf_get_filename(nameptr, fname, lfi)) &&
-			    udf_match(flen, fname, &(dentry->d_name))) {
+
+			if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)) &&
+				udf_match(flen, fname, &(dentry->d_name)))
+			{
 				if (fibh->sbh != fibh->ebh)
 					udf_release_data(fibh->ebh);
 				udf_release_data(fibh->sbh);
@@ -533,7 +555,6 @@
 		block = eloc.logicalBlockNum + ((elen - 1) >>
 			dir->i_sb->s_blocksize_bits);
 
-		*err = -ENOSPC;
 		if (!(fibh->ebh = udf_bread(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err)))
 		{
 			udf_release_data(bh);
@@ -568,7 +589,7 @@
 	cfi->fileVersionNum = cpu_to_le16(1);
 	cfi->lengthFileIdent = namelen;
 	cfi->lengthOfImpUse = cpu_to_le16(0);
-	if (!udf_write_fi(cfi, fi, fibh, NULL, name))
+	if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name))
 	{
 		udf_release_data(bh);
 		dir->i_size += nfidlen;
@@ -584,16 +605,18 @@
 		if (fibh->sbh != fibh->ebh)
 			udf_release_data(fibh->ebh);
 		udf_release_data(fibh->sbh);
+		*err = -EIO;
 		return NULL;
 	}
 }
 
-static int udf_delete_entry(struct FileIdentDesc *fi,
-	struct udf_fileident_bh *fibh,
-	struct FileIdentDesc *cfi)
+static int udf_delete_entry(struct inode *inode, struct FileIdentDesc *fi,
+	struct udf_fileident_bh *fibh, struct FileIdentDesc *cfi)
 {
 	cfi->fileCharacteristics |= FILE_DELETED;
-	return udf_write_fi(cfi, fi, fibh, NULL, NULL);
+	if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
+		memset(&(cfi->icb), 0x00, sizeof(long_ad));
+	return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL);
 }
 
 static int udf_create(struct inode *dir, struct dentry *dentry, int mode)
@@ -627,7 +650,7 @@
 	cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
 	*(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
 		cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
-	udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
 	if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
 	{
 		mark_inode_dirty(dir);
@@ -665,7 +688,7 @@
 	cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
 	*(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
 		cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
-	udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
 	if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
 	{
 		mark_inode_dirty(dir);
@@ -700,7 +723,6 @@
 
 	inode->i_op = &udf_dir_inode_operations;
 	inode->i_fop = &udf_dir_operations;
-	inode->i_size = 0;
 	if (!(fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err)))
 	{
 		inode->i_nlink--;
@@ -714,7 +736,7 @@
 	*(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
 		cpu_to_le32(UDF_I_UNIQUE(dir) & 0x00000000FFFFFFFFUL);
 	cfi.fileCharacteristics = FILE_DIRECTORY | FILE_PARENT;
-	udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+	udf_write_fi(inode, &cfi, fi, &fibh, NULL, NULL);
 	udf_release_data(fibh.sbh);
 	inode->i_mode = S_IFDIR | mode;
 	if (dir->i_mode & S_ISGID)
@@ -733,7 +755,7 @@
 	*(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
 		cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
 	cfi.fileCharacteristics |= FILE_DIRECTORY;
-	udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
 	dir->i_version = ++event;
 	dir->i_nlink++;
 	mark_inode_dirty(dir);
@@ -763,6 +785,7 @@
 	if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
 		&bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
 	{
+		offset >>= dir->i_sb->s_blocksize_bits;
 		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
 		if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
 		{
@@ -830,7 +853,7 @@
 	retval = -ENOTEMPTY;
 	if (!empty_dir(inode))
 		goto end_rmdir;
-	retval = udf_delete_entry(fi, &fibh, &cfi);
+	retval = udf_delete_entry(dir, fi, &fibh, &cfi);
 	dir->i_version = ++event;
 	if (retval)
 		goto end_rmdir;
@@ -885,7 +908,7 @@
 			inode->i_ino, inode->i_nlink);
 		inode->i_nlink = 1;
 	}
-	retval = udf_delete_entry(fi, &fibh, &cfi);
+	retval = udf_delete_entry(dir, fi, &fibh, &cfi);
 	if (retval)
 		goto end_unlink;
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -940,6 +963,7 @@
 		eloc.logicalBlockNum = block;
 		eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
 		elen = inode->i_sb->s_blocksize;
+		UDF_I_LENEXTENTS(inode) = elen;
 		extoffset = udf_file_entry_alloc_offset(inode);
 		udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 0);
 		udf_release_data(bh);
@@ -947,11 +971,18 @@
 		inode->i_blocks = inode->i_sb->s_blocksize / 512;
 		block = udf_get_pblock(inode->i_sb, block,
 			UDF_I_LOCATION(inode).partitionReferenceNum, 0);
+		bh = udf_tread(inode->i_sb, block, inode->i_sb->s_blocksize);
+		lock_buffer(bh);
+		memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
+		mark_buffer_uptodate(bh, 1);
+		unlock_buffer(bh);
+		mark_buffer_dirty_inode(bh, inode);
 	}
 	else
+	{
 		block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
-
-	bh = udf_tread(inode->i_sb, block, inode->i_sb->s_blocksize);
+		bh = udf_tread(inode->i_sb, block, inode->i_sb->s_blocksize);
+	}
 	ea = bh->b_data + udf_ext0_offset(inode);
 
 	eoffset = inode->i_sb->s_blocksize - udf_ext0_offset(inode);
@@ -1042,7 +1073,7 @@
 		lvhd->uniqueID = cpu_to_le64(uniqueID);
 		mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb));
 	}
-	udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
 	if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
 	{
 		mark_inode_dirty(dir);
@@ -1095,7 +1126,7 @@
 		lvhd->uniqueID = cpu_to_le64(uniqueID);
 		mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb));
 	}
-	udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
 	if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
 	{
 		mark_inode_dirty(dir);
@@ -1126,7 +1157,12 @@
 	int retval = -ENOENT;
 
 	old_inode = old_dentry->d_inode;
-	ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
+	if ((ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi)))
+	{
+		if (ofibh.sbh != ofibh.ebh)
+			udf_release_data(ofibh.ebh);
+		udf_release_data(ofibh.sbh);
+	}
 	if (!ofi || udf_get_lb_pblock(old_dir->i_sb, lelb_to_cpu(ocfi.icb.extLocation), 0) !=
 		old_inode->i_ino)
 	{
@@ -1197,9 +1233,11 @@
 	ncfi.fileVersionNum = ocfi.fileVersionNum;
 	ncfi.fileCharacteristics = ocfi.fileCharacteristics;
 	memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(long_ad));
-	udf_write_fi(&ncfi, nfi, &nfibh, NULL, NULL);
+	udf_write_fi(new_dir, &ncfi, nfi, &nfibh, NULL, NULL);
 
-	udf_delete_entry(ofi, &ofibh, &ocfi);
+	/* The old fid may have moved - find it again */
+	ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
+	udf_delete_entry(old_dir, ofi, &ofibh, &ocfi);
 
 	old_dir->i_version = ++event;
 	if (new_inode)
@@ -1216,15 +1254,15 @@
 	if (dir_bh)
 	{
 		dir_fi->icb.extLocation = lelb_to_cpu(UDF_I_LOCATION(new_dir));
-		udf_update_tag((char *)dir_fi, sizeof(struct FileIdentDesc) +
-			cpu_to_le16(dir_fi->lengthOfImpUse));
+		udf_update_tag((char *)dir_fi, (sizeof(struct FileIdentDesc) +
+			cpu_to_le16(dir_fi->lengthOfImpUse) + 3) & ~3);
 		if (UDF_I_ALLOCTYPE(old_inode) == ICB_FLAG_AD_IN_ICB)
 		{
 			mark_inode_dirty(old_inode);
 			old_inode->i_version = ++event;
 		}
 		else
-			mark_buffer_dirty(dir_bh);
+			mark_buffer_dirty_inode(dir_bh, old_inode);
 		old_dir->i_nlink --;
 		mark_inode_dirty(old_dir);
 		if (new_inode)
@@ -1239,16 +1277,17 @@
 		}
 	}
 
-	retval = 0;
-
-end_rename:
-	udf_release_data(dir_bh);
 	if (ofi)
 	{
 		if (ofibh.sbh != ofibh.ebh)
 			udf_release_data(ofibh.ebh);
 		udf_release_data(ofibh.sbh);
 	}
+
+	retval = 0;
+
+end_rename:
+	udf_release_data(dir_bh);
 	if (nfi)
 	{
 		if (nfibh.sbh != nfibh.ebh)
diff -u --recursive --new-file v2.4.5/linux/fs/udf/partition.c linux/fs/udf/partition.c
--- v2.4.5/linux/fs/udf/partition.c	Fri Apr 13 20:26:07 2001
+++ linux/fs/udf/partition.c	Mon Jun 11 19:15:27 2001
@@ -7,7 +7,7 @@
  * CONTACTS
  *      E-mail regarding any portion of the Linux UDF file system should be
  *      directed to the development team mailing list (run by majordomo):
- *              linux_udf@hootie.lvld.hp.com
+ *              linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *      This file is distributed under the terms of the GNU General Public
@@ -74,7 +74,7 @@
 		index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(Uint32) + block;
 	}
 
-	loc = udf_locked_block_map(UDF_SB_VAT(sb), newblock);
+	loc = udf_block_map(UDF_SB_VAT(sb), newblock);
 
 	if (!(bh = bread(sb->s_dev, loc, sb->s_blocksize)))
 	{
@@ -103,135 +103,123 @@
 
 Uint32 udf_get_pblock_spar15(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset)
 {
-	Uint32 packet = (block + offset) >> UDF_SB_TYPESPAR(sb,partition).s_spar_pshift;
-	Uint32 index = 0;
-
-	if (UDF_SB_TYPESPAR(sb,partition).s_spar_indexsize == 8)
-		index = UDF_SB_TYPESPAR(sb,partition).s_spar_remap.s_spar_remap8[packet];
-	else if (UDF_SB_TYPESPAR(sb,partition).s_spar_indexsize == 16)
-		index = UDF_SB_TYPESPAR(sb,partition).s_spar_remap.s_spar_remap16[packet];
-	else if (UDF_SB_TYPESPAR(sb,partition).s_spar_indexsize == 32)
-		index = UDF_SB_TYPESPAR(sb,partition).s_spar_remap.s_spar_remap32[packet];
-
-	if (index == ((1 << UDF_SB_TYPESPAR(sb,partition).s_spar_indexsize)-1))
-		return UDF_SB_PARTROOT(sb,partition) + block + offset;
-
-	packet = UDF_SB_TYPESPAR(sb,partition).s_spar_map[index];
-	return packet + ((block + offset) & ((1 << UDF_SB_TYPESPAR(sb,partition).s_spar_pshift)-1));
-}
-
-void udf_fill_spartable(struct super_block *sb, struct udf_sparing_data *sdata, int partlen)
-{
-	Uint16 ident;
-	Uint32 spartable;
 	int i;
-	struct buffer_head *bh;
-	struct SparingTable *st;
+	struct SparingTable *st = NULL;
+	Uint32 packet = (block + offset) & ~(UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1);
 
 	for (i=0; i<4; i++)
 	{
-		if (!(spartable = sdata->s_spar_loc[i]))
-			continue;
-
-		bh = udf_read_tagged(sb, spartable, spartable, &ident);
-
-		if (!bh)
+		if (UDF_SB_TYPESPAR(sb,partition).s_spar_map[i] != NULL)
 		{
-			sdata->s_spar_loc[i] = 0;
-			continue;
+			st = (struct SparingTable *)UDF_SB_TYPESPAR(sb,partition).s_spar_map[i]->b_data;
+			break;
 		}
+	}
 
-		if (ident == 0)
+	if (st)
+	{
+		for (i=0; i<st->reallocationTableLen; i++)
 		{
-			st = (struct SparingTable *)bh->b_data;
-			if (!strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING)))
+			if (le32_to_cpu(st->mapEntry[i].origLocation) >= 0xFFFFFFF0)
+				break;
+			else if (le32_to_cpu(st->mapEntry[i].origLocation) == packet)
 			{
-				SparingEntry *se;
-				Uint16 rtl = le16_to_cpu(st->reallocationTableLen);
-				int index;
+				return le32_to_cpu(st->mapEntry[i].mappedLocation) +
+					((block + offset) & (UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1));
+			}
+			else if (le32_to_cpu(st->mapEntry[i].origLocation) > packet)
+				break;
+		}
+	}
+	return UDF_SB_PARTROOT(sb,partition) + block + offset;
+}
 
-				if (!sdata->s_spar_map)
+int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
+{
+	struct udf_sparing_data *sdata;
+	struct SparingTable *st = NULL;
+	SparingEntry mapEntry;
+	Uint32 packet;
+	int i, j, k, l;
+
+	for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
+	{
+		if (old_block > UDF_SB_PARTROOT(sb,i) &&
+		    old_block < UDF_SB_PARTROOT(sb,i) + UDF_SB_PARTLEN(sb,i))
+		{
+			sdata = &UDF_SB_TYPESPAR(sb,i);
+			packet = (old_block - UDF_SB_PARTROOT(sb,i)) & ~(sdata->s_packet_len - 1);
+
+			for (j=0; j<4; j++)
+			{
+				if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL)
 				{
-					int num = 1, mapsize;
-					sdata->s_spar_indexsize = 8;
-					while (rtl*sizeof(Uint32) >= (1 << sdata->s_spar_indexsize))
-					{
-						num ++;
-						sdata->s_spar_indexsize <<= 1;
-					}
-					mapsize = (rtl * sizeof(Uint32)) +
-						((partlen/(1 << sdata->s_spar_pshift)) * sizeof(Uint8) * num);
-					sdata->s_spar_map = kmalloc(mapsize, GFP_KERNEL);
-					if (!sdata->s_spar_map) {
-						printk("couldnt allocate UDF s_spar_map!\n");
-						return;
-					}
-					sdata->s_spar_remap.s_spar_remap32 = &sdata->s_spar_map[rtl];
-					memset(sdata->s_spar_map, 0xFF, mapsize);
+					st = (struct SparingTable *)sdata->s_spar_map[j]->b_data;
+					break;
 				}
+			}
+
+			if (!st)
+				return 1;
 
-				index = sizeof(struct SparingTable);
-				for (i=0; i<rtl; i++)
+			for (k=0; k<st->reallocationTableLen; k++)
+			{
+				if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF)
 				{
-					if (index > sb->s_blocksize)
+					for (; j<4; j++)
 					{
-						udf_release_data(bh);
-						bh = udf_tread(sb, ++spartable, sb->s_blocksize);
-						if (!bh)
+						if (sdata->s_spar_map[j])
 						{
-							sdata->s_spar_loc[i] = 0;
-							continue;
+							st = (struct SparingTable *)sdata->s_spar_map[j]->b_data;
+							st->mapEntry[k].origLocation = cpu_to_le32(packet);
+							udf_update_tag((char *)st, sizeof(struct SparingTable) + st->reallocationTableLen * sizeof(SparingEntry));
+							mark_buffer_dirty(sdata->s_spar_map[j]);
 						}
-						index = 0;
 					}
-					se = (SparingEntry *)&(bh->b_data[index]);
-					index += sizeof(SparingEntry);
-
-					if (sdata->s_spar_map[i] == 0xFFFFFFFF)
-						sdata->s_spar_map[i] = le32_to_cpu(se->mappedLocation);
-					else if (sdata->s_spar_map[i] != le32_to_cpu(se->mappedLocation))
-					{
-						udf_debug("Found conflicting Sparing Data (%d vs %d for entry %d)\n",
-							sdata->s_spar_map[i], le32_to_cpu(se->mappedLocation), i);
-					}
-
-					if (le32_to_cpu(se->origLocation) < 0xFFFFFFF0)
+					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
+						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
+					return 0;
+				}
+				else if (le32_to_cpu(st->mapEntry[k].origLocation) == packet)
+				{
+					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
+						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
+					return 0;
+				}
+				else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet)
+					break;
+			}
+			for (l=k; l<st->reallocationTableLen; l++)
+			{
+				if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF)
+				{
+					for (; j<4; j++)
 					{
-						int packet = le32_to_cpu(se->origLocation) >> sdata->s_spar_pshift;
-						if (sdata->s_spar_indexsize == 8)
-						{
-							if (sdata->s_spar_remap.s_spar_remap8[packet] == 0xFF)
-								sdata->s_spar_remap.s_spar_remap8[packet] = i;
-							else if (sdata->s_spar_remap.s_spar_remap8[packet] != i)
-							{
-								udf_debug("Found conflicting Sparing Data (%d vs %d)\n",
-									sdata->s_spar_remap.s_spar_remap8[packet], i);
-							}
-						}
-						else if (sdata->s_spar_indexsize == 16)
+						if (sdata->s_spar_map[j])
 						{
-							if (sdata->s_spar_remap.s_spar_remap16[packet] == 0xFFFF)
-								sdata->s_spar_remap.s_spar_remap16[packet] = i;
-							else if (sdata->s_spar_remap.s_spar_remap16[packet] != i)
-							{
-								udf_debug("Found conflicting Sparing Data (%d vs %d)\n",
-									sdata->s_spar_remap.s_spar_remap16[packet], i);
-							}
-						}
-						else if (sdata->s_spar_indexsize == 32)
-						{
-							if (sdata->s_spar_remap.s_spar_remap32[packet] == 0xFFFFFFFF)
-								sdata->s_spar_remap.s_spar_remap32[packet] = i;
-							else if (sdata->s_spar_remap.s_spar_remap32[packet] != i)
-							{
-								udf_debug("Found conflicting Sparing Data (%d vs %d)\n",
-									sdata->s_spar_remap.s_spar_remap32[packet], i);
-							}
+							st = (struct SparingTable *)sdata->s_spar_map[j]->b_data;
+							mapEntry = st->mapEntry[l];
+							mapEntry.origLocation = cpu_to_le32(packet);
+							memmove(&st->mapEntry[k+1], &st->mapEntry[k], (l-k)*sizeof(SparingEntry));
+							st->mapEntry[k] = mapEntry;
+							udf_update_tag((char *)st, sizeof(struct SparingTable) + st->reallocationTableLen * sizeof(SparingEntry));
+							mark_buffer_dirty(sdata->s_spar_map[j]);
 						}
 					}
+					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
+						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
+					return 0;
 				}
 			}
+			return 1;
 		}
-		udf_release_data(bh);
 	}
+	if (i == UDF_SB_NUMPARTS(sb))
+	{
+		/* outside of partitions */
+		/* for now, fail =) */
+		return 1;
+	}
+
+	return 0;
 }
diff -u --recursive --new-file v2.4.5/linux/fs/udf/super.c linux/fs/udf/super.c
--- v2.4.5/linux/fs/udf/super.c	Mon Apr 23 10:00:21 2001
+++ linux/fs/udf/super.c	Mon Jun 11 19:15:27 2001
@@ -17,7 +17,7 @@
  * CONTACTS
  *  E-mail regarding any portion of the Linux UDF file system should be
  *  directed to the development team mailing list (run by majordomo):
- *	  linux_udf@hootie.lvld.hp.com
+ *	  linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *  This file is distributed under the terms of the GNU General Public
@@ -71,7 +71,7 @@
 #define VDS_POS_IMP_USE_VOL_DESC	4
 #define VDS_POS_VOL_DESC_PTR		5
 #define VDS_POS_TERMINATING_DESC	6
-#define VDS_POS_LENGTH				7
+#define VDS_POS_LENGTH			7
 
 static char error_buf[1024];
 
@@ -125,6 +125,7 @@
 	mode_t umask;
 	gid_t gid;
 	uid_t uid;
+	struct nls_table *nls_map;
 };
 
 static int __init init_udf_fs(void)
@@ -139,6 +140,8 @@
 	unregister_filesystem(&udf_fstype);
 }
 
+EXPORT_NO_SYMBOLS;
+
 module_init(init_udf_fs)
 module_exit(exit_udf_fs)
 
@@ -161,7 +164,8 @@
  *	noadinicb	Don't embed data in the inode
  *	shortad		Use short ad's
  *	longad		Use long ad's (default)
- *	strict		Set strict conformance (unused)
+ *	strict		Set strict conformance
+ *	iocharset=	Set the NLS character set
  *
  *	The remaining are for debugging and disaster recovery:
  *
@@ -209,6 +213,7 @@
 	uopt->volume = 0xFFFFFFFF;
 	uopt->rootdir = 0xFFFFFFFF;
 	uopt->fileset = 0xFFFFFFFF;
+	uopt->nls_map = NULL;
 
 	if (!options)
 		return 1;
@@ -257,6 +262,15 @@
 			uopt->fileset = simple_strtoul(val, NULL, 0);
 		else if (!strcmp(opt, "rootdir") && val)
 			uopt->rootdir = simple_strtoul(val, NULL, 0);
+#ifdef CONFIG_NLS
+		else if (!strcmp(opt, "iocharset") && val)
+		{
+			uopt->nls_map = load_nls(val);
+			uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
+		}
+#endif
+		else if (!strcmp(opt, "utf8") && !val)
+			uopt->flags |= (1 << UDF_FLAG_UTF8);
 		else if (val)
 		{
 			printk(KERN_ERR "udf: bad mount option \"%s=%s\"\n",
@@ -280,7 +294,7 @@
 		udf_open_lvid(sb);
 	sb->s_dirt = 0;
 }
-		
+
 static int
 udf_remount_fs(struct super_block *sb, int *flags, char *options)
 {
@@ -299,7 +313,7 @@
 	UDF_SB(sb)->s_gid   = uopt.gid;
 	UDF_SB(sb)->s_umask = uopt.umask;
 
-#if CONFIG_UDF_RW != 1
+#if UDFFS_RW != 1
 	*flags |= MS_RDONLY;
 #endif
 
@@ -344,12 +358,14 @@
 udf_set_blocksize(struct super_block *sb, int bsize)
 {
 	/* Use specified block size if specified */
-	sb->s_blocksize = get_hardsect_size(sb->s_dev);
-	if (bsize > sb->s_blocksize)
+	if (bsize)
 		sb->s_blocksize = bsize;
+	if (get_hardsect_size(sb->s_dev) > sb->s_blocksize)
+		sb->s_blocksize = get_hardsect_size(sb->s_dev); 
 
 	/* Block size must be an even multiple of 512 */
-	switch (sb->s_blocksize) {
+	switch (sb->s_blocksize)
+	{
 		case 512: sb->s_blocksize_bits = 9;	break;
 		case 1024: sb->s_blocksize_bits = 10; break;
 		case 2048: sb->s_blocksize_bits = 11; break;
@@ -373,6 +389,7 @@
 {
 	struct VolStructDesc *vsd = NULL;
 	int sector = 32768;
+	int sectorsize;
 	struct buffer_head *bh = NULL;
 	int iso9660=0;
 	int nsr02=0;
@@ -380,14 +397,19 @@
 
 	/* Block size must be a multiple of 512 */
 	if (sb->s_blocksize & 511)
-		return sector;
+		return 0;
+
+	if (sb->s_blocksize < sizeof(struct VolStructDesc))
+		sectorsize = sizeof(struct VolStructDesc);
+	else
+		sectorsize = sb->s_blocksize;
 
 	sector += (UDF_SB_SESSION(sb) << sb->s_blocksize_bits);
 
 	udf_debug("Starting at sector %u (%ld byte sectors)\n",
 		(sector >> sb->s_blocksize_bits), sb->s_blocksize);
 	/* Process the sequence (if applicable) */
-	for (;!nsr02 && !nsr03; sector += 2048)
+	for (;!nsr02 && !nsr03; sector += sectorsize)
 	{
 		/* Read a block */
 		bh = udf_tread(sb, sector >> sb->s_blocksize_bits, sb->s_blocksize);
@@ -479,9 +501,9 @@
 {
 	int varlastblock = udf_variable_to_fixed(lastblock);
 	int last[] =  { lastblock, lastblock - 2,
-					lastblock - 150, lastblock - 152,
-					varlastblock, varlastblock - 2,
-					varlastblock - 150, varlastblock - 152 };
+			lastblock - 150, lastblock - 152,
+			varlastblock, varlastblock - 2,
+			varlastblock - 150, varlastblock - 152 };
 	struct buffer_head *bh = NULL;
 	Uint16 ident;
 	Uint32 location;
@@ -504,7 +526,7 @@
 
 	for (i=0; (!lastblock && i<sizeof(last)/sizeof(int)); i++)
 	{
-		if (!(bh = bread(sb->s_dev, last[i], sb->s_blocksize)))
+		if (last[i] < 0 || !(bh = bread(sb->s_dev, last[i], sb->s_blocksize)))
 		{
 			ident = location = 0;
 		}
@@ -777,7 +799,7 @@
 	struct PartitionDesc *p;
 	int i;
 
-	p=(struct PartitionDesc *)bh->b_data;
+	p = (struct PartitionDesc *)bh->b_data;
 
 	for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
 	{
@@ -788,9 +810,6 @@
 			UDF_SB_PARTLEN(sb,i) = le32_to_cpu(p->partitionLength); /* blocks */
 			UDF_SB_PARTROOT(sb,i) = le32_to_cpu(p->partitionStartingLocation) + UDF_SB_SESSION(sb);
 
-			if (UDF_SB_PARTTYPE(sb,i) == UDF_SPARABLE_MAP15)
-				udf_fill_spartable(sb, &UDF_SB_TYPESPAR(sb,i), UDF_SB_PARTLEN(sb,i));
-
 			if (!strcmp(p->partitionContents.ident, PARTITION_CONTENTS_NSR02) ||
 				!strcmp(p->partitionContents.ident, PARTITION_CONTENTS_NSR03))
 			{
@@ -798,26 +817,54 @@
 
 				phd = (struct PartitionHeaderDesc *)(p->partitionContentsUse);
 				if (phd->unallocatedSpaceTable.extLength)
-					udf_debug("unallocatedSpaceTable (part %d)\n", i);
+				{
+					lb_addr loc = { le32_to_cpu(phd->unallocatedSpaceTable.extPosition), i };
+
+					UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table =
+						udf_iget(sb, loc);
+					UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_TABLE;
+					udf_debug("unallocatedSpaceTable (part %d) @ %ld\n",
+						i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table->i_ino);
+				}
 				if (phd->unallocatedSpaceBitmap.extLength)
 				{
-					UDF_SB_PARTMAPS(sb)[i].s_uspace.bitmap =
-						le32_to_cpu(phd->unallocatedSpaceBitmap.extPosition);
-					UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_BITMAP;
-					udf_debug("unallocatedSpaceBitmap (part %d) @ %d\n",
-						i, UDF_SB_PARTMAPS(sb)[i].s_uspace.bitmap);
+					UDF_SB_ALLOC_BITMAP(sb, i, s_uspace);
+					if (UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap != NULL)
+					{
+						UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extLength =
+							le32_to_cpu(phd->unallocatedSpaceBitmap.extLength);
+						UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extPosition =
+							le32_to_cpu(phd->unallocatedSpaceBitmap.extPosition);
+						UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_BITMAP;
+						udf_debug("unallocatedSpaceBitmap (part %d) @ %d\n",
+							i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extPosition);
+					}
 				}
 				if (phd->partitionIntegrityTable.extLength)
 					udf_debug("partitionIntegrityTable (part %d)\n", i);
 				if (phd->freedSpaceTable.extLength)
-					udf_debug("freedSpaceTable (part %d)\n", i);
+				{
+					lb_addr loc = { le32_to_cpu(phd->freedSpaceTable.extPosition), i };
+
+					UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table =
+						udf_iget(sb, loc);
+					UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_TABLE;
+					udf_debug("freedSpaceTable (part %d) @ %ld\n",
+						i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table->i_ino);
+				}
 				if (phd->freedSpaceBitmap.extLength)
 				{
-					UDF_SB_PARTMAPS(sb)[i].s_fspace.bitmap =
-						le32_to_cpu(phd->freedSpaceBitmap.extPosition);
-					UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_BITMAP;
-					udf_debug("freedSpaceBitmap (part %d) @ %d\n",
-						i, UDF_SB_PARTMAPS(sb)[i].s_fspace.bitmap);
+					UDF_SB_ALLOC_BITMAP(sb, i, s_fspace);
+					if (UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap != NULL)
+					{
+						UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extLength =
+							le32_to_cpu(phd->freedSpaceBitmap.extLength);
+						UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extPosition =
+							le32_to_cpu(phd->freedSpaceBitmap.extPosition);
+						UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_BITMAP;
+						udf_debug("freedSpaceBitmap (part %d) @ %d\n",
+							i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extPosition);
+					}
 				}
 			}
 			break;
@@ -844,15 +891,13 @@
 
 	lvd = (struct LogicalVolDesc *)bh->b_data;
 
-	UDF_SB_NUMPARTS(sb) = le32_to_cpu(lvd->numPartitionMaps);
-	UDF_SB_ALLOC_PARTMAPS(sb, UDF_SB_NUMPARTS(sb));
+	UDF_SB_ALLOC_PARTMAPS(sb, le32_to_cpu(lvd->numPartitionMaps));
 
 	for (i=0,offset=0;
 		 i<UDF_SB_NUMPARTS(sb) && offset<le32_to_cpu(lvd->mapTableLength);
 		 i++,offset+=((struct GenericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapLength)
 	{
 		type = ((struct GenericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapType;
-		udf_debug("Partition (%d) type %d\n", i, type);
 		if (type == 1)
 		{
 			struct GenericPartitionMap1 *gpm1 = (struct GenericPartitionMap1 *)&(lvd->partitionMaps[offset]);
@@ -879,16 +924,29 @@
 			}
 			else if (!strncmp(upm2->partIdent.ident, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE)))
 			{
-				int plen;
-
+				Uint32 loc;
+				Uint16 ident;
+				struct SparingTable *st;
 				struct SparablePartitionMap *spm = (struct SparablePartitionMap *)&(lvd->partitionMaps[offset]);
+
 				UDF_SB_PARTTYPE(sb,i) = UDF_SPARABLE_MAP15;
-				plen = le16_to_cpu(spm->packetLength);
-				UDF_SB_TYPESPAR(sb,i).s_spar_pshift = 0;
-				while (plen >>= 1)
-					UDF_SB_TYPESPAR(sb,i).s_spar_pshift ++;
+				UDF_SB_TYPESPAR(sb,i).s_packet_len = le16_to_cpu(spm->packetLength);
 				for (j=0; j<spm->numSparingTables; j++)
-					UDF_SB_TYPESPAR(sb,i).s_spar_loc[j] = le32_to_cpu(spm->locSparingTable[j]);
+				{
+					loc = le32_to_cpu(spm->locSparingTable[j]);
+					UDF_SB_TYPESPAR(sb,i).s_spar_map[j] =
+						udf_read_tagged(sb, loc, loc, &ident);
+					if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL)
+					{
+						st = (struct SparingTable *)UDF_SB_TYPESPAR(sb,i).s_spar_map[j]->b_data;
+						if (ident != 0 ||
+							strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING)))
+						{
+							udf_release_data(UDF_SB_TYPESPAR(sb,i).s_spar_map[j]);
+							UDF_SB_TYPESPAR(sb,i).s_spar_map[j] = NULL;
+						}
+					}
+				}
 				UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_spar15;
 			}
 			else
@@ -899,6 +957,8 @@
 			UDF_SB_PARTVSN(sb,i) = le16_to_cpu(upm2->volSeqNum);
 			UDF_SB_PARTNUM(sb,i) = le16_to_cpu(upm2->partitionNum);
 		}
+		udf_debug("Partition (%d:%d) type %d on volume %d\n",
+			i, UDF_SB_PARTNUM(sb,i), type, UDF_SB_PARTVSN(sb,i));
 	}
 
 	if (fileset)
@@ -963,10 +1023,12 @@
 	struct buffer_head *bh = NULL;
 	struct udf_vds_record vds[VDS_POS_LENGTH];
 	struct GenericDesc *gd;
+	struct VolDescPtr *vdp;
 	int done=0;
 	int i,j;
 	Uint32 vdsn;
 	Uint16 ident;
+	long next_s = 0, next_e = 0;
 
 	memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
 
@@ -995,6 +1057,12 @@
 				{
 					vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum = vdsn;
 					vds[VDS_POS_VOL_DESC_PTR].block = block;
+
+					vdp = (struct VolDescPtr *)bh->b_data;
+					next_s = le32_to_cpu(vdp->nextVolDescSeqExt.extLocation);
+					next_e = le32_to_cpu(vdp->nextVolDescSeqExt.extLength);
+					next_e = next_e >> sb->s_blocksize_bits;
+					next_e += next_s;
 				}
 				break;
 			case TID_IMP_USE_VOL_DESC: /* ISO 13346 3/10.4 */
@@ -1024,7 +1092,14 @@
 				break;
 			case TID_TERMINATING_DESC: /* ISO 13346 3/10.9 */
 				vds[VDS_POS_TERMINATING_DESC].block = block;
-				done = 1;
+				if (next_e)
+				{
+					block = next_s;
+					lastblock = next_e;
+					next_s = next_e = 0;
+				}
+				else
+					done = 1;
 				break;
 		}
 		udf_release_data(bh);
@@ -1098,7 +1173,7 @@
 	for (i=0; i<sizeof(UDF_SB_ANCHOR(sb))/sizeof(int); i++)
 	{
 		if (UDF_SB_ANCHOR(sb)[i] && (bh = udf_read_tagged(sb,
-			UDF_SB_ANCHOR(sb)[i], UDF_SB_ANCHOR(sb)[i] - UDF_SB_SESSION(sb), &ident)))
+			UDF_SB_ANCHOR(sb)[i], UDF_SB_ANCHOR(sb)[i], &ident)))
 		{
 			anchor = (struct AnchorVolDescPtr *)bh->b_data;
 
@@ -1155,10 +1230,10 @@
 						UDF_SB_PARTVSN(sb,i) == UDF_SB_PARTVSN(sb,j) &&
 						UDF_SB_PARTNUM(sb,i) == UDF_SB_PARTNUM(sb,j))
 					{
-							ino.partitionReferenceNum = j;
-							ino.logicalBlockNum = UDF_SB_LASTBLOCK(sb) -
-								UDF_SB_PARTROOT(sb,j);
-							break;
+						ino.partitionReferenceNum = j;
+						ino.logicalBlockNum = UDF_SB_LASTBLOCK(sb) -
+							UDF_SB_PARTROOT(sb,j);
+						break;
 					}
 				}
 
@@ -1219,7 +1294,6 @@
 					((Uint8 *)&(UDF_SB_LVID(sb)->descTag))[i];
 
 		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
-		sb->s_dirt = 0;
 	}
 }
 
@@ -1276,10 +1350,10 @@
 static struct super_block *
 udf_read_super(struct super_block *sb, void *options, int silent)
 {
+	int i;
 	struct inode *inode=NULL;
 	struct udf_options uopt;
 	lb_addr rootdir, fileset;
-	int i;
 
 	uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB);
 	uopt.uid = -1;
@@ -1288,13 +1362,33 @@
 
 	memset(UDF_SB(sb), 0x00, sizeof(struct udf_sb_info));
 
-#if CONFIG_UDF_RW != 1
+#if UDFFS_RW != 1
 	sb->s_flags |= MS_RDONLY;
 #endif
 
 	if (!udf_parse_options((char *)options, &uopt))
 		goto error_out;
 
+	if (uopt.flags & (1 << UDF_FLAG_UTF8) &&
+	    uopt.flags & (1 << UDF_FLAG_NLS_MAP))
+	{
+		udf_error(sb, "udf_read_super",
+			"utf8 cannot be combined with iocharset\n");
+		goto error_out;
+	}
+#ifdef CONFIG_NLS
+	if ((uopt.flags & (1 << UDF_FLAG_NLS_MAP)) && !uopt.nls_map)
+	{
+		uopt.nls_map = load_nls_default();
+		if (!uopt.nls_map)
+			uopt.flags &= ~(1 << UDF_FLAG_NLS_MAP);
+		else
+			udf_debug("Using default NLS map\n");
+	}
+#endif
+	if (!(uopt.flags & (1 << UDF_FLAG_NLS_MAP)))
+		uopt.flags |= (1 << UDF_FLAG_UTF8);
+
 	fileset.logicalBlockNum = 0xFFFFFFFF;
 	fileset.partitionReferenceNum = 0xFFFF;
 
@@ -1302,6 +1396,7 @@
 	UDF_SB(sb)->s_uid = uopt.uid;
 	UDF_SB(sb)->s_gid = uopt.gid;
 	UDF_SB(sb)->s_umask = uopt.umask;
+	UDF_SB(sb)->s_nls_map = uopt.nls_map;
 
 	/* Set the block size for all transfers */
 	if (!udf_set_blocksize(sb, uopt.blocksize))
@@ -1335,13 +1430,6 @@
 	sb->s_dirt = 0;
 	sb->s_magic = UDF_SUPER_MAGIC;
 
-	for (i=0; i<UDF_MAX_BLOCK_LOADED; i++)
-	{
-		UDF_SB_BLOCK_BITMAP_NUMBER(sb,i) = 0;
-		UDF_SB_BLOCK_BITMAP(sb,i) = NULL;
-	}
-	UDF_SB_LOADED_BLOCK_BITMAPS(sb) = 0;
-
 	if (udf_load_partition(sb, &fileset))
 	{
 		printk("UDF-fs: No partition found (1)\n");
@@ -1365,6 +1453,8 @@
 			sb->s_flags |= MS_RDONLY;
 		}
 
+		UDF_SB_UDFREV(sb) = minUDFWriteRev;
+
 		if (minUDFReadRev >= UDF_VERS_USE_EXTENDED_FE)
 			UDF_SET_FLAG(sb, UDF_FLAG_USE_EXTENDED_FE);
 		if (minUDFReadRev >= UDF_VERS_USE_STREAMS)
@@ -1387,8 +1477,8 @@
 	{
 		timestamp ts;
 		udf_time_to_stamp(&ts, UDF_SB_RECORDTIME(sb), 0);
-		udf_info("UDF %s (%s) Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
-			UDFFS_VERSION, UDFFS_DATE,
+		udf_info("UDF %s-%s (%s) Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
+			UDFFS_VERSION, UDFFS_RW ? "rw" : "ro", UDFFS_DATE,
 			UDF_SB_VOLIDENT(sb), ts.year, ts.month, ts.day, ts.hour, ts.minute,
 			ts.typeAndTimezone);
 	}
@@ -1420,6 +1510,40 @@
 error_out:
 	if (UDF_SB_VAT(sb))
 		iput(UDF_SB_VAT(sb));
+	if (UDF_SB_NUMPARTS(sb))
+	{
+		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE)
+			iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
+		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE)
+			iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
+		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
+		{
+			for (i=0; i<UDF_SB_BITMAP_NR_GROUPS(sb,UDF_SB_PARTITION(sb),s_uspace); i++)
+			{
+				if (UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace,i))
+					udf_release_data(UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace,i));
+			}
+			kfree(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_bitmap);
+		}
+		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
+		{
+			for (i=0; i<UDF_SB_BITMAP_NR_GROUPS(sb,UDF_SB_PARTITION(sb),s_fspace); i++)
+			{
+				if (UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace,i))
+					udf_release_data(UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace,i));
+			}
+			kfree(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_bitmap);
+		}
+		if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15)
+		{
+			for (i=0; i<4; i++)
+				udf_release_data(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
+		}
+	}
+#ifdef CONFIG_NLS
+	if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
+		unload_nls(UDF_SB(sb)->s_nls_map);
+#endif
 	if (!(sb->s_flags & MS_RDONLY))
 		udf_close_lvid(sb);
 	udf_release_data(UDF_SB_LVIDBH(sb));
@@ -1476,11 +1600,43 @@
 
 	if (UDF_SB_VAT(sb))
 		iput(UDF_SB_VAT(sb));
+	if (UDF_SB_NUMPARTS(sb))
+	{
+		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE)
+			iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
+		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE)
+			iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
+		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
+		{
+			for (i=0; i<UDF_SB_BITMAP_NR_GROUPS(sb,UDF_SB_PARTITION(sb),s_uspace); i++)
+			{
+				if (UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace,i))
+					udf_release_data(UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace,i));
+			}
+			kfree(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_bitmap);
+		}
+		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
+		{
+			for (i=0; i<UDF_SB_BITMAP_NR_GROUPS(sb,UDF_SB_PARTITION(sb),s_fspace); i++)
+			{
+				if (UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace,i))
+					udf_release_data(UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace,i));
+			}
+			kfree(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_bitmap);
+		}
+		if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15)
+		{
+			for (i=0; i<4; i++)
+				udf_release_data(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
+		}
+	}
+#ifdef CONFIG_NLS
+	if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
+		unload_nls(UDF_SB(sb)->s_nls_map);
+#endif
 	if (!(sb->s_flags & MS_RDONLY))
 		udf_close_lvid(sb);
 	udf_release_data(UDF_SB_LVIDBH(sb));
-	for (i=0; i<UDF_MAX_BLOCK_LOADED; i++)
-		udf_release_data(UDF_SB_BLOCK_BITMAP(sb, i));
 	UDF_SB_FREE(sb);
 }
 
@@ -1518,89 +1674,130 @@
 static unsigned char udf_bitmap_lookup[16] = {
 	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
 };
-	
+
 static unsigned int
-udf_count_free(struct super_block *sb)
+udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
 {
 	struct buffer_head *bh = NULL;
 	unsigned int accum = 0;
+	int index;
+	int block = 0, newblock;
 	lb_addr loc;
-	Uint32 bitmap;
+	Uint32 bytes;
+	Uint8 value;
+	Uint8 *ptr;
+	Uint16 ident;
+	struct SpaceBitmapDesc *bm;
 
-	if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
-		bitmap = UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.bitmap;
-	else if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
-		bitmap = UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.bitmap;
-	else
-		bitmap = 0xFFFFFFFF;
+	loc.logicalBlockNum = bitmap->s_extPosition;
+	loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
+	bh = udf_read_ptagged(sb, loc, 0, &ident);
 
-	if (bitmap != 0xFFFFFFFF)
+	if (!bh)
+	{
+		printk(KERN_ERR "udf: udf_count_free failed\n");
+		return 0;
+	}
+	else if (ident != TID_SPACE_BITMAP_DESC)
 	{
-		struct SpaceBitmapDesc *bm;
-		int block = 0, newblock, index;
-		Uint16 ident;
-		Uint32 bytes;
-		Uint8 value;
-		Uint8 * ptr;
-
-		loc.logicalBlockNum = bitmap;
-		loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
-		bh = udf_read_ptagged(sb, loc, 0, &ident);
+		udf_release_data(bh);
+		printk(KERN_ERR "udf: udf_count_free failed\n");
+		return 0;
+	}
 
-		if (!bh)
-		{
-			printk(KERN_ERR "udf: udf_count_free failed\n");
-			return 0;
+	bm = (struct SpaceBitmapDesc *)bh->b_data;
+	bytes = bm->numOfBytes;
+	index = sizeof(struct SpaceBitmapDesc); /* offset in first block only */
+	ptr = (Uint8 *)bh->b_data;
+
+	while ( bytes > 0 )
+	{
+		while ((bytes > 0) && (index < sb->s_blocksize))
+		{
+			value = ptr[index];
+			accum += udf_bitmap_lookup[ value & 0x0f ];
+			accum += udf_bitmap_lookup[ value >> 4 ];
+			index++;
+			bytes--;
 		}
-		else if (ident != TID_SPACE_BITMAP_DESC)
+		if ( bytes )
 		{
 			udf_release_data(bh);
-			printk(KERN_ERR "udf: udf_count_free failed\n");
-			return 0;
-		}
-
-		bm = (struct SpaceBitmapDesc *)bh->b_data;
-		bytes = bm->numOfBytes;
-		index = sizeof(struct SpaceBitmapDesc); /* offset in first block only */
-		ptr = (Uint8 *)bh->b_data;
-
-		while ( bytes > 0 )
-		{
-			while ((bytes > 0) && (index < sb->s_blocksize))
-			{
-				value = ptr[index];
-				accum += udf_bitmap_lookup[ value & 0x0f ];
-				accum += udf_bitmap_lookup[ value >> 4 ];
-				index++;
-				bytes--;
-			}
-			if ( bytes )
+			newblock = udf_get_lb_pblock(sb, loc, ++block);
+			bh = udf_tread(sb, newblock, sb->s_blocksize);
+			if (!bh)
 			{
-				udf_release_data(bh);
-				newblock = udf_get_lb_pblock(sb, loc, ++block);
-				bh = udf_tread(sb, newblock, sb->s_blocksize);
-				if (!bh)
-				{
-					udf_debug("read failed\n");
-					return accum;
-				}
-				index = 0;
-				ptr = (Uint8 *)bh->b_data;
+				udf_debug("read failed\n");
+				return accum;
 			}
+			index = 0;
+			ptr = (Uint8 *)bh->b_data;
 		}
-		udf_release_data(bh);
 	}
-	else
+	udf_release_data(bh);
+	return accum;
+}
+
+static unsigned int
+udf_count_free_table(struct super_block *sb, struct inode * table)
+{
+	unsigned int accum = 0;
+	Uint32 extoffset, elen;
+	lb_addr bloc, eloc;
+	char etype;
+	struct buffer_head *bh = NULL;
+
+	bloc = UDF_I_LOCATION(table);
+	extoffset = sizeof(struct UnallocatedSpaceEntry);
+
+	while ((etype = udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
 	{
-		if (UDF_SB_LVIDBH(sb))
+		accum += (elen >> table->i_sb->s_blocksize_bits);
+	}
+	udf_release_data(bh);
+	return accum;
+}
+	
+static unsigned int
+udf_count_free(struct super_block *sb)
+{
+	unsigned int accum = 0;
+
+	if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
+	{
+		accum += udf_count_free_bitmap(sb,
+			UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_bitmap);
+	}
+	if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
+	{
+		accum += udf_count_free_bitmap(sb,
+			UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_bitmap);
+	}
+	if (accum)
+		return accum;
+
+	if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE)
+	{
+		accum += udf_count_free_table(sb,
+			UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
+	}
+	if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE)
+	{
+		accum += udf_count_free_table(sb,
+			UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
+	}
+	if (accum)
+		return accum;
+
+	if (UDF_SB_LVIDBH(sb))
+	{
+		if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb))
 		{
-			if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb))
-				accum = le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]);
+			accum = le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]);
 
 			if (accum == 0xFFFFFFFF)
 				accum = 0;
 		}
 	}
-
 	return accum;
 }
diff -u --recursive --new-file v2.4.5/linux/fs/udf/symlink.c linux/fs/udf/symlink.c
--- v2.4.5/linux/fs/udf/symlink.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/udf/symlink.c	Mon Jun 11 19:15:27 2001
@@ -7,7 +7,7 @@
  * CONTACTS
  *	E-mail regarding any portion of the Linux UDF file system should be
  *	directed to the development team mailing list (run by majordomo):
- *		linux_udf@hootie.lvld.hp.com
+ *		linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *	This file is distributed under the terms of the GNU General Public
@@ -126,5 +126,5 @@
  * symlinks can't do much...
  */
 struct address_space_operations udf_symlink_aops = {
-	readpage:			udf_symlink_filler,
+	readpage:		udf_symlink_filler,
 };
diff -u --recursive --new-file v2.4.5/linux/fs/udf/truncate.c linux/fs/udf/truncate.c
--- v2.4.5/linux/fs/udf/truncate.c	Tue Sep  5 14:07:30 2000
+++ linux/fs/udf/truncate.c	Mon Jun 11 19:15:27 2001
@@ -7,7 +7,7 @@
  * CONTACTS
  *	E-mail regarding any portion of the Linux UDF file system should be
  *	directed to the development team mailing list (run by majordomo):
- *		linux_udf@hootie.lvld.hp.com
+ *		linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *	This file is distributed under the terms of the GNU General Public
@@ -33,7 +33,7 @@
 #include "udf_sb.h"
 
 static void extent_trunc(struct inode * inode, lb_addr bloc, int extoffset,
-	lb_addr eloc, Uint8 etype, Uint32 elen, struct buffer_head **bh, Uint32 nelen)
+	lb_addr eloc, Uint8 etype, Uint32 elen, struct buffer_head *bh, Uint32 nelen)
 {
 	lb_addr neloc = { 0, 0 };
 	int blocks = inode->i_sb->s_blocksize / 512;
@@ -62,7 +62,7 @@
 	}
 }
 
-void udf_trunc(struct inode * inode)
+void udf_truncate_extents(struct inode * inode)
 {
 	lb_addr bloc, eloc, neloc = { 0, 0 };
 	Uint32 extoffset, elen, offset, nelen = 0, lelen = 0, lenalloc;
@@ -79,12 +79,11 @@
 		adsize = 0;
 
 	etype = inode_bmap(inode, first_block, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
-	offset = (offset << inode->i_sb->s_blocksize_bits) |
-		(inode->i_size & (inode->i_sb->s_blocksize - 1));
+	offset += (inode->i_size & (inode->i_sb->s_blocksize - 1));
 	if (etype != -1)
 	{
 		extoffset -= adsize;
-		extent_trunc(inode, bloc, extoffset, eloc, etype, elen, &bh, offset);
+		extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, offset);
 		extoffset += adsize;
 
 		if (offset)
@@ -101,7 +100,7 @@
 		{
 			if (etype == EXTENT_NEXT_EXTENT_ALLOCDECS)
 			{
-				udf_write_aext(inode, bloc, &extoffset, neloc, nelen, &bh, 0);
+				udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0);
 				extoffset = 0;
 				if (lelen)
 				{
@@ -122,9 +121,12 @@
 					{
 						struct AllocExtDesc *aed = (struct AllocExtDesc *)(bh->b_data);
 						aed->lengthAllocDescs = cpu_to_le32(lenalloc);
-						udf_update_tag(bh->b_data, lenalloc +
-							sizeof(struct AllocExtDesc));
-						mark_buffer_dirty(bh);
+						if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+							udf_update_tag(bh->b_data, lenalloc +
+								sizeof(struct AllocExtDesc));
+						else
+							udf_update_tag(bh->b_data, sizeof(struct AllocExtDesc));
+						mark_buffer_dirty_inode(bh, inode);
 					}
 				}
 
@@ -140,7 +142,7 @@
 			}
 			else
 			{
-				extent_trunc(inode, bloc, extoffset, eloc, etype, elen, &bh, 0);
+				extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0);
 				extoffset += adsize;
 			}
 		}
@@ -164,9 +166,12 @@
 			{
 				struct AllocExtDesc *aed = (struct AllocExtDesc *)(bh->b_data);
 				aed->lengthAllocDescs = cpu_to_le32(lenalloc);
-				udf_update_tag(bh->b_data, lenalloc +
-					sizeof(struct AllocExtDesc));
-				mark_buffer_dirty(bh);
+				if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+					udf_update_tag(bh->b_data, lenalloc +
+						sizeof(struct AllocExtDesc));
+				else
+					udf_update_tag(bh->b_data, sizeof(struct AllocExtDesc));
+				mark_buffer_dirty_inode(bh, inode);
 			}
 		}
 	}
@@ -180,7 +185,7 @@
 			{
 				extoffset -= adsize;
 				elen = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) | (elen + offset);
-				udf_write_aext(inode, bloc, &extoffset, eloc, elen, &bh, 0);
+				udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 0);
 			}
 			else if (etype == EXTENT_NOT_RECORDED_ALLOCATED)
 			{
@@ -189,7 +194,7 @@
 				nelen = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) |
 					((elen + offset + inode->i_sb->s_blocksize - 1) &
 					~(inode->i_sb->s_blocksize - 1));
-				udf_write_aext(inode, bloc, &extoffset, neloc, nelen, &bh, 1);
+				udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1);
 				udf_add_aext(inode, &bloc, &extoffset, eloc, (etype << 30) | elen, &bh, 1);
 			}
 			else
@@ -200,7 +205,7 @@
 					elen = (EXTENT_RECORDED_ALLOCATED << 30) |
 						((elen + inode->i_sb->s_blocksize - 1) &
 						~(inode->i_sb->s_blocksize - 1));
-					udf_write_aext(inode, bloc, &extoffset, eloc, elen, &bh, 1);
+					udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 1);
 				}
 				memset(&eloc, 0x00, sizeof(lb_addr));
 				elen = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) | offset;
@@ -208,40 +213,7 @@
 			}
 		}
 	}
+	UDF_I_LENEXTENTS(inode) = inode->i_size;
 
 	udf_release_data(bh);
-}
-
-void udf_truncate(struct inode * inode)
-{
-	int err;
-
-	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
-			S_ISLNK(inode->i_mode)))
-		return;
-	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
-		return;
-
-	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
-	{
-		if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
-			inode->i_size))
-		{
-			udf_expand_file_adinicb(inode, inode->i_size, &err);
-			if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
-			{
-				inode->i_size = UDF_I_LENALLOC(inode);
-				return;
-			}
-			else
-				udf_trunc(inode);
-		}
-		else
-			UDF_I_LENALLOC(inode) = inode->i_size;
-	}
-	else
-		udf_trunc(inode);
-
-	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	mark_inode_dirty(inode);
 }
diff -u --recursive --new-file v2.4.5/linux/fs/udf/udf_i.h linux/fs/udf/udf_i.h
--- v2.4.5/linux/fs/udf/udf_i.h	Thu Mar  2 11:17:32 2000
+++ linux/fs/udf/udf_i.h	Mon Jun 11 19:15:27 2001
@@ -6,6 +6,7 @@
 #define UDF_I_LOCATION(X)	( UDF_I(X)->i_location )
 #define UDF_I_LENEATTR(X)	( UDF_I(X)->i_lenEAttr )
 #define UDF_I_LENALLOC(X)	( UDF_I(X)->i_lenAlloc )
+#define UDF_I_LENEXTENTS(X)	( UDF_I(X)->i_lenExtents )
 #define UDF_I_UNIQUE(X)		( UDF_I(X)->i_unique )
 #define UDF_I_ALLOCTYPE(X)	( UDF_I(X)->i_alloc_type )
 #define UDF_I_EXTENDED_FE(X)( UDF_I(X)->i_extended_fe )
diff -u --recursive --new-file v2.4.5/linux/fs/udf/udf_sb.h linux/fs/udf/udf_sb.h
--- v2.4.5/linux/fs/udf/udf_sb.h	Mon Mar 20 08:17:43 2000
+++ linux/fs/udf/udf_sb.h	Mon Jun 11 19:15:27 2001
@@ -1,11 +1,11 @@
 #ifndef __LINUX_UDF_SB_H
 #define __LINUX_UDF_SB_H
 
-/* Since UDF 1.50 is ISO 13346 based... */
-#define UDF_SUPER_MAGIC				0x15013346
+/* Since UDF 2.01 is ISO 13346 based... */
+#define UDF_SUPER_MAGIC			0x15013346
 
-#define UDF_MAX_READ_VERSION		0x0200
-#define UDF_MAX_WRITE_VERSION		0x0200
+#define UDF_MAX_READ_VERSION		0x0201
+#define UDF_MAX_WRITE_VERSION		0x0201
 
 #define UDF_FLAG_USE_EXTENDED_FE	0
 #define UDF_VERS_USE_EXTENDED_FE	0x0200
@@ -14,16 +14,18 @@
 #define UDF_FLAG_USE_SHORT_AD		2
 #define UDF_FLAG_USE_AD_IN_ICB		3
 #define UDF_FLAG_USE_FILE_CTIME_EA	4
-#define UDF_FLAG_STRICT				5
-#define UDF_FLAG_UNDELETE			6
-#define UDF_FLAG_UNHIDE				7
-#define UDF_FLAG_VARCONV			8
-
-#define UDF_PART_FLAG_UNALLOC_BITMAP		0x0001
-#define UDF_PART_FLAG_UNALLOC_TABLE			0x0002
-#define UDF_PART_FLAG_FREED_BITMAP			0x0004
-#define UDF_PART_FLAG_FREED_TABLE			0x0008
-	
+#define UDF_FLAG_STRICT			5
+#define UDF_FLAG_UNDELETE		6
+#define UDF_FLAG_UNHIDE			7
+#define UDF_FLAG_VARCONV		8
+#define UDF_FLAG_NLS_MAP		9
+#define UDF_FLAG_UTF8			10
+
+#define UDF_PART_FLAG_UNALLOC_BITMAP	0x0001
+#define UDF_PART_FLAG_UNALLOC_TABLE	0x0002
+#define UDF_PART_FLAG_FREED_BITMAP	0x0004
+#define UDF_PART_FLAG_FREED_TABLE	0x0008
+
 #define UDF_SB_FREE(X)\
 {\
 	if (UDF_SB(X))\
@@ -37,11 +39,41 @@
 
 #define UDF_SB_ALLOC_PARTMAPS(X,Y)\
 {\
-	UDF_SB_NUMPARTS(X) = Y;\
 	UDF_SB_PARTMAPS(X) = kmalloc(sizeof(struct udf_part_map) * Y, GFP_KERNEL);\
-	memset(UDF_SB_PARTMAPS(X), 0x00, sizeof(struct udf_part_map) * Y);\
+	if (UDF_SB_PARTMAPS(X) != NULL)\
+	{\
+		UDF_SB_NUMPARTS(X) = Y;\
+		memset(UDF_SB_PARTMAPS(X), 0x00, sizeof(struct udf_part_map) * Y);\
+	}\
+	else\
+	{\
+		UDF_SB_NUMPARTS(X) = 0;\
+		udf_error(X, __FUNCTION__, "Unable to allocate space for %d partition maps", Y);\
+	}\
 }
 
+#define UDF_SB_ALLOC_BITMAP(X,Y,Z)\
+{\
+	int nr_groups = ((UDF_SB_PARTLEN((X),(Y)) + (sizeof(struct SpaceBitmapDesc) << 3) +\
+		((X)->s_blocksize * 8) - 1) / ((X)->s_blocksize * 8));\
+	UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = kmalloc(sizeof(struct udf_bitmap) +\
+		sizeof(struct buffer_head *) * nr_groups,\
+		GFP_KERNEL);\
+	if (UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap != NULL)\
+	{\
+		memset(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap, 0x00,\
+			sizeof(struct udf_bitmap) + sizeof(struct buffer_head *) * nr_groups);\
+		UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap =\
+			(struct buffer_head **)(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap + 1);\
+		UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups = nr_groups;\
+	}\
+	else\
+	{\
+		udf_error(X, __FUNCTION__, "Unable to allocate space for bitmap and %d buffer_head pointers", nr_groups);\
+	}\
+}
+
+
 #define UDF_QUERY_FLAG(X,Y)				( UDF_SB(X)->s_flags & ( 1 << (Y) ) )
 #define UDF_SET_FLAG(X,Y)				( UDF_SB(X)->s_flags |= ( 1 << (Y) ) )
 #define UDF_CLEAR_FLAG(X,Y)				( UDF_SB(X)->s_flags &= ~( 1 << (Y) ) )
@@ -58,6 +90,8 @@
 #define UDF_SB_TYPEVIRT(X,Y)			( UDF_SB_PARTMAPS(X)[(Y)].s_type_specific.s_virtual )
 #define UDF_SB_PARTFUNC(X,Y)			( UDF_SB_PARTMAPS(X)[(Y)].s_partition_func )
 #define UDF_SB_PARTFLAGS(X,Y)			( UDF_SB_PARTMAPS(X)[(Y)].s_partition_flags )
+#define UDF_SB_BITMAP(X,Y,Z,I)			( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap[I] )
+#define UDF_SB_BITMAP_NR_GROUPS(X,Y,Z)	( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups )
 
 #define UDF_SB_VOLIDENT(X)				( UDF_SB(X)->s_volident )
 #define UDF_SB_NUMPARTS(X)				( UDF_SB(X)->s_partitions )
@@ -69,9 +103,6 @@
 #define UDF_SB_LVID(X)					( (struct LogicalVolIntegrityDesc *)UDF_SB_LVIDBH(X)->b_data )
 #define UDF_SB_LVIDIU(X)				( (struct LogicalVolIntegrityDescImpUse *)&(UDF_SB_LVID(X)->impUse[UDF_SB_LVID(X)->numOfPartitions * 2 * sizeof(Uint32)/sizeof(Uint8)]) )
 
-#define UDF_SB_LOADED_BLOCK_BITMAPS(X)	( UDF_SB(X)->s_loaded_block_bitmaps )
-#define UDF_SB_BLOCK_BITMAP_NUMBER(X,Y) ( UDF_SB(X)->s_block_bitmap_number[(Y)] )
-#define UDF_SB_BLOCK_BITMAP(X,Y)		( UDF_SB(X)->s_block_bitmap[(Y)] )
 #define UDF_SB_UMASK(X)					( UDF_SB(X)->s_umask )
 #define UDF_SB_GID(X)					( UDF_SB(X)->s_gid )
 #define UDF_SB_UID(X)					( UDF_SB(X)->s_uid )
diff -u --recursive --new-file v2.4.5/linux/fs/udf/udfdecl.h linux/fs/udf/udfdecl.h
--- v2.4.5/linux/fs/udf/udfdecl.h	Mon Dec 11 13:27:05 2000
+++ linux/fs/udf/udfdecl.h	Mon Jun 11 19:15:27 2001
@@ -12,14 +12,6 @@
 #include <linux/config.h>
 #include <linux/types.h>
 
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,7)
-#error "The UDF Module Current Requires Kernel Version 2.3.7 or greater"
-#endif
-
 #include <linux/fs.h>
 
 #if !defined(CONFIG_UDF_FS) && !defined(CONFIG_UDF_FS_MODULE)
@@ -119,7 +111,7 @@
 extern void udf_warning(struct super_block *, const char *, const char *, ...);
 
 /* namei.c */
-extern int udf_write_fi(struct FileIdentDesc *, struct FileIdentDesc *, struct udf_fileident_bh *, Uint8 *, Uint8 *);
+extern int udf_write_fi(struct inode *inode, struct FileIdentDesc *, struct FileIdentDesc *, struct udf_fileident_bh *, Uint8 *, Uint8 *);
 
 /* file.c */
 extern int udf_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
@@ -131,15 +123,15 @@
 extern struct buffer_head * udf_expand_dir_adinicb(struct inode *, int *, int *);
 extern struct buffer_head * udf_getblk(struct inode *, long, int, int *);
 extern struct buffer_head * udf_bread(struct inode *, int, int, int *);
+extern void udf_truncate(struct inode *);
 extern void udf_read_inode(struct inode *);
 extern void udf_put_inode(struct inode *);
 extern void udf_delete_inode(struct inode *);
 extern void udf_write_inode(struct inode *, int);
-extern long udf_locked_block_map(struct inode *, long);
 extern long udf_block_map(struct inode *, long);
 extern int inode_bmap(struct inode *, int, lb_addr *, Uint32 *, lb_addr *, Uint32 *, Uint32 *, struct buffer_head **);
 extern int udf_add_aext(struct inode *, lb_addr *, int *, lb_addr, Uint32, struct buffer_head **, int);
-extern int udf_write_aext(struct inode *, lb_addr, int *, lb_addr, Uint32, struct buffer_head **, int);
+extern int udf_write_aext(struct inode *, lb_addr, int *, lb_addr, Uint32, struct buffer_head *, int);
 extern int udf_insert_aext(struct inode *, lb_addr, int, lb_addr, Uint32, struct buffer_head *);
 extern int udf_delete_aext(struct inode *, lb_addr, int, lb_addr, Uint32, struct buffer_head *);
 extern int udf_next_aext(struct inode *, lb_addr *, int *, lb_addr *, Uint32 *, struct buffer_head **, int);
@@ -148,6 +140,7 @@
 
 /* misc.c */
 extern int udf_read_tagged_data(char *, int size, int fd, int block, int partref);
+extern struct buffer_head *udf_tgetblk(struct super_block *, int, int);
 extern struct buffer_head *udf_tread(struct super_block *, int, int);
 extern struct GenericAttrFormat *udf_add_extendedattr(struct inode *, Uint32, Uint32, Uint8, struct buffer_head **);
 extern struct GenericAttrFormat *udf_get_extendedattr(struct inode *, Uint32, Uint8, struct buffer_head **);
@@ -165,18 +158,17 @@
 extern Uint32 udf_get_pblock_virt15(struct super_block *, Uint32, Uint16, Uint32);
 extern Uint32 udf_get_pblock_virt20(struct super_block *, Uint32, Uint16, Uint32);
 extern Uint32 udf_get_pblock_spar15(struct super_block *, Uint32, Uint16, Uint32);
-extern void udf_fill_spartable(struct super_block *, struct udf_sparing_data *, int);
+extern int udf_relocate_blocks(struct super_block *, long, long *);
 
 /* unicode.c */
-extern int udf_get_filename(Uint8 *, Uint8 *, int);
+extern int udf_get_filename(struct super_block *, Uint8 *, Uint8 *, int);
 
 /* ialloc.c */
 extern void udf_free_inode(struct inode *);
 extern struct inode * udf_new_inode (const struct inode *, int, int *);
 
 /* truncate.c */
-extern void udf_trunc(struct inode *);
-extern void udf_truncate(struct inode *);
+extern void udf_truncate_extents(struct inode *);
 
 /* balloc.c */
 extern void udf_free_blocks(const struct inode *, lb_addr, Uint32, Uint32);
@@ -184,7 +176,8 @@
 extern int udf_new_block(const struct inode *, Uint16, Uint32, int *);
 
 /* fsync.c */
-extern int udf_sync_file(struct file *, struct dentry *, int);
+extern int udf_fsync_file(struct file *, struct dentry *, int);
+extern int udf_fsync_inode(struct inode *, int);
 
 /* directory.c */
 extern Uint8 * udf_filead_read(struct inode *, Uint8 *, Uint8, lb_addr, int *, int *, struct buffer_head **, int *);
@@ -206,6 +199,10 @@
 extern int udf_build_ustr_exact(struct ustr *, dstring *, int);
 extern int udf_CS0toUTF8(struct ustr *, struct ustr *);
 extern int udf_UTF8toCS0(dstring *, struct ustr *, int);
+#ifdef __KERNEL__
+extern int udf_CS0toNLS(struct nls_table *, struct ustr *, struct ustr *);
+extern int udf_NLStoCS0(struct nls_table *, dstring *, struct ustr *, int);
+#endif
 
 /* crc.c */
 extern Uint16 udf_crc(Uint8 *, Uint32, Uint16);
diff -u --recursive --new-file v2.4.5/linux/fs/udf/udfend.h linux/fs/udf/udfend.h
--- v2.4.5/linux/fs/udf/udfend.h	Mon Dec 11 13:27:05 2000
+++ linux/fs/udf/udfend.h	Mon Jun 11 19:15:27 2001
@@ -80,6 +80,22 @@
 	return out;
 }
 
+static inline short_ad lesa_to_cpu(short_ad in)
+{
+	short_ad out;
+	out.extLength = le32_to_cpu(in.extLength);
+	out.extPosition = le32_to_cpu(in.extPosition);
+	return out;
+}
+
+static inline short_ad cpu_to_lesa(short_ad in)
+{
+	short_ad out;
+	out.extLength = cpu_to_le32(in.extLength);
+	out.extPosition = cpu_to_le32(in.extPosition);
+	return out;
+}
+
 static inline long_ad lela_to_cpu(long_ad in)
 {
 	long_ad out;
diff -u --recursive --new-file v2.4.5/linux/fs/udf/udftime.c linux/fs/udf/udftime.c
--- v2.4.5/linux/fs/udf/udftime.c	Thu Mar  2 11:17:32 2000
+++ linux/fs/udf/udftime.c	Mon Jun 11 19:15:27 2001
@@ -105,6 +105,8 @@
 		offset = src.typeAndTimezone << 4;
 		/* sign extent offset */
 		offset = (offset >> 4);
+		if (offset == -2047) /* unspecified offset */
+			offset = 0;
 	}
 	else
 		offset = 0;
diff -u --recursive --new-file v2.4.5/linux/fs/udf/unicode.c linux/fs/udf/unicode.c
--- v2.4.5/linux/fs/udf/unicode.c	Mon Mar 20 08:17:43 2000
+++ linux/fs/udf/unicode.c	Mon Jun 11 19:15:27 2001
@@ -14,7 +14,7 @@
  * CONTACTS
  *	E-mail regarding any portion of the Linux UDF file system should be
  *	directed to the development team's mailing list (run by majordomo):
- *		linux_udf@hootie.lvld.hp.com
+ *		linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *	This file is distributed under the terms of the GNU General Public
@@ -27,7 +27,9 @@
 #ifdef __KERNEL__
 #include <linux/kernel.h>
 #include <linux/string.h>	/* for memset */
+#include <linux/nls.h>
 #include <linux/udf_fs.h>
+#include "udf_sb.h"
 #else
 #include <string.h>
 #endif
@@ -127,7 +129,7 @@
 }
 
 /*
- * udf_ocu_to_udf8
+ * udf_ocu_to_utf8
  *
  * PURPOSE
  *	Convert OSTA Compressed Unicode to the UTF-8 equivalent.
@@ -327,7 +329,88 @@
 }
 
 #ifdef __KERNEL__
-int udf_get_filename(Uint8 *sname, Uint8 *dname, int flen)
+int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, struct ustr *ocu_i)
+{
+	Uint8 *ocu;
+	Uint32 c;
+	Uint8 cmp_id, ocu_len;
+	int i;
+
+	ocu = ocu_i->u_name;
+
+	ocu_len = ocu_i->u_len;
+	cmp_id = ocu_i->u_cmpID;
+	utf_o->u_len = 0;
+
+	if (ocu_len == 0)
+	{
+		memset(utf_o, 0, sizeof(struct ustr));
+		utf_o->u_cmpID = 0;
+		utf_o->u_len = 0;
+		return 0;
+	}
+
+	if ((cmp_id != 8) && (cmp_id != 16))
+	{
+		printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name);
+		return 0;
+	}
+
+	for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN-3)) ;)
+	{
+		/* Expand OSTA compressed Unicode to Unicode */
+		c = ocu[i++];
+		if (cmp_id == 16)
+			c = (c << 8) | ocu[i++];
+
+		utf_o->u_len += nls->uni2char(c, &utf_o->u_name[utf_o->u_len], 
+			UDF_NAME_LEN - utf_o->u_len);
+	}
+	utf_o->u_cmpID=8;
+	utf_o->u_hash=0L;
+	utf_o->padding=0;
+
+	return utf_o->u_len;
+}
+
+int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, int length)
+{
+	unsigned len, i, max_val;
+	Uint16 uni_char;
+	int uni_cnt;
+	int u_len = 0;
+
+	memset(ocu, 0, sizeof(dstring) * length);
+	ocu[0] = 8;
+	max_val = 0xffU;
+
+try_again:
+	uni_char = 0U;
+	uni_cnt = 0U;
+	for (i = 0U; i < uni->u_len; i++)
+	{
+		len = nls->char2uni(&uni->u_name[i], uni->u_len-i, &uni_char);
+
+		if (len == 2 && max_val == 0xff)
+		{
+			max_val = 0xffffU;
+			ocu[0] = (Uint8)0x10U;
+			goto try_again;
+		}
+		
+		if (max_val == 0xffffU)
+		{
+			ocu[++u_len] = (Uint8)(uni_char >> 8);
+			i++;
+		}
+		ocu[++u_len] = (Uint8)(uni_char & 0xffU);
+	}
+
+	ocu[length - 1] = (Uint8)u_len + 1;
+	return u_len + 1;
+}
+
+int udf_get_filename(struct super_block *sb, Uint8 *sname, Uint8 *dname, int flen)
 {
 	struct ustr filename, unifilename;
 	int len;
@@ -337,11 +420,24 @@
 		return 0;
 	}
 
-	if (!udf_CS0toUTF8(&filename, &unifilename) )
+	if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8))
 	{
-		udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
-		return 0;
+		if (!udf_CS0toUTF8(&filename, &unifilename) )
+		{
+			udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
+			return 0;
+		}
+	}
+	else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
+	{
+		if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, &filename, &unifilename) )
+		{
+			udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
+			return 0;
+		}
 	}
+	else
+		return 0;
 
 	if ((len = udf_translate_to_linux(dname, filename.u_name, filename.u_len,
 		unifilename.u_name, unifilename.u_len)))
diff -u --recursive --new-file v2.4.5/linux/include/asm-alpha/delay.h linux/include/asm-alpha/delay.h
--- v2.4.5/linux/include/asm-alpha/delay.h	Tue Jan  2 16:45:37 2001
+++ linux/include/asm-alpha/delay.h	Wed Jun 20 11:10:27 2001
@@ -1,48 +1,8 @@
 #ifndef __ALPHA_DELAY_H
 #define __ALPHA_DELAY_H
 
-#include <linux/config.h>
-#include <asm/param.h>
-#include <asm/smp.h>
-
-/*
- * Copyright (C) 1993, 2000 Linus Torvalds
- *
- * Delay routines, using a pre-computed "loops_per_jiffy" value.
- */
-
-/*
- * Use only for very small delays (< 1 msec). 
- *
- * The active part of our cycle counter is only 32-bits wide, and
- * we're treating the difference between two marks as signed.  On
- * a 1GHz box, that's about 2 seconds.
- */
-
-extern __inline__ void
-__delay(int loops)
-{
-	int tmp;
-	__asm__ __volatile__(
-		"	rpcc %0\n"
-		"	addl %1,%0,%1\n"
-		"1:	rpcc %0\n"
-		"	subl %1,%0,%0\n"
-		"	bgt %0,1b"
-		: "=&r" (tmp), "=r" (loops) : "1"(loops));
-}
-
-extern __inline__ void
-__udelay(unsigned long usecs, unsigned long lpj)
-{
-	usecs *= (((unsigned long)HZ << 32) / 1000000) * lpj;
-	__delay((long)usecs >> 32);
-}
-
-#ifdef CONFIG_SMP
-#define udelay(u)  __udelay((u), cpu_data[smp_processor_id()].loops_per_jiffy)
-#else
-#define udelay(u)  __udelay((u), loops_per_jiffy)
-#endif
+extern void __delay(int loops);
+extern void __udelay(unsigned long usecs, unsigned long lpj);
+extern void udelay(unsigned long usecs);
 
 #endif /* defined(__ALPHA_DELAY_H) */
diff -u --recursive --new-file v2.4.5/linux/include/asm-alpha/hardirq.h linux/include/asm-alpha/hardirq.h
--- v2.4.5/linux/include/asm-alpha/hardirq.h	Fri Aug  4 16:15:37 2000
+++ linux/include/asm-alpha/hardirq.h	Mon Jun 11 19:15:27 2001
@@ -6,8 +6,7 @@
 
 /* entry.S is sensitive to the offsets of these fields */
 typedef struct {
-	unsigned int __softirq_active;
-	unsigned int __softirq_mask;
+	unsigned long __softirq_pending;
 	unsigned int __local_irq_count;
 	unsigned int __local_bh_count;
 	unsigned int __syscall_count;
diff -u --recursive --new-file v2.4.5/linux/include/asm-alpha/linux_logo.h linux/include/asm-alpha/linux_logo.h
--- v2.4.5/linux/include/asm-alpha/linux_logo.h	Thu Oct  1 10:02:22 1998
+++ linux/include/asm-alpha/linux_logo.h	Mon Jun 11 19:15:27 2001
@@ -23,26 +23,5 @@
 
 #define linux_logo_banner "Linux/AXP version " UTS_RELEASE
 
-#define LINUX_LOGO_COLORS 214
-
-#ifdef INCLUDE_LINUX_LOGO_DATA
-
-#define INCLUDE_LINUX_LOGOBW
-#define INCLUDE_LINUX_LOGO16
-
 #include <linux/linux_logo.h>
 
-#else
-
-/* prototypes only */
-extern unsigned char linux_logo_red[];
-extern unsigned char linux_logo_green[];
-extern unsigned char linux_logo_blue[];
-extern unsigned char linux_logo[];
-extern unsigned char linux_logo_bw[];
-extern unsigned char linux_logo16_red[];
-extern unsigned char linux_logo16_green[];
-extern unsigned char linux_logo16_blue[];
-extern unsigned char linux_logo16[];
-
-#endif
diff -u --recursive --new-file v2.4.5/linux/include/asm-alpha/softirq.h linux/include/asm-alpha/softirq.h
--- v2.4.5/linux/include/asm-alpha/softirq.h	Sun Aug  6 12:42:21 2000
+++ linux/include/asm-alpha/softirq.h	Mon Jun 11 19:15:27 2001
@@ -18,8 +18,11 @@
 }
 
 #define local_bh_enable()	cpu_bh_enable(smp_processor_id())
+#define __local_bh_enable	local_bh_enable
 #define local_bh_disable()	cpu_bh_disable(smp_processor_id())
 
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
+
+#define __cpu_raise_softirq(cpu,nr) set_bit((nr), &softirq_pending(cpu))
 
 #endif /* _ALPHA_SOFTIRQ_H */
diff -u --recursive --new-file v2.4.5/linux/include/asm-alpha/termios.h linux/include/asm-alpha/termios.h
--- v2.4.5/linux/include/asm-alpha/termios.h	Sat Feb  3 20:00:45 2001
+++ linux/include/asm-alpha/termios.h	Mon Jun 11 19:15:27 2001
@@ -82,6 +82,7 @@
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14
+#define N_HCI		15  /* Bluetooth HCI UART */
 
 #ifdef __KERNEL__
 /*	eof=^D		eol=\0		eol2=\0		erase=del
diff -u --recursive --new-file v2.4.5/linux/include/asm-arm/linux_logo.h linux/include/asm-arm/linux_logo.h
--- v2.4.5/linux/include/asm-arm/linux_logo.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-arm/linux_logo.h	Mon Jun 11 19:15:27 2001
@@ -15,26 +15,5 @@
 
 #define linux_logo_banner "ARM Linux version " UTS_RELEASE
 
-#define LINUX_LOGO_COLORS	214
-
-#ifdef INCLUDE_LINUX_LOGO_DATA
-
-#define INCLUDE_LINUX_LOGOBW
-#define INCLUDE_LINUX_LOGO16
-
 #include <linux/linux_logo.h>
 
-#else
-
-/* prototypes only */
-extern unsigned char linux_logo_red[];
-extern unsigned char linux_logo_green[];
-extern unsigned char linux_logo_blue[];
-extern unsigned char linux_logo[];
-extern unsigned char linux_logo_bw[];
-extern unsigned char linux_logo16[];
-extern unsigned char *linux_serial_image;
-
-extern int (*console_show_logo)(void);
-
-#endif
diff -u --recursive --new-file v2.4.5/linux/include/asm-arm/termios.h linux/include/asm-arm/termios.h
--- v2.4.5/linux/include/asm-arm/termios.h	Sat Feb  3 20:00:45 2001
+++ linux/include/asm-arm/termios.h	Mon Jun 11 19:15:27 2001
@@ -65,6 +65,7 @@
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14
+#define N_HCI		15  /* Bluetooth HCI UART */
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-i386/hardirq.h linux/include/asm-i386/hardirq.h
--- v2.4.5/linux/include/asm-i386/hardirq.h	Fri May 25 18:01:27 2001
+++ linux/include/asm-i386/hardirq.h	Wed Jun 20 12:16:56 2001
@@ -5,10 +5,9 @@
 #include <linux/threads.h>
 #include <linux/irq.h>
 
-/* entry.S is sensitive to the offsets of these fields */
+/* assembly code in softirq.h is sensitive to the offsets of these fields */
 typedef struct {
-	unsigned int __softirq_active;
-	unsigned int __softirq_mask;
+	unsigned int __softirq_pending;
 	unsigned int __local_irq_count;
 	unsigned int __local_bh_count;
 	unsigned int __syscall_count;
diff -u --recursive --new-file v2.4.5/linux/include/asm-i386/hw_irq.h linux/include/asm-i386/hw_irq.h
--- v2.4.5/linux/include/asm-i386/hw_irq.h	Fri May 25 18:01:26 2001
+++ linux/include/asm-i386/hw_irq.h	Wed Jun 20 12:16:56 2001
@@ -13,6 +13,7 @@
  */
 
 #include <linux/config.h>
+#include <asm/atomic.h>
 #include <asm/irq.h>
 
 /*
@@ -83,7 +84,9 @@
 extern void send_IPI(int dest, int vector);
 
 extern unsigned long io_apic_irqs;
-extern volatile unsigned long irq_err_count;
+
+extern atomic_t irq_err_count;
+extern atomic_t irq_mis_count;
 
 extern char _stext, _etext;
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-i386/io_apic.h linux/include/asm-i386/io_apic.h
--- v2.4.5/linux/include/asm-i386/io_apic.h	Fri May 25 18:01:26 2001
+++ linux/include/asm-i386/io_apic.h	Wed Jun 20 12:16:56 2001
@@ -12,6 +12,8 @@
 
 #ifdef CONFIG_X86_IO_APIC
 
+#define APIC_MISMATCH_DEBUG
+
 #define IO_APIC_BASE(idx) \
 		((volatile int *)__fix_to_virt(FIX_IO_APIC_BASE_0 + idx))
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-i386/linux_logo.h linux/include/asm-i386/linux_logo.h
--- v2.4.5/linux/include/asm-i386/linux_logo.h	Fri May 25 18:02:51 2001
+++ linux/include/asm-i386/linux_logo.h	Mon Jun 11 19:15:27 2001
@@ -23,26 +23,5 @@
 
 #define linux_logo_banner "Linux/ia32 version " UTS_RELEASE
 
-#define LINUX_LOGO_COLORS 214
-
-#ifdef INCLUDE_LINUX_LOGO_DATA
-
-#define INCLUDE_LINUX_LOGOBW
-#define INCLUDE_LINUX_LOGO16
-
 #include <linux/linux_logo.h>
 
-#else
-
-/* prototypes only */
-extern unsigned char linux_logo_red[];
-extern unsigned char linux_logo_green[];
-extern unsigned char linux_logo_blue[];
-extern unsigned char linux_logo[];
-extern unsigned char linux_logo_bw[];
-extern unsigned char linux_logo16_red[];
-extern unsigned char linux_logo16_green[];
-extern unsigned char linux_logo16_blue[];
-extern unsigned char linux_logo16[];
-
-#endif
diff -u --recursive --new-file v2.4.5/linux/include/asm-i386/mca_dma.h linux/include/asm-i386/mca_dma.h
--- v2.4.5/linux/include/asm-i386/mca_dma.h	Wed Apr 12 09:47:29 2000
+++ linux/include/asm-i386/mca_dma.h	Tue Jun 12 11:06:54 2001
@@ -199,4 +199,4 @@
 	outb(mode, MCA_DMA_REG_EXE);
 }
 
-#endif MCA_DMA_H
+#endif /* MCA_DMA_H */
diff -u --recursive --new-file v2.4.5/linux/include/asm-i386/pci.h linux/include/asm-i386/pci.h
--- v2.4.5/linux/include/asm-i386/pci.h	Fri May 25 18:02:07 2001
+++ linux/include/asm-i386/pci.h	Wed Jun 20 12:17:25 2001
@@ -1,13 +1,19 @@
 #ifndef __i386_PCI_H
 #define __i386_PCI_H
 
+#include <linux/config.h>
+
 #ifdef __KERNEL__
 
 /* Can be used to override the logic in pci_scan_bus for skipping
    already-configured bus numbers - to be used for buggy BIOSes
    or architectures with incomplete PCI setup by the loader */
 
+#ifdef CONFIG_PCI
+extern unsigned int pcibios_assign_all_busses(void);
+#else
 #define pcibios_assign_all_busses()	0
+#endif
 
 extern unsigned long pci_mem_start;
 #define PCIBIOS_MIN_IO		0x1000
diff -u --recursive --new-file v2.4.5/linux/include/asm-i386/softirq.h linux/include/asm-i386/softirq.h
--- v2.4.5/linux/include/asm-i386/softirq.h	Fri May 25 18:01:27 2001
+++ linux/include/asm-i386/softirq.h	Wed Jun 20 12:16:56 2001
@@ -4,12 +4,46 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-#define cpu_bh_disable(cpu)	do { local_bh_count(cpu)++; barrier(); } while (0)
-#define cpu_bh_enable(cpu)	do { barrier(); local_bh_count(cpu)--; } while (0)
+#define __cpu_bh_enable(cpu) \
+		do { barrier(); local_bh_count(cpu)--; } while (0)
+#define cpu_bh_disable(cpu) \
+		do { local_bh_count(cpu)++; barrier(); } while (0)
 
 #define local_bh_disable()	cpu_bh_disable(smp_processor_id())
-#define local_bh_enable()	cpu_bh_enable(smp_processor_id())
+#define __local_bh_enable()	__cpu_bh_enable(smp_processor_id())
+#define __cpu_raise_softirq(cpu,nr) set_bit((nr), &softirq_pending(cpu));
+#define raise_softirq(nr) __cpu_raise_softirq(smp_processor_id(), (nr))
 
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
+
+/*
+ * NOTE: this assembly code assumes:
+ *
+ *    (char *)&local_bh_count - 8 == (char *)&softirq_pending
+ *
+ * If you change the offsets in irq_stat then you have to
+ * update this code as well.
+ */
+#define local_bh_enable()						\
+do {									\
+	unsigned int *ptr = &local_bh_count(smp_processor_id());	\
+									\
+	if (!--*ptr)							\
+		__asm__ __volatile__ (					\
+			"cmpl $0, -8(%0);"				\
+			"jnz 2f;"					\
+			"1:;"						\
+									\
+			".section .text.lock,\"ax\";"			\
+			"2: pushl %%eax; pushl %%ecx; pushl %%edx;"	\
+			"call do_softirq;"				\
+			"popl %%edx; popl %%ecx; popl %%eax;"		\
+			"jmp 1b;"					\
+			".previous;"					\
+									\
+		: /* no output */					\
+		: "r" (ptr)						\
+		/* no registers clobbered */ );				\
+} while (0)
 
 #endif	/* __ASM_SOFTIRQ_H */
diff -u --recursive --new-file v2.4.5/linux/include/asm-i386/termios.h linux/include/asm-i386/termios.h
--- v2.4.5/linux/include/asm-i386/termios.h	Sat Feb  3 20:00:45 2001
+++ linux/include/asm-i386/termios.h	Mon Jun 11 19:15:27 2001
@@ -55,6 +55,7 @@
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14	/* synchronous PPP */
+#define N_HCI		15  /* Bluetooth HCI UART */
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-ia64/linux_logo.h linux/include/asm-ia64/linux_logo.h
--- v2.4.5/linux/include/asm-ia64/linux_logo.h	Sun Feb  6 18:42:40 2000
+++ linux/include/asm-ia64/linux_logo.h	Mon Jun 11 19:15:27 2001
@@ -24,26 +24,5 @@
 
 #define linux_logo_banner "Linux/ia64 version " UTS_RELEASE
 
-#define LINUX_LOGO_COLORS 214
-
-#ifdef INCLUDE_LINUX_LOGO_DATA
-
-#define INCLUDE_LINUX_LOGOBW
-#define INCLUDE_LINUX_LOGO16
-
 #include <linux/linux_logo.h>
 
-#else
-
-/* prototypes only */
-extern unsigned char linux_logo_red[];
-extern unsigned char linux_logo_green[];
-extern unsigned char linux_logo_blue[];
-extern unsigned char linux_logo[];
-extern unsigned char linux_logo_bw[];
-extern unsigned char linux_logo16_red[];
-extern unsigned char linux_logo16_green[];
-extern unsigned char linux_logo16_blue[];
-extern unsigned char linux_logo16[];
-
-#endif
diff -u --recursive --new-file v2.4.5/linux/include/asm-ia64/termios.h linux/include/asm-ia64/termios.h
--- v2.4.5/linux/include/asm-ia64/termios.h	Sat Feb  3 20:00:45 2001
+++ linux/include/asm-ia64/termios.h	Mon Jun 11 19:15:27 2001
@@ -62,6 +62,7 @@
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS msgs */
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14	/* synchronous PPP */
+#define N_HCI		15  /* Bluetooth HCI UART */
 
 # ifdef __KERNEL__
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/amigahw.h linux/include/asm-m68k/amigahw.h
--- v2.4.5/linux/include/asm-m68k/amigahw.h	Mon Nov 27 17:57:34 2000
+++ linux/include/asm-m68k/amigahw.h	Mon Jun 11 19:15:27 2001
@@ -106,6 +106,7 @@
     AMIGAHW_DECLARE(ALICE_NTSC);	/* NTSC Alice (8374) */
     AMIGAHW_DECLARE(MAGIC_REKICK);	/* A3000 Magic Hard Rekick */
     AMIGAHW_DECLARE(PCMCIA);		/* PCMCIA Slot */
+    AMIGAHW_DECLARE(GG2_ISA);		/* GG2 Zorro2ISA Bridge */
     AMIGAHW_DECLARE(ZORRO);		/* Zorro AutoConfig */
     AMIGAHW_DECLARE(ZORRO3);		/* Zorro III */
 };
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/amigayle.h linux/include/asm-m68k/amigayle.h
--- v2.4.5/linux/include/asm-m68k/amigayle.h	Thu Jul 30 11:08:20 1998
+++ linux/include/asm-m68k/amigayle.h	Mon Jun 11 19:15:27 2001
@@ -17,8 +17,8 @@
 #ifndef _M68K_AMIGAYLE_H_
 #define _M68K_AMIGAYLE_H_
 
+#include <linux/types.h>
 #include <asm/amigahw.h>
-#include <asm/io.h>
 
 /* memory layout */
 
@@ -59,11 +59,13 @@
 
 #define gayle_attribute ((volatile u_char *)(GAYLE_ATTRIBUTE))
 
+#if 0
 #define gayle_inb(a) readb( GAYLE_IO+(a)+(((a)&1)*GAYLE_ODD) )
 #define gayle_outb(v,a) writeb( v, GAYLE_IO+(a)+(((a)&1)*GAYLE_ODD) )
 
 #define gayle_inw(a) readw( GAYLE_IO+(a) )
 #define gayle_outw(v,a) writew( v, GAYLE_IO+(a) )
+#endif
 
 /* GAYLE_CARDSTATUS bit def */
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/bitops.h linux/include/asm-m68k/bitops.h
--- v2.4.5/linux/include/asm-m68k/bitops.h	Sat Feb  3 11:26:44 2001
+++ linux/include/asm-m68k/bitops.h	Mon Jun 11 19:15:27 2001
@@ -19,23 +19,23 @@
    __constant_test_and_set_bit(nr, vaddr) : \
    __generic_test_and_set_bit(nr, vaddr))
 
-extern __inline__ int __constant_test_and_set_bit(int nr,void * vaddr)
+extern __inline__ int __constant_test_and_set_bit(int nr,volatile void * vaddr)
 {
 	char retval;
 
-	__asm__ __volatile__ ("bset %1,%2; sne %0"
-	     : "=d" (retval)
-	     : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3]));
+	__asm__ __volatile__ ("bset %2,%1; sne %0"
+	     : "=d" (retval), "+m" (((volatile char *)vaddr)[(nr^31) >> 3])
+	     : "di" (nr & 7));
 
 	return retval;
 }
 
-extern __inline__ int __generic_test_and_set_bit(int nr,void * vaddr)
+extern __inline__ int __generic_test_and_set_bit(int nr,volatile void * vaddr)
 {
 	char retval;
 
 	__asm__ __volatile__ ("bfset %2@{%1:#1}; sne %0"
-	     : "=d" (retval) : "d" (nr^31), "a" (vaddr));
+	     : "=d" (retval) : "d" (nr^31), "a" (vaddr) : "memory");
 
 	return retval;
 }
@@ -45,16 +45,16 @@
    __constant_set_bit(nr, vaddr) : \
    __generic_set_bit(nr, vaddr))
 
-extern __inline__ void __constant_set_bit(int nr, void * vaddr)
+extern __inline__ void __constant_set_bit(int nr, volatile void * vaddr)
 {
-	__asm__ __volatile__ ("bset %0,%1"
-	     : : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3]));
+	__asm__ __volatile__ ("bset %1,%0"
+	     : "+m" (((volatile char *)vaddr)[(nr^31) >> 3]) : "di" (nr & 7));
 }
 
-extern __inline__ void __generic_set_bit(int nr, void * vaddr)
+extern __inline__ void __generic_set_bit(int nr, volatile void * vaddr)
 {
 	__asm__ __volatile__ ("bfset %1@{%0:#1}"
-	     : : "d" (nr^31), "a" (vaddr));
+	     : : "d" (nr^31), "a" (vaddr) : "memory");
 }
 
 #define test_and_clear_bit(nr,vaddr) \
@@ -62,23 +62,23 @@
    __constant_test_and_clear_bit(nr, vaddr) : \
    __generic_test_and_clear_bit(nr, vaddr))
 
-extern __inline__ int __constant_test_and_clear_bit(int nr, void * vaddr)
+extern __inline__ int __constant_test_and_clear_bit(int nr, volatile void * vaddr)
 {
 	char retval;
 
-	__asm__ __volatile__ ("bclr %1,%2; sne %0"
-	     : "=d" (retval)
-	     : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3]));
+	__asm__ __volatile__ ("bclr %2,%1; sne %0"
+	     : "=d" (retval), "+m" (((volatile char *)vaddr)[(nr^31) >> 3])
+	     : "di" (nr & 7));
 
 	return retval;
 }
 
-extern __inline__ int __generic_test_and_clear_bit(int nr, void * vaddr)
+extern __inline__ int __generic_test_and_clear_bit(int nr, volatile void * vaddr)
 {
 	char retval;
 
 	__asm__ __volatile__ ("bfclr %2@{%1:#1}; sne %0"
-	     : "=d" (retval) : "d" (nr^31), "a" (vaddr));
+	     : "=d" (retval) : "d" (nr^31), "a" (vaddr) : "memory");
 
 	return retval;
 }
@@ -94,16 +94,16 @@
    __constant_clear_bit(nr, vaddr) : \
    __generic_clear_bit(nr, vaddr))
 
-extern __inline__ void __constant_clear_bit(int nr, void * vaddr)
+extern __inline__ void __constant_clear_bit(int nr, volatile void * vaddr)
 {
-	__asm__ __volatile__ ("bclr %0,%1"
-	     : : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3]));
+	__asm__ __volatile__ ("bclr %1,%0"
+	     : "+m" (((volatile char *)vaddr)[(nr^31) >> 3]) : "di" (nr & 7));
 }
 
-extern __inline__ void __generic_clear_bit(int nr, void * vaddr)
+extern __inline__ void __generic_clear_bit(int nr, volatile void * vaddr)
 {
 	__asm__ __volatile__ ("bfclr %1@{%0:#1}"
-	     : : "d" (nr^31), "a" (vaddr));
+	     : : "d" (nr^31), "a" (vaddr) : "memory");
 }
 
 #define test_and_change_bit(nr,vaddr) \
@@ -111,23 +111,26 @@
    __constant_test_and_change_bit(nr, vaddr) : \
    __generic_test_and_change_bit(nr, vaddr))
 
-extern __inline__ int __constant_test_and_change_bit(int nr, void * vaddr)
+#define __test_and_change_bit(nr,vaddr) test_and_change_bit(nr,vaddr)
+#define __change_bit(nr,vaddr) change_bit(nr,vaddr)
+
+extern __inline__ int __constant_test_and_change_bit(int nr, volatile void * vaddr)
 {
 	char retval;
 
-	__asm__ __volatile__ ("bchg %1,%2; sne %0"
-	     : "=d" (retval)
-	     : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3]));
+	__asm__ __volatile__ ("bchg %2,%1; sne %0"
+	     : "=d" (retval), "+m" (((volatile char *)vaddr)[(nr^31) >> 3])
+	     : "di" (nr & 7));
 
 	return retval;
 }
 
-extern __inline__ int __generic_test_and_change_bit(int nr, void * vaddr)
+extern __inline__ int __generic_test_and_change_bit(int nr, volatile void * vaddr)
 {
 	char retval;
 
 	__asm__ __volatile__ ("bfchg %2@{%1:#1}; sne %0"
-	     : "=d" (retval) : "d" (nr^31), "a" (vaddr));
+	     : "=d" (retval) : "d" (nr^31), "a" (vaddr) : "memory");
 
 	return retval;
 }
@@ -137,21 +140,21 @@
    __constant_change_bit(nr, vaddr) : \
    __generic_change_bit(nr, vaddr))
 
-extern __inline__ void __constant_change_bit(int nr, void * vaddr)
+extern __inline__ void __constant_change_bit(int nr, volatile void * vaddr)
 {
-	__asm__ __volatile__ ("bchg %0,%1"
-	     : : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3]));
+	__asm__ __volatile__ ("bchg %1,%0"
+	     : "+m" (((volatile char *)vaddr)[(nr^31) >> 3]) : "di" (nr & 7));
 }
 
-extern __inline__ void __generic_change_bit(int nr, void * vaddr)
+extern __inline__ void __generic_change_bit(int nr, volatile void * vaddr)
 {
 	__asm__ __volatile__ ("bfchg %1@{%0:#1}"
-	     : : "d" (nr^31), "a" (vaddr));
+	     : : "d" (nr^31), "a" (vaddr) : "memory");
 }
 
-extern __inline__ int test_bit(int nr, const void * vaddr)
+extern __inline__ int test_bit(int nr, const volatile void * vaddr)
 {
-	return ((1UL << (nr & 31)) & (((const unsigned int *) vaddr)[nr >> 5])) != 0;
+	return ((1UL << (nr & 31)) & (((const volatile unsigned int *) vaddr)[nr >> 5])) != 0;
 }
 
 extern __inline__ int find_first_zero_bit(void * vaddr, unsigned size)
@@ -228,7 +231,7 @@
 {
 	int cnt;
 
-	asm ("bfffo %1{#0:#0},%0" : "=d" (cnt) : "dm" (x & -x));
+	__asm__ __volatile__("bfffo %1{#0:#0},%0" : "=d" (cnt) : "dm" (x & -x));
 
 	return 32 - cnt;
 }
@@ -268,12 +271,12 @@
 }
 
 extern __inline__ int
-minix_test_and_set_bit (int nr, void *vaddr)
+minix_test_and_set_bit (int nr, volatile void *vaddr)
 {
 	char retval;
 
 	__asm__ __volatile__ ("bfset %2{%1:#1}; sne %0"
-	     : "=d" (retval) : "d" (nr^15), "m" (*(char *)vaddr));
+	     : "=d" (retval) : "d" (nr^15), "m" (*(volatile char *)vaddr) : "memory");
 
 	return retval;
 }
@@ -281,50 +284,50 @@
 #define minix_set_bit(nr,addr)	((void)minix_test_and_set_bit(nr,addr))
 
 extern __inline__ int
-minix_test_and_clear_bit (int nr, void *vaddr)
+minix_test_and_clear_bit (int nr, volatile void *vaddr)
 {
 	char retval;
 
 	__asm__ __volatile__ ("bfclr %2{%1:#1}; sne %0"
-	     : "=d" (retval) : "d" (nr^15), "m" (*(char *) vaddr));
+	     : "=d" (retval) : "d" (nr^15), "m" (*(volatile char *) vaddr) : "memory");
 
 	return retval;
 }
 
 extern __inline__ int
-minix_test_bit (int nr, const void *vaddr)
+minix_test_bit (int nr, const volatile void *vaddr)
 {
-	return ((1U << (nr & 15)) & (((const unsigned short *) vaddr)[nr >> 4])) != 0;
+	return ((1U << (nr & 15)) & (((const volatile unsigned short *) vaddr)[nr >> 4])) != 0;
 }
 
 /* Bitmap functions for the ext2 filesystem. */
 
 extern __inline__ int
-ext2_set_bit (int nr, void *vaddr)
+ext2_set_bit (int nr, volatile void *vaddr)
 {
 	char retval;
 
 	__asm__ __volatile__ ("bfset %2{%1,#1}; sne %0"
-	     : "=d" (retval) : "d" (nr^7), "m" (*(char *) vaddr));
+	     : "=d" (retval) : "d" (nr^7), "m" (*(volatile char *) vaddr) : "memory");
 
 	return retval;
 }
 
 extern __inline__ int
-ext2_clear_bit (int nr, void *vaddr)
+ext2_clear_bit (int nr, volatile void *vaddr)
 {
 	char retval;
 
 	__asm__ __volatile__ ("bfclr %2{%1,#1}; sne %0"
-	     : "=d" (retval) : "d" (nr^7), "m" (*(char *) vaddr));
+	     : "=d" (retval) : "d" (nr^7), "m" (*(volatile char *) vaddr) : "memory");
 
 	return retval;
 }
 
 extern __inline__ int
-ext2_test_bit (int nr, const void *vaddr)
+ext2_test_bit (int nr, const volatile void *vaddr)
 {
-	return ((1U << (nr & 7)) & (((const unsigned char *) vaddr)[nr >> 3])) != 0;
+	return ((1U << (nr & 7)) & (((const volatile unsigned char *) vaddr)[nr >> 3])) != 0;
 }
 
 extern __inline__ int
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/dvma.h linux/include/asm-m68k/dvma.h
--- v2.4.5/linux/include/asm-m68k/dvma.h	Fri Dec 29 14:07:23 2000
+++ linux/include/asm-m68k/dvma.h	Mon Jun 11 19:15:27 2001
@@ -11,17 +11,37 @@
 
 #include <linux/config.h>
 
+#define DVMA_PAGE_SHIFT	13
+#define DVMA_PAGE_SIZE	(1UL << DVMA_PAGE_SHIFT)
+#define DVMA_PAGE_MASK	(~(DVMA_PAGE_SIZE-1))
+#define DVMA_PAGE_ALIGN(addr)	(((addr)+DVMA_PAGE_SIZE-1)&DVMA_PAGE_MASK)
+
+extern void dvma_init(void);	
+extern int dvma_map_iommu(unsigned long kaddr, unsigned long baddr, 
+			  int len);
+
+#define dvma_malloc(x) dvma_malloc_align(x, 0)
+#define dvma_map(x, y) dvma_map_align(x, y, 0)
+
+extern unsigned long dvma_map_align(unsigned long kaddr, int len, 
+			    int align);
+extern void *dvma_malloc_align(unsigned long len, unsigned long align);
+
+extern void dvma_unmap(void *baddr);
+extern void dvma_free(void *vaddr);
+
+
 #ifdef CONFIG_SUN3
 /* sun3 dvma page support */
 
-#define DVMA_RESERVED_PMEGS 2 /* 256k of dvma */
-
 /* memory and pmegs potentially reserved for dvma */
 #define DVMA_PMEG_START 10
 #define DVMA_PMEG_END 16
-#define DVMA_START 0xff00000
-#define DVMA_END 0xffe0000
+#define DVMA_START 0xf00000
+#define DVMA_END 0xfe0000
 #define DVMA_SIZE (DVMA_END-DVMA_START)
+#define IOMMU_TOTAL_ENTRIES 128
+#define IOMMU_ENTRIES 120
 
 /* empirical kludge -- dvma regions only seem to work right on 0x10000 
    byte boundries */
@@ -29,15 +49,40 @@
 #define DVMA_ALIGN(addr) (((addr)+DVMA_REGION_SIZE-1) & \
                          ~(DVMA_REGION_SIZE-1))
 
-
 /* virt <-> phys conversions */
-#define sun3_dvma_vtop(x) ((unsigned long)(x) & 0xffffff)
-#define sun3_dvma_ptov(x) ((unsigned long)(x) | 0xf000000)
+#define dvma_vtop(x) ((unsigned long)(x) & 0xffffff)
+#define dvma_ptov(x) ((unsigned long)(x) | 0xf000000)
+#define dvma_vtob(x) dvma_vtop(x)
+#define dvma_btov(x) dvma_ptov(x)
+
+extern inline int dvma_map_cpu(unsigned long kaddr, unsigned long vaddr, int len)
+{
+	return 0;
+}
+
+extern unsigned long dvma_page(unsigned long kaddr, unsigned long vaddr);
 
-extern void sun3_dvma_init(void);	
-extern void *sun3_dvma_malloc(int len);
 #else /* Sun3x */
 
+/* sun3x dvma page support */
+
+#define DVMA_START 0x0
+#define DVMA_END 0xf00000
+#define DVMA_SIZE (DVMA_END-DVMA_START)
+#define IOMMU_TOTAL_ENTRIES	   2048
+/* the prom takes the top meg */
+#define IOMMU_ENTRIES              (IOMMU_TOTAL_ENTRIES - 0x80)
+
+#define dvma_vtob(x) ((unsigned long)(x) & 0x00ffffff)
+#define dvma_btov(x) ((unsigned long)(x) | 0xff000000)
+
+extern int dvma_map_cpu(unsigned long kaddr, unsigned long vaddr, int len);
+
+
+
+/* everything below this line is specific to dma used for the onboard 
+   ESP scsi on sun3x */
+
 /* Structure to describe the current status of DMA registers on the Sparc */
 struct sparc_dma_registers {
   __volatile__ unsigned long cond_reg;	/* DMA condition register */
@@ -188,7 +233,7 @@
 	dma->running = 0;                                                  \
 } while(0)
 
-extern unsigned long dvma_alloc (unsigned long, unsigned long);
-extern void dvma_free (unsigned long, unsigned long);
+
 #endif /* !CONFIG_SUN3 */
+
 #endif /* !(__M68K_DVMA_H) */
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/floppy.h linux/include/asm-m68k/floppy.h
--- v2.4.5/linux/include/asm-m68k/floppy.h	Thu Jan  4 13:00:55 2001
+++ linux/include/asm-m68k/floppy.h	Mon Jun 11 19:15:27 2001
@@ -1,23 +1,58 @@
 /*
- * Q40 Architecture specific parts of the Floppy driver
+ * Implementation independent bits of the Floppy driver.
+ *
+ * much of this file is derived from what was originally the Q40 floppy driver.
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1999
+ * Copyright (C) 1999, 2000, 2001
+ *
+ * Sun3x support added 2/4/2000 Sam Creasey (sammy@oh.verio.com)
+ *
  */
 
 #include <asm/io.h>
 
 #include <linux/vmalloc.h>
 
-
 asmlinkage void floppy_hardint(int irq, void *dev_id, struct pt_regs * regs);
 
+/* constants... */
+
 #undef MAX_DMA_ADDRESS
 #define MAX_DMA_ADDRESS   0x00  /* nothing like that */
 
+
+/*
+ * Again, the CMOS information doesn't work on m68k..
+ */
+#define FLOPPY0_TYPE (MACH_IS_Q40 ? 6 : 4)
+#define FLOPPY1_TYPE 0
+
+#define FLOPPY_MOTOR_MASK 0xf0
+
+
+/* basically PC init + set use_virtual_dma */
+#define  FDC1 m68k_floppy_init()
+static int FDC2 = -1;
+
+
+#define N_FDC 1
+#define N_DRIVE 8
+
+
+/* vdma globals adapted from asm-i386/floppy.h */
+
+static int virtual_dma_count=0;
+static int virtual_dma_residue=0;
+static char *virtual_dma_addr=0;
+static int virtual_dma_mode=0;
+static int doing_pdma=0;
+
+#include <asm/sun3xflop.h>
+
 extern spinlock_t  dma_spin_lock;
 
 static __inline__ unsigned long claim_dma_lock(void)
@@ -33,23 +68,46 @@
 }
 
 
+static __inline__ unsigned char fd_inb(int port)
+{
+	if(MACH_IS_Q40)
+		return inb_p(port);
+	else if(MACH_IS_SUN3X)
+		return sun3x_82072_fd_inb(port);
+}
 
-#define fd_inb(port)			inb_p(port)
-#define fd_outb(port,value)		outb_p(port,value)
+static __inline__ void fd_outb(unsigned char value, int port)
+{
+	if(MACH_IS_Q40)
+		outb_p(value, port);
+	else if(MACH_IS_SUN3X)
+		sun3x_82072_fd_outb(value, port);
+}
 
 
-#define fd_request_dma()        vdma_request_dma(FLOPPY_DMA,"floppy")
-/*#define fd_free_dma()           */
+static int fd_request_irq(void)
+{
+	if(MACH_IS_Q40)
+		return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
+						   "floppy", NULL);
+	else if(MACH_IS_SUN3X) 
+		return sun3xflop_request_irq();
+	
+}
 
+static void fd_free_irq(void)
+{
+	if(MACH_IS_Q40)
+		free_irq(FLOPPY_IRQ, NULL);
+}
 
+#define fd_request_dma()        vdma_request_dma(FLOPPY_DMA,"floppy")
 #define fd_get_dma_residue()    vdma_get_dma_residue(FLOPPY_DMA)
 #define fd_dma_mem_alloc(size)	vdma_mem_alloc(size)
 #define fd_dma_setup(addr, size, mode, io) vdma_dma_setup(addr, size, mode, io)
 
-
 #define fd_enable_irq()           /* nothing... */
 #define fd_disable_irq()          /* nothing... */
-#define fd_free_irq()		free_irq(FLOPPY_IRQ, NULL)
 
 #define fd_free_dma()             /* nothing */
 
@@ -60,62 +118,71 @@
 #define DMA_MODE_WRITE 0x48
 
 
-static int q40_floppy_init(void)
+static int m68k_floppy_init(void)
 {
   use_virtual_dma =1;
-  /* FLOPPY_IRQ=6; */
-
+  can_use_virtual_dma = 1;
+ 
+  
   if (MACH_IS_Q40)  
-    return 0x3f0;
+	  return 0x3f0;
+  else if(MACH_IS_SUN3X)
+	  return sun3xflop_init();
   else
     return -1;
 }
 
 
+static int vdma_request_dma(unsigned int dmanr, const char * device_id)
+{
+	return 0;
+}
 
 
-/*
- * Again, the CMOS information doesn't work on the Q40..
- */
-#define FLOPPY0_TYPE 6
-#define FLOPPY1_TYPE 0
-
-
-
-
-#define FLOPPY_MOTOR_MASK 0xf0
-
-
-
+static int vdma_get_dma_residue(unsigned int dummy)
+{
+	return virtual_dma_count + virtual_dma_residue;
+}
 
-/* basically PC init + set use_virtual_dma */
-#define  FDC1 q40_floppy_init()
-static int FDC2 = -1;
 
+static unsigned long vdma_mem_alloc(unsigned long size)
+{
+	return (unsigned long) vmalloc(size);
 
-#define N_FDC 1
-#define N_DRIVE 8
+}
 
+static void _fd_dma_mem_free(unsigned long addr, unsigned long size)
+{
+        vfree((void *)addr);
+}
+#define fd_dma_mem_free(addr,size) _fd_dma_mem_free(addr, size)
 
 
-/* vdma stuff adapted from asm-i386/floppy.h */
+/* choose_dma_mode ???*/
 
-static int virtual_dma_count=0;
-static int virtual_dma_residue=0;
-static char *virtual_dma_addr=0;
-static int virtual_dma_mode=0;
-static int doing_pdma=0;
+static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
+{
+	doing_pdma = 1;
+	virtual_dma_port = (MACH_IS_Q40 ? io : 0);
+	virtual_dma_mode = (mode  == DMA_MODE_WRITE);
+	virtual_dma_addr = addr;
+	virtual_dma_count = size;
+	virtual_dma_residue = 0;
+	return 0;
+}
 
 
 
-static int fd_request_irq(void)
+static void fd_disable_dma(void)
 {
-  return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
-						   "floppy", NULL);
+	doing_pdma = 0;
+	virtual_dma_residue += virtual_dma_count;
+	virtual_dma_count=0;
 }
 
-/*#define SLOW_DOWN do{outb(0,0x80);}while(0)*/
-#define SLOW_DOWN do{int count=1;do{if(!jiffies)break;}while(count-->0);}while(0)
+
+
+/* this is the only truly Q40 specific function */
 
 asmlinkage void floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
 {
@@ -185,55 +252,6 @@
 	if(!virtual_dma_count)
 		dma_wait++;
 #endif
-}
-
-
-
-static int vdma_request_dma(unsigned int dmanr, const char * device_id)
-{
-	return 0;
-}
-
-
-static int vdma_get_dma_residue(unsigned int dummy)
-{
-	return virtual_dma_count + virtual_dma_residue;
-}
-
-
-static unsigned long vdma_mem_alloc(unsigned long size)
-{
-	return (unsigned long) vmalloc(size);
-
-}
-
-static void _fd_dma_mem_free(unsigned long addr, unsigned long size)
-{
-        vfree((void *)addr);
-}
-#define fd_dma_mem_free(addr,size) _fd_dma_mem_free(addr, size)
-
-
-/* choose_dma_mode ???*/
-
-static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
-{
-	doing_pdma = 1;
-	virtual_dma_port = io;
-	virtual_dma_mode = (mode  == DMA_MODE_WRITE);
-	virtual_dma_addr = addr;
-	virtual_dma_count = size;
-	virtual_dma_residue = 0;
-	return 0;
-}
-
-
-
-static void fd_disable_dma(void)
-{
-	doing_pdma = 0;
-	virtual_dma_residue += virtual_dma_count;
-	virtual_dma_count=0;
 }
 
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/ide.h linux/include/asm-m68k/ide.h
--- v2.4.5/linux/include/asm-m68k/ide.h	Fri Dec 29 14:07:23 2000
+++ linux/include/asm-m68k/ide.h	Mon Jun 11 19:15:27 2001
@@ -61,10 +61,6 @@
           return 0;
 }
 
-/*
- *  Can we do this in a generic manner??
- */
-
 
 /*
  * Set up a hw structure for a specified data port, control port and IRQ.
@@ -160,219 +156,64 @@
 #define SUPPORT_VLB_SYNC 0
 
 /* this definition is used only on startup .. */
-#ifndef CONFIG_Q40
 #undef HD_DATA
 #define HD_DATA NULL
+
+
+/* get rid of defs from io.h - ide has its private and conflicting versions */
+#undef inb
+#undef inw
+#undef outb
+#undef outw
+#undef inb_p
+#undef outb_p
+#undef insw
+#undef outsw
+#undef insw_swapw
+#undef outsw_swapw
+
+/* 
+ * define IO method and translation,
+ * so far only Q40 has ide-if on ISA 
+*/
+#ifndef CONFIG_Q40
+
+#define ADDR_TRANS_B(_addr_) (_addr_)
+#define ADDR_TRANS_W(_addr_) (_addr_)
+
 #else
-#ifdef MACH_Q40_ONLY
-#undef HD_DATA
-#define HD_DATA ((ide_ioreg_t)0x1f0)
-#else
-#undef HD_DATA
-#define HD_DATA   (MACH_IS_Q40 ? (ide_ioreg_t)0x1f0 : 0)
-#endif
+
+#define ADDR_TRANS_B(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_B(_addr_)) : (_addr_))
+#define ADDR_TRANS_W(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_W(_addr_)) : (_addr_))
 #endif
 
+#define inb(p)     in_8(ADDR_TRANS_B(p))
+#define inb_p(p)     in_8(ADDR_TRANS_B(p))
+#define inw(p)     in_be16(ADDR_TRANS_W(p))
+#define outb(v,p)  out_8(ADDR_TRANS_B(p),v)
+#define outb_p(v,p)  out_8(ADDR_TRANS_B(p),v)
+#define outw(v,p)  out_be16(ADDR_TRANS_W(p),v)
+
+#define insw(port, buf, nr) raw_insw(ADDR_TRANS_W(port), buf, nr)
+#define outsw(port, buf, nr) raw_outsw(ADDR_TRANS_W(port), buf, nr)
 
 #define insl(data_reg, buffer, wcount) insw(data_reg, buffer, (wcount)<<1)
 #define outsl(data_reg, buffer, wcount) outsw(data_reg, buffer, (wcount)<<1)
 
-#ifdef CONFIG_Q40
-#ifdef MACH_Q40_ONLY
-#define ADDR_TRANS(_addr_) (Q40_ISA_IO_W(_addr_))
-#else
-#define ADDR_TRANS(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_W(_addr_)) : (_addr_))
-#endif
-#else
-#define ADDR_TRANS(_addr_) (_addr_)
-#endif
 
-#define insw(port, buf, nr) ({				\
-	unsigned char *_port = (unsigned char *) ADDR_TRANS(port);	\
-	unsigned char *_buf = (buf);			\
-	int _nr = (nr);					\
-	unsigned long _tmp;				\
-							\
-	if (_nr & 15) {					\
-		_tmp = (_nr & 15) - 1;			\
-		asm volatile (				\
-			"1: movew %2@,%0@+; dbra %1,1b"	\
-			: "=a" (_buf), "=d" (_tmp)	\
-			: "a" (_port), "0" (_buf),	\
-			  "1" (_tmp));			\
-	}						\
-	if (_nr >> 4) {					\
-		_tmp = (_nr >> 4) - 1;			\
-		asm volatile (				\
-			"1: "				\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"dbra %1,1b"			\
-			: "=a" (_buf), "=d" (_tmp)	\
-			: "a" (_port), "0" (_buf),	\
-			  "1" (_tmp));			\
-	}						\
-})
-
-#define outsw(port, buf, nr) ({				\
-	unsigned char *_port = (unsigned char *) ADDR_TRANS(port);	\
-	unsigned char *_buf = (buf);			\
-	int _nr = (nr);					\
-	unsigned long _tmp;				\
-							\
-	if (_nr & 15) {					\
-		_tmp = (_nr & 15) - 1;			\
-		asm volatile (				\
-			"1: movew %0@+,%2@; dbra %1,1b"	\
-			: "=a" (_buf), "=d" (_tmp)	\
-			: "a" (_port), "0" (_buf),	\
-			  "1" (_tmp));			\
-	}						\
-	if (_nr >> 4) {					\
-		_tmp = (_nr >> 4) - 1;			\
-		asm volatile (				\
-			"1: "				\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"dbra %1,1b"	   		\
-			: "=a" (_buf), "=d" (_tmp)	\
-			: "a" (_port), "0" (_buf),	\
-			  "1" (_tmp));			\
-	}						\
-})
 
 #if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+
 #define insl_swapw(data_reg, buffer, wcount) \
     insw_swapw(data_reg, buffer, (wcount)<<1)
 #define outsl_swapw(data_reg, buffer, wcount) \
     outsw_swapw(data_reg, buffer, (wcount)<<1)
 
-#define insw_swapw(port, buf, nr) \
-    if ((nr) % 8) \
-	__asm__ __volatile__ \
-	       ("movel %0,%/a0; \
-		 movel %1,%/a1; \
-		 movel %2,%/d6; \
-		 subql #1,%/d6; \
-	       1:movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 dbra %/d6,1b" : \
-		: "g" (ADDR_TRANS(port)), "g" (buf), "g" (nr) \
-		: "d0", "a0", "a1", "d6"); \
-    else \
-	__asm__ __volatile__ \
-	       ("movel %0,%/a0; \
-		 movel %1,%/a1; \
-		 movel %2,%/d6; \
-		 lsrl  #3,%/d6; \
-		 subql #1,%/d6; \
-	       1:movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 dbra %/d6,1b" : \
-		: "g" (ADDR_TRANS(port)), "g" (buf), "g" (nr) \
-		: "d0", "a0", "a1", "d6") 
-
-
-#define outsw_swapw(port, buf, nr) \
-    if ((nr) % 8) \
-	__asm__ __volatile__ \
-	       ("movel %0,%/a0; \
-		 movel %1,%/a1; \
-		 movel %2,%/d6; \
-		 subql #1,%/d6; \
-	       1:movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 dbra %/d6,1b" : \
-		: "g" (ADDR_TRANS(port)), "g" (buf), "g" (nr) \
-		: "d0", "a0", "a1", "d6"); \
-    else \
-	__asm__ __volatile__ \
-	       ("movel %0,%/a0; \
-		 movel %1,%/a1; \
-		 movel %2,%/d6; \
-		 lsrl  #3,%/d6; \
-		 subql #1,%/d6; \
-	       1:movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 dbra %/d6,1b" : \
-		: "g" (ADDR_TRANS(port)), "g" (buf), "g" (nr) \
-		: "d0", "a0", "a1", "d6")
+#define insw_swapw(port, buf, nr) raw_insw_swapw(ADDR_TRANS_W(port), buf, nr)
+#define outsw_swapw(port, buf, nr) raw_outsw_swapw(ADDR_TRANS_W(port),buf,nr)
+
+#endif /* CONFIG_ATARI || CONFIG_Q40 */
 
-#endif /* CONFIG_ATARI */
 
 #define T_CHAR          (0x0000)        /* char:  don't touch  */
 #define T_SHORT         (0x4000)        /* short: 12 -> 21     */
@@ -387,7 +228,15 @@
 #define D_INT(cnt)      (T_INT   | (cnt))
 #define D_TEXT(cnt)     (T_TEXT  | (cnt))
 
-#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC)
+/* Q40 and Atari have byteswapped IDE bus and since many interesting
+ * values in the identification string are text, chars and words they
+ * happened to be almost correct without swapping.. However *_capacity 
+ * is needed for drives over 8 GB. RZ */
+#if defined(CONFIG_Q40) || defined(CONFIG_ATARI)
+#define M68K_IDE_SWAPW  (MACH_IS_Q40 || MACH_IS_ATARI)
+#endif
+
+#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC) || defined(M68K_IDE_SWAPW)
 static u_short driveid_types[] = {
 	D_SHORT(10),	/* config - vendor2 */
 	D_TEXT(20),	/* serial_no */
@@ -402,7 +251,7 @@
 	D_INT(1),	/* cur_capacity */
 	D_CHAR(2),	/* multsect - multsect_valid */
 	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reservedyy */
+	D_SHORT(194)	/* dma_1word - reserved */
 };
 
 #define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
@@ -410,13 +259,19 @@
 
 static __inline__ void ide_fix_driveid(struct hd_driveid *id)
 {
-#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC)
+#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC) || defined(M68K_IDE_SWAPW)
    u_char *p = (u_char *)id;
    int i, j, cnt;
    u_char t;
 
-   if (!MACH_IS_AMIGA && !MACH_IS_MAC)
+   if (!MACH_IS_AMIGA && !MACH_IS_MAC && !MACH_IS_Q40 && !MACH_IS_ATARI)
    	return;
+#ifdef M68K_IDE_SWAPW
+   if (M68K_IDE_SWAPW)    /* fix bus byteorder first */
+      for (i=0; i < 512; i+=2) {
+	 t = p[i]; p[i] = p[i+1]; p[i+1] = t; 
+      }
+#endif
    for (i = 0; i < num_driveid_types; i++) {
       cnt = driveid_types[i] & T_MASK_COUNT;
       switch (driveid_types[i] & T_MASK_TYPE) {
@@ -425,28 +280,28 @@
             break;
          case T_SHORT:
             for (j = 0; j < cnt; j++) {
-               t = p[0];
-               p[0] = p[1];
-               p[1] = t;
+	       t = p[0];
+	       p[0] = p[1];
+	       p[1] = t;
                p += 2;
             }
             break;
          case T_INT:
             for (j = 0; j < cnt; j++) {
-               t = p[0];
-               p[0] = p[3];
-               p[3] = t;
-               t = p[1];
-               p[1] = p[2];
-               p[2] = t;
+	       t = p[0];
+	       p[0] = p[3];
+	       p[3] = t;
+	       t = p[1];
+	       p[1] = p[2];
+	       p[2] = t;
                p += 4;
             }
             break;
          case T_TEXT:
             for (j = 0; j < cnt; j += 2) {
-               t = p[0];
-               p[0] = p[1];
-               p[1] = t;
+	       t = p[0];
+	       p[0] = p[1];
+	       p[1] = t;
                p += 2;
             }
             break;
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/intersil.h linux/include/asm-m68k/intersil.h
--- v2.4.5/linux/include/asm-m68k/intersil.h	Fri Dec 29 14:07:23 2000
+++ linux/include/asm-m68k/intersil.h	Mon Jun 11 19:15:27 2001
@@ -25,21 +25,21 @@
 #define INTERSIL_HZ_100_MASK	 0x02
 
 struct intersil_dt {
-	u_char	csec;
-	u_char	hour;
-	u_char	minute;
-	u_char	second;
-	u_char	month;
-	u_char	day;
-	u_char	year;
-	u_char	weekday;
+	unsigned char	csec;
+	unsigned char	hour;
+	unsigned char	minute;
+	unsigned char	second;
+	unsigned char	month;
+	unsigned char	day;
+	unsigned char	year;
+	unsigned char	weekday;
 };
 
 struct intersil_7170 {
 	struct intersil_dt counter;
 	struct intersil_dt alarm;
-	u_char	int_reg;
-	u_char	cmd_reg;
+	unsigned char	int_reg;
+	unsigned char	cmd_reg;
 };
 
 extern volatile char* clock_va;
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/io.h linux/include/asm-m68k/io.h
--- v2.4.5/linux/include/asm-m68k/io.h	Thu Jan  4 13:00:55 2001
+++ linux/include/asm-m68k/io.h	Mon Jun 11 19:15:27 2001
@@ -1,57 +1,260 @@
-#ifndef _M68K_IO_H
-#define _M68K_IO_H
+/*
+ * linux/include/asm-m68k/io.h 
+ *
+ * 4/1/00 RZ: - rewritten to avoid clashes between ISA/PCI and other
+ *              IO access
+ *            - added Q40 support
+ *            - added skeleton for GG-II and Amiga PCMCIA
+ * 2/3/01 RZ: - moved a few more defs into raw_io.h
+ *
+ * inX/outX/readX/writeX should not be used by any driver unless it does
+ * ISA or PCI access. Other drivers should use function defined in raw_io.h
+ * or define its own macros on top of these.
+ *
+ *    inX(),outX()              are for PCI and ISA I/O
+ *    readX(),writeX()          are for PCI memory
+ *    isa_readX(),isa_writeX()  are for ISA memory
+ *
+ * moved mem{cpy,set}_*io inside CONFIG_PCI
+ */
+
+#ifndef _IO_H
+#define _IO_H
 
 #ifdef __KERNEL__
 
 #include <linux/config.h>
+#include <asm/raw_io.h>
+#include <asm/virtconvert.h>
+
 
 #ifdef CONFIG_ATARI
 #include <asm/atarihw.h>
-
-#define SLOW_DOWN_IO	do { if (MACH_IS_ATARI) MFPDELAY(); } while (0)
 #endif
 
-#include <asm/virtconvert.h>
 
 /*
- * These are for PCI shared memory _only_ and should never be used
- * on any other type of memory, including Zorro memory. They are meant to
- * access the bus in the bus byte order which is little-endian!.
- *
- * readX/writeX() are used to access memory mapped devices. On some
- * architectures the memory mapped IO stuff needs to be accessed
- * differently. On the m68k architecture, we just read/write the
- * memory location directly.
+ * IO/MEM definitions for various ISA bridges
  */
-/* ++roman: The assignments to temp. vars avoid that gcc sometimes generates
- * two accesses to memory, which may be undesireable for some devices.
+
+
+#ifdef CONFIG_Q40
+
+#define q40_isa_io_base  0xff400000
+#define q40_isa_mem_base 0xff800000
+
+#define Q40_ISA_IO_B(ioaddr) (q40_isa_io_base+1+4*((unsigned long)(ioaddr)))
+#define Q40_ISA_IO_W(ioaddr) (q40_isa_io_base+  4*((unsigned long)(ioaddr)))
+#define Q40_ISA_MEM_B(madr)  (q40_isa_mem_base+1+4*((unsigned long)(madr)))
+#define Q40_ISA_MEM_W(madr)  (q40_isa_mem_base+  4*((unsigned long)(madr)))
+
+#define MACH_HAS_ISA 1
+#endif /* Q40 */
+
+/* GG-II Zorro to ISA bridge */
+#ifdef CONFIG_GG2
+
+extern unsigned long gg2_isa_base;
+#define GG2_ISA_IO_B(ioaddr) (gg2_isa_base+1+((unsigned long)(ioaddr)*4))
+#define GG2_ISA_IO_W(ioaddr) (gg2_isa_base+  ((unsigned long)(ioaddr)*4))
+#define GG2_ISA_MEM_B(madr)  (gg2_isa_base+1+(((unsigned long)(madr)*4) & 0xfffff))
+#define GG2_ISA_MEM_W(madr)  (gg2_isa_base+  (((unsigned long)(madr)*4) & 0xfffff))
+
+#ifndef MACH_HAS_ISA
+#define MACH_HAS_ISA 1
+#else 
+#undef MACH_HAS_ISA
+#define MACH_HAS_ISA m
+#endif
+#endif /* GG2 */
+
+#ifdef CONFIG_AMIGA_PCMCIA
+#include <asm/amigayle.h>
+
+#define AG_ISA_IO_B(ioaddr) ( GAYLE_IO+(ioaddr)+(((ioaddr)&1)*GAYLE_ODD) )
+#define AG_ISA_IO_W(ioaddr) ( GAYLE_IO+(ioaddr) )
+
+#ifndef MACH_HAS_ISA
+#define MACH_HAS_ISA 1
+#else 
+#undef MACH_HAS_ISA
+#define MACH_HAS_ISA m
+#endif
+#endif /* AMIGA_PCMCIA */
+
+
+
+#ifdef MACH_HAS_ISA
+
+#define Q40_ISA (1)
+#define GG2_ISA (2)
+#define AG_ISA  (3)
+
+#if defined(CONFIG_Q40) && MACH_HAS_ISA==1
+#define ISA_TYPE Q40_ISA
+#define ISA_SEX  0
+#endif
+#if defined(CONFIG_AMIGA_PCMCIA) && MACH_HAS_ISA==1
+#define ISA_TYPE AG_ISA
+#define ISA_SEX  1
+#endif 
+#if defined(CONFIG_GG2) && MACH_HAS_ISA==1
+#define ISA_TYPE GG2_ISA
+#define ISA_SEX  0
+#endif
+
+#ifdef CONFIG_ISA
+extern int isa_type;
+extern int isa_sex;
+
+#define ISA_TYPE isa_type
+#define ISA_SEX  isa_sex
+#endif
+
+/*
+ * define inline addr translation functions. Normally only one variant will
+ * be compiled in so the case statement will be optimised away
  */
-#define readb(addr) \
-    ({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; })
-#define readw(addr) \
-    ({ unsigned short __v = (*(volatile unsigned short *) (addr)); __v; })
-#define readl(addr) \
-    ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; })
-
-#define writeb(b,addr) (void)((*(volatile unsigned char *) (addr)) = (b))
-#define writew(b,addr) (void)((*(volatile unsigned short *) (addr)) = (b))
-#define writel(b,addr) (void)((*(volatile unsigned int *) (addr)) = (b))
-
-#define memset_io(a,b,c)	memset((void *)(a),(b),(c))
-#define memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
-#define memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
 
-#define inb_p(addr) readb(addr)
-#define inb(addr) readb(addr)
+static inline unsigned long isa_itb(long addr)
+{
+  switch(ISA_TYPE)
+    {
+#ifdef CONFIG_Q40
+    case Q40_ISA: return Q40_ISA_IO_B(addr);
+#endif
+#ifdef CONFIG_GG2
+    case GG2_ISA: return GG2_ISA_IO_B(addr);
+#endif
+#ifdef CONFIG_AMIGA_PCMCIA
+    case AG_ISA: return AG_ISA_IO_B(addr);
+#endif
+    default: return 0; /* avoid warnings, just in case */
+    }
+}
+static inline unsigned long isa_itw(long addr)
+{
+  switch(ISA_TYPE)
+    {
+#ifdef CONFIG_Q40
+    case Q40_ISA: return Q40_ISA_IO_W(addr);
+#endif
+#ifdef CONFIG_GG2
+    case GG2_ISA: return GG2_ISA_IO_W(addr);
+#endif
+#ifdef CONFIG_AMIGA_PCMCIA
+    case AG_ISA: return AG_ISA_IO_W(addr);
+#endif
+    default: return 0; /* avoid warnings, just in case */
+    }
+}
+static inline unsigned long isa_mtb(long addr)
+{
+  switch(ISA_TYPE)
+    {
+#ifdef CONFIG_Q40
+    case Q40_ISA: return Q40_ISA_MEM_B(addr);
+#endif
+#ifdef CONFIG_GG2
+    case GG2_ISA: return GG2_ISA_MEM_B(addr);
+#endif
+      /* FIXME: any ISA mem mapping for PCMCIA? */
+    default: return 0; /* avoid warnings, just in case */
+    }
+}
+static inline unsigned long isa_mtw(long addr)
+{
+  switch(ISA_TYPE)
+    {
+#ifdef CONFIG_Q40
+    case Q40_ISA: return Q40_ISA_MEM_W(addr);
+#endif
+#ifdef CONFIG_GG2
+    case GG2_ISA: return GG2_ISA_MEM_W(addr);
+#endif
+    default: return 0; /* avoid warnings, just in case */
+    }
+}
 
-#define outb(x,addr) ((void) writeb(x,addr))
-#define outb_p(x,addr) outb(x,addr)
 
-#ifndef CONFIG_SUN3
-#define IO_SPACE_LIMIT 0xffff
+#define isa_inb(port)      in_8(isa_itb(port))
+#define isa_inw(port)      (ISA_SEX ? in_be16(isa_itw(port)) : in_le16(isa_itw(port)))
+#define isa_outb(val,port) out_8(isa_itb(port),(val))
+#define isa_outw(val,port) (ISA_SEX ? out_be16(isa_itw(port),(val)) : out_le16(isa_itw(port),(val)))
+
+#define isa_readb(p)       in_8(isa_mtb(p))
+#define isa_readw(p)       in_le16(isa_mtw(p))
+#define isa_writeb(val,p)  out_8(isa_mtb(p),(val))
+#define isa_writew(val,p)  out_le16(isa_mtw(p),(val))
+
+#define isa_inb_p(p)      ({unsigned char v=isa_inb(p);isa_outb(0,0x80);v;})
+#define isa_outb_p(v,p)   ({isa_outb((v),(p));isa_outb(0,0x80);})
+
+#define isa_insb(port, buf, nr) raw_insb(isa_itb(port), (buf), (nr))
+#define isa_outsb(port, buf, nr) raw_outsb(isa_itb(port), (buf), (nr))
+
+#define isa_insw(port, buf, nr)     \
+       (ISA_SEX ? raw_insw(isa_itw(port), (buf), (nr)) :    \
+                  raw_insw_swapw(isa_itw(port), (buf), (nr)))
+
+#define isa_outsw(port, buf, nr)    \
+       (ISA_SEX ? raw_outsw(isa_itw(port), (buf), (nr)) :  \
+                  raw_outsw_swapw(isa_itw(port), (buf), (nr)))
+#endif  /* MACH_HAS_ISA */
+
+
+#if defined(CONFIG_ISA) && !defined(CONFIG_PCI) 
+#define inb     isa_inb
+#define inb_p   isa_inb_p
+#define outb    isa_outb
+#define outb_p  isa_outb_p
+#define inw     isa_inw
+#define outw    isa_outw
+#define inl     isa_inw
+#define outl    isa_outw
+#define insb    isa_insb
+#define insw    isa_insw
+#define outsb   isa_outsb
+#define outsw   isa_outsw
+#endif /* MACH_HAS_ISA */
+
+
+#if defined(CONFIG_PCI)
+
+#define inl(port)       in_le32(port)
+#define outl(val,port)  out_le32((port),(val))
+
+#define readb(addr)  in_8(addr)
+#define readw(addr)  in_le16(addr)
+#define readl(addr)  in_le32(addr)
+
+#define writeb(val,addr)  out_8((addr),(val))
+#define writew(val,addr)  out_le16((addr),(val))
+#define writel(val,addr)  out_le32((addr),(val))
+
+
+#ifndef CONFIG_ISA
+#define inb(port)      in_8(port)
+#define outb(val,port) out_8((port),(val))
+#define inw(port)      in_le16(port)
+#define outw(val,port) out_le16((port),(val))
+
 #else
-#define IO_SPACE_LIMIT 0x0fffffff
+/*
+ * kernel with both ISA and PCI compiled in, those have 
+ * conflicting defs for in/out. Simply consider port < 1024 
+ * ISA and everything else PCI
+ */
+#define inb(port) ((port)<1024 ? isa_inb(port) : in_8(port))
+#define inb_p(port) ((port)<1024 ? isa_inb_p(port) : in_8(port))
+#define inw(port) ((port)<1024 ? isa_inw(port) : in_le16(port))
+
+#define outb(val,port) ((port)<1024 ? isa_outb((val),(port)) : out_8((port),(val)))
+#define outb_p(val,port) ((port)<1024 ? isa_outb_p((val),(port)) : out_8((port),(val)))
+#define outw(val,port) ((port)<1024 ? isa_outw((val),(port)) : out_le16((port),(val)))
 #endif
+#endif /* CONFIG_PCI */
+
 
 /* Values for nocacheflag and cmode */
 #define IOMAP_FULL_CACHING		0
@@ -59,7 +262,10 @@
 #define IOMAP_NOCACHE_NONSER		2
 #define IOMAP_WRITETHROUGH		3
 
-extern void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag);
+extern void iounmap(void *addr);
+
+extern void *__ioremap(unsigned long physaddr, unsigned long size,
+		       int cacheflag);
 extern void __iounmap(void *addr, unsigned long size);
 
 extern inline void *ioremap(unsigned long physaddr, unsigned long size)
@@ -70,11 +276,13 @@
 {
 	return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
 }
-extern inline void *ioremap_writethrough(unsigned long physaddr, unsigned long size)
+extern inline void *ioremap_writethrough(unsigned long physaddr,
+					 unsigned long size)
 {
 	return __ioremap(physaddr, size, IOMAP_WRITETHROUGH);
 }
-extern inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size)
+extern inline void *ioremap_fullcache(unsigned long physaddr,
+				      unsigned long size)
 {
 	return __ioremap(physaddr, size, IOMAP_FULL_CACHING);
 }
@@ -87,6 +295,11 @@
 #define dma_cache_wback(_start,_size)		do { } while (0)
 #define dma_cache_wback_inv(_start,_size)	do { } while (0)
 
-#endif /* __KERNEL__ */
+#ifndef CONFIG_SUN3
+#define IO_SPACE_LIMIT 0xffff
+#else
+#define IO_SPACE_LIMIT 0x0fffffff
+#endif
 
-#endif /* _M68K_IO_H */
+#endif /* __KERNEL__ */
+#endif /* _IO_H */
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/linux_logo.h linux/include/asm-m68k/linux_logo.h
--- v2.4.5/linux/include/asm-m68k/linux_logo.h	Mon Oct  5 13:54:39 1998
+++ linux/include/asm-m68k/linux_logo.h	Tue Jun 12 10:39:50 2001
@@ -26,883 +26,899 @@
 
 #ifdef CONFIG_MAC
 
-#define LINUX_LOGO_COLORS 95
+#define __HAVE_ARCH_LINUX_LOGO
+
+#define LINUX_LOGO_COLORS	185
 
 #ifdef INCLUDE_LINUX_LOGO_DATA
 
 unsigned char linux_logo_red[] __initdata = {
-  0x02, 0x82, 0xEA, 0x42, 0xC2, 0x82, 0xE2, 0xA2,
-  0xDA, 0xC2, 0x22, 0x62, 0xB2, 0x92, 0xD2, 0x8A,
-  0xB2, 0xFA, 0xDA, 0x32, 0x72, 0x12, 0xF2, 0x52,
-  0xF2, 0xEA, 0xFA, 0xAA, 0xCA, 0x9A, 0xE2, 0xAA,
-  0x8A, 0xEA, 0xD2, 0x92, 0xEA, 0xDA, 0x2A, 0x6A,
-  0xDA, 0xBA, 0xD2, 0x52, 0x7A, 0x2A, 0x5A, 0x0A,
-  0x6A, 0xEA, 0xE2, 0xC6, 0x96, 0xF2, 0x3A, 0x1A,
-  0xB2, 0xBA, 0xF2, 0xDA, 0x0A, 0x86, 0x4A, 0xCA,
-  0x8A, 0xE2, 0xA6, 0xDA, 0x66, 0xBA, 0x92, 0xDA,
-  0xA2, 0xB6, 0x76, 0x12, 0xF2, 0xFA, 0xEA, 0xAE,
-  0xCE, 0x9E, 0xB2, 0x8E, 0xF2, 0xD2, 0xA2, 0x6E,
-  0xBE, 0xD6, 0x7E, 0x5E, 0xC2, 0xFA, 0x3A
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0xfa,
+    0xf2, 0xf6, 0xe7, 0x74, 0x65, 0x7b, 0xea, 0xdd,
+    0xd6, 0x5e, 0xbe, 0x5a, 0xe2, 0xda, 0xee, 0xb6,
+    0xce, 0x65, 0x6e, 0x6a, 0xd2, 0xc6, 0x90, 0xca,
+    0x9e, 0xbb, 0xb2, 0x8a, 0xa2, 0x9a, 0x86, 0xc3,
+    0xfd, 0xae, 0x3e, 0xaa, 0x95, 0x80, 0x76, 0x79,
+    0x62, 0x36, 0x9a, 0xe2, 0xec, 0xe1, 0xb8, 0xd7,
+    0xaf, 0x25, 0xbc, 0xc0, 0xef, 0xea, 0xe8, 0xe8,
+    0xf5, 0xf1, 0xda, 0xd3, 0x79, 0xdb, 0xf4, 0xf6,
+    0xf6, 0xf6, 0xe2, 0x3d, 0xb4, 0xce, 0xe6, 0xee,
+    0xf6, 0xa6, 0x68, 0xd8, 0xec, 0xf5, 0xc6, 0xc8,
+    0x9c, 0x89, 0xd2, 0xee, 0xcb, 0xb9, 0xd2, 0x66,
+    0x5e, 0x8b, 0xbe, 0xa8, 0xd5, 0xca, 0xb6, 0xae,
+    0x9c, 0xc5, 0x8d, 0xbe, 0xbe, 0xb2, 0x9a, 0xa8,
+    0x16, 0x12, 0x4a, 0x8e, 0xf2, 0xf6, 0xe4, 0xf1,
+    0x26, 0x9a, 0xea, 0xf6, 0xe0, 0xd2, 0x9a, 0x2e,
+    0x70, 0xd6, 0x46, 0x7c, 0xb4, 0x62, 0xd6, 0xa3,
+    0x74, 0xa7, 0xa2, 0xca, 0xe0, 0xae, 0xbe, 0xce,
+    0xa3, 0x8e, 0x6d, 0x8e, 0x32, 0xaf, 0x50, 0x9e,
+    0x5b, 0x8a, 0x98, 0x82, 0x7a, 0x82, 0x56, 0x7c,
+    0x8a, 0x56, 0x5e, 0x86, 0x6a, 0x52, 0x59, 0x64,
+    0x5e,
 };
 
 unsigned char linux_logo_green[] __initdata = {
-  0x02, 0x82, 0xC2, 0x42, 0x8A, 0x56, 0xE2, 0xA2,
-  0xAA, 0xC2, 0x22, 0x62, 0x86, 0x92, 0x9E, 0x6E,
-  0xB2, 0xB2, 0xD2, 0x32, 0x72, 0x12, 0xD2, 0x52,
-  0xF2, 0xB2, 0xC2, 0xAA, 0xCA, 0x9A, 0xA2, 0x7E,
-  0x8A, 0xCA, 0x92, 0x66, 0xEA, 0xB2, 0x2A, 0x6A,
-  0xA2, 0xBA, 0xD2, 0x36, 0x7A, 0x1A, 0x5A, 0x0A,
-  0x4A, 0xE6, 0xAE, 0xC6, 0x96, 0xBA, 0x3A, 0x1A,
-  0xAA, 0x7A, 0xCA, 0xDA, 0x02, 0x86, 0x4A, 0x8A,
-  0x5E, 0xE2, 0xA6, 0xAE, 0x66, 0x82, 0x92, 0x9A,
-  0x72, 0xB6, 0x76, 0x12, 0xD2, 0xFA, 0xB2, 0xAE,
-  0xCE, 0x9E, 0x7A, 0x8E, 0xCA, 0x92, 0x6A, 0x6E,
-  0xBE, 0xD6, 0x7E, 0x5E, 0xC6, 0xBA, 0x3E
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0xfa,
+    0xf2, 0xf6, 0xe7, 0x74, 0x65, 0x7b, 0xea, 0xdd,
+    0xd6, 0x5e, 0xbe, 0x5a, 0xe2, 0xda, 0xee, 0xb6,
+    0xce, 0x62, 0x6e, 0x6a, 0xd2, 0xc6, 0x90, 0xca,
+    0x9e, 0xbb, 0xb2, 0x8a, 0xa2, 0x9a, 0x86, 0xc3,
+    0xfd, 0xae, 0x3e, 0xaa, 0x95, 0x80, 0x62, 0x5c,
+    0x4e, 0x26, 0x72, 0xaa, 0xba, 0xaf, 0x90, 0xae,
+    0x92, 0x1a, 0xa4, 0x85, 0xb6, 0xbe, 0xc3, 0xc8,
+    0xcf, 0xd0, 0xc2, 0xce, 0x57, 0xa2, 0xd6, 0xda,
+    0xda, 0xd7, 0xb8, 0x2a, 0x7b, 0x91, 0xae, 0xca,
+    0xda, 0xa6, 0x45, 0x9e, 0xb2, 0xd7, 0x9b, 0x90,
+    0x76, 0x5c, 0xa2, 0xbe, 0xa6, 0x85, 0x96, 0x4e,
+    0x46, 0x66, 0x92, 0x7a, 0x9a, 0x96, 0x9d, 0x9a,
+    0x6b, 0x8a, 0x8d, 0x8e, 0xb2, 0xa6, 0x79, 0x7c,
+    0x12, 0x0e, 0x36, 0x86, 0xba, 0xbe, 0xb8, 0xc4,
+    0x1e, 0x8e, 0xae, 0xba, 0xb2, 0xa6, 0x7a, 0x20,
+    0x64, 0xaa, 0x2f, 0x70, 0x85, 0x46, 0xa6, 0x6e,
+    0x51, 0x72, 0x92, 0xa2, 0xa6, 0x87, 0x96, 0xa2,
+    0x85, 0x7a, 0x6a, 0x6e, 0x22, 0x76, 0x36, 0x76,
+    0x3c, 0x6e, 0x63, 0x53, 0x66, 0x62, 0x42, 0x50,
+    0x56, 0x42, 0x56, 0x56, 0x56, 0x3e, 0x51, 0x52,
+    0x56,
 };
 
 unsigned char linux_logo_blue[] __initdata = {
-  0x04, 0x84, 0x04, 0x44, 0x04, 0x04, 0xDC, 0xA4,
-  0x0C, 0xC4, 0x1C, 0x64, 0x04, 0x8C, 0x04, 0x34,
-  0xB4, 0x0C, 0xAC, 0x34, 0x74, 0x04, 0x0C, 0x4C,
-  0xF4, 0x0C, 0x0C, 0xAC, 0xCC, 0x9C, 0x0C, 0x04,
-  0x8C, 0x0C, 0x04, 0x04, 0xEC, 0x2C, 0x2C, 0x6C,
-  0x04, 0xBC, 0xD4, 0x04, 0x7C, 0x04, 0x5C, 0x0C,
-  0x04, 0xEC, 0x04, 0xC4, 0x94, 0x14, 0x3C, 0x1C,
-  0xA4, 0x04, 0x24, 0xDC, 0x04, 0x84, 0x4C, 0x0C,
-  0x04, 0xE4, 0xA4, 0x04, 0x64, 0x04, 0x94, 0x14,
-  0x0C, 0xB4, 0x74, 0x14, 0x24, 0xFC, 0x14, 0xAC,
-  0xCC, 0x9C, 0x0C, 0x8C, 0x14, 0x14, 0x04, 0x6C,
-  0xBC, 0xD4, 0x7C, 0x5C, 0xD4, 0x14, 0x3C
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x01, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x06, 0xfa,
+    0xf2, 0xf6, 0xe7, 0x74, 0x65, 0x7b, 0xea, 0xdd,
+    0xd6, 0x5e, 0xbe, 0x5a, 0xe2, 0xda, 0xee, 0xb6,
+    0xce, 0x59, 0x6e, 0x6a, 0xd2, 0xc6, 0x90, 0xca,
+    0x9e, 0xbb, 0xb2, 0x8a, 0xa2, 0x9a, 0x86, 0xc3,
+    0xfd, 0xae, 0x3e, 0xaa, 0x95, 0x80, 0x2e, 0x08,
+    0x0a, 0x06, 0x0a, 0x0b, 0x0b, 0x0f, 0x0c, 0x0f,
+    0x3d, 0x09, 0x73, 0x09, 0x0d, 0x0a, 0x10, 0x1e,
+    0x2d, 0x13, 0x86, 0xba, 0x19, 0x0a, 0x36, 0x3c,
+    0x26, 0x14, 0x0d, 0x06, 0x07, 0x0a, 0x0b, 0x0f,
+    0x4a, 0xa6, 0x06, 0x0a, 0x0c, 0x2b, 0x0a, 0x0b,
+    0x0a, 0x06, 0x0a, 0x0a, 0x11, 0x0b, 0x0a, 0x0a,
+    0x1e, 0x0f, 0x0d, 0x0a, 0x0b, 0x22, 0x6a, 0x72,
+    0x0b, 0x0b, 0x8d, 0x22, 0x90, 0x92, 0x3c, 0x2c,
+    0x06, 0x06, 0x0e, 0x6a, 0x0e, 0x0e, 0x3e, 0x0e,
+    0x0a, 0x5a, 0x0d, 0x0e, 0x3e, 0x0a, 0x2e, 0x06,
+    0x4e, 0x36, 0x06, 0x58, 0x24, 0x06, 0x3a, 0x08,
+    0x08, 0x07, 0x5e, 0x45, 0x0a, 0x32, 0x2e, 0x2a,
+    0x43, 0x48, 0x5f, 0x2e, 0x06, 0x06, 0x07, 0x24,
+    0x06, 0x32, 0x06, 0x06, 0x46, 0x2e, 0x22, 0x06,
+    0x06, 0x1e, 0x4c, 0x06, 0x3a, 0x22, 0x42, 0x34,
+    0x42,
 };
 
 unsigned char linux_logo[] __initdata = {
-  0x53, 0x3D, 0x40, 0x73, 0x71, 0x3B, 0x3B, 0x71,
-  0x3D, 0x54, 0x73, 0x40, 0x73, 0x3D, 0x27, 0x71,
-  0x40, 0x6A, 0x7A, 0x3D, 0x3B, 0x30, 0x30, 0x62,
-  0x40, 0x6A, 0x21, 0x62, 0x78, 0x29, 0x49, 0x30,
-  0x6F, 0x27, 0x54, 0x3D, 0x62, 0x27, 0x54, 0x66,
-  0x71, 0x6F, 0x6F, 0x6F, 0x78, 0x53, 0x29, 0x29,
-  0x53, 0x70, 0x53, 0x3D, 0x40, 0x73, 0x71, 0x3B,
-  0x3B, 0x71, 0x3D, 0x54, 0x73, 0x40, 0x73, 0x3D,
-  0x27, 0x71, 0x40, 0x6A, 0x7A, 0x3D, 0x3B, 0x30,
-  0x30, 0x62, 0x40, 0x6A, 0x21, 0x62, 0x78, 0x29,
-  0x71, 0x4C, 0x6A, 0x40, 0x71, 0x62, 0x27, 0x71,
-  0x54, 0x66, 0x73, 0x40, 0x73, 0x3D, 0x3D, 0x40,
-  0x6A, 0x77, 0x7A, 0x71, 0x30, 0x69, 0x6F, 0x71,
-  0x54, 0x73, 0x3D, 0x30, 0x49, 0x30, 0x3B, 0x62,
-  0x27, 0x3D, 0x54, 0x3D, 0x71, 0x71, 0x27, 0x62,
-  0x62, 0x3B, 0x62, 0x27, 0x3B, 0x69, 0x69, 0x69,
-  0x69, 0x30, 0x71, 0x4C, 0x6A, 0x40, 0x71, 0x62,
-  0x27, 0x71, 0x54, 0x66, 0x73, 0x40, 0x73, 0x3D,
-  0x3D, 0x40, 0x6A, 0x77, 0x7A, 0x71, 0x30, 0x69,
-  0x6F, 0x71, 0x54, 0x73, 0x3D, 0x30, 0x49, 0x30,
-  0x40, 0x34, 0x34, 0x40, 0x27, 0x6F, 0x62, 0x3D,
-  0x54, 0x66, 0x40, 0x73, 0x66, 0x66, 0x2D, 0x5D,
-  0x7A, 0x5D, 0x3D, 0x6F, 0x69, 0x69, 0x30, 0x27,
-  0x27, 0x27, 0x62, 0x6F, 0x30, 0x3B, 0x62, 0x27,
-  0x3D, 0x54, 0x2D, 0x54, 0x27, 0x71, 0x3D, 0x27,
-  0x62, 0x62, 0x62, 0x62, 0x3B, 0x30, 0x6F, 0x6F,
-  0x6F, 0x71, 0x40, 0x34, 0x34, 0x40, 0x27, 0x6F,
-  0x62, 0x3D, 0x54, 0x66, 0x40, 0x73, 0x66, 0x66,
-  0x2D, 0x5D, 0x7A, 0x5D, 0x3D, 0x6F, 0x69, 0x69,
-  0x30, 0x27, 0x27, 0x27, 0x62, 0x6F, 0x30, 0x6F,
-  0x4C, 0x77, 0x6A, 0x2D, 0x3B, 0x6F, 0x3B, 0x71,
-  0x54, 0x66, 0x2D, 0x73, 0x66, 0x54, 0x73, 0x73,
-  0x73, 0x3D, 0x62, 0x6F, 0x69, 0x30, 0x6F, 0x27,
-  0x3D, 0x3D, 0x27, 0x62, 0x62, 0x62, 0x27, 0x71,
-  0x54, 0x73, 0x73, 0x54, 0x3D, 0x3D, 0x20, 0x20,
-  0x20, 0x20, 0x3B, 0x62, 0x3B, 0x62, 0x71, 0x71,
-  0x3D, 0x2D, 0x4C, 0x77, 0x6A, 0x66, 0x3B, 0x6F,
-  0x3B, 0x71, 0x54, 0x66, 0x2D, 0x73, 0x66, 0x54,
-  0x73, 0x73, 0x73, 0x3D, 0x62, 0x6F, 0x69, 0x30,
-  0x6F, 0x27, 0x3D, 0x3D, 0x27, 0x62, 0x62, 0x27,
-  0x4C, 0x4C, 0x5D, 0x71, 0x30, 0x30, 0x3B, 0x27,
-  0x54, 0x66, 0x73, 0x66, 0x66, 0x54, 0x54, 0x3D,
-  0x27, 0x62, 0x6F, 0x30, 0x30, 0x6F, 0x27, 0x3D,
-  0x54, 0x54, 0x3D, 0x71, 0x3D, 0x71, 0x3D, 0x3D,
-  0x66, 0x73, 0x66, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x71, 0x3D,
-  0x66, 0x40, 0x4C, 0x4C, 0x5D, 0x71, 0x30, 0x30,
-  0x3B, 0x27, 0x54, 0x66, 0x73, 0x66, 0x66, 0x54,
-  0x54, 0x3D, 0x27, 0x62, 0x6F, 0x30, 0x30, 0x6F,
-  0x27, 0x3D, 0x54, 0x54, 0x3D, 0x71, 0x71, 0x71,
-  0x5D, 0x5D, 0x54, 0x62, 0x69, 0x69, 0x3B, 0x3D,
-  0x66, 0x40, 0x73, 0x66, 0x54, 0x54, 0x71, 0x62,
-  0x3B, 0x6F, 0x6F, 0x6F, 0x3B, 0x27, 0x3D, 0x2D,
-  0x66, 0x54, 0x71, 0x71, 0x27, 0x71, 0x71, 0x3D,
-  0x3D, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54,
-  0x73, 0x40, 0x5D, 0x5D, 0x54, 0x62, 0x69, 0x69,
-  0x3B, 0x3D, 0x66, 0x40, 0x73, 0x66, 0x54, 0x54,
-  0x71, 0x62, 0x3B, 0x6F, 0x6F, 0x6F, 0x3B, 0x27,
-  0x3D, 0x66, 0x66, 0x54, 0x71, 0x71, 0x27, 0x71,
-  0x66, 0x73, 0x3D, 0x27, 0x6F, 0x6F, 0x62, 0x54,
-  0x40, 0x21, 0x5D, 0x73, 0x3D, 0x27, 0x62, 0x6F,
-  0x6F, 0x3B, 0x3B, 0x62, 0x27, 0x71, 0x3D, 0x3D,
-  0x3D, 0x71, 0x62, 0x62, 0x62, 0x27, 0x27, 0x71,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x4F, 0x46, 0x2A, 0x20, 0x20,
-  0x20, 0x73, 0x66, 0x73, 0x3D, 0x27, 0x6F, 0x6F,
-  0x62, 0x54, 0x40, 0x21, 0x5D, 0x73, 0x3D, 0x27,
-  0x62, 0x6F, 0x6F, 0x3B, 0x3B, 0x62, 0x27, 0x71,
-  0x3D, 0x3D, 0x3D, 0x71, 0x62, 0x27, 0x62, 0x27,
-  0x3D, 0x40, 0x66, 0x27, 0x3B, 0x3B, 0x71, 0x66,
-  0x7A, 0x21, 0x40, 0x54, 0x27, 0x3B, 0x6F, 0x3B,
-  0x62, 0x62, 0x27, 0x6D, 0x6D, 0x6D, 0x6D, 0x38,
-  0x6D, 0x6D, 0x38, 0x6D, 0x38, 0x6D, 0x38, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x6D, 0x6D, 0x38, 0x6D, 0x6D, 0x38,
-  0x38, 0x6D, 0x38, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D,
-  0x6F, 0x3B, 0x62, 0x62, 0x27, 0x27, 0x27, 0x27,
-  0x71, 0x3D, 0x71, 0x71, 0x71, 0x71, 0x3D, 0x3D,
-  0x27, 0x40, 0x54, 0x62, 0x30, 0x30, 0x27, 0x40,
-  0x7A, 0x5D, 0x54, 0x3D, 0x62, 0x30, 0x30, 0x3B,
-  0x71, 0x3D, 0x71, 0x38, 0x6D, 0x6D, 0x6D, 0x6D,
-  0x38, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x38, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x6D, 0x6D, 0x38, 0x6D, 0x6D,
-  0x6D, 0x6D, 0x38, 0x6D, 0x38, 0x6D, 0x6D, 0x6D,
-  0x30, 0x3B, 0x71, 0x3D, 0x71, 0x27, 0x71, 0x71,
-  0x3D, 0x66, 0x73, 0x40, 0x73, 0x66, 0x2D, 0x66,
-  0x30, 0x66, 0x71, 0x6F, 0x69, 0x6F, 0x54, 0x21,
-  0x7A, 0x66, 0x3D, 0x3B, 0x6F, 0x6F, 0x3B, 0x71,
-  0x54, 0x66, 0x3D, 0x4C, 0x44, 0x51, 0x44, 0x44,
-  0x44, 0x38, 0x44, 0x38, 0x44, 0x38, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x6D, 0x38, 0x6D, 0x6D, 0x6D,
-  0x38, 0x6D, 0x6D, 0x38, 0x6D, 0x38, 0x38, 0x51,
-  0x3B, 0x71, 0x54, 0x66, 0x3D, 0x3D, 0x3D, 0x2D,
-  0x40, 0x40, 0x5D, 0x40, 0x73, 0x66, 0x66, 0x3D,
-  0x69, 0x27, 0x3B, 0x30, 0x69, 0x3B, 0x73, 0x7A,
-  0x21, 0x3D, 0x62, 0x3B, 0x6F, 0x3B, 0x27, 0x66,
-  0x73, 0x73, 0x54, 0x4E, 0x44, 0x26, 0x26, 0x5B,
-  0x26, 0x44, 0x44, 0x44, 0x44, 0x44, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x38, 0x38, 0x38, 0x38, 0x38,
-  0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x6D, 0x26,
-  0x27, 0x66, 0x73, 0x73, 0x66, 0x2D, 0x66, 0x2D,
-  0x66, 0x54, 0x54, 0x71, 0x27, 0x27, 0x27, 0x62,
-  0x69, 0x3B, 0x6F, 0x6F, 0x62, 0x54, 0x40, 0x21,
-  0x73, 0x27, 0x3B, 0x3B, 0x71, 0x54, 0x66, 0x66,
-  0x73, 0x73, 0x2D, 0x37, 0x44, 0x51, 0x38, 0x38,
-  0x44, 0x6D, 0x38, 0x6D, 0x38, 0x38, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x38, 0x6D, 0x38, 0x6D,
-  0x38, 0x6D, 0x6D, 0x6D, 0x38, 0x38, 0x6D, 0x70,
-  0x2D, 0x66, 0x73, 0x66, 0x66, 0x54, 0x54, 0x54,
-  0x27, 0x62, 0x6F, 0x6F, 0x6F, 0x6F, 0x3B, 0x62,
-  0x3B, 0x27, 0x27, 0x27, 0x3D, 0x40, 0x21, 0x40,
-  0x54, 0x62, 0x3B, 0x71, 0x73, 0x5D, 0x40, 0x73,
-  0x66, 0x66, 0x2D, 0x33, 0x6D, 0x26, 0x44, 0x4F,
-  0x5E, 0x5E, 0x37, 0x5E, 0x37, 0x46, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x44, 0x26, 0x26, 0x44,
-  0x70, 0x38, 0x26, 0x38, 0x38, 0x44, 0x6D, 0x53,
-  0x40, 0x73, 0x66, 0x2D, 0x66, 0x73, 0x66, 0x54,
-  0x27, 0x6F, 0x30, 0x69, 0x30, 0x6F, 0x62, 0x62,
-  0x62, 0x71, 0x3D, 0x54, 0x73, 0x5D, 0x5D, 0x66,
-  0x27, 0x62, 0x71, 0x54, 0x5D, 0x5D, 0x66, 0x3D,
-  0x3D, 0x73, 0x40, 0x37, 0x44, 0x44, 0x51, 0x20,
-  0x6F, 0x6F, 0x62, 0x27, 0x27, 0x20, 0x20, 0x20,
-  0x4F, 0x20, 0x2A, 0x2A, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x71, 0x3D, 0x73, 0x5D,
-  0x40, 0x54, 0x27, 0x3B, 0x2D, 0x6D, 0x38, 0x3C,
-  0x66, 0x3D, 0x54, 0x66, 0x40, 0x40, 0x73, 0x54,
-  0x62, 0x6F, 0x30, 0x6F, 0x62, 0x71, 0x71, 0x71,
-  0x62, 0x3D, 0x66, 0x73, 0x40, 0x5D, 0x73, 0x71,
-  0x62, 0x27, 0x54, 0x73, 0x5D, 0x73, 0x27, 0x62,
-  0x71, 0x40, 0x21, 0x37, 0x26, 0x51, 0x44, 0x4E,
-  0x3B, 0x71, 0x2D, 0x73, 0x2D, 0x20, 0x20, 0x20,
-  0x35, 0x73, 0x77, 0x4F, 0x6B, 0x20, 0x20, 0x4F,
-  0x20, 0x73, 0x73, 0x73, 0x58, 0x20, 0x77, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x2D, 0x40, 0x40, 0x5D,
-  0x73, 0x71, 0x62, 0x27, 0x71, 0x38, 0x44, 0x49,
-  0x27, 0x62, 0x3D, 0x40, 0x21, 0x40, 0x54, 0x27,
-  0x3B, 0x6F, 0x3B, 0x71, 0x54, 0x66, 0x66, 0x3D,
-  0x62, 0x54, 0x40, 0x21, 0x7A, 0x40, 0x3D, 0x62,
-  0x62, 0x71, 0x66, 0x40, 0x66, 0x71, 0x62, 0x3B,
-  0x54, 0x5D, 0x73, 0x23, 0x51, 0x26, 0x26, 0x30,
-  0x3B, 0x3D, 0x66, 0x73, 0x66, 0x20, 0x20, 0x4F,
-  0x58, 0x7C, 0x62, 0x34, 0x57, 0x20, 0x20, 0x20,
-  0x73, 0x58, 0x49, 0x7C, 0x79, 0x73, 0x20, 0x4F,
-  0x20, 0x20, 0x20, 0x20, 0x40, 0x21, 0x7A, 0x40,
-  0x3D, 0x27, 0x62, 0x71, 0x49, 0x44, 0x6D, 0x78,
-  0x62, 0x3B, 0x3D, 0x5D, 0x40, 0x3D, 0x3B, 0x69,
-  0x49, 0x49, 0x3B, 0x71, 0x66, 0x73, 0x66, 0x54,
-  0x27, 0x66, 0x5D, 0x7A, 0x21, 0x73, 0x71, 0x62,
-  0x27, 0x54, 0x73, 0x66, 0x3D, 0x27, 0x62, 0x62,
-  0x54, 0x73, 0x71, 0x37, 0x26, 0x5B, 0x44, 0x5B,
-  0x27, 0x54, 0x40, 0x2D, 0x54, 0x20, 0x20, 0x77,
-  0x78, 0x6D, 0x6D, 0x6D, 0x20, 0x20, 0x20, 0x20,
-  0x79, 0x38, 0x38, 0x6D, 0x6D, 0x69, 0x2D, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x7A, 0x7A, 0x40,
-  0x71, 0x62, 0x27, 0x54, 0x79, 0x26, 0x38, 0x49,
-  0x3B, 0x27, 0x54, 0x2D, 0x71, 0x6F, 0x49, 0x53,
-  0x78, 0x30, 0x27, 0x54, 0x40, 0x73, 0x54, 0x3D,
-  0x71, 0x66, 0x5D, 0x7A, 0x21, 0x66, 0x27, 0x3B,
-  0x27, 0x66, 0x73, 0x54, 0x27, 0x27, 0x27, 0x3D,
-  0x3D, 0x71, 0x6F, 0x5E, 0x26, 0x79, 0x26, 0x78,
-  0x5D, 0x4C, 0x4C, 0x21, 0x73, 0x20, 0x20, 0x2D,
-  0x35, 0x5C, 0x46, 0x38, 0x77, 0x20, 0x4F, 0x20,
-  0x51, 0x6D, 0x20, 0x2D, 0x20, 0x6D, 0x6D, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x7A, 0x21, 0x54,
-  0x62, 0x3B, 0x27, 0x2D, 0x29, 0x26, 0x44, 0x70,
-  0x27, 0x3D, 0x3D, 0x71, 0x6F, 0x78, 0x53, 0x29,
-  0x69, 0x3D, 0x21, 0x4C, 0x4C, 0x5D, 0x66, 0x54,
-  0x54, 0x73, 0x21, 0x6A, 0x21, 0x3D, 0x3B, 0x3B,
-  0x71, 0x66, 0x66, 0x3D, 0x27, 0x27, 0x71, 0x3D,
-  0x27, 0x6F, 0x49, 0x7E, 0x61, 0x5B, 0x44, 0x26,
-  0x34, 0x34, 0x6A, 0x21, 0x73, 0x66, 0x20, 0x32,
-  0x20, 0x20, 0x2D, 0x6D, 0x77, 0x2A, 0x37, 0x20,
-  0x6D, 0x20, 0x20, 0x20, 0x7E, 0x38, 0x38, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x4C, 0x21, 0x3D,
-  0x3B, 0x3B, 0x71, 0x73, 0x69, 0x44, 0x38, 0x71,
-  0x27, 0x3D, 0x71, 0x3B, 0x49, 0x29, 0x29, 0x6F,
-  0x54, 0x7A, 0x34, 0x77, 0x6A, 0x21, 0x66, 0x66,
-  0x4C, 0x7A, 0x21, 0x4C, 0x21, 0x71, 0x3B, 0x3B,
-  0x54, 0x73, 0x3D, 0x62, 0x3B, 0x62, 0x62, 0x62,
-  0x62, 0x69, 0x29, 0x2B, 0x79, 0x79, 0x26, 0x38,
-  0x47, 0x6A, 0x5D, 0x54, 0x27, 0x3D, 0x20, 0x29,
-  0x57, 0x20, 0x2D, 0x61, 0x37, 0x5C, 0x20, 0x20,
-  0x29, 0x20, 0x20, 0x20, 0x20, 0x29, 0x6D, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x6A, 0x21, 0x3D,
-  0x3B, 0x3B, 0x54, 0x66, 0x78, 0x26, 0x26, 0x30,
-  0x62, 0x62, 0x3B, 0x69, 0x78, 0x78, 0x6F, 0x66,
-  0x6A, 0x64, 0x47, 0x4C, 0x5D, 0x54, 0x71, 0x71,
-  0x4C, 0x5D, 0x5D, 0x21, 0x5D, 0x71, 0x3B, 0x62,
-  0x54, 0x66, 0x27, 0x3B, 0x6F, 0x6F, 0x3B, 0x3B,
-  0x6F, 0x49, 0x78, 0x23, 0x4A, 0x79, 0x4A, 0x6D,
-  0x34, 0x21, 0x66, 0x3D, 0x62, 0x27, 0x20, 0x20,
-  0x38, 0x20, 0x20, 0x52, 0x3A, 0x52, 0x63, 0x36,
-  0x48, 0x4D, 0x20, 0x20, 0x20, 0x6D, 0x38, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x5D, 0x3D,
-  0x3B, 0x62, 0x2D, 0x66, 0x79, 0x26, 0x51, 0x54,
-  0x3B, 0x62, 0x6F, 0x49, 0x78, 0x30, 0x66, 0x34,
-  0x2B, 0x2B, 0x34, 0x21, 0x66, 0x71, 0x62, 0x62,
-  0x3D, 0x3D, 0x54, 0x5D, 0x40, 0x71, 0x3B, 0x3B,
-  0x54, 0x54, 0x3B, 0x69, 0x30, 0x6F, 0x3B, 0x27,
-  0x6F, 0x78, 0x78, 0x46, 0x26, 0x5B, 0x4A, 0x51,
-  0x5D, 0x54, 0x71, 0x62, 0x3B, 0x3B, 0x20, 0x20,
-  0x6D, 0x20, 0x72, 0x55, 0x3A, 0x74, 0x41, 0x39,
-  0x45, 0x5A, 0x24, 0x2F, 0x6D, 0x38, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x40, 0x27,
-  0x3B, 0x62, 0x3D, 0x54, 0x30, 0x5B, 0x26, 0x27,
-  0x3B, 0x62, 0x6F, 0x78, 0x78, 0x3B, 0x21, 0x64,
-  0x7B, 0x77, 0x5D, 0x54, 0x71, 0x62, 0x62, 0x3B,
-  0x53, 0x62, 0x71, 0x73, 0x73, 0x27, 0x6F, 0x3B,
-  0x3D, 0x3D, 0x3B, 0x49, 0x30, 0x62, 0x27, 0x27,
-  0x6F, 0x78, 0x49, 0x46, 0x79, 0x53, 0x4A, 0x38,
-  0x2D, 0x71, 0x62, 0x6F, 0x6F, 0x6F, 0x20, 0x20,
-  0x20, 0x24, 0x52, 0x3A, 0x22, 0x41, 0x5A, 0x45,
-  0x45, 0x63, 0x41, 0x22, 0x36, 0x28, 0x4D, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x73, 0x27,
-  0x6F, 0x3B, 0x3D, 0x3D, 0x49, 0x51, 0x61, 0x69,
-  0x27, 0x27, 0x30, 0x78, 0x69, 0x71, 0x4C, 0x64,
-  0x34, 0x5D, 0x66, 0x71, 0x62, 0x6F, 0x6F, 0x6F,
-  0x79, 0x27, 0x66, 0x73, 0x66, 0x62, 0x6F, 0x6F,
-  0x3D, 0x3D, 0x3B, 0x30, 0x30, 0x62, 0x3D, 0x71,
-  0x6F, 0x69, 0x6F, 0x23, 0x5B, 0x4A, 0x4A, 0x38,
-  0x66, 0x3D, 0x3B, 0x6F, 0x6F, 0x3B, 0x20, 0x4D,
-  0x43, 0x48, 0x39, 0x55, 0x22, 0x22, 0x41, 0x45,
-  0x45, 0x45, 0x45, 0x41, 0x22, 0x45, 0x5A, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x2D, 0x62,
-  0x30, 0x3B, 0x3D, 0x3D, 0x27, 0x26, 0x61, 0x27,
-  0x3D, 0x27, 0x6F, 0x69, 0x6F, 0x54, 0x4C, 0x34,
-  0x7A, 0x40, 0x66, 0x54, 0x62, 0x30, 0x6F, 0x3B,
-  0x53, 0x7A, 0x7A, 0x73, 0x54, 0x62, 0x30, 0x3B,
-  0x3D, 0x3D, 0x62, 0x30, 0x30, 0x3B, 0x71, 0x62,
-  0x30, 0x30, 0x27, 0x7E, 0x70, 0x70, 0x3C, 0x6D,
-  0x21, 0x66, 0x3B, 0x69, 0x3B, 0x71, 0x20, 0x72,
-  0x24, 0x67, 0x22, 0x22, 0x36, 0x36, 0x45, 0x45,
-  0x45, 0x22, 0x41, 0x41, 0x3F, 0x42, 0x52, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x54, 0x62,
-  0x30, 0x3B, 0x3D, 0x54, 0x62, 0x26, 0x79, 0x3B,
-  0x71, 0x27, 0x30, 0x30, 0x27, 0x5D, 0x4C, 0x6A,
-  0x7A, 0x7A, 0x5D, 0x54, 0x3B, 0x30, 0x6F, 0x71,
-  0x27, 0x64, 0x77, 0x40, 0x71, 0x62, 0x3B, 0x62,
-  0x3D, 0x54, 0x27, 0x3B, 0x6F, 0x3B, 0x27, 0x27,
-  0x62, 0x3B, 0x3D, 0x23, 0x26, 0x5B, 0x3C, 0x38,
-  0x5D, 0x71, 0x69, 0x69, 0x62, 0x54, 0x20, 0x50,
-  0x5F, 0x48, 0x3A, 0x55, 0x41, 0x63, 0x70, 0x22,
-  0x22, 0x45, 0x3F, 0x42, 0x48, 0x48, 0x45, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x71, 0x62,
-  0x3B, 0x62, 0x3D, 0x54, 0x30, 0x26, 0x61, 0x71,
-  0x27, 0x27, 0x62, 0x62, 0x54, 0x5D, 0x7A, 0x4C,
-  0x4C, 0x4C, 0x5D, 0x71, 0x30, 0x69, 0x62, 0x54,
-  0x7A, 0x64, 0x34, 0x73, 0x71, 0x27, 0x62, 0x62,
-  0x71, 0x54, 0x71, 0x3B, 0x6F, 0x3B, 0x71, 0x3D,
-  0x3D, 0x71, 0x2D, 0x7E, 0x79, 0x53, 0x3C, 0x38,
-  0x3D, 0x6F, 0x78, 0x49, 0x71, 0x73, 0x20, 0x20,
-  0x25, 0x3F, 0x3A, 0x41, 0x5A, 0x45, 0x41, 0x45,
-  0x3F, 0x50, 0x24, 0x28, 0x28, 0x3F, 0x4D, 0x20,
-  0x20, 0x77, 0x77, 0x20, 0x20, 0x20, 0x71, 0x27,
-  0x62, 0x62, 0x71, 0x54, 0x78, 0x79, 0x38, 0x71,
-  0x71, 0x3D, 0x71, 0x71, 0x66, 0x5D, 0x5D, 0x21,
-  0x21, 0x21, 0x54, 0x30, 0x78, 0x69, 0x27, 0x66,
-  0x7A, 0x4C, 0x40, 0x3D, 0x27, 0x62, 0x62, 0x3B,
-  0x62, 0x71, 0x62, 0x30, 0x69, 0x6F, 0x71, 0x54,
-  0x3D, 0x3D, 0x54, 0x23, 0x4A, 0x3C, 0x3C, 0x38,
-  0x6F, 0x29, 0x53, 0x30, 0x54, 0x66, 0x20, 0x57,
-  0x7C, 0x25, 0x4B, 0x3F, 0x43, 0x4B, 0x4B, 0x2C,
-  0x2E, 0x2E, 0x2E, 0x24, 0x58, 0x58, 0x78, 0x20,
-  0x20, 0x20, 0x34, 0x77, 0x20, 0x20, 0x20, 0x62,
-  0x62, 0x3B, 0x62, 0x71, 0x29, 0x79, 0x61, 0x27,
-  0x27, 0x54, 0x54, 0x71, 0x54, 0x54, 0x66, 0x54,
-  0x66, 0x71, 0x6F, 0x78, 0x53, 0x69, 0x54, 0x73,
-  0x73, 0x73, 0x3D, 0x27, 0x27, 0x27, 0x62, 0x3B,
-  0x62, 0x71, 0x71, 0x3B, 0x6F, 0x3B, 0x27, 0x54,
-  0x66, 0x3D, 0x3D, 0x37, 0x53, 0x78, 0x49, 0x38,
-  0x78, 0x29, 0x78, 0x3B, 0x66, 0x73, 0x20, 0x20,
-  0x7C, 0x69, 0x68, 0x68, 0x52, 0x2E, 0x42, 0x67,
-  0x5F, 0x45, 0x2C, 0x69, 0x78, 0x32, 0x78, 0x78,
-  0x20, 0x20, 0x34, 0x77, 0x35, 0x20, 0x20, 0x27,
-  0x62, 0x3B, 0x62, 0x71, 0x30, 0x26, 0x61, 0x73,
-  0x27, 0x3D, 0x66, 0x3D, 0x3D, 0x27, 0x27, 0x62,
-  0x62, 0x6F, 0x78, 0x53, 0x78, 0x62, 0x54, 0x66,
-  0x27, 0x71, 0x3D, 0x71, 0x62, 0x62, 0x27, 0x3B,
-  0x62, 0x71, 0x71, 0x27, 0x27, 0x27, 0x27, 0x3D,
-  0x54, 0x3D, 0x27, 0x7E, 0x29, 0x29, 0x29, 0x6D,
-  0x49, 0x49, 0x6F, 0x54, 0x73, 0x54, 0x20, 0x20,
-  0x29, 0x7C, 0x69, 0x43, 0x76, 0x72, 0x2C, 0x76,
-  0x68, 0x62, 0x78, 0x29, 0x6D, 0x38, 0x6D, 0x32,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62,
-  0x27, 0x3B, 0x62, 0x71, 0x78, 0x61, 0x6D, 0x3C,
-  0x27, 0x3D, 0x54, 0x3D, 0x27, 0x62, 0x3B, 0x6F,
-  0x6F, 0x69, 0x49, 0x49, 0x6F, 0x3D, 0x73, 0x66,
-  0x3D, 0x3D, 0x3D, 0x3D, 0x71, 0x27, 0x71, 0x62,
-  0x62, 0x71, 0x3D, 0x71, 0x71, 0x71, 0x27, 0x71,
-  0x54, 0x3D, 0x27, 0x46, 0x49, 0x78, 0x49, 0x6D,
-  0x6F, 0x27, 0x54, 0x73, 0x40, 0x20, 0x20, 0x20,
-  0x44, 0x32, 0x29, 0x49, 0x77, 0x2F, 0x73, 0x62,
-  0x29, 0x32, 0x29, 0x51, 0x6D, 0x38, 0x6D, 0x38,
-  0x56, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x71, 0x62, 0x62, 0x71, 0x6F, 0x70, 0x38, 0x71,
-  0x27, 0x71, 0x54, 0x3D, 0x62, 0x3B, 0x3B, 0x6F,
-  0x6F, 0x6F, 0x3B, 0x27, 0x54, 0x40, 0x73, 0x66,
-  0x40, 0x40, 0x66, 0x3D, 0x71, 0x3D, 0x71, 0x71,
-  0x27, 0x27, 0x3D, 0x54, 0x3D, 0x3D, 0x71, 0x54,
-  0x73, 0x73, 0x3D, 0x46, 0x78, 0x49, 0x78, 0x44,
-  0x66, 0x73, 0x5D, 0x5D, 0x35, 0x20, 0x20, 0x78,
-  0x6D, 0x51, 0x78, 0x49, 0x58, 0x29, 0x29, 0x49,
-  0x29, 0x79, 0x38, 0x38, 0x6D, 0x6D, 0x38, 0x6D,
-  0x6D, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x6B, 0x71, 0x27, 0x27, 0x29, 0x3C, 0x44, 0x40,
-  0x3D, 0x54, 0x73, 0x73, 0x54, 0x71, 0x71, 0x3D,
-  0x3D, 0x3D, 0x66, 0x40, 0x5D, 0x5D, 0x5D, 0x40,
-  0x21, 0x5D, 0x73, 0x66, 0x3D, 0x3D, 0x71, 0x71,
-  0x27, 0x27, 0x3D, 0x54, 0x54, 0x66, 0x54, 0x73,
-  0x5D, 0x21, 0x40, 0x33, 0x69, 0x49, 0x30, 0x38,
-  0x7A, 0x7A, 0x7A, 0x21, 0x6B, 0x20, 0x20, 0x6D,
-  0x38, 0x6D, 0x38, 0x7C, 0x49, 0x29, 0x69, 0x78,
-  0x38, 0x38, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x38,
-  0x6D, 0x37, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x71, 0x27, 0x71, 0x78, 0x3C, 0x26, 0x30,
-  0x66, 0x66, 0x5D, 0x21, 0x5D, 0x73, 0x73, 0x40,
-  0x5D, 0x21, 0x7A, 0x4C, 0x21, 0x5D, 0x21, 0x21,
-  0x5D, 0x54, 0x54, 0x54, 0x3D, 0x71, 0x3D, 0x71,
-  0x27, 0x27, 0x71, 0x54, 0x66, 0x54, 0x66, 0x66,
-  0x5D, 0x21, 0x5D, 0x7E, 0x29, 0x69, 0x49, 0x6D,
-  0x4C, 0x7A, 0x5D, 0x20, 0x20, 0x20, 0x51, 0x38,
-  0x6D, 0x6D, 0x6D, 0x44, 0x69, 0x78, 0x5B, 0x6D,
-  0x6D, 0x6D, 0x6D, 0x6D, 0x38, 0x6D, 0x6D, 0x6D,
-  0x38, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x62, 0x27, 0x3C, 0x69, 0x38, 0x71,
-  0x54, 0x73, 0x5D, 0x21, 0x40, 0x73, 0x66, 0x73,
-  0x21, 0x4C, 0x4C, 0x7A, 0x5D, 0x5D, 0x5D, 0x4C,
-  0x66, 0x62, 0x62, 0x27, 0x71, 0x71, 0x71, 0x27,
-  0x27, 0x27, 0x71, 0x3D, 0x54, 0x54, 0x54, 0x54,
-  0x73, 0x73, 0x3D, 0x57, 0x29, 0x69, 0x30, 0x38,
-  0x73, 0x73, 0x20, 0x20, 0x20, 0x2D, 0x6D, 0x6D,
-  0x38, 0x6D, 0x6D, 0x6D, 0x38, 0x38, 0x6D, 0x6D,
-  0x6D, 0x38, 0x6D, 0x6D, 0x38, 0x6D, 0x6D, 0x6D,
-  0x6D, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x27, 0x5B, 0x53, 0x6D, 0x73,
-  0x54, 0x54, 0x73, 0x73, 0x3D, 0x27, 0x27, 0x71,
-  0x66, 0x40, 0x73, 0x40, 0x66, 0x73, 0x40, 0x21,
-  0x62, 0x30, 0x6F, 0x62, 0x27, 0x71, 0x3D, 0x71,
-  0x27, 0x71, 0x71, 0x71, 0x3D, 0x3D, 0x3D, 0x3D,
-  0x3D, 0x27, 0x58, 0x46, 0x69, 0x30, 0x6F, 0x6D,
-  0x3D, 0x71, 0x20, 0x20, 0x20, 0x44, 0x6D, 0x6D,
-  0x6D, 0x6D, 0x6D, 0x38, 0x6D, 0x6D, 0x38, 0x6D,
-  0x38, 0x6D, 0x38, 0x6D, 0x6D, 0x6D, 0x38, 0x6D,
-  0x6D, 0x6D, 0x2F, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x70, 0x53, 0x38, 0x27,
-  0x3D, 0x3D, 0x3D, 0x71, 0x3B, 0x30, 0x62, 0x3D,
-  0x66, 0x54, 0x3D, 0x71, 0x3D, 0x3D, 0x66, 0x66,
-  0x3B, 0x69, 0x69, 0x6F, 0x62, 0x27, 0x3D, 0x71,
-  0x27, 0x27, 0x27, 0x27, 0x71, 0x3D, 0x3D, 0x3D,
-  0x3D, 0x27, 0x3B, 0x46, 0x62, 0x3B, 0x49, 0x38,
-  0x3D, 0x20, 0x20, 0x20, 0x34, 0x44, 0x6D, 0x6D,
-  0x38, 0x6D, 0x6D, 0x38, 0x6D, 0x6D, 0x38, 0x6D,
-  0x6D, 0x6D, 0x6D, 0x38, 0x6D, 0x6D, 0x38, 0x6D,
-  0x38, 0x6D, 0x26, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x21, 0x49, 0x79, 0x51, 0x5D,
-  0x3D, 0x3D, 0x71, 0x27, 0x62, 0x62, 0x3D, 0x73,
-  0x40, 0x66, 0x3D, 0x3D, 0x54, 0x3D, 0x3D, 0x71,
-  0x78, 0x49, 0x69, 0x30, 0x3B, 0x62, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x71, 0x71, 0x71, 0x3D, 0x3D,
-  0x3D, 0x27, 0x3D, 0x33, 0x49, 0x69, 0x62, 0x44,
-  0x20, 0x20, 0x20, 0x20, 0x2D, 0x32, 0x6D, 0x38,
-  0x6D, 0x6D, 0x6D, 0x6D, 0x38, 0x38, 0x6D, 0x6D,
-  0x6D, 0x6D, 0x38, 0x6D, 0x38, 0x6D, 0x38, 0x51,
-  0x26, 0x61, 0x44, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x6A, 0x70, 0x6F, 0x6D, 0x21,
-  0x71, 0x3D, 0x3D, 0x71, 0x3D, 0x66, 0x40, 0x5D,
-  0x40, 0x73, 0x66, 0x73, 0x66, 0x54, 0x3D, 0x71,
-  0x70, 0x78, 0x49, 0x30, 0x6F, 0x6F, 0x62, 0x62,
-  0x62, 0x27, 0x71, 0x3D, 0x54, 0x54, 0x54, 0x3D,
-  0x3D, 0x71, 0x3D, 0x2A, 0x30, 0x2D, 0x3B, 0x26,
-  0x38, 0x20, 0x20, 0x20, 0x2D, 0x62, 0x32, 0x26,
-  0x38, 0x6D, 0x6D, 0x38, 0x5B, 0x38, 0x6D, 0x38,
-  0x6D, 0x6D, 0x6D, 0x26, 0x32, 0x29, 0x29, 0x29,
-  0x53, 0x29, 0x61, 0x6D, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x44, 0x3D, 0x3C, 0x62, 0x79, 0x7A,
-  0x54, 0x54, 0x71, 0x27, 0x3D, 0x66, 0x73, 0x40,
-  0x73, 0x66, 0x66, 0x73, 0x2D, 0x54, 0x71, 0x71,
-  0x4A, 0x3B, 0x62, 0x3B, 0x3B, 0x3B, 0x3B, 0x27,
-  0x27, 0x27, 0x71, 0x3D, 0x2D, 0x73, 0x73, 0x54,
-  0x3D, 0x71, 0x71, 0x33, 0x30, 0x71, 0x5D, 0x38,
-  0x6D, 0x6D, 0x38, 0x38, 0x38, 0x6D, 0x6D, 0x6D,
-  0x6D, 0x6D, 0x44, 0x38, 0x6F, 0x7A, 0x64, 0x64,
-  0x23, 0x23, 0x56, 0x23, 0x23, 0x7B, 0x47, 0x64,
-  0x54, 0x29, 0x44, 0x38, 0x38, 0x6D, 0x38, 0x38,
-  0x6D, 0x38, 0x38, 0x6D, 0x53, 0x49, 0x6D, 0x34,
-  0x73, 0x54, 0x3D, 0x71, 0x71, 0x3D, 0x54, 0x3D,
-  0x3D, 0x54, 0x66, 0x66, 0x66, 0x54, 0x54, 0x3D,
-  0x49, 0x3D, 0x54, 0x54, 0x3D, 0x71, 0x27, 0x27,
-  0x71, 0x71, 0x71, 0x3D, 0x54, 0x54, 0x54, 0x3D,
-  0x3D, 0x71, 0x71, 0x33, 0x29, 0x3D, 0x3D, 0x6D,
-  0x38, 0x6D, 0x6D, 0x38, 0x6D, 0x38, 0x38, 0x6D,
-  0x38, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x38, 0x6D,
-  0x38, 0x6D, 0x38, 0x6D, 0x6D, 0x38, 0x6D, 0x6D,
-  0x38, 0x6D, 0x6D, 0x6D, 0x38, 0x38, 0x6D, 0x44,
-  0x6D, 0x38, 0x38, 0x6D, 0x69, 0x78, 0x61, 0x73,
-  0x54, 0x3D, 0x3D, 0x71, 0x71, 0x3D, 0x3D, 0x3D,
-  0x71, 0x3D, 0x3D, 0x3D, 0x3D, 0x54, 0x3D, 0x71,
-  0x3B, 0x66, 0x73, 0x73, 0x2D, 0x2D, 0x54, 0x3D,
-  0x71, 0x71, 0x3D, 0x71, 0x71, 0x71, 0x27, 0x27,
-  0x27, 0x71, 0x71, 0x33, 0x3B, 0x62, 0x27, 0x3D,
-  0x27, 0x3B, 0x3B, 0x27, 0x62, 0x3B, 0x3D, 0x3D,
-  0x30, 0x27, 0x62, 0x62, 0x62, 0x71, 0x30, 0x27,
-  0x3B, 0x6F, 0x30, 0x30, 0x3B, 0x30, 0x3B, 0x62,
-  0x3B, 0x69, 0x49, 0x30, 0x29, 0x29, 0x29, 0x29,
-  0x49, 0x29, 0x30, 0x29, 0x29, 0x29, 0x51, 0x21,
-  0x27, 0x27, 0x71, 0x71, 0x71, 0x3D, 0x3D, 0x71,
-  0x71, 0x71, 0x71, 0x3D, 0x71, 0x71, 0x71, 0x62,
-  0x3B, 0x54, 0x66, 0x66, 0x66, 0x54, 0x3D, 0x54,
-  0x66, 0x54, 0x3D, 0x27, 0x62, 0x62, 0x3B, 0x3B,
-  0x3B, 0x62, 0x27, 0x33, 0x30, 0x6F, 0x71, 0x3B,
-  0x62, 0x3B, 0x62, 0x27, 0x27, 0x30, 0x62, 0x27,
-  0x62, 0x27, 0x3B, 0x49, 0x3B, 0x30, 0x29, 0x3B,
-  0x3B, 0x30, 0x30, 0x69, 0x30, 0x6F, 0x30, 0x49,
-  0x3B, 0x6F, 0x49, 0x29, 0x49, 0x49, 0x3C, 0x29,
-  0x49, 0x49, 0x69, 0x70, 0x70, 0x29, 0x51, 0x27,
-  0x3B, 0x3B, 0x3B, 0x62, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x3D, 0x3D, 0x3D, 0x71, 0x27, 0x27, 0x27,
-  0x69, 0x71, 0x3D, 0x54, 0x71, 0x62, 0x27, 0x71,
-  0x54, 0x2D, 0x3D, 0x27, 0x62, 0x3B, 0x3B, 0x3B,
-  0x3B, 0x62, 0x62, 0x33, 0x27, 0x27, 0x3B, 0x71,
-  0x27, 0x71, 0x27, 0x62, 0x71, 0x6F, 0x27, 0x71,
-  0x3B, 0x62, 0x62, 0x6F, 0x62, 0x6F, 0x6F, 0x6F,
-  0x6F, 0x69, 0x62, 0x49, 0x69, 0x49, 0x6F, 0x62,
-  0x62, 0x49, 0x69, 0x71, 0x6F, 0x6F, 0x6F, 0x69,
-  0x69, 0x69, 0x30, 0x29, 0x30, 0x69, 0x44, 0x7B,
-  0x3B, 0x3B, 0x3B, 0x62, 0x62, 0x62, 0x62, 0x62,
-  0x27, 0x3D, 0x3D, 0x54, 0x71, 0x3D, 0x3D, 0x54,
-  0x69, 0x71, 0x3D, 0x71, 0x62, 0x3B, 0x3B, 0x27,
-  0x54, 0x54, 0x3D, 0x71, 0x71, 0x71, 0x27, 0x62,
-  0x62, 0x62, 0x27, 0x2A, 0x3D, 0x71, 0x3D, 0x71,
-  0x3D, 0x62, 0x27, 0x30, 0x30, 0x62, 0x3B, 0x71,
-  0x3B, 0x30, 0x30, 0x49, 0x29, 0x30, 0x30, 0x30,
-  0x27, 0x49, 0x62, 0x30, 0x6F, 0x30, 0x3B, 0x3B,
-  0x6F, 0x3B, 0x49, 0x30, 0x30, 0x3C, 0x3B, 0x49,
-  0x30, 0x69, 0x6F, 0x78, 0x30, 0x62, 0x44, 0x7B,
-  0x27, 0x62, 0x62, 0x62, 0x71, 0x71, 0x3D, 0x54,
-  0x3D, 0x73, 0x66, 0x73, 0x66, 0x73, 0x73, 0x66,
-  0x62, 0x66, 0x66, 0x3D, 0x27, 0x3B, 0x3B, 0x71,
-  0x3D, 0x3D, 0x3D, 0x54, 0x54, 0x71, 0x3D, 0x3D,
-  0x54, 0x73, 0x5D, 0x33, 0x62, 0x27, 0x54, 0x27,
-  0x71, 0x3B, 0x71, 0x71, 0x62, 0x3B, 0x54, 0x3B,
-  0x71, 0x6F, 0x62, 0x62, 0x62, 0x62, 0x69, 0x71,
-  0x71, 0x6F, 0x3B, 0x71, 0x30, 0x62, 0x71, 0x6F,
-  0x3B, 0x62, 0x6F, 0x62, 0x6F, 0x69, 0x6F, 0x69,
-  0x6F, 0x30, 0x49, 0x3C, 0x69, 0x3B, 0x79, 0x21,
-  0x20, 0x3D, 0x54, 0x73, 0x5D, 0x5D, 0x5D, 0x40,
-  0x40, 0x73, 0x73, 0x73, 0x2D, 0x66, 0x66, 0x3D,
-  0x3D, 0x54, 0x54, 0x3D, 0x71, 0x27, 0x62, 0x27,
-  0x71, 0x71, 0x3D, 0x54, 0x54, 0x3D, 0x3D, 0x54,
-  0x5D, 0x6A, 0x77, 0x46, 0x71, 0x2D, 0x54, 0x27,
-  0x54, 0x3B, 0x3B, 0x3B, 0x6F, 0x3B, 0x71, 0x27,
-  0x3B, 0x27, 0x3B, 0x3B, 0x27, 0x27, 0x3B, 0x3B,
-  0x3B, 0x62, 0x3D, 0x62, 0x3D, 0x27, 0x3B, 0x54,
-  0x3B, 0x2D, 0x49, 0x3B, 0x3B, 0x29, 0x49, 0x3C,
-  0x53, 0x69, 0x53, 0x3C, 0x78, 0x3D, 0x78, 0x5D,
-  0x20, 0x66, 0x5D, 0x6A, 0x47, 0x77, 0x4C, 0x5D,
-  0x66, 0x3D, 0x3D, 0x66, 0x73, 0x66, 0x3D, 0x62,
-  0x62, 0x62, 0x71, 0x3D, 0x71, 0x27, 0x27, 0x27,
-  0x71, 0x71, 0x71, 0x3D, 0x3D, 0x71, 0x71, 0x73,
-  0x7A, 0x77, 0x47, 0x46, 0x27, 0x73, 0x27, 0x54,
-  0x3D, 0x71, 0x62, 0x6F, 0x27, 0x71, 0x27, 0x71,
-  0x71, 0x71, 0x62, 0x62, 0x71, 0x71, 0x71, 0x62,
-  0x62, 0x3B, 0x69, 0x49, 0x62, 0x6F, 0x62, 0x3D,
-  0x6F, 0x6F, 0x62, 0x78, 0x2A, 0x20, 0x6B, 0x20,
-  0x2A, 0x20, 0x20, 0x2A, 0x3B, 0x6F, 0x3C, 0x4C,
-  0x20, 0x20, 0x7A, 0x77, 0x47, 0x6A, 0x5D, 0x54,
-  0x27, 0x6F, 0x3B, 0x54, 0x40, 0x2D, 0x71, 0x6F,
-  0x49, 0x6F, 0x27, 0x3D, 0x71, 0x62, 0x62, 0x3B,
-  0x62, 0x27, 0x71, 0x3D, 0x3D, 0x71, 0x71, 0x66,
-  0x7A, 0x34, 0x6A, 0x46, 0x27, 0x5D, 0x3D, 0x54,
-  0x3D, 0x3D, 0x3D, 0x62, 0x27, 0x71, 0x27, 0x3D,
-  0x3B, 0x3D, 0x30, 0x27, 0x27, 0x3B, 0x27, 0x3D,
-  0x20, 0x20, 0x2A, 0x46, 0x46, 0x2A, 0x35, 0x2A,
-  0x46, 0x46, 0x23, 0x2A, 0x7A, 0x4F, 0x4F, 0x6B,
-  0x6B, 0x4F, 0x4F, 0x62, 0x3B, 0x62, 0x78, 0x20,
-  0x20, 0x20, 0x7A, 0x34, 0x34, 0x40, 0x54, 0x71,
-  0x3B, 0x69, 0x6F, 0x40, 0x7A, 0x66, 0x62, 0x69,
-  0x3C, 0x3B, 0x71, 0x3D, 0x27, 0x3B, 0x6F, 0x27,
-  0x71, 0x3D, 0x3D, 0x66, 0x2D, 0x3D, 0x62, 0x27,
-  0x2D, 0x4C, 0x7A, 0x33, 0x27, 0x3D, 0x54, 0x2D,
-  0x54, 0x62, 0x54, 0x27, 0x54, 0x27, 0x54, 0x71,
-  0x62, 0x71, 0x71, 0x62, 0x62, 0x54, 0x71, 0x62,
-  0x7A, 0x6B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x35, 0x57,
-  0x6B, 0x20, 0x20, 0x30, 0x6F, 0x27, 0x29, 0x20,
-  0x20, 0x20, 0x66, 0x4C, 0x7A, 0x54, 0x62, 0x3B,
-  0x6F, 0x30, 0x71, 0x7A, 0x4C, 0x3D, 0x69, 0x78,
-  0x53, 0x3D, 0x73, 0x2D, 0x71, 0x62, 0x3B, 0x71,
-  0x3D, 0x2D, 0x2D, 0x40, 0x73, 0x3D, 0x27, 0x71,
-  0x40, 0x6A, 0x20, 0x20, 0x71, 0x2D, 0x62, 0x2D,
-  0x3D, 0x3B, 0x71, 0x27, 0x54, 0x27, 0x3D, 0x3D,
-  0x27, 0x2D, 0x27, 0x3D, 0x3B, 0x2D, 0x3D, 0x3B,
-  0x34, 0x2D, 0x77, 0x6A, 0x77, 0x2D, 0x6A, 0x7A,
-  0x5D, 0x6A, 0x5D, 0x54, 0x71, 0x44, 0x6D, 0x6D,
-  0x6D, 0x38, 0x26, 0x30, 0x54, 0x62, 0x20, 0x20,
-  0x20, 0x20, 0x40, 0x6A, 0x4C, 0x54, 0x6F, 0x69,
-  0x30, 0x62, 0x40, 0x6A, 0x21, 0x62, 0x49, 0x29,
-  0x71, 0x4C, 0x34, 0x5D, 0x71, 0x3B, 0x27, 0x71,
-  0x54, 0x54, 0x40, 0x40, 0x73, 0x3D, 0x3D, 0x40,
-  0x6A, 0x20, 0x20, 0x33, 0x2D, 0x73, 0x40, 0x4E,
-  0x77, 0x7A, 0x3D, 0x54, 0x2D, 0x54, 0x71, 0x54,
-  0x62, 0x71, 0x71, 0x62, 0x71, 0x71, 0x71, 0x71,
-  0x2D, 0x3B, 0x27, 0x3B, 0x49, 0x6F, 0x3B, 0x3B,
-  0x27, 0x3B, 0x3B, 0x30, 0x49, 0x53, 0x6F, 0x6F,
-  0x69, 0x3B, 0x6F, 0x53, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x6A, 0x77, 0x21, 0x27, 0x30, 0x30,
-  0x6F, 0x71, 0x66, 0x73, 0x3D, 0x30, 0x49, 0x30,
-  0x5D, 0x34, 0x34, 0x40, 0x27, 0x6F, 0x62, 0x3D,
-  0x54, 0x66, 0x40, 0x73, 0x2D, 0x66, 0x2D, 0x5D,
-  0x7A, 0x20, 0x20, 0x56, 0x20, 0x54, 0x5D, 0x5E,
-  0x33, 0x71, 0x3D, 0x62, 0x27, 0x3B, 0x27, 0x30,
-  0x3B, 0x3D, 0x27, 0x3D, 0x3D, 0x3D, 0x3B, 0x73,
-  0x54, 0x62, 0x62, 0x62, 0x30, 0x6F, 0x71, 0x6F,
-  0x6F, 0x6F, 0x6F, 0x71, 0x62, 0x3B, 0x3B, 0x49,
-  0x3B, 0x3B, 0x3B, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x7A, 0x21, 0x54, 0x3B, 0x69, 0x69,
-  0x30, 0x62, 0x27, 0x71, 0x62, 0x30, 0x30, 0x6F,
-  0x4C, 0x77, 0x6A, 0x66, 0x62, 0x6F, 0x62, 0x71,
-  0x54, 0x66, 0x2D, 0x73, 0x66, 0x54, 0x73, 0x73,
-  0x73, 0x20, 0x20, 0x7E, 0x20, 0x3D, 0x27, 0x6B,
-  0x35, 0x21, 0x54, 0x3D, 0x71, 0x71, 0x54, 0x62,
-  0x62, 0x71, 0x71, 0x69, 0x71, 0x54, 0x54, 0x30,
-  0x27, 0x3B, 0x3B, 0x3B, 0x6F, 0x30, 0x3B, 0x30,
-  0x3B, 0x30, 0x30, 0x27, 0x30, 0x6F, 0x62, 0x69,
-  0x6F, 0x6F, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x73, 0x3D, 0x62, 0x6F, 0x69, 0x69,
-  0x6F, 0x71, 0x3D, 0x71, 0x27, 0x62, 0x62, 0x27,
-  0x4C, 0x4C, 0x5D, 0x71, 0x30, 0x69, 0x3B, 0x71,
-  0x54, 0x66, 0x73, 0x66, 0x66, 0x66, 0x54, 0x3D,
-  0x71, 0x20, 0x20, 0x7E, 0x20, 0x20, 0x21, 0x62,
-  0x69, 0x27, 0x5D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3B,
-  0x3D, 0x3D, 0x27, 0x3B, 0x27, 0x3D, 0x71, 0x6F,
-  0x54, 0x62, 0x6F, 0x30, 0x6F, 0x6F, 0x62, 0x6F,
-  0x62, 0x62, 0x62, 0x62, 0x3B, 0x3B, 0x27, 0x3B,
-  0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x27, 0x3B, 0x6F, 0x30, 0x6F, 0x6F,
-  0x62, 0x3D, 0x66, 0x54, 0x54, 0x71, 0x71, 0x71,
-  0x5D, 0x5D, 0x54, 0x3B, 0x69, 0x69, 0x3B, 0x71,
-  0x54, 0x40, 0x73, 0x66, 0x54, 0x3D, 0x71, 0x62,
-  0x6F, 0x20, 0x20, 0x39, 0x20, 0x20, 0x20, 0x2D,
-  0x2D, 0x73, 0x40, 0x54, 0x54, 0x54, 0x71, 0x73,
-  0x54, 0x73, 0x71, 0x54, 0x54, 0x54, 0x27, 0x3B,
-  0x3D, 0x3B, 0x27, 0x62, 0x3B, 0x3B, 0x3B, 0x27,
-  0x27, 0x3B, 0x3B, 0x27, 0x62, 0x62, 0x71, 0x62,
-  0x71, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x3B, 0x6F, 0x30, 0x6F, 0x3B, 0x27,
-  0x3D, 0x66, 0x66, 0x54, 0x71, 0x71, 0x27, 0x71,
-  0x66, 0x73, 0x54, 0x27, 0x6F, 0x6F, 0x27, 0x54,
-  0x40, 0x21, 0x5D, 0x73, 0x3D, 0x27, 0x62, 0x3B,
-  0x3B, 0x42, 0x74, 0x52, 0x52, 0x6E, 0x20, 0x20,
-  0x40, 0x54, 0x3D, 0x3D, 0x3D, 0x40, 0x27, 0x3B,
-  0x30, 0x40, 0x27, 0x27, 0x27, 0x71, 0x54, 0x6F,
-  0x5D, 0x6F, 0x3B, 0x71, 0x71, 0x6F, 0x73, 0x6F,
-  0x54, 0x6F, 0x54, 0x27, 0x39, 0x6E, 0x6E, 0x3B,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x3B, 0x3B, 0x3B, 0x62, 0x27, 0x71,
-  0x3D, 0x3D, 0x3D, 0x27, 0x62, 0x27, 0x62, 0x27,
-  0x3D, 0x40, 0x54, 0x27, 0x3B, 0x3B, 0x27, 0x73,
-  0x7A, 0x21, 0x40, 0x54, 0x71, 0x62, 0x6F, 0x6F,
-  0x3B, 0x67, 0x3A, 0x3A, 0x5A, 0x48, 0x3A, 0x20,
-  0x20, 0x53, 0x6D, 0x38, 0x38, 0x6D, 0x38, 0x38,
-  0x6D, 0x38, 0x79, 0x6D, 0x38, 0x6D, 0x6D, 0x6D,
-  0x6D, 0x6D, 0x38, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D,
-  0x6D, 0x6D, 0x6D, 0x67, 0x52, 0x41, 0x22, 0x2F,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4F, 0x6B,
-  0x43, 0x3A, 0x3B, 0x27, 0x27, 0x62, 0x27, 0x71,
-  0x71, 0x71, 0x71, 0x3D, 0x71, 0x71, 0x3D, 0x3D,
-  0x27, 0x40, 0x54, 0x27, 0x30, 0x30, 0x27, 0x40,
-  0x7A, 0x5D, 0x54, 0x71, 0x3B, 0x30, 0x30, 0x3B,
-  0x42, 0x67, 0x67, 0x3E, 0x3A, 0x48, 0x22, 0x5A,
-  0x4F, 0x20, 0x2D, 0x6D, 0x6D, 0x6D, 0x6D, 0x38,
-  0x6D, 0x6D, 0x26, 0x6D, 0x38, 0x6D, 0x38, 0x6D,
-  0x6D, 0x6D, 0x38, 0x6D, 0x38, 0x38, 0x6D, 0x38,
-  0x6D, 0x38, 0x38, 0x3E, 0x55, 0x6C, 0x22, 0x73,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4D,
-  0x5A, 0x45, 0x36, 0x3D, 0x71, 0x27, 0x27, 0x71,
-  0x54, 0x66, 0x73, 0x40, 0x73, 0x66, 0x2D, 0x66,
-  0x30, 0x66, 0x71, 0x30, 0x69, 0x6F, 0x3D, 0x21,
-  0x7A, 0x66, 0x3D, 0x62, 0x3B, 0x6F, 0x3B, 0x28,
-  0x67, 0x52, 0x5A, 0x74, 0x41, 0x3A, 0x74, 0x3A,
-  0x52, 0x20, 0x20, 0x7E, 0x38, 0x6D, 0x6D, 0x6D,
-  0x6D, 0x38, 0x38, 0x6D, 0x6D, 0x6D, 0x6D, 0x38,
-  0x38, 0x6D, 0x6D, 0x38, 0x6D, 0x6D, 0x38, 0x6D,
-  0x6D, 0x6D, 0x6D, 0x2F, 0x52, 0x22, 0x28, 0x50,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2E,
-  0x41, 0x5A, 0x5A, 0x66, 0x54, 0x3D, 0x54, 0x66,
-  0x73, 0x40, 0x40, 0x40, 0x73, 0x66, 0x66, 0x3D,
-  0x69, 0x27, 0x3B, 0x30, 0x30, 0x62, 0x73, 0x7A,
-  0x21, 0x3D, 0x3B, 0x6F, 0x6F, 0x62, 0x2F, 0x75,
-  0x28, 0x55, 0x22, 0x3A, 0x31, 0x3A, 0x41, 0x3A,
-  0x5A, 0x2E, 0x20, 0x4F, 0x20, 0x6D, 0x6D, 0x6D,
-  0x6D, 0x6D, 0x38, 0x6D, 0x38, 0x6D, 0x6D, 0x6D,
-  0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x38,
-  0x6D, 0x6D, 0x78, 0x2F, 0x31, 0x55, 0x2E, 0x3F,
-  0x50, 0x20, 0x20, 0x20, 0x20, 0x4D, 0x24, 0x52,
-  0x22, 0x22, 0x31, 0x2D, 0x66, 0x54, 0x66, 0x66,
-  0x66, 0x66, 0x54, 0x71, 0x27, 0x27, 0x27, 0x62,
-  0x30, 0x3B, 0x3B, 0x6F, 0x3B, 0x3D, 0x40, 0x21,
-  0x73, 0x71, 0x5F, 0x6E, 0x2E, 0x2E, 0x67, 0x52,
-  0x52, 0x31, 0x7D, 0x48, 0x3A, 0x3A, 0x74, 0x74,
-  0x55, 0x39, 0x20, 0x20, 0x20, 0x20, 0x38, 0x6D,
-  0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D,
-  0x38, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D,
-  0x6D, 0x29, 0x29, 0x2F, 0x55, 0x52, 0x2E, 0x24,
-  0x72, 0x68, 0x25, 0x76, 0x68, 0x3F, 0x2E, 0x39,
-  0x52, 0x74, 0x3A, 0x73, 0x66, 0x66, 0x54, 0x54,
-  0x27, 0x3B, 0x6F, 0x6F, 0x6F, 0x6F, 0x3B, 0x62,
-  0x3B, 0x62, 0x27, 0x71, 0x54, 0x40, 0x21, 0x40,
-  0x3D, 0x2E, 0x48, 0x6E, 0x55, 0x55, 0x6E, 0x55,
-  0x3A, 0x74, 0x3E, 0x55, 0x74, 0x5A, 0x22, 0x3A,
-  0x3A, 0x36, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x38,
-  0x6D, 0x6D, 0x38, 0x6D, 0x38, 0x6D, 0x6D, 0x6D,
-  0x38, 0x6D, 0x38, 0x38, 0x6D, 0x38, 0x6D, 0x38,
-  0x6D, 0x32, 0x78, 0x62, 0x3E, 0x52, 0x28, 0x42,
-  0x65, 0x24, 0x5F, 0x24, 0x5F, 0x2E, 0x55, 0x22,
-  0x3A, 0x41, 0x74, 0x31, 0x54, 0x73, 0x66, 0x54,
-  0x27, 0x6F, 0x30, 0x69, 0x30, 0x6F, 0x62, 0x62,
-  0x62, 0x71, 0x3D, 0x54, 0x73, 0x5D, 0x5D, 0x66,
-  0x71, 0x2E, 0x22, 0x31, 0x55, 0x3A, 0x31, 0x5A,
-  0x3A, 0x3A, 0x74, 0x5A, 0x74, 0x3E, 0x31, 0x3A,
-  0x55, 0x22, 0x22, 0x35, 0x20, 0x20, 0x20, 0x20,
-  0x34, 0x38, 0x6D, 0x6D, 0x6D, 0x38, 0x38, 0x6D,
-  0x6D, 0x38, 0x6D, 0x6D, 0x38, 0x6D, 0x6D, 0x6D,
-  0x38, 0x79, 0x29, 0x2F, 0x42, 0x52, 0x28, 0x48,
-  0x48, 0x2E, 0x2E, 0x48, 0x3E, 0x52, 0x3A, 0x74,
-  0x7D, 0x3A, 0x3A, 0x3E, 0x40, 0x40, 0x40, 0x54,
-  0x27, 0x6F, 0x30, 0x6F, 0x62, 0x71, 0x71, 0x71,
-  0x62, 0x3D, 0x66, 0x73, 0x40, 0x5D, 0x73, 0x71,
-  0x62, 0x28, 0x55, 0x5A, 0x5A, 0x55, 0x3A, 0x41,
-  0x55, 0x3A, 0x3A, 0x31, 0x55, 0x55, 0x5A, 0x74,
-  0x3A, 0x31, 0x22, 0x48, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x6D, 0x38, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D,
-  0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x38, 0x6D, 0x6D,
-  0x6D, 0x6D, 0x29, 0x2F, 0x24, 0x28, 0x28, 0x52,
-  0x52, 0x48, 0x48, 0x28, 0x39, 0x52, 0x74, 0x48,
-  0x74, 0x55, 0x22, 0x41, 0x5A, 0x40, 0x54, 0x27,
-  0x3B, 0x6F, 0x3B, 0x71, 0x54, 0x66, 0x66, 0x3D,
-  0x62, 0x54, 0x40, 0x21, 0x7A, 0x40, 0x3D, 0x62,
-  0x62, 0x48, 0x52, 0x55, 0x6C, 0x5A, 0x31, 0x31,
-  0x5A, 0x41, 0x31, 0x3A, 0x3A, 0x7D, 0x31, 0x3A,
-  0x41, 0x41, 0x22, 0x36, 0x42, 0x20, 0x20, 0x20,
-  0x20, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x38,
-  0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x38,
-  0x6D, 0x6D, 0x29, 0x25, 0x59, 0x2E, 0x39, 0x39,
-  0x55, 0x39, 0x39, 0x39, 0x31, 0x22, 0x3A, 0x74,
-  0x5A, 0x3E, 0x6C, 0x3E, 0x31, 0x3E, 0x3A, 0x69,
-  0x49, 0x49, 0x3B, 0x71, 0x66, 0x73, 0x66, 0x54,
-  0x27, 0x66, 0x5D, 0x7A, 0x21, 0x73, 0x71, 0x62,
-  0x27, 0x75, 0x39, 0x41, 0x3A, 0x36, 0x7D, 0x74,
-  0x74, 0x41, 0x55, 0x55, 0x3A, 0x3A, 0x3A, 0x3A,
-  0x31, 0x31, 0x5A, 0x22, 0x52, 0x20, 0x20, 0x20,
-  0x26, 0x38, 0x6D, 0x38, 0x6D, 0x38, 0x6D, 0x38,
-  0x6D, 0x38, 0x38, 0x6D, 0x6D, 0x6D, 0x6D, 0x38,
-  0x38, 0x6D, 0x20, 0x60, 0x24, 0x48, 0x39, 0x3A,
-  0x55, 0x55, 0x31, 0x55, 0x41, 0x74, 0x41, 0x22,
-  0x7D, 0x3A, 0x22, 0x3E, 0x41, 0x5A, 0x3A, 0x74,
-  0x78, 0x30, 0x27, 0x54, 0x40, 0x73, 0x54, 0x3D,
-  0x71, 0x54, 0x5D, 0x7A, 0x21, 0x66, 0x62, 0x3B,
-  0x71, 0x5F, 0x52, 0x3E, 0x41, 0x5A, 0x5A, 0x22,
-  0x3E, 0x3A, 0x74, 0x3E, 0x55, 0x55, 0x3A, 0x31,
-  0x41, 0x3A, 0x48, 0x55, 0x41, 0x42, 0x6D, 0x38,
-  0x38, 0x6D, 0x6D, 0x6D, 0x38, 0x6D, 0x6D, 0x6D,
-  0x38, 0x6D, 0x6D, 0x38, 0x6D, 0x38, 0x6D, 0x6D,
-  0x6D, 0x20, 0x20, 0x25, 0x24, 0x28, 0x52, 0x3A,
-  0x5A, 0x5A, 0x5A, 0x5A, 0x74, 0x74, 0x7D, 0x74,
-  0x3A, 0x74, 0x3A, 0x41, 0x7D, 0x41, 0x3A, 0x3A,
-  0x69, 0x3D, 0x21, 0x4C, 0x4C, 0x5D, 0x66, 0x54,
-  0x66, 0x73, 0x21, 0x6A, 0x21, 0x3D, 0x3B, 0x6F,
-  0x71, 0x75, 0x48, 0x31, 0x5A, 0x3A, 0x3E, 0x48,
-  0x74, 0x7D, 0x3A, 0x7D, 0x3A, 0x3A, 0x55, 0x74,
-  0x5A, 0x3A, 0x41, 0x55, 0x22, 0x22, 0x3F, 0x6D,
-  0x6D, 0x38, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D,
-  0x6D, 0x6D, 0x6D, 0x38, 0x6D, 0x6D, 0x6D, 0x38,
-  0x20, 0x20, 0x20, 0x60, 0x42, 0x28, 0x39, 0x3A,
-  0x3A, 0x31, 0x41, 0x3A, 0x22, 0x55, 0x74, 0x55,
-  0x74, 0x74, 0x74, 0x3A, 0x3A, 0x74, 0x3A, 0x67,
-  0x54, 0x7A, 0x34, 0x77, 0x6A, 0x21, 0x66, 0x66,
-  0x7A, 0x21, 0x21, 0x4C, 0x21, 0x3D, 0x3B, 0x62,
-  0x66, 0x67, 0x28, 0x55, 0x41, 0x31, 0x55, 0x3A,
-  0x74, 0x41, 0x31, 0x3A, 0x3A, 0x41, 0x3A, 0x36,
-  0x5A, 0x5A, 0x31, 0x31, 0x39, 0x22, 0x24, 0x43,
-  0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x38, 0x6D, 0x6D,
-  0x6D, 0x38, 0x6D, 0x6D, 0x6D, 0x38, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x60, 0x24, 0x63, 0x39, 0x55,
-  0x31, 0x5A, 0x3A, 0x74, 0x3A, 0x31, 0x3A, 0x31,
-  0x5A, 0x48, 0x3A, 0x7D, 0x48, 0x41, 0x31, 0x3E,
-  0x6A, 0x64, 0x47, 0x4C, 0x5D, 0x54, 0x71, 0x71,
-  0x6A, 0x5D, 0x5D, 0x21, 0x5D, 0x3D, 0x3B, 0x62,
-  0x66, 0x42, 0x39, 0x3A, 0x41, 0x3A, 0x31, 0x3A,
-  0x7D, 0x3A, 0x74, 0x41, 0x31, 0x31, 0x3E, 0x41,
-  0x5A, 0x41, 0x3A, 0x31, 0x39, 0x52, 0x48, 0x25,
-  0x62, 0x6D, 0x38, 0x38, 0x6D, 0x38, 0x6D, 0x6D,
-  0x6D, 0x6D, 0x6D, 0x6D, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x4D, 0x43, 0x5F, 0x28, 0x52, 0x3E,
-  0x22, 0x31, 0x3A, 0x3A, 0x55, 0x3A, 0x3E, 0x31,
-  0x74, 0x67, 0x3E, 0x3A, 0x3E, 0x67, 0x54, 0x34,
-  0x2B, 0x2B, 0x34, 0x21, 0x66, 0x71, 0x62, 0x62,
-  0x3D, 0x3D, 0x54, 0x5D, 0x40, 0x27, 0x6F, 0x3B,
-  0x67, 0x48, 0x48, 0x39, 0x52, 0x7D, 0x7D, 0x22,
-  0x74, 0x3A, 0x5A, 0x5A, 0x3A, 0x55, 0x31, 0x3A,
-  0x41, 0x7D, 0x3A, 0x22, 0x55, 0x48, 0x42, 0x76,
-  0x4B, 0x20, 0x37, 0x6D, 0x6D, 0x6D, 0x38, 0x78,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x4D, 0x76, 0x42, 0x48, 0x55, 0x74,
-  0x41, 0x6C, 0x48, 0x31, 0x31, 0x3A, 0x5A, 0x74,
-  0x31, 0x6C, 0x22, 0x3E, 0x67, 0x62, 0x7A, 0x64,
-  0x7B, 0x77, 0x5D, 0x54, 0x71, 0x62, 0x62, 0x3B,
-  0x53, 0x62, 0x71, 0x73, 0x73, 0x27, 0x6F, 0x3B,
-  0x67, 0x2E, 0x5F, 0x48, 0x48, 0x52, 0x52, 0x52,
-  0x52, 0x52, 0x31, 0x41, 0x74, 0x41, 0x74, 0x31,
-  0x74, 0x3A, 0x74, 0x74, 0x48, 0x48, 0x42, 0x72,
-  0x4B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x4B, 0x68, 0x42, 0x28, 0x55, 0x74,
-  0x5A, 0x3A, 0x48, 0x55, 0x5A, 0x31, 0x55, 0x55,
-  0x39, 0x67, 0x2F, 0x49, 0x69, 0x27, 0x4C, 0x64,
-  0x34, 0x5D, 0x66, 0x71, 0x62, 0x6F, 0x6F, 0x6F,
-  0x79, 0x27, 0x66, 0x73, 0x66, 0x27, 0x6F, 0x3B,
-  0x54, 0x24, 0x5F, 0x59, 0x24, 0x24, 0x42, 0x2E,
-  0x48, 0x67, 0x28, 0x39, 0x52, 0x39, 0x31, 0x3E,
-  0x55, 0x3A, 0x3A, 0x31, 0x39, 0x48, 0x24, 0x76,
-  0x50, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x4B, 0x76, 0x24, 0x42, 0x52, 0x55,
-  0x41, 0x31, 0x31, 0x39, 0x52, 0x52, 0x48, 0x67,
-  0x72, 0x71, 0x6F, 0x69, 0x58, 0x2D, 0x4C, 0x34,
-  0x7A, 0x40, 0x66, 0x54, 0x62, 0x30, 0x6F, 0x3B,
-  0x53, 0x7A, 0x7A, 0x73, 0x3D, 0x62, 0x30, 0x6F,
-  0x3D, 0x3D, 0x3B, 0x60, 0x2F, 0x76, 0x59, 0x59,
-  0x59, 0x24, 0x24, 0x5F, 0x42, 0x2E, 0x28, 0x55,
-  0x3A, 0x39, 0x39, 0x48, 0x48, 0x65, 0x68, 0x25,
-  0x4B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x4B, 0x25, 0x72, 0x65, 0x2E, 0x28,
-  0x52, 0x28, 0x48, 0x48, 0x2E, 0x24, 0x3F, 0x4B,
-  0x71, 0x27, 0x30, 0x30, 0x27, 0x5D, 0x4C, 0x6A,
-  0x7A, 0x7A, 0x5D, 0x54, 0x3B, 0x30, 0x6F, 0x71,
-  0x27, 0x64, 0x34, 0x40, 0x3D, 0x62, 0x3B, 0x27,
-  0x3D, 0x54, 0x71, 0x3B, 0x3B, 0x62, 0x71, 0x4B,
-  0x43, 0x43, 0x76, 0x76, 0x72, 0x59, 0x24, 0x24,
-  0x42, 0x2E, 0x42, 0x24, 0x2C, 0x76, 0x60, 0x50,
-  0x4D, 0x20, 0x20, 0x20, 0x20, 0x62, 0x27, 0x3D,
-  0x3D, 0x27, 0x62, 0x62, 0x27, 0x27, 0x62, 0x30,
-  0x20, 0x20, 0x4B, 0x25, 0x76, 0x59, 0x24, 0x24,
-  0x42, 0x42, 0x42, 0x65, 0x3F, 0x60, 0x6F, 0x62,
-  0x27, 0x27, 0x62, 0x3B, 0x3D, 0x5D, 0x7A, 0x4C,
-  0x4C, 0x4C, 0x5D, 0x71, 0x30, 0x69, 0x62, 0x54,
-  0x7A, 0x2B, 0x34, 0x2D, 0x71, 0x27, 0x58, 0x62,
-  0x71, 0x3D, 0x71, 0x6F, 0x30, 0x6F, 0x27, 0x54,
-  0x3D, 0x71, 0x66, 0x4B, 0x25, 0x60, 0x76, 0x76,
-  0x72, 0x72, 0x3F, 0x76, 0x76, 0x60, 0x50, 0x4B,
-  0x20, 0x73, 0x3D, 0x62, 0x3B, 0x27, 0x71, 0x3D,
-  0x3D, 0x71, 0x27, 0x62, 0x62, 0x27, 0x62, 0x3B,
-  0x30, 0x27, 0x4D, 0x4B, 0x25, 0x76, 0x72, 0x2C,
-  0x59, 0x2C, 0x3F, 0x76, 0x25, 0x62, 0x30, 0x3B,
-  0x71, 0x3D, 0x71, 0x71, 0x66, 0x5D, 0x5D, 0x21,
-  0x21, 0x21, 0x54, 0x30, 0x78, 0x69, 0x27, 0x66,
-  0x7A, 0x4C, 0x5D, 0x3D, 0x27, 0x62, 0x62, 0x3B,
-  0x62, 0x3D, 0x27, 0x6F, 0x30, 0x3B, 0x71, 0x54,
-  0x3D, 0x3D, 0x54, 0x66, 0x66, 0x66, 0x4B, 0x25,
-  0x25, 0x25, 0x25, 0x60, 0x25, 0x50, 0x4B, 0x71,
-  0x54, 0x54, 0x71, 0x27, 0x3D, 0x54, 0x54, 0x3D,
-  0x3D, 0x71, 0x3B, 0x3B, 0x62, 0x3B, 0x62, 0x3B,
-  0x27, 0x54, 0x4C, 0x4D, 0x4B, 0x25, 0x76, 0x76,
-  0x68, 0x43, 0x25, 0x50, 0x27, 0x30, 0x30, 0x58,
-  0x27, 0x54, 0x54, 0x3D, 0x54, 0x54, 0x66, 0x54,
-  0x66, 0x71, 0x6F, 0x78, 0x53, 0x69, 0x54, 0x73,
-  0x66, 0x66, 0x54, 0x27, 0x27, 0x27, 0x62, 0x3B,
-  0x3B, 0x27, 0x27, 0x3B, 0x6F, 0x62, 0x27, 0x54,
-  0x66, 0x3D, 0x3D, 0x27, 0x27, 0x27, 0x62, 0x6F,
-  0x78, 0x53, 0x78, 0x62, 0x66, 0x73, 0x3D, 0x3D,
-  0x66, 0x2D, 0x54, 0x54, 0x73, 0x73, 0x54, 0x71,
-  0x71, 0x27, 0x3B, 0x6F, 0x3B, 0x3B, 0x62, 0x3B,
-  0x3B, 0x71, 0x73, 0x73, 0x54, 0x71, 0x62, 0x27,
-  0x27, 0x58, 0x62, 0x71, 0x71, 0x6F, 0x6F, 0x62,
-  0x27, 0x54, 0x66, 0x3D, 0x3D, 0x27, 0x27, 0x62,
-  0x62, 0x6F, 0x78, 0x53, 0x78, 0x62, 0x54, 0x66,
-  0x71, 0x3D, 0x71, 0x71, 0x62, 0x27, 0x27, 0x62,
-  0x62, 0x71, 0x3D, 0x27, 0x27, 0x62, 0x27, 0x3D,
-  0x54, 0x3D, 0x27, 0x62, 0x3B, 0x6F, 0x6F, 0x69,
-  0x78, 0x78, 0x6F, 0x54, 0x73, 0x66, 0x54, 0x54,
-  0x40, 0x5D, 0x40, 0x40, 0x40, 0x66, 0x3D, 0x71,
-  0x27, 0x27, 0x3B, 0x30, 0x6F, 0x3B, 0x3B, 0x62,
-  0x3B, 0x3B, 0x27, 0x71, 0x71, 0x27, 0x62, 0x62,
-  0x62, 0x62, 0x62, 0x71, 0x71, 0x71, 0x62, 0x62,
-  0x27, 0x71, 0x54, 0x3D, 0x27, 0x62, 0x3B, 0x6F,
-  0x6F, 0x69, 0x49, 0x49, 0x6F, 0x3D, 0x73, 0x66
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22,
+    0x22, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+    0x26, 0x26, 0x25, 0x28, 0x23, 0x22, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x25, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d,
+    0x2d, 0x2e, 0x2c, 0x2b, 0x2a, 0x25, 0x28, 0x22,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x24, 0x2a, 0x2c, 0x2f, 0x2c, 0x30, 0x30, 0x24,
+    0x25, 0x27, 0x2b, 0x2c, 0x2f, 0x31, 0x32, 0x25,
+    0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
+    0x33, 0x34, 0x35, 0x21, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x21, 0x2b, 0x2f, 0x2c,
+    0x30, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
+    0x2d, 0x27, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x31,
+    0x2d, 0x32, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x37, 0x37, 0x37, 0x37, 0x38,
+    0x37, 0x37, 0x39, 0x37, 0x39, 0x38, 0x39, 0x3a,
+    0x32, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x23, 0x32, 0x27, 0x21, 0x36,
+    0x34, 0x38, 0x38, 0x39, 0x38, 0x37, 0x38, 0x39,
+    0x38, 0x37, 0x38, 0x37, 0x37, 0x37, 0x37, 0x37,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x38, 0x37, 0x37, 0x37, 0x37,
+    0x38, 0x39, 0x37, 0x37, 0x37, 0x37, 0x38, 0x3b,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x25, 0x2f, 0x3c, 0x32, 0x22,
+    0x36, 0x3d, 0x38, 0x37, 0x39, 0x37, 0x38, 0x37,
+    0x39, 0x37, 0x38, 0x37, 0x38, 0x37, 0x37, 0x37,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x3d, 0x3e, 0x3a, 0x3e, 0x3e,
+    0x3e, 0x3f, 0x3e, 0x3a, 0x3e, 0x3e, 0x40, 0x22,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x26, 0x41, 0x41, 0x35, 0x25,
+    0x36, 0x22, 0x42, 0x38, 0x38, 0x37, 0x37, 0x38,
+    0x39, 0x37, 0x37, 0x38, 0x37, 0x38, 0x38, 0x3a,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x43, 0x3e, 0x44, 0x44, 0x45,
+    0x44, 0x40, 0x3a, 0x3f, 0x3a, 0x3f, 0x3b, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x25, 0x2b, 0x30, 0x28, 0x22,
+    0x36, 0x36, 0x35, 0x38, 0x38, 0x38, 0x38, 0x38,
+    0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x37, 0x44,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x34, 0x3e, 0x3a, 0x38, 0x38,
+    0x3e, 0x3e, 0x46, 0x3e, 0x46, 0x46, 0x33, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x22, 0x22, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x47, 0x38, 0x37, 0x37, 0x37,
+    0x38, 0x37, 0x37, 0x37, 0x38, 0x38, 0x37, 0x48,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x33, 0x37, 0x44, 0x3e, 0x22,
+    0x2d, 0x2c, 0x49, 0x43, 0x4a, 0x4b, 0x22, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x49, 0x4c, 0x46, 0x44, 0x46,
+    0x4c, 0x38, 0x44, 0x38, 0x38, 0x3e, 0x37, 0x4d,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x34, 0x3e, 0x3e, 0x3a, 0x36,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x36, 0x36,
+    0x36, 0x21, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x21, 0x23, 0x22, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x28, 0x34, 0x27, 0x22, 0x20,
+    0x21, 0x20, 0x20, 0x20, 0x4e, 0x37, 0x38, 0x4f,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x34, 0x44, 0x3a, 0x3e, 0x43,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
+    0x21, 0x21, 0x24, 0x27, 0x21, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x28, 0x27, 0x22, 0x33, 0x24, 0x36,
+    0x36, 0x36, 0x36, 0x22, 0x2f, 0x2a, 0x23, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x50, 0x38, 0x3e, 0x51,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x2c, 0x3a, 0x44, 0x44, 0x52,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
+    0x30, 0x3b, 0x41, 0x24, 0x24, 0x36, 0x36, 0x36,
+    0x23, 0x2f, 0x53, 0x54, 0x55, 0x30, 0x25, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2f, 0x32, 0x23, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x51, 0x3e, 0x37, 0x42,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x34, 0x44, 0x45, 0x3e, 0x45,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x23,
+    0x56, 0x4d, 0x57, 0x3b, 0x22, 0x36, 0x36, 0x21,
+    0x49, 0x51, 0x4c, 0x45, 0x40, 0x56, 0x23, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2f, 0x33, 0x28, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x40, 0x44, 0x38, 0x51,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x2e, 0x44, 0x40, 0x44, 0x42,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x2b,
+    0x45, 0x57, 0x44, 0x39, 0x35, 0x36, 0x36, 0x26,
+    0x4c, 0x58, 0x59, 0x3d, 0x3f, 0x3e, 0x2e, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x57, 0x44, 0x3e, 0x48,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x5a, 0x44, 0x45, 0x3e, 0x44,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x34, 0x36, 0x4b,
+    0x5b, 0x25, 0x2f, 0x44, 0x3d, 0x22, 0x23, 0x32,
+    0x3a, 0x42, 0x21, 0x31, 0x43, 0x46, 0x50, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x47, 0x3e, 0x38, 0x50,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x49, 0x40, 0x40, 0x44, 0x38,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x21, 0x3b,
+    0x4b, 0x21, 0x31, 0x5c, 0x5d, 0x28, 0x30, 0x2b,
+    0x3f, 0x4b, 0x36, 0x23, 0x32, 0x42, 0x4d, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x2e, 0x5a, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x42, 0x44, 0x44, 0x52,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x2c, 0x4c, 0x40, 0x4c, 0x37,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x41, 0x23, 0x3c,
+    0x5d, 0x36, 0x28, 0x3b, 0x5e, 0x5f, 0x5f, 0x60,
+    0x54, 0x4b, 0x36, 0x36, 0x36, 0x57, 0x57, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2e, 0x5a, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x40, 0x44, 0x3a, 0x5c,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x29, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x2a, 0x44, 0x45, 0x4c, 0x3a,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x43, 0x23, 0x35,
+    0x4c, 0x25, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
+    0x67, 0x68, 0x69, 0x36, 0x31, 0x39, 0x53, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x2c, 0x25, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x52, 0x45, 0x44, 0x54,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x2a, 0x40, 0x4d, 0x4c, 0x38,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x22,
+    0x57, 0x6a, 0x6b, 0x65, 0x6c, 0x6d, 0x6e, 0x6f,
+    0x70, 0x71, 0x6e, 0x66, 0x72, 0x73, 0x2a, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x33, 0x2e, 0x26, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x51, 0x3a, 0x44, 0x47,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x2c, 0x45, 0x4c, 0x4c, 0x38,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x2f, 0x23, 0x36,
+    0x74, 0x6b, 0x75, 0x6c, 0x64, 0x6e, 0x71, 0x76,
+    0x77, 0x78, 0x79, 0x71, 0x71, 0x7a, 0x74, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x33, 0x34, 0x27, 0x22,
+    0x20, 0x20, 0x20, 0x20, 0x54, 0x44, 0x44, 0x54,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x5a, 0x48, 0x48, 0x4f, 0x37,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x34, 0x26, 0x7b,
+    0x7c, 0x7d, 0x7e, 0x6c, 0x6d, 0x7f, 0x71, 0x80,
+    0x78, 0x79, 0x79, 0x79, 0x7a, 0x67, 0x66, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x25, 0x41, 0x2a, 0x23,
+    0x20, 0x20, 0x20, 0x20, 0x81, 0x44, 0x40, 0x5b,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x2c, 0x44, 0x45, 0x4f, 0x38,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x33, 0x82,
+    0x6b, 0x83, 0x84, 0x64, 0x6e, 0x71, 0x76, 0x85,
+    0x79, 0x79, 0x71, 0x86, 0x87, 0x83, 0x88, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x21, 0x43, 0x2b, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x52, 0x44, 0x44, 0x50,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x5a, 0x40, 0x4d, 0x4f, 0x38,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x32, 0x24,
+    0x89, 0x8a, 0x6c, 0x8b, 0x7f, 0x71, 0x79, 0x79,
+    0x71, 0x8c, 0x8d, 0x8e, 0x83, 0x8e, 0x8f, 0x36,
+    0x21, 0x2b, 0x23, 0x36, 0x36, 0x5a, 0x2e, 0x26,
+    0x22, 0x20, 0x20, 0x20, 0x42, 0x40, 0x38, 0x50,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x2c, 0x4c, 0x4f, 0x4f, 0x38,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x2d, 0x33, 0x21,
+    0x90, 0x91, 0x92, 0x7a, 0x6f, 0x6e, 0x67, 0x92,
+    0x93, 0x6b, 0x8e, 0x94, 0x95, 0x96, 0x49, 0x36,
+    0x36, 0x2d, 0x3b, 0x35, 0x36, 0x24, 0x43, 0x32,
+    0x28, 0x21, 0x20, 0x20, 0x57, 0x40, 0x44, 0x54,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x34, 0x4d, 0x42, 0x51, 0x38,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x33, 0x21,
+    0x5d, 0x97, 0x98, 0x93, 0x86, 0x66, 0x99, 0x87,
+    0x7d, 0x7d, 0x99, 0x6a, 0x57, 0x4d, 0x59, 0x23,
+    0x36, 0x24, 0x3b, 0x3b, 0x24, 0x36, 0x2e, 0x31,
+    0x26, 0x22, 0x20, 0x20, 0x52, 0x44, 0x44, 0x9a,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x5a, 0x57, 0x57, 0x57, 0x37,
+    0x20, 0x20, 0x21, 0x28, 0x33, 0x3c, 0x25, 0x22,
+    0x53, 0x42, 0x97, 0x98, 0x99, 0x87, 0x99, 0x6b,
+    0x7c, 0x9b, 0x9c, 0x51, 0x4f, 0x3f, 0x40, 0x2c,
+    0x36, 0x36, 0x33, 0x5a, 0x21, 0x36, 0x22, 0x43,
+    0x33, 0x28, 0x21, 0x20, 0x42, 0x44, 0x37, 0x4f,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x2a, 0x51, 0x42, 0x51, 0x37,
+    0x20, 0x20, 0x22, 0x27, 0x2e, 0x2e, 0x36, 0x21,
+    0x4e, 0x4d, 0x42, 0x9d, 0x9e, 0x98, 0x98, 0x9f,
+    0x97, 0x51, 0x42, 0x4c, 0x39, 0x58, 0x58, 0x47,
+    0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x5a,
+    0x2e, 0x27, 0x23, 0x20, 0x59, 0x48, 0x38, 0x50,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x2a, 0x42, 0x51, 0x42, 0x3e,
+    0x20, 0x22, 0x24, 0x2b, 0x41, 0x28, 0x36, 0x32,
+    0x3e, 0x3f, 0x42, 0x42, 0x42, 0x51, 0x51, 0x42,
+    0x42, 0x57, 0x40, 0x38, 0x58, 0x58, 0x58, 0x58,
+    0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x23,
+    0x2f, 0x2b, 0x24, 0x21, 0x57, 0x4f, 0x3e, 0x53,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x33, 0x47, 0x51, 0x52, 0x38,
+    0x21, 0x28, 0x32, 0x43, 0x32, 0x28, 0x21, 0x47,
+    0x58, 0x39, 0x48, 0x42, 0x42, 0x42, 0x42, 0x42,
+    0x48, 0x3a, 0x37, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x4f, 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x2a, 0x2f, 0x2a, 0x28, 0x42, 0x4f, 0x44, 0x52,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x5a, 0x57, 0x47, 0x51, 0x37,
+    0x23, 0x30, 0x2e, 0x2c, 0x36, 0x21, 0x43, 0x37,
+    0x58, 0x58, 0x46, 0x4d, 0x42, 0x42, 0x57, 0x3f,
+    0x39, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2d, 0x31, 0x27, 0x4f, 0x47, 0x38, 0x50,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x25, 0x57, 0x47, 0x52, 0x38,
+    0x27, 0x2c, 0x2d, 0x21, 0x36, 0x28, 0x45, 0x58,
+    0x58, 0x58, 0x58, 0x39, 0x44, 0x3a, 0x39, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x52, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x28, 0x43, 0x5a, 0x45, 0x4d, 0x37, 0x9a,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x2a, 0x47, 0x52, 0x59, 0x37,
+    0x35, 0x43, 0x28, 0x36, 0x36, 0x4a, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x37, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x3a, 0x28, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x28, 0x41, 0x48, 0x4d, 0x38, 0x54,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x2a, 0x81, 0x5b, 0x51, 0x38,
+    0x43, 0x25, 0x36, 0x36, 0x23, 0x57, 0x37, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x37, 0x38, 0x2b, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x30, 0x51, 0x40, 0x3a, 0x56,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x33, 0x51, 0x47, 0x81, 0x3e,
+    0x27, 0x36, 0x36, 0x36, 0x2a, 0x57, 0x39, 0x58,
+    0x58, 0x58, 0x58, 0x37, 0x38, 0x38, 0x37, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x37, 0x39, 0x46,
+    0x44, 0x3a, 0x3c, 0x21, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x48, 0x59, 0x37, 0x5d,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x27, 0x52, 0x4e, 0x5b, 0x44,
+    0x36, 0x36, 0x36, 0x21, 0x31, 0x5b, 0x48, 0x3e,
+    0x39, 0x37, 0x37, 0x46, 0x44, 0x3a, 0x46, 0x37,
+    0x37, 0x37, 0x39, 0x3a, 0x40, 0x48, 0x4f, 0x4f,
+    0x4d, 0x4f, 0x47, 0x28, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x4f, 0x81, 0x40, 0x5d,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x33, 0x52, 0x50, 0x56, 0x38,
+    0x36, 0x36, 0x36, 0x22, 0x41, 0x47, 0x45, 0x38,
+    0x37, 0x58, 0x58, 0x37, 0x3e, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x39, 0x46, 0x44, 0x4c, 0x4f,
+    0x57, 0x57, 0x4c, 0x50, 0x21, 0x23, 0x33, 0x23,
+    0x36, 0x36, 0x36, 0x36, 0x4d, 0x51, 0x39, 0x3b,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x33, 0x57, 0x55, 0x55, 0x37,
+    0x37, 0x37, 0x38, 0x38, 0x38, 0x37, 0x37, 0x37,
+    0x37, 0x37, 0x38, 0x37, 0x37, 0x37, 0x38, 0x37,
+    0x37, 0x37, 0x37, 0x39, 0x3e, 0x37, 0x38, 0x38,
+    0x38, 0x37, 0x38, 0x38, 0x38, 0x37, 0x38, 0x38,
+    0x37, 0x38, 0x38, 0x37, 0x47, 0x42, 0x48, 0x9a,
+    0x25, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x33, 0x5b, 0x81, 0x5d, 0x37,
+    0x38, 0x37, 0x37, 0x38, 0x37, 0x38, 0x38, 0x37,
+    0x38, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x37,
+    0x38, 0x37, 0x38, 0x37, 0x37, 0x38, 0x37, 0x37,
+    0x38, 0x37, 0x37, 0x37, 0x38, 0x38, 0x37, 0x3e,
+    0x37, 0x38, 0x38, 0x37, 0x57, 0x57, 0x48, 0x5d,
+    0x2a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x33, 0x52, 0x59, 0x50, 0x5b,
+    0x54, 0x5b, 0x5b, 0x54, 0x81, 0x5b, 0x55, 0x55,
+    0x52, 0x54, 0x81, 0x81, 0x81, 0x50, 0x52, 0x54,
+    0x5b, 0x59, 0x52, 0x52, 0x5b, 0x52, 0x5b, 0x81,
+    0x5b, 0x47, 0x51, 0x52, 0x57, 0x57, 0x57, 0x57,
+    0x51, 0x57, 0x52, 0x57, 0x48, 0x57, 0x4c, 0x3b,
+    0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x33, 0x54, 0x54, 0x5b, 0x50,
+    0x54, 0x50, 0x54, 0x81, 0x50, 0x59, 0x54, 0x50,
+    0x5b, 0x81, 0x81, 0x59, 0x81, 0x59, 0x59, 0x59,
+    0x59, 0x47, 0x81, 0x51, 0x47, 0x51, 0x59, 0x81,
+    0x81, 0x51, 0x47, 0x50, 0x59, 0x59, 0x59, 0x47,
+    0x47, 0x47, 0x52, 0x57, 0x52, 0x47, 0x59, 0x26,
+    0x2d, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x22, 0x27, 0x55, 0x50, 0x55, 0x50,
+    0x55, 0x81, 0x54, 0x52, 0x52, 0x81, 0x5b, 0x50,
+    0x5b, 0x52, 0x52, 0x51, 0x57, 0x52, 0x52, 0x52,
+    0x54, 0x51, 0x81, 0x52, 0x59, 0x52, 0x5b, 0x5b,
+    0x59, 0x5b, 0x51, 0x52, 0x52, 0x4f, 0x5b, 0x51,
+    0x52, 0x47, 0x59, 0x42, 0x47, 0x81, 0x5c, 0x21,
+    0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x33, 0x81, 0x54, 0x5c, 0x54,
+    0x50, 0x5b, 0x50, 0x50, 0x81, 0x5b, 0x5c, 0x5b,
+    0x50, 0x59, 0x81, 0x81, 0x81, 0x81, 0x47, 0x50,
+    0x50, 0x59, 0x5b, 0x50, 0x52, 0x81, 0x50, 0x59,
+    0x5b, 0x81, 0x59, 0x81, 0x59, 0x47, 0x59, 0x47,
+    0x59, 0x52, 0x51, 0x48, 0x51, 0x52, 0x5d, 0x36,
+    0x2e, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x22, 0x25, 0x2a, 0x50, 0x4e, 0x5c, 0x54,
+    0x5c, 0x5b, 0x5b, 0x5b, 0x59, 0x5b, 0x50, 0x54,
+    0x5b, 0x54, 0x5b, 0x5b, 0x54, 0x54, 0x5b, 0x5b,
+    0x5b, 0x81, 0x55, 0x81, 0x55, 0x54, 0x5b, 0x5c,
+    0x5b, 0x4e, 0x51, 0x5b, 0x5b, 0x57, 0x51, 0x4f,
+    0x4d, 0x47, 0x4f, 0x4c, 0x51, 0x52, 0x4b, 0x36,
+    0x2a, 0x2e, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x2a, 0x2a, 0x50, 0x9a, 0x54, 0x5c,
+    0x55, 0x50, 0x81, 0x59, 0x54, 0x50, 0x54, 0x50,
+    0x50, 0x50, 0x81, 0x81, 0x50, 0x50, 0x50, 0x81,
+    0x81, 0x5b, 0x47, 0x51, 0x81, 0x59, 0x81, 0x55,
+    0x59, 0x59, 0x81, 0x42, 0x27, 0x36, 0x28, 0x36,
+    0x27, 0x36, 0x28, 0x2d, 0x47, 0x52, 0x2d, 0x36,
+    0x22, 0x2f, 0x30, 0x22, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x22, 0x25, 0x2c, 0x26, 0x53, 0x4e, 0x55, 0x5c,
+    0x55, 0x55, 0x55, 0x81, 0x54, 0x50, 0x54, 0x55,
+    0x5b, 0x55, 0x52, 0x54, 0x54, 0x5b, 0x54, 0x55,
+    0x36, 0x36, 0x27, 0x2a, 0x2a, 0x27, 0xa0, 0x27,
+    0x2a, 0x2a, 0x2c, 0x27, 0x5d, 0x22, 0x22, 0x28,
+    0x28, 0x22, 0x25, 0x59, 0x51, 0x53, 0x27, 0x36,
+    0x21, 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x28, 0x32, 0x2f, 0x21, 0x4a, 0x54, 0x5c, 0x4e,
+    0x5c, 0x81, 0x5c, 0x54, 0x5c, 0x54, 0x5c, 0x50,
+    0x81, 0x50, 0x50, 0x81, 0x81, 0x5c, 0x50, 0x81,
+    0x5d, 0x28, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xa0, 0x25,
+    0x28, 0x21, 0x28, 0x81, 0x59, 0x4a, 0x28, 0x36,
+    0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x25, 0x2c, 0x5a, 0x36, 0x32, 0x9a, 0x81, 0x4e,
+    0x55, 0x5b, 0x50, 0x54, 0x5c, 0x54, 0x55, 0x55,
+    0x54, 0x4e, 0x54, 0x55, 0x5b, 0x4e, 0x55, 0x5b,
+    0x3b, 0x4e, 0x4a, 0x3b, 0x4a, 0x4e, 0x3b, 0x5d,
+    0x56, 0x3b, 0x56, 0x5c, 0x50, 0x3a, 0x3e, 0x40,
+    0x4f, 0x57, 0x81, 0x4e, 0x4e, 0x27, 0x36, 0x36,
+    0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x30, 0x2d, 0x21, 0x36, 0x23, 0x3d, 0x53, 0x43,
+    0x4a, 0x5d, 0x55, 0x5c, 0x4e, 0x5c, 0x50, 0x5c,
+    0x81, 0x50, 0x50, 0x81, 0x50, 0x50, 0x50, 0x50,
+    0x4e, 0x5b, 0x54, 0x5b, 0x51, 0x59, 0x5b, 0x5b,
+    0x54, 0x5b, 0x5b, 0x52, 0x51, 0x42, 0x5b, 0x5c,
+    0x5c, 0x53, 0x5b, 0x3b, 0x28, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x5a, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0x2e, 0x36, 0x36, 0x23, 0x41, 0x56, 0x2e,
+    0x33, 0x50, 0x55, 0x81, 0x54, 0x5b, 0x54, 0x52,
+    0x5b, 0x55, 0x54, 0x55, 0x55, 0x55, 0x5b, 0x9a,
+    0x5c, 0x81, 0x81, 0x81, 0x52, 0x59, 0x50, 0x59,
+    0x59, 0x59, 0x59, 0x50, 0x81, 0x81, 0x5b, 0x5b,
+    0x5b, 0x54, 0x34, 0x22, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x5a, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x2b, 0x5a, 0x36, 0x36, 0x36, 0x27, 0x3d, 0x28,
+    0xa0, 0x5d, 0x5c, 0x55, 0x50, 0x50, 0x5c, 0x81,
+    0x81, 0x50, 0x50, 0x47, 0x50, 0x5c, 0x5c, 0x52,
+    0x54, 0x5b, 0x5b, 0x5b, 0x59, 0x52, 0x5b, 0x52,
+    0x5b, 0x52, 0x52, 0x54, 0x59, 0x5b, 0x81, 0x81,
+    0x9a, 0x33, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x35, 0x5a, 0x36, 0x36, 0x36, 0x36, 0x30, 0x4e,
+    0x52, 0x54, 0x56, 0x55, 0x55, 0x55, 0x55, 0x5b,
+    0x55, 0x55, 0x54, 0x5b, 0x54, 0x55, 0x50, 0x59,
+    0x5c, 0x81, 0x59, 0x52, 0x59, 0x59, 0x81, 0x59,
+    0x81, 0x81, 0x81, 0x81, 0x5b, 0x5b, 0x81, 0x53,
+    0x2a, 0x27, 0xa1, 0x24, 0x25, 0x28, 0x21, 0x36,
+    0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x25,
+    0x5a, 0x4b, 0xa2, 0x8d, 0x8a, 0x5f, 0x21, 0x2d,
+    0x55, 0x5c, 0x9a, 0x5c, 0x5c, 0x5c, 0x50, 0x9a,
+    0x5c, 0x9a, 0x50, 0x5c, 0x5c, 0x5c, 0x54, 0x5b,
+    0x55, 0x5b, 0x54, 0x81, 0x5b, 0x5b, 0x5b, 0x54,
+    0x54, 0x5b, 0x5b, 0x5b, 0x5b, 0x54, 0x54, 0x30,
+    0x23, 0x36, 0x36, 0x36, 0x21, 0x28, 0x2c, 0x30,
+    0x21, 0x41, 0x33, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x28, 0x30,
+    0x2d, 0xa3, 0x83, 0xa4, 0xa5, 0xa5, 0x88, 0x22,
+    0x3b, 0x47, 0x53, 0x55, 0x55, 0x53, 0x54, 0x5b,
+    0x52, 0x53, 0x54, 0x54, 0x54, 0x50, 0x5c, 0x59,
+    0x56, 0x59, 0x5b, 0x50, 0x50, 0x59, 0x9a, 0x59,
+    0x5c, 0x81, 0x50, 0x59, 0x9a, 0x52, 0x68, 0x69,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x30, 0x32,
+    0x25, 0x4b, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x24, 0x26, 0x30, 0x33, 0x31,
+    0x4b, 0x9b, 0x63, 0xa4, 0xa5, 0xa5, 0xa5, 0x62,
+    0x21, 0x2e, 0x44, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x3a, 0x37, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0xa6, 0xa7, 0x71, 0x6e, 0xa8,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x26, 0x25,
+    0x8c, 0xa9, 0x2c, 0x25, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x30, 0x35, 0x2d, 0x2f, 0x3c, 0x3d,
+    0x68, 0x8e, 0xaa, 0xab, 0xa5, 0xa5, 0xa5, 0x8b,
+    0x8f, 0x36, 0x32, 0x4d, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x3e, 0x38, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0xac, 0xa4, 0xa7, 0xad, 0xa0,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x5f,
+    0x7f, 0x6e, 0x34, 0x27, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x23, 0x30, 0x31, 0xae, 0x9b, 0x87, 0x99, 0x99,
+    0x94, 0x63, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0x65, 0xaf, 0x36, 0x24, 0x50, 0x37, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x37, 0x38, 0xac, 0x6c, 0x64, 0x94, 0xaf,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x7b, 0x65,
+    0x8b, 0x64, 0xb0, 0x2a, 0x23, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x24, 0x2b, 0xae, 0x94, 0x63, 0x7e, 0x63, 0x63,
+    0x84, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa7, 0x66, 0x22, 0x36, 0x21, 0x3b, 0x38, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x3a, 0x4d, 0xb1, 0x84, 0x84, 0x8e, 0x89,
+    0xa1, 0x36, 0x36, 0x36, 0x21, 0xb2, 0x87, 0x84,
+    0x6c, 0x6c, 0xb3, 0x35, 0x24, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x31, 0xb4, 0x63, 0x6c, 0xa4, 0xa4, 0xab,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa5, 0x6e, 0xb5, 0x36, 0x36, 0x36, 0x2c, 0x3f,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x48, 0x4d, 0xb6, 0x7e, 0x7e, 0x83, 0x6b,
+    0xb7, 0xb8, 0x8f, 0xb8, 0xb9, 0x99, 0x63, 0x6c,
+    0xa4, 0xa4, 0xba, 0x2d, 0x27, 0x23, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x26, 0x2d, 0x9b, 0x63, 0x6c, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa7, 0x8c, 0xa0, 0x36, 0x36, 0x36, 0x30,
+    0x45, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x37, 0x48, 0x4d, 0xbb, 0x63, 0x84, 0xbc, 0x8e,
+    0x87, 0x99, 0x6b, 0x99, 0x8e, 0x63, 0xa4, 0xa5,
+    0xa5, 0xab, 0x65, 0xb3, 0x5a, 0x26, 0x23, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2d, 0xbd, 0xbc, 0x6c, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa7, 0x91, 0x36, 0x36, 0x36, 0x36,
+    0x2d, 0x37, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x37, 0x40, 0x4d, 0xbe, 0x75, 0x84, 0xaa, 0xbc,
+    0x83, 0x94, 0x94, 0x83, 0x63, 0x6c, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa4, 0xbf, 0x3c, 0x35, 0x26, 0x23,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2e, 0xbd, 0x83, 0x84, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa7, 0x7a, 0x7b, 0x36, 0x36, 0x36,
+    0x24, 0x46, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x44, 0x51, 0xb4, 0x83, 0x84, 0x6c, 0x84,
+    0x7e, 0x63, 0x63, 0x7e, 0x84, 0xa4, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xab, 0x6c, 0xbf, 0x4b, 0x2c, 0x27,
+    0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x25, 0x31, 0xc0, 0x94, 0x84, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa7, 0x92, 0xa1, 0x36, 0x36,
+    0x32, 0x39, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x3f, 0x2f, 0x98, 0x83, 0x84, 0xa4, 0xab,
+    0xa4, 0x6c, 0x6c, 0xa4, 0xa4, 0xab, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0x65, 0xc1, 0x2c,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x25, 0x31, 0xc0, 0x8e, 0x84, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0x6e, 0x5f, 0x27, 0x4b,
+    0x3f, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x38, 0x34, 0xa1, 0xb7, 0x83, 0x84, 0xa4, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xc0,
+    0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2d, 0xc0, 0x8e, 0x84, 0xab, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa7, 0x67, 0x9c, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x45,
+    0x35, 0x36, 0xa0, 0xb9, 0x83, 0x84, 0xab, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xab, 0xa4, 0xbe,
+    0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x30, 0x2f, 0xb4, 0x94, 0x84, 0xab, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0x6e, 0x92, 0x40,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x37, 0x5b, 0x25,
+    0x36, 0x36, 0x69, 0xb7, 0x75, 0x6c, 0xab, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xab, 0x84, 0xbc, 0xc1,
+    0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0xc2, 0x6b, 0xbc, 0xa4, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0x7a, 0x8a, 0xc3,
+    0x44, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x58, 0x58, 0x58, 0x58, 0x4d, 0x2c, 0x36, 0x36,
+    0x36, 0x36, 0xc4, 0x98, 0x75, 0x6c, 0xab, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa4, 0xaa, 0x94, 0xae, 0x2c,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x35, 0x9e, 0x7d, 0xaa, 0xa4, 0xab, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xab, 0x84, 0x8a, 0xb7,
+    0x7b, 0x53, 0x45, 0x37, 0x58, 0x58, 0x58, 0x37,
+    0x38, 0x4c, 0x4e, 0x2c, 0x21, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x7b, 0xb7, 0x83, 0x84, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa5, 0x6c, 0x7e, 0x83, 0x9b, 0xb3, 0x31, 0x30,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x5a, 0x9f, 0x7d, 0xbc, 0x84, 0x6c, 0xa4, 0xa4,
+    0xab, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0x84, 0x83, 0xc5,
+    0xc6, 0x36, 0x21, 0x26, 0x2b, 0x5a, 0x33, 0x30,
+    0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xc6, 0xb9, 0x94, 0x84, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0x6c, 0x6c,
+    0x7e, 0x8e, 0xbd, 0xb3, 0x34, 0x2b, 0x27, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0xc7, 0x6b, 0x87, 0x83, 0x75, 0xbc, 0x63,
+    0x7e, 0x84, 0x6c, 0x6c, 0xa4, 0xab, 0xa5, 0xa5,
+    0xa5, 0xa5, 0xa5, 0xa5, 0xab, 0x7e, 0x8e, 0xb7,
+    0x82, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xc8, 0xb9, 0x7d, 0x7e, 0xa4, 0xa5,
+    0xa5, 0xa5, 0xab, 0xa4, 0x6c, 0x7e, 0xbc, 0x94,
+    0xb4, 0xb3, 0x2f, 0x35, 0x30, 0x24, 0x22, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x27, 0x31, 0xc9, 0xc7, 0xb9, 0x7c, 0x6b, 0x99,
+    0x87, 0x7d, 0x94, 0x75, 0xbc, 0x7e, 0x6c, 0xa4,
+    0xab, 0xab, 0xab, 0xab, 0x6c, 0x83, 0x8d, 0xca,
+    0x82, 0xa1, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xc6, 0xca, 0x6b, 0x75, 0x84, 0x6c,
+    0xab, 0xa4, 0x6c, 0x84, 0xbc, 0x7d, 0x6b, 0x9e,
+    0x41, 0x5a, 0x2a, 0x24, 0x23, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x28, 0x27, 0x35, 0x2d, 0x49, 0xb3, 0xc3, 0x98,
+    0xb7, 0xb9, 0xc5, 0x7c, 0x8d, 0x99, 0x8e, 0x75,
+    0x63, 0x84, 0x84, 0xaa, 0x75, 0x99, 0xb7, 0xcb,
+    0xc8, 0x22, 0x36, 0x36, 0x28, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x25, 0x36,
+    0x36, 0x21, 0xb2, 0x89, 0xc5, 0x87, 0x75, 0x7e,
+    0xaa, 0x7e, 0x75, 0x8e, 0x6b, 0xb7, 0xb3, 0x34,
+    0x33, 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x24, 0x27, 0x2a, 0x35, 0x2e, 0x2f,
+    0x49, 0xcc, 0xcd, 0x74, 0x89, 0xca, 0xb7, 0x7c,
+    0x8d, 0x99, 0x7d, 0x87, 0x7c, 0x98, 0xcb, 0x82,
+    0xc4, 0x2b, 0x4a, 0x49, 0x2f, 0x34, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x34, 0x2f, 0x41,
+    0x4b, 0x3c, 0xce, 0xcf, 0x98, 0x7c, 0x6b, 0x87,
+    0x7d, 0x87, 0x6b, 0xc5, 0x91, 0xc2, 0x31, 0x2a,
+    0x24, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x22, 0x23, 0x24, 0x26, 0x30,
+    0x33, 0x5a, 0x2e, 0x43, 0x49, 0xb0, 0x74, 0xcf,
+    0x89, 0xca, 0xca, 0xca, 0xd0, 0xcf, 0xb5, 0xd1,
+    0x49, 0x34, 0x35, 0x32, 0x30, 0x27, 0x27, 0x27,
+    0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x2a,
+    0x2b, 0x34, 0xd2, 0xc8, 0xd3, 0x98, 0xb9, 0xc5,
+    0xc5, 0xb9, 0xca, 0x74, 0x49, 0x5a, 0x27, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22,
+    0x28, 0x24, 0x26, 0x2a, 0x33, 0x2c, 0x2f, 0x49,
+    0xd4, 0xb5, 0x82, 0x82, 0x82, 0xc8, 0xd5, 0x43,
+    0x5a, 0x30, 0x24, 0x23, 0x22, 0x22, 0x22, 0x22,
+    0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23,
+    0x24, 0x2a, 0x31, 0xd6, 0xc6, 0x82, 0xcf, 0x89,
+    0xd3, 0xb8, 0xd7, 0x2f, 0x35, 0x26, 0x23, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x22, 0x23, 0x28, 0x25, 0x30, 0x2b,
+    0x31, 0x2f, 0xd2, 0xd6, 0xd6, 0x2f, 0x2e, 0x33,
+    0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x27, 0x35, 0x34, 0xd6, 0xd6, 0xd6,
+    0xd8, 0xd2, 0x2e, 0x33, 0x25, 0x23, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x23, 0x28,
+    0x26, 0x30, 0x32, 0x2b, 0x33, 0x2a, 0x26, 0x28,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x25, 0x30, 0x33, 0x35, 0x35,
+    0x2b, 0x2a, 0x26, 0x28, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x21, 0x22, 0x23, 0x28, 0x28, 0x23, 0x22, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x23, 0x28, 0x24, 0x24,
+    0x28, 0x23, 0x22, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 };
 
-#endif
-
-#else
+#endif /* !INCLUDE_LINUX_LOGO_DATA */
 
-#define LINUX_LOGO_COLORS 214
+#endif /* CONFIG_MAC */
 
-#endif
-
-#ifdef INCLUDE_LINUX_LOGO_DATA
-
-#define INCLUDE_LINUX_LOGOBW
-#define INCLUDE_LINUX_LOGO16
 #include <linux/linux_logo.h>
 
-#else
-
-/* prototypes only */
-extern unsigned char linux_logo_red[];
-extern unsigned char linux_logo_green[];
-extern unsigned char linux_logo_blue[];
-extern unsigned char linux_logo[];
-extern unsigned char linux_logo_bw[];
-extern unsigned char linux_logo16_red[];
-extern unsigned char linux_logo16_green[];
-extern unsigned char linux_logo16_blue[];
-extern unsigned char linux_logo16[];
-
-#endif
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/mac_psc.h linux/include/asm-m68k/mac_psc.h
--- v2.4.5/linux/include/asm-m68k/mac_psc.h	Sat Sep  4 13:06:41 1999
+++ linux/include/asm-m68k/mac_psc.h	Mon Jun 11 19:15:27 2001
@@ -51,6 +51,8 @@
  * One-shot DMA control registers
  */
 
+#define PSC_MYSTERY	0x804
+
 #define PSC_CTL_BASE	0xC00
 
 #define PSC_SCSI_CTL	0xC00
@@ -70,6 +72,9 @@
 #define PSC_ADDR_BASE	0x1000
 #define PSC_LEN_BASE	0x1004
 #define PSC_CMD_BASE	0x1008
+
+#define PSC_SET0	0x00
+#define PSC_SET1	0x10
 
 #define PSC_SCSI_ADDR	0x1000 	/* confirmed */
 #define PSC_SCSI_LEN	0x1004 	/* confirmed */
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/mc146818rtc.h linux/include/asm-m68k/mc146818rtc.h
--- v2.4.5/linux/include/asm-m68k/mc146818rtc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/mc146818rtc.h	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,48 @@
+/*
+ * Machine dependent access functions for RTC registers.
+ */
+#ifndef _ASM_MC146818RTC_H
+#define _ASM_MC146818RTC_H
+
+#include <linux/config.h>
+
+#ifdef CONFIG_ATARI
+/* RTC in Atari machines */
+
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/io.h>
+#define RTC_HAS_IRQ	(ATARIHW_PRESENT(TT_MFP))
+#define RTC_IRQ 	IRQ_TT_MFP_RTC
+#define RTC_IRQ_FLAGS	IRQ_TYPE_FAST
+#define RTC_PORT(x)	(TT_RTC_BAS + 2*(x))
+#define RTC_ALWAYS_BCD	0	/* TOS uses binary mode, Linux should be able
+				 * to deal with both modes */
+
+#define RTC_CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
+#define RTC_MACH_INIT()							\
+    do {								\
+	epoch = atari_rtc_year_offset + 1900;				\
+	if (RTC_HAS_IRQ)						\
+	    /* select RTC int on H->L edge */				\
+	    tt_mfp.active_edge &= ~0x40;				\
+    } while(0)
+#define RTC_MACH_EXIT()
+
+/* On Atari, the year was stored with base 1970 in old TOS versions (before
+ * 3.06). Later, Atari recognized that this broke leap year recognition, and
+ * changed the base to 1968. Medusa and Hades always use the new version. */
+#define RTC_CENTURY_SWITCH	-1	/* no century switch */
+#define RTC_MINYEAR		epoch
+
+#define CMOS_READ(addr) ({ \
+outb_p((addr),RTC_PORT(0)); \
+inb_p(RTC_PORT(1)); \
+})
+#define CMOS_WRITE(val, addr) ({ \
+outb_p((addr),RTC_PORT(0)); \
+outb_p((val),RTC_PORT(1)); \
+})
+#endif /* CONFIG_ATARI */
+
+#endif /* _ASM_MC146818RTC_H */
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/motorola_pgalloc.h linux/include/asm-m68k/motorola_pgalloc.h
--- v2.4.5/linux/include/asm-m68k/motorola_pgalloc.h	Mon Apr 23 15:28:07 2001
+++ linux/include/asm-m68k/motorola_pgalloc.h	Mon Jun 11 19:15:27 2001
@@ -21,6 +21,22 @@
 extern pmd_t *get_pointer_table(void);
 extern int free_pointer_table(pmd_t *);
 
+
+extern inline void flush_tlb_kernel_page(unsigned long addr)
+{
+	if (CPU_IS_040_OR_060) {
+		mm_segment_t old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		__asm__ __volatile__(".chip 68040\n\t"
+				     "pflush (%0)\n\t"
+				     ".chip 68k"
+				     : : "a" (addr));
+		set_fs(old_fs);
+	} else
+		__asm__ __volatile__("pflush #4,#4,(%0)" : : "a" (addr));
+}
+
+
 extern inline pte_t *get_pte_fast(void)
 {
 	unsigned long *ret;
@@ -33,6 +49,29 @@
 	}
 	return (pte_t *)ret;
 }
+#define pte_alloc_one_fast(mm,addr)  get_pte_fast()
+
+static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+ 	pte_t *pte;
+
+	pte = (pte_t *) __get_free_page(GFP_KERNEL);
+	if (pte) {
+	         clear_page(pte);
+		 __flush_page_to_ram((unsigned long)pte);
+		 flush_tlb_kernel_page((unsigned long)pte);
+		 nocache_page((unsigned long)pte);
+		}
+
+	return pte;
+}
+
+
+extern __inline__ pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+        return get_pointer_table();
+}
+
 
 extern inline void free_pte_fast(pte_t *pte)
 {
@@ -59,6 +98,7 @@
 	}
 	return (pmd_t *)ret;
 }
+#define pmd_alloc_one_fast(mm,addr) get_pmd_fast()
 
 extern inline void free_pmd_fast(pmd_t *pmd)
 {
@@ -94,46 +134,11 @@
 	free_pte_fast(pte);
 }
 
-extern inline pte_t *pte_alloc(pmd_t *pmd, unsigned long address)
-{
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-	if (pmd_none(*pmd)) {
-		pte_t *page = get_pte_fast();
-
-		if (!page)
-			return get_pte_slow(pmd, address);
-		pmd_set(pmd,page);
-		return page + address;
-	}
-	if (pmd_bad(*pmd)) {
-		__bad_pte(pmd);
-		return NULL;
-	}
-	return (pte_t *)__pmd_page(*pmd) + address;
-}
-
 extern inline void pmd_free(pmd_t *pmd)
 {
 	free_pmd_fast(pmd);
 }
 
-extern inline pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address)
-{
-	address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
-	if (pgd_none(*pgd)) {
-		pmd_t *page = get_pmd_fast();
-
-		if (!page)
-			return get_pmd_slow(pgd, address);
-		pgd_set(pgd, page);
-		return page + address;
-	}
-	if (pgd_bad(*pgd)) {
-		__bad_pmd(pgd);
-		return NULL;
-	}
-	return (pmd_t *)__pgd_page(*pgd) + address;
-}
 
 extern inline void pte_free_kernel(pte_t *pte)
 {
@@ -142,7 +147,7 @@
 
 extern inline pte_t *pte_alloc_kernel(pmd_t *pmd, unsigned long address)
 {
-	return pte_alloc(pmd, address);
+	return pte_alloc(&init_mm,pmd, address);
 }
 
 extern inline void pmd_free_kernel(pmd_t *pmd)
@@ -152,7 +157,7 @@
 
 extern inline pmd_t *pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
 {
-	return pmd_alloc(pgd, address);
+	return pmd_alloc(&init_mm,pgd, address);
 }
 
 extern inline void pgd_free(pgd_t *pgd)
@@ -168,6 +173,11 @@
 	return pgd;
 }
 
+
+#define pmd_populate(MM, PMD, PTE)	pmd_set(PMD, PTE)
+#define pgd_populate(MM, PGD, PMD)	pgd_set(PGD, PMD)
+
+
 extern int do_check_pgt_cache(int, int);
 
 extern inline void set_pgdir(unsigned long address, pgd_t entry)
@@ -238,19 +248,6 @@
 		__flush_tlb();
 }
 
-extern inline void flush_tlb_kernel_page(unsigned long addr)
-{
-	if (CPU_IS_040_OR_060) {
-		mm_segment_t old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		__asm__ __volatile__(".chip 68040\n\t"
-				     "pflush (%0)\n\t"
-				     ".chip 68k"
-				     : : "a" (addr));
-		set_fs(old_fs);
-	} else
-		__asm__ __volatile__("pflush #4,#4,(%0)" : : "a" (addr));
-}
 
 extern inline void flush_tlb_pgtables(struct mm_struct *mm,
 				      unsigned long start, unsigned long end)
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/openprom.h linux/include/asm-m68k/openprom.h
--- v2.4.5/linux/include/asm-m68k/openprom.h	Fri Nov 12 04:29:47 1999
+++ linux/include/asm-m68k/openprom.h	Mon Jun 11 19:15:27 2001
@@ -89,7 +89,7 @@
 	int *fd_stdout;
 };
 
-#ifdef CONFIG_SUN3
+#if defined(CONFIG_SUN3) || defined(CONFIG_SUN3X)
 struct linux_romvec {
 	char		*pv_initsp;		
 	int		(*pv_startmon)(void);
@@ -173,12 +173,15 @@
 						
 	void		(*pv_halt)(void);	
 	unsigned char	*pv_memorybitmap;	
+
+#ifdef CONFIG_SUN3
 	void		(*pv_setctxt)(int ctxt, char *va, int pmeg);
 	void		(*pv_vector_cmd)(void);	
 	int		dummy1z;
 	int		dummy2z;
 	int		dummy3z;
 	int		dummy4z;
+#endif
 };
 #else
 /* The top level PROM vector. */
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/parport.h linux/include/asm-m68k/parport.h
--- v2.4.5/linux/include/asm-m68k/parport.h	Mon Nov 27 17:11:26 2000
+++ linux/include/asm-m68k/parport.h	Mon Jun 11 19:15:27 2001
@@ -11,6 +11,9 @@
 #ifndef _ASM_M68K_PARPORT_H
 #define _ASM_M68K_PARPORT_H 1
 
+#define insl(port,buf,len)   isa_insb(port,buf,(len)<<2)
+#define outsl(port,buf,len)  isa_outsb(port,buf,(len)<<2)
+
 /* no dma, or IRQ autoprobing */
 static int __devinit parport_pc_find_isa_ports (int autoirq, int autodma);
 static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma)
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/pgalloc.h linux/include/asm-m68k/pgalloc.h
--- v2.4.5/linux/include/asm-m68k/pgalloc.h	Tue Dec  5 12:43:48 2000
+++ linux/include/asm-m68k/pgalloc.h	Mon Jun 11 19:15:27 2001
@@ -105,14 +105,14 @@
 }
 
 /* Push the page at kernel virtual address and clear the icache */
+/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
 #define flush_page_to_ram(page) __flush_page_to_ram((unsigned long) page_address(page))
 extern inline void __flush_page_to_ram(unsigned long address)
 {
 	if (CPU_IS_040_OR_060) {
 		__asm__ __volatile__("nop\n\t"
 				     ".chip 68040\n\t"
-				     "cpushp %%dc,(%0)\n\t"
-				     "cinvp %%ic,(%0)\n\t"
+				     "cpushp %%bc,(%0)\n\t"
 				     ".chip 68k"
 				     : : "a" (__pa((void *)address)));
 	} else {
@@ -128,6 +128,7 @@
 #define flush_dcache_page(page)			do { } while (0)
 
 /* Push n pages at kernel virtual address and clear the icache */
+/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
 extern inline void flush_icache_range (unsigned long address,
 				       unsigned long endaddr)
 {
@@ -137,8 +138,7 @@
 		while (--n >= 0) {
 			__asm__ __volatile__("nop\n\t"
 					     ".chip 68040\n\t"
-					     "cpushp %%dc,(%0)\n\t"
-					     "cinvp %%ic,(%0)\n\t"
+					     "cpushp %%bc,(%0)\n\t"
 					     ".chip 68k"
 					     : : "a" (virt_to_phys((void *)address)));
 			address += PAGE_SIZE;
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/q40_keyboard.h linux/include/asm-m68k/q40_keyboard.h
--- v2.4.5/linux/include/asm-m68k/q40_keyboard.h	Mon Nov 27 17:57:34 2000
+++ linux/include/asm-m68k/q40_keyboard.h	Mon Jun 11 19:15:27 2001
@@ -1,11 +1,7 @@
 /*
  *  linux/include/asm-m68k/q40_keyboard.h
  *
- *  Created 
- */
-
-/*
- *  This file contains the Q40 specific keyboard definitions
+ *  Q40 specific keyboard definitions
  */
 
 
@@ -23,23 +19,12 @@
 			   char raw_mode);
 extern char q40kbd_unexpected_up(unsigned char keycode);
 extern void q40kbd_leds(unsigned char leds);
+extern int q40kbd_is_sysrq(unsigned char keycode);
 extern void q40kbd_init_hw(void);
 extern unsigned char q40kbd_sysrq_xlate[128];
 
 
-#if 0
-#define kbd_setkeycode		q40kbd_setkeycode
-#define kbd_getkeycode		q40kbd_getkeycode
-#define kbd_pretranslate	q40kbd_pretranslate
-#define kbd_translate		q40kbd_translate
-#define kbd_unexpected_up	q40kbd_unexpected_up
-#define kbd_leds		q40kbd_leds
-#define kbd_init_hw		q40kbd_init_hw
-#define kbd_sysrq_xlate		q40kbd_sysrq_xlate
-
 
-#define SYSRQ_KEY 0x54
-#endif
 #endif /* __KERNEL__ */
 
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/q40_master.h linux/include/asm-m68k/q40_master.h
--- v2.4.5/linux/include/asm-m68k/q40_master.h	Mon Nov 27 17:11:26 2000
+++ linux/include/asm-m68k/q40_master.h	Mon Jun 11 19:15:27 2001
@@ -6,7 +6,7 @@
 #ifndef _Q40_MASTER_H
 #define _Q40_MASTER_H
 
-#include <asm/io.h>
+#include <asm/raw_io.h>
 
 
 #define q40_master_addr 0xff000000
@@ -17,6 +17,10 @@
 #define KEYCODE_REG         0x1c      /* value of received scancode  */
 #define DISPLAY_CONTROL_REG 0x18
 #define FRAME_CLEAR_REG     0x24
+#define LED_REG             0x30
+
+#define Q40_LED_ON()        master_outb(1,LED_REG)
+#define Q40_LED_OFF()       master_outb(0,LED_REG)
 
 #define INTERRUPT_REG       IIRQ_REG  /* "native" ints */
 #define KEY_IRQ_ENABLE_REG  0x08      /**/
@@ -35,13 +39,10 @@
 #endif
 #define EXT_ENABLE_REG      0x10      /* ... rest of the ISA ints ... */
 
-#if 0
-#define master_inb(_reg_)           (*(((unsigned char *)q40_master_addr)+_reg_))
-#define master_outb(_b_,_reg_)      (*(((unsigned char *)q40_master_addr)+_reg_)=(_b_))
-#else
-#define master_inb(_reg_)      native_inb((unsigned char *)q40_master_addr+_reg_)
-#define master_outb(_b_,_reg_)  native_outb(_b_,(unsigned char *)q40_master_addr+_reg_)
-#endif
+
+#define master_inb(_reg_)      in_8((unsigned char *)q40_master_addr+_reg_)
+#define master_outb(_b_,_reg_)  out_8((unsigned char *)q40_master_addr+_reg_,_b_)
+
 
 /* define some Q40 specific ints */
 #include "q40ints.h"
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/raw_io.h linux/include/asm-m68k/raw_io.h
--- v2.4.5/linux/include/asm-m68k/raw_io.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/raw_io.h	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,242 @@
+/*
+ * linux/include/asm-m68k/io_native.h 
+ *
+ * 10/20/00 RZ: - created from bits of io.h and ide.h to cleanup namespace
+ *
+ */
+
+#ifndef _RAW_IO_H
+#define _RAW_IO_H
+
+#ifdef __KERNEL__
+
+
+/* ++roman: The assignments to temp. vars avoid that gcc sometimes generates
+ * two accesses to memory, which may be undesirable for some devices.
+ */
+#define in_8(addr) \
+    ({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; })
+#define in_be16(addr) \
+    ({ unsigned short __v = (*(volatile unsigned short *) (addr)); __v; })
+#define in_be32(addr) \
+    ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; })
+
+#define out_8(addr,b) (void)((*(volatile unsigned char *) (addr)) = (b))
+#define out_be16(addr,b) (void)((*(volatile unsigned short *) (addr)) = (b))
+#define out_be32(addr,b) (void)((*(volatile unsigned int *) (addr)) = (b))
+
+#define raw_inb in_8
+#define raw_inw in_be16
+#define raw_inl in_be32
+
+#define raw_outb(val,port) out_8((port),(val))
+#define raw_outw(val,port) out_be16((port),(val))
+#define raw_outl(val,port) out_be32((port),(val))
+
+#define raw_insb(port, buf, len) ({	   \
+	volatile unsigned char *_port = (volatile unsigned char *) (port);   \
+        unsigned char *_buf =(unsigned char *)(buf);	   \
+        unsigned int  _i,_len=(unsigned int)(len);	   \
+        for(_i=0; _i< _len; _i++)  \
+           *_buf++=in_8(_port);      \
+  })
+
+#define raw_outsb(port, buf, len) ({	   \
+	volatile unsigned char *_port = (volatile unsigned char *) (port);   \
+        unsigned char *_buf =(unsigned char *)(buf);	   \
+        unsigned int  _i,_len=(unsigned int)(len);	   \
+        for( _i=0; _i< _len; _i++)  \
+           out_8(_port,*_buf++);      \
+  })
+ 
+
+#define raw_insw(port, buf, nr) ({				\
+	volatile unsigned char *_port = (volatile unsigned char *) (port);	\
+	unsigned char *_buf = (unsigned char *)(buf);			\
+	unsigned int _nr = (unsigned int)(nr);					\
+	unsigned long _tmp;				\
+							\
+	if (_nr & 15) {					\
+		_tmp = (_nr & 15) - 1;			\
+		asm volatile (				\
+			"1: movew %2@,%0@+; dbra %1,1b"	\
+			: "=a" (_buf), "=d" (_tmp)	\
+			: "a" (_port), "0" (_buf),	\
+			  "1" (_tmp));			\
+	}						\
+	if (_nr >> 4) {					\
+		_tmp = (_nr >> 4) - 1;			\
+		asm volatile (				\
+			"1: "				\
+			"movew %2@,%0@+; "		\
+			"movew %2@,%0@+; "		\
+			"movew %2@,%0@+; "		\
+			"movew %2@,%0@+; "		\
+			"movew %2@,%0@+; "		\
+			"movew %2@,%0@+; "		\
+			"movew %2@,%0@+; "		\
+			"movew %2@,%0@+; "		\
+			"movew %2@,%0@+; "		\
+			"movew %2@,%0@+; "		\
+			"movew %2@,%0@+; "		\
+			"movew %2@,%0@+; "		\
+			"movew %2@,%0@+; "		\
+			"movew %2@,%0@+; "		\
+			"movew %2@,%0@+; "		\
+			"movew %2@,%0@+; "		\
+			"dbra %1,1b"			\
+			: "=a" (_buf), "=d" (_tmp)	\
+			: "a" (_port), "0" (_buf),	\
+			  "1" (_tmp));			\
+	}						\
+})
+
+#define raw_outsw(port, buf, nr) ({				\
+	volatile unsigned char *_port = (volatile unsigned char *) (port);	\
+	unsigned char *_buf = (unsigned char *)(buf);			\
+	unsigned int _nr = (unsigned int)(nr);					\
+	unsigned long _tmp;				\
+							\
+	if (_nr & 15) {					\
+		_tmp = (_nr & 15) - 1;			\
+		asm volatile (				\
+			"1: movew %0@+,%2@; dbra %1,1b"	\
+			: "=a" (_buf), "=d" (_tmp)	\
+			: "a" (_port), "0" (_buf),	\
+			  "1" (_tmp));			\
+	}						\
+	if (_nr >> 4) {					\
+		_tmp = (_nr >> 4) - 1;			\
+		asm volatile (				\
+			"1: "				\
+			"movew %0@+,%2@; "		\
+			"movew %0@+,%2@; "		\
+			"movew %0@+,%2@; "		\
+			"movew %0@+,%2@; "		\
+			"movew %0@+,%2@; "		\
+			"movew %0@+,%2@; "		\
+			"movew %0@+,%2@; "		\
+			"movew %0@+,%2@; "		\
+			"movew %0@+,%2@; "		\
+			"movew %0@+,%2@; "		\
+			"movew %0@+,%2@; "		\
+			"movew %0@+,%2@; "		\
+			"movew %0@+,%2@; "		\
+			"movew %0@+,%2@; "		\
+			"movew %0@+,%2@; "		\
+			"movew %0@+,%2@; "		\
+			"dbra %1,1b"	   		\
+			: "=a" (_buf), "=d" (_tmp)	\
+			: "a" (_port), "0" (_buf),	\
+			  "1" (_tmp));			\
+	}						\
+})
+
+
+#define raw_insw_swapw(port, buf, nr) \
+({  if ((nr) % 8) \
+	__asm__ __volatile__ \
+	       ("movel %0,%/a0; \
+		 movel %1,%/a1; \
+		 movel %2,%/d6; \
+		 subql #1,%/d6; \
+	       1:movew %/a0@,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a1@+; \
+		 dbra %/d6,1b"  \
+		:               \
+		: "g" (port), "g" (buf), "g" (nr) \
+		: "d0", "a0", "a1", "d6"); \
+    else \
+	__asm__ __volatile__ \
+	       ("movel %0,%/a0; \
+		 movel %1,%/a1; \
+		 movel %2,%/d6; \
+		 lsrl  #3,%/d6; \
+		 subql #1,%/d6; \
+	       1:movew %/a0@,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a1@+; \
+		 movew %/a0@,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a1@+; \
+		 movew %/a0@,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a1@+; \
+		 movew %/a0@,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a1@+; \
+		 movew %/a0@,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a1@+; \
+		 movew %/a0@,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a1@+; \
+		 movew %/a0@,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a1@+; \
+		 movew %/a0@,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a1@+; \
+		 dbra %/d6,1b"  \
+                :               \
+		: "g" (port), "g" (buf), "g" (nr) \
+		: "d0", "a0", "a1", "d6"); \
+})
+
+
+#define raw_outsw_swapw(port, buf, nr) \
+({  if ((nr) % 8) \
+	__asm__ __volatile__ \
+	       ("movel %0,%/a0; \
+		 movel %1,%/a1; \
+		 movel %2,%/d6; \
+		 subql #1,%/d6; \
+	       1:movew %/a1@+,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a0@; \
+		 dbra %/d6,1b"  \
+                :               \
+		: "g" (port), "g" (buf), "g" (nr) \
+		: "d0", "a0", "a1", "d6"); \
+    else \
+	__asm__ __volatile__ \
+	       ("movel %0,%/a0; \
+		 movel %1,%/a1; \
+		 movel %2,%/d6; \
+		 lsrl  #3,%/d6; \
+		 subql #1,%/d6; \
+	       1:movew %/a1@+,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a0@; \
+		 movew %/a1@+,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a0@; \
+		 movew %/a1@+,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a0@; \
+		 movew %/a1@+,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a0@; \
+		 movew %/a1@+,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a0@; \
+		 movew %/a1@+,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a0@; \
+		 movew %/a1@+,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a0@; \
+		 movew %/a1@+,%/d0; \
+		 rolw  #8,%/d0; \
+		 movew %/d0,%/a0@; \
+		 dbra %/d6,1b"  \
+                :               \
+		: "g" (port), "g" (buf), "g" (nr) \
+		: "d0", "a0", "a1", "d6"); \
+})
+
+
+#endif /* __KERNEL__ */
+
+#endif /* _RAW_IO_H */
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/rtc.h linux/include/asm-m68k/rtc.h
--- v2.4.5/linux/include/asm-m68k/rtc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/rtc.h	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,49 @@
+/* asm-m68k/rtc.h
+ *
+ * Copyright Richard Zidlicky
+ * implementation details for genrtc/q40rtc driver
+ */
+/* permission is hereby granted to copy, modify and redistribute this code
+ * in terms of the GNU Library General Public License, Version 2 or later,
+ * at your option.
+ */
+
+#ifndef _ASM_RTC_H
+#define _ASM_RTC_H
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+
+struct hwclk_time {
+	unsigned	sec;	/* 0..59 */
+	unsigned	min;	/* 0..59 */
+	unsigned	hour;	/* 0..23 */
+	unsigned	day;	/* 1..31 */
+	unsigned	mon;	/* 0..11 */
+	unsigned	year;	/* 70... */
+	int		wday;	/* 0..6, 0 is Sunday, -1 means unknown/don't set */
+};
+
+/* a few implementation details for the emulation : */
+
+extern unsigned gen_rtc_irq_flags; /* which sort(s) of interrupts caused int */
+extern unsigned gen_rtc_irq_ctrl;  /*                             are enabled */
+extern short q40rtc_oldsecs;
+
+#define RTC_PIE 0x40		/* periodic interrupt enable */
+#define RTC_AIE 0x20		/* alarm interrupt enable */
+#define RTC_UIE 0x10		/* update-finished interrupt enable */
+
+extern void gen_rtc_interrupt(unsigned long);
+
+/* some dummy definitions */
+#define RTC_SQWE 0x08		/* enable square-wave output */
+#define RTC_DM_BINARY 0x04	/* all time/date values are BCD if clear */
+#define RTC_24H 0x02		/* 24 hour mode - else hours bit 7 means pm */
+#define RTC_DST_EN 0x01	        /* auto switch DST - works f. USA only */
+
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM__RTC_H */
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/sbus.h linux/include/asm-m68k/sbus.h
--- v2.4.5/linux/include/asm-m68k/sbus.h	Sat Sep  4 13:06:41 1999
+++ linux/include/asm-m68k/sbus.h	Mon Jun 11 19:15:27 2001
@@ -17,4 +17,27 @@
 
 #define ARCH_SUN4  0
 
+/* sbus IO functions stolen from include/asm-sparc/io.h for the serial driver */
+/* No SBUS on the Sun3, kludge -- sam */
+
+extern inline void _sbus_writeb(unsigned char val, unsigned long addr)
+{
+	*(volatile unsigned char *)addr = val;
+}
+
+extern inline unsigned char _sbus_readb(unsigned long addr)
+{
+	return *(volatile unsigned char *)addr;
+}
+
+extern inline void _sbus_writel(unsigned long val, unsigned long addr)
+{
+	*(volatile unsigned long *)addr = val;
+
+}
+
+#define sbus_readb(a) _sbus_readb((unsigned long)a)
+#define sbus_writeb(v, a) _sbus_writeb(v, (unsigned long)a)
+#define sbus_writel(v, a) _sbus_writel(v, (unsigned long)a)
+
 #endif
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/serial.h linux/include/asm-m68k/serial.h
--- v2.4.5/linux/include/asm-m68k/serial.h	Wed Apr 18 11:49:13 2001
+++ linux/include/asm-m68k/serial.h	Mon Jun 11 19:15:27 2001
@@ -7,11 +7,6 @@
  */
 
 #include <linux/config.h>
-#if 0
-#define rs_init serial_rs_init
-#define register_serial serial_register_serial
-#define unregister_serial serial_unregister_serial
-#endif
 
 /*
  * This assumes you have a 1.8432 MHz clock for your UART.
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/string.h linux/include/asm-m68k/string.h
--- v2.4.5/linux/include/asm-m68k/string.h	Thu Apr 27 15:55:09 2000
+++ linux/include/asm-m68k/string.h	Mon Jun 11 19:15:27 2001
@@ -80,8 +80,9 @@
   return( (char *) s);
 }
 
+#if 0
 #define __HAVE_ARCH_STRPBRK
-static inline char * strpbrk(const char * cs,const char * ct)
+extern inline char * strpbrk(const char * cs,const char * ct)
 {
   const char *sc1,*sc2;
   
@@ -91,7 +92,9 @@
 	return((char *) sc1);
   return( NULL );
 }
+#endif
 
+#if 0
 #define __HAVE_ARCH_STRSPN
 static inline size_t strspn(const char *s, const char *accept)
 {
@@ -112,9 +115,11 @@
 
   return count;
 }
+#endif
 
+#if 0
 #define __HAVE_ARCH_STRTOK
-static inline char * strtok(char * s,const char * ct)
+extern inline char * strtok(char * s,const char * ct)
 {
   char *sbegin, *send;
   
@@ -133,6 +138,7 @@
   ___strtok = send;
   return (sbegin);
 }
+#endif
 
 /* strstr !! */
 
@@ -318,7 +324,7 @@
 #ifdef CPU_M68040_OR_M68060_ONLY
 
   if (((unsigned long) s) & 0x0f)
-	  memset(s, c, count);
+	  __memset_g(s, c, count);
   else{
 	  *((unsigned long *)(s))++ = data;
 	  *((unsigned long *)(s))++ = data;
@@ -356,6 +362,8 @@
   return xs;
 }
 
+extern void *memset(void *,int,__kernel_size_t);
+
 #define __memset_const(s,c,count) \
 ((count==PAGE_SIZE) ? \
   __memset_page((s),(c),(count)) : \
@@ -364,7 +372,7 @@
 #define memset(s, c, count) \
 (__builtin_constant_p(count) ? \
  __memset_const((s),(c),(count)) : \
- memset((s),(c),(count)))
+ __memset_g((s),(c),(count)))
 
 #define __HAVE_ARCH_MEMCPY
 /*
@@ -541,5 +549,15 @@
 (__builtin_constant_p(n) ? \
  __builtin_memcmp((cs),(ct),(n)) : \
  memcmp((cs),(ct),(n)))
+
+#define __HAVE_ARCH_MEMCHR
+extern inline void * memchr(const void * cs, int c, size_t count) {
+	/* Someone else can optimize this, I don't care - tonym@mac.linux-m68k.org */
+	unsigned char *ret = (unsigned char *)cs;
+	for(;count>0;count--,ret++)
+		if(*ret == c) return ret;
+
+	return NULL;
+}
 
 #endif /* _M68K_STRING_H_ */
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/sun3_pgalloc.h linux/include/asm-m68k/sun3_pgalloc.h
--- v2.4.5/linux/include/asm-m68k/sun3_pgalloc.h	Mon Apr 23 15:28:07 2001
+++ linux/include/asm-m68k/sun3_pgalloc.h	Mon Jun 11 19:15:27 2001
@@ -74,46 +74,30 @@
         return (pmd_t *) pgd;
 }
 
+#define pmd_alloc_one_fast(mm, address) ({ BUG(); ((pmd_t *)1); })
+#define pmd_alloc_one(mm,address)       ({ BUG(); ((pmd_t *)2); })
+
 extern inline void pte_free(pte_t * pte)
 {
         free_page((unsigned long) pte);
 }
 
-extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
-{
-	address = (address >> (PAGE_SHIFT-2)) & 4*(PTRS_PER_PTE - 1);
-
-repeat:
-	if (pmd_none(*pmd))
-		goto getnew;
-	if (pmd_bad(*pmd))
-		goto fix;
-	return (pte_t *) (__pmd_page(*pmd) + address);
-
-getnew:
+static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
 {
 	unsigned long page = __get_free_page(GFP_KERNEL);
-	if (!pmd_none(*pmd))
-		goto freenew;
+
 	if (!page)
-		goto oom;
+		return NULL;
+		
 	memset((void *)page, 0, PAGE_SIZE);
 //	pmd_val(*pmd) = SUN3_PMD_MAGIC + __pa(page);
-	pmd_val(*pmd) = __pa(page);
-	return (pte_t *) (page + address);
-freenew:
-	free_page(page);
-	goto repeat;
+/*	pmd_val(*pmd) = __pa(page); */
+	return (pte_t *) (page);
 }
 
-fix:
-	printk(bad_pmd_string, pmd_val(*pmd));
-	printk("in normal pgd offset %08x\n", (unsigned int)pmd);
-oom:
-//	pmd_val(*pmd) = SUN3_PMD_MAGIC + __pa(BAD_PAGETABLE);
-	pmd_val(*pmd) = __pa(BAD_PAGETABLE);
-	return NULL;
-}
+#define pte_alloc_one_fast(mm,addr) pte_alloc_one(mm,addr)
+
+#define pmd_populate(mm, pmd, pte) (pmd_val(*pmd) = __pa((unsigned long)pte))
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
@@ -124,11 +108,6 @@
         pmd_val(*pmd) = 0;
 }
 
-extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
-{
-        return (pmd_t *) pgd;
-}
-
 extern inline void pgd_free(pgd_t * pgd)
 {
         free_page((unsigned long) pgd);
@@ -143,6 +122,8 @@
      memset(new_pgd, 0, (PAGE_OFFSET >> PGDIR_SHIFT));
      return new_pgd;
 }
+
+#define pgd_populate(mm, pmd, pte) BUG()
 
 /* FIXME: the sun3 doesn't have a page table cache! 
    (but the motorola routine should just return 0) */
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/sun3_pgtable.h linux/include/asm-m68k/sun3_pgtable.h
--- v2.4.5/linux/include/asm-m68k/sun3_pgtable.h	Mon Nov 27 18:00:49 2000
+++ linux/include/asm-m68k/sun3_pgtable.h	Mon Jun 11 19:15:27 2001
@@ -135,12 +135,13 @@
 extern inline int pmd_bad2 (pmd_t *pmd) { return 0; }
 #define pmd_bad(pmd) pmd_bad2(&(pmd))
 extern inline int pmd_present2 (pmd_t *pmd) { return pmd_val (*pmd) & SUN3_PMD_VALID; }
-#define pmd_present(pmd) pmd_present2(&(pmd))
+/* #define pmd_present(pmd) pmd_present2(&(pmd)) */
+#define pmd_present(pmd) (!pmd_none2(&(pmd)))
 extern inline void pmd_clear (pmd_t *pmdp) { pmd_val (*pmdp) = 0; }
 
 extern inline int pgd_none (pgd_t pgd) { return 0; }
 extern inline int pgd_bad (pgd_t pgd) { return 0; }
-extern inline int pgd_present (pgd_t pgd) { return 0; }
+extern inline int pgd_present (pgd_t pgd) { return 1; }
 extern inline void pgd_clear (pgd_t *pgdp) {}
 
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/sun3ints.h linux/include/asm-m68k/sun3ints.h
--- v2.4.5/linux/include/asm-m68k/sun3ints.h	Fri Nov 12 04:29:47 1999
+++ linux/include/asm-m68k/sun3ints.h	Mon Jun 11 19:15:27 2001
@@ -26,5 +26,15 @@
                      void (*handler)(int, void *, struct pt_regs *),
                      unsigned long flags, const char *devname, void *dev_id
 		    );
+extern void sun3_init_IRQ (void);
+extern void (*sun3_default_handler[]) (int, void *, struct pt_regs *);
+extern void (*sun3_inthandler[]) (int, void *, struct pt_regs *);
+extern void sun3_free_irq (unsigned int irq, void *dev_id);
+extern void sun3_enable_interrupts (void);
+extern void sun3_disable_interrupts (void);
+extern int sun3_get_irq_list(char *buf);
+extern void sun3_process_int(int, struct pt_regs *);
+extern volatile unsigned char* sun3_intreg;
+
 
 #endif /* SUN3INTS_H */
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/sun3x.h linux/include/asm-m68k/sun3x.h
--- v2.4.5/linux/include/asm-m68k/sun3x.h	Tue May 11 09:57:14 1999
+++ linux/include/asm-m68k/sun3x.h	Mon Jun 11 19:15:27 2001
@@ -15,6 +15,9 @@
 #define SUN3X_VIDEO_P4ID  0x50300000
 #define SUN3X_ESP_BASE	  0x66000000
 #define SUN3X_ESP_DMA	  0x66001000
+#define SUN3X_FDC         0x6e000000
+#define SUN3X_FDC_FCR     0x6e000400
+#define SUN3X_FDC_FVR     0x6e000800
 
 /* some NVRAM addresses */
 #define SUN3X_EEPROM_CONS 	(SUN3X_EEPROM + 0x1f)
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/sun3xflop.h linux/include/asm-m68k/sun3xflop.h
--- v2.4.5/linux/include/asm-m68k/sun3xflop.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/sun3xflop.h	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,263 @@
+/* sun3xflop.h: Sun3/80 specific parts of the floppy driver.
+ *
+ * Derived partially from asm-sparc/floppy.h, which is:
+ *     Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Sun3x version 2/4/2000 Sam Creasey (sammy@oh.verio.com)
+ */
+
+#ifndef __ASM_SUN3X_FLOPPY_H
+#define __ASM_SUN3X_FLOPPY_H
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/sun3x.h>
+
+/* default interrupt vector */
+#define SUN3X_FDC_IRQ 0x40
+
+/* some constants */
+#define FCR_TC 0x1
+#define FCR_EJECT 0x2
+#define FCR_MTRON 0x4
+#define FCR_DSEL1 0x8
+#define FCR_DSEL0 0x10
+
+/* We don't need no stinkin' I/O port allocation crap. */
+#undef release_region
+#undef check_region
+#undef request_region
+#define release_region(X, Y)	do { } while(0)
+#define check_region(X, Y)	(0)
+#define request_region(X, Y, Z)	(1)
+
+struct sun3xflop_private {
+	volatile unsigned char *status_r;
+	volatile unsigned char *data_r;
+	volatile unsigned char *fcr_r;
+	volatile unsigned char *fvr_r;
+	unsigned char fcr;
+} sun3x_fdc;
+
+/* Super paranoid... */
+#undef HAVE_DISABLE_HLT
+
+/* Routines unique to each controller type on a Sun. */
+static unsigned char sun3x_82072_fd_inb(int port)
+{
+	static int once = 0;
+//	udelay(5);
+	switch(port & 7) {
+	default:
+		printk("floppy: Asked to read unknown port %d\n", port);
+		panic("floppy: Port bolixed.");
+	case 4: /* FD_STATUS */
+		return (*sun3x_fdc.status_r) & ~STATUS_DMA;
+	case 5: /* FD_DATA */
+		return (*sun3x_fdc.data_r);
+	case 7: /* FD_DIR */
+		/* ugly hack, I can't find a way to actually detect the disk */
+		if(!once) {
+			once = 1;
+			return 0x80;
+		}
+		return 0;
+	};
+	panic("sun_82072_fd_inb: How did I get here?");
+}
+
+static void sun3x_82072_fd_outb(unsigned char value, int port)
+{
+//	udelay(5);
+	switch(port & 7) {
+	default:
+		printk("floppy: Asked to write to unknown port %d\n", port);
+		panic("floppy: Port bolixed.");
+	case 2: /* FD_DOR */
+		/* Oh geese, 82072 on the Sun has no DOR register,
+		 * so we make do with taunting the FCR.
+		 *
+		 * ASSUMPTIONS:  There will only ever be one floppy
+		 *               drive attached to a Sun controller
+		 *               and it will be at drive zero.
+		 */
+
+	{
+		unsigned char fcr = sun3x_fdc.fcr;
+
+		if(value & 0x10) {
+			fcr |= (FCR_DSEL0 | FCR_MTRON);
+		} else 
+			fcr &= ~(FCR_DSEL0 | FCR_MTRON);
+		
+		
+		if(fcr != sun3x_fdc.fcr) { 
+			*(sun3x_fdc.fcr_r) = fcr;
+			sun3x_fdc.fcr = fcr;
+		}
+	}
+		break;
+	case 5: /* FD_DATA */
+		*(sun3x_fdc.data_r) = value;
+		break;
+	case 7: /* FD_DCR */
+		*(sun3x_fdc.status_r) = value;
+		break;
+	case 4: /* FD_STATUS */
+		*(sun3x_fdc.status_r) = value;
+		break;
+	};
+	return;
+}
+
+
+asmlinkage void sun3xflop_hardint(int irq, void *dev_id, struct pt_regs * regs)
+{
+	register unsigned char st;
+
+#undef TRACE_FLPY_INT
+#define NO_FLOPPY_ASSEMBLER
+
+#ifdef TRACE_FLPY_INT 
+	static int calls=0;
+	static int bytes=0;
+	static int dma_wait=0;
+#endif
+	if(!doing_pdma) {
+		floppy_interrupt(irq, dev_id, regs);
+		return;
+	}
+
+//	printk("doing pdma\n");// st %x\n", sun_fdc->status_82072);
+
+#ifdef TRACE_FLPY_INT
+	if(!calls)
+		bytes = virtual_dma_count;
+#endif
+
+	{
+		register int lcount;
+		register char *lptr;
+
+		for(lcount=virtual_dma_count, lptr=virtual_dma_addr; 
+		    lcount; lcount--, lptr++) {
+//			st=fd_inb(virtual_dma_port+4) & 0x80 ;
+			st = *(sun3x_fdc.status_r);
+//			if(st != 0xa0)
+//				break;
+	
+			if((st & 0x80) == 0) {
+				virtual_dma_count = lcount;
+				virtual_dma_addr = lptr;
+				return;
+			}
+
+			if((st & 0x20) == 0)
+				break;
+		
+			if(virtual_dma_mode)
+//				fd_outb(*lptr, virtual_dma_port+5);
+				*(sun3x_fdc.data_r) = *lptr;
+			else
+//				*lptr = fd_inb(virtual_dma_port+5);
+				*lptr = *(sun3x_fdc.data_r);
+		}
+		
+		virtual_dma_count = lcount;
+		virtual_dma_addr = lptr;
+//		st = fd_inb(virtual_dma_port+4);
+		st = *(sun3x_fdc.status_r);
+	}
+
+#ifdef TRACE_FLPY_INT
+	calls++;
+#endif
+//	printk("st=%02x\n", st);
+	if(st == 0x20)
+		return;
+	if(!(st & 0x20)) {
+		virtual_dma_residue += virtual_dma_count;
+		virtual_dma_count=0;
+		doing_pdma = 0;
+
+#ifdef TRACE_FLPY_INT
+		printk("count=%x, residue=%x calls=%d bytes=%x dma_wait=%d\n", 
+		       virtual_dma_count, virtual_dma_residue, calls, bytes,
+		       dma_wait);
+		calls = 0;
+		dma_wait=0;
+#endif
+
+		floppy_interrupt(irq, dev_id, regs);
+		return;
+	}
+
+	
+#ifdef TRACE_FLPY_INT
+	if(!virtual_dma_count)
+		dma_wait++;
+#endif
+}
+
+static int sun3xflop_request_irq(void)
+{
+	static int once = 0;
+	int error;
+
+	if(!once) {
+		once = 1;
+		error = request_irq(FLOPPY_IRQ, sun3xflop_hardint, SA_INTERRUPT, "floppy", 0);
+		return ((error == 0) ? 0 : -1);
+	} else return 0;
+}
+
+static void __init floppy_set_flags(int *ints,int param, int param2);
+
+static int sun3xflop_init(void)
+{
+	if(FLOPPY_IRQ < 0x40)
+		FLOPPY_IRQ = SUN3X_FDC_IRQ;
+
+	sun3x_fdc.status_r = (volatile unsigned char *)SUN3X_FDC;
+	sun3x_fdc.data_r  = (volatile unsigned char *)(SUN3X_FDC+1);
+	sun3x_fdc.fcr_r = (volatile unsigned char *)SUN3X_FDC_FCR;
+	sun3x_fdc.fvr_r = (volatile unsigned char *)SUN3X_FDC_FVR;
+	sun3x_fdc.fcr = 0;
+
+	/* Last minute sanity check... */
+	if(*sun3x_fdc.status_r == 0xff) {
+		return -1;
+	}
+	
+	*sun3x_fdc.fvr_r = FLOPPY_IRQ;
+	
+	*sun3x_fdc.fcr_r = FCR_TC;
+	udelay(10);
+	*sun3x_fdc.fcr_r = 0;
+
+	/* Success... */
+	floppy_set_flags(0, 1, FD_BROKEN_DCL); // I don't know how to detect this.
+	allowed_drive_mask = 0x01;
+	return (int) SUN3X_FDC;
+}
+
+/* I'm not precisely sure this eject routine works */
+static int sun3x_eject(void)
+{
+	if(MACH_IS_SUN3X) {
+	
+		sun3x_fdc.fcr |= (FCR_DSEL0 | FCR_EJECT);
+		*(sun3x_fdc.fcr_r) = sun3x_fdc.fcr;
+		udelay(10);
+		sun3x_fdc.fcr &= ~(FCR_DSEL0 | FCR_EJECT);
+		*(sun3x_fdc.fcr_r) = sun3x_fdc.fcr;
+	}
+
+	return 0;
+}
+
+#define fd_eject(drive) sun3x_eject()
+
+#endif /* !(__ASM_SUN3X_FLOPPY_H) */
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/sun3xprom.h linux/include/asm-m68k/sun3xprom.h
--- v2.4.5/linux/include/asm-m68k/sun3xprom.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/sun3xprom.h	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,43 @@
+/* Useful PROM locations */
+
+#ifndef SUN3X_PROM_H
+#define SUN3X_PROM_H
+
+extern void (*sun3x_putchar)(int);
+extern int (*sun3x_getchar)(void);
+extern int (*sun3x_mayget)(void);
+extern int (*sun3x_mayput)(int);
+
+void sun3x_reboot(void);
+void sun3x_abort(void);
+void sun3x_prom_init(void);
+unsigned long sun3x_prom_ptov(unsigned long pa, unsigned long size);
+
+/* interesting hardware locations */
+#define SUN3X_IOMMU       0x60000000
+#define SUN3X_ENAREG      0x61000000
+#define SUN3X_INTREG      0x61001400
+#define SUN3X_DIAGREG     0x61001800
+#define SUN3X_ZS1         0x62000000
+#define SUN3X_ZS2         0x62002000
+#define SUN3X_LANCE       0x65002000
+#define SUN3X_EEPROM      0x64000000
+#define SUN3X_IDPROM      0x640007d8
+#define SUN3X_VIDEO_BASE  0x50400000
+#define SUN3X_VIDEO_REGS  0x50300000
+
+/* vector table */
+#define SUN3X_PROM_BASE   0xfefe0000
+#define SUN3X_P_GETCHAR   (SUN3X_PROM_BASE + 20)
+#define SUN3X_P_PUTCHAR   (SUN3X_PROM_BASE + 24)
+#define SUN3X_P_MAYGET    (SUN3X_PROM_BASE + 28)
+#define SUN3X_P_MAYPUT    (SUN3X_PROM_BASE + 32)
+#define SUN3X_P_REBOOT    (SUN3X_PROM_BASE + 96)
+#define SUN3X_P_SETLEDS   (SUN3X_PROM_BASE + 144)
+#define SUN3X_P_ABORT     (SUN3X_PROM_BASE + 152)
+
+/* mapped area */
+#define SUN3X_MAP_START   0xfee00000
+#define SUN3X_MAP_END     0xff000000
+
+#endif
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/system.h linux/include/asm-m68k/system.h
--- v2.4.5/linux/include/asm-m68k/system.h	Mon Nov 27 18:00:49 2000
+++ linux/include/asm-m68k/system.h	Mon Jun 11 19:15:27 2001
@@ -52,9 +52,9 @@
 #define __sti() asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory")
 #else
 #include <asm/hardirq.h>
-#define __sti() ({								\
-	if (!local_irq_count(smp_processor_id()))				\
-		asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory");	\
+#define __sti() ({							      \
+	if (MACH_IS_Q40 || !local_irq_count(smp_processor_id()))              \
+		asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory");  \
 })
 #endif
 #define __cli() asm volatile ("oriw  #0x0700,%%sr": : : "memory")
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/termios.h linux/include/asm-m68k/termios.h
--- v2.4.5/linux/include/asm-m68k/termios.h	Sat Feb  3 20:00:45 2001
+++ linux/include/asm-m68k/termios.h	Mon Jun 11 19:15:27 2001
@@ -65,6 +65,7 @@
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14
+#define N_HCI		15  /* Bluetooth HCI UART */
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-m68k/zorro.h linux/include/asm-m68k/zorro.h
--- v2.4.5/linux/include/asm-m68k/zorro.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/zorro.h	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,18 @@
+#ifndef _ASM_ZORRO_H
+#define _ASM_ZORRO_H
+#include <asm/raw_io.h>
+
+#define z_readb raw_inb
+#define z_readw raw_inw
+#define z_readl raw_inl
+
+#define z_writeb raw_outb
+#define z_writew raw_outw
+#define z_writel raw_outl
+
+#define z_memset_io(a,b,c)	memset((void *)(a),(b),(c))
+#define z_memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
+#define z_memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
+
+
+#endif /* _ASM_ZORRO_H */
diff -u --recursive --new-file v2.4.5/linux/include/asm-mips/linux_logo.h linux/include/asm-mips/linux_logo.h
--- v2.4.5/linux/include/asm-mips/linux_logo.h	Sat May 13 08:31:25 2000
+++ linux/include/asm-mips/linux_logo.h	Mon Jun 11 19:15:27 2001
@@ -24,918 +24,897 @@
 
 #define linux_logo_banner "Linux/MIPS version " UTS_RELEASE
 
-#define LINUX_LOGO_COLORS 212
+#define __HAVE_ARCH_LINUX_LOGO
+
+#define LINUX_LOGO_COLORS	187
 
 #ifdef INCLUDE_LINUX_LOGO_DATA
 
 unsigned char linux_logo_red[] __initdata = {
-  0x03, 0x82, 0xE9, 0xBF, 0x42, 0xC9, 0x7E, 0xC0,
-  0xE9, 0xE3, 0xC2, 0x24, 0xA4, 0x65, 0xEC, 0xC4,
-  0x82, 0x9F, 0xF3, 0x12, 0x5F, 0xA0, 0xC2, 0xED,
-  0x3E, 0xD5, 0xDB, 0xA0, 0x1C, 0xF4, 0xEB, 0xA4,
-  0xCD, 0x0A, 0x9A, 0x51, 0xCC, 0xBE, 0xC0, 0xBA,
-  0x74, 0xDC, 0xAA, 0xF6, 0xD3, 0xC5, 0xE6, 0x26,
-  0xC2, 0x83, 0x38, 0xEA, 0x49, 0xB0, 0xED, 0xE5,
-  0xF4, 0x96, 0x96, 0x1B, 0xFA, 0xCC, 0xF2, 0x0F,
-  0xCD, 0xE5, 0xF4, 0xD3, 0x50, 0x7A, 0xB5, 0xDE,
-  0xD5, 0xB6, 0x60, 0x0A, 0x6A, 0xEA, 0xD4, 0xEB,
-  0xC1, 0xCA, 0xEA, 0xEC, 0x2A, 0x96, 0x95, 0xDC,
-  0xE4, 0xCE, 0xEC, 0x1E, 0xDC, 0x8A, 0xD1, 0xF6,
-  0x3C, 0x5E, 0xC6, 0xB4, 0xB2, 0xAC, 0xBA, 0x9E,
-  0x0F, 0x59, 0xBA, 0xFA, 0xCC, 0xBF, 0x82, 0xCE,
-  0xE6, 0x4F, 0xAA, 0x4C, 0xCA, 0x8E, 0x8E, 0xDF,
-  0x2C, 0xB6, 0x3B, 0xDE, 0xCE, 0xEE, 0x46, 0x4A,
-  0x6F, 0x7A, 0x82, 0xE4, 0xAA, 0x88, 0xE2, 0xCE,
-  0xAE, 0xB6, 0x70, 0xC2, 0x9A, 0xDA, 0x35, 0x9E,
-  0x95, 0xC0, 0x7E, 0x8C, 0xC2, 0xB6, 0xCE, 0xB9,
-  0xD5, 0xAA, 0xC1, 0xF4, 0xC7, 0xB6, 0xB6, 0xA3,
-  0xF2, 0x68, 0xDB, 0x76, 0xDC, 0x57, 0xD3, 0xA8,
-  0xC0, 0xEF, 0x46, 0xF4, 0x2F, 0xD7, 0x53, 0x36,
-  0xE6, 0xA7, 0xCA, 0xCB, 0x7E, 0xE4, 0x86, 0x9A,
-  0xCE, 0x94, 0xB4, 0x1D, 0xDA, 0xCE, 0x6C, 0xE6,
-  0x9E, 0xC6, 0xDA, 0x16, 0xFA, 0xAA, 0x56, 0xB6,
-  0xFE, 0x6E, 0xEA, 0xCE, 0xE5, 0xCC, 0xDB, 0xD3,
-  0xED, 0xDC, 0xF4, 0x72
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65,
+    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+    0xc3, 0x65, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x76, 0x79,
+    0x62, 0x36, 0x9a, 0xe2, 0xec, 0xe1, 0xb8, 0xd7,
+    0xaf, 0x25, 0xbc, 0xc0, 0xef, 0xea, 0xe8, 0xe8,
+    0xf5, 0xf1, 0xda, 0xd3, 0x79, 0xdb, 0xf4, 0xf6,
+    0xf6, 0xf6, 0xe2, 0x3d, 0xb4, 0xce, 0xe6, 0xee,
+    0xf6, 0x68, 0xd8, 0xec, 0xf5, 0xc6, 0xc8, 0x9c,
+    0x89, 0xd2, 0xee, 0xcb, 0xb9, 0xd2, 0x66, 0x5e,
+    0x8b, 0xbe, 0xa8, 0xd5, 0xca, 0xb6, 0xae, 0x9c,
+    0xc5, 0xbe, 0xbe, 0xca, 0x90, 0xb2, 0x9a, 0xa8,
+    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x8d,
+    0x12, 0x4a, 0x8e, 0xf2, 0xf6, 0xee, 0xb5, 0xe4,
+    0xf1, 0x26, 0x9a, 0xea, 0xf6, 0xe0, 0xd2, 0x16,
+    0x9a, 0x2e, 0x70, 0xd6, 0x46, 0x7c, 0xb4, 0x62,
+    0xd6, 0xa3, 0x74, 0xa7, 0xa2, 0xca, 0xe0, 0xae,
+    0xbe, 0xce, 0xa3, 0x8e, 0x6d, 0x8e, 0x32, 0xaf,
+    0x50, 0x9e, 0x5b, 0x8a, 0x98, 0x82, 0x7a, 0x82,
+    0x56, 0x7c, 0x8a, 0x56, 0x5e, 0x86, 0x6a, 0x52,
+    0x59, 0x64, 0x5e,
 };
 
 unsigned char linux_logo_green[] __initdata = {
-  0x03, 0x82, 0xC4, 0x83, 0x42, 0xA2, 0x4A, 0xA4,
-  0xE5, 0xA6, 0xC2, 0x24, 0xA4, 0x65, 0xB4, 0x94,
-  0x66, 0x87, 0xB6, 0x12, 0x44, 0x6C, 0x96, 0xD4,
-  0x36, 0x95, 0xB2, 0x92, 0x0E, 0xF4, 0xBC, 0x77,
-  0xA5, 0x0A, 0x92, 0x52, 0xB4, 0x9A, 0x8C, 0xB2,
-  0x74, 0xC2, 0x8E, 0xBD, 0xA2, 0xCA, 0xD2, 0x12,
-  0xB6, 0x61, 0x24, 0xDA, 0x33, 0x79, 0xCB, 0xAC,
-  0xDA, 0x84, 0x7A, 0x1B, 0xFA, 0x8D, 0xBE, 0x06,
-  0x93, 0xBB, 0xBC, 0xAB, 0x44, 0x62, 0x83, 0xDA,
-  0x9B, 0xA2, 0x4C, 0x04, 0x6A, 0xB6, 0xC8, 0xBD,
-  0x8D, 0xB6, 0xAD, 0xEC, 0x2A, 0x68, 0x62, 0x9D,
-  0xC4, 0xC4, 0xB4, 0x13, 0xA3, 0x8A, 0xD2, 0xD6,
-  0x3C, 0x5D, 0x8C, 0x7E, 0x82, 0xAC, 0x96, 0x7E,
-  0x0D, 0x5A, 0xBA, 0xBB, 0xCC, 0xBE, 0x76, 0xB6,
-  0xDE, 0x4E, 0x9A, 0x3C, 0xBE, 0x8E, 0x6E, 0xCB,
-  0x1C, 0xAA, 0x2E, 0xBE, 0xAA, 0xDE, 0x3E, 0x4B,
-  0x4D, 0x7A, 0x54, 0xE4, 0x8E, 0x6E, 0xCA, 0x9B,
-  0x70, 0x9E, 0x5A, 0xAA, 0x9A, 0xBE, 0x34, 0x9E,
-  0x71, 0x9E, 0x7E, 0x5F, 0xAA, 0x8A, 0xBE, 0x91,
-  0xCE, 0x88, 0x92, 0xDB, 0xC6, 0xAB, 0x8A, 0x72,
-  0xE2, 0x44, 0xC3, 0x54, 0xAA, 0x45, 0xBB, 0x92,
-  0xBA, 0xC4, 0x46, 0xCA, 0x2D, 0xD6, 0x3B, 0x1A,
-  0xC2, 0x7E, 0xA6, 0xCB, 0x7A, 0xDC, 0x86, 0x72,
-  0xB6, 0x94, 0xB4, 0x1C, 0xBC, 0xAE, 0x4C, 0xD6,
-  0x62, 0x86, 0xD3, 0x16, 0xF6, 0x7A, 0x55, 0x79,
-  0xFE, 0x6E, 0xC6, 0xC6, 0xAA, 0x93, 0xDC, 0x9D,
-  0xAE, 0xA4, 0xD4, 0x56
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65,
+    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+    0xc3, 0x62, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x62, 0x5c,
+    0x4e, 0x26, 0x72, 0xaa, 0xba, 0xaf, 0x90, 0xae,
+    0x92, 0x1a, 0xa4, 0x85, 0xb6, 0xbe, 0xc3, 0xc8,
+    0xcf, 0xd0, 0xc2, 0xce, 0x57, 0xa2, 0xd6, 0xda,
+    0xda, 0xd7, 0xb8, 0x2a, 0x7b, 0x91, 0xae, 0xca,
+    0xda, 0x45, 0x9e, 0xb2, 0xd7, 0x9b, 0x90, 0x76,
+    0x5c, 0xa2, 0xbe, 0xa6, 0x85, 0x96, 0x4e, 0x46,
+    0x66, 0x92, 0x7a, 0x9a, 0x96, 0x9d, 0x9a, 0x6b,
+    0x8a, 0x8e, 0xb2, 0xca, 0x90, 0xa6, 0x79, 0x7c,
+    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x8d,
+    0x0e, 0x36, 0x86, 0xba, 0xbe, 0xcc, 0x8e, 0xb8,
+    0xc4, 0x1e, 0x8e, 0xae, 0xba, 0xb2, 0xa6, 0x12,
+    0x7a, 0x20, 0x64, 0xaa, 0x2f, 0x70, 0x85, 0x46,
+    0xa6, 0x6e, 0x51, 0x72, 0x92, 0xa2, 0xa6, 0x87,
+    0x96, 0xa2, 0x85, 0x7a, 0x6a, 0x6e, 0x22, 0x76,
+    0x36, 0x76, 0x3c, 0x6e, 0x63, 0x53, 0x66, 0x62,
+    0x42, 0x50, 0x56, 0x42, 0x56, 0x56, 0x56, 0x3e,
+    0x51, 0x52, 0x56,
 };
 
 unsigned char linux_logo_blue[] __initdata = {
-  0x04, 0x84, 0x10, 0x0C, 0x41, 0x14, 0x04, 0x78,
-  0xC7, 0x0E, 0xC4, 0x24, 0xA4, 0x64, 0x0C, 0x0D,
-  0x17, 0x24, 0x0D, 0x13, 0x11, 0x07, 0x40, 0x22,
-  0x0C, 0x0C, 0x11, 0x78, 0x06, 0xF4, 0x0B, 0x0A,
-  0x47, 0x0B, 0x7C, 0x54, 0x6C, 0x0C, 0x0D, 0x9C,
-  0x73, 0x54, 0x14, 0x0C, 0x0F, 0xC7, 0x94, 0x04,
-  0x94, 0x17, 0x0A, 0x6C, 0x08, 0x0F, 0x14, 0x0B,
-  0x12, 0x68, 0x28, 0x11, 0xFA, 0x0A, 0x34, 0x09,
-  0x0A, 0x2F, 0x15, 0x19, 0x14, 0x3C, 0x06, 0xC4,
-  0x0B, 0x84, 0x24, 0x08, 0x69, 0x38, 0xBC, 0x15,
-  0x1F, 0xA0, 0x0A, 0xEC, 0x2A, 0x0C, 0x0C, 0x0C,
-  0x2C, 0xA0, 0x15, 0x07, 0x0B, 0x8C, 0xD3, 0x10,
-  0x3B, 0x5C, 0x0C, 0x04, 0x3C, 0xAC, 0x54, 0x1C,
-  0x0B, 0x5B, 0xBB, 0x0A, 0xC1, 0xBB, 0x5C, 0x3C,
-  0xBC, 0x4D, 0x74, 0x10, 0x8C, 0x8C, 0x14, 0x91,
-  0x0C, 0x74, 0x17, 0x0C, 0x48, 0x9C, 0x3C, 0x4C,
-  0x09, 0x7C, 0x05, 0xE4, 0x34, 0x38, 0x6C, 0x11,
-  0x08, 0x7C, 0x18, 0x2C, 0x9C, 0x4C, 0x34, 0x9C,
-  0x29, 0x54, 0x7C, 0x0C, 0x78, 0x18, 0x9C, 0x14,
-  0xBA, 0x30, 0x27, 0x31, 0xC2, 0x97, 0x24, 0x09,
-  0xB4, 0x04, 0x87, 0x0C, 0x14, 0x1F, 0x7C, 0x64,
-  0xB0, 0x0F, 0x45, 0x10, 0x2C, 0xD4, 0x0A, 0x04,
-  0x44, 0x1F, 0x2C, 0xCC, 0x7C, 0xD8, 0x84, 0x0C,
-  0x8C, 0x94, 0xB4, 0x1D, 0x20, 0x5C, 0x18, 0xB4,
-  0x04, 0x09, 0xBC, 0x14, 0xF4, 0x08, 0x54, 0x07,
-  0xFC, 0x6C, 0x24, 0xB4, 0x15, 0x18, 0xDB, 0x17,
-  0x17, 0x18, 0x21, 0x24
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x01, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x06, 0x65,
+    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+    0xc3, 0x59, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x2e, 0x08,
+    0x0a, 0x06, 0x0a, 0x0b, 0x0b, 0x0f, 0x0c, 0x0f,
+    0x3d, 0x09, 0x73, 0x09, 0x0d, 0x0a, 0x10, 0x1e,
+    0x2d, 0x13, 0x86, 0xba, 0x19, 0x0a, 0x36, 0x3c,
+    0x26, 0x14, 0x0d, 0x06, 0x07, 0x0a, 0x0b, 0x0f,
+    0x4a, 0x06, 0x0a, 0x0c, 0x2b, 0x0a, 0x0b, 0x0a,
+    0x06, 0x0a, 0x0a, 0x11, 0x0b, 0x0a, 0x0a, 0x1e,
+    0x0f, 0x0d, 0x0a, 0x0b, 0x22, 0x6a, 0x72, 0x0b,
+    0x0b, 0x22, 0x90, 0xca, 0x90, 0x92, 0x3c, 0x2c,
+    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x8d,
+    0x06, 0x0e, 0x6a, 0x0e, 0x0e, 0x5b, 0x2c, 0x3e,
+    0x0e, 0x0a, 0x5a, 0x0d, 0x0e, 0x3e, 0x0a, 0x06,
+    0x2e, 0x06, 0x4e, 0x36, 0x06, 0x58, 0x24, 0x06,
+    0x3a, 0x08, 0x08, 0x07, 0x5e, 0x45, 0x0a, 0x32,
+    0x2e, 0x2a, 0x43, 0x48, 0x5f, 0x2e, 0x06, 0x06,
+    0x07, 0x24, 0x06, 0x32, 0x06, 0x06, 0x46, 0x2e,
+    0x22, 0x06, 0x06, 0x1e, 0x4c, 0x06, 0x3a, 0x22,
+    0x42, 0x34, 0x42,
 };
 
 unsigned char linux_logo[] __initdata = {
-  0xBC, 0xAC, 0x7D, 0x95, 0xAF, 0x85, 0x2C, 0x2C,
-  0xAC, 0xD9, 0x95, 0x7D, 0x95, 0xAC, 0x2C, 0xAF,
-  0x7D, 0x48, 0xB2, 0xAC, 0x85, 0xDA, 0xDA, 0x2C,
-  0x7D, 0x48, 0x21, 0x2C, 0x8D, 0x2A, 0x8A, 0xDA,
-  0x85, 0x2C, 0xD9, 0xAC, 0x2C, 0x2C, 0xD9, 0xD9,
-  0xAF, 0x85, 0x85, 0x85, 0x8D, 0xBC, 0x2A, 0x2A,
-  0xBC, 0x8C, 0xBC, 0xAC, 0x7D, 0x95, 0xAF, 0x85,
-  0x2C, 0x2C, 0xAC, 0xD9, 0x95, 0x7D, 0x95, 0xAC,
-  0x2C, 0xAF, 0x7D, 0x48, 0xB2, 0xAC, 0x85, 0xDA,
-  0xDA, 0x2C, 0x7D, 0x48, 0x21, 0x2C, 0x8D, 0x2A,
-  0xAF, 0xA1, 0x48, 0x7D, 0xAF, 0x2C, 0x2C, 0xAC,
-  0xD9, 0xD9, 0x95, 0x7D, 0x95, 0xAC, 0xD9, 0x7D,
-  0x48, 0xE9, 0x21, 0xAF, 0xDA, 0xDA, 0x85, 0x2C,
-  0xD9, 0xD9, 0xAC, 0xDA, 0x8A, 0xDA, 0x85, 0x2C,
-  0x2C, 0xAC, 0xD9, 0xAC, 0xAF, 0xAF, 0x2C, 0x2C,
-  0x2C, 0x85, 0x2C, 0x2C, 0x85, 0xDA, 0xDA, 0xDA,
-  0xDA, 0xDA, 0xAF, 0xA1, 0x48, 0x7D, 0xAF, 0x2C,
-  0x2C, 0xAC, 0xD9, 0xD9, 0x95, 0x7D, 0x95, 0xAC,
-  0xD9, 0x7D, 0x48, 0xE9, 0x21, 0xAF, 0xDA, 0xDA,
-  0x85, 0x2C, 0xD9, 0xD9, 0xAC, 0xDA, 0x8A, 0xDA,
-  0x7D, 0x48, 0x48, 0x7D, 0x2C, 0x85, 0x2C, 0xAF,
-  0xD9, 0xD9, 0x7D, 0x95, 0xD9, 0xD9, 0xD9, 0x7D,
-  0xB2, 0x21, 0xD9, 0x85, 0xDA, 0xDA, 0x85, 0x2C,
-  0xAF, 0x2C, 0x2C, 0xDA, 0x85, 0x85, 0x2C, 0x2C,
-  0xAC, 0xD9, 0xD9, 0xAF, 0xDA, 0x85, 0x2C, 0x2C,
-  0x85, 0xDA, 0xDA, 0x85, 0x85, 0xDA, 0x85, 0x85,
-  0x85, 0xAF, 0x7D, 0x48, 0x48, 0x7D, 0x2C, 0x85,
-  0x2C, 0xAF, 0xD9, 0xD9, 0x7D, 0x95, 0xD9, 0xD9,
-  0xD9, 0x7D, 0xB2, 0x21, 0xD9, 0x85, 0xDA, 0xDA,
-  0x85, 0x2C, 0xAF, 0x2C, 0x2C, 0xDA, 0xDA, 0x85,
-  0xA1, 0xE9, 0x48, 0x95, 0x85, 0xDA, 0x85, 0xAF,
-  0xD9, 0xD9, 0x95, 0x95, 0xD9, 0xD9, 0x95, 0x95,
-  0xD9, 0xAC, 0x85, 0x85, 0xDA, 0xDA, 0x85, 0x2C,
-  0xAC, 0xAC, 0x2C, 0x2C, 0x85, 0x2C, 0x2C, 0xAC,
-  0xD9, 0xD9, 0x2C, 0x91, 0x41, 0x20, 0x6B, 0x20,
-  0x6B, 0x20, 0x6B, 0xAE, 0x2C, 0x85, 0x2C, 0x2C,
-  0xAC, 0xD9, 0xA1, 0xE9, 0x48, 0x95, 0x85, 0xDA,
-  0x85, 0xAF, 0xD9, 0xD9, 0x95, 0x95, 0xD9, 0xD9,
-  0x95, 0x95, 0xD9, 0xAC, 0x85, 0x85, 0xDA, 0xDA,
-  0x85, 0x2C, 0xAC, 0xAC, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xA1, 0xA1, 0xD6, 0xAF, 0xDA, 0xDA, 0x85, 0x2C,
-  0xD9, 0xD9, 0x95, 0x95, 0xD9, 0xD9, 0xD9, 0xD9,
-  0x2C, 0x2C, 0xDA, 0xDA, 0xDA, 0x85, 0x2C, 0xD9,
-  0xD9, 0xD9, 0xD9, 0xAC, 0xAC, 0xAC, 0xAF, 0xAC,
-  0x2C, 0xB2, 0x88, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x6B, 0x80, 0x85, 0x2C,
-  0xD9, 0xD6, 0xA1, 0xA1, 0xD6, 0xAF, 0xDA, 0xDA,
-  0x85, 0x2C, 0xD9, 0xD9, 0x95, 0x95, 0xD9, 0xD9,
-  0xD9, 0xD9, 0x2C, 0x2C, 0xDA, 0xDA, 0xDA, 0x85,
-  0x2C, 0xD9, 0xD9, 0xD9, 0xD9, 0xAF, 0xAF, 0xAF,
-  0xD6, 0xD6, 0xD9, 0x2C, 0xDA, 0xDA, 0x2C, 0xAC,
-  0xD9, 0x7D, 0x95, 0xD9, 0xD9, 0xD9, 0xAF, 0x2C,
-  0x85, 0x85, 0x85, 0x85, 0x2C, 0x2C, 0xAC, 0xD9,
-  0xD9, 0xD9, 0xAF, 0xAF, 0x2C, 0x2C, 0xAF, 0xDA,
-  0xAE, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x41, 0xE3, 0x20, 0x6B, 0x48,
-  0xAC, 0x95, 0xD6, 0xD6, 0xD9, 0x2C, 0xDA, 0xDA,
-  0x2C, 0xAC, 0xD9, 0x7D, 0x95, 0xD9, 0xD9, 0xD9,
-  0xAF, 0x2C, 0x85, 0x85, 0x85, 0x85, 0x2C, 0x2C,
-  0xAC, 0xD9, 0xD9, 0xD9, 0xAF, 0xAF, 0xAF, 0xAF,
-  0xD9, 0xD9, 0xD9, 0x2C, 0x85, 0x85, 0x2C, 0xD9,
-  0x7D, 0x21, 0xD6, 0xD9, 0xAF, 0x2C, 0x85, 0x85,
-  0x85, 0x85, 0x85, 0x85, 0x2C, 0xAF, 0xAF, 0xAC,
-  0xAF, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x89,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x74, 0x43, 0x80, 0x41, 0x20,
-  0x9F, 0x2C, 0xD9, 0xD9, 0xD9, 0x2C, 0x85, 0x85,
-  0x2C, 0xD9, 0x7D, 0x21, 0xD6, 0xD9, 0xAF, 0x2C,
-  0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x2C, 0xAF,
-  0xAF, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xD9, 0x7D, 0xD9, 0xAF, 0x85, 0x85, 0x2C, 0xD9,
-  0xB2, 0x21, 0x7D, 0xD9, 0xAF, 0x2C, 0x85, 0x85,
-  0x85, 0x2C, 0x2C, 0x2C, 0x2C, 0xAF, 0xAF, 0xAC,
-  0xAF, 0xAC, 0xAF, 0xAF, 0xAC, 0xAC, 0x85, 0x41,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xAE, 0x48, 0x89, 0x74, 0x41,
-  0x6B, 0xD6, 0xD9, 0x7D, 0xD9, 0xAF, 0x85, 0x85,
-  0x2C, 0xD9, 0xB2, 0x21, 0x7D, 0xD9, 0xAF, 0x2C,
-  0x85, 0x85, 0x85, 0x2C, 0x2C, 0x2C, 0x2C, 0xAF,
-  0xAF, 0xAC, 0xAF, 0xAC, 0xAC, 0x2C, 0xAF, 0xAC,
-  0x2C, 0x7D, 0xD9, 0x2C, 0xDA, 0x85, 0x2C, 0x7D,
-  0xB2, 0xD6, 0xD9, 0xAF, 0x85, 0x85, 0x85, 0x85,
-  0xAF, 0xAC, 0xAC, 0xAF, 0xAF, 0xAC, 0xAC, 0xD9,
-  0x95, 0x7D, 0x95, 0x95, 0xD9, 0xD9, 0x48, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x6B, 0xAE, 0xE6, 0x80, 0x2B, 0x88,
-  0x20, 0x33, 0xDA, 0x95, 0xD9, 0x2C, 0xDA, 0x85,
-  0x2C, 0x7D, 0xB2, 0xD6, 0xD9, 0xAF, 0x85, 0x85,
-  0x85, 0x85, 0xAF, 0xAC, 0xAC, 0xAF, 0xAF, 0xAC,
-  0xAC, 0xD9, 0x95, 0x95, 0x7D, 0x95, 0x95, 0xD9,
-  0x85, 0xD9, 0x2C, 0x85, 0xDA, 0xDA, 0xD9, 0x21,
-  0xA1, 0xD9, 0xAF, 0x2C, 0x85, 0xDA, 0x85, 0xAF,
-  0xD9, 0xD9, 0xAC, 0xAC, 0xAC, 0xD9, 0x7D, 0xD6,
-  0xD6, 0x7D, 0x95, 0xD9, 0xD9, 0x85, 0xDB, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xDB, 0xE3, 0x6B, 0x20, 0x20,
-  0x20, 0x20, 0xE9, 0xD9, 0x2C, 0x85, 0xDA, 0xDA,
-  0xD9, 0x21, 0xA1, 0xD9, 0xAF, 0x2C, 0x85, 0xDA,
-  0x85, 0xAF, 0xD9, 0xD9, 0xAC, 0xAC, 0xAC, 0xD9,
-  0x7D, 0xD6, 0xD6, 0x7D, 0x95, 0xD9, 0xD9, 0xD9,
-  0xDA, 0x2C, 0x85, 0xDA, 0xDA, 0x85, 0x95, 0x21,
-  0x21, 0xD9, 0x85, 0x85, 0x85, 0x2C, 0x2C, 0xD9,
-  0x95, 0x95, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9,
-  0xAC, 0xAC, 0x2C, 0xAF, 0x2C, 0x85, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x88, 0xDA, 0x85, 0xDA, 0xDA, 0x85,
-  0x95, 0x21, 0x21, 0xD9, 0x85, 0x85, 0x85, 0x2C,
-  0x2C, 0xD9, 0x95, 0x95, 0xD9, 0xD9, 0xD9, 0xD9,
-  0xD9, 0xD9, 0xD9, 0xAF, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xDA, 0x2C, 0x85, 0x85, 0x2C, 0xD9, 0xD6, 0xB2,
-  0x95, 0x2C, 0x85, 0x85, 0xAF, 0xAC, 0x95, 0x95,
-  0x7D, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0x2C, 0x85,
-  0x85, 0x85, 0x85, 0x85, 0x85, 0xAC, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xAC, 0x85, 0x85, 0x2C, 0xD9,
-  0xD6, 0xB2, 0x95, 0x2C, 0x85, 0x85, 0xAF, 0xAC,
-  0x95, 0x95, 0x7D, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9,
-  0x2C, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
-  0x85, 0x2C, 0x2C, 0x2C, 0xAC, 0x95, 0xD6, 0x7D,
-  0xD9, 0x2C, 0x2C, 0xAF, 0x95, 0x7D, 0x7D, 0x95,
-  0x95, 0xD9, 0xD9, 0x95, 0xD9, 0xD9, 0x2C, 0x85,
-  0xDA, 0xDA, 0xDA, 0x85, 0x85, 0x21, 0x20, 0x20,
-  0x6B, 0x41, 0xDB, 0x6B, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x41, 0xDB, 0xDB, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xE6, 0x2C, 0x2C, 0xAC, 0x95,
-  0xD6, 0x7D, 0xD9, 0x2C, 0x2C, 0xAF, 0x95, 0x7D,
-  0x7D, 0x95, 0x95, 0xD9, 0xD9, 0x95, 0xD9, 0xD9,
-  0x2C, 0x85, 0xDA, 0xDA, 0xDA, 0x85, 0x2C, 0x2C,
-  0x2C, 0xAF, 0xAC, 0xD9, 0x95, 0xD6, 0xD6, 0xD9,
-  0x2C, 0x2C, 0x2C, 0xD9, 0xD6, 0xD6, 0xD9, 0xAF,
-  0xAC, 0x95, 0xD6, 0x7D, 0x7D, 0xD9, 0x2C, 0x85,
-  0xDA, 0xDA, 0x2C, 0xAF, 0xAF, 0x21, 0x20, 0x20,
-  0x88, 0x2B, 0x88, 0x74, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0xAE, 0x2D, 0x2D, 0x74, 0x74, 0x88, 0x20,
-  0x20, 0x20, 0x20, 0x80, 0xAC, 0xD9, 0x95, 0xD6,
-  0xD6, 0xD9, 0x2C, 0x2C, 0x2C, 0xD9, 0xD6, 0xD6,
-  0xD9, 0xAF, 0xAC, 0x95, 0xD6, 0x7D, 0x7D, 0xD9,
-  0x2C, 0xDA, 0xDA, 0x85, 0x2C, 0xAF, 0xAF, 0xAF,
-  0x2C, 0xAF, 0xD9, 0x95, 0xD6, 0xD6, 0x95, 0xAF,
-  0x2C, 0x2C, 0xD9, 0x95, 0xD6, 0x95, 0xAF, 0x2C,
-  0xAC, 0x7D, 0x21, 0x95, 0xD9, 0x2C, 0x85, 0x85,
-  0x85, 0xAF, 0xD9, 0x95, 0xD9, 0x7D, 0x20, 0x33,
-  0x7D, 0x8A, 0x7D, 0x5B, 0x6B, 0x20, 0x20, 0x6B,
-  0xE6, 0xD9, 0x85, 0x2A, 0xDA, 0x2B, 0x41, 0x20,
-  0x20, 0x20, 0x6B, 0x74, 0xD9, 0x95, 0xD6, 0xD6,
-  0x95, 0xAF, 0x2C, 0x2C, 0xD9, 0x95, 0xD6, 0x95,
-  0xAF, 0x2C, 0xAC, 0x7D, 0x21, 0x95, 0xD9, 0x2C,
-  0x85, 0x85, 0x85, 0x2C, 0xD9, 0xD9, 0xD9, 0xD9,
-  0x85, 0xD9, 0x7D, 0x21, 0x21, 0x7D, 0xAC, 0x2C,
-  0x2C, 0xAC, 0xD9, 0x7D, 0xD9, 0xAF, 0x2C, 0x85,
-  0xAC, 0x7D, 0x7D, 0xAC, 0x85, 0xDA, 0x8A, 0xDA,
-  0x85, 0xAF, 0xD9, 0x7D, 0xD9, 0x95, 0x20, 0x91,
-  0xBC, 0x73, 0xEE, 0x7D, 0x20, 0x20, 0x20, 0x80,
-  0x4D, 0x3D, 0x73, 0x73, 0xA3, 0xD6, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x2B, 0x7D, 0x21, 0x21, 0x7D,
-  0xAC, 0x2C, 0x2C, 0xAC, 0xD9, 0x7D, 0xD9, 0xAF,
-  0x2C, 0x85, 0xAC, 0x7D, 0x7D, 0xAC, 0x85, 0xDA,
-  0x8A, 0x8A, 0x85, 0xAC, 0xD9, 0x7D, 0xD9, 0xAC,
-  0x2C, 0xD9, 0xD6, 0xB2, 0xB2, 0x7D, 0xAF, 0x85,
-  0x2C, 0xD9, 0x95, 0x95, 0xAF, 0x2C, 0x2C, 0x2C,
-  0xD9, 0xD9, 0xAC, 0x85, 0x8D, 0x2A, 0x2A, 0xDA,
-  0xAF, 0xD9, 0x95, 0x95, 0xD9, 0xAC, 0x20, 0xAF,
-  0x2C, 0xE6, 0x8D, 0x73, 0xE3, 0x20, 0x20, 0x48,
-  0x5C, 0xDA, 0x5B, 0x43, 0xBC, 0x73, 0x2B, 0x20,
-  0x20, 0x20, 0x20, 0x41, 0xD6, 0xB2, 0xB2, 0x7D,
-  0xAF, 0x85, 0x2C, 0xD9, 0x95, 0x95, 0xAF, 0x2C,
-  0x2C, 0x2C, 0xD9, 0xD9, 0xAC, 0x85, 0x8A, 0x2A,
-  0x8D, 0xDA, 0xAF, 0xD9, 0x95, 0x95, 0xD9, 0xAF,
-  0xAC, 0xD9, 0xD6, 0xB2, 0x21, 0xD9, 0x2C, 0x85,
-  0x2C, 0xD9, 0x95, 0xD9, 0xAF, 0x2C, 0x2C, 0xAC,
-  0xAC, 0xAF, 0x85, 0x8D, 0xBC, 0xBC, 0xDA, 0xD9,
-  0xD6, 0xA1, 0xA1, 0x21, 0xD9, 0xAC, 0x20, 0x2A,
-  0xCC, 0xAE, 0x9F, 0xE4, 0xAE, 0x5B, 0x74, 0xA1,
-  0xE4, 0xAE, 0x20, 0x9F, 0x89, 0xE8, 0xE6, 0x20,
-  0x20, 0x20, 0x20, 0x41, 0xD6, 0xB2, 0x21, 0xD9,
-  0x2C, 0x85, 0x2C, 0xD9, 0x95, 0xD9, 0xAF, 0x2C,
-  0x2C, 0xAC, 0xAC, 0xAF, 0x85, 0x8D, 0xBC, 0x2A,
-  0xDA, 0xD9, 0xD6, 0xA1, 0xA1, 0x21, 0xD9, 0xD9,
-  0xD9, 0x95, 0x21, 0xA1, 0x21, 0xAC, 0x85, 0x85,
-  0xAC, 0xD9, 0xD9, 0xAF, 0x2C, 0x2C, 0xAF, 0xAC,
-  0xAF, 0x85, 0x8A, 0x2A, 0x2A, 0xDA, 0xD9, 0xA1,
-  0x48, 0xE9, 0x48, 0x21, 0x95, 0xAC, 0x20, 0x2A,
-  0xDB, 0x41, 0x74, 0xBC, 0x2B, 0x7B, 0x7B, 0x80,
-  0x73, 0x41, 0x20, 0x6B, 0x2B, 0xE8, 0x2D, 0x20,
-  0x20, 0x20, 0x20, 0x33, 0x21, 0xA1, 0x21, 0xAC,
-  0x85, 0x85, 0xAC, 0xD9, 0xD9, 0xAF, 0x2C, 0x2C,
-  0xAF, 0xAC, 0xAF, 0x85, 0x8A, 0xBC, 0x2A, 0xDA,
-  0xD9, 0xA1, 0x48, 0xE9, 0x48, 0x21, 0xD9, 0xD9,
-  0xA1, 0xB2, 0xB2, 0x48, 0xD6, 0xAC, 0x2C, 0x2C,
-  0xD9, 0x95, 0xAF, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C,
-  0x85, 0x8A, 0x8D, 0x8D, 0x85, 0x95, 0xA1, 0x6C,
-  0x6C, 0x48, 0xD6, 0xD9, 0x2C, 0x85, 0x20, 0x2C,
-  0x89, 0x20, 0x3C, 0xB9, 0xA7, 0x63, 0xD2, 0xB9,
-  0xC6, 0x9A, 0x20, 0x20, 0x43, 0x5C, 0xE6, 0x20,
-  0x20, 0x20, 0x20, 0x33, 0xB2, 0x48, 0xD6, 0xAC,
-  0x2C, 0x2C, 0xD9, 0x95, 0xAF, 0x2C, 0x2C, 0x2C,
-  0x2C, 0x2C, 0x85, 0x8A, 0x8D, 0x8D, 0x85, 0x95,
-  0xA1, 0x6C, 0x6C, 0x48, 0xD6, 0xD9, 0xAF, 0xAC,
-  0xA1, 0xD6, 0x7D, 0xB2, 0xD6, 0xAF, 0x85, 0x85,
-  0xD9, 0x95, 0x2C, 0x85, 0xDA, 0x85, 0x85, 0x2C,
-  0x85, 0x8A, 0x8D, 0xDA, 0xD9, 0x48, 0x81, 0x2D,
-  0x48, 0xD6, 0xD9, 0xAC, 0x2C, 0x85, 0x20, 0x2D,
-  0xEE, 0x93, 0xD1, 0xA7, 0x3E, 0x3E, 0x3A, 0x25,
-  0x56, 0xAB, 0xAA, 0xC5, 0xEE, 0xEE, 0x33, 0x20,
-  0x20, 0x20, 0x20, 0x41, 0xD9, 0xB2, 0xD6, 0xAF,
-  0x85, 0x85, 0xD9, 0x95, 0x2C, 0x85, 0xDA, 0x85,
-  0x85, 0x2C, 0x85, 0x8A, 0x8D, 0xDA, 0xD9, 0x48,
-  0x81, 0x2D, 0x48, 0xD6, 0xD9, 0xAF, 0x2C, 0x2C,
-  0xAC, 0xAF, 0xD9, 0x7D, 0xD6, 0x2C, 0x85, 0x2C,
-  0xD9, 0xD9, 0x2C, 0xDA, 0xDA, 0xDA, 0x2C, 0x2C,
-  0x85, 0x8D, 0x8D, 0x2C, 0x21, 0x2D, 0x2D, 0xE9,
-  0xD6, 0xD9, 0xAF, 0x2C, 0x85, 0xDA, 0x20, 0xE3,
-  0xB4, 0xBE, 0xF1, 0x3E, 0x9B, 0x22, 0x56, 0xF2,
-  0xBB, 0x7F, 0x56, 0xDC, 0x8F, 0x5A, 0x5F, 0x20,
-  0x20, 0x20, 0x20, 0x6B, 0x2C, 0x7D, 0xD6, 0x2C,
-  0x85, 0x2C, 0xD9, 0xD9, 0x2C, 0xDA, 0xDA, 0xDA,
-  0x2C, 0x2C, 0x85, 0x8D, 0x8A, 0x85, 0x21, 0x2D,
-  0x2D, 0xE9, 0xD6, 0xD9, 0xAF, 0x2C, 0x85, 0x85,
-  0x2A, 0x85, 0xAC, 0x95, 0x95, 0x2C, 0x85, 0x85,
-  0xAC, 0xAF, 0x85, 0xDA, 0xDA, 0x85, 0x2C, 0x2C,
-  0xDA, 0x8A, 0x8A, 0xAF, 0xA1, 0x2D, 0xE9, 0xD6,
-  0xD9, 0xAC, 0x85, 0x85, 0x85, 0xDA, 0x20, 0x52,
-  0x55, 0xED, 0x57, 0x3E, 0x22, 0x56, 0x37, 0xBB,
-  0xBB, 0x58, 0x7F, 0x7F, 0x56, 0x5E, 0xC5, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x2C, 0x95, 0x95, 0x2C,
-  0x85, 0x85, 0xAC, 0xAF, 0x85, 0xDA, 0xDA, 0x85,
-  0x2C, 0x2C, 0xDA, 0x8D, 0xDA, 0xAF, 0xA1, 0x2D,
-  0xE9, 0xD6, 0xD9, 0xAF, 0x2C, 0x85, 0x85, 0x85,
-  0xCD, 0xAF, 0xD9, 0x95, 0xD9, 0x2C, 0xDA, 0x85,
-  0xAF, 0xD9, 0x85, 0xDA, 0x85, 0x2C, 0xAC, 0xAF,
-  0x85, 0x8A, 0x85, 0xD9, 0x48, 0x48, 0xB2, 0x95,
-  0x95, 0xAC, 0x2C, 0x85, 0xDA, 0xDA, 0x6B, 0xB3,
-  0x46, 0x7C, 0x2E, 0x9B, 0x22, 0x56, 0xBB, 0x37,
-  0x58, 0x58, 0xF2, 0x3A, 0x46, 0x63, 0x64, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x2D, 0x95, 0xD9, 0x2C,
-  0xDA, 0x85, 0xAF, 0xD9, 0x85, 0xDA, 0x85, 0x2C,
-  0xAC, 0xAF, 0x85, 0xDA, 0x85, 0xD9, 0x48, 0x48,
-  0xB2, 0x95, 0x95, 0xD9, 0x85, 0xDA, 0x85, 0x85,
-  0xBC, 0xB2, 0xB2, 0x7D, 0xD9, 0x2C, 0xDA, 0x85,
-  0xAF, 0xD9, 0x85, 0xDA, 0x85, 0x85, 0xAF, 0x2C,
-  0x85, 0xDA, 0x2C, 0x7D, 0xA1, 0x48, 0xB2, 0x21,
-  0xD6, 0xD9, 0x85, 0xDA, 0x85, 0xDA, 0x41, 0x51,
-  0xB7, 0xEC, 0x2E, 0x22, 0x56, 0x37, 0xBB, 0xF2,
-  0x37, 0xEA, 0x2F, 0x2F, 0x77, 0xA7, 0x38, 0x20,
-  0x20, 0x6B, 0x20, 0x20, 0x5B, 0x2C, 0xD9, 0x2C,
-  0xDA, 0x85, 0xAF, 0xD9, 0x85, 0xDA, 0x85, 0x85,
-  0xAF, 0x2C, 0xDA, 0xDA, 0x2C, 0x7D, 0xA1, 0x48,
-  0xB2, 0x21, 0xD6, 0xD9, 0x2C, 0xDA, 0x85, 0xAF,
-  0x2C, 0x2D, 0x48, 0x7D, 0xAF, 0x2C, 0x85, 0x2C,
-  0xD9, 0xAC, 0xAF, 0x85, 0x85, 0x2C, 0x2C, 0x2C,
-  0x85, 0x2C, 0xD9, 0xD6, 0xA1, 0xA1, 0x48, 0xA1,
-  0x21, 0x2C, 0xDA, 0xDA, 0x2C, 0x85, 0x41, 0x98,
-  0xA2, 0xA7, 0x6F, 0xC9, 0x37, 0xF2, 0xF2, 0x9B,
-  0xB7, 0x66, 0x60, 0x4C, 0xED, 0x84, 0x3C, 0x20,
-  0x5B, 0x2D, 0x2B, 0x6B, 0x20, 0xAF, 0xAF, 0x2C,
-  0x85, 0x2C, 0xD9, 0xAC, 0xAF, 0x85, 0x85, 0x2C,
-  0x2C, 0x2C, 0x2C, 0x85, 0xD9, 0xD6, 0xA1, 0xA1,
-  0x48, 0xA1, 0xD6, 0xAF, 0xDA, 0x8A, 0x2C, 0xD9,
-  0xB2, 0x2D, 0x48, 0x95, 0x2C, 0x2C, 0x2C, 0x85,
-  0xAC, 0xAC, 0xAF, 0x85, 0xDA, 0x85, 0xAF, 0xAC,
-  0xAF, 0x2C, 0xD9, 0xD6, 0xD6, 0xD6, 0x21, 0xD6,
-  0xD9, 0xDA, 0x8D, 0xDA, 0xAF, 0x2C, 0x20, 0x88,
-  0x42, 0x51, 0x3F, 0x2F, 0x45, 0xB7, 0x66, 0x55,
-  0x46, 0x60, 0x5D, 0x36, 0xD8, 0x71, 0x43, 0x20,
-  0x20, 0x2D, 0xB2, 0x80, 0x20, 0x2D, 0x2C, 0x2C,
-  0x2C, 0x85, 0xAC, 0xAC, 0xAF, 0x85, 0xDA, 0x85,
-  0xAF, 0xAC, 0xAC, 0xAF, 0xD9, 0xD6, 0xD6, 0xD6,
-  0x21, 0xD6, 0xD9, 0xDA, 0x8D, 0x8A, 0x2C, 0xD9,
-  0xB2, 0x48, 0xD6, 0xAC, 0xAF, 0x2C, 0x2C, 0x85,
-  0x2C, 0xAC, 0x2C, 0xDA, 0xDA, 0x85, 0xAF, 0xD9,
-  0xD9, 0xAC, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xAC,
-  0x85, 0x8D, 0xBC, 0xDA, 0xD9, 0xDA, 0x20, 0xE3,
-  0xDA, 0x69, 0x96, 0xB5, 0xF1, 0x68, 0x5D, 0x82,
-  0xE1, 0xBE, 0x27, 0x8D, 0x4D, 0xD3, 0x7D, 0x20,
-  0x20, 0xDB, 0xA1, 0xCA, 0x20, 0x88, 0x85, 0x2C,
-  0x2C, 0x85, 0x2C, 0xAC, 0x2C, 0xDA, 0xDA, 0x85,
-  0xAF, 0xD9, 0xAC, 0xAF, 0xD9, 0xD9, 0xD9, 0xD9,
-  0xD9, 0xAC, 0xDA, 0x8D, 0xBC, 0xDA, 0xD9, 0x95,
-  0xD9, 0x95, 0xAC, 0x2C, 0x2C, 0x2C, 0x2C, 0x85,
-  0x85, 0xAF, 0xAF, 0x85, 0x85, 0x2C, 0x2C, 0xAC,
-  0xD9, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C, 0x2C, 0x85,
-  0x8D, 0x2A, 0x2A, 0x85, 0xD9, 0x95, 0x20, 0xDB,
-  0x8D, 0x8D, 0x99, 0xB0, 0x35, 0xE5, 0x3F, 0x35,
-  0xB9, 0x50, 0x8A, 0x4D, 0x73, 0xE8, 0xA3, 0xCC,
-  0x20, 0x20, 0x33, 0x6B, 0x20, 0x20, 0xCC, 0x85,
-  0x2C, 0x85, 0x85, 0xAF, 0xAF, 0x85, 0x85, 0x85,
-  0x2C, 0xD9, 0xD9, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C,
-  0x2C, 0x85, 0x8A, 0x2A, 0x8D, 0x2C, 0xD9, 0xD9,
-  0xAF, 0xAF, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C, 0x85,
-  0x2C, 0xAF, 0xAF, 0xAF, 0x2C, 0x2C, 0x2C, 0xAC,
-  0xD9, 0xAC, 0xAF, 0x2C, 0x85, 0x85, 0xDA, 0xDA,
-  0x8A, 0x8A, 0x85, 0xD9, 0x2C, 0x2B, 0x20, 0xAE,
-  0xA3, 0xBC, 0x8D, 0xC8, 0xA9, 0xC7, 0x92, 0x47,
-  0x8D, 0x8D, 0x7E, 0xE4, 0xE8, 0xE8, 0x5C, 0x2C,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6B, 0xAF,
-  0x2C, 0x85, 0x2C, 0xAF, 0xAF, 0xAF, 0x2C, 0x2C,
-  0x2C, 0xAF, 0xD9, 0xAC, 0x2C, 0x2C, 0x85, 0x85,
-  0x85, 0xDA, 0x8D, 0x8A, 0x85, 0xAC, 0x95, 0xD9,
-  0xAC, 0xAC, 0xAC, 0xAC, 0x2C, 0xAF, 0xAF, 0x2C,
-  0x2C, 0xAF, 0xAF, 0xAC, 0x2C, 0xAF, 0x2C, 0xAF,
-  0xD9, 0xAC, 0x2C, 0x2C, 0x85, 0x85, 0x85, 0x85,
-  0x85, 0x2C, 0xD9, 0xD9, 0x2D, 0x6B, 0x41, 0x2A,
-  0xE8, 0xA3, 0xC8, 0x8D, 0x8A, 0x8A, 0x8A, 0x8D,
-  0x4D, 0xA3, 0x3D, 0xE8, 0xE8, 0xE8, 0xE8, 0x5C,
-  0xAE, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xDB,
-  0xDA, 0x2C, 0x2C, 0xAF, 0xAF, 0xAC, 0xAC, 0xAF,
-  0x2C, 0xAC, 0xD9, 0xAC, 0x2C, 0x2C, 0x85, 0x85,
-  0x85, 0x85, 0x85, 0x2C, 0xD9, 0x95, 0x7D, 0xD9,
-  0x7D, 0x7D, 0xD9, 0xAC, 0xAC, 0xAF, 0xAF, 0xAF,
-  0x2C, 0x2C, 0xAC, 0xAC, 0xD9, 0xAC, 0xAC, 0xD9,
-  0x95, 0xD9, 0xAC, 0xAF, 0xAF, 0xAC, 0xAF, 0xAC,
-  0xD9, 0x7D, 0x7D, 0x7D, 0x33, 0x41, 0x2D, 0xE8,
-  0xE8, 0x5C, 0xD3, 0x8D, 0x8D, 0x8D, 0x8D, 0x7E,
-  0x3D, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xDA, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x81, 0x2C, 0x2C, 0x2C, 0xAC, 0xAC, 0xAC, 0xAC,
-  0xAC, 0xD9, 0x95, 0x95, 0xAC, 0xAF, 0xAF, 0xAF,
-  0xAF, 0xAC, 0xD9, 0x95, 0x7D, 0xD6, 0xD6, 0x7D,
-  0x21, 0xD6, 0x95, 0xD9, 0xD9, 0xAC, 0xAF, 0xAF,
-  0x2C, 0xAF, 0xAC, 0xAC, 0xD9, 0xD9, 0xD9, 0xD9,
-  0x21, 0x21, 0x7D, 0x95, 0x95, 0x7D, 0xD6, 0x21,
-  0xB2, 0xA1, 0x2C, 0x88, 0x20, 0xE3, 0xA3, 0xE8,
-  0xE8, 0xE8, 0xE4, 0xEE, 0xD3, 0x7E, 0x73, 0x5C,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0x5C, 0x2B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x2C, 0xAF, 0xAF, 0xAC, 0xD9, 0xD9, 0xD9,
-  0xD9, 0xD9, 0xD6, 0x21, 0x7D, 0x95, 0x95, 0x7D,
-  0xD6, 0xB2, 0xA1, 0xA1, 0xB2, 0xD6, 0x21, 0x21,
-  0x21, 0xD9, 0xD9, 0xD9, 0xAC, 0xAF, 0xAC, 0xAF,
-  0x2C, 0x2C, 0xAC, 0xD9, 0xD9, 0xD9, 0xD9, 0x95,
-  0x7D, 0xB2, 0xD6, 0x95, 0xD9, 0x95, 0xD6, 0xA1,
-  0xA1, 0xAF, 0x5B, 0x20, 0x20, 0xD6, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE8, 0x5C, 0xE8, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE8, 0x48, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0xE3, 0x8A, 0x2C, 0xAC, 0xAC, 0xD9, 0xD9,
-  0xD9, 0x95, 0xD6, 0xB2, 0xD6, 0x95, 0xD9, 0x95,
-  0x21, 0xB2, 0xA1, 0xB2, 0xD6, 0xD6, 0xD6, 0xA1,
-  0xD9, 0x2C, 0x2C, 0x2C, 0xAF, 0xAF, 0xAC, 0xAF,
-  0x2C, 0x2C, 0xAF, 0xAC, 0xD9, 0xAC, 0xD9, 0xD9,
-  0xD9, 0x95, 0xAC, 0x2C, 0x2C, 0xAC, 0x95, 0x7D,
-  0xD9, 0x91, 0x20, 0x20, 0xE3, 0xA3, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE8, 0x85, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x2B, 0x8A, 0xAF, 0xAC, 0xD9, 0xAC,
-  0xD9, 0xD9, 0xD9, 0x95, 0xAC, 0x2C, 0x2C, 0xAC,
-  0x95, 0x7D, 0x95, 0x95, 0xD9, 0x95, 0x7D, 0x21,
-  0x2C, 0xDA, 0xDA, 0x85, 0x2C, 0xAF, 0xAF, 0xAF,
-  0xAF, 0xAF, 0x2C, 0xAF, 0xAF, 0xAC, 0xAC, 0xAC,
-  0xD9, 0xAF, 0x85, 0x85, 0x2C, 0xAF, 0xD9, 0xAF,
-  0x48, 0x20, 0x20, 0x20, 0xE6, 0xA3, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0x5C,
-  0xE4, 0x73, 0x41, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x2B, 0xDA, 0xAF, 0xAF, 0xAC,
-  0xAC, 0xAF, 0xD9, 0x2C, 0x85, 0x85, 0x2C, 0xAF,
-  0xD9, 0xD9, 0xAC, 0xAF, 0xAC, 0xD9, 0xD9, 0xD9,
-  0x85, 0xDA, 0xDA, 0x85, 0x2C, 0x2C, 0xAC, 0xAF,
-  0xAF, 0xAF, 0xAF, 0x2C, 0xAF, 0xAF, 0xAC, 0xAC,
-  0xAF, 0x2C, 0x2C, 0x2C, 0xAC, 0x95, 0x95, 0xA1,
-  0x20, 0x20, 0x20, 0x20, 0xE9, 0x8C, 0x5C, 0xE8,
-  0xE8, 0xE8, 0xE8, 0x3D, 0x73, 0x73, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE4, 0x73, 0x73, 0x73, 0xCD,
-  0x7E, 0xA3, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x24, 0x85, 0xAF, 0xAF,
-  0xAC, 0xAC, 0xAC, 0xAF, 0x85, 0x2C, 0xAC, 0x95,
-  0x95, 0xD9, 0xAC, 0xAC, 0xAC, 0xD9, 0xAC, 0xAF,
-  0x8A, 0x8A, 0xDA, 0xDA, 0x85, 0x2C, 0x2C, 0x2C,
-  0x2C, 0x2C, 0x2C, 0xAF, 0xAF, 0xAC, 0xAF, 0xAC,
-  0xAC, 0xAF, 0xAF, 0xD9, 0xD6, 0xD6, 0x2C, 0x88,
-  0x20, 0x20, 0x20, 0x88, 0xB2, 0xDA, 0x7E, 0x73,
-  0xE8, 0xE8, 0xE8, 0x3D, 0x73, 0xE8, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xA3, 0xCD, 0xD3, 0x2A, 0x2A,
-  0x2A, 0x8C, 0x8D, 0x88, 0x20, 0xE3, 0x6B, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x41, 0x85, 0xAF, 0xAC,
-  0xAC, 0xAC, 0xAC, 0xAF, 0xAC, 0xD9, 0x7D, 0xD6,
-  0x7D, 0x7D, 0xD9, 0x95, 0xD9, 0xAC, 0xAC, 0xAF,
-  0xD3, 0x8D, 0xDA, 0xDA, 0x85, 0x85, 0x2C, 0x2C,
-  0x2C, 0xAF, 0xAF, 0xAC, 0xD9, 0xD9, 0xD9, 0xD9,
-  0xAF, 0xAF, 0xAC, 0xD9, 0x95, 0x7D, 0xAC, 0x20,
-  0x20, 0x20, 0x20, 0xDB, 0x2C, 0xA3, 0x5C, 0xE8,
-  0xE8, 0xE8, 0xE8, 0x5C, 0x3D, 0x3D, 0xE8, 0xE8,
-  0xE8, 0xE4, 0xE8, 0xE8, 0xE8, 0xE4, 0x73, 0xEE,
-  0xD3, 0x2A, 0xEE, 0xAC, 0x20, 0x33, 0x2B, 0xE3,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x9F, 0xAF, 0xD9,
-  0xD9, 0xAC, 0xAF, 0xAF, 0xAC, 0xD9, 0x95, 0x7D,
-  0xD9, 0x95, 0x95, 0x95, 0x95, 0xD9, 0xAF, 0xAF,
-  0x7E, 0x85, 0x85, 0x2C, 0x85, 0x85, 0x85, 0x2C,
-  0x2C, 0x2C, 0xAF, 0xD9, 0xD9, 0x95, 0xD9, 0xAC,
-  0xAC, 0xAF, 0xAF, 0xAC, 0xAC, 0xAC, 0x91, 0x20,
-  0x33, 0xE3, 0x41, 0x48, 0x73, 0x5C, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xA3, 0xD6, 0x6C, 0x85, 0xE8,
-  0xDA, 0xAE, 0xB2, 0xA3, 0x5C, 0xE8, 0xE8, 0xE8,
-  0x3D, 0xEE, 0x4D, 0xA3, 0x24, 0x20, 0x6B, 0xDB,
-  0x2B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x85, 0x95,
-  0xD9, 0xD9, 0xAC, 0xAF, 0xAF, 0xAC, 0xD9, 0xAC,
-  0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xAC, 0xD9, 0xAC,
-  0x8A, 0xD9, 0xAC, 0xD9, 0xAC, 0xAC, 0x2C, 0x2C,
-  0xAF, 0xAF, 0xAF, 0xAC, 0xD9, 0xD9, 0xD9, 0xD9,
-  0xAF, 0xAF, 0xAF, 0xAC, 0xAC, 0x85, 0x33, 0x20,
-  0xCC, 0x20, 0xE3, 0xA3, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE8, 0xA3, 0xD9, 0x81, 0xAC, 0xDA, 0x2D, 0x5C,
-  0x48, 0x41, 0x88, 0x74, 0x21, 0xA3, 0xE8, 0xE8,
-  0xE8, 0xE8, 0x73, 0x8C, 0x8A, 0x20, 0x20, 0x20,
-  0xDB, 0x33, 0x20, 0x20, 0x20, 0x20, 0xE6, 0xD9,
-  0xD9, 0xAC, 0xAC, 0xAF, 0xAC, 0xAF, 0xAC, 0xAF,
-  0xAF, 0xAC, 0xD9, 0xAF, 0xD9, 0xAC, 0xAC, 0xAF,
-  0x85, 0xD9, 0x95, 0xD9, 0x95, 0xD9, 0xD9, 0xAC,
-  0xAF, 0xAC, 0xAF, 0xAF, 0x2C, 0xAF, 0x2C, 0x2C,
-  0xAF, 0xAF, 0xAF, 0xAC, 0xAC, 0x2C, 0x20, 0x5B,
-  0x33, 0x20, 0xD6, 0xE8, 0xE8, 0xE8, 0xE8, 0x73,
-  0xAF, 0x2D, 0xD9, 0xDA, 0xB2, 0x81, 0x81, 0xE4,
-  0xA1, 0x91, 0x2B, 0x88, 0x33, 0x80, 0xAF, 0x73,
-  0xE8, 0xE8, 0xE8, 0x5C, 0xA3, 0x80, 0x41, 0xCC,
-  0x2B, 0xCC, 0x20, 0x20, 0x20, 0x20, 0x88, 0xDA,
-  0x2C, 0x2C, 0x2C, 0xAF, 0xAF, 0xAC, 0xAC, 0xAF,
-  0xAF, 0xAF, 0xAF, 0xAC, 0xAF, 0xAF, 0xAF, 0x2C,
-  0x85, 0xD9, 0xD9, 0xD9, 0xD9, 0xAC, 0xAC, 0xD9,
-  0xD9, 0xD9, 0xAC, 0x2C, 0x2C, 0x2C, 0x85, 0x85,
-  0x85, 0x2C, 0x2C, 0xAF, 0x2C, 0x91, 0x20, 0xAE,
-  0x20, 0xDB, 0x3D, 0xE8, 0xE8, 0x5C, 0xB2, 0x80,
-  0xB2, 0xAF, 0x48, 0xB2, 0x48, 0x89, 0x89, 0x3D,
-  0x21, 0x48, 0x6C, 0x2D, 0x2B, 0x41, 0xE3, 0xAE,
-  0xD9, 0x5C, 0xE8, 0xE8, 0xE8, 0x95, 0x33, 0x80,
-  0xAE, 0x33, 0x2B, 0x20, 0x20, 0x20, 0x20, 0x95,
-  0x85, 0x2C, 0x85, 0x2C, 0x2C, 0xAF, 0x2C, 0x2C,
-  0x2C, 0xAF, 0xAC, 0xAF, 0xAF, 0x2C, 0x2C, 0x2C,
-  0xDA, 0xAF, 0xD9, 0xD9, 0xAF, 0x2C, 0x2C, 0x2C,
-  0xAC, 0xD9, 0xAC, 0xAF, 0x2C, 0x85, 0x2C, 0x85,
-  0x85, 0x2C, 0x2C, 0x2C, 0x8A, 0x41, 0xDB, 0x33,
-  0x20, 0x95, 0xE8, 0xE8, 0xE8, 0xA3, 0xDB, 0x88,
-  0xDB, 0x80, 0xD6, 0x7E, 0x85, 0x2D, 0xE6, 0x5C,
-  0x21, 0x48, 0xD9, 0x7E, 0xD6, 0x2B, 0xCC, 0xAC,
-  0x85, 0xBC, 0xE8, 0xE8, 0xE8, 0xCD, 0x88, 0x5B,
-  0x41, 0x20, 0xAE, 0x20, 0x20, 0x20, 0x20, 0x74,
-  0xDA, 0x85, 0x85, 0x85, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xAF, 0xAC, 0xD9, 0xD9, 0xAC, 0xAC, 0xAC, 0xD9,
-  0x8A, 0xAF, 0xAC, 0xAC, 0x2C, 0x85, 0x2C, 0xAF,
-  0xD9, 0xD9, 0xAF, 0xAF, 0xAF, 0x2C, 0xAF, 0x2C,
-  0x2C, 0x2C, 0x2C, 0xAF, 0x95, 0x20, 0x74, 0x20,
-  0x33, 0xA3, 0xE8, 0xE8, 0xE8, 0xE4, 0x7D, 0xCC,
-  0x6B, 0x33, 0xAE, 0x2C, 0x85, 0x2D, 0x9F, 0x73,
-  0xA1, 0x2D, 0x2C, 0xDA, 0x89, 0x48, 0xD3, 0xD9,
-  0x21, 0xA3, 0xE8, 0xE8, 0xE8, 0xE8, 0xE3, 0x20,
-  0x20, 0x20, 0xDB, 0x41, 0x20, 0x20, 0x20, 0x20,
-  0xDA, 0x2C, 0x2C, 0x2C, 0x2C, 0xAF, 0xAC, 0xAC,
-  0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0x95, 0x95, 0xD9,
-  0x2C, 0xD9, 0xD9, 0xAC, 0x2C, 0x2C, 0x85, 0xAF,
-  0xAF, 0xAF, 0xAC, 0xAC, 0xD9, 0xAC, 0xAF, 0xAC,
-  0xAC, 0x95, 0xD6, 0x7D, 0xAE, 0x88, 0x2B, 0x20,
-  0x6C, 0xE8, 0xE8, 0xE8, 0x73, 0xEE, 0x73, 0x2C,
-  0x89, 0x2B, 0x41, 0x33, 0xCC, 0xCC, 0x80, 0x3D,
-  0x2D, 0x74, 0x80, 0x48, 0x8D, 0x95, 0x48, 0x95,
-  0xEE, 0x5C, 0x5C, 0xE8, 0xE8, 0xE8, 0x24, 0x20,
-  0x20, 0x20, 0x5B, 0xDB, 0x20, 0x20, 0x20, 0x20,
-  0xAF, 0xAC, 0xD9, 0x95, 0xD6, 0xD6, 0xD6, 0x7D,
-  0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0xD9, 0xAC,
-  0xAC, 0xD9, 0xD9, 0xAC, 0x2C, 0x2C, 0x2C, 0xAF,
-  0xAC, 0xAC, 0xAC, 0xAC, 0xD9, 0xAC, 0xAC, 0xD9,
-  0xD6, 0x48, 0xE9, 0x95, 0x20, 0x2B, 0x41, 0x6B,
-  0x8D, 0xE8, 0xE8, 0xCD, 0x2B, 0x2B, 0x2C, 0x73,
-  0xCD, 0x48, 0xCA, 0x5B, 0x41, 0x5B, 0x74, 0xDA,
-  0x80, 0xE6, 0xC8, 0x85, 0xA1, 0x7D, 0x8D, 0x3D,
-  0x7E, 0xE9, 0x7D, 0xEE, 0xE8, 0xE8, 0x81, 0x20,
-  0x20, 0x20, 0xE3, 0xE3, 0x20, 0x20, 0x20, 0x20,
-  0x2D, 0xD9, 0xD6, 0x48, 0x6C, 0xE9, 0xA1, 0xD6,
-  0xD9, 0xD9, 0xAC, 0xD9, 0xD9, 0x95, 0xAC, 0x2C,
-  0x2C, 0x2C, 0x2C, 0xD9, 0xAC, 0x2C, 0x2C, 0x2C,
-  0xAF, 0x2C, 0xAF, 0xD9, 0xAC, 0xAF, 0xAF, 0x95,
-  0xB2, 0xE9, 0x21, 0x2B, 0x41, 0x2B, 0x20, 0x5B,
-  0x3D, 0xE8, 0xE8, 0x8D, 0x2B, 0x88, 0x5B, 0xE6,
-  0xBC, 0x73, 0x85, 0x89, 0x80, 0x5B, 0xE3, 0xAE,
-  0x2C, 0x8A, 0xD6, 0xB2, 0x2C, 0xA3, 0xA3, 0xD9,
-  0xA1, 0x2C, 0x85, 0x8D, 0xE8, 0xE8, 0x48, 0x20,
-  0x20, 0x20, 0xE3, 0x88, 0x20, 0x20, 0x20, 0x20,
-  0xAE, 0xD9, 0xB2, 0xE9, 0x6C, 0x48, 0xD6, 0xD9,
-  0x2C, 0x85, 0x2C, 0xD9, 0x7D, 0xD9, 0x2C, 0x85,
-  0x8D, 0x85, 0x2C, 0xAC, 0xAF, 0x2C, 0x2C, 0x85,
-  0x2C, 0x2C, 0xAF, 0xAC, 0xAC, 0xAF, 0xAF, 0xD9,
-  0xB2, 0x48, 0xB2, 0x20, 0x20, 0xCC, 0x20, 0x9F,
-  0xE8, 0xE8, 0xE8, 0xCD, 0x48, 0x89, 0xDB, 0x88,
-  0x2B, 0xE9, 0xCD, 0x2A, 0x48, 0x80, 0xAE, 0xAE,
-  0x7D, 0x48, 0x21, 0xEE, 0x3D, 0x2C, 0x48, 0x85,
-  0x2C, 0x95, 0x7D, 0x8C, 0xE8, 0xE8, 0xB2, 0x20,
-  0x20, 0x20, 0xDB, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0xDB, 0x2C, 0xB2, 0x48, 0x48, 0x7D, 0xD9, 0xAF,
-  0x85, 0x8A, 0x85, 0x7D, 0xB2, 0x95, 0x85, 0xDA,
-  0xD3, 0x85, 0xAF, 0xAC, 0x2C, 0x85, 0x85, 0x2C,
-  0xAC, 0xAC, 0xAC, 0xD9, 0xD9, 0xAC, 0x2C, 0x2C,
-  0xD9, 0xAC, 0x5B, 0x20, 0x20, 0xAE, 0x20, 0x2D,
-  0xE8, 0xE8, 0xE8, 0x7E, 0xD6, 0x48, 0xE9, 0xAE,
-  0x88, 0x5B, 0x80, 0x6C, 0xAE, 0xCA, 0x91, 0xE9,
-  0x43, 0x9F, 0xE6, 0x2C, 0x48, 0x21, 0xBC, 0x95,
-  0x95, 0xD6, 0x21, 0x7E, 0xE8, 0xE8, 0x7D, 0x20,
-  0x20, 0x20, 0x2B, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x6B, 0xDA, 0xD9, 0x48, 0xB2, 0xD9, 0x2C, 0x85,
-  0xDA, 0xDA, 0x2C, 0xA1, 0x48, 0xAC, 0xDA, 0x8D,
-  0x2A, 0xAC, 0x7D, 0x95, 0xAF, 0x85, 0x2C, 0x2C,
-  0xAC, 0xD9, 0x95, 0x7D, 0x95, 0xAC, 0x2C, 0xAF,
-  0x7D, 0xD6, 0x20, 0x20, 0x88, 0x9F, 0x20, 0xA1,
-  0xE8, 0xE8, 0xE8, 0xA3, 0xD6, 0x6C, 0xB2, 0x2C,
-  0x89, 0xE3, 0x88, 0xDB, 0xCC, 0x24, 0x7D, 0xEE,
-  0xB2, 0xCC, 0xAE, 0x2D, 0xDA, 0x2C, 0xD6, 0x2C,
-  0xB2, 0x2D, 0xD6, 0xEE, 0xE8, 0xE8, 0x95, 0x20,
-  0x20, 0x20, 0xDB, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x6B, 0xDA, 0x95, 0xA1, 0xB2, 0xAC, 0x85, 0x85,
-  0xDA, 0x2C, 0x95, 0xA1, 0x21, 0x2C, 0x8A, 0x2A,
-  0xAF, 0xA1, 0x48, 0xD6, 0xAF, 0x2C, 0x2C, 0xAC,
-  0xD9, 0xD9, 0x95, 0x7D, 0x95, 0xAC, 0xD9, 0x7D,
-  0x48, 0xE6, 0x20, 0x20, 0x33, 0x89, 0x6B, 0x95,
-  0xE8, 0xE8, 0xE8, 0xA3, 0x21, 0x48, 0xAF, 0xAF,
-  0x9F, 0xE9, 0x43, 0x33, 0x33, 0x2D, 0xDA, 0xCD,
-  0xD6, 0xAE, 0x85, 0x2C, 0x7D, 0xD6, 0x91, 0xB8,
-  0xD4, 0x48, 0x7D, 0xA3, 0xE8, 0xE8, 0x95, 0x20,
-  0x20, 0x33, 0xE3, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x2C, 0x48, 0x6C, 0xB2, 0xAF, 0xDA, 0xDA,
-  0x85, 0xAF, 0xD9, 0x95, 0xAC, 0xDA, 0x8A, 0xDA,
-  0x7D, 0x48, 0x48, 0x7D, 0x2C, 0x85, 0x2C, 0xAF,
-  0xD9, 0xD9, 0x7D, 0x95, 0xD9, 0xD9, 0x95, 0xD6,
-  0x21, 0x24, 0x20, 0x20, 0x20, 0x5B, 0xDB, 0xAC,
-  0xE8, 0xE8, 0xE8, 0x3D, 0x7D, 0x48, 0xE6, 0x2D,
-  0x85, 0x81, 0x81, 0x48, 0xAE, 0xCA, 0x89, 0xCC,
-  0xAE, 0xDB, 0x2D, 0x95, 0x21, 0xCC, 0xDB, 0xAE,
-  0x91, 0xE9, 0x7D, 0x73, 0xE8, 0xE8, 0x48, 0x20,
-  0x6B, 0x74, 0x41, 0x88, 0x6B, 0x20, 0x20, 0x20,
-  0x6B, 0x95, 0xB2, 0xD6, 0xD9, 0x85, 0xDA, 0xDA,
-  0xDA, 0x2C, 0xAF, 0xAF, 0x2C, 0xDA, 0xDA, 0x85,
-  0xA1, 0xE9, 0x48, 0x95, 0x85, 0xDA, 0x85, 0xAC,
-  0xD9, 0xD9, 0x95, 0x95, 0xD9, 0xD9, 0xD9, 0x95,
-  0x95, 0x6C, 0x41, 0x93, 0x93, 0x41, 0xDB, 0x95,
-  0xE8, 0xE8, 0xE8, 0x3D, 0x95, 0xD4, 0x6C, 0x21,
-  0x2D, 0x95, 0xCD, 0x2C, 0xD6, 0xD9, 0x6C, 0x91,
-  0x89, 0x7D, 0xAC, 0x2A, 0x8D, 0xE6, 0xCC, 0x88,
-  0x74, 0x48, 0xD9, 0xE4, 0xE8, 0xE8, 0xE6, 0x88,
-  0x2B, 0x88, 0x20, 0x33, 0xDB, 0x2B, 0xDB, 0x20,
-  0x91, 0x7D, 0xD9, 0xD9, 0x85, 0x85, 0xDA, 0xDA,
-  0x85, 0xAF, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xA1, 0xA1, 0xD6, 0xAF, 0x85, 0xDA, 0x85, 0x2C,
-  0xD9, 0xD9, 0x95, 0x95, 0xD9, 0xD9, 0xD9, 0xAC,
-  0x2C, 0x47, 0x87, 0x3E, 0x3E, 0xA4, 0x7B, 0x80,
-  0xA3, 0xE8, 0xE8, 0x5C, 0x7D, 0x48, 0xE6, 0xD9,
-  0xBC, 0xEE, 0x7D, 0x43, 0xD6, 0x21, 0x43, 0x6C,
-  0x43, 0x7D, 0x7D, 0xB2, 0x8A, 0xEE, 0x2C, 0xCA,
-  0xAE, 0x48, 0x2C, 0xE4, 0xE8, 0x5C, 0xCC, 0x88,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x91, 0xE3,
-  0x21, 0xD9, 0x2C, 0x2C, 0xDA, 0xDA, 0xDA, 0x85,
-  0x2C, 0xAC, 0xD9, 0xD9, 0xAC, 0xAF, 0xAF, 0xAF,
-  0xD6, 0x7D, 0xD9, 0x2C, 0xDA, 0xDA, 0x85, 0xAC,
-  0xD9, 0x7D, 0x7D, 0xD9, 0xD9, 0xD9, 0x2C, 0x2C,
-  0xB8, 0x9C, 0xEC, 0x62, 0x6F, 0x62, 0x70, 0x3C,
-  0xAE, 0xCD, 0xE8, 0xE8, 0x8C, 0x7D, 0xC8, 0x3D,
-  0x8A, 0xE9, 0x2D, 0x9E, 0xA1, 0xD6, 0x48, 0x73,
-  0x81, 0xD6, 0xD6, 0xAE, 0x5B, 0x2D, 0xA3, 0xA3,
-  0x21, 0x21, 0xCD, 0xE8, 0xC0, 0x56, 0x31, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0xCC, 0xDB,
-  0x42, 0x85, 0x85, 0x85, 0x85, 0x85, 0x2C, 0x2C,
-  0xAC, 0xD9, 0xD9, 0xD9, 0xAC, 0xAF, 0xAF, 0xAF,
-  0xD9, 0x95, 0xAC, 0x2C, 0x85, 0x85, 0x2C, 0xD9,
-  0x7D, 0xD6, 0xD6, 0xD9, 0xAC, 0xAF, 0x8A, 0xBC,
-  0xC2, 0x68, 0x2E, 0x4B, 0xC9, 0x8B, 0x62, 0x87,
-  0x3C, 0x74, 0xBC, 0xE8, 0xE8, 0xE4, 0xEE, 0xA1,
-  0xE9, 0x21, 0xE6, 0x89, 0x48, 0x7D, 0xB2, 0x5C,
-  0x6C, 0x7D, 0x21, 0x80, 0xE3, 0x33, 0xCC, 0x2C,
-  0x3D, 0x3D, 0xE8, 0xE8, 0xEC, 0xCB, 0x5A, 0x6B,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x88, 0x41, 0x51,
-  0x49, 0x28, 0x85, 0x85, 0x85, 0x85, 0x2C, 0xAF,
-  0xAC, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xD9, 0x95, 0xD9, 0x2C, 0x85, 0x85, 0x2C, 0xD9,
-  0xB2, 0xB2, 0x2C, 0x2A, 0x79, 0x79, 0x97, 0x44,
-  0xED, 0x29, 0x32, 0x62, 0x4B, 0x62, 0x6F, 0x22,
-  0xF3, 0x6B, 0x33, 0x85, 0x73, 0xE4, 0x2D, 0x2B,
-  0xCC, 0x9F, 0xDA, 0xBC, 0x48, 0xD6, 0xA1, 0xE4,
-  0xE9, 0xD6, 0xD9, 0x2A, 0xB2, 0x2B, 0x2B, 0xA1,
-  0xB8, 0xE8, 0xE8, 0xE8, 0xEC, 0x3E, 0x30, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x6B, 0x54, 0xDC,
-  0xC9, 0x53, 0xBC, 0x2C, 0x2C, 0x2C, 0xAF, 0xAF,
-  0xAF, 0xAC, 0xAF, 0xAC, 0xAC, 0x2C, 0xAF, 0xAC,
-  0x2C, 0x7D, 0xD9, 0x2C, 0x85, 0xDA, 0xAF, 0x7D,
-  0xB2, 0xAC, 0xC6, 0xBA, 0x4C, 0xEF, 0xA7, 0xEF,
-  0xEC, 0x7A, 0x62, 0x4B, 0x62, 0x4B, 0x8B, 0x4B,
-  0x3A, 0x52, 0x20, 0x6B, 0x21, 0x73, 0xAC, 0x2B,
-  0x41, 0x33, 0x48, 0x67, 0xA1, 0xD6, 0xD6, 0x5C,
-  0xE9, 0xD6, 0x2C, 0xEE, 0xB2, 0x9F, 0x8A, 0x95,
-  0x4D, 0xE8, 0xE8, 0x3D, 0x7A, 0x57, 0xD1, 0x7B,
-  0x20, 0x20, 0x20, 0x20, 0x6B, 0xCF, 0xBA, 0x3E,
-  0x3E, 0xD0, 0xBC, 0xAC, 0xAC, 0x2C, 0x2C, 0xAC,
-  0xD9, 0xD9, 0x95, 0x95, 0x7D, 0x95, 0x95, 0xD9,
-  0x85, 0xD9, 0xAF, 0xDA, 0xDA, 0x85, 0xAC, 0x21,
-  0xB2, 0x2A, 0xBA, 0x57, 0x2E, 0x2E, 0x2E, 0x7A,
-  0x32, 0x62, 0x8B, 0x4B, 0x8B, 0x4B, 0x4B, 0x4B,
-  0xC9, 0x4A, 0x5F, 0x20, 0x20, 0x2D, 0xA3, 0xD9,
-  0xCA, 0x88, 0xDB, 0x24, 0x48, 0x7D, 0xB2, 0xE4,
-  0x2D, 0x7D, 0x7D, 0x81, 0xA1, 0xDA, 0x21, 0xDA,
-  0xE4, 0xE8, 0xEE, 0xF1, 0x2E, 0x57, 0x82, 0x76,
-  0x52, 0x4F, 0x4F, 0x98, 0xDE, 0xB5, 0xEC, 0x2E,
-  0x3E, 0x6D, 0x85, 0x2C, 0xAC, 0xAC, 0xD9, 0xD9,
-  0x95, 0xD6, 0x7D, 0x7D, 0x95, 0xD9, 0xD9, 0xD9,
-  0xDA, 0x2C, 0x85, 0xDA, 0xDA, 0x2C, 0x95, 0xB2,
-  0x21, 0xB8, 0xED, 0x2E, 0x3E, 0x4B, 0xC9, 0x4B,
-  0x8B, 0x62, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x22, 0x6F, 0xCE, 0x20, 0x20, 0x20, 0x80, 0xCD,
-  0xDA, 0x2D, 0x2B, 0xDB, 0xE9, 0xD6, 0x95, 0x5C,
-  0x2D, 0x7D, 0x7D, 0xAF, 0xAF, 0xAC, 0xEE, 0x5C,
-  0xE8, 0xE8, 0xEB, 0x25, 0x7A, 0x57, 0x39, 0xE1,
-  0x83, 0xA8, 0x55, 0x83, 0x82, 0x57, 0x32, 0x8B,
-  0x62, 0x6D, 0xEB, 0x95, 0xD9, 0xD9, 0xD9, 0xD9,
-  0xD9, 0xD9, 0xD9, 0xAF, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xDA, 0x2C, 0x85, 0x85, 0x85, 0xAC, 0xD6, 0x21,
-  0x95, 0x6E, 0xED, 0x57, 0x62, 0x4B, 0x8B, 0x4B,
-  0x4B, 0x62, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x62,
-  0x62, 0x62, 0x25, 0x3C, 0x20, 0x20, 0x20, 0xE3,
-  0x2A, 0xBC, 0x7D, 0xCA, 0x6C, 0xD6, 0x95, 0x3D,
-  0x81, 0x7D, 0xD6, 0xD6, 0xDA, 0x73, 0xE8, 0xE8,
-  0xE8, 0x4D, 0x94, 0xED, 0x72, 0x3A, 0xF1, 0xA7,
-  0x39, 0xED, 0x39, 0xEF, 0x57, 0x32, 0x8B, 0x4B,
-  0x62, 0x62, 0xA6, 0x2A, 0xD9, 0xD9, 0xD9, 0xD9,
-  0x2C, 0x2C, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
-  0x85, 0x2C, 0x2C, 0xAF, 0xAC, 0x95, 0x21, 0x7D,
-  0xAC, 0x8C, 0x46, 0xC4, 0x62, 0x8B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x62, 0xC9, 0x30, 0x7B, 0x20, 0x20, 0x20,
-  0x41, 0x4D, 0x3D, 0x85, 0x48, 0x21, 0xDA, 0x3D,
-  0xE9, 0xD6, 0xD9, 0xCD, 0x5C, 0xE8, 0xE8, 0xE8,
-  0xE8, 0x4D, 0x71, 0x46, 0xEC, 0x2E, 0x72, 0xEC,
-  0x29, 0x29, 0x7C, 0x29, 0x2E, 0x4B, 0x4B, 0x62,
-  0x62, 0x4B, 0x3A, 0xAD, 0xE2, 0xAF, 0xD9, 0xD9,
-  0x2C, 0xDA, 0xDA, 0xDA, 0xDA, 0x85, 0x2C, 0x2C,
-  0x2C, 0xAF, 0xAC, 0xD9, 0x95, 0xD6, 0xD6, 0xD9,
-  0x2C, 0x8C, 0xBA, 0x7C, 0x2E, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x62, 0xC9, 0xDC, 0x34, 0x20, 0x20, 0x20,
-  0x20, 0xAC, 0xE8, 0x5C, 0x8C, 0xBC, 0xE4, 0xE8,
-  0xEE, 0x2A, 0xA3, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE4, 0x7E, 0x65, 0x46, 0x29, 0x62, 0x62, 0x2E,
-  0x2E, 0x72, 0x2E, 0x2E, 0x32, 0x4B, 0x4B, 0x62,
-  0x4B, 0x4B, 0x4B, 0x32, 0x61, 0x9D, 0x2C, 0xD9,
-  0x2C, 0x85, 0xDA, 0x85, 0x2C, 0xAF, 0xAF, 0xAF,
-  0x2C, 0xAC, 0xD9, 0x95, 0xD6, 0x7D, 0x95, 0xAC,
-  0x2C, 0xDA, 0x40, 0x7C, 0x2E, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x62, 0x62, 0x22, 0xB7, 0xCE, 0x20, 0x20,
-  0x20, 0x95, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0x5C,
-  0x3D, 0xE9, 0x9A, 0x46, 0x7C, 0x32, 0x8B, 0x62,
-  0x4B, 0x8B, 0x8B, 0x4B, 0x4B, 0x4B, 0x4B, 0x62,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x62, 0x61, 0x4E, 0xDA,
-  0x85, 0x85, 0x85, 0x2C, 0xD9, 0xD9, 0xD9, 0xD9,
-  0x85, 0xD9, 0x7D, 0x21, 0x21, 0xD6, 0xAC, 0x2C,
-  0x2C, 0xDA, 0xDD, 0x77, 0x8B, 0x62, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x3E, 0x8B, 0x32, 0xC9, 0x22, 0x68, 0x88, 0x33,
-  0xA1, 0x73, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0x5C, 0x5C, 0x5C, 0x5C, 0x3D,
-  0x89, 0x20, 0x54, 0x23, 0x29, 0x2E, 0x4B, 0x62,
-  0x4B, 0x3E, 0x4B, 0x62, 0x4B, 0x4B, 0x4B, 0x8B,
-  0x8B, 0xC9, 0x6F, 0x4B, 0x8B, 0x4B, 0x78, 0xE2,
-  0x8A, 0x8A, 0x85, 0xAC, 0xD9, 0x7D, 0xD9, 0xAC,
-  0x2C, 0xD9, 0xD6, 0xB2, 0x21, 0x7D, 0xAF, 0x85,
-  0x2C, 0xDA, 0x40, 0xEF, 0x62, 0x62, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x8B, 0x4B, 0xC9, 0x63, 0xB4, 0x5C,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE8, 0x5C, 0x5C, 0xCD, 0xAE,
-  0x20, 0x20, 0xCE, 0xE1, 0x57, 0x32, 0x4B, 0x4B,
-  0x8B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x8B, 0x4B, 0x62, 0x4B, 0x62, 0x2E, 0x61, 0x28,
-  0x8D, 0xDA, 0xAF, 0xD9, 0x95, 0x95, 0xD9, 0xAF,
-  0xAF, 0xD9, 0xD6, 0xB2, 0x21, 0xD9, 0x2C, 0x85,
-  0xAF, 0xEB, 0xE1, 0x57, 0x2E, 0x62, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x3E, 0x9B, 0x31, 0x6E,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0x5C, 0xE8, 0xE8, 0xE8, 0x3D, 0x7D, 0x33, 0x6B,
-  0x20, 0x20, 0x34, 0x23, 0x29, 0x3E, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x3E, 0x62, 0x62, 0x2E, 0xC4, 0x49, 0xD5,
-  0xDA, 0xD9, 0xD6, 0xA1, 0xA1, 0x21, 0xD9, 0xD9,
-  0xD9, 0x95, 0x21, 0x48, 0xD6, 0xAC, 0x85, 0x85,
-  0xAF, 0xB6, 0x5D, 0x2E, 0x32, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x62, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x62, 0x2E, 0x45, 0xDE,
-  0xDA, 0x5C, 0xE8, 0x5C, 0xE8, 0xE8, 0x5C, 0xE8,
-  0x5C, 0x5C, 0xA3, 0xAC, 0x2B, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x34, 0x23, 0x29, 0x62, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x62, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x3E, 0x3E, 0x63, 0x40, 0x97, 0x28, 0xDA,
-  0xD9, 0xA1, 0x48, 0xE9, 0x48, 0x21, 0xD9, 0xD9,
-  0xA1, 0xB2, 0xB2, 0xA1, 0x21, 0xAC, 0x85, 0x2C,
-  0xDA, 0x36, 0x77, 0x72, 0x62, 0x8B, 0x62, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x3E, 0xEC, 0x2F, 0x51,
-  0xE3, 0xAE, 0x48, 0x2C, 0xDA, 0xDA, 0x85, 0xAC,
-  0x48, 0x9E, 0x88, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x41, 0xA0, 0x23, 0x72, 0x2E, 0x4B, 0x4B,
-  0x4B, 0x62, 0x62, 0x4B, 0x4B, 0x4B, 0x2E, 0x8B,
-  0xF0, 0x4C, 0x40, 0xC2, 0x90, 0x8D, 0x85, 0xD9,
-  0xA1, 0x6C, 0x6C, 0x48, 0xD6, 0xD9, 0xAF, 0xAC,
-  0xA1, 0xD6, 0xD6, 0xB2, 0xD6, 0xAC, 0x85, 0x85,
-  0x4D, 0xBE, 0x39, 0x4C, 0x57, 0x2E, 0x2E, 0x2E,
-  0x3E, 0x3E, 0x62, 0x3E, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x8B, 0x8B, 0x57, 0x60, 0x76,
-  0x52, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x3C, 0xA0, 0x23, 0x7C, 0x2E, 0x4B, 0x4B,
-  0x8B, 0x62, 0x4B, 0x4B, 0x3E, 0x7A, 0xF0, 0x29,
-  0x36, 0x97, 0xBC, 0x8A, 0x8D, 0xDA, 0xD9, 0x48,
-  0x81, 0x2D, 0x48, 0xD6, 0xD9, 0xAF, 0x2C, 0x2C,
-  0xAC, 0xAF, 0xD9, 0x7D, 0x7D, 0x2C, 0x85, 0x85,
-  0x85, 0xB4, 0x66, 0x23, 0x46, 0x2F, 0x60, 0x68,
-  0x77, 0x29, 0x29, 0xF0, 0x2E, 0x2E, 0x62, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x32, 0x7C, 0x83, 0xB3,
-  0x54, 0x6B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x6B, 0x7B, 0xC3, 0xE7, 0x39, 0x72, 0x62, 0x62,
-  0x62, 0x62, 0x62, 0x2E, 0x29, 0x77, 0xA7, 0x36,
-  0xB8, 0x85, 0x85, 0x8D, 0x8D, 0x85, 0xB2, 0x2D,
-  0x2D, 0xE9, 0xD6, 0xD9, 0xAF, 0x2C, 0x85, 0x85,
-  0x2A, 0x85, 0xAC, 0x95, 0x95, 0xAF, 0x85, 0x85,
-  0xAF, 0x8C, 0xDF, 0xC6, 0xB1, 0xD1, 0xE5, 0xE7,
-  0x83, 0x23, 0x5D, 0x60, 0x39, 0x77, 0xEC, 0x2E,
-  0x2E, 0x32, 0x32, 0x2E, 0x7C, 0x5D, 0x35, 0xA2,
-  0x54, 0x6B, 0x6B, 0x20, 0x6B, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x6B, 0x88, 0xC1, 0x35, 0xE1, 0x77, 0x57, 0x2E,
-  0x2E, 0x72, 0x29, 0x77, 0x60, 0xB5, 0x44, 0xE2,
-  0x2C, 0x2C, 0xDA, 0x8A, 0xDA, 0xAF, 0xA1, 0x2D,
-  0xE9, 0xD6, 0xD9, 0xAF, 0x2C, 0x85, 0x85, 0x85,
-  0xEE, 0xAF, 0xD9, 0x7D, 0xD9, 0x2C, 0xDA, 0x85,
-  0xAC, 0xAF, 0x85, 0xDA, 0x8A, 0x2A, 0xE2, 0x50,
-  0x86, 0xD7, 0x75, 0x35, 0xA8, 0xE7, 0xE1, 0x5D,
-  0x68, 0x7C, 0xF1, 0x68, 0xE1, 0xBF, 0xA2, 0xC1,
-  0x52, 0x2B, 0x7D, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C,
-  0x2C, 0x85, 0x85, 0x85, 0x2C, 0x2C, 0x2C, 0x95,
-  0xE9, 0x74, 0xCE, 0xE0, 0xE7, 0x60, 0x77, 0x77,
-  0x7C, 0xEF, 0x5D, 0x23, 0x3F, 0xB6, 0x8A, 0x2C,
-  0xAC, 0xAF, 0x85, 0x8A, 0x85, 0xD9, 0x48, 0x48,
-  0xB2, 0x95, 0x95, 0xD9, 0x85, 0xDA, 0x85, 0x85,
-  0xD3, 0xB2, 0x21, 0x7D, 0xAC, 0x2C, 0xDA, 0x85,
-  0xAC, 0xAC, 0x85, 0x85, 0x85, 0x2C, 0xAF, 0x2C,
-  0xDA, 0x8C, 0x79, 0xC7, 0xB0, 0x51, 0xB3, 0x35,
-  0xBF, 0xE5, 0xE7, 0xA8, 0xE0, 0xA2, 0xC1, 0x34,
-  0x7D, 0x85, 0xAC, 0xD9, 0xAC, 0xAF, 0xAC, 0xAC,
-  0xAF, 0x2C, 0x2C, 0x2C, 0x2C, 0xAF, 0xAF, 0x85,
-  0xC8, 0xCD, 0x6A, 0x26, 0x35, 0x3F, 0x83, 0x23,
-  0x23, 0xE7, 0xBF, 0x96, 0xEB, 0xDA, 0xDA, 0x2C,
-  0x2C, 0x2C, 0x85, 0xDA, 0x2C, 0x7D, 0xA1, 0x48,
-  0xB2, 0x21, 0xD6, 0xD9, 0x2C, 0xDA, 0x85, 0xAF,
-  0xAF, 0x2D, 0xE9, 0x7D, 0xAC, 0x2C, 0x85, 0x2C,
-  0xD9, 0xD9, 0xAF, 0x85, 0x85, 0x85, 0x2C, 0x2C,
-  0x2C, 0x85, 0xD9, 0x21, 0xAC, 0x2C, 0xBD, 0xA5,
-  0xC3, 0xA2, 0xA2, 0xA2, 0x26, 0xC1, 0xCE, 0x2A,
-  0xAF, 0x95, 0xD9, 0x2C, 0x2C, 0x85, 0x2C, 0xAF,
-  0xAC, 0x2C, 0x85, 0x2C, 0xAF, 0x2C, 0x85, 0xDA,
-  0x8D, 0x2A, 0x85, 0x34, 0xC1, 0xB3, 0x76, 0x35,
-  0xE0, 0x30, 0xA5, 0xB6, 0x2C, 0x85, 0x85, 0x85,
-  0xAF, 0x2C, 0x85, 0x85, 0xD9, 0xD6, 0xA1, 0xA1,
-  0x48, 0xA1, 0xD6, 0xAF, 0xDA, 0x8A, 0x2C, 0xD9,
-  0xB2, 0x2D, 0x48, 0xD9, 0xAF, 0x2C, 0x2C, 0x85,
-  0xAF, 0xAC, 0x2C, 0x85, 0x85, 0x85, 0xAF, 0xAC,
-  0xAC, 0x2C, 0xD9, 0xD6, 0xD6, 0x21, 0xB2, 0x2C,
-  0xC8, 0x3B, 0x65, 0xC5, 0xCE, 0x8E, 0xC8, 0x2C,
-  0xD9, 0x95, 0xAC, 0x2C, 0x2C, 0x2C, 0xAF, 0xAC,
-  0xAC, 0xAF, 0x2C, 0x85, 0x2C, 0x2C, 0x2C, 0x85,
-  0xDA, 0x2C, 0xD6, 0xAF, 0x59, 0x65, 0xDE, 0xF3,
-  0xF3, 0x59, 0xBC, 0xAC, 0xAF, 0x85, 0x85, 0x85,
-  0xAF, 0xD9, 0xAF, 0x2C, 0xD9, 0xD6, 0xD6, 0xD6,
-  0x21, 0xD6, 0xD9, 0xDA, 0x8D, 0x8A, 0x2C, 0xD9,
-  0xB2, 0xA1, 0xD6, 0xAC, 0x2C, 0x2C, 0x2C, 0x85,
-  0x2C, 0xAC, 0x2C, 0xDA, 0xDA, 0x85, 0xAF, 0xD9,
-  0xD9, 0xAC, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xAC,
-  0x85, 0x2A, 0x4D, 0xBC, 0x85, 0xAC, 0xAF, 0xAF,
-  0xAC, 0xD9, 0xAF, 0x2C, 0xAF, 0xD9, 0xD9, 0xAC,
-  0xAC, 0xAF, 0x85, 0x2C, 0x85, 0x2C, 0x2C, 0x2C,
-  0x2C, 0xD9, 0xB2, 0xD4, 0xD6, 0x2C, 0x8A, 0xDA,
-  0xC8, 0x85, 0x2C, 0xAC, 0x2C, 0xDA, 0xDA, 0x85,
-  0xAF, 0xAC, 0xD9, 0xAC, 0xD9, 0xD9, 0xD9, 0xD9,
-  0xD9, 0xAC, 0xDA, 0x8D, 0xBC, 0xDA, 0xD9, 0x95,
-  0x95, 0xD9, 0xD9, 0xAF, 0x2C, 0x2C, 0x2C, 0x85,
-  0x2C, 0xAF, 0xAF, 0x85, 0x85, 0x85, 0x2C, 0xAC,
-  0xD9, 0xAF, 0xAF, 0xAF, 0x2C, 0x2C, 0x2C, 0x85,
-  0x8A, 0x2A, 0x8D, 0x2C, 0xD9, 0x95, 0xAC, 0xAC,
-  0xD9, 0xD9, 0xD9, 0xD9, 0x95, 0x95, 0xD9, 0xAF,
-  0xAF, 0x2C, 0x85, 0x85, 0x85, 0x85, 0x85, 0x2C,
-  0x85, 0x2C, 0xD9, 0xD9, 0xD9, 0x2C, 0x2C, 0x2C,
-  0x2C, 0x85, 0x85, 0xAF, 0xAF, 0x85, 0x85, 0x85,
-  0xAF, 0xD9, 0xD9, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C,
-  0x2C, 0x85, 0x8A, 0x2A, 0x8D, 0x2C, 0xD9, 0xD9,
-  0x2C, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C,
-  0x85, 0xAF, 0xAC, 0x2C, 0x2C, 0x2C, 0x2C, 0xAC,
-  0xD9, 0xD9, 0xAF, 0x85, 0x85, 0x85, 0xDA, 0xDA,
-  0x8A, 0x8A, 0x85, 0xAC, 0xD9, 0xD9, 0xAC, 0xD9,
-  0xD6, 0xD6, 0x7D, 0x95, 0x7D, 0xD9, 0xAF, 0xAF,
-  0xAF, 0x2C, 0x85, 0x85, 0xDA, 0x85, 0x2C, 0x85,
-  0x85, 0x2C, 0xAF, 0xAC, 0xAF, 0xAF, 0x2C, 0x2C,
-  0x2C, 0x2C, 0x2C, 0xAF, 0xAC, 0x2C, 0x2C, 0x2C,
-  0x2C, 0xAF, 0xD9, 0xAC, 0xAF, 0x2C, 0x85, 0x85,
-  0x85, 0xDA, 0x8D, 0x8A, 0x85, 0xAC, 0x95, 0xD9
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22,
+    0x22, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+    0x26, 0x26, 0x25, 0x28, 0x23, 0x22, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x25, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d,
+    0x2d, 0x2e, 0x2c, 0x2b, 0x2a, 0x25, 0x28, 0x22,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x24, 0x2a, 0x2c, 0x2f, 0x2c, 0x30, 0x30, 0x24,
+    0x25, 0x27, 0x2b, 0x2c, 0x2f, 0x31, 0x32, 0x25,
+    0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
+    0x33, 0x34, 0x35, 0x21, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x21, 0x2b, 0x2f, 0x2c,
+    0x30, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
+    0x2d, 0x27, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x31,
+    0x2d, 0x32, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x28, 0x2a, 0x34,
+    0x25, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x23, 0x32, 0x27, 0x21, 0x36,
+    0x2a, 0x2d, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x22, 0x26, 0x2c, 0x35,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x25, 0x2f, 0x37, 0x32, 0x22,
+    0x36, 0x35, 0x31, 0x27, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x22,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x26, 0x38, 0x38, 0x35, 0x25,
+    0x36, 0x21, 0x2d, 0x2b, 0x24, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x24, 0x39, 0x39, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x25, 0x2b, 0x30, 0x28, 0x22,
+    0x36, 0x36, 0x27, 0x34, 0x30, 0x23, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x26, 0x2d, 0x26, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x22, 0x22, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x2d, 0x33, 0x28, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x2b, 0x2c, 0x25, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x36, 0x36,
+    0x36, 0x21, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x21, 0x23, 0x22, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x28, 0x34, 0x27, 0x22, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
+    0x21, 0x21, 0x24, 0x27, 0x21, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x28, 0x27, 0x22, 0x33, 0x24, 0x36,
+    0x36, 0x36, 0x36, 0x22, 0x2f, 0x2a, 0x23, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
+    0x30, 0x3a, 0x38, 0x24, 0x24, 0x36, 0x36, 0x36,
+    0x23, 0x2f, 0x3b, 0x3c, 0x3d, 0x30, 0x25, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2f, 0x32, 0x23, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x23,
+    0x3e, 0x3f, 0x40, 0x3a, 0x22, 0x36, 0x36, 0x21,
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x3e, 0x23, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2f, 0x33, 0x28, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x2b,
+    0x44, 0x40, 0x46, 0x47, 0x35, 0x36, 0x36, 0x26,
+    0x43, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x2e, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x34, 0x36, 0x4d,
+    0x4e, 0x25, 0x2f, 0x46, 0x4a, 0x22, 0x23, 0x32,
+    0x4f, 0x50, 0x21, 0x31, 0x51, 0x52, 0x53, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x21, 0x3a,
+    0x4d, 0x21, 0x31, 0x54, 0x55, 0x28, 0x30, 0x2b,
+    0x4b, 0x4d, 0x36, 0x23, 0x32, 0x50, 0x3f, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x38, 0x23, 0x37,
+    0x55, 0x36, 0x28, 0x3a, 0x56, 0x57, 0x57, 0x58,
+    0x3c, 0x4d, 0x36, 0x36, 0x36, 0x40, 0x40, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x29, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x51, 0x23, 0x35,
+    0x43, 0x25, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e,
+    0x5f, 0x60, 0x61, 0x36, 0x31, 0x47, 0x3b, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x2c, 0x25, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x22,
+    0x40, 0x62, 0x63, 0x5d, 0x64, 0x65, 0x66, 0x67,
+    0x68, 0x69, 0x66, 0x5e, 0x6a, 0x6b, 0x2a, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x33, 0x2e, 0x26, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x2f, 0x23, 0x36,
+    0x6c, 0x63, 0x6d, 0x64, 0x5c, 0x66, 0x69, 0x6e,
+    0x6f, 0x70, 0x71, 0x69, 0x69, 0x72, 0x6c, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x33, 0x34, 0x27, 0x22,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x34, 0x26, 0x73,
+    0x74, 0x75, 0x76, 0x64, 0x65, 0x77, 0x69, 0x78,
+    0x70, 0x71, 0x71, 0x71, 0x72, 0x5f, 0x5e, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x25, 0x38, 0x2a, 0x23,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x33, 0x79,
+    0x63, 0x7a, 0x7b, 0x5c, 0x66, 0x69, 0x6e, 0x7c,
+    0x71, 0x71, 0x69, 0x7d, 0x7e, 0x7a, 0x7f, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x21, 0x51, 0x2b, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x32, 0x24,
+    0x80, 0x81, 0x64, 0x82, 0x77, 0x69, 0x71, 0x71,
+    0x69, 0x83, 0x84, 0x85, 0x7a, 0x85, 0x86, 0x36,
+    0x21, 0x2b, 0x23, 0x36, 0x36, 0x39, 0x2e, 0x26,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x2d, 0x33, 0x21,
+    0x87, 0x88, 0x89, 0x72, 0x67, 0x66, 0x5f, 0x89,
+    0x8a, 0x63, 0x85, 0x8b, 0x8c, 0x8d, 0x41, 0x36,
+    0x36, 0x2d, 0x3a, 0x35, 0x36, 0x24, 0x51, 0x32,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x33, 0x21,
+    0x55, 0x8e, 0x8f, 0x8a, 0x7d, 0x5e, 0x90, 0x7e,
+    0x75, 0x75, 0x90, 0x62, 0x40, 0x3f, 0x49, 0x23,
+    0x36, 0x24, 0x3a, 0x3a, 0x24, 0x36, 0x2e, 0x31,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x28, 0x33, 0x37, 0x25, 0x22,
+    0x3b, 0x50, 0x8e, 0x8f, 0x90, 0x7e, 0x90, 0x63,
+    0x74, 0x91, 0x92, 0x42, 0x93, 0x4b, 0x45, 0x2c,
+    0x36, 0x36, 0x33, 0x39, 0x21, 0x36, 0x22, 0x51,
+    0x33, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x22, 0x27, 0x2e, 0x2e, 0x36, 0x21,
+    0x94, 0x3f, 0x50, 0x95, 0x96, 0x8f, 0x8f, 0x97,
+    0x8e, 0x42, 0x50, 0x43, 0x47, 0x48, 0x48, 0x98,
+    0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39,
+    0x2e, 0x27, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x22, 0x24, 0x2b, 0x38, 0x28, 0x36, 0x32,
+    0x4c, 0x4b, 0x50, 0x50, 0x50, 0x42, 0x42, 0x50,
+    0x50, 0x40, 0x45, 0x99, 0x48, 0x48, 0x48, 0x48,
+    0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x23,
+    0x2f, 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x32, 0x51, 0x32, 0x28, 0x21, 0x98,
+    0x48, 0x47, 0x9a, 0x50, 0x50, 0x50, 0x50, 0x50,
+    0x9a, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x93, 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x2a, 0x2f, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x23, 0x30, 0x2e, 0x2c, 0x36, 0x21, 0x51, 0x9b,
+    0x48, 0x48, 0x52, 0x3f, 0x50, 0x50, 0x40, 0x4b,
+    0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2d, 0x31, 0x27, 0x23, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x27, 0x2c, 0x2d, 0x21, 0x36, 0x28, 0x44, 0x48,
+    0x48, 0x48, 0x48, 0x47, 0x46, 0x4f, 0x47, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x9c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x28, 0x51, 0x39, 0x26, 0x22, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
+    0x35, 0x51, 0x28, 0x36, 0x36, 0x9d, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x4f, 0x28, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x28, 0x38, 0x2b, 0x25, 0x22, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
+    0x51, 0x25, 0x36, 0x36, 0x23, 0x40, 0x9b, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x9b, 0x99, 0x2b, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x30, 0x2f, 0x33, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x23, 0x30, 0x34,
+    0x27, 0x36, 0x36, 0x36, 0x2a, 0x40, 0x47, 0x48,
+    0x48, 0x48, 0x48, 0x9b, 0x99, 0x99, 0x9b, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x47, 0x52,
+    0x46, 0x4f, 0x37, 0x21, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x30, 0x34, 0x2a, 0x23,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x22, 0x25, 0x39, 0x2c,
+    0x36, 0x36, 0x36, 0x21, 0x31, 0x4e, 0x9a, 0x4c,
+    0x47, 0x9b, 0x9b, 0x52, 0x46, 0x4f, 0x52, 0x9b,
+    0x9b, 0x9b, 0x47, 0x4f, 0x45, 0x9a, 0x93, 0x93,
+    0x3f, 0x93, 0x98, 0x28, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, 0x26,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x28,
+    0x36, 0x36, 0x36, 0x22, 0x38, 0x98, 0x44, 0x99,
+    0x9b, 0x48, 0x48, 0x9b, 0x4c, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x47, 0x52, 0x46, 0x43, 0x93,
+    0x40, 0x40, 0x43, 0x53, 0x21, 0x23, 0x33, 0x23,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x2f, 0x32,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x24, 0x2b, 0x31, 0x36,
+    0x36, 0x22, 0x36, 0x24, 0x9e, 0x4f, 0x9b, 0x48,
+    0x48, 0x48, 0x48, 0x9b, 0x99, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x47,
+    0x4f, 0x9a, 0x3f, 0x46, 0x38, 0x36, 0x21, 0x30,
+    0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c,
+    0x25, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2e, 0x33, 0x36,
+    0x25, 0x25, 0x36, 0x4d, 0x52, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x4f, 0x3e, 0x4d, 0x49, 0x48,
+    0x98, 0x2b, 0x55, 0x4f, 0x9b, 0x48, 0x48, 0x48,
+    0x48, 0x47, 0x44, 0x93, 0x43, 0x23, 0x36, 0x36,
+    0x26, 0x24, 0x36, 0x36, 0x36, 0x36, 0x28, 0x2f,
+    0x2a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x51, 0x24, 0x36,
+    0x2a, 0x36, 0x28, 0x44, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x4f, 0x54, 0x38, 0x3d, 0x98, 0x37, 0x9b,
+    0x3a, 0x22, 0x23, 0x2a, 0x55, 0x4f, 0x48, 0x48,
+    0x48, 0x48, 0x9b, 0x4b, 0x44, 0x37, 0x36, 0x23,
+    0x28, 0x30, 0x22, 0x36, 0x36, 0x36, 0x36, 0x2d,
+    0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x28, 0x2b, 0x34, 0x36, 0x25,
+    0x24, 0x36, 0x4a, 0x48, 0x48, 0x48, 0x48, 0x52,
+    0x53, 0x37, 0x54, 0x98, 0x55, 0x38, 0x38, 0x47,
+    0x4a, 0x2d, 0x30, 0x23, 0x28, 0x39, 0x53, 0x52,
+    0x48, 0x48, 0x48, 0x9b, 0x52, 0x3f, 0x21, 0x30,
+    0x35, 0x25, 0x30, 0x36, 0x36, 0x36, 0x36, 0x32,
+    0x2d, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x22, 0x26, 0x2e, 0x35, 0x36, 0x2a,
+    0x36, 0x24, 0x4f, 0x48, 0x48, 0x9b, 0x55, 0x39,
+    0x55, 0x53, 0x3a, 0x55, 0x3a, 0x51, 0x51, 0x47,
+    0x55, 0x3a, 0x4d, 0x37, 0x30, 0x22, 0x24, 0x2b,
+    0x54, 0x9b, 0x48, 0x48, 0x48, 0x47, 0x32, 0x30,
+    0x2a, 0x23, 0x30, 0x23, 0x36, 0x36, 0x36, 0x21,
+    0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x2a, 0x51, 0x28, 0x28, 0x25,
+    0x36, 0x3a, 0x48, 0x48, 0x48, 0x4f, 0x26, 0x23,
+    0x26, 0x39, 0x3e, 0x43, 0x49, 0x37, 0x2f, 0x9b,
+    0x55, 0x3a, 0x54, 0x43, 0x3e, 0x30, 0x32, 0x3d,
+    0x49, 0x3f, 0x48, 0x48, 0x48, 0x48, 0x38, 0x21,
+    0x36, 0x36, 0x22, 0x27, 0x36, 0x36, 0x36, 0x36,
+    0x2e, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x22, 0x25, 0x2c, 0x34, 0x36, 0x30, 0x21,
+    0x23, 0x43, 0x48, 0x48, 0x48, 0x47, 0x3b, 0x32,
+    0x21, 0x28, 0x2b, 0x9e, 0x49, 0x37, 0x2e, 0x52,
+    0x4a, 0x37, 0x9e, 0x98, 0x51, 0x3a, 0x93, 0x54,
+    0x55, 0x4f, 0x48, 0x48, 0x48, 0x48, 0x94, 0x36,
+    0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36,
+    0x2a, 0x2e, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x2a, 0x51, 0x25, 0x21, 0x2a, 0x36,
+    0x2e, 0x9b, 0x48, 0x48, 0x52, 0x4b, 0x52, 0x9e,
+    0x51, 0x30, 0x22, 0x28, 0x32, 0x32, 0x39, 0x47,
+    0x37, 0x2a, 0x39, 0x3a, 0x50, 0x9f, 0x3a, 0x9f,
+    0x4b, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x98, 0x36,
+    0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36,
+    0x22, 0x2f, 0x30, 0x22, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x22, 0x25, 0x2c, 0x34, 0x36, 0x24, 0x28, 0x36,
+    0x54, 0x48, 0x48, 0x45, 0x30, 0x30, 0x9e, 0x52,
+    0x45, 0x3a, 0x31, 0x25, 0x22, 0x25, 0x2a, 0x98,
+    0x39, 0x2f, 0x42, 0x49, 0x4a, 0x3b, 0x50, 0x47,
+    0x43, 0x9d, 0x3b, 0x4b, 0x48, 0x48, 0x9a, 0x36,
+    0x36, 0x36, 0x36, 0x30, 0x36, 0x36, 0x36, 0x36,
+    0x21, 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x28, 0x32, 0x2f, 0x28, 0x36, 0x27, 0x22, 0x21,
+    0x43, 0x48, 0x48, 0x50, 0x30, 0x23, 0x25, 0x2f,
+    0x3f, 0x52, 0x49, 0x51, 0x39, 0x25, 0x24, 0x2b,
+    0x9e, 0x42, 0x3e, 0x55, 0x9e, 0x4f, 0x4f, 0x54,
+    0x4a, 0x9e, 0x49, 0x50, 0x48, 0x48, 0x4b, 0x21,
+    0x36, 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x25, 0x2c, 0x39, 0x36, 0x36, 0x30, 0x22, 0x25,
+    0x52, 0x48, 0x48, 0x45, 0x3a, 0x51, 0x26, 0x23,
+    0x30, 0x9d, 0x45, 0x40, 0x3a, 0x39, 0x2b, 0x2b,
+    0x3b, 0x3a, 0x55, 0x4b, 0x47, 0x9e, 0x3a, 0x49,
+    0x9e, 0x9f, 0x3b, 0x9a, 0x48, 0x48, 0x4f, 0x21,
+    0x36, 0x36, 0x22, 0x26, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x30, 0x2d, 0x21, 0x36, 0x36, 0x32, 0x23, 0x2a,
+    0x47, 0x48, 0x48, 0x43, 0x3e, 0x3a, 0x9d, 0x2b,
+    0x23, 0x25, 0x39, 0x4d, 0x2b, 0x31, 0x2d, 0x9d,
+    0x34, 0x2e, 0x2f, 0x9e, 0x3a, 0x55, 0x3f, 0x9f,
+    0x9f, 0x3e, 0x55, 0x43, 0x48, 0x48, 0x4c, 0x22,
+    0x36, 0x36, 0x24, 0x23, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0x2e, 0x36, 0x36, 0x23, 0x31, 0x27, 0x39,
+    0x9b, 0x48, 0x48, 0x4f, 0x3e, 0x4d, 0x55, 0x9e,
+    0x51, 0x24, 0x23, 0x26, 0x32, 0x2c, 0x3b, 0x4b,
+    0x55, 0x32, 0x2b, 0x37, 0x98, 0x9e, 0x3e, 0x9e,
+    0x55, 0x37, 0x3e, 0x4b, 0x48, 0x48, 0x4c, 0x23,
+    0x36, 0x36, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x2b, 0x39, 0x36, 0x36, 0x36, 0x26, 0x32, 0x31,
+    0x9b, 0x48, 0x48, 0x4f, 0x55, 0x3a, 0x53, 0x53,
+    0x2e, 0x9d, 0x34, 0x28, 0x28, 0x37, 0x98, 0x45,
+    0x3e, 0x2b, 0x49, 0x9e, 0x3b, 0x3e, 0x2d, 0x6b,
+    0x4a, 0x3a, 0x3b, 0x4f, 0x48, 0x48, 0x46, 0x22,
+    0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x35, 0x39, 0x36, 0x36, 0x36, 0x36, 0x26, 0x2d,
+    0x9b, 0x48, 0x48, 0x47, 0x3b, 0x3a, 0x2f, 0x37,
+    0x49, 0x38, 0x38, 0x3a, 0x2b, 0x31, 0x51, 0x32,
+    0x2b, 0x26, 0x37, 0x9f, 0x55, 0x32, 0x26, 0x2b,
+    0x2d, 0x9d, 0x3b, 0x52, 0x48, 0x48, 0x9a, 0x36,
+    0x24, 0x27, 0xa0, 0x24, 0x25, 0x28, 0x21, 0x36,
+    0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x25,
+    0x39, 0x4d, 0xa1, 0x84, 0x81, 0x57, 0x21, 0x39,
+    0x52, 0x48, 0x48, 0x47, 0x9f, 0x4a, 0x4d, 0x55,
+    0x37, 0x9f, 0x45, 0x9e, 0x3e, 0x54, 0x4d, 0x2d,
+    0x51, 0x3b, 0x3d, 0x40, 0x50, 0x2f, 0x32, 0x23,
+    0x2a, 0x3a, 0x54, 0x47, 0x48, 0x48, 0x53, 0x28,
+    0x23, 0x36, 0x36, 0x36, 0x21, 0x28, 0x2c, 0x30,
+    0x21, 0x38, 0x33, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x28, 0x30,
+    0x2d, 0xa2, 0x7a, 0xa3, 0xa4, 0xa4, 0x7f, 0x22,
+    0x51, 0x52, 0x48, 0x9b, 0x3b, 0x3a, 0x2f, 0x54,
+    0x3f, 0x4b, 0x3b, 0x34, 0x3e, 0x55, 0x34, 0x4d,
+    0x34, 0x3b, 0x3b, 0x55, 0x42, 0x4b, 0x9e, 0x31,
+    0x2b, 0x3a, 0x9e, 0x47, 0xa5, 0xa5, 0xa6, 0x61,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x30, 0x32,
+    0x25, 0x4d, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x24, 0x26, 0x30, 0x33, 0x31,
+    0x4d, 0x91, 0x5b, 0xa3, 0xa4, 0xa4, 0xa4, 0x5a,
+    0x21, 0x2e, 0x46, 0x48, 0x9a, 0x3b, 0x42, 0x47,
+    0x42, 0x9d, 0x37, 0x39, 0x4a, 0x3e, 0x3a, 0x52,
+    0x38, 0x3e, 0x3e, 0x2b, 0x25, 0x37, 0x4f, 0x4f,
+    0x55, 0x55, 0x45, 0xa7, 0xa8, 0x69, 0x66, 0xa9,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x26, 0x25,
+    0x83, 0xaa, 0x2c, 0x25, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x30, 0x35, 0x2d, 0x2f, 0x37, 0x4a,
+    0x60, 0x85, 0xab, 0xac, 0xa4, 0xa4, 0xa4, 0x82,
+    0x86, 0x36, 0x32, 0x3f, 0x48, 0x47, 0x4b, 0x4a,
+    0x9d, 0x55, 0x2f, 0x51, 0x3a, 0x3b, 0x55, 0x9b,
+    0x4d, 0x3b, 0x55, 0x39, 0x24, 0x28, 0x32, 0x9e,
+    0x47, 0x47, 0x48, 0xad, 0xa3, 0xa8, 0xae, 0xaf,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x57,
+    0x77, 0x66, 0x34, 0x27, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x23, 0x30, 0x31, 0xb0, 0x91, 0x7e, 0x90, 0x90,
+    0x8b, 0x5b, 0xa3, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0x5d, 0xb1, 0x36, 0x24, 0x53, 0x47, 0x37, 0x30,
+    0x32, 0x2e, 0x98, 0x3f, 0x3a, 0x3e, 0x4a, 0x47,
+    0x9d, 0x3e, 0x54, 0x40, 0x55, 0x30, 0x30, 0x4a,
+    0x6b, 0x9b, 0x99, 0xad, 0x64, 0x5c, 0x8b, 0xb1,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x73, 0x5d,
+    0x82, 0x5c, 0xb2, 0x2a, 0x23, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x24, 0x2b, 0xb0, 0x8b, 0x5b, 0x76, 0x5b, 0x5b,
+    0x7b, 0xa3, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa8, 0x5e, 0x22, 0x36, 0x21, 0x3a, 0x3d, 0x30,
+    0x22, 0x28, 0x3a, 0x44, 0x4a, 0x3e, 0x3e, 0x9b,
+    0x9d, 0x3e, 0x9e, 0x4b, 0x55, 0x2e, 0x42, 0x9f,
+    0x93, 0x4f, 0x3f, 0xb3, 0x7b, 0x7b, 0x85, 0x80,
+    0xa0, 0x36, 0x36, 0x36, 0x21, 0xb4, 0x7e, 0x7b,
+    0x64, 0x64, 0xb5, 0x35, 0x24, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x31, 0xb6, 0x5b, 0x64, 0xa3, 0xa3, 0xac,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0x66, 0xb7, 0x36, 0x36, 0x36, 0x2c, 0x54,
+    0x31, 0x23, 0x26, 0x2c, 0x3a, 0x3b, 0x55, 0x47,
+    0x37, 0x3b, 0x3b, 0x38, 0x4a, 0x98, 0x55, 0x98,
+    0x47, 0x9a, 0x3f, 0xb8, 0x76, 0x76, 0x7a, 0x63,
+    0xb9, 0xba, 0x86, 0xba, 0xbb, 0x90, 0x5b, 0x64,
+    0xa3, 0xa3, 0xbc, 0x2d, 0x27, 0x23, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x26, 0x2d, 0x91, 0x5b, 0x64, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa8, 0x83, 0xaf, 0x36, 0x36, 0x36, 0x30,
+    0x98, 0x37, 0x30, 0x26, 0x9d, 0x3e, 0x9f, 0x9b,
+    0x37, 0x3b, 0x3b, 0x53, 0x53, 0x3d, 0x4b, 0x48,
+    0x9b, 0x9a, 0x3f, 0xbd, 0x5b, 0x7b, 0xbe, 0x85,
+    0x7e, 0x90, 0x63, 0x90, 0x85, 0x5b, 0xa3, 0xa4,
+    0xa4, 0xac, 0x5d, 0xb5, 0x39, 0x26, 0x23, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2d, 0xbf, 0xbe, 0x64, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa8, 0x88, 0x36, 0x36, 0x36, 0x36,
+    0x2d, 0x3f, 0x3b, 0x31, 0x4d, 0x3e, 0x9f, 0x47,
+    0x38, 0x3b, 0x3e, 0x3e, 0x98, 0x52, 0x48, 0x48,
+    0x9b, 0x45, 0x3f, 0xc0, 0x6d, 0x7b, 0xab, 0xbe,
+    0x7a, 0x8b, 0x8b, 0x7a, 0x5b, 0x64, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa3, 0xc1, 0x37, 0x35, 0x26, 0x23,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2e, 0xbf, 0x7a, 0x7b, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa8, 0x72, 0x73, 0x36, 0x36, 0x36,
+    0x24, 0x52, 0x47, 0x49, 0x3a, 0x55, 0x98, 0x47,
+    0x9d, 0x3e, 0x54, 0x45, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x46, 0x42, 0xb6, 0x7a, 0x7b, 0x64, 0x7b,
+    0x76, 0x5b, 0x5b, 0x76, 0x7b, 0xa3, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xac, 0x64, 0xc1, 0x4d, 0x2c, 0x27,
+    0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x25, 0x31, 0xc2, 0x8b, 0x7b, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa8, 0x89, 0xa0, 0x36, 0x36,
+    0x32, 0x47, 0x48, 0x9b, 0x9a, 0x3f, 0x47, 0x48,
+    0x4b, 0x40, 0x4f, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x4b, 0x2f, 0x8f, 0x7a, 0x7b, 0xa3, 0xac,
+    0xa3, 0x64, 0x64, 0xa3, 0xa3, 0xac, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa3, 0x5d, 0xc3, 0x2c,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x25, 0x31, 0xc2, 0x85, 0x7b, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0x66, 0x57, 0x27, 0x4d,
+    0x4b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x99, 0x34, 0xa0, 0xb9, 0x7a, 0x7b, 0xa3, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa3, 0xc2,
+    0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2d, 0xc2, 0x85, 0x7b, 0xac, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa8, 0x5f, 0x92, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x44,
+    0x35, 0x36, 0xaf, 0xbb, 0x7a, 0x7b, 0xac, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xac, 0xa3, 0xc0,
+    0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x30, 0x2f, 0xb6, 0x8b, 0x7b, 0xac, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0x66, 0x89, 0x45,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x4e, 0x25,
+    0x36, 0x36, 0x61, 0xb9, 0x6d, 0x64, 0xac, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xac, 0x7b, 0xbe, 0xc3,
+    0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0xc4, 0x63, 0xbe, 0xa3, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa3, 0x72, 0x81, 0xc5,
+    0x46, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x3f, 0x2c, 0x36, 0x36,
+    0x36, 0x36, 0xc6, 0x8f, 0x6d, 0x64, 0xac, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa3, 0xab, 0x8b, 0xb0, 0x2c,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x35, 0x96, 0x75, 0xab, 0xa3, 0xac, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xac, 0x7b, 0x81, 0xb9,
+    0x73, 0x3b, 0x44, 0x9b, 0x48, 0x48, 0x48, 0x9b,
+    0x99, 0x43, 0x94, 0x2c, 0x21, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x73, 0xb9, 0x7a, 0x7b, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0x64, 0x76, 0x7a, 0x91, 0xb5, 0x31, 0x30,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x39, 0x97, 0x75, 0xbe, 0x7b, 0x64, 0xa3, 0xa3,
+    0xac, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0x7b, 0x7a, 0xc7,
+    0xc8, 0x36, 0x21, 0x26, 0x2b, 0x39, 0x33, 0x30,
+    0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xc8, 0xbb, 0x8b, 0x7b, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa3, 0x64, 0x64,
+    0x76, 0x85, 0xbf, 0xb5, 0x34, 0x2b, 0x27, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0xc9, 0x63, 0x7e, 0x7a, 0x6d, 0xbe, 0x5b,
+    0x76, 0x7b, 0x64, 0x64, 0xa3, 0xac, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xac, 0x76, 0x85, 0xb9,
+    0x79, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xca, 0xbb, 0x75, 0x76, 0xa3, 0xa4,
+    0xa4, 0xa4, 0xac, 0xa3, 0x64, 0x76, 0xbe, 0x8b,
+    0xb6, 0xb5, 0x2f, 0x35, 0x30, 0x24, 0x22, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x27, 0x31, 0xcb, 0xc9, 0xbb, 0x74, 0x63, 0x90,
+    0x7e, 0x75, 0x8b, 0x6d, 0xbe, 0x76, 0x64, 0xa3,
+    0xac, 0xac, 0xac, 0xac, 0x64, 0x7a, 0x84, 0xcc,
+    0x79, 0xa0, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xc8, 0xcc, 0x63, 0x6d, 0x7b, 0x64,
+    0xac, 0xa3, 0x64, 0x7b, 0xbe, 0x75, 0x63, 0x96,
+    0x38, 0x39, 0x2a, 0x24, 0x23, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x28, 0x27, 0x35, 0x2d, 0x41, 0xb5, 0xc5, 0x8f,
+    0xb9, 0xbb, 0xc7, 0x74, 0x84, 0x90, 0x85, 0x6d,
+    0x5b, 0x7b, 0x7b, 0xab, 0x6d, 0x90, 0xb9, 0xcd,
+    0xca, 0x22, 0x36, 0x36, 0x28, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x25, 0x36,
+    0x36, 0x21, 0xb4, 0x80, 0xc7, 0x7e, 0x6d, 0x76,
+    0xab, 0x76, 0x6d, 0x85, 0x63, 0xb9, 0xb5, 0x34,
+    0x33, 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x24, 0x27, 0x2a, 0x35, 0x2e, 0x2f,
+    0x41, 0xce, 0xcf, 0x6c, 0x80, 0xcc, 0xb9, 0x74,
+    0x84, 0x90, 0x75, 0x7e, 0x74, 0x8f, 0xcd, 0x79,
+    0xc6, 0x2b, 0x9d, 0x41, 0x2f, 0x34, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x34, 0x2f, 0x38,
+    0x4d, 0x37, 0xd0, 0xd1, 0x8f, 0x74, 0x63, 0x7e,
+    0x75, 0x7e, 0x63, 0xc7, 0x88, 0xc4, 0x31, 0x2a,
+    0x24, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x22, 0x23, 0x24, 0x26, 0x30,
+    0x33, 0x39, 0x2e, 0x51, 0x41, 0xb2, 0x6c, 0xd1,
+    0x80, 0xcc, 0xcc, 0xcc, 0xd2, 0xd1, 0xb7, 0xd3,
+    0x41, 0x34, 0x35, 0x32, 0x30, 0x27, 0x27, 0x27,
+    0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x2a,
+    0x2b, 0x34, 0xd4, 0xca, 0xd5, 0x8f, 0xbb, 0xc7,
+    0xc7, 0xbb, 0xcc, 0x6c, 0x41, 0x39, 0x27, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22,
+    0x28, 0x24, 0x26, 0x2a, 0x33, 0x2c, 0x2f, 0x41,
+    0xd6, 0xb7, 0x79, 0x79, 0x79, 0xca, 0xd7, 0x51,
+    0x39, 0x30, 0x24, 0x23, 0x22, 0x22, 0x22, 0x22,
+    0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23,
+    0x24, 0x2a, 0x31, 0xd8, 0xc8, 0x79, 0xd1, 0x80,
+    0xd5, 0xba, 0xd9, 0x2f, 0x35, 0x26, 0x23, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x22, 0x23, 0x28, 0x25, 0x30, 0x2b,
+    0x31, 0x2f, 0xd4, 0xd8, 0xd8, 0x2f, 0x2e, 0x33,
+    0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x27, 0x35, 0x34, 0xd8, 0xd8, 0xd8,
+    0xda, 0xd4, 0x2e, 0x33, 0x25, 0x23, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x23, 0x28,
+    0x26, 0x30, 0x32, 0x2b, 0x33, 0x2a, 0x26, 0x28,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x25, 0x30, 0x33, 0x35, 0x35,
+    0x2b, 0x2a, 0x26, 0x28, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x21, 0x22, 0x23, 0x28, 0x28, 0x23, 0x22, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x23, 0x28, 0x24, 0x24,
+    0x28, 0x23, 0x22, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 };
 
-#define INCLUDE_LINUX_LOGOBW
-#define INCLUDE_LINUX_LOGO16
-#include <linux/linux_logo.h>
-
-#else
+#endif /* INCLUDE_LINUX_LOGO_DATA */
 
-/* prototypes only */
-extern unsigned char linux_logo_red[];
-extern unsigned char linux_logo_green[];
-extern unsigned char linux_logo_blue[];
-extern unsigned char linux_logo[];
-extern unsigned char linux_logo_bw[];
-extern unsigned char linux_logo16_red[];
-extern unsigned char linux_logo16_green[];
-extern unsigned char linux_logo16_blue[];
-extern unsigned char linux_logo16[];
+#include <linux/linux_logo.h>
 
-#endif
diff -u --recursive --new-file v2.4.5/linux/include/asm-mips/termios.h linux/include/asm-mips/termios.h
--- v2.4.5/linux/include/asm-mips/termios.h	Sat Feb  3 20:00:45 2001
+++ linux/include/asm-mips/termios.h	Mon Jun 11 19:15:27 2001
@@ -101,6 +101,7 @@
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14	/* synchronous PPP */
+#define N_HCI		15  /* Bluetooth HCI UART */
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-mips64/linux_logo.h linux/include/asm-mips64/linux_logo.h
--- v2.4.5/linux/include/asm-mips64/linux_logo.h	Sat May 13 08:31:25 2000
+++ linux/include/asm-mips64/linux_logo.h	Mon Jun 11 19:15:27 2001
@@ -24,918 +24,897 @@
 
 #define linux_logo_banner "Linux/MIPS64 version " UTS_RELEASE
 
-#define LINUX_LOGO_COLORS 212
+#define __HAVE_ARCH_LINUX_LOGO
+
+#define LINUX_LOGO_COLORS	187
 
 #ifdef INCLUDE_LINUX_LOGO_DATA
 
 unsigned char linux_logo_red[] __initdata = {
-  0x03, 0x82, 0xE9, 0xBF, 0x42, 0xC9, 0x7E, 0xC0,
-  0xE9, 0xE3, 0xC2, 0x24, 0xA4, 0x65, 0xEC, 0xC4,
-  0x82, 0x9F, 0xF3, 0x12, 0x5F, 0xA0, 0xC2, 0xED,
-  0x3E, 0xD5, 0xDB, 0xA0, 0x1C, 0xF4, 0xEB, 0xA4,
-  0xCD, 0x0A, 0x9A, 0x51, 0xCC, 0xBE, 0xC0, 0xBA,
-  0x74, 0xDC, 0xAA, 0xF6, 0xD3, 0xC5, 0xE6, 0x26,
-  0xC2, 0x83, 0x38, 0xEA, 0x49, 0xB0, 0xED, 0xE5,
-  0xF4, 0x96, 0x96, 0x1B, 0xFA, 0xCC, 0xF2, 0x0F,
-  0xCD, 0xE5, 0xF4, 0xD3, 0x50, 0x7A, 0xB5, 0xDE,
-  0xD5, 0xB6, 0x60, 0x0A, 0x6A, 0xEA, 0xD4, 0xEB,
-  0xC1, 0xCA, 0xEA, 0xEC, 0x2A, 0x96, 0x95, 0xDC,
-  0xE4, 0xCE, 0xEC, 0x1E, 0xDC, 0x8A, 0xD1, 0xF6,
-  0x3C, 0x5E, 0xC6, 0xB4, 0xB2, 0xAC, 0xBA, 0x9E,
-  0x0F, 0x59, 0xBA, 0xFA, 0xCC, 0xBF, 0x82, 0xCE,
-  0xE6, 0x4F, 0xAA, 0x4C, 0xCA, 0x8E, 0x8E, 0xDF,
-  0x2C, 0xB6, 0x3B, 0xDE, 0xCE, 0xEE, 0x46, 0x4A,
-  0x6F, 0x7A, 0x82, 0xE4, 0xAA, 0x88, 0xE2, 0xCE,
-  0xAE, 0xB6, 0x70, 0xC2, 0x9A, 0xDA, 0x35, 0x9E,
-  0x95, 0xC0, 0x7E, 0x8C, 0xC2, 0xB6, 0xCE, 0xB9,
-  0xD5, 0xAA, 0xC1, 0xF4, 0xC7, 0xB6, 0xB6, 0xA3,
-  0xF2, 0x68, 0xDB, 0x76, 0xDC, 0x57, 0xD3, 0xA8,
-  0xC0, 0xEF, 0x46, 0xF4, 0x2F, 0xD7, 0x53, 0x36,
-  0xE6, 0xA7, 0xCA, 0xCB, 0x7E, 0xE4, 0x86, 0x9A,
-  0xCE, 0x94, 0xB4, 0x1D, 0xDA, 0xCE, 0x6C, 0xE6,
-  0x9E, 0xC6, 0xDA, 0x16, 0xFA, 0xAA, 0x56, 0xB6,
-  0xFE, 0x6E, 0xEA, 0xCE, 0xE5, 0xCC, 0xDB, 0xD3,
-  0xED, 0xDC, 0xF4, 0x72
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65,
+    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+    0xc3, 0x65, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x76, 0x79,
+    0x62, 0x36, 0x9a, 0xe2, 0xec, 0xe1, 0xb8, 0xd7,
+    0xaf, 0x25, 0xbc, 0xc0, 0xef, 0xea, 0xe8, 0xe8,
+    0xf5, 0xf1, 0xda, 0xd3, 0x79, 0xdb, 0xf4, 0xf6,
+    0xf6, 0xf6, 0xe2, 0x3d, 0xb4, 0xce, 0xe6, 0xee,
+    0xf6, 0x68, 0xd8, 0xec, 0xf5, 0xc6, 0xc8, 0x9c,
+    0x89, 0xd2, 0xee, 0xcb, 0xb9, 0xd2, 0x66, 0x5e,
+    0x8b, 0xbe, 0xa8, 0xd5, 0xca, 0xb6, 0xae, 0x9c,
+    0xc5, 0xbe, 0xbe, 0xca, 0x90, 0xb2, 0x9a, 0xa8,
+    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x8d,
+    0x12, 0x4a, 0x8e, 0xf2, 0xf6, 0xee, 0xb5, 0xe4,
+    0xf1, 0x26, 0x9a, 0xea, 0xf6, 0xe0, 0xd2, 0x16,
+    0x9a, 0x2e, 0x70, 0xd6, 0x46, 0x7c, 0xb4, 0x62,
+    0xd6, 0xa3, 0x74, 0xa7, 0xa2, 0xca, 0xe0, 0xae,
+    0xbe, 0xce, 0xa3, 0x8e, 0x6d, 0x8e, 0x32, 0xaf,
+    0x50, 0x9e, 0x5b, 0x8a, 0x98, 0x82, 0x7a, 0x82,
+    0x56, 0x7c, 0x8a, 0x56, 0x5e, 0x86, 0x6a, 0x52,
+    0x59, 0x64, 0x5e,
 };
 
 unsigned char linux_logo_green[] __initdata = {
-  0x03, 0x82, 0xC4, 0x83, 0x42, 0xA2, 0x4A, 0xA4,
-  0xE5, 0xA6, 0xC2, 0x24, 0xA4, 0x65, 0xB4, 0x94,
-  0x66, 0x87, 0xB6, 0x12, 0x44, 0x6C, 0x96, 0xD4,
-  0x36, 0x95, 0xB2, 0x92, 0x0E, 0xF4, 0xBC, 0x77,
-  0xA5, 0x0A, 0x92, 0x52, 0xB4, 0x9A, 0x8C, 0xB2,
-  0x74, 0xC2, 0x8E, 0xBD, 0xA2, 0xCA, 0xD2, 0x12,
-  0xB6, 0x61, 0x24, 0xDA, 0x33, 0x79, 0xCB, 0xAC,
-  0xDA, 0x84, 0x7A, 0x1B, 0xFA, 0x8D, 0xBE, 0x06,
-  0x93, 0xBB, 0xBC, 0xAB, 0x44, 0x62, 0x83, 0xDA,
-  0x9B, 0xA2, 0x4C, 0x04, 0x6A, 0xB6, 0xC8, 0xBD,
-  0x8D, 0xB6, 0xAD, 0xEC, 0x2A, 0x68, 0x62, 0x9D,
-  0xC4, 0xC4, 0xB4, 0x13, 0xA3, 0x8A, 0xD2, 0xD6,
-  0x3C, 0x5D, 0x8C, 0x7E, 0x82, 0xAC, 0x96, 0x7E,
-  0x0D, 0x5A, 0xBA, 0xBB, 0xCC, 0xBE, 0x76, 0xB6,
-  0xDE, 0x4E, 0x9A, 0x3C, 0xBE, 0x8E, 0x6E, 0xCB,
-  0x1C, 0xAA, 0x2E, 0xBE, 0xAA, 0xDE, 0x3E, 0x4B,
-  0x4D, 0x7A, 0x54, 0xE4, 0x8E, 0x6E, 0xCA, 0x9B,
-  0x70, 0x9E, 0x5A, 0xAA, 0x9A, 0xBE, 0x34, 0x9E,
-  0x71, 0x9E, 0x7E, 0x5F, 0xAA, 0x8A, 0xBE, 0x91,
-  0xCE, 0x88, 0x92, 0xDB, 0xC6, 0xAB, 0x8A, 0x72,
-  0xE2, 0x44, 0xC3, 0x54, 0xAA, 0x45, 0xBB, 0x92,
-  0xBA, 0xC4, 0x46, 0xCA, 0x2D, 0xD6, 0x3B, 0x1A,
-  0xC2, 0x7E, 0xA6, 0xCB, 0x7A, 0xDC, 0x86, 0x72,
-  0xB6, 0x94, 0xB4, 0x1C, 0xBC, 0xAE, 0x4C, 0xD6,
-  0x62, 0x86, 0xD3, 0x16, 0xF6, 0x7A, 0x55, 0x79,
-  0xFE, 0x6E, 0xC6, 0xC6, 0xAA, 0x93, 0xDC, 0x9D,
-  0xAE, 0xA4, 0xD4, 0x56
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65,
+    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+    0xc3, 0x62, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x62, 0x5c,
+    0x4e, 0x26, 0x72, 0xaa, 0xba, 0xaf, 0x90, 0xae,
+    0x92, 0x1a, 0xa4, 0x85, 0xb6, 0xbe, 0xc3, 0xc8,
+    0xcf, 0xd0, 0xc2, 0xce, 0x57, 0xa2, 0xd6, 0xda,
+    0xda, 0xd7, 0xb8, 0x2a, 0x7b, 0x91, 0xae, 0xca,
+    0xda, 0x45, 0x9e, 0xb2, 0xd7, 0x9b, 0x90, 0x76,
+    0x5c, 0xa2, 0xbe, 0xa6, 0x85, 0x96, 0x4e, 0x46,
+    0x66, 0x92, 0x7a, 0x9a, 0x96, 0x9d, 0x9a, 0x6b,
+    0x8a, 0x8e, 0xb2, 0xca, 0x90, 0xa6, 0x79, 0x7c,
+    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x8d,
+    0x0e, 0x36, 0x86, 0xba, 0xbe, 0xcc, 0x8e, 0xb8,
+    0xc4, 0x1e, 0x8e, 0xae, 0xba, 0xb2, 0xa6, 0x12,
+    0x7a, 0x20, 0x64, 0xaa, 0x2f, 0x70, 0x85, 0x46,
+    0xa6, 0x6e, 0x51, 0x72, 0x92, 0xa2, 0xa6, 0x87,
+    0x96, 0xa2, 0x85, 0x7a, 0x6a, 0x6e, 0x22, 0x76,
+    0x36, 0x76, 0x3c, 0x6e, 0x63, 0x53, 0x66, 0x62,
+    0x42, 0x50, 0x56, 0x42, 0x56, 0x56, 0x56, 0x3e,
+    0x51, 0x52, 0x56,
 };
 
 unsigned char linux_logo_blue[] __initdata = {
-  0x04, 0x84, 0x10, 0x0C, 0x41, 0x14, 0x04, 0x78,
-  0xC7, 0x0E, 0xC4, 0x24, 0xA4, 0x64, 0x0C, 0x0D,
-  0x17, 0x24, 0x0D, 0x13, 0x11, 0x07, 0x40, 0x22,
-  0x0C, 0x0C, 0x11, 0x78, 0x06, 0xF4, 0x0B, 0x0A,
-  0x47, 0x0B, 0x7C, 0x54, 0x6C, 0x0C, 0x0D, 0x9C,
-  0x73, 0x54, 0x14, 0x0C, 0x0F, 0xC7, 0x94, 0x04,
-  0x94, 0x17, 0x0A, 0x6C, 0x08, 0x0F, 0x14, 0x0B,
-  0x12, 0x68, 0x28, 0x11, 0xFA, 0x0A, 0x34, 0x09,
-  0x0A, 0x2F, 0x15, 0x19, 0x14, 0x3C, 0x06, 0xC4,
-  0x0B, 0x84, 0x24, 0x08, 0x69, 0x38, 0xBC, 0x15,
-  0x1F, 0xA0, 0x0A, 0xEC, 0x2A, 0x0C, 0x0C, 0x0C,
-  0x2C, 0xA0, 0x15, 0x07, 0x0B, 0x8C, 0xD3, 0x10,
-  0x3B, 0x5C, 0x0C, 0x04, 0x3C, 0xAC, 0x54, 0x1C,
-  0x0B, 0x5B, 0xBB, 0x0A, 0xC1, 0xBB, 0x5C, 0x3C,
-  0xBC, 0x4D, 0x74, 0x10, 0x8C, 0x8C, 0x14, 0x91,
-  0x0C, 0x74, 0x17, 0x0C, 0x48, 0x9C, 0x3C, 0x4C,
-  0x09, 0x7C, 0x05, 0xE4, 0x34, 0x38, 0x6C, 0x11,
-  0x08, 0x7C, 0x18, 0x2C, 0x9C, 0x4C, 0x34, 0x9C,
-  0x29, 0x54, 0x7C, 0x0C, 0x78, 0x18, 0x9C, 0x14,
-  0xBA, 0x30, 0x27, 0x31, 0xC2, 0x97, 0x24, 0x09,
-  0xB4, 0x04, 0x87, 0x0C, 0x14, 0x1F, 0x7C, 0x64,
-  0xB0, 0x0F, 0x45, 0x10, 0x2C, 0xD4, 0x0A, 0x04,
-  0x44, 0x1F, 0x2C, 0xCC, 0x7C, 0xD8, 0x84, 0x0C,
-  0x8C, 0x94, 0xB4, 0x1D, 0x20, 0x5C, 0x18, 0xB4,
-  0x04, 0x09, 0xBC, 0x14, 0xF4, 0x08, 0x54, 0x07,
-  0xFC, 0x6C, 0x24, 0xB4, 0x15, 0x18, 0xDB, 0x17,
-  0x17, 0x18, 0x21, 0x24
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x01, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x06, 0x65,
+    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+    0xc3, 0x59, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x2e, 0x08,
+    0x0a, 0x06, 0x0a, 0x0b, 0x0b, 0x0f, 0x0c, 0x0f,
+    0x3d, 0x09, 0x73, 0x09, 0x0d, 0x0a, 0x10, 0x1e,
+    0x2d, 0x13, 0x86, 0xba, 0x19, 0x0a, 0x36, 0x3c,
+    0x26, 0x14, 0x0d, 0x06, 0x07, 0x0a, 0x0b, 0x0f,
+    0x4a, 0x06, 0x0a, 0x0c, 0x2b, 0x0a, 0x0b, 0x0a,
+    0x06, 0x0a, 0x0a, 0x11, 0x0b, 0x0a, 0x0a, 0x1e,
+    0x0f, 0x0d, 0x0a, 0x0b, 0x22, 0x6a, 0x72, 0x0b,
+    0x0b, 0x22, 0x90, 0xca, 0x90, 0x92, 0x3c, 0x2c,
+    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x8d,
+    0x06, 0x0e, 0x6a, 0x0e, 0x0e, 0x5b, 0x2c, 0x3e,
+    0x0e, 0x0a, 0x5a, 0x0d, 0x0e, 0x3e, 0x0a, 0x06,
+    0x2e, 0x06, 0x4e, 0x36, 0x06, 0x58, 0x24, 0x06,
+    0x3a, 0x08, 0x08, 0x07, 0x5e, 0x45, 0x0a, 0x32,
+    0x2e, 0x2a, 0x43, 0x48, 0x5f, 0x2e, 0x06, 0x06,
+    0x07, 0x24, 0x06, 0x32, 0x06, 0x06, 0x46, 0x2e,
+    0x22, 0x06, 0x06, 0x1e, 0x4c, 0x06, 0x3a, 0x22,
+    0x42, 0x34, 0x42,
 };
 
 unsigned char linux_logo[] __initdata = {
-  0xBC, 0xAC, 0x7D, 0x95, 0xAF, 0x85, 0x2C, 0x2C,
-  0xAC, 0xD9, 0x95, 0x7D, 0x95, 0xAC, 0x2C, 0xAF,
-  0x7D, 0x48, 0xB2, 0xAC, 0x85, 0xDA, 0xDA, 0x2C,
-  0x7D, 0x48, 0x21, 0x2C, 0x8D, 0x2A, 0x8A, 0xDA,
-  0x85, 0x2C, 0xD9, 0xAC, 0x2C, 0x2C, 0xD9, 0xD9,
-  0xAF, 0x85, 0x85, 0x85, 0x8D, 0xBC, 0x2A, 0x2A,
-  0xBC, 0x8C, 0xBC, 0xAC, 0x7D, 0x95, 0xAF, 0x85,
-  0x2C, 0x2C, 0xAC, 0xD9, 0x95, 0x7D, 0x95, 0xAC,
-  0x2C, 0xAF, 0x7D, 0x48, 0xB2, 0xAC, 0x85, 0xDA,
-  0xDA, 0x2C, 0x7D, 0x48, 0x21, 0x2C, 0x8D, 0x2A,
-  0xAF, 0xA1, 0x48, 0x7D, 0xAF, 0x2C, 0x2C, 0xAC,
-  0xD9, 0xD9, 0x95, 0x7D, 0x95, 0xAC, 0xD9, 0x7D,
-  0x48, 0xE9, 0x21, 0xAF, 0xDA, 0xDA, 0x85, 0x2C,
-  0xD9, 0xD9, 0xAC, 0xDA, 0x8A, 0xDA, 0x85, 0x2C,
-  0x2C, 0xAC, 0xD9, 0xAC, 0xAF, 0xAF, 0x2C, 0x2C,
-  0x2C, 0x85, 0x2C, 0x2C, 0x85, 0xDA, 0xDA, 0xDA,
-  0xDA, 0xDA, 0xAF, 0xA1, 0x48, 0x7D, 0xAF, 0x2C,
-  0x2C, 0xAC, 0xD9, 0xD9, 0x95, 0x7D, 0x95, 0xAC,
-  0xD9, 0x7D, 0x48, 0xE9, 0x21, 0xAF, 0xDA, 0xDA,
-  0x85, 0x2C, 0xD9, 0xD9, 0xAC, 0xDA, 0x8A, 0xDA,
-  0x7D, 0x48, 0x48, 0x7D, 0x2C, 0x85, 0x2C, 0xAF,
-  0xD9, 0xD9, 0x7D, 0x95, 0xD9, 0xD9, 0xD9, 0x7D,
-  0xB2, 0x21, 0xD9, 0x85, 0xDA, 0xDA, 0x85, 0x2C,
-  0xAF, 0x2C, 0x2C, 0xDA, 0x85, 0x85, 0x2C, 0x2C,
-  0xAC, 0xD9, 0xD9, 0xAF, 0xDA, 0x85, 0x2C, 0x2C,
-  0x85, 0xDA, 0xDA, 0x85, 0x85, 0xDA, 0x85, 0x85,
-  0x85, 0xAF, 0x7D, 0x48, 0x48, 0x7D, 0x2C, 0x85,
-  0x2C, 0xAF, 0xD9, 0xD9, 0x7D, 0x95, 0xD9, 0xD9,
-  0xD9, 0x7D, 0xB2, 0x21, 0xD9, 0x85, 0xDA, 0xDA,
-  0x85, 0x2C, 0xAF, 0x2C, 0x2C, 0xDA, 0xDA, 0x85,
-  0xA1, 0xE9, 0x48, 0x95, 0x85, 0xDA, 0x85, 0xAF,
-  0xD9, 0xD9, 0x95, 0x95, 0xD9, 0xD9, 0x95, 0x95,
-  0xD9, 0xAC, 0x85, 0x85, 0xDA, 0xDA, 0x85, 0x2C,
-  0xAC, 0xAC, 0x2C, 0x2C, 0x85, 0x2C, 0x2C, 0xAC,
-  0xD9, 0xD9, 0x2C, 0x91, 0x41, 0x20, 0x6B, 0x20,
-  0x6B, 0x20, 0x6B, 0xAE, 0x2C, 0x85, 0x2C, 0x2C,
-  0xAC, 0xD9, 0xA1, 0xE9, 0x48, 0x95, 0x85, 0xDA,
-  0x85, 0xAF, 0xD9, 0xD9, 0x95, 0x95, 0xD9, 0xD9,
-  0x95, 0x95, 0xD9, 0xAC, 0x85, 0x85, 0xDA, 0xDA,
-  0x85, 0x2C, 0xAC, 0xAC, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xA1, 0xA1, 0xD6, 0xAF, 0xDA, 0xDA, 0x85, 0x2C,
-  0xD9, 0xD9, 0x95, 0x95, 0xD9, 0xD9, 0xD9, 0xD9,
-  0x2C, 0x2C, 0xDA, 0xDA, 0xDA, 0x85, 0x2C, 0xD9,
-  0xD9, 0xD9, 0xD9, 0xAC, 0xAC, 0xAC, 0xAF, 0xAC,
-  0x2C, 0xB2, 0x88, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x6B, 0x80, 0x85, 0x2C,
-  0xD9, 0xD6, 0xA1, 0xA1, 0xD6, 0xAF, 0xDA, 0xDA,
-  0x85, 0x2C, 0xD9, 0xD9, 0x95, 0x95, 0xD9, 0xD9,
-  0xD9, 0xD9, 0x2C, 0x2C, 0xDA, 0xDA, 0xDA, 0x85,
-  0x2C, 0xD9, 0xD9, 0xD9, 0xD9, 0xAF, 0xAF, 0xAF,
-  0xD6, 0xD6, 0xD9, 0x2C, 0xDA, 0xDA, 0x2C, 0xAC,
-  0xD9, 0x7D, 0x95, 0xD9, 0xD9, 0xD9, 0xAF, 0x2C,
-  0x85, 0x85, 0x85, 0x85, 0x2C, 0x2C, 0xAC, 0xD9,
-  0xD9, 0xD9, 0xAF, 0xAF, 0x2C, 0x2C, 0xAF, 0xDA,
-  0xAE, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x41, 0xE3, 0x20, 0x6B, 0x48,
-  0xAC, 0x95, 0xD6, 0xD6, 0xD9, 0x2C, 0xDA, 0xDA,
-  0x2C, 0xAC, 0xD9, 0x7D, 0x95, 0xD9, 0xD9, 0xD9,
-  0xAF, 0x2C, 0x85, 0x85, 0x85, 0x85, 0x2C, 0x2C,
-  0xAC, 0xD9, 0xD9, 0xD9, 0xAF, 0xAF, 0xAF, 0xAF,
-  0xD9, 0xD9, 0xD9, 0x2C, 0x85, 0x85, 0x2C, 0xD9,
-  0x7D, 0x21, 0xD6, 0xD9, 0xAF, 0x2C, 0x85, 0x85,
-  0x85, 0x85, 0x85, 0x85, 0x2C, 0xAF, 0xAF, 0xAC,
-  0xAF, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x89,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x74, 0x43, 0x80, 0x41, 0x20,
-  0x9F, 0x2C, 0xD9, 0xD9, 0xD9, 0x2C, 0x85, 0x85,
-  0x2C, 0xD9, 0x7D, 0x21, 0xD6, 0xD9, 0xAF, 0x2C,
-  0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x2C, 0xAF,
-  0xAF, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xD9, 0x7D, 0xD9, 0xAF, 0x85, 0x85, 0x2C, 0xD9,
-  0xB2, 0x21, 0x7D, 0xD9, 0xAF, 0x2C, 0x85, 0x85,
-  0x85, 0x2C, 0x2C, 0x2C, 0x2C, 0xAF, 0xAF, 0xAC,
-  0xAF, 0xAC, 0xAF, 0xAF, 0xAC, 0xAC, 0x85, 0x41,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xAE, 0x48, 0x89, 0x74, 0x41,
-  0x6B, 0xD6, 0xD9, 0x7D, 0xD9, 0xAF, 0x85, 0x85,
-  0x2C, 0xD9, 0xB2, 0x21, 0x7D, 0xD9, 0xAF, 0x2C,
-  0x85, 0x85, 0x85, 0x2C, 0x2C, 0x2C, 0x2C, 0xAF,
-  0xAF, 0xAC, 0xAF, 0xAC, 0xAC, 0x2C, 0xAF, 0xAC,
-  0x2C, 0x7D, 0xD9, 0x2C, 0xDA, 0x85, 0x2C, 0x7D,
-  0xB2, 0xD6, 0xD9, 0xAF, 0x85, 0x85, 0x85, 0x85,
-  0xAF, 0xAC, 0xAC, 0xAF, 0xAF, 0xAC, 0xAC, 0xD9,
-  0x95, 0x7D, 0x95, 0x95, 0xD9, 0xD9, 0x48, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x6B, 0xAE, 0xE6, 0x80, 0x2B, 0x88,
-  0x20, 0x33, 0xDA, 0x95, 0xD9, 0x2C, 0xDA, 0x85,
-  0x2C, 0x7D, 0xB2, 0xD6, 0xD9, 0xAF, 0x85, 0x85,
-  0x85, 0x85, 0xAF, 0xAC, 0xAC, 0xAF, 0xAF, 0xAC,
-  0xAC, 0xD9, 0x95, 0x95, 0x7D, 0x95, 0x95, 0xD9,
-  0x85, 0xD9, 0x2C, 0x85, 0xDA, 0xDA, 0xD9, 0x21,
-  0xA1, 0xD9, 0xAF, 0x2C, 0x85, 0xDA, 0x85, 0xAF,
-  0xD9, 0xD9, 0xAC, 0xAC, 0xAC, 0xD9, 0x7D, 0xD6,
-  0xD6, 0x7D, 0x95, 0xD9, 0xD9, 0x85, 0xDB, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xDB, 0xE3, 0x6B, 0x20, 0x20,
-  0x20, 0x20, 0xE9, 0xD9, 0x2C, 0x85, 0xDA, 0xDA,
-  0xD9, 0x21, 0xA1, 0xD9, 0xAF, 0x2C, 0x85, 0xDA,
-  0x85, 0xAF, 0xD9, 0xD9, 0xAC, 0xAC, 0xAC, 0xD9,
-  0x7D, 0xD6, 0xD6, 0x7D, 0x95, 0xD9, 0xD9, 0xD9,
-  0xDA, 0x2C, 0x85, 0xDA, 0xDA, 0x85, 0x95, 0x21,
-  0x21, 0xD9, 0x85, 0x85, 0x85, 0x2C, 0x2C, 0xD9,
-  0x95, 0x95, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9,
-  0xAC, 0xAC, 0x2C, 0xAF, 0x2C, 0x85, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x88, 0xDA, 0x85, 0xDA, 0xDA, 0x85,
-  0x95, 0x21, 0x21, 0xD9, 0x85, 0x85, 0x85, 0x2C,
-  0x2C, 0xD9, 0x95, 0x95, 0xD9, 0xD9, 0xD9, 0xD9,
-  0xD9, 0xD9, 0xD9, 0xAF, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xDA, 0x2C, 0x85, 0x85, 0x2C, 0xD9, 0xD6, 0xB2,
-  0x95, 0x2C, 0x85, 0x85, 0xAF, 0xAC, 0x95, 0x95,
-  0x7D, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0x2C, 0x85,
-  0x85, 0x85, 0x85, 0x85, 0x85, 0xAC, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xAC, 0x85, 0x85, 0x2C, 0xD9,
-  0xD6, 0xB2, 0x95, 0x2C, 0x85, 0x85, 0xAF, 0xAC,
-  0x95, 0x95, 0x7D, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9,
-  0x2C, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
-  0x85, 0x2C, 0x2C, 0x2C, 0xAC, 0x95, 0xD6, 0x7D,
-  0xD9, 0x2C, 0x2C, 0xAF, 0x95, 0x7D, 0x7D, 0x95,
-  0x95, 0xD9, 0xD9, 0x95, 0xD9, 0xD9, 0x2C, 0x85,
-  0xDA, 0xDA, 0xDA, 0x85, 0x85, 0x21, 0x20, 0x20,
-  0x6B, 0x41, 0xDB, 0x6B, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x41, 0xDB, 0xDB, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xE6, 0x2C, 0x2C, 0xAC, 0x95,
-  0xD6, 0x7D, 0xD9, 0x2C, 0x2C, 0xAF, 0x95, 0x7D,
-  0x7D, 0x95, 0x95, 0xD9, 0xD9, 0x95, 0xD9, 0xD9,
-  0x2C, 0x85, 0xDA, 0xDA, 0xDA, 0x85, 0x2C, 0x2C,
-  0x2C, 0xAF, 0xAC, 0xD9, 0x95, 0xD6, 0xD6, 0xD9,
-  0x2C, 0x2C, 0x2C, 0xD9, 0xD6, 0xD6, 0xD9, 0xAF,
-  0xAC, 0x95, 0xD6, 0x7D, 0x7D, 0xD9, 0x2C, 0x85,
-  0xDA, 0xDA, 0x2C, 0xAF, 0xAF, 0x21, 0x20, 0x20,
-  0x88, 0x2B, 0x88, 0x74, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0xAE, 0x2D, 0x2D, 0x74, 0x74, 0x88, 0x20,
-  0x20, 0x20, 0x20, 0x80, 0xAC, 0xD9, 0x95, 0xD6,
-  0xD6, 0xD9, 0x2C, 0x2C, 0x2C, 0xD9, 0xD6, 0xD6,
-  0xD9, 0xAF, 0xAC, 0x95, 0xD6, 0x7D, 0x7D, 0xD9,
-  0x2C, 0xDA, 0xDA, 0x85, 0x2C, 0xAF, 0xAF, 0xAF,
-  0x2C, 0xAF, 0xD9, 0x95, 0xD6, 0xD6, 0x95, 0xAF,
-  0x2C, 0x2C, 0xD9, 0x95, 0xD6, 0x95, 0xAF, 0x2C,
-  0xAC, 0x7D, 0x21, 0x95, 0xD9, 0x2C, 0x85, 0x85,
-  0x85, 0xAF, 0xD9, 0x95, 0xD9, 0x7D, 0x20, 0x33,
-  0x7D, 0x8A, 0x7D, 0x5B, 0x6B, 0x20, 0x20, 0x6B,
-  0xE6, 0xD9, 0x85, 0x2A, 0xDA, 0x2B, 0x41, 0x20,
-  0x20, 0x20, 0x6B, 0x74, 0xD9, 0x95, 0xD6, 0xD6,
-  0x95, 0xAF, 0x2C, 0x2C, 0xD9, 0x95, 0xD6, 0x95,
-  0xAF, 0x2C, 0xAC, 0x7D, 0x21, 0x95, 0xD9, 0x2C,
-  0x85, 0x85, 0x85, 0x2C, 0xD9, 0xD9, 0xD9, 0xD9,
-  0x85, 0xD9, 0x7D, 0x21, 0x21, 0x7D, 0xAC, 0x2C,
-  0x2C, 0xAC, 0xD9, 0x7D, 0xD9, 0xAF, 0x2C, 0x85,
-  0xAC, 0x7D, 0x7D, 0xAC, 0x85, 0xDA, 0x8A, 0xDA,
-  0x85, 0xAF, 0xD9, 0x7D, 0xD9, 0x95, 0x20, 0x91,
-  0xBC, 0x73, 0xEE, 0x7D, 0x20, 0x20, 0x20, 0x80,
-  0x4D, 0x3D, 0x73, 0x73, 0xA3, 0xD6, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x2B, 0x7D, 0x21, 0x21, 0x7D,
-  0xAC, 0x2C, 0x2C, 0xAC, 0xD9, 0x7D, 0xD9, 0xAF,
-  0x2C, 0x85, 0xAC, 0x7D, 0x7D, 0xAC, 0x85, 0xDA,
-  0x8A, 0x8A, 0x85, 0xAC, 0xD9, 0x7D, 0xD9, 0xAC,
-  0x2C, 0xD9, 0xD6, 0xB2, 0xB2, 0x7D, 0xAF, 0x85,
-  0x2C, 0xD9, 0x95, 0x95, 0xAF, 0x2C, 0x2C, 0x2C,
-  0xD9, 0xD9, 0xAC, 0x85, 0x8D, 0x2A, 0x2A, 0xDA,
-  0xAF, 0xD9, 0x95, 0x95, 0xD9, 0xAC, 0x20, 0xAF,
-  0x2C, 0xE6, 0x8D, 0x73, 0xE3, 0x20, 0x20, 0x48,
-  0x5C, 0xDA, 0x5B, 0x43, 0xBC, 0x73, 0x2B, 0x20,
-  0x20, 0x20, 0x20, 0x41, 0xD6, 0xB2, 0xB2, 0x7D,
-  0xAF, 0x85, 0x2C, 0xD9, 0x95, 0x95, 0xAF, 0x2C,
-  0x2C, 0x2C, 0xD9, 0xD9, 0xAC, 0x85, 0x8A, 0x2A,
-  0x8D, 0xDA, 0xAF, 0xD9, 0x95, 0x95, 0xD9, 0xAF,
-  0xAC, 0xD9, 0xD6, 0xB2, 0x21, 0xD9, 0x2C, 0x85,
-  0x2C, 0xD9, 0x95, 0xD9, 0xAF, 0x2C, 0x2C, 0xAC,
-  0xAC, 0xAF, 0x85, 0x8D, 0xBC, 0xBC, 0xDA, 0xD9,
-  0xD6, 0xA1, 0xA1, 0x21, 0xD9, 0xAC, 0x20, 0x2A,
-  0xCC, 0xAE, 0x9F, 0xE4, 0xAE, 0x5B, 0x74, 0xA1,
-  0xE4, 0xAE, 0x20, 0x9F, 0x89, 0xE8, 0xE6, 0x20,
-  0x20, 0x20, 0x20, 0x41, 0xD6, 0xB2, 0x21, 0xD9,
-  0x2C, 0x85, 0x2C, 0xD9, 0x95, 0xD9, 0xAF, 0x2C,
-  0x2C, 0xAC, 0xAC, 0xAF, 0x85, 0x8D, 0xBC, 0x2A,
-  0xDA, 0xD9, 0xD6, 0xA1, 0xA1, 0x21, 0xD9, 0xD9,
-  0xD9, 0x95, 0x21, 0xA1, 0x21, 0xAC, 0x85, 0x85,
-  0xAC, 0xD9, 0xD9, 0xAF, 0x2C, 0x2C, 0xAF, 0xAC,
-  0xAF, 0x85, 0x8A, 0x2A, 0x2A, 0xDA, 0xD9, 0xA1,
-  0x48, 0xE9, 0x48, 0x21, 0x95, 0xAC, 0x20, 0x2A,
-  0xDB, 0x41, 0x74, 0xBC, 0x2B, 0x7B, 0x7B, 0x80,
-  0x73, 0x41, 0x20, 0x6B, 0x2B, 0xE8, 0x2D, 0x20,
-  0x20, 0x20, 0x20, 0x33, 0x21, 0xA1, 0x21, 0xAC,
-  0x85, 0x85, 0xAC, 0xD9, 0xD9, 0xAF, 0x2C, 0x2C,
-  0xAF, 0xAC, 0xAF, 0x85, 0x8A, 0xBC, 0x2A, 0xDA,
-  0xD9, 0xA1, 0x48, 0xE9, 0x48, 0x21, 0xD9, 0xD9,
-  0xA1, 0xB2, 0xB2, 0x48, 0xD6, 0xAC, 0x2C, 0x2C,
-  0xD9, 0x95, 0xAF, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C,
-  0x85, 0x8A, 0x8D, 0x8D, 0x85, 0x95, 0xA1, 0x6C,
-  0x6C, 0x48, 0xD6, 0xD9, 0x2C, 0x85, 0x20, 0x2C,
-  0x89, 0x20, 0x3C, 0xB9, 0xA7, 0x63, 0xD2, 0xB9,
-  0xC6, 0x9A, 0x20, 0x20, 0x43, 0x5C, 0xE6, 0x20,
-  0x20, 0x20, 0x20, 0x33, 0xB2, 0x48, 0xD6, 0xAC,
-  0x2C, 0x2C, 0xD9, 0x95, 0xAF, 0x2C, 0x2C, 0x2C,
-  0x2C, 0x2C, 0x85, 0x8A, 0x8D, 0x8D, 0x85, 0x95,
-  0xA1, 0x6C, 0x6C, 0x48, 0xD6, 0xD9, 0xAF, 0xAC,
-  0xA1, 0xD6, 0x7D, 0xB2, 0xD6, 0xAF, 0x85, 0x85,
-  0xD9, 0x95, 0x2C, 0x85, 0xDA, 0x85, 0x85, 0x2C,
-  0x85, 0x8A, 0x8D, 0xDA, 0xD9, 0x48, 0x81, 0x2D,
-  0x48, 0xD6, 0xD9, 0xAC, 0x2C, 0x85, 0x20, 0x2D,
-  0xEE, 0x93, 0xD1, 0xA7, 0x3E, 0x3E, 0x3A, 0x25,
-  0x56, 0xAB, 0xAA, 0xC5, 0xEE, 0xEE, 0x33, 0x20,
-  0x20, 0x20, 0x20, 0x41, 0xD9, 0xB2, 0xD6, 0xAF,
-  0x85, 0x85, 0xD9, 0x95, 0x2C, 0x85, 0xDA, 0x85,
-  0x85, 0x2C, 0x85, 0x8A, 0x8D, 0xDA, 0xD9, 0x48,
-  0x81, 0x2D, 0x48, 0xD6, 0xD9, 0xAF, 0x2C, 0x2C,
-  0xAC, 0xAF, 0xD9, 0x7D, 0xD6, 0x2C, 0x85, 0x2C,
-  0xD9, 0xD9, 0x2C, 0xDA, 0xDA, 0xDA, 0x2C, 0x2C,
-  0x85, 0x8D, 0x8D, 0x2C, 0x21, 0x2D, 0x2D, 0xE9,
-  0xD6, 0xD9, 0xAF, 0x2C, 0x85, 0xDA, 0x20, 0xE3,
-  0xB4, 0xBE, 0xF1, 0x3E, 0x9B, 0x22, 0x56, 0xF2,
-  0xBB, 0x7F, 0x56, 0xDC, 0x8F, 0x5A, 0x5F, 0x20,
-  0x20, 0x20, 0x20, 0x6B, 0x2C, 0x7D, 0xD6, 0x2C,
-  0x85, 0x2C, 0xD9, 0xD9, 0x2C, 0xDA, 0xDA, 0xDA,
-  0x2C, 0x2C, 0x85, 0x8D, 0x8A, 0x85, 0x21, 0x2D,
-  0x2D, 0xE9, 0xD6, 0xD9, 0xAF, 0x2C, 0x85, 0x85,
-  0x2A, 0x85, 0xAC, 0x95, 0x95, 0x2C, 0x85, 0x85,
-  0xAC, 0xAF, 0x85, 0xDA, 0xDA, 0x85, 0x2C, 0x2C,
-  0xDA, 0x8A, 0x8A, 0xAF, 0xA1, 0x2D, 0xE9, 0xD6,
-  0xD9, 0xAC, 0x85, 0x85, 0x85, 0xDA, 0x20, 0x52,
-  0x55, 0xED, 0x57, 0x3E, 0x22, 0x56, 0x37, 0xBB,
-  0xBB, 0x58, 0x7F, 0x7F, 0x56, 0x5E, 0xC5, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x2C, 0x95, 0x95, 0x2C,
-  0x85, 0x85, 0xAC, 0xAF, 0x85, 0xDA, 0xDA, 0x85,
-  0x2C, 0x2C, 0xDA, 0x8D, 0xDA, 0xAF, 0xA1, 0x2D,
-  0xE9, 0xD6, 0xD9, 0xAF, 0x2C, 0x85, 0x85, 0x85,
-  0xCD, 0xAF, 0xD9, 0x95, 0xD9, 0x2C, 0xDA, 0x85,
-  0xAF, 0xD9, 0x85, 0xDA, 0x85, 0x2C, 0xAC, 0xAF,
-  0x85, 0x8A, 0x85, 0xD9, 0x48, 0x48, 0xB2, 0x95,
-  0x95, 0xAC, 0x2C, 0x85, 0xDA, 0xDA, 0x6B, 0xB3,
-  0x46, 0x7C, 0x2E, 0x9B, 0x22, 0x56, 0xBB, 0x37,
-  0x58, 0x58, 0xF2, 0x3A, 0x46, 0x63, 0x64, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x2D, 0x95, 0xD9, 0x2C,
-  0xDA, 0x85, 0xAF, 0xD9, 0x85, 0xDA, 0x85, 0x2C,
-  0xAC, 0xAF, 0x85, 0xDA, 0x85, 0xD9, 0x48, 0x48,
-  0xB2, 0x95, 0x95, 0xD9, 0x85, 0xDA, 0x85, 0x85,
-  0xBC, 0xB2, 0xB2, 0x7D, 0xD9, 0x2C, 0xDA, 0x85,
-  0xAF, 0xD9, 0x85, 0xDA, 0x85, 0x85, 0xAF, 0x2C,
-  0x85, 0xDA, 0x2C, 0x7D, 0xA1, 0x48, 0xB2, 0x21,
-  0xD6, 0xD9, 0x85, 0xDA, 0x85, 0xDA, 0x41, 0x51,
-  0xB7, 0xEC, 0x2E, 0x22, 0x56, 0x37, 0xBB, 0xF2,
-  0x37, 0xEA, 0x2F, 0x2F, 0x77, 0xA7, 0x38, 0x20,
-  0x20, 0x6B, 0x20, 0x20, 0x5B, 0x2C, 0xD9, 0x2C,
-  0xDA, 0x85, 0xAF, 0xD9, 0x85, 0xDA, 0x85, 0x85,
-  0xAF, 0x2C, 0xDA, 0xDA, 0x2C, 0x7D, 0xA1, 0x48,
-  0xB2, 0x21, 0xD6, 0xD9, 0x2C, 0xDA, 0x85, 0xAF,
-  0x2C, 0x2D, 0x48, 0x7D, 0xAF, 0x2C, 0x85, 0x2C,
-  0xD9, 0xAC, 0xAF, 0x85, 0x85, 0x2C, 0x2C, 0x2C,
-  0x85, 0x2C, 0xD9, 0xD6, 0xA1, 0xA1, 0x48, 0xA1,
-  0x21, 0x2C, 0xDA, 0xDA, 0x2C, 0x85, 0x41, 0x98,
-  0xA2, 0xA7, 0x6F, 0xC9, 0x37, 0xF2, 0xF2, 0x9B,
-  0xB7, 0x66, 0x60, 0x4C, 0xED, 0x84, 0x3C, 0x20,
-  0x5B, 0x2D, 0x2B, 0x6B, 0x20, 0xAF, 0xAF, 0x2C,
-  0x85, 0x2C, 0xD9, 0xAC, 0xAF, 0x85, 0x85, 0x2C,
-  0x2C, 0x2C, 0x2C, 0x85, 0xD9, 0xD6, 0xA1, 0xA1,
-  0x48, 0xA1, 0xD6, 0xAF, 0xDA, 0x8A, 0x2C, 0xD9,
-  0xB2, 0x2D, 0x48, 0x95, 0x2C, 0x2C, 0x2C, 0x85,
-  0xAC, 0xAC, 0xAF, 0x85, 0xDA, 0x85, 0xAF, 0xAC,
-  0xAF, 0x2C, 0xD9, 0xD6, 0xD6, 0xD6, 0x21, 0xD6,
-  0xD9, 0xDA, 0x8D, 0xDA, 0xAF, 0x2C, 0x20, 0x88,
-  0x42, 0x51, 0x3F, 0x2F, 0x45, 0xB7, 0x66, 0x55,
-  0x46, 0x60, 0x5D, 0x36, 0xD8, 0x71, 0x43, 0x20,
-  0x20, 0x2D, 0xB2, 0x80, 0x20, 0x2D, 0x2C, 0x2C,
-  0x2C, 0x85, 0xAC, 0xAC, 0xAF, 0x85, 0xDA, 0x85,
-  0xAF, 0xAC, 0xAC, 0xAF, 0xD9, 0xD6, 0xD6, 0xD6,
-  0x21, 0xD6, 0xD9, 0xDA, 0x8D, 0x8A, 0x2C, 0xD9,
-  0xB2, 0x48, 0xD6, 0xAC, 0xAF, 0x2C, 0x2C, 0x85,
-  0x2C, 0xAC, 0x2C, 0xDA, 0xDA, 0x85, 0xAF, 0xD9,
-  0xD9, 0xAC, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xAC,
-  0x85, 0x8D, 0xBC, 0xDA, 0xD9, 0xDA, 0x20, 0xE3,
-  0xDA, 0x69, 0x96, 0xB5, 0xF1, 0x68, 0x5D, 0x82,
-  0xE1, 0xBE, 0x27, 0x8D, 0x4D, 0xD3, 0x7D, 0x20,
-  0x20, 0xDB, 0xA1, 0xCA, 0x20, 0x88, 0x85, 0x2C,
-  0x2C, 0x85, 0x2C, 0xAC, 0x2C, 0xDA, 0xDA, 0x85,
-  0xAF, 0xD9, 0xAC, 0xAF, 0xD9, 0xD9, 0xD9, 0xD9,
-  0xD9, 0xAC, 0xDA, 0x8D, 0xBC, 0xDA, 0xD9, 0x95,
-  0xD9, 0x95, 0xAC, 0x2C, 0x2C, 0x2C, 0x2C, 0x85,
-  0x85, 0xAF, 0xAF, 0x85, 0x85, 0x2C, 0x2C, 0xAC,
-  0xD9, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C, 0x2C, 0x85,
-  0x8D, 0x2A, 0x2A, 0x85, 0xD9, 0x95, 0x20, 0xDB,
-  0x8D, 0x8D, 0x99, 0xB0, 0x35, 0xE5, 0x3F, 0x35,
-  0xB9, 0x50, 0x8A, 0x4D, 0x73, 0xE8, 0xA3, 0xCC,
-  0x20, 0x20, 0x33, 0x6B, 0x20, 0x20, 0xCC, 0x85,
-  0x2C, 0x85, 0x85, 0xAF, 0xAF, 0x85, 0x85, 0x85,
-  0x2C, 0xD9, 0xD9, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C,
-  0x2C, 0x85, 0x8A, 0x2A, 0x8D, 0x2C, 0xD9, 0xD9,
-  0xAF, 0xAF, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C, 0x85,
-  0x2C, 0xAF, 0xAF, 0xAF, 0x2C, 0x2C, 0x2C, 0xAC,
-  0xD9, 0xAC, 0xAF, 0x2C, 0x85, 0x85, 0xDA, 0xDA,
-  0x8A, 0x8A, 0x85, 0xD9, 0x2C, 0x2B, 0x20, 0xAE,
-  0xA3, 0xBC, 0x8D, 0xC8, 0xA9, 0xC7, 0x92, 0x47,
-  0x8D, 0x8D, 0x7E, 0xE4, 0xE8, 0xE8, 0x5C, 0x2C,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6B, 0xAF,
-  0x2C, 0x85, 0x2C, 0xAF, 0xAF, 0xAF, 0x2C, 0x2C,
-  0x2C, 0xAF, 0xD9, 0xAC, 0x2C, 0x2C, 0x85, 0x85,
-  0x85, 0xDA, 0x8D, 0x8A, 0x85, 0xAC, 0x95, 0xD9,
-  0xAC, 0xAC, 0xAC, 0xAC, 0x2C, 0xAF, 0xAF, 0x2C,
-  0x2C, 0xAF, 0xAF, 0xAC, 0x2C, 0xAF, 0x2C, 0xAF,
-  0xD9, 0xAC, 0x2C, 0x2C, 0x85, 0x85, 0x85, 0x85,
-  0x85, 0x2C, 0xD9, 0xD9, 0x2D, 0x6B, 0x41, 0x2A,
-  0xE8, 0xA3, 0xC8, 0x8D, 0x8A, 0x8A, 0x8A, 0x8D,
-  0x4D, 0xA3, 0x3D, 0xE8, 0xE8, 0xE8, 0xE8, 0x5C,
-  0xAE, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xDB,
-  0xDA, 0x2C, 0x2C, 0xAF, 0xAF, 0xAC, 0xAC, 0xAF,
-  0x2C, 0xAC, 0xD9, 0xAC, 0x2C, 0x2C, 0x85, 0x85,
-  0x85, 0x85, 0x85, 0x2C, 0xD9, 0x95, 0x7D, 0xD9,
-  0x7D, 0x7D, 0xD9, 0xAC, 0xAC, 0xAF, 0xAF, 0xAF,
-  0x2C, 0x2C, 0xAC, 0xAC, 0xD9, 0xAC, 0xAC, 0xD9,
-  0x95, 0xD9, 0xAC, 0xAF, 0xAF, 0xAC, 0xAF, 0xAC,
-  0xD9, 0x7D, 0x7D, 0x7D, 0x33, 0x41, 0x2D, 0xE8,
-  0xE8, 0x5C, 0xD3, 0x8D, 0x8D, 0x8D, 0x8D, 0x7E,
-  0x3D, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xDA, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x81, 0x2C, 0x2C, 0x2C, 0xAC, 0xAC, 0xAC, 0xAC,
-  0xAC, 0xD9, 0x95, 0x95, 0xAC, 0xAF, 0xAF, 0xAF,
-  0xAF, 0xAC, 0xD9, 0x95, 0x7D, 0xD6, 0xD6, 0x7D,
-  0x21, 0xD6, 0x95, 0xD9, 0xD9, 0xAC, 0xAF, 0xAF,
-  0x2C, 0xAF, 0xAC, 0xAC, 0xD9, 0xD9, 0xD9, 0xD9,
-  0x21, 0x21, 0x7D, 0x95, 0x95, 0x7D, 0xD6, 0x21,
-  0xB2, 0xA1, 0x2C, 0x88, 0x20, 0xE3, 0xA3, 0xE8,
-  0xE8, 0xE8, 0xE4, 0xEE, 0xD3, 0x7E, 0x73, 0x5C,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0x5C, 0x2B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x2C, 0xAF, 0xAF, 0xAC, 0xD9, 0xD9, 0xD9,
-  0xD9, 0xD9, 0xD6, 0x21, 0x7D, 0x95, 0x95, 0x7D,
-  0xD6, 0xB2, 0xA1, 0xA1, 0xB2, 0xD6, 0x21, 0x21,
-  0x21, 0xD9, 0xD9, 0xD9, 0xAC, 0xAF, 0xAC, 0xAF,
-  0x2C, 0x2C, 0xAC, 0xD9, 0xD9, 0xD9, 0xD9, 0x95,
-  0x7D, 0xB2, 0xD6, 0x95, 0xD9, 0x95, 0xD6, 0xA1,
-  0xA1, 0xAF, 0x5B, 0x20, 0x20, 0xD6, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE8, 0x5C, 0xE8, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE8, 0x48, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0xE3, 0x8A, 0x2C, 0xAC, 0xAC, 0xD9, 0xD9,
-  0xD9, 0x95, 0xD6, 0xB2, 0xD6, 0x95, 0xD9, 0x95,
-  0x21, 0xB2, 0xA1, 0xB2, 0xD6, 0xD6, 0xD6, 0xA1,
-  0xD9, 0x2C, 0x2C, 0x2C, 0xAF, 0xAF, 0xAC, 0xAF,
-  0x2C, 0x2C, 0xAF, 0xAC, 0xD9, 0xAC, 0xD9, 0xD9,
-  0xD9, 0x95, 0xAC, 0x2C, 0x2C, 0xAC, 0x95, 0x7D,
-  0xD9, 0x91, 0x20, 0x20, 0xE3, 0xA3, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE8, 0x85, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x2B, 0x8A, 0xAF, 0xAC, 0xD9, 0xAC,
-  0xD9, 0xD9, 0xD9, 0x95, 0xAC, 0x2C, 0x2C, 0xAC,
-  0x95, 0x7D, 0x95, 0x95, 0xD9, 0x95, 0x7D, 0x21,
-  0x2C, 0xDA, 0xDA, 0x85, 0x2C, 0xAF, 0xAF, 0xAF,
-  0xAF, 0xAF, 0x2C, 0xAF, 0xAF, 0xAC, 0xAC, 0xAC,
-  0xD9, 0xAF, 0x85, 0x85, 0x2C, 0xAF, 0xD9, 0xAF,
-  0x48, 0x20, 0x20, 0x20, 0xE6, 0xA3, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0x5C,
-  0xE4, 0x73, 0x41, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x2B, 0xDA, 0xAF, 0xAF, 0xAC,
-  0xAC, 0xAF, 0xD9, 0x2C, 0x85, 0x85, 0x2C, 0xAF,
-  0xD9, 0xD9, 0xAC, 0xAF, 0xAC, 0xD9, 0xD9, 0xD9,
-  0x85, 0xDA, 0xDA, 0x85, 0x2C, 0x2C, 0xAC, 0xAF,
-  0xAF, 0xAF, 0xAF, 0x2C, 0xAF, 0xAF, 0xAC, 0xAC,
-  0xAF, 0x2C, 0x2C, 0x2C, 0xAC, 0x95, 0x95, 0xA1,
-  0x20, 0x20, 0x20, 0x20, 0xE9, 0x8C, 0x5C, 0xE8,
-  0xE8, 0xE8, 0xE8, 0x3D, 0x73, 0x73, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE4, 0x73, 0x73, 0x73, 0xCD,
-  0x7E, 0xA3, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x24, 0x85, 0xAF, 0xAF,
-  0xAC, 0xAC, 0xAC, 0xAF, 0x85, 0x2C, 0xAC, 0x95,
-  0x95, 0xD9, 0xAC, 0xAC, 0xAC, 0xD9, 0xAC, 0xAF,
-  0x8A, 0x8A, 0xDA, 0xDA, 0x85, 0x2C, 0x2C, 0x2C,
-  0x2C, 0x2C, 0x2C, 0xAF, 0xAF, 0xAC, 0xAF, 0xAC,
-  0xAC, 0xAF, 0xAF, 0xD9, 0xD6, 0xD6, 0x2C, 0x88,
-  0x20, 0x20, 0x20, 0x88, 0xB2, 0xDA, 0x7E, 0x73,
-  0xE8, 0xE8, 0xE8, 0x3D, 0x73, 0xE8, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xA3, 0xCD, 0xD3, 0x2A, 0x2A,
-  0x2A, 0x8C, 0x8D, 0x88, 0x20, 0xE3, 0x6B, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x41, 0x85, 0xAF, 0xAC,
-  0xAC, 0xAC, 0xAC, 0xAF, 0xAC, 0xD9, 0x7D, 0xD6,
-  0x7D, 0x7D, 0xD9, 0x95, 0xD9, 0xAC, 0xAC, 0xAF,
-  0xD3, 0x8D, 0xDA, 0xDA, 0x85, 0x85, 0x2C, 0x2C,
-  0x2C, 0xAF, 0xAF, 0xAC, 0xD9, 0xD9, 0xD9, 0xD9,
-  0xAF, 0xAF, 0xAC, 0xD9, 0x95, 0x7D, 0xAC, 0x20,
-  0x20, 0x20, 0x20, 0xDB, 0x2C, 0xA3, 0x5C, 0xE8,
-  0xE8, 0xE8, 0xE8, 0x5C, 0x3D, 0x3D, 0xE8, 0xE8,
-  0xE8, 0xE4, 0xE8, 0xE8, 0xE8, 0xE4, 0x73, 0xEE,
-  0xD3, 0x2A, 0xEE, 0xAC, 0x20, 0x33, 0x2B, 0xE3,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x9F, 0xAF, 0xD9,
-  0xD9, 0xAC, 0xAF, 0xAF, 0xAC, 0xD9, 0x95, 0x7D,
-  0xD9, 0x95, 0x95, 0x95, 0x95, 0xD9, 0xAF, 0xAF,
-  0x7E, 0x85, 0x85, 0x2C, 0x85, 0x85, 0x85, 0x2C,
-  0x2C, 0x2C, 0xAF, 0xD9, 0xD9, 0x95, 0xD9, 0xAC,
-  0xAC, 0xAF, 0xAF, 0xAC, 0xAC, 0xAC, 0x91, 0x20,
-  0x33, 0xE3, 0x41, 0x48, 0x73, 0x5C, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xA3, 0xD6, 0x6C, 0x85, 0xE8,
-  0xDA, 0xAE, 0xB2, 0xA3, 0x5C, 0xE8, 0xE8, 0xE8,
-  0x3D, 0xEE, 0x4D, 0xA3, 0x24, 0x20, 0x6B, 0xDB,
-  0x2B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x85, 0x95,
-  0xD9, 0xD9, 0xAC, 0xAF, 0xAF, 0xAC, 0xD9, 0xAC,
-  0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xAC, 0xD9, 0xAC,
-  0x8A, 0xD9, 0xAC, 0xD9, 0xAC, 0xAC, 0x2C, 0x2C,
-  0xAF, 0xAF, 0xAF, 0xAC, 0xD9, 0xD9, 0xD9, 0xD9,
-  0xAF, 0xAF, 0xAF, 0xAC, 0xAC, 0x85, 0x33, 0x20,
-  0xCC, 0x20, 0xE3, 0xA3, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE8, 0xA3, 0xD9, 0x81, 0xAC, 0xDA, 0x2D, 0x5C,
-  0x48, 0x41, 0x88, 0x74, 0x21, 0xA3, 0xE8, 0xE8,
-  0xE8, 0xE8, 0x73, 0x8C, 0x8A, 0x20, 0x20, 0x20,
-  0xDB, 0x33, 0x20, 0x20, 0x20, 0x20, 0xE6, 0xD9,
-  0xD9, 0xAC, 0xAC, 0xAF, 0xAC, 0xAF, 0xAC, 0xAF,
-  0xAF, 0xAC, 0xD9, 0xAF, 0xD9, 0xAC, 0xAC, 0xAF,
-  0x85, 0xD9, 0x95, 0xD9, 0x95, 0xD9, 0xD9, 0xAC,
-  0xAF, 0xAC, 0xAF, 0xAF, 0x2C, 0xAF, 0x2C, 0x2C,
-  0xAF, 0xAF, 0xAF, 0xAC, 0xAC, 0x2C, 0x20, 0x5B,
-  0x33, 0x20, 0xD6, 0xE8, 0xE8, 0xE8, 0xE8, 0x73,
-  0xAF, 0x2D, 0xD9, 0xDA, 0xB2, 0x81, 0x81, 0xE4,
-  0xA1, 0x91, 0x2B, 0x88, 0x33, 0x80, 0xAF, 0x73,
-  0xE8, 0xE8, 0xE8, 0x5C, 0xA3, 0x80, 0x41, 0xCC,
-  0x2B, 0xCC, 0x20, 0x20, 0x20, 0x20, 0x88, 0xDA,
-  0x2C, 0x2C, 0x2C, 0xAF, 0xAF, 0xAC, 0xAC, 0xAF,
-  0xAF, 0xAF, 0xAF, 0xAC, 0xAF, 0xAF, 0xAF, 0x2C,
-  0x85, 0xD9, 0xD9, 0xD9, 0xD9, 0xAC, 0xAC, 0xD9,
-  0xD9, 0xD9, 0xAC, 0x2C, 0x2C, 0x2C, 0x85, 0x85,
-  0x85, 0x2C, 0x2C, 0xAF, 0x2C, 0x91, 0x20, 0xAE,
-  0x20, 0xDB, 0x3D, 0xE8, 0xE8, 0x5C, 0xB2, 0x80,
-  0xB2, 0xAF, 0x48, 0xB2, 0x48, 0x89, 0x89, 0x3D,
-  0x21, 0x48, 0x6C, 0x2D, 0x2B, 0x41, 0xE3, 0xAE,
-  0xD9, 0x5C, 0xE8, 0xE8, 0xE8, 0x95, 0x33, 0x80,
-  0xAE, 0x33, 0x2B, 0x20, 0x20, 0x20, 0x20, 0x95,
-  0x85, 0x2C, 0x85, 0x2C, 0x2C, 0xAF, 0x2C, 0x2C,
-  0x2C, 0xAF, 0xAC, 0xAF, 0xAF, 0x2C, 0x2C, 0x2C,
-  0xDA, 0xAF, 0xD9, 0xD9, 0xAF, 0x2C, 0x2C, 0x2C,
-  0xAC, 0xD9, 0xAC, 0xAF, 0x2C, 0x85, 0x2C, 0x85,
-  0x85, 0x2C, 0x2C, 0x2C, 0x8A, 0x41, 0xDB, 0x33,
-  0x20, 0x95, 0xE8, 0xE8, 0xE8, 0xA3, 0xDB, 0x88,
-  0xDB, 0x80, 0xD6, 0x7E, 0x85, 0x2D, 0xE6, 0x5C,
-  0x21, 0x48, 0xD9, 0x7E, 0xD6, 0x2B, 0xCC, 0xAC,
-  0x85, 0xBC, 0xE8, 0xE8, 0xE8, 0xCD, 0x88, 0x5B,
-  0x41, 0x20, 0xAE, 0x20, 0x20, 0x20, 0x20, 0x74,
-  0xDA, 0x85, 0x85, 0x85, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xAF, 0xAC, 0xD9, 0xD9, 0xAC, 0xAC, 0xAC, 0xD9,
-  0x8A, 0xAF, 0xAC, 0xAC, 0x2C, 0x85, 0x2C, 0xAF,
-  0xD9, 0xD9, 0xAF, 0xAF, 0xAF, 0x2C, 0xAF, 0x2C,
-  0x2C, 0x2C, 0x2C, 0xAF, 0x95, 0x20, 0x74, 0x20,
-  0x33, 0xA3, 0xE8, 0xE8, 0xE8, 0xE4, 0x7D, 0xCC,
-  0x6B, 0x33, 0xAE, 0x2C, 0x85, 0x2D, 0x9F, 0x73,
-  0xA1, 0x2D, 0x2C, 0xDA, 0x89, 0x48, 0xD3, 0xD9,
-  0x21, 0xA3, 0xE8, 0xE8, 0xE8, 0xE8, 0xE3, 0x20,
-  0x20, 0x20, 0xDB, 0x41, 0x20, 0x20, 0x20, 0x20,
-  0xDA, 0x2C, 0x2C, 0x2C, 0x2C, 0xAF, 0xAC, 0xAC,
-  0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0x95, 0x95, 0xD9,
-  0x2C, 0xD9, 0xD9, 0xAC, 0x2C, 0x2C, 0x85, 0xAF,
-  0xAF, 0xAF, 0xAC, 0xAC, 0xD9, 0xAC, 0xAF, 0xAC,
-  0xAC, 0x95, 0xD6, 0x7D, 0xAE, 0x88, 0x2B, 0x20,
-  0x6C, 0xE8, 0xE8, 0xE8, 0x73, 0xEE, 0x73, 0x2C,
-  0x89, 0x2B, 0x41, 0x33, 0xCC, 0xCC, 0x80, 0x3D,
-  0x2D, 0x74, 0x80, 0x48, 0x8D, 0x95, 0x48, 0x95,
-  0xEE, 0x5C, 0x5C, 0xE8, 0xE8, 0xE8, 0x24, 0x20,
-  0x20, 0x20, 0x5B, 0xDB, 0x20, 0x20, 0x20, 0x20,
-  0xAF, 0xAC, 0xD9, 0x95, 0xD6, 0xD6, 0xD6, 0x7D,
-  0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0xD9, 0xAC,
-  0xAC, 0xD9, 0xD9, 0xAC, 0x2C, 0x2C, 0x2C, 0xAF,
-  0xAC, 0xAC, 0xAC, 0xAC, 0xD9, 0xAC, 0xAC, 0xD9,
-  0xD6, 0x48, 0xE9, 0x95, 0x20, 0x2B, 0x41, 0x6B,
-  0x8D, 0xE8, 0xE8, 0xCD, 0x2B, 0x2B, 0x2C, 0x73,
-  0xCD, 0x48, 0xCA, 0x5B, 0x41, 0x5B, 0x74, 0xDA,
-  0x80, 0xE6, 0xC8, 0x85, 0xA1, 0x7D, 0x8D, 0x3D,
-  0x7E, 0xE9, 0x7D, 0xEE, 0xE8, 0xE8, 0x81, 0x20,
-  0x20, 0x20, 0xE3, 0xE3, 0x20, 0x20, 0x20, 0x20,
-  0x2D, 0xD9, 0xD6, 0x48, 0x6C, 0xE9, 0xA1, 0xD6,
-  0xD9, 0xD9, 0xAC, 0xD9, 0xD9, 0x95, 0xAC, 0x2C,
-  0x2C, 0x2C, 0x2C, 0xD9, 0xAC, 0x2C, 0x2C, 0x2C,
-  0xAF, 0x2C, 0xAF, 0xD9, 0xAC, 0xAF, 0xAF, 0x95,
-  0xB2, 0xE9, 0x21, 0x2B, 0x41, 0x2B, 0x20, 0x5B,
-  0x3D, 0xE8, 0xE8, 0x8D, 0x2B, 0x88, 0x5B, 0xE6,
-  0xBC, 0x73, 0x85, 0x89, 0x80, 0x5B, 0xE3, 0xAE,
-  0x2C, 0x8A, 0xD6, 0xB2, 0x2C, 0xA3, 0xA3, 0xD9,
-  0xA1, 0x2C, 0x85, 0x8D, 0xE8, 0xE8, 0x48, 0x20,
-  0x20, 0x20, 0xE3, 0x88, 0x20, 0x20, 0x20, 0x20,
-  0xAE, 0xD9, 0xB2, 0xE9, 0x6C, 0x48, 0xD6, 0xD9,
-  0x2C, 0x85, 0x2C, 0xD9, 0x7D, 0xD9, 0x2C, 0x85,
-  0x8D, 0x85, 0x2C, 0xAC, 0xAF, 0x2C, 0x2C, 0x85,
-  0x2C, 0x2C, 0xAF, 0xAC, 0xAC, 0xAF, 0xAF, 0xD9,
-  0xB2, 0x48, 0xB2, 0x20, 0x20, 0xCC, 0x20, 0x9F,
-  0xE8, 0xE8, 0xE8, 0xCD, 0x48, 0x89, 0xDB, 0x88,
-  0x2B, 0xE9, 0xCD, 0x2A, 0x48, 0x80, 0xAE, 0xAE,
-  0x7D, 0x48, 0x21, 0xEE, 0x3D, 0x2C, 0x48, 0x85,
-  0x2C, 0x95, 0x7D, 0x8C, 0xE8, 0xE8, 0xB2, 0x20,
-  0x20, 0x20, 0xDB, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0xDB, 0x2C, 0xB2, 0x48, 0x48, 0x7D, 0xD9, 0xAF,
-  0x85, 0x8A, 0x85, 0x7D, 0xB2, 0x95, 0x85, 0xDA,
-  0xD3, 0x85, 0xAF, 0xAC, 0x2C, 0x85, 0x85, 0x2C,
-  0xAC, 0xAC, 0xAC, 0xD9, 0xD9, 0xAC, 0x2C, 0x2C,
-  0xD9, 0xAC, 0x5B, 0x20, 0x20, 0xAE, 0x20, 0x2D,
-  0xE8, 0xE8, 0xE8, 0x7E, 0xD6, 0x48, 0xE9, 0xAE,
-  0x88, 0x5B, 0x80, 0x6C, 0xAE, 0xCA, 0x91, 0xE9,
-  0x43, 0x9F, 0xE6, 0x2C, 0x48, 0x21, 0xBC, 0x95,
-  0x95, 0xD6, 0x21, 0x7E, 0xE8, 0xE8, 0x7D, 0x20,
-  0x20, 0x20, 0x2B, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x6B, 0xDA, 0xD9, 0x48, 0xB2, 0xD9, 0x2C, 0x85,
-  0xDA, 0xDA, 0x2C, 0xA1, 0x48, 0xAC, 0xDA, 0x8D,
-  0x2A, 0xAC, 0x7D, 0x95, 0xAF, 0x85, 0x2C, 0x2C,
-  0xAC, 0xD9, 0x95, 0x7D, 0x95, 0xAC, 0x2C, 0xAF,
-  0x7D, 0xD6, 0x20, 0x20, 0x88, 0x9F, 0x20, 0xA1,
-  0xE8, 0xE8, 0xE8, 0xA3, 0xD6, 0x6C, 0xB2, 0x2C,
-  0x89, 0xE3, 0x88, 0xDB, 0xCC, 0x24, 0x7D, 0xEE,
-  0xB2, 0xCC, 0xAE, 0x2D, 0xDA, 0x2C, 0xD6, 0x2C,
-  0xB2, 0x2D, 0xD6, 0xEE, 0xE8, 0xE8, 0x95, 0x20,
-  0x20, 0x20, 0xDB, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x6B, 0xDA, 0x95, 0xA1, 0xB2, 0xAC, 0x85, 0x85,
-  0xDA, 0x2C, 0x95, 0xA1, 0x21, 0x2C, 0x8A, 0x2A,
-  0xAF, 0xA1, 0x48, 0xD6, 0xAF, 0x2C, 0x2C, 0xAC,
-  0xD9, 0xD9, 0x95, 0x7D, 0x95, 0xAC, 0xD9, 0x7D,
-  0x48, 0xE6, 0x20, 0x20, 0x33, 0x89, 0x6B, 0x95,
-  0xE8, 0xE8, 0xE8, 0xA3, 0x21, 0x48, 0xAF, 0xAF,
-  0x9F, 0xE9, 0x43, 0x33, 0x33, 0x2D, 0xDA, 0xCD,
-  0xD6, 0xAE, 0x85, 0x2C, 0x7D, 0xD6, 0x91, 0xB8,
-  0xD4, 0x48, 0x7D, 0xA3, 0xE8, 0xE8, 0x95, 0x20,
-  0x20, 0x33, 0xE3, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x2C, 0x48, 0x6C, 0xB2, 0xAF, 0xDA, 0xDA,
-  0x85, 0xAF, 0xD9, 0x95, 0xAC, 0xDA, 0x8A, 0xDA,
-  0x7D, 0x48, 0x48, 0x7D, 0x2C, 0x85, 0x2C, 0xAF,
-  0xD9, 0xD9, 0x7D, 0x95, 0xD9, 0xD9, 0x95, 0xD6,
-  0x21, 0x24, 0x20, 0x20, 0x20, 0x5B, 0xDB, 0xAC,
-  0xE8, 0xE8, 0xE8, 0x3D, 0x7D, 0x48, 0xE6, 0x2D,
-  0x85, 0x81, 0x81, 0x48, 0xAE, 0xCA, 0x89, 0xCC,
-  0xAE, 0xDB, 0x2D, 0x95, 0x21, 0xCC, 0xDB, 0xAE,
-  0x91, 0xE9, 0x7D, 0x73, 0xE8, 0xE8, 0x48, 0x20,
-  0x6B, 0x74, 0x41, 0x88, 0x6B, 0x20, 0x20, 0x20,
-  0x6B, 0x95, 0xB2, 0xD6, 0xD9, 0x85, 0xDA, 0xDA,
-  0xDA, 0x2C, 0xAF, 0xAF, 0x2C, 0xDA, 0xDA, 0x85,
-  0xA1, 0xE9, 0x48, 0x95, 0x85, 0xDA, 0x85, 0xAC,
-  0xD9, 0xD9, 0x95, 0x95, 0xD9, 0xD9, 0xD9, 0x95,
-  0x95, 0x6C, 0x41, 0x93, 0x93, 0x41, 0xDB, 0x95,
-  0xE8, 0xE8, 0xE8, 0x3D, 0x95, 0xD4, 0x6C, 0x21,
-  0x2D, 0x95, 0xCD, 0x2C, 0xD6, 0xD9, 0x6C, 0x91,
-  0x89, 0x7D, 0xAC, 0x2A, 0x8D, 0xE6, 0xCC, 0x88,
-  0x74, 0x48, 0xD9, 0xE4, 0xE8, 0xE8, 0xE6, 0x88,
-  0x2B, 0x88, 0x20, 0x33, 0xDB, 0x2B, 0xDB, 0x20,
-  0x91, 0x7D, 0xD9, 0xD9, 0x85, 0x85, 0xDA, 0xDA,
-  0x85, 0xAF, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xA1, 0xA1, 0xD6, 0xAF, 0x85, 0xDA, 0x85, 0x2C,
-  0xD9, 0xD9, 0x95, 0x95, 0xD9, 0xD9, 0xD9, 0xAC,
-  0x2C, 0x47, 0x87, 0x3E, 0x3E, 0xA4, 0x7B, 0x80,
-  0xA3, 0xE8, 0xE8, 0x5C, 0x7D, 0x48, 0xE6, 0xD9,
-  0xBC, 0xEE, 0x7D, 0x43, 0xD6, 0x21, 0x43, 0x6C,
-  0x43, 0x7D, 0x7D, 0xB2, 0x8A, 0xEE, 0x2C, 0xCA,
-  0xAE, 0x48, 0x2C, 0xE4, 0xE8, 0x5C, 0xCC, 0x88,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x91, 0xE3,
-  0x21, 0xD9, 0x2C, 0x2C, 0xDA, 0xDA, 0xDA, 0x85,
-  0x2C, 0xAC, 0xD9, 0xD9, 0xAC, 0xAF, 0xAF, 0xAF,
-  0xD6, 0x7D, 0xD9, 0x2C, 0xDA, 0xDA, 0x85, 0xAC,
-  0xD9, 0x7D, 0x7D, 0xD9, 0xD9, 0xD9, 0x2C, 0x2C,
-  0xB8, 0x9C, 0xEC, 0x62, 0x6F, 0x62, 0x70, 0x3C,
-  0xAE, 0xCD, 0xE8, 0xE8, 0x8C, 0x7D, 0xC8, 0x3D,
-  0x8A, 0xE9, 0x2D, 0x9E, 0xA1, 0xD6, 0x48, 0x73,
-  0x81, 0xD6, 0xD6, 0xAE, 0x5B, 0x2D, 0xA3, 0xA3,
-  0x21, 0x21, 0xCD, 0xE8, 0xC0, 0x56, 0x31, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0xCC, 0xDB,
-  0x42, 0x85, 0x85, 0x85, 0x85, 0x85, 0x2C, 0x2C,
-  0xAC, 0xD9, 0xD9, 0xD9, 0xAC, 0xAF, 0xAF, 0xAF,
-  0xD9, 0x95, 0xAC, 0x2C, 0x85, 0x85, 0x2C, 0xD9,
-  0x7D, 0xD6, 0xD6, 0xD9, 0xAC, 0xAF, 0x8A, 0xBC,
-  0xC2, 0x68, 0x2E, 0x4B, 0xC9, 0x8B, 0x62, 0x87,
-  0x3C, 0x74, 0xBC, 0xE8, 0xE8, 0xE4, 0xEE, 0xA1,
-  0xE9, 0x21, 0xE6, 0x89, 0x48, 0x7D, 0xB2, 0x5C,
-  0x6C, 0x7D, 0x21, 0x80, 0xE3, 0x33, 0xCC, 0x2C,
-  0x3D, 0x3D, 0xE8, 0xE8, 0xEC, 0xCB, 0x5A, 0x6B,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x88, 0x41, 0x51,
-  0x49, 0x28, 0x85, 0x85, 0x85, 0x85, 0x2C, 0xAF,
-  0xAC, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xD9, 0x95, 0xD9, 0x2C, 0x85, 0x85, 0x2C, 0xD9,
-  0xB2, 0xB2, 0x2C, 0x2A, 0x79, 0x79, 0x97, 0x44,
-  0xED, 0x29, 0x32, 0x62, 0x4B, 0x62, 0x6F, 0x22,
-  0xF3, 0x6B, 0x33, 0x85, 0x73, 0xE4, 0x2D, 0x2B,
-  0xCC, 0x9F, 0xDA, 0xBC, 0x48, 0xD6, 0xA1, 0xE4,
-  0xE9, 0xD6, 0xD9, 0x2A, 0xB2, 0x2B, 0x2B, 0xA1,
-  0xB8, 0xE8, 0xE8, 0xE8, 0xEC, 0x3E, 0x30, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x6B, 0x54, 0xDC,
-  0xC9, 0x53, 0xBC, 0x2C, 0x2C, 0x2C, 0xAF, 0xAF,
-  0xAF, 0xAC, 0xAF, 0xAC, 0xAC, 0x2C, 0xAF, 0xAC,
-  0x2C, 0x7D, 0xD9, 0x2C, 0x85, 0xDA, 0xAF, 0x7D,
-  0xB2, 0xAC, 0xC6, 0xBA, 0x4C, 0xEF, 0xA7, 0xEF,
-  0xEC, 0x7A, 0x62, 0x4B, 0x62, 0x4B, 0x8B, 0x4B,
-  0x3A, 0x52, 0x20, 0x6B, 0x21, 0x73, 0xAC, 0x2B,
-  0x41, 0x33, 0x48, 0x67, 0xA1, 0xD6, 0xD6, 0x5C,
-  0xE9, 0xD6, 0x2C, 0xEE, 0xB2, 0x9F, 0x8A, 0x95,
-  0x4D, 0xE8, 0xE8, 0x3D, 0x7A, 0x57, 0xD1, 0x7B,
-  0x20, 0x20, 0x20, 0x20, 0x6B, 0xCF, 0xBA, 0x3E,
-  0x3E, 0xD0, 0xBC, 0xAC, 0xAC, 0x2C, 0x2C, 0xAC,
-  0xD9, 0xD9, 0x95, 0x95, 0x7D, 0x95, 0x95, 0xD9,
-  0x85, 0xD9, 0xAF, 0xDA, 0xDA, 0x85, 0xAC, 0x21,
-  0xB2, 0x2A, 0xBA, 0x57, 0x2E, 0x2E, 0x2E, 0x7A,
-  0x32, 0x62, 0x8B, 0x4B, 0x8B, 0x4B, 0x4B, 0x4B,
-  0xC9, 0x4A, 0x5F, 0x20, 0x20, 0x2D, 0xA3, 0xD9,
-  0xCA, 0x88, 0xDB, 0x24, 0x48, 0x7D, 0xB2, 0xE4,
-  0x2D, 0x7D, 0x7D, 0x81, 0xA1, 0xDA, 0x21, 0xDA,
-  0xE4, 0xE8, 0xEE, 0xF1, 0x2E, 0x57, 0x82, 0x76,
-  0x52, 0x4F, 0x4F, 0x98, 0xDE, 0xB5, 0xEC, 0x2E,
-  0x3E, 0x6D, 0x85, 0x2C, 0xAC, 0xAC, 0xD9, 0xD9,
-  0x95, 0xD6, 0x7D, 0x7D, 0x95, 0xD9, 0xD9, 0xD9,
-  0xDA, 0x2C, 0x85, 0xDA, 0xDA, 0x2C, 0x95, 0xB2,
-  0x21, 0xB8, 0xED, 0x2E, 0x3E, 0x4B, 0xC9, 0x4B,
-  0x8B, 0x62, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x22, 0x6F, 0xCE, 0x20, 0x20, 0x20, 0x80, 0xCD,
-  0xDA, 0x2D, 0x2B, 0xDB, 0xE9, 0xD6, 0x95, 0x5C,
-  0x2D, 0x7D, 0x7D, 0xAF, 0xAF, 0xAC, 0xEE, 0x5C,
-  0xE8, 0xE8, 0xEB, 0x25, 0x7A, 0x57, 0x39, 0xE1,
-  0x83, 0xA8, 0x55, 0x83, 0x82, 0x57, 0x32, 0x8B,
-  0x62, 0x6D, 0xEB, 0x95, 0xD9, 0xD9, 0xD9, 0xD9,
-  0xD9, 0xD9, 0xD9, 0xAF, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xDA, 0x2C, 0x85, 0x85, 0x85, 0xAC, 0xD6, 0x21,
-  0x95, 0x6E, 0xED, 0x57, 0x62, 0x4B, 0x8B, 0x4B,
-  0x4B, 0x62, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x62,
-  0x62, 0x62, 0x25, 0x3C, 0x20, 0x20, 0x20, 0xE3,
-  0x2A, 0xBC, 0x7D, 0xCA, 0x6C, 0xD6, 0x95, 0x3D,
-  0x81, 0x7D, 0xD6, 0xD6, 0xDA, 0x73, 0xE8, 0xE8,
-  0xE8, 0x4D, 0x94, 0xED, 0x72, 0x3A, 0xF1, 0xA7,
-  0x39, 0xED, 0x39, 0xEF, 0x57, 0x32, 0x8B, 0x4B,
-  0x62, 0x62, 0xA6, 0x2A, 0xD9, 0xD9, 0xD9, 0xD9,
-  0x2C, 0x2C, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
-  0x85, 0x2C, 0x2C, 0xAF, 0xAC, 0x95, 0x21, 0x7D,
-  0xAC, 0x8C, 0x46, 0xC4, 0x62, 0x8B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x62, 0xC9, 0x30, 0x7B, 0x20, 0x20, 0x20,
-  0x41, 0x4D, 0x3D, 0x85, 0x48, 0x21, 0xDA, 0x3D,
-  0xE9, 0xD6, 0xD9, 0xCD, 0x5C, 0xE8, 0xE8, 0xE8,
-  0xE8, 0x4D, 0x71, 0x46, 0xEC, 0x2E, 0x72, 0xEC,
-  0x29, 0x29, 0x7C, 0x29, 0x2E, 0x4B, 0x4B, 0x62,
-  0x62, 0x4B, 0x3A, 0xAD, 0xE2, 0xAF, 0xD9, 0xD9,
-  0x2C, 0xDA, 0xDA, 0xDA, 0xDA, 0x85, 0x2C, 0x2C,
-  0x2C, 0xAF, 0xAC, 0xD9, 0x95, 0xD6, 0xD6, 0xD9,
-  0x2C, 0x8C, 0xBA, 0x7C, 0x2E, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x62, 0xC9, 0xDC, 0x34, 0x20, 0x20, 0x20,
-  0x20, 0xAC, 0xE8, 0x5C, 0x8C, 0xBC, 0xE4, 0xE8,
-  0xEE, 0x2A, 0xA3, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE4, 0x7E, 0x65, 0x46, 0x29, 0x62, 0x62, 0x2E,
-  0x2E, 0x72, 0x2E, 0x2E, 0x32, 0x4B, 0x4B, 0x62,
-  0x4B, 0x4B, 0x4B, 0x32, 0x61, 0x9D, 0x2C, 0xD9,
-  0x2C, 0x85, 0xDA, 0x85, 0x2C, 0xAF, 0xAF, 0xAF,
-  0x2C, 0xAC, 0xD9, 0x95, 0xD6, 0x7D, 0x95, 0xAC,
-  0x2C, 0xDA, 0x40, 0x7C, 0x2E, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x62, 0x62, 0x22, 0xB7, 0xCE, 0x20, 0x20,
-  0x20, 0x95, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0x5C,
-  0x3D, 0xE9, 0x9A, 0x46, 0x7C, 0x32, 0x8B, 0x62,
-  0x4B, 0x8B, 0x8B, 0x4B, 0x4B, 0x4B, 0x4B, 0x62,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x62, 0x61, 0x4E, 0xDA,
-  0x85, 0x85, 0x85, 0x2C, 0xD9, 0xD9, 0xD9, 0xD9,
-  0x85, 0xD9, 0x7D, 0x21, 0x21, 0xD6, 0xAC, 0x2C,
-  0x2C, 0xDA, 0xDD, 0x77, 0x8B, 0x62, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x3E, 0x8B, 0x32, 0xC9, 0x22, 0x68, 0x88, 0x33,
-  0xA1, 0x73, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0x5C, 0x5C, 0x5C, 0x5C, 0x3D,
-  0x89, 0x20, 0x54, 0x23, 0x29, 0x2E, 0x4B, 0x62,
-  0x4B, 0x3E, 0x4B, 0x62, 0x4B, 0x4B, 0x4B, 0x8B,
-  0x8B, 0xC9, 0x6F, 0x4B, 0x8B, 0x4B, 0x78, 0xE2,
-  0x8A, 0x8A, 0x85, 0xAC, 0xD9, 0x7D, 0xD9, 0xAC,
-  0x2C, 0xD9, 0xD6, 0xB2, 0x21, 0x7D, 0xAF, 0x85,
-  0x2C, 0xDA, 0x40, 0xEF, 0x62, 0x62, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x8B, 0x4B, 0xC9, 0x63, 0xB4, 0x5C,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0xE8, 0xE8, 0xE8, 0xE8, 0x5C, 0x5C, 0xCD, 0xAE,
-  0x20, 0x20, 0xCE, 0xE1, 0x57, 0x32, 0x4B, 0x4B,
-  0x8B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x8B, 0x4B, 0x62, 0x4B, 0x62, 0x2E, 0x61, 0x28,
-  0x8D, 0xDA, 0xAF, 0xD9, 0x95, 0x95, 0xD9, 0xAF,
-  0xAF, 0xD9, 0xD6, 0xB2, 0x21, 0xD9, 0x2C, 0x85,
-  0xAF, 0xEB, 0xE1, 0x57, 0x2E, 0x62, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x3E, 0x9B, 0x31, 0x6E,
-  0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-  0x5C, 0xE8, 0xE8, 0xE8, 0x3D, 0x7D, 0x33, 0x6B,
-  0x20, 0x20, 0x34, 0x23, 0x29, 0x3E, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x3E, 0x62, 0x62, 0x2E, 0xC4, 0x49, 0xD5,
-  0xDA, 0xD9, 0xD6, 0xA1, 0xA1, 0x21, 0xD9, 0xD9,
-  0xD9, 0x95, 0x21, 0x48, 0xD6, 0xAC, 0x85, 0x85,
-  0xAF, 0xB6, 0x5D, 0x2E, 0x32, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x62, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x62, 0x2E, 0x45, 0xDE,
-  0xDA, 0x5C, 0xE8, 0x5C, 0xE8, 0xE8, 0x5C, 0xE8,
-  0x5C, 0x5C, 0xA3, 0xAC, 0x2B, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x34, 0x23, 0x29, 0x62, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x62, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x3E, 0x3E, 0x63, 0x40, 0x97, 0x28, 0xDA,
-  0xD9, 0xA1, 0x48, 0xE9, 0x48, 0x21, 0xD9, 0xD9,
-  0xA1, 0xB2, 0xB2, 0xA1, 0x21, 0xAC, 0x85, 0x2C,
-  0xDA, 0x36, 0x77, 0x72, 0x62, 0x8B, 0x62, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x3E, 0xEC, 0x2F, 0x51,
-  0xE3, 0xAE, 0x48, 0x2C, 0xDA, 0xDA, 0x85, 0xAC,
-  0x48, 0x9E, 0x88, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x41, 0xA0, 0x23, 0x72, 0x2E, 0x4B, 0x4B,
-  0x4B, 0x62, 0x62, 0x4B, 0x4B, 0x4B, 0x2E, 0x8B,
-  0xF0, 0x4C, 0x40, 0xC2, 0x90, 0x8D, 0x85, 0xD9,
-  0xA1, 0x6C, 0x6C, 0x48, 0xD6, 0xD9, 0xAF, 0xAC,
-  0xA1, 0xD6, 0xD6, 0xB2, 0xD6, 0xAC, 0x85, 0x85,
-  0x4D, 0xBE, 0x39, 0x4C, 0x57, 0x2E, 0x2E, 0x2E,
-  0x3E, 0x3E, 0x62, 0x3E, 0x4B, 0x4B, 0x4B, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x8B, 0x8B, 0x57, 0x60, 0x76,
-  0x52, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x3C, 0xA0, 0x23, 0x7C, 0x2E, 0x4B, 0x4B,
-  0x8B, 0x62, 0x4B, 0x4B, 0x3E, 0x7A, 0xF0, 0x29,
-  0x36, 0x97, 0xBC, 0x8A, 0x8D, 0xDA, 0xD9, 0x48,
-  0x81, 0x2D, 0x48, 0xD6, 0xD9, 0xAF, 0x2C, 0x2C,
-  0xAC, 0xAF, 0xD9, 0x7D, 0x7D, 0x2C, 0x85, 0x85,
-  0x85, 0xB4, 0x66, 0x23, 0x46, 0x2F, 0x60, 0x68,
-  0x77, 0x29, 0x29, 0xF0, 0x2E, 0x2E, 0x62, 0x4B,
-  0x4B, 0x4B, 0x4B, 0x4B, 0x32, 0x7C, 0x83, 0xB3,
-  0x54, 0x6B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x6B, 0x7B, 0xC3, 0xE7, 0x39, 0x72, 0x62, 0x62,
-  0x62, 0x62, 0x62, 0x2E, 0x29, 0x77, 0xA7, 0x36,
-  0xB8, 0x85, 0x85, 0x8D, 0x8D, 0x85, 0xB2, 0x2D,
-  0x2D, 0xE9, 0xD6, 0xD9, 0xAF, 0x2C, 0x85, 0x85,
-  0x2A, 0x85, 0xAC, 0x95, 0x95, 0xAF, 0x85, 0x85,
-  0xAF, 0x8C, 0xDF, 0xC6, 0xB1, 0xD1, 0xE5, 0xE7,
-  0x83, 0x23, 0x5D, 0x60, 0x39, 0x77, 0xEC, 0x2E,
-  0x2E, 0x32, 0x32, 0x2E, 0x7C, 0x5D, 0x35, 0xA2,
-  0x54, 0x6B, 0x6B, 0x20, 0x6B, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x6B, 0x88, 0xC1, 0x35, 0xE1, 0x77, 0x57, 0x2E,
-  0x2E, 0x72, 0x29, 0x77, 0x60, 0xB5, 0x44, 0xE2,
-  0x2C, 0x2C, 0xDA, 0x8A, 0xDA, 0xAF, 0xA1, 0x2D,
-  0xE9, 0xD6, 0xD9, 0xAF, 0x2C, 0x85, 0x85, 0x85,
-  0xEE, 0xAF, 0xD9, 0x7D, 0xD9, 0x2C, 0xDA, 0x85,
-  0xAC, 0xAF, 0x85, 0xDA, 0x8A, 0x2A, 0xE2, 0x50,
-  0x86, 0xD7, 0x75, 0x35, 0xA8, 0xE7, 0xE1, 0x5D,
-  0x68, 0x7C, 0xF1, 0x68, 0xE1, 0xBF, 0xA2, 0xC1,
-  0x52, 0x2B, 0x7D, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C,
-  0x2C, 0x85, 0x85, 0x85, 0x2C, 0x2C, 0x2C, 0x95,
-  0xE9, 0x74, 0xCE, 0xE0, 0xE7, 0x60, 0x77, 0x77,
-  0x7C, 0xEF, 0x5D, 0x23, 0x3F, 0xB6, 0x8A, 0x2C,
-  0xAC, 0xAF, 0x85, 0x8A, 0x85, 0xD9, 0x48, 0x48,
-  0xB2, 0x95, 0x95, 0xD9, 0x85, 0xDA, 0x85, 0x85,
-  0xD3, 0xB2, 0x21, 0x7D, 0xAC, 0x2C, 0xDA, 0x85,
-  0xAC, 0xAC, 0x85, 0x85, 0x85, 0x2C, 0xAF, 0x2C,
-  0xDA, 0x8C, 0x79, 0xC7, 0xB0, 0x51, 0xB3, 0x35,
-  0xBF, 0xE5, 0xE7, 0xA8, 0xE0, 0xA2, 0xC1, 0x34,
-  0x7D, 0x85, 0xAC, 0xD9, 0xAC, 0xAF, 0xAC, 0xAC,
-  0xAF, 0x2C, 0x2C, 0x2C, 0x2C, 0xAF, 0xAF, 0x85,
-  0xC8, 0xCD, 0x6A, 0x26, 0x35, 0x3F, 0x83, 0x23,
-  0x23, 0xE7, 0xBF, 0x96, 0xEB, 0xDA, 0xDA, 0x2C,
-  0x2C, 0x2C, 0x85, 0xDA, 0x2C, 0x7D, 0xA1, 0x48,
-  0xB2, 0x21, 0xD6, 0xD9, 0x2C, 0xDA, 0x85, 0xAF,
-  0xAF, 0x2D, 0xE9, 0x7D, 0xAC, 0x2C, 0x85, 0x2C,
-  0xD9, 0xD9, 0xAF, 0x85, 0x85, 0x85, 0x2C, 0x2C,
-  0x2C, 0x85, 0xD9, 0x21, 0xAC, 0x2C, 0xBD, 0xA5,
-  0xC3, 0xA2, 0xA2, 0xA2, 0x26, 0xC1, 0xCE, 0x2A,
-  0xAF, 0x95, 0xD9, 0x2C, 0x2C, 0x85, 0x2C, 0xAF,
-  0xAC, 0x2C, 0x85, 0x2C, 0xAF, 0x2C, 0x85, 0xDA,
-  0x8D, 0x2A, 0x85, 0x34, 0xC1, 0xB3, 0x76, 0x35,
-  0xE0, 0x30, 0xA5, 0xB6, 0x2C, 0x85, 0x85, 0x85,
-  0xAF, 0x2C, 0x85, 0x85, 0xD9, 0xD6, 0xA1, 0xA1,
-  0x48, 0xA1, 0xD6, 0xAF, 0xDA, 0x8A, 0x2C, 0xD9,
-  0xB2, 0x2D, 0x48, 0xD9, 0xAF, 0x2C, 0x2C, 0x85,
-  0xAF, 0xAC, 0x2C, 0x85, 0x85, 0x85, 0xAF, 0xAC,
-  0xAC, 0x2C, 0xD9, 0xD6, 0xD6, 0x21, 0xB2, 0x2C,
-  0xC8, 0x3B, 0x65, 0xC5, 0xCE, 0x8E, 0xC8, 0x2C,
-  0xD9, 0x95, 0xAC, 0x2C, 0x2C, 0x2C, 0xAF, 0xAC,
-  0xAC, 0xAF, 0x2C, 0x85, 0x2C, 0x2C, 0x2C, 0x85,
-  0xDA, 0x2C, 0xD6, 0xAF, 0x59, 0x65, 0xDE, 0xF3,
-  0xF3, 0x59, 0xBC, 0xAC, 0xAF, 0x85, 0x85, 0x85,
-  0xAF, 0xD9, 0xAF, 0x2C, 0xD9, 0xD6, 0xD6, 0xD6,
-  0x21, 0xD6, 0xD9, 0xDA, 0x8D, 0x8A, 0x2C, 0xD9,
-  0xB2, 0xA1, 0xD6, 0xAC, 0x2C, 0x2C, 0x2C, 0x85,
-  0x2C, 0xAC, 0x2C, 0xDA, 0xDA, 0x85, 0xAF, 0xD9,
-  0xD9, 0xAC, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xAC,
-  0x85, 0x2A, 0x4D, 0xBC, 0x85, 0xAC, 0xAF, 0xAF,
-  0xAC, 0xD9, 0xAF, 0x2C, 0xAF, 0xD9, 0xD9, 0xAC,
-  0xAC, 0xAF, 0x85, 0x2C, 0x85, 0x2C, 0x2C, 0x2C,
-  0x2C, 0xD9, 0xB2, 0xD4, 0xD6, 0x2C, 0x8A, 0xDA,
-  0xC8, 0x85, 0x2C, 0xAC, 0x2C, 0xDA, 0xDA, 0x85,
-  0xAF, 0xAC, 0xD9, 0xAC, 0xD9, 0xD9, 0xD9, 0xD9,
-  0xD9, 0xAC, 0xDA, 0x8D, 0xBC, 0xDA, 0xD9, 0x95,
-  0x95, 0xD9, 0xD9, 0xAF, 0x2C, 0x2C, 0x2C, 0x85,
-  0x2C, 0xAF, 0xAF, 0x85, 0x85, 0x85, 0x2C, 0xAC,
-  0xD9, 0xAF, 0xAF, 0xAF, 0x2C, 0x2C, 0x2C, 0x85,
-  0x8A, 0x2A, 0x8D, 0x2C, 0xD9, 0x95, 0xAC, 0xAC,
-  0xD9, 0xD9, 0xD9, 0xD9, 0x95, 0x95, 0xD9, 0xAF,
-  0xAF, 0x2C, 0x85, 0x85, 0x85, 0x85, 0x85, 0x2C,
-  0x85, 0x2C, 0xD9, 0xD9, 0xD9, 0x2C, 0x2C, 0x2C,
-  0x2C, 0x85, 0x85, 0xAF, 0xAF, 0x85, 0x85, 0x85,
-  0xAF, 0xD9, 0xD9, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C,
-  0x2C, 0x85, 0x8A, 0x2A, 0x8D, 0x2C, 0xD9, 0xD9,
-  0x2C, 0xAC, 0xAF, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C,
-  0x85, 0xAF, 0xAC, 0x2C, 0x2C, 0x2C, 0x2C, 0xAC,
-  0xD9, 0xD9, 0xAF, 0x85, 0x85, 0x85, 0xDA, 0xDA,
-  0x8A, 0x8A, 0x85, 0xAC, 0xD9, 0xD9, 0xAC, 0xD9,
-  0xD6, 0xD6, 0x7D, 0x95, 0x7D, 0xD9, 0xAF, 0xAF,
-  0xAF, 0x2C, 0x85, 0x85, 0xDA, 0x85, 0x2C, 0x85,
-  0x85, 0x2C, 0xAF, 0xAC, 0xAF, 0xAF, 0x2C, 0x2C,
-  0x2C, 0x2C, 0x2C, 0xAF, 0xAC, 0x2C, 0x2C, 0x2C,
-  0x2C, 0xAF, 0xD9, 0xAC, 0xAF, 0x2C, 0x85, 0x85,
-  0x85, 0xDA, 0x8D, 0x8A, 0x85, 0xAC, 0x95, 0xD9
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22,
+    0x22, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+    0x26, 0x26, 0x25, 0x28, 0x23, 0x22, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x25, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d,
+    0x2d, 0x2e, 0x2c, 0x2b, 0x2a, 0x25, 0x28, 0x22,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x24, 0x2a, 0x2c, 0x2f, 0x2c, 0x30, 0x30, 0x24,
+    0x25, 0x27, 0x2b, 0x2c, 0x2f, 0x31, 0x32, 0x25,
+    0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
+    0x33, 0x34, 0x35, 0x21, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x21, 0x2b, 0x2f, 0x2c,
+    0x30, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
+    0x2d, 0x27, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x31,
+    0x2d, 0x32, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x28, 0x2a, 0x34,
+    0x25, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x23, 0x32, 0x27, 0x21, 0x36,
+    0x2a, 0x2d, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x22, 0x26, 0x2c, 0x35,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x25, 0x2f, 0x37, 0x32, 0x22,
+    0x36, 0x35, 0x31, 0x27, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x22,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x26, 0x38, 0x38, 0x35, 0x25,
+    0x36, 0x21, 0x2d, 0x2b, 0x24, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x24, 0x39, 0x39, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x25, 0x2b, 0x30, 0x28, 0x22,
+    0x36, 0x36, 0x27, 0x34, 0x30, 0x23, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x26, 0x2d, 0x26, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x22, 0x22, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x2d, 0x33, 0x28, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x2b, 0x2c, 0x25, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x36, 0x36,
+    0x36, 0x21, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x21, 0x23, 0x22, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x28, 0x34, 0x27, 0x22, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
+    0x21, 0x21, 0x24, 0x27, 0x21, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x28, 0x27, 0x22, 0x33, 0x24, 0x36,
+    0x36, 0x36, 0x36, 0x22, 0x2f, 0x2a, 0x23, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
+    0x30, 0x3a, 0x38, 0x24, 0x24, 0x36, 0x36, 0x36,
+    0x23, 0x2f, 0x3b, 0x3c, 0x3d, 0x30, 0x25, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2f, 0x32, 0x23, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x23,
+    0x3e, 0x3f, 0x40, 0x3a, 0x22, 0x36, 0x36, 0x21,
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x3e, 0x23, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2f, 0x33, 0x28, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x2b,
+    0x44, 0x40, 0x46, 0x47, 0x35, 0x36, 0x36, 0x26,
+    0x43, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x2e, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x34, 0x36, 0x4d,
+    0x4e, 0x25, 0x2f, 0x46, 0x4a, 0x22, 0x23, 0x32,
+    0x4f, 0x50, 0x21, 0x31, 0x51, 0x52, 0x53, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x21, 0x3a,
+    0x4d, 0x21, 0x31, 0x54, 0x55, 0x28, 0x30, 0x2b,
+    0x4b, 0x4d, 0x36, 0x23, 0x32, 0x50, 0x3f, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x38, 0x23, 0x37,
+    0x55, 0x36, 0x28, 0x3a, 0x56, 0x57, 0x57, 0x58,
+    0x3c, 0x4d, 0x36, 0x36, 0x36, 0x40, 0x40, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x29, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x51, 0x23, 0x35,
+    0x43, 0x25, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e,
+    0x5f, 0x60, 0x61, 0x36, 0x31, 0x47, 0x3b, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x2c, 0x25, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x22,
+    0x40, 0x62, 0x63, 0x5d, 0x64, 0x65, 0x66, 0x67,
+    0x68, 0x69, 0x66, 0x5e, 0x6a, 0x6b, 0x2a, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x33, 0x2e, 0x26, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x2f, 0x23, 0x36,
+    0x6c, 0x63, 0x6d, 0x64, 0x5c, 0x66, 0x69, 0x6e,
+    0x6f, 0x70, 0x71, 0x69, 0x69, 0x72, 0x6c, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x33, 0x34, 0x27, 0x22,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x34, 0x26, 0x73,
+    0x74, 0x75, 0x76, 0x64, 0x65, 0x77, 0x69, 0x78,
+    0x70, 0x71, 0x71, 0x71, 0x72, 0x5f, 0x5e, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x25, 0x38, 0x2a, 0x23,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x33, 0x79,
+    0x63, 0x7a, 0x7b, 0x5c, 0x66, 0x69, 0x6e, 0x7c,
+    0x71, 0x71, 0x69, 0x7d, 0x7e, 0x7a, 0x7f, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x21, 0x51, 0x2b, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x32, 0x24,
+    0x80, 0x81, 0x64, 0x82, 0x77, 0x69, 0x71, 0x71,
+    0x69, 0x83, 0x84, 0x85, 0x7a, 0x85, 0x86, 0x36,
+    0x21, 0x2b, 0x23, 0x36, 0x36, 0x39, 0x2e, 0x26,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x2d, 0x33, 0x21,
+    0x87, 0x88, 0x89, 0x72, 0x67, 0x66, 0x5f, 0x89,
+    0x8a, 0x63, 0x85, 0x8b, 0x8c, 0x8d, 0x41, 0x36,
+    0x36, 0x2d, 0x3a, 0x35, 0x36, 0x24, 0x51, 0x32,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x33, 0x21,
+    0x55, 0x8e, 0x8f, 0x8a, 0x7d, 0x5e, 0x90, 0x7e,
+    0x75, 0x75, 0x90, 0x62, 0x40, 0x3f, 0x49, 0x23,
+    0x36, 0x24, 0x3a, 0x3a, 0x24, 0x36, 0x2e, 0x31,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x28, 0x33, 0x37, 0x25, 0x22,
+    0x3b, 0x50, 0x8e, 0x8f, 0x90, 0x7e, 0x90, 0x63,
+    0x74, 0x91, 0x92, 0x42, 0x93, 0x4b, 0x45, 0x2c,
+    0x36, 0x36, 0x33, 0x39, 0x21, 0x36, 0x22, 0x51,
+    0x33, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x22, 0x27, 0x2e, 0x2e, 0x36, 0x21,
+    0x94, 0x3f, 0x50, 0x95, 0x96, 0x8f, 0x8f, 0x97,
+    0x8e, 0x42, 0x50, 0x43, 0x47, 0x48, 0x48, 0x98,
+    0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39,
+    0x2e, 0x27, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x22, 0x24, 0x2b, 0x38, 0x28, 0x36, 0x32,
+    0x4c, 0x4b, 0x50, 0x50, 0x50, 0x42, 0x42, 0x50,
+    0x50, 0x40, 0x45, 0x99, 0x48, 0x48, 0x48, 0x48,
+    0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x23,
+    0x2f, 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x32, 0x51, 0x32, 0x28, 0x21, 0x98,
+    0x48, 0x47, 0x9a, 0x50, 0x50, 0x50, 0x50, 0x50,
+    0x9a, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x93, 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x2a, 0x2f, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x23, 0x30, 0x2e, 0x2c, 0x36, 0x21, 0x51, 0x9b,
+    0x48, 0x48, 0x52, 0x3f, 0x50, 0x50, 0x40, 0x4b,
+    0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2d, 0x31, 0x27, 0x23, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x27, 0x2c, 0x2d, 0x21, 0x36, 0x28, 0x44, 0x48,
+    0x48, 0x48, 0x48, 0x47, 0x46, 0x4f, 0x47, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x9c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x28, 0x51, 0x39, 0x26, 0x22, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
+    0x35, 0x51, 0x28, 0x36, 0x36, 0x9d, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x4f, 0x28, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x28, 0x38, 0x2b, 0x25, 0x22, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
+    0x51, 0x25, 0x36, 0x36, 0x23, 0x40, 0x9b, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x9b, 0x99, 0x2b, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x30, 0x2f, 0x33, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x23, 0x30, 0x34,
+    0x27, 0x36, 0x36, 0x36, 0x2a, 0x40, 0x47, 0x48,
+    0x48, 0x48, 0x48, 0x9b, 0x99, 0x99, 0x9b, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x47, 0x52,
+    0x46, 0x4f, 0x37, 0x21, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x30, 0x34, 0x2a, 0x23,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x22, 0x25, 0x39, 0x2c,
+    0x36, 0x36, 0x36, 0x21, 0x31, 0x4e, 0x9a, 0x4c,
+    0x47, 0x9b, 0x9b, 0x52, 0x46, 0x4f, 0x52, 0x9b,
+    0x9b, 0x9b, 0x47, 0x4f, 0x45, 0x9a, 0x93, 0x93,
+    0x3f, 0x93, 0x98, 0x28, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, 0x26,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x28,
+    0x36, 0x36, 0x36, 0x22, 0x38, 0x98, 0x44, 0x99,
+    0x9b, 0x48, 0x48, 0x9b, 0x4c, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x47, 0x52, 0x46, 0x43, 0x93,
+    0x40, 0x40, 0x43, 0x53, 0x21, 0x23, 0x33, 0x23,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x2f, 0x32,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x24, 0x2b, 0x31, 0x36,
+    0x36, 0x22, 0x36, 0x24, 0x9e, 0x4f, 0x9b, 0x48,
+    0x48, 0x48, 0x48, 0x9b, 0x99, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x47,
+    0x4f, 0x9a, 0x3f, 0x46, 0x38, 0x36, 0x21, 0x30,
+    0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c,
+    0x25, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2e, 0x33, 0x36,
+    0x25, 0x25, 0x36, 0x4d, 0x52, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x4f, 0x3e, 0x4d, 0x49, 0x48,
+    0x98, 0x2b, 0x55, 0x4f, 0x9b, 0x48, 0x48, 0x48,
+    0x48, 0x47, 0x44, 0x93, 0x43, 0x23, 0x36, 0x36,
+    0x26, 0x24, 0x36, 0x36, 0x36, 0x36, 0x28, 0x2f,
+    0x2a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x51, 0x24, 0x36,
+    0x2a, 0x36, 0x28, 0x44, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x4f, 0x54, 0x38, 0x3d, 0x98, 0x37, 0x9b,
+    0x3a, 0x22, 0x23, 0x2a, 0x55, 0x4f, 0x48, 0x48,
+    0x48, 0x48, 0x9b, 0x4b, 0x44, 0x37, 0x36, 0x23,
+    0x28, 0x30, 0x22, 0x36, 0x36, 0x36, 0x36, 0x2d,
+    0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x28, 0x2b, 0x34, 0x36, 0x25,
+    0x24, 0x36, 0x4a, 0x48, 0x48, 0x48, 0x48, 0x52,
+    0x53, 0x37, 0x54, 0x98, 0x55, 0x38, 0x38, 0x47,
+    0x4a, 0x2d, 0x30, 0x23, 0x28, 0x39, 0x53, 0x52,
+    0x48, 0x48, 0x48, 0x9b, 0x52, 0x3f, 0x21, 0x30,
+    0x35, 0x25, 0x30, 0x36, 0x36, 0x36, 0x36, 0x32,
+    0x2d, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x22, 0x26, 0x2e, 0x35, 0x36, 0x2a,
+    0x36, 0x24, 0x4f, 0x48, 0x48, 0x9b, 0x55, 0x39,
+    0x55, 0x53, 0x3a, 0x55, 0x3a, 0x51, 0x51, 0x47,
+    0x55, 0x3a, 0x4d, 0x37, 0x30, 0x22, 0x24, 0x2b,
+    0x54, 0x9b, 0x48, 0x48, 0x48, 0x47, 0x32, 0x30,
+    0x2a, 0x23, 0x30, 0x23, 0x36, 0x36, 0x36, 0x21,
+    0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x2a, 0x51, 0x28, 0x28, 0x25,
+    0x36, 0x3a, 0x48, 0x48, 0x48, 0x4f, 0x26, 0x23,
+    0x26, 0x39, 0x3e, 0x43, 0x49, 0x37, 0x2f, 0x9b,
+    0x55, 0x3a, 0x54, 0x43, 0x3e, 0x30, 0x32, 0x3d,
+    0x49, 0x3f, 0x48, 0x48, 0x48, 0x48, 0x38, 0x21,
+    0x36, 0x36, 0x22, 0x27, 0x36, 0x36, 0x36, 0x36,
+    0x2e, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x22, 0x25, 0x2c, 0x34, 0x36, 0x30, 0x21,
+    0x23, 0x43, 0x48, 0x48, 0x48, 0x47, 0x3b, 0x32,
+    0x21, 0x28, 0x2b, 0x9e, 0x49, 0x37, 0x2e, 0x52,
+    0x4a, 0x37, 0x9e, 0x98, 0x51, 0x3a, 0x93, 0x54,
+    0x55, 0x4f, 0x48, 0x48, 0x48, 0x48, 0x94, 0x36,
+    0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36,
+    0x2a, 0x2e, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x2a, 0x51, 0x25, 0x21, 0x2a, 0x36,
+    0x2e, 0x9b, 0x48, 0x48, 0x52, 0x4b, 0x52, 0x9e,
+    0x51, 0x30, 0x22, 0x28, 0x32, 0x32, 0x39, 0x47,
+    0x37, 0x2a, 0x39, 0x3a, 0x50, 0x9f, 0x3a, 0x9f,
+    0x4b, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x98, 0x36,
+    0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36,
+    0x22, 0x2f, 0x30, 0x22, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x22, 0x25, 0x2c, 0x34, 0x36, 0x24, 0x28, 0x36,
+    0x54, 0x48, 0x48, 0x45, 0x30, 0x30, 0x9e, 0x52,
+    0x45, 0x3a, 0x31, 0x25, 0x22, 0x25, 0x2a, 0x98,
+    0x39, 0x2f, 0x42, 0x49, 0x4a, 0x3b, 0x50, 0x47,
+    0x43, 0x9d, 0x3b, 0x4b, 0x48, 0x48, 0x9a, 0x36,
+    0x36, 0x36, 0x36, 0x30, 0x36, 0x36, 0x36, 0x36,
+    0x21, 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x28, 0x32, 0x2f, 0x28, 0x36, 0x27, 0x22, 0x21,
+    0x43, 0x48, 0x48, 0x50, 0x30, 0x23, 0x25, 0x2f,
+    0x3f, 0x52, 0x49, 0x51, 0x39, 0x25, 0x24, 0x2b,
+    0x9e, 0x42, 0x3e, 0x55, 0x9e, 0x4f, 0x4f, 0x54,
+    0x4a, 0x9e, 0x49, 0x50, 0x48, 0x48, 0x4b, 0x21,
+    0x36, 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x25, 0x2c, 0x39, 0x36, 0x36, 0x30, 0x22, 0x25,
+    0x52, 0x48, 0x48, 0x45, 0x3a, 0x51, 0x26, 0x23,
+    0x30, 0x9d, 0x45, 0x40, 0x3a, 0x39, 0x2b, 0x2b,
+    0x3b, 0x3a, 0x55, 0x4b, 0x47, 0x9e, 0x3a, 0x49,
+    0x9e, 0x9f, 0x3b, 0x9a, 0x48, 0x48, 0x4f, 0x21,
+    0x36, 0x36, 0x22, 0x26, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x30, 0x2d, 0x21, 0x36, 0x36, 0x32, 0x23, 0x2a,
+    0x47, 0x48, 0x48, 0x43, 0x3e, 0x3a, 0x9d, 0x2b,
+    0x23, 0x25, 0x39, 0x4d, 0x2b, 0x31, 0x2d, 0x9d,
+    0x34, 0x2e, 0x2f, 0x9e, 0x3a, 0x55, 0x3f, 0x9f,
+    0x9f, 0x3e, 0x55, 0x43, 0x48, 0x48, 0x4c, 0x22,
+    0x36, 0x36, 0x24, 0x23, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0x2e, 0x36, 0x36, 0x23, 0x31, 0x27, 0x39,
+    0x9b, 0x48, 0x48, 0x4f, 0x3e, 0x4d, 0x55, 0x9e,
+    0x51, 0x24, 0x23, 0x26, 0x32, 0x2c, 0x3b, 0x4b,
+    0x55, 0x32, 0x2b, 0x37, 0x98, 0x9e, 0x3e, 0x9e,
+    0x55, 0x37, 0x3e, 0x4b, 0x48, 0x48, 0x4c, 0x23,
+    0x36, 0x36, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x2b, 0x39, 0x36, 0x36, 0x36, 0x26, 0x32, 0x31,
+    0x9b, 0x48, 0x48, 0x4f, 0x55, 0x3a, 0x53, 0x53,
+    0x2e, 0x9d, 0x34, 0x28, 0x28, 0x37, 0x98, 0x45,
+    0x3e, 0x2b, 0x49, 0x9e, 0x3b, 0x3e, 0x2d, 0x6b,
+    0x4a, 0x3a, 0x3b, 0x4f, 0x48, 0x48, 0x46, 0x22,
+    0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x35, 0x39, 0x36, 0x36, 0x36, 0x36, 0x26, 0x2d,
+    0x9b, 0x48, 0x48, 0x47, 0x3b, 0x3a, 0x2f, 0x37,
+    0x49, 0x38, 0x38, 0x3a, 0x2b, 0x31, 0x51, 0x32,
+    0x2b, 0x26, 0x37, 0x9f, 0x55, 0x32, 0x26, 0x2b,
+    0x2d, 0x9d, 0x3b, 0x52, 0x48, 0x48, 0x9a, 0x36,
+    0x24, 0x27, 0xa0, 0x24, 0x25, 0x28, 0x21, 0x36,
+    0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x25,
+    0x39, 0x4d, 0xa1, 0x84, 0x81, 0x57, 0x21, 0x39,
+    0x52, 0x48, 0x48, 0x47, 0x9f, 0x4a, 0x4d, 0x55,
+    0x37, 0x9f, 0x45, 0x9e, 0x3e, 0x54, 0x4d, 0x2d,
+    0x51, 0x3b, 0x3d, 0x40, 0x50, 0x2f, 0x32, 0x23,
+    0x2a, 0x3a, 0x54, 0x47, 0x48, 0x48, 0x53, 0x28,
+    0x23, 0x36, 0x36, 0x36, 0x21, 0x28, 0x2c, 0x30,
+    0x21, 0x38, 0x33, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x28, 0x30,
+    0x2d, 0xa2, 0x7a, 0xa3, 0xa4, 0xa4, 0x7f, 0x22,
+    0x51, 0x52, 0x48, 0x9b, 0x3b, 0x3a, 0x2f, 0x54,
+    0x3f, 0x4b, 0x3b, 0x34, 0x3e, 0x55, 0x34, 0x4d,
+    0x34, 0x3b, 0x3b, 0x55, 0x42, 0x4b, 0x9e, 0x31,
+    0x2b, 0x3a, 0x9e, 0x47, 0xa5, 0xa5, 0xa6, 0x61,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x30, 0x32,
+    0x25, 0x4d, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x24, 0x26, 0x30, 0x33, 0x31,
+    0x4d, 0x91, 0x5b, 0xa3, 0xa4, 0xa4, 0xa4, 0x5a,
+    0x21, 0x2e, 0x46, 0x48, 0x9a, 0x3b, 0x42, 0x47,
+    0x42, 0x9d, 0x37, 0x39, 0x4a, 0x3e, 0x3a, 0x52,
+    0x38, 0x3e, 0x3e, 0x2b, 0x25, 0x37, 0x4f, 0x4f,
+    0x55, 0x55, 0x45, 0xa7, 0xa8, 0x69, 0x66, 0xa9,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x26, 0x25,
+    0x83, 0xaa, 0x2c, 0x25, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x30, 0x35, 0x2d, 0x2f, 0x37, 0x4a,
+    0x60, 0x85, 0xab, 0xac, 0xa4, 0xa4, 0xa4, 0x82,
+    0x86, 0x36, 0x32, 0x3f, 0x48, 0x47, 0x4b, 0x4a,
+    0x9d, 0x55, 0x2f, 0x51, 0x3a, 0x3b, 0x55, 0x9b,
+    0x4d, 0x3b, 0x55, 0x39, 0x24, 0x28, 0x32, 0x9e,
+    0x47, 0x47, 0x48, 0xad, 0xa3, 0xa8, 0xae, 0xaf,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x57,
+    0x77, 0x66, 0x34, 0x27, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x23, 0x30, 0x31, 0xb0, 0x91, 0x7e, 0x90, 0x90,
+    0x8b, 0x5b, 0xa3, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0x5d, 0xb1, 0x36, 0x24, 0x53, 0x47, 0x37, 0x30,
+    0x32, 0x2e, 0x98, 0x3f, 0x3a, 0x3e, 0x4a, 0x47,
+    0x9d, 0x3e, 0x54, 0x40, 0x55, 0x30, 0x30, 0x4a,
+    0x6b, 0x9b, 0x99, 0xad, 0x64, 0x5c, 0x8b, 0xb1,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x73, 0x5d,
+    0x82, 0x5c, 0xb2, 0x2a, 0x23, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x24, 0x2b, 0xb0, 0x8b, 0x5b, 0x76, 0x5b, 0x5b,
+    0x7b, 0xa3, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa8, 0x5e, 0x22, 0x36, 0x21, 0x3a, 0x3d, 0x30,
+    0x22, 0x28, 0x3a, 0x44, 0x4a, 0x3e, 0x3e, 0x9b,
+    0x9d, 0x3e, 0x9e, 0x4b, 0x55, 0x2e, 0x42, 0x9f,
+    0x93, 0x4f, 0x3f, 0xb3, 0x7b, 0x7b, 0x85, 0x80,
+    0xa0, 0x36, 0x36, 0x36, 0x21, 0xb4, 0x7e, 0x7b,
+    0x64, 0x64, 0xb5, 0x35, 0x24, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x31, 0xb6, 0x5b, 0x64, 0xa3, 0xa3, 0xac,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0x66, 0xb7, 0x36, 0x36, 0x36, 0x2c, 0x54,
+    0x31, 0x23, 0x26, 0x2c, 0x3a, 0x3b, 0x55, 0x47,
+    0x37, 0x3b, 0x3b, 0x38, 0x4a, 0x98, 0x55, 0x98,
+    0x47, 0x9a, 0x3f, 0xb8, 0x76, 0x76, 0x7a, 0x63,
+    0xb9, 0xba, 0x86, 0xba, 0xbb, 0x90, 0x5b, 0x64,
+    0xa3, 0xa3, 0xbc, 0x2d, 0x27, 0x23, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x26, 0x2d, 0x91, 0x5b, 0x64, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa8, 0x83, 0xaf, 0x36, 0x36, 0x36, 0x30,
+    0x98, 0x37, 0x30, 0x26, 0x9d, 0x3e, 0x9f, 0x9b,
+    0x37, 0x3b, 0x3b, 0x53, 0x53, 0x3d, 0x4b, 0x48,
+    0x9b, 0x9a, 0x3f, 0xbd, 0x5b, 0x7b, 0xbe, 0x85,
+    0x7e, 0x90, 0x63, 0x90, 0x85, 0x5b, 0xa3, 0xa4,
+    0xa4, 0xac, 0x5d, 0xb5, 0x39, 0x26, 0x23, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2d, 0xbf, 0xbe, 0x64, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa8, 0x88, 0x36, 0x36, 0x36, 0x36,
+    0x2d, 0x3f, 0x3b, 0x31, 0x4d, 0x3e, 0x9f, 0x47,
+    0x38, 0x3b, 0x3e, 0x3e, 0x98, 0x52, 0x48, 0x48,
+    0x9b, 0x45, 0x3f, 0xc0, 0x6d, 0x7b, 0xab, 0xbe,
+    0x7a, 0x8b, 0x8b, 0x7a, 0x5b, 0x64, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa3, 0xc1, 0x37, 0x35, 0x26, 0x23,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2e, 0xbf, 0x7a, 0x7b, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa8, 0x72, 0x73, 0x36, 0x36, 0x36,
+    0x24, 0x52, 0x47, 0x49, 0x3a, 0x55, 0x98, 0x47,
+    0x9d, 0x3e, 0x54, 0x45, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x46, 0x42, 0xb6, 0x7a, 0x7b, 0x64, 0x7b,
+    0x76, 0x5b, 0x5b, 0x76, 0x7b, 0xa3, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xac, 0x64, 0xc1, 0x4d, 0x2c, 0x27,
+    0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x25, 0x31, 0xc2, 0x8b, 0x7b, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa8, 0x89, 0xa0, 0x36, 0x36,
+    0x32, 0x47, 0x48, 0x9b, 0x9a, 0x3f, 0x47, 0x48,
+    0x4b, 0x40, 0x4f, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x4b, 0x2f, 0x8f, 0x7a, 0x7b, 0xa3, 0xac,
+    0xa3, 0x64, 0x64, 0xa3, 0xa3, 0xac, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa3, 0x5d, 0xc3, 0x2c,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x25, 0x31, 0xc2, 0x85, 0x7b, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0x66, 0x57, 0x27, 0x4d,
+    0x4b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x99, 0x34, 0xa0, 0xb9, 0x7a, 0x7b, 0xa3, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa3, 0xc2,
+    0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2d, 0xc2, 0x85, 0x7b, 0xac, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa8, 0x5f, 0x92, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x44,
+    0x35, 0x36, 0xaf, 0xbb, 0x7a, 0x7b, 0xac, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xac, 0xa3, 0xc0,
+    0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x30, 0x2f, 0xb6, 0x8b, 0x7b, 0xac, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0x66, 0x89, 0x45,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x4e, 0x25,
+    0x36, 0x36, 0x61, 0xb9, 0x6d, 0x64, 0xac, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xac, 0x7b, 0xbe, 0xc3,
+    0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0xc4, 0x63, 0xbe, 0xa3, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa3, 0x72, 0x81, 0xc5,
+    0x46, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x3f, 0x2c, 0x36, 0x36,
+    0x36, 0x36, 0xc6, 0x8f, 0x6d, 0x64, 0xac, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa3, 0xab, 0x8b, 0xb0, 0x2c,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x35, 0x96, 0x75, 0xab, 0xa3, 0xac, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xac, 0x7b, 0x81, 0xb9,
+    0x73, 0x3b, 0x44, 0x9b, 0x48, 0x48, 0x48, 0x9b,
+    0x99, 0x43, 0x94, 0x2c, 0x21, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x73, 0xb9, 0x7a, 0x7b, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0x64, 0x76, 0x7a, 0x91, 0xb5, 0x31, 0x30,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x39, 0x97, 0x75, 0xbe, 0x7b, 0x64, 0xa3, 0xa3,
+    0xac, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0x7b, 0x7a, 0xc7,
+    0xc8, 0x36, 0x21, 0x26, 0x2b, 0x39, 0x33, 0x30,
+    0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xc8, 0xbb, 0x8b, 0x7b, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa3, 0x64, 0x64,
+    0x76, 0x85, 0xbf, 0xb5, 0x34, 0x2b, 0x27, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0xc9, 0x63, 0x7e, 0x7a, 0x6d, 0xbe, 0x5b,
+    0x76, 0x7b, 0x64, 0x64, 0xa3, 0xac, 0xa4, 0xa4,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xac, 0x76, 0x85, 0xb9,
+    0x79, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xca, 0xbb, 0x75, 0x76, 0xa3, 0xa4,
+    0xa4, 0xa4, 0xac, 0xa3, 0x64, 0x76, 0xbe, 0x8b,
+    0xb6, 0xb5, 0x2f, 0x35, 0x30, 0x24, 0x22, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x27, 0x31, 0xcb, 0xc9, 0xbb, 0x74, 0x63, 0x90,
+    0x7e, 0x75, 0x8b, 0x6d, 0xbe, 0x76, 0x64, 0xa3,
+    0xac, 0xac, 0xac, 0xac, 0x64, 0x7a, 0x84, 0xcc,
+    0x79, 0xa0, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xc8, 0xcc, 0x63, 0x6d, 0x7b, 0x64,
+    0xac, 0xa3, 0x64, 0x7b, 0xbe, 0x75, 0x63, 0x96,
+    0x38, 0x39, 0x2a, 0x24, 0x23, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x28, 0x27, 0x35, 0x2d, 0x41, 0xb5, 0xc5, 0x8f,
+    0xb9, 0xbb, 0xc7, 0x74, 0x84, 0x90, 0x85, 0x6d,
+    0x5b, 0x7b, 0x7b, 0xab, 0x6d, 0x90, 0xb9, 0xcd,
+    0xca, 0x22, 0x36, 0x36, 0x28, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x25, 0x36,
+    0x36, 0x21, 0xb4, 0x80, 0xc7, 0x7e, 0x6d, 0x76,
+    0xab, 0x76, 0x6d, 0x85, 0x63, 0xb9, 0xb5, 0x34,
+    0x33, 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x24, 0x27, 0x2a, 0x35, 0x2e, 0x2f,
+    0x41, 0xce, 0xcf, 0x6c, 0x80, 0xcc, 0xb9, 0x74,
+    0x84, 0x90, 0x75, 0x7e, 0x74, 0x8f, 0xcd, 0x79,
+    0xc6, 0x2b, 0x9d, 0x41, 0x2f, 0x34, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x34, 0x2f, 0x38,
+    0x4d, 0x37, 0xd0, 0xd1, 0x8f, 0x74, 0x63, 0x7e,
+    0x75, 0x7e, 0x63, 0xc7, 0x88, 0xc4, 0x31, 0x2a,
+    0x24, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x22, 0x23, 0x24, 0x26, 0x30,
+    0x33, 0x39, 0x2e, 0x51, 0x41, 0xb2, 0x6c, 0xd1,
+    0x80, 0xcc, 0xcc, 0xcc, 0xd2, 0xd1, 0xb7, 0xd3,
+    0x41, 0x34, 0x35, 0x32, 0x30, 0x27, 0x27, 0x27,
+    0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x2a,
+    0x2b, 0x34, 0xd4, 0xca, 0xd5, 0x8f, 0xbb, 0xc7,
+    0xc7, 0xbb, 0xcc, 0x6c, 0x41, 0x39, 0x27, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22,
+    0x28, 0x24, 0x26, 0x2a, 0x33, 0x2c, 0x2f, 0x41,
+    0xd6, 0xb7, 0x79, 0x79, 0x79, 0xca, 0xd7, 0x51,
+    0x39, 0x30, 0x24, 0x23, 0x22, 0x22, 0x22, 0x22,
+    0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23,
+    0x24, 0x2a, 0x31, 0xd8, 0xc8, 0x79, 0xd1, 0x80,
+    0xd5, 0xba, 0xd9, 0x2f, 0x35, 0x26, 0x23, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x22, 0x23, 0x28, 0x25, 0x30, 0x2b,
+    0x31, 0x2f, 0xd4, 0xd8, 0xd8, 0x2f, 0x2e, 0x33,
+    0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x27, 0x35, 0x34, 0xd8, 0xd8, 0xd8,
+    0xda, 0xd4, 0x2e, 0x33, 0x25, 0x23, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x23, 0x28,
+    0x26, 0x30, 0x32, 0x2b, 0x33, 0x2a, 0x26, 0x28,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x25, 0x30, 0x33, 0x35, 0x35,
+    0x2b, 0x2a, 0x26, 0x28, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x21, 0x22, 0x23, 0x28, 0x28, 0x23, 0x22, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x23, 0x28, 0x24, 0x24,
+    0x28, 0x23, 0x22, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 };
 
-#define INCLUDE_LINUX_LOGOBW
-#define INCLUDE_LINUX_LOGO16
-#include <linux/linux_logo.h>
-
-#else
+#endif /* INCLUDE_LINUX_LOGO_DATA */
 
-/* prototypes only */
-extern unsigned char linux_logo_red[];
-extern unsigned char linux_logo_green[];
-extern unsigned char linux_logo_blue[];
-extern unsigned char linux_logo[];
-extern unsigned char linux_logo_bw[];
-extern unsigned char linux_logo16_red[];
-extern unsigned char linux_logo16_green[];
-extern unsigned char linux_logo16_blue[];
-extern unsigned char linux_logo16[];
+#include <linux/linux_logo.h>
 
-#endif
diff -u --recursive --new-file v2.4.5/linux/include/asm-mips64/termios.h linux/include/asm-mips64/termios.h
--- v2.4.5/linux/include/asm-mips64/termios.h	Sat Feb  3 20:00:45 2001
+++ linux/include/asm-mips64/termios.h	Mon Jun 11 19:15:27 2001
@@ -101,6 +101,7 @@
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14	/* synchronous PPP */
+#define N_HCI		15  /* Bluetooth HCI UART */
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-parisc/linux_logo.h linux/include/asm-parisc/linux_logo.h
--- v2.4.5/linux/include/asm-parisc/linux_logo.h	Tue Dec  5 12:29:39 2000
+++ linux/include/asm-parisc/linux_logo.h	Mon Jun 11 19:15:27 2001
@@ -23,26 +23,5 @@
 
 #define linux_logo_banner "Linux/PA-RISC version " UTS_RELEASE
 
-#define LINUX_LOGO_COLORS 214
-
-#ifdef INCLUDE_LINUX_LOGO_DATA
-
-#define INCLUDE_LINUX_LOGOBW
-#define INCLUDE_LINUX_LOGO16
-
 #include <linux/linux_logo.h>
 
-#else
-
-/* prototypes only */
-extern unsigned char linux_logo_red[];
-extern unsigned char linux_logo_green[];
-extern unsigned char linux_logo_blue[];
-extern unsigned char linux_logo[];
-extern unsigned char linux_logo_bw[];
-extern unsigned char linux_logo16_red[];
-extern unsigned char linux_logo16_green[];
-extern unsigned char linux_logo16_blue[];
-extern unsigned char linux_logo16[];
-
-#endif
diff -u --recursive --new-file v2.4.5/linux/include/asm-parisc/termios.h linux/include/asm-parisc/termios.h
--- v2.4.5/linux/include/asm-parisc/termios.h	Sat Feb  3 20:00:45 2001
+++ linux/include/asm-parisc/termios.h	Mon Jun 11 19:15:27 2001
@@ -53,6 +53,7 @@
 #define N_PROFIBUS_FDL	10	/* Reserved for Profibus <Dave@mvhi.com> */
 #define N_IRDA		11	/* Linux IR - http://irda.sourceforge.net/ */
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
+#define N_HCI		15  /* Bluetooth HCI UART */
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-ppc/bitops.h linux/include/asm-ppc/bitops.h
--- v2.4.5/linux/include/asm-ppc/bitops.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/bitops.h	Mon Jun 11 19:15:27 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.bitops.h 1.7 05/17/01 18:14:24 cort
+ * BK Id: SCCS/s.bitops.h 1.9 05/26/01 14:48:14 paulus
  */
 /*
  * bitops.h: Bit string operations on the ppc
@@ -24,12 +24,9 @@
 #define SMP_MB
 #endif /* CONFIG_SMP */
 
-#define __INLINE_BITOPS	1
-
-#if __INLINE_BITOPS
 /*
  * These used to be if'd out here because using : "cc" as a constraint
- * resulted in errors from egcs.  Things may be OK with gcc-2.95.
+ * resulted in errors from egcs.  Things appear to be OK with gcc-2.95.
  */
 static __inline__ void set_bit(int nr, volatile void * addr)
 {
@@ -80,6 +77,17 @@
 	: "cc");
 }
 
+/*
+ * non-atomic version
+ */
+static __inline__ void __clear_bit(int nr, volatile void *addr)
+{
+	unsigned long mask = 1 << (nr & 0x1f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+
+	*p &= ~mask;
+}
+
 static __inline__ void change_bit(int nr, volatile void *addr)
 {
 	unsigned long old;
@@ -97,6 +105,17 @@
 }
 
 /*
+ * non-atomic version
+ */
+static __inline__ void __change_bit(int nr, volatile void *addr)
+{
+	unsigned long mask = 1 << (nr & 0x1f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+
+	*p ^= mask;
+}
+
+/*
  * test_and_*_bit do imply a memory barrier (?)
  */
 static __inline__ int test_and_set_bit(int nr, volatile void *addr)
@@ -181,16 +200,19 @@
 
 	return (old & mask) != 0;
 }
-#else /* __INLINE_BITOPS */
 
-extern void set_bit(int nr, volatile void *addr);
-extern void clear_bit(int nr, volatile void *addr);
-extern void change_bit(int nr, volatile void *addr);
-extern int test_and_set_bit(int nr, volatile void *addr);
-extern int test_and_clear_bit(int nr, volatile void *addr);
-extern int test_and_change_bit(int nr, volatile void *addr);
+/*
+ * non-atomic version
+ */
+static __inline__ int __test_and_change_bit(int nr, volatile void *addr)
+{
+	unsigned long mask = 1 << (nr & 0x1f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+	unsigned long old = *p;
 
-#endif /* __INLINE_BITOPS */
+	*p = old ^ mask;
+	return (old & mask) != 0;
+}
 
 static __inline__ int test_bit(int nr, __const__ volatile void *addr)
 {
@@ -283,8 +305,6 @@
 	return result + ffz(tmp);
 }
 
-
-#define _EXT2_HAVE_ASM_BITOPS_
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-ppc/hardirq.h linux/include/asm-ppc/hardirq.h
--- v2.4.5/linux/include/asm-ppc/hardirq.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/hardirq.h	Tue Jun 12 11:07:16 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.hardirq.h 1.7 05/17/01 18:14:24 cort
+ * BK Id: SCCS/s.hardirq.h 1.10 06/09/01 22:16:38 paulus
  */
 #ifdef __KERNEL__
 #ifndef __ASM_HARDIRQ_H
@@ -15,8 +15,7 @@
  * for uniformity.
  */
 typedef struct {
-	unsigned int __softirq_active;
-	unsigned int __softirq_mask;
+	unsigned long __softirq_pending;	/* set_bit is used on this */
 	unsigned int __local_irq_count;
 	unsigned int __local_bh_count;
 	unsigned int __syscall_count;
diff -u --recursive --new-file v2.4.5/linux/include/asm-ppc/linux_logo.h linux/include/asm-ppc/linux_logo.h
--- v2.4.5/linux/include/asm-ppc/linux_logo.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/linux_logo.h	Mon Jun 11 19:15:27 2001
@@ -21,23 +21,7 @@
 
 #define LINUX_LOGO_HEIGHT	80
 #define LINUX_LOGO_WIDTH	80
-#define LINUX_LOGO_COLORS	214
 
-#ifdef INCLUDE_LINUX_LOGO_DATA
-
-#define INCLUDE_LINUX_LOGOBW
-#define INCLUDE_LINUX_LOGO16
 #include <linux/linux_logo.h>
 
-#else
-
-/* prototypes only */
-extern unsigned char linux_logo_red[];
-extern unsigned char linux_logo_green[];
-extern unsigned char linux_logo_blue[];
-extern unsigned char linux_logo[];
-extern unsigned char linux_logo_bw[];
-extern unsigned char linux_logo16[];
-
-#endif
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.4.5/linux/include/asm-ppc/softirq.h linux/include/asm-ppc/softirq.h
--- v2.4.5/linux/include/asm-ppc/softirq.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/softirq.h	Tue Jun 12 11:07:16 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.softirq.h 1.5 05/17/01 18:14:25 cort
+ * BK Id: SCCS/s.softirq.h 1.10 06/09/01 22:16:38 paulus
  */
 #ifdef __KERNEL__
 #ifndef __ASM_SOFTIRQ_H
@@ -8,8 +8,29 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-#define local_bh_disable()	do { local_bh_count(smp_processor_id())++; barrier(); } while (0)
-#define local_bh_enable()	do { barrier(); local_bh_count(smp_processor_id())--; } while (0)
+#define local_bh_disable()			\
+do {						\
+	local_bh_count(smp_processor_id())++;	\
+	barrier();				\
+} while (0)
+
+#define __local_bh_enable()			\
+do {						\
+	barrier();				\
+	local_bh_count(smp_processor_id())--;	\
+} while (0)
+
+#define local_bh_enable()				\
+do {							\
+	if (!--local_bh_count(smp_processor_id())	\
+	    && softirq_pending(smp_processor_id())) {	\
+		do_softirq();				\
+		__sti();				\
+	}						\
+} while (0)
+
+#define __cpu_raise_softirq(cpu, nr) set_bit((nr), &softirq_pending(cpu));
+#define raise_softirq(nr)	__cpu_raise_softirq(smp_processor_id(), (nr))
 
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-ppc/termios.h linux/include/asm-ppc/termios.h
--- v2.4.5/linux/include/asm-ppc/termios.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/termios.h	Mon Jun 11 19:15:27 2001
@@ -193,6 +193,7 @@
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14
+#define N_HCI		15  /* Bluetooth HCI UART */
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-s390/termios.h linux/include/asm-s390/termios.h
--- v2.4.5/linux/include/asm-s390/termios.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/termios.h	Mon Jun 11 19:15:27 2001
@@ -63,6 +63,7 @@
 #define N_IRDA		11	/* Linux IR - http://irda.sourceforge.net/ */
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC         13	/* synchronous HDLC */
+#define N_HCI		15  /* Bluetooth HCI UART */
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-s390x/termios.h linux/include/asm-s390x/termios.h
--- v2.4.5/linux/include/asm-s390x/termios.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/termios.h	Mon Jun 11 19:15:27 2001
@@ -63,6 +63,7 @@
 #define N_IRDA		11	/* Linux IR - http://irda.sourceforge.net/ */
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC         13	/* synchronous HDLC */
+#define N_BT		15	/* bluetooth */
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-sh/linux_logo.h linux/include/asm-sh/linux_logo.h
--- v2.4.5/linux/include/asm-sh/linux_logo.h	Mon Jun 19 17:59:38 2000
+++ linux/include/asm-sh/linux_logo.h	Mon Jun 11 19:15:27 2001
@@ -23,26 +23,5 @@
 
 #define linux_logo_banner "Linux/SuperH version " UTS_RELEASE
 
-#define LINUX_LOGO_COLORS 214
-
-#ifdef INCLUDE_LINUX_LOGO_DATA
-
-#define INCLUDE_LINUX_LOGOBW
-#define INCLUDE_LINUX_LOGO16
-
 #include <linux/linux_logo.h>
 
-#else
-
-/* prototypes only */
-extern unsigned char linux_logo_red[];
-extern unsigned char linux_logo_green[];
-extern unsigned char linux_logo_blue[];
-extern unsigned char linux_logo[];
-extern unsigned char linux_logo_bw[];
-extern unsigned char linux_logo16_red[];
-extern unsigned char linux_logo16_green[];
-extern unsigned char linux_logo16_blue[];
-extern unsigned char linux_logo16[];
-
-#endif
diff -u --recursive --new-file v2.4.5/linux/include/asm-sh/termios.h linux/include/asm-sh/termios.h
--- v2.4.5/linux/include/asm-sh/termios.h	Sat Feb  3 20:00:45 2001
+++ linux/include/asm-sh/termios.h	Mon Jun 11 19:15:27 2001
@@ -55,6 +55,7 @@
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14
+#define N_HCI		15  /* Bluetooth HCI UART */
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-sparc/audioio.h linux/include/asm-sparc/audioio.h
--- v2.4.5/linux/include/asm-sparc/audioio.h	Tue Oct 10 10:33:52 2000
+++ linux/include/asm-sparc/audioio.h	Mon Jun 11 19:15:27 2001
@@ -428,9 +428,6 @@
 extern int unregister_sparcaudio_driver(struct sparcaudio_driver *, int);
 extern void sparcaudio_output_done(struct sparcaudio_driver *, int);
 extern void sparcaudio_input_done(struct sparcaudio_driver *, int);
-extern int amd7930_init(void);
-extern int cs4231_init(void);
-extern int dbri_init(void);
 
 #endif
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-sparc/hardirq.h linux/include/asm-sparc/hardirq.h
--- v2.4.5/linux/include/asm-sparc/hardirq.h	Mon Aug 28 21:20:03 2000
+++ linux/include/asm-sparc/hardirq.h	Tue Jun 12 11:08:46 2001
@@ -14,8 +14,8 @@
 
 /* entry.S is sensitive to the offsets of these fields */
 typedef struct {
-	unsigned int __softirq_active;
-	unsigned int __softirq_mask;
+	unsigned int __softirq_pending;
+	unsigned int __unused_1;
 #ifndef CONFIG_SMP
 	unsigned int __local_irq_count;
 #else
diff -u --recursive --new-file v2.4.5/linux/include/asm-sparc/linux_logo.h linux/include/asm-sparc/linux_logo.h
--- v2.4.5/linux/include/asm-sparc/linux_logo.h	Wed Sep 30 14:16:33 1998
+++ linux/include/asm-sparc/linux_logo.h	Tue Jun 12 11:08:46 2001
@@ -1,4 +1,4 @@
-/* $Id: linux_logo.h,v 1.6 1998/08/20 04:44:39 ecd Exp $
+/* $Id: linux_logo.h,v 1.7 2001/06/08 23:01:58 davem Exp $
  * include/asm-sparc/linux_logo.h: This is a linux logo
  *                                 to be displayed on boot.
  *
@@ -23,1025 +23,912 @@
 
 #define linux_logo_banner "Linux/SPARC version " UTS_RELEASE
 
-#define LINUX_LOGO_COLORS 219
+#define __HAVE_ARCH_LINUX_LOGO
+#define __HAVE_ARCH_LINUX_LOGO16
+
+#define LINUX_LOGO_COLORS	221
 
 #ifdef INCLUDE_LINUX_LOGO_DATA
 
 unsigned char linux_logo_red[] __initdata = {
-  0x03, 0x9E, 0xEC, 0xEE, 0xC4, 0xDA, 0x50, 0xC9,
-  0xC5, 0xED, 0x65, 0xE3, 0xE3, 0xF4, 0x24, 0xA4,
-  0xEC, 0xEE, 0x94, 0xE5, 0xE3, 0x6A, 0xA6, 0xC4,
-  0xDC, 0xE5, 0x13, 0xF3, 0xD1, 0xFD, 0xE2, 0xDB,
-  0xA0, 0xC2, 0xEC, 0xB8, 0xC2, 0xD5, 0xF2, 0xF4,
-  0xC5, 0x3E, 0xF1, 0x1B, 0x55, 0xF5, 0xCF, 0xF7,
-  0xA9, 0xB4, 0xEB, 0x6C, 0x0A, 0x74, 0xB4, 0xF7,
-  0xF0, 0xF5, 0xD4, 0xF2, 0xCE, 0xF5, 0xC7, 0x26,
-  0x5B, 0xF4, 0xBC, 0x7F, 0xAB, 0x82, 0x94, 0xE5,
-  0xFC, 0x3A, 0xF2, 0xFD, 0xF0, 0x1C, 0xEF, 0xD4,
-  0xF3, 0x0F, 0xED, 0xF7, 0xC9, 0x49, 0xC3, 0xBA,
-  0xC8, 0xD4, 0xE7, 0xF3, 0xF5, 0xA7, 0xEC, 0xF9,
-  0xFA, 0x0A, 0xF5, 0xCF, 0xFC, 0xEA, 0xE1, 0xA6,
-  0xD6, 0xBC, 0xF8, 0xF7, 0xB4, 0xEB, 0xDC, 0x84,
-  0xCE, 0xBA, 0x45, 0xD6, 0x86, 0x50, 0x96, 0xC6,
-  0x8C, 0x6E, 0xE8, 0x60, 0x3C, 0x70, 0xF0, 0x93,
-  0x7C, 0xDA, 0xDA, 0x9C, 0xBA, 0x6D, 0x4D, 0x2B,
-  0x2F, 0x8B, 0xE0, 0xCC, 0xDA, 0x5C, 0x3D, 0xEE,
-  0xDB, 0x46, 0xAC, 0x96, 0xCE, 0xD1, 0xE3, 0xF1,
-  0x96, 0x7A, 0x80, 0xB2, 0xBA, 0xB6, 0xD2, 0x1E,
-  0x7E, 0xAA, 0xC4, 0xF0, 0x96, 0x65, 0x9E, 0xC2,
-  0xAA, 0xF5, 0xF2, 0xE9, 0xE6, 0xD1, 0x35, 0xC7,
-  0xF6, 0xB6, 0xE8, 0x82, 0xBE, 0xC2, 0xF2, 0x9E,
-  0xC7, 0xB4, 0x0F, 0xF7, 0xE8, 0xD8, 0xCC, 0x9C,
-  0xD8, 0xD8, 0xA0, 0xEA, 0xC6, 0xA8, 0xE0, 0xEC,
-  0xD1, 0xF7, 0xF4, 0xFC, 0x75, 0xBD, 0xDC, 0xDD,
-  0xCC, 0xE1, 0xFA, 0xEE, 0xAA, 0xEC, 0xF2, 0xB8,
-  0xE2, 0xCD, 0x87
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65,
+    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+    0xc3, 0x65, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x76, 0x79,
+    0x62, 0x36, 0x9a, 0xe2, 0xec, 0xe1, 0xb8, 0xd7,
+    0xaf, 0x25, 0xbc, 0xc0, 0xef, 0xea, 0xe8, 0xe8,
+    0xf5, 0xf1, 0xda, 0xd3, 0x79, 0xdb, 0xf4, 0xf6,
+    0xf6, 0xf6, 0xe2, 0x3d, 0xb4, 0xce, 0xe6, 0xee,
+    0xf6, 0x68, 0xd8, 0xec, 0xf5, 0xc6, 0xc8, 0x9c,
+    0x89, 0xd2, 0xee, 0xcb, 0xb9, 0xd2, 0x66, 0x5e,
+    0x8b, 0xbe, 0xa8, 0xd5, 0xca, 0xb6, 0xae, 0x9c,
+    0xc5, 0xbe, 0xbe, 0xca, 0x90, 0xb2, 0x9a, 0xa8,
+    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xfe,
+    0xf6, 0xec, 0xfe, 0xd2, 0xea, 0xf5, 0xf2, 0xf2,
+    0xe9, 0xee, 0xf6, 0xf2, 0xee, 0xf6, 0xda, 0xd4,
+    0xfa, 0xca, 0xf2, 0xf6, 0xfe, 0xf2, 0xda, 0xe4,
+    0xf6, 0xdd, 0xf2, 0xee, 0xfa, 0xf0, 0x12, 0x4a,
+    0xd6, 0xf2, 0x8e, 0xf2, 0xf6, 0xf6, 0xb5, 0xf1,
+    0x26, 0x9a, 0xea, 0xf6, 0xe0, 0xd2, 0x16, 0x9a,
+    0x2e, 0xd2, 0x70, 0xd6, 0x46, 0x7c, 0xb4, 0x62,
+    0xda, 0xee, 0xd6, 0xa3, 0x74, 0xa7, 0xa2, 0xe0,
+    0xae, 0xbe, 0xce, 0xe2, 0xa3, 0x8e, 0x6d, 0x8e,
+    0x32, 0xaf, 0x50, 0x9e, 0x5b, 0x8a, 0x98, 0x82,
+    0x7a, 0x82, 0x56, 0x7c, 0x8a, 0x56, 0x5e, 0x86,
+    0x6a, 0x52, 0x59, 0x64, 0x5e,
 };
 
 unsigned char linux_logo_green[] __initdata = {
-  0x03, 0x88, 0xC4, 0xE2, 0x85, 0xC2, 0x44, 0xA3,
-  0xA9, 0xD3, 0x65, 0xA6, 0xC5, 0xF3, 0x24, 0xA4,
-  0xB4, 0xD6, 0x63, 0xD5, 0xB7, 0x44, 0x86, 0x94,
-  0xC2, 0xE4, 0x14, 0xB6, 0xD2, 0xFB, 0xD4, 0xB2,
-  0x73, 0x96, 0xDB, 0x92, 0xC2, 0x95, 0xC2, 0xDA,
-  0xA4, 0x36, 0xD4, 0x0E, 0x55, 0xF4, 0xC4, 0xE9,
-  0x75, 0xB4, 0xBC, 0x52, 0x0A, 0x74, 0x84, 0xEB,
-  0xDC, 0xDA, 0xA2, 0xD6, 0x9B, 0xBD, 0xB7, 0x12,
-  0x44, 0xCA, 0x8C, 0x65, 0x7B, 0x54, 0x94, 0xAB,
-  0xF4, 0x25, 0xC4, 0xFD, 0xE4, 0x1C, 0xDD, 0xAB,
-  0xBD, 0x06, 0xCB, 0xD6, 0xCA, 0x33, 0x8C, 0xA2,
-  0x92, 0x9C, 0xBC, 0xDB, 0xCD, 0x6E, 0xEC, 0xEE,
-  0xBC, 0x03, 0xDA, 0xCE, 0xF4, 0xB6, 0xDB, 0x92,
-  0xAD, 0xBC, 0xDE, 0xD5, 0x7B, 0xAE, 0x9D, 0x84,
-  0xB6, 0x96, 0x44, 0xBA, 0x6E, 0x3C, 0x7A, 0xB2,
-  0x8C, 0x4C, 0xCE, 0x4C, 0x3C, 0x5A, 0xCA, 0x6D,
-  0x7C, 0xCE, 0xDA, 0x9C, 0xAA, 0x6D, 0x4D, 0x2B,
-  0x1B, 0x5E, 0xCB, 0xAC, 0xBE, 0x5C, 0x2E, 0xDC,
-  0xBD, 0x3E, 0xAC, 0x82, 0xB6, 0xBE, 0xD3, 0xBD,
-  0x72, 0x62, 0x6C, 0x82, 0x92, 0x9E, 0xB0, 0x13,
-  0x4A, 0x8E, 0xBE, 0xCE, 0x86, 0x45, 0x6B, 0xAA,
-  0x9A, 0xC5, 0xC6, 0xDA, 0xC5, 0xC4, 0x34, 0x9B,
-  0xCC, 0xAC, 0xC4, 0x76, 0x9A, 0x9E, 0xEE, 0x62,
-  0xC6, 0x76, 0x0D, 0xE4, 0xDA, 0xD5, 0xA5, 0x92,
-  0xCD, 0xB2, 0x7C, 0xCC, 0xBE, 0x7E, 0xDC, 0xD6,
-  0xB9, 0xE3, 0xD4, 0xF6, 0x55, 0x82, 0xA4, 0xAA,
-  0x8D, 0xBB, 0xCE, 0xD5, 0x8A, 0xDB, 0xD4, 0x8B,
-  0xCA, 0x93, 0x63
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65,
+    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+    0xc3, 0x62, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x62, 0x5c,
+    0x4e, 0x26, 0x72, 0xaa, 0xba, 0xaf, 0x90, 0xae,
+    0x92, 0x1a, 0xa4, 0x85, 0xb6, 0xbe, 0xc3, 0xc8,
+    0xcf, 0xd0, 0xc2, 0xce, 0x57, 0xa2, 0xd6, 0xda,
+    0xda, 0xd7, 0xb8, 0x2a, 0x7b, 0x91, 0xae, 0xca,
+    0xda, 0x45, 0x9e, 0xb2, 0xd7, 0x9b, 0x90, 0x76,
+    0x5c, 0xa2, 0xbe, 0xa6, 0x85, 0x96, 0x4e, 0x46,
+    0x66, 0x92, 0x7a, 0x9a, 0x96, 0x9d, 0x9a, 0x6b,
+    0x8a, 0x8e, 0xb2, 0xca, 0x90, 0xa6, 0x79, 0x7c,
+    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xfa,
+    0xea, 0xd7, 0xf6, 0xbc, 0xda, 0xde, 0xda, 0xe6,
+    0xca, 0xd8, 0xea, 0xe0, 0xcc, 0xf2, 0xce, 0xb2,
+    0xee, 0xa2, 0xd6, 0xe6, 0xf6, 0xd7, 0xc5, 0xb8,
+    0xc6, 0xb9, 0xce, 0xde, 0xce, 0xc6, 0x0e, 0x36,
+    0xae, 0xbe, 0x86, 0xba, 0xbe, 0xe6, 0x8e, 0xc4,
+    0x1e, 0x8e, 0xae, 0xba, 0xb2, 0xa6, 0x12, 0x7a,
+    0x20, 0xc6, 0x64, 0xaa, 0x2f, 0x70, 0x85, 0x46,
+    0xce, 0xd6, 0xa6, 0x6e, 0x51, 0x72, 0x92, 0xa6,
+    0x87, 0x96, 0xa2, 0xd6, 0x85, 0x7a, 0x6a, 0x6e,
+    0x22, 0x76, 0x36, 0x76, 0x3c, 0x6e, 0x63, 0x53,
+    0x66, 0x62, 0x42, 0x50, 0x56, 0x42, 0x56, 0x56,
+    0x56, 0x3e, 0x51, 0x52, 0x56,
 };
 
 unsigned char linux_logo_blue[] __initdata = {
-  0x04, 0x28, 0x10, 0x8C, 0x0B, 0x84, 0x14, 0x1A,
-  0x77, 0x1F, 0x64, 0x0E, 0x85, 0xD2, 0x24, 0xA4,
-  0x0F, 0x54, 0x0C, 0x7C, 0x3F, 0x04, 0x20, 0x0D,
-  0x54, 0xDF, 0x14, 0x0D, 0xD1, 0xE9, 0xB0, 0x11,
-  0x0A, 0x40, 0x57, 0x14, 0xC3, 0x0C, 0x04, 0x12,
-  0x50, 0x0C, 0x7D, 0x05, 0x55, 0xF2, 0xBA, 0xC7,
-  0x09, 0xB4, 0x0E, 0x24, 0x0B, 0x74, 0x0C, 0xB6,
-  0x80, 0x48, 0x10, 0x34, 0x0F, 0x0C, 0xA0, 0x04,
-  0x19, 0x10, 0x0E, 0x14, 0x0E, 0x05, 0x94, 0x0E,
-  0xCA, 0x0B, 0x46, 0xFB, 0xB4, 0x1C, 0x9B, 0x1A,
-  0x21, 0x09, 0x14, 0x4D, 0xCB, 0x08, 0x11, 0x7C,
-  0x20, 0x10, 0x24, 0x66, 0x79, 0x07, 0xEA, 0xC9,
-  0x0C, 0x08, 0x38, 0xC4, 0xD8, 0x24, 0xBE, 0x6C,
-  0x51, 0xBB, 0x8C, 0x36, 0x0A, 0x0F, 0x0C, 0x84,
-  0x3C, 0x54, 0x44, 0x7C, 0x28, 0x0E, 0x28, 0x7F,
-  0x8C, 0x0F, 0x54, 0x24, 0x3C, 0x18, 0x54, 0x17,
-  0x7C, 0x9C, 0xDA, 0x9C, 0x7C, 0x6C, 0x4D, 0x2C,
-  0x09, 0x0E, 0x8A, 0x50, 0x4C, 0x5B, 0x14, 0xAC,
-  0x19, 0x3C, 0xAC, 0x5C, 0x64, 0x97, 0x94, 0x37,
-  0x29, 0x3C, 0x44, 0x3C, 0x2C, 0x7C, 0x70, 0x07,
-  0x04, 0x29, 0xB2, 0x64, 0x74, 0x07, 0x07, 0x2C,
-  0x74, 0x2E, 0x6C, 0xA4, 0x29, 0x9E, 0x34, 0x27,
-  0x2F, 0x98, 0x48, 0x5C, 0x0C, 0x5C, 0xE8, 0x04,
-  0xC2, 0x0C, 0x0A, 0xB2, 0x74, 0xCB, 0x46, 0x78,
-  0xB4, 0x5C, 0x18, 0x80, 0x8C, 0x24, 0xD9, 0xAC,
-  0x87, 0x99, 0x1D, 0xE8, 0x14, 0x0D, 0x10, 0x17,
-  0x0A, 0x67, 0x3C, 0x68, 0x3C, 0x69, 0x90, 0x22,
-  0x6C, 0x0D, 0x17
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x01, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x06, 0x65,
+    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+    0xc3, 0x59, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x2e, 0x08,
+    0x0a, 0x06, 0x0a, 0x0b, 0x0b, 0x0f, 0x0c, 0x0f,
+    0x3d, 0x09, 0x73, 0x09, 0x0d, 0x0a, 0x10, 0x1e,
+    0x2d, 0x13, 0x86, 0xba, 0x19, 0x0a, 0x36, 0x3c,
+    0x26, 0x14, 0x0d, 0x06, 0x07, 0x0a, 0x0b, 0x0f,
+    0x4a, 0x06, 0x0a, 0x0c, 0x2b, 0x0a, 0x0b, 0x0a,
+    0x06, 0x0a, 0x0a, 0x11, 0x0b, 0x0a, 0x0a, 0x1e,
+    0x0f, 0x0d, 0x0a, 0x0b, 0x22, 0x6a, 0x72, 0x0b,
+    0x0b, 0x22, 0x90, 0xca, 0x90, 0x92, 0x3c, 0x2c,
+    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xea,
+    0xb6, 0x7c, 0xda, 0x8e, 0xa6, 0x87, 0x66, 0xb6,
+    0x81, 0x6a, 0xc6, 0x9a, 0x5b, 0xd2, 0xb6, 0x6a,
+    0xca, 0x45, 0x92, 0xb2, 0xca, 0x52, 0x8a, 0x3e,
+    0x2e, 0x66, 0x66, 0xae, 0x3e, 0x47, 0x06, 0x0e,
+    0x52, 0x36, 0x6a, 0x0e, 0x0e, 0xbe, 0x2c, 0x0e,
+    0x0a, 0x5a, 0x0d, 0x0e, 0x3e, 0x0a, 0x06, 0x2e,
+    0x06, 0x9e, 0x4e, 0x36, 0x06, 0x58, 0x24, 0x06,
+    0x9e, 0xae, 0x3a, 0x08, 0x08, 0x07, 0x5e, 0x0a,
+    0x32, 0x2e, 0x2a, 0xb2, 0x43, 0x48, 0x5f, 0x2e,
+    0x06, 0x06, 0x07, 0x24, 0x06, 0x32, 0x06, 0x06,
+    0x46, 0x2e, 0x22, 0x06, 0x06, 0x1e, 0x4c, 0x06,
+    0x3a, 0x22, 0x42, 0x34, 0x42,
 };
 
 unsigned char linux_logo[] __initdata = {
-  0xD8, 0xA3, 0x98, 0x98, 0xA3, 0xB2, 0x2F, 0x2F,
-  0xA3, 0x66, 0x98, 0x98, 0x98, 0xA3, 0x2F, 0xA3,
-  0x98, 0x55, 0xA0, 0xA3, 0xB2, 0x51, 0x51, 0x2F,
-  0x98, 0x55, 0x8F, 0x2F, 0x89, 0x44, 0x89, 0x51,
-  0xB2, 0x2F, 0x66, 0xA3, 0x2F, 0x2F, 0x66, 0x66,
-  0xA3, 0xB2, 0xB2, 0xB2, 0x89, 0xD8, 0x44, 0x44,
-  0xD8, 0x83, 0xD8, 0xA3, 0x98, 0x98, 0xA3, 0xB2,
-  0x2F, 0x2F, 0xA3, 0x66, 0x98, 0x98, 0x98, 0xA3,
-  0x2F, 0xA3, 0x98, 0x55, 0xA0, 0xA3, 0xB2, 0x51,
-  0x51, 0x2F, 0x98, 0x55, 0x8F, 0x2F, 0x89, 0x44,
-  0xA3, 0x55, 0x55, 0x98, 0x2F, 0x2F, 0x2F, 0xA3,
-  0x66, 0x66, 0x98, 0x98, 0x66, 0x66, 0x66, 0x98,
-  0x55, 0xA5, 0x8F, 0xA3, 0x51, 0x51, 0xB2, 0x2F,
-  0x66, 0x66, 0xA3, 0x51, 0x89, 0x51, 0xB2, 0x2F,
-  0x2F, 0xA3, 0x66, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F,
-  0xB2, 0xB2, 0x2F, 0x2F, 0xB2, 0x51, 0x51, 0x51,
-  0x51, 0x51, 0xA3, 0x55, 0x55, 0x98, 0x2F, 0x2F,
-  0x2F, 0xA3, 0x66, 0x66, 0x98, 0x98, 0x66, 0x66,
-  0x66, 0x98, 0x55, 0xA5, 0x8F, 0xA3, 0x51, 0x51,
-  0xB2, 0x2F, 0x66, 0x66, 0xA3, 0x51, 0x89, 0x51,
-  0x98, 0xA5, 0x55, 0x8F, 0x2F, 0xB2, 0x2F, 0xA3,
-  0x66, 0x66, 0x98, 0x8F, 0x66, 0x66, 0x66, 0x98,
-  0xA0, 0x8F, 0xA3, 0xB2, 0x51, 0x51, 0xB2, 0x2F,
-  0xA3, 0xA3, 0x2F, 0xB2, 0x51, 0xB2, 0x2F, 0x2F,
-  0xA3, 0x66, 0x98, 0xA3, 0x51, 0xB2, 0x2F, 0xA3,
-  0xB2, 0x51, 0x51, 0xB2, 0xB2, 0x51, 0xB2, 0xB2,
-  0xB2, 0x2F, 0x98, 0xA5, 0x55, 0x8F, 0x2F, 0xB2,
-  0x2F, 0xA3, 0x66, 0x66, 0x98, 0x8F, 0x66, 0x66,
-  0x66, 0x98, 0xA0, 0x8F, 0xA3, 0xB2, 0x51, 0x51,
-  0xB2, 0x2F, 0xA3, 0xA3, 0x2F, 0x51, 0x51, 0xB2,
-  0xA0, 0xA5, 0x55, 0x66, 0xB2, 0x51, 0xB2, 0xA3,
-  0x66, 0x66, 0x98, 0x66, 0x66, 0x66, 0x98, 0x98,
-  0x66, 0xA3, 0x2F, 0xB2, 0x51, 0x51, 0xB2, 0xA3,
-  0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0xA3,
-  0x66, 0x98, 0xB2, 0x4C, 0x54, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xCE, 0x2F, 0xB2, 0x2F, 0x2F,
-  0xA3, 0x98, 0xA0, 0xA5, 0x55, 0x66, 0xB2, 0x51,
-  0xB2, 0xA3, 0x66, 0x66, 0x98, 0x66, 0x66, 0x66,
-  0x98, 0x98, 0x66, 0xA3, 0x2F, 0xB2, 0x51, 0x51,
-  0xB2, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F,
-  0xA0, 0xA0, 0x8F, 0xA3, 0xB2, 0x51, 0xB2, 0x2F,
-  0x66, 0x66, 0x98, 0x66, 0x66, 0x66, 0x66, 0x66,
-  0xA3, 0x2F, 0x51, 0x51, 0x51, 0xB2, 0x2F, 0xA3,
-  0x66, 0x66, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
-  0x2F, 0xA0, 0xDA, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x9C, 0xB2, 0xA3,
-  0x66, 0x98, 0xA0, 0xA0, 0x8F, 0xA3, 0xB2, 0x51,
-  0xB2, 0x2F, 0x66, 0x66, 0x98, 0x66, 0x66, 0x66,
-  0x66, 0x66, 0xA3, 0x2F, 0x51, 0x51, 0x51, 0xB2,
-  0x2F, 0xA3, 0x66, 0x66, 0x66, 0xA3, 0xA3, 0xA3,
-  0x8F, 0x8F, 0x66, 0x2F, 0x51, 0x51, 0xB2, 0xA3,
-  0x66, 0x98, 0x98, 0x66, 0x66, 0x66, 0x2F, 0x2F,
-  0xB2, 0x51, 0xB2, 0xB2, 0x2F, 0x2F, 0xA3, 0x66,
-  0x66, 0x66, 0xA3, 0xA3, 0x2F, 0xA3, 0xA3, 0xB2,
-  0x9C, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xDA, 0x3A, 0x20, 0x54, 0x55,
-  0xA3, 0x98, 0x8F, 0x8F, 0x66, 0x2F, 0x51, 0x51,
-  0xB2, 0xA3, 0x66, 0x98, 0x98, 0x66, 0x66, 0x66,
-  0x2F, 0x2F, 0xB2, 0x51, 0xB2, 0xB2, 0x2F, 0x2F,
-  0xA3, 0x66, 0x66, 0x66, 0x2F, 0xA3, 0x2F, 0x2F,
-  0x66, 0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0x2F, 0x66,
-  0x8F, 0x8F, 0x8F, 0x66, 0xA3, 0xA3, 0xB2, 0xB2,
-  0xB2, 0xB2, 0xB2, 0xB2, 0x2F, 0xA3, 0xA3, 0xA3,
-  0xA3, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0xAD,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xA7, 0x4C, 0xCE, 0xDA, 0x20,
-  0xA6, 0x2F, 0x66, 0x66, 0xA3, 0x2F, 0xB2, 0xB2,
-  0x2F, 0x66, 0x8F, 0x8F, 0x8F, 0x66, 0xA3, 0xA3,
-  0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0x2F, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F,
-  0xA3, 0x98, 0x66, 0x2F, 0xB2, 0xB2, 0x2F, 0x98,
-  0x8F, 0x8F, 0x98, 0x66, 0xA3, 0xB2, 0xB2, 0xB2,
-  0x2F, 0x2F, 0x2F, 0x2F, 0xA3, 0x2F, 0xA3, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0x51, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xCE, 0x55, 0xAD, 0xA7, 0x54,
-  0x20, 0x8F, 0xA3, 0x98, 0x66, 0x2F, 0xB2, 0xB2,
-  0x2F, 0x98, 0x8F, 0x8F, 0x98, 0x66, 0xA3, 0xB2,
-  0xB2, 0xB2, 0x2F, 0x2F, 0x2F, 0x2F, 0xA3, 0x2F,
-  0xA3, 0xA3, 0xA3, 0x2F, 0xA3, 0xA3, 0xA3, 0xA3,
-  0xA3, 0x8F, 0x66, 0x2F, 0xB2, 0x51, 0x2F, 0x98,
-  0xA0, 0x8F, 0x66, 0xA3, 0x2F, 0x51, 0x51, 0xB2,
-  0xA3, 0xA3, 0xA3, 0x2F, 0xA3, 0xA3, 0x66, 0x66,
-  0x98, 0x98, 0x98, 0x66, 0x98, 0x66, 0x55, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xCE, 0x4C, 0x9C, 0x2E, 0xDA,
-  0x20, 0xDA, 0x51, 0x8F, 0x66, 0x2F, 0xB2, 0x51,
-  0x2F, 0x98, 0xA0, 0x8F, 0x66, 0xA3, 0x2F, 0x51,
-  0x51, 0xB2, 0xA3, 0xA3, 0xA3, 0x2F, 0xA3, 0xA3,
-  0x66, 0x66, 0x98, 0x98, 0x98, 0x98, 0x98, 0x66,
-  0x51, 0x66, 0x2F, 0xB2, 0x51, 0xB2, 0xA3, 0xA0,
-  0xA0, 0x66, 0xA3, 0xB2, 0xB2, 0xB2, 0xB2, 0xA3,
-  0x66, 0x66, 0x66, 0xA3, 0xA3, 0x66, 0x98, 0x98,
-  0x98, 0x98, 0x98, 0x66, 0x66, 0xB2, 0x6D, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x6D, 0x3A, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0xA5, 0x66, 0x2F, 0xB2, 0x51, 0xB2,
-  0xA3, 0xA0, 0xA0, 0x66, 0xA3, 0xB2, 0xB2, 0xB2,
-  0xB2, 0xA3, 0x66, 0x66, 0x66, 0xA3, 0xA3, 0x66,
-  0x98, 0x98, 0x8F, 0x98, 0x66, 0x66, 0x66, 0x66,
-  0x51, 0x2F, 0xB2, 0x51, 0x51, 0x2F, 0x66, 0xA0,
-  0x8F, 0xA3, 0x2F, 0xB2, 0xB2, 0x2F, 0x2F, 0x66,
-  0x98, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
-  0x66, 0x2F, 0xA3, 0x2F, 0x2F, 0x51, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0xDA, 0x51, 0xB2, 0x51, 0x51, 0x2F,
-  0x66, 0xA0, 0x8F, 0xA3, 0x2F, 0xB2, 0xB2, 0x2F,
-  0x2F, 0x66, 0x98, 0x66, 0x66, 0x66, 0x66, 0x66,
-  0x66, 0x66, 0x66, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F,
-  0x51, 0x2F, 0xB2, 0x51, 0x2F, 0xA3, 0x8F, 0x8F,
-  0x98, 0xA3, 0xB2, 0xB2, 0x2F, 0xA3, 0x98, 0x66,
-  0x98, 0x98, 0x66, 0x66, 0x66, 0x66, 0xA3, 0x2F,
-  0xB2, 0xB2, 0x51, 0xB2, 0xB2, 0x66, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xA3, 0xB2, 0x51, 0x2F, 0xA3,
-  0x8F, 0x8F, 0x98, 0xA3, 0xB2, 0xB2, 0x2F, 0xA3,
-  0x98, 0x66, 0x98, 0x98, 0x66, 0x66, 0x66, 0x66,
-  0xA3, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2,
-  0xB2, 0x2F, 0xA3, 0x2F, 0x66, 0x98, 0x8F, 0x98,
-  0xA3, 0x2F, 0x2F, 0xA3, 0x98, 0x98, 0x98, 0x98,
-  0x66, 0x98, 0x66, 0x98, 0x66, 0xA3, 0x2F, 0xB2,
-  0x51, 0x51, 0x51, 0xB2, 0xB2, 0x8F, 0x20, 0x20,
-  0x20, 0x54, 0x6D, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x54, 0x6D, 0x6D, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x4C, 0xA3, 0x2F, 0x66, 0x98,
-  0x8F, 0x98, 0xA3, 0x2F, 0x2F, 0xA3, 0x98, 0x98,
-  0x98, 0x98, 0x66, 0x98, 0x66, 0x98, 0x66, 0xA3,
-  0x2F, 0xB2, 0x51, 0x51, 0x51, 0xB2, 0x2F, 0x2F,
-  0x2F, 0xA3, 0xA3, 0x66, 0x98, 0x98, 0x8F, 0x98,
-  0x2F, 0x2F, 0x2F, 0x66, 0x8F, 0x8F, 0x98, 0xA3,
-  0x66, 0x66, 0x8F, 0x98, 0x98, 0x66, 0x2F, 0xB2,
-  0x51, 0xB2, 0x2F, 0xA3, 0xA3, 0xA0, 0x20, 0x20,
-  0xDA, 0x2E, 0x3A, 0xA7, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0xCE, 0x2A, 0x2A, 0x2E, 0xA7, 0xDA, 0x20,
-  0x20, 0x20, 0x20, 0x9C, 0xA3, 0x66, 0x98, 0x98,
-  0x8F, 0x98, 0x2F, 0x2F, 0x2F, 0x66, 0x8F, 0x8F,
-  0x98, 0xA3, 0x66, 0x66, 0x8F, 0x98, 0x98, 0x66,
-  0x2F, 0xB2, 0x51, 0xB2, 0x2F, 0x2F, 0xA3, 0xA3,
-  0xB2, 0xA3, 0x66, 0x98, 0x8F, 0x8F, 0x66, 0xA3,
-  0x2F, 0x2F, 0x66, 0x98, 0x98, 0x66, 0x2F, 0x2F,
-  0xA3, 0x98, 0x8F, 0x98, 0x66, 0x2F, 0xB2, 0xB2,
-  0xB2, 0xA3, 0x66, 0x66, 0x66, 0x98, 0x20, 0x3A,
-  0x98, 0x89, 0x8F, 0x6D, 0x20, 0x20, 0x20, 0x20,
-  0x4C, 0x66, 0x51, 0x44, 0x51, 0x2E, 0x54, 0x20,
-  0x20, 0x20, 0x20, 0xA7, 0x66, 0x98, 0x8F, 0x8F,
-  0x66, 0xA3, 0x2F, 0x2F, 0x66, 0x98, 0x98, 0x66,
-  0x2F, 0x2F, 0xA3, 0x98, 0x8F, 0x98, 0x66, 0x2F,
-  0xB2, 0xB2, 0xB2, 0xA3, 0x66, 0x66, 0x66, 0xA3,
-  0x2F, 0x66, 0x98, 0x8F, 0x8F, 0x98, 0x66, 0x2F,
-  0x2F, 0xA3, 0x66, 0x98, 0x98, 0xA3, 0x2F, 0xB2,
-  0xA3, 0x8F, 0x98, 0xA3, 0xB2, 0x51, 0x89, 0x89,
-  0xB2, 0xA3, 0x66, 0x98, 0x66, 0x98, 0x20, 0xA6,
-  0x44, 0x39, 0xE6, 0x98, 0x20, 0x20, 0x20, 0x9C,
-  0x74, 0xD6, 0x7E, 0xD6, 0x39, 0x8F, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x2E, 0x98, 0x8F, 0x8F, 0x98,
-  0x66, 0x2F, 0x2F, 0xA3, 0x66, 0x98, 0x98, 0xA3,
-  0x2F, 0xB2, 0x66, 0x98, 0x8F, 0xA3, 0xB2, 0x51,
-  0x89, 0x89, 0xB2, 0xA3, 0x66, 0x98, 0x66, 0x66,
-  0x2F, 0x66, 0x8F, 0xA0, 0x8F, 0x98, 0xA3, 0xB2,
-  0x2F, 0x66, 0x66, 0x66, 0xA3, 0x2F, 0x2F, 0x2F,
-  0x66, 0x98, 0xA3, 0xB2, 0x89, 0x44, 0x89, 0x51,
-  0x2F, 0x66, 0x98, 0x98, 0xA3, 0x66, 0x20, 0x2F,
-  0x2F, 0xAD, 0x89, 0xD6, 0x3A, 0x20, 0x20, 0x55,
-  0x6B, 0x51, 0x6D, 0x4C, 0xD8, 0xD6, 0x2E, 0x20,
-  0x20, 0x20, 0x20, 0x54, 0x8F, 0xA0, 0x8F, 0x98,
-  0xA3, 0xB2, 0x2F, 0x66, 0x66, 0x66, 0xA3, 0x2F,
-  0xB2, 0x2F, 0x66, 0x66, 0xA3, 0xB2, 0x89, 0x44,
-  0x89, 0x51, 0x2F, 0x66, 0x98, 0x98, 0xA3, 0xA3,
-  0xA3, 0x66, 0x8F, 0xA0, 0x8F, 0x66, 0x2F, 0xB2,
-  0xA3, 0x66, 0x98, 0x66, 0xA3, 0x2F, 0x2F, 0xA3,
-  0xA3, 0x2F, 0xB2, 0x89, 0xD8, 0xD8, 0x51, 0x66,
-  0x8F, 0xA0, 0xA0, 0x8F, 0x98, 0xA3, 0x20, 0x44,
-  0xA7, 0xCE, 0xA6, 0x4D, 0xCE, 0x6D, 0xA7, 0xA0,
-  0x6B, 0xA7, 0x20, 0x92, 0xAD, 0x6B, 0x4C, 0x20,
-  0x20, 0x20, 0x20, 0x54, 0x98, 0xA0, 0x8F, 0x66,
-  0x2F, 0xB2, 0xA3, 0x66, 0x98, 0x66, 0xA3, 0x2F,
-  0x2F, 0xA3, 0xA3, 0xA3, 0xB2, 0x89, 0xD8, 0xD8,
-  0x51, 0x66, 0x8F, 0xA0, 0xA0, 0x8F, 0x98, 0x66,
-  0x66, 0x66, 0x8F, 0x55, 0x8F, 0xA3, 0xB2, 0xB2,
-  0xA3, 0x66, 0x66, 0xA3, 0x2F, 0xA3, 0xA3, 0xA3,
-  0xA3, 0xB2, 0x89, 0x44, 0x44, 0x51, 0x66, 0xA0,
-  0x55, 0xA5, 0x55, 0x8F, 0x66, 0xA3, 0x20, 0x44,
-  0x6D, 0x54, 0xA7, 0x74, 0x2E, 0x4B, 0xBF, 0x9C,
-  0x7E, 0xDA, 0x20, 0x54, 0x2E, 0x6B, 0x2A, 0x20,
-  0x20, 0x20, 0x20, 0x3A, 0x8F, 0x55, 0x8F, 0xA3,
-  0xB2, 0xB2, 0xA3, 0x66, 0x66, 0xA3, 0xA3, 0x2F,
-  0xA3, 0xA3, 0xA3, 0xB2, 0x89, 0x44, 0x44, 0x51,
-  0x66, 0xA0, 0xA5, 0xA5, 0x55, 0x8F, 0x66, 0x66,
-  0xA0, 0xA0, 0xA0, 0xA0, 0x8F, 0xA3, 0x2F, 0xB2,
-  0x66, 0x98, 0xA3, 0x2F, 0x2F, 0xB2, 0x2F, 0x2F,
-  0xB2, 0x51, 0x89, 0x89, 0xB2, 0x98, 0xA0, 0x2A,
-  0xA5, 0x55, 0x98, 0x66, 0xA3, 0xB2, 0x20, 0x2F,
-  0x4C, 0x20, 0x4B, 0xBB, 0xCF, 0x6F, 0x27, 0x36,
-  0x93, 0xCE, 0x20, 0x20, 0xA6, 0x3D, 0x4C, 0x20,
-  0x20, 0x20, 0x20, 0xDA, 0xA0, 0xA0, 0x8F, 0xA3,
-  0x2F, 0xB2, 0x66, 0x98, 0xA3, 0x2F, 0xB2, 0x2F,
-  0x2F, 0x2F, 0xB2, 0x51, 0x89, 0x89, 0xB2, 0x98,
-  0xA0, 0x2A, 0xA5, 0xA0, 0x8F, 0x66, 0xA3, 0xA3,
-  0xA0, 0x8F, 0x8F, 0xA0, 0x8F, 0xA3, 0xB2, 0x2F,
-  0x66, 0x98, 0x2F, 0xB2, 0xB2, 0xB2, 0xB2, 0x2F,
-  0xB2, 0x89, 0x44, 0x51, 0x66, 0x55, 0xAD, 0x2A,
-  0x55, 0x8F, 0x66, 0xA3, 0x2F, 0xB2, 0x20, 0x2A,
-  0xE6, 0x95, 0xE5, 0x5A, 0x52, 0x52, 0x3F, 0x27,
-  0x22, 0xC7, 0x9D, 0x60, 0xA2, 0xA2, 0x3A, 0x20,
-  0x20, 0x20, 0x20, 0x54, 0x66, 0xA0, 0x8F, 0xA3,
-  0xB2, 0x2F, 0x66, 0x98, 0x2F, 0xB2, 0xB2, 0xB2,
-  0xB2, 0x2F, 0xB2, 0x89, 0x44, 0x51, 0x66, 0x55,
-  0x2A, 0x2A, 0xA5, 0x8F, 0x66, 0xA3, 0x2F, 0x2F,
-  0xA3, 0xA3, 0x66, 0x98, 0x98, 0x2F, 0xB2, 0xB2,
-  0xA3, 0xA3, 0x2F, 0x51, 0x51, 0x51, 0x2F, 0x2F,
-  0x51, 0x89, 0x89, 0x2F, 0x8F, 0x2A, 0x2A, 0xA5,
-  0x8F, 0x66, 0xA3, 0xB2, 0x2F, 0x51, 0x20, 0x6D,
-  0x77, 0xF7, 0xEE, 0x30, 0xB0, 0x72, 0x72, 0x5B,
-  0x82, 0xEA, 0x72, 0xB0, 0x90, 0x96, 0x71, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x2F, 0x98, 0x98, 0x2F,
-  0xB2, 0xB2, 0x66, 0xA3, 0x2F, 0x51, 0x51, 0xB2,
-  0xB2, 0x2F, 0x51, 0x89, 0x89, 0x2F, 0x8F, 0x2A,
-  0xAD, 0xA5, 0x98, 0x66, 0xA3, 0xB2, 0x2F, 0xB2,
-  0xD8, 0xB2, 0xA3, 0x98, 0x98, 0x2F, 0xB2, 0xB2,
-  0x66, 0xA3, 0xB2, 0x51, 0x51, 0xB2, 0x2F, 0xA3,
-  0x51, 0x89, 0x89, 0xA3, 0xA0, 0x2A, 0xA5, 0x8F,
-  0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0x51, 0x20, 0x69,
-  0x64, 0xF9, 0x3F, 0x52, 0x52, 0x72, 0x29, 0x82,
-  0x47, 0x47, 0x47, 0x8B, 0x72, 0xB7, 0x60, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x2F, 0x98, 0x98, 0x2F,
-  0xB2, 0xB2, 0xA3, 0xA3, 0xB2, 0x89, 0x51, 0x2F,
-  0x2F, 0xA3, 0x51, 0x89, 0x89, 0xA3, 0xA0, 0x2A,
-  0xA5, 0x8F, 0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0xB2,
-  0xDD, 0xA3, 0x66, 0x98, 0x66, 0x2F, 0xB2, 0xB2,
-  0xA3, 0xA3, 0xB2, 0x51, 0xB2, 0x2F, 0xA3, 0x2F,
-  0xB2, 0x89, 0xB2, 0x66, 0xA0, 0xA5, 0x8F, 0x98,
-  0x66, 0x66, 0xB2, 0x51, 0x51, 0x51, 0x81, 0xFA,
-  0x62, 0xEE, 0x30, 0x52, 0x22, 0x72, 0x82, 0x82,
-  0x47, 0x47, 0xEA, 0x3F, 0x37, 0x6F, 0x26, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x2A, 0x98, 0x66, 0x2F,
-  0x51, 0xB2, 0xA3, 0x66, 0xB2, 0x51, 0x51, 0xB2,
-  0xA3, 0x2F, 0xB2, 0x89, 0xB2, 0x66, 0x55, 0x55,
-  0x8F, 0x98, 0x66, 0xA3, 0xB2, 0x51, 0x51, 0xB2,
-  0x74, 0xA0, 0x8F, 0x98, 0x66, 0xB2, 0xB2, 0xB2,
-  0xA3, 0xA3, 0x2F, 0x51, 0x51, 0x2F, 0xA3, 0x2F,
-  0xB2, 0x51, 0xA3, 0x98, 0xA0, 0x55, 0xA0, 0xA0,
-  0x8F, 0x66, 0x2F, 0x51, 0xB2, 0x51, 0x54, 0xA9,
-  0x62, 0xEF, 0x52, 0x22, 0x72, 0x29, 0xEA, 0xEA,
-  0x29, 0x22, 0x37, 0x37, 0x8E, 0xCF, 0x49, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x6D, 0x2F, 0x66, 0x2F,
-  0x51, 0xB2, 0xA3, 0x66, 0x2F, 0xB2, 0xB2, 0x2F,
-  0xA3, 0x2F, 0xB2, 0x51, 0x2F, 0x98, 0xA0, 0x55,
-  0xA0, 0xA0, 0x8F, 0x66, 0x2F, 0x51, 0xB2, 0xA3,
-  0xA3, 0x2A, 0xA5, 0x98, 0xA3, 0x2F, 0xB2, 0x2F,
-  0x66, 0x66, 0x2F, 0xB2, 0xB2, 0xB2, 0x2F, 0x2F,
-  0xB2, 0x2F, 0xA3, 0x8F, 0xA0, 0xA0, 0xA0, 0xA0,
-  0x8F, 0xA3, 0x51, 0x51, 0x2F, 0xB2, 0x54, 0xA8,
-  0x65, 0x5C, 0x52, 0x22, 0x29, 0x29, 0x29, 0xB0,
-  0x62, 0x56, 0xF9, 0x79, 0xF9, 0xBB, 0x4B, 0x20,
-  0x6D, 0xA5, 0x2E, 0x20, 0x20, 0xA3, 0xA3, 0x2F,
-  0xB2, 0x2F, 0xA3, 0x66, 0x2F, 0xB2, 0xB2, 0xB2,
-  0x2F, 0x2F, 0xB2, 0x2F, 0x66, 0x8F, 0xA0, 0xA0,
-  0x55, 0xA0, 0x8F, 0xA3, 0x51, 0x51, 0x2F, 0xA3,
-  0xA0, 0x2A, 0x55, 0x66, 0xA3, 0x2F, 0xB2, 0xB2,
-  0xA3, 0x66, 0xA3, 0xB2, 0xB2, 0xB2, 0xA3, 0x66,
-  0xA3, 0xA3, 0x66, 0x8F, 0x8F, 0x8F, 0xA0, 0x98,
-  0xA3, 0x51, 0x89, 0x89, 0xA3, 0x2F, 0x20, 0x54,
-  0xDF, 0xFA, 0x40, 0x37, 0xD4, 0x43, 0x56, 0x64,
-  0x76, 0xF9, 0x78, 0x41, 0x5E, 0x5E, 0x4C, 0x20,
-  0x20, 0xAD, 0x8F, 0x9C, 0x20, 0xA5, 0xA3, 0x2F,
-  0x2F, 0x2F, 0xA3, 0x66, 0x2F, 0xB2, 0xB2, 0xB2,
-  0xA3, 0x66, 0xA3, 0x2F, 0x66, 0x8F, 0x8F, 0x8F,
-  0x8F, 0x8F, 0xA3, 0x51, 0x89, 0x51, 0xA3, 0x66,
-  0xA0, 0xA0, 0x8F, 0xA3, 0x2F, 0x2F, 0x2F, 0xB2,
-  0x2F, 0xA3, 0x2F, 0xB2, 0x51, 0xB2, 0x2F, 0x66,
-  0xA3, 0xA3, 0x66, 0x66, 0x66, 0x66, 0x66, 0xA3,
-  0xB2, 0x89, 0xD8, 0x51, 0x66, 0x51, 0x20, 0x6D,
-  0x51, 0x77, 0x9F, 0xF7, 0xEE, 0x8E, 0xF9, 0xF0,
-  0x24, 0xF7, 0x77, 0x5E, 0x74, 0xD8, 0x98, 0x20,
-  0x20, 0x2E, 0x55, 0x92, 0x20, 0x54, 0x51, 0x2F,
-  0x2F, 0xB2, 0xB2, 0xA3, 0x2F, 0x51, 0x51, 0xB2,
-  0xA3, 0xA3, 0x66, 0xA3, 0x66, 0x66, 0x66, 0x66,
-  0x66, 0xA3, 0xB2, 0x89, 0xD8, 0x51, 0xA3, 0x98,
-  0x98, 0x66, 0x66, 0xA3, 0x2F, 0x2F, 0x2F, 0xB2,
-  0xB2, 0x2F, 0x2F, 0xB2, 0xB2, 0x2F, 0x2F, 0x66,
-  0x66, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0xB2,
-  0x89, 0xD8, 0x89, 0xB2, 0x66, 0x66, 0x20, 0x6D,
-  0x89, 0xC2, 0xA4, 0x96, 0xC6, 0x64, 0x50, 0x40,
-  0xF4, 0x97, 0x89, 0x74, 0x7E, 0x6B, 0x39, 0xA7,
-  0x20, 0x20, 0x3A, 0x54, 0x20, 0x20, 0xA7, 0x51,
-  0x2F, 0xB2, 0xB2, 0xA3, 0xA3, 0xB2, 0xB2, 0xB2,
-  0xA3, 0xA3, 0x66, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F,
-  0x2F, 0xB2, 0x89, 0xD8, 0x44, 0x2F, 0x66, 0x66,
-  0x2F, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F, 0xB2,
-  0x2F, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0xA3,
-  0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0xB2, 0x51, 0x51,
-  0x89, 0x89, 0xB2, 0x66, 0x2F, 0x6D, 0x20, 0xCE,
-  0x39, 0x74, 0x89, 0x5E, 0xBD, 0x87, 0xC8, 0xD1,
-  0x89, 0x44, 0x3C, 0x4D, 0x6B, 0x6B, 0x6B, 0x2F,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xA3,
-  0x2F, 0x2F, 0x2F, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F,
-  0x2F, 0xA3, 0x66, 0x66, 0x2F, 0xB2, 0xB2, 0xB2,
-  0x51, 0x51, 0x89, 0x89, 0xB2, 0xA3, 0x98, 0x66,
-  0xA3, 0x66, 0x66, 0xA3, 0xA3, 0xA3, 0xA3, 0x2F,
-  0x2F, 0xA3, 0xA3, 0xA3, 0x2F, 0xA3, 0x2F, 0xA3,
-  0x66, 0x66, 0x2F, 0x2F, 0xB2, 0xB2, 0xB2, 0xB2,
-  0xB2, 0x2F, 0x66, 0x66, 0x2A, 0x20, 0x54, 0x44,
-  0x6B, 0x39, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
-  0xD8, 0x39, 0x4D, 0x6B, 0x6B, 0x6B, 0x6B, 0x4D,
-  0x9C, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6D,
-  0x51, 0x2F, 0x2F, 0x2F, 0xA3, 0xA3, 0xA3, 0x2F,
-  0xA3, 0xA3, 0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0xB2,
-  0xB2, 0xB2, 0xB2, 0x2F, 0x66, 0x98, 0x98, 0x66,
-  0x98, 0x98, 0x66, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
-  0x2F, 0x2F, 0xA3, 0xA3, 0x66, 0xA3, 0xA3, 0x66,
-  0x98, 0x66, 0x66, 0x2F, 0xA3, 0xA3, 0xA3, 0xA3,
-  0x66, 0x98, 0x98, 0x98, 0x3A, 0x54, 0x2A, 0x6B,
-  0x6B, 0x6B, 0x83, 0x44, 0x89, 0x89, 0x44, 0x3C,
-  0xD6, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0xB2, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0xAD, 0x2F, 0x2F, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
-  0xA3, 0x66, 0x66, 0x98, 0x66, 0xA3, 0xA3, 0xA3,
-  0xA3, 0xA3, 0x66, 0x98, 0x8F, 0x8F, 0x8F, 0x98,
-  0x8F, 0x98, 0x98, 0x66, 0xA3, 0xA3, 0xA3, 0xA3,
-  0x2F, 0xA3, 0xA3, 0x66, 0x66, 0x66, 0x66, 0x66,
-  0x8F, 0x8F, 0x8F, 0x98, 0x98, 0x98, 0x8F, 0xA0,
-  0xA0, 0xA0, 0xA3, 0xDA, 0x20, 0x3A, 0x39, 0x6B,
-  0x6B, 0x6B, 0x4D, 0xA2, 0x74, 0x3C, 0x7E, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x2F, 0x2F, 0xA3, 0x66, 0x66, 0x66, 0x66,
-  0x66, 0x98, 0x8F, 0x8F, 0x98, 0x98, 0x98, 0x98,
-  0x8F, 0xA0, 0xA0, 0xA0, 0x8F, 0x8F, 0x8F, 0xA0,
-  0x8F, 0x66, 0x66, 0xA3, 0x66, 0xA3, 0xA3, 0x2F,
-  0x2F, 0x2F, 0xA3, 0xA3, 0x66, 0x66, 0x66, 0x98,
-  0x98, 0xA0, 0x98, 0x66, 0x66, 0x98, 0x8F, 0xA0,
-  0xA0, 0xA3, 0x2E, 0x20, 0x20, 0x8F, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x3D, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x55, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x3A, 0x51, 0x2F, 0xA3, 0x66, 0x66, 0x66,
-  0x66, 0x66, 0x98, 0x8F, 0x8F, 0x98, 0x66, 0x98,
-  0x8F, 0xA0, 0xA0, 0x8F, 0x8F, 0x8F, 0x8F, 0xA0,
-  0x66, 0x2F, 0x2F, 0x2F, 0x2F, 0xA3, 0xA3, 0xA3,
-  0x2F, 0x2F, 0xA3, 0xA3, 0x66, 0xA3, 0x66, 0x66,
-  0x66, 0x98, 0xA3, 0x2F, 0x2F, 0xA3, 0x66, 0x8F,
-  0x66, 0xA6, 0x20, 0x20, 0x6D, 0x39, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x6B, 0xB2, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x2E, 0x89, 0xA3, 0xA3, 0x66, 0x66,
-  0x66, 0x66, 0x98, 0x98, 0xA3, 0x2F, 0x2F, 0xA3,
-  0x66, 0x8F, 0x98, 0x98, 0x66, 0x98, 0x98, 0x8F,
-  0x2F, 0x51, 0xB2, 0xB2, 0x2F, 0xA3, 0xA3, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
-  0xA3, 0xA3, 0x2F, 0xB2, 0x2F, 0xA3, 0x66, 0x2F,
-  0x55, 0x20, 0x20, 0x20, 0x4C, 0x39, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x4D, 0x7E, 0x54, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x2E, 0x51, 0xA3, 0xA3, 0xA3,
-  0xA3, 0xA3, 0xA3, 0x2F, 0xB2, 0xB2, 0x2F, 0xA3,
-  0x66, 0x66, 0xA3, 0xA3, 0xA3, 0xA3, 0x66, 0x66,
-  0xB2, 0x51, 0x51, 0xB2, 0xB2, 0xA3, 0x2F, 0xA3,
-  0x2F, 0x2F, 0x2F, 0xA3, 0xA3, 0xA3, 0xA3, 0x66,
-  0xA3, 0x2F, 0xB2, 0x2F, 0xA3, 0x98, 0x98, 0xA0,
-  0x20, 0x20, 0x20, 0x20, 0xA5, 0x83, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x4D, 0x7E, 0x4D, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x4D, 0x4D, 0xD6, 0x7E, 0xDD,
-  0x3C, 0x39, 0xA7, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x92, 0xB2, 0xA3, 0xA3,
-  0xA3, 0x66, 0xA3, 0x2F, 0x2F, 0x2F, 0xA3, 0x98,
-  0x98, 0x66, 0xA3, 0xA3, 0x66, 0x66, 0x66, 0xA3,
-  0x89, 0x89, 0x51, 0xB2, 0xB2, 0x2F, 0x2F, 0x2F,
-  0x2F, 0xA3, 0xA3, 0x2F, 0xA3, 0xA3, 0xA3, 0xA3,
-  0xA3, 0xA3, 0xA3, 0x66, 0x8F, 0x8F, 0x2F, 0xDA,
-  0x20, 0x20, 0x20, 0xDA, 0xA0, 0x51, 0x3C, 0x7E,
-  0x6B, 0x6B, 0x6B, 0x4D, 0x7E, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x7E, 0x3C, 0xD8, 0x44, 0xD8,
-  0x44, 0x83, 0x89, 0xDA, 0x20, 0x3A, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0xB2, 0xA3, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0x66, 0x8F, 0x8F,
-  0x98, 0x98, 0x98, 0x98, 0x66, 0xA3, 0xA3, 0x2F,
-  0x3C, 0x89, 0x89, 0x51, 0xB2, 0xB2, 0x2F, 0x2F,
-  0x2F, 0x2F, 0xA3, 0xA3, 0x66, 0x66, 0x66, 0xA3,
-  0xA3, 0xA3, 0xA3, 0x66, 0x98, 0x98, 0xA3, 0x20,
-  0x20, 0x20, 0x20, 0x6D, 0x2F, 0xE6, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x3D, 0xD6, 0x3D,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x4D, 0x7E, 0xA2,
-  0x74, 0x44, 0xA2, 0xA3, 0x20, 0x3A, 0x2E, 0x6D,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0xA6, 0xA3, 0x66,
-  0x66, 0x66, 0xA3, 0x2F, 0xA3, 0x66, 0x66, 0x98,
-  0x66, 0x66, 0x98, 0x98, 0x98, 0x66, 0xA3, 0xA3,
-  0x83, 0xB2, 0x2F, 0x2F, 0xB2, 0xB2, 0xB2, 0x2F,
-  0x2F, 0x2F, 0xA3, 0x66, 0x66, 0x98, 0x98, 0x66,
-  0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0x66, 0xA6, 0x20,
-  0x3A, 0x3A, 0x54, 0x55, 0x7E, 0x6B, 0x6B, 0x6B,
-  0x4D, 0x3D, 0x6B, 0x6B, 0x6B, 0x57, 0x33, 0xEB,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x4D, 0xA2, 0x74, 0x39, 0x92, 0x20, 0x20, 0x6D,
-  0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x98,
-  0x98, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0x66, 0x66,
-  0x66, 0x66, 0x66, 0x66, 0x66, 0xA3, 0x66, 0xA3,
-  0x89, 0xA3, 0x66, 0x66, 0xA3, 0xA3, 0x2F, 0x2F,
-  0xA3, 0x2F, 0xA3, 0xA3, 0x66, 0x66, 0x66, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xB2, 0x3A, 0x20,
-  0xA7, 0x20, 0x3A, 0x39, 0x6B, 0x6B, 0x6B, 0x6B,
-  0xB5, 0xCB, 0x6B, 0x6B, 0x3D, 0x8A, 0x42, 0x3D,
-  0x6B, 0x6B, 0x6B, 0x84, 0x6C, 0x4D, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x7E, 0x83, 0x51, 0x20, 0x20, 0x20,
-  0x6D, 0x3A, 0x20, 0x20, 0x20, 0x20, 0xAD, 0x66,
-  0x66, 0x66, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0x66, 0xA3, 0xA3, 0xA3,
-  0xB2, 0x98, 0x66, 0x66, 0x98, 0x66, 0x66, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F,
-  0xA3, 0x2F, 0xA3, 0xA3, 0xA3, 0x2F, 0x20, 0x6D,
-  0x3A, 0x20, 0x98, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0xAA, 0x33, 0x6B, 0x6B, 0x3D, 0xF5, 0x7B, 0x3D,
-  0x6B, 0x6B, 0x4F, 0x4A, 0x58, 0x3D, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x7E, 0x7E, 0x9C, 0x54, 0xA7,
-  0x2E, 0xA7, 0x20, 0x20, 0x20, 0x20, 0x54, 0x51,
-  0x2F, 0x2F, 0xA3, 0x2F, 0xA3, 0xA3, 0xA3, 0xA3,
-  0x2F, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0x2F,
-  0xB2, 0x66, 0x66, 0x66, 0x66, 0xA3, 0x66, 0xA3,
-  0x66, 0x66, 0xA3, 0x2F, 0x2F, 0xB2, 0x2F, 0xB2,
-  0x2F, 0x2F, 0x2F, 0xA3, 0x2F, 0xA6, 0x20, 0xCE,
-  0x20, 0x6D, 0x4D, 0x6B, 0xD6, 0x7E, 0x6B, 0x6B,
-  0x6E, 0x9A, 0x57, 0x6B, 0x2D, 0x7B, 0x7B, 0x3D,
-  0x6B, 0x84, 0xF5, 0x7B, 0x84, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x98, 0x3A, 0x9C,
-  0xCE, 0x3A, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x98,
-  0xB2, 0xB2, 0x2F, 0x2F, 0x2F, 0xA3, 0x2F, 0x2F,
-  0x2F, 0xA3, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F,
-  0x89, 0xA3, 0x66, 0x66, 0xA3, 0x2F, 0x2F, 0xA3,
-  0x66, 0x66, 0xA3, 0xA3, 0x2F, 0x2F, 0xB2, 0xB2,
-  0xB2, 0x2F, 0x2F, 0x2F, 0x89, 0x54, 0x6D, 0x3A,
-  0x20, 0x98, 0x6B, 0x6B, 0xE0, 0xB4, 0x6B, 0x6B,
-  0x2D, 0x9E, 0x4A, 0x3D, 0x84, 0xF5, 0xF5, 0x84,
-  0x6B, 0x6E, 0x59, 0x6C, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x3D, 0x6B, 0x6B, 0x6B, 0x6B, 0xDD, 0xDA, 0x6D,
-  0x54, 0x20, 0xCE, 0x20, 0x20, 0x20, 0x20, 0xA7,
-  0x51, 0xB2, 0xB2, 0xB2, 0x2F, 0xB2, 0x2F, 0x2F,
-  0x2F, 0x66, 0x66, 0xA3, 0xA3, 0xA3, 0xA3, 0x66,
-  0x89, 0xA3, 0xA3, 0xA3, 0x2F, 0xB2, 0xB2, 0x2F,
-  0x66, 0x66, 0xA3, 0xA3, 0x2F, 0xA3, 0xA3, 0x2F,
-  0xB2, 0x2F, 0x2F, 0xA3, 0x98, 0x20, 0xA7, 0x20,
-  0x3A, 0x7E, 0x6B, 0x6B, 0x7F, 0xDE, 0xF6, 0x3D,
-  0x6B, 0xDB, 0x8A, 0xDB, 0xE9, 0xF3, 0xF3, 0xDB,
-  0x68, 0xF3, 0x73, 0x7F, 0x6B, 0x6B, 0x57, 0x58,
-  0xDC, 0x2D, 0x6B, 0x6B, 0x6B, 0x6B, 0x3A, 0x20,
-  0x20, 0x20, 0x6D, 0x54, 0x20, 0x20, 0x20, 0x20,
-  0x51, 0x2F, 0x2F, 0x2F, 0xA3, 0xA3, 0xA3, 0x66,
-  0xA3, 0x66, 0x98, 0x98, 0x66, 0x98, 0x98, 0x66,
-  0x2F, 0x66, 0x66, 0xA3, 0x2F, 0xB2, 0x2F, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0x66, 0xA3, 0xA3, 0xA3,
-  0x66, 0x98, 0x8F, 0x98, 0xCE, 0xDA, 0x2E, 0x20,
-  0x2A, 0x6B, 0x6B, 0x6B, 0x6B, 0x2C, 0x34, 0xCB,
-  0xEB, 0x6C, 0x31, 0x59, 0x82, 0x82, 0x8B, 0x82,
-  0xF3, 0x73, 0xE9, 0x6B, 0x3D, 0x6E, 0xF3, 0x4A,
-  0x4F, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x92, 0x20,
-  0x20, 0x20, 0x6D, 0x6D, 0x20, 0x20, 0x20, 0x20,
-  0xA3, 0xA3, 0x66, 0x98, 0x98, 0x8F, 0x8F, 0x98,
-  0x98, 0x98, 0x98, 0x66, 0x98, 0x66, 0x66, 0xA3,
-  0xA3, 0x66, 0x66, 0x66, 0xA3, 0x2F, 0x2F, 0xA3,
-  0xA3, 0xA3, 0x66, 0x66, 0xA3, 0xA3, 0xA3, 0x66,
-  0x8F, 0x55, 0xA5, 0x98, 0x20, 0x2E, 0x54, 0x54,
-  0x89, 0x6B, 0x6B, 0x6B, 0x6B, 0x84, 0xE3, 0x4A,
-  0x58, 0x42, 0x5B, 0x8B, 0x82, 0x82, 0x82, 0x82,
-  0x82, 0x59, 0x58, 0x57, 0x57, 0x59, 0x7B, 0x84,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0xAD, 0x20,
-  0x20, 0x20, 0x3A, 0x3A, 0x20, 0x20, 0x20, 0x20,
-  0x2A, 0x66, 0x8F, 0x55, 0xA5, 0xA5, 0xA0, 0x8F,
-  0x66, 0xA3, 0xA3, 0x66, 0x98, 0x66, 0x66, 0x2F,
-  0x2F, 0x2F, 0x2F, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F,
-  0xA3, 0x2F, 0xA3, 0xA3, 0x66, 0xA3, 0xA3, 0x66,
-  0x8F, 0xA5, 0x8F, 0x2E, 0x20, 0x2E, 0x20, 0x3A,
-  0x4D, 0x6B, 0xE6, 0x84, 0x3D, 0x6B, 0xEB, 0x4A,
-  0xC9, 0x8B, 0x8B, 0x31, 0x59, 0x82, 0x59, 0x59,
-  0x5B, 0x82, 0x59, 0x73, 0x7B, 0xDC, 0x57, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x55, 0x20,
-  0x20, 0x20, 0x6D, 0xDA, 0x20, 0x20, 0x20, 0x20,
-  0x9C, 0x66, 0x8F, 0xA5, 0xA5, 0x55, 0x8F, 0x66,
-  0x2F, 0xB2, 0x2F, 0x66, 0x98, 0x98, 0x2F, 0x51,
-  0x89, 0xB2, 0x2F, 0xA3, 0xA3, 0xB2, 0xB2, 0xB2,
-  0x2F, 0x2F, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0x66,
-  0x8F, 0xA5, 0x8F, 0x20, 0x20, 0xA7, 0x20, 0xA6,
-  0x6B, 0x6B, 0xE4, 0x48, 0x2C, 0xDB, 0x4F, 0x9E,
-  0xD0, 0xD0, 0x8B, 0x82, 0x82, 0x82, 0x82, 0x82,
-  0x59, 0x82, 0x82, 0x73, 0x7B, 0x68, 0x6B, 0x3D,
-  0x68, 0x68, 0x84, 0x3D, 0x6B, 0x6B, 0xA0, 0x20,
-  0x20, 0x20, 0x6D, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x6D, 0x2F, 0xA0, 0xA5, 0x55, 0x98, 0x66, 0xA3,
-  0xB2, 0x89, 0xB2, 0x98, 0x8F, 0x98, 0x2F, 0x51,
-  0x74, 0xB2, 0xA3, 0xA3, 0x2F, 0x2F, 0xB2, 0x2F,
-  0xA3, 0xA3, 0xA3, 0x66, 0x66, 0xA3, 0x2F, 0xA3,
-  0x98, 0xA3, 0x6D, 0x20, 0x20, 0xCE, 0x20, 0x2A,
-  0x6B, 0x6B, 0xEB, 0x2C, 0xE1, 0xF1, 0x7C, 0xD0,
-  0x8B, 0x8B, 0x82, 0x82, 0x82, 0x82, 0x82, 0x59,
-  0x82, 0x82, 0x42, 0x82, 0x31, 0x57, 0x4F, 0x7B,
-  0x7B, 0xF5, 0xF6, 0xDB, 0x6B, 0x6B, 0x98, 0x20,
-  0x20, 0x20, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x51, 0x66, 0xA0, 0xA0, 0x66, 0x2F, 0xB2,
-  0xB2, 0x51, 0x2F, 0xA0, 0x55, 0xA3, 0x51, 0x89,
-  0x44, 0xA3, 0x98, 0x98, 0x2F, 0x2F, 0x2F, 0xA3,
-  0xA3, 0x66, 0x98, 0x98, 0x98, 0xA3, 0x2F, 0x2F,
-  0x98, 0x8F, 0x20, 0x20, 0x3A, 0xA6, 0x20, 0xA0,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x7F, 0x7F, 0xC3, 0xC9,
-  0xD0, 0xD0, 0x29, 0x59, 0x82, 0x73, 0x82, 0x73,
-  0x59, 0x59, 0x59, 0x59, 0x59, 0x58, 0xAF, 0xF5,
-  0x8A, 0x68, 0xEB, 0x6B, 0x6B, 0x6B, 0x98, 0x20,
-  0x20, 0x20, 0x6D, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x51, 0x98, 0x55, 0xA0, 0xA3, 0xB2, 0x51,
-  0x51, 0x2F, 0x98, 0x55, 0x8F, 0xB2, 0x89, 0x44,
-  0xA3, 0x55, 0x55, 0x98, 0xA3, 0xB2, 0x2F, 0xA3,
-  0x66, 0x66, 0x98, 0x8F, 0x66, 0xA3, 0x66, 0x98,
-  0x55, 0x4C, 0x20, 0x20, 0xDA, 0xAD, 0x20, 0x98,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x3D, 0x9A, 0xD0,
-  0xF2, 0x8B, 0x8B, 0x8B, 0x73, 0x82, 0x5B, 0x82,
-  0x82, 0x59, 0x59, 0x73, 0x73, 0x58, 0x3D, 0x3D,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x66, 0x20,
-  0x20, 0x3A, 0x3A, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x2F, 0x55, 0xA5, 0x8F, 0xA3, 0x51, 0x51,
-  0xB2, 0xA3, 0x66, 0x66, 0xA3, 0xB2, 0x89, 0x51,
-  0x98, 0xA5, 0x55, 0x8F, 0x2F, 0xB2, 0xB2, 0xA3,
-  0x66, 0x66, 0x98, 0x98, 0x98, 0x66, 0x66, 0x8F,
-  0x8F, 0x92, 0x20, 0x20, 0x20, 0x6D, 0x6D, 0xA3,
-  0x6B, 0x6B, 0xEB, 0x7F, 0x4F, 0xDB, 0xD2, 0xC9,
-  0xC9, 0xD0, 0x8B, 0x8B, 0x73, 0x82, 0x59, 0x8B,
-  0x59, 0x82, 0x59, 0x59, 0x73, 0xF5, 0xEB, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x55, 0x20,
-  0x20, 0xA7, 0x54, 0xDA, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x98, 0xA0, 0x8F, 0xA3, 0xB2, 0x51, 0x51,
-  0x51, 0x2F, 0xA3, 0xA3, 0xB2, 0xB2, 0x51, 0xB2,
-  0xA0, 0xA5, 0x55, 0x66, 0x2F, 0x51, 0x2F, 0xA3,
-  0x66, 0x66, 0x66, 0x98, 0x66, 0x66, 0x98, 0x98,
-  0x98, 0x2A, 0x54, 0x95, 0x95, 0x71, 0x2E, 0x98,
-  0x6B, 0x6B, 0x4D, 0x28, 0xDE, 0x88, 0xB7, 0x70,
-  0xC9, 0xC9, 0xD0, 0xF2, 0x8B, 0x8B, 0x8B, 0x59,
-  0x59, 0x59, 0x59, 0x5B, 0x59, 0xF3, 0x57, 0xE9,
-  0xDB, 0x84, 0x6B, 0x6B, 0x6B, 0x6B, 0x4C, 0xDA,
-  0x2E, 0xDA, 0x20, 0xDA, 0x2E, 0x2E, 0x6D, 0x20,
-  0x4C, 0x98, 0x66, 0xA3, 0x2F, 0xB2, 0x51, 0x51,
-  0xB2, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F,
-  0xA0, 0xA0, 0x8F, 0x2F, 0xB2, 0x89, 0xB2, 0xA3,
-  0x66, 0x66, 0x98, 0x66, 0x66, 0x66, 0x66, 0xA3,
-  0x2F, 0xD1, 0xE2, 0x52, 0x52, 0xF4, 0xBF, 0x9C,
-  0x39, 0x6B, 0x6B, 0x6B, 0x7F, 0x4F, 0xE3, 0x6A,
-  0xD0, 0xC9, 0xC9, 0xD0, 0xD0, 0x8B, 0x8B, 0x82,
-  0x5B, 0x5B, 0x73, 0x8B, 0x59, 0x23, 0x6E, 0x31,
-  0x59, 0x7B, 0xDB, 0x84, 0x68, 0x7F, 0xAE, 0x54,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0xA6, 0x3A,
-  0xA0, 0xA3, 0xA3, 0x2F, 0x51, 0x51, 0x51, 0xB2,
-  0x2F, 0xA3, 0x66, 0x66, 0xA3, 0xA3, 0xA3, 0xA3,
-  0x8F, 0x8F, 0x66, 0x2F, 0x51, 0x51, 0xB2, 0xA3,
-  0x66, 0x98, 0x98, 0x66, 0x66, 0xA3, 0x2F, 0x2F,
-  0x3C, 0x88, 0x8D, 0x52, 0x52, 0x5D, 0xF7, 0xBF,
-  0xCE, 0xA2, 0x6B, 0x6B, 0x6B, 0x6B, 0x7F, 0x85,
-  0x70, 0xC9, 0xC9, 0xC9, 0xD0, 0xEA, 0x8B, 0x5B,
-  0x82, 0xEA, 0x82, 0x82, 0x42, 0x57, 0x3D, 0x68,
-  0x68, 0x57, 0x4A, 0x34, 0x22, 0xCC, 0x21, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0xDA, 0xA7, 0x6D,
-  0xDF, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0x2F, 0x2F,
-  0xA3, 0x66, 0x66, 0x66, 0xA3, 0xA3, 0x2F, 0x2F,
-  0x66, 0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0x2F, 0x66,
-  0x8F, 0x8F, 0x8F, 0x98, 0xA3, 0xA3, 0x89, 0xD8,
-  0x25, 0x5C, 0x3B, 0x5D, 0x52, 0x80, 0x70, 0x36,
-  0x71, 0xA7, 0x44, 0x6B, 0x84, 0xCB, 0xAA, 0xF3,
-  0xC9, 0xC9, 0xC9, 0xC9, 0xD0, 0x8B, 0x5B, 0x5B,
-  0x5B, 0xEA, 0x82, 0x47, 0x7B, 0x68, 0x3D, 0x3D,
-  0x6B, 0x3D, 0x6C, 0x2B, 0x80, 0x61, 0x96, 0x81,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x3A, 0xDA, 0x63,
-  0xAC, 0x6C, 0xB2, 0xB2, 0xB2, 0xB2, 0x2F, 0xA3,
-  0xA3, 0x66, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F,
-  0x66, 0x98, 0x66, 0xA3, 0xB2, 0xB2, 0x2F, 0x66,
-  0x8F, 0x8F, 0x2F, 0xD8, 0xE4, 0xCD, 0xAA, 0xB4,
-  0x78, 0x2B, 0x3B, 0x70, 0x46, 0x5D, 0x5D, 0x52,
-  0x9D, 0x81, 0x3A, 0xA3, 0xCD, 0x48, 0xBE, 0x4F,
-  0xC3, 0xC9, 0xD0, 0xD0, 0xD0, 0xEA, 0x5B, 0x8B,
-  0x5B, 0x82, 0x8B, 0x59, 0x4A, 0xF3, 0x33, 0x7F,
-  0x3D, 0x6B, 0x4F, 0x6F, 0x5D, 0x52, 0x63, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x75, 0x85,
-  0x72, 0xDC, 0xD8, 0x2F, 0xA3, 0x2F, 0xA3, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
-  0xA3, 0x98, 0x66, 0x2F, 0xB2, 0x51, 0xA3, 0x98,
-  0xA0, 0xA3, 0x93, 0xCF, 0x79, 0x27, 0x5C, 0x79,
-  0x2B, 0x30, 0x80, 0x80, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x3F, 0x69, 0x20, 0x20, 0x2A, 0xD6, 0x3D, 0x6B,
-  0x84, 0xE3, 0x34, 0xB7, 0xC9, 0xD0, 0xD0, 0xF2,
-  0xD0, 0x8B, 0x31, 0x68, 0x68, 0x6E, 0x31, 0x33,
-  0x7F, 0x7E, 0xA1, 0x6F, 0x52, 0x8D, 0xE5, 0xBF,
-  0x20, 0x20, 0x20, 0x20, 0x81, 0xA8, 0x78, 0x52,
-  0x52, 0xD2, 0xD8, 0xA3, 0xA3, 0x2F, 0x2F, 0xA3,
-  0xA3, 0x66, 0x98, 0x98, 0x98, 0x98, 0x98, 0x66,
-  0x51, 0x66, 0x2F, 0x51, 0x51, 0xB2, 0xA3, 0xA0,
-  0xA0, 0x44, 0x78, 0xEF, 0x52, 0x30, 0x30, 0x30,
-  0x3B, 0x70, 0x5D, 0x5D, 0x5D, 0x80, 0x5D, 0x5D,
-  0x46, 0xC1, 0x71, 0x20, 0x81, 0xB1, 0xDD, 0x3D,
-  0xA1, 0xE7, 0xDB, 0xCA, 0xD2, 0x6A, 0x6A, 0x6A,
-  0xF3, 0xE9, 0xDB, 0x8A, 0x84, 0x3D, 0x84, 0xDC,
-  0x25, 0x44, 0xB5, 0xEE, 0x30, 0xEF, 0xF0, 0x32,
-  0x69, 0x5F, 0x4B, 0xA8, 0x99, 0x56, 0x67, 0x30,
-  0x30, 0x34, 0xB2, 0x2F, 0xA3, 0xA3, 0x66, 0x66,
-  0x98, 0x8F, 0x98, 0x98, 0x66, 0x66, 0x66, 0x66,
-  0x51, 0x2F, 0xB2, 0x51, 0x51, 0x2F, 0x66, 0xA0,
-  0x8F, 0xE0, 0xF9, 0x8D, 0x52, 0x5D, 0x46, 0x5D,
-  0x80, 0x5D, 0x80, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x52, 0x52, 0x60, 0x81, 0x20, 0x20, 0x6D, 0xD1,
-  0x48, 0xE7, 0x6B, 0x33, 0xF6, 0x7F, 0x7F, 0xDB,
-  0x84, 0x6B, 0x6C, 0x6A, 0xF3, 0xEB, 0x6B, 0x3D,
-  0x4F, 0xD8, 0xCD, 0x79, 0x30, 0x67, 0xF9, 0x24,
-  0xED, 0xD9, 0x8C, 0xED, 0x37, 0x2B, 0x3B, 0x5D,
-  0x80, 0x85, 0x4E, 0x98, 0x66, 0x66, 0x66, 0x66,
-  0x66, 0x66, 0x66, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F,
-  0x51, 0x2F, 0xB2, 0xB2, 0xB2, 0xA3, 0x8F, 0x8F,
-  0x98, 0xE0, 0xF0, 0x67, 0x5D, 0x80, 0x80, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x80, 0x5D, 0x5D, 0x5D,
-  0x5D, 0x70, 0x27, 0x4B, 0x20, 0x81, 0x71, 0x3A,
-  0xB5, 0xEB, 0x3D, 0xF1, 0xE1, 0x84, 0x84, 0xF1,
-  0xE3, 0x3D, 0x6B, 0x6C, 0x34, 0xE7, 0x6B, 0x6B,
-  0xD6, 0x74, 0x5E, 0x78, 0x67, 0x30, 0xEE, 0x5C,
-  0xF9, 0xF9, 0x45, 0x5C, 0x2B, 0x3B, 0x5D, 0x5D,
-  0x5D, 0x5D, 0xF8, 0x44, 0x66, 0x66, 0x66, 0x66,
-  0x2F, 0x2F, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2,
-  0xB2, 0x2F, 0xA3, 0xA3, 0xA3, 0x98, 0x8F, 0x98,
-  0x66, 0x83, 0x76, 0x67, 0x30, 0x80, 0x5D, 0x80,
-  0x5D, 0x5D, 0x80, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x80, 0x5D, 0x22, 0xFA, 0x20, 0x81, 0x20, 0x20,
-  0xA5, 0x6B, 0x6B, 0xE8, 0xBE, 0x3D, 0x6B, 0x2C,
-  0xE1, 0xEB, 0x6B, 0x3D, 0x3E, 0xA1, 0x6B, 0x6B,
-  0x4D, 0x74, 0xE8, 0x62, 0x67, 0x30, 0x8D, 0x67,
-  0xEE, 0xEE, 0xEE, 0x67, 0x30, 0x80, 0x5D, 0x5D,
-  0x52, 0x5D, 0x85, 0xAC, 0x3E, 0xA3, 0x66, 0x66,
-  0x2F, 0x51, 0x51, 0x51, 0x51, 0xB2, 0x2F, 0x2F,
-  0x2F, 0xA3, 0xA3, 0x66, 0x98, 0x8F, 0x8F, 0x66,
-  0x2F, 0x83, 0xBC, 0xEE, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x80, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x22, 0xB0, 0xAE, 0x81, 0x20, 0x20,
-  0x4C, 0x3D, 0xEB, 0x39, 0x57, 0x6B, 0x6B, 0x3E,
-  0x97, 0x3D, 0x6B, 0x3D, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x3D, 0x3C, 0xBA, 0x62, 0xEE, 0x5D, 0x5D, 0x30,
-  0x30, 0x8D, 0x8D, 0x30, 0x52, 0x5D, 0x5D, 0x80,
-  0x5D, 0x5D, 0x5D, 0x85, 0xB0, 0x6E, 0x2F, 0x66,
-  0x2F, 0xB2, 0x51, 0xB2, 0x2F, 0x2F, 0xA3, 0xA3,
-  0xB2, 0xA3, 0x66, 0x98, 0x98, 0x8F, 0x98, 0xA3,
-  0x2F, 0x51, 0xDE, 0x8E, 0x30, 0x5D, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x52, 0x80, 0x5D, 0x22, 0x43, 0x4B, 0x20, 0x6D,
-  0x44, 0x6B, 0x6B, 0x3D, 0x6B, 0x6B, 0x6B, 0x4D,
-  0x3D, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x3D, 0x6B,
-  0x4D, 0x2A, 0xAE, 0x76, 0xEE, 0x30, 0x80, 0x80,
-  0x80, 0x80, 0x80, 0x80, 0x5D, 0x5D, 0x5D, 0x80,
-  0x5D, 0x5D, 0x80, 0x80, 0x5D, 0x7A, 0xB6, 0x51,
-  0xB2, 0xB2, 0xB2, 0xA3, 0x66, 0x66, 0x66, 0xA3,
-  0x2F, 0x66, 0x98, 0x8F, 0xA0, 0x98, 0xA3, 0x2F,
-  0x2F, 0x51, 0xAB, 0x8E, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x80,
-  0x5D, 0x80, 0x5D, 0x52, 0x52, 0x94, 0x2F, 0x7E,
-  0x6B, 0x3D, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x7E,
-  0xAD, 0x54, 0xAE, 0x24, 0x2B, 0x3B, 0x5D, 0x52,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x80, 0x5D, 0x5D, 0x80,
-  0x5D, 0x52, 0x52, 0x5D, 0x5D, 0x5D, 0xD2, 0x3E,
-  0x89, 0x89, 0xB2, 0xA3, 0x66, 0x98, 0x66, 0x66,
-  0x2F, 0x66, 0x8F, 0x8F, 0xA0, 0x98, 0xA3, 0xB2,
-  0x2F, 0x51, 0xDE, 0x79, 0x5D, 0x80, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x80, 0x5D, 0x52, 0x6F, 0xA4, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x4D, 0xA2, 0xCE,
-  0x20, 0x20, 0x95, 0x24, 0x67, 0x3B, 0x80, 0x80,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x80, 0x5D, 0x5D, 0x5D, 0x5D, 0x30, 0xB0, 0x86,
-  0x89, 0x51, 0x2F, 0x66, 0x98, 0x98, 0xA3, 0xA3,
-  0xA3, 0x66, 0x8F, 0xA0, 0x8F, 0x66, 0x2F, 0xB2,
-  0x2F, 0x4E, 0x76, 0x2B, 0x30, 0x5D, 0x5D, 0x5D,
-  0x80, 0x80, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x80, 0x5D, 0x5D, 0x5D, 0x46, 0x52, 0x21, 0x74,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x7E, 0x98, 0x3A, 0x20,
-  0x20, 0x81, 0x60, 0xED, 0x2B, 0x52, 0x5D, 0x5D,
-  0x80, 0x5D, 0x5D, 0x80, 0x5D, 0x5D, 0x5D, 0x80,
-  0x22, 0x5D, 0x5D, 0x5D, 0x8D, 0x2B, 0x38, 0x39,
-  0x51, 0x66, 0x8F, 0xA0, 0xA0, 0x8F, 0x98, 0x66,
-  0x66, 0x66, 0x8F, 0x55, 0x8F, 0xA3, 0xB2, 0xB2,
-  0xA3, 0xE8, 0xF9, 0x30, 0x3B, 0x80, 0x5D, 0x5D,
-  0x5D, 0x80, 0x80, 0x5D, 0x5D, 0x5D, 0x80, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x52, 0x30, 0xD4, 0x99,
-  0x51, 0x4D, 0x6B, 0x6B, 0x6B, 0x6B, 0x4D, 0x6B,
-  0x6B, 0x6B, 0x7E, 0xA3, 0x2E, 0x20, 0x20, 0x20,
-  0x20, 0x81, 0xC5, 0xED, 0x2B, 0x3B, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x80, 0x5D, 0x5D, 0x80,
-  0x5D, 0x52, 0x52, 0x6F, 0xDE, 0x2C, 0x39, 0x51,
-  0x66, 0xA0, 0xA5, 0xA5, 0x55, 0x8F, 0x66, 0x66,
-  0xA0, 0xA0, 0xA0, 0xA0, 0x8F, 0xA3, 0x2F, 0x2F,
-  0x51, 0xD5, 0x45, 0x8D, 0x3B, 0x5D, 0x80, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x80, 0x5D, 0x5D, 0x5D, 0x52, 0x67, 0x37, 0xA9,
-  0x3A, 0xCE, 0xA0, 0x2F, 0x51, 0x51, 0xB2, 0xA3,
-  0xA5, 0x9C, 0x54, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x54, 0x99, 0xED, 0x67, 0x30, 0x5D, 0x5D,
-  0x5D, 0x80, 0x5D, 0x5D, 0x5D, 0x5D, 0x3B, 0x80,
-  0x8D, 0x79, 0x48, 0x2C, 0x39, 0x44, 0xB2, 0x66,
-  0xA0, 0x2A, 0xA5, 0xA0, 0x8F, 0x66, 0xA3, 0xA3,
-  0xA0, 0x8F, 0x8F, 0xA0, 0x8F, 0xA3, 0xB2, 0xB2,
-  0xD8, 0xBC, 0x45, 0xEE, 0x67, 0x8D, 0x30, 0x30,
-  0x52, 0x52, 0x80, 0x5D, 0x5D, 0x5D, 0x5D, 0x80,
-  0x5D, 0x5D, 0x5D, 0x80, 0x3B, 0x67, 0xF9, 0x32,
-  0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0xBF, 0xEC, 0xED, 0x2B, 0x30, 0x5D, 0x5D,
-  0x80, 0x5D, 0x5D, 0x5D, 0x52, 0x30, 0x67, 0x2B,
-  0xCF, 0xAA, 0xD8, 0x89, 0x89, 0x51, 0x66, 0x55,
-  0x2A, 0x2A, 0xA5, 0x8F, 0x66, 0xA3, 0x2F, 0x2F,
-  0xA3, 0xA3, 0x66, 0x98, 0x98, 0x2F, 0xB2, 0x2F,
-  0xD1, 0x28, 0x56, 0xED, 0x62, 0x37, 0x5C, 0x79,
-  0x8E, 0x2B, 0x2B, 0x30, 0x30, 0x30, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x80, 0x3B, 0xEE, 0x56, 0xA9,
-  0x75, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x5F, 0x99, 0xD9, 0x45, 0x8D, 0x3B, 0x5D,
-  0x5D, 0x3B, 0x5D, 0x8D, 0x2B, 0x79, 0x79, 0x41,
-  0x83, 0xB2, 0xB2, 0x89, 0x89, 0x2F, 0xA0, 0x2A,
-  0xAD, 0xA5, 0x98, 0x66, 0xA3, 0xB2, 0x2F, 0xB2,
-  0xD8, 0xB2, 0xA3, 0x98, 0x98, 0x2F, 0x51, 0xB2,
-  0xA3, 0x83, 0x3E, 0x25, 0xD5, 0xE5, 0x50, 0x8C,
-  0xED, 0x24, 0x24, 0xF0, 0x45, 0x8E, 0x2B, 0x30,
-  0x30, 0x5D, 0x3B, 0x30, 0xEE, 0xF0, 0xC6, 0x65,
-  0x75, 0x71, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x4B, 0xC5, 0x7D, 0x24, 0xEE, 0x67, 0x30,
-  0x30, 0x8D, 0x67, 0x8E, 0xF9, 0xF7, 0x97, 0xDD,
-  0x2F, 0x2F, 0x51, 0x89, 0x89, 0x2F, 0x55, 0x2A,
-  0xA5, 0x8F, 0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0xB2,
-  0xDD, 0xA3, 0x66, 0x98, 0x66, 0x2F, 0xB2, 0xB2,
-  0xA3, 0xA3, 0xB2, 0x51, 0x89, 0x44, 0xE0, 0x5E,
-  0x91, 0x9F, 0x9F, 0x7D, 0x7D, 0xD9, 0x24, 0xF0,
-  0x79, 0x8E, 0xEE, 0x8E, 0x24, 0x40, 0x65, 0x35,
-  0x69, 0x2E, 0x98, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F,
-  0x2F, 0xB2, 0xB2, 0xB2, 0x2F, 0x2F, 0x2F, 0x98,
-  0xA5, 0xA7, 0x95, 0xD7, 0x8C, 0xF0, 0x8E, 0x8E,
-  0xEE, 0x79, 0xF0, 0xED, 0x50, 0xE8, 0x89, 0x2F,
-  0xA3, 0xA3, 0xB2, 0x89, 0xB2, 0x66, 0xA0, 0x55,
-  0x8F, 0x98, 0x66, 0xA3, 0xB2, 0x51, 0x51, 0xB2,
-  0x74, 0xA0, 0xA0, 0x98, 0x66, 0xB2, 0xB2, 0xB2,
-  0xA3, 0xA3, 0x2F, 0xB2, 0xB2, 0xB2, 0xA3, 0x2F,
-  0x51, 0x83, 0xE4, 0x87, 0xB8, 0xFA, 0xA9, 0xC6,
-  0x40, 0x64, 0x64, 0x50, 0xD7, 0x65, 0x35, 0x60,
-  0x98, 0xB2, 0x66, 0x66, 0xA3, 0x2F, 0xA3, 0xA3,
-  0xA3, 0x2F, 0x2F, 0x2F, 0x2F, 0xA3, 0x2F, 0xB2,
-  0x89, 0xDD, 0x9B, 0xC0, 0x7D, 0x50, 0x8C, 0xED,
-  0xED, 0x8C, 0x40, 0x9F, 0x4E, 0x51, 0xB2, 0x2F,
-  0x2F, 0x2F, 0xB2, 0x51, 0xA3, 0x98, 0xA0, 0x55,
-  0xA0, 0xA0, 0x8F, 0x66, 0x2F, 0x51, 0xB2, 0xA3,
-  0xA3, 0x2A, 0x55, 0x98, 0xA3, 0x2F, 0xB2, 0x2F,
-  0x66, 0x66, 0x2F, 0xB2, 0xD1, 0x2F, 0x2F, 0xA3,
-  0xB2, 0xB2, 0xA3, 0x8F, 0xA3, 0x2F, 0xD1, 0x94,
-  0xEC, 0x65, 0x65, 0xC0, 0xC0, 0x35, 0x95, 0xC2,
-  0xA3, 0x98, 0x66, 0xA3, 0x2F, 0x2F, 0x2F, 0xA3,
-  0xA3, 0x2F, 0xB2, 0x2F, 0x2F, 0x2F, 0x2F, 0x51,
-  0x89, 0x44, 0xD1, 0x60, 0x35, 0xA9, 0x32, 0xC6,
-  0xD7, 0x32, 0x94, 0x44, 0x2F, 0xB2, 0xB2, 0xB2,
-  0xA3, 0x2F, 0xB2, 0x2F, 0xA3, 0x8F, 0xA0, 0xA0,
-  0x55, 0xA0, 0x8F, 0xA3, 0x51, 0x51, 0x2F, 0xA3,
-  0x8F, 0x2A, 0x55, 0x66, 0xA3, 0x2F, 0x2F, 0xB2,
-  0xA3, 0x66, 0x2F, 0xB2, 0x51, 0xB2, 0x2F, 0x66,
-  0xA3, 0xA3, 0x66, 0x8F, 0x8F, 0x8F, 0xA0, 0x2F,
-  0x5E, 0xDF, 0xB9, 0x60, 0x95, 0xD3, 0x89, 0x2F,
-  0xA3, 0x66, 0xA3, 0x2F, 0xB2, 0x2F, 0xA3, 0xA3,
-  0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0xB2,
-  0x51, 0x2F, 0x8F, 0x2F, 0xC4, 0xB9, 0x9B, 0xEC,
-  0x53, 0xB3, 0x4E, 0xA3, 0x2F, 0xB2, 0xB2, 0xB2,
-  0xA3, 0x66, 0xA3, 0xA3, 0x66, 0x8F, 0x8F, 0x8F,
-  0x8F, 0x8F, 0xA3, 0x51, 0x89, 0x51, 0xA3, 0x66,
-  0xA0, 0x55, 0x8F, 0xA3, 0x2F, 0x2F, 0x2F, 0xB2,
-  0x2F, 0xA3, 0x2F, 0x51, 0x51, 0xB2, 0xA3, 0x66,
-  0x66, 0xA3, 0x66, 0x66, 0x66, 0x66, 0x66, 0xA3,
-  0xB2, 0xC2, 0x74, 0xD8, 0xB2, 0xA3, 0xA3, 0xA3,
-  0x66, 0x66, 0x2F, 0x2F, 0xA3, 0x66, 0x66, 0x66,
-  0xA3, 0xA3, 0xB2, 0xB2, 0xB2, 0xB2, 0x2F, 0xB2,
-  0x2F, 0x66, 0xA0, 0x55, 0x98, 0x2F, 0x89, 0x89,
-  0x89, 0xB2, 0x2F, 0xA3, 0x2F, 0x51, 0x51, 0xB2,
-  0x2F, 0x66, 0xA3, 0xA3, 0x66, 0x66, 0x66, 0x66,
-  0x66, 0xA3, 0xB2, 0x89, 0xD8, 0x51, 0xA3, 0x98,
-  0x66, 0x98, 0x66, 0x2F, 0x2F, 0x2F, 0x2F, 0xB2,
-  0xB2, 0xA3, 0xA3, 0xB2, 0xB2, 0xB2, 0x2F, 0xA3,
-  0x66, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0xB2,
-  0x89, 0xD8, 0x89, 0x2F, 0x66, 0x66, 0xA3, 0xA3,
-  0x98, 0x98, 0x66, 0x66, 0x98, 0x98, 0x66, 0xA3,
-  0x2F, 0xA3, 0xB2, 0xB2, 0xB2, 0xB2, 0x2F, 0x2F,
-  0xB2, 0x2F, 0x66, 0x98, 0x66, 0xA3, 0x2F, 0x2F,
-  0x2F, 0xB2, 0x2F, 0xA3, 0xA3, 0xB2, 0xB2, 0x2F,
-  0x2F, 0x66, 0x66, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F,
-  0x2F, 0xB2, 0x89, 0xD8, 0x44, 0x2F, 0x66, 0x66,
-  0xA3, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F,
-  0x2F, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0xA3,
-  0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0xB2, 0x51, 0x51,
-  0x89, 0x89, 0xB2, 0xA3, 0x98, 0x66, 0xA3, 0x66,
-  0x98, 0x98, 0x98, 0x98, 0x98, 0x66, 0xA3, 0x2F,
-  0xA3, 0x2F, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2,
-  0xB2, 0x2F, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F,
-  0x2F, 0xB2, 0xB2, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F,
-  0x2F, 0xA3, 0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0xB2,
-  0x51, 0x51, 0x89, 0x89, 0xB2, 0xA3, 0x98, 0x66
-};
-
-unsigned char linux_logo_bw[] __initdata = {
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F,
-  0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFE, 0x3F, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xC7, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xC3,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF,
-  0xFB, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFD, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF,
-  0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xCF, 0xC3, 0xF8, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x87, 0x81, 0xF9,
-  0xF8, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xA7,
-  0x99, 0xF9, 0xC2, 0x40, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xF3, 0xBC, 0xF9, 0x90, 0x00, 0x1F, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xE3, 0xBC, 0xF9, 0xA0, 0x00,
-  0x8F, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0, 0x3C, 0xF9,
-  0x83, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0,
-  0x19, 0xF0, 0x1F, 0xFE, 0x0F, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xC0, 0x03, 0xF0, 0x3F, 0xF7, 0x8F, 0xFF,
-  0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8, 0x7F, 0xF7,
-  0xC7, 0xFF, 0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8,
-  0x6F, 0xF7, 0xE7, 0xFF, 0xFF, 0xFF, 0xF9, 0x80,
-  0x01, 0xF8, 0x7F, 0xF7, 0xE7, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xC0, 0x21, 0xD8, 0x7F, 0xE7, 0xEF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xB1, 0x80, 0xEC, 0x7B, 0xFF,
-  0xEF, 0xFF, 0xFF, 0xFF, 0xF1, 0x90, 0x00, 0xE4,
-  0x7B, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xF1, 0x8C,
-  0xC0, 0x7C, 0x79, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF,
-  0xE3, 0x80, 0x00, 0x7C, 0x7C, 0xFF, 0xCF, 0xFF,
-  0xFF, 0xFF, 0xE3, 0x80, 0x00, 0x7F, 0x77, 0xFF,
-  0xDF, 0xFF, 0xFF, 0xFF, 0x87, 0x00, 0x00, 0x3F,
-  0x3F, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0x0E, 0x00,
-  0x00, 0x3F, 0xBF, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF,
-  0x1E, 0x00, 0x00, 0x1F, 0x9F, 0xFF, 0x3F, 0xFF,
-  0xFF, 0xFE, 0x1C, 0x00, 0x00, 0x1F, 0x9F, 0xFF,
-  0x7F, 0xFF, 0xFF, 0xFE, 0x3C, 0x00, 0x00, 0x1F,
-  0x8F, 0xFE, 0x7F, 0xFF, 0xFF, 0xFC, 0x7C, 0x00,
-  0x00, 0x0F, 0xC7, 0xFC, 0xFF, 0xFF, 0xFF, 0xFC,
-  0xF8, 0x00, 0x00, 0x0F, 0xF7, 0xF9, 0xFF, 0xFF,
-  0xFF, 0xFC, 0xF8, 0x00, 0x00, 0x07, 0xFB, 0xF3,
-  0xFF, 0xFF, 0xFF, 0xF8, 0xF8, 0x00, 0x00, 0x07,
-  0xFD, 0xE7, 0xFF, 0xFF, 0xFF, 0xF9, 0xF0, 0x00,
-  0x00, 0x03, 0xFE, 0x8F, 0xFF, 0xFF, 0xFF, 0xF1,
-  0xF0, 0x00, 0x00, 0x03, 0xFE, 0x1F, 0xFF, 0xFF,
-  0xFF, 0xF1, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xBF,
-  0xFF, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x00, 0x00,
-  0xFE, 0xBF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC0, 0x00,
-  0x00, 0x00, 0xFE, 0x3F, 0xFF, 0xFF, 0xFF, 0xC7,
-  0xC0, 0x00, 0x00, 0x01, 0xFE, 0xBF, 0xFF, 0xFF,
-  0xFF, 0xC7, 0x80, 0x00, 0x00, 0x01, 0xFE, 0x9F,
-  0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x00, 0x01,
-  0xFE, 0x07, 0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00,
-  0x00, 0x01, 0xFE, 0x87, 0xFF, 0xFF, 0xFF, 0x9F,
-  0x80, 0x00, 0x00, 0x01, 0xFD, 0x33, 0xFF, 0xFF,
-  0xFF, 0x9F, 0x80, 0x00, 0x00, 0x01, 0x80, 0xF3,
-  0xFF, 0xFF, 0xFF, 0x9E, 0x80, 0x00, 0x00, 0x03,
-  0x8B, 0xF9, 0xFF, 0xFF, 0xFF, 0x9F, 0x80, 0x00,
-  0x00, 0x02, 0x27, 0xF8, 0xFF, 0xFF, 0xFF, 0x99,
-  0x80, 0x00, 0x00, 0x00, 0x07, 0xF8, 0xFF, 0xFF,
-  0xFF, 0x00, 0x80, 0x00, 0x00, 0x01, 0x8F, 0xF8,
-  0xFF, 0xFF, 0xFE, 0x20, 0x60, 0x00, 0x00, 0x00,
-  0xE3, 0xF8, 0xFF, 0xFF, 0xF8, 0x00, 0x30, 0x00,
-  0x00, 0x00, 0xF8, 0x78, 0xFF, 0xFF, 0xC0, 0x40,
-  0x38, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x7F, 0xFF,
-  0x81, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xFC, 0x20,
-  0x7F, 0xFF, 0x90, 0x00, 0x1E, 0x00, 0x00, 0x00,
-  0x78, 0x10, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0x80,
-  0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00,
-  0x07, 0xC0, 0x00, 0x00, 0x00, 0x08, 0xFF, 0xFF,
-  0xC0, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x04,
-  0x7F, 0xFF, 0x80, 0x00, 0x03, 0xC0, 0x00, 0x10,
-  0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x01, 0x80,
-  0x00, 0x30, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00,
-  0x00, 0x00, 0x00, 0x70, 0x00, 0x01, 0x4F, 0xFF,
-  0x80, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00,
-  0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x80, 0x03, 0xF0,
-  0x00, 0x00, 0x8F, 0xFF, 0x80, 0x00, 0x00, 0x40,
-  0x0F, 0xF0, 0x00, 0x04, 0x1F, 0xFF, 0x80, 0x00,
-  0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x10, 0x1F, 0xFF,
-  0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x40,
-  0xFF, 0xFF, 0x98, 0x00, 0x00, 0xFF, 0xFF, 0xF0,
-  0x00, 0x83, 0xFF, 0xFF, 0x81, 0xE0, 0x01, 0xFF,
-  0xFF, 0xF8, 0x02, 0x07, 0xFF, 0xFF, 0x80, 0x3F,
-  0x07, 0xE0, 0x00, 0x1C, 0x0C, 0x1F, 0xFF, 0xFF,
-  0xF8, 0x03, 0xFF, 0x80, 0x00, 0x1F, 0x78, 0x1F,
-  0xFF, 0xFF, 0xFF, 0x80, 0x7F, 0x00, 0x07, 0x0F,
-  0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0x0C, 0x07,
-  0xFF, 0x83, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0x00, 0x1F, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 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,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22,
+    0x22, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+    0x26, 0x26, 0x25, 0x28, 0x23, 0x22, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x25, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d,
+    0x2d, 0x2e, 0x2c, 0x2b, 0x2a, 0x25, 0x28, 0x22,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x24, 0x2a, 0x2c, 0x2f, 0x2c, 0x30, 0x30, 0x24,
+    0x25, 0x27, 0x2b, 0x2c, 0x2f, 0x31, 0x32, 0x25,
+    0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
+    0x33, 0x34, 0x35, 0x21, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x21, 0x2b, 0x2f, 0x2c,
+    0x30, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
+    0x2d, 0x27, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x31,
+    0x2d, 0x32, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x28, 0x2a, 0x34,
+    0x25, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x23, 0x32, 0x27, 0x21, 0x36,
+    0x2a, 0x2d, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x22, 0x26, 0x2c, 0x35,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x25, 0x2f, 0x37, 0x32, 0x22,
+    0x36, 0x35, 0x31, 0x27, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x22,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x26, 0x38, 0x38, 0x35, 0x25,
+    0x36, 0x21, 0x2d, 0x2b, 0x24, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x24, 0x39, 0x39, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x25, 0x2b, 0x30, 0x28, 0x22,
+    0x36, 0x36, 0x27, 0x34, 0x30, 0x23, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x26, 0x2d, 0x26, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x22, 0x22, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x2d, 0x33, 0x28, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x2b, 0x2c, 0x25, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x36, 0x36,
+    0x36, 0x21, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x21, 0x23, 0x22, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x28, 0x34, 0x27, 0x22, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
+    0x21, 0x21, 0x24, 0x27, 0x21, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x28, 0x27, 0x22, 0x33, 0x24, 0x36,
+    0x36, 0x36, 0x36, 0x22, 0x2f, 0x2a, 0x23, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
+    0x30, 0x3a, 0x38, 0x24, 0x24, 0x36, 0x36, 0x36,
+    0x23, 0x2f, 0x3b, 0x3c, 0x3d, 0x30, 0x25, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2f, 0x32, 0x23, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x23,
+    0x3e, 0x3f, 0x40, 0x3a, 0x22, 0x36, 0x36, 0x21,
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x3e, 0x23, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2f, 0x33, 0x28, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x2b,
+    0x44, 0x40, 0x46, 0x47, 0x35, 0x36, 0x36, 0x26,
+    0x43, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x2e, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x34, 0x36, 0x4d,
+    0x4e, 0x25, 0x2f, 0x46, 0x4a, 0x22, 0x23, 0x32,
+    0x4f, 0x50, 0x21, 0x31, 0x51, 0x52, 0x53, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x21, 0x3a,
+    0x4d, 0x21, 0x31, 0x54, 0x55, 0x28, 0x30, 0x2b,
+    0x4b, 0x4d, 0x36, 0x23, 0x32, 0x50, 0x3f, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x38, 0x23, 0x37,
+    0x55, 0x36, 0x28, 0x3a, 0x56, 0x57, 0x57, 0x58,
+    0x3c, 0x4d, 0x36, 0x36, 0x36, 0x40, 0x40, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x29, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x51, 0x23, 0x35,
+    0x43, 0x25, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e,
+    0x5f, 0x60, 0x61, 0x36, 0x31, 0x47, 0x3b, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x2c, 0x25, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x22,
+    0x40, 0x62, 0x63, 0x5d, 0x64, 0x65, 0x66, 0x67,
+    0x68, 0x69, 0x66, 0x5e, 0x6a, 0x6b, 0x2a, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x33, 0x2e, 0x26, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x2f, 0x23, 0x36,
+    0x6c, 0x63, 0x6d, 0x64, 0x5c, 0x66, 0x69, 0x6e,
+    0x6f, 0x70, 0x71, 0x69, 0x69, 0x72, 0x6c, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x33, 0x34, 0x27, 0x22,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x34, 0x26, 0x73,
+    0x74, 0x75, 0x76, 0x64, 0x65, 0x77, 0x69, 0x78,
+    0x70, 0x71, 0x71, 0x71, 0x72, 0x5f, 0x5e, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x25, 0x38, 0x2a, 0x23,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x33, 0x79,
+    0x63, 0x7a, 0x7b, 0x5c, 0x66, 0x69, 0x6e, 0x7c,
+    0x71, 0x71, 0x69, 0x7d, 0x7e, 0x7a, 0x7f, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x21, 0x51, 0x2b, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x32, 0x24,
+    0x80, 0x81, 0x64, 0x82, 0x77, 0x69, 0x71, 0x71,
+    0x69, 0x83, 0x84, 0x85, 0x7a, 0x85, 0x86, 0x36,
+    0x21, 0x2b, 0x23, 0x36, 0x36, 0x39, 0x2e, 0x26,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x2d, 0x33, 0x21,
+    0x87, 0x88, 0x89, 0x72, 0x67, 0x66, 0x5f, 0x89,
+    0x8a, 0x63, 0x85, 0x8b, 0x8c, 0x8d, 0x41, 0x36,
+    0x36, 0x2d, 0x3a, 0x35, 0x36, 0x24, 0x51, 0x32,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x33, 0x21,
+    0x55, 0x8e, 0x8f, 0x8a, 0x7d, 0x5e, 0x90, 0x7e,
+    0x75, 0x75, 0x90, 0x62, 0x40, 0x3f, 0x49, 0x23,
+    0x36, 0x24, 0x3a, 0x3a, 0x24, 0x36, 0x2e, 0x31,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x28, 0x33, 0x37, 0x25, 0x22,
+    0x3b, 0x50, 0x8e, 0x8f, 0x90, 0x7e, 0x90, 0x63,
+    0x74, 0x91, 0x92, 0x42, 0x93, 0x4b, 0x45, 0x2c,
+    0x36, 0x36, 0x33, 0x39, 0x21, 0x36, 0x22, 0x51,
+    0x33, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x22, 0x27, 0x2e, 0x2e, 0x36, 0x21,
+    0x94, 0x3f, 0x50, 0x95, 0x96, 0x8f, 0x8f, 0x97,
+    0x8e, 0x42, 0x50, 0x43, 0x47, 0x48, 0x48, 0x98,
+    0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39,
+    0x2e, 0x27, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x22, 0x24, 0x2b, 0x38, 0x28, 0x36, 0x32,
+    0x4c, 0x4b, 0x50, 0x50, 0x50, 0x42, 0x42, 0x50,
+    0x50, 0x40, 0x45, 0x99, 0x48, 0x48, 0x48, 0x48,
+    0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x23,
+    0x2f, 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x32, 0x51, 0x32, 0x28, 0x21, 0x98,
+    0x48, 0x47, 0x9a, 0x50, 0x50, 0x50, 0x50, 0x50,
+    0x9a, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x93, 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x2a, 0x2f, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x23, 0x30, 0x2e, 0x2c, 0x36, 0x21, 0x51, 0x9b,
+    0x48, 0x48, 0x52, 0x3f, 0x50, 0x50, 0x40, 0x4b,
+    0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2d, 0x31, 0x27, 0x23, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x27, 0x2c, 0x2d, 0x21, 0x36, 0x28, 0x44, 0x48,
+    0x48, 0x48, 0x48, 0x47, 0x46, 0x4f, 0x47, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x9c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x28, 0x51, 0x39, 0x26, 0x22, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
+    0x35, 0x51, 0x28, 0x36, 0x36, 0x9d, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x4f, 0x28, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x28, 0x38, 0x2b, 0x25, 0x22, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
+    0x51, 0x25, 0x36, 0x36, 0x23, 0x40, 0x9b, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x9b, 0x99, 0x2b, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x30, 0x2f, 0x33, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x23, 0x30, 0x34,
+    0x27, 0x36, 0x36, 0x36, 0x2a, 0x40, 0x47, 0x48,
+    0x48, 0x48, 0x48, 0x9b, 0x99, 0x99, 0x9b, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x47, 0x52,
+    0x46, 0x4f, 0x37, 0x21, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x30, 0x34, 0x2a, 0x23,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x22, 0x25, 0x39, 0x2c,
+    0x36, 0x36, 0x36, 0x21, 0x31, 0x4e, 0x9a, 0x4c,
+    0x47, 0x9b, 0x9b, 0x52, 0x46, 0x4f, 0x52, 0x9b,
+    0x9b, 0x9b, 0x47, 0x4f, 0x45, 0x9a, 0x93, 0x93,
+    0x3f, 0x93, 0x98, 0x28, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, 0x26,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x28,
+    0x36, 0x36, 0x36, 0x22, 0x38, 0x98, 0x44, 0x99,
+    0x9b, 0x48, 0x48, 0x9b, 0x4c, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x47, 0x52, 0x46, 0x43, 0x93,
+    0x40, 0x40, 0x43, 0x53, 0x21, 0x23, 0x33, 0x23,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x2f, 0x32,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x24, 0x2b, 0x31, 0x36,
+    0x36, 0x22, 0x36, 0x24, 0x9e, 0x4f, 0x9b, 0x48,
+    0x48, 0x48, 0x48, 0x9b, 0x99, 0x9f, 0x52, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x47,
+    0x4f, 0x9a, 0x3f, 0x46, 0x38, 0x36, 0x21, 0x30,
+    0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c,
+    0x25, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2e, 0x33, 0x36,
+    0x25, 0x25, 0x36, 0x4d, 0x52, 0x48, 0x48, 0x48,
+    0x47, 0x9f, 0x48, 0x48, 0x48, 0xa0, 0xa1, 0xa2,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x47, 0x44, 0x93, 0x43, 0x23, 0x36, 0x36,
+    0x26, 0x24, 0x36, 0x36, 0x36, 0x36, 0x28, 0x2f,
+    0x2a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x51, 0x24, 0x36,
+    0x2a, 0x36, 0x28, 0x44, 0x48, 0x48, 0x48, 0x48,
+    0xa3, 0xa4, 0x48, 0x48, 0x9f, 0xa5, 0xa6, 0x9f,
+    0x48, 0x48, 0x48, 0xa2, 0xa7, 0x47, 0x48, 0x48,
+    0x48, 0x48, 0x9b, 0x4b, 0x44, 0x37, 0x36, 0x23,
+    0x28, 0x30, 0x22, 0x36, 0x36, 0x36, 0x36, 0x2d,
+    0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x28, 0x2b, 0x34, 0x36, 0x25,
+    0x24, 0x36, 0x4a, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0xa8, 0xa1, 0x48, 0x48, 0x9f, 0xa9, 0xa6, 0x9f,
+    0x48, 0x48, 0xaa, 0xa1, 0xa5, 0x9f, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x9b, 0x52, 0x3f, 0x21, 0x30,
+    0x35, 0x25, 0x30, 0x36, 0x36, 0x36, 0x36, 0x32,
+    0x2d, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x22, 0x26, 0x2e, 0x35, 0x36, 0x2a,
+    0x36, 0x24, 0x4f, 0x48, 0x52, 0x52, 0x48, 0x48,
+    0xab, 0xac, 0xa0, 0x48, 0xad, 0xa6, 0xa6, 0x9f,
+    0x48, 0xa2, 0xa9, 0xa6, 0xa2, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x47, 0x32, 0x30,
+    0x2a, 0x23, 0x30, 0x23, 0x36, 0x36, 0x36, 0x21,
+    0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x2a, 0x51, 0x28, 0x28, 0x25,
+    0x36, 0x3a, 0x48, 0x48, 0xae, 0xaf, 0x48, 0x48,
+    0xad, 0xac, 0xa1, 0x9f, 0xa2, 0xa9, 0xa9, 0xa2,
+    0x48, 0xab, 0x78, 0xa7, 0x48, 0x48, 0x48, 0x48,
+    0x9f, 0x48, 0x48, 0x48, 0x48, 0x48, 0x38, 0x21,
+    0x36, 0x36, 0x22, 0x27, 0x36, 0x36, 0x36, 0x36,
+    0x2e, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x22, 0x25, 0x2c, 0x34, 0x36, 0x30, 0x21,
+    0x23, 0x43, 0x48, 0x48, 0xb0, 0xb1, 0xb2, 0x9f,
+    0x48, 0xb3, 0xa5, 0xb3, 0xab, 0xa9, 0xa9, 0xb3,
+    0xb4, 0xa9, 0xb5, 0xb0, 0x48, 0x48, 0xa0, 0xa5,
+    0xa1, 0xad, 0x48, 0x48, 0x48, 0x48, 0x94, 0x36,
+    0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36,
+    0x2a, 0x2e, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x2a, 0x51, 0x25, 0x21, 0x2a, 0x36,
+    0x2e, 0x9b, 0x48, 0x48, 0x48, 0xb6, 0xb7, 0xa4,
+    0xa2, 0xa7, 0xb5, 0x78, 0x6f, 0x6f, 0x6e, 0x6f,
+    0xa9, 0xb5, 0xab, 0x48, 0x9f, 0xab, 0xa9, 0xa1,
+    0xaa, 0x48, 0x48, 0x48, 0x48, 0x48, 0x98, 0x36,
+    0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36,
+    0x22, 0x2f, 0x30, 0x22, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x22, 0x25, 0x2c, 0x34, 0x36, 0x24, 0x28, 0x36,
+    0x54, 0x48, 0x48, 0x48, 0x48, 0xa2, 0xa8, 0xa1,
+    0xa5, 0xa6, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f,
+    0x6f, 0x78, 0xa5, 0xa0, 0xa0, 0x78, 0xa6, 0xa2,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36,
+    0x36, 0x36, 0x36, 0x30, 0x36, 0x36, 0x36, 0x36,
+    0x21, 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x28, 0x32, 0x2f, 0x28, 0x36, 0x27, 0x22, 0x21,
+    0x43, 0x48, 0x4b, 0xa2, 0x9f, 0x48, 0xa2, 0xa1,
+    0xb8, 0x6e, 0x6e, 0xb5, 0x78, 0x6f, 0x78, 0x78,
+    0x6e, 0x6f, 0x78, 0xb5, 0xa6, 0xa1, 0xa0, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4b, 0x21,
+    0x36, 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x25, 0x2c, 0x39, 0x36, 0x36, 0x30, 0x22, 0x25,
+    0x52, 0x48, 0xa3, 0xb1, 0xb6, 0xb3, 0xaa, 0xac,
+    0x68, 0x68, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
+    0x78, 0x6f, 0x6f, 0xb5, 0xa6, 0xb4, 0x48, 0x9f,
+    0xb4, 0xb4, 0xa2, 0x9f, 0x48, 0x48, 0x4f, 0x21,
+    0x36, 0x36, 0x22, 0x26, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x30, 0x2d, 0x21, 0x36, 0x36, 0x32, 0x23, 0x2a,
+    0x47, 0x48, 0xa2, 0xb6, 0xaf, 0xb9, 0xba, 0x68,
+    0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x78,
+    0x6f, 0x6f, 0xa6, 0x6f, 0xb5, 0xa0, 0xaa, 0xa6,
+    0xa6, 0xa9, 0xb2, 0xb3, 0x48, 0x48, 0x4c, 0x22,
+    0x36, 0x36, 0x24, 0x23, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0x2e, 0x36, 0x36, 0x23, 0x31, 0x27, 0x39,
+    0x9b, 0x48, 0x48, 0x48, 0xb0, 0xb0, 0xba, 0xb8,
+    0x68, 0x68, 0x69, 0x78, 0x6f, 0xb5, 0x6f, 0xb5,
+    0x78, 0x78, 0x78, 0x78, 0x78, 0xa5, 0xbb, 0xa9,
+    0xa5, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x23,
+    0x36, 0x36, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x2b, 0x39, 0x36, 0x36, 0x36, 0x26, 0x32, 0x31,
+    0x9b, 0x48, 0x48, 0x48, 0x48, 0x9f, 0xac, 0x68,
+    0xbc, 0x6e, 0x6e, 0x6e, 0xb5, 0x6f, 0x6e, 0x6f,
+    0x6f, 0x78, 0x78, 0xb5, 0xb5, 0xa5, 0x9f, 0x9f,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x46, 0x22,
+    0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x35, 0x39, 0x36, 0x36, 0x36, 0x36, 0x26, 0x2d,
+    0x9b, 0x48, 0x48, 0xb0, 0xaa, 0xb3, 0xbd, 0xb8,
+    0xb8, 0x68, 0x6e, 0x6e, 0xb5, 0x6f, 0x78, 0x6e,
+    0x78, 0x6f, 0x78, 0x78, 0xb5, 0xa9, 0xa2, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36,
+    0x24, 0x27, 0xbe, 0x24, 0x25, 0x28, 0x21, 0x36,
+    0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x25,
+    0x39, 0x4d, 0xbf, 0x84, 0x81, 0x57, 0x21, 0x39,
+    0x52, 0x48, 0x48, 0x62, 0xb1, 0xc0, 0xc1, 0xc1,
+    0xb8, 0xb8, 0x68, 0xbc, 0x6e, 0x6e, 0x6e, 0x78,
+    0x78, 0x78, 0x78, 0x6e, 0x78, 0xa9, 0xa0, 0xab,
+    0xb3, 0xa2, 0x48, 0x48, 0x48, 0x48, 0x53, 0x28,
+    0x23, 0x36, 0x36, 0x36, 0x21, 0x28, 0x2c, 0x30,
+    0x21, 0x38, 0x33, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x28, 0x30,
+    0x2d, 0xc2, 0x7a, 0xc3, 0xc4, 0xc4, 0x7f, 0x22,
+    0x51, 0x52, 0x48, 0x48, 0xb0, 0xaa, 0xa8, 0xbd,
+    0x68, 0xb8, 0xb8, 0x68, 0x68, 0x6e, 0x6e, 0x6f,
+    0x6e, 0x6e, 0xb5, 0x6e, 0x78, 0xab, 0xab, 0xb5,
+    0x78, 0xa6, 0xb3, 0xc5, 0xac, 0xac, 0xc6, 0x61,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x30, 0x32,
+    0x25, 0x4d, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x24, 0x26, 0x30, 0x33, 0x31,
+    0x4d, 0x91, 0x5b, 0xc3, 0xc4, 0xc4, 0xc4, 0x5a,
+    0x21, 0x2e, 0x46, 0x48, 0x48, 0x48, 0xb0, 0x64,
+    0xc1, 0xb8, 0xb8, 0xb8, 0x68, 0x71, 0x6e, 0x6e,
+    0x6f, 0x71, 0x6f, 0x6f, 0xa6, 0xa0, 0x9f, 0xb4,
+    0xb4, 0xa0, 0xa1, 0xb7, 0xc7, 0x69, 0x66, 0xc8,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x26, 0x25,
+    0x83, 0xc9, 0x2c, 0x25, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x30, 0x35, 0x2d, 0x2f, 0x37, 0x4a,
+    0x60, 0x85, 0xca, 0xcb, 0xc4, 0xc4, 0xc4, 0x82,
+    0x86, 0x36, 0x32, 0x3f, 0xa2, 0xa4, 0xa8, 0xa9,
+    0xb8, 0xb8, 0xb8, 0xb8, 0x68, 0x6e, 0x6e, 0x6e,
+    0x6e, 0x71, 0x6f, 0x71, 0xa6, 0xb4, 0x9f, 0x9f,
+    0x48, 0x48, 0x48, 0xcc, 0xc3, 0xc7, 0xcd, 0xce,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x57,
+    0x77, 0x66, 0x34, 0x27, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x23, 0x30, 0x31, 0xcf, 0x91, 0x7e, 0x90, 0x90,
+    0x8b, 0x5b, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0x5d, 0xd0, 0x36, 0x24, 0xd1, 0xb1, 0xaf, 0xaa,
+    0xba, 0xb8, 0x68, 0x68, 0x68, 0x71, 0x6e, 0x6e,
+    0x6e, 0x6f, 0x6e, 0x78, 0xa1, 0xa9, 0xa1, 0xb0,
+    0x9f, 0x9b, 0x99, 0xcc, 0x64, 0x5c, 0x8b, 0xd0,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x73, 0x5d,
+    0x82, 0x5c, 0xd2, 0x2a, 0x23, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x24, 0x2b, 0xcf, 0x8b, 0x5b, 0x76, 0x5b, 0x5b,
+    0x7b, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc7, 0x5e, 0x22, 0x36, 0x21, 0x3a, 0x99, 0x48,
+    0xa2, 0xa8, 0xb7, 0xc1, 0xb8, 0x68, 0x68, 0xbc,
+    0x68, 0x6e, 0xb5, 0xb4, 0xb4, 0xab, 0xb5, 0xa1,
+    0xb0, 0x4f, 0x3f, 0xd3, 0x7b, 0x7b, 0x85, 0x80,
+    0xbe, 0x36, 0x36, 0x36, 0x21, 0xd4, 0x7e, 0x7b,
+    0x64, 0x64, 0xd5, 0x35, 0x24, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x31, 0xd6, 0x5b, 0x64, 0xc3, 0xc3, 0xcb,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0x66, 0xd7, 0x36, 0x36, 0x36, 0x2c, 0x4b,
+    0xd8, 0xd9, 0xb3, 0xa8, 0xbd, 0xbd, 0xbd, 0xbd,
+    0xa9, 0xab, 0xb3, 0xa5, 0xa2, 0x9f, 0xa2, 0xa1,
+    0x6a, 0x9a, 0x3f, 0xda, 0x76, 0x76, 0x7a, 0x63,
+    0xdb, 0xdc, 0x86, 0xdc, 0xdd, 0x90, 0x5b, 0x64,
+    0xc3, 0xc3, 0xde, 0x2d, 0x27, 0x23, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x26, 0x2d, 0x91, 0x5b, 0x64, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc7, 0x83, 0xce, 0x36, 0x36, 0x36, 0x30,
+    0xb1, 0xd9, 0x48, 0xa1, 0xb2, 0xb0, 0xb0, 0xb3,
+    0xa2, 0x48, 0xa7, 0xbd, 0xa9, 0xa2, 0x48, 0x9f,
+    0xaa, 0x9a, 0x3f, 0xb1, 0x5b, 0x7b, 0xdf, 0x85,
+    0x7e, 0x90, 0x63, 0x90, 0x85, 0x5b, 0xc3, 0xc4,
+    0xc4, 0xcb, 0x5d, 0xd5, 0x39, 0x26, 0x23, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2d, 0xe0, 0xdf, 0x64, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc7, 0x88, 0x36, 0x36, 0x36, 0x36,
+    0x2d, 0x9b, 0x48, 0xb9, 0xaf, 0xa2, 0xa2, 0xb9,
+    0xa8, 0x9f, 0x48, 0xa7, 0xb7, 0xd9, 0x48, 0x48,
+    0x9b, 0x45, 0x3f, 0xe1, 0x6d, 0x7b, 0xca, 0xdf,
+    0x7a, 0x8b, 0x8b, 0x7a, 0x5b, 0x64, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc3, 0xe2, 0x37, 0x35, 0x26, 0x23,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2e, 0xe0, 0x7a, 0x7b, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc7, 0x72, 0x73, 0x36, 0x36, 0x36,
+    0x24, 0x52, 0x48, 0xa3, 0xaf, 0x9f, 0x48, 0xb6,
+    0xaf, 0xa2, 0x48, 0x9f, 0xe3, 0xd8, 0x48, 0x48,
+    0x48, 0x46, 0x42, 0xd6, 0x7a, 0x7b, 0x64, 0x7b,
+    0x76, 0x5b, 0x5b, 0x76, 0x7b, 0xc3, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xcb, 0x64, 0xe2, 0x4d, 0x2c, 0x27,
+    0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x25, 0x31, 0xe4, 0x8b, 0x7b, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc7, 0x89, 0xbe, 0x36, 0x36,
+    0x32, 0x47, 0x48, 0x4f, 0xa0, 0x48, 0x48, 0xe3,
+    0x92, 0x9f, 0x48, 0x9f, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x4b, 0x2f, 0x8f, 0x7a, 0x7b, 0xc3, 0xcb,
+    0xc3, 0x64, 0x64, 0xc3, 0xc3, 0xcb, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x5d, 0xe5, 0x2c,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x25, 0x31, 0xe4, 0x85, 0x7b, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0x66, 0x57, 0x27, 0x4d,
+    0x4b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x99, 0x34, 0xbe, 0xdb, 0x7a, 0x7b, 0xc3, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0xe4,
+    0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2d, 0xe4, 0x85, 0x7b, 0xcb, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc7, 0x5f, 0x92, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x44,
+    0x35, 0x36, 0xce, 0xdd, 0x7a, 0x7b, 0xcb, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0xc3, 0xe1,
+    0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x30, 0x2f, 0xd6, 0x8b, 0x7b, 0xcb, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0x66, 0x89, 0x45,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x4e, 0x25,
+    0x36, 0x36, 0x61, 0xdb, 0x6d, 0x64, 0xcb, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x7b, 0xdf, 0xe5,
+    0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0xe6, 0x63, 0xdf, 0xc3, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x72, 0x81, 0xe7,
+    0x46, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x3f, 0x2c, 0x36, 0x36,
+    0x36, 0x36, 0xe8, 0x8f, 0x6d, 0x64, 0xcb, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc3, 0xca, 0x8b, 0xcf, 0x2c,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x35, 0x96, 0x75, 0xca, 0xc3, 0xcb, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x7b, 0x81, 0xdb,
+    0x73, 0x3b, 0x44, 0x9b, 0x48, 0x48, 0x48, 0x9b,
+    0x99, 0x43, 0x94, 0x2c, 0x21, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x73, 0xdb, 0x7a, 0x7b, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0x64, 0x76, 0x7a, 0x91, 0xd5, 0x31, 0x30,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x39, 0x97, 0x75, 0xdf, 0x7b, 0x64, 0xc3, 0xc3,
+    0xcb, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0x7b, 0x7a, 0xe9,
+    0xea, 0x36, 0x21, 0x26, 0x2b, 0x39, 0x33, 0x30,
+    0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xea, 0xdd, 0x8b, 0x7b, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x64, 0x64,
+    0x76, 0x85, 0xe0, 0xd5, 0x34, 0x2b, 0x27, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0xeb, 0x63, 0x7e, 0x7a, 0x6d, 0xdf, 0x5b,
+    0x76, 0x7b, 0x64, 0x64, 0xc3, 0xcb, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x76, 0x85, 0xdb,
+    0x79, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xec, 0xdd, 0x75, 0x76, 0xc3, 0xc4,
+    0xc4, 0xc4, 0xcb, 0xc3, 0x64, 0x76, 0xdf, 0x8b,
+    0xd6, 0xd5, 0x2f, 0x35, 0x30, 0x24, 0x22, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x27, 0x31, 0xed, 0xeb, 0xdd, 0x74, 0x63, 0x90,
+    0x7e, 0x75, 0x8b, 0x6d, 0xdf, 0x76, 0x64, 0xc3,
+    0xcb, 0xcb, 0xcb, 0xcb, 0x64, 0x7a, 0x84, 0xee,
+    0x79, 0xbe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xea, 0xee, 0x63, 0x6d, 0x7b, 0x64,
+    0xcb, 0xc3, 0x64, 0x7b, 0xdf, 0x75, 0x63, 0x96,
+    0x38, 0x39, 0x2a, 0x24, 0x23, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x28, 0x27, 0x35, 0x2d, 0x41, 0xd5, 0xe7, 0x8f,
+    0xdb, 0xdd, 0xe9, 0x74, 0x84, 0x90, 0x85, 0x6d,
+    0x5b, 0x7b, 0x7b, 0xca, 0x6d, 0x90, 0xdb, 0xef,
+    0xec, 0x22, 0x36, 0x36, 0x28, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x25, 0x36,
+    0x36, 0x21, 0xd4, 0x80, 0xe9, 0x7e, 0x6d, 0x76,
+    0xca, 0x76, 0x6d, 0x85, 0x63, 0xdb, 0xd5, 0x34,
+    0x33, 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x24, 0x27, 0x2a, 0x35, 0x2e, 0x2f,
+    0x41, 0xf0, 0xf1, 0x6c, 0x80, 0xee, 0xdb, 0x74,
+    0x84, 0x90, 0x75, 0x7e, 0x74, 0x8f, 0xef, 0x79,
+    0xe8, 0x2b, 0x9d, 0x41, 0x2f, 0x34, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x34, 0x2f, 0x38,
+    0x4d, 0x37, 0xf2, 0xf3, 0x8f, 0x74, 0x63, 0x7e,
+    0x75, 0x7e, 0x63, 0xe9, 0x88, 0xe6, 0x31, 0x2a,
+    0x24, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x22, 0x23, 0x24, 0x26, 0x30,
+    0x33, 0x39, 0x2e, 0x51, 0x41, 0xd2, 0x6c, 0xf3,
+    0x80, 0xee, 0xee, 0xee, 0xf4, 0xf3, 0xd7, 0xf5,
+    0x41, 0x34, 0x35, 0x32, 0x30, 0x27, 0x27, 0x27,
+    0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x2a,
+    0x2b, 0x34, 0xf6, 0xec, 0xf7, 0x8f, 0xdd, 0xe9,
+    0xe9, 0xdd, 0xee, 0x6c, 0x41, 0x39, 0x27, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22,
+    0x28, 0x24, 0x26, 0x2a, 0x33, 0x2c, 0x2f, 0x41,
+    0xf8, 0xd7, 0x79, 0x79, 0x79, 0xec, 0xf9, 0x51,
+    0x39, 0x30, 0x24, 0x23, 0x22, 0x22, 0x22, 0x22,
+    0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23,
+    0x24, 0x2a, 0x31, 0xfa, 0xea, 0x79, 0xf3, 0x80,
+    0xf7, 0xdc, 0xfb, 0x2f, 0x35, 0x26, 0x23, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x22, 0x23, 0x28, 0x25, 0x30, 0x2b,
+    0x31, 0x2f, 0xf6, 0xfa, 0xfa, 0x2f, 0x2e, 0x33,
+    0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x27, 0x35, 0x34, 0xfa, 0xfa, 0xfa,
+    0xfc, 0xf6, 0x2e, 0x33, 0x25, 0x23, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x23, 0x28,
+    0x26, 0x30, 0x32, 0x2b, 0x33, 0x2a, 0x26, 0x28,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x25, 0x30, 0x33, 0x35, 0x35,
+    0x2b, 0x2a, 0x26, 0x28, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x21, 0x22, 0x23, 0x28, 0x28, 0x23, 0x22, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x23, 0x28, 0x24, 0x24,
+    0x28, 0x23, 0x22, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 };
 
-unsigned char linux_logo16_red[1];
-unsigned char linux_logo16_green[1];
-unsigned char linux_logo16_blue[1];
 unsigned char linux_logo16[1];
 
-#else
+#endif /* INCLUDE_LINUX_LOGO_DATA */
 
-/* prototypes only */
-extern unsigned char linux_logo_red[];
-extern unsigned char linux_logo_green[];
-extern unsigned char linux_logo_blue[];
-extern unsigned char linux_logo[];
-extern unsigned char linux_logo_bw[];
-extern unsigned char linux_logo16_red[];
-extern unsigned char linux_logo16_green[];
-extern unsigned char linux_logo16_blue[];
-extern unsigned char linux_logo16[];
+#include <linux/linux_logo.h>
 
-#endif
diff -u --recursive --new-file v2.4.5/linux/include/asm-sparc/softirq.h linux/include/asm-sparc/softirq.h
--- v2.4.5/linux/include/asm-sparc/softirq.h	Sun Aug  6 12:42:21 2000
+++ linux/include/asm-sparc/softirq.h	Tue Jun 12 11:08:46 2001
@@ -14,8 +14,21 @@
 #include <asm/hardirq.h>
 
 #define local_bh_disable()	(local_bh_count(smp_processor_id())++)
-#define local_bh_enable()	(local_bh_count(smp_processor_id())--)
-
+#define __local_bh_enable()	(local_bh_count(smp_processor_id())--)
+#define local_bh_enable()			  \
+do { if (!--local_bh_count(smp_processor_id()) && \
+	 softirq_pending(smp_processor_id())) {   \
+		do_softirq();			  \
+		__sti();			  \
+     }						  \
+} while (0)
+#define __cpu_raise_softirq(cpu, nr)	(softirq_pending(cpu) |= (1<<nr))
+#define raise_softirq(nr)				\
+do {	unsigned long flags;				\
+	local_irq_save(flags);				\
+	__cpu_raise_softirq(smp_processor_id(), nr);	\
+	local_irq_restore(flags);			\
+} while (0)
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
 
 #endif	/* __SPARC_SOFTIRQ_H */
diff -u --recursive --new-file v2.4.5/linux/include/asm-sparc/termios.h linux/include/asm-sparc/termios.h
--- v2.4.5/linux/include/asm-sparc/termios.h	Fri Feb  9 11:37:03 2001
+++ linux/include/asm-sparc/termios.h	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: termios.h,v 1.31 2001/02/05 05:54:29 davem Exp $ */
+/* $Id: termios.h,v 1.32 2001/06/01 08:12:11 davem Exp $ */
 #ifndef _SPARC_TERMIOS_H
 #define _SPARC_TERMIOS_H
 
@@ -70,6 +70,7 @@
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14	/* synchronous PPP */
+#define N_HCI		15  /* Bluetooth HCI UART */
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-sparc64/audioio.h linux/include/asm-sparc64/audioio.h
--- v2.4.5/linux/include/asm-sparc64/audioio.h	Tue Oct 10 10:33:52 2000
+++ linux/include/asm-sparc64/audioio.h	Mon Jun 11 19:15:27 2001
@@ -428,8 +428,6 @@
 extern int unregister_sparcaudio_driver(struct sparcaudio_driver *, int);
 extern void sparcaudio_output_done(struct sparcaudio_driver *, int);
 extern void sparcaudio_input_done(struct sparcaudio_driver *, int);
-extern int amd7930_init(void);
-extern int cs4231_init(void);
 
 #endif
 
diff -u --recursive --new-file v2.4.5/linux/include/asm-sparc64/auxio.h linux/include/asm-sparc64/auxio.h
--- v2.4.5/linux/include/asm-sparc64/auxio.h	Mon Dec 20 22:05:52 1999
+++ linux/include/asm-sparc64/auxio.h	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: auxio.h,v 1.2 1999/09/21 14:39:25 davem Exp $
+/* $Id: auxio.h,v 1.3 2001/06/05 08:16:34 davem Exp $
  * auxio.h:  Definitions and code for the Auxiliary I/O register.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,7 @@
 #define _SPARC64_AUXIO_H
 
 #include <asm/system.h>
+#include <asm/io.h>
 
 /* FIXME: All of this should be checked for sun4u. It has /sbus/auxio, but
    I don't know whether it is the same and don't have a floppy */
diff -u --recursive --new-file v2.4.5/linux/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h
--- v2.4.5/linux/include/asm-sparc64/bitops.h	Thu Apr 26 22:17:26 2001
+++ linux/include/asm-sparc64/bitops.h	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.33 2001/04/24 01:09:12 davem Exp $
+/* $Id: bitops.h,v 1.34 2001/05/27 00:09:29 davem Exp $
  * bitops.h: Bit string operations on the V9.
  *
  * Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -20,13 +20,46 @@
 #define clear_bit(nr,addr)		((void)___test_and_clear_bit(nr,addr))
 #define change_bit(nr,addr)		((void)___test_and_change_bit(nr,addr))
 
-/* "non-atomic" versions, nothing special for now... */
-#define __set_bit(X,Y)		set_bit(X,Y)
-#define __clear_bit(X,Y)	clear_bit(X,Y)
-#define __change_bit(X,Y)	change_bit(X,Y)
-#define __test_and_set_bit(X,Y)		test_and_set_bit(X,Y)
-#define __test_and_clear_bit(X,Y)	test_and_clear_bit(X,Y)
-#define __test_and_change_bit(X,Y)	test_and_change_bit(X,Y)
+/* "non-atomic" versions... */
+#define __set_bit(X,Y)					\
+do {	unsigned long __nr = (X);			\
+	long *__m = ((long *) (Y)) + (__nr >> 6);	\
+	*__m |= (1UL << (__nr & 63));			\
+} while (0)
+#define __clear_bit(X,Y)				\
+do {	unsigned long __nr = (X);			\
+	long *__m = ((long *) (Y)) + (__nr >> 6);	\
+	*__m &= ~(1UL << (__nr & 63));			\
+} while (0)
+#define __change_bit(X,Y)				\
+do {	unsigned long __nr = (X);			\
+	long *__m = ((long *) (Y)) + (__nr >> 6);	\
+	*__m ^= (1UL << (__nr & 63));			\
+} while (0)
+#define __test_and_set_bit(X,Y)				\
+({	unsigned long __nr = (X);			\
+	long *__m = ((long *) (Y)) + (__nr >> 6);	\
+	long __old = *__m;				\
+	long __mask = (1UL << (__nr & 63));		\
+	*__m = (__old | __mask);			\
+	((__old & __mask) != 0);			\
+})
+#define __test_and_clear_bit(X,Y)			\
+({	unsigned long __nr = (X);			\
+	long *__m = ((long *) (Y)) + (__nr >> 6);	\
+	long __old = *__m;				\
+	long __mask = (1UL << (__nr & 63));		\
+	*__m = (__old & ~__mask);			\
+	((__old & __mask) != 0);			\
+})
+#define __test_and_change_bit(X,Y)			\
+({	unsigned long __nr = (X);			\
+	long *__m = ((long *) (Y)) + (__nr >> 6);	\
+	long __old = *__m;				\
+	long __mask = (1UL << (__nr & 63));		\
+	*__m = (__old ^ __mask);			\
+	((__old & __mask) != 0);			\
+})
 
 #define smp_mb__before_clear_bit()	do { } while(0)
 #define smp_mb__after_clear_bit()	do { } while(0)
diff -u --recursive --new-file v2.4.5/linux/include/asm-sparc64/hardirq.h linux/include/asm-sparc64/hardirq.h
--- v2.4.5/linux/include/asm-sparc64/hardirq.h	Wed Aug 23 09:30:13 2000
+++ linux/include/asm-sparc64/hardirq.h	Tue Jun 12 11:08:46 2001
@@ -13,8 +13,8 @@
 
 /* entry.S is sensitive to the offsets of these fields */
 typedef struct {
-	unsigned int __softirq_active;
-	unsigned int __softirq_mask;
+	unsigned int __softirq_pending;
+	unsigned int __unused_1;
 #ifndef CONFIG_SMP
 	unsigned int __local_irq_count;
 #else
diff -u --recursive --new-file v2.4.5/linux/include/asm-sparc64/linux_logo.h linux/include/asm-sparc64/linux_logo.h
--- v2.4.5/linux/include/asm-sparc64/linux_logo.h	Tue Aug  4 16:03:35 1998
+++ linux/include/asm-sparc64/linux_logo.h	Tue Jun 12 11:08:46 2001
@@ -1,4 +1,4 @@
-/* $Id: linux_logo.h,v 1.6 1998/07/30 16:30:48 jj Exp $
+/* $Id: linux_logo.h,v 1.7 2001/06/08 23:01:58 davem Exp $
  * include/asm-sparc64/linux_logo.h: This is a linux logo
  *                                   to be displayed on boot.
  *
@@ -23,1025 +23,912 @@
 
 #define linux_logo_banner "Linux/UltraSPARC version " UTS_RELEASE
 
-#define LINUX_LOGO_COLORS 219
+#define __HAVE_ARCH_LINUX_LOGO
+#define __HAVE_ARCH_LINUX_LOGO16
+
+#define LINUX_LOGO_COLORS	221
 
 #ifdef INCLUDE_LINUX_LOGO_DATA
 
 unsigned char linux_logo_red[] __initdata = {
-  0x03, 0x9E, 0xEC, 0xEE, 0xC4, 0xDA, 0x50, 0xC9,
-  0xC5, 0xED, 0x65, 0xE3, 0xE3, 0xF4, 0x24, 0xA4,
-  0xEC, 0xEE, 0x94, 0xE5, 0xE3, 0x6A, 0xA6, 0xC4,
-  0xDC, 0xE5, 0x13, 0xF3, 0xD1, 0xFD, 0xE2, 0xDB,
-  0xA0, 0xC2, 0xEC, 0xB8, 0xC2, 0xD5, 0xF2, 0xF4,
-  0xC5, 0x3E, 0xF1, 0x1B, 0x55, 0xF5, 0xCF, 0xF7,
-  0xA9, 0xB4, 0xEB, 0x6C, 0x0A, 0x74, 0xB4, 0xF7,
-  0xF0, 0xF5, 0xD4, 0xF2, 0xCE, 0xF5, 0xC7, 0x26,
-  0x5B, 0xF4, 0xBC, 0x7F, 0xAB, 0x82, 0x94, 0xE5,
-  0xFC, 0x3A, 0xF2, 0xFD, 0xF0, 0x1C, 0xEF, 0xD4,
-  0xF3, 0x0F, 0xED, 0xF7, 0xC9, 0x49, 0xC3, 0xBA,
-  0xC8, 0xD4, 0xE7, 0xF3, 0xF5, 0xA7, 0xEC, 0xF9,
-  0xFA, 0x0A, 0xF5, 0xCF, 0xFC, 0xEA, 0xE1, 0xA6,
-  0xD6, 0xBC, 0xF8, 0xF7, 0xB4, 0xEB, 0xDC, 0x84,
-  0xCE, 0xBA, 0x45, 0xD6, 0x86, 0x50, 0x96, 0xC6,
-  0x8C, 0x6E, 0xE8, 0x60, 0x3C, 0x70, 0xF0, 0x93,
-  0x7C, 0xDA, 0xDA, 0x9C, 0xBA, 0x6D, 0x4D, 0x2B,
-  0x2F, 0x8B, 0xE0, 0xCC, 0xDA, 0x5C, 0x3D, 0xEE,
-  0xDB, 0x46, 0xAC, 0x96, 0xCE, 0xD1, 0xE3, 0xF1,
-  0x96, 0x7A, 0x80, 0xB2, 0xBA, 0xB6, 0xD2, 0x1E,
-  0x7E, 0xAA, 0xC4, 0xF0, 0x96, 0x65, 0x9E, 0xC2,
-  0xAA, 0xF5, 0xF2, 0xE9, 0xE6, 0xD1, 0x35, 0xC7,
-  0xF6, 0xB6, 0xE8, 0x82, 0xBE, 0xC2, 0xF2, 0x9E,
-  0xC7, 0xB4, 0x0F, 0xF7, 0xE8, 0xD8, 0xCC, 0x9C,
-  0xD8, 0xD8, 0xA0, 0xEA, 0xC6, 0xA8, 0xE0, 0xEC,
-  0xD1, 0xF7, 0xF4, 0xFC, 0x75, 0xBD, 0xDC, 0xDD,
-  0xCC, 0xE1, 0xFA, 0xEE, 0xAA, 0xEC, 0xF2, 0xB8,
-  0xE2, 0xCD, 0x87
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65,
+    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+    0xc3, 0x65, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x76, 0x79,
+    0x62, 0x36, 0x9a, 0xe2, 0xec, 0xe1, 0xb8, 0xd7,
+    0xaf, 0x25, 0xbc, 0xc0, 0xef, 0xea, 0xe8, 0xe8,
+    0xf5, 0xf1, 0xda, 0xd3, 0x79, 0xdb, 0xf4, 0xf6,
+    0xf6, 0xf6, 0xe2, 0x3d, 0xb4, 0xce, 0xe6, 0xee,
+    0xf6, 0x68, 0xd8, 0xec, 0xf5, 0xc6, 0xc8, 0x9c,
+    0x89, 0xd2, 0xee, 0xcb, 0xb9, 0xd2, 0x66, 0x5e,
+    0x8b, 0xbe, 0xa8, 0xd5, 0xca, 0xb6, 0xae, 0x9c,
+    0xc5, 0xbe, 0xbe, 0xca, 0x90, 0xb2, 0x9a, 0xa8,
+    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xfe,
+    0xf6, 0xec, 0xfe, 0xd2, 0xea, 0xf5, 0xf2, 0xf2,
+    0xe9, 0xee, 0xf6, 0xf2, 0xee, 0xf6, 0xda, 0xd4,
+    0xfa, 0xca, 0xf2, 0xf6, 0xfe, 0xf2, 0xda, 0xe4,
+    0xf6, 0xdd, 0xf2, 0xee, 0xfa, 0xf0, 0x12, 0x4a,
+    0xd6, 0xf2, 0x8e, 0xf2, 0xf6, 0xf6, 0xb5, 0xf1,
+    0x26, 0x9a, 0xea, 0xf6, 0xe0, 0xd2, 0x16, 0x9a,
+    0x2e, 0xd2, 0x70, 0xd6, 0x46, 0x7c, 0xb4, 0x62,
+    0xda, 0xee, 0xd6, 0xa3, 0x74, 0xa7, 0xa2, 0xe0,
+    0xae, 0xbe, 0xce, 0xe2, 0xa3, 0x8e, 0x6d, 0x8e,
+    0x32, 0xaf, 0x50, 0x9e, 0x5b, 0x8a, 0x98, 0x82,
+    0x7a, 0x82, 0x56, 0x7c, 0x8a, 0x56, 0x5e, 0x86,
+    0x6a, 0x52, 0x59, 0x64, 0x5e,
 };
 
 unsigned char linux_logo_green[] __initdata = {
-  0x03, 0x88, 0xC4, 0xE2, 0x85, 0xC2, 0x44, 0xA3,
-  0xA9, 0xD3, 0x65, 0xA6, 0xC5, 0xF3, 0x24, 0xA4,
-  0xB4, 0xD6, 0x63, 0xD5, 0xB7, 0x44, 0x86, 0x94,
-  0xC2, 0xE4, 0x14, 0xB6, 0xD2, 0xFB, 0xD4, 0xB2,
-  0x73, 0x96, 0xDB, 0x92, 0xC2, 0x95, 0xC2, 0xDA,
-  0xA4, 0x36, 0xD4, 0x0E, 0x55, 0xF4, 0xC4, 0xE9,
-  0x75, 0xB4, 0xBC, 0x52, 0x0A, 0x74, 0x84, 0xEB,
-  0xDC, 0xDA, 0xA2, 0xD6, 0x9B, 0xBD, 0xB7, 0x12,
-  0x44, 0xCA, 0x8C, 0x65, 0x7B, 0x54, 0x94, 0xAB,
-  0xF4, 0x25, 0xC4, 0xFD, 0xE4, 0x1C, 0xDD, 0xAB,
-  0xBD, 0x06, 0xCB, 0xD6, 0xCA, 0x33, 0x8C, 0xA2,
-  0x92, 0x9C, 0xBC, 0xDB, 0xCD, 0x6E, 0xEC, 0xEE,
-  0xBC, 0x03, 0xDA, 0xCE, 0xF4, 0xB6, 0xDB, 0x92,
-  0xAD, 0xBC, 0xDE, 0xD5, 0x7B, 0xAE, 0x9D, 0x84,
-  0xB6, 0x96, 0x44, 0xBA, 0x6E, 0x3C, 0x7A, 0xB2,
-  0x8C, 0x4C, 0xCE, 0x4C, 0x3C, 0x5A, 0xCA, 0x6D,
-  0x7C, 0xCE, 0xDA, 0x9C, 0xAA, 0x6D, 0x4D, 0x2B,
-  0x1B, 0x5E, 0xCB, 0xAC, 0xBE, 0x5C, 0x2E, 0xDC,
-  0xBD, 0x3E, 0xAC, 0x82, 0xB6, 0xBE, 0xD3, 0xBD,
-  0x72, 0x62, 0x6C, 0x82, 0x92, 0x9E, 0xB0, 0x13,
-  0x4A, 0x8E, 0xBE, 0xCE, 0x86, 0x45, 0x6B, 0xAA,
-  0x9A, 0xC5, 0xC6, 0xDA, 0xC5, 0xC4, 0x34, 0x9B,
-  0xCC, 0xAC, 0xC4, 0x76, 0x9A, 0x9E, 0xEE, 0x62,
-  0xC6, 0x76, 0x0D, 0xE4, 0xDA, 0xD5, 0xA5, 0x92,
-  0xCD, 0xB2, 0x7C, 0xCC, 0xBE, 0x7E, 0xDC, 0xD6,
-  0xB9, 0xE3, 0xD4, 0xF6, 0x55, 0x82, 0xA4, 0xAA,
-  0x8D, 0xBB, 0xCE, 0xD5, 0x8A, 0xDB, 0xD4, 0x8B,
-  0xCA, 0x93, 0x63
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65,
+    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+    0xc3, 0x62, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x62, 0x5c,
+    0x4e, 0x26, 0x72, 0xaa, 0xba, 0xaf, 0x90, 0xae,
+    0x92, 0x1a, 0xa4, 0x85, 0xb6, 0xbe, 0xc3, 0xc8,
+    0xcf, 0xd0, 0xc2, 0xce, 0x57, 0xa2, 0xd6, 0xda,
+    0xda, 0xd7, 0xb8, 0x2a, 0x7b, 0x91, 0xae, 0xca,
+    0xda, 0x45, 0x9e, 0xb2, 0xd7, 0x9b, 0x90, 0x76,
+    0x5c, 0xa2, 0xbe, 0xa6, 0x85, 0x96, 0x4e, 0x46,
+    0x66, 0x92, 0x7a, 0x9a, 0x96, 0x9d, 0x9a, 0x6b,
+    0x8a, 0x8e, 0xb2, 0xca, 0x90, 0xa6, 0x79, 0x7c,
+    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xfa,
+    0xea, 0xd7, 0xf6, 0xbc, 0xda, 0xde, 0xda, 0xe6,
+    0xca, 0xd8, 0xea, 0xe0, 0xcc, 0xf2, 0xce, 0xb2,
+    0xee, 0xa2, 0xd6, 0xe6, 0xf6, 0xd7, 0xc5, 0xb8,
+    0xc6, 0xb9, 0xce, 0xde, 0xce, 0xc6, 0x0e, 0x36,
+    0xae, 0xbe, 0x86, 0xba, 0xbe, 0xe6, 0x8e, 0xc4,
+    0x1e, 0x8e, 0xae, 0xba, 0xb2, 0xa6, 0x12, 0x7a,
+    0x20, 0xc6, 0x64, 0xaa, 0x2f, 0x70, 0x85, 0x46,
+    0xce, 0xd6, 0xa6, 0x6e, 0x51, 0x72, 0x92, 0xa6,
+    0x87, 0x96, 0xa2, 0xd6, 0x85, 0x7a, 0x6a, 0x6e,
+    0x22, 0x76, 0x36, 0x76, 0x3c, 0x6e, 0x63, 0x53,
+    0x66, 0x62, 0x42, 0x50, 0x56, 0x42, 0x56, 0x56,
+    0x56, 0x3e, 0x51, 0x52, 0x56,
 };
 
 unsigned char linux_logo_blue[] __initdata = {
-  0x04, 0x28, 0x10, 0x8C, 0x0B, 0x84, 0x14, 0x1A,
-  0x77, 0x1F, 0x64, 0x0E, 0x85, 0xD2, 0x24, 0xA4,
-  0x0F, 0x54, 0x0C, 0x7C, 0x3F, 0x04, 0x20, 0x0D,
-  0x54, 0xDF, 0x14, 0x0D, 0xD1, 0xE9, 0xB0, 0x11,
-  0x0A, 0x40, 0x57, 0x14, 0xC3, 0x0C, 0x04, 0x12,
-  0x50, 0x0C, 0x7D, 0x05, 0x55, 0xF2, 0xBA, 0xC7,
-  0x09, 0xB4, 0x0E, 0x24, 0x0B, 0x74, 0x0C, 0xB6,
-  0x80, 0x48, 0x10, 0x34, 0x0F, 0x0C, 0xA0, 0x04,
-  0x19, 0x10, 0x0E, 0x14, 0x0E, 0x05, 0x94, 0x0E,
-  0xCA, 0x0B, 0x46, 0xFB, 0xB4, 0x1C, 0x9B, 0x1A,
-  0x21, 0x09, 0x14, 0x4D, 0xCB, 0x08, 0x11, 0x7C,
-  0x20, 0x10, 0x24, 0x66, 0x79, 0x07, 0xEA, 0xC9,
-  0x0C, 0x08, 0x38, 0xC4, 0xD8, 0x24, 0xBE, 0x6C,
-  0x51, 0xBB, 0x8C, 0x36, 0x0A, 0x0F, 0x0C, 0x84,
-  0x3C, 0x54, 0x44, 0x7C, 0x28, 0x0E, 0x28, 0x7F,
-  0x8C, 0x0F, 0x54, 0x24, 0x3C, 0x18, 0x54, 0x17,
-  0x7C, 0x9C, 0xDA, 0x9C, 0x7C, 0x6C, 0x4D, 0x2C,
-  0x09, 0x0E, 0x8A, 0x50, 0x4C, 0x5B, 0x14, 0xAC,
-  0x19, 0x3C, 0xAC, 0x5C, 0x64, 0x97, 0x94, 0x37,
-  0x29, 0x3C, 0x44, 0x3C, 0x2C, 0x7C, 0x70, 0x07,
-  0x04, 0x29, 0xB2, 0x64, 0x74, 0x07, 0x07, 0x2C,
-  0x74, 0x2E, 0x6C, 0xA4, 0x29, 0x9E, 0x34, 0x27,
-  0x2F, 0x98, 0x48, 0x5C, 0x0C, 0x5C, 0xE8, 0x04,
-  0xC2, 0x0C, 0x0A, 0xB2, 0x74, 0xCB, 0x46, 0x78,
-  0xB4, 0x5C, 0x18, 0x80, 0x8C, 0x24, 0xD9, 0xAC,
-  0x87, 0x99, 0x1D, 0xE8, 0x14, 0x0D, 0x10, 0x17,
-  0x0A, 0x67, 0x3C, 0x68, 0x3C, 0x69, 0x90, 0x22,
-  0x6C, 0x0D, 0x17
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x01, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x06, 0x65,
+    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+    0xc3, 0x59, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x2e, 0x08,
+    0x0a, 0x06, 0x0a, 0x0b, 0x0b, 0x0f, 0x0c, 0x0f,
+    0x3d, 0x09, 0x73, 0x09, 0x0d, 0x0a, 0x10, 0x1e,
+    0x2d, 0x13, 0x86, 0xba, 0x19, 0x0a, 0x36, 0x3c,
+    0x26, 0x14, 0x0d, 0x06, 0x07, 0x0a, 0x0b, 0x0f,
+    0x4a, 0x06, 0x0a, 0x0c, 0x2b, 0x0a, 0x0b, 0x0a,
+    0x06, 0x0a, 0x0a, 0x11, 0x0b, 0x0a, 0x0a, 0x1e,
+    0x0f, 0x0d, 0x0a, 0x0b, 0x22, 0x6a, 0x72, 0x0b,
+    0x0b, 0x22, 0x90, 0xca, 0x90, 0x92, 0x3c, 0x2c,
+    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xea,
+    0xb6, 0x7c, 0xda, 0x8e, 0xa6, 0x87, 0x66, 0xb6,
+    0x81, 0x6a, 0xc6, 0x9a, 0x5b, 0xd2, 0xb6, 0x6a,
+    0xca, 0x45, 0x92, 0xb2, 0xca, 0x52, 0x8a, 0x3e,
+    0x2e, 0x66, 0x66, 0xae, 0x3e, 0x47, 0x06, 0x0e,
+    0x52, 0x36, 0x6a, 0x0e, 0x0e, 0xbe, 0x2c, 0x0e,
+    0x0a, 0x5a, 0x0d, 0x0e, 0x3e, 0x0a, 0x06, 0x2e,
+    0x06, 0x9e, 0x4e, 0x36, 0x06, 0x58, 0x24, 0x06,
+    0x9e, 0xae, 0x3a, 0x08, 0x08, 0x07, 0x5e, 0x0a,
+    0x32, 0x2e, 0x2a, 0xb2, 0x43, 0x48, 0x5f, 0x2e,
+    0x06, 0x06, 0x07, 0x24, 0x06, 0x32, 0x06, 0x06,
+    0x46, 0x2e, 0x22, 0x06, 0x06, 0x1e, 0x4c, 0x06,
+    0x3a, 0x22, 0x42, 0x34, 0x42,
 };
 
 unsigned char linux_logo[] __initdata = {
-  0xD8, 0xA3, 0x98, 0x98, 0xA3, 0xB2, 0x2F, 0x2F,
-  0xA3, 0x66, 0x98, 0x98, 0x98, 0xA3, 0x2F, 0xA3,
-  0x98, 0x55, 0xA0, 0xA3, 0xB2, 0x51, 0x51, 0x2F,
-  0x98, 0x55, 0x8F, 0x2F, 0x89, 0x44, 0x89, 0x51,
-  0xB2, 0x2F, 0x66, 0xA3, 0x2F, 0x2F, 0x66, 0x66,
-  0xA3, 0xB2, 0xB2, 0xB2, 0x89, 0xD8, 0x44, 0x44,
-  0xD8, 0x83, 0xD8, 0xA3, 0x98, 0x98, 0xA3, 0xB2,
-  0x2F, 0x2F, 0xA3, 0x66, 0x98, 0x98, 0x98, 0xA3,
-  0x2F, 0xA3, 0x98, 0x55, 0xA0, 0xA3, 0xB2, 0x51,
-  0x51, 0x2F, 0x98, 0x55, 0x8F, 0x2F, 0x89, 0x44,
-  0xA3, 0x55, 0x55, 0x98, 0x2F, 0x2F, 0x2F, 0xA3,
-  0x66, 0x66, 0x98, 0x98, 0x66, 0x66, 0x66, 0x98,
-  0x55, 0xA5, 0x8F, 0xA3, 0x51, 0x51, 0xB2, 0x2F,
-  0x66, 0x66, 0xA3, 0x51, 0x89, 0x51, 0xB2, 0x2F,
-  0x2F, 0xA3, 0x66, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F,
-  0xB2, 0xB2, 0x2F, 0x2F, 0xB2, 0x51, 0x51, 0x51,
-  0x51, 0x51, 0xA3, 0x55, 0x55, 0x98, 0x2F, 0x2F,
-  0x2F, 0xA3, 0x66, 0x66, 0x98, 0x98, 0x66, 0x66,
-  0x66, 0x98, 0x55, 0xA5, 0x8F, 0xA3, 0x51, 0x51,
-  0xB2, 0x2F, 0x66, 0x66, 0xA3, 0x51, 0x89, 0x51,
-  0x98, 0xA5, 0x55, 0x8F, 0x2F, 0xB2, 0x2F, 0xA3,
-  0x66, 0x66, 0x98, 0x8F, 0x66, 0x66, 0x66, 0x98,
-  0xA0, 0x8F, 0xA3, 0xB2, 0x51, 0x51, 0xB2, 0x2F,
-  0xA3, 0xA3, 0x2F, 0xB2, 0x51, 0xB2, 0x2F, 0x2F,
-  0xA3, 0x66, 0x98, 0xA3, 0x51, 0xB2, 0x2F, 0xA3,
-  0xB2, 0x51, 0x51, 0xB2, 0xB2, 0x51, 0xB2, 0xB2,
-  0xB2, 0x2F, 0x98, 0xA5, 0x55, 0x8F, 0x2F, 0xB2,
-  0x2F, 0xA3, 0x66, 0x66, 0x98, 0x8F, 0x66, 0x66,
-  0x66, 0x98, 0xA0, 0x8F, 0xA3, 0xB2, 0x51, 0x51,
-  0xB2, 0x2F, 0xA3, 0xA3, 0x2F, 0x51, 0x51, 0xB2,
-  0xA0, 0xA5, 0x55, 0x66, 0xB2, 0x51, 0xB2, 0xA3,
-  0x66, 0x66, 0x98, 0x66, 0x66, 0x66, 0x98, 0x98,
-  0x66, 0xA3, 0x2F, 0xB2, 0x51, 0x51, 0xB2, 0xA3,
-  0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0xA3,
-  0x66, 0x98, 0xB2, 0x4C, 0x54, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xCE, 0x2F, 0xB2, 0x2F, 0x2F,
-  0xA3, 0x98, 0xA0, 0xA5, 0x55, 0x66, 0xB2, 0x51,
-  0xB2, 0xA3, 0x66, 0x66, 0x98, 0x66, 0x66, 0x66,
-  0x98, 0x98, 0x66, 0xA3, 0x2F, 0xB2, 0x51, 0x51,
-  0xB2, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F,
-  0xA0, 0xA0, 0x8F, 0xA3, 0xB2, 0x51, 0xB2, 0x2F,
-  0x66, 0x66, 0x98, 0x66, 0x66, 0x66, 0x66, 0x66,
-  0xA3, 0x2F, 0x51, 0x51, 0x51, 0xB2, 0x2F, 0xA3,
-  0x66, 0x66, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
-  0x2F, 0xA0, 0xDA, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x9C, 0xB2, 0xA3,
-  0x66, 0x98, 0xA0, 0xA0, 0x8F, 0xA3, 0xB2, 0x51,
-  0xB2, 0x2F, 0x66, 0x66, 0x98, 0x66, 0x66, 0x66,
-  0x66, 0x66, 0xA3, 0x2F, 0x51, 0x51, 0x51, 0xB2,
-  0x2F, 0xA3, 0x66, 0x66, 0x66, 0xA3, 0xA3, 0xA3,
-  0x8F, 0x8F, 0x66, 0x2F, 0x51, 0x51, 0xB2, 0xA3,
-  0x66, 0x98, 0x98, 0x66, 0x66, 0x66, 0x2F, 0x2F,
-  0xB2, 0x51, 0xB2, 0xB2, 0x2F, 0x2F, 0xA3, 0x66,
-  0x66, 0x66, 0xA3, 0xA3, 0x2F, 0xA3, 0xA3, 0xB2,
-  0x9C, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xDA, 0x3A, 0x20, 0x54, 0x55,
-  0xA3, 0x98, 0x8F, 0x8F, 0x66, 0x2F, 0x51, 0x51,
-  0xB2, 0xA3, 0x66, 0x98, 0x98, 0x66, 0x66, 0x66,
-  0x2F, 0x2F, 0xB2, 0x51, 0xB2, 0xB2, 0x2F, 0x2F,
-  0xA3, 0x66, 0x66, 0x66, 0x2F, 0xA3, 0x2F, 0x2F,
-  0x66, 0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0x2F, 0x66,
-  0x8F, 0x8F, 0x8F, 0x66, 0xA3, 0xA3, 0xB2, 0xB2,
-  0xB2, 0xB2, 0xB2, 0xB2, 0x2F, 0xA3, 0xA3, 0xA3,
-  0xA3, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0xAD,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xA7, 0x4C, 0xCE, 0xDA, 0x20,
-  0xA6, 0x2F, 0x66, 0x66, 0xA3, 0x2F, 0xB2, 0xB2,
-  0x2F, 0x66, 0x8F, 0x8F, 0x8F, 0x66, 0xA3, 0xA3,
-  0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0x2F, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F,
-  0xA3, 0x98, 0x66, 0x2F, 0xB2, 0xB2, 0x2F, 0x98,
-  0x8F, 0x8F, 0x98, 0x66, 0xA3, 0xB2, 0xB2, 0xB2,
-  0x2F, 0x2F, 0x2F, 0x2F, 0xA3, 0x2F, 0xA3, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0x51, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xCE, 0x55, 0xAD, 0xA7, 0x54,
-  0x20, 0x8F, 0xA3, 0x98, 0x66, 0x2F, 0xB2, 0xB2,
-  0x2F, 0x98, 0x8F, 0x8F, 0x98, 0x66, 0xA3, 0xB2,
-  0xB2, 0xB2, 0x2F, 0x2F, 0x2F, 0x2F, 0xA3, 0x2F,
-  0xA3, 0xA3, 0xA3, 0x2F, 0xA3, 0xA3, 0xA3, 0xA3,
-  0xA3, 0x8F, 0x66, 0x2F, 0xB2, 0x51, 0x2F, 0x98,
-  0xA0, 0x8F, 0x66, 0xA3, 0x2F, 0x51, 0x51, 0xB2,
-  0xA3, 0xA3, 0xA3, 0x2F, 0xA3, 0xA3, 0x66, 0x66,
-  0x98, 0x98, 0x98, 0x66, 0x98, 0x66, 0x55, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xCE, 0x4C, 0x9C, 0x2E, 0xDA,
-  0x20, 0xDA, 0x51, 0x8F, 0x66, 0x2F, 0xB2, 0x51,
-  0x2F, 0x98, 0xA0, 0x8F, 0x66, 0xA3, 0x2F, 0x51,
-  0x51, 0xB2, 0xA3, 0xA3, 0xA3, 0x2F, 0xA3, 0xA3,
-  0x66, 0x66, 0x98, 0x98, 0x98, 0x98, 0x98, 0x66,
-  0x51, 0x66, 0x2F, 0xB2, 0x51, 0xB2, 0xA3, 0xA0,
-  0xA0, 0x66, 0xA3, 0xB2, 0xB2, 0xB2, 0xB2, 0xA3,
-  0x66, 0x66, 0x66, 0xA3, 0xA3, 0x66, 0x98, 0x98,
-  0x98, 0x98, 0x98, 0x66, 0x66, 0xB2, 0x6D, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x6D, 0x3A, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0xA5, 0x66, 0x2F, 0xB2, 0x51, 0xB2,
-  0xA3, 0xA0, 0xA0, 0x66, 0xA3, 0xB2, 0xB2, 0xB2,
-  0xB2, 0xA3, 0x66, 0x66, 0x66, 0xA3, 0xA3, 0x66,
-  0x98, 0x98, 0x8F, 0x98, 0x66, 0x66, 0x66, 0x66,
-  0x51, 0x2F, 0xB2, 0x51, 0x51, 0x2F, 0x66, 0xA0,
-  0x8F, 0xA3, 0x2F, 0xB2, 0xB2, 0x2F, 0x2F, 0x66,
-  0x98, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
-  0x66, 0x2F, 0xA3, 0x2F, 0x2F, 0x51, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0xDA, 0x51, 0xB2, 0x51, 0x51, 0x2F,
-  0x66, 0xA0, 0x8F, 0xA3, 0x2F, 0xB2, 0xB2, 0x2F,
-  0x2F, 0x66, 0x98, 0x66, 0x66, 0x66, 0x66, 0x66,
-  0x66, 0x66, 0x66, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F,
-  0x51, 0x2F, 0xB2, 0x51, 0x2F, 0xA3, 0x8F, 0x8F,
-  0x98, 0xA3, 0xB2, 0xB2, 0x2F, 0xA3, 0x98, 0x66,
-  0x98, 0x98, 0x66, 0x66, 0x66, 0x66, 0xA3, 0x2F,
-  0xB2, 0xB2, 0x51, 0xB2, 0xB2, 0x66, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xA3, 0xB2, 0x51, 0x2F, 0xA3,
-  0x8F, 0x8F, 0x98, 0xA3, 0xB2, 0xB2, 0x2F, 0xA3,
-  0x98, 0x66, 0x98, 0x98, 0x66, 0x66, 0x66, 0x66,
-  0xA3, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2,
-  0xB2, 0x2F, 0xA3, 0x2F, 0x66, 0x98, 0x8F, 0x98,
-  0xA3, 0x2F, 0x2F, 0xA3, 0x98, 0x98, 0x98, 0x98,
-  0x66, 0x98, 0x66, 0x98, 0x66, 0xA3, 0x2F, 0xB2,
-  0x51, 0x51, 0x51, 0xB2, 0xB2, 0x8F, 0x20, 0x20,
-  0x20, 0x54, 0x6D, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x54, 0x6D, 0x6D, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x4C, 0xA3, 0x2F, 0x66, 0x98,
-  0x8F, 0x98, 0xA3, 0x2F, 0x2F, 0xA3, 0x98, 0x98,
-  0x98, 0x98, 0x66, 0x98, 0x66, 0x98, 0x66, 0xA3,
-  0x2F, 0xB2, 0x51, 0x51, 0x51, 0xB2, 0x2F, 0x2F,
-  0x2F, 0xA3, 0xA3, 0x66, 0x98, 0x98, 0x8F, 0x98,
-  0x2F, 0x2F, 0x2F, 0x66, 0x8F, 0x8F, 0x98, 0xA3,
-  0x66, 0x66, 0x8F, 0x98, 0x98, 0x66, 0x2F, 0xB2,
-  0x51, 0xB2, 0x2F, 0xA3, 0xA3, 0xA0, 0x20, 0x20,
-  0xDA, 0x2E, 0x3A, 0xA7, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0xCE, 0x2A, 0x2A, 0x2E, 0xA7, 0xDA, 0x20,
-  0x20, 0x20, 0x20, 0x9C, 0xA3, 0x66, 0x98, 0x98,
-  0x8F, 0x98, 0x2F, 0x2F, 0x2F, 0x66, 0x8F, 0x8F,
-  0x98, 0xA3, 0x66, 0x66, 0x8F, 0x98, 0x98, 0x66,
-  0x2F, 0xB2, 0x51, 0xB2, 0x2F, 0x2F, 0xA3, 0xA3,
-  0xB2, 0xA3, 0x66, 0x98, 0x8F, 0x8F, 0x66, 0xA3,
-  0x2F, 0x2F, 0x66, 0x98, 0x98, 0x66, 0x2F, 0x2F,
-  0xA3, 0x98, 0x8F, 0x98, 0x66, 0x2F, 0xB2, 0xB2,
-  0xB2, 0xA3, 0x66, 0x66, 0x66, 0x98, 0x20, 0x3A,
-  0x98, 0x89, 0x8F, 0x6D, 0x20, 0x20, 0x20, 0x20,
-  0x4C, 0x66, 0x51, 0x44, 0x51, 0x2E, 0x54, 0x20,
-  0x20, 0x20, 0x20, 0xA7, 0x66, 0x98, 0x8F, 0x8F,
-  0x66, 0xA3, 0x2F, 0x2F, 0x66, 0x98, 0x98, 0x66,
-  0x2F, 0x2F, 0xA3, 0x98, 0x8F, 0x98, 0x66, 0x2F,
-  0xB2, 0xB2, 0xB2, 0xA3, 0x66, 0x66, 0x66, 0xA3,
-  0x2F, 0x66, 0x98, 0x8F, 0x8F, 0x98, 0x66, 0x2F,
-  0x2F, 0xA3, 0x66, 0x98, 0x98, 0xA3, 0x2F, 0xB2,
-  0xA3, 0x8F, 0x98, 0xA3, 0xB2, 0x51, 0x89, 0x89,
-  0xB2, 0xA3, 0x66, 0x98, 0x66, 0x98, 0x20, 0xA6,
-  0x44, 0x39, 0xE6, 0x98, 0x20, 0x20, 0x20, 0x9C,
-  0x74, 0xD6, 0x7E, 0xD6, 0x39, 0x8F, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x2E, 0x98, 0x8F, 0x8F, 0x98,
-  0x66, 0x2F, 0x2F, 0xA3, 0x66, 0x98, 0x98, 0xA3,
-  0x2F, 0xB2, 0x66, 0x98, 0x8F, 0xA3, 0xB2, 0x51,
-  0x89, 0x89, 0xB2, 0xA3, 0x66, 0x98, 0x66, 0x66,
-  0x2F, 0x66, 0x8F, 0xA0, 0x8F, 0x98, 0xA3, 0xB2,
-  0x2F, 0x66, 0x66, 0x66, 0xA3, 0x2F, 0x2F, 0x2F,
-  0x66, 0x98, 0xA3, 0xB2, 0x89, 0x44, 0x89, 0x51,
-  0x2F, 0x66, 0x98, 0x98, 0xA3, 0x66, 0x20, 0x2F,
-  0x2F, 0xAD, 0x89, 0xD6, 0x3A, 0x20, 0x20, 0x55,
-  0x6B, 0x51, 0x6D, 0x4C, 0xD8, 0xD6, 0x2E, 0x20,
-  0x20, 0x20, 0x20, 0x54, 0x8F, 0xA0, 0x8F, 0x98,
-  0xA3, 0xB2, 0x2F, 0x66, 0x66, 0x66, 0xA3, 0x2F,
-  0xB2, 0x2F, 0x66, 0x66, 0xA3, 0xB2, 0x89, 0x44,
-  0x89, 0x51, 0x2F, 0x66, 0x98, 0x98, 0xA3, 0xA3,
-  0xA3, 0x66, 0x8F, 0xA0, 0x8F, 0x66, 0x2F, 0xB2,
-  0xA3, 0x66, 0x98, 0x66, 0xA3, 0x2F, 0x2F, 0xA3,
-  0xA3, 0x2F, 0xB2, 0x89, 0xD8, 0xD8, 0x51, 0x66,
-  0x8F, 0xA0, 0xA0, 0x8F, 0x98, 0xA3, 0x20, 0x44,
-  0xA7, 0xCE, 0xA6, 0x4D, 0xCE, 0x6D, 0xA7, 0xA0,
-  0x6B, 0xA7, 0x20, 0x92, 0xAD, 0x6B, 0x4C, 0x20,
-  0x20, 0x20, 0x20, 0x54, 0x98, 0xA0, 0x8F, 0x66,
-  0x2F, 0xB2, 0xA3, 0x66, 0x98, 0x66, 0xA3, 0x2F,
-  0x2F, 0xA3, 0xA3, 0xA3, 0xB2, 0x89, 0xD8, 0xD8,
-  0x51, 0x66, 0x8F, 0xA0, 0xA0, 0x8F, 0x98, 0x66,
-  0x66, 0x66, 0x8F, 0x55, 0x8F, 0xA3, 0xB2, 0xB2,
-  0xA3, 0x66, 0x66, 0xA3, 0x2F, 0xA3, 0xA3, 0xA3,
-  0xA3, 0xB2, 0x89, 0x44, 0x44, 0x51, 0x66, 0xA0,
-  0x55, 0xA5, 0x55, 0x8F, 0x66, 0xA3, 0x20, 0x44,
-  0x6D, 0x54, 0xA7, 0x74, 0x2E, 0x4B, 0xBF, 0x9C,
-  0x7E, 0xDA, 0x20, 0x54, 0x2E, 0x6B, 0x2A, 0x20,
-  0x20, 0x20, 0x20, 0x3A, 0x8F, 0x55, 0x8F, 0xA3,
-  0xB2, 0xB2, 0xA3, 0x66, 0x66, 0xA3, 0xA3, 0x2F,
-  0xA3, 0xA3, 0xA3, 0xB2, 0x89, 0x44, 0x44, 0x51,
-  0x66, 0xA0, 0xA5, 0xA5, 0x55, 0x8F, 0x66, 0x66,
-  0xA0, 0xA0, 0xA0, 0xA0, 0x8F, 0xA3, 0x2F, 0xB2,
-  0x66, 0x98, 0xA3, 0x2F, 0x2F, 0xB2, 0x2F, 0x2F,
-  0xB2, 0x51, 0x89, 0x89, 0xB2, 0x98, 0xA0, 0x2A,
-  0xA5, 0x55, 0x98, 0x66, 0xA3, 0xB2, 0x20, 0x2F,
-  0x4C, 0x20, 0x4B, 0xBB, 0xCF, 0x6F, 0x27, 0x36,
-  0x93, 0xCE, 0x20, 0x20, 0xA6, 0x3D, 0x4C, 0x20,
-  0x20, 0x20, 0x20, 0xDA, 0xA0, 0xA0, 0x8F, 0xA3,
-  0x2F, 0xB2, 0x66, 0x98, 0xA3, 0x2F, 0xB2, 0x2F,
-  0x2F, 0x2F, 0xB2, 0x51, 0x89, 0x89, 0xB2, 0x98,
-  0xA0, 0x2A, 0xA5, 0xA0, 0x8F, 0x66, 0xA3, 0xA3,
-  0xA0, 0x8F, 0x8F, 0xA0, 0x8F, 0xA3, 0xB2, 0x2F,
-  0x66, 0x98, 0x2F, 0xB2, 0xB2, 0xB2, 0xB2, 0x2F,
-  0xB2, 0x89, 0x44, 0x51, 0x66, 0x55, 0xAD, 0x2A,
-  0x55, 0x8F, 0x66, 0xA3, 0x2F, 0xB2, 0x20, 0x2A,
-  0xE6, 0x95, 0xE5, 0x5A, 0x52, 0x52, 0x3F, 0x27,
-  0x22, 0xC7, 0x9D, 0x60, 0xA2, 0xA2, 0x3A, 0x20,
-  0x20, 0x20, 0x20, 0x54, 0x66, 0xA0, 0x8F, 0xA3,
-  0xB2, 0x2F, 0x66, 0x98, 0x2F, 0xB2, 0xB2, 0xB2,
-  0xB2, 0x2F, 0xB2, 0x89, 0x44, 0x51, 0x66, 0x55,
-  0x2A, 0x2A, 0xA5, 0x8F, 0x66, 0xA3, 0x2F, 0x2F,
-  0xA3, 0xA3, 0x66, 0x98, 0x98, 0x2F, 0xB2, 0xB2,
-  0xA3, 0xA3, 0x2F, 0x51, 0x51, 0x51, 0x2F, 0x2F,
-  0x51, 0x89, 0x89, 0x2F, 0x8F, 0x2A, 0x2A, 0xA5,
-  0x8F, 0x66, 0xA3, 0xB2, 0x2F, 0x51, 0x20, 0x6D,
-  0x77, 0xF7, 0xEE, 0x30, 0xB0, 0x72, 0x72, 0x5B,
-  0x82, 0xEA, 0x72, 0xB0, 0x90, 0x96, 0x71, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x2F, 0x98, 0x98, 0x2F,
-  0xB2, 0xB2, 0x66, 0xA3, 0x2F, 0x51, 0x51, 0xB2,
-  0xB2, 0x2F, 0x51, 0x89, 0x89, 0x2F, 0x8F, 0x2A,
-  0xAD, 0xA5, 0x98, 0x66, 0xA3, 0xB2, 0x2F, 0xB2,
-  0xD8, 0xB2, 0xA3, 0x98, 0x98, 0x2F, 0xB2, 0xB2,
-  0x66, 0xA3, 0xB2, 0x51, 0x51, 0xB2, 0x2F, 0xA3,
-  0x51, 0x89, 0x89, 0xA3, 0xA0, 0x2A, 0xA5, 0x8F,
-  0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0x51, 0x20, 0x69,
-  0x64, 0xF9, 0x3F, 0x52, 0x52, 0x72, 0x29, 0x82,
-  0x47, 0x47, 0x47, 0x8B, 0x72, 0xB7, 0x60, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x2F, 0x98, 0x98, 0x2F,
-  0xB2, 0xB2, 0xA3, 0xA3, 0xB2, 0x89, 0x51, 0x2F,
-  0x2F, 0xA3, 0x51, 0x89, 0x89, 0xA3, 0xA0, 0x2A,
-  0xA5, 0x8F, 0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0xB2,
-  0xDD, 0xA3, 0x66, 0x98, 0x66, 0x2F, 0xB2, 0xB2,
-  0xA3, 0xA3, 0xB2, 0x51, 0xB2, 0x2F, 0xA3, 0x2F,
-  0xB2, 0x89, 0xB2, 0x66, 0xA0, 0xA5, 0x8F, 0x98,
-  0x66, 0x66, 0xB2, 0x51, 0x51, 0x51, 0x81, 0xFA,
-  0x62, 0xEE, 0x30, 0x52, 0x22, 0x72, 0x82, 0x82,
-  0x47, 0x47, 0xEA, 0x3F, 0x37, 0x6F, 0x26, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x2A, 0x98, 0x66, 0x2F,
-  0x51, 0xB2, 0xA3, 0x66, 0xB2, 0x51, 0x51, 0xB2,
-  0xA3, 0x2F, 0xB2, 0x89, 0xB2, 0x66, 0x55, 0x55,
-  0x8F, 0x98, 0x66, 0xA3, 0xB2, 0x51, 0x51, 0xB2,
-  0x74, 0xA0, 0x8F, 0x98, 0x66, 0xB2, 0xB2, 0xB2,
-  0xA3, 0xA3, 0x2F, 0x51, 0x51, 0x2F, 0xA3, 0x2F,
-  0xB2, 0x51, 0xA3, 0x98, 0xA0, 0x55, 0xA0, 0xA0,
-  0x8F, 0x66, 0x2F, 0x51, 0xB2, 0x51, 0x54, 0xA9,
-  0x62, 0xEF, 0x52, 0x22, 0x72, 0x29, 0xEA, 0xEA,
-  0x29, 0x22, 0x37, 0x37, 0x8E, 0xCF, 0x49, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x6D, 0x2F, 0x66, 0x2F,
-  0x51, 0xB2, 0xA3, 0x66, 0x2F, 0xB2, 0xB2, 0x2F,
-  0xA3, 0x2F, 0xB2, 0x51, 0x2F, 0x98, 0xA0, 0x55,
-  0xA0, 0xA0, 0x8F, 0x66, 0x2F, 0x51, 0xB2, 0xA3,
-  0xA3, 0x2A, 0xA5, 0x98, 0xA3, 0x2F, 0xB2, 0x2F,
-  0x66, 0x66, 0x2F, 0xB2, 0xB2, 0xB2, 0x2F, 0x2F,
-  0xB2, 0x2F, 0xA3, 0x8F, 0xA0, 0xA0, 0xA0, 0xA0,
-  0x8F, 0xA3, 0x51, 0x51, 0x2F, 0xB2, 0x54, 0xA8,
-  0x65, 0x5C, 0x52, 0x22, 0x29, 0x29, 0x29, 0xB0,
-  0x62, 0x56, 0xF9, 0x79, 0xF9, 0xBB, 0x4B, 0x20,
-  0x6D, 0xA5, 0x2E, 0x20, 0x20, 0xA3, 0xA3, 0x2F,
-  0xB2, 0x2F, 0xA3, 0x66, 0x2F, 0xB2, 0xB2, 0xB2,
-  0x2F, 0x2F, 0xB2, 0x2F, 0x66, 0x8F, 0xA0, 0xA0,
-  0x55, 0xA0, 0x8F, 0xA3, 0x51, 0x51, 0x2F, 0xA3,
-  0xA0, 0x2A, 0x55, 0x66, 0xA3, 0x2F, 0xB2, 0xB2,
-  0xA3, 0x66, 0xA3, 0xB2, 0xB2, 0xB2, 0xA3, 0x66,
-  0xA3, 0xA3, 0x66, 0x8F, 0x8F, 0x8F, 0xA0, 0x98,
-  0xA3, 0x51, 0x89, 0x89, 0xA3, 0x2F, 0x20, 0x54,
-  0xDF, 0xFA, 0x40, 0x37, 0xD4, 0x43, 0x56, 0x64,
-  0x76, 0xF9, 0x78, 0x41, 0x5E, 0x5E, 0x4C, 0x20,
-  0x20, 0xAD, 0x8F, 0x9C, 0x20, 0xA5, 0xA3, 0x2F,
-  0x2F, 0x2F, 0xA3, 0x66, 0x2F, 0xB2, 0xB2, 0xB2,
-  0xA3, 0x66, 0xA3, 0x2F, 0x66, 0x8F, 0x8F, 0x8F,
-  0x8F, 0x8F, 0xA3, 0x51, 0x89, 0x51, 0xA3, 0x66,
-  0xA0, 0xA0, 0x8F, 0xA3, 0x2F, 0x2F, 0x2F, 0xB2,
-  0x2F, 0xA3, 0x2F, 0xB2, 0x51, 0xB2, 0x2F, 0x66,
-  0xA3, 0xA3, 0x66, 0x66, 0x66, 0x66, 0x66, 0xA3,
-  0xB2, 0x89, 0xD8, 0x51, 0x66, 0x51, 0x20, 0x6D,
-  0x51, 0x77, 0x9F, 0xF7, 0xEE, 0x8E, 0xF9, 0xF0,
-  0x24, 0xF7, 0x77, 0x5E, 0x74, 0xD8, 0x98, 0x20,
-  0x20, 0x2E, 0x55, 0x92, 0x20, 0x54, 0x51, 0x2F,
-  0x2F, 0xB2, 0xB2, 0xA3, 0x2F, 0x51, 0x51, 0xB2,
-  0xA3, 0xA3, 0x66, 0xA3, 0x66, 0x66, 0x66, 0x66,
-  0x66, 0xA3, 0xB2, 0x89, 0xD8, 0x51, 0xA3, 0x98,
-  0x98, 0x66, 0x66, 0xA3, 0x2F, 0x2F, 0x2F, 0xB2,
-  0xB2, 0x2F, 0x2F, 0xB2, 0xB2, 0x2F, 0x2F, 0x66,
-  0x66, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0xB2,
-  0x89, 0xD8, 0x89, 0xB2, 0x66, 0x66, 0x20, 0x6D,
-  0x89, 0xC2, 0xA4, 0x96, 0xC6, 0x64, 0x50, 0x40,
-  0xF4, 0x97, 0x89, 0x74, 0x7E, 0x6B, 0x39, 0xA7,
-  0x20, 0x20, 0x3A, 0x54, 0x20, 0x20, 0xA7, 0x51,
-  0x2F, 0xB2, 0xB2, 0xA3, 0xA3, 0xB2, 0xB2, 0xB2,
-  0xA3, 0xA3, 0x66, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F,
-  0x2F, 0xB2, 0x89, 0xD8, 0x44, 0x2F, 0x66, 0x66,
-  0x2F, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F, 0xB2,
-  0x2F, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0xA3,
-  0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0xB2, 0x51, 0x51,
-  0x89, 0x89, 0xB2, 0x66, 0x2F, 0x6D, 0x20, 0xCE,
-  0x39, 0x74, 0x89, 0x5E, 0xBD, 0x87, 0xC8, 0xD1,
-  0x89, 0x44, 0x3C, 0x4D, 0x6B, 0x6B, 0x6B, 0x2F,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xA3,
-  0x2F, 0x2F, 0x2F, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F,
-  0x2F, 0xA3, 0x66, 0x66, 0x2F, 0xB2, 0xB2, 0xB2,
-  0x51, 0x51, 0x89, 0x89, 0xB2, 0xA3, 0x98, 0x66,
-  0xA3, 0x66, 0x66, 0xA3, 0xA3, 0xA3, 0xA3, 0x2F,
-  0x2F, 0xA3, 0xA3, 0xA3, 0x2F, 0xA3, 0x2F, 0xA3,
-  0x66, 0x66, 0x2F, 0x2F, 0xB2, 0xB2, 0xB2, 0xB2,
-  0xB2, 0x2F, 0x66, 0x66, 0x2A, 0x20, 0x54, 0x44,
-  0x6B, 0x39, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
-  0xD8, 0x39, 0x4D, 0x6B, 0x6B, 0x6B, 0x6B, 0x4D,
-  0x9C, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6D,
-  0x51, 0x2F, 0x2F, 0x2F, 0xA3, 0xA3, 0xA3, 0x2F,
-  0xA3, 0xA3, 0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0xB2,
-  0xB2, 0xB2, 0xB2, 0x2F, 0x66, 0x98, 0x98, 0x66,
-  0x98, 0x98, 0x66, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
-  0x2F, 0x2F, 0xA3, 0xA3, 0x66, 0xA3, 0xA3, 0x66,
-  0x98, 0x66, 0x66, 0x2F, 0xA3, 0xA3, 0xA3, 0xA3,
-  0x66, 0x98, 0x98, 0x98, 0x3A, 0x54, 0x2A, 0x6B,
-  0x6B, 0x6B, 0x83, 0x44, 0x89, 0x89, 0x44, 0x3C,
-  0xD6, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0xB2, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0xAD, 0x2F, 0x2F, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
-  0xA3, 0x66, 0x66, 0x98, 0x66, 0xA3, 0xA3, 0xA3,
-  0xA3, 0xA3, 0x66, 0x98, 0x8F, 0x8F, 0x8F, 0x98,
-  0x8F, 0x98, 0x98, 0x66, 0xA3, 0xA3, 0xA3, 0xA3,
-  0x2F, 0xA3, 0xA3, 0x66, 0x66, 0x66, 0x66, 0x66,
-  0x8F, 0x8F, 0x8F, 0x98, 0x98, 0x98, 0x8F, 0xA0,
-  0xA0, 0xA0, 0xA3, 0xDA, 0x20, 0x3A, 0x39, 0x6B,
-  0x6B, 0x6B, 0x4D, 0xA2, 0x74, 0x3C, 0x7E, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x2F, 0x2F, 0xA3, 0x66, 0x66, 0x66, 0x66,
-  0x66, 0x98, 0x8F, 0x8F, 0x98, 0x98, 0x98, 0x98,
-  0x8F, 0xA0, 0xA0, 0xA0, 0x8F, 0x8F, 0x8F, 0xA0,
-  0x8F, 0x66, 0x66, 0xA3, 0x66, 0xA3, 0xA3, 0x2F,
-  0x2F, 0x2F, 0xA3, 0xA3, 0x66, 0x66, 0x66, 0x98,
-  0x98, 0xA0, 0x98, 0x66, 0x66, 0x98, 0x8F, 0xA0,
-  0xA0, 0xA3, 0x2E, 0x20, 0x20, 0x8F, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x3D, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x55, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x3A, 0x51, 0x2F, 0xA3, 0x66, 0x66, 0x66,
-  0x66, 0x66, 0x98, 0x8F, 0x8F, 0x98, 0x66, 0x98,
-  0x8F, 0xA0, 0xA0, 0x8F, 0x8F, 0x8F, 0x8F, 0xA0,
-  0x66, 0x2F, 0x2F, 0x2F, 0x2F, 0xA3, 0xA3, 0xA3,
-  0x2F, 0x2F, 0xA3, 0xA3, 0x66, 0xA3, 0x66, 0x66,
-  0x66, 0x98, 0xA3, 0x2F, 0x2F, 0xA3, 0x66, 0x8F,
-  0x66, 0xA6, 0x20, 0x20, 0x6D, 0x39, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x6B, 0xB2, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x2E, 0x89, 0xA3, 0xA3, 0x66, 0x66,
-  0x66, 0x66, 0x98, 0x98, 0xA3, 0x2F, 0x2F, 0xA3,
-  0x66, 0x8F, 0x98, 0x98, 0x66, 0x98, 0x98, 0x8F,
-  0x2F, 0x51, 0xB2, 0xB2, 0x2F, 0xA3, 0xA3, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
-  0xA3, 0xA3, 0x2F, 0xB2, 0x2F, 0xA3, 0x66, 0x2F,
-  0x55, 0x20, 0x20, 0x20, 0x4C, 0x39, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x4D, 0x7E, 0x54, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x2E, 0x51, 0xA3, 0xA3, 0xA3,
-  0xA3, 0xA3, 0xA3, 0x2F, 0xB2, 0xB2, 0x2F, 0xA3,
-  0x66, 0x66, 0xA3, 0xA3, 0xA3, 0xA3, 0x66, 0x66,
-  0xB2, 0x51, 0x51, 0xB2, 0xB2, 0xA3, 0x2F, 0xA3,
-  0x2F, 0x2F, 0x2F, 0xA3, 0xA3, 0xA3, 0xA3, 0x66,
-  0xA3, 0x2F, 0xB2, 0x2F, 0xA3, 0x98, 0x98, 0xA0,
-  0x20, 0x20, 0x20, 0x20, 0xA5, 0x83, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x4D, 0x7E, 0x4D, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x4D, 0x4D, 0xD6, 0x7E, 0xDD,
-  0x3C, 0x39, 0xA7, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x92, 0xB2, 0xA3, 0xA3,
-  0xA3, 0x66, 0xA3, 0x2F, 0x2F, 0x2F, 0xA3, 0x98,
-  0x98, 0x66, 0xA3, 0xA3, 0x66, 0x66, 0x66, 0xA3,
-  0x89, 0x89, 0x51, 0xB2, 0xB2, 0x2F, 0x2F, 0x2F,
-  0x2F, 0xA3, 0xA3, 0x2F, 0xA3, 0xA3, 0xA3, 0xA3,
-  0xA3, 0xA3, 0xA3, 0x66, 0x8F, 0x8F, 0x2F, 0xDA,
-  0x20, 0x20, 0x20, 0xDA, 0xA0, 0x51, 0x3C, 0x7E,
-  0x6B, 0x6B, 0x6B, 0x4D, 0x7E, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x7E, 0x3C, 0xD8, 0x44, 0xD8,
-  0x44, 0x83, 0x89, 0xDA, 0x20, 0x3A, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0xB2, 0xA3, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0x66, 0x8F, 0x8F,
-  0x98, 0x98, 0x98, 0x98, 0x66, 0xA3, 0xA3, 0x2F,
-  0x3C, 0x89, 0x89, 0x51, 0xB2, 0xB2, 0x2F, 0x2F,
-  0x2F, 0x2F, 0xA3, 0xA3, 0x66, 0x66, 0x66, 0xA3,
-  0xA3, 0xA3, 0xA3, 0x66, 0x98, 0x98, 0xA3, 0x20,
-  0x20, 0x20, 0x20, 0x6D, 0x2F, 0xE6, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x3D, 0xD6, 0x3D,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x4D, 0x7E, 0xA2,
-  0x74, 0x44, 0xA2, 0xA3, 0x20, 0x3A, 0x2E, 0x6D,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0xA6, 0xA3, 0x66,
-  0x66, 0x66, 0xA3, 0x2F, 0xA3, 0x66, 0x66, 0x98,
-  0x66, 0x66, 0x98, 0x98, 0x98, 0x66, 0xA3, 0xA3,
-  0x83, 0xB2, 0x2F, 0x2F, 0xB2, 0xB2, 0xB2, 0x2F,
-  0x2F, 0x2F, 0xA3, 0x66, 0x66, 0x98, 0x98, 0x66,
-  0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0x66, 0xA6, 0x20,
-  0x3A, 0x3A, 0x54, 0x55, 0x7E, 0x6B, 0x6B, 0x6B,
-  0x4D, 0x3D, 0x6B, 0x6B, 0x6B, 0x57, 0x33, 0xEB,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x4D, 0xA2, 0x74, 0x39, 0x92, 0x20, 0x20, 0x6D,
-  0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x98,
-  0x98, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0x66, 0x66,
-  0x66, 0x66, 0x66, 0x66, 0x66, 0xA3, 0x66, 0xA3,
-  0x89, 0xA3, 0x66, 0x66, 0xA3, 0xA3, 0x2F, 0x2F,
-  0xA3, 0x2F, 0xA3, 0xA3, 0x66, 0x66, 0x66, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xB2, 0x3A, 0x20,
-  0xA7, 0x20, 0x3A, 0x39, 0x6B, 0x6B, 0x6B, 0x6B,
-  0xB5, 0xCB, 0x6B, 0x6B, 0x3D, 0x8A, 0x42, 0x3D,
-  0x6B, 0x6B, 0x6B, 0x84, 0x6C, 0x4D, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x7E, 0x83, 0x51, 0x20, 0x20, 0x20,
-  0x6D, 0x3A, 0x20, 0x20, 0x20, 0x20, 0xAD, 0x66,
-  0x66, 0x66, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0x66, 0xA3, 0xA3, 0xA3,
-  0xB2, 0x98, 0x66, 0x66, 0x98, 0x66, 0x66, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F,
-  0xA3, 0x2F, 0xA3, 0xA3, 0xA3, 0x2F, 0x20, 0x6D,
-  0x3A, 0x20, 0x98, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0xAA, 0x33, 0x6B, 0x6B, 0x3D, 0xF5, 0x7B, 0x3D,
-  0x6B, 0x6B, 0x4F, 0x4A, 0x58, 0x3D, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x7E, 0x7E, 0x9C, 0x54, 0xA7,
-  0x2E, 0xA7, 0x20, 0x20, 0x20, 0x20, 0x54, 0x51,
-  0x2F, 0x2F, 0xA3, 0x2F, 0xA3, 0xA3, 0xA3, 0xA3,
-  0x2F, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0x2F,
-  0xB2, 0x66, 0x66, 0x66, 0x66, 0xA3, 0x66, 0xA3,
-  0x66, 0x66, 0xA3, 0x2F, 0x2F, 0xB2, 0x2F, 0xB2,
-  0x2F, 0x2F, 0x2F, 0xA3, 0x2F, 0xA6, 0x20, 0xCE,
-  0x20, 0x6D, 0x4D, 0x6B, 0xD6, 0x7E, 0x6B, 0x6B,
-  0x6E, 0x9A, 0x57, 0x6B, 0x2D, 0x7B, 0x7B, 0x3D,
-  0x6B, 0x84, 0xF5, 0x7B, 0x84, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x98, 0x3A, 0x9C,
-  0xCE, 0x3A, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x98,
-  0xB2, 0xB2, 0x2F, 0x2F, 0x2F, 0xA3, 0x2F, 0x2F,
-  0x2F, 0xA3, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F,
-  0x89, 0xA3, 0x66, 0x66, 0xA3, 0x2F, 0x2F, 0xA3,
-  0x66, 0x66, 0xA3, 0xA3, 0x2F, 0x2F, 0xB2, 0xB2,
-  0xB2, 0x2F, 0x2F, 0x2F, 0x89, 0x54, 0x6D, 0x3A,
-  0x20, 0x98, 0x6B, 0x6B, 0xE0, 0xB4, 0x6B, 0x6B,
-  0x2D, 0x9E, 0x4A, 0x3D, 0x84, 0xF5, 0xF5, 0x84,
-  0x6B, 0x6E, 0x59, 0x6C, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x3D, 0x6B, 0x6B, 0x6B, 0x6B, 0xDD, 0xDA, 0x6D,
-  0x54, 0x20, 0xCE, 0x20, 0x20, 0x20, 0x20, 0xA7,
-  0x51, 0xB2, 0xB2, 0xB2, 0x2F, 0xB2, 0x2F, 0x2F,
-  0x2F, 0x66, 0x66, 0xA3, 0xA3, 0xA3, 0xA3, 0x66,
-  0x89, 0xA3, 0xA3, 0xA3, 0x2F, 0xB2, 0xB2, 0x2F,
-  0x66, 0x66, 0xA3, 0xA3, 0x2F, 0xA3, 0xA3, 0x2F,
-  0xB2, 0x2F, 0x2F, 0xA3, 0x98, 0x20, 0xA7, 0x20,
-  0x3A, 0x7E, 0x6B, 0x6B, 0x7F, 0xDE, 0xF6, 0x3D,
-  0x6B, 0xDB, 0x8A, 0xDB, 0xE9, 0xF3, 0xF3, 0xDB,
-  0x68, 0xF3, 0x73, 0x7F, 0x6B, 0x6B, 0x57, 0x58,
-  0xDC, 0x2D, 0x6B, 0x6B, 0x6B, 0x6B, 0x3A, 0x20,
-  0x20, 0x20, 0x6D, 0x54, 0x20, 0x20, 0x20, 0x20,
-  0x51, 0x2F, 0x2F, 0x2F, 0xA3, 0xA3, 0xA3, 0x66,
-  0xA3, 0x66, 0x98, 0x98, 0x66, 0x98, 0x98, 0x66,
-  0x2F, 0x66, 0x66, 0xA3, 0x2F, 0xB2, 0x2F, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0x66, 0xA3, 0xA3, 0xA3,
-  0x66, 0x98, 0x8F, 0x98, 0xCE, 0xDA, 0x2E, 0x20,
-  0x2A, 0x6B, 0x6B, 0x6B, 0x6B, 0x2C, 0x34, 0xCB,
-  0xEB, 0x6C, 0x31, 0x59, 0x82, 0x82, 0x8B, 0x82,
-  0xF3, 0x73, 0xE9, 0x6B, 0x3D, 0x6E, 0xF3, 0x4A,
-  0x4F, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x92, 0x20,
-  0x20, 0x20, 0x6D, 0x6D, 0x20, 0x20, 0x20, 0x20,
-  0xA3, 0xA3, 0x66, 0x98, 0x98, 0x8F, 0x8F, 0x98,
-  0x98, 0x98, 0x98, 0x66, 0x98, 0x66, 0x66, 0xA3,
-  0xA3, 0x66, 0x66, 0x66, 0xA3, 0x2F, 0x2F, 0xA3,
-  0xA3, 0xA3, 0x66, 0x66, 0xA3, 0xA3, 0xA3, 0x66,
-  0x8F, 0x55, 0xA5, 0x98, 0x20, 0x2E, 0x54, 0x54,
-  0x89, 0x6B, 0x6B, 0x6B, 0x6B, 0x84, 0xE3, 0x4A,
-  0x58, 0x42, 0x5B, 0x8B, 0x82, 0x82, 0x82, 0x82,
-  0x82, 0x59, 0x58, 0x57, 0x57, 0x59, 0x7B, 0x84,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0xAD, 0x20,
-  0x20, 0x20, 0x3A, 0x3A, 0x20, 0x20, 0x20, 0x20,
-  0x2A, 0x66, 0x8F, 0x55, 0xA5, 0xA5, 0xA0, 0x8F,
-  0x66, 0xA3, 0xA3, 0x66, 0x98, 0x66, 0x66, 0x2F,
-  0x2F, 0x2F, 0x2F, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F,
-  0xA3, 0x2F, 0xA3, 0xA3, 0x66, 0xA3, 0xA3, 0x66,
-  0x8F, 0xA5, 0x8F, 0x2E, 0x20, 0x2E, 0x20, 0x3A,
-  0x4D, 0x6B, 0xE6, 0x84, 0x3D, 0x6B, 0xEB, 0x4A,
-  0xC9, 0x8B, 0x8B, 0x31, 0x59, 0x82, 0x59, 0x59,
-  0x5B, 0x82, 0x59, 0x73, 0x7B, 0xDC, 0x57, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x55, 0x20,
-  0x20, 0x20, 0x6D, 0xDA, 0x20, 0x20, 0x20, 0x20,
-  0x9C, 0x66, 0x8F, 0xA5, 0xA5, 0x55, 0x8F, 0x66,
-  0x2F, 0xB2, 0x2F, 0x66, 0x98, 0x98, 0x2F, 0x51,
-  0x89, 0xB2, 0x2F, 0xA3, 0xA3, 0xB2, 0xB2, 0xB2,
-  0x2F, 0x2F, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0x66,
-  0x8F, 0xA5, 0x8F, 0x20, 0x20, 0xA7, 0x20, 0xA6,
-  0x6B, 0x6B, 0xE4, 0x48, 0x2C, 0xDB, 0x4F, 0x9E,
-  0xD0, 0xD0, 0x8B, 0x82, 0x82, 0x82, 0x82, 0x82,
-  0x59, 0x82, 0x82, 0x73, 0x7B, 0x68, 0x6B, 0x3D,
-  0x68, 0x68, 0x84, 0x3D, 0x6B, 0x6B, 0xA0, 0x20,
-  0x20, 0x20, 0x6D, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x6D, 0x2F, 0xA0, 0xA5, 0x55, 0x98, 0x66, 0xA3,
-  0xB2, 0x89, 0xB2, 0x98, 0x8F, 0x98, 0x2F, 0x51,
-  0x74, 0xB2, 0xA3, 0xA3, 0x2F, 0x2F, 0xB2, 0x2F,
-  0xA3, 0xA3, 0xA3, 0x66, 0x66, 0xA3, 0x2F, 0xA3,
-  0x98, 0xA3, 0x6D, 0x20, 0x20, 0xCE, 0x20, 0x2A,
-  0x6B, 0x6B, 0xEB, 0x2C, 0xE1, 0xF1, 0x7C, 0xD0,
-  0x8B, 0x8B, 0x82, 0x82, 0x82, 0x82, 0x82, 0x59,
-  0x82, 0x82, 0x42, 0x82, 0x31, 0x57, 0x4F, 0x7B,
-  0x7B, 0xF5, 0xF6, 0xDB, 0x6B, 0x6B, 0x98, 0x20,
-  0x20, 0x20, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x51, 0x66, 0xA0, 0xA0, 0x66, 0x2F, 0xB2,
-  0xB2, 0x51, 0x2F, 0xA0, 0x55, 0xA3, 0x51, 0x89,
-  0x44, 0xA3, 0x98, 0x98, 0x2F, 0x2F, 0x2F, 0xA3,
-  0xA3, 0x66, 0x98, 0x98, 0x98, 0xA3, 0x2F, 0x2F,
-  0x98, 0x8F, 0x20, 0x20, 0x3A, 0xA6, 0x20, 0xA0,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x7F, 0x7F, 0xC3, 0xC9,
-  0xD0, 0xD0, 0x29, 0x59, 0x82, 0x73, 0x82, 0x73,
-  0x59, 0x59, 0x59, 0x59, 0x59, 0x58, 0xAF, 0xF5,
-  0x8A, 0x68, 0xEB, 0x6B, 0x6B, 0x6B, 0x98, 0x20,
-  0x20, 0x20, 0x6D, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x51, 0x98, 0x55, 0xA0, 0xA3, 0xB2, 0x51,
-  0x51, 0x2F, 0x98, 0x55, 0x8F, 0xB2, 0x89, 0x44,
-  0xA3, 0x55, 0x55, 0x98, 0xA3, 0xB2, 0x2F, 0xA3,
-  0x66, 0x66, 0x98, 0x8F, 0x66, 0xA3, 0x66, 0x98,
-  0x55, 0x4C, 0x20, 0x20, 0xDA, 0xAD, 0x20, 0x98,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x3D, 0x9A, 0xD0,
-  0xF2, 0x8B, 0x8B, 0x8B, 0x73, 0x82, 0x5B, 0x82,
-  0x82, 0x59, 0x59, 0x73, 0x73, 0x58, 0x3D, 0x3D,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x66, 0x20,
-  0x20, 0x3A, 0x3A, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x2F, 0x55, 0xA5, 0x8F, 0xA3, 0x51, 0x51,
-  0xB2, 0xA3, 0x66, 0x66, 0xA3, 0xB2, 0x89, 0x51,
-  0x98, 0xA5, 0x55, 0x8F, 0x2F, 0xB2, 0xB2, 0xA3,
-  0x66, 0x66, 0x98, 0x98, 0x98, 0x66, 0x66, 0x8F,
-  0x8F, 0x92, 0x20, 0x20, 0x20, 0x6D, 0x6D, 0xA3,
-  0x6B, 0x6B, 0xEB, 0x7F, 0x4F, 0xDB, 0xD2, 0xC9,
-  0xC9, 0xD0, 0x8B, 0x8B, 0x73, 0x82, 0x59, 0x8B,
-  0x59, 0x82, 0x59, 0x59, 0x73, 0xF5, 0xEB, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x55, 0x20,
-  0x20, 0xA7, 0x54, 0xDA, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x98, 0xA0, 0x8F, 0xA3, 0xB2, 0x51, 0x51,
-  0x51, 0x2F, 0xA3, 0xA3, 0xB2, 0xB2, 0x51, 0xB2,
-  0xA0, 0xA5, 0x55, 0x66, 0x2F, 0x51, 0x2F, 0xA3,
-  0x66, 0x66, 0x66, 0x98, 0x66, 0x66, 0x98, 0x98,
-  0x98, 0x2A, 0x54, 0x95, 0x95, 0x71, 0x2E, 0x98,
-  0x6B, 0x6B, 0x4D, 0x28, 0xDE, 0x88, 0xB7, 0x70,
-  0xC9, 0xC9, 0xD0, 0xF2, 0x8B, 0x8B, 0x8B, 0x59,
-  0x59, 0x59, 0x59, 0x5B, 0x59, 0xF3, 0x57, 0xE9,
-  0xDB, 0x84, 0x6B, 0x6B, 0x6B, 0x6B, 0x4C, 0xDA,
-  0x2E, 0xDA, 0x20, 0xDA, 0x2E, 0x2E, 0x6D, 0x20,
-  0x4C, 0x98, 0x66, 0xA3, 0x2F, 0xB2, 0x51, 0x51,
-  0xB2, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F,
-  0xA0, 0xA0, 0x8F, 0x2F, 0xB2, 0x89, 0xB2, 0xA3,
-  0x66, 0x66, 0x98, 0x66, 0x66, 0x66, 0x66, 0xA3,
-  0x2F, 0xD1, 0xE2, 0x52, 0x52, 0xF4, 0xBF, 0x9C,
-  0x39, 0x6B, 0x6B, 0x6B, 0x7F, 0x4F, 0xE3, 0x6A,
-  0xD0, 0xC9, 0xC9, 0xD0, 0xD0, 0x8B, 0x8B, 0x82,
-  0x5B, 0x5B, 0x73, 0x8B, 0x59, 0x23, 0x6E, 0x31,
-  0x59, 0x7B, 0xDB, 0x84, 0x68, 0x7F, 0xAE, 0x54,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0xA6, 0x3A,
-  0xA0, 0xA3, 0xA3, 0x2F, 0x51, 0x51, 0x51, 0xB2,
-  0x2F, 0xA3, 0x66, 0x66, 0xA3, 0xA3, 0xA3, 0xA3,
-  0x8F, 0x8F, 0x66, 0x2F, 0x51, 0x51, 0xB2, 0xA3,
-  0x66, 0x98, 0x98, 0x66, 0x66, 0xA3, 0x2F, 0x2F,
-  0x3C, 0x88, 0x8D, 0x52, 0x52, 0x5D, 0xF7, 0xBF,
-  0xCE, 0xA2, 0x6B, 0x6B, 0x6B, 0x6B, 0x7F, 0x85,
-  0x70, 0xC9, 0xC9, 0xC9, 0xD0, 0xEA, 0x8B, 0x5B,
-  0x82, 0xEA, 0x82, 0x82, 0x42, 0x57, 0x3D, 0x68,
-  0x68, 0x57, 0x4A, 0x34, 0x22, 0xCC, 0x21, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0xDA, 0xA7, 0x6D,
-  0xDF, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0x2F, 0x2F,
-  0xA3, 0x66, 0x66, 0x66, 0xA3, 0xA3, 0x2F, 0x2F,
-  0x66, 0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0x2F, 0x66,
-  0x8F, 0x8F, 0x8F, 0x98, 0xA3, 0xA3, 0x89, 0xD8,
-  0x25, 0x5C, 0x3B, 0x5D, 0x52, 0x80, 0x70, 0x36,
-  0x71, 0xA7, 0x44, 0x6B, 0x84, 0xCB, 0xAA, 0xF3,
-  0xC9, 0xC9, 0xC9, 0xC9, 0xD0, 0x8B, 0x5B, 0x5B,
-  0x5B, 0xEA, 0x82, 0x47, 0x7B, 0x68, 0x3D, 0x3D,
-  0x6B, 0x3D, 0x6C, 0x2B, 0x80, 0x61, 0x96, 0x81,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x3A, 0xDA, 0x63,
-  0xAC, 0x6C, 0xB2, 0xB2, 0xB2, 0xB2, 0x2F, 0xA3,
-  0xA3, 0x66, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F,
-  0x66, 0x98, 0x66, 0xA3, 0xB2, 0xB2, 0x2F, 0x66,
-  0x8F, 0x8F, 0x2F, 0xD8, 0xE4, 0xCD, 0xAA, 0xB4,
-  0x78, 0x2B, 0x3B, 0x70, 0x46, 0x5D, 0x5D, 0x52,
-  0x9D, 0x81, 0x3A, 0xA3, 0xCD, 0x48, 0xBE, 0x4F,
-  0xC3, 0xC9, 0xD0, 0xD0, 0xD0, 0xEA, 0x5B, 0x8B,
-  0x5B, 0x82, 0x8B, 0x59, 0x4A, 0xF3, 0x33, 0x7F,
-  0x3D, 0x6B, 0x4F, 0x6F, 0x5D, 0x52, 0x63, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x75, 0x85,
-  0x72, 0xDC, 0xD8, 0x2F, 0xA3, 0x2F, 0xA3, 0xA3,
-  0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
-  0xA3, 0x98, 0x66, 0x2F, 0xB2, 0x51, 0xA3, 0x98,
-  0xA0, 0xA3, 0x93, 0xCF, 0x79, 0x27, 0x5C, 0x79,
-  0x2B, 0x30, 0x80, 0x80, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x3F, 0x69, 0x20, 0x20, 0x2A, 0xD6, 0x3D, 0x6B,
-  0x84, 0xE3, 0x34, 0xB7, 0xC9, 0xD0, 0xD0, 0xF2,
-  0xD0, 0x8B, 0x31, 0x68, 0x68, 0x6E, 0x31, 0x33,
-  0x7F, 0x7E, 0xA1, 0x6F, 0x52, 0x8D, 0xE5, 0xBF,
-  0x20, 0x20, 0x20, 0x20, 0x81, 0xA8, 0x78, 0x52,
-  0x52, 0xD2, 0xD8, 0xA3, 0xA3, 0x2F, 0x2F, 0xA3,
-  0xA3, 0x66, 0x98, 0x98, 0x98, 0x98, 0x98, 0x66,
-  0x51, 0x66, 0x2F, 0x51, 0x51, 0xB2, 0xA3, 0xA0,
-  0xA0, 0x44, 0x78, 0xEF, 0x52, 0x30, 0x30, 0x30,
-  0x3B, 0x70, 0x5D, 0x5D, 0x5D, 0x80, 0x5D, 0x5D,
-  0x46, 0xC1, 0x71, 0x20, 0x81, 0xB1, 0xDD, 0x3D,
-  0xA1, 0xE7, 0xDB, 0xCA, 0xD2, 0x6A, 0x6A, 0x6A,
-  0xF3, 0xE9, 0xDB, 0x8A, 0x84, 0x3D, 0x84, 0xDC,
-  0x25, 0x44, 0xB5, 0xEE, 0x30, 0xEF, 0xF0, 0x32,
-  0x69, 0x5F, 0x4B, 0xA8, 0x99, 0x56, 0x67, 0x30,
-  0x30, 0x34, 0xB2, 0x2F, 0xA3, 0xA3, 0x66, 0x66,
-  0x98, 0x8F, 0x98, 0x98, 0x66, 0x66, 0x66, 0x66,
-  0x51, 0x2F, 0xB2, 0x51, 0x51, 0x2F, 0x66, 0xA0,
-  0x8F, 0xE0, 0xF9, 0x8D, 0x52, 0x5D, 0x46, 0x5D,
-  0x80, 0x5D, 0x80, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x52, 0x52, 0x60, 0x81, 0x20, 0x20, 0x6D, 0xD1,
-  0x48, 0xE7, 0x6B, 0x33, 0xF6, 0x7F, 0x7F, 0xDB,
-  0x84, 0x6B, 0x6C, 0x6A, 0xF3, 0xEB, 0x6B, 0x3D,
-  0x4F, 0xD8, 0xCD, 0x79, 0x30, 0x67, 0xF9, 0x24,
-  0xED, 0xD9, 0x8C, 0xED, 0x37, 0x2B, 0x3B, 0x5D,
-  0x80, 0x85, 0x4E, 0x98, 0x66, 0x66, 0x66, 0x66,
-  0x66, 0x66, 0x66, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F,
-  0x51, 0x2F, 0xB2, 0xB2, 0xB2, 0xA3, 0x8F, 0x8F,
-  0x98, 0xE0, 0xF0, 0x67, 0x5D, 0x80, 0x80, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x80, 0x5D, 0x5D, 0x5D,
-  0x5D, 0x70, 0x27, 0x4B, 0x20, 0x81, 0x71, 0x3A,
-  0xB5, 0xEB, 0x3D, 0xF1, 0xE1, 0x84, 0x84, 0xF1,
-  0xE3, 0x3D, 0x6B, 0x6C, 0x34, 0xE7, 0x6B, 0x6B,
-  0xD6, 0x74, 0x5E, 0x78, 0x67, 0x30, 0xEE, 0x5C,
-  0xF9, 0xF9, 0x45, 0x5C, 0x2B, 0x3B, 0x5D, 0x5D,
-  0x5D, 0x5D, 0xF8, 0x44, 0x66, 0x66, 0x66, 0x66,
-  0x2F, 0x2F, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2,
-  0xB2, 0x2F, 0xA3, 0xA3, 0xA3, 0x98, 0x8F, 0x98,
-  0x66, 0x83, 0x76, 0x67, 0x30, 0x80, 0x5D, 0x80,
-  0x5D, 0x5D, 0x80, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x80, 0x5D, 0x22, 0xFA, 0x20, 0x81, 0x20, 0x20,
-  0xA5, 0x6B, 0x6B, 0xE8, 0xBE, 0x3D, 0x6B, 0x2C,
-  0xE1, 0xEB, 0x6B, 0x3D, 0x3E, 0xA1, 0x6B, 0x6B,
-  0x4D, 0x74, 0xE8, 0x62, 0x67, 0x30, 0x8D, 0x67,
-  0xEE, 0xEE, 0xEE, 0x67, 0x30, 0x80, 0x5D, 0x5D,
-  0x52, 0x5D, 0x85, 0xAC, 0x3E, 0xA3, 0x66, 0x66,
-  0x2F, 0x51, 0x51, 0x51, 0x51, 0xB2, 0x2F, 0x2F,
-  0x2F, 0xA3, 0xA3, 0x66, 0x98, 0x8F, 0x8F, 0x66,
-  0x2F, 0x83, 0xBC, 0xEE, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x80, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x22, 0xB0, 0xAE, 0x81, 0x20, 0x20,
-  0x4C, 0x3D, 0xEB, 0x39, 0x57, 0x6B, 0x6B, 0x3E,
-  0x97, 0x3D, 0x6B, 0x3D, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x3D, 0x3C, 0xBA, 0x62, 0xEE, 0x5D, 0x5D, 0x30,
-  0x30, 0x8D, 0x8D, 0x30, 0x52, 0x5D, 0x5D, 0x80,
-  0x5D, 0x5D, 0x5D, 0x85, 0xB0, 0x6E, 0x2F, 0x66,
-  0x2F, 0xB2, 0x51, 0xB2, 0x2F, 0x2F, 0xA3, 0xA3,
-  0xB2, 0xA3, 0x66, 0x98, 0x98, 0x8F, 0x98, 0xA3,
-  0x2F, 0x51, 0xDE, 0x8E, 0x30, 0x5D, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x52, 0x80, 0x5D, 0x22, 0x43, 0x4B, 0x20, 0x6D,
-  0x44, 0x6B, 0x6B, 0x3D, 0x6B, 0x6B, 0x6B, 0x4D,
-  0x3D, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x3D, 0x6B,
-  0x4D, 0x2A, 0xAE, 0x76, 0xEE, 0x30, 0x80, 0x80,
-  0x80, 0x80, 0x80, 0x80, 0x5D, 0x5D, 0x5D, 0x80,
-  0x5D, 0x5D, 0x80, 0x80, 0x5D, 0x7A, 0xB6, 0x51,
-  0xB2, 0xB2, 0xB2, 0xA3, 0x66, 0x66, 0x66, 0xA3,
-  0x2F, 0x66, 0x98, 0x8F, 0xA0, 0x98, 0xA3, 0x2F,
-  0x2F, 0x51, 0xAB, 0x8E, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x80,
-  0x5D, 0x80, 0x5D, 0x52, 0x52, 0x94, 0x2F, 0x7E,
-  0x6B, 0x3D, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x7E,
-  0xAD, 0x54, 0xAE, 0x24, 0x2B, 0x3B, 0x5D, 0x52,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x80, 0x5D, 0x5D, 0x80,
-  0x5D, 0x52, 0x52, 0x5D, 0x5D, 0x5D, 0xD2, 0x3E,
-  0x89, 0x89, 0xB2, 0xA3, 0x66, 0x98, 0x66, 0x66,
-  0x2F, 0x66, 0x8F, 0x8F, 0xA0, 0x98, 0xA3, 0xB2,
-  0x2F, 0x51, 0xDE, 0x79, 0x5D, 0x80, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x80, 0x5D, 0x52, 0x6F, 0xA4, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x4D, 0xA2, 0xCE,
-  0x20, 0x20, 0x95, 0x24, 0x67, 0x3B, 0x80, 0x80,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x80, 0x5D, 0x5D, 0x5D, 0x5D, 0x30, 0xB0, 0x86,
-  0x89, 0x51, 0x2F, 0x66, 0x98, 0x98, 0xA3, 0xA3,
-  0xA3, 0x66, 0x8F, 0xA0, 0x8F, 0x66, 0x2F, 0xB2,
-  0x2F, 0x4E, 0x76, 0x2B, 0x30, 0x5D, 0x5D, 0x5D,
-  0x80, 0x80, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x80, 0x5D, 0x5D, 0x5D, 0x46, 0x52, 0x21, 0x74,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
-  0x6B, 0x6B, 0x6B, 0x6B, 0x7E, 0x98, 0x3A, 0x20,
-  0x20, 0x81, 0x60, 0xED, 0x2B, 0x52, 0x5D, 0x5D,
-  0x80, 0x5D, 0x5D, 0x80, 0x5D, 0x5D, 0x5D, 0x80,
-  0x22, 0x5D, 0x5D, 0x5D, 0x8D, 0x2B, 0x38, 0x39,
-  0x51, 0x66, 0x8F, 0xA0, 0xA0, 0x8F, 0x98, 0x66,
-  0x66, 0x66, 0x8F, 0x55, 0x8F, 0xA3, 0xB2, 0xB2,
-  0xA3, 0xE8, 0xF9, 0x30, 0x3B, 0x80, 0x5D, 0x5D,
-  0x5D, 0x80, 0x80, 0x5D, 0x5D, 0x5D, 0x80, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x52, 0x30, 0xD4, 0x99,
-  0x51, 0x4D, 0x6B, 0x6B, 0x6B, 0x6B, 0x4D, 0x6B,
-  0x6B, 0x6B, 0x7E, 0xA3, 0x2E, 0x20, 0x20, 0x20,
-  0x20, 0x81, 0xC5, 0xED, 0x2B, 0x3B, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x80, 0x5D, 0x5D, 0x80,
-  0x5D, 0x52, 0x52, 0x6F, 0xDE, 0x2C, 0x39, 0x51,
-  0x66, 0xA0, 0xA5, 0xA5, 0x55, 0x8F, 0x66, 0x66,
-  0xA0, 0xA0, 0xA0, 0xA0, 0x8F, 0xA3, 0x2F, 0x2F,
-  0x51, 0xD5, 0x45, 0x8D, 0x3B, 0x5D, 0x80, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D,
-  0x80, 0x5D, 0x5D, 0x5D, 0x52, 0x67, 0x37, 0xA9,
-  0x3A, 0xCE, 0xA0, 0x2F, 0x51, 0x51, 0xB2, 0xA3,
-  0xA5, 0x9C, 0x54, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x54, 0x99, 0xED, 0x67, 0x30, 0x5D, 0x5D,
-  0x5D, 0x80, 0x5D, 0x5D, 0x5D, 0x5D, 0x3B, 0x80,
-  0x8D, 0x79, 0x48, 0x2C, 0x39, 0x44, 0xB2, 0x66,
-  0xA0, 0x2A, 0xA5, 0xA0, 0x8F, 0x66, 0xA3, 0xA3,
-  0xA0, 0x8F, 0x8F, 0xA0, 0x8F, 0xA3, 0xB2, 0xB2,
-  0xD8, 0xBC, 0x45, 0xEE, 0x67, 0x8D, 0x30, 0x30,
-  0x52, 0x52, 0x80, 0x5D, 0x5D, 0x5D, 0x5D, 0x80,
-  0x5D, 0x5D, 0x5D, 0x80, 0x3B, 0x67, 0xF9, 0x32,
-  0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0xBF, 0xEC, 0xED, 0x2B, 0x30, 0x5D, 0x5D,
-  0x80, 0x5D, 0x5D, 0x5D, 0x52, 0x30, 0x67, 0x2B,
-  0xCF, 0xAA, 0xD8, 0x89, 0x89, 0x51, 0x66, 0x55,
-  0x2A, 0x2A, 0xA5, 0x8F, 0x66, 0xA3, 0x2F, 0x2F,
-  0xA3, 0xA3, 0x66, 0x98, 0x98, 0x2F, 0xB2, 0x2F,
-  0xD1, 0x28, 0x56, 0xED, 0x62, 0x37, 0x5C, 0x79,
-  0x8E, 0x2B, 0x2B, 0x30, 0x30, 0x30, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x80, 0x3B, 0xEE, 0x56, 0xA9,
-  0x75, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x5F, 0x99, 0xD9, 0x45, 0x8D, 0x3B, 0x5D,
-  0x5D, 0x3B, 0x5D, 0x8D, 0x2B, 0x79, 0x79, 0x41,
-  0x83, 0xB2, 0xB2, 0x89, 0x89, 0x2F, 0xA0, 0x2A,
-  0xAD, 0xA5, 0x98, 0x66, 0xA3, 0xB2, 0x2F, 0xB2,
-  0xD8, 0xB2, 0xA3, 0x98, 0x98, 0x2F, 0x51, 0xB2,
-  0xA3, 0x83, 0x3E, 0x25, 0xD5, 0xE5, 0x50, 0x8C,
-  0xED, 0x24, 0x24, 0xF0, 0x45, 0x8E, 0x2B, 0x30,
-  0x30, 0x5D, 0x3B, 0x30, 0xEE, 0xF0, 0xC6, 0x65,
-  0x75, 0x71, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x4B, 0xC5, 0x7D, 0x24, 0xEE, 0x67, 0x30,
-  0x30, 0x8D, 0x67, 0x8E, 0xF9, 0xF7, 0x97, 0xDD,
-  0x2F, 0x2F, 0x51, 0x89, 0x89, 0x2F, 0x55, 0x2A,
-  0xA5, 0x8F, 0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0xB2,
-  0xDD, 0xA3, 0x66, 0x98, 0x66, 0x2F, 0xB2, 0xB2,
-  0xA3, 0xA3, 0xB2, 0x51, 0x89, 0x44, 0xE0, 0x5E,
-  0x91, 0x9F, 0x9F, 0x7D, 0x7D, 0xD9, 0x24, 0xF0,
-  0x79, 0x8E, 0xEE, 0x8E, 0x24, 0x40, 0x65, 0x35,
-  0x69, 0x2E, 0x98, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F,
-  0x2F, 0xB2, 0xB2, 0xB2, 0x2F, 0x2F, 0x2F, 0x98,
-  0xA5, 0xA7, 0x95, 0xD7, 0x8C, 0xF0, 0x8E, 0x8E,
-  0xEE, 0x79, 0xF0, 0xED, 0x50, 0xE8, 0x89, 0x2F,
-  0xA3, 0xA3, 0xB2, 0x89, 0xB2, 0x66, 0xA0, 0x55,
-  0x8F, 0x98, 0x66, 0xA3, 0xB2, 0x51, 0x51, 0xB2,
-  0x74, 0xA0, 0xA0, 0x98, 0x66, 0xB2, 0xB2, 0xB2,
-  0xA3, 0xA3, 0x2F, 0xB2, 0xB2, 0xB2, 0xA3, 0x2F,
-  0x51, 0x83, 0xE4, 0x87, 0xB8, 0xFA, 0xA9, 0xC6,
-  0x40, 0x64, 0x64, 0x50, 0xD7, 0x65, 0x35, 0x60,
-  0x98, 0xB2, 0x66, 0x66, 0xA3, 0x2F, 0xA3, 0xA3,
-  0xA3, 0x2F, 0x2F, 0x2F, 0x2F, 0xA3, 0x2F, 0xB2,
-  0x89, 0xDD, 0x9B, 0xC0, 0x7D, 0x50, 0x8C, 0xED,
-  0xED, 0x8C, 0x40, 0x9F, 0x4E, 0x51, 0xB2, 0x2F,
-  0x2F, 0x2F, 0xB2, 0x51, 0xA3, 0x98, 0xA0, 0x55,
-  0xA0, 0xA0, 0x8F, 0x66, 0x2F, 0x51, 0xB2, 0xA3,
-  0xA3, 0x2A, 0x55, 0x98, 0xA3, 0x2F, 0xB2, 0x2F,
-  0x66, 0x66, 0x2F, 0xB2, 0xD1, 0x2F, 0x2F, 0xA3,
-  0xB2, 0xB2, 0xA3, 0x8F, 0xA3, 0x2F, 0xD1, 0x94,
-  0xEC, 0x65, 0x65, 0xC0, 0xC0, 0x35, 0x95, 0xC2,
-  0xA3, 0x98, 0x66, 0xA3, 0x2F, 0x2F, 0x2F, 0xA3,
-  0xA3, 0x2F, 0xB2, 0x2F, 0x2F, 0x2F, 0x2F, 0x51,
-  0x89, 0x44, 0xD1, 0x60, 0x35, 0xA9, 0x32, 0xC6,
-  0xD7, 0x32, 0x94, 0x44, 0x2F, 0xB2, 0xB2, 0xB2,
-  0xA3, 0x2F, 0xB2, 0x2F, 0xA3, 0x8F, 0xA0, 0xA0,
-  0x55, 0xA0, 0x8F, 0xA3, 0x51, 0x51, 0x2F, 0xA3,
-  0x8F, 0x2A, 0x55, 0x66, 0xA3, 0x2F, 0x2F, 0xB2,
-  0xA3, 0x66, 0x2F, 0xB2, 0x51, 0xB2, 0x2F, 0x66,
-  0xA3, 0xA3, 0x66, 0x8F, 0x8F, 0x8F, 0xA0, 0x2F,
-  0x5E, 0xDF, 0xB9, 0x60, 0x95, 0xD3, 0x89, 0x2F,
-  0xA3, 0x66, 0xA3, 0x2F, 0xB2, 0x2F, 0xA3, 0xA3,
-  0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0xB2,
-  0x51, 0x2F, 0x8F, 0x2F, 0xC4, 0xB9, 0x9B, 0xEC,
-  0x53, 0xB3, 0x4E, 0xA3, 0x2F, 0xB2, 0xB2, 0xB2,
-  0xA3, 0x66, 0xA3, 0xA3, 0x66, 0x8F, 0x8F, 0x8F,
-  0x8F, 0x8F, 0xA3, 0x51, 0x89, 0x51, 0xA3, 0x66,
-  0xA0, 0x55, 0x8F, 0xA3, 0x2F, 0x2F, 0x2F, 0xB2,
-  0x2F, 0xA3, 0x2F, 0x51, 0x51, 0xB2, 0xA3, 0x66,
-  0x66, 0xA3, 0x66, 0x66, 0x66, 0x66, 0x66, 0xA3,
-  0xB2, 0xC2, 0x74, 0xD8, 0xB2, 0xA3, 0xA3, 0xA3,
-  0x66, 0x66, 0x2F, 0x2F, 0xA3, 0x66, 0x66, 0x66,
-  0xA3, 0xA3, 0xB2, 0xB2, 0xB2, 0xB2, 0x2F, 0xB2,
-  0x2F, 0x66, 0xA0, 0x55, 0x98, 0x2F, 0x89, 0x89,
-  0x89, 0xB2, 0x2F, 0xA3, 0x2F, 0x51, 0x51, 0xB2,
-  0x2F, 0x66, 0xA3, 0xA3, 0x66, 0x66, 0x66, 0x66,
-  0x66, 0xA3, 0xB2, 0x89, 0xD8, 0x51, 0xA3, 0x98,
-  0x66, 0x98, 0x66, 0x2F, 0x2F, 0x2F, 0x2F, 0xB2,
-  0xB2, 0xA3, 0xA3, 0xB2, 0xB2, 0xB2, 0x2F, 0xA3,
-  0x66, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0xB2,
-  0x89, 0xD8, 0x89, 0x2F, 0x66, 0x66, 0xA3, 0xA3,
-  0x98, 0x98, 0x66, 0x66, 0x98, 0x98, 0x66, 0xA3,
-  0x2F, 0xA3, 0xB2, 0xB2, 0xB2, 0xB2, 0x2F, 0x2F,
-  0xB2, 0x2F, 0x66, 0x98, 0x66, 0xA3, 0x2F, 0x2F,
-  0x2F, 0xB2, 0x2F, 0xA3, 0xA3, 0xB2, 0xB2, 0x2F,
-  0x2F, 0x66, 0x66, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F,
-  0x2F, 0xB2, 0x89, 0xD8, 0x44, 0x2F, 0x66, 0x66,
-  0xA3, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0x2F,
-  0x2F, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F, 0xA3,
-  0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0xB2, 0x51, 0x51,
-  0x89, 0x89, 0xB2, 0xA3, 0x98, 0x66, 0xA3, 0x66,
-  0x98, 0x98, 0x98, 0x98, 0x98, 0x66, 0xA3, 0x2F,
-  0xA3, 0x2F, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2,
-  0xB2, 0x2F, 0xA3, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F,
-  0x2F, 0xB2, 0xB2, 0xA3, 0xA3, 0x2F, 0x2F, 0x2F,
-  0x2F, 0xA3, 0x66, 0xA3, 0x2F, 0xB2, 0xB2, 0xB2,
-  0x51, 0x51, 0x89, 0x89, 0xB2, 0xA3, 0x98, 0x66
-};
-
-unsigned char linux_logo_bw[] __initdata = {
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F,
-  0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFE, 0x3F, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xC7, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xC3,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF,
-  0xFB, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFD, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF,
-  0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xCF, 0xC3, 0xF8, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x87, 0x81, 0xF9,
-  0xF8, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xA7,
-  0x99, 0xF9, 0xC2, 0x40, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xF3, 0xBC, 0xF9, 0x90, 0x00, 0x1F, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xE3, 0xBC, 0xF9, 0xA0, 0x00,
-  0x8F, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0, 0x3C, 0xF9,
-  0x83, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0,
-  0x19, 0xF0, 0x1F, 0xFE, 0x0F, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xC0, 0x03, 0xF0, 0x3F, 0xF7, 0x8F, 0xFF,
-  0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8, 0x7F, 0xF7,
-  0xC7, 0xFF, 0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8,
-  0x6F, 0xF7, 0xE7, 0xFF, 0xFF, 0xFF, 0xF9, 0x80,
-  0x01, 0xF8, 0x7F, 0xF7, 0xE7, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xC0, 0x21, 0xD8, 0x7F, 0xE7, 0xEF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xB1, 0x80, 0xEC, 0x7B, 0xFF,
-  0xEF, 0xFF, 0xFF, 0xFF, 0xF1, 0x90, 0x00, 0xE4,
-  0x7B, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xF1, 0x8C,
-  0xC0, 0x7C, 0x79, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF,
-  0xE3, 0x80, 0x00, 0x7C, 0x7C, 0xFF, 0xCF, 0xFF,
-  0xFF, 0xFF, 0xE3, 0x80, 0x00, 0x7F, 0x77, 0xFF,
-  0xDF, 0xFF, 0xFF, 0xFF, 0x87, 0x00, 0x00, 0x3F,
-  0x3F, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0x0E, 0x00,
-  0x00, 0x3F, 0xBF, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF,
-  0x1E, 0x00, 0x00, 0x1F, 0x9F, 0xFF, 0x3F, 0xFF,
-  0xFF, 0xFE, 0x1C, 0x00, 0x00, 0x1F, 0x9F, 0xFF,
-  0x7F, 0xFF, 0xFF, 0xFE, 0x3C, 0x00, 0x00, 0x1F,
-  0x8F, 0xFE, 0x7F, 0xFF, 0xFF, 0xFC, 0x7C, 0x00,
-  0x00, 0x0F, 0xC7, 0xFC, 0xFF, 0xFF, 0xFF, 0xFC,
-  0xF8, 0x00, 0x00, 0x0F, 0xF7, 0xF9, 0xFF, 0xFF,
-  0xFF, 0xFC, 0xF8, 0x00, 0x00, 0x07, 0xFB, 0xF3,
-  0xFF, 0xFF, 0xFF, 0xF8, 0xF8, 0x00, 0x00, 0x07,
-  0xFD, 0xE7, 0xFF, 0xFF, 0xFF, 0xF9, 0xF0, 0x00,
-  0x00, 0x03, 0xFE, 0x8F, 0xFF, 0xFF, 0xFF, 0xF1,
-  0xF0, 0x00, 0x00, 0x03, 0xFE, 0x1F, 0xFF, 0xFF,
-  0xFF, 0xF1, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xBF,
-  0xFF, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x00, 0x00,
-  0xFE, 0xBF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC0, 0x00,
-  0x00, 0x00, 0xFE, 0x3F, 0xFF, 0xFF, 0xFF, 0xC7,
-  0xC0, 0x00, 0x00, 0x01, 0xFE, 0xBF, 0xFF, 0xFF,
-  0xFF, 0xC7, 0x80, 0x00, 0x00, 0x01, 0xFE, 0x9F,
-  0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x00, 0x01,
-  0xFE, 0x07, 0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00,
-  0x00, 0x01, 0xFE, 0x87, 0xFF, 0xFF, 0xFF, 0x9F,
-  0x80, 0x00, 0x00, 0x01, 0xFD, 0x33, 0xFF, 0xFF,
-  0xFF, 0x9F, 0x80, 0x00, 0x00, 0x01, 0x80, 0xF3,
-  0xFF, 0xFF, 0xFF, 0x9E, 0x80, 0x00, 0x00, 0x03,
-  0x8B, 0xF9, 0xFF, 0xFF, 0xFF, 0x9F, 0x80, 0x00,
-  0x00, 0x02, 0x27, 0xF8, 0xFF, 0xFF, 0xFF, 0x99,
-  0x80, 0x00, 0x00, 0x00, 0x07, 0xF8, 0xFF, 0xFF,
-  0xFF, 0x00, 0x80, 0x00, 0x00, 0x01, 0x8F, 0xF8,
-  0xFF, 0xFF, 0xFE, 0x20, 0x60, 0x00, 0x00, 0x00,
-  0xE3, 0xF8, 0xFF, 0xFF, 0xF8, 0x00, 0x30, 0x00,
-  0x00, 0x00, 0xF8, 0x78, 0xFF, 0xFF, 0xC0, 0x40,
-  0x38, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x7F, 0xFF,
-  0x81, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xFC, 0x20,
-  0x7F, 0xFF, 0x90, 0x00, 0x1E, 0x00, 0x00, 0x00,
-  0x78, 0x10, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0x80,
-  0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00,
-  0x07, 0xC0, 0x00, 0x00, 0x00, 0x08, 0xFF, 0xFF,
-  0xC0, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x04,
-  0x7F, 0xFF, 0x80, 0x00, 0x03, 0xC0, 0x00, 0x10,
-  0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x01, 0x80,
-  0x00, 0x30, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00,
-  0x00, 0x00, 0x00, 0x70, 0x00, 0x01, 0x4F, 0xFF,
-  0x80, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00,
-  0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x80, 0x03, 0xF0,
-  0x00, 0x00, 0x8F, 0xFF, 0x80, 0x00, 0x00, 0x40,
-  0x0F, 0xF0, 0x00, 0x04, 0x1F, 0xFF, 0x80, 0x00,
-  0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x10, 0x1F, 0xFF,
-  0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x40,
-  0xFF, 0xFF, 0x98, 0x00, 0x00, 0xFF, 0xFF, 0xF0,
-  0x00, 0x83, 0xFF, 0xFF, 0x81, 0xE0, 0x01, 0xFF,
-  0xFF, 0xF8, 0x02, 0x07, 0xFF, 0xFF, 0x80, 0x3F,
-  0x07, 0xE0, 0x00, 0x1C, 0x0C, 0x1F, 0xFF, 0xFF,
-  0xF8, 0x03, 0xFF, 0x80, 0x00, 0x1F, 0x78, 0x1F,
-  0xFF, 0xFF, 0xFF, 0x80, 0x7F, 0x00, 0x07, 0x0F,
-  0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0x0C, 0x07,
-  0xFF, 0x83, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0x00, 0x1F, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 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,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22,
+    0x22, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+    0x26, 0x26, 0x25, 0x28, 0x23, 0x22, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x25, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d,
+    0x2d, 0x2e, 0x2c, 0x2b, 0x2a, 0x25, 0x28, 0x22,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x24, 0x2a, 0x2c, 0x2f, 0x2c, 0x30, 0x30, 0x24,
+    0x25, 0x27, 0x2b, 0x2c, 0x2f, 0x31, 0x32, 0x25,
+    0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
+    0x33, 0x34, 0x35, 0x21, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x21, 0x2b, 0x2f, 0x2c,
+    0x30, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
+    0x2d, 0x27, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x31,
+    0x2d, 0x32, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x28, 0x2a, 0x34,
+    0x25, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x23, 0x32, 0x27, 0x21, 0x36,
+    0x2a, 0x2d, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x22, 0x26, 0x2c, 0x35,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x25, 0x2f, 0x37, 0x32, 0x22,
+    0x36, 0x35, 0x31, 0x27, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x22,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x26, 0x38, 0x38, 0x35, 0x25,
+    0x36, 0x21, 0x2d, 0x2b, 0x24, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x24, 0x39, 0x39, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x25, 0x2b, 0x30, 0x28, 0x22,
+    0x36, 0x36, 0x27, 0x34, 0x30, 0x23, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x26, 0x2d, 0x26, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x22, 0x22, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x2d, 0x33, 0x28, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x2b, 0x2c, 0x25, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x36, 0x36,
+    0x36, 0x21, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x21, 0x23, 0x22, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x28, 0x34, 0x27, 0x22, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
+    0x21, 0x21, 0x24, 0x27, 0x21, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x28, 0x27, 0x22, 0x33, 0x24, 0x36,
+    0x36, 0x36, 0x36, 0x22, 0x2f, 0x2a, 0x23, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
+    0x30, 0x3a, 0x38, 0x24, 0x24, 0x36, 0x36, 0x36,
+    0x23, 0x2f, 0x3b, 0x3c, 0x3d, 0x30, 0x25, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2f, 0x32, 0x23, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x23,
+    0x3e, 0x3f, 0x40, 0x3a, 0x22, 0x36, 0x36, 0x21,
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x3e, 0x23, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2f, 0x33, 0x28, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x2b,
+    0x44, 0x40, 0x46, 0x47, 0x35, 0x36, 0x36, 0x26,
+    0x43, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x2e, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x34, 0x36, 0x4d,
+    0x4e, 0x25, 0x2f, 0x46, 0x4a, 0x22, 0x23, 0x32,
+    0x4f, 0x50, 0x21, 0x31, 0x51, 0x52, 0x53, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x21, 0x3a,
+    0x4d, 0x21, 0x31, 0x54, 0x55, 0x28, 0x30, 0x2b,
+    0x4b, 0x4d, 0x36, 0x23, 0x32, 0x50, 0x3f, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x38, 0x23, 0x37,
+    0x55, 0x36, 0x28, 0x3a, 0x56, 0x57, 0x57, 0x58,
+    0x3c, 0x4d, 0x36, 0x36, 0x36, 0x40, 0x40, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x29, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x51, 0x23, 0x35,
+    0x43, 0x25, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e,
+    0x5f, 0x60, 0x61, 0x36, 0x31, 0x47, 0x3b, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x2c, 0x25, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x22,
+    0x40, 0x62, 0x63, 0x5d, 0x64, 0x65, 0x66, 0x67,
+    0x68, 0x69, 0x66, 0x5e, 0x6a, 0x6b, 0x2a, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x33, 0x2e, 0x26, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x2f, 0x23, 0x36,
+    0x6c, 0x63, 0x6d, 0x64, 0x5c, 0x66, 0x69, 0x6e,
+    0x6f, 0x70, 0x71, 0x69, 0x69, 0x72, 0x6c, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x33, 0x34, 0x27, 0x22,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x34, 0x26, 0x73,
+    0x74, 0x75, 0x76, 0x64, 0x65, 0x77, 0x69, 0x78,
+    0x70, 0x71, 0x71, 0x71, 0x72, 0x5f, 0x5e, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x25, 0x38, 0x2a, 0x23,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x33, 0x79,
+    0x63, 0x7a, 0x7b, 0x5c, 0x66, 0x69, 0x6e, 0x7c,
+    0x71, 0x71, 0x69, 0x7d, 0x7e, 0x7a, 0x7f, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x21, 0x51, 0x2b, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x32, 0x24,
+    0x80, 0x81, 0x64, 0x82, 0x77, 0x69, 0x71, 0x71,
+    0x69, 0x83, 0x84, 0x85, 0x7a, 0x85, 0x86, 0x36,
+    0x21, 0x2b, 0x23, 0x36, 0x36, 0x39, 0x2e, 0x26,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x2d, 0x33, 0x21,
+    0x87, 0x88, 0x89, 0x72, 0x67, 0x66, 0x5f, 0x89,
+    0x8a, 0x63, 0x85, 0x8b, 0x8c, 0x8d, 0x41, 0x36,
+    0x36, 0x2d, 0x3a, 0x35, 0x36, 0x24, 0x51, 0x32,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x33, 0x21,
+    0x55, 0x8e, 0x8f, 0x8a, 0x7d, 0x5e, 0x90, 0x7e,
+    0x75, 0x75, 0x90, 0x62, 0x40, 0x3f, 0x49, 0x23,
+    0x36, 0x24, 0x3a, 0x3a, 0x24, 0x36, 0x2e, 0x31,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x28, 0x33, 0x37, 0x25, 0x22,
+    0x3b, 0x50, 0x8e, 0x8f, 0x90, 0x7e, 0x90, 0x63,
+    0x74, 0x91, 0x92, 0x42, 0x93, 0x4b, 0x45, 0x2c,
+    0x36, 0x36, 0x33, 0x39, 0x21, 0x36, 0x22, 0x51,
+    0x33, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x22, 0x27, 0x2e, 0x2e, 0x36, 0x21,
+    0x94, 0x3f, 0x50, 0x95, 0x96, 0x8f, 0x8f, 0x97,
+    0x8e, 0x42, 0x50, 0x43, 0x47, 0x48, 0x48, 0x98,
+    0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39,
+    0x2e, 0x27, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x22, 0x24, 0x2b, 0x38, 0x28, 0x36, 0x32,
+    0x4c, 0x4b, 0x50, 0x50, 0x50, 0x42, 0x42, 0x50,
+    0x50, 0x40, 0x45, 0x99, 0x48, 0x48, 0x48, 0x48,
+    0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x23,
+    0x2f, 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x32, 0x51, 0x32, 0x28, 0x21, 0x98,
+    0x48, 0x47, 0x9a, 0x50, 0x50, 0x50, 0x50, 0x50,
+    0x9a, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x93, 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x2a, 0x2f, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x23, 0x30, 0x2e, 0x2c, 0x36, 0x21, 0x51, 0x9b,
+    0x48, 0x48, 0x52, 0x3f, 0x50, 0x50, 0x40, 0x4b,
+    0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2d, 0x31, 0x27, 0x23, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x27, 0x2c, 0x2d, 0x21, 0x36, 0x28, 0x44, 0x48,
+    0x48, 0x48, 0x48, 0x47, 0x46, 0x4f, 0x47, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x9c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x28, 0x51, 0x39, 0x26, 0x22, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
+    0x35, 0x51, 0x28, 0x36, 0x36, 0x9d, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x4f, 0x28, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x28, 0x38, 0x2b, 0x25, 0x22, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
+    0x51, 0x25, 0x36, 0x36, 0x23, 0x40, 0x9b, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x9b, 0x99, 0x2b, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x30, 0x2f, 0x33, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x23, 0x30, 0x34,
+    0x27, 0x36, 0x36, 0x36, 0x2a, 0x40, 0x47, 0x48,
+    0x48, 0x48, 0x48, 0x9b, 0x99, 0x99, 0x9b, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x47, 0x52,
+    0x46, 0x4f, 0x37, 0x21, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x30, 0x34, 0x2a, 0x23,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x22, 0x25, 0x39, 0x2c,
+    0x36, 0x36, 0x36, 0x21, 0x31, 0x4e, 0x9a, 0x4c,
+    0x47, 0x9b, 0x9b, 0x52, 0x46, 0x4f, 0x52, 0x9b,
+    0x9b, 0x9b, 0x47, 0x4f, 0x45, 0x9a, 0x93, 0x93,
+    0x3f, 0x93, 0x98, 0x28, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, 0x26,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x28,
+    0x36, 0x36, 0x36, 0x22, 0x38, 0x98, 0x44, 0x99,
+    0x9b, 0x48, 0x48, 0x9b, 0x4c, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x47, 0x52, 0x46, 0x43, 0x93,
+    0x40, 0x40, 0x43, 0x53, 0x21, 0x23, 0x33, 0x23,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x2f, 0x32,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x24, 0x2b, 0x31, 0x36,
+    0x36, 0x22, 0x36, 0x24, 0x9e, 0x4f, 0x9b, 0x48,
+    0x48, 0x48, 0x48, 0x9b, 0x99, 0x9f, 0x52, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x47,
+    0x4f, 0x9a, 0x3f, 0x46, 0x38, 0x36, 0x21, 0x30,
+    0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c,
+    0x25, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2e, 0x33, 0x36,
+    0x25, 0x25, 0x36, 0x4d, 0x52, 0x48, 0x48, 0x48,
+    0x47, 0x9f, 0x48, 0x48, 0x48, 0xa0, 0xa1, 0xa2,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x47, 0x44, 0x93, 0x43, 0x23, 0x36, 0x36,
+    0x26, 0x24, 0x36, 0x36, 0x36, 0x36, 0x28, 0x2f,
+    0x2a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x51, 0x24, 0x36,
+    0x2a, 0x36, 0x28, 0x44, 0x48, 0x48, 0x48, 0x48,
+    0xa3, 0xa4, 0x48, 0x48, 0x9f, 0xa5, 0xa6, 0x9f,
+    0x48, 0x48, 0x48, 0xa2, 0xa7, 0x47, 0x48, 0x48,
+    0x48, 0x48, 0x9b, 0x4b, 0x44, 0x37, 0x36, 0x23,
+    0x28, 0x30, 0x22, 0x36, 0x36, 0x36, 0x36, 0x2d,
+    0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x28, 0x2b, 0x34, 0x36, 0x25,
+    0x24, 0x36, 0x4a, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0xa8, 0xa1, 0x48, 0x48, 0x9f, 0xa9, 0xa6, 0x9f,
+    0x48, 0x48, 0xaa, 0xa1, 0xa5, 0x9f, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x9b, 0x52, 0x3f, 0x21, 0x30,
+    0x35, 0x25, 0x30, 0x36, 0x36, 0x36, 0x36, 0x32,
+    0x2d, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x22, 0x26, 0x2e, 0x35, 0x36, 0x2a,
+    0x36, 0x24, 0x4f, 0x48, 0x52, 0x52, 0x48, 0x48,
+    0xab, 0xac, 0xa0, 0x48, 0xad, 0xa6, 0xa6, 0x9f,
+    0x48, 0xa2, 0xa9, 0xa6, 0xa2, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x47, 0x32, 0x30,
+    0x2a, 0x23, 0x30, 0x23, 0x36, 0x36, 0x36, 0x21,
+    0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x2a, 0x51, 0x28, 0x28, 0x25,
+    0x36, 0x3a, 0x48, 0x48, 0xae, 0xaf, 0x48, 0x48,
+    0xad, 0xac, 0xa1, 0x9f, 0xa2, 0xa9, 0xa9, 0xa2,
+    0x48, 0xab, 0x78, 0xa7, 0x48, 0x48, 0x48, 0x48,
+    0x9f, 0x48, 0x48, 0x48, 0x48, 0x48, 0x38, 0x21,
+    0x36, 0x36, 0x22, 0x27, 0x36, 0x36, 0x36, 0x36,
+    0x2e, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x22, 0x25, 0x2c, 0x34, 0x36, 0x30, 0x21,
+    0x23, 0x43, 0x48, 0x48, 0xb0, 0xb1, 0xb2, 0x9f,
+    0x48, 0xb3, 0xa5, 0xb3, 0xab, 0xa9, 0xa9, 0xb3,
+    0xb4, 0xa9, 0xb5, 0xb0, 0x48, 0x48, 0xa0, 0xa5,
+    0xa1, 0xad, 0x48, 0x48, 0x48, 0x48, 0x94, 0x36,
+    0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36,
+    0x2a, 0x2e, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x2a, 0x51, 0x25, 0x21, 0x2a, 0x36,
+    0x2e, 0x9b, 0x48, 0x48, 0x48, 0xb6, 0xb7, 0xa4,
+    0xa2, 0xa7, 0xb5, 0x78, 0x6f, 0x6f, 0x6e, 0x6f,
+    0xa9, 0xb5, 0xab, 0x48, 0x9f, 0xab, 0xa9, 0xa1,
+    0xaa, 0x48, 0x48, 0x48, 0x48, 0x48, 0x98, 0x36,
+    0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36,
+    0x22, 0x2f, 0x30, 0x22, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x22, 0x25, 0x2c, 0x34, 0x36, 0x24, 0x28, 0x36,
+    0x54, 0x48, 0x48, 0x48, 0x48, 0xa2, 0xa8, 0xa1,
+    0xa5, 0xa6, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f,
+    0x6f, 0x78, 0xa5, 0xa0, 0xa0, 0x78, 0xa6, 0xa2,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36,
+    0x36, 0x36, 0x36, 0x30, 0x36, 0x36, 0x36, 0x36,
+    0x21, 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x28, 0x32, 0x2f, 0x28, 0x36, 0x27, 0x22, 0x21,
+    0x43, 0x48, 0x4b, 0xa2, 0x9f, 0x48, 0xa2, 0xa1,
+    0xb8, 0x6e, 0x6e, 0xb5, 0x78, 0x6f, 0x78, 0x78,
+    0x6e, 0x6f, 0x78, 0xb5, 0xa6, 0xa1, 0xa0, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4b, 0x21,
+    0x36, 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x25, 0x2c, 0x39, 0x36, 0x36, 0x30, 0x22, 0x25,
+    0x52, 0x48, 0xa3, 0xb1, 0xb6, 0xb3, 0xaa, 0xac,
+    0x68, 0x68, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
+    0x78, 0x6f, 0x6f, 0xb5, 0xa6, 0xb4, 0x48, 0x9f,
+    0xb4, 0xb4, 0xa2, 0x9f, 0x48, 0x48, 0x4f, 0x21,
+    0x36, 0x36, 0x22, 0x26, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x30, 0x2d, 0x21, 0x36, 0x36, 0x32, 0x23, 0x2a,
+    0x47, 0x48, 0xa2, 0xb6, 0xaf, 0xb9, 0xba, 0x68,
+    0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x78,
+    0x6f, 0x6f, 0xa6, 0x6f, 0xb5, 0xa0, 0xaa, 0xa6,
+    0xa6, 0xa9, 0xb2, 0xb3, 0x48, 0x48, 0x4c, 0x22,
+    0x36, 0x36, 0x24, 0x23, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0x2e, 0x36, 0x36, 0x23, 0x31, 0x27, 0x39,
+    0x9b, 0x48, 0x48, 0x48, 0xb0, 0xb0, 0xba, 0xb8,
+    0x68, 0x68, 0x69, 0x78, 0x6f, 0xb5, 0x6f, 0xb5,
+    0x78, 0x78, 0x78, 0x78, 0x78, 0xa5, 0xbb, 0xa9,
+    0xa5, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x23,
+    0x36, 0x36, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x2b, 0x39, 0x36, 0x36, 0x36, 0x26, 0x32, 0x31,
+    0x9b, 0x48, 0x48, 0x48, 0x48, 0x9f, 0xac, 0x68,
+    0xbc, 0x6e, 0x6e, 0x6e, 0xb5, 0x6f, 0x6e, 0x6f,
+    0x6f, 0x78, 0x78, 0xb5, 0xb5, 0xa5, 0x9f, 0x9f,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x46, 0x22,
+    0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x35, 0x39, 0x36, 0x36, 0x36, 0x36, 0x26, 0x2d,
+    0x9b, 0x48, 0x48, 0xb0, 0xaa, 0xb3, 0xbd, 0xb8,
+    0xb8, 0x68, 0x6e, 0x6e, 0xb5, 0x6f, 0x78, 0x6e,
+    0x78, 0x6f, 0x78, 0x78, 0xb5, 0xa9, 0xa2, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36,
+    0x24, 0x27, 0xbe, 0x24, 0x25, 0x28, 0x21, 0x36,
+    0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x25,
+    0x39, 0x4d, 0xbf, 0x84, 0x81, 0x57, 0x21, 0x39,
+    0x52, 0x48, 0x48, 0x62, 0xb1, 0xc0, 0xc1, 0xc1,
+    0xb8, 0xb8, 0x68, 0xbc, 0x6e, 0x6e, 0x6e, 0x78,
+    0x78, 0x78, 0x78, 0x6e, 0x78, 0xa9, 0xa0, 0xab,
+    0xb3, 0xa2, 0x48, 0x48, 0x48, 0x48, 0x53, 0x28,
+    0x23, 0x36, 0x36, 0x36, 0x21, 0x28, 0x2c, 0x30,
+    0x21, 0x38, 0x33, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x28, 0x30,
+    0x2d, 0xc2, 0x7a, 0xc3, 0xc4, 0xc4, 0x7f, 0x22,
+    0x51, 0x52, 0x48, 0x48, 0xb0, 0xaa, 0xa8, 0xbd,
+    0x68, 0xb8, 0xb8, 0x68, 0x68, 0x6e, 0x6e, 0x6f,
+    0x6e, 0x6e, 0xb5, 0x6e, 0x78, 0xab, 0xab, 0xb5,
+    0x78, 0xa6, 0xb3, 0xc5, 0xac, 0xac, 0xc6, 0x61,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x30, 0x32,
+    0x25, 0x4d, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x24, 0x26, 0x30, 0x33, 0x31,
+    0x4d, 0x91, 0x5b, 0xc3, 0xc4, 0xc4, 0xc4, 0x5a,
+    0x21, 0x2e, 0x46, 0x48, 0x48, 0x48, 0xb0, 0x64,
+    0xc1, 0xb8, 0xb8, 0xb8, 0x68, 0x71, 0x6e, 0x6e,
+    0x6f, 0x71, 0x6f, 0x6f, 0xa6, 0xa0, 0x9f, 0xb4,
+    0xb4, 0xa0, 0xa1, 0xb7, 0xc7, 0x69, 0x66, 0xc8,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x26, 0x25,
+    0x83, 0xc9, 0x2c, 0x25, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x30, 0x35, 0x2d, 0x2f, 0x37, 0x4a,
+    0x60, 0x85, 0xca, 0xcb, 0xc4, 0xc4, 0xc4, 0x82,
+    0x86, 0x36, 0x32, 0x3f, 0xa2, 0xa4, 0xa8, 0xa9,
+    0xb8, 0xb8, 0xb8, 0xb8, 0x68, 0x6e, 0x6e, 0x6e,
+    0x6e, 0x71, 0x6f, 0x71, 0xa6, 0xb4, 0x9f, 0x9f,
+    0x48, 0x48, 0x48, 0xcc, 0xc3, 0xc7, 0xcd, 0xce,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x57,
+    0x77, 0x66, 0x34, 0x27, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x23, 0x30, 0x31, 0xcf, 0x91, 0x7e, 0x90, 0x90,
+    0x8b, 0x5b, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0x5d, 0xd0, 0x36, 0x24, 0xd1, 0xb1, 0xaf, 0xaa,
+    0xba, 0xb8, 0x68, 0x68, 0x68, 0x71, 0x6e, 0x6e,
+    0x6e, 0x6f, 0x6e, 0x78, 0xa1, 0xa9, 0xa1, 0xb0,
+    0x9f, 0x9b, 0x99, 0xcc, 0x64, 0x5c, 0x8b, 0xd0,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x73, 0x5d,
+    0x82, 0x5c, 0xd2, 0x2a, 0x23, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x24, 0x2b, 0xcf, 0x8b, 0x5b, 0x76, 0x5b, 0x5b,
+    0x7b, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc7, 0x5e, 0x22, 0x36, 0x21, 0x3a, 0x99, 0x48,
+    0xa2, 0xa8, 0xb7, 0xc1, 0xb8, 0x68, 0x68, 0xbc,
+    0x68, 0x6e, 0xb5, 0xb4, 0xb4, 0xab, 0xb5, 0xa1,
+    0xb0, 0x4f, 0x3f, 0xd3, 0x7b, 0x7b, 0x85, 0x80,
+    0xbe, 0x36, 0x36, 0x36, 0x21, 0xd4, 0x7e, 0x7b,
+    0x64, 0x64, 0xd5, 0x35, 0x24, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x31, 0xd6, 0x5b, 0x64, 0xc3, 0xc3, 0xcb,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0x66, 0xd7, 0x36, 0x36, 0x36, 0x2c, 0x4b,
+    0xd8, 0xd9, 0xb3, 0xa8, 0xbd, 0xbd, 0xbd, 0xbd,
+    0xa9, 0xab, 0xb3, 0xa5, 0xa2, 0x9f, 0xa2, 0xa1,
+    0x6a, 0x9a, 0x3f, 0xda, 0x76, 0x76, 0x7a, 0x63,
+    0xdb, 0xdc, 0x86, 0xdc, 0xdd, 0x90, 0x5b, 0x64,
+    0xc3, 0xc3, 0xde, 0x2d, 0x27, 0x23, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x26, 0x2d, 0x91, 0x5b, 0x64, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc7, 0x83, 0xce, 0x36, 0x36, 0x36, 0x30,
+    0xb1, 0xd9, 0x48, 0xa1, 0xb2, 0xb0, 0xb0, 0xb3,
+    0xa2, 0x48, 0xa7, 0xbd, 0xa9, 0xa2, 0x48, 0x9f,
+    0xaa, 0x9a, 0x3f, 0xb1, 0x5b, 0x7b, 0xdf, 0x85,
+    0x7e, 0x90, 0x63, 0x90, 0x85, 0x5b, 0xc3, 0xc4,
+    0xc4, 0xcb, 0x5d, 0xd5, 0x39, 0x26, 0x23, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2d, 0xe0, 0xdf, 0x64, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc7, 0x88, 0x36, 0x36, 0x36, 0x36,
+    0x2d, 0x9b, 0x48, 0xb9, 0xaf, 0xa2, 0xa2, 0xb9,
+    0xa8, 0x9f, 0x48, 0xa7, 0xb7, 0xd9, 0x48, 0x48,
+    0x9b, 0x45, 0x3f, 0xe1, 0x6d, 0x7b, 0xca, 0xdf,
+    0x7a, 0x8b, 0x8b, 0x7a, 0x5b, 0x64, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc3, 0xe2, 0x37, 0x35, 0x26, 0x23,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2e, 0xe0, 0x7a, 0x7b, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc7, 0x72, 0x73, 0x36, 0x36, 0x36,
+    0x24, 0x52, 0x48, 0xa3, 0xaf, 0x9f, 0x48, 0xb6,
+    0xaf, 0xa2, 0x48, 0x9f, 0xe3, 0xd8, 0x48, 0x48,
+    0x48, 0x46, 0x42, 0xd6, 0x7a, 0x7b, 0x64, 0x7b,
+    0x76, 0x5b, 0x5b, 0x76, 0x7b, 0xc3, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xcb, 0x64, 0xe2, 0x4d, 0x2c, 0x27,
+    0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x25, 0x31, 0xe4, 0x8b, 0x7b, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc7, 0x89, 0xbe, 0x36, 0x36,
+    0x32, 0x47, 0x48, 0x4f, 0xa0, 0x48, 0x48, 0xe3,
+    0x92, 0x9f, 0x48, 0x9f, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x4b, 0x2f, 0x8f, 0x7a, 0x7b, 0xc3, 0xcb,
+    0xc3, 0x64, 0x64, 0xc3, 0xc3, 0xcb, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x5d, 0xe5, 0x2c,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x25, 0x31, 0xe4, 0x85, 0x7b, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0x66, 0x57, 0x27, 0x4d,
+    0x4b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x99, 0x34, 0xbe, 0xdb, 0x7a, 0x7b, 0xc3, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0xe4,
+    0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2d, 0xe4, 0x85, 0x7b, 0xcb, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc7, 0x5f, 0x92, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x44,
+    0x35, 0x36, 0xce, 0xdd, 0x7a, 0x7b, 0xcb, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0xc3, 0xe1,
+    0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x30, 0x2f, 0xd6, 0x8b, 0x7b, 0xcb, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0x66, 0x89, 0x45,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x4e, 0x25,
+    0x36, 0x36, 0x61, 0xdb, 0x6d, 0x64, 0xcb, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x7b, 0xdf, 0xe5,
+    0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0xe6, 0x63, 0xdf, 0xc3, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x72, 0x81, 0xe7,
+    0x46, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x3f, 0x2c, 0x36, 0x36,
+    0x36, 0x36, 0xe8, 0x8f, 0x6d, 0x64, 0xcb, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc3, 0xca, 0x8b, 0xcf, 0x2c,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x35, 0x96, 0x75, 0xca, 0xc3, 0xcb, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x7b, 0x81, 0xdb,
+    0x73, 0x3b, 0x44, 0x9b, 0x48, 0x48, 0x48, 0x9b,
+    0x99, 0x43, 0x94, 0x2c, 0x21, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x73, 0xdb, 0x7a, 0x7b, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0x64, 0x76, 0x7a, 0x91, 0xd5, 0x31, 0x30,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x39, 0x97, 0x75, 0xdf, 0x7b, 0x64, 0xc3, 0xc3,
+    0xcb, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0x7b, 0x7a, 0xe9,
+    0xea, 0x36, 0x21, 0x26, 0x2b, 0x39, 0x33, 0x30,
+    0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xea, 0xdd, 0x8b, 0x7b, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x64, 0x64,
+    0x76, 0x85, 0xe0, 0xd5, 0x34, 0x2b, 0x27, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0xeb, 0x63, 0x7e, 0x7a, 0x6d, 0xdf, 0x5b,
+    0x76, 0x7b, 0x64, 0x64, 0xc3, 0xcb, 0xc4, 0xc4,
+    0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x76, 0x85, 0xdb,
+    0x79, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xec, 0xdd, 0x75, 0x76, 0xc3, 0xc4,
+    0xc4, 0xc4, 0xcb, 0xc3, 0x64, 0x76, 0xdf, 0x8b,
+    0xd6, 0xd5, 0x2f, 0x35, 0x30, 0x24, 0x22, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x27, 0x31, 0xed, 0xeb, 0xdd, 0x74, 0x63, 0x90,
+    0x7e, 0x75, 0x8b, 0x6d, 0xdf, 0x76, 0x64, 0xc3,
+    0xcb, 0xcb, 0xcb, 0xcb, 0x64, 0x7a, 0x84, 0xee,
+    0x79, 0xbe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xea, 0xee, 0x63, 0x6d, 0x7b, 0x64,
+    0xcb, 0xc3, 0x64, 0x7b, 0xdf, 0x75, 0x63, 0x96,
+    0x38, 0x39, 0x2a, 0x24, 0x23, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x28, 0x27, 0x35, 0x2d, 0x41, 0xd5, 0xe7, 0x8f,
+    0xdb, 0xdd, 0xe9, 0x74, 0x84, 0x90, 0x85, 0x6d,
+    0x5b, 0x7b, 0x7b, 0xca, 0x6d, 0x90, 0xdb, 0xef,
+    0xec, 0x22, 0x36, 0x36, 0x28, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x25, 0x36,
+    0x36, 0x21, 0xd4, 0x80, 0xe9, 0x7e, 0x6d, 0x76,
+    0xca, 0x76, 0x6d, 0x85, 0x63, 0xdb, 0xd5, 0x34,
+    0x33, 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x24, 0x27, 0x2a, 0x35, 0x2e, 0x2f,
+    0x41, 0xf0, 0xf1, 0x6c, 0x80, 0xee, 0xdb, 0x74,
+    0x84, 0x90, 0x75, 0x7e, 0x74, 0x8f, 0xef, 0x79,
+    0xe8, 0x2b, 0x9d, 0x41, 0x2f, 0x34, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x34, 0x2f, 0x38,
+    0x4d, 0x37, 0xf2, 0xf3, 0x8f, 0x74, 0x63, 0x7e,
+    0x75, 0x7e, 0x63, 0xe9, 0x88, 0xe6, 0x31, 0x2a,
+    0x24, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x22, 0x23, 0x24, 0x26, 0x30,
+    0x33, 0x39, 0x2e, 0x51, 0x41, 0xd2, 0x6c, 0xf3,
+    0x80, 0xee, 0xee, 0xee, 0xf4, 0xf3, 0xd7, 0xf5,
+    0x41, 0x34, 0x35, 0x32, 0x30, 0x27, 0x27, 0x27,
+    0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x2a,
+    0x2b, 0x34, 0xf6, 0xec, 0xf7, 0x8f, 0xdd, 0xe9,
+    0xe9, 0xdd, 0xee, 0x6c, 0x41, 0x39, 0x27, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22,
+    0x28, 0x24, 0x26, 0x2a, 0x33, 0x2c, 0x2f, 0x41,
+    0xf8, 0xd7, 0x79, 0x79, 0x79, 0xec, 0xf9, 0x51,
+    0x39, 0x30, 0x24, 0x23, 0x22, 0x22, 0x22, 0x22,
+    0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23,
+    0x24, 0x2a, 0x31, 0xfa, 0xea, 0x79, 0xf3, 0x80,
+    0xf7, 0xdc, 0xfb, 0x2f, 0x35, 0x26, 0x23, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x22, 0x23, 0x28, 0x25, 0x30, 0x2b,
+    0x31, 0x2f, 0xf6, 0xfa, 0xfa, 0x2f, 0x2e, 0x33,
+    0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x27, 0x35, 0x34, 0xfa, 0xfa, 0xfa,
+    0xfc, 0xf6, 0x2e, 0x33, 0x25, 0x23, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x23, 0x28,
+    0x26, 0x30, 0x32, 0x2b, 0x33, 0x2a, 0x26, 0x28,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x25, 0x30, 0x33, 0x35, 0x35,
+    0x2b, 0x2a, 0x26, 0x28, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x21, 0x22, 0x23, 0x28, 0x28, 0x23, 0x22, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x23, 0x28, 0x24, 0x24,
+    0x28, 0x23, 0x22, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 };
 
-unsigned char linux_logo16_red[0];
-unsigned char linux_logo16_green[0];
-unsigned char linux_logo16_blue[0];
 unsigned char linux_logo16[0];
 
-#else
+#endif /* INCLUDE_LINUX_LOGO_DATA */
 
-/* prototypes only */
-extern unsigned char linux_logo_red[];
-extern unsigned char linux_logo_green[];
-extern unsigned char linux_logo_blue[];
-extern unsigned char linux_logo[];
-extern unsigned char linux_logo_bw[];
-extern unsigned char linux_logo16_red[];
-extern unsigned char linux_logo16_green[];
-extern unsigned char linux_logo16_blue[];
-extern unsigned char linux_logo16[];
+#include <linux/linux_logo.h>
 
-#endif
diff -u --recursive --new-file v2.4.5/linux/include/asm-sparc64/sab82532.h linux/include/asm-sparc64/sab82532.h
--- v2.4.5/linux/include/asm-sparc64/sab82532.h	Fri Apr 14 09:37:10 2000
+++ linux/include/asm-sparc64/sab82532.h	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: sab82532.h,v 1.6 2000/04/13 07:22:35 ecd Exp $
+/* $Id: sab82532.h,v 1.7 2001/05/23 23:09:10 ecd Exp $
  * sab82532.h: Register Definitions for the Siemens SAB82532 DUSCC
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -9,6 +9,7 @@
 
 #include <linux/types.h>
 #include <linux/serial.h>
+#include <linux/circ_buf.h>
 
 struct sab82532_async_rd_regs {
 	u8	rfifo[0x20];	/* Receive FIFO				*/
@@ -150,7 +151,7 @@
 	int				 close_delay;
 	unsigned short			 closing_wait;
 	unsigned short			 closing_wait2;
-	int				 all_sent;
+	unsigned long			 irqflags;
 	int				 is_console;
 	unsigned char			 interrupt_mask0;
 	unsigned char			 interrupt_mask1;
@@ -166,10 +167,7 @@
 	int				 blocked_open;
 	long				 session;
 	long				 pgrp;
-	unsigned char			*xmit_buf;
-	int				 xmit_head;
-	int				 xmit_tail;
-	int				 xmit_cnt;
+	struct circ_buf			 xmit;
 	struct tq_struct		 tqueue;
 	struct tq_struct		 tqueue_hangup;
 	struct async_icount		 icount;
@@ -181,6 +179,11 @@
 	struct sab82532			*next;
 	struct sab82532			*prev;
 };
+
+
+/* irqflags bits */
+#define SAB82532_ALLS			0x00000001
+#define SAB82532_XPR			0x00000002
 
 
 /* RFIFO Status Byte */
diff -u --recursive --new-file v2.4.5/linux/include/asm-sparc64/softirq.h linux/include/asm-sparc64/softirq.h
--- v2.4.5/linux/include/asm-sparc64/softirq.h	Sun Aug  6 12:42:21 2000
+++ linux/include/asm-sparc64/softirq.h	Tue Jun 12 11:08:46 2001
@@ -11,8 +11,21 @@
 #include <asm/system.h>		/* for membar() */
 
 #define local_bh_disable()	(local_bh_count(smp_processor_id())++)
-#define local_bh_enable()	(local_bh_count(smp_processor_id())--)
-
+#define __local_bh_enable()	(local_bh_count(smp_processor_id())--)
+#define local_bh_enable()			  \
+do { if (!--local_bh_count(smp_processor_id()) && \
+	 softirq_pending(smp_processor_id())) {   \
+		do_softirq();			  \
+		__sti();			  \
+     }						  \
+} while (0)
+#define __cpu_raise_softirq(cpu, nr)	(softirq_pending(cpu) |= (1<<nr))
+#define raise_softirq(nr)				\
+do {	unsigned long flags;				\
+	local_irq_save(flags);				\
+	__cpu_raise_softirq(smp_processor_id(), nr);	\
+	local_irq_restore(flags);			\
+} while (0)
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
 
 #endif /* !(__SPARC64_SOFTIRQ_H) */
diff -u --recursive --new-file v2.4.5/linux/include/asm-sparc64/string.h linux/include/asm-sparc64/string.h
--- v2.4.5/linux/include/asm-sparc64/string.h	Mon Oct 30 14:34:12 2000
+++ linux/include/asm-sparc64/string.h	Tue Jun 12 11:08:46 2001
@@ -1,4 +1,4 @@
-/* $Id: string.h,v 1.18 2000/10/30 21:01:41 davem Exp $
+/* $Id: string.h,v 1.19 2001/06/05 20:56:33 davem Exp $
  * string.h: External definitions for optimized assembly string
  *           routines for the Linux Kernel.
  *
@@ -105,6 +105,7 @@
 })
 
 #define __HAVE_ARCH_MEMCMP
+extern int memcmp(const void *,const void *,__kernel_size_t);
 
 /* Now the str*() stuff... */
 #define __HAVE_ARCH_STRLEN
diff -u --recursive --new-file v2.4.5/linux/include/asm-sparc64/termios.h linux/include/asm-sparc64/termios.h
--- v2.4.5/linux/include/asm-sparc64/termios.h	Fri Feb  9 11:37:03 2001
+++ linux/include/asm-sparc64/termios.h	Mon Jun 11 19:15:27 2001
@@ -1,4 +1,4 @@
-/* $Id: termios.h,v 1.10 2001/02/05 05:54:29 davem Exp $ */
+/* $Id: termios.h,v 1.11 2001/06/01 08:12:11 davem Exp $ */
 #ifndef _SPARC64_TERMIOS_H
 #define _SPARC64_TERMIOS_H
 
@@ -70,6 +70,7 @@
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14	/* synchronous PPP */
+#define N_HCI		15  /* Bluetooth HCI UART */
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.4.5/linux/include/linux/coda_cache.h linux/include/linux/coda_cache.h
--- v2.4.5/linux/include/linux/coda_cache.h	Tue Sep 19 15:08:59 2000
+++ linux/include/linux/coda_cache.h	Tue Jun 12 11:06:54 2001
@@ -19,4 +19,4 @@
 /* for downcalls and attributes and lookups */
 void coda_flag_inode_children(struct inode *inode, int flag);
 
-#endif _CFSNC_HEADER_
+#endif /* _CFSNC_HEADER_ */
diff -u --recursive --new-file v2.4.5/linux/include/linux/dcache.h linux/include/linux/dcache.h
--- v2.4.5/linux/include/linux/dcache.h	Fri May 25 18:01:26 2001
+++ linux/include/linux/dcache.h	Wed Jun 20 12:16:56 2001
@@ -68,12 +68,12 @@
 	unsigned int d_flags;
 	struct inode  * d_inode;	/* Where the name belongs to - NULL is negative */
 	struct dentry * d_parent;	/* parent directory */
-	struct list_head d_vfsmnt;
 	struct list_head d_hash;	/* lookup hash list */
 	struct list_head d_lru;		/* d_count = 0 LRU list */
 	struct list_head d_child;	/* child of parent list */
 	struct list_head d_subdirs;	/* our children */
 	struct list_head d_alias;	/* inode alias list */
+	int d_mounted;
 	struct qstr d_name;
 	unsigned long d_time;		/* used by d_revalidate */
 	struct dentry_operations  *d_op;
@@ -265,9 +265,10 @@
 
 static __inline__ int d_mountpoint(struct dentry *dentry)
 {
-	return !list_empty(&dentry->d_vfsmnt);
+	return dentry->d_mounted;
 }
 
+extern struct vfsmount *lookup_mnt(struct vfsmount *, struct dentry *);
 #endif /* __KERNEL__ */
 
 #endif	/* __LINUX_DCACHE_H */
diff -u --recursive --new-file v2.4.5/linux/include/linux/devfs_fs_kernel.h linux/include/linux/devfs_fs_kernel.h
--- v2.4.5/linux/include/linux/devfs_fs_kernel.h	Fri May 25 18:01:28 2001
+++ linux/include/linux/devfs_fs_kernel.h	Wed Jun 20 12:16:56 2001
@@ -163,7 +163,7 @@
 {
     return -ENOSYS;
 }
-static inline void *devfs_get_info (devfs_handle_t de, unsigned long size)
+static inline void *devfs_get_info (devfs_handle_t de)
 {
     return NULL;
 }
diff -u --recursive --new-file v2.4.5/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h
--- v2.4.5/linux/include/linux/ext2_fs.h	Fri May 25 18:01:27 2001
+++ linux/include/linux/ext2_fs.h	Wed Jun 20 12:16:56 2001
@@ -498,16 +498,17 @@
  * Ext2 directory file types.  Only the low 3 bits are used.  The
  * other bits are reserved for now.
  */
-#define EXT2_FT_UNKNOWN		0
-#define EXT2_FT_REG_FILE	1
-#define EXT2_FT_DIR		2
-#define EXT2_FT_CHRDEV		3
-#define EXT2_FT_BLKDEV 		4
-#define EXT2_FT_FIFO		5
-#define EXT2_FT_SOCK		6
-#define EXT2_FT_SYMLINK		7
-
-#define EXT2_FT_MAX		8
+enum {
+	EXT2_FT_UNKNOWN,
+	EXT2_FT_REG_FILE,
+	EXT2_FT_DIR,
+	EXT2_FT_CHRDEV,
+	EXT2_FT_BLKDEV,
+	EXT2_FT_FIFO,
+	EXT2_FT_SOCK,
+	EXT2_FT_SYMLINK,
+	EXT2_FT_MAX
+};
 
 /*
  * EXT2_DIR_PAD defines the directory entries boundaries
@@ -552,9 +553,6 @@
 extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
 
 /* dir.c */
-extern int ext2_check_dir_entry (const char *, struct inode *,
-				 struct ext2_dir_entry_2 *, struct buffer_head *,
-				 unsigned long);
 
 /* file.c */
 extern int ext2_read (struct inode *, struct file *, char *, int);
@@ -613,6 +611,14 @@
 
 /* dir.c */
 extern struct file_operations ext2_dir_operations;
+extern int ext2_add_link (struct dentry *, struct inode *);
+extern ino_t ext2_inode_by_name(struct inode *, struct dentry *);
+extern int ext2_make_empty(struct inode *, struct inode *);
+extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,struct dentry *, struct page **);
+extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *);
+extern int ext2_empty_dir (struct inode *);
+extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **);
+extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *);
 
 /* file.c */
 extern struct inode_operations ext2_file_inode_operations;
diff -u --recursive --new-file v2.4.5/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.4.5/linux/include/linux/fs.h	Fri May 25 18:01:28 2001
+++ linux/include/linux/fs.h	Wed Jun 20 12:16:56 2001
@@ -204,15 +204,22 @@
 
 extern void buffer_init(unsigned long);
 extern void inode_init(unsigned long);
+extern void mnt_init(unsigned long);
 
 /* bh state bits */
-#define BH_Uptodate	0	/* 1 if the buffer contains valid data */
-#define BH_Dirty	1	/* 1 if the buffer is dirty */
-#define BH_Lock		2	/* 1 if the buffer is locked */
-#define BH_Req		3	/* 0 if the buffer has been invalidated */
-#define BH_Mapped	4	/* 1 if the buffer has a disk mapping */
-#define BH_New		5	/* 1 if the buffer is new and not yet written out */
-#define BH_Protected	6	/* 1 if the buffer is protected */
+enum bh_state_bits {
+	BH_Uptodate,	/* 1 if the buffer contains valid data */
+	BH_Dirty,	/* 1 if the buffer is dirty */
+	BH_Lock,	/* 1 if the buffer is locked */
+	BH_Req,		/* 0 if the buffer has been invalidated */
+	BH_Mapped,	/* 1 if the buffer has a disk mapping */
+	BH_New,		/* 1 if the buffer is new and not yet written out */
+	BH_Protected,	/* 1 if the buffer is protected */
+
+	BH_PrivateStart,/* not a state bit, but the first bit available
+			 * for private allocation by other entities
+			 */
+};
 
 /*
  * Try to keep the most commonly used fields in single cache lines (16
@@ -835,6 +842,31 @@
 	int (*remount_fs) (struct super_block *, int *, char *);
 	void (*clear_inode) (struct inode *);
 	void (*umount_begin) (struct super_block *);
+
+	/* Following are for knfsd to interact with "interesting" filesystems
+	 * Currently just reiserfs, but possibly FAT and others later
+	 *
+	 * fh_to_dentry is given a filehandle fragement with length, and a type flag
+	 *   and must return a dentry for the referenced object or, if "parent" is
+	 *   set, a dentry for the parent of the object.
+	 *   If a dentry cannot be found, a "root" dentry should be created and
+	 *   flaged as DCACHE_NFSD_DISCONNECTED. nfsd_iget is an example implementation.
+	 *
+	 * dentry_to_fh is given a dentry and must generate the filesys specific
+	 *   part of the file handle.  Available length is passed in *lenp and used
+	 *   length should be returned therein.
+	 *   If need_parent is set, then dentry_to_fh should encode sufficient information
+	 *   to find the (current) parent.
+	 *   dentry_to_fh should return a 1byte "type" which will be passed back in
+	 *   the fhtype arguement to fh_to_dentry.  Type of 0 is reserved.
+	 *   If filesystem was exportable before the introduction of fh_to_dentry,
+	 *   types 1 and 2 should be used is that same way as the generic code.
+	 *   Type 255 means error.
+	 *
+	 * Lengths are in units of 4bytes, not bytes.
+	 */
+	struct dentry * (*fh_to_dentry)(struct super_block *sb, __u32 *fh, int len, int fhtype, int parent);
+	int (*dentry_to_fh)(struct dentry *, __u32 *fh, int *lenp, int need_parent);
 };
 
 /* Inode state bits.. */
@@ -1312,7 +1344,6 @@
 
 extern struct file_system_type *get_fs_type(const char *name);
 extern struct super_block *get_super(kdev_t);
-extern void put_super(kdev_t);
 static inline int is_mounted(kdev_t dev)
 {
 	struct super_block *sb = get_super(dev);
diff -u --recursive --new-file v2.4.5/linux/include/linux/ibmtr.h linux/include/linux/ibmtr.h
--- v2.4.5/linux/include/linux/ibmtr.h	Sun Apr  2 15:38:54 2000
+++ linux/include/linux/ibmtr.h	Wed Jun 20 11:13:18 2001
@@ -1,3 +1,6 @@
+#ifndef __LINUX_IBMTR_H__
+#define __LINUX_IBMTR_H__
+
 /* Definitions for an IBM Token Ring card. */
 /* This file is distributed under the GNU GPL   */
 
@@ -452,3 +455,4 @@
 	unsigned char funct_address[4];
 };
 
+#endif /* __LINUX_IBMTR_H__ */
diff -u --recursive --new-file v2.4.5/linux/include/linux/if_arp.h linux/include/linux/if_arp.h
--- v2.4.5/linux/include/linux/if_arp.h	Fri May 25 18:02:10 2001
+++ linux/include/linux/if_arp.h	Wed Jun 20 12:17:44 2001
@@ -79,6 +79,7 @@
 #define ARPHRD_FCFABRIC	787		/* Fibrechannel fabric		*/
 	/* 787->799 reserved for fibrechannel media types */
 #define ARPHRD_IEEE802_TR 800		/* Magic type ident for TR	*/
+#define ARPHRD_IEEE80211 801		/* IEEE 802.11			*/
 
 #define ARPHRD_VOID	  0xFFFF	/* Void type, nothing is known */
 
diff -u --recursive --new-file v2.4.5/linux/include/linux/if_tun.h linux/include/linux/if_tun.h
--- v2.4.5/linux/include/linux/if_tun.h	Wed Aug 23 09:30:13 2000
+++ linux/include/linux/if_tun.h	Mon Jun 11 19:15:27 2001
@@ -12,7 +12,7 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  *  GNU General Public License for more details.
  *
- *  $Id: if_tun.h,v 1.1 2000/08/23 05:59:28 davem Exp $
+ *  $Id: if_tun.h,v 1.2 2001/06/01 18:39:47 davem Exp $
  */
 
 #ifndef __IF_TUN_H
@@ -32,15 +32,18 @@
 #endif
 
 struct tun_struct {
-	char 			name[8];
+	char 			*name;
 	unsigned long 		flags;
+	int			attached;
+	uid_t			owner;
 
-	struct fasync_struct    *fasync;
 	wait_queue_head_t	read_wait;
+	struct sk_buff_head	readq;
 
 	struct net_device	dev;
-	struct sk_buff_head	txq;
-        struct net_device_stats	stats;
+	struct net_device_stats	stats;
+
+	struct fasync_struct    *fasync;
 
 #ifdef TUN_DEBUG	
 	int debug;
@@ -53,14 +56,8 @@
 
 #endif /* __KERNEL__ */
 
-/* Number of devices */
-#define TUN_MAX_DEV	255
-
-/* TX queue size */
-#define TUN_TXQ_SIZE	10
-
-/* Max frame size */
-#define TUN_MAX_FRAME	4096
+/* Read queue size */
+#define TUN_READQ_SIZE	10
 
 /* TUN device flags */
 #define TUN_TUN_DEV 	0x0001	
@@ -70,22 +67,25 @@
 #define TUN_FASYNC	0x0010
 #define TUN_NOCHECKSUM	0x0020
 #define TUN_NO_PI	0x0040
-
-#define TUN_IFF_SET	0x1000
+#define TUN_ONE_QUEUE	0x0080
+#define TUN_PERSIST 	0x0100	
 
 /* Ioctl defines */
-#define TUNSETNOCSUM (('T'<< 8) | 200) 
-#define TUNSETDEBUG  (('T'<< 8) | 201) 
-#define TUNSETIFF    (('T'<< 8) | 202) 
+#define TUNSETNOCSUM  _IOW('T', 200, int) 
+#define TUNSETDEBUG   _IOW('T', 201, int) 
+#define TUNSETIFF     _IOW('T', 202, int) 
+#define TUNSETPERSIST _IOW('T', 203, int) 
+#define TUNSETOWNER   _IOW('T', 204, int)
 
 /* TUNSETIFF ifr flags */
 #define IFF_TUN		0x0001
 #define IFF_TAP		0x0002
 #define IFF_NO_PI	0x1000
+#define IFF_ONE_QUEUE	0x2000
 
 struct tun_pi {
-   unsigned short flags;
-   unsigned short proto;
+	unsigned short flags;
+	unsigned short proto;
 };
 #define TUN_PKT_STRIP	0x0001
 
diff -u --recursive --new-file v2.4.5/linux/include/linux/interrupt.h linux/include/linux/interrupt.h
--- v2.4.5/linux/include/linux/interrupt.h	Fri May 25 18:01:27 2001
+++ linux/include/linux/interrupt.h	Wed Jun 20 12:16:56 2001
@@ -74,22 +74,6 @@
 asmlinkage void do_softirq(void);
 extern void open_softirq(int nr, void (*action)(struct softirq_action*), void *data);
 
-static inline void __cpu_raise_softirq(int cpu, int nr)
-{
-	softirq_active(cpu) |= (1<<nr);
-}
-
-
-/* I do not want to use atomic variables now, so that cli/sti */
-static inline void raise_softirq(int nr)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	__cpu_raise_softirq(smp_processor_id(), nr);
-	local_irq_restore(flags);
-}
-
 extern void softirq_init(void);
 
 
@@ -133,7 +117,7 @@
 enum
 {
 	TASKLET_STATE_SCHED,	/* Tasklet is scheduled for execution */
-	TASKLET_STATE_RUN	/* Tasklet is running (SMP only) */
+	TASKLET_STATE_RUN	/* Tasklet is running */
 };
 
 struct tasklet_head
@@ -144,44 +128,12 @@
 extern struct tasklet_head tasklet_vec[NR_CPUS];
 extern struct tasklet_head tasklet_hi_vec[NR_CPUS];
 
-#ifdef CONFIG_SMP
 #define tasklet_trylock(t) (!test_and_set_bit(TASKLET_STATE_RUN, &(t)->state))
-#define tasklet_unlock_wait(t) while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); }
 #define tasklet_unlock(t) clear_bit(TASKLET_STATE_RUN, &(t)->state)
-#else
-#define tasklet_trylock(t) 1
-#define tasklet_unlock_wait(t) do { } while (0)
-#define tasklet_unlock(t) do { } while (0)
-#endif
-
-static inline void tasklet_schedule(struct tasklet_struct *t)
-{
-	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
-		int cpu = smp_processor_id();
-		unsigned long flags;
-
-		local_irq_save(flags);
-		t->next = tasklet_vec[cpu].list;
-		tasklet_vec[cpu].list = t;
-		__cpu_raise_softirq(cpu, TASKLET_SOFTIRQ);
-		local_irq_restore(flags);
-	}
-}
-
-static inline void tasklet_hi_schedule(struct tasklet_struct *t)
-{
-	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
-		int cpu = smp_processor_id();
-		unsigned long flags;
-
-		local_irq_save(flags);
-		t->next = tasklet_hi_vec[cpu].list;
-		tasklet_hi_vec[cpu].list = t;
-		__cpu_raise_softirq(cpu, HI_SOFTIRQ);
-		local_irq_restore(flags);
-	}
-}
+#define tasklet_unlock_wait(t) while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); }
 
+extern void tasklet_schedule(struct tasklet_struct *t);
+extern void tasklet_hi_schedule(struct tasklet_struct *t);
 
 static inline void tasklet_disable_nosync(struct tasklet_struct *t)
 {
@@ -196,7 +148,14 @@
 
 static inline void tasklet_enable(struct tasklet_struct *t)
 {
-	atomic_dec(&t->count);
+	if (atomic_dec_and_test(&t->count))
+		tasklet_schedule(t);
+}
+
+static inline void tasklet_hi_enable(struct tasklet_struct *t)
+{
+	if (atomic_dec_and_test(&t->count))
+		tasklet_hi_schedule(t);
 }
 
 extern void tasklet_kill(struct tasklet_struct *t);
diff -u --recursive --new-file v2.4.5/linux/include/linux/irq.h linux/include/linux/irq.h
--- v2.4.5/linux/include/linux/irq.h	Fri May 25 18:01:27 2001
+++ linux/include/linux/irq.h	Wed Jun 20 12:16:56 2001
@@ -62,7 +62,4 @@
 extern hw_irq_controller no_irq_type;  /* needed in every arch ? */
 extern void no_action(int cpl, void *dev_id, struct pt_regs *regs);
 
-extern volatile unsigned long irq_err_count;
-
 #endif /* __asm_h */
-
diff -u --recursive --new-file v2.4.5/linux/include/linux/irq_cpustat.h linux/include/linux/irq_cpustat.h
--- v2.4.5/linux/include/linux/irq_cpustat.h	Fri May 25 18:01:26 2001
+++ linux/include/linux/irq_cpustat.h	Wed Jun 20 12:16:56 2001
@@ -26,8 +26,7 @@
 #endif	
 
   /* arch independent irq_stat fields */
-#define softirq_active(cpu)	__IRQ_STAT((cpu), __softirq_active)
-#define softirq_mask(cpu)	__IRQ_STAT((cpu), __softirq_mask)
+#define softirq_pending(cpu)	__IRQ_STAT((cpu), __softirq_pending)
 #define local_irq_count(cpu)	__IRQ_STAT((cpu), __local_irq_count)
 #define local_bh_count(cpu)	__IRQ_STAT((cpu), __local_bh_count)
 #define syscall_count(cpu)	__IRQ_STAT((cpu), __syscall_count)
diff -u --recursive --new-file v2.4.5/linux/include/linux/kernel.h linux/include/linux/kernel.h
--- v2.4.5/linux/include/linux/kernel.h	Sun May 20 12:11:39 2001
+++ linux/include/linux/kernel.h	Tue Jun 12 11:51:43 2001
@@ -125,6 +125,7 @@
 	unsigned long totalswap;	/* Total swap space size */
 	unsigned long freeswap;		/* swap space still available */
 	unsigned short procs;		/* Number of current processes */
+	unsigned short pad;		/* explicit padding for m68k */
 	unsigned long totalhigh;	/* Total high memory size */
 	unsigned long freehigh;		/* Available high memory size */
 	unsigned int mem_unit;		/* Memory unit size in bytes */
diff -u --recursive --new-file v2.4.5/linux/include/linux/linux_logo.h linux/include/linux/linux_logo.h
--- v2.4.5/linux/include/linux/linux_logo.h	Wed Sep 30 14:16:33 1998
+++ linux/include/linux/linux_logo.h	Mon Jun 11 19:15:27 2001
@@ -18,1428 +18,1403 @@
  * but should contain %s to display the version
  */
 
-#if LINUX_LOGO_COLORS == 214
+#ifndef __HAVE_ARCH_LINUX_LOGO
+#define LINUX_LOGO_COLORS	187
+#endif
+
+#ifdef INCLUDE_LINUX_LOGO_DATA
+
+#ifndef __HAVE_ARCH_LINUX_LOGO
 
 unsigned char linux_logo_red[] __initdata = {
-  0x02, 0x9E, 0xE9, 0xC4, 0x50, 0xC9, 0xC4, 0xE9,
-  0x65, 0xE3, 0xC2, 0x25, 0xA4, 0xEC, 0x90, 0xA6,
-  0xC4, 0x6A, 0xD1, 0xF3, 0x12, 0xED, 0xA0, 0xC2,
-  0xB8, 0xD5, 0xDB, 0xD2, 0x3E, 0x16, 0xEB, 0x54,
-  0xA9, 0xCD, 0xF5, 0x0A, 0xBA, 0xB3, 0xDC, 0x74,
-  0xCE, 0xF6, 0xD3, 0xC5, 0xEA, 0xB8, 0xED, 0x5E,
-  0xE5, 0x26, 0xF4, 0xA9, 0x82, 0x94, 0xE6, 0x38,
-  0xF2, 0x0F, 0x7F, 0x49, 0xE5, 0xF4, 0xD3, 0xC3,
-  0xC2, 0x1E, 0xD5, 0xC6, 0xA4, 0xFA, 0x0A, 0xBA,
-  0xD4, 0xEB, 0xEA, 0xEC, 0xA8, 0xBC, 0xB4, 0xDC,
-  0x84, 0xE4, 0xCE, 0xEC, 0x92, 0xCD, 0xDC, 0x8B,
-  0xCC, 0x1E, 0xF6, 0xB2, 0x60, 0x2A, 0x96, 0x52,
-  0x0F, 0xBD, 0xFA, 0xCC, 0xB8, 0x7A, 0x4C, 0xD2,
-  0x06, 0xEF, 0x44, 0x64, 0xF4, 0xBA, 0xCE, 0xE6,
-  0x8A, 0x6F, 0x3C, 0x70, 0x7C, 0x9C, 0xBA, 0xDF,
-  0x2C, 0x4D, 0x3B, 0xCA, 0xDE, 0xCE, 0xEE, 0x46,
-  0x6A, 0xAC, 0x96, 0xE5, 0x96, 0x7A, 0xBA, 0xB6,
-  0xE2, 0x7E, 0xAA, 0xC5, 0x96, 0x9E, 0xC2, 0xAA,
-  0xDA, 0x35, 0xB6, 0x82, 0x88, 0xBE, 0xC2, 0x9E,
-  0xB4, 0xD5, 0xDA, 0x9C, 0xA0, 0xD0, 0xA8, 0xC7,
-  0x72, 0xF2, 0xDB, 0x76, 0xDC, 0xBE, 0xAA, 0xF4,
-  0x87, 0x2F, 0x53, 0x8E, 0x36, 0xCE, 0xE6, 0xCA,
-  0xCB, 0xE4, 0xD6, 0xAA, 0x42, 0x5D, 0xB4, 0x59,
-  0x1C, 0xC8, 0x96, 0x6C, 0xDA, 0xCE, 0xE6, 0xCB,
-  0x96, 0x16, 0xFA, 0xBE, 0xAE, 0xFE, 0x6E, 0xD6,
-  0xCE, 0xB6, 0xE5, 0xED, 0xDB, 0xDC, 0xF4, 0x72,
-  0x1F, 0xAE, 0xE6, 0xC2, 0xCA, 0xC4
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65,
+    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+    0xc3, 0x65, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x76, 0x79,
+    0x62, 0x36, 0x9a, 0xe2, 0xec, 0xe1, 0xb8, 0xd7,
+    0xaf, 0x25, 0xbc, 0xc0, 0xef, 0xea, 0xe8, 0xe8,
+    0xf5, 0xf1, 0xda, 0xd3, 0x79, 0xdb, 0xf4, 0xf6,
+    0xf6, 0xf6, 0xe2, 0x3d, 0xb4, 0xce, 0xe6, 0xee,
+    0xf6, 0x68, 0xd8, 0xec, 0xf5, 0xc6, 0xc8, 0x9c,
+    0x89, 0xd2, 0xee, 0xcb, 0xb9, 0xd2, 0x66, 0x5e,
+    0x8b, 0xbe, 0xa8, 0xd5, 0xca, 0xb6, 0xae, 0x9c,
+    0xc5, 0xbe, 0xbe, 0xca, 0x90, 0xb2, 0x9a, 0xa8,
+    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x12,
+    0x4a, 0x8e, 0xf2, 0xf6, 0xf6, 0xee, 0xb5, 0xe4,
+    0xf1, 0x26, 0x9a, 0xea, 0xf6, 0xe0, 0xd2, 0x16,
+    0x9a, 0x2e, 0x70, 0xd6, 0x46, 0x7c, 0xb4, 0x62,
+    0xd6, 0xa3, 0x74, 0xa7, 0xa2, 0xca, 0xe0, 0xae,
+    0xbe, 0xce, 0xa3, 0x8e, 0x6d, 0x8e, 0x32, 0xaf,
+    0x50, 0x9e, 0x5b, 0x8a, 0x98, 0x82, 0x7a, 0x82,
+    0x56, 0x7c, 0x8a, 0x56, 0x5e, 0x86, 0x6a, 0x52,
+    0x59, 0x64, 0x5e,
 };
 
 unsigned char linux_logo_green[] __initdata = {
-  0x02, 0x88, 0xC4, 0x85, 0x44, 0xA2, 0xA8, 0xE5,
-  0x65, 0xA6, 0xC2, 0x24, 0xA4, 0xB4, 0x62, 0x86,
-  0x94, 0x44, 0xD2, 0xB6, 0x12, 0xD4, 0x73, 0x96,
-  0x92, 0x95, 0xB2, 0xC2, 0x36, 0x0E, 0xBC, 0x54,
-  0x75, 0xA5, 0xF5, 0x0A, 0xB2, 0x83, 0xC2, 0x74,
-  0x9B, 0xBD, 0xA2, 0xCA, 0xDA, 0x8C, 0xCB, 0x42,
-  0xAC, 0x12, 0xDA, 0x7B, 0x54, 0x94, 0xD2, 0x24,
-  0xBE, 0x06, 0x65, 0x33, 0xBB, 0xBC, 0xAB, 0x8C,
-  0x92, 0x1E, 0x9B, 0xB6, 0x6E, 0xFB, 0x04, 0xA2,
-  0xC8, 0xBD, 0xAD, 0xEC, 0x92, 0xBC, 0x7B, 0x9D,
-  0x84, 0xC4, 0xC4, 0xB4, 0x6C, 0x93, 0xA3, 0x5E,
-  0x8D, 0x13, 0xD6, 0x82, 0x4C, 0x2A, 0x7A, 0x5A,
-  0x0D, 0x82, 0xBB, 0xCC, 0x8B, 0x6A, 0x3C, 0xBE,
-  0x06, 0xC4, 0x44, 0x45, 0xDB, 0x96, 0xB6, 0xDE,
-  0x8A, 0x4D, 0x3C, 0x5A, 0x7C, 0x9C, 0xAA, 0xCB,
-  0x1C, 0x4D, 0x2E, 0xB2, 0xBE, 0xAA, 0xDE, 0x3E,
-  0x6A, 0xAC, 0x82, 0xE5, 0x72, 0x62, 0x92, 0x9E,
-  0xCA, 0x4A, 0x8E, 0xBE, 0x86, 0x6B, 0xAA, 0x9A,
-  0xBE, 0x34, 0xAB, 0x76, 0x6E, 0x9A, 0x9E, 0x62,
-  0x76, 0xCE, 0xD3, 0x92, 0x7C, 0xB8, 0x7E, 0xC6,
-  0x5E, 0xE2, 0xC3, 0x54, 0xAA, 0x9E, 0x8A, 0xCA,
-  0x63, 0x2D, 0x3B, 0x8E, 0x1A, 0x9E, 0xC2, 0xA6,
-  0xCB, 0xDC, 0xD6, 0x8E, 0x26, 0x5C, 0xB4, 0x45,
-  0x1C, 0xB8, 0x6E, 0x4C, 0xBC, 0xAE, 0xD6, 0x92,
-  0x63, 0x16, 0xF6, 0x8C, 0x7A, 0xFE, 0x6E, 0xBA,
-  0xC6, 0x86, 0xAA, 0xAE, 0xDB, 0xA4, 0xD4, 0x56,
-  0x0E, 0x6E, 0xB6, 0xB2, 0xBE, 0xBE
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65,
+    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+    0xc3, 0x62, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x62, 0x5c,
+    0x4e, 0x26, 0x72, 0xaa, 0xba, 0xaf, 0x90, 0xae,
+    0x92, 0x1a, 0xa4, 0x85, 0xb6, 0xbe, 0xc3, 0xc8,
+    0xcf, 0xd0, 0xc2, 0xce, 0x57, 0xa2, 0xd6, 0xda,
+    0xda, 0xd7, 0xb8, 0x2a, 0x7b, 0x91, 0xae, 0xca,
+    0xda, 0x45, 0x9e, 0xb2, 0xd7, 0x9b, 0x90, 0x76,
+    0x5c, 0xa2, 0xbe, 0xa6, 0x85, 0x96, 0x4e, 0x46,
+    0x66, 0x92, 0x7a, 0x9a, 0x96, 0x9d, 0x9a, 0x6b,
+    0x8a, 0x8e, 0xb2, 0xca, 0x90, 0xa6, 0x79, 0x7c,
+    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x0e,
+    0x36, 0x86, 0xba, 0xbe, 0xe6, 0xcc, 0x8e, 0xb8,
+    0xc4, 0x1e, 0x8e, 0xae, 0xba, 0xb2, 0xa6, 0x12,
+    0x7a, 0x20, 0x64, 0xaa, 0x2f, 0x70, 0x85, 0x46,
+    0xa6, 0x6e, 0x51, 0x72, 0x92, 0xa2, 0xa6, 0x87,
+    0x96, 0xa2, 0x85, 0x7a, 0x6a, 0x6e, 0x22, 0x76,
+    0x36, 0x76, 0x3c, 0x6e, 0x63, 0x53, 0x66, 0x62,
+    0x42, 0x50, 0x56, 0x42, 0x56, 0x56, 0x56, 0x3e,
+    0x51, 0x52, 0x56,
 };
 
 unsigned char linux_logo_blue[] __initdata = {
-  0x04, 0x28, 0x10, 0x0B, 0x14, 0x14, 0x74, 0xC7,
-  0x64, 0x0E, 0xC3, 0x24, 0xA4, 0x0C, 0x10, 0x20,
-  0x0D, 0x04, 0xD1, 0x0D, 0x13, 0x22, 0x0A, 0x40,
-  0x14, 0x0C, 0x11, 0x94, 0x0C, 0x08, 0x0B, 0x56,
-  0x09, 0x47, 0xF4, 0x0B, 0x9C, 0x07, 0x54, 0x74,
-  0x0F, 0x0C, 0x0F, 0xC7, 0x6C, 0x14, 0x14, 0x11,
-  0x0B, 0x04, 0x12, 0x0C, 0x05, 0x94, 0x94, 0x0A,
-  0x34, 0x09, 0x14, 0x08, 0x2F, 0x15, 0x19, 0x11,
-  0x28, 0x0C, 0x0B, 0x94, 0x08, 0xFA, 0x08, 0x7C,
-  0xBC, 0x15, 0x0A, 0xEC, 0x64, 0xBB, 0x0A, 0x0C,
-  0x84, 0x2C, 0xA0, 0x15, 0x10, 0x0D, 0x0B, 0x0E,
-  0x0A, 0x07, 0x10, 0x3C, 0x24, 0x2C, 0x28, 0x5C,
-  0x0A, 0x0D, 0x0A, 0xC1, 0x22, 0x4C, 0x10, 0x94,
-  0x04, 0x0F, 0x45, 0x08, 0x31, 0x54, 0x3C, 0xBC,
-  0x8C, 0x09, 0x3C, 0x18, 0x7C, 0x9C, 0x7C, 0x91,
-  0x0C, 0x4D, 0x17, 0x74, 0x0C, 0x48, 0x9C, 0x3C,
-  0x6A, 0xAC, 0x5C, 0xE3, 0x29, 0x3C, 0x2C, 0x7C,
-  0x6C, 0x04, 0x14, 0xA9, 0x74, 0x07, 0x2C, 0x74,
-  0x4C, 0x34, 0x97, 0x5C, 0x38, 0x0C, 0x5C, 0x04,
-  0x0C, 0xBA, 0xBC, 0x78, 0x18, 0x88, 0x24, 0xC2,
-  0x3C, 0xB4, 0x87, 0x0C, 0x14, 0x4C, 0x3C, 0x10,
-  0x17, 0x2C, 0x0A, 0x8C, 0x04, 0x1C, 0x44, 0x2C,
-  0xCD, 0xD8, 0xD4, 0x34, 0x0C, 0x5B, 0xB4, 0x1E,
-  0x1D, 0xAC, 0x24, 0x18, 0x20, 0x5C, 0xB4, 0x1C,
-  0x09, 0x14, 0xFC, 0x0C, 0x10, 0xFC, 0x6C, 0x7C,
-  0xB4, 0x1C, 0x15, 0x17, 0xDB, 0x18, 0x21, 0x24,
-  0x04, 0x04, 0x44, 0x8C, 0x8C, 0xB7
+    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+    0x12, 0x01, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x06, 0x65,
+    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+    0xc3, 0x59, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x2e, 0x08,
+    0x0a, 0x06, 0x0a, 0x0b, 0x0b, 0x0f, 0x0c, 0x0f,
+    0x3d, 0x09, 0x73, 0x09, 0x0d, 0x0a, 0x10, 0x1e,
+    0x2d, 0x13, 0x86, 0xba, 0x19, 0x0a, 0x36, 0x3c,
+    0x26, 0x14, 0x0d, 0x06, 0x07, 0x0a, 0x0b, 0x0f,
+    0x4a, 0x06, 0x0a, 0x0c, 0x2b, 0x0a, 0x0b, 0x0a,
+    0x06, 0x0a, 0x0a, 0x11, 0x0b, 0x0a, 0x0a, 0x1e,
+    0x0f, 0x0d, 0x0a, 0x0b, 0x22, 0x6a, 0x72, 0x0b,
+    0x0b, 0x22, 0x90, 0xca, 0x90, 0x92, 0x3c, 0x2c,
+    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x06,
+    0x0e, 0x6a, 0x0e, 0x0e, 0xbe, 0x5b, 0x2c, 0x3e,
+    0x0e, 0x0a, 0x5a, 0x0d, 0x0e, 0x3e, 0x0a, 0x06,
+    0x2e, 0x06, 0x4e, 0x36, 0x06, 0x58, 0x24, 0x06,
+    0x3a, 0x08, 0x08, 0x07, 0x5e, 0x45, 0x0a, 0x32,
+    0x2e, 0x2a, 0x43, 0x48, 0x5f, 0x2e, 0x06, 0x06,
+    0x07, 0x24, 0x06, 0x32, 0x06, 0x06, 0x46, 0x2e,
+    0x22, 0x06, 0x06, 0x1e, 0x4c, 0x06, 0x3a, 0x22,
+    0x42, 0x34, 0x42,
 };
 
 unsigned char linux_logo[] __initdata = {
-  0xBF, 0x95, 0x90, 0xCB, 0x95, 0xA1, 0x2C, 0x2C,
-  0x95, 0x55, 0xCB, 0x90, 0xCB, 0x95, 0x2C, 0x95,
-  0xCB, 0x47, 0x94, 0x95, 0xA1, 0xD6, 0xD6, 0x2C,
-  0x90, 0x47, 0x70, 0x2C, 0x6D, 0x2A, 0x6D, 0xD6,
-  0xA1, 0x2C, 0x55, 0x95, 0x2C, 0x2C, 0x55, 0x55,
-  0x95, 0xA1, 0xA1, 0xA1, 0x6D, 0xBF, 0x2A, 0x2A,
-  0xBF, 0x83, 0xBF, 0x95, 0x90, 0xCB, 0x95, 0xA1,
-  0x2C, 0x2C, 0x95, 0x55, 0xCB, 0x90, 0xCB, 0x95,
-  0x2C, 0x95, 0xCB, 0x47, 0x94, 0x95, 0xA1, 0xD6,
-  0xD6, 0x2C, 0x90, 0x47, 0x70, 0x2C, 0x6D, 0x2A,
-  0x95, 0x47, 0x47, 0x90, 0x2C, 0x2C, 0x2C, 0x95,
-  0x55, 0x55, 0xCB, 0x90, 0xCB, 0x55, 0x55, 0xCB,
-  0x47, 0xE6, 0x70, 0x95, 0xD6, 0xD6, 0xA1, 0x2C,
-  0x55, 0x55, 0x95, 0xD6, 0x6D, 0xD6, 0xA1, 0x2C,
-  0x2C, 0x95, 0x55, 0x95, 0x95, 0x95, 0x2C, 0x2C,
-  0xA1, 0xA1, 0x2C, 0x2C, 0xA1, 0xD6, 0xD6, 0xD6,
-  0xD6, 0xD6, 0x95, 0x47, 0x47, 0x90, 0x2C, 0x2C,
-  0x2C, 0x95, 0x55, 0x55, 0xCB, 0x90, 0xCB, 0x55,
-  0x55, 0xCB, 0x47, 0xE6, 0x70, 0x95, 0xD6, 0xD6,
-  0xA1, 0x2C, 0x55, 0x55, 0x95, 0xD6, 0x6D, 0xD6,
-  0x90, 0x47, 0x47, 0x70, 0x2C, 0xA1, 0x2C, 0x95,
-  0x55, 0x55, 0x90, 0xCB, 0x55, 0x55, 0x55, 0x70,
-  0x94, 0x70, 0x95, 0xA1, 0xD6, 0xD6, 0xA1, 0x2C,
-  0x95, 0x95, 0x2C, 0xA1, 0xD6, 0xA1, 0x2C, 0x2C,
-  0x95, 0x55, 0xCB, 0x95, 0xD6, 0xA1, 0x2C, 0x95,
-  0xA1, 0xD6, 0xD6, 0xA1, 0xA1, 0xD6, 0xA1, 0xA1,
-  0xA1, 0x2C, 0x90, 0x47, 0x47, 0x70, 0x2C, 0xA1,
-  0x2C, 0x95, 0x55, 0x55, 0x90, 0xCB, 0x55, 0x55,
-  0x55, 0x70, 0x94, 0x70, 0x95, 0xA1, 0xD6, 0xD6,
-  0xA1, 0x2C, 0x95, 0x95, 0x2C, 0xD6, 0xD6, 0xA1,
-  0x94, 0xA0, 0x47, 0x55, 0x2C, 0xD6, 0xA1, 0x95,
-  0x55, 0x55, 0xCB, 0xCB, 0x55, 0x55, 0xCB, 0xCB,
-  0x55, 0x95, 0x2C, 0xA1, 0xD6, 0xD6, 0xA1, 0x2C,
-  0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x95,
-  0x55, 0x55, 0x2C, 0x3F, 0x80, 0x20, 0x88, 0x88,
-  0x88, 0x20, 0x88, 0xB1, 0x2C, 0xA1, 0x2C, 0x2C,
-  0x95, 0xCB, 0x94, 0xA0, 0x47, 0x55, 0x2C, 0xD6,
-  0xA1, 0x95, 0x55, 0x55, 0xCB, 0xCB, 0x55, 0x55,
-  0xCB, 0xCB, 0x55, 0x95, 0x2C, 0xA1, 0xD6, 0xD6,
-  0xA1, 0x2C, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C,
-  0x94, 0x94, 0x70, 0x2C, 0xA1, 0xD6, 0xA1, 0x2C,
-  0x55, 0x55, 0xCB, 0x55, 0x55, 0x55, 0x55, 0x55,
-  0x95, 0x2C, 0xD6, 0xD6, 0xD6, 0xA1, 0x2C, 0x95,
-  0x55, 0x55, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
-  0x2C, 0x94, 0x80, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x88, 0x92, 0xA1, 0x95,
-  0x55, 0x90, 0x94, 0x94, 0x70, 0x2C, 0xA1, 0xD6,
-  0xA1, 0x2C, 0x55, 0x55, 0xCB, 0x55, 0x55, 0x55,
-  0x55, 0x55, 0x95, 0x2C, 0xD6, 0xD6, 0xD6, 0xA1,
-  0x2C, 0x95, 0x55, 0x55, 0x55, 0x95, 0x95, 0x95,
-  0x70, 0x70, 0x55, 0x2C, 0xD6, 0xD6, 0xA1, 0x95,
-  0x55, 0x90, 0xCB, 0xCB, 0x55, 0x55, 0x2C, 0x2C,
-  0xA1, 0xD6, 0xA1, 0xA1, 0x2C, 0x2C, 0x95, 0x55,
-  0x55, 0x55, 0x95, 0x95, 0x2C, 0x95, 0x95, 0xD6,
-  0xB1, 0x88, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x80, 0x34, 0x88, 0x43, 0x47,
-  0x95, 0xCB, 0x70, 0x70, 0x55, 0x2C, 0xD6, 0xD6,
-  0xA1, 0x95, 0x55, 0x90, 0xCB, 0xCB, 0x55, 0x55,
-  0x2C, 0x2C, 0xA1, 0xD6, 0xA1, 0xA1, 0xA1, 0x2C,
-  0x55, 0x55, 0x55, 0x55, 0x2C, 0x95, 0x2C, 0x2C,
-  0x55, 0x55, 0x95, 0x2C, 0xA1, 0xA1, 0x2C, 0x55,
-  0x90, 0x70, 0x90, 0x55, 0x95, 0x95, 0xA1, 0xA1,
-  0xA1, 0xA1, 0xA1, 0xA1, 0x2C, 0x95, 0x95, 0x95,
-  0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0xD5,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x88, 0x7D, 0x3F, 0xB1, 0x80, 0x20,
-  0x99, 0x2C, 0x55, 0x55, 0x95, 0x2C, 0xA1, 0xA1,
-  0x2C, 0x55, 0x90, 0x70, 0x90, 0x55, 0x95, 0x95,
-  0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0x2C, 0x2C, 0x2C,
-  0x95, 0x55, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C,
-  0x95, 0x90, 0x55, 0x2C, 0xA1, 0xA1, 0x95, 0xCB,
-  0x70, 0x94, 0x90, 0x55, 0x95, 0xA1, 0xA1, 0xA1,
-  0x2C, 0x2C, 0x2C, 0x2C, 0x95, 0x95, 0x95, 0x95,
-  0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0xA1, 0x88,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0xB1, 0x47, 0xD5, 0x7D, 0x43,
-  0x20, 0x70, 0x95, 0x90, 0x55, 0x2C, 0xA1, 0xA1,
-  0x95, 0xCB, 0x70, 0x94, 0x90, 0x55, 0x95, 0xA1,
-  0xA1, 0xA1, 0x2C, 0x95, 0x2C, 0x2C, 0x95, 0x95,
-  0x95, 0x95, 0x95, 0x2C, 0x95, 0x95, 0x95, 0x95,
-  0x95, 0x90, 0x55, 0x2C, 0xD6, 0xD6, 0x2C, 0x90,
-  0x94, 0x70, 0x55, 0x95, 0x2C, 0xD6, 0xD6, 0xA1,
-  0x95, 0x95, 0x95, 0x2C, 0x2C, 0x95, 0x55, 0x55,
-  0xCB, 0xCB, 0xCB, 0x55, 0xCB, 0x55, 0x47, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x88, 0xB1, 0x3F, 0x92, 0x2B, 0x80,
-  0x20, 0x80, 0xD6, 0x70, 0x55, 0x2C, 0xD6, 0xD6,
-  0x2C, 0x90, 0x94, 0x70, 0x55, 0x95, 0x2C, 0xD6,
-  0xD6, 0xA1, 0x2C, 0x95, 0x95, 0x2C, 0x2C, 0x95,
-  0x95, 0x55, 0x90, 0xCB, 0xCB, 0xCB, 0xCB, 0x55,
-  0xD6, 0x55, 0x95, 0xA1, 0xD6, 0xA1, 0x55, 0x70,
-  0x94, 0x55, 0x95, 0xA1, 0xA1, 0xA1, 0xA1, 0x95,
-  0x55, 0x55, 0x55, 0x95, 0x55, 0x55, 0xCB, 0x90,
-  0x70, 0x90, 0xCB, 0x55, 0x55, 0xA1, 0xD8, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x88, 0xD8, 0xE1, 0x88, 0x20, 0x20,
-  0x88, 0x88, 0xE6, 0x55, 0x2C, 0xA1, 0xD6, 0xA1,
-  0x55, 0x70, 0x94, 0x55, 0x95, 0xA1, 0xA1, 0xA1,
-  0xA1, 0x95, 0x55, 0x55, 0x95, 0x95, 0x55, 0x55,
-  0x90, 0x90, 0x90, 0x90, 0xCB, 0x55, 0x55, 0x55,
-  0xD6, 0x2C, 0xA1, 0xD6, 0xD6, 0xA1, 0xCB, 0x70,
-  0x70, 0x95, 0x2C, 0xA1, 0xA1, 0x2C, 0x2C, 0x55,
-  0xCB, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
-  0x55, 0x95, 0x2C, 0x95, 0x2C, 0xD6, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x80, 0xD6, 0xA1, 0xD6, 0xD6, 0xA1,
-  0xCB, 0x70, 0x70, 0x95, 0x2C, 0xA1, 0xA1, 0x2C,
-  0x2C, 0x55, 0xCB, 0xCB, 0x55, 0x55, 0x55, 0x55,
-  0x55, 0x55, 0x55, 0x95, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xD6, 0xA1, 0xA1, 0xA1, 0xA1, 0x55, 0x70, 0x94,
-  0xCB, 0x95, 0xA1, 0xA1, 0x2C, 0x95, 0xCB, 0x55,
-  0x90, 0xCB, 0x55, 0x55, 0x55, 0x55, 0x95, 0xA1,
-  0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0x95, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x88, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x88, 0x95, 0xA1, 0xA1, 0xA1, 0x55,
-  0x70, 0x94, 0xCB, 0x95, 0xA1, 0xA1, 0x2C, 0x95,
-  0xCB, 0xCB, 0x90, 0xCB, 0x55, 0x55, 0x55, 0x55,
-  0x95, 0x2C, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1,
-  0x2C, 0x2C, 0x2C, 0x95, 0x95, 0xCB, 0x70, 0x70,
-  0x95, 0x2C, 0x2C, 0x95, 0xCB, 0x70, 0x90, 0xCB,
-  0xCB, 0x55, 0x55, 0xCB, 0x55, 0x55, 0x2C, 0xD6,
-  0xD6, 0xD6, 0xD6, 0xA1, 0x2C, 0x70, 0x20, 0x20,
-  0x88, 0x43, 0xD8, 0x43, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x88, 0x88, 0x43, 0x2B, 0xD8, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x3F, 0x2C, 0x95, 0x95, 0xCB,
-  0x70, 0x70, 0x95, 0x2C, 0x2C, 0x95, 0xCB, 0x90,
-  0x90, 0xCB, 0x55, 0xCB, 0x55, 0xCB, 0x55, 0x95,
-  0x2C, 0xD6, 0xD6, 0xD6, 0xD6, 0xA1, 0x2C, 0x2C,
-  0xA1, 0x95, 0x95, 0x55, 0xCB, 0x70, 0x90, 0x55,
-  0x2C, 0x2C, 0x2C, 0x55, 0x70, 0x70, 0x55, 0x95,
-  0x95, 0xCB, 0x90, 0x90, 0x90, 0x95, 0x2C, 0xA1,
-  0xD6, 0xD6, 0x2C, 0x2C, 0x95, 0x70, 0x20, 0x20,
-  0x80, 0x2B, 0x34, 0x2B, 0x88, 0x20, 0x20, 0x20,
-  0x88, 0xB1, 0x28, 0x28, 0x2B, 0x7D, 0x80, 0x20,
-  0x20, 0x20, 0x20, 0x92, 0x95, 0x55, 0xCB, 0x70,
-  0x90, 0x55, 0x2C, 0x2C, 0x2C, 0x55, 0x70, 0x70,
-  0x55, 0x95, 0x55, 0x55, 0x90, 0x90, 0x90, 0x55,
-  0x2C, 0xA1, 0xD6, 0xA1, 0x2C, 0x2C, 0x95, 0x95,
-  0xA1, 0x95, 0x55, 0xCB, 0x90, 0x70, 0xCB, 0x95,
-  0xA1, 0x95, 0x95, 0xCB, 0x90, 0xCB, 0x95, 0x2C,
-  0x95, 0x70, 0x70, 0x90, 0x55, 0x2C, 0xA1, 0xA1,
-  0x2C, 0x2C, 0x55, 0xCB, 0x55, 0x90, 0x20, 0x34,
-  0x90, 0x6D, 0x70, 0xD8, 0x43, 0x20, 0x20, 0x88,
-  0x3F, 0x55, 0xA1, 0x2A, 0xD6, 0x7D, 0x43, 0x20,
-  0x20, 0x20, 0x88, 0x7D, 0x55, 0xCB, 0x90, 0x70,
-  0xCB, 0x95, 0xA1, 0x95, 0x95, 0xCB, 0x70, 0xCB,
-  0x95, 0xA1, 0x95, 0x70, 0x70, 0xCB, 0x55, 0x2C,
-  0xA1, 0xA1, 0xA1, 0x95, 0x55, 0x55, 0x55, 0x95,
-  0x2C, 0x55, 0x90, 0x70, 0x94, 0x90, 0x95, 0x2C,
-  0x2C, 0x95, 0xCB, 0x90, 0x55, 0x95, 0xA1, 0xA1,
-  0x95, 0x90, 0x90, 0x95, 0xA1, 0xD6, 0xD6, 0x6D,
-  0xA1, 0x95, 0x55, 0xCB, 0x55, 0xCB, 0x20, 0x99,
-  0xBF, 0xA3, 0xA3, 0x90, 0x20, 0x20, 0x20, 0x92,
-  0x83, 0x6B, 0x6B, 0x6B, 0xA3, 0x70, 0x88, 0x20,
-  0x20, 0x20, 0x20, 0x2B, 0x90, 0x70, 0x94, 0x90,
-  0x95, 0x2C, 0x2C, 0x95, 0xCB, 0x90, 0x55, 0x95,
-  0xA1, 0x2C, 0x55, 0x90, 0x90, 0x95, 0xA1, 0xD6,
-  0xD6, 0x6D, 0xA1, 0x95, 0x55, 0xCB, 0x55, 0x55,
-  0x2C, 0x55, 0x70, 0x70, 0x94, 0x90, 0x95, 0x2C,
-  0x2C, 0x55, 0xCB, 0xCB, 0x95, 0x2C, 0x2C, 0x2C,
-  0x55, 0x55, 0x95, 0xA1, 0x6D, 0xBF, 0x6D, 0xD6,
-  0x95, 0x55, 0x90, 0xCB, 0x55, 0x95, 0x88, 0x95,
-  0x2C, 0x3F, 0x6D, 0x6B, 0x34, 0x20, 0x20, 0x47,
-  0x65, 0xD6, 0xE1, 0x3F, 0x2A, 0x6B, 0x2B, 0x20,
-  0x20, 0x20, 0x20, 0x43, 0x70, 0x70, 0x94, 0x90,
-  0x95, 0x2C, 0x2C, 0x55, 0x55, 0x55, 0x95, 0x2C,
-  0xA1, 0x2C, 0x55, 0xCB, 0x95, 0xA1, 0x6D, 0xBF,
-  0x6D, 0xD6, 0x2C, 0x55, 0x90, 0xCB, 0x95, 0x95,
-  0x95, 0x55, 0x70, 0x94, 0x70, 0x55, 0x2C, 0xA1,
-  0x2C, 0x55, 0xCB, 0x55, 0x2C, 0x95, 0x2C, 0x95,
-  0x95, 0x95, 0xA1, 0x6D, 0xBF, 0x2A, 0xD6, 0x95,
-  0x70, 0x94, 0x94, 0x70, 0x55, 0x55, 0x20, 0xBF,
-  0xC9, 0xB1, 0x99, 0x42, 0xB1, 0x61, 0x7D, 0x94,
-  0x65, 0xB1, 0x88, 0x99, 0xD5, 0xE5, 0x7F, 0x20,
-  0x20, 0x20, 0x20, 0x43, 0x70, 0x94, 0x70, 0x55,
-  0x2C, 0xA1, 0x2C, 0x55, 0x90, 0x55, 0x2C, 0x95,
-  0x2C, 0x95, 0x95, 0x2C, 0xA1, 0x6D, 0xBF, 0xBF,
-  0xD6, 0x55, 0x70, 0x94, 0x94, 0x70, 0xCB, 0x55,
-  0x55, 0xCB, 0x70, 0x94, 0x70, 0x95, 0xA1, 0xA1,
-  0x95, 0x55, 0x55, 0x95, 0x2C, 0x95, 0x95, 0x95,
-  0x95, 0xA1, 0x6D, 0x2A, 0x2A, 0xD6, 0x55, 0x94,
-  0xE6, 0xE6, 0x47, 0x70, 0x55, 0x95, 0x20, 0x2A,
-  0xD8, 0x43, 0xC9, 0x83, 0x98, 0x79, 0x34, 0x9F,
-  0x6B, 0x43, 0x20, 0x88, 0x2B, 0x65, 0xA0, 0x20,
-  0x20, 0x20, 0x20, 0xE1, 0x70, 0x94, 0x70, 0x95,
-  0xA1, 0xA1, 0x95, 0x55, 0x55, 0x95, 0x2C, 0x95,
-  0x95, 0x95, 0x95, 0xA1, 0x6D, 0xBF, 0x2A, 0xD6,
-  0x55, 0x94, 0xE6, 0xE6, 0x47, 0x70, 0x55, 0x55,
-  0x94, 0x70, 0x94, 0x47, 0x70, 0x95, 0x2C, 0x2C,
-  0x95, 0xCB, 0x95, 0x2C, 0x2C, 0xA1, 0x2C, 0x2C,
-  0xA1, 0xD6, 0x6D, 0x6D, 0xA1, 0xCB, 0x47, 0x28,
-  0xE6, 0x47, 0x70, 0x55, 0x95, 0xA1, 0x20, 0x2C,
-  0x7F, 0x88, 0xF0, 0xC6, 0x25, 0x5E, 0xCF, 0x2F,
-  0xE7, 0x9A, 0x20, 0x88, 0x99, 0x65, 0x3F, 0x20,
-  0x20, 0x20, 0x20, 0x34, 0x94, 0x47, 0x70, 0x95,
-  0xA1, 0x2C, 0x55, 0xCB, 0x95, 0x2C, 0x2C, 0xA1,
-  0x2C, 0x2C, 0xA1, 0xD6, 0x6D, 0x6D, 0xA1, 0xCB,
-  0x94, 0x28, 0xA0, 0x47, 0x70, 0x55, 0x95, 0x95,
-  0x47, 0x70, 0x90, 0x94, 0x70, 0x95, 0xA1, 0x2C,
-  0x55, 0x55, 0x2C, 0xA1, 0xA1, 0xA1, 0xA1, 0x2C,
-  0xA1, 0x6D, 0x2A, 0xD6, 0x55, 0x47, 0x28, 0x28,
-  0x47, 0x70, 0x55, 0x95, 0x2C, 0xA1, 0x20, 0x28,
-  0xEC, 0x86, 0xBE, 0x48, 0x3E, 0x3E, 0x3A, 0x25,
-  0x4E, 0xAE, 0x93, 0xD7, 0xEC, 0xD1, 0x34, 0x20,
-  0x20, 0x20, 0x20, 0x43, 0x55, 0x94, 0x70, 0x95,
-  0xA1, 0xA1, 0x55, 0xCB, 0x2C, 0xA1, 0xA1, 0xA1,
-  0xA1, 0x2C, 0xA1, 0x6D, 0x6D, 0xD6, 0x55, 0x47,
-  0x28, 0x28, 0x47, 0x70, 0x55, 0x95, 0x2C, 0x2C,
-  0x95, 0x95, 0x55, 0x90, 0xCB, 0x2C, 0xA1, 0xA1,
-  0x55, 0x55, 0x2C, 0xD6, 0xD6, 0xA1, 0xA1, 0x2C,
-  0xD6, 0x6D, 0x6D, 0xA1, 0x70, 0x28, 0xD5, 0xE6,
-  0x70, 0x55, 0x95, 0x2C, 0xA1, 0xD6, 0x20, 0xE1,
-  0x26, 0x84, 0x76, 0x73, 0x9C, 0x22, 0x4E, 0x35,
-  0x8C, 0x7A, 0x4E, 0xDC, 0x8E, 0x7E, 0x3D, 0x88,
-  0x20, 0x20, 0x20, 0x88, 0x2C, 0x90, 0x90, 0x95,
-  0xA1, 0x2C, 0x55, 0x55, 0x2C, 0xD6, 0xD6, 0xD6,
-  0x2C, 0x2C, 0xD6, 0x2A, 0x6D, 0x2C, 0x70, 0x28,
-  0xD5, 0xE6, 0x70, 0x55, 0x95, 0xA1, 0x2C, 0xA1,
-  0xBF, 0xA1, 0x95, 0xCB, 0xCB, 0x2C, 0xA1, 0xA1,
-  0x95, 0x95, 0xA1, 0xD6, 0xD6, 0xA1, 0x2C, 0x95,
-  0xD6, 0x6D, 0xD6, 0x95, 0x94, 0x28, 0xE6, 0x70,
-  0x55, 0x95, 0xA1, 0xA1, 0xA1, 0xD6, 0x20, 0x57,
-  0xE4, 0xDF, 0x50, 0x3E, 0x22, 0x4E, 0x35, 0x8C,
-  0x8C, 0x52, 0x52, 0x7A, 0x4E, 0x58, 0xD7, 0x20,
-  0x20, 0x20, 0x20, 0x88, 0x2C, 0xCB, 0x55, 0x2C,
-  0xA1, 0xA1, 0x95, 0x95, 0xA1, 0xD6, 0xD6, 0xA1,
-  0x2C, 0x95, 0xA1, 0x6D, 0x6D, 0x95, 0x47, 0xA0,
-  0xE6, 0x70, 0x55, 0x95, 0x2C, 0xA1, 0xA1, 0xA1,
-  0xD2, 0x95, 0x55, 0x90, 0x55, 0x2C, 0xD6, 0xA1,
-  0x95, 0x95, 0xA1, 0xD6, 0xD6, 0x2C, 0x95, 0x2C,
-  0xA1, 0x6D, 0xA1, 0x55, 0x94, 0x47, 0x94, 0xCB,
-  0x55, 0x95, 0x2C, 0xA1, 0xD6, 0xD6, 0x59, 0xC8,
-  0xE3, 0x76, 0x2D, 0x3E, 0x22, 0x4E, 0x8C, 0x35,
-  0x52, 0x52, 0xEE, 0x3A, 0x4D, 0xED, 0x24, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x28, 0xCB, 0x55, 0x2C,
-  0xD6, 0xA1, 0x95, 0x95, 0xA1, 0xD6, 0xA1, 0x2C,
-  0x95, 0x2C, 0xD6, 0x6D, 0xA1, 0x55, 0x94, 0xE6,
-  0x70, 0xCB, 0x55, 0x95, 0xA1, 0xD6, 0xD6, 0xA1,
-  0xD0, 0x94, 0x94, 0x90, 0x55, 0x2C, 0xA1, 0xA1,
-  0x55, 0x95, 0xA1, 0xA1, 0xA1, 0x2C, 0x95, 0x2C,
-  0xA1, 0xD6, 0x2C, 0x70, 0x94, 0x94, 0x94, 0x94,
-  0x70, 0x55, 0xA1, 0xD6, 0xA1, 0xD6, 0x88, 0x77,
-  0x38, 0xC4, 0x3E, 0x69, 0x4E, 0x35, 0x8C, 0xEE,
-  0x35, 0x89, 0x30, 0x30, 0x4A, 0x48, 0x3C, 0x20,
-  0x20, 0x88, 0x20, 0x20, 0xD8, 0x2C, 0x55, 0x2C,
-  0xD6, 0xA1, 0x95, 0x95, 0x2C, 0xD6, 0xA1, 0x2C,
-  0x95, 0x2C, 0xA1, 0xD6, 0x2C, 0x90, 0x94, 0x47,
-  0x94, 0x94, 0x70, 0x55, 0x2C, 0xD6, 0xA1, 0x95,
-  0x95, 0x28, 0x47, 0x90, 0x95, 0x2C, 0xA1, 0x2C,
-  0x95, 0x55, 0x95, 0xA1, 0xD6, 0xA1, 0x2C, 0x2C,
-  0xA1, 0xA1, 0x55, 0x70, 0x94, 0x47, 0x94, 0x94,
-  0x70, 0x2C, 0xD6, 0xD6, 0x2C, 0xA1, 0x43, 0x98,
-  0x54, 0x48, 0x3E, 0x22, 0x35, 0xEE, 0xEE, 0x9C,
-  0x4D, 0x45, 0x75, 0x4A, 0xDF, 0x7B, 0x3D, 0x20,
-  0xD8, 0x28, 0x2B, 0x88, 0x20, 0x95, 0x95, 0x2C,
-  0xA1, 0x2C, 0x55, 0x55, 0x2C, 0xA1, 0xD6, 0xA1,
-  0x2C, 0x95, 0xA1, 0x2C, 0x55, 0x70, 0x94, 0x94,
-  0x94, 0x94, 0x70, 0x95, 0xD6, 0xD6, 0x2C, 0x95,
-  0x70, 0x28, 0x47, 0x55, 0x95, 0x2C, 0x2C, 0x2C,
-  0x95, 0x95, 0x95, 0xA1, 0xA1, 0xA1, 0x95, 0x55,
-  0x95, 0x95, 0x55, 0x70, 0x70, 0x70, 0x94, 0x70,
-  0x55, 0xD6, 0x6D, 0xD6, 0x95, 0x2C, 0x20, 0x43,
-  0xBB, 0xC8, 0x36, 0x30, 0x30, 0x38, 0x45, 0x6E,
-  0xE3, 0x75, 0x78, 0x37, 0xBD, 0xD9, 0x3F, 0x20,
-  0x88, 0xD5, 0x70, 0xB1, 0x88, 0xA0, 0x95, 0x2C,
-  0x2C, 0xA1, 0x95, 0x55, 0x95, 0xA1, 0xA1, 0xA1,
-  0x2C, 0x55, 0x95, 0x2C, 0x55, 0x70, 0x70, 0x70,
-  0x94, 0x70, 0x55, 0xD6, 0x6D, 0x6D, 0x95, 0x55,
-  0x94, 0x47, 0x70, 0x95, 0x2C, 0x2C, 0x2C, 0xA1,
-  0x2C, 0x95, 0x2C, 0xA1, 0xD6, 0xA1, 0x2C, 0x55,
-  0x55, 0x95, 0x95, 0x55, 0x55, 0x55, 0x55, 0x95,
-  0xA1, 0x6D, 0x4B, 0xD6, 0x55, 0xD6, 0x20, 0xD8,
-  0xD6, 0x67, 0xDA, 0x4D, 0xED, 0x62, 0x78, 0x78,
-  0x23, 0x84, 0x67, 0xF5, 0x4B, 0xBF, 0x90, 0x88,
-  0x88, 0x2B, 0x47, 0x99, 0x20, 0x43, 0xD6, 0x2C,
-  0x2C, 0xA1, 0x2C, 0x95, 0x2C, 0xA1, 0xD6, 0xA1,
-  0x95, 0x95, 0x55, 0x95, 0x55, 0x55, 0x55, 0x55,
-  0x55, 0x95, 0xD6, 0x6D, 0xBF, 0xD6, 0x55, 0xCB,
-  0x55, 0x55, 0x55, 0x2C, 0x2C, 0x2C, 0x2C, 0xA1,
-  0x2C, 0x2C, 0x2C, 0xA1, 0xA1, 0x2C, 0x2C, 0x95,
-  0x55, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0xA1,
-  0x6D, 0x2A, 0x2A, 0xA1, 0x55, 0x55, 0x20, 0xD8,
-  0x6D, 0xAB, 0x96, 0x7E, 0x64, 0x53, 0x36, 0x36,
-  0xC6, 0x63, 0x6D, 0xD0, 0x6B, 0xE5, 0xA3, 0x7D,
-  0x20, 0x88, 0x80, 0x88, 0x20, 0x20, 0xC9, 0xA1,
-  0x2C, 0xA1, 0xA1, 0x2C, 0x2C, 0xA1, 0xA1, 0xA1,
-  0x95, 0x95, 0x55, 0x95, 0x95, 0x2C, 0x2C, 0x2C,
-  0x2C, 0xA1, 0x6D, 0xBF, 0x6D, 0xA1, 0x55, 0x55,
-  0x95, 0x95, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0xA1,
-  0xA1, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0x95,
-  0x55, 0x55, 0x2C, 0x2C, 0xA1, 0xA1, 0xD6, 0xD6,
-  0x6D, 0x6D, 0xA1, 0x55, 0x2C, 0xD8, 0x20, 0xB1,
-  0xA3, 0x4B, 0x6D, 0xD9, 0xA7, 0x6C, 0xAF, 0xB2,
-  0x6D, 0x2A, 0x83, 0x42, 0xE5, 0xE5, 0x65, 0x2C,
-  0x20, 0x20, 0x88, 0x20, 0x20, 0x20, 0x88, 0x95,
-  0x2C, 0xA1, 0x2C, 0x95, 0x95, 0x2C, 0x2C, 0x2C,
-  0x2C, 0x95, 0x55, 0x55, 0x2C, 0x2C, 0xA1, 0xA1,
-  0xD6, 0xD6, 0x6D, 0x6D, 0xA1, 0x55, 0xCB, 0x55,
-  0x95, 0x55, 0x95, 0x95, 0x2C, 0x2C, 0x95, 0x2C,
-  0x2C, 0x95, 0x95, 0x95, 0x95, 0x95, 0x2C, 0x95,
-  0x55, 0x95, 0x2C, 0x2C, 0xA1, 0xA1, 0xD6, 0xA1,
-  0xA1, 0x2C, 0x55, 0x55, 0x28, 0x88, 0x43, 0x2A,
-  0xE5, 0xA3, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D,
-  0xBF, 0xA3, 0x42, 0xE5, 0xE5, 0xE5, 0xE5, 0x65,
-  0xB1, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xD8,
-  0xD6, 0x2C, 0x2C, 0x95, 0x95, 0x95, 0x95, 0x2C,
-  0x95, 0x95, 0x55, 0x95, 0x2C, 0x2C, 0xA1, 0xA1,
-  0xA1, 0xA1, 0xA1, 0x2C, 0x95, 0x90, 0x90, 0x55,
-  0x90, 0xCB, 0x55, 0x95, 0x95, 0x95, 0x95, 0x95,
-  0x2C, 0x2C, 0x95, 0x55, 0x95, 0x95, 0x95, 0x55,
-  0x55, 0xCB, 0x55, 0x2C, 0x95, 0x95, 0x95, 0x95,
-  0x55, 0x90, 0x90, 0x90, 0xE1, 0x43, 0x28, 0xE5,
-  0xE5, 0x65, 0xD0, 0x6D, 0x6D, 0x6D, 0x2A, 0xD2,
-  0x42, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xD6, 0x20, 0x20, 0x20, 0x20, 0x20, 0x88, 0x88,
-  0xD5, 0x2C, 0x2C, 0x2C, 0x95, 0x55, 0x95, 0x95,
-  0x95, 0x55, 0x55, 0xCB, 0x55, 0x95, 0x2C, 0x95,
-  0x95, 0x95, 0x55, 0x90, 0x70, 0x70, 0x70, 0x90,
-  0x70, 0x70, 0xCB, 0x55, 0x55, 0x95, 0x95, 0x95,
-  0x2C, 0x95, 0x95, 0x55, 0x55, 0x55, 0x55, 0xCB,
-  0x70, 0x70, 0x70, 0xCB, 0x90, 0x90, 0x70, 0x94,
-  0x94, 0x94, 0x2C, 0x80, 0x20, 0xE1, 0xA3, 0xE5,
-  0xE5, 0xE5, 0x42, 0xEC, 0xD0, 0x83, 0xA3, 0x65,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0x65, 0x7D, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x88, 0x2C, 0x95, 0x95, 0x95, 0x55, 0x55, 0x55,
-  0x55, 0xCB, 0x70, 0x70, 0x90, 0x90, 0x90, 0x90,
-  0x70, 0x94, 0x94, 0x94, 0x70, 0x70, 0x70, 0x70,
-  0x70, 0x55, 0x55, 0x55, 0x95, 0x95, 0x95, 0x95,
-  0x2C, 0x2C, 0x95, 0x55, 0x55, 0x55, 0x55, 0x55,
-  0x90, 0x70, 0x90, 0x55, 0x55, 0xCB, 0x70, 0x94,
-  0x94, 0x95, 0xD8, 0x20, 0x88, 0x70, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0x65, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0x47, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0xE1, 0x6D, 0x2C, 0x95, 0x55, 0x55, 0x55,
-  0x55, 0x55, 0x90, 0x70, 0x70, 0x55, 0x55, 0xCB,
-  0x70, 0x94, 0x94, 0x94, 0x70, 0x90, 0x70, 0x94,
-  0x55, 0x2C, 0x2C, 0x2C, 0x95, 0x2C, 0x95, 0x95,
-  0x2C, 0x2C, 0x2C, 0x55, 0x55, 0x55, 0x55, 0x55,
-  0xCB, 0xCB, 0x95, 0x2C, 0x2C, 0x95, 0x55, 0x90,
-  0x55, 0x99, 0x20, 0x20, 0xE1, 0xA3, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xD6, 0x88, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x2B, 0x6D, 0x95, 0x95, 0x55, 0x55,
-  0x55, 0x55, 0xCB, 0x55, 0x95, 0x2C, 0x2C, 0x95,
-  0x55, 0x90, 0xCB, 0xCB, 0xCB, 0xCB, 0x90, 0x70,
-  0x2C, 0xD6, 0xD6, 0x2C, 0x2C, 0x95, 0x95, 0x95,
-  0x95, 0x95, 0x95, 0x2C, 0x95, 0x95, 0x95, 0x95,
-  0x95, 0x95, 0x2C, 0xA1, 0x2C, 0x95, 0x55, 0x95,
-  0xE6, 0x88, 0x20, 0x20, 0x3F, 0xA3, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0x42, 0xA3, 0x88, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x88, 0x2B, 0xD6, 0x95, 0x95, 0x95,
-  0x95, 0x95, 0x95, 0x95, 0x2C, 0xA1, 0x2C, 0x95,
-  0x55, 0x55, 0x95, 0x95, 0x95, 0x55, 0x55, 0x55,
-  0xA1, 0xD6, 0xD6, 0xA1, 0x2C, 0x2C, 0x95, 0x2C,
-  0x2C, 0x2C, 0x95, 0x2C, 0x95, 0x95, 0x55, 0x95,
-  0x95, 0x2C, 0x2C, 0x2C, 0x95, 0xCB, 0xCB, 0x94,
-  0x20, 0x20, 0x20, 0x20, 0xE6, 0x83, 0x65, 0xE5,
-  0xE5, 0xE5, 0xE5, 0x42, 0x6B, 0x6B, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0x42, 0x6B, 0x6B, 0xA3, 0xD2,
-  0xD2, 0x6B, 0xC9, 0x20, 0x20, 0x88, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x88, 0x8A, 0xA1, 0x95, 0x95,
-  0x95, 0x55, 0x95, 0x2C, 0xA1, 0x2C, 0x95, 0xCB,
-  0xCB, 0x55, 0x95, 0x95, 0x95, 0x55, 0x55, 0x95,
-  0x6D, 0x6D, 0x6D, 0xD6, 0xA1, 0x2C, 0x2C, 0x95,
-  0x2C, 0x95, 0x2C, 0x95, 0x95, 0x95, 0x95, 0x95,
-  0x95, 0x95, 0x95, 0x55, 0x70, 0x70, 0x2C, 0x80,
-  0x88, 0x20, 0x20, 0x80, 0x94, 0xD6, 0x32, 0x6B,
-  0xE5, 0xE5, 0xE5, 0x42, 0x6B, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xA3, 0xD2, 0xD0, 0xBF, 0x2A,
-  0x2A, 0xD0, 0x6D, 0x34, 0x20, 0xE1, 0x88, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x88, 0xA1, 0x95, 0x95,
-  0x95, 0x95, 0x95, 0x95, 0x95, 0x55, 0x70, 0x70,
-  0x70, 0x90, 0xCB, 0xCB, 0xCB, 0x95, 0x95, 0x2C,
-  0xD0, 0x6D, 0xD6, 0xD6, 0xA1, 0xA1, 0xA1, 0x2C,
-  0x2C, 0x2C, 0x2C, 0x95, 0x55, 0x55, 0x55, 0x95,
-  0x95, 0x2C, 0x95, 0x55, 0xCB, 0xCB, 0x95, 0x88,
-  0x20, 0x20, 0x88, 0xD8, 0x2C, 0xD1, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0x65, 0x65, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x42, 0x6B, 0xEC,
-  0xBF, 0x2A, 0xEC, 0x95, 0x20, 0x34, 0x2B, 0xE1,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x99, 0x95, 0x55,
-  0x55, 0x55, 0x95, 0x95, 0x95, 0x55, 0xCB, 0xCB,
-  0x55, 0x55, 0xCB, 0xCB, 0xCB, 0x55, 0x95, 0x95,
-  0x32, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0x2C, 0x2C,
-  0xA1, 0x95, 0x95, 0x95, 0x55, 0xCB, 0xCB, 0x55,
-  0x95, 0x95, 0x95, 0x95, 0x95, 0x55, 0x99, 0x20,
-  0xE1, 0xE1, 0x43, 0x47, 0x6B, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0x42, 0xEC, 0xBF, 0xA3, 0x8A, 0x20, 0x88, 0xD8,
-  0x2B, 0x20, 0x20, 0x20, 0x88, 0x88, 0x2C, 0xCB,
-  0xCB, 0x95, 0x95, 0x2C, 0x95, 0x95, 0x55, 0x95,
-  0x55, 0x55, 0x55, 0x55, 0x55, 0x95, 0x55, 0x95,
-  0x6D, 0x55, 0x55, 0x55, 0x95, 0x95, 0x2C, 0x95,
-  0x2C, 0x95, 0x95, 0x55, 0x55, 0x55, 0x55, 0x95,
-  0x95, 0x95, 0x95, 0x95, 0x95, 0xA1, 0x34, 0x20,
-  0xC9, 0x20, 0xE1, 0xA3, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xA3, 0x83, 0x6D, 0x20, 0x88, 0x88,
-  0x2B, 0x34, 0x20, 0x20, 0x20, 0x88, 0xD5, 0x55,
-  0x55, 0x55, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
-  0x95, 0x95, 0x95, 0x95, 0x55, 0x55, 0x95, 0x95,
-  0x2C, 0x55, 0xCB, 0x55, 0xCB, 0x55, 0x55, 0x95,
-  0x95, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C,
-  0x2C, 0x95, 0x95, 0x55, 0x95, 0x2C, 0x20, 0xD8,
-  0xE1, 0x20, 0x70, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0x65, 0xA3, 0x92, 0x43, 0x7D,
-  0xD8, 0xC9, 0x88, 0x20, 0x20, 0x20, 0x43, 0xD6,
-  0x2C, 0x2C, 0x95, 0x95, 0x95, 0x55, 0x95, 0x2C,
-  0x95, 0x95, 0x95, 0x95, 0x95, 0x2C, 0x95, 0x2C,
-  0xA1, 0x55, 0x55, 0x55, 0x55, 0x95, 0x95, 0x55,
-  0x55, 0x55, 0x95, 0x95, 0x2C, 0x2C, 0xA1, 0x2C,
-  0xA1, 0x2C, 0x2C, 0x95, 0x2C, 0x99, 0x88, 0xB1,
-  0x20, 0xD8, 0x42, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xCB, 0x34, 0x8A,
-  0xC9, 0x34, 0x2B, 0x20, 0x20, 0x20, 0x20, 0x90,
-  0xA1, 0xA1, 0xA1, 0x2C, 0x2C, 0x95, 0x95, 0x2C,
-  0x2C, 0x95, 0x95, 0x95, 0x95, 0x2C, 0x2C, 0x2C,
-  0xD6, 0x2C, 0x55, 0x55, 0x95, 0x2C, 0x2C, 0x2C,
-  0x55, 0xCB, 0x55, 0x2C, 0x2C, 0xA1, 0x2C, 0xA1,
-  0xA1, 0xA1, 0x2C, 0x2C, 0x6D, 0x43, 0xD8, 0x80,
-  0x88, 0xCB, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x32, 0x80, 0xE1,
-  0x80, 0x20, 0xB1, 0x20, 0x20, 0x20, 0x20, 0xC9,
-  0xD6, 0xA1, 0xA1, 0xA1, 0x2C, 0xA1, 0x2C, 0x2C,
-  0x2C, 0x55, 0x55, 0x55, 0x95, 0x95, 0x95, 0x55,
-  0xD6, 0x95, 0x95, 0x95, 0x2C, 0xA1, 0x2C, 0x2C,
-  0x95, 0x95, 0x95, 0x95, 0x95, 0x2C, 0x95, 0x2C,
-  0x2C, 0x2C, 0x2C, 0x95, 0xCB, 0x20, 0xC9, 0x20,
-  0xE1, 0xA3, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0x42, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xD8, 0x20,
-  0x20, 0x20, 0x2B, 0x43, 0x20, 0x20, 0x20, 0x88,
-  0xD6, 0x2C, 0x2C, 0x2C, 0x95, 0x95, 0x95, 0x55,
-  0x95, 0x55, 0x55, 0xCB, 0x55, 0xCB, 0xCB, 0x55,
-  0x2C, 0x55, 0x55, 0x95, 0x2C, 0x2C, 0xA1, 0x95,
-  0x55, 0x95, 0x55, 0x95, 0x95, 0x95, 0x95, 0x95,
-  0x55, 0xCB, 0x70, 0xCB, 0xC9, 0x80, 0x2B, 0x20,
-  0xA0, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0x42, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x92, 0x20,
-  0x20, 0x20, 0xE1, 0xD8, 0x20, 0x20, 0x20, 0x20,
-  0x95, 0x95, 0x55, 0xCB, 0x90, 0x90, 0x70, 0x90,
-  0x90, 0x90, 0xCB, 0xCB, 0xCB, 0xCB, 0x55, 0x95,
-  0x95, 0x55, 0x55, 0x95, 0x95, 0x2C, 0x2C, 0x2C,
-  0x95, 0x95, 0x55, 0x55, 0x55, 0x95, 0x95, 0x55,
-  0x90, 0x47, 0xA0, 0x55, 0x20, 0x2B, 0x43, 0x88,
-  0x6D, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0x6B, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x28, 0x20,
-  0x20, 0x20, 0xE1, 0xE1, 0x20, 0x20, 0x20, 0x20,
-  0x28, 0x55, 0x90, 0x47, 0xA0, 0x47, 0x94, 0x70,
-  0x55, 0x95, 0x95, 0x55, 0xCB, 0x55, 0x55, 0x2C,
-  0x2C, 0x2C, 0x95, 0x95, 0x95, 0x2C, 0x2C, 0x2C,
-  0x95, 0x2C, 0x95, 0x95, 0x95, 0x95, 0x95, 0x55,
-  0x94, 0xE6, 0x70, 0x2B, 0x88, 0x2B, 0x88, 0xE1,
-  0x65, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0x6B, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x47, 0x20,
-  0x20, 0x20, 0xE1, 0x34, 0x20, 0x20, 0x20, 0x20,
-  0xB1, 0x95, 0x94, 0xE6, 0xA0, 0x47, 0x70, 0x55,
-  0x2C, 0xA1, 0x2C, 0x55, 0x90, 0xCB, 0x2C, 0xD6,
-  0x6D, 0xA1, 0x2C, 0x95, 0x95, 0xA1, 0x2C, 0xA1,
-  0x2C, 0x2C, 0x95, 0x95, 0x95, 0x95, 0x95, 0x55,
-  0x70, 0xE6, 0x70, 0x20, 0x20, 0x7D, 0x20, 0x8A,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0x65, 0xA3, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x94, 0x20,
-  0x20, 0x20, 0xD8, 0x88, 0x20, 0x20, 0x20, 0x20,
-  0xD8, 0x2C, 0x94, 0x47, 0x47, 0x90, 0x95, 0x95,
-  0xA1, 0x6D, 0xA1, 0x90, 0x94, 0x55, 0x2C, 0xD6,
-  0xD0, 0xA1, 0x95, 0x95, 0x2C, 0x2C, 0xA1, 0x2C,
-  0x95, 0x95, 0x55, 0x55, 0x55, 0x95, 0x2C, 0x2C,
-  0xCB, 0x95, 0xD8, 0x20, 0x20, 0xB1, 0x88, 0x28,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE2, 0xA3, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xCB, 0x20,
-  0x20, 0x20, 0x2B, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x88, 0xD6, 0x55, 0x47, 0x94, 0x55, 0x2C, 0xA1,
-  0xA1, 0xD6, 0x95, 0x94, 0x94, 0x55, 0xD6, 0x6D,
-  0xBF, 0x95, 0x90, 0xCB, 0x2C, 0x2C, 0x2C, 0x2C,
-  0x55, 0x95, 0xCB, 0x90, 0x90, 0x95, 0x2C, 0x95,
-  0x90, 0x70, 0x20, 0x20, 0x34, 0x8A, 0x20, 0x94,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0x65, 0x6B, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xCB, 0x20,
-  0x20, 0x88, 0x2B, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x88, 0xD6, 0xCB, 0x47, 0x94, 0x55, 0xA1, 0xD6,
-  0xD6, 0x2C, 0xCB, 0x47, 0x70, 0xA1, 0x6D, 0x2A,
-  0x95, 0x47, 0x47, 0x70, 0x95, 0xA1, 0x2C, 0x95,
-  0x55, 0x55, 0x90, 0x90, 0x55, 0x55, 0x55, 0x90,
-  0x47, 0xD5, 0x20, 0x20, 0x80, 0xD5, 0x43, 0xCB,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0x42, 0x6B, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xCB, 0x20,
-  0x20, 0x80, 0x34, 0x20, 0x20, 0x20, 0x88, 0x20,
-  0x20, 0x2C, 0x47, 0xE6, 0x70, 0x2C, 0xD6, 0xD6,
-  0xA1, 0x2C, 0x55, 0xCB, 0x95, 0xA1, 0x6D, 0xD6,
-  0x90, 0x47, 0x47, 0x90, 0x2C, 0xA1, 0x2C, 0x95,
-  0x55, 0x55, 0x90, 0x90, 0x55, 0x55, 0x55, 0x70,
-  0x94, 0x8A, 0x20, 0x88, 0x88, 0xE1, 0xD8, 0x95,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE2, 0x42, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x47, 0x20,
-  0x43, 0x7D, 0x43, 0x80, 0x88, 0x20, 0x20, 0x20,
-  0x88, 0xCB, 0x94, 0x70, 0x55, 0xA1, 0xD6, 0xD6,
-  0xA1, 0x2C, 0x2C, 0x95, 0xA1, 0xA1, 0xD6, 0xA1,
-  0x94, 0xE6, 0x47, 0x55, 0x2C, 0xD6, 0xA1, 0x95,
-  0x55, 0x55, 0xCB, 0xCB, 0x55, 0x55, 0xCB, 0xCB,
-  0x55, 0xA0, 0x43, 0x86, 0x86, 0x43, 0xD8, 0xCB,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0x65, 0x6B, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x3F, 0x80,
-  0xD8, 0x80, 0x88, 0x34, 0xD8, 0x2B, 0xD8, 0x20,
-  0x99, 0x90, 0x55, 0x95, 0x2C, 0xA1, 0xD6, 0xD6,
-  0xA1, 0x95, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C,
-  0x94, 0x94, 0x70, 0x2C, 0xA1, 0xD6, 0xA1, 0x2C,
-  0x55, 0x55, 0xCB, 0x55, 0x55, 0x55, 0x55, 0x55,
-  0x95, 0x44, 0xBC, 0x3E, 0x5D, 0xD3, 0x79, 0x92,
-  0xA3, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0x65, 0x42, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x65, 0x9A, 0x34,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x99, 0xE1,
-  0x70, 0x55, 0x95, 0xA1, 0xD6, 0xD6, 0xD6, 0xA1,
-  0x2C, 0x95, 0x55, 0x55, 0x95, 0x95, 0x95, 0x95,
-  0x70, 0x70, 0x55, 0x2C, 0xD6, 0xD6, 0xA1, 0x95,
-  0x55, 0x90, 0xCB, 0xCB, 0x55, 0x55, 0x2C, 0x2C,
-  0x32, 0x9D, 0xEB, 0x5D, 0x69, 0x49, 0x84, 0xF0,
-  0xB1, 0xEC, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0x42, 0x6B, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xC1, 0x4E, 0x21, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x34, 0xC9, 0xD8,
-  0xBB, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0x2C, 0x2C,
-  0x95, 0x55, 0x55, 0x55, 0x95, 0x95, 0x2C, 0x2C,
-  0x55, 0xCB, 0x95, 0x2C, 0xA1, 0xA1, 0x2C, 0x55,
-  0x90, 0x70, 0x90, 0x55, 0x95, 0x95, 0x6D, 0xD0,
-  0xC2, 0x48, 0x6A, 0x49, 0x69, 0x82, 0x5D, 0x2F,
-  0x59, 0x7D, 0xBF, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0x65, 0x6B, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xEA, 0xC7, 0x7E, 0x66,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x34, 0x43, 0x5A,
-  0x46, 0x27, 0xA1, 0xA1, 0xA1, 0xA1, 0x2C, 0x95,
-  0x95, 0x55, 0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C,
-  0x95, 0x90, 0x55, 0x2C, 0xA1, 0xA1, 0x95, 0x55,
-  0x94, 0x94, 0x2C, 0x2A, 0x72, 0x3B, 0x56, 0xDD,
-  0xDF, 0x29, 0x5D, 0x49, 0x89, 0x5D, 0x3E, 0x69,
-  0x93, 0x66, 0x34, 0xA1, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0x65, 0x42, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xEA, 0x3E, 0x5A, 0x66,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x5B, 0x73,
-  0x89, 0x4C, 0xBF, 0x2C, 0x95, 0x2C, 0x2C, 0x95,
-  0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
-  0x2C, 0x70, 0x55, 0x2C, 0xD6, 0xD6, 0x2C, 0xCB,
-  0x70, 0x55, 0xE7, 0x60, 0x4A, 0x48, 0xCD, 0x4A,
-  0x29, 0x73, 0x5D, 0x82, 0x49, 0x49, 0x49, 0x49,
-  0x3A, 0x57, 0x88, 0x88, 0x70, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0x42, 0x73, 0x50, 0xBE, 0x79,
-  0x20, 0x20, 0x20, 0x20, 0x66, 0xCC, 0x37, 0x9C,
-  0x3E, 0xCE, 0xBF, 0x95, 0x95, 0x95, 0x2C, 0x95,
-  0x95, 0x55, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0x55,
-  0xA1, 0x55, 0x95, 0xA1, 0xD6, 0xA1, 0x55, 0x94,
-  0x94, 0xE8, 0x60, 0xC4, 0x3E, 0x2D, 0x2D, 0x2D,
-  0x33, 0x5D, 0x82, 0x49, 0x49, 0x49, 0x49, 0x49,
-  0x89, 0xAA, 0x59, 0x20, 0x20, 0x28, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xEC, 0x4A, 0x2D, 0x50, 0x78, 0x2E,
-  0x57, 0x51, 0xF0, 0x57, 0x31, 0x4D, 0x50, 0x2D,
-  0x5D, 0xF2, 0xA1, 0x2C, 0x95, 0x95, 0x55, 0x55,
-  0x90, 0x90, 0x70, 0x90, 0xCB, 0x55, 0x55, 0x55,
-  0x6D, 0x2C, 0xA1, 0xD6, 0xD6, 0xA1, 0x55, 0x94,
-  0x70, 0xB9, 0x75, 0x50, 0x3E, 0x49, 0x49, 0x49,
-  0x5D, 0x82, 0x49, 0x49, 0x82, 0x49, 0x49, 0x49,
-  0x89, 0x69, 0x4F, 0x20, 0x20, 0x20, 0x8A, 0x42,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0x83, 0x4A, 0x3A, 0x50, 0x62, 0x23,
-  0x81, 0xB8, 0xB8, 0xE9, 0x5F, 0x29, 0x33, 0x5D,
-  0x5D, 0x73, 0xE8, 0xCB, 0x55, 0x55, 0x55, 0x55,
-  0x55, 0x55, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xD6, 0xA1, 0xA1, 0xA1, 0xA1, 0x55, 0x70, 0x70,
-  0xCB, 0x68, 0x75, 0x50, 0x82, 0x49, 0x49, 0x49,
-  0x5D, 0x49, 0x49, 0x5D, 0x49, 0x49, 0x5D, 0x82,
-  0x69, 0x5D, 0x25, 0xF0, 0x20, 0x20, 0x20, 0xE1,
-  0x2A, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0x4B, 0xF4, 0xDF, 0x50, 0x73, 0x76, 0x48,
-  0x75, 0xDF, 0x75, 0x62, 0xC4, 0x33, 0x82, 0x49,
-  0x5D, 0x5D, 0xA8, 0xF5, 0x55, 0x55, 0x55, 0x55,
-  0x2C, 0x2C, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1,
-  0x2C, 0x2C, 0x2C, 0x95, 0x95, 0xCB, 0x70, 0x70,
-  0x95, 0x83, 0x5F, 0xEA, 0x2D, 0x49, 0x49, 0x49,
-  0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
-  0x5D, 0x49, 0x22, 0x5A, 0x79, 0x20, 0x20, 0x20,
-  0x80, 0xD2, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0x65, 0xD0, 0x63, 0x5F, 0x29, 0x2D, 0x2D, 0xEA,
-  0x29, 0x29, 0x76, 0x50, 0x2D, 0x82, 0x49, 0x49,
-  0x3E, 0x49, 0x5C, 0xB0, 0xBA, 0x95, 0x55, 0x55,
-  0x2C, 0xA1, 0xD6, 0xD6, 0xD6, 0xA1, 0x2C, 0x2C,
-  0xA1, 0x95, 0x95, 0x55, 0xCB, 0x70, 0x70, 0x55,
-  0x2C, 0x83, 0x60, 0x76, 0x5D, 0x49, 0x49, 0x49,
-  0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
-  0x49, 0x5D, 0x89, 0xDC, 0x8B, 0x20, 0x20, 0x20,
-  0x20, 0x95, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE2, 0x32, 0x85, 0xE3, 0x29, 0x2D, 0x33, 0x2D,
-  0x2D, 0x2D, 0x6A, 0x2D, 0x33, 0x5D, 0x49, 0x82,
-  0x49, 0x49, 0x82, 0x73, 0x5C, 0x9E, 0x2C, 0x55,
-  0x2C, 0xA1, 0xD6, 0xA1, 0x2C, 0x2C, 0x95, 0x95,
-  0x2C, 0x95, 0x55, 0xCB, 0x90, 0x90, 0xCB, 0x95,
-  0x2C, 0x6D, 0x41, 0x6F, 0x3E, 0x49, 0x49, 0x49,
-  0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
-  0x49, 0x82, 0x3E, 0x4E, 0x38, 0xCA, 0x20, 0x20,
-  0x20, 0x55, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x65,
-  0x42, 0xA0, 0xD4, 0xE3, 0x29, 0x2D, 0x82, 0x5D,
-  0x5D, 0x82, 0x82, 0x49, 0x49, 0x49, 0x49, 0x49,
-  0x49, 0x3E, 0x49, 0x49, 0x49, 0x5C, 0x56, 0xD6,
-  0xA1, 0xA1, 0xA1, 0x95, 0x55, 0x55, 0x55, 0x95,
-  0xA1, 0x55, 0x90, 0x70, 0x94, 0x70, 0x95, 0x2C,
-  0x2C, 0xD6, 0xDD, 0x6F, 0x33, 0x49, 0x49, 0x49,
-  0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
-  0x5D, 0x5D, 0x82, 0x69, 0x22, 0x62, 0x80, 0x34,
-  0x94, 0x6B, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0x65, 0xE5, 0x65, 0x6B,
-  0xD5, 0x88, 0x5B, 0xE3, 0x29, 0x5D, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x5D, 0x5D, 0x49, 0x49, 0x49, 0x82,
-  0x49, 0x49, 0x89, 0x49, 0x82, 0x49, 0x71, 0xBA,
-  0x6D, 0x6D, 0xA1, 0x95, 0x55, 0xCB, 0x55, 0x55,
-  0x2C, 0x55, 0x70, 0x70, 0x70, 0x90, 0x95, 0xA1,
-  0x2C, 0xA1, 0x41, 0x76, 0x5D, 0x5D, 0x49, 0x49,
-  0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
-  0x49, 0x5D, 0x82, 0x5D, 0x89, 0x5E, 0x96, 0x65,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0xE5, 0xE5, 0xE5, 0xE5, 0x65, 0x65, 0xEC, 0xB1,
-  0x20, 0x20, 0xCA, 0x23, 0x29, 0x33, 0x49, 0x5D,
-  0x49, 0x82, 0x49, 0x49, 0x49, 0x49, 0x49, 0x82,
-  0x49, 0x82, 0x5D, 0x5D, 0x5D, 0x2D, 0x5C, 0x8F,
-  0x6D, 0xD6, 0x2C, 0x55, 0x90, 0xCB, 0x95, 0x95,
-  0x95, 0x55, 0x70, 0x94, 0x70, 0x55, 0x2C, 0xA1,
-  0x95, 0xE8, 0x5F, 0x76, 0x33, 0x5D, 0x49, 0x49,
-  0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
-  0x49, 0x49, 0x49, 0x49, 0x3E, 0x9C, 0x2F, 0x68,
-  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-  0x65, 0xE5, 0x65, 0xE5, 0x6B, 0x90, 0x80, 0x20,
-  0x20, 0x20, 0x4F, 0x81, 0x50, 0x3E, 0x49, 0x49,
-  0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
-  0x69, 0x69, 0x49, 0x5D, 0x2D, 0xC4, 0x46, 0xA3,
-  0xD6, 0x55, 0x70, 0x94, 0x94, 0x70, 0xCB, 0x55,
-  0x55, 0xCB, 0x70, 0x47, 0x70, 0x95, 0xA1, 0xA1,
-  0x95, 0xBD, 0x75, 0x2D, 0x33, 0x49, 0x49, 0x49,
-  0x49, 0x49, 0x5D, 0x49, 0x49, 0x49, 0x49, 0x49,
-  0x49, 0x49, 0x49, 0x49, 0x5D, 0x2D, 0xB5, 0xDB,
-  0xD6, 0x65, 0xE5, 0x65, 0xE5, 0xE5, 0x65, 0xE5,
-  0x65, 0x65, 0x6B, 0x95, 0x2B, 0x88, 0x20, 0x20,
-  0x20, 0x20, 0x8B, 0x81, 0x29, 0x33, 0x49, 0x49,
-  0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
-  0x49, 0x3E, 0x3E, 0x5E, 0x41, 0x97, 0x27, 0xD6,
-  0x55, 0x94, 0xE6, 0xE6, 0x47, 0x70, 0x55, 0x55,
-  0x94, 0x70, 0x94, 0x94, 0x70, 0x55, 0xA1, 0x2C,
-  0x6D, 0xC5, 0x39, 0x6A, 0x5D, 0x5D, 0x49, 0x49,
-  0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
-  0x49, 0x49, 0x49, 0x49, 0x3E, 0xEA, 0x30, 0x77,
-  0xE1, 0xC9, 0x94, 0x2C, 0xD6, 0xD6, 0xA1, 0x55,
-  0x47, 0x9F, 0x43, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x80, 0x91, 0x81, 0x6A, 0x2D, 0x49, 0x49,
-  0x49, 0x5D, 0x5D, 0x49, 0x49, 0x5D, 0x5D, 0x82,
-  0xEB, 0x4A, 0x41, 0xC2, 0x8F, 0xF5, 0xA1, 0x55,
-  0x94, 0x28, 0xA0, 0x47, 0x70, 0x55, 0x95, 0x95,
-  0x47, 0x70, 0x70, 0x94, 0x90, 0x95, 0xA1, 0x2C,
-  0xE8, 0xA6, 0x39, 0x76, 0x50, 0x50, 0x2D, 0x2D,
-  0x3E, 0x3E, 0x5D, 0x3E, 0x5D, 0x5D, 0x49, 0x82,
-  0x49, 0x49, 0x49, 0x82, 0x82, 0x50, 0x75, 0xE0,
-  0x57, 0x20, 0x88, 0x88, 0x20, 0x20, 0x88, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x79, 0x91, 0x81, 0x76, 0x33, 0x49, 0x49,
-  0x5D, 0x82, 0x49, 0x49, 0x3E, 0x6A, 0xEA, 0x29,
-  0xDF, 0x97, 0xBF, 0x6D, 0x6D, 0xD6, 0x55, 0x47,
-  0x28, 0x28, 0x47, 0x70, 0x55, 0x95, 0x2C, 0x2C,
-  0x95, 0x95, 0x55, 0x90, 0x90, 0x95, 0xA1, 0xA1,
-  0xD6, 0x26, 0x45, 0x81, 0x5F, 0x30, 0x48, 0x6F,
-  0x6F, 0x29, 0x29, 0x6A, 0x2D, 0x2D, 0x5D, 0x49,
-  0x49, 0x49, 0x49, 0x49, 0x2D, 0x76, 0x6E, 0x77,
-  0x5B, 0x66, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x79, 0xA9, 0xB8, 0x39, 0x50, 0x5D, 0x5D,
-  0x5D, 0x5D, 0x3E, 0x2D, 0x29, 0x76, 0xCD, 0x37,
-  0xB9, 0xA1, 0xA1, 0x6D, 0x6D, 0x2C, 0x94, 0x28,
-  0xD5, 0xE6, 0x70, 0x55, 0x95, 0xA1, 0x2C, 0xA1,
-  0xBF, 0xA1, 0x95, 0xCB, 0x55, 0x95, 0xA1, 0x2C,
-  0x95, 0x83, 0xDE, 0x87, 0xB6, 0xBE, 0x40, 0x6E,
-  0x81, 0x81, 0x78, 0x78, 0x39, 0x6F, 0xEA, 0x2D,
-  0x2D, 0x33, 0x33, 0x33, 0x76, 0x30, 0x64, 0x54,
-  0x5B, 0x66, 0x20, 0x20, 0x66, 0x20, 0x88, 0x20,
-  0x20, 0x20, 0x88, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x88, 0x34, 0x8B, 0xF1, 0x23, 0x6F, 0x50, 0x2D,
-  0x2D, 0x6A, 0x29, 0x6F, 0x78, 0x84, 0x9B, 0xD2,
-  0x2C, 0x2C, 0xD6, 0x6D, 0x6D, 0x2C, 0x47, 0xA0,
-  0xE6, 0x70, 0x55, 0x95, 0x2C, 0xA1, 0xA1, 0xA1,
-  0xD2, 0x95, 0x55, 0xCB, 0x55, 0x2C, 0xD6, 0xA1,
-  0x95, 0x95, 0xA1, 0xD6, 0x6D, 0x6D, 0xBA, 0xF3,
-  0x8D, 0x36, 0x74, 0x36, 0xF1, 0xB8, 0x23, 0x78,
-  0x62, 0x4A, 0x29, 0x62, 0x23, 0xF1, 0x54, 0x31,
-  0x57, 0x2B, 0x90, 0x95, 0x2C, 0x2C, 0x2C, 0x2C,
-  0xA1, 0xA1, 0xA1, 0xA1, 0x2C, 0x2C, 0x2C, 0xCB,
-  0xE6, 0x7D, 0xCA, 0xB7, 0xB8, 0x75, 0x6F, 0x6F,
-  0x76, 0x6F, 0x78, 0x81, 0x53, 0xBD, 0x6D, 0x2C,
-  0x95, 0x95, 0xA1, 0x6D, 0xA1, 0x55, 0x94, 0xE6,
-  0x70, 0xCB, 0x55, 0x95, 0xA1, 0xD6, 0xD6, 0xA1,
-  0xD0, 0x94, 0x94, 0x90, 0x95, 0x2C, 0xD6, 0xA1,
-  0x95, 0x55, 0x2C, 0xA1, 0xD6, 0xA1, 0x95, 0x2C,
-  0xD6, 0x68, 0xAB, 0x6C, 0xA4, 0x77, 0x77, 0xAD,
-  0x40, 0x53, 0x6E, 0x40, 0xB7, 0x54, 0x31, 0xD7,
-  0xAC, 0xD6, 0x55, 0x55, 0x95, 0x95, 0x95, 0x55,
-  0x95, 0x2C, 0x2C, 0xA1, 0x95, 0x95, 0x2C, 0xA1,
-  0x6D, 0xD2, 0x7C, 0x54, 0xAD, 0x40, 0x6E, 0x81,
-  0x81, 0x6E, 0x36, 0xDA, 0xE8, 0xD6, 0xD6, 0x2C,
-  0x2C, 0x2C, 0xA1, 0xD6, 0x95, 0x90, 0x94, 0x47,
-  0x94, 0x94, 0x70, 0x55, 0x2C, 0xD6, 0xA1, 0x95,
-  0x95, 0x28, 0x47, 0x90, 0x95, 0x2C, 0xA1, 0x2C,
-  0x55, 0x95, 0x2C, 0xA1, 0xA1, 0x2C, 0x2C, 0x2C,
-  0x2C, 0xA1, 0x55, 0x70, 0x95, 0x2C, 0xB2, 0xB4,
-  0xC3, 0xC3, 0x54, 0x54, 0xA9, 0x31, 0xCA, 0x2A,
-  0x95, 0x90, 0x55, 0x95, 0x2C, 0xA1, 0x2C, 0x95,
-  0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0xD6,
-  0x6D, 0x2A, 0xB2, 0x4F, 0x31, 0x2E, 0xE0, 0xAD,
-  0xB7, 0xC8, 0xB4, 0xF5, 0x2C, 0xA1, 0xA1, 0xA1,
-  0x95, 0x2C, 0xA1, 0x2C, 0x95, 0x70, 0x94, 0x94,
-  0x94, 0x94, 0x70, 0x95, 0xD6, 0xD6, 0x2C, 0x95,
-  0x94, 0x28, 0x47, 0xCB, 0x95, 0x2C, 0xA1, 0xA1,
-  0x95, 0x55, 0x2C, 0xA1, 0xD6, 0xA1, 0x95, 0x95,
-  0x95, 0x2C, 0x55, 0x70, 0x70, 0x70, 0x94, 0x2C,
-  0x63, 0xBB, 0xA5, 0xD7, 0xCA, 0xB3, 0x6D, 0x2C,
-  0x55, 0x55, 0x95, 0x2C, 0x2C, 0x2C, 0x95, 0x95,
-  0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0xA1,
-  0xD6, 0x2C, 0x70, 0x95, 0xAC, 0xC0, 0xDB, 0xEF,
-  0xEF, 0xA2, 0xE8, 0x95, 0x95, 0xA1, 0xD6, 0xA1,
-  0x95, 0x55, 0x2C, 0x95, 0x55, 0x70, 0x70, 0x70,
-  0x94, 0x70, 0x55, 0xD6, 0x6D, 0x6D, 0x95, 0x55,
-  0x70, 0x47, 0x70, 0x95, 0x2C, 0x2C, 0x2C, 0xA1,
-  0x2C, 0x95, 0x2C, 0xA1, 0xD6, 0xA1, 0x95, 0x55,
-  0x55, 0x95, 0x55, 0x55, 0x55, 0x55, 0x55, 0x95,
-  0xA1, 0xF5, 0xBF, 0xBF, 0xA1, 0x95, 0x95, 0x95,
-  0x95, 0x55, 0x2C, 0x2C, 0x95, 0x55, 0x55, 0x95,
-  0x95, 0x95, 0xA1, 0xA1, 0xA1, 0xA1, 0x2C, 0xA1,
-  0x2C, 0x55, 0x70, 0x94, 0x90, 0x2C, 0x6D, 0x6D,
-  0x6D, 0xA1, 0x2C, 0x95, 0x2C, 0xA1, 0xD6, 0xA1,
-  0x2C, 0x55, 0x55, 0x95, 0x55, 0x55, 0x55, 0x55,
-  0x55, 0x95, 0xD6, 0x6D, 0xBF, 0xD6, 0x55, 0xCB,
-  0x55, 0x55, 0x55, 0x2C, 0x2C, 0x2C, 0x2C, 0xA1,
-  0xA1, 0x95, 0x2C, 0xA1, 0xA1, 0xA1, 0x2C, 0x95,
-  0x55, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0xA1,
-  0x6D, 0xBF, 0x6D, 0x2C, 0x55, 0x55, 0x95, 0x95,
-  0xCB, 0xCB, 0x55, 0x55, 0xCB, 0x55, 0x55, 0x95,
-  0x95, 0x2C, 0x2C, 0xA1, 0xA1, 0xA1, 0x2C, 0x2C,
-  0xA1, 0x95, 0xCB, 0xCB, 0x95, 0x95, 0x2C, 0x2C,
-  0x2C, 0xA1, 0x2C, 0x2C, 0x2C, 0xA1, 0xA1, 0x2C,
-  0x2C, 0x95, 0x55, 0x95, 0x95, 0x2C, 0x2C, 0x2C,
-  0x2C, 0xA1, 0x6D, 0xBF, 0x6D, 0xA1, 0x55, 0x55,
-  0x95, 0x95, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C,
-  0x2C, 0x95, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x95,
-  0x55, 0x95, 0x2C, 0x2C, 0xA1, 0xA1, 0xD6, 0xD6,
-  0x6D, 0x6D, 0xA1, 0x95, 0xCB, 0x55, 0x95, 0x55,
-  0x90, 0x70, 0xCB, 0xCB, 0x90, 0xCB, 0x95, 0x95,
-  0x2C, 0x2C, 0xA1, 0xD6, 0xA1, 0xA1, 0xA1, 0xA1,
-  0xA1, 0xA1, 0x2C, 0x95, 0x95, 0x2C, 0x2C, 0x2C,
-  0x2C, 0xA1, 0x2C, 0x95, 0x95, 0x95, 0x2C, 0x2C,
-  0x2C, 0x95, 0x55, 0x55, 0x2C, 0x2C, 0xA1, 0xA1,
-  0xD6, 0xD6, 0x6D, 0x6D, 0xA1, 0x55, 0xCB, 0x55
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22,
+    0x22, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+    0x26, 0x26, 0x25, 0x28, 0x23, 0x22, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x25, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d,
+    0x2d, 0x2e, 0x2c, 0x2b, 0x2a, 0x25, 0x28, 0x22,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x24, 0x2a, 0x2c, 0x2f, 0x2c, 0x30, 0x30, 0x24,
+    0x25, 0x27, 0x2b, 0x2c, 0x2f, 0x31, 0x32, 0x25,
+    0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
+    0x33, 0x34, 0x35, 0x21, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x21, 0x2b, 0x2f, 0x2c,
+    0x30, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
+    0x2d, 0x27, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x31,
+    0x2d, 0x32, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x28, 0x2a, 0x34,
+    0x25, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x23, 0x32, 0x27, 0x21, 0x36,
+    0x2a, 0x2d, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x22, 0x26, 0x2c, 0x35,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x25, 0x2f, 0x37, 0x32, 0x22,
+    0x36, 0x35, 0x31, 0x27, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x22,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x26, 0x38, 0x38, 0x35, 0x25,
+    0x36, 0x21, 0x2d, 0x2b, 0x24, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x24, 0x39, 0x39, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x25, 0x2b, 0x30, 0x28, 0x22,
+    0x36, 0x36, 0x27, 0x34, 0x30, 0x23, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x26, 0x2d, 0x26, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x22, 0x22, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x2d, 0x33, 0x28, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x2b, 0x2c, 0x25, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x36, 0x36,
+    0x36, 0x21, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x21, 0x23, 0x22, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x28, 0x34, 0x27, 0x22, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
+    0x21, 0x21, 0x24, 0x27, 0x21, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x28, 0x27, 0x22, 0x33, 0x24, 0x36,
+    0x36, 0x36, 0x36, 0x22, 0x2f, 0x2a, 0x23, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
+    0x30, 0x3a, 0x38, 0x24, 0x24, 0x36, 0x36, 0x36,
+    0x23, 0x2f, 0x3b, 0x3c, 0x3d, 0x30, 0x25, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2f, 0x32, 0x23, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x23,
+    0x3e, 0x3f, 0x40, 0x3a, 0x22, 0x36, 0x36, 0x21,
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x3e, 0x23, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2f, 0x33, 0x28, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x2b,
+    0x44, 0x40, 0x46, 0x47, 0x35, 0x36, 0x36, 0x26,
+    0x43, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x2e, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x32, 0x34, 0x36, 0x4d,
+    0x4e, 0x25, 0x2f, 0x46, 0x4a, 0x22, 0x23, 0x32,
+    0x4f, 0x50, 0x21, 0x31, 0x51, 0x52, 0x53, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x21, 0x3a,
+    0x4d, 0x21, 0x31, 0x54, 0x55, 0x28, 0x30, 0x2b,
+    0x4b, 0x4d, 0x36, 0x23, 0x32, 0x50, 0x3f, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x20, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x38, 0x23, 0x37,
+    0x55, 0x36, 0x28, 0x3a, 0x56, 0x57, 0x57, 0x58,
+    0x3c, 0x4d, 0x36, 0x36, 0x36, 0x40, 0x40, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x29, 0x29, 0x29, 0x20, 0x29, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x51, 0x23, 0x35,
+    0x43, 0x25, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e,
+    0x5f, 0x60, 0x61, 0x36, 0x31, 0x47, 0x3b, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x31, 0x2c, 0x25, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x22,
+    0x40, 0x62, 0x63, 0x5d, 0x64, 0x65, 0x66, 0x67,
+    0x68, 0x69, 0x66, 0x5e, 0x6a, 0x6b, 0x2a, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x33, 0x2e, 0x26, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x2f, 0x23, 0x36,
+    0x6c, 0x63, 0x6d, 0x64, 0x5c, 0x66, 0x69, 0x6e,
+    0x6f, 0x70, 0x71, 0x69, 0x69, 0x72, 0x6c, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x33, 0x34, 0x27, 0x22,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x34, 0x26, 0x73,
+    0x74, 0x75, 0x76, 0x64, 0x65, 0x77, 0x69, 0x78,
+    0x70, 0x71, 0x71, 0x71, 0x72, 0x5f, 0x5e, 0x21,
+    0x36, 0x36, 0x36, 0x36, 0x25, 0x38, 0x2a, 0x23,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x33, 0x79,
+    0x63, 0x7a, 0x7b, 0x5c, 0x66, 0x69, 0x6e, 0x7c,
+    0x71, 0x71, 0x69, 0x7d, 0x7e, 0x7a, 0x7f, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x21, 0x51, 0x2b, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x32, 0x24,
+    0x80, 0x81, 0x64, 0x82, 0x77, 0x69, 0x71, 0x71,
+    0x69, 0x83, 0x84, 0x85, 0x7a, 0x85, 0x86, 0x36,
+    0x21, 0x2b, 0x23, 0x36, 0x36, 0x39, 0x2e, 0x26,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x27, 0x2d, 0x33, 0x21,
+    0x87, 0x88, 0x89, 0x72, 0x67, 0x66, 0x5f, 0x89,
+    0x8a, 0x63, 0x85, 0x8b, 0x8c, 0x8d, 0x41, 0x36,
+    0x36, 0x2d, 0x3a, 0x35, 0x36, 0x24, 0x51, 0x32,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x33, 0x21,
+    0x55, 0x8e, 0x8f, 0x8a, 0x7d, 0x5e, 0x90, 0x7e,
+    0x75, 0x75, 0x90, 0x62, 0x40, 0x3f, 0x49, 0x23,
+    0x36, 0x24, 0x3a, 0x3a, 0x24, 0x36, 0x2e, 0x31,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x28, 0x33, 0x37, 0x25, 0x22,
+    0x3b, 0x50, 0x8e, 0x8f, 0x90, 0x7e, 0x90, 0x63,
+    0x74, 0x91, 0x92, 0x42, 0x93, 0x4b, 0x45, 0x2c,
+    0x36, 0x36, 0x33, 0x39, 0x21, 0x36, 0x22, 0x51,
+    0x33, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x22, 0x27, 0x2e, 0x2e, 0x36, 0x21,
+    0x94, 0x3f, 0x50, 0x95, 0x96, 0x8f, 0x8f, 0x97,
+    0x8e, 0x42, 0x50, 0x43, 0x47, 0x48, 0x48, 0x98,
+    0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39,
+    0x2e, 0x27, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x22, 0x24, 0x2b, 0x38, 0x28, 0x36, 0x32,
+    0x4c, 0x4b, 0x50, 0x50, 0x50, 0x42, 0x42, 0x50,
+    0x50, 0x40, 0x45, 0x99, 0x48, 0x48, 0x48, 0x48,
+    0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x23,
+    0x2f, 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x32, 0x51, 0x32, 0x28, 0x21, 0x98,
+    0x48, 0x47, 0x9a, 0x50, 0x50, 0x50, 0x50, 0x50,
+    0x9a, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x93, 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x2a, 0x2f, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x23, 0x30, 0x2e, 0x2c, 0x36, 0x21, 0x51, 0x9b,
+    0x48, 0x48, 0x52, 0x3f, 0x50, 0x50, 0x40, 0x4b,
+    0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2d, 0x31, 0x27, 0x23, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x27, 0x2c, 0x2d, 0x21, 0x36, 0x28, 0x44, 0x48,
+    0x48, 0x48, 0x48, 0x47, 0x46, 0x4f, 0x47, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x9c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x28, 0x51, 0x39, 0x26, 0x22, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
+    0x35, 0x51, 0x28, 0x36, 0x36, 0x9d, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x4f, 0x28, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x28, 0x38, 0x2b, 0x25, 0x22, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
+    0x51, 0x25, 0x36, 0x36, 0x23, 0x40, 0x9b, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x9b, 0x99, 0x2b, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x30, 0x2f, 0x33, 0x24, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x23, 0x30, 0x34,
+    0x27, 0x36, 0x36, 0x36, 0x2a, 0x40, 0x47, 0x48,
+    0x48, 0x48, 0x48, 0x9b, 0x99, 0x99, 0x9b, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x47, 0x52,
+    0x46, 0x4f, 0x37, 0x21, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x30, 0x34, 0x2a, 0x23,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x22, 0x25, 0x39, 0x2c,
+    0x36, 0x36, 0x36, 0x21, 0x31, 0x4e, 0x9a, 0x4c,
+    0x47, 0x9b, 0x9b, 0x52, 0x46, 0x4f, 0x52, 0x9b,
+    0x9b, 0x9b, 0x47, 0x4f, 0x45, 0x9a, 0x93, 0x93,
+    0x3f, 0x93, 0x98, 0x28, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, 0x26,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x28,
+    0x36, 0x36, 0x36, 0x22, 0x38, 0x98, 0x44, 0x99,
+    0x9b, 0x48, 0x48, 0x9b, 0x4c, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x47, 0x52, 0x46, 0x43, 0x93,
+    0x40, 0x40, 0x43, 0x53, 0x21, 0x23, 0x33, 0x23,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x2f, 0x32,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x24, 0x2b, 0x31, 0x36,
+    0x36, 0x22, 0x36, 0x24, 0x9e, 0x4f, 0x9b, 0x48,
+    0x48, 0x48, 0x48, 0x9b, 0x99, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x47,
+    0x4f, 0x9a, 0x3f, 0x46, 0x38, 0x36, 0x21, 0x30,
+    0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c,
+    0x25, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x22, 0x26, 0x2e, 0x33, 0x36,
+    0x25, 0x25, 0x36, 0x4d, 0x52, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x47, 0x44, 0x93, 0x43, 0x23, 0x36, 0x36,
+    0x26, 0x24, 0x36, 0x36, 0x36, 0x36, 0x28, 0x2f,
+    0x2a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x23, 0x2a, 0x51, 0x24, 0x36,
+    0x2a, 0x36, 0x28, 0x44, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x9b, 0x4b, 0x44, 0x37, 0x36, 0x23,
+    0x28, 0x30, 0x22, 0x36, 0x36, 0x36, 0x36, 0x2d,
+    0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x28, 0x2b, 0x34, 0x36, 0x25,
+    0x24, 0x36, 0x4a, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x9b, 0x52, 0x3f, 0x21, 0x30,
+    0x35, 0x25, 0x30, 0x36, 0x36, 0x36, 0x36, 0x32,
+    0x2d, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x22, 0x26, 0x2e, 0x35, 0x36, 0x2a,
+    0x36, 0x24, 0x4f, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x47, 0x32, 0x30,
+    0x2a, 0x23, 0x30, 0x23, 0x36, 0x36, 0x36, 0x21,
+    0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x2a, 0x51, 0x28, 0x28, 0x25,
+    0x36, 0x3a, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x9b, 0x52, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x38, 0x21,
+    0x36, 0x36, 0x22, 0x27, 0x36, 0x36, 0x36, 0x36,
+    0x2e, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x22, 0x25, 0x2c, 0x34, 0x36, 0x30, 0x21,
+    0x23, 0x43, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x47, 0x99, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x94, 0x36,
+    0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36,
+    0x2a, 0x2e, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x2a, 0x51, 0x25, 0x21, 0x2a, 0x36,
+    0x2e, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x99, 0x99, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x98, 0x36,
+    0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36,
+    0x22, 0x2f, 0x30, 0x22, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x22, 0x25, 0x2c, 0x34, 0x36, 0x24, 0x28, 0x36,
+    0x54, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36,
+    0x36, 0x36, 0x36, 0x30, 0x36, 0x36, 0x36, 0x36,
+    0x21, 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x28, 0x32, 0x2f, 0x28, 0x36, 0x27, 0x22, 0x21,
+    0x43, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4b, 0x21,
+    0x36, 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x25, 0x2c, 0x39, 0x36, 0x36, 0x30, 0x22, 0x25,
+    0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x4f, 0x52, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4f, 0x21,
+    0x36, 0x36, 0x22, 0x26, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x30, 0x2d, 0x21, 0x36, 0x36, 0x32, 0x23, 0x2a,
+    0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x4f, 0x99, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x22,
+    0x36, 0x36, 0x24, 0x23, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0x2e, 0x36, 0x36, 0x23, 0x31, 0x27, 0x39,
+    0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x23,
+    0x36, 0x36, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x2b, 0x39, 0x36, 0x36, 0x36, 0x26, 0x32, 0x31,
+    0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x46, 0x22,
+    0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x35, 0x39, 0x36, 0x36, 0x36, 0x36, 0x26, 0x2d,
+    0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36,
+    0x24, 0x27, 0x9f, 0x24, 0x25, 0x28, 0x21, 0x36,
+    0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x25,
+    0x39, 0x4d, 0xa0, 0x84, 0x81, 0x57, 0x21, 0x39,
+    0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x53, 0x28,
+    0x23, 0x36, 0x36, 0x36, 0x21, 0x28, 0x2c, 0x30,
+    0x21, 0x38, 0x33, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x28, 0x30,
+    0x2d, 0xa1, 0x7a, 0xa2, 0xa3, 0xa3, 0x7f, 0x22,
+    0x51, 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0xa4, 0xa5, 0xa5, 0xa6, 0x61,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x30, 0x32,
+    0x25, 0x4d, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x24, 0x26, 0x30, 0x33, 0x31,
+    0x4d, 0x91, 0x5b, 0xa2, 0xa3, 0xa3, 0xa3, 0x5a,
+    0x21, 0x2e, 0x46, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0xa7, 0xa8, 0x69, 0x66, 0xa9,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x26, 0x25,
+    0x83, 0xaa, 0x2c, 0x25, 0x21, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x30, 0x35, 0x2d, 0x2f, 0x37, 0x4a,
+    0x60, 0x85, 0xab, 0xac, 0xa3, 0xa3, 0xa3, 0x82,
+    0x86, 0x36, 0x32, 0x3f, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0xad, 0xa2, 0xa8, 0xae, 0xaf,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x57,
+    0x77, 0x66, 0x34, 0x27, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x23, 0x30, 0x31, 0xb0, 0x91, 0x7e, 0x90, 0x90,
+    0x8b, 0x5b, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0x5d, 0xb1, 0x36, 0x24, 0x53, 0x9b, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x9b, 0x99, 0xad, 0x64, 0x5c, 0x8b, 0xb1,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x73, 0x5d,
+    0x82, 0x5c, 0xb2, 0x2a, 0x23, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x24, 0x2b, 0xb0, 0x8b, 0x5b, 0x76, 0x5b, 0x5b,
+    0x7b, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa8, 0x5e, 0x22, 0x36, 0x21, 0x3a, 0x99, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x4f, 0x3f, 0xb3, 0x7b, 0x7b, 0x85, 0x80,
+    0x9f, 0x36, 0x36, 0x36, 0x21, 0xb4, 0x7e, 0x7b,
+    0x64, 0x64, 0xb5, 0x35, 0x24, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x31, 0xb6, 0x5b, 0x64, 0xa2, 0xa2, 0xac,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa3, 0x66, 0xb7, 0x36, 0x36, 0x36, 0x2c, 0x4b,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x9a, 0x3f, 0xb8, 0x76, 0x76, 0x7a, 0x63,
+    0xb9, 0xba, 0x86, 0xba, 0xbb, 0x90, 0x5b, 0x64,
+    0xa2, 0xa2, 0xbc, 0x2d, 0x27, 0x23, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x26, 0x2d, 0x91, 0x5b, 0x64, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa8, 0x83, 0xaf, 0x36, 0x36, 0x36, 0x30,
+    0x44, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x9b, 0x9a, 0x3f, 0xbd, 0x5b, 0x7b, 0xbe, 0x85,
+    0x7e, 0x90, 0x63, 0x90, 0x85, 0x5b, 0xa2, 0xa3,
+    0xa3, 0xac, 0x5d, 0xb5, 0x39, 0x26, 0x23, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2d, 0xbf, 0xbe, 0x64, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa8, 0x88, 0x36, 0x36, 0x36, 0x36,
+    0x2d, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x9b, 0x45, 0x3f, 0xc0, 0x6d, 0x7b, 0xab, 0xbe,
+    0x7a, 0x8b, 0x8b, 0x7a, 0x5b, 0x64, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa2, 0xc1, 0x37, 0x35, 0x26, 0x23,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2e, 0xbf, 0x7a, 0x7b, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa8, 0x72, 0x73, 0x36, 0x36, 0x36,
+    0x24, 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x46, 0x42, 0xb6, 0x7a, 0x7b, 0x64, 0x7b,
+    0x76, 0x5b, 0x5b, 0x76, 0x7b, 0xa2, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xac, 0x64, 0xc1, 0x4d, 0x2c, 0x27,
+    0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x25, 0x31, 0xc2, 0x8b, 0x7b, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa8, 0x89, 0x9f, 0x36, 0x36,
+    0x32, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x4b, 0x2f, 0x8f, 0x7a, 0x7b, 0xa2, 0xac,
+    0xa2, 0x64, 0x64, 0xa2, 0xa2, 0xac, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x5d, 0xc3, 0x2c,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x25, 0x31, 0xc2, 0x85, 0x7b, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0x66, 0x57, 0x27, 0x4d,
+    0x4b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x99, 0x34, 0x9f, 0xb9, 0x7a, 0x7b, 0xa2, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xc2,
+    0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+    0x26, 0x2d, 0xc2, 0x85, 0x7b, 0xac, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa8, 0x5f, 0x92, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x44,
+    0x35, 0x36, 0xaf, 0xbb, 0x7a, 0x7b, 0xac, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0xa2, 0xc0,
+    0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x30, 0x2f, 0xb6, 0x8b, 0x7b, 0xac, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x66, 0x89, 0x45,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x4e, 0x25,
+    0x36, 0x36, 0x61, 0xb9, 0x6d, 0x64, 0xac, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x7b, 0xbe, 0xc3,
+    0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0xc4, 0x63, 0xbe, 0xa2, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x72, 0x81, 0xc5,
+    0x46, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x48, 0x48, 0x48, 0x48, 0x3f, 0x2c, 0x36, 0x36,
+    0x36, 0x36, 0xc6, 0x8f, 0x6d, 0x64, 0xac, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa2, 0xab, 0x8b, 0xb0, 0x2c,
+    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x35, 0x96, 0x75, 0xab, 0xa2, 0xac, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x7b, 0x81, 0xb9,
+    0x73, 0x3b, 0x44, 0x9b, 0x48, 0x48, 0x48, 0x9b,
+    0x99, 0x43, 0x94, 0x2c, 0x21, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x73, 0xb9, 0x7a, 0x7b, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa3, 0x64, 0x76, 0x7a, 0x91, 0xb5, 0x31, 0x30,
+    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+    0x39, 0x97, 0x75, 0xbe, 0x7b, 0x64, 0xa2, 0xa2,
+    0xac, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x7b, 0x7a, 0xc7,
+    0xc8, 0x36, 0x21, 0x26, 0x2b, 0x39, 0x33, 0x30,
+    0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xc8, 0xbb, 0x8b, 0x7b, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x64, 0x64,
+    0x76, 0x85, 0xbf, 0xb5, 0x34, 0x2b, 0x27, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+    0x33, 0xc9, 0x63, 0x7e, 0x7a, 0x6d, 0xbe, 0x5b,
+    0x76, 0x7b, 0x64, 0x64, 0xa2, 0xac, 0xa3, 0xa3,
+    0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x76, 0x85, 0xb9,
+    0x79, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xca, 0xbb, 0x75, 0x76, 0xa2, 0xa3,
+    0xa3, 0xa3, 0xac, 0xa2, 0x64, 0x76, 0xbe, 0x8b,
+    0xb6, 0xb5, 0x2f, 0x35, 0x30, 0x24, 0x22, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+    0x27, 0x31, 0xcb, 0xc9, 0xbb, 0x74, 0x63, 0x90,
+    0x7e, 0x75, 0x8b, 0x6d, 0xbe, 0x76, 0x64, 0xa2,
+    0xac, 0xac, 0xac, 0xac, 0x64, 0x7a, 0x84, 0xcc,
+    0x79, 0x9f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x21, 0xc8, 0xcc, 0x63, 0x6d, 0x7b, 0x64,
+    0xac, 0xa2, 0x64, 0x7b, 0xbe, 0x75, 0x63, 0x96,
+    0x38, 0x39, 0x2a, 0x24, 0x23, 0x21, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x28, 0x27, 0x35, 0x2d, 0x41, 0xb5, 0xc5, 0x8f,
+    0xb9, 0xbb, 0xc7, 0x74, 0x84, 0x90, 0x85, 0x6d,
+    0x5b, 0x7b, 0x7b, 0xab, 0x6d, 0x90, 0xb9, 0xcd,
+    0xca, 0x22, 0x36, 0x36, 0x28, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x25, 0x36,
+    0x36, 0x21, 0xb4, 0x80, 0xc7, 0x7e, 0x6d, 0x76,
+    0xab, 0x76, 0x6d, 0x85, 0x63, 0xb9, 0xb5, 0x34,
+    0x33, 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x23, 0x24, 0x27, 0x2a, 0x35, 0x2e, 0x2f,
+    0x41, 0xce, 0xcf, 0x6c, 0x80, 0xcc, 0xb9, 0x74,
+    0x84, 0x90, 0x75, 0x7e, 0x74, 0x8f, 0xcd, 0x79,
+    0xc6, 0x2b, 0x9d, 0x41, 0x2f, 0x34, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x34, 0x2f, 0x38,
+    0x4d, 0x37, 0xd0, 0xd1, 0x8f, 0x74, 0x63, 0x7e,
+    0x75, 0x7e, 0x63, 0xc7, 0x88, 0xc4, 0x31, 0x2a,
+    0x24, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x21, 0x22, 0x23, 0x24, 0x26, 0x30,
+    0x33, 0x39, 0x2e, 0x51, 0x41, 0xb2, 0x6c, 0xd1,
+    0x80, 0xcc, 0xcc, 0xcc, 0xd2, 0xd1, 0xb7, 0xd3,
+    0x41, 0x34, 0x35, 0x32, 0x30, 0x27, 0x27, 0x27,
+    0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x2a,
+    0x2b, 0x34, 0xd4, 0xca, 0xd5, 0x8f, 0xbb, 0xc7,
+    0xc7, 0xbb, 0xcc, 0x6c, 0x41, 0x39, 0x27, 0x28,
+    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22,
+    0x28, 0x24, 0x26, 0x2a, 0x33, 0x2c, 0x2f, 0x41,
+    0xd6, 0xb7, 0x79, 0x79, 0x79, 0xca, 0xd7, 0x51,
+    0x39, 0x30, 0x24, 0x23, 0x22, 0x22, 0x22, 0x22,
+    0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23,
+    0x24, 0x2a, 0x31, 0xd8, 0xc8, 0x79, 0xd1, 0x80,
+    0xd5, 0xba, 0xd9, 0x2f, 0x35, 0x26, 0x23, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x22, 0x23, 0x28, 0x25, 0x30, 0x2b,
+    0x31, 0x2f, 0xd4, 0xd8, 0xd8, 0x2f, 0x2e, 0x33,
+    0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x21, 0x28, 0x27, 0x35, 0x34, 0xd8, 0xd8, 0xd8,
+    0xda, 0xd4, 0x2e, 0x33, 0x25, 0x23, 0x21, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x23, 0x28,
+    0x26, 0x30, 0x32, 0x2b, 0x33, 0x2a, 0x26, 0x28,
+    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x21, 0x23, 0x25, 0x30, 0x33, 0x35, 0x35,
+    0x2b, 0x2a, 0x26, 0x28, 0x22, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+    0x21, 0x22, 0x23, 0x28, 0x28, 0x23, 0x22, 0x21,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x21, 0x23, 0x28, 0x24, 0x24,
+    0x28, 0x23, 0x22, 0x21, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 };
 
-#endif
+#endif /* !__HAVE_ARCH_LINUX_LOGO */
 
-#ifdef INCLUDE_LINUX_LOGOBW
+#ifndef __HAVE_ARCH_LINUX_LOGOBW
 
 unsigned char linux_logo_bw[] __initdata = {
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F,
-  0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFE, 0x3F, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xC7, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xC3,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF,
-  0xFB, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFD, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF,
-  0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xCF, 0xC3, 0xF8, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x87, 0x81, 0xF9,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xA7,
-  0x99, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xF3, 0xBC, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xE3, 0xBC, 0xF9, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0, 0x3C, 0xF9,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0,
-  0x19, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xC0, 0x03, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x80,
-  0x01, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xC0, 0x21, 0xD8, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xB1, 0x80, 0xEC, 0xC0, 0x1F,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x90, 0x00, 0xE4,
-  0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x8C,
-  0xC0, 0x7C, 0x04, 0x81, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xE3, 0x80, 0x00, 0x7C, 0x40, 0x11, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xE3, 0x80, 0x00, 0x7F, 0xD2, 0x29,
-  0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0x00, 0x00, 0x3F,
-  0x80, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0x0E, 0x00,
-  0x00, 0x3F, 0x80, 0x19, 0xFF, 0xFF, 0xFF, 0xFF,
-  0x1E, 0x00, 0x00, 0x1F, 0x80, 0x19, 0xFF, 0xFF,
-  0xFF, 0xFE, 0x1C, 0x00, 0x00, 0x1E, 0x80, 0x19,
-  0xFF, 0xFF, 0xFF, 0xFE, 0x3C, 0x00, 0x00, 0x1E,
-  0x80, 0x11, 0xFF, 0xFF, 0xFF, 0xFC, 0x7C, 0x00,
-  0x00, 0x0F, 0x80, 0x11, 0xFF, 0xFF, 0xFF, 0xFC,
-  0xF8, 0x00, 0x00, 0x0E, 0x80, 0x11, 0xFF, 0xFF,
-  0xFF, 0xFC, 0xF8, 0x00, 0x00, 0x06, 0x00, 0x11,
-  0xFF, 0xFF, 0xFF, 0xF8, 0xF8, 0x00, 0x00, 0x06,
-  0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xF9, 0xF0, 0x00,
-  0x00, 0x02, 0x00, 0x09, 0xFF, 0xFF, 0xFF, 0xF1,
-  0xF0, 0x00, 0x00, 0x02, 0x80, 0x10, 0xFF, 0xFF,
-  0xFF, 0xF1, 0xE0, 0x00, 0x00, 0x00, 0x97, 0x10,
-  0xFF, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x00, 0x00,
-  0xDF, 0xF0, 0xFF, 0xFF, 0xFF, 0xE3, 0xC0, 0x00,
-  0x00, 0x00, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xC7,
-  0xC0, 0x00, 0x00, 0x01, 0xFF, 0xF8, 0xFF, 0xFF,
-  0xFF, 0xC7, 0x80, 0x00, 0x00, 0x01, 0xFF, 0xF8,
-  0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x00, 0x01,
-  0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00,
-  0x00, 0x01, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x9F,
-  0x80, 0x00, 0x00, 0x01, 0xFF, 0xF8, 0xFF, 0xFF,
-  0xFF, 0x9F, 0x80, 0x00, 0x00, 0x01, 0x80, 0x18,
-  0xFF, 0xFF, 0xFF, 0x9E, 0x80, 0x00, 0x00, 0x03,
-  0xA8, 0x11, 0xFF, 0xFF, 0xFF, 0x9F, 0x80, 0x00,
-  0x00, 0x02, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x99,
-  0x80, 0x00, 0x00, 0x00, 0x00, 0x09, 0xFF, 0xFF,
-  0xFF, 0x00, 0x80, 0x00, 0x00, 0x01, 0xC0, 0x01,
-  0xFF, 0xFF, 0xFE, 0x20, 0x60, 0x00, 0x00, 0x00,
-  0xFF, 0xC3, 0xFF, 0xFF, 0xF8, 0x00, 0x30, 0x00,
-  0x00, 0x00, 0xFF, 0x0F, 0xFF, 0xFF, 0xC0, 0x40,
-  0x38, 0x00, 0x00, 0x00, 0xFE, 0x47, 0xFF, 0xFF,
-  0x81, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xFC, 0x23,
-  0xFF, 0xFF, 0x90, 0x00, 0x1E, 0x00, 0x00, 0x00,
-  0x78, 0x11, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0x80,
-  0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00,
-  0x07, 0xC0, 0x00, 0x00, 0x00, 0x08, 0xFF, 0xFF,
-  0xC0, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x04,
-  0x7F, 0xFF, 0x80, 0x00, 0x03, 0xC0, 0x00, 0x10,
-  0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x01, 0x80,
-  0x00, 0x30, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00,
-  0x00, 0x00, 0x00, 0x70, 0x00, 0x01, 0x4F, 0xFF,
-  0x80, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00,
-  0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x80, 0x03, 0xF0,
-  0x00, 0x00, 0x8F, 0xFF, 0x80, 0x00, 0x00, 0x40,
-  0x0F, 0xF0, 0x00, 0x04, 0x1F, 0xFF, 0x80, 0x00,
-  0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x10, 0x1F, 0xFF,
-  0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x40,
-  0xFF, 0xFF, 0x98, 0x00, 0x00, 0xFF, 0xFF, 0xF0,
-  0x00, 0x83, 0xFF, 0xFF, 0x81, 0xE0, 0x01, 0xFF,
-  0xFF, 0xF8, 0x02, 0x07, 0xFF, 0xFF, 0x80, 0x3F,
-  0x07, 0xE0, 0x00, 0x1C, 0x0C, 0x1F, 0xFF, 0xFF,
-  0xF8, 0x03, 0xFF, 0x80, 0x00, 0x1F, 0x78, 0x1F,
-  0xFF, 0xFF, 0xFF, 0x80, 0x7F, 0x00, 0x07, 0x0F,
-  0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0x0C, 0x07,
-  0xFF, 0x83, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0x00, 0x1F, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 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, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xcf, 0xf3, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xbf, 0xfc, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfd, 0xff, 0xf3, 0xdf, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfd, 0xff, 0xf7, 0xef, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0x9f, 0x87, 0xfb, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0x0f, 0x03, 0xfb, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0x67, 0x33, 0xfb, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0xe7, 0x79, 0xfb, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0xf7, 0x79, 0xfb, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0xff, 0xf9, 0xf7, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0x60, 0x3b, 0xf7, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0x89, 0x07, 0xfb, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0x00, 0x03, 0xfb, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0x00, 0x0d, 0xfb, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0x80, 0x33, 0xfd, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0xc0, 0xc3, 0xfd, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0xff, 0x0d, 0xdd, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfb, 0x40, 0x31, 0xee, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xf7, 0x20, 0xc1, 0xee, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xf7, 0x1f, 0x00, 0xff, 0x7f, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xef, 0x00, 0x00, 0x7f, 0xbf, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xee, 0x00, 0x00, 0x7f, 0xbf, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xde, 0x00, 0x00, 0x7f, 0xdf, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xbc, 0x00, 0x00, 0x3f, 0xef, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0x7c, 0x00, 0x00, 0x3f, 0xf7, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0x7c, 0x00, 0x00, 0x1f, 0xf7, 0xff, 0xff,
+    0xff, 0xff, 0xfe, 0xff, 0x1c, 0x07, 0xdf, 0xfb, 0xff, 0xff,
+    0xff, 0xff, 0xfd, 0xfc, 0x08, 0x0f, 0xef, 0xfd, 0xff, 0xff,
+    0xff, 0xff, 0xfd, 0xf8, 0x00, 0x01, 0xef, 0xfd, 0xff, 0xff,
+    0xff, 0xff, 0xfb, 0xf0, 0x00, 0x00, 0x7f, 0xfe, 0xff, 0xff,
+    0xff, 0xff, 0xfb, 0xe0, 0x00, 0x00, 0x1f, 0xfe, 0xff, 0xff,
+    0xff, 0xff, 0xf7, 0xe0, 0x00, 0x00, 0x07, 0xbf, 0x7f, 0xff,
+    0xff, 0xff, 0xf7, 0xc0, 0x00, 0x00, 0x03, 0xbf, 0x7f, 0xff,
+    0xff, 0xff, 0xef, 0xc0, 0x00, 0x00, 0x03, 0xdf, 0xbf, 0xff,
+    0xff, 0xff, 0xef, 0x80, 0x00, 0x00, 0x03, 0xdf, 0xbf, 0xff,
+    0xff, 0xff, 0xdf, 0x80, 0x00, 0x00, 0x03, 0xdf, 0xbf, 0xff,
+    0xff, 0xff, 0xdf, 0x80, 0x00, 0x00, 0x01, 0xef, 0xdf, 0xff,
+    0xff, 0xff, 0xdf, 0x80, 0x00, 0x00, 0x01, 0xef, 0xdf, 0xff,
+    0xff, 0xff, 0xbf, 0x00, 0x20, 0x00, 0x01, 0xef, 0xdf, 0xff,
+    0xff, 0xff, 0xbf, 0x00, 0x20, 0x00, 0x01, 0xef, 0xdf, 0xff,
+    0xff, 0xff, 0xbf, 0x00, 0x20, 0x00, 0x01, 0xef, 0xdf, 0xff,
+    0xff, 0xff, 0xbf, 0x00, 0x20, 0x00, 0x01, 0xef, 0xdf, 0xff,
+    0xff, 0xff, 0xbf, 0x00, 0x20, 0x00, 0x03, 0x03, 0xdf, 0xff,
+    0xff, 0xff, 0xbf, 0x00, 0x20, 0x00, 0x02, 0xfd, 0xdf, 0xff,
+    0xff, 0xff, 0xa3, 0x80, 0x00, 0x00, 0x1f, 0xff, 0xdf, 0xff,
+    0xff, 0xff, 0xc1, 0xc0, 0x00, 0x00, 0x11, 0xff, 0x3f, 0xff,
+    0xff, 0xff, 0x80, 0xe0, 0x00, 0x00, 0x21, 0xfe, 0x3f, 0xff,
+    0xff, 0xff, 0x00, 0x70, 0x00, 0x00, 0x21, 0xfc, 0x3f, 0xff,
+    0xff, 0xfe, 0x00, 0x3c, 0x00, 0x00, 0x20, 0xf8, 0x3f, 0xff,
+    0xff, 0xf0, 0x00, 0x3e, 0x00, 0x00, 0x20, 0x00, 0x3f, 0xff,
+    0xff, 0xc0, 0x00, 0x1f, 0x00, 0x00, 0x20, 0x00, 0x3f, 0xff,
+    0xff, 0xc0, 0x00, 0x1f, 0x80, 0x00, 0x20, 0x00, 0x1f, 0xff,
+    0xff, 0xc0, 0x00, 0x0f, 0x80, 0x00, 0x20, 0x00, 0x07, 0xff,
+    0xff, 0xc0, 0x00, 0x07, 0x80, 0x00, 0x20, 0x00, 0x03, 0xff,
+    0xff, 0xc0, 0x00, 0x07, 0x80, 0x00, 0x60, 0x00, 0x01, 0xff,
+    0xff, 0xc0, 0x00, 0x02, 0x00, 0x00, 0xe0, 0x00, 0x01, 0xff,
+    0xff, 0xc0, 0x00, 0x01, 0x00, 0x01, 0xe0, 0x00, 0x01, 0xff,
+    0xff, 0xc0, 0x00, 0x00, 0x80, 0x07, 0xe0, 0x00, 0x03, 0xff,
+    0xff, 0xc0, 0x00, 0x00, 0x80, 0x3f, 0xe0, 0x00, 0x0f, 0xff,
+    0xff, 0xc0, 0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x1f, 0xff,
+    0xff, 0xc0, 0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x7f, 0xff,
+    0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0xff, 0xff,
+    0xff, 0xfc, 0x00, 0x00, 0x7f, 0xff, 0xc0, 0x03, 0xff, 0xff,
+    0xff, 0xff, 0xc0, 0x00, 0x70, 0x00, 0xc0, 0x07, 0xff, 0xff,
+    0xff, 0xff, 0xfc, 0x00, 0x8f, 0xff, 0x20, 0x0f, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xe0, 0x1f, 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,
 };
 
-#endif
+#endif /* !__HAVE_ARCH_LINUX_LOGOBW */
 
-#ifdef INCLUDE_LINUX_LOGO16
+#ifndef __HAVE_ARCH_LINUX_LOGO16
 
-unsigned char linux_logo16_red[] __initdata = {
-    0x00, 0x90, 0xb0, 0x9c, 0xf7, 0x35, 0x83, 0xa5,
-    0x65, 0x8f, 0x98, 0xc9, 0xdb, 0xe1, 0xe7, 0xf8
+unsigned char linux_logo16[] __initdata = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x88, 0x88, 0x88, 0x80, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x88, 0x80, 0x00, 0x00, 0x08, 0x88, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x00,
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x80,
+    0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+    0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+    0x08, 0x70, 0x00, 0x00, 0x00, 0x77, 0x70, 0x00,
+    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+    0x87, 0x77, 0x00, 0x00, 0x07, 0xff, 0xf7, 0x00,
+    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
+    0x77, 0xff, 0x00, 0x00, 0x7f, 0x77, 0xf7, 0x00,
+    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
+    0x70, 0x0f, 0x80, 0x00, 0xf7, 0x08, 0x7f, 0x70,
+    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
+    0x80, 0x07, 0x80, 0x00, 0xf8, 0x00, 0x8f, 0x70,
+    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
+    0x70, 0x07, 0x88, 0x88, 0xf8, 0x00, 0x8f, 0x70,
+    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+    0xf0, 0x06, 0xe6, 0xe6, 0xe6, 0x00, 0x8f, 0x00,
+    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+    0x77, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x77, 0x00,
+    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+    0x06, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0x00,
+    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+    0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x60,
+    0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80,
+    0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0x60,
+    0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80,
+    0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x66, 0x66, 0x80,
+    0x08, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80,
+    0x86, 0xe6, 0xe6, 0xe6, 0x66, 0x66, 0x66, 0x80,
+    0x08, 0x78, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80,
+    0x86, 0x66, 0x66, 0x66, 0x66, 0x66, 0x77, 0x70,
+    0x00, 0x77, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+    0x87, 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x78,
+    0x00, 0x88, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+    0x87, 0x76, 0x66, 0x66, 0x77, 0x77, 0xff, 0xf7,
+    0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08,
+    0xff, 0x77, 0x77, 0x77, 0x77, 0xff, 0xff, 0xff,
+    0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
+    0xff, 0x77, 0x77, 0x77, 0x7f, 0xff, 0xff, 0xff,
+    0x70, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x8f,
+    0xff, 0xf7, 0x77, 0x77, 0xff, 0xff, 0xff, 0xff,
+    0xf0, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x7f,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xf8, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xf7, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x87, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x87, 0x77,
+    0xff, 0xf7, 0x77, 0xff, 0xff, 0xff, 0x77, 0x77,
+    0x77, 0x78, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x77, 0x7f,
+    0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x77,
+    0x77, 0x78, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x7f, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xf7, 0x77, 0x00, 0x08, 0x80, 0x00, 0x00, 0x80,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x80, 0x80, 0x08, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0x77, 0x80, 0x00, 0x08, 0x00, 0x00, 0x08,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x08, 0x00, 0x80, 0x07, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0x78, 0x00, 0x08, 0x80, 0x00, 0x08,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x08, 0x08, 0x00, 0x8f, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xf7, 0x08, 0x80, 0x80, 0x00, 0x08,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x08, 0x08, 0x08, 0x7f, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xf7, 0x08, 0x80, 0x80, 0x00, 0x00,
+    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x80, 0x08, 0x07, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0x80, 0x00, 0x08, 0x00, 0x00,
+    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x80, 0x80, 0x0f, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0x70, 0x00, 0x08, 0x00, 0x00,
+    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x08, 0x00, 0x80, 0x8f, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0x70, 0x00, 0x08, 0x00, 0x00,
+    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x08, 0x08, 0x00, 0x7f, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0x70, 0x00, 0x08, 0x00, 0x00,
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x80, 0x08, 0x00, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xf0, 0x00, 0x08, 0x00, 0x00,
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x08, 0x00, 0x08, 0x00, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xf0, 0x00, 0x08, 0x00, 0x00,
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x08, 0x00, 0x08, 0x08, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xf0, 0x00, 0x08, 0x00, 0x00,
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x08, 0x00, 0x08, 0x08, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xf0, 0x00, 0x08, 0x00, 0x00,
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x08, 0x00, 0x00, 0x88, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xf0, 0x00, 0x08, 0x00, 0x00,
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x08, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xf0, 0x88, 0x88, 0x80, 0x00,
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x08, 0x06, 0xe6, 0x00, 0x8f, 0xff, 0xff, 0xff,
+    0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x08, 0x80,
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x6e, 0x6e, 0x60, 0x08, 0xff, 0xff, 0xff,
+    0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xe6, 0xe0, 0x00, 0x00, 0x00, 0x88,
+    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x06, 0xe6, 0xe6, 0xe6, 0x00, 0x8f, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xfe, 0x6e, 0x60, 0x00, 0x00, 0x00, 0x00,
+    0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x6e, 0x6e, 0x6e, 0x6e, 0x60, 0x08, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xf6, 0xe6, 0xe0, 0x00, 0x00, 0x00, 0x06,
+    0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xe6, 0xe6,
+    0xe6, 0xe6, 0xe6, 0xe6, 0xe0, 0x00, 0x8f, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xfe, 0x6e, 0x60, 0x00, 0x00, 0x00, 0x0e,
+    0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x6e, 0x6e,
+    0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x00, 0x08, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0x76, 0xe6, 0xe6, 0x00, 0x00, 0x00, 0xe6,
+    0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xe6, 0xe6,
+    0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe0, 0x00, 0x8f,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xf7, 0x7e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e,
+    0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x6e, 0x6e,
+    0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x60, 0x00, 0x08,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xf7, 0x76, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
+    0xe6, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xe6, 0xe6,
+    0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0x00, 0x00,
+    0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xf7, 0x7e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e,
+    0x6e, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x6e, 0x6e,
+    0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x60, 0x00,
+    0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xf7, 0x76, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
+    0xe6, 0xe6, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xe6, 0xe6,
+    0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe0, 0x00,
+    0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xf7, 0x8e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e,
+    0x6e, 0x6e, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x6e, 0x6e,
+    0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x88,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0x78, 0x86, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
+    0xe6, 0xe6, 0xe6, 0xe6, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xe6, 0xe6,
+    0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xef,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7,
+    0x80, 0x06, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e,
+    0x6e, 0x6e, 0x6e, 0x6e, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x6e, 0x6e,
+    0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78,
+    0x00, 0x06, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
+    0xe6, 0xe6, 0xe6, 0xe0, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xe6, 0xe6,
+    0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
+    0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x80,
+    0x00, 0x06, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e,
+    0x6e, 0x6e, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x0e, 0x6e, 0x6e, 0x6e,
+    0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x66,
+    0x67, 0xff, 0xff, 0xff, 0xff, 0x78, 0x80, 0x00,
+    0x00, 0x86, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
+    0xe6, 0xe6, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x06, 0xe6, 0xe6, 0xe6,
+    0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
+    0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x86, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e,
+    0x66, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x0e, 0x6e, 0x6e, 0x6e,
+    0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x66,
+    0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x86, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
+    0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xe6, 0xe6,
+    0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
+    0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x86, 0x6e, 0x6e, 0x6e, 0x6e, 0x66, 0x66,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,
+    0x66, 0x66, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x66,
+    0x60, 0x00, 0x88, 0x88, 0x88, 0x88, 0x88, 0x80,
+    0x00, 0x06, 0x66, 0xe6, 0xe6, 0xe6, 0x66, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x66, 0x66, 0x66, 0x66, 0xe6, 0xe6, 0x66,
+    0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+    0x88, 0x86, 0x66, 0x6e, 0x6e, 0x66, 0x60, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x06, 0x66, 0x66, 0x66, 0x66,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x06, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x06, 0x66, 0x66, 0x60,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x66, 0x66, 0x66, 0x60, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-unsigned char linux_logo16_green[] __initdata = {
-    0x00, 0x90, 0xb0, 0x9c, 0xf7, 0x2e, 0x83, 0xa5,
-    0x65, 0x6e, 0x98, 0x89, 0xbf, 0xac, 0xda, 0xf8
-};
+#endif /* !__HAVE_ARCH_LINUX_LOGO16 */
 
-unsigned char linux_logo16_blue[] __initdata = {
-    0x00, 0x90, 0xaf, 0x9c, 0xf7, 0x2b, 0x82, 0xa5,
-    0x65, 0x41, 0x97, 0x1e, 0x60, 0x29, 0xa5, 0xf8
-};
+#else /* !INCLUDE_LINUX_LOGO_DATA */
 
-unsigned char linux_logo16[] __initdata = {
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa1, 0x11, 0x11,
-    0x61, 0x16, 0x66, 0x66, 0x11, 0x11, 0x11, 0x11,
-    0x11, 0x11, 0x1a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0xa8, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x87, 0x77, 0x77, 0x77, 0x77,
-    0x77, 0x77, 0x73, 0x33, 0x33, 0x3a, 0xaa, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-    0xaa, 0xaa, 0xa3, 0x33, 0x33, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x77,
-    0x77, 0x27, 0x77, 0x77, 0x77, 0x33, 0x3a, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-    0xaa, 0xa3, 0x33, 0x33, 0x30, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x55, 0x50, 0x08, 0x33, 0x77, 0x77,
-    0x77, 0x72, 0x72, 0x27, 0x77, 0x77, 0x33, 0x33,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-    0xa3, 0x33, 0x33, 0x77, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x58, 0x85, 0x00, 0x11, 0x11, 0xaa,
-    0xa3, 0x37, 0x77, 0x72, 0x22, 0x22, 0x77, 0x73,
-    0x33, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa3,
-    0x33, 0x37, 0x77, 0x33, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x56, 0x85, 0x00, 0x06, 0x66, 0x11,
-    0x11, 0x1a, 0xa3, 0x37, 0x77, 0x72, 0x22, 0x77,
-    0x73, 0x33, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x33,
-    0x33, 0x33, 0x33, 0x30, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x55, 0x00, 0x00, 0x06, 0x66, 0x66,
-    0x66, 0x66, 0x11, 0x1a, 0xa3, 0x77, 0x72, 0x22,
-    0x77, 0x73, 0x3a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0x33,
-    0x33, 0x33, 0x33, 0xa0, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11,
-    0x66, 0x66, 0x66, 0x66, 0x11, 0xa3, 0x77, 0x22,
-    0x22, 0x77, 0x33, 0x33, 0xaa, 0xaa, 0xaa, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0x33, 0x33,
-    0x33, 0x3a, 0xa1, 0x10, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x33,
-    0xaa, 0x11, 0x16, 0x66, 0x66, 0x61, 0x1a, 0x37,
-    0x22, 0x22, 0x77, 0x33, 0x3a, 0xaa, 0xaa, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xa3, 0x33, 0x33, 0x33,
-    0x3a, 0xa1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x22,
-    0x22, 0x77, 0x3a, 0x11, 0x66, 0x66, 0x66, 0x1a,
-    0x37, 0x22, 0x22, 0x77, 0x33, 0x3a, 0xaa, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0x33, 0x33, 0x3a,
-    0xa1, 0x11, 0x11, 0x10, 0x00, 0x00, 0x50, 0x00,
-    0x00, 0x05, 0x80, 0x50, 0x00, 0x00, 0x07, 0x72,
-    0x22, 0x22, 0x22, 0x73, 0xa1, 0x66, 0x66, 0x61,
-    0x1a, 0x77, 0x22, 0x27, 0x73, 0x33, 0xaa, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0x33, 0x3a, 0xaa,
-    0x11, 0x11, 0x1a, 0xa0, 0x08, 0x71, 0x05, 0x00,
-    0x00, 0x12, 0x22, 0x50, 0x00, 0x00, 0x07, 0x77,
-    0x77, 0x72, 0x22, 0x22, 0x27, 0x31, 0x16, 0x66,
-    0x61, 0x13, 0x77, 0x22, 0x77, 0x33, 0x3a, 0xaa,
-    0xaa, 0xaa, 0xaa, 0xa3, 0x33, 0x33, 0xaa, 0xa1,
-    0x11, 0x1a, 0x33, 0x70, 0x07, 0x2e, 0x70, 0x00,
-    0x01, 0x44, 0x42, 0x60, 0x00, 0x00, 0x02, 0x22,
-    0x22, 0x22, 0x22, 0x22, 0x22, 0x27, 0x31, 0x66,
-    0x66, 0x61, 0xa3, 0x72, 0x22, 0x77, 0x33, 0xaa,
-    0xaa, 0xaa, 0xa3, 0x33, 0x33, 0xaa, 0xaa, 0x11,
-    0x1a, 0x33, 0x77, 0x30, 0x04, 0x82, 0x40, 0x00,
-    0x54, 0x48, 0x54, 0x40, 0x00, 0x00, 0x01, 0xaa,
-    0x32, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x31,
-    0x66, 0x66, 0x11, 0x37, 0x22, 0x27, 0x73, 0x3a,
-    0xaa, 0xaa, 0xa3, 0x33, 0x3a, 0xaa, 0xaa, 0xaa,
-    0xa3, 0x77, 0xaa, 0x10, 0x50, 0x08, 0x46, 0x05,
-    0x54, 0x80, 0x50, 0x42, 0x00, 0x00, 0x08, 0x66,
-    0x66, 0x1a, 0x32, 0x22, 0x22, 0x22, 0x22, 0x27,
-    0x31, 0x66, 0x66, 0x13, 0x72, 0x22, 0x77, 0x33,
-    0xaa, 0xaa, 0xaa, 0x33, 0xaa, 0xa1, 0xaa, 0xa3,
-    0x37, 0xa1, 0x1a, 0x30, 0x50, 0x06, 0x26, 0x00,
-    0x54, 0x00, 0x00, 0x44, 0x00, 0x00, 0x08, 0xe2,
-    0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x22, 0x22,
-    0x27, 0xa6, 0x66, 0x61, 0xa7, 0x72, 0x27, 0x73,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x33,
-    0x31, 0x11, 0x37, 0x70, 0x02, 0x00, 0xab, 0xbb,
-    0xb6, 0x00, 0x00, 0xf4, 0x00, 0x00, 0xee, 0xee,
-    0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x22,
-    0x22, 0x23, 0x16, 0x66, 0x1a, 0x37, 0x22, 0x77,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa3, 0x3a,
-    0x11, 0xa7, 0x33, 0x10, 0x04, 0x09, 0xbd, 0xdd,
-    0xbd, 0xd0, 0x04, 0x45, 0x00, 0x0e, 0xee, 0xee,
-    0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x22,
-    0x22, 0x22, 0x71, 0x66, 0x66, 0x13, 0x72, 0x27,
-    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0x11,
-    0xa3, 0x73, 0xa1, 0x60, 0x08, 0xbd, 0xdd, 0xdd,
-    0xdd, 0xdd, 0xdb, 0x90, 0x00, 0x02, 0xec, 0xee,
-    0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xce, 0x22,
-    0x22, 0x22, 0x27, 0xa6, 0x66, 0x61, 0x37, 0x27,
-    0x1a, 0xaa, 0xaa, 0xaa, 0xaa, 0xa3, 0xa1, 0x1a,
-    0x33, 0xa1, 0x16, 0x60, 0x0b, 0xbd, 0xdd, 0xdd,
-    0xcd, 0xdd, 0xdd, 0xd9, 0x00, 0x00, 0xec, 0xcc,
-    0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0xa2,
-    0x22, 0x22, 0x22, 0x7a, 0x66, 0x66, 0x13, 0x77,
-    0x1a, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x11, 0x33,
-    0xaa, 0x11, 0x66, 0x60, 0x9b, 0xdd, 0xdd, 0xdd,
-    0xcd, 0xdd, 0xdb, 0xb9, 0x00, 0x00, 0xec, 0xcc,
-    0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xee, 0x61,
-    0x72, 0x22, 0x22, 0x22, 0xa1, 0x66, 0x61, 0x37,
-    0x1a, 0xaa, 0xaa, 0xaa, 0xa3, 0xa1, 0x13, 0x3a,
-    0x11, 0x11, 0x11, 0x10, 0x5b, 0xdd, 0xdd, 0xdc,
-    0xdd, 0xdd, 0xbd, 0xd9, 0x00, 0x00, 0xec, 0xcc,
-    0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xee, 0x86,
-    0x17, 0x22, 0x22, 0x22, 0x23, 0x16, 0x66, 0xaa,
-    0xaa, 0xa3, 0x3a, 0xaa, 0xaa, 0x1a, 0x3a, 0xa1,
-    0x11, 0x11, 0x1a, 0x70, 0x05, 0xbd, 0xdd, 0xdd,
-    0xdb, 0x5b, 0xdd, 0xb0, 0x00, 0x60, 0x2e, 0xcc,
-    0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xe6, 0x88,
-    0x66, 0x32, 0x22, 0x22, 0x22, 0x36, 0x66, 0x11,
-    0x33, 0x33, 0x3a, 0xaa, 0x11, 0xaa, 0xaa, 0xa1,
-    0x11, 0x1a, 0x3a, 0x60, 0x02, 0x99, 0xbb, 0xb9,
-    0x9b, 0xbb, 0xbc, 0x22, 0x00, 0x86, 0x5e, 0xcc,
-    0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xe1, 0x68,
-    0x86, 0x63, 0x22, 0x22, 0x22, 0x2a, 0x66, 0x66,
-    0x33, 0x33, 0xaa, 0xaa, 0x1a, 0xaa, 0xaa, 0x11,
-    0x1a, 0xa7, 0x68, 0x80, 0x02, 0x2b, 0xbd, 0xbb,
-    0xbb, 0xb9, 0x22, 0x22, 0x00, 0x06, 0x6e, 0xcc,
-    0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xc7, 0xa6,
-    0x88, 0x86, 0x32, 0x22, 0x22, 0x27, 0xa6, 0x66,
-    0x33, 0x3a, 0xaa, 0xa1, 0xaa, 0xaa, 0xa1, 0x11,
-    0xa3, 0xa6, 0x88, 0x80, 0x02, 0x22, 0x9b, 0xbb,
-    0xbb, 0x22, 0x24, 0xf4, 0x60, 0x00, 0x0c, 0xcc,
-    0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xc2, 0x21,
-    0x68, 0x88, 0x63, 0x22, 0x22, 0x22, 0x71, 0x66,
-    0x33, 0x3a, 0x11, 0x11, 0xaa, 0xaa, 0x11, 0xaa,
-    0x71, 0x88, 0x88, 0x00, 0x02, 0xe2, 0x26, 0x99,
-    0x22, 0x22, 0x4f, 0xf4, 0x40, 0x00, 0x0c, 0xcc,
-    0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x22, 0x22,
-    0x16, 0x88, 0x86, 0xa2, 0x22, 0x22, 0x27, 0x11,
-    0x33, 0xa1, 0x11, 0x11, 0xaa, 0x31, 0x1a, 0xa3,
-    0x68, 0x88, 0x81, 0x00, 0x54, 0x42, 0x22, 0x22,
-    0x22, 0x44, 0xff, 0xff, 0x48, 0x00, 0x00, 0x99,
-    0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x22, 0x22,
-    0x21, 0x88, 0x88, 0x6a, 0x22, 0x22, 0x22, 0x31,
-    0x3a, 0xa1, 0x11, 0x1a, 0xa3, 0x11, 0x33, 0x36,
-    0x88, 0x86, 0x30, 0x00, 0x4f, 0x44, 0x22, 0x22,
-    0x24, 0xff, 0xff, 0xff, 0x44, 0x00, 0x00, 0x99,
-    0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x95, 0x22, 0x72,
-    0x22, 0x18, 0x88, 0x86, 0x32, 0x22, 0x22, 0x27,
-    0xaa, 0x11, 0x11, 0x1a, 0x31, 0x13, 0x33, 0x68,
-    0x88, 0x6a, 0x00, 0x02, 0x4f, 0x4f, 0x42, 0x24,
-    0x4f, 0xff, 0xff, 0xff, 0xf4, 0x50, 0x00, 0x99,
-    0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x22, 0x73,
-    0x72, 0x26, 0x88, 0x88, 0x63, 0x22, 0x22, 0x22,
-    0x11, 0x11, 0x11, 0xa3, 0xa1, 0x73, 0xa6, 0x88,
-    0x81, 0xa5, 0x00, 0x04, 0x4f, 0x4f, 0x44, 0x4f,
-    0xff, 0xff, 0xff, 0xff, 0xf4, 0x40, 0x00, 0x99,
-    0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x12, 0x27,
-    0xaa, 0x22, 0x68, 0x55, 0x86, 0x72, 0x22, 0x22,
-    0x11, 0x11, 0x1a, 0x33, 0x13, 0x3a, 0x18, 0x88,
-    0x1a, 0x10, 0x00, 0x44, 0x4f, 0x4f, 0xff, 0x4f,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x99,
-    0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x61, 0x22,
-    0x3a, 0xa2, 0x26, 0x85, 0x58, 0x67, 0x22, 0x22,
-    0x61, 0x61, 0x1a, 0x7a, 0x37, 0x31, 0x88, 0x81,
-    0x11, 0x00, 0x05, 0xe4, 0x44, 0xff, 0xff, 0xff,
-    0x4f, 0xf4, 0x44, 0xff, 0xff, 0xf5, 0x00, 0x99,
-    0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x88, 0x12,
-    0x2a, 0xaa, 0x72, 0x68, 0x55, 0x81, 0x22, 0x22,
-    0x66, 0x61, 0xa3, 0x33, 0x73, 0x16, 0x88, 0x11,
-    0x10, 0x00, 0x08, 0x74, 0x44, 0x4f, 0x44, 0x44,
-    0xf4, 0xf4, 0x44, 0x44, 0xe2, 0x44, 0x00, 0x99,
-    0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x88, 0x81,
-    0x22, 0xaa, 0xa7, 0x26, 0x85, 0x88, 0x12, 0x22,
-    0x66, 0x61, 0x37, 0xa7, 0x3a, 0x66, 0x66, 0x11,
-    0x80, 0x00, 0x0a, 0x72, 0x44, 0x4f, 0x44, 0x4f,
-    0xff, 0x44, 0x44, 0x22, 0x22, 0x24, 0x00, 0x99,
-    0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x85, 0x88,
-    0x12, 0x2a, 0xaa, 0x22, 0x68, 0x58, 0x63, 0x22,
-    0x66, 0x1a, 0x73, 0x77, 0x31, 0x66, 0x61, 0x11,
-    0x00, 0x00, 0x07, 0x44, 0xff, 0x4f, 0xf4, 0x4f,
-    0xff, 0x4f, 0x44, 0xf4, 0x42, 0x22, 0x40, 0x9b,
-    0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xb9, 0x85, 0x55,
-    0x81, 0x27, 0xaa, 0xa2, 0x78, 0x88, 0x86, 0x72,
-    0x66, 0x13, 0x77, 0x73, 0x11, 0x66, 0x61, 0x76,
-    0x00, 0x50, 0x84, 0xf4, 0xff, 0x4f, 0xf4, 0xff,
-    0xff, 0x4f, 0x44, 0xff, 0x4f, 0x42, 0x40, 0x9b,
-    0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xb9, 0x68, 0x55,
-    0x58, 0x12, 0x3a, 0xaa, 0x23, 0x88, 0x88, 0xa7,
-    0x66, 0xa7, 0x77, 0x7a, 0x16, 0x66, 0x1a, 0x15,
-    0x05, 0x00, 0x4f, 0xf4, 0xff, 0x4f, 0xf4, 0xff,
-    0xff, 0x4f, 0x44, 0xff, 0x4f, 0x44, 0x24, 0x9b,
-    0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xb9, 0x26, 0x55,
-    0x55, 0x81, 0x23, 0xaa, 0x32, 0x18, 0x88, 0x6a,
-    0x61, 0x37, 0x77, 0x31, 0x66, 0x66, 0x17, 0x60,
-    0x05, 0x08, 0x4f, 0xf4, 0xff, 0x4f, 0xf4, 0xff,
-    0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x4e, 0x99,
-    0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0xa2, 0x65,
-    0x55, 0x58, 0xa2, 0x7a, 0xa2, 0x26, 0x88, 0x61,
-    0x61, 0x32, 0x27, 0xa1, 0x66, 0x61, 0x31, 0x60,
-    0x00, 0x04, 0x4f, 0xf4, 0xff, 0x44, 0x44, 0xff,
-    0xff, 0x4f, 0x44, 0xff, 0x4f, 0x44, 0xf4, 0x99,
-    0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x9b, 0xaa, 0x26,
-    0x55, 0x55, 0x87, 0x27, 0x33, 0x27, 0x68, 0x61,
-    0x1a, 0x72, 0x27, 0xa6, 0x66, 0x6a, 0x71, 0x00,
-    0x80, 0x84, 0xff, 0xf4, 0xff, 0x44, 0x44, 0xff,
-    0xff, 0x4f, 0x44, 0xff, 0x4f, 0x44, 0xf4, 0x99,
-    0x9b, 0x9b, 0x99, 0xb9, 0xb9, 0x99, 0xaa, 0xa2,
-    0x85, 0x55, 0x56, 0x22, 0x27, 0x22, 0x36, 0x66,
-    0x13, 0x22, 0x23, 0x16, 0x86, 0x63, 0x73, 0x00,
-    0x00, 0x44, 0xf4, 0xf4, 0xff, 0x44, 0x44, 0xff,
-    0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x4f, 0x99,
-    0x9b, 0x99, 0x99, 0x99, 0xb9, 0x99, 0xaa, 0xaa,
-    0x28, 0x55, 0x58, 0x12, 0x22, 0x22, 0x21, 0x11,
-    0xa3, 0x27, 0x7a, 0x66, 0x86, 0x17, 0x75, 0x05,
-    0x05, 0xff, 0xf4, 0xf4, 0xff, 0x44, 0x44, 0xff,
-    0xff, 0x4f, 0x44, 0x4f, 0x4f, 0x44, 0x4f, 0x99,
-    0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x3a, 0xaa,
-    0xa2, 0x85, 0x58, 0x67, 0x72, 0x22, 0x27, 0xa1,
-    0x37, 0x27, 0x7a, 0x68, 0x86, 0xa2, 0x70, 0x00,
-    0x02, 0xff, 0xf4, 0xf4, 0xff, 0x44, 0x44, 0x4f,
-    0xff, 0x4f, 0x44, 0xf4, 0xf4, 0xf4, 0xf4, 0x99,
-    0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x23, 0xaa,
-    0xa7, 0x78, 0x88, 0x81, 0x77, 0x22, 0x27, 0x3a,
-    0x72, 0x73, 0x71, 0x68, 0x66, 0x32, 0x50, 0x00,
-    0x04, 0x4f, 0xf4, 0xf4, 0xff, 0x44, 0x44, 0x4f,
-    0xff, 0x4f, 0x44, 0xf4, 0xf4, 0xf4, 0x44, 0x95,
-    0x99, 0x99, 0x99, 0x99, 0x99, 0x55, 0x12, 0x3a,
-    0xaa, 0x21, 0x88, 0x81, 0x77, 0x27, 0x73, 0x73,
-    0x72, 0x33, 0x36, 0x86, 0x61, 0x72, 0x00, 0x00,
-    0x04, 0x44, 0xf4, 0xf4, 0xf4, 0x44, 0x44, 0x4f,
-    0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x44, 0x55,
-    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x8a, 0x27,
-    0xaa, 0x77, 0x68, 0x61, 0x23, 0x71, 0x11, 0x3a,
-    0x27, 0xa3, 0x36, 0x86, 0x61, 0x20, 0x00, 0x00,
-    0x04, 0xf4, 0xf4, 0xf4, 0xf4, 0x44, 0x44, 0x4f,
-    0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x41, 0x59,
-    0x99, 0x99, 0x99, 0x99, 0x99, 0x95, 0x58, 0x77,
-    0x27, 0x32, 0x36, 0x63, 0x23, 0x71, 0x66, 0x11,
-    0x27, 0x13, 0xa6, 0x86, 0x6a, 0x20, 0x00, 0x50,
-    0x04, 0x4f, 0x4f, 0x4f, 0x4f, 0x44, 0x44, 0x4f,
-    0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x41, 0x99,
-    0x9b, 0xbb, 0xbb, 0xbb, 0xb9, 0x99, 0x68, 0x13,
-    0x32, 0x22, 0x73, 0xa7, 0x2a, 0x31, 0x88, 0x66,
-    0x7a, 0x13, 0x18, 0x66, 0x63, 0x20, 0x00, 0x06,
-    0x0f, 0x4f, 0x4f, 0x4f, 0x4f, 0x44, 0x44, 0x4f,
-    0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x49, 0x95,
-    0xa9, 0xa9, 0x99, 0x97, 0x92, 0x99, 0x65, 0x6a,
-    0x17, 0x22, 0x23, 0x72, 0x27, 0xaa, 0x88, 0x88,
-    0xa1, 0x17, 0x68, 0x66, 0x67, 0x70, 0x00, 0x05,
-    0x0f, 0x4f, 0x4f, 0x4f, 0x4f, 0x44, 0x44, 0x4f,
-    0xff, 0x4f, 0x44, 0xff, 0xf4, 0xf4, 0x49, 0x9c,
-    0x2e, 0xee, 0xee, 0xee, 0xee, 0xa9, 0x65, 0x8a,
-    0x1a, 0xaa, 0x37, 0x72, 0x27, 0x37, 0x88, 0x88,
-    0x11, 0x17, 0x68, 0x66, 0x67, 0x10, 0x9d, 0xd0,
-    0x84, 0x44, 0xff, 0x4f, 0x4f, 0x44, 0xf4, 0x4f,
-    0xff, 0x4f, 0x44, 0xff, 0xf4, 0xf4, 0x4f, 0x69,
-    0xcc, 0xee, 0xee, 0xee, 0xec, 0x99, 0x88, 0x63,
-    0x61, 0x68, 0x61, 0x72, 0x22, 0x7a, 0x68, 0x88,
-    0x11, 0x17, 0x88, 0x66, 0x12, 0x1b, 0xdd, 0xdd,
-    0x02, 0x44, 0x4f, 0x4f, 0x4f, 0x44, 0x44, 0x4f,
-    0xff, 0x4f, 0x44, 0xff, 0xff, 0x4f, 0x4c, 0xc5,
-    0x0c, 0xc1, 0x11, 0x1c, 0xc0, 0x26, 0x66, 0x17,
-    0x66, 0x88, 0x88, 0x12, 0x22, 0x23, 0xa8, 0x88,
-    0x11, 0x13, 0x88, 0x66, 0x17, 0xbb, 0xdd, 0xdd,
-    0xd0, 0x8f, 0xff, 0xf4, 0xf4, 0x44, 0xf4, 0x4f,
-    0xff, 0x4f, 0x44, 0xf4, 0x4f, 0x44, 0xdd, 0xdd,
-    0x00, 0x00, 0x00, 0x05, 0x9d, 0x21, 0x66, 0x27,
-    0xa6, 0x65, 0x58, 0x67, 0x22, 0x27, 0x28, 0x88,
-    0x11, 0xaa, 0x86, 0x68, 0x1a, 0xbb, 0xdd, 0xdd,
-    0xdb, 0x05, 0xf4, 0xf4, 0xf4, 0xf4, 0x44, 0x4f,
-    0xff, 0x4f, 0x44, 0xf4, 0xf4, 0xf4, 0xdd, 0xdb,
-    0x00, 0x00, 0x00, 0x00, 0xdd, 0xda, 0x66, 0x22,
-    0x71, 0x15, 0x55, 0x81, 0x22, 0x22, 0x76, 0x88,
-    0x11, 0x31, 0x88, 0x88, 0xab, 0xbd, 0xdd, 0xdd,
-    0xdd, 0x00, 0x04, 0x44, 0xff, 0xff, 0x4f, 0x4f,
-    0xff, 0x4f, 0x44, 0xf4, 0xf4, 0x44, 0xdd, 0xdb,
-    0x00, 0x00, 0x00, 0x0b, 0xdd, 0xda, 0x11, 0x22,
-    0x23, 0x68, 0x55, 0x86, 0x22, 0x22, 0x7a, 0x88,
-    0x1a, 0x71, 0x88, 0x89, 0xbb, 0xdd, 0xdd, 0xdd,
-    0xdd, 0xd0, 0x00, 0x4f, 0x44, 0xff, 0x4f, 0x4f,
-    0xff, 0x4f, 0x44, 0xf4, 0xff, 0xe2, 0xdd, 0xdb,
-    0x90, 0x00, 0x05, 0xbd, 0xdd, 0xb8, 0x63, 0x22,
-    0x27, 0xa6, 0x55, 0x88, 0x77, 0x22, 0x22, 0x88,
-    0x1a, 0x28, 0xbd, 0xdb, 0xdd, 0xdd, 0xdd, 0xdd,
-    0xdd, 0xdb, 0x00, 0x07, 0x44, 0x4f, 0x4f, 0x4f,
-    0xff, 0x4f, 0x44, 0x4f, 0x4f, 0x22, 0xdd, 0xdb,
-    0xbb, 0x9b, 0xbb, 0xbd, 0xdd, 0xd5, 0x86, 0x22,
-    0x22, 0x77, 0x85, 0x88, 0x17, 0x22, 0x22, 0x88,
-    0xaa, 0x2b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-    0xdd, 0xdd, 0x00, 0x00, 0x54, 0x4f, 0x4f, 0x4f,
-    0xff, 0x4f, 0x44, 0xf4, 0x44, 0x22, 0xbd, 0xdd,
-    0xbb, 0xbb, 0xbb, 0xdd, 0xdd, 0xdd, 0x88, 0x72,
-    0x27, 0x22, 0x88, 0x88, 0x67, 0x72, 0x22, 0x18,
-    0x33, 0x2d, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-    0xdd, 0xdd, 0xd0, 0x00, 0x05, 0x4f, 0x4f, 0x4f,
-    0xff, 0x4f, 0x44, 0x44, 0x4f, 0x22, 0xbd, 0xdd,
-    0xdb, 0xbb, 0xdd, 0xdd, 0xdd, 0xdd, 0x88, 0x17,
-    0x27, 0x72, 0x68, 0x88, 0x87, 0x32, 0x22, 0x36,
-    0x37, 0x2d, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-    0xdd, 0xdd, 0xd5, 0x00, 0x00, 0x4f, 0x4f, 0x4f,
-    0xff, 0xf4, 0xf4, 0xf4, 0xf4, 0x22, 0xbb, 0xdd,
-    0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xd8, 0x67,
-    0x72, 0x77, 0x38, 0x88, 0x83, 0x37, 0x22, 0x26,
-    0x72, 0x2b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-    0xdd, 0xdd, 0xdd, 0x00, 0x00, 0x4f, 0x4f, 0x4f,
-    0xff, 0xf4, 0xf4, 0xf4, 0x44, 0x25, 0xbb, 0xdd,
-    0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xd3,
-    0x32, 0x73, 0x76, 0x88, 0x81, 0x33, 0x22, 0x2a,
-    0x22, 0x2b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-    0xdd, 0xdd, 0xdd, 0xb0, 0x54, 0x4f, 0x4f, 0x4f,
-    0xff, 0xf4, 0xf4, 0xff, 0x44, 0x00, 0xbb, 0xdd,
-    0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-    0xa7, 0x73, 0x26, 0x88, 0x86, 0x7a, 0x72, 0x27,
-    0x22, 0x2b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-    0xdd, 0xdd, 0xdd, 0xdb, 0x44, 0xff, 0x4f, 0x4f,
-    0xff, 0xf4, 0xf4, 0x44, 0x40, 0x05, 0xbb, 0xdd,
-    0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-    0x13, 0x23, 0x21, 0x68, 0x86, 0x17, 0x72, 0x22,
-    0x22, 0x2b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-    0xdd, 0xdd, 0xdd, 0xdb, 0x44, 0x4f, 0x4f, 0x4f,
-    0xff, 0xff, 0x44, 0x42, 0x00, 0x05, 0xbd, 0xdd,
-    0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-    0x87, 0x27, 0x27, 0x16, 0x66, 0x67, 0x22, 0x22,
-    0x72, 0x7b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-    0xdd, 0xdd, 0xdd, 0xdd, 0x94, 0x44, 0x44, 0x44,
-    0x44, 0x44, 0x44, 0x00, 0x00, 0x05, 0xbb, 0xdd,
-    0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xb8,
-    0x86, 0x22, 0x22, 0x7a, 0x68, 0x81, 0x22, 0x22,
-    0x37, 0x7b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-    0xdd, 0xdd, 0xdd, 0xdb, 0xb5, 0x44, 0x44, 0x44,
-    0x44, 0x47, 0x00, 0x00, 0x00, 0x05, 0xbd, 0xdd,
-    0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xd8, 0x68,
-    0x58, 0x72, 0x22, 0x27, 0x18, 0x86, 0x72, 0x22,
-    0x1a, 0xbb, 0xbd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-    0xdd, 0xdd, 0xdd, 0xdb, 0xb5, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xbb, 0xdd,
-    0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xb9, 0x18, 0x85,
-    0x58, 0x12, 0x22, 0x36, 0x18, 0x88, 0x32, 0x22,
-    0x61, 0x3b, 0xbb, 0xbb, 0xbd, 0xdd, 0xdd, 0xdd,
-    0xdd, 0xdd, 0xdd, 0xdb, 0xb9, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xbb, 0xdd,
-    0xdd, 0xdd, 0xdd, 0xdd, 0xb9, 0x7a, 0x68, 0x85,
-    0x88, 0x62, 0x27, 0x16, 0x18, 0x88, 0x12, 0x27,
-    0x86, 0x18, 0x9b, 0xbb, 0xbb, 0xbb, 0xbb, 0xbd,
-    0xdd, 0xdd, 0xdd, 0xbb, 0xb5, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xbb, 0xbd,
-    0xdd, 0xdd, 0xdb, 0xbb, 0x87, 0x31, 0x68, 0x65,
-    0x88, 0x82, 0x23, 0x16, 0x18, 0x88, 0x12, 0x23,
-    0x88, 0x67, 0x27, 0xa8, 0x9b, 0xbb, 0xbb, 0xbb,
-    0xbd, 0xdd, 0xbb, 0xbb, 0x95, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x9b, 0xbb,
-    0xbb, 0xbb, 0xbb, 0x96, 0x87, 0x16, 0x68, 0x18,
-    0x88, 0x62, 0x31, 0x66, 0x18, 0x88, 0x62, 0x73,
-    0x88, 0x63, 0x27, 0x33, 0x65, 0x55, 0x99, 0x9b,
-    0xbb, 0xbb, 0xbb, 0x99, 0x55, 0x0a, 0xa1, 0x86,
-    0x81, 0x68, 0x88, 0x55, 0x58, 0x85, 0x9b, 0xbb,
-    0xbb, 0xbb, 0x95, 0x88, 0x83, 0x66, 0x66, 0x18,
-    0x66, 0x82, 0xa1, 0x66, 0x18, 0x88, 0x62, 0x33,
-    0x88, 0x81, 0x27, 0x7a, 0x18, 0x58, 0x86, 0x85,
-    0x99, 0x99, 0x99, 0x95, 0x53, 0x2a, 0xaa, 0x88,
-    0x67, 0x31, 0x68, 0x55, 0x58, 0x85, 0x59, 0xbb,
-    0xbb, 0xb9, 0x58, 0x68, 0x83, 0x66, 0x61, 0x16,
-    0x66, 0x62, 0x16, 0x66, 0x68, 0x88, 0x62, 0xaa,
-    0x88, 0x86, 0x27, 0x77, 0x78, 0x55, 0x88, 0x22,
-    0x25, 0x55, 0x95, 0x55, 0x6a, 0xa2, 0x2a, 0x88,
-    0x62, 0x27, 0x37, 0x38, 0x88, 0x87, 0x55, 0x59,
-    0x95, 0x58, 0x16, 0x88, 0x8a, 0x66, 0x63, 0x68,
-    0x86, 0x67, 0x66, 0x66, 0x68, 0x88, 0x12, 0x11,
-    0x88, 0x88, 0x72, 0x77, 0x78, 0x85, 0x58, 0x17,
-    0x23, 0x32, 0x55, 0x55, 0x81, 0x13, 0x73, 0x66,
-    0x62, 0x7a, 0xaa, 0x38, 0x88, 0x58, 0x27, 0x55,
-    0x58, 0x32, 0x38, 0x88, 0x81, 0x66, 0xa2, 0x88,
-    0x86, 0x61, 0x66, 0x61, 0x66, 0x68, 0x13, 0x11,
-    0x88, 0x88, 0x12, 0x22, 0x71, 0x85, 0x58, 0x62,
-    0x23, 0xa2, 0x68, 0x88, 0x81, 0x66, 0x88, 0x88,
-    0x63, 0x2a, 0xaa, 0x28, 0x88, 0x55, 0x86, 0x61,
-    0x66, 0x66, 0x68, 0x88, 0x66, 0x66, 0x77, 0x88,
-    0x68, 0x16, 0x66, 0x62, 0x66, 0x68, 0xa1, 0x61,
-    0x88, 0x88, 0x62, 0x22, 0x22, 0x85, 0x55, 0x83,
-    0x72, 0x37, 0xa8, 0x88, 0x61, 0x66, 0x85, 0x55,
-    0x86, 0x23, 0xaa, 0x71, 0x88, 0x85, 0x88, 0x66,
-    0x88, 0x86, 0x88, 0x88, 0x16, 0x61, 0x21, 0x88,
-    0x66, 0xa6, 0x86, 0x17, 0x66, 0x66, 0x31, 0x61,
-    0x88, 0x88, 0x87, 0x72, 0x22, 0x68, 0x55, 0x86,
-    0x77, 0x77, 0x36, 0x88, 0x13, 0x68, 0x85, 0x55,
-    0x58, 0x12, 0x73, 0x72, 0x76, 0x88, 0x88, 0x68,
-    0x88, 0x88, 0x88, 0x66, 0x36, 0x63, 0x26, 0x86,
-    0x86, 0x36, 0x86, 0x11, 0x66, 0x66, 0x76, 0x61,
-    0x88, 0x88, 0x81, 0x22, 0x22, 0x38, 0x85, 0x58,
-    0x37, 0x22, 0x21, 0x68, 0xa2, 0x31, 0x68, 0x55,
-    0x55, 0x81, 0x22, 0x22, 0xa8, 0x88, 0x88, 0x68,
-    0x86, 0x88, 0x68, 0x81, 0x36, 0x17, 0x21, 0x68,
-    0x86, 0x16, 0x66, 0x26, 0x66, 0x61, 0x36, 0x66,
-    0x68, 0x88, 0x86, 0x27, 0x22, 0x28, 0x88, 0x88,
-    0x17, 0x72, 0x2a, 0x66, 0xa2, 0x22, 0x36, 0x55,
-    0x55, 0x58, 0x37, 0x3a, 0x16, 0x66, 0x66, 0x66,
-    0x66, 0x18, 0x88, 0x67, 0x16, 0x12, 0x71, 0x68,
-    0x81, 0x68, 0x61, 0x76, 0x66, 0x6a, 0x16, 0x66,
-    0x88, 0x88, 0x86, 0x77, 0x22, 0x26, 0x88, 0x88,
-    0x13, 0x37, 0x71, 0x66, 0xa2, 0x33, 0x2a, 0x85,
-    0x55, 0x55, 0x17, 0x73, 0x16, 0x66, 0x66, 0x68,
-    0x63, 0x88, 0x88, 0xa2, 0x66, 0xa2, 0xa6, 0x88,
-    0x61, 0x68, 0x6a, 0x76, 0x66, 0x6a, 0x66, 0x6a
-};
+/* prototypes only */
+extern unsigned char linux_logo_red[];
+extern unsigned char linux_logo_green[];
+extern unsigned char linux_logo_blue[];
+extern unsigned char linux_logo[];
+extern unsigned char linux_logo_bw[];
+extern unsigned char linux_logo16[];
+
+#endif /* !INCLUDE_LINUX_LOGO_DATA */
 
-#endif
diff -u --recursive --new-file v2.4.5/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.4.5/linux/include/linux/mm.h	Fri May 25 18:01:28 2001
+++ linux/include/linux/mm.h	Wed Jun 20 12:16:56 2001
@@ -10,6 +10,7 @@
 #include <linux/string.h>
 #include <linux/list.h>
 #include <linux/mmzone.h>
+#include <linux/swap.h>
 
 extern unsigned long max_mapnr;
 extern unsigned long num_physpages;
@@ -39,32 +40,37 @@
  * library, the executable area etc).
  */
 struct vm_area_struct {
-	struct mm_struct * vm_mm;	/* VM area parameters */
-	unsigned long vm_start;
-	unsigned long vm_end;
+	struct mm_struct * vm_mm;	/* The address space we belong to. */
+	unsigned long vm_start;		/* Our start address within vm_mm. */
+	unsigned long vm_end;		/* Our end address within vm_mm. */
 
 	/* linked list of VM areas per task, sorted by address */
 	struct vm_area_struct *vm_next;
 
-	pgprot_t vm_page_prot;
-	unsigned long vm_flags;
+	pgprot_t vm_page_prot;		/* Access permissions of this VMA. */
+	unsigned long vm_flags;		/* Flags, listed below. */
 
 	/* AVL tree of VM areas per task, sorted by address */
 	short vm_avl_height;
 	struct vm_area_struct * vm_avl_left;
 	struct vm_area_struct * vm_avl_right;
 
-	/* For areas with an address space and backing store,
+	/*
+	 * For areas with an address space and backing store,
 	 * one of the address_space->i_mmap{,shared} lists,
 	 * for shm areas, the list of attaches, otherwise unused.
 	 */
 	struct vm_area_struct *vm_next_share;
 	struct vm_area_struct **vm_pprev_share;
 
+	/* Function pointers to deal with this struct. */
 	struct vm_operations_struct * vm_ops;
-	unsigned long vm_pgoff;		/* offset in PAGE_SIZE units, *not* PAGE_CACHE_SIZE */
-	struct file * vm_file;
-	unsigned long vm_raend;
+
+	/* Information about our backing store: */
+	unsigned long vm_pgoff;		/* Offset (within vm_file) in PAGE_SIZE
+					   units, *not* PAGE_CACHE_SIZE */
+	struct file * vm_file;		/* File we map to (can be NULL). */
+	unsigned long vm_raend;		/* XXX: put full readahead info here. */
 	void * vm_private_data;		/* was vm_pte (shared mem) */
 };
 
@@ -90,6 +96,7 @@
 #define VM_LOCKED	0x00002000
 #define VM_IO           0x00004000	/* Memory mapped I/O or similar */
 
+					/* Used by sys_madvise() */
 #define VM_SEQ_READ	0x00008000	/* App will access data sequentially */
 #define VM_RAND_READ	0x00010000	/* App will not benefit from clustered reads */
 
@@ -124,37 +131,144 @@
 };
 
 /*
+ * Each physical page in the system has a struct page associated with
+ * it to keep track of whatever it is we are using the page for at the
+ * moment. Note that we have no way to track which tasks are using
+ * a page.
+ *
  * Try to keep the most commonly accessed fields in single cache lines
  * here (16 bytes or greater).  This ordering should be particularly
  * beneficial on 32-bit processors.
  *
  * The first line is data used in page cache lookup, the second line
  * is used for linear searches (eg. clock algorithm scans). 
+ *
+ * TODO: make this structure smaller, it could be as small as 32 bytes.
  */
 typedef struct page {
-	struct list_head list;
-	struct address_space *mapping;
-	unsigned long index;
-	struct page *next_hash;
-	atomic_t count;
-	unsigned long flags;	/* atomic flags, some possibly updated asynchronously */
-	struct list_head lru;
-	unsigned long age;
-	wait_queue_head_t wait;
-	struct page **pprev_hash;
-	struct buffer_head * buffers;
-	void *virtual; /* non-NULL if kmapped */
-	struct zone_struct *zone;
+	struct list_head list;		/* ->mapping has some page lists. */
+	struct address_space *mapping;	/* The inode (or ...) we belong to. */
+	unsigned long index;		/* Our offset within mapping. */
+	struct page *next_hash;		/* Next page sharing our hash bucket in
+					   the pagecache hash table. */
+	atomic_t count;			/* Usage count, see below. */
+	unsigned long flags;		/* atomic flags, some possibly
+					   updated asynchronously */
+	struct list_head lru;		/* Pageout list, eg. active_list;
+					   protected by pagemap_lru_lock !! */
+	unsigned long age;		/* Page aging counter. */
+	wait_queue_head_t wait;		/* Page locked?  Stand in line... */
+	struct page **pprev_hash;	/* Complement to *next_hash. */
+	struct buffer_head * buffers;	/* Buffer maps us to a disk block. */
+	void *virtual;			/* Kernel virtual address (NULL if
+					   not kmapped, ie. highmem) */
+	struct zone_struct *zone;	/* Memory zone we are in. */
 } mem_map_t;
 
+/*
+ * Methods to modify the page usage count.
+ *
+ * What counts for a page usage:
+ * - cache mapping   (page->mapping)
+ * - disk mapping    (page->buffers)
+ * - page mapped in a task's page tables, each mapping
+ *   is counted separately
+ *
+ * Also, many kernel routines increase the page count before a critical
+ * routine so they can be sure the page doesn't go away from under them.
+ */
 #define get_page(p)		atomic_inc(&(p)->count)
 #define put_page(p)		__free_page(p)
 #define put_page_testzero(p) 	atomic_dec_and_test(&(p)->count)
 #define page_count(p)		atomic_read(&(p)->count)
 #define set_page_count(p,v) 	atomic_set(&(p)->count, v)
 
-/* Page flag bit values */
-#define PG_locked		 0
+/*
+ * Various page->flags bits:
+ *
+ * PG_reserved is set for special pages, which can never be swapped
+ * out. Some of them might not even exist (eg. empty_bad_page)...
+ *
+ * Multiple processes may "see" the same page. E.g. for untouched
+ * mappings of /dev/null, all processes see the same page full of
+ * zeroes, and text pages of executables and shared libraries have
+ * only one copy in memory, at most, normally.
+ *
+ * For the non-reserved pages, page->count denotes a reference count.
+ *   page->count == 0 means the page is free.
+ *   page->count == 1 means the page is used for exactly one purpose
+ *   (e.g. a private data page of one process).
+ *
+ * A page may be used for kmalloc() or anyone else who does a
+ * __get_free_page(). In this case the page->count is at least 1, and
+ * all other fields are unused but should be 0 or NULL. The
+ * management of this page is the responsibility of the one who uses
+ * it.
+ *
+ * The other pages (we may call them "process pages") are completely
+ * managed by the Linux memory manager: I/O, buffers, swapping etc.
+ * The following discussion applies only to them.
+ *
+ * A page may belong to an inode's memory mapping. In this case,
+ * page->mapping is the pointer to the inode, and page->offset is the
+ * file offset of the page (not necessarily a multiple of PAGE_SIZE).
+ *
+ * A page may have buffers allocated to it. In this case,
+ * page->buffers is a circular list of these buffer heads. Else,
+ * page->buffers == NULL.
+ *
+ * For pages belonging to inodes, the page->count is the number of
+ * attaches, plus 1 if buffers are allocated to the page, plus one
+ * for the page cache itself.
+ *
+ * All pages belonging to an inode are in these doubly linked lists:
+ * mapping->clean_pages, mapping->dirty_pages and mapping->locked_pages;
+ * using the page->list list_head. These fields are also used for
+ * freelist managemet (when page->count==0).
+ *
+ * There is also a hash table mapping (inode,offset) to the page
+ * in memory if present. The lists for this hash table use the fields
+ * page->next_hash and page->pprev_hash.
+ *
+ * All process pages can do I/O:
+ * - inode pages may need to be read from disk,
+ * - inode pages which have been modified and are MAP_SHARED may need
+ *   to be written to disk,
+ * - private pages which have been modified may need to be swapped out
+ *   to swap space and (later) to be read back into memory.
+ * During disk I/O, PG_locked is used. This bit is set before I/O
+ * and reset when I/O completes. page->wait is a wait queue of all
+ * tasks waiting for the I/O on this page to complete.
+ * PG_uptodate tells whether the page's contents is valid.
+ * When a read completes, the page becomes uptodate, unless a disk I/O
+ * error happened.
+ *
+ * For choosing which pages to swap out, inode pages carry a
+ * PG_referenced bit, which is set any time the system accesses
+ * that page through the (inode,offset) hash table. This referenced
+ * bit, together with the referenced bit in the page tables, is used
+ * to manipulate page->age and move the page across the active,
+ * inactive_dirty and inactive_clean lists.
+ *
+ * Note that the referenced bit, the page->lru list_head and the
+ * active, inactive_dirty and inactive_clean lists are protected by
+ * the pagemap_lru_lock, and *NOT* by the usual PG_locked bit!
+ *
+ * PG_skip is used on sparc/sparc64 architectures to "skip" certain
+ * parts of the address space.
+ *
+ * PG_error is set to indicate that an I/O error occurred on this page.
+ *
+ * PG_arch_1 is an architecture specific page state bit.  The generic
+ * code guarentees that this bit is cleared for a page when it first
+ * is entered into the page cache.
+ *
+ * PG_highmem pages are not permanently mapped into the kernel virtual
+ * address space, they need to be kmapped separately for doing IO on
+ * the pages. The struct page (these bits with information) are always
+ * mapped into kernel address space...
+ */
+#define PG_locked		 0	/* Page is locked. Don't touch. */
 #define PG_error		 1
 #define PG_referenced		 2
 #define PG_uptodate		 3
@@ -167,6 +281,7 @@
 #define PG_skip			10
 #define PG_inactive_clean	11
 #define PG_highmem		12
+#define PG_checked		13	/* kill me in 2.5.<early>. */
 				/* bits 21-29 unused */
 #define PG_arch_1		30
 #define PG_reserved		31
@@ -181,6 +296,8 @@
 #define PageLocked(page)	test_bit(PG_locked, &(page)->flags)
 #define LockPage(page)		set_bit(PG_locked, &(page)->flags)
 #define TryLockPage(page)	test_and_set_bit(PG_locked, &(page)->flags)
+#define PageChecked(page)	test_bit(PG_checked, &(page)->flags)
+#define SetPageChecked(page)	set_bit(PG_checked, &(page)->flags)
 
 extern void __set_page_dirty(struct page *);
 
@@ -254,81 +371,7 @@
 #define NOPAGE_SIGBUS	(NULL)
 #define NOPAGE_OOM	((struct page *) (-1))
 
-
-/*
- * Various page->flags bits:
- *
- * PG_reserved is set for a page which must never be accessed (which
- * may not even be present).
- *
- * PG_DMA has been removed, page->zone now tells exactly wether the
- * page is suited to do DMAing into.
- *
- * Multiple processes may "see" the same page. E.g. for untouched
- * mappings of /dev/null, all processes see the same page full of
- * zeroes, and text pages of executables and shared libraries have
- * only one copy in memory, at most, normally.
- *
- * For the non-reserved pages, page->count denotes a reference count.
- *   page->count == 0 means the page is free.
- *   page->count == 1 means the page is used for exactly one purpose
- *   (e.g. a private data page of one process).
- *
- * A page may be used for kmalloc() or anyone else who does a
- * __get_free_page(). In this case the page->count is at least 1, and
- * all other fields are unused but should be 0 or NULL. The
- * management of this page is the responsibility of the one who uses
- * it.
- *
- * The other pages (we may call them "process pages") are completely
- * managed by the Linux memory manager: I/O, buffers, swapping etc.
- * The following discussion applies only to them.
- *
- * A page may belong to an inode's memory mapping. In this case,
- * page->inode is the pointer to the inode, and page->offset is the
- * file offset of the page (not necessarily a multiple of PAGE_SIZE).
- *
- * A page may have buffers allocated to it. In this case,
- * page->buffers is a circular list of these buffer heads. Else,
- * page->buffers == NULL.
- *
- * For pages belonging to inodes, the page->count is the number of
- * attaches, plus 1 if buffers are allocated to the page.
- *
- * All pages belonging to an inode make up a doubly linked list
- * inode->i_pages, using the fields page->next and page->prev. (These
- * fields are also used for freelist management when page->count==0.)
- * There is also a hash table mapping (inode,offset) to the page
- * in memory if present. The lists for this hash table use the fields
- * page->next_hash and page->pprev_hash.
- *
- * All process pages can do I/O:
- * - inode pages may need to be read from disk,
- * - inode pages which have been modified and are MAP_SHARED may need
- *   to be written to disk,
- * - private pages which have been modified may need to be swapped out
- *   to swap space and (later) to be read back into memory.
- * During disk I/O, PG_locked is used. This bit is set before I/O
- * and reset when I/O completes. page->wait is a wait queue of all
- * tasks waiting for the I/O on this page to complete.
- * PG_uptodate tells whether the page's contents is valid.
- * When a read completes, the page becomes uptodate, unless a disk I/O
- * error happened.
- *
- * For choosing which pages to swap out, inode pages carry a
- * PG_referenced bit, which is set any time the system accesses
- * that page through the (inode,offset) hash table.
- *
- * PG_skip is used on sparc/sparc64 architectures to "skip" certain
- * parts of the address space.
- *
- * PG_error is set to indicate that an I/O error occurred on this page.
- *
- * PG_arch_1 is an architecture specific page state bit.  The generic
- * code guarentees that this bit is cleared for a page when it first
- * is entered into the page cache.
- */
-
+/* The array of struct pages */
 extern mem_map_t * mem_map;
 
 /*
@@ -337,10 +380,10 @@
  * can allocate highmem pages, the *get*page*() variants return
  * virtual kernel addresses to the allocated page(s).
  */
-extern struct page * FASTCALL(__alloc_pages(zonelist_t *zonelist, unsigned long order));
+extern struct page * FASTCALL(_alloc_pages(unsigned int gfp_mask, unsigned long order));
+extern struct page * FASTCALL(__alloc_pages(unsigned int gfp_mask, unsigned long order, zonelist_t *zonelist));
 extern struct page * alloc_pages_node(int nid, int gfp_mask, unsigned long order);
 
-#ifndef CONFIG_DISCONTIGMEM
 static inline struct page * alloc_pages(int gfp_mask, unsigned long order)
 {
 	/*
@@ -348,11 +391,8 @@
 	 */
 	if (order >= MAX_ORDER)
 		return NULL;
-	return __alloc_pages(contig_page_data.node_zonelists+(gfp_mask), order);
+	return _alloc_pages(gfp_mask, order);
 }
-#else /* !CONFIG_DISCONTIGMEM */
-extern struct page * alloc_pages(int gfp_mask, unsigned long order);
-#endif /* !CONFIG_DISCONTIGMEM */
 
 #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)
 
@@ -427,6 +467,23 @@
 extern void si_meminfo(struct sysinfo * val);
 extern void swapin_readahead(swp_entry_t);
 
+/*
+ * Work out if there are any other processes sharing this
+ * swap cache page. Never mind the buffers.
+ */
+static inline int exclusive_swap_page(struct page *page)
+{
+	unsigned int count;
+
+	if (!PageLocked(page))
+		BUG();
+	if (!PageSwapCache(page))
+		return 0;
+	count = page_count(page) - !!page->buffers;	/*  2: us + swap cache */
+	count += swap_count(page);			/* +1: just swap cache */
+	return count == 3;				/* =3: total */
+}
+
 /* mmap.c */
 extern void lock_vma_mappings(struct vm_area_struct *);
 extern void unlock_vma_mappings(struct vm_area_struct *);
@@ -471,18 +528,17 @@
 /*
  * GFP bitmasks..
  */
-#define __GFP_WAIT	0x01
-#define __GFP_HIGH	0x02
-#define __GFP_IO	0x04
-#define __GFP_DMA	0x08
-#ifdef CONFIG_HIGHMEM
-#define __GFP_HIGHMEM	0x10
-#else
-#define __GFP_HIGHMEM	0x0 /* noop */
-#endif
+/* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low four bits) */
+#define __GFP_DMA	0x01
+#define __GFP_HIGHMEM	0x02
+
+/* Action modifiers - doesn't change the zoning */
+#define __GFP_WAIT	0x10
+#define __GFP_HIGH	0x20
+#define __GFP_IO	0x40
+#define __GFP_BUFFER	0x80
 
-
-#define GFP_BUFFER	(__GFP_HIGH | __GFP_WAIT)
+#define GFP_BUFFER	(__GFP_HIGH | __GFP_WAIT | __GFP_BUFFER)
 #define GFP_ATOMIC	(__GFP_HIGH)
 #define GFP_USER	(             __GFP_WAIT | __GFP_IO)
 #define GFP_HIGHUSER	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHMEM)
@@ -533,11 +589,6 @@
 }
 
 extern struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr);
-
-#define buffer_under_min()	(atomic_read(&buffermem_pages) * 100 < \
-				buffer_mem.min_percent * num_physpages)
-#define pgcache_under_min()	(atomic_read(&page_cache_size) * 100 < \
-				page_cache.min_percent * num_physpages)
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.4.5/linux/include/linux/mmzone.h linux/include/linux/mmzone.h
--- v2.4.5/linux/include/linux/mmzone.h	Fri May 25 18:01:27 2001
+++ linux/include/linux/mmzone.h	Wed Jun 20 12:16:56 2001
@@ -78,10 +78,9 @@
  */
 typedef struct zonelist_struct {
 	zone_t * zones [MAX_NR_ZONES+1]; // NULL delimited
-	int gfp_mask;
 } zonelist_t;
 
-#define NR_GFPINDEX		0x20
+#define GFP_ZONEMASK	0x0f
 
 /*
  * The pg_data_t structure is used in machines with CONFIG_DISCONTIGMEM
@@ -97,7 +96,7 @@
 struct bootmem_data;
 typedef struct pglist_data {
 	zone_t node_zones[MAX_NR_ZONES];
-	zonelist_t node_zonelists[NR_GFPINDEX];
+	zonelist_t node_zonelists[GFP_ZONEMASK+1];
 	struct page *node_mem_map;
 	unsigned long *valid_addr_bitmap;
 	struct bootmem_data *bdata;
diff -u --recursive --new-file v2.4.5/linux/include/linux/mount.h linux/include/linux/mount.h
--- v2.4.5/linux/include/linux/mount.h	Fri May 25 12:36:42 2001
+++ linux/include/linux/mount.h	Mon Jun 11 19:15:27 2001
@@ -14,12 +14,11 @@
 
 struct vfsmount
 {
+	struct list_head mnt_hash;
+	struct vfsmount *mnt_parent;	/* fs we are mounted on */
 	struct dentry *mnt_mountpoint;	/* dentry of mountpoint */
 	struct dentry *mnt_root;	/* root of the mounted tree */
-	struct vfsmount *mnt_parent;	/* fs we are mounted on */
 	struct list_head mnt_instances;	/* other vfsmounts of the same fs */
-	struct list_head mnt_clash;	/* those who are mounted on (other */
-					/* instances) of the same dentry */
 	struct super_block *mnt_sb;	/* pointer to superblock */
 	struct list_head mnt_mounts;	/* list of children, anchored here */
 	struct list_head mnt_child;	/* and going through their mnt_child */
diff -u --recursive --new-file v2.4.5/linux/include/linux/mtd/cfi.h linux/include/linux/mtd/cfi.h
--- v2.4.5/linux/include/linux/mtd/cfi.h	Mon Dec 11 13:16:46 2000
+++ linux/include/linux/mtd/cfi.h	Tue Jun 12 10:30:27 2001
@@ -1,14 +1,160 @@
 
 /* Common Flash Interface structures 
  * See http://support.intel.com/design/flash/technote/index.htm
- * $Id: cfi.h,v 1.6 2000/07/03 13:29:16 dwmw2 Exp $
+ * $Id: cfi.h,v 1.21 2001/06/03 01:32:57 nico Exp $
  */
 
 #ifndef __MTD_CFI_H__
 #define __MTD_CFI_H__
 
+#include <linux/config.h>
+#include <linux/delay.h>
 #include <linux/types.h>
 #include <linux/mtd/flashchip.h>
+#include <linux/mtd/cfi_endian.h>
+
+/*
+ * You can optimize the code size and performance by defining only 
+ * the geometry(ies) available on your hardware.
+ * CFIDEV_INTERLEAVE_n, where  represents the interleave (number of chips to fill the bus width)
+ * CFIDEV_BUSWIDTH_n, where n is the bus width in bytes (1, 2 or 4 bytes)
+ *
+ * By default, all (known) geometries are supported.
+ */
+
+#ifndef CONFIG_MTD_CFI_GEOMETRY
+
+#define CFIDEV_INTERLEAVE_1 (1)
+#define CFIDEV_INTERLEAVE_2 (2)
+#define CFIDEV_INTERLEAVE_4 (4)
+
+#define CFIDEV_BUSWIDTH_1 (1)
+#define CFIDEV_BUSWIDTH_2 (2)
+#define CFIDEV_BUSWIDTH_4 (4)
+
+#else
+
+#ifdef CONFIG_MTD_CFI_I1
+#define CFIDEV_INTERLEAVE_1 (1)
+#endif
+#ifdef CONFIG_MTD_CFI_I2
+#define CFIDEV_INTERLEAVE_2 (2)
+#endif
+#ifdef CONFIG_MTD_CFI_I4
+#define CFIDEV_INTERLEAVE_4 (4)
+#endif
+
+#ifdef CONFIG_MTD_CFI_B1
+#define CFIDEV_BUSWIDTH_1 (1)
+#endif
+#ifdef CONFIG_MTD_CFI_B2
+#define CFIDEV_BUSWIDTH_2 (2)
+#endif
+#ifdef CONFIG_MTD_CFI_B4
+#define CFIDEV_BUSWIDTH_4 (4)
+#endif
+
+#endif
+
+/*
+ * The following macros are used to select the code to execute:
+ *   cfi_buswidth_is_*()
+ *   cfi_interleave_is_*()
+ *   [where * is either 1, 2 or 4]
+ * Those macros should be used with 'if' statements.  If only one of few
+ * geometry arrangements are selected, they expand to constants thus allowing
+ * the compiler (most of them being 0) to optimize away all the unneeded code,
+ * while still validating the syntax (which is not possible with embedded 
+ * #if ... #endif constructs).
+ */
+
+#ifdef CFIDEV_INTERLEAVE_1
+# ifdef CFIDEV_INTERLEAVE
+#  undef CFIDEV_INTERLEAVE
+#  define CFIDEV_INTERLEAVE (cfi->interleave)
+# else
+#  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_1
+# endif
+# define cfi_interleave_is_1() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_1)
+#else
+# define cfi_interleave_is_1() (0)
+#endif
+
+#ifdef CFIDEV_INTERLEAVE_2
+# ifdef CFIDEV_INTERLEAVE
+#  undef CFIDEV_INTERLEAVE
+#  define CFIDEV_INTERLEAVE (cfi->interleave)
+# else
+#  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_2
+# endif
+# define cfi_interleave_is_2() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_2)
+#else
+# define cfi_interleave_is_2() (0)
+#endif
+
+#ifdef CFIDEV_INTERLEAVE_4
+# ifdef CFIDEV_INTERLEAVE
+#  undef CFIDEV_INTERLEAVE
+#  define CFIDEV_INTERLEAVE (cfi->interleave)
+# else
+#  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_4
+# endif
+# define cfi_interleave_is_4() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_4)
+#else
+# define cfi_interleave_is_4() (0)
+#endif
+
+#ifndef CFIDEV_INTERLEAVE
+#error You must define at least one interleave to support!
+#endif
+
+#ifdef CFIDEV_BUSWIDTH_1
+# ifdef CFIDEV_BUSWIDTH
+#  undef CFIDEV_BUSWIDTH
+#  define CFIDEV_BUSWIDTH (map->buswidth)
+# else
+#  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_1
+# endif
+# define cfi_buswidth_is_1() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_1)
+#else
+# define cfi_buswidth_is_1() (0)
+#endif
+
+#ifdef CFIDEV_BUSWIDTH_2
+# ifdef CFIDEV_BUSWIDTH
+#  undef CFIDEV_BUSWIDTH
+#  define CFIDEV_BUSWIDTH (map->buswidth)
+# else
+#  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_2
+# endif
+# define cfi_buswidth_is_2() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_2)
+#else
+# define cfi_buswidth_is_2() (0)
+#endif
+
+#ifdef CFIDEV_BUSWIDTH_4
+# ifdef CFIDEV_BUSWIDTH
+#  undef CFIDEV_BUSWIDTH
+#  define CFIDEV_BUSWIDTH (map->buswidth)
+# else
+#  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_4
+# endif
+# define cfi_buswidth_is_4() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_4)
+#else
+# define cfi_buswidth_is_4() (0)
+#endif
+
+#ifndef CFIDEV_BUSWIDTH
+#error You must define at least one bus width to support!
+#endif
+
+/* NB: these values must represents the number of bytes needed to meet the 
+ *     device type (x8, x16, x32).  Eg. a 32 bit device is 4 x 8 bytes. 
+ *     These numbers are used in calculations.
+ */
+#define CFI_DEVICETYPE_X8  (8 / 8)
+#define CFI_DEVICETYPE_X16 (16 / 8)
+#define CFI_DEVICETYPE_X32 (32 / 8)
 
 /* NB: We keep these structures in memory in HOST byteorder, except
  * where individually noted.
@@ -37,7 +183,7 @@
   __u16 InterfaceDesc;
   __u16 MaxBufWriteSize;
   __u8  NumEraseRegions;
-  __u32 EraseRegionInfo[1]; /* Not host ordered */
+  __u32 EraseRegionInfo[0]; /* Not host ordered */
 } __attribute__((packed));
 
 /* Extended Query Structure for both PRI and ALT */
@@ -82,20 +228,164 @@
 #define P_ID_RESERVED 65535
 
 
+#define CFI_MODE_CFI	0
+#define CFI_MODE_JEDEC	1
+
 struct cfi_private {
 	__u16 cmdset;
 	void *cmdset_priv;
 	int interleave;
+	int device_type;
+	int cfi_mode;		/* Are we a JEDEC device pretending to be CFI? */
+	int addr_unlock1;
+	int addr_unlock2;
+	int fast_prog;
 	struct mtd_info *(*cmdset_setup)(struct map_info *);
-	struct cfi_ident cfiq; /* For now only one. We insist that all devs
+	struct cfi_ident *cfiq; /* For now only one. We insist that all devs
 				  must be of the same type. */
+	__u8 mfr, id;
 	int numchips;
 	unsigned long chipshift; /* Because they're of the same type */
 	const char *im_name;	 /* inter_module name for cmdset_setup */
 	struct flchip chips[0];  /* per-chip data structure for each chip */
-	/* do not add extra fields after "chips" */
 };
 
 #define MAX_CFI_CHIPS 8 /* Entirely arbitrary to avoid realloc() */
+
+/*
+ * Returns the command address according to the given geometry.
+ */
+static inline __u32 cfi_build_cmd_addr(__u32 cmd_ofs, int interleave, int type)
+{
+	return (cmd_ofs * type) * interleave;
+}
+
+/*
+ * Transforms the CFI command for the given geometry (bus width & interleave.
+ */
+static inline __u32 cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
+{
+	__u32 val = 0;
+
+	if (cfi_buswidth_is_1()) {
+		/* 1 x8 device */
+		val = cmd;
+	} else if (cfi_buswidth_is_2()) {
+		if (cfi_interleave_is_1()) {
+			/* 1 x16 device in x16 mode */
+			val = cpu_to_cfi16(cmd);
+		} else if (cfi_interleave_is_2()) {
+			/* 2 (x8, x16 or x32) devices in x8 mode */
+			val = cpu_to_cfi16((cmd << 8) | cmd);
+		}
+	} else if (cfi_buswidth_is_4()) {
+		if (cfi_interleave_is_1()) {
+			/* 1 x32 device in x32 mode */
+			val = cpu_to_cfi32(cmd);
+		} else if (cfi_interleave_is_2()) {
+			/* 2 x16 device in x16 mode */
+			val = cpu_to_cfi32((cmd << 16) | cmd);
+		} else if (cfi_interleave_is_4()) {
+			/* 4 (x8, x16 or x32) devices in x8 mode */
+			val = (cmd << 16) | cmd;
+			val = cpu_to_cfi32((val << 8) | val);
+		}
+	}
+	return val;
+}
+#define CMD(x)  cfi_build_cmd((x), map, cfi)
+
+/*
+ * Read a value according to the bus width.
+ */
+
+static inline __u32 cfi_read(struct map_info *map, __u32 addr)
+{
+	if (cfi_buswidth_is_1()) {
+		return map->read8(map, addr);
+	} else if (cfi_buswidth_is_2()) {
+		return map->read16(map, addr);
+	} else if (cfi_buswidth_is_4()) {
+		return map->read32(map, addr);
+	} else {
+		return 0;
+	}
+}
+
+/*
+ * Write a value according to the bus width.
+ */
+
+static inline void cfi_write(struct map_info *map, __u32 val, __u32 addr)
+{
+	if (cfi_buswidth_is_1()) {
+		map->write8(map, val, addr);
+	} else if (cfi_buswidth_is_2()) {
+		map->write16(map, val, addr);
+	} else if (cfi_buswidth_is_4()) {
+		map->write32(map, val, addr);
+	}
+}
+
+/*
+ * Sends a CFI command to a bank of flash for the given geometry.
+ *
+ * Returns the offset in flash where the command was written.
+ * If prev_val is non-null, it will be set to the value at the command address,
+ * before the command was written.
+ */
+static inline __u32 cfi_send_gen_cmd(u_char cmd, __u32 cmd_addr, __u32 base,
+				struct map_info *map, struct cfi_private *cfi,
+				int type, __u32 *prev_val)
+{
+	__u32 val;
+	__u32 addr = base + cfi_build_cmd_addr(cmd_addr, CFIDEV_INTERLEAVE, type);
+
+	val = cfi_build_cmd(cmd, map, cfi);
+
+	if (prev_val)
+		*prev_val = cfi_read(map, addr);
+
+	cfi_write(map, val, addr);
+
+	return addr - base;
+}
+
+static inline __u8 cfi_read_query(struct map_info *map, __u32 addr)
+{
+	if (cfi_buswidth_is_1()) {
+		return map->read8(map, addr);
+	} else if (cfi_buswidth_is_2()) {
+		return cfi16_to_cpu(map->read16(map, addr));
+	} else if (cfi_buswidth_is_4()) {
+		return cfi32_to_cpu(map->read32(map, addr));
+	} else {
+		return 0;
+	}
+}
+
+#ifndef min
+#define min(x,y) ( (x)<(y)?(x):(y) )
+#endif
+
+static inline void cfi_udelay(int us)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+	if (current->need_resched)
+		schedule();
+	else
+#endif
+		udelay(us);
+}
+static inline void cfi_spin_lock(spinlock_t *mutex)
+{
+	spin_lock_bh(mutex);
+}
+
+static inline void cfi_spin_unlock(spinlock_t *mutex)
+{
+	spin_unlock_bh(mutex);
+}
+
 
 #endif /* __MTD_CFI_H__ */
diff -u --recursive --new-file v2.4.5/linux/include/linux/mtd/cfi_endian.h linux/include/linux/mtd/cfi_endian.h
--- v2.4.5/linux/include/linux/mtd/cfi_endian.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/mtd/cfi_endian.h	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,141 @@
+/*
+ * $Id: cfi_endian.h,v 1.9 2001/04/23 21:19:11 nico Exp $
+ *
+ * It seems that some helpful people decided to make life easier
+ * for software engineers who aren't capable of dealing with the 
+ * concept of byteswapping, and advise engineers to swap the bytes
+ * by wiring the data lines up to flash chips from BE hosts backwards.
+ *
+ * So we have ugly stuff here to disable the byteswapping where necessary.
+ * I'm not going to try to do this dynamically.
+ *
+ * At first I thought these guys were on crack, but then I discovered the
+ * LART. 
+ *
+ */
+
+#include <asm/byteorder.h>
+
+#ifndef CONFIG_MTD_CFI_ADV_OPTIONS
+
+#define CFI_HOST_ENDIAN
+
+#else
+
+#ifdef CONFIG_MTD_CFI_NOSWAP
+#define CFI_HOST_ENDIAN
+#endif
+
+#ifdef CONFIG_MTD_CFI_LE_BYTE_SWAP
+#define CFI_LITTLE_ENDIAN
+#endif
+
+#ifdef CONFIG_MTD_CFI_BE_BYTE_SWAP
+#define CFI_BIG_ENDIAN
+#endif
+
+#ifdef CONFIG_MTD_CFI_LART_BIT_SWAP
+#define CFI_LART_ENDIAN
+#endif
+
+#endif
+
+#if defined(CFI_LITTLE_ENDIAN)
+#define cpu_to_cfi8(x) (x)
+#define cfi8_to_cpu(x) (x)
+#define cpu_to_cfi16(x) cpu_to_le16(x)
+#define cpu_to_cfi32(x) cpu_to_le32(x)
+#define cfi16_to_cpu(x) le16_to_cpu(x)
+#define cfi32_to_cpu(x) le32_to_cpu(x)
+#elif defined (CFI_BIG_ENDIAN)
+#define cpu_to_cfi8(x) (x)
+#define cfi8_to_cpu(x) (x)
+#define cpu_to_cfi16(x) cpu_to_be16(x)
+#define cpu_to_cfi32(x) cpu_to_be32(x)
+#define cfi16_to_cpu(x) be16_to_cpu(x)
+#define cfi32_to_cpu(x) be32_to_cpu(x)
+#elif defined (CFI_HOST_ENDIAN)
+#define cpu_to_cfi8(x) (x)
+#define cfi8_to_cpu(x) (x)
+#define cpu_to_cfi16(x) (x)
+#define cpu_to_cfi32(x) (x)
+#define cfi16_to_cpu(x) (x)
+#define cfi32_to_cpu(x) (x)
+#elif defined (CFI_LART_ENDIAN)
+/* 
+   Fuck me backwards. The data line mapping on LART is as follows:
+
+	U2	CPU	|	U3	CPU
+	 0	20	|	0	12
+	 1	22	|	1	14
+	 2	19	|	2	11
+	 3	17	|	3	9
+	 4	24	|	4	0
+	 5	26	|	5	2
+	 6	31	|	6	7
+	 7	29	|	7	5
+	 8	21	|	8	13
+	 9	23	|	9	15
+	 10	18	|	10	10
+	 11	16	|	11	8
+	 12	25	|	12	1
+	 13	27	|	13	3
+	 14	30	|	14	6
+	 15	28	|	15	4
+
+   For historical reference: the reason why the LART has this strange
+   mapping is that the designer of the board wanted address lines to
+   be as short as possible. Why? Because in that way you don't need
+   drivers in the address lines so the memory access time can be held
+   short. -- Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
+*/
+/* cpu_to_cfi16() and cfi16_to_cpu() are not needed because the LART
+ * only has 32 bit wide Flash memory. -- Erik
+ */
+#define cpu_to_cfi16(x) (x)
+#define cfi16_to_cpu(x) (x)
+static inline __u32 cfi32_to_cpu(__u32 x)
+{
+	__u32 ret;
+
+	ret =  (x & 0x08009000) >> 11;
+	ret |= (x & 0x00002000) >> 10;
+	ret |= (x & 0x04004000) >> 8;
+	ret |= (x & 0x00000010) >> 4;
+	ret |= (x & 0x91000820) >> 3;
+	ret |= (x & 0x22080080) >> 2;
+	ret |= (x & 0x40000400);
+	ret |= (x & 0x00040040) << 1;
+	ret |= (x & 0x00110000) << 4;
+	ret |= (x & 0x00220100) << 5;
+	ret |= (x & 0x00800208) << 6;
+	ret |= (x & 0x00400004) << 9;
+	ret |= (x & 0x00000001) << 12;
+	ret |= (x & 0x00000002) << 13;
+
+	return ret;
+}
+static inline __u32 cpu_to_cfi32(__u32 x)
+{
+	__u32 ret;
+
+	ret =  (x & 0x00010012) << 11;
+	ret |= (x & 0x00000008) << 10;
+	ret |= (x & 0x00040040) << 8;
+	ret |= (x & 0x00000001) << 4;
+	ret |= (x & 0x12200104) << 3;
+	ret |= (x & 0x08820020) << 2;
+	ret |= (x & 0x40000400);
+	ret |= (x & 0x00080080) >> 1;
+	ret |= (x & 0x01100000) >> 4;
+	ret |= (x & 0x04402000) >> 5;
+	ret |= (x & 0x20008200) >> 6;
+	ret |= (x & 0x80000800) >> 9;
+	ret |= (x & 0x00001000) >> 12;
+	ret |= (x & 0x00004000) >> 13;
+
+	return ret;
+}
+#else
+#error No CFI endianness defined
+#endif
diff -u --recursive --new-file v2.4.5/linux/include/linux/mtd/doc2000.h linux/include/linux/mtd/doc2000.h
--- v2.4.5/linux/include/linux/mtd/doc2000.h	Mon Dec 11 14:57:58 2000
+++ linux/include/linux/mtd/doc2000.h	Tue Jun 12 10:30:27 2001
@@ -2,7 +2,7 @@
 /* Linux driver for Disk-On-Chip 2000       */
 /* (c) 1999 Machine Vision Holdings, Inc.   */
 /* Author: David Woodhouse <dwmw2@mvhi.com> */
-/* $Id: doc2000.h,v 1.12 2000/11/03 12:43:43 dwmw2 Exp $ */
+/* $Id: doc2000.h,v 1.13 2001/05/29 12:03:45 dwmw2 Exp $ */
 
 #ifndef __MTD_DOC2000_H__
 #define __MTD_DOC2000_H__
@@ -43,15 +43,19 @@
  * On PPC, it's mmap'd and 16-bit wide.
  * Others use readb/writeb 
  */
-#if defined(__arm__) 
-#define ReadDOC_(adr, reg)      ((unsigned char)(*(__u32 *)(((unsigned long)adr)+(reg<<2))))
-#define WriteDOC_(d, adr, reg)  do{ *(__u32 *)(((unsigned long)adr)+(reg<<2)) = (__u32)d} while(0)
+#if defined(__arm__)
+#define ReadDOC_(adr, reg)      ((unsigned char)(*(__u32 *)(((unsigned long)adr)+((reg)<<2))))
+#define WriteDOC_(d, adr, reg)  do{ *(__u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0)
+#define DOC_IOREMAP_LEN 0x8000
 #elif defined(__ppc__)
-#define ReadDOC_(adr, reg)      ((unsigned char)(*(__u16 *)(((unsigned long)adr)+(reg<<1))))
-#define WriteDOC_(d, adr, reg)  do{ *(__u16 *)(((unsigned long)adr)+(reg<<1)) = (__u16)d} while(0)
+#define ReadDOC_(adr, reg)      ((unsigned char)(*(__u16 *)(((unsigned long)adr)+((reg)<<1))))
+#define WriteDOC_(d, adr, reg)  do{ *(__u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0)
+#define DOC_IOREMAP_LEN 0x4000
 #else
-#define ReadDOC_(adr, reg)      readb(((unsigned long)adr) + reg)
-#define WriteDOC_(d, adr, reg)  writeb(d, ((unsigned long)adr) + reg)
+#define ReadDOC_(adr, reg)      readb(((unsigned long)adr) + (reg))
+#define WriteDOC_(d, adr, reg)  writeb(d, ((unsigned long)adr) + (reg))
+#define DOC_IOREMAP_LEN 0x2000
+
 #endif
 
 #if defined(__i386__)
diff -u --recursive --new-file v2.4.5/linux/include/linux/mtd/flashchip.h linux/include/linux/mtd/flashchip.h
--- v2.4.5/linux/include/linux/mtd/flashchip.h	Mon Dec 11 13:16:46 2000
+++ linux/include/linux/mtd/flashchip.h	Tue Jun 12 10:30:27 2001
@@ -6,7 +6,7 @@
  *
  * (C) 2000 Red Hat. GPLd.
  *
- * $Id: flashchip.h,v 1.4 2000/07/03 12:58:41 dwmw2 Exp $
+ * $Id: flashchip.h,v 1.7 2001/01/18 03:52:36 nico Exp $
  *
  */
 
@@ -25,12 +25,17 @@
 	FL_CFI_QUERY,
 	FL_JEDEC_QUERY,
 	FL_ERASING,
+	FL_ERASE_SUSPENDING,
 	FL_ERASE_SUSPENDED,
 	FL_WRITING,
+	FL_WRITING_TO_BUFFER,
+	FL_WRITE_SUSPENDING,
 	FL_WRITE_SUSPENDED,
 	FL_PM_SUSPENDED,
 	FL_SYNCING,
 	FL_UNLOADING,
+	FL_LOCKING,
+	FL_UNLOCKING,
 	FL_UNKNOWN
 } flstate_t;
 
diff -u --recursive --new-file v2.4.5/linux/include/linux/mtd/map.h linux/include/linux/mtd/map.h
--- v2.4.5/linux/include/linux/mtd/map.h	Fri Feb  9 11:29:44 2001
+++ linux/include/linux/mtd/map.h	Tue Jun 12 10:30:27 2001
@@ -1,6 +1,6 @@
 
 /* Overhauled routines for dealing with different mmap regions of flash */
-/* $Id: map.h,v 1.10.2.2 2001/01/09 00:44:51 dwmw2 Exp $ */
+/* $Id: map.h,v 1.24 2001/06/09 19:53:16 dwmw2 Exp $ */
 
 #ifndef __LINUX_MTD_MAP_H__
 #define __LINUX_MTD_MAP_H__
@@ -53,47 +53,23 @@
 	unsigned long map_priv_1;
 	unsigned long map_priv_2;
 	void *fldrv_priv;
-	void (*fldrv_destroy)(struct mtd_info *);
-	const char *im_name;
+	struct mtd_chip_driver *fldrv;
 };
 
-#ifdef CONFIG_MODULES
-/* 
- * Probe for the contents of a map device and make an MTD structure
- * if anything is recognised. Doesn't register it because the calling
- * map driver needs to set the 'module' field first.
- */
-static inline struct mtd_info *do_map_probe(struct map_info *map, const char *funcname, const char *modname)
-{
-	struct mtd_info *(*probe_p)(struct map_info *);
-	struct mtd_info *mtd = NULL;
 
-	if ((probe_p = inter_module_get_request(modname, funcname)))
-		mtd = (*probe_p)(map);	/* map->im_name is set by probe */
+struct mtd_chip_driver {
+	struct mtd_info *(*probe)(struct map_info *map);
+	void (*destroy)(struct mtd_info *);
+	struct module *module;
+	char *name;
+	struct list_head list;
+};
 
-	return mtd;
-}
+void register_mtd_chip_driver(struct mtd_chip_driver *);
+void unregister_mtd_chip_driver(struct mtd_chip_driver *);
 
+struct mtd_info *do_map_probe(char *name, struct map_info *map);
 
-/* 
- * Commonly-used probe functions for different types of chip.
- */
-#define do_cfi_probe(x) do_map_probe(x, "cfi_probe", "cfi_probe")
-#define do_jedec_probe(x) do_map_probe(x, "jedec_probe", "jedec_probe")
-#define do_ram_probe(x) do_map_probe(x, "map_ram_probe", "map_ram")
-#define do_rom_probe(x) do_map_probe(x, "map_rom_probe", "map_rom")
-#else
-	/* without module support, call probe function directly */
-extern struct mtd_info *cfi_probe(struct map_info *);
-extern struct mtd_info *jedec_probe(struct map_info *);
-extern struct mtd_info *map_ram_probe(struct map_info *);
-extern struct mtd_info *map_rom_probe(struct map_info *);
-
-#define do_cfi_probe(x) cfi_probe(x)
-#define do_jedec_probe(x) jedec_probe(x)
-#define do_ram_probe(x) map_ram_probe(x)
-#define do_rom_probe(x) map_rom_probe(x)
-#endif
 
 /*
  * Destroy an MTD device which was created for a map device.
@@ -103,8 +79,11 @@
 {
 	struct map_info *map = mtd->priv;
 
-	map->fldrv_destroy(mtd);
-	inter_module_put(map->im_name);
+	map->fldrv->destroy(mtd);
+#ifdef CONFIG_MODULES
+	if (map->fldrv->module)
+		__MOD_DEC_USE_COUNT(map->fldrv->module);
+#endif
 	kfree(mtd);
 }
 
diff -u --recursive --new-file v2.4.5/linux/include/linux/mtd/mapped.h linux/include/linux/mtd/mapped.h
--- v2.4.5/linux/include/linux/mtd/mapped.h	Tue Jul  4 10:12:33 2000
+++ linux/include/linux/mtd/mapped.h	Wed Dec 31 16:00:00 1969
@@ -1,92 +0,0 @@
-// -*- mode: cpp; mode: fold -*-
-// Description                                                          /*{{{*/
-// $Id: mapped.h,v 1.2 2000/03/14 17:13:12 dwmw2 Exp $
-/* ######################################################################
-
-   Memory Mapped  MTD Routines
-   
-   These routines are support routines for memory mapped chips, with
-   routines to support common sorts of flash. For devices that are based
-   on a memory mapped interface these routines provide everything necessary,
-   only a window changing function is required by the low level implementation.
-   
-   The entry point to setup and register a memory mapped MTD device, 
-   mtd_mapped_setup will perform a detection sequence that can determine
-   the type size and configuration of many sorts of chip setups. 
-
-   ROMs and RAMs are detected and passed off to very simple routines, Flash
-   writing and erasing is handled as well.
-   
-   ##################################################################### */
-									/*}}}*/
-#ifndef __MTD_FLASH_H__
-#define __MTD_FLASH_H__
-
-#include <linux/types.h>
-#include <linux/mtd/mtd.h>
-
-// MTD flags for ordinary flash
-struct JEDECTable
-{
-   u_short jedec;
-   char *name;
-   u_long size;
-   u_long sectorsize;
-   u_long capabilities;
-};
-
-// JEDEC being 0 is the end of the chip array
-struct flash_chip
-{
-   u_short jedec;
-   u_long size;
-   u_long sectorsize;
-   u_long base;
-   u_long capabilities;
-   
-   // These markers are filled in by the flash_chip_scan function
-   u_long start;
-   u_long length;
-};
-
-struct mapped_mtd_info
-{
-   struct mtd_info mtd;
-   u_long pagesize;        // Size of the memory window
-   u_long maxsize;         // Maximum MTD size in pages
-   u_char mfr,id;
-   char part[100];            // Part Catalogue number if available
-   int *lock;
-   // Multiple chip support, only used if this is type MTD_FLASH
-   u_char interleve;       // Address chip interleve (0 = concatination)
-   struct flash_chip chips[5];
-  
-   // Operations
-   unsigned long (*page)(struct mapped_mtd_info *map,unsigned long page);
-   int (*jedec_sense)(struct mapped_mtd_info *map);
-};
-
-extern struct JEDECTable mtd_JEDEC_table[];
-
-// Automatic configurators
-extern int mtd_mapped_setup(struct mapped_mtd_info *map);
-extern int mtd_mapped_remove(struct mapped_mtd_info *map);
-
-// Generic functions
-extern int flash_jedec(struct mapped_mtd_info *map);
-extern int flash_erase(struct mtd_info *map, struct erase_info *instr);
-extern int flash_write(struct mtd_info *map, loff_t start, size_t len,
-		       size_t *retlen, const u_char *buf);
-extern int rom_read(struct mtd_info *map, loff_t start, size_t len,
-		    size_t *retlen, u_char *buf);
-extern int ram_write(struct mtd_info *map, loff_t start, size_t len,
-		     size_t *retlen, const u_char *buf);
-
-// Helpers
-extern int page_jump(struct mapped_mtd_info *map,unsigned long start,
-		     unsigned long len,unsigned long *buffer,
-		     unsigned long *size);
-extern void flash_chip_scan(struct mapped_mtd_info *map,unsigned long start,
-			    unsigned long len);
-
-#endif /* __MTD_FLASH_H__ */
diff -u --recursive --new-file v2.4.5/linux/include/linux/mtd/mtd.h linux/include/linux/mtd/mtd.h
--- v2.4.5/linux/include/linux/mtd/mtd.h	Fri Dec 29 14:07:24 2000
+++ linux/include/linux/mtd/mtd.h	Tue Jun 12 10:30:27 2001
@@ -1,5 +1,5 @@
 
-/* $Id: mtd.h,v 1.26 2000/10/30 17:18:04 sjhill Exp $ */
+/* $Id: mtd.h,v 1.33 2001/06/09 00:08:59 dwmw2 Exp $ */
 
 #ifndef __MTD_MTD_H__
 #define __MTD_MTD_H__
@@ -16,13 +16,13 @@
 #endif /* __KERNEL__ */
 
 struct erase_info_user {
-	unsigned long start;
-	unsigned long length;
+	u_int32_t start;
+	u_int32_t length;
 };
 
 struct mtd_oob_buf {
-	loff_t start;
-	ssize_t length;
+	u_int32_t start;
+	u_int32_t length;
 	unsigned char *ptr;
 };
 
@@ -68,13 +68,21 @@
 
 struct mtd_info_user {
 	u_char type;
-	u_long flags;
-	u_long size;	 // Total size of the MTD
-	u_long erasesize;
-	u_long oobblock;  // Size of OOB blocks (e.g. 512)
-	u_long oobsize;   // Amount of OOB data per block (e.g. 16)
-        u_long ecctype;
-        u_long eccsize;
+	u_int32_t flags;
+	u_int32_t size;	 // Total size of the MTD
+	u_int32_t erasesize;
+	u_int32_t oobblock;  // Size of OOB blocks (e.g. 512)
+	u_int32_t oobsize;   // Amount of OOB data per block (e.g. 16)
+	u_int32_t ecctype;
+	u_int32_t eccsize;
+};
+
+struct region_info_user {
+	u_int32_t offset;		/* At which this region starts, 
+					 * from the beginning of the MTD */
+	u_int32_t erasesize;		/* For this region */
+	u_int32_t numblocks;		/* Number of blocks in this region */
+	u_int32_t regionindex;
 };
 
 #define MEMGETINFO              _IOR('M', 1, struct mtd_info_user)
@@ -83,11 +91,14 @@
 #define MEMREADOOB              _IOWR('M', 4, struct mtd_oob_buf)
 #define MEMLOCK                 _IOW('M', 5, struct erase_info_user)
 #define MEMUNLOCK               _IOW('M', 6, struct erase_info_user)
+#define MEMGETREGIONCOUNT	_IOR('M', 7, int)
+#define MEMGETREGIONINFO	_IOWR('M', 8, struct region_info_user)
 
 #ifndef __KERNEL__
 
 typedef struct mtd_info_user mtd_info_t;
 typedef struct erase_info_user erase_info_t;
+typedef struct region_info_user region_info_t;
 
 	/* User-space ioctl definitions */
 
@@ -103,8 +114,8 @@
 
 struct erase_info {
 	struct mtd_info *mtd;
-	u_long addr;
-	u_long len;
+	u_int32_t addr;
+	u_int32_t len;
 	u_long time;
 	u_long retries;
 	u_int dev;
@@ -115,22 +126,40 @@
 	struct erase_info *next;
 };
 
+struct mtd_erase_region_info {
+	u_int32_t offset;			/* At which this region starts, from the beginning of the MTD */
+	u_int32_t erasesize;		/* For this region */
+	u_int32_t numblocks;		/* Number of blocks of erasesize in this region */
+};
 
 struct mtd_info {
 	u_char type;
-	u_long flags;
-	u_long size;	 // Total size of the MTD
-	u_long erasesize;
-	u_long oobblock;  // Size of OOB blocks (e.g. 512)
-	u_long oobsize;   // Amount of OOB data per block (e.g. 16)
-        u_long ecctype;
-        u_long eccsize;
+	u_int32_t flags;
+	u_int32_t size;	 // Total size of the MTD
+
+	/* "Major" erase size for the device. Naďve users may take this
+	 * to be the only erase size available, or may use the more detailed
+	 * information below if they desire
+	 */
+	u_int32_t erasesize;
+
+	u_int32_t oobblock;  // Size of OOB blocks (e.g. 512)
+	u_int32_t oobsize;   // Amount of OOB data per block (e.g. 16)
+	u_int32_t ecctype;
+	u_int32_t eccsize;
 
 	// Kernel-only stuff starts here.
 	char *name;
 	int index;
 
-	u_long bank_size;
+	/* Data for variable erase regions. If numeraseregions is zero,
+	 * it means that the whole device has erasesize as given above. 
+	 */
+	int numeraseregions;
+	struct mtd_erase_region_info *eraseregions; 
+
+	/* This really shouldn't be here. It can go away in 2.5 */
+	u_int32_t bank_size;
 
 	struct module *module;
 	int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
diff -u --recursive --new-file v2.4.5/linux/include/linux/mtd/nand_ecc.h linux/include/linux/mtd/nand_ecc.h
--- v2.4.5/linux/include/linux/mtd/nand_ecc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/mtd/nand_ecc.h	Tue Jun 12 10:30:27 2001
@@ -0,0 +1,28 @@
+/*
+ *  drivers/mtd/nand_ecc.h
+ *
+ *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ *
+ * $Id: nand_ecc.h,v 1.1 2000/10/12 00:57:15 sjhill 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.
+ *
+ * This file is the header for the ECC algorithm.
+ */
+
+/*
+ * Creates non-inverted ECC code from line parity
+ */
+void nand_trans_result(u_char reg2, u_char reg3, u_char *ecc_code);
+
+/*
+ * Calculate 3 byte ECC code for 256 byte block
+ */
+void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
+
+/*
+ * Detect and correct a 1 bit error for 256 byte block
+ */
+int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
diff -u --recursive --new-file v2.4.5/linux/include/linux/mtd/nftl.h linux/include/linux/mtd/nftl.h
--- v2.4.5/linux/include/linux/mtd/nftl.h	Mon Dec 11 14:57:58 2000
+++ linux/include/linux/mtd/nftl.h	Tue Jun 12 10:30:27 2001
@@ -2,7 +2,7 @@
 /* Defines for NAND Flash Translation Layer  */
 /* (c) 1999 Machine Vision Holdings, Inc.    */
 /* Author: David Woodhouse <dwmw2@mvhi.com>  */
-/* $Id: nftl.h,v 1.9 2000/11/07 05:48:49 ollie Exp $ */
+/* $Id: nftl.h,v 1.10 2000/12/29 00:25:38 dwmw2 Exp $ */
 
 #ifndef __MTD_NFTL_H__
 #define __MTD_NFTL_H__
@@ -115,6 +115,7 @@
 
 #define MAX_NFTLS 16
 #define MAX_SECTORS_PER_UNIT 32
+#define NFTL_PARTN_BITS 4
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.4.5/linux/include/linux/mtd/partitions.h linux/include/linux/mtd/partitions.h
--- v2.4.5/linux/include/linux/mtd/partitions.h	Mon Dec 11 14:57:58 2000
+++ linux/include/linux/mtd/partitions.h	Tue Jun 12 10:30:27 2001
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: partitions.h,v 1.3 2000/11/10 23:35:12 nico Exp $
+ * $Id: partitions.h,v 1.6 2001/03/17 17:10:21 dwmw2 Exp $
  */
 
 #ifndef MTD_PARTITIONS_H
@@ -22,10 +22,11 @@
  *
  * For each partition, these fields are available:
  * name: string that will be used to label the partition's MTD device.
- * size: the partition size; if 0, the partition will extend to the end of the 
- * 	master MTD device.
- * offset: absolute starting position within the master MTD device; if 0,
- * 	partition will start where the previous one ended.
+ * size: the partition size; if defined as MTDPART_SIZ_FULL, the partition 
+ * 	will extend to the end of the master MTD device.
+ * offset: absolute starting position within the master MTD device; if 
+ * 	defined as MTDPART_OFS_APPEND, the partition will start where the 
+ * 	previous one ended.
  * mask_flags: contains flags that have to be masked (removed) from the 
  * 	master MTD flag set for the corresponding MTD partition.
  * 	For example, to force a read-only partition, simply adding 
@@ -37,10 +38,13 @@
 
 struct mtd_partition {
 	char *name;		/* identifier string */
-	u_long size;		/* partition size */
-	u_long offset;		/* offset within the master MTD space */
-	u_long mask_flags;	/* master MTD flags to mask out for this partition */
+	u_int32_t size;		/* partition size */
+	u_int32_t offset;		/* offset within the master MTD space */
+	u_int32_t mask_flags;	/* master MTD flags to mask out for this partition */
 };
+
+#define MTDPART_OFS_APPEND	(-1)
+#define MTDPART_SIZ_FULL	(0)
 
 
 int add_mtd_partitions(struct mtd_info *, struct mtd_partition *, int);
diff -u --recursive --new-file v2.4.5/linux/include/linux/netfilter_bridge.h linux/include/linux/netfilter_bridge.h
--- v2.4.5/linux/include/linux/netfilter_bridge.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/netfilter_bridge.h	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,24 @@
+#ifndef __LINUX_BRIDGE_NETFILTER_H
+#define __LINUX_BRIDGE_NETFILTER_H
+
+/* bridge-specific defines for netfilter. 
+ */
+
+#include <linux/config.h>
+#include <linux/netfilter.h>
+
+/* Bridge Hooks */
+/* After promisc drops, checksum checks. */
+#define NF_BR_PRE_ROUTING	0
+/* If the packet is destined for this box. */
+#define NF_BR_LOCAL_IN		1
+/* If the packet is destined for another interface. */
+#define NF_BR_FORWARD		2
+/* Packets coming from a local process. */
+#define NF_BR_LOCAL_OUT		3
+/* Packets about to hit the wire. */
+#define NF_BR_POST_ROUTING	4
+#define NF_BR_NUMHOOKS		5
+
+
+#endif
diff -u --recursive --new-file v2.4.5/linux/include/linux/netfilter_ipv4/ip_tables.h linux/include/linux/netfilter_ipv4/ip_tables.h
--- v2.4.5/linux/include/linux/netfilter_ipv4/ip_tables.h	Mon Dec 11 13:31:24 2000
+++ linux/include/linux/netfilter_ipv4/ip_tables.h	Mon Jun 11 19:15:27 2001
@@ -300,14 +300,14 @@
 ({						\
 	unsigned int __i;			\
 	int __ret = 0;				\
-	struct ipt_entry_match *__m;		\
+	struct ipt_entry_match *__match;	\
 						\
 	for (__i = sizeof(struct ipt_entry);	\
 	     __i < (e)->target_offset;		\
-	     __i += __m->u.match_size) {	\
-		__m = (void *)(e) + __i;	\
+	     __i += __match->u.match_size) {	\
+		__match = (void *)(e) + __i;	\
 						\
-		__ret = fn(__m , ## args);	\
+		__ret = fn(__match , ## args);	\
 		if (__ret != 0)			\
 			break;			\
 	}					\
@@ -319,12 +319,12 @@
 ({								\
 	unsigned int __i;					\
 	int __ret = 0;						\
-	struct ipt_entry *__e;					\
+	struct ipt_entry *__entry;				\
 								\
-	for (__i = 0; __i < (size); __i += __e->next_offset) {	\
-		__e = (void *)(entries) + __i;			\
+	for (__i = 0; __i < (size); __i += __entry->next_offset) { \
+		__entry = (void *)(entries) + __i;		\
 								\
-		__ret = fn(__e , ## args);			\
+		__ret = fn(__entry , ## args);			\
 		if (__ret != 0)					\
 			break;					\
 	}							\
diff -u --recursive --new-file v2.4.5/linux/include/linux/parport_pc.h linux/include/linux/parport_pc.h
--- v2.4.5/linux/include/linux/parport_pc.h	Sat May 19 18:07:04 2001
+++ linux/include/linux/parport_pc.h	Mon Jun 11 19:15:27 2001
@@ -224,5 +224,6 @@
 					      unsigned long base_hi,
 					      int irq, int dma,
 					      struct pci_dev *dev);
+extern void parport_pc_unregister_port (struct parport *p);
 
 #endif
diff -u --recursive --new-file v2.4.5/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.4.5/linux/include/linux/pci.h	Fri May 25 18:02:11 2001
+++ linux/include/linux/pci.h	Wed Jun 20 12:17:25 2001
@@ -327,6 +327,9 @@
 #define pci_for_each_dev_reverse(dev) \
 	for(dev = pci_dev_g(pci_devices.prev); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.prev))
 
+#define pci_for_each_bus(bus) \
+for(bus = pci_bus_b(pci_root_buses.next); bus != pci_bus_b(&pci_root_buses); bus = pci_bus_b(bus->node.next))
+
 /*
  * The pci_dev structure is used to describe both PCI and ISAPnP devices.
  */
@@ -356,6 +359,10 @@
 					   this if your device has broken DMA
 					   or supports 64-bit transfers.  */
 
+	u32             current_state;  /* Current operating state. In ACPI-speak,
+					   this is D0-D3, D0 being fully functional,
+					   and D3 being off. */
+
 	/* device is compatible with these IDs */
 	unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE];
 	unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE];
@@ -469,10 +476,11 @@
 	struct list_head node;
 	char *name;
 	const struct pci_device_id *id_table;	/* NULL if wants all devices */
-	int (*probe)(struct pci_dev *dev, const struct pci_device_id *id);	/* New device inserted */
-	void (*remove)(struct pci_dev *dev);	/* Device removed (NULL if not a hot-plug capable driver) */
-	void (*suspend)(struct pci_dev *dev);	/* Device suspended */
-	void (*resume)(struct pci_dev *dev);	/* Device woken up */
+	int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id);	/* New device inserted */
+	void (*remove) (struct pci_dev *dev);	/* Device removed (NULL if not a hot-plug capable driver) */
+	int  (*suspend)(struct pci_dev *dev, u32 state);	/* Device suspended */
+	int  (*resume) (struct pci_dev *dev);	                /* Device woken up */
+	int  (*enable_wake) (struct pci_dev *dev, u32 state, int enable);   /* Enable wake event */
 };
 
 
@@ -547,13 +555,17 @@
 int pci_write_config_word(struct pci_dev *dev, int where, u16 val);
 int pci_write_config_dword(struct pci_dev *dev, int where, u32 val);
 
-#define HAVE_PCI_DISABLE_DEVICE
 int pci_enable_device(struct pci_dev *dev);
 void pci_disable_device(struct pci_dev *dev);
 void pci_set_master(struct pci_dev *dev);
 int pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask);
-int pci_set_power_state(struct pci_dev *dev, int state);
 int pci_assign_resource(struct pci_dev *dev, int i);
+
+/* Power management related routines */
+int pci_save_state(struct pci_dev *dev, u32 *buffer);
+int pci_restore_state(struct pci_dev *dev, u32 *buffer);
+int pci_set_power_state(struct pci_dev *dev, int state);
+int pci_enable_wake(struct pci_dev *dev, u32 state, int enable);
 
 /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
 
diff -u --recursive --new-file v2.4.5/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- v2.4.5/linux/include/linux/pci_ids.h	Wed May 16 10:25:39 2001
+++ linux/include/linux/pci_ids.h	Wed Jun 20 11:16:01 2001
@@ -160,20 +160,37 @@
 #define PCI_DEVICE_ID_NCR_YELLOWFIN	0x0701
 
 #define PCI_VENDOR_ID_ATI		0x1002
+/* Mach64 */
 #define PCI_DEVICE_ID_ATI_68800		0x4158
 #define PCI_DEVICE_ID_ATI_215CT222	0x4354
 #define PCI_DEVICE_ID_ATI_210888CX	0x4358
+#define PCI_DEVICE_ID_ATI_215ET222	0x4554
+/* Mach64 / Rage */
 #define PCI_DEVICE_ID_ATI_215GB		0x4742
 #define PCI_DEVICE_ID_ATI_215GD		0x4744
 #define PCI_DEVICE_ID_ATI_215GI		0x4749
 #define PCI_DEVICE_ID_ATI_215GP		0x4750
 #define PCI_DEVICE_ID_ATI_215GQ		0x4751
+#define PCI_DEVICE_ID_ATI_215XL		0x4752
 #define PCI_DEVICE_ID_ATI_215GT		0x4754
 #define PCI_DEVICE_ID_ATI_215GTB	0x4755
+#define PCI_DEVICE_ID_ATI_215_IV	0x4756
+#define PCI_DEVICE_ID_ATI_215_IW	0x4757
+#define PCI_DEVICE_ID_ATI_215_IZ	0x475A
 #define PCI_DEVICE_ID_ATI_210888GX	0x4758
-#define PCI_DEVICE_ID_ATI_215LG		0x4c47
-#define PCI_DEVICE_ID_ATI_264LT		0x4c54
+#define PCI_DEVICE_ID_ATI_215_LB	0x4c42
+#define PCI_DEVICE_ID_ATI_215_LD	0x4c44
+#define PCI_DEVICE_ID_ATI_215_LG	0x4c47
+#define PCI_DEVICE_ID_ATI_215_LI	0x4c49
+#define PCI_DEVICE_ID_ATI_215_LM	0x4c4D
+#define PCI_DEVICE_ID_ATI_215_LN	0x4c4E
+#define PCI_DEVICE_ID_ATI_215_LR	0x4c52
+#define PCI_DEVICE_ID_ATI_215_LS	0x4c53
+#define PCI_DEVICE_ID_ATI_264_LT	0x4c54
+/* Mach64 VT */
 #define PCI_DEVICE_ID_ATI_264VT		0x5654
+#define PCI_DEVICE_ID_ATI_264VU		0x5655
+#define PCI_DEVICE_ID_ATI_264VV		0x5656
 /* Rage128 Pro GL */
 #define PCI_DEVICE_ID_ATI_Rage128_PA	0x5041
 #define PCI_DEVICE_ID_ATI_Rage128_PB	0x5042
@@ -1135,6 +1152,7 @@
 #define PCI_DEVICE_ID_AVM_B1		0x0700
 #define PCI_DEVICE_ID_AVM_C4		0x0800
 #define PCI_DEVICE_ID_AVM_A1		0x0a00
+#define PCI_DEVICE_ID_AVM_C2		0x1100
 #define PCI_DEVICE_ID_AVM_T1		0x1200
 
 #define PCI_VENDOR_ID_DIPIX		0x1246
@@ -1476,13 +1494,18 @@
 #define PCI_DEVICE_ID_INTEL_82801AB_5	0x2425
 #define PCI_DEVICE_ID_INTEL_82801AB_6	0x2426
 #define PCI_DEVICE_ID_INTEL_82801AB_8	0x2428
-#define PCI_DEVICE_ID_INTEL_82820FW_0	0x2440
-#define PCI_DEVICE_ID_INTEL_82820FW_1	0x2442
-#define PCI_DEVICE_ID_INTEL_82820FW_2	0x2443
-#define PCI_DEVICE_ID_INTEL_82820FW_3	0x2444
-#define PCI_DEVICE_ID_INTEL_82820FW_4	0x2449
-#define PCI_DEVICE_ID_INTEL_82820FW_5	0x244b
-#define PCI_DEVICE_ID_INTEL_82820FW_6	0x244e
+#define PCI_DEVICE_ID_INTEL_82801BA_0	0x2440
+#define PCI_DEVICE_ID_INTEL_82801BA_1	0x2442
+#define PCI_DEVICE_ID_INTEL_82801BA_2	0x2443
+#define PCI_DEVICE_ID_INTEL_82801BA_3	0x2444
+#define PCI_DEVICE_ID_INTEL_82801BA_4	0x2445
+#define PCI_DEVICE_ID_INTEL_82801BA_5	0x2446
+#define PCI_DEVICE_ID_INTEL_82801BA_6	0x2448
+#define PCI_DEVICE_ID_INTEL_82801BA_7	0x2449
+#define PCI_DEVICE_ID_INTEL_82801BA_8	0x244a
+#define PCI_DEVICE_ID_INTEL_82801BA_9	0x244b
+#define PCI_DEVICE_ID_INTEL_82801BA_10	0x244c
+#define PCI_DEVICE_ID_INTEL_82801BA_11	0x244e
 #define PCI_DEVICE_ID_INTEL_82810_MC1	0x7120
 #define PCI_DEVICE_ID_INTEL_82810_IG1	0x7121
 #define PCI_DEVICE_ID_INTEL_82810_MC3	0x7122
diff -u --recursive --new-file v2.4.5/linux/include/linux/quotaops.h linux/include/linux/quotaops.h
--- v2.4.5/linux/include/linux/quotaops.h	Fri May 25 18:01:57 2001
+++ linux/include/linux/quotaops.h	Wed Jun 20 12:17:15 2001
@@ -21,7 +21,6 @@
  */
 extern void dquot_initialize(struct inode *inode, short type);
 extern void dquot_drop(struct inode *inode);
-extern void invalidate_dquots(kdev_t dev, short type);
 extern int  quota_off(struct super_block *sb, short type);
 extern int  sync_dquots(kdev_t dev, short type);
 
diff -u --recursive --new-file v2.4.5/linux/include/linux/reiserfs_fs.h linux/include/linux/reiserfs_fs.h
--- v2.4.5/linux/include/linux/reiserfs_fs.h	Fri Apr 27 14:18:08 2001
+++ linux/include/linux/reiserfs_fs.h	Tue Jun 12 11:12:47 2001
@@ -1806,6 +1806,10 @@
 extern int reiserfs_notify_change(struct dentry * dentry, struct iattr * attr);
 void reiserfs_write_inode (struct inode * inode, int) ;
 
+/* nfsd support functions */
+struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, __u32 *fh, int len, int fhtype, int parent);
+int reiserfs_dentry_to_fh(struct dentry *, __u32 *fh, int *lenp, int need_parent);
+
 /* we don't mark inodes dirty, we just log them */
 void reiserfs_dirty_inode (struct inode * inode) ;
 
diff -u --recursive --new-file v2.4.5/linux/include/linux/slab.h linux/include/linux/slab.h
--- v2.4.5/linux/include/linux/slab.h	Fri May 25 18:01:28 2001
+++ linux/include/linux/slab.h	Wed Jun 20 12:16:56 2001
@@ -22,7 +22,7 @@
 #define	SLAB_NFS		GFP_NFS
 #define	SLAB_DMA		GFP_DMA
 
-#define SLAB_LEVEL_MASK		(__GFP_WAIT|__GFP_HIGH|__GFP_IO)
+#define SLAB_LEVEL_MASK		(__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_BUFFER)
 #define	SLAB_NO_GROW		0x00001000UL	/* don't grow a cache */
 
 /* flags to pass to kmem_cache_create().
diff -u --recursive --new-file v2.4.5/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h
--- v2.4.5/linux/include/linux/smb_fs.h	Tue May 15 13:40:55 2001
+++ linux/include/linux/smb_fs.h	Wed Jun 20 16:07:57 2001
@@ -93,6 +93,11 @@
 
 #endif /* DEBUG_SMB_MALLOC */
 
+/*
+ * Flags for the in-memory inode
+ */
+#define SMB_F_LOCALWRITE	0x02	/* file modified locally */
+
 
 /* NT1 protocol capability bits */
 #define SMB_CAP_RAW_MODE         0x0001
diff -u --recursive --new-file v2.4.5/linux/include/linux/smb_fs_i.h linux/include/linux/smb_fs_i.h
--- v2.4.5/linux/include/linux/smb_fs_i.h	Fri May 25 18:01:26 2001
+++ linux/include/linux/smb_fs_i.h	Wed Jun 20 16:07:57 2001
@@ -26,6 +26,7 @@
 	__u16 attr;		/* Attribute fields, DOS value */
 
 	__u16 access;		/* Access mode */
+	__u16 flags;
 	unsigned long oldmtime;	/* last time refreshed */
 	unsigned long closed;	/* timestamp when closed */
 	unsigned openers;	/* number of fileid users */
diff -u --recursive --new-file v2.4.5/linux/include/linux/socket.h linux/include/linux/socket.h
--- v2.4.5/linux/include/linux/socket.h	Fri May 25 18:01:26 2001
+++ linux/include/linux/socket.h	Wed Jun 20 12:16:56 2001
@@ -156,6 +156,7 @@
 #define AF_IRDA		23	/* IRDA sockets			*/
 #define AF_PPPOX	24	/* PPPoX sockets		*/
 #define AF_WANPIPE	25	/* Wanpipe API Sockets */
+#define AF_BLUETOOTH	31	/* Bluetooth sockets 		*/
 #define AF_MAX		32	/* For now.. */
 
 /* Protocol families, same as address families. */
@@ -186,6 +187,7 @@
 #define PF_IRDA		AF_IRDA
 #define PF_PPPOX	AF_PPPOX
 #define PF_WANPIPE	AF_WANPIPE
+#define PF_BLUETOOTH	AF_BLUETOOTH
 #define PF_MAX		AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
diff -u --recursive --new-file v2.4.5/linux/include/linux/sunrpc/xprt.h linux/include/linux/sunrpc/xprt.h
--- v2.4.5/linux/include/linux/sunrpc/xprt.h	Fri May 25 18:01:27 2001
+++ linux/include/linux/sunrpc/xprt.h	Wed Jun 20 12:17:44 2001
@@ -138,7 +138,7 @@
 	struct rpc_wait_queue	reconn;		/* waiting for reconnect */
 	struct rpc_rqst *	free;		/* free slots */
 	struct rpc_rqst		slot[RPC_MAXREQS];
-	unsigned int		sockstate;	/* Socket state */
+	unsigned long		sockstate;	/* Socket state */
 	unsigned char		shutdown   : 1,	/* being shut down */
 				nocong	   : 1,	/* no congestion control */
 				stream     : 1,	/* TCP */
diff -u --recursive --new-file v2.4.5/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.4.5/linux/include/linux/swap.h	Fri May 25 18:01:27 2001
+++ linux/include/linux/swap.h	Wed Jun 20 12:16:56 2001
@@ -133,6 +133,7 @@
 extern void __delete_from_swap_cache(struct page *page);
 extern void delete_from_swap_cache(struct page *page);
 extern void delete_from_swap_cache_nolock(struct page *page);
+extern void free_page_and_swap_cache(struct page *page);
 
 /* linux/mm/swapfile.c */
 extern unsigned int nr_swapfiles;
@@ -200,6 +201,16 @@
 	ZERO_PAGE_BUG \
 	SetPageInactiveDirty(page); \
 	list_add(&(page)->lru, &inactive_dirty_list); \
+	nr_inactive_dirty_pages++; \
+	page->zone->inactive_dirty_pages++; \
+}
+
+/* Like the above, but add us after the bookmark. */
+#define add_page_to_inactive_dirty_list_marker(page) { \
+	DEBUG_ADD_PAGE \
+	ZERO_PAGE_BUG \
+	SetPageInactiveDirty(page); \
+	list_add(&(page)->lru, marker_lru); \
 	nr_inactive_dirty_pages++; \
 	page->zone->inactive_dirty_pages++; \
 }
diff -u --recursive --new-file v2.4.5/linux/include/linux/udf_167.h linux/include/linux/udf_167.h
--- v2.4.5/linux/include/linux/udf_167.h	Mon Dec 11 13:27:05 2000
+++ linux/include/linux/udf_167.h	Mon Jun 11 19:15:27 2001
@@ -31,7 +31,7 @@
  * CONTACTS
  *	E-mail regarding any portion of the Linux UDF file system should be
  *	directed to the development team mailing list (run by majordomo):
- *		linux_udf@hootie.lvld.hp.com
+ *		linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *	This file is distributed under the terms of the GNU General Public
diff -u --recursive --new-file v2.4.5/linux/include/linux/udf_fs.h linux/include/linux/udf_fs.h
--- v2.4.5/linux/include/linux/udf_fs.h	Mon Jan  1 09:57:08 2001
+++ linux/include/linux/udf_fs.h	Mon Jun 11 19:15:27 2001
@@ -16,7 +16,7 @@
  * CONTACTS
  *	E-mail regarding any portion of the Linux UDF file system should be
  *	directed to the development team mailing list (run by majordomo):
- *		linux_udf@hootie.lvld.hp.com
+ *		linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *	This file is distributed under the terms of the GNU General Public
@@ -35,10 +35,20 @@
 #define _LINUX_UDF_FS_H
 
 #define UDF_PREALLOCATE
-#define UDF_DEFAULT_PREALLOC_BLOCKS		8
+#define UDF_DEFAULT_PREALLOC_BLOCKS	8
 
-#define UDFFS_DATE		"2000/02/29"
-#define UDFFS_VERSION	"0.9.1"
+#define UDFFS_DATE			"2001/06/06"
+#define UDFFS_VERSION			"0.9.4"
+
+#if !defined(UDFFS_RW)
+
+#if defined(CONFIG_UDF_RW)
+#define UDFFS_RW			1
+#else /* !defined(CONFIG_UDF_RW) */
+#define UDFFS_RW			0
+#endif /* defined(CONFIG_UDF_RW) */
+
+#endif /* !defined(UDFFS_RW) */
 
 #define UDFFS_DEBUG
 
diff -u --recursive --new-file v2.4.5/linux/include/linux/udf_fs_i.h linux/include/linux/udf_fs_i.h
--- v2.4.5/linux/include/linux/udf_fs_i.h	Thu Mar  2 11:17:32 2000
+++ linux/include/linux/udf_fs_i.h	Mon Jun 11 19:15:27 2001
@@ -6,7 +6,7 @@
  * CONTACTS
  *	E-mail regarding any portion of the Linux UDF file system should be
  *	directed to the development team mailing list (run by majordomo):
- *		linux_udf@hootie.lvld.hp.com
+ *		linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *	This file is distributed under the terms of the GNU General Public
@@ -38,6 +38,7 @@
 	__u64 i_unique;
 	__u32 i_lenEAttr;
 	__u32 i_lenAlloc;
+	__u64 i_lenExtents;
 	__u32 i_next_alloc_block;
 	__u32 i_next_alloc_goal;
 	unsigned i_alloc_type : 3;
@@ -54,5 +55,6 @@
 #define UDF_GETEASIZE   _IOR('l', 0x40, int)
 #define UDF_GETEABLOCK  _IOR('l', 0x41, void *)
 #define UDF_GETVOLIDENT _IOR('l', 0x42, void *)
+#define UDF_RELOCATE_BLOCKS _IOWR('l', 0x43, long)
 
 #endif /* !defined(_LINUX_UDF_FS_I_H) */
diff -u --recursive --new-file v2.4.5/linux/include/linux/udf_fs_sb.h linux/include/linux/udf_fs_sb.h
--- v2.4.5/linux/include/linux/udf_fs_sb.h	Mon Mar 20 08:17:43 2000
+++ linux/include/linux/udf_fs_sb.h	Wed Jun 20 12:16:55 2001
@@ -6,7 +6,7 @@
  * CONTACTS
  *	E-mail regarding any portion of the Linux UDF file system should be
  *	directed to the development team mailing list (run by majordomo):
- *		linux_udf@hootie.lvld.hp.com
+ *		linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *	This file is distributed under the terms of the GNU General Public
@@ -18,6 +18,10 @@
 #if !defined(_LINUX_UDF_FS_SB_H)
 #define _LINUX_UDF_FS_SB_H
 
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
 #pragma pack(1)
 
 #define UDF_MAX_BLOCK_LOADED	8
@@ -29,16 +33,8 @@
 
 struct udf_sparing_data
 {
-	__u32	s_spar_loc[4];
-	__u8	s_spar_pshift;
-	__u8	s_spar_indexsize;
-	__u32	*s_spar_map;
-	union
-	{
-		__u8	*s_spar_remap8;
-		__u16	*s_spar_remap16;
-		__u32	*s_spar_remap32;
-	} s_spar_remap;
+	__u16	s_packet_len;
+	struct buffer_head *s_spar_map[4];
 };
 
 struct udf_virtual_data
@@ -47,18 +43,26 @@
 	__u16	s_start_offset;
 };
 
+struct udf_bitmap
+{
+	__u32			s_extLength;
+	__u32			s_extPosition;
+	__u16			s_nr_groups;
+	struct buffer_head 	**s_block_bitmap;
+};
+
 struct udf_part_map
 {
 	union
 	{
-		__u32			bitmap;
-		struct inode	*table;
-	}		s_uspace;
+		struct udf_bitmap	*s_bitmap;
+		struct inode		*s_table;
+	} s_uspace;
 	union
 	{
-		__u32			bitmap;
-		struct inode	*table;
-	}		s_fspace;
+		struct udf_bitmap	*s_bitmap;
+		struct inode		*s_table;
+	} s_fspace;
 	__u32	s_partition_root;
 	__u32	s_partition_len;
 	__u16	s_partition_type;
@@ -77,43 +81,42 @@
 
 struct udf_sb_info
 {
-	struct udf_part_map *s_partmaps;
-	__u8  s_volident[32];
+	struct udf_part_map	*s_partmaps;
+	__u8			s_volident[32];
 
 	/* Overall info */
-	__u16 s_partitions;
-	__u16 s_partition;
+	__u16			s_partitions;
+	__u16			s_partition;
 
 	/* Sector headers */
-	__u32 s_session;
-	__u32 s_anchor[4];
-	__u32 s_lastblock;
-
-	struct buffer_head *s_lvidbh;
-
-	__u16 s_loaded_block_bitmaps;
-	__u32 s_block_bitmap_number[UDF_MAX_BLOCK_LOADED];
-	struct buffer_head *s_block_bitmap[UDF_MAX_BLOCK_LOADED];
+	__u32			s_session;
+	__u32			s_anchor[4];
+	__u32			s_lastblock;
+
+	struct buffer_head	*s_lvidbh;
 
 	/* Default permissions */
-	mode_t s_umask;
-	gid_t s_gid;
-	uid_t s_uid;
+	mode_t			s_umask;
+	gid_t			s_gid;
+	uid_t			s_uid;
 
 	/* Root Info */
-	time_t s_recordtime;
+	time_t			s_recordtime;
 
 	/* Fileset Info */
-	__u16 s_serialnum;
+	__u16			s_serialnum;
 
 	/* highest UDF revision we have recorded to this media */
-	__u16 s_udfrev;
+	__u16			s_udfrev;
 
 	/* Miscellaneous flags */
-	__u32 s_flags;
+	__u32			s_flags;
+
+	/* Encoding info */
+	struct nls_table	*s_nls_map;
 
 	/* VAT inode */
-	struct inode    *s_vat;
+	struct inode		*s_vat;
 };
 
 #endif /* !defined(_LINUX_UDF_FS_SB_H) */
diff -u --recursive --new-file v2.4.5/linux/include/linux/udf_udf.h linux/include/linux/udf_udf.h
--- v2.4.5/linux/include/linux/udf_udf.h	Mon Dec 11 13:27:05 2000
+++ linux/include/linux/udf_udf.h	Mon Jun 11 19:15:27 2001
@@ -10,7 +10,7 @@
  * CONTACTS
  *	E-mail regarding any portion of the Linux UDF file system should be
  *	directed to the development team mailing list (run by majordomo):
- *		linux_udf@hootie.lvld.hp.com
+ *		linux_udf@hpesjro.fc.hp.com
  *
  * COPYRIGHT
  *	This file is distributed under the terms of the GNU General Public
diff -u --recursive --new-file v2.4.5/linux/include/net/bluetooth/bluetooth.h linux/include/net/bluetooth/bluetooth.h
--- v2.4.5/linux/include/net/bluetooth/bluetooth.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/bluetooth/bluetooth.h	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,82 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ *  $Id: bluetooth.h,v 1.1 2001/06/01 08:12:11 davem Exp $
+ */
+
+#ifndef __IF_BLUETOOTH_H
+#define __IF_BLUETOOTH_H
+
+#include <asm/types.h>
+#include <asm/byteorder.h>
+
+#define BTPROTO_L2CAP   0
+#define BTPROTO_HCI     1
+
+#define SOL_HCI     0
+#define SOL_L2CAP   6
+
+typedef struct {
+	__u8 b0, b1, b2, b3, b4, b5;
+} bdaddr_t;
+
+#define BDADDR_ANY ((bdaddr_t *)"\000\000\000\000\000")
+
+/* Connection and socket states */
+enum {
+	BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
+	BT_OPEN,
+	BT_BOUND,
+	BT_LISTEN,
+	BT_CONNECT,
+	BT_CONFIG,
+	BT_DISCONN,
+	BT_CLOSED
+};
+
+/* Copy, swap, convert BD Address */
+static __inline__ int bacmp(bdaddr_t *ba1, bdaddr_t *ba2)
+{
+	return memcmp(ba1, ba2, sizeof(bdaddr_t));
+}
+static __inline__ void bacpy(bdaddr_t *dst, bdaddr_t *src)
+{
+	memcpy(dst, src, sizeof(bdaddr_t));
+}
+
+extern void baswap(bdaddr_t *dst, bdaddr_t *src);
+
+extern char *batostr(bdaddr_t *ba);
+extern bdaddr_t *strtoba(char *str);
+
+/* Endianness conversions */
+#define htobs(a)	__cpu_to_le16(a)
+#define htobl(a)	__cpu_to_le32(a)
+#define btohs(a)	__le16_to_cpu(a)
+#define btohl(a)	__le32_to_cpu(a)
+
+int bterr(__u16 code);
+
+#endif /* __IF_BLUETOOTH_H */
diff -u --recursive --new-file v2.4.5/linux/include/net/bluetooth/bluez.h linux/include/net/bluetooth/bluez.h
--- v2.4.5/linux/include/net/bluetooth/bluez.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/bluetooth/bluez.h	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,176 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ *  $Id: bluez.h,v 1.1 2001/06/01 08:12:11 davem Exp $
+ */
+
+#ifndef __IF_BLUEZ_H
+#define __IF_BLUEZ_H
+
+#include <net/sock.h>
+
+#define BLUEZ_VER "1.0"
+
+#define BLUEZ_MAX_PROTO 	2
+
+/* Reserv for core and drivers use */
+#define BLUEZ_SKB_RESERVE	8
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/* Debugging */
+#ifdef BLUEZ_DEBUG
+
+#define HCI_CORE_DEBUG		1
+#define HCI_SOCK_DEBUG		1
+#define HCI_UART_DEBUG		1
+#define HCI_USB_DEBUG		1
+//#define HCI_DATA_DUMP		1
+
+#define L2CAP_DEBUG			1
+
+#endif /* BLUEZ_DEBUG */
+
+extern void bluez_dump(char *pref, __u8 *buf, int count);
+
+#define INF(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg)
+#define DBG(fmt, arg...) printk(KERN_INFO __FUNCTION__ ": " fmt "\n" , ## arg)
+#define ERR(fmt, arg...) printk(KERN_ERR  __FUNCTION__ ": " fmt "\n" , ## arg)
+
+#ifdef HCI_DATA_DUMP
+#define DMP(buf, len)    bluez_dump(__FUNCTION__, buf, len)
+#else
+#define DMP(D...)
+#endif
+
+/* ----- Sockets ------ */
+struct bluez_sock_list {
+	struct sock *head;
+	rwlock_t     lock;
+};
+
+extern int  bluez_sock_register(int proto, struct net_proto_family *ops);
+extern int  bluez_sock_unregister(int proto);
+
+extern void bluez_sock_link(struct bluez_sock_list *l, struct sock *s);
+extern void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s);
+
+/* ----- SKB helpers ----- */
+struct bluez_skb_cb {
+	int    incomming, fragmented;
+	struct sk_buff_head frags;
+};
+#define bluez_cb(skb)	((struct bluez_skb_cb *)(skb->cb)) 
+
+static __inline__ struct sk_buff *bluez_skb_alloc(unsigned int len, int how)
+{
+	struct sk_buff *skb;
+
+	if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) {
+		bluez_cb(skb)->incomming  = 0;
+		bluez_cb(skb)->fragmented = 0;
+		skb_reserve(skb, BLUEZ_SKB_RESERVE);
+	}
+	return skb;
+}
+
+static __inline__ struct sk_buff *bluez_skb_clone(struct sk_buff *skb, int how)
+{
+	struct sk_buff *new;
+
+	if ((new = skb_clone(skb, how)))
+		bluez_cb(new)->fragmented = 0;
+	return new;
+}
+
+static __inline__ struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len, 
+						       int nb, int *err)
+{
+	struct sk_buff *skb;
+
+	if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) {
+		bluez_cb(skb)->incomming  = 0;
+		bluez_cb(skb)->fragmented = 0;
+		skb_reserve(skb, BLUEZ_SKB_RESERVE);
+	}
+
+	return skb;
+}
+
+static __inline__ int bluez_skb_frags(struct sk_buff *skb)
+{
+	if (bluez_cb(skb)->fragmented)
+		return skb_queue_len(&bluez_cb(skb)->frags);
+	return 0;
+}
+
+static __inline__ void bluez_skb_add_frag(struct sk_buff *skb, struct sk_buff *frag)
+{
+	if (!bluez_cb(skb)->fragmented) {
+		skb_queue_head_init(&bluez_cb(skb)->frags);
+		bluez_cb(skb)->fragmented = 1;
+	}
+	__skb_queue_tail(&bluez_cb(skb)->frags, frag);
+}
+
+static __inline__ struct sk_buff *bluez_skb_next_frag(struct sk_buff *skb)
+{
+	if (bluez_cb(skb)->fragmented)
+		return skb_peek(&bluez_cb(skb)->frags);
+	if (skb->next == (void *) skb->list)
+		return NULL;
+	return skb->next;
+}
+
+static __inline__ struct sk_buff *bluez_skb_get_frag(struct sk_buff *skb)
+{
+	if (bluez_cb(skb)->fragmented)
+		return __skb_dequeue(&bluez_cb(skb)->frags);
+	return NULL;
+}
+
+static __inline__ void bluez_skb_free(struct sk_buff *skb)
+{
+	if (bluez_cb(skb)->fragmented)
+		__skb_queue_purge(&bluez_cb(skb)->frags);
+	kfree_skb(skb);
+}
+
+static __inline__ void bluez_skb_queue_purge(struct sk_buff_head *q)
+{
+	struct sk_buff *skb;
+
+	while((skb = skb_dequeue(q)))
+		bluez_skb_free(skb);
+}
+
+extern int hci_core_init(void);
+extern int hci_core_cleanup(void);
+extern int hci_sock_init(void);
+extern int hci_sock_cleanup(void);
+
+#endif /* __IF_BLUEZ_H */
diff -u --recursive --new-file v2.4.5/linux/include/net/bluetooth/hci.h linux/include/net/bluetooth/hci.h
--- v2.4.5/linux/include/net/bluetooth/hci.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/bluetooth/hci.h	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,370 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ *  $Id: hci.h,v 1.1 2001/06/01 08:12:11 davem Exp $
+ */
+
+#ifndef __IF_HCI_H
+#define __IF_HCI_H
+
+#include <asm/byteorder.h>
+
+/* HCI Packet types */
+#define HCI_COMMAND_PKT		0x01
+#define HCI_ACLDATA_PKT 	0x02
+#define HCI_SCODATA_PKT 	0x03
+#define HCI_EVENT_PKT		0x04
+#define HCI_UNKNOWN_PKT		0xff
+
+/* -----  HCI Commands ----- */
+/* OGF & OCF values */
+
+/* Informational Parameters */
+#define OGF_INFO_PARAM	0x04
+#define OCF_NOP			0x0000
+
+#define OCF_READ_BUFFER_SIZE		0x0005
+typedef struct {
+	__u8 	status;
+	__u16 	acl_mtu;
+	__u8 	sco_mtu;
+	__u16 	acl_max_pkt;
+	__u16	sco_max_pkt;
+} __attribute__ ((packed)) 	read_buffer_size_rp;
+
+#define OCF_READ_BD_ADDR		0x0009
+typedef struct {
+	__u8 status;
+	bdaddr_t bdaddr;
+} __attribute__ ((packed))		read_bd_addr_rp;
+
+/* Host Controller and Baseband */
+#define OGF_HOST_CTL			0x03
+#define OCF_RESET				0x0003
+#define OCF_WRITE_AUTH_ENABLE	0x0020
+	#define AUTH_DISABLED			0x00
+	#define AUTH_ENABLED			0x01
+
+#define OCF_WRITE_CA_TIMEOUT  	0x0016		/* Write_Connection_Accept_Timeout */
+#define OCF_WRITE_PG_TIMEOUT  	0x0018		/* Write_Page_Timeout */
+
+#define OCF_WRITE_SCAN_ENABLE 	0x001A
+	#define SCANS_DISABLED		0x00
+	#define IS_ENA_PS_DIS		0x01    /* Inquiry scan enabled Page Scan disabled */
+	#define IS_DIS_PS_ENA		0x02    /* Inquiry scan disabled Page Scan enabled */
+	#define IS_ENA_PS_ENA		0x03    /* Inquiry scan enabled Page Scan enabled  */
+
+#define OCF_SET_EVENT_FLT	0x0005
+typedef struct {
+	__u8 	flt_type;
+	__u8 	cond_type;
+	__u8 	condition;
+} __attribute__ ((packed))		set_event_flt_cp;
+#define SET_EVENT_FLT_CP_SIZE 	3
+
+/* Filter types */
+#define FLT_CLEAR_ALL	0x00
+#define FLT_INQ_RESULT	0x01
+#define FLT_CONN_SETUP	0x02
+
+/* CONN_SETUP Condition types */
+#define CONN_SETUP_ALLOW_ALL	0x00
+#define CONN_SETUP_ALLOW_CLASS	0x01
+#define CONN_SETUP_ALLOW_BDADDR	0x02
+
+/* CONN_SETUP Conditions */
+#define CONN_SETUP_AUTO_OFF	0x01
+#define CONN_SETUP_AUTO_ON		0x02
+
+/* Link Control */
+#define OGF_LINK_CTL	0x01 
+#define OCF_CREATE_CONN	0x0005
+typedef struct {
+	bdaddr_t bdaddr;
+	__u16 	pkt_type;
+	__u8 	pscan_rep_mode;
+	__u8 	pscan_mode;
+	__u16 	clock_offset;
+	__u8 	role_switch;
+} __attribute__ ((packed))		create_conn_cp;
+#define CREATE_CONN_CP_SIZE 	13
+
+#define OCF_ACCEPT_CONN_REQ	0x0009
+typedef struct {
+	bdaddr_t bdaddr;
+	__u8 	role;
+} __attribute__ ((packed))		accept_conn_req_cp;
+#define ACCEPT_CONN_REQ_CP_SIZE 	7
+
+#define OCF_DISCONNECT	0x0006
+typedef struct {
+	__u16 	handle;
+	__u8 	reason;
+} __attribute__ ((packed))		disconnect_cp;
+#define DISCONNECT_CP_SIZE 	3
+
+#define OCF_INQUIRY		0x0001
+typedef struct {
+	__u8 	lap[3];
+	__u8 	lenght;
+	__u8	num_rsp;
+} __attribute__ ((packed))		inquiry_cp;
+#define INQUIRY_CP_SIZE 		5
+
+#define OGF_LINK_POLICY	 	0x02   /* Link Policy */
+
+/* --------- HCI Events --------- */
+#define EVT_INQUIRY_COMPLETE 	0x01
+
+#define EVT_INQUIRY_RESULT 	0x02
+typedef struct {
+	bdaddr_t	bdaddr;
+	__u8	pscan_rep_mode;
+	__u8	pscan_period_mode;
+	__u8	pscan_mode;
+	__u8	class[3];
+	__u16	clock_offset;
+} __attribute__ ((packed))		inquiry_info;
+#define INQUIRY_INFO_SIZE 	14
+
+#define EVT_CONN_COMPLETE 	0x03
+typedef struct {
+	__u8	status;
+	__u16	handle;
+	bdaddr_t	bdaddr;
+	__u8	link_type;
+	__u8	encr_mode;
+} __attribute__ ((packed))		evt_conn_complete;
+#define EVT_CONN_COMPLETE_SIZE 	13
+
+#define EVT_CONN_REQUEST	0x04
+typedef struct {
+	bdaddr_t 	bdaddr;
+#if defined 	(__LITTLE_ENDIAN_BITFIELD)
+	__u32 	class	:24;
+	__u32 	type 	:8;
+#else /*  	(__BIG_ENDIAN_BITFIELD) */
+	__u32 	type 	:8;
+	__u32 	class	:24;
+#endif
+} __attribute__ ((packed))		evt_conn_request;
+#define EVT_CONN_REQUEST_SIZE 	10
+
+#define EVT_DISCONN_COMPLETE	0x05
+typedef struct {
+	__u8 	status;
+	__u16 	handle;
+	__u8 	reason;
+} __attribute__ ((packed))		evt_disconn_complete;
+#define EVT_DISCONN_COMPLETE_SIZE 	4
+
+#define EVT_CMD_COMPLETE 	0x0e
+typedef struct {
+	__u8 	ncmd;
+	__u16 	opcode;
+} __attribute__ ((packed))		evt_cmd_complete;
+#define EVT_CMD_COMPLETE_SIZE 	3
+
+#define EVT_CMD_STATUS 		0x0f
+typedef struct {
+	__u8 	status;
+	__u8 	ncmd;
+	__u16 	opcode;
+} __attribute__ ((packed))		evt_cmd_status;
+#define EVT_CMD_STATUS_SIZE 		4
+
+#define EVT_NUM_COMP_PKTS	0x13
+typedef struct {
+	__u8 	num_hndl;
+	/* variable lenght part */
+} __attribute__ ((packed))		evt_num_comp_pkts;
+#define EVT_NUM_COMP_PKTS_SIZE 	1
+
+#define EVT_HCI_DEV_EVENT	0xfd
+typedef struct {
+	__u16 	event;
+	__u16 	param;
+} __attribute__ ((packed))		evt_hci_dev_event;
+#define EVT_HCI_DEV_EVENT_SIZE 	4
+
+/* --------  HCI Packet structures  -------- */
+#define HCI_TYPE_LEN	1
+
+typedef struct {
+	__u16 	opcode;		/* OCF & OGF */
+	__u8 	plen;
+} __attribute__ ((packed))	hci_command_hdr;
+#define HCI_COMMAND_HDR_SIZE 	3
+
+typedef struct {
+	__u8 	evt;
+	__u8 	plen;
+} __attribute__ ((packed))	hci_event_hdr;
+#define HCI_EVENT_HDR_SIZE 	2
+
+typedef struct {
+	__u16 	handle;		/* Handle & Flags(PB, BC) */
+	__u16 	dlen;
+} __attribute__ ((packed))	hci_acl_hdr;
+#define HCI_ACL_HDR_SIZE 	4
+
+typedef struct {
+	__u16 	handle;
+	__u8 	dlen;
+} __attribute__ ((packed))	hci_sco_hdr;
+#define HCI_SCO_HDR_SIZE 	3
+
+/* Command opcode pack/unpack */
+#define cmd_opcode_pack(ocf, ogf)	(__u16)((ocf & 0x03ff)|(ogf << 10))
+#define cmd_opcode_ogf(op)		(op >> 10)
+#define cmd_opcode_ocf(op)		(op & 0x03ff)
+
+/* ACL handle and flags pack/unpack */
+#define acl_handle_pack(h, f)	(__u16)((h & 0x0fff)|(f << 12))
+#define acl_handle(h)			(h & 0x0fff)
+#define acl_flags(h)			(h >> 12)
+
+/* ACL flags */
+#define ACL_CONT		0x0001
+#define ACL_START		0x0002
+#define ACL_ACTIVE_BCAST	0x0010
+#define ACL_PICO_BCAST		0x0020
+
+/* Max frame size */
+#define HCI_MAX_FRAME	4096
+
+/* HCI device types */
+#define HCI_UART 	0
+#define HCI_USB		1
+#define HCI_EMU		2
+
+/* HCI device modes */
+#define HCI_NORMAL 	0x0001
+#define HCI_RAW		0x0002
+#define HCI_MODE_MASK   (HCI_NORMAL | HCI_RAW)
+#define HCI_SOCK	0x1000
+
+/* HCI device states */
+#define HCI_INIT	0x0010
+#define HCI_UP 		0x0020
+#define HCI_RUNNING	0x0040
+
+/* HCI device flags */
+#define HCI_PSCAN	0x0100
+#define HCI_ISCAN	0x0200
+#define HCI_AUTH	0x0400
+
+/* HCI Packet types */
+#define HCI_DM1 	0x0008
+#define HCI_DM3 	0x0400
+#define HCI_DM5 	0x4000
+#define HCI_DH1 	0x0010
+#define HCI_DH3 	0x0800
+#define HCI_DH5 	0x8000
+
+/* HCI Ioctl defines */
+#define HCIDEVUP	_IOW('H', 201, int)
+#define HCIDEVDOWN	_IOW('H', 202, int)
+#define HCIDEVRESET	_IOW('H', 203, int)
+#define HCIRESETSTAT	_IOW('H', 204, int)
+#define HCIGETINFO	_IOR('H', 205, int)
+#define HCIGETDEVLIST	_IOR('H', 206, int)
+#define HCISETRAW	_IOW('H', 207, int)
+#define HCISETSCAN	_IOW('H', 208, int)
+#define HCISETAUTH	_IOW('H', 209, int)
+#define HCIINQUIRY	_IOWR('H', 210, int)
+
+/* HCI Socket options */
+#define HCI_DATA_DIR	0x0001
+#define HCI_FILTER	0x0002
+
+/* HCI CMSG types */
+#define HCI_CMSG_DIR	0x0001
+
+struct sockaddr_hci {
+	sa_family_t	    hci_family;
+	unsigned short  hci_dev;
+};
+#define HCI_DEV_NONE	0xffff
+
+struct hci_dev_req {
+	__u16 dev_id;
+	__u32 dev_opt;
+};
+
+struct hci_dev_list_req {
+	__u16  dev_num;
+	struct hci_dev_req dev_req[0];	/* hci_dev_req structures */
+};
+
+struct hci_inquiry_req {
+	__u16 dev_id;
+	__u16 flags;
+	__u8  lap[3];
+	__u8  length;
+	__u8  num_rsp;
+};
+#define IREQ_CACHE_FLUSH 0x0001
+
+struct hci_dev_stats {
+	__u32 err_rx;
+	__u32 err_tx;
+	__u32 cmd_tx;
+	__u32 evt_rx;
+	__u32 acl_tx;
+	__u32 acl_rx;
+	__u32 sco_tx;
+	__u32 sco_rx;
+	__u32 byte_rx;
+	__u32 byte_tx;
+};
+
+struct hci_dev_info {
+	__u16 dev_id;
+	char  name[8];
+
+	__u32 flags;
+	__u8  type;
+
+	__u16 acl_mtu;
+	__u16 acl_max;
+	__u16 sco_mtu;
+	__u16 sco_max;
+
+	bdaddr_t bdaddr;
+
+	struct hci_dev_stats stat;
+};
+
+/* Number of devices */
+#define HCI_MAX_DEV 	8
+
+/* HCI dev events */
+#define HCI_DEV_REG	1
+#define HCI_DEV_UNREG   2
+#define HCI_DEV_UP	3
+#define HCI_DEV_DOWN	4
+
+#endif /* __IF_HCI_H */
diff -u --recursive --new-file v2.4.5/linux/include/net/bluetooth/hci_core.h linux/include/net/bluetooth/hci_core.h
--- v2.4.5/linux/include/net/bluetooth/hci_core.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/bluetooth/hci_core.h	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,343 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/* 
+ * $Id: hci_core.h,v 1.1 2001/06/01 08:12:11 davem Exp $ 
+ */
+
+#ifndef __IF_HCI_CORE_H
+#define __IF_HCI_CORE_H
+
+#include "hci.h"
+
+/* HCI upper protocols */
+#define HCI_MAX_PROTO 	1
+#define HCI_PROTO_L2CAP	0
+
+#define HCI_INIT_TIMEOUT (HZ * 10)
+
+/* ----- Inquiry cache ----- */
+#define INQUIRY_CACHE_AGE_MAX   (HZ*5)    // 5 seconds
+#define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   // 60 seconds
+
+struct inquiry_entry {
+	struct inquiry_entry 	*next;
+	__u32			timestamp;
+	inquiry_info		info;
+};
+
+struct inquiry_cache {
+	spinlock_t 		lock;
+	__u32			timestamp;
+	struct inquiry_entry 	*list;
+};
+
+static __inline__ void inquiry_cache_init(struct inquiry_cache *cache)
+{
+	spin_lock_init(&cache->lock);
+	cache->list = NULL;
+}
+
+static __inline__ void inquiry_cache_lock(struct inquiry_cache *cache)
+{
+	spin_lock(&cache->lock);
+}
+
+static __inline__ void inquiry_cache_unlock(struct inquiry_cache *cache)
+{
+	spin_unlock(&cache->lock);
+}
+
+static __inline__ void inquiry_cache_lock_bh(struct inquiry_cache *cache)
+{
+	spin_lock_bh(&cache->lock);
+}
+
+static __inline__ void inquiry_cache_unlock_bh(struct inquiry_cache *cache)
+{
+	spin_unlock_bh(&cache->lock);
+}
+
+static __inline__ long inquiry_cache_age(struct inquiry_cache *cache)
+{
+	return jiffies - cache->timestamp;
+}
+
+static __inline__ long inquiry_entry_age(struct inquiry_entry *e)
+{
+	return jiffies - e->timestamp;
+}
+extern void inquiry_cache_flush(struct inquiry_cache *cache);
+
+/* ----- Connection hash ----- */
+#define HCI_MAX_CONN 	10
+
+/* FIXME:
+ * We assume that handle is a number - 0 ... HCI_MAX_CONN.
+ */
+struct conn_hash {
+	spinlock_t 	lock;
+	unsigned int	num;
+	void 		*conn[HCI_MAX_CONN];
+};
+
+static __inline__ void conn_hash_init(struct conn_hash *h)
+{
+	memset(h, 0, sizeof(struct conn_hash));
+	spin_lock_init(&h->lock);
+}
+
+static __inline__ void conn_hash_lock(struct conn_hash *h)
+{
+	spin_lock(&h->lock);
+}
+
+static __inline__ void conn_hash_unlock(struct conn_hash *h)
+{
+	spin_unlock(&h->lock);
+}
+
+static __inline__ void *__conn_hash_add(struct conn_hash *h, __u16 handle, void *conn)
+{
+	if (!h->conn[handle]) {
+		h->conn[handle] = conn;
+		h->num++;
+		return conn;
+	} else
+		return NULL;
+}
+
+static __inline__ void *conn_hash_add(struct conn_hash *h, __u16 handle, void *conn)
+{
+	if (handle >= HCI_MAX_CONN)
+		return NULL;
+
+	conn_hash_lock(h);
+	conn = __conn_hash_add(h, handle, conn);
+	conn_hash_unlock(h);
+
+	return conn;
+}
+
+static __inline__ void *__conn_hash_del(struct conn_hash *h, __u16 handle)
+{
+	void *conn = h->conn[handle];
+
+	if (conn) {
+		h->conn[handle] = NULL;
+		h->num--;
+		return conn;
+	} else
+		return NULL;
+}
+
+static __inline__ void *conn_hash_del(struct conn_hash *h, __u16 handle)
+{
+	void *conn;
+
+	if (handle >= HCI_MAX_CONN)
+		return NULL;
+	conn_hash_lock(h);
+	conn = __conn_hash_del(h, handle); 
+	conn_hash_unlock(h);
+
+	return conn;
+}
+
+static __inline__ void *__conn_hash_lookup(struct conn_hash *h, __u16 handle)
+{
+	return h->conn[handle];
+}
+
+static __inline__ void *conn_hash_lookup(struct conn_hash *h, __u16 handle)
+{
+	void *conn;
+
+	if (handle >= HCI_MAX_CONN)
+		return NULL;
+
+	conn_hash_lock(h);
+	conn = __conn_hash_lookup(h, handle);
+	conn_hash_unlock(h);
+
+	return conn;
+}
+
+struct hci_dev;
+
+/* ----- HCI Connections ----- */
+struct hci_conn {
+	bdaddr_t	dst;
+	__u16		handle;
+
+	unsigned int 	acl_sent;
+	unsigned int 	sco_sent;
+
+	struct hci_dev 	*hdev;
+	void		*l2cap_data;
+	void		*priv;
+
+	struct sk_buff_head	acl_q;
+	struct sk_buff_head	sco_q;
+};
+
+/* ----- HCI Devices ----- */
+struct hci_dev {
+	atomic_t 	refcnt;
+
+	char		name[8];
+	__u32	 	flags;
+	__u16		id;
+	__u8	 	type;
+	bdaddr_t	bdaddr;
+
+	atomic_t 	cmd_cnt;
+	unsigned int 	acl_cnt;
+	unsigned int 	sco_cnt;
+
+	unsigned int	acl_mtu;
+	unsigned int 	sco_mtu;
+	unsigned int	acl_max;
+	unsigned int	sco_max;
+
+	void		*driver_data;
+	void		*l2cap_data;
+	void		*priv;
+
+	struct tasklet_struct 	cmd_task;
+	struct tasklet_struct	rx_task;
+	struct tasklet_struct 	tx_task;
+
+	struct sk_buff_head	rx_q;
+	struct sk_buff_head 	raw_q;
+	struct sk_buff_head 	cmd_q;
+	struct sk_buff     	*cmd_sent;
+
+	struct semaphore	req_lock;
+	wait_queue_head_t	req_wait_q;
+	__u32			req_status;
+	__u32			req_result;
+
+	struct inquiry_cache 	inq_cache;
+
+	struct conn_hash 	conn_hash;
+
+	struct hci_dev_stats 	stat;
+
+	int (*open)(struct hci_dev *hdev);
+	int (*close)(struct hci_dev *hdev);
+	int (*flush)(struct hci_dev *hdev);
+	int (*send)(struct sk_buff *skb);
+};
+
+static __inline__ void hci_dev_hold(struct hci_dev *hdev)
+{
+	atomic_inc(&hdev->refcnt);
+}
+
+static __inline__ void hci_dev_put(struct hci_dev *hdev)
+{
+	atomic_dec(&hdev->refcnt);
+}
+
+extern struct hci_dev *hci_dev_get(int index);
+
+#define SENT_CMD_PARAM(X)	(((X->cmd_sent->data) + HCI_COMMAND_HDR_SIZE))
+
+extern int hci_register_dev(struct hci_dev *hdev);
+extern int hci_unregister_dev(struct hci_dev *hdev);
+extern int hci_dev_open(__u16 dev);
+extern int hci_dev_close(__u16 dev);
+extern int hci_dev_reset(__u16 dev);
+extern int hci_dev_reset_stat(__u16 dev);
+extern int hci_dev_info(unsigned long arg);
+extern int hci_dev_list(unsigned long arg);
+extern int hci_dev_setscan(unsigned long arg);
+extern int hci_dev_setauth(unsigned long arg);
+extern int hci_inquiry(unsigned long arg);
+
+extern __u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode);
+extern __u32 hci_dev_getmode(struct hci_dev *hdev);
+
+extern int hci_recv_frame(struct sk_buff *skb);
+
+/* ----- HCI tasks ----- */
+static __inline__ void hci_sched_cmd(struct hci_dev *hdev)
+{
+	tasklet_schedule(&hdev->cmd_task);
+}
+
+static __inline__ void hci_sched_rx(struct hci_dev *hdev)
+{
+	tasklet_schedule(&hdev->rx_task);
+}
+
+static __inline__ void hci_sched_tx(struct hci_dev *hdev)
+{
+	tasklet_schedule(&hdev->tx_task);
+}
+
+/* ----- HCI protocols ----- */
+struct hci_proto {
+	char 		*name;
+	__u32		id;
+	__u32		flags;
+
+	void		*priv;
+
+	int (*connect_ind) 	(struct hci_dev *hdev, bdaddr_t *bdaddr);
+	int (*connect_cfm)	(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *conn);
+	int (*disconn_ind)	(struct hci_conn *conn, __u8 reason);
+	int (*recv_acldata)	(struct hci_conn *conn, struct sk_buff *skb , __u16 flags);
+	int (*recv_scodata)	(struct hci_conn *conn, struct sk_buff *skb);
+};
+
+extern int hci_register_proto(struct hci_proto *hproto);
+extern int hci_unregister_proto(struct hci_proto *hproto);
+extern int hci_register_notifier(struct notifier_block *nb);
+extern int hci_unregister_notifier(struct notifier_block *nb);
+extern int hci_connect(struct hci_dev * hdev, bdaddr_t * bdaddr);
+extern int hci_disconnect(struct hci_conn *conn, __u8 reason);
+extern int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void * param);
+extern int hci_send_raw(struct sk_buff *skb);
+extern int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
+extern int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
+
+/* ----- HCI Sockets ----- */
+extern void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
+
+/* HCI info for socket */
+#define hci_pi(sk)	((struct hci_pinfo *) &sk->protinfo)
+struct hci_pinfo {
+	struct hci_dev 	*hdev;
+	__u32 	   	cmsg_flags;
+	__u32 	   	mask;
+};
+
+/* ----- HCI requests ----- */
+#define HCI_REQ_DONE	  0
+#define HCI_REQ_PEND	  1
+#define HCI_REQ_CANCELED  2
+
+#endif /* __IF_HCI_CORE_H */
diff -u --recursive --new-file v2.4.5/linux/include/net/bluetooth/hci_emu.h linux/include/net/bluetooth/hci_emu.h
--- v2.4.5/linux/include/net/bluetooth/hci_emu.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/bluetooth/hci_emu.h	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,52 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * $Id: hci_emu.h,v 1.1 2001/06/01 08:12:11 davem Exp $
+ */
+
+#ifndef __IF_HCI_EMU_H
+#define __IF_HCI_EMU_H
+
+#ifdef __KERNEL__
+
+struct hci_emu_struct {
+	struct hci_dev       hdev;
+	__u32                flags;
+	wait_queue_head_t    read_wait;
+	struct sk_buff_head  readq;
+	struct fasync_struct *fasync;
+};
+
+#endif /* __KERNEL__ */
+
+#define HCI_EMU_MINOR		250
+
+/* Max frame size */
+#define HCI_EMU_MAX_FRAME	4096
+
+/* HCI_EMU device flags */
+#define HCI_EMU_FASYNC		0x0010
+
+#endif /* __IF_HCI_EMU_H */
diff -u --recursive --new-file v2.4.5/linux/include/net/bluetooth/hci_uart.h linux/include/net/bluetooth/hci_uart.h
--- v2.4.5/linux/include/net/bluetooth/hci_uart.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/bluetooth/hci_uart.h	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,60 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * $Id: hci_uart.h,v 1.1 2001/06/01 08:12:11 davem Exp $
+ */
+
+#define HCI_MAX_READ 2048
+
+#ifdef __KERNEL__
+
+#define tty2n_hci(tty)  ((struct n_hci *)((tty)->disc_data))
+#define n_hci2tty(n_hci) ((n_hci)->tty)
+
+struct n_hci {
+	struct tty_struct *tty;
+	struct hci_dev hdev;
+
+	struct sk_buff_head txq;
+	unsigned long tx_state;
+
+	spinlock_t rx_lock;
+	unsigned long rx_state;
+	unsigned long rx_count;
+	struct sk_buff *rx_skb;
+};
+
+/* Transmit states  */
+#define TRANS_SENDING		1
+#define TRANS_WAKEUP		2
+
+/* Receiver States */
+#define WAIT_PACKET_TYPE	0
+#define WAIT_EVENT_HDR	 	1
+#define WAIT_ACL_HDR		2
+#define WAIT_SCO_HDR		3
+#define WAIT_DATA	        4
+
+#endif /* __KERNEL__ */
diff -u --recursive --new-file v2.4.5/linux/include/net/bluetooth/hci_usb.h linux/include/net/bluetooth/hci_usb.h
--- v2.4.5/linux/include/net/bluetooth/hci_usb.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/bluetooth/hci_usb.h	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,70 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * $Id: hci_usb.h,v 1.1 2001/06/01 08:12:11 davem Exp $
+ */
+
+#ifdef __KERNEL__
+
+#define HCI_USB_MAX_READ     2048
+
+/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
+#define HCI_DEV_CLASS        0xe0	/* Wireless class */
+#define HCI_DEV_SUBCLASS     0x01	/* RF subclass */
+#define HCI_DEV_PROTOCOL     0x01	/* Bluetooth programming protocol */
+
+#define HCI_CTRL_REQ	     0x20
+
+struct hci_usb {
+	struct usb_device 	*udev;
+
+	devrequest		dev_req;
+	struct urb 		*ctrl_urb;
+	struct urb		*intr_urb;
+	struct urb		*read_urb;
+	struct urb		*write_urb;
+
+	__u8			*read_buf;
+	__u8			*intr_buf;
+	struct sk_buff		*intr_skb;
+	int			intr_count;
+
+	__u8			bulk_out_ep_addr;
+	__u8			bulk_in_ep_addr;
+	__u8			intr_in_ep_addr;
+	__u8			intr_in_interval;
+
+	struct hci_dev		hdev;
+
+	unsigned long		tx_state;
+	struct sk_buff_head	tx_ctrl_q;
+	struct sk_buff_head	tx_write_q;
+};
+
+/* Transmit states  */
+#define HCI_TX_CTRL	1
+#define HCI_TX_WRITE	2
+
+#endif /* __KERNEL__ */
diff -u --recursive --new-file v2.4.5/linux/include/net/bluetooth/l2cap.h linux/include/net/bluetooth/l2cap.h
--- v2.4.5/linux/include/net/bluetooth/l2cap.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/bluetooth/l2cap.h	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,155 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ *  $Id: l2cap.h,v 1.1 2001/06/01 08:12:11 davem Exp $
+ */
+
+#ifndef __L2CAP_H
+#define __L2CAP_H
+
+#include <asm/types.h>
+#include <asm/byteorder.h>
+
+/* L2CAP socket address */
+struct sockaddr_l2 {
+	sa_family_t	l2_family;
+	unsigned short	l2_psm;
+	bdaddr_t	l2_bdaddr;
+};
+
+/* set/get sockopt defines */
+#define L2CAP_OPTIONS  0x01
+struct l2cap_options {
+	__u16 omtu;
+	__u16 imtu;
+	__u16 flush_to;
+	__u32 token_rate;
+	__u32 bucket_size;
+	__u32 pick_band;
+	__u32 latency;
+	__u32 delay_var;
+};
+
+/* L2CAP defaults */
+#define L2CAP_DEFAULT_MTU 	672
+#define L2CAP_DEFAULT_FLUSH_TO	0xFFFF
+
+#define L2CAP_CONN_TIMEOUT 	(HZ * 40)
+
+/* L2CAP command codes */
+#define L2CAP_COMMAND_REJ 0x01
+#define L2CAP_CONN_REQ    0x02
+#define L2CAP_CONN_RSP    0x03
+#define L2CAP_CONF_REQ    0x04
+#define L2CAP_CONF_RSP    0x05
+#define L2CAP_DISCONN_REQ 0x06
+#define L2CAP_DISCONN_RSP 0x07
+#define L2CAP_ECHO_REQ    0x08
+#define L2CAP_ECHO_RSP    0x09
+#define L2CAP_INFO_REQ    0x0a
+#define L2CAP_INFO_RSP    0x0b
+
+/* L2CAP structures */
+
+typedef struct {
+	__u16      len;
+	__u16      cid;
+} __attribute__ ((packed)) 	l2cap_hdr;
+#define L2CAP_HDR_SIZE		4
+
+typedef struct {
+	__u8       code;
+	__u8       ident;
+	__u16      len;
+} __attribute__ ((packed))	l2cap_cmd_hdr;
+#define L2CAP_CMD_HDR_SIZE	4
+
+typedef struct {
+	__u16      reason;
+} __attribute__ ((packed))	l2cap_cmd_rej;
+#define L2CAP_CMD_REJ_SIZE	2
+
+typedef struct {
+	__u16      psm;
+	__u16      scid;
+} __attribute__ ((packed))	l2cap_conn_req;
+#define L2CAP_CONN_REQ_SIZE	4
+
+typedef struct {
+	__u16      dcid;
+	__u16      scid;
+	__u16      result;
+	__u16      status;
+} __attribute__ ((packed))	l2cap_conn_rsp;
+#define L2CAP_CONN_RSP_SIZE	8
+
+#define L2CAP_CONN_SUCCESS    0x0000
+#define L2CAP_CONN_PEND       0x0001
+#define L2CAP_CONN_BAD_PSM    0x0002
+#define L2CAP_CONN_SEC_BLOCK  0x0003
+#define L2CAP_CONN_NO_MEM     0x0004
+
+typedef struct {
+	__u16      dcid;
+	__u16      flags;
+	__u8       data[0];
+} __attribute__ ((packed))	l2cap_conf_req;
+#define L2CAP_CONF_REQ_SIZE	4
+
+typedef struct {
+	__u16      scid;
+	__u16      flags;
+	__u16      result;
+	__u8       data[0];
+} __attribute__ ((packed))	l2cap_conf_rsp;
+#define L2CAP_CONF_RSP_SIZE   	6
+
+#define L2CAP_CONF_SUCCESS	0x00
+#define L2CAP_CONF_UNACCEPT	0x01
+
+typedef struct {
+	__u8       type;
+	__u8       len;
+	__u8       val[0];
+} __attribute__ ((packed))	l2cap_conf_opt;
+#define L2CAP_CONF_OPT_SIZE	2
+
+#define L2CAP_CONF_MTU		0x01
+#define L2CAP_CONF_FLUSH_TO	0x02
+#define L2CAP_CONF_QOS		0x03
+
+typedef struct {
+	__u16      dcid;
+	__u16      scid;
+} __attribute__ ((packed)) 	l2cap_disconn_req;
+#define L2CAP_DISCONN_REQ_SIZE	4
+
+typedef struct {
+	__u16      dcid;
+	__u16      scid;
+} __attribute__ ((packed)) 	l2cap_disconn_rsp;
+#define L2CAP_DISCONN_RSP_SIZE	4
+
+#endif /* __L2CAP_H */
diff -u --recursive --new-file v2.4.5/linux/include/net/bluetooth/l2cap_core.h linux/include/net/bluetooth/l2cap_core.h
--- v2.4.5/linux/include/net/bluetooth/l2cap_core.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/bluetooth/l2cap_core.h	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,142 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ *  $Id: l2cap_core.h,v 1.1 2001/06/01 08:12:11 davem Exp $
+ */
+
+#ifndef __L2CAP_CORE_H
+#define __L2CAP_CORE_H
+
+#ifdef __KERNEL__
+
+/* ----- L2CAP interface ----- */
+struct l2cap_iff {
+	struct list_head list;
+	struct hci_dev   *hdev;
+	bdaddr_t         *bdaddr;
+	__u16            mtu;
+	spinlock_t       lock;
+	struct list_head conn_list;
+};
+
+static __inline__ void l2cap_iff_lock(struct l2cap_iff *iff)
+{
+	spin_lock(&iff->lock);
+}
+
+static __inline__ void l2cap_iff_unlock(struct l2cap_iff *iff)
+{
+	spin_unlock(&iff->lock);
+}
+
+/* ----- L2CAP connections ----- */
+struct l2cap_chan_list {
+	struct sock	*head;
+	rwlock_t	lock;
+	long		num;
+};
+
+struct l2cap_conn {
+	struct l2cap_iff *iff;
+	struct list_head list;
+
+	struct hci_conn	 *hconn;
+
+	__u16		state;
+	__u8		out;
+	bdaddr_t	src;
+	bdaddr_t	dst;
+
+	spinlock_t	lock;
+	atomic_t	refcnt;
+
+	struct sk_buff *rx_skb;
+	__u32		rx_len;
+	__u8		rx_ident;
+	__u8		tx_ident;
+
+	struct l2cap_chan_list chan_list;
+};
+
+static __inline__ void __l2cap_conn_link(struct l2cap_iff *iff, struct l2cap_conn *c)
+{
+	list_add(&c->list, &iff->conn_list);
+}
+
+static __inline__ void __l2cap_conn_unlink(struct l2cap_iff *iff, struct l2cap_conn *c)
+{
+	list_del(&c->list);
+}
+
+/* ----- L2CAP channel and socket info ----- */
+#define l2cap_pi(sk)   ((struct l2cap_pinfo *) &sk->protinfo)
+
+struct l2cap_accept_q {
+	struct sock 	*head;
+	struct sock 	*tail;
+};
+
+struct l2cap_pinfo {
+	bdaddr_t	src;
+	bdaddr_t	dst;
+	__u16		psm;
+	__u16		dcid;
+	__u16		scid;
+	__u32		flags;
+
+	__u16		imtu;
+	__u16		omtu;
+	__u16		flush_to;
+
+	__u8		conf_state;
+	__u16		conf_mtu;
+
+	__u8		ident;
+
+	struct l2cap_conn 	*conn;
+	struct sock 		*next_c;
+	struct sock 		*prev_c;
+
+	struct sock *parent;
+	struct sock *next_q;
+	struct sock *prev_q;
+
+	struct l2cap_accept_q accept_q;
+};
+
+#define CONF_INPUT  0x01
+#define CONF_OUTPUT 0x02
+#define CONF_DONE	(CONF_INPUT | CONF_OUTPUT)
+
+extern struct bluez_sock_list l2cap_sk_list;
+extern struct list_head  l2cap_iff_list;
+extern rwlock_t l2cap_rt_lock;
+
+extern void l2cap_register_proc(void);
+extern void l2cap_unregister_proc(void);
+
+#endif /* __KERNEL__ */
+
+#endif /* __L2CAP_CORE_H */
diff -u --recursive --new-file v2.4.5/linux/include/net/irda/irdacall.h linux/include/net/irda/irdacall.h
--- v2.4.5/linux/include/net/irda/irdacall.h	Thu Dec 17 09:01:03 1998
+++ linux/include/net/irda/irdacall.h	Wed Dec 31 16:00:00 1969
@@ -1,2 +0,0 @@
-/* Separate to keep compilation of protocols.c simpler */
-extern void irda_proto_init(struct net_proto *pro);
diff -u --recursive --new-file v2.4.5/linux/init/main.c linux/init/main.c
--- v2.4.5/linux/init/main.c	Tue May 22 09:35:42 2001
+++ linux/init/main.c	Wed Jun 20 11:10:27 2001
@@ -62,7 +62,8 @@
 #endif
 
 #ifdef CONFIG_IRDA
-#include <net/irda/irda_device.h>
+extern int irda_proto_init(void);
+extern int irda_device_init(void);
 #endif
 
 #ifdef CONFIG_X86_IO_APIC
diff -u --recursive --new-file v2.4.5/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.4.5/linux/kernel/ksyms.c	Thu May 24 15:20:18 2001
+++ linux/kernel/ksyms.c	Mon Jun 11 19:15:27 2001
@@ -90,17 +90,13 @@
 EXPORT_SYMBOL(exit_sighand);
 
 /* internal kernel memory management */
+EXPORT_SYMBOL(_alloc_pages);
 EXPORT_SYMBOL(__alloc_pages);
 EXPORT_SYMBOL(alloc_pages_node);
 EXPORT_SYMBOL(__get_free_pages);
 EXPORT_SYMBOL(get_zeroed_page);
 EXPORT_SYMBOL(__free_pages);
 EXPORT_SYMBOL(free_pages);
-#ifndef CONFIG_DISCONTIGMEM
-EXPORT_SYMBOL(contig_page_data);
-#else
-EXPORT_SYMBOL(alloc_pages);
-#endif
 EXPORT_SYMBOL(num_physpages);
 EXPORT_SYMBOL(kmem_find_general_cachep);
 EXPORT_SYMBOL(kmem_cache_create);
@@ -144,6 +140,7 @@
 EXPORT_SYMBOL(force_delete);
 EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(follow_down);
+EXPORT_SYMBOL(lookup_mnt);
 EXPORT_SYMBOL(path_init);
 EXPORT_SYMBOL(path_walk);
 EXPORT_SYMBOL(path_release);
@@ -539,6 +536,9 @@
 EXPORT_SYMBOL(tasklet_init);
 EXPORT_SYMBOL(tasklet_kill);
 EXPORT_SYMBOL(__run_task_queue);
+EXPORT_SYMBOL(do_softirq);
+EXPORT_SYMBOL(tasklet_schedule);
+EXPORT_SYMBOL(tasklet_hi_schedule);
 
 /* init task, for moving kthread roots - ought to export a function ?? */
 
diff -u --recursive --new-file v2.4.5/linux/kernel/sched.c linux/kernel/sched.c
--- v2.4.5/linux/kernel/sched.c	Fri Apr 20 18:26:16 2001
+++ linux/kernel/sched.c	Mon Jun 11 19:15:27 2001
@@ -544,7 +544,7 @@
 	release_kernel_lock(prev, this_cpu);
 
 	/* Do "administrative" work here while we don't hold any locks */
-	if (softirq_active(this_cpu) & softirq_mask(this_cpu))
+	if (softirq_pending(this_cpu))
 		goto handle_softirq;
 handle_softirq_back:
 
diff -u --recursive --new-file v2.4.5/linux/kernel/softirq.c linux/kernel/softirq.c
--- v2.4.5/linux/kernel/softirq.c	Fri Dec 29 14:07:24 2000
+++ linux/kernel/softirq.c	Mon Jun 11 19:15:27 2001
@@ -50,70 +50,50 @@
 asmlinkage void do_softirq()
 {
 	int cpu = smp_processor_id();
-	__u32 active, mask;
+	__u32 pending;
 
 	if (in_interrupt())
 		return;
 
-	local_bh_disable();
-
 	local_irq_disable();
-	mask = softirq_mask(cpu);
-	active = softirq_active(cpu) & mask;
 
-	if (active) {
+	pending = softirq_pending(cpu);
+
+	if (pending) {
 		struct softirq_action *h;
 
+		local_bh_disable();
 restart:
-		/* Reset active bitmask before enabling irqs */
-		softirq_active(cpu) &= ~active;
+		/* Reset the pending bitmask before enabling irqs */
+		softirq_pending(cpu) = 0;
 
 		local_irq_enable();
 
 		h = softirq_vec;
-		mask &= ~active;
 
 		do {
-			if (active & 1)
+			if (pending & 1)
 				h->action(h);
 			h++;
-			active >>= 1;
-		} while (active);
+			pending >>= 1;
+		} while (pending);
 
 		local_irq_disable();
 
-		active = softirq_active(cpu);
-		if ((active &= mask) != 0)
-			goto retry;
+		pending = softirq_pending(cpu);
+		if (pending)
+			goto restart;
+		__local_bh_enable();
 	}
 
-	local_bh_enable();
-
-	/* Leave with locally disabled hard irqs. It is critical to close
-	 * window for infinite recursion, while we help local bh count,
-	 * it protected us. Now we are defenceless.
-	 */
-	return;
-
-retry:
-	goto restart;
+	local_irq_enable();
 }
 
 
-static spinlock_t softirq_mask_lock = SPIN_LOCK_UNLOCKED;
-
 void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
 {
-	unsigned long flags;
-	int i;
-
-	spin_lock_irqsave(&softirq_mask_lock, flags);
 	softirq_vec[nr].data = data;
 	softirq_vec[nr].action = action;
-
-	for (i=0; i<NR_CPUS; i++)
-		softirq_mask(i) |= (1<<nr);
-	spin_unlock_irqrestore(&softirq_mask_lock, flags);
 }
 
 
@@ -121,6 +101,45 @@
 
 struct tasklet_head tasklet_vec[NR_CPUS] __cacheline_aligned;
 
+void tasklet_schedule(struct tasklet_struct *t)
+{
+	unsigned long flags;
+	int cpu;
+
+	cpu = smp_processor_id();
+	local_irq_save(flags);
+	/*
+	 * If nobody is running it then add it to this CPU's
+	 * tasklet queue.
+	 */
+	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state) &&
+						tasklet_trylock(t)) {
+		t->next = tasklet_vec[cpu].list;
+		tasklet_vec[cpu].list = t;
+		__cpu_raise_softirq(cpu, TASKLET_SOFTIRQ);
+		tasklet_unlock(t);
+	}
+	local_irq_restore(flags);
+}
+
+void tasklet_hi_schedule(struct tasklet_struct *t)
+{
+	unsigned long flags;
+	int cpu;
+
+	cpu = smp_processor_id();
+	local_irq_save(flags);
+
+	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state) &&
+						tasklet_trylock(t)) {
+		t->next = tasklet_hi_vec[cpu].list;
+		tasklet_hi_vec[cpu].list = t;
+		__cpu_raise_softirq(cpu, HI_SOFTIRQ);
+		tasklet_unlock(t);
+	}
+	local_irq_restore(flags);
+}
+
 static void tasklet_action(struct softirq_action *a)
 {
 	int cpu = smp_processor_id();
@@ -129,37 +148,37 @@
 	local_irq_disable();
 	list = tasklet_vec[cpu].list;
 	tasklet_vec[cpu].list = NULL;
-	local_irq_enable();
 
-	while (list != NULL) {
+	while (list) {
 		struct tasklet_struct *t = list;
 
 		list = list->next;
 
-		if (tasklet_trylock(t)) {
-			if (atomic_read(&t->count) == 0) {
-				clear_bit(TASKLET_STATE_SCHED, &t->state);
-
-				t->func(t->data);
-				/*
-				 * talklet_trylock() uses test_and_set_bit that imply
-				 * an mb when it returns zero, thus we need the explicit
-				 * mb only here: while closing the critical section.
-				 */
-#ifdef CONFIG_SMP
-				smp_mb__before_clear_bit();
-#endif
-				tasklet_unlock(t);
-				continue;
-			}
-			tasklet_unlock(t);
+		/*
+		 * A tasklet is only added to the queue while it's
+		 * locked, so no other CPU can have this tasklet
+		 * pending:
+		 */
+		if (!tasklet_trylock(t))
+			BUG();
+repeat:
+		if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
+			BUG();
+		if (!atomic_read(&t->count)) {
+			local_irq_enable();
+			t->func(t->data);
+			local_irq_disable();
+			/*
+			 * One more run if the tasklet got reactivated:
+			 */
+			if (test_bit(TASKLET_STATE_SCHED, &t->state))
+				goto repeat;
 		}
-		local_irq_disable();
-		t->next = tasklet_vec[cpu].list;
-		tasklet_vec[cpu].list = t;
-		__cpu_raise_softirq(cpu, TASKLET_SOFTIRQ);
-		local_irq_enable();
+		tasklet_unlock(t);
+		if (test_bit(TASKLET_STATE_SCHED, &t->state))
+			tasklet_schedule(t);
 	}
+	local_irq_enable();
 }
 
 
@@ -174,39 +193,40 @@
 	local_irq_disable();
 	list = tasklet_hi_vec[cpu].list;
 	tasklet_hi_vec[cpu].list = NULL;
-	local_irq_enable();
 
-	while (list != NULL) {
+	while (list) {
 		struct tasklet_struct *t = list;
 
 		list = list->next;
 
-		if (tasklet_trylock(t)) {
-			if (atomic_read(&t->count) == 0) {
-				clear_bit(TASKLET_STATE_SCHED, &t->state);
-
-				t->func(t->data);
-				tasklet_unlock(t);
-				continue;
-			}
-			tasklet_unlock(t);
+		if (!tasklet_trylock(t))
+			BUG();
+repeat:
+		if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
+			BUG();
+		if (!atomic_read(&t->count)) {
+			local_irq_enable();
+			t->func(t->data);
+			local_irq_disable();
+			if (test_bit(TASKLET_STATE_SCHED, &t->state))
+				goto repeat;
 		}
-		local_irq_disable();
-		t->next = tasklet_hi_vec[cpu].list;
-		tasklet_hi_vec[cpu].list = t;
-		__cpu_raise_softirq(cpu, HI_SOFTIRQ);
-		local_irq_enable();
+		tasklet_unlock(t);
+		if (test_bit(TASKLET_STATE_SCHED, &t->state))
+			tasklet_hi_schedule(t);
 	}
+	local_irq_enable();
 }
 
 
 void tasklet_init(struct tasklet_struct *t,
 		  void (*func)(unsigned long), unsigned long data)
 {
-	t->func = func;
-	t->data = data;
+	t->next = NULL;
 	t->state = 0;
 	atomic_set(&t->count, 0);
+	t->func = func;
+	t->data = data;
 }
 
 void tasklet_kill(struct tasklet_struct *t)
diff -u --recursive --new-file v2.4.5/linux/kernel/timer.c linux/kernel/timer.c
--- v2.4.5/linux/kernel/timer.c	Sun Dec 10 09:53:19 2000
+++ linux/kernel/timer.c	Tue Jun 12 16:40:11 2001
@@ -32,7 +32,7 @@
 long tick = (1000000 + HZ/2) / HZ;	/* timer interrupt period */
 
 /* The current time */
-volatile struct timeval xtime __attribute__ ((aligned (16)));
+struct timeval xtime __attribute__ ((aligned (16)));
 
 /* Don't completely fail for HZ > 500.  */
 int tickadj = 500/HZ ? : 1;		/* microsecs */
diff -u --recursive --new-file v2.4.5/linux/lib/brlock.c linux/lib/brlock.c
--- v2.4.5/linux/lib/brlock.c	Mon Apr 24 13:59:56 2000
+++ linux/lib/brlock.c	Mon Jun 11 19:15:27 2001
@@ -25,7 +25,7 @@
 	int i;
 
 	for (i = 0; i < smp_num_cpus; i++)
-		write_lock(__brlock_array[idx] + cpu_logical_map(i));
+		write_lock(&__brlock_array[cpu_logical_map(i)][idx]);
 }
 
 void __br_write_unlock (enum brlock_indices idx)
@@ -33,7 +33,7 @@
 	int i;
 
 	for (i = 0; i < smp_num_cpus; i++)
-		write_unlock(__brlock_array[idx] + cpu_logical_map(i));
+		write_unlock(&__brlock_array[cpu_logical_map(i)][idx]);
 }
 
 #else /* ! __BRLOCK_USE_ATOMICS */
diff -u --recursive --new-file v2.4.5/linux/mm/filemap.c linux/mm/filemap.c
--- v2.4.5/linux/mm/filemap.c	Tue May 22 10:52:35 2001
+++ linux/mm/filemap.c	Tue Jun 12 11:16:41 2001
@@ -230,17 +230,17 @@
 		unsigned long offset;
 
 		page = list_entry(curr, struct page, list);
-		curr = curr->next;
 		offset = page->index;
 
 		/* Is one of the pages to truncate? */
 		if ((offset >= start) || (*partial && (offset + 1) == start)) {
+			list_del(head);
+			list_add(head, curr);
 			if (TryLockPage(page)) {
 				page_cache_get(page);
 				spin_unlock(&pagecache_lock);
 				wait_on_page(page);
-				page_cache_release(page);
-				return 1;
+				goto out_restart;
 			}
 			page_cache_get(page);
 			spin_unlock(&pagecache_lock);
@@ -252,11 +252,15 @@
 				truncate_complete_page(page);
 
 			UnlockPage(page);
-			page_cache_release(page);
-			return 1;
+			goto out_restart;
 		}
+		curr = curr->next;
 	}
 	return 0;
+out_restart:
+	page_cache_release(page);
+	spin_lock(&pagecache_lock);
+	return 1;
 }
 
 
@@ -273,15 +277,19 @@
 {
 	unsigned long start = (lstart + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 	unsigned partial = lstart & (PAGE_CACHE_SIZE - 1);
+	int complete;
 
-repeat:
 	spin_lock(&pagecache_lock);
-	if (truncate_list_pages(&mapping->clean_pages, start, &partial))
-		goto repeat;
-	if (truncate_list_pages(&mapping->dirty_pages, start, &partial))
-		goto repeat;
-	if (truncate_list_pages(&mapping->locked_pages, start, &partial))
-		goto repeat;
+	do {
+		complete = 1;
+		while (truncate_list_pages(&mapping->clean_pages, start, &partial))
+			complete = 0;
+		while (truncate_list_pages(&mapping->dirty_pages, start, &partial))
+			complete = 0;
+		while (truncate_list_pages(&mapping->locked_pages, start, &partial))
+			complete = 0;
+	} while (!complete);
+	/* Traversed all three lists without dropping the lock */
 	spin_unlock(&pagecache_lock);
 }
 
@@ -529,7 +537,7 @@
 	if (PageLocked(page))
 		BUG();
 
-	flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_dirty) | (1 << PG_referenced) | (1 << PG_arch_1));
+	flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_dirty) | (1 << PG_referenced) | (1 << PG_arch_1) | (1 << PG_checked));
 	page->flags = flags | (1 << PG_locked);
 	page_cache_get(page);
 	page->index = offset;
diff -u --recursive --new-file v2.4.5/linux/mm/memory.c linux/mm/memory.c
--- v2.4.5/linux/mm/memory.c	Fri Apr 27 14:23:25 2001
+++ linux/mm/memory.c	Mon Jun 11 19:15:27 2001
@@ -274,7 +274,7 @@
 		 */
 		if (pte_dirty(pte) && page->mapping)
 			set_page_dirty(page);
-		page_cache_release(page);
+		free_page_and_swap_cache(page);
 		return 1;
 	}
 	swap_free(pte_to_swp_entry(pte));
@@ -870,24 +870,6 @@
 	flush_cache_page(vma, address);
 	establish_pte(vma, address, page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
 }
-
-/*
- * Work out if there are any other processes sharing this
- * swap cache page. Never mind the buffers.
- */
-static inline int exclusive_swap_page(struct page *page)
-{
-	unsigned int count;
-
-	if (!PageLocked(page))
-		BUG();
-	if (!PageSwapCache(page))
-		return 0;
-	count = page_count(page) - !!page->buffers;	/*  2: us + swap cache */
-	count += swap_count(page);			/* +1: just swap cache */
-	return count == 3;				/* =3: total */
-}
-
 
 /*
  * This routine handles present pages, when users try to write
diff -u --recursive --new-file v2.4.5/linux/mm/numa.c linux/mm/numa.c
--- v2.4.5/linux/mm/numa.c	Mon Oct 16 15:25:45 2000
+++ linux/mm/numa.c	Mon Jun 11 19:15:27 2001
@@ -34,7 +34,7 @@
 struct page * alloc_pages_node(int nid, int gfp_mask, unsigned long order)
 {
 #ifdef CONFIG_NUMA
-	return __alloc_pages(NODE_DATA(nid)->node_zonelists + gfp_mask, order);
+	return __alloc_pages(gfp_mask, order, NODE_DATA(nid)->node_zonelists + (gfp_mask & GFP_ZONEMASK));
 #else
 	return alloc_pages(gfp_mask, order);
 #endif
@@ -85,14 +85,14 @@
 static struct page * alloc_pages_pgdat(pg_data_t *pgdat, int gfp_mask,
 	unsigned long order)
 {
-	return __alloc_pages(pgdat->node_zonelists + gfp_mask, order);
+	return __alloc_pages(gfp_mask, order, pgdat->node_zonelists + (gfp_mask & GFP_ZONEMASK));
 }
 
 /*
  * This can be refined. Currently, tries to do round robin, instead
  * should do concentratic circle search, starting from current node.
  */
-struct page * alloc_pages(int gfp_mask, unsigned long order)
+struct page * _alloc_pages(int gfp_mask, unsigned long order)
 {
 	struct page *ret = 0;
 	pg_data_t *start, *temp;
diff -u --recursive --new-file v2.4.5/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.4.5/linux/mm/page_alloc.c	Fri May 25 16:55:23 2001
+++ linux/mm/page_alloc.c	Mon Jun 11 19:15:27 2001
@@ -268,15 +268,21 @@
 	return NULL;
 }
 
+#ifndef CONFIG_DISCONTIGMEM
+struct page *_alloc_pages(unsigned int gfp_mask, unsigned long order)
+{
+	return __alloc_pages(gfp_mask, order,
+		contig_page_data.node_zonelists+(gfp_mask & GFP_ZONEMASK));
+}
+#endif
 
 /*
  * This is the 'heart' of the zoned buddy allocator:
  */
-struct page * __alloc_pages(zonelist_t *zonelist, unsigned long order)
+struct page * __alloc_pages(unsigned int gfp_mask, unsigned long order, zonelist_t *zonelist)
 {
 	zone_t **zone;
 	int direct_reclaim = 0;
-	unsigned int gfp_mask = zonelist->gfp_mask;
 	struct page * page;
 
 	/*
@@ -428,18 +434,26 @@
 		}
 		/*
 		 * When we arrive here, we are really tight on memory.
+		 * Since kswapd didn't succeed in freeing pages for us,
+		 * we try to help it.
 		 *
-		 * We try to free pages ourselves by:
-		 * 	- shrinking the i/d caches.
-		 * 	- reclaiming unused memory from the slab caches.
-		 * 	- swapping/syncing pages to disk (done by page_launder)
-		 * 	- moving clean pages from the inactive dirty list to
-		 * 	  the inactive clean list. (done by page_launder)
+		 * Single page allocs loop until the allocation succeeds.
+		 * Multi-page allocs can fail due to memory fragmentation;
+		 * in that case we bail out to prevent infinite loops and
+		 * hanging device drivers ...
+		 *
+		 * Another issue are GFP_BUFFER allocations; because they
+		 * do not have __GFP_IO set it's possible we cannot make
+		 * any progress freeing pages, in that case it's better
+		 * to give up than to deadlock the kernel looping here.
 		 */
 		if (gfp_mask & __GFP_WAIT) {
 			memory_pressure++;
-			try_to_free_pages(gfp_mask);
-			goto try_again;
+			if (!order || free_shortage()) {
+				int progress = try_to_free_pages(gfp_mask);
+				if (progress || gfp_mask & __GFP_IO)
+					goto try_again;
+			}
 		}
 	}
 
@@ -671,14 +685,13 @@
 {
 	int i, j, k;
 
-	for (i = 0; i < NR_GFPINDEX; i++) {
+	for (i = 0; i <= GFP_ZONEMASK; i++) {
 		zonelist_t *zonelist;
 		zone_t *zone;
 
 		zonelist = pgdat->node_zonelists + i;
 		memset(zonelist, 0, sizeof(*zonelist));
 
-		zonelist->gfp_mask = i;
 		j = 0;
 		k = ZONE_NORMAL;
 		if (i & __GFP_HIGHMEM)
diff -u --recursive --new-file v2.4.5/linux/mm/swap_state.c linux/mm/swap_state.c
--- v2.4.5/linux/mm/swap_state.c	Thu May 24 15:20:18 2001
+++ linux/mm/swap_state.c	Mon Jun 11 19:15:27 2001
@@ -145,6 +145,30 @@
 	UnlockPage(page);
 }
 
+/* 
+ * Perform a free_page(), also freeing any swap cache associated with
+ * this page if it is the last user of the page. Can not do a lock_page,
+ * as we are holding the page_table_lock spinlock.
+ */
+void free_page_and_swap_cache(struct page *page)
+{
+	/* 
+	 * If we are the only user, then try to free up the swap cache. 
+	 * 
+	 * Its ok to check for PageSwapCache without the page lock
+	 * here because we are going to recheck again inside 
+	 * exclusive_swap_page() _with_ the lock. 
+	 * 					- Marcelo
+	 */
+	if (PageSwapCache(page) && !TryLockPage(page)) {
+		if (exclusive_swap_page(page))
+			delete_from_swap_cache_nolock(page);
+		UnlockPage(page);
+	}
+	page_cache_release(page);
+}
+
+
 /*
  * Lookup a swap entry in the swap cache. A found page will be returned
  * unlocked and with its refcount incremented - we rely on the kernel
diff -u --recursive --new-file v2.4.5/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.4.5/linux/mm/swapfile.c	Sat May 19 17:16:18 2001
+++ linux/mm/swapfile.c	Mon Jun 11 19:15:27 2001
@@ -343,6 +343,16 @@
 
 	while (1) {
 		/*
+		 * The algorithm is inefficient but seldomly used
+		 * and probably not worth fixing.
+		 *
+		 * Make sure that we aren't completely killing
+		 * interactive performance.
+		 */
+		if (current->need_resched)
+			schedule();
+			
+		/*
 		 * Find a swap page in use and read it in.
 		 */
 		swap_device_lock(si);
diff -u --recursive --new-file v2.4.5/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.4.5/linux/mm/vmscan.c	Fri May 25 17:00:18 2001
+++ linux/mm/vmscan.c	Tue Jun 12 16:02:38 2001
@@ -265,12 +265,9 @@
 	return !count;
 }
 
-/*
- * N.B. This function returns only 0 or 1.  Return values != 1 from
- * the lower level routines result in continued processing.
- */
-#define SWAP_SHIFT 5
-#define SWAP_MIN 8
+#define SWAP_MM_SHIFT	4
+#define SWAP_SHIFT	5
+#define SWAP_MIN	8
 
 static inline int swap_amount(struct mm_struct *mm)
 {
@@ -283,7 +280,7 @@
 	return nr;
 }
 
-static int swap_out(unsigned int priority, int gfp_mask)
+static void swap_out(unsigned int priority, int gfp_mask)
 {
 	int counter;
 	int retval = 0;
@@ -294,7 +291,7 @@
 		retval = swap_out_mm(mm, swap_amount(mm));
 
 	/* Then, look at the other mm's */
-	counter = (mmlist_nr << SWAP_SHIFT) >> priority;
+	counter = (mmlist_nr << SWAP_MM_SHIFT) >> priority;
 	do {
 		struct list_head *p;
 
@@ -316,11 +313,10 @@
 		retval |= swap_out_mm(mm, swap_amount(mm));
 		mmput(mm);
 	} while (--counter >= 0);
-	return retval;
+	return;
 
 empty:
 	spin_unlock(&mmlist_lock);
-	return 0;
 }
 
 
@@ -411,7 +407,7 @@
 /**
  * page_launder - clean dirty inactive pages, move to inactive_clean list
  * @gfp_mask: what operations we are allowed to do
- * @sync: should we wait synchronously for the cleaning of pages
+ * @sync: are we allowed to do synchronous IO in emergencies ?
  *
  * When this function is called, we are most likely low on free +
  * inactive_clean pages. Since we want to refill those pages as
@@ -428,18 +424,18 @@
  * go out to Matthew Dillon.
  */
 #define MAX_LAUNDER 		(4 * (1 << page_cluster))
+#define CAN_DO_IO		(gfp_mask & __GFP_IO)
+#define CAN_DO_BUFFERS		(gfp_mask & __GFP_BUFFER)
+#define marker_lru		(&marker_page_struct.lru)
 int page_launder(int gfp_mask, int sync)
 {
+	static int cannot_free_pages;
 	int launder_loop, maxscan, cleaned_pages, maxlaunder;
-	int can_get_io_locks;
 	struct list_head * page_lru;
 	struct page * page;
 
-	/*
-	 * We can only grab the IO locks (eg. for flushing dirty
-	 * buffers to disk) if __GFP_IO is set.
-	 */
-	can_get_io_locks = gfp_mask & __GFP_IO;
+	/* Our bookmark of where we are in the inactive_dirty list. */
+	struct page marker_page_struct = { zone: NULL };
 
 	launder_loop = 0;
 	maxlaunder = 0;
@@ -447,11 +443,44 @@
 
 dirty_page_rescan:
 	spin_lock(&pagemap_lru_lock);
-	maxscan = nr_inactive_dirty_pages;
-	while ((page_lru = inactive_dirty_list.prev) != &inactive_dirty_list &&
-				maxscan-- > 0) {
+	/*
+	 * By not scanning all inactive dirty pages we'll write out
+	 * really old dirty pages before evicting newer clean pages.
+	 * This should cause some LRU behaviour if we have a large
+	 * amount of inactive pages (due to eg. drop behind).
+	 *
+	 * It also makes us accumulate dirty pages until we have enough
+	 * to be worth writing to disk without causing excessive disk
+	 * seeks and eliminates the infinite penalty clean pages incurred
+	 * vs. dirty pages.
+	 */
+	maxscan = nr_inactive_dirty_pages / 4;
+	if (launder_loop)
+		maxscan *= 2;
+	list_add_tail(marker_lru, &inactive_dirty_list);
+	for (;;) {
+		page_lru = marker_lru->prev;
+		if (page_lru == &inactive_dirty_list)
+			break;
+		if (--maxscan < 0)
+			break;
+		if (!free_shortage())
+			break;
+
 		page = list_entry(page_lru, struct page, lru);
 
+		/* Move the bookmark backwards.. */
+		list_del(marker_lru);
+		list_add_tail(marker_lru, page_lru);
+
+		/* Don't waste CPU if chances are we cannot free anything. */
+		if (launder_loop && maxlaunder < 0 && cannot_free_pages)
+			break;
+
+		/* Skip other people's marker pages. */
+		if (!page->zone)
+			continue;
+
 		/* Wrong page on list?! (list corruption, should not happen) */
 		if (!PageInactiveDirty(page)) {
 			printk("VM: page_launder, wrong page on list.\n");
@@ -472,11 +501,9 @@
 
 		/*
 		 * The page is locked. IO in progress?
-		 * Move it to the back of the list.
+		 * Skip the page, we'll take a look when it unlocks.
 		 */
 		if (TryLockPage(page)) {
-			list_del(page_lru);
-			list_add(page_lru, &inactive_dirty_list);
 			continue;
 		}
 
@@ -490,10 +517,8 @@
 			if (!writepage)
 				goto page_active;
 
-			/* First time through? Move it to the back of the list */
-			if (!launder_loop) {
-				list_del(page_lru);
-				list_add(page_lru, &inactive_dirty_list);
+			/* First time through? Skip the page. */
+			if (!launder_loop || !CAN_DO_IO) {
 				UnlockPage(page);
 				continue;
 			}
@@ -506,6 +531,8 @@
 			writepage(page);
 			page_cache_release(page);
 
+			maxlaunder--;
+
 			/* And re-start the thing.. */
 			spin_lock(&pagemap_lru_lock);
 			continue;
@@ -533,9 +560,9 @@
 			spin_unlock(&pagemap_lru_lock);
 
 			/* Will we do (asynchronous) IO? */
-			if (launder_loop && maxlaunder == 0 && sync)
+			if (launder_loop && maxlaunder-- == 0 && sync)
 				wait = 2;	/* Synchrounous IO */
-			else if (launder_loop && maxlaunder-- > 0)
+			else if (launder_loop && maxlaunder > 0)
 				wait = 1;	/* Async IO */
 			else
 				wait = 0;	/* No IO */
@@ -552,7 +579,7 @@
 
 			/* The buffers were not freed. */
 			if (!clearedbuf) {
-				add_page_to_inactive_dirty_list(page);
+				add_page_to_inactive_dirty_list_marker(page);
 
 			/* The page was only in the buffer cache. */
 			} else if (!page->mapping) {
@@ -608,6 +635,8 @@
 			UnlockPage(page);
 		}
 	}
+	/* Remove our marker. */
+	list_del(marker_lru);
 	spin_unlock(&pagemap_lru_lock);
 
 	/*
@@ -621,18 +650,31 @@
 	 * loads, flush out the dirty pages before we have to wait on
 	 * IO.
 	 */
-	if (can_get_io_locks && !launder_loop && free_shortage()) {
+	if ((CAN_DO_IO || CAN_DO_BUFFERS) && !launder_loop && free_shortage()) {
 		launder_loop = 1;
-		/* If we cleaned pages, never do synchronous IO. */
-		if (cleaned_pages)
+		/*
+		 * If we, or the previous process running page_launder(),
+		 * managed to free any pages we never do synchronous IO.
+		 */
+		if (cleaned_pages || !cannot_free_pages)
 			sync = 0;
+		/* Else, do synchronous IO (if we are allowed to). */
+		else if (sync)
+			sync = 1;
 		/* We only do a few "out of order" flushes. */
 		maxlaunder = MAX_LAUNDER;
-		/* Kflushd takes care of the rest. */
+		/* Let bdflush take care of the rest. */
 		wakeup_bdflush(0);
 		goto dirty_page_rescan;
 	}
 
+	/*
+	 * If we failed to free pages (because all pages are dirty)
+	 * we remember this for the next time. This will prevent us
+	 * from wasting too much CPU here.
+	 */
+	cannot_free_pages = !cleaned_pages;
+
 	/* Return the number of pages moved to the inactive_clean list. */
 	return cleaned_pages;
 }
@@ -655,24 +697,10 @@
 
 	/*
 	 * When we are background aging, we try to increase the page aging
-	 * information in the system. When we have too many inactive pages
-	 * we don't do background aging since having all pages on the
-	 * inactive list decreases aging information.
-	 *
-	 * Since not all active pages have to be on the active list, we round
-	 * nr_active_pages up to num_physpages/2, if needed.
+	 * information in the system.
 	 */
-	if (!target) {
-		int inactive = nr_free_pages() + nr_inactive_clean_pages() +
-						nr_inactive_dirty_pages;
-		int active = MAX(nr_active_pages, num_physpages / 2);
-		if (active > 10 * inactive)
-			maxscan = nr_active_pages >> 4;
-		else if (active > 3 * inactive)
-			maxscan = nr_active_pages >> 8;
-		else
-			return 0;
-	}
+	if (!target)
+		maxscan = nr_active_pages >> 4;
 
 	/* Take the lock while messing with the list... */
 	spin_lock(&pagemap_lru_lock);
@@ -792,6 +820,8 @@
 			int zone_shortage;
 			zone_t *zone = pgdat->node_zones+ i;
 
+			if (!zone->size)
+				continue;
 			zone_shortage = zone->pages_high;
 			zone_shortage -= zone->inactive_dirty_pages;
 			zone_shortage -= zone->inactive_clean_pages;
@@ -843,13 +873,13 @@
 				return 1;
 		}
 
+		/* Walk the VM space for a bit.. */
+		swap_out(DEF_PRIORITY, gfp_mask);
+
 		count -= refill_inactive_scan(DEF_PRIORITY, count);
 		if (count <= 0)
 			goto done;
 
-		/* If refill_inactive_scan failed, try to page stuff out.. */
-		swap_out(DEF_PRIORITY, gfp_mask);
-
 		if (--maxtry <= 0)
 				return 0;
 		
@@ -872,7 +902,7 @@
 	 * list, so this is a relatively cheap operation.
 	 */
 	if (free_shortage()) {
-		ret += page_launder(gfp_mask, user);
+		ret += page_launder(gfp_mask, 1);
 		shrink_dcache_memory(DEF_PRIORITY, gfp_mask);
 		shrink_icache_memory(DEF_PRIORITY, gfp_mask);
 	}
diff -u --recursive --new-file v2.4.5/linux/net/Makefile linux/net/Makefile
--- v2.4.5/linux/net/Makefile	Fri Dec 29 14:07:24 2000
+++ linux/net/Makefile	Mon Jun 11 19:15:27 2001
@@ -7,7 +7,7 @@
 
 O_TARGET :=	network.o
 
-mod-subdirs :=	ipv4/netfilter ipv6/netfilter ipx irda atm netlink sched
+mod-subdirs :=	ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched
 export-objs :=	netsyms.o
 
 subdir-y :=	core ethernet
@@ -40,6 +40,7 @@
 subdir-$(CONFIG_ROSE)		+= rose
 subdir-$(CONFIG_AX25)		+= ax25
 subdir-$(CONFIG_IRDA)		+= irda
+subdir-$(CONFIG_BLUEZ)		+= bluetooth
 subdir-$(CONFIG_SUNRPC)		+= sunrpc
 subdir-$(CONFIG_ATM)		+= atm
 subdir-$(CONFIG_DECNET)		+= decnet
diff -u --recursive --new-file v2.4.5/linux/net/README linux/net/README
--- v2.4.5/linux/net/README	Wed May 16 10:31:27 2001
+++ linux/net/README	Mon Jun 11 19:15:27 2001
@@ -22,5 +22,5 @@
 wanrouter		gene@compuserve.com, jaspreet@sangoma and dm@sangoma.com
 unix			alan@lxorguk.ukuu.org.uk
 x25			g4klx@g4klx.demon.co.uk
-
+bluetooth		maxk@qualcomm.com
 
diff -u --recursive --new-file v2.4.5/linux/net/bluetooth/Config.in linux/net/bluetooth/Config.in
--- v2.4.5/linux/net/bluetooth/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/net/bluetooth/Config.in	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,16 @@
+#
+# Bluetooth configuration
+#
+
+if [ "$CONFIG_NET" != "n" ]; then
+   mainmenu_option next_comment
+   comment 'Bluetooth support'
+   dep_tristate 'Bluetooth subsystem support' CONFIG_BLUEZ $CONFIG_NET
+
+   if [ "$CONFIG_BLUEZ" != "n" ]; then
+      dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ
+      source drivers/bluetooth/Config.in
+   fi
+   endmenu
+fi
+
diff -u --recursive --new-file v2.4.5/linux/net/bluetooth/Makefile linux/net/bluetooth/Makefile
--- v2.4.5/linux/net/bluetooth/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/net/bluetooth/Makefile	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,20 @@
+#
+# Makefile for the Bluetooth subsystem
+#
+O_TARGET	:= bluetooth.o
+
+list-multi	:= hci.o l2cap.o
+export-objs	:= syms.o
+hci-objs	:= af_bluetooth.o hci_core.o hci_sock.o lib.o syms.o
+l2cap-objs	:= l2cap_core.o l2cap_proc.o
+
+obj-$(CONFIG_BLUEZ) += hci.o
+obj-$(CONFIG_BLUEZ_L2CAP) += l2cap.o
+
+include $(TOPDIR)/Rules.make
+
+hci.o: $(hci-objs)
+	$(LD) -r -o $@ $(hci-objs)
+
+l2cap.o: $(l2cap-objs)
+	$(LD) -r -o $@ $(l2cap-objs)
diff -u --recursive --new-file v2.4.5/linux/net/bluetooth/af_bluetooth.c linux/net/bluetooth/af_bluetooth.c
--- v2.4.5/linux/net/bluetooth/af_bluetooth.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bluetooth/af_bluetooth.c	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,164 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * BlueZ Bluetooth address family and sockets.
+ *
+ * $Id: af_bluetooth.c,v 1.1 2001/06/01 08:12:11 davem Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <net/sock.h>
+
+#if defined(CONFIG_KMOD)
+#include <linux/kmod.h>
+#endif
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/bluez.h>
+
+/* Bluetooth sockets */
+static struct net_proto_family *bluez_sock[BLUEZ_MAX_PROTO];
+
+int bluez_sock_register(int proto, struct net_proto_family *ops)
+{
+	if (proto > BLUEZ_MAX_PROTO)
+		return -EINVAL;
+
+	if (bluez_sock[proto])
+		return -EEXIST;
+
+	bluez_sock[proto] = ops;
+	return 0;
+}
+
+int bluez_sock_unregister(int proto)
+{
+	if (proto > BLUEZ_MAX_PROTO)
+		return -EINVAL;
+
+	if (!bluez_sock[proto])
+		return -ENOENT;
+
+	bluez_sock[proto] = NULL;
+	return 0;
+}
+
+static int bluez_sock_create(struct socket *sock, int proto)
+{
+	if (proto > BLUEZ_MAX_PROTO)
+		return -EINVAL;
+
+#if defined(CONFIG_KMOD)
+	if (!bluez_sock[proto]) {
+		char module_name[30];
+		sprintf(module_name, "bt-proto-%d", proto);
+		request_module(module_name);
+	}
+#endif
+
+	if (!bluez_sock[proto])
+		return -ENOENT;
+
+	return bluez_sock[proto]->create(sock, proto);
+}
+
+void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk)
+{
+	write_lock(&l->lock);
+
+	sk->next = l->head;
+	l->head = sk;
+	sock_hold(sk);
+
+	write_unlock(&l->lock);
+}
+
+void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *sk)
+{
+	struct sock **skp;
+
+	write_lock(&l->lock);
+	for (skp = &l->head; *skp; skp = &((*skp)->next)) {
+		if (*skp == sk) {
+			*skp = sk->next;
+			__sock_put(sk);
+			break;
+		}
+	}
+	write_unlock(&l->lock);
+}
+
+struct net_proto_family bluez_sock_family_ops =
+{
+	PF_BLUETOOTH, bluez_sock_create
+};
+
+int bluez_init(void)
+{
+	INF("BlueZ HCI Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
+		 BLUEZ_VER);
+	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+
+	proc_mkdir("bluetooth", NULL);
+
+	sock_register(&bluez_sock_family_ops);
+
+	/* Init HCI Core */
+	hci_core_init();
+
+	/* Init sockets */
+	hci_sock_init();
+
+	return 0;
+}
+
+void bluez_cleanup(void)
+{
+	/* Release socket */
+	hci_sock_cleanup();
+
+	/* Release core */
+	hci_core_cleanup();
+
+	sock_unregister(PF_BLUETOOTH);
+
+	remove_proc_entry("bluetooth", NULL);
+}
+
+#ifdef MODULE
+module_init(bluez_init);
+module_exit(bluez_cleanup);
+#endif
diff -u --recursive --new-file v2.4.5/linux/net/bluetooth/hci_core.c linux/net/bluetooth/hci_core.c
--- v2.4.5/linux/net/bluetooth/hci_core.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bluetooth/hci_core.c	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,1870 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * BlueZ HCI Core.
+ *
+ * $Id: hci_core.c,v 1.2 2001/06/01 16:57:03 davem Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <net/sock.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/bluez.h>
+#include <net/bluetooth/hci_core.h>
+
+#ifndef HCI_CORE_DEBUG
+#undef  DBG
+#define DBG( A... )
+#endif
+
+static void hci_cmd_task(unsigned long arg);
+static void hci_rx_task(unsigned long arg);
+static void hci_tx_task(unsigned long arg);
+static void hci_notify(struct hci_dev *hdev, int event);
+
+static rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
+
+/* HCI device list */
+struct hci_dev *hdev_list[HCI_MAX_DEV];
+spinlock_t hdev_list_lock;
+#define GET_HDEV(a) (hdev_list[a])
+
+/* HCI protocol list */
+struct hci_proto *hproto_list[HCI_MAX_PROTO];
+#define GET_HPROTO(a) (hproto_list[a])
+
+/* HCI notifiers list */
+struct notifier_block *hci_dev_notifier;
+
+/* HCI device notifications */
+int hci_register_notifier(struct notifier_block *nb)
+{
+	int err, i;
+	struct hci_dev *hdev;
+
+	if ((err = notifier_chain_register(&hci_dev_notifier, nb)))
+		return err;
+
+	/* Notify about already registered devices */
+	spin_lock(&hdev_list_lock);
+	for (i = 0; i < HCI_MAX_DEV; i++) {
+		if (!(hdev = GET_HDEV(i)))
+			continue;
+		if (hdev->flags & HCI_UP)
+			(*nb->notifier_call)(nb, HCI_DEV_UP, hdev);
+	}
+	spin_unlock(&hdev_list_lock);
+
+	return 0;
+}
+
+int hci_unregister_notifier(struct notifier_block *nb)
+{
+	return notifier_chain_unregister(&hci_dev_notifier, nb);
+}
+
+static __inline__ void hci_notify(struct hci_dev *hdev, int event)
+{
+	notifier_call_chain(&hci_dev_notifier, event, hdev);
+}
+
+/* Get HCI device by index (device is locked on return)*/
+struct hci_dev *hci_dev_get(int index)
+{
+	struct hci_dev *hdev;
+	DBG("%d", index);
+
+	if (index < 0 || index >= HCI_MAX_DEV)
+		return NULL;
+
+	spin_lock(&hdev_list_lock);
+	if ((hdev = GET_HDEV(index)))
+		hci_dev_hold(hdev);
+	spin_unlock(&hdev_list_lock);
+
+	return hdev;
+}
+
+/* Flush inquiry cache */
+void inquiry_cache_flush(struct inquiry_cache *cache)
+{
+	struct inquiry_entry *next = cache->list, *e;
+
+	DBG("cache %p", cache);
+
+	cache->list = NULL;
+	while ((e = next)) {
+		next = e->next;
+		kfree(e);
+	}
+}
+
+/* Lookup by bdaddr.
+ * Cache must be locked. */
+static struct inquiry_entry * __inquiry_cache_lookup(struct inquiry_cache *cache, bdaddr_t *bdaddr)
+{
+	struct inquiry_entry *e;
+
+	DBG("cache %p, %s", cache, batostr(bdaddr));
+
+	for (e = cache->list; e; e = e->next)
+		if (!bacmp(&e->info.bdaddr, bdaddr))
+			break;
+
+	return e;
+}
+
+static void inquiry_cache_update(struct inquiry_cache *cache, inquiry_info *info)
+{
+	struct inquiry_entry *e;
+
+	DBG("cache %p, %s", cache, batostr(&info->bdaddr));
+
+	inquiry_cache_lock(cache);
+
+	if (!(e = __inquiry_cache_lookup(cache, &info->bdaddr))) {
+		/* Entry not in the cache. Add new one. */
+		if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
+			goto unlock;
+		memset(e, 0, sizeof(struct inquiry_entry));
+		e->next     = cache->list;
+		cache->list = e;
+	}
+
+	memcpy(&e->info, info, sizeof(inquiry_info));
+	e->timestamp = jiffies;
+	cache->timestamp = jiffies;
+unlock:
+	inquiry_cache_unlock(cache);
+}
+
+static int inquiry_cache_dump(struct inquiry_cache *cache, int num, __u8 *buf)
+{
+	inquiry_info *info = (inquiry_info *) buf;
+	struct inquiry_entry *e;
+	int copied = 0;
+
+	inquiry_cache_lock(cache);
+
+	for (e = cache->list; e && copied < num; e = e->next, copied++)
+		memcpy(info++, &e->info, sizeof(inquiry_info));
+
+	inquiry_cache_unlock(cache);
+
+	DBG("cache %p, copied %d", cache, copied);
+	return copied;
+}
+
+/* --------- BaseBand connections --------- */
+static struct hci_conn *hci_conn_add(struct hci_dev *hdev, __u16 handle, bdaddr_t *dst)
+{
+	struct hci_conn *conn;
+
+	DBG("%s handle %d dst %s", hdev->name, handle, batostr(dst));
+
+	if (handle > HCI_MAX_CONN) {
+		ERR("%s BUG handle %d is to large", hdev->name, handle);
+		return NULL;
+	}
+
+	if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
+		return NULL;
+	memset(conn, 0, sizeof(struct hci_conn));
+
+	bacpy(&conn->dst, dst);
+	conn->handle = handle;
+	conn->hdev   = hdev;
+
+	skb_queue_head_init(&conn->acl_q);
+	skb_queue_head_init(&conn->sco_q);
+
+	if (conn_hash_add(&hdev->conn_hash, handle, conn)) {
+		hci_dev_hold(hdev);
+		return conn;
+	} else {
+		kfree(conn);
+		return NULL;
+	}
+}
+
+static int hci_conn_del(struct hci_dev *hdev, struct hci_conn *conn)
+{
+	DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
+
+	if (conn_hash_del(&hdev->conn_hash, conn->handle)) {
+		hci_dev_put(hdev);
+
+		/* Unacked frames */
+		hdev->acl_cnt += conn->acl_sent;
+	}
+
+	bluez_skb_queue_purge(&conn->acl_q);
+	bluez_skb_queue_purge(&conn->sco_q);
+
+	kfree(conn);
+	return 0;
+}
+
+/* Drop all connection on the device */
+static void hci_conn_hash_flush(struct hci_dev *hdev)
+{
+	struct hci_proto *hp = GET_HPROTO(HCI_PROTO_L2CAP);
+	struct conn_hash *h = &hdev->conn_hash;
+	int i;
+
+	DBG("hdev %s", hdev->name);
+
+	for (i = 0; i < HCI_MAX_CONN; i++) {
+		struct hci_conn *conn;
+
+		if (!(conn = conn_hash_lookup(h, i)))
+			continue;
+
+		if (hp && hp->disconn_ind)
+			hp->disconn_ind(conn, 0x16);
+		
+		hci_conn_del(hdev, conn);
+	}
+}
+
+int hci_connect(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+	struct inquiry_cache *cache = &hdev->inq_cache;
+	struct inquiry_entry *e;
+	create_conn_cp cc;
+	__u16 clock_offset;
+
+	DBG("%s bdaddr %s", hdev->name, batostr(bdaddr));
+
+	if (!(hdev->flags & HCI_UP))
+		return -ENODEV;
+
+	inquiry_cache_lock_bh(cache);
+
+	if (!(e = __inquiry_cache_lookup(cache, bdaddr)) || inquiry_entry_age(e) > INQUIRY_ENTRY_AGE_MAX) {
+		cc.pscan_rep_mode = 0;
+		cc.pscan_mode     = 0;
+		clock_offset      = 0;
+	} else {
+		cc.pscan_rep_mode = e->info.pscan_rep_mode;
+		cc.pscan_mode     = e->info.pscan_mode;
+		clock_offset      = __le16_to_cpu(e->info.clock_offset) & 0x8000;
+	}
+
+	inquiry_cache_unlock_bh(cache);
+
+	bacpy(&cc.bdaddr, bdaddr);
+	cc.pkt_type	= __cpu_to_le16(HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5);
+	cc.clock_offset	= __cpu_to_le16(clock_offset);
+	cc.role_switch	= 0;
+	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, CREATE_CONN_CP_SIZE, &cc);
+
+	return 0;
+}
+
+int hci_disconnect(struct hci_conn *conn, __u8 reason)
+{
+	disconnect_cp dc;
+
+	DBG("conn %p handle %d", conn, conn->handle);
+
+	dc.handle = __cpu_to_le16(conn->handle);
+	dc.reason = reason;
+	hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, DISCONNECT_CP_SIZE, &dc);
+
+	return 0;
+}
+
+/* --------- HCI request handling ------------ */
+static __inline__ void hci_req_lock(struct hci_dev *hdev)
+{
+	down(&hdev->req_lock);
+}
+
+static __inline__ void hci_req_unlock(struct hci_dev *hdev)
+{
+	up(&hdev->req_lock);
+}
+
+static __inline__ void hci_req_complete(struct hci_dev *hdev, int result)
+{
+	DBG("%s result 0x%2.2x", hdev->name, result);
+
+	if (hdev->req_status == HCI_REQ_PEND) {
+		hdev->req_result = result;
+		hdev->req_status = HCI_REQ_DONE;
+		wake_up_interruptible(&hdev->req_wait_q);
+	}
+}
+
+static __inline__ void hci_req_cancel(struct hci_dev *hdev, int err)
+{
+	DBG("%s err 0x%2.2x", hdev->name, err);
+
+	if (hdev->req_status == HCI_REQ_PEND) {
+		hdev->req_result = err;
+		hdev->req_status = HCI_REQ_CANCELED;
+		wake_up_interruptible(&hdev->req_wait_q);
+	}
+}
+
+/* Execute request and wait for completion. */
+static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
+                         unsigned long opt, __u32 timeout)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int err = 0;
+
+	DBG("%s start", hdev->name);
+
+	hdev->req_status = HCI_REQ_PEND;
+
+	add_wait_queue(&hdev->req_wait_q, &wait);
+	current->state = TASK_INTERRUPTIBLE;
+
+	req(hdev, opt);
+	schedule_timeout(timeout);
+
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&hdev->req_wait_q, &wait);
+
+	if (signal_pending(current))
+		return -EINTR;
+
+	switch (hdev->req_status) {
+	case HCI_REQ_DONE:
+		err = -bterr(hdev->req_result);
+		break;
+
+	case HCI_REQ_CANCELED:
+		err = -hdev->req_result;
+		break;
+
+	default:
+		err = -ETIMEDOUT;
+		break;
+	};
+
+	hdev->req_status = hdev->req_result = 0;
+
+	DBG("%s end: err %d", hdev->name, err);
+
+	return err;
+}
+
+static __inline__ int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
+                                  unsigned long opt, __u32 timeout)
+{
+	int ret;
+
+	/* Serialize all requests */
+	hci_req_lock(hdev);
+	ret = __hci_request(hdev, req, opt, timeout);
+	hci_req_unlock(hdev);
+
+	return ret;
+}
+
+/* --------- HCI requests ---------- */
+static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
+{
+	DBG("%s %ld", hdev->name, opt);
+
+	/* Reset device */
+	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
+}
+
+static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
+{
+	set_event_flt_cp ec;
+	__u16 param;
+
+	DBG("%s %ld", hdev->name, opt);
+
+	/* Mandatory initialization */
+
+	/* Read Buffer Size (ACL mtu, max pkt, etc.) */
+	hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL);
+
+	/* Read BD Address */
+	hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL);
+
+	/* Optional initialization */
+
+	/* Clear Event Filters */
+	ec.flt_type  = FLT_CLEAR_ALL;
+	ec.cond_type = 0;
+	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, SET_EVENT_FLT_CP_SIZE, &ec);
+
+	/* Page timeout ~ 20 secs */
+	param = __cpu_to_le16(0x8000);
+	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_PG_TIMEOUT, 2, &param);
+
+	/* Connection accept timeout ~20 secs */
+	param = __cpu_to_le16(0x7d00);
+	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_CA_TIMEOUT, 2, &param);
+}
+
+static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
+{
+	__u8 scan = opt;
+
+	DBG("%s %x", hdev->name, scan);
+
+	/* Inquiry and Page scans */
+	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &scan);
+}
+
+static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
+{
+	__u8 auth = opt;
+
+	DBG("%s %x", hdev->name, auth);
+
+	/* Authentication */
+	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE, 1, &auth);
+}
+
+static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
+{
+	struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
+	inquiry_cp ic;
+
+	DBG("%s", hdev->name);
+
+	/* Start Inquiry */
+	memcpy(&ic.lap, &ir->lap, 3);
+	ic.lenght  = ir->length;
+	ic.num_rsp = ir->num_rsp;
+	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, INQUIRY_CP_SIZE, &ic);
+}
+
+/* Open HCI device */
+int hci_dev_open(__u16 dev)
+{
+	struct hci_dev *hdev;
+	int ret = 0;
+
+	if (!(hdev = hci_dev_get(dev)))
+		return -ENODEV;
+
+	DBG("%s %p", hdev->name, hdev);
+
+	hci_req_lock(hdev);
+
+	if (hdev->flags & HCI_UP) {
+		ret = -EALREADY;
+		goto done;
+	}
+
+	/* Initialize device */
+	if (hdev->open(hdev)) {
+		ret = -EIO;
+		goto done;
+	}
+
+	atomic_set(&hdev->cmd_cnt, 1);
+	hdev->cmd_sent= NULL;
+	hdev->flags  |= HCI_INIT;
+
+	__hci_request(hdev, hci_reset_req, 0, HZ);
+
+	if (!(ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT))) {
+		hdev->flags |= HCI_UP;
+		hci_notify(hdev, HCI_DEV_UP);
+	}
+
+	hdev->flags &= ~HCI_INIT;
+
+done:
+	hci_req_unlock(hdev);
+	hci_dev_put(hdev);
+
+	return ret;
+}
+
+/* Close HCI device */
+int hci_dev_close(__u16 dev)
+{
+	struct hci_dev *hdev;
+
+	if (!(hdev = hci_dev_get(dev)))
+		return -ENODEV;
+
+	DBG("%s %p", hdev->name, hdev);
+
+	hci_req_cancel(hdev, ENODEV);
+	hci_req_lock(hdev);
+
+	if (!(hdev->flags & HCI_UP))
+		goto done;
+
+	/* Kill RX and TX tasks */
+	tasklet_kill(&hdev->rx_task);
+	tasklet_kill(&hdev->tx_task);
+
+	inquiry_cache_flush(&hdev->inq_cache);
+
+	hci_conn_hash_flush(hdev);
+
+	/* Clear flags */
+	hdev->flags &= (HCI_NORMAL | HCI_SOCK);
+
+	hci_notify(hdev, HCI_DEV_DOWN);
+
+	if (hdev->flush)
+		hdev->flush(hdev);
+
+	/* Reset device */
+	bluez_skb_queue_purge(&hdev->cmd_q);
+	atomic_set(&hdev->cmd_cnt, 1);
+	hdev->flags |= HCI_INIT;
+	__hci_request(hdev, hci_reset_req, 0, HZ);
+	hdev->flags &= ~HCI_INIT;
+
+	/* Kill cmd task */
+	tasklet_kill(&hdev->cmd_task);
+
+	/* Drop queues */
+	bluez_skb_queue_purge(&hdev->rx_q);
+	bluez_skb_queue_purge(&hdev->cmd_q);
+	bluez_skb_queue_purge(&hdev->raw_q);
+
+	/* Drop last sent command */
+	if (hdev->cmd_sent) {
+		bluez_skb_free(hdev->cmd_sent);
+		hdev->cmd_sent = NULL;
+	}
+
+	/* After this point our queues are empty
+	 * and no tasks are scheduled.
+	 */
+	hdev->close(hdev);
+
+done:
+	hci_req_unlock(hdev);
+	hci_dev_put(hdev);
+
+	return 0;
+}
+
+/* Interface to HCI drivers */
+
+/* Register HCI device */
+int hci_register_dev(struct hci_dev *hdev)
+{
+	int i;
+
+	DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
+
+	/* Find free slot */
+	spin_lock_bh(&hdev_list_lock);
+	for (i = 0; i < HCI_MAX_DEV; i++) {
+		if (!hdev_list[i]) {
+			hdev_list[i] = hdev;
+
+			sprintf(hdev->name, "hci%d", i);
+			atomic_set(&hdev->refcnt, 0);
+			hdev->id    = i;
+			hdev->flags = HCI_NORMAL;
+
+			tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev);
+			tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
+			tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
+
+			skb_queue_head_init(&hdev->rx_q);
+			skb_queue_head_init(&hdev->cmd_q);
+			skb_queue_head_init(&hdev->raw_q);
+
+			init_waitqueue_head(&hdev->req_wait_q);
+			init_MUTEX(&hdev->req_lock);
+
+			inquiry_cache_init(&hdev->inq_cache);
+
+			conn_hash_init(&hdev->conn_hash);
+
+			memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
+
+			hci_notify(hdev, HCI_DEV_REG);
+
+			MOD_INC_USE_COUNT;
+			break;
+		}
+	}
+	spin_unlock_bh(&hdev_list_lock);
+
+	return (i == HCI_MAX_DEV) ? -1 : i;
+}
+
+/* Unregister HCI device */
+int hci_unregister_dev(struct hci_dev *hdev)
+{
+	int i;
+
+	DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
+
+	if (hdev->flags & HCI_UP)
+		hci_dev_close(hdev->id);
+
+	/* Find device slot */
+	spin_lock(&hdev_list_lock);
+	for (i = 0; i < HCI_MAX_DEV; i++) {
+		if (hdev_list[i] == hdev) {
+			hdev_list[i] = NULL;
+			MOD_DEC_USE_COUNT;
+			break;
+		}
+	}
+	spin_unlock(&hdev_list_lock);
+
+	hci_notify(hdev, HCI_DEV_UNREG);
+
+	/* Sleep while device is in use */
+	while (atomic_read(&hdev->refcnt)) {
+		int sleep_cnt = 100;
+
+		DBG("%s sleeping on lock %d", hdev->name, atomic_read(&hdev->refcnt));
+
+		sleep_on_timeout(&hdev->req_wait_q, HZ*10);
+		if (!(--sleep_cnt))
+			break;
+	}
+
+	return 0;
+}
+
+/* Interface to upper protocols */
+
+/* Register/Unregister protocols.
+ * hci_task_lock is used to ensure that no tasks are running.
+ */
+int hci_register_proto(struct hci_proto *hproto)
+{
+	int err = 0;
+
+	DBG("%p name %s", hproto, hproto->name);
+
+	if (hproto->id >= HCI_MAX_PROTO)
+		return -EINVAL;
+
+	write_lock_bh(&hci_task_lock);
+
+	if (!hproto_list[hproto->id])
+		hproto_list[hproto->id] = hproto;
+	else
+		err = -1;
+
+	write_unlock_bh(&hci_task_lock);
+
+	return err;
+}
+
+int hci_unregister_proto(struct hci_proto *hproto)
+{
+	int err = 0;
+
+	DBG("%p name %s", hproto, hproto->name);
+
+	if (hproto->id > HCI_MAX_PROTO)
+		return -EINVAL;
+
+	write_lock_bh(&hci_task_lock);
+
+	if (hproto_list[hproto->id])
+		hproto_list[hproto->id] = NULL;
+	else
+		err = -ENOENT;
+
+	write_unlock_bh(&hci_task_lock);
+
+	return err;
+}
+
+static int hci_send_frame(struct sk_buff *skb)
+{
+	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+
+	if (!hdev) {
+		bluez_skb_free(skb);
+		return -ENODEV;
+	}
+
+	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
+
+	if (hdev->flags & HCI_SOCK)
+		hci_send_to_sock(hdev, skb);
+
+	/* Get rid of skb owner, prior to sending to the driver. */
+	skb_orphan(skb);
+
+	return hdev->send(skb);
+}
+
+/* ACL scheduler */
+static __inline__ struct hci_conn *hci_low_acl_sent(struct hci_dev *hdev, int *quote)
+{
+	struct conn_hash *h = &hdev->conn_hash;
+	struct hci_conn *conn = NULL;
+	int i, num = 0, min = 0xffff;
+
+	conn_hash_lock(h);
+	for (i = 0; i < HCI_MAX_CONN; i++) {
+		struct hci_conn *c;
+
+		if (!(c = __conn_hash_lookup(h,i)) || !skb_queue_len(&c->acl_q))
+			continue;
+		num++;
+
+		if (c->acl_sent < min) {
+			min  = c->acl_sent;
+			conn = c;
+		}
+	}
+	conn_hash_unlock(h);
+
+	if (conn) {
+		int q = hdev->acl_cnt / num;
+		*quote = q ? q : 1;
+	} else
+		*quote = 0;
+
+	DBG("conn %p quote %d", conn, *quote);
+
+	return conn;
+}
+
+static __inline__ void hci_sched_acl(struct hci_dev *hdev)
+{
+	struct hci_conn *conn;
+	struct sk_buff *skb, *frag;
+	int quote;
+
+	DBG("%s", hdev->name);
+
+	while (hdev->acl_cnt) {
+		if (!(conn = hci_low_acl_sent(hdev, &quote)))
+			break;
+
+		while (quote && (skb = skb_peek(&conn->acl_q))) {
+			if (bluez_skb_frags(skb)+1 > hdev->acl_cnt) {
+				/* FIXME: Schedule next connection */
+				goto done;
+			}
+
+			if (!(frag = bluez_skb_clone(skb, GFP_ATOMIC)))
+				break;
+
+			skb_unlink(skb);
+			do {
+				DBG("frag %p len %d", frag, frag->len);
+
+				hci_send_frame(frag);
+
+				conn->acl_sent++;
+				hdev->acl_cnt--;
+				quote--;
+			} while ((frag = bluez_skb_get_frag(skb)));
+			kfree_skb(skb);
+		}
+	}
+done:
+	return;
+}
+
+/* Schedule SCO */
+static __inline__ void hci_sched_sco(struct hci_dev *hdev)
+{
+	struct conn_hash *h = &hdev->conn_hash;
+	struct sk_buff *skb;
+	int i;
+
+	DBG("%s", hdev->name);
+
+	conn_hash_lock(h);
+	for (i = 0; i< HCI_MAX_CONN; i++) {
+		struct hci_conn *conn;
+
+		if (!(conn = __conn_hash_lookup(h, i)))
+			continue;
+
+		while (hdev->sco_cnt && (skb = skb_dequeue(&conn->sco_q))) {
+			hci_send_frame(skb);
+			conn->sco_sent++;
+			hdev->sco_cnt--;
+		}
+	}
+	conn_hash_unlock(h);
+}
+
+/* Send raw HCI frame */
+int hci_send_raw(struct sk_buff *skb)
+{
+	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+
+	if (!hdev) {
+		bluez_skb_free(skb);
+		return -ENODEV;
+	}
+
+	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
+
+	/* Queue frame according it's type */
+	switch (skb->pkt_type) {
+	case HCI_COMMAND_PKT:
+		skb_queue_tail(&hdev->cmd_q, skb);
+		hci_sched_cmd(hdev);
+		break;
+
+	case HCI_ACLDATA_PKT:
+	case HCI_SCODATA_PKT:
+		/* FIXME:
+		 * Check header here and queue to aproptiate connection.
+		 */
+	default:
+		skb_queue_tail(&hdev->raw_q, skb);
+		hci_sched_tx(hdev);
+
+		return 0;
+	};
+
+	return 0;
+}
+
+/* Send HCI command */
+int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param)
+{
+	int len = HCI_COMMAND_HDR_SIZE + plen;
+	hci_command_hdr *hc;
+	struct sk_buff *skb;
+
+	DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen);
+
+	if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) {
+		ERR("%s Can't allocate memory for HCI command", hdev->name);
+		return -ENOMEM;
+	}
+	
+	hc = (hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE);
+	hc->opcode = __cpu_to_le16(cmd_opcode_pack(ocf, ogf));
+	hc->plen   = plen;
+
+	if (plen)
+		memcpy(skb_put(skb, plen), param, plen);
+
+	DBG("skb len %d", skb->len);
+
+	skb->pkt_type = HCI_COMMAND_PKT;
+	skb->dev = (void *) hdev;
+	skb_queue_tail(&hdev->cmd_q, skb);
+	hci_sched_cmd(hdev);
+
+	return 0;
+}
+
+/* Send ACL data */
+
+static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
+{
+	int len = skb->len;	
+	hci_acl_hdr *ah;
+
+	ah = (hci_acl_hdr *) skb_push(skb, HCI_ACL_HDR_SIZE);
+	ah->handle = __cpu_to_le16(acl_handle_pack(handle, flags));
+	ah->dlen   = __cpu_to_le16(len);
+
+	skb->h.raw = (void *) ah;
+}
+
+int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
+{
+	struct hci_dev *hdev = conn->hdev;
+	struct sk_buff *frag;
+	int sent = 0;
+
+	DBG("%s conn %p len %d flags 0x%x", hdev->name, conn, skb->len, flags);
+	DBG("frags %d", bluez_skb_frags(skb));
+
+	/* Add ACL header to all fragments */
+	flags |= ACL_START;
+	frag = skb;
+	do {
+		DBG("frag %p len %d", frag, frag->len);
+		sent += frag->len;
+
+		hci_add_acl_hdr(frag, conn->handle, flags);
+		frag->pkt_type = HCI_ACLDATA_PKT;
+		frag->dev = (void *) hdev;
+
+		flags = ACL_CONT;
+	} while ((frag = bluez_skb_next_frag(frag)));
+
+	skb_queue_tail(&conn->acl_q, skb);
+	hci_sched_tx(hdev);
+
+	return sent;
+}
+
+/* Send SCO data */
+int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
+{
+	struct hci_dev *hdev = conn->hdev;
+	hci_sco_hdr hs;
+
+	DBG("%s len %d", hdev->name, skb->len);
+
+	if (skb->len > hdev->sco_mtu) {
+		bluez_skb_free(skb);
+		return -EINVAL;
+	}
+
+	hs.handle = __cpu_to_le16(conn->handle);
+	hs.dlen   = skb->len;
+
+	skb->h.raw = skb_push(skb, HCI_SCO_HDR_SIZE);
+	memcpy(skb->h.raw, &hs, HCI_SCO_HDR_SIZE);
+
+	skb->dev = (void *) hdev;
+	skb->pkt_type = HCI_SCODATA_PKT;
+	skb_queue_tail(&conn->sco_q, skb);
+	hci_sched_tx(hdev);
+
+	return 0;
+}
+
+/* Handle HCI Event packets */
+
+/* Command Complete OGF LINK_CTL  */
+static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+{
+	DBG("%s ocf 0x%x", hdev->name, ocf);
+
+	switch (ocf) {
+	default:
+		DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
+		break;
+	};
+}
+
+/* Command Complete OGF LINK_POLICY  */
+static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+{
+	DBG("%s ocf 0x%x", hdev->name, ocf);
+
+	switch (ocf) {
+	default:
+		DBG("%s: Command complete: ogf LINK_POLICY ocf %x", hdev->name, ocf);
+		break;
+	};
+}
+
+/* Command Complete OGF HOST_CTL  */
+static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+{
+	__u8 status, param;
+
+	DBG("%s ocf 0x%x", hdev->name, ocf);
+
+	switch (ocf) {
+	case OCF_RESET:
+		status = *((__u8 *) skb->data);
+
+		hci_req_complete(hdev, status);
+		break;
+
+	case OCF_SET_EVENT_FLT:
+		status = *((__u8 *) skb->data);
+
+		if (status) {
+			DBG("%s SET_EVENT_FLT failed %d", hdev->name, status);
+		} else {
+			DBG("%s SET_EVENT_FLT succeseful", hdev->name);
+		}
+		break;
+
+	case OCF_WRITE_AUTH_ENABLE:
+		status = *((__u8 *) skb->data);
+		param  = *(SENT_CMD_PARAM(hdev));
+
+		if (!status) {
+			if (param == AUTH_ENABLED)
+				hdev->flags |= HCI_AUTH;
+			else
+				hdev->flags &= ~HCI_AUTH;
+		}
+		hci_req_complete(hdev, status);
+		break;
+
+	case OCF_WRITE_CA_TIMEOUT:
+		status = *((__u8 *) skb->data);
+
+		if (status) {
+			DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status);
+		} else {
+			DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
+		}
+		break;
+
+	case OCF_WRITE_PG_TIMEOUT:
+		status = *((__u8 *) skb->data);
+
+		if (status) {
+			DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
+		} else {
+			DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
+		}
+		break;
+
+	case OCF_WRITE_SCAN_ENABLE:
+		status = *((__u8 *) skb->data);
+		param  = *(SENT_CMD_PARAM(hdev));
+
+		if (!status) {
+			switch (param) {
+			case IS_ENA_PS_ENA:
+				hdev->flags |=  HCI_PSCAN | HCI_ISCAN;
+				break;
+
+			case IS_ENA_PS_DIS:
+				hdev->flags &= ~HCI_PSCAN;
+				hdev->flags |=  HCI_ISCAN;
+				break;
+
+			case IS_DIS_PS_ENA:
+				hdev->flags &= ~HCI_ISCAN;
+				hdev->flags |=  HCI_PSCAN;
+				break;
+
+			default:
+				hdev->flags &= ~(HCI_ISCAN | HCI_PSCAN);
+				break;
+			};
+		}
+		hci_req_complete(hdev, status);
+		break;
+
+	default:
+		DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf);
+		break;
+	};
+}
+
+/* Command Complete OGF INFO_PARAM  */
+static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+{
+	read_buffer_size_rp *rsp;
+	read_bd_addr_rp *rap;
+
+	DBG("%s ocf 0x%x", hdev->name, ocf);
+
+	switch (ocf) {
+	case OCF_READ_BUFFER_SIZE:
+		rsp = (read_buffer_size_rp *) skb->data;
+
+		if (rsp->status) {
+			DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, rsp->status);
+			break;
+		}
+
+		hdev->acl_mtu = __le16_to_cpu(rsp->acl_mtu);
+		hdev->sco_mtu = rsp->sco_mtu;
+		hdev->acl_max = hdev->acl_cnt = __le16_to_cpu(rsp->acl_max_pkt);
+		hdev->sco_max = hdev->sco_cnt = __le16_to_cpu(rsp->sco_max_pkt);
+
+		DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
+		    hdev->acl_mtu, hdev->sco_mtu, hdev->acl_max, hdev->sco_max);
+
+		break;
+
+	case OCF_READ_BD_ADDR:
+		rap = (read_bd_addr_rp *) skb->data;
+
+		if (!rap->status) {
+			bacpy(&hdev->bdaddr, &rap->bdaddr);
+		} else {
+			DBG("%s: READ_BD_ADDR failed %d", hdev->name, rap->status);
+		}
+
+		hci_req_complete(hdev, rap->status);
+		break;
+
+	default:
+		DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
+		break;
+	};
+}
+
+/* Command Status OGF LINK_CTL  */
+static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
+{
+	struct hci_proto * hp;
+
+	DBG("%s ocf 0x%x", hdev->name, ocf);
+
+	switch (ocf) {
+	case OCF_CREATE_CONN:
+		if (status) {
+			create_conn_cp *cc = (void *) SENT_CMD_PARAM(hdev);
+			DBG("%s Create connection error: status 0x%x %s", hdev->name,
+			    status, batostr(&cc->bdaddr));
+
+			/* Notify upper protocols */
+			if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm) {
+				tasklet_disable(&hdev->tx_task);
+				hp->connect_cfm(hdev, &cc->bdaddr, status, NULL);
+				tasklet_enable(&hdev->tx_task);
+			}
+		}
+		break;
+
+	case OCF_INQUIRY:
+		if (status) {
+			DBG("%s Inquiry error: status 0x%x", hdev->name, status);
+			hci_req_complete(hdev, status);
+		}
+		break;
+
+	default:
+		DBG("%s Command status: ogf LINK_CTL ocf %x", hdev->name, ocf);
+		break;
+	};
+}
+
+/* Command Status OGF LINK_POLICY */
+static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
+{
+	DBG("%s ocf 0x%x", hdev->name, ocf);
+
+	switch (ocf) {
+	default:
+		DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf);
+		break;
+	};
+}
+
+/* Command Status OGF HOST_CTL */
+static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
+{
+	DBG("%s ocf 0x%x", hdev->name, ocf);
+
+	switch (ocf) {
+	default:
+		DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf);
+		break;
+	};
+}
+
+/* Command Status OGF INFO_PARAM  */
+static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status)
+{
+	DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf);
+
+	switch (ocf) {
+	default:
+		DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
+		break;
+	};
+}
+
+/* Inquiry Complete */
+static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *) skb->data);
+
+	DBG("%s status %d", hdev->name, status);
+
+	hci_req_complete(hdev, status);
+}
+
+/* Inquiry Result */
+static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	inquiry_info *info = (inquiry_info *) (skb->data + 1);
+	int num_rsp = *((__u8 *) skb->data);
+
+	DBG("%s num_rsp %d", hdev->name, num_rsp);
+
+	for (; num_rsp; num_rsp--)
+		inquiry_cache_update(&hdev->inq_cache, info++);
+}
+
+/* Connect Request */
+static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	evt_conn_request *cr = (evt_conn_request *) skb->data;
+	struct hci_proto *hp;
+	accept_conn_req_cp ac;
+	int accept = 0;
+
+	DBG("%s Connection request: %s type 0x%x", hdev->name, batostr(&cr->bdaddr), cr->type);
+
+	/* Notify upper protocols */
+	if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_ind) {
+		tasklet_disable(&hdev->tx_task);
+		accept = hp->connect_ind(hdev, &cr->bdaddr);
+		tasklet_enable(&hdev->tx_task);
+	}
+
+	if (accept) {
+		/* Connection accepted by upper layer */
+		bacpy(&ac.bdaddr, &cr->bdaddr);
+		ac.role = 0x01; /* Remain slave */
+		hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, ACCEPT_CONN_REQ_CP_SIZE, &ac);
+	} else {
+		/* Connection rejected by upper layer */
+		/* FIXME: 
+		 * Should we use HCI reject here ?
+		 */
+		return;
+	}
+}
+
+/* Connect Complete */
+static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	evt_conn_complete *cc = (evt_conn_complete *) skb->data;
+	struct hci_conn *conn = NULL;
+	struct hci_proto *hp;
+
+	DBG("%s", hdev->name);
+
+	tasklet_disable(&hdev->tx_task);
+
+	if (!cc->status)
+ 		conn = hci_conn_add(hdev, __le16_to_cpu(cc->handle), &cc->bdaddr);
+
+	/* Notify upper protocols */
+	if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm)
+		hp->connect_cfm(hdev, &cc->bdaddr, cc->status, conn);
+
+	tasklet_enable(&hdev->tx_task);
+}
+
+/* Disconnect Complete */
+static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	evt_disconn_complete *dc = (evt_disconn_complete *) skb->data;
+	struct hci_conn *conn = NULL;
+	struct hci_proto *hp;
+	__u16 handle = __le16_to_cpu(dc->handle);
+
+	DBG("%s", hdev->name);
+
+	if (!dc->status && (conn = conn_hash_lookup(&hdev->conn_hash, handle))) {
+		tasklet_disable(&hdev->tx_task);
+
+		/* Notify upper protocols */
+		if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind)
+			hp->disconn_ind(conn, dc->reason);
+
+		hci_conn_del(hdev, conn);
+
+		tasklet_enable(&hdev->tx_task);
+	}
+}
+
+/* Number of completed packets */
+static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data;
+	__u16 *ptr;
+	int i;
+
+	skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE);
+
+	DBG("%s num_hndl %d", hdev->name, nc->num_hndl);
+
+	if (skb->len < nc->num_hndl * 4) {
+		DBG("%s bad parameters", hdev->name);
+		return;
+	}
+
+	tasklet_disable(&hdev->tx_task);
+
+	for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) {
+		struct hci_conn *conn;
+		__u16 handle, count;
+
+		handle = __le16_to_cpu(*ptr++);
+		count  = __le16_to_cpu(*ptr++);
+
+		hdev->acl_cnt += count;
+
+		if ((conn = conn_hash_lookup(&hdev->conn_hash, handle)))
+			conn->acl_sent -= count;
+	}
+
+	tasklet_enable(&hdev->tx_task);
+	
+	hci_sched_tx(hdev);
+}
+
+static __inline__ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	hci_event_hdr *he = (hci_event_hdr *) skb->data;
+	evt_cmd_status *cs;
+	evt_cmd_complete *ec;
+	__u16 opcode, ocf, ogf;
+
+	skb_pull(skb, HCI_EVENT_HDR_SIZE);
+
+	DBG("%s evt 0x%x", hdev->name, he->evt);
+
+	switch (he->evt) {
+	case EVT_NUM_COMP_PKTS:
+		hci_num_comp_pkts_evt(hdev, skb);
+		break;
+
+	case EVT_INQUIRY_COMPLETE:
+		hci_inquiry_complete_evt(hdev, skb);
+		break;
+
+	case EVT_INQUIRY_RESULT:
+		hci_inquiry_result_evt(hdev, skb);
+		break;
+
+	case EVT_CONN_REQUEST:
+		hci_conn_request_evt(hdev, skb);
+		break;
+
+	case EVT_CONN_COMPLETE:
+		hci_conn_complete_evt(hdev, skb);
+		break;
+
+	case EVT_DISCONN_COMPLETE:
+		hci_disconn_complete_evt(hdev, skb);
+		break;
+
+	case EVT_CMD_STATUS:
+		cs = (evt_cmd_status *) skb->data;
+		skb_pull(skb, EVT_CMD_STATUS_SIZE);
+				
+		opcode = __le16_to_cpu(cs->opcode);
+		ogf = cmd_opcode_ogf(opcode);
+		ocf = cmd_opcode_ocf(opcode);
+
+		if (cs->ncmd) {
+			atomic_set(&hdev->cmd_cnt, 1);
+			hci_sched_cmd(hdev);
+		}
+
+		switch (ogf) {
+		case OGF_INFO_PARAM:
+			hci_cs_info_param(hdev, ocf, cs->status);
+			break;
+
+		case OGF_HOST_CTL:
+			hci_cs_host_ctl(hdev, ocf, cs->status);
+			break;
+
+		case OGF_LINK_CTL:
+			hci_cs_link_ctl(hdev, ocf, cs->status);
+			break;
+
+		case OGF_LINK_POLICY:
+			hci_cs_link_policy(hdev, ocf, cs->status);
+			break;
+
+		default:
+			DBG("%s Command Status OGF %x", hdev->name, ogf);
+			break;
+		};
+
+		break;
+
+	case EVT_CMD_COMPLETE:
+		ec = (evt_cmd_complete *) skb->data;
+		skb_pull(skb, EVT_CMD_COMPLETE_SIZE);
+
+		opcode = __le16_to_cpu(ec->opcode);
+		ogf = cmd_opcode_ogf(opcode);
+		ocf = cmd_opcode_ocf(opcode);
+
+		if (ec->ncmd) {
+			atomic_set(&hdev->cmd_cnt, 1);
+			hci_sched_cmd(hdev);
+		}
+
+		switch (ogf) {
+		case OGF_INFO_PARAM:
+			hci_cc_info_param(hdev, ocf, skb);
+			break;
+
+		case OGF_HOST_CTL:
+			hci_cc_host_ctl(hdev, ocf, skb);
+			break;
+
+		case OGF_LINK_CTL:
+			hci_cc_link_ctl(hdev, ocf, skb);
+			break;
+
+		case OGF_LINK_POLICY:
+			hci_cc_link_policy(hdev, ocf, skb);
+			break;
+
+		default:
+			DBG("%s Command Completed OGF %x", hdev->name, ogf);
+			break;
+		};
+
+		break;
+	};
+
+	bluez_skb_free(skb);
+	hdev->stat.evt_rx++;
+}
+
+/* ACL data packet */
+static __inline__ void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	hci_acl_hdr *ah = (void *) skb->data;
+	struct hci_conn *conn;
+	__u16 handle, flags;
+
+	skb_pull(skb, HCI_ACL_HDR_SIZE);
+
+	handle = __le16_to_cpu(ah->handle);
+	flags  = acl_flags(handle);
+	handle = acl_handle(handle);
+
+	DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
+
+	if ((conn = conn_hash_lookup(&hdev->conn_hash, handle))) {
+		struct hci_proto *hp;
+
+		/* Send to upper protocol */
+		if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->recv_acldata)
+			hp->recv_acldata(conn, skb, flags);
+		else
+			bluez_skb_free(skb);
+	}
+
+	hdev->stat.acl_rx++;
+}
+
+/* SCO data packet */
+static __inline__ void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	hci_sco_hdr *sh = (void *) skb->data;
+	struct hci_conn *conn;
+
+	skb_pull(skb, HCI_SCO_HDR_SIZE);
+
+	DBG("%s len %d", hdev->name, skb->len);
+
+	if ((conn = conn_hash_lookup(&hdev->conn_hash, __le16_to_cpu(sh->handle)))) {
+		struct hci_proto *hp;
+
+		/* Send to upper protocol */
+		if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->recv_acldata)
+			hp->recv_scodata(conn, skb);
+		else
+			bluez_skb_free(skb);
+	}
+
+	hdev->stat.sco_rx++;
+}
+
+/* ----- HCI tasks ----- */
+void hci_rx_task(unsigned long arg)
+{
+	struct hci_dev *hdev = (struct hci_dev *) arg;
+	struct sk_buff *skb;
+
+	DBG("%s", hdev->name);
+
+	read_lock(&hci_task_lock);
+
+	while ((skb = skb_dequeue(&hdev->rx_q))) {
+		if (hdev->flags & HCI_SOCK) {
+			/* Send copy to the sockets */
+			hci_send_to_sock(hdev, skb);
+		}
+
+		if (hdev->flags & HCI_INIT) {
+			/* Don't process data packets in this states. */
+			switch (skb->pkt_type) {
+			case HCI_ACLDATA_PKT:
+			case HCI_SCODATA_PKT:
+				bluez_skb_free(skb);
+				continue;
+			};
+		}
+
+		if (hdev->flags & HCI_NORMAL) {
+			/* Handle frame */
+			switch (skb->pkt_type) {
+			case HCI_EVENT_PKT:
+				hci_event_packet(hdev, skb);
+				break;
+
+			case HCI_ACLDATA_PKT:
+				DBG("%s ACL data packet", hdev->name);
+				hci_acldata_packet(hdev, skb);
+				break;
+
+			case HCI_SCODATA_PKT:
+				DBG("%s SCO data packet", hdev->name);
+				hci_scodata_packet(hdev, skb);
+				break;
+
+			default:
+				bluez_skb_free(skb);
+				break;
+			};
+		} else {
+			bluez_skb_free(skb);
+		}
+	}
+
+	read_unlock(&hci_task_lock);
+}
+
+static void hci_tx_task(unsigned long arg)
+{
+	struct hci_dev *hdev = (struct hci_dev *) arg;
+	struct sk_buff *skb;
+
+	read_lock(&hci_task_lock);
+
+	DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt);
+
+	/* Schedule queues and send stuff to HCI driver */
+
+	hci_sched_acl(hdev);
+
+	hci_sched_sco(hdev);
+
+	/* Send next queued raw(unknown type) packet */
+	while ((skb = skb_dequeue(&hdev->raw_q)))
+		hci_send_frame(skb);
+
+	read_unlock(&hci_task_lock);
+}
+
+static void hci_cmd_task(unsigned long arg)
+{
+	struct hci_dev *hdev = (struct hci_dev *) arg;
+	struct sk_buff *skb;
+
+	DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
+
+	/* Send queued commands */
+	if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) {
+		if (hdev->cmd_sent)
+			bluez_skb_free(hdev->cmd_sent);
+
+		if ((hdev->cmd_sent = bluez_skb_clone(skb, GFP_ATOMIC))) {
+			atomic_dec(&hdev->cmd_cnt);
+			hci_send_frame(skb);
+		} else {
+			skb_queue_head(&hdev->cmd_q, skb);
+			hci_sched_cmd(hdev);
+		}
+	}
+}
+
+/* Receive frame from HCI drivers */
+int hci_recv_frame(struct sk_buff *skb)
+{
+	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+
+	if (!hdev || !(hdev->flags & (HCI_UP | HCI_INIT))) {
+		bluez_skb_free(skb);
+		return -1;
+	}
+
+	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
+
+	/* Incomming skb */
+	bluez_cb(skb)->incomming = 1;
+
+	/* Queue frame for rx task */
+	skb_queue_tail(&hdev->rx_q, skb);
+	hci_sched_rx(hdev);
+
+	return 0;
+}
+
+/* ----- HCI Ioctl helpers ----- */
+int hci_dev_reset(__u16 dev)
+{
+	struct hci_dev *hdev;
+	int ret = 0;
+
+	if (!(hdev = hci_dev_get(dev)))
+		return -ENODEV;
+
+	hci_req_lock(hdev);
+	tasklet_disable(&hdev->tx_task);
+
+	if (!(hdev->flags & HCI_UP))
+		goto done;
+
+	/* Drop queues */
+	bluez_skb_queue_purge(&hdev->rx_q);
+	bluez_skb_queue_purge(&hdev->cmd_q);
+
+	inquiry_cache_flush(&hdev->inq_cache);
+
+	hci_conn_hash_flush(hdev);
+
+	if (hdev->flush)
+		hdev->flush(hdev);
+
+	atomic_set(&hdev->cmd_cnt, 1); 
+	hdev->acl_cnt = 0; hdev->sco_cnt = 0;
+
+	ret = __hci_request(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT);
+
+done:
+	tasklet_enable(&hdev->tx_task);
+	hci_req_unlock(hdev);
+	hci_dev_put(hdev);
+
+	return ret;
+}
+
+int hci_dev_reset_stat(__u16 dev)
+{
+	struct hci_dev *hdev;
+	int ret = 0;
+
+	if (!(hdev = hci_dev_get(dev)))
+		return -ENODEV;
+
+	memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
+
+	hci_dev_put(hdev);
+
+	return ret;
+}
+
+int hci_dev_setauth(unsigned long arg)
+{
+	struct hci_dev *hdev;
+	struct hci_dev_req dr;
+	int ret = 0;
+
+	if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
+		return -EFAULT;
+
+	if (!(hdev = hci_dev_get(dr.dev_id)))
+		return -ENODEV;
+
+	ret = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);
+
+	hci_dev_put(hdev);
+
+	return ret;
+}
+
+int hci_dev_setscan(unsigned long arg)
+{
+	struct hci_dev *hdev;
+	struct hci_dev_req dr;
+	int ret = 0;
+
+	if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
+		return -EFAULT;
+
+	if (!(hdev = hci_dev_get(dr.dev_id)))
+		return -ENODEV;
+
+	ret = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);
+
+	hci_dev_put(hdev);
+
+	return ret;
+}
+
+int hci_dev_list(unsigned long arg)
+{
+	struct hci_dev_list_req *dl;
+	struct hci_dev_req *dr;
+	struct hci_dev *hdev;
+	int i, n, size;
+	__u16 dev_num;
+
+	if (get_user(dev_num, (__u16 *) arg))
+		return -EFAULT;
+
+	size = dev_num * sizeof(struct hci_dev_req) + sizeof(__u16);
+
+	if (verify_area(VERIFY_WRITE, (void *) arg, size))
+		return -EFAULT;
+
+	if (!(dl = kmalloc(size, GFP_KERNEL)))
+		return -ENOMEM;
+	dr = dl->dev_req;
+
+	spin_lock_bh(&hdev_list_lock);
+	for (i = 0, n = 0; i < HCI_MAX_DEV && n < dev_num; i++) {
+		if ((hdev = hdev_list[i])) {
+			(dr + n)->dev_id  = hdev->id;
+			(dr + n)->dev_opt = hdev->flags;
+			n++;
+		}
+	}
+	spin_unlock_bh(&hdev_list_lock);
+
+	dl->dev_num = n;
+	size = n * sizeof(struct hci_dev_req) + sizeof(__u16);
+
+	copy_to_user((void *) arg, dl, size);
+
+	return 0;
+}
+
+int hci_dev_info(unsigned long arg)
+{
+	struct hci_dev *hdev;
+	struct hci_dev_info di;
+	int err = 0;
+
+	if (copy_from_user(&di, (void *) arg, sizeof(di)))
+		return -EFAULT;
+
+	if (!(hdev = hci_dev_get(di.dev_id)))
+		return -ENODEV;
+
+	strcpy(di.name, hdev->name);
+	di.type    = hdev->type;
+	di.flags   = hdev->flags;
+	di.acl_mtu = hdev->acl_mtu;
+	di.acl_max = hdev->acl_max;
+	di.sco_mtu = hdev->sco_mtu;
+	di.sco_max = hdev->sco_max;
+	di.bdaddr  = hdev->bdaddr;
+
+	memcpy(&di.stat, &hdev->stat, sizeof(di.stat));
+
+	if (copy_to_user((void *) arg, &di, sizeof(di)))
+		err = -EFAULT;
+
+	hci_dev_put(hdev);
+
+	return err;
+}
+
+__u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode)
+{
+	__u32 omode = hdev->flags & HCI_MODE_MASK;
+
+	hdev->flags &= ~HCI_MODE_MASK;
+	hdev->flags |= (mode & HCI_MODE_MASK);
+
+	return omode;
+}
+
+__u32 hci_dev_getmode(struct hci_dev *hdev)
+{
+	return hdev->flags & HCI_MODE_MASK;
+}
+
+int hci_inquiry(unsigned long arg)
+{
+	struct inquiry_cache *cache;
+	struct hci_inquiry_req ir;
+	struct hci_dev *hdev;
+	int err = 0, do_inquiry = 0;
+	long timeo;
+	__u8 *buf, *ptr;
+
+	ptr = (void *) arg;
+	if (copy_from_user(&ir, ptr, sizeof(ir)))
+		return -EFAULT;
+
+	if (!(hdev = hci_dev_get(ir.dev_id)))
+		return -ENODEV;
+
+	cache = &hdev->inq_cache;
+
+	inquiry_cache_lock(cache);
+	if (inquiry_cache_age(cache) > INQUIRY_CACHE_AGE_MAX || ir.flags & IREQ_CACHE_FLUSH) {
+		inquiry_cache_flush(cache);
+		do_inquiry = 1;
+	}
+	inquiry_cache_unlock(cache);
+
+	timeo = ir.length * 2 * HZ;
+	if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
+		goto done;
+
+	/* cache_dump can't sleep. Therefore we allocate temp buffer and then
+	 * copy it to the user space.
+	 */
+	if (!(buf = kmalloc(sizeof(inquiry_info) * ir.num_rsp, GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto done;
+	}
+	ir.num_rsp = inquiry_cache_dump(cache, ir.num_rsp, buf);
+
+	DBG("num_rsp %d", ir.num_rsp);
+
+	if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + (sizeof(inquiry_info) * ir.num_rsp))) {
+		copy_to_user(ptr, &ir, sizeof(ir));
+		ptr += sizeof(ir);
+	        copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp);
+	} else 
+		err = -EFAULT;
+
+	kfree(buf);
+
+done:
+	hci_dev_put(hdev);
+
+	return err;
+}
+
+int hci_core_init(void)
+{
+	/* Init locks */
+	spin_lock_init(&hdev_list_lock);
+
+	return 0;
+}
+
+int hci_core_cleanup(void)
+{
+	return 0;
+}
diff -u --recursive --new-file v2.4.5/linux/net/bluetooth/hci_sock.c linux/net/bluetooth/hci_sock.c
--- v2.4.5/linux/net/bluetooth/hci_sock.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bluetooth/hci_sock.c	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,511 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * BlueZ HCI socket layer.
+ *
+ * $Id: hci_sock.c,v 1.1 2001/06/01 08:12:11 davem Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <linux/socket.h>
+#include <linux/ioctl.h>
+#include <net/sock.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/bluez.h>
+#include <net/bluetooth/hci_core.h>
+
+#ifndef HCI_SOCK_DEBUG
+#undef  DBG
+#define DBG( A... )
+#endif
+
+/* HCI socket interface */
+
+static struct bluez_sock_list hci_sk_list = {
+	lock: RW_LOCK_UNLOCKED
+};
+
+static struct sock *hci_sock_lookup(struct hci_dev *hdev)
+{
+	struct sock *sk;
+
+	read_lock(&hci_sk_list.lock);
+	for (sk = hci_sk_list.head; sk; sk = sk->next) {
+		if (hci_pi(sk)->hdev == hdev)
+			break;
+	}
+	read_unlock(&hci_sk_list.lock);
+	return sk;
+}
+
+/* Send frame to RAW socket */
+void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct sk_buff *nskb;
+	struct sock * sk;
+
+	DBG("hdev %p len %d", hdev, skb->len);
+
+	read_lock(&hci_sk_list.lock);
+	for (sk = hci_sk_list.head; sk; sk = sk->next) {
+		if (sk->state != BT_BOUND || hci_pi(sk)->hdev != hdev)
+			continue;
+
+		/* Don't send frame to the socket it came from */
+		if (skb->sk == sk)
+			continue;
+
+		if (!(nskb = bluez_skb_clone(skb, GFP_ATOMIC)))
+			continue;
+
+		/* Put type byte before the data */
+		memcpy(skb_push(nskb, 1), &nskb->pkt_type, 1);
+
+		skb_queue_tail(&sk->receive_queue, nskb);
+		sk->data_ready(sk, nskb->len);
+	}
+	read_unlock(&hci_sk_list.lock);
+}
+
+static int hci_sock_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+	struct hci_dev *hdev = hci_pi(sk)->hdev;
+
+	DBG("sock %p sk %p", sock, sk);
+
+	if (!sk)
+		return 0;
+
+	bluez_sock_unlink(&hci_sk_list, sk);
+
+	if (hdev) {
+		if (!hci_sock_lookup(hdev))
+			hdev->flags &= ~HCI_SOCK;
+
+		hci_dev_put(hdev);
+	}
+
+	sock_orphan(sk);
+
+	bluez_skb_queue_purge(&sk->receive_queue);
+	bluez_skb_queue_purge(&sk->write_queue);
+
+	sock_put(sk);
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	struct sock *sk = sock->sk;
+	struct hci_dev *hdev = hci_pi(sk)->hdev;
+	__u32 mode;
+
+	DBG("cmd %x", cmd);
+
+	switch (cmd) {
+	case HCIGETINFO:
+		return hci_dev_info(arg);
+
+	case HCIGETDEVLIST:
+		return hci_dev_list(arg);
+
+	case HCIDEVUP:
+		if (!capable(CAP_NET_ADMIN))
+			return -EACCES;
+
+		return hci_dev_open(arg);
+
+	case HCIDEVDOWN:
+		if (!capable(CAP_NET_ADMIN))
+			return -EACCES;
+
+		return hci_dev_close(arg);
+
+	case HCIDEVRESET:
+		if (!capable(CAP_NET_ADMIN))
+			return -EACCES;
+
+		return hci_dev_reset(arg);
+
+	case HCIRESETSTAT:
+		if (!capable(CAP_NET_ADMIN))
+			return -EACCES;
+
+		return hci_dev_reset_stat(arg);
+
+	case HCISETSCAN:
+		if (!capable(CAP_NET_ADMIN))
+			return -EACCES;
+
+		return hci_dev_setscan(arg);
+
+	case HCISETAUTH:
+		if (!capable(CAP_NET_ADMIN))
+			return -EACCES;
+
+		return hci_dev_setauth(arg);
+
+	case HCISETRAW:
+		if (!capable(CAP_NET_ADMIN))
+			return -EACCES;
+
+		if (!hdev)
+			return -EBADFD;
+
+		if (arg)
+			mode = HCI_RAW;
+		else
+			mode = HCI_NORMAL;
+
+		return hci_dev_setmode(hdev, mode);
+
+	case HCIINQUIRY:
+		return hci_inquiry(arg);
+
+	default:
+		return -EINVAL;
+	};
+}
+
+static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+{
+	struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
+	struct sock *sk = sock->sk;
+	struct hci_dev *hdev = NULL;
+
+	DBG("sock %p sk %p", sock, sk);
+
+	if (!haddr || haddr->hci_family != AF_BLUETOOTH)
+		return -EINVAL;
+
+	if (hci_pi(sk)->hdev) {
+		/* Already bound */
+		return 0;
+	}
+
+	if (haddr->hci_dev != HCI_DEV_NONE) {
+		if (!(hdev = hci_dev_get(haddr->hci_dev)))
+			return -ENODEV;
+
+		hdev->flags |= HCI_SOCK;
+	}
+
+	hci_pi(sk)->hdev = hdev;
+	sk->state = BT_BOUND;
+
+	return 0;
+}
+
+static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer)
+{
+	struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
+	struct sock *sk = sock->sk;
+
+	DBG("sock %p sk %p", sock, sk);
+
+	*addr_len = sizeof(*haddr);
+	haddr->hci_family = AF_BLUETOOTH;
+	haddr->hci_dev    = hci_pi(sk)->hdev->id;
+
+	return 0;
+}
+
+static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+                            struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	struct hci_dev *hdev = hci_pi(sk)->hdev;
+	struct sk_buff *skb;
+	int err;
+
+	DBG("sock %p sk %p", sock, sk);
+
+	if (msg->msg_flags & MSG_OOB)
+		return -EOPNOTSUPP;
+
+	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
+		return -EINVAL;
+
+	if (!hdev)
+		return -EBADFD;
+
+	if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
+		return err;
+
+	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
+		kfree_skb(skb);
+		return -EFAULT;
+	}
+
+	skb->dev = (void *) hdev;
+	skb->pkt_type = *((unsigned char *) skb->data);
+	skb_pull(skb, 1);
+
+	/* Send frame to HCI core */
+	hci_send_raw(skb);
+
+	return len;
+}
+
+static __inline__ void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
+{
+	__u32 flags = hci_pi(sk)->cmsg_flags;
+
+	if (flags & HCI_CMSG_DIR)
+        	put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(int), &bluez_cb(skb)->incomming);
+}
+ 
+static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len,
+                            int flags, struct scm_cookie *scm)
+{
+	int noblock = flags & MSG_DONTWAIT;
+	struct sock *sk = sock->sk;
+	struct sk_buff *skb;
+	int copied, err;
+
+	DBG("sock %p sk %p", sock, sk);
+
+	if (flags & (MSG_OOB | MSG_PEEK))
+		return -EOPNOTSUPP;
+
+	if (!(skb = skb_recv_datagram(sk, flags, noblock, &err)))
+		return err;
+
+	msg->msg_namelen = 0;
+
+	copied = skb->len;
+	if (len < copied) {
+		msg->msg_flags |= MSG_TRUNC;
+		copied = len;
+	}
+
+	skb->h.raw = skb->data;
+	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+
+	if (hci_pi(sk)->cmsg_flags)
+		hci_sock_cmsg(sk, msg, skb);
+
+	skb_free_datagram(sk, skb);
+
+	return err ? : copied;
+}
+
+int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+{
+	struct sock *sk = sock->sk;
+	int err = 0, opt;
+
+	if (get_user(opt, (int *)optval))
+		return -EFAULT;
+
+	DBG("sk %p, opt %d", sk, opt);
+
+	lock_sock(sk);
+
+	switch (optname) {
+	case HCI_DATA_DIR:
+		if (opt)
+			hci_pi(sk)->cmsg_flags |= HCI_CMSG_DIR;
+		else
+			hci_pi(sk)->cmsg_flags &= ~HCI_CMSG_DIR;
+		break;
+
+	default:
+		err = -ENOPROTOOPT;
+		break;
+	};
+
+	release_sock(sk);
+	return err;
+}
+
+int hci_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+{
+	struct sock *sk = sock->sk;
+	int len, opt; 
+
+	if (get_user(len, optlen))
+		return -EFAULT;
+
+	switch (optname) {
+	case HCI_DATA_DIR:
+		if (hci_pi(sk)->cmsg_flags & HCI_CMSG_DIR)
+			opt = 1;
+		else 
+			opt = 0;
+
+		if (put_user(opt, optval))
+			return -EFAULT;
+		break;
+
+	default:
+		return -ENOPROTOOPT;
+		break;
+	};
+
+	return 0;
+}
+
+struct proto_ops hci_sock_ops = {
+	family:		PF_BLUETOOTH,
+	release:	hci_sock_release,
+	bind:		hci_sock_bind,
+	getname:	hci_sock_getname,
+	sendmsg:	hci_sock_sendmsg,
+	recvmsg:	hci_sock_recvmsg,
+	ioctl:		hci_sock_ioctl,
+	poll:		datagram_poll,
+	listen:		sock_no_listen,
+	shutdown:	sock_no_shutdown,
+	setsockopt:	hci_sock_setsockopt,
+	getsockopt:	hci_sock_getsockopt,
+	connect:	sock_no_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		sock_no_accept,
+	mmap:		sock_no_mmap
+};
+
+static int hci_sock_create(struct socket *sock, int protocol)
+{
+	struct sock *sk;
+
+	DBG("sock %p", sock);
+
+	if (sock->type != SOCK_RAW)
+		return -ESOCKTNOSUPPORT;
+
+	sock->ops = &hci_sock_ops;
+
+	if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1)))
+		return -ENOMEM;
+
+	sock->state = SS_UNCONNECTED;
+	sock_init_data(sock, sk);
+
+	memset(&sk->protinfo, 0, sizeof(struct hci_pinfo));
+	sk->destruct = NULL;
+	sk->protocol = protocol;
+	sk->state    = BT_OPEN;
+
+	bluez_sock_link(&hci_sk_list, sk);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+	struct hci_dev *hdev = (struct hci_dev *) ptr;
+	struct sk_buff *skb;
+
+	DBG("hdev %s event %ld", hdev->name, event);
+
+	/* Send event to sockets */
+	if ((skb = bluez_skb_alloc(HCI_EVENT_HDR_SIZE + EVT_HCI_DEV_EVENT_SIZE, GFP_ATOMIC))) {
+		hci_event_hdr eh = { EVT_HCI_DEV_EVENT, EVT_HCI_DEV_EVENT_SIZE };
+		evt_hci_dev_event he = { event, hdev->id };
+
+		skb->pkt_type = HCI_EVENT_PKT;
+		memcpy(skb_put(skb, HCI_EVENT_HDR_SIZE), &eh, HCI_EVENT_HDR_SIZE);
+		memcpy(skb_put(skb, EVT_HCI_DEV_EVENT_SIZE), &he, EVT_HCI_DEV_EVENT_SIZE);
+
+		hci_send_to_sock(NULL, skb);
+		bluez_skb_free(skb);
+	}
+
+	if (event == HCI_DEV_UNREG) {
+		struct sock *sk;
+
+		/* Detach sockets from device */
+		read_lock(&hci_sk_list.lock);
+		for (sk = hci_sk_list.head; sk; sk = sk->next) {
+			if (hci_pi(sk)->hdev == hdev) {
+				hci_pi(sk)->hdev = NULL;
+				sk->err = EPIPE;
+				sk->state = BT_OPEN;
+				sk->state_change(sk);
+
+				hci_dev_put(hdev);
+			}
+		}
+		read_unlock(&hci_sk_list.lock);
+	}
+
+	return NOTIFY_DONE;
+}
+
+struct net_proto_family hci_sock_family_ops = {
+	family: PF_BLUETOOTH,
+	create: hci_sock_create
+};
+
+struct notifier_block hci_sock_nblock = {
+	notifier_call: hci_sock_dev_event
+};
+
+int hci_sock_init(void)
+{
+	if (bluez_sock_register(BTPROTO_HCI, &hci_sock_family_ops)) {
+		ERR("Can't register HCI socket");
+		return -EPROTO;
+	}
+
+	hci_register_notifier(&hci_sock_nblock);
+
+	return 0;
+}
+
+int hci_sock_cleanup(void)
+{
+	if (bluez_sock_unregister(BTPROTO_HCI))
+		ERR("Can't unregister HCI socket");
+
+	hci_unregister_notifier(&hci_sock_nblock);
+
+	return 0;
+}
diff -u --recursive --new-file v2.4.5/linux/net/bluetooth/l2cap_core.c linux/net/bluetooth/l2cap_core.c
--- v2.4.5/linux/net/bluetooth/l2cap_core.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bluetooth/l2cap_core.c	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,2202 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * BlueZ L2CAP core and sockets.
+ *
+ * $Id: l2cap_core.c,v 1.1 2001/06/01 08:12:11 davem Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/list.h>
+#include <net/sock.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/bluez.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
+#include <net/bluetooth/l2cap_core.h>
+
+#ifndef L2CAP_DEBUG
+#undef  DBG
+#define DBG( A... )
+#endif
+
+struct proto_ops l2cap_sock_ops;
+
+struct bluez_sock_list l2cap_sk_list = {
+	lock: RW_LOCK_UNLOCKED
+};
+
+struct list_head l2cap_iff_list = LIST_HEAD_INIT(l2cap_iff_list);
+rwlock_t l2cap_rt_lock = RW_LOCK_UNLOCKED;
+
+static int  l2cap_conn_del(struct l2cap_conn *conn, int err);
+
+static __inline__ void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
+static void l2cap_chan_del(struct sock *sk, int err);
+static int  l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len);
+
+static void l2cap_sock_close(struct sock *sk);
+static void l2cap_sock_kill(struct sock *sk);
+
+static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data);
+static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data);
+
+/* -------- L2CAP interfaces & routing --------- */
+/* Add/delete L2CAP interface.
+ * Must be called with locked rt_lock
+ */ 
+
+static void l2cap_iff_add(struct hci_dev *hdev)
+{
+	struct l2cap_iff *iff;
+
+	DBG("%s", hdev->name);
+
+	DBG("iff_list %p next %p prev %p", &l2cap_iff_list, l2cap_iff_list.next, l2cap_iff_list.prev);
+
+	/* Allocate new interface and lock HCI device */
+	if (!(iff = kmalloc(sizeof(struct l2cap_iff), GFP_KERNEL))) {
+		ERR("Can't allocate new interface %s", hdev->name);
+		return;
+	}
+	memset(iff, 0, sizeof(struct l2cap_iff));
+
+	hci_dev_hold(hdev);
+	hdev->l2cap_data = iff;
+	iff->hdev   = hdev;
+	iff->mtu    = hdev->acl_mtu - HCI_ACL_HDR_SIZE;
+	iff->bdaddr = &hdev->bdaddr;
+
+	spin_lock_init(&iff->lock);
+	INIT_LIST_HEAD(&iff->conn_list);
+
+	list_add(&iff->list, &l2cap_iff_list);
+}
+
+static void l2cap_iff_del(struct hci_dev *hdev)
+{
+	struct l2cap_iff *iff;
+
+	if (!(iff = hdev->l2cap_data))
+		return;
+
+	DBG("%s iff %p", hdev->name, iff);
+
+	list_del(&iff->list);
+
+	l2cap_iff_lock(iff);
+
+	/* Drop connections */
+	while (!list_empty(&iff->conn_list)) {
+		struct l2cap_conn *c;
+
+		c = list_entry(iff->conn_list.next, struct l2cap_conn, list);
+		l2cap_conn_del(c, ENODEV);
+	}
+
+	l2cap_iff_unlock(iff);
+
+	/* Unlock HCI device */
+	hdev->l2cap_data = NULL;
+	hci_dev_put(hdev);
+
+	kfree(iff);
+}
+
+/* Get route. Returns L2CAP interface.
+ * Must be called with locked rt_lock
+ */
+static struct l2cap_iff *l2cap_get_route(bdaddr_t *src, bdaddr_t *dst)
+{
+	struct list_head *p;
+	int use_src;
+
+	DBG("%s -> %s", batostr(src), batostr(dst));
+
+	use_src = bacmp(src, BDADDR_ANY) ? 0 : 1;
+	
+	/* Simple routing: 
+	 * 	No source address - find interface with bdaddr != dst 
+	 *	Source address 	  - find interface with bdaddr == src 
+	 */
+
+	list_for_each(p, &l2cap_iff_list) {
+		struct l2cap_iff *iff;
+
+		iff = list_entry(p, struct l2cap_iff, list);
+
+		if (use_src && !bacmp(iff->bdaddr, src))
+			return iff;
+		else if (bacmp(iff->bdaddr, dst))
+			return iff;
+	}
+	return NULL;
+}
+
+/* ----- L2CAP timers ------ */
+static void l2cap_timeout(unsigned long arg)
+{
+	struct sock *sk = (struct sock *) arg;
+
+	DBG("sock %p state %d", sk, sk->state);
+
+	bh_lock_sock(sk);
+	switch (sk->state) {
+	case BT_DISCONN:
+		l2cap_chan_del(sk, ETIMEDOUT);
+		break;
+
+	default:
+		sk->err = ETIMEDOUT;
+		sk->state_change(sk);
+		break;
+	};
+	bh_unlock_sock(sk);
+
+	l2cap_sock_kill(sk);
+	sock_put(sk);
+}
+
+static void l2cap_set_timer(struct sock *sk, long timeout)
+{
+	DBG("sock %p state %d timeout %ld", sk, sk->state, timeout);
+
+	if (!mod_timer(&sk->timer, jiffies + timeout))
+		sock_hold(sk);
+}
+
+static void l2cap_clear_timer(struct sock *sk)
+{
+	DBG("sock %p state %d", sk, sk->state);
+
+	if (timer_pending(&sk->timer) && del_timer(&sk->timer))
+		__sock_put(sk);
+}
+
+static void l2cap_init_timer(struct sock *sk)
+{
+	init_timer(&sk->timer);
+	sk->timer.function = l2cap_timeout;
+	sk->timer.data = (unsigned long)sk;
+}
+
+/* -------- L2CAP connections --------- */
+/* Add new connection to the interface.
+ * Interface must be locked
+ */
+static struct l2cap_conn *l2cap_conn_add(struct l2cap_iff *iff, bdaddr_t *dst)
+{
+	struct l2cap_conn *conn;
+	bdaddr_t *src = iff->bdaddr;
+
+	if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_KERNEL)))
+		return NULL;
+
+	memset(conn, 0, sizeof(struct l2cap_conn));
+
+	conn->state = BT_OPEN;
+	conn->iff   = iff;
+	bacpy(&conn->src, src);
+	bacpy(&conn->dst, dst);
+
+	spin_lock_init(&conn->lock);
+	conn->chan_list.lock = RW_LOCK_UNLOCKED;
+
+	__l2cap_conn_link(iff, conn);
+
+	DBG("%s -> %s, %p", batostr(src), batostr(dst), conn);
+
+	MOD_INC_USE_COUNT;
+
+	return conn;
+}
+
+/* Delete connection on the interface.
+ * Interface must be locked
+ */
+static int l2cap_conn_del(struct l2cap_conn *conn, int err)
+{
+	struct sock *sk;
+
+	DBG("conn %p, state %d, err %d", conn, conn->state, err);
+
+	__l2cap_conn_unlink(conn->iff, conn);
+
+	conn->state = BT_CLOSED;
+
+	if (conn->rx_skb)
+		bluez_skb_free(conn->rx_skb);
+
+	/* Kill channels */
+	while ((sk = conn->chan_list.head)) {
+		bh_lock_sock(sk);
+		l2cap_clear_timer(sk);
+		l2cap_chan_del(sk, err);
+		bh_unlock_sock(sk);
+
+		l2cap_sock_kill(sk);
+	}
+
+	kfree(conn);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static __inline__ struct l2cap_conn *l2cap_get_conn_by_addr(struct l2cap_iff *iff, bdaddr_t *dst)
+{
+	struct list_head *p;
+
+	list_for_each(p, &iff->conn_list){
+		struct l2cap_conn *c;
+
+		c = list_entry(p, struct l2cap_conn, list);
+		if (!bacmp(&c->dst, dst))
+			return c;
+	}
+	return NULL;
+}
+
+int l2cap_connect(struct sock *sk)
+{
+	bdaddr_t *src = &l2cap_pi(sk)->src;
+	bdaddr_t *dst = &l2cap_pi(sk)->dst;
+	struct l2cap_conn *conn;
+	struct l2cap_iff *iff;
+	int err = 0;
+
+	DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
+
+	read_lock_bh(&l2cap_rt_lock);
+
+	/* Get route to remote BD address */
+	if (!(iff = l2cap_get_route(src, dst))) {
+		err = -EHOSTUNREACH;
+		goto done;
+	}
+
+	/* Update source addr of the socket */
+	bacpy(src, iff->bdaddr);
+
+	l2cap_iff_lock(iff);
+
+	if (!(conn = l2cap_get_conn_by_addr(iff, dst))) {
+		/* Connection doesn't exist */
+		if (!(conn = l2cap_conn_add(iff, dst))) {
+			l2cap_iff_unlock(iff);
+			err = -ENOMEM;
+			goto done;
+		}
+		conn->out = 1;
+	}
+
+	l2cap_iff_unlock(iff);
+
+	l2cap_chan_add(conn, sk, NULL);
+
+	sk->state = BT_CONNECT;
+	l2cap_set_timer(sk, sk->sndtimeo);
+
+	switch (conn->state) {
+	case BT_CONNECTED:
+		if (sk->type == SOCK_SEQPACKET) {
+			l2cap_conn_req req;
+			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+			req.psm  = l2cap_pi(sk)->psm;
+			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
+		} else {
+			sk->state = BT_CONNECTED;
+			l2cap_clear_timer(sk);
+		}
+		break;
+
+	case BT_CONNECT:
+		break;
+
+	default:
+		/* Create ACL connection */
+		conn->state = BT_CONNECT;
+		hci_connect(iff->hdev, dst);
+		break;
+	};
+
+done:
+	read_unlock_bh(&l2cap_rt_lock);
+
+	return err;
+}
+
+/* ------ Channel queues for listening sockets ------ */
+void l2cap_accept_queue(struct sock *parent, struct sock *sk)
+{
+	struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
+
+	DBG("parent %p, sk %p", parent, sk);
+
+	sock_hold(sk);
+	l2cap_pi(sk)->parent = parent;
+	l2cap_pi(sk)->next_q = NULL;
+
+	if (!q->head) {
+		q->head = q->tail = sk;
+	} else {
+		struct sock *tail = q->tail;
+
+		l2cap_pi(sk)->prev_q = tail;
+		l2cap_pi(tail)->next_q = sk;
+		q->tail = sk;
+	}
+
+	parent->ack_backlog++;
+}
+
+void l2cap_accept_unlink(struct sock *sk)
+{
+	struct sock *parent = l2cap_pi(sk)->parent;
+	struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
+	struct sock *next, *prev;
+
+	DBG("sk %p", sk);
+
+	next = l2cap_pi(sk)->next_q;
+	prev = l2cap_pi(sk)->prev_q;
+
+	if (sk == q->head)
+		q->head = next;
+	if (sk == q->tail)
+		q->tail = prev;
+
+	if (next)
+		l2cap_pi(next)->prev_q = prev;
+	if (prev)
+		l2cap_pi(prev)->next_q = next;
+
+	l2cap_pi(sk)->parent = NULL;
+
+	parent->ack_backlog--;
+	__sock_put(sk);
+}
+
+/* Get next connected channel in queue. */
+struct sock *l2cap_accept_dequeue(struct sock *parent, int state)
+{
+	struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
+	struct sock *sk;
+
+	for (sk = q->head; sk; sk = l2cap_pi(sk)->next_q){
+		if (!state || sk->state == state) {
+			l2cap_accept_unlink(sk);
+			break;
+		}
+	}
+
+	DBG("parent %p, sk %p", parent, sk);
+
+	return sk;
+}
+
+/* -------- Socket interface ---------- */
+static struct sock *__l2cap_get_sock_by_addr(struct sockaddr_l2 *addr)
+{
+	bdaddr_t *src = &addr->l2_bdaddr;
+	__u16 psm = addr->l2_psm;
+	struct sock *sk;
+
+	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
+		if (l2cap_pi(sk)->psm == psm &&
+		    !bacmp(&l2cap_pi(sk)->src, src))
+			break;
+	}
+
+	return sk;
+}
+
+/* Find socket listening on psm and source bdaddr.
+ * Returns closest match.
+ */
+static struct sock *l2cap_get_sock_listen(bdaddr_t *src, __u16 psm)
+{
+	struct sock *sk, *sk1 = NULL;
+
+	read_lock(&l2cap_sk_list.lock);
+
+	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
+		struct l2cap_pinfo *pi;
+
+		if (sk->state != BT_LISTEN)
+			continue;
+
+		pi = l2cap_pi(sk);
+
+		if (pi->psm == psm) {
+			/* Exact match. */
+			if (!bacmp(&pi->src, src))
+				break;
+
+			/* Closest match */
+			if (!bacmp(&pi->src, BDADDR_ANY))
+				sk1 = sk;
+		}
+	}
+
+	read_unlock(&l2cap_sk_list.lock);
+
+	return sk ? sk : sk1;
+}
+
+static void l2cap_sock_destruct(struct sock *sk)
+{
+	DBG("sk %p", sk);
+
+	bluez_skb_queue_purge(&sk->receive_queue);
+	bluez_skb_queue_purge(&sk->write_queue);
+
+	MOD_DEC_USE_COUNT;
+}
+
+static void l2cap_sock_cleanup_listen(struct sock *parent)
+{
+	struct sock *sk;
+
+	DBG("parent %p", parent);
+
+	/* Close not yet accepted channels */
+	while ((sk = l2cap_accept_dequeue(parent, 0)))
+		l2cap_sock_close(sk);
+
+	parent->state  = BT_CLOSED;
+	parent->zapped = 1;
+}
+
+/* Kill socket (only if zapped and orphan)
+ * Must be called on unlocked socket.
+ */
+static void l2cap_sock_kill(struct sock *sk)
+{
+	if (!sk->zapped || sk->socket)
+		return;
+
+	DBG("sk %p state %d", sk, sk->state);
+
+	/* Kill poor orphan */
+	bluez_sock_unlink(&l2cap_sk_list, sk);
+	sk->dead = 1;
+	sock_put(sk);
+}
+
+/* Close socket.
+ * Must be called on unlocked socket.
+ */
+static void l2cap_sock_close(struct sock *sk)
+{
+	struct l2cap_conn *conn;
+
+	lock_sock(sk);
+
+	conn = l2cap_pi(sk)->conn;
+
+	DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket);
+
+	switch (sk->state) {
+	case BT_LISTEN:
+		l2cap_sock_cleanup_listen(sk);
+		break;
+
+	case BT_CONNECTED:
+	case BT_CONFIG:
+		if (sk->type == SOCK_SEQPACKET) {
+			l2cap_disconn_req req;
+
+			sk->state = BT_DISCONN;
+
+			req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+			l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
+
+			l2cap_set_timer(sk, sk->sndtimeo);
+		} else {
+			l2cap_chan_del(sk, ECONNRESET);
+		}
+		break;
+
+	case BT_CONNECT:
+	case BT_DISCONN:
+		l2cap_chan_del(sk, ECONNRESET);
+		break;
+
+	default:
+		sk->zapped = 1;
+		break;
+	};
+
+	release_sock(sk);
+
+	l2cap_sock_kill(sk);
+}
+
+static void l2cap_sock_init(struct sock *sk, struct sock *parent)
+{
+	struct l2cap_pinfo *pi = l2cap_pi(sk);
+
+	DBG("sk %p", sk);
+
+	if (parent) {
+		sk->type = parent->type;
+
+		pi->imtu = l2cap_pi(parent)->imtu;
+		pi->omtu = l2cap_pi(parent)->omtu;
+	} else {
+		pi->imtu = L2CAP_DEFAULT_MTU;
+		pi->omtu = 0;
+	}
+
+	/* Default config options */
+	pi->conf_mtu = L2CAP_DEFAULT_MTU;
+	pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+}
+
+static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio)
+{
+	struct sock *sk;
+
+	if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
+		return NULL;
+
+	sock_init_data(sock, sk);
+
+	sk->zapped   = 0;
+
+	sk->destruct = l2cap_sock_destruct;
+	sk->sndtimeo = L2CAP_CONN_TIMEOUT;
+
+	sk->protocol = proto;
+	sk->state    = BT_OPEN;
+
+	l2cap_init_timer(sk);
+
+	bluez_sock_link(&l2cap_sk_list, sk);
+
+	MOD_INC_USE_COUNT;
+
+	return sk;
+}
+
+static int l2cap_sock_create(struct socket *sock, int protocol)
+{
+	struct sock *sk;
+
+	DBG("sock %p", sock);
+
+	sock->state = SS_UNCONNECTED;
+
+	if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_RAW)
+		return -ESOCKTNOSUPPORT;
+
+	sock->ops = &l2cap_sock_ops;
+
+	if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL)))
+		return -ENOMEM;
+
+	l2cap_sock_init(sk, NULL);
+
+	return 0;
+}
+
+static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+{
+	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
+
+	if (!addr || addr->sa_family != AF_BLUETOOTH)
+		return -EINVAL;
+
+	lock_sock(sk);
+
+	if (sk->state != BT_OPEN) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	write_lock(&l2cap_sk_list.lock);
+
+	if (la->l2_psm && __l2cap_get_sock_by_addr(la)) {
+		err = -EADDRINUSE;
+		goto unlock;
+	}
+
+	/* Save source address */
+	bacpy(&l2cap_pi(sk)->src, &la->l2_bdaddr);
+	l2cap_pi(sk)->psm = la->l2_psm;
+	sk->state = BT_BOUND;
+
+unlock:
+	write_unlock(&l2cap_sk_list.lock);
+
+done:
+	release_sock(sk);
+
+	return err;
+}
+
+static int l2cap_sock_w4_connect(struct sock *sk, int flags)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
+	int err = 0;
+
+	add_wait_queue(sk->sleep, &wait);
+	current->state = TASK_INTERRUPTIBLE;
+
+	while (sk->state != BT_CONNECTED) {
+		if (!timeo) {
+			err = -EAGAIN;
+			break;
+		}
+
+		release_sock(sk);
+		timeo = schedule_timeout(timeo);
+		lock_sock(sk);
+
+		err = 0;
+		if (sk->state == BT_CONNECTED)
+			break;
+
+		if (sk->err) {
+			err = sock_error(sk);
+			break;
+		}
+
+		if (signal_pending(current)) {
+			err = sock_intr_errno(timeo);
+			break;
+		}
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(sk->sleep, &wait);
+
+	return err;
+}
+
+static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
+{
+	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	lock_sock(sk);
+
+	DBG("sk %p", sk);
+
+	if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
+		err = -EINVAL;
+		goto done;
+	}
+
+	if (sk->state != BT_OPEN && sk->state != BT_BOUND) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	if (sk->type == SOCK_SEQPACKET && !la->l2_psm) {
+		err = -EINVAL;
+		goto done;
+	}
+
+	/* Set destination address and psm */
+	bacpy(&l2cap_pi(sk)->dst, &la->l2_bdaddr);
+	l2cap_pi(sk)->psm = la->l2_psm;
+
+	if ((err = l2cap_connect(sk)))
+		goto done;
+
+	err = l2cap_sock_w4_connect(sk, flags);
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+int l2cap_sock_listen(struct socket *sock, int backlog)
+{
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	DBG("sk %p backlog %d", sk, backlog);
+
+	lock_sock(sk);
+
+	if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	if (!l2cap_pi(sk)->psm) {
+		err = -EINVAL;
+		goto done;
+	}
+
+	sk->max_ack_backlog = backlog;
+	sk->ack_backlog = 0;
+	sk->state = BT_LISTEN;
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct sock *sk = sock->sk, *ch;
+	long timeo;
+	int err = 0;
+
+	lock_sock(sk);
+
+	if (sk->state != BT_LISTEN) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
+
+	DBG("sk %p timeo %ld", sk, timeo);
+
+	/* Wait for an incoming connection. (wake-one). */
+	add_wait_queue_exclusive(sk->sleep, &wait);
+	current->state = TASK_INTERRUPTIBLE;
+	while (!(ch = l2cap_accept_dequeue(sk, BT_CONNECTED))) {
+		if (!timeo) {
+			err = -EAGAIN;
+			break;
+		}
+
+		release_sock(sk);
+		timeo = schedule_timeout(timeo);
+		lock_sock(sk);
+
+		if (sk->state != BT_LISTEN) {
+			err = -EBADFD;
+			break;
+		}
+
+		if (signal_pending(current)) {
+			err = sock_intr_errno(timeo);
+			break;
+		}
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(sk->sleep, &wait);
+
+	if (err)
+		goto done;
+
+	sock_graft(ch, newsock);
+	newsock->state = SS_CONNECTED;
+
+	DBG("new socket %p", ch);
+
+done:
+	release_sock(sk);
+
+	return err;
+}
+
+static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
+{
+	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
+	struct sock *sk = sock->sk;
+
+	DBG("sock %p, sk %p", sock, sk);
+
+	addr->sa_family = AF_BLUETOOTH;
+	*len = sizeof(struct sockaddr_l2);
+
+	if (peer)
+		bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->dst);
+	else
+		bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->src);
+
+	la->l2_psm = l2cap_pi(sk)->psm;
+
+	return 0;
+}
+
+static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	DBG("sock %p, sk %p", sock, sk);
+
+	if (sk->err)
+		return sock_error(sk);
+
+	if (msg->msg_flags & MSG_OOB)
+		return -EOPNOTSUPP;
+
+	lock_sock(sk);
+
+	if (sk->state == BT_CONNECTED)
+		err = l2cap_chan_send(sk, msg, len);
+	else
+		err = -ENOTCONN;
+
+	release_sock(sk);
+	return err;
+}
+
+static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	int noblock = flags & MSG_DONTWAIT;
+	int copied, err;
+	struct sk_buff *skb;
+
+	DBG("sock %p, sk %p", sock, sk);
+
+	if (flags & (MSG_OOB))
+		return -EOPNOTSUPP;
+
+	if (sk->state == BT_CLOSED)
+		return 0;
+
+	if (!(skb = skb_recv_datagram(sk, flags, noblock, &err)))
+		return err;
+
+	msg->msg_namelen = 0;
+
+	copied = skb->len;
+	if (len < copied) {
+		msg->msg_flags |= MSG_TRUNC;
+		copied = len;
+	}
+
+	skb->h.raw = skb->data;
+	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+
+	skb_free_datagram(sk, skb);
+
+	return err ? : copied;
+}
+
+int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+{
+	struct sock *sk = sock->sk;
+	struct l2cap_options opts;
+	int err = 0;
+
+	DBG("sk %p", sk);
+
+	lock_sock(sk);
+
+	switch (optname) {
+	case L2CAP_OPTIONS:
+		if (copy_from_user((char *)&opts, optval, optlen)) {
+			err = -EFAULT;
+			break;
+		}
+		l2cap_pi(sk)->imtu = opts.imtu;
+		l2cap_pi(sk)->omtu = opts.omtu;
+		break;
+
+	default:
+		err = -ENOPROTOOPT;
+		break;
+	};
+
+	release_sock(sk);
+
+	return err;
+}
+
+int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+{
+	struct sock *sk = sock->sk;
+	struct l2cap_options opts;
+	int len; 
+
+	if (get_user(len, optlen))
+		return -EFAULT;
+
+	switch (optname) {
+	case L2CAP_OPTIONS:
+		opts.imtu     = l2cap_pi(sk)->imtu;
+		opts.omtu     = l2cap_pi(sk)->omtu;
+		opts.flush_to = l2cap_pi(sk)->flush_to;
+
+		len = MIN(len, sizeof(opts));
+		if (copy_to_user(optval, (char *)&opts, len))
+			return -EFAULT;
+
+		break;
+
+	default:
+		return -ENOPROTOOPT;
+		break;
+	};
+
+	return 0;
+}
+
+static int l2cap_sock_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+
+	DBG("sock %p, sk %p", sock, sk);
+
+	if (!sk)
+		return 0;
+
+	sock_orphan(sk);
+
+	l2cap_sock_close(sk);
+
+	return 0;
+}
+
+/* --------- L2CAP channels --------- */
+static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
+{
+	struct sock *s;
+
+	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+		if (l2cap_pi(s)->dcid == cid)
+			break;
+	}
+
+	return s;
+}
+
+static __inline__ struct sock *l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
+{
+	struct sock *s;
+
+	read_lock(&l->lock);
+	s = __l2cap_get_chan_by_dcid(l, cid);
+	read_unlock(&l->lock);
+
+	return s;
+}
+
+static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
+{
+	struct sock *s;
+
+	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+		if (l2cap_pi(s)->scid == cid)
+			break;
+	}
+
+	return s;
+}
+static __inline__ struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
+{
+	struct sock *s;
+
+	read_lock(&l->lock);
+	s = __l2cap_get_chan_by_scid(l, cid);
+	read_unlock(&l->lock);
+
+	return s;
+}
+
+static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident)
+{
+	struct sock *s;
+
+	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+		if (l2cap_pi(s)->ident == ident)
+			break;
+	}
+
+	return s;
+}
+
+static __inline__ struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident)
+{
+	struct sock *s;
+
+	read_lock(&l->lock);
+	s = __l2cap_get_chan_by_ident(l, ident);
+	read_unlock(&l->lock);
+
+	return s;
+}
+
+static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
+{
+	__u16 cid = 0x0040;
+
+	for (; cid < 0xffff; cid++) {
+		if(!__l2cap_get_chan_by_scid(l, cid))
+			return cid;
+	}
+
+	return 0;
+}
+
+static __inline__ void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
+{
+	sock_hold(sk);
+
+	if (l->head)
+		l2cap_pi(l->head)->prev_c = sk;
+
+	l2cap_pi(sk)->next_c = l->head;
+	l2cap_pi(sk)->prev_c = NULL;
+	l->head = sk;
+}
+
+static __inline__ void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
+{
+	struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
+
+	write_lock(&l->lock);
+	if (sk == l->head)
+		l->head = next;
+
+	if (next)
+		l2cap_pi(next)->prev_c = prev;
+	if (prev)
+		l2cap_pi(prev)->next_c = next;
+	write_unlock(&l->lock);
+
+	__sock_put(sk);
+}
+
+static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
+{
+	struct l2cap_chan_list *l = &conn->chan_list;
+
+	DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
+
+	atomic_inc(&conn->refcnt);
+	l2cap_pi(sk)->conn = conn;
+
+	if (sk->type == SOCK_SEQPACKET) {
+		/* Alloc CID for normal socket */
+		l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
+	} else {
+		/* Raw socket can send only signalling messages */
+		l2cap_pi(sk)->scid = 0x0001;
+		l2cap_pi(sk)->dcid = 0x0001;
+		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
+	}
+
+	__l2cap_chan_link(l, sk);
+
+	if (parent)
+		l2cap_accept_queue(parent, sk);
+}
+
+static __inline__ void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
+{
+	struct l2cap_chan_list *l = &conn->chan_list;
+
+	write_lock(&l->lock);
+	__l2cap_chan_add(conn, sk, parent);
+	write_unlock(&l->lock);
+}
+
+/* Delete channel. Must be called on the locked socket. */
+static void l2cap_chan_del(struct sock *sk, int err)
+{
+	struct l2cap_conn *conn;
+	struct sock *parent;
+
+	conn = l2cap_pi(sk)->conn;
+	parent = l2cap_pi(sk)->parent;
+
+	DBG("sk %p, conn %p, err %d", sk, conn, err);
+
+	if (parent) {
+		/* Unlink from parent accept queue */
+		bh_lock_sock(parent);
+		l2cap_accept_unlink(sk);
+		bh_unlock_sock(parent);
+	}
+
+	if (conn) {
+		/* Unlink from channel list */
+		l2cap_chan_unlink(&conn->chan_list, sk);
+		l2cap_pi(sk)->conn = NULL;
+
+		if (conn->out &&
+		    conn->state == BT_CONNECTED &&
+		    atomic_dec_and_test(&conn->refcnt)) {
+			/* Disconnect baseband */
+			hci_disconnect(conn->hconn, 0x13);
+		}
+	}
+
+	sk->state  = BT_CLOSED;
+	sk->err    = err;
+	sk->state_change(sk);
+
+	sk->zapped = 1;
+}
+
+static void l2cap_conn_ready(struct l2cap_conn *conn)
+{
+	struct l2cap_chan_list *l = &conn->chan_list;
+	struct sock *sk;
+
+	DBG("conn %p", conn);
+
+	read_lock(&l->lock);
+
+	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+		bh_lock_sock(sk);
+
+		if (sk->type != SOCK_SEQPACKET) {
+			sk->state = BT_CONNECTED;
+			sk->state_change(sk);
+			l2cap_clear_timer(sk);
+		} else if (sk->state == BT_CONNECT) {
+			l2cap_conn_req req;
+			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+			req.psm  = l2cap_pi(sk)->psm;
+			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
+
+			l2cap_set_timer(sk, sk->sndtimeo);
+		}
+
+		bh_unlock_sock(sk);
+	}
+
+	read_unlock(&l->lock);
+}
+
+static void l2cap_chan_ready(struct sock *sk)
+{
+	struct sock *parent = l2cap_pi(sk)->parent;
+
+	DBG("sk %p, parent %p", sk, parent);
+
+	l2cap_pi(sk)->conf_state = 0;
+	l2cap_clear_timer(sk);
+
+	if (!parent) {
+		/* Outgoing channel.
+		 * Wake up socket sleeping on connect.
+		 */
+		sk->state = BT_CONNECTED;
+		sk->state_change(sk);
+	} else {
+		/* Incomming channel.
+		 * Wake up socket sleeping on accept.
+		 */
+		parent->state_change(parent);
+	}
+}
+
+/* Copy frame to all raw sockets on that connection */
+void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	struct l2cap_chan_list *l = &conn->chan_list;
+	struct sk_buff *nskb;
+	struct sock * sk;
+
+	DBG("conn %p", conn);
+
+	read_lock(&l->lock);
+	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+		if (sk->type != SOCK_RAW)
+			continue;
+
+		/* Don't send frame to the socket it came from */
+		if (skb->sk == sk)
+			continue;
+
+		if (!(nskb = bluez_skb_clone(skb, GFP_ATOMIC)))
+			continue;
+
+		skb_queue_tail(&sk->receive_queue, nskb);
+		sk->data_ready(sk, nskb->len);
+	}
+	read_unlock(&l->lock);
+}
+
+static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len)
+{
+	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+	struct l2cap_iff  *iff  = conn->iff;
+	struct sk_buff *skb, *frag;
+	int err, size, count, sent=0;
+	l2cap_hdr * lh;
+
+	/* Check outgoing MTU */
+	if (len > l2cap_pi(sk)->omtu)
+		return -EINVAL;
+
+	/* First fragment (with L2CAP header) */
+	count = MIN(iff->mtu - L2CAP_HDR_SIZE, len);
+	size  = L2CAP_HDR_SIZE + count;
+	if (!(skb = bluez_skb_send_alloc(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)))
+		return err;
+
+	/* Create L2CAP header */
+	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
+	lh->len = __cpu_to_le16(len);
+	lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+
+	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
+		err = -EFAULT;
+		goto fail;
+	}
+
+	sent += count;
+	len  -= count;
+
+	/* Continuation fragments (no L2CAP header) */
+	while (len) {
+		count = MIN(iff->mtu, len);
+
+		if (!(frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err)))
+			goto fail;
+
+		bluez_skb_add_frag(skb, frag);
+	
+		if (memcpy_fromiovec(skb_put(frag, count), msg->msg_iov, count)) {
+			err = -EFAULT;
+			goto fail;
+		}
+
+		sent += count;
+		len  -= count;
+	}
+
+	if ((err = hci_send_acl(conn->hconn, skb, 0)) < 0)
+		goto fail;
+
+	return sent;
+
+fail:
+	bluez_skb_free(skb);
+
+	return err;
+}
+/* --------- L2CAP signalling commands --------- */
+static __inline__ __u8 l2cap_get_ident(struct l2cap_conn *conn)
+{
+	__u8 id;
+
+	/* Get next available identificator.
+	 *    1 - 199 are used by kernel.
+	 *  200 - 254 are used by utilities like l2ping, etc 
+	 */
+
+	spin_lock(&conn->lock);
+
+	if (++conn->tx_ident > 199)
+		conn->tx_ident = 1;
+
+	id = conn->tx_ident;
+
+	spin_unlock(&conn->lock);
+
+	return id;
+}
+
+static __inline__ struct sk_buff *l2cap_build_cmd(__u8 code, __u8 ident, __u16 len, void *data)
+{
+	struct sk_buff *skb;
+	l2cap_cmd_hdr *cmd;
+	l2cap_hdr *lh;
+	int size;
+
+	DBG("code 0x%2.2x, ident 0x%2.2x, len %d", code, ident, len);
+
+	size = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + len;
+	if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC)))
+		return NULL;
+
+	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
+	lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + len);
+	lh->cid = __cpu_to_le16(0x0001);
+
+	cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
+	cmd->code  = code;
+	cmd->ident = ident;
+	cmd->len   = __cpu_to_le16(len);
+
+	if (len)
+		memcpy(skb_put(skb, len), data, len);
+
+	return skb;
+}
+
+static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data)
+{
+	struct sk_buff *skb;
+	__u8 ident;
+
+	DBG("code 0x%2.2x", code);
+
+	ident = l2cap_get_ident(conn);
+	if (!(skb = l2cap_build_cmd(code, ident, len, data)))
+		return -ENOMEM;
+	skb->dev = (void *) conn->iff->hdev;
+	return hci_send_acl(conn->hconn, skb, 0);
+}
+
+static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data)
+{
+	struct sk_buff *skb;
+
+	DBG("code 0x%2.2x", code);
+
+	if (!(skb = l2cap_build_cmd(code, ident, len, data)))
+		return -ENOMEM;
+
+	skb->dev = (void *) conn->iff->hdev;
+
+	return hci_send_acl(conn->hconn, skb, 0);
+}
+
+static __inline__ int l2cap_get_conf_opt(__u8 **ptr, __u8 *type, __u32 *val)
+{
+	l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr);
+	int len;
+
+	*type = opt->type;
+	switch (opt->len) {
+	case 1:
+		*val = *((__u8 *) opt->val);
+		break;
+
+	case 2:
+		*val = __le16_to_cpu(*((__u16 *)opt->val));
+		break;
+
+	case 4:
+		*val = __le32_to_cpu(*((__u32 *)opt->val));
+		break;
+
+	default:
+		*val = 0L;
+		break;
+	};
+
+	DBG("type 0x%2.2x len %d val 0x%8.8x", *type, opt->len, *val);
+
+	len = L2CAP_CONF_OPT_SIZE + opt->len;
+
+	*ptr += len;
+
+	return len;
+}
+
+static __inline__ void l2cap_parse_conf_req(struct sock *sk, char *data, int len)
+{
+	__u8 type; __u32 val;
+	__u8 *ptr = data;
+
+	DBG("sk %p len %d", sk, len);
+
+	while (len >= L2CAP_CONF_OPT_SIZE) {
+		len -= l2cap_get_conf_opt(&ptr, &type, &val);
+
+		switch (type) {
+		case L2CAP_CONF_MTU:
+			l2cap_pi(sk)->conf_mtu = val;
+			break;
+
+		case L2CAP_CONF_FLUSH_TO:
+			l2cap_pi(sk)->flush_to = val;
+			break;
+
+		case L2CAP_CONF_QOS:
+			break;
+		};
+	}
+}
+
+static __inline__ void l2cap_add_conf_opt(__u8 **ptr, __u8 type, __u8 len, __u32 val)
+{
+	register l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr);
+
+	DBG("type 0x%2.2x len %d val 0x%8.8x", type, len, val);
+
+	opt->type = type;
+	opt->len  = len;
+	switch (len) {
+	case 1:
+		*((__u8 *) opt->val)  = val;
+		break;
+
+	case 2:
+		*((__u16 *) opt->val) = __cpu_to_le16(val);
+		break;
+
+	case 4:
+		*((__u32 *) opt->val) = __cpu_to_le32(val);
+		break;
+	};
+
+	*ptr += L2CAP_CONF_OPT_SIZE + len;
+}
+
+static int l2cap_build_conf_req(struct sock *sk, __u8 *data)
+{
+	struct l2cap_pinfo *pi = l2cap_pi(sk);
+	l2cap_conf_req *req = (l2cap_conf_req *) data;
+	__u8 *ptr = req->data;
+
+	DBG("sk %p", sk);
+
+	if (pi->imtu != L2CAP_DEFAULT_MTU)
+		l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
+
+	/* FIXME. Need actual value of the flush timeout */
+	//if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
+	//   l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
+
+	req->dcid  = __cpu_to_le16(pi->dcid);
+	req->flags = __cpu_to_le16(0);
+
+	return ptr - data;
+}
+
+static int l2cap_conf_output(struct sock *sk, __u8 **ptr)
+{
+	struct l2cap_pinfo *pi = l2cap_pi(sk);
+	int result = 0;
+
+	/* Configure output options and let other side know
+	 * which ones we don't like.
+	 */
+	if (pi->conf_mtu < pi->omtu) {
+		l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, l2cap_pi(sk)->omtu);
+		result = L2CAP_CONF_UNACCEPT;
+	} else {
+		pi->omtu = pi->conf_mtu;
+	}
+
+	DBG("sk %p result %d", sk, result);
+	return result;
+}
+
+static int l2cap_build_conf_rsp(struct sock *sk, __u8 *data, int *result)
+{
+	l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data;
+	__u8 *ptr = rsp->data;
+
+	DBG("sk %p complete %d", sk, result ? 1 : 0);
+
+	if (result)
+		*result = l2cap_conf_output(sk, &ptr);
+
+	rsp->scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
+	rsp->result = __cpu_to_le16(result ? *result : 0);
+	rsp->flags  = __cpu_to_le16(0);
+
+	return ptr - data;
+}
+
+static __inline__ int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+{
+	struct l2cap_chan_list *list = &conn->chan_list;
+	l2cap_conn_req *req = (l2cap_conn_req *) data;
+	l2cap_conn_rsp rsp;
+	struct sock *sk, *parent;
+
+	__u16 scid = __le16_to_cpu(req->scid);
+	__u16 psm  = req->psm;
+
+	DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
+
+	/* Check if we have socket listening on psm */
+	if (!(parent = l2cap_get_sock_listen(&conn->src, psm)))
+		goto reject;
+
+	bh_lock_sock(parent);
+	write_lock(&list->lock);
+
+	/* Check if we already have channel with that dcid */
+	if (__l2cap_get_chan_by_dcid(list, scid))
+		goto unlock;
+
+	/* Check for backlog size */
+	if (parent->ack_backlog > parent->max_ack_backlog)
+		goto unlock;
+
+	if (!(sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC)))
+		goto unlock;
+
+	l2cap_sock_init(sk, parent);
+
+	bacpy(&l2cap_pi(sk)->src, &conn->src);
+	bacpy(&l2cap_pi(sk)->dst, &conn->dst);
+	l2cap_pi(sk)->psm  = psm;
+	l2cap_pi(sk)->dcid = scid;
+
+	__l2cap_chan_add(conn, sk, parent);
+	sk->state = BT_CONFIG;
+
+	write_unlock(&list->lock);
+	bh_unlock_sock(parent);
+
+	rsp.dcid   = __cpu_to_le16(l2cap_pi(sk)->scid);
+	rsp.scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
+	rsp.result = __cpu_to_le16(0);
+	rsp.status = __cpu_to_le16(0);
+	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
+
+	return 0;
+
+unlock:
+	write_unlock(&list->lock);
+	bh_unlock_sock(parent);
+
+reject:
+	rsp.scid   = __cpu_to_le16(scid);
+	rsp.dcid   = __cpu_to_le16(0);
+	rsp.status = __cpu_to_le16(0);
+	rsp.result = __cpu_to_le16(L2CAP_CONN_NO_MEM);
+	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
+
+	return 0;
+}
+
+static __inline__ int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+{
+	l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data;
+	__u16 scid, dcid, result, status;
+	struct sock *sk;
+
+	scid   = __le16_to_cpu(rsp->scid);
+	dcid   = __le16_to_cpu(rsp->dcid);
+	result = __le16_to_cpu(rsp->result);
+	status = __le16_to_cpu(rsp->status);
+
+	DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
+
+	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+		return -ENOENT;
+
+	bh_lock_sock(sk);
+
+	if (!result) {
+		char req[64];
+
+		l2cap_pi(sk)->dcid = dcid;
+		sk->state = BT_CONFIG;
+
+		l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
+	} else {
+		l2cap_chan_del(sk, ECONNREFUSED);
+	}
+
+	bh_unlock_sock(sk);
+	return 0;
+}
+
+static __inline__ int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+{
+	l2cap_conf_req * req = (l2cap_conf_req *) data;
+	__u16 dcid, flags;
+	__u8 rsp[64];
+	struct sock *sk;
+	int result;
+
+	dcid  = __le16_to_cpu(req->dcid);
+	flags = __le16_to_cpu(req->flags);
+
+	DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
+
+	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
+		return -ENOENT;
+
+	bh_lock_sock(sk);
+
+	l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE);
+
+	if (flags & 0x01) {
+		/* Incomplete config. Send empty response. */
+		l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
+		goto unlock;
+	}
+
+	/* Complete config. */
+	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp);
+
+	if (result)
+		goto unlock;
+
+	/* Output config done */
+	l2cap_pi(sk)->conf_state |= CONF_OUTPUT;
+
+	if (l2cap_pi(sk)->conf_state == CONF_DONE) {
+		sk->state = BT_CONNECTED;
+		l2cap_chan_ready(sk);
+	} else {
+		char req[64];
+		l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
+	}
+
+unlock:
+	bh_unlock_sock(sk);
+
+	return 0;
+}
+
+static __inline__ int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+{
+	l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data;
+	__u16 scid, flags, result;
+	struct sock *sk;
+	int err = 0;
+
+	scid   = __le16_to_cpu(rsp->scid);
+	flags  = __le16_to_cpu(rsp->flags);
+	result = __le16_to_cpu(rsp->result);
+
+	DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result);
+
+	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+		return -ENOENT;
+
+	bh_lock_sock(sk);
+
+	if (sk->state != BT_CONFIG) {
+		err = -EINVAL;
+		goto done;
+	}
+
+	if (result) {
+		l2cap_disconn_req req;
+
+		/* They didn't like our options. Well... we do not negotiate.
+		 * Close channel.
+		 */
+		sk->state = BT_DISCONN;
+
+		req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+		req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+		l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
+
+		l2cap_set_timer(sk, sk->sndtimeo);
+		goto done;
+	}
+
+	if (flags & 0x01)
+		goto done;
+
+	/* Input config done */
+	l2cap_pi(sk)->conf_state |= CONF_INPUT;
+
+	if (l2cap_pi(sk)->conf_state == CONF_DONE) {
+		sk->state = BT_CONNECTED;
+		l2cap_chan_ready(sk);
+	}
+
+done:
+	bh_unlock_sock(sk);
+
+	return err;
+}
+
+static __inline__ int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+{
+	l2cap_disconn_req *req = (l2cap_disconn_req *) data;
+	l2cap_disconn_rsp rsp;
+	__u16 dcid, scid;
+	struct sock *sk;
+
+	scid = __le16_to_cpu(req->scid);
+	dcid = __le16_to_cpu(req->dcid);
+
+	DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
+
+	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
+		return 0;
+
+	bh_lock_sock(sk);
+
+	rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
+	rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+	l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp);
+
+	l2cap_chan_del(sk, ECONNRESET);
+
+	bh_unlock_sock(sk);
+
+	l2cap_sock_kill(sk);
+
+	return 0;
+}
+
+static __inline__ int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+{
+	l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data;
+	__u16 dcid, scid;
+	struct sock *sk;
+
+	scid = __le16_to_cpu(rsp->scid);
+	dcid = __le16_to_cpu(rsp->dcid);
+
+	DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
+
+	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+		return -ENOENT;
+
+	bh_lock_sock(sk);
+	l2cap_clear_timer(sk);
+	l2cap_chan_del(sk, ECONNABORTED);
+	bh_unlock_sock(sk);
+
+	l2cap_sock_kill(sk);
+
+	return 0;
+}
+
+static __inline__ void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	__u8 *data = skb->data;
+	int len = skb->len;
+	l2cap_cmd_hdr cmd;
+	int err = 0;
+
+	while (len >= L2CAP_CMD_HDR_SIZE) {
+		memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
+		data += L2CAP_CMD_HDR_SIZE;
+		len  -= L2CAP_CMD_HDR_SIZE;
+
+		cmd.len = le16_to_cpu(cmd.len);
+
+		DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident);
+
+		if (cmd.len > len || !cmd.ident) {
+			DBG("corrupted command");
+			break;
+		}
+
+		switch (cmd.code) {
+		case L2CAP_CONN_REQ:
+			err = l2cap_connect_req(conn, &cmd, data);
+			break;
+
+		case L2CAP_CONN_RSP:
+			err = l2cap_connect_rsp(conn, &cmd, data);
+			break;
+
+		case L2CAP_CONF_REQ:
+			err = l2cap_config_req(conn, &cmd, data);
+			break;
+
+		case L2CAP_CONF_RSP:
+			err = l2cap_config_rsp(conn, &cmd, data);
+			break;
+
+		case L2CAP_DISCONN_REQ:
+			err = l2cap_disconnect_req(conn, &cmd, data);
+			break;
+
+		case L2CAP_DISCONN_RSP:
+			err = l2cap_disconnect_rsp(conn, &cmd, data);
+			break;
+
+		case L2CAP_COMMAND_REJ:
+			/* FIXME: We should process this */
+			l2cap_raw_recv(conn, skb);
+			break;
+
+		case L2CAP_ECHO_REQ:
+			l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
+			break;
+
+		case L2CAP_ECHO_RSP:
+		case L2CAP_INFO_REQ:
+		case L2CAP_INFO_RSP:
+			l2cap_raw_recv(conn, skb);
+			break;
+
+		default:
+			ERR("Uknown signaling command 0x%2.2x", cmd.code);
+			err = -EINVAL;
+			break;
+		};
+
+		if (err) {
+			l2cap_cmd_rej rej;
+			DBG("error %d", err);
+
+			/* FIXME: Map err to a valid reason. */
+			rej.reason = cpu_to_le16(0);
+			l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej);
+		}
+
+		data += cmd.len;
+		len  -= cmd.len;
+	}
+
+	bluez_skb_free(skb);
+}
+
+static __inline__ int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb)
+{
+	struct sock *sk;
+
+	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, cid))) {
+		DBG("unknown cid 0x%4.4x", cid);
+		goto drop;
+	}
+
+	DBG("sk %p, len %d", sk, skb->len);
+
+	if (sk->state != BT_CONNECTED)
+		goto drop;
+
+	if (l2cap_pi(sk)->imtu < skb->len)
+		goto drop;
+
+	skb_queue_tail(&sk->receive_queue, skb);
+	sk->data_ready(sk, skb->len);
+
+	return 0;
+
+drop:
+	bluez_skb_free(skb);
+
+	return 0;
+}
+
+static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	l2cap_hdr *lh = (l2cap_hdr *) skb->data;
+	__u16 cid, len;
+
+	skb_pull(skb, L2CAP_HDR_SIZE);
+	cid = le16_to_cpu(lh->cid);
+	len = le16_to_cpu(lh->len);
+
+	DBG("len %d, cid 0x%4.4x", len, cid);
+
+	if (cid == 0x0001)
+		l2cap_sig_channel(conn, skb);
+	else	
+		l2cap_data_channel(conn, cid, skb);
+}
+
+/* ------------ L2CAP interface with lower layer (HCI) ------------- */
+static int l2cap_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+	struct hci_dev *hdev = (struct hci_dev *) ptr;
+
+	DBG("hdev %s, event %ld", hdev->name, event);
+
+	write_lock(&l2cap_rt_lock);
+
+	switch (event) {
+	case HCI_DEV_UP:
+		l2cap_iff_add(hdev);
+		break;
+
+	case HCI_DEV_DOWN:
+		l2cap_iff_del(hdev);
+		break;
+	};
+
+	write_unlock(&l2cap_rt_lock);
+
+	return NOTIFY_DONE;
+}
+
+int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+	struct l2cap_iff *iff;
+
+	DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
+
+	if (!(iff = hdev->l2cap_data)) {
+		ERR("unknown interface");
+		return 0;
+	}
+
+	/* Always accept connection */
+	return 1;
+}
+
+int l2cap_connect_cfm(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *hconn)
+{
+	struct l2cap_conn *conn;
+	struct l2cap_iff *iff;
+	int err = 0;
+
+	DBG("hdev %s bdaddr %s hconn %p", hdev->name, batostr(bdaddr), hconn);
+
+	if (!(iff = hdev->l2cap_data)) {
+		ERR("unknown interface");
+		return 0;
+	}
+
+	l2cap_iff_lock(iff);
+
+	conn = l2cap_get_conn_by_addr(iff, bdaddr);
+
+	if (conn) {
+		/* Outgoing connection */
+		DBG("Outgoing connection: %s -> %s, %p, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), conn, status);
+
+		if (!status && hconn) {
+			conn->state = BT_CONNECTED;
+			conn->hconn = hconn;
+
+			hconn->l2cap_data = (void *)conn;
+
+			/* Establish channels */
+			l2cap_conn_ready(conn);
+		} else {
+			l2cap_conn_del(conn, bterr(status));
+		}
+	} else {
+		/* Incomming connection */
+		DBG("Incomming connection: %s -> %s, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), status);
+	
+		if (status || !hconn)
+			goto done;
+
+		if (!(conn = l2cap_conn_add(iff, bdaddr))) {
+			err = -ENOMEM;
+			goto done;
+		}
+
+		conn->state = BT_CONNECTED;
+		conn->hconn = hconn;
+
+		hconn->l2cap_data = (void *)conn;
+	}
+
+done:
+	l2cap_iff_unlock(iff);
+
+	return err;
+}
+
+int l2cap_disconn_ind(struct hci_conn *hconn, __u8 reason)
+{
+	struct l2cap_conn *conn = hconn->l2cap_data;
+
+	DBG("hconn %p reason %d", hconn, reason);
+
+	if (!conn) {
+		ERR("unknown connection");
+		return 0;
+	}
+	conn->hconn = NULL;
+
+	l2cap_iff_lock(conn->iff);
+	l2cap_conn_del(conn, bterr(reason));
+	l2cap_iff_unlock(conn->iff);
+
+	return 0;
+}
+
+int l2cap_recv_acldata(struct hci_conn *hconn, struct sk_buff *skb, __u16 flags)
+{
+	struct l2cap_conn *conn = hconn->l2cap_data;
+
+	if (!conn) {
+		ERR("unknown connection");
+		goto drop;
+	}
+
+	DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
+
+	if (flags & ACL_START) {
+		int flen, tlen, size;
+		l2cap_hdr *lh;
+
+		if (skb->len < L2CAP_HDR_SIZE) {
+			DBG("Corrupted L2CAP frame %d", skb->len);
+			goto drop;
+		}
+
+		lh = (l2cap_hdr *)skb->data;
+		tlen = __le16_to_cpu(lh->len);
+		flen = skb->len - L2CAP_HDR_SIZE;
+
+		DBG("Start: total len %d, frag len %d", tlen, flen);
+
+		if (flen == tlen) {
+			/* Complete frame received */
+			l2cap_recv_frame(conn, skb);
+			return 0;
+		}
+
+		/* Allocate skb for the complete frame (with header) */
+		size = L2CAP_HDR_SIZE + tlen;
+		if (!(conn->rx_skb = bluez_skb_alloc(size, GFP_ATOMIC)))
+			goto drop;
+
+		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
+
+		conn->rx_len = tlen - flen;
+	} else {
+		DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
+
+		/* Check length */
+		if (skb->len > conn->rx_len) {
+			if (conn->rx_skb) {
+				bluez_skb_free(conn->rx_skb);
+				conn->rx_skb = NULL;
+			}
+			goto drop;
+		}
+
+		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
+		conn->rx_len -= skb->len;
+
+		if (!conn->rx_len) {
+			/* Complete frame received */
+			l2cap_recv_frame(conn, conn->rx_skb);
+			conn->rx_skb = NULL;
+			conn->rx_len = 0;
+		}
+	}
+
+drop:
+	bluez_skb_free(skb);
+
+	return 0;
+}
+
+struct proto_ops l2cap_sock_ops = {
+	family:		PF_BLUETOOTH,
+	release:	l2cap_sock_release,
+	bind:		l2cap_sock_bind,
+	connect:	l2cap_sock_connect,
+	listen:		l2cap_sock_listen,
+	accept:		l2cap_sock_accept,
+	getname:	l2cap_sock_getname,
+	sendmsg:	l2cap_sock_sendmsg,
+	recvmsg:	l2cap_sock_recvmsg,
+	poll:		datagram_poll,
+	socketpair:	sock_no_socketpair,
+	ioctl:		sock_no_ioctl,
+	shutdown:	sock_no_shutdown,
+	setsockopt:	l2cap_sock_setsockopt,
+	getsockopt:	l2cap_sock_getsockopt,
+	mmap:		sock_no_mmap
+};
+
+struct net_proto_family l2cap_sock_family_ops = {
+	family:		PF_BLUETOOTH,
+	create:		l2cap_sock_create
+};
+
+struct hci_proto l2cap_hci_proto = {
+	name:		"L2CAP",
+	id:		HCI_PROTO_L2CAP,
+	connect_ind:	l2cap_connect_ind,
+	connect_cfm:	l2cap_connect_cfm,
+	disconn_ind:	l2cap_disconn_ind,
+	recv_acldata:	l2cap_recv_acldata,
+};
+
+struct notifier_block l2cap_nblock = {
+	notifier_call: l2cap_dev_event
+};
+
+int __init l2cap_init(void)
+{
+	INF("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc",
+		BLUEZ_VER);
+	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+
+	if (bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops)) {
+		ERR("Can't register L2CAP socket");
+		return -EPROTO;
+	}
+
+	if (hci_register_proto(&l2cap_hci_proto) < 0) {
+		ERR("Can't register L2CAP protocol");
+		return -EPROTO;
+	}
+
+	hci_register_notifier(&l2cap_nblock);
+
+	l2cap_register_proc();
+
+	return 0;
+}
+
+void l2cap_cleanup(void)
+{
+	l2cap_unregister_proc();
+
+	/* Unregister socket, protocol and notifier */
+	if (bluez_sock_unregister(BTPROTO_L2CAP))
+		ERR("Can't unregister L2CAP socket");
+
+	if (hci_unregister_proto(&l2cap_hci_proto) < 0)
+		ERR("Can't unregister L2CAP protocol");
+
+	hci_unregister_notifier(&l2cap_nblock);
+
+	/* We _must_ not have any sockets and/or connections
+	 * at this stage.
+	 */
+
+	/* Free interface list and unlock HCI devices */
+	{
+		struct list_head *list = &l2cap_iff_list;
+
+		while (!list_empty(list)) {
+			struct l2cap_iff *iff;
+
+			iff = list_entry(list->next, struct l2cap_iff, list);
+			l2cap_iff_del(iff->hdev);
+		}
+	}
+}
+
+module_init(l2cap_init);
+module_exit(l2cap_cleanup);
diff -u --recursive --new-file v2.4.5/linux/net/bluetooth/l2cap_proc.c linux/net/bluetooth/l2cap_proc.c
--- v2.4.5/linux/net/bluetooth/l2cap_proc.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bluetooth/l2cap_proc.c	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,165 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * BlueZ L2CAP proc fs support.
+ *
+ * $Id: l2cap_proc.c,v 1.1 2001/06/01 08:12:11 davem Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/list.h>
+#include <net/sock.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <net/bluetooth/bluez.h>
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap_core.h>
+
+#ifndef L2CAP_DEBUG
+#undef  DBG
+#define DBG( A... )
+#endif
+
+/* ----- PROC fs support ----- */
+static int l2cap_conn_dump(char *buf, struct l2cap_iff *iff)
+{
+	struct list_head *p;
+	char *ptr = buf;
+
+	list_for_each(p, &iff->conn_list) {
+		struct l2cap_conn *c;
+
+		c = list_entry(p, struct l2cap_conn, list);
+		ptr += sprintf(ptr, "    %p %d %p %p %s %s\n", 
+				c, c->state, c->iff, c->hconn, batostr(&c->src), batostr(&c->dst));
+	}
+
+	return ptr - buf;
+}
+
+static int l2cap_iff_dump(char *buf)
+{
+	struct list_head *p;
+	char *ptr = buf;
+
+	ptr += sprintf(ptr, "Interfaces:\n");
+
+	write_lock(&l2cap_rt_lock);
+
+	list_for_each(p, &l2cap_iff_list) {
+		struct l2cap_iff *iff;
+
+		iff = list_entry(p, struct l2cap_iff, list);
+
+		ptr += sprintf(ptr, "  %s %p %p\n", iff->hdev->name, iff, iff->hdev);
+		
+		l2cap_iff_lock(iff);
+		ptr += l2cap_conn_dump(ptr, iff);
+		l2cap_iff_unlock(iff);
+	}
+
+	write_unlock(&l2cap_rt_lock);
+
+	ptr += sprintf(ptr, "\n");
+
+	return ptr - buf;
+}
+
+static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
+{
+	struct l2cap_pinfo *pi;
+	struct sock *sk;
+	char *ptr = buf;
+
+	ptr += sprintf(ptr, "Sockets:\n");
+
+	write_lock(&list->lock);
+
+	for (sk = list->head; sk; sk = sk->next) {
+		pi = l2cap_pi(sk);
+		ptr += sprintf(ptr, "  %p %d %p %d %s %s 0x%4.4x 0x%4.4x %d %d\n", sk, sk->state, pi->conn, pi->psm,
+		               batostr(&pi->src), batostr(&pi->dst), pi->scid, pi->dcid, pi->imtu, pi->omtu );
+	}
+
+	write_unlock(&list->lock);
+
+	ptr += sprintf(ptr, "\n");
+
+	return ptr - buf;
+}
+
+static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
+{
+	char *ptr = buf;
+	int len;
+
+	DBG("count %d, offset %ld", count, offset);
+
+	ptr += l2cap_iff_dump(ptr);
+	ptr += l2cap_sock_dump(ptr, &l2cap_sk_list);
+	len  = ptr - buf;
+
+	if (len <= count + offset)
+		*eof = 1;
+
+	*start = buf + offset;
+	len -= offset;
+
+	if (len > count)
+		len = count;
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+
+void l2cap_register_proc(void)
+{
+	create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL);
+}
+
+void l2cap_unregister_proc(void)
+{
+	remove_proc_entry("bluetooth/l2cap", NULL);
+}
diff -u --recursive --new-file v2.4.5/linux/net/bluetooth/lib.c linux/net/bluetooth/lib.c
--- v2.4.5/linux/net/bluetooth/lib.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bluetooth/lib.c	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,174 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * BlueZ kernel library.
+ *
+ * $Id: lib.c,v 1.1 2001/06/01 08:12:11 davem Exp $
+ */
+
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <asm/errno.h>
+
+#include <net/bluetooth/bluetooth.h>
+
+void bluez_dump(char *pref, __u8 *buf, int count)
+{
+	char *ptr;
+	char line[100];
+	int i;
+
+	printk(KERN_INFO "%s: dump, len %d\n", pref, count);
+
+	ptr = line;
+	*ptr = 0;
+	for (i = 0; i<count; i++) {
+		ptr += sprintf(ptr, " %2.2X", buf[i]);
+
+		if (i && !((i + 1) % 20)) {
+			printk(KERN_INFO "%s:%s\n", pref, line);
+			ptr = line;
+			*ptr = 0;
+		}
+	}
+
+	if (line[0])
+		printk(KERN_INFO "%s:%s\n", pref, line);
+}
+
+void baswap(bdaddr_t *dst, bdaddr_t *src)
+{
+	unsigned char *d = (unsigned char *) dst;
+	unsigned char *s = (unsigned char *) src;
+	int i;
+
+	for (i = 0; i < 6; i++)
+		d[i] = s[5 - i];
+}
+
+char *batostr(bdaddr_t *ba)
+{
+	static char str[2][18];
+	static int i = 1;
+
+	i ^= 1;
+	sprintf(str[i], "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+	        ba->b0, ba->b1, ba->b2, ba->b3, ba->b4, ba->b5);
+
+	return str[i];
+}
+
+/* Bluetooth error codes to Unix errno mapping */
+int bterr(__u16 code)
+{
+	switch (code) {
+	case 0:
+		return 0;
+
+	case 0x01:
+		return EBADRQC;
+
+	case 0x02:
+		return ENOTCONN;
+
+	case 0x03:
+		return EIO;
+
+	case 0x04:
+		return EHOSTDOWN;
+
+	case 0x05:
+		return EACCES;
+
+	case 0x06:
+		return EINVAL;
+
+	case 0x07:
+		return ENOMEM;
+
+	case 0x08:
+		return ETIMEDOUT;
+
+	case 0x09:
+		return EMLINK;
+
+	case 0x0a:
+		return EMLINK;
+
+	case 0x0b:
+		return EALREADY;
+
+	case 0x0c:
+		return EBUSY;
+
+	case 0x0d:
+	case 0x0e:
+	case 0x0f:
+		return ECONNREFUSED;
+
+	case 0x10:
+		return ETIMEDOUT;
+
+	case 0x11:
+	case 0x27:
+	case 0x29:
+	case 0x20:
+		return EOPNOTSUPP;
+
+	case 0x12:
+		return EINVAL;
+
+	case 0x13:
+	case 0x14:
+	case 0x15:
+		return ECONNRESET;
+
+	case 0x16:
+		return ECONNABORTED;
+
+	case 0x17:
+		return ELOOP;
+
+	case 0x18:
+		return EACCES;
+
+	case 0x1a:
+		return EPROTONOSUPPORT;
+
+	case 0x1b:
+		return ECONNREFUSED;
+
+	case 0x19:
+	case 0x1e:
+	case 0x23:
+	case 0x24:
+	case 0x25:
+		return EPROTO;
+
+	default:
+		return ENOSYS;
+	};
+}
diff -u --recursive --new-file v2.4.5/linux/net/bluetooth/syms.c linux/net/bluetooth/syms.c
--- v2.4.5/linux/net/bluetooth/syms.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bluetooth/syms.c	Mon Jun 11 19:15:27 2001
@@ -0,0 +1,72 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * BlueZ symbols.
+ *
+ * $Id: syms.c,v 1.1 2001/06/01 08:12:11 davem Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/bluez.h>
+#include <net/bluetooth/hci_core.h>
+
+/* HCI Core */
+EXPORT_SYMBOL(hci_register_dev);
+EXPORT_SYMBOL(hci_unregister_dev);
+EXPORT_SYMBOL(hci_register_proto);
+EXPORT_SYMBOL(hci_unregister_proto);
+EXPORT_SYMBOL(hci_register_notifier);
+EXPORT_SYMBOL(hci_unregister_notifier);
+
+EXPORT_SYMBOL(hci_connect);
+EXPORT_SYMBOL(hci_disconnect);
+EXPORT_SYMBOL(hci_dev_get);
+
+EXPORT_SYMBOL(hci_recv_frame);
+EXPORT_SYMBOL(hci_send_acl);
+EXPORT_SYMBOL(hci_send_sco);
+EXPORT_SYMBOL(hci_send_raw);
+
+/* BlueZ lib */
+EXPORT_SYMBOL(bluez_dump);
+EXPORT_SYMBOL(baswap);
+EXPORT_SYMBOL(batostr);
+EXPORT_SYMBOL(bterr);
+
+/* BlueZ sockets */
+EXPORT_SYMBOL(bluez_sock_register);
+EXPORT_SYMBOL(bluez_sock_unregister);
+EXPORT_SYMBOL(bluez_sock_link);
+EXPORT_SYMBOL(bluez_sock_unlink);
diff -u --recursive --new-file v2.4.5/linux/net/bridge/br_device.c linux/net/bridge/br_device.c
--- v2.4.5/linux/net/bridge/br_device.c	Thu Mar  2 11:41:11 2000
+++ linux/net/bridge/br_device.c	Mon Jun 11 19:15:27 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_device.c,v 1.3 2000/03/01 02:58:09 davem Exp $
+ *	$Id: br_device.c,v 1.4 2001/06/01 09:28:28 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -56,17 +56,17 @@
 	dest = skb->data;
 
 	if (dest[0] & 1) {
-		br_flood(br, skb, 0);
+		br_flood_deliver(br, skb, 0);
 		return 0;
 	}
 
 	if ((dst = br_fdb_get(br, dest)) != NULL) {
-		br_forward(dst->dst, skb);
+		br_deliver(dst->dst, skb);
 		br_fdb_put(dst);
 		return 0;
 	}
 
-	br_flood(br, skb, 0);
+	br_flood_deliver(br, skb, 0);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.5/linux/net/bridge/br_forward.c linux/net/bridge/br_forward.c
--- v2.4.5/linux/net/bridge/br_forward.c	Mon Feb 21 17:35:06 2000
+++ linux/net/bridge/br_forward.c	Mon Jun 11 19:15:27 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_forward.c,v 1.2 2000/02/21 15:51:33 davem Exp $
+ *	$Id: br_forward.c,v 1.3 2001/06/01 09:28:28 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -18,9 +18,10 @@
 #include <linux/inetdevice.h>
 #include <linux/skbuff.h>
 #include <linux/if_bridge.h>
+#include <linux/netfilter_bridge.h>
 #include "br_private.h"
 
-static inline int should_forward(struct net_bridge_port *p, struct sk_buff *skb)
+static inline int should_deliver(struct net_bridge_port *p, struct sk_buff *skb)
 {
 	if (skb->dev == p->dev ||
 	    p->state != BR_STATE_FORWARDING)
@@ -29,16 +30,51 @@
 	return 1;
 }
 
+static int __br_forward_finish(struct sk_buff *skb)
+{
+	NF_HOOK(PF_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev,
+			dev_queue_xmit);
+
+	return 0;
+}
+
+static void __br_deliver(struct net_bridge_port *to, struct sk_buff *skb)
+{
+	struct net_device *indev;
+
+	indev = skb->dev;
+	skb->dev = to->dev;
+
+	NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, indev, skb->dev,
+			__br_forward_finish);
+}
+
 static void __br_forward(struct net_bridge_port *to, struct sk_buff *skb)
 {
+	struct net_device *indev;
+
+	indev = skb->dev;
 	skb->dev = to->dev;
-	dev_queue_xmit(skb);
+
+	NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev,
+			__br_forward_finish);
+}
+
+/* called under bridge lock */
+void br_deliver(struct net_bridge_port *to, struct sk_buff *skb)
+{
+	if (should_deliver(to, skb)) {
+		__br_deliver(to, skb);
+		return;
+	}
+
+	kfree_skb(skb);
 }
 
 /* called under bridge lock */
 void br_forward(struct net_bridge_port *to, struct sk_buff *skb)
 {
-	if (should_forward(to, skb)) {
+	if (should_deliver(to, skb)) {
 		__br_forward(to, skb);
 		return;
 	}
@@ -47,7 +83,8 @@
 }
 
 /* called under bridge lock */
-void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone)
+static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone,
+	void (*__packet_hook)(struct net_bridge_port *p, struct sk_buff *skb))
 {
 	struct net_bridge_port *p;
 	struct net_bridge_port *prev;
@@ -67,7 +104,7 @@
 
 	p = br->port_list;
 	while (p != NULL) {
-		if (should_forward(p, skb)) {
+		if (should_deliver(p, skb)) {
 			if (prev != NULL) {
 				struct sk_buff *skb2;
 
@@ -77,7 +114,7 @@
 					return;
 				}
 
-				__br_forward(prev, skb2);
+				__packet_hook(prev, skb2);
 			}
 
 			prev = p;
@@ -87,9 +124,21 @@
 	}
 
 	if (prev != NULL) {
-		__br_forward(prev, skb);
+		__packet_hook(prev, skb);
 		return;
 	}
 
 	kfree_skb(skb);
+}
+
+/* called under bridge lock */
+void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, int clone)
+{
+	br_flood(br, skb, clone, __br_deliver);
+}
+
+/* called under bridge lock */
+void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, int clone)
+{
+	br_flood(br, skb, clone, __br_forward);
 }
diff -u --recursive --new-file v2.4.5/linux/net/bridge/br_input.c linux/net/bridge/br_input.c
--- v2.4.5/linux/net/bridge/br_input.c	Fri Dec 29 14:07:24 2000
+++ linux/net/bridge/br_input.c	Mon Jun 11 19:15:27 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_input.c,v 1.7 2000/12/13 16:44:14 davem Exp $
+ *	$Id: br_input.c,v 1.8 2001/06/01 09:28:28 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -17,20 +17,33 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/if_bridge.h>
+#include <linux/netfilter_bridge.h>
 #include "br_private.h"
 
 unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
 
+static int br_pass_frame_up_finish(struct sk_buff *skb)
+{
+	netif_rx(skb);
+
+	return 0;
+}
+
 static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
 {
+	struct net_device *indev;
+
 	br->statistics.rx_packets++;
 	br->statistics.rx_bytes += skb->len;
 
+	indev = skb->dev;
 	skb->dev = &br->dev;
 	skb->pkt_type = PACKET_HOST;
 	skb_pull(skb, skb->mac.raw - skb->data);
 	skb->protocol = eth_type_trans(skb, &br->dev);
-	netif_rx(skb);
+
+	NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
+			br_pass_frame_up_finish);
 }
 
 static void __br_handle_frame(struct sk_buff *skb)
@@ -91,7 +104,7 @@
 		goto freeandout;
 
 	if (dest[0] & 1) {
-		br_flood(br, skb, 1);
+		br_flood_forward(br, skb, 1);
 		if (!passedup)
 			br_pass_frame_up(br, skb);
 		else
@@ -116,7 +129,7 @@
 		return;
 	}
 
-	br_flood(br, skb, 0);
+	br_flood_forward(br, skb, 0);
 	return;
 
  handle_special_frame:
@@ -129,7 +142,7 @@
 	kfree_skb(skb);
 }
 
-void br_handle_frame(struct sk_buff *skb)
+static int br_handle_frame_finish(struct sk_buff *skb)
 {
 	struct net_bridge *br;
 
@@ -137,4 +150,12 @@
 	read_lock(&br->lock);
 	__br_handle_frame(skb);
 	read_unlock(&br->lock);
+
+	return 0;
+}
+
+void br_handle_frame(struct sk_buff *skb)
+{
+	NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
+			br_handle_frame_finish);
 }
diff -u --recursive --new-file v2.4.5/linux/net/bridge/br_private.h linux/net/bridge/br_private.h
--- v2.4.5/linux/net/bridge/br_private.h	Fri Feb  9 11:34:13 2001
+++ linux/net/bridge/br_private.h	Mon Jun 11 19:15:27 2001
@@ -4,7 +4,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_private.h,v 1.5 2001/02/05 06:03:47 davem Exp $
+ *	$Id: br_private.h,v 1.6 2001/06/01 09:28:28 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -141,11 +141,16 @@
 		   int is_local);
 
 /* br_forward.c */
+extern void br_deliver(struct net_bridge_port *to,
+		struct sk_buff *skb);
 extern void br_forward(struct net_bridge_port *to,
 		struct sk_buff *skb);
-extern void br_flood(struct net_bridge *br,
-	      struct sk_buff *skb,
-	      int clone);
+extern void br_flood_deliver(struct net_bridge *br,
+		      struct sk_buff *skb,
+		      int clone);
+extern void br_flood_forward(struct net_bridge *br,
+		      struct sk_buff *skb,
+		      int clone);
 
 /* br_if.c */
 extern int br_add_bridge(char *name);
diff -u --recursive --new-file v2.4.5/linux/net/core/dev.c linux/net/core/dev.c
--- v2.4.5/linux/net/core/dev.c	Sat May 19 18:11:49 2001
+++ linux/net/core/dev.c	Mon Jun 11 19:15:27 2001
@@ -1278,7 +1278,7 @@
 
 	ret = pt->func(skb, skb->dev, pt);
 
-	tasklet_enable(bh_task_vec+TIMER_BH);
+	tasklet_hi_enable(bh_task_vec+TIMER_BH);
 	spin_unlock(&net_bh_lock);
 	return ret;
 }
diff -u --recursive --new-file v2.4.5/linux/net/core/neighbour.c linux/net/core/neighbour.c
--- v2.4.5/linux/net/core/neighbour.c	Tue Nov 28 21:53:45 2000
+++ linux/net/core/neighbour.c	Mon Jun 11 19:15:27 2001
@@ -308,7 +308,7 @@
 	}
 
 	/* Device specific setup. */
-	if (n->parms && n->parms->neigh_setup &&
+	if (n->parms->neigh_setup &&
 	    (error = n->parms->neigh_setup(n)) < 0) {
 		neigh_release(n);
 		return ERR_PTR(error);
diff -u --recursive --new-file v2.4.5/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
--- v2.4.5/linux/net/ipv4/fib_frontend.c	Wed May 16 10:31:23 2001
+++ linux/net/ipv4/fib_frontend.c	Mon Jun 11 19:15:27 2001
@@ -5,7 +5,7 @@
  *
  *		IPv4 Forwarding Information Base: FIB frontend.
  *
- * Version:	$Id: fib_frontend.c,v 1.24 2001/05/13 18:14:46 davem Exp $
+ * Version:	$Id: fib_frontend.c,v 1.25 2001/05/29 22:16:25 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -236,8 +236,7 @@
 	if (res.type != RTN_UNICAST)
 		goto e_inval_res;
 	*spec_dst = FIB_RES_PREFSRC(res);
-	if (itag)
-		fib_combine_itag(itag, &res);
+	fib_combine_itag(itag, &res);
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
 	if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)
 #else
diff -u --recursive --new-file v2.4.5/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v2.4.5/linux/net/ipv4/ip_output.c	Thu Apr 12 12:11:39 2001
+++ linux/net/ipv4/ip_output.c	Mon Jun 11 19:15:27 2001
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) output module.
  *
- * Version:	$Id: ip_output.c,v 1.91 2001/03/29 06:25:55 davem Exp $
+ * Version:	$Id: ip_output.c,v 1.93 2001/06/01 14:59:31 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -499,7 +499,7 @@
 	 *	Begin outputting the bytes.
 	 */
 
-	id = (sk ? sk->protinfo.af_inet.id++ : 0);
+	id = sk->protinfo.af_inet.id++;
 
 	do {
 		char *data;
@@ -848,6 +848,7 @@
 		offset += len;
 
 #ifdef CONFIG_NETFILTER
+		skb2->nfmark = skb->nfmark;
 		/* Connection association is same as pre-frag packet */
 		skb2->nfct = skb->nfct;
 		nf_conntrack_get(skb2->nfct);
diff -u --recursive --new-file v2.4.5/linux/net/ipv4/netfilter/ipfwadm_core.c linux/net/ipv4/netfilter/ipfwadm_core.c
--- v2.4.5/linux/net/ipv4/netfilter/ipfwadm_core.c	Fri Aug  4 18:18:49 2000
+++ linux/net/ipv4/netfilter/ipfwadm_core.c	Mon Jun 11 19:15:27 2001
@@ -20,7 +20,7 @@
  *	license in recognition of the original copyright.
  *				-- Alan Cox.
  *
- *	$Id: ipfwadm_core.c,v 1.4 2000/07/26 01:04:21 davem Exp $
+ *	$Id: ipfwadm_core.c,v 1.5 2001/06/01 14:56:53 davem Exp $
  *
  *	Ported from BSD to Linux,
  *		Alan Cox 22/Nov/1994.
@@ -515,7 +515,7 @@
 			}
 			continue;	/* Mismatch */
 
-		ifa_ok:
+		ifa_ok:;
 		}
 
 		/*
diff -u --recursive --new-file v2.4.5/linux/net/ipv4/netfilter/ipt_REJECT.c linux/net/ipv4/netfilter/ipt_REJECT.c
--- v2.4.5/linux/net/ipv4/netfilter/ipt_REJECT.c	Fri Apr 27 14:15:01 2001
+++ linux/net/ipv4/netfilter/ipt_REJECT.c	Mon Jun 11 19:15:27 2001
@@ -309,9 +309,9 @@
     		break;
 	case IPT_TCP_RESET:
 		send_reset(*pskb, hooknum == NF_IP_LOCAL_IN);
-		break;
 	case IPT_ICMP_ECHOREPLY:
 		/* Doesn't happen. */
+		break;
 	}
 
 	return NF_DROP;
diff -u --recursive --new-file v2.4.5/linux/net/ipv4/netfilter/ipt_unclean.c linux/net/ipv4/netfilter/ipt_unclean.c
--- v2.4.5/linux/net/ipv4/netfilter/ipt_unclean.c	Thu Apr 27 15:43:15 2000
+++ linux/net/ipv4/netfilter/ipt_unclean.c	Wed Jun 20 16:05:21 2001
@@ -76,7 +76,7 @@
 		    = { 12, 12, ICMP_NOT_ERROR, 0, 0 } };
 
 	/* Can't do anything if it's a fragment. */
-	if (!offset)
+	if (offset)
 		return 1;
 
 	/* Must cover type and code. */
@@ -87,7 +87,7 @@
 
 	/* If not embedded. */
 	if (!embedded) {
-		/* Bad checksum?  Don't print, just drop. */
+		/* Bad checksum?  Don't print, just ignore. */
 		if (!more_frags
 		    && ip_compute_csum((unsigned char *) icmph, datalen) != 0)
 			return 0;
@@ -108,6 +108,8 @@
 			   length of iph + 8 bytes. */
 			struct iphdr *inner = (void *)icmph + 8;
 
+			/* datalen > 8 since all ICMP_IS_ERROR types
+                           have min length > 8 */
 			if (datalen - 8 < sizeof(struct iphdr)) {
 				limpk("ICMP error internal way too short\n");
 				return 0;
@@ -155,6 +157,8 @@
 		u_int32_t arg = ntohl(icmph->un.gateway);
 
 		if (icmph->code == 0) {
+			/* Code 0 means that upper 8 bits is pointer
+                           to problem. */
 			if ((arg >> 24) >= iph->ihl*4) {
 				limpk("ICMP PARAMETERPROB ptr = %u\n",
 				      ntohl(icmph->un.gateway) >> 24);
@@ -196,7 +200,7 @@
 	  int embedded)
 {
 	/* Can't do anything if it's a fragment. */
-	if (!offset)
+	if (offset)
 		return 1;
 
 	/* CHECK: Must cover UDP header. */
@@ -205,7 +209,7 @@
 		return 0;
 	}
 
-	/* Bad checksum?  Don't print, just drop. */
+	/* Bad checksum?  Don't print, just say it's unclean. */
 	/* FIXME: SRC ROUTE packets won't match checksum --RR */
 	if (!more_frags && !embedded
 	    && csum_tcpudp_magic(iph->saddr, iph->daddr, datalen, IPPROTO_UDP,
@@ -263,7 +267,7 @@
 	  int more_frags,
 	  int embedded)
 {
-	u_int8_t *opt = (u_int8_t *)(tcph + 1);
+	u_int8_t *opt = (u_int8_t *)tcph;
 	u_int8_t tcpflags;
 	int end_of_options = 0;
 	size_t i;
@@ -272,7 +276,7 @@
 	/* In fact, this is caught below (offset < 516). */
 
 	/* Can't do anything if it's a fragment. */
-	if (!offset)
+	if (offset)
 		return 1;
 
 	/* CHECK: Smaller than minimal TCP hdr. */
@@ -281,7 +285,8 @@
 			limpk("Packet length %u < TCP header.\n", datalen);
 			return 0;
 		}
-		/* Must have ports available (datalen >= 8). */
+		/* Must have ports available (datalen >= 8), from
+                   check_icmp which set embedded = 1 */
 		/* CHECK: TCP ports inside ICMP error */
 		if (!tcph->source || !tcph->dest) {
 			limpk("Zero TCP ports %u/%u.\n",
@@ -301,7 +306,7 @@
 			return 1;
 	}
 
-	/* Bad checksum?  Don't print, just drop. */
+	/* Bad checksum?  Don't print, just say it's unclean. */
 	/* FIXME: SRC ROUTE packets won't match checksum --RR */
 	if (!more_frags && !embedded
 	    && csum_tcpudp_magic(iph->saddr, iph->daddr, datalen, IPPROTO_TCP,
@@ -373,6 +378,8 @@
 				      (unsigned int) opt[i], i);
 				return 0;
 			}
+			/* Move to next option */
+			i += opt[i+1];
 		}
 	}
 
@@ -384,7 +391,7 @@
 static int
 check_ip(struct iphdr *iph, size_t length, int embedded)
 {
-	u_int8_t *opt = (u_int8_t *)(iph + 1);
+	u_int8_t *opt = (u_int8_t *)iph;
 	int end_of_options = 0;
 	void *protoh;
 	size_t datalen;
@@ -430,18 +437,20 @@
 				      opt[i]);
 				return 0;
 			}
-			/* CHECK: zero-length options. */
-			else if (opt[i+1] == 0) {
-				limpk("IP option %u 0 len\n",
-				      opt[i]);
+			/* CHECK: zero-length or one-length options. */
+			else if (opt[i+1] < 2) {
+				limpk("IP option %u %u len\n",
+				      opt[i], opt[i+1]);
 				return 0;
 			}
 			/* CHECK: oversize options. */
-			else if (opt[i+1] + i >= iph->ihl * 4) {
+			else if (opt[i+1] + i > iph->ihl * 4) {
 				limpk("IP option %u at %u too long\n",
 				      opt[i], i);
 				return 0;
 			}
+			/* Move to next option */
+			i += opt[i+1];
 		}
 	}
 
@@ -495,10 +504,10 @@
 		return 0;
 	}
 
-	/* CHECK: Min offset of frag = 128 - 60 (max IP hdr len). */
-	if (offset && offset * 8 < MIN_LIKELY_MTU - 60) {
+	/* CHECK: Min offset of frag = 128 - IP hdr len. */
+	if (offset && offset * 8 < MIN_LIKELY_MTU - iph->ihl * 4) {
 		limpk("Fragment starts at %u < %u\n", offset * 8,
-		      MIN_LIKELY_MTU-60);
+		      MIN_LIKELY_MTU - iph->ihl * 4);
 		return 0;
 	}
 
diff -u --recursive --new-file v2.4.5/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v2.4.5/linux/net/ipv4/raw.c	Wed May 16 10:31:27 2001
+++ linux/net/ipv4/raw.c	Thu Jun 14 14:16:58 2001
@@ -5,7 +5,7 @@
  *
  *		RAW - implementation of IP "raw" sockets.
  *
- * Version:	$Id: raw.c,v 1.61 2001/05/03 20:56:04 davem Exp $
+ * Version:	$Id: raw.c,v 1.62 2001/06/05 10:52:15 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -121,8 +121,11 @@
 	int type;
 
 	type = skb->h.icmph->type;
-	if (type < 32)
-		return test_bit(type, &sk->tp_pinfo.tp_raw4.filter);
+	if (type < 32) {
+		__u32 data = sk->tp_pinfo.tp_raw4.filter.data;
+
+		return ((1 << type) & data) != 0;
+	}
 
 	/* Do not block unknown ICMP types */
 	return 0;
diff -u --recursive --new-file v2.4.5/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.4.5/linux/net/ipv4/tcp_input.c	Thu May 24 15:00:59 2001
+++ linux/net/ipv4/tcp_input.c	Mon Jun 11 19:15:27 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.231 2001/05/22 05:15:16 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.232 2001/05/24 22:32:49 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -2611,10 +2611,10 @@
 	if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) {
 		/* A retransmit, 2nd most common case.  Force an immediate ack. */
 		NET_INC_STATS_BH(DelayedACKLost);
-		tcp_enter_quickack_mode(tp);
 		tcp_dsack_set(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq);
 
 out_of_window:
+		tcp_enter_quickack_mode(tp);
 		tcp_schedule_ack(tp);
 drop:
 		__kfree_skb(skb);
diff -u --recursive --new-file v2.4.5/linux/net/ipv6/ip6_fib.c linux/net/ipv6/ip6_fib.c
--- v2.4.5/linux/net/ipv6/ip6_fib.c	Sun Mar 25 18:14:25 2001
+++ linux/net/ipv6/ip6_fib.c	Thu Jun 14 14:16:58 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: ip6_fib.c,v 1.23 2001/03/19 20:31:17 davem Exp $
+ *	$Id: ip6_fib.c,v 1.24 2001/06/05 11:36:55 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -174,7 +174,7 @@
 
 			xb = ntohl(xb);
 
-			while (test_bit(j, &xb) == 0)
+			while ((xb & (1 << j)) == 0)
 				j--;
 
 			return (i * 32 + 31 - j);
diff -u --recursive --new-file v2.4.5/linux/net/ipv6/raw.c linux/net/ipv6/raw.c
--- v2.4.5/linux/net/ipv6/raw.c	Thu Apr 12 12:11:39 2001
+++ linux/net/ipv6/raw.c	Thu Jun 14 14:16:58 2001
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/raw.c
  *
- *	$Id: raw.c,v 1.45 2001/02/18 09:10:42 davem Exp $
+ *	$Id: raw.c,v 1.46 2001/06/05 11:36:55 davem Exp $
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
@@ -117,8 +117,13 @@
 
 	opt = &sk->tp_pinfo.tp_raw;
 	if (pskb_may_pull(skb, sizeof(struct icmp6hdr))) {
+		__u32 *data = &opt->filter.data[0];
+		int bit_nr;
+
 		icmph = (struct icmp6hdr *) skb->data;
-		return test_bit(icmph->icmp6_type, &opt->filter);
+		bit_nr = icmph->icmp6_type;
+
+		return (data[bit_nr >> 5] & (1 << (bit_nr & 31))) != 0;
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.4.5/linux/net/irda/irnet/irnet.h linux/net/irda/irnet/irnet.h
--- v2.4.5/linux/net/irda/irnet/irnet.h	Tue May  1 16:05:00 2001
+++ linux/net/irda/irnet/irnet.h	Mon Jun 11 19:15:27 2001
@@ -168,6 +168,23 @@
  *		(but PPP doesn't read the MTU value :-()
  *	o Declare hashbin HB_NOLOCK instead of HB_LOCAL to avoid
  *		disabling and enabling irq twice
+ *
+ * v6 - 31/05/01 - Jean II
+ *	o Print source address in Found, Discovery, Expiry & Request events
+ *	o Print requested source address in /proc/net/irnet
+ *	o Change control channel input. Allow multiple commands in one line.
+ *	o Add saddr command to change ap->rsaddr (and use that in IrDA)
+ *	---
+ *	o Make the IrDA connection procedure totally asynchronous.
+ *	  Heavy rewrite of the IAS query code and the whole connection
+ *	  procedure. Now, irnet_connect() no longer need to be called from
+ *	  a process context...
+ *	o Enable IrDA connect retries in ppp_irnet_send(). The good thing
+ *	  is that IrDA connect retries are directly driven by PPP LCP
+ *	  retries (we retry for each LCP packet), so that everything
+ *	  is transparently controlled from pppd lcp-max-configure.
+ *	o Add ttp_connect flag to prevent rentry on the connect procedure
+ *	o Test and fixups to eliminate side effects of retries
  */
 
 /***************************** INCLUDES *****************************/
@@ -181,6 +198,8 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/netdevice.h>
 #include <linux/poll.h>
+#include <linux/config.h>
+#include <linux/ctype.h>	/* isspace() */
 #include <asm/uaccess.h>
 
 #include <linux/ppp_defs.h>
@@ -214,7 +233,7 @@
 
 /* PPP side of the business */
 #define BLOCK_WHEN_CONNECT	/* Block packets when connecting */
-#undef CONNECT_IN_SEND		/* Will crash hard your box... */
+#define CONNECT_IN_SEND		/* Retry IrDA connection procedure */
 #undef FLUSH_TO_PPP		/* Not sure about this one, let's play safe */
 #undef SECURE_DEVIRNET		/* Bah... */
 
@@ -249,9 +268,11 @@
 #define DEBUG_IRDA_SERV_INFO	0	/* various info */
 #define DEBUG_IRDA_SERV_ERROR	1	/* problems */
 #define DEBUG_IRDA_TCB_TRACE	0	/* IRDA IrTTP callbacks */
-#define DEBUG_IRDA_OCB_TRACE	0	/* IRDA other callbacks */
 #define DEBUG_IRDA_CB_INFO	0	/* various info */
 #define DEBUG_IRDA_CB_ERROR	1	/* problems */
+#define DEBUG_IRDA_OCB_TRACE	0	/* IRDA other callbacks */
+#define DEBUG_IRDA_OCB_INFO	0	/* various info */
+#define DEBUG_IRDA_OCB_ERROR	1	/* problems */
 
 #define DEBUG_ASSERT		0	/* Verify all assertions */
 
@@ -351,13 +372,15 @@
   /* ------------------------ IrTTP part ------------------------ */
   /* We create a pseudo "socket" over the IrDA tranport */
   int			ttp_open;	/* Set when IrTTP is ready */
+  int			ttp_connect;	/* Set when IrTTP is connecting */
   struct tsap_cb *	tsap;		/* IrTTP instance (the connection) */
 
   char			rname[NICKNAME_MAX_LEN + 1];
 					/* IrDA nickname of destination */
-  __u32			raddr;		/* Requested peer IrDA address */
-  __u32			saddr;		/* my local IrDA address */
+  __u32			rdaddr;		/* Requested peer IrDA address */
+  __u32			rsaddr;		/* Requested local IrDA address */
   __u32			daddr;		/* actual peer IrDA address */
+  __u32			saddr;		/* my local IrDA address */
   __u8			dtsap_sel;	/* Remote TSAP selector */
   __u8			stsap_sel;	/* Local TSAP selector */
 
@@ -374,17 +397,14 @@
   int			nslots;		/* Number of slots for discovery */
 
   struct iriap_cb *	iriap;		/* Used to query remote IAS */
-  wait_queue_head_t	query_wait;	/* Wait for the answer to a query */
-  struct ias_value *	ias_result;	/* Result of remote IAS query */
   int			errno;		/* status of the IAS query */
 
-  /* ---------------------- Optional parts ---------------------- */
-#ifdef INITIAL_DISCOVERY
-  /* Stuff used to dump discovery log */
+  /* -------------------- Discovery log part -------------------- */
+  /* Used by initial discovery on the control channel
+   * and by irnet_discover_daddr_and_lsap_sel() */
   struct irda_device_info *discoveries;	/* Copy of the discovery log */
   int			disco_index;	/* Last read in the discovery log */
   int			disco_number;	/* Size of the discovery log */
-#endif /* INITIAL_DISCOVERY */
 
 } irnet_socket;
 
@@ -411,8 +431,9 @@
 {
   irnet_event	event;
   int		unit;
-  __u32		addr;
-  char		name[NICKNAME_MAX_LEN + 1];
+  __u32		saddr;
+  __u32		daddr;
+  char		name[NICKNAME_MAX_LEN + 1];	/* 21 + 1 */
 } irnet_log;
 
 /*
diff -u --recursive --new-file v2.4.5/linux/net/irda/irnet/irnet_irda.c linux/net/irda/irnet/irnet_irda.c
--- v2.4.5/linux/net/irda/irnet/irnet_irda.c	Sat May 19 17:47:55 2001
+++ linux/net/irda/irnet/irnet_irda.c	Mon Jun 11 19:15:27 2001
@@ -8,7 +8,6 @@
  * and exchange frames with IrTTP.
  */
 
-#include <linux/config.h>
 #include "irnet_irda.h"		/* Private header */
 
 /************************* CONTROL CHANNEL *************************/
@@ -27,14 +26,15 @@
 static void
 irnet_post_event(irnet_socket *	ap,
 		 irnet_event	event,
-		 __u32		addr,
+		 __u32		saddr,
+		 __u32		daddr,
 		 char *		name)
 {
   unsigned long		flags;		/* For spinlock */
   int			index;		/* In the log */
 
-  DENTER(CTRL_TRACE, "(ap=0x%X, event=%d, addr=%08x, name=``%s'')\n",
-	 (unsigned int) ap, event, addr, name);
+  DENTER(CTRL_TRACE, "(ap=0x%X, event=%d, daddr=%08x, name=``%s'')\n",
+	 (unsigned int) ap, event, daddr, name);
 
   /* Protect this section via spinlock.
    * Note : as we are the only event producer, we only need to exclude
@@ -45,7 +45,8 @@
   /* Copy the event in the log */
   index = irnet_events.index;
   irnet_events.log[index].event = event;
-  irnet_events.log[index].addr = addr;
+  irnet_events.log[index].daddr = daddr;
+  irnet_events.log[index].saddr = saddr;
   /* Try to copy IrDA nickname */
   if(name)
     strcpy(irnet_events.log[index].name, name);
@@ -129,6 +130,92 @@
 
 /*------------------------------------------------------------------*/
 /*
+ * Function irnet_ias_to_tsap (self, result, value)
+ *
+ *    Examine an IAS object and extract TSAP
+ *
+ * We do an IAP query to find the TSAP associated with the IrNET service.
+ * When IrIAP pass us the result of the query, this function look at
+ * the return values to check for failures and extract the TSAP if
+ * possible.
+ * Also deallocate value
+ * The failure is in self->errno
+ * Return TSAP or -1
+ */
+static inline __u8
+irnet_ias_to_tsap(irnet_socket *	self,
+		  int			result,
+		  struct ias_value *	value)
+{
+  __u8	dtsap_sel = 0;		/* TSAP we are looking for */
+
+  DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);
+
+  /* By default, no error */
+  self->errno = 0;
+
+  /* Check if request succeeded */
+  switch(result)
+    {
+      /* Standard errors : service not available */
+    case IAS_CLASS_UNKNOWN:
+    case IAS_ATTRIB_UNKNOWN:
+      DEBUG(IRDA_SR_INFO, "IAS object doesn't exist ! (%d)\n", result);
+      self->errno = -EADDRNOTAVAIL;
+      break;
+
+      /* Other errors, most likely IrDA stack failure */
+    default :
+      DEBUG(IRDA_SR_INFO, "IAS query failed ! (%d)\n", result);
+      self->errno = -EHOSTUNREACH;
+      break;
+
+      /* Success : we got what we wanted */
+    case IAS_SUCCESS:
+      break;
+    }
+
+  /* Check what was returned to us */
+  if(value != NULL)
+    {
+      /* What type of argument have we got ? */
+      switch(value->type)
+	{
+	case IAS_INTEGER:
+	  DEBUG(IRDA_SR_INFO, "result=%d\n", value->t.integer);
+	  if(value->t.integer != -1)
+	    /* Get the remote TSAP selector */
+	    dtsap_sel = value->t.integer;
+	  else 
+	    self->errno = -EADDRNOTAVAIL;
+	  break;
+	default:
+	  self->errno = -EADDRNOTAVAIL;
+	  DERROR(IRDA_SR_ERROR, "bad type ! (0x%X)\n", value->type);
+	  break;
+	}
+
+      /* Cleanup */
+      irias_delete_value(value);
+    }
+  else	/* value == NULL */
+    {
+      /* Nothing returned to us - usually result != SUCCESS */
+      if(!(self->errno))
+	{
+	  DERROR(IRDA_SR_ERROR,
+		 "IrDA bug : result == SUCCESS && value == NULL\n");
+	  self->errno = -EHOSTUNREACH;
+	}
+    }
+  DEXIT(IRDA_SR_TRACE, "\n");
+
+  /* Return the TSAP */
+  return(dtsap_sel);
+}
+
+/*------------------------------------------------------------------*/
+/*
  * Function irnet_find_lsap_sel (self)
  *
  *    Try to lookup LSAP selector in remote LM-IAS
@@ -139,7 +226,7 @@
  * Note that in some case, the query fail even before we go to sleep,
  * creating some races...
  */
-static int
+static inline int
 irnet_find_lsap_sel(irnet_socket *	self)
 {
   DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);
@@ -155,48 +242,101 @@
   self->errno = -EHOSTUNREACH;
 
   /* Query remote LM-IAS */
-  iriap_getvaluebyclass_request(self->iriap, self->saddr, self->daddr,
+  iriap_getvaluebyclass_request(self->iriap, self->rsaddr, self->daddr,
 				IRNET_SERVICE_NAME, IRNET_IAS_VALUE);
-  /* Wait for answer (if not already failed) */
-  if(self->iriap != NULL)
-    interruptible_sleep_on(&self->query_wait);
 
-  /* Check what happened */
-  if(self->errno)
+  /* The above request is non-blocking.
+   * After a while, IrDA will call us back in irnet_getvalue_confirm()
+   * We will then call irnet_ias_to_tsap() and finish the
+   * connection procedure */
+
+  DEXIT(IRDA_SR_TRACE, "\n");
+  return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_connect_tsap (self)
+ *
+ *    Initialise the TTP socket and initiate TTP connection
+ *
+ */
+static inline int
+irnet_connect_tsap(irnet_socket *	self)
+{
+  int		err;
+
+  DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);
+
+  /* Open a local TSAP (an IrTTP instance) */
+  err = irnet_open_tsap(self);
+  if(err != 0)
     {
-      DEBUG(IRDA_SR_INFO, "IAS query failed! (%d)\n", self->errno);
-      /* Requested object/attribute doesn't exist */
-      if((self->errno == IAS_CLASS_UNKNOWN) ||
-	 (self->errno == IAS_ATTRIB_UNKNOWN))
-	return (-EADDRNOTAVAIL);
-      else
-	return (-EHOSTUNREACH);
+      self->ttp_connect = 0;
+      DERROR(IRDA_SR_ERROR, "connect aborted!\n");
+      return(err);
     }
 
-  /* Get the remote TSAP selector */
-  switch(self->ias_result->type)
+  /* Connect to remote device */
+  err = irttp_connect_request(self->tsap, self->dtsap_sel, 
+			      self->rsaddr, self->daddr, NULL, 
+			      self->max_sdu_size_rx, NULL);
+  if(err != 0)
     {
-    case IAS_INTEGER:
-      DEBUG(IRDA_SR_INFO, "result=%d\n", self->ias_result->t.integer);
-      if(self->ias_result->t.integer != -1)
-	self->dtsap_sel = self->ias_result->t.integer;
-      else 
-	self->dtsap_sel = 0;
-      break;
-    default:
-      self->dtsap_sel = 0;
-      DERROR(IRDA_SR_ERROR, "bad type ! (0x%X)\n", self->ias_result->type);
-      break;
+      self->ttp_connect = 0;
+      DERROR(IRDA_SR_ERROR, "connect aborted!\n");
+      return(err);
     }
-  /* Cleanup */
-  if(self->ias_result)
-    irias_delete_value(self->ias_result);
+
+  /* The above call is non-blocking.
+   * After a while, the IrDA stack will either call us back in
+   * irnet_connect_confirm() or irnet_disconnect_indication()
+   * See you there ;-) */
 
   DEXIT(IRDA_SR_TRACE, "\n");
-  if(self->dtsap_sel)
-    return 0;
+  return(err);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_discover_next_daddr (self)
+ *
+ *    Query the IrNET TSAP of the next device in the log.
+ *
+ * Used in the TSAP discovery procedure.
+ */
+static inline int
+irnet_discover_next_daddr(irnet_socket *	self)
+{
+  /* Close the last instance of IrIAP, and open a new one.
+   * We can't reuse the IrIAP instance in the IrIAP callback */
+  if(self->iriap)
+    {
+      iriap_close(self->iriap);
+      self->iriap = NULL;
+    }
+  /* Create a new IAP instance */
+  self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
+			   irnet_discovervalue_confirm);
 
-  return -EADDRNOTAVAIL;
+  /* Next discovery - before the call to avoid races */
+  self->disco_index++;
+
+  /* Check if we have one more address to try */
+  if(self->disco_index < self->disco_number)
+    {
+      /* Query remote LM-IAS */
+      iriap_getvaluebyclass_request(self->iriap,
+				    self->discoveries[self->disco_index].saddr,
+				    self->discoveries[self->disco_index].daddr,
+				    IRNET_SERVICE_NAME, IRNET_IAS_VALUE);
+      /* The above request is non-blocking.
+       * After a while, IrDA will call us back in irnet_discovervalue_confirm()
+       * We will then call irnet_ias_to_tsap() and come back here again... */
+      return(0);
+    }
+  else
+    return(1);
 }
 
 /*------------------------------------------------------------------*/
@@ -205,100 +345,67 @@
  *
  *    This try to find a device with the requested service.
  *
+ * Initiate a TSAP discovery procedure.
  * It basically look into the discovery log. For each address in the list,
  * it queries the LM-IAS of the device to find if this device offer
  * the requested service.
  * If there is more than one node supporting the service, we complain
  * to the user (it should move devices around).
- * The, we set both the destination address and the lsap selector to point
- * on the service on the unique device we have found.
+ * If we find one node which have the requested TSAP, we connect to it.
  *
- * Note : this function fails if there is more than one device in range,
- * because IrLMP doesn't disconnect the LAP when the last LSAP is closed.
- * Moreover, we would need to wait the LAP disconnection...
+ * This function just start the whole procedure. It request the discovery
+ * log and submit the first IAS query.
+ * The bulk of the job is handled in irnet_discovervalue_confirm()
+ *
+ * Note : this procedure fails if there is more than one device in range
+ * on the same dongle, because IrLMP doesn't disconnect the LAP when the
+ * last LSAP is closed. Moreover, we would need to wait the LAP
+ * disconnection...
  */
 static inline int
 irnet_discover_daddr_and_lsap_sel(irnet_socket *	self)
 {
-  struct irda_device_info *discoveries;	/* Copy of the discovery log */
-  int	number;			/* Number of nodes in the log */
-  int	i;
-  int	err = -ENETUNREACH;
-  __u32	daddr = DEV_ADDR_ANY;	/* Address we found the service on */
-  __u8	dtsap_sel = 0x0;	/* TSAP associated with it */
+  int	ret;
 
   DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);
 
-  /* Ask lmp for the current discovery log
-   * Note : we have to use irlmp_get_discoveries(), as opposed
-   * to play with the cachelog directly, because while we are
-   * making our ias query, le log might change... */
-  discoveries = irlmp_get_discoveries(&number, self->mask);
-  /* Check if the we got some results */
-  if (discoveries == NULL)
-    DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n");
+  /* Ask lmp for the current discovery log */
+  self->discoveries = irlmp_get_discoveries(&self->disco_number, self->mask);
 
-  /* 
-   * Now, check all discovered devices (if any), and connect
-   * client only about the services that the client is
-   * interested in...
-   */
-  for(i = 0; i < number; i++)
+  /* Check if the we got some results */
+  if(self->discoveries == NULL)
     {
-      /* Try the address in the log */
-      self->daddr = discoveries[i].daddr;
-      self->saddr = 0x0;
-      DEBUG(IRDA_SR_INFO, "trying daddr = %08x\n", self->daddr);
-
-      /* Query remote LM-IAS for this service */
-      err = irnet_find_lsap_sel(self);
-      switch(err)
-	{
-	case 0:
-	  /* We found the requested service */
-	  if(daddr != DEV_ADDR_ANY)
-	    {
-	      DEBUG(IRDA_SR_INFO, "More than one device in range supports IrNET...\n");
-	    }
-	  else
-	    {
-	      /* First time we found that one, save it ! */
-	      daddr = self->daddr;
-	      dtsap_sel = self->dtsap_sel;
-	    }
-	  break;
-	case -EADDRNOTAVAIL:
-	  /* Requested service simply doesn't exist on this node */
-	  break;
-	default:
-	  /* Something bad did happen :-( */
-	  DERROR(IRDA_SR_ERROR, "unexpected IAS query failure\n");
-	  self->daddr = DEV_ADDR_ANY;
-	  kfree(discoveries);
-	  return(-EHOSTUNREACH);
-	  break;
-	}
+      self->disco_number = -1;
+      self->ttp_connect = 0;
+      DRETURN(-ENETUNREACH, IRDA_SR_INFO, "No Cachelog...\n");
     }
-  /* Cleanup our copy of the discovery log */
-  kfree(discoveries);
+  DEBUG(IRDA_SR_INFO, "Got the log (0x%X), size is %d\n",
+	(unsigned int) self->discoveries, self->disco_number);
 
-  /* Check out what we found */
-  if(daddr == DEV_ADDR_ANY)
+  /* Start with the first discovery */
+  self->disco_index = -1;
+  self->daddr = DEV_ADDR_ANY;
+
+  /* This will fail if the log is empty - this is non-blocking */
+  ret = irnet_discover_next_daddr(self);
+  if(ret)
     {
-      self->daddr = DEV_ADDR_ANY;
-      DEXIT(IRDA_SR_INFO, "cannot discover IrNET in any device !!!\n");
-      return(-EADDRNOTAVAIL);
+      /* Close IAP */
+      iriap_close(self->iriap);
+      self->iriap = NULL;
+
+      /* Cleanup our copy of the discovery log */
+      kfree(self->discoveries);
+      self->discoveries = NULL;
+
+      self->ttp_connect = 0;
+      DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n");
     }
 
-  /* Revert back to discovered device & service */
-  self->daddr = daddr;
-  self->saddr = 0x0;
-  self->dtsap_sel = dtsap_sel;
+  /* Follow me in irnet_discovervalue_confirm() */
 
-  DEBUG(IRDA_SR_INFO, "discovered IrNET at address %08x\n", self->daddr);
   DEXIT(IRDA_SR_TRACE, "\n");
-
-  return 0;
+  return(0);
 }
 
 /*------------------------------------------------------------------*/
@@ -367,13 +474,13 @@
 
   self->magic = IRNET_MAGIC;	/* Paranoia */
 
-  init_waitqueue_head(&self->query_wait);
-
   self->ttp_open = 0;		/* Prevent higher layer from accessing IrTTP */
+  self->ttp_connect = 0;	/* Not connecting yet */
   self->rname[0] = '\0';	/* May be set via control channel */
-  self->raddr = DEV_ADDR_ANY;	/* May be set via control channel */
+  self->rdaddr = DEV_ADDR_ANY;	/* May be set via control channel */
+  self->rsaddr = 0x0;		/* May be set via control channel */
   self->daddr = DEV_ADDR_ANY;	/* Until we get connected */
-  self->saddr = 0x0;		/* so IrLMP assign us any link */
+  self->saddr = 0x0;		/* Until we get connected */
   self->max_sdu_size_rx = TTP_SAR_UNBOUND;
 
   /* Register as a client with IrLMP */
@@ -395,6 +502,12 @@
  *	o convert device name to an address
  *	o find the socket number (dlsap)
  *	o Establish the connection
+ *
+ * Note : We no longer mimic af_irda. The IAS query for finding the TSAP
+ * is done asynchronously, like the TTP connection. This allow us to
+ * call this function from any context (not only process).
+ * The downside is that following what's happening in there is tricky
+ * because it involve various functions all over the place...
  */
 int
 irda_irnet_connect(irnet_socket *	self)
@@ -406,8 +519,11 @@
   /* Check if we have opened a local TSAP :
    * If we have already opened a TSAP, it means that either we are already
    * connected or in the process of doing so... */
-  if(self->tsap != NULL)
+  if(self->ttp_connect)
     DRETURN(-EBUSY, IRDA_SOCK_INFO, "Already connecting...\n");
+  self->ttp_connect = 1;
+  if((self->iriap != NULL) || (self->tsap != NULL))
+    DERROR(IRDA_SOCK_ERROR, "Socket not cleaned up...\n");
 
   /* Insert ourselves in the hashbin so that the IrNET server can find us.
    * Notes : 4th arg is string of 32 char max and must be null terminated
@@ -423,41 +539,34 @@
     }
 
   /* If we don't have anything (no address, no name) */
-  if((self->raddr == DEV_ADDR_ANY) && (self->rname[0] == '\0'))
+  if((self->rdaddr == DEV_ADDR_ANY) && (self->rname[0] == '\0'))
     {
       /* Try to find a suitable address */
-      if((err = irnet_discover_daddr_and_lsap_sel(self)) != 0) 
+      if((err = irnet_discover_daddr_and_lsap_sel(self)) != 0)
 	DRETURN(err, IRDA_SOCK_INFO, "auto-connect failed!\n");
+      /* In most cases, the call above is non-blocking */
     }
   else
     {
       /* If we have only the name (no address), try to get an address */
-      if(self->raddr == DEV_ADDR_ANY)
+      if(self->rdaddr == DEV_ADDR_ANY)
 	{
 	  if((err = irnet_dname_to_daddr(self)) != 0)
-	    DRETURN(err, IRDA_SOCK_INFO, "name-connect failed!\n");
+	    DRETURN(err, IRDA_SOCK_INFO, "name connect failed!\n");
 	}
       else
 	/* Use the requested destination address */
-	self->daddr = self->raddr;
+	self->daddr = self->rdaddr;
 
       /* Query remote LM-IAS to find LSAP selector */
-      if((err = irnet_find_lsap_sel(self)) != 0)
-	DRETURN(err, IRDA_SOCK_INFO, "connect failed!\n");
+      irnet_find_lsap_sel(self);
+      /* The above call is non blocking */
     }
-  DEBUG(IRDA_SOCK_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n",
-	self->daddr, self->dtsap_sel);
-
-  /* Open a local TSAP (an IrTTP instance) */
-  err = irnet_open_tsap(self);
-  DABORT(err != 0, err, IRDA_SOCK_ERROR, "connect aborted!\n");
-
-  /* Connect to remote device */
-  err = irttp_connect_request(self->tsap, self->dtsap_sel, 
-			      self->saddr, self->daddr, NULL, 
-			      self->max_sdu_size_rx, NULL);
-  DABORT(err != 0, err, IRDA_SOCK_ERROR, "connect aborted!\n");
 
+  /* At this point, we are waiting for the IrDA stack to call us back,
+   * or we have already failed.
+   * We will finish the connection procedure in irnet_connect_tsap().
+   */
   DEXIT(IRDA_SOCK_TRACE, "\n");
   return(0);
 }
@@ -494,8 +603,21 @@
   irlmp_unregister_client(self->ckey);
 
   /* Unregister with LM-IAS */
-  if(self->iriap) 
-    iriap_close(self->iriap);
+  if(self->iriap)
+    { 
+      iriap_close(self->iriap);
+      self->iriap = NULL;
+    }
+
+  /* If we were connected, post a message */
+  if(self->ttp_open)
+    {
+      /* Note : as the disconnect comes from ppp_generic, the unit number
+       * doesn't exist anymore when we post the event, so we need to pass
+       * NULL as the first arg... */
+      irnet_post_event(NULL, IRNET_DISCONNECT_TO,
+		       self->saddr, self->daddr, self->rname);
+    }
 
   /* Prevent higher layer from accessing IrTTP */
   self->ttp_open = 0;
@@ -507,10 +629,6 @@
       irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
       irttp_close_tsap(self->tsap);
       self->tsap = NULL;
-      /* Note : as the disconnect comes from ppp_generic, the unit number
-       * doesn't exist anymore when we post the event, so we need to pass
-       * NULL as the first arg... */
-      irnet_post_event(NULL, IRNET_DISCONNECT_TO, self->daddr, self->rname);
     }
   self->stsap_sel = 0;
 
@@ -591,8 +709,9 @@
 
   DENTER(IRDA_SERV_TRACE, "(self=0x%X)\n", (unsigned int) self);
 
-  /* Get the address of the requester */
+  /* Get the addresses of the requester */
   self->daddr = irttp_get_daddr(self->tsap);
+  self->saddr = irttp_get_saddr(self->tsap);
 
   /* Try to get the IrDA nickname of the requester */
   err = irnet_daddr_to_dname(self);
@@ -621,7 +740,7 @@
       while(new !=(irnet_socket *) NULL)
 	{
 	  /* Does it have the same address ? */
-	  if((new->raddr == self->daddr) || (new->daddr == self->daddr))
+	  if((new->rdaddr == self->daddr) || (new->daddr == self->daddr))
 	    {
 	      /* Yes !!! Get it.. */
 	      DEBUG(IRDA_SERV_INFO, "Socket 0x%X matches daddr %#08x.\n",
@@ -639,7 +758,7 @@
       while(new !=(irnet_socket *) NULL)
 	{
 	  /* Is it available ? */
-	  if(!(new->ttp_open) && (new->raddr == DEV_ADDR_ANY) &&
+	  if(!(new->ttp_open) && (new->rdaddr == DEV_ADDR_ANY) &&
 	     (new->rname[0] == '\0') && (new->ppp_open))
 	    {
 	      /* Yes !!! Get it.. */
@@ -703,6 +822,7 @@
 
   /* Allow PPP to send its junk over the new socket... */
   new->ttp_open = 1;
+  new->ttp_connect = 0;
 #ifdef CONNECT_INDIC_KICK
   /* As currently we don't packets in ppp_irnet_send(), this is not needed...
    * Also, not doing it give IrDA a chance to finish the setup properly
@@ -711,7 +831,8 @@
 #endif /* CONNECT_INDIC_KICK */
 
   /* Notify the control channel */
-  irnet_post_event(new, IRNET_CONNECT_FROM, new->daddr, self->rname);
+  irnet_post_event(new, IRNET_CONNECT_FROM,
+		   new->saddr, new->daddr, self->rname);
 
   DEXIT(IRDA_SERV_TRACE, "\n");
   return 0;
@@ -740,13 +861,14 @@
   irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
 #endif /* FAIL_SEND_DISCONNECT */
 
+  /* Notify the control channel (see irnet_find_socket()) */
+  irnet_post_event(NULL, IRNET_REQUEST_FROM,
+		   self->saddr, self->daddr, self->rname);
+
   /* Clean up the server to keep it in listen state */
   self->tsap->dtsap_sel = self->tsap->lsap->dlsap_sel = LSAP_ANY;
   self->tsap->lsap->lsap_state = LSAP_DISCONNECTED;
 
-  /* Notify the control channel */
-  irnet_post_event(NULL, IRNET_REQUEST_FROM, self->daddr, self->rname);
-
   DEXIT(IRDA_SERV_TRACE, "\n");
   return;
 }
@@ -934,14 +1056,17 @@
 
   /* If we were active, notify the control channel */
   if(self->ttp_open)
-    irnet_post_event(self, IRNET_DISCONNECT_FROM, self->daddr, self->rname);
+    irnet_post_event(self, IRNET_DISCONNECT_FROM,
+		     self->saddr, self->daddr, self->rname);
   else
     /* If we were trying to connect, notify the control channel */
     if((self->tsap) && (self != &irnet_server.s))
-      irnet_post_event(self, IRNET_NOANSWER_FROM, self->daddr, self->rname);
+      irnet_post_event(self, IRNET_NOANSWER_FROM,
+		       self->saddr, self->daddr, self->rname);
 
   /* Prevent higher layer from accessing IrTTP */
   self->ttp_open = 0;
+  self->ttp_connect = 0;
 
   /* Close our IrTTP connection */
   if((self->tsap) && (self != &irnet_server.s))
@@ -1001,6 +1126,7 @@
   self->saddr = irttp_get_saddr(self->tsap);
 
   /* Allow higher layer to access IrTTP */
+  self->ttp_connect = 0;
   self->ttp_open = 1;
   /* Give a kick in the ass of ppp_generic so that he sends us some data */
   ppp_output_wakeup(&self->chan);
@@ -1021,7 +1147,8 @@
     kfree_skb(skb);
 
   /* Notify the control channel */
-  irnet_post_event(self, IRNET_CONNECT_TO, self->daddr, self->rname);
+  irnet_post_event(self, IRNET_CONNECT_TO,
+		   self->saddr, self->daddr, self->rname);
 
   DEXIT(IRDA_TCB_TRACE, "\n");
 }
@@ -1081,7 +1208,6 @@
 			LOCK_STATUS lock)
 {
   irnet_socket *	self = (irnet_socket *) instance;
-  LOCAL_FLOW		oldflow = self->tx_flow;
 
   DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
   DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n");
@@ -1090,7 +1216,8 @@
   switch(link)
     {
     case STATUS_NO_ACTIVITY:
-      irnet_post_event(self, IRNET_BLOCKED_LINK, self->daddr, self->rname);
+      irnet_post_event(self, IRNET_BLOCKED_LINK,
+		       self->saddr, self->daddr, self->rname);
       break;
     default:
       DEBUG(IRDA_CB_INFO, "Unknown status...\n");
@@ -1199,10 +1326,14 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Function irnet_getvalue_confirm (obj_id, value, priv)
+ * Function irnet_getvalue_confirm (result, obj_id, value, priv)
  *
- *    Got answer from remote LM-IAS, just pass object to requester...
+ *    Got answer from remote LM-IAS, just connect
  *
+ * This is the reply to a IAS query we were doing to find the TSAP of
+ * the device we want to connect to.
+ * If we have found a valid TSAP, just initiate the TTP connection
+ * on this TSAP.
  */
 static void
 irnet_getvalue_confirm(int	result,
@@ -1213,27 +1344,146 @@
   irnet_socket *	self = (irnet_socket *) priv;
 
   DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
-  DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n");
+  DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n");
 
   /* We probably don't need to make any more queries */
   iriap_close(self->iriap);
   self->iriap = NULL;
 
-  /* Check if request succeeded */
-  if(result != IAS_SUCCESS)
+  /* Check if already connected (via irnet_connect_socket()) */
+  if(self->ttp_open)
     {
-      DEBUG(IRDA_CB_INFO, "IAS query failed! (%d)\n", result);
-      self->errno = result;	/* We really need it later */
+      DERROR(IRDA_OCB_ERROR, "Socket already connected. Ouch !\n");
+      return;
     }
-  else
+
+  /* Post process the IAS reply */
+  self->dtsap_sel = irnet_ias_to_tsap(self, result, value);
+
+  /* If error, just go out */
+  if(self->errno)
+    {
+      self->ttp_connect = 0;
+      DERROR(IRDA_OCB_ERROR, "IAS connect failed ! (0x%X)\n", self->errno);
+      return;
+    }
+
+  DEBUG(IRDA_OCB_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n",
+	self->daddr, self->dtsap_sel);
+
+  /* Start up TTP - non blocking */
+  irnet_connect_tsap(self);
+
+  DEXIT(IRDA_OCB_TRACE, "\n");
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_discovervalue_confirm (result, obj_id, value, priv)
+ *
+ *    Handle the TSAP discovery procedure state machine.
+ *    Got answer from remote LM-IAS, try next device
+ *
+ * We are doing a  TSAP discovery procedure, and we got an answer to
+ * a IAS query we were doing to find the TSAP on one of the address
+ * in the discovery log.
+ *
+ * If we have found a valid TSAP for the first time, save it. If it's
+ * not the first time we found one, complain.
+ *
+ * If we have more addresses in the log, just initiate a new query.
+ * Note that those query may fail (see irnet_discover_daddr_and_lsap_sel())
+ *
+ * Otherwise, wrap up the procedure (cleanup), check if we have found
+ * any device and connect to it.
+ */
+static void
+irnet_discovervalue_confirm(int		result,
+			    __u16	obj_id, 
+			    struct ias_value *value,
+			    void *	priv)
+{
+  irnet_socket *	self = (irnet_socket *) priv;
+  __u8			dtsap_sel;		/* TSAP we are looking for */
+
+  DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
+  DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n");
+
+  /* Post process the IAS reply */
+  dtsap_sel = irnet_ias_to_tsap(self, result, value);
+
+  /* Have we got something ? */
+  if(self->errno == 0)
+    {
+      /* We found the requested service */
+      if(self->daddr != DEV_ADDR_ANY)
+	{
+	  DERROR(IRDA_OCB_ERROR, "More than one device in range supports IrNET...\n");
+	}
+      else
+	{
+	  /* First time we found that one, save it ! */
+	  self->daddr = self->discoveries[self->disco_index].daddr;
+	  self->dtsap_sel = dtsap_sel;
+	}
+    }
+
+  /* If no failure */
+  if((self->errno == -EADDRNOTAVAIL) || (self->errno == 0))
+    {
+      int	ret;
+
+      /* Search the next node */
+      ret = irnet_discover_next_daddr(self);
+      if(!ret)
+	{
+	  /* In this case, the above request was non-blocking.
+	   * We will return here after a while... */
+	  return;
+	}
+      /* In this case, we have processed the last discovery item */
+    }
+
+  /* No more queries to be done (failure or last one) */
+
+  /* We probably don't need to make any more queries */
+  iriap_close(self->iriap);
+  self->iriap = NULL;
+
+  /* No more items : remove the log and signal termination */
+  DEBUG(IRDA_OCB_INFO, "Cleaning up log (0x%X)\n",
+	(unsigned int) self->discoveries);
+  if(self->discoveries != NULL)
+    {
+      /* Cleanup our copy of the discovery log */
+      kfree(self->discoveries);
+      self->discoveries = NULL;
+    }
+  self->disco_number = -1;
+
+  /* Check out what we found */
+  if(self->daddr == DEV_ADDR_ANY)
     {
-      /* Pass the object to the caller (so the caller must delete it) */
-      self->ias_result = value;
-      self->errno = 0;
+      self->daddr = DEV_ADDR_ANY;
+      self->ttp_connect = 0;
+      DEXIT(IRDA_OCB_TRACE, ": cannot discover IrNET in any device !!!\n");
+      return;
     }
 
-  /* Wake up any processes waiting for result */
-  wake_up_interruptible(&self->query_wait);
+  /* Check if already connected (via irnet_connect_socket()) */
+  if(self->ttp_open)
+    {
+      DERROR(IRDA_OCB_ERROR, "Socket already connected. Ouch !\n");
+      return;
+    }
+
+  /* We have a valid address - just connect */
+
+  DEBUG(IRDA_OCB_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n",
+	self->daddr, self->dtsap_sel);
+
+  /* Start up TTP - non blocking */
+  irnet_connect_tsap(self);
 
   DEXIT(IRDA_OCB_TRACE, "\n");
 }
@@ -1268,7 +1518,7 @@
   irnet_socket *	self = &irnet_server.s;
 	
   DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
-  DASSERT(priv == &irnet_server, , IRDA_CB_ERROR,
+  DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR,
 	  "Invalid instance (0x%X) !!!\n", (unsigned int) priv);
 
   /* Check if node is discovered is a new one or an old one.
@@ -1280,12 +1530,12 @@
       return;		/* Too old, not interesting -> goodbye */
     }
 
-  DEBUG(IRDA_CB_INFO, "Discovered new IrNET/IrLAN node %s...\n",
+  DEBUG(IRDA_OCB_INFO, "Discovered new IrNET/IrLAN node %s...\n",
 	discovery->nickname);
 
   /* Notify the control channel */
-  irnet_post_event(NULL, IRNET_DISCOVER, discovery->daddr,
-		   discovery->nickname);
+  irnet_post_event(NULL, IRNET_DISCOVER,
+		   discovery->saddr, discovery->daddr, discovery->nickname);
 
   DEXIT(IRDA_OCB_TRACE, "\n");
 }
@@ -1306,15 +1556,15 @@
   irnet_socket *	self = &irnet_server.s;
 	
   DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
-  DASSERT(priv == &irnet_server, , IRDA_CB_ERROR,
+  DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR,
 	  "Invalid instance (0x%X) !!!\n", (unsigned int) priv);
 
-  DEBUG(IRDA_CB_INFO, "IrNET/IrLAN node %s expired...\n",
+  DEBUG(IRDA_OCB_INFO, "IrNET/IrLAN node %s expired...\n",
 	expiry->nickname);
 
   /* Notify the control channel */
-  irnet_post_event(NULL, IRNET_EXPIRE, expiry->daddr,
-		   expiry->nickname);
+  irnet_post_event(NULL, IRNET_EXPIRE,
+		   expiry->saddr, expiry->daddr, expiry->nickname);
 
   DEXIT(IRDA_OCB_TRACE, "\n");
 }
@@ -1370,7 +1620,8 @@
 
       /* First, get the requested configuration */
       len += sprintf(buf+len, "Requested IrDA name: \"%s\", ", self->rname);
-      len += sprintf(buf+len, "addr: %08x\n", self->raddr);
+      len += sprintf(buf+len, "daddr: %08x, ", self->rdaddr);
+      len += sprintf(buf+len, "saddr: %08x\n", self->rsaddr);
 
       /* Second, get all the PPP info */
       len += sprintf(buf+len, "	PPP state: %s",
@@ -1393,7 +1644,13 @@
 	if(self->tsap != NULL)
 	  state = "connecting";
 	else
-	  state = "idle";
+	  if(self->iriap != NULL)
+	    state = "searching";
+	  else
+	    if(self->ttp_connect)
+	      state = "weird";
+	    else
+	      state = "idle";
       len += sprintf(buf+len, "\n	IrDA state: %s, ", state);
       len += sprintf(buf+len, "daddr: %08x, ", self->daddr);
       len += sprintf(buf+len, "stsap_sel: %02x, ", self->stsap_sel);
diff -u --recursive --new-file v2.4.5/linux/net/irda/irnet/irnet_irda.h linux/net/irda/irnet/irnet_irda.h
--- v2.4.5/linux/net/irda/irnet/irnet_irda.h	Tue May  1 16:05:00 2001
+++ linux/net/irda/irnet/irnet_irda.h	Mon Jun 11 19:15:27 2001
@@ -13,7 +13,6 @@
 #define IRNET_IRDA_H
 
 /***************************** INCLUDES *****************************/
-#include <linux/config.h>
 /* Please add other headers in irnet.h */
 
 #include "irnet.h"		/* Module global include */
@@ -69,13 +68,22 @@
 	irnet_post_event(irnet_socket *,
 			 irnet_event,
 			 __u32,
+			 __u32,
 			 char *);
 /* ----------------------- IRDA SUBROUTINES ----------------------- */
 static inline int
 	irnet_open_tsap(irnet_socket *);
-static int
+static inline __u8
+	irnet_ias_to_tsap(irnet_socket *,
+			  int,
+			  struct ias_value *);
+static inline int
 	irnet_find_lsap_sel(irnet_socket *);
 static inline int
+	irnet_connect_tsap(irnet_socket *);
+static inline int
+	irnet_discover_next_daddr(irnet_socket *);
+static inline int
 	irnet_discover_daddr_and_lsap_sel(irnet_socket *);
 static inline int
 	irnet_dname_to_daddr(irnet_socket *);
@@ -135,6 +143,11 @@
 			       __u16,
 			       struct ias_value *,
 			       void *);
+static void
+	irnet_discovervalue_confirm(int,
+				    __u16, 
+				    struct ias_value *,
+				    void *);
 #ifdef DISCOVERY_EVENTS
 static void
 	irnet_discovery_indication(discovery_t *,
diff -u --recursive --new-file v2.4.5/linux/net/irda/irnet/irnet_ppp.c linux/net/irda/irnet/irnet_ppp.c
--- v2.4.5/linux/net/irda/irnet/irnet_ppp.c	Tue May  1 16:05:00 2001
+++ linux/net/irda/irnet/irnet_ppp.c	Mon Jun 11 19:15:27 2001
@@ -37,13 +37,15 @@
 		 const char *	buf,
 		 size_t		count)
 {
-  char		command[5 + NICKNAME_MAX_LEN + 2];
-  int		length = count;
+  char		command[IRNET_MAX_COMMAND];
+  char *	start;		/* Current command beeing processed */
+  char *	next;		/* Next command to process */
+  int		length;		/* Length of current command */
 
   DENTER(CTRL_TRACE, "(ap=0x%X, count=%d)\n", (unsigned int) ap, count);
 
   /* Check for overflow... */
-  DABORT(count > (5 + NICKNAME_MAX_LEN + 1), -ENOMEM,
+  DABORT(count >= IRNET_MAX_COMMAND, -ENOMEM,
 	 CTRL_ERROR, "Too much data !!!\n");
 
   /* Get the data in the driver */
@@ -53,58 +55,110 @@
       return -EFAULT;
     }
 
-  /* Strip out '\n' if needed, and safe terminate the string */
-  if(command[length - 1] == '\0')
-    length--;
-  if(command[length - 1] == '\n')
-    length--;
-  command[length] = '\0';
-  DEBUG(CTRL_INFO, "Command received is ``%s'' (%d-%d).\n",
-	command, length, count);
-
-  /* Check if we recognised the command */
-  /* First command : name */
-  if(!strncmp(command, "name", 4))
-    {
-      /* Copy the name only if is included and not "any" */
-      if((length > 5) && (strcmp(command + 5, "any")))
+  /* Safe terminate the string */
+  command[count] = '\0';
+  DEBUG(CTRL_INFO, "Command line received is ``%s'' (%d).\n",
+	command, count);
+
+  /* Check every commands in the command line */
+  next = command;
+  while(next != NULL)
+    {
+      /* Look at the next command */
+      start = next;
+
+      /* Scrap whitespaces before the command */
+      while(isspace(*start))
+	start++;
+
+      /* ',' is our command separator */
+      next = strchr(start, ',');
+      if(next)
 	{
-	  /* Copy the name for later reuse (including the '/0') */
-	  memcpy(ap->rname, command + 5, length - 5 + 1);
+	  *next = '\0';			/* Terminate command */
+	  length = next - start;	/* Length */
+	  next++;			/* Skip the '\0' */
 	}
       else
-	ap->rname[0] = '\0';
-      DEXIT(CTRL_TRACE, " - rname = ``%s''\n", ap->rname);
-      return(count);
-    }
+	length = strlen(start);
 
-  /* Second command : addr */
-  if(!strncmp(command, "addr", 4))
-    {
-      /* Copy the address only if is included and not "any" */
-      if((length > 5) && (strcmp(command + 5, "any")))
+      DEBUG(CTRL_INFO, "Found command ``%s'' (%d).\n", start, length);
+
+      /* Check if we recognised one of the known command
+       * We can't use "switch" with strings, so hack with "continue" */
+      
+      /* First command : name -> Requested IrDA nickname */
+      if(!strncmp(start, "name", 4))
 	{
-	  char *	endp;
-	  __u32		daddr;
+	  /* Copy the name only if is included and not "any" */
+	  if((length > 5) && (strcmp(start + 5, "any")))
+	    {
+	      /* Strip out trailing whitespaces */
+	      while(isspace(start[length - 1]))
+		length--;
+
+	      /* Copy the name for later reuse */
+	      memcpy(ap->rname, start + 5, length - 5);
+	      ap->rname[length - 5] = '\0';
+	    }
+	  else
+	    ap->rname[0] = '\0';
+	  DEBUG(CTRL_INFO, "Got rname = ``%s''\n", ap->rname);
 
-	  /* Convert argument to a number (last arg is the base) */
-	  daddr = simple_strtoul(command + 5, &endp, 16);
-	  /* Has it worked  ? (endp should be command + count) */
-	  DABORT(endp <= (command + 5), -EINVAL,
-		 CTRL_ERROR, "Invalid address.\n");
-	  /* Save it */
-	  ap->raddr = daddr;
+	  /* Restart the loop */
+	  continue;
+	}
+
+      /* Second command : addr, daddr -> Requested IrDA destination address
+       * Also process : saddr -> Requested IrDA source address */
+      if((!strncmp(start, "addr", 4)) ||
+	 (!strncmp(start, "daddr", 5)) ||
+	 (!strncmp(start, "saddr", 5)))
+	{
+	  __u32		addr = DEV_ADDR_ANY;
+
+	  /* Copy the address only if is included and not "any" */
+	  if((length > 5) && (strcmp(start + 5, "any")))
+	    {
+	      char *	begp = start + 5;
+	      char *	endp;
+
+	      /* Scrap whitespaces before the command */
+	      while(isspace(*begp))
+		begp++;
+
+	      /* Convert argument to a number (last arg is the base) */
+	      addr = simple_strtoul(begp, &endp, 16);
+	      /* Has it worked  ? (endp should be start + length) */
+	      DABORT(endp <= (start + 5), -EINVAL,
+		     CTRL_ERROR, "Invalid address.\n");
+	    }
+	  /* Which type of address ? */
+	  if(start[0] == 's')
+	    {
+	      /* Save it */
+	      ap->rsaddr = addr;
+	      DEBUG(CTRL_INFO, "Got rsaddr = %08x\n", ap->rsaddr);
+	    }
+	  else
+	    {
+	      /* Save it */
+	      ap->rdaddr = addr;
+	      DEBUG(CTRL_INFO, "Got rdaddr = %08x\n", ap->rdaddr);
+	    }
+
+	  /* Restart the loop */
+	  continue;
 	}
-      else
-	ap->raddr = DEV_ADDR_ANY;
-      DEXIT(CTRL_TRACE, " - raddr = %08x\n", ap->raddr);
-      return(count);
-    }
 
-  /* Other possible command : connect N (number of retries) */
+      /* Other possible command : connect N (number of retries) */
 
-  /* Failed... */
-  DABORT(1, -EINVAL, CTRL_ERROR, "Not a recognised IrNET command.\n");
+      /* No command matched -> Failed... */
+      DABORT(1, -EINVAL, CTRL_ERROR, "Not a recognised IrNET command.\n");
+    }
+
+  /* Success : we have parsed all commands successfully */
+  return(count);
 }
 
 #ifdef INITIAL_DISCOVERY
@@ -157,9 +211,10 @@
   if(ap->disco_index < ap->disco_number)
     {
       /* Write an event */
-      sprintf(event, "Found %08x (%s)\n",
+      sprintf(event, "Found %08x (%s) behind %08x\n",
 	      ap->discoveries[ap->disco_index].daddr,
-	      ap->discoveries[ap->disco_index].info);
+	      ap->discoveries[ap->disco_index].info,
+	      ap->discoveries[ap->disco_index].saddr);
       DEBUG(CTRL_INFO, "Writing discovery %d : %s\n",
 	    ap->disco_index, ap->discoveries[ap->disco_index].info);
 
@@ -256,53 +311,56 @@
   switch(irnet_events.log[ap->event_index].event)
     {
     case IRNET_DISCOVER:
-      sprintf(event, "Discovered %08x (%s)\n",
-	      irnet_events.log[ap->event_index].addr,
-	      irnet_events.log[ap->event_index].name);
+      sprintf(event, "Discovered %08x (%s) behind %08x\n",
+	      irnet_events.log[ap->event_index].daddr,
+	      irnet_events.log[ap->event_index].name,
+	      irnet_events.log[ap->event_index].saddr);
       break;
     case IRNET_EXPIRE:
-      sprintf(event, "Expired %08x (%s)\n",
-	      irnet_events.log[ap->event_index].addr,
-	      irnet_events.log[ap->event_index].name);
+      sprintf(event, "Expired %08x (%s) behind %08x\n",
+	      irnet_events.log[ap->event_index].daddr,
+	      irnet_events.log[ap->event_index].name,
+	      irnet_events.log[ap->event_index].saddr);
       break;
     case IRNET_CONNECT_TO:
       sprintf(event, "Connected to %08x (%s) on ppp%d\n",
-	      irnet_events.log[ap->event_index].addr,
+	      irnet_events.log[ap->event_index].daddr,
 	      irnet_events.log[ap->event_index].name,
 	      irnet_events.log[ap->event_index].unit);
       break;
     case IRNET_CONNECT_FROM:
       sprintf(event, "Connection from %08x (%s) on ppp%d\n",
-	      irnet_events.log[ap->event_index].addr,
+	      irnet_events.log[ap->event_index].daddr,
 	      irnet_events.log[ap->event_index].name,
 	      irnet_events.log[ap->event_index].unit);
       break;
     case IRNET_REQUEST_FROM:
-      sprintf(event, "Request from %08x (%s)\n",
-	      irnet_events.log[ap->event_index].addr,
-	      irnet_events.log[ap->event_index].name);
+      sprintf(event, "Request from %08x (%s) behind %08x\n",
+	      irnet_events.log[ap->event_index].daddr,
+	      irnet_events.log[ap->event_index].name,
+	      irnet_events.log[ap->event_index].saddr);
       break;
     case IRNET_NOANSWER_FROM:
       sprintf(event, "No-answer from %08x (%s) on ppp%d\n",
-	      irnet_events.log[ap->event_index].addr,
+	      irnet_events.log[ap->event_index].daddr,
 	      irnet_events.log[ap->event_index].name,
 	      irnet_events.log[ap->event_index].unit);
       break;
     case IRNET_BLOCKED_LINK:
       sprintf(event, "Blocked link with %08x (%s) on ppp%d\n",
-	      irnet_events.log[ap->event_index].addr,
+	      irnet_events.log[ap->event_index].daddr,
 	      irnet_events.log[ap->event_index].name,
 	      irnet_events.log[ap->event_index].unit);
       break;
     case IRNET_DISCONNECT_FROM:
       sprintf(event, "Disconnection from %08x (%s) on ppp%d\n",
-	      irnet_events.log[ap->event_index].addr,
+	      irnet_events.log[ap->event_index].daddr,
 	      irnet_events.log[ap->event_index].name,
 	      irnet_events.log[ap->event_index].unit);
       break;
     case IRNET_DISCONNECT_TO:
       sprintf(event, "Disconnected to %08x (%s)\n",
-	      irnet_events.log[ap->event_index].addr,
+	      irnet_events.log[ap->event_index].daddr,
 	      irnet_events.log[ap->event_index].name);
       break;
     default:
@@ -794,11 +852,9 @@
     {
 #ifdef CONNECT_IN_SEND
       /* Let's try to connect one more time... */
-      /* Note : we won't connect fully yet, but we should be ready for
-       * next packet... */
-      /* Note : we can't do that, we need to have a process context to
-       * go through interruptible_sleep_on() in irnet_find_lsap_sel()
-       * We need to find another way... */
+      /* Note : we won't be connected after this call, but we should be
+       * ready for next packet... */
+      /* If we are already connecting, this will fail */
       irda_irnet_connect(self);
 #endif /* CONNECT_IN_SEND */
 
diff -u --recursive --new-file v2.4.5/linux/net/irda/irnet/irnet_ppp.h linux/net/irda/irnet/irnet_ppp.h
--- v2.4.5/linux/net/irda/irnet/irnet_ppp.h	Mon Apr 30 16:26:09 2001
+++ linux/net/irda/irnet/irnet_ppp.h	Mon Jun 11 19:15:27 2001
@@ -22,13 +22,8 @@
 #define IRNET_MAJOR	10	/* Misc range */
 #define IRNET_MINOR	187	/* Official allocation */
 
-#ifdef LINKNAME_IOCTL
-/* Compatibility with old ppp drivers
- * Should be defined in <linux/if_ppp.h> */
-#ifndef PPPIOCSLINKNAME
-#define PPPIOCSLINKNAME	_IOW('t', 74, struct ppp_option_data)
-#endif /* PPPIOCSLINKNAME */
-#endif /* LINKNAME_IOCTL */
+/* IrNET control channel stuff */
+#define IRNET_MAX_COMMAND	256	/* Max length of a command line */
 
 /* PPP hardcore stuff */
 
diff -u --recursive --new-file v2.4.5/linux/net/khttpd/security.h linux/net/khttpd/security.h
--- v2.4.5/linux/net/khttpd/security.h	Wed Aug 18 09:45:10 1999
+++ linux/net/khttpd/security.h	Tue Jun 12 11:06:54 2001
@@ -9,4 +9,4 @@
 	char value[32-sizeof(void*)];  /* fill 1 cache-line */
 };
 
-#endif
\ No newline at end of file
+#endif
diff -u --recursive --new-file v2.4.5/linux/net/sched/sch_cbq.c linux/net/sched/sch_cbq.c
--- v2.4.5/linux/net/sched/sch_cbq.c	Sun Mar 25 18:14:25 2001
+++ linux/net/sched/sch_cbq.c	Mon Jun 11 19:15:27 2001
@@ -282,6 +282,7 @@
 		case TC_POLICE_SHOT:
 			return NULL;
 		default:
+			break;
 		}
 #endif
 		if (cl->level == 0)
diff -u --recursive --new-file v2.4.5/linux/net/socket.c linux/net/socket.c
--- v2.4.5/linux/net/socket.c	Wed Apr 25 16:13:50 2001
+++ linux/net/socket.c	Mon Jun 11 19:15:27 2001
@@ -1668,6 +1668,10 @@
 extern void wanrouter_init(void);
 #endif
 
+#ifdef CONFIG_BLUEZ
+extern void bluez_init(void);
+#endif
+
 void __init sock_init(void)
 {
 	int i;
@@ -1726,6 +1730,10 @@
 #endif
 #ifdef CONFIG_NETFILTER
 	netfilter_init();
+#endif
+
+#ifdef CONFIG_BLUEZ
+	bluez_init();
 #endif
 }
 
