## Automatically generated incremental diff
## From:   linux-2.4.9-pre1
## To:     linux-2.4.9-pre2
## Robot:  $Id: make-incremental-diff,v 1.8 2001/12/04 06:05:04 hpa Exp $

diff -urN linux-2.4.9-pre1/CREDITS linux/CREDITS
--- linux-2.4.9-pre1/CREDITS	Mon Dec  3 23:01:02 2001
+++ linux/CREDITS	Mon Dec  3 23:01:21 2001
@@ -948,6 +948,15 @@
 S: San Jose, California 95131
 S: USA
 
+N: Fernando Fuganti
+E: fuganti@conectiva.com.br
+E: fuganti@netbank.com.br
+D: random kernel hacker, ZF MachZ Watchdog driver
+S: Conectiva S.A.
+S: R. Tocantins, 89 - Cristo Rei
+S: 80050-430 - Curitiba - Paraná
+S: Brazil
+
 N: Nigel Gamble
 E: nigel@nrg.org
 E: nigel@sgi.com
diff -urN linux-2.4.9-pre1/Documentation/devices.txt linux/Documentation/devices.txt
--- linux-2.4.9-pre1/Documentation/devices.txt	Sat May 19 17:43:05 2001
+++ linux/Documentation/devices.txt	Mon Dec  3 23:01:21 2001
@@ -1,17 +1,19 @@
+
 		       LINUX ALLOCATED DEVICES
 	     Maintained by H. Peter Anvin <device@lanana.org>
 
-		   Last revised: December 29, 2000
+		      Last revised: 3 June 2001
 
 This list is the Linux Device List, the official registry of allocated
 device numbers and /dev directory nodes for the Linux operating
 system.
 
-The latest version of this list is included with the Linux kernel
-sources.  It is also available separately from 
-http://www.kernel.org/pub/linux/docs/device-list/ or
-ftp://ftp.kernel.org/pub/linux/docs/device-list/.  The LaTeX version
-of this document is no longer maintained.
+The latest version of this list is available from
+http://www.lanana.org/docs/device-list/ or
+ftp://ftp.kernel.org/pub/linux/docs/device-list/.  This version may be
+newer than the one distributed with the Linux kernel.
+
+The LaTeX version of this document is no longer maintained.
 
 This document is included by reference into the Filesystem Hierarchy
 Standard (FHS).	 The FHS is available from http://www.pathname.com/fhs/.
@@ -38,6 +40,13 @@
 
 	  **** DEVICE DRIVERS AUTHORS PLEASE READ THIS ****
 
+THE DEVICE REGISTRY IS OFFICIALLY FROZEN FOR LINUS TORVALDS' KERNEL
+TREE.  At Linus' request, no more allocations will be made official
+for Linus' kernel tree; the 3 June 2001 version of this list is the
+official final version of this registry.  At Alan Cox' request,
+however, the registry will continue to be maintained for the -ac
+series of kernels, and registrations will be accepted.
+
 To have a major number allocated, or a minor number in situations
 where that applies (e.g. busmice), please contact me with the
 appropriate device information.	 Also, if you have additional
@@ -391,12 +400,25 @@
 		199 = /dev/scanners/cuecat :CueCat barcode scanner
 		200 = /dev/net/tun	TAP/TUN network device
 		201 = /dev/button/gulpb	Transmeta GULP-B buttons
-		204 = /dev/video/em8300	    EM8300 DVD decoder control
-		205 = /dev/video/em8300_mv  EM8300 DVD decoder video
-		206 = /dev/video/em8300_ma  EM8300 DVD decoder audio
-		207 = /dev/video/em8300_sp  EM8300 DVD decoder subpicture
-		208 = /dev/compaq/cpqphpc Compaq PCI Hot Plug Controller
-		209 = /dev/compaq/cpqrid  Compaq Remote Insight Driver
+		204 = /dev/video/em8300		EM8300 DVD decoder control
+		205 = /dev/video/em8300_mv	EM8300 DVD decoder video
+		206 = /dev/video/em8300_ma	EM8300 DVD decoder audio
+		207 = /dev/video/em8300_sp	EM8300 DVD decoder subpicture
+		208 = /dev/compaq/cpqphpc	Compaq PCI Hot Plug Controller
+		209 = /dev/compaq/cpqrid	Compaq Remote Insight Driver
+		210 = /dev/impi/bt	IMPI coprocessor block transfer	
+		211 = /dev/impi/smic	IMPI coprocessor stream interface
+		212 = /dev/watchdogs/0	First watchdog device
+		213 = /dev/watchdogs/1	Second watchdog device
+		214 = /dev/watchdogs/2	Third watchdog device
+		215 = /dev/watchdogs/3	Fourth watchdog device
+		216 = /dev/fujitsu/apanel	Fujitsu/Siemens application panel
+		217 = /dev/ni/natmotn		National Instruments Motion
+		218 = /dev/kchuid	Inter-process chuid control
+		219 = /dev/modems/mwave	MWave modem firmware upload
+		220 = /dev/mptctl	Message passing technology (MPT) control
+		221 = /dev/mvista/hssdsi	Montavista PICMG hot swap system driver
+		222 = /dev/mvista/hasi		Montavista PICMG high availability
 		240-255			Reserved for local use
 
  11 char	Raw keyboard device
@@ -430,14 +452,19 @@
 		  1 = /dev/dos_cd1	Second MSCDEX CD-ROM
 		    ...
 
- 13 char	PC speaker (OBSOLETE)
-		  0 = /dev/pcmixer	Emulates /dev/mixer
-		  1 = /dev/pcsp		Emulates /dev/dsp (8-bit)
-		  4 = /dev/pcaudio	Emulates /dev/audio
-		  5 = /dev/pcsp16	Emulates /dev/dsp (16-bit)
+ 13 char	Input core
+		  0 = /dev/input/js0	First joystick
+		  1 = /dev/input/js1	Second joystick
+		    ...
+		 32 = /dev/input/mouse0	First mouse
+		 33 = /dev/input/mouse1	Second mouse
+		    ...
+		 63 = /dev/input/mice	Unified mouse
+		 64 = /dev/input/event0	First event queue
+		 65 = /dev/input/event1	Second event queue
+		    ...
 
-		The current PC speaker driver uses the Open Sound
-		System interface, and these devices are obsolete.
+		Each device type has 5 bits (32 minors).
 
     block	8-bit MFM/RLL/IDE controller
 		  0 = /dev/xda		First XT disk whole disk
@@ -664,13 +691,12 @@
 		    ...
 		 31 = /dev/fb31		32nd frame buffer
 
-		Backward compatibility aliases {2.6}
-
-		 32 = /dev/fb1		Second frame buffer
+		For backwards compatibility {2.6} the following
+		progression is also handled by current kernels:
+		  0 = /dev/fb0
+		 32 = /dev/fb1
 		    ...
-		224 = /dev/fb7		Eighth frame buffer
-
-		All additional minor numbers are reserved.
+		224 = /dev/fb7
 
     block	Aztech/Orchid/Okano/Wearnes CD-ROM
 		  0 = /dev/aztcd	Aztech CD-ROM
@@ -945,7 +971,7 @@
 		  0 = /dev/rd/c0d0	First disk, whole disk
 		  8 = /dev/rd/c0d1	Second disk, whole disk
 		    ...
-		248 = /dev/rd/c0d15	16th disk, whole disk
+		248 = /dev/rd/c0d15	32nd disk, whole disk
 
 		For partitions add:
 		  0 = /dev/rd/c?d?	Whole disk
@@ -961,7 +987,7 @@
 		  0 = /dev/rd/c1d0	First disk, whole disk
 		  8 = /dev/rd/c1d1	Second disk, whole disk
 		    ...
-		248 = /dev/rd/c1d15	16th disk, whole disk
+		248 = /dev/rd/c1d31	32nd disk, whole disk
 
 		Partitions are handled as for major 48.
 
@@ -971,7 +997,7 @@
 		  0 = /dev/rd/c2d0	First disk, whole disk
 		  8 = /dev/rd/c2d1	Second disk, whole disk
 		    ...
-		248 = /dev/rd/c2d15	16th disk, whole disk
+		248 = /dev/rd/c2d31	32nd disk, whole disk
 
  51 char	Baycom radio modem
 		  0 = /dev/bc0		First Baycom radio modem
@@ -981,7 +1007,7 @@
 		  0 = /dev/rd/c3d0	First disk, whole disk
 		  8 = /dev/rd/c3d1	Second disk, whole disk
 		    ...
-		248 = /dev/rd/c3d15	16th disk, whole disk
+		248 = /dev/rd/c3d31	32nd disk, whole disk
 
 		Partitions are handled as for major 48.
 
@@ -994,7 +1020,7 @@
 		  0 = /dev/rd/c4d0	First disk, whole disk
 		  8 = /dev/rd/c4d1	Second disk, whole disk
 		    ...
-		248 = /dev/rd/c4d15	16th disk, whole disk
+		248 = /dev/rd/c4d31	32nd disk, whole disk
 
 		Partitions are handled as for major 48.
 
@@ -1016,7 +1042,7 @@
 		  0 = /dev/rd/c5d0	First disk, whole disk
 		  8 = /dev/rd/c5d1	Second disk, whole disk
 		    ...
-		248 = /dev/rd/c5d15	16th disk, whole disk
+		248 = /dev/rd/c5d31	32nd disk, whole disk
 
 		Partitions are handled as for major 48.
 
@@ -1033,7 +1059,7 @@
 		  0 = /dev/rd/c6d0	First disk, whole disk
 		  8 = /dev/rd/c6d1	Second disk, whole disk
 		    ...
-		248 = /dev/rd/c6d15	16th disk, whole disk
+		248 = /dev/rd/c6d31	32nd disk, whole disk
 
 		Partitions are handled as for major 48.
 
@@ -1043,7 +1069,7 @@
 		  0 = /dev/rd/c7d0	First disk, whole disk
 		  8 = /dev/rd/c7d1	Second disk, whole disk
 		    ...
-		248 = /dev/rd/c7d15	16th disk, whole disk
+		248 = /dev/rd/c7d31	32nd disk, whole disk
 
 		Partitions are handled as for major 48.
 
@@ -1541,7 +1567,6 @@
 		Partitions are handled the same way as for the first
 		interface (see major number 3).
 
-
  89 char	I2C bus interface
 		  0 = /dev/i2c-0	First I2C adapter
 		  1 = /dev/i2c-1	Second I2C adapter
@@ -1610,23 +1635,29 @@
 		  1 = /dev/dcxx1	Second capture card
 		    ...
 
+    block	IBM S/390 DASD block storage
+		  0 = /dev/dasda	First DASD device, major
+		  1 = /dev/dasda1	First DASD device, block 1
+		  2 = /dev/dasda2	First DASD device, block 2
+		  3 = /dev/dasda3	First DASD device, block 3
+		  4 = /dev/dasdb	Second DASD device, major
+		  5 = /dev/dasdb1	Second DASD device, block 1
+		  6 = /dev/dasdb2	Second DASD device, block 2
+		  7 = /dev/dasdb3	Second DASD device, block 3
+		    ...
+
  95 char	IP filter
 		  0 = /dev/ipl		Filter control device/log file
 		  1 = /dev/ipnat	NAT control device/log file
 		  2 = /dev/ipstate	State information log file
 		  3 = /dev/ipauth	Authentication control device/log file
-
-    block	IBM S/390 DASD block storage
-		  0 = /dev/dasd0	First DASD device, major
-		  1 = /dev/dasd0a	First DASD device, block 1
-		  2 = /dev/dasd0b	First DASD device, block 2
-		  3 = /dev/dasd0c	First DASD device, block 3
-		  4 = /dev/dasd1	Second DASD device, major
-		  5 = /dev/dasd1a	Second DASD device, block 1
-		  6 = /dev/dasd1b	Second DASD device, block 2
-		  7 = /dev/dasd1c	Second DASD device, block 3
 		    ...		
 
+    block	IBM S/390 VM/ESA minidisk
+		  0 = /dev/mnda		First VM/ESA minidisk
+		  1 = /dev/mndb		Second VM/ESA minidisk
+		    ...
+
  96 char	Parallel port ATAPI tape devices
 		  0 = /dev/pt0		First parallel port ATAPI tape
 		  1 = /dev/pt1		Second parallel port ATAPI tape
@@ -1635,11 +1666,6 @@
 		129 = /dev/npt1		Second p.p. ATAPI tape, no rewind
 		    ...
 
-    block	IBM S/390 VM/ESA minidisk
-		  0 = /dev/msd0		First VM/ESA minidisk
-		  1 = /dev/msd1		Second VM/ESA minidisk
-		    ...
-
  97 char	Parallel port generic ATAPI interface
 		  0 = /dev/pg0		First parallel port ATAPI device
 		  1 = /dev/pg1		Second parallel port ATAPI device
@@ -1706,6 +1732,16 @@
 		  2 = /dev/tlk2		Third Teletext decoder
 		  3 = /dev/tlk3		Fourth Teletext decoder
 
+    block	Compressed block device
+		  0 = /dev/cbd/a	First compressed block device, whole device
+		 16 = /dev/cbd/b	Second compressed block device, whole device
+		    ...
+		240 = /dev/cbd/p	16th compressed block device, whole device
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
 103 char	Arla network file system
 		  0 = /dev/xfs0		Arla XFS
 
@@ -1837,11 +1873,30 @@
 		There is currently a device-naming conflict between
 		these and PAM multimodems (major 78).
 
+    block	IBM iSeries virtual disk
+		  0 = /dev/iseries/vda	First virtual disk, whole disk
+		  8 = /dev/iseries/vdb	Second virtual disk, whole disk
+		    ...
+		200 = /dev/iseries/vdz	26th virtual disk, whole disk
+		208 = /dev/iseries/vdaa	27th virtual disk, whole disk
+		    ...
+		240 = /dev/iseries/vdaf	32nd virtual disk, whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 7.
+
 113 char	ISI serial card - alternate devices
 		  0 = /dev/cum0		Callout device for ttyM0
 		  1 = /dev/cum1		Callout device for ttyM1
 		    ...
 
+    block	IBM iSeries virtual CD-ROM
+
+		  0 = /dev/iseries/vcda	First virtual CD-ROM
+		  1 = /dev/iseries/vcdb	Second virtual CD-ROM
+		    ...
+
 114 char	Picture Elements ISE board
 		  0 = /dev/ise0		First ISE board
 		  1 = /dev/ise1		Second ISE board
@@ -2005,9 +2060,9 @@
 		    ...
 
 162 char	Raw block device interface
-		  0 = /dev/raw		Raw I/O control device
-		  1 = /dev/raw1		First raw I/O device
-		  2 = /dev/raw2		Second raw I/O device
+		  0 = /dev/rawctl	Raw I/O control device
+		  1 = /dev/raw/raw1	First raw I/O device
+		  2 = /dev/raw/raw2	Second raw I/O device
 		    ...
 
 163 char	Radio Tech BIM-XXX-RS232 radio modem
@@ -2219,7 +2274,22 @@
 		    ...
 		255 = /dev/nvidiactl		Nvidia card control device
 
-196-197		UNASSIGNED
+196 char	Tormenta T1 card
+		  0 = /dev/tor/0		Master control channel for all cards
+		  1 = /dev/tor/1		First DS0
+		  2 = /dev/tor/2		Second DS0
+		    ...
+		 48 = /dev/tor/48		48th DS0
+		 49 = /dev/tor/49		First pseudo-channel
+		 50 = /dev/tor/50		Second pseudo-channel
+		    ...
+
+197 char	OpenTNF tracing facility
+		  0 = /dev/tnf/t0		Trace 0 data extraction
+		  1 = /dev/tnf/t1		Trace 1 data extraction
+		    ...
+		128 = /dev/tnf/status		Tracing facility status
+		130 = /dev/tnf/trace		Tracing device
 
 198 char	Total Impact TPMP2 quad coprocessor PCI card
 		  0 = /dev/tpmp2/0		First card
@@ -2288,6 +2358,9 @@
 		 16 = /dev/ttyAM0		ARM "AMBA" serial port 0
 		    ...
 		 31 = /dev/ttyAM15		ARM "AMBA" serial port 15
+		 32 = /dev/ttyDB0		DataBooster serial port 0
+		    ...
+		 39 = /dev/ttyDB7		DataBooster serial port 7
 
 205 char	Low-density serial ports (alternate device)
 		  0 = /dev/culu0		Callout device for ttyLU0
@@ -2309,6 +2382,9 @@
 		 16 = /dev/cuam0		Callout device for ttyAM0
 		    ...
 		 31 = /dev/cuam15		Callout device for ttyAM15
+		 32 = /dev/cudb0		Callout device for ttyDB0
+		    ...
+		 39 = /dev/cudb7		Callout device for ttyDB7
 
 206 char	OnStream SC-x0 tape devices
 		  0 = /dev/osst0		First OnStream SCSI tape, mode 0
@@ -2450,7 +2526,59 @@
 		  1 = /dev/cuy1			Callout device for ttyY1
 		    ...
 
-226-239		UNASSIGNED
+226 char	Direct Rendering Infrastructure (DRI)
+		  0 = /dev/dri/card0		First graphics card
+		  1 = /dev/dri/card1		Second graphics card
+		    ...
+
+227 char	IBM 3270 terminal block-mode access
+		  0 = /dev/3270/tub		Controlling interface
+		  1 = /dev/3270/tub1		First 3270 terminal
+		  2 = /dev/3270/tub2		Second 3270 terminal
+		    ...
+
+228 char	IBM 3270 terminal Unix tty access
+		  1 = /dev/3270/tty1		First 3270 terminal
+		  2 = /dev/3270/tty2		Seconds 3270 terminal
+		    ...
+
+229 char	IBM iSeries virtual console
+		  0 = /dev/iseries/vtty0	First console port
+		  1 = /dev/iseries/vtty1	Second console port
+		    ...
+
+230 char	IBM iSeries virtual tape
+		  0 = /dev/iseries/vt0		First virtual tape, mode 0
+		  1 = /dev/iseries/vt1		Second virtual tape, mode 0
+		    ...
+		 32 = /dev/iseries/vt0l		First virtual tape, mode 1
+		 33 = /dev/iseries/vt1l		Second virtual tape, mode 1
+		    ...
+		 64 = /dev/iseries/vt0m		First virtual tape, mode 2
+		 65 = /dev/iseries/vt1m		Second virtual tape, mode 2
+		    ...
+		 96 = /dev/iseries/vt0a		First virtual tape, mode 3
+		 97 = /dev/iseries/vt1a		Second virtual tape, mode 3
+		      ...
+		128 = /dev/iseries/nvt0		First virtual tape, mode 0, no rewind
+		129 = /dev/iseries/nvt1		Second virtual tape, mode 0, no rewind
+		    ...
+		160 = /dev/iseries/nvt0l	First virtual tape, mode 1, no rewind
+		161 = /dev/iseries/nvt1l	Second virtual tape, mode 1, no rewind
+		    ...
+		192 = /dev/iseries/nvt0m	First virtual tape, mode 2, no rewind
+		193 = /dev/iseries/nvt1m	Second virtual tape, mode 2, no rewind
+		    ...
+		224 = /dev/iseries/nvt0a	First virtual tape, mode 3, no rewind
+		225 = /dev/iseries/nvt1a	Second virtual tape, mode 3, no rewind
+		    ...
+
+		"No rewind" refers to the omission of the default
+		automatic rewind on device close.  The MTREW or MTOFFL
+		ioctl()'s can be used to rewind the tape regardless of
+		the device used to access it.
+
+231-239		UNASSIGNED
 
 240-254		LOCAL/EXPERIMENTAL USE
 
@@ -2647,3 +2775,4 @@
 in our notation).  This removes the problem of exhausting the
 namespace and enables the kernel to automatically create the device
 nodes for the slaves on demand using the "devpts" filesystem.
+
diff -urN linux-2.4.9-pre1/Documentation/parisc/mm linux/Documentation/parisc/mm
--- linux-2.4.9-pre1/Documentation/parisc/mm	Tue Dec  5 12:29:38 2000
+++ linux/Documentation/parisc/mm	Wed Dec 31 16:00:00 1969
@@ -1,31 +0,0 @@
-
-The current state of Linux/PA-RISC mm is BROKEN.
-
-Someone needs to sit down and thoroughly rewrite all the cache flushing
-macro definitions.  Here are some of the problems, followed by what I
-think needs to be done about them.
-
-(1) We're using fdce / fice everywhere.  This has to stop (except in
-the routines which flush the entire cache).  The right instructions to
-be using are fdc/fic.
-
-(2) fdc/fic will throw exceptions if the address they reference isn't
-mapped.  Therefore we need to check the page is mapped before flushing
-(we're guaranteed not to have the page dirty if we don't have a software
-mapping for it any longer, right?)
-
-(3) the flush macros are right now tunnelled down to one routine to flush
-the data cache and one routine to flush the insn cache.  this is wrong.
-we should take hints from how we're called and optimise our routines
-accordingly.
-
-(4) fdc/fic actually take space register arguments.  fic takes an 3-bit sr
-argument and fdc takes a 2-bit sr argument.  right now, there's a lot of
-pissing about with %sr1 and all the macros use %sr1.  This is crazy.  We
-normally _know_ what's being referred to, and it's the current task.  So
-if we want to flush that, just use %sr3.  If it happens to be kernel,
-use %sr0 for fdc and %sr4 for fic.
-
-(5) we need to write flush_kernel_dcache_range and use it on kernel
-addresses.  all the macros are defined to work on the _current task's_
-virtual address space.
diff -urN linux-2.4.9-pre1/Documentation/usb/philips.txt linux/Documentation/usb/philips.txt
--- linux-2.4.9-pre1/Documentation/usb/philips.txt	Wed Jul  4 11:50:38 2001
+++ linux/Documentation/usb/philips.txt	Mon Dec  3 23:01:21 2001
@@ -1,5 +1,5 @@
 This file contains some additional information for the Philips webcams.
-E-mail: webcam@smcc.demon.nl                        Last updated: 2001-04-25
+E-mail: webcam@smcc.demon.nl                        Last updated: 2001-07-27
 
 The main webpage for the Philips driver is http://www.smcc.demon.nl/webcam/.
 It contains a lot of extra information, a FAQ, and the binary plugin
@@ -29,10 +29,9 @@
 
 palette
    Specifies the desired colour order that should be delivered by read() and
-   mmap(). The string can be one of bgr24, rgb24, rgb32, bgr32, yuyv,
-   yuv420, yuv420p. If the tool you use produces odd colours (more
-   specificly, red and blue are swapped), try palette=bgr24 or
-   palette=rgb24.
+   mmap(). The string can be one of yuv420 or yuv420p; however, yuv420 will
+   be phased out, leaving only yuv420p, so this option will disappear
+   entirely.
 
    Only the native yuv420/yuv420p format is supported by the in kernel driver. 
    If you want to use other formats with in-kernel conversion download the
@@ -73,7 +72,7 @@
 
 compression (only useful with the plugin)
    With this option you can control the compression factor that the camera
-   use to squeeze the image through the USB bus. You can set the 
+   uses to squeeze the image through the USB bus. You can set the 
    parameter between 0 and 3:
      0 = prefer uncompressed images; if the requested mode is not available
          in an uncompressed format, the driver will silently switch to low
@@ -83,7 +82,7 @@
      3 = high compression.
       
    High compression takes less bandwidth of course, but it could also
-   introduce some unwanted artefacts. The default is 2, medium compression. 
+   introduce some unwanted artefacts. The default is 2, medium compression.
    See the FAQ on the website for an overview of which modes require
    compression.
       
@@ -91,7 +90,6 @@
    The 645 and 646 have fixed compression parameters.      
 
 trace
-
    In order to better detect problems, it is now possible to turn on a
    'trace' of some of the calls the module makes; it logs all items in your
    kernel log at debug level.
diff -urN linux-2.4.9-pre1/MAINTAINERS linux/MAINTAINERS
--- linux-2.4.9-pre1/MAINTAINERS	Mon Dec  3 23:01:02 2001
+++ linux/MAINTAINERS	Mon Dec  3 23:01:21 2001
@@ -227,6 +227,12 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+BLUETOOTH SUBSYSTEM (BlueZ)
+P:	Maxim Krasnyansky
+M:	maxk@qualcomm.com
+W:	http://bluez.sf.net
+S:	Maintained
+
 BTTV VIDEO4LINUX DRIVER
 P:	Gerd Knorr
 M:	kraxel@goldbach.in-berlin.de
@@ -500,6 +506,13 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+FARSYNC SYNCHRONOUS DRIVER
+P:	Bob Dunlop
+M:	rjd@xyzzy.clara.co.uk
+M:	bob.dunlop@farsite.co.uk
+W:	http://www.farsite.co.uk/
+S:	Supported
+
 FILE LOCKING (flock() and fcntl()/lockf())
 P:	Matthew Wilcox
 M:	matthew@wil.cx
@@ -637,7 +650,7 @@
 IDE DRIVER [GENERAL]
 P:	Andre Hedrick
 M:	andre@linux-ide.org
-M:	ahedrick@atipa.com
+M:	andre@aslab.com
 M:	andre@suse.com
 L:	linux-kernel@vger.kernel.org
 W:	http://www.kernel.org/pub/linux/kernel/people/hedrick/
@@ -693,6 +706,12 @@
 L:	linux1394-devel@lists.sourceforge.net
 S:	Maintained
 
+IMS TWINTURBO FRAMEBUFFER DRIVER
+P:	Paul Mundt
+M:	lethal@chaoticdreams.org
+L:	linux-fbdev-devel@lists.sourceforge.net
+S:	Maintained
+
 INTEL APIC/IOAPIC, LOWLEVEL X86 SMP SUPPORT
 P:	Ingo Molnar
 M:	mingo@redhat.com
@@ -1601,17 +1620,18 @@
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 
+ZF MACHZ WATCHDOG
+P:	Fernando Fuganti
+M:	fuganti@conectiva.com.br
+M:	fuganti@netbank.com.br
+W:	http://cvs.conectiva.com.br/drivers/ZFL-watchdog/
+S:	Maintained
+
 ZR36120 VIDEO FOR LINUX DRIVER
 P:	Pauline Middelink
 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 -urN linux-2.4.9-pre1/Makefile linux/Makefile
--- linux-2.4.9-pre1/Makefile	Mon Dec  3 23:01:02 2001
+++ linux/Makefile	Mon Dec  3 23:01:21 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 9
-EXTRAVERSION =-pre1
+EXTRAVERSION =-pre2
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.9-pre1/arch/arm/config.in linux/arch/arm/config.in
--- linux-2.4.9-pre1/arch/arm/config.in	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/config.in	Mon Dec  3 23:01:21 2001
@@ -483,8 +483,8 @@
         "$CONFIG_ARCH_INTEGRATOR" = "y" -o \
         "$CONFIG_ARCH_TBOX" = "y" -o       \
         "$CONFIG_ARCH_CLPS7500" = "y" -o   \
-	"$CONFIG_ARCH_P720T" = "y" -o      \
-	"$CONFIG_ARCH_ANAKIN" = "y" ]; then
+        "$CONFIG_ARCH_P720T" = "y" -o      \
+        "$CONFIG_ARCH_ANAKIN" = "y" ]; then
       define_bool CONFIG_PC_KEYMAP y
    fi
    if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then
diff -urN linux-2.4.9-pre1/arch/arm/def-configs/pleb linux/arch/arm/def-configs/pleb
--- linux-2.4.9-pre1/arch/arm/def-configs/pleb	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/def-configs/pleb	Mon Dec  3 23:01:21 2001
@@ -0,0 +1,535 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_RPC is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_ANAKIN is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_BITSY is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+CONFIG_SA1100_PLEB=y
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_USB_NETLINK is not set
+# CONFIG_SA1100_USB_CHAR is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_32v3 is not set
+CONFIG_CPU_32v4=y
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_SA110 is not set
+CONFIG_CPU_SA1100=y
+CONFIG_DISCONTIGMEM=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+# CONFIG_ISA_DMA is not set
+CONFIG_CPU_FREQ=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="console=ttySA0,9600"
+# CONFIG_PFS168_CMDLINE is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# 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_ARM_INTEGRATOR 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
+# 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
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+CONFIG_INET_ECN=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+CONFIG_SERIAL_SA1100=y
+# CONFIG_SERIAL_SA1100_OLD is not set
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SA1100_DEFAULT_BAUDRATE=9600
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X is not set
+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_UCB1200 is not set
+# CONFIG_TOUCHSCREEN_UCB1200 is not set
+# CONFIG_AUDIO_UCB1200 is not set
+# CONFIG_ADC_UCB1200 is not set
+# CONFIG_TOUCHSCREEN_BITSY is not set
+CONFIG_PROFILER=y
+# CONFIG_PFS168_SPI is not set
+# CONFIG_PFS168_DTMF is not set
+# CONFIG_PFS168_MISC is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_SA1100_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_TMPFS=y
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFS_V3 is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_NO_PGT_CACHE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
diff -urN linux-2.4.9-pre1/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S
--- linux-2.4.9-pre1/arch/arm/kernel/head-armv.S	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/kernel/head-armv.S	Mon Dec  3 23:01:21 2001
@@ -248,12 +248,12 @@
 		/*
 		 * Ensure that the first section of RAM is present.
 		 * we assume that:
-		 *  1. the RAM is aligned to a 128MB boundary
-		 *  2. the kernel is executing in the same 128MB chunk
+		 *  1. the RAM is aligned to a 32MB boundary
+		 *  2. the kernel is executing in the same 32MB chunk
 		 *     as the start of RAM.
 		 */
-		bic	r0, r0, #0x07f00000 >> 18	@ round down
-		and	r2, r5, #0xf8000000		@ round down
+		bic	r0, r0, #0x01f00000 >> 18	@ round down
+		and	r2, r5, #0xfe000000		@ round down
 		add	r3, r8, r2			@ flags + rambase
 		str	r3, [r0]
 
diff -urN linux-2.4.9-pre1/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c
--- linux-2.4.9-pre1/arch/arm/kernel/process.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/kernel/process.c	Mon Dec  3 23:01:21 2001
@@ -124,7 +124,7 @@
 		pm_power_off();
 }
 
-void machine_restart(char * __unused)
+void machine_restart(void * __unused)
 {
 	/*
 	 * Clean and disable cache, and turn off interrupts
diff -urN linux-2.4.9-pre1/arch/arm/mach-anakin/arch.c linux/arch/arm/mach-anakin/arch.c
--- linux-2.4.9-pre1/arch/arm/mach-anakin/arch.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-anakin/arch.c	Mon Dec  3 23:01:21 2001
@@ -28,7 +28,7 @@
 
 static void __init
 fixup_anakin(struct machine_desc *desc, struct param_struct *unused,
-	     char **cmdline, struct meminfo *mi)
+             char **cmdline, struct meminfo *mi)
 {
 	ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
 	setup_ramdisk(1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE);
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/assabet.c linux/arch/arm/mach-sa1100/assabet.c
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/assabet.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/assabet.c	Mon Dec  3 23:01:21 2001
@@ -39,7 +39,7 @@
 
 static int __init assabet_init(void)
 {
-	if (machine_has_neponset()) {
+	if (machine_is_assabet() && machine_has_neponset()) {
 		/*
 		 * Angel sets this, but other bootloaders may not.
 		 *
@@ -167,6 +167,8 @@
   { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
   { 0xf1000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */
   { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */
+  /*  f3000000 - neponset system registers */
+  /*  f4000000 - neponset SA1111 registers */
   LAST_DESC
 };
 
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/bitsy.c linux/arch/arm/mach-sa1100/bitsy.c
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/bitsy.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/bitsy.c	Mon Dec  3 23:01:21 2001
@@ -51,9 +51,9 @@
 {
 	if (port->mapbase == _Ser3UTCR0) {
 		if (mctrl & TIOCM_RTS)
-			GPSR = GPIO_BITSY_COM_RTS;
-		else
 			GPCR = GPIO_BITSY_COM_RTS;
+		else
+			GPSR = GPIO_BITSY_COM_RTS;
 	}
 }
 
@@ -63,9 +63,9 @@
 
 	if (port->mapbase == _Ser3UTCR0) {
 		int gplr = GPLR;
-		if (!(gplr & GPIO_BITSY_COM_DCD))
+		if (gplr & GPIO_BITSY_COM_DCD)
 			ret &= ~TIOCM_CD;
-		if (!(gplr & GPIO_BITSY_COM_CTS))
+		if (gplr & GPIO_BITSY_COM_CTS)
 			ret &= ~TIOCM_CTS;
 	}
 
@@ -150,7 +150,7 @@
 static struct map_desc bitsy_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
   { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf0000000, 0x49000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* EGPIO 0 */
+  { 0xf0000000, 0x49000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0 */
   { 0xf1000000, 0x10000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 2 */
   { 0xf3000000, 0x40000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 4 */
   LAST_DESC
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/cpu-sa1110.c linux/arch/arm/mach-sa1100/cpu-sa1110.c
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/cpu-sa1110.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/cpu-sa1110.c	Mon Dec  3 23:01:21 2001
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2001 Russell King
  *
- *  $Id: cpu-sa1110.c,v 1.2 2001/07/24 20:25:25 rmk Exp $
+ *  $Id: cpu-sa1110.c,v 1.3 2001/08/12 15:41:53 rmk 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
@@ -48,7 +48,7 @@
 	u_short refresh;	/* refresh time for array (us)	 */
 };
 
-static struct sdram_params tc59sm716_cl2_params = {
+static struct sdram_params tc59sm716_cl2_params __initdata = {
 	rows:		    12,
 	tck:		    10,
 	trcd:		    20,
@@ -58,7 +58,7 @@
 	cas_latency:	     2,
 };
 
-static struct sdram_params tc59sm716_cl3_params = {
+static struct sdram_params tc59sm716_cl3_params __initdata = {
 	rows:		    12,
 	tck:		     8,
 	trcd:		    20,
@@ -68,6 +68,8 @@
 	cas_latency:	     3,
 };
 
+static struct sdram_params sdram_params;
+
 /*
  * Given a period in ns and frequency in khz, calculate the number of
  * cycles of frequency in period.  Note that we round up to the next
@@ -205,7 +207,14 @@
 sdram_notifier(struct notifier_block *nb, unsigned long val, void *data)
 {
 	struct cpufreq_info *ci = data;
-	struct sdram_params *sdram = &tc59sm716_cl3_params;
+	struct sdram_params *sdram = &sdram_params;
+
+	/* were we initialised? */
+	if (sdram->cas_latency == 0) {
+		struct cpufreq_minmax *m = data;
+		m->min_freq = m->max_freq = m->cur_freq;
+		return 0;
+	}
 
 	switch (val) {
 	case CPUFREQ_MINMAX:
@@ -247,11 +256,24 @@
 
 static int __init sa1110_sdram_init(void)
 {
-	struct sdram_params *sdram = &tc59sm716_cl3_params;
+	struct sdram_params *sdram = NULL;
 	unsigned int cur_freq = cpufreq_get(smp_processor_id());
+	int ret = -ENODEV;
+
+	if (machine_is_assabet())
+		sdram = &tc59sm716_cl3_params;
 
-	sdram_update_timing(cur_freq, sdram);
-	sdram_update_refresh(cur_freq, sdram);
+	if (sdram) {
+		printk(KERN_DEBUG "SDRAM: tck: %d trcd: %d trp: %d"
+			" twr: %d refresh: %d cas_latency: %d",
+			sdram->tck, sdram->trcd, sdram->trp,
+			sdram->twr, sdram->refresh, sdram->cas_latency);
+
+		memcpy(&sdram_params, sdram, sizeof(sdram_params));
+
+		sdram_update_timing(cur_freq, &sdram_params);
+		sdram_update_refresh(cur_freq, &sdram_params);
+	}
 
 	return cpufreq_register_notifier(&sa1110_clkchg_block);
 }
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/dma-sa1100.c linux/arch/arm/mach-sa1100/dma-sa1100.c
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/dma-sa1100.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/dma-sa1100.c	Mon Dec  3 23:01:21 2001
@@ -115,7 +115,7 @@
 	for (;;) {
 		buf = dma->tail;
 
-		if (!buf) {
+		if (!buf || dma->stopped) {
 			/* no more data available */
 			DPRINTK("process: no more buf (dma %s)\n",
 				dma->curr ? "active" : "inactive");
@@ -388,11 +388,16 @@
 			*addr = buf->dma_ptr;
 		DPRINTK("curr_pos: b=%#x a=%#x\n", (int)dma->curr->id, *addr);
 		ret = 0;
+	} else if (dma->tail && dma->stopped) {
+		dma_buf_t *buf = dma->tail;
+		if (buf_id)
+			*buf_id = buf->id;
+		*addr = buf->dma_ptr;
+		ret = 0;
 	} else {
 		if (buf_id)
 			*buf_id = NULL;
 		*addr = 0;
-		DPRINTK("curr_pos: spinning\n");
 		ret = -ENXIO;
 	}
 	local_irq_restore(flags);
@@ -403,11 +408,36 @@
 int sa1100_dma_stop(dmach_t channel)
 {
 	sa1100_dma_t *dma = &dma_chan[channel];
+	int flags;
 
 	if (channel_is_sa1111_sac(channel))
 		return sa1111_dma_stop(channel);
 
+	if (dma->stopped)
+		return 0;
+	local_irq_save(flags);
+	dma->stopped = 1;
+	/*
+	 * Stop DMA and tweak state variables so everything could restart
+	 * from there when resume/wakeup occurs.
+	 */
 	dma->regs->ClrDCSR = DCSR_RUN | DCSR_IE;
+	if (dma->curr) {
+		dma_buf_t *buf = dma->curr;
+		if (dma->spin_ref <= 0) {
+			dma_addr_t curpos;
+			sa1100_dma_get_current(channel, NULL, &curpos);
+			buf->size += buf->dma_ptr - curpos;
+			buf->dma_ptr = curpos;
+		}
+		buf->ref = 0;
+		dma->tail = buf;
+		dma->curr = NULL;
+	}
+	dma->spin_ref = 0;
+	dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB;
+	process_dma(dma);
+	local_irq_restore(flags);
 	return 0;
 }
 
@@ -422,7 +452,15 @@
 	if (channel_is_sa1111_sac(channel))
 		return sa1111_dma_resume(channel);
 
-	dma->regs->SetDCSR = DCSR_RUN | DCSR_IE;
+	if (dma->stopped) {
+		int flags;
+		save_flags_cli(flags);
+		dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB|DCSR_RUN|DCSR_IE;
+		dma->stopped = 0;
+		dma->spin_ref = 0;
+		process_dma(dma);
+		restore_flags(flags);
+	}
 	return 0;
 }
 
@@ -445,9 +483,9 @@
 	if (!buf)
 		buf = dma->tail;
 	dma->head = dma->tail = dma->curr = NULL;
+	dma->stopped = 0;
 	dma->spin_ref = 0;
-	if (dma->spin_size)
-		process_dma(dma);
+	process_dma(dma);
 	local_irq_restore(flags);
 	while (buf) {
 		next_buf = buf->next;
@@ -502,7 +540,8 @@
 
 int sa1100_dma_sleep(dmach_t channel)
 {
-	sa1100_dma_t *dma = &dma_chan[channel];
+        sa1100_dma_t *dma = &dma_chan[channel];
+	int orig_state;
 
 	if ((unsigned)channel >= MAX_SA1100_DMA_CHANNELS || !dma->in_use)
 		return -EINVAL;
@@ -515,28 +554,17 @@
 		return 0;
 	}
 
-	/*
-	 * Stop DMA and tweak state variables so everything could restart
-	 * from there when wakeup occurs.
-	 */
-	dma->regs->ClrDCSR = DCSR_RUN | DCSR_IE;
-	if (dma->curr) {
-		dma_buf_t *buf = dma->curr;
-		dma_addr_t curpos;
-		sa1100_dma_get_current(channel, NULL, &curpos);
-		buf->size += buf->dma_ptr - curpos;
-		buf->dma_ptr = curpos;
-		buf->ref = 0;
-		dma->tail = buf;
-		dma->curr = NULL;
-	}
+	orig_state = dma->stopped;
+	sa1100_dma_stop(channel);
+	dma->regs->ClrDCSR = DCSR_RUN | DCSR_IE | DCSR_STRTA | DCSR_STRTB;
+	dma->stopped = orig_state;
 	dma->spin_ref = 0;
 	return 0;
 }
 
 int sa1100_dma_wakeup(dmach_t channel)
 {
-	sa1100_dma_t *dma = &dma_chan[channel];
+        sa1100_dma_t *dma = &dma_chan[channel];
 	dma_regs_t *regs;
 	int flags;
 
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/dma-sa1111.c linux/arch/arm/mach-sa1100/dma-sa1111.c
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/dma-sa1111.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/dma-sa1111.c	Mon Dec  3 23:01:21 2001
@@ -236,7 +236,6 @@
 	dma->device_id = device_id;
 	dma->callback = NULL;
 	dma->spin_size = 0;
-	dma->ready = 1;
 
 	return 0;
 }
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/dma.h linux/arch/arm/mach-sa1100/dma.h
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/dma.h	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/dma.h	Mon Dec  3 23:01:21 2001
@@ -34,7 +34,7 @@
 	dma_buf_t *head;	/* where to insert buffers */
 	dma_buf_t *tail;	/* where to remove buffers */
 	dma_buf_t *curr;	/* buffer currently DMA'ed */
-	int ready;		/* 1 if DMA can occur */
+	int stopped;		/* 1 if DMA is stalled */
 	dma_regs_t *regs;	/* points to appropriate DMA registers */
 	int irq;		/* IRQ used by the channel */
 	dma_callback_t callback; /* ... to call when buffers are done */
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/generic.c linux/arch/arm/mach-sa1100/generic.c
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/generic.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/generic.c	Mon Dec  3 23:01:21 2001
@@ -160,10 +160,10 @@
  /* virtual     physical    length      domain     r  w  c  b */
   { 0xf6000000, 0x20000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA0 IO */
   { 0xf7000000, 0x30000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA1 IO */
-  { 0xf8000000, 0x80000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */
-  { 0xfa000000, 0x90000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */
-  { 0xfc000000, 0xa0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */
-  { 0xfe000000, 0xb0000000, 0x01f00000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD + DMA */
+  { 0xf8000000, 0x80000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */
+  { 0xfa000000, 0x90000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */
+  { 0xfc000000, 0xa0000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */
+  { 0xfe000000, 0xb0000000, 0x00200000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD + DMA */
   LAST_DESC
 };
 
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/lart.c linux/arch/arm/mach-sa1100/lart.c
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/lart.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/lart.c	Mon Dec  3 23:01:21 2001
@@ -16,31 +16,6 @@
 #include "generic.h"
 
 
-static void __init
-fixup_lart(struct machine_desc *desc, struct param_struct *params,
-	   char **cmdline, struct meminfo *mi)
-{
-	/*
-	 * Note that LART is a special case - it doesn't use physical
-	 * address line A23 on the DRAM, so we effectively have 4 * 8MB
-	 * in two SA1100 banks.
-	 */
-	SET_BANK( 0, 0xc0000000, 8*1024*1024 );
-	SET_BANK( 1, 0xc1000000, 8*1024*1024 );
-	SET_BANK( 2, 0xc8000000, 8*1024*1024 );
-	SET_BANK( 3, 0xc9000000, 8*1024*1024 );
-	SET_BANK( 4, 0xd0000000, 64*1024*1024 );
-	SET_BANK( 5, 0xd8000000, 64*1024*1024 );
-
-	/* make this 5 if you have the 64MB expansion card, or
-	 * 6 if you have two 64MB expansion cards */
-	mi->nr_banks = 4;
-
-	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
-	setup_ramdisk(1, 0, 0, 8192);
-	setup_initrd(0xc0400000, 4*1024*1024);
-}
-
 static struct map_desc lart_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
   { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash memory */
@@ -55,6 +30,7 @@
 
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
+	sa1100_register_uart(2, 2);
 	GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD);
 	GPDR |= GPIO_UART_TXD;
 	GPDR &= ~GPIO_UART_RXD;
@@ -63,7 +39,7 @@
 
 MACHINE_START(LART, "LART")
 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
-	FIXUP(fixup_lart)
+	BOOT_PARAMS(0xc0000100)
 	MAPIO(lart_map_io)
 	INITIRQ(sa1100_init_irq)
 MACHINE_END
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/leds-cerf.c linux/arch/arm/mach-sa1100/leds-cerf.c
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/leds-cerf.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/leds-cerf.c	Mon Dec  3 23:01:21 2001
@@ -27,85 +27,85 @@
 
 void cerf_leds_event(led_event_t evt)
 {
-	unsigned long flags;
+        unsigned long flags;
 
 	local_irq_save(flags);
 
-	switch (evt) {
-	case led_start:
-		hw_led_state = LED_MASK;
-		led_state = LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = LED_MASK;
-		break;
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = LED_MASK;
-		break;
+        switch (evt) {
+        case led_start:
+                hw_led_state = LED_MASK;
+                led_state = LED_STATE_ENABLED;
+                break;
+
+        case led_stop:
+                led_state &= ~LED_STATE_ENABLED;
+                break;
+
+        case led_claim:
+                led_state |= LED_STATE_CLAIMED;
+                hw_led_state = LED_MASK;
+                break;
+        case led_release:
+                led_state &= ~LED_STATE_CLAIMED;
+                hw_led_state = LED_MASK;
+                break;
 
 #ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state ^= LED_D0;
-		break;
+        case led_timer:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state ^= LED_D0;
+                break;
 #endif
 
 #ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~LED_D1;
-		break;
-
-	case led_idle_end:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= LED_D1;
-		break;
+        case led_idle_start:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state &= ~LED_D1;
+                break;
+
+        case led_idle_end:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state |= LED_D1;
+                break;
 #endif
-	case led_green_on:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~LED_D2;
-		break;
-
-	case led_green_off:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= LED_D2;
-		break;
-
-	case led_amber_on:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~LED_D3;
-		break;
-
-	case led_amber_off:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= LED_D3;
-		break;
-
-	case led_red_on:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~LED_D1;
-		break;
-
-	case led_red_off:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= LED_D1;
-		break;
-
-	default:
-		break;
-	}
-
-	if  (led_state & LED_STATE_ENABLED) {
-		GPSR = hw_led_state;
-		GPCR = hw_led_state ^ LED_MASK;
-	}
+        case led_green_on:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state &= ~LED_D2;
+                break;
+
+        case led_green_off:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state |= LED_D2;
+                break;
+
+        case led_amber_on:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state &= ~LED_D3;
+                break;
+
+        case led_amber_off:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state |= LED_D3;
+                break;
+
+        case led_red_on:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state &= ~LED_D1;
+                break;
+
+        case led_red_off:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state |= LED_D1;
+                break;
+
+        default:
+                break;
+        }
+
+        if  (led_state & LED_STATE_ENABLED) {
+                GPSR = hw_led_state;
+                GPCR = hw_led_state ^ LED_MASK;
+        }
 
 	local_irq_restore(flags);
 }
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/leds-lart.c linux/arch/arm/mach-sa1100/leds-lart.c
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/leds-lart.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/leds-lart.c	Mon Dec  3 23:01:21 2001
@@ -66,7 +66,7 @@
 #ifdef CONFIG_LEDS_CPU
 	case led_idle_start:
 		/* The LART people like the LED to be off when the
-		   system is idle... */
+                   system is idle... */
 		if (!(led_state & LED_STATE_CLAIMED))
 			hw_led_state &= ~LED_23;
 		break;
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/leds-simpad.c linux/arch/arm/mach-sa1100/leds-simpad.c
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/leds-simpad.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/leds-simpad.c	Mon Dec  3 23:01:21 2001
@@ -31,7 +31,7 @@
 	switch (evt)
 	{
 	case led_start:
-		hw_led_state = LED_GREEN;
+	        hw_led_state = LED_GREEN;
 		led_state = LED_STATE_ENABLED;
 		break;
 
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/neponset.c linux/arch/arm/mach-sa1100/neponset.c
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/neponset.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/neponset.c	Mon Dec  3 23:01:21 2001
@@ -74,6 +74,10 @@
 
 static int __init neponset_init(void)
 {
+	/* only on assabet */
+	if (!machine_is_assabet())
+		return 0;
+
 	if (machine_has_neponset()) {
 		LEDS = WHOAMI;
 
@@ -108,7 +112,7 @@
 
 static struct map_desc neponset_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */
+  { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */
   { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
   LAST_DESC
 };
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/pleb.c linux/arch/arm/mach-sa1100/pleb.c
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/pleb.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/pleb.c	Mon Dec  3 23:01:21 2001
@@ -15,6 +15,23 @@
 
 #include "generic.h"
 
+static void __init
+fixup_pleb(struct machine_desc *desc, struct param_struct *params,
+           char **cmdline, struct meminfo *mi)
+{
+	SET_BANK(0, 0xc0000000, 16*1024*1024);
+	SET_BANK(1, 0xc8000000, 16*1024*1024);
+	SET_BANK(2, 0xd0000000, 16*1024*1024);
+	SET_BANK(3, 0xd8000000, 16*1024*1024);
+
+	/* make this 4 a second memory card is used to make 64MB */
+	/* make it 1 if a 16MB memory card is used */
+	mi->nr_banks = 2; /* Default 32MB */
+
+	ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+	setup_ramdisk(1, 0, 0, 8192);
+	setup_initrd(0xc0400000, 4*1024*1024);
+}
 
 static struct map_desc pleb_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
@@ -29,10 +46,16 @@
 	iotable_init(pleb_io_desc);
 
 	sa1100_register_uart(0, 3);
+        sa1100_register_uart(1, 1);
+        GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD);
+        GPDR |= GPIO_UART_TXD;
+        GPDR &= ~GPIO_UART_RXD;
+        PPAR |= PPAR_UPR;
 }
 
 MACHINE_START(PLEB, "PLEB")
 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	FIXUP(fixup_pleb)
 	MAPIO(pleb_map_io)
 	INITIRQ(sa1100_init_irq)
 MACHINE_END
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/sa1111-pcibuf.c linux/arch/arm/mach-sa1100/sa1111-pcibuf.c
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/sa1111-pcibuf.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/sa1111-pcibuf.c	Mon Dec  3 23:01:21 2001
@@ -20,6 +20,8 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 
+#include "pcipool.h"
+
 /*
  * simple buffer allocator for copying of unsafe to safe buffers
  * uses __alloc/__free for actual buffers
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/sa1111.c linux/arch/arm/mach-sa1100/sa1111.c
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/sa1111.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/sa1111.c	Mon Dec  3 23:01:21 2001
@@ -300,8 +300,8 @@
 
 	/* take out of reset */
 	/* set power sense and control lines (this from the diags code) */
-	*Reset = ( PwrSensePolLow << 6 )
-	       | ( PwrCtrlPolLow << 7 );
+        *Reset = ( PwrSensePolLow << 6 )
+               | ( PwrCtrlPolLow << 7 );
 
 	*Status = 0;
 
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/sherman.c linux/arch/arm/mach-sa1100/sherman.c
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/sherman.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/sherman.c	Mon Dec  3 23:01:21 2001
@@ -45,8 +45,8 @@
 }
 
 MACHINE_START(SHERMAN, "Blazie Engineering Sherman")
-	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
-	FIXUP(fixup_sherman)
-	MAPIO(sherman_map_io)
+        BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+        FIXUP(fixup_sherman)
+        MAPIO(sherman_map_io)
 	INITIRQ(sa1100_init_irq)
 MACHINE_END
diff -urN linux-2.4.9-pre1/arch/arm/mach-sa1100/simpad.c linux/arch/arm/mach-sa1100/simpad.c
--- linux-2.4.9-pre1/arch/arm/mach-sa1100/simpad.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mach-sa1100/simpad.c	Mon Dec  3 23:01:21 2001
@@ -66,7 +66,7 @@
 	iotable_init(simpad_io_desc);
 
 	sa1100_register_uart(0, 3);
-	sa1100_register_uart(1, 1);
+        sa1100_register_uart(1, 1);
 }
 
 
diff -urN linux-2.4.9-pre1/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c
--- linux-2.4.9-pre1/arch/arm/mm/fault-armv.c	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/mm/fault-armv.c	Mon Dec  3 23:01:21 2001
@@ -631,15 +631,119 @@
 }
 
 /*
- * if PG_dcache_dirty is set for the page, we need to ensure that any
- * cache entries for the kernels virtual memory range are written
- * back to the page.
+ * We take the easy way out of this problem - we make the
+ * PTE uncacheable.  However, we leave the write buffer on.
  */
-void check_pgcache_dirty(struct page *page)
+static void adjust_pte(struct vm_area_struct *vma, unsigned long address)
 {
-	if (VALID_PAGE(page) && page->mapping &&
-	    test_and_clear_bit(PG_dcache_dirty, &page->flags)) {
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte, entry;
+
+	pgd = pgd_offset(vma->vm_mm, address);
+	if (pgd_none(*pgd))
+		return;
+	if (pgd_bad(*pgd))
+		goto bad_pgd;
+
+	pmd = pmd_offset(pgd, address);
+	if (pmd_none(*pmd))
+		return;
+	if (pmd_bad(*pmd))
+		goto bad_pmd;
+
+	pte = pte_offset(pmd, address);
+	entry = *pte;
+
+	/*
+	 * If this page isn't present, or is already setup to
+	 * fault (ie, is old), we can safely ignore any issues.
+	 */
+	if (pte_present(entry) && pte_val(entry) & L_PTE_CACHEABLE) {
+		flush_cache_page(vma, address);
+		pte_val(entry) &= ~L_PTE_CACHEABLE;
+		set_pte(pte, entry);
+		flush_tlb_page(vma, address);
+	}
+	return;
+
+bad_pgd:
+	pgd_ERROR(*pgd);
+	pgd_clear(pgd);
+	return;
+
+bad_pmd:
+	pmd_ERROR(*pmd);
+	pmd_clear(pmd);
+	return;
+}
+
+/*
+ * Take care of architecture specific things when placing a new PTE into
+ * a page table, or changing an existing PTE.  Basically, there are two
+ * things that we need to take care of:
+ *
+ *  1. If PG_dcache_dirty is set for the page, we need to ensure
+ *     that any cache entries for the kernels virtual memory
+ *     range are written back to the page.
+ *  2. If we have multiple shared mappings of the same space in
+ *     an object, we need to deal with the cache aliasing issues.
+ *
+ * Note that the page_table_lock will be held.
+ */
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
+{
+	struct page *page = pte_page(pte);
+	struct vm_area_struct *mpnt;
+	struct mm_struct *mm;
+	unsigned long pgoff;
+	int aliases;
+
+	if (!VALID_PAGE(page) || !page->mapping)
+		return;
+
+	if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) {
 		unsigned long kvirt = (unsigned long)page_address(page);
 		cpu_cache_clean_invalidate_range(kvirt, kvirt + PAGE_SIZE, 0);
 	}
+
+	mm = vma->vm_mm;
+	pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
+	aliases = 0;
+
+	/*
+	 * If we have any shared mappings that are in the same mm
+	 * space, then we need to handle them specially to maintain
+	 * cache coherency.
+	 */
+	for (mpnt = page->mapping->i_mmap_shared; mpnt;
+	     mpnt = mpnt->vm_next_share) {
+		unsigned long off;
+
+		/*
+		 * If this VMA is not in our MM, we can ignore it.
+		 * Note that we intentionally don't mask out the VMA
+		 * that we are fixing up.
+		 */
+		if (mpnt->vm_mm != mm && mpnt != vma)
+			continue;
+
+		/*
+		 * If the page isn't in this VMA, we can also ignore it.
+		 */
+		if (pgoff < mpnt->vm_pgoff)
+			continue;
+
+		off = pgoff - mpnt->vm_pgoff;
+		if (off >= (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT)
+			continue;
+
+		/*
+		 * Ok, it is within mpnt.  Fix it up.
+		 */
+		adjust_pte(mpnt, mpnt->vm_start + (off << PAGE_SHIFT));
+		aliases ++;
+	}
+	if (aliases)
+		adjust_pte(vma, addr);
 }
diff -urN linux-2.4.9-pre1/arch/arm/tools/mach-types linux/arch/arm/tools/mach-types
--- linux-2.4.9-pre1/arch/arm/tools/mach-types	Mon Dec  3 23:01:02 2001
+++ linux/arch/arm/tools/mach-types	Mon Dec  3 23:01:22 2001
@@ -6,7 +6,7 @@
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Wed Jul 25 10:07:10 2001
+# Last update: Thu Aug 9 22:46:02 2001
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -114,3 +114,4 @@
 gator			SA1100_GATOR		GATOR			103
 granite			ARCH_GRANITE		GRANITE			104
 consus			SA1100_CONSUS		CONSUS			105
+aaec2000_aaed20		ARCH_AAEC2000_AAED2000	AAEC2000_AAED2000	106
diff -urN linux-2.4.9-pre1/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- linux-2.4.9-pre1/drivers/char/tty_io.c	Sun Jul 15 16:15:44 2001
+++ linux/drivers/char/tty_io.c	Mon Dec  3 23:01:22 2001
@@ -105,7 +105,6 @@
 #ifdef CONFIG_VT
 extern void con_init_devfs (void);
 #endif
-extern int rio_init(void);
 
 #define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
 #define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
@@ -154,7 +153,7 @@
 extern void con3215_init(void);
 extern void tty3215_init(void);
 extern void tub3270_con_init(void);
-extern void tub3270_initfunc(void);
+extern void tub3270_init(void);
 extern void rs285_console_init(void);
 extern void sa1100_rs_console_init(void);
 extern void sgi_serial_console_init(void);
@@ -400,13 +399,8 @@
 	return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
 }
 
-static loff_t tty_lseek(struct file * file, loff_t offset, int orig)
-{
-	return -ESPIPE;
-}
-
 static struct file_operations tty_fops = {
-	llseek:		tty_lseek,
+	llseek:		no_llseek,
 	read:		tty_read,
 	write:		tty_write,
 	poll:		tty_poll,
@@ -417,7 +411,7 @@
 };
 
 static struct file_operations hung_up_tty_fops = {
-	llseek:		tty_lseek,
+	llseek:		no_llseek,
 	read:		hung_up_tty_read,
 	write:		hung_up_tty_write,
 	poll:		hung_up_tty_poll,
@@ -2194,7 +2188,9 @@
 #if (defined(CONFIG_8xx) || defined(CONFIG_8260))
 	console_8xx_init();
 #elif defined(CONFIG_MAC_SERIAL)
-	mac_scc_console_init();
+ 	mac_scc_console_init();
+#elif defined(CONFIG_PARISC)
+	pdc_console_init();
 #elif defined(CONFIG_SERIAL)
 	serial_console_init();
 #endif /* CONFIG_8xx */
@@ -2211,15 +2207,18 @@
 	sci_console_init();
 #endif
 #endif
-#ifdef CONFIG_3215
-        con3215_init();
-#endif
-#ifdef CONFIG_3270_CONSOLE
+#ifdef CONFIG_TN3270_CONSOLE
 	tub3270_con_init();
 #endif
+#ifdef CONFIG_TN3215
+	con3215_init();
+#endif
 #ifdef CONFIG_HWC
         hwc_console_init();
 #endif
+#ifdef CONFIG_STDIO_CONSOLE
+	stdio_console_init();
+#endif
 #ifdef CONFIG_SERIAL_21285_CONSOLE
 	rs285_console_init();
 #endif
@@ -2309,6 +2308,7 @@
 
 	kbd_init();
 #endif
+
 #ifdef CONFIG_ESPSERIAL  /* init ESP before rs, so rs doesn't see the port */
 	espserial_init();
 #endif
@@ -2342,9 +2342,6 @@
 #ifdef CONFIG_SPECIALIX
 	specialix_init();
 #endif
-#ifdef CONFIG_RIO
-	rio_init();
-#endif
 #if (defined(CONFIG_8xx) || defined(CONFIG_8260))
 	rs_8xx_init();
 #endif /* CONFIG_8xx */
@@ -2358,10 +2355,10 @@
 #ifdef CONFIG_VT
 	vcs_init();
 #endif
-#ifdef CONFIG_3270
-	tub3270_initfunc();
+#ifdef CONFIG_TN3270
+	tub3270_init();
 #endif
-#ifdef CONFIG_3215
+#ifdef CONFIG_TN3215
 	tty3215_init();
 #endif
 #ifdef CONFIG_HWC
diff -urN linux-2.4.9-pre1/drivers/char/tty_ioctl.c linux/drivers/char/tty_ioctl.c
--- linux-2.4.9-pre1/drivers/char/tty_ioctl.c	Wed Mar 15 19:48:06 2000
+++ linux/drivers/char/tty_ioctl.c	Mon Dec  3 23:01:22 2001
@@ -47,7 +47,7 @@
 #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
 	char buf[64];
 	
-	printk("%s wait until sent...\n", tty_name(tty, buf));
+	printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
 #endif
 	if (!tty->driver.chars_in_buffer)
 		return;
@@ -56,7 +56,7 @@
 		timeout = MAX_SCHEDULE_TIMEOUT;
 	do {
 #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
-		printk("waiting %s...(%d)\n", tty_name(tty, buf),
+		printk(KERN_DEBUG "waiting %s...(%d)\n", tty_name(tty, buf),
 		       tty->driver.chars_in_buffer(tty));
 #endif
 		set_current_state(TASK_INTERRUPTIBLE);
@@ -82,7 +82,7 @@
 #define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
 
 	if (!locked) {
-		printk("Warning?!? termios_locked is NULL.\n");
+		printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
 		return;
 	}
 
diff -urN linux-2.4.9-pre1/drivers/char/vt.c linux/drivers/char/vt.c
--- linux-2.4.9-pre1/drivers/char/vt.c	Mon Dec  3 23:01:02 2001
+++ linux/drivers/char/vt.c	Mon Dec  3 23:01:22 2001
@@ -7,6 +7,7 @@
  *  Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
  *  Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995
  *  Some code moved for less code duplication - Andi Kleen - Mar 1997
+ *  Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001
  */
 
 #include <linux/config.h>
@@ -287,8 +288,10 @@
 		p = func_table[i];
 		if(p)
 			for ( ; *p && sz; p++, sz--)
-				put_user(*p, q++);
-		put_user('\0', q);
+				if (put_user(*p, q++))
+					return -EFAULT;
+		if (put_user('\0', q))
+			return -EFAULT;
 		return ((p && *p) ? -EOVERFLOW : 0);
 	case KDSKBSENT:
 		if (!perm)
@@ -739,10 +742,8 @@
 		struct vt_stat *vtstat = (struct vt_stat *)arg;
 		unsigned short state, mask;
 
-		i = verify_area(VERIFY_WRITE,(void *)vtstat, sizeof(struct vt_stat));
-		if (i)
-			return i;
-		put_user(fg_console + 1, &vtstat->v_active);
+		if (put_user(fg_console + 1, &vtstat->v_active))
+			return -EFAULT;
 		state = 1;	/* /dev/tty0 is always open */
 		for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1)
 			if (VT_IS_IN_USE(i))
@@ -878,11 +879,9 @@
 		ushort ll,cc;
 		if (!perm)
 			return -EPERM;
-		i = verify_area(VERIFY_READ, (void *)vtsizes, sizeof(struct vt_sizes));
-		if (i)
-			return i;
-		get_user(ll, &vtsizes->v_rows);
-		get_user(cc, &vtsizes->v_cols);
+		if (get_user(ll, &vtsizes->v_rows) ||
+		    get_user(cc, &vtsizes->v_cols))
+			return -EFAULT;
 		return vc_resize_all(ll, cc);
 	}
 
@@ -892,15 +891,15 @@
 		ushort ll,cc,vlin,clin,vcol,ccol;
 		if (!perm)
 			return -EPERM;
-		i = verify_area(VERIFY_READ, (void *)vtconsize, sizeof(struct vt_consize));
-		if (i)
-			return i;
-		get_user(ll, &vtconsize->v_rows);
-		get_user(cc, &vtconsize->v_cols);
-		get_user(vlin, &vtconsize->v_vlin);
-		get_user(clin, &vtconsize->v_clin);
-		get_user(vcol, &vtconsize->v_vcol);
-		get_user(ccol, &vtconsize->v_ccol);
+		if (verify_area(VERIFY_READ, (void *)vtconsize,
+				sizeof(struct vt_consize)))
+			return -EFAULT;
+		__get_user(ll, &vtconsize->v_rows);
+		__get_user(cc, &vtconsize->v_cols);
+		__get_user(vlin, &vtconsize->v_vlin);
+		__get_user(clin, &vtconsize->v_clin);
+		__get_user(vcol, &vtconsize->v_vcol);
+		__get_user(ccol, &vtconsize->v_ccol);
 		vlin = vlin ? vlin : video_scan_lines;
 		if ( clin )
 		  {
@@ -1067,10 +1066,6 @@
 
 			if (!perm)
 				return -EPERM;
-			i = verify_area(VERIFY_READ, (void *) arg,
-					sizeof(struct vc_mode));
-			if (i)
-				return i;
 			if (copy_from_user(&mode, (void *) arg, sizeof(mode)))
 				return -EFAULT;
 			return console_setmode(&mode, cmd == VC_SETMODE);
@@ -1088,10 +1083,6 @@
 				   was changed from 0x766a to 0x766c */
 				return console_powermode((int) arg);
 			}
-			i = verify_area(VERIFY_READ, (void *) arg,
-					sizeof(int));
-			if (i)
-				return i;
 			if (get_user(cmap_size, (int *) arg))
 				return -EFAULT;
 			if (cmap_size % 3)
diff -urN linux-2.4.9-pre1/drivers/isdn/eicon/common.c linux/drivers/isdn/eicon/common.c
--- linux-2.4.9-pre1/drivers/isdn/eicon/common.c	Mon Dec  3 23:01:02 2001
+++ linux/drivers/isdn/eicon/common.c	Mon Dec  3 23:01:22 2001
@@ -37,9 +37,6 @@
 #define DIVAS_IRQ_RESET		0xC18
 #define DIVAS_IRQ_RESET_VAL	0xFE
 
-#define	PCI_LATENCY	PCI_LATENCY_TIMER
-#define PCI_INTERRUPT	PCI_INTERRUPT_LINE
-
 #define TEST_INT_DIVAS		0x11
 #define TEST_INT_DIVAS_BRI	0x12
 #define TEST_INT_DIVAS_Q	0x13
@@ -478,7 +475,6 @@
 int DivasCardNew(dia_card_t *card_info)
 {
 	card_t *card;
-	byte b;
 	static boolean_t first_call = TRUE;
 	boolean_t NeedISRandReset = FALSE;
 
@@ -567,10 +563,6 @@
 			return -1;
 		}
 
-		b = card->cfg.irq;
-
-		UxPciConfigWrite(card->hw, sizeof(b), PCI_INTERRUPT_LINE, &b);
-
 		if (card_info->card_type != DIA_CARD_TYPE_DIVA_SERVER_Q)
 		{
 			if ((*card->card_reset)(card))
@@ -670,7 +662,7 @@
 		return -1;
 	}
 
-	bzero(card->e_tbl, sizeof(E_INFO) * num_entities);
+	memset(card->e_tbl, 0, sizeof(E_INFO) * num_entities);
 	card->e_max = num_entities;
 
     DIVA_DIDD_Read(d, sizeof(d));
diff -urN linux-2.4.9-pre1/drivers/isdn/eicon/linchr.c linux/drivers/isdn/eicon/linchr.c
--- linux-2.4.9-pre1/drivers/isdn/eicon/linchr.c	Wed Jun 27 17:10:55 2001
+++ linux/drivers/isdn/eicon/linchr.c	Mon Dec  3 23:01:22 2001
@@ -37,7 +37,6 @@
 
 extern int DivasCardNext;
 void UxPause(long ms);
-void bcopy(void *pSource, void *pDest, dword dwLength);
 int DivasGetMem(mem_block_t *);
 
 #define DIA_IOCTL_UNLOCK 12
@@ -157,11 +156,8 @@
 {
 	word wMask = 0;
 
-    if (!DivasLogFifoEmpty())
-    {
+	if (!DivasLogFifoEmpty())
 		wMask |= POLLIN | POLLRDNORM;
-	}
-
 	return wMask;
 }
 
@@ -174,14 +170,14 @@
 	{
 		printk(KERN_WARNING "Divas: Divalog buffer specifed a size that is too small (%d - %d required)\n",
 			BufferSize, sizeof(klog_t));
-		return 0;
+		return -EIO;
 	}
 
 	pHeadItem = (klog_t *) DivasLogFifoRead();
 
 	if (pHeadItem)
 	{
-		bcopy(pHeadItem, pClientLogBuffer, sizeof(klog_t));
+		memcpy(pClientLogBuffer, pHeadItem, sizeof(klog_t));
 		kfree(pHeadItem);
 		return sizeof(klog_t);
 	}
diff -urN linux-2.4.9-pre1/drivers/isdn/eicon/linsys.c linux/drivers/isdn/eicon/linsys.c
--- linux-2.4.9-pre1/drivers/isdn/eicon/linsys.c	Fri Mar  2 11:12:08 2001
+++ linux/drivers/isdn/eicon/linsys.c	Mon Dec  3 23:01:22 2001
@@ -38,18 +38,6 @@
 
 #include "uxio.h"
 
-#ifdef MODULE
-void bcopy(void *pSource, void *pDest, dword dwLength)
-{
-	memcpy(pDest, pSource, dwLength);
-}
-#endif
-
-void bzero(void *pDataArea, dword dwLength)
-{
-	memset(pDataArea, 0, dwLength);
-}
-
 int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg)
 {
 	/* Use UxPciConfigWrite	routines to initialise PCI config space */
diff -urN linux-2.4.9-pre1/drivers/isdn/eicon/uxio.h linux/drivers/isdn/eicon/uxio.h
--- linux-2.4.9-pre1/drivers/isdn/eicon/uxio.h	Fri Mar  2 11:12:08 2001
+++ linux/drivers/isdn/eicon/uxio.h	Mon Dec  3 23:01:22 2001
@@ -58,10 +58,6 @@
 	isr_fn_t	*user_isr;
 };
 
-void bcopy(void *pSource, void *pDest, dword dwLength);
-void bzero(void *pDataArea, dword dwLength);
-
-
 /*
  * Get a card handle to enable card to be accessed
  */
diff -urN linux-2.4.9-pre1/drivers/pci/pci.c linux/drivers/pci/pci.c
--- linux-2.4.9-pre1/drivers/pci/pci.c	Wed Jul  4 09:41:34 2001
+++ linux/drivers/pci/pci.c	Mon Dec  3 23:01:22 2001
@@ -290,6 +290,15 @@
 	/* enter specified state */
 	pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr);
 
+	/* Mandatory power management transition delays */
+	/* see PCI PM 1.1 5.6.1 table 18 */
+	if(state == 3 || dev->current_state == 3)
+	{
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/100);
+	}
+	else if(state == 2 || dev->current_state == 2)
+		udelay(200);
 	dev->current_state = state;
 
 	return 0;
diff -urN linux-2.4.9-pre1/drivers/pci/pci.ids linux/drivers/pci/pci.ids
--- linux-2.4.9-pre1/drivers/pci/pci.ids	Mon Dec  3 23:01:02 2001
+++ linux/drivers/pci/pci.ids	Mon Dec  3 23:01:22 2001
@@ -4270,6 +4270,9 @@
 1607  Lava Semiconductor Manufacturing Inc
 1608  Automated Wagering International
 1609  Scimetric Instruments Inc
+1619  FarSite Communications Ltd
+	0400  FarSync T2P (2 port X.21/V.35/V.24)
+	0440  FarSync T4P (4 port X.21/V.35/V.24)
 1668  Action Tec Electronics Inc
 1813  Ambient Technologies Inc
 1a08  Sierra semiconductor
diff -urN linux-2.4.9-pre1/drivers/pcmcia/bulkmem.c linux/drivers/pcmcia/bulkmem.c
--- linux-2.4.9-pre1/drivers/pcmcia/bulkmem.c	Tue Mar  6 19:28:32 2001
+++ linux/drivers/pcmcia/bulkmem.c	Mon Dec  3 23:01:22 2001
@@ -211,7 +211,7 @@
     retry_erase((erase_busy_t *)arg, MTD_REQ_TIMEOUT);
 }
 
-static void setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
+static int setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
 {
     erase_busy_t *busy;
     region_info_t *info;
@@ -229,6 +229,8 @@
 	else {
 	    erase->State = 1;
 	    busy = kmalloc(sizeof(erase_busy_t), GFP_KERNEL);
+	    if (!busy)
+		return CS_GENERAL_FAILURE;
 	    busy->erase = erase;
 	    busy->client = handle;
 	    init_timer(&busy->timeout);
@@ -238,6 +240,7 @@
 	    retry_erase(busy, 0);
 	}
     }
+    return CS_SUCCESS;
 } /* setup_erase_request */
 
 /*======================================================================
@@ -322,7 +325,7 @@
     
 ======================================================================*/
 
-static void setup_regions(client_handle_t handle, int attr,
+static int setup_regions(client_handle_t handle, int attr,
 			  memory_handle_t *list)
 {
     int i, code, has_jedec, has_geo;
@@ -337,7 +340,7 @@
 
     code = (attr) ? CISTPL_DEVICE_A : CISTPL_DEVICE;
     if (read_tuple(handle, code, &device) != CS_SUCCESS)
-	return;
+	return CS_GENERAL_FAILURE;
     code = (attr) ? CISTPL_JEDEC_A : CISTPL_JEDEC_C;
     has_jedec = (read_tuple(handle, code, &jedec) == CS_SUCCESS);
     if (has_jedec && (device.ndev != jedec.nid)) {
@@ -360,6 +363,8 @@
 	if ((device.dev[i].type != CISTPL_DTYPE_NULL) &&
 	    (device.dev[i].size != 0)) {
 	    r = kmalloc(sizeof(*r), GFP_KERNEL);
+	    if (!r)
+		return CS_GENERAL_FAILURE;
 	    r->region_magic = REGION_MAGIC;
 	    r->state = 0;
 	    r->dev_info[0] = '\0';
@@ -384,6 +389,7 @@
 	}
 	offset += device.dev[i].size;
     }
+    return CS_SUCCESS;
 } /* setup_regions */
 
 /*======================================================================
@@ -417,8 +423,10 @@
     
     if ((handle->Attributes & INFO_MASTER_CLIENT) &&
 	(!(s->state & SOCKET_REGION_INFO))) {
-	setup_regions(handle, 0, &s->c_region);
-	setup_regions(handle, 1, &s->a_region);
+	if (setup_regions(handle, 0, &s->c_region) != CS_SUCCESS)
+	    return CS_GENERAL_FAILURE;
+	if (setup_regions(handle, 1, &s->a_region) != CS_SUCCESS)
+	    return CS_GENERAL_FAILURE;
 	s->state |= SOCKET_REGION_INFO;
     }
 
diff -urN linux-2.4.9-pre1/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- linux-2.4.9-pre1/drivers/scsi/advansys.c	Fri Apr 27 13:59:18 2001
+++ linux/drivers/scsi/advansys.c	Mon Dec  3 23:01:22 2001
@@ -789,7 +789,7 @@
 #include <linux/types.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
diff -urN linux-2.4.9-pre1/drivers/scsi/aic7xxx/aic7770.c linux/drivers/scsi/aic7xxx/aic7770.c
--- linux-2.4.9-pre1/drivers/scsi/aic7xxx/aic7770.c	Mon Dec  3 23:01:02 2001
+++ linux/drivers/scsi/aic7xxx/aic7770.c	Mon Dec  3 23:01:22 2001
@@ -15,7 +15,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
diff -urN linux-2.4.9-pre1/drivers/scsi/aic7xxx/aic7770_linux.c linux/drivers/scsi/aic7xxx/aic7770_linux.c
--- linux-2.4.9-pre1/drivers/scsi/aic7xxx/aic7770_linux.c	Fri May  4 15:16:28 2001
+++ linux/drivers/scsi/aic7xxx/aic7770_linux.c	Mon Dec  3 23:01:22 2001
@@ -14,7 +14,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
diff -urN linux-2.4.9-pre1/drivers/scsi/aic7xxx/aic7xxx.c linux/drivers/scsi/aic7xxx/aic7xxx.c
--- linux-2.4.9-pre1/drivers/scsi/aic7xxx/aic7xxx.c	Mon Dec  3 23:01:03 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx.c	Mon Dec  3 23:01:22 2001
@@ -14,7 +14,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
diff -urN linux-2.4.9-pre1/drivers/scsi/aic7xxx/aic7xxx_93cx6.c linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
--- linux-2.4.9-pre1/drivers/scsi/aic7xxx/aic7xxx_93cx6.c	Mon Dec  3 23:01:03 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.c	Mon Dec  3 23:01:22 2001
@@ -14,7 +14,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
diff -urN linux-2.4.9-pre1/drivers/scsi/aic7xxx/aic7xxx_linux.c linux/drivers/scsi/aic7xxx/aic7xxx_linux.c
--- linux-2.4.9-pre1/drivers/scsi/aic7xxx/aic7xxx_linux.c	Mon Dec  3 23:01:03 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_linux.c	Mon Dec  3 23:01:22 2001
@@ -52,7 +52,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
diff -urN linux-2.4.9-pre1/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c
--- linux-2.4.9-pre1/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c	Mon Dec  3 23:01:03 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c	Mon Dec  3 23:01:22 2001
@@ -14,7 +14,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
diff -urN linux-2.4.9-pre1/drivers/scsi/aic7xxx/aic7xxx_pci.c linux/drivers/scsi/aic7xxx/aic7xxx_pci.c
--- linux-2.4.9-pre1/drivers/scsi/aic7xxx/aic7xxx_pci.c	Mon Dec  3 23:01:03 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_pci.c	Mon Dec  3 23:01:22 2001
@@ -16,7 +16,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
diff -urN linux-2.4.9-pre1/drivers/scsi/aic7xxx/aic7xxx_proc.c linux/drivers/scsi/aic7xxx/aic7xxx_proc.c
--- linux-2.4.9-pre1/drivers/scsi/aic7xxx/aic7xxx_proc.c	Fri May  4 15:16:28 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_proc.c	Mon Dec  3 23:01:22 2001
@@ -12,7 +12,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
diff -urN linux-2.4.9-pre1/drivers/scsi/aic7xxx/aicasm/aicasm.c linux/drivers/scsi/aic7xxx/aicasm/aicasm.c
--- linux-2.4.9-pre1/drivers/scsi/aic7xxx/aicasm/aicasm.c	Mon Dec  3 23:01:03 2001
+++ linux/drivers/scsi/aic7xxx/aicasm/aicasm.c	Mon Dec  3 23:01:22 2001
@@ -14,7 +14,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
diff -urN linux-2.4.9-pre1/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c
--- linux-2.4.9-pre1/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c	Mon Dec  3 23:01:03 2001
+++ linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c	Mon Dec  3 23:01:22 2001
@@ -14,7 +14,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
diff -urN linux-2.4.9-pre1/drivers/sound/emu10k1/audio.c linux/drivers/sound/emu10k1/audio.c
--- linux-2.4.9-pre1/drivers/sound/emu10k1/audio.c	Mon Dec  3 23:01:03 2001
+++ linux/drivers/sound/emu10k1/audio.c	Mon Dec  3 23:01:22 2001
@@ -1218,7 +1218,6 @@
 		tasklet_init(&woinst->timer.tasklet, emu10k1_waveout_bh, (unsigned long) wave_dev);
 		wave_dev->woinst = woinst;
 		emu10k1_waveout_setformat(wave_dev, &woinst->format);
-
 	}
 
 	file->private_data = (void *) wave_dev;
@@ -1261,7 +1260,7 @@
 
 		spin_unlock_irqrestore(&woinst->lock, flags);
 		/* wait for the tasklet (bottom-half) to finish */
-		tasklet_unlock_wait(&woinst->timer.tasklet);
+		tasklet_kill(&woinst->timer.tasklet);
 		kfree(wave_dev->woinst);
 	}
 
@@ -1275,7 +1274,7 @@
 		}
 
 		spin_unlock_irqrestore(&wiinst->lock, flags);
-		tasklet_unlock_wait(&wiinst->timer.tasklet);
+		tasklet_kill(&wiinst->timer.tasklet);
 		kfree(wave_dev->wiinst);
 	}
 
@@ -1491,6 +1490,9 @@
 	u32 bytestocopy;
 	unsigned long flags;
 
+	if (!wiinst)
+		return;
+
 	spin_lock_irqsave(&wiinst->lock, flags);
 
 	if (!(wiinst->state & WAVE_STATE_STARTED)) {
@@ -1517,6 +1519,9 @@
 	struct woinst *woinst = wave_dev->woinst;
 	u32 bytestocopy;
 	unsigned long flags;
+
+	if (!woinst)
+		return;
 
 	spin_lock_irqsave(&woinst->lock, flags);
 
diff -urN linux-2.4.9-pre1/drivers/sound/emu10k1/main.c linux/drivers/sound/emu10k1/main.c
--- linux-2.4.9-pre1/drivers/sound/emu10k1/main.c	Mon Dec  3 23:01:03 2001
+++ linux/drivers/sound/emu10k1/main.c	Mon Dec  3 23:01:22 2001
@@ -370,10 +370,10 @@
 
 static void __devinit emu10k1_midi_cleanup(struct emu10k1_card *card)
 {
-    tasklet_unlock_wait(&card->mpuout->tasklet);
+    tasklet_kill(&card->mpuout->tasklet);
     kfree(card->mpuout);
 
-    tasklet_unlock_wait(&card->mpuin->tasklet);
+    tasklet_kill(&card->mpuin->tasklet);
     kfree(card->mpuin);
 
 #ifdef EMU10K1_SEQUENCER
diff -urN linux-2.4.9-pre1/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- linux-2.4.9-pre1/drivers/sound/i810_audio.c	Mon Dec  3 23:01:03 2001
+++ linux/drivers/sound/i810_audio.c	Mon Dec  3 23:01:22 2001
@@ -1451,7 +1451,7 @@
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
 		if(val==0) {
-			ret = -EINVAL;
+			return -EINVAL;
 		} else {
 			ret = 1;
 		}
diff -urN linux-2.4.9-pre1/drivers/usb/CDCEther.c linux/drivers/usb/CDCEther.c
--- linux-2.4.9-pre1/drivers/usb/CDCEther.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/CDCEther.c	Mon Dec  3 23:01:22 2001
@@ -0,0 +1,1279 @@
+// Portions of this file taken from 
+// Petko Manolov - Petkan (petkan@dce.bg)
+// from his driver pegasus.c
+
+/*
+ * 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/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/usb.h>
+#include <linux/module.h>
+#include "CDCEther.h"
+
+static const char *version = __FILE__ ": v0.98.4 4 July 2001 Brad Hards and another";
+
+// We will attempt to probe anything that is in the
+// communication device class...
+// We will sort through them later.
+static struct usb_device_id CDCEther_ids[] = {
+	{ USB_DEVICE_INFO(2, 0, 0) },
+	{ }
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// Callback routines from USB device /////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static void read_bulk_callback( struct urb *urb )
+{
+	ether_dev_t *ether_dev = urb->context;
+	struct net_device *net;
+	int count = urb->actual_length, res;
+	struct sk_buff	*skb;
+
+	// Sanity check 
+	if ( !ether_dev || !(ether_dev->flags & CDC_ETHER_RUNNING) ) {
+		dbg("BULK IN callback but driver is not active!");
+		return;
+	}
+
+	net = ether_dev->net;
+	if ( !netif_device_present(net) ) {
+		// Somebody killed our network interface...
+		return;
+	}
+
+	if ( ether_dev->flags & CDC_ETHER_RX_BUSY ) {
+		// Are we already trying to receive a frame???
+		ether_dev->stats.rx_errors++;
+		dbg("ether_dev Rx busy");
+		return;
+	}
+
+	// We are busy, leave us alone!
+	ether_dev->flags |= CDC_ETHER_RX_BUSY;
+
+	switch ( urb->status ) {
+		case USB_ST_NOERROR:
+			break;
+		case USB_ST_NORESPONSE:
+			dbg( "no repsonse in BULK IN" );
+			ether_dev->flags &= ~CDC_ETHER_RX_BUSY;
+			break;
+		default:
+			dbg( "%s: RX status %d", net->name, urb->status );
+			goto goon;
+	}
+
+	// Check to make sure we got some data...
+	if ( !count ) {
+		// We got no data!!!
+		goto goon;
+	}
+
+	// Tell the kernel we want some memory
+	if ( !(skb = dev_alloc_skb(count)) ) {
+		// We got no receive buffer.
+		goto goon;
+	}
+
+	// Here's where it came from
+	skb->dev = net;
+	
+	// Now we copy it over
+	eth_copy_and_sum(skb, ether_dev->rx_buff, count, 0);
+	
+	// Not sure
+	skb_put(skb, count);
+	// Not sure here either
+	skb->protocol = eth_type_trans(skb, net);
+	
+	// Ship it off to the kernel
+	netif_rx(skb);
+	
+	// update out statistics
+	ether_dev->stats.rx_packets++;
+	ether_dev->stats.rx_bytes += count;
+
+goon:
+	// Prep the USB to wait for another frame
+	FILL_BULK_URB( &ether_dev->rx_urb, ether_dev->usb,
+			usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in),
+			ether_dev->rx_buff, ether_dev->wMaxSegmentSize, 
+			read_bulk_callback, ether_dev );
+			
+	// Give this to the USB subsystem so it can tell us 
+	// when more data arrives.
+	if ( (res = usb_submit_urb(&ether_dev->rx_urb)) ) {
+		warn( __FUNCTION__ " failed submint rx_urb %d", res);
+	}
+	
+	// We are no longer busy, show us the frames!!!
+	ether_dev->flags &= ~CDC_ETHER_RX_BUSY;
+}
+
+static void write_bulk_callback( struct urb *urb )
+{
+	ether_dev_t *ether_dev = urb->context;
+
+	// Sanity check
+	if ( !ether_dev || !(ether_dev->flags & CDC_ETHER_RUNNING) ) {
+		// We are insane!!!
+		err( "write_bulk_callback: device not running" );
+		return;
+	}
+
+	// Do we still have a valid kernel network device?
+	if ( !netif_device_present(ether_dev->net) ) {
+		// Someone killed our network interface.
+		err( "write_bulk_callback: net device not present" );
+		return;
+	}
+
+	// Hmm...  What on Earth could have happened???
+	if ( urb->status ) {
+		info("%s: TX status %d", ether_dev->net->name, urb->status);
+	}
+
+	// Update the network interface and tell it we are
+	// ready for another frame
+	ether_dev->net->trans_start = jiffies;
+	netif_wake_queue( ether_dev->net );
+}
+
+//static void intr_callback( struct urb *urb )
+//{
+//	ether_dev_t *ether_dev = urb->context;
+//	struct net_device *net;
+//	__u8	*d;
+//
+//	if ( !ether_dev )
+//		return;
+//		
+//	switch ( urb->status ) {
+//		case USB_ST_NOERROR:
+//			break;
+//		case USB_ST_URB_KILLED:
+//			return;
+//		default:
+//			info("intr status %d", urb->status);
+//	}
+//
+//	d = urb->transfer_buffer;
+//	net = ether_dev->net;
+//	if ( d[0] & 0xfc ) {
+//		ether_dev->stats.tx_errors++;
+//		if ( d[0] & TX_UNDERRUN )
+//			ether_dev->stats.tx_fifo_errors++;
+//		if ( d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT) )
+//			ether_dev->stats.tx_aborted_errors++;
+//		if ( d[0] & LATE_COL )
+//			ether_dev->stats.tx_window_errors++;
+//		if ( d[0] & (NO_CARRIER | LOSS_CARRIER) )
+//			ether_dev->stats.tx_carrier_errors++;
+//	}
+//}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routines for turning net traffic on and off on the USB side ///////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static inline int enable_net_traffic( ether_dev_t *ether_dev )
+{
+	struct usb_device *usb = ether_dev->usb;
+
+	// Here would be the time to set the data interface to the configuration where
+	// it has two endpoints that use a protocol we can understand.
+
+	if (usb_set_interface( usb, 
+	                        ether_dev->data_bInterfaceNumber, 
+	                        ether_dev->data_bAlternateSetting_with_traffic ) )  {
+		err("usb_set_interface() failed" );
+		err("Attempted to set interface %d", ether_dev->data_bInterfaceNumber);
+		err("To alternate setting       %d", ether_dev->data_bAlternateSetting_with_traffic);
+		return -1;
+	}
+	return 0;
+}
+
+static inline void disable_net_traffic( ether_dev_t *ether_dev )
+{
+	// The thing to do is to set the data interface to the alternate setting that has
+	// no endpoints.  This is what the spec suggests.
+
+	if (ether_dev->data_interface_altset_num_without_traffic >= 0 ) {
+		if (usb_set_interface( ether_dev->usb, 
+		                        ether_dev->data_bInterfaceNumber, 
+		                        ether_dev->data_bAlternateSetting_without_traffic ) ) 	{
+			err("usb_set_interface() failed");
+		}
+	} else {
+		// Some devices just may not support this...
+		warn("No way to disable net traffic");
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Callback routines for kernel Ethernet Device //////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static void CDCEther_tx_timeout( struct net_device *net )
+{
+	ether_dev_t *ether_dev = net->priv;
+
+	// Sanity check
+	if ( !ether_dev ) {
+		// Seems to be a case of insanity here
+		return;
+	}
+
+	// Tell syslog we are hosed.
+	warn("%s: Tx timed out.", net->name);
+	
+	// Tear the waiting frame off the list
+	ether_dev->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
+	usb_unlink_urb( &ether_dev->tx_urb );
+	
+	// Update statistics
+	ether_dev->stats.tx_errors++;
+}
+
+static int CDCEther_start_xmit( struct sk_buff *skb, struct net_device *net )
+{
+	ether_dev_t	*ether_dev = net->priv;
+	int 	count;
+	int 	res;
+
+	// If we are told to transmit an ethernet frame that fits EXACTLY 
+	// into an integer number of USB packets, we force it to send one 
+	// more byte so the device will get a runt USB packet signalling the 
+	// end of the ethernet frame
+	if ( (skb->len) ^ (ether_dev->data_ep_out_size) ) {
+		// It was not an exact multiple
+		// no need to add anything extra
+		count = skb->len;
+	} else {
+		// Add one to make it NOT an exact multiple
+		count = skb->len + 1;
+	}
+
+	// Tell the kernel, "No more frames 'til we are done
+	// with this one.'
+	netif_stop_queue( net );
+
+	// Copy it from kernel memory to OUR memory
+	memcpy(ether_dev->tx_buff, skb->data, skb->len);
+
+	// Fill in the URB for shipping it out.
+	FILL_BULK_URB( &ether_dev->tx_urb, ether_dev->usb,
+			usb_sndbulkpipe(ether_dev->usb, ether_dev->data_ep_out),
+			ether_dev->tx_buff, ether_dev->wMaxSegmentSize, 
+			write_bulk_callback, ether_dev );
+
+	// Tell the URB how much it will be transporting today
+	ether_dev->tx_urb.transfer_buffer_length = count;
+	
+	// Send the URB on its merry way.
+	if ((res = usb_submit_urb(&ether_dev->tx_urb)))  {
+		// Hmm...  It didn't go. Tell someone...
+		warn("failed tx_urb %d", res);
+		// update some stats...
+		ether_dev->stats.tx_errors++;
+		// and tell the kernel to give us another.
+		// Maybe we'll get it right next time.
+		netif_start_queue( net );
+	} else {
+		// Okay, it went out.
+		// Update statistics
+		ether_dev->stats.tx_packets++;
+		ether_dev->stats.tx_bytes += skb->len;
+		// And tell the kernel when the last transmit occurred.
+		net->trans_start = jiffies;
+	}
+
+	// We are done with the kernel's memory
+	dev_kfree_skb(skb);
+
+	// We are done here.
+	return 0;
+}
+
+static struct net_device_stats *CDCEther_netdev_stats( struct net_device *net )
+{
+	// Easy enough!
+	return &((ether_dev_t *)net->priv)->stats;
+}
+
+static int CDCEther_open(struct net_device *net)
+{
+	ether_dev_t *ether_dev = (ether_dev_t *)net->priv;
+	int	res;
+
+	// We are finally getting used!
+	MOD_INC_USE_COUNT;
+
+	// Turn on the USB and let the packets flow!!!
+	if ( (res = enable_net_traffic( ether_dev )) ) {
+		err( __FUNCTION__ "can't enable_net_traffic() - %d", res );
+		MOD_DEC_USE_COUNT;
+		return -EIO;
+	}
+
+	// Prep a receive URB
+	FILL_BULK_URB( &ether_dev->rx_urb, ether_dev->usb,
+			usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in),
+			ether_dev->rx_buff, ether_dev->wMaxSegmentSize, 
+			read_bulk_callback, ether_dev );
+
+	// Put it out there so the device can send us stuff
+	if ( (res = usb_submit_urb(&ether_dev->rx_urb)) )
+	{
+		// Hmm...  Okay...
+		warn( __FUNCTION__ " failed rx_urb %d", res );
+	}
+
+	// Tell the kernel we are ready to start receiving from it
+	netif_start_queue( net );
+	
+	// We are up and running.
+	ether_dev->flags |= CDC_ETHER_RUNNING;
+
+	// Let's get ready to move frames!!!
+	return 0;
+}
+
+static int CDCEther_close( struct net_device *net )
+{
+	ether_dev_t	*ether_dev = net->priv;
+
+	// We are no longer running.
+	ether_dev->flags &= ~CDC_ETHER_RUNNING;
+	
+	// Tell the kernel to stop sending us stuff
+	netif_stop_queue( net );
+	
+	// If we are not already unplugged, turn off USB
+	// traffic
+	if ( !(ether_dev->flags & CDC_ETHER_UNPLUG) ) {
+		disable_net_traffic( ether_dev );
+	}
+
+	// We don't need the URBs anymore.
+	usb_unlink_urb( &ether_dev->rx_urb );
+	usb_unlink_urb( &ether_dev->tx_urb );
+	usb_unlink_urb( &ether_dev->intr_urb );
+	
+	// We are not being used now.
+	MOD_DEC_USE_COUNT;
+
+	// That's it.  I'm done.
+	return 0;
+}
+
+static int CDCEther_ioctl( struct net_device *net, struct ifreq *rq, int cmd )
+{
+	//__u16 *data = (__u16 *)&rq->ifr_data;
+	//ether_dev_t	*ether_dev = net->priv;
+
+	// No support here yet.
+	// Do we need support???
+	switch(cmd) {
+		case SIOCDEVPRIVATE:
+			return -EOPNOTSUPP;
+		case SIOCDEVPRIVATE+1:
+			return -EOPNOTSUPP;
+		case SIOCDEVPRIVATE+2:
+			//return 0;
+			return -EOPNOTSUPP;
+		default:
+			return -EOPNOTSUPP;
+	}
+}
+
+static void CDCEther_set_multicast( struct net_device *net )
+{
+	ether_dev_t *ether_dev = net->priv;
+
+	// Tell the kernel to stop sending us frames while we get this
+	// all set up.
+	netif_stop_queue(net);
+
+	// Do what we are told.
+	if (net->flags & IFF_PROMISC) {
+		// TODO - Turn on promiscuous mode
+		info( "%s: Promiscuous mode enabled", net->name);
+	} else if (net->flags & IFF_ALLMULTI){
+		// TODO - Here we need to tell the device to block ALL multicast traffic.
+		info("%s: set allmulti", net->name);
+	} else if (net->mc_count > ether_dev->wNumberMCFilters)	{
+		// TODO - Here we need to set multicast filters, but
+		// There are more than our limit...  Hmm...
+		info("%s: set too many MC filters", net->name);
+	} else {
+		// TODO - Here we are supposed to set SOME of the multicast filters.
+		// I must learn how to do this...
+		//info("%s: set Rx mode", net->name);
+	}
+
+	// Tell the kernel to start giving frames to us again.
+	netif_wake_queue(net);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routines used to parse out the Functional Descriptors /////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static int parse_header_functional_descriptor( int *bFunctionLength, 
+                                               int bDescriptorType, 
+                                               int bDescriptorSubtype,
+                                               unsigned char *data,
+                                               ether_dev_t *ether_dev,
+                                               int *requirements )
+{
+	// Check to make sure we haven't seen one of these already.
+	if ( (~*requirements) & REQ_HDR_FUNC_DESCR ) {
+		err( "Multiple Header Functional Descriptors found." );
+		return -1;
+	}
+	
+	// Is it the right size???
+	if (*bFunctionLength != 5) {
+		info( "Invalid length in Header Functional Descriptor" );
+		// This is a hack to get around a particular device (NO NAMES)
+		// It has this function length set to the length of the
+		// whole class-specific descriptor
+		*bFunctionLength = 5;
+	}
+	
+	// Nothing extremely useful here.
+	// We'll keep it for posterity
+	ether_dev->bcdCDC = data[0] + (data[1] << 8);
+	dbg( "Found Header descriptor, CDC version %x", ether_dev->bcdCDC);
+
+	// We've seen one of these
+	*requirements &= ~REQ_HDR_FUNC_DESCR;
+	
+	// It's all good.
+	return 0;
+}
+
+static int parse_union_functional_descriptor( int *bFunctionLength, 
+                                              int bDescriptorType, 
+                                              int bDescriptorSubtype,
+                                              unsigned char *data,
+                                              ether_dev_t *ether_dev,
+                                              int *requirements )
+{
+	// Check to make sure we haven't seen one of these already.
+	if ( (~*requirements) & REQ_UNION_FUNC_DESCR ) {
+		err( "Multiple Union Functional Descriptors found." );
+		return -1;
+	}
+
+	// Is it the right size?
+	if (*bFunctionLength != 5) {
+		// It is NOT the size we expected.
+		err( "Unsupported length in Union Functional Descriptor" );
+		return -1;
+	}
+	
+	// Sanity check of sorts
+	if (ether_dev->comm_interface != data[0]) {
+		// This tells us that we are chasing the wrong comm
+		// interface or we are crazy or something else weird.
+		if (ether_dev->comm_interface == data[1]) {
+			info( "Probably broken Union descriptor, fudging data interface" );
+			// We'll need this in a few microseconds, 
+			// so guess here, and hope for the best
+			ether_dev->data_interface = data[0];
+		} else {
+			err( "Union Functional Descriptor is broken beyond repair" );
+			return -1;
+		}
+	} else{ // Descriptor is OK
+       		// We'll need this in a few microseconds!
+		ether_dev->data_interface = data[1];
+	}
+
+	// We've seen one of these now.
+	*requirements &= ~REQ_UNION_FUNC_DESCR;
+	
+	// Done
+	return 0;
+}
+
+static int parse_ethernet_functional_descriptor( int *bFunctionLength, 
+                                                 int bDescriptorType, 
+                                                 int bDescriptorSubtype,
+                                                 unsigned char *data,
+                                                 ether_dev_t *ether_dev,
+                                                 int *requirements )
+{
+	// Check to make sure we haven't seen one of these already.
+	if ( (~*requirements) & REQ_ETH_FUNC_DESCR ) {
+		err( "Multiple Ethernet Functional Descriptors found." );
+		return -1;
+	}
+	
+	// Is it the right size?
+	if (*bFunctionLength != 13) {
+		err( "Invalid length in Ethernet Networking Functional Descriptor" );
+		return -1;
+	}
+	
+	// Lots of goodies from this one.  They are all important.
+	ether_dev->iMACAddress = data[0];
+	ether_dev->bmEthernetStatistics = data[1] + (data[2] << 8) + (data[3] << 16) + (data[4] << 24);
+	ether_dev->wMaxSegmentSize = data[5] + (data[6] << 8);
+	ether_dev->wNumberMCFilters = (data[7] + (data[8] << 8)) & 0x00007FFF;
+	ether_dev->bNumberPowerFilters = data[9];
+	
+	// We've seen one of these now.
+	*requirements &= ~REQ_ETH_FUNC_DESCR;
+	
+	// That's all she wrote.
+	return 0;
+}
+
+static int parse_protocol_unit_functional_descriptor( int *bFunctionLength, 
+                                                      int bDescriptorType, 
+                                                      int bDescriptorSubtype,
+                                                      unsigned char *data,
+                                                      ether_dev_t *ether_dev,
+                                                      int *requirements )
+{
+	// There should only be one type if we are sane
+	if (bDescriptorType != CS_INTERFACE) {
+		info( "Invalid bDescriptorType found." );
+		return -1;
+	}
+
+	// The Subtype tells the tale.
+	switch (bDescriptorSubtype){
+		case 0x00:	// Header Functional Descriptor
+			return parse_header_functional_descriptor( bFunctionLength,
+			                                           bDescriptorType,
+			                                           bDescriptorSubtype,
+			                                           data,
+			                                           ether_dev,
+			                                           requirements );
+			break;
+		case 0x06:	// Union Functional Descriptor
+			return parse_union_functional_descriptor( bFunctionLength,
+			                                          bDescriptorType,
+			                                          bDescriptorSubtype,
+			                                          data,
+			                                          ether_dev,
+			                                          requirements );
+			break;
+		case 0x0F:	// Ethernet Networking Functional Descriptor
+			return parse_ethernet_functional_descriptor( bFunctionLength,
+			                                             bDescriptorType,
+			                                             bDescriptorSubtype,
+			                                             data,
+			                                             ether_dev,
+			                                             requirements );
+			break;
+		default:	// We don't support this at this time...
+			// However that doesn't necessarily indicate an error.
+			dbg( "Unexpected header type %x:", bDescriptorSubtype );
+			return 0;
+	}
+	// How did we get here???
+	return -1;
+}
+
+static int parse_ethernet_class_information( unsigned char *data, int length, ether_dev_t *ether_dev )
+{
+	int loc = 0;
+	int rc;
+	int bFunctionLength;
+	int bDescriptorType;
+	int bDescriptorSubtype;
+	int requirements = REQUIREMENTS_TOTAL;
+
+	// As long as there is something here, we will try to parse it
+	while (loc < length) {
+		// Length
+		bFunctionLength = data[loc];
+		loc++;
+		
+		// Type
+		bDescriptorType = data[loc];
+		loc++;
+		
+		// Subtype
+		bDescriptorSubtype = data[loc];
+		loc++;
+		
+		// ship this off to be processed elsewhere.
+		rc = parse_protocol_unit_functional_descriptor( &bFunctionLength, 
+		                                                bDescriptorType, 
+		                                                bDescriptorSubtype, 
+		                                                &data[loc],
+		                                                ether_dev,
+		                                                &requirements );
+		// Did it process okay?
+		if (rc)	{
+			// Something was hosed somewhere.
+			// No need to continue;
+			err("Bad descriptor parsing: %x", rc );
+			return -1;
+		}
+		// We have already taken three bytes.
+		loc += (bFunctionLength - 3);
+	}
+	// Check to see if we got everything we need.
+	if (requirements) {
+		// We missed some of the requirements...
+		err( "Not all required functional descriptors present 0x%08X", requirements );
+		return -1;
+	}
+	// We got everything.
+	return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routine to check for the existence of the Functional Descriptors //////////
+//////////////////////////////////////////////////////////////////////////////
+
+static int find_and_parse_ethernet_class_information( struct usb_device *device, ether_dev_t *ether_dev )
+{
+	struct usb_config_descriptor *conf = NULL;
+	struct usb_interface *comm_intf_group = NULL;
+	struct usb_interface_descriptor *comm_intf = NULL;
+	int rc = -1;
+	// The assumption here is that find_ethernet_comm_interface
+	// and find_valid_configuration 
+	// have already filled in the information about where to find
+	// the a valid commication interface.
+
+	conf = &( device->config[ether_dev->configuration_num] );
+	comm_intf_group = &( conf->interface[ether_dev->comm_interface] );
+	comm_intf = &( comm_intf_group->altsetting[ether_dev->comm_interface_altset_num] );
+	// Let's check and see if it has the extra information we need...
+
+	if (comm_intf->extralen > 0) {
+		// This is where the information is SUPPOSED to be.
+		rc = parse_ethernet_class_information( comm_intf->extra, comm_intf->extralen, ether_dev );
+	} else if (conf->extralen > 0) {
+		// This is a hack.  The spec says it should be at the interface 
+		// location checked above.  However I have seen it here also.
+		// This is the same device that requires the functional descriptor hack above
+		warn( "Ethernet information found at device configuration.  This is broken." );
+		rc = parse_ethernet_class_information( conf->extra, conf->extralen, ether_dev );
+	} else 	{
+		// I don't know where else to look.
+		warn( "No ethernet information found." );
+		rc = -1;
+	}
+	return rc;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routines to verify the data interface /////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static int get_data_interface_endpoints( struct usb_device *device, ether_dev_t *ether_dev )
+{
+	struct usb_config_descriptor *conf = NULL;
+	struct usb_interface *data_intf_group = NULL;
+	struct usb_interface_descriptor *data_intf = NULL;
+	
+	// Walk through and get to the data interface we are checking.
+	conf = &( device->config[ether_dev->configuration_num] );
+	data_intf_group = &( conf->interface[ether_dev->data_interface] );
+	data_intf = &( data_intf_group->altsetting[ether_dev->data_interface_altset_num_with_traffic] );
+
+	// Start out assuming we won't find anything we can use
+	ether_dev->data_ep_in = 0;
+	ether_dev->data_ep_out = 0;
+	
+	// If these are not BULK endpoints, we don't want them
+	if ( data_intf->endpoint[0].bmAttributes != 0x02 ) {
+		return -1;
+	} if ( data_intf->endpoint[1].bmAttributes != 0x02 ) {
+		return -1;
+	}
+
+	// Check the first endpoint to see if it is IN or OUT
+	if ( data_intf->endpoint[0].bEndpointAddress & 0x80 ) {
+		// This endpoint is IN
+		ether_dev->data_ep_in = data_intf->endpoint[0].bEndpointAddress & 0x7F;
+	} else {
+		// This endpoint is OUT
+		ether_dev->data_ep_out = data_intf->endpoint[0].bEndpointAddress & 0x7F;
+		ether_dev->data_ep_out_size = data_intf->endpoint[0].wMaxPacketSize;
+	}
+
+	// Check the second endpoint to see if it is IN or OUT
+	if ( data_intf->endpoint[1].bEndpointAddress & 0x80 ) {
+		// This endpoint is IN
+		ether_dev->data_ep_in = data_intf->endpoint[1].bEndpointAddress & 0x7F;
+	} else	{
+		// This endpoint is OUT
+		ether_dev->data_ep_out = data_intf->endpoint[1].bEndpointAddress & 0x7F;
+		ether_dev->data_ep_out_size = data_intf->endpoint[1].wMaxPacketSize;
+	}
+	
+	// Now make sure we got both an IN and an OUT
+	if (ether_dev->data_ep_in && ether_dev->data_ep_out) {
+		// We did get both, we are in good shape...
+		info( "detected BULK OUT packets of size %d", ether_dev->data_ep_out_size );
+		return 0;
+	}
+	return -1;
+}
+
+static int verify_ethernet_data_interface( struct usb_device *device, ether_dev_t *ether_dev )
+{
+	struct usb_config_descriptor *conf = NULL;
+	struct usb_interface *data_intf_group = NULL;
+	struct usb_interface_descriptor *data_intf = NULL;
+	int rc = -1;
+	int status;
+	int altset_num;
+
+	// The assumption here is that parse_ethernet_class_information()
+	// and find_valid_configuration() 
+	// have already filled in the information about where to find
+	// a data interface
+	conf = &( device->config[ether_dev->configuration_num] );
+	data_intf_group = &( conf->interface[ether_dev->data_interface] );
+
+	// start out assuming we won't find what we are looking for.
+	ether_dev->data_interface_altset_num_with_traffic = -1;
+	ether_dev->data_bAlternateSetting_with_traffic = -1;
+	ether_dev->data_interface_altset_num_without_traffic = -1;
+	ether_dev->data_bAlternateSetting_without_traffic = -1;
+
+	// Walk through every possible setting for this interface until
+	// we find what makes us happy.
+	for ( altset_num = 0; altset_num < data_intf_group->num_altsetting; altset_num++ ) {
+		data_intf = &( data_intf_group->altsetting[altset_num] );
+
+		// Is this a data interface we like?
+		if ( ( data_intf->bInterfaceClass == 0x0A )
+		   && ( data_intf->bInterfaceSubClass == 0x00 )
+		   && ( data_intf->bInterfaceProtocol == 0x00 ) ) {
+			if ( data_intf->bNumEndpoints == 2 ) {
+				// We are required to have one of these.
+				// An interface with 2 endpoints to send Ethernet traffic back and forth
+				// It actually may be possible that the device might only
+				// communicate in a vendor specific manner.
+				// That would not be very nice.
+				// We can add that one later.
+				ether_dev->data_bInterfaceNumber = data_intf->bInterfaceNumber;
+				ether_dev->data_interface_altset_num_with_traffic = altset_num;
+				ether_dev->data_bAlternateSetting_with_traffic = data_intf->bAlternateSetting;
+				status = get_data_interface_endpoints( device, ether_dev );
+				if (!status) {
+					rc = 0;
+				}
+			}
+			if ( data_intf->bNumEndpoints == 0 ) {
+				// According to the spec we are SUPPOSED to have one of these
+				// In fact the device is supposed to come up in this state.
+				// However, I have seen a device that did not have such an interface.
+				// So it must be just optional for our driver...
+				ether_dev->data_bInterfaceNumber = data_intf->bInterfaceNumber;
+				ether_dev->data_interface_altset_num_without_traffic = altset_num;
+				ether_dev->data_bAlternateSetting_without_traffic = data_intf->bAlternateSetting;
+			}
+		}
+	}
+	return rc;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routine to find a communication interface /////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static int find_ethernet_comm_interface( struct usb_device *device, ether_dev_t *ether_dev )
+{
+	struct usb_config_descriptor *conf = NULL;
+	struct usb_interface *comm_intf_group = NULL;
+	struct usb_interface_descriptor *comm_intf = NULL;
+	int intf_num;
+	int altset_num;
+	int rc;
+
+	conf = &( device->config[ether_dev->configuration_num] );
+
+	// We need to check and see if any of these interfaces are something we want.
+	// Walk through each interface one at a time
+	for ( intf_num = 0; intf_num < conf->bNumInterfaces; intf_num++ ) {
+		comm_intf_group = &( conf->interface[intf_num] );
+		// Now for each of those interfaces, check every possible
+		// alternate setting.
+		for ( altset_num = 0; altset_num < comm_intf_group->num_altsetting; altset_num++ ) {
+			comm_intf = &( comm_intf_group->altsetting[altset_num] );
+
+			// Is this a communication class of interface of the
+			// ethernet subclass variety.
+			if ( ( comm_intf->bInterfaceClass == 0x02 )
+			   && ( comm_intf->bInterfaceSubClass == 0x06 )
+			   && ( comm_intf->bInterfaceProtocol == 0x00 ) ) {
+				if ( comm_intf->bNumEndpoints == 1 ) {
+					// Good, we found one, we will try this one
+					// Fill in the structure...
+					ether_dev->comm_interface = intf_num;
+					ether_dev->comm_bInterfaceNumber = comm_intf->bInterfaceNumber;
+					ether_dev->comm_interface_altset_num = altset_num;
+					ether_dev->comm_bAlternateSetting = comm_intf->bAlternateSetting;
+
+					// Look for the Ethernet Functional Descriptors
+					rc = find_and_parse_ethernet_class_information( device, ether_dev );
+					if (rc) {
+						// Nope this was no good after all.
+						continue;
+					}
+
+					// Check that we really can talk to the data
+					// interface 
+					// This includes # of endpoints, protocols,
+					// etc.
+					rc = verify_ethernet_data_interface( device, ether_dev );
+					if (rc)	{
+						// We got something we didn't like
+						continue;
+					}
+					// This communication interface seems to give us everything
+					// we require.  We have all the ethernet info we need.
+					// Let's get out of here and go home right now.
+					return 0;
+				} else {
+                                        // bNumEndPoints != 1
+					// We found an interface that had the wrong number of 
+					// endpoints but would have otherwise been okay
+				} // end bNumEndpoints check.
+			} // end interface specifics check.
+		} // end for altset_num
+	} // end for intf_num
+	return -1;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routine to go through all configurations and find one that ////////////////
+// is an Ethernet Networking Device //////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static int find_valid_configuration( struct usb_device *device, ether_dev_t *ether_dev )
+{
+	struct usb_config_descriptor *conf = NULL;
+	int conf_num;
+	int rc;
+
+	// We will try each and every possible configuration
+	for ( conf_num = 0; conf_num < device->descriptor.bNumConfigurations; conf_num++ ) {
+		conf = &( device->config[conf_num] );
+
+		// Our first requirement : 2 interfaces
+		if ( conf->bNumInterfaces != 2 ) {
+			// I currently don't know how to handle devices with any number of interfaces
+			// other than 2.
+			continue;
+		}
+
+		// This one passed our first check, fill in some 
+		// useful data
+		ether_dev->configuration_num = conf_num;
+		ether_dev->bConfigurationValue = conf->bConfigurationValue;
+
+		// Now run it through the ringers and see what comes
+		// out the other side.
+		rc = find_ethernet_comm_interface( device, ether_dev );
+
+		// Check if we found an ethernet Communcation Device
+		if ( !rc ) {
+			// We found one.
+			return 0;
+		}
+	}
+	// None of the configurations suited us.
+	return -1;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routine that checks a given configuration to see if any driver ////////////
+// has claimed any of the devices interfaces /////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static int check_for_claimed_interfaces( struct usb_config_descriptor *config )
+{
+	struct usb_interface *comm_intf_group;
+	int intf_num;
+
+	// Go through all the interfaces and make sure none are 
+	// claimed by anybody else.
+	for ( intf_num = 0; intf_num < config->bNumInterfaces; intf_num++ ) {
+		comm_intf_group = &( config->interface[intf_num] );
+		if ( usb_interface_claimed( comm_intf_group ) )	{
+			// Somebody has beat us to this guy.
+			// We can't change the configuration out from underneath of whoever
+			// is using this device, so we will go ahead and give up.
+			return -1;
+		}
+	}
+	// We made it all the way through.
+	// I guess no one has claimed any of these interfaces.
+	return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routines to ask for and set the kernel network interface's MAC address ////
+// Used by driver's probe routine ////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static inline unsigned char hex2dec( unsigned char digit )
+{
+	// Is there a standard way to do this???
+	// I have written this code TOO MANY times.
+	if ( (digit >= '0') && (digit <= '9') )	{
+		return (digit - '0');
+	}
+	if ( (digit >= 'a') && (digit <= 'f') )	{
+		return (digit - 'a' + 10);
+	}
+	if ( (digit >= 'A') && (digit <= 'F') )	{
+		return (digit - 'A' + 10);
+	}
+	return 0;
+}
+
+static void set_ethernet_addr( ether_dev_t *ether_dev )
+{
+	unsigned char	mac_addr[6];
+	int		i;
+	int 		len;
+	unsigned char	buffer[13];
+
+	// Let's assume we don't get anything...
+	mac_addr[0] = 0x00;
+	mac_addr[1] = 0x00;
+	mac_addr[2] = 0x00;
+	mac_addr[3] = 0x00;
+	mac_addr[4] = 0x00;
+	mac_addr[5] = 0x00;
+
+	// Let's ask the device...
+	len = usb_string(ether_dev->usb, ether_dev->iMACAddress, buffer, 13);
+
+	// Sanity check!
+	if (len != 12)	{
+		// You gotta love failing sanity checks
+		err("Attempting to get MAC address returned %d bytes", len);
+		return;
+	}
+
+	// Fill in the mac_addr
+	for (i = 0; i < 6; i++)	{
+		mac_addr[i] = ( hex2dec( buffer[2 * i] ) << 4 ) + hex2dec( buffer[2 * i + 1] );
+	}
+
+	// Now copy it over to the kernel's network driver.
+	memcpy( ether_dev->net->dev_addr, mac_addr, sizeof(mac_addr) );
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routine to print to syslog information about the driver ///////////////////
+// Used by driver's probe routine ////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+void log_device_info(ether_dev_t *ether_dev)
+{
+	int len;
+	int string_num;
+	unsigned char manu[256];
+	unsigned char prod[256];
+	unsigned char sern[256];
+	unsigned char *mac_addr;
+
+	// Default empty strings in case we don't find a real one
+	manu[0] = 0x00;
+	prod[0] = 0x00;
+	sern[0] = 0x00;
+
+	// Try to get the device Manufacturer
+	string_num = ether_dev->usb->descriptor.iManufacturer;
+	if (string_num)	{
+		// Put it into its buffer
+		len = usb_string(ether_dev->usb, string_num, manu, 255);
+		// Just to be safe
+		manu[len] = 0x00;
+	}
+
+	// Try to get the device Product Name
+	string_num = ether_dev->usb->descriptor.iProduct;
+	if (string_num)	{
+		// Put it into its buffer
+		len = usb_string(ether_dev->usb, string_num, prod, 255);
+		// Just to be safe
+		prod[len] = 0x00;
+	}
+
+	// Try to get the device Serial Number
+	string_num = ether_dev->usb->descriptor.iSerialNumber;
+	if (string_num)	{
+		// Put it into its buffer
+		len = usb_string(ether_dev->usb, string_num, sern, 255);
+		// Just to be safe
+		sern[len] = 0x00;
+	}
+
+	// This makes it easier for us to print
+	mac_addr = ether_dev->net->dev_addr;
+
+	// Now send everything we found to the syslog
+	info( "%s: %s %s %s %02X:%02X:%02X:%02X:%02X:%02X", 
+	      ether_dev->net->name, manu, prod, sern, mac_addr[0], 
+	      mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], 
+	      mac_addr[5] );
+}
+
+/* Forward declaration */
+static struct usb_driver CDCEther_driver ;
+
+//////////////////////////////////////////////////////////////////////////////
+// Module's probe routine ////////////////////////////////////////////////////
+// claims interfaces if they are for an Ethernet CDC /////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static void * CDCEther_probe( struct usb_device *usb, unsigned int ifnum,
+			     const struct usb_device_id *id)
+{
+	struct net_device	*net;
+	ether_dev_t		*ether_dev;
+	int 			rc;
+
+	// First we should check the active configuration to see if 
+	// any other driver has claimed any of the interfaces.
+	if ( check_for_claimed_interfaces( usb->actconfig ) ) {
+		// Someone has already put there grubby paws on this device.
+		// We don't want it now...
+		return NULL;
+	}
+
+	// We might be finding a device we can use.
+	// We all go ahead and allocate our storage space.
+	// We need to because we have to start filling in the data that
+	// we are going to need later.
+	if(!(ether_dev = kmalloc(sizeof(ether_dev_t), GFP_KERNEL))) {
+		err("out of memory allocating device structure");
+		return NULL;
+	}
+
+	// Zero everything out.
+	memset(ether_dev, 0, sizeof(ether_dev_t));
+
+	// Let's see if we can find a configuration we can use.
+	rc = find_valid_configuration( usb, ether_dev );
+	if (rc)	{
+		// Nope we couldn't find one we liked.
+		// This device was not meant for us to control.
+		kfree( ether_dev );
+		return	NULL;
+	}
+
+	// Now that we FOUND a configuration. let's try to make the 
+	// device go into it.
+	if ( usb_set_configuration( usb, ether_dev->bConfigurationValue ) ) {
+		err("usb_set_configuration() failed");
+		kfree( ether_dev );
+		return NULL;
+	}
+
+	// Now set the communication interface up as required.
+	if (usb_set_interface(usb, ether_dev->comm_bInterfaceNumber, ether_dev->comm_bAlternateSetting)) {
+		err("usb_set_interface() failed");
+		kfree( ether_dev );
+		return NULL;
+	}
+
+	// Only turn traffic on right now if we must...
+	if (ether_dev->data_interface_altset_num_without_traffic >= 0)	{
+		// We found an alternate setting for the data
+		// interface that allows us to turn off traffic.
+		// We should use it.
+		if (usb_set_interface( usb, 
+		                       ether_dev->data_bInterfaceNumber, 
+		                       ether_dev->data_bAlternateSetting_without_traffic)) {
+			err("usb_set_interface() failed");
+			kfree( ether_dev );
+			return NULL;
+		}
+	} else	{
+		// We didn't find an alternate setting for the data
+		// interface that would let us turn off traffic.
+		// Oh well, let's go ahead and do what we must...
+		if (usb_set_interface( usb, 
+		                       ether_dev->data_bInterfaceNumber, 
+		                       ether_dev->data_bAlternateSetting_with_traffic)) {
+			err("usb_set_interface() failed");
+			kfree( ether_dev );
+			return NULL;
+		}
+	}
+
+	// Now we need to get a kernel Ethernet interface.
+	net = init_etherdev( NULL, 0 );
+	if ( !net ) {
+		// Hmm...  The kernel is not sharing today...
+		// Fine, we didn't want it anyway...
+		err( "Unable to initialize ethernet device" );
+		kfree( ether_dev );
+		return	NULL;
+	}
+
+	// Now that we have an ethernet device, let's set it up
+	// (And I don't mean "set [it] up the bomb".)
+	net->priv = ether_dev;
+	net->open = CDCEther_open;
+	net->stop = CDCEther_close;
+	net->watchdog_timeo = CDC_ETHER_TX_TIMEOUT;
+	net->tx_timeout = CDCEther_tx_timeout;   // TX timeout function
+	net->do_ioctl = CDCEther_ioctl;
+	net->hard_start_xmit = CDCEther_start_xmit;
+	net->set_multicast_list = CDCEther_set_multicast;
+	net->get_stats = CDCEther_netdev_stats;
+	net->mtu = ether_dev->wMaxSegmentSize - 14;
+
+	// We'll keep track of this information for later...
+	ether_dev->usb = usb;
+	ether_dev->net = net;
+	
+	// and don't forget the MAC address.
+	set_ethernet_addr( ether_dev );
+
+	// Send a message to syslog about what we are handling
+	log_device_info( ether_dev );
+
+	// I claim this interface to be a CDC Ethernet Networking device
+	usb_driver_claim_interface( &CDCEther_driver, 
+	                            &(usb->config[ether_dev->configuration_num].interface[ether_dev->comm_interface]), 
+	                            ether_dev );
+	// I claim this interface to be a CDC Ethernet Networking device
+	usb_driver_claim_interface( &CDCEther_driver, 
+	                            &(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]), 
+	                            ether_dev );
+
+	// Does this REALLY do anything???
+	usb_inc_dev_use( usb );
+
+	// TODO - last minute HACK
+	ether_dev->comm_ep_in = 5;
+
+	// Okay, we are finally done...
+	return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Module's disconnect routine ///////////////////////////////////////////////
+// Called when the driver is unloaded or the device is unplugged /////////////
+// (Whichever happens first assuming the driver suceeded at its probe) ///////
+//////////////////////////////////////////////////////////////////////////////
+
+static void CDCEther_disconnect( struct usb_device *usb, void *ptr )
+{
+	ether_dev_t *ether_dev = ptr;
+
+	// Sanity check!!!
+	if ( !ether_dev || !ether_dev->usb ) {
+		// We failed.  We are insane!!!
+		warn("unregistering non-existant device");
+		return;
+	}
+
+	// Make sure we fail the sanity check if we try this again.
+	ether_dev->usb = NULL;
+	
+	// It is possible that this function is called before
+	// the "close" function.
+	// This tells the close function we are already disconnected
+	ether_dev->flags |= CDC_ETHER_UNPLUG;
+	
+	// We don't need the network device any more
+	unregister_netdev( ether_dev->net );
+	
+	// For sanity checks
+	ether_dev->net = NULL;
+
+	// I ask again, does this do anything???
+	usb_dec_dev_use( usb );
+
+	// We are done with this interface
+	usb_driver_release_interface( &CDCEther_driver, 
+	                              &(usb->config[ether_dev->configuration_num].interface[ether_dev->comm_interface]) );
+
+	// We are done with this interface too
+	usb_driver_release_interface( &CDCEther_driver, 
+	                              &(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]) );
+
+	// No more tied up kernel memory
+	kfree( ether_dev );
+	
+	// This does no good, but it looks nice!
+	ether_dev = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Driver info ///////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static struct usb_driver CDCEther_driver = {
+	name:		"CDCEther",
+	probe:		CDCEther_probe,
+	disconnect:	CDCEther_disconnect,
+	id_table:	CDCEther_ids,
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// init and exit routines called when driver is installed and uninstalled ////
+//////////////////////////////////////////////////////////////////////////////
+
+int __init CDCEther_init(void)
+{
+	info( "%s", version );
+	return usb_register( &CDCEther_driver );
+}
+
+void __exit CDCEther_exit(void)
+{
+	usb_deregister( &CDCEther_driver );
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Module info ///////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+module_init( CDCEther_init );
+module_exit( CDCEther_exit );
+
+MODULE_AUTHOR("Brad Hards and another");
+MODULE_DESCRIPTION("USB CDC Ethernet driver");
+
+MODULE_DEVICE_TABLE (usb, CDCEther_ids);
+
+//////////////////////////////////////////////////////////////////////////////
+// End of file ///////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
diff -urN linux-2.4.9-pre1/drivers/usb/CDCEther.h linux/drivers/usb/CDCEther.h
--- linux-2.4.9-pre1/drivers/usb/CDCEther.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/CDCEther.h	Mon Dec  3 23:01:22 2001
@@ -0,0 +1,88 @@
+// Portions of this file taken from 
+// Petko Manolov - Petkan (petkan@dce.bg)
+// from his driver pegasus.h
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#define CS_INTERFACE			0x24
+
+#define	CDC_ETHER_MAX_MTU		1536
+
+#define	CDC_ETHER_PRESENT		0x00000001
+#define	CDC_ETHER_RUNNING		0x00000002
+#define	CDC_ETHER_TX_BUSY		0x00000004
+#define	CDC_ETHER_RX_BUSY		0x00000008
+#define	CDC_ETHER_UNPLUG		0x00000040
+
+#define	CDC_ETHER_TX_TIMEOUT	(HZ*10)
+
+#define	TX_UNDERRUN				0x80
+#define	EXCESSIVE_COL			0x40
+#define	LATE_COL				0x20
+#define	NO_CARRIER				0x10
+#define	LOSS_CARRIER			0x08
+#define	JABBER_TIMEOUT			0x04
+
+#define	CDC_ETHER_REQT_READ		0xc0
+#define	CDC_ETHER_REQT_WRITE	0x40
+#define	CDC_ETHER_REQ_GET_REGS	0xf0
+#define	CDC_ETHER_REQ_SET_REGS	0xf1
+#define	CDC_ETHER_REQ_SET_REG	PIPERIDER_REQ_SET_REGS
+#define	ALIGN(x)		x __attribute__((aligned(L1_CACHE_BYTES)))
+
+typedef struct _ether_dev_t {
+	struct usb_device	*usb;
+	struct net_device	*net;
+	struct net_device_stats	stats;
+	unsigned		flags;
+	int			configuration_num;
+	int			bConfigurationValue;
+	int			comm_interface;
+	int			comm_bInterfaceNumber;
+	int			comm_interface_altset_num;
+	int			comm_bAlternateSetting;
+	int			comm_ep_in;
+	int			data_interface;
+	int			data_bInterfaceNumber;
+	int			data_interface_altset_num_with_traffic;
+	int			data_bAlternateSetting_with_traffic;
+	int			data_interface_altset_num_without_traffic;
+	int			data_bAlternateSetting_without_traffic;
+	int			data_ep_in;
+	int			data_ep_out;
+	int			data_ep_out_size;
+	__u16			bcdCDC;
+	__u8			iMACAddress;
+	__u32			bmEthernetStatistics;
+	__u16			wMaxSegmentSize;
+	__u16			wNumberMCFilters;
+	__u8			bNumberPowerFilters;
+	int			intr_interval;
+	struct urb		rx_urb, tx_urb, intr_urb;
+	unsigned char		ALIGN(rx_buff[CDC_ETHER_MAX_MTU]);
+	unsigned char		ALIGN(tx_buff[CDC_ETHER_MAX_MTU]);
+	unsigned char		ALIGN(intr_buff[8]);
+} ether_dev_t;
+
+#define REQ_HDR_FUNC_DESCR	0x0001
+#define REQ_UNION_FUNC_DESCR	0x0002
+#define REQ_ETH_FUNC_DESCR	0x0004
+#define REQUIREMENTS_TOTAL	0x0007
+
+
+
diff -urN linux-2.4.9-pre1/drivers/usb/kaweth.c linux/drivers/usb/kaweth.c
--- linux-2.4.9-pre1/drivers/usb/kaweth.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/kaweth.c	Mon Dec  3 23:01:22 2001
@@ -0,0 +1,1054 @@
+/****************************************************************
+ *
+ *     kaweth.c - driver for KL5KUSB101 based USB->Ethernet
+ *
+ *     (c) 2000 Interlan Communications
+ *     (c) 2000 Stephane Alnet
+ *     (C) 2001 Brad Hards
+ *
+ *     Original author: The Zapman <zapman@interlan.net>
+ *     Inspired by, and much credit goes to Michael Rothwell 
+ *     <rothwell@interlan.net> for the test equipment, help, and patience
+ *     Based off of (and with thanks to) Petko Manolov's pegaus.c driver.
+ *     Also many thanks to Joel Silverman and Ed Surprenant at Kawasaki 
+ *     for providing the firmware and driver resources.
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2, or 
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software Foundation,
+ *     Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
+ *
+ ****************************************************************/
+
+/* TODO:
+ * Fix in_interrupt() problem
+ * Develop test procedures for USB net interfaces
+ * Run test procedures
+ * Fix bugs from previous two steps
+ * Snoop other OSs for any tricks we're not doing
+ * SMP locking
+ * Reduce arbitrary timeouts 
+ * Smart multicast support 
+ * Temporary MAC change support
+ * Tunable SOFs parameter - ioctl()?
+ * Ethernet stats collection
+ * Code formatting improvements
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/usb.h>
+#include <linux/types.h>
+#include <asm/semaphore.h>
+
+#define DEBUG
+
+#ifdef DEBUG
+#define kaweth_dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" ,##arg)
+#else
+#define kaweth_dbg(format, arg...) do {} while (0)
+#endif
+#define kaweth_err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" ,##arg)
+#define kaweth_info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ##arg)
+#define kaweth_warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ##arg)
+
+
+#include "kawethfw.h"
+
+#define KAWETH_MTU			1514
+#define KAWETH_BUF_SIZE			1664
+#define KAWETH_TX_TIMEOUT		(5 * HZ)
+#define KAWETH_FIRMWARE_BUF_SIZE	4096
+#define KAWETH_CONTROL_TIMEOUT		(30 * HZ)
+
+#define KAWETH_STATUS_BROKEN		0x0000001
+#define KAWETH_STATUS_CLOSING		0x0000002
+
+#define KAWETH_PACKET_FILTER_PROMISCUOUS	0x01
+#define KAWETH_PACKET_FILTER_ALL_MULTICAST	0x02
+#define KAWETH_PACKET_FILTER_DIRECTED		0x04
+#define KAWETH_PACKET_FILTER_BROADCAST		0x08
+#define KAWETH_PACKET_FILTER_MULTICAST		0x10
+
+/* Table 7 */
+#define KAWETH_COMMAND_GET_ETHERNET_DESC	0x00
+#define KAWETH_COMMAND_MULTICAST_FILTERS        0x01
+#define KAWETH_COMMAND_SET_PACKET_FILTER	0x02
+#define KAWETH_COMMAND_STATISTICS               0x03
+#define KAWETH_COMMAND_SET_TEMP_MAC     	0x06
+#define KAWETH_COMMAND_GET_TEMP_MAC             0x07
+#define KAWETH_COMMAND_SET_URB_SIZE		0x08
+#define KAWETH_COMMAND_SET_SOFS_WAIT		0x09
+#define KAWETH_COMMAND_SCAN			0xFF
+
+#define KAWETH_SOFS_TO_WAIT			0x05
+
+
+MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr> and Brad Hards <bhards@bigpond.net.au>");
+MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver");
+
+static void *kaweth_probe(
+            struct usb_device *dev,             /* the device */
+            unsigned ifnum,                     /* what interface */
+            const struct usb_device_id *id      /* from id_table */
+	);
+static void kaweth_disconnect(struct usb_device *dev, void *ptr);
+int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
+				devrequest *cmd, void *data, int len,
+				int timeout);
+
+/****************************************************************
+ *     usb_device_id
+ ****************************************************************/
+static struct usb_device_id usb_klsi_table[] = {
+	{ USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */ 
+	{ USB_DEVICE(0x04bb, 0x0901) }, /* I-O DATA USB-ET/T */
+	{ USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */ 
+	{ USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */ 
+	{ USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */ 
+	{ USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */
+	{ USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */ 
+	{ USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */
+	{ USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */
+	{ USB_DEVICE(0x066b, 0x2202) }, /* Linksys USB10T */ 
+	{ USB_DEVICE(0x06e1, 0x0008) }, /* ADS USB-10BT */ 
+	{ USB_DEVICE(0x06e1, 0x0009) }, /* ADS USB-10BT */ 
+	{ USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */ 
+	{ USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */ 
+	{ USB_DEVICE(0x07b8, 0x4000) }, /* D-Link DU-E10 */
+	{ USB_DEVICE(0x0846, 0x1001) }, /* NetGear EA-101 */
+	{ USB_DEVICE(0x0846, 0x1002) }, /* NetGear EA-101 */
+	{ USB_DEVICE(0x085a, 0x0008) }, /* PortGear Ethernet Adapter */
+	{ USB_DEVICE(0x085a, 0x0009) }, /* PortGear Ethernet Adapter */
+	{ USB_DEVICE(0x087d, 0x5704) }, /* Jaton USB Ethernet Device Adapter */
+	{ USB_DEVICE(0x0951, 0x0008) }, /* Kingston Technology USB Ethernet Adapter */
+	{ USB_DEVICE(0x095a, 0x3003) }, /* Portsmith Express Ethernet Adapter */
+	{ USB_DEVICE(0x10bd, 0x1427) }, /* ASANTE USB To Ethernet Adapter */
+	{ USB_DEVICE(0x1342, 0x0204) }, /* Mobility USB-Ethernet Adapter */
+	{ USB_DEVICE(0x13d2, 0x0400) }, /* Shark Pocket Adapter */
+	{ USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */ 
+	{ USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */ 
+	{ USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */ 
+	{ USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */
+	{} /* Null terminator */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_klsi_table);
+
+/****************************************************************
+ *     kaweth_driver
+ ****************************************************************/
+static struct usb_driver kaweth_driver = {
+	name:		"kaweth",
+	probe:		kaweth_probe,
+	disconnect:	kaweth_disconnect,
+	id_table:       usb_klsi_table,
+};
+
+typedef __u8 eth_addr_t[6];
+
+/****************************************************************
+ *     usb_eth_dev
+ ****************************************************************/
+struct usb_eth_dev {
+	char *name;
+	__u16 vendor;
+	__u16 device;
+	void *pdata;
+};
+
+/****************************************************************
+ *     kaweth_ethernet_configuration
+ *     Refer Table 8
+ ****************************************************************/
+struct kaweth_ethernet_configuration
+{
+	__u8 size;
+	__u8 reserved1;
+	__u8 reserved2;
+	eth_addr_t hw_addr;
+	__u32 statistics_mask;
+	__u16 segment_size;
+	__u16 max_multicast_filters;
+	__u8 reserved3;
+} __attribute__ ((packed));
+
+/****************************************************************
+ *     kaweth_device
+ ****************************************************************/
+struct kaweth_device
+{
+	spinlock_t device_lock;
+
+	__u32 status;
+
+	struct usb_device *dev;
+	struct net_device *net;
+	wait_queue_head_t control_wait;
+
+	struct urb *rx_urb;
+	struct urb *tx_urb;
+	
+	__u8 firmware_buf[KAWETH_FIRMWARE_BUF_SIZE];
+	__u8 tx_buf[KAWETH_BUF_SIZE];
+	__u8 rx_buf[KAWETH_BUF_SIZE];
+	__u16 packet_filter_bitmap;
+
+	struct kaweth_ethernet_configuration configuration;
+
+	struct net_device_stats stats;
+} __attribute__ ((packed));
+
+
+/****************************************************************
+ *     kaweth_control
+ ****************************************************************/
+static int kaweth_control(struct kaweth_device *kaweth,
+			  unsigned int pipe, 
+			  __u8 request, 
+			  __u8 requesttype, 
+			  __u16 value, 
+			  __u16 index,
+			  void *data, 
+			  __u16 size, 
+			  int timeout)
+{
+	devrequest *dr;
+
+	kaweth_dbg("kaweth_control()");
+
+	if(in_interrupt()) {
+		kaweth_dbg("in_interrupt()");
+		return -EBUSY;
+	}
+
+	dr = kmalloc(sizeof(devrequest), 
+                     in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+
+	if(!dr)
+	{
+		kaweth_dbg("kmalloc() failed");
+		return -ENOMEM;
+	}
+	
+	dr->requesttype = requesttype;
+	dr->request = request;
+	dr->value = value;
+	dr->index = index;
+	dr->length = size;
+
+	return kaweth_internal_control_msg(kaweth->dev,
+					pipe,
+					dr,
+					data,
+					size,
+					timeout);
+}
+
+/****************************************************************
+ *     kaweth_read_configuration
+ ****************************************************************/
+static int kaweth_read_configuration(struct kaweth_device *kaweth)
+{
+	int retval;
+
+	kaweth_dbg("Reading kaweth configuration");
+
+	retval = kaweth_control(kaweth,
+				usb_rcvctrlpipe(kaweth->dev, 0),
+				KAWETH_COMMAND_GET_ETHERNET_DESC,
+				USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
+				0,
+				0,
+				(void *)&kaweth->configuration,
+				sizeof(kaweth->configuration),
+				KAWETH_CONTROL_TIMEOUT);
+
+	return retval;
+}
+
+/****************************************************************
+ *     kaweth_set_urb_size
+ ****************************************************************/
+static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size)
+{
+	int retval;
+
+	kaweth_dbg("Setting URB size to %d", (unsigned)urb_size);
+
+	retval = kaweth_control(kaweth,
+				usb_sndctrlpipe(kaweth->dev, 0),
+				KAWETH_COMMAND_SET_URB_SIZE,
+				USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+				urb_size,
+				0,
+				(void *)&kaweth->firmware_buf,
+				0,
+				KAWETH_CONTROL_TIMEOUT);
+
+	return retval;
+}
+
+/****************************************************************
+ *     kaweth_set_sofs_wait
+ ****************************************************************/
+static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait)
+{
+	int retval;
+
+	kaweth_dbg("Set SOFS wait to %d", (unsigned)sofs_wait);
+
+	retval = kaweth_control(kaweth,
+				usb_sndctrlpipe(kaweth->dev, 0),
+				KAWETH_COMMAND_SET_SOFS_WAIT,
+				USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+				sofs_wait,
+				0,
+				(void *)&kaweth->firmware_buf,
+				0,
+				KAWETH_CONTROL_TIMEOUT);
+
+	return retval;
+}
+
+/****************************************************************
+ *     kaweth_set_receive_filter
+ ****************************************************************/
+static int kaweth_set_receive_filter(struct kaweth_device *kaweth,
+				     __u16 receive_filter)
+{
+	int retval;
+
+	kaweth_dbg("Set receive filter to %d", (unsigned)receive_filter);
+
+	retval = kaweth_control(kaweth,
+				usb_sndctrlpipe(kaweth->dev, 0),
+				KAWETH_COMMAND_SET_PACKET_FILTER,
+				USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+				receive_filter,
+				0,
+				(void *)&kaweth->firmware_buf,
+				0,
+				KAWETH_CONTROL_TIMEOUT);
+
+	return retval;
+}
+
+/****************************************************************
+ *     kaweth_download_firmware
+ ****************************************************************/
+static int kaweth_download_firmware(struct kaweth_device *kaweth, 
+				    __u8 *data, 
+				    __u16 data_len,
+				    __u8 interrupt,
+				    __u8 type)
+{	
+	if(data_len > KAWETH_FIRMWARE_BUF_SIZE)	{
+		kaweth_err("Firmware too big: %d", data_len);
+		return -ENOSPC;
+	}
+	
+	memcpy(kaweth->firmware_buf, data, data_len);
+	
+	kaweth->firmware_buf[2] = (data_len & 0xFF) - 7;
+	kaweth->firmware_buf[3] = data_len >> 8;
+	kaweth->firmware_buf[4] = type;
+	kaweth->firmware_buf[5] = interrupt;
+
+	kaweth_dbg("Downloading firmware at %x to kaweth device at %x", 
+	    (int)data, 
+	    (int)kaweth);
+	kaweth_dbg("Firmware length: %d", data_len);
+
+	return kaweth_control(kaweth,
+		              usb_sndctrlpipe(kaweth->dev, 0),
+			      KAWETH_COMMAND_SCAN,
+			      USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+			      0,
+			      0,
+			      (void *)&kaweth->firmware_buf,
+			      data_len,
+			      KAWETH_CONTROL_TIMEOUT);
+}
+
+/****************************************************************
+ *     kaweth_trigger_firmware
+ ****************************************************************/
+static int kaweth_trigger_firmware(struct kaweth_device *kaweth,
+				   __u8 interrupt)
+{
+	kaweth->firmware_buf[0] = 0xB6;
+	kaweth->firmware_buf[1] = 0xC3;
+	kaweth->firmware_buf[2] = 0x01;
+	kaweth->firmware_buf[3] = 0x00;
+	kaweth->firmware_buf[4] = 0x06;
+	kaweth->firmware_buf[5] = interrupt;
+	kaweth->firmware_buf[6] = 0x00;
+	kaweth->firmware_buf[7] = 0x00;
+	
+	kaweth_dbg("Triggering firmware");
+
+	return kaweth_control(kaweth,
+			      usb_sndctrlpipe(kaweth->dev, 0),
+			      KAWETH_COMMAND_SCAN,
+			      USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+			      0,
+			      0,
+			      (void *)&kaweth->firmware_buf,
+			      8,
+			      KAWETH_CONTROL_TIMEOUT);
+}
+
+/****************************************************************
+ *     kaweth_reset
+ ****************************************************************/
+static int kaweth_reset(struct kaweth_device *kaweth)
+{
+	int result;
+
+	kaweth_dbg("kaweth_reset(%p)", kaweth);
+	result = kaweth_control(kaweth,
+				usb_sndctrlpipe(kaweth->dev, 0),
+				USB_REQ_SET_CONFIGURATION, 
+				0, 
+				kaweth->dev->config[0].bConfigurationValue,
+				0, 
+				NULL, 
+				0, 
+				KAWETH_CONTROL_TIMEOUT);
+
+	udelay(10000);
+
+	kaweth_dbg("kaweth_reset() returns %d.",result);
+
+	return result;
+}
+
+static void kaweth_usb_receive(struct urb *);
+
+/****************************************************************
+ *     kaweth_resubmit_rx_urb
+ ****************************************************************/
+static inline void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth)
+{
+	int result;
+
+	memset(kaweth->rx_urb, 0, sizeof(*kaweth->rx_urb));
+
+	FILL_BULK_URB(kaweth->rx_urb,
+		      kaweth->dev,
+		      usb_rcvbulkpipe(kaweth->dev, 1),
+		      kaweth->rx_buf,
+		      KAWETH_BUF_SIZE,
+		      kaweth_usb_receive,
+		      kaweth);
+
+	if((result = usb_submit_urb(kaweth->rx_urb))) {
+		kaweth_err("resubmitting rx_urb %d failed", result);
+	}
+}
+
+static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth);
+
+/****************************************************************
+ *     kaweth_usb_receive
+ ****************************************************************/
+static void kaweth_usb_receive(struct urb *urb)
+{
+	struct kaweth_device *kaweth = urb->context;
+	struct net_device *net = kaweth->net;
+	
+	int count = urb->actual_length;
+	int count2 = urb->transfer_buffer_length;
+			
+	__u16 pkt_len = *(__u16 *)kaweth->rx_buf;
+
+	struct sk_buff *skb;
+
+	if(kaweth->status & KAWETH_STATUS_CLOSING) {
+		return;
+	}
+	
+	if(urb->status && urb->status != -EREMOTEIO && count != 1) { 
+		kaweth_err("%s RX status: %d count: %d packet_len: %d",
+                           net->name, 
+			   urb->status,
+			   count, 
+			   (int)pkt_len);
+		kaweth_resubmit_rx_urb(kaweth);
+                return;
+	}
+
+	if(kaweth->net && (count > 2)) {
+		if(pkt_len > (count - 2)) {
+			kaweth_err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count);
+			kaweth_err("Packet len & 2047: %x", pkt_len & 2047);
+			kaweth_err("Count 2: %x", count2);
+		        kaweth_resubmit_rx_urb(kaweth);
+                        return;
+                }
+		
+		if(!(skb = dev_alloc_skb(pkt_len+2))) {
+		        kaweth_resubmit_rx_urb(kaweth);
+                        return;
+		}
+
+		skb->dev = net;
+
+		eth_copy_and_sum(skb, kaweth->rx_buf + 2, pkt_len, 0);
+		
+		skb_put(skb, pkt_len);
+
+		skb->protocol = eth_type_trans(skb, net);
+		
+		netif_rx(skb);
+		
+		kaweth->stats.rx_packets++;
+		kaweth->stats.rx_bytes += pkt_len;
+	}
+
+	kaweth_resubmit_rx_urb(kaweth);
+}
+
+/****************************************************************
+ *     kaweth_open
+ ****************************************************************/
+static int kaweth_open(struct net_device *net)
+{
+	struct kaweth_device *kaweth = (struct kaweth_device *)net->priv;
+
+	kaweth_dbg("Dev usage: %d", kaweth->dev->refcnt.counter);
+
+	kaweth_dbg("Opening network device.");
+
+	kaweth_resubmit_rx_urb(kaweth);
+
+	netif_start_queue(net);
+
+	MOD_INC_USE_COUNT;
+
+	kaweth_async_set_rx_mode(kaweth);
+	return 0;
+}
+
+/****************************************************************
+ *     kaweth_close
+ ****************************************************************/
+static int kaweth_close(struct net_device *net)
+{
+	struct kaweth_device *kaweth = net->priv;
+
+	netif_stop_queue(net);
+
+	kaweth->status |= KAWETH_STATUS_CLOSING;
+
+	usb_unlink_urb(kaweth->rx_urb);
+
+	kaweth->status &= ~KAWETH_STATUS_CLOSING;
+
+	MOD_DEC_USE_COUNT;
+
+	printk("Dev usage: %d", kaweth->dev->refcnt.counter);
+
+	return 0;
+}
+
+/****************************************************************
+ *     kaweth_ioctl
+ ****************************************************************/
+static int kaweth_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+	return -EOPNOTSUPP;
+}
+
+/****************************************************************
+ *     kaweth_usb_transmit_complete
+ ****************************************************************/
+static void kaweth_usb_transmit_complete(struct urb *urb)
+{
+	struct kaweth_device *kaweth = urb->context;
+
+	spin_lock(&kaweth->device_lock);
+
+	if (urb->status)
+		kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status);
+
+	netif_wake_queue(kaweth->net);
+
+	spin_unlock(&kaweth->device_lock);
+}
+
+/****************************************************************
+ *     kaweth_start_xmit
+ ****************************************************************/
+static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
+{
+	struct kaweth_device *kaweth = net->priv;
+	int count = skb->len;
+	
+	int res;
+
+	spin_lock(&kaweth->device_lock);
+
+	kaweth_async_set_rx_mode(kaweth);
+	netif_stop_queue(net);
+
+	*((__u16 *)kaweth->tx_buf) = skb->len;
+
+	memcpy(kaweth->tx_buf + 2, skb->data, skb->len);
+
+	memset(kaweth->tx_urb, 0, sizeof(*kaweth->tx_urb));
+
+	FILL_BULK_URB(kaweth->tx_urb,
+		      kaweth->dev,
+		      usb_sndbulkpipe(kaweth->dev, 2),
+		      kaweth->tx_buf,
+		      count + 2,
+		      kaweth_usb_transmit_complete,
+		      kaweth);
+
+	if((res = usb_submit_urb(kaweth->tx_urb)))
+	{
+		kaweth_warn("kaweth failed tx_urb %d", res);
+		kaweth->stats.tx_errors++;
+		
+		netif_start_queue(net);
+	} 
+	else 
+	{
+		kaweth->stats.tx_packets++;
+		kaweth->stats.tx_bytes += skb->len;
+		net->trans_start = jiffies;
+	}
+
+	dev_kfree_skb(skb);
+
+	spin_unlock(&kaweth->device_lock);
+
+	return 0;
+}
+
+/****************************************************************
+ *     kaweth_set_rx_mode
+ ****************************************************************/
+static void kaweth_set_rx_mode(struct net_device *net)
+{
+	struct kaweth_device *kaweth = net->priv;
+	
+	__u16 packet_filter_bitmap = KAWETH_PACKET_FILTER_DIRECTED |
+                                     KAWETH_PACKET_FILTER_BROADCAST |
+		                     KAWETH_PACKET_FILTER_MULTICAST;
+
+	kaweth_dbg("Setting Rx mode to %d", packet_filter_bitmap);
+
+	netif_stop_queue(net);
+
+	if (net->flags & IFF_PROMISC) {
+		packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS;
+	} 
+	else if ((net->mc_count) || (net->flags & IFF_ALLMULTI)) {
+		packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST;
+	}
+
+	kaweth->packet_filter_bitmap = packet_filter_bitmap;
+	netif_wake_queue(net);
+}
+
+/****************************************************************
+ *     kaweth_async_set_rx_mode
+ ****************************************************************/
+static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth)
+{
+	__u16 packet_filter_bitmap = kaweth->packet_filter_bitmap;
+	kaweth->packet_filter_bitmap = 0;	
+	if(packet_filter_bitmap == 0) return;
+
+	{
+	int result;
+	result = kaweth_control(kaweth,
+				usb_sndctrlpipe(kaweth->dev, 0),
+				KAWETH_COMMAND_SET_PACKET_FILTER,
+				USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+				packet_filter_bitmap,
+				0,
+				(void *)&kaweth->firmware_buf,
+				0,
+				KAWETH_CONTROL_TIMEOUT);
+
+	if(result < 0) {
+		kaweth_err("Failed to set Rx mode: %d", result);
+	}
+	else {
+		kaweth_dbg("Set Rx mode to %d", packet_filter_bitmap);
+	}
+	}
+}
+
+/****************************************************************
+ *     kaweth_netdev_stats
+ ****************************************************************/
+static struct net_device_stats *kaweth_netdev_stats(struct net_device *dev)
+{
+	return &((struct kaweth_device *)dev->priv)->stats;
+}
+
+/****************************************************************
+ *     kaweth_tx_timeout
+ ****************************************************************/
+static void kaweth_tx_timeout(struct net_device *net)
+{
+	struct kaweth_device *kaweth = net->priv;
+
+	kaweth_warn("%s: Tx timed out. Resetting.", net->name);
+	kaweth->stats.tx_errors++;
+	net->trans_start = jiffies;
+
+	usb_unlink_urb(kaweth->tx_urb);
+
+	netif_wake_queue(net);
+}
+
+/****************************************************************
+ *     kaweth_probe
+ ****************************************************************/
+static void *kaweth_probe(
+            struct usb_device *dev,             /* the device */
+            unsigned ifnum,                      /* what interface */
+            const struct usb_device_id *id      /* from id_table */
+	)
+{
+	struct kaweth_device *kaweth;
+	const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+	int result = 0;
+
+	kaweth_dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x",
+		 dev->devnum, 
+		 (int)dev->descriptor.idVendor, 
+		 (int)dev->descriptor.idProduct,
+		 (int)dev->descriptor.bcdDevice);
+
+	kaweth_dbg("Device at %p", dev);
+
+	kaweth_dbg("Descriptor length: %x type: %x", 
+		 (int)dev->descriptor.bLength,
+		 (int)dev->descriptor.bDescriptorType);
+
+	if(!(kaweth = kmalloc(sizeof(struct kaweth_device), GFP_KERNEL))) {
+		kaweth_dbg("out of memory allocating device structure\n");
+		return NULL;
+	}
+
+	memset(kaweth, 0, sizeof(struct kaweth_device));
+
+	kaweth->dev = dev;
+	kaweth->status = 0;
+	kaweth->net = NULL;
+	kaweth->device_lock = SPIN_LOCK_UNLOCKED;
+		
+	kaweth_dbg("Resetting.");
+
+	kaweth_reset(kaweth);
+
+	/*
+	 * If high byte of bcdDevice is nonzero, firmware is already
+	 * downloaded. Don't try to do it again, or we'll hang the device.
+	 */
+
+	if (dev->descriptor.bcdDevice >> 8) {
+		kaweth_info("Firmware present in device.");
+	} else {
+		/* Download the firmware */
+		kaweth_info("Downloading firmware...");
+		if ((result = kaweth_download_firmware(kaweth, 
+						      kaweth_new_code, 
+						      len_kaweth_new_code, 
+						      100, 
+						      2)) < 0) {
+			kaweth_err("Error downloading firmware (%d)", result);
+			kfree(kaweth);
+			return NULL;
+		}
+
+		if ((result = kaweth_download_firmware(kaweth, 
+						      kaweth_new_code_fix, 
+						      len_kaweth_new_code_fix, 
+						      100, 
+						      3)) < 0) {
+			kaweth_err("Error downloading firmware fix (%d)", result);
+			kfree(kaweth);
+			return NULL;
+		}
+
+		if ((result = kaweth_download_firmware(kaweth,
+						      kaweth_trigger_code,
+						      len_kaweth_trigger_code,
+						      126,
+						      2)) < 0) {
+			kaweth_err("Error downloading trigger code (%d)", result);
+			kfree(kaweth);
+			return NULL;
+		}
+
+		if ((result = kaweth_download_firmware(kaweth,
+						      kaweth_trigger_code_fix,
+						      len_kaweth_trigger_code_fix,
+						      126,
+						      3)) < 0) {
+			kaweth_err("Error downloading trigger code fix (%d)", result);
+			kfree(kaweth);
+			return NULL;
+		}
+
+
+		if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) {
+			kaweth_err("Error triggering firmware (%d)", result);
+			kfree(kaweth);
+			return NULL;
+		}
+
+		/* Device will now disappear for a moment...  */
+		kaweth_info("Firmware loaded.  I'll be back...");
+		return NULL;
+	}
+
+	result = kaweth_read_configuration(kaweth);
+
+	if(result < 0) {
+		kaweth_err("Error reading configuration (%d), no net device created", result);
+		kfree(kaweth);
+		return NULL;
+	}
+
+	kaweth_info("Statistics collection: %x", kaweth->configuration.statistics_mask);
+	kaweth_info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1));
+	kaweth_info("MTU: %d", kaweth->configuration.segment_size);
+	kaweth_info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+		 (int)kaweth->configuration.hw_addr[0],
+		 (int)kaweth->configuration.hw_addr[1],
+		 (int)kaweth->configuration.hw_addr[2],
+		 (int)kaweth->configuration.hw_addr[3],
+		 (int)kaweth->configuration.hw_addr[4],
+		 (int)kaweth->configuration.hw_addr[5]);
+
+	if(!memcmp(&kaweth->configuration.hw_addr,
+                   &bcast_addr, 
+		   sizeof(bcast_addr))) {
+		kaweth_err("Firmware not functioning properly, no net device created");
+		kfree(kaweth);
+		return NULL;
+	}
+
+	if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) {
+		kaweth_dbg("Error setting URB size");
+		return kaweth;
+	}
+	
+	if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) {
+		kaweth_err("Error setting SOFS wait");
+		return kaweth;
+	}
+
+	result = kaweth_set_receive_filter(kaweth, 
+                                           KAWETH_PACKET_FILTER_DIRECTED |
+                                           KAWETH_PACKET_FILTER_BROADCAST |
+                                           KAWETH_PACKET_FILTER_MULTICAST);
+
+	if(result < 0) {
+		kaweth_err("Error setting receive filter");
+		return kaweth;
+	}
+	
+	kaweth_dbg("Initializing net device.");
+
+	kaweth->tx_urb = usb_alloc_urb(0);
+	kaweth->rx_urb = usb_alloc_urb(0);
+
+	kaweth->net = init_etherdev(0, 0);
+
+	memcpy(kaweth->net->broadcast, &bcast_addr, sizeof(bcast_addr));
+	memcpy(kaweth->net->dev_addr, 
+               &kaweth->configuration.hw_addr,
+               sizeof(kaweth->configuration.hw_addr));
+	 
+	kaweth->net->priv = kaweth;
+	kaweth->net->open = kaweth_open;
+	kaweth->net->stop = kaweth_close;
+
+	kaweth->net->watchdog_timeo = KAWETH_TX_TIMEOUT;
+	kaweth->net->tx_timeout = kaweth_tx_timeout;
+	
+	kaweth->net->do_ioctl = kaweth_ioctl;
+	kaweth->net->hard_start_xmit = kaweth_start_xmit;
+	kaweth->net->set_multicast_list = kaweth_set_rx_mode;
+	kaweth->net->get_stats = kaweth_netdev_stats;
+	kaweth->net->mtu = kaweth->configuration.segment_size;
+
+	memset(&kaweth->stats, 0, sizeof(kaweth->stats));
+
+	kaweth_info("kaweth interface created at %s", kaweth->net->name);
+								
+	kaweth_dbg("Kaweth probe returning.");
+
+	return kaweth;
+}
+
+/****************************************************************
+ *     kaweth_disconnect
+ ****************************************************************/
+static void kaweth_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct kaweth_device *kaweth = ptr;
+
+	kaweth_info("Unregistering");
+
+	if (!kaweth) {
+		kaweth_warn("unregistering non-existant device");
+		return;
+	}
+
+	if(kaweth->net) {
+		if(kaweth->net->flags & IFF_UP) {
+			kaweth_dbg("Closing net device");
+			dev_close(kaweth->net);
+		}
+
+		kaweth_dbg("Unregistering net device");
+		unregister_netdev(kaweth->net);
+	}
+
+	usb_free_urb(kaweth->rx_urb);
+	usb_free_urb(kaweth->tx_urb);
+
+	kfree(kaweth);
+}
+
+
+/*-------------------------------------------------------------------*
+ * completion handler for compatibility wrappers (sync control/bulk) *
+ *-------------------------------------------------------------------*/
+static void usb_api_blocking_completion(urb_t *urb)
+{
+        api_wrapper_data *awd = (api_wrapper_data *)urb->context;
+
+        if (waitqueue_active(awd->wakeup)) {
+                wake_up(awd->wakeup);
+	}
+
+}
+
+/*-------------------------------------------------------------------*
+ *                         COMPATIBILITY STUFF                       *
+ *-------------------------------------------------------------------*/
+
+// Starts urb and waits for completion or timeout
+static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
+{
+        DECLARE_WAITQUEUE(wait, current);
+        DECLARE_WAIT_QUEUE_HEAD(wqh);
+        api_wrapper_data awd;
+        int status;
+
+        awd.wakeup = &wqh;
+        init_waitqueue_head(&wqh);
+        current->state = TASK_INTERRUPTIBLE;
+        add_wait_queue(&wqh, &wait);
+        urb->context = &awd;
+        status = usb_submit_urb(urb);
+        if (status) {
+                // something went wrong
+                usb_free_urb(urb);
+                current->state = TASK_RUNNING;
+                remove_wait_queue(&wqh, &wait);
+                return status;
+        }
+
+        if (urb->status == -EINPROGRESS) {
+                while (timeout && urb->status == -EINPROGRESS)
+                        status = timeout = schedule_timeout(timeout);
+        } 
+	else {
+                status = 1;
+	}
+
+        current->state = TASK_RUNNING;
+        remove_wait_queue(&wqh, &wait);
+
+        if (!status) {
+                // timeout
+                kaweth_warn("usb_control/bulk_msg: timeout");
+                usb_unlink_urb(urb);  // remove urb safely
+                status = -ETIMEDOUT;
+        }
+	else {
+                status = urb->status;
+	}
+
+        if (actual_length) {
+                *actual_length = urb->actual_length;
+	}
+
+        usb_free_urb(urb);
+        return status;
+}
+
+/*-------------------------------------------------------------------*/
+// returns status (negative) or length (positive)
+int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
+                            devrequest *cmd,  void *data, int len, int timeout)
+{
+        urb_t *urb;
+        int retv;
+        int length;
+
+        urb = usb_alloc_urb(0);
+        if (!urb)
+                return -ENOMEM;
+
+        FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data,
+			 len, (usb_complete_t)usb_api_blocking_completion,0);
+
+        retv = usb_start_wait_urb(urb, timeout, &length);
+        if (retv < 0) {
+                return retv;
+	}
+        else {
+                return length;
+	}
+}
+
+
+/****************************************************************
+ *     kaweth_init
+ ****************************************************************/
+int __init kaweth_init(void)
+{
+	kaweth_dbg("Driver loading");
+	return usb_register(&kaweth_driver);
+}
+
+/****************************************************************
+ *     kaweth_exit
+ ****************************************************************/
+void __exit kaweth_exit(void)
+{
+	usb_deregister(&kaweth_driver);
+}
+
+module_init(kaweth_init);
+module_exit(kaweth_exit);
+
diff -urN linux-2.4.9-pre1/drivers/usb/kawethfw.h linux/drivers/usb/kawethfw.h
--- linux-2.4.9-pre1/drivers/usb/kawethfw.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/kawethfw.h	Mon Dec  3 23:01:22 2001
@@ -0,0 +1,557 @@
+/******************************************/
+/* NOTE: B6/C3 is data header signature   */
+/*       0xAA/0xBB is data length = total */
+/*       bytes - 7, 0xCC is type, 0xDD is */
+/*       interrupt to use.                */
+/******************************************/
+
+/****************************************************************
+ *     kaweth_trigger_code
+ ****************************************************************/
+static __u8 kaweth_trigger_code[] = 
+{
+    0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD,
+    0xc8, 0x07, 0xa0, 0x00, 0xf0, 0x07, 0x5e, 0x00,
+    0x06, 0x00, 0xf0, 0x07, 0x0a, 0x00, 0x08, 0x00,
+    0xf0, 0x09, 0x00, 0x00, 0x02, 0x00, 0xe7, 0x07,
+    0x36, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00,
+    0x04, 0x00, 0xe7, 0x07, 0x50, 0xc3, 0x10, 0xc0,
+    0xf0, 0x09, 0x0e, 0xc0, 0x00, 0x00, 0xe7, 0x87,
+    0x01, 0x00, 0x0e, 0xc0, 0x97, 0xcf, 0xd7, 0x09,
+    0x00, 0xc0, 0x17, 0x02, 0xc8, 0x07, 0xa0, 0x00,
+    0xe7, 0x17, 0x50, 0xc3, 0x10, 0xc0, 0x30, 0xd8,
+    0x04, 0x00, 0x30, 0x5c, 0x08, 0x00, 0x04, 0x00,
+    0xb0, 0xc0, 0x06, 0x00, 0xc8, 0x05, 0xe7, 0x05,
+    0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, 0x49, 0xaf,
+    0xc0, 0x07, 0x00, 0x00, 0x60, 0xaf, 0x4a, 0xaf,
+    0x00, 0x0c, 0x0c, 0x00, 0x40, 0xd2, 0x00, 0x1c,
+    0x0c, 0x00, 0x40, 0xd2, 0x30, 0x00, 0x08, 0x00,
+    0xf0, 0x07, 0x00, 0x00, 0x04, 0x00, 0xf0, 0x07,
+    0x86, 0x00, 0x06, 0x00, 0x67, 0xcf, 0x27, 0x0c,
+    0x02, 0x00, 0x00, 0x00, 0x27, 0x0c, 0x00, 0x00,
+    0x0e, 0xc0, 0x49, 0xaf, 0x64, 0xaf, 0xc0, 0x07,
+    0x00, 0x00, 0x4b, 0xaf, 0x4a, 0xaf, 0x5a, 0xcf,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x94, 0x00, 0x05, 0x00,
+    0x00, 0x00
+};
+/****************************************************************
+ *     kaweth_trigger_code_fix
+ ****************************************************************/
+static __u8 kaweth_trigger_code_fix[] = 
+{
+    0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD,
+    0x02, 0x00, 0x06, 0x00, 0x18, 0x00, 0x3e, 0x00,
+    0x80, 0x00, 0x98, 0x00, 0xaa, 0x00,
+    0x00, 0x00
+};
+
+/****************************************************************
+ *     kaweth_new_code
+ ****************************************************************/
+static __u8 kaweth_new_code[] = 
+{
+    0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD,
+    0x9f, 0xcf, 0xde, 0x06, 0xe7, 0x57, 0x00, 0x00,
+    0xc4, 0x06, 0x97, 0xc1, 0xe7, 0x67, 0xff, 0x1f,
+    0x28, 0xc0, 0xe7, 0x87, 0x00, 0x04, 0x24, 0xc0,
+    0xe7, 0x67, 0xff, 0xf9, 0x22, 0xc0, 0x97, 0xcf,
+    0xd7, 0x09, 0x00, 0xc0, 0xe7, 0x09, 0xa2, 0xc0,
+    0xbe, 0x06, 0x9f, 0xaf, 0x36, 0x00, 0xe7, 0x05,
+    0x00, 0xc0, 0xa7, 0xcf, 0xbc, 0x06, 0x97, 0xcf,
+    0xe7, 0x57, 0x00, 0x00, 0xb8, 0x06, 0xa7, 0xa1,
+    0xb8, 0x06, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00,
+    0x14, 0x08, 0x0a, 0xc0, 0xe7, 0x57, 0x00, 0x00,
+    0xa4, 0xc0, 0xa7, 0xc0, 0x7a, 0x06, 0x9f, 0xaf,
+    0x92, 0x07, 0xe7, 0x07, 0x00, 0x00, 0x14, 0x08,
+    0xe7, 0x57, 0xff, 0xff, 0xba, 0x06, 0x9f, 0xa0,
+    0x38, 0x00, 0xe7, 0x59, 0xba, 0x06, 0xbe, 0x06,
+    0x9f, 0xa0, 0x38, 0x00, 0xc8, 0x09, 0xca, 0x06,
+    0x08, 0x62, 0x9f, 0xa1, 0x36, 0x08, 0xc0, 0x09,
+    0x76, 0x06, 0x00, 0x60, 0xa7, 0xc0, 0x7a, 0x06,
+    0x9f, 0xaf, 0xcc, 0x02, 0xe7, 0x57, 0x00, 0x00,
+    0xb8, 0x06, 0xa7, 0xc1, 0x7a, 0x06, 0x9f, 0xaf,
+    0x04, 0x00, 0xe7, 0x57, 0x00, 0x00, 0x8e, 0x06,
+    0x0a, 0xc1, 0xe7, 0x09, 0x20, 0xc0, 0x10, 0x08,
+    0xe7, 0xd0, 0x10, 0x08, 0xe7, 0x67, 0x40, 0x00,
+    0x10, 0x08, 0x9f, 0xaf, 0x92, 0x0c, 0xc0, 0x09,
+    0xd0, 0x06, 0x00, 0x60, 0x05, 0xc4, 0xc0, 0x59,
+    0xbe, 0x06, 0x02, 0xc0, 0x9f, 0xaf, 0xec, 0x00,
+    0x9f, 0xaf, 0x34, 0x02, 0xe7, 0x57, 0x00, 0x00,
+    0xa6, 0x06, 0x9f, 0xa0, 0x7a, 0x02, 0xa7, 0xcf,
+    0x7a, 0x06, 0x48, 0x02, 0xe7, 0x09, 0xbe, 0x06,
+    0xd0, 0x06, 0xc8, 0x37, 0x04, 0x00, 0x9f, 0xaf,
+    0x08, 0x03, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00,
+    0xce, 0x06, 0x97, 0xc0, 0xd7, 0x09, 0x00, 0xc0,
+    0xc1, 0xdf, 0xc8, 0x09, 0xc6, 0x06, 0x08, 0x62,
+    0x14, 0xc0, 0x27, 0x04, 0xc6, 0x06, 0x10, 0x94,
+    0xf0, 0x07, 0x10, 0x08, 0x02, 0x00, 0xc1, 0x07,
+    0x01, 0x00, 0x70, 0x00, 0x04, 0x00, 0xf0, 0x07,
+    0x30, 0x01, 0x06, 0x00, 0x50, 0xaf, 0xe7, 0x07,
+    0xff, 0xff, 0xd0, 0x06, 0xe7, 0x07, 0x00, 0x00,
+    0xce, 0x06, 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf,
+    0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x48, 0x02,
+    0xd0, 0x09, 0xc6, 0x06, 0x27, 0x02, 0xc6, 0x06,
+    0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, 0x48, 0x02,
+    0xc8, 0x37, 0x04, 0x00, 0x00, 0x0c, 0x0c, 0x00,
+    0x00, 0x60, 0x21, 0xc0, 0xc0, 0x37, 0x3e, 0x00,
+    0x23, 0xc9, 0xc0, 0x57, 0xb4, 0x05, 0x1b, 0xc8,
+    0xc0, 0x17, 0x3f, 0x00, 0xc0, 0x67, 0xc0, 0xff,
+    0x30, 0x00, 0x08, 0x00, 0xf0, 0x07, 0x00, 0x00,
+    0x04, 0x00, 0x00, 0x02, 0xc0, 0x17, 0x4c, 0x00,
+    0x30, 0x00, 0x06, 0x00, 0xf0, 0x07, 0xa0, 0x01,
+    0x0a, 0x00, 0x48, 0x02, 0xc1, 0x07, 0x02, 0x00,
+    0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x51, 0xaf,
+    0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, 0x9f, 0xaf,
+    0x08, 0x03, 0x9f, 0xaf, 0x7a, 0x02, 0x97, 0xcf,
+    0x9f, 0xaf, 0x7a, 0x02, 0xc9, 0x37, 0x04, 0x00,
+    0xc1, 0xdf, 0xc8, 0x09, 0xa2, 0x06, 0x50, 0x02,
+    0x67, 0x02, 0xa2, 0x06, 0xd1, 0x07, 0x00, 0x00,
+    0x27, 0xd8, 0xaa, 0x06, 0xc0, 0xdf, 0x9f, 0xaf,
+    0xc4, 0x01, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00,
+    0xd2, 0x06, 0x97, 0xc1, 0xe7, 0x57, 0x01, 0x00,
+    0xa8, 0x06, 0x97, 0xc0, 0xc8, 0x09, 0xa0, 0x06,
+    0x08, 0x62, 0x97, 0xc0, 0x00, 0x02, 0xc0, 0x17,
+    0x0e, 0x00, 0x27, 0x00, 0x34, 0x01, 0x27, 0x0c,
+    0x0c, 0x00, 0x36, 0x01, 0xe7, 0x07, 0x50, 0xc3,
+    0x12, 0xc0, 0xe7, 0x07, 0xcc, 0x0b, 0x02, 0x00,
+    0xe7, 0x07, 0x01, 0x00, 0xa8, 0x06, 0xe7, 0x07,
+    0x05, 0x00, 0x90, 0xc0, 0x97, 0xcf, 0xc8, 0x09,
+    0xa4, 0x06, 0x08, 0x62, 0x02, 0xc0, 0x10, 0x64,
+    0x07, 0xc1, 0xe7, 0x07, 0x00, 0x00, 0x9e, 0x06,
+    0xe7, 0x07, 0x72, 0x04, 0x24, 0x00, 0x97, 0xcf,
+    0x27, 0x04, 0xa4, 0x06, 0xc8, 0x17, 0x0e, 0x00,
+    0x27, 0x02, 0x9e, 0x06, 0xe7, 0x07, 0x80, 0x04,
+    0x24, 0x00, 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0,
+    0xc1, 0xdf, 0xe7, 0x57, 0x00, 0x00, 0x90, 0x06,
+    0x13, 0xc1, 0x9f, 0xaf, 0x06, 0x02, 0xe7, 0x57,
+    0x00, 0x00, 0x9e, 0x06, 0x13, 0xc0, 0xe7, 0x09,
+    0x9e, 0x06, 0x30, 0x01, 0xe7, 0x07, 0xf2, 0x05,
+    0x32, 0x01, 0xe7, 0x07, 0x10, 0x00, 0x96, 0xc0,
+    0xe7, 0x09, 0x9e, 0x06, 0x90, 0x06, 0x04, 0xcf,
+    0xe7, 0x57, 0x00, 0x00, 0x9e, 0x06, 0x02, 0xc1,
+    0x9f, 0xaf, 0x06, 0x02, 0xe7, 0x05, 0x00, 0xc0,
+    0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf,
+    0x08, 0x92, 0xe7, 0x57, 0x02, 0x00, 0xaa, 0x06,
+    0x02, 0xc3, 0xc8, 0x09, 0xa4, 0x06, 0x27, 0x02,
+    0xa6, 0x06, 0x08, 0x62, 0x03, 0xc1, 0xe7, 0x05,
+    0x00, 0xc0, 0x97, 0xcf, 0x27, 0x04, 0xa4, 0x06,
+    0xe7, 0x05, 0x00, 0xc0, 0xf0, 0x07, 0x40, 0x00,
+    0x08, 0x00, 0xf0, 0x07, 0x00, 0x00, 0x04, 0x00,
+    0x00, 0x02, 0xc0, 0x17, 0x0c, 0x00, 0x30, 0x00,
+    0x06, 0x00, 0xf0, 0x07, 0x46, 0x01, 0x0a, 0x00,
+    0xc8, 0x17, 0x04, 0x00, 0xc1, 0x07, 0x02, 0x00,
+    0x51, 0xaf, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00,
+    0x96, 0x06, 0x97, 0xc0, 0xc1, 0xdf, 0xc8, 0x09,
+    0x96, 0x06, 0x27, 0x04, 0x96, 0x06, 0x27, 0x52,
+    0x98, 0x06, 0x03, 0xc1, 0xe7, 0x07, 0x96, 0x06,
+    0x98, 0x06, 0xc0, 0xdf, 0x17, 0x02, 0xc8, 0x17,
+    0x0e, 0x00, 0x9f, 0xaf, 0xba, 0x03, 0xc8, 0x05,
+    0x00, 0x60, 0x03, 0xc0, 0x9f, 0xaf, 0x24, 0x03,
+    0x97, 0xcf, 0x9f, 0xaf, 0x08, 0x03, 0x97, 0xcf,
+    0x57, 0x02, 0xc9, 0x07, 0xa4, 0x06, 0xd7, 0x09,
+    0x00, 0xc0, 0xc1, 0xdf, 0x08, 0x62, 0x1b, 0xc0,
+    0x50, 0x04, 0x11, 0x02, 0xe7, 0x05, 0x00, 0xc0,
+    0xc9, 0x05, 0x97, 0xcf, 0x97, 0x02, 0xca, 0x09,
+    0xd6, 0x06, 0xf2, 0x17, 0x01, 0x00, 0x04, 0x00,
+    0xf2, 0x27, 0x00, 0x00, 0x06, 0x00, 0xca, 0x17,
+    0x2c, 0x00, 0xf8, 0x77, 0x01, 0x00, 0x0e, 0x00,
+    0x06, 0xc0, 0xca, 0xd9, 0xf8, 0x57, 0xff, 0x00,
+    0x0e, 0x00, 0x01, 0xc1, 0xca, 0xd9, 0x22, 0x1c,
+    0x0c, 0x00, 0xe2, 0x27, 0x00, 0x00, 0xe2, 0x17,
+    0x01, 0x00, 0xe2, 0x27, 0x00, 0x00, 0xca, 0x05,
+    0x00, 0x0c, 0x0c, 0x00, 0xc0, 0x17, 0x41, 0x00,
+    0xc0, 0x67, 0xc0, 0xff, 0x30, 0x00, 0x08, 0x00,
+    0x00, 0x02, 0xc0, 0x17, 0x0c, 0x00, 0x30, 0x00,
+    0x06, 0x00, 0xf0, 0x07, 0xda, 0x00, 0x0a, 0x00,
+    0xf0, 0x07, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0c,
+    0x08, 0x00, 0x40, 0xd1, 0x01, 0x00, 0xc0, 0x19,
+    0xce, 0x06, 0xc0, 0x59, 0xc2, 0x06, 0x04, 0xc9,
+    0x49, 0xaf, 0x9f, 0xaf, 0xec, 0x00, 0x4a, 0xaf,
+    0x67, 0x10, 0xce, 0x06, 0xc8, 0x17, 0x04, 0x00,
+    0xc1, 0x07, 0x01, 0x00, 0xd7, 0x09, 0x00, 0xc0,
+    0xc1, 0xdf, 0x50, 0xaf, 0xe7, 0x05, 0x00, 0xc0,
+    0x97, 0xcf, 0xc0, 0x07, 0x01, 0x00, 0xc1, 0x09,
+    0xac, 0x06, 0xc1, 0x77, 0x01, 0x00, 0x97, 0xc1,
+    0xd8, 0x77, 0x01, 0x00, 0x12, 0xc0, 0xc9, 0x07,
+    0x6a, 0x06, 0x9f, 0xaf, 0x08, 0x04, 0x04, 0xc1,
+    0xc1, 0x77, 0x08, 0x00, 0x13, 0xc0, 0x97, 0xcf,
+    0xc1, 0x77, 0x02, 0x00, 0x97, 0xc1, 0xc1, 0x77,
+    0x10, 0x00, 0x0c, 0xc0, 0x9f, 0xaf, 0x2c, 0x04,
+    0x97, 0xcf, 0xc1, 0x77, 0x04, 0x00, 0x06, 0xc0,
+    0xc9, 0x07, 0x70, 0x06, 0x9f, 0xaf, 0x08, 0x04,
+    0x97, 0xc0, 0x00, 0xcf, 0x00, 0x90, 0x97, 0xcf,
+    0x50, 0x54, 0x97, 0xc1, 0x70, 0x5c, 0x02, 0x00,
+    0x02, 0x00, 0x97, 0xc1, 0x70, 0x5c, 0x04, 0x00,
+    0x04, 0x00, 0x97, 0xcf, 0x80, 0x01, 0xc0, 0x00,
+    0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0c, 0x00,
+    0x06, 0x00, 0x00, 0x00, 0xcb, 0x09, 0xb2, 0x06,
+    0xcc, 0x09, 0xb4, 0x06, 0x0b, 0x53, 0x11, 0xc0,
+    0xc9, 0x02, 0xca, 0x07, 0x1c, 0x04, 0x9f, 0xaf,
+    0x08, 0x04, 0x97, 0xc0, 0x0a, 0xc8, 0x82, 0x08,
+    0x0a, 0xcf, 0x82, 0x08, 0x9f, 0xaf, 0x08, 0x04,
+    0x97, 0xc0, 0x05, 0xc2, 0x89, 0x30, 0x82, 0x60,
+    0x78, 0xc1, 0x00, 0x90, 0x97, 0xcf, 0x89, 0x10,
+    0x09, 0x53, 0x79, 0xc2, 0x89, 0x30, 0x82, 0x08,
+    0x7a, 0xcf, 0xc0, 0xdf, 0x97, 0xcf, 0xc0, 0xdf,
+    0x97, 0xcf, 0xe7, 0x09, 0x96, 0xc0, 0x92, 0x06,
+    0xe7, 0x09, 0x98, 0xc0, 0x94, 0x06, 0x0f, 0xcf,
+    0xe7, 0x09, 0x96, 0xc0, 0x92, 0x06, 0xe7, 0x09,
+    0x98, 0xc0, 0x94, 0x06, 0xe7, 0x09, 0x9e, 0x06,
+    0x30, 0x01, 0xe7, 0x07, 0xf2, 0x05, 0x32, 0x01,
+    0xe7, 0x07, 0x10, 0x00, 0x96, 0xc0, 0xd7, 0x09,
+    0x00, 0xc0, 0x17, 0x02, 0xc8, 0x09, 0x90, 0x06,
+    0xc8, 0x37, 0x0e, 0x00, 0xe7, 0x77, 0x2a, 0x00,
+    0x92, 0x06, 0x30, 0xc0, 0x97, 0x02, 0xca, 0x09,
+    0xd6, 0x06, 0xe7, 0x77, 0x20, 0x00, 0x92, 0x06,
+    0x0e, 0xc0, 0xf2, 0x17, 0x01, 0x00, 0x10, 0x00,
+    0xf2, 0x27, 0x00, 0x00, 0x12, 0x00, 0xe7, 0x77,
+    0x0a, 0x00, 0x92, 0x06, 0xca, 0x05, 0x1e, 0xc0,
+    0x97, 0x02, 0xca, 0x09, 0xd6, 0x06, 0xf2, 0x17,
+    0x01, 0x00, 0x0c, 0x00, 0xf2, 0x27, 0x00, 0x00,
+    0x0e, 0x00, 0xe7, 0x77, 0x02, 0x00, 0x92, 0x06,
+    0x07, 0xc0, 0xf2, 0x17, 0x01, 0x00, 0x44, 0x00,
+    0xf2, 0x27, 0x00, 0x00, 0x46, 0x00, 0x06, 0xcf,
+    0xf2, 0x17, 0x01, 0x00, 0x60, 0x00, 0xf2, 0x27,
+    0x00, 0x00, 0x62, 0x00, 0xca, 0x05, 0x9f, 0xaf,
+    0x08, 0x03, 0x0f, 0xcf, 0x57, 0x02, 0x09, 0x02,
+    0xf1, 0x09, 0x94, 0x06, 0x0c, 0x00, 0xf1, 0xda,
+    0x0c, 0x00, 0xc8, 0x09, 0x98, 0x06, 0x50, 0x02,
+    0x67, 0x02, 0x98, 0x06, 0xd1, 0x07, 0x00, 0x00,
+    0xc9, 0x05, 0xe7, 0x09, 0x9e, 0x06, 0x90, 0x06,
+    0xe7, 0x57, 0x00, 0x00, 0x90, 0x06, 0x02, 0xc0,
+    0x9f, 0xaf, 0x06, 0x02, 0xc8, 0x05, 0xe7, 0x05,
+    0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, 0xd7, 0x09,
+    0x00, 0xc0, 0x17, 0x00, 0x17, 0x02, 0x97, 0x02,
+    0xc0, 0x09, 0x92, 0xc0, 0xe7, 0x07, 0x04, 0x00,
+    0x90, 0xc0, 0xca, 0x09, 0xd6, 0x06, 0xe7, 0x07,
+    0x00, 0x00, 0xa8, 0x06, 0xe7, 0x07, 0x6a, 0x04,
+    0x02, 0x00, 0xc0, 0x77, 0x02, 0x00, 0x08, 0xc0,
+    0xf2, 0x17, 0x01, 0x00, 0x50, 0x00, 0xf2, 0x27,
+    0x00, 0x00, 0x52, 0x00, 0x9f, 0xcf, 0x24, 0x06,
+    0xc0, 0x77, 0x10, 0x00, 0x06, 0xc0, 0xf2, 0x17,
+    0x01, 0x00, 0x58, 0x00, 0xf2, 0x27, 0x00, 0x00,
+    0x5a, 0x00, 0xc0, 0x77, 0x80, 0x00, 0x06, 0xc0,
+    0xf2, 0x17, 0x01, 0x00, 0x70, 0x00, 0xf2, 0x27,
+    0x00, 0x00, 0x72, 0x00, 0xc0, 0x77, 0x08, 0x00,
+    0x1d, 0xc1, 0xf2, 0x17, 0x01, 0x00, 0x08, 0x00,
+    0xf2, 0x27, 0x00, 0x00, 0x0a, 0x00, 0xc0, 0x77,
+    0x00, 0x02, 0x06, 0xc0, 0xf2, 0x17, 0x01, 0x00,
+    0x64, 0x00, 0xf2, 0x27, 0x00, 0x00, 0x66, 0x00,
+    0xc0, 0x77, 0x40, 0x00, 0x06, 0xc0, 0xf2, 0x17,
+    0x01, 0x00, 0x5c, 0x00, 0xf2, 0x27, 0x00, 0x00,
+    0x5e, 0x00, 0xc0, 0x77, 0x01, 0x00, 0x01, 0xc0,
+    0x1b, 0xcf, 0x1a, 0xcf, 0xf2, 0x17, 0x01, 0x00,
+    0x00, 0x00, 0xf2, 0x27, 0x00, 0x00, 0x02, 0x00,
+    0xc8, 0x09, 0x34, 0x01, 0xca, 0x17, 0x14, 0x00,
+    0xd8, 0x77, 0x01, 0x00, 0x05, 0xc0, 0xca, 0xd9,
+    0xd8, 0x57, 0xff, 0x00, 0x01, 0xc0, 0xca, 0xd9,
+    0xe2, 0x19, 0x94, 0xc0, 0xe2, 0x27, 0x00, 0x00,
+    0xe2, 0x17, 0x01, 0x00, 0xe2, 0x27, 0x00, 0x00,
+    0x9f, 0xaf, 0x40, 0x06, 0x9f, 0xaf, 0xc4, 0x01,
+    0xe7, 0x57, 0x00, 0x00, 0xd2, 0x06, 0x9f, 0xa1,
+    0x0e, 0x0a, 0xca, 0x05, 0xc8, 0x05, 0xc0, 0x05,
+    0xe7, 0x05, 0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf,
+    0xc8, 0x09, 0xa0, 0x06, 0x08, 0x62, 0x97, 0xc0,
+    0x27, 0x04, 0xa0, 0x06, 0x27, 0x52, 0xa2, 0x06,
+    0x03, 0xc1, 0xe7, 0x07, 0xa0, 0x06, 0xa2, 0x06,
+    0x9f, 0xaf, 0x08, 0x03, 0xe7, 0x57, 0x00, 0x00,
+    0xaa, 0x06, 0x02, 0xc0, 0x27, 0xda, 0xaa, 0x06,
+    0x97, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xff, 0xff, 0xfb, 0x13, 0xe7, 0x57,
+    0x00, 0x80, 0xb2, 0x00, 0x06, 0xc2, 0xe7, 0x07,
+    0xee, 0x0b, 0x12, 0x00, 0xe7, 0x07, 0x34, 0x0c,
+    0xb2, 0x00, 0xe7, 0x07, 0xc6, 0x07, 0xf2, 0x02,
+    0xc8, 0x09, 0xb4, 0x00, 0xf8, 0x07, 0x02, 0x00,
+    0x0d, 0x00, 0xd7, 0x09, 0x0e, 0xc0, 0xe7, 0x07,
+    0x00, 0x00, 0x0e, 0xc0, 0xc8, 0x09, 0xde, 0x00,
+    0xc8, 0x17, 0x09, 0x00, 0xc9, 0x07, 0xda, 0x06,
+    0xc0, 0x07, 0x04, 0x00, 0x68, 0x0a, 0x00, 0xda,
+    0x7d, 0xc1, 0xe7, 0x09, 0xc0, 0x00, 0x7c, 0x06,
+    0xe7, 0x09, 0xbe, 0x00, 0x78, 0x06, 0xe7, 0x09,
+    0x10, 0x00, 0xbc, 0x06, 0xc8, 0x07, 0xd6, 0x07,
+    0x9f, 0xaf, 0xae, 0x07, 0x9f, 0xaf, 0x00, 0x0a,
+    0xc8, 0x09, 0xde, 0x00, 0x00, 0x0e, 0x0f, 0x00,
+    0x41, 0x90, 0x9f, 0xde, 0x06, 0x00, 0x44, 0xaf,
+    0x27, 0x00, 0xb2, 0x06, 0x27, 0x00, 0xb4, 0x06,
+    0x27, 0x00, 0xb6, 0x06, 0xc0, 0x07, 0x74, 0x00,
+    0x44, 0xaf, 0x27, 0x00, 0xd6, 0x06, 0x08, 0x00,
+    0x00, 0x90, 0xc1, 0x07, 0x3a, 0x00, 0x20, 0x00,
+    0x01, 0xda, 0x7d, 0xc1, 0x9f, 0xaf, 0xba, 0x09,
+    0xc0, 0x07, 0x44, 0x00, 0x48, 0xaf, 0x27, 0x00,
+    0x7a, 0x06, 0x9f, 0xaf, 0x96, 0x0a, 0xe7, 0x07,
+    0x01, 0x00, 0xc0, 0x06, 0xe7, 0x05, 0x0e, 0xc0,
+    0x97, 0xcf, 0x49, 0xaf, 0xe7, 0x87, 0x43, 0x00,
+    0x0e, 0xc0, 0xe7, 0x07, 0xff, 0xff, 0xbe, 0x06,
+    0x9f, 0xaf, 0xae, 0x0a, 0xc0, 0x07, 0x01, 0x00,
+    0x60, 0xaf, 0x4a, 0xaf, 0x97, 0xcf, 0x00, 0x08,
+    0x09, 0x08, 0x11, 0x08, 0x00, 0xda, 0x7c, 0xc1,
+    0x97, 0xcf, 0x67, 0x04, 0xcc, 0x02, 0xc0, 0xdf,
+    0x51, 0x94, 0xb1, 0xaf, 0x06, 0x00, 0xc1, 0xdf,
+    0xc9, 0x09, 0xcc, 0x02, 0x49, 0x62, 0x75, 0xc1,
+    0xc0, 0xdf, 0xa7, 0xcf, 0xd6, 0x02, 0x0e, 0x00,
+    0x24, 0x00, 0x80, 0x04, 0x22, 0x00, 0x4e, 0x05,
+    0xd0, 0x00, 0x0e, 0x0a, 0xaa, 0x00, 0x30, 0x08,
+    0xbe, 0x00, 0x4a, 0x0a, 0x10, 0x00, 0x20, 0x00,
+    0x04, 0x00, 0x6e, 0x04, 0x02, 0x00, 0x6a, 0x04,
+    0x06, 0x00, 0x00, 0x00, 0x24, 0xc0, 0x04, 0x04,
+    0x28, 0xc0, 0xfe, 0xfb, 0x1e, 0xc0, 0x00, 0x04,
+    0x22, 0xc0, 0xff, 0xf4, 0xc0, 0x00, 0x90, 0x09,
+    0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x56, 0x08,
+    0x60, 0x08, 0xd0, 0x08, 0xda, 0x08, 0x00, 0x09,
+    0x04, 0x09, 0x08, 0x09, 0x32, 0x09, 0x42, 0x09,
+    0x50, 0x09, 0x52, 0x09, 0x5a, 0x09, 0x5a, 0x09,
+    0x27, 0x02, 0xca, 0x06, 0x97, 0xcf, 0xe7, 0x07,
+    0x00, 0x00, 0xca, 0x06, 0x0a, 0x0e, 0x01, 0x00,
+    0xca, 0x57, 0x0e, 0x00, 0x9f, 0xc3, 0x5a, 0x09,
+    0xca, 0x37, 0x00, 0x00, 0x9f, 0xc2, 0x5a, 0x09,
+    0x0a, 0xd2, 0xb2, 0xcf, 0x16, 0x08, 0xc8, 0x09,
+    0xde, 0x00, 0x07, 0x06, 0x9f, 0xcf, 0x6c, 0x09,
+    0x17, 0x02, 0xc8, 0x09, 0xde, 0x00, 0x00, 0x0e,
+    0x0f, 0x00, 0x41, 0x90, 0x9f, 0xde, 0x06, 0x00,
+    0xc8, 0x05, 0x30, 0x50, 0x06, 0x00, 0x9f, 0xc8,
+    0x5a, 0x09, 0x27, 0x0c, 0x02, 0x00, 0xb0, 0x06,
+    0xc0, 0x09, 0xb2, 0x06, 0x27, 0x00, 0xb4, 0x06,
+    0xe7, 0x07, 0x00, 0x00, 0xae, 0x06, 0x27, 0x00,
+    0x80, 0x06, 0x00, 0x1c, 0x06, 0x00, 0x27, 0x00,
+    0xb6, 0x06, 0x41, 0x90, 0x67, 0x50, 0xb0, 0x06,
+    0x0d, 0xc0, 0x67, 0x00, 0x7e, 0x06, 0x27, 0x0c,
+    0x06, 0x00, 0x82, 0x06, 0xe7, 0x07, 0xbc, 0x08,
+    0x84, 0x06, 0xc8, 0x07, 0x7e, 0x06, 0x41, 0x90,
+    0x51, 0xaf, 0x97, 0xcf, 0x9f, 0xaf, 0x48, 0x0c,
+    0xe7, 0x09, 0xb6, 0x06, 0xb4, 0x06, 0xe7, 0x09,
+    0xb0, 0x06, 0xae, 0x06, 0x59, 0xaf, 0x97, 0xcf,
+    0x27, 0x0c, 0x02, 0x00, 0xac, 0x06, 0x59, 0xaf,
+    0x97, 0xcf, 0x09, 0x0c, 0x02, 0x00, 0x09, 0xda,
+    0x49, 0xd2, 0xc9, 0x19, 0xd6, 0x06, 0xc8, 0x07,
+    0x7e, 0x06, 0xe0, 0x07, 0x00, 0x00, 0x60, 0x02,
+    0xe0, 0x07, 0x04, 0x00, 0xd0, 0x07, 0xcc, 0x08,
+    0x48, 0xdb, 0x41, 0x90, 0x50, 0xaf, 0x97, 0xcf,
+    0x59, 0xaf, 0x97, 0xcf, 0x59, 0xaf, 0x97, 0xcf,
+    0xf0, 0x57, 0x06, 0x00, 0x06, 0x00, 0x25, 0xc1,
+    0xe7, 0x07, 0x70, 0x06, 0x80, 0x06, 0x41, 0x90,
+    0x67, 0x00, 0x7e, 0x06, 0x27, 0x0c, 0x06, 0x00,
+    0x82, 0x06, 0xe7, 0x07, 0x8c, 0x09, 0x84, 0x06,
+    0xc8, 0x07, 0x7e, 0x06, 0x41, 0x90, 0x51, 0xaf,
+    0x97, 0xcf, 0x07, 0x0c, 0x06, 0x00, 0xc7, 0x57,
+    0x06, 0x00, 0x0f, 0xc1, 0xc8, 0x07, 0x70, 0x06,
+    0x15, 0xcf, 0x00, 0x0c, 0x02, 0x00, 0x00, 0xda,
+    0x40, 0xd1, 0x27, 0x00, 0xc2, 0x06, 0x1e, 0xcf,
+    0x1d, 0xcf, 0x27, 0x0c, 0x02, 0x00, 0xcc, 0x06,
+    0x19, 0xcf, 0x27, 0x02, 0x20, 0x01, 0xe7, 0x07,
+    0x08, 0x00, 0x22, 0x01, 0xe7, 0x07, 0x13, 0x00,
+    0xb0, 0xc0, 0x97, 0xcf, 0x41, 0x90, 0x67, 0x00,
+    0x7e, 0x06, 0xe7, 0x01, 0x82, 0x06, 0x27, 0x02,
+    0x80, 0x06, 0xe7, 0x07, 0x8c, 0x09, 0x84, 0x06,
+    0xc8, 0x07, 0x7e, 0x06, 0xc1, 0x07, 0x00, 0x80,
+    0x50, 0xaf, 0x97, 0xcf, 0x59, 0xaf, 0x97, 0xcf,
+    0x00, 0x60, 0x05, 0xc0, 0xe7, 0x07, 0x00, 0x00,
+    0xc4, 0x06, 0xa7, 0xcf, 0x7c, 0x06, 0x9f, 0xaf,
+    0x00, 0x0a, 0xe7, 0x07, 0x01, 0x00, 0xc4, 0x06,
+    0x49, 0xaf, 0xd7, 0x09, 0x00, 0xc0, 0x07, 0xaf,
+    0xe7, 0x05, 0x00, 0xc0, 0x4a, 0xaf, 0xa7, 0xcf,
+    0x7c, 0x06, 0xc0, 0x07, 0xfe, 0x7f, 0x44, 0xaf,
+    0x40, 0x00, 0xc0, 0x37, 0x00, 0x01, 0x41, 0x90,
+    0xc0, 0x37, 0x08, 0x00, 0xdf, 0xde, 0x50, 0x06,
+    0xc0, 0x57, 0x10, 0x00, 0x02, 0xc2, 0xc0, 0x07,
+    0x10, 0x00, 0x27, 0x00, 0x9a, 0x06, 0x41, 0x90,
+    0x9f, 0xde, 0x40, 0x06, 0x44, 0xaf, 0x27, 0x00,
+    0x9c, 0x06, 0xc0, 0x09, 0x9a, 0x06, 0x41, 0x90,
+    0x00, 0xd2, 0x00, 0xd8, 0x9f, 0xde, 0x08, 0x00,
+    0x44, 0xaf, 0x27, 0x00, 0xc8, 0x06, 0x97, 0xcf,
+    0xe7, 0x87, 0x00, 0x84, 0x28, 0xc0, 0xe7, 0x67,
+    0xff, 0xfb, 0x24, 0xc0, 0x97, 0xcf, 0xe7, 0x87,
+    0x01, 0x00, 0xd2, 0x06, 0xe7, 0x57, 0x00, 0x00,
+    0xa8, 0x06, 0x97, 0xc1, 0x9f, 0xaf, 0x00, 0x0a,
+    0xe7, 0x87, 0x00, 0x06, 0x22, 0xc0, 0xe7, 0x07,
+    0x00, 0x00, 0x90, 0xc0, 0xe7, 0x67, 0xfe, 0xff,
+    0x3e, 0xc0, 0xe7, 0x07, 0x26, 0x00, 0x0a, 0xc0,
+    0xe7, 0x87, 0x01, 0x00, 0x3e, 0xc0, 0xe7, 0x07,
+    0xff, 0xff, 0xbe, 0x06, 0x9f, 0xaf, 0x10, 0x0b,
+    0x97, 0xcf, 0x17, 0x00, 0xa7, 0xaf, 0x78, 0x06,
+    0xc0, 0x05, 0x27, 0x00, 0x76, 0x06, 0xe7, 0x87,
+    0x01, 0x00, 0xd2, 0x06, 0x9f, 0xaf, 0x00, 0x0a,
+    0xe7, 0x07, 0x0c, 0x00, 0x40, 0xc0, 0x9f, 0xaf,
+    0x10, 0x0b, 0x00, 0x90, 0x27, 0x00, 0xa6, 0x06,
+    0x27, 0x00, 0xaa, 0x06, 0xe7, 0x09, 0xb2, 0x06,
+    0xb4, 0x06, 0x27, 0x00, 0xae, 0x06, 0x27, 0x00,
+    0xac, 0x06, 0x9f, 0xaf, 0xae, 0x0a, 0xc0, 0x07,
+    0x00, 0x00, 0x27, 0x00, 0xb2, 0x02, 0x27, 0x00,
+    0xb4, 0x02, 0x27, 0x00, 0x8e, 0x06, 0xc0, 0x07,
+    0x06, 0x00, 0xc8, 0x09, 0xde, 0x00, 0xc8, 0x17,
+    0x03, 0x00, 0xc9, 0x07, 0x70, 0x06, 0x29, 0x0a,
+    0x00, 0xda, 0x7d, 0xc1, 0x97, 0xcf, 0xd7, 0x09,
+    0x00, 0xc0, 0xc1, 0xdf, 0x00, 0x90, 0x27, 0x00,
+    0x96, 0x06, 0xe7, 0x07, 0x96, 0x06, 0x98, 0x06,
+    0x27, 0x00, 0xa0, 0x06, 0xe7, 0x07, 0xa0, 0x06,
+    0xa2, 0x06, 0x27, 0x00, 0xa6, 0x06, 0x27, 0x00,
+    0x90, 0x06, 0x27, 0x00, 0x9e, 0x06, 0xc8, 0x09,
+    0x9c, 0x06, 0xc1, 0x09, 0x9a, 0x06, 0xc9, 0x07,
+    0xa4, 0x06, 0x11, 0x02, 0x09, 0x02, 0xc8, 0x17,
+    0x40, 0x06, 0x01, 0xda, 0x7a, 0xc1, 0x51, 0x94,
+    0xc8, 0x09, 0xc8, 0x06, 0xc9, 0x07, 0xc6, 0x06,
+    0xc1, 0x09, 0x9a, 0x06, 0x11, 0x02, 0x09, 0x02,
+    0xc8, 0x17, 0x08, 0x00, 0x01, 0xda, 0x7a, 0xc1,
+    0x51, 0x94, 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf,
+    0xe7, 0x57, 0x00, 0x00, 0x76, 0x06, 0x97, 0xc0,
+    0x9f, 0xaf, 0x04, 0x00, 0xe7, 0x09, 0xbe, 0x06,
+    0xba, 0x06, 0xe7, 0x57, 0xff, 0xff, 0xba, 0x06,
+    0x04, 0xc1, 0xe7, 0x07, 0x10, 0x0b, 0xb8, 0x06,
+    0x97, 0xcf, 0xe7, 0x17, 0x32, 0x00, 0xba, 0x06,
+    0xe7, 0x67, 0xff, 0x07, 0xba, 0x06, 0xe7, 0x07,
+    0x46, 0x0b, 0xb8, 0x06, 0x97, 0xcf, 0xe7, 0x57,
+    0x00, 0x00, 0xc0, 0x06, 0x23, 0xc0, 0xe7, 0x07,
+    0x04, 0x00, 0x90, 0xc0, 0xe7, 0x07, 0x00, 0x80,
+    0x80, 0xc0, 0xe7, 0x07, 0x00, 0x00, 0x80, 0xc0,
+    0xe7, 0x07, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0x07,
+    0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xc0, 0x07,
+    0x00, 0x00, 0xe7, 0x07, 0x00, 0x00, 0x80, 0xc0,
+    0xe7, 0x07, 0x00, 0x80, 0x80, 0xc0, 0xe7, 0x07,
+    0x00, 0x80, 0x40, 0xc0, 0xc0, 0x07, 0x00, 0x00,
+    0xe7, 0x07, 0x00, 0x00, 0x40, 0xc0, 0xe7, 0x07,
+    0x00, 0x00, 0x80, 0xc0, 0xe7, 0x07, 0x04, 0x00,
+    0x90, 0xc0, 0xe7, 0x07, 0x00, 0x02, 0x40, 0xc0,
+    0xe7, 0x07, 0x0c, 0x02, 0x40, 0xc0, 0xe7, 0x07,
+    0x00, 0x00, 0xc0, 0x06, 0xe7, 0x07, 0x00, 0x00,
+    0xb8, 0x06, 0xe7, 0x07, 0x00, 0x00, 0xd2, 0x06,
+    0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x9f, 0xaf,
+    0x34, 0x02, 0xe7, 0x05, 0x00, 0xc0, 0x9f, 0xaf,
+    0xc4, 0x01, 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0,
+    0x17, 0x00, 0x17, 0x02, 0x97, 0x02, 0xe7, 0x57,
+    0x00, 0x00, 0xa8, 0x06, 0x06, 0xc0, 0xc0, 0x09,
+    0x92, 0xc0, 0xc0, 0x77, 0x09, 0x02, 0x9f, 0xc1,
+    0x5c, 0x05, 0x9f, 0xcf, 0x32, 0x06, 0xd7, 0x09,
+    0x0e, 0xc0, 0xe7, 0x07, 0x00, 0x00, 0x0e, 0xc0,
+    0x9f, 0xaf, 0x02, 0x0c, 0xe7, 0x05, 0x0e, 0xc0,
+    0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, 0x17, 0x02,
+    0xc8, 0x09, 0xb0, 0xc0, 0xe7, 0x67, 0xfe, 0x7f,
+    0xb0, 0xc0, 0xc8, 0x77, 0x00, 0x20, 0x9f, 0xc1,
+    0x64, 0xeb, 0xe7, 0x57, 0x00, 0x00, 0xc8, 0x02,
+    0x9f, 0xc1, 0x80, 0xeb, 0xc8, 0x99, 0xca, 0x02,
+    0xc8, 0x67, 0x04, 0x00, 0x9f, 0xc1, 0x96, 0xeb,
+    0x9f, 0xcf, 0x4c, 0xeb, 0xe7, 0x07, 0x00, 0x00,
+    0xa6, 0xc0, 0xe7, 0x09, 0xb0, 0xc0, 0xc8, 0x02,
+    0xe7, 0x07, 0x03, 0x00, 0xb0, 0xc0, 0x97, 0xcf,
+    0xc0, 0x09, 0xb0, 0x06, 0xc0, 0x37, 0x01, 0x00,
+    0x97, 0xc9, 0xc9, 0x09, 0xb2, 0x06, 0x02, 0x00,
+    0x41, 0x90, 0x48, 0x02, 0xc9, 0x17, 0x06, 0x00,
+    0x9f, 0xaf, 0x08, 0x04, 0x9f, 0xa2, 0x72, 0x0c,
+    0x02, 0xda, 0x77, 0xc1, 0x41, 0x60, 0x71, 0xc1,
+    0x97, 0xcf, 0x17, 0x02, 0x57, 0x02, 0x43, 0x04,
+    0x21, 0x04, 0xe0, 0x00, 0x43, 0x04, 0x21, 0x04,
+    0xe0, 0x00, 0x43, 0x04, 0x21, 0x04, 0xe0, 0x00,
+    0xc1, 0x07, 0x01, 0x00, 0xc9, 0x05, 0xc8, 0x05,
+    0x97, 0xcf, 0xe7, 0x07, 0x01, 0x00, 0x8e, 0x06,
+    0xc8, 0x07, 0x86, 0x06, 0xe7, 0x07, 0x00, 0x00,
+    0x86, 0x06, 0xe7, 0x07, 0x10, 0x08, 0x88, 0x06,
+    0xe7, 0x07, 0x04, 0x00, 0x8a, 0x06, 0xe7, 0x07,
+    0xbc, 0x0c, 0x8c, 0x06, 0xc1, 0x07, 0x03, 0x80,
+    0x50, 0xaf, 0x97, 0xcf, 0xe7, 0x07, 0x00, 0x00,
+    0x8e, 0x06, 0x97, 0xcf,
+    0x00, 0x00
+};
+
+/****************************************************************
+ *     kaweth_new_code_fix
+ ****************************************************************/
+static __u8 kaweth_new_code_fix[] = 
+{
+    0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD,
+    0x02, 0x00, 0x08, 0x00, 0x28, 0x00, 0x2c, 0x00,
+    0x34, 0x00, 0x3c, 0x00, 0x40, 0x00, 0x48, 0x00,
+    0x54, 0x00, 0x58, 0x00, 0x5e, 0x00, 0x64, 0x00,
+    0x68, 0x00, 0x6e, 0x00, 0x6c, 0x00, 0x72, 0x00,
+    0x76, 0x00, 0x7c, 0x00, 0x80, 0x00, 0x86, 0x00,
+    0x8a, 0x00, 0x90, 0x00, 0x94, 0x00, 0x98, 0x00,
+    0x9e, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xb0, 0x00,
+    0xb4, 0x00, 0xb8, 0x00, 0xc0, 0x00, 0xc6, 0x00,
+    0xca, 0x00, 0xd0, 0x00, 0xd4, 0x00, 0xd8, 0x00,
+    0xe0, 0x00, 0xde, 0x00, 0xe8, 0x00, 0xf0, 0x00,
+    0xfc, 0x00, 0x04, 0x01, 0x0a, 0x01, 0x18, 0x01,
+    0x22, 0x01, 0x28, 0x01, 0x3a, 0x01, 0x3e, 0x01,
+    0x7e, 0x01, 0x98, 0x01, 0x9c, 0x01, 0xa2, 0x01,
+    0xac, 0x01, 0xb2, 0x01, 0xba, 0x01, 0xc0, 0x01,
+    0xc8, 0x01, 0xd0, 0x01, 0xd6, 0x01, 0xf4, 0x01,
+    0xfc, 0x01, 0x08, 0x02, 0x16, 0x02, 0x1a, 0x02,
+    0x22, 0x02, 0x2a, 0x02, 0x2e, 0x02, 0x3e, 0x02,
+    0x44, 0x02, 0x4a, 0x02, 0x50, 0x02, 0x64, 0x02,
+    0x62, 0x02, 0x6c, 0x02, 0x72, 0x02, 0x86, 0x02,
+    0x8c, 0x02, 0x90, 0x02, 0x9e, 0x02, 0xbc, 0x02,
+    0xd0, 0x02, 0xd8, 0x02, 0xdc, 0x02, 0xe0, 0x02,
+    0xe8, 0x02, 0xe6, 0x02, 0xf4, 0x02, 0xfe, 0x02,
+    0x04, 0x03, 0x0c, 0x03, 0x28, 0x03, 0x7c, 0x03,
+    0x90, 0x03, 0x94, 0x03, 0x9c, 0x03, 0xa2, 0x03,
+    0xc0, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0xee, 0x03,
+    0xfa, 0x03, 0xfe, 0x03, 0x2e, 0x04, 0x32, 0x04,
+    0x3c, 0x04, 0x40, 0x04, 0x4e, 0x04, 0x76, 0x04,
+    0x7c, 0x04, 0x84, 0x04, 0x8a, 0x04, 0x8e, 0x04,
+    0xa6, 0x04, 0xb0, 0x04, 0xb8, 0x04, 0xbe, 0x04,
+    0xd2, 0x04, 0xdc, 0x04, 0xee, 0x04, 0x10, 0x05,
+    0x1a, 0x05, 0x24, 0x05, 0x2a, 0x05, 0x36, 0x05,
+    0x34, 0x05, 0x3c, 0x05, 0x42, 0x05, 0x64, 0x05,
+    0x6a, 0x05, 0x6e, 0x05, 0x86, 0x05, 0x22, 0x06,
+    0x26, 0x06, 0x2c, 0x06, 0x30, 0x06, 0x42, 0x06,
+    0x4a, 0x06, 0x4e, 0x06, 0x56, 0x06, 0x54, 0x06,
+    0x5a, 0x06, 0x60, 0x06, 0x66, 0x06, 0xe8, 0x06,
+    0xee, 0x06, 0xf4, 0x06, 0x16, 0x07, 0x26, 0x07,
+    0x2c, 0x07, 0x32, 0x07, 0x36, 0x07, 0x3a, 0x07,
+    0x3e, 0x07, 0x52, 0x07, 0x56, 0x07, 0x5a, 0x07,
+    0x64, 0x07, 0x76, 0x07, 0x7a, 0x07, 0x80, 0x07,
+    0x84, 0x07, 0x8a, 0x07, 0x9e, 0x07, 0xa2, 0x07,
+    0xda, 0x07, 0xde, 0x07, 0xe2, 0x07, 0xe6, 0x07,
+    0xea, 0x07, 0xee, 0x07, 0xf2, 0x07, 0xf6, 0x07,
+    0x0e, 0x08, 0x16, 0x08, 0x18, 0x08, 0x1a, 0x08,
+    0x1c, 0x08, 0x1e, 0x08, 0x20, 0x08, 0x22, 0x08,
+    0x24, 0x08, 0x26, 0x08, 0x28, 0x08, 0x2a, 0x08,
+    0x2c, 0x08, 0x2e, 0x08, 0x32, 0x08, 0x3a, 0x08,
+    0x46, 0x08, 0x4e, 0x08, 0x54, 0x08, 0x5e, 0x08,
+    0x78, 0x08, 0x7e, 0x08, 0x82, 0x08, 0x86, 0x08,
+    0x8c, 0x08, 0x90, 0x08, 0x98, 0x08, 0x9e, 0x08,
+    0xa4, 0x08, 0xaa, 0x08, 0xb0, 0x08, 0xae, 0x08,
+    0xb4, 0x08, 0xbe, 0x08, 0xc4, 0x08, 0xc2, 0x08,
+    0xca, 0x08, 0xc8, 0x08, 0xd4, 0x08, 0xe4, 0x08,
+    0xe8, 0x08, 0xf6, 0x08, 0x14, 0x09, 0x12, 0x09,
+    0x1a, 0x09, 0x20, 0x09, 0x26, 0x09, 0x24, 0x09,
+    0x2a, 0x09, 0x3e, 0x09, 0x4c, 0x09, 0x56, 0x09,
+    0x70, 0x09, 0x74, 0x09, 0x78, 0x09, 0x7e, 0x09,
+    0x7c, 0x09, 0x82, 0x09, 0x98, 0x09, 0x9c, 0x09,
+    0xa0, 0x09, 0xa6, 0x09, 0xb8, 0x09, 0xdc, 0x09,
+    0xe8, 0x09, 0xec, 0x09, 0xfc, 0x09, 0x12, 0x0a,
+    0x18, 0x0a, 0x1e, 0x0a, 0x42, 0x0a, 0x46, 0x0a,
+    0x4e, 0x0a, 0x54, 0x0a, 0x5a, 0x0a, 0x5e, 0x0a,
+    0x68, 0x0a, 0x6e, 0x0a, 0x72, 0x0a, 0x78, 0x0a,
+    0x76, 0x0a, 0x7c, 0x0a, 0x80, 0x0a, 0x84, 0x0a,
+    0x94, 0x0a, 0xa4, 0x0a, 0xb8, 0x0a, 0xbe, 0x0a,
+    0xbc, 0x0a, 0xc2, 0x0a, 0xc8, 0x0a, 0xc6, 0x0a,
+    0xcc, 0x0a, 0xd0, 0x0a, 0xd4, 0x0a, 0xd8, 0x0a,
+    0xdc, 0x0a, 0xe0, 0x0a, 0xf2, 0x0a, 0xf6, 0x0a,
+    0xfa, 0x0a, 0x14, 0x0b, 0x1a, 0x0b, 0x20, 0x0b,
+    0x1e, 0x0b, 0x26, 0x0b, 0x2e, 0x0b, 0x2c, 0x0b,
+    0x36, 0x0b, 0x3c, 0x0b, 0x42, 0x0b, 0x40, 0x0b,
+    0x4a, 0x0b, 0xaa, 0x0b, 0xb0, 0x0b, 0xb6, 0x0b,
+    0xc0, 0x0b, 0xc8, 0x0b, 0xda, 0x0b, 0xe8, 0x0b,
+    0xec, 0x0b, 0xfa, 0x0b, 0x4a, 0x0c, 0x54, 0x0c,
+    0x62, 0x0c, 0x66, 0x0c, 0x96, 0x0c, 0x9a, 0x0c,
+    0xa0, 0x0c, 0xa6, 0x0c, 0xa4, 0x0c, 0xac, 0x0c,
+    0xb2, 0x0c, 0xb0, 0x0c, 0xc0, 0x0c,
+    0x00, 0x00
+};
+
+
+const int len_kaweth_trigger_code = sizeof(kaweth_trigger_code);
+const int len_kaweth_trigger_code_fix = sizeof(kaweth_trigger_code_fix);
+const int len_kaweth_new_code = sizeof(kaweth_new_code);
+const int len_kaweth_new_code_fix = sizeof(kaweth_new_code_fix);
diff -urN linux-2.4.9-pre1/drivers/video/acornfb.c linux/drivers/video/acornfb.c
--- linux-2.4.9-pre1/drivers/video/acornfb.c	Wed Apr 18 11:49:12 2001
+++ linux/drivers/video/acornfb.c	Mon Dec  3 23:01:22 2001
@@ -1,7 +1,7 @@
 /*
  *  linux/drivers/video/acornfb.c
  *
- *  Copyright (C) 1998-2000 Russell King
+ *  Copyright (C) 1998-2001 Russell King
  *
  * 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
@@ -30,6 +30,7 @@
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/mach-types.h>
 #include <asm/uaccess.h>
 
 #include <video/fbcon.h>
@@ -43,6 +44,14 @@
 #include "acornfb.h"
 
 /*
+ * VIDC machines can't do 16 or 32BPP modes.
+ */
+#ifdef HAS_VIDC
+#undef FBCON_HAS_CFB16
+#undef FBCON_HAS_CFB32
+#endif
+
+/*
  * Default resolution.
  * NOTE that it has to be supported in the table towards
  * the end of this file.
@@ -117,37 +126,50 @@
  * 25.175  3	25.175
  * 36.000  3	36.000
  */
-static struct pixclock {
+struct pixclock {
 	u_long	min_clock;
 	u_long	max_clock;
 	u_int	vidc_ctl;
 	u_int	vid_ctl;
-} pixclocks[] = {
+};
+
+static struct pixclock arc_clocks[] = {
 	/* we allow +/-1% on these */
 	{ 123750, 126250, VIDC_CTRL_DIV3,   VID_CTL_24MHz },	/*  8.000MHz */
 	{  82500,  84167, VIDC_CTRL_DIV2,   VID_CTL_24MHz },	/* 12.000MHz */
 	{  61875,  63125, VIDC_CTRL_DIV1_5, VID_CTL_24MHz },	/* 16.000MHz */
 	{  41250,  42083, VIDC_CTRL_DIV1,   VID_CTL_24MHz },	/* 24.000MHz */
+};
+
 #ifdef CONFIG_ARCH_A5K
+static struct pixclock a5k_clocks[] = {
 	{ 117974, 120357, VIDC_CTRL_DIV3,   VID_CTL_25MHz },	/*  8.392MHz */
 	{  78649,  80238, VIDC_CTRL_DIV2,   VID_CTL_25MHz },	/* 12.588MHz */
 	{  58987,  60178, VIDC_CTRL_DIV1_5, VID_CTL_25MHz },	/* 16.588MHz */
 	{  55000,  56111, VIDC_CTRL_DIV2,   VID_CTL_36MHz },	/* 18.000MHz */
 	{  39325,  40119, VIDC_CTRL_DIV1,   VID_CTL_25MHz },	/* 25.175MHz */
 	{  27500,  28055, VIDC_CTRL_DIV1,   VID_CTL_36MHz },	/* 36.000MHz */
-#endif
-	{ 0, }
 };
+#endif
 
 static struct pixclock *
 acornfb_valid_pixrate(u_long pixclock)
 {
 	u_int i;
 
-	for (i = 0; pixclocks[i].min_clock; i++)
-		if (pixclock > pixclocks[i].min_clock &&
-		    pixclock < pixclocks[i].max_clock)
-			return pixclocks + i;
+	for (i = 0; i < ARRAY_SIZE(arc_clocks); i++)
+		if (pixclock > arc_clocks[i].min_clock &&
+		    pixclock < arc_clocks[i].max_clock)
+			return arc_clocks + i;
+
+#ifdef CONFIG_ARCH_A5K
+	if (machine_is_a5k()) {
+		for (i = 0; i < ARRAY_SIZE(a5k_clocks); i++)
+			if (pixclock > a5k_clocks[i].min_clock &&
+			    pixclock < a5k_clocks[i].max_clock)
+				return a5k_clocks + i;
+	}
+#endif
 
 	return NULL;
 }
@@ -215,11 +237,15 @@
 		break;
 	}
 
-	if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
-		vid_ctl |= VID_CTL_HS_NHSYNC;
+	if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */
+		vidc_ctl |= VIDC_CTRL_CSYNC;
+	else {
+		if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
+			vid_ctl |= VID_CTL_HS_NHSYNC;
 
-	if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
-		vid_ctl |= VID_CTL_VS_NVSYNC;
+		if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
+			vid_ctl |= VID_CTL_VS_NVSYNC;
+	}
 
 	sync_len	= var->hsync_len;
 	display_start	= sync_len + var->left_margin;
@@ -262,9 +288,9 @@
 	vidc.v_display_end	= display_end - 1;
 	vidc.v_border_end	= vidc.v_display_end;
 
-#ifdef CONFIG_ARCH_A5K
-	__raw_writeb(vid_ctl, IOEB_VID_CTL);
-#endif
+	if (machine_is_a5k())
+		__raw_writeb(vid_ctl, IOEB_VID_CTL);
+
 	if (memcmp(&current_vidc, &vidc, sizeof(vidc))) {
 		current_vidc = vidc;
 
@@ -719,30 +745,19 @@
 	pal = acornfb_palette_encode(regno, red, green, blue, trans);
 	current_par.palette[regno] = pal;
 
-#ifdef HAS_VIDC20
-	if (regno < 16) {
-		switch (bpp) {
-#ifdef FBCON_HAS_CFB16
-		case 16:
-			current_par.cmap.cfb16[regno] =
-				regno | regno << 5 | regno << 10;
-			break;
-#endif
 #ifdef FBCON_HAS_CFB32
-		case 32:
-			current_par.cmap.cfb32[regno] =
+	if (bpp == 32 && regno < 16) {
+		current_par.cmap.cfb32[regno] =
 				regno | regno << 8 | regno << 16;
-			break;
-#endif
-		default:
-			break;
-		}
 	}
-
+#endif
 #ifdef FBCON_HAS_CFB16
-	if (bpp == 16) {
+	if (bpp == 16 && regno < 16) {
 		int i;
 
+		current_par.cmap.cfb16[regno] =
+				regno | regno << 5 | regno << 10;
+
 		pal.p = 0;
 		vidc_writel(0x10000000);
 		for (i = 0; i < 256; i += 1) {
@@ -754,7 +769,6 @@
 		}
 	} else
 #endif
-#endif
 		acornfb_palette_write(regno, pal);
 
 	return 0;
@@ -797,52 +811,73 @@
 }
 
 static int
-acornfb_decode_var(struct fb_var_screeninfo *var, int con, int *visual)
+acornfb_decode_var(struct fb_var_screeninfo *var, int con)
 {
 	int err;
 
+#if defined(HAS_VIDC20)
+	var->red.offset    = 0;
+	var->red.length    = 8;
+	var->green         = var->red;
+	var->blue          = var->red;
+	var->transp.offset = 0;
+	var->transp.length = 4;
+#elif defined(HAS_VIDC)
+	var->red.length	   = 4;
+	var->green         = var->red;
+	var->blue          = var->red;
+	var->transp.length = 1;
+#endif
+
 	switch (var->bits_per_pixel) {
 #ifdef FBCON_HAS_MFB
 	case 1:
-		*visual = FB_VISUAL_MONO10;
 		break;
 #endif
-#ifdef FBCON_HAS_CFB8
-	case 8:
-#ifdef HAS_VIDC
-		*visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
-#else
-		*visual = FB_VISUAL_PSEUDOCOLOR;
-#endif
+#ifdef FBCON_HAS_CFB2
+	case 2:
 		break;
 #endif
 #ifdef FBCON_HAS_CFB4
 	case 4:
-		*visual = FB_VISUAL_PSEUDOCOLOR;
 		break;
 #endif
-#ifdef FBCON_HAS_CFB2
-	case 2:
-		*visual = FB_VISUAL_PSEUDOCOLOR;
+#ifdef FBCON_HAS_CFB8
+	case 8:
 		break;
 #endif
-#ifdef HAS_VIDC20
 #ifdef FBCON_HAS_CFB16
 	case 16:
-		*visual = FB_VISUAL_DIRECTCOLOR;
+		var->red.offset    = 0;
+		var->red.length    = 5;
+		var->green.offset  = 5;
+		var->green.length  = 5;
+		var->blue.offset   = 10;
+		var->blue.length   = 5;
+		var->transp.offset = 15;
+		var->transp.length = 1;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB32
 	case 32:
-		*visual = FB_VISUAL_TRUECOLOR;
+		var->red.offset    = 0;
+		var->red.length    = 8;
+		var->green.offset  = 8;
+		var->green.length  = 8;
+		var->blue.offset   = 16;
+		var->blue.length   = 8;
+		var->transp.offset = 24;
+		var->transp.length = 4;
 		break;
 #endif
-#endif
 	default:
 		return -EINVAL;
 	}
 
-	if (!acornfb_valid_pixrate(var->pixclock))
+	/*
+	 * Check to see if the pixel rate is valid.
+	 */
+	if (!var->pixclock || !acornfb_valid_pixrate(var->pixclock))
 		return -EINVAL;
 
 	/*
@@ -857,50 +892,7 @@
 	 * Validate the timing against the
 	 * monitor hardware.
 	 */
-	err = acornfb_validate_timing(var, &fb_info.monspecs);
-	if (err)
-		return err;
-
-#if defined(HAS_VIDC20)
-	switch (var->bits_per_pixel) {
-	case 1: case 2: case 4: case 8:
-		var->red.offset    = 0;
-		var->red.length    = 8;
-		var->green         = var->red;
-		var->blue          = var->red;
-		var->transp.offset = 0;
-		var->transp.length = 4;
-		break;
-
-	case 16:
-		var->red.offset    = 0;
-		var->red.length    = 5;
-		var->green.offset  = 5;
-		var->green.length  = 5;
-		var->blue.offset   = 10;
-		var->blue.length   = 5;
-		var->transp.offset = 15;
-		var->transp.length = 1;
-		break;
-
-	case 32:
-		var->red.offset    = 0;
-		var->red.length    = 8;
-		var->green.offset  = 8;
-		var->green.length  = 8;
-		var->blue.offset   = 16;
-		var->blue.length   = 8;
-		var->transp.offset = 24;
-		var->transp.length = 4;
-		break;
-	}
-#elif defined(HAS_VIDC)
-	var->red.length	   = 4;
-	var->green         = var->red;
-	var->blue          = var->red;
-	var->transp.length = 1;
-#endif
-	return 0;
+	return acornfb_validate_timing(var, &fb_info.monspecs);
 }
 
 static int
@@ -945,14 +937,14 @@
 acornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
 {
 	struct display *display;
-	int err, chgvar = 0, visual;
+	int err, chgvar = 0;
 
 	if (con >= 0)
 		display = fb_display + con;
 	else
 		display = &global_disp;
 
-	err = acornfb_decode_var(var, con, &visual);
+	err = acornfb_decode_var(var, con);
 	if (err)
 		return err;
 
@@ -991,40 +983,37 @@
 	if (var->activate & FB_ACTIVATE_ALL)
 		global_disp.var = display->var;
 
-	display->screen_base	= (char *)current_par.screen_base;
-	display->visual		= visual;
-	display->type		= FB_TYPE_PACKED_PIXELS;
-	display->type_aux	= 0;
-	display->ypanstep	= 1;
-	display->ywrapstep	= 1;
-	display->line_length	=
-	display->next_line      = (var->xres * var->bits_per_pixel) / 8;
-	display->can_soft_blank	= visual == FB_VISUAL_PSEUDOCOLOR ? 1 : 0;
-	display->inverse	= 0;
-
 	switch (display->var.bits_per_pixel) {
 #ifdef FBCON_HAS_MFB
 	case 1:
 		current_par.palette_size = 2;
 		display->dispsw = &fbcon_mfb;
+		display->visual = FB_VISUAL_MONO10;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB2
 	case 2:
 		current_par.palette_size = 4;
 		display->dispsw = &fbcon_cfb2;
+		display->visual = FB_VISUAL_PSEUDOCOLOR;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB4
 	case 4:
 		current_par.palette_size = 16;
 		display->dispsw = &fbcon_cfb4;
+		display->visual = FB_VISUAL_PSEUDOCOLOR;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB8
 	case 8:
 		current_par.palette_size = VIDC_PALETTE_SIZE;
 		display->dispsw = &fbcon_cfb8;
+#ifdef HAS_VIDC
+		display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+#else
+		display->visual = FB_VISUAL_PSEUDOCOLOR;
+#endif
 		break;
 #endif
 #ifdef FBCON_HAS_CFB16
@@ -1032,6 +1021,7 @@
 		current_par.palette_size = 32;
 		display->dispsw = &fbcon_cfb16;
 		display->dispsw_data = current_par.cmap.cfb16;
+		display->visual = FB_VISUAL_DIRECTCOLOR;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB32
@@ -1039,6 +1029,7 @@
 		current_par.palette_size = VIDC_PALETTE_SIZE;
 		display->dispsw = &fbcon_cfb32;
 		display->dispsw_data = current_par.cmap.cfb32;
+		display->visual = FB_VISUAL_TRUECOLOR;
 		break;
 #endif
 	default:
@@ -1046,6 +1037,16 @@
 		break;
 	}
 
+	display->screen_base	= (char *)current_par.screen_base;
+	display->type		= FB_TYPE_PACKED_PIXELS;
+	display->type_aux	= 0;
+	display->ypanstep	= 1;
+	display->ywrapstep	= 1;
+	display->line_length	=
+	display->next_line      = (var->xres * var->bits_per_pixel) / 8;
+	display->can_soft_blank	= display->visual == FB_VISUAL_PSEUDOCOLOR ? 1 : 0;
+	display->inverse	= 0;
+
 	if (chgvar && info && info->changevar)
 		info->changevar(con);
 
@@ -1205,18 +1206,8 @@
 	union palette p;
 	int i, bpp = fb_display[current_par.currcon].var.bits_per_pixel;
 
-	if (bpp != 16) {
-		for (i = 0; i < current_par.palette_size; i++) {
-			if (blank)
-				p = acornfb_palette_encode(i, 0, 0, 0, 0);
-			else
-				p = current_par.palette[i];
-
-			acornfb_palette_write(i, p);
-		}
-	}
 #ifdef FBCON_HAS_CFB16
-	else {
+	if (bpp == 16) {
 		p.p = 0;
 
 		for (i = 0; i < 256; i++) {
@@ -1229,8 +1220,18 @@
 			}
 			acornfb_palette_write(i, current_par.palette[i]);
 		}
-	}
+	} else
 #endif
+	{
+		for (i = 0; i < current_par.palette_size; i++) {
+			if (blank)
+				p = acornfb_palette_encode(i, 0, 0, 0, 0);
+			else
+				p = current_par.palette[i];
+
+			acornfb_palette_write(i, p);
+		}
+	}
 }
 
 /*
diff -urN linux-2.4.9-pre1/drivers/video/acornfb.h linux/drivers/video/acornfb.h
--- linux-2.4.9-pre1/drivers/video/acornfb.h	Mon Sep 18 15:15:22 2000
+++ linux/drivers/video/acornfb.h	Mon Dec  3 23:01:22 2001
@@ -115,6 +115,7 @@
 #define VID_CTL_25MHz		(1)
 #define VID_CTL_36MHz		(2)
 
+#define VIDC_CTRL_CSYNC		(1 << 7)
 #define VIDC_CTRL_INTERLACE	(1 << 6)
 #define VIDC_CTRL_FIFO_0_4	(0 << 4)
 #define VIDC_CTRL_FIFO_1_5	(1 << 4)
diff -urN linux-2.4.9-pre1/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c
--- linux-2.4.9-pre1/drivers/video/cyber2000fb.c	Wed Jul  4 11:50:39 2001
+++ linux/drivers/video/cyber2000fb.c	Mon Dec  3 23:01:22 2001
@@ -53,15 +53,6 @@
  */
 /*#define CFB16_IS_CFB15*/
 
-/*
- * This is the offset of the PCI space in physical memory
- */
-#ifdef CONFIG_FOOTBRIDGE
-#define PCI_PHYS_OFFSET	0x80000000
-#else
-#define	PCI_PHYS_OFFSET	0x00000000
-#endif
-
 static char			*CyberRegs;
 
 #include "cyber2000fb.h"
@@ -1074,18 +1065,18 @@
 	case 2:	/* vsync off */
     		cyber2000_grphw(0x16, 0x04);
 		break;	
-	case 1:	/* just software blanking of screen */
+	case 1:	/* soft blank */
 		cyber2000_grphw(0x16, 0x00);
-		for (i = 0; i < 256; i++) {
+		for (i = 0; i < NR_PALETTE; i++) {
 			cyber2000_outb(i, 0x3c8);
 			cyber2000_outb(0, 0x3c9);
 			cyber2000_outb(0, 0x3c9);
 			cyber2000_outb(0, 0x3c9);
 		}
 		break;
-	default: /* case 0, or anything else: unblank */
+	default: /* unblank */
 		cyber2000_grphw(0x16, 0x00);
-		for (i = 0; i < 256; i++) {
+		for (i = 0; i < NR_PALETTE; i++) {
 			cyber2000_outb(i, 0x3c8);
 			cyber2000_outb(cfb->palette[i].red, 0x3c9);
 			cyber2000_outb(cfb->palette[i].green, 0x3c9);
@@ -1323,7 +1314,7 @@
 	cyber2000_outb(0x01, 0x3cf);
 
 	/*
-	 * MCLK on the NetWinder is fixed at 75MHz
+	 * MCLK on the NetWinder and the Shark is fixed at 75MHz
 	 */
 	cfb->mclk_mult = 0xdb;
 	cfb->mclk_div  = 0x54;
@@ -1361,7 +1352,7 @@
 }
 
 static struct cfb_info * __devinit
-cyberpro_alloc_fb_info(struct pci_dev *dev, const struct pci_device_id *id)
+cyberpro_alloc_fb_info(struct pci_dev *dev, const struct pci_device_id *id, char *name)
 {
 	struct cfb_info *cfb;
 
@@ -1385,7 +1376,7 @@
 	else
 		cfb->divisors[3] = 8;
 
-	sprintf(cfb->fb.fix.id, "CyberPro%4X", id->device);
+	strcpy(cfb->fb.fix.id, name);
 
 	cfb->fb.fix.type	= FB_TYPE_PACKED_PIXELS;
 	cfb->fb.fix.type_aux	= 0;
@@ -1440,14 +1431,9 @@
 
 	mmio_base = pci_resource_start(dev, 0) + MMIO_OFFSET;
 
-	cfb->fb.fix.mmio_start = mmio_base + PCI_PHYS_OFFSET;
+	cfb->fb.fix.mmio_start = mmio_base;
 	cfb->fb.fix.mmio_len   = MMIO_SIZE;
 
-	if (!request_mem_region(mmio_base, MMIO_SIZE, "memory mapped I/O")) {
-		printk("%s: memory mapped IO in use\n", cfb->fb.fix.id);
-		return -EBUSY;
-	}
-
 	CyberRegs = ioremap(mmio_base, MMIO_SIZE);
 	if (!CyberRegs) {
 		printk("%s: unable to map memory mapped IO\n",
@@ -1465,9 +1451,6 @@
 	if (cfb && CyberRegs) {
 		iounmap(CyberRegs);
 		CyberRegs = NULL;
-
-		release_mem_region(cfb->fb.fix.mmio_start - PCI_PHYS_OFFSET,
-				   cfb->fb.fix.mmio_len);
 	}
 }
 
@@ -1481,15 +1464,9 @@
 
 	smem_base = pci_resource_start(dev, 0);
 
-	cfb->fb.fix.smem_start	= smem_base + PCI_PHYS_OFFSET;
+	cfb->fb.fix.smem_start	= smem_base;
 	cfb->fb.fix.smem_len	= smem_len;
 
-	if (!request_mem_region(smem_base, smem_len, "frame buffer")) {
-		printk("%s: frame buffer in use\n",
-		       cfb->fb.fix.id);
-		return -EBUSY;
-	}
-
 	cfb->fb.screen_base = ioremap(smem_base, smem_len);
 	if (!cfb->fb.screen_base) {
 		printk("%s: unable to map screen memory\n",
@@ -1505,9 +1482,6 @@
 	if (cfb && cfb->fb.screen_base) {
 		iounmap(cfb->fb.screen_base);
 		cfb->fb.screen_base = NULL;
-
-		release_mem_region(cfb->fb.fix.smem_start - PCI_PHYS_OFFSET,
-				   cfb->fb.fix.smem_len);
 	}
 }
 
@@ -1517,14 +1491,21 @@
 	struct cfb_info *cfb;
 	u_int h_sync, v_sync;
 	u_long smem_size;
+	char name[16];
 	int err;
 
+	sprintf(name, "CyberPro%4X", id->device);
+
 	err = pci_enable_device(dev);
 	if (err)
 		return err;
 
+	err = pci_request_regions(dev, name);
+	if (err)
+		return err;
+
 	err = -ENOMEM;
-	cfb = cyberpro_alloc_fb_info(dev, id);
+	cfb = cyberpro_alloc_fb_info(dev, id, name);
 	if (!cfb)
 		goto failed;
 
@@ -1593,6 +1574,9 @@
 	cyberpro_unmap_mmio(cfb);
 	cyberpro_free_fb_info(cfb);
 
+release:
+	pci_release_regions(dev);
+
 	return err;
 }
 
@@ -1621,6 +1605,8 @@
 		pci_set_drvdata(dev, NULL);
 		if (cfb == int_cfb_info)
 			int_cfb_info = NULL;
+
+		pci_release_regions(dev);
 	}
 }
 
diff -urN linux-2.4.9-pre1/drivers/video/sa1100fb.c linux/drivers/video/sa1100fb.c
--- linux-2.4.9-pre1/drivers/video/sa1100fb.c	Wed Apr 18 11:49:12 2001
+++ linux/drivers/video/sa1100fb.c	Mon Dec  3 23:01:22 2001
@@ -1,59 +1,135 @@
 /*
- * linux/drivers/video/sa1100fb.c -- StrongARM 1100 LCD Controller Frame Buffer Device
+ *  linux/drivers/video/sa1100fb.c
  *
  *  Copyright (C) 1999 Eric A. Thomas
- *  
+ *   Based on acornfb.c Copyright (C) Russell King.
+ *
  * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
  *
- */
-
-
-/*
- *   Code Status:
+ *	        StrongARM 1100 LCD Controller Frame Buffer Driver
+ *
+ * Please direct your questions and comments on this driver to the following
+ * email address:
+ *
+ *	linux-arm-kernel@lists.arm.linux.org.uk
+ *
+ * Clean patches should be sent to the ARM Linux Patch System.  Please see the
+ * following web page for more information:
+ *
+ *	http://www.arm.linux.org.uk/developer/patches/info.shtml
+ *
+ * Thank you.
+ *
+ * Known problems:
+ *  - With the Neponset plugged into an Assabet, LCD powerdown
+ *    doesn't work (LCD stays powered up).  Therefore we shouldn't
+ *    blank the screen.
+ *  - We don't limit the CPU clock rate nor the mode selection
+ *    according to the available SDRAM bandwidth.
+ *
+ *
+ * Code Status:
  * 1999/04/01:
- * 	Driver appears to be working for Brutus 320x200x8bpp mode.  Other
- * 	resolutions are working, but only the 8bpp mode is supported.
- * 	Changes need to be made to the palette encode and decode routines
- * 	to support 4 and 16 bpp modes.  
- * 	Driver is not designed to be a module.  The FrameBuffer is statically
- * 	allocated since dynamic allocation of a 300k buffer cannot be 
- * 	guaranteed. 
- * 
+ *	- Driver appears to be working for Brutus 320x200x8bpp mode.  Other
+ *	  resolutions are working, but only the 8bpp mode is supported.
+ *	  Changes need to be made to the palette encode and decode routines
+ *	  to support 4 and 16 bpp modes.  
+ *	  Driver is not designed to be a module.  The FrameBuffer is statically
+ *	  allocated since dynamic allocation of a 300k buffer cannot be 
+ *	  guaranteed. 
+ *
  * 1999/06/17:
- * 	FrameBuffer memory is now allocated at run-time when the
- * 	driver is initialized.    
+ *	- FrameBuffer memory is now allocated at run-time when the
+ *	  driver is initialized.    
+ *
+ * 2000/04/10: Nicolas Pitre <nico@cam.org>
+ *	- Big cleanup for dynamic selection of machine type at run time.
  *
- * 2000/04/10:
- * 	Big cleanup for dynamic selection of machine type at run time.
- * 		Nicolas Pitre <nico@cam.org>
- * 
- * 2000/07/19:
- * 	Support for Bitsy aka Compaq iPAQ H3600 added.
- * 		Jamey Hicks <jamey@crl.dec.com>
- * 
- * 2000/08/07:
- * 	Resolved an issue caused by a change made to the Assabet's PLD 
- * 	earlier this year which broke the framebuffer driver for newer 
- * 	Phase 4 Assabets.  Some other parameters were changed to optimize for
- * 	the Sharp display.
- * 		Tak-Shing Chan <tchan.rd@idthk.com>
- * 		Jeff Sutherland <jsutherland@accelent.com>
- * 
- * 2000/08/09:
- * 	XP860 support added
- * 		Kunihiko IMAI <imai@vasara.co.jp>
- *
- * 2000/08/19:
- * 	Allows standard options to be passed on the kernel command line
- * 	for most common passive displays.
- * 		Mark Huang <mhuang@livetoy.com>
+ * 2000/07/19: Jamey Hicks <jamey@crl.dec.com>
+ *	- Support for Bitsy aka Compaq iPAQ H3600 added.
+ *
+ * 2000/08/07: Tak-Shing Chan <tchan.rd@idthk.com>
+ *	       Jeff Sutherland <jsutherland@accelent.com>
+ *	- Resolved an issue caused by a change made to the Assabet's PLD 
+ *	  earlier this year which broke the framebuffer driver for newer 
+ *	  Phase 4 Assabets.  Some other parameters were changed to optimize
+ *	  for the Sharp display.
+ *
+ * 2000/08/09: Kunihiko IMAI <imai@vasara.co.jp>
+ *	- XP860 support added
+ *
+ * 2000/08/19: Mark Huang <mhuang@livetoy.com>
+ *	- Allows standard options to be passed on the kernel command line
+ *	  for most common passive displays.
  *
  * 2000/08/29:
- *	s/save_flags_cli/local_irq_save/
- *      remove unneeded extra save_flags_cli in
- *       sa1100fb_enable_lcd_controller
+ *	- s/save_flags_cli/local_irq_save/
+ *	- remove unneeded extra save_flags_cli in sa1100fb_enable_lcd_controller
+ *
+ * 2000/10/10: Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
+ *	- Updated LART stuff. Fixed some minor bugs.
+ *
+ * 2000/10/30: Murphy Chen <murphy@mail.dialogue.com.tw>
+ *	- Pangolin support added
+ *
+ * 2000/10/31: Roman Jordan <jor@hoeft-wessel.de>
+ *	- Huw Webpanel support added
+ *
+ * 2000/11/23: Eric Peng <ericpeng@coventive.com>
+ *	- Freebird add
+ *
+ * 2001/02/07: Jamey Hicks <jamey.hicks@compaq.com> 
+ *	       Cliff Brake <cbrake@accelent.com>
+ *	- Added PM callback
+ *
+ * 2001/05/26: <rmk@arm.linux.org.uk>
+ *	- Fix 16bpp so that (a) we use the right colours rather than some
+ *	  totally random colour depending on what was in page 0, and (b)
+ *	  we don't de-reference a NULL pointer.
+ *	- remove duplicated implementation of consistent_alloc()
+ *	- convert dma address types to dma_addr_t
+ *	- remove unused 'montype' stuff
+ *	- remove redundant zero inits of init_var after the initial
+ *	  memzero.
+ *	- remove allow_modeset (acornfb idea does not belong here)
+ *
+ * 2001/05/28: <rmk@arm.linux.org.uk>
+ *	- massive cleanup - move machine dependent data into structures
+ *	- I've left various #warnings in - if you see one, and know
+ *	  the hardware concerned, please get in contact with me.
+ *
+ * 2001/05/31: <rmk@arm.linux.org.uk>
+ *	- Fix LCCR1 HSW value, fix all machine type specifications to
+ *	  keep values in line.  (Please check your machine type specs)
+ *
+ * 2001/06/10: <rmk@arm.linux.org.uk>
+ *	- Fiddle with the LCD controller from task context only; mainly
+ *	  so that we can run with interrupts on, and sleep.
+ *	- Convert #warnings into #errors.  No pain, no gain. ;)
+ *
+ * 2001/06/14: <rmk@arm.linux.org.uk>
+ *	- Make the palette BPS value for 12bpp come out correctly.
+ *	- Take notice of "greyscale" on any colour depth.
+ *	- Make truecolor visuals use the RGB channel encoding information.
+ *
+ * 2001/07/02: <rmk@arm.linux.org.uk>
+ *	- Fix colourmap problems.
+ *
+ * 2001/07/13: <abraham@2d3d.co.za>
+ *	- Added support for the ICP LCD-Kit01 on LART. This LCD is
+ *	  manufactured by Prime View, model no V16C6448AB
+ *
+ * 2001/07/23: <rmk@arm.linux.org.uk>
+ *	- Hand merge version from handhelds.org CVS tree.  See patch
+ *	  notes for 595/1 for more information.
+ *	- Drop 12bpp (it's 16bpp with different colour register mappings).
+ *	- This hardware can not do direct colour.  Therefore we don't
+ *	  support it.
+ *
+ * 2001/07/27: <rmk@arm.linux.org.uk>
+ *	- Halve YRES on dual scan LCDs.
  */
 
 #include <linux/config.h>
@@ -62,21 +138,19 @@
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
+#include <linux/interrupt.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/fb.h>
 #include <linux/delay.h>
-#include <linux/wrapper.h>
+#include <linux/pm.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
 
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 #include <asm/uaccess.h>
-#include <asm/proc/pgtable.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-mfb.h>
@@ -84,328 +158,902 @@
 #include <video/fbcon-cfb8.h>
 #include <video/fbcon-cfb16.h>
 
+/*
+ * enable this if your panel appears to have broken
+ */
+#undef CHECK_COMPAT
 
 /*
- *  Debug macros 
+ * debugging?
  */
-//#define DEBUG 
-#ifdef DEBUG
-#  define DPRINTK(fmt, args...)	printk("%s: " fmt, __FUNCTION__ , ## args)
-#else
-#  define DPRINTK(fmt, args...)
-#endif
+#define DEBUG 0
+/*
+ * Complain if VAR is out of range.
+ */
+#define DEBUG_VAR 1
 
+#undef ASSABET_PAL_VIDEO
 
-/* Memory size macros for determining required FrameBuffer size */
-#define MAX_PALETTE_NUM_ENTRIES		256
-#define MAX_PALETTE_MEM_SIZE		(MAX_PALETTE_NUM_ENTRIES * 2)
-#define MAX_PIXEL_MEM_SIZE \
-	((current_par.max_xres * current_par.max_yres * current_par.max_bpp)/8)
-#define MAX_FRAMEBUFFER_MEM_SIZE \
-	(MAX_PIXEL_MEM_SIZE + MAX_PALETTE_MEM_SIZE + 32)
-#define ALLOCATED_FB_MEM_SIZE \
-	(PAGE_ALIGN(MAX_FRAMEBUFFER_MEM_SIZE + PAGE_SIZE * 2))
+#include "sa1100fb.h"
 
-#define SA1100_PALETTE_MEM_SIZE(bpp)	(((bpp)==8?256:16)*2)
-#define SA1100_PALETTE_MODE_VAL(bpp)    (((bpp) & 0x018) << 9)
+void (*sa1100fb_blank_helper)(int blank);
+EXPORT_SYMBOL(sa1100fb_blank_helper);
 
-/* Minimum X and Y resolutions */
-#define MIN_XRES	64
-#define MIN_YRES	64
 
-/* Possible controller_state modes */
-#define LCD_MODE_DISABLED		0    // Controller is disabled and Disable Done received
-#define LCD_MODE_DISABLE_BEFORE_ENABLE	1    // Re-enable after Disable Done IRQ is received
-#define LCD_MODE_ENABLED		2    // Controller is enabled
+#ifdef CHECK_COMPAT
+static void
+sa1100fb_check_shadow(struct sa1100fb_lcd_reg *new_regs,
+			   struct fb_var_screeninfo *var, u_int pcd)
+{
+	struct sa1100fb_lcd_reg shadow;
+	int different = 0;
 
-#define SA1100_NAME	"SA1100"
-#define NR_MONTYPES	1
+	/*
+	 * These machines are good machines!
+	 */
+	if (machine_is_assabet() || machine_is_bitsy())
+		return;
 
-static inline void
-sa1100fb_assabet_set_truecolor(u_int is_true_color)
-{
-#ifdef CONFIG_SA1100_ASSABET
+	/*
+	 * The following ones are bad, bad, bad.
+	 * Please make yours good!
+	 */
+	if (machine_is_pangolin()) {
+		DPRINTK("Configuring Pangolin LCD\n");
+		shadow.lccr0 =
+		    LCCR0_LEN + LCCR0_Color + LCCR0_LDM +
+		    LCCR0_BAM + LCCR0_ERM + LCCR0_Act +
+		    LCCR0_LtlEnd + LCCR0_DMADel(0);
+		shadow.lccr1 =
+		    LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(64) +
+		    LCCR1_BegLnDel(160) + LCCR1_EndLnDel(24);
+		shadow.lccr2 =
+		    LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(7) +
+		    LCCR2_BegFrmDel(7) + LCCR2_EndFrmDel(1);
+		shadow.lccr3 =
+		    LCCR3_PixClkDiv(pcd) + LCCR3_HorSnchH +
+		    LCCR3_VrtSnchH + LCCR3_PixFlEdg + LCCR3_OutEnH;
+
+		DPRINTK("pcd = %x, PixCldDiv(pcd)=%x\n",
+			pcd, LCCR3_PixClkDiv(pcd));
+	}
+	if (machine_is_freebird()) {
+		DPRINTK("Configuring  Freebird LCD\n");
 #if 1
-	// phase 4 or newer Assabet's
-        if (is_true_color)
-		BCR_set(BCR_LCD_12RGB);
-	else
-		BCR_clear(BCR_LCD_12RGB);
+		shadow.lccr0 = 0x00000038;
+		shadow.lccr1 = 0x010108e0;
+		shadow.lccr2 = 0x0000053f;
+		shadow.lccr3 = 0x00000c20;
 #else
-	// older Assabet's
-        if (is_true_color)
-		BCR_clear(BCR_LCD_12RGB);
-	else
-		BCR_set(BCR_LCD_12RGB);
+		shadow.lccr0 =
+		    LCCR0_LEN + LCCR0_Color + LCCR0_Sngl +
+		    LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Pas +
+		    LCCR0_LtlEnd + LCCR0_DMADel(0);
+		/* Check ,Chester */
+		shadow.lccr1 =
+		    LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(5) +
+		    LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9);
+		/* Check ,Chester */
+		shadow.lccr2 =
+		    LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
+		    LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0);
+		/* Check ,Chester */
+		shadow.lccr3 =
+		    LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH +
+		    LCCR3_HorSnchH + LCCR3_ACBsCntOff +
+		    LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(pcd);
+#endif
+	}
+	if (machine_is_brutus()) {
+		DPRINTK("Configuring  Brutus LCD\n");
+		shadow.lccr0 =
+		    LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Pas +
+		    LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+		    LCCR0_DMADel(0);
+		shadow.lccr1 =
+		    LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(3) +
+		    LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101);
+		shadow.lccr2 =
+		    LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
+		    LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0);
+		shadow.lccr3 =
+		    LCCR3_OutEnH + LCCR3_PixRsEdg + LCCR3_VrtSnchH +
+		    LCCR3_HorSnchH + LCCR3_ACBsCntOff +
+		    LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(44);
+	}
+	if (machine_is_huw_webpanel()) {
+		DPRINTK("Configuring  HuW LCD\n");
+		shadow.lccr0 = LCCR0_LEN + LCCR0_Dual + LCCR0_LDM;
+		shadow.lccr1 = LCCR1_DisWdth(var->xres) +
+		    LCCR1_HorSnchWdth(3) +
+		    LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101);
+		shadow.lccr2 = 239 + LCCR2_VrtSnchWdth(1);
+		shadow.lccr3 = 8 + LCCR3_OutEnH +
+		    LCCR3_PixRsEdg + LCCR3_VrtSnchH +
+		    LCCR3_HorSnchH + LCCR3_ACBsCntOff + LCCR3_ACBsDiv(2);
+	}
+#ifdef CONFIG_SA1100_CERF
+	if (machine_is_cerf()) {
+		DPRINTK("Configuring Cerf LCD\n");
+#if defined (CONFIG_CERF_LCD_72_A)
+		shadow.lccr0 =
+		    LCCR0_LEN + LCCR0_Color + LCCR0_Dual +
+		    LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Pas +
+		    LCCR0_LtlEnd + LCCR0_DMADel(0);
+		shadow.lccr1 =
+		    LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(5) +
+		    LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9);
+		shadow.lccr2 =
+		    LCCR2_DisHght(var->yres / 2) + LCCR2_VrtSnchWdth(1) +
+		    LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0);
+		shadow.lccr3 =
+		    LCCR3_OutEnH + LCCR3_PixRsEdg + LCCR3_VrtSnchH +
+		    LCCR3_HorSnchH + LCCR3_ACBsCntOff +
+		    LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(38);
+#elif defined (CONFIG_CERF_LCD_57_A)
+		shadow.lccr0 =
+		    LCCR0_LEN + LCCR0_Color + LCCR0_Sngl +
+		    LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Pas +
+		    LCCR0_LtlEnd + LCCR0_DMADel(0);
+		shadow.lccr1 =
+		    LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(5) +
+		    LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9);
+		shadow.lccr2 =
+		    LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
+		    LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0);
+		shadow.lccr3 =
+		    LCCR3_OutEnH + LCCR3_PixRsEdg + LCCR3_VrtSnchH +
+		    LCCR3_HorSnchH + LCCR3_ACBsCntOff +
+		    LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(38);
+#elif defined (CONFIG_CERF_LCD_38_A)
+		shadow.lccr0 =
+		    LCCR0_LEN + LCCR0_Color + LCCR0_Sngl +
+		    LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Pas +
+		    LCCR0_LtlEnd + LCCR0_DMADel(0);
+		shadow.lccr1 =
+		    LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(5) +
+		    LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9);
+		shadow.lccr2 =
+		    LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
+		    LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0);
+		shadow.lccr3 =
+		    LCCR3_OutEnH + LCCR3_PixRsEdg + LCCR3_VrtSnchH +
+		    LCCR3_HorSnchH + LCCR3_ACBsCntOff +
+		    LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(38);
+#else
+#error "Must have a CerfBoard LCD form factor selected"
+#endif
+	}
+#endif
+	if (machine_is_lart()) {
+		DPRINTK("Configuring LART LCD\n");
+#if defined LART_GREY_LCD
+		shadow.lccr0 =
+		    LCCR0_LEN + LCCR0_Mono + LCCR0_Sngl + LCCR0_Pas +
+		    LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+		    LCCR0_DMADel(0);
+		shadow.lccr1 =
+		    LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(1) +
+		    LCCR1_BegLnDel(4) + LCCR1_EndLnDel(2);
+		shadow.lccr2 =
+		    LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
+		    LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0);
+		shadow.lccr3 =
+		    LCCR3_PixClkDiv(34) + LCCR3_ACBsDiv(512) +
+		    LCCR3_ACBsCntOff + LCCR3_HorSnchH + LCCR3_VrtSnchH;
+#endif
+#if defined LART_COLOR_LCD
+		shadow.lccr0 =
+		    LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
+		    LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+		    LCCR0_DMADel(0);
+		shadow.lccr1 =
+		    LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(2) +
+		    LCCR1_BegLnDel(69) + LCCR1_EndLnDel(8);
+		shadow.lccr2 =
+		    LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(3) +
+		    LCCR2_BegFrmDel(14) + LCCR2_EndFrmDel(4);
+		shadow.lccr3 =
+		    LCCR3_PixClkDiv(34) + LCCR3_ACBsDiv(512) +
+		    LCCR3_ACBsCntOff + LCCR3_HorSnchL + LCCR3_VrtSnchL +
+		    LCCR3_PixFlEdg;
 #endif
+#if defined LART_VIDEO_OUT
+		shadow.lccr0 =
+		    LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
+		    LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+		    LCCR0_DMADel(0);
+		shadow.lccr1 =
+		    LCCR1_DisWdth(640) + LCCR1_HorSnchWdth(95) +
+		    LCCR1_BegLnDel(40) + LCCR1_EndLnDel(24);
+		shadow.lccr2 =
+		    LCCR2_DisHght(480) + LCCR2_VrtSnchWdth(2) +
+		    LCCR2_BegFrmDel(32) + LCCR2_EndFrmDel(11);
+		shadow.lccr3 =
+		    LCCR3_PixClkDiv(8) + LCCR3_ACBsDiv(512) +
+		    LCCR3_ACBsCntOff + LCCR3_HorSnchH + LCCR3_VrtSnchH +
+		    LCCR3_PixFlEdg + LCCR3_OutEnL;
 #endif
+	}
+	if (machine_is_graphicsclient()) {
+		DPRINTK("Configuring GraphicsClient LCD\n");
+		shadow.lccr0 =
+		    LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act;
+		shadow.lccr1 =
+		    LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(9) +
+		    LCCR1_EndLnDel(54) + LCCR1_BegLnDel(54);
+		shadow.lccr2 =
+		    LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(9) +
+		    LCCR2_EndFrmDel(32) + LCCR2_BegFrmDel(24);
+		shadow.lccr3 =
+		    LCCR3_PixClkDiv(10) + LCCR3_ACBsDiv(2) +
+		    LCCR3_ACBsCntOff + LCCR3_HorSnchL + LCCR3_VrtSnchL;
+	}
+	if (machine_is_omnimeter()) {
+		DPRINTK("Configuring  OMNI LCD\n");
+		shadow.lccr0 = LCCR0_LEN | LCCR0_CMS | LCCR0_DPD;
+		shadow.lccr1 =
+		    LCCR1_BegLnDel(10) + LCCR1_EndLnDel(10) +
+		    LCCR1_HorSnchWdth(1) + LCCR1_DisWdth(var->xres);
+		shadow.lccr2 = LCCR2_DisHght(var->yres);
+		shadow.lccr3 =
+		    LCCR3_ACBsDiv(0xFF) + LCCR3_PixClkDiv(44);
+//jca (GetPCD(25) << LCD3_V_PCD);
+	}
+	if (machine_is_xp860()) {
+		DPRINTK("Configuring XP860 LCD\n");
+		shadow.lccr0 =
+		    LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
+		    LCCR0_LtlEnd + LCCR0_LDM + LCCR0_ERM + LCCR0_DMADel(0);
+		shadow.lccr1 =
+		    LCCR1_DisWdth(var->xres) +
+		    LCCR1_HorSnchWdth(var->hsync_len) +
+		    LCCR1_BegLnDel(var->left_margin) +
+		    LCCR1_EndLnDel(var->right_margin);
+		shadow.lccr2 =
+		    LCCR2_DisHght(var->yres) +
+		    LCCR2_VrtSnchWdth(var->vsync_len) +
+		    LCCR2_BegFrmDel(var->upper_margin) +
+		    LCCR2_EndFrmDel(var->lower_margin);
+		shadow.lccr3 =
+		    LCCR3_PixClkDiv(6) + LCCR3_HorSnchL + LCCR3_VrtSnchL;
+	}
+
+	/*
+	 * Ok, since we're calculating these values, we want to know
+	 * if the calculation is correct.  If you see any of these
+	 * messages _PLEASE_ report the incident to me for diagnosis,
+	 * including details about what was happening when the
+	 * messages appeared. --rmk, 30 March 2001
+	 */
+	if (shadow.lccr0 != new_regs->lccr0) {
+		printk(KERN_ERR "LCCR1 mismatch: 0x%08x != 0x%08x\n",
+			shadow.lccr1, new_regs->lccr1);
+		different = 1;
+	}
+	if (shadow.lccr1 != new_regs->lccr1) {
+		printk(KERN_ERR "LCCR1 mismatch: 0x%08x != 0x%08x\n",
+			shadow.lccr1, new_regs->lccr1);
+		different = 1;
+	}
+	if (shadow.lccr2 != new_regs->lccr2) {
+		printk(KERN_ERR "LCCR2 mismatch: 0x%08x != 0x%08x\n",
+			shadow.lccr2, new_regs->lccr2);
+		different = 1;
+	}
+	if (shadow.lccr3 != new_regs->lccr3) {
+		printk(KERN_ERR "LCCR3 mismatch: 0x%08x != 0x%08x\n",
+			shadow.lccr3, new_regs->lccr3);
+		different = 1;
+	}
+	if (different) {
+		printk(KERN_ERR "var: xres=%d hslen=%d lm=%d rm=%d\n",
+			var->xres, var->hsync_len,
+			var->left_margin, var->right_margin);
+		printk(KERN_ERR "var: yres=%d vslen=%d um=%d bm=%d\n",
+			var->yres, var->vsync_len,
+			var->upper_margin, var->lower_margin);
+
+		printk(KERN_ERR "Please report this to Russell King "
+			"<rmk@arm.linux.org.uk>\n");
+	}
+
+	DPRINTK("olccr0 = 0x%08x\n", shadow.lccr0);
+	DPRINTK("olccr1 = 0x%08x\n", shadow.lccr1);
+	DPRINTK("olccr2 = 0x%08x\n", shadow.lccr2);
+	DPRINTK("olccr3 = 0x%08x\n", shadow.lccr3);
 }
+#else
+#define sa1100fb_check_shadow(regs,var,pcd)
+#endif
+
 
-static u_char *VideoMemRegion;
-static u_char *VideoMemRegion_phys;
 
-/* Local LCD controller parameters */
-/* These can be reduced by making better use of fb_var_screeninfo parameters.  */
-/* Several duplicates exist in the two structures. */
-struct sa1100fb_par {
-	u_char		*p_screen_base;
-	u_char		*v_screen_base;
-	u_short		*p_palette_base;
-	u_short		*v_palette_base;
-	unsigned long	screen_size;
-	unsigned int	palette_size;
-	unsigned int	max_xres;
-	unsigned int	max_yres;
-	unsigned int	xres;
-	unsigned int	yres;
-	unsigned int	xres_virtual;
-	unsigned int	yres_virtual;
-	unsigned int	max_bpp;
-	unsigned int	bits_per_pixel;
-	  signed int	montype;
-	unsigned int	currcon;
-	unsigned int	visual;
-	unsigned int	allow_modeset : 1;
-	unsigned int	active_lcd : 1;
-	unsigned int	inv_4bpp : 1;
-	volatile u_char	controller_state;
+/*
+ * IMHO this looks wrong.  In 8BPP, length should be 8.
+ */
+static struct sa1100fb_rgb rgb_8 = {
+	red:	{ offset: 0,  length: 4, },
+	green:	{ offset: 0,  length: 4, },
+	blue:	{ offset: 0,  length: 4, },
+	transp:	{ offset: 0,  length: 0, },
 };
 
-/* Shadows for LCD controller registers */
-struct sa1100fb_lcd_reg {
-	Address	dbar1;
-	Address dbar2;
-	Word	lccr0;
-	Word	lccr1;
-	Word	lccr2;
-	Word	lccr3;
+static struct sa1100fb_rgb def_rgb_16 = {
+	red:	{ offset: 11, length: 5, },
+	green:	{ offset: 5,  length: 6, },
+	blue:	{ offset: 0,  length: 5, },
+	transp:	{ offset: 0,  length: 0, },
 };
 
-/* Fake monspecs to fill in fbinfo structure */
-static struct fb_monspecs monspecs __initdata = {
-	 30000, 70000, 50, 65, 0 	/* Generic */
+#ifdef CONFIG_SA1100_ASSABET
+static struct sa1100fb_mach_info assabet_info __initdata = {
+#ifdef ASSABET_PAL_VIDEO
+	pixclock:	67797,		bpp:		16,
+	xres:		640,		yres:		512,
+
+	hsync_len:	64,		vsync_len:	6,
+	left_margin:	125,		upper_margin:	70,
+	right_margin:	115,		lower_margin:	36,
+
+	sync:		0,
+
+	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg |	LCCR3_ACBsDiv(512),
+#else
+	pixclock:	171521,		bpp:		16,
+	xres:		320,		yres:		240,
+
+	hsync_len:	5,		vsync_len:	1,
+	left_margin:	61,		upper_margin:	3,
+	right_margin:	9,		lower_margin:	0,
+
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg |	LCCR3_ACBsDiv(2),
+#endif
 };
+#endif
 
-static struct display global_disp;	/* Initial (default) Display Settings */
-static struct fb_info fb_info;
-static struct sa1100fb_par current_par;
-static struct fb_var_screeninfo __initdata init_var = {};
-static struct sa1100fb_lcd_reg lcd_shadow;
-
-
-static int  sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);
-static int  sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);
-static int  sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);
-static int  sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);
-static int  sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);
- 
-static int  sa1100fb_switch(int con, struct fb_info *info);
-static void sa1100fb_blank(int blank, struct fb_info *info);
-static int  sa1100fb_map_video_memory(void);
-static int  sa1100fb_activate_var(struct fb_var_screeninfo *var);
-static void sa1100fb_enable_lcd_controller(void);
-static void sa1100fb_disable_lcd_controller(void);
+#ifdef CONFIG_SA1100_BITSY
+static struct sa1100fb_mach_info bitsy_info __initdata = {
+#ifdef CONFIG_IPAQ_H3100
+	pixclock:	0,		bpp:		4,
+	xres:		320,		yres:		240,
+
+	hsync_len:	26,		vsync_len:	41,
+	left_margin:	4,		upper_margin:	0,
+	right_margin:	4,		lower_margin:	0,
+
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	cmap_greyscale:	1,		cmap_static:	1,
+	cmap_inverse:	1,
+
+	lccr0:		LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+#error FIXME
+	/*
+	 * Sorry, this should have read:
+	 * FIXME: please get rid of the PCD and PixClkDiv definitions
+	 * in favour of pixclock. --rmk
+	 */
+#else
+	pixclock:	5722222,	bpp:		16,
+	xres:		320,		yres:		240,
 
-static struct fb_ops sa1100fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	sa1100fb_get_fix,
-	fb_get_var:	sa1100fb_get_var,
-	fb_set_var:	sa1100fb_set_var,
-	fb_get_cmap:	sa1100fb_get_cmap,
-	fb_set_cmap:	sa1100fb_set_cmap,
+	hsync_len:	3,		vsync_len:	3,
+	left_margin:	12,		upper_margin:	10,
+	right_margin:	17,		lower_margin:	1,
+
+	sync:		0,
+
+	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+#endif
 };
 
+static struct sa1100fb_rgb bitsy_rgb_16 = {
+	red:	{ offset: 12, length: 4, },
+	green:	{ offset: 7,  length: 4, },
+	blue:	{ offset: 1,  length: 4, },
+	transp:	{ offset: 0,  length: 0, },
+};
+#endif
 
-/*
- * sa1100fb_palette_write:
- *    Write palette data to the LCD frame buffer's palette area
- */
-static inline void
-sa1100fb_palette_write(u_int regno, u_short pal)
+#ifdef CONFIG_SA1100_BRUTUS
+static struct sa1100fb_mach_info brutus_info __initdata = {
+	pixclock:	0,		bpp:		8,
+	xres:		320,		yres:		240,
+
+	hsync_len:	3,		vsync_len:	1,
+	left_margin:	41,		upper_margin:	0,
+	right_margin:	101,		lower_margin:	0,
+
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
+			LCCR3_PixClkDiv(44),
+};
+#endif
+
+#ifdef CONFIG_SA1100_CERF
+static struct sa1100fb_mach_info cerf_info __initdata = {
+	pixclock:	171521,		bpp:		8,
+#if defined(CONFIG_CERF_LCD_72_A)
+	xres:		640,		yres:		480,
+	lccr0:		LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
+			LCCR3_PixClkDiv(38),
+#elif defined(CONFIG_CERF_LCD_57_A)
+	xres:		320,		yres:		240,
+	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
+			LCCR3_PixClkDiv(38),
+#elif defined(CONFIG_CERF_LCD_38_A)
+	xres:		240,		yres:		320,
+	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
+			LCCR3_PixClkDiv(38),
+#else
+#error "Must have a CerfBoard LCD form factor selected"
+#endif
+
+	hsync_len:	5,		vsync_len:	1,
+	left_margin:	61,		upper_margin:	3,
+	right_margin:	9,		lower_margin:	0,
+
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+};
+#endif
+
+#ifdef CONFIG_SA1100_FREEBIRD
+#warning Please check this carefully
+static struct sa1100fb_mach_info freebird_info __initdata = {
+	pixclock:	171521,		bpp:		16,
+	xres:		240,		yres:		320,
+
+	hsync_len:	3,		vsync_len:	2,
+	left_margin:	2,		upper_margin:	0,
+	right_margin:	2,		lower_margin:	0,
+
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(2),
+};
+
+static struct sa1100fb_rgb freebird_rgb_16 = {
+	red:	{ offset: 8,  length: 4, },
+	green:	{ offset: 4,  length: 4, },
+	blue:	{ offset: 0,  length: 4, },
+	transp:	{ offset: 12, length: 4, },
+};
+#endif
+
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+static struct sa1100fb_mach_info graphicsclient_info __initdata = {
+	pixclock:	0,		bpp:		8,
+	xres:		640,		yres:		480,
+
+	hsync_len:	9,		vsync_len:	9,
+	left_margin:	54,		upper_margin:	24,
+	right_margin:	54,		lower_margin:	32,
+
+	sync:		0,
+
+	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
+			LCCR3_PixClkDiv(10),
+};
+#endif
+
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+static struct sa1100fb_mach_info huw_webpanel_info __initdata = {
+	pixclock:	0,		bpp:		8,
+	xres:		640,		yres:		480,
+
+	hsync_len:	3,		vsync_len:	1,
+	left_margin:	41,		upper_margin:	0,
+	right_margin:	101,		lower_margin:	0,
+
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	lccr0:		LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) | 8,
+#error FIXME
+	/*
+	 * FIXME: please get rid of the '| 8' in preference to an
+	 * LCCR3_PixClkDiv() version. --rmk
+	 */
+};
+#endif
+
+#ifdef LART_GREY_LCD
+static struct sa1100fb_mach_info lart_grey_info __initdata = {
+	pixclock:	150000,		bpp:		4,
+	xres:		320,		yres:		240,
+
+	hsync_len:	1,		vsync_len:	1,
+	left_margin:	4,		upper_margin:	0,
+	right_margin:	2,		lower_margin:	0,
+
+	cmap_greyscale:	1,
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	lccr0:		LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+#ifdef LART_COLOR_LCD
+static struct sa1100fb_mach_info lart_color_info __initdata = {
+	pixclock:	150000,		bpp:		16,
+	xres:		320,		yres:		240,
+
+	hsync_len:	2,		vsync_len:	3,
+	left_margin:	69,		upper_margin:	14,
+	right_margin:	8,		lower_margin:	4,
+
+	sync:		0,
+
+	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+#ifdef LART_VIDEO_OUT
+static struct sa1100fb_mach_info lart_video_info __initdata = {
+	pixclock:	39721,		bpp:		16,
+	xres:		640,		yres:		480,
+
+	hsync_len:	95,		vsync_len:	2,
+	left_margin:	40,		upper_margin:	32,
+	right_margin:	24,		lower_margin:	11,
+
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	lccr3:		LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+
+#ifdef LART_KIT01_LCD
+static struct sa1100fb_mach_info lart_kit01_info __initdata =
 {
-	current_par.v_palette_base[regno] = (regno ? pal : pal | 
-	                                     SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel));
-}
+	pixclock:	63291,		bpp:		16,
+	xres:		640,		yres:		480,
+
+	hsync_len:	64,		vsync_len:	3,
+	left_margin:	122,		upper_margin:	45,
+	right_margin:	10,		lower_margin:	10,
+
+	sync:		0,
+
+	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixFlEdg
+};
+#endif
 
+#ifdef CONFIG_SA1100_OMNIMETER
+static struct sa1100fb_mach_info omnimeter_info __initdata = {
+	pixclock:	0,		bpp:		4,
+	xres:		480,		yres:		320,
+
+	hsync_len:	1,		vsync_len:	1,
+	left_margin:	10,		upper_margin:	0,
+	right_margin:	10,		lower_margin:	0,
+
+	cmap_greyscale:	1,
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	lccr0:		LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_8PixMono,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(255) |
+			LCCR3_PixClkDiv(44),
+#error FIXME: fix pixclock, ACBsDiv
+	/*
+	 * FIXME: I think ACBsDiv is wrong above - should it be 512 (disabled)?
+	 *   - rmk
+	 */
+};
+#endif
+
+#ifdef CONFIG_SA1100_PANGOLIN
+static struct sa1100fb_mach_info pangolin_info __initdata = {
+	pixclock:	341521,		bpp:		16,
+	xres:		800,		yres:		600,
+
+	hsync_len:	64,		vsync_len:	7,
+	left_margin:	160,		upper_margin:	7,
+	right_margin:	24,		lower_margin:	1,
+
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixFlEdg,
+};
+#endif
 
-static inline u_short
-sa1100fb_palette_encode(u_int regno, u_int red, u_int green, u_int blue, u_int trans)
+#ifdef CONFIG_SA1100_XP860
+static struct sa1100fb_mach_info xp860_info __initdata = {
+	pixclock:	0,		bpp:		8,
+	xres:		1024,		yres:		768,
+
+	hsync_len:	3,		vsync_len:	3,
+	left_margin:	3,		upper_margin:	2,
+	right_margin:	2,		lower_margin:	1,
+
+	sync:		0,
+
+	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_PixClkDiv(6),
+};
+#endif
+
+static struct sa1100fb_mach_info * __init
+sa1100fb_get_machine_info(struct sa1100fb_info *fbi)
 {
-	u_int pal;
+	struct sa1100fb_mach_info *inf = NULL;
 
-	if(current_par.bits_per_pixel == 4){
-		/*
-		 * RGB -> luminance is defined to be
-		 * Y =  0.299 * R + 0.587 * G + 0.114 * B
-		 */
-		pal = (19595 * red + 38470 * green + 7471 * blue) >> 28;
-		if( current_par.inv_4bpp )
-			pal = 15 - pal;
+	/*
+	 *            R        G       B       T
+	 * default  {11,5}, { 5,6}, { 0,5}, { 0,0}
+	 * bitsy    {12,4}, { 7,4}, { 1,4}, { 0,0}
+	 * freebird { 8,4}, { 4,4}, { 0,4}, {12,4}
+	 */
+#ifdef CONFIG_SA1100_ASSABET
+	if (machine_is_assabet()) {
+		inf = &assabet_info;
 	}
-	else{
-		pal   = ((red   >>  4) & 0xf00);
-		pal  |= ((green >>  8) & 0x0f0);
-		pal  |= ((blue  >> 12) & 0x00f);
+#endif
+#ifdef CONFIG_SA1100_BITSY
+	if (machine_is_bitsy()) {
+		inf = &bitsy_info;
+		fbi->rgb[RGB_16] = &bitsy_rgb_16;
 	}
-
-	return pal;
-}
-	    
-static inline u_short
-sa1100fb_palette_read(u_int regno)
-{
-	return (current_par.v_palette_base[regno] & 0x0FFF);
+#endif
+#ifdef CONFIG_SA1100_BRUTUS
+	if (machine_is_brutus()) {
+		inf = &brutus_info;
+	}
+#endif
+#ifdef CONFIG_SA1100_CERF
+	if (machine_is_cerf()) {
+		inf = &cerf_info;
+	}
+#endif
+#ifdef CONFIG_SA1100_FREEBIRD
+	if (machine_is_freebird()) {
+		inf = &freebird_info;
+		fbi->rgb[RGB_16] = &freebird_rgb16;
+	}
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+	if (machine_is_graphicsclient()) {
+		inf = &graphicsclient_info;
+	}
+#endif
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+	if (machine_is_huw_webpanel()) {
+		inf = &huw_webpanel_info;
+	}
+#endif
+#ifdef CONFIG_SA1100_LART
+	if (machine_is_lart()) {
+#ifdef LART_GREY_LCD
+		inf = &lart_grey_info;
+#endif
+#ifdef LART_COLOR_LCD
+		inf = &lart_color_info;
+#endif
+#ifdef LART_VIDEO_OUT
+		inf = &lart_video_info;
+#endif
+#ifdef LART_KIT01_LCD
+		inf = &lart_kit01_info;
+#endif
+	}
+#endif
+#ifdef CONFIG_SA1100_OMNIMETER
+	if (machine_is_omnimeter()) {
+		inf = &omnimeter_info;
+	}
+#endif
+#ifdef CONFIG_SA1100_PANGOLIN
+	if (machine_is_pangolin()) {
+		inf = &pangolin_info;
+	}
+#endif
+#ifdef CONFIG_SA1100_XP860
+	if (machine_is_xp860()) {
+		inf = &xp860_info;
+	}
+#endif
+	return inf;
 }
 
+static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *);
+static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state);
 
-static void
-sa1100fb_palette_decode(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans)
+static inline void sa1100fb_schedule_task(struct sa1100fb_info *fbi, u_int state)
 {
-	u_short pal;
+	unsigned long flags;
 
-	pal = sa1100fb_palette_read(regno);
-
-	if( current_par.bits_per_pixel == 4){
-		if( current_par.inv_4bpp )
-			pal = 15 - pal;
-		pal &= 0x000f;
-		pal |= pal << 4;
-		pal |= pal << 8;
-		*blue = *green = *red = pal;
-	}
-	else{
-		*blue   = (pal & 0x000f) << 12;
-		*green  = (pal & 0x00f0) << 8;
-		*red    = (pal & 0x0f00) << 4;
+	local_irq_save(flags);
+	/*
+	 * We need to handle two requests being made at the same time.
+	 * There are two important cases:
+	 *  1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE)
+	 *     We must perform the unblanking, which will do our REENABLE for us.
+	 *  2. When we are blanking, but immediately unblank before we have
+	 *     blanked.  We do the "REENABLE" thing here as well, just to be sure.
+	 */
+	if (fbi->task_state == C_ENABLE && state == C_REENABLE)
+		state = (u_int) -1;
+	if (fbi->task_state == C_DISABLE && state == C_ENABLE)
+		state = C_REENABLE;
+
+	if (state != (u_int)-1) {
+		fbi->task_state = state;
+		schedule_task(&fbi->task);
 	}
-        *trans  = 0;
+	local_irq_restore(flags);
 }
 
-static int
-sa1100fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans, struct fb_info *info)
+/*
+ * Get the VAR structure pointer for the specified console
+ */
+static inline struct fb_var_screeninfo *get_con_var(struct fb_info *info, int con)
 {
-	if (regno >= current_par.palette_size)
-		return 1;
-	
-	sa1100fb_palette_decode(regno, red, green, blue, trans);
-
-	return 0;
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	return (con == fbi->currcon || con == -1) ? &fbi->fb.var : &fb_display[con].var;
 }
 
-
-static int
-sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info)
+/*
+ * Get the DISPLAY structure pointer for the specified console
+ */
+static inline struct display *get_con_display(struct fb_info *info, int con)
 {
-	u_short pal;
-
-	if (regno >= current_par.palette_size)
-		return 1;
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	return (con < 0) ? fbi->fb.disp : &fb_display[con];
+}
 
-	pal = sa1100fb_palette_encode(regno, red, green, blue, trans);
+/*
+ * Get the CMAP pointer for the specified console
+ */
+static inline struct fb_cmap *get_con_cmap(struct fb_info *info, int con)
+{
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	return (con == fbi->currcon || con == -1) ? &fbi->fb.cmap : &fb_display[con].cmap;
+}
 
-	sa1100fb_palette_write(regno, pal);
+static inline u_int
+chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
 
-	return 0;
+/*
+ * Convert bits-per-pixel to a hardware palette PBS value.
+ */
+static inline u_int
+palette_pbs(struct fb_var_screeninfo *var)
+{
+	int ret = 0;
+	switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+	case 4:  ret = 0 << 12;	break;
+#endif
+#ifdef FBCON_HAS_CFB8
+	case 8:  ret = 1 << 12; break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16: ret = 2 << 12; break;
+#endif
+	}
+	return ret;
 }
 
 static int
-sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-		 struct fb_info *info)
+sa1100fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
+		       u_int trans, struct fb_info *info)
 {
-	int err = 0;
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	u_int val, ret = 1;
 
-        DPRINTK("current_par.visual=%d\n", current_par.visual);
-	if (con == current_par.currcon)
-		err = fb_get_cmap(cmap, kspc, sa1100fb_getcolreg, info);
-	else if (fb_display[con].cmap.len)
-		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-	else
-		fb_copy_cmap(fb_default_cmap(current_par.palette_size),
-			     cmap, kspc ? 0 : 2);
-	return err;
+	if (regno < fbi->palette_size) {
+		val = ((red >> 4) & 0xf00);
+		val |= ((green >> 8) & 0x0f0);
+		val |= ((blue >> 12) & 0x00f);
+
+		if (regno == 0)
+			val |= palette_pbs(&fbi->fb.var);
+
+		fbi->palette_cpu[regno] = val;
+		ret = 0;
+	}
+	return ret;
 }
 
 static int
-sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-		  struct fb_info *info)
+sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+		   u_int trans, struct fb_info *info)
 {
-	int err = 0;
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	struct display *disp = get_con_display(info, fbi->currcon);
+	u_int val;
+	int ret = 1;
 
-        DPRINTK("current_par.visual=%d\n", current_par.visual);
-	if (!fb_display[con].cmap.len)
-		err = fb_alloc_cmap(&fb_display[con].cmap,
-				    current_par.palette_size, 0);
-	if (!err) {
-		if (con == current_par.currcon)
-			err = fb_set_cmap(cmap, kspc, sa1100fb_setcolreg,
-					  info);
-		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+	/*
+	 * If inverse mode was selected, invert all the colours
+	 * rather than the register number.  The register number
+	 * is what you poke into the framebuffer to produce the
+	 * colour you requested.
+	 */
+	if (disp->inverse) {
+		red   = 0xffff - red;
+		green = 0xffff - green;
+		blue  = 0xffff - blue;
 	}
-	return err;
-}
 
-static void inline
-sa1100fb_get_par(struct sa1100fb_par *par)
-{
-	*par = current_par;
-}
+	/*
+	 * If greyscale is true, then we convert the RGB value
+	 * to greyscale no mater what visual we are using.
+	 */
+	if (fbi->fb.var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green +
+					7471 * blue) >> 16;
+
+	switch (fbi->fb.disp->visual) {
+	case FB_VISUAL_TRUECOLOR:
+		/*
+		 * 12 or 16-bit True Colour.  We encode the RGB value
+		 * according to the RGB bitfield information.
+		 */
+		if (regno < 16) {
+			u16 *pal = fbi->fb.pseudo_palette;
+
+			val  = chan_to_field(red, &fbi->fb.var.red);
+			val |= chan_to_field(green, &fbi->fb.var.green);
+			val |= chan_to_field(blue, &fbi->fb.var.blue);
 
+			pal[regno] = val;
+			ret = 0;
+		}
+		break;
+
+	case FB_VISUAL_STATIC_PSEUDOCOLOR:
+	case FB_VISUAL_PSEUDOCOLOR:
+		ret = sa1100fb_setpalettereg(regno, red, green, blue, trans, info);
+		break;
+	}
+
+	return ret;
+}
 
 /*
- * sa1100fb_encode_var():
- * 	Modify var structure using values in par
+ *  sa1100fb_display_dma_period()
+ *    Calculate the minimum period (in picoseconds) between two DMA
+ *    requests for the LCD controller.
  */
-static int 
-sa1100fb_encode_var(struct fb_var_screeninfo *var,
-                    struct sa1100fb_par *par)
+static unsigned int
+sa1100fb_display_dma_period(struct fb_var_screeninfo *var)
 {
-        // Don't know if really want to zero var on entry.
-        // Look at set_var to see.  If so, may need to add extra params to par     
-//	memset(var, 0, sizeof(struct fb_var_screeninfo));
- 
-	var->xres = par->xres;
-	var->yres = par->yres;
-	var->xres_virtual = par->xres_virtual;
-	var->yres_virtual = par->yres_virtual;
+	unsigned int mem_bits_per_pixel;
 
-	var->bits_per_pixel = par->bits_per_pixel;
+	mem_bits_per_pixel = var->bits_per_pixel;
+	if (mem_bits_per_pixel == 12)
+		mem_bits_per_pixel = 16;
 
-        DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
-	switch(var->bits_per_pixel) {
-	case 2:
-	case 4:
-	case 8:
-		var->red.length	   = 4;
-		var->green         = var->red;
-		var->blue          = var->red;
-		var->transp.length = 0;
-		break;
-	case 12:          // This case should differ for Active/Passive mode  
-	case 16:
-                if (machine_is_bitsy()) {
-                        var->red.length    = 4;
-                        var->blue.length   = 4;
-                        var->green.length  = 4;
-                        var->transp.length = 0;
-                        var->red.offset    = 12;
-                        var->green.offset  = 7;
-                        var->blue.offset   = 1;
-                        var->transp.offset = 0;
-                } else {
-                        var->red.length    = 5;
-                        var->blue.length   = 5;
-                        var->green.length  = 6;
-                        var->transp.length = 0;
-                        var->red.offset    = 11;
-                        var->green.offset  = 5;
-                        var->blue.offset   = 0;
-                        var->transp.offset = 0;
-                }
-                break;
-	}
-	return 0;
+	/*
+	 * Period = pixclock * bits_per_byte * bytes_per_transfer
+	 *		/ memory_bits_per_pixel;
+	 */
+	return var->pixclock * 8 * 16 / mem_bits_per_pixel;
 }
- 
+
 /*
  *  sa1100fb_decode_var():
  *    Get the video params out of 'var'. If a value doesn't fit, round it up,
@@ -416,867 +1064,1236 @@
  *    bitfields, horizontal timing, vertical timing.
  */
 static int
-sa1100fb_decode_var(struct fb_var_screeninfo *var, 
-                    struct sa1100fb_par *par)
+sa1100fb_validate_var(struct fb_var_screeninfo *var,
+		      struct sa1100fb_info *fbi)
+{
+	int ret = -EINVAL;
+
+	if (var->xres < MIN_XRES)
+		var->xres = MIN_XRES;
+	if (var->yres < MIN_YRES)
+		var->yres = MIN_YRES;
+	if (var->xres > fbi->max_xres)
+		var->xres = fbi->max_xres;
+	if (var->yres > fbi->max_yres)
+		var->yres = fbi->max_yres;
+	var->xres_virtual =
+	    var->xres_virtual < var->xres ? var->xres : var->xres_virtual;
+	var->yres_virtual =
+	    var->yres_virtual < var->yres ? var->yres : var->yres_virtual;
+
+	DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
+	switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+	case 4:		ret = 0; break;
+#endif
+#ifdef FBCON_HAS_CFB8
+	case 8:		ret = 0; break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:	ret = 0; break;
+#endif
+	default:
+		break;
+	}
+
+	printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz",
+		sa1100fb_display_dma_period(var),
+		cpufreq_get(smp_processor_id()));
+
+	return ret;
+}
+
+static inline void sa1100fb_set_truecolor(u_int is_true_color)
+{
+	DPRINTK("true_color = %d\n", is_true_color);
+#ifdef CONFIG_SA1100_ASSABET
+	if (machine_is_assabet()) {
+#if 1
+		// phase 4 or newer Assabet's
+		if (is_true_color)
+			BCR_set(BCR_LCD_12RGB);
+		else
+			BCR_clear(BCR_LCD_12RGB);
+#else
+		// older Assabet's
+		if (is_true_color)
+			BCR_clear(BCR_LCD_12RGB);
+		else
+			BCR_set(BCR_LCD_12RGB);
+#endif
+	}
+#endif
+}
+
+static void
+sa1100fb_hw_set_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
 {
-	u_long palette_mem_phys;
 	u_long palette_mem_size;
 
-	*par = current_par;
+	fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
+
+	palette_mem_size = fbi->palette_size * sizeof(u16);
+
+	DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
+
+	fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
+	fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
+
+	fb_set_cmap(&fbi->fb.cmap, 1, sa1100fb_setcolreg, &fbi->fb);
+
+	/* Set board control register to handle new color depth */
+	sa1100fb_set_truecolor(var->bits_per_pixel >= 16);
+
+#ifdef CONFIG_SA1100_OMNIMETER
+#error Do we have to do this here?   We already do it at init time.
+	if (machine_is_omnimeter())
+		SetLCDContrast(DefaultLCDContrast);
+#endif
+
+	sa1100fb_activate_var(var, fbi);
+
+	fbi->palette_cpu[0] = (fbi->palette_cpu[0] &
+					 0xcfff) | palette_pbs(var);
+
+}
+
+/*
+ * sa1100fb_set_var():
+ *	Set the user defined part of the display for the specified console
+ */
+static int
+sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	struct fb_var_screeninfo *dvar = get_con_var(&fbi->fb, con);
+	struct display *display = get_con_display(&fbi->fb, con);
+	int err, chgvar = 0, rgbidx;
+
+	DPRINTK("set_var\n");
 
-	if ((par->xres = var->xres) < MIN_XRES)
-		par->xres = MIN_XRES; 
-	if ((par->yres = var->yres) < MIN_YRES)
-		par->yres = MIN_YRES;
-	if (par->xres > current_par.max_xres)
-		par->xres = current_par.max_xres;
-	if (par->yres > current_par.max_yres)
-		par->yres = current_par.max_yres; 
-	par->xres_virtual = 
-		var->xres_virtual < par->xres ? par->xres : var->xres_virtual;
-        par->yres_virtual = 
-		var->yres_virtual < par->yres ? par->yres : var->yres_virtual;
-        par->bits_per_pixel = var->bits_per_pixel;
+	/*
+	 * Decode var contents into a par structure, adjusting any
+	 * out of range values.
+	 */
+	err = sa1100fb_validate_var(var, fbi);
+	if (err)
+		return err;
+
+	if (var->activate & FB_ACTIVATE_TEST)
+		return 0;
+
+	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
+		return -EINVAL;
+
+	if (dvar->xres != var->xres)
+		chgvar = 1;
+	if (dvar->yres != var->yres)
+		chgvar = 1;
+	if (dvar->xres_virtual != var->xres_virtual)
+		chgvar = 1;
+	if (dvar->yres_virtual != var->yres_virtual)
+		chgvar = 1;
+	if (dvar->bits_per_pixel != var->bits_per_pixel)
+		chgvar = 1;
+	if (con < 0)
+		chgvar = 0;
 
-        DPRINTK("par->bits_per_pixel=%d\n", par->bits_per_pixel);
-	switch (par->bits_per_pixel) {
+	switch (var->bits_per_pixel) {
 #ifdef FBCON_HAS_CFB4
-        case 4:
-		par->visual = FB_VISUAL_PSEUDOCOLOR;
-		par->palette_size = 16; 
-                break;
+	case 4:
+		if (fbi->cmap_static)
+			display->visual	= FB_VISUAL_STATIC_PSEUDOCOLOR;
+		else
+			display->visual	= FB_VISUAL_PSEUDOCOLOR;
+		display->line_length	= var->xres / 2;
+		display->dispsw		= &fbcon_cfb4;
+		rgbidx			= RGB_8;
+		break;
 #endif
 #ifdef FBCON_HAS_CFB8
 	case 8:
-		par->visual = FB_VISUAL_PSEUDOCOLOR;
-		par->palette_size = 256; 
+		if (fbi->cmap_static)
+			display->visual	= FB_VISUAL_STATIC_PSEUDOCOLOR;
+		else
+			display->visual	= FB_VISUAL_PSEUDOCOLOR;
+		display->line_length	= var->xres;
+		display->dispsw		= &fbcon_cfb8;
+		rgbidx			= RGB_8;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB16
-	case 16:  /* RGB 565 */
-		par->visual = FB_VISUAL_TRUECOLOR;
-		par->palette_size = 0; 
+	case 16:
+		display->visual		= FB_VISUAL_TRUECOLOR;
+		display->line_length	= var->xres * 2;
+		display->dispsw		= &fbcon_cfb16;
+		display->dispsw_data	= fbi->fb.pseudo_palette;
+		rgbidx			= RGB_16;
 		break;
 #endif
 	default:
+		rgbidx = 0;
+		display->dispsw = &fbcon_dummy;
+		break;
+	}
+
+	display->screen_base	= fbi->screen_cpu;
+	display->next_line	= display->line_length;
+	display->type		= fbi->fb.fix.type;
+	display->type_aux	= fbi->fb.fix.type_aux;
+	display->ypanstep	= fbi->fb.fix.ypanstep;
+	display->ywrapstep	= fbi->fb.fix.ywrapstep;
+	display->can_soft_blank	= 1;
+	display->inverse	= fbi->cmap_inverse;
+
+	*dvar			= *var;
+	dvar->activate		&= ~FB_ACTIVATE_ALL;
+
+	/*
+	 * Copy the RGB parameters for this display
+	 * from the machine specific parameters.
+	 */
+	dvar->red		= fbi->rgb[rgbidx]->red;
+	dvar->green		= fbi->rgb[rgbidx]->green;
+	dvar->blue		= fbi->rgb[rgbidx]->blue;
+	dvar->transp		= fbi->rgb[rgbidx]->transp;
+
+	DPRINTK("RGBT length = %d:%d:%d:%d\n",
+		dvar->red.length, dvar->green.length, dvar->blue.length,
+		dvar->transp.length);
+
+	DPRINTK("RGBT offset = %d:%d:%d:%d\n",
+		dvar->red.offset, dvar->green.offset, dvar->blue.offset,
+		dvar->transp.offset);
+
+	/*
+	 * Update the old var.  The fbcon drivers still use this.
+	 * Once they are using fbi->fb.var, this can be dropped.
+	 */
+	display->var = *dvar;
+
+	/*
+	 * If we are setting all the virtual consoles, also set the
+	 * defaults used to create new consoles.
+	 */
+	if (var->activate & FB_ACTIVATE_ALL)
+		fbi->fb.disp->var = *dvar;
+
+	/*
+	 * If the console has changed and the console has defined
+	 * a changevar function, call that function.
+	 */
+	if (chgvar && info && fbi->fb.changevar)
+		fbi->fb.changevar(con);
+
+	/* If the current console is selected, activate the new var. */
+	if (con != fbi->currcon)
+		return 0;
+
+	sa1100fb_hw_set_var(dvar, fbi);
+
+	return 0;
+}
+
+static int
+__do_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+	      struct fb_info *info)
+{
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	struct fb_cmap *dcmap = get_con_cmap(info, con);
+	int err = 0;
+
+	if (con == -1)
+		con = fbi->currcon;
+
+	/* no colormap allocated? (we always have "this" colour map allocated) */
+	if (con >= 0)
+		err = fb_alloc_cmap(&fb_display[con].cmap, fbi->palette_size, 0);
+
+	if (!err && con == fbi->currcon)
+		err = fb_set_cmap(cmap, kspc, sa1100fb_setcolreg, info);
+
+	if (!err)
+		fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
+
+	return err;
+}
+
+static int
+sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+		  struct fb_info *info)
+{
+	struct display *disp = get_con_display(info, con);
+
+	if (disp->visual == FB_VISUAL_TRUECOLOR ||
+	    disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
 		return -EINVAL;
+
+	return __do_set_cmap(cmap, kspc, con, info);
+}
+
+static int
+sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
+{
+	struct display *display = get_con_display(info, con);
+
+	*fix = info->fix;
+
+	fix->line_length = display->line_length;
+	fix->visual	 = display->visual;
+	return 0;
+}
+
+static int
+sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	*var = *get_con_var(info, con);
+	return 0;
+}
+
+static int
+sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
+{
+	struct fb_cmap *dcmap = get_con_cmap(info, con);
+	fb_copy_cmap(dcmap, cmap, kspc ? 0 : 2);
+	return 0;
+}
+
+static struct fb_ops sa1100fb_ops = {
+	owner:		THIS_MODULE,
+	fb_get_fix:	sa1100fb_get_fix,
+	fb_get_var:	sa1100fb_get_var,
+	fb_set_var:	sa1100fb_set_var,
+	fb_get_cmap:	sa1100fb_get_cmap,
+	fb_set_cmap:	sa1100fb_set_cmap,
+};
+
+/*
+ *  sa1100fb_switch():       
+ *	Change to the specified console.  Palette and video mode
+ *      are changed to the console's stored parameters.
+ *
+ *	Uh oh, this can be called from a tasklet (IRQ)
+ */
+static int sa1100fb_switch(int con, struct fb_info *info)
+{
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	struct display *disp;
+	struct fb_cmap *cmap;
+
+	DPRINTK("con=%d info->modename=%s\n", con, fbi->fb.modename);
+
+	if (con == fbi->currcon)
+		return 0;
+
+	if (fbi->currcon >= 0) {
+		disp = fb_display + fbi->currcon;
+
+		/*
+		 * Save the old colormap and video mode.
+		 */
+		disp->var = fbi->fb.var;
+
+		if (disp->cmap.len)
+			fb_copy_cmap(&fbi->fb.cmap, &disp->cmap, 0);
 	}
 
-	palette_mem_size = SA1100_PALETTE_MEM_SIZE(par->bits_per_pixel);
-	palette_mem_phys = (u_long)VideoMemRegion_phys + PAGE_SIZE - palette_mem_size;
-	par->p_palette_base = (u_short *)palette_mem_phys;
-        par->v_palette_base = (u_short *)((u_long)VideoMemRegion + PAGE_SIZE - palette_mem_size);
-	par->p_screen_base  = (u_char *)((u_long)VideoMemRegion_phys + PAGE_SIZE); 
-	par->v_screen_base  = (u_char *)((u_long)VideoMemRegion      + PAGE_SIZE); 
-
-	DPRINTK("p_palette_base = 0x%08lx\n",(u_long)par->p_palette_base);
-	DPRINTK("v_palette_base = 0x%08lx\n",(u_long)par->v_palette_base);
-	DPRINTK("palette_size = 0x%08lx\n",(u_long)par->palette_size);
-	DPRINTK("palette_mem_size = 0x%08lx\n",(u_long)palette_mem_size);
-	DPRINTK("p_screen_base  = 0x%08lx\n",(u_long)par->p_screen_base);
-	DPRINTK("v_screen_base  = 0x%08lx\n",(u_long)par->v_screen_base);
-	DPRINTK("VideoMemRegion = 0x%08lx\n",(u_long)VideoMemRegion);
-	DPRINTK("VideoMemRegion_phys = 0x%08lx\n",(u_long)VideoMemRegion_phys);
+	fbi->currcon = con;
+	disp = fb_display + con;
+
+	/*
+	 * Make sure that our colourmap contains 256 entries.
+	 */
+	fb_alloc_cmap(&fbi->fb.cmap, 256, 0);
+
+	if (disp->cmap.len)
+		cmap = &disp->cmap;
+	else
+		cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
+
+	fb_copy_cmap(cmap, &fbi->fb.cmap, 0);
+
+	fbi->fb.var = disp->var;
+	fbi->fb.var.activate = FB_ACTIVATE_NOW;
+
+	sa1100fb_set_var(&fbi->fb.var, con, info);
+	return 0;
+}
+
+/*
+ * Formal definition of the VESA spec:
+ *  On
+ *  	This refers to the state of the display when it is in full operation
+ *  Stand-By
+ *  	This defines an optional operating state of minimal power reduction with
+ *  	the shortest recovery time
+ *  Suspend
+ *  	This refers to a level of power management in which substantial power
+ *  	reduction is achieved by the display.  The display can have a longer 
+ *  	recovery time from this state than from the Stand-by state
+ *  Off
+ *  	This indicates that the display is consuming the lowest level of power
+ *  	and is non-operational. Recovery from this state may optionally require
+ *  	the user to manually power on the monitor
+ *
+ *  Now, the fbdev driver adds an additional state, (blank), where they
+ *  turn off the video (maybe by colormap tricks), but don't mess with the
+ *  video itself: think of it semantically between on and Stand-By.
+ *
+ *  So here's what we should do in our fbdev blank routine:
+ *
+ *  	VESA_NO_BLANKING (mode 0)	Video on,  front/back light on
+ *  	VESA_VSYNC_SUSPEND (mode 1)  	Video on,  front/back light off
+ *  	VESA_HSYNC_SUSPEND (mode 2)  	Video on,  front/back light off
+ *  	VESA_POWERDOWN (mode 3)		Video off, front/back light off
+ *
+ *  This will match the matrox implementation.
+ */
+/*
+ * sa1100fb_blank():
+ *	Blank the display by setting all palette values to zero.  Note, the 
+ * 	12 and 16 bpp modes don't really use the palette, so this will not
+ *      blank the display in all modes.  
+ */
+static void sa1100fb_blank(int blank, struct fb_info *info)
+{
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	int i;
+
+	DPRINTK("sa1100fb_blank: blank=%d info->modename=%s\n", blank,
+		fbi->fb.modename);
+
+	switch (blank) {
+	case VESA_POWERDOWN:
+	case VESA_VSYNC_SUSPEND:
+	case VESA_HSYNC_SUSPEND:
+		if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR ||
+		    fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+			for (i = 0; i < fbi->palette_size; i++)
+				sa1100fb_setpalettereg(i, 0, 0, 0, 0, info);
+		sa1100fb_schedule_task(fbi, C_DISABLE);
+		if (sa1100fb_blank_helper)
+			sa1100fb_blank_helper(blank);
+		break;
+
+	case VESA_NO_BLANKING:
+		if (sa1100fb_blank_helper)
+			sa1100fb_blank_helper(blank);
+		if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR ||
+		    fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+			fb_set_cmap(&fbi->fb.cmap, 1, sa1100fb_setcolreg, info);
+		sa1100fb_schedule_task(fbi, C_ENABLE);
+	}
+}
+
+static int sa1100fb_updatevar(int con, struct fb_info *info)
+{
+	DPRINTK("entered\n");
+	return 0;
+}
+
+/*
+ * Calculate the PCD value from the clock rate (in picoseconds).
+ * We take account of the PPCR clock setting.
+ */
+static inline int get_pcd(unsigned int pixclock)
+{
+	unsigned int pcd;
 
-	return 0;
+	if (pixclock) {
+		pcd = get_cclk_frequency() * pixclock;
+		pcd /= 10000000;
+		pcd += 1;	/* make up for integer math truncations */
+	} else {
+		/*
+		 * People seem to be missing this message.  Make it big.
+		 * Make it stand out.  Make sure people see it.
+		 */
+		printk(KERN_WARNING "******************************************************\n");
+		printk(KERN_WARNING "**            ZERO PIXEL CLOCK DETECTED             **\n");
+		printk(KERN_WARNING "** You are using a zero pixclock.  This means that  **\n");
+		printk(KERN_WARNING "** clock scaling will not be able to adjust your    **\n");
+		printk(KERN_WARNING "** your timing parameters appropriately, and the    **\n");
+		printk(KERN_WARNING "** bandwidth calculations will fail to work.  This  **\n");
+		printk(KERN_WARNING "** will shortly become an error condition, which    **\n");
+		printk(KERN_WARNING "** will prevent your LCD display working.  Please   **\n");
+		printk(KERN_WARNING "** send your patches in as soon as possible to shut **\n");
+		printk(KERN_WARNING "** this message up.                                 **\n");
+		printk(KERN_WARNING "******************************************************\n");
+		pcd = 0;
+	}
+	return pcd;
 }
 
-static int
-sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+/*
+ * sa1100fb_activate_var():
+ *	Configures LCD Controller based on entries in var parameter.  Settings are      
+ *      only written to the controller if changes were made.  
+ */
+static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
 {
-	struct sa1100fb_par par;
+	struct sa1100fb_lcd_reg new_regs;
+	u_int half_screen_size, yres, pcd = get_pcd(var->pixclock);
+	u_long flags;
+
+	DPRINTK("Configuring SA1100 LCD\n");
+
+	DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n",
+		var->xres, var->hsync_len,
+		var->left_margin, var->right_margin);
+	DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n",
+		var->yres, var->vsync_len,
+		var->upper_margin, var->lower_margin);
+
+#if DEBUG_VAR
+	if (var->xres < 16        || var->xres > 1024)
+		printk(KERN_ERR "%s: invalid xres %d\n",
+			fbi->fb.fix.id, var->xres);
+	if (var->hsync_len < 1    || var->hsync_len > 64)
+		printk(KERN_ERR "%s: invalid hsync_len %d\n",
+			fbi->fb.fix.id, var->hsync_len);
+	if (var->left_margin < 1  || var->left_margin > 255)
+		printk(KERN_ERR "%s: invalid left_margin %d\n",
+			fbi->fb.fix.id, var->left_margin);
+	if (var->right_margin < 1 || var->right_margin > 255)
+		printk(KERN_ERR "%s: invalid right_margin %d\n",
+			fbi->fb.fix.id, var->right_margin);
+	if (var->yres < 1         || var->yres > 1024)
+		printk(KERN_ERR "%s: invalid yres %d\n",
+			fbi->fb.fix.id, var->yres);
+	if (var->vsync_len < 1    || var->vsync_len > 64)
+		printk(KERN_ERR "%s: invalid vsync_len %d\n",
+			fbi->fb.fix.id, var->vsync_len);
+	if (var->upper_margin < 0 || var->upper_margin > 255)
+		printk(KERN_ERR "%s: invalid upper_margin %d\n",
+			fbi->fb.fix.id, var->upper_margin);
+	if (var->lower_margin < 0 || var->lower_margin > 255)
+		printk(KERN_ERR "%s: invalid lower_margin %d\n",
+			fbi->fb.fix.id, var->lower_margin);
+#endif
+
+	new_regs.lccr0 = fbi->lccr0 |
+		LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
+		LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
+
+	new_regs.lccr1 =
+		LCCR1_DisWdth(var->xres) +
+		LCCR1_HorSnchWdth(var->hsync_len) +
+		LCCR1_BegLnDel(var->left_margin) +
+		LCCR1_EndLnDel(var->right_margin);
+
+	/*
+	 * If we have a dual scan LCD, then we need to halve
+	 * the YRES parameter.
+	 */
+	yres = var->yres;
+	if (fbi->lccr0 & LCCR0_Dual)
+		yres /= 2;
+
+	new_regs.lccr2 =
+		LCCR2_DisHght(yres) +
+		LCCR2_VrtSnchWdth(var->vsync_len) +
+		LCCR2_BegFrmDel(var->upper_margin) +
+		LCCR2_EndFrmDel(var->lower_margin);
+
+	new_regs.lccr3 = fbi->lccr3 |
+		(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
+		(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL) |
+		LCCR3_ACBsCntOff;
+
+	if (pcd)
+		new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
+
+	sa1100fb_check_shadow(&new_regs, var, pcd);
+
+	DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0);
+	DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1);
+	DPRINTK("nlccr2 = 0x%08x\n", new_regs.lccr2);
+	DPRINTK("nlccr3 = 0x%08x\n", new_regs.lccr3);
+
+	half_screen_size = var->bits_per_pixel;
+	half_screen_size = half_screen_size * var->xres * var->yres / 16;
+
+	/* Update shadow copy atomically */
+	local_irq_save(flags);
+	fbi->dbar1 = fbi->palette_dma;
+	fbi->dbar2 = fbi->screen_dma + half_screen_size;
+
+	fbi->reg_lccr0 = new_regs.lccr0;
+	fbi->reg_lccr1 = new_regs.lccr1;
+	fbi->reg_lccr2 = new_regs.lccr2;
+	fbi->reg_lccr3 = new_regs.lccr3;
+	local_irq_restore(flags);
 
-        DPRINTK("con=%d\n", con);
-	if (con == -1) {
-		sa1100fb_get_par(&par);
-		sa1100fb_encode_var(var, &par);
-	} else
-		*var = fb_display[con].var;
+	/*
+	 * Only update the registers if the controller is enabled
+	 * and something has changed.
+	 */
+	if ((LCCR0 != fbi->reg_lccr0)       || (LCCR1 != fbi->reg_lccr1) ||
+	    (LCCR2 != fbi->reg_lccr2)       || (LCCR3 != fbi->reg_lccr3) ||
+	    (DBAR1 != (Address) fbi->dbar1) || (DBAR2 != (Address) fbi->dbar2))
+		sa1100fb_schedule_task(fbi, C_REENABLE);
 
 	return 0;
 }
 
 /*
- * sa1100fb_set_var():
- *	Set the user defined part of the display for the specified console
+ * NOTE!  The following functions are purely helpers for set_ctrlr_state.
+ * Do not call them directly; set_ctrlr_state does the correct serialisation
+ * to ensure that things happen in the right way 100% of time time.
+ *	-- rmk
  */
-static int
-sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+
+/*
+ * FIXME: move LCD power stuff into sa1100fb_power_up_lcd()
+ * Also, I'm expecting that the backlight stuff should
+ * be handled differently.
+ */
+static void sa1100fb_backlight_on(struct sa1100fb_info *fbi)
 {
-	struct display *display;
-	int err, chgvar = 0;
-	struct sa1100fb_par par;
+	DPRINTK("backlight on\n");
 
-	if (con >= 0)
-		display = &fb_display[con]; /* Display settings for console */
-	else
-		display = &global_disp;     /* Default display settings */
+#ifdef CONFIG_SA1100_FREEBIRD
+#error FIXME
+	if (machine_is_freebird()) {
+		BCR_set(BCR_FREEBIRD_LCD_PWR | BCR_FREEBIRD_LCD_DISP);
+	}
+#endif
+#ifdef CONFIG_SA1100_FREEBIRD
+	if (machine_is_freebird()) {
+		/* Turn on backlight ,Chester */
+		BCR_set(BCR_FREEBIRD_LCD_BACKLIGHT);
+	}
+#endif
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+#error FIXME
+	if (machine_is_huw_webpanel()) {
+		BCR_set(BCR_CCFL_POW + BCR_PWM_BACKLIGHT);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_task(200 * HZ / 1000);
+		BCR_set(BCR_TFT_ENA);
+	}
+#endif
+#ifdef CONFIG_SA1100_OMNIMETER
+	if (machine_is_omnimeter())
+		LEDBacklightOn();
+#endif
+#ifdef CONFIG_SA1100_BITSY
+	/* what rmk said --dneuer */
+#endif
+}
 
-	/* Decode var contents into a par structure, adjusting any */
-	/* out of range values. */
-	if ((err = sa1100fb_decode_var(var, &par)))
-		return err;
-	// Store adjusted par values into var structure
-	sa1100fb_encode_var(var, &par);
-       
-	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
-		return 0;
-	else if (((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) && 
-		 ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NXTOPEN))
-		return -EINVAL;
+/*
+ * FIXME: move LCD power stuf into sa1100fb_power_down_lcd()
+ * Also, I'm expecting that the backlight stuff should
+ * be handled differently.
+ */
+static void sa1100fb_backlight_off(struct sa1100fb_info *fbi)
+{
+	DPRINTK("backlight off\n");
 
-	if (con >= 0) {
-		if ((display->var.xres != var->xres) ||
-		    (display->var.yres != var->yres) ||
-		    (display->var.xres_virtual != var->xres_virtual) ||
-		    (display->var.yres_virtual != var->yres_virtual) ||
-		    (display->var.sync != var->sync)                 ||
-                    (display->var.bits_per_pixel != var->bits_per_pixel) ||
-		    (memcmp(&display->var.red, &var->red, sizeof(var->red))) ||
-		    (memcmp(&display->var.green, &var->green, sizeof(var->green))) ||
-		    (memcmp(&display->var.blue, &var->blue, sizeof(var->blue)))) 
-			chgvar = 1;
-	}
-
-	display->var = *var;
-	display->screen_base	= par.v_screen_base;
-	display->visual		= par.visual;
-	display->type		= FB_TYPE_PACKED_PIXELS;
-	display->type_aux	= 0;
-	display->ypanstep	= 0;
-	display->ywrapstep	= 0;
-	display->line_length	= 
-	display->next_line      = (var->xres * var->bits_per_pixel) / 8;
+#ifdef CONFIG_SA1100_FREEBIRD
+#error FIXME
+	if (machine_is_freebird()) {
+		BCR_clear(BCR_FREEBIRD_LCD_PWR | BCR_FREEBIRD_LCD_DISP
+			  /*| BCR_FREEBIRD_LCD_BACKLIGHT */ );
+	}
+#endif
+#ifdef CONFIG_SA1100_OMNIMETER
+	if (machine_is_omnimeter())
+		LEDBacklightOff();
+#endif
+#ifdef CONFIG_SA1100_BITSY
+	/* what rmk said --dneuer */
+#endif
+}
 
-	display->can_soft_blank	= 1;
-	display->inverse	= 0;
+static void sa1100fb_power_up_lcd(struct sa1100fb_info *fbi)
+{
+	DPRINTK("LCD power on\n");
 
-	switch (display->var.bits_per_pixel) {
-#ifdef FBCON_HAS_CFB4
-        case 4:
-		display->dispsw = &fbcon_cfb4;
-		break;
+#if defined(CONFIG_SA1100_ASSABET) && !defined(ASSABET_PAL_VIDEO)
+	if (machine_is_assabet())
+		BCR_set(BCR_LCD_ON);
 #endif
-#ifdef FBCON_HAS_CFB8
-	case 8: 
-		display->dispsw = &fbcon_cfb8;
-		break;
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+	if (machine_is_huw_webpanel())
+		BCR_clear(BCR_TFT_NPWR);
 #endif
-#ifdef FBCON_HAS_CFB16
-	case 16:
-		display->dispsw = &fbcon_cfb16;
-		break;
+#ifdef CONFIG_SA1100_OMNIMETER
+	if (machine_is_omnimeter())
+		LCDPowerOn();
 #endif
-	default:
-		display->dispsw = &fbcon_dummy;
-		break;
+#ifdef CONFIG_SA1100_BITSY
+	if (machine_is_bitsy()) {
+		set_bitsy_egpio(EGPIO_BITSY_LCD_ON |
+				EGPIO_BITSY_LCD_PCI |
+				EGPIO_BITSY_LCD_5V_ON |
+				EGPIO_BITSY_LVDD_ON);
 	}
+#endif
+}
 
-	/* If the console has changed and the console has defined */
-	/* a changevar function, call that function. */
-	if (chgvar && info && info->changevar)
-		info->changevar(con);
-
-        /* If the current console is selected and it's not truecolor, 
-	 *  update the palette 
-	 */
-	if ((con == current_par.currcon) &&
-	    (current_par.visual != FB_VISUAL_TRUECOLOR)) {
-		struct fb_cmap *cmap;
-		
-		current_par = par;
-		if (display->cmap.len)
-			cmap = &display->cmap;
-		else
-			cmap = fb_default_cmap(current_par.palette_size);
+static void sa1100fb_power_down_lcd(struct sa1100fb_info *fbi)
+{
+	DPRINTK("LCD power off\n");
 
-		fb_set_cmap(cmap, 1, sa1100fb_setcolreg, info);
+#if defined(CONFIG_SA1100_ASSABET) && !defined(ASSABET_PAL_VIDEO)
+	if (machine_is_assabet())
+		BCR_clear(BCR_LCD_ON);
+#endif
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+	// dont forget to set the control lines to zero (?)
+	if (machine_is_huw_webpanel())
+		BCR_set(BCR_TFT_NPWR);
+#endif
+#ifdef CONFIG_SA1100_BITSY
+	if (machine_is_bitsy()) {
+		clr_bitsy_egpio(EGPIO_BITSY_LCD_ON |
+				EGPIO_BITSY_LCD_PCI |
+				EGPIO_BITSY_LCD_5V_ON |
+				EGPIO_BITSY_LVDD_ON);
 	}
-
-	/* If the current console is selected, activate the new var. */
-	if (con == current_par.currcon)
-		sa1100fb_activate_var(var);
-	
-	return 0;
+#endif
 }
 
-static int
-sa1100fb_updatevar(int con, struct fb_info *info)
+static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
 {
-	DPRINTK("entered\n");
-	return 0;
-}
+	u_int mask = 0;
 
-static int
-sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
-{
-	struct display *display;
+	/*
+	 * Enable GPIO<9:2> for LCD use if:
+	 *  1. Active display, or
+	 *  2. Color Dual Passive display
+	 *
+	 * see table 11.8 on page 11-27 in the SA1100 manual
+	 *   -- Erik.
+	 *
+	 * SA1110 spec update nr. 25 says we can and should
+	 * clear LDD15 to 12 for 4 or 8bpp modes with active
+	 * panels.  
+	 */
+	if ((fbi->reg_lccr0 & LCCR0_CMS) == LCCR0_Color &&
+	    (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) {
+		mask = GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9  | GPIO_LDD8;
+
+		if (fbi->fb.var.bits_per_pixel > 8 ||
+		    (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual)
+			mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12;
 
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-	strcpy(fix->id, SA1100_NAME);
+	}
 
-	if (con >= 0)
-	{
-		DPRINTK("Using console specific display for con=%d\n",con);
-		display = &fb_display[con];  /* Display settings for console */
+#ifdef CONFIG_SA1100_FREEBIRD
+#error Please contact <rmk@arm.linux.org.uk> about this
+	if (machine_is_freebird()) {
+		/* Color single passive */
+		mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
+			GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9  | GPIO_LDD8;
 	}
-	else
-		display = &global_disp;      /* Default display settings */
+#endif
+#ifdef CONFIG_SA1100_CERF
+#error Please contact <rmk@arm.linux.org.uk> about this
+	if (machine_is_cerf()) {
+		/* GPIO15 is used as a bypass for 3.8" displays */
+		mask |= GPIO_GPIO15;
+
+		/* FIXME: why is this? The Cerf's display doesn't seem
+		 * to be dual scan or active. I just leave it here,
+		 * but in my opinion this is definitively wrong.
+		 *  -- Erik <J.A.K.Mouw@its.tudelft.nl>
+		 */
 
-	fix->smem_start	 = (unsigned long)current_par.p_screen_base;
-	fix->smem_len	 = current_par.screen_size;
-	fix->type	 = display->type;
-	fix->type_aux	 = display->type_aux;
-	fix->xpanstep	 = 0;
-	fix->ypanstep	 = display->ypanstep;
-	fix->ywrapstep	 = display->ywrapstep;
-	fix->visual	 = display->visual;
-	fix->line_length = display->line_length;
-	fix->accel	 = FB_ACCEL_NONE;
+		/* REPLY: Umm.. Well to be honest, the 5.7" LCD which
+		 * this was used for does not use these pins, but
+		 * apparently all hell breaks loose if they are not
+		 * set on the Cerf, so we decided to leave them in ;)
+		 *  -- Daniel Chemko <dchemko@intrinsyc.com>
+		 */
+		/* color {dual/single} passive */
+		mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
+			GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9  | GPIO_LDD8;
+	}
+#endif
 
-	return 0;
+	if (mask) {
+		GPDR |= mask;
+		GAFR |= mask;
+	}
 }
 
-
-static void
-__init sa1100fb_init_fbinfo(void)
+static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
 {
-	strcpy(fb_info.modename, SA1100_NAME);
-	strcpy(fb_info.fontname, "Acorn8x8");
-
-	fb_info.node		= -1;
-	fb_info.flags		= FBINFO_FLAG_DEFAULT;
-	fb_info.fbops		= &sa1100fb_ops;
-        fb_info.monspecs	= monspecs;
-	fb_info.disp		= &global_disp;
-	fb_info.changevar	= NULL;
-	fb_info.switch_con	= sa1100fb_switch;
-	fb_info.updatevar	= sa1100fb_updatevar;
-	fb_info.blank		= sa1100fb_blank;
-
-	/*
-	 * setup initial parameters
-	 */
-	memset(&init_var, 0, sizeof(init_var));
-
-	init_var.transp.length	= 0;
-	init_var.nonstd		= 0;
-	init_var.activate	= FB_ACTIVATE_NOW;
-	init_var.xoffset	= 0;
-	init_var.yoffset	= 0;
-	init_var.height		= -1;
-	init_var.width		= -1;
-	init_var.vmode		= FB_VMODE_NONINTERLACED;
+	DPRINTK("Enabling LCD controller\n");
 
-	if (machine_is_assabet()) {
-		current_par.max_xres	= 320;
-		current_par.max_yres	= 240;
-		current_par.max_bpp	= 16;
-		init_var.red.length	= 5;				
-		init_var.green.length	= 6;
-		init_var.blue.length	= 5;
-		init_var.grayscale	= 0;
-		init_var.sync		= 0;
-		init_var.pixclock	= 171521;
-	} else if (machine_is_cerf()) {
-		current_par.max_xres	= 320;
-		current_par.max_yres	= 240;
-		current_par.max_bpp	= 8;
-		init_var.red.length	= 4;				
-		init_var.green.length	= 4;
-		init_var.blue.length	= 4;
-		init_var.grayscale	= 0;
-		init_var.sync		= 0;
-		init_var.pixclock	= 171521;
-	} else if (machine_is_pangolin()) {
-		current_par.max_xres	= 1024;
-		current_par.max_yres	= 768;
-		current_par.max_bpp	= 16;
-		init_var.red.length	= 5;
-		init_var.green.length	= 6;
-		init_var.blue.length	= 5;
-		init_var.grayscale	= 0;
-		init_var.sync		= 0;	
-		init_var.pixclock	= 15400;
-	} else if (machine_is_bitsy()) {
-		current_par.max_xres	= 320;
-		current_par.max_yres	= 240;
-		current_par.max_bpp	= 16;
-		init_var.red.length	= 4;
-		init_var.green.length	= 4;
-		init_var.blue.length	= 4;
-		init_var.red.offset	= 12;
-		init_var.green.offset	= 7;
-		init_var.blue.offset	= 1;
-		init_var.grayscale	= 0;
-	} else if (machine_is_brutus()) {
-		current_par.max_xres	= 320;
-		current_par.max_yres	= 240;
-		current_par.max_bpp	= 8;
-		init_var.red.length	= 4;				
-		init_var.green		= init_var.red;
-		init_var.blue		= init_var.red;
-		init_var.sync		= 0;
-	} else if (machine_is_lart()) {
-		current_par.max_xres	= 320;
-		current_par.max_yres	= 240;
-		current_par.max_bpp	= 4;
-		init_var.red.length	= 4;				
-		init_var.green		= init_var.red;
-		init_var.blue		= init_var.red;
-		init_var.grayscale	= 1;
-		init_var.pixclock	= 150000;	
-		init_var.sync		= 0;
-	} else if (machine_is_graphicsclient()) {
-		current_par.max_xres	= 640;
-		current_par.max_yres	= 480;
-		current_par.max_bpp	= 8;
-		init_var.red.length	= 4;				
-		init_var.green		= init_var.red;
-		init_var.blue		= init_var.red;
-		init_var.sync		= 0;
-	} else if (machine_is_xp860()) {
-		current_par.max_xres	= 1024;
-		current_par.max_yres	= 768;
-
-		current_par.max_bpp	= 8;
-		init_var.red.length	= 4;
-		init_var.green		= init_var.red;
-		init_var.blue		= init_var.red;
-
-		init_var.hsync_len	= 4;
-		init_var.left_margin	= 3;
-		init_var.right_margin	= 2;
-
-		init_var.vsync_len	= 3;
-		init_var.upper_margin	= 2;
-		init_var.lower_margin	= 1;
-		
-	}
-
-	current_par.p_palette_base	= NULL;
-	current_par.v_palette_base	= NULL;
-	current_par.p_screen_base	= NULL;
-	current_par.v_screen_base	= NULL;
-	current_par.palette_size	= MAX_PALETTE_NUM_ENTRIES;
-	current_par.screen_size		= MAX_PIXEL_MEM_SIZE;
-	current_par.montype		= -1;
-	current_par.currcon		= -1;
-	current_par.allow_modeset	=  1;
-	current_par.controller_state	= LCD_MODE_DISABLED;
-
-	init_var.xres			= current_par.max_xres;
-	init_var.yres			= current_par.max_yres;
-	init_var.xres_virtual		= init_var.xres;
-	init_var.yres_virtual		= init_var.yres;
-	init_var.bits_per_pixel		= current_par.max_bpp;
-			
-}
+	/*
+	 * Make sure the mode bits are present in the first palette entry
+	 */
+	fbi->palette_cpu[0] &= 0xcfff;
+	fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
 
+	/* Sequence from 11.7.10 */
+	LCCR3 = fbi->reg_lccr3;
+	LCCR2 = fbi->reg_lccr2;
+	LCCR1 = fbi->reg_lccr1;
+	LCCR0 = fbi->reg_lccr0 & ~LCCR0_LEN;
+	DBAR1 = (Address) fbi->dbar1;
+	DBAR2 = (Address) fbi->dbar2;
+	LCCR0 |= LCCR0_LEN;
+
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+#error Where is GPIO24 set as an output?  Can we fit this in somewhere else?
+	if (machine_is_graphicsclient()) {
+		// From ADS doc again...same as disable
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(20 * HZ / 1000);
+		GPSR |= GPIO_GPIO24;
+	}
+#endif
 
+	DPRINTK("DBAR1 = %p\n", DBAR1);
+	DPRINTK("DBAR2 = %p\n", DBAR2);
+	DPRINTK("LCCR0 = 0x%08x\n", LCCR0);
+	DPRINTK("LCCR1 = 0x%08x\n", LCCR1);
+	DPRINTK("LCCR2 = 0x%08x\n", LCCR2);
+	DPRINTK("LCCR3 = 0x%08x\n", LCCR3);
+}
 
-/*
- * sa1100fb_map_video_memory():
- *      Allocates the DRAM memory for the frame buffer.  This buffer is  
- *	remapped into a non-cached, non-buffered, memory region to  
- *      allow palette and pixel writes to occur without flushing the 
- *      cache.  Once this area is remapped, all virtual memory
- *      access to the video memory should occur at the new region.
- */
-static int
-__init sa1100fb_map_video_memory(void)
+static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
 {
-	u_int  required_pages;
-	u_int  extra_pages;
-	u_int  order;
-        struct page *page;
-        char   *allocated_region;
+	DECLARE_WAITQUEUE(wait, current);
 
-	if (VideoMemRegion != NULL)
-		return -EINVAL;
+	DPRINTK("Disabling LCD controller\n");
 
-	DPRINTK("-1-");
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+#error Where is GPIO24 set as an output?  Can we fit this in somewhere else?
+	if (machine_is_graphicsclient()) {
+		/*
+		 * From ADS internal document:
+		 *  GPIO24 should be LOW at least 10msec prior to disabling
+		 *  the LCD interface.
+		 *
+		 * We'll wait 20msec.
+		 */
+		GPCR |= GPIO_GPIO24;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(20 * HZ / 1000);
+	}
+#endif
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+#error Move me into sa1100fb_power_up_lcd and/or sa1100fb_backlight_on
+	if (machine_is_huw_webpanel()) {
+		// dont forget to set the control lines to zero (?)
+		DPRINTK("ShutDown HuW LCD controller\n");
+		BCR_clear(BCR_TFT_ENA + BCR_CCFL_POW + BCR_PWM_BACKLIGHT);
+	}
+#endif
 
-	/* Find order required to allocate enough memory for framebuffer */
-	required_pages = ALLOCATED_FB_MEM_SIZE >> PAGE_SHIFT;
-        for (order = 0 ; required_pages >> order ; order++) {;}
-        extra_pages = (1 << order) - required_pages;
-
-        if ((allocated_region = 
-             (char *)__get_free_pages(GFP_KERNEL | GFP_DMA, order)) == NULL)
-           return -ENOMEM;
-
-        VideoMemRegion = (u_char *)allocated_region + (extra_pages << PAGE_SHIFT); 
-        VideoMemRegion_phys = (u_char *)__virt_to_phys((u_long)VideoMemRegion);
-
-	/* Free all pages that we don't need but were given to us because */
-	/* __get_free_pages() works on powers of 2. */
-	for (;extra_pages;extra_pages--)
-          free_page((u_int)allocated_region + ((extra_pages-1) << PAGE_SHIFT));
-
-        /* Set reserved flag for fb memory to allow it to be remapped into */
-        /* user space by the common fbmem driver using remap_page_range(). */
-	for(page = virt_to_page(VideoMemRegion); 
-	    page < virt_to_page(VideoMemRegion + ALLOCATED_FB_MEM_SIZE); page++)
-	  mem_map_reserve(page);
-
-	/* Remap the fb memory to a non-buffered, non-cached region */
-	VideoMemRegion = (u_char *)__ioremap((u_long)VideoMemRegion_phys,
-					     ALLOCATED_FB_MEM_SIZE,
-					     L_PTE_PRESENT  |
-					     L_PTE_YOUNG    |
-					     L_PTE_DIRTY    |
-					     L_PTE_WRITE);
-	return (VideoMemRegion == NULL ? -EINVAL : 0);
-}
-
-static const int frequency[16] = {
-	59000000,
-        73700000,
-        88500000,
-        103200000,
-        118000000,
-        132700000,
-        147500000,
-        162200000,
-        176900000,
-        191700000,
-        206400000, 
-	230000000,
-	245000000,
-	260000000,
-	275000000,
-	290000000
-};
+	add_wait_queue(&fbi->ctrlr_wait, &wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
 
+	LCSR = 0xffffffff;	/* Clear LCD Status Register */
+	LCCR0 &= ~LCCR0_LDM;	/* Enable LCD Disable Done Interrupt */
+	enable_irq(IRQ_LCD);	/* Enable LCD IRQ */
+	LCCR0 &= ~LCCR0_LEN;	/* Disable LCD Controller */
+
+	schedule_timeout(20 * HZ / 1000);
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&fbi->ctrlr_wait, &wait);
+}
 
-static inline int get_pcd(unsigned int pixclock)
+/*
+ *  sa1100fb_handle_irq: Handle 'LCD DONE' interrupts.
+ */
+static void sa1100fb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
-	unsigned int pcd = 0;
+	struct sa1100fb_info *fbi = dev_id;
+	unsigned int lcsr = LCSR;
 
-	if (machine_is_assabet() | machine_is_pangolin()) {
-		pcd = frequency[PPCR & 0xf] / 1000;
-		pcd *= pixclock / 1000;
-		pcd = pcd / 1000000;
-		pcd++; /* make up for integer math truncations */
+	if (lcsr & LCSR_LDD) {
+		LCCR0 |= LCCR0_LDM;
+		wake_up(&fbi->ctrlr_wait);
 	}
-	return pcd;
-}
 
+	LCSR = lcsr;
+}
 
 /*
- * sa1100fb_activate_var():
- *	Configures LCD Controller based on entries in var parameter.  Settings are      
- *      only written to the controller if changes were made.  
+ * This function must be called from task context only, since it will
+ * sleep when disabling the LCD controller, or if we get two contending
+ * processes trying to alter state.
  */
-static int
-sa1100fb_activate_var(struct fb_var_screeninfo *var)
-{						       
-	u_long	flags;
-	int pcd = get_pcd(var->pixclock);
-
-	DPRINTK("Configuring  SA1100 LCD\n");
+static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
+{
+	u_int old_state;
 
-	if (current_par.p_palette_base == NULL)
-		return -EINVAL;
+	down(&fbi->ctrlr_sem);
 
-	DPRINTK("activating\n");
+	old_state = fbi->state;
 
-	/* Disable interrupts and save status */
-	local_irq_save(flags);		// disable the interrupts and save flags
+	switch (state) {
+	case C_DISABLE_CLKCHANGE:
+		/*
+		 * Disable controller for clock change.  If the
+		 * controller is already disabled, then do nothing.
+		 */
+		if (old_state != C_DISABLE) {
+			fbi->state = state;
+			sa1100fb_disable_controller(fbi);
+		}
+		break;
 
-	/* Reset the LCD Controller's DMA address if it has changed */
-  	lcd_shadow.dbar1 = (Address)current_par.p_palette_base;
-	lcd_shadow.dbar2 = (Address)(current_par.p_screen_base + (current_par.xres * current_par.yres * current_par.bits_per_pixel / 8 / 2));
+	case C_DISABLE:
+		/*
+		 * Disable controller
+		 */
+		if (old_state != C_DISABLE) {
+			fbi->state = state;
 
-	DPRINTK("Configuring xres = %d, yres = %d\n",var->xres, var->yres);
+			sa1100fb_backlight_off(fbi);
+			if (old_state != C_DISABLE_CLKCHANGE)
+				sa1100fb_disable_controller(fbi);
+			sa1100fb_power_down_lcd(fbi);
+		}
+		break;
 
-	if (machine_is_assabet()) {
-		DPRINTK("Configuring  Assabet LCD\n");
-		lcd_shadow.lccr0 = 
-			LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + 
-			LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Act +
-			LCCR0_LtlEnd + LCCR0_DMADel(0);
-		lcd_shadow.lccr1 = 
-			LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(6) + 
-			LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9);
-		lcd_shadow.lccr2 = 
-			LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + 
-			LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0);
-		lcd_shadow.lccr3 = 
-			LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + 
-			LCCR3_HorSnchH + LCCR3_ACBsCntOff + 
-			LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(pcd);
-
-		/* Set board control register to handle new color depth */
-		sa1100fb_assabet_set_truecolor(var->bits_per_pixel >= 16);
-	} else if (machine_is_pangolin()) {
-		DPRINTK("Configuring Pangolin LCD\n");
-		lcd_shadow.lccr0 = 
-			LCCR0_LEN + LCCR0_Color + LCCR0_LDM +
-			LCCR0_BAM + LCCR0_ERM + LCCR0_Act +
-			LCCR0_LtlEnd + LCCR0_DMADel(0);
-		lcd_shadow.lccr1 = 
-			LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(63) + 
-			LCCR1_BegLnDel(127) + LCCR1_EndLnDel(127);
-		lcd_shadow.lccr2 = 
-			LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(2) + 
-			LCCR2_BegFrmDel(18) + LCCR2_EndFrmDel(18);
-		lcd_shadow.lccr3 = 
-			LCCR3_PixClkDiv(pcd) + LCCR3_HorSnchH +
-			LCCR3_VrtSnchH + LCCR3_OutEnH;
-		DPRINTK("pcd = %d\n", pcd);
-		DPRINTK("LCCR1_DisWdth(var->xres) = 0x%x\n",
-			LCCR1_DisWdth(var->xres));
-		DPRINTK("LCCR2_DisHght(var->yres) = 0x%x\n",
-			LCCR2_DisHght(var->yres));
-	} else if (machine_is_bitsy()) {
-		DPRINTK("Configuring  Bitsy LCD\n");
-		lcd_shadow.lccr0 = LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
-				   LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + 
-				   LCCR0_DMADel(0);
-		lcd_shadow.lccr1 = LCCR1_DisWdth( var->xres ) +
-				   LCCR1_HorSnchWdth( 4 ) +
-				   LCCR1_BegLnDel( 0xC ) +
-				   LCCR1_EndLnDel( 0x11 );
-		lcd_shadow.lccr2 = LCCR2_DisHght( var->yres + 1 ) +
-				   LCCR2_VrtSnchWdth( 3 )+
-				   LCCR2_BegFrmDel( 10 ) +
-				   LCCR2_EndFrmDel( 1 );
-		lcd_shadow.lccr3 = (/* PCD */ 0x10
-                                    | /* ACB */ 0
-                                    | /* API */ 0
-                                    | LCCR3_VrtSnchL
-                                    | LCCR3_HorSnchL);
-	} else if (machine_is_brutus()) {
- 		DPRINTK("Configuring  Brutus LCD\n");
- 		lcd_shadow.lccr0 = 
- 			LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Pas + 
- 			LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + 
- 			LCCR0_DMADel(0);
- 		lcd_shadow.lccr1 = 
- 			LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(4) + 
- 			LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101);
- 		lcd_shadow.lccr2 = 
- 			LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + 
- 			LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0);
- 		lcd_shadow.lccr3 = 
- 			LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + 
- 			LCCR3_HorSnchH + LCCR3_ACBsCntOff + 
- 			LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(44);
-	} else if (machine_is_cerf()) {
-		DPRINTK("Configuring Cerf LCD\n");
-		lcd_shadow.lccr0 = 
-			LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + 
-			LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Pas +
-			LCCR0_LtlEnd + LCCR0_DMADel(0);
-		lcd_shadow.lccr1 = 
-			LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(6) + 
-			LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9);
-		lcd_shadow.lccr2 = 
-			LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + 
-			LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0);
-		lcd_shadow.lccr3 = 
-			LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + 
-			LCCR3_HorSnchH + LCCR3_ACBsCntOff + 
-			LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(38);
-	} else if (machine_is_lart()) {
-		DPRINTK("Configuring LART LCD\n");
-		lcd_shadow.lccr0 = 
-			LCCR0_LEN + LCCR0_Mono + LCCR0_Sngl + LCCR0_Pas +
-			LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + 
-			LCCR0_DMADel(0);
-		lcd_shadow.lccr1 = 
-			LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(2) +
-			LCCR1_BegLnDel(4) + LCCR1_EndLnDel(2);
-		lcd_shadow.lccr2 = 
-			LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
-			LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0);
-		lcd_shadow.lccr3 = 
-			LCCR3_PixClkDiv(34) + LCCR3_ACBsDiv(512) +
-			LCCR3_ACBsCntOff + LCCR3_HorSnchH + LCCR3_VrtSnchH;
-	} else if (machine_is_graphicsclient()) {
-		DPRINTK("Configuring GraphicsClient LCD\n");
-		lcd_shadow.lccr0 = 
-			LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act;
-		lcd_shadow.lccr1 = 
-			LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(10) +
-			LCCR1_EndLnDel(81) + LCCR1_BegLnDel(81);
-		lcd_shadow.lccr2 = 
-			LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(9) + 
-			LCCR2_EndFrmDel (20) + LCCR2_BegFrmDel(20);
-		lcd_shadow.lccr3 = 
-			LCCR3_PixClkDiv(6) + LCCR3_ACBsDiv(2) + 
-			LCCR3_ACBsCntOff + LCCR3_HorSnchL + LCCR3_VrtSnchL;
-	} else if (machine_is_xp860()) {
-		DPRINTK("Configuring XP860 LCD\n");
-		lcd_shadow.lccr0 = 
-			LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
-			LCCR0_LtlEnd + LCCR0_LDM + LCCR0_ERM +
-			LCCR0_DMADel(0);
-		lcd_shadow.lccr1 = 
-			LCCR1_DisWdth(var->xres) + 
-			LCCR1_HorSnchWdth(var->hsync_len) +
-			LCCR1_BegLnDel(var->left_margin) +
-			LCCR1_EndLnDel(var->right_margin);
-		lcd_shadow.lccr2 = 
-			LCCR2_DisHght(var->yres) + 
-			LCCR2_VrtSnchWdth(var->vsync_len) +
-			LCCR2_BegFrmDel(var->upper_margin) +
-			LCCR2_EndFrmDel(var->lower_margin);
-		lcd_shadow.lccr3 = 
-			LCCR3_PixClkDiv(6) +
-			LCCR3_HorSnchL + LCCR3_VrtSnchL;
-	}
+	case C_ENABLE_CLKCHANGE:
+		/*
+		 * Enable the controller after clock change.  Only
+		 * do this if we were disabled for the clock change.
+		 */
+		if (old_state == C_DISABLE_CLKCHANGE) {
+			fbi->state = C_ENABLE;
+			sa1100fb_enable_controller(fbi);
+		}
+		break;
 
-	/* Restore interrupt status */
-	local_irq_restore(flags);
+	case C_REENABLE:
+		/*
+		 * Re-enable the controller only if it was already
+		 * enabled.  This is so we reprogram the control
+		 * registers.
+		 */
+		if (old_state == C_ENABLE) {
+			sa1100fb_disable_controller(fbi);
+			sa1100fb_setup_gpio(fbi);
+			sa1100fb_enable_controller(fbi);
+		}
+		break;
 
-	if (( LCCR0 != lcd_shadow.lccr0 ) ||
-	    ( LCCR1 != lcd_shadow.lccr1 ) ||
-	    ( LCCR2 != lcd_shadow.lccr2 ) ||
-            ( LCCR3 != lcd_shadow.lccr3 ) ||
-	    ( DBAR1 != lcd_shadow.dbar1 ) ||
-	    ( DBAR2 != lcd_shadow.dbar2 ))
-	{
-		sa1100fb_enable_lcd_controller();
+	case C_ENABLE:
+		/*
+		 * Power up the LCD screen, enable controller, and
+		 * turn on the backlight.
+		 */
+		if (old_state != C_ENABLE) {
+			fbi->state = C_ENABLE;
+			sa1100fb_setup_gpio(fbi);
+			sa1100fb_power_up_lcd(fbi);
+			sa1100fb_enable_controller(fbi);
+			sa1100fb_backlight_on(fbi);
+		}
+		break;
 	}
-
-  	return 0;
+	up(&fbi->ctrlr_sem);
 }
 
-
 /*
- *  sa1100fb_inter_handler():
- *	Interrupt handler for LCD controller.  Processes disable done interrupt (LDD)
- *      to reenable controller if controller was disabled to change register values.
+ * Our LCD controller task (which is called when we blank or unblank)
+ * via keventd.
  */
-static void sa1100fb_inter_handler(int irq, void *dev_id, struct pt_regs *regs)
+static void sa1100fb_task(void *dummy)
 {
-        if (LCSR & LCSR_LDD) {
-                int controller_state = current_par.controller_state;
-	        /* Disable Done Flag is set */
-		LCCR0 |= LCCR0_LDM;	      /* Mask LCD Disable Done Interrupt */
-		current_par.controller_state = LCD_MODE_DISABLED;
-		if (controller_state == LCD_MODE_DISABLE_BEFORE_ENABLE) {
-		        DPRINTK("sa1100fb_inter_handler: re-enabling LCD controller\n");
-			sa1100fb_enable_lcd_controller();
-		} else {
-			/*
-			 * Second half of sa1100fb_disable_lcd_controller()
-			 */
-			if (machine_is_assabet()) {
-#ifdef CONFIG_SA1100_ASSABET
-				BCR_clear(BCR_LCD_ON);
-#endif
-			} else if (machine_is_bitsy()) {
-#ifdef CONFIG_SA1100_BITSY
-		                if (current_par.controller_state != LCD_MODE_DISABLE_BEFORE_ENABLE)
-		                        clr_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON);
-#endif
-			}
-		}
-	}
-	LCSR = 0;		      /* Clear LCD Status Register */
-}
+	struct sa1100fb_info *fbi = dummy;
+	u_int state = xchg(&fbi->task_state, -1);
 
+	set_ctrlr_state(fbi, state);
+}
 
+#ifdef CONFIG_CPU_FREQ
 /*
- *  sa1100fb_disable_lcd_controller():
- *    	Disables LCD controller by and enables LDD interrupt.  The controller_state
- *      is not changed until the LDD interrupt is received to indicate the current
- *      frame has completed.  Platform specific hardware disabling is also included.
+ * Calculate the minimum DMA period over all displays that we own.
+ * This, together with the SDRAM bandwidth defines the slowest CPU
+ * frequency that can be selected.
  */
-static void sa1100fb_disable_lcd_controller(void)
+static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
 {
-        DPRINTK("Disabling LCD controller\n");
+	unsigned int min_period = (unsigned int)-1;
+	int i;
 
-	/* Exit if already LCD disabled, or LDD IRQ unmasked */
-	if ((current_par.controller_state == LCD_MODE_DISABLED) ||
-	    (!(LCCR0 & LCCR0_LDM))) {
-		DPRINTK("LCD already disabled\n");
-		return;
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		unsigned int period;
+
+		/*
+		 * Do we own this display?
+		 */
+		if (fb_display[i].fb_info != &fbi->fb)
+			continue;
+
+		/*
+		 * Ok, calculate its DMA period
+		 */
+		period = sa1100fb_display_dma_period(get_con_var(fbi, i));
+		if (period < min_period)
+			min_period = period;
 	}
 
-	LCSR = 0;	/* Clear LCD Status Register */
-	LCCR0 &= ~(LCCR0_LDM);	/* Enable LCD Disable Done Interrupt */
-	enable_irq(IRQ_LCD);	      /* Enable LCD IRQ */
-	LCCR0 &= ~(LCCR0_LEN);	/* Disable LCD Controller */
+	return min_period;
 }
 
 /*
- *  sa1100fb_enable_lcd_controller():
- *    	Enables LCD controller.  If the controller is already enabled, it is first disabled.
- *      This forces all changes to the LCD controller registers to be done when the 
- *      controller is disabled.  Platform specific hardware enabling is also included.
+ * CPU clock speed change handler.  We need to adjust the LCD timing
+ * parameters when the CPU clock is adjusted by the power management
+ * subsystem.
  */
-static void sa1100fb_enable_lcd_controller(void)
+static int
+sa1100fb_clkchg_notifier(struct notifier_block *nb, unsigned long val,
+			 void *data)
 {
-	u_long	flags;
-
-	local_irq_save(flags);		
+	struct sa1100fb_info *fbi = TO_INF(nb, clockchg);
+	struct cpufreq_minmax *mm = data;
+	u_int pcd;
+
+	switch (val) {
+	case CPUFREQ_MINMAX:
+		printk(KERN_DEBUG "min dma period: %d ps, old clock %d kHz, "
+			"new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
+			mm->cur_freq, mm->new_freq);
+		/* todo: fill in min/max values */
+		break;
 
-        /* Disable controller before changing parameters */
-	if (current_par.controller_state == LCD_MODE_ENABLED) 	{
-		current_par.controller_state = LCD_MODE_DISABLE_BEFORE_ENABLE;
-		sa1100fb_disable_lcd_controller();
-	} else {
-		DPRINTK("Enabling LCD controller\n");
+	case CPUFREQ_PRECHANGE:
+		set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
+		break;
 
-		/* Make sure the mode bits are present in the first palette entry */
-		current_par.v_palette_base[0] &= 0x0FFF; 	           
-		current_par.v_palette_base[0] |= SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel);
-
-		/* Enable GPIO<9:2> for LCD usage if dual-scan */
-		if (lcd_shadow.lccr0 & LCCR0_SDS) {
-		  GPDR |= 0x3fc;
-		  GAFR |= 0x3fc;
-		}
+	case CPUFREQ_POSTCHANGE:
+		pcd = get_pcd(fbi->fb.var.pixclock);
+		fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
+		set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
+		break;
+	}
+	return 0;
+}
+#endif
 
-		/* Sequence from 11.7.10 */
-		LCCR3 = lcd_shadow.lccr3;
-		LCCR2 = lcd_shadow.lccr2;
-		LCCR1 = lcd_shadow.lccr1;
-		LCCR0 = lcd_shadow.lccr0 & ~LCCR0_LEN;
-		DBAR1 = lcd_shadow.dbar1;
-		DBAR2 = lcd_shadow.dbar2;
-		LCCR0 |= LCCR0_LEN;
+#ifdef CONFIG_PM
+/*
+ * Power management hook.  Note that we won't be called from IRQ context,
+ * unlike the blank functions above, so we may sleep.
+ */
+static int
+sa1100fb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
+{
+	struct sa1100fb_info *fbi = pm_dev->data;
 
-		if (machine_is_assabet()) {
-#ifdef CONFIG_SA1100_ASSABET
-			BCR_set(BCR_LCD_ON);
-#endif
-		} else if (machine_is_bitsy()) {
-#ifdef CONFIG_SA1100_BITSY
-                  set_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON);
-			DPRINTK("DBAR1=%p\n", DBAR1);
-			DPRINTK("LCCR0=%x\n", LCCR0);
-			DPRINTK("LCCR1=%x\n", LCCR1);
-			DPRINTK("LCCR2=%x\n", LCCR2);
-			DPRINTK("LCCR3=%x\n", LCCR3);
-#endif
-		}
+	DPRINTK("pm_callback: %d\n", req);
 
-		current_par.controller_state = LCD_MODE_ENABLED;
+	if (req == PM_SUSPEND || req == PM_RESUME) {
+		int state = (int)data;
 
+		if (state == 0) {
+			/* Enter D0. */
+			set_ctrlr_state(fbi, C_ENABLE);
+		} else {
+			/* Enter D1-D3.  Disable the LCD controller.  */
+			set_ctrlr_state(fbi, C_DISABLE);
+		}
 	}
-	/* Restore interrupt status */
-	local_irq_restore(flags);
+	DPRINTK("done\n");
+	return 0;
 }
+#endif
 
 /*
- * sa1100fb_blank():
- *	Blank the display by setting all palette values to zero.  Note, the 
- * 	12 and 16 bpp modes don't really use the palette, so this will not
- *      blank the display in all modes.  
+ * sa1100fb_map_video_memory():
+ *      Allocates the DRAM memory for the frame buffer.  This buffer is  
+ *	remapped into a non-cached, non-buffered, memory region to  
+ *      allow palette and pixel writes to occur without flushing the 
+ *      cache.  Once this area is remapped, all virtual memory
+ *      access to the video memory should occur at the new region.
  */
-static void
-sa1100fb_blank(int blank, struct fb_info *info)
+static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
 {
-	int i;
+	/*
+	 * We reserve one page for the palette, plus the size
+	 * of the framebuffer.
+	 */
+	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
+	fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size,
+					&fbi->map_dma);
 
-  	DPRINTK("blank=%d info->modename=%s\n", blank, info->modename);
-	if (blank) {
-                if (current_par.visual != FB_VISUAL_TRUECOLOR)
-		for (i = 0; i < current_par.palette_size; i++)
-			sa1100fb_palette_write(i, sa1100fb_palette_encode(i, 0, 0, 0, 0));
-		sa1100fb_disable_lcd_controller();
-	}
-	else {
-                if (current_par.visual != FB_VISUAL_TRUECOLOR)
-		sa1100fb_set_cmap(&fb_display[current_par.currcon].cmap, 1, 
-		                  current_par.currcon, info); 
-		sa1100fb_enable_lcd_controller();
+	if (fbi->map_cpu) {
+		fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE;
+		fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
+		fbi->fb.fix.smem_start = fbi->screen_dma;
 	}
-	/* TODO: Bitsy support for blanking display */
+
+	return fbi->map_cpu ? 0 : -ENOMEM;
 }
 
+/* Fake monspecs to fill in fbinfo structure */
+static struct fb_monspecs monspecs __initdata = {
+	30000, 70000, 50, 65, 0	/* Generic */
+};
 
-/*
- *  sa1100fb_switch():       
- *	Change to the specified console.  Palette and video mode
- *      are changed to the console's stored parameters. 
- */
-static int
-sa1100fb_switch(int con, struct fb_info *info)
-{
 
-  	DPRINTK("con=%d info->modename=%s\n", con, info->modename);
-        if (current_par.visual != FB_VISUAL_TRUECOLOR) {
-                struct fb_cmap *cmap;
-		if (current_par.currcon >= 0) {
-			// Get the colormap for the selected console 
-			cmap = &fb_display[current_par.currcon].cmap;
-			
-			if (cmap->len)
-				fb_get_cmap(cmap, 1, sa1100fb_getcolreg, info);
-		}
-        }
+static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
+{
+	struct sa1100fb_mach_info *inf;
+	struct sa1100fb_info *fbi;
 
-	current_par.currcon = con;
-	fb_display[con].var.activate = FB_ACTIVATE_NOW;
-	DPRINTK("fb_display[%d].var.activate=%x\n", con, fb_display[con].var.activate);
-	sa1100fb_set_var(&fb_display[con].var, con, info);
-	current_par.v_palette_base[0] = (current_par.v_palette_base[0] &
-		0xcfff) | SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel);
+	fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(struct display) +
+		      sizeof(u16) * 16, GFP_KERNEL);
+	if (!fbi)
+		return NULL;
+
+	memset(fbi, 0, sizeof(struct sa1100fb_info) + sizeof(struct display));
+
+	fbi->currcon		= -1;
+
+	strcpy(fbi->fb.fix.id, SA1100_NAME);
+
+	fbi->fb.fix.type	= FB_TYPE_PACKED_PIXELS;
+	fbi->fb.fix.type_aux	= 0;
+	fbi->fb.fix.xpanstep	= 0;
+	fbi->fb.fix.ypanstep	= 0;
+	fbi->fb.fix.ywrapstep	= 0;
+	fbi->fb.fix.accel	= FB_ACCEL_NONE;
+
+	fbi->fb.var.nonstd	= 0;
+	fbi->fb.var.activate	= FB_ACTIVATE_NOW;
+	fbi->fb.var.height	= -1;
+	fbi->fb.var.width	= -1;
+	fbi->fb.var.accel_flags	= 0;
+	fbi->fb.var.vmode	= FB_VMODE_NONINTERLACED;
+
+	strcpy(fbi->fb.modename, SA1100_NAME);
+	strcpy(fbi->fb.fontname, "Acorn8x8");
+
+	fbi->fb.fbops		= &sa1100fb_ops;
+	fbi->fb.changevar	= NULL;
+	fbi->fb.switch_con	= sa1100fb_switch;
+	fbi->fb.updatevar	= sa1100fb_updatevar;
+	fbi->fb.blank		= sa1100fb_blank;
+	fbi->fb.flags		= FBINFO_FLAG_DEFAULT;
+	fbi->fb.node		= -1;
+	fbi->fb.monspecs	= monspecs;
+	fbi->fb.disp		= (struct display *)(fbi + 1);
+	fbi->fb.pseudo_palette	= (void *)(fbi->fb.disp + 1);
+
+	fbi->rgb[RGB_8]		= &rgb_8;
+	fbi->rgb[RGB_16]	= &def_rgb_16;
+
+	inf = sa1100fb_get_machine_info(fbi);
+
+	fbi->max_xres			= inf->xres;
+	fbi->fb.var.xres		= inf->xres;
+	fbi->fb.var.xres_virtual	= inf->xres;
+	fbi->max_yres			= inf->yres;
+	fbi->fb.var.yres		= inf->yres;
+	fbi->fb.var.yres_virtual	= inf->yres;
+	fbi->max_bpp			= inf->bpp;
+	fbi->fb.var.bits_per_pixel	= inf->bpp;
+	fbi->fb.var.pixclock		= inf->pixclock;
+	fbi->fb.var.hsync_len		= inf->hsync_len;
+	fbi->fb.var.left_margin		= inf->left_margin;
+	fbi->fb.var.right_margin	= inf->right_margin;
+	fbi->fb.var.vsync_len		= inf->vsync_len;
+	fbi->fb.var.upper_margin	= inf->upper_margin;
+	fbi->fb.var.lower_margin	= inf->lower_margin;
+	fbi->fb.var.sync		= inf->sync;
+	fbi->fb.var.grayscale		= inf->cmap_greyscale;
+	fbi->cmap_inverse		= inf->cmap_inverse;
+	fbi->cmap_static		= inf->cmap_static;
+	fbi->lccr0			= inf->lccr0;
+	fbi->lccr3			= inf->lccr3;
+	fbi->state			= C_DISABLE;
+	fbi->task_state			= (u_char)-1;
+	fbi->fb.fix.smem_len		= fbi->max_xres * fbi->max_yres *
+					  fbi->max_bpp / 8;
+
+	init_waitqueue_head(&fbi->ctrlr_wait);
+	INIT_TQUEUE(&fbi->task, sa1100fb_task, fbi);
+	init_MUTEX(&fbi->ctrlr_sem);
 
-	return 0;
+	return fbi;
 }
 
-
 int __init sa1100fb_init(void)
 {
+	struct sa1100fb_info *fbi;
 	int ret;
 
-	sa1100fb_init_fbinfo();
+	fbi = sa1100fb_init_fbinfo();
+	ret = -ENOMEM;
+	if (!fbi)
+		goto failed;
 
 	/* Initialize video memory */
-	if ((ret = sa1100fb_map_video_memory()) != 0)
-		return ret;
+	ret = sa1100fb_map_video_memory(fbi);
+	if (ret)
+		goto failed;
+
+	ret = request_irq(IRQ_LCD, sa1100fb_handle_irq, SA_INTERRUPT,
+			  fbi->fb.fix.id, fbi);
+	if (ret) {
+		printk(KERN_ERR "sa1100fb: failed in request_irq: %d\n", ret);
+		goto failed;
+	}
 
-	if (current_par.montype < 0 || current_par.montype > NR_MONTYPES)
-		current_par.montype = 1;
+#if defined(CONFIG_SA1100_ASSABET) && defined(ASSABET_PAL_VIDEO)
+	if (machine_is_assabet())
+		BCR_clear(BCR_LCD_ON);
+#endif
 
-	if (request_irq(IRQ_LCD, sa1100fb_inter_handler, SA_INTERRUPT, "SA1100 LCD", NULL) != 0) {
-		printk(KERN_ERR "sa1100fb: failed in request_irq\n");
-		return -EBUSY;
+#ifdef CONFIG_SA1100_FREEBIRD
+#error Please move this into sa1100fb_power_up_lcd
+	if (machine_is_freebird()) {
+		BCR_set(BCR_FREEBIRD_LCD_DISP);
+		mdelay(20);
+		BCR_set(BCR_FREEBIRD_LCD_PWR);
+		mdelay(20);
 	}
-	DPRINTK("sa1100fb: request_irq succeeded\n");
-	disable_irq(IRQ_LCD);
+#endif
 
-	if (machine_is_assabet()) {
-		GPDR |= 0x3fc;
-		GAFR |= 0x3fc;
-		sa1100fb_assabet_set_truecolor(current_par.visual ==
-					       FB_VISUAL_TRUECOLOR);
-	} else if (machine_is_pangolin()) {
-		GPDR |= 0x3fc;
-		GAFR |= 0x3fc;
-	} else if (machine_is_bitsy()) {
-		GPDR = (GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 | GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8);
-		GAFR |= (GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 | GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8);
-	} else if (machine_is_cerf()) {
-		GPDR |= 0x3fc;
-		GAFR |= 0x3fc;
-	} else if (machine_is_xp860()) {
-		GPDR |= 0x3fc;
-		GAFR |= 0x3fc;
-	}
-
-	if (sa1100fb_set_var(&init_var, -1, &fb_info))
-		current_par.allow_modeset = 0;
-	sa1100fb_decode_var(&init_var, &current_par);
+	sa1100fb_set_var(&fbi->fb.var, -1, &fbi->fb);
+
+	ret = register_framebuffer(&fbi->fb);
+	if (ret < 0)
+		goto failed;
+
+#ifdef CONFIG_PM
+	/*
+	 * Note that the console registers this as well, but we want to
+	 * power down the display prior to sleeping.
+	 */
+	fbi->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, sa1100fb_pm_callback);
+	if (fbi->pm)
+		fbi->pm->data = fbi;
+#endif
+#ifdef CONFIG_CPU_FREQ
+	fbi->clockchg.notifier_call = sa1100fb_clkchg_notifier;
+	cpufreq_register_notifier(&fbi->clockchg);
+#endif
 
-	register_framebuffer(&fb_info);
+	/*
+	 * Ok, now enable the LCD controller
+	 */
+	set_ctrlr_state(fbi, C_ENABLE);
 
 	/* This driver cannot be unloaded at the moment */
 	MOD_INC_USE_COUNT;
 
 	return 0;
+
+failed:
+	if (fbi)
+		kfree(fbi);
+	return ret;
 }
 
 int __init sa1100fb_setup(char *options)
 {
+#if 0
 	char *this_opt;
 
 	if (!options || !*options)
@@ -1285,24 +2302,33 @@
 	for (this_opt = strtok(options, ","); this_opt;
 	     this_opt = strtok(NULL, ",")) {
 
-	  if (!strncmp(this_opt, "bpp:", 4))
- 	    current_par.max_bpp = simple_strtoul(this_opt+4, NULL, 0);
-
-	  if (!strncmp(this_opt, "lccr0:", 6))
-	    lcd_shadow.lccr0 = simple_strtoul(this_opt+6, NULL, 0);
-	  if (!strncmp(this_opt, "lccr1:", 6)) {
-	    lcd_shadow.lccr1 = simple_strtoul(this_opt+6, NULL, 0);
-	    current_par.max_xres = (lcd_shadow.lccr1 & 0x3ff) + 16;
-	  }
-	  if (!strncmp(this_opt, "lccr2:", 6)) {
-	    lcd_shadow.lccr2 = simple_strtoul(this_opt+6, NULL, 0);
-	    current_par.max_yres = (lcd_shadow.lccr0 & LCCR0_SDS) ? 
-	      ((lcd_shadow.lccr2 & 0x3ff) + 1) * 2 :
-	      ((lcd_shadow.lccr2 & 0x3ff) + 1);
-	  }
-	  if (!strncmp(this_opt, "lccr3:", 6))
-	    lcd_shadow.lccr3 = simple_strtoul(this_opt+6, NULL, 0);
+		if (!strncmp(this_opt, "bpp:", 4))
+			current_par.max_bpp =
+			    simple_strtoul(this_opt + 4, NULL, 0);
+
+		if (!strncmp(this_opt, "lccr0:", 6))
+			lcd_shadow.lccr0 =
+			    simple_strtoul(this_opt + 6, NULL, 0);
+		if (!strncmp(this_opt, "lccr1:", 6)) {
+			lcd_shadow.lccr1 =
+			    simple_strtoul(this_opt + 6, NULL, 0);
+			current_par.max_xres =
+			    (lcd_shadow.lccr1 & 0x3ff) + 16;
+		}
+		if (!strncmp(this_opt, "lccr2:", 6)) {
+			lcd_shadow.lccr2 =
+			    simple_strtoul(this_opt + 6, NULL, 0);
+			current_par.max_yres =
+			    (lcd_shadow.
+			     lccr0 & LCCR0_SDS) ? ((lcd_shadow.
+						    lccr2 & 0x3ff) +
+						   1) *
+			    2 : ((lcd_shadow.lccr2 & 0x3ff) + 1);
+		}
+		if (!strncmp(this_opt, "lccr3:", 6))
+			lcd_shadow.lccr3 =
+			    simple_strtoul(this_opt + 6, NULL, 0);
 	}
+#endif
 	return 0;
 }
-
diff -urN linux-2.4.9-pre1/drivers/video/sa1100fb.h linux/drivers/video/sa1100fb.h
--- linux-2.4.9-pre1/drivers/video/sa1100fb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/sa1100fb.h	Mon Dec  3 23:01:22 2001
@@ -0,0 +1,147 @@
+/*
+ * linux/drivers/video/sa1100fb.h
+ *    -- StrongARM 1100 LCD Controller Frame Buffer Device
+ *
+ *  Copyright (C) 1999 Eric A. Thomas
+ *   Based on acornfb.c Copyright (C) Russell King.
+ *  
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * These are the bitfields for each
+ * display depth that we support.
+ */
+struct sa1100fb_rgb {
+	struct fb_bitfield	red;
+	struct fb_bitfield	green;
+	struct fb_bitfield	blue;
+	struct fb_bitfield	transp;
+};
+
+/*
+ * This structure describes the machine which we are running on.
+ */
+struct sa1100fb_mach_info {
+	u_long		pixclock;
+
+	u_short		xres;
+	u_short		yres;
+
+	u_char		bpp;
+	u_char		hsync_len;
+	u_char		left_margin;
+	u_char		right_margin;
+
+	u_char		vsync_len;
+	u_char		upper_margin;
+	u_char		lower_margin;
+	u_char		sync;
+
+	u_int		cmap_greyscale:1,
+			cmap_inverse:1,
+			cmap_static:1,
+			unused:29;
+
+	u_int		lccr0;
+	u_int		lccr3;
+};
+
+/* Shadows for LCD controller registers */
+struct sa1100fb_lcd_reg {
+	Word lccr0;
+	Word lccr1;
+	Word lccr2;
+	Word lccr3;
+};
+
+#define RGB_8	(0)
+#define RGB_16	(1)
+#define NR_RGB	2
+
+struct sa1100fb_info {
+	struct fb_info		fb;
+	signed int		currcon;
+
+	struct sa1100fb_rgb	*rgb[NR_RGB];
+
+	u_int			max_bpp;
+	u_int			max_xres;
+	u_int			max_yres;
+
+	/*
+	 * These are the addresses we mapped
+	 * the framebuffer memory region to.
+	 */
+	dma_addr_t		map_dma;
+	u_char *		map_cpu;
+	u_int			map_size;
+
+	u_char *		screen_cpu;
+	dma_addr_t		screen_dma;
+	u16 *			palette_cpu;
+	dma_addr_t		palette_dma;
+	u_int			palette_size;
+
+	dma_addr_t		dbar1;
+	dma_addr_t		dbar2;
+
+	u_int			lccr0;
+	u_int			lccr3;
+	u_int			cmap_inverse:1,
+				cmap_static:1,
+				unused:30;
+
+	u_int			reg_lccr0;
+	u_int			reg_lccr1;
+	u_int			reg_lccr2;
+	u_int			reg_lccr3;
+
+	volatile u_char		state;
+	volatile u_char		task_state;
+	struct semaphore	ctrlr_sem;
+	wait_queue_head_t	ctrlr_wait;
+	struct tq_struct	task;
+
+#ifdef CONFIG_PM
+	struct pm_dev		*pm;
+#endif
+#ifdef CONFIG_CPU_FREQ
+	struct notifier_block	clockchg;
+#endif
+};
+
+#define __type_entry(ptr,type,member) ((type *)((char *)(ptr)-offsetof(type,member)))
+
+#define TO_INF(ptr,member)	__type_entry(ptr,struct sa1100fb_info,member)
+
+#define SA1100_PALETTE_MODE_VAL(bpp)    (((bpp) & 0x018) << 9)
+
+/*
+ * These are the actions for set_ctrlr_state
+ */
+#define C_DISABLE		(0)
+#define C_ENABLE		(1)
+#define C_DISABLE_CLKCHANGE	(2)
+#define C_ENABLE_CLKCHANGE	(3)
+#define C_REENABLE		(4)
+
+#define SA1100_NAME	"SA1100"
+
+/*
+ *  Debug macros 
+ */
+#if DEBUG
+#  define DPRINTK(fmt, args...)	printk("%s: " fmt, __FUNCTION__ , ## args)
+#else
+#  define DPRINTK(fmt, args...)
+#endif
+
+/*
+ * Minimum X and Y resolutions
+ */
+#define MIN_XRES	64
+#define MIN_YRES	64
+
diff -urN linux-2.4.9-pre1/fs/hpfs/file.c linux/fs/hpfs/file.c
--- linux-2.4.9-pre1/fs/hpfs/file.c	Fri Dec 29 14:07:57 2000
+++ linux/fs/hpfs/file.c	Mon Dec  3 23:01:22 2001
@@ -11,6 +11,8 @@
 #include <linux/smp_lock.h>
 #include "hpfs_fn.h"
 
+#define BLOCKS(size) (((size) + 511) >> 9)
+
 /* HUH? */
 int hpfs_open(struct inode *i, struct file *f)
 {
@@ -46,7 +48,7 @@
 	unsigned n, disk_secno;
 	struct fnode *fnode;
 	struct buffer_head *bh;
-	if (((inode->i_size + 511) >> 9) <= file_secno) return 0;
+	if (BLOCKS(inode->u.hpfs_i.mmu_private) <= file_secno) return 0;
 	n = file_secno - inode->i_hpfs_file_sec;
 	if (n < inode->i_hpfs_n_secs) return inode->i_hpfs_disk_sec + n;
 	if (!(fnode = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) return 0;
diff -urN linux-2.4.9-pre1/fs/hpfs/inode.c linux/fs/hpfs/inode.c
--- linux-2.4.9-pre1/fs/hpfs/inode.c	Mon Jan 22 10:40:47 2001
+++ linux/fs/hpfs/inode.c	Mon Dec  3 23:01:22 2001
@@ -12,6 +12,7 @@
 
 static struct file_operations hpfs_file_ops =
 {
+	llseek:		generic_file_llseek,
 	read:		generic_file_read,
 	write:		hpfs_file_write,
 	mmap:		generic_file_mmap,
diff -urN linux-2.4.9-pre1/fs/nfs/file.c linux/fs/nfs/file.c
--- linux-2.4.9-pre1/fs/nfs/file.c	Tue May 22 09:26:06 2001
+++ linux/fs/nfs/file.c	Mon Dec  3 23:01:22 2001
@@ -42,6 +42,7 @@
 static int  nfs_file_release(struct inode *, struct file *);
 
 struct file_operations nfs_file_operations = {
+	llseek:		generic_file_llseek,
 	read:		nfs_file_read,
 	write:		nfs_file_write,
 	mmap:		nfs_file_mmap,
diff -urN linux-2.4.9-pre1/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c
--- linux-2.4.9-pre1/fs/nfsd/nfsfh.c	Mon Dec  3 23:01:03 2001
+++ linux/fs/nfsd/nfsfh.c	Mon Dec  3 23:01:22 2001
@@ -41,7 +41,7 @@
  * the name matching the specified inode number.
  */
 static int filldir_one(void * __buf, const char * name, int len,
-			off_t pos, ino_t ino, unsigned int d_type)
+			loff_t pos, ino_t ino, unsigned int d_type)
 {
 	struct nfsd_getdents_callback *buf = __buf;
 	struct qstr *qs = buf->name;
diff -urN linux-2.4.9-pre1/fs/sysv/file.c linux/fs/sysv/file.c
--- linux-2.4.9-pre1/fs/sysv/file.c	Mon Jul  2 14:03:04 2001
+++ linux/fs/sysv/file.c	Mon Dec  3 23:01:22 2001
@@ -21,6 +21,7 @@
  * the coh filesystem.
  */
 struct file_operations sysv_file_operations = {
+	llseek:		generic_file_llseek,
 	read:		generic_file_read,
 	write:		generic_file_write,
 	mmap:		generic_file_mmap,
diff -urN linux-2.4.9-pre1/fs/ufs/file.c linux/fs/ufs/file.c
--- linux-2.4.9-pre1/fs/ufs/file.c	Sat Feb 26 20:33:08 2000
+++ linux/fs/ufs/file.c	Mon Dec  3 23:01:22 2001
@@ -71,11 +71,13 @@
  * We have mostly NULL's here: the current defaults are ok for
  * the ufs filesystem.
  */
+ 
 struct file_operations ufs_file_operations = {
 	llseek:		ufs_file_lseek,
 	read:		generic_file_read,
 	write:		generic_file_write,
 	mmap:		generic_file_mmap,
+	open:           generic_file_open,
 };
 
 struct inode_operations ufs_file_inode_operations = {
diff -urN linux-2.4.9-pre1/include/asm-arm/arch-sa1100/SA-1100.h linux/include/asm-arm/arch-sa1100/SA-1100.h
--- linux-2.4.9-pre1/include/asm-arm/arch-sa1100/SA-1100.h	Mon Dec  3 23:01:03 2001
+++ linux/include/asm-arm/arch-sa1100/SA-1100.h	Mon Dec  3 23:01:22 2001
@@ -2761,10 +2761,10 @@
 #define LCCR1_DisWdth(Pixel)    	/*  Display Width [16..1024 pix.]  */ \
                 	(((Pixel) - 16)/16 << FShft (LCCR1_PPL))
 #define LCCR1_HSW	Fld (6, 10)	/* Horizontal Synchronization      */
-					/* pulse Width - 1 [Tpix] (L_LCLK) */
+                	        	/* pulse Width - 1 [Tpix] (L_LCLK) */
 #define LCCR1_HorSnchWdth(Tpix) 	/*  Horizontal Synchronization     */ \
-					/*  pulse Width [1..64 Tpix]       */ \
-			(((Tpix) - 1) << FShft (LCCR1_HSW))
+                	        	/*  pulse Width [1..64 Tpix]       */ \
+                	(((Tpix) - 1) << FShft (LCCR1_HSW))
 #define LCCR1_ELW	Fld (8, 16)	/* End-of-Line pixel clock Wait    */
                 	        	/* count - 1 [Tpix]                */
 #define LCCR1_EndLnDel(Tpix)    	/*  End-of-Line Delay              */ \
diff -urN linux-2.4.9-pre1/include/asm-arm/arch-sa1100/assabet.h linux/include/asm-arm/arch-sa1100/assabet.h
--- linux-2.4.9-pre1/include/asm-arm/arch-sa1100/assabet.h	Mon Dec  3 23:01:03 2001
+++ linux/include/asm-arm/arch-sa1100/assabet.h	Mon Dec  3 23:01:22 2001
@@ -124,8 +124,8 @@
 #define NEPONSET_USAR_IRQ	MISC_IRQ1
 
 #define NEPONSET_CPLD_BASE      (0x10000000)
-#define Nep_p2v( x )            ((x) - NEPONSET_CPLD_BASE + 0xf0000000)
-#define Nep_v2p( x )            ((x) - 0xf0000000 + NEPONSET_CPLD_BASE)
+#define Nep_p2v( x )            ((x) - NEPONSET_CPLD_BASE + 0xf3000000)
+#define Nep_v2p( x )            ((x) - 0xf3000000 + NEPONSET_CPLD_BASE)
 
 #define _IRR                    0x10000024      /* Interrupt Reason Register */
 #define _AUD_CTL                0x100000c0      /* Audio controls (RW)       */
diff -urN linux-2.4.9-pre1/include/asm-arm/arch-sa1100/ide.h linux/include/asm-arm/arch-sa1100/ide.h
--- linux-2.4.9-pre1/include/asm-arm/arch-sa1100/ide.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-arm/arch-sa1100/ide.h	Mon Dec  3 23:01:22 2001
@@ -112,15 +112,15 @@
         hw_regs_t hw;
 
         /* Enable GPIO as interrupt line */
-        GPDR &= ~GPIO_GPIO1;
-        set_GPIO_IRQ_edge(GPIO_GPIO1, GPIO_RISING_EDGE);
+        GPDR &= ~LART_GPIO_IDE;
+        set_GPIO_IRQ_edge(LART_GPIO_IDE, GPIO_RISING_EDGE);
         
         /* set PCMCIA interface timing */
         MECR = 0x00060006;
 
         /* init the interface */
 	ide_init_hwif_ports(&hw, PCMCIA_IO_0_BASE + 0x0000, PCMCIA_IO_0_BASE + 0x1000, NULL);
-        hw.irq = IRQ_GPIO1;
+        hw.irq = LART_IRQ_IDE;
         ide_register_hw(&hw, NULL);
 #endif
     }
diff -urN linux-2.4.9-pre1/include/asm-arm/arch-sa1100/lart.h linux/include/asm-arm/arch-sa1100/lart.h
--- linux-2.4.9-pre1/include/asm-arm/arch-sa1100/lart.h	Mon Dec  3 23:01:03 2001
+++ linux/include/asm-arm/arch-sa1100/lart.h	Mon Dec  3 23:01:22 2001
@@ -1,7 +1,13 @@
 #ifndef _INCLUDE_LART_H
 #define _INCLUDE_LART_H
 
-#define GPIO_UCB1200_IRQ        GPIO_GPIO (18)
-#define IRQ_GPIO_UCB1200_IRQ    IRQ_GPIO18
+#define LART_GPIO_ETH0			GPIO_GPIO0
+#define LART_IRQ_ETH0			IRQ_GPIO0
+
+#define LART_GPIO_IDE			GPIO_GPIO1
+#define LART_IRQ_IDE			IRQ_GPIO1
+
+#define LART_GPIO_UCB1200		GPIO_GPIO18
+#define LART_IRQ_UCB1200		IRQ_GPIO18
 
 #endif
diff -urN linux-2.4.9-pre1/include/asm-arm/arch-sa1100/simpad.h linux/include/asm-arm/arch-sa1100/simpad.h
--- linux-2.4.9-pre1/include/asm-arm/arch-sa1100/simpad.h	Mon Dec  3 23:01:03 2001
+++ linux/include/asm-arm/arch-sa1100/simpad.h	Mon Dec  3 23:01:22 2001
@@ -51,12 +51,12 @@
 
 #define SA1100_UART1_EXT \
   (struct huw_irq_desc){GPIO_UART1_CTS, IRQ_UART1_CTS, \
-			GPIO_UART1_DCD, IRQ_UART1_DCD, \
-			GPIO_UART1_DSR, IRQ_UART1_DSR}
+                        GPIO_UART1_DCD, IRQ_UART1_DCD, \
+                        GPIO_UART1_DSR, IRQ_UART1_DSR}
 #define SA1100_UART3_EXT \
   (struct huw_irq_desc){GPIO_UART3_CTS, IRQ_UART3_CTS, \
-			GPIO_UART3_DCD, IRQ_UART3_DCD, \
-			GPIO_UART3_DSR, IRQ_UART3_DSR}
+                        GPIO_UART3_DCD, IRQ_UART3_DCD, \
+                        GPIO_UART3_DSR, IRQ_UART3_DSR}
 
 
 /*---  PCMCIA  ---*/
diff -urN linux-2.4.9-pre1/include/asm-arm/keyboard.h linux/include/asm-arm/keyboard.h
--- linux-2.4.9-pre1/include/asm-arm/keyboard.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/keyboard.h	Mon Dec  3 23:01:22 2001
@@ -23,6 +23,12 @@
 
 #include <asm/arch/keyboard.h>
 
+#ifndef kbd_rate
+struct kbd_repeat;
+
+extern int kbd_rate(struct kbd_repeat *rate) __attribute__((weak));
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASM_ARM_KEYBOARD_H */
diff -urN linux-2.4.9-pre1/include/asm-arm/proc-armv/cache.h linux/include/asm-arm/proc-armv/cache.h
--- linux-2.4.9-pre1/include/asm-arm/proc-armv/cache.h	Mon Dec  3 23:01:03 2001
+++ linux/include/asm-arm/proc-armv/cache.h	Mon Dec  3 23:01:22 2001
@@ -231,7 +231,4 @@
  * cache entries for the kernels virtual memory range are written
  * back to the page.
  */
-extern void check_pgcache_dirty(struct page *page);
-
-#define update_mmu_cache(vma,address,pte) check_pgcache_dirty(pte_page(pte))
-
+extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte);
diff -urN linux-2.4.9-pre1/ipc/util.c linux/ipc/util.c
--- linux-2.4.9-pre1/ipc/util.c	Mon Feb 19 10:18:18 2001
+++ linux/ipc/util.c	Mon Dec  3 23:01:22 2001
@@ -75,7 +75,7 @@
 		ids->size = 0;
 	}
 	ids->ary = SPIN_LOCK_UNLOCKED;
-	for(i=0;i<size;i++)
+	for(i=0;i<ids->size;i++)
 		ids->entries[i].p = NULL;
 }
 
diff -urN linux-2.4.9-pre1/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-2.4.9-pre1/kernel/ksyms.c	Mon Dec  3 23:01:03 2001
+++ linux/kernel/ksyms.c	Mon Dec  3 23:01:22 2001
@@ -243,6 +243,8 @@
 EXPORT_SYMBOL(vfs_rename);
 EXPORT_SYMBOL(vfs_statfs);
 EXPORT_SYMBOL(generic_read_dir);
+EXPORT_SYMBOL(generic_file_llseek);
+EXPORT_SYMBOL(no_llseek);
 EXPORT_SYMBOL(__pollwait);
 EXPORT_SYMBOL(poll_freewait);
 EXPORT_SYMBOL(ROOT_DEV);
