Date: Thu, 19 Mar 1998 20:15:49 +0100
From: Jes Sorensen <Jes.Sorensen@cern.ch>
To: linux-m68k@lists.linux-m68k.org
Subject: L68K: 2.0.33pl1-pre take 2
Sender: owner-linux-m68k@phil.uni-sb.de

Hi

Here is a second attempt for the 2.0.33pl1 patch, which includes the
patches posted to the list recently and the following changes:

An old fix for the APNE driver from Alain Malek.
Frank Neumann's port of Andreas' pg-prot fix (Electric Fence)

and I think I found the reason why the blitter scrolling didn't work on
the CyberVision64 ... I am particularly interested if CV64 users would
try out this patch.

The patch is relative to the 2.0.33 release archive, so if you already
applied the 2.0.33pl1-pre patch I posted the other day you will have to
un-apply that before applying this patch.

Jes

diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/Documentation/Configure.help linux20/Documentation/Configure.help
--- /data/tmp/linux-2.0.33/Documentation/Configure.help	Wed Dec 17 10:02:16 1997
+++ linux20/Documentation/Configure.help	Tue Mar 17 11:33:02 1998
@@ -4237,10 +4237,10 @@
 
 Amiga Cirrus Logic support
 CONFIG_FB_CLGEN
-  If you have either a Piccolo, Piccolo SD64, Picasso II or GVP 
-  Spectrum graphic board in your Amiga, say Y here to enable the
-  driver for those boards. Otherwise say N. See 
-  Documentation/m68k/clgen.txt for installation and usage 
+  If you have either a Piccolo, Piccolo SD64, Picasso II, GVP 
+  Spectrum or Picasso IV graphic board in your Amiga, say Y here to 
+  enable the driver for those boards. Otherwise say N.
+  See Documentation/m68k/clgen.txt for installation and usage 
   instructions.
 
 Amiga GSP (TMS340x0) support
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/Documentation/m68k/clgen.txt linux20/Documentation/m68k/clgen.txt
--- /data/tmp/linux-2.0.33/Documentation/m68k/clgen.txt	Mon Jul 14 12:07:41 1997
+++ linux20/Documentation/m68k/clgen.txt	Mon Jan 12 15:51:21 1998
@@ -1,9 +1,9 @@
 
-
-            clgen v1.0 - a generic driver for Cirrus Logic based
+                          clgen v1.3 (12-Jan-98)
+                  A generic driver for Cirrus Logic based
                graphic boards for the Amiga under Linux/m68k
 
-                     Copyright (c) 1997 by Frank Neumann
+                  Copyright (c) 1997,1998 by Frank Neumann
 
 ------------------------------------------------------------------------
 
@@ -13,6 +13,26 @@
 IT IS IMPORTANT THAT YOU READ ALL OF THIS BEFORE EVEN ATTEMPTING TO USE
 THE DRIVER! DON'T EXPECT X11 TO WORK AS ON INTEL LINUX BOXES!
 
+0) Changes since v1.2
+   - some bugfixes
+   - now accepts monitorcap: and mode: on command line
+
+   Changes since v1.0
+   - text consoles on your graphic board! Just start the kernel with
+     amiboot [..] video=clgen
+   - For 8 bpp (standard case), console scrolling&filling is accelerated
+   - Picasso IV support
+   - no more need to use the "tog" tool
+   - correct standard VGA color palette
+   - uses the FB_ACTIVATE_* flags correctly now
+   - correct behaviour when used with fbset
+
+   Important! The driver now sits in fb0*, so you can remove the old fb1*
+   entries from /dev. Though, you'll either have to rename your fb0*
+   entries to more meaningful names ("fb0pal" is a bit irritating for
+   1024x768 :-), or create additional symlinks with meaningful names;
+   see below in "Creating /dev entries".
+
 
 1) Supported hardware
 ---------------------
@@ -22,13 +42,14 @@
 - Piccolo      (Ingenieurbuero Helfrich)
 - EGS Spectrum (GVP)
 - Picasso II   (Villagetronic)
+- Picasso IV   (Villagetronic)
 
 The Picasso II is only supported in linear (non-segmented) mode. Please
 make sure that the switch on the rear of the board is set to linear mode.
 
 All other boards only do linear mode, and should thus work out of the box.
 It shouldn't matter whether you use them in Z2 or Z3 mode; the only
-difference probably being that through into the Z2 area is not as fast as
+difference probably being that throughput into the Z2 area is not as fast as
 into Z3 memory.
 
 
@@ -38,7 +59,7 @@
 - Variable resolutions: The user can create his own resolutions if he knows
   what he is doing. The driver comes with some pre-generated resolutions, 
   though:
-  640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock
+  640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock (startup mode)
   800x600, 48 kHz, 72 Hz, 50 MHz PixClock
   1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock
   320x200, 31.4 kHz, 70 Hz, 25 MHz PixClock (Super-LoRes ;-)
@@ -68,19 +89,25 @@
   feature of the vga controller which outputs every scanline twice. The
   supplied 320x200 mode uses this. Amaze your friends with a game like
   Thrust filling the entire screen! :-)
+  Please note that this mode is not yet available with fbset, as it misses
+  a little option I have to add. It's still in the kernel, though.
 
 - Supports multiple boards in one computer: While probably not many users
   will ever need this feature, I found it very helpful while developing. :-)
   At startup, the driver looks for all boards it supports, and initializes
   and registers each of them.
+  TODO: This does currently NOT work (v1.2) due to the number of changes
+  I had to put in for console support.
 
 - Should correctly determine the amount of DRAM available on the board
   (please mail me if this does not work on your board!)
 
 - Allows to set the maximum vertical/horizontal frequencies with regard to
-  the connected monitor. This is done via a new little program "freq"
-  (see below) which might be integrated into fbset later.
+  the connected monitor. This is done either at the amiboot command line
+  (recommended) or via a little program "freq" (see below).
 
+- Allows larger consoles than the default right at kernel startup time;
+  no PC-ish hassle with something like svgatextmode!
 
 3) Installing the driver
 ------------------------
@@ -97,12 +124,15 @@
 archive you unpacked. However, it might also already have been applied
 to the kernel source tree; if that is so, I forgot to update this text
 file in time; in that case bug me to update it. :-)
-I used a 2.0.29 kernel source tree. I haven't yet tried with 2.1.x kernels;
-this might require a few changes.
+I used a 2.0.33 kernel source tree. Adapting the driver for 2.1.xx kernels
+will be the next thing to do. Please be patient.
 
 Applying source patches should be something you know about; in a nutshell:
 (cd /usr/src/linux; patch -p0 -s < "path_to_clgen_diffs" )
 
+After that, copy the driver main files (clgen.c and clgen.h) to their
+destination in "arch/m68k/amiga/" in the kernel source tree.
+
 Next, start the configuration with 
 # make config
 
@@ -128,46 +158,106 @@
 in /dev. Usually, you already have a couple of fb0* nodes in there which 
 are associated with the built-in video hardware of the Amiga (OCS, ECS or 
 AGA).
-Likewise, you will now create some nodes for the clgen driver, which should
-be named fb1*. Here is what I suggest; these are sort-of telling names that 
-correspond to the modes that come with the driver:
-
-cd /dev
-mknod fb1current c 29 32
-mknod fb1autodetect c 29 33
-mknod fb1_640 c 29 34
-mknod fb1_800 c 29 35
-mknod fb1_1024 c 29 36
-mknod fb1_320 c 29 37
-mknod fb1_1024i c 29 38
-mknod fb1_1024hi c 29 39
-mknod fb1_1280i c 29 40
+
+Now, when starting the kernel with the console on the graphic board, the
+fb0 framebuffer device is not used by the Amiga's video chipset (OCS/ECS/AGA),
+but by the graphic board. This means you still use the fb0* entries in
+/dev, but the video modes "behind" the names have changed (they are now
+the predefined modes in the clgen driver). 
+
+You could now either remove the old fb0* devices and create new ones with
+the same major/minor device number, but with more meaningful names, or
+(what I recommend) keep the old ones and create the new, meaningful names
+as symlinks pointing to the old ones.
+
+Here is what I suggest; these are sort-of telling names that correspond to 
+the modes that come with the driver.
+
+First, log in as root, go to /dev, check that there are already the
+"typical" fb0 devices for Amiga; the following should exist:
+
+crw-rw-rw-   1 root     root      29,   0 Aug  5  1996 fb0current
+crw-rw-rw-   1 root     root      29,   1 Oct  1  1996 fb0autodetect
+crw-rw-rw-   1 root     root      29,   2 Oct 21 20:11 fb0ntsc
+crw-rw-rw-   1 root     root      29,   3 Oct 21 20:11 fb0ntsc-lace
+crw-rw-rw-   1 root     root      29,   4 Oct 21 17:34 fb0pal
+crw-rw-rw-   1 root     root      29,   5 Dec 31  1996 fb0pal-lace
+crw-rw-rw-   1 root     root      29,   6 Dec  5  1996 fb0multiscan
+crw-rw-rw-   1 root     root      29,   7 Dec  5  1996 fb0multiscan-lace
+crw-rw-rw-   1 root     root      29,   8 Oct 21 17:34 fb0a2024-10
+
+If they don't exist, get the fbset program source, compile and install
+it; it contains a target in the Makefile to create those (and more) device
+nodes for you.
+
+Now, create the clgen device nodes as symlinks pointing to the old devices:
+# ln -s fb0ntsc fb0cl-low
+# ln -s fb0ntsc-lace fb0cl-med
+# ln -s fb0pal fb0cl-high
+# ln -s fb0multiscan fb0cl-highi
+# ln -s fb0multiscan-lace fb0cl-highi+
+# ln -s fb0a2024-10 fb0cl-vhigh
+
+You should now see this:
+
+root@colorpot:/dev> ll fb0cl*
+lrwxrwxrwx   1 root        6 Dec 19 15:47 fb0cl-high -> fb0pal
+lrwxrwxrwx   1 root       12 Dec 19 15:47 fb0cl-highi -> fb0multiscan
+lrwxrwxrwx   1 root       17 Dec 19 15:47 fb0cl-highi+ -> fb0multiscan-lace
+lrwxrwxrwx   1 root        7 Dec 19 15:47 fb0cl-low -> fb0ntsc
+lrwxrwxrwx   1 root       12 Dec 19 15:47 fb0cl-med -> fb0ntsc-lace
+lrwxrwxrwx   1 root       11 Dec 19 15:48 fb0cl-vhigh -> fb0a2024-10
+
+Well, that's it. Now you can access the modes through meaningful (or so I
+think :-) names, but still have the old Amiga video mode names around.
+
+At this time you might wonder what video modes are actually behind those
+names; here is a short list:
+
+/dev name     resolution    line frequency (kHz)    frame frequency (Hz)
+              x     y
+fb0cl-low     640   480           31.25                   60
+fb0cl-med     800   600           48.1                    72
+fb0cl-high    1024  768           56                      70
+fb0cl-highi   1024  768           31.3                    77   (*)
+fb0cl-highi+  1024  768           46.3                    113  (*)
+fb0cl-vhigh   1280  1024          51                      87   (*)
+
+(*) interlaced video modes
+
+Additionally, you might want to create one more symlink that will be used
+for X11 at all times; for instance, I always use the 1024x768 non-interlaced
+mode for X11 (which is named "fb0cl-high" in the example above).
+So, I create a symlink:
+
+# ln -s fb0cl-high fb0x11
+
+And now I just tell the Xserver to use this mode when starting:
+$ export FRAMEBUFFER=/dev/fb0x11
+$ startx
 
 
 5) Installing the utilities
 ---------------------------
 
-This driver comes what a small set of tools for maintenance; these are
-"freq", "tog" and a slightly modified version of "fbset". You get both 
-sources and binaries. For now, I suggest to copy the binaries to your
-/usr/local/bin directory and having your PATH variable point at that
-location.
+[Please note: Now that it is possible to set the monitor limits immediately
+at kernel-startup time, there is no more need for "freq" at all; but I
+still include it for your convenience.
+For information about setting the monitor limits on the amiboot command line,
+see below in "Starting the kernel"].
+
+This driver comes with a small tool for maintenance named "freq".
+You get both sources and binaries (compiled for libc6 aka glibc).
+For now, I suggest to copy the binary to your /sbin directory and having 
+your PATH variable point at that location.
 
 "freq" allows to inquire or set the current monitor limits for the driver,
 on a per-board basis.
 
-"tog" is a tool to switch the relais on the graphic board that selects
-between "Pass-Through" mode (Amiga video signal is passed through the
-graphic board) or "Board mode" (where the board's own video signal is
-sent to the output).
-
-The new "fbset" is just slightly extended to allow to set/clear the
-the "ClockHalving" bit which is usually required for DoubleScan modes
-(at least on VGA boards). Its purpose is to avoid interferences between
-the video and the memory clock if they are close to each other. These
-interferences cause jagged vertical lines in the display, and by first
-doubling the video clock and then "artificially" halving it again this
-problem goes away.
+There used to be another tool named "tog", but this is not required
+anymore and will do nothing when started against this driver version;
+please delete it. Also, remove any invocations of it, like in your
+$HOME/.xinitrc.
 
 
 6) Checking the cabling
@@ -178,20 +268,59 @@
 board's 9-pin input with a short cable, and the VGA board's output is
 connected to the monitor. This allows to either see the Amiga video signal
 (by letting it pass through the board) or the VGA board's signal (by
-switching the toggle via "tog".
+switching the toggle). If you start the kernel with "video=clgen", though
+(see below, under "Starting the kernel"), the board's own video output is
+visible all the time and there is no Amiga display at all, so there is no
+need to ever switch back to the Amiga signal.
 
 If you have a 2-monitor-setup (one monitor connected to the Amiga, the other
-connected to the VGA board), the usage of "tog" is still the same; but you 
-can just instruct "tog" to switch to the VGA board's output ONCE at boot
-time, and never have to care about it afterwards. 
-
+connected to the VGA board), you will see that when you start the kernel
+with "video=clgen", the Amiga's signal is just a gray blank screen. This
+is so because the Amiga display subsystem is not initialized at all.
+You can safely forget about the monitor connected to the Amiga's video
+output now.
 
 7) Starting the kernel
 ----------------------
 
-Starting the kernel works just the same way you were used to; there are
-(as of now) no additional parameters you have to give. This might change
-one day when console support is added.
+Starting the kernel with its display on your graphics board works similar to
+the way you used to start kernels before: To your list of options passed to 
+either amiboot or amiga-lilo (I only use amiboot, so I can't explain what
+exactly you have to do to the latter), add the following:
+
+video=clgen[:suboption,suboption]
+
+The suboptions allow you to set the monitor capabilities or startup video
+mode right here, instead of having to use freq or fbset later. Here's
+how they have to look like:
+
+monitorcap:vmin;vmax;hmin;hmax
+
+  where vmin and vmax are vertical minimum and maximum frequencies in Hz,
+  and hmin and hmax are horizontal min/max frequencies in kHz(!).
+  The default values are "monitorcap:50;90;30;38", which means vertical
+  range from 50 to 90 Hz and horizontal range from 30 to 38 kHz.
+
+mode:{low|med|high}
+  This sets the startup (default) video mode for all consoles.
+
+  Name    resolution[pixels]   hfreq[kHz]     vfreq[Hz]   columns  rows
+  low        640x480            31.25           60           80     30
+  med        800x600            48              72          100     37
+  high      1024x768            55.8            70          128     48
+
+So, here's as an example a complete line from MY current setup;
+don't even think about using exactly this line in your setup:
+
+   "video=clgen:monitorcap:50;120;30;86,mode:high"
+
+PLEASE NOTE! The ";" character under AmigaOS has the meaning of a comment,
+thereby discarding the rest of the line. Therefore, if you use the
+"monitorcap:" suboption, don't forget to enclose the whole option in
+double quotes (" ") to avoid this misinterpretation of ";". If the kernel
+does not start in the way you expected, this is a possible reason; type
+"cat /proc/cmdline" to see whether really the whole parameter list was
+passed through.
 
 When the kernel starts, you should see the clgen driver report its
 version number and what hardware it has found, like this:
@@ -199,7 +328,8 @@
 [..]
    0x42000000: Helfrich SD64 Graphics Board (RAM) (Z3, 16M)
    0x00e90000: Helfrich SD64 Graphics Board (REG) (Z2, 64K)
- clgen: Driver for Cirrus Logic based graphic boards, v1.0 (27-Feb-97)
+ clgen: Driver for Cirrus Logic based graphic boards, v1.3 (12-Jan-98)
+ clgen: Monitor limits set to H: 30000 - 86000 Hz, V: 50 - 120 Hz
  clgen: SD64 board detected;  RAM (16384 KB) at $42000000,  REG at $e90000
  clgen: This board has 4194304 bytes of DRAM memory
 [..]
@@ -209,37 +339,24 @@
 than the amount of RAM on the board. The number in the last line should
 be the actual amount of RAM your board has.
 
-When you see these messages, the driver has started up successfully, and
-has already initialized the board to a safe video mode (640x480). You just
-can't see it because the board's video toggle switch is still in 
-"Pass-Through" mode.
-
-To see the video output of the board, log in as root, make sure you have
-created the necessary device nodes as described in the 
-"Creating /dev entries" section, and type 
-
-tog 1 1
-
-The monitor should now display the VGA board's signal - which, if everything
-went well, is a 640x480 display with a line frequency of 31.5 kHz, a 
-frame frequency of 60 Hz, showing a black screen surrounded by a white
-border with a pattern of colors in the center (16 shades of each white,
-red, green, blue, yellow, purple, cyan). 
+At this point you can already open a bottle of champagne, because if you
+can read the above messages, it means the driver works for you. The (default)
+console looks pretty much like before on OCS/ECS/AGA, but it's now in 
+60 Hz instead of 50 Hz (PAL), and it uses 256 colors. Of course, if you
+immediately try to use one of the higher console sizes (mode:med or 
+mode:high), it will look even better :-). But for a start it's probably
+wise to begin with the default mode and make sure that it works.
+
+If you attempt to start the kernel with a video mode that exceeds the
+monitor limits, the driver will fall back to the standard "low" mode instead.
+Also, if your "monitorcap:" suboption makes no sense, the driver will
+switch back to the default of H:30-38 kHz, V:50-90 Hz.
+
+The display might be misaligned now (like too wide or not centered).
 If your monitor has the ability to store video mode settings (display
 size and location), you can use its controls now to center the display.
-
-To switch back to the Amiga's video display, you will have to type
-in (BLINDLY):
-
-tog 1 0
-
-This may seem very unconvenient, but it's all I can do at the moment.
-You'd better get a feeling for typing this; it might happen e.g. that
-your Xsession crashes and leaves you with a "frozen" display from the
-VGA board; at that time you will also have to use "tog 1 0" manually
-to switch back to the Amiga display.
-More information on the usage and parameters of "tog" can be found below
-in the "Switching to/back from the board" section.
+Though, you can also use fbset to do that; see below, in "Using fbset
+to adjust modes".
 
 
 8) Setting/inquiring the monitor limits
@@ -251,7 +368,7 @@
 the specifications of the monitor. But how can the driver know the limits?
 The answer is: You have to tell him.
 
-By default, clgen assumes that the connected monitor is a"poor" model that
+By default, clgen assumes that the connected monitor is a "poor" model that
 can only do 30 - 38 kHz line frequency and 50 - 90 Hz frame frequency. 
 These should be "careful" defaults for most monitors in use nowadays.
 Also, the video mode that the board produces at kernel startup is a
@@ -265,8 +382,14 @@
       clgen: desired mode exceeds monitor limits (rejected)!
 
 If your monitor CAN handle higher frequencies than the default, please look
-up its limits in your monitor's manual, and use the "freq" tool to tell the
-driver about it. The usage is:
+up its limits in your monitor's manual, and set the corresponding values
+in the kernel, using either the "monitorcap:" option as explained in the
+previous chapter, or use the "freq" tool to tell the driver about it. 
+I recommend using the "monitorcap:" option of amiboot, as your monitor limits
+will probably rarely ever change in the near future, and most of the time
+there is no need to change the limits during one Linux session.
+
+The usage is:
 
 Usage: freq [-q] [-f n] [-s minhor:maxhor:minvert:maxvert]
  -q                                queries the current monitor settings
@@ -274,19 +397,19 @@
  -s minhor:maxhor:minvert:maxvert  sets new limits
     All min/max values are in Hertz (hz), e.g. 30000:38000:50:90
 
-So, to get the current limits for framebuffer #1 (which is probably
+So, to get the current limits for framebuffer #0 (which is probably
 your graphic board), type:
 
-root@debian:~> freq -f 1 -q
-Current monitor limit settings for fb driver #1 [CLGen:SD64]:
+root@debian:~> freq -f 0 -q
+Current monitor limit settings for fb driver #0 [CLGen:SD64]:
 Horizontal: 30000 - 38000 Hz
 Vertical: 50 - 90 Hz
 
 Let's assume your monitor can do 30 - 58 kHz line frequency, and 50 - 100
 Hz frame frequency. Then, you'd type (as root):
 
-root@debian:~> freq -f 1 -s 30000:58000:50:100
-Monitor limit settings for fb driver #1 [CLGen:SD64] have been set to:
+root@debian:~> freq -f 0 -s 30000:58000:50:100
+Monitor limit settings for fb driver #0 [CLGen:SD64] have been set to:
 Horizontal: 30000 - 58000 Hz
 Vertical: 50 - 100 Hz
 
@@ -298,30 +421,28 @@
 PLEASE NOTE: Don't just enter some invented numbers - LOOK UP THE SPECS
 IN YOUR MONITOR'S MANUAL! Otherwise you risk damaging your hardware.
 
-
-9) Switching to/back from the board
------------------------------------
-You have already learnt about the "tog" utility that is used to switch
-the signal relais on the graphic board. Here is how "tog" is actually
-used:
-
-root@debian:~/txt> tog
-Usage: tog <boardnum> 0/1
-0=Video from Amiga
-1=Video from board
-
-So, the first parameter to "tog" is the board number - or, rather the
-framebuffer number. As the built-in video hardware is serviced by the
-amifb framebuffer (#0), your graphic board will typically be registered
-as framebuffer #1, and so this parameter will be 1 in most cases.
-The second parameter is self-explanatory: It selects either the
-"PassThrough" or the "Board" mode.
-
-This command is intentionally named so short to allow easy&quick
-"blind typing".
+PLEASE NOTE2: If you are upgrading from the 1.0 driver, check out any place
+where you start freq; the framebuffer number is now 0 and not 1 anymore
+(as it used to be)!
+
+Personal suggestion: If you do not want to use the "monitorcap:" option
+for whatever reason, I suggest to put the "freq" invocation into a startup
+file like "/etc/init.d/boot" (or however it is called on your installation).
+But note that by the time the program is started, your root partition is
+probably the only one that is mounted - so keep the "freq" binary in a place
+on the root partition (like /sbin).
+
+PLEASE NOTE3: Once you have installed the "freq" invocation in a startup
+file like suggested in the previous note, starting the kernel with an
+Amiga console again ("video=pal-lace" or similar), you might run into
+problems when trying to change a mode; this is so because some of the Amiga's
+video modes just use 15 kHz line frequency (even if doubled by a hardware
+flickerfixer; it's the number that counts), and your monitor can only do 
+30 kHz or above. In that case, you will have to change the monitor limits
+again before you can change video modes for it.
 
 
-10) Using fbset to adjust modes
+9) Using fbset to adjust modes
 -------------------------------
 You have probably 2 choices to center the display on your monitor:
 You can either use the monitor itself (newer models are able to store
@@ -336,7 +457,7 @@
 640x480 image, but it is not centered. Now you can use fbset like this
 to move the image around:
 
-# fbset -ofb /dev/fb1current -move [left|right|up|down]
+# fbset -move [left|right|up|down]
 
 This will move the image in the corresponding directions (not every
 invocation moves the display as the granularity of fbset is finer than
@@ -347,12 +468,43 @@
 fbset to print out the current timing parameters of the "current"
 video mode:
 
-# fbset -ifb /dev/fb1current --info
+# fbset -i
 
 and write the "mode" part of the output into your /etc/fb.modes file
-where it is quickly available.
-
-(This section is still a bit short; sorry. To be extended..)
+where it is quickly available. Replace the "name" with a meaningful name
+(I suugest to choose a naming scheme that start with "cl-", like "cl-high".
+From now on, you can immediately set this mode with a command like
+"fbset cl-high".
+
+NOTE GPM USERS!
+The "gpm" program which lets you do Cut&Paste operations on the console
+will not notice when you change the console's video mode (size) and will
+continue to use the columns/rows numbers it has determined when it started.
+This can lead to two strange things:
+
+a) You change to a higher-resolution console: The mouse cursor of gpm will
+   not be able to access certain parts of the console (at the far right
+   and bottom of the screen).
+
+b) You change to a lower-resolution console: It is possible to move the
+   mouse cursor out of the visible area.
+
+These are no bugs of clgen. My solution suggestions are:
+- to fix gpm's signal handling (if it's really the culprit)
+- to not change the console size at all (and only use mode:xxx at startup)
+- to restart gpm after a console size change
+
+In section "Example of fb.modes entries" below you will find a list of
+modes that you can append to your /etc/fb.modes file. The listed modes are
+exactly the same as those found in the kernel driver (except for the
+SuperLoRes mode).
+
+All of this still doesn't really help you because the mode used by the kernel
+at startup time is not taken from /etc/fb.modes, but from the driver itself;
+if you have changed the video mode and want it to appear like that
+immediately at kernel startup time, you still have the option to put your
+new timings into the driver's mode database itself and compile your own
+custom kernel. 
 
 
 PLEASE NOTE: THE PARAMETER CHECKING IN THE DRIVER IS VERY INCOMPLETE;
@@ -366,10 +518,10 @@
 640x480 pixels, which is usually too little for reasonable working in X11.
 So, to create a virtual workspace of, say, 1024x768 pixels, you'd
 type:
-# fbset -ofb /dev/fb1_640 -vxres 1024 -vyres 768
+# fbset -ofb /dev/fb0x11 -vxres 1024 -vyres 768
 
 Now you just have to tell the Xserver which mode to use, and start it:
-# export FRAMEBUFFER=/dev/fb1_640
+# export FRAMEBUFFER=/dev/fb0x11
 # startx
 
 When the Xserver has started, trying moving the mouse pointer against
@@ -377,44 +529,111 @@
 effect.
 
 
-11) Starting/using X11 with clgen
+10) Starting/using X11 with clgen
 ---------------------------------
 The application that's (IMHO) going to be the most-used one is the X
 Window System. Unfortunately, using it with the clgen driver is not quite
-as easy as is with Linux on i386 machines.
+as easy as is with Linux on i386 machines, but it's very close by now.
+
+The only thing you have to do before you can start X is to tell the Xserver
+on which framebuffer device it has to work; using bash, this is typically
+something like:
 
-The problem is this: The Xserver on PCs allows to switch back and forth
-between the text consoles and the Xserver's graphical display at any
-time. This is also true for the m68k implementation of the Xserver, but
-the kernel-based graphic drivers do not get to know when a switch occurs,
-and so the clgen driver cannot tell when it has to switch the monitor
-relais on the board. This problem does not occur on the built-in (OCS/
-ECS/AGA) framebuffer because it never has to switch a monitor bit.
-
-The only way out is to either manually type in the "tog" invocations when
-you want to switch, or rather not use the VT/X switching capability at
-all during one X session.
-
-Now, to at least have the switch automatically perform its task at the 
-start and end of an Xsession, I suggest to put the following lines into 
-your ~/.xinitrc:
-
-- Immediately before the first X application is started (like fvwm, xterm
-  or whatever), put in:
-
-  tog 1 1
-
-- Behind the last application (the critical application; this is the one
-  that is not started in the background and makes the Xsession fall through
-  when it is terminated) :
-  tog 1 0
+$ export FRAMEBUFFER=/dev/fb0x11
+$ startx
 
-This should be usable - although it is certainly not nice.
+Replace the "fb0x11" with whatever video mode device you want to use for X.
 
 If you rather start an Xsession via xdm instead of "startx", you will have
-to put the "tog 1 1" line into something like /etc/init.d/boot (or 
-wherever your xdm gets started). In that case you'll probably never
-want to switch back to VCs.
+to put the "export ..." line into something like /etc/init.d/boot (or 
+wherever your xdm gets started). It's just important that FRAMEBUFFER
+is set to the correct device name before the Xserver starts.
+
+
+11) Example of fb.modes entries
+-------------------------------
+
+The following is an excerpt from my /etc/fb.modes file; it provides the
+same video modes as those predefined in the clgen driver. Just append this
+to your /etc/fb.modes file, and you can immediately switch to one of them
+by feeding its name (from the "mode" line) to fbset, like so:
+
+$ fbset cl-med
+
+This will of course only work if:
+ - your monitor can operate at the desired frequency
+ - you set the monitor limits with freq accordingly
+
+
+########################
+## CLGen modes, as found in the predefined modes in the driver
+########################
+
+# 640x480. This mode should work on ANY Multiscan monitor
+mode "cl-low"
+	# H: 31.250 kHz, V: 59.524 Hz
+	geometry 640 480 640 480 8
+	timings 40000 32 32 33 10 96 2
+	hsync high
+	vsync high
+	bcast false
+endmode
+
+# 800x600. Nices for consoles
+mode "cl-med"
+	# H: 48.077 kHz, V: 72.188 Hz
+	geometry 800 600 800 600 8
+	timings 20000 64 56 23 37 120 6
+	hsync high
+	vsync high
+	bcast false
+endmode
+
+# 1024x768, non-interlaced. If your monitor can do this, it's a
+# good choice for X11.
+mode "cl-high"
+	# H: 55.866 kHz, V: 69.399 Hz
+	geometry 1024 768 1024 768 8
+	timings 12500 92 112 31 2 204 4
+	hsync high
+	vsync high
+	bcast false
+endmode
+
+# 1024x768, interlaced. If your monitor is not capable of high
+# horizontal frequencies, this might be a good alternative to cl-high.
+mode "cl-highi"
+	# H: 31.360 kHz, V: 76.769 Hz
+	geometry 1024 768 1024 768 8
+	timings 22268 92 112 32 9 204 8
+	hsync high
+	vsync high
+	laced true
+	bcast false
+endmode
+
+# 1024x768 interlaced, but with a bit higher frequencies, so less flicker.
+mode "cl-highi+"
+	# H: 46.240 kHz, V: 113.196 Hz
+	geometry 1024 768 1024 768 8
+	timings 15102 92 112 32 9 204 8
+	hsync high
+	vsync high
+	laced true
+	bcast false
+endmode
+
+# 1280x1024 interlaced. For those who want "full-size" X11. :-)
+mode "cl-vhigh"
+	# H: 51.020 kHz, V: 87.589 Hz
+	geometry 1280 1024 1280 1024 8
+	timings 12500 56 16 128 1 216 12
+	hsync high
+	vsync high
+	laced true
+	bcast false
+endmode
+
 
 
 12) Not-Yet-Features(tm), ToDo's
@@ -431,20 +650,13 @@
   "rrrrrggg gggbbbbb", but instead "gggbbbbb rrrrrggg" which the Xserver
   will probably never be able to cope with).
 
-- module support: Allow the driver to be compiled as a module that can be
-  loaded/unloaded on demand.
-
-- Console support: It would be nice to also make use of the boards' text
-  modes, but this is not nicely integratable into the current m68k 
-  console handling. Probably when the whole stuff has been cleared up,
-  I'll go for this. Of course, once that is implemented, it will NOT be
-  possible to use the console feature AND a modularized driver at once. :-)
-
-- Make use of the BitBlt engine: I understand that lacking blitter support
-  leaves a good deal of the hardware capabilities unused, but the current
-  framebuffer driver does not make any provisions for using accelerated
-  hardware. Probably once we adopt the ggi concept, this might be added.
-  Until then, there is nothing I can do about it.
+- Make use of the BitBlt engine for X11: I understand that lacking blitter 
+  support leaves a good deal of the hardware capabilities unused, but the 
+  current framebuffer driver does not make any provisions for using 
+  accelerated hardware in an application program (like the Xserver).
+  Probably once we adopt the ggi concept, this might be added.
+  Until then, there is nothing I can do about it. But at least the console
+  is already accelerated.
 
 
 13) Non-features(tm), also known as Known bugs
@@ -454,20 +666,8 @@
   border that should actually be at the right border. I haven't yet found
   the reason for this.
 
-- On my monitor, the SD64 display in 1024x768 looks somewhat blurry (all
-  characters "smear" a bit to the right). I'm not sure what causes this;
-  the cable is a good one (BNC). If other people notice this, too (and find
-  that under AmigaOS they do NOT have this problem), I might have to 
-  investigate on it.
-
-- I could test this driver on a Piccolo, SD64 and Picasso II; therefore,
-  the Spectrum support is yet untested by me. If someone with a Spectrum
-  uses this driver: PLEASE TELL ME ABOUT THE RESULTS! I believe it
-  should work, but the Spectrum support was put in "blindly".
-
-- A lot of safety checks still need to be written; e.g., you can easily
-  create Oopses by requesting a display larger than the board's DRAM
-  area. So, DON'T DO THAT.
+- A few safety checks are still not in there. Use the driver, but don't stress
+  it to its limits :-}.
 
 
 14) Credits
@@ -479,7 +679,8 @@
 - Joerg Ringelberg of Viona, Karlsruhe, for supplying me with the databooks
   for CL GD542x/5434.
 - Klaus Burkert of Villagetronic for some hints on Fifo threshold settings
-  during the Steinhagen Amiga meeting in October '96.
+  during the Steinhagen Amiga meeting in October '96, and also for info
+  on how to turn off the VideoCapture unit on the P4.
 - My professor of the Computer Graphics department, Peter Gorny, for
   accepting this as topic for a "Studienarbeit". I always knew studying
   CAN be fun at times. :-)
@@ -491,12 +692,15 @@
   of the ideas behind fb.
 - Geert Uytterhoeven for several helpful hints and suggestions
 - Anyone else involved in making Linux/m68k as usable and stable as it is
-  now. Although I believe we won't be able to push Billybox Gates out
+  now. Although I believe we won't be able to push Billyboy Gates out
   of the market with this, it shows how well people from all over the world
   can cooperate in the Internet to work on a common goal.
 - All you users who bugged me then and now about when this beast will be
   released; I know it took MUCH longer than I had expected/told you,
   but after all it's out now, and is free. Forgive me.
+- The "beta guinea pigs" :-) on IRC - Chels, Nes, pCp, you know who you are.
+  Thanks for testing&bug reporting.
+
 
 15) Contacting the author
 ------------------------
@@ -514,6 +718,11 @@
 from those too much mailing lists I'm subscribed to ;-). Oh, and one more
 thing: I DO NOT LIKE MIME-MAIL.
 
+The newest version of this driver should always be available through my
+homepage: http://www.informatik.uni-oldenburg.de/~amigo/
+Look out for some "Linux/m68k" stuff in that page. I'm sure you'll be
+able to find it! :-)
+
 If you want to report a bug, please don't forget to include:
  - what kernel you are running
  - what version of clgen you are using
@@ -522,10 +731,28 @@
  - whether the problem is reproducible or not
  - ..and any other information that might be helpful.
 
+
 16) History
 ----------
 
  *  - 16-Mar-1997: v1.0 First public release
+ *  - 22-Oct-1997: v1.1 Added basic console support, P4 support (not working)
+ *                      This was never released to the public
+ *  - 19-Dec-1997: v1.2 Public release
+ *                      working console support
+ *                      working P4 support
+ *                      hardware-accelerated RectFill/BitBLT on consoles
+ *                      (only in 8 bits right now)
+ *                      correct standard VGA colour table
+ *                      1 bit support working again
+ *                      uses the FB_ACTIVATE_* flags correctly now
+ *                      correct behaviour when used with fbset
+ * - 12-Jan-1998: v1.3  Public release
+ *                      correct CLUT handling for Picasso4 (was BGR, not RGB)
+ *                      removed left-over printk for Picasso II
+ *                      now accepts monitorcap: and mode: on command line
+ *                      correct "scrolling" when height or width = 0
+ *                      (though that's been done in console/fbcon.c)
 
 
 42) Final words
@@ -537,10 +764,10 @@
 in hearing how you managed to do that, though. :-)
 This is free software, but I'd never reject signs of appreciation. Even
 a little postcard is something I'd always welcome.
-Personal plug: I might be able to finish my studies in late '98 - got an
-interesting job then? Here I am. :-)
+Personal plug: I might be able to finish my studies sometime in spring '99 - 
+got an interesting job then? Here I am. :-)
 
-Frank, March 16th, 1997
+Frank, 12 Jan 1998
 --
 +        Frank Neumann, Hauptstr. 107, 26131 Oldenburg, Germany         +
 +     InterNet: Frank.Neumann@informatik.uni-oldenburg.de IRC:Franky    +
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/arch/m68k/amiga/amifb.c linux20/arch/m68k/amiga/amifb.c
--- /data/tmp/linux-2.0.33/arch/m68k/amiga/amifb.c	Wed Dec 17 10:02:21 1997
+++ linux20/arch/m68k/amiga/amifb.c	Thu Mar  5 12:10:08 1998
@@ -1322,7 +1322,11 @@
 #endif /* CONFIG_FB_CYBER */
 
 #ifdef CONFIG_FB_CLGEN			/* Cirrus Logic boards */
-extern void clgen_fb_init(long *mem_start);
+extern int clgen_probe(void);
+extern void clgen_video_setup(char *options, int *ints);
+extern struct fb_info *clgen_fb_init(long *mem_start);
+
+static int amifb_clgen = 0;
 #endif
 
 #ifdef CONFIG_GSP_RESOLVER			/* DMI Resolver */
@@ -1358,6 +1362,15 @@
 		}
 #endif /* CONFIG_FB_CYBER */
 
+#ifdef CONFIG_FB_CLGEN
+	if (options && *options)
+		if (!strncmp(options, "clgen", 5) && clgen_probe()) {
+			amifb_clgen = 1;
+			clgen_video_setup(options, ints);
+			return;
+		}
+#endif /* CONFIG_FB_CLGEN */
+
 #ifdef CONFIG_GSP_RESOLVER
 	if (options && *options)
 		if (!strncmp(options, "resolver", 5) && resolver_probe()) {
@@ -1833,6 +1846,11 @@
 		return Cyber_fb_init(mem_start);
 #endif /* CONFIG_FB_CYBER */
 
+#ifdef CONFIG_FB_CLGEN
+	if (amifb_clgen)
+		return clgen_fb_init(mem_start);
+#endif
+
 #ifdef CONFIG_GSP_RESOLVER
 	if (amifb_resolver){
 		custom.dmacon = DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
@@ -1992,10 +2010,6 @@
 	fb_info.blank = &amifbcon_blank;
 
 	amiga_fb_set_var(&amiga_fb_predefined[0], 0, GET_FB_IDX(node));
-
-#ifdef CONFIG_FB_CLGEN
-	clgen_fb_init(mem_start);
-#endif
 
 	return &fb_info;
 }
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/arch/m68k/amiga/clgen.c linux20/arch/m68k/amiga/clgen.c
--- /data/tmp/linux-2.0.33/arch/m68k/amiga/clgen.c	Wed Dec 17 10:02:22 1997
+++ linux20/arch/m68k/amiga/clgen.c	Mon Mar 16 11:10:05 1998
@@ -1,14 +1,36 @@
-
 /*
  * arch/m68k/amiga/clgen.c - kernel-based graphic board driver for
  *                            Cirrus-Logic based VGA boards
  *
- *    Copyright (c) 1997 Frank Neumann
+ * This driver currently supports: Piccolo, Picasso II, GVP Spectrum, 
+ * Piccolo SD64, Picasso IV
+ *
+ *    Copyright (c) 1997,1998 Frank Neumann
  *
  *
  *  History:
  *  - 16-Mar-1997: v1.0 First public release
  *
+ *  - 22-Oct-1997: v1.1 Added basic console support, P4 support (not working)
+ *                      This was never released to the public
+ *  - 19-Dec-1997: v1.2 Public release
+ *			working console support
+ *                      working P4 support
+ *			hardware-accelerated RectFill/BitBLT on consoles
+ *			(only in 8 bits right now)
+ *			correct standard VGA colour table
+ *			1 bit support working again
+ *			uses the FB_ACTIVATE_* flags correctly now
+ *			correct behaviour when used with fbset
+ *
+ *  - 12-Jan-1998: v1.3 Public release
+ *			correct CLUT handling for Picasso IV (was BGR, not RGB)
+ *			removed left-over printk for Picasso II
+ *			now accepts monitorcap: and mode: on command line
+ *			correct "scrolling" when height or width = 0
+ * 			(though that's been done in console/fbcon.c)
+ * - 29-Jan-1998: v1.3b Added support for P4 in Zorro II (A2000)
+ *
  * 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.
@@ -19,6 +41,14 @@
 /* Please ignore the following lines of german/english notices. :-) */
 
 /*
+	alle moeglichen Checks fuer die anderen Karten aktivieren
+	Beschleunigung  fuer 1 Bit
+	hi/true color modes wieder aktivieren (zumindest 24/32 bpp)
+	
+	- need to make a copy of the screenmode database for each new board
+	- get rid of the ugly DELAY stuff (use jiffies instead)
+	"weiches" Blanken?
+
 	### Noch zu ueberpruefen: Aenderungen vom 4. Okt:
 		VSSM2 nicht mehr in der +$fff-Translation bei RGen/WGen
 		WClut/RClut: Auch +$fff beruecksichtigen
@@ -29,33 +59,6 @@
 	Bugfix fuer 320er-Modus: letzte Spalte..
 */
 
-/*
-	Next steps:
-x	- export vfmin etc. from amifb, check for bounds
-(x)	- checks for bounds of Max. MClk/VClk
-x	- new ioctl()s: FBIOGET_MONITORSPEC and FBIOPUT_MONITORSPEC (root only)
-x	- new ioctl() for internal purposes: FBIOSWITCH_MONIBIT
-(x)	- corresponding extensions to fbset
-x	- handling of interlaced/doublescan screens
-x	- color registers handling
-x	- color modes (need to extend autoscroll function!)
-x	- hsync/vsync polarity
-	- Handling of ACTIVATE_NOW (see amifb.c)
-    - also: check if values are ok - if not: return val (!= 0)
-	(- simple blitter support (FBIOBITBLT) )
-x	- support for other boards (PicassoII, Piccolo, Spectrum)
-x	- support for multiple boards
-	- need to make a copy of the screenmode database for each new board
-	- console mode(s?)
-	- module support: board unregistering?
-x	- memory testing: 1/2/4 MB boards
-x	- documentation
-x	- tests: on 040/060, in Z2/Z3 mode
-x	- finish clgen_fb_get_var() (also clgen_fb_get_fix()?)
-x	- output version number+date at driver startup
-x	- activate monitor setting checks
-*/
-
 /*** INCLUDES ***/
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -66,6 +69,7 @@
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/tty.h>
+#include <linux/malloc.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/console.h>
@@ -77,13 +81,13 @@
 #include "clgen.h"
 
 /*** DEFINES ***/
-#define CLGEN_VERSION "1.0 (16-Mar-97)"
-/* #define DEBUG if(1)  */
+#define CLGEN_VERSION "1.3b (29-Jan-98)"
+/* #define DEBUG if(1) */
 #define DEBUG if(0)
 
 /* this is not nice, but I just need a delay of a few cycles */
 #define DELAY { int del; for (del = 0; del < 100; del++) ; }
-
+#define DELAY2(n) {int k; for(k = 0; k < n; k++) {long x; x = 1234567/1234;}}
 #define arraysize(x)    (sizeof(x)/sizeof(*(x)))
 
 /* copied from drivers/char/fbmem.c :-\ */
@@ -98,6 +102,7 @@
 #define BT_PICCOLO  2
 #define BT_PICASSO  3
 #define BT_SPECTRUM 4
+#define BT_PICASSO4 5
 
 #define MAX_NUM_BOARDS 7
 
@@ -117,13 +122,15 @@
 	/* mapped in (it's in Zorro-II space) */
 	unsigned long PhysAddr;   /* physical start address of board (DRAM) */
 	unsigned char *VirtAddr;  /* virtual address of board after kernel_map */
+	unsigned char *VirtRAMAddr; /* virtual start address of DRAM area */
 	unsigned long size;       /* length of board address space in bytes */
 	int smallboard;           /* board has small/large mem, shortcut */
+	int p4flag;		  /* auxiliary flag for P4 in Z2 mode */
 	unsigned char SFR;        /* shadow of "special function register" */
 	/* This maybe not really belongs here, but for now... */
-	int xres, yres;
+/* ###	int xres, yres; */
 	int xoffset, yoffset;
-	int vxres, vyres;
+/* ###	int vxres, vyres; */
 	int line_length;
 	int visual;
 	int bpp;
@@ -153,7 +160,7 @@
 	{ 
 		640, 480, 640, 480, 0, 0, 8, 0, 
 		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 
-		0, 0, -1, -1, FB_ACCEL_NONE, 40000, 32, 32, 33, 10, 96, 2,
+		0, 0, -1, -1, FB_ACCEL_CLGEN, 40000, 32, 32, 33, 10, 96, 2,
 		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
 	},
 
@@ -165,7 +172,7 @@
 	{ 
 		800, 600, 800, 600, 0, 0, 8, 0, 
 		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 
-		0, 0, -1, -1, FB_ACCEL_NONE, 20000, 64, 56, 23, 37, 120, 6,
+		0, 0, -1, -1, FB_ACCEL_CLGEN, 20000, 64, 56, 23, 37, 120, 6,
 		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
 	},
 
@@ -173,13 +180,13 @@
 	/* 
 		Modeline from XF86Config:
 		Mode "1024x768"
-			DotClock 80
-			HTimings 1024 1136 1340 1432 VTimings 768 770 774 805
+		DotClock 80
+		HTimings 1024 1136 1340 1432 VTimings 768 770 774 805
 	*/
 	{ 
 		1024, 768, 1024, 768, 0, 0, 8, 0, 
 		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 
-		0, 0, -1, -1, FB_ACCEL_NONE, 12500, 92, 112, 31, 2, 204, 4,
+		0, 0, -1, -1, FB_ACCEL_CLGEN, 12500, 92, 112, 31, 2, 204, 4,
 		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
 	},
 
@@ -188,9 +195,9 @@
 		self-invented mode, uses DoubleScan and autoscroll
 	*/
 	{
-		320, 200, 1024, 768, 0, 0, 8, 0, 
+		320, 200, 320, 200, 0, 0, 8, 0, 
 		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 
-		0, 0, -1, -1, FB_ACCEL_NONE, 39726, 40, 16, 16, 7, 24, 1,
+		0, 0, -1, -1, FB_ACCEL_CLGEN, 39726, 40, 16, 16, 7, 24, 1,
 		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 
 		FB_VMODE_DOUBLE | FB_VMODE_CLOCK_HALVE
 	},
@@ -202,7 +209,7 @@
 	{
 		1024, 768, 1024, 768, 0, 0, 8, 0, 
 		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, 22268, 92, 112, 32, 9, 204, 8, 
+		0, 0, -1, -1, FB_ACCEL_CLGEN, 22268, 92, 112, 32, 9, 204, 8, 
 		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 
 		FB_VMODE_INTERLACED
 	},
@@ -214,7 +221,7 @@
 	{
 		1024, 768, 1024, 768, 0, 0, 8, 0, 
 		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, 15102, 92, 112, 32, 9, 204, 8, 
+		0, 0, -1, -1, FB_ACCEL_CLGEN, 15102, 92, 112, 32, 9, 204, 8, 
 		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 
 		FB_VMODE_INTERLACED
 	},
@@ -229,7 +236,7 @@
 	{
 		1280, 1024, 1280, 1024, 0, 0, 8, 0, 
 		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, 12500, 56, 16, 128, 1, 216, 12,
+		0, 0, -1, -1, FB_ACCEL_CLGEN, 12500, 56, 16, 128, 1, 216, 12,
 		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 
 		FB_VMODE_INTERLACED
 	},
@@ -250,10 +257,50 @@
 
 #define NUM_TOTAL_MODES		arraysize(clgen_fb_predefined)
 
+   /*
+    *    Default Colormaps
+    */
+
+/* the default colour table, for VGA+ colour systems */
+static u_short red16[] = 
+      {	0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa,
+	0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff};
+static u_short green16[] = 
+      {	0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0xaaaa, 0xaaaa,
+	0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff};
+static u_short blue16[] = 
+      {	0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa,
+	0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff};
+
+static u_short red2[]=
+        { 0x0000,0xaaaa};
+static u_short green2[]=
+        { 0x0000,0xaaaa};
+static u_short blue2[]=
+        { 0x0000,0xaaaa};
+
+static struct fb_cmap default_16_colors =
+	{ 0, 16, red16, green16, blue16, NULL };
+static struct fb_cmap default_2_colors = 
+	{ 0, 2, red2, green2, blue2, NULL };
+
+
 /*** GLOBAL VARIABLES ***/
 struct clgenstruct clboards[MAX_NUM_BOARDS];
+static int currcon = 0;
 static int num_inited = 0; /* number of boards currently init'ed */
 static int g_slotnum = -1;
+static int g_startmode = 1;  /* initial video mode */
+static struct display disp[MAX_NR_CONSOLES];
+static struct fb_info fb_info;
+
+static struct fb_hwswitch {
+   /* Display Control */
+   int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue,
+                    u_int *transp);
+   int (*setcolreg)(u_int regno, u_int red, u_int green, u_int blue,
+                    u_int transp);
+} *fbhw;
 
 /*** EXTERNAL STUFF ***/
 extern unsigned long kernel_map(unsigned long paddr, unsigned long size,
@@ -261,38 +308,74 @@
 
 
 /*** PROTOTYPES ***/
-void 				init_vgachip( int fbidx );
-void				WGen( int regnum, unsigned char val );
+void 			init_vgachip( int fbidx );
+void			WGen( int regnum, unsigned char val );
 unsigned char 		RGen( int regnum );
-void 				WSeq( unsigned char regnum, unsigned char val );
+void 			WSeq( unsigned char regnum, unsigned char val );
 unsigned char 		RSeq( unsigned char regnum );
-void 				WCrt( unsigned char regnum, unsigned char val );
+void 			WCrt( unsigned char regnum, unsigned char val );
 unsigned char		RCrt( unsigned char regnum );
-void				WGfx( unsigned char regnum, unsigned char val );
+void			WGfx( unsigned char regnum, unsigned char val );
 unsigned char		RGfx( unsigned char regnum );
-void				WAttr( unsigned char regnum, unsigned char val );
-void				AttrOn( void );
+void			WAttr( unsigned char regnum, unsigned char val );
+void			AttrOn( void );
 unsigned char		RAttr( unsigned char regnum );
-void				WHDR( unsigned char val );
+void			WHDR( unsigned char val );
 unsigned char		RHDR( void );
-void				WSFR( unsigned char val );
-void				WSFR2( unsigned char val );
-void				WClut( unsigned char regnum, unsigned char red, unsigned char green, unsigned char blue );
-void				RClut( unsigned char regnum, unsigned char *red, unsigned char *green, unsigned char *blue );
-void				SelectMap( unsigned char mapnum );
+void			WSFR( unsigned char val );
+void			WSFR2( unsigned char val );
+void			WClut( unsigned char regnum, unsigned char red, unsigned char green, unsigned char blue );
+void			RClut( unsigned char regnum, unsigned char *red, unsigned char *green, unsigned char *blue );
+void			SelectMap( unsigned char mapnum );
 void	bestclock( long freq, long *best, long *nom, long *den, long *div, long maxfreq );
 static int clgen_fb_get_fix(struct fb_fix_screeninfo *fix, int con, int fbidx);
 static int clgen_fb_get_var(struct fb_var_screeninfo *var, int con, int fbidx);
 static int clgen_fb_set_var(struct fb_var_screeninfo *var, int con, int fbidx);
+static void clgen_set_var( struct fb_var_screeninfo *var, int clearflag );
+
+static struct fb_cmap *get_default_colormap( int len );
+static int do_fb_get_cmap( struct fb_cmap *cmap, struct fb_var_screeninfo *var,
+                          int kspc );
+static int do_fb_set_cmap( struct fb_cmap *cmap, struct fb_var_screeninfo *var,
+                          int kspc );
+static void do_install_cmap( int con );
+static void memcpy_fs( int fsfromto, void *to, void *from, int len );
+static void copy_cmap( struct fb_cmap *from, struct fb_cmap *to, int fsfromto );
+static int alloc_cmap( struct fb_cmap *cmap, int len, int transp );
+static int clgen_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                         u_int transp);
+static int clgen_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+                         u_int *transp);
+
+static void clgen_fb_set_disp( int con, int fbidx );
+
 static int clgen_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, int fbidx);
 static int clgen_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, int fbidx);
+
+void clgen_WaitBLT( void );
+void clgen_BitBLT (u_short curx, u_short cury, u_short destx, u_short desty,
+		u_short width, u_short height, u_short line_length);
+void clgen_RectFill (u_short x, u_short y, u_short width, u_short height,
+                     u_char color, u_short line_length);
+
 static int clgen_fb_ioctl(struct inode *inode, struct file *file,
     unsigned int cmd, unsigned long arg, int con, int fbidx);
 static int clgen_fb_pan_display(struct fb_var_screeninfo *var, int val, int fbidx);
 static int clgen_get_monitorspec(struct fb_monitorspec *spec, int val, int fbidx);
 static int clgen_put_monitorspec(struct fb_monitorspec *spec, int val, int fbidx);
 int					find_clboard( int fbidx );
-void				clgen_fb_init( long *mem_start );
+struct fb_info 				*clgen_fb_init( long *mem_start );
+static int clgen_switch( int );
+static int clgen_updatevar( int );
+static void clgen_blank( int );
+
+int clgen_probe( void );
+void clgen_video_setup( char *options, int *ints );
+static char *strtoke( char *s, const char *ct );
+
+static struct fb_hwswitch clgen_hwswitch = {
+   clgen_getcolreg, clgen_setcolreg
+};
 
 /********************************************/
 /* init_vgachip() - initialize the VGA chip */
@@ -344,12 +427,25 @@
 			DELAY
 			break;
 
+		case BT_PICASSO4:
+			WCrt(CRT51, 0x00); /* disable flickerfixer */
+			DELAY2(2000000)
+			WGfx(GR2F, 0x00); /* from Klaus' NetBSD driver: */
+			WGfx(GR33, 0x00); /* put blitter into 542x compat */
+			WGfx(GR31, 0x00); /* mode */
+			break;
+
 		default:
 			printk(KERN_ERR "clgen: Warning: Unknown board type\n");
 			break;
 	}
 
-    WGen(VSSM, 0x10);  /* EGS: 0x16 */
+    /* the P4 is not fully initialized here; I rely on it having been inited under      */
+    /* AmigaOS already, which seems to work just fine (Klaus advised to do it this way) */
+
+    if (clboards[slotnum].boardtype != BT_PICASSO4)
+    {
+	WGen(VSSM, 0x10);  /* EGS: 0x16 */
 	WGen(POS102, 0x01);
 	WGen(VSSM, 0x08);  /* EGS: 0x0e */
 
@@ -359,7 +455,7 @@
 	WSeq(SR0, 0x03);  /* reset sequencer logic */
 
 	WSeq(SR1, 0x21);  /* FullBandwidth (video off) and 8/9 dot clock */
-    WGen(MISC_W, 0xc1);  /* polarity (-/-), disable access to display memory, CRTC base address: color */
+	WGen(MISC_W, 0xc1);  /* polarity (-/-), disable access to display memory, CRTC base address: color */
 
 /*	WGfx(GRA, 0xce);    "magic cookie" - doesn't make any sense to me.. */
 	WSeq(SR6, 0x12);   /* unlock all extension registers */
@@ -391,6 +487,7 @@
 			printk(KERN_ERR "clgen: unknown boardtype\n");
 			break;
 	}
+    }
 
 	WSeq(SR2, 0xff);  /* plane mask: nothing */
 	WSeq(SR3, 0x00);  /* character map select: doesn't even matter in gx mode */
@@ -415,6 +512,10 @@
 			WSeq(SR7, 0x80);
 			break;
 
+		case BT_PICASSO4:
+			WSeq(SR7, 0x20);
+			break;
+
 		default:
 			printk(KERN_ERR "clgen: unknown board type\n");
 			break;
@@ -427,8 +528,12 @@
 	WSeq(SR12, 0x00); /* graphics cursor attributes */
 	WSeq(SR13, 0x00); /* graphics cursor pattern address */
 
-	WSeq(SR17, 0x00); /* configuration readback and ext. color: .. */
-	WSeq(SR18, 0x02); /* signature generator */
+	/* writing these on a P4 might give problems..  */
+	if (clboards[slotnum].boardtype != BT_PICASSO4)
+	{
+		WSeq(SR17, 0x00); /* configuration readback and ext. color */
+		WSeq(SR18, 0x02); /* signature generator */
+	}
 
 	/* MCLK select etc. */
 	switch(clboards[slotnum].boardtype)
@@ -449,6 +554,10 @@
 			WSeq(SR1F, 0x22);
 			break;
 
+		case BT_PICASSO4:
+/*			WSeq(SR1F, 0x1c); */
+			break;
+
 		default:
 			printk(KERN_ERR "clgen: unknown board type!\n");
 			break;
@@ -463,7 +572,7 @@
 	WCrt(CRTF, 0x00);  /* text cursor location low: 0 */
 
 	WCrt(CRT14, 0x00); /* Underline Row scanline: - */
-    WCrt(CRT17, 0xc3); /* mode control: timing enable, byte mode, no compat modes */
+	WCrt(CRT17, 0xc3); /* mode control: timing enable, byte mode, no compat modes */
 	WCrt(CRT18, 0x00); /* Line Compare: not needed */
 	/* ### add 0x40 for text modes with > 30 MHz pixclock */
 	WCrt(CRT1B, 0x02); /* ext. display controls: ext.adr. wrap */
@@ -505,8 +614,8 @@
 	WAttr(AR10, 0x01); /* Attribute Controller mode: graphics mode */
 	WAttr(AR11, 0x00); /* Overscan color reg.: reg. 0 */
 	WAttr(AR12, 0x0f); /* Color Plane enable: Enable all 4 planes */
-	WAttr(AR33, 0x00); /* Pixel Panning: - */
-    WAttr(AR14, 0x00); /* Color Select: - */
+/* ### 	WAttr(AR33, 0x00); * Pixel Panning: - */
+	WAttr(AR14, 0x00); /* Color Select: - */
 
 	WGen(M_3C6, 0xff); /* Pixel mask: no mask */
 
@@ -550,56 +659,71 @@
 	/* misc... */
 	WHDR(0); /* Hidden DAC register: - */
 
-	/* "pre-set" a RAMsize; if the test succeeds, double it */
-	if (clboards[slotnum].boardtype == BT_SD64)
-		clboards[slotnum].size = 0x400000;
-	else
-		clboards[slotnum].size = 0x200000;
+	/* if p4flag is set, board RAM size has already been determined, so skip test */
+	if (!clboards[slotnum].p4flag)
+	{
+		/* "pre-set" a RAMsize; if the test succeeds, double it */
+		if (clboards[slotnum].boardtype == BT_SD64 ||
+			clboards[slotnum].boardtype == BT_PICASSO4)
+			clboards[slotnum].size = 0x400000;
+		else
+			clboards[slotnum].size = 0x200000;
 
-	/* assume it's a "large memory" board (2/4 MB) */
-	clboards[slotnum].smallboard = FALSE;
+		/* assume it's a "large memory" board (2/4 MB) */
+		clboards[slotnum].smallboard = FALSE;
 
-	/* check for 1/2 MB Piccolo/Picasso/Spectrum resp. 2/4 MB SD64 */
-	/* DRAM register has already been pre-set for "large", so it is*/
-	/* only modified if we find that this is a "small" version */
-	{
-		unsigned volatile char *ram = clboards[slotnum].VirtAddr;
-		int i, flag = 0;
+		/* check for 1/2 MB Piccolo/Picasso/Spectrum resp. 2/4 MB SD64 */
+		/* DRAM register has already been pre-set for "large", so it is*/
+		/* only modified if we find that this is a "small" version */
+		{
+			unsigned volatile char *ram = clboards[slotnum].VirtRAMAddr;
+			int i, flag = 0;
 
-		ram += (clboards[slotnum].size >> 1);
+			ram += (clboards[slotnum].size >> 1);
 
-		for (i = 0; i < 256; i++)
-			*(ram+i) = (unsigned char)i;
+			for (i = 0; i < 256; i++)
+				*(ram+i) = (unsigned char)i;
 
-		for (i = 0; i < 256; i++)
-		{
-			if (*(ram + i) != i)
-				flag = 1;
-		}
+			for (i = 0; i < 256; i++)
+			{
+				if (*(ram + i) != i)
+					flag = 1;
+			}
 
-		/* if the DRAM test failed, halve RAM value */
-		if (flag)
-		{
-			clboards[slotnum].size /= 2;
-			clboards[slotnum].smallboard = TRUE;
-			switch(clboards[slotnum].boardtype)
+			/* if the DRAM test failed, halve RAM value */
+			if (flag)
 			{
-				case BT_SD64:
-					WSeq(SRF, 0x38);  /* 2 MB Ram SD64 */
-					break;
+				clboards[slotnum].size /= 2;
+				clboards[slotnum].smallboard = TRUE;
+				switch(clboards[slotnum].boardtype)
+				{
+					case BT_SD64:
+						WSeq(SRF, 0x38);  /* 2 MB Ram SD64 */
+						break;
 
-				case BT_PICCOLO:
-				case BT_PICASSO:
-				case BT_SPECTRUM:
-					WSeq(SRF, 0x30); /* 1 MB DRAM */
-					break;
-				default:
-					printk(KERN_WARNING "clgen: Uuhh..?\n");
+					case BT_PICCOLO:
+					case BT_PICASSO:
+					case BT_SPECTRUM:
+						WSeq(SRF, 0x30); /* 1 MB DRAM */
+						break;
+
+					case BT_PICASSO4:
+						WSeq(SRF, 0x38);   /* ### like SD64? */
+						break;
+					default:
+						printk(KERN_WARNING "clgen: Uuhh..?\n");
+				}
 			}
 		}
-
-		printk(KERN_INFO "clgen: This board has %ld bytes of DRAM memory\n", clboards[slotnum].size);
 	}
+	else
+	{
+		/* In case of P4 in Z2 mode, set reg here */
+		if (clboards[slotnum].smallboard)
+			WSeq(SRF, 0x38);
+	}
+
+	printk(KERN_INFO "clgen: This board has %ld bytes of DRAM memory\n", clboards[slotnum].size);
 }
 
 
@@ -613,7 +737,7 @@
 /*** WGen() - write into one of the external/general registers ***/
 void WGen(int regnum, unsigned char val)
 {
-    unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + regnum;
+	unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + regnum;
 
 	if(clboards[g_slotnum].boardtype == BT_PICASSO)
 	{
@@ -629,7 +753,7 @@
 /*** RGen() - read out one of the external/general registers ***/
 unsigned char RGen(int regnum)
 {
-    unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + regnum;
+	unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + regnum;
 
 	if(clboards[g_slotnum].boardtype == BT_PICASSO)
 	{
@@ -645,7 +769,7 @@
 /*** WSeq() - write into a register of the sequencer ***/
 void WSeq(unsigned char regnum, unsigned char val)
 {
-    unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + SRX;
+	unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + SRX;
 
 	*reg     = regnum;
 	*(reg+1) = val;
@@ -654,7 +778,7 @@
 /*** RSeq() - read out one of the Sequencer registers ***/
 unsigned char RSeq(unsigned char regnum)
 {
-    unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + SRX;
+	unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + SRX;
 
 	*reg = regnum;
 	return *(reg+1);
@@ -663,7 +787,7 @@
 /*** WCrt() - write into a register of the CRT controller ***/
 void WCrt(unsigned char regnum, unsigned char val)
 {
-    unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + CRTX;
+	unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + CRTX;
 
 	*reg = regnum;
 	*(reg+1) = val;
@@ -672,7 +796,7 @@
 /*** RCrt() - read out one of the CRT controller registers ***/
 unsigned char RCrt(unsigned char regnum)
 {
-    unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + CRTX;
+	unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + CRTX;
 
 	*reg = regnum;
 	return *(reg+1);
@@ -681,7 +805,7 @@
 /*** WGfx() - write into a register of the Gfx controller ***/
 void WGfx(unsigned char regnum, unsigned char val)
 {
-    unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + GRX;
+	unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + GRX;
 
 	*reg = regnum;
 	*(reg+1) = val;
@@ -690,7 +814,7 @@
 /*** RGfx() - read out one of the Gfx controller registers ***/
 unsigned char RGfx(unsigned char regnum)
 {
-    unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + GRX;
+	unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + GRX;
 
 	*reg = regnum;
 	return *(reg+1);
@@ -699,7 +823,7 @@
 /*** WAttr() - write into a register of the Attribute controller ***/
 void WAttr(unsigned char regnum, unsigned char val)
 {
-    unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + ARX;
+	unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + ARX;
 
 	/* if the next access to the attribute controller is a data write access, */
 	/* simply write back the information that was already there before, so that */
@@ -726,11 +850,12 @@
 /*** AttrOn() - turn on VideoEnable for Attribute controller ***/
 void AttrOn()
 {
-    unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + ARX;
+	unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + ARX;
 
 	if (RCrt(CRT24) & 0x80)
 	{
-		/* if we're just in "write value" mode, write back the same value as before to not modify anything */
+		/* if we're just in "write value" mode, write back the */
+		/* same value as before to not modify anything */
 		unsigned volatile char *reg2 = clboards[g_slotnum].VirtRegBase + ARX;
 		*reg2 = *(reg2+1);
 	}
@@ -746,7 +871,7 @@
 /*** RAttr() - read out a register of the Attribute controller ***/
 unsigned char RAttr(unsigned char regnum)
 {
-    unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + ARX;
+	unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + ARX;
 
 	/* (explanation see above in WAttr() ) */
 
@@ -769,7 +894,7 @@
  */
 void WHDR(unsigned char val)
 {
-    unsigned char dummy;
+	unsigned char dummy;
 
 	if(clboards[g_slotnum].boardtype == BT_PICASSO)
 	{
@@ -814,7 +939,7 @@
 /* (Is there any board for the Amiga that uses the 5428 ?) */
 unsigned char RHDR()
 {
-    unsigned char dummy;
+	unsigned char dummy;
 
 	dummy = RGen(M_3C6);
 	dummy = RGen(M_3C6);
@@ -829,7 +954,7 @@
 
 void WSFR(unsigned char val)
 {
-    unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + 0x8000;
+	unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + 0x8000;
 	*reg = val;
 }
 
@@ -839,7 +964,7 @@
 	/* writing an arbitrary value to this one causes the monitor switcher */
 	/* to flip to Amiga display */
 
-    unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + 0x9000;
+	unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + 0x9000;
 	*reg = val;
 }
 
@@ -848,12 +973,14 @@
 {
 	unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + 0x3c8;
 
-	if(clboards[g_slotnum].boardtype == BT_PICASSO)
+	if(clboards[g_slotnum].boardtype == BT_PICASSO ||
+		clboards[g_slotnum].boardtype == BT_PICASSO4)
 	{
 		/* address write mode register is not translated.. */
 		*reg = regnum;
-		/* but DAC data register IS. */
-		reg += 0xfff;
+		/* but DAC data register IS, at least for Picasso II */
+		if(clboards[g_slotnum].boardtype == BT_PICASSO)
+			reg += 0xfff;
 		*(reg+1) = (red   >> 2);
 		*(reg+1) = (green >> 2);
 		*(reg+1) = (blue  >> 2);
@@ -872,10 +999,12 @@
 {
 	unsigned volatile char *reg = clboards[g_slotnum].VirtRegBase + 0x3c7;
 
-	if(clboards[g_slotnum].boardtype == BT_PICASSO)
+	if(clboards[g_slotnum].boardtype == BT_PICASSO ||
+		clboards[g_slotnum].boardtype == BT_PICASSO4)
 	{
-		reg += 0xfff;
 		*reg = regnum;
+		if(clboards[g_slotnum].boardtype == BT_PICASSO)
+			reg += 0xfff;
 		*red   = *(reg+2) << 2;
 		*green = *(reg+2) << 2;
 		*blue  = *(reg+2) << 2;
@@ -892,7 +1021,7 @@
 /*** SelectMap() - choose one of the 4 memory planes for reading (and its mask for writing) ***/
 void SelectMap(unsigned char mapnum)
 {
-    unsigned char mask = 1 << mapnum;
+	unsigned char mask = 1 << mapnum;
 
 	WGfx(GR4, mapnum);
 	WSeq(SR2, mask);
@@ -983,17 +1112,22 @@
 
 static int clgen_fb_get_fix(struct fb_fix_screeninfo *fix, int con, int fbidx)
 {
-	int slotnum;
+	int i, slotnum;
+
+	if (con == -1)
+	{
+		printk(KERN_WARNING "CLGEN: What? con == -1? (1)\n");
+		/* ### Fix this..? */
+		con = 0;
+	}
 
 	slotnum = find_clboard(fbidx);
 	if (slotnum == -1)
 	{
-		printk(KERN_WARNING "CLGEN: Warning: Board not found in get_fix)!!\n");
+		printk(KERN_WARNING "CLGEN: Warning: Board not found in get_fix!!\n");
 		return 0;
 	}
 
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-
 	/* ID: maximum of 16 characters */
 	strcpy(fix->id, "CLGen:");
 	switch(clboards[slotnum].boardtype)
@@ -1010,11 +1144,14 @@
 		case BT_PICASSO:
 			strcat(fix->id, "Picasso");
 			break;
+		case BT_PICASSO4:
+			strcat(fix->id, "Picasso IV");
+			break;
 	}
 
-	fix->smem_start = clboards[slotnum].VirtAddr;
+	fix->smem_start = clboards[slotnum].VirtRAMAddr;
 
-	if (clboards[slotnum].bpp == 1)
+	if (disp[con].var.bits_per_pixel == 1)
 	{
 		/* monochrome: only 1 memory plane */
 		fix->smem_len = clboards[slotnum].size / 4;
@@ -1025,22 +1162,19 @@
 		fix->smem_len = clboards[slotnum].size;
 	}
 
-	fix->type = clboards[slotnum].type;
+	fix->type = disp[con].type;
 	fix->type_aux = 0;
-	fix->visual = clboards[slotnum].visual;
+	fix->visual = disp[con].visual;
 
 	fix->xpanstep = 1;
 	fix->ypanstep = 1;
 	fix->ywrapstep = 0;
 	/* Is this ever used (in the X server?) ? */
-	/* geert's answer: yes */
-	fix->line_length = clboards[slotnum].line_length;
+	fix->line_length = disp[con].line_length;
+	fix->accel = FB_ACCEL_CLGEN;
 
-#if 0
-	/* geert: someone with more knowledge should fix this */
-	fix->mmio_start = xxx;
-	fix->mmio_len = xxx;
-#endif
+	for (i = 0; i < arraysize(fix->reserved); i++)
+		fix->reserved[i] = 0;
 
 	return(0);
 }
@@ -1055,6 +1189,13 @@
 {
 	int slotnum;
 
+	if (con == -1)
+	{
+		printk(KERN_WARNING "CLGEN: What? con == -1? (2)\n");
+		/* ### Fix this..? */
+		con = 0;
+	}
+
 	slotnum = find_clboard(fbidx);
 	if (slotnum == -1)
 	{
@@ -1065,10 +1206,28 @@
 	g_slotnum = slotnum;
 
 	/* this is really all there is to it. */
-	memcpy(var, &clboards[slotnum].currentinfo, sizeof(struct fb_var_screeninfo));
+	*var = disp[con].var;
+
 	return(0);
 }
 
+static void clgen_fb_set_disp(int con, int fbidx)
+{
+	struct fb_fix_screeninfo fix;
+
+	clgen_fb_get_fix(&fix, con, fbidx);
+	if (con == -1)
+		con = 0;
+	disp[con].screen_base = (u_char *)fix.smem_start;
+	disp[con].type_aux = fix.type_aux;
+	disp[con].ypanstep = fix.ypanstep;
+	disp[con].ywrapstep = fix.ywrapstep;
+	disp[con].can_soft_blank = 1;
+	/* ### add inverse support later? */
+	disp[con].inverse = 0;
+
+}
+
 /*************************************************************************
 	clgen_fb_set_var()
 
@@ -1078,14 +1237,17 @@
 static int clgen_fb_set_var(struct fb_var_screeninfo *var, int con, int fbidx)
 {
 	int xres, hfront, hsync, hback, yres, vfront, vsync, vback;
-	int offset = 0;
 	long freq, best, nom, den, div;
-	long hfreq, vfreq, hf2, vf2;
-	CLGenData data;
-	unsigned char tmp;
+	long hfreq, vfreq, hf2, vf2; 
 	float freq_f;
-	int i, slotnum;
-	long amount;
+	int slotnum, err;
+	int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
+	int activate = var->activate;
+	static int firsttime = 1;
+
+	/* if it's not the current console we change, quit here. */
+	if (con != currcon)
+		return 1;
 
 	slotnum = find_clboard(fbidx);
 	if (slotnum == -1)
@@ -1104,8 +1266,9 @@
 
 	DEBUG printk("desired pixclock: %ld kHz\n", freq);	
 
-	/* the SD64 has a higher max. videoclock */
-	if (clboards[slotnum].boardtype == BT_SD64)
+	/* the SD64/P4 have a higher max. videoclock */
+	if (clboards[slotnum].boardtype == BT_SD64 ||
+		clboards[slotnum].boardtype == BT_PICASSO4)
 		bestclock(freq, &best, &nom, &den, &div, 140000);
 	else
 		bestclock(freq, &best, &nom, &den, &div, 90000);
@@ -1114,29 +1277,6 @@
 
 	DEBUG printk("Best possible values for given frequency: best: %ld kHz  nom: %ld  den: %ld  div: %ld\n", best, nom, den, div);
 
-#if 0
-	/* turn off board.. */
-	switch(clboards[slotnum].boardtype)
-	{
-		case BT_SD64:
-			clboards[slotnum].SFR &= 0xfe;
-			WSFR(clboards[slotnum].SFR);
-			break;
-
-		case BT_PICCOLO:
-			clboards[slotnum].SFR &= 0xf7;
-			WSFR(clboards[slotnum].SFR);
-			break;
-
-		case BT_PICASSO:
-		case BT_SPECTRUM:
-
-		default:
-			printk(KERN_WARNING "CLGEN: unknown board..?\n");
-			break;
-	}
-#endif
-
 	xres   = var->xres;
 	hfront = var->right_margin;
 	hsync  = var->hsync_len;
@@ -1196,22 +1336,176 @@
 	else
 		DEBUG printk(KERN_WARNING "(within monitor limits)\n");
 
-	if (var->bits_per_pixel != 1 && var->bits_per_pixel != 8)
+	if (var->bits_per_pixel != 1 && var->bits_per_pixel != 8) 
 	{
 		printk(KERN_WARNING "clgen: driver only supports 1 and 8 bits depth at the moment\n");
 		return -EINVAL;
 	}
 
-	/* At this point, I can be sure that the mode is "valid" for the */
-	/* currently connected monitor (within limits), so start         */
-	/* programming registers here. */
+    /* fill out the rest of the fb_var_screeninfo (this was the reason */
+    /* for this driver coming too late for Jes' christmas 2.0.33 rel)  */
+    var->activate = 0;
+    var->red.offset = 0;
+    var->red.length = 8;
+    var->red.msb_right = 0;
+
+    var->green.offset = 0;
+    var->green.length = 8;
+    var->green.msb_right = 0;
+
+    var->blue.offset = 0;
+    var->blue.length = 8;
+    var->blue.msb_right = 0;
+
+    /* right now, hardware acceleration is only enabled for 8bpp */
+    if (var->bits_per_pixel == 8)
+	var->accel = FB_ACCEL_CLGEN;
+
+    if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW )
+    {
+	/* now fill up the disp[] structure according to clboards[..] */
+	/* There are many duplicate entries in those two, but for now */
+	/* I'll carry around both of them. */
+	oldxres = disp[con].var.xres;
+	oldyres = disp[con].var.yres;
+	oldvxres = disp[con].var.xres_virtual;
+	oldvyres = disp[con].var.yres_virtual;
+	oldbpp = disp[con].var.bits_per_pixel;
+	disp[con].var = *var;
+
+	if (oldxres != var->xres || oldyres != var->yres ||
+	  oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
+	  oldbpp != var->bits_per_pixel || firsttime)
+	{
+		if (var->bits_per_pixel == 1)
+		{
+			clboards[slotnum].line_length = var->xres_virtual / 8;
+			clboards[slotnum].bpp = 1;
+			clboards[slotnum].visual = FB_VISUAL_MONO10;
+			clboards[slotnum].type = FB_TYPE_PACKED_PIXELS;
+			disp[con].var.xoffset = 0;
+			disp[con].var.yoffset = 0;
+			disp[con].line_length = clboards[slotnum].line_length;
+			disp[con].var.bits_per_pixel = clboards[slotnum].bpp;
+			disp[con].visual =  clboards[slotnum].visual;
+			disp[con].type =  clboards[slotnum].type;
+		}
+		else if (var->bits_per_pixel == 8)
+		{
+			clboards[slotnum].line_length = var->xres_virtual;
+			clboards[slotnum].bpp = 8;
+			clboards[slotnum].visual = FB_VISUAL_PSEUDOCOLOR;
+			clboards[slotnum].type = FB_TYPE_PACKED_PIXELS;
+			disp[con].var.xoffset = 0; /* ## should be set synchronous to clboards[..] */
+			disp[con].var.yoffset = 0;
+			disp[con].line_length = clboards[slotnum].line_length;
+			disp[con].var.bits_per_pixel = clboards[slotnum].bpp;
+			disp[con].visual =  clboards[slotnum].visual;
+			disp[con].type =  clboards[slotnum].type;
+		}
+
+		clgen_fb_set_disp(con, fbidx);
+		if (!firsttime && fb_info.changevar)
+		{
+			(*fb_info.changevar)(con);
+		}
+
+	}
+	else
+	{
+		/* set mode in hardware; with NOCLEAR! */
+		if (con == currcon)
+			clgen_set_var(&disp[con].var, 0);
+	}
+
+	if (oldbpp != var->bits_per_pixel)
+	{
+ 		if ((err = alloc_cmap(&disp[con].cmap, 0, 0)))
+			return err;
+		do_install_cmap(con);
+	}
+
+	/* ### still necessary? */
+	firsttime = 0;
+    }
+
+    DEBUG printk(KERN_INFO "clgen_fb_set_var: exit\n");
+
+    return(0);
+}
+
+
+/*************************************************************************
+	clgen_set_var()
+
+	actually writes the values for a new video mode into the hardware,
+	uses the information supplied through a fb_var_screeninfo structure.
+
+	It should be safe to call this function repeatedly (what happens
+	when you do e.g. "fbset -depth 1")
+**************************************************************************/
+
+static void clgen_set_var(struct fb_var_screeninfo *var, int clearflag )
+{
+	unsigned char tmp;
+	int slotnum = g_slotnum;
+	int xres, hfront, hsync, hback, yres, vfront, vsync, vback;
+	long freq, best, nom, den, div;
+	float freq_f;
+	int offset = 0;
+	CLGenData data;
 
 	/* switching to a (new) mode always means resetting panning values */
 	clboards[slotnum].xoffset = 0;
 	clboards[slotnum].yoffset = 0;
 
+	/* convert from ps to kHz */
+	freq_f = (1.0/(float)var->pixclock) * 1000000000;
+	freq = (long)freq_f;
+
+	DEBUG printk("desired pixclock: %ld kHz\n", freq);	
+
+	/* the SD64/P4 have a higher max. videoclock */
+	if (clboards[slotnum].boardtype == BT_SD64 ||
+		clboards[slotnum].boardtype == BT_PICASSO4)
+		bestclock(freq, &best, &nom, &den, &div, 140000);
+	else
+		bestclock(freq, &best, &nom, &den, &div, 90000);
+
+	freq = best;
+
+	DEBUG printk("Best possible values for given frequency: best: %ld kHz  nom: %ld  den: %ld  div: %ld\n", best, nom, den, div);
+
+	xres   = var->xres;
+	hfront = var->right_margin;
+	hsync  = var->hsync_len;
+	hback  = var->left_margin;
+
+	if (var->vmode & FB_VMODE_DOUBLE)
+	{
+		yres = var->yres * 2;
+		vfront = var->lower_margin * 2;
+		vsync  = var->vsync_len * 2;
+		vback  = var->upper_margin * 2;
+	}
+	else if (var->vmode & FB_VMODE_INTERLACED)
+	{
+		yres   = (var->yres + 1) / 2;
+		vfront = (var->lower_margin + 1) / 2;
+		vsync  = (var->vsync_len + 1) / 2;
+		vback  = (var->upper_margin + 1) / 2;
+	}
+	else
+	{
+		yres   = var->yres;
+		vfront = var->lower_margin;
+		vsync  = var->vsync_len;
+		vback  = var->upper_margin;
+	}
+
+
 	/* this is our "current" mode storage place */
-	memcpy(&clboards[slotnum].currentinfo, var, sizeof(struct fb_var_screeninfo));
+/*	memcpy(&clboards[slotnum].currentinfo, var, sizeof(struct fb_var_screeninfo)); */
 
 	data.HorizTotal      = (xres / 8) + (hfront / 8) + (hsync / 8) + (hback / 8) - 5;
 	data.HorizDispEnd    = (xres / 8) - 1;
@@ -1335,7 +1629,7 @@
 		tmp = (den << 1) | 0x01;
 
 	if (clboards[slotnum].boardtype == BT_SD64)
-		tmp |= 0x80; /* 6 bit denominator */
+		tmp |= 0x80; /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
 	WSeq(SR1B, tmp);
 
 	WCrt(CRT17, 0xc3); /* mode control: CRTC enable, ROTATE(?), 16bit address wrap, no compat. */
@@ -1367,9 +1661,11 @@
 	if (var->bits_per_pixel == 1)
 	{
 	DEBUG printk(KERN_INFO "clgen: preparing for 1 bit deep display\n");
+#if 0
 		/* restore first 2 color registers for mono mode */
 		WClut( 0, 0x00, 0x00, 0x00);  /* background: black */
 		WClut( 1, 0xff, 0xff, 0xff);  /* foreground: white */
+#endif
 		
 		WGfx(GR5,     0);      /* mode register */
 		/* Extended Sequencer Mode */
@@ -1405,6 +1701,13 @@
 				WSeq(SRF, 0xb0);    /* evtl d0? avoid FIFO underruns..? */
 				break;
 
+			case BT_PICASSO4:
+	DEBUG printk(KERN_INFO "(for Picasso IV)\n");
+				WSeq(SR7, 0x20);
+/*				WSeq(SR1F, 0x1c); */
+/* SRF not being set here...	WSeq(SRF, 0xd0); */
+				break;
+
 			default:
 				printk(KERN_WARNING "clgen: unknown Board\n");
 				break;
@@ -1448,6 +1751,12 @@
 				WSeq(SRF, 0xb0);    /* Fast Page-Mode writes */
 				break;
 
+			case BT_PICASSO4:
+				WSeq(SR7, 0x21);
+				WSeq(SRF, 0xb8); /* ### INCOMPLETE!! */
+/*				WSeq(SR1F, 0x1c); */
+				break;
+
 			default:
 				printk(KERN_WARNING "clgen: unknown Board\n");
 				break;
@@ -1492,6 +1801,11 @@
 				WSeq(SR1F, 0x22);     /* MCLK select */
 				break;
 
+			case BT_PICASSO4:
+				WSeq(SR7, 0x27);
+/*				WSeq(SR1F, 0x1c);  */
+				break;
+
 			default:
 				printk(KERN_WARNING "CLGEN: unknown Board\n");
 				break;
@@ -1536,6 +1850,11 @@
 				WSeq(SR1F, 0x22);     /* MCLK select */
 				break;
 
+			case BT_PICASSO4:
+				WSeq(SR7, 0x25);
+/*				WSeq(SR1F, 0x1c);  */
+				break;
+
 			default:
 				printk(KERN_WARNING "clgen: unknown Board\n");
 				break;
@@ -1560,14 +1879,15 @@
 	if (offset & 0x100)  /* offset overflow bit */
 		tmp |= 0x10;
 	WCrt(CRT1B,tmp);    /* screen start addr #16-18, fastpagemode cycles */
-	if (clboards[slotnum].boardtype == BT_SD64)
+	if (clboards[slotnum].boardtype == BT_SD64 ||
+		clboards[slotnum].boardtype == BT_PICASSO4)
 		WCrt(CRT1D, 0x00);   /* screen start address bit 19 */
 
 	WCrt(CRTE,    0);      /* text cursor location high */
 	WCrt(CRTF,    0);      /* text cursor location low */
 	WCrt(CRT14,   0);      /* underline row scanline = at very bottom */
 
-	WAttr(AR10,  1);       /* controller mode */
+	WAttr(AR10,  1);      /* controller mode */
 	WAttr(AR11,  0);      /* overscan (border) color */
 	WAttr(AR12, 15);      /* color plane enable */
 	WAttr(AR33,  0);      /* pixel panning */
@@ -1600,44 +1920,27 @@
 	switch(clboards[slotnum].boardtype)
 	{
 		case BT_SD64:
-#if 0
 			clboards[slotnum].SFR |= 0x21;
 			WSFR(clboards[slotnum].SFR);
-	DEBUG printk(KERN_INFO "clgen: doing memset (SD64) at $%p, 1 MB...", clboards[slotnum].VirtAddr);
-			memset(clboards[slotnum].VirtAddr, 0, 1048576);
-	DEBUG printk("clgen: done.\n");
-#endif
 			break;
 
 		case BT_PICCOLO:
-#if 0
 			clboards[slotnum].SFR |= 0x28;
 			WSFR(clboards[slotnum].SFR);
-	DEBUG printk(KERN_INFO "clgen: doing memset (Piccolo) at $%p, 1/2 MB...", clboards[slotnum].VirtAddr);
-			memset(clboards[slotnum].VirtAddr, 0, 524288);
-	DEBUG printk("clgen: done.\n");
-#endif
 			break;
 
 		case BT_PICASSO:
-#if 0
-			printk("Switching to Picasso display\n");
 			clboards[slotnum].SFR = 0xff;
 			WSFR(clboards[slotnum].SFR);
-	DEBUG printk(KERN_INFO "clgen: doing memset (Picasso) at $%p, 1/2 MB...", clboards[slotnum].VirtAddr);
-			memset(clboards[slotnum].VirtAddr, 0, 524288);
-	DEBUG printk("clgen: done.\n");
-#endif
 			break;
 
 		case BT_SPECTRUM:
-#if 0
 			clboards[slotnum].SFR = 0x6f;
 			WSFR(clboards[slotnum].SFR);
-	DEBUG printk(KERN_INFO "clgen:doing memset (Spectrum) at $%p, 1/2 MB...", clboards[slotnum].VirtAddr);
-			memset(clboards[slotnum].VirtAddr, 0, 524288);
-	DEBUG printk("clgen: done.\n");
-#endif
+			break;
+
+		case BT_PICASSO4:
+			/* no monitor bit to be switched here */
 			break;
 
 		default:
@@ -1646,109 +1949,55 @@
 
 	}
 
-	/* perform the actual memset */
-	if (var->bits_per_pixel == 1)
-		/* if mono, we only fill one memory plane */
-		amount = clboards[slotnum].size / 4;
-	else
-		/* in all other modes, clear the whole board mem */
-		amount = clboards[slotnum].size;
-	memset(clboards[slotnum].VirtAddr, 0, amount);
-
-
-	/* draw some graphics */
-	if (var->bits_per_pixel == 1)
+	if (clearflag)
 	{
-		for (i = 0; i < var->xres_virtual; i++)
-		{
-			*(unsigned char *)(clboards[slotnum].VirtAddr + (i/8) ) = 0xff;
-			*(unsigned char *)(clboards[slotnum].VirtAddr + ((var->yres-1) * clboards[slotnum].line_length) + (i/8) ) = 0xff;
-			*(unsigned char *)(clboards[slotnum].VirtAddr + ((var->yres_virtual-1) * clboards[slotnum].line_length) + (i/8) ) = 0xff;
-		}
-
-		for (i = 0; i < var->yres_virtual; i++)
-		{
-			*(unsigned char *)(clboards[slotnum].VirtAddr + (i * clboards[slotnum].line_length) ) = 0xff;
-			*(unsigned char *)(clboards[slotnum].VirtAddr + ((var->xres-1) / 8) + (i * clboards[slotnum].line_length) ) = 0xff;
-			*(unsigned char *)(clboards[slotnum].VirtAddr + ((var->xres_virtual-1) / 8) + (i * clboards[slotnum].line_length) ) = 0xff;
-		}
-
-		for (i = 0; i < var->yres_virtual; i++)
-		{
-			float step = (float)var->xres_virtual / (float)var->yres_virtual;
-			*(unsigned char *)(clboards[slotnum].VirtAddr + (i*clboards[slotnum].line_length) + (int)((step * i) / 8) ) = 0xff;
-		}
+		DEBUG printk(KERN_INFO "clgen: clearing display...");
+		clgen_RectFill(0, 0, xres, yres, 0, xres);
+		clgen_WaitBLT();
+		DEBUG printk("clgen: done.\n");
 	}
-	else if (var->bits_per_pixel == 8)
-	{
-		int i2, j, k, xoff, yoff;
-		unsigned char *base, *base2;
+}
 
-		/* create a sample CLUT */
-		WClut( 0, 0x00, 0x00, 0x00);
-		WClut( 1, 0xff, 0xff, 0xff);
 
-		for (i = 0; i < 16; i++)
-		{
-			WClut(128 + i, ((0xff>>4)*i), ((0xff>>4)*i), ((0xff>>4)*i));
-			WClut(144 + i, ((0xff>>4)*i), ((0x00>>4)*i), ((0x00>>4)*i));
-			WClut(160 + i, ((0x00>>4)*i), ((0xff>>4)*i), ((0x00>>4)*i));
-			WClut(176 + i, ((0x00>>4)*i), ((0x00>>4)*i), ((0xff>>4)*i));
-			WClut(192 + i, ((0xff>>4)*i), ((0xff>>4)*i), ((0x00>>4)*i));
-			WClut(208 + i, ((0xff>>4)*i), ((0x00>>4)*i), ((0xff>>4)*i));
-			WClut(224 + i, ((0x00>>4)*i), ((0xff>>4)*i), ((0xff>>4)*i));
-		}
+/**************
+ New versions of fb_get_cmap / fb_set_cmap, copied from amifb / cyberfb
+**************/
 
-		for (i = 0; i < var->xres_virtual; i++)
-		{
-			*(unsigned char *)(clboards[slotnum].VirtAddr + i ) = 0x01;
-			*(unsigned char *)(clboards[slotnum].VirtAddr + ((var->yres-1) * clboards[slotnum].line_length) + i ) = 0x01;
-			*(unsigned char *)(clboards[slotnum].VirtAddr + ((var->yres_virtual-1) * clboards[slotnum].line_length) + i ) = 0x01;
-		}
 
-		for (i = 0; i < var->yres_virtual; i++)
-		{
-			*(unsigned char *)(clboards[slotnum].VirtAddr + (i * clboards[slotnum].line_length) ) = 0x01;
-			*(unsigned char *)(clboards[slotnum].VirtAddr + (var->xres-1) + (i * clboards[slotnum].line_length) ) = 0x01;
-			*(unsigned char *)(clboards[slotnum].VirtAddr + (var->xres_virtual-1) + (i * clboards[slotnum].line_length) ) = 0x01;
-		}
+   /*
+    *    Get the Colormap
+    */
 
-		xoff = (var->xres / 2) - 128;
-		yoff = (var->yres / 2) - 84;
-		base = clboards[slotnum].VirtAddr + 
-			(yoff * clboards[slotnum].line_length) + xoff;
+static int clgen_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, int fbidx)
+{
+	int slotnum;
 
-		for (i2 = 0; i2 < 7; i2++)
-		{
-			for (j = 0; j < 16; j++)
-			{
-				for (k = 0; k < 23; k++)
-				{
-					base2 = base + i2 * clboards[slotnum].line_length * 24 +
-						j * 16 +
-						k * clboards[slotnum].line_length;
-					memset(base2, 128 + i2 * 16 + j, 15);
-				}	
-			}
-		}
+	slotnum = find_clboard(fbidx);
+	if (slotnum == -1)
+	{
+		DEBUG printk(KERN_WARNING "clgen: Warning: Board not found in get_cmap)!!\n");
+		return 0;
 	}
 
-	DEBUG printk(KERN_INFO "clgen_fb_set_var: exit\n");
-    return(0);
-}
+	g_slotnum = slotnum;
 
-/*************************************************************************
-	clgen_fb_get_cmap()
+	if (con == currcon) /* current console? */
+		return(do_fb_get_cmap(cmap, &disp[con].var, kspc));
+	else if (disp[con].cmap.len) /* non default colormap? */
+		copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2);
+	else
+		copy_cmap(get_default_colormap(1 << disp[con].var.bits_per_pixel), cmap,
+		kspc ? 0 : 2);
+	return(0);
+}
 
-	get one or more entries from the current colormap
-**************************************************************************/
+   /*
+    *    Set the Colormap
+    */
 
-static int clgen_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, int fbidx)
+static int clgen_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, int fbidx)
 {
-	int i, start;
-	unsigned short *red, *green, *blue, *transp;
-	unsigned char tred, tgreen, tblue;
-	unsigned short hred, hgreen, hblue, htransp;
+	int err;
 	int slotnum;
 
 	slotnum = find_clboard(fbidx);
@@ -1760,120 +2009,406 @@
 
 	g_slotnum = slotnum;
 
-	red = cmap->red;
-	green = cmap->green;
-	blue = cmap->blue;
-	transp = cmap->transp;
-
-	start = cmap->start;
-	if (start < 0)
-		return(-EINVAL);
-
-	for (i = 0; i < cmap->len; i++)
+	if (!disp[con].cmap.len) /* no colormap allocated? */
 	{
-		if (i < 256)
-			RClut(start++, &tred, &tgreen, &tblue);
-		else
-			tred = tgreen = tblue = 0;
+		if ((err = alloc_cmap(&disp[con].cmap, 
+			1<<disp[con].var.bits_per_pixel, 0)))
+		return(err);
+	}
+	if (con == currcon)              /* current console? */
+		return(do_fb_set_cmap(cmap, &disp[con].var, kspc));
+	else
+		copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
+	return(0);
+}
 
-		/* convert to X11 16 bit color representation */
-		/* This is not exactly right, but there is no measurable difference */
-		hred    = (unsigned short) tred << 8;
-		hgreen  = (unsigned short) tgreen << 8;
-		hblue   = (unsigned short) tblue << 8;
-		htransp = 0;
 
-		if (kspc)
-		{
-			*red   = hred;
-			*green = hgreen;
-			*blue  = hblue;
-			if (transp)
-				*transp = htransp;
+
+/**********************
+  Auxiliary cmap handling functions, again directly copied from cyberfb
+**********************/
+
+/* two tiny "wrappers" to avoid having to change prototypes in other places */
+static int clgen_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+                         u_int *transp)
+{
+	unsigned char bred, bgreen, bblue;
+
+	if (regno > 255 || regno < 0)
+		return (1);
+	RClut(regno, &bred, &bgreen, &bblue);
+
+	*red    = (u_int)bred;
+	*green  = (u_int)bgreen;
+	*blue   = (u_int)bblue;
+	*transp = 0;
+	return (0);
+}
+
+static int clgen_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                         u_int transp)
+{
+	if (regno > 255 || regno < 0)
+		return (1);
+
+	/* "transparent" stuff is completely ignored. */
+	WClut(regno, (red & 0xff), (green & 0xff), (blue & 0xff));
+
+	return (0);
+}
+
+
+static struct fb_cmap *get_default_colormap(int len)
+{
+	if (len == 2)
+		return &default_2_colors;
+	return &default_16_colors;
+}
+
+#define CNVT_TOHW(val,width)     ((((val)<<(width))+0x7fff-(val))>>16)
+#define CNVT_FROMHW(val,width)   (((width) ? ((((val)<<16)-(val)) / \
+                                              ((1<<(width))-1)) : 0))
+
+static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
+                          int kspc)
+{
+   int i, start;
+   u_short *red, *green, *blue, *transp;
+   u_int hred, hgreen, hblue, htransp;
+
+   red = cmap->red;
+   green = cmap->green;
+   blue = cmap->blue;
+   transp = cmap->transp;
+   start = cmap->start;
+   if (start < 0)
+      return(-EINVAL);
+   for (i = 0; i < cmap->len; i++) {
+      if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
+         return(0);
+      hred = CNVT_FROMHW(hred, var->red.length);
+      hgreen = CNVT_FROMHW(hgreen, var->green.length);
+      hblue = CNVT_FROMHW(hblue, var->blue.length);
+      htransp = CNVT_FROMHW(htransp, var->transp.length);
+      if (kspc) {
+         *red = hred;
+         *green = hgreen;
+         *blue = hblue;
+         if (transp)
+            *transp = htransp;
+      } else {
+         put_fs_word(hred, red);
+         put_fs_word(hgreen, green);
+         put_fs_word(hblue, blue);
+         if (transp)
+            put_fs_word(htransp, transp);
+      }
+      red++;
+      green++;
+      blue++;
+      if (transp)
+         transp++;
+   }
+   return(0);
+}
+
+
+static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
+                          int kspc)
+{
+   int i, start;
+   u_short *red, *green, *blue, *transp;
+   u_int hred, hgreen, hblue, htransp;
+
+   red = cmap->red;
+   green = cmap->green;
+   blue = cmap->blue;
+   transp = cmap->transp;
+   start = cmap->start;
+
+   if (start < 0)
+      return(-EINVAL);
+   for (i = 0; i < cmap->len; i++) {
+      if (kspc) {
+         hred = *red;
+         hgreen = *green;
+         hblue = *blue;
+         htransp = transp ? *transp : 0;
+      } else {
+         hred = get_fs_word(red);
+         hgreen = get_fs_word(green);
+         hblue = get_fs_word(blue);
+         htransp = transp ? get_fs_word(transp) : 0;
+      }
+      hred = CNVT_TOHW(hred, var->red.length);
+      hgreen = CNVT_TOHW(hgreen, var->green.length);
+      hblue = CNVT_TOHW(hblue, var->blue.length);
+      htransp = CNVT_TOHW(htransp, var->transp.length);
+      red++;
+      green++;
+      blue++;
+      if (transp)
+         transp++;
+      if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp))
+         return(0);
+   }
+   return(0);
+}
+
+
+static void do_install_cmap(int con)
+{
+   if (con != currcon)
+      return;
+   if (disp[con].cmap.len)
+     do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1);
+   else
+      do_fb_set_cmap(get_default_colormap(1 << disp[con].var.bits_per_pixel),
+                                          &disp[con].var, 1);
+}
+
+static void memcpy_fs(int fsfromto, void *to, void *from, int len)
+{
+   switch (fsfromto) {
+      case 0:
+         memcpy(to, from, len);
+         return;
+      case 1:
+         memcpy_fromfs(to, from, len);
+         return;
+      case 2:
+         memcpy_tofs(to, from, len);
+         return;
+   }
+}
+
+
+static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
+{
+   int size;
+   int tooff = 0, fromoff = 0;
+
+   if (to->start > from->start)
+      fromoff = to->start-from->start;
+   else
+      tooff = from->start-to->start;
+   size = to->len-tooff;
+   if (size > from->len-fromoff)
+      size = from->len-fromoff;
+   if (size < 0)
+      return;
+   size *= sizeof(u_short);
+   memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
+   memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
+   memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
+   if (from->transp && to->transp)
+      memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size);
+}
+
+
+static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
+{
+   int size = len*sizeof(u_short);
+
+	DEBUG printk("entry alloc_cmap; len = %d, old cmap->len: %d\n", len, cmap->len);
+   if (cmap->len != len) {
+      if (cmap->red)
+         kfree(cmap->red);
+      if (cmap->green)
+         kfree(cmap->green);
+      if (cmap->blue)
+         kfree(cmap->blue);
+      if (cmap->transp)
+         kfree(cmap->transp);
+      cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
+      cmap->len = 0;
+      if (!len)
+         return(0);
+      if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
+         return(-1);
+      if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
+         return(-1);
+      if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
+         return(-1);
+      if (transp) {
+         if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
+            return(-1);
+      } else
+         cmap->transp = NULL;
+   }
+   cmap->start = 0;
+   cmap->len = len;
+   copy_cmap(get_default_colormap(len), cmap, 0);
+   return(0);
+}
+
+
+/*******************************************************************
+	clgen_WaitBLT()
+
+	Wait for the BitBLT engine to complete a possible earlier job
+*********************************************************************/
+
+void clgen_WaitBLT()
+{
+	/* now busy-wait until we're done */
+	while (RGfx(GR31) & 0x08)
+		;
+}
+
+
+/*******************************************************************
+	clgen_BitBLT()
+
+	perform accelerated "scrolling"
+********************************************************************/
+
+/* #############
+These accel funcs are not yet ok for multiple boards!
+############### */
+
+void clgen_BitBLT (u_short curx, u_short cury, u_short destx, u_short desty,
+		u_short width, u_short height, u_short line_length)
+{
+	u_short nwidth, nheight;
+	u_long nsrc, ndest;
+	u_char bltmode;
+
+	nwidth = width - 1;
+	nheight = height - 1;
+
+	bltmode = 0x00;
+	/* if source adr < dest addr, do the Blt backwards */
+	if (cury <= desty)
+	{
+		if (cury == desty)
+		{
+			/* if src and dest are on the same line, check x */
+			if (curx < destx)
+				bltmode |= 0x01;
 		}
 		else
-		{
-			put_user(hred, red);
-			put_user(hgreen, green);
-			put_user(hblue, blue);
-			if (transp)
-				put_user(htransp, transp);
-		}
-		red++;
-		green++;
-		blue++;
-		if (transp)
-			transp++;
+			bltmode |= 0x01;
 	}
 
-	return(0);
+	if (!bltmode)
+	{
+		/* standard case: forward blitting */
+		nsrc = (cury * line_length) + curx;
+		ndest = (desty * line_length) + destx;
+	}
+	else
+	{
+		/* this means start addresses are at the end, counting backwards */
+		nsrc = cury * line_length + curx + nheight * line_length + nwidth;
+		ndest = desty * line_length + destx + nheight * line_length + nwidth;
+	}
+
+	clgen_WaitBLT(); /* ### NOT OK for multiple boards! */
+
+	/*
+		run-down of registers to be programmed:
+		destination pitch
+		source pitch
+		BLT width/height
+		source start
+		destination start
+		BLT mode
+		BLT ROP
+		GR0 / GR1: "fill color"
+		start/stop
+	*/
+
+	/* pitch: set to line_length */
+	WGfx(GR24, line_length & 0xff);	/* dest pitch low */
+	WGfx(GR25, (line_length >> 8));	/* dest pitch hi */
+	WGfx(GR26, line_length & 0xff);	/* source pitch low */
+	WGfx(GR27, (line_length >> 8));	/* source pitch hi */
+
+	/* BLT width: actual number of pixels - 1 */
+	WGfx(GR20, nwidth & 0xff);	/* BLT width low */
+	WGfx(GR21, (nwidth >> 8));	/* BLT width hi */
+
+	/* BLT height: actual number of lines -1 */
+	WGfx(GR22, nheight & 0xff);	/* BLT height low */
+	WGfx(GR23, (nheight >> 8));	/* BLT width hi */
+
+	/* BLT destination */
+	WGfx(GR28, (u_char)(ndest & 0xff));	/* BLT dest low */
+	WGfx(GR29, (u_char)(ndest >> 8));	/* BLT dest mid */
+	WGfx(GR2A, (u_char)(ndest >> 16));	/* BLT dest hi */
+
+	/* BLT source */
+	WGfx(GR2C, (u_char)(nsrc & 0xff));	/* BLT src low */
+	WGfx(GR2D, (u_char)(nsrc >> 8));	/* BLT src mid */
+	WGfx(GR2E, (u_char)(nsrc >> 16));	/* BLT src hi */
+
+	/* BLT mode */
+	WGfx(GR30, bltmode);	/* BLT mode */
+
+	/* BLT ROP: SrcCopy */
+	WGfx(GR32, 0x0d);	/* BLT ROP */
+
+	/* and finally: GO! */
+	WGfx(GR31, 0x02);	/* BLT Start/status */
 }
 
-/*************************************************************************
-	clgen_fb_set_cmap()
+/*******************************************************************
+	clgen_RectFill()
 
-	set one or more entries in the current colormap
-**************************************************************************/
+	perform accelerated rectangle fill
+********************************************************************/
 
-static int clgen_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, int fbidx)
+void clgen_RectFill (u_short x, u_short y, u_short width, u_short height,
+                     u_char color, u_short line_length)
 {
-	int i, start;
-	unsigned short *red, *green, *blue, *transp;
-	unsigned char tred, tgreen, tblue;
-	unsigned short hred, hgreen, hblue, htransp;
-	int slotnum;
+	u_short nwidth, nheight;
+	u_long ndest;
 
-	slotnum = find_clboard(fbidx);
-	if (slotnum == -1)
-	{
-		DEBUG printk(KERN_WARNING "clgen: Warning: Board not found in set_cmap)!!\n");
-		return 0;
-	}
+	nwidth = width - 1;
+	nheight = height - 1;
 
-	g_slotnum = slotnum;
+	ndest = (y * line_length) + x;
 
-	red = cmap->red;
-	green = cmap->green;
-	blue = cmap->blue;
-	transp = cmap->transp;
+	clgen_WaitBLT(); /* ### NOT OK for multiple boards! */
 
-	start = cmap->start;
-	if (start < 0)
-		return(-EINVAL);
+	/* pitch: set to line_length */
+	WGfx(GR24, line_length & 0xff);	/* dest pitch low */
+	WGfx(GR25, (line_length >> 8));	/* dest pitch hi */
+	WGfx(GR26, line_length & 0xff);	/* source pitch low */
+	WGfx(GR27, (line_length >> 8));	/* source pitch hi */
 
-	for (i = 0; i < cmap->len; i++)
-	{
-		if (kspc)
-		{
-			hred = *red;
-			hgreen = *green;
-			hblue = *blue;
-			htransp = (transp) ? *transp : 0;
-		}
-		else
-		{
-			hred   = get_user(red);
-			hgreen = get_user(green);
-			hblue  = get_user(blue);
-			htransp = (transp) ? get_user(transp) : 0;
-		}
+	/* BLT width: actual number of pixels - 1 */
+	WGfx(GR20, nwidth & 0xff);	/* BLT width low */
+	WGfx(GR21, (nwidth >> 8));	/* BLT width hi */
 
-		/* convert X11 16 bit to Cirrus Logic color register representation */
-		tred    = hred >> 8;
-		tgreen  = hgreen >> 8;
-		tblue   = hblue >> 8;
-		htransp = 0;
-
-		WClut(start++, tred, tgreen, tblue);
-
-		red++;
-		green++;
-		blue++;
-		if (transp)
-			transp++;
-	}
+	/* BLT height: actual number of lines -1 */
+	WGfx(GR22, nheight & 0xff);	/* BLT height low */
+	WGfx(GR23, (nheight >> 8));	/* BLT width hi */
 
-	return(0);
+	/* BLT destination */
+	WGfx(GR28, (u_char)(ndest & 0xff));	/* BLT dest low */
+	WGfx(GR29, (u_char)(ndest >> 8));	/* BLT dest mid */
+	WGfx(GR2A, (u_char)(ndest >> 16));	/* BLT dest hi */
+
+	/* BLT source: set to 0 (is a dummy here anyway) */
+	WGfx(GR2C, 0x00);	/* BLT src low */
+	WGfx(GR2D, 0x00);	/* BLT src mid */
+	WGfx(GR2E, 0x00);	/* BLT src hi */
+
+	/* This is a ColorExpand Blt, using the */
+	/* same color for foreground and background */
+	WGfx(GR0, color);	/* foreground color */
+	WGfx(GR1, color);	/* background color */
+
+	/* BLT mode: color expand, Enable 8x8 copy (faster?) */
+	WGfx(GR30, 0xc0);	/* BLT mode */
+
+	/* BLT ROP: SrcCopy */
+	WGfx(GR32, 0x0d);	/* BLT ROP */
+
+	/* and finally: GO! */
+	WGfx(GR31, 0x02);	/* BLT Start/status */
 }
 
 /*************************************************************************
@@ -1898,6 +2433,7 @@
 
 	switch(cmd)
 	{
+#if 0
 		case FBIOSWITCH_MONIBIT:
 			/* set monitor bit */
 			if (arg == 0)
@@ -1925,6 +2461,10 @@
 						WSFR(clboards[slotnum].SFR);
 						break;
 
+					case BT_PICASSO4:
+						/* nothing - dummy func */
+						break;
+
 					default:
 						DEBUG printk("clgen: Huh?\n");
 						break;
@@ -1955,12 +2495,17 @@
 						WSFR(clboards[slotnum].SFR);
 						break;
 
+					case BT_PICASSO4:
+						/* nothing - dummy func */
+						break;
+
 					default:
 						DEBUG printk("clgen: Huh?\n");
 						break;
 				}
 			}
 			break;
+#endif
 		default:
 			return -EINVAL;
 			break;
@@ -2043,7 +2588,8 @@
 	tmp2 = (RCrt(CRT1B) & 0xf2) | tmp; /* 0xf2 is %11110010, exclude tmp bits */
 	WCrt(CRT1B, tmp2);
 	/* construct bit 19 of screen start address (only on SD64) */
-	if (clboards[slotnum].boardtype == BT_SD64)
+	if (clboards[slotnum].boardtype == BT_SD64 ||
+		clboards[slotnum].boardtype == BT_PICASSO4)
 	{
 		tmp2 = 0;
 		if (base & 0x80000)
@@ -2112,7 +2658,6 @@
     clgen_fb_get_cmap, clgen_fb_set_cmap, clgen_fb_pan_display,
     clgen_fb_ioctl, clgen_get_monitorspec, clgen_put_monitorspec };
 
-/* ### MISSING FUNCTIONS HERE: fb_switch, fb_updatevar(?), fb_blank() */
 
 /********************************************************************/
 /* find_clboard() - locate clboard struct for an fbidx              */
@@ -2133,15 +2678,20 @@
 /********************************************************************/
 /* clgen_fb_init() - master initialization function                 */
 /********************************************************************/
-void clgen_fb_init(long *mem_start)
+struct fb_info *clgen_fb_init(long *mem_start)
 {
-	int key, key2;
-	struct ConfigDev *cd, *cd2;
-	int err, i, slotnum;
+	int key = 0, key2 = 0, key3 = 0;
+	struct ConfigDev *cd = NULL, *cd2 = NULL, *cd3 = NULL;
+	int err, i, slotnum, p4flag = 0;
 	int btype;
+	static int firstpass = 0;
+	static struct fb_var_screeninfo init_var;
 
 	printk(KERN_INFO "clgen: Driver for Cirrus Logic based graphic boards, v" CLGEN_VERSION "\n");
 
+	fbhw = &clgen_hwswitch;
+	/* ### fbhw->init()? */
+
 	/* Free all slots */
 	for (i = 0; i < MAX_NUM_BOARDS; i++)
 		clboards[i].fbnum = -1;
@@ -2194,66 +2744,164 @@
 			}
 		}
 
+
+		/* none found, check next board type (Picasso 4, 4th ProdID (Zorro 3)) */
+		if (btype == -1)
+		{
+			key  = zorro_find(MANUF_VILLAGE_TRONIC, PROD_PICASSO_IV_4, 0, 0);
+			if (key != 0)
+			{
+				btype = BT_PICASSO4;
+				printk(KERN_INFO "clgen: Picasso IV board detected; ");
+				p4flag = 0;
+			}
+		}
+
+
+		/* none found, check next board type (Picasso 4 In Zorro 2) */
+		if (btype == -1)
+		{
+			key  = zorro_find(MANUF_VILLAGE_TRONIC, PROD_PICASSO_IV, 0, 0);
+			key2 = zorro_find(MANUF_VILLAGE_TRONIC, PROD_PICASSO_IV_2, 0, 0);
+			key3 = zorro_find(MANUF_VILLAGE_TRONIC, PROD_PICASSO_IV_3, 0, 0);
+			if (key != 0)
+			{
+				btype = BT_PICASSO4;
+				printk(KERN_INFO "clgen: Picasso IV board (in Zorro II) detected; ");
+				p4flag = 1;
+			}
+		}
+
+
 		/* When we get here with != -1, we have a board to be init'ed. */
 		if (btype != -1)
 		{
 			cd = zorro_get_board(key);
-			printk(" RAM (%d KB) at $%lx, ",
-				(unsigned int)(cd->cd_BoardSize/1024),
-				(unsigned long)(cd->cd_BoardAddr));
-
 			cd2 = zorro_get_board(key2);
-			printk(" REG at $%lx\n", (unsigned long)(cd2->cd_BoardAddr));
+			if (p4flag)
+				cd3 = zorro_get_board(key3);
 
 			/* search for a free slot in the clboards[] array */
 			slotnum = find_clboard(-1);
 			if (slotnum == -1)
 			{
 				printk(KERN_ERR "clgen: Warning: Could not get a free slot for board!\n");
-				return;
+				return(NULL);
 			}
 
+			clboards[slotnum].p4flag = 0;
+
 			DEBUG printk(KERN_INFO "clgen: Found a free slot for this board at array elem #%d\n", slotnum);
 			/* set address for RAM area of board */
-			clboards[slotnum].PhysAddr = (unsigned long)cd->cd_BoardAddr;
-			clboards[slotnum].size = cd->cd_BoardSize;
+			if (btype != BT_PICASSO4)
+			{
+				clboards[slotnum].PhysAddr = (unsigned long)cd->cd_BoardAddr;
+				clboards[slotnum].size = cd->cd_BoardSize;
+			}
+			else
+			{
+				/* p4flag set: P4 in Z2 mode, else in Z3 */
+				if (!p4flag)
+				{
+					/* To be precise, for the P4 this is not the */
+					/* begin of the board, but the begin of RAM. */
+					clboards[slotnum].PhysAddr = (unsigned long)cd->cd_BoardAddr + 0x1000000;
+					clboards[slotnum].size = cd->cd_BoardSize;
+				}
+				else
+				{
+					clboards[slotnum].PhysAddr = (unsigned long)cd->cd_BoardAddr;
+					clboards[slotnum].size = cd->cd_BoardSize;
+					clboards[slotnum].smallboard = TRUE;
+					if (key2)
+					{
+						DEBUG printk(KERN_INFO "clgen: detected Picasso IV in Z2 with both banks enabled (4 MB)\n");
+						clboards[slotnum].size += cd2->cd_BoardSize;
+						clboards[slotnum].smallboard = FALSE;
+					}
+					else
+					{
+						DEBUG printk(KERN_INFO "clgen: detected Picasso IV in Z2 with one bank enabled (2 MB)\n");
+					}
+					/* flag: this board needs no RAM amount check */
+					clboards[slotnum].p4flag = 1;
+				}
+			}
 
 			/* map the physical board address to a virtual address in */
 			/* kernel space; but only if it's really in Zorro III address */
 			/* space; Z2 boards (like the Picasso) are in the low 16 MB region */
 			/* which is automatically mapped so that no kernel_map is */
 			/* necessary there (only Z2 address translation) */
-			if (clboards[slotnum].PhysAddr > 0x01000000)
+			if (btype != BT_PICASSO4 || p4flag)
 			{
-				clboards[slotnum].VirtAddr = (unsigned char *)kernel_map(
-					clboards[slotnum].PhysAddr, 
-					clboards[slotnum].size, KERNELMAP_NOCACHE_SER, mem_start);
+				if (clboards[slotnum].PhysAddr > 0x01000000)
+				{
+					clboards[slotnum].VirtAddr = (unsigned char *)kernel_map(
+						(unsigned long)cd->cd_BoardAddr, 
+						cd->cd_BoardSize, KERNELMAP_NOCACHE_SER, mem_start);
+				}
+				else
+					clboards[slotnum].VirtAddr = (unsigned char *)(ZTWO_VADDR(clboards[slotnum].PhysAddr));
+
+				/* for most boards, start of DRAM = start of board */
+				clboards[slotnum].VirtRAMAddr = clboards[slotnum].VirtAddr;
 			}
 			else
-				clboards[slotnum].VirtAddr = (unsigned char *)(ZTWO_VADDR(clboards[slotnum].PhysAddr));
+			{
+				/* for P4 (Z3), map in its address space in 2 chunks (### TEST! ) */
+				/* (note the ugly hardcoded 16M number) */
+				clboards[slotnum].VirtRegBase = (unsigned char *)kernel_map(
+					(unsigned long)cd->cd_BoardAddr, 
+					16777216, KERNELMAP_NOCACHE_SER, mem_start);
+
+				clboards[slotnum].VirtRegBase += 0x600000;
+
+				clboards[slotnum].VirtRAMAddr = (unsigned char *)kernel_map(
+					(unsigned long)cd->cd_BoardAddr + 16777216, 
+					16777216, KERNELMAP_NOCACHE_SER, mem_start);
+			}
 
+			printk(KERN_INFO "clgen: Virtual address for board set to: $%p\n", clboards[slotnum].VirtAddr);
+			printk(KERN_INFO "clgen: (RAM start set to: $%p)\n", clboards[slotnum].VirtRAMAddr);
+#if 0
 			DEBUG printk(KERN_INFO "clgen: Virtual address for board set to: $%p\n", clboards[slotnum].VirtAddr);
+			DEBUG printk(KERN_INFO "clgen: (RAM start set to: $%p)\n", clboards[slotnum].VirtRAMAddr);
+#endif
 
 			/* set address for REG area of board */
-			clboards[slotnum].RegBase = cd2->cd_BoardAddr;
-			clboards[slotnum].VirtRegBase = 
-				(unsigned char *)ZTWO_VADDR(clboards[slotnum].RegBase);
+			if (btype != BT_PICASSO4 || p4flag)
+			{
+				if (!p4flag)
+					clboards[slotnum].RegBase = cd2->cd_BoardAddr;
+				else
+					clboards[slotnum].RegBase = cd3->cd_BoardAddr + 0x10000;
+
+				clboards[slotnum].VirtRegBase = 
+					(unsigned char *)ZTWO_VADDR(clboards[slotnum].RegBase);
+			}
+
 
 			/* set defaults for monitor specifications */
 			/* these should be careful values for most, even old, monitors */
-			clboards[slotnum].mon_hfmin = 30000;
-			clboards[slotnum].mon_hfmax = 38000;
-			clboards[slotnum].mon_vfmin = 50;
-			clboards[slotnum].mon_vfmax = 90;
 
-			/* set up a few more things, register framebuffer driver with kernel etc */
+			/* set them only if they haven't been set before */
+			if (clboards[slotnum].mon_hfmin == -1)
+			{
+				clboards[slotnum].mon_hfmin = 30000;
+				clboards[slotnum].mon_hfmax = 38000;
+				clboards[slotnum].mon_vfmin = 50;
+				clboards[slotnum].mon_vfmax = 90;
+			}
+
+			/* set up a few more things, register framebuffer driver etc */
 			err = register_framebuffer("CL Generic", 
 				&clboards[slotnum].node, &clgen_fb_ops,
 				NUM_TOTAL_MODES, clgen_fb_predefined);
 			if (err)
 			{
 				printk(KERN_ERR "clgen: WARNING - could not register fb device; err = %d!\n", err);
-				return;
+				return(NULL);
 			}
 
 			/* create fbnum from inode */
@@ -2262,7 +2910,19 @@
 
 			/* mark this board as "autoconfigured" */
 			zorro_config_board(key, 0);
-			zorro_config_board(key2, 0);
+			if (btype != BT_PICASSO4)
+				zorro_config_board(key2, 0);
+			else
+			{
+				/* configure the other 2 areas of Z2 P4 if found */
+				if (p4flag)
+				{
+					if (key2)
+						zorro_config_board(key2, 0);
+					if (key3)
+						zorro_config_board(key3, 0);
+				}
+			}
 
 			num_inited++;
 			DEBUG printk(KERN_INFO "clgen: Number of init'ed CLGEN boards at this time: %d\n", num_inited);
@@ -2287,6 +2947,9 @@
 				case BT_SPECTRUM:
 					DEBUG printk("GVP Spectrum\n");
 					break;
+				case BT_PICASSO4:
+					DEBUG printk("Picasso IV\n");
+					break;
 				default: 
 					DEBUG printk("Unidentified - Huh?\n");
 					break;
@@ -2300,10 +2963,243 @@
 			init_vgachip(clboards[slotnum].fbnum);
 
 			/* board gets init'ed with 640x480 mode, 31.25 kHz, 60 Hz, 8bit */
-			clgen_fb_set_var(&clgen_fb_predefined[1], 0, clboards[slotnum].fbnum);
+			init_var = clgen_fb_predefined[g_startmode];
+			init_var.activate = FB_ACTIVATE_NOW;
+			err = clgen_fb_set_var(&init_var, 0, clboards[slotnum].fbnum);
+			if (err)
+			{
+				/* This monitor limits/video mode combo */
+				/* SHOULD never fail. */
+				printk(KERN_WARNING "clgen: Unable to set video mode; resetting to default.\n");
+				clboards[slotnum].mon_hfmin = 30000;
+				clboards[slotnum].mon_hfmax = 38000;
+				clboards[slotnum].mon_vfmin = 50;
+				clboards[slotnum].mon_vfmax = 90;
+				init_var = clgen_fb_predefined[1];
+				init_var.activate = FB_ACTIVATE_NOW;
+				clgen_fb_set_var(&init_var, 0, clboards[slotnum].fbnum);
+			}
+
+			/* only the first board found can be the console */
+			if (firstpass == 0)
+			{
+				firstpass = 1;
+				strcpy(fb_info.modename, "CLGEN-default");
+				fb_info.disp = disp;
+				fb_info.switch_con = &clgen_switch;
+				fb_info.updatevar = &clgen_updatevar;
+				fb_info.blank = &clgen_blank;
+				return(&fb_info);
+			}
 		}
 	} while (btype != -1);
+	return(NULL);    /* shouldn't ever come here.. */
 
 	/* done */
 }
 
+/**************************/
+/* small support functions copied over from cyberfb.c. */
+/* a typical meeting hack.. dunno if this can work at all. It's 1:30 a.m. */
+/* Too many beers. */
+/**************************/
+
+static int clgen_switch(int con)
+{
+	/* Do we have to save the colormap? */
+	if (disp[currcon].cmap.len)
+		do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
+
+	/* ### WARNING - requires fbidx patch here! */
+	currcon = con;
+	/* set mode in harware, WITH clearflag set */
+	clgen_set_var(&disp[con].var, 1);
+	/* Install new colormap */
+	do_install_cmap(con);
+	return(0);
+}
+
+static int clgen_updatevar(int con)
+{
+   return(0);
+}
+
+static void clgen_blank(int blank)
+{
+	unsigned char val;
+
+	if (blank)
+		/* activate blanker */
+	{
+		val = RSeq(SR1);
+		WSeq(SR1, val | 0x20); /* set "FullBandwidth" bit */
+	}
+	else
+	{
+		val = RSeq(SR1);
+		WSeq(SR1, val & 0xdf); /* clear "FullBandwidth" bit */
+	}
+/*	printk(KERN_WARNING "CLGEN: Blank-di-blank: called with blank=%d...\n", blank); */
+}
+
+
+
+/******************************************************************/
+/* clgen_probe() - tiny function to see if the required board(s)  */
+/* is there at all. Mimics the behaviour of Cyber_probe()         */
+/******************************************************************/
+
+int clgen_probe()
+{
+	int bla;
+
+	/* if the DRAM area of any of these boards is found, I can be */
+	/* pretty sure the rest is also there - enough anyway to attempt */	
+	/* to start to initialize the console on it. */
+
+	/* SD64? */
+	bla = zorro_find(MANUF_HELFRICH2, PROD_SD64_RAM, 0, 0);
+	if (bla)
+		return bla;
+
+	/* Piccolo? */
+	bla = zorro_find(MANUF_HELFRICH2, PROD_PICCOLO_RAM, 0, 0);
+	if (bla)
+		return bla;
+
+	/* Picasso II? */
+	bla = zorro_find(MANUF_VILLAGE_TRONIC, PROD_PICASSO_II_RAM, 0, 0);
+	if (bla)
+		return bla;
+
+	/* GVP Spectrum? */
+	bla = zorro_find(MANUF_GVP2, PROD_SPECTRUM_RAM, 0, 0);
+	if (bla)
+		return bla;
+
+	/* Picasso IV in Z3? */
+	bla = zorro_find(MANUF_VILLAGE_TRONIC, PROD_PICASSO_IV_4, 0, 0);
+	if (bla)
+		return bla;
+
+	/* Picasso IV in Z2? */
+	bla = zorro_find(MANUF_VILLAGE_TRONIC, PROD_PICASSO_IV, 0, 0);
+	if (bla)
+		return bla;
+
+	return 0;
+}
+
+
+/*****************************************************************/
+/* clgen_video_setup() might be used later for parsing possible  */
+/* arguments to the video= bootstrap parameter. Right now, there */
+/* is nothing I do here.                                         */
+/*****************************************************************/
+
+void clgen_video_setup(char *options, int *ints)
+{
+	char *this_opt;
+	char mcap_spec[80];
+
+	/* ### Warning BAD HACK - will not work with multiple boards */
+	clboards[0].mon_hfmin = -1;
+	clboards[0].mon_hfmax = -1;
+	clboards[0].mon_vfmin = -1;
+	clboards[0].mon_vfmax = -1;
+
+	mcap_spec[0] = '\0';
+	fb_info.fontname[0] = '\0';
+
+	if (!options || !*options)
+		return;
+
+	if (!strncmp(options, "clgen:", 6))
+		options += 6;
+
+	for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ","))
+	{
+		char *p;
+		if (!strncmp(this_opt, "monitorcap:", 11))
+			strcpy(mcap_spec, this_opt+11);
+		else if (!strncmp(this_opt, "mode:", 5))
+		{
+			p = this_opt + 5;
+			/* slightly hardcoded indices into mode table, sorry */
+			if (!strncmp(p, "low", 3))
+				g_startmode = 1;
+			else if (!strncmp(p, "med", 3))
+				g_startmode = 2;
+			else if (!strncmp(p, "high", 4))
+				g_startmode = 3;
+			else
+				g_startmode = 1;
+		}
+	}
+
+	if (*mcap_spec)
+	{
+		char *p;
+		int vmin, vmax, hmin, hmax;
+
+	/* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
+	 * <V*> vertical freq. in Hz
+	 * <H*> horizontal freq. in kHz
+	 */
+
+		if (!(p = strtoke(mcap_spec, ";")) || !*p)
+			goto cap_invalid;
+		vmin = simple_strtoul(p, NULL, 10);
+		if (vmin <= 0)
+			goto cap_invalid;
+		if (!(p = strtoke(NULL, ";")) || !*p)
+			goto cap_invalid;
+		vmax = simple_strtoul(p, NULL, 10);
+		if (vmax <= 0 || vmax <= vmin)
+			goto cap_invalid;
+		if (!(p = strtoke(NULL, ";")) || !*p)
+			goto cap_invalid;
+		hmin = 1000 * simple_strtoul(p, NULL, 10);
+		if (hmin <= 0)
+			goto cap_invalid;
+		if (!(p = strtoke(NULL, "")) || !*p)
+			goto cap_invalid;
+		hmax = 1000 * simple_strtoul(p, NULL, 10);
+		if (hmax <= 0 || hmax <= hmin)
+			goto cap_invalid;
+
+		/* ### Warning BAD HACK - will not work with multiple boards */
+		clboards[0].mon_hfmin = hmin;
+		clboards[0].mon_hfmax = hmax;
+		clboards[0].mon_vfmin = vmin;
+		clboards[0].mon_vfmax = vmax;
+		printk(KERN_INFO "clgen: Monitor limits set to H: %d - %d Hz, V: %d - %d Hz\n", hmin, hmax, vmin, vmax);
+cap_invalid:
+		;
+	}
+}
+
+
+/*
+ * A strtok which returns empty strings, too
+ * (Taken from Geert's amiga/amifb.c)
+ */
+
+static char *strtoke(char *s,const char *ct)
+{
+	char *sbegin, *send;
+	static char *ssave = NULL;
+
+	sbegin  = s ? s : ssave;
+	if (!sbegin)
+		return NULL;
+	if (*sbegin == '\0') {
+		ssave = NULL;
+		return NULL;
+	}
+	send = strpbrk(sbegin, ct);
+	if (send && *send != '\0')
+		*send++ = '\0';
+	ssave = send;
+	return sbegin;
+}
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/arch/m68k/amiga/clgen.h linux20/arch/m68k/amiga/clgen.h
--- /data/tmp/linux-2.0.33/arch/m68k/amiga/clgen.h	Mon Jul 14 12:07:52 1997
+++ linux20/arch/m68k/amiga/clgen.h	Mon Jan 12 15:32:51 1998
@@ -92,6 +92,7 @@
 #define CRT1D	0x1d	/* Overlay Extended Control register */
 #define CRT25	0x25	/* Part Status Register */
 #define CRT27	0x27	/* ID Register */
+#define CRT51	0x51	/* P4 disable "flicker fixer" */
 
 /*** Graphics Controller Registers ***/
 #define GRX	0x3ce	/* Graphics Controller Index */
@@ -133,9 +134,11 @@
 #define GR2C	0x2c	/* BLT Source Start Low */
 #define GR2D	0x2d	/* BLT Source Start Mid */
 #define GR2E	0x2e	/* BLT Source Start High */
+#define GR2F	0x2f	/* Picasso IV Blitter compat mode..? */
 #define GR30	0x30	/* BLT Mode */
 #define GR31	0x31	/* BLT Start/Status */
 #define GR32	0x32	/* BLT Raster Operation */
+#define GR33	0x33	/* another P4 "compat" register.. */
 #define GR34	0x34	/* Transparent Color Select Low */
 #define GR35	0x35	/* Transparent Color Select High */
 #define GR38	0x38	/* Source Transparent Color Mask Low */
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/arch/m68k/amiga/cyberfb.c linux20/arch/m68k/amiga/cyberfb.c
--- /data/tmp/linux-2.0.33/arch/m68k/amiga/cyberfb.c	Wed Dec 17 18:40:54 1997
+++ linux20/arch/m68k/amiga/cyberfb.c	Thu Mar 19 19:51:45 1998
@@ -80,7 +80,7 @@
 
 
 #define wb_64(reg,dat) (*((unsigned char volatile *)CyberRegs + reg) = dat)
-#define ww_64(reg,dat) (*((unsigned short volatile *)CyberRegs + reg) = dat)
+#define ww_64(reg,dat) (*((unsigned short volatile *)(CyberRegs + reg)) = dat)
 
 
 struct Cyber_fb_par {
@@ -511,6 +511,11 @@
 	fix->smem_len = CyberSize;
 
 	fix->type = FB_TYPE_PACKED_PIXELS;
+	if (CV3D)
+		fix->accel = FB_ACCEL_S3VIRGE;
+	else
+		fix->accel = FB_ACCEL_S3TRIO64;
+			
 	fix->type_aux = 0;
 	if (par->bpp == 8)
 		fix->visual = FB_VISUAL_PSEUDOCOLOR;
@@ -594,9 +599,9 @@
 	var->width = -1;
 
 	if (CV3D)
-		var->accel = FB_ACCEL_CYBERVISION3D;
+		var->accel = FB_ACCEL_S3VIRGE;
 	else
-		var->accel = FB_ACCEL_CYBERVISION;
+		var->accel = FB_ACCEL_S3TRIO64;
 
 	var->vmode = FB_VMODE_NONINTERLACED;
 
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/arch/m68k/amiga/zorro.c linux20/arch/m68k/amiga/zorro.c
--- /data/tmp/linux-2.0.33/arch/m68k/amiga/zorro.c	Fri Dec 12 21:43:22 1997
+++ linux20/arch/m68k/amiga/zorro.c	Wed Mar 18 10:49:41 1998
@@ -564,7 +564,8 @@
 END
 
 BEGIN_PROD(PETSOFF)
-   PROD("Delfina DSP", DELFINA)
+   PROD("Delfina Sound Board", DELFINA)
+   PROD("Delfina Lite Sound Board", DELFINA_LITE)
 END
 
 BEGIN_PROD(UWE_GERLACH)
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/arch/m68k/console/fbcon.c linux20/arch/m68k/console/fbcon.c
--- /data/tmp/linux-2.0.33/arch/m68k/console/fbcon.c	Fri Nov 28 22:48:04 1997
+++ linux20/arch/m68k/console/fbcon.c	Mon Mar 16 11:21:00 1998
@@ -97,6 +97,7 @@
 #undef CONFIG_FBCON_32PACKED
 #undef CONFIG_FBCON_CYBER
 #undef CONFIG_FBCON_VIRGE
+#undef CONFIG_FBCON_CLGEN
 
 
 /* Monochrome is default */
@@ -130,6 +131,16 @@
 #endif
 #endif
 
+/* CLGen boards (only 8bit packed pixel accel consoles atm) */
+#ifdef CONFIG_FB_CLGEN
+#ifndef CONFIG_FBCON_CLGEN
+#define CONFIG_FBCON_CLGEN
+#ifndef CONFIG_FBCON_8PACKED
+#define CONFIG_FBCON_8PACKED
+#endif
+#endif
+#endif /* CONFIG_FB_CLGEN */
+
 #endif /* CONFIG_AMIGA */
 
 /* Atari support */
@@ -164,7 +175,8 @@
 
 #if defined(CONFIG_FBCON_CYBER) || defined(CONFIG_FBCON_VIRGE) || \
     defined(CONFIG_FBCON_8PACKED) || defined(CONFIG_FBCON_16PACKED) || \
-    defined(CONFIG_FBCON_24PACKED) || defined(CONFIG_FBCON_32PACKED)
+    defined(CONFIG_FBCON_24PACKED) || defined(CONFIG_FBCON_32PACKED) || \
+    defined(CONFIG_FBCON_CLGEN)
 #define CONFIG_FBCON_PACKED
 #else
 #undef CONFIG_FBCON_PACKED
@@ -459,6 +471,29 @@
 			     u_short height, u_short color);
 #endif
 
+   /*
+    *    Cirrus Logic boards (accelerated)
+    */
+
+#ifdef CONFIG_FBCON_CLGEN
+static void bmove_clgen(struct display *p, int sy, int sx, int dy, int dx,
+                        int height, int width);
+static void clear_clgen(struct vc_data *conp, struct display *p, int sy, int sx,
+                        int height, int width);
+static void putc_clgen(struct vc_data *conp, struct display *p, int c, int y,
+                       int x);
+static void putcs_clgen(struct vc_data *conp, struct display *p, const char *s,
+                        int count, int y, int x);
+static void rev_char_clgen(struct display *p, int x, int y);
+
+extern void clgen_WaitBLT(void);
+extern void clgen_BitBLT(u_short curx, u_short cury, u_short destx,
+                         u_short desty, u_short width, u_short height,
+                         u_short mode);
+extern void clgen_RectFill(u_short x, u_short y, u_short width, u_short height,
+                           u_short mode, u_short color);
+#endif /* CONFIG_FBCON_CLGEN */
+
 
    /*
     *    `switch' for the Low Level Operations
@@ -538,6 +573,12 @@
 };
 #endif
 
+#ifdef CONFIG_FBCON_CLGEN
+struct display_switch dispsw_clgen = {
+   bmove_clgen, clear_clgen, putc_clgen, putcs_clgen, rev_char_clgen
+};
+#endif /* CONFIG_FBCON_CLGEN */
+
 
 static u_long fbcon_startup(u_long kmem_start, char **display_desc)
 {
@@ -690,15 +731,21 @@
       p->next_line = p->var.xres_virtual*p->var.bits_per_pixel>>3;
       p->next_plane = 0;
 #ifdef CONFIG_FBCON_CYBER
-      if (p->var.accel == FB_ACCEL_CYBERVISION)
+      if (p->var.accel == FB_ACCEL_S3TRIO64)
          p->dispsw = &dispsw_cyber;
       else
 #endif
 #ifdef CONFIG_FBCON_VIRGE
-      if (p->var.accel == FB_ACCEL_CYBERVISION3D)
+      if (p->var.accel == FB_ACCEL_S3VIRGE)
 	 p->dispsw = &dispsw_cyber3d;
       else
 #endif
+#ifdef CONFIG_FBCON_CLGEN
+/* ### to be extended with handling of different depths (1bit, 24..?) */
+      if (p->var.accel == FB_ACCEL_CLGEN)
+         p->dispsw = &dispsw_clgen;
+      else
+#endif /* CONFIG_FBCON_CLGEN */
 #ifdef CONFIG_FBCON_8PACKED
       if (p->var.bits_per_pixel == 8)
          p->dispsw = &dispsw_8_packed;
@@ -3817,6 +3864,126 @@
 
 #endif
 
+
+/* ====================================================================== */
+
+#ifdef CONFIG_FBCON_CLGEN
+
+   /*
+    *    Cirrus Logic boards (accelerated)
+    */
+
+static void bmove_clgen(struct display *p, int sy, int sx, int dy, int dx,
+                        int height, int width)
+{
+	if (width == 0 || height == 0)
+		return;
+	sx *= 8; 
+
+	dx *= 8; 
+	width *= 8;
+	clgen_BitBLT((u_short)sx, (u_short)(sy*p->fontheight), (u_short)dx,
+		(u_short)(dy*p->fontheight), (u_short)width,
+		(u_short)(height*p->fontheight), (u_short)p->line_length);
+}
+
+
+static void clear_clgen(struct vc_data *conp, struct display *p, int sy, int sx,
+                        int height, int width)
+{
+	u_char bg;
+        
+	if (width == 0 || height == 0)
+		return;
+
+	sx *= 8;
+	width *= 8;
+	bg = attr_bgcol_ec(p,conp);
+	clgen_RectFill((u_short)sx, (u_short)(sy*p->fontheight), (u_short)width,
+		(u_short)(height*p->fontheight), bg, p->line_length); 
+}
+
+
+static void putc_clgen(struct vc_data *conp, struct display *p, int c, int y,
+                       int x)
+{
+	u_char *dest,*cdat;
+	int bytes=p->next_line,rows;
+	ulong eorx,fgx,bgx;
+
+	c &= 0xff;
+
+	dest = p->screen_base + y * p->fontheight * bytes + x * 8;
+	cdat = p->fontdata + c * p->fontheight;
+
+	fgx=attr_fgcol(p,conp);
+	bgx=attr_bgcol(p,conp);
+	fgx |= (fgx << 8);
+	fgx |= (fgx << 16);
+	bgx |= (bgx << 8);
+	bgx |= (bgx << 16);
+	eorx = fgx ^ bgx;
+
+	clgen_WaitBLT();
+
+	for (rows = p->fontheight ; rows-- ; dest += bytes) {
+		((u_long *)dest)[0]=
+			(nibbletab_8_packed[*cdat >> 4] & eorx) ^ bgx;
+		((u_long *)dest)[1]=
+			(nibbletab_8_packed[*cdat++ & 0xf] & eorx) ^ bgx;
+	}
+}
+
+
+static void putcs_clgen(struct vc_data *conp, struct display *p, const char *s,
+                        int count, int y, int x)
+{
+	u_char *cdat, c, *dest, *dest0;
+	int rows,bytes=p->next_line;
+	u_long eorx, fgx, bgx;
+
+	dest0 = p->screen_base + y * p->fontheight * bytes + x * 8;
+	fgx=attr_fgcol(p,conp);
+	bgx=attr_bgcol(p,conp);
+	fgx |= (fgx << 8);
+	fgx |= (fgx << 16);
+	bgx |= (bgx << 8);
+	bgx |= (bgx << 16);
+	eorx = fgx ^ bgx;
+
+	clgen_WaitBLT();
+
+	while (count--) {
+		c = *s++;
+		cdat = p->fontdata + c * p->fontheight;
+
+		for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
+			((u_long *)dest)[0]=
+			(nibbletab_8_packed[*cdat >> 4] & eorx) ^ bgx;
+			((u_long *)dest)[1]=
+			(nibbletab_8_packed[*cdat++ & 0xf] & eorx) ^ bgx;
+		}
+		dest0+=8;
+	}
+}
+
+
+static void rev_char_clgen(struct display *p, int x, int y)
+{
+	u_char *dest;
+	int bytes=p->next_line, rows;
+
+	dest = p->screen_base + y * p->fontheight * bytes + x * 8;
+
+	clgen_WaitBLT();
+
+	for (rows = p->fontheight ; rows-- ; dest += bytes) {
+		((u_long *)dest)[0] ^= 0x0f0f0f0f;
+		((u_long *)dest)[1] ^= 0x0f0f0f0f;
+	}
+}
+
+#endif /* CONFIG_FBCON_CLGEN */
 
 /* ====================================================================== */
 
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/arch/m68k/kernel/traps.c linux20/arch/m68k/kernel/traps.c
--- /data/tmp/linux-2.0.33/arch/m68k/kernel/traps.c	Sat Oct  5 13:24:07 1996
+++ linux20/arch/m68k/kernel/traps.c	Thu Mar 19 19:05:03 1998
@@ -195,7 +195,7 @@
 			return;
 	}
 	
-	if (fslw & (MMU060_DESC_ERR | MMU060_WP)) {
+	if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) {
 		unsigned long errorcode;
 		unsigned long addr = fp->un.fmt4.effaddr;
 		errorcode = ((fslw & MMU060_WP) ? 1 : 0) |
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/arch/m68k/mm/init.c linux20/arch/m68k/mm/init.c
--- /data/tmp/linux-2.0.33/arch/m68k/mm/init.c	Thu Feb 27 14:51:05 1997
+++ linux20/arch/m68k/mm/init.c	Thu Mar 19 19:05:03 1998
@@ -315,6 +315,18 @@
 		for (i = 0; i < 16; i++)
 			pgprot_val(protection_map[i]) |= _PAGE_CACHE040;
 	}
+	/* Fix the PAGE_NONE value. */
+	if (CPU_IS_040_OR_060) {
+		/* On the 680[46]0 we can use the _PAGE_SUPER bit.  */
+		pgprot_val(protection_map[0]) |= _PAGE_SUPER;
+		pgprot_val(protection_map[VM_SHARED]) |= _PAGE_SUPER;
+	} else {
+		/* Otherwise we must fake it. */
+		pgprot_val(protection_map[0]) &= ~_PAGE_PRESENT;
+		pgprot_val(protection_map[0]) |= _PAGE_FAKE_SUPER;
+		pgprot_val(protection_map[VM_SHARED]) &= ~_PAGE_PRESENT;
+		pgprot_val(protection_map[VM_SHARED]) |= _PAGE_FAKE_SUPER;
+	}
 
 	/*
 	 * Map the physical memory available into the kernel virtual
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/drivers/block/amiflop.c linux20/drivers/block/amiflop.c
--- /data/tmp/linux-2.0.33/drivers/block/amiflop.c	Thu Sep 11 21:19:24 1997
+++ linux20/drivers/block/amiflop.c	Fri Mar 13 21:26:56 1998
@@ -1827,8 +1827,8 @@
 
 void amiga_floppy_setup (char *str, int *ints)
 {
-printk ("amiflop: Setting default df0 to %x\n", ints[1]);
-fd_def_df0 = ints[1];
+	printk ("amiflop: Setting default df0 to %x\n", ints[1]);
+	fd_def_df0 = ints[1];
 }
 
 static struct file_operations floppy_fops = {
@@ -1915,6 +1915,7 @@
   timer_table[FLOPPY_TIMER].fn = NULL;
   timer_active &= ~(1 << FLOPPY_TIMER);
 
+#if 0
   if (fd_def_df0==0) {
     if ((boot_info.bi_amiga.model == AMI_3000) ||
         (boot_info.bi_amiga.model == AMI_3000T) ||
@@ -1924,6 +1925,9 @@
     else
       fd_def_df0=FD_DD_3;
   }
+#else
+  fd_def_df0 = FD_DD_3;
+#endif
 
   probe_drives();
 
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/drivers/char/fbmem.c linux20/drivers/char/fbmem.c
--- /data/tmp/linux-2.0.33/drivers/char/fbmem.c	Wed Dec 17 10:02:26 1997
+++ linux20/drivers/char/fbmem.c	Fri Mar 13 18:58:12 1998
@@ -260,18 +260,6 @@
 		/* Use no-cache mode, serialized */
                 pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S;
         }
-
-	fb->fb_get_fix(&fix, PROC_CONSOLE(), fbidx);
-	if ((vma->vm_end - vma->vm_start + vma->vm_offset) > fix.smem_len)
-		return -EINVAL;
-	vma->vm_offset += (unsigned long)fix.smem_start;
-	if (vma->vm_offset & ~PAGE_MASK)
-		return -ENXIO;
-	if (CPU_IS_040_OR_060) {
-		pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
-		/* Use write-through cache mode */
-		pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S;
-	}
 	if (remap_page_range(vma->vm_start, vma->vm_offset,
 			     vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/drivers/net/apne.c linux20/drivers/net/apne.c
--- /data/tmp/linux-2.0.33/drivers/net/apne.c	Wed Dec 17 16:23:26 1997
+++ linux20/drivers/net/apne.c	Thu Mar 19 18:59:47 1998
@@ -123,28 +123,6 @@
 
 #define WORDSWAP(a) ( (((a)>>8)&0xff) | ((a)<<8) )
 
-/* word io */
-
-static inline unsigned short get_user_word_io(const short * addr)
-{
-	register unsigned short _v;
-
-	__asm__ __volatile__ ("movew %1,%0":"=dm" (_v):"m" (*addr));
-	return _v;
-}
-#define inw_p(addr) get_user_word_io((short *)(addr))
-#define inw(addr) get_user_word_io((short *)(addr))
-
-static inline void put_user_word_io(short val,short *addr)
-{
-	__asm__ __volatile__ ("movew %0,%1"
-			      : /* no outputs */
-			      :"idm" (val),"m" (*addr)
-			      : "memory");
-}
-#define outw_p(x,addr) put_user_word_io((x),(short *)(addr))
-#define outw(x,addr) put_user_word_io((x),(short *)(addr))
-
 static const char *version =
     "apne.c:v1.0 11/29/97 Alain Malek (Alain.Malek@cryogen.com)\n";
 
@@ -1357,11 +1335,12 @@
 
 static int init_pcmcia(void)
 {
-	unsigned char config;
+	u_char config;
 #ifndef MANUAL_CONFIG
-	unsigned char tuple[32];
+	u_char tuple[32];
+	int offset_len;
 #endif
-	unsigned short offset;
+	u_long offset;
 
 	pcmcia_reset();
 	pcmcia_program_voltage(PCMCIA_0V);
@@ -1384,7 +1363,11 @@
 	if (pcmcia_copy_tuple(CISTPL_CONFIG, tuple, 32) < 6)
 		return 0;
 
-	offset = (tuple[5] << 8) | tuple[4];
+	offset_len = (tuple[2] & 0x3) + 1;
+	offset = 0;
+	while(offset_len--) {
+		offset = (offset << 8) | tuple[4+offset_len];
+	}
 #endif
 
 	outb(config, GAYLE_ATTRIBUTE+offset);
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/include/asm-m68k/amigayle.h linux20/include/asm-m68k/amigayle.h
--- /data/tmp/linux-2.0.33/include/asm-m68k/amigayle.h	Wed Dec 17 12:08:11 1997
+++ linux20/include/asm-m68k/amigayle.h	Thu Mar 19 18:59:47 1998
@@ -19,6 +19,7 @@
 #define _ASMm68k_AMIGAYLE_H_
 
 #include <asm/amigahw.h>
+#include <asm/io.h>
 
 /* memory layout */
 
@@ -59,11 +60,11 @@
 
 #define gayle_attribute ((volatile u_char *)(GAYLE_ATTRIBUTE))
 
-#define gayle_inb(a) (*(volatile u_char *)(GAYLE_IO+(a)+(((a)&1)*GAYLE_ODD)))
-#define gayle_outb(v,a) ((*(volatile u_char *)(GAYLE_IO+(a)+(((a)&1)*GAYLE_ODD))) = (v))
+#define gayle_inb(a) readb( GAYLE_IO+(a)+(((a)&1)*GAYLE_ODD) )
+#define gayle_outb(v,a) writeb( v, GAYLE_IO+(a)+(((a)&1)*GAYLE_ODD) )
 
-#define gayle_inw(a) (*(volatile u_short *)(GAYLE_IO+(a)))
-#define gayle_outw(v,a) ((*(volatile u_short *)(GAYLE_IO+(a))) = (v))
+#define gayle_inw(a) readw( GAYLE_IO+(a) )
+#define gayle_outw(v,a) writew( v, GAYLE_IO+(a) )
 
 /* GAYLE_CARDSTATUS bit def */
 
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/include/asm-m68k/pgtable.h linux20/include/asm-m68k/pgtable.h
--- /data/tmp/linux-2.0.33/include/asm-m68k/pgtable.h	Wed Oct  9 23:00:56 1996
+++ linux20/include/asm-m68k/pgtable.h	Thu Mar 19 19:05:57 1998
@@ -130,6 +130,8 @@
 #define _PAGE_RONLY	0x004
 #define _PAGE_ACCESSED	0x008
 #define _PAGE_DIRTY	0x010
+#define _PAGE_SUPER	0x080	/* 68040 supervisor only */
+#define _PAGE_FAKE_SUPER 0x200	/* fake supervisor only on 680[23]0 */
 #define _PAGE_GLOBAL040	0x400	/* 68040 global bit, used for kva descs */
 #define _PAGE_COW	0x800	/* implemented in software */
 #define _PAGE_NOCACHE030 0x040	/* 68030 no-cache mode */
@@ -278,7 +280,7 @@
 { return PTOV(pgd_val(pgd) & _TABLE_MASK); }
 
 extern inline int pte_none(pte_t pte)		{ return !pte_val(pte); }
-extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_PRESENT; }
+extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & (_PAGE_PRESENT | _PAGE_FAKE_SUPER); }
 extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
 
 extern inline int pmd_none2(pmd_t *pmd)		{ return !pmd_val(*pmd); }
@@ -726,6 +728,8 @@
  * I don't know what is going on here, but since these were changed,
  * swapping hasn't been working on the 68040.
  */
+/* With the new handling of PAGE_NONE the old definitions definitely
+   don't work any more.  */
 
 #define SWP_TYPE(entry)  (((entry) >> 2) & 0x7f)
 #if 0
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/include/asm-m68k/serial.h linux20/include/asm-m68k/serial.h
--- /data/tmp/linux-2.0.33/include/asm-m68k/serial.h	Fri Sep 19 11:15:44 1997
+++ linux20/include/asm-m68k/serial.h	Thu Mar  5 12:23:39 1998
@@ -354,7 +354,7 @@
 	info->icount.cts++;
 	wake_up_interruptible(&info->delta_msr_wait);
 	
-	if ((info->flags & ASYNC_CTS_FLOW) && info->tty)
+	if ((info->flags & ASYNC_CTS_FLOW) && info->tty) {
 		if (info->tty->hw_stopped) {
 			if (cts) {
 #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
@@ -371,7 +371,7 @@
 				rs_stop( info->tty );
 			}
 		}
-		
+	}
 }
 
 
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/include/asm-m68k/zorro.h linux20/include/asm-m68k/zorro.h
--- /data/tmp/linux-2.0.33/include/asm-m68k/zorro.h	Sun Oct 26 18:12:52 1997
+++ linux20/include/asm-m68k/zorro.h	Wed Mar 18 10:49:31 1998
@@ -428,7 +428,8 @@
 #define PROD_APOLLO_TURBO      (0x23)	/* Apollo Turbo Board */
 
 #define MANUF_PETSOFF          (0x38A5)	/* Petsoff LP */
-#define PROD_DELFINA           (0x00)	/* Delfina DSP */
+#define PROD_DELFINA           (0x00)	/* Delfina Sound Board */
+#define PROD_DELFINA_LITE      (0x01)	/* Delfina Lite Sound Board */
 
 #define MANUF_UWE_GERLACH      (0x3FF7)	/* Uwe Gerlach */
 #define PROD_UG_RAM_ROM        (0xd4)	/* RAM/ROM */
diff -urN -X /home/jes/exclude-linux /data/tmp/linux-2.0.33/include/linux/fb.h linux20/include/linux/fb.h
--- /data/tmp/linux-2.0.33/include/linux/fb.h	Wed Dec 17 10:02:39 1997
+++ linux20/include/linux/fb.h	Mon Mar 16 11:16:45 1998
@@ -42,7 +42,8 @@
         __u32 line_length;		/* length of a line in bytes    */
 	unsigned char *mmio_start;	/* Start of Memory Mapped I/O   */
 	__u32 mmio_len;			/* Length of Memory Mapped I/O  */
-	__u16 reserved[5];		/* Reserved for future compatibility */
+	__u32 accel;			/* Type of acceleration available */
+	__u16 reserved[3];		/* Reserved for future compatibility */
 };
 
 struct fb_bitfield {
@@ -65,9 +66,10 @@
 #define FB_ACCEL_NONE		0	/* no hardware accelerator	*/
 #define FB_ACCEL_ATARIBLITT	1	/* Atari Blitter		*/
 #define FB_ACCEL_AMIGABLITT	2	/* Amiga Blitter                */
-#define FB_ACCEL_CYBERVISION	3	/* Cybervision64 (S3 Trio64)    */
-#define FB_ACCEL_RETINAZ3	4	/* RetinaZ3 (NCR77C32BLT)       */
-#define FB_ACCEL_CYBERVISION3D	5	/* Cybervision64/3D (S3 ViRGE)  */
+#define FB_ACCEL_S3TRIO64	3	/* Cybervision64 (S3 Trio64)    */
+#define FB_ACCEL_NCR77C32BLT	4	/* RetinaZ3 (NCR77C32BLT)       */
+#define FB_ACCEL_S3VIRGE	5	/* Cybervision64/3D (S3 ViRGE)  */
+#define FB_ACCEL_CLGEN		6	/* CirrusLogic BitBLT boards	*/
 
 #define FB_SYNC_HOR_HIGH_ACT	1	/* horizontal sync high active	*/
 #define FB_SYNC_VERT_HIGH_ACT	2	/* vertical sync high active	*/
@@ -85,7 +87,7 @@
 #define FB_VMODE_YWRAP		256	/* ywrap instead of panning     */
 #define FB_VMODE_SMOOTH_XPAN	512	/* smooth xpan possible (internally used) */
 #define FB_VMODE_CONUPDATE	512	/* don't update x/yoffset	*/
-#define FB_VMODE_CLOCK_HALVE 1024 /* hint for VGA driver: halve dot clock */
+#define FB_VMODE_CLOCK_HALVE	1024	/* hint for VGA driver: halve dot clock */
 
 struct fb_var_screeninfo {
 	__u32 xres;			/* visible resolution		*/
@@ -96,7 +98,7 @@
 	__u32 yoffset;			/* resolution			*/
 
 	__u32 bits_per_pixel;		/* guess what 			*/
-	__u32 grayscale;			/* != 0 Graylevels instead of colors */
+	__u32 grayscale;		/* != 0 Graylevels instead of colors */
 
 	struct fb_bitfield red;		/* bitfield in fb mem if true color, */
 	struct fb_bitfield green;	/* else only length is significant */
@@ -113,13 +115,13 @@
 	__u32 accel;			/* see FB_ACCEL_*		*/
 
 	/* Timing: All values in pixclocks, except pixclock (of course) */
-	__u32 pixclock;		/* pixel clock in ps (pico seconds) */
-	__u32 left_margin;	/* time from sync to picture	*/
-	__u32 right_margin;	/* time from picture to sync	*/
-	__u32 upper_margin;	/* time from sync to picture	*/
+	__u32 pixclock;			/* pixel clock in ps (pico seconds) */
+	__u32 left_margin;		/* time from sync to picture	*/
+	__u32 right_margin;		/* time from picture to sync	*/
+	__u32 upper_margin;		/* time from sync to picture	*/
 	__u32 lower_margin;
-	__u32 hsync_len;	/* length of horizontal sync	*/
-	__u32 vsync_len;	/* length of vertical sync	*/
+	__u32 hsync_len;		/* length of horizontal sync	*/
+	__u32 vsync_len;		/* length of vertical sync	*/
 	__u32 sync;			/* see FB_SYNC_*		*/
 	__u32 vmode;			/* see FB_VMODE_*		*/
 	__u32 reserved[6];		/* Reserved for future compatibility */
@@ -128,10 +130,10 @@
 struct fb_cmap {
 	__u32 start;			/* First entry	*/
 	__u32 len;			/* Number of entries */
-	__u16 *red;		/* Red values	*/
+	__u16 *red;			/* Red values	*/
 	__u16 *green;
 	__u16 *blue;
-	__u16 *transp;		/* transparency, can be NULL */
+	__u16 *transp;			/* transparency, can be NULL */
 };
 
 struct fb_monitorspec {
@@ -149,9 +151,9 @@
 	/* get non settable parameters	*/
 	int (*fb_get_fix) (struct fb_fix_screeninfo *, int, int); 
 	/* get settable parameters	*/
-	int (*fb_get_var) (struct fb_var_screeninfo *, int, int);		
+	int (*fb_get_var) (struct fb_var_screeninfo *, int, int);
 	/* set settable parameters	*/
-	int (*fb_set_var) (struct fb_var_screeninfo *, int, int);		
+	int (*fb_set_var) (struct fb_var_screeninfo *, int, int);
 	/* get colormap			*/
 	int (*fb_get_cmap) (struct fb_cmap *, int, int, int);
 	/* set colormap			*/
