]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.129pre1 2.1.129pre1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:17:15 +0000 (15:17 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:17:15 +0000 (15:17 -0500)
85 files changed:
Documentation/Configure.help
Documentation/networking/ltpc.txt
Documentation/sysctl/README
Documentation/sysctl/fs.txt [new file with mode: 0644]
Documentation/sysctl/kernel.txt
Documentation/sysctl/vm.txt
Makefile
arch/i386/kernel/i386_ksyms.c
drivers/block/Config.in
drivers/block/ide-probe.c
drivers/block/via82c586.c
drivers/cdrom/cdrom.c
drivers/char/random.c
drivers/misc/parport_arc.c
drivers/misc/parport_ax.c
drivers/misc/parport_init.c
drivers/misc/parport_pc.c
drivers/net/3c59x.c
drivers/net/Space.c
drivers/net/hamradio/mkiss.c
drivers/net/hostess_sv11.c
drivers/net/ltpc.c
drivers/net/shaper.c
drivers/net/syncppp.c
drivers/scsi/NCR5380.c
drivers/scsi/scsi.c
drivers/scsi/scsi_proc.c
drivers/sound/ad1848.c
drivers/sound/soundcard.c
drivers/video/Config.in
drivers/video/Makefile
drivers/video/amifb.c
drivers/video/atyfb.c
drivers/video/chipsfb.c
drivers/video/clgenfb.c
drivers/video/controlfb.c
drivers/video/cvppcfb.c [new file with mode: 0644]
drivers/video/cyberfb.c
drivers/video/fbcon-iplan2p2.c
drivers/video/fbcon-iplan2p4.c
drivers/video/fbcon-iplan2p8.c
drivers/video/fbcon-mfb.c
drivers/video/fbgen.c
drivers/video/fbmem.c
drivers/video/fonts.c
drivers/video/imsttfb.c
drivers/video/matroxfb.c [new file with mode: 0644]
drivers/video/retz3fb.c
drivers/video/retz3fb.h
drivers/video/sbusfb.c
drivers/video/virgefb.c
fs/attr.c
fs/autofs/root.c
fs/block_dev.c
fs/buffer.c
fs/exec.c
fs/fcntl.c
fs/fifo.c
fs/file_table.c
fs/ioctl.c
fs/locks.c
fs/msdos/namei.c
fs/namei.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/read.c
fs/nfs/write.c
fs/open.c
fs/pipe.c
fs/read_write.c
fs/select.c
fs/stat.c
fs/super.c
include/linux/fb.h
include/linux/mm.h
include/linux/nfs_fs.h
include/linux/proc_fs.h
include/video/fbcon.h
init/main.c
net/appletalk/aarp.c
net/appletalk/ddp.c
net/ax25/ax25_ip.c
net/ipx/af_ipx.c
net/netsyms.c

index c449ef5b3bedca0cf0c0fe832fb142458f2f07bb..abec1923c375f949a763fbc3a339d8fcbcb1ba24 100644 (file)
@@ -1759,6 +1759,58 @@ CONFIG_FB_COMPAT_XPMAC
   which includes a server that supports the frame buffer device
   directly (XF68_FBDev).
 
+Matrox unified accelerated driver
+CONFIG_FB_MATROX
+  Say Y here if you have Matrox Millenium, Matrox Millenium II, Matrox
+  Mystique, Matrox Mystique 220 or Matrox Productiva G100 in your box.
+  At this time,  G100 support  is untested and  G200 support  does not
+  exist at all.  If you want,  you can select  M, in this  case module
+  matroxfb.o will be created.
+  You can pass parameters into driver if it is compiled into kernel by 
+  specifying "video=matrox:XXX", where meaning of XXX you can found at 
+  the end of main source file  (drivers/video/matroxfb.c) at boottime.
+  Same  parameters can  be passed  into insmod  if driver  is used  as 
+  module.
+
+Matrox Millenium support
+CONFIG_FB_MATROX_MILLENIUM
+  Say Y here if you have Matrox Millenium or Matrox Millenium II in the
+  box. If you  select "Advanced  lowlevel driver  options", you  should 
+  check 4 bpp packed pixel, 8 bpp packed pixel, 16 bpp packed pixel, 24
+  bpp  packed pixel  and 32  bpp packed  pixel. You  can also  use font 
+  widths different from 8.
+
+Matrox Mystique support
+CONFIG_FB_MATROX_MYSTIQUE
+  Say Y here if you have  Matrox Mystique or Matrox Mystique 220 in the 
+  box.  If you  select  "Advanced lowlevel driver options",  you should 
+  check  8 bpp packed pixel,  16 bpp packed pixel,  24 bpp packed pixel
+  and  32 bpp  packed pixel.  You can  also use  font widths  different 
+  from 8.
+
+Matrox G100 support
+CONFIG_FB_MATROX_G100
+  Say Y here  if you have  Matrox Productiva G100  in the box. But THIS 
+  DRIVER  IS NOT  TESTED BECAUSE  OF I  HAVE NO  G100  board  and  G100 
+  technical sheets  are top secret at this time.  But driver should not 
+  cause any damage to your computer.
+  If you select  "Advanced lowlevel  driver options",  you should check
+  8 bpp  packed pixel,  16 bpp  packed pixel,  24 bpp  packed pixel and 
+  32 bpp packed pixel. You can also use font widths different from 8.
+
+Matrox unified driver multihead support
+CONFIG_FB_MATROX_MULTIHEAD
+  Say Y  here if you  have more  than one (supported) Matrox  device in 
+  computer  and you  want to  use all  of them.  If you  have only  one 
+  device,  you should say N because of driver compiled with Y is larger 
+  and a bit slower, especially on ia32 (ix86).
+  If you compiled  driver as module,  you are VERY  interested in speed 
+  and  you can  use 40KB  of memory  per each  Matrox  device,  you can 
+  compile driver  without multihead  support and  instead of  it insmod 
+  more module instances. In this case, you MUST specify parameter dev=N 
+  to insmod, where N is sequential number of Matrox device  (0 = first, 
+  1 = second and so on).
+  
 MDA text console (dual-headed)
 CONFIG_MDA_CONSOLE
   Say Y here if you have an old MDA or monochrome Hercules graphics
@@ -3740,6 +3792,13 @@ CONFIG_SCSI_FUTURE_DOMAIN
   The module will be called fdomain.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+Future Domain MCS-600/700 SCSI support
+CONFIG_SCSI_FD_MCS
+ This is support for Future Domain MCS 600/700 MCA SCSI adapters. Some
+ PS/2s are also equipped with IBM Fast SCSI Adapter/A which is an OEM
+ of the MCS 700. This driver also supports Reply SB16/SCSI card (the 
+ SCSI part). It supports multiple adapters in the same system.
+
 Generic NCR5380/53c400 SCSI support
 CONFIG_SCSI_GENERIC_NCR5380
   This is the generic NCR family of SCSI controllers, not to be
@@ -5013,9 +5072,9 @@ CONFIG_NET_PROFILE
 
 Comtrol Hostess SV-11 support
 CONFIG_HOSTESS_SV11
-  This is a network card for high speed synchronous serial links. It
-  is commonly used to connect to Cisco equipment over HSSI links. At
-  this point, the driver can only be compiled as a module.
+  This is a network card for low speed synchronous serial links, at
+  up to 256Kbits. It supports both PPP and Cisco HDLC
+  At this point, the driver can only be compiled as a module.
 
 WAN Drivers
 CONFIG_WAN_DRIVERS
@@ -5576,7 +5635,7 @@ CONFIG_SEEQ8005
   is for you, read the Ethernet-HOWTO, available via FTP (user:
   anonymous) from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
 
-AT1700 support
+AT1700/1720 support
 CONFIG_AT1700
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
index 50a39ea881f3f75687da6827577d4399441a3072..ed9983f0786b215d5aee043534a35626efd59a6d 100644 (file)
@@ -6,18 +6,37 @@ There are a number of different LocalTalk cards for the PC; this
 driver applies only to the one with the 65c02 processor chip on it.
 
 To include it in the kernel, select the CONFIG_LTPC switch in the
-configuration dialog; at this time (kernel 2.1.23) compiling it as
-a module will not work.
+configuration dialog.  You can also compile it as a module.
+
+While the driver will attempt to autoprobe the I/O port address, IRQ
+line, and DMA channel of the card, this does not always work.  For
+this reason, you should be prepared to supply these parameters
+yourself.  (see "Card Configuration" below for how to determine or
+change the settings on your card)
+
+When the driver is compiled into the kernel, you can add a line such
+as the following to your /etc/lilo.conf:
+
+ append="ltpc=0x240,9,1"
+
+where the parameters (in order) are the port address, IRQ, and DMA
+channel.  The second and third values can be omitted, in which case
+the driver will try to determine them itself.
+
+If you load the driver as a module, you can pass the parameters "io=",
+"irq=", and "dma=" on the command line with insmod or modprobe, or add
+them as options in /etc/conf.modules:
+
+ alias lt0 ltpc # autoload the module when the interface is configured
+ options ltpc io=0x240 irq=9 dma=1
 
 Before starting up the netatalk demons (perhaps in rc.local), you
 need to add a line such as:
 
-/sbin/ifconfig ltalk0 127.0.0.42
+ /sbin/ifconfig lt0 127.0.0.42
 
-
-The driver will autoprobe, and you should see a message like:
-"LocalTalk card found at 240, IR9, DMA1."
-at bootup.
+The address is unimportant - however, the card needs to be configured
+with ifconfig so that Netatalk can find it.
 
 The appropriate netatalk configuration depends on whether you are
 attached to a network that includes AppleTalk routers or not.  If,
@@ -25,22 +44,22 @@ like me, you are simply connecting to your home Macintoshes and
 printers, you need to set up netatalk to "seed".  The way I do this
 is to have the lines
 
-dummy -seed -phase 2 -net 2000 -addr 2000.26 -zone "1033"
-ltalk0 -seed -phase 1 -net 1033 -addr 1033.27 -zone "1033"
+ dummy -seed -phase 2 -net 2000 -addr 2000.26 -zone "1033"
+ lt0 -seed -phase 1 -net 1033 -addr 1033.27 -zone "1033"
 
 in my atalkd.conf.  What is going on here is that I need to fool
 netatalk into thinking that there are two AppleTalk interfaces
-present -- otherwise it refuses to seed.  This is a hack, and a
-more permanent solution would be to alter the netatalk code.
-Note that the dummy driver needs to accept multicasts also -- earlier
-versions of dummy.c may need to be patched.  
-
+present; otherwise, it refuses to seed.  This is a hack, and a more
+permanent solution would be to alter the netatalk code.  Also, make
+sure you have the correct name for the dummy interface - If it's
+compiled as a module, you will need to refer to it as "dummy0" or some
+such.
 
 If you are attached to an extended AppleTalk network, with routers on
 it, then you don't need to fool around with this -- the appropriate
 line in atalkd.conf is
 
-ltalk0 -phase 1
+ lt0 -phase 1
 
 --------------------------------------
 
@@ -74,19 +93,32 @@ board.  Set the switches so as not to conflict with other hardware.
 --------------------------------------
 
 IP:
-       Many people are interested in this driver in order to use IP
-when LocalTalk, but no Ethernet, is available.  While the code to do
-this is not strictly speaking part of this driver, an experimental 
-version is available which seems to work under kernel 2.0.xx.  It is
-not yet functional in the 2.1.xx kernels.
+
+Yes, it is possible to do IP over LocalTalk.  However, you can't just
+treat the LocalTalk device like an ordinary Ethernet device, even if
+that's what it looks like to Netatalk.
+
+Instead, you follow the same procedure as for doing IP in EtherTalk.
+See Documentation/networking/ipddp.txt for more information about the
+kernel driver and userspace tools needed.
 
 --------------------------------------
 
 BUGS:
 
-2.0.xx:
+IRQ autoprobing often doesn't work on a cold boot.  To get around
+this, either compile the driver as a module, or pass the parameters
+for the card to the kernel as described above.
+
+Also, as usual, autoprobing is not recommended when you use the driver
+as a module. (though it usually works at boot time, at least)
+
+Polled mode is *really* slow sometimes, but this seems to depend on
+the configuration of the network.
 
-2.1.xx:        The module support doesn't work yet.
+It may theoretically be possible to use two LTPC cards in the same
+machine, but this is unsupported, so if you really want to do this,
+you'll probably have to hack the initialization code a bit.
 
 ______________________________________
 
@@ -96,3 +128,4 @@ work, and to Denis Hainsworth for doing the bleeding-edge testing.
 
 -- Bradford Johnson <bradford@math.umn.edu>
 
+-- Updated 11/09/1998 by David Huggins-Daines <dhd@debian.org>
index ca08da9dae9192e034f252002a65f94d16e49032..11d3f3f0bd877251f768a49043bbb6d8b22e3876 100644 (file)
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/*/*                version 0.1
+Documentation for /proc/sys/           kernel version 2.1.128
        (c) 1998, Rik van Riel <H.H.vanRiel@phys.uu.nl>
 
 'Why', I hear you ask, 'would anyone even _want_ documentation
@@ -12,6 +12,9 @@ have the time or knowledge to read the source code.
 Furthermore, the programmers who built sysctl have built it to
 be actually used, not just for the fun of programming it :-)
 
+If you prefer HTML, feel free to visit the Linux-MM homepage
+<http://www.phys.uu.nl/~riel/mm-patch/>...
+
 ==============================================================
 
 Legal blurb:
@@ -58,9 +61,9 @@ The subdirs are about:
 debug/         <empty>
 dev/           device specific information (eg dev/cdrom/info)
 fs/            specific filesystems
+               filehandle, inode, dentry and quota tuning
                binfmt_misc <linux/Documentation/binfmt_misc.txt>
 kernel/                global kernel info / tuning
-               open file / inode tuning
                miscellaneous stuff
 net/           networking stuff, for documentation look in:
                <linux/Documentation/networking/>
diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt
new file mode 100644 (file)
index 0000000..425e23f
--- /dev/null
@@ -0,0 +1,116 @@
+Documentation for /proc/sys/fs/*       kernel version 2.1.128
+       (c) 1998, Rik van Riel <H.H.vanRiel@phys.uu.nl>
+
+For general info and legal blurb, please look in README.
+
+==============================================================
+
+This file contains documentation for the sysctl files in
+/proc/sys/fs/ and is valid for Linux kernel version 2.1.
+
+The files in this directory can be used to tune and monitor
+miscellaneous and general things in the operation of the Linux
+kernel. Since some of the files _can_ be used to screw up your
+system, it is advisable to read both documentation and source
+before actually making adjustments.
+
+Currently, these files are in /proc/sys/fs:
+- dentry-state
+- dquot-max
+- dquot-nr
+- file-max
+- file-nr
+- inode-max
+- inode-nr
+- inode-state
+
+Documentation for the files in /proc/sys/fs/binfmt_misc is
+in Documentation/binfmt_misc.txt.
+
+==============================================================
+
+dentry-state:
+
+From linux/fs/dentry.c:
+--------------------------------------------------------------
+struct {
+        int nr_dentry;
+        int nr_unused;
+        int age_limit;         /* age in seconds */
+        int want_pages;        /* pages requested by system */
+        int dummy[2];
+} dentry_stat = {0, 0, 45, 0,};
+-------------------------------------------------------------- 
+
+Dentries are dynamically allocated and deallocated, and
+nr_dentry seems to be 0 all the time. Hence it's safe to
+assume that only nr_unused, age_limit and want_pages are
+used. Nr_unused seems to be exactly what its name says.
+Age_limit is the age in seconds after which dcache entries
+can be reclaimed when memory is short and want_pages is
+nonzero when shrink_dcache_pages() has been called and the
+dcache isn't pruned yet.
+
+==============================================================
+
+dquot-max & dquot-nr:
+
+The file dquot-max shows the maximum number of cached disk
+quota entries.
+
+The file dquot-nr shows the number of allocated disk quota
+entries and the number of free disk quota entries.
+
+If the number of free cached disk quotas is very low and
+you have some awesome number of simultaneous system users,
+you might want to raise the limit.
+
+==============================================================
+
+file-max & file-nr:
+
+The kernel allocates file handles dynamically, but as yet it
+doesn't free them again.
+
+The value in file-max denotes the maximum number of file-
+handles that the Linux kernel will allocate. When you get lots
+of error messages about running out of file handles, you might
+want to increase this limit.
+
+The three values in file-nr denote the number of allocated
+file handles, the number of used file handles and the maximum
+number of file handles. When the allocated file handles come
+close to the maximum, but the number of actually used ones is
+far behind, you've encountered a peak in your usage of file
+handles and you don't need to increase the maximum.
+
+==============================================================
+
+inode-max, inode-nr & inode-state:
+
+As with file handles, the kernel allocates the inode structures
+dynamically, but can't free them yet.
+
+The value in inode-max denotes the maximum number of inode
+handlers. This value should be 3-4 times larger than the value
+in file-max, since stdin, stdout and network sockets also
+need an inode struct to handle them. When you regularly run
+out of inodes, you need to increase this value.
+
+The file inode-nr contains the first two items from
+inode-state, so we'll skip to that file...
+
+Inode-state contains three actual numbers and four dummies.
+The actual numbers are, in order of appearance, nr_inodes,
+nr_free_inodes and preshrink.
+
+Nr_inodes stands for the number of inodes the system has
+allocated, this can be slightly more than inode-max because
+Linux allocates them one pageful at a time.
+
+Nr_free_inodes represents the number of free inodes (?) and
+preshrink is nonzero when the nr_inodes > inode-max and the
+system needs to prune the inode list instead of allocating
+more.
+
+
index d29c4c66f03cdfe84424b67a7dced3ed866ee6bb..c47f7e1c292c458342a993a79e9fcf0d3e6e289e 100644 (file)
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/kernel/*   version 0.1
+Documentation for /proc/sys/kernel/*   kernel version 2.1.128
        (c) 1998, Rik van Riel <H.H.vanRiel@phys.uu.nl>
 
 For general info and legal blurb, please look in README.
@@ -14,26 +14,27 @@ kernel. Since some of the files _can_ be used to screw up your
 system, it is advisable to read both documentation and source
 before actually making adjustments.
 
-Currently, these files are in /proc/sys/kernel:
+Currently, these files might (depending on your configuration)
+show up in /proc/sys/kernel:
 - acct
 - ctrl-alt-del
 - dentry-state
 - domainname
-- file-max
-- file-nr
 - hostname
-- inode-max
-- inode-nr
-- inode-state
+- htab-reclaim                [ PPC only ]
+- java-appletviewer           [ binfmt_java, obsolete ]
+- java-interpreter            [ binfmt_java, obsolete ]
 - modprobe                    ==> Documentation/kmod.txt
 - osrelease
 - ostype
 - panic
+- powersave-nap               [ PPC only ]
 - printk
 - real-root-dev               ==> Documentation/initrd.txt
-- reboot-cmd                  ==> SPARC specific
-- securelevel
+- reboot-cmd                  [ SPARC only ]
+- sg-big-buff                 [ generic SCSI device (sg) ]
 - version
+- zero-paged                  [ PPC only ]
 
 ==============================================================
 
@@ -69,30 +70,6 @@ to decide what to do with it.
 
 ==============================================================
 
-dentry-state:
-
-From linux/fs/dentry.c:
---------------------------------------------------------------
-struct {
-        int nr_dentry;
-        int nr_unused;
-        int age_limit;         /* age in seconds */
-        int want_pages;        /* pages requested by system */
-        int dummy[2];
-} dentry_stat = {0, 0, 45, 0,};
--------------------------------------------------------------- 
-
-Dentries are dynamically allocated and deallocated, and
-nr_dentry seems to be 0 all the time. Hence it's safe to
-assume that only nr_unused, age_limit and want_pages are
-used. Nr_unused seems to be exactly what its name says.
-Age_limit is the age in seconds after which dcache entries
-can be reclaimed when memory is short and want_pages is
-nonzero when shrink_dcache_pages() has been called and the
-dcache isn't pruned yet.
-
-==============================================================
-
 domainname & hostname:
 
 These files can be controlled to set the domainname and
@@ -104,52 +81,12 @@ would suffice to set your hostname and domainname.
 
 ==============================================================
 
-file-max & file-nr:
-
-The kernel allocates file handles dynamically, but as yet it
-doesn't free them again.
-
-The value in file-max denotes the maximum number of file-
-handles that the Linux kernel will allocate. When you get lots
-of error messages about running out of file handles, you might
-want to increase this limit.
-
-The three values in file-nr denote the number of allocated
-file handles, the number of used file handles and the maximum
-number of file handles. When the allocated file handles come
-close to the maximum, but the number of actually used ones is
-far behind, you've encountered a peak in your usage of file
-handles and you don't need to increase the maximum.
-
-==============================================================
-
-inode-max, inode-nr & inode-state:
-
-As with file handles, the kernel allocates the inode structures
-dynamically, but can't free them yet.
-
-The value in inode-max denotes the maximum number of inode
-handlers. This value should be 3-4 times larger than the value
-in file-max, since stdin, stdout and network sockets also
-need an inode struct to handle them. When you regularly run
-out of inodes, you need to increase this value.
-
-The file inode-nr contains the first two items from
-inode-state, so we'll skip to that file...
-
-Inode-state contains three actual numbers and four dummies.
-The actual numbers are, in order of appearance, nr_inodes,
-nr_free_inodes and preshrink.
-
-Nr_inodes stands for the number of inodes the system has
-allocated, this can be slightly more than inode-max because
-Linux allocates them one pageful at a time.
-
-Nr_free_inodes represents the number of free inodes (?) and
-preshrink is nonzero when the nr_inodes > inode-max and the
-system needs to prune the inode list instead of allocating
-more.
+htab-reclaim: (PPC only)
 
+Setting this to a non-zero value, the PowerPC htab
+(see Documentation/powerpc/ppc_htab.txt) is pruned
+each time the system hits the idle loop.
 ==============================================================
 
 osrelease, ostype & version:
@@ -177,6 +114,13 @@ software watchdog, the recommended setting is 60.
 
 ==============================================================
 
+powersave-nap: (PPC only)
+
+If set, Linux-PPC will use the 'nap' mode of powersaving,
+otherwise the 'doze' mode will be used.
+
+==============================================================
+
 printk:
 
 The four values in printk denote: console_loglevel,
@@ -202,27 +146,30 @@ occur when the compiler changes. (???)
 
 ==============================================================
 
-securelevel:
+reboot-cmd: (Sparc only)
 
-When the value in this file is nonzero, root is prohibited
-from:
-- changing the immutable and append-only flags on files
-- changing sysctl things (limited ???)
+??? This seems to be a way to give an argument to the Sparc
+ROM/Flash boot loader. Maybe to tell it what to do after
+rebooting. ???
 
 ==============================================================
 
-real-root-dev: (CONFIG_INITRD only)
+sg-big-buff:
 
-This file is used to configure the real root device when using
-an initial ramdisk to configure the system before switching to
-the 'real' root device. See linux/Documentation/initrd.txt for
-more info.
+This file shows the size of the generic SCSI (sg) buffer.
+You can't tune it just yet, but you could change it on
+compile time by editing include/scsi/sg.h and changing
+the value of SG_BIG_BUFF.
 
-==============================================================
+There shouldn't be any reason to change this value. If
+you can come up with one, you probably know what you
+are doing anyway :)
 
-reboot-cmd: (Sparc only)
+==============================================================
 
-??? This seems to be a way to give an argument to the Sparc
-ROM/Flash boot loader. Maybe to tell it what to do after
-rebooting. ???
+zero-paged: (PPC only)
 
+When enabled (non-zero), Linux-PPC will pre-zero pages in
+the idle loop, possibly speeding up get_free_pages. Since
+this only affects what the idle loop is doing, you should
+enable this and see if anything changes.
index c49a2fe439a499a07f6faf37dfe8f152a78dc83d..359478216877bad4c43d9a5e6a6b610e1d136ee5 100644 (file)
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/vm/*       version 0.1
+Documentation for /proc/sys/vm/*       kernel version 2.1.128
        (c) 1998, Rik van Riel <H.H.vanRiel@phys.uu.nl>
 
 For general info and legal blurb, please look in README.
@@ -20,8 +20,8 @@ Currently, these files are in /proc/sys/vm:
 - kswapd
 - overcommit_memory
 - pagecache
+- pagetable_cache
 - swapctl
-- swapout_interval
 
 ==============================================================
 
@@ -56,7 +56,7 @@ union bdflush_param{
 } bdf_prm = {{40, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
 --------------------------------------------------------------
 
-The first parameter governs the maximum number of of dirty
+The first parameter governs the maximum number of dirty
 buffers in the buffer cache. Dirty means that the contents
 of the buffer still have to be written to disk (as opposed
 to a clean buffer, which can just be forgotten about).
@@ -101,8 +101,9 @@ The values are:
 min_percent    -- this is the minimum percentage of memory
                   that should be spent on buffer memory
 borrow_percent  -- when Linux is short on memory, and the
-                   buffer cache uses more memory, free pages
-                   are stolen from it
+                   buffer cache uses more memory than this,
+                   the MM subsystem will prune the buffercache
+                   more heavily than other memory
 max_percent     -- this is the maximum amount of memory that
                    can be used for buffer memory 
 
@@ -112,25 +113,17 @@ freepages:
 This file contains the values in the struct freepages. That
 struct contains three members: min, low and high.
 
-Although the goal of the Linux memory management subsystem
-is to avoid fragmentation and make large chunks of free
-memory (so that we can hand out DMA buffers and such), there
-still are some page-based limits in the system, mainly to
-make sure we don't waste too much memory trying to get large
-free area's.
-
 The meaning of the numbers is:
 
 freepages.min  When the number of free pages in the system
                reaches this number, only the kernel can
                allocate more memory.
-freepages.low  If memory is too fragmented, the swapout
-               daemon is started, except when the number
-               of free pages is larger than freepages.low.
-freepages.high The swapping daemon exits when memory is
-               sufficiently defragmented, when the number
-               of free pages reaches freepages.high or when
-               it has tried the maximum number of times. 
+freepages.low  If the number of free pages gets below this
+               point, the kernel starts swapping agressively.
+freepages.high The kernel tries to keep up to this amount of
+               memory free; if memory comes below this point,
+               the kernel gently starts swapping in the hopes
+               that it never has to do real agressive swapping.
 
 ==============================================================
 
@@ -210,7 +203,8 @@ pagecache:
 
 This file does exactly the same as buffermem, only this
 file controls the struct page_cache, and thus controls
-the amount of memory allowed for memory mapping of files.
+the amount of memory allowed for memory mapping and generic
+caching of files.
 
 You don't want the minimum level to be too low, otherwise
 your system might thrash when memory is tight or fragmentation
@@ -218,6 +212,23 @@ is high...
 
 ==============================================================
 
+pagetable_cache:
+
+The kernel keeps a number of page tables in a per-processor
+cache (this helps a lot on SMP systems). The cache size for
+each processor will be between the low and the high value.
+
+On a low-memory, single CPU system you can safely set these
+values to 0 so you don't waste the memory. On SMP systems it
+is used so that the system can do fast pagetable allocations
+without having to aquire the kernel memory lock.
+
+For large systems, the settings are probably OK. For normal
+systems they won't hurt a bit. For small systems (<16MB ram)
+it might be advantageous to set both values to 0.
+
+==============================================================
+
 swapctl:
 
 This file contains no less than 8 variables.
@@ -274,14 +285,4 @@ process pages in order to satisfy buffer memory demands, you
 might want to either increase sc_bufferout_weight, or decrease
 the value of sc_pageout_weight.
 
-==============================================================
-
-swapout_interval:
-
-The single value in this file controls the amount of time
-between successive wakeups of kswapd when nr_free_pages is
-between free_pages_low and free_pages_high. The default value
-of HZ/4 is usually right, but when kswapd can't keep up with
-the number of allocations in your system, you might want to
-decrease this number. 
 
index a2e14844698527b71939540e8e72e0b7b2f7c7f8..10d326e1626f764c96363b28dc9023af7189e3f3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 128
+SUBLEVEL = 129
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
index 6d11e2121d52dae809c4c69d00aab529fb4e5497..50bffc888aa07986afd6ebec081dffe741982105 100644 (file)
@@ -98,6 +98,9 @@ EXPORT_SYMBOL(mca_get_adapter_name);
 EXPORT_SYMBOL(mca_set_adapter_procfn);
 EXPORT_SYMBOL(mca_isenabled);
 EXPORT_SYMBOL(mca_isadapter);
+EXPORT_SYMBOL(mca_mark_as_used);
+EXPORT_SYMBOL(mca_mark_as_unused);
+EXPORT_SYMBOL(mca_find_unused_adapter);
 #endif
 
 #ifdef CONFIG_VT
index 65a9fdd19b9c03fd5c98535694a882a1c4cfc706..73a48f6a377d86098d5d5c525aee362ca858eee4 100644 (file)
@@ -77,7 +77,7 @@ else
   fi
 fi
 if [ "$CONFIG_MCA" = "y" ]; then
-  bool 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2
+  tristate 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2
 fi
 if [ "$CONFIG_ZORRO" = "y" ]; then
   tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM
@@ -94,7 +94,9 @@ fi
 comment 'Additional Block Devices'
 
 tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
-tristate 'Network block device support' CONFIG_BLK_DEV_NBD
+if [ "$CONFIG_NET" = "y" ]; then
+  tristate 'Network block device support' CONFIG_BLK_DEV_NBD
+fi
 bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
 if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
   tristate '   Linear (append) mode' CONFIG_MD_LINEAR
index 1d8b52bbba485ea28e8b1832594ca9cfc9cc6896..bcaa402216e55e01b816ca821838be72b2fe3930 100644 (file)
@@ -78,8 +78,18 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
        ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
 
        id->model[sizeof(id->model)-1] = '\0';  /* we depend on this a lot! */
-       drive->present = 1;
        printk("%s: %s, ", drive->name, id->model);
+       drive->present = 1;
+
+       /*
+        * Prevent long system lockup probing later for non-existant
+        * slave drive if the hwif is actually a Kodak CompactFlash card.
+        */
+       if (!strcmp(id->model, "KODAK ATA_FLASH")) {
+               ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit];
+               mate->present = 0;
+               mate->noprobe = 1;
+       }
 
        /*
         * Check for an ATAPI device
index d802f393f5613cd79eedd0b886c64a62210d10ee..28bf80c7628421d9426ded14add7ffc1e9a6077a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/via82C586.c     Version 0.01    Aug 16, 1998
+ * linux/drivers/block/via82c586.c     Version 0.01    Aug 16, 1998
  *
  *  Copyright (C) 1998 Michel Aubry
  *  Copyright (C) 1998 Andre Hedrick
index eaf67e4aacba5a8c67e440d1f0a5a80a7eb8a908..85ed482b87e9c390965a020645a8b3d4229506dc 100644 (file)
@@ -174,7 +174,9 @@ static int check_for_audio_disc(struct cdrom_device_info * cdi,
                         struct cdrom_device_ops * cdo);
 static void sanitize_format(union cdrom_addr *addr, 
                u_char * curr, u_char requested);
+#ifdef CONFIG_SYSCTL
 static void cdrom_sysctl_register(void);
+#endif /* CONFIG_SYSCTL */ 
 static struct cdrom_device_info *topCdromPtr = NULL;
 
 struct file_operations cdrom_fops =
index d08111080626ce2e4c2139a1538c66d9592ff24b..c980d5192573180ff2eae2fe26f9071fe9c7cbdb 100644 (file)
@@ -1407,19 +1407,15 @@ random_ioctl(struct inode * inode, struct file * file,
        
        switch (cmd) {
        case RNDGETENTCNT:
-               retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-               if (retval)
-                       return(retval);
                ent_count = random_state.entropy_count;
-               put_user(ent_count, (int *) arg);
+               if (put_user(ent_count, (int *) arg))
+                       return -EFAULT;
                return 0;
        case RNDADDTOENTCNT:
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               retval = verify_area(VERIFY_READ, (void *) arg, sizeof(int));
-               if (retval)
-                       return(retval);
-               get_user(ent_count, (int *) arg);
+               if (get_user(ent_count, (int *) arg))
+                       return -EFAULT;
                /*
                 * Add i to entropy_count, limiting the result to be
                 * between 0 and POOLBITS.
@@ -1446,16 +1442,14 @@ random_ioctl(struct inode * inode, struct file * file,
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
                p = (int *) arg;
-               retval = verify_area(VERIFY_WRITE, (void *) p, sizeof(int));
-               if (retval)
-                       return(retval);
                ent_count = random_state.entropy_count;
-               put_user(ent_count, p++);
-               retval = verify_area(VERIFY_WRITE, (void *) p, sizeof(int));
-               if (retval)
-                       return(retval);
-               get_user(size, p);
-               put_user(POOLWORDS, p++);
+               if (put_user(ent_count, p++))
+                       return -EFAULT;
+                       
+               if (get_user(size, p))
+                       return -EFAULT;
+               if (put_user(POOLWORDS, p++))
+                       return -EFAULT;
                if (size < 0)
                        return -EINVAL;
                if (size > POOLWORDS)
@@ -1467,16 +1461,12 @@ random_ioctl(struct inode * inode, struct file * file,
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
                p = (int *) arg;
-               retval = verify_area(VERIFY_READ, (void *) p, 2*sizeof(int));
-               if (retval)
-                       return(retval);
-               get_user(ent_count, p++);
+               if (get_user(ent_count, p++))
+                       return -EFAULT;
                if (ent_count < 0)
                        return -EINVAL;
-               get_user(size, p++);
-               retval = verify_area(VERIFY_READ, (void *) p, size);
-               if (retval)
-                       return retval;
+               if (get_user(size, p++))
+                       return -EFAULT;
                retval = random_write(file, (const char *) p,
                                      size, &file->f_pos);
                if (retval < 0)
index 37c1e4e9ae856aa79e448ff17804fc8ad3aad383..b231e9ee0f27aeeaa492d12154bbc070d8333195 100644 (file)
@@ -141,7 +141,9 @@ int parport_arc_init(void)
 
        printk(KERN_INFO "%s: Archimedes on-board port, using irq %d\n",
               p->irq);
+#ifdef CONFIG_PROC_FS
        parport_proc_register(p);
+#endif
        p->flags |= PARPORT_FLAG_COMA;
 
        if (parport_probe_hook)
index b32cac13b3278a76e58ddd2d5103c670409dcefb..bbd544640b5a547454c6272f38f760c06a35ac69 100644 (file)
@@ -585,7 +585,9 @@ init_one_port(struct linux_ebus_device *dev)
                printmode(ECPPS2);
        }
        printk("]\n");
+#ifdef CONFIG_PROC_FS
        parport_proc_register(p);
+#endif
        p->flags |= PARPORT_FLAG_COMA;
 
        p->ops->write_control(p, 0x0c);
@@ -628,7 +630,9 @@ cleanup_module(void)
                if (p->modes & PARPORT_MODE_PCSPP) { 
                        if (!(p->flags & PARPORT_FLAG_COMA)) 
                                parport_quiesce(p);
+#ifdef CONFIG_PROC_FS
                        parport_proc_unregister(p);
+#endif
                        parport_unregister_port(p);
                }
                p = tmp;
index 9b90bae8b39889d039635294e1a4759befe311d2..7fcefe436d690476b6f2332982598a6e4d2a5875 100644 (file)
@@ -98,13 +98,17 @@ __initfunc(void parport_setup(char *str, int *ints))
 #ifdef MODULE
 int init_module(void)
 {
+#ifdef CONFIG_PROC_FS
        (void)parport_proc_init();      /* We can go on without it. */
+#endif
        return 0;
 }
 
 void cleanup_module(void)
 {
+#ifdef CONFIG_PROC_FS
        parport_proc_cleanup();
+#endif
 }
 #else
 __initfunc(int parport_init(void))
@@ -115,7 +119,9 @@ __initfunc(int parport_init(void))
 #ifdef CONFIG_PNP_PARPORT
        parport_probe_hook = &parport_probe_one;
 #endif
+#ifdef CONFIG_PROC_FS
        parport_proc_init();
+#endif
 #ifdef CONFIG_PARPORT_PC
        parport_pc_init(io, irq, dma);
 #endif
@@ -139,8 +145,10 @@ EXPORT_SYMBOL(parport_unregister_device);
 EXPORT_SYMBOL(parport_enumerate);
 EXPORT_SYMBOL(parport_ieee1284_nibble_mode_ok);
 EXPORT_SYMBOL(parport_wait_peripheral);
+#ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(parport_proc_register);
 EXPORT_SYMBOL(parport_proc_unregister);
+#endif
 EXPORT_SYMBOL(parport_probe_hook);
 EXPORT_SYMBOL(parport_parse_irqs);
 
index fece4c0b2fcc836e6188d4c9a6dff092910e8bf8..c493246dd5e6c074d8a71e0050878b2be1a22f60 100644 (file)
@@ -755,9 +755,11 @@ static int probe_one_port(unsigned long int base, int irq, int dma)
        }
 #undef printmode
        printk("]\n");
+#ifdef CONFIG_PROC_FS
        if (probedirq != PARPORT_IRQ_NONE) 
                printk("%s: detected irq %d; use procfs to enable interrupt-driven operation.\n", p->name, probedirq);
        parport_proc_register(p);
+#endif
        p->flags |= PARPORT_FLAG_COMA;
 
        /* Done probing.  Now put the port into a sensible start-up state. */
@@ -821,7 +823,9 @@ void cleanup_module(void)
                if (p->modes & PARPORT_MODE_PCSPP) { 
                        if (!(p->flags & PARPORT_FLAG_COMA)) 
                                parport_quiesce(p);
+#ifdef CONFIG_PROC_FS
                        parport_proc_unregister(p);
+#endif
                        parport_unregister_port(p);
                }
                p = tmp;
index 1711de5dcfa60629942fd4b2cf6c497f2cdbc24d..547d0497cd3265f4de313267b9fa9a8162e67ae6 100644 (file)
@@ -77,7 +77,6 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
-#include <linux/bios32.h>
 #include <linux/timer.h>
 
 #include <asm/byteorder.h>
index 6007d235ed2d6de6066c94bd66da6a5fa2a78e8c..1aac1d29528b583ab63ad80b20e9316d3d9749ad 100644 (file)
@@ -559,7 +559,7 @@ static int hippi_probe(struct device *dev)
 #if defined(CONFIG_LTPC)
     extern int ltpc_probe(struct device *);
     static struct device dev_ltpc = {
-        "ltalk0\0   ",
+        "lt0\0   ",
                 0, 0, 0, 0,
                 0x0, 0,
                 0, 0, 0, NEXT_DEV, ltpc_probe };
index 4d7b96c4033c17727b40ab2b9ea4c4cc30f51079..ab1ecab6a637808bbd969da1e5c64390032a708a 100644 (file)
@@ -894,7 +894,6 @@ static int ax_set_dev_mac_address(struct device *dev, void *addr)
 static int ax25_disp_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
 {
        struct ax_disp *ax = (struct ax_disp *)tty->disc_data;
-       int err;
        unsigned int tmp;
 
        /* First make sure we're connected. */
index dcadac95746a56da78ed14f8648eb34b5e355016..8317d37e046aa92a9e8e64347630caa35ad80fca 100644 (file)
@@ -160,8 +160,8 @@ static int hostess_close(struct device *d)
 
 static int hostess_ioctl(struct device *d, struct ifreq *ifr, int cmd)
 {
-       struct sv11_device *sv11=d->priv;
-       /* z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */
+       /* struct sv11_device *sv11=d->priv;
+          z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */
        return sppp_do_ioctl(d, ifr,cmd);
 }
 
index 1392fa60a0c91902c24373ad79ffe215b512ec39..c90f059451af32f554c2bda7513cfa9e7f222a97 100644 (file)
  * Hacked about a bit to clean things up - Alan Cox 
  * Probably broken it from the origina 1.8
  *
+
+ * 1998/11/09: David Huggins-Daines <dhd@debian.org>
+ * Cleaned up the initialization code to use the standard autoirq methods,
+   and to probe for things in the standard order of i/o, irq, dma.  This
+   removes the "reset the reset" hack, because I couldn't figure out an
+   easy way to get the card to trigger an interrupt after it.
+ * Added support for passing configuration parameters on the kernel command
+   line and through insmod
+ * Changed the device name from "ltalk0" to "lt0", both to conform with the
+   other localtalk driver, and to clear up the inconsistency between the
+   module and the non-module versions of the driver :-)
+ * Added a bunch of comments (I was going to make some enums for the state
+   codes and the register offsets, but I'm still not sure exactly what their
+   semantics are)
+ * Don't poll anymore in interrupt-driven mode
+ * It seems to work as a module now (as of 2.1.127), but I don't think
+   I'm responsible for that...
+
+ *
  * Revision 1.7  1996/12/12 03:42:33  bradford
  * DMA alloc cribbed from 3c505.c.
  *
@@ -180,6 +199,9 @@ static int debug=0;
 #define DEBUG_UPPER 2
 #define DEBUG_LOWER 4
 
+static int io=0;
+static int irq=0;
+static int dma=0;
 
 #ifdef MODULE
 #include <linux/module.h>
@@ -245,25 +267,34 @@ static unsigned long dma_mem_alloc(int size)
         return __get_dma_pages(GFP_KERNEL, order);
 }
 
+/* DMA data buffer, DMA command buffer */
 static unsigned char *ltdmabuf;
 static unsigned char *ltdmacbuf;
 
+/* private struct, holds our appletalk address */
+
 struct ltpc_private
 {
        struct net_device_stats stats;
        struct at_addr my_addr;
 };
 
+/* transmit queue element struct */
+
 struct xmitQel {
        struct xmitQel *next;
+       /* command buffer */
        unsigned char *cbuf;
        short cbuflen;
+       /* data buffer */
        unsigned char *dbuf;
        short dbuflen;
        unsigned char QWrite;   /* read or write data */
        unsigned char mailbox;
 };
 
+/* the transmit queue itself */
+
 static struct xmitQel *xmQhd=NULL,*xmQtl=NULL;
 
 static void enQ(struct xmitQel *qel)
@@ -310,8 +341,10 @@ static struct xmitQel *deQ(void)
        return qel;
 }
 
+/* and... the queue elements we'll be using */
 static struct xmitQel qels[16];
 
+/* and their corresponding mailboxes */
 static unsigned char mailbox[16];
 static unsigned char mboxinuse[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 
@@ -331,6 +364,8 @@ static int wait_timeout(struct device *dev, int c)
        return 1; /* timed out */
 }
 
+/* get the first free mailbox */
+
 static int getmbox(void)
 {
        unsigned long flags;
@@ -347,6 +382,7 @@ static int getmbox(void)
        return 0;
 }
 
+/* read a command from the card */
 static void handlefc(struct device *dev)
 {
        /* called *only* from idle, non-reentrant */
@@ -370,6 +406,7 @@ static void handlefc(struct device *dev)
        if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n");
 }
 
+/* read data from the card */
 static void handlefd(struct device *dev)
 {
        int dma = dev->dma;
@@ -463,7 +500,8 @@ static void handlecommand(struct device *dev)
        if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n");
 } 
 
-static unsigned char rescbuf[2] = {0,0};
+/* ready made command for getting the result from the card */
+static unsigned char rescbuf[2] = {LT_GETRESULT,0};
 static unsigned char resdbuf[2];
 
 static int QInIdle=0;
@@ -482,7 +520,7 @@ static void idle(struct device *dev)
        struct xmitQel *q=0;
        int oops;
        int i;
-       int statusPort = dev->base_addr+6;
+       int base = dev->base_addr;
 
        save_flags(flags);
        cli();
@@ -495,8 +533,8 @@ static void idle(struct device *dev)
 
        restore_flags(flags);
 
-
-       (void) inb_p(statusPort); /* this tri-states the IRQ line */
+       /* this tri-states the IRQ line */
+       (void) inb_p(base+6);
 
        oops = 100;
 
@@ -506,19 +544,22 @@ loop:
                goto done;
        }
 
-       state = inb_p(statusPort);
-       if (state != inb_p(statusPort)) goto loop;
+       state = inb_p(base+6);
+       if (state != inb_p(base+6)) goto loop;
 
        switch(state) {
-               case 0xfc: 
+               case 0xfc:
+                       /* incoming command */
                        if (debug&DEBUG_LOWER) printk("idle: fc\n");
                        handlefc(dev); 
                        break;
-               case 0xfd: 
+               case 0xfd:
+                       /* incoming data */
                        if(debug&DEBUG_LOWER) printk("idle: fd\n");
                        handlefd(dev); 
                        break;
-               case 0xf9: 
+               case 0xf9:
+                       /* result ready */
                        if (debug&DEBUG_LOWER) printk("idle: f9\n");
                        if(!mboxinuse[0]) {
                                mboxinuse[0] = 1;
@@ -536,6 +577,7 @@ loop:
                                printk("timed out idle f9\n");
                        break;
                case 0xf8:
+                       /* ?? */
                        if (xmQhd) {
                                inb_p(dev->base_addr+1);
                                inb_p(dev->base_addr+0);
@@ -545,7 +587,8 @@ loop:
                                goto done;
                        }
                        break;
-               case 0xfa: 
+               case 0xfa:
+                       /* waiting for command */
                        if(debug&DEBUG_LOWER) printk("idle: fa\n");
                        if (xmQhd) {
                                q=deQ();
@@ -561,7 +604,7 @@ loop:
                                        printk("\n");
                                }
                                handlecommand(dev);
-                                       if(0xfa==inb_p(statusPort)) {
+                                       if(0xfa==inb_p(base+6)) {
                                                /* we timed out, so return */
                                                goto done;
                                        } 
@@ -582,13 +625,17 @@ loop:
                                }
                        } 
                        break;
-               case 0xfb:
+               case 0Xfb:
+                       /* data transfer ready */
                        if(debug&DEBUG_LOWER) printk("idle: fb\n");
                        if(q->QWrite) {
                                memcpy(ltdmabuf,q->dbuf,q->dbuflen);
                                handlewrite(dev);
                        } else {
                                handleread(dev);
+                               /* non-zero mailbox numbers are for
+                                  commmands, 0 is for GETRESULT
+                                  requests */
                                if(q->mailbox) {
                                        memcpy(q->dbuf,ltdmabuf,q->dbuflen);
                                } else { 
@@ -605,13 +652,14 @@ done:
        QInIdle=0;
 
        /* now set the interrupts back as appropriate */
-       /* the first 7 takes it out of tri-state (but still high) */
+       /* the first read takes it out of tri-state (but still high) */
        /* the second resets it */
-       /* note that after this point, any read of 6 will trigger an interrupt */
+       /* note that after this point, any read of base+6 will
+          trigger an interrupt */
 
        if (dev->irq) {
-               inb_p(dev->base_addr+7);
-               inb_p(dev->base_addr+7);
+               inb_p(base+7);
+               inb_p(base+7);
        }
        return;
 }
@@ -703,6 +751,8 @@ static int set_30 (struct device *dev,int x)
        return do_write(dev, &c, sizeof(c.setflags),&c,0);
 }
 
+/* LLAP to DDP translation */
+
 static int sendup_buffer (struct device *dev)
 {
        /* on entry, command is in ltdmacbuf, data in ltdmabuf */
@@ -912,23 +962,14 @@ static void ltpc_poll(unsigned long l)
        if (!dev)
                return;  /* we've been downed */
 
-       if (dev->irq) 
-       {
-               /* we're set up for interrupts */
-               if (0xf8 != inb_p(dev->base_addr+7)) {
-                       /* trigger an interrupt */
-                       (void) inb_p(dev->base_addr+6);
-               }
-               ltpc_timer.expires = jiffies+100;
-       } else {
-               /* we're strictly polling mode */
-               idle(dev);
-               ltpc_timer.expires = jiffies+5;
-       }
-
+       idle(dev);
+       ltpc_timer.expires = jiffies+5;
+       
        add_timer(&ltpc_timer);
 }
 
+/* DDP to LLAP translation */
+
 static int ltpc_xmit(struct sk_buff *skb, struct device *dev)
 {
        /* in kernel 1.3.xx, on entry skb->data points to ddp header,
@@ -975,150 +1016,18 @@ static struct net_device_stats *ltpc_get_stats(struct device *dev)
        return stats;
 }
 
-static unsigned short irqhitmask;
-
-__initfunc(static void lt_probe_handler(int irq, void *dev_id, struct pt_regs *reg_ptr))
-{
-       irqhitmask |= 1<<irq;
-}
-
-__initfunc(int ltpc_probe(struct device *dev))
+/* initialization stuff */
+  
+__initfunc(int ltpc_probe_dma(int base))
 {
-       int err;
-       unsigned char dma=0;
-       short base=0;
-       unsigned char irq=0;
-       int x=0,y=0;
-       int timeout;
-       int probe3, probe4, probe9;
-       unsigned short straymask;
-       unsigned long flags;
-       unsigned long f;
-
-       err = ltpc_init(dev);
-       if (err) return err;
-
-       /* occasionally the card comes up with reset latched, so we need
-        * to "reset the reset" first of all -- check the irq first also
-        */
-
-       save_flags(flags);
-       cli();
-
-       probe3 = request_irq( 3, &lt_probe_handler, 0, "ltpc_probe",dev);
-       probe4 = request_irq( 4, &lt_probe_handler, 0, "ltpc_probe",dev);
-       probe9 = request_irq( 9, &lt_probe_handler, 0, "ltpc_probe",dev);
-
-       irqhitmask = 0;
-
-       sti();
-
-       timeout = jiffies+2;
-       while(timeout>jiffies) ;  /* wait for strays */
-
-       straymask = irqhitmask;  /* pick up any strays */
-       /* if someone already owns this address, don't probe */ 
-       if (!check_region(0x220,8)) {
-               inb_p(0x227);
-               inb_p(0x227);
-               x=inb_p(0x226);
-               timeout = jiffies+2;
-               while(timeout>jiffies) ;
-               if(straymask != irqhitmask) base = 0x220;
-       }
-       if (!check_region(0x240,8)) {
-               inb_p(0x247);
-               inb_p(0x247);
-               y=inb_p(0x246);
-               timeout = jiffies+2;
-               while(timeout>jiffies) ;
-               if(straymask != irqhitmask) base = 0x240;
-       }
-
-       /* at this point, either we have an irq and the base addr, or
-        * there isn't any irq and we don't know the base address, but
-        * in either event the card is no longer latched in reset and
-        * the irq request line is tri-stated.
-        */
-
-       cli();
-       if (!probe3) free_irq(3,dev);
-       if (!probe4) free_irq(4,dev);
-       if (!probe9) free_irq(9,dev);
-
-       sti();
-       irqhitmask &= ~straymask;
-
-       irq = ffz(~irqhitmask);
-       if (irqhitmask != 1<<irq)
-               printk("ltpc card raised more than one interrupt!\n");
-
-       if (!base) {
-               if (!check_region(0x220,8)) {
-                       x = inb_p(0x220+6);
-                       if ( (x!=0xff) && (x>=0xf0) ) base = 0x220;
-               }
-               if (!check_region(0x240,8)) {
-                       y = inb_p(0x240+6);
-                       if ( (y!=0xff) && (y>=0xf0) ) base = 0x240;
-               } 
-       }
-
-       if(base) {
-               request_region(base,8,"ltpc");
-       } else {
-               printk("LocalTalk card not found; 220 = %02x, 240 = %02x.\n",x,y);
-               restore_flags(flags);
-               return -1;
-       }
-
-       ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
-
-       if (ltdmabuf) ltdmacbuf = &ltdmabuf[800];
-
-       if (!ltdmabuf) {
-               printk("ltpc: mem alloc failed\n");
-               restore_flags(flags);
-               return(-1);
-       }
-
-       if(debug&DEBUG_VERBOSE) {
-               printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
-       }
-
-       /* reset the card */
-
-       inb_p(base+1);
-       inb_p(base+3);
-       timeout = jiffies+2;
-       while(timeout>jiffies) ; /* hold it in reset for a coupla jiffies */
-       inb_p(base+0);
-       inb_p(base+2);
-       inb_p(base+7); /* clear reset */
-       inb_p(base+4); 
-       inb_p(base+5);
-       inb_p(base+5); /* enable dma */
-       inb_p(base+6); /* tri-state interrupt line */
-
-       timeout = jiffies+100;
-       
-       while(timeout>jiffies) {
-               /* wait for the card to complete initialization */
-       }
-       /* now, figure out which dma channel we're using */
-
-       /* set up both dma 1 and 3 for read call */
-
-       if (!request_dma(1,"ltpc")) {
-       
-               f=claim_dma_lock();
-               disable_dma(1);
-               clear_dma_ff(1);
+       int dma = 0;
+       int timeout;
+       unsigned long f;
+  
+       if (!request_dma(1,"ltpc")) {
+               f=claim_dma_lock();
+               disable_dma(1);
+               clear_dma_ff(1);
                set_dma_mode(1,DMA_MODE_WRITE);
                set_dma_addr(1,virt_to_bus(ltdmabuf));
                set_dma_count(1,sizeof(struct lt_mem));
@@ -1142,26 +1051,26 @@ __initfunc(int ltpc_probe(struct device *dev))
 
        /* FIXME -- do timings better! */
 
-       ltdmabuf[0] = 2; /* read request */
+       ltdmabuf[0] = LT_READMEM;
        ltdmabuf[1] = 1;  /* mailbox */
        ltdmabuf[2] = 0; ltdmabuf[3] = 0;  /* address */
        ltdmabuf[4] = 0; ltdmabuf[5] = 1;  /* read 0x0100 bytes */
        ltdmabuf[6] = 0; /* dunno if this is necessary */
 
-       inb_p(base+1);
-       inb_p(base+0);
+       inb_p(io+1);
+       inb_p(io+0);
        timeout = jiffies+100;
        while(timeout>jiffies) {
-               if ( 0xfa == inb_p(base+6) ) break;
+               if ( 0xfa == inb_p(io+6) ) break;
        }
 
-       inb_p(base+3);
-       inb_p(base+2);
+       inb_p(io+3);
+       inb_p(io+2);
        while(timeout>jiffies) {
-               if ( 0xfb == inb_p(base+6) ) break;
+               if ( 0xfb == inb_p(io+6) ) break;
        }
 
-       /* release the other dma channel */
+       /* release the other dma channel (if we opened both of them) */
 
        if ( (dma&0x2) && (get_dma_residue(3)==sizeof(struct lt_mem)) ){
                dma&=1;
@@ -1172,31 +1081,134 @@ __initfunc(int ltpc_probe(struct device *dev))
                dma&=0x2;
                free_dma(1);
        }
-       if (!dma) {  /* no dma channel */
-               printk("No DMA channel found on ltpc card.\n");
-               restore_flags(flags);
-               return -1;
-       } 
-  
+
        /* fix up dma number */
        dma|=1;
 
-       /* set up read */
+       return dma;
+}
+
+__initfunc(int ltpc_probe(struct device *dev))
+{
+       int err;
+       int x=0,y=0;
+       int timeout;
+       int autoirq;
+       unsigned long flags;
+       unsigned long f;
+
+       save_flags(flags);
+
+       /* probe for the I/O port address */
+       if (io != 0x240 && !check_region(0x220,8)) {
+               x = inb_p(0x220+6);
+               if ( (x!=0xff) && (x>=0xf0) ) io = 0x220;
+       }
+       
+       if (io != 0x220 && !check_region(0x240,8)) {
+               y = inb_p(0x240+6);
+               if ( (y!=0xff) && (y>=0xf0) ) io = 0x240;
+       } 
+
+       if(io) {
+               /* found it, now grab it */
+               request_region(io,8,"ltpc");
+       } else {
+               /* give up in despair */
+               printk ("LocalTalk card not found; 220 = %02x, 240 = %02x.\n",
+                       x,y);
+               restore_flags(flags);
+               return -1;
+       }
+
+       /* probe for the IRQ line */
+       if (irq < 2) {
+               autoirq_setup(2);
+
+               /* reset the interrupt line */
+               inb_p(io+7);
+               inb_p(io+7);
+               /* trigger an interrupt (I hope) */
+               inb_p(io+6);
+
+               autoirq = autoirq_report(1);
+
+               if (autoirq == 0) {
+                       printk("ltpc: probe at %#x failed to detect IRQ line.\n",
+                               io);
+               }
+               else {
+                       irq = autoirq;
+               }
+       }
+
+       /* allocate a DMA buffer */
+       ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
+
+       if (ltdmabuf) ltdmacbuf = &ltdmabuf[800];
+
+       if (!ltdmabuf) {
+               printk("ltpc: mem alloc failed\n");
+               restore_flags(flags);
+               return(-1);
+       }
+
+       if(debug&DEBUG_VERBOSE) {
+               printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
+       }
+
+       /* reset the card */
+
+       inb_p(io+1);
+       inb_p(io+3);
+       timeout = jiffies+2;
+       while(timeout>jiffies) ; /* hold it in reset for a coupla jiffies */
+       inb_p(io+0);
+       inb_p(io+2);
+       inb_p(io+7); /* clear reset */
+       inb_p(io+4); 
+       inb_p(io+5);
+       inb_p(io+5); /* enable dma */
+       inb_p(io+6); /* tri-state interrupt line */
+
+       timeout = jiffies+100;
+       
+       while(timeout>jiffies) {
+               /* wait for the card to complete initialization */
+       }
+       /* now, figure out which dma channel we're using, unless it's
+          already been specified */
+       /* well, 0 is a legal DMA channel, but the LTPC card doesn't
+          use it... */
+       if (dma == 0) {
+               dma = ltpc_probe_dma(io);
+               if (!dma) {  /* no dma channel */
+                       printk("No DMA channel found on ltpc card.\n");
+                       restore_flags(flags);
+                       return -1;
+               }
+       }
+
+       /* print out friendly message */
 
        if(irq)
-               printk("LocalTalk card found at %03x, IR%d, DMA%d.\n",base,irq,dma);
+               printk("Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma);
        else
-               printk("LocalTalk card found at %03x, DMA%d.  Using polled mode.\n",base,dma);
-    
-       dev->base_addr = base;
+               printk("Apple/Farallon LocalTalk-PC card at %03x, DMA%d.  Using polled mode.\n",io,dma);
+
+       /* seems more logical to do this *after* probing the card... */
+       err = ltpc_init(dev);
+       if (err) return err;
+
+       dev->base_addr = io;
        dev->irq = irq;
        dev->dma = dma;
 
-       if(debug&DEBUG_VERBOSE) {
-               printk("finishing up transfer\n");
-       }
-       
+       /* the card will want to send a result at this point */
+       /* (I think... leaving out this part makes the kernel crash,
+           so I put it back in...) */
+
        f=claim_dma_lock();
        disable_dma(dma);
        clear_dma_ff(dma);
@@ -1206,41 +1218,65 @@ __initfunc(int ltpc_probe(struct device *dev))
        enable_dma(dma);
        release_dma_lock(f);
 
-       (void) inb_p(base+3);
-       (void) inb_p(base+2);
+       (void) inb_p(io+3);
+       (void) inb_p(io+2);
        timeout = jiffies+100;
        while(timeout>jiffies) {
-               if( 0xf9 == inb_p(base+6)) break;
+               if( 0xf9 == inb_p(io+6)) break;
        }
 
        if(debug&DEBUG_VERBOSE) {
                printk("setting up timer and irq\n");
        }
 
-       init_timer(&ltpc_timer);
-       ltpc_timer.function=ltpc_poll;
-       ltpc_timer.data = (unsigned long) dev;
-
        if (irq) {
+               /* grab it and don't let go :-) */
                (void) request_irq( irq, &ltpc_interrupt, 0, "ltpc", dev);
-               (void) inb_p(base+7);  /* enable interrupts from board */
-               (void) inb_p(base+7);  /* and reset irq line */
-               ltpc_timer.expires = 100;
-                 /* poll it once per second just in case */
+               (void) inb_p(io+7);  /* enable interrupts from board */
+               (void) inb_p(io+7);  /* and reset irq line */
        } else {
-               ltpc_timer.expires = 5;
-                 /* polled mode -- 20 times per second */
-       }
-
-       ltpc_timer.expires += jiffies;  /* 1.2 to 1.3 change... */
-
-       add_timer(&ltpc_timer);
+               /* polled mode -- 20 times per second */
+               /* this is really, really slow... should it poll more often? */
+               init_timer(&ltpc_timer);
+               ltpc_timer.function=ltpc_poll;
+               ltpc_timer.data = (unsigned long) dev;
 
-       restore_flags(flags); 
+               ltpc_timer.expires = jiffies + 5;
+               add_timer(&ltpc_timer);
+               restore_flags(flags); 
+       }
 
        return 0;
 }
 
+/* handles "ltpc=io,irq,dma" kernel command lines */
+__initfunc(void ltpc_setup(char *str, int *ints))
+{
+       if (ints[0] == 0) {
+               if (str && !strncmp(str, "auto", 4)) {
+                       /* do nothing :-) */
+               }
+               else {
+                       /* usage message */
+                       printk (KERN_ERR
+                               "ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n");
+               }
+               return;
+       } else {
+               io = ints[1];
+               if (ints[0] > 1) {
+                       irq = ints[2];
+                       return;
+               }
+               if (ints[0] > 2) {
+                       dma = ints[3];
+                       return;
+               }
+               /* ignore any other paramters */
+       }
+       return;
+}
+
 #ifdef MODULE
 
 static char dev_name[8];
@@ -1251,17 +1287,28 @@ static struct device dev_ltpc = {
                0x0, 0,
                0, 0, 0, NULL, ltpc_probe };
 
+MODULE_PARM(debug, "i");
+MODULE_PARM(io, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(dma, "i");
+
 int init_module(void)
 {
+       int err, result;
+       
+        if(io == 0)
+               printk(KERN_NOTICE
+                      "ltpc: Autoprobing is not recommended for modules\n");
+
        /* Find a name for this unit */
-       int err=dev_alloc_name(&dev_ltpc,"lt%d");
+       err=dev_alloc_name(&dev_ltpc,"lt%d");
        
        if(err<0)
                return err;
 
-       if (register_netdev(&dev_ltpc) != 0) {
-               if(debug&DEBUG_VERBOSE) printk("EIO from register_netdev\n");
-               return -EIO;
+       if ((result = register_netdev(&dev_ltpc)) != 0) {
+               printk(KERN_DEBUG "could not register Localtalk-PC device\n");
+               return result;
        } else {
                if(debug&DEBUG_VERBOSE) printk("0 from register_netdev\n");
                return 0;
@@ -1322,3 +1369,4 @@ void cleanup_module(void)
        if(debug&DEBUG_VERBOSE) printk("returning from cleanup_module\n");
 }
 #endif /* MODULE */
+
index 9879f3de06789f8e7ca1be498c73135628456e72..ab82b9d2bf4bd58f9db2af5469ab8654ee90dbce 100644 (file)
@@ -157,7 +157,7 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
         
        skb->shapelatency=0;
        skb->shapeclock=shaper->recovery;
-       if(skb->shapeclock<jiffies)
+       if(time_before(skb->shapeclock, jiffies))
                skb->shapeclock=jiffies;
        skb->priority=0;        /* short term bug fix */
        skb->shapestamp=jiffies;
@@ -320,7 +320,7 @@ static void shaper_kick(struct shaper *shaper)
                 
                if(sh_debug)
                        printk("Clock = %d, jiffies = %ld\n", skb->shapeclock, jiffies);
-               if(skb->shapeclock <= jiffies + SHAPER_BURST)
+               if(skb->shapeclock - jiffies <= SHAPER_BURST)
                {
                        /*
                         *      Pull the frame and get interrupts back on.
@@ -385,10 +385,14 @@ static int shaper_open(struct device *dev)
        
        /*
         *      Can't open until attached.
+        *      Also can't open until speed is set, or we'll get
+        *      a division by zero.
         */
         
        if(shaper->dev==NULL)
                return -ENODEV;
+       if(shaper->bitspersec==0)
+               return -EINVAL;
        MOD_INC_USE_COUNT;
        return 0;
 }
@@ -543,6 +547,7 @@ static int shaper_attach(struct device *shdev, struct shaper *sh, struct device
        shdev->type=dev->type;
        shdev->addr_len=dev->addr_len;
        shdev->mtu=dev->mtu;
+       sh->bitspersec=0;
        return 0;
 }
 
@@ -564,7 +569,7 @@ static int shaper_ioctl(struct device *dev,  struct ifreq *ifr, int cmd)
                case SHAPER_GET_DEV:
                        if(sh->dev==NULL)
                                return -ENODEV;
-                       memcpy(ss->ss_name, sh->dev->name, sizeof(ss->ss_name));
+                       strcpy(ss->ss_name, sh->dev->name);
                        return 0;
                case SHAPER_SET_SPEED:
                        shaper_setspeed(sh,ss->ss_speed);
index 48d5c5d116a10df1f1d6814ba044f32c29e028e6..db3c117022a869cbdc0def06c6b5f494fc9010c5 100644 (file)
@@ -859,6 +859,9 @@ int sppp_do_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
        if(dev->flags&IFF_UP)
                return -EBUSY;
                
+       if(!capable(CAP_NET_ADMIN))
+               return -EPERM;
+       
        switch(cmd)
        {
                case SPPPIOCCISCO:
@@ -872,11 +875,7 @@ int sppp_do_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
                case SPPPIOCDEBUG:
                        sp->pp_flags&=~PP_DEBUG;
                        if(ifr->ifr_flags)
-                       {
-                               if(!capable(CAP_NET_ADMIN))
-                                       return -EPERM;
                                sp->pp_flags|=PP_DEBUG;
-                       }
                        break;
                default:
                        return -EINVAL;
index 8028bd5b394427bd609cc2b4d28184a6fe16249c..bba8f70de590d447d910b6a349f5ec4baa5c61c1 100644 (file)
@@ -686,7 +686,7 @@ void NCR5380_timer_fn(unsigned long surplus_to_requirements)
        save_flags(flags);
        cli();
        for (; expires_first &&
-               ((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires <= jiffies; ) 
+               time_before_eq(((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires, jiffies); )
        {
                instance = ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer;
                ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer = NULL;
@@ -776,7 +776,7 @@ __initfunc(static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA |
                      ICR_ASSERT_SEL);
 
-       while (probe_irq == IRQ_NONE && jiffies < timeout)
+       while (probe_irq == IRQ_NONE && time_before(jiffies,timeout))
                barrier();
 
        NCR5380_write(SELECT_ENABLE_REG, 0);
@@ -1123,7 +1123,7 @@ __initfunc(static void NCR5380_init(struct Scsi_Host *instance, int flags))
                        printk("scsi%d: SCSI bus busy, waiting up to five seconds\n",
                               instance->host_no);
                        timeout = jiffies + 5 * HZ;
-                       while (jiffies < timeout && (NCR5380_read(STATUS_REG) & SR_BSY));
+                       while (time_before(jiffies,timeout) && (NCR5380_read(STATUS_REG) & SR_BSY));
                        break;
                case 2:
                        printk("scsi%d: bus busy, attempting abort\n",
@@ -1417,7 +1417,7 @@ static void NCR5380_main(void) {
                            && !hostdata->dmalen
 #endif
 #ifdef USLEEP
-                           && (!hostdata->time_expires || hostdata->time_expires <= jiffies)
+                           && (!hostdata->time_expires || time_before_eq(hostdata->time_expires, jiffies))
 #endif
                            ) {
                                restore_flags(flags);
@@ -1532,10 +1532,10 @@ static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) {
 
                                                                spin_unlock_irq(&io_request_lock);
                                                                while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK
-                                                                      && jiffies < timeout);
+                                                                      && time_before(jiffies, timeout));
                                                                spin_lock_irq(&io_request_lock);
                                                                
-                                                               if (jiffies >= timeout)
+                                                               if (time_after_eq(jiffies, timeout) )
                                                                        printk("scsi%d: timeout at NCR5380.c:%d\n",
                                                                               host->host_no, __LINE__);
                                                        }
@@ -1681,11 +1681,11 @@ static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag)
                spin_unlock_irq(&io_request_lock);
 
                while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
-                      && jiffies < timeout);
+                      && time_before(jiffies,timeout));
 
                spin_lock_irq(&io_request_lock);
                       
-               if (jiffies >= timeout) {
+               if (time_after_eq(jiffies,timeout)) {
                        printk("scsi: arbitration timeout at %d\n", __LINE__);
                        NCR5380_write(MODE_REG, MR_BASE);
                        NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
@@ -1844,7 +1844,7 @@ part2:
                                waiting period */
 #else
        spin_unlock_irq(&io_request_lock);
-       while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) &
+       while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) &
                                        (SR_BSY | SR_IO)));
        spin_lock_irq(&io_request_lock);
 #endif
@@ -1915,10 +1915,10 @@ part2:
                unsigned long timeout = jiffies + NCR_TIMEOUT;
 
                spin_unlock_irq(&io_request_lock);
-               while (!(NCR5380_read(STATUS_REG) & SR_REQ) && jiffies < timeout);
+               while (!(NCR5380_read(STATUS_REG) & SR_REQ) && time_before(jiffies, timeout));
                spin_lock_irq(&io_request_lock);
                
-               if (jiffies >= timeout) {
+               if (time_after_eq(jiffies, timeout)) {
                        printk("scsi%d: timeout at NCR5380.c:%d\n", __LINE__);
                        NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
                        return -1;
@@ -3082,7 +3082,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
                {
                        /* RvC: go to sleep if polling time expired
                         */
-                       if (!cmd->device->disconnect && jiffies >= poll_time) 
+                       if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time))
                        {
                                hostdata->time_expires = jiffies + USLEEP_SLEEP;
 #if (NDEBUG & NDEBUG_USLEEP)
index 805e1f8111f873bfcbcacfab1fe2eae5205098b2..1aa855f5138b5025e036a1578da80814246a1e3a 100644 (file)
@@ -226,6 +226,7 @@ static struct dev_info device_list[] =
 {"MEDIAVIS","RENO CD-ROMX2A","2.03",BLIST_NOLUN},/*Responds to all lun */
 {"MICROP", "4110", "*", BLIST_NOTQ},           /* Buggy Tagged Queuing */
 {"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN},  /* Locks-up when LUN>0 polled. */
+{"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN},    /* Responds to all lun */
 {"RODIME","RO3000S","2.33", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
 {"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},     /* causes failed REQUEST SENSE on lun 1
                                                 * for aha152x controller, which causes
index cebab71ef05513d48614baed9e5ac371f4a53345..4ed9ba6343dec3d0394d3c0e41e0d902f037a22e 100644 (file)
@@ -110,14 +110,29 @@ extern int dispatch_scsi_info(int ino, char *buffer, char **start,
     return(-EBADF);
 }
 
+static void scsi_proc_fill_inode(struct inode *inode, int fill)
+{
+Scsi_Host_Template *shpnt;
+
+shpnt = scsi_hosts;
+while (shpnt && shpnt->proc_dir->low_ino != inode->i_ino)
+    shpnt = shpnt->next;
+if (!shpnt || !shpnt->module)
+    return;
+if (fill)
+    __MOD_INC_USE_COUNT(shpnt->module);
+else
+    __MOD_DEC_USE_COUNT(shpnt->module);
+}
+
 void build_proc_dir_entries(Scsi_Host_Template *tpnt)
 {
     struct Scsi_Host *hpnt;
-
     struct scsi_dir *scsi_hba_dir;
 
     proc_scsi_register(0, tpnt->proc_dir);
-    
+    tpnt->proc_dir->fill_inode = &scsi_proc_fill_inode;
+
     hpnt = scsi_hostlist;
     while (hpnt) {
         if (tpnt == hpnt->hostt) {
index e004a48cec7126ecf79fbdcf0959f09f28790360..d3a74355088df90f6ffd9db800888b3e655a0611 100644 (file)
@@ -1934,7 +1934,7 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int
 
                if (!share_dma)
                {
-                       if (irq > 0)
+                       if (devc->irq > 0) /* There is no point in freeing irq, if it wasn't allocated */
                                free_irq(devc->irq, (void *)devc->dev_no);
 
                        sound_free_dma(audio_devs[dev]->dmap_out->dma);
index 3e3abd044aa12664d403c193340abe126f703964..b830afdd2f17a0e1a8a9159cac867c53e7b71ca8 100644 (file)
@@ -292,11 +292,13 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len
         return len;
 }
 
+#ifdef CONFIG_PROC_FS
 static struct proc_dir_entry proc_root_sound = {
         PROC_SOUND, 5, "sound",
         S_IFREG | S_IRUGO, 1, 0, 0,
         0, NULL, sound_proc_get_info
 };
+#endif
 
 #ifndef MIN
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
@@ -842,8 +844,10 @@ soundcard_init(void)
                audio_init_devices();
        }
 #endif
+#ifdef CONFIG_PROC_FS
        if (proc_register(&proc_root, &proc_root_sound))
                printk(KERN_ERR "sound: registering /proc/sound failed\n");
+#endif         
 }
 
 static int      sound[20] = {
index e6aa9697fd3378d3d55469fa53541f7bbffe4763..1c18e0bf94533c35712c157f7ae40dfdecb674e7 100644 (file)
@@ -22,6 +22,7 @@ if [ "$CONFIG_FB" = "y" ]; then
     tristate 'Amiga CyberVision support' CONFIG_FB_CYBER
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       bool 'Amiga CyberVision3D support (experimental)' CONFIG_FB_VIRGE
+      bool 'Amiga CyberVisionPPC support (experimental)' CONFIG_FB_CVPPC
       tristate 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3
       tristate 'Amiga CLgen driver' CONFIG_FB_CLGEN
     fi
@@ -55,6 +56,17 @@ if [ "$CONFIG_FB" = "y" ]; then
     bool 'VESA VGA graphics console' CONFIG_FB_VESA
     define_bool CONFIG_VIDEO_SELECT y
   fi
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    if [ "$CONFIG_PCI" != "n" ]; then
+      tristate 'Matrox acceleration' CONFIG_FB_MATROX
+      if  [ "$CONFIG_FB_MATROX" != "n" ]; then
+        bool '  Millenium I/II support' CONFIG_FB_MATROX_MILLENIUM
+        bool '  Mystique support' CONFIG_FB_MATROX_MYSTIQUE
+        bool '  G100/G200 support' CONFIG_FB_MATROX_G100
+        bool '  Multihead support' CONFIG_FB_MATROX_MULTIHEAD
+      fi
+    fi
+  fi
   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
     bool 'SBUS and UPA framebuffers' CONFIG_FB_SBUS
     if [ "$CONFIG_FB_SBUS" != "n" ]; then
@@ -141,8 +153,9 @@ if [ "$CONFIG_FB" = "y" ]; then
         "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \
         "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
         "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_G364" = "y" -o \
+        "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
         "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
-         "$CONFIG_FB_IGA" = "y" ]; then
+         "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" ]; then
       define_bool CONFIG_FBCON_CFB8 y
     else
       if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
@@ -152,8 +165,9 @@ if [ "$CONFIG_FB" = "y" ]; then
           "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \
           "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
           "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_G364" = "m" -o \
+          "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
           "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
-           "$CONFIG_FB_IGA" = "y" ]; then
+           "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" ]; then
        define_bool CONFIG_FBCON_CFB8 m
       fi
     fi
@@ -161,36 +175,44 @@ if [ "$CONFIG_FB" = "y" ]; then
         "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
         "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \
         "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
-        "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" ]; then
+        "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
+        "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
+        "$CONFIG_FB_MATROX" = "y" ]; then
       define_bool CONFIG_FBCON_CFB16 y
     else
       if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
           "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
           "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \
           "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
-          "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" ]; then
+          "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
+          "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
+          "$CONFIG_FB_MATROX" = "m" ]; then
        define_bool CONFIG_FBCON_CFB16 m
       fi
     fi
     if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
-        "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" ]; then
+        "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
+         "$CONFIG_FB_MATROX" = "y" ]; then
       define_bool CONFIG_FBCON_CFB24 y
     else
       if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
-          "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" ]; then
+          "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
+          "$CONFIG_FB_MATROX" = "m" ]; then
        define_bool CONFIG_FBCON_CFB24 m
       fi
     fi
     if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
         "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
         "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
-        "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" ]; then
+        "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
+        "$CONFIG_FB_MATROX" = "y" ]; then
       define_bool CONFIG_FBCON_CFB32 y
     else
       if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
           "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
           "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
-          "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" ]; then
+          "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
+          "$CONFIG_FB_MATROX" = "m" ]; then
        define_bool CONFIG_FBCON_CFB32 m
       fi
     fi
index 18ce5c3ea76a4a3914bee3c0dcfa0dce520caff5..ccf51e05642efcfd5a76f4ae71b25c947aa7deb2 100644 (file)
@@ -123,6 +123,11 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_FB_CVPPC),y)
+L_OBJS += cvppcfb.o
+CONFIG_FBGEN_BUILTIN = y
+endif
+
 ifeq ($(CONFIG_FB_MAC),y)
 L_OBJS += macfb.o
 endif
@@ -311,6 +316,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_FB_MATROX),y)
+L_OBJS += matroxfb.o
+else
+  ifeq ($(CONFIG_FB_MATROX),m)
+  M_OBJS += matroxfb.o
+  endif
+endif
+
 # Generic Low Level Drivers
 
 ifeq ($(CONFIG_FBCON_AFB),y)
index a4f74c526d3735b676e7cf3bccf65f769feb3e40..ed588ab0d6ad1493dbbd846f4c79cb8a1a067aac 100644 (file)
@@ -60,6 +60,7 @@
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #include <asm/setup.h>
+#include <asm/io.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-afb.h>
@@ -1478,7 +1479,8 @@ static int amifb_set_var(struct fb_var_screeninfo *var, int con,
                        struct fb_fix_screeninfo fix;
 
                        ami_encode_fix(&fix, &par);
-                       display->screen_base = fix.smem_start;
+                       display->screen_base = 
+                               phys_to_virt ((unsigned long) fix.smem_start);
                        display->visual = fix.visual;
                        display->type = fix.type;
                        display->type_aux = fix.type_aux;
@@ -2124,7 +2126,7 @@ static int ami_encode_fix(struct fb_fix_screeninfo *fix,
 {
        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
        strcpy(fix->id, amifb_name);
-       fix->smem_start = (char *)videomemory;
+       fix->smem_start = (char*) virt_to_phys((void *)videomemory);
        fix->smem_len = videomemorysize;
 
 #ifdef FBCON_HAS_MFB
index 170fb93a2fa7181301560a21a59a20a190b96b1b..df3e9715ec64e0ae0e5ac98223fa528ac389fc0b 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: atyfb.c,v 1.81 1998/10/14 16:45:38 ecd Exp $
+/*  $Id: atyfb.c,v 1.89 1998/11/12 13:07:26 geert Exp $
  *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
  *
  *     Copyright (C) 1997-1998  Geert Uytterhoeven
@@ -400,12 +400,15 @@ static char atyfb_name[16] = "ATY Mach64";
 static char fontname[40] __initdata = { 0 };
 static char curblink __initdata = 1;
 static char noaccel __initdata = 0;
+static u32 default_vram __initdata = 0;
+static int default_pll __initdata = 0;
+static int default_mclk __initdata = 0;
 
 static const u32 ref_clk_per = 1000000000000ULL/14318180;
 
 #if defined(CONFIG_PPC)
-static int default_vmode = VMODE_NVRAM;
-static int default_cmode = CMODE_NVRAM;
+static int default_vmode __initdata = VMODE_NVRAM;
+static int default_cmode __initdata = CMODE_NVRAM;
 #endif
 
 #ifdef CONFIG_ATARI
@@ -448,11 +451,11 @@ static struct aty_features {
 };
 
 static const char *aty_gx_ram[8] __initdata = {
-    "DRAM", "VRAM", "VRAM", "DRAM", "GDRAM", "EVRAM", "EVRAM", "RESV"
+    "DRAM", "VRAM", "VRAM", "DRAM", "DRAM", "VRAM", "VRAM", "RESV"
 };
 
 static const char *aty_ct_ram[8] __initdata = {
-    "OFF", "DRAM", "EDO", "HPDRAM", "SDRAM", "SGRAM", "WRAM", "RESV"
+    "OFF", "DRAM", "EDO", "EDO", "SDRAM", "SGRAM", "WRAM", "RESV"
 };
 
 
@@ -540,7 +543,6 @@ static void reset_engine(const struct fb_info_aty *info)
                aty_ld_le32(GEN_TEST_CNTL, info) | GUI_ENGINE_ENABLE, info);
     /* ensure engine is not locked up by clearing any FIFO or */
     /* HOST errors */
-    aty_st_le32(0xf4,0xa955,info);
     aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, info) | BUS_HOST_ERR_ACK |
                          BUS_FIFO_ERR_ACK, info);
 }
@@ -1346,7 +1348,7 @@ static void aty_set_pll_gx(const struct fb_info_aty *info,
            aty_st_514(0x03, 0x00, info);       /* Sync Control */
            aty_st_514(0x05, 0x00, info);       /* Power Management */
            aty_st_514(0x20, pll->m, info);     /* F0 / M0 */
-           aty_st_514(0x21, pll->m, info);     /* F1 / N0 */
+           aty_st_514(0x21, pll->n, info);     /* F1 / N0 */
            break;
     }
 }
@@ -1492,7 +1494,14 @@ static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div,
                    (vclk_fb_div*mclk_post_div*bpp);
     if (xclks_per_row < (1<<11))
        FAIL("Dotclock to high");
-    fifo_size = 24;
+    if ((Gx == GT_CHIP_ID) || (Gx == GU_CHIP_ID) || (Gx == VT_CHIP_ID) ||
+       (Gx == VU_CHIP_ID)) {
+       fifo_size = 24;
+       dsp_loop_latency = 0;
+    } else {
+       fifo_size = 32;
+       dsp_loop_latency = 2;
+    }
     dsp_precision = 0;
     y = (xclks_per_row*fifo_size)>>11;
     while (y) {
@@ -1506,21 +1515,21 @@ static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div,
     if (info->total_vram > 1*1024*1024) {
        if (info->ram_type >= SDRAM) {
            /* >1 MB SDRAM */
-           dsp_loop_latency = 8;
+           dsp_loop_latency += 8;
            page_size = 8;
        } else {
            /* >1 MB DRAM */
-           dsp_loop_latency = 6;
+           dsp_loop_latency += 6;
            page_size = 9;
        }
     } else {
        if (info->ram_type >= SDRAM) {
            /* <2 MB SDRAM */
-           dsp_loop_latency = 9;
+           dsp_loop_latency += 9;
            page_size = 10;
        } else {
            /* <2 MB DRAM */
-           dsp_loop_latency = 8;
+           dsp_loop_latency += 8;
            page_size = 10;
        }
     }
@@ -2385,7 +2394,7 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name))
     struct fb_var_screeninfo var;
     struct display *disp;
     const char *chipname = NULL, *ramname = NULL;
-    int pll, mclk;
+    int pll, mclk, gtb_memsize;
 #if defined(CONFIG_PPC)
     int sense;
 #endif
@@ -2463,30 +2472,14 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name))
            }
        }
     }
-    if (mclk < 44)
-       info->mem_refresh_rate = 0;     /* 000 = 10 Mhz - 43 Mhz */
-    else if (mclk < 50)
-       info->mem_refresh_rate = 1;     /* 001 = 44 Mhz - 49 Mhz */
-    else if (mclk < 55)
-       info->mem_refresh_rate = 2;     /* 010 = 50 Mhz - 54 Mhz */
-    else if (mclk < 66)
-       info->mem_refresh_rate = 3;     /* 011 = 55 Mhz - 65 Mhz */
-    else if (mclk < 75)
-       info->mem_refresh_rate = 4;     /* 100 = 66 Mhz - 74 Mhz */
-    else if (mclk < 80)
-       info->mem_refresh_rate = 5;     /* 101 = 75 Mhz - 79 Mhz */
-    else if (mclk < 100)
-       info->mem_refresh_rate = 6;     /* 110 = 80 Mhz - 100 Mhz */
-    else
-       info->mem_refresh_rate = 7;     /* 111 = 100 Mhz and above */
-    info->pll_per = 1000000/pll;
-    info->mclk_per = 1000000/mclk;
 
     i = aty_ld_le32(MEM_CNTL, info);
-    if (((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) ||
-       ((Gx == VT_CHIP_ID) && (Rev & 0x01)) || (Gx == VU_CHIP_ID) ||
-       (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
-       (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID))
+    gtb_memsize = (((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID)
+               || ((Gx == VT_CHIP_ID) && (Rev & 0x01)) || (Gx == VU_CHIP_ID)
+               || (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID)
+               || (Gx == GD_CHIP_ID) || (Gx == GI_CHIP_ID)
+               || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID));
+    if (gtb_memsize)
        switch (i & 0xF) {      /* 0xF used instead of MEM_SIZE_ALIAS */
            case MEM_SIZE_512K:
                info->total_vram = 0x80000;
@@ -2538,10 +2531,51 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name))
          info->total_vram += 0x400000;
     }
 
+    if (default_vram) {
+       info->total_vram = default_vram*1024;
+       i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);
+       if (info->total_vram <= 0x80000)
+           i |= MEM_SIZE_512K;
+       else if (info->total_vram <= 0x100000)
+           i |= MEM_SIZE_1M;
+       else if (info->total_vram <= 0x200000)
+           i |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M;
+       else if (info->total_vram <= 0x400000)
+           i |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M;
+       else if (info->total_vram <= 0x600000)
+           i |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M;
+       else
+           i |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M;
+       aty_st_le32(MEM_CNTL, i, info);
+    }
+    if (default_pll)
+       pll = default_pll;
+    if (default_mclk)
+       mclk = default_mclk;
+
     printk("%d%c %s, %d MHz PLL, %d Mhz MCLK\n", 
           info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20), 
           info->total_vram == 0x80000 ? 'K' : 'M', ramname, pll, mclk);
 
+    if (mclk < 44)
+       info->mem_refresh_rate = 0;     /* 000 = 10 Mhz - 43 Mhz */
+    else if (mclk < 50)
+       info->mem_refresh_rate = 1;     /* 001 = 44 Mhz - 49 Mhz */
+    else if (mclk < 55)
+       info->mem_refresh_rate = 2;     /* 010 = 50 Mhz - 54 Mhz */
+    else if (mclk < 66)
+       info->mem_refresh_rate = 3;     /* 011 = 55 Mhz - 65 Mhz */
+    else if (mclk < 75)
+       info->mem_refresh_rate = 4;     /* 100 = 66 Mhz - 74 Mhz */
+    else if (mclk < 80)
+       info->mem_refresh_rate = 5;     /* 101 = 75 Mhz - 79 Mhz */
+    else if (mclk < 100)
+       info->mem_refresh_rate = 6;     /* 110 = 80 Mhz - 100 Mhz */
+    else
+       info->mem_refresh_rate = 7;     /* 111 = 100 Mhz and above */
+    info->pll_per = 1000000/pll;
+    info->mclk_per = 1000000/mclk;
+
 #ifdef DEBUG
     if ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
        int i;
@@ -2806,11 +2840,11 @@ __initfunc(void atyfb_init(void))
            if (node == pcp->prom_node) {
 
                struct fb_var_screeninfo *var = &default_var;
+               unsigned int N, P, Q, M, T;
                u32 v_total, h_total;
                struct crtc crtc;
                u8 pll_regs[16];
                u8 clock_cntl;
-               unsigned int N, P, Q, M, T;
 
                crtc.vxres = prom_getintdefault(node, "width", 1024);
                crtc.vyres = prom_getintdefault(node, "height", 768);
@@ -2833,33 +2867,28 @@ __initfunc(void atyfb_init(void))
                 */
                clock_cntl = aty_ld_8(CLOCK_CNTL, info);
                /* printk("atyfb: CLOCK_CNTL: %02x\n", clock_cntl); */
-               for (i = 0; i < 16; i++) {
+               for (i = 0; i < 16; i++)
                        pll_regs[i] = aty_ld_pll(i, info);
-                       /* printk("atyfb: PLL %2d: %02x\n", i, pll_regs[i]); */
-               }
+
                /*
                 * PLL Reference Devider M:
                 */
                M = pll_regs[2];
-               /* printk("atyfb: M: %02x\n", M); */
 
                /*
                 * PLL Feedback Devider N (Dependant on CLOCK_CNTL):
                 */
                N = pll_regs[7 + (clock_cntl & 3)];
-               /* printk("atyfb: N: %02x\n", N); */
 
                /*
                 * PLL Post Devider P (Dependant on CLOCK_CNTL):
                 */
                P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1));
-               /* printk("atyfb: P: %2d\n", P); */
 
                /*
                 * PLL Devider Q:
                 */
                Q = N / P;
-               /* printk("atyfb: Q: %d\n", Q); */
 
                /*
                 * Target Frequency:
@@ -2871,11 +2900,8 @@ __initfunc(void atyfb_init(void))
                 * where R is XTALIN (= 14318 kHz).
                 */
                T = 2 * Q * 14318 / M;
-               /* printk("atyfb: T: %d\n", T); */
 
-               default_var.pixclock =
-                       ((1000000000000ULL / v_total) * 1000) / (T * h_total);
-               /* printk("atyfb: pixclock: %d\n", default_var.pixclock); */
+               default_var.pixclock = 1000000000 / T;
            }
 
 #else /* __sparc__ */
@@ -2984,69 +3010,65 @@ __initfunc(void atyfb_of_init(struct device_node *dp))
     struct fb_info_aty *info;
     int i;
 
-    for (; dp; dp = dp->next) {
-       switch (dp->n_addrs) {
-           case 1:
-           case 2:
-           case 3:
-               addr = dp->addrs[0].address;
-               break;
-           case 4:
-               addr = dp->addrs[1].address;
-               break;
-           default:
-               printk("Warning: got %d adresses for ATY:\n", dp->n_addrs);
-               for (i = 0; i < dp->n_addrs; i++)
-                   printk(" %08x-%08x", dp->addrs[i].address,
-                          dp->addrs[i].address+dp->addrs[i].size-1);
-               if (dp->n_addrs)
-                   printk("\n");
-               continue;
-       }
-
-       info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
-       if (!info) {
-           printk("atyfb_of_init: can't alloc fb_info_aty\n");
+    switch (dp->n_addrs) {
+       case 1:
+       case 2:
+       case 3:
+           addr = dp->addrs[0].address;
+           break;
+       case 4:
+           addr = dp->addrs[1].address;
+           break;
+       default:
+           printk("Warning: got %d adresses for ATY:\n", dp->n_addrs);
+           for (i = 0; i < dp->n_addrs; i++)
+               printk(" %08x-%08x", dp->addrs[i].address,
+                      dp->addrs[i].address+dp->addrs[i].size-1);
+           if (dp->n_addrs)
+               printk("\n");
            return;
-       }
-       memset(info, 0, sizeof(struct fb_info_aty));
+    }
+
+    info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
+    if (!info) {
+       printk("atyfb_of_init: can't alloc fb_info_aty\n");
+       return;
+    }
+    memset(info, 0, sizeof(struct fb_info_aty));
 
-       info->ati_regbase = (unsigned long)ioremap(0x7ff000+addr,
-                                                  0x1000)+0xc00;
-       info->ati_regbase_phys = 0x7ff000+addr;
-       info->ati_regbase = (unsigned long)ioremap(info->ati_regbase_phys,
+    info->ati_regbase_phys = 0x7ff000+addr;
+    info->ati_regbase = (unsigned long)ioremap(info->ati_regbase_phys,
                                                   0x1000);
-       info->ati_regbase_phys += 0xc00;
-       info->ati_regbase += 0xc00;
-
-       /* enable memory-space accesses using config-space command register */
-       if (pci_device_loc(dp, &bus, &devfn) == 0) {
-           pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
-           if (cmd != 0xffff) {
-               cmd |= PCI_COMMAND_MEMORY;
-               pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
-           }
+    info->ati_regbase_phys += 0xc00;
+    info->ati_regbase += 0xc00;
+
+    /* enable memory-space accesses using config-space command register */
+    if (pci_device_loc(dp, &bus, &devfn) == 0) {
+       pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+       if (cmd != 0xffff) {
+           cmd |= PCI_COMMAND_MEMORY;
+           pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
        }
+    }
 
 #ifdef __BIG_ENDIAN
-       /* Use the big-endian aperture */
-       addr += 0x800000;
+    /* Use the big-endian aperture */
+    addr += 0x800000;
 #endif
 
-       /* Map in frame buffer */
-       info->frame_buffer_phys = addr;
-       info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
+    /* Map in frame buffer */
+    info->frame_buffer_phys = addr;
+    info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
 
-       if (!aty_init(info, dp->full_name)) {
-           kfree(info);
-           return;
-       }
+    if (!aty_init(info, dp->full_name)) {
+       kfree(info);
+       return;
+    }
 
 #ifdef CONFIG_FB_COMPAT_XPMAC
-       if (!console_fb_info)
-           console_fb_info = &info->fb_info;
+    if (!console_fb_info)
+       console_fb_info = &info->fb_info;
 #endif /* CONFIG_FB_COMPAT_XPMAC */
-    }
 }
 #endif /* CONFIG_FB_OF */
 
@@ -3074,7 +3096,12 @@ __initfunc(void atyfb_setup(char *options, int *ints))
                curblink = 0;
        } else if (!strncmp(this_opt, "noaccel", 7)) {
                noaccel = 1;
-       }
+       } else if (!strncmp(this_opt, "vram:", 5))
+               default_vram = simple_strtoul(this_opt+5, NULL, 0);
+       else if (!strncmp(this_opt, "pll:", 4))
+               default_pll = simple_strtoul(this_opt+4, NULL, 0);
+       else if (!strncmp(this_opt, "mclk:", 5))
+               default_mclk = simple_strtoul(this_opt+5, NULL, 0);
 #if defined(CONFIG_PPC)
        else if (!strncmp(this_opt, "vmode:", 6)) {
            unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
index 98f734129ccd8f4aeeede52acde86bac7cda57a6..699ae96ff409e3fca0da3b8ba41945a5e962e11b 100644 (file)
@@ -480,7 +480,7 @@ static struct chips_init_reg chips_init_fr[] = {
        { 0x0b, 0x11 },
        { 0x10, 0x0c },
        { 0x11, 0xe0 },
-       { 0x12, 0x40 },
+       /* { 0x12, 0x40 }, -- 3400 needs 40, 2400 needs 48, no way to tell */
        { 0x20, 0x63 },
        { 0x21, 0x68 },
        { 0x22, 0x19 },
index 8cc875548754778c570900bacb6fd2bd3d480bf7..68078c09161fc197d4c6a951ada9522210492de7 100644 (file)
@@ -89,6 +89,9 @@ struct clgenfb_info
     int btype;
     int smallboard;
     unsigned char SFR; /* Shadow of special function register */
+
+    unsigned long fbmem_phys;
+    unsigned long fbregs_phys;
     
     struct clgenfb_par currentmode;
     union {
@@ -333,7 +336,7 @@ static int clgen_encode_fix(struct fb_fix_screeninfo *fix, const void *par,
     memset(fix, 0, sizeof(struct fb_fix_screeninfo));
     strcpy(fix->id, clgenfb_name);
        
-    fix->smem_start    = (char*)_info->fbmem;
+    fix->smem_start    = (char*)_info->fbmem_phys;
     
     /* monochrome: only 1 memory plane */
     /* 8 bit and above: Use whole memory area */
@@ -346,7 +349,7 @@ static int clgen_encode_fix(struct fb_fix_screeninfo *fix, const void *par,
     fix->ypanstep      = 1;
     fix->ywrapstep     = 0;
     fix->line_length   = _par->line_length;
-    fix->mmio_start    = (char *)_info->regs;
+    fix->mmio_start    = (char *)_info->fbregs_phys;
     fix->mmio_len      = 0x10000;
     fix->accel         = FB_ACCEL_NONE;
 
@@ -410,7 +413,7 @@ static int clgen_decode_var(const struct fb_var_screeninfo *var, void *par,
     
     /* use highest possible virtual resolution */
     if (_par->var.xres_virtual == -1 &&
-       _par->var.xres_virtual == -1)
+       _par->var.yres_virtual == -1)
     {
        printk("clgen: using maximum available virtual resolution\n");
        for (i=0; modes[i].xres != -1; i++)
@@ -1534,8 +1537,10 @@ __initfunc(void clgenfb_init(void))
                                              KERNELMAP_NOCACHE_SER, NULL);
         DEBUG printk(KERN_INFO "clgen: Virtual address for board set to: $%p\n", fb_info->regs);
        fb_info->regs += 0x600000;
+       fb_info->fbregs_phys = board_addr + 0x600000;
 
-       fb_info->fbmem = kernel_map(board_addr + 16777216, 16777216, 
+       fb_info->fbmem_phys = board_addr + 16777216;
+       fb_info->fbmem = kernel_map(fb_info->fbmem_phys, 16777216, 
                              KERNELMAP_NOCACHE_SER, NULL);
        DEBUG printk(KERN_INFO "clgen: (RAM start set to: $%lx)\n", fb_info->fbmem);
     }
@@ -1544,6 +1549,7 @@ __initfunc(void clgenfb_init(void))
         cd2 = zorro_get_board(key2);
         printk(" REG at $%lx\n", (unsigned long)cd2->cd_BoardAddr);
 
+       fb_info->fbmem_phys = board_addr;
         if (board_addr > 0x01000000)
            fb_info->fbmem = kernel_map(board_addr, board_size, 
                                  KERNELMAP_NOCACHE_SER, NULL);
@@ -1552,6 +1558,7 @@ __initfunc(void clgenfb_init(void))
 
         /* set address for REG area of board */
        fb_info->regs = (unsigned char *)ZTWO_VADDR(cd2->cd_BoardAddr);
+       fb_info->fbregs_phys = (unsigned long) cd2->cd_BoardAddr;
 
         DEBUG printk(KERN_INFO "clgen: Virtual address for board set to: $%p\n", fb_info->regs);
        DEBUG printk(KERN_INFO "clgen: (RAM start set to: $%lx)\n", fb_info->fbmem);
index 586d7aefc065232eb784dc9d004719a2b9bf48f6..d1a63b64fef87a18f33d67a88732eb745142f553 100644 (file)
@@ -59,6 +59,9 @@
 
 static int currcon = 0;
 static int switching = 0;
+static char fontname[40] __initdata = { 0 };
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
 
 struct fb_par_control {
        int     vmode, cmode;
@@ -102,7 +105,10 @@ struct fb_info_control {
  * Exported functions
  */
 void control_init(void);
+#ifdef CONFIG_FB_OF
 void control_of_init(struct device_node *dp);
+#endif
+void controlfb_setup(char *options, int *ints);
 
 static int control_open(struct fb_info *info, int user);
 static int control_release(struct fb_info *info, int user);
@@ -989,7 +995,7 @@ static void control_init_info(struct fb_info *info, struct fb_info_control *p)
        info->node = -1;        /* ??? danj */
        info->fbops = &controlfb_ops;
        info->disp = &p->disp;
-       info->fontname[0] = 0;
+       strcpy(info->fontname, fontname);
        info->changevar = NULL;
        info->switch_con = &controlfb_switch;
        info->updatevar = &controlfb_updatevar;
@@ -1016,13 +1022,51 @@ static void control_par_to_all(struct fb_info_control *p, int init)
        }
 }
 
-#if 0
+/* Parse user speficied options (`video=controlfb:') */
 __initfunc(void controlfb_setup(char *options, int *ints))
 {
-    /* Parse user speficied options (`video=controlfb:') */
-       FUNCID;
+       char *this_opt;
+
+       if (!options || !*options)
+               return;
+
+       for (this_opt = strtok(options, ","); this_opt;
+            this_opt = strtok(NULL, ",")) {
+               if (!strncmp(this_opt, "font:", 5)) {
+                       char *p;
+                       int i;
+
+                       p = this_opt +5;
+                       for (i = 0; i < sizeof(fontname) - 1; i++)
+                               if (!*p || *p == ' ' || *p == ',')
+                                       break;
+                       memcpy(fontname, this_opt + 5, i);
+                       fontname[i] = 0;
+               }
+               if (!strncmp(this_opt, "vmode:", 6)) {
+                       int vmode = simple_strtoul(this_opt+6, NULL, 0);
+               if (vmode > 0 && vmode <= VMODE_MAX)
+                       default_vmode = vmode;
+               } else if (!strncmp(this_opt, "cmode:", 6)) {
+                       int depth = simple_strtoul(this_opt+6, NULL, 0);
+                       switch (depth) {
+                        case 8:
+                               default_cmode = CMODE_8;
+                               break;
+                        case 15:
+                        case 16:
+                               default_cmode = CMODE_16;
+                               break;
+                        case 24:
+                        case 32:
+                               default_cmode = CMODE_32;
+                               break;
+                       }
+               }
+       }
 }
 
+#if 0
 static int controlfb_pan_display(struct fb_var_screeninfo *var,
                           struct controlfb_par *par,
                           const struct fb_info *fb_info)
@@ -1037,5 +1081,4 @@ static int controlfb_pan_display(struct fb_var_screeninfo *var,
 
     return 0;
 }
-
 #endif
diff --git a/drivers/video/cvppcfb.c b/drivers/video/cvppcfb.c
new file mode 100644 (file)
index 0000000..a41cd0c
--- /dev/null
@@ -0,0 +1,605 @@
+/*
+ * CybervisionPPC (TVP4020) low level driver for the frame buffer device
+ *                          ^^^^^^^^^
+ *                          literally ;)
+ *
+ * Copyright (c) 1998 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) (v124)
+ * --------------------------------------------------------------------------
+ * based on linux/drivers/video/skeletonfb.c by Geert Uytterhoeven
+ * --------------------------------------------------------------------------
+ * TODO h/w parameters detect/modify, 8-bit CLUT, acceleration
+ * --------------------------------------------------------------------------
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/amigahw.h>
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb32.h>
+#include <asm/setup.h>
+#include <asm/io.h>
+
+#define ISDIGIT(a) ((a)>='0' && (a)<='9')
+
+#undef CVPPCFB_MASTER_DEBUG
+#ifdef CVPPCFB_MASTER_DEBUG
+#define FBEGIN if (usr_startup.debug>1)\
+                       printk(__FUNCTION__ " {\n")
+#define FEND   if (usr_startup.debug>1)\
+                       printk("} /* " __FUNCTION__ " */\n")
+#define DPRINTK(a,b...)        if (usr_startup.debug)\
+                       printk("%s: " a, __FUNCTION__ , ## b)
+#else
+#define FBEGIN
+#define FEND
+#define DPRINTK(a,b...)
+#endif 
+
+static const char cvppcfb_name[16]="CybervisionPPC";
+
+struct cvppcfb_startup {               /* startup options */
+       char font[40];
+       u32 xres;
+       u32 yres;
+       u32 bpp;
+       unsigned long debug;
+       unsigned long YANW;                     /* You Are Not Welcome */
+       struct fb_monspecs monitor;
+};
+static struct cvppcfb_startup usr_startup = {
+       "\0", 640, 480, 16, 0, 1, { 31, 32, 58, 62, 0 } };
+
+#define CVPPC_BASE     0xe0000000
+#define CVPPC_SIZE     0x00800000
+static char* video_base;       /* virtual address of board video memory */
+static unsigned long video_phys;/* physical address of board video memory */
+static u32 video_size;         /* size of board video memory */
+
+struct cvppcfb_par {           /* board parameters (sort of) */
+       u32 xres;
+       u32 yres;
+       u32 vxres;
+       u32 vyres;
+       u32 vxoff;
+       u32 vyoff;
+       u32 bpp;
+       u32 clock;
+       u32 sflags;
+       u32 left;
+       u32 right;
+       u32 top;
+       u32 bottom;
+       u32 hsynclen;
+       u32 vsynclen;
+};
+
+struct cvppcfb_info {
+       struct fb_info_gen gen;
+       struct cvppcfb_par current_par;
+       int current_par_valid;
+       struct display disp;
+       struct {
+               u8 transp;
+               u8 red;
+               u8 green;
+               u8 blue;
+       } palette[256];
+       union {
+#ifdef FBCON_HAS_CFB16
+               u16 cmap16[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+               u32 cmap32[16];
+#endif
+       } cmap;
+};
+static struct cvppcfb_info fb_info;
+
+/*
+ * declaration of hw switch functions
+ */
+static void cvppcfb_detect(void);
+static int cvppcfb_encode_fix(struct fb_fix_screeninfo* fix,
+                               const void* par, struct fb_info_gen* info);
+static int cvppcfb_decode_var(const struct fb_var_screeninfo* var,
+                                       void* par, struct fb_info_gen* info);
+static int cvppcfb_encode_var(struct fb_var_screeninfo* var,
+                               const void* par, struct fb_info_gen* info);
+static void cvppcfb_get_par(void* par, struct fb_info_gen* info);
+static void cvppcfb_set_par(const void* par, struct fb_info_gen* info);
+static int cvppcfb_getcolreg(unsigned regno,
+                       unsigned* red, unsigned* green, unsigned* blue,
+                               unsigned* transp, struct fb_info* info);
+static int cvppcfb_setcolreg(unsigned regno,
+                       unsigned red, unsigned green, unsigned blue,
+                               unsigned transp, struct fb_info* info);
+static void cvppcfb_dispsw(const void* par, struct display* disp,
+                                               struct fb_info_gen* info);
+
+static struct fbgen_hwswitch cvppcfb_hwswitch={
+       cvppcfb_detect, cvppcfb_encode_fix, cvppcfb_decode_var,
+       cvppcfb_encode_var, cvppcfb_get_par, cvppcfb_set_par,
+       cvppcfb_getcolreg, cvppcfb_setcolreg, NULL /* pan_display() */,
+       NULL /* blank() */, cvppcfb_dispsw
+};
+
+/*
+ * declaration of ops switch functions
+ */
+static int cvppcfb_open(struct fb_info* info, int user);
+static int cvppcfb_release(struct fb_info* info, int user);
+
+static struct fb_ops cvppcfb_ops={
+       cvppcfb_open, cvppcfb_release, fbgen_get_fix, fbgen_get_var,
+       fbgen_set_var, fbgen_get_cmap, fbgen_set_cmap, fbgen_pan_display,
+       fbgen_ioctl, NULL /* fb_mmap() */
+};
+
+/*
+ * the actual definition of the above mentioned functions follows
+ */
+
+/*
+ * private functions
+ */
+
+static void cvppcfb_set_modename(struct cvppcfb_info* info,
+                                               struct cvppcfb_startup* s) {
+
+       strcpy(info->gen.info.modename, cvppcfb_name);
+}
+
+static void cvppcfb_decode_opt(struct cvppcfb_startup* s, void* par,
+                                               struct cvppcfb_info* info) {
+       struct cvppcfb_par* p=(struct cvppcfb_par* )par;
+
+       memset(p, 0, sizeof(struct cvppcfb_par));
+       p->xres=p->vxres=(s->xres+7)&~7;
+       p->yres=p->vyres=s->yres;
+       p->bpp=(s->bpp+7)&~7;
+       if (p->bpp==24)
+               p->bpp=32;
+       if (p->bpp<32)
+               p->clock=6666;
+       else
+               p->clock=10000;
+}
+
+static void cvppcfb_encode_mcap(char* options, struct fb_monspecs* mcap) {
+       char* next;
+       int i=0;
+
+       while (i<4 && options) {
+               if ((next=strchr(options, ';')))
+                       *(next++)='\0';
+               switch (i++) {
+                       case 0:                         /* vmin */
+                               mcap->vfmin=(__u16 )
+                                       simple_strtoul(options, NULL, 0);
+                               break;
+                       case 1:                         /* vmax */
+                               mcap->vfmax=(__u16 )
+                                       simple_strtoul(options, NULL, 0);
+                               break;
+                       case 2:                         /* hmin */
+                               mcap->hfmin=(__u32 )
+                                       simple_strtoul(options, NULL, 0);
+                               break;
+                       case 3:                         /* hmax */
+                               mcap->hfmax=(__u32 )
+                                       simple_strtoul(options, NULL, 0);
+                               break;
+               }
+               options=next;
+       }
+}
+
+static void cvppcfb_encode_mode(char* options, struct cvppcfb_startup* s) {
+       char* next;
+       int i=0;
+
+       while (i<3 && options) {
+               if ((next=strchr(options, ';')))
+                       *(next++)='\0';
+               switch (i++) {
+                       case 0:
+                               s->xres=(u32 )
+                                       simple_strtoul(options, NULL, 0);
+                               break;
+                       case 1:
+                               s->yres=(u32 )
+                                       simple_strtoul(options, NULL, 0);
+                               break;
+                       case 2:
+                               s->bpp=(u32 )
+                                       simple_strtoul(options, NULL, 0);
+                               break;
+               }
+               options=next;
+       }
+}
+
+/*
+ * protected functions
+ */
+
+static void cvppcfb_detect(void) {
+
+       FBEGIN;
+       FEND;
+}
+
+static int cvppcfb_encode_fix(struct fb_fix_screeninfo* fix,
+                       const void* par, struct fb_info_gen* info) {
+
+       FBEGIN;
+       strcpy(fix->id, cvppcfb_name);
+       fix->smem_start=(char* )video_phys;
+       fix->smem_len=(__u32 )video_size;
+       fix->type=FB_TYPE_PACKED_PIXELS;
+       if (((struct cvppcfb_par* )par)->bpp==8)
+               fix->visual=FB_VISUAL_PSEUDOCOLOR;
+       else
+               fix->visual=FB_VISUAL_TRUECOLOR;
+       fix->xpanstep=fix->ypanstep=fix->ywrapstep=0;
+       fix->line_length=0;                     /* computed by fbcon */
+       fix->mmio_start=NULL;
+       fix->mmio_len=0;
+       fix->accel=FB_ACCEL_NONE;
+       FEND;
+       return 0;
+}
+
+static int cvppcfb_decode_var(const struct fb_var_screeninfo* var,
+                               void* par, struct fb_info_gen* info) {
+       struct cvppcfb_par p;
+
+       FBEGIN;
+       memset(&p, 0, sizeof(struct cvppcfb_par));
+       p.bpp=(var->bits_per_pixel+7)&~7;
+       if (p.bpp==24)
+               p.bpp=32;
+       if (p.bpp>32) {
+               DPRINTK("depth too big (%lu)\n", p.bpp);
+               return -EINVAL;
+       }
+       p.xres=(var->xres+7)&~7;
+       p.yres=var->yres;
+       if (p.xres<320 || p.yres<200 || p.xres>2048 || p.yres>2048) {
+               DPRINTK("bad resolution (%lux%lu)\n", p.xres, p.yres);
+               return -EINVAL;
+       }
+       p.vxres=(var->xres_virtual+7)&~7;
+       p.vxoff=(var->xoffset+7)&~7;
+       p.vyres=var->yres_virtual;
+       p.vyoff=var->yoffset;
+       if (p.vxres<p.xres+p.vxoff)
+               p.vxres=p.xres+p.vxoff;
+       if (p.vyres<p.yres+p.vyoff)
+               p.vyres=p.yres+p.vyoff;
+       if (p.vxres*p.vyres*p.bpp/8>video_size) {
+               DPRINTK("no memory for screen (%lux%lux%lu)\n",
+                                               p.vxres, p.vyres, p.bpp);
+               return -EINVAL;
+       }
+       p.sflags=var->sync&(FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT);
+       p.clock=var->pixclock;
+       if (p.clock<6666) {
+               DPRINTK("pixclock too fast (%lu)\n", p.clock);
+               return -EINVAL;
+       }
+       p.left=var->left_margin;
+       p.top=var->upper_margin;
+       p.right=var->right_margin;
+       p.bottom=var->lower_margin;
+       p.hsynclen=var->hsync_len;
+       p.vsynclen=var->vsync_len;
+       *((struct cvppcfb_par* )par)=p;
+       FEND;
+       return 0;
+}
+
+static int cvppcfb_encode_var(struct fb_var_screeninfo* var,
+                               const void* par, struct fb_info_gen* info) {
+       struct cvppcfb_par* p=(struct cvppcfb_par* )par;
+       struct fb_var_screeninfo v;
+
+       FBEGIN;
+       memset(&v, 0, sizeof(struct fb_var_screeninfo));
+       v.xres=p->xres;
+       v.yres=p->yres;
+       v.xres_virtual=p->vxres;
+       v.yres_virtual=p->vyres;
+       v.xoffset=p->vxoff;
+       v.yoffset=p->vyoff;
+       v.bits_per_pixel=p->bpp;
+       switch (p->bpp) {
+               case 16:
+                       v.red.offset=11;
+                       v.red.length=5;
+                       v.green.offset=5;
+                       v.green.length=6;
+                       v.blue.length=5;
+                       break;
+               case 32:
+                       v.transp.offset=24;
+                       v.red.offset=16;
+                       v.green.offset=8;
+                       v.transp.length=8;
+                       /* fallback */
+               case 8:
+                       v.red.length=v.green.length=v.blue.length=8;
+                       break;
+       }
+       v.activate=FB_ACTIVATE_NOW;
+       v.height=v.width=-1;
+       v.pixclock=p->clock;
+       v.left_margin=p->left;
+       v.right_margin=p->right;
+       v.upper_margin=p->top;
+       v.lower_margin=p->bottom;
+       v.hsync_len=p->hsynclen;
+       v.vsync_len=p->vsynclen;
+       v.sync=p->sflags;
+       v.vmode=FB_VMODE_NONINTERLACED;
+       *var=v;
+       FEND;
+       return 0;
+}
+
+static void cvppcfb_get_par(void* par, struct fb_info_gen* info) {
+       struct cvppcfb_info* i=(struct cvppcfb_info* )info;
+       
+       FBEGIN;
+       if (i->current_par_valid)
+               *((struct cvppcfb_par* )par)=i->current_par;
+       else
+               cvppcfb_decode_opt(&usr_startup, par, i);
+       FEND;
+}
+
+static void cvppcfb_set_par(const void* par, struct fb_info_gen* info) {
+       struct cvppcfb_info* i=(struct cvppcfb_info* )info;
+
+       FBEGIN;
+       i->current_par=*((struct cvppcfb_par* )par);
+       i->current_par_valid=1;
+       FEND;
+}
+
+static int cvppcfb_getcolreg(unsigned regno,
+                       unsigned* red, unsigned* green, unsigned* blue,
+                               unsigned* transp, struct fb_info* info) {
+       struct cvppcfb_info* i=(struct cvppcfb_info* )info;
+
+       if (regno<256) {
+               *red=i->palette[regno].red<<8|i->palette[regno].red;
+               *green=i->palette[regno].green<<8|i->palette[regno].green;
+               *blue=i->palette[regno].blue<<8|i->palette[regno].blue;
+               *transp=i->palette[regno].transp<<8|i->palette[regno].transp;
+       }
+       return regno>255;
+}
+
+static int cvppcfb_setcolreg(unsigned regno,
+                       unsigned red, unsigned green, unsigned blue,
+                               unsigned transp, struct fb_info* info) {
+       struct cvppcfb_info* i=(struct cvppcfb_info* )info;
+
+       if (regno<16) {
+               switch (i->current_par.bpp) {
+#ifdef FBCON_HAS_CFB8
+                       case 8:
+                               DPRINTK("8 bit depth not supported yet.\n");
+                               return 1;
+#endif
+#ifdef FBCON_HAS_CFB16
+                       case 16:
+                               i->cmap.cmap16[regno]=
+                                       ((u32 )red & 0xf800) |
+                                       (((u32 )green & 0xfc00)>>5) |
+                                       (((u32 )blue & 0xf800)>>11);
+                               break;
+#endif
+#ifdef FBCON_HAS_CFB32
+                       case 32:
+                               i->cmap.cmap32[regno]=
+                                       (((u32 )transp & 0xff00) << 16) |
+                                       (((u32 )red & 0xff00) << 8) |
+                                       (((u32 )green & 0xff00)) |
+                                       (((u32 )blue & 0xff00) >> 8);
+                               break;
+#endif
+               }
+       }
+       if (regno<256) {
+               i->palette[regno].red=red >> 8;
+               i->palette[regno].green=green >> 8;
+               i->palette[regno].blue=blue >> 8;
+               i->palette[regno].transp=transp >> 8;
+       }
+       return regno>255;
+}
+
+static void cvppcfb_dispsw(const void* par, struct display* disp,
+                                               struct fb_info_gen* info) {
+       struct cvppcfb_info* i=(struct cvppcfb_info* )info;
+       unsigned long flags;
+
+       FBEGIN;
+       save_flags(flags);
+       cli();
+       switch (((struct cvppcfb_par* )par)->bpp) {
+#ifdef FBCON_HAS_CFB8
+               case 8:
+                       disp->dispsw=&fbcon_cfb8;
+                       break;
+#endif
+#ifdef FBCON_HAS_CFB16
+               case 16:
+                       disp->dispsw=&fbcon_cfb16;
+                       disp->dispsw_data=i->cmap.cmap16;
+                       break;
+#endif
+#ifdef FBCON_HAS_CFB32
+               case 32:
+                       disp->dispsw=&fbcon_cfb32;
+                       disp->dispsw_data=i->cmap.cmap32;
+                       break;
+#endif
+               default:
+                       disp->dispsw=&fbcon_dummy;
+                       break;
+       }
+       restore_flags(flags);
+       FEND;
+}
+
+static int cvppcfb_open(struct fb_info* info, int user) {
+
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+static int cvppcfb_release(struct fb_info* info, int user) {
+
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+/*
+ * public functions
+ */
+
+void cvppcfb_cleanup(struct fb_info* info) {
+
+       unregister_framebuffer(info);
+}
+
+__initfunc(void cvppcfb_init(void)) {
+
+       FBEGIN;
+#ifdef CVPPCFB_MASTER_DEBUG
+       printk("cvppcfb_init():\n");
+       printk("    resolution %ldx%ldx%ld\n", usr_startup.xres,
+                                       usr_startup.yres, usr_startup.bpp);
+       printk("    debug: %ld, YANW: %ld\n", usr_startup.debug,
+                                               usr_startup.YANW);
+       printk("    monitorcap: %ld,%ld,%ld,%ld\n",
+                       usr_startup.monitor.vfmin, usr_startup.monitor.vfmax,
+                       usr_startup.monitor.hfmin, usr_startup.monitor.hfmax);
+#endif
+       if (usr_startup.YANW)                   /* cannot probe yet */
+               return;
+       memset(&fb_info, 0, sizeof(struct cvppcfb_info));
+       video_size=CVPPC_SIZE;
+       video_phys=CVPPC_BASE;
+#ifdef CONFIG_APUS
+       video_base=(char* )
+               kernel_map(video_phys, video_size, KERNELMAP_NOCACHE_SER, NULL);
+#else
+       video_base=ioremap(video_phys, video_size);
+#endif
+       DPRINTK("video_phys=%08lx, video_base=%08lx\n", video_phys, video_base);
+       DPRINTK("phys_to_virt(video_phys)=%08lx\n", phys_to_virt(video_phys));
+       DPRINTK("virt_to_phys(video_base)=%08lx\n", virt_to_phys(video_base));
+       fb_info.disp.scrollmode=SCROLL_YREDRAW;
+       fb_info.gen.parsize=sizeof(struct cvppcfb_par);
+       fb_info.gen.fbhw=&cvppcfb_hwswitch;
+       cvppcfb_set_modename(&fb_info, &usr_startup);
+       fb_info.gen.info.flags=FBINFO_FLAG_DEFAULT;
+       fb_info.gen.info.fbops=&cvppcfb_ops;
+       fb_info.gen.info.monspecs=usr_startup.monitor;
+       fb_info.gen.info.disp=&fb_info.disp;
+       strcpy(fb_info.gen.info.fontname, usr_startup.font);
+       fb_info.gen.info.switch_con=&fbgen_switch;
+       fb_info.gen.info.updatevar=&fbgen_update_var;
+       fb_info.gen.info.blank=&fbgen_blank;
+       fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info);
+       if (fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen)<0) {
+               printk( "cvppcfb: bad startup configuration: "
+                       "unable to register.\n");
+               return;
+       }
+       fbgen_set_disp(-1, &fb_info.gen);
+       fbgen_install_cmap(0, &fb_info.gen);
+       if (register_framebuffer(&fb_info.gen.info)<0) {
+               printk("cvppcfb: unable to register.\n");
+               return;
+       }
+       printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
+               GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename,
+                                       (unsigned long )(video_size>>10));
+       MOD_INC_USE_COUNT;
+       FEND;
+}
+
+__initfunc(void cvppcfb_setup(char* options, int* ints)) {
+       char* next;
+
+       usr_startup.YANW=0;
+       DPRINTK("options: '%s'\n", options);
+       while (options) {
+               if ((next=strchr(options, ',')))
+                       *(next++)='\0';
+               if (!strncmp(options, "monitorcap:", 11))
+                       cvppcfb_encode_mcap(options+11, &usr_startup.monitor);
+               else if (!strncmp(options, "debug:", 6)) {
+                       if (ISDIGIT(options[6]))
+                               usr_startup.debug=options[6]-'0';
+                       else
+                               usr_startup.debug=1;
+               }
+               else if (!strncmp(options, "mode:", 5))
+                       cvppcfb_encode_mode(options+5, &usr_startup);
+               else if (!strncmp(options, "font:", 5))
+                       strcpy(usr_startup.font, options+5);
+               else
+                       DPRINTK("unrecognized option '%s'\n", options);
+               options=next;
+       }
+#ifdef CVPPCFB_MASTER_DEBUG
+       printk("cvppcfb_setup():\n");
+       printk("    resolution %ldx%ldx%ld\n", usr_startup.xres,
+                                       usr_startup.yres, usr_startup.bpp);
+       printk("    debug: %ld, YANW: %ld\n", usr_startup.debug,
+                                               usr_startup.YANW);
+       printk("    monitorcap: %ld,%ld,%ld,%ld\n",
+                       usr_startup.monitor.vfmin, usr_startup.monitor.vfmax,
+                       usr_startup.monitor.hfmin, usr_startup.monitor.hfmax);
+#endif
+}
+
+/*
+ * modularization
+ */
+
+#ifdef MODULE
+int init_module(void) {
+
+       cvppcfb_init();
+}
+
+void cleanup_module(void) {
+
+       cvppcfb_cleanup();
+}
+#endif /* MODULE */
+
index 1150504d50c2f438412ea81b253fc0447b55e03c..c3165128848d8ab33e85bba085f38219a5325227 100644 (file)
@@ -122,6 +122,8 @@ static unsigned char Cyber_colour_table [256][3];
 static unsigned long CyberMem;
 static unsigned long CyberSize;
 static volatile char *CyberRegs;
+static unsigned long CyberMem_phys;
+static unsigned long CyberRegs_phys;
  
 
 /*
@@ -178,6 +180,13 @@ static struct fb_videomode cyberfb_predefined[] __initdata = {
            0, 0, -1, -1, FB_ACCELF_TEXT, CYBER16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
            FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
        }
+    }, {
+       "1024x768-16", {         /* Cybervision 16 bpp */
+           1024, 768, 1024, 768, 0, 0, 16, 0,
+           {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+           0, 0, -1, -1, 0, CYBER16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+           FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+       }
     }
 };
 
@@ -372,9 +381,9 @@ static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
 {
        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
        strcpy(fix->id, cyberfb_name);
-       fix->smem_start = (char *)CyberMem;
+       fix->smem_start = (char*) CyberMem_phys;
        fix->smem_len = CyberSize;
-       fix->mmio_start = (char *)CyberRegs;
+       fix->mmio_start = (char*) CyberRegs_phys;
        fix->mmio_len = 0x10000;
 
        fix->type = FB_TYPE_PACKED_PIXELS;
@@ -846,7 +855,7 @@ static void cyberfb_set_disp(int con, struct fb_info *info)
        cyberfb_get_fix(&fix, con, info);
        if (con == -1)
                con = 0;
-       display->screen_base = fix.smem_start;
+       display->screen_base = (char*) CyberMem;
        display->visual = fix.visual;
        display->type = fix.type;
        display->type_aux = fix.type_aux;
@@ -1030,7 +1039,9 @@ __initfunc(void cyberfb_init(void))
        board_addr = (unsigned long)cd->cd_BoardAddr;
 
        /* This includes the video memory as well as the S3 register set */
-       CyberMem = kernel_map (board_addr + 0x01400000, 0x01000000,
+       CyberMem_phys = board_addr + 0x01400000;
+       CyberRegs_phys = CyberMem_phys + 0x00c00000;
+       CyberMem = kernel_map (CyberMem_phys, 0x01000000,
                               KERNELMAP_NOCACHE_SER, NULL);
        CyberRegs = (char*) (CyberMem + 0x00c00000);
 
index 829e89e35947dc7b3a8f413dee5b9a1d186ded6b..2fa889a0c35a601de9ccba4cb374328ed27191d0 100644 (file)
@@ -368,6 +368,30 @@ void fbcon_iplan2p2_revc(struct display *p, int xx, int yy)
     }
 }
 
+void fbcon_iplan2p2_clear_margins(struct vc_data *conp, struct display *p,
+                                 int bottom_only)
+{
+    u32 offset;
+    int bytes;
+    int lines;
+    u32 cval;
+
+/* No need to handle right margin, cannot occur with fontwidth == 8 */
+
+    bytes = p->next_line;
+    if (fontheightlog(p)) {
+       lines = p->var.yres - (conp->vc_rows << fontheightlog(p));
+       offset = ((p->yscroll + conp->vc_rows) * bytes) << fontheightlog(p);
+    } else {
+       lines = p->var.yres - conp->vc_rows * fontheight(p);
+       offset = (p->yscroll + conp->vc_rows) * bytes * fontheight(p);
+    }
+    if (lines) {
+       cval = expand2l(COLOR_2P(attr_bgcol_ec(p,conp)));
+       memset_even_2p(p->screen_base+offset, lines * bytes, cval);
+    }
+}
+
 
     /*
      *  `switch' for the low level operations
@@ -376,7 +400,7 @@ void fbcon_iplan2p2_revc(struct display *p, int xx, int yy)
 struct display_switch fbcon_iplan2p2 = {
     fbcon_iplan2p2_setup, fbcon_iplan2p2_bmove, fbcon_iplan2p2_clear,
     fbcon_iplan2p2_putc, fbcon_iplan2p2_putcs, fbcon_iplan2p2_revc, NULL,
-    NULL, NULL, FONTWIDTH(8)
+    NULL, fbcon_iplan2p2_clear_margins, FONTWIDTH(8)
 };
 
 
@@ -402,3 +426,4 @@ EXPORT_SYMBOL(fbcon_iplan2p2_clear);
 EXPORT_SYMBOL(fbcon_iplan2p2_putc);
 EXPORT_SYMBOL(fbcon_iplan2p2_putcs);
 EXPORT_SYMBOL(fbcon_iplan2p2_revc);
+EXPORT_SYMBOL(fbcon_iplan2p2_clear_margins);
index 74eb40cef6701e08646c3cdc4224a017a8772a24..265c54d8439e741ccabf70e8b6805296545b723e 100644 (file)
@@ -388,6 +388,30 @@ void fbcon_iplan2p4_revc(struct display *p, int xx, int yy)
     }
 }
 
+void fbcon_iplan2p4_clear_margins(struct vc_data *conp, struct display *p,
+                                 int bottom_only)
+{
+    u32 offset;
+    int bytes;
+    int lines;
+    u32 cval1, cval2;
+
+/* No need to handle right margin, cannot occur with fontwidth == 8 */
+
+    bytes = p->next_line;
+    if (fontheightlog(p)) {
+       lines = p->var.yres - (conp->vc_rows << fontheightlog(p));
+       offset = ((p->yscroll + conp->vc_rows) * bytes) << fontheightlog(p);
+    } else {
+       lines = p->var.yres - conp->vc_rows * fontheight(p);
+       offset = (p->yscroll + conp->vc_rows) * bytes * fontheight(p);
+    }
+    if (lines) {
+       expand4dl(attr_bgcol_ec(p,conp), &cval1, &cval2);
+       memset_even_4p(p->screen_base+offset, lines * bytes, cval1, cval2);
+    }
+}
+
 
     /*
      *  `switch' for the low level operations
@@ -396,7 +420,7 @@ void fbcon_iplan2p4_revc(struct display *p, int xx, int yy)
 struct display_switch fbcon_iplan2p4 = {
     fbcon_iplan2p4_setup, fbcon_iplan2p4_bmove, fbcon_iplan2p4_clear,
     fbcon_iplan2p4_putc, fbcon_iplan2p4_putcs, fbcon_iplan2p4_revc, NULL,
-    NULL, NULL, FONTWIDTH(8)
+    NULL, fbcon_iplan2p4_clear_margins, FONTWIDTH(8)
 };
 
 
@@ -422,3 +446,4 @@ EXPORT_SYMBOL(fbcon_iplan2p4_clear);
 EXPORT_SYMBOL(fbcon_iplan2p4_putc);
 EXPORT_SYMBOL(fbcon_iplan2p4_putcs);
 EXPORT_SYMBOL(fbcon_iplan2p4_revc);
+EXPORT_SYMBOL(fbcon_iplan2p4_clear_margins);
index 307bece45618010ea509c302d4ef7e235f01a9fd..ff42bc96b9c5bb7e6e4732223a65be488bd9e99f 100644 (file)
@@ -425,6 +425,31 @@ void fbcon_iplan2p8_revc(struct display *p, int xx, int yy)
     }
 }
 
+void fbcon_iplan2p8_clear_margins(struct vc_data *conp, struct display *p,
+                                 int bottom_only)
+{
+    u32 offset;
+    int bytes;
+    int lines;
+    u32 cval1, cval2, cval3, cval4;
+
+/* No need to handle right margin, cannot occur with fontwidth == 8 */
+
+    bytes = p->next_line;
+    if (fontheightlog(p)) {
+       lines = p->var.yres - (conp->vc_rows << fontheightlog(p));
+       offset = ((p->yscroll + conp->vc_rows) * bytes) << fontheightlog(p);
+    } else {
+       lines = p->var.yres - conp->vc_rows * fontheight(p);
+       offset = (p->yscroll + conp->vc_rows) * bytes * fontheight(p);
+    }
+    if (lines) {
+       expand8ql(attr_bgcol_ec(p,conp), &cval1, &cval2, &cval3, &cval4);
+       memset_even_8p(p->screen_base+offset, lines * bytes,
+                      cval1, cval2, cval3, cval4);
+    }
+}
+
 
     /*
      *  `switch' for the low level operations
@@ -433,7 +458,7 @@ void fbcon_iplan2p8_revc(struct display *p, int xx, int yy)
 struct display_switch fbcon_iplan2p8 = {
     fbcon_iplan2p8_setup, fbcon_iplan2p8_bmove, fbcon_iplan2p8_clear,
     fbcon_iplan2p8_putc, fbcon_iplan2p8_putcs, fbcon_iplan2p8_revc, NULL,
-    NULL, NULL, FONTWIDTH(8)
+    NULL, fbcon_iplan2p8_clear_margins, FONTWIDTH(8)
 };
 
 
@@ -459,3 +484,4 @@ EXPORT_SYMBOL(fbcon_iplan2p8_clear);
 EXPORT_SYMBOL(fbcon_iplan2p8_putc);
 EXPORT_SYMBOL(fbcon_iplan2p8_putcs);
 EXPORT_SYMBOL(fbcon_iplan2p8_revc);
+EXPORT_SYMBOL(fbcon_iplan2p8_clear_margins);
index 05c74729a6c9daa7f73f5c8a75a0319380892166..32f1ea8d4b5d47b7b2f3616c6badfe803eae18b9 100644 (file)
@@ -66,7 +66,7 @@ void fbcon_mfb_clear(struct vc_data *conp, struct display *p, int sy, int sx,
 {
     u8 *dest;
     u_int rows;
-    int inverse = conp ? attr_reverse(p,conp->vc_attr) : 0;
+    int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0;
 
     dest = p->screen_base+sy*fontheight(p)*p->next_line+sx;
 
@@ -148,6 +148,28 @@ void fbcon_mfb_revc(struct display *p, int xx, int yy)
        *dest = ~*dest;
 }
 
+void fbcon_mfb_clear_margins(struct vc_data *conp, struct display *p,
+                            int bottom_only)
+{
+    u8 *dest;
+    int height, bottom;
+    int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0;
+
+    /* XXX Need to handle right margin? */
+
+    height = p->var.yres - conp->vc_rows * fontheight(p);
+    if (!height)
+       return;
+    bottom = conp->vc_rows + p->yscroll;
+    if (bottom >= p->vrows)
+       bottom -= p->vrows;
+    dest = p->screen_base + bottom * fontheight(p) * p->next_line;
+    if (inverse)
+       mymemset(dest, height * p->next_line);
+    else
+       mymemclear(dest, height * p->next_line);
+}
+
 
     /*
      *  `switch' for the low level operations
@@ -155,7 +177,8 @@ void fbcon_mfb_revc(struct display *p, int xx, int yy)
 
 struct display_switch fbcon_mfb = {
     fbcon_mfb_setup, fbcon_mfb_bmove, fbcon_mfb_clear, fbcon_mfb_putc,
-    fbcon_mfb_putcs, fbcon_mfb_revc, NULL, NULL, NULL, FONTWIDTH(8)
+    fbcon_mfb_putcs, fbcon_mfb_revc, NULL, NULL, fbcon_mfb_clear_margins,
+    FONTWIDTH(8)
 };
 
 
@@ -181,3 +204,4 @@ EXPORT_SYMBOL(fbcon_mfb_clear);
 EXPORT_SYMBOL(fbcon_mfb_putc);
 EXPORT_SYMBOL(fbcon_mfb_putcs);
 EXPORT_SYMBOL(fbcon_mfb_revc);
+EXPORT_SYMBOL(fbcon_mfb_clear_margins);
index eb9645c21ca22fd480011ad474391b96f40a619f..c3c42ed5ea982e0ce03619a22f6cf13b8bd0de06 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 
 #include <asm/uaccess.h>
+#include <asm/io.h>
 
 
 static int currcon = 0;
@@ -243,7 +244,7 @@ void fbgen_set_disp(int con, struct fb_info_gen *info)
     memset(&fix, 0, sizeof(struct fb_fix_screeninfo));
     fbhw->encode_fix(&fix, &par, info);
 
-    display->screen_base = fix.smem_start;
+    display->screen_base = phys_to_virt((unsigned long)fix.smem_start);
     display->visual = fix.visual;
     display->type = fix.type;
     display->type_aux = fix.type_aux;
index 748d5705f3bcc5059597e47dd046538b1eb6d945..1fa507998890d2c82df418a2e02981a20dac3d85 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/kmod.h>
 #endif
 
-#ifdef __mc68000__
+#if defined(__mc68000__) || defined(CONFIG_APUS)
 #include <asm/setup.h>
 #endif
 #ifdef __powerpc__
@@ -56,6 +56,8 @@ extern void macfb_init(void);
 extern void macfb_setup(char *options, int *ints);
 extern void cyberfb_init(void);
 extern void cyberfb_setup(char *options, int *ints);
+extern void cvppcfb_init(void);
+extern void cvppcfb_setup(char *options, int *ints);
 extern void retz3fb_init(void);
 extern void retz3fb_setup(char *options, int *ints);
 extern void clgenfb_init(void);
@@ -69,6 +71,7 @@ extern void atyfb_setup(char *options, int *ints);
 extern void igafb_init(void);
 extern void igafb_setup(char *options, int *ints);
 extern void imsttfb_init(void);
+extern void imsttfb_setup(char *options, int *ints);
 extern void dnfb_init(void);
 extern void tgafb_init(void);
 extern void virgefb_init(void);
@@ -78,6 +81,8 @@ extern void s3triofb_init(void);
 extern void s3triofb_setup(char *options, int *ints);
 extern void vesafb_init(void);
 extern void vesafb_setup(char *options, int *ints);
+extern void matroxfb_init(void);
+extern void matroxfb_setup(char* options, int *ints);
 extern void hpfb_init(void);
 extern void hpfb_setup(char *options, int *ints);
 extern void sbusfb_init(void);
@@ -109,12 +114,18 @@ static struct {
 #ifdef CONFIG_FB_CYBER
        { "cyber", cyberfb_init, cyberfb_setup },
 #endif
+#ifdef CONFIG_FB_CVPPC
+       { "cvppcfb", cvppcfb_init, cvppcfb_setup },
+#endif
 #ifdef CONFIG_FB_CLGEN
        { "clgen", clgenfb_init, clgenfb_setup },
 #endif
 #ifdef CONFIG_FB_OF
        { "offb", offb_init, offb_setup },
 #endif
+#ifdef CONFIG_FB_SBUS
+       { "sbus", sbusfb_init, sbusfb_setup },
+#endif
 #ifdef CONFIG_FB_ATY
        { "atyfb", atyfb_init, atyfb_setup },
 #endif
@@ -122,7 +133,7 @@ static struct {
         { "igafb", igafb_init, igafb_setup },
 #endif
 #ifdef CONFIG_FB_IMSTT
-       { "imsttfb", imsttfb_init, NULL },
+       { "imsttfb", imsttfb_init, imsttfb_setup },
 #endif
 #ifdef CONFIG_APOLLO
        { "apollo", dnfb_init, NULL },
@@ -139,12 +150,12 @@ static struct {
 #ifdef CONFIG_FB_VESA
        { "vesa", vesafb_init, vesafb_setup },
 #endif 
+#ifdef CONFIG_FB_MATROX
+       { "matrox", matroxfb_init, matroxfb_setup },
+#endif
 #ifdef CONFIG_FB_HP300
        { "hpfb", hpfb_init, hpfb_setup },
 #endif 
-#ifdef CONFIG_FB_SBUS
-       { "sbus", sbusfb_init, sbusfb_setup },
-#endif
 #ifdef CONFIG_FB_VALKYRIE
        { "valkyriefb", valkyriefb_init, valkyriefb_setup },
 #endif
@@ -260,6 +271,23 @@ fb_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 }
 
 
+static int set_all_vcs(int fbidx, struct fb_ops *fb,
+                      struct fb_var_screeninfo *var, struct fb_info *info)
+{
+    int unit, err;
+
+    var->activate |= FB_ACTIVATE_TEST;
+    err = fb->fb_set_var(var, PROC_CONSOLE(), info);
+    var->activate &= ~FB_ACTIVATE_TEST;
+    if (err)
+           return err;
+    info->disp->var = *var;
+    for (unit = 0; unit < MAX_NR_CONSOLES; unit++)
+           if (fb_display[unit].conp && con2fb_map[unit] == fbidx)
+                   fb->fb_set_var(var, unit, info);
+    return 0;
+}
+
 static void set_con2fb_map(int unit, int newidx)
 {
     int oldidx = con2fb_map[unit];
@@ -334,7 +362,10 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        case FBIOPUT_VSCREENINFO:
                if (copy_from_user(&var, (void *) arg, sizeof(var)))
                        return -EFAULT;
-               if ((i = fb->fb_set_var(&var, PROC_CONSOLE(), info)))
+               i = var.activate & FB_ACTIVATE_ALL
+                           ? set_all_vcs(fbidx, fb, &var, info)
+                           : fb->fb_set_var(&var, PROC_CONSOLE(), info);
+               if (i)
                        return i;
                if (copy_to_user((void *) arg, &var, sizeof(var)))
                        return -EFAULT;
index 399548730f65667cb36b60d46814f2dc98ed0863..52ab1a6976828eb3305e661a9cf4e0d0d31a44cf 100644 (file)
@@ -90,7 +90,7 @@ struct fbcon_font_desc *fbcon_get_default_font(int xres, int yres)
     for(i=0; i<num_fonts; i++) {
        f = fbcon_fonts[i];
        c = f->pref;
-#ifdef __mc68000__
+#if defined(__mc68000__) || defined(CONFIG_APUS)
 #ifdef CONFIG_FONT_PEARL_8x8
        if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX)
            c = 100;
index b71973a3dd8dfada9fa5bccc5268a148d229723b..d50c403a6fddf50d745598ba1e69424b08bbab39 100644 (file)
@@ -130,17 +130,17 @@ enum {
        CLKCTL          = 0x02, /* (0x01) Miscellaneous Clock Control */
        SYNCCTL         = 0x03, /* (0x00) Sync Control */
        HSYNCPOS        = 0x04, /* (0x00) Horizontal Sync Position */
-       PWRMNGMT        = 0x05, /* (0x00) Power Management  [multiples of 4 unblack screen] */
-       DACOP           = 0x06, /* (0x02) DAC Operation  [0-3 coloured, 4-7 green, odd light, even dark] */
+       PWRMNGMT        = 0x05, /* (0x00) Power Management */
+       DACOP           = 0x06, /* (0x02) DAC Operation */
        PALETCTL        = 0x07, /* (0x00) Palette Control */
        SYSCLKCTL       = 0x08, /* (0x01) System Clock Control */
        PIXFMT          = 0x0a, /* () Pixel Format  [bpp >> 3 + 2] */
        BPP8            = 0x0b, /* () 8 Bits/Pixel Control */
-       BPP16           = 0x0c, /* () 16 Bits/Pixel Control  [15 or 1 for 555] */
+       BPP16           = 0x0c, /* () 16 Bits/Pixel Control  [bit 1=1 for 565] */
        BPP24           = 0x0d, /* () 24 Bits/Pixel Control */
        BPP32           = 0x0e, /* () 32 Bits/Pixel Control */
-       PIXCTL1         = 0x10, /* (0x05) Pixel PLL Control 1  [5-7 ok] */
-       PIXCTL2         = 0x11, /* (0x00) Pixel PLL Control 2  [multiples of 20 ok] */
+       PIXCTL1         = 0x10, /* (0x05) Pixel PLL Control 1 */
+       PIXCTL2         = 0x11, /* (0x00) Pixel PLL Control 2 */
        SYSCLKN         = 0x15, /* () System Clock N (System PLL Reference Divider) */
        SYSCLKM         = 0x16, /* () System Clock M (System PLL VCO Divider) */
        SYSCLKP         = 0x17, /* () System Clock P */
@@ -149,18 +149,19 @@ enum {
         * Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1)
         * c is charge pump bias which depends on the VCO frequency  
         */
-       PIXCLKM         = 0x20, /* () Pixel Clock M */
-       PIXCLKN         = 0x21, /* () Pixel Clock N */
-       PIXCLKP         = 0x22, /* () Pixel Clock P */
-       PIXCLKC         = 0x23, /* () Pixel Clock C */
-       CURSCTL         = 0x30, /* (0x00) Cursor Control  [1=curs1, 2=curs2, 5=curs3] */
+       PIXM0           = 0x20, /* () Pixel M 0 */
+       PIXN0           = 0x21, /* () Pixel N 0 */
+       PIXP0           = 0x22, /* () Pixel P 0 */
+       PIXC0           = 0x23, /* () Pixel C 0 */
+       CURSCTL         = 0x30, /* (0x00) Cursor Control */
        CURSXLO         = 0x31, /* () Cursor X position, low 8 bits */
        CURSXHI         = 0x32, /* () Cursor X position, high 8 bits */
        CURSYLO         = 0x33, /* () Cursor Y position, low 8 bits */
        CURSYHI         = 0x34, /* () Cursor Y position, high 8 bits */
-       CURSHOTX        = 0x35, /* () ???  [position relative to CURSX] */
-       CURSHOTY        = 0x36, /* () ???  [position relative to CURSY] */
-       CURSACAEN       = 0x37, /* () ???  [even=cursor on, odd=cursor off] */
+       CURSHOTX        = 0x35, /* () Cursor Hot Spot X */
+       CURSHOTY        = 0x36, /* () Cursor Hot Spot Y */
+       CURSACCTL       = 0x37, /* () Advanced Cursor Control Enable */
+       CURSACATTR      = 0x38, /* () Advanced Cursor Attribute */
        CURS1R          = 0x40, /* () Cursor 1 Red */
        CURS1G          = 0x41, /* () Cursor 1 Green */
        CURS1B          = 0x42, /* () Cursor 1 Blue */
@@ -238,7 +239,7 @@ struct initvalues {
        __u8 addr, value;
 };
 
-static struct initvalues ibm_initregs[] = {
+static struct initvalues ibm_initregs[] __initdata = {
        { CLKCTL,       0x21 },
        { SYNCCTL,      0x00 },
        { HSYNCPOS,     0x00 },
@@ -264,10 +265,18 @@ static struct initvalues ibm_initregs[] = {
        { SYSCLKM,      0x4f },
        { SYSCLKP,      0x00 },
        { SYSCLKC,      0x00 },
-       { CURSCTL,      0x00 },
+       { CURSCTL,      0x02 },
+       { CURSACCTL,    0x01 },
+       { CURSACATTR,   0xa8 },
+       { CURS1R,       0xff },
+       { CURS1G,       0xff },
+       { CURS1B,       0xff },
        { CURS2R,       0xff },
        { CURS2G,       0xff },
        { CURS2B,       0xff },
+       { CURS3R,       0xff },
+       { CURS3G,       0xff },
+       { CURS3B,       0xff },
        { BORDR,        0xff },
        { BORDG,        0xff },
        { BORDB,        0xff },
@@ -277,7 +286,7 @@ static struct initvalues ibm_initregs[] = {
        { KEYCTL,       0x00 }
 };
 
-static struct initvalues tvp_initregs[] = {
+static struct initvalues tvp_initregs[] __initdata = {
        { 0x6,  0x00 },
        { 0x7,  0xe4 },
        { 0xf,  0x06 },
@@ -320,12 +329,12 @@ struct imstt_regvals {
 };
 
 struct imstt_cursor {
+       struct timer_list timer;
        int enable;
        int on;
        int vbl_cnt;
        int blink_rate;
-       __u16 x, y;
-       struct timer_list timer;
+       __u16 x, y, width, height;
 };
 
 struct fb_info_imstt {
@@ -349,9 +358,9 @@ struct fb_info_imstt {
        } palette[256];
        struct imstt_regvals init;
        struct imstt_cursor cursor;
-       __u8 *frame_buffer_phys, *frame_buffer;
-       __u32 *dc_regs_phys, *dc_regs;
-       __u8 *cmap_regs_phys, *cmap_regs;
+       volatile __u8 *frame_buffer_phys, *frame_buffer;
+       volatile __u32 *dc_regs_phys, *dc_regs;
+       volatile __u8 *cmap_regs_phys, *cmap_regs;
        __u32 total_vram;
        __u32 ramdac;
 };
@@ -364,6 +373,12 @@ struct fb_info_imstt {
 #define CURSOR_DRAW_DELAY      2
 
 static int currcon = 0;
+static char fontname[40] __initdata = { 0 };
+static char curblink __initdata = 1;
+static char noaccel __initdata = 0;
+#if defined(CONFIG_PPC)
+static signed char init_vmode __initdata = -1, init_cmode __initdata = -1;
+#endif
 
 static struct imstt_regvals tvp_reg_init_2 = {
        512,
@@ -504,7 +519,7 @@ compute_imstt_regvals_ibm (struct fb_info_imstt *p, int xres, int yres)
 
        init->hes = hes;
        init->heb = heb;
-       init->hsb = init->heb + xres / 8;
+       init->hsb = init->heb + (xres >> 3);
        init->ht = init->hsb + htp;
        init->ves = 0x0003;
        init->veb = veb;
@@ -568,16 +583,15 @@ set_imstt_regvals_ibm (struct fb_info_imstt *p, u_int bpp)
        __u8 pformat = (bpp >> 3) + 2;
 
        p->cmap_regs[PIDXHI] = 0;               eieio();
-       p->cmap_regs[PIDXLO] = PIXCLKM;         eieio();
+       p->cmap_regs[PIDXLO] = PIXM0;           eieio();
        p->cmap_regs[PIDXDATA] = init->pclk_m;  eieio();
-       p->cmap_regs[PIDXLO] = PIXCLKN;         eieio();
+       p->cmap_regs[PIDXLO] = PIXN0;           eieio();
        p->cmap_regs[PIDXDATA] = init->pclk_n;  eieio();
-       p->cmap_regs[PIDXLO] = PIXCLKP;         eieio();
+       p->cmap_regs[PIDXLO] = PIXP0;           eieio();
        p->cmap_regs[PIDXDATA] = init->pclk_p;  eieio();
-       p->cmap_regs[PIDXLO] = PIXCLKC;         eieio();
+       p->cmap_regs[PIDXLO] = PIXC0;           eieio();
        p->cmap_regs[PIDXDATA] = 0x02;          eieio();
 
-       p->cmap_regs[PIDXHI] = 0;               eieio();
        p->cmap_regs[PIDXLO] = PIXFMT;          eieio();
        p->cmap_regs[PIDXDATA] = pformat;       eieio();
 }
@@ -652,7 +666,7 @@ static void
 set_imstt_regvals (struct fb_info_imstt *p, u_int bpp)
 {
        struct imstt_regvals *init = &p->init;
-       __u32 ctl, pitch, byteswap, scr;
+       __u32 ctl, pitch, byteswap, scr, line_pitch = init->pitch * (bpp >> 3);
 
        if (p->ramdac == IBM)
                set_imstt_regvals_ibm(p, bpp);
@@ -674,23 +688,23 @@ set_imstt_regvals (struct fb_info_imstt *p, u_int bpp)
        switch (bpp) {
                case 8:
                        ctl = 0x17b1;
-                       pitch = init->pitch / 4;
-                       byteswap = 0x0;
+                       pitch = init->pitch >> 2;
+                       byteswap = 0x000;
                        break;
                case 16:
                        ctl = 0x17b3;
-                       pitch = init->pitch / 2;
-                       byteswap = 0x1;
+                       pitch = init->pitch >> 1;
+                       byteswap = 0x100;
                        break;
                case 24:
                        ctl = 0x17b9;
-                       pitch = init->pitch - (p->init.pitch / 4);
-                       byteswap = 0x2;
+                       pitch = init->pitch - (p->init.pitch >> 2);
+                       byteswap = 0x200;
                        break;
                case 32:
                        ctl = 0x17b5;
                        pitch = init->pitch;
-                       byteswap = 0x3;
+                       byteswap = 0x300;
                        break;
        }
        if (p->ramdac == TVP)
@@ -712,7 +726,6 @@ set_imstt_regvals (struct fb_info_imstt *p, u_int bpp)
        out_le32(&p->dc_regs[RRSC], 0x980);
        out_le32(&p->dc_regs[RRCR], 0x11);
 
-       out_le32(&p->dc_regs[SSR], 0);
        if (p->ramdac == IBM) {
                out_le32(&p->dc_regs[HRIR], 0x0100);
                out_le32(&p->dc_regs[CMR], 0x00ff);
@@ -725,20 +738,19 @@ set_imstt_regvals (struct fb_info_imstt *p, u_int bpp)
 
        switch (p->total_vram) {
                case 0x00200000:
-                       scr = 0x059d | (byteswap << 8);
+                       scr = 0x059d | byteswap;
                        break;
                case 0x00400000:
-                       pitch /= 2;
-                       scr = 0xd0dc | (byteswap << 8);
-                       break;
                case 0x00800000:
                        pitch /= 2;
-                       scr = 0x150dd | (byteswap << 8);
+                       scr = 0x150dd | byteswap;
                        break;
        }
 
        out_le32(&p->dc_regs[SCR], scr);
        out_le32(&p->dc_regs[SPR], pitch);
+       out_le32(&p->dc_regs[SP], (line_pitch << 16) | line_pitch);
+       out_le32(&p->dc_regs[DP_OCTRL], line_pitch);
 
        out_le32(&p->dc_regs[STGCTL], ctl);
 }
@@ -755,8 +767,8 @@ set_16 (struct fb_info_imstt *p, __u8 x)
        }
 }
 
-#define set_555(_p)    set_16(_p, 15)
-#define set_565(_p)    set_16(_p, 0)   /* 220, 224 is darker in X */
+#define set_555(_p)    set_16(_p, 0x01)
+#define set_565(_p)    set_16(_p, 0x03)
 
 static void
 imstt_set_cursor (struct fb_info_imstt *p, int on)
@@ -765,19 +777,19 @@ imstt_set_cursor (struct fb_info_imstt *p, int on)
 
        p->cmap_regs[PIDXHI] = 0;
        if (!on) {
-               p->cmap_regs[PIDXLO] = CURSCTL;
-               p->cmap_regs[PIDXDATA] = 0x00;
+               p->cmap_regs[PIDXLO] = CURSCTL; eieio();
+               p->cmap_regs[PIDXDATA] = 0x00;  eieio();
        } else {
-               p->cmap_regs[PIDXLO] = CURSXHI;
-               p->cmap_regs[PIDXDATA] = c->x >> 8;
-               p->cmap_regs[PIDXLO] = CURSXLO;
-               p->cmap_regs[PIDXDATA] = c->x & 0xff;
-               p->cmap_regs[PIDXLO] = CURSYHI;
-               p->cmap_regs[PIDXDATA] = c->y >> 8;
-               p->cmap_regs[PIDXLO] = CURSYLO;
-               p->cmap_regs[PIDXDATA] = c->y & 0xff;
-               p->cmap_regs[PIDXLO] = CURSCTL;
-               p->cmap_regs[PIDXDATA] = 0x02;
+               p->cmap_regs[PIDXLO] = CURSXHI;         eieio();
+               p->cmap_regs[PIDXDATA] = c->x >> 8;     eieio();
+               p->cmap_regs[PIDXLO] = CURSXLO;         eieio();
+               p->cmap_regs[PIDXDATA] = c->x & 0xff;   eieio();
+               p->cmap_regs[PIDXLO] = CURSYHI;         eieio();
+               p->cmap_regs[PIDXDATA] = c->y >> 8;     eieio();
+               p->cmap_regs[PIDXLO] = CURSYLO;         eieio();
+               p->cmap_regs[PIDXDATA] = c->y & 0xff;   eieio();
+               p->cmap_regs[PIDXLO] = CURSCTL;         eieio();
+               p->cmap_regs[PIDXDATA] = 0x02;          eieio();
        }
 }
 
@@ -796,8 +808,8 @@ imsttfb_cursor (struct display *disp, int mode, int x, int y)
        c->enable = 0;
        if (c->on)
                imstt_set_cursor(p, 0);
-       c->x = x;
-       c->y = y;
+       c->x = x - disp->var.xoffset;
+       c->y = y - disp->var.yoffset;
 
        switch (mode) {
                case CM_ERASE:
@@ -817,6 +829,28 @@ imsttfb_cursor (struct display *disp, int mode, int x, int y)
 static int
 imsttfb_set_font (struct display *disp, int width, int height)
 {
+       struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info;
+       struct imstt_cursor *c = &p->cursor;
+       u_int x, y;
+
+       if (width > 32 || height > 32)
+               return -EINVAL;
+
+       c->height = height;
+       c->width = width;
+
+       p->cmap_regs[PIDXHI] = 1;       eieio();
+       for (x = 0; x < 0x100; x++) {
+               p->cmap_regs[PIDXLO] = x;       eieio();
+               p->cmap_regs[PIDXDATA] = 0x00;  eieio();
+       }
+       p->cmap_regs[PIDXHI] = 1;       eieio();
+       for (y = 0; y < height; y++)
+               for (x = 0; x < width >> 2; x++) {
+                       p->cmap_regs[PIDXLO] = x + y * 8;       eieio();
+                       p->cmap_regs[PIDXDATA] = 0xff;          eieio();
+               }
+
        return 1;
 }
 
@@ -845,64 +879,59 @@ imstt_cursor_init (struct fb_info_imstt *p))
 {
        struct imstt_cursor *c = &p->cursor;
 
+       imsttfb_set_font(&p->disp, fontwidth(&p->disp), fontheight(&p->disp));
+
        c->enable = 1;
        c->on = 1;
-       c->blink_rate = CURSOR_BLINK_RATE;
-       c->vbl_cnt = CURSOR_DRAW_DELAY;
        c->x = c->y = 0;
+       c->blink_rate = 0;
+       c->vbl_cnt = CURSOR_DRAW_DELAY;
 
-       init_timer(&c->timer);
-       c->timer.expires = jiffies + (HZ / 50);
-       c->timer.data = (unsigned long)p;
-       c->timer.function = imstt_cursor_timer_handler;
-       add_timer(&c->timer);
+       if (curblink) {
+               c->blink_rate = CURSOR_BLINK_RATE;
+               init_timer(&c->timer);
+               c->timer.expires = jiffies + (HZ / 50);
+               c->timer.data = (unsigned long)p;
+               c->timer.function = imstt_cursor_timer_handler;
+               add_timer(&c->timer);
+       }
 }
 
 static void
 imsttfb_rectcopy (struct display *disp, int sy, int sx, int dy, int dx, int height, int width)
 {
        struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info;
-       __u32 cnt_reg, stat, xxx = 0;
-       __u32   line_pitch = disp->var.xres * (disp->var.bits_per_pixel >> 3),
-               rect_height = height,
-               rect_width = width * (disp->var.bits_per_pixel >> 3),
-               fb_offset_old = sy * line_pitch + (sx * (disp->var.bits_per_pixel >> 3)),
-               fb_offset_new = dy * line_pitch + (dx * (disp->var.bits_per_pixel >> 3));
+       __u32   Bpp = disp->var.bits_per_pixel >> 3,
+               line_pitch = disp->line_length,
+               fb_offset_old, fb_offset_new;
 
-       stat = in_le32(&p->dc_regs[SSTATUS]) & 0xff;
+       fb_offset_old = sy * line_pitch + sx * Bpp;
+       fb_offset_new = dy * line_pitch + dx * Bpp;
 
-       cnt_reg = ((rect_height - 1) << 16) | (rect_width - 1);
-       out_le32(&p->dc_regs[CNT], cnt_reg);
+       while (in_le32(&p->dc_regs[SSTATUS]) & 0x80);
+       out_le32(&p->dc_regs[CNT], ((height - 1) << 16) | (width * Bpp - 1));
        out_le32(&p->dc_regs[S1SA], fb_offset_old);
-       out_le32(&p->dc_regs[DSA], fb_offset_old);
-       out_le32(&p->dc_regs[SP], line_pitch);
-       out_le32(&p->dc_regs[DP_OCTRL], line_pitch);
-       out_le32(&p->dc_regs[BLTCTL], 0x5);
-
-       if (++stat == 0x20)
-               stat = 0x10;
-       while ((in_le32(&p->dc_regs[SSTATUS]) & 0xff) != stat && xxx++ < 0xff)
-               eieio();
-
-       cnt_reg = ((rect_height - 1) << 16) | (0xffff - (rect_width - 2));
-       out_le32(&p->dc_regs[CNT], cnt_reg);
+       /* out_le32(&p->dc_regs[S2SA], fb_offset_new); */
        out_le32(&p->dc_regs[DSA], fb_offset_new);
-#if 0
-       out_le32(&p->dc_regs[S1SA], fb_offset_old);
-       out_le32(&p->dc_regs[SP], line_pitch);
-       out_le32(&p->dc_regs[DP_OCTRL], line_pitch);
-#endif
-       out_le32(&p->dc_regs[BLTCTL], 0x85);
-
-       if (++stat == 0x20)
-               stat = 0x10;
-       while ((in_le32(&p->dc_regs[SSTATUS]) & 0xff) != stat && xxx++ < 0xff)
-               eieio();
+       out_le32(&p->dc_regs[BLTCTL], 0xc0000005);
+       while (in_le32(&p->dc_regs[SSTATUS]) & 0x80);
+       while (in_le32(&p->dc_regs[SSTATUS]) & 0x40);
 }
 
 static void
 imsttfbcon_bmove (struct display *disp, int sy, int sx, int dy, int dx, int height, int width)
 {
+       /* XXX .. */
+       if (sy < dy || (sy == dy && sx < dx)) {
+               switch (disp->var.bits_per_pixel) {
+               case 8: fbcon_cfb8_bmove(disp, sy, sx, dy, dx, height, width); break;
+               case 16: fbcon_cfb16_bmove(disp, sy, sx, dy, dx, height, width); break;
+               case 24: fbcon_cfb24_bmove(disp, sy, sx, dy, dx, height, width); break;
+               case 32: fbcon_cfb32_bmove(disp, sy, sx, dy, dx, height, width); break;
+               }
+               return;
+       }
+
        sy *= fontheight(disp);
        sx *= fontwidth(disp);
        dy *= fontheight(disp);
@@ -1020,7 +1049,7 @@ imsttfb_setcolreg (u_int regno, u_int red, u_int green, u_int blue,
        p->palette[regno].blue = blue;
 
        /* PADDRW/PDATA are the same as TVPPADDRW/TVPPDATA */
-       if (p->ramdac == TVP && fb_display[currcon].var.green.length == 5 /* && bpp == 16 */) {
+       if (bpp == 16 && p->ramdac == TVP && fb_display[currcon].var.green.length == 5) {
                p->cmap_regs[PADDRW] = regno << 3;      eieio();
        } else {
                p->cmap_regs[PADDRW] = regno;           eieio();
@@ -1100,12 +1129,10 @@ imsttfb_get_var (struct fb_var_screeninfo *var, int con, struct fb_info *info)
 }
 
 static void
-set_dispsw (struct display *disp, struct fb_info_imstt *p)
+set_disp (struct display *disp, struct fb_info_imstt *p)
 {
        u_int accel = disp->var.accel_flags & FB_ACCELF_TEXT;
 
-       disp->visual = disp->var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
-                                                    : FB_VISUAL_DIRECTCOLOR;
        p->dispsw = fbcon_dummy;
        disp->dispsw = &p->dispsw;
        disp->dispsw_data = 0;
@@ -1124,7 +1151,7 @@ set_dispsw (struct display *disp, struct fb_info_imstt *p)
 #endif
                        break;
                case 16:        /* RGB 555 */
-                       if (disp->var.red.offset != 11)
+                       if (disp->var.green.length != 6)
                                disp->var.red.offset = 10;
                        disp->var.red.length = 5;
                        disp->var.green.offset = 5;
@@ -1173,6 +1200,47 @@ set_dispsw (struct display *disp, struct fb_info_imstt *p)
                p->dispsw.cursor = imsttfb_cursor;
                p->dispsw.set_font = imsttfb_set_font;
        }
+
+       disp->visual = disp->var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
+                                                    : FB_VISUAL_DIRECTCOLOR;
+       disp->screen_base = (__u8 *)p->frame_buffer;
+       disp->visual = p->fix.visual;
+       disp->type = p->fix.type;
+       disp->type_aux = p->fix.type_aux;
+       disp->line_length = disp->var.xres * (disp->var.bits_per_pixel >> 3);
+       disp->can_soft_blank = 1;
+       disp->inverse = 0;
+       disp->ypanstep = 1;
+       disp->ywrapstep = 0;
+       if (accel) {
+               disp->scrollmode = SCROLL_YNOMOVE;
+               if (disp->var.yres == disp->var.yres_virtual) {
+                       __u32 vram = (p->total_vram - (PAGE_SIZE << 2));
+                       disp->var.yres_virtual = ((vram << 3) / disp->var.bits_per_pixel) / disp->var.xres_virtual;
+                       if (disp->var.yres_virtual < disp->var.yres)
+                               disp->var.yres_virtual = disp->var.yres;
+               }
+       } else {
+               disp->scrollmode = SCROLL_YREDRAW;
+               disp->var.yoffset = disp->var.xoffset = 0;
+               out_le32(&p->dc_regs[SSR], 0);
+       }
+
+       disp->var.activate = 0;
+       disp->var.red.msb_right = 0;
+       disp->var.green.msb_right = 0;
+       disp->var.blue.msb_right = 0;
+       disp->var.transp.msb_right = 0;
+       disp->var.height = -1;
+       disp->var.width = -1;
+       disp->var.vmode = FB_VMODE_NONINTERLACED;
+       disp->var.left_margin = disp->var.right_margin = 16;
+       disp->var.upper_margin = disp->var.lower_margin = 16;
+       disp->var.hsync_len = disp->var.vsync_len = 8;
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+       set_display_info(disp);
+#endif
 }
 
 static int
@@ -1180,7 +1248,7 @@ imsttfb_set_var (struct fb_var_screeninfo *var, int con, struct fb_info *info)
 {
        struct fb_info_imstt *p = (struct fb_info_imstt *)info;
        struct display *disp;
-       u_int oldbpp, oldxres, oldyres, oldgreenlen, oldaccel;
+       u_int oldbpp, oldxres, oldyres, oldgreenlen;
 
        disp = &fb_display[con];
 
@@ -1205,37 +1273,16 @@ imsttfb_set_var (struct fb_var_screeninfo *var, int con, struct fb_info *info)
        oldxres = disp->var.xres;
        oldyres = disp->var.yres;
        oldgreenlen = disp->var.green.length;
-       oldaccel = disp->var.accel_flags;
-
-       disp->var = *var;
-
-       disp->var.activate = 0;
-       disp->var.red.msb_right = 0;
-       disp->var.green.msb_right = 0;
-       disp->var.blue.msb_right = 0;
-       disp->var.transp.msb_right = 0;
-       disp->var.height = -1;
-       disp->var.width = -1;
-       disp->var.vmode = FB_VMODE_NONINTERLACED;
-       disp->var.left_margin = disp->var.right_margin = 16;
-       disp->var.upper_margin = disp->var.lower_margin = 16;
-       disp->var.hsync_len = disp->var.vsync_len = 8;
 
-       disp->screen_base = p->frame_buffer;
-       disp->inverse = 0;
-       disp->ypanstep = 1;
-       disp->ywrapstep = 0;
-       disp->scrollmode = SCROLL_YREDRAW;
+       disp->var.bits_per_pixel = var->bits_per_pixel;
+       disp->var.xres = var->xres;
+       disp->var.yres = var->yres;
+       disp->var.xres_virtual = var->xres_virtual;
+       disp->var.yres_virtual = var->yres_virtual;
+       disp->var.green.length = var->green.length;
+       disp->var.accel_flags = var->accel_flags;
 
-       if (oldbpp != disp->var.bits_per_pixel || oldgreenlen != disp->var.green.length || oldaccel != disp->var.accel_flags)
-               set_dispsw(disp, p);
-
-       if (oldxres != disp->var.xres || oldbpp != disp->var.bits_per_pixel)
-               disp->line_length = disp->var.xres * (disp->var.bits_per_pixel >> 3);
-
-#ifdef CONFIG_FB_COMPAT_XPMAC
-       set_display_info(disp);
-#endif
+       set_disp(disp, p);
 
        if (info->changevar)
                (*info->changevar)(con);
@@ -1267,17 +1314,18 @@ static int
 imsttfb_pan_display (struct fb_var_screeninfo *var, int con, struct fb_info *info)
 {
        struct fb_info_imstt *p = (struct fb_info_imstt *)info;
-       u_int off;
+       struct display *disp = &fb_display[con];
+       __u32 off;
 
-       if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual
-           || var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+       if (var->xoffset + disp->var.xres > disp->var.xres_virtual
+           || var->yoffset + disp->var.yres > disp->var.yres_virtual)
                return -EINVAL;
 
-       fb_display[con].var.xoffset = var->xoffset;
-       fb_display[con].var.yoffset = var->yoffset;
+       disp->var.xoffset = var->xoffset;
+       disp->var.yoffset = var->yoffset;
        if (con == currcon) {
-               off = var->yoffset * (fb_display[con].line_length / 8)
-                     + (var->xoffset * (fb_display[con].var.bits_per_pixel >> 3)) / 8;
+               off = var->yoffset * (disp->line_length >> 3)
+                     + ((var->xoffset * (disp->var.bits_per_pixel >> 3)) >> 3);
                out_le32(&p->dc_regs[SSR], off);
        }
 
@@ -1321,8 +1369,8 @@ imsttfb_set_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
 #define FBIMSTT_GETREG         0x545402
 #define FBIMSTT_SETCMAPREG     0x545403
 #define FBIMSTT_GETCMAPREG     0x545404
-#define FBIMSTT_SETINITREG     0x545405
-#define FBIMSTT_GETINITREG     0x545406
+#define FBIMSTT_SETIDXREG      0x545405
+#define FBIMSTT_GETIDXREG      0x545406
 
 static int
 imsttfb_ioctl (struct inode *inode, struct file *file, u_int cmd,
@@ -1337,34 +1385,34 @@ imsttfb_ioctl (struct inode *inode, struct file *file, u_int cmd,
                        if (copy_from_user(reg, (void *)arg, 8) || reg[0] > (0x40000 - sizeof(reg[0])) / sizeof(reg[0]))
                                return -EFAULT;
                        out_le32(&p->dc_regs[reg[0]], reg[1]);
-                       break;
+                       return 0;
                case FBIMSTT_GETREG:
                        if (copy_from_user(reg, (void *)arg, 4) || reg[0] > (0x40000 - sizeof(reg[0])) / sizeof(reg[0]))
                                return -EFAULT;
                        reg[1] = in_le32(&p->dc_regs[reg[0]]);
                        if (copy_to_user((void *)(arg + 4), &reg[1], 4))
                                return -EFAULT;
-                       break;
+                       return 0;
                case FBIMSTT_SETCMAPREG:
                        if (copy_from_user(reg, (void *)arg, 8) || reg[0] > (0x17c0000 - sizeof(reg[0])) / sizeof(reg[0]))
                                return -EFAULT;
                        out_le32(&((u_int *)p->cmap_regs)[reg[0]], reg[1]);
-                       break;
+                       return 0;
                case FBIMSTT_GETCMAPREG:
                        if (copy_from_user(reg, (void *)arg, 4) || reg[0] > (0x17c0000 - sizeof(reg[0])) / sizeof(reg[0]))
                                return -EFAULT;
                        reg[1] = in_le32(&((u_int *)p->cmap_regs)[reg[0]]);
                        if (copy_to_user((void *)(arg + 4), &reg[1], 4))
                                return -EFAULT;
-                       break;
-               case FBIMSTT_SETINITREG:
+                       return 0;
+               case FBIMSTT_SETIDXREG:
                        if (copy_from_user(init, (void *)arg, 2))
                                return -EFAULT;
                        p->cmap_regs[PIDXHI] = 0;               eieio();
                        p->cmap_regs[PIDXLO] = init[0];         eieio();
                        p->cmap_regs[PIDXDATA] = init[1];       eieio();
-                       break;
-               case FBIMSTT_GETINITREG:
+                       return 0;
+               case FBIMSTT_GETIDXREG:
                        if (copy_from_user(init, (void *)arg, 1))
                                return -EFAULT;
                        p->cmap_regs[PIDXHI] = 0;               eieio();
@@ -1372,12 +1420,10 @@ imsttfb_ioctl (struct inode *inode, struct file *file, u_int cmd,
                        init[1] = p->cmap_regs[PIDXDATA];
                        if (copy_to_user((void *)(arg + 1), &init[1], 1))
                                return -EFAULT;
-                       break;
+                       return 0;
                default:
                        return -ENOIOCTLCMD;
        }
-
-       return 0;
 }
 
 static struct fb_ops imsttfb_ops = {
@@ -1397,6 +1443,7 @@ imsttfbcon_switch (int con, struct fb_info *info)
 {
        struct fb_info_imstt *p = (struct fb_info_imstt *)info;
        struct display *old = &fb_display[currcon], *new = &fb_display[con];
+       __u32 off;
 
        if (old->cmap.len)
                fb_get_cmap(&old->cmap, 1, imsttfb_getcolreg, info);
@@ -1410,7 +1457,7 @@ imsttfbcon_switch (int con, struct fb_info *info)
            || old->var.yres != new->var.yres
            || old->var.bits_per_pixel != new->var.bits_per_pixel
            || old->var.green.length != new->var.green.length) {
-               set_dispsw(new, p);
+               set_disp(new, p);
                if (!compute_imstt_regvals(p, new->var.xres, new->var.yres))
                        return -1;
                if (new->var.bits_per_pixel == 16) {
@@ -1420,9 +1467,11 @@ imsttfbcon_switch (int con, struct fb_info *info)
                                set_555(p);
                }
                set_imstt_regvals(p, new->var.bits_per_pixel);
-#ifdef CONFIG_FB_COMPAT_XPMAC
-               set_display_info(new);
-#endif
+       }
+       if (old->var.yoffset != new->var.yoffset || old->var.xoffset != new->var.xoffset) {
+               off = new->var.yoffset * (new->line_length >> 3)
+                     + ((new->var.xoffset * (new->var.bits_per_pixel >> 3)) >> 3);
+               out_le32(&p->dc_regs[SSR], off);
        }
 
        do_install_cmap(con, info);
@@ -1430,18 +1479,44 @@ imsttfbcon_switch (int con, struct fb_info *info)
        return 0;
 }
 
+static inline void
+imsttfb_rectfill (struct display *disp, u_int sy, u_int sx, u_int height, u_int width, __u32 bgx)
+{
+       memset(disp->screen_base + sy + sx, bgx, height * width * (disp->var.bits_per_pixel >> 3));
+}
+
 static int
 imsttfbcon_updatevar (int con, struct fb_info *info)
 {
        struct fb_info_imstt *p = (struct fb_info_imstt *)info;
-       u_int off;
+       struct display *disp = &fb_display[con];
+       struct vc_data *conp = disp->conp;
+       __u32 off, yres, yoffset, sy, height;
 
-       if (con == currcon) {
-               off = fb_display[con].var.yoffset * (fb_display[con].line_length / 8)
-                     + (fb_display[con].var.xoffset * (fb_display[con].var.bits_per_pixel >> 3)) / 8;
-               out_le32(&p->dc_regs[SSR], off);
+       if (con != currcon)
+               goto out;
+
+       yres = disp->var.yres;
+       yoffset = disp->var.yoffset;
+       sy = (conp->vc_rows + disp->yscroll) * fontheight(disp);
+       height = yres - conp->vc_rows * fontheight(disp);
+
+       if (height && (yoffset + yres > sy)) {
+               __u32 bgx = attr_bgcol_ec(disp, conp);
+
+               if (sy + height > disp->var.yres_virtual)
+                       printk("updatevar: %u + %u > %u\n", sy, height, disp->var.yres_virtual);
+               imsttfb_rectfill(disp, sy, disp->var.xoffset, height, disp->var.xres, bgx);
        }
 
+       if (p->ramdac == IBM && (yoffset + yres <= sy))
+               imsttfb_cursor(disp, CM_ERASE, p->cursor.x, p->cursor.y);
+
+       off = disp->var.yoffset * (disp->line_length >> 3)
+             + ((disp->var.xoffset * (disp->var.bits_per_pixel >> 3)) >> 3); 
+       out_le32(&p->dc_regs[SSR], off);
+
+out:
        return 0;
 }
 
@@ -1455,7 +1530,21 @@ imsttfbcon_blank (int blank, struct fb_info *info)
        if (blank > 0) {
                switch (blank - 1) {
                        case VESA_NO_BLANKING:
+                       case VESA_POWERDOWN:
                                ctrl &= ~0x00000380;
+                               if (p->ramdac == IBM) {
+                                       p->cmap_regs[PIDXHI] = 0;       eieio();
+                                       p->cmap_regs[PIDXLO] = MISCTL2; eieio();
+                                       p->cmap_regs[PIDXDATA] = 0x55;  eieio();
+                                       p->cmap_regs[PIDXLO] = MISCTL1; eieio();
+                                       p->cmap_regs[PIDXDATA] = 0x11;  eieio();
+                                       p->cmap_regs[PIDXLO] = SYNCCTL; eieio();
+                                       p->cmap_regs[PIDXDATA] = 0x0f;  eieio();
+                                       p->cmap_regs[PIDXLO] = PWRMNGMT;eieio();
+                                       p->cmap_regs[PIDXDATA] = 0x1f;  eieio();
+                                       p->cmap_regs[PIDXLO] = CLKCTL;  eieio();
+                                       p->cmap_regs[PIDXDATA] = 0xc0;
+                               }
                                break;
                        case VESA_VSYNC_SUSPEND:
                                ctrl &= ~0x00000020;
@@ -1463,12 +1552,23 @@ imsttfbcon_blank (int blank, struct fb_info *info)
                        case VESA_HSYNC_SUSPEND:
                                ctrl &= ~0x00000010;
                                break;
-                       case VESA_POWERDOWN:
-                               ctrl &= ~0x00000380;
-                               break;
                }
        } else {
-               ctrl |= p->ramdac == IBM ? 0x000017b0 : 0x00001780;
+               if (p->ramdac == IBM) {
+                       ctrl |= 0x000017b0;
+                       p->cmap_regs[PIDXHI] = 0;       eieio();
+                       p->cmap_regs[PIDXLO] = CLKCTL;  eieio();
+                       p->cmap_regs[PIDXDATA] = 0x01;  eieio();
+                       p->cmap_regs[PIDXLO] = PWRMNGMT;eieio();
+                       p->cmap_regs[PIDXDATA] = 0x00;  eieio();
+                       p->cmap_regs[PIDXLO] = SYNCCTL; eieio();
+                       p->cmap_regs[PIDXDATA] = 0x00;  eieio();
+                       p->cmap_regs[PIDXLO] = MISCTL1; eieio();
+                       p->cmap_regs[PIDXDATA] = 0x01;  eieio();
+                       p->cmap_regs[PIDXLO] = MISCTL2; eieio();
+                       p->cmap_regs[PIDXDATA] = 0x45;  eieio();
+               } else
+                       ctrl |= 0x00001780;
        }
        out_le32(&p->dc_regs[STGCTL], ctrl);
 }
@@ -1477,6 +1577,7 @@ __initfunc(static void
 init_imstt(struct fb_info_imstt *p))
 {
        __u32 i, tmp;
+       __u32 *ip, *end;
 
        tmp = in_le32(&p->dc_regs[PRC]);
        if (p->ramdac == IBM)
@@ -1484,15 +1585,19 @@ init_imstt(struct fb_info_imstt *p))
        else
                p->total_vram = 0x00800000;
 
-       memset(p->frame_buffer, 0, p->total_vram);
+       ip = (__u32 *)p->frame_buffer;
+       end = (__u32 *)(p->frame_buffer + p->total_vram);
+       while (ip < end)
+               *ip++ = 0;
 
        /* initialize the card */
        tmp = in_le32(&p->dc_regs[STGCTL]);
        out_le32(&p->dc_regs[STGCTL], tmp & ~0x1);
+       out_le32(&p->dc_regs[SSR], 0);
 
        /* set default values for DAC registers */ 
        if (p->ramdac == IBM) {
-               p->cmap_regs[PPMASK] = 0xff;
+               p->cmap_regs[PPMASK] = 0xff;    eieio();
                p->cmap_regs[PIDXHI] = 0;       eieio();
                for (i = 0; i < sizeof(ibm_initregs) / sizeof(*ibm_initregs); i++) {
                        p->cmap_regs[PIDXLO] = ibm_initregs[i].addr;    eieio();
@@ -1507,14 +1612,18 @@ init_imstt(struct fb_info_imstt *p))
 
 #if USE_NV_MODES && defined(CONFIG_PPC)
        {
-               int vmode, cmode;
-
-               vmode = nvram_read_byte(NV_VMODE);
-               if (vmode <= 0 || vmode > VMODE_MAX)
-                       vmode = VMODE_640_480_67;
-               cmode = nvram_read_byte(NV_CMODE);
-               if (cmode < CMODE_8 || cmode > CMODE_32)
-                       cmode = CMODE_8;
+               int vmode = init_vmode, cmode = init_cmode;
+
+               if (vmode == -1) {
+                       vmode = nvram_read_byte(NV_VMODE);
+                       if (vmode <= 0 || vmode > VMODE_MAX)
+                               vmode = VMODE_640_480_67;
+               }
+               if (cmode == -1) {
+                       cmode = nvram_read_byte(NV_CMODE);
+                       if (cmode < CMODE_8 || cmode > CMODE_32)
+                               cmode = CMODE_8;
+               }
                if (mac_vmode_to_var(vmode, cmode, &p->disp.var)) {
                        p->disp.var.xres = p->disp.var.xres_virtual = INIT_XRES;
                        p->disp.var.yres = p->disp.var.yres_virtual = INIT_YRES;
@@ -1527,22 +1636,6 @@ init_imstt(struct fb_info_imstt *p))
        p->disp.var.bits_per_pixel = INIT_BPP;
 #endif
 
-       p->disp.var.height = p->disp.var.width = -1;
-       p->disp.var.vmode = FB_VMODE_NONINTERLACED;
-       p->disp.var.left_margin = p->disp.var.right_margin = 16;
-       p->disp.var.upper_margin = p->disp.var.lower_margin = 16;
-       p->disp.var.hsync_len = p->disp.var.vsync_len = 8;
-       p->disp.var.accel_flags = 0; /* FB_ACCELF_TEXT; */
-
-       set_dispsw(&p->disp, p);
-       if (p->ramdac == IBM)
-               imstt_cursor_init(p);
-
-       if (p->disp.var.green.length == 6)
-               set_565(p);
-       else
-               set_555(p);
-
        if ((p->disp.var.xres * p->disp.var.yres) * (p->disp.var.bits_per_pixel >> 3) > p->total_vram
            || !(compute_imstt_regvals(p, p->disp.var.xres, p->disp.var.yres))) {
                printk("imsttfb: %ux%ux%u not supported\n", p->disp.var.xres, p->disp.var.yres, p->disp.var.bits_per_pixel);
@@ -1550,10 +1643,6 @@ init_imstt(struct fb_info_imstt *p))
                return;
        }
 
-       set_imstt_regvals(p, p->disp.var.bits_per_pixel);
-
-       p->disp.var.pixclock = 1000000 / getclkMHz(p);
-
        sprintf(p->fix.id, "IMS TT (%s)", p->ramdac == IBM ? "IBM" : "TVP");
        p->fix.smem_start = (__u8 *)p->frame_buffer_phys;
        p->fix.smem_len = p->total_vram;
@@ -1568,21 +1657,24 @@ init_imstt(struct fb_info_imstt *p))
        p->fix.ypanstep = 1;
        p->fix.ywrapstep = 0;
 
-       p->disp.screen_base = p->frame_buffer;
-       p->disp.visual = p->fix.visual;
-       p->disp.type = p->fix.type;
-       p->disp.type_aux = p->fix.type_aux;
-       p->disp.line_length = p->fix.line_length;
-       p->disp.can_soft_blank = 1;
-       p->disp.ypanstep = 1;
-       p->disp.ywrapstep = 0;
-       p->disp.scrollmode = SCROLL_YREDRAW;
+       p->disp.var.accel_flags = noaccel ? 0 : FB_ACCELF_TEXT;
+       set_disp(&p->disp, p);
+
+       if (p->ramdac == IBM)
+               imstt_cursor_init(p);
+       if (p->disp.var.green.length == 6)
+               set_565(p);
+       else
+               set_555(p);
+       set_imstt_regvals(p, p->disp.var.bits_per_pixel);
+
+       p->disp.var.pixclock = 1000000 / getclkMHz(p);
 
        strcpy(p->info.modename, p->fix.id);
+       strcpy(p->info.fontname, fontname);
        p->info.node = -1;
        p->info.fbops = &imsttfb_ops;
        p->info.disp = &p->disp;
-       p->info.fontname[0] = 0;
        p->info.changevar = 0;
        p->info.switch_con = &imsttfbcon_switch;
        p->info.updatevar = &imsttfbcon_updatevar;
@@ -1606,18 +1698,18 @@ init_imstt(struct fb_info_imstt *p))
                GET_FB_IDX(p->info.node), p->fix.id, p->total_vram >> 20, tmp);
 
 #ifdef CONFIG_FB_COMPAT_XPMAC
-       strncpy(display_info.name, p->fix.id, sizeof display_info.name);
+       strncpy(display_info.name, "IMS,tt128mb", sizeof(display_info.name));
        display_info.fb_address = (__u32)p->frame_buffer_phys;
        display_info.cmap_adr_address = (__u32)&p->cmap_regs_phys[PADDRW];
        display_info.cmap_data_address = (__u32)&p->cmap_regs_phys[PDATA];
-       display_info.disp_reg_address = 0;
+       display_info.disp_reg_address = (__u32)p->dc_regs_phys;
        set_display_info(&p->disp);
        if (!console_fb_info)
                console_fb_info = &p->info;
 #endif /* CONFIG_FB_COMPAT_XPMAC */
 }
 
-#if defined(CONFIG_FB_OF) || defined(CONFIG_PPC)
+#if defined(CONFIG_FB_OF)
 __initfunc(void
 imsttfb_of_init(struct device_node *dp))
 {
@@ -1667,22 +1759,60 @@ imsttfb_of_init(struct device_node *dp))
 __initfunc(void
 imsttfb_init(void))
 {
-#if defined(CONFIG_PPC)
-       u_int i;
-       struct device_node *dp;
-       char *names[4] = {"IMS,tt128mb","IMS,tt128mbA","IMS,tt128mb8","IMS,tt128mb8A"};
+#if !defined(CONFIG_FB_OF)
+       /* ... */
+#endif
+}
+
+__initfunc(void
+imsttfb_setup(char *options, int *ints))
+{
+       char *this_opt;
 
-#ifdef CONFIG_FB_OF
-       if (prom_num_displays)
+       if (!options || !*options)
                return;
-#endif
 
-       for (i = 0; i < 4; i++) {
-               dp = find_devices(names[i]);
-               if (dp)
-                       imsttfb_of_init(dp);
-       }
-#else
-       /* ... */
+       for (this_opt = strtok(options, ","); this_opt;
+            this_opt = strtok(NULL, ",")) {
+               if (!strncmp(this_opt, "font:", 5)) {
+                       char *p;
+                       int i;
+
+                       p = this_opt + 5;
+                       for (i = 0; i < sizeof(fontname) - 1; i++)
+                               if (!*p || *p == ' ' || *p == ',')
+                                       break;
+                       memcpy(fontname, this_opt + 5, i);
+                       fontname[i] = 0;
+               } else if (!strncmp(this_opt, "noblink", 7)) {
+                       curblink = 0;
+               } else if (!strncmp(this_opt, "noaccel", 7)) {
+                       noaccel = 1;
+               }
+#if defined(CONFIG_PPC)
+               else if (!strncmp(this_opt, "vmode:", 6)) {
+                       int vmode = simple_strtoul(this_opt+6, NULL, 0);
+                       if (vmode > 0 && vmode <= VMODE_MAX)
+                               init_vmode = vmode;
+               } else if (!strncmp(this_opt, "cmode:", 6)) {
+                       int cmode = simple_strtoul(this_opt+6, NULL, 0);
+                       switch (cmode) {
+                               case CMODE_8:
+                               case 8:
+                                       init_cmode = CMODE_8;
+                                       break;
+                               case CMODE_16:
+                               case 15:
+                               case 16:
+                                       init_cmode = CMODE_16;
+                                       break;
+                               case CMODE_32:
+                               case 24:
+                               case 32:
+                                       init_cmode = CMODE_32;
+                                       break;
+                       }
+               }
 #endif
+       }
 }
diff --git a/drivers/video/matroxfb.c b/drivers/video/matroxfb.c
new file mode 100644 (file)
index 0000000..4d1d8e5
--- /dev/null
@@ -0,0 +1,4373 @@
+/*
+ *
+ * Hardware accelerated Matrox Millenium I, II, Mystique and G200
+ *
+ * (c) 1998 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Version: 1.3 1998/10/28 
+ *
+ * MTRR stuff: 1998 Tom Rini <tmrini@ntplx.net>
+ *
+ * Contributors: "menion?" <menion@mindless.com>
+ *                     Betatesting, fixes, ideas
+ *
+ *               "Kurt Garloff" <garloff@kg1.ping.de>
+ *                     Betatesting, fixes, ideas, videomodes, videomodes timmings
+ *
+ *               "Tom Rini" <tmrini@ntplx.net>
+ *                     MTRR stuff, betatesting, fixes, ideas
+ *
+ *               "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
+ *                     Betatesting
+ *
+ *               "Kelly French" <targon@hazmat.com>
+ *                     Betatesting, bug reporting
+ *
+ *               "Pablo Bianucci" <pbian@pccp.com.ar>
+ *                     Fixes, ideas, betatesting
+ *
+ *               "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
+ *                     Fixes, enhandcements, ideas, betatesting
+ *
+ *               "Paul Womar" <Paul@pwomar.demon.co.uk>
+ *               "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
+ *               "Owen Waller" <O.Waller@ee.qub.ac.uk>
+ *                     PPC betatesting 
+ *                     
+ * (following author is not in any relation with this code, but his code
+ *  is included in this driver)
+ *
+ * Based on framebuffer driver for VBE 2.0 compliant graphic boards
+ *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * (following author is not in any relation with this code, but his ideas
+ *  were used when writting this driver)
+ *
+ *              FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
+ *
+ */ 
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb4.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#ifndef __i386__
+#ifndef ioremap_nocache
+#define ioremap_nocache(X,Y) ioremap(X,Y)
+#endif 
+#endif
+
+#ifdef DEBUG
+#define dprintk(X...)  printk(X)
+#else
+#define dprintk(X...)
+#endif
+
+#ifndef PCI_SS_VENDOR_ID_SIEMENS_NIXDORF
+#define PCI_SS_VENDOR_ID_SIEMENS_NIXDORF       0x110A
+#endif
+#ifndef PCI_SS_VENDOR_ID_MATROX
+#define PCI_SS_VENDOR_ID_MATROX                PCI_VENDOR_ID_MATROX
+#endif
+#ifndef PCI_DEVICE_ID_MATROX_G200_AGP
+#define PCI_DEVICE_ID_MATROX_G200_AGP  0x0521
+#endif
+#ifndef PCI_DEVICE_ID_MATROX_G100
+#define PCI_DEVICE_ID_MATROX_G100      0x1000
+#endif
+#ifndef PCI_DEVICE_ID_MATROX_G100_AGP
+#define PCI_DEVICE_ID_MATROX_G100_AGP  0x1001
+#endif
+
+#ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP
+#define PCI_SS_ID_MATROX_UNSPECIFIED           0xFF00
+#define PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP   0xFF01
+#define PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP     0xFF02
+#define PCI_SS_ID_MATROX_MILLENIUM_G200_AGP    0xFF03
+#define PCI_SS_ID_MATROX_MARVEL_G200_AGP       0xFF04
+#define PCI_SS_ID_MATROX_MGA_G100_PCI          0xFF05
+#define PCI_SS_ID_MATROX_MGA_G100_AGP          0x1001
+#define PCI_SS_ID_SIEMENS_MGA_G100_AGP         0x001E /* 30 */
+#define PCI_SS_ID_SIEMENS_MGA_G200_AGP         0x0032 /* 50 */
+#endif
+
+#define MX_VISUAL_TRUECOLOR    FB_VISUAL_DIRECTCOLOR
+#define MX_VISUAL_DIRECTCOLOR  FB_VISUAL_TRUECOLOR
+#define MX_VISUAL_PSEUDOCOLOR  FB_VISUAL_PSEUDOCOLOR
+
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+
+/* G100, G200 and Mystique have (almost) same DAC */
+#undef NEED_DAC1064
+#if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G100)
+#define NEED_DAC1064 1
+#endif
+
+struct matroxfb_par
+{
+       struct fb_var_screeninfo var;
+
+       unsigned int    final_bppShift;
+       int             visual;         /* unfortunately, fix */
+       int             video_type;
+       int             cmap_len;
+};
+
+struct my_timming {
+       unsigned int pixclock;
+       unsigned int HDisplay;
+       unsigned int HSyncStart;
+       unsigned int HSyncEnd;
+       unsigned int HTotal;
+       unsigned int VDisplay;
+       unsigned int VSyncStart;
+       unsigned int VSyncEnd;
+       unsigned int VTotal;
+       unsigned int sync;
+       int          dblscan;
+       int          interlaced;
+};
+
+struct matrox_fb_info;
+
+#define MATROX_2MB_WITH_4MB_ADDON
+
+struct matrox_pll_features {
+       unsigned int    vco_freq_min;   
+       unsigned int    ref_freq;
+       unsigned int    feed_div_min;
+       unsigned int    feed_div_max;
+       unsigned int    in_div_min;
+       unsigned int    in_div_max;
+       unsigned int    post_shift_max;
+};
+
+struct matrox_DAC1064_features {
+       u_int8_t        xvrefctrl;
+};
+
+struct matrox_accel_features {
+       int             has_cacheflush;
+};
+
+/* current hardware status */
+struct matrox_hw_state {
+       u_int32_t       MXoptionReg;
+       unsigned char   DACclk[6];
+       unsigned char   DACreg[64];
+       unsigned char   MiscOutReg;
+       unsigned char   DACpal[768];
+       unsigned char   CRTC[25];
+       unsigned char   CRTCEXT[6];
+       unsigned char   SEQ[5];
+       /* unused for MGA mode, but who knows... */
+       unsigned char   GCTL[9];
+       /* unused for MGA mode, but who knows... */
+       unsigned char   ATTR[21];
+};
+
+struct matrox_accel_data {
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+       unsigned char   ramdac_rev;
+#endif
+       u_int32_t       m_dwg_rect;
+};
+
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+#define ACCESS_FBINFO(x) (minfo->x)
+#define ACCESS_FBINFO2(info, x) (((struct matrox_fb_info*)info)->x)
+
+#define MINFO minfo
+
+#define WPMINFO struct matrox_fb_info* minfo,
+#define CPMINFO        const struct matrox_fb_info* minfo,
+#define PMINFO  minfo,
+
+static struct matrox_fb_info* mxinfo(struct display* p) {
+       return (struct matrox_fb_info*)p->fb_info;
+}
+
+#define PMXINFO(p) mxinfo(p),
+#define MINFO_FROM_DISP(x) struct matrox_fb_info* minfo = mxinfo(x)
+
+#else
+
+struct matrox_fb_info global_mxinfo;
+struct display global_disp;
+
+#define ACCESS_FBINFO(x) (global_mxinfo.x)
+#define ACCESS_FBINFO2(info, x) (global_mxinfo.x)
+
+#define MINFO (&global_mxinfo)
+
+#define WPMINFO
+#define CPMINFO
+#define PMINFO
+
+#if 0
+static struct matrox_fb_info* mxinfo(struct display* p) {
+       return &global_mxinfo;
+}
+#endif
+
+#define PMXINFO(p)
+#define MINFO_FROM_DISP(x)
+
+#endif
+
+struct matrox_switch {
+       int     (*preinit)(WPMINFO struct matrox_hw_state*);
+       void    (*reset)(WPMINFO struct matrox_hw_state*);
+       int     (*init)(CPMINFO struct matrox_hw_state*, struct my_timming*);
+       void    (*restore)(WPMINFO struct matrox_hw_state*, struct matrox_hw_state*, struct display*);
+};
+
+struct matrox_fb_info {
+       /* fb_info must be first */
+       struct fb_info          fbcon;
+
+       struct matrox_fb_info*  next_fb;
+
+       struct matroxfb_par     curr;
+       struct matrox_hw_state  hw1;
+       struct matrox_hw_state  hw2;
+       struct matrox_hw_state* newhw;
+       struct matrox_hw_state* currenthw;
+
+       struct matrox_accel_data accel;
+
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+       unsigned int    _mga_ydstorg;
+       unsigned int    _curr_ydstorg;
+#endif
+
+       struct pci_dev*         pcidev;
+
+       unsigned long   video_base;     /* physical */
+       char*           video_vbase;    /* CPU view */
+       unsigned int    video_len;
+
+       unsigned long   mmio_base;      /* physical */
+       unsigned char*  mmio;           /* CPU view */
+       unsigned int    mmio_len;
+
+       unsigned int    max_pixel_clock;
+
+       struct matrox_switch*   hw_switch;
+       int             currcon;
+
+       struct {
+               struct matrox_pll_features pll;
+               struct matrox_DAC1064_features DAC1064;
+               struct matrox_accel_features accel;
+               } features;
+
+       int                     interleave;
+       int                     millenium;
+       int                     milleniumII;
+       struct {
+               int             cfb4;
+               const int*      vxres;
+                             } capable;
+#ifdef CONFIG_MTRR
+       struct {
+               int             vram;
+               int             vram_valid;
+                             } mtrr;
+#endif
+       struct {
+               int             precise_width;
+               int             mga_24bpp_fix;
+               int             novga;
+               int             nobios;
+               int             nopciretry;
+               int             inverse;
+               int             hwcursor;
+
+               int             accelerator;
+               int             video64bits;
+                             } devflags;
+       struct display_switch   dispsw;
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+       struct {
+               unsigned int x;
+               unsigned int y;
+               unsigned int w;
+               unsigned int h;
+               volatile unsigned int mode;
+                             } cursor;
+#endif
+#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32)
+       union {
+#ifdef FBCON_HAS_CFB16
+               u_int16_t       cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB24
+               u_int32_t       cfb24[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+               u_int32_t       cfb32[16];
+#endif
+       } cmap;
+#endif
+       struct { unsigned red, green, blue, transp; } palette[256];
+};
+
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+#define mga_ydstorg(x) ACCESS_FBINFO2(x, _mga_ydstorg)
+#define curr_ydstorg(x)        ACCESS_FBINFO2(x, _curr_ydstorg)
+#else
+#define mga_ydstorg(x) (0)
+#define curr_ydstorg(x) (0)
+#endif
+
+#define PCI_OPTION_REG 0x40
+#define PCI_MGA_INDEX  0x44
+#define PCI_MGA_DATA   0x48
+
+#define M_DWGCTL       0x1C00
+#define M_MACCESS      0x1C04
+#define M_CTLWTST      0x1C08
+
+#define M_PLNWT                0x1C1C
+
+#define M_BCOL         0x1C20
+#define M_FCOL         0x1C24
+
+#define M_SGN          0x1C58
+#define M_LEN          0x1C5C
+#define M_AR0          0x1C60
+#define M_AR1          0x1C64
+#define M_AR2          0x1C68
+#define M_AR3          0x1C6C
+#define M_AR4          0x1C70
+#define M_AR5          0x1C74
+#define M_AR6          0x1C78
+
+#define M_CXBNDRY      0x1C80
+#define M_FXBNDRY      0x1C84
+#define M_YDSTLEN      0x1C88
+#define M_PITCH                0x1C8C
+#define M_YDST         0x1C90
+#define M_YDSTORG      0x1C94
+#define M_YTOP         0x1C98
+#define M_YBOT         0x1C9C
+
+/* mystique only */
+#define M_CACHEFLUSH   0x1FFF
+
+#define M_EXEC         0x0100
+
+#define M_DWG_TRAP     0x04
+#define M_DWG_BITBLT   0x08
+#define M_DWG_ILOAD    0x09
+
+#define M_DWG_LINEAR   0x0080
+#define M_DWG_SOLID    0x0800
+#define M_DWG_ARZERO   0x1000
+#define M_DWG_SGNZERO  0x2000
+#define M_DWG_SHIFTZERO        0x4000
+
+#define M_DWG_REPLACE  0x000C0000
+#define M_DWG_REPLACE2 (M_DWG_REPLACE | 0x40)
+#define M_DWG_XOR      0x00060010
+
+#define M_DWG_BFCOL    0x04000000
+#define M_DWG_BMONOWF  0x08000000
+
+#define M_DWG_TRANSC   0x40000000
+
+#define M_FIFOSTATUS   0x1E10
+#define M_STATUS       0x1E14
+
+#define M_IEN          0x1E1C
+
+#define M_VCOUNT       0x1E20
+
+#define M_RESET                0x1E40
+
+#define M_OPMODE       0x1E54
+#define     M_OPMODE_DMA_GEN_WRITE     0x00
+#define     M_OPMODE_DMA_BLIT          0x04
+#define     M_OPMODE_DMA_VECTOR_WRITE  0x08
+#define     M_OPMODE_DMA_LE            0x0000          /* little endian - no transformation */
+#define     M_OPMODE_DMA_BE_8BPP       0x0000
+#define     M_OPMODE_DMA_BE_16BPP      0x0100
+#define     M_OPMODE_DMA_BE_32BPP      0x0200
+#define     M_OPMODE_DIR_LE            0x000000        /* little endian - no transformation */
+#define     M_OPMODE_DIR_BE_8BPP       0x000000
+#define     M_OPMODE_DIR_BE_16BPP      0x010000
+#define     M_OPMODE_DIR_BE_32BPP      0x020000
+
+#define M_ATTR_INDEX   0x1FC0
+#define M_ATTR_DATA    0x1FC1
+
+#define M_MISC_REG     0x1FC2
+#define M_3C2_RD       0x1FC2
+
+#define M_SEQ_INDEX    0x1FC4
+#define M_SEQ_DATA     0x1FC5
+
+#define M_MISC_REG_READ        0x1FCC
+
+#define M_GRAPHICS_INDEX 0x1FCE
+#define M_GRAPHICS_DATA        0x1FCF
+
+#define M_CRTC_INDEX   0x1FD4
+
+#define M_ATTR_RESET   0x1FDA
+#define M_3DA_WR       0x1FDA
+
+#define M_EXTVGA_INDEX 0x1FDE
+#define M_EXTVGA_DATA  0x1FDF
+
+#define M_RAMDAC_BASE  0x3C00
+
+/* fortunately, same on TVP3026 and MGA1064 */
+#define M_DAC_REG      (M_RAMDAC_BASE+0)
+#define M_DAC_VAL      (M_RAMDAC_BASE+1)
+#define M_PALETTE_MASK (M_RAMDAC_BASE+2)
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+#define TVP3026_INDEX          0x00
+#define TVP3026_PALWRADD       0x00
+#define TVP3026_PALDATA                0x01
+#define TVP3026_PIXRDMSK       0x02
+#define TVP3026_PALRDADD       0x03
+#define TVP3026_CURCOLWRADD    0x04
+#define     TVP3026_CLOVERSCAN         0x00
+#define     TVP3026_CLCOLOR0           0x01
+#define     TVP3026_CLCOLOR1           0x02
+#define     TVP3026_CLCOLOR2           0x03
+#define TVP3026_CURCOLDATA     0x05
+#define TVP3026_CURCOLRDADD    0x07
+#define TVP3026_CURCTRL                0x09
+#define TVP3026_X_DATAREG      0x0A
+#define TVP3026_CURRAMDATA     0x0B
+#define TVP3026_CURPOSXL       0x0C
+#define TVP3026_CURPOSXH       0x0D
+#define TVP3026_CURPOSYL       0x0E
+#define TVP3026_CURPOSYH       0x0F
+
+#define TVP3026_XSILICONREV    0x01
+#define TVP3026_XCURCTRL       0x06
+#define     TVP3026_XCURCTRL_DIS       0x00    /* transparent, transparent, transparent, transparent */
+#define     TVP3026_XCURCTRL_3COLOR    0x01    /* transparent, 0, 1, 2 */
+#define     TVP3026_XCURCTRL_XGA       0x02    /* 0, 1, transparent, complement */
+#define     TVP3026_XCURCTRL_XWIN      0x03    /* transparent, transparent, 0, 1 */
+#define     TVP3026_XCURCTRL_BLANK2048 0x00
+#define     TVP3026_XCURCTRL_BLANK4096 0x10
+#define     TVP3026_XCURCTRL_INTERLACED        0x20
+#define     TVP3026_XCURCTRL_ODD       0x00 /* ext.signal ODD/\EVEN */
+#define     TVP3026_XCURCTRL_EVEN      0x40 /* ext.signal EVEN/\ODD */
+#define     TVP3026_XCURCTRL_INDIRECT  0x00
+#define     TVP3026_XCURCTRL_DIRECT    0x80
+#define TVP3026_XLATCHCTRL     0x0F
+#define     TVP3026_XLATCHCTRL_1_1     0x06
+#define     TVP3026_XLATCHCTRL_2_1     0x07
+#define     TVP3026_XLATCHCTRL_4_1     0x06
+#define     TVP3026_XLATCHCTRL_8_1     0x06
+#define     TVP3026_XLATCHCTRL_16_1    0x06
+#define     TVP3026A_XLATCHCTRL_4_3    0x07
+#define     TVP3026B_XLATCHCTRL_4_3    0x08
+#define     TVP3026B_XLATCHCTRL_8_3    0x06    /* ??? do not understand... but it works... ??? */
+#define TVP3026_XTRUECOLORCTRL 0x18
+#define     TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_ACCEL    0x00
+#define     TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_TVP      0x20
+#define     TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR         0x80
+#define     TVP3026_XTRUECOLORCTRL_TRUECOLOR           0x40 /* paletized */
+#define     TVP3026_XTRUECOLORCTRL_DIRECTCOLOR         0x00
+#define     TVP3026_XTRUECOLORCTRL_24_ALTERNATE                0x08 /* 5:4/5:2 instead of 4:3/8:3 */
+#define     TVP3026_XTRUECOLORCTRL_RGB_888             0x16 /* 4:3/8:3 (or 5:4/5:2) */
+#define            TVP3026_XTRUECOLORCTRL_BGR_888              0x17
+#define     TVP3026_XTRUECOLORCTRL_ORGB_8888           0x06
+#define     TVP3026_XTRUECOLORCTRL_BGRO_8888           0x07
+#define     TVP3026_XTRUECOLORCTRL_RGB_565             0x05
+#define     TVP3026_XTRUECOLORCTRL_ORGB_1555           0x04
+#define     TVP3026_XTRUECOLORCTRL_RGB_664             0x03
+#define     TVP3026_XTRUECOLORCTRL_RGBO_4444           0x01
+#define TVP3026_XMUXCTRL       0x19
+#define     TVP3026_XMUXCTRL_MEMORY_8BIT                       0x01 /* - */
+#define     TVP3026_XMUXCTRL_MEMORY_16BIT                      0x02 /* - */
+#define     TVP3026_XMUXCTRL_MEMORY_32BIT                      0x03 /* 2MB RAM, 512K * 4 */
+#define     TVP3026_XMUXCTRL_MEMORY_64BIT                      0x04 /* >2MB RAM, 512K * 8 & more */
+#define     TVP3026_XMUXCTRL_PIXEL_4BIT                                0x40 /* L0,H0,L1,H1... */
+#define     TVP3026_XMUXCTRL_PIXEL_4BIT_SWAPPED                        0x60 /* H0,L0,H1,L1... */
+#define     TVP3026_XMUXCTRL_PIXEL_8BIT                                0x48
+#define     TVP3026_XMUXCTRL_PIXEL_16BIT                       0x50
+#define     TVP3026_XMUXCTRL_PIXEL_32BIT                       0x58
+#define     TVP3026_XMUXCTRL_VGA                               0x98 /* VGA MEMORY, 8BIT PIXEL */
+#define TVP3026_XCLKCTRL       0x1A
+#define     TVP3026_XCLKCTRL_DIV1      0x00
+#define     TVP3026_XCLKCTRL_DIV2      0x10
+#define     TVP3026_XCLKCTRL_DIV4      0x20
+#define     TVP3026_XCLKCTRL_DIV8      0x30
+#define     TVP3026_XCLKCTRL_DIV16     0x40
+#define     TVP3026_XCLKCTRL_DIV32     0x50
+#define     TVP3026_XCLKCTRL_DIV64     0x60
+#define     TVP3026_XCLKCTRL_CLKSTOPPED        0x70
+#define     TVP3026_XCLKCTRL_SRC_CLK0  0x00
+#define     TVP3026_XCLKCTRL_SRC_CLK1   0x01
+#define     TVP3026_XCLKCTRL_SRC_CLK2  0x02    /* CLK2 is TTL source*/
+#define     TVP3026_XCLKCTRL_SRC_NCLK2 0x03    /* not CLK2 is TTL source */
+#define     TVP3026_XCLKCTRL_SRC_ECLK2 0x04    /* CLK2 and not CLK2 is ECL source */
+#define     TVP3026_XCLKCTRL_SRC_PLL   0x05
+#define     TVP3026_XCLKCTRL_SRC_DIS   0x06    /* disable & poweroff internal clock */
+#define     TVP3026_XCLKCTRL_SRC_CLK0VGA 0x07
+#define TVP3026_XPALETTEPAGE   0x1C
+#define TVP3026_XGENCTRL       0x1D
+#define     TVP3026_XGENCTRL_HSYNC_POS 0x00
+#define     TVP3026_XGENCTRL_HSYNC_NEG 0x01
+#define     TVP3026_XGENCTRL_VSYNC_POS 0x00
+#define     TVP3026_XGENCTRL_VSYNC_NEG 0x02
+#define     TVP3026_XGENCTRL_LITTLE_ENDIAN 0x00
+#define     TVP3026_XGENCTRL_BIG_ENDIAN    0x08
+#define     TVP3026_XGENCTRL_BLACK_0IRE                0x00
+#define     TVP3026_XGENCTRL_BLACK_75IRE       0x10
+#define     TVP3026_XGENCTRL_NO_SYNC_ON_GREEN  0x00
+#define     TVP3026_XGENCTRL_SYNC_ON_GREEN     0x20
+#define     TVP3026_XGENCTRL_OVERSCAN_DIS      0x00
+#define     TVP3026_XGENCTRL_OVERSCAN_EN       0x40
+#define TVP3026_XMISCCTRL      0x1E
+#define     TVP3026_XMISCCTRL_DAC_PUP  0x00
+#define     TVP3026_XMISCCTRL_DAC_PDOWN        0x01
+#define     TVP3026_XMISCCTRL_DAC_EXT  0x00 /* or 8, bit 3 is ignored */
+#define     TVP3026_XMISCCTRL_DAC_6BIT 0x04
+#define     TVP3026_XMISCCTRL_DAC_8BIT 0x0C
+#define     TVP3026_XMISCCTRL_PSEL_DIS 0x00
+#define     TVP3026_XMISCCTRL_PSEL_EN  0x10
+#define     TVP3026_XMISCCTRL_PSEL_LOW 0x00 /* PSEL high selects directcolor */
+#define     TVP3026_XMISCCTRL_PSEL_HIGH 0x20 /* PSEL high selects truecolor or pseudocolor */
+#define TVP3026_XGENIOCTRL     0x2A
+#define TVP3026_XGENIODATA     0x2B
+#define TVP3026_XPLLADDR       0x2C
+#define     TVP3026_XPLLADDR_X(LOOP,MCLK,PIX) (((LOOP)<<4) | ((MCLK)<<2) | (PIX))
+#define     TVP3026_XPLLDATA_N         0x00
+#define     TVP3026_XPLLDATA_M         0x01
+#define     TVP3026_XPLLDATA_P         0x02
+#define     TVP3026_XPLLDATA_STAT      0x03
+#define TVP3026_XPIXPLLDATA    0x2D
+#define TVP3026_XMEMPLLDATA    0x2E
+#define TVP3026_XLOOPPLLDATA   0x2F
+#define TVP3026_XCOLKEYOVRMIN  0x30
+#define TVP3026_XCOLKEYOVRMAX  0x31
+#define TVP3026_XCOLKEYREDMIN  0x32
+#define TVP3026_XCOLKEYREDMAX  0x33
+#define TVP3026_XCOLKEYGREENMIN        0x34
+#define TVP3026_XCOLKEYGREENMAX        0x35
+#define TVP3026_XCOLKEYBLUEMIN 0x36
+#define TVP3026_XCOLKEYBLUEMAX 0x37
+#define TVP3026_XCOLKEYCTRL    0x38
+#define     TVP3026_XCOLKEYCTRL_OVR_EN 0x01
+#define     TVP3026_XCOLKEYCTRL_RED_EN 0x02
+#define     TVP3026_XCOLKEYCTRL_GREEN_EN 0x04
+#define     TVP3026_XCOLKEYCTRL_BLUE_EN        0x08
+#define     TVP3026_XCOLKEYCTRL_NEGATE 0x10
+#define     TVP3026_XCOLKEYCTRL_ZOOM1  0x00
+#define     TVP3026_XCOLKEYCTRL_ZOOM2  0x20
+#define     TVP3026_XCOLKEYCTRL_ZOOM4  0x40
+#define     TVP3026_XCOLKEYCTRL_ZOOM8  0x60
+#define     TVP3026_XCOLKEYCTRL_ZOOM16 0x80
+#define     TVP3026_XCOLKEYCTRL_ZOOM32 0xA0
+#define TVP3026_XMEMPLLCTRL    0x39
+#define     TVP3026_XMEMPLLCTRL_DIV(X) (((X)-1)>>1)    /* 2,4,6,8,10,12,14,16, division applied to LOOP PLL after divide by 2^P */
+#define     TVP3026_XMEMPLLCTRL_STROBEMKC4     0x08
+#define     TVP3026_XMEMPLLCTRL_MCLK_DOTCLOCK  0x00    /* MKC4 */
+#define     TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL   0x10    /* MKC4 */
+#define     TVP3026_XMEMPLLCTRL_RCLK_PIXPLL    0x00
+#define     TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL   0x20
+#define     TVP3026_XMEMPLLCTRL_RCLK_DOTDIVN   0x40    /* dot clock divided by loop pclk N prescaler */
+#define TVP3026_XSENSETEST     0x3A
+#define TVP3026_XTESTMODEDATA  0x3B
+#define TVP3026_XCRCREML       0x3C
+#define TVP3026_XCRCREMH       0x3D
+#define TVP3026_XCRCBITSEL     0x3E
+#define TVP3026_XID            0x3F
+
+#endif
+
+#ifdef NEED_DAC1064
+
+#define DAC1064_OPT_SCLK_PCI   0x00
+#define DAC1064_OPT_SCLK_PLL   0x01
+#define DAC1064_OPT_SCLK_EXT   0x02
+#define DAC1064_OPT_SCLK_MASK  0x03
+#define DAC1064_OPT_GDIV1      0x04    /* maybe it is GDIV2 on G100 ?! */
+#define DAC1064_OPT_GDIV3      0x00
+#define DAC1064_OPT_MDIV1      0x08
+#define DAC1064_OPT_MDIV2      0x00
+#define DAC1064_OPT_RESERVED   0x10
+
+#define M1064_INDEX    0x00
+#define M1064_PALWRADD 0x00
+#define M1064_PALDATA  0x01
+#define M1064_PIXRDMSK 0x02
+#define M1064_PALRDADD 0x03
+#define M1064_X_DATAREG        0x0A
+#define M1064_CURPOSXL 0x0C    /* can be accessed as DWORD */
+#define M1064_CURPOSXH 0x0D
+#define M1064_CURPOSYL 0x0E
+#define M1064_CURPOSYH 0x0F
+
+#define M1064_XCURADDL         0x04
+#define M1064_XCURADDH         0x05
+#define M1064_XCURCTRL         0x06
+#define     M1064_XCURCTRL_DIS         0x00    /* transparent, transparent, transparent, transparent */
+#define     M1064_XCURCTRL_3COLOR      0x01    /* transparent, 0, 1, 2 */
+#define     M1064_XCURCTRL_XGA         0x02    /* 0, 1, transparent, complement */
+#define     M1064_XCURCTRL_XWIN                0x03    /* transparent, transparent, 0, 1 */
+#define M1064_XCURCOL0RED      0x08
+#define M1064_XCURCOL0GREEN    0x09
+#define M1064_XCURCOL0BLUE     0x0A
+#define M1064_XCURCOL1RED      0x0C
+#define M1064_XCURCOL1GREEN    0x0D
+#define M1064_XCURCOL1BLUE     0x0E
+#define M1064_XCURCOL2RED      0x10
+#define M1064_XCURCOL2GREEN    0x11
+#define M1064_XCURCOL2BLUE     0x12
+#define DAC1064_XVREFCTRL      0x18
+#define      DAC1064_XVREFCTRL_INTERNAL                0x3F
+#define      DAC1064_XVREFCTRL_EXTERNAL                0x00
+#define      DAC1064_XVREFCTRL_G100_DEFAULT    0x03
+#define M1064_XMULCTRL         0x19
+#define      M1064_XMULCTRL_DEPTH_8BPP         0x00    /* 8 bpp paletized */
+#define      M1064_XMULCTRL_DEPTH_15BPP_1BPP   0x01    /* 15 bpp paletized + 1 bpp overlay */
+#define      M1064_XMULCTRL_DEPTH_16BPP                0x02    /* 16 bpp paletized */
+#define      M1064_XMULCTRL_DEPTH_24BPP                0x03    /* 24 bpp paletized */
+#define      M1064_XMULCTRL_DEPTH_24BPP_8BPP   0x04    /* 24 bpp direct + 8 bpp overlay paletized */
+#define      M1064_XMULCTRL_2G8V16             0x05    /* 15 bpp video direct, half xres, 8bpp paletized */
+#define      M1064_XMULCTRL_G16V16             0x06    /* 15 bpp video, 15bpp graphics, one of them paletized */
+#define      M1064_XMULCTRL_DEPTH_32BPP                0x07    /* 24 bpp paletized + 8 bpp unused */
+#define      M1064_XMULCTRL_GRAPHICS_PALETIZED 0x00
+#define      M1064_XMULCTRL_VIDEO_PALETIZED    0x08
+#define M1064_XPIXCLKCTRL      0x1A
+#define      M1064_XPIXCLKCTRL_SRC_PCI         0x00
+#define      M1064_XPIXCLKCTRL_SRC_PLL         0x01
+#define      M1064_XPIXCLKCTRL_SRC_EXT         0x02
+#define      M1064_XPIXCLKCTRL_SRC_MASK                0x03
+#define      M1064_XPIXCLKCTRL_EN              0x00
+#define      M1064_XPIXCLKCTRL_DIS             0x04
+#define      M1064_XPIXCLKCTRL_PLL_DOWN                0x00
+#define      M1064_XPIXCLKCTRL_PLL_UP          0x08
+#define M1064_XGENCTRL         0x1D
+#define      M1064_XGENCTRL_VS_0               0x00
+#define      M1064_XGENCTRL_VS_1               0x01
+#define      M1064_XGENCTRL_ALPHA_DIS          0x00
+#define      M1064_XGENCTRL_ALPHA_EN           0x02
+#define      M1064_XGENCTRL_BLACK_0IRE         0x00
+#define      M1064_XGENCTRL_BLACK_75IRE                0x10
+#define      M1064_XGENCTRL_SYNC_ON_GREEN      0x00
+#define      M1064_XGENCTRL_NO_SYNC_ON_GREEN   0x20
+#define      M1064_XGENCTRL_SYNC_ON_GREEN_MASK 0x20
+#define M1064_XMISCCTRL                0x1E
+#define      M1064_XMISCCTRL_DAC_DIS           0x00
+#define      M1064_XMISCCTRL_DAC_EN            0x01
+#define      M1064_XMISCCTRL_MFC_VGA           0x00
+#define      M1064_XMISCCTRL_MFC_MAFC          0x02
+#define      M1064_XMISCCTRL_MFC_DIS           0x06
+#define      M1064_XMISCCTRL_DAC_6BIT          0x00
+#define      M1064_XMISCCTRL_DAC_8BIT          0x08
+#define      M1064_XMISCCTRL_LUT_DIS           0x00
+#define      M1064_XMISCCTRL_LUT_EN            0x10
+#define M1064_XGENIOCTRL       0x2A
+#define M1064_XGENIODATA       0x2B
+#define DAC1064_XSYSPLLM       0x2C
+#define DAC1064_XSYSPLLN       0x2D
+#define DAC1064_XSYSPLLP       0x2E
+#define DAC1064_XSYSPLLSTAT    0x2F
+#define M1064_XZOOMCTRL                0x38
+#define      M1064_XZOOMCTRL_1                 0x00
+#define      M1064_XZOOMCTRL_2                 0x01
+#define      M1064_XZOOMCTRL_4                 0x03
+#define M1064_XSENSETEST       0x3A
+#define      M1064_XSENSETEST_BCOMP            0x01
+#define      M1064_XSENSETEST_GCOMP            0x02
+#define      M1064_XSENSETEST_RCOMP            0x04
+#define      M1064_XSENSETEST_PDOWN            0x00
+#define      M1064_XSENSETEST_PUP              0x80
+#define M1064_XCRCREML         0x3C
+#define M1064_XCRCREMH         0x3D
+#define M1064_XCRCBITSEL       0x3E
+#define M1064_XCOLKEYMASKL     0x40
+#define M1064_XCOLKEYMASKH     0x41
+#define M1064_XCOLKEYL         0x42
+#define M1064_XCOLKEYH         0x43
+#define M1064_XPIXPLLAM                0x44
+#define M1064_XPIXPLLAN                0x45
+#define M1064_XPIXPLLAP                0x46
+#define M1064_XPIXPLLBM                0x48
+#define M1064_XPIXPLLBN                0x49
+#define M1064_XPIXPLLBP                0x4A
+#define M1064_XPIXPLLCM                0x4C
+#define M1064_XPIXPLLCN                0x4D
+#define M1064_XPIXPLLCP                0x4E
+#define M1064_XPIXPLLSTAT      0x4F
+
+#endif
+
+#ifdef __LITTLE_ENDIAN
+#define MX_OPTION_BSWAP                0x00000000
+
+#define M_OPMODE_4BPP  (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_8BPP  (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_16BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_24BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_32BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#else
+#ifdef __BIG_ENDIAN
+#define MX_OPTION_BSWAP                0x80000000
+
+#define M_OPMODE_4BPP  (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) /* TODO */
+#define M_OPMODE_8BPP  (M_OPMODE_DMA_BE_8BPP  | M_OPMODE_DIR_BE_8BPP  | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_16BPP (M_OPMODE_DMA_BE_16BPP | M_OPMODE_DIR_BE_16BPP | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_24BPP (M_OPMODE_DMA_BE_8BPP | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT)       /* TODO, ?32 */
+#define M_OPMODE_32BPP (M_OPMODE_DMA_BE_32BPP | M_OPMODE_DIR_BE_32BPP | M_OPMODE_DMA_BLIT)
+#else
+#error "Byte ordering have to be defined. Cannot continue."
+#endif
+#endif
+
+#define mga_inb(addr)  (*(volatile u_int8_t*)(ACCESS_FBINFO(mmio)+(addr)))
+/* #define mga_inw(addr)       *(volatile u_int16_t*)(ACCESS_FBINFO(mmio)+(addr)) */
+#define mga_inl(addr)  (*(volatile u_int32_t*)(ACCESS_FBINFO(mmio)+(addr)))
+#define mga_outb(addr,val) *(volatile u_int8_t*)(ACCESS_FBINFO(mmio)+(addr))=(val)
+/* #define mga_outw(addr,val) *(volatile u_int16_t*)(ACCESS_FBINFO(mmio)+(addr))=(val) */
+#define mga_outl(addr,val) *(volatile u_int32_t*)(ACCESS_FBINFO(mmio)+(addr))=(val)
+#define mga_readr(port,idx) (mga_outb((port),(idx)), mga_inb((port)+1))
+#ifdef __LITTLE_ENDIAN
+#define __mga_outw(addr,val) *(volatile u_int16_t*)(ACCESS_FBINFO(mmio)+(addr))=(val)
+#define mga_setr(addr,port,val) __mga_outw(addr, ((val)<<8) | (port))
+#else
+#define mga_setr(addr,port,val) do { mga_outb(addr, port); mga_outb((addr)+1, val); } while (0)
+#endif
+
+#ifdef __LITTLE_ENDIAN
+#define mga_fifo(n)    do {} while (mga_inb(M_FIFOSTATUS) < (n))
+#else
+#define mga_fifo(n)    do {} while ((mga_inl(M_FIFOSTATUS) & 0xFF) < (n))
+#endif
+
+static void WaitTillIdle(const struct matrox_fb_info* minfo) {
+       do {} while (mga_inl(M_STATUS) & 0x10000);
+}
+
+/* code speedup */
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+#define isInterleave(x)         (x->interleave)
+#define isMillenium(x)  (x->millenium)
+#define isMilleniumII(x) (x->milleniumII)
+#else
+#define isInterleave(x)  (0)
+#define isMillenium(x)  (0)
+#define isMilleniumII(x) (0)
+#endif
+
+static void matrox_cfbX_init(struct matrox_fb_info* minfo) {
+       u_int32_t maccess;
+       u_int32_t mpitch;
+       u_int32_t mopmode;
+
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+       curr_ydstorg(MINFO) = mga_ydstorg(MINFO);
+#endif
+       mpitch = ACCESS_FBINFO(curr.var.xres_virtual);
+       switch (ACCESS_FBINFO(curr.var.bits_per_pixel)) {
+               case 4:         maccess = 0x00000000;   /* accelerate as 8bpp video */
+                               mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */
+                               mopmode = M_OPMODE_4BPP;
+                               break;
+               case 8:         maccess = 0x00000000; 
+                               mopmode = M_OPMODE_8BPP;
+                               break;
+               case 16:        if (ACCESS_FBINFO(curr.var.green.length) == 5)
+                                       maccess = 0xC0000001; 
+                               else
+                                       maccess = 0x40000001; 
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+                               curr_ydstorg(MINFO) >>= 1;
+#endif
+                               mopmode = M_OPMODE_16BPP;
+                               break;
+               case 24:        maccess = 0x00000003;
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+                               curr_ydstorg(MINFO) /= 3;
+#endif
+                               mopmode = M_OPMODE_24BPP;
+                               break;
+               case 32:        maccess = 0x00000002; 
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+                               curr_ydstorg(MINFO) >>= 2;
+#endif
+                               mopmode = M_OPMODE_32BPP;
+                               break;
+               default:        maccess = 0x00000000; 
+                               mopmode = 0x00000000;
+                               break;  /* turn off acceleration!!! */
+       }
+       mga_fifo(8);
+       mga_outl(M_PITCH, mpitch);
+       mga_outl(M_YDSTORG, curr_ydstorg(MINFO));
+       mga_outl(M_PLNWT, -1);
+       mga_outl(M_OPMODE, mopmode);
+       mga_outl(M_CXBNDRY, 0xFFFF0000);
+       mga_outl(M_YTOP, 0);
+       mga_outl(M_YBOT, 0x007FFFFF);
+       mga_outl(M_MACCESS, maccess);
+       ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
+       if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC;
+}
+
+static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) {
+       int pixx = p->var.xres_virtual, start, end;
+       MINFO_FROM_DISP(p);
+
+       sx *= fontwidth(p);
+       dx *= fontwidth(p);
+       width *= fontwidth(p);
+       height *= fontheight(p);
+       sy *= fontheight(p);
+       dy *= fontheight(p);
+       if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
+               mga_fifo(2);
+               mga_outl(M_AR5, pixx);
+               mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
+                              M_DWG_BFCOL | M_DWG_REPLACE);
+               width--;
+               start = sy*pixx+sx+curr_ydstorg(MINFO);
+               end = start+width;
+       } else {
+               mga_fifo(3);
+               mga_outl(M_SGN, 5);
+               mga_outl(M_AR5, -pixx);
+               mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
+               width--;
+               end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO);
+               start = end+width;
+               dy += height-1;
+       }
+       mga_fifo(4);
+       mga_outl(M_AR0, end);
+       mga_outl(M_AR3, start);
+       mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
+       mga_outl(M_YDSTLEN | M_EXEC, ((dy)<<16) | height);
+       WaitTillIdle(MINFO);
+}
+
+#ifdef FBCON_HAS_CFB4
+static void matrox_cfb4_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) {
+       int pixx, start, end;
+       MINFO_FROM_DISP(p);
+       /* both (sx or dx or width) and fontwidth() are odd, so their multiply is
+          also odd, that means that we cannot use acceleration */
+       if ((sx | dx | width) & fontwidth(p) & 1) {
+               fbcon_cfb4_bmove(p, sy, sx, dy, dx, height, width);
+               return;
+       }
+       sx *= fontwidth(p);
+       dx *= fontwidth(p);
+       width *= fontwidth(p);
+       height *= fontheight(p);
+       sy *= fontheight(p);
+       dy *= fontheight(p);
+       pixx = p->var.xres_virtual >> 1;
+       sx >>= 1;
+       dx >>= 1;
+       width >>= 1;
+       if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
+               mga_fifo(2);
+               mga_outl(M_AR5, pixx);
+               mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
+                       M_DWG_BFCOL | M_DWG_REPLACE);
+               width--;
+               start = sy*pixx+sx+curr_ydstorg(MINFO);
+               end = start+width;
+       } else {
+               mga_fifo(3);
+               mga_outl(M_SGN, 5);
+               mga_outl(M_AR5, -pixx);
+               mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
+               width--;
+               end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO);
+               start = end+width;
+               dy += height-1;
+       }
+       mga_fifo(5);
+       mga_outl(M_AR0, end);
+       mga_outl(M_AR3, start);
+       mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
+       mga_outl(M_YDST, dy*pixx >> 5);
+       mga_outl(M_LEN | M_EXEC, height);
+       WaitTillIdle(MINFO);
+}
+#endif
+
+static void matroxfb_accel_clear(CPMINFO u_int32_t color, int sy, int sx, int height, 
+               int width) {
+       mga_fifo(4);
+       mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE);
+       mga_outl(M_FCOL, color);
+       mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
+       mga_outl(M_YDSTLEN | M_EXEC, (sy << 16) | height);
+       WaitTillIdle(MINFO);
+}
+
+static void matrox_cfbX_clear(u_int32_t color, struct display* p, int sy, int sx, int height, int width) {
+       matroxfb_accel_clear(PMXINFO(p) color, sy * fontheight(p), sx * fontwidth(p),
+                            height * fontheight(p), width * fontwidth(p));
+}
+
+#ifdef FBCON_HAS_CFB4
+static void matrox_cfb4_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
+       u_int32_t bgx;
+       int whattodo;
+       MINFO_FROM_DISP(p);
+
+       whattodo = 0; 
+       bgx = attr_bgcol_ec(p, conp);
+       bgx |= bgx << 4;
+       bgx |= bgx << 8;
+       bgx |= bgx << 16;
+       sy *= fontheight(p);
+       sx *= fontwidth(p);
+       height *= fontheight(p);
+       width *= fontwidth(p);
+       if (sx & 1) {
+               sx ++;
+               if (!width) return;
+               width --;
+               whattodo = 1;
+       }
+       if (width & 1) {
+               whattodo |= 2;
+       }
+       width >>= 1;
+       sx >>= 1;
+       if (width) {
+               mga_fifo(5);
+               mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE2);
+               mga_outl(M_FCOL, bgx);
+               mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
+               mga_outl(M_YDST, sy * p->var.xres_virtual >> 6);
+               mga_outl(M_LEN | M_EXEC, height);
+               WaitTillIdle(MINFO);
+       }
+       if (whattodo) {
+               u_int32_t step = p->var.xres_virtual >> 1;
+               if (whattodo & 1) {
+                       u_int8_t* uaddr = p->screen_base + sy * step + sx - 1;
+                       u_int32_t loop;
+                       u_int8_t bgx2 = bgx & 0xF0;
+                       for (loop = height; loop > 0; loop --) {
+                               *uaddr = (*uaddr & 0x0F) | bgx2;
+                               uaddr += step;
+                       }
+               }
+               if (whattodo & 2) {
+                       u_int8_t* uaddr = p->screen_base + sy * step + sx + width;
+                       u_int32_t loop;
+                       u_int8_t bgx2 = bgx & 0x0F;
+                       for (loop = height; loop > 0; loop --) {
+                               *uaddr = (*uaddr & 0xF0) | bgx2;
+                               uaddr += step;
+                       }
+               }
+       }
+}
+#endif
+
+#ifdef FBCON_HAS_CFB8
+static void matrox_cfb8_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
+       u_int32_t bgx;
+
+       bgx = attr_bgcol_ec(p, conp);
+       bgx |= bgx << 8;
+       bgx |= bgx << 16;
+       matrox_cfbX_clear(bgx, p, sy, sx, height, width);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static void matrox_cfb16_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
+       u_int32_t bgx;
+
+       bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+       matrox_cfbX_clear((bgx << 16) | bgx, p, sy, sx, height, width);
+}
+#endif
+
+#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
+static void matrox_cfb32_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
+       u_int32_t bgx;
+
+       bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+       matrox_cfbX_clear(bgx, p, sy, sx, height, width);
+}
+#endif
+
+static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) {
+       u_int32_t ar0;
+       u_int32_t step;
+       MINFO_FROM_DISP(p);
+
+       yy *= fontheight(p);
+       xx *= fontwidth(p);
+       mga_fifo(7);
+       mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
+
+       mga_outl(M_FCOL, fgx);
+       mga_outl(M_BCOL, bgx);
+       ar0 = fontwidth(p) - 1;
+       mga_outl(M_FXBNDRY, ((xx+ar0)<<16) | xx);
+       if (fontwidth(p) <= 8)
+               step = 1;
+       else if (fontwidth(p) <= 16)
+               step = 2;
+       else 
+               step = 4;
+       /* TODO: set OPMODE_DMA_LE for BE */
+       if (fontwidth(p) == step << 3) {
+               size_t charcell = fontheight(p)*step;
+               /* TODO: Align charcell to 4B for BE */
+               mga_outl(M_AR3, 0);
+               mga_outl(M_AR0, fontheight(p)*fontwidth(p)-1);
+               mga_outl(M_YDSTLEN | M_EXEC, (yy<<16) | fontheight(p));
+               memcpy(ACCESS_FBINFO(mmio), p->fontdata+(c&p->charmask)*charcell, charcell);
+       } else {
+               u8* chardata = p->fontdata+(c&p->charmask)*fontheight(p)*step;
+               u_int32_t ydstlen_tmp = (yy << 16) | 1;
+               int i;
+               switch (step) {
+               case 1: 
+                       for (i = fontheight(p); i > 0; i--) {
+                               mga_fifo(3);
+                               mga_outl(M_AR0, ar0);
+                               mga_outl(M_AR3, 0);
+                               mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+#ifdef __LITTLE_ENDIAN
+                               *(u_int32_t*)ACCESS_FBINFO(mmio) = *chardata++;
+#else
+                               *(u_int32_t*)ACCESS_FBINFO(mmio) = (*chardata++) << 24;
+#endif
+                               ydstlen_tmp += 0x10000;
+                       }
+                       break;
+               case 2:
+                       for (i = fontheight(p); i > 0; i--) {
+                               mga_fifo(3);
+                               mga_outl(M_AR0, ar0);
+                               mga_outl(M_AR3, 0);
+                               mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+#ifdef __LITTLE_ENDIAN
+                               *(u_int32_t*)ACCESS_FBINFO(mmio) = *(u_int16_t*)chardata;
+#else
+                               *(u_int32_t*)ACCESS_FBINFO(mmio) = (*(u_int16_t*)chardata) << 16;
+#endif
+                               ydstlen_tmp += 0x10000;
+                               chardata += 2;
+                       }
+                       break;
+               case 4:
+                       for (i = fontheight(p); i > 0; i--) {
+                               mga_fifo(3);
+                               mga_outl(M_AR0, ar0);
+                               mga_outl(M_AR3, 0);
+                               mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+                               *(u_int32_t*)ACCESS_FBINFO(mmio) = *(u_int32_t*)chardata;
+                               ydstlen_tmp += 0x10000;
+                               chardata += 4;
+                       }
+                       break;
+               }
+       }
+       /* TODO: restore OPMODE for BE */
+       WaitTillIdle(MINFO);
+}
+
+#ifdef FBCON_HAS_CFB8
+static void matrox_cfb8_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
+       u_int32_t fgx, bgx;
+
+       fgx = attr_fgcol(p, c);
+       bgx = attr_bgcol(p, c);
+       fgx |= (fgx << 8);
+       fgx |= (fgx << 16);
+       bgx |= (bgx << 8);
+       bgx |= (bgx << 16);
+       matrox_cfbX_putc(fgx, bgx, p, c, yy, xx);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static void matrox_cfb16_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
+       u_int32_t fgx, bgx;
+
+       fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, c)];
+       bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, c)];
+       fgx |= (fgx << 16);
+       bgx |= (bgx << 16);
+       matrox_cfbX_putc(fgx, bgx, p, c, yy, xx);
+}
+#endif
+
+#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
+static void matrox_cfb32_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
+       u_int32_t fgx, bgx;
+
+       fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, c)];
+       bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, c)];
+       matrox_cfbX_putc(fgx, bgx, p, c, yy, xx);
+}
+#endif
+
+static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+       u_int32_t step;
+       u_int32_t ydstlen;
+       u_int32_t xlen;
+       u_int32_t ar0;
+       u_int32_t charcell;
+       u_int32_t fxbndry;
+       int easy;
+       MINFO_FROM_DISP(p);
+
+       yy *= fontheight(p);
+       xx *= fontwidth(p);
+       if (fontwidth(p) <= 8)
+               step = 1;
+       else if (fontwidth(p) <= 16)
+               step = 2;
+       else
+               step = 4;
+       charcell = fontheight(p)*step;
+       xlen = (charcell + 3) & ~3;
+       if (fontwidth(p) == step << 3) {
+               ydstlen = (yy<<16) | fontheight(p);
+               ar0 = fontheight(p)*fontwidth(p) - 1;
+               easy = 1;
+       } else {
+               ydstlen = (yy<<16) | 1;
+               ar0 = fontwidth(p) - 1;
+               easy = 0;
+       }
+       mga_fifo(3);
+       mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
+       mga_outl(M_FCOL, fgx);
+       mga_outl(M_BCOL, bgx);
+       /* TODO: set OPMODE_DMA_LE for BE */
+       fxbndry = ((xx + fontwidth(p) - 1) << 16) | xx;
+       while (count--) {
+               u_int8_t* chardata = p->fontdata + (*s++ & p->charmask)*charcell;
+
+               mga_fifo(4);
+               mga_outl(M_FXBNDRY, fxbndry);
+               if (easy) {
+                       mga_outl(M_AR0, ar0);
+                       mga_outl(M_AR3, 0);
+                       mga_outl(M_YDSTLEN | M_EXEC, ydstlen);
+                       memcpy(ACCESS_FBINFO(mmio), chardata, xlen);
+               } else {
+                       u_int32_t ydstlen_tmp = ydstlen;
+                       int i;
+                       switch (step) {
+                               case 1: 
+                                       for (i = fontheight(p); i > 0; i--) {
+                                               mga_fifo(3);
+                                               mga_outl(M_AR0, ar0);
+                                               mga_outl(M_AR3, 0);
+                                               mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+#ifdef __LITTLE_ENDIAN
+                                               *(u_int32_t*)ACCESS_FBINFO(mmio) = *chardata++;
+#else
+                                               *(u_int32_t*)ACCESS_FBINFO(mmio) = (*chardata++) << 24;
+#endif
+                                               ydstlen_tmp += 0x10000;
+                                       }
+                                       break;
+                               case 2:
+                                       for (i = fontheight(p); i > 0; i--) {
+                                               mga_fifo(3);
+                                               mga_outl(M_AR0, ar0);
+                                               mga_outl(M_AR3, 0);
+                                               mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+#ifdef __LITTLE_ENDIAN
+                                               *(u_int32_t*)ACCESS_FBINFO(mmio) = *(u_int16_t*)chardata;
+#else
+                                               *(u_int32_t*)ACCESS_FBINFO(mmio) = (*(u_int16_t*)chardata) << 32;
+#endif
+                                               ydstlen_tmp += 0x10000;
+                                               chardata += 2;
+                                       }
+                                       break;
+                               case 4:
+                                       for (i = fontheight(p); i > 0; i--) {
+                                               mga_fifo(3);
+                                               mga_outl(M_AR0, ar0);
+                                               mga_outl(M_AR3, 0);
+                                               mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+                                               *(u_int32_t*)ACCESS_FBINFO(mmio) = *(u_int32_t*)chardata;
+                                               ydstlen_tmp += 0x10000;
+                                               chardata += 4;
+                                       }
+                                       break;
+                       }
+               }
+               fxbndry += fontwidth(p) + (fontwidth(p) << 16);
+       }
+       /* TODO: restore OPMODE for BE */
+       WaitTillIdle(MINFO);
+}
+
+#ifdef FBCON_HAS_CFB8
+static void matrox_cfb8_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+       u_int32_t fgx, bgx;
+
+       fgx = attr_fgcol(p, *s);
+       bgx = attr_bgcol(p, *s);
+       fgx |= (fgx << 8);
+       fgx |= (fgx << 16);
+       bgx |= (bgx << 8);
+       bgx |= (bgx << 16);
+       matrox_cfbX_putcs(fgx, bgx, p, s, count, yy, xx);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static void matrox_cfb16_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+       u_int32_t fgx, bgx;
+
+       fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, *s)];
+       bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, *s)];
+       fgx |= (fgx << 16);
+       bgx |= (bgx << 16);
+       matrox_cfbX_putcs(fgx, bgx, p, s, count, yy, xx);
+}
+#endif
+
+#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
+static void matrox_cfb32_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+       u_int32_t fgx, bgx;
+
+       fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, *s)];
+       bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, *s)];
+       matrox_cfbX_putcs(fgx, bgx, p, s, count, yy, xx);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB4
+static void matrox_cfb4_revc(struct display* p, int xx, int yy) {
+       MINFO_FROM_DISP(p);
+
+       if (fontwidth(p) & 1) {
+               fbcon_cfb4_revc(p, xx, yy);
+               return;
+       }
+       yy *= fontheight(p);
+       xx *= fontwidth(p);
+       xx |= (xx + fontwidth(p)) << 16;
+       xx >>= 1;
+
+       mga_fifo(5);
+       mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
+       mga_outl(M_FCOL, 0xFFFFFFFF);
+       mga_outl(M_FXBNDRY, xx);
+       mga_outl(M_YDST, yy * p->var.xres_virtual >> 6);
+       mga_outl(M_LEN | M_EXEC, fontheight(p));
+       WaitTillIdle(MINFO);
+} 
+#endif
+
+#ifdef FBCON_HAS_CFB8
+static void matrox_cfb8_revc(struct display* p, int xx, int yy) {
+       MINFO_FROM_DISP(p);
+
+       yy *= fontheight(p);
+       xx *= fontwidth(p);
+
+       mga_fifo(4);
+       mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
+       mga_outl(M_FCOL, 0x0F0F0F0F);
+       mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
+       mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+       WaitTillIdle(MINFO);
+}
+#endif
+
+static void matrox_cfbX_revc(struct display* p, int xx, int yy) {
+       MINFO_FROM_DISP(p);
+
+       yy *= fontheight(p);
+       xx *= fontwidth(p);
+
+       mga_fifo(4);
+       mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
+       mga_outl(M_FCOL, 0xFFFFFFFF);
+       mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
+       mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+       WaitTillIdle(MINFO);
+}
+
+static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) {
+       unsigned int bottom_height, right_width;
+       unsigned int bottom_start, right_start;
+       unsigned int cell_h, cell_w;
+
+       cell_w = fontwidth(p);
+       if (!cell_w) return;    /* PARANOID */
+       right_width = p->var.xres % cell_w;
+       right_start = p->var.xres - right_width;
+       if (!bottom_only && right_width) {
+               matroxfb_accel_clear(     PMXINFO(p)
+                            /* color */  0x00000000,
+                            /* y */      p->var.yoffset,
+                            /* x */      p->var.xoffset + right_start,
+                            /* height */ p->var.yres,
+                            /* width */  right_width);
+       }
+       cell_h = fontheight(p);
+       if (!cell_h) return;    /* PARANOID */
+       bottom_height = p->var.yres % cell_h;
+       if (bottom_height) {
+               bottom_start = p->var.yres - bottom_height;
+               matroxfb_accel_clear(             PMXINFO(p)
+                                    /* color */  0x00000000,
+                                    /* y */      p->var.yoffset + bottom_start,
+                                    /* x */      p->var.xoffset,
+                                    /* height */ bottom_height,
+                                    /* width */  right_start);
+       }
+}
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static void outTi3026(CPMINFO int reg, int val) {
+       mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, reg);
+       mga_outb(M_RAMDAC_BASE+TVP3026_X_DATAREG, val);
+}
+
+static int inTi3026(CPMINFO int reg) {
+       mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, reg);
+       return mga_inb(M_RAMDAC_BASE+TVP3026_X_DATAREG);
+}
+
+#define POS3026_XCURCTRL       20
+
+static void matroxfb_ti3026_cursor(struct display* p, int mode, int x, int y) {
+       MINFO_FROM_DISP(p);
+
+       if (mode == CM_ERASE) {
+               outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]) & ~3);
+               return;
+       }
+       x *= fontwidth(p);
+       y *= fontheight(p);
+       y -= p->var.yoffset;
+       if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y))) {
+               ACCESS_FBINFO(cursor.x) = x;
+               ACCESS_FBINFO(cursor.y) = y;
+               x += 64;
+               y += 64;
+               outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]) & ~3);
+               mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXL, x);
+               mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXH, x >> 8);
+               mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYL, y);
+               mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYH, y >> 8);
+       }
+       outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]) | 2);
+}
+#undef POS3026_XCURCTRL
+
+static void matroxfb_ti3026_createcursor(WPMINFO int w, int h) {
+       u_int32_t xline;
+       int i;
+
+       ACCESS_FBINFO(cursor.w) = w;
+       ACCESS_FBINFO(cursor.h) = h;
+       xline = (~0) << (32 - ACCESS_FBINFO(cursor.w));
+       mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, 0);
+       for (i = 0; i < ACCESS_FBINFO(cursor.h); i++) {
+               mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 24);
+               mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 16);
+               mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 8);
+               mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline);
+               mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+               mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+               mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+               mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+       }
+       i *= 8;
+       for (; i < 512; i++)
+               mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+       for (i = 0; i < 512; i++) 
+               mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0xFF);
+}
+       
+static int matroxfb_ti3026_setfont(struct display* p, int width, int height) {
+       matroxfb_ti3026_createcursor(PMXINFO(p) width, height);
+       return 0;
+}
+#endif
+
+#define matrox_cfb16_revc matrox_cfbX_revc
+#define matrox_cfb24_revc matrox_cfbX_revc
+#define matrox_cfb32_revc matrox_cfbX_revc
+
+#define matrox_cfb24_clear matrox_cfb32_clear
+#define matrox_cfb24_putc matrox_cfb32_putc
+#define matrox_cfb24_putcs matrox_cfb32_putcs
+
+#ifdef FBCON_HAS_CFB4
+static struct display_switch matroxfb_cfb4 = {
+       fbcon_cfb4_setup,     matrox_cfb4_bmove,  matrox_cfb4_clear,
+       fbcon_cfb4_putc,      fbcon_cfb4_putcs,   matrox_cfb4_revc,
+       NULL,                 NULL,               NULL,
+       /* cursor... */       /* set_font... */
+       FONTWIDTH(8) /* fix, fix, fix it */
+};
+#endif
+
+#ifdef FBCON_HAS_CFB8
+static struct display_switch matroxfb_cfb8 = {
+       fbcon_cfb8_setup,     matrox_cfbX_bmove,  matrox_cfb8_clear,
+       matrox_cfb8_putc,     matrox_cfb8_putcs,  matrox_cfb8_revc,
+       NULL,                 NULL,               matrox_cfbX_clear_margins,
+       ~1 /* FONTWIDTHS */
+};
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static struct display_switch matroxfb_cfb16 = {
+       fbcon_cfb16_setup,    matrox_cfbX_bmove,  matrox_cfb16_clear,
+       matrox_cfb16_putc,    matrox_cfb16_putcs, matrox_cfb16_revc,
+       NULL,                 NULL,               matrox_cfbX_clear_margins,
+       ~1 /* FONTWIDTHS */
+};
+#endif
+
+#ifdef FBCON_HAS_CFB24
+static struct display_switch matroxfb_cfb24 = {
+       fbcon_cfb24_setup,    matrox_cfbX_bmove,  matrox_cfb24_clear,
+       matrox_cfb24_putc,    matrox_cfb24_putcs, matrox_cfb24_revc,
+       NULL,                 NULL,               matrox_cfbX_clear_margins,
+       ~1 /* FONTWIDTHS */ /* TODO: and what about non-aligned access on BE? I think that there are no in my code */
+};
+#endif
+
+#ifdef FBCON_HAS_CFB32
+static struct display_switch matroxfb_cfb32 = {
+       fbcon_cfb32_setup,    matrox_cfbX_bmove,  matrox_cfb32_clear,
+       matrox_cfb32_putc,    matrox_cfb32_putcs, matrox_cfb32_revc,
+       NULL,                 NULL,               matrox_cfbX_clear_margins,
+       ~1 /* FONTWIDTHS */
+};
+#endif
+
+static struct pci_dev* pci_find(struct pci_dev* p) {
+       if (p) return p->next;
+       return pci_devices;
+}
+
+static void initMatrox(WPMINFO int con, struct display* p) {
+       struct display_switch *swtmp;
+
+       p->dispsw_data = NULL;
+       if ((p->var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) {
+               switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+                       case 4:
+                               swtmp = &fbcon_cfb4;
+                               break;
+#endif
+#ifdef FBCON_HAS_CFB8
+                       case 8:
+                               swtmp = &fbcon_cfb8;
+                               break;
+#endif
+#ifdef FBCON_HAS_CFB16
+                       case 16:
+                               p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16);
+                               swtmp = &fbcon_cfb16;
+                               break;
+#endif
+#ifdef FBCON_HAS_CFB24
+                       case 24:
+                               p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24);
+                               swtmp = &fbcon_cfb24;
+                               break;
+#endif
+#ifdef FBCON_HAS_CFB32
+                       case 32:
+                               p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32);
+                               swtmp = &fbcon_cfb32;
+                               break;
+#endif
+                       default:
+                               p->dispsw = &fbcon_dummy;
+                               return;
+               }
+               dprintk(KERN_INFO "matroxfb: acceleration disabled\n");
+       } else {
+               switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+                       case 4:
+                               swtmp = &matroxfb_cfb4;
+                               break;
+#endif
+#ifdef FBCON_HAS_CFB8
+                       case 8:
+                               swtmp = &matroxfb_cfb8;
+                               break;
+#endif
+#ifdef FBCON_HAS_CFB16
+                       case 16:
+                               p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16);
+                               swtmp = &matroxfb_cfb16;
+                               break;
+#endif
+#ifdef FBCON_HAS_CFB24
+                       case 24:
+                               p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24);
+                               swtmp = &matroxfb_cfb24;
+                               break;
+#endif
+#ifdef FBCON_HAS_CFB32
+                       case 32:
+                               p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32);
+                               swtmp = &matroxfb_cfb32;
+                               break;
+#endif
+                       default:
+                               p->dispsw = &fbcon_dummy;
+                               return;
+               }
+               dprintk(KERN_INFO "matroxfb: now accelerated\n");
+       }
+       memcpy(&ACCESS_FBINFO(dispsw), swtmp, sizeof(ACCESS_FBINFO(dispsw)));
+       p->dispsw = &ACCESS_FBINFO(dispsw);
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+       if (isMillenium(MINFO) && ACCESS_FBINFO(devflags.hwcursor)) {
+               ACCESS_FBINFO(dispsw.cursor) = matroxfb_ti3026_cursor;
+               ACCESS_FBINFO(dispsw.set_font) = matroxfb_ti3026_setfont;
+       }
+#endif
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * card parameters
+ */
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo vesafb_defined __initdata = {
+       0,0,0,0,        /* W,H, W, H (virtual) load xres,xres_virtual*/
+       0,0,            /* virtual -> visible no offset */
+       8,              /* depth -> load bits_per_pixel */
+       0,              /* greyscale ? */
+       {0,0,0},        /* R */
+       {0,0,0},        /* G */
+       {0,0,0},        /* B */
+       {0,0,0},        /* transparency */
+       0,              /* standard pixel format */
+       FB_ACTIVATE_NOW,
+       -1,-1,
+       FB_ACCELF_TEXT, /* accel flags */
+       0L,0L,0L,0L,0L,
+       0L,0L,0,        /* No sync info */
+       FB_VMODE_NONINTERLACED,
+       {0,0,0,0,0,0}
+};
+
+
+
+/* --------------------------------------------------------------------- */
+
+static void matrox_pan_var(struct fb_var_screeninfo *var, struct matrox_fb_info* minfo) {
+       struct matroxfb_par* p = &ACCESS_FBINFO(curr);
+       unsigned int pos;
+       unsigned short p0, p1, p2;
+
+       p->var.xoffset = var->xoffset;
+       p->var.yoffset = var->yoffset;
+       if (var->vmode & FB_VMODE_YWRAP)
+               p->var.vmode |= FB_VMODE_YWRAP;
+       else
+               p->var.vmode &= FB_VMODE_YWRAP;
+       
+       pos = (p->var.yoffset * p->var.xres_virtual + p->var.xoffset) * p->final_bppShift / 32;
+       if (mga_ydstorg(MINFO)) {
+               if (isInterleave(MINFO))
+                       pos += mga_ydstorg(MINFO) >> 3;
+               else
+                       pos += mga_ydstorg(MINFO) >> 2;
+       }
+
+       p0 = ACCESS_FBINFO(currenthw)->CRTC[0x0D] = pos & 0xFF;
+       p1 = ACCESS_FBINFO(currenthw)->CRTC[0x0C] = (pos & 0xFF00) >> 8;
+       p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F);
+       mga_setr(M_CRTC_INDEX, 0x0D, p0);
+       mga_setr(M_CRTC_INDEX, 0x0C, p1);
+       mga_setr(M_EXTVGA_INDEX, 0x00, p2);
+}
+
+       /*
+        * Open/Release the frame buffer device
+        */
+
+static int matroxfb_open(struct fb_info *info, int user)
+{
+       /*
+        * Nothing, only a usage count for the moment
+        */
+       MOD_INC_USE_COUNT;
+       return(0);
+}
+
+static int matroxfb_release(struct fb_info *info, int user)
+{
+       MOD_DEC_USE_COUNT;
+       return(0);
+}
+
+static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con,
+               struct fb_info* info) {
+#define minfo ((struct matrox_fb_info*)info)
+       if (var->vmode & FB_VMODE_YWRAP) {
+               if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
+                       return -EINVAL;
+       } else {
+               if (var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
+                   var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+                       return -EINVAL;
+       }
+       if (con == ACCESS_FBINFO(currcon))
+               matrox_pan_var(var, MINFO);
+       fb_display[con].var.xoffset = var->xoffset;
+       fb_display[con].var.yoffset = var->yoffset;
+       if (var->vmode & FB_VMODE_YWRAP)
+               fb_display[con].var.vmode |= FB_VMODE_YWRAP;
+       else
+               fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
+       return 0;
+#undef minfo
+}
+       
+static int matroxfb_updatevar(int con, struct fb_info *info)
+{
+       matrox_pan_var(&fb_display[con].var, (struct matrox_fb_info*)info);
+       return 0;
+}
+
+static int matroxfb_get_final_bppShift(CPMINFO int bpp) {
+       int bppshft2;
+
+       bppshft2 = bpp;
+       if (isInterleave(MINFO))
+               bppshft2 >>= 1;
+       if (ACCESS_FBINFO(devflags.video64bits))
+               bppshft2 >>= 1;
+       return bppshft2;
+}
+                               
+static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) {
+       int over;
+       int rounding;
+
+       switch (bpp) {
+               case 4:         rounding = 128;
+                               break;
+               case 8:         rounding = 64;
+                               break;
+               case 16:        rounding = 32;
+                               break;
+               case 24:        rounding = 64;
+                               break;
+               default:        rounding = 16;
+                               break;
+       }
+       if (isInterleave(MINFO)) {
+               rounding *= 2;
+       }
+       over = xres % rounding;
+       if (over) 
+               xres += rounding-over;
+       return xres;
+}
+
+static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) {
+       const int* width;
+       int xres_new;
+
+       width = ACCESS_FBINFO(capable.vxres);
+
+       if (ACCESS_FBINFO(devflags.precise_width)) {
+               while (*width) {
+                       if ((*width >= xres) && (matroxfb_test_and_set_rounding(PMINFO *width, bpp) == *width)) {
+                               break;
+                       }
+                       width++;
+               }
+               xres_new = *width;
+       } else {
+               xres_new = matroxfb_test_and_set_rounding(PMINFO xres, bpp);
+       }
+       if (!xres_new) return 0;
+       if (xres != xres_new) {
+               printk(KERN_INFO "matroxfb: cannot set xres to %d, rounded up to %d\n", xres, xres_new);
+       }
+       return xres_new;
+}
+
+#ifdef NEED_DAC1064
+static void outDAC1064(CPMINFO int reg, int val) {
+       mga_outb(M_RAMDAC_BASE+M1064_INDEX, reg);
+       mga_outb(M_RAMDAC_BASE+M1064_X_DATAREG, val);
+}
+
+static int inDAC1064(CPMINFO int reg) {
+       mga_outb(M_RAMDAC_BASE+M1064_INDEX, reg);
+       return mga_inb(M_RAMDAC_BASE+M1064_X_DATAREG);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static const unsigned char DACseq[] =
+{ TVP3026_XLATCHCTRL, TVP3026_XTRUECOLORCTRL, 
+  TVP3026_XMUXCTRL, TVP3026_XCLKCTRL, 
+  TVP3026_XPALETTEPAGE, 
+  TVP3026_XGENCTRL, 
+  TVP3026_XMISCCTRL, 
+  TVP3026_XGENIOCTRL,
+  TVP3026_XGENIODATA, 
+  TVP3026_XCOLKEYOVRMIN, TVP3026_XCOLKEYOVRMAX, TVP3026_XCOLKEYREDMIN, TVP3026_XCOLKEYREDMAX,
+  TVP3026_XCOLKEYGREENMIN, TVP3026_XCOLKEYGREENMAX, TVP3026_XCOLKEYBLUEMIN, TVP3026_XCOLKEYBLUEMAX,
+  TVP3026_XCOLKEYCTRL,
+  TVP3026_XMEMPLLCTRL, TVP3026_XSENSETEST, TVP3026_XCURCTRL };
+
+#define POS3026_XLATCHCTRL     0
+#define POS3026_XTRUECOLORCTRL 1
+#define POS3026_XMUXCTRL       2
+#define POS3026_XCLKCTRL       3
+#define POS3026_XGENCTRL       5
+#define POS3026_XMISCCTRL      6
+#define POS3026_XMEMPLLCTRL    18
+#define POS3026_XCURCTRL       20
+
+static const unsigned char MGADACbpp32[] =
+{ TVP3026_XLATCHCTRL_2_1, TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_8888,
+  0x00, TVP3026_XCLKCTRL_DIV1 | TVP3026_XCLKCTRL_SRC_PLL, 
+  0x00, 
+  TVP3026_XGENCTRL_HSYNC_POS | TVP3026_XGENCTRL_VSYNC_POS | TVP3026_XGENCTRL_LITTLE_ENDIAN | TVP3026_XGENCTRL_BLACK_0IRE | TVP3026_XGENCTRL_NO_SYNC_ON_GREEN | TVP3026_XGENCTRL_OVERSCAN_DIS, 
+  TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_HIGH, 
+  0x00, 
+  0x1E, 
+  0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF,
+  TVP3026_XCOLKEYCTRL_ZOOM1, 
+  0x00, 0x00, TVP3026_XCURCTRL_DIS };
+#endif /* CONFIG_FB_MATROX_MILLENIUM */
+
+static int PLL_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) {
+       unsigned int bestdiff = ~0;
+       unsigned int bestvco = 0;
+       unsigned int fxtal = ACCESS_FBINFO(features.pll.ref_freq);
+       unsigned int fwant;
+       int p;
+
+       fwant = freq;
+
+#ifdef DEBUG
+       printk(KERN_ERR "post_shift_max: %d\n", ACCESS_FBINFO(features.pll.post_shift_max));
+       printk(KERN_ERR "ref_freq: %d\n", ACCESS_FBINFO(features.pll.ref_freq));
+       printk(KERN_ERR "freq: %d\n", freq);
+       printk(KERN_ERR "vco_freq_min: %d\n", ACCESS_FBINFO(features.pll.vco_freq_min));
+       printk(KERN_ERR "in_div_min: %d\n", ACCESS_FBINFO(features.pll.in_div_min));
+       printk(KERN_ERR "in_div_max: %d\n", ACCESS_FBINFO(features.pll.in_div_max));
+       printk(KERN_ERR "feed_div_min: %d\n", ACCESS_FBINFO(features.pll.feed_div_min));
+       printk(KERN_ERR "feed_div_max: %d\n", ACCESS_FBINFO(features.pll.feed_div_max));
+       printk(KERN_ERR "fmax: %d\n", fmax);
+#endif
+       for (p = 0; p < ACCESS_FBINFO(features.pll.post_shift_max); p++) {
+               if (fwant * 2 > fmax)
+                       break;
+               fwant *= 2;
+       }
+       if (fwant < ACCESS_FBINFO(features.pll.vco_freq_min)) fwant = ACCESS_FBINFO(features.pll.vco_freq_min);
+       if (fwant > fmax) fwant = fmax;
+       for (; p >= 0; fwant >>= 1, bestdiff >>= 1, --p) {
+               int m;
+
+               if (fwant < ACCESS_FBINFO(features.pll.vco_freq_min)) break;
+               for (m = ACCESS_FBINFO(features.pll.in_div_min); m <= ACCESS_FBINFO(features.pll.in_div_max); m++) {
+                       unsigned int diff, fvco;
+                       int n;
+
+                       n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1;
+                       if (n > ACCESS_FBINFO(features.pll.feed_div_max)) 
+                               break;
+                       if (n < ACCESS_FBINFO(features.pll.feed_div_min))
+                               n = ACCESS_FBINFO(features.pll.feed_div_min);
+                       fvco = (fxtal * (n + 1)) / (m + 1);
+                       if (fvco < fwant)
+                               diff = fwant - fvco;
+                       else
+                               diff = fvco - fwant;
+                       if (diff < bestdiff) {
+                               bestdiff = diff;
+                               *post = p;
+                               *in = m;
+                               *feed = n;
+                               bestvco = fvco;
+                       }
+               }
+       }
+       dprintk(KERN_ERR "clk: %02X %02X %02X %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant);
+       return bestvco;
+}
+
+#ifdef NEED_DAC1064
+static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) {
+       unsigned int fvco;
+       unsigned int p;
+
+       fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p);
+       p = (1 << p) - 1;
+       if (fvco <= 100000)
+               ;
+       else if (fvco <= 140000)
+               p |= 0x08;
+       else if (fvco <= 180000)
+               p |= 0x10;
+       else
+               p |= 0x18;
+       *post = p;
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* in, int* feed, int* post) {
+       unsigned int fvco;
+       unsigned int lin, lfeed, lpost;
+
+       fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost);
+       fvco >>= (*post = lpost);
+       *in = 64 - lin;
+       *feed = 64 - lfeed;
+       return fvco;
+}
+
+static int Ti3026_setpclk(CPMINFO struct matrox_hw_state* hw, int clk, int Bpp) {
+       unsigned int f_pll;
+       unsigned int pixfeed, pixin, pixpost;
+       unsigned int loopfeed, loopin, looppost, loopdiv, z;
+       
+       f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost);
+       
+       hw->DACclk[0] = pixin | 0xC0;
+       hw->DACclk[1] = pixfeed;
+       hw->DACclk[2] = pixpost | 0xB0;
+       if (ACCESS_FBINFO(curr.var.bits_per_pixel) == 24) {
+               loopfeed = 3;           /* set lm to any possible value */
+               loopin = 3 * 32 / Bpp;
+       } else {
+               loopfeed = 4;
+               loopin = 4 * 32 / Bpp;
+       }
+       z = (110000 * loopin) / (f_pll * loopfeed);
+       loopdiv = 0; /* div 2 */
+       if (z < 2)
+               looppost = 0;
+       else if (z < 4)
+               looppost = 1;
+       else if (z < 8)
+               looppost = 2;
+       else {
+               looppost = 3;
+               loopdiv = z/16; 
+       }
+       if (ACCESS_FBINFO(curr.var.bits_per_pixel) == 24) {
+               hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
+               hw->DACclk[4] = (65 - loopfeed) | 0x80;
+               if (ACCESS_FBINFO(accel.ramdac_rev) > 0x20) {
+                       if (isInterleave(MINFO))
+                               hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_8_3;
+                       else {
+                               hw->DACclk[4] &= ~0xC0;
+                               hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_4_3;
+                       }
+               }
+               hw->DACclk[5] = looppost | 0xF8;
+               if (ACCESS_FBINFO(devflags.mga_24bpp_fix))
+                       hw->DACclk[5] ^= 0x40;
+       } else {
+               hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
+               hw->DACclk[4] = 65 - loopfeed;
+               hw->DACclk[5] = looppost | 0xF0;
+       }
+       hw->DACreg[POS3026_XMEMPLLCTRL] = loopdiv | TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL;
+       return 0;
+}
+#endif
+
+static void var2my(struct fb_var_screeninfo* var, struct my_timming* mt) {
+       unsigned int pixclock = var->pixclock;
+       if (!pixclock) pixclock = 10000;        /* 10ns = 100MHz */
+       mt->pixclock = 1000000000 / pixclock;
+       if (mt->pixclock < 1) mt->pixclock = 1;
+       mt->dblscan = var->vmode & FB_VMODE_DOUBLE;
+       mt->interlaced = var->vmode & FB_VMODE_INTERLACED;
+       mt->HDisplay = var->xres;
+       mt->HSyncStart = mt->HDisplay + var->right_margin;
+       mt->HSyncEnd = mt->HSyncStart + var->hsync_len;
+       mt->HTotal = mt->HSyncEnd + var->left_margin;
+       mt->VDisplay = var->yres;
+       mt->VSyncStart = mt->VDisplay + var->lower_margin;
+       mt->VSyncEnd = mt->VSyncStart + var->vsync_len;
+       mt->VTotal = mt->VSyncEnd + var->upper_margin;
+       mt->sync = var->sync;
+}
+
+static int vgaHWinit(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+       unsigned int hd, hs, he, ht;
+       unsigned int vd, vs, ve, vt;
+       unsigned int wd;
+       unsigned int divider;
+       int i;
+
+       hw->SEQ[0] = 0x00;
+       hw->SEQ[1] = 0x01;      /* or 0x09 */
+       hw->SEQ[2] = 0x0F;      /* bitplanes */
+       hw->SEQ[3] = 0x00;
+       hw->SEQ[4] = 0x0E;
+       /* CRTC 0..7, 9, 16..19, 21, 22 are reprogrammed by Matrox Millenium code... Hope that by MGA1064 too */
+       if (m->dblscan) {
+               m->VTotal <<= 1;
+               m->VDisplay <<= 1;
+               m->VSyncStart <<= 1;
+               m->VSyncEnd <<= 1;
+       }
+       if (m->interlaced) {
+               m->VTotal >>= 1;
+               m->VDisplay >>= 1;
+               m->VSyncStart >>= 1;
+               m->VSyncEnd >>= 1;
+       }
+
+       /* GCTL is ignored when not using 0xA0000 aperture */
+       hw->GCTL[0] = 0x00;
+       hw->GCTL[1] = 0x00;
+       hw->GCTL[2] = 0x00;
+       hw->GCTL[3] = 0x00;
+       hw->GCTL[4] = 0x00;
+       hw->GCTL[5] = 0x40;
+       hw->GCTL[6] = 0x05;
+       hw->GCTL[7] = 0x0F;
+       hw->GCTL[8] = 0xFF;
+
+       /* Whole ATTR is ignored in PowerGraphics mode */
+       for (i = 0; i < 16; i++)
+               hw->ATTR[i] = i;
+       hw->ATTR[16] = 0x41;
+       hw->ATTR[17] = 0xFF;
+       hw->ATTR[18] = 0x0F;
+       hw->ATTR[19] = 0x00;
+       hw->ATTR[20] = 0x00;
+
+       hd = m->HDisplay >> 3;
+       hs = m->HSyncStart >> 3;
+       he = m->HSyncEnd >> 3;
+       ht = m->HTotal >> 3;
+       /* standard timmings are in 8pixels, but for interleaved we cannot */
+       /* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */
+       /* using 16 or more pixels per unit can save us */
+       divider = ACCESS_FBINFO(curr.final_bppShift);
+       while (divider & 3) {
+               hd >>= 1;
+               hs >>= 1;
+               he >>= 1;
+               ht >>= 1;
+               divider <<= 1;
+       }
+       divider = divider / 4;
+       /* divider can be from 1 to 8 */
+       while (divider > 8) {
+               hd <<= 1;
+               hs <<= 1;
+               he <<= 1;
+               ht <<= 1;
+               divider >>= 1;
+       }
+       hd = hd - 1;
+       hs = hs - 1;
+       he = he - 1;
+       ht = ht - 1;
+       vd = m->VDisplay - 1;
+       vs = m->VSyncStart - 1;
+       ve = m->VSyncEnd - 1;
+       vt = m->VTotal - 2;
+       if (((ht & 0x0F) == 0x0E) || ((ht & 0x0F) == 0x04))
+               ht++;
+       wd = ACCESS_FBINFO(curr.var.xres_virtual) * ACCESS_FBINFO(curr.final_bppShift) / 64;
+
+       hw->CRTCEXT[0] = 0;
+       hw->CRTCEXT[5] = 0;
+       if (m->interlaced) {
+               hw->CRTCEXT[0] = 0x80;
+               hw->CRTCEXT[5] = (hs + he - ht) >> 1;
+               if (!m->dblscan)
+                       wd <<= 1;
+               vt &= ~1;
+       }
+       hw->CRTCEXT[0] |=  (wd & 0x300) >> 4;
+       hw->CRTCEXT[1] = (((ht - 4) & 0x100) >> 8) |
+                         ((hd      & 0x100) >> 7) | /* blanking */
+                         ((hs      & 0x100) >> 6) | /* sync start */
+                          (ht      & 0x040);    /* end hor. blanking */
+       hw->CRTCEXT[2] =  ((vt & 0xC00) >> 10) |
+                         ((vd & 0x400) >>  8) |        /* disp end */
+                         ((vd & 0xC00) >>  7) |        /* vblanking start */
+                         ((vs & 0xC00) >>  5);
+       hw->CRTCEXT[3] = (divider - 1) | 0x80;
+       hw->CRTCEXT[4] = 0;
+
+       hw->CRTC[0] = ht-4;
+       hw->CRTC[1] = hd;
+       hw->CRTC[2] = hd;
+       hw->CRTC[3] = (ht & 0x1F) | 0x80;
+       hw->CRTC[4] = hs;
+       hw->CRTC[5] = ((ht & 0x20) << 2) | (he & 0x1F);
+       hw->CRTC[6] = vt & 0xFF;
+       hw->CRTC[7] = ((vt & 0x100) >> 8) |
+                     ((vd & 0x100) >> 7) |
+                     ((vs & 0x100) >> 6) |
+                     ((vd & 0x100) >> 5) |
+                     0x10                |
+                     ((vt & 0x200) >> 4) |
+                     ((vd & 0x200) >> 3) |
+                     ((vs & 0x200) >> 2);
+       hw->CRTC[8] = 0x00;
+       hw->CRTC[9] = ((vd & 0x200) >> 4) | 0x40;
+       if (m->dblscan && !m->interlaced)
+               hw->CRTC[9] |= 0x80;
+       for (i = 10; i < 16; i++)
+               hw->CRTC[i] = 0x00;
+       hw->CRTC[16] = vs /* & 0xFF */;
+       hw->CRTC[17] = (ve & 0x0F) | 0x20;
+       hw->CRTC[18] = vd /* & 0xFF */;
+       hw->CRTC[19] = wd /* & 0xFF */;
+       hw->CRTC[20] = 0x00;
+       hw->CRTC[21] = vd /* & 0xFF */;
+       hw->CRTC[22] = (vt + 1) /* & 0xFF */;
+       hw->CRTC[23] = 0xC3;
+       hw->CRTC[24] = 0xFF;
+       return 0;
+};
+
+#ifdef NEED_DAC1064
+
+static const unsigned char MGA1064_DAC_regs[] = {
+               M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL,
+               M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE,
+               M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE,
+               M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE, 
+               DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL, 
+               M1064_XMISCCTRL,
+               M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST, 
+               M1064_XCRCBITSEL,
+               M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH };
+
+#define POS1064_XVREFCTRL              12
+#define POS1064_XMULCTRL               13
+#define POS1064_XGENCTRL               15
+
+static const unsigned char MGA1064_DAC[] = {
+               0xFF, 0x1F/*Memsizedependent*/, M1064_XCURCTRL_DIS,
+               0x00, 0x00, 0x00,       /* black */
+               0xFF, 0xFF, 0xFF,       /* white */
+               0xFF, 0x00, 0x00,       /* red */ 
+               0x00, 0,  
+               M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL, 
+               M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN, 
+               M1064_XMISCCTRL_DAC_EN | M1064_XMISCCTRL_MFC_VGA | M1064_XMISCCTRL_DAC_8BIT | M1064_XMISCCTRL_LUT_EN,
+               0x10, 0x3F, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN, 
+               0x00,
+               0x00, 0x00, 0xFF, 0xFF};
+
+static void DAC1064_setpclk(CPMINFO struct matrox_hw_state* hw, unsigned long fout) {
+       unsigned int m, n, p;
+
+       DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
+       hw->DACclk[0] = m;
+       hw->DACclk[1] = n;
+       hw->DACclk[2] = p;
+}
+
+static void DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem) {
+       u_int32_t mx;
+
+       mx = hw->MXoptionReg | 0x00000004;
+       pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+       mx &= ~0x000000BB;
+       if (oscinfo & DAC1064_OPT_GDIV1)
+               mx |= 0x00000008;
+       if (oscinfo & DAC1064_OPT_MDIV1)
+               mx |= 0x00000010;
+       if (oscinfo & DAC1064_OPT_RESERVED)
+               mx |= 0x00000080;
+       if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) {
+               /* select PCI clock until we have setup oscilator... */
+               int clk;
+               unsigned int m, n, p;
+
+               /* powerup system PLL, select PCI clock */
+               mx |= 0x00000020;
+               pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+               mx &= ~0x00000004;
+               pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+
+               /* !!! you must not access device if MCLK is not running !!!
+                  Doing so cause immediate PCI lockup :-( Maybe they should
+                  generate ABORT or I/O (parity...) error and Linux should 
+                  recover from this... (kill driver/process). But world is not
+                  perfect... */
+               /* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not
+                  select PLL... because of PLL can be stopped at this time) */
+               DAC1064_calcclock(PMINFO fmem, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
+               outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3] = m);
+               outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4] = n);
+               outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5] = p);
+               for (clk = 65536; clk; --clk) {
+                       if (inDAC1064(PMINFO DAC1064_XSYSPLLSTAT) & 0x40)
+                               break;
+               }
+               if (!clk)
+                       printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n");
+               /* select PLL */
+               mx |= 0x00000005;
+       } else {
+               /* select specified system clock source */
+               mx |= oscinfo & DAC1064_OPT_SCLK_MASK;
+       }
+       pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+       mx &= ~0x00000004;
+       pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+       hw->MXoptionReg = mx;
+}
+
+static int DAC1064_init_1(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+       memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs));
+       switch (ACCESS_FBINFO(curr.var.bits_per_pixel)) {
+               /* case 4: not supported by MGA1064 DAC */
+               case 8: 
+                       hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+                       break;
+               case 16:
+                       if (ACCESS_FBINFO(curr.var.green.length) == 5)
+                               hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+                       else
+                               hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+                       break;
+               case 24: 
+                       hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+                       break;
+               case 32:
+                       hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+                       break;
+               default:
+                       return 1;       /* unsupported depth */
+       }
+       hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl);
+       hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK;
+       hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN;
+       return 0;
+}
+
+static int DAC1064_init_2(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+       DAC1064_setpclk(PMINFO hw, m->pixclock);
+       if (ACCESS_FBINFO(curr.var.bits_per_pixel) > 16) {      /* 256 entries */
+               int i;
+
+               for (i = 0; i < 256; i++) {
+                       hw->DACpal[i * 3 + 0] = i;
+                       hw->DACpal[i * 3 + 1] = i;
+                       hw->DACpal[i * 3 + 2] = i;
+               }
+       } else if (ACCESS_FBINFO(curr.var.bits_per_pixel) > 8) {
+               if (ACCESS_FBINFO(curr.var.green.length) == 5) {        /* 0..31, 128..159 */
+                       int i;
+
+                       for (i = 0; i < 32; i++) {
+                               /* with p15 == 0 */
+                               hw->DACpal[i * 3 + 0] = i << 3;
+                               hw->DACpal[i * 3 + 1] = i << 3;
+                               hw->DACpal[i * 3 + 2] = i << 3;
+                               /* with p15 == 1 */
+                               hw->DACpal[(i + 128) * 3 + 0] = i << 3;
+                               hw->DACpal[(i + 128) * 3 + 1] = i << 3;
+                               hw->DACpal[(i + 128) * 3 + 2] = i << 3;
+                       }
+               } else {
+                       int i;
+
+                       for (i = 0; i < 64; i++) {              /* 0..63 */
+                               hw->DACpal[i * 3 + 0] = i << 3;
+                               hw->DACpal[i * 3 + 1] = i << 2;
+                               hw->DACpal[i * 3 + 2] = i << 3;
+                       }
+               }
+       } else {
+               memset(hw->DACpal, 0, 768);
+       }
+       return 0;
+}
+
+static void DAC1064_restore_1(CPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) {
+       outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]);
+       outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]);
+       outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]);
+       if (!oldhw || memcmp(hw->DACreg, oldhw->DACreg, sizeof(MGA1064_DAC_regs))) {
+               int i;
+
+               for (i = 0; i < sizeof(MGA1064_DAC_regs); i++)
+                       outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]);
+       }
+}
+
+static void DAC1064_restore_2(CPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) {
+       int i;
+       for (i = 0; i < 3; i++)
+               outDAC1064(PMINFO M1064_XPIXPLLCM + i, hw->DACclk[i]);
+       while (!(inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40));
+#ifdef DEBUG
+       dprintk(KERN_DEBUG "DAC1064regs ");
+       for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
+               dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], hw->DACreg[i]);
+               if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
+       }
+       dprintk("\n" KERN_DEBUG "DAC1064clk ");
+       for (i = 0; i < 6; i++)
+               dprintk("C%02X=%02X ", i, hw->DACclk[i]);
+       dprintk("\n");
+#endif
+}
+#endif /* NEED_DAC1064 */
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static int MGA1064_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+       if (DAC1064_init_1(PMINFO hw, m)) return 1;
+       if (vgaHWinit(PMINFO hw, m)) return 1;
+
+       hw->MiscOutReg = 0xCB;
+       if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+               hw->MiscOutReg &= ~0x40;
+       if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+               hw->MiscOutReg &= ~0x80;
+       if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
+               hw->CRTCEXT[3] |= 0x40;
+
+       if (DAC1064_init_2(PMINFO hw, m)) return 1;
+       return 0;               
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+static int MGAG100_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+       if (DAC1064_init_1(PMINFO hw, m)) return 1;
+       hw->MXoptionReg &= ~0x2000;
+       if (vgaHWinit(PMINFO hw, m)) return 1;
+
+       hw->MiscOutReg = 0xEF;
+       if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+               hw->MiscOutReg &= ~0x40;
+       if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+               hw->MiscOutReg &= ~0x80;
+       if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
+               hw->CRTCEXT[3] |= 0x40;
+
+       if (DAC1064_init_2(PMINFO hw, m)) return 1;
+       return 0;               
+}
+#endif /* G100 */
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static int Ti3026_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+       u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT;
+
+       memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg));
+       switch (ACCESS_FBINFO(curr.var.bits_per_pixel)) {
+               case 4: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1;       /* or _8_1, they are same */
+                       hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
+                       hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_4BIT;
+                       hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV8;
+                       hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
+                       break;
+               case 8: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1;        /* or _4_1, they are same */
+                       hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
+                       hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_8BIT;
+                       hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
+                       hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
+                       break;
+               case 16:
+                       /* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used everytime) */
+                       hw->DACreg[POS3026_XTRUECOLORCTRL] = (ACCESS_FBINFO(curr.var.green.length) == 5)? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555 ) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565);
+                       hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT;
+                       hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2;
+                       break;
+               case 24:
+                       /* XLATCHCTRL is: for (A) use _4_3 (?_8_3 is same? TBD), for (B) it is set in setpclk */
+                       hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_888;
+                       hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
+                       hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
+                       break;
+               case 32:
+                       /* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used everytime) */
+                       hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
+                       break;
+               default:
+                       return 1;       /* TODO: failed */
+       }
+       if (vgaHWinit(PMINFO hw, m)) return 1;
+
+       /* set SYNC */
+       hw->MiscOutReg = 0xCB;
+       if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+               hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_HSYNC_NEG;
+       if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+               hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_VSYNC_NEG;
+       if (m->sync & FB_SYNC_ON_GREEN)
+               hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_SYNC_ON_GREEN;
+
+       /* set DELAY */
+       if (ACCESS_FBINFO(video_len) < 0x400000)
+               hw->CRTCEXT[3] |= 0x08;
+       else if (ACCESS_FBINFO(video_len) > 0x400000)
+               hw->CRTCEXT[3] |= 0x10;
+
+       /* set HWCURSOR */
+       if (m->interlaced) {
+               hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_INTERLACED;
+       }
+
+       /* set interleaving */
+       hw->MXoptionReg &= ~0x00001000;
+       if (isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000;
+
+       /* set DAC */
+       Ti3026_setpclk(PMINFO hw, m->pixclock, ACCESS_FBINFO(curr.final_bppShift));
+       return 0;
+}
+#endif /* CONFIG_FB_MATROX_MILLENIUM */
+
+static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) {
+       switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+               case 4:
+                       return 16;      /* pseudocolor... 16 entries HW palette */
+#endif
+#ifdef FBCON_HAS_CFB8
+               case 8:
+                       return 256;     /* pseudocolor... 256 entries HW palette */
+#endif
+#ifdef FBCON_HAS_CFB16
+               case 16:
+                       return 16;      /* directcolor... 16 entries SW palette */
+                                       /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+#endif
+#ifdef FBCON_HAS_CFB24
+               case 24:
+                       return 16;      /* directcolor... 16 entries SW palette */
+                                       /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+#endif
+#ifdef FBCON_HAS_CFB32
+               case 32:
+                       return 16;      /* directcolor... 16 entries SW palette */
+                                       /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+#endif
+       }
+       return 16;      /* return something reasonable... or panic()? */
+}
+
+static int matroxfb_decode_var(CPMINFO struct fb_var_screeninfo *var, int *visual, int *video_cmap_len) {
+       unsigned int vramlen;
+       unsigned int memlen;
+
+       if ((var->xres > var->xres_virtual) || (var->yres > var->yres_virtual) || 
+           (var->xoffset > var->xres_virtual) || (var->yoffset > var->yres_virtual))
+               return -EINVAL;
+       switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+               case 4:  if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL;
+                        break;
+#endif
+#ifdef FBCON_HAS_CFB8
+               case 8:  break;
+#endif
+#ifdef FBCON_HAS_CFB16
+               case 16: break;
+#endif
+#ifdef FBCON_HAS_CFB24
+               case 24: break;
+#endif
+#ifdef FBCON_HAS_CFB32
+               case 32: break;
+#endif
+               default: return -EINVAL;
+       }
+       vramlen = ACCESS_FBINFO(video_len);
+       if (vramlen > 0x800000) vramlen = 0x800000;
+       var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, var->bits_per_pixel);
+       memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+       if (memlen > vramlen) 
+               return -EINVAL; /* out of memory */
+       /* There is hardware bug that no line can cross 4MB boundary */
+       /* give up for CFB24, it is impossible to easy workaround it */
+       /* for other try to do something */
+       if ((memlen > 0x400000) && (var->bits_per_pixel != 24)) {
+               int new_xres = var->xres_virtual;
+
+               if (new_xres <= 512)
+                       new_xres = 512;
+               else if (new_xres <= 1024)
+                       new_xres = 1024;
+               else if (new_xres <= 2048)
+                       new_xres = 2048;
+               else
+                       new_xres = var->xres_virtual;
+               memlen = new_xres * var->bits_per_pixel / 8;
+               /* if now out of memory, try shrink virtual height */
+               /* but if new virtual height is smaller than visible height, return -EINVAL */
+               if (var->yres_virtual * memlen > vramlen) {
+                       int new_yres;
+
+                       new_yres = vramlen / memlen;
+                       if (new_yres < var->yres)
+                               return -EINVAL;
+                       var->yres_virtual = new_yres;
+               }
+               var->xres_virtual = new_xres;
+       }
+
+       if (var->bits_per_pixel == 4) {
+               var->red.offset = 0;
+               var->red.length = 8;
+               var->green.offset = 0;
+               var->green.length = 8;
+               var->blue.offset = 0;
+               var->blue.length = 8;
+               var->transp.offset = 0;
+               var->transp.length = 0;
+               *visual = MX_VISUAL_PSEUDOCOLOR;
+       } else if (var->bits_per_pixel <= 8) {
+               var->red.offset = 0;
+               var->red.length = 8;
+               var->green.offset = 0;
+               var->green.length = 8;
+               var->blue.offset = 0;
+               var->blue.length = 8;
+               var->transp.offset = 0;
+               var->transp.length = 0;
+               *visual = MX_VISUAL_PSEUDOCOLOR;
+       } else {
+               if (var->bits_per_pixel <= 16) {
+                       if (var->green.length == 5) {
+                               var->red.offset    = 10;
+                               var->red.length    = 5;
+                               var->green.offset  = 5;
+                               var->green.length  = 5;
+                               var->blue.offset   = 0;
+                               var->blue.length   = 5;
+                               var->transp.offset = 15;
+                               var->transp.length = 1;
+                       } else {
+                               var->red.offset    = 11;
+                               var->red.length    = 5;
+                               var->green.offset  = 5;
+                               var->green.length  = 6;
+                               var->blue.offset   = 0;
+                               var->blue.length   = 5;
+                               var->transp.offset = 0;
+                               var->transp.length = 0;
+                       }
+               } else if (var->bits_per_pixel <= 24) {
+                       var->red.offset    = 16;
+                       var->red.length    = 8;
+                       var->green.offset  = 8;
+                       var->green.length  = 8;
+                       var->blue.offset   = 0;
+                       var->blue.length   = 8;
+                       var->transp.offset = 0;
+                       var->transp.length = 0;
+               } else {
+                       var->red.offset    = 16;
+                       var->red.length    = 8;
+                       var->green.offset  = 8;
+                       var->green.length  = 8;
+                       var->blue.offset   = 0;
+                       var->blue.length   = 8;
+                       var->transp.offset = 24;
+                       var->transp.length = 8;
+               }
+               dprintk("matroxfb: truecolor: "
+                      "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+                      var->transp.length,
+                      var->red.length,
+                      var->green.length,
+                      var->blue.length,
+                      var->transp.offset,
+                      var->red.offset,
+                      var->green.offset,
+                      var->blue.offset);
+               *visual = MX_VISUAL_DIRECTCOLOR;
+       }
+       *video_cmap_len = matroxfb_get_cmap_len(var);
+       dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel,
+                               var->xres_virtual, var->yres_virtual);
+       return 0;
+}
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+__initfunc(static void ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout)) {
+       unsigned int f_pll;
+       unsigned int pclk_m, pclk_n, pclk_p;
+       unsigned int mclk_m, mclk_n, mclk_p;
+       unsigned int rfhcnt, mclk_ctl;
+       int tmout;
+
+       f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p);
+
+       /* save pclk */
+       outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
+       pclk_n = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+       outTi3026(PMINFO TVP3026_XPLLADDR, 0xFD);
+       pclk_m = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+       outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
+       pclk_p = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+       
+       /* stop pclk */
+       outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
+       outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
+
+       /* set pclk to new mclk */
+       outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
+       outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_n | 0xC0);
+       outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_m);
+       outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_p | 0xB0);
+       
+       /* wait for PLL to lock */
+       for (tmout = 500000; tmout; tmout--) {
+               if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
+                       break;
+               udelay(10);
+       };
+       if (!tmout)
+               printk(KERN_ERR "matroxfb: Temporary pixel PLL not locked after 5 secs\n");
+
+       /* output pclk on mclk pin */
+       mclk_ctl = inTi3026(PMINFO TVP3026_XMEMPLLCTRL);
+       outTi3026(PMINFO TVP3026_XMEMPLLCTRL, mclk_ctl & 0xE7);
+       outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_STROBEMKC4);
+
+       /* stop MCLK */
+       outTi3026(PMINFO TVP3026_XPLLADDR, 0xFB);
+       outTi3026(PMINFO TVP3026_XMEMPLLDATA, 0x00);
+
+       /* set mclk to new freq */
+       outTi3026(PMINFO TVP3026_XPLLADDR, 0xF3);
+       outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_n | 0xC0);
+       outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_m);
+       outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_p | 0xB0);
+
+       /* wait for PLL to lock */
+       for (tmout = 500000; tmout; tmout--) {
+               if (inTi3026(PMINFO TVP3026_XMEMPLLDATA) & 0x40) 
+                       break;
+               udelay(10);
+       }
+       if (!tmout)
+               printk(KERN_ERR "matroxfb: Memory PLL not locked after 5 secs\n");
+
+       f_pll = f_pll * 333 / (10000 << mclk_p);        
+       if (isMilleniumII(MINFO)) {
+               rfhcnt = (f_pll - 128) / 256;
+               if (rfhcnt > 15)
+                       rfhcnt = 15;
+       } else {
+               rfhcnt = (f_pll - 64) / 128;
+               if (rfhcnt > 15)
+                       rfhcnt = 0;
+       }
+       hw->MXoptionReg = (hw->MXoptionReg & ~0x000F0000) | (rfhcnt << 16);
+       pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); 
+
+       /* output MCLK to MCLK pin */   
+       outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
+       outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl       ) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_STROBEMKC4);
+
+       /* stop PCLK */
+       outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
+       outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
+
+       /* restore pclk */
+       outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
+       outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_n);
+       outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_m);
+       outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_p);
+
+       /* wait for PLL to lock */
+       for (tmout = 500000; tmout; tmout--) {
+               if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
+                       break;
+               udelay(10);
+       }
+       if (!tmout)
+               printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
+}
+
+__initfunc(static void ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw)) {
+       ACCESS_FBINFO(features.pll.vco_freq_min) = 110000; 
+       ACCESS_FBINFO(features.pll.ref_freq)     = 114545;
+       ACCESS_FBINFO(features.pll.feed_div_min) = 2;
+       ACCESS_FBINFO(features.pll.feed_div_max) = 24;
+       ACCESS_FBINFO(features.pll.in_div_min)   = 2;
+       ACCESS_FBINFO(features.pll.in_div_max)   = 63;
+       ACCESS_FBINFO(features.pll.post_shift_max) = 3;
+       ACCESS_FBINFO(max_pixel_clock) = 220000;
+       ti3026_setMCLK(PMINFO hw, 60000);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+__initfunc(static void MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw)) {
+       unsigned char rev;
+
+       /* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */
+       ACCESS_FBINFO(features.pll.vco_freq_min) = 50000; 
+       ACCESS_FBINFO(features.pll.ref_freq)     = 14318;
+       ACCESS_FBINFO(features.pll.feed_div_min) = 100;
+       ACCESS_FBINFO(features.pll.feed_div_max) = 127;
+       ACCESS_FBINFO(features.pll.in_div_min)   = 1;
+       ACCESS_FBINFO(features.pll.in_div_max)   = 31;
+       ACCESS_FBINFO(features.pll.post_shift_max) = 3;
+       ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_EXTERNAL;
+       /* I hope */
+       pci_read_config_byte(ACCESS_FBINFO(pcidev), PCI_REVISION_ID, &rev);
+       if (rev < 3)
+               ACCESS_FBINFO(max_pixel_clock) = 170000;
+       else
+               ACCESS_FBINFO(max_pixel_clock) = 220000;
+       /* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */
+       DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
+}
+
+__initfunc(static int MGA1064_preinit(WPMINFO struct matrox_hw_state* hw)) {
+       static const int vxres_mystique[] = { 512,        640, 768,  800,  832,  960, 
+                                            1024, 1152, 1280,      1600, 1664, 1920, 
+                                            2048,    0};
+       /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
+       ACCESS_FBINFO(capable.vxres) = vxres_mystique;
+       ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
+
+       hw->MXoptionReg &= 0xC0000100;
+       hw->MXoptionReg |= 0x00094E20;
+       if (ACCESS_FBINFO(devflags.novga))
+               hw->MXoptionReg &= ~0x00000100;
+       if (ACCESS_FBINFO(devflags.nobios))
+               hw->MXoptionReg &= ~0x40000000;
+       if (ACCESS_FBINFO(devflags.nopciretry))
+               hw->MXoptionReg |=  0x20000000;
+       pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+       mga_setr(M_SEQ_INDEX, 0x01, 0x20);
+       mga_outl(M_CTLWTST, 0x00000000);
+       udelay(200);
+       mga_outl(M_MACCESS, 0x00008000);
+       udelay(100);
+       mga_outl(M_MACCESS, 0x0000C000);
+       return 0;
+}
+
+__initfunc(static void MGA1064_reset(WPMINFO struct matrox_hw_state* hw)) {
+       MGA1064_ramdac_init(PMINFO hw);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+/* BIOS environ */
+static int x7AF4 = 0;    /* flags */
+#if 0
+static int def50 = 0;  /* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */
+#endif
+
+#if 0
+__initfunc(static int G100_ReadFeatureConn(const struct matrox_fb_info* minfo)) {
+       int ret;
+
+       mga_outb(M_3DA_WR, 0x01);
+       ret =        (mga_inb(M_3C2_RD) >> 5) & 0x03;
+       mga_outb(M_3DA_WR, 0x02);
+       return ret | ((mga_inb(M_3C2_RD) >> 3) & 0x0C);
+}
+#endif
+
+__initfunc(static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p)) {
+       int reg;
+       int selClk;
+       int clk;
+
+       outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS);
+       switch (flags & 3) {
+               case 0:         reg = M1064_XPIXPLLAM; break;
+               case 1:         reg = M1064_XPIXPLLBM; break;
+               default:        reg = M1064_XPIXPLLCM; break;
+       }
+       outDAC1064(PMINFO reg++, m);
+       outDAC1064(PMINFO reg++, n);
+       outDAC1064(PMINFO reg, p);
+       selClk = mga_inb(M_MISC_REG_READ) & ~0xC;
+       /* there should be flags & 0x03 & case 0/1/else */
+       /* and we should first select source and after that we should wait for PLL */
+       /* and we are waiting for PLL with oscilator disabled... Is it right? */
+       switch (flags & 0x03) {
+               case 0x00:      break;
+               case 0x01:      selClk |= 4; break;
+               default:        selClk |= 0x0C; break;
+       }
+       mga_outb(M_MISC_REG, selClk);
+       for (clk = 65536; clk; clk--)
+               if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
+                       break;
+       if (!clk)
+               printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A');
+       selClk = inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK;
+       switch (flags & 0x0C) {
+               case 0x00:      selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break;
+               case 0x04:      selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break;
+               default:        selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break;
+       }
+       outDAC1064(PMINFO M1064_XPIXCLKCTRL, selClk);
+       outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS);
+}
+
+__initfunc(static void MGAG100_setPixClock(CPMINFO int flags, int freq)) {
+       unsigned int m, n, p;
+
+       DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
+       MGAG100_progPixClock(PMINFO flags, m, n, p);
+}
+
+__initfunc(static int MGAG100_preinit(WPMINFO struct matrox_hw_state* hw)) {
+       static const int vxres_g100[] = {  512,        640, 768,  800,  832,  960, 
+                                          1024, 1152, 1280,      1600, 1664, 1920, 
+                                          2048, 0};
+#if 0
+       u_int32_t reg50;
+       u_int32_t q;
+#endif
+
+       /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
+       ACCESS_FBINFO(capable.vxres) = vxres_g100;
+       ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
+       
+       hw->MXoptionReg &= 0xC0000100;
+       hw->MXoptionReg |= 0x00078C20;
+       if (ACCESS_FBINFO(devflags.novga))
+               hw->MXoptionReg &= ~0x00000100;
+       if (ACCESS_FBINFO(devflags.nobios))
+               hw->MXoptionReg &= ~0x40000000;
+       if (ACCESS_FBINFO(devflags.nopciretry))
+               hw->MXoptionReg |=  0x20000000;
+       pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+
+       mga_outl(M_CTLWTST, 0x03258A31);        /* 03258A31 is x7AF0, default is 0x02032521 */
+#if 0
+       hw->MXoptionReg |= 0x1000;
+       pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+       pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, &reg50);
+       q = def50 & 0x3000;
+       reg50 = (reg50 & ~0x3000) | q;
+       pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50);
+       mga_outb(0x1C05, 0x00);
+       mga_outb(0x1C05, 0x80);
+       udelay(100);
+       mga_outb(0x1C05, 0x40);
+       mga_outb(0x1C05, 0xC0);
+       pci_write_config_byte(ACCESS_FBINFO(pcidev), 0x50, def50 & 0x0F);
+       {
+               volatile u_int8_t* ptr;
+               mga_outb(M_GRAPHICS_INDEX, 6);
+               mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4);
+               mga_setr(M_EXTVGA_INDEX, 0x03, 0x81);
+               mga_setr(M_EXTVGA_INDEX, 0x04, 0x00);
+               ptr = ACCESS_FBINFO(video_vbase);
+               ptr[0x000] = 0xAA;
+               ptr[0x800] = 0x55;
+               if (ptr[0x000] != 0xAA) {
+                       hw->MXoptionReg &= ~0x1000;
+               }
+       }
+#endif
+       hw->MXoptionReg = (hw->MXoptionReg & ~0x1F8000) | 0x78000;
+#if 0
+       if (!(x7AF4 & 0x10))
+               hw->MXoptionReg |= 0x4000;
+#endif
+       pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+       return 0;
+}
+       
+__initfunc(static void MGAG100_reset(WPMINFO struct matrox_hw_state* hw)) {
+       u_int8_t b;
+
+       ACCESS_FBINFO(features.pll.vco_freq_min) = 50000;
+       ACCESS_FBINFO(features.pll.ref_freq)     = 27000;
+       ACCESS_FBINFO(features.pll.feed_div_min) = 7;
+       ACCESS_FBINFO(features.pll.feed_div_max) = 127;
+       ACCESS_FBINFO(features.pll.in_div_min)   = 1;
+       ACCESS_FBINFO(features.pll.in_div_max)   = 31;
+       ACCESS_FBINFO(features.pll.post_shift_max) = 3;
+       ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_G100_DEFAULT;
+       ACCESS_FBINFO(max_pixel_clock) = 220000;
+
+       {
+#ifdef G100_BROKEN_IBM_82351
+               u_int32_t d;
+
+               find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */
+               pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b);
+               if (b == ACCESS_FBINFO(pcidev)->bus->number) {
+                       pci_write_config_byte(ibm, PCI_COMMAND+1, 0);   /* disable back-to-back & SERR */
+                       pci_write_config_byte(ibm, 0x41, 0xF4);         /* ??? */
+                       pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0);  /* ??? */
+                       pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00); /* ??? */
+               }
+#endif
+               if (x7AF4 & 8) {
+                       hw->MXoptionReg |= 0x40;
+                       pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+               }
+               mga_setr(M_EXTVGA_INDEX, 0x06, 0x50);
+       }
+       DAC1064_setmclk(PMINFO hw, DAC1064_OPT_SCLK_PLL, 120000);
+       MGAG100_setPixClock(PMINFO 4, 25175);
+       MGAG100_setPixClock(PMINFO 5, 28322);
+       if (x7AF4 & 0x10) {
+               b = inDAC1064(PMINFO M1064_XGENIODATA) & ~1;
+               outDAC1064(PMINFO M1064_XGENIODATA, b);
+               b = inDAC1064(PMINFO M1064_XGENIOCTRL) | 1;
+               outDAC1064(PMINFO M1064_XGENIOCTRL, b);
+       }
+}
+#endif
+
+static void vgaHWrestore(CPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw) {
+       int i;
+
+       dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg);
+       dprintk(KERN_INFO "SEQ regs:   ");
+       for (i = 0; i < 5; i++)
+               dprintk("%02X:", hw->SEQ[i]);
+       dprintk("\n");
+       dprintk(KERN_INFO "GDC regs:   ");
+       for (i = 0; i < 9; i++)
+               dprintk("%02X:", hw->GCTL[i]);
+       dprintk("\n");
+       dprintk(KERN_INFO "CRTC regs: ");
+       for (i = 0; i < 25; i++)
+               dprintk("%02X:", hw->CRTC[i]);
+       dprintk("\n");
+       dprintk(KERN_INFO "ATTR regs: ");
+       for (i = 0; i < 21; i++)
+               dprintk("%02X:", hw->ATTR[i]);
+       dprintk("\n");
+
+       mga_inb(M_ATTR_RESET);
+       mga_outb(M_ATTR_INDEX, 0);
+       mga_outb(M_MISC_REG, hw->MiscOutReg);
+       for (i = 1; i < 5; i++)
+               mga_setr(M_SEQ_INDEX, i, hw->SEQ[i]);
+       mga_setr(M_CRTC_INDEX, 17, hw->CRTC[17] & 0x7F);
+       for (i = 0; i < 25; i++)
+               mga_setr(M_CRTC_INDEX, i, hw->CRTC[i]);
+       for (i = 0; i < 9; i++)
+               mga_setr(M_GRAPHICS_INDEX, i, hw->GCTL[i]);
+       for (i = 0; i < 21; i++) {
+               mga_inb(M_ATTR_RESET);
+               mga_outb(M_ATTR_INDEX, i);
+               mga_outb(M_ATTR_INDEX, hw->ATTR[i]);
+       }
+       mga_outb(M_PALETTE_MASK, 0xFF);
+       mga_outb(M_DAC_REG, 0x00);
+       for (i = 0; i < 768; i++)
+               mga_outb(M_DAC_VAL, hw->DACpal[i]);
+       mga_inb(M_ATTR_RESET);
+       mga_outb(M_ATTR_INDEX, 0x20);
+}
+
+static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green,
+                           unsigned blue, unsigned transp,
+                           struct fb_info *fb_info)
+{
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+       struct matrox_fb_info* minfo = (struct matrox_fb_info*)fb_info;
+#endif
+       /*
+        *  Set a single color register. The values supplied are
+        *  already rounded down to the hardware's capabilities
+        *  (according to the entries in the `var' structure). Return
+        *  != 0 for invalid regno.
+        */
+       
+       if (regno >= ACCESS_FBINFO(curr.cmap_len))
+               return 1;
+       
+       ACCESS_FBINFO(palette[regno].red)   = red;
+       ACCESS_FBINFO(palette[regno].green) = green;
+       ACCESS_FBINFO(palette[regno].blue)  = blue;
+       ACCESS_FBINFO(palette[regno].transp) = transp;
+
+       red = CNVT_TOHW(red, ACCESS_FBINFO(curr.var.red.length));
+       green = CNVT_TOHW(green, ACCESS_FBINFO(curr.var.green.length));
+       blue = CNVT_TOHW(blue, ACCESS_FBINFO(curr.var.blue.length));
+       transp = CNVT_TOHW(transp, ACCESS_FBINFO(curr.var.transp.length));
+
+       switch (ACCESS_FBINFO(curr.var.bits_per_pixel)) {
+#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4)
+#ifdef FBCON_HAS_CFB4
+       case 4:
+#endif
+#ifdef FBCON_HAS_CFB8
+       case 8:
+#endif
+               mga_outb(M_DAC_REG, regno);
+               mga_outb(M_DAC_VAL, red);
+               mga_outb(M_DAC_VAL, green);
+               mga_outb(M_DAC_VAL, blue);
+               break;
+#endif
+#ifdef FBCON_HAS_CFB16 
+       case 16:
+               ACCESS_FBINFO(cmap.cfb16[regno]) =
+                       (red << ACCESS_FBINFO(curr.var.red.offset))     | 
+                       (green << ACCESS_FBINFO(curr.var.green.offset)) | 
+                       (blue << ACCESS_FBINFO(curr.var.blue.offset))   |
+                       (transp << ACCESS_FBINFO(curr.var.transp.offset)); /* for 1:5:5:5 */
+               break;
+#endif
+#ifdef FBCON_HAS_CFB24
+       case 24:
+               ACCESS_FBINFO(cmap.cfb24[regno]) =
+                       (red   << ACCESS_FBINFO(curr.var.red.offset))   |
+                       (green << ACCESS_FBINFO(curr.var.green.offset)) |
+                       (blue  << ACCESS_FBINFO(curr.var.blue.offset));
+               break;
+#endif
+#ifdef FBCON_HAS_CFB32
+       case 32:
+               ACCESS_FBINFO(cmap.cfb32[regno]) =
+                       (red   << ACCESS_FBINFO(curr.var.red.offset))   |
+                       (green << ACCESS_FBINFO(curr.var.green.offset)) |
+                       (blue  << ACCESS_FBINFO(curr.var.blue.offset))  |
+                       (transp << ACCESS_FBINFO(curr.var.transp.offset));      /* 8:8:8:8 */
+               break;
+#endif
+       }
+       return 0;
+}
+
+static void do_install_cmap(WPMINFO int con)
+{
+       struct display* dsp;
+
+       if (con != ACCESS_FBINFO(currcon))
+               return;
+       if (con >= 0)
+               dsp = fb_display+con;
+       else
+               dsp = ACCESS_FBINFO(fbcon.disp);
+       if (dsp->cmap.len)
+               fb_set_cmap(&dsp->cmap, 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon));
+       else
+               fb_set_cmap(fb_default_cmap(ACCESS_FBINFO(curr.cmap_len)),
+                           1, matrox_setcolreg, &ACCESS_FBINFO(fbcon));
+}
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static void MGA1064_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
+       int i;
+
+       pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+       mga_outb(M_IEN, 0x00);
+       mga_outb(M_CACHEFLUSH, 0x00);
+       DAC1064_restore_1(PMINFO hw, oldhw);
+       for (i = 0; i < 6; i++)
+               mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+       vgaHWrestore(PMINFO hw, oldhw);
+       DAC1064_restore_2(PMINFO hw, oldhw);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+static void MGAG100_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
+       int i;
+
+       pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+       DAC1064_restore_1(PMINFO hw, oldhw);
+       for (i = 0; i < 6; i++)
+               mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+       vgaHWrestore(PMINFO hw, oldhw);
+       DAC1064_restore_2(PMINFO hw, oldhw);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static void Ti3026_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
+       int i;
+
+       dprintk(KERN_INFO "EXTVGA regs: ");
+       for (i = 0; i < 6; i++)
+               dprintk("%02X:", hw->CRTCEXT[i]);
+       dprintk("\n");
+
+       for (i = 0; i < 6; i++)
+               mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+
+       pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+
+       vgaHWrestore(PMINFO hw, oldhw);
+
+       for (i = 0; i < 21; i++) {
+               outTi3026(PMINFO DACseq[i], hw->DACreg[i]);
+       }
+       if (!oldhw || memcmp(hw->DACclk, oldhw->DACclk, 6)) {
+               /* agrhh... setting up PLL is very slow on Millenium... */
+               /* Mystique PLL is locked in few ms, but Millenium PLL lock takes about 0.15 s... */
+               /* Maybe even we should call schedule() ? */
+
+               outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]);
+               outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
+               outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0);
+               outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0);
+
+               outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
+               for (i = 0; i < 3; i++)
+                       outTi3026(PMINFO TVP3026_XPIXPLLDATA, hw->DACclk[i]);
+               /* wait for PLL only if PLL clock requested (always for PowerMode) */
+               if (hw->MiscOutReg & 0x08) {
+                       int tmout;
+                       outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
+                       for (tmout = 500000; tmout; --tmout) {
+                               if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40) 
+                                       break;
+                               udelay(10);
+                       }
+                       if (!tmout)
+                               printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
+                       else
+                               dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout);
+               }
+               outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]);
+               outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
+               for (i = 3; i < 6; i++)
+                       outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]);
+               if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[3] & 0xC0) == 0xC0)) {
+                       int tmout;
+
+                       outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
+                       for (tmout = 500000; tmout; --tmout) {
+                               if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40) 
+                                       break;
+                               udelay(10);
+                       }
+                       if (!tmout)
+                               printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n");
+                       else
+                               dprintk(KERN_INFO "LoopPLL: %d\n", 500000-tmout);
+               }
+       }
+       matroxfb_ti3026_createcursor(PMINFO fontwidth(p), fontheight(p));
+
+       dprintk(KERN_DEBUG "3026DACregs ");
+       for (i = 0; i < 21; i++) {
+               dprintk("R%02X=%02X ", DACseq[i], hw->DACreg[i]);
+               if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
+       }
+       dprintk("\n" KERN_DEBUG "DACclk ");
+       for (i = 0; i < 6; i++)
+               dprintk("C%02X=%02X ", i, hw->DACclk[i]);
+       dprintk("\n");
+}
+#endif
+
+static int matroxfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+                        struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+       memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+       strcpy(fix->id,"MATROX");
+
+       fix->smem_start = (void*)ACCESS_FBINFO(video_base);
+       fix->smem_len = ACCESS_FBINFO(video_len);
+       fix->type = ACCESS_FBINFO(curr.video_type);
+       fix->visual = ACCESS_FBINFO(curr.visual);
+       fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */
+       fix->ypanstep = 1;
+       fix->ywrapstep = 0;
+       fix->line_length = (ACCESS_FBINFO(curr.var.xres_virtual) * ACCESS_FBINFO(curr.var.bits_per_pixel)) >> 3;
+       fix->mmio_start = (void*)ACCESS_FBINFO(mmio_base);
+       fix->mmio_len = ACCESS_FBINFO(mmio_len);
+       fix->accel = ACCESS_FBINFO(devflags.accelerator);
+       return 0;
+#undef minfo
+}
+
+static int matroxfb_get_var(struct fb_var_screeninfo *var, int con,
+                        struct fb_info *info)
+{
+       if(con < 0)
+               *var=ACCESS_FBINFO2(info, curr.var);
+       else
+               *var=fb_display[con].var;
+       return 0;
+}
+
+static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
+                        struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+       int err;
+       int visual;
+       int cmap_len;
+       struct display* display;
+       int chgvar;
+
+       if ((err = matroxfb_decode_var(PMINFO var, &visual, &cmap_len)) != 0) 
+               return err;
+       switch (var->activate & FB_ACTIVATE_MASK) {
+               case FB_ACTIVATE_TEST:  return 0;
+               case FB_ACTIVATE_NXTOPEN:       /* ?? */
+               case FB_ACTIVATE_NOW:   break;  /* continue */
+               default:                return -EINVAL; /* unknown */
+       }
+       if (con >= 0) {
+               display = fb_display+con;
+               chgvar = ((display->var.xres != var->xres) || 
+                   (display->var.yres != var->yres) || 
+                    (display->var.xres_virtual != var->xres_virtual) ||
+                   (display->var.yres_virtual != var->yres_virtual) || 
+                   (display->var.bits_per_pixel != var->bits_per_pixel) ||
+                   memcmp(&display->var.red, &var->red, sizeof(var->red)) || 
+                   memcmp(&display->var.green, &var->green, sizeof(var->green)) ||
+                   memcmp(&display->var.blue, &var->blue, sizeof(var->blue)));
+       } else {
+               display = ACCESS_FBINFO(fbcon.disp);
+               chgvar = 0;
+       }
+       display->var = *var;
+       /* cmap */
+       display->screen_base = ACCESS_FBINFO(video_vbase);
+       display->visual = visual;
+       display->type = FB_TYPE_PACKED_PIXELS;
+       display->type_aux = 0;
+       display->ypanstep = 1;
+       display->ywrapstep = 0;
+       display->next_line = display->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
+       display->can_soft_blank = 1;
+       display->inverse = ACCESS_FBINFO(devflags.inverse);
+       /* conp, fb_info, vrows, cursor_x, cursor_y, fgcol, bgcol */
+       /* next_plane, fontdata, _font*, userfont */
+       initMatrox(PMINFO con, display);        /* dispsw */
+       /* dispsw, scrollmode, yscroll */
+       /* fgshift, bgshift, charmask */
+       if (chgvar && info && info->changevar)
+               info->changevar(con);
+       if (con == ACCESS_FBINFO(currcon)) {
+               unsigned int pos;
+
+               ACCESS_FBINFO(curr.var) = *var;
+               ACCESS_FBINFO(curr.visual) = visual;
+               ACCESS_FBINFO(curr.cmap_len) = cmap_len;
+               ACCESS_FBINFO(curr.final_bppShift) = matroxfb_get_final_bppShift(PMINFO var->bits_per_pixel);
+               if (visual == MX_VISUAL_PSEUDOCOLOR) {
+                       int i;
+
+                       for (i = 0; i < 16; i++) {
+                               int j;
+
+                               j = color_table[i];
+                               ACCESS_FBINFO(palette[i].red)   = default_red[j];
+                               ACCESS_FBINFO(palette[i].green) = default_grn[j];
+                               ACCESS_FBINFO(palette[i].blue)  = default_blu[j];
+                       }
+               }
+
+               {       struct my_timming mt;
+                       struct matrox_hw_state* hw;
+                       struct matrox_hw_state* ohw;
+
+                       var2my(var, &mt);
+                       hw = ACCESS_FBINFO(newhw);
+                       ohw = ACCESS_FBINFO(currenthw);
+
+                       /* MXoptionReg is not set from scratch */
+                       hw->MXoptionReg = ohw->MXoptionReg;
+                       /* DACclk[3]..[5] are not initialized with DAC1064 */
+                       memcpy(hw->DACclk, ohw->DACclk, sizeof(hw->DACclk));
+                       /* others are initialized by init() */
+
+                       ACCESS_FBINFO(hw_switch->init(PMINFO hw, &mt));
+                       pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32;
+                       if (mga_ydstorg(MINFO)) {
+                               if (isInterleave(MINFO))
+                                       pos += mga_ydstorg(MINFO) >> 3;
+                               else
+                                       pos += mga_ydstorg(MINFO) >> 2;
+                       }
+
+                       hw->CRTC[0x0D] = pos & 0xFF;
+                       hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
+                       hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F);
+                       ACCESS_FBINFO(hw_switch->restore(PMINFO hw, ohw, display));
+                       ACCESS_FBINFO(currenthw) = hw;
+                       ACCESS_FBINFO(newhw) = ohw;
+                       matrox_cfbX_init(MINFO);
+                       do_install_cmap(PMINFO con);
+               }
+       }
+       return 0;
+#undef minfo
+}
+
+static int matrox_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+                           unsigned *blue, unsigned *transp,
+                           struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+       /*
+        *  Read a single color register and split it into colors/transparent.
+        *  Return != 0 for invalid regno.
+        */
+
+       if (regno >= ACCESS_FBINFO(curr.cmap_len))
+               return 1;
+
+       *red   = ACCESS_FBINFO(palette[regno].red);
+       *green = ACCESS_FBINFO(palette[regno].green);
+       *blue  = ACCESS_FBINFO(palette[regno].blue);
+       *transp = ACCESS_FBINFO(palette[regno].transp);
+       return 0;
+#undef minfo
+}
+
+static int matroxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+                            struct fb_info *info)
+{
+       struct display* dsp = (con < 0) ? info->disp : fb_display+con;
+
+       if (con == ACCESS_FBINFO2(info, currcon)) /* current console? */
+               return fb_get_cmap(cmap, kspc, matrox_getcolreg, info);
+       else if (dsp->cmap.len) /* non default colormap? */
+               fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2);
+       else
+               fb_copy_cmap(fb_default_cmap(matroxfb_get_cmap_len(&dsp->var)),
+                            cmap, kspc ? 0 : 2);
+       return 0;
+}
+
+static int matroxfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+                            struct fb_info *info)
+{
+       int cmap_len;
+       struct display* dsp = (con < 0) ? info->disp : (fb_display + con);
+
+       cmap_len = matroxfb_get_cmap_len(&dsp->var);
+       if (dsp->cmap.len != cmap_len) {
+               int err;
+
+               err = fb_alloc_cmap(&dsp->cmap, cmap_len, 0);
+               if (err)
+                       return err;
+       }
+       if (con == ACCESS_FBINFO2(info, currcon))                       /* current console? */
+               return fb_set_cmap(cmap, kspc, matrox_setcolreg, info);
+       else
+               fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1);
+       return 0;
+}
+
+static int matroxfb_ioctl(struct inode *inode, struct file *file, 
+                         unsigned int cmd, unsigned long arg, int con,
+                         struct fb_info *info)
+{
+       return -EINVAL;
+}
+
+static struct fb_ops matroxfb_ops = {
+       matroxfb_open,
+       matroxfb_release,
+       matroxfb_get_fix,
+       matroxfb_get_var,
+       matroxfb_set_var,
+       matroxfb_get_cmap,
+       matroxfb_set_cmap,
+       matroxfb_pan_display,
+       matroxfb_ioctl,
+       NULL                    /* mmap */
+};
+
+static int matroxfb_switch(int con, struct fb_info *info)
+{
+       struct fb_cmap* cmap;
+       if (ACCESS_FBINFO2(info, currcon) >= 0) {
+               /* Do we have to save the colormap? */
+               cmap = &fb_display[ACCESS_FBINFO2(info, currcon)].cmap;
+               dprintk(KERN_DEBUG "switch1: con = %d, cmap.len = %d\n", ACCESS_FBINFO2(info, currcon), cmap->len);
+
+               if (cmap->len) {
+                       dprintk(KERN_DEBUG "switch1a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
+                       fb_get_cmap(cmap, 1, matrox_getcolreg, info);
+#ifdef DEBUG
+                       if (cmap->red) {
+                               dprintk(KERN_DEBUG "switch1r: %X\n", cmap->red[0]);
+                       }
+#endif
+               }
+       }
+       ACCESS_FBINFO2(info, currcon) = con;
+       fb_display[con].var.activate = FB_ACTIVATE_NOW;
+#ifdef DEBUG
+       cmap = &fb_display[con].cmap;
+       dprintk(KERN_DEBUG "switch2: con = %d, cmap.len = %d\n", con, cmap->len);
+       dprintk(KERN_DEBUG "switch2a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
+       if (fb_display[con].cmap.red) {
+               dprintk(KERN_DEBUG "switch2r: %X\n", cmap->red[0]);
+       }
+#endif
+       matroxfb_set_var(&fb_display[con].var, con, info);
+#ifdef DEBUG
+       dprintk(KERN_DEBUG "switch3: con = %d, cmap.len = %d\n", con, cmap->len);
+       dprintk(KERN_DEBUG "switch3a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
+       if (fb_display[con].cmap.red) {
+               dprintk(KERN_DEBUG "switch3r: %X\n", cmap->red[0]);
+       }
+#endif
+       return 0;
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static void matroxfb_blank(int blank, struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+       int seq;
+       int crtc;
+
+       switch (blank) {
+               case 1:  seq = 0x20; crtc = 0x00; break; /* works ??? */
+               case 2:  seq = 0x20; crtc = 0x10; break;
+               case 3:  seq = 0x20; crtc = 0x20; break;
+               case 4:  seq = 0x20; crtc = 0x30; break;
+               default: seq = 0x00; crtc = 0x00; break;
+       }
+       mga_outb(M_SEQ_INDEX, 1);
+       mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
+       mga_outb(M_EXTVGA_INDEX, 1);
+       mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
+#undef minfo
+}
+
+#define RSResolution(X)        ((X) & 0x0F)
+#define RS640x400      1
+#define RS640x480      2
+#define RS800x600      3
+#define RS1024x768     4
+#define RS1280x1024    5
+#define RS1600x1200    6
+#define RS768x576      7
+#define RS960x720      8
+#define RS1152x864     9
+#define RS1408x1056    10
+/* B-F */
+static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = {
+       {  640,  400,  48, 16, 39,  8,  96, 2, 70 },
+       {  640,  480,  48, 16, 33, 10,  96, 2, 60 },
+       {  800,  600, 144, 24, 28,  8, 112, 6, 60 },
+       { 1024,  768, 160, 32, 30,  4, 128, 4, 60 },
+       { 1280, 1024, 224, 32, 32,  4, 136, 4, 60 },
+       { 1600, 1200, 272, 48, 32,  5, 152, 5, 60 },
+       {  768,  576, 144, 16, 28,  6, 112, 4, 60 },
+       {  960,  720, 144, 24, 28,  8, 112, 4, 60 },
+       { 1152,  864, 192, 32, 30,  4, 128, 4, 60 },
+       { 1408, 1056, 256, 40, 32,  5, 144, 5, 60 }
+};
+
+#define RSDepth(X)     (((X) >> 4) & 0x0F)
+#define RS8bpp         0x1
+#define RS15bpp                0x2
+#define RS16bpp                0x3
+#define RS32bpp                0x4
+#define RS4bpp         0x5
+#define RS24bpp                0x6
+/* 7-F */
+static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; } colors[] __initdata = {
+       { {  0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, {  0, 0, 0},  8 },
+       { { 10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0}, 16 },
+       { { 11, 5, 0}, { 6, 5, 0}, { 0, 5, 0}, {  0, 0, 0}, 16 },
+       { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 24, 8, 0}, 32 },
+       { {  0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, {  0, 0, 0},  4 },
+       { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, {  0, 0, 0}, 24 }
+};
+
+#define RSCreate(X,Y)  ((X) | ((Y) << 4))
+static struct { int vesa; int info; } *RSptr, vesamap[] __initdata = {
+/* default must be first */
+#ifdef FBCON_HAS_CFB8
+       { 0x101, RSCreate(RS640x480,   RS8bpp ) },
+       { 0x100, RSCreate(RS640x400,   RS8bpp ) },
+       { 0x180, RSCreate(RS768x576,   RS8bpp ) },
+       { 0x103, RSCreate(RS800x600,   RS8bpp ) },
+       { 0x188, RSCreate(RS960x720,   RS8bpp ) },
+       { 0x105, RSCreate(RS1024x768,  RS8bpp ) },
+       { 0x190, RSCreate(RS1152x864,  RS8bpp ) },
+       { 0x107, RSCreate(RS1280x1024, RS8bpp ) },
+       { 0x198, RSCreate(RS1408x1056, RS8bpp ) },
+       { 0x11C, RSCreate(RS1600x1200, RS8bpp ) },
+#endif
+#ifdef FBCON_HAS_CFB4
+       { 0x102, RSCreate(RS800x600,   RS4bpp ) },
+       { 0x104, RSCreate(RS1024x768,  RS4bpp ) },
+#endif
+#ifdef FBCON_HAS_CFB16
+       { 0x110, RSCreate(RS640x480,   RS15bpp) },
+       { 0x181, RSCreate(RS768x576,   RS15bpp) },
+       { 0x113, RSCreate(RS800x600,   RS15bpp) },
+       { 0x189, RSCreate(RS960x720,   RS15bpp) },
+       { 0x116, RSCreate(RS1024x768,  RS15bpp) },
+       { 0x191, RSCreate(RS1152x864,  RS15bpp) },
+       { 0x119, RSCreate(RS1280x1024, RS15bpp) },
+       { 0x199, RSCreate(RS1408x1056, RS15bpp) },
+       { 0x11D, RSCreate(RS1600x1200, RS15bpp) },
+       { 0x111, RSCreate(RS640x480,   RS16bpp) },
+       { 0x182, RSCreate(RS768x576,   RS16bpp) },
+       { 0x114, RSCreate(RS800x600,   RS16bpp) },
+       { 0x18A, RSCreate(RS960x720,   RS16bpp) },
+       { 0x117, RSCreate(RS1024x768,  RS16bpp) },
+       { 0x192, RSCreate(RS1152x864,  RS16bpp) },
+       { 0x11A, RSCreate(RS1280x1024, RS16bpp) },
+       { 0x19A, RSCreate(RS1408x1056, RS16bpp) },
+       { 0x11E, RSCreate(RS1600x1200, RS16bpp) },
+#endif
+#ifdef FBCON_HAS_CFB24
+       { 0x1B2, RSCreate(RS640x480,   RS24bpp) },
+       { 0x184, RSCreate(RS768x576,   RS24bpp) },
+       { 0x1B5, RSCreate(RS800x600,   RS24bpp) },
+       { 0x18C, RSCreate(RS960x720,   RS24bpp) },
+       { 0x1B8, RSCreate(RS1024x768,  RS24bpp) },
+       { 0x194, RSCreate(RS1152x864,  RS24bpp) },
+       { 0x1BB, RSCreate(RS1280x1024, RS24bpp) },
+       { 0x19C, RSCreate(RS1408x1056, RS24bpp) },
+       { 0x1BF, RSCreate(RS1600x1200, RS24bpp) },
+#endif
+#ifdef FBCON_HAS_CFB32
+       { 0x112, RSCreate(RS640x480,   RS32bpp) },
+       { 0x183, RSCreate(RS768x576,   RS32bpp) },
+       { 0x115, RSCreate(RS800x600,   RS32bpp) },
+       { 0x18B, RSCreate(RS960x720,   RS32bpp) },
+       { 0x118, RSCreate(RS1024x768,  RS32bpp) },
+       { 0x193, RSCreate(RS1152x864,  RS32bpp) },
+       { 0x11B, RSCreate(RS1280x1024, RS32bpp) },
+       { 0x19B, RSCreate(RS1408x1056, RS32bpp) },
+#endif
+       {     0, 0                                 }};
+
+/* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */
+static unsigned int mem = 0;           /* "matrox:mem:xxxxxM" */
+static int option_precise_width = 1;   /* cannot be changed, option_precise_width==0 must imply noaccel */
+static int inv24 = 0;                  /* "matrox:inv24" */
+static int disabled = 0;               /* "matrox:disabled" */
+static int noaccel = 0;                        /* "matrox:noaccel" */
+static int nopan = 0;                  /* "matrox:nopan" */
+static int no_pci_retry = 0;           /* "matrox:nopciretry" */
+static int novga = 0;                  /* "matrox:novga" */
+static int nobios = 0;                 /* "matrox:nobios" */
+static int inverse = 0;                        /* "matrox:inverse" */
+static int hwcursor = 0;               /* "matrox:hwcursor" */
+static int dev = -1;                   /* "matrox:dev:xxxxx" */
+static unsigned int vesa = 0x101;      /* "matrox:vesa:xxxxx" */
+static unsigned int depth = 0;         /* "matrox:depth:xxxxx" */
+static unsigned int xres = 0;          /* "matrox:xres:xxxxx" */
+static unsigned int yres = 0;          /* "matrox:yres:xxxxx" */
+static unsigned int upper = 0;         /* "matrox:upper:xxxxx" */
+static unsigned int lower = 0;         /* "matrox:lower:xxxxx" */
+static unsigned int vslen = 0;         /* "matrox:vslen:xxxxx" */
+static unsigned int left = 0;          /* "matrox:left:xxxxx" */
+static unsigned int right = 0;         /* "matrox:right:xxxxx" */
+static unsigned int hslen = 0;         /* "matrox:hslen:xxxxx" */
+static unsigned int pixclock = 0;      /* "matrox:pixclock:xxxxx" */
+static int sync = -1;                  /* "matrox:sync:xxxxx" */
+static int fv = 0;                     /* "matrox:fv:xxxxx" */
+static int fh = 0;                     /* "matrox:fh:xxxxxk" */
+static int maxclk = 0;                 /* "matrox:maxclk:xxxxM" */
+static char fontname[64];              /* "matrox:font:xxxxx" */
+
+#ifndef MODULE
+__initfunc(void matroxfb_setup(char *options, int *ints)) {
+       char *this_opt;
+       
+       fontname[0] = '\0';
+       
+       if (!options || !*options)
+               return;
+       
+       for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+               if (!*this_opt) continue;
+               
+               dprintk("matroxfb_setup: option %s\n", this_opt);
+               
+               if (! strcmp(this_opt, "inverse"))
+                       inverse = 1;
+               else if (!strcmp(this_opt, "disabled"))
+                       disabled = 1;
+               else if (!strcmp(this_opt, "noaccel"))
+                       noaccel = 1;
+               else if (!strcmp(this_opt, "nopan"))
+                       nopan = 1;
+               else if (!strcmp(this_opt, "nopciretry"))
+                       no_pci_retry = 1;
+               else if (!strcmp(this_opt, "novga"))
+                       novga = 1;
+               else if (!strcmp(this_opt, "nobios"))
+                       nobios = 1;
+               else if (!strcmp(this_opt, "inv24"))
+                       inv24 = 1;
+               else if (!strcmp(this_opt, "hwcursor"))
+                       hwcursor = 1;
+               else if (!strncmp(this_opt, "dev:", 4))
+                       dev = simple_strtoul(this_opt+4, NULL, 0);
+               else if (!strncmp(this_opt, "depth:", 6)) {
+                       switch (simple_strtoul(this_opt+6, NULL, 0)) {
+                               case 4: depth = RS4bpp; break;
+                               case 8: depth = RS8bpp; break;
+                               case 15:depth = RS15bpp; break;
+                               case 16:depth = RS16bpp; break;
+                               case 24:depth = RS24bpp; break;
+                               case 32:depth = RS32bpp; break;
+                               default:
+                                       printk(KERN_ERR "matroxfb: unsupported color depth\n");
+                       }
+               } else if (!strncmp(this_opt, "xres:", 5))
+                       xres = simple_strtoul(this_opt+5, NULL, 0);
+               else if (!strncmp(this_opt, "yres:", 5))
+                       yres = simple_strtoul(this_opt+5, NULL, 0);
+               else if (!strncmp(this_opt, "vslen:", 6))
+                       vslen = simple_strtoul(this_opt+6, NULL, 0);
+               else if (!strncmp(this_opt, "hslen:", 6))
+                       hslen = simple_strtoul(this_opt+6, NULL, 0);
+               else if (!strncmp(this_opt, "left:", 5))
+                       left = simple_strtoul(this_opt+5, NULL, 0);
+               else if (!strncmp(this_opt, "right:", 6))
+                       right = simple_strtoul(this_opt+6, NULL, 0);
+               else if (!strncmp(this_opt, "upper:", 6))
+                       upper = simple_strtoul(this_opt+6, NULL, 0);
+               else if (!strncmp(this_opt, "lower:", 6))
+                       lower = simple_strtoul(this_opt+6, NULL, 0);
+               else if (!strncmp(this_opt, "pixclock:", 9))
+                       pixclock = simple_strtoul(this_opt+9, NULL, 0);
+               else if (!strncmp(this_opt, "sync:", 5))
+                       sync = simple_strtoul(this_opt+5, NULL, 0);
+               else if (!strncmp(this_opt, "vesa:", 5)) 
+                       vesa = simple_strtoul(this_opt+5, NULL, 0);
+               else if (!strncmp(this_opt, "font:", 5))
+                       strcpy(fontname, this_opt+5);
+               else if (!strncmp(this_opt, "maxclk:", 7))
+                       maxclk = simple_strtoul(this_opt+7, NULL, 0);
+               else if (!strncmp(this_opt, "fh:", 3))
+                       fh = simple_strtoul(this_opt+3, NULL, 0);
+               else if (!strncmp(this_opt, "fv:", 3)) 
+                       fv = simple_strtoul(this_opt+3, NULL, 0);
+               else if (!strncmp(this_opt, "mem:", 4)) 
+                       mem = simple_strtoul(this_opt+4, NULL, 0);
+               else {
+                       printk(KERN_ERR "matroxfb: unknown parameter %s\n", this_opt);
+               }
+       }
+}
+#endif
+
+__initfunc(static int matroxfb_getmemory(WPMINFO int maxSize, unsigned int* realOffset, int *realSize)) {
+       volatile unsigned char* vm;
+       int offs;
+       int offs2;
+       unsigned char store;
+       unsigned char bytes[16];
+       unsigned char* tmp;
+       unsigned long cbase;
+       unsigned long mbase;
+       unsigned int clen;
+       unsigned int mlen;
+
+       vm = ACCESS_FBINFO(video_vbase);
+       maxSize &= ~0x1FFFFF;   /* must be X*2MB (really it must be 2 or X*4MB) */
+       /* at least 2MB */
+       if (maxSize < 0x0200000) return 0;
+       if (maxSize > 0x1000000) maxSize = 0x1000000;
+       
+       mga_outb(M_EXTVGA_INDEX, 0x03);
+       mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80);
+
+       store = vm[0x1234];
+       tmp = bytes;
+       for (offs = 0x100000; offs < maxSize; offs += 0x200000)
+               *tmp++ = vm[offs];                      
+       for (offs = 0x100000; offs < maxSize; offs += 0x200000)
+               vm[offs] = 0x02;
+       if (ACCESS_FBINFO(features.accel.has_cacheflush))
+               mga_outb(M_CACHEFLUSH, 0x00);
+       else
+               vm[0x1234] = 0x99;
+       cbase = mbase = 0;
+       clen = mlen = 0;
+       for (offs = 0x100000; offs < maxSize; offs += 0x200000) {
+               if (vm[offs] != 0x02) 
+                       continue;
+               vm[offs] -= 0x02;
+               if (vm[offs]) 
+                       continue;
+               if (offs - 0x100000 == cbase + clen) {
+                       clen += 0x200000;
+               } else {
+                       cbase = offs - 0x100000;
+                       clen = 0x200000;
+               }
+               if ((clen > mlen)
+#ifndef MATROX_2MB_WITH_4MB_ADDON
+                   && (cbase == 0)
+#endif
+                  ) {
+                       mbase = cbase;
+                       mlen = clen;
+               }
+       }
+       tmp = bytes;
+       for (offs2 = 0x100000; offs2 < maxSize; offs2 += 0x200000)
+               vm[offs2] = *tmp++;
+       vm[0x1234] = store;
+
+       mga_outb(M_EXTVGA_INDEX, 0x03);
+       mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) & ~0x80);
+
+       *realOffset = mbase;
+       *realSize = mlen;
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+       ACCESS_FBINFO(interleave) = !(!isMillenium(MINFO) || (mbase & 0x3FFFFF) || (mlen & 0x3FFFFF));
+#endif
+       return 1;
+}
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+__initfunc(static int Ti3026_preinit(WPMINFO struct matrox_hw_state* hw)) {
+       static const int vxres_mill2[] = { 512,        640, 768,  800,  832,  960, 
+                                         1024, 1152, 1280,      1600, 1664, 1920, 
+                                         2048, 0};
+       static const int vxres_mill1[] = {             640, 768,  800,        960, 
+                                         1024, 1152, 1280,      1600,       1920, 
+                                         2048, 0};
+       ACCESS_FBINFO(millenium) = 1;
+       ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL);
+       ACCESS_FBINFO(capable.cfb4) = 1;
+       ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1;
+       /* preserve VGA I/O, BIOS and PPC */
+       hw->MXoptionReg &= 0xC0000100;
+       hw->MXoptionReg |= 0x002C0000;
+       if (ACCESS_FBINFO(devflags.novga))
+               hw->MXoptionReg &= ~0x00000100;
+       if (ACCESS_FBINFO(devflags.nobios))
+               hw->MXoptionReg &= ~0x40000000;
+       if (ACCESS_FBINFO(devflags.nopciretry))
+               hw->MXoptionReg |=  0x20000000;
+       pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+       return 0;
+}
+
+__initfunc(static void Ti3026_reset(WPMINFO struct matrox_hw_state* hw)) {
+       ACCESS_FBINFO(accel.ramdac_rev) = inTi3026(PMINFO TVP3026_XSILICONREV);
+
+       outTi3026(PMINFO TVP3026_XCLKCTRL, TVP3026_XCLKCTRL_SRC_CLK0VGA | TVP3026_XCLKCTRL_CLKSTOPPED);
+       outTi3026(PMINFO TVP3026_XTRUECOLORCTRL, TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR);
+       outTi3026(PMINFO TVP3026_XMUXCTRL, TVP3026_XMUXCTRL_VGA);
+       
+       outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
+       outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0x00);
+       outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
+
+       mga_outb(M_MISC_REG, 0x67);
+
+       outTi3026(PMINFO TVP3026_XMEMPLLCTRL, TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
+
+       ti3026_ramdac_init(PMINFO hw);
+
+       dprintk(KERN_INFO "matroxfb: PCI OPTION = %08X\n", hw->MXoptionReg);
+
+       mga_outl(M_RESET, 1);
+       udelay(250);
+       mga_outl(M_RESET, 0);
+       udelay(250);
+       /* wait for retrace, draw black square and so on... */
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static struct matrox_switch matrox_millenium = { 
+       Ti3026_preinit, Ti3026_reset, Ti3026_init, Ti3026_restore 
+};
+#endif
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static struct matrox_switch matrox_mystique = {
+       MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore
+};
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+static struct matrox_switch matrox_G100 = {
+       MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore
+};
+#endif
+
+struct video_board {
+       int maxvram;
+       int accelID;
+       struct matrox_switch* lowlevel;
+                };
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static struct video_board vbMillenium __initdata       = {0x0800000,   FB_ACCEL_MATROX_MGA2064W,       &matrox_millenium};
+static struct video_board vbMillenium2 __initdata      = {0x1000000,   FB_ACCEL_MATROX_MGA2164W,       &matrox_millenium};
+static struct video_board vbMillenium2A __initdata     = {0x1000000,   FB_ACCEL_MATROX_MGA2164W_AGP,   &matrox_millenium};
+#endif /* CONFIG_FB_MATROX_MILLENIUM */
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static struct video_board vbMystique __initdata                = {0x0800000,   FB_ACCEL_MATROX_MGA1064SG,      &matrox_mystique};
+#endif /* CONFIG_FB_MATROX_MYSTIQUE */
+#ifdef CONFIG_FB_MATROX_G100
+static struct video_board vbG100 __initdata            = {0x0800000,   FB_ACCEL_MATROX_MGAG100,        &matrox_G100};
+static struct video_board vbG200 __initdata            = {0x1000000,   FB_ACCEL_MATROX_MGAG200,        &matrox_G100};
+#endif
+
+#define DEVF_VIDEO64BIT        0x01
+#define        DEVF_SWAPS      0x02
+#define DEVF_MILLENIUM 0x04
+#define        DEVF_MILLENIUM2 0x08
+static struct board {
+       unsigned short vendor, device, rev, svid, sid;
+       unsigned flags;
+       struct video_board* base;
+       const char* name;
+               } dev_list[] __initdata = {
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_MIL,       0xFF,
+               0,                      0,
+               DEVF_MILLENIUM,
+               &vbMillenium,
+               "Millenium (PCI)"},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_MIL_2,     0xFF,
+               0,                      0,
+               DEVF_MILLENIUM | DEVF_MILLENIUM2 | DEVF_SWAPS,
+               &vbMillenium2,
+               "Millenium II (PCI)"},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_MIL_2_AGP, 0xFF,
+               0,                      0,
+               DEVF_MILLENIUM | DEVF_MILLENIUM2 | DEVF_SWAPS,
+               &vbMillenium2A,
+               "Millenium II (AGP)"},
+#endif
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_MYS,       0x02,
+               0,                      0,
+               DEVF_VIDEO64BIT,
+               &vbMystique,
+               "Mystique (PCI)"},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_MYS,       0xFF,
+               0,                      0,
+               DEVF_VIDEO64BIT | DEVF_SWAPS,
+               &vbMystique,
+               "Mystique 220 (PCI)"},
+#endif
+#ifdef CONFIG_FB_MATROX_G100
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G100,      0xFF,
+               PCI_SS_VENDOR_ID_MATROX,        PCI_SS_ID_MATROX_MGA_G100_PCI,
+               DEVF_VIDEO64BIT | DEVF_SWAPS,
+               &vbG100,
+               "MGA-G100 (PCI)"},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G100,      0xFF,
+               0,                      0,
+               DEVF_VIDEO64BIT | DEVF_SWAPS,
+               &vbG100,
+               "unknown G100 (PCI)"},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G100_AGP,  0xFF,
+               PCI_SS_VENDOR_ID_MATROX,        PCI_SS_ID_MATROX_UNSPECIFIED,
+               DEVF_VIDEO64BIT | DEVF_SWAPS,
+               &vbG100,
+               "MGA-G100 (AGP)"},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G100_AGP,  0xFF,
+               PCI_SS_VENDOR_ID_MATROX,        PCI_SS_ID_MATROX_MGA_G100_AGP,
+               DEVF_VIDEO64BIT | DEVF_SWAPS,
+               &vbG100,
+               "MGA-G100 (AGP)"},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G100_AGP,  0xFF,
+               PCI_SS_VENDOR_ID_SIEMENS_NIXDORF,       PCI_SS_ID_SIEMENS_MGA_G100_AGP,
+               DEVF_VIDEO64BIT | DEVF_SWAPS,
+               &vbG100,
+               "MGA-G100 (AGP)"},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G100_AGP,  0xFF,
+               PCI_SS_VENDOR_ID_MATROX,        PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP,
+               DEVF_VIDEO64BIT | DEVF_SWAPS,
+               &vbG100,
+               "Productiva G100 (AGP)"},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G100_AGP,  0xFF,
+               0,                      0,
+               DEVF_VIDEO64BIT | DEVF_SWAPS,
+               &vbG100,
+               "unknown G100 (AGP)"},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G200_AGP,  0xFF,
+               PCI_SS_VENDOR_ID_MATROX,        PCI_SS_ID_MATROX_UNSPECIFIED,
+               DEVF_VIDEO64BIT | DEVF_SWAPS,
+               &vbG200,
+               "MGA-G200 (AGP)"},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G200_AGP,  0xFF,
+               PCI_SS_VENDOR_ID_MATROX,        PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP,
+               DEVF_VIDEO64BIT | DEVF_SWAPS,
+               &vbG200,
+               "Mystique G200 (AGP)"},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G200_AGP,  0xFF,
+               PCI_SS_VENDOR_ID_MATROX,        PCI_SS_ID_MATROX_MILLENIUM_G200_AGP,
+               DEVF_VIDEO64BIT | DEVF_SWAPS,
+               &vbG200,
+               "Millenium G200 (AGP)"},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G200_AGP,  0xFF,
+               PCI_SS_VENDOR_ID_MATROX,        PCI_SS_ID_MATROX_MARVEL_G200_AGP,
+               DEVF_VIDEO64BIT | DEVF_SWAPS,
+               &vbG200,
+               "Marvel G200 (AGP)"},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G200_AGP,  0xFF,
+               PCI_SS_VENDOR_ID_SIEMENS_NIXDORF,       PCI_SS_ID_SIEMENS_MGA_G200_AGP,
+               DEVF_VIDEO64BIT | DEVF_SWAPS,
+               &vbG200,
+               "MGA-G200 (AGP)"},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G200_AGP,  0xFF,
+               0,                      0,
+               DEVF_VIDEO64BIT | DEVF_SWAPS,
+               &vbG200,
+               "unknown G200 (AGP)"},
+#endif
+       {0,                     0,                              0xFF,
+               0,                      0,
+               0,
+               NULL,
+               NULL}};
+       
+__initfunc(static int initMatrox2(WPMINFO struct display* d, struct board* b)) {
+       unsigned long ctrlptr_phys = 0;
+       unsigned long video_base_phys = 0;
+       int memsize;
+       struct matrox_hw_state* hw = ACCESS_FBINFO(currenthw);
+
+       /* set default values... */
+       vesafb_defined.accel_flags = FB_ACCELF_TEXT;
+
+       ACCESS_FBINFO(hw_switch) = b->base->lowlevel;
+       ACCESS_FBINFO(devflags.accelerator) = b->base->accelID;
+
+       printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name);
+       ACCESS_FBINFO(devflags.video64bits) = b->flags & DEVF_VIDEO64BIT;
+       if (b->flags & DEVF_SWAPS) {
+               ctrlptr_phys = ACCESS_FBINFO(pcidev)->base_address[1] & ~0x3FFF;
+               video_base_phys = ACCESS_FBINFO(pcidev)->base_address[0] & ~0x7FFFFF;   /* aligned at 8MB (or 16 for Mill 2) */
+       } else {
+               ctrlptr_phys = ACCESS_FBINFO(pcidev)->base_address[0] & ~0x3FFF;
+               video_base_phys = ACCESS_FBINFO(pcidev)->base_address[1] & ~0x7FFFFF;   /* aligned at 8MB */
+       }
+       if (!ctrlptr_phys) {
+               printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n");
+               return -EINVAL;
+       }
+       if (!video_base_phys) {
+               printk(KERN_ERR "matroxfb: video RAM is not available in PCI address space, matroxfb disabled\n");
+               return -EINVAL;
+       }
+       ACCESS_FBINFO(mmio) = ioremap_nocache(ctrlptr_phys, 16384); /* do we really need ioremap_nocache? */
+       if (!ACCESS_FBINFO(mmio)) {
+               printk(KERN_ERR "matroxfb: cannot ioremap(%lX, 16384), matroxfb disabled\n", ctrlptr_phys);
+               return -ENOMEM;
+       }
+       ACCESS_FBINFO(mmio_base) = ctrlptr_phys;
+       ACCESS_FBINFO(mmio_len) = 16384;
+       memsize = b->base->maxvram;
+/* convert mem (autodetect k, M) */
+       if (mem < 1024) mem *= 1024;
+       if (mem < 0x00100000) mem *= 1024;
+
+       if (mem && (mem < memsize))
+               memsize = mem;
+       ACCESS_FBINFO(video_vbase) = ioremap(video_base_phys, memsize);
+       ACCESS_FBINFO(video_base) = video_base_phys;
+       if (!ACCESS_FBINFO(video_vbase)) {
+               printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n", 
+                       video_base_phys, memsize);
+               iounmap(ACCESS_FBINFO(mmio));
+               return -ENOMEM;
+       }
+       {
+               u_int32_t cmd;
+               u_int32_t mga_option;
+
+               /* Matrox MilleniumII is deactivated on bootup, but address
+                  regions are assigned to board. So we have to enable it */
+               pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &mga_option);
+               pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd);
+               mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */
+               if ((cmd & PCI_COMMAND_MEMORY) !=
+                          PCI_COMMAND_MEMORY) {
+                       /* But if we have to enable it, we have probably to
+                           disable VGA I/O and BIOS... Sure? */
+                       dprintk(KERN_WARNING "matroxfb: PCI BIOS did not enable device!\n");
+                       cmd = (cmd | PCI_COMMAND_MEMORY) & ~PCI_COMMAND_VGA_PALETTE;
+                       mga_option &=  0xBFFFFEFF; 
+                       ACCESS_FBINFO(devflags.novga) = 1;
+                       ACCESS_FBINFO(devflags.nobios) = 1;
+               }
+               mga_option |= MX_OPTION_BSWAP;
+               if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, NULL)) {
+                       if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) {
+                               printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n");
+                       }
+                       mga_option |= 0x20000000;
+                       ACCESS_FBINFO(devflags.nopciretry) = 1;
+               }
+               pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, cmd);
+               pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mga_option);
+               hw->MXoptionReg = mga_option;
+
+               /* select non-DMA memory for PCI_MGA_DATA, otherwise dump of PCI cfg space can lock PCI bus */
+               /* maybe preinit() candidate, but it is same... for all devices... at this time... */
+               pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MGA_INDEX, 0x00003C00);
+       }
+
+       if (ACCESS_FBINFO(hw_switch)->preinit(PMINFO hw)) {
+               iounmap(ACCESS_FBINFO(video_vbase));
+               iounmap(ACCESS_FBINFO(mmio));
+               return -ENXIO;
+       }
+
+       {
+               unsigned int offs;
+
+               if (!matroxfb_getmemory(PMINFO memsize, &offs, &ACCESS_FBINFO(video_len)) || !ACCESS_FBINFO(video_len)) {
+                       printk(KERN_ERR "matroxfb: cannot determine memory size\n");
+                       iounmap(ACCESS_FBINFO(video_vbase));
+                       iounmap(ACCESS_FBINFO(mmio));
+                       return -ENOMEM;
+               }
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+#ifdef FBCON_HAS_CFB24
+               {
+                       unsigned int end = offs + ACCESS_FBINFO(video_len);
+
+                       if (offs)
+                               offs = ((offs - 1) / (4096 * 3) + 1) * 4096 * 3;
+                       ACCESS_FBINFO(video_len) = end - offs;
+               }
+#endif
+               mga_ydstorg(MINFO) = offs;
+               video_base_phys += offs;
+#endif
+       }
+       ACCESS_FBINFO(curr.video_type) = FB_TYPE_PACKED_PIXELS;
+       ACCESS_FBINFO(currcon) = -1;
+       iounmap(ACCESS_FBINFO(video_vbase));
+       ACCESS_FBINFO(video_vbase) = ioremap(video_base_phys, ACCESS_FBINFO(video_len));
+       ACCESS_FBINFO(video_base) = video_base_phys;
+       if (!ACCESS_FBINFO(video_vbase)) {
+               printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n", 
+                       video_base_phys, ACCESS_FBINFO(video_len));
+               iounmap(ACCESS_FBINFO(mmio));
+               return -ENOMEM;
+       }
+#ifdef CONFIG_MTRR
+       ACCESS_FBINFO(mtrr.vram) = mtrr_add(video_base_phys, ACCESS_FBINFO(video_len), MTRR_TYPE_WRCOMB, 1);
+       ACCESS_FBINFO(mtrr.vram_valid) = 1;
+       printk(KERN_INFO "matroxfb: MTRR's turned on\n");
+#endif /* CONFIG_MTRR */
+
+/* validate params, autodetect k, M */
+       if (fh < 1000) fh *= 1000;      /* 1kHz minimum */
+       if (maxclk < 1000) maxclk *= 1000;      /* kHz -> Hz, MHz -> kHz */
+       if (maxclk < 1000000) maxclk *= 1000;   /* kHz -> Hz, 1MHz minimum */
+       vesa &= 0x1DFF;         /* mask out clearscreen, acceleration and so on */
+
+       ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
+       ACCESS_FBINFO(fbcon.monspecs.hfmax) = fh;
+       ACCESS_FBINFO(fbcon.monspecs.vfmin) = 0;
+       ACCESS_FBINFO(fbcon.monspecs.vfmax) = fv;
+       ACCESS_FBINFO(fbcon.monspecs.dpms) = 0; /* TBD */
+
+/* static settings */
+       for (RSptr = vesamap; RSptr->vesa; RSptr++) {
+               if (RSptr->vesa == vesa) break;
+       }
+       if (!RSptr->vesa) {
+               printk(KERN_ERR "Invalid vesa mode 0x%04X\n", vesa);
+               RSptr = vesamap;
+       }
+       {
+               int res = RSResolution(RSptr->info)-1;
+               if (!left)
+                       left = timmings[res].left;
+               if (!xres)
+                       xres = timmings[res].xres;
+               if (!right)
+                       right = timmings[res].right;
+               if (!hslen)
+                       hslen = timmings[res].hslen;
+               if (!upper)
+                       upper = timmings[res].upper;
+               if (!yres)
+                       yres = timmings[res].yres;
+               if (!lower)
+                       lower = timmings[res].lower;
+               if (!vslen)
+                       vslen = timmings[res].vslen;
+               if (!(fv||fh||maxclk||pixclock))
+                       fv = timmings[res].vfreq;
+               if (!depth)
+                       depth = RSDepth(RSptr->info);
+       }
+       if (sync == -1) {
+               sync = 0;
+               if (yres < 480)
+                       sync |= FB_SYNC_VERT_HIGH_ACT;
+       }
+       if (xres < 320)
+               xres = 320;
+       if (xres > 2048)
+               xres = 2048;
+       if (yres < 200)
+               yres = 200;
+       if (yres > 2048)
+               yres = 2048;
+       {
+               int tmp;
+
+               if (fv) {
+                       tmp = fv * (upper + yres + lower + vslen);
+                       if ((tmp < fh) || (fh == 0)) fh = tmp;
+               }
+               if (fh) {
+                       tmp = fh * (left + xres + right + hslen);
+                       if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
+               }
+               maxclk = (maxclk + 499) / 500;
+               if (maxclk) {
+                       tmp = (2000000000 + maxclk) / maxclk;
+                       if (tmp > pixclock) pixclock = tmp;
+               }
+       }
+       vesafb_defined.red = colors[depth-1].red;
+       vesafb_defined.green = colors[depth-1].green;
+       vesafb_defined.blue = colors[depth-1].blue;
+       vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel;
+       if (pixclock < 2000)            /* > 500MHz */
+               pixclock = 4000;        /* 250MHz */
+       if (pixclock > 1000000)
+               pixclock = 1000000;     /* 1MHz */
+       vesafb_defined.xres = xres;
+       vesafb_defined.yres = yres;
+       {
+               int pixel_size = vesafb_defined.bits_per_pixel;
+               int avamem = ACCESS_FBINFO(video_len);
+
+               /* displaying is possible only in first 8MB */
+               if (avamem > 0x8000000)
+                       avamem = 0x8000000;
+
+               vesafb_defined.xres_virtual = matroxfb_pitch_adjust(PMINFO xres, pixel_size);
+               if (nopan) {
+                       vesafb_defined.yres_virtual = yres;
+               } else {
+                       vesafb_defined.yres_virtual = (avamem * 8 / (pixel_size * vesafb_defined.xres_virtual)) & ~0x1F;
+                       if (vesafb_defined.yres_virtual < vesafb_defined.yres)
+                               vesafb_defined.yres_virtual = yres;
+               }
+       }
+       vesafb_defined.xoffset = 0;
+       vesafb_defined.yoffset = 0;
+       vesafb_defined.grayscale = 0;
+       vesafb_defined.pixclock = pixclock;
+       vesafb_defined.left_margin = left;
+       vesafb_defined.right_margin = right;
+       vesafb_defined.hsync_len = hslen;
+       vesafb_defined.upper_margin = upper;
+       vesafb_defined.lower_margin = lower;
+       vesafb_defined.vsync_len = vslen;
+       vesafb_defined.sync = sync;
+       vesafb_defined.vmode = 0;
+
+       if (!ACCESS_FBINFO(devflags.novga))
+               request_region(0x3C0, 32, "matrox");
+       if (noaccel)
+               vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT;
+
+       strcpy(ACCESS_FBINFO(fbcon.modename), "MATROX VGA");
+       ACCESS_FBINFO(fbcon.changevar) = NULL;
+       ACCESS_FBINFO(fbcon.node) = -1;
+       ACCESS_FBINFO(fbcon.fbops) = &matroxfb_ops;
+       ACCESS_FBINFO(fbcon.disp) = d;
+       ACCESS_FBINFO(fbcon.switch_con) = &matroxfb_switch;
+       ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar;
+       ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank;
+       ACCESS_FBINFO(fbcon.flags) = FBINFO_FLAG_DEFAULT;
+       ACCESS_FBINFO(hw_switch->reset(PMINFO hw));
+
+       if (matroxfb_set_var(&vesafb_defined, -2, &ACCESS_FBINFO(fbcon))) {
+               printk(KERN_ERR "matroxfb: cannot set required parameters\n");
+               return -EINVAL;
+       }
+
+       printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n",
+               vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel,
+               vesafb_defined.xres_virtual, vesafb_defined.yres_virtual);
+       printk(KERN_INFO "matroxfb: framebuffer at 0x%lX, mapped to 0x%p, size %d\n",
+               ACCESS_FBINFO(video_base), ACCESS_FBINFO(video_vbase), ACCESS_FBINFO(video_len));
+       
+/* We do not have to set currcon to 0... register_framebuffer do it for us on first console
+ * and we do not want currcon == 0 for subsequent framebuffers */
+
+       if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0)
+               return -EINVAL;
+       printk("fb%d: %s frame buffer device\n",
+              GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), ACCESS_FBINFO(fbcon.modename));
+       if (ACCESS_FBINFO(currcon) < 0) {
+               /* there is no console on this fb... but we have to initialize hardware 
+                * until someone tells me what is proper thing to do */
+               printk(KERN_INFO "fb%d: initializing hardware\n",
+                       GET_FB_IDX(ACCESS_FBINFO(fbcon.node)));
+               matroxfb_set_var(&vesafb_defined, -1, &ACCESS_FBINFO(fbcon));
+       }
+       return 0;
+}
+
+static struct matrox_fb_info* fb_list = NULL;
+
+__initfunc(static int matrox_init(void)) {
+       struct pci_dev* pdev = NULL;
+
+       if (disabled)
+               return -ENXIO; 
+       while ((pdev = pci_find(pdev)) != NULL) {
+               struct board* b;
+               u_int8_t rev;
+               u_int16_t svid;
+               u_int16_t sid;
+
+               pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+               pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &svid);
+               pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sid);
+               for (b = dev_list; b->vendor; b++) {
+                       if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < rev)) continue;
+                       if (b->svid)
+                               if ((b->svid != svid) || (b->sid != sid)) continue;
+                       if (dev <= 0) {
+                               struct matrox_fb_info* minfo;
+                               struct display* d;
+                               int err;
+
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+                               minfo = (struct matrox_fb_info*)kmalloc(sizeof(*minfo), GFP_KERNEL);
+                               if (minfo) {
+                                       d = (struct display*)kmalloc(sizeof(*d), GFP_KERNEL);
+                                       if (d) {
+#else
+                               minfo = &global_mxinfo;
+                               d = &global_disp;
+#endif
+                               memset(MINFO, 0, sizeof(*MINFO));
+                               memset(d, 0, sizeof(*d));
+
+                               ACCESS_FBINFO(currenthw) = &ACCESS_FBINFO(hw1);
+                               ACCESS_FBINFO(newhw) = &ACCESS_FBINFO(hw2);
+                               ACCESS_FBINFO(pcidev) = pdev;
+                               /* CMDLINE */
+                               memcpy(ACCESS_FBINFO(fbcon.fontname), fontname, sizeof(ACCESS_FBINFO(fbcon.fontname)));
+                               /* DEVFLAGS */
+                               ACCESS_FBINFO(devflags.inverse) = inverse;
+                               ACCESS_FBINFO(devflags.novga) = novga;
+                               ACCESS_FBINFO(devflags.nobios) = nobios;
+                               ACCESS_FBINFO(devflags.nopciretry) = no_pci_retry;
+                               ACCESS_FBINFO(devflags.mga_24bpp_fix) = inv24;
+                               ACCESS_FBINFO(devflags.precise_width) = option_precise_width;
+                               ACCESS_FBINFO(devflags.hwcursor) = hwcursor;
+
+                               err = initMatrox2(PMINFO d, b);
+                               if (!err) {
+                                       ACCESS_FBINFO(next_fb) = fb_list;
+                                       fb_list = MINFO;
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+                                       goto leave;
+#else
+                                       return 0;
+#endif
+                               }
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+                                               kfree(d);
+                                       }
+                                       kfree(minfo);
+                               }
+#endif
+                       }
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+leave:;
+#endif
+                       if (dev == 0) return 0;
+                       if (dev > 0) dev--;
+                       break;
+               }
+       }
+       return 0;
+}
+
+#ifndef MODULE
+__initfunc(void matroxfb_init(void))
+{
+       matrox_init();
+}
+
+#else
+
+MODULE_AUTHOR("(c) 1998 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millenium/Mystique");
+MODULE_PARM(mem, "i");
+MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)");
+MODULE_PARM(disabled, "i");
+MODULE_PARM_DESC(disabled, "Disabled (0 or 1=disabled), meaningless for module (default=0)");
+MODULE_PARM(noaccel, "i");
+MODULE_PARM_DESC(noaccel, "Do not use accelerating engine (0 or 1=disabled) (default=0)");
+MODULE_PARM(nopan, "i");
+MODULE_PARM_DESC(nopan, "Disable pan on startup (0 or 1=disabled) (default=0)");
+MODULE_PARM(no_pci_retry, "i");
+MODULE_PARM_DESC(no_pci_retry, "PCI retries enabled (0 or 1=disabled) (default=0)");
+MODULE_PARM(novga, "i");
+MODULE_PARM_DESC(novga, "VGA I/O (0x3C0-0x3DF) disabled (0 or 1=disabled) (default=0)");
+MODULE_PARM(nobios, "i");
+MODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)"); 
+MODULE_PARM(inv24, "i");
+MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)");
+MODULE_PARM(inverse, "i");
+MODULE_PARM_DESC(inverse, "Inverse (0 or 1) (default=0)");
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+MODULE_PARM(dev, "i");
+MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=all working)");
+#else
+MODULE_PARM(dev, "i");
+MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=first working)");
+#endif
+MODULE_PARM(vesa, "i");
+MODULE_PARM_DESC(vesa, "Startup videomode (0x100-0x1FF) (default=0x101)");
+MODULE_PARM(xres, "i");
+MODULE_PARM_DESC(xres, "Horizontal resolutioni (px), overrides xres from vesa (default=vesa)");
+MODULE_PARM(yres, "i");
+MODULE_PARM_DESC(yres, "Vertical resolution (scans), overrides yres from vesa (default=vesa)");
+MODULE_PARM(upper, "i");
+MODULE_PARM_DESC(upper, "Upper blank space (scans), overrides upper from vesa (default=vesa)");
+MODULE_PARM(lower, "i");
+MODULE_PARM_DESC(lower, "Lower blank space (scans), overrides lower from vesa (default=vesa)");
+MODULE_PARM(vslen, "i");
+MODULE_PARM_DESC(vslen, "Vertical sync length (scans), overrides lower from vesa (default=vesa)");
+MODULE_PARM(left, "i");
+MODULE_PARM_DESC(left, "Left blank space (px), overrides left from vesa (default=vesa)");
+MODULE_PARM(right, "i");
+MODULE_PARM_DESC(right, "Right blank space (px), overrides right from vesa (default=vesa)");
+MODULE_PARM(hslen, "i");
+MODULE_PARM_DESC(hslen, "Horizontal sync length (px), overrides hslen from vesa (default=vesa)");
+MODULE_PARM(pixclock, "i");
+MODULE_PARM_DESC(pixclock, "Pixelclock (ns), overrides pixclock from vesa (default=vesa)");
+MODULE_PARM(sync, "i");
+MODULE_PARM_DESC(sync, "Sync polarity, overrides sync from vesa (default=vesa)");
+MODULE_PARM(depth, "i");
+MODULE_PARM_DESC(depth, "Color depth (8,15,16,24,32) (default=vesa)");
+MODULE_PARM(maxclk, "i");
+MODULE_PARM_DESC(maxclk, "Startup maximal clock, 0-999MHz, 1000-999999kHz, 1000000-INF Hz");
+MODULE_PARM(fh, "i");
+MODULE_PARM_DESC(fh, "Startup horizontal frequency, 0-999kHz, 1000-INF Hz");
+MODULE_PARM(fv, "i");
+MODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n"
+"You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\"\n");
+
+
+__initfunc(int init_module(void)) {
+       if (depth == 0)
+               depth = 0;      /* default */
+       else if (depth == 4)
+               depth = RS4bpp;
+       else if (depth == 8)
+               depth = RS8bpp;
+       else if (depth == 15)
+               depth = RS15bpp;
+       else if (depth == 16)
+               depth = RS16bpp;
+       else if (depth == 24)
+               depth = RS24bpp;
+       else if (depth == 32)
+               depth = RS32bpp;
+       else {
+               printk(KERN_ERR "matroxfb: depth %d is not supported, using default\n", depth);
+               depth = 0;
+       }
+       matrox_init();
+       if (!fb_list) return -ENXIO;
+       return 0;
+}
+
+void cleanup_module(void) {
+       while (fb_list) {
+               struct matrox_fb_info* minfo;
+
+               minfo = fb_list;
+               fb_list = fb_list->next_fb;
+               unregister_framebuffer(&ACCESS_FBINFO(fbcon));
+#ifdef CONFIG_MTRR
+               if (ACCESS_FBINFO(mtrr.vram_valid))
+                       mtrr_del(ACCESS_FBINFO(mtrr.vram), ACCESS_FBINFO(video_base), ACCESS_FBINFO(video_len));
+#endif
+               iounmap(ACCESS_FBINFO(mmio));
+               iounmap(ACCESS_FBINFO(video_vbase));
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+               kfree_s(ACCESS_FBINFO(fbcon.disp), sizeof(struct display));
+               kfree_s(minfo, sizeof(struct matrox_fb_info));
+#endif
+       }
+}
+#endif /* MODULE */
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
index 42c43ced9ca38dc0b75f91dff54a3dd23efa6106..8bfffe1474183fd16776037583461cb98ceab40a 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
+#include <asm/io.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
@@ -98,38 +99,26 @@ struct display_data {
        long v_dispend;         /* Horizontal Display End */
 };
 
-static struct retz3fb_par current_par;
-
-static int current_par_valid = 0;
-static int currcon = 0;
-
-static struct display disp;
-static struct fb_info fb_info;
-
-
-/*
- *    Switch for Chipset Independency
- */
-
-static struct fb_hwswitch {
-
-   /* Initialisation */
+struct retz3_fb_info {
+       struct fb_info info;
+       unsigned long base;
+       unsigned long fbmem;
+       unsigned long fbsize;
+       volatile unsigned char *regs;
+       unsigned long physfbmem;
+       unsigned long physregs;
+       int currcon;
+       int current_par_valid; /* set to 0 by memset */
+       struct display disp;
+       struct retz3fb_par current_par;
+       unsigned char color_table [256][3];
+};
 
-   int (*init)(void);
 
-   /* Display Control */
+static char fontname[40] __initdata = { 0 };
 
-   int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3fb_par *par);
-   int (*decode_var)(struct fb_var_screeninfo *var, struct retz3fb_par *par);
-   int (*encode_var)(struct fb_var_screeninfo *var, struct retz3fb_par *par);
-   int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned
-                   int *green, unsigned int *blue, unsigned int *transp,
-                       struct fb_info *info);
-   int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int
-                   green, unsigned int blue, unsigned int transp,
-                       struct fb_info *info);
-   void (*blank)(int blank);
-} *fbhw;
+#define retz3info(info) ((struct retz3_fb_info *)(info))
+#define fbinfo(info) ((struct fb_info *)(info))
 
 
 /*
@@ -139,13 +128,6 @@ static struct fb_hwswitch {
 static char retz3fb_name[16] = "RetinaZ3";
 
 
-static unsigned char retz3_color_table [256][3];
-static unsigned long z3_mem;
-static unsigned long z3_fbmem;
-static unsigned long z3_size;
-static volatile unsigned char *z3_regs;
-
-
 /*
  * A small info on how to convert XFree86 timing values into fb
  * timings - by Frank Neumann:
@@ -197,7 +179,7 @@ static struct fb_videomode retz3fb_predefined[] __initdata = {
            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_ACCELF_TEXT, 38461, 28, 32, 12, 10, 96, 2,
-           FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+           FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
        }
     },
     /*
@@ -228,14 +210,14 @@ static struct fb_videomode retz3fb_predefined[] __initdata = {
            640, 480, 640, 480, 0, 0, 16, 0,
            {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
            0, 0, -1, -1, 0, 38461/2, 28, 32, 12, 10, 96, 2,
-           FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+           FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
        }
     }, {
        "640x480-24", {         /* 640x480, 24 bpp */
            640, 480, 640, 480, 0, 0, 24, 0,
            {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0},
            0, 0, -1, -1, 0, 38461/3, 28, 32, 12, 10, 96, 2,
-           FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+           FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
        }
     },
 };
@@ -297,7 +279,7 @@ static struct display_switch fbcon_retz3_8;
  *    Accelerated Functions used by the low level console driver
  */
 
-static void retz3_bitblt(struct fb_var_screeninfo *scr,
+static void retz3_bitblt(struct display *p,
                         unsigned short curx, unsigned short cury, unsigned
                         short destx, unsigned short desty, unsigned short
                         width, unsigned short height, unsigned short cmd,
@@ -307,29 +289,28 @@ static void retz3_bitblt(struct fb_var_screeninfo *scr,
  *   Hardware Specific Routines
  */
 
-static int retz3_init(void);
-static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct retz3fb_par *par);
+static int retz3_encode_fix(struct fb_info *info,
+                           struct fb_fix_screeninfo *fix,
+                           struct retz3fb_par *par);
 static int retz3_decode_var(struct fb_var_screeninfo *var,
-                          struct retz3fb_par *par);
+                           struct retz3fb_par *par);
 static int retz3_encode_var(struct fb_var_screeninfo *var,
-                          struct retz3fb_par *par);
+                           struct retz3fb_par *par);
 static int retz3_getcolreg(unsigned int regno, unsigned int *red,
                           unsigned int *green, unsigned int *blue,
                           unsigned int *transp, struct fb_info *info);
 static int retz3_setcolreg(unsigned int regno, unsigned int red,
                           unsigned int green, unsigned int blue,
                           unsigned int transp, struct fb_info *info);
-static void retz3_blank(int blank);
-
 
 /*
  *    Internal routines
  */
 
-static void retz3fb_get_par(struct retz3fb_par *par);
-static void retz3fb_set_par(struct retz3fb_par *par);
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
+static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par);
+static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par);
+static int do_fb_set_var(struct fb_info *info,
+                        struct fb_var_screeninfo *var, int isactive);
 static void do_install_cmap(int con, struct fb_info *info);
 static void retz3fb_set_disp(int con, struct fb_info *info);
 static int get_video_mode(const char *name);
@@ -381,12 +362,11 @@ static unsigned short find_fq(unsigned int freq)
 }
 
 
-static int retz3_set_video(struct fb_var_screeninfo *var,
+static int retz3_set_video(struct fb_info *info,
+                          struct fb_var_screeninfo *var,
                           struct retz3fb_par *par)
 {
-#if 0
-       float freq_f;
-#endif
+       volatile unsigned char *regs = retz3info(info)->regs;
        unsigned int freq;
 
        int xres, hfront, hsync, hback;
@@ -482,11 +462,11 @@ static int retz3_set_video(struct fb_var_screeninfo *var,
        if (data.v_total >= 1024)
                printk("MAYDAY: v_total >= 1024; bailing out!\n");
 
-       reg_w(GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
-       reg_w(GREG_FEATURE_CONTROL_W, 0x00);
+       reg_w(regs, GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
+       reg_w(regs, GREG_FEATURE_CONTROL_W, 0x00);
 
-       seq_w(SEQ_RESET, 0x00);
-       seq_w(SEQ_RESET, 0x03); /* reset sequencer logic */
+       seq_w(regs, SEQ_RESET, 0x00);
+       seq_w(regs, SEQ_RESET, 0x03);   /* reset sequencer logic */
 
        /*
         * CLOCKING_MODE bits:
@@ -495,32 +475,32 @@ static int retz3_set_video(struct fb_var_screeninfo *var,
         * (The CL drivers sets it to 0x21 with the comment:
         *  FullBandwidth (video off) and 8/9 dot clock)
         */
-       seq_w(SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
+       seq_w(regs, SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
 
-       seq_w(SEQ_MAP_MASK, 0x0f);        /* enable writing to plane 0-3 */
-       seq_w(SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
-       seq_w(SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
-       seq_w(SEQ_RESET, 0x01);
-       seq_w(SEQ_RESET, 0x03);
+       seq_w(regs, SEQ_MAP_MASK, 0x0f);        /* enable writing to plane 0-3 */
+       seq_w(regs, SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
+       seq_w(regs, SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
+       seq_w(regs, SEQ_RESET, 0x01);
+       seq_w(regs, SEQ_RESET, 0x03);
 
-       seq_w(SEQ_EXTENDED_ENABLE, 0x05);
+       seq_w(regs, SEQ_EXTENDED_ENABLE, 0x05);
 
-       seq_w(SEQ_CURSOR_CONTROL, 0x00);        /* disable cursor */
-       seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
-       seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
-       seq_w(SEQ_LINEAR_0, 0x4a);
-       seq_w(SEQ_LINEAR_1, 0x00);
+       seq_w(regs, SEQ_CURSOR_CONTROL, 0x00);  /* disable cursor */
+       seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00);
+       seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00);
+       seq_w(regs, SEQ_LINEAR_0, 0x4a);
+       seq_w(regs, SEQ_LINEAR_1, 0x00);
 
-       seq_w(SEQ_SEC_HOST_OFF_HI, 0x00);
-       seq_w(SEQ_SEC_HOST_OFF_LO, 0x00);
-       seq_w(SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
+       seq_w(regs, SEQ_SEC_HOST_OFF_HI, 0x00);
+       seq_w(regs, SEQ_SEC_HOST_OFF_LO, 0x00);
+       seq_w(regs, SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
 
        /*
         * The lower 4 bits (0-3) are used to set the font-width for
         * text-mode - DON'T try to set this for gfx-mode.
         */
-       seq_w(SEQ_EXT_CLOCK_MODE, 0x10);
-       seq_w(SEQ_EXT_VIDEO_ADDR, 0x03);
+       seq_w(regs, SEQ_EXT_CLOCK_MODE, 0x10);
+       seq_w(regs, SEQ_EXT_VIDEO_ADDR, 0x03);
 
        /*
         * Extended Pixel Control:
@@ -528,52 +508,52 @@ static int retz3_set_video(struct fb_var_screeninfo *var,
         * bit 1: (Packed/Nibble Pixel Format ?)
         * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp
         */
-       seq_w(SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
-
-       seq_w(SEQ_BUS_WIDTH_FEEDB, 0x04);
-       seq_w(SEQ_COLOR_EXP_WFG, 0x01);
-       seq_w(SEQ_COLOR_EXP_WBG, 0x00);
-       seq_w(SEQ_EXT_RW_CONTROL, 0x00);
-       seq_w(SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
-       seq_w(SEQ_COLOR_KEY_CNTL, 0x40);
-       seq_w(SEQ_COLOR_KEY_MATCH0, 0x00);
-       seq_w(SEQ_COLOR_KEY_MATCH1, 0x00);
-       seq_w(SEQ_COLOR_KEY_MATCH2, 0x00);
-       seq_w(SEQ_CRC_CONTROL, 0x00);
-       seq_w(SEQ_PERF_SELECT, 0x10);
-       seq_w(SEQ_ACM_APERTURE_1, 0x00);
-       seq_w(SEQ_ACM_APERTURE_2, 0x30);
-       seq_w(SEQ_ACM_APERTURE_3, 0x00);
-       seq_w(SEQ_MEMORY_MAP_CNTL, 0x03);
+       seq_w(regs, SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
+
+       seq_w(regs, SEQ_BUS_WIDTH_FEEDB, 0x04);
+       seq_w(regs, SEQ_COLOR_EXP_WFG, 0x01);
+       seq_w(regs, SEQ_COLOR_EXP_WBG, 0x00);
+       seq_w(regs, SEQ_EXT_RW_CONTROL, 0x00);
+       seq_w(regs, SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
+       seq_w(regs, SEQ_COLOR_KEY_CNTL, 0x40);
+       seq_w(regs, SEQ_COLOR_KEY_MATCH0, 0x00);
+       seq_w(regs, SEQ_COLOR_KEY_MATCH1, 0x00);
+       seq_w(regs, SEQ_COLOR_KEY_MATCH2, 0x00);
+       seq_w(regs, SEQ_CRC_CONTROL, 0x00);
+       seq_w(regs, SEQ_PERF_SELECT, 0x10);
+       seq_w(regs, SEQ_ACM_APERTURE_1, 0x00);
+       seq_w(regs, SEQ_ACM_APERTURE_2, 0x30);
+       seq_w(regs, SEQ_ACM_APERTURE_3, 0x00);
+       seq_w(regs, SEQ_MEMORY_MAP_CNTL, 0x03);
 
 
        /* unlock register CRT0..CRT7 */
-       crt_w(CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
+       crt_w(regs, CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
 
        /* Zuerst zu schreibende Werte nur per printk ausgeben */
        DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total);
-       crt_w(CRT_HOR_TOTAL, data.h_total & 0xff);
+       crt_w(regs, CRT_HOR_TOTAL, data.h_total & 0xff);
 
        DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend);
-       crt_w(CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
+       crt_w(regs, CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
 
        DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart);
-       crt_w(CRT_START_HOR_BLANK, data.h_bstart & 0xff);
+       crt_w(regs, CRT_START_HOR_BLANK, data.h_bstart & 0xff);
 
        DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32);
-       crt_w(CRT_END_HOR_BLANK,  0x80 | (data.h_bstop & 0x1f));
+       crt_w(regs, CRT_END_HOR_BLANK,  0x80 | (data.h_bstop & 0x1f));
 
        DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart);
-       crt_w(CRT_START_HOR_RETR, data.h_sstart & 0xff);
+       crt_w(regs, CRT_START_HOR_RETR, data.h_sstart & 0xff);
 
        tmp = (data.h_sstop & 0x1f);
        if (data.h_bstop & 0x20)
                tmp |= 0x80;
        DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp);
-       crt_w(CRT_END_HOR_RETR, tmp);
+       crt_w(regs, CRT_END_HOR_RETR, tmp);
 
        DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff);
-       crt_w(CRT_VER_TOTAL, (data.v_total & 0xff));
+       crt_w(regs, CRT_VER_TOTAL, (data.v_total & 0xff));
 
        tmp = 0x10;  /* LineCompare bit #9 */
        if (data.v_total & 256)
@@ -591,9 +571,9 @@ static int retz3_set_video(struct fb_var_screeninfo *var,
        if (data.v_sstart & 512)
                tmp |= 0x80;
        DEBUG printk("CRT_OVERFLOW: %d\n", tmp);
-       crt_w(CRT_OVERFLOW, tmp);
+       crt_w(regs, CRT_OVERFLOW, tmp);
 
-       crt_w(CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
+       crt_w(regs, CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
 
        tmp = 0x40; /* LineCompare bit #8 */
        if (data.v_bstart & 512)
@@ -601,47 +581,47 @@ static int retz3_set_video(struct fb_var_screeninfo *var,
        if (var->vmode & FB_VMODE_DOUBLE)
                tmp |= 0x80;
        DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp);
-       crt_w(CRT_MAX_SCAN_LINE, tmp);
+       crt_w(regs, CRT_MAX_SCAN_LINE, tmp);
 
-       crt_w(CRT_CURSOR_START, 0x00);
-       crt_w(CRT_CURSOR_END, 8 & 0x1f); /* font height */
+       crt_w(regs, CRT_CURSOR_START, 0x00);
+       crt_w(regs, CRT_CURSOR_END, 8 & 0x1f); /* font height */
 
-       crt_w(CRT_START_ADDR_HIGH, 0x00);
-       crt_w(CRT_START_ADDR_LOW, 0x00);
+       crt_w(regs, CRT_START_ADDR_HIGH, 0x00);
+       crt_w(regs, CRT_START_ADDR_LOW, 0x00);
 
-       crt_w(CRT_CURSOR_LOC_HIGH, 0x00);
-       crt_w(CRT_CURSOR_LOC_LOW, 0x00);
+       crt_w(regs, CRT_CURSOR_LOC_HIGH, 0x00);
+       crt_w(regs, CRT_CURSOR_LOC_LOW, 0x00);
 
        DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff);
-       crt_w(CRT_START_VER_RETR, (data.v_sstart & 0xff));
+       crt_w(regs, CRT_START_VER_RETR, (data.v_sstart & 0xff));
 
 #if 1
        /* 5 refresh cycles per scanline */
        DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16);
-       crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
+       crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
 #else
        DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16);
-       crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
+       crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
 #endif
        DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff);
-       crt_w(CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
+       crt_w(regs, CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
 
        DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff);
-       crt_w(CRT_START_VER_BLANK, (data.v_bstart & 0xff));
+       crt_w(regs, CRT_START_VER_BLANK, (data.v_bstart & 0xff));
 
        DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff);
-       crt_w(CRT_END_VER_BLANK, (data.v_bstop & 0xff));
+       crt_w(regs, CRT_END_VER_BLANK, (data.v_bstop & 0xff));
 
        DEBUG printk("CRT_MODE_CONTROL: 0xe3\n");
-       crt_w(CRT_MODE_CONTROL, 0xe3);
+       crt_w(regs, CRT_MODE_CONTROL, 0xe3);
 
        DEBUG printk("CRT_LINE_COMPARE: 0xff\n");
-       crt_w(CRT_LINE_COMPARE, 0xff);
+       crt_w(regs, CRT_LINE_COMPARE, 0xff);
 
        tmp = (var->xres_virtual / 8) * (bpp / 8);
-       crt_w(CRT_OFFSET, tmp);
+       crt_w(regs, CRT_OFFSET, tmp);
 
-       crt_w(CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
+       crt_w(regs, CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
 
        tmp = 0x20;                     /* Enable extended end bits */
        if (data.h_total & 0x100)
@@ -655,12 +635,12 @@ static int retz3_set_video(struct fb_var_screeninfo *var,
        if (var->vmode & FB_VMODE_INTERLACED)
                tmp |= 0x10;
        DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
-       crt_w(CRT_EXT_HOR_TIMING1, tmp);
+       crt_w(regs, CRT_EXT_HOR_TIMING1, tmp);
 
        tmp = 0x00;
        if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
                tmp |= 0x10;
-       crt_w(CRT_EXT_START_ADDR, tmp);
+       crt_w(regs, CRT_EXT_START_ADDR, tmp);
 
        tmp = 0x00;
        if (data.h_total & 0x200)
@@ -673,7 +653,7 @@ static int retz3_set_video(struct fb_var_screeninfo *var,
                tmp |= 0x08;
        tmp |= ((data.h_bstop & 0xc0) >> 2);
        tmp |= ((data.h_sstop & 0x60) << 1);
-       crt_w(CRT_EXT_HOR_TIMING2, tmp);
+       crt_w(regs, CRT_EXT_HOR_TIMING2, tmp);
        DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp);
 
        tmp = 0x10;                     /* Line compare bit 10 */
@@ -688,138 +668,84 @@ static int retz3_set_video(struct fb_var_screeninfo *var,
        tmp |= ((data.v_bstop & 0x300) >> 3);
        if (data.v_sstop & 0x10)
                tmp |= 0x80;
-       crt_w(CRT_EXT_VER_TIMING, tmp);
+       crt_w(regs, CRT_EXT_VER_TIMING, tmp);
        DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp);
 
-       crt_w(CRT_MONITOR_POWER, 0x00);
+       crt_w(regs, CRT_MONITOR_POWER, 0x00);
 
        /*
         * Convert from ps to Hz.
         */
-#if 0
-       freq_f = (1.0/(float)var->pixclock) * 1000000000;
-       freq = ((unsigned int)freq_f) * 1000;
-#else
        freq = 2000000000 / var->pixclock;
        freq = freq * 500;
-#endif
 
        best_freq = find_fq(freq);
-       pll_w(0x02, best_freq);
+       pll_w(regs, 0x02, best_freq);
        best_freq = find_fq(61000000);
-       pll_w(0x0a, best_freq);
-       pll_w(0x0e, 0x22);
-
-       gfx_w(GFX_SET_RESET, 0x00);
-       gfx_w(GFX_ENABLE_SET_RESET, 0x00);
-       gfx_w(GFX_COLOR_COMPARE, 0x00);
-       gfx_w(GFX_DATA_ROTATE, 0x00);
-       gfx_w(GFX_READ_MAP_SELECT, 0x00);
-       gfx_w(GFX_GRAPHICS_MODE, 0x00);
-       gfx_w(GFX_MISC, 0x05);
-       gfx_w(GFX_COLOR_XCARE, 0x0f);
-       gfx_w(GFX_BITMASK, 0xff);
-
-       reg_r(ACT_ADDRESS_RESET);
-       attr_w(ACT_PALETTE0 , 0x00);
-       attr_w(ACT_PALETTE1 , 0x01);
-       attr_w(ACT_PALETTE2 , 0x02);
-       attr_w(ACT_PALETTE3 , 0x03);
-       attr_w(ACT_PALETTE4 , 0x04);
-       attr_w(ACT_PALETTE5 , 0x05);
-       attr_w(ACT_PALETTE6 , 0x06);
-       attr_w(ACT_PALETTE7 , 0x07);
-       attr_w(ACT_PALETTE8 , 0x08);
-       attr_w(ACT_PALETTE9 , 0x09);
-       attr_w(ACT_PALETTE10, 0x0a);
-       attr_w(ACT_PALETTE11, 0x0b);
-       attr_w(ACT_PALETTE12, 0x0c);
-       attr_w(ACT_PALETTE13, 0x0d);
-       attr_w(ACT_PALETTE14, 0x0e);
-       attr_w(ACT_PALETTE15, 0x0f);
-       reg_r(ACT_ADDRESS_RESET);
-
-       attr_w(ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
-
-       attr_w(ACT_OVERSCAN_COLOR, 0x00);
-       attr_w(ACT_COLOR_PLANE_ENA, 0x0f);
-       attr_w(ACT_HOR_PEL_PANNING, 0x00);
-       attr_w(ACT_COLOR_SELECT, 0x00);
-
-       reg_r(ACT_ADDRESS_RESET);
-       reg_w(ACT_DATA, 0x20);
-
-       reg_w(VDAC_MASK, 0xff);
+       pll_w(regs, 0x0a, best_freq);
+       pll_w(regs, 0x0e, 0x22);
+
+       gfx_w(regs, GFX_SET_RESET, 0x00);
+       gfx_w(regs, GFX_ENABLE_SET_RESET, 0x00);
+       gfx_w(regs, GFX_COLOR_COMPARE, 0x00);
+       gfx_w(regs, GFX_DATA_ROTATE, 0x00);
+       gfx_w(regs, GFX_READ_MAP_SELECT, 0x00);
+       gfx_w(regs, GFX_GRAPHICS_MODE, 0x00);
+       gfx_w(regs, GFX_MISC, 0x05);
+       gfx_w(regs, GFX_COLOR_XCARE, 0x0f);
+       gfx_w(regs, GFX_BITMASK, 0xff);
+
+       reg_r(regs, ACT_ADDRESS_RESET);
+       attr_w(regs, ACT_PALETTE0 , 0x00);
+       attr_w(regs, ACT_PALETTE1 , 0x01);
+       attr_w(regs, ACT_PALETTE2 , 0x02);
+       attr_w(regs, ACT_PALETTE3 , 0x03);
+       attr_w(regs, ACT_PALETTE4 , 0x04);
+       attr_w(regs, ACT_PALETTE5 , 0x05);
+       attr_w(regs, ACT_PALETTE6 , 0x06);
+       attr_w(regs, ACT_PALETTE7 , 0x07);
+       attr_w(regs, ACT_PALETTE8 , 0x08);
+       attr_w(regs, ACT_PALETTE9 , 0x09);
+       attr_w(regs, ACT_PALETTE10, 0x0a);
+       attr_w(regs, ACT_PALETTE11, 0x0b);
+       attr_w(regs, ACT_PALETTE12, 0x0c);
+       attr_w(regs, ACT_PALETTE13, 0x0d);
+       attr_w(regs, ACT_PALETTE14, 0x0e);
+       attr_w(regs, ACT_PALETTE15, 0x0f);
+       reg_r(regs, ACT_ADDRESS_RESET);
+
+       attr_w(regs, ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
+
+       attr_w(regs, ACT_OVERSCAN_COLOR, 0x00);
+       attr_w(regs, ACT_COLOR_PLANE_ENA, 0x0f);
+       attr_w(regs, ACT_HOR_PEL_PANNING, 0x00);
+       attr_w(regs, ACT_COLOR_SELECT, 0x00);
+
+       reg_r(regs, ACT_ADDRESS_RESET);
+       reg_w(regs, ACT_DATA, 0x20);
+
+       reg_w(regs, VDAC_MASK, 0xff);
 
        /*
         * Extended palette adressing ???
         */
        switch (bpp){
        case 8:
-               reg_w(0x83c6, 0x00);
+               reg_w(regs, 0x83c6, 0x00);
                break;
        case 16:
-               reg_w(0x83c6, 0x60);
+               reg_w(regs, 0x83c6, 0x60);
                break;
        case 24:
-               reg_w(0x83c6, 0xe0);
+               reg_w(regs, 0x83c6, 0xe0);
                break;
        default:
                printk("Illegal color-depth: %i\n", bpp);
        }
 
-       reg_w(VDAC_ADDRESS, 0x00);
-
-       seq_w(SEQ_MAP_MASK, 0x0f );
-
-       return 0;
-}
-
-/*
- *    Initialization
- *
- *    Set the default video mode for this chipset. If a video mode was
- *    specified on the command line, it will override the default mode.
- */
-
-static int retz3_init(void)
-{
-       short i;
-#if 0
-       volatile unsigned long *CursorBase;
-#endif
-
-       for (i = 0; i < 256; i++){
-               for (i = 0; i < 256; i++){
-                       retz3_color_table [i][0] = i;
-                       retz3_color_table [i][1] = i;
-                       retz3_color_table [i][2] = i;
-               }
-       }
-
-       /* Disable hardware cursor */
+       reg_w(regs, VDAC_ADDRESS, 0x00);
 
-       seq_w(SEQ_CURSOR_Y_INDEX, 0x00);
-
-#if 0
-       /* Initialize hardware cursor */
-       CursorBase = (unsigned long *)((char *)(z3_mem) + z3_size - 0x400);
-       for (i=0; i < 8; i++){
-               *(CursorBase  +(i*4)) = 0xffffff00;
-               *(CursorBase+1+(i*4)) = 0xffff0000;
-               *(CursorBase+2+(i*4)) = 0xffff0000;
-               *(CursorBase+3+(i*4)) = 0xffff0000;
-       }
-       for (i=8; i < 64; i++){
-               *(CursorBase  +(i*4)) = 0xffff0000;
-               *(CursorBase+1+(i*4)) = 0xffff0000;
-               *(CursorBase+2+(i*4)) = 0xffff0000;
-               *(CursorBase+3+(i*4)) = 0xffff0000;
-       }
-#endif
-
-       retz3_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, NULL /* unused */);
-       retz3_setcolreg (254, 0, 0, 0, 0, NULL /* unused */);
+       seq_w(regs, SEQ_MAP_MASK, 0x0f );
 
        return 0;
 }
@@ -830,14 +756,17 @@ static int retz3_init(void)
  *    values in the `par' structure.
  */
 
-static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
+static int retz3_encode_fix(struct fb_info *info,
+                           struct fb_fix_screeninfo *fix,
                            struct retz3fb_par *par)
 {
+       struct retz3_fb_info *zinfo = retz3info(info);
+
        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
        strcpy(fix->id, retz3fb_name);
-       fix->smem_start = (char *)z3_fbmem;
-       fix->smem_len = z3_size;
-       fix->mmio_start = (char *)z3_regs;
+       fix->smem_start = (char *)(zinfo->physfbmem);
+       fix->smem_len = zinfo->fbsize;
+       fix->mmio_start = (char *)(zinfo->physregs);
        fix->mmio_len = 0x00c00000;
 
        fix->type = FB_TYPE_PACKED_PIXELS;
@@ -950,6 +879,9 @@ static int retz3_setcolreg(unsigned int regno, unsigned int red,
                           unsigned int green, unsigned int blue,
                           unsigned int transp, struct fb_info *info)
 {
+       struct retz3_fb_info *zinfo = retz3info(info);
+       volatile unsigned char *regs = zinfo->regs;
+
        /* We'll get to this */
 
        if (regno > 255)
@@ -959,14 +891,14 @@ static int retz3_setcolreg(unsigned int regno, unsigned int red,
        green >>= 10;
        blue >>= 10;
 
-       retz3_color_table [regno][0] = red;
-       retz3_color_table [regno][1] = green;
-       retz3_color_table [regno][2] = blue;
+       zinfo->color_table[regno][0] = red;
+       zinfo->color_table[regno][1] = green;
+       zinfo->color_table[regno][2] = blue;
 
-       reg_w(VDAC_ADDRESS_W, regno);
-       reg_w(VDAC_DATA, red);
-       reg_w(VDAC_DATA, green);
-       reg_w(VDAC_DATA, blue);
+       reg_w(regs, VDAC_ADDRESS_W, regno);
+       reg_w(regs, VDAC_DATA, red);
+       reg_w(regs, VDAC_DATA, green);
+       reg_w(regs, VDAC_DATA, blue);
 
        return 0;
 }
@@ -981,55 +913,32 @@ static int retz3_getcolreg(unsigned int regno, unsigned int *red,
                           unsigned int *green, unsigned int *blue,
                           unsigned int *transp, struct fb_info *info)
 {
+       struct retz3_fb_info *zinfo = retz3info(info);
        int t;
 
        if (regno > 255)
                return 1;
-       t       = retz3_color_table [regno][0];
+       t       = zinfo->color_table[regno][0];
        *red    = (t<<10) | (t<<4) | (t>>2);
-       t       = retz3_color_table [regno][1];
+       t       = zinfo->color_table[regno][1];
        *green  = (t<<10) | (t<<4) | (t>>2);
-       t       = retz3_color_table [regno][2];
+       t       = zinfo->color_table[regno][2];
        *blue   = (t<<10) | (t<<4) | (t>>2);
        *transp = 0;
        return 0;
 }
 
 
-/*
- *    (Un)Blank the screen
- */
-
-void retz3_blank(int blank)
-{
-       short i;
-
-       if (blank)
-               for (i = 0; i < 256; i++){
-                       reg_w(VDAC_ADDRESS_W, i);
-                       reg_w(VDAC_DATA, 0);
-                       reg_w(VDAC_DATA, 0);
-                       reg_w(VDAC_DATA, 0);
-               }
-       else
-               for (i = 0; i < 256; i++){
-                       reg_w(VDAC_ADDRESS_W, i);
-                       reg_w(VDAC_DATA, retz3_color_table [i][0]);
-                       reg_w(VDAC_DATA, retz3_color_table [i][1]);
-                       reg_w(VDAC_DATA, retz3_color_table [i][2]);
-               }
-}
-
-
-static void retz3_bitblt (struct fb_var_screeninfo *var,
+static void retz3_bitblt (struct display *p,
                          unsigned short srcx, unsigned short srcy,
                          unsigned short destx, unsigned short desty,
                          unsigned short width, unsigned short height,
                          unsigned short cmd, unsigned short mask)
 {
-
-       volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET);
-       unsigned long *pattern = (unsigned long *)(z3_fbmem + PAT_MEM_OFF);
+       struct fb_var_screeninfo *var = &p->var;
+       struct retz3_fb_info *zinfo = retz3info(p->fb_info);
+       volatile unsigned long *acm = (unsigned long *)(zinfo->base + ACM_OFFSET);
+       unsigned long *pattern = (unsigned long *)(zinfo->fbmem + PAT_MEM_OFF);
 
        unsigned short mod;
        unsigned long tmp;
@@ -1132,55 +1041,50 @@ static void retz3_MoveCursor (unsigned short x, unsigned short y)
 }
 #endif
 
-/* -------------------- Interfaces to hardware functions -------------------- */
-
-
-static struct fb_hwswitch retz3_switch = {
-       retz3_init, retz3_encode_fix, retz3_decode_var, retz3_encode_var,
-       retz3_getcolreg, retz3_setcolreg, retz3_blank
-};
-
-
-/* -------------------- Generic routines ------------------------------------ */
-
 
 /*
  *    Fill the hardware's `par' structure.
  */
 
-static void retz3fb_get_par(struct retz3fb_par *par)
+static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par)
 {
-       if (current_par_valid)
-               *par = current_par;
+       struct retz3_fb_info *zinfo = retz3info(info);
+
+       if (zinfo->current_par_valid)
+               *par = zinfo->current_par;
        else
-               fbhw->decode_var(&retz3fb_default, par);
+               retz3_decode_var(&retz3fb_default, par);
 }
 
 
-static void retz3fb_set_par(struct retz3fb_par *par)
+static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par)
 {
-       current_par = *par;
-       current_par_valid = 1;
+       struct retz3_fb_info *zinfo = retz3info(info);
+
+       zinfo->current_par = *par;
+       zinfo->current_par_valid = 1;
 }
 
 
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
+static int do_fb_set_var(struct fb_info *info,
+                        struct fb_var_screeninfo *var, int isactive)
 {
        int err, activate;
        struct retz3fb_par par;
+       struct retz3_fb_info *zinfo = retz3info(info);
 
-       if ((err = fbhw->decode_var(var, &par)))
+       if ((err = retz3_decode_var(var, &par)))
                return err;
        activate = var->activate;
 
        /* XXX ... what to do about isactive ? */
 
        if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
-               retz3fb_set_par(&par);
-       fbhw->encode_var(var, &par);
+               retz3fb_set_par(info, &par);
+       retz3_encode_var(var, &par);
        var->activate = activate;
 
-       retz3_set_video(var, &current_par);
+       retz3_set_video(info, var, &zinfo->current_par);
 
        return 0;
 }
@@ -1188,13 +1092,15 @@ static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
 
 static void do_install_cmap(int con, struct fb_info *info)
 {
-       if (con != currcon)
+       struct retz3_fb_info *zinfo = retz3info(info);
+
+       if (con != zinfo->currcon)
                return;
        if (fb_display[con].cmap.len)
-               fb_set_cmap(&fb_display[con].cmap, 1, fbhw->setcolreg, info);
+               fb_set_cmap(&fb_display[con].cmap, 1, retz3_setcolreg, info);
        else
                fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
-                                           1, fbhw->setcolreg, info);
+                                           1, retz3_setcolreg, info);
 }
 
 
@@ -1230,10 +1136,10 @@ static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
        int error = 0;
 
        if (con == -1)
-               retz3fb_get_par(&par);
+               retz3fb_get_par(info, &par);
        else
-               error = fbhw->decode_var(&fb_display[con].var, &par);
-       return(error ? error : fbhw->encode_fix(fix, &par));
+               error = retz3_decode_var(&fb_display[con].var, &par);
+       return(error ? error : retz3_encode_fix(info, fix, &par));
 }
 
 
@@ -1248,8 +1154,8 @@ static int retz3fb_get_var(struct fb_var_screeninfo *var, int con,
        int error = 0;
 
        if (con == -1) {
-               retz3fb_get_par(&par);
-               error = fbhw->encode_var(var, &par);
+               retz3fb_get_par(info, &par);
+               error = retz3_encode_var(var, &par);
        } else
                *var = fb_display[con].var;
        return error;
@@ -1261,18 +1167,19 @@ static void retz3fb_set_disp(int con, struct fb_info *info)
 {
        struct fb_fix_screeninfo fix;
        struct display *display;
+       struct retz3_fb_info *zinfo = retz3info(info);
 
        if (con >= 0)
                display = &fb_display[con];
        else
-               display = &disp;        /* used during initialization */
+               display = &zinfo->disp; /* used during initialization */
 
        retz3fb_get_fix(&fix, con, info);
 
        if (con == -1)
                con = 0;
 
-       display->screen_base = fix.smem_start;
+       display->screen_base = (char *)zinfo->fbmem;
        display->visual = fix.visual;
        display->type = fix.type;
        display->type_aux = fix.type_aux;
@@ -1308,6 +1215,7 @@ static void retz3fb_set_disp(int con, struct fb_info *info)
 }
 #endif
 
+
 /*
  *    Set the User Defined Part of the Display
  */
@@ -1317,18 +1225,14 @@ static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
 {
        int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
        struct display *display;
+       struct retz3_fb_info *zinfo = retz3info(info);
 
        if (con >= 0)
                display = &fb_display[con];
        else
-               display = &disp;        /* used during initialization */
-
-#if 0
-       if (con == -1)
-               con = 0;
-#endif
+               display = &zinfo->disp; /* used during initialization */
 
-       if ((err = do_fb_set_var(var, con == currcon)))
+       if ((err = do_fb_set_var(info, var, con == zinfo->currcon)))
                return err;
        if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
                oldxres = display->var.xres;
@@ -1348,7 +1252,7 @@ static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
                        struct fb_fix_screeninfo fix;
                        retz3fb_get_fix(&fix, con, info);
 
-                       display->screen_base = fix.smem_start;
+                       display->screen_base = (char *)zinfo->fbmem;
                        display->visual = fix.visual;
                        display->type = fix.type;
                        display->type_aux = fix.type_aux;
@@ -1379,8 +1283,8 @@ static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
 /*
        retz3fb_set_disp(con, info);
 */
-                       if (fb_info.changevar)
-                               (*fb_info.changevar)(con);
+                       if (info->changevar)
+                               (*info->changevar)(con);
                }
 
                if (oldbpp != var->bits_per_pixel) {
@@ -1400,8 +1304,10 @@ static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
 static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                            struct fb_info *info)
 {
-       if (con == currcon) /* current console? */
-               return(fb_get_cmap(cmap, kspc, fbhw->getcolreg, info));
+       struct retz3_fb_info *zinfo = retz3info(info);
+
+       if (con == zinfo->currcon) /* current console? */
+               return(fb_get_cmap(cmap, kspc, retz3_getcolreg, info));
        else if (fb_display[con].cmap.len) /* non default colormap? */
                fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
        else
@@ -1419,6 +1325,7 @@ static int retz3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                            struct fb_info *info)
 {
        int err;
+       struct retz3_fb_info *zinfo = retz3info(info);
 
        if (!fb_display[con].cmap.len) {       /* no colormap allocated? */
                if ((err = fb_alloc_cmap(&fb_display[con].cmap,
@@ -1426,8 +1333,8 @@ static int retz3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                                         0)))
                        return err;
        }
-       if (con == currcon)              /* current console? */
-               return(fb_set_cmap(cmap, kspc, fbhw->setcolreg, info));
+       if (con == zinfo->currcon)              /* current console? */
+               return(fb_set_cmap(cmap, kspc, retz3_setcolreg, info));
        else
                fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
        return 0;
@@ -1470,8 +1377,6 @@ __initfunc(void retz3fb_setup(char *options, int *ints))
 {
        char *this_opt;
 
-       fb_info.fontname[0] = '\0';
-
        if (!options || !*options)
                return;
 
@@ -1480,9 +1385,10 @@ __initfunc(void retz3fb_setup(char *options, int *ints))
                if (!strcmp(this_opt, "inverse")) {
                        z3fb_inverse = 1;
                        fb_invert_cmaps();
-               } else if (!strncmp(this_opt, "font:", 5))
-                       strcpy(fb_info.fontname, this_opt+5);
-               else
+               } else if (!strncmp(this_opt, "font:", 5)) {
+                       strncpy(fontname, this_opt+5, 39);
+                       fontname[39] = '\0';
+               }else
                        z3fb_mode = get_video_mode(this_opt);
        }
 }
@@ -1497,59 +1403,79 @@ __initfunc(void retz3fb_init(void))
        unsigned long board_addr, board_size;
        unsigned int key;
        const struct ConfigDev *cd;
-
+       volatile unsigned char *regs;
        struct retz3fb_par par;
+       struct retz3_fb_info *zinfo;
+       struct fb_info *fb_info;
+       short i;
 
        if (!(key = zorro_find(ZORRO_PROD_MACROSYSTEMS_RETINA_Z3, 0, 0)))
                return;
 
+       if (!(zinfo = kmalloc(sizeof(struct retz3_fb_info), GFP_KERNEL)))
+               return;
+       memset(zinfo, 0, sizeof(struct retz3_fb_info));
+
        cd = zorro_get_board (key);
        zorro_config_board (key, 0);
        board_addr = (unsigned long)cd->cd_BoardAddr;
        board_size = (unsigned long)cd->cd_BoardSize;
 
-       z3_mem = kernel_map (board_addr, board_size,
-                            KERNELMAP_NOCACHE_SER, NULL);
-
-       z3_regs = (char*) z3_mem;
-       z3_fbmem = z3_mem + VIDEO_MEM_OFFSET;
-
+       zinfo->base = kernel_map (board_addr, board_size,
+                                  KERNELMAP_NOCACHE_SER, NULL);
+       zinfo->regs = (unsigned char *)(zinfo->base);
+       zinfo->fbmem = zinfo->base + VIDEO_MEM_OFFSET;
        /* Get memory size - for now we asume its a 4MB board */
+       zinfo->fbsize = 0x00400000; /* 4 MB */
+       zinfo->physregs = board_addr;
+       zinfo->physfbmem = board_addr + VIDEO_MEM_OFFSET;
 
-       z3_size = 0x00400000; /* 4 MB */
+       fb_info = fbinfo(zinfo);
 
-       fbhw = &retz3_switch;
-
-       fbhw->init();
+       for (i = 0; i < 256; i++){
+               for (i = 0; i < 256; i++){
+                       zinfo->color_table[i][0] = i;
+                       zinfo->color_table[i][1] = i;
+                       zinfo->color_table[i][2] = i;
+               }
+       }
 
-       strcpy(fb_info.modename, retz3fb_name);
-       fb_info.changevar = NULL;
-       fb_info.node = -1;
-       fb_info.fbops = &retz3fb_ops;
-       fb_info.disp = &disp;
-       fb_info.switch_con = &z3fb_switch;
-       fb_info.updatevar = &z3fb_updatevar;
-       fb_info.blank = &z3fb_blank;
-       fb_info.flags = FBINFO_FLAG_DEFAULT;
+       regs = zinfo->regs;
+       /* Disable hardware cursor */
+       seq_w(regs, SEQ_CURSOR_Y_INDEX, 0x00);
+
+       retz3_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, fb_info);
+       retz3_setcolreg (254, 0, 0, 0, 0, fb_info);
+
+       strcpy(fb_info->modename, retz3fb_name);
+       fb_info->changevar = NULL;
+       fb_info->node = -1;
+       fb_info->fbops = &retz3fb_ops;
+       fb_info->disp = &zinfo->disp;
+       fb_info->switch_con = &z3fb_switch;
+       fb_info->updatevar = &z3fb_updatevar;
+       fb_info->blank = &z3fb_blank;
+       fb_info->flags = FBINFO_FLAG_DEFAULT;
+       strncpy(fb_info->fontname, fontname, 40);
 
        if (z3fb_mode == -1)
                retz3fb_default = retz3fb_predefined[0].var;
 
-       fbhw->decode_var(&retz3fb_default, &par);
-       fbhw->encode_var(&retz3fb_default, &par);
+       retz3_decode_var(&retz3fb_default, &par);
+       retz3_encode_var(&retz3fb_default, &par);
 
-       do_fb_set_var(&retz3fb_default, 0);
-       retz3fb_get_var(&disp.var, -1, &fb_info);
+       do_fb_set_var(fb_info, &retz3fb_default, 0);
+       retz3fb_get_var(&zinfo->disp.var, -1, fb_info);
 
-       retz3fb_set_disp(-1, &fb_info);
+       retz3fb_set_disp(-1, fb_info);
 
-       do_install_cmap(0, &fb_info);
+       do_install_cmap(0, fb_info);
 
-       if (register_framebuffer(&fb_info) < 0)
+       if (register_framebuffer(fb_info) < 0)
                return;
 
        printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
-              GET_FB_IDX(fb_info.node), fb_info.modename, z3_size>>10);
+              GET_FB_IDX(fb_info->node), fb_info->modename,zinfo->fbsize>>10);
 
        /* TODO: This driver cannot be unloaded yet */
        MOD_INC_USE_COUNT;
@@ -1558,13 +1484,15 @@ __initfunc(void retz3fb_init(void))
 
 static int z3fb_switch(int con, struct fb_info *info)
 {
+       struct retz3_fb_info *zinfo = retz3info(info);
+
        /* Do we have to save the colormap? */
-       if (fb_display[currcon].cmap.len)
-               fb_get_cmap(&fb_display[currcon].cmap, 1, fbhw->getcolreg,
-                           info);
+       if (fb_display[zinfo->currcon].cmap.len)
+               fb_get_cmap(&fb_display[zinfo->currcon].cmap, 1,
+                           retz3_getcolreg, info);
 
-       do_fb_set_var(&fb_display[con].var, 1);
-       currcon = con;
+       do_fb_set_var(info, &fb_display[con].var, 1);
+       zinfo->currcon = con;
        /* Install new colormap */
        do_install_cmap(con, info);
        return 0;
@@ -1590,7 +1518,24 @@ static int z3fb_updatevar(int con, struct fb_info *info)
 
 static void z3fb_blank(int blank, struct fb_info *info)
 {
-       fbhw->blank(blank);
+       struct retz3_fb_info *zinfo = retz3info(info);
+       volatile unsigned char *regs = retz3info(info)->regs;
+       short i;
+
+       if (blank)
+               for (i = 0; i < 256; i++){
+                       reg_w(regs, VDAC_ADDRESS_W, i);
+                       reg_w(regs, VDAC_DATA, 0);
+                       reg_w(regs, VDAC_DATA, 0);
+                       reg_w(regs, VDAC_DATA, 0);
+               }
+       else
+               for (i = 0; i < 256; i++){
+                       reg_w(regs, VDAC_ADDRESS_W, i);
+                       reg_w(regs, VDAC_DATA, zinfo->color_table[i][0]);
+                       reg_w(regs, VDAC_DATA, zinfo->color_table[i][1]);
+                       reg_w(regs, VDAC_DATA, zinfo->color_table[i][2]);
+               }
 }
 
 
@@ -1635,8 +1580,8 @@ void cleanup_module(void)
  */
 
 #ifdef FBCON_HAS_CFB8
-static void fbcon_retz3_8_bmove(struct display *p, int sy, int sx, int dy, int dx,
-                       int height, int width)
+static void fbcon_retz3_8_bmove(struct display *p, int sy, int sx,
+                               int dy, int dx, int height, int width)
 {
        int fontwidth = fontwidth(p);
 
@@ -1644,7 +1589,7 @@ static void fbcon_retz3_8_bmove(struct display *p, int sy, int sx, int dy, int d
        dx *= fontwidth;
        width *= fontwidth;
 
-       retz3_bitblt(&p->var,
+       retz3_bitblt(p,
                     (unsigned short)sx,
                     (unsigned short)(sy*fontheight(p)),
                     (unsigned short)dx,
@@ -1655,8 +1600,8 @@ static void fbcon_retz3_8_bmove(struct display *p, int sy, int sx, int dy, int d
                     0xffff);
 }
 
-static void fbcon_retz3_8_clear(struct vc_data *conp, struct display *p, int
-                       sy, int sx, int height, int width)
+static void fbcon_retz3_8_clear(struct vc_data *conp, struct display *p,
+                               int sy, int sx, int height, int width)
 {
        unsigned short col;
        int fontwidth = fontwidth(p);
@@ -1668,7 +1613,7 @@ static void fbcon_retz3_8_clear(struct vc_data *conp, struct display *p, int
        col &= 0xff;
        col |= (col << 8);
 
-       retz3_bitblt(&p->var,
+       retz3_bitblt(p,
                     (unsigned short)sx,
                     (unsigned short)(sy*fontheight(p)),
                     (unsigned short)sx,
index 1498428602f474837f6e5fe0269c73ab7731b54a..5cc75106772047248ae883e7bd74d44ed99cafb8 100644 (file)
 /*
  * Macros to read and write to registers.
  */
-#define reg_w(reg,dat) (*(z3_regs + reg) = dat)
-#define reg_r(reg) (*(z3_regs + reg))
+#define reg_w(regs, reg,dat) (*(regs + reg) = dat)
+#define reg_r(regs, reg) (*(regs + reg))
 
 /*
  * Macro to access the sequencer.
  */
-#define seq_w(sreg,sdat) \
-       do{ reg_w(SEQ_IDX, sreg); reg_w(SEQ_DATA, sdat); } while(0)
+#define seq_w(regs, sreg, sdat) \
+       do{ reg_w(regs, SEQ_IDX, sreg); reg_w(regs, SEQ_DATA, sdat); } while(0)
 
 /*
  * Macro to access the CRT controller.
  */
-#define crt_w(creg,cdat) \
-       do{ reg_w(CRT_IDX, creg); reg_w(CRT_DATA, cdat); } while(0)
+#define crt_w(regs, creg, cdat) \
+       do{ reg_w(regs, CRT_IDX, creg); reg_w(regs, CRT_DATA, cdat); } while(0)
 
 /*
  * Macro to access the graphics controller.
  */
-#define gfx_w(greg,gdat) \
-       do{ reg_w(GFX_IDX, greg); reg_w(GFX_DATA, gdat); } while(0)
+#define gfx_w(regs, greg, gdat) \
+       do{ reg_w(regs, GFX_IDX, greg); reg_w(regs, GFX_DATA, gdat); } while(0)
 
 /*
  * Macro to access the attribute controller.
  */
-#define attr_w(areg,adat) \
-       do{ reg_w(ACT_IDX, areg); reg_w(ACT_DATA, adat); } while(0)
+#define attr_w(regs, areg, adat) \
+       do{ reg_w(regs, ACT_IDX, areg); reg_w(regs, ACT_DATA, adat); } while(0)
 
 /*
  * Macro to access the pll.
  */
-#define pll_w(preg,pdat) \
-       do{ reg_w(PLL_IDX, preg); \
-           reg_w(PLL_DATA, (pdat & 0xff)); \
-           reg_w(PLL_DATA, (pdat >> 8));\
+#define pll_w(regs, preg, pdat) \
+       do{ reg_w(regs, PLL_IDX, preg); \
+           reg_w(regs, PLL_DATA, (pdat & 0xff)); \
+           reg_w(regs, PLL_DATA, (pdat >> 8));\
        } while(0)
 
 /*
index bbe37b27396f5f0032a8153329a0688ead1197c9..f4fbe2ec5e447ad0e6fe7dd4e6f3a3846723e593 100644 (file)
@@ -184,7 +184,8 @@ static int sbusfb_mmap(struct fb_info *info, struct file *file,
 #ifdef __sparc_v9__
        /* Align it as much as desirable */
        {
-               int j, max = -1, alignment, s = 0;
+               unsigned long j, alignment, s = 0;
+               int max = -1;
                
                map_offset = vma->vm_offset+size;
                for (i = 0; fb->mmap_map[i].size; i++) {
index c7533d2cc2bda37b40141f3dbfb74dd1eeca2c26..59d16e90bfe3d9598f607a27806d3f01f508f2fc 100644 (file)
@@ -152,6 +152,8 @@ static unsigned long CyberMem;
 static unsigned long CyberSize;
 static volatile char *CyberRegs;
 static volatile unsigned long CyberVGARegs; /* ++Andre: for CV64/3D, see macros at the beginning */
+static unsigned long CyberMem_phys;
+static unsigned long CyberRegs_phys;
  
 
 /*
@@ -208,6 +210,13 @@ static struct fb_videomode virgefb_predefined[] __initdata = {
            0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
            FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
        }
+    }, {
+       "1024x768-16", {         /* Cybervision 16 bpp */
+           1024, 768, 1024, 768, 0, 0, 16, 0,
+           {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+           0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+           FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+       }
     }
 };
 
@@ -371,9 +380,9 @@ static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
 {
        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
        strcpy(fix->id, virgefb_name);
-       fix->smem_start = (char *)CyberMem;
+       fix->smem_start = (char*) CyberMem_phys;
        fix->smem_len = CyberSize;
-       fix->mmio_start = (char *)CyberRegs;
+       fix->mmio_start = (char*) CyberRegs_phys;
        fix->mmio_len = 0x10000; /* TODO: verify this for the CV64/3D */
 
        fix->type = FB_TYPE_PACKED_PIXELS;
@@ -843,7 +852,7 @@ static void virgefb_set_disp(int con, struct fb_info *info)
        virgefb_get_fix(&fix, con, info);
        if (con == -1)
                con = 0;
-       display->screen_base = fix.smem_start;
+       display->screen_base = (char*) CyberMem;
        display->visual = fix.visual;
        display->type = fix.type;
        display->type_aux = fix.type_aux;
@@ -1033,7 +1042,8 @@ __initfunc(void virgefb_init(void))
                 * Ok we got the board running in Z2 space.
                 */
 
-               CyberMem = ZTWO_VADDR(board_addr);
+               CyberMem_phys = board_addr;
+               CyberMem = ZTWO_VADDR(CyberMem_phys);
                printk("CV3D detected running in Z2 mode ... not yet supported!\n");
                return;
        }
@@ -1041,10 +1051,13 @@ __initfunc(void virgefb_init(void))
        {
                CyberVGARegs = kernel_map(board_addr +0x0c000000, 0x00010000,
                                               KERNELMAP_NOCACHE_SER, NULL);
-               CyberRegs = (char *)kernel_map(board_addr +0x05000000,
+
+               CyberRegs_phys = board_addr + 0x05000000;
+               CyberMem_phys  = board_addr + 0x04800000;
+               CyberRegs = (char *)kernel_map(CyberRegs_phys,
                                               0x00010000,
                                               KERNELMAP_NOCACHE_SER, NULL);
-               CyberMem = kernel_map(board_addr + 0x04800000, 0x00400000,
+               CyberMem = kernel_map(CyberMem_phys, 0x00400000,
                                      KERNELMAP_NOCACHE_SER, NULL);
                printk("CV3D detected running in Z3 mode\n");
        }
index 789713164274ca82463bd8de163fe0a1239774ba..21adfd00ebbb38beadb40135506c348f75f82bb2 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -5,12 +5,9 @@
  *  changes by Thomas Schoebel-Theuer
  */
 
-#include <linux/stat.h>
 #include <linux/sched.h>
-#include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/string.h>
-#include <asm/system.h>
 
 /* Taken over from the old code... */
 
index 89acd374f816360cbb014cc5279062fe1cca0f44..acf05f536431ba907a8079c31a17768be631515b 100644 (file)
@@ -112,7 +112,8 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
        if ( !(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) ) {
                do {
                        if ( status && dentry->d_inode ) {
-                               printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name);
+                               if ( status != -ENOENT )
+                                       printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name);
                                return 0; /* Try to get the kernel to invalidate this dentry */
                        }
 
index 7591037d070390646ae14298f286233ba2686b16..11b5d02d2c84312c3951efa7ac0d39de514f09b2 100644 (file)
@@ -4,15 +4,11 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
+#include <linux/mm.h>
 #include <linux/locks.h>
 #include <linux/fcntl.h>
-#include <linux/mm.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 extern int *blk_size[];
 extern int *blksize_size[];
index 3810ab115414f9fc0798f8fa8fdc8647b47fd987..3ca874e37b1757bd1396ccea0355dfad47dee535 100644 (file)
  * - RMK
  */
 
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/string.h>
+#include <linux/malloc.h>
 #include <linux/locks.h>
 #include <linux/errno.h>
-#include <linux/malloc.h>
-#include <linux/slab.h>
-#include <linux/pagemap.h>
 #include <linux/swap.h>
 #include <linux/swapctl.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/vmalloc.h>
 #include <linux/blkdev.h>
@@ -44,7 +37,6 @@
 #include <linux/init.h>
 #include <linux/quotaops.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/bitops.h>
index 2a35ed7dad25514694aea375bf51ecf588c353ac..b18493bb656891ac0b2fdfadb6b36225990e3863 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
  * formats. 
  */
 
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/file.h>
 #include <linux/mman.h>
 #include <linux/a.out.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/string.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
-#include <linux/ptrace.h>
 #include <linux/user.h>
-#include <linux/binfmts.h>
-#include <linux/personality.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
 
-#include <linux/config.h>
-
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif
index 4d784e474f5a3162ce10476708a1bd21b8cd748c..036c9eb1fe968da2dd54d6cb400c699820ce3714 100644 (file)
@@ -4,18 +4,10 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
-#include <linux/file.h>
-#include <linux/string.h>
 #include <linux/mm.h>
-#include <linux/smp.h>
+#include <linux/file.h>
 #include <linux/smp_lock.h>
 
-#include <asm/bitops.h>
 #include <asm/uaccess.h>
 
 extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
index 7536995ac76f0a78aa768c803d3626d153625a42..dbcbcb754ee17cb4f320f98f339c5b7190dff5bf 100644 (file)
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -4,10 +4,6 @@
  *  written by Paul H. Hargrove
  */
 
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
 #include <linux/mm.h>
 
 static int fifo_open(struct inode * inode,struct file * filp)
index 6a4b1df4341314bfc403ae1bbf02072db04c4aba..200b6049bc303aba42da3cf0c0ec23f4e234f5d6 100644 (file)
@@ -5,13 +5,8 @@
  *  Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/string.h>
-#include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/file.h>
 #include <linux/init.h>
 
 /* SLAB cache for filp's. */
index 59429ba16b10f94daa94c2677cc15f37bd5e3c9b..9ac7c3bf2abbe37989097a4982d3db02d8b4a61e 100644 (file)
@@ -4,15 +4,8 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/termios.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
-#include <linux/fcntl.h> /* for f_flags values */
 #include <linux/file.h>
 
 #include <asm/uaccess.h>
index 9f79cc649243af42163dd01c429fbb6c35065d11..022206bbb1b085cd219968f4dfac984bbaae177f 100644 (file)
  */
 
 #include <linux/malloc.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
 #include <linux/file.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
index 0e03e79ee382c311bf82f7c583909e07e2d3bc49..25e2204b4a18d9a65d56c2e6b775fd3c403860c1 100644 (file)
@@ -5,17 +5,14 @@
  *  Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
  */
 
-#include <linux/config.h>
 
 #define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/sched.h>
 #include <linux/msdos_fs.h>
-#include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
-#include <linux/stat.h>
 
 #include <asm/uaccess.h>
 
index 974d92f17e7076941394c77d6752131193c4d087..642adacdaa75db24664c3093cf64853e2150a41e 100644 (file)
  * lookup logic.
  */
 
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/quotaops.h>
 
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 #include <asm/semaphore.h>
-#include <asm/spinlock.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 
index 35b380cd830282fd26dead1087747dd3f43cac6f..2a91c4f9d07e283cae1e57110ccf11eb1dba7cae 100644 (file)
@@ -488,13 +488,7 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
 printk("nfs_dentry_iput: pending writes for %s/%s, i_count=%d\n",
 dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_count);
 #endif
-               while (nfs_find_dentry_request(inode, dentry)) {
-#ifdef NFS_PARANOIA
-printk("nfs_dentry_iput: flushing %s/%s\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-#endif
-                       nfs_flush_dirty_pages(inode, 0, 0, 0);
-               }
+               nfs_wbinval(inode);
        }
        iput(inode);
 }
@@ -940,7 +934,7 @@ static int nfs_safe_remove(struct dentry *dentry)
        error = -EBUSY;
        if (inode) {
                if (NFS_WRITEBACK(inode)) {
-                       nfs_flush_dirty_pages(inode, 0, 0, 0);
+                       nfs_wbinval(inode);
                        if (NFS_WRITEBACK(inode)) {
 #ifdef NFS_PARANOIA
 printk("nfs_safe_remove: %s/%s writes pending, d_count=%d\n",
@@ -1204,7 +1198,7 @@ new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
 printk("nfs_rename: %s/%s has pending writes\n",
 old_dentry->d_parent->d_name.name, old_dentry->d_name.name);
 #endif
-                       nfs_flush_dirty_pages(old_inode, 0, 0, 0);
+                       nfs_wbinval(old_inode);
                        if (NFS_WRITEBACK(old_inode)) {
 #ifdef NFS_PARANOIA
 printk("nfs_rename: %s/%s has pending writes after flush\n",
index 5a815b0f83774e1aad07b5318af46f52ada88caa..8e13fe6575453740be92c9701f2a19a7f9558ef0 100644 (file)
@@ -95,7 +95,7 @@ nfs_file_close(struct inode *inode, struct file *file)
 
        dfprintk(VFS, "nfs: close(%x/%ld)\n", inode->i_dev, inode->i_ino);
 
-       status = nfs_flush_dirty_pages(inode, 0, 0, 0);
+       status = nfs_wbinval(inode);
        error = nfs_write_error(inode);
        if (!status)
                status = error;
@@ -162,7 +162,7 @@ nfs_fsync(struct file *file, struct dentry *dentry)
 
        dfprintk(VFS, "nfs: fsync(%x/%ld)\n", inode->i_dev, inode->i_ino);
 
-       status = nfs_flush_dirty_pages(inode, current->pid, 0, 0);
+       status = nfs_wbinval_pid(inode, current->pid);
        error = nfs_write_error(inode);
        if (!status)
                status = error;
@@ -246,7 +246,7 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
         * been killed by a signal, that is). */
        if (cmd == F_SETLK && fl->fl_type == F_UNLCK
            && !signal_pending(current)) {
-               status = nfs_flush_dirty_pages(inode, current->pid,
+               status = nfs_wb_area(inode, /* current->pid  ?*/
                        fl->fl_start, fl->fl_end == NLM_OFFSET_MAX? 0 :
                        fl->fl_end - fl->fl_start + 1);
                if (status < 0)
index e165958fb45bbc9a56a5cd308bb4192277019bbf..d11c20ab67e5cd7d0f8d6b0a63dc9630b3d0278b 100644 (file)
@@ -105,7 +105,7 @@ nfs_delete_inode(struct inode * inode)
 #ifdef NFS_DEBUG_VERBOSE
 printk("nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
 #endif
-               nfs_invalidate_pages(inode);
+               nfs_inval(inode);
                while (NFS_WRITEBACK(inode) != NULL &&
                       time_before(jiffies, timeout)) {
                        current->state = TASK_INTERRUPTIBLE;
@@ -827,7 +827,7 @@ printk("nfs_refresh_inode: invalidating %ld pages\n", inode->i_nrpages);
        if (!S_ISDIR(inode->i_mode)) {
                /* This sends off all dirty pages off to the server.
                 * Note that this function must not sleep. */
-               nfs_invalidate_pages(inode);
+               nfs_inval(inode);
                invalidate_inode_pages(inode);
        } else
                nfs_invalidate_dircache(inode);
index 58b8942327fb7891ed0dfa77f66bc52490864c90..26d0cb8244edcec3b228c7430f87ad137f3bc466 100644 (file)
@@ -235,9 +235,10 @@ nfs_readpage(struct file *file, struct page *page)
         * Try to flush any pending writes to the file..
         *
         * NOTE! Because we own the page lock, there cannot
-        * be any new pending writes generated at this point.
+        * be any new pending writes generated at this point
+        * for this page (other pages can be written to).
         */
-       error = nfs_flush_pages(inode, 0, 0, 0);
+       error = nfs_wb_page(inode, page);
        if (error)
                return error;
 
index d1ce5af5eadc562b53881d52d7e69163e8c6bab8..e5ec43f056126bd473d35c79460cec26aa898e82 100644 (file)
@@ -546,65 +546,101 @@ nfs_cancel_dirty(struct inode *inode, pid_t pid)
 }
 
 /*
- * Try to flush any dirty pages, returning a success marker..
- *
- * Unlike "nfs_flush_dirty_pages()" this does not invalidate
- * the writes if it is interrupted. The caller will instead
- * look at the error code and gracefully fail to do what it
- * wanted to do. 
+ * If we're waiting on somebody else's request
+ * we need to increment the counter during the
+ * wait so that the request doesn't disappear
+ * from under us during the wait..
  */
-int
-nfs_flush_pages(struct inode *inode, pid_t pid, off_t offset, off_t len)
+static int FASTCALL(wait_on_other_req(struct nfs_wreq *));
+static int wait_on_other_req(struct nfs_wreq *req)
 {
        int retval;
+       req->wb_count++;
+       retval = wait_on_write_request(req);
+       free_write_request(req);
+       return retval;
+}
 
-       do {
-               struct nfs_wreq *req = NFS_WRITEBACK(inode);
-               struct nfs_wreq *head = req;
+/*
+ * This writes back a set of requests according to the condition.
+ *
+ * If this ever gets much more convoluted, use a fn pointer for
+ * the condition..
+ */
+#define NFS_WB(inode, cond) { int retval = 0 ; \
+       do { \
+               struct nfs_wreq *req = NFS_WRITEBACK(inode); \
+               struct nfs_wreq *head = req; \
+               if (!req) break; \
+               for (;;) { \
+                       if (!(req->wb_flags & NFS_WRITE_COMPLETE)) \
+                               if (cond) break; \
+                       req = WB_NEXT(req); \
+                       if (req == head) goto out; \
+               } \
+               retval = wait_on_other_req(req); \
+       } while (!retval); \
+out:   return retval; \
+}
 
-               if (!req)
-                       return 0;
+int
+nfs_wb_all(struct inode *inode)
+{
+       NFS_WB(inode, 1);
+}
 
-               /*
-                * Iterate over all outstanding write requests,
-                * looking for any that are ours..
-                */
-               for (;;) {
-                       if (!(req->wb_flags & NFS_WRITE_COMPLETE)) {
-                               if (!pid || req->wb_pid == pid)
-                                       break;
-                       }
-                       req = WB_NEXT(req);
-                       if (req == head)
-                               return 0;
-               }
+/*
+ * Write back all requests on one page - we do this before reading it.
+ */
+int
+nfs_wb_page(struct inode *inode, struct page *page)
+{
+       NFS_WB(inode, req->wb_page == page);
+}
 
-               req->wb_count++;
-               retval = wait_on_write_request(req);
-               free_write_request(req);
-       } while (!retval);
-       return retval;
-}      
+/*
+ * Write back all pending writes for one user.. 
+ */
+int
+nfs_wb_pid(struct inode *inode, pid_t pid)
+{
+       NFS_WB(inode, req->wb_pid == pid);
+}
 
 /*
- * Flush out all dirty pages belonging to a certain user process and
- * maybe wait for the RPC calls to complete.
- *
- * Another purpose of this function is sync()ing a file range before a
- * write lock is released. This is what offset and length are for, even if
- * this isn't used by the nlm module yet.
+ * Write back everything in a specific area for locking purposes..
  */
 int
-nfs_flush_dirty_pages(struct inode *inode, pid_t pid, off_t offset, off_t len)
+nfs_wb_area(struct inode *inode, off_t offset, off_t len)
 {
-       int retval = nfs_flush_pages(inode, pid, offset, len);
+       NFS_WB(inode, 1);
+}
+
+/*
+ * Write back and invalidate. Sometimes we can't leave the stuff
+ * hanging if we can't write it out.
+ */
+int
+nfs_wbinval(struct inode *inode)
+{
+       int retval = nfs_wb_all(inode);
+
+       if (retval)
+               nfs_cancel_dirty(inode,0);
+       return retval;
+}
+
+int nfs_wbinval_pid(struct inode *inode, pid_t pid)
+{
+       int retval = nfs_wb_pid(inode, pid);
+       
        if (retval)
                nfs_cancel_dirty(inode,pid);
        return retval;
 }
 
 void
-nfs_invalidate_pages(struct inode *inode)
+nfs_inval(struct inode *inode)
 {
        nfs_cancel_dirty(inode,0);
 }
index 924a7c85230c811e4e583a5f5d687ddb04fa0120..6f110d12667f43b77982cbe793609c887e2d23c1 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -4,21 +4,11 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/vfs.h>
-#include <linux/types.h>
+#include <linux/mm.h>
 #include <linux/utime.h>
-#include <linux/errno.h>
 #include <linux/fcntl.h>
 #include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/tty.h>
-#include <linux/time.h>
-#include <linux/mm.h>
 #include <linux/file.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/quotaops.h>
 
index 7eb4591d597f0c289480fec389a9471eabb2a39e..999013ef83bdb790adbf1ac369fec4140f9f76f7 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -4,12 +4,6 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/termios.h>
 #include <linux/mm.h>
 #include <linux/file.h>
 #include <linux/poll.h>
index e36a2d1e1add742d726554eb12bf4698142c3839..00fa17ed6514ded60c1391291e0e3d5c45185fdf 100644 (file)
@@ -4,19 +4,12 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/types.h>
-#include <linux/errno.h>
+#include <linux/malloc.h> 
 #include <linux/stat.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/fcntl.h>
 #include <linux/file.h>
-#include <linux/mm.h>
 #include <linux/uio.h>
-#include <linux/malloc.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
-#include <linux/limits.h>
 
 #include <asm/uaccess.h>
 
index fc1011aba55a3874d8644955f8c3fa4951080fac..486c315d45ab48d5d94a7c549558d61a57fcae0d 100644 (file)
  *     parameter to reflect time remaining.
  */
 
-#include <linux/types.h>
-#include <linux/time.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/personality.h>
-#include <linux/mm.h>
 #include <linux/malloc.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/poll.h>
 #include <linux/file.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #define ROUND_UP(x,y) (((x)+(y)-1)/(y))
 #define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
index b552aa68c2b725c218f5a7889816fe7d4b382992..0246a44a137a8f24816aa215b675ae04ec84ca5e 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -4,15 +4,9 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/fs.h>
 #include <linux/file.h>
-#include <linux/kernel.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
index 4ea1e6efbacd6e42fb74cb408e53cc84703b1a44..be5294f2f166273b68dd54e581199a50936135c5 100644 (file)
  *  Added change_root: Werner Almesberger & Hans Lermen, Feb '96
  */
 
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mount.h>
 #include <linux/malloc.h>
-#include <linux/major.h>
-#include <linux/stat.h>
-#include <linux/errno.h>
-#include <linux/string.h>
 #include <linux/locks.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/fd.h>
 #include <linux/init.h>
 #include <linux/quotaops.h>
 #include <linux/acct.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/bitops.h>
 
 #include <linux/nfs_fs.h>
 #include <linux/nfs_fs_sb.h>
index d35ab607fc95826450aa28acd819ffadf52caa6e..cb5618a56661f2ae86a632268e9c25c681573d84 100644 (file)
 #define FB_ACCEL_SUN_CGSIX     12      /* Sun cg6                      */
 #define FB_ACCEL_SUN_LEO       13      /* Sun leo/zx                   */
 #define FB_ACCEL_IMS_TWINTURBO 14      /* IMS Twin Turbo               */
+#define FB_ACCEL_3DLABS_PERMEDIA2 15   /* 3Dlabs Permedia 2            */
+#define FB_ACCEL_MATROX_MGA2064W 16    /* Matrox MGA2064W (Millenium)  */
+#define FB_ACCEL_MATROX_MGA1064SG 17   /* Matrox MGA1064SG (Mystique)  */
+#define FB_ACCEL_MATROX_MGA2164W 18    /* Matrox MGA2164W (Millenium II) */
+#define FB_ACCEL_MATROX_MGA2164W_AGP 19        /* Matrox MGA2164W (Millenium II) */
+#define FB_ACCEL_MATROX_MGAG100        20      /* Matrox G100 (Productiva G100) */
+#define FB_ACCEL_MATROX_MGAG200        21      /* Matrox G200 (Myst, Mill, ...) */
 
 struct fb_fix_screeninfo {
        char id[16];                    /* identification string eg "TT Builtin" */
@@ -100,6 +107,7 @@ struct fb_bitfield {
                                        /* values                       */
 #define FB_ACTIVATE_VBL               16       /* activate values on next vbl  */
 #define FB_CHANGE_CMAP_VBL     32      /* change colormap on vbl       */
+#define FB_ACTIVATE_ALL               64       /* change all VCs on this fb    */
 
 #define FB_ACCELF_TEXT         1       /* text mode acceleration */
 
index 21967f6ee60c5525539ca71f8f004211c35d5a72..08e35bb847fd77dcd5c497523dc974f40db89abd 100644 (file)
@@ -3,7 +3,6 @@
 
 #include <linux/sched.h>
 #include <linux/errno.h>
-#include <linux/kernel.h>
 
 #ifdef __KERNEL__
 
index c6ea474365ebcb283cfae55d011fabaa0e6e3f64..cb0048b6c01955513ef265e8d20a84c33777ad3e 100644 (file)
@@ -215,10 +215,25 @@ extern int  nfs_writepage(struct file *, struct page *);
 extern int  nfs_find_dentry_request(struct inode *, struct dentry *);
 extern int  nfs_check_failed_request(struct inode *);
 extern int  nfs_check_error(struct inode *);
-extern int  nfs_flush_pages(struct inode *, pid_t, off_t, off_t);
-extern int  nfs_flush_dirty_pages(struct inode *, pid_t, off_t, off_t);
+
+/*
+ * Try to write back everything synchronously (but check the
+ * return value!)
+ */
+extern int  nfs_wb_all(struct inode *);
+extern int  nfs_wb_page(struct inode *, struct page *);
+extern int  nfs_wb_pid(struct inode *, pid_t);
+extern int  nfs_wb_area(struct inode *, off_t, off_t);
+
+/*
+ * Invalidate write-backs, possibly trying to write them
+ * back first..
+ */
+extern void nfs_inval(struct inode *);
+extern int  nfs_wbinval(struct inode *);
+extern int  nfs_wbinval_pid(struct inode *, pid_t);
+
 extern int  nfs_truncate_dirty_pages(struct inode *, unsigned long);
-extern void nfs_invalidate_pages(struct inode *);
 extern int  nfs_updatepage(struct file *, struct page *, unsigned long, unsigned int, int);
 
 /*
index ef7649b1e254a8bac00a9fd2a713dc2163c2d95a..5adaa85e8be315ee0c2d07e5cbd7a7ec9017298b 100644 (file)
@@ -143,6 +143,7 @@ enum net_directory_inos {
        PROC_NET_NETSTAT,
        PROC_NET_IPFW_CHAINS,
        PROC_NET_IPFW_CHAIN_NAMES,
+       PROC_NET_AT_AARP,
        PROC_NET_LAST
 };
 
@@ -174,6 +175,7 @@ enum scsi_directory_inos {
        PROC_SCSI_ULTRASTOR,
        PROC_SCSI_7000FASST,
        PROC_SCSI_IBMMCA,
+       PROC_SCSI_FD_MCS,
        PROC_SCSI_EATA2X,
        PROC_SCSI_DC390T,
        PROC_SCSI_AM53C974,
@@ -332,7 +334,7 @@ static inline int proc_scsi_unregister(struct proc_dir_entry *driver, int x)
 {
     extern void scsi_init_free(char *ptr, unsigned int size);
 
-    if(x <= PROC_SCSI_FILE)
+    if(x < PROC_SCSI_FILE)
        return(proc_unregister(proc_scsi, x));
     else {
        struct proc_dir_entry **p = &driver->subdir, *dp;
index 8f82db4c2a5b76ccae3d0b0fcc75a7a3713f71a3..4145f56e30bbb5c303a7cf3982e4d8c44266e038 100644 (file)
@@ -125,7 +125,7 @@ extern void fbcon_redraw_bmove(struct display *, int, int, int, int, int, int);
 /* ================================================================= */
 
 
-#ifdef __mc68000__
+#if defined(__mc68000__)
 
 /* ====================================================================== */
 
@@ -363,31 +363,7 @@ static __inline__ void fast_memmove(char *dst, const char *src, size_t size)
        : "d0", "d1", "a0", "a1", "memory");
 }
 
-#else /* !m68k */
-
-    /*
-     *  Anyone who'd like to write asm functions for other CPUs?
-     *   (Why are these functions better than those from include/asm/string.h?)
-     */
-
-#ifndef CONFIG_SUN4
-
-static __inline__ void *mymemclear_small(void *s, size_t count)
-{
-    return(memset(s, 0, count));
-}
-
-static __inline__ void *mymemclear(void *s, size_t count)
-{
-    return(memset(s, 0, count));
-}
-
-static __inline__ void *mymemset(void *s, size_t count)
-{
-    return(memset(s, 255, count));
-}
-
-#else
+#elif defined(CONFIG_SUN4)
 
 /* You may think that I'm crazy and that I should use generic
    routines.  No, I'm not: sun4's framebuffer crashes if we std
@@ -415,9 +391,44 @@ static __inline__ void *mymemclear_small(void *s, size_t count)
 {
     return sun4_memset(s, 0, count);
 }
-#endif
 
-#ifdef __i386__
+/* To be honest, this is slow_memmove :). But sun4 is crappy, so what we can do. */
+static __inline__ void fast_memmove(void *d, const void *s, size_t count)
+{
+    int i;
+    if (d<s) {
+       for (i=0; i<count; i++)
+           ((char *) d)[i] = ((char *) s)[i];
+    } else
+       for (i=0; i<count; i++)
+           ((char *) d)[count-i-1] = ((char *) s)[count-i-1];
+}
+
+static __inline__ void *mymemmove(char *dst, const char *src, size_t size)
+{
+    fast_memmove(dst, src, size);
+    return dst;
+}
+
+#else
+
+static __inline__ void *mymemclear_small(void *s, size_t count)
+{
+    return(memset(s, 0, count));
+}
+
+static __inline__ void *mymemclear(void *s, size_t count)
+{
+    return(memset(s, 0, count));
+}
+
+static __inline__ void *mymemset(void *s, size_t count)
+{
+    return(memset(s, 255, count));
+}
+
+#if defined(__i386__)
+
 static __inline__ void fast_memmove(void *d, const void *s, size_t count)
 {
     if (d < s) {
@@ -466,28 +477,12 @@ static __inline__ void *mymemmove(char *dst, const char *src, size_t size)
     return dst;
 }
 
-#else
+#else /* !i386 */
 
-#ifdef CONFIG_SUN4
-/* To be honest, this is slow_memmove :). But sun4 is crappy, so what we can do. */
-static __inline__ void fast_memmove(void *d, const void *s, size_t count)
-{
-    int i;
-    if (d<s) {
-       for (i=0; i<count; i++)
-           ((char *) d)[i] = ((char *) s)[i];
-    } else
-       for (i=0; i<count; i++)
-           ((char *) d)[count-i-1] = ((char *) s)[count-i-1];
-}
-
-static __inline__ void *mymemmove(char *dst, const char *src, size_t size)
-{
-    fast_memmove(dst, src, size);
-    return dst;
-}
-
-#else
+    /*
+     *  Anyone who'd like to write asm functions for other CPUs?
+     *   (Why are these functions better than those from include/asm/string.h?)
+     */
 
 static __inline__ void *mymemmove(void *d, const void *s, size_t count)
 {
@@ -499,10 +494,8 @@ static __inline__ void fast_memmove(char *dst, const char *src, size_t size)
     memmove(dst, src, size);
 }
 
-#endif /* !sun4 */
-
 #endif /* !i386 */
 
-#endif /* !m68k */
+#endif
 
 #endif /* _VIDEO_FBCON_H */
index f208b17b672988e2ed0c23f97f555d2a75e44c88..5ec3967a354f4a104a0bf8f8b1176b6374e011c0 100644 (file)
@@ -324,6 +324,9 @@ extern void ftape_setup(char *str, int *ints);
 #ifdef CONFIG_MDA_CONSOLE
 extern void mdacon_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_LTPC
+extern void ltpc_setup(char *str, int *ints);
+#endif
 
 #if defined(CONFIG_SYSVIPC)
 extern void ipc_init(void);
@@ -370,7 +373,7 @@ char *get_options(char *str, int *ints)
        char *cur = str;
        int i=1;
 
-       while (cur && isdigit(*cur) && i <= 10) {
+       while (cur && (*cur=='-' || isdigit(*cur)) && i <= 10) {
                ints[i++] = simple_strtol(cur,NULL,0);
                if ((cur = strchr(cur,',')) != NULL)
                        cur++;
@@ -837,6 +840,9 @@ static struct kernel_param cooked_params[] __initdata = {
 #endif
 #ifdef CONFIG_MACMOUSE
        { "adb_buttons=", adb_mouse_setup },
+#endif
+#ifdef CONFIG_LTPC
+       { "ltpc=", ltpc_setup },
 #endif
        { 0, 0 }
 };
index 89ce0b56d18f62d23c8750660cf8de4afcbd7b31..74540951f4b31744f1ee8d17d6098a2ae417a8f7 100644 (file)
@@ -23,6 +23,8 @@
  *             Inside AppleTalk (2nd Ed).
  *     Fixes:
  *             Jaume Grau      -       flush caches on AARP_PROBE
+ *             Rob Newberry    -       Added proxy AARP and AARP proc fs, 
+ *                                     moved probing from DDP module.
  *
  */
 
@@ -53,6 +55,7 @@
 #include <net/psnap.h>
 #include <linux/atalk.h>
 #include <linux/init.h>
+#include <linux/proc_fs.h>
 
  
 int sysctl_aarp_expiry_time = AARP_EXPIRY_TIME;
@@ -69,6 +72,7 @@ struct aarp_entry
        /* These first two are only used for unresolved entries */
        unsigned long last_sent;                /* Last time we xmitted the aarp request */
        struct sk_buff_head packet_queue;       /* Queue of frames wait for resolution */
+       int status;                             /* Used for proxy AARP */
        unsigned long expires_at;               /* Entry expiry time */
        struct at_addr target_addr;             /* DDP Address */
        struct device *dev;                     /* Device to use */
@@ -77,12 +81,11 @@ struct aarp_entry
        struct aarp_entry *next;                /* Next entry in chain */
 };
 
-
 /*
- *     Hashed list of resolved and unresolved entries
+ *     Hashed list of resolved, unresolved and proxy entries
  */
 
-static struct aarp_entry *resolved[AARP_HASH_SIZE], *unresolved[AARP_HASH_SIZE];
+static struct aarp_entry *resolved[AARP_HASH_SIZE], *unresolved[AARP_HASH_SIZE], *proxies[AARP_HASH_SIZE];
 static int unresolved_count=0;
 
 /*
@@ -224,7 +227,7 @@ static void aarp_send_reply(struct device *dev, struct at_addr *us, struct at_ad
 }
 
 /*
- *     Send probe frames. Called from atif_probe_device.
+ *     Send probe frames. Called from aarp_probe_network and aarp_proxy_probe_network.
  */
  
 void aarp_send_probe(struct device *dev, struct at_addr *us)
@@ -360,6 +363,7 @@ static void aarp_expire_timeout(unsigned long unused)
                aarp_expire_timer(&resolved[ct]);
                aarp_kick(&unresolved[ct]);
                aarp_expire_timer(&unresolved[ct]);
+               aarp_expire_timer(&proxies[ct]);
        }
        del_timer(&aarp_timer);
        if(unresolved_count==0)
@@ -382,6 +386,7 @@ static int aarp_device_event(struct notifier_block *this, unsigned long event, v
                {
                        aarp_expire_device(&resolved[ct],ptr);
                        aarp_expire_device(&unresolved[ct],ptr);
+                       aarp_expire_device(&proxies[ct],ptr);
                }
        }
        return NOTIFY_DONE;
@@ -420,6 +425,156 @@ static struct aarp_entry *aarp_find_entry(struct aarp_entry *list, struct device
        return list;
 }
 
+void aarp_proxy_remove(struct device *dev, struct at_addr *sa)
+{
+       struct aarp_entry *a;
+       int hash;
+       
+       hash =  sa->s_node % (AARP_HASH_SIZE-1);
+       a = aarp_find_entry(proxies[hash], dev, sa);
+       if (a)
+       {
+               a->expires_at = 0;
+               
+       }
+}
+
+struct at_addr* aarp_proxy_find(struct device *dev, struct at_addr *sa)
+{
+       struct aarp_entry *a;
+       int hash;
+
+       hash =  sa->s_node % (AARP_HASH_SIZE-1);
+       a = aarp_find_entry(proxies[hash], dev, sa);
+       if (a != NULL)
+               return sa;
+       
+       return NULL;
+}
+
+       
+/*
+ * Probe a Phase 1 device or a device that requires its Net:Node to
+ * be set via an ioctl.
+ */
+void aarp_send_probe_phase1(struct atalk_iface *iface)
+{
+    struct ifreq atreq;
+    struct sockaddr_at *sa = (struct sockaddr_at *)&atreq.ifr_addr;
+
+    sa->sat_addr.s_node = iface->address.s_node;
+    sa->sat_addr.s_net  = ntohs(iface->address.s_net);
+
+       /* We pass the Net:Node to the drivers/cards by a Device ioctl. */
+       if(!(iface->dev->do_ioctl(iface->dev, &atreq, SIOCSIFADDR)))
+    {
+       (void)iface->dev->do_ioctl(iface->dev, &atreq, SIOCGIFADDR);
+       if((iface->address.s_net != htons(sa->sat_addr.s_net))
+                               || (iface->address.s_node != sa->sat_addr.s_node))
+                       iface->status |= ATIF_PROBE_FAIL;
+
+               iface->address.s_net  = htons(sa->sat_addr.s_net);
+               iface->address.s_node = sa->sat_addr.s_node;
+       }
+
+       return;
+}
+
+
+void aarp_probe_network(struct atalk_iface *atif)
+{
+       if(atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP)
+               aarp_send_probe_phase1(atif);
+       else
+       {
+               unsigned int count;
+               for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++)
+               {
+                       aarp_send_probe(atif->dev, &atif->address);
+
+                       /*
+                        * Defer 1/10th
+                        */
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout(HZ/10);
+                                                       
+                       if (atif->status & ATIF_PROBE_FAIL)
+                               break;
+               }
+       }
+}
+
+int aarp_proxy_probe_network(struct atalk_iface *atif, struct at_addr *sa)
+{
+       struct  aarp_entry      *entry;
+       unsigned int count;
+       int     hash;
+       
+       /*
+        * we don't currently support LocalTalk or PPP for proxy AARP;
+        * if someone wants to try and add it, have fun
+        */
+       if (atif->dev->type == ARPHRD_LOCALTLK)
+               return (-EPROTONOSUPPORT);
+               
+       if (atif->dev->type == ARPHRD_PPP)
+               return (-EPROTONOSUPPORT);
+               
+       /* 
+        * create a new AARP entry with the flags set to be published -- 
+        * we need this one to hang around even if it's in use
+        */
+       entry = aarp_alloc();
+       if (entry == NULL)
+               return (-ENOMEM);
+       
+       entry->expires_at = -1;
+       entry->status = ATIF_PROBE;
+       entry->target_addr.s_node = sa->s_node;
+       entry->target_addr.s_net = sa->s_net;
+       entry->dev = atif->dev;
+
+       hash = sa->s_node % (AARP_HASH_SIZE-1);
+       entry->next = proxies[hash];
+       proxies[hash] = entry;
+       
+       for(count = 0; count < AARP_RETRANSMIT_LIMIT; count++)
+       {
+               aarp_send_probe(atif->dev, sa);
+
+               /*
+                * Defer 1/10th
+                */
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(HZ/10);
+                                               
+               if (entry->status & ATIF_PROBE_FAIL)
+                       break;
+       }
+       
+       /*
+        * FIX ME: I think we need exclusive access to the status flags,
+        *              in case some one fails the probe while we're removing
+        *              the probe flag.
+        */
+       if (entry->status & ATIF_PROBE_FAIL)
+       {
+               /* free the entry */
+               entry->expires_at = 0;
+               
+               /* return network full */
+               return (-EADDRINUSE);
+       }
+       else
+       {
+               /* clear the probing flag */
+               entry->status &= ~ATIF_PROBE;
+       }
+
+       return 1;       
+}
+
+
 /*
  *     Send a DDP frame
  */
@@ -654,7 +809,7 @@ static int aarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
 {
        struct elapaarp *ea=(struct elapaarp *)skb->h.raw;
        struct aarp_entry *a;
-       struct at_addr sa, *ma;
+       struct at_addr sa, *ma, da;
        unsigned long flags;
        int hash;
        struct atalk_iface *ifa;
@@ -736,8 +891,34 @@ static int aarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
                        kfree_skb(skb);
                        return 1;               
                }
-       }                                
+       }
        
+       /*
+        * Check for replies of proxy AARP entries
+        */
+
+       /*
+        * FIX ME: do we need a cli() here? 
+        * aarp_find_entry does one on its own, between saving and restoring flags, so
+        * I don't think it is necessary, but I could be wrong -- it's happened before
+        */
+       da.s_node = ea->pa_dst_node;
+       da.s_net = ea->pa_dst_net;
+       a = aarp_find_entry(proxies[hash], dev, &da);
+       if (a != NULL)
+               if (a->status & ATIF_PROBE)
+               {
+                       a->status |= ATIF_PROBE_FAIL;
+                       
+                       /*
+                        * we do not respond to probe or request packets for 
+                        * this address while we are probing this address
+                        */
+                       restore_flags(flags);
+                       kfree_skb(skb);
+                       return 1;
+               }
+
        switch(ea->function)
        {
                case AARP_REPLY:        
@@ -747,7 +928,7 @@ static int aarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
                         *      Find the entry  
                         */
                         
-                       cli();
+                       cli();  /* FIX ME: is this cli() necessary? aarp_find_entry does one on its own... */
                        if((a=aarp_find_entry(unresolved[hash],dev,&sa))==NULL || dev != a->dev)
                                break;
                        /*
@@ -770,12 +951,32 @@ static int aarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
                         *      If it is my address set ma to my address and reply. We can treat probe and
                         *      request the same. Probe simply means we shouldn't cache the querying host, 
                         *      as in a probe they are proposing an address not using one.
+                        *      
+                        *      Support for proxy-AARP added.  We check if the address is one
+                        *      of our proxies before we toss the packet out.
                         */
                         
-                       ma=&ifa->address;
                        sa.s_node=ea->pa_dst_node;
                        sa.s_net=ea->pa_dst_net;
-                       
+
+                       /*
+                        * see if we have a matching proxy
+                        */
+                       ma = aarp_proxy_find(dev, &sa);
+                       if (!ma)
+                       {
+                               ma=&ifa->address;
+                       }
+                       else
+                       {
+                               /*
+                                * we need to make a copy of the entry
+                                */
+                               da.s_node = sa.s_node;
+                               da.s_net = da.s_net;
+                               ma = &da;
+                       }
+
                        if(ea->function==AARP_PROBE)
                        {
                                /* A probe implies someone trying to get an
@@ -845,11 +1046,104 @@ void aarp_device_down(struct device *dev)
        {
                aarp_expire_device(&resolved[ct], dev);
                aarp_expire_device(&unresolved[ct], dev);
+               aarp_expire_device(&proxies[ct], dev);
        }
 
        return;
 }
 
+/*
+ * Called from proc fs
+ */
+int aarp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+       /* we should dump all our AARP entries */
+       struct aarp_entry       *entry;
+       int                     len, ct;
+
+       len = sprintf(buffer,
+               "%-10.10s  ""%-10.10s""%-18.18s""%12.12s""%12.12s"" xmit_count  status\n",
+               "address","device","hw addr","last_sent", "expires");
+       for (ct = 0; ct < AARP_HASH_SIZE; ct++)
+       {
+               for (entry = resolved[ct]; entry; entry = entry->next)
+               {
+                       len+= sprintf(buffer+len,"%6u:%-3u  ",
+                               (unsigned int)ntohs(entry->target_addr.s_net),
+                               (unsigned int)(entry->target_addr.s_node));
+                       len+= sprintf(buffer+len,"%-10.10s",
+                               entry->dev->name);
+                       len+= sprintf(buffer+len,"%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+                               (int)(entry->hwaddr[0] & 0x000000FF),
+                               (int)(entry->hwaddr[1] & 0x000000FF),
+                               (int)(entry->hwaddr[2] & 0x000000FF),
+                               (int)(entry->hwaddr[3] & 0x000000FF),
+                               (int)(entry->hwaddr[4] & 0x000000FF),
+                               (int)(entry->hwaddr[5] & 0x000000FF));
+                       len+= sprintf(buffer+len,"%12lu ""%12lu ",
+                               (unsigned long)entry->last_sent,
+                               (unsigned long)entry->expires_at);
+                       len+=sprintf(buffer+len,"%10u",
+                               (unsigned int)entry->xmit_count);
+
+                       len+=sprintf(buffer+len,"   resolved\n");
+               }
+       }
+
+       for (ct = 0; ct < AARP_HASH_SIZE; ct++)
+       {
+               for (entry = unresolved[ct]; entry; entry = entry->next)
+               {
+                       len+= sprintf(buffer+len,"%6u:%-3u  ",
+                               (unsigned int)ntohs(entry->target_addr.s_net),
+                               (unsigned int)(entry->target_addr.s_node));
+                       len+= sprintf(buffer+len,"%-10.10s",
+                               entry->dev->name);
+                       len+= sprintf(buffer+len,"%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+                               (int)(entry->hwaddr[0] & 0x000000FF),
+                               (int)(entry->hwaddr[1] & 0x000000FF),
+                               (int)(entry->hwaddr[2] & 0x000000FF),
+                               (int)(entry->hwaddr[3] & 0x000000FF),
+                               (int)(entry->hwaddr[4] & 0x000000FF),
+                               (int)(entry->hwaddr[5] & 0x000000FF));
+                       len+= sprintf(buffer+len,"%12lu ""%12lu ",
+                               (unsigned long)entry->last_sent,
+                               (unsigned long)entry->expires_at);
+                       len+=sprintf(buffer+len,"%10u",
+                               (unsigned int)entry->xmit_count);
+                       len+=sprintf(buffer+len," unresolved\n");
+               }
+       }
+
+       for (ct = 0; ct < AARP_HASH_SIZE; ct++)
+       {
+               for (entry = proxies[ct]; entry; entry = entry->next)
+               {
+                       len+= sprintf(buffer+len,"%6u:%-3u  ",
+                               (unsigned int)ntohs(entry->target_addr.s_net),
+                               (unsigned int)(entry->target_addr.s_node));
+                       len+= sprintf(buffer+len,"%-10.10s",
+                               entry->dev->name);
+                       len+= sprintf(buffer+len,"%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+                               (int)(entry->hwaddr[0] & 0x000000FF),
+                               (int)(entry->hwaddr[1] & 0x000000FF),
+                               (int)(entry->hwaddr[2] & 0x000000FF),
+                               (int)(entry->hwaddr[3] & 0x000000FF),
+                               (int)(entry->hwaddr[4] & 0x000000FF),
+                               (int)(entry->hwaddr[5] & 0x000000FF));
+                       len+= sprintf(buffer+len,"%12lu ""%12lu ",
+                               (unsigned long)entry->last_sent,
+                               (unsigned long)entry->expires_at);
+                       len+=sprintf(buffer+len,"%10u",
+                               (unsigned int)entry->xmit_count);
+                       len+=sprintf(buffer+len,"      proxy\n");
+               }
+       }
+
+
+       return len;
+}
+
 #ifdef MODULE
 /*
  * General module cleanup. Called from cleanup_module() in ddp.c.
@@ -862,4 +1156,27 @@ void aarp_cleanup_module(void)
 }
 
 #endif  /* MODULE */
+
+#ifdef CONFIG_PROC_FS
+
+static struct proc_dir_entry proc_aarp_entries=
+{
+       PROC_NET_AT_AARP, 4, "aarp",
+       S_IFREG | S_IRUGO, 1, 0, 0,
+       0, &proc_net_inode_operations,
+       aarp_get_info
+};
+
+void aarp_register_proc_fs(void)
+{
+       proc_net_register(&proc_aarp_entries);
+}
+
+void aarp_unregister_proc_fs(void)
+{
+       proc_net_unregister(PROC_NET_AT_AARP);
+}
+
+#endif
+
 #endif  /* CONFIG_ATALK || CONFIG_ATALK_MODULE */
index 36062dfc0e19aee723881ac7d26decaad516d51c..c79fc6874e9e10d252ce3fb13f43f30d140d9d53 100644 (file)
@@ -29,6 +29,8 @@
  *                                             driver file. (ipddp.c & ipddp.h)
  *             Jay Schulist            :       Made work as module with 
  *                                             AppleTalk drivers, cleaned it.
+ *             Rob Newberry            :       Added proxy AARP and AARP proc fs, 
+ *                                             moved probing to AARP module.
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
 #include <linux/init.h>
 
 
+#ifdef CONFIG_PROC_FS
+extern void aarp_register_proc_fs(void);
+extern void aarp_unregister_proc_fs(void);
+#endif
+
+extern void aarp_probe_network(struct atalk_iface *atif);
+extern int  aarp_proxy_probe_network(struct atalk_iface *atif, struct at_addr *sa);
+extern void aarp_proxy_remove(struct device *dev, struct at_addr *sa);
+
+
 #undef APPLETALK_DEBUG
 
 #ifdef APPLETALK_DEBUG
@@ -301,32 +313,6 @@ static struct atalk_iface *atif_add_device(struct device *dev, struct at_addr *s
        return (iface);
 }
 
-/*
- * Probe a Phase 1 device or a device that requires its Net:Node to
- * be set via an ioctl.
- */
-void atif_send_probe_phase1(struct atalk_iface *iface)
-{
-        struct ifreq atreq;
-        struct sockaddr_at *sa = (struct sockaddr_at *)&atreq.ifr_addr;
-
-        sa->sat_addr.s_node = iface->address.s_node;
-        sa->sat_addr.s_net  = ntohs(iface->address.s_net);
-
-         /* We pass the Net:Node to the drivers/cards by a Device ioctl. */
-        if(!(iface->dev->do_ioctl(iface->dev, &atreq, SIOCSIFADDR)))
-        {
-                (void)iface->dev->do_ioctl(iface->dev, &atreq, SIOCGIFADDR);
-                if((iface->address.s_net != htons(sa->sat_addr.s_net))
-                       || (iface->address.s_node != sa->sat_addr.s_node))
-                        iface->status |= ATIF_PROBE_FAIL;
-
-                iface->address.s_net  = htons(sa->sat_addr.s_net);
-               iface->address.s_node = sa->sat_addr.s_node;
-        }
-
-        return;
-}
 
 /*
  * Perform phase 2 AARP probing on our tentative address.
@@ -336,7 +322,7 @@ static int atif_probe_device(struct atalk_iface *atif)
        int netrange=ntohs(atif->nets.nr_lastnet)-ntohs(atif->nets.nr_firstnet)+1;
        int probe_net=ntohs(atif->address.s_net);
        int probe_node=atif->address.s_node;
-       int ct, netct, nodect;
+       int netct, nodect;
 
        /*
         * Offset the network we start probing with.
@@ -372,23 +358,8 @@ static int atif_probe_device(struct atalk_iface *atif)
                                /*
                                 * Probe a proposed address.
                                 */
+                               aarp_probe_network(atif);
 
-                               if(atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP)
-                                        atif_send_probe_phase1(atif);
-                                else
-                                {
-                                       for(ct = 0; ct < AARP_RETRANSMIT_LIMIT; ct++)
-                                       {
-                                               aarp_send_probe(atif->dev, &atif->address);
-                                               /*
-                                                * Defer 1/10th
-                                                */
-                                               current->state = TASK_INTERRUPTIBLE;
-                                               schedule_timeout(HZ/10);
-                                               if(atif->status & ATIF_PROBE_FAIL)
-                                                       break;
-                                       }
-                               }
                                if(!(atif->status & ATIF_PROBE_FAIL))
                                        return (0);
                        }
@@ -402,6 +373,69 @@ static int atif_probe_device(struct atalk_iface *atif)
        return (-EADDRINUSE);   /* Network is full... */
 }
 
+
+/*
+ * Perform AARP probing for a proxy address
+ */
+static int atif_proxy_probe_device(struct atalk_iface *atif, struct at_addr* proxy_addr)
+{
+       int netrange=ntohs(atif->nets.nr_lastnet)-ntohs(atif->nets.nr_firstnet)+1;
+       int probe_net=ntohs(atif->address.s_net);       // we probe the interface's network
+       int probe_node=ATADDR_ANYNODE;                          // we'll take anything
+       int netct, nodect;
+
+       /*
+        * Offset the network we start probing with.
+        */
+
+       if(probe_net == ATADDR_ANYNET)
+       {
+               if(!netrange)
+                       probe_net = ntohs(atif->nets.nr_firstnet);
+               else
+                       probe_net = ntohs(atif->nets.nr_firstnet) + (jiffies%netrange);
+       }
+
+       if(probe_node == ATADDR_ANYNODE)
+               probe_node = jiffies&0xFF;
+               
+       /*
+        * Scan the networks.
+        */
+
+       for(netct = 0; netct <= netrange; netct++)
+       {
+               /*
+                * Sweep the available nodes from a given start.
+                */
+
+               proxy_addr->s_net = htons(probe_net);
+               for(nodect = 0; nodect < 256; nodect++)
+               {
+                       proxy_addr->s_node = ((nodect+probe_node) & 0xFF);
+                       if((proxy_addr->s_node>0) && (proxy_addr->s_node<254))
+                       {
+                               /*
+                                * Tell AARP to probe a proposed address.
+                                */
+                               int probe_result = aarp_proxy_probe_network(atif, proxy_addr);
+
+                               if (probe_result == 0)
+                                       return 0;
+                                       
+                               if (probe_result != -EADDRINUSE)
+                                       return probe_result;
+                       }
+               }
+               probe_net++;
+               if(probe_net > ntohs(atif->nets.nr_lastnet))
+                       probe_net = ntohs(atif->nets.nr_firstnet);
+       }
+
+       return (-EADDRINUSE);   /* Network is full... */
+}
+
+
 struct at_addr *atalk_find_dev_addr(struct device *dev)
 {
        struct atalk_iface *iface=dev->atalk_ptr;
@@ -481,19 +515,46 @@ static struct atalk_iface *atalk_find_interface(int net, int node)
  */
 static struct atalk_route *atrtr_find(struct at_addr *target)
 {
+       /*
+        * we must search through all routes unless we find a 
+        * host route, because some host routes might overlap
+        * network routes
+        */
        struct atalk_route *r;
-
+       struct atalk_route *net_route = NULL;
+       
        for(r=atalk_router_list; r != NULL; r=r->next)
        {
                if(!(r->flags & RTF_UP))
                        continue;
                if(r->target.s_net == target->s_net)
                {
-                       if(!(r->flags&RTF_HOST) 
-                               || r->target.s_node == target->s_node)
-                               return (r);
+                       if (r->flags & RTF_HOST)
+                       {
+                               /*
+                                * if this host route is for the target,
+                                * the we're done
+                                */
+                               if (r->target.s_node == target->s_node)
+                                       return (r);
+                       }
+                       else
+                       {
+                               /*
+                                * this route will work if there isn't a
+                                * direct host route, so cache it
+                                */
+                               net_route = r;
+                       }
                }
        }
+       
+       /* 
+        * if we found a network route but not a direct host
+        * route, then return it
+        */
+       if (net_route != NULL)
+               return (net_route);
 
        if(atrtr_default.dev)
                return (&atrtr_default);
@@ -705,6 +766,7 @@ int atif_ioctl(int cmd, void *arg)
        int ct;
        int limit;
        struct rtentry rtdef;
+       int     add_route;
 
        if(copy_from_user(&atreq,arg,sizeof(atreq)))
                return (-EFAULT);
@@ -730,6 +792,18 @@ int atif_ioctl(int cmd, void *arg)
 
                        nr=(struct netrange *)&sa->sat_zero[0];
 
+                       add_route = 1;
+
+                       /*
+                        * if this is a point-to-point iface, and we already have an 
+                        * iface for this AppleTalk address, then we should not add a route
+                        */
+                       if (dev->flags & IFF_POINTOPOINT && atalk_find_interface(sa->sat_addr.s_net, sa->sat_addr.s_node))
+                       {
+                               printk(KERN_DEBUG "AppleTalk: point-to-point interface added with existing address\n");
+                               add_route = 0;
+                       }
+                       
                        /*
                         * Phase 1 is fine on LocalTalk but we don't do
                         * EtherTalk phase 1. Anyone wanting to add it go ahead.
@@ -764,7 +838,7 @@ int atif_ioctl(int cmd, void *arg)
                         * error and atalkd will try another.
                         */
 
-                       if(!(dev->flags & IFF_LOOPBACK) && atif_probe_device(atif) < 0)
+                       if(!(dev->flags & IFF_LOOPBACK) && !(dev->flags & IFF_POINTOPOINT) && atif_probe_device(atif) < 0)
                        {
                                atif_drop_device(dev);
                                return (-EADDRINUSE);
@@ -782,7 +856,7 @@ int atif_ioctl(int cmd, void *arg)
                        rtdef.rt_flags = RTF_UP;
                        sa->sat_family = AF_APPLETALK;
                        sa->sat_addr.s_node = ATADDR_ANYNODE;
-                       if(dev->flags & IFF_LOOPBACK)
+                       if((dev->flags & IFF_LOOPBACK) || (dev->flags & IFF_POINTOPOINT))
                                rtdef.rt_flags |= RTF_HOST;
 
                        /*
@@ -803,11 +877,12 @@ int atif_ioctl(int cmd, void *arg)
                                        printk(KERN_WARNING "Too many routes/iface.\n");
                                        return (-EINVAL);
                                }
-                               for(ct=ntohs(nr->nr_firstnet);ct<=limit;ct++)
-                               {
-                                       sa->sat_addr.s_net = htons(ct);
-                                       atrtr_create(&rtdef, dev);
-                               }
+                               if (add_route)
+                                       for(ct=ntohs(nr->nr_firstnet);ct<=limit;ct++)
+                                       {
+                                               sa->sat_addr.s_net = htons(ct);
+                                               atrtr_create(&rtdef, dev);
+                                       }
                        }
                        dev_mc_add(dev, aarp_mcast, 6, 1);
                        return (0);
@@ -835,6 +910,68 @@ int atif_ioctl(int cmd, void *arg)
                                return (-EINVAL);
                        atalk_dev_down(dev);
                        break;                  
+
+               case SIOCSARP:
+                       if(!suser())
+                                return (-EPERM);
+                        if(sa->sat_family != AF_APPLETALK)
+                                return (-EINVAL);
+
+                        /*
+                         * for now, we only support proxy AARP on ELAP;
+                         * we should be able to do it for LocalTalk, too.
+                         */
+                        if(dev->type != ARPHRD_ETHER)
+                                return (-EPROTONOSUPPORT);
+
+                        /*
+                         * atif points to the current interface on this network;
+                         * we aren't concerned about its current status (at least for now),
+                         * but it has all the settings about the network we're going
+                         * to probe.  consequently, it must exist.
+                         */
+                        if (!atif)
+                                return (-EADDRNOTAVAIL);
+
+                        nr=(struct netrange *)&(atif->nets);
+                        /*
+                         * Phase 1 is fine on Localtalk but we don't do
+                         * Ethertalk phase 1. Anyone wanting to add it go ahead.
+                         */
+                        if(dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
+                                return (-EPROTONOSUPPORT);
+
+                        if(sa->sat_addr.s_node == ATADDR_BCAST
+                                || sa->sat_addr.s_node == 254)
+                                return (-EINVAL);
+
+                        /*
+                         * Check if the chosen address is used. If so we
+                         * error and ATCP will try another.
+                         */
+                       if (atif_proxy_probe_device(atif, &(sa->sat_addr)) < 0)
+                               return (-EADDRINUSE);
+                       
+                       /*
+                         * We now have an address on the local network, and the AARP
+                         * code will defend it for us until we take it down.
+                         * We don't set up any routes right now, because ATCP will
+                         * install them manually via SIOCADDRT.
+                         */
+                        break;
+
+                case SIOCDARP:
+                        if(!suser())
+                                return (-EPERM);
+                        if(sa->sat_family != AF_APPLETALK)
+                                return (-EINVAL);
+
+                        /*
+                         * give to aarp module to remove proxy entry
+                         */
+                        aarp_proxy_remove(atif->dev, &(sa->sat_addr));
+
+                        return (0);
        }
 
        if(copy_to_user(arg, &atreq, sizeof(atreq)))
@@ -849,6 +986,7 @@ int atif_ioctl(int cmd, void *arg)
 static int atrtr_ioctl(unsigned int cmd, void *arg)
 {
        struct rtentry rt;
+       struct device *dev = NULL;
 
        if(copy_from_user(&rt, arg, sizeof(rt)))
                return (-EFAULT);
@@ -861,7 +999,12 @@ static int atrtr_ioctl(unsigned int cmd, void *arg)
                        return (atrtr_delete(&((struct sockaddr_at *)&rt.rt_dst)->sat_addr));
 
                case SIOCADDRT:
-                       return (atrtr_create(&rt, NULL));
+                       /* FIX ME: the name of the device is still in user space, isn't it? */
+                       if (rt.rt_dev != NULL)
+                               if ((dev = dev_get(rt.rt_dev)) == NULL)
+                                       return -(ENODEV);
+                       
+                       return (atrtr_create(&rt, dev));
 
                default:
                        return (-EINVAL);
@@ -1004,7 +1147,15 @@ static int atalk_create(struct socket *sock, int protocol)
                case SOCK_DGRAM:
                        sock->ops = &atalk_dgram_ops;
                        break;
-
+                       
+               case SOCK_STREAM:
+                       /*
+                        * TO DO: if you want to implement ADSP, here's the place to start
+                        */
+                       /*
+                       sock->ops = &atalk_stream_ops;
+                       break;
+                       */
                default:
                        sk_free((void *)sk);
                        return (-ESOCKTNOSUPPORT);
@@ -1330,6 +1481,13 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
                 */
                if (skb->pkt_type != PACKET_HOST || ddp->deh_dnet == 0)
                {
+                       /*
+                        * FIX ME:
+                        * Can it ever happen that a packet is from a PPP iface and needs to be broadcast onto the default network?
+                        */
+                       if (dev->type == ARPHRD_PPP)
+                               printk(KERN_DEBUG "AppleTalk: didn't forward broadcast packet received from PPP iface\n");
+                       
                        kfree_skb(skb);
                        return (0);
                }
@@ -1821,6 +1979,8 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg)
                case SIOCGIFBRDADDR:
                case SIOCATALKDIFADDR:
                case SIOCDIFADDR:
+               case SIOCSARP:  /* proxy AARP */
+               case SIOCDARP:  /* proxy AARP */
                        return (atif_ioctl(cmd,(void *)arg));
 
                /*
@@ -1966,6 +2126,8 @@ __initfunc(void atalk_proto_init(struct net_proto *pro))
        proc_net_register(&proc_appletalk);
        proc_net_register(&proc_atalk_route);
        proc_net_register(&proc_atalk_iface);
+
+       aarp_register_proc_fs();
 #endif /* CONFIG_PROC_FS */
 
 #ifdef CONFIG_SYSCTL
@@ -2006,6 +2168,8 @@ void cleanup_module(void)
        proc_net_unregister(PROC_NET_ATALK);
        proc_net_unregister(PROC_NET_AT_ROUTE);
        proc_net_unregister(PROC_NET_ATIF);
+
+       aarp_unregister_proc_fs();
 #endif /* CONFIG_PROC_FS */
 
        aarp_cleanup_module();  /* General aarp clean-up. */
index b5d5f071ef1e3083ee42792de1758e59ea2ee584..1382132ed022a482ad266d535e473fa4775deca5 100644 (file)
@@ -195,6 +195,18 @@ int ax25_rebuild_header(struct sk_buff *skb)
        return 1;
 }
 
+#else  /* INET */
+
+int ax25_encapsulate(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+       return -AX25_HEADER_LEN;
+}
+
+int ax25_rebuild_header(struct sk_buff *skb)
+{
+       return 1;
+}
+
 #endif
 
 #endif
index 0db8e06ef69c32732cc49066068db6d9dd87d787..5990b69a3cc49b03d6d5a32a37d63c6e53174f5e 100644 (file)
@@ -2324,6 +2324,7 @@ extern struct datalink_proto *make_8023_client(void);
 extern void destroy_EII_client(struct datalink_proto *);
 extern void destroy_8023_client(struct datalink_proto *);
 
+#ifdef CONFIG_PROC_FS
 struct proc_dir_entry ipx_procinfo = {
        PROC_NET_IPX, 3, "ipx", S_IFREG | S_IRUGO,
        1, 0, 0, 0, &proc_net_inode_operations, ipx_get_info
@@ -2338,6 +2339,7 @@ struct proc_dir_entry ipx_rt_procinfo = {
        PROC_NET_IPX_ROUTE, 9, "ipx_route", S_IFREG | S_IRUGO,
        1, 0, 0, 0, &proc_net_inode_operations, ipx_rt_get_info
 };
+#endif
 
 static unsigned char ipx_8022_type = 0xE0;
 static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
index a5b6afc9b13394c35ed6a50c637bb0be645c0468..d3e96333d452476abc59b41b5c3c0d28ecd99bfe 100644 (file)
 #include <linux/types.h>
 #include <linux/net.h>
 #include <linux/in.h>
+#include <net/sock.h>
+#include <net/dst.h>
+#include <net/checksum.h>
+#include <net/pkt_sched.h>
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/fddidevice.h>
 #include <linux/trdevice.h>
 #include <linux/ioport.h>
 #include <net/neighbour.h>
@@ -23,8 +29,6 @@
 
 #ifdef CONFIG_INET
 #include <linux/ip.h>
-#include <linux/etherdevice.h>
-#include <linux/fddidevice.h>
 #include <net/protocol.h>
 #include <net/arp.h>
 #include <net/ip.h>
 #include <net/route.h>
 #include <net/scm.h>
 #include <net/inet_common.h>
-#include <net/pkt_sched.h>
 #include <linux/inet.h>
 #include <linux/mroute.h>
 #include <linux/igmp.h>
 
 extern struct net_proto_family inet_family_ops;
 
+#ifdef CONFIG_DLCI_MODULE
+extern int (*dlci_ioctl_hook)(unsigned int, void *);
+EXPORT_SYMBOL(dlci_ioctl_hook);
+#endif
+
+#endif
+
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 #include <linux/in6.h>
 #include <linux/icmpv6.h>
@@ -52,7 +62,6 @@ extern struct net_proto_family inet_family_ops;
 extern int tcp_tw_death_row_slot;
 #endif
 
-#endif
 
 #include <linux/rtnetlink.h>
 
@@ -213,9 +222,6 @@ EXPORT_SYMBOL(ip_route_output);
 EXPORT_SYMBOL(icmp_send);
 EXPORT_SYMBOL(ip_options_compile);
 EXPORT_SYMBOL(arp_send);
-#ifdef CONFIG_SHAPER_MODULE
-EXPORT_SYMBOL(arp_broken_ops);
-#endif
 EXPORT_SYMBOL(ip_id_count);
 EXPORT_SYMBOL(ip_send_check);
 EXPORT_SYMBOL(ip_fragment);
@@ -227,6 +233,9 @@ EXPORT_SYMBOL(__ip_finish_output);
 EXPORT_SYMBOL(inet_dgram_ops);
 EXPORT_SYMBOL(ip_cmsg_recv);
 EXPORT_SYMBOL(__release_sock);
+EXPORT_SYMBOL(arp_find);
+EXPORT_SYMBOL(ip_rcv);
+EXPORT_SYMBOL(arp_rcv);
 
 /* needed for ip_gre -cw */
 EXPORT_SYMBOL(ip_statistics);
@@ -436,12 +445,9 @@ EXPORT_SYMBOL(netdev_fc_xoff);
 EXPORT_SYMBOL(dev_base);
 EXPORT_SYMBOL(dev_close);
 EXPORT_SYMBOL(dev_mc_add);
-EXPORT_SYMBOL(arp_find);
 EXPORT_SYMBOL(n_tty_ioctl);
 EXPORT_SYMBOL(tty_register_ldisc);
 EXPORT_SYMBOL(kill_fasync);
-EXPORT_SYMBOL(ip_rcv);
-EXPORT_SYMBOL(arp_rcv);
 EXPORT_SYMBOL(dev_mc_delete);
 
 EXPORT_SYMBOL(if_port_text);
@@ -451,10 +457,6 @@ EXPORT_SYMBOL(if_port_text);
 EXPORT_SYMBOL(ltalk_setup);
 #endif
 
-#ifdef CONFIG_DLCI_MODULE
-extern int (*dlci_ioctl_hook)(unsigned int, void *);
-EXPORT_SYMBOL(dlci_ioctl_hook);
-#endif
 
 /* Packet scheduler modules want these. */
 EXPORT_SYMBOL(qdisc_destroy);