]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.112pre2 2.1.112pre2
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:16:05 +0000 (15:16 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:16:05 +0000 (15:16 -0500)
156 files changed:
Documentation/Configure.help
MAINTAINERS
Makefile
arch/i386/kernel/io_apic.c
arch/i386/mm/ioremap.c
drivers/char/console.c
drivers/char/consolemap.c
drivers/char/fbmem.c
drivers/char/selection.c
drivers/char/vc_screen.c
drivers/char/vt.c
drivers/misc/parport_procfs.c
drivers/net/3c509.c
drivers/net/Config.in
drivers/net/Makefile
drivers/net/Space.c
drivers/net/bmac.c [new file with mode: 0644]
drivers/net/bmac.h [new file with mode: 0644]
drivers/net/daynaport.c [new file with mode: 0644]
drivers/net/eepro.c
drivers/net/ibmtr.c
drivers/net/ibmtr.h
drivers/net/lance.c
drivers/net/mace.c
drivers/net/myri_sbus.c
drivers/net/plip.c
drivers/net/seeq8005.c
drivers/net/sk_g16.c
drivers/net/sonic.c
drivers/net/sunhme.c
drivers/net/sunlance.c
drivers/net/sunqe.c
drivers/net/wavelan.c
drivers/net/wavelan.h
drivers/net/wavelan.p.h
drivers/scsi/eata.c
drivers/scsi/eata.h
drivers/scsi/u14-34f.c
drivers/scsi/u14-34f.h
drivers/video/Config.in
drivers/video/Makefile
drivers/video/atafb.c
drivers/video/atyfb.c
drivers/video/bwtwofb.c [new file with mode: 0644]
drivers/video/cgsixfb.c
drivers/video/cgthreefb.c [new file with mode: 0644]
drivers/video/clgenfb.c [new file with mode: 0644]
drivers/video/clgenfb.h [new file with mode: 0644]
drivers/video/controlfb.c [new file with mode: 0644]
drivers/video/controlfb.h [new file with mode: 0644]
drivers/video/creatorfb.c
drivers/video/cyberfb.c
drivers/video/dnfb.c
drivers/video/dummycon.c
drivers/video/fbcon-afb.c
drivers/video/fbcon-afb.h
drivers/video/fbcon-cfb16.c
drivers/video/fbcon-cfb16.h
drivers/video/fbcon-cfb2.c
drivers/video/fbcon-cfb2.h
drivers/video/fbcon-cfb24.c
drivers/video/fbcon-cfb24.h
drivers/video/fbcon-cfb32.c
drivers/video/fbcon-cfb32.h
drivers/video/fbcon-cfb4.c
drivers/video/fbcon-cfb4.h
drivers/video/fbcon-cfb8.c
drivers/video/fbcon-cfb8.h
drivers/video/fbcon-ilbm.c
drivers/video/fbcon-ilbm.h
drivers/video/fbcon-iplan2p2.c
drivers/video/fbcon-iplan2p2.h
drivers/video/fbcon-iplan2p4.c
drivers/video/fbcon-iplan2p4.h
drivers/video/fbcon-iplan2p8.c
drivers/video/fbcon-iplan2p8.h
drivers/video/fbcon-mac.c
drivers/video/fbcon-mac.h
drivers/video/fbcon-mfb.c
drivers/video/fbcon-mfb.h
drivers/video/fbcon-vga.h
drivers/video/fbcon.c
drivers/video/fbcon.h
drivers/video/fbgen.c
drivers/video/font_acorn_8x8.c
drivers/video/fonts.c
drivers/video/macfb.c
drivers/video/macmodes.c
drivers/video/macmodes.h
drivers/video/offb.c
drivers/video/platinumfb.c [new file with mode: 0644]
drivers/video/platinumfb.h [new file with mode: 0644]
drivers/video/prom.uni [new file with mode: 0644]
drivers/video/promcon.c
drivers/video/retz3fb.c
drivers/video/sbusfb.c
drivers/video/sbusfb.h
drivers/video/skeletonfb.c
drivers/video/tcxfb.c [new file with mode: 0644]
drivers/video/tgafb.c
drivers/video/vesafb.c
drivers/video/vfb.c
drivers/video/vgacon.c
drivers/video/virgefb.c
fs/ufs/truncate.c
include/linux/console_struct.h
include/linux/consolemap.h
include/linux/fb.h
include/linux/in6.h
include/linux/kd.h
include/linux/proc_fs.h
include/linux/selection.h
include/linux/simp.h [deleted file]
include/linux/skbuff.h
include/linux/socket.h
include/linux/vt_kern.h
include/net/ip6_route.h
include/net/ipv6.h
include/net/sock.h
include/net/x25.h
mm/memory.c
mm/mmap.c
mm/simp.c [deleted file]
net/Makefile
net/ax25/af_ax25.c
net/core/skbuff.c
net/core/sock.c
net/econet/econet.c
net/ipv4/arp.c
net/ipv4/fib_hash.c
net/ipv4/icmp.c
net/ipv4/ip_fragment.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/ipconfig.c
net/ipv4/rarp.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv6/addrconf.c
net/ipv6/ip6_input.c
net/ipv6/ip6_output.c
net/ipv6/ipv6_sockglue.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/udp.c
net/netlink/af_netlink.c
net/netsyms.c
net/packet/af_packet.c
net/x25/af_x25.c
net/x25/x25_dev.c
net/x25/x25_facilities.c
net/x25/x25_in.c
net/x25/x25_link.c

index 615a866e6a45b49f26e201fa80cbd360f46da41a..0435f52d2ae87445a2d9326ef5945d3574045d61 100644 (file)
@@ -5983,18 +5983,6 @@ CONFIG_ISP16_CDI
   The module will be called isp16.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-Preload dcache
-CONFIG_DCACHE_PRELOAD
-  Preloading will create dcache entries when a directory is scanned
-  (e.g. because the ls command was used) for the *first* time. This
-  should speed up successive lookups of information about files in
-  that directory, but can also consume large amounts of memory.
-
-  Please report speedups (or slowdowns due to the memory usage if they
-  occur) to schoebel@informatik.uni-stuttgart.de .
-
-  If unsure, say N.
-
 Quota support
 CONFIG_QUOTA
   If you say Y here, you will be able to set per user limits for disk
@@ -6005,173 +5993,6 @@ CONFIG_QUOTA
   ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini. Probably the quota
   support is only useful for multi user systems. If unsure, say N.
 
-Online mirror support
-CONFIG_OMIRR
-  omirr is a package for _symmetric_ mirroring of files over the
-  Internet. In contrast to rdist, the online mirror daemon (omirrd) is
-  running all the time and transfers any changes on the file system as
-  soon as possible to all other servers. Symmetric means that all
-  servers have equal rights in changing a file: the last changer of a
-  file will win. This is the same behaviour as multiple processes
-  operating on a global file system. In effect, omirr can do the same
-  as NFS mounts, but will have better performance since the data is
-  stored on local disks. In contrast to a cache filesystem which has a
-  dedicated master copy, broken connections and/or servers are no
-  problem for continuing work on the remaining ones, because there is
-  no master copy. Every computer that wants to participate in the
-  mirroring needs to run the daemon omirrd, contained in the omirr
-  package which is available via FTP (user: anonymous) from
-  ftp://ftp.isa.de/pub/home/luik. You must say Y if you want to use
-  in.omirrd, but you should (but need not) say N if you don't (for
-  performance reasons).
-
-  Note that this is experimental code; use at your own risk.
-
-Filename translation support
-CONFIG_TRANS_NAMES
-  This is a useful feature if you have a pool of diskless Linux
-  clients which mount their root filesystems from a central
-  server. Depending on their hostnames, the clients can then see
-  different versions of certain files, which keeps maintenance at a
-  minimum when used for configuration files. The kernel running on the
-  clients should have this option enabled. If you don't administer a
-  pool of Linux clients, say N here, otherwise read on:
-
-  When you say Y here, filenames, directory names etc become
-  context-sensitive.  If you have a file named
-  "/etc/config#host=banana#", it will appear (by default) as
-  hardlinked to "/etc/config" on host "banana", while on host "mango"
-  another file "/etc/config#host=mango#" will appear as having been
-  hardlinked to "/etc/config".
-  This default behaviour can be changed by setting the _first_
-  environment variable NAMETRANS to a colon-separated list of suffixes
-  which are tried in the specified order. For example, in 
-  'env - NAMETRANS=#host=mango#:#ktype=diskless# "`env`" command ...'
-   
-  the command will see the same files as if it had been executed on
-  host "mango" with a diskless kernel.
-
-  Using NAMETRANS supersedes _all_ default translations. Thus
-  translations can be completely switched off with an empty list,
-  e.g. 
-
-  'env - NAMETRANS= "`env`" command ...'  
-
-  Note that some system utilities like tar, dump, restore should be
-  used with translation switched off, in order to avoid doubled space
-  in archive files and when extracting from them. Also, make sure that
-  nfsd, mountd (and similar ones like samba daemons) run without
-  translation, in order to avoid doubled (or even wrong) translation
-  at the server and at the client.
-
-  You can automatically force the creation of context-dependent
-  filenames if there exists a template filename like
-  "/etc/mtab#host=CREATE#". As soon as a process running on "mango"
-  tries to create a file "/etc/mtab", the version
-  "/etc/mtab#host=mango#" is created instead (which appears in turn as
-  hardlinked to "/etc/mtab").  Note that if you want to make
-  "/etc/fstab" context-dependent, you should execute "touch
-  /etc/mtab#host=CREATE#" and "touch /etc/mtab.tmp#host=CREATE#",
-  because mount, umount and others running on different hosts would
-  otherwise try to create one shared /etc/mtab which would result in a
-  clash. Also one should execute "touch /etc/nologin#host=CREATE#" to
-  prevent global side effects from shutdown resp. runlevel.
-
-  Please read Documentation/transname.txt if you intend to say Y here.
-
-Restrict translation to gid
-CONFIG_TRANS_RESTRICT
-  If you say Y here, default filename translations are carried out
-  only if the parent directory of the context-sensitive file belongs
-  to a specific group id (gid). Trying to translate names everywhere
-  will decrease performance of file openings. Normally translations
-  are used only in system configuration files but not in ordinary user
-  file space. So you should change the gid of directories containing
-  context-dependent files to some special group like "adm" (group id
-  4) and enable this option. As a result, users will not notice any
-  performance degradation resulting from filename translation.
-
-  Note that translations resulting from the first environment variable
-  "NAMETRANS=..." are always carried out regardless of the gid of
-  directories.
-
-  Beware: before turning on this option make sure that all directories
-  containing context-dependent files belong to the special group, or
-  system initialization may fail. If unsure, select N.
-
-Group id (gid) for translation restriction
-CONFIG_TRANS_GID
-  Default name translations will be carried out only inside directories
-  belonging to the group id (gid) that you specify here.
-  Default is 4 (group "adm").
-
-Nodename (hostname) translation
-CONFIG_TR_NODENAME
-  Enables translation of name suffixes like in
-  "/etc/config#host=banana#".  The syntax is
-  <filename>#host=<hostname>#. The hostname can be queried with the
-  command "uname -n". Normally this option is used heavily when
-  translation is enabled. If unsure, say Y.
-
-Kernelname translation
-CONFIG_TR_KERNNAME
-  Enables translation of name suffixes like in
-  "/etc/config#kname=default#".  The string is hard compiled into the
-  kernel by the following option.  Useful if your kernel does not know
-  the hostname at boot time, and there is no way to tell the hostname
-  by lilo or bootp. Please avoid using this option and prefer
-  "Nodename (hostname) translation" (CONFIG_TR_NODENAME) wherever
-  possible. When mounting the root over NFS, the own hostname must be
-  known at boot time anyway; this option is just for special use.
-  Note that the default translations are tried in the order as
-  occurring in the configuration, that is 1) host 2) kname 3) ktype 4)
-  machine 5) system. If unsure, say Y.
-
-String for kernelname translation
-CONFIG_KERNNAME
-  Enter the string you want to compile into the kernel. The string
-  will be used as context in context-dependent files like
-  "/etc/config#kname=<string>#".
-
-Kerneltype translation
-CONFIG_TR_KERNTYPE
-  Enables translation of name suffixes like in
-  "/etc/config#ktype=default#".  The syntax is
-  <filename>#ktype=<string>#. The string is hard compiled in the
-  kernel by the following option. Use if you want to create different
-  kernels with different behaviour. For example, use the string
-  "default" on your server, and use "diskless" on all your diskless
-  clients (and perhaps "dataless" on dataless clients). This way you
-  can avoid dozens of "config#host=<something># with same contents and
-  you have no effort when new machines are added. If unsure, say Y.
-
-String for kerneltype translation
-CONFIG_KERNTYPE
-  Enter the string you want to compile into the kernel. The string
-  will be used as context in context-dependent files like
-  "/etc/config#ktype=default#". If your kernel is to be used on a
-  server, you probably can use "default" here. If your kernel is
-  intended for a diskless client, you probably should enter "diskless"
-  here.
-
-Machine type translation
-CONFIG_TR_MACHINE
-  Enables translation of name suffixes like in
-  "/etc/config#machine=i486#".  The syntax is
-  <filename>#machine=<id>#. The machine types can be queried with the
-  command "uname -m". Normally used only on multi-architecture
-  installations. If unsure, say Y.
-
-System name translation
-CONFIG_TR_SYSNAME
-  Enables translation of name suffixes like in
-  "/etc/config#system=Linux#".  The syntax is
-  <filename>#system=<id>#. The system name can be queried with the
-  command "uname -s". Currently only supported by Linux, but hopefully
-  other operating systems will pick up the idea of context-dependent
-  translations. If unsure, say Y.
-
 Minix fs support
 CONFIG_MINIX_FS
   Minix is a simple operating system used in many classes about
index c29f8a85c84b23ea824fb6e58eabd912c5ba3c3c..05e1137b0be4352fd3d8eb5e93e5523e406bff1d 100644 (file)
@@ -310,6 +310,12 @@ M: Paul.Russell@rustcorp.com.au
 W:     http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html
 S:     Maintained
 
+IP FIREWALL
+P:     Paul Russell
+M:     Paul.Russell@rustcorp.com.au
+W:     http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html
+S:     Maintained
+
 IPX/SPX NETWORK LAYER
 P:     Jay Schulist
 M:     Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
@@ -325,6 +331,7 @@ S:  Maintained
 JOYSTICK DRIVER
 P:     Vojtech Pavlik
 M:     vojtech@atrey.karlin.mff.cuni.cz
+W:     http://atrey.karlin.mff.cuni.cz/~vojtech/joystick/
 L:     linux-joystick@atrey.karlin.mff.cuni.cz
 S:     Maintained
 
@@ -563,6 +570,12 @@ M: Jay.Schulist@spacs.k12.wi.us
 L:     linux-net@vger.rutgers.edu
 S:     Supported
 
+SPX NETWORK LAYER
+P:     Jay Schulist
+M:     Jay.Schulist@spacs.k12.wi.us
+L:     linux-net@vger.rutgers.edu
+S:     Supported
+
 STALLION TECHNOLOGIES MULTIPORT SERIAL BOARDS
 P:     Greg Ungerer
 M:     support@stallion.oz.au
index 31b3c0e6773a5047fc0874d9cbfffa73487cbd01..101cd1d37794f65791ed188fcb201ed462995ffa 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -340,7 +340,8 @@ clean:      archclean
        rm -f core `find . -name '.*.flags' -print`
        rm -f vmlinux System.map
        rm -f .tmp*
-       rm -f drivers/char/consolemap_deftbl.c drivers/char/conmakehash
+       rm -f drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c
+       rm -f drivers/char/conmakehash
        rm -f drivers/sound/bin2hex drivers/sound/hex2hex
        if [ -d modules ]; then \
                rm -f core `find modules/ -type f -print`; \
index b8a05d049a5935acf3445223a5c9b5327a2fd3b7..7e160f17e38fccefd2dcab13bdfb02c31a5f5852 100644 (file)
@@ -966,21 +966,6 @@ static void disable_level_ioapic_irq(unsigned int irq)
        mask_IO_APIC_irq(irq);
 }
 
-/*
- * Enter and exit the irq handler context..
- */
-static inline void enter_ioapic_irq(int cpu)
-{
-       hardirq_enter(cpu);
-       while (test_bit(0,&global_irq_lock)) barrier();
-}
-
-static inline void exit_ioapic_irq(int cpu)
-{
-       hardirq_exit(cpu);
-       release_irqlock(cpu);
-}      
-
 static void do_edge_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs)
 {
        irq_desc_t *desc = irq_desc + irq;
@@ -1014,7 +999,7 @@ static void do_edge_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs)
        if (!action)
                return;
 
-       enter_ioapic_irq(cpu);
+       irq_enter(cpu, irq);
 
        /*
         * Edge triggered interrupts need to remember
@@ -1035,7 +1020,7 @@ static void do_edge_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs)
        desc->status &= IRQ_DISABLED;
        spin_unlock(&irq_controller_lock);
 
-       exit_ioapic_irq(cpu);
+       irq_exit(cpu, irq);
 }
 
 static void do_level_ioapic_IRQ (unsigned int irq, int cpu,
@@ -1074,7 +1059,7 @@ static void do_level_ioapic_IRQ (unsigned int irq, int cpu,
        if (!action)
                return;
 
-       enter_ioapic_irq(cpu);
+       irq_enter(cpu, irq);
 
        handle_IRQ_event(irq, regs);
 
@@ -1084,7 +1069,7 @@ static void do_level_ioapic_IRQ (unsigned int irq, int cpu,
                unmask_IO_APIC_irq(irq);
        spin_unlock(&irq_controller_lock);
 
-       exit_ioapic_irq(cpu);
+       irq_exit(cpu, irq);
 }
 
 /*
index b3fd2bdc574c26fe87cb0fbc8d1c322401c8d0f4..740f4551fbbb9616f0bdb651ff509e31f7c05f08 100644 (file)
@@ -90,13 +90,34 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
        void * addr;
        struct vm_struct * area;
 
-       if (phys_addr < virt_to_phys(high_memory))
+       /*
+        * Don't remap the low PCI/ISA area, it's always mapped..
+        */
+       if (phys_addr >= 0xA0000 && (phys_addr+size) <= 0x100000)
                return phys_to_virt(phys_addr);
+
+       /*
+        * Don't allow anybody to remap normal RAM that we're using..
+        */
+       if (phys_addr < virt_to_phys(high_memory))
+               return NULL;
+
+       /*
+        * Mappings have to be page-aligned
+        */
        if (phys_addr & ~PAGE_MASK)
                return NULL;
        size = PAGE_ALIGN(size);
+
+       /*
+        * Don't allow mappings that wrap..
+        */
        if (!size || size > phys_addr + size)
                return NULL;
+
+       /*
+        * Ok, go for it..
+        */
        area = get_vm_area(size);
        if (!area)
                return NULL;
index ee61b3a0052767e6f0566d0f3a3403bb61a627b1..e4b861d1db31f74cd3c4e36059124132e8e6e41d 100644 (file)
@@ -188,7 +188,7 @@ static inline unsigned short *screenpos(int currcons, int offset, int viewed)
        return p;
 }
 
-static inline void scrolldelta(int lines)
+static void scrolldelta(int lines)
 {
        int currcons = fg_console;
 
@@ -314,6 +314,8 @@ static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _unde
                a ^= 0x80;
        if (_intensity == 2)
                a ^= 0x08;
+       if (hi_font_mask == 0x100)
+               a <<= 1;
        return a;
        }
 #else
@@ -339,17 +341,23 @@ void invert_screen(int currcons, int offset, int count, int viewed)
                sw->con_invert_region(vc_cons[currcons].d, p, count);
 #ifndef VT_BUF_VRAM_ONLY
        else {
-               int col = can_do_color;
                u16 *q = p;
                int cnt = count;
 
-               while (cnt--) {
-                       u16 a = *q;
-                       if (col)
+               if (!can_do_color) {
+                       while (cnt--) *q++ ^= 0x0800;
+               } else if (hi_font_mask == 0x100) {
+                       while (cnt--) {
+                               u16 a = *q;
+                               a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
+                               *q++ = a;
+                       }
+               } else {
+                       while (cnt--) {
+                               u16 a = *q;
                                a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
-                       else
-                               a ^= 0x0800;
-                       *q++ = a;
+                               *q++ = a;
+                       }
                }
        }
 #endif
@@ -436,9 +444,9 @@ static void add_softcursor(int currcons)
        int i = scr_readw((u16 *) pos);
        u32 type = cursor_type;
 
+       if (! (type & 0x10)) return;
        if (softcursor_original != -1) return;
        softcursor_original = i;
-       if (! (type & 0x10)) return;
        i |= ((type >> 8) & 0xff00 );
        i ^= ((type) & 0xff00 );
        if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
@@ -450,6 +458,8 @@ static void add_softcursor(int currcons)
 
 static void hide_cursor(int currcons)
 {
+       if (currcons == sel_cons)
+               clear_selection();
        if (softcursor_original != -1) {
                scr_writew(softcursor_original,(u16 *) pos);
                if (DO_UPDATE)
@@ -464,6 +474,8 @@ void set_cursor(int currcons)
     if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS)
        return;
     if (deccm) {
+       if (currcons == sel_cons)
+               clear_selection();
        add_softcursor(currcons);
        if ((cursor_type & 0x0f) != 1)
            sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
@@ -510,8 +522,6 @@ void update_screen(int new_console)
        }
        lock = 1;
 
-       clear_selection();
-
        hide_cursor(currcons);
        if (fg_console != new_console) {
                display = vc_cons[new_console].d->vc_display_fg;
@@ -552,6 +562,8 @@ void visual_init(int currcons)
     sw = conswitchp;
     cons_num = currcons;
     display_fg = &master_display_fg;
+    vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir;
+    vc_cons[currcons].d->vc_uni_pagedir = 0;
     hi_font_mask = 0;
     complement_mask = 0;
     sw->con_init(vc_cons[currcons].d, 1);
@@ -591,6 +603,7 @@ int vc_allocate(unsigned int currcons, int init)    /* return 0 on success */
                vt_cons[currcons] = NULL;
                return -ENOMEM;
            }
+           con_set_default_unimap(currcons);
            screenbuf = (unsigned short *) q;
            kmalloced = 1;
            screenbuf_size = video_screen_size;
@@ -1667,14 +1680,10 @@ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
                        /* DEC screen alignment test. kludge :-) */
                        video_erase_char =
                                (video_erase_char & 0xff00) | 'E';
-                       /* Arno:
-                        * Doesn't work, because csi_J(c,2)
-                        * calls con_clear and doesn't print
-                        * the erase char..     FIXME
-                        */
                        csi_J(currcons, 2);
                        video_erase_char =
                                (video_erase_char & 0xff00) | ' ';
+                       do_update_region(currcons, origin, screenbuf_size/2);
                }
                return;
        case ESsetG0:
@@ -1755,10 +1764,6 @@ static int do_con_write(struct tty_struct * tty, int from_user,
        if (IS_FG)
                hide_cursor(currcons);
 
-       /* clear the selection */
-       if (currcons == sel_cons)
-               clear_selection();
-
        disable_bh(CONSOLE_BH);
        while (!tty->stopped && count) {
                enable_bh(CONSOLE_BH);
@@ -1825,11 +1830,11 @@ static int do_con_write(struct tty_struct * tty, int from_user,
 
                if (vc_state == ESnormal && ok) {
                        /* Now try to find out how to display it */
-                       tc = conv_uni_to_pc(tc);
+                       tc = conv_uni_to_pc(vc_cons[currcons].d, tc);
                        if ( tc == -4 ) {
                                 /* If we got -4 (not found) then see if we have
                                    defined a replacement character (U+FFFD) */
-                                tc = conv_uni_to_pc(0xfffd);
+                                tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd);
 
                                /* One reason for the -4 can be that we just
                                   did a clear_unimap();
@@ -1889,8 +1894,7 @@ static int do_con_write(struct tty_struct * tty, int from_user,
 static void console_bh(void)
 {
        if (want_console >= 0) {
-               if (want_console != fg_console) {
-                       clear_selection();
+               if (want_console != fg_console && vc_cons_allocated(want_console)) {
                        hide_cursor(fg_console);
                        save_screen();
                        change_console(want_console);
@@ -2401,8 +2405,8 @@ void do_blank_screen(int nopowersave)
 
        /* entering graphics mode? */
        if (nopowersave) {
-               save_screen();
                hide_cursor(currcons);
+               save_screen();
                sw->con_blank(vc_cons[currcons].d, -1);
                console_blanked = fg_console + 1;
                set_origin(currcons);
@@ -2460,6 +2464,9 @@ void do_unblank_screen(void)
 
        currcons = fg_console;
        console_blanked = 0;
+#ifdef CONFIG_APM
+       apm_display_unblank();
+#endif
        if (sw->con_blank(vc_cons[currcons].d, 0))
                /* Low-level driver cannot restore -> do it ourselves */
                update_screen(fg_console);
@@ -2567,24 +2574,31 @@ void reset_palette (int currcons)
  *  /Jes
  */
 
-#define max_font_size 32768
+#define max_font_size 65536
 
 int con_font_op(int currcons, struct console_font_op *op)
 {
        int rc = -EINVAL;
-       int size, set;
-       u8 *temp;
+       int size = max_font_size, set;
+       u8 *temp = NULL;
        struct console_font_op old_op;
 
        if (vt_cons[currcons]->vc_mode != KD_TEXT)
                goto quit;
-       memcpy(&old_op, &op, sizeof(op));
+       memcpy(&old_op, op, sizeof(old_op));
        if (op->op == KD_FONT_OP_SET) {
+               if (!op->data)
+                       return -EINVAL;
                if (op->charcount > 512)
                        goto quit;
                if (!op->height) {              /* Need to guess font height [compat] */
                        int h, i;
                        u8 *charmap = op->data, tmp;
+                       
+                       /* If from KDFONTOP ioctl, don't allow things which can be done in userland,
+                          so that we can get rid of this soon */
+                       if (op->flags & KD_FONT_FLAG_NEW)
+                               goto quit;
                        rc = -EFAULT;
                        for (h = 32; h > 0; h--)
                                for (i = 0; i < op->charcount; i++) {
@@ -2605,32 +2619,44 @@ int con_font_op(int currcons, struct console_font_op *op)
                if (size > max_font_size)
                        return -ENOSPC;
                set = 1;
-       } else if (op->op == KD_FONT_OP_GET) {
-               size = max_font_size;
+       } else if (op->op == KD_FONT_OP_GET)
                set = 0;
-       else
+       else
                return sw->con_font_op(vc_cons[currcons].d, op);
-       temp = kmalloc(size, GFP_KERNEL);
-       if (!temp)
-               return -ENOMEM;
-       if (set && copy_from_user(temp, op->data, size)) {
-               rc = -EFAULT;
-               goto quit2;
+       if (op->data) {
+               temp = kmalloc(size, GFP_KERNEL);
+               if (!temp)
+                       return -ENOMEM;
+               if (set && copy_from_user(temp, op->data, size)) {
+                       rc = -EFAULT;
+                       goto quit;
+               }
+               op->data = temp;
        }
-       op->data = temp;
        rc = sw->con_font_op(vc_cons[currcons].d, op);
        op->data = old_op.data;
        if (!rc && !set) {
                int c = (op->width+7)/8 * 32 * op->charcount;
-               if (op->width > old_op.width ||
-                   op->height > old_op.height ||
-                   op->charcount > old_op.charcount)
+               
+               if (op->data && op->charcount > old_op.charcount)
                        rc = -ENOSPC;
-               else if (copy_to_user(old_op.data, op->data, c))
+               if (op->flags & KD_FONT_FLAG_NEW) {
+                       if (op->width > old_op.width || 
+                           op->height > old_op.height)
+                               rc = -ENOSPC;
+               } else {
+                       if (op->width != 8)
+                               rc = -EIO;
+                       else if ((old_op.height && op->height > old_op.height) ||
+                                op->height > 32)
+                               rc = -ENOSPC;
+               }
+               if (!rc && op->data && copy_to_user(op->data, temp, c))
                        rc = -EFAULT;
        }
-quit2: kfree_s(temp, size);
-quit:  return rc;
+quit:  if (temp)
+               kfree_s(temp, size);
+       return rc;
 }
 
 /*
@@ -2666,6 +2692,22 @@ void putconsxy(int currcons, char *p)
        set_cursor(currcons);
 }
 
+u16 vcs_scr_readw(int currcons, u16 *org)
+{
+       if (org == pos && softcursor_original != -1)
+               return softcursor_original;
+       return scr_readw(org);
+}
+
+void vcs_scr_writew(int currcons, u16 val, u16 *org)
+{
+       scr_writew(val, org);
+       if (org == pos) {
+               softcursor_original = -1;
+               add_softcursor(currcons);
+       }
+}
+
 
 /*
  *     Visible symbols for modules
index 5a9300bf8c10772ee433ae4b4ce7aac7f05a7682..e63386d7c0612217f48bec68e394c4fa4ef36f8c 100644 (file)
@@ -5,6 +5,8 @@
  * to font positions.
  *
  * aeb, 950210
+ *
+ * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998
  */
 
 #include <linux/kd.h>
@@ -14,6 +16,8 @@
 #include <linux/init.h>
 #include <asm/uaccess.h>
 #include <linux/consolemap.h>
+#include <linux/console_struct.h>
+#include <linux/vt_kern.h>
 
 static unsigned short translations[][256] = {
   /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
@@ -163,29 +167,36 @@ static unsigned short translations[][256] = {
 
 #define MAX_GLYPH 512          /* Max possible glyph value */
 
-static unsigned char * inv_translate = NULL;
-static unsigned char inv_norm_transl[MAX_GLYPH];
-static unsigned char * inverse_translations[4] = { NULL, NULL, NULL, NULL };
+static int inv_translate;
+
+struct uni_pagedir {
+       u16             **uni_pgdir[32];
+       unsigned long   refcount;
+       unsigned long   sum;
+       unsigned char   *inverse_translations[4];
+       int             readonly;
+};
 
-static void set_inverse_transl(int i)
+static struct uni_pagedir *dflt;
+
+static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i)
 {
        int j, glyph;
-       unsigned short *p = translations[i];
-       unsigned char *q = inverse_translations[i];
+       unsigned short *t = translations[i];
+       unsigned char *q;
+       
+       if (!p) return;
+       q = p->inverse_translations[i];
 
        if (!q) {
-               /* slightly messy to avoid calling kmalloc too early */
-               q = inverse_translations[i] = ((i == LAT1_MAP)
-                       ? inv_norm_transl
-                       : (unsigned char *) kmalloc(MAX_GLYPH, GFP_KERNEL));
-               if (!q)
-                       return;
+               q = p->inverse_translations[i] = (unsigned char *) 
+                       kmalloc(MAX_GLYPH, GFP_KERNEL);
+               if (!q) return;
        }
-       for (j=0; j<MAX_GLYPH; j++)
-               q[j] = 0;
+       memset(q, 0, MAX_GLYPH);
 
-       for (j=0; j<E_TABSZ; j++) {
-               glyph = conv_uni_to_pc(p[j]);
+       for (j = 0; j < E_TABSZ; j++) {
+               glyph = conv_uni_to_pc(conp, t[j]);
                if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) {
                        /* prefer '-' above SHY etc. */
                        q[glyph] = j;
@@ -195,9 +206,7 @@ static void set_inverse_transl(int i)
 
 unsigned short *set_translate(int m)
 {
-       if (!inverse_translations[m])
-               set_inverse_transl(m);
-       inv_translate = inverse_translations[m];
+       inv_translate = m;
        return translations[m];
 }
 
@@ -208,13 +217,33 @@ unsigned short *set_translate(int m)
  *    was active, or using Unicode.
  * Still, it is now possible to a certain extent to cut and paste non-ASCII.
  */
-unsigned char inverse_translate(int glyph) {
-       if ( glyph < 0 || glyph >= MAX_GLYPH )
+unsigned char inverse_translate(struct vc_data *conp, int glyph)
+{
+       struct uni_pagedir *p;
+       
+       if (glyph < 0 || glyph >= MAX_GLYPH)
                return 0;
+       else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc) ||
+                !p->inverse_translations[inv_translate])
+               return glyph;
        else
-               return ((inv_translate && inv_translate[glyph])
-                       ? inv_translate[glyph]
-                       : (unsigned char)(glyph & 0xff));
+               return p->inverse_translations[inv_translate][glyph];
+}
+
+static void update_user_maps(void)
+{
+       int i;
+       struct uni_pagedir *p, *q = NULL;
+       
+       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               if (!vc_cons_allocated(i))
+                       continue;
+               p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+               if (p && p != q) {
+                       set_inverse_transl(vc_cons[i].d, p, USER_MAP);
+                       q = p;
+               }
+       }
 }
 
 /*
@@ -240,7 +269,7 @@ int con_set_trans_old(unsigned char * arg)
                p[i] = UNI_DIRECT_BASE | uc;
        }
 
-       set_inverse_transl(USER_MAP);
+       update_user_maps();
        return 0;
 }
 
@@ -255,7 +284,7 @@ int con_get_trans_old(unsigned char * arg)
 
        for (i=0; i<E_TABSZ ; i++)
          {
-           ch = conv_uni_to_pc(p[i]);
+           ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
            __put_user((ch & ~0xff) ? 0 : ch, arg+i);
          }
        return 0;
@@ -277,7 +306,7 @@ int con_set_trans_new(ushort * arg)
                p[i] = us;
        }
 
-       set_inverse_transl(USER_MAP);
+       update_user_maps();
        return 0;
 }
 
@@ -310,90 +339,188 @@ int con_get_trans_new(ushort * arg)
 extern u8 dfont_unicount[];    /* Defined in console_defmap.c */
 extern u16 dfont_unitable[];
 
-int hashtable_contents_valid = 0; /* Use ASCII-only mode for bootup */
+static void con_release_unimap(struct uni_pagedir *p)
+{
+       u16 **p1;
+       int i, j;
+
+       if (p == dflt) dflt = NULL;  
+       for (i = 0; i < 32; i++) {
+               if ((p1 = p->uni_pgdir[i]) != NULL) {
+                       for (j = 0; j < 32; j++)
+                               if (p1[j])
+                                       kfree(p1[j]);
+                       kfree(p1);
+               }
+               p->uni_pgdir[i] = NULL;
+       }
+       for (i = 0; i < 4; i++)
+               if (p->inverse_translations[i]) {
+                       kfree(p->inverse_translations[i]);
+                       p->inverse_translations[i] = NULL;
+               }
+}
 
-static u16 **uni_pagedir[32] =
+void con_free_unimap(int con)
 {
-  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
-};
+       struct uni_pagedir *p;
+       struct vc_data *conp = vc_cons[con].d;
+       
+       p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+       if (!p) return;
+       *conp->vc_uni_pagedir_loc = 0;
+       if (--p->refcount) return;
+       con_release_unimap(p);
+       kfree(p);
+}
+  
+static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
+{
+       int i, j, k;
+       struct uni_pagedir *q;
+       
+       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               if (!vc_cons_allocated(i))
+                       continue;
+               q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+               if (!q || q == p || q->sum != p->sum)
+                       continue;
+               for (j = 0; j < 32; j++) {
+                       u16 **p1, **q1;
+                       p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
+                       if (!p1 && !q1)
+                               continue;
+                       if (!p1 || !q1)
+                               break;
+                       for (k = 0; k < 32; k++) {
+                               if (!p1[k] && !q1[k])
+                                       continue;
+                               if (!p1[k] || !q1[k])
+                                       break;
+                               if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
+                                       break;
+                       }
+                       if (k < 32)
+                               break;
+               }
+               if (j == 32) {
+                       q->refcount++;
+                       *conp->vc_uni_pagedir_loc = (unsigned long)q;
+                       con_release_unimap(p);
+                       kfree(p);
+                       return 1;
+               }
+       }
+       return 0;
+}
 
 static int
-con_insert_unipair(u_short unicode, u_short fontpos)
+con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
 {
-  int i, n;
-  u16 **p1, *p2;
-
-  if ( !(p1 = uni_pagedir[n = unicode >> 11]) )
-    {
-      p1 = uni_pagedir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
-      if ( !p1 )
-       return -ENOMEM;
-
-      for ( i = 0 ; i < 32 ; i++ )
-       p1[i] = NULL;
-    }
-
-  if ( !(p2 = p1[n = (unicode >> 6) & 0x1f]) )
-    {
-      p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
-      if ( !p2 )
-       return -ENOMEM;
-
-      for ( i = 0 ; i < 64 ; i++ )
-       p2[i] = 0xffff;         /* No glyph for this character (yet) */
-    }
-
-  p2[unicode & 0x3f] = fontpos;
-  
-  return 0;
+       int i, n;
+       u16 **p1, *p2;
+
+       if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
+               p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
+               if (!p1) return -ENOMEM;
+               for (i = 0; i < 32; i++)
+                       p1[i] = NULL;
+       }
+
+       if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
+               p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
+               if (!p2) return -ENOMEM;
+               memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
+       }
+
+       p2[unicode & 0x3f] = fontpos;
+       
+       p->sum += (fontpos << 20) + unicode;
+
+       return 0;
 }
-  
+
 /* ui is a leftover from using a hashtable, but might be used again */
-void
-con_clear_unimap(struct unimapinit *ui)
+int con_clear_unimap(int con, struct unimapinit *ui)
 {
-  int i, j;
-  u16 **p1;
+       struct uni_pagedir *p, *q;
+       struct vc_data *conp = vc_cons[con].d;
   
-  for ( i = 0 ; i < 32 ; i++ )
-    {
-      if ( (p1 = uni_pagedir[i]) != NULL )
-       {
-         for ( j = 0 ; j < 32 ; j++ )
-           {
-             if ( p1[j] )
-               kfree(p1[j]);
-           }
-         kfree(p1);
+       p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+       if (p && p->readonly) return -EIO;
+       if (!p || --p->refcount) {
+               q = (struct uni_pagedir *)kmalloc(sizeof(*p), GFP_KERNEL);
+               if (!q) {
+                       if (p) p->refcount++;
+                       return -ENOMEM;
+               }
+               memset(q, 0, sizeof(*q));
+               q->refcount=1;
+               *conp->vc_uni_pagedir_loc = (unsigned long)q;
+       } else {
+               if (p == dflt) dflt = NULL;
+               p->refcount++;
+               p->sum = 0;
+               con_release_unimap(p);
        }
-      uni_pagedir[i] = NULL;
-    }
-
-  hashtable_contents_valid = 1;
+       return 0;
 }
 
 int
-con_set_unimap(ushort ct, struct unipair *list)
+con_set_unimap(int con, ushort ct, struct unipair *list)
 {
-  int err = 0, err1, i;
-
-  while( ct-- )
-    {
-      unsigned short unicode, fontpos;
-      __get_user(unicode, &list->unicode);
-      __get_user(fontpos, &list->fontpos);
-      if ( (err1 = con_insert_unipair(unicode,fontpos)) != 0 )
-       err = err1;
-      list++;
-    }
-
-  for ( i = 0 ; i <= 3 ; i++ )
-    set_inverse_transl(i); /* Update all inverse translations */
+       int err = 0, err1, i;
+       struct uni_pagedir *p, *q;
+       struct vc_data *conp = vc_cons[con].d;
+
+       p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+       if (p->readonly) return -EIO;
+       
+       if (!ct) return 0;
+       
+       if (p->refcount > 1) {
+               int j, k;
+               u16 **p1, *p2, l;
+               
+               err1 = con_clear_unimap(con, NULL);
+               if (err1) return err1;
+               
+               q = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+               for (i = 0, l = 0; i < 32; i++)
+               if ((p1 = p->uni_pgdir[i]))
+                       for (j = 0; j < 32; j++)
+                       if ((p2 = p1[j]))
+                               for (k = 0; k < 64; k++, l++)
+                               if (p2[k] != 0xffff) {
+                                       err1 = con_insert_unipair(q, l, p2[k]);
+                                       if (err1) {
+                                               p->refcount++;
+                                               *conp->vc_uni_pagedir_loc = (unsigned long)p;
+                                               con_release_unimap(q);
+                                               kfree(q);
+                                               return err1; 
+                                       }
+                               }
+               p = q;
+       } else if (p == dflt)
+               dflt = NULL;
+       
+       while (ct--) {
+               unsigned short unicode, fontpos;
+               __get_user(unicode, &list->unicode);
+               __get_user(fontpos, &list->fontpos);
+               if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
+                       err = err1;
+                       list++;
+       }
+       
+       if (con_unify_unimap(conp, p))
+               return err;
+
+       for (i = 0; i <= 3; i++)
+               set_inverse_transl(conp, p, i); /* Update all inverse translations */
   
-  return err;
+       return err;
 }
 
 /* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
@@ -401,83 +528,123 @@ con_set_unimap(ushort ct, struct unipair *list)
    with.  This routine is executed at sys_setup time, and when the
    PIO_FONTRESET ioctl is called. */
 
-void
-con_set_default_unimap(void)
+int
+con_set_default_unimap(int con)
 {
-  int i, j;
-  u16 *p;
-
-  /* The default font is always 256 characters */
-
-  con_clear_unimap(NULL);
+       int i, j, err = 0, err1;
+       u16 *q;
+       struct uni_pagedir *p;
+       struct vc_data *conp = vc_cons[con].d;
+       
+       if (dflt) {
+               p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+               if (p == dflt)
+                       return 0;
+               dflt->refcount++;
+               *conp->vc_uni_pagedir_loc = (unsigned long)dflt;
+               if (p && --p->refcount) {
+                       con_release_unimap(p);
+                       kfree(p);
+               }
+               return 0;
+       }
+       
+       /* The default font is always 256 characters */
 
-  p = dfont_unitable;
-  for ( i = 0 ; i < 256 ; i++ )
-    for ( j = dfont_unicount[i] ; j ; j-- )
-      con_insert_unipair(*(p++), i);
+       err = con_clear_unimap(con,NULL);
+       if (err) return err;
+    
+       p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+       q = dfont_unitable;
+       
+       for (i = 0; i < 256; i++)
+               for (j = dfont_unicount[i]; j; j--) {
+                       err1 = con_insert_unipair(p, *(q++), i);
+                       if (err1)
+                               err = err1;
+               }
+                       
+       if (con_unify_unimap(conp, p)) {
+               dflt = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+               return err;
+       }
 
-  for ( i = 0 ; i <= 3 ; i++ )
-    set_inverse_transl(i);     /* Update all inverse translations */
+       for (i = 0; i <= 3; i++)
+               set_inverse_transl(conp, p, i); /* Update all inverse translations */
+       dflt = p;
+       return err;
 }
 
 int
-con_get_unimap(ushort ct, ushort *uct, struct unipair *list){
+con_get_unimap(int con, ushort ct, ushort *uct, struct unipair *list)
+{
        int i, j, k, ect;
        u16 **p1, *p2;
+       struct uni_pagedir *p;
+       struct vc_data *conp = vc_cons[con].d;
 
        ect = 0;
-       if (hashtable_contents_valid)
-         {
-           for ( i = 0 ; i < 32 ; i++ )
-             if ( (p1 = uni_pagedir[i]) != NULL )
-               for ( j = 0 ; j < 32 ; j++ )
-                 if ( (p2 = *(p1++)) != NULL )
-                   for ( k = 0 ; k < 64 ; k++ )
-                     {
-                       if ( *p2 < MAX_GLYPH && ect++ < ct )
-                         {
-                           __put_user((u_short)((i<<11)+(j<<6)+k),
-                                    &list->unicode);
-                           __put_user((u_short) *p2, &list->fontpos);
-                           list++;
-                         }
-                       p2++;
-                     }
-         }
+       if (*conp->vc_uni_pagedir_loc) {
+               p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+               for (i = 0; i < 32; i++)
+               if ((p1 = p->uni_pgdir[i]))
+                       for (j = 0; j < 32; j++)
+                       if ((p2 = *(p1++)))
+                               for (k = 0; k < 64; k++) {
+                                       if (*p2 < MAX_GLYPH && ect++ < ct) {
+                                               __put_user((u_short)((i<<11)+(j<<6)+k),
+                                                          &list->unicode);
+                                               __put_user((u_short) *p2, 
+                                                          &list->fontpos);
+                                               list++;
+                                       }
+                                       p2++;
+                               }
+       }
        __put_user(ect, uct);
        return ((ect <= ct) ? 0 : -ENOMEM);
 }
 
+void con_protect_unimap(int con, int rdonly)
+{
+       struct uni_pagedir *p = (struct uni_pagedir *)
+               *vc_cons[con].d->vc_uni_pagedir_loc;
+       
+       if (p) p->readonly = rdonly;
+}
+
 int
-conv_uni_to_pc(long ucs) 
+conv_uni_to_pc(struct vc_data *conp, long ucs) 
 {
-  int h;
-  u16 **p1, *p2;
-  
-  /* Only 16-bit codes supported at this time */
-  if (ucs > 0xffff)
-    ucs = 0xfffd;              /* U+FFFD: REPLACEMENT CHARACTER */
-  else if (ucs < 0x20 || ucs >= 0xfffe)
-    return -1;         /* Not a printable character */
-  else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
-    return -2;                 /* Zero-width space */
-  /*
-   * UNI_DIRECT_BASE indicates the start of the region in the User Zone
-   * which always has a 1:1 mapping to the currently loaded font.  The
-   * UNI_DIRECT_MASK indicates the bit span of the region.
-   */
-  else if ( (ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE )
-    return ucs & UNI_DIRECT_MASK;
+       int h;
+       u16 **p1, *p2;
+       struct uni_pagedir *p;
   
-  if (!hashtable_contents_valid)
-    return -3;
+       /* Only 16-bit codes supported at this time */
+       if (ucs > 0xffff)
+               ucs = 0xfffd;           /* U+FFFD: REPLACEMENT CHARACTER */
+       else if (ucs < 0x20 || ucs >= 0xfffe)
+               return -1;              /* Not a printable character */
+       else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
+               return -2;                      /* Zero-width space */
+       /*
+        * UNI_DIRECT_BASE indicates the start of the region in the User Zone
+        * which always has a 1:1 mapping to the currently loaded font.  The
+        * UNI_DIRECT_MASK indicates the bit span of the region.
+        */
+       else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
+               return ucs & UNI_DIRECT_MASK;
   
-  if ( (p1 = uni_pagedir[ucs >> 11]) &&
-      (p2 = p1[(ucs >> 6) & 0x1f]) &&
-      (h = p2[ucs & 0x3f]) < MAX_GLYPH )
-    return h;
+       if (!*conp->vc_uni_pagedir_loc)
+               return -3;
+
+       p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;  
+       if ((p1 = p->uni_pgdir[ucs >> 11]) &&
+           (p2 = p1[(ucs >> 6) & 0x1f]) &&
+           (h = p2[ucs & 0x3f]) < MAX_GLYPH)
+               return h;
 
-  return -4;           /* not found */
+       return -4;              /* not found */
 }
 
 /*
@@ -488,5 +655,9 @@ conv_uni_to_pc(long ucs)
 __initfunc(void
 console_map_init(void))
 {
-  con_set_default_unimap();
+       int i;
+       
+       for (i = 0; i < MAX_NR_CONSOLES; i++)
+               if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
+                       con_set_default_unimap(i);
 }
index 7179022aae0821f86b3bb4214c4b531053169627..eaa2c504070d3e7825d29f23c6ace190c156352d 100644 (file)
@@ -420,6 +420,9 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
 #elif defined(__sparc__)
        /* Should never get here, all fb drivers should have their own
           mmap routines */
+#elif defined(__i386__)
+       if (boot_cpu_data.x86 > 3)
+               pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
 #else
 #warning What do we have to do here??
 #endif
@@ -497,7 +500,7 @@ register_framebuffer(struct fb_info *fb_info)
 
        if (first) {
                first = 0;
-               take_over_console(&fb_con, 0, MAX_NR_CONSOLES-1, 1);
+               take_over_console(&fb_con, 12, MAX_NR_CONSOLES-1, 1);
        }
 
        return 0;
index b253bbad8fd7a235d521a8d51e785e758f98acdc..3910d0e30cd5299e041ab7527cf6e5ae0ae53600 100644 (file)
@@ -60,7 +60,7 @@ highlight_pointer(const int where) {
 static unsigned char
 sel_pos(int n)
 {
-       return inverse_translate(screen_glyph(sel_cons, n));
+       return inverse_translate(vc_cons[sel_cons].d, screen_glyph(sel_cons, n));
 }
 
 /* remove the current selection highlight, if any,
index 7e61082a98a522bc57d97f4786b2140888301da2..2c266dfe8bdf17209cf97f207c0c18d339b7746a 100644 (file)
@@ -7,7 +7,8 @@
  *            [minor: N]
  *
  * /dev/vcsaN: idem, but including attributes, and prefixed with
- *     the 4 bytes lines,columns,x,y (as screendump used to give)
+ *     the 4 bytes lines,columns,x,y (as screendump used to give).
+ *     Attribute/character pair is in native endianity.
  *            [minor: N+128]
  *
  * This replaces screendump and part of selection, so that the system
@@ -20,6 +21,8 @@
  *      - making it shorter - scr_readw are macros which expand in PRETTY long code
  */
 
+#include <linux/config.h>
+
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/errno.h>
 #undef addr
 #define HEADER_SIZE    4
 
-static unsigned short
-func_scr_readw(unsigned short *org)
-{
-return scr_readw( org );
-}
-
-static void
-func_scr_writew(unsigned short val, unsigned short *org)
-{
-scr_writew( val, org );
-}
-
 static int
 vcs_size(struct inode *inode)
 {
@@ -91,7 +82,7 @@ static long long vcs_lseek(struct file *file, long long offset, int orig)
        return file->f_pos;
 }
 
-#define RETURN( x ) { enable_bh( CONSOLE_BH ); return x; }
+#define RETURN(x) { enable_bh(CONSOLE_BH); return x; }
 static ssize_t
 vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 {
@@ -104,7 +95,7 @@ vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 
        attr = (currcons & 128);
        currcons = (currcons & 127);
-       disable_bh( CONSOLE_BH );
+       disable_bh(CONSOLE_BH);
        if (currcons == 0) {
                currcons = fg_console;
                viewed = 1;
@@ -125,7 +116,7 @@ vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
        if (!attr) {
                org = screen_pos(currcons, p, viewed);
                while (count-- > 0)
-                       put_user(func_scr_readw(org++) & 0xff, buf++);
+                       put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++);
        } else {
                if (p < HEADER_SIZE) {
                        char header[HEADER_SIZE];
@@ -140,21 +131,21 @@ vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
                    org = screen_pos(currcons, p/2, viewed);
                    if ((p & 1) && count > 0)
 #ifdef __BIG_ENDIAN
-                           { count--; put_user(func_scr_readw(org++) & 0xff, buf++); }
+                           { count--; put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++); }
 #else
-                           { count--; put_user(func_scr_readw(org++) >> 8, buf++); }
+                           { count--; put_user(vcs_scr_readw(currcons, org++) >> 8, buf++); }
 #endif
                }
                while (count > 1) {
-                       put_user(func_scr_readw(org++), (unsigned short *) buf);
+                       put_user(vcs_scr_readw(currcons, org++), (unsigned short *) buf);
                        buf += 2;
                        count -= 2;
                }
                if (count > 0)
 #ifdef __BIG_ENDIAN
-                       put_user(func_scr_readw(org) >> 8, buf++);
+                       put_user(vcs_scr_readw(currcons, org) >> 8, buf++);
 #else
-                       put_user(func_scr_readw(org) & 0xff, buf++);
+                       put_user(vcs_scr_readw(currcons, org) & 0xff, buf++);
 #endif
        }
        read = buf - buf0;
@@ -174,7 +165,7 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 
        attr = (currcons & 128);
        currcons = (currcons & 127);
-       disable_bh( CONSOLE_BH );
+       disable_bh(CONSOLE_BH);
        if (currcons == 0) {
                currcons = fg_console;
                viewed = 1;
@@ -198,7 +189,7 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
                        unsigned char c;
                        count--;
                        get_user(c, (const unsigned char*)buf++);
-                       func_scr_writew((func_scr_readw(org) & 0xff00) | c, org);
+                       vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org);
                        org++;
                }
        } else {
@@ -218,11 +209,11 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
                                count--;
                                get_user(c,buf++);
 #ifdef __BIG_ENDIAN
-                               func_scr_writew(c |
-                                    (func_scr_readw(org) & 0xff00), org);
+                               vcs_scr_writew(currcons, c |
+                                    (vcs_scr_readw(currcons, org) & 0xff00), org);
 #else
-                               func_scr_writew((c << 8) |
-                                    (func_scr_readw(org) & 0xff), org);
+                               vcs_scr_writew(currcons, (c << 8) |
+                                    (vcs_scr_readw(currcons, org) & 0xff), org);
 #endif
                                org++;
                        }
@@ -230,7 +221,7 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
                while (count > 1) {
                        unsigned short w;
                        get_user(w, (const unsigned short *) buf);
-                       func_scr_writew(w, org++);
+                       vcs_scr_writew(currcons, w, org++);
                        buf += 2;
                        count -= 2;
                }
@@ -238,9 +229,9 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
                        unsigned char c;
                        get_user(c, (const unsigned char*)buf++);
 #ifdef __BIG_ENDIAN
-                       func_scr_writew((func_scr_readw(org) & 0xff) | (c << 8), org);
+                       vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff) | (c << 8), org);
 #else
-                       func_scr_writew((func_scr_readw(org) & 0xff00) | c, org);
+                       vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org);
 #endif
                }
        }
index 992fa55ad34f9d5d68c4658b49e32bfa2776dde5..8b8ba87ec095e7ef6b1f618f23d1b542d35be586 100644 (file)
@@ -113,21 +113,18 @@ kd_size_changed(int row, int col)
 }
 
 /*
- * Generates sound of some count for some number of clock ticks
- * [count = 1193180 / frequency]
+ * Generates sound of some frequency for some number of clock ticks
  *
  * If freq is 0, will turn off sound, else will turn it on for that time.
  * If msec is 0, will return immediately, else will sleep for msec time, then
  * turn sound off.
  *
- * We use the BEEP_TIMER vector since we're using the same method to
- * generate sound, and we'll overwrite any beep in progress. That may
- * be something to fix later, if we like.
- *
  * We also return immediately, which is what was implied within the X
  * comments - KDMKTONE doesn't put the process to sleep.
  */
-/* FIXME: This should go to arch-dependent code */
+
+#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) || defined(__mips__)
+
 static void
 kd_nosound(unsigned long ignored)
 {
@@ -168,6 +165,15 @@ _kd_mksound(unsigned int hz, unsigned int ticks)
        return;
 }
 
+#else
+
+void
+_kd_mksound(unsigned int hz, unsigned int ticks)
+{
+}
+
+#endif
+
 void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound;
 
 
@@ -394,8 +400,6 @@ do_fontx_ioctl(int cmd, struct consolefontdesc *user_cfd, int perm)
                op.data = cfdarg.chardata;
                return con_font_op(fg_console, &op);
        case GIO_FONTX: {
-               if (!cfdarg.chardata)
-                       return 0;
                op.op = KD_FONT_OP_GET;
                op.flags = 0;
                op.width = 8;
@@ -432,9 +436,9 @@ do_unimap_ioctl(int cmd, struct unimapdesc *user_ud,int perm)
        case PIO_UNIMAP:
                if (!perm)
                        return -EPERM;
-               return con_set_unimap(tmp.entry_ct, tmp.entries);
+               return con_set_unimap(fg_console, tmp.entry_ct, tmp.entries);
        case GIO_UNIMAP:
-               return con_get_unimap(tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
+               return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
        }
        return 0;
 }
@@ -994,11 +998,11 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
 #else
                {
                struct console_font_op op;
-               op.op = KD_FONT_SET_DEFAULT;
+               op.op = KD_FONT_OP_SET_DEFAULT;
                op.data = NULL;
                i = con_font_op(fg_console, &op);
                if (i) return i;
-               con_set_default_unimap();
+               con_set_default_unimap(fg_console);
                return 0;
                }
 #endif
@@ -1010,6 +1014,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                        return -EFAULT;
                if (!perm && op.op != KD_FONT_OP_GET)
                        return -EPERM;
+               op.flags |= KD_FONT_FLAG_NEW;
                i = con_font_op(console, &op);
                if (i) return i;
                if (copy_to_user((void *) arg, &op, sizeof(op)))
@@ -1039,7 +1044,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                        return -EPERM;
                i = copy_from_user(&ui, (void *)arg, sizeof(struct unimapinit));
                if (i) return -EFAULT;
-               con_clear_unimap(&ui);
+               con_clear_unimap(fg_console, &ui);
                return 0;
              }
 
@@ -1189,10 +1194,6 @@ void complete_change_console(unsigned int new_console)
 {
        unsigned char old_vc_mode;
 
-        if ((new_console == fg_console) || (vt_dont_switch))
-                return;
-        if (!vc_cons_allocated(new_console))
-                return;
        last_console = fg_console;
 
        /*
index 7e097c8a41b616dbc7952e04d42673d3bab7e3a9..151920e335d26ebdf44ef72fda95252659b14a95 100644 (file)
@@ -182,6 +182,8 @@ static int autoprobe_read_proc (char *page, char **start, off_t off,
        int len = 0;
        const char *str;
 
+       page[0] = '\0';
+
        if ((str = pp->probe_info.class_name) != NULL)
                len += sprintf (page+len, "CLASS:%s;\n", str);
 
@@ -199,7 +201,7 @@ static int autoprobe_read_proc (char *page, char **start, off_t off,
 
        *start = 0;
        *eof   = 1;
-       return strlen (page);
+       return len;
 }
 
 static inline void destroy_proc_entry(struct proc_dir_entry *root, 
index 1bc7ed8afc11df596131544410855c587939419b..bbeab290c9f9c32f38f374c465fec6be054205e2 100644 (file)
@@ -451,6 +451,8 @@ el3_start_xmit(struct sk_buff *skb, struct device *dev)
                dev->tbusy = 0;
        }
 
+       lp->stats.tx_bytes += skb->len;
+       
        if (el3_debug > 4) {
                printk("%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
                           dev->name, skb->len, inw(ioaddr + EL3_STATUS));
@@ -667,6 +669,7 @@ el3_rx(struct device *dev)
                        struct sk_buff *skb;
 
                        skb = dev_alloc_skb(pkt_len+5);
+                       lp->stats.rx_bytes += pkt_len;
                        if (el3_debug > 4)
                                printk("Receiving packet size %d status %4.4x.\n",
                                           pkt_len, rx_status);
index 829811dfb75f90a8174b593bedf1f91cb0f56f27..0f3a9d44074b4466865cef39d71ebcc60756c2fe 100644 (file)
@@ -31,8 +31,14 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
       source drivers/acorn/net/Config.in
     fi
   fi
-  if [ "$CONFIG_PMAC" = "y" ]; then
-    bool 'MACE (Power Mac Ethernet) support' CONFIG_MACE
+  if [ "$CONFIG_PPC" = "y" ]; then
+    bool 'MACE (Power Mac ethernet) support' CONFIG_MACE
+    bool 'BMAC (G3 ethernet) support' CONFIG_BMAC
+  fi
+  if [ "$CONFIG_APUS" = "y" ]; then
+    tristate 'Ariadne support' CONFIG_ARIADNE
+    tristate 'A2065 support' CONFIG_A2065
+    tristate 'Hydra support' CONFIG_HYDRA
   fi
   if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then
     bool 'MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC
index 74888461b8df3110c3dcf12a5f924dd7de08e38f..1b8bf79ba522e11120811c69207ba1546163356c 100644 (file)
@@ -151,6 +151,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_ETHERH),y)
+CONFIG_8390_BUILTIN = y
+else
+  ifeq ($(CONFIG_ETHERH),m)
+  CONFIG_8390_MODULE = y
+  endif
+endif
+
 ifeq ($(CONFIG_NE2K_PCI),y)
 L_OBJS += ne2k-pci.o
 CONFIG_8390_BUILTIN = y
@@ -853,6 +861,10 @@ ifeq ($(CONFIG_MACE),y)
 L_OBJS += mace.o
 endif
 
+ifeq ($(CONFIG_BMAC),y)
+L_OBJS += bmac.o
+endif
+
 ifeq ($(CONFIG_VENDOR_SANGOMA),y)
   LX_OBJS += sdladrv.o
   L_OBJS += sdlamain.o
index ee12ef9113cd48a917cbbbce67f4f9e78f6bce2a..99084afc9e381172af83ec4a141887ed4c590b2d 100644 (file)
@@ -95,6 +95,7 @@ extern int bionet_probe(struct device *);
 extern int pamsnet_probe(struct device *);
 extern int tlan_probe(struct device *);
 extern int mace_probe(struct device *);
+extern int bmac_probe(struct device *);
 extern int cs89x0_probe(struct device *dev);
 extern int ethertap_probe(struct device *dev);
 extern int ether1_probe (struct device *dev);
@@ -380,6 +381,9 @@ struct devprobe m68k_probes[] __initdata = {
 struct devprobe ppc_probes[] __initdata = {
 #ifdef CONFIG_MACE
        {mace_probe, 0},
+#endif
+#ifdef CONFIG_BMAC
+       {bmac_probe, 0},
 #endif
        {NULL, 0},
 };
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
new file mode 100644 (file)
index 0000000..237f0c9
--- /dev/null
@@ -0,0 +1,1450 @@
+/*
+ * Network device driver for the BMAC ethernet controller on
+ * Apple Powermacs.  Assumes it's under a DBDMA controller.
+ *
+ * Copyright (C) 1998 Randy Gobbel.
+ */
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/proc_fs.h>
+#include <asm/prom.h>
+#include <asm/dbdma.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include "bmac.h"
+
+#define trunc_page(x)  ((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1))))
+#define round_page(x)  trunc_page(((unsigned long)(x)) + ((unsigned long)(PAGE_SIZE - 1)))
+
+/*
+ * CRC polynomial - used in working out multicast filter bits.
+ */
+#define ENET_CRCPOLY 0x04c11db7
+
+/* a bunch of constants for the "Heathrow" interrupt controller.
+   These really should be in an include file somewhere */
+#define IoBaseHeathrow ((unsigned *)0xf3000000)
+#define HeathrowFCR 0x0038     /* FCR offset from Heathrow Base Address */
+#define fcrEnetEnabledBits     0x60000000 /* mask to enable Enet Xcvr/Controller */
+#define fcrResetEnetCell       0x80000000 /* mask used to reset Enet cell */
+#define fcrClearResetEnetCell  0x7fffffff /* mask used to clear reset Enet cell */
+#define fcrDisableEnet         0x1fffffff /* mask to disable Enet Xcvr/Controller */
+
+#define N_RX_RING      64
+#define N_TX_RING      32
+#define MAX_TX_ACTIVE  1
+#define ETHERCRC       4
+#define ETHERMINPACKET 64
+#define ETHERMTU       1500
+#define RX_BUFLEN      (ETHERMTU + 14 + ETHERCRC + 2)
+#define TX_TIMEOUT     HZ      /* 1 second */
+
+/* Bits in transmit DMA status */
+#define TX_DMA_ERR     0x80
+
+#define XXDEBUG(args)
+
+struct bmac_data {
+/*     volatile struct bmac *bmac; */
+       struct sk_buff_head *queue;
+       volatile struct dbdma_regs *tx_dma;
+       int tx_dma_intr;
+       volatile struct dbdma_regs *rx_dma;
+       int rx_dma_intr;
+       volatile struct dbdma_cmd *tx_cmds;     /* xmit dma command list */
+       volatile struct dbdma_cmd *rx_cmds;     /* recv dma command list */
+       struct sk_buff *rx_bufs[N_RX_RING];
+       int rx_fill;
+       int rx_empty;
+       struct sk_buff *tx_bufs[N_TX_RING];
+       char *tx_double[N_TX_RING]; /* yuck--double buffering */
+       int tx_fill;
+       int tx_empty;
+       unsigned char tx_fullup;
+       struct net_device_stats stats;
+       struct timer_list tx_timeout;
+       int timeout_active;
+       int reset_and_enabled;
+       int rx_allocated;
+       int tx_allocated;
+       unsigned short hash_use_count[64];
+       unsigned short hash_table_mask[4];
+};
+
+typedef struct bmac_reg_entry {
+       char *name;
+       unsigned short reg_offset;
+} bmac_reg_entry_t;
+
+#define N_REG_ENTRIES 30
+
+bmac_reg_entry_t reg_entries[N_REG_ENTRIES] = {
+       {"MEMADD", MEMADD},
+       {"MEMDATAHI", MEMDATAHI},
+       {"MEMDATALO", MEMDATALO},
+       {"TXPNTR", TXPNTR},
+       {"RXPNTR", RXPNTR},
+       {"IPG1", IPG1},
+       {"IPG2", IPG2},
+       {"ALIMIT", ALIMIT},
+       {"SLOT", SLOT},
+       {"PALEN", PALEN},
+       {"PAPAT", PAPAT},
+       {"TXSFD", TXSFD},
+       {"JAM", JAM},
+       {"TXMAX", TXMAX},
+       {"TXMIN", TXMIN},
+       {"PAREG", PAREG},
+       {"DCNT", DCNT},
+       {"NCCNT", NCCNT},
+       {"NTCNT", NTCNT},
+       {"EXCNT", EXCNT},
+       {"LTCNT", LTCNT},
+       {"TXSM", TXSM},
+       {"RXCFG", RXCFG},
+       {"RXMAX", RXMAX},
+       {"RXMIN", RXMIN},
+       {"FRCNT", FRCNT},
+       {"AECNT", AECNT},
+       {"FECNT", FECNT},
+       {"RXSM", RXSM},
+       {"RXCV", RXCV}
+};
+
+struct device *bmac_devs = NULL;
+
+#if 0
+/*
+ * If we can't get a skbuff when we need it, we use this area for DMA.
+ */
+static unsigned char dummy_buf[RX_BUFLEN];
+#endif
+
+/*
+ * Number of bytes of private data per BMAC: allow enough for
+ * the rx and tx dma commands plus a branch dma command each,
+ * and another 16 bytes to allow us to align the dma command
+ * buffers on a 16 byte boundary.
+ */
+#define PRIV_BYTES     (sizeof(struct bmac_data) \
+                        + (N_RX_RING + N_TX_RING + 4) * sizeof(struct dbdma_cmd) \
+                        + sizeof(struct sk_buff_head))
+
+static unsigned char bitrev(unsigned char b);
+static int bmac_open(struct device *dev);
+static int bmac_close(struct device *dev);
+static int bmac_transmit_packet(struct sk_buff *skb, struct device *dev);
+static struct net_device_stats *bmac_stats(struct device *dev);
+static void bmac_set_multicast(struct device *dev);
+static int bmac_reset_and_enable(struct device *dev, int enable);
+static void bmac_start_chip(struct device *dev);
+static int bmac_init_chip(struct device *dev);
+static void bmac_init_registers(struct device *dev);
+static void bmac_reset_chip(struct device *dev);
+static int bmac_set_address(struct device *dev, void *addr);
+static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void bmac_set_timeout(struct device *dev);
+static void bmac_tx_timeout(unsigned long data);
+static void bmac_reset_chip(struct device *dev);
+static void bmac_init_registers(struct device *dev);
+static int bmac_proc_info ( char *buffer, char **start, off_t offset, int length, int dummy);
+static int bmac_output(struct sk_buff *skb, struct device *dev);
+static void bmac_start(struct device *dev);
+
+#define        DBDMA_SET(x)    ( ((x) | (x) << 16) )
+#define        DBDMA_CLEAR(x)  ( (x) << 16)
+
+static __inline__ void
+dbdma_st32(volatile unsigned long *a, unsigned long x)
+{
+       __asm__ volatile( "stwbrx %0,0,%1" : : "r" (x), "r" (a) : "memory");
+       return;
+}
+
+static __inline__ unsigned long
+dbdma_ld32(volatile unsigned long *a)
+{
+       unsigned long swap;
+       __asm__ volatile ("lwbrx %0,0,%1" :  "=r" (swap) : "r" (a));
+       return swap;
+}
+
+void
+dbdma_stop(volatile struct dbdma_regs *dmap)
+{
+       dbdma_st32((volatile unsigned long *)&dmap->control, DBDMA_CLEAR(RUN) | DBDMA_SET(FLUSH));
+       eieio();
+  
+       while (dbdma_ld32((volatile unsigned long *)&dmap->status) & (ACTIVE|FLUSH))
+               eieio();
+}
+
+static void
+dbdma_continue(volatile struct dbdma_regs *dmap)
+{
+       dbdma_st32((volatile unsigned long *)&dmap->control,
+                  DBDMA_SET(RUN|WAKE) | DBDMA_CLEAR(PAUSE|DEAD));
+       eieio();
+}
+
+static void
+dbdma_reset(volatile struct dbdma_regs *dmap)
+{
+       dbdma_st32((volatile unsigned long *)&dmap->control, 
+                  DBDMA_CLEAR(ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN));      
+       eieio();
+       while (dbdma_ld32((volatile unsigned long *)&dmap->status) & RUN) eieio();
+}
+
+static void
+dbdma_setcmd(volatile struct dbdma_cmd *cp,
+            unsigned short cmd, unsigned count, unsigned long addr,
+            unsigned long cmd_dep)
+{
+       out_le16(&cp->command, cmd);
+       out_le16(&cp->req_count, count);
+       out_le32(&cp->phy_addr, addr);
+       out_le32(&cp->cmd_dep, cmd_dep);
+       out_le16(&cp->xfer_status, 0);
+       out_le16(&cp->res_count, 0);
+}
+
+static __inline__
+void bmwrite(struct device *dev, unsigned long reg_offset, unsigned data )
+{
+       out_le16((void *)dev->base_addr + reg_offset, data);
+}
+
+
+static __inline__
+volatile unsigned short bmread(struct device *dev, unsigned long reg_offset )
+{
+       return in_le16((void *)dev->base_addr + reg_offset); 
+}
+
+static void
+bmac_reset_chip(struct device *dev)
+{
+       struct bmac_data *bp = (struct bmac_data *) dev->priv;
+       volatile struct dbdma_regs *rd = bp->rx_dma;
+       volatile struct dbdma_regs *td = bp->tx_dma;
+       volatile unsigned *heathrowFCR;
+       unsigned int fcrValue;
+        
+       dbdma_reset(rd);
+       dbdma_reset(td);
+
+       heathrowFCR = (unsigned *)((unsigned char *)IoBaseHeathrow + HeathrowFCR);
+
+       fcrValue = in_le32(heathrowFCR);
+
+       fcrValue &= fcrDisableEnet;     /* clear out Xvr and Controller Bit */
+       out_le32(heathrowFCR, fcrValue);
+       udelay(50000);
+
+       fcrValue |= fcrResetEnetCell;   /* set bit to reset them */
+       out_le32(heathrowFCR, fcrValue);
+       udelay(50000);
+       
+       fcrValue &= fcrDisableEnet;
+       out_le32(heathrowFCR, fcrValue);
+       udelay(50000);
+
+       fcrValue |= fcrEnetEnabledBits;
+       out_le32(heathrowFCR, fcrValue);
+       udelay(50000);
+       
+       out_le32(heathrowFCR, fcrValue);
+}
+
+static void
+bmac_init_registers(struct device *dev)
+{
+       struct bmac_data *bp = (struct bmac_data *) dev->priv;
+       volatile unsigned short regValue;
+       unsigned short *pWord16;
+       int i;
+
+/* XXDEBUG(("bmac: enter init_registers\n")); */
+
+       bmwrite(dev, TXRST, TxResetBit);
+
+       do {
+               regValue = bmread(dev, TXRST); /* wait for reset to clear..acknowledge */
+       } while (regValue & TxResetBit);
+
+       bmwrite(dev, RXRST, RxResetValue);
+       bmwrite(dev, XCVRIF, ClkBit | SerialMode | COLActiveLow);       
+       bmwrite(dev, RSEED, (unsigned short)0x1968);            
+
+       regValue = bmread(dev, XIFC);
+       regValue |= TxOutputEnable;
+       bmwrite(dev, XIFC, regValue);
+
+       bmread(dev, PAREG);
+
+       /* set collision counters to 0 */
+       bmwrite(dev, NCCNT, 0);
+       bmwrite(dev, NTCNT, 0);
+       bmwrite(dev, EXCNT, 0);
+       bmwrite(dev, LTCNT, 0);
+
+       /* set rx counters to 0 */
+       bmwrite(dev, FRCNT, 0);
+       bmwrite(dev, LECNT, 0);
+       bmwrite(dev, AECNT, 0);
+       bmwrite(dev, FECNT, 0);
+       bmwrite(dev, RXCV, 0);
+
+       /* set tx fifo information */
+       bmwrite(dev, TXTH, 4);  /* 4 octets before tx starts */
+
+       bmwrite(dev, TXFIFOCSR, 0);     /* first disable txFIFO */
+       bmwrite(dev, TXFIFOCSR, TxFIFOEnable );
+
+       /* set rx fifo information */
+       bmwrite(dev, RXFIFOCSR, 0);     /* first disable rxFIFO */
+       bmwrite(dev, RXFIFOCSR, RxFIFOEnable ); 
+
+       //bmwrite(dev, TXCFG, TxMACEnable);             /* TxNeverGiveUp maybe later */
+       bmread(dev, STATUS);            /* read it just to clear it */
+
+       bmwrite(dev, INTDISABLE, EnableNormal);
+
+       /* zero out the chip Hash Filter registers */
+       for (i=0; i<4; i++) bp->hash_table_mask[i] = 0;
+       bmwrite(dev, BHASH3, bp->hash_table_mask[0]);   /* bits 15 - 0 */
+       bmwrite(dev, BHASH2, bp->hash_table_mask[1]);   /* bits 31 - 16 */
+       bmwrite(dev, BHASH1, bp->hash_table_mask[2]);   /* bits 47 - 32 */
+       bmwrite(dev, BHASH0, bp->hash_table_mask[3]);   /* bits 63 - 48 */
+       
+       pWord16 = (unsigned short *)dev->dev_addr;
+       bmwrite(dev, MADD0, *pWord16++);
+       bmwrite(dev, MADD1, *pWord16++);
+       bmwrite(dev, MADD2, *pWord16);
+    
+
+       bmwrite(dev, RXCFG, RxCRCNoStrip | RxHashFilterEnable | RxRejectOwnPackets);
+    
+       return;
+}
+
+#if 0
+static void
+bmac_disable_interrupts(struct device *dev)
+{
+       bmwrite(dev, INTDISABLE, DisableAll);
+}
+
+static void
+bmac_enable_interrupts(struct device *dev)
+{
+       bmwrite(dev, INTDISABLE, EnableNormal);
+}
+#endif
+
+
+static void
+bmac_start_chip(struct device *dev)
+{
+       struct bmac_data *bp = (struct bmac_data *) dev->priv;
+       volatile struct dbdma_regs *rd = bp->rx_dma;
+       unsigned short  oldConfig;
+
+       /* enable rx dma channel */
+       dbdma_continue(rd);
+  
+       /* turn on rx plus any other bits already on (promiscuous possibly) */
+       oldConfig = bmread(dev, RXCFG);         
+       bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); 
+       oldConfig = bmread(dev, TXCFG);         
+       bmwrite(dev, TXCFG, oldConfig | TxMACEnable );  
+}
+
+static int
+bmac_init_chip(struct device *dev)
+{
+       bmac_init_registers(dev);
+       return 1;
+}
+
+static int bmac_set_address(struct device *dev, void *addr)
+{
+       unsigned char *p = addr;
+       unsigned short *pWord16;
+       unsigned long flags;
+       int i;
+
+       XXDEBUG(("bmac: enter set_address\n"));
+       save_flags(flags); cli();
+
+       for (i = 0; i < 6; ++i) {
+               dev->dev_addr[i] = p[i];
+       }
+       /* load up the hardware address */
+       pWord16  = (unsigned short *)dev->dev_addr;
+       bmwrite(dev, MADD0, *pWord16++);
+       bmwrite(dev, MADD1, *pWord16++);
+       bmwrite(dev, MADD2, *pWord16);
+
+       restore_flags(flags);
+       XXDEBUG(("bmac: exit set_address\n"));
+       return 0;
+}
+
+static inline void bmac_set_timeout(struct device *dev)
+{
+       struct bmac_data *bp = (struct bmac_data *) dev->priv;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       if (bp->timeout_active)
+               del_timer(&bp->tx_timeout);
+       bp->tx_timeout.expires = jiffies + TX_TIMEOUT;
+       bp->tx_timeout.function = bmac_tx_timeout;
+       bp->tx_timeout.data = (unsigned long) dev;
+       add_timer(&bp->tx_timeout);
+       bp->timeout_active = 1;
+       restore_flags(flags);
+}
+
+static void
+bmac_construct_xmt(struct sk_buff *skb, volatile struct dbdma_cmd *cp,
+                  char *doubleBuf)
+{
+       void *vaddr, *page_break;
+       unsigned long baddr;
+       unsigned long len;
+
+       len = skb->len;
+       vaddr = skb->data;
+       baddr = virt_to_bus(vaddr);
+       page_break = round_page(vaddr);
+       if (trunc_page(vaddr) != trunc_page(vaddr+len) &&
+           (unsigned long)round_page(baddr) != virt_to_bus(page_break))  {
+               baddr = virt_to_bus(doubleBuf);
+               XXDEBUG(("bmac: double buffering, double=%#08x, skb->data=%#08x, len=%d\n", doubleBuf, skb->data, len));
+       } else
+               flush_page_to_ram((unsigned long)vaddr);
+
+       dbdma_setcmd(cp, (OUTPUT_LAST | INTR_ALWAYS | WAIT_IFCLR), len, baddr, 0);
+}
+
+static void
+bmac_construct_rxbuff(unsigned char *addr, volatile struct dbdma_cmd *cp)
+{
+       dbdma_setcmd(cp, (INPUT_LAST | INTR_ALWAYS), RX_BUFLEN, virt_to_bus(addr), 0);
+}
+
+/* Bit-reverse one byte of an ethernet hardware address. */
+static unsigned char
+bitrev(unsigned char b)
+{
+       int d = 0, i;
+
+       for (i = 0; i < 8; ++i, b >>= 1)
+               d = (d << 1) | (b & 1);
+       return d;
+}
+
+
+static int
+bmac_init_tx_ring(struct bmac_data *bp)
+{
+       int i;
+       volatile struct dbdma_regs *td = bp->tx_dma;
+       char *addr;
+
+       if (!bp->tx_allocated) {
+               /* zero out tx cmds, alloc space for double buffering */
+               addr = (char *)kmalloc(ETHERMTU * N_TX_RING, GFP_DMA);
+               for (i = 0; i < N_TX_RING; i++, addr += ETHERMTU) bp->tx_double[i] = addr;
+               bp->tx_allocated = 1;
+       }
+       memset((char *)bp->tx_cmds, 0, (N_TX_RING+1) * sizeof(struct dbdma_cmd));
+
+       bp->tx_empty = 0;
+       bp->tx_fill = 0;
+       bp->tx_fullup = 0;
+
+       /* put a branch at the end of the tx command list */
+       dbdma_setcmd(&bp->tx_cmds[N_TX_RING],
+                    (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->tx_cmds));
+
+       /* reset tx dma */
+       dbdma_reset(td);
+       out_le32(&td->wait_sel, 0x00200020);
+       out_le32(&td->cmdptr, virt_to_bus(bp->tx_cmds));
+
+       return 1;
+
+}
+
+static int
+bmac_init_rx_ring(struct bmac_data *bp)
+{
+       volatile struct dbdma_regs *rd = bp->rx_dma;
+       int i;
+
+       /* initialize list of sk_buffs for receiving and set up recv dma */
+       if (!bp->rx_allocated) {
+               for (i = 0; i < N_RX_RING; i++) {
+                       bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2);
+                       skb_reserve(bp->rx_bufs[i], 2);
+               }
+               bp->rx_allocated = 1;
+       }
+
+       memset((char *)bp->rx_cmds, 0, (N_RX_RING+1) * sizeof(struct dbdma_cmd));
+       for (i = 0; i < N_RX_RING; i++)
+               bmac_construct_rxbuff(bp->rx_bufs[i]->data, &bp->rx_cmds[i]);
+
+       bp->rx_empty = 0;
+       bp->rx_fill = i;
+
+       /* Put a branch back to the beginning of the receive command list */
+       dbdma_setcmd(&bp->rx_cmds[N_RX_RING],
+                    (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->rx_cmds));
+
+       /* start rx dma */
+       dbdma_reset(rd);
+       out_le32(&rd->cmdptr, virt_to_bus(bp->rx_cmds));
+
+       return 1;
+}
+
+
+static int bmac_transmit_packet(struct sk_buff *skb, struct device *dev)
+{
+       struct bmac_data *bp = (struct bmac_data *) dev->priv;
+       volatile struct dbdma_regs *td = bp->tx_dma;
+       int i;
+
+       /* see if there's a free slot in the tx ring */
+/* XXDEBUG(("bmac_xmit_start: empty=%d fill=%d\n", */
+/*          bp->tx_empty, bp->tx_fill)); */
+       i = bp->tx_fill + 1;
+       if (i >= N_TX_RING) i = 0;
+       if (i == bp->tx_empty) {
+               dev->tbusy = 1;
+               bp->tx_fullup = 1;
+               XXDEBUG(("bmac_transmit_packet: tx ring full\n"));
+               return -1;              /* can't take it at the moment */
+       }
+
+       dbdma_setcmd(&bp->tx_cmds[i], DBDMA_STOP, 0, 0, 0);
+
+       bmac_construct_xmt(skb, &bp->tx_cmds[bp->tx_fill], bp->tx_double[bp->tx_fill]);
+
+       bp->tx_bufs[bp->tx_fill] = skb;
+       bp->tx_fill = i;
+
+       dbdma_continue(td);
+
+       return 0;
+}
+
+static int rxintcount = 0;
+
+static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct device *dev = (struct device *) dev_id;
+       struct bmac_data *bp = (struct bmac_data *) dev->priv;
+       volatile struct dbdma_regs *rd = bp->rx_dma;
+       volatile struct dbdma_cmd *cp;
+       int i, nb, stat;
+       struct sk_buff *skb;
+       unsigned int residual;
+       int last;
+       unsigned long flags;
+
+       save_flags(flags); cli();
+
+       if (++rxintcount < 10) {
+               XXDEBUG(("bmac_rxdma_intr\n"));
+       }
+
+       last = -1;
+       i = bp->rx_empty;
+
+       while (1) {
+               cp = &bp->rx_cmds[i];
+               stat = ld_le16(&cp->xfer_status);
+               residual = ld_le16(&cp->res_count);
+               if ((stat & ACTIVE) == 0) break;
+               nb = RX_BUFLEN - residual - 2;
+               if (nb < (ETHERMINPACKET - ETHERCRC)) {
+                       skb = NULL;
+                       bp->stats.rx_length_errors++;
+                       bp->stats.rx_errors++;
+               } else skb =  bp->rx_bufs[i];
+               if (skb != NULL) {
+                       nb -= ETHERCRC;
+                       skb_put(skb, nb);
+                       skb->dev = dev;
+                       skb->protocol = eth_type_trans(skb, dev);
+                       netif_rx(skb);
+                       bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2);
+                       skb_reserve(bp->rx_bufs[i], 2);
+                       bmac_construct_rxbuff(bp->rx_bufs[i]->data, &bp->rx_cmds[i]);
+                       ++bp->stats.rx_packets;
+               } else {
+                       ++bp->stats.rx_dropped;
+               }
+               st_le16(&cp->res_count, 0);
+               st_le16(&cp->xfer_status, 0);
+               last = i;
+               if (++i >= N_RX_RING) i = 0;
+       }
+
+       if (last != -1) {
+               bp->rx_fill = last;
+               bp->rx_empty = i;
+       }
+
+       restore_flags(flags);
+
+       dbdma_continue(rd);
+
+       if (rxintcount < 10) {
+               XXDEBUG(("bmac_rxdma_intr done\n"));
+       }
+}
+
+static int txintcount = 0;
+
+static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct device *dev = (struct device *) dev_id;
+       struct bmac_data *bp = (struct bmac_data *) dev->priv;
+       volatile struct dbdma_cmd *cp;
+       int stat;
+       unsigned long flags;
+
+       save_flags(flags); cli();
+
+       if (txintcount++ < 10) {
+               XXDEBUG(("bmac_txdma_intr\n"));
+       }
+
+/*     del_timer(&bp->tx_timeout); */
+/*     bp->timeout_active = 0; */
+
+       while (1) {
+               cp = &bp->tx_cmds[bp->tx_empty];
+               stat = ld_le16(&cp->xfer_status);
+               if (txintcount < 10) {
+                       XXDEBUG(("bmac_txdma_xfer_stat=%#0x\n", stat));
+               }
+               if (!(stat & ACTIVE)) break;
+
+               if (bp->tx_bufs[bp->tx_empty]) {
+                       ++bp->stats.tx_packets;
+                       dev_kfree_skb(bp->tx_bufs[bp->tx_empty]);
+               }
+               bp->tx_bufs[bp->tx_empty] = NULL;
+               bp->tx_fullup = 0;
+               dev->tbusy = 0;
+/* XXDEBUG(("bmac_intr: cleared tbusy, empty=%d fill=%d\n", */
+/*              i, bp->tx_fill)); */
+               mark_bh(NET_BH);
+               if (++bp->tx_empty >= N_TX_RING) bp->tx_empty = 0;
+               if (bp->tx_empty == bp->tx_fill) break;
+       }
+
+       restore_flags(flags);
+
+       if (txintcount < 10) {
+               XXDEBUG(("bmac_txdma_intr done->bmac_start\n"));
+       }
+
+       bmac_start(dev);
+}
+
+static struct net_device_stats *bmac_stats(struct device *dev)
+{
+       struct bmac_data *p = (struct bmac_data *) dev->priv;
+
+       return &p->stats;
+}
+
+#if 0
+/* Real fast bit-reversal algorithm, 6-bit values */
+static int reverse6[64] = {
+       0x0,0x20,0x10,0x30,0x8,0x28,0x18,0x38,
+       0x4,0x24,0x14,0x34,0xc,0x2c,0x1c,0x3c,
+       0x2,0x22,0x12,0x32,0xa,0x2a,0x1a,0x3a,
+       0x6,0x26,0x16,0x36,0xe,0x2e,0x1e,0x3e,
+       0x1,0x21,0x11,0x31,0x9,0x29,0x19,0x39,
+       0x5,0x25,0x15,0x35,0xd,0x2d,0x1d,0x3d,
+       0x3,0x23,0x13,0x33,0xb,0x2b,0x1b,0x3b,
+       0x7,0x27,0x17,0x37,0xf,0x2f,0x1f,0x3f
+};
+
+static unsigned int
+crc416(unsigned int curval, unsigned short nxtval)
+{
+       register unsigned int counter, cur = curval, next = nxtval;
+       register int high_crc_set, low_data_set;
+
+       /* Swap bytes */
+       next = ((next & 0x00FF) << 8) | (next >> 8);
+
+       /* Compute bit-by-bit */
+       for (counter = 0; counter < 16; ++counter) {
+               /* is high CRC bit set? */
+               if ((cur & 0x80000000) == 0) high_crc_set = 0;
+               else high_crc_set = 1;
+      
+               cur = cur << 1;
+       
+               if ((next & 0x0001) == 0) low_data_set = 0;
+               else low_data_set = 1;
+
+               next = next >> 1;
+       
+               /* do the XOR */
+               if (high_crc_set ^ low_data_set) cur = cur ^ ENET_CRCPOLY;
+       }
+       return cur;
+}
+
+static unsigned int
+bmac_crc(unsigned short *address)
+{      
+       unsigned int newcrc;
+
+       XXDEBUG(("bmac_crc: addr=%#04x, %#04x, %#04x\n", *address, address[1], address[2]));
+       newcrc = crc416(0xffffffff, *address);  /* address bits 47 - 32 */
+       newcrc = crc416(newcrc, address[1]);    /* address bits 31 - 16 */
+       newcrc = crc416(newcrc, address[2]);    /* address bits 15 - 0  */
+
+       return(newcrc);
+}
+
+/*
+ * Add requested mcast addr to BMac's hash table filter.  
+ *  
+ */
+
+static void
+bmac_addhash(struct bmac_data *bp, unsigned char *addr)
+{      
+       unsigned int     crc;
+       unsigned short   mask;
+
+       if (!(*addr 
+             crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */
+             crc = reverse6[crc];      /* Hyperfast bit-reversing algorithm */
+             if (bp->hash_use_count[crc]++) return; /* This bit is already set */
+             mask = crc % 16;
+             mask = (unsigned char)1 << mask;
+             bp->hash_use_count[crc/16] |= mask;
+             }
+
+           static void
+           bmac_removehash(struct bmac_data *bp, unsigned char *addr)
+           {   
+                   unsigned int crc;
+                   unsigned char mask;
+
+                   /* Now, delete the address from the filter copy, as indicated */
+                   crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */
+                   crc = reverse6[crc];        /* Hyperfast bit-reversing algorithm */
+                   if (bp->hash_use_count[crc] == 0) return; /* That bit wasn't in use! */
+                   if (--bp->hash_use_count[crc]) return; /* That bit is still in use */
+                   mask = crc % 16;
+                   mask = ((unsigned char)1 << mask) ^ 0xffff; /* To turn off bit */
+                   bp->hash_table_mask[crc/16] &= mask;
+           }
+
+/*
+ * Sync the adapter with the software copy of the multicast mask
+ *  (logical address filter).
+ */
+
+                   static void
+                   bmac_rx_off(struct device *dev)
+                   {
+                           unsigned short rx_cfg;
+
+                           rx_cfg = bmread(dev, RXCFG);
+                           rx_cfg &= ~RxMACEnable;
+                           bmwrite(dev, RXCFG, rx_cfg);
+                           do {
+                                   rx_cfg = bmread(dev, RXCFG);
+                           }  while (rx_cfg & RxMACEnable);
+                   }
+
+                           unsigned short
+                           bmac_rx_on(struct device *dev, int hash_enable, int promisc_enable)
+                           {
+                                   unsigned short rx_cfg;
+
+                                   rx_cfg = bmread(dev, RXCFG);
+                                   rx_cfg |= RxMACEnable;
+                                   if (hash_enable) rx_cfg |= RxHashFilterEnable;
+                                   else rx_cfg &= ~RxHashFilterEnable;
+                                   if (promisc_enable) rx_cfg |= RxPromiscEnable;
+                                   else rx_cfg &= ~RxPromiscEnable;
+                                   bmwrite(dev, RXRST, RxResetValue);
+                                   bmwrite(dev, RXFIFOCSR, 0); /* first disable rxFIFO */
+                                   bmwrite(dev, RXFIFOCSR, RxFIFOEnable ); 
+                                   bmwrite(dev, RXCFG, rx_cfg );
+                                   return rx_cfg;
+                           }
+
+                                   static void
+                                   bmac_update_hash_table_mask(struct device *dev, struct bmac_data *bp)
+                                   {
+                                           bmwrite(dev, BHASH3, bp->hash_table_mask[0]); /* bits 15 - 0 */
+                                           bmwrite(dev, BHASH2, bp->hash_table_mask[1]); /* bits 31 - 16 */
+                                           bmwrite(dev, BHASH1, bp->hash_table_mask[2]); /* bits 47 - 32 */
+                                           bmwrite(dev, BHASH0, bp->hash_table_mask[3]); /* bits 63 - 48 */
+                                   }
+
+#if 0
+                                           static void
+                                           bmac_add_multi(struct device *dev,
+                                                          struct bmac_data *bp, unsigned char *addr)
+                                           {
+/* XXDEBUG(("bmac: enter bmac_add_multi\n")); */
+                                                   bmac_addhash(bp, addr);
+                                                   bmac_rx_off(dev);
+                                                   bmac_update_hash_table_mask(dev, bp);
+                                                   bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0);
+/* XXDEBUG(("bmac: exit bmac_add_multi\n")); */
+                                           }
+
+                                                   static void
+                                                   bmac_remove_multi(struct device *dev,
+                                                                     struct bmac_data *bp, unsigned char *addr)
+                                                   {
+                                                           bmac_removehash(bp, addr);
+                                                           bmac_rx_off(dev);
+                                                           bmac_update_hash_table_mask(dev, bp);
+                                                           bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0);
+                                                   }
+#endif
+
+/* Set or clear the multicast filter for this adaptor.
+    num_addrs == -1    Promiscuous mode, receive all packets
+    num_addrs == 0     Normal mode, clear multicast list
+    num_addrs > 0      Multicast mode, receive normal and MC packets, and do
+                       best-effort filtering.
+ */
+                                                           static void bmac_set_multicast(struct device *dev)
+                                                           {
+                                                                   struct dev_mc_list *dmi;
+                                                                   struct bmac_data *bp = (struct bmac_data *) dev->priv;
+                                                                   int num_addrs = dev->mc_count;
+                                                                   unsigned short rx_cfg;
+                                                                   int i;
+
+                                                                   XXDEBUG(("bmac: enter bmac_set_multicast, n_addrs=%d\n", num_addrs));
+
+                                                                   if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
+                                                                           for (i=0; i<4; i++) bp->hash_table_mask[i] = 0xffff;
+                                                                           bmac_update_hash_table_mask(dev, bp);
+                                                                           rx_cfg = bmac_rx_on(dev, 1, 0);
+                                                                           XXDEBUG(("bmac: all multi, rx_cfg=%#08x\n"));
+                                                                   } else if if ((dev->flags & IFF_PROMISC) || (num_addrs < 0)) {
+                                                                           rx_cfg = bmread(dev, RXCFG);
+                                                                           rx_cfg |= RxPromiscEnable;
+                                                                           bmwrite(dev, RXCFG, rx_cfg);
+                                                                           rx_cfg = bmac_rx_on(dev, 0, 1);
+                                                                           XXDEBUG(("bmac: promisc mode enabled, rx_cfg=%#08x\n", rx_cfg));
+                                                                   } else {
+                                                                           for (i=0; i<4; i++) bp->hash_table_mask[i] = 0;
+                                                                           for (i=0; i<64; i++) bp->hash_use_count[i] = 0;
+                                                                           if (num_addrs == 0) {
+                                                                                   rx_cfg = bmac_rx_on(dev, 0, 0);
+                                                                                   XXDEBUG(("bmac: multi disabled, rx_cfg=%#08x\n", rx_cfg));
+                                                                           } else {
+                                                                                   for (dmi=dev->mc_list; dmi!=NULL; dmi=dmi->next)
+                                                                                           bmac_addhash(bp, dmi->dmi_addr);
+                                                                                   bmac_update_hash_table_mask(dev, bp);
+                                                                                   rx_cfg = bmac_rx_on(dev, 1, 0);
+                                                                                   XXDEBUG(("bmac: multi enabled, rx_cfg=%#08x\n", rx_cfg));
+                                                                           }
+                                                                   }
+/* XXDEBUG(("bmac: exit bmac_set_multicast\n")); */
+                                                           }
+#endif
+
+/* The version of set_multicast below was lifted from sunhme.c */
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
+
+                                                                   static void bmac_set_multicast(struct device *dev)
+                                                                   {
+                                                                           struct dev_mc_list *dmi = dev->mc_list;
+                                                                           char *addrs;
+                                                                           int i, j, bit, byte;
+                                                                           unsigned short rx_cfg;
+                                                                           u32 crc, poly = CRC_POLYNOMIAL_LE;
+    
+                                                                           /* Let the transmits drain. */
+/*     while(dev->tbusy) schedule(); */
+    
+                                                                           /* Lock out others. */
+/*     set_bit(0, (void *) &dev->tbusy); */
+    
+                                                                           if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
+                                                                                   bmwrite(dev, BHASH0, 0xffff);
+                                                                                   bmwrite(dev, BHASH1, 0xffff);
+                                                                                   bmwrite(dev, BHASH2, 0xffff);
+                                                                                   bmwrite(dev, BHASH3, 0xffff);
+                                                                           } else if(dev->flags & IFF_PROMISC) {
+                                                                                   rx_cfg = bmread(dev, RXCFG);
+                                                                                   rx_cfg |= RxPromiscEnable;
+                                                                                   bmwrite(dev, RXCFG, rx_cfg);
+                                                                           } else {
+                                                                                   u16 hash_table[4];
+       
+                                                                                   for(i = 0; i < 4; i++) hash_table[i] = 0;
+       
+                                                                                   for(i = 0; i < dev->mc_count; i++) {
+                                                                                           addrs = dmi->dmi_addr;
+                                                                                           dmi = dmi->next;
+           
+                                                                                           if(!(*addrs & 1))
+                                                                                                   continue;
+           
+                                                                                           crc = 0xffffffffU;
+                                                                                           for(byte = 0; byte < 6; byte++) {
+                                                                                                   for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
+                                                                                                           int test;
+                   
+                                                                                                           test = ((bit ^ crc) & 0x01);
+                                                                                                           crc >>= 1;
+                                                                                                           if(test)
+                                                                                                                   crc = crc ^ poly;
+                                                                                                   }
+                                                                                           }
+                                                                                           crc >>= 26;
+                                                                                           hash_table[crc >> 4] |= 1 << (crc & 0xf);
+                                                                                   }
+                                                                                   bmwrite(dev, BHASH0, hash_table[0]);
+                                                                                   bmwrite(dev, BHASH1, hash_table[1]);
+                                                                                   bmwrite(dev, BHASH2, hash_table[2]);
+                                                                                   bmwrite(dev, BHASH3, hash_table[3]);
+                                                                           }
+    
+                                                                           /* Let us get going again. */
+/*     dev->tbusy = 0; */
+                                                                   }
+
+
+                                                                           static int miscintcount = 0;
+
+                                                                           static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs)
+                                                                           {
+                                                                                   struct device *dev = (struct device *) dev_id;
+                                                                                   struct bmac_data *bp = (struct bmac_data *)dev->priv;
+                                                                                   unsigned int status = bmread(dev, STATUS);
+                                                                                   if (miscintcount++ < 10) {
+                                                                                           XXDEBUG(("bmac_misc_intr\n"));
+                                                                                   }
+/* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */
+/*     bmac_txdma_intr_inner(irq, dev_id, regs); */
+/*   if (status & FrameReceived) bp->stats.rx_dropped++; */
+                                                                                   if (status & RxErrorMask) bp->stats.rx_errors++;
+                                                                                   if (status & RxCRCCntExp) bp->stats.rx_crc_errors++;
+                                                                                   if (status & RxLenCntExp) bp->stats.rx_length_errors++;
+                                                                                   if (status & RxOverFlow) bp->stats.rx_over_errors++;
+                                                                                   if (status & RxAlignCntExp) bp->stats.rx_frame_errors++;
+
+/*   if (status & FrameSent) bp->stats.tx_dropped++; */
+                                                                                   if (status & TxErrorMask) bp->stats.tx_errors++;
+                                                                                   if (status & TxUnderrun) bp->stats.tx_fifo_errors++;
+                                                                                   if (status & TxNormalCollExp) bp->stats.collisions++;
+                                                                           }
+
+/*
+ * Procedure for reading EEPROM 
+ */
+#define SROMAddressLength      5
+#define DataInOn               0x0008
+#define DataInOff              0x0000
+#define Clk                    0x0002
+#define ChipSelect             0x0001
+#define SDIShiftCount          3
+#define SD0ShiftCount          2
+#define        DelayValue              1000    /* number of microseconds */
+#define SROMStartOffset                10      /* this is in words */
+#define SROMReadCount          3       /* number of words to read from SROM */
+#define SROMAddressBits                6
+#define EnetAddressOffset      20
+
+                                                                                   static unsigned char
+                                                                                   bmac_clock_out_bit(struct device *dev)
+                                                                                   {
+                                                                                           unsigned short         data;
+                                                                                           unsigned short         val;
+
+                                                                                           bmwrite(dev, SROMCSR, ChipSelect | Clk);
+                                                                                           udelay(DelayValue);
+    
+                                                                                           data = bmread(dev, SROMCSR);
+                                                                                           udelay(DelayValue);
+                                                                                           val = (data >> SD0ShiftCount) & 1;
+
+                                                                                           bmwrite(dev, SROMCSR, ChipSelect);
+                                                                                           udelay(DelayValue);
+    
+                                                                                           return val;
+                                                                                   }
+
+                                                                                           static void
+                                                                                           bmac_clock_in_bit(struct device *dev, unsigned int val)
+                                                                                           {
+                                                                                                   unsigned short              data;    
+
+                                                                                                   if (val != 0 && val != 1) return;
+    
+                                                                                                   data = (val << SDIShiftCount);
+                                                                                                   bmwrite(dev, SROMCSR, data | ChipSelect  );
+                                                                                                   udelay(DelayValue);
+    
+                                                                                                   bmwrite(dev, SROMCSR, data | ChipSelect | Clk );
+                                                                                                   udelay(DelayValue);
+
+                                                                                                   bmwrite(dev, SROMCSR, data | ChipSelect);
+                                                                                                   udelay(DelayValue);
+                                                                                           }
+
+                                                                                                   static void
+                                                                                                   reset_and_select_srom(struct device *dev)
+                                                                                                   {
+                                                                                                           /* first reset */
+                                                                                                           bmwrite(dev, SROMCSR, 0);
+                                                                                                           udelay(DelayValue);
+    
+                                                                                                           /* send it the read command (110) */
+                                                                                                           bmac_clock_in_bit(dev, 1);
+                                                                                                           bmac_clock_in_bit(dev, 1);
+                                                                                                           bmac_clock_in_bit(dev, 0);
+                                                                                                   }
+
+                                                                                                           static unsigned short
+                                                                                                           read_srom(struct device *dev, unsigned int addr, unsigned int addr_len)
+                                                                                                           {
+                                                                                                                   unsigned short data, val;
+                                                                                                                   int i;
+    
+                                                                                                                   /* send out the address we want to read from */
+                                                                                                                   for (i = 0; i < addr_len; i++)      {
+                                                                                                                           val = addr >> (addr_len-i-1);
+                                                                                                                           bmac_clock_in_bit(dev, val & 1);
+                                                                                                                   }
+    
+                                                                                                                   /* Now read in the 16-bit data */
+                                                                                                                   data = 0;
+                                                                                                                   for (i = 0; i < 16; i++)    {
+                                                                                                                           val = bmac_clock_out_bit(dev);
+                                                                                                                           data <<= 1;
+                                                                                                                           data |= val;
+                                                                                                                   }
+                                                                                                                   bmwrite(dev, SROMCSR, 0);
+    
+                                                                                                                   return data;
+                                                                                                           }
+
+/*
+ * It looks like Cogent and SMC use different methods for calculating
+ * checksums. What a pain.. 
+ */
+
+                                                                                                                   static int
+                                                                                                                   bmac_verify_checksum(struct device *dev)
+                                                                                                                   {
+                                                                                                                           unsigned short data, storedCS;
+    
+                                                                                                                           reset_and_select_srom(dev);
+                                                                                                                           data = read_srom(dev, 3, SROMAddressBits);
+                                                                                                                           storedCS = ((data >> 8) & 0x0ff) | ((data << 8) & 0xff00);
+    
+                                                                                                                           return 0;
+                                                                                                                   }
+
+
+                                                                                                                           static void
+                                                                                                                           bmac_get_station_address(struct device *dev, unsigned char *ea)
+                                                                                                                           {
+                                                                                                                                   int i;
+                                                                                                                                   unsigned short data;
+
+                                                                                                                                   for (i = 0; i < 6; i++)     
+                                                                                                                                   {
+                                                                                                                                           reset_and_select_srom(dev);
+                                                                                                                                           data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits);
+                                                                                                                                           ea[2*i]   = bitrev(data & 0x0ff);
+                                                                                                                                           ea[2*i+1] = bitrev((data >> 8) & 0x0ff);
+                                                                                                                                   }
+                                                                                                                           }
+
+                                                                                                                                   static int bmac_reset_and_enable(struct device *dev, int enable)
+                                                                                                                                   {
+                                                                                                                                           struct bmac_data *bp = dev->priv;
+                                                                                                                                           unsigned long flags;
+
+                                                                                                                                           save_flags(flags); cli();
+                                                                                                                                           bp->reset_and_enabled = 0;
+                                                                                                                                           bmac_reset_chip(dev);
+                                                                                                                                           if (enable) {
+                                                                                                                                                   if (!bmac_init_tx_ring(bp) || !bmac_init_rx_ring(bp)) return 0;
+                                                                                                                                                   if (!bmac_init_chip(dev)) return 0;
+                                                                                                                                                   bmac_start_chip(dev);
+                                                                                                                                                   bmwrite(dev, INTDISABLE, EnableNormal);
+                                                                                                                                                   bp->reset_and_enabled = 1;
+/*     { */
+/*         unsigned char random_packet[100]; */
+/*         unsigned int i; */
+/*         struct sk_buff *skb = dev_alloc_skb(RX_BUFLEN+2); */
+/*         unsigned char *data = skb_put(skb, sizeof(random_packet)); */
+/* XXDEBUG(("transmitting random packet\n")); */
+/*         for (i = 0; i < sizeof(random_packet); i++) data[i] = i; */
+/*         bmac_transmit_packet(skb, dev); */
+/* XXDEBUG(("done transmitting random packet\n")); */
+/*     } */
+                                                                                                                                           }
+                                                                                                                                           restore_flags(flags);
+                                                                                                                                           return 1;
+                                                                                                                                   }
+
+                                                                                                                                           int
+                                                                                                                                           bmac_probe(struct device *dev)
+                                                                                                                                           {
+                                                                                                                                                   int j, rev;
+                                                                                                                                                   struct bmac_data *bp;
+                                                                                                                                                   struct device_node *bmacs;
+                                                                                                                                                   unsigned char *addr;
+
+                                                                                                                                                   bmacs = find_devices("bmac");
+                                                                                                                                                   if (bmacs == NULL) return ENODEV;
+
+                                                                                                                                                   bmac_devs = dev; /* KLUDGE!! */
+
+                                                                                                                                                   if (bmacs->n_addrs != 3 || bmacs->n_intrs != 3) {
+                                                                                                                                                           printk(KERN_ERR "can't use BMAC %s: expect 3 addrs and 3 intrs\n",
+                                                                                                                                                                  bmacs->full_name);
+                                                                                                                                                           return EINVAL;
+                                                                                                                                                   }
+    
+                                                                                                                                                   if (dev == NULL) {
+                                                                                                                                                           dev = init_etherdev(NULL, PRIV_BYTES);
+                                                                                                                                                           bmac_devs = dev;  /*KLUDGE!!*/
+                                                                                                                                                   } else {
+                                                                                                                                                           /* XXX this doesn't look right (but it's never used :-) */
+                                                                                                                                                           dev->priv = kmalloc(PRIV_BYTES, GFP_KERNEL);
+                                                                                                                                                           if (dev->priv == 0) return -ENOMEM;
+                                                                                                                                                   }
+    
+                                                                                                                                                   dev->base_addr = bmacs->addrs[0].address;
+                                                                                                                                                   dev->irq = bmacs->intrs[0].line;
+    
+                                                                                                                                                   bmwrite(dev, INTDISABLE, DisableAll);
+
+                                                                                                                                                   if (request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev)) {
+                                                                                                                                                           printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq);
+                                                                                                                                                           return -EAGAIN;
+                                                                                                                                                   }
+                                                                                                                                                   if (request_irq(bmacs->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma",
+                                                                                                                                                                   dev)) {
+                                                                                                                                                           printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[1].line);
+                                                                                                                                                           return -EAGAIN;
+                                                                                                                                                   }
+                                                                                                                                                   if (request_irq(bmacs->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma",
+                                                                                                                                                                   dev)) {
+                                                                                                                                                           printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[2].line);
+                                                                                                                                                           return -EAGAIN;
+                                                                                                                                                   }
+    
+                                                                                                                                                   addr = get_property(bmacs, "mac-address", NULL);
+                                                                                                                                                   if (addr == NULL) {
+                                                                                                                                                           addr = get_property(bmacs, "local-mac-address", NULL);
+                                                                                                                                                           if (addr == NULL) {
+                                                                                                                                                                   printk(KERN_ERR "Can't get mac-address for BMAC at %lx\n",
+                                                                                                                                                                          dev->base_addr);
+                                                                                                                                                                   return -EAGAIN;
+                                                                                                                                                           }
+                                                                                                                                                   }
+    
+                                                                                                                                                   printk(KERN_INFO "%s: BMAC at", dev->name);
+                                                                                                                                                   rev = addr[0] == 0 && addr[1] == 0xA0;
+                                                                                                                                                   for (j = 0; j < 6; ++j) {
+                                                                                                                                                           dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+                                                                                                                                                           printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
+                                                                                                                                                   }
+                                                                                                                                                   XXDEBUG((", base_addr=%#0lx", dev->base_addr));
+                                                                                                                                                   printk("\n");
+    
+                                                                                                                                                   dev->open = bmac_open;
+                                                                                                                                                   dev->stop = bmac_close;
+                                                                                                                                                   dev->hard_start_xmit = bmac_output;
+                                                                                                                                                   dev->get_stats = bmac_stats;
+                                                                                                                                                   dev->set_multicast_list = bmac_set_multicast;
+                                                                                                                                                   dev->set_mac_address = bmac_set_address;
+
+                                                                                                                                                   bmac_get_station_address(dev, addr);
+                                                                                                                                                   if (bmac_verify_checksum(dev) != 0) return EINVAL;
+    
+                                                                                                                                                   ether_setup(dev);
+    
+                                                                                                                                                   bp = (struct bmac_data *) dev->priv;
+                                                                                                                                                   memset(bp, 0, sizeof(struct bmac_data));
+                                                                                                                                                   bp->tx_dma = (volatile struct dbdma_regs *) bmacs->addrs[1].address;
+                                                                                                                                                   bp->tx_dma_intr = bmacs->intrs[1].line;
+                                                                                                                                                   bp->rx_dma = (volatile struct dbdma_regs *) bmacs->addrs[2].address;
+                                                                                                                                                   bp->rx_dma_intr = bmacs->intrs[2].line;
+    
+                                                                                                                                                   bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1);
+                                                                                                                                                   bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1;
+
+                                                                                                                                                   bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1);
+                                                                                                                                                   skb_queue_head_init(bp->queue);
+    
+                                                                                                                                                   memset(&bp->stats, 0, sizeof(bp->stats));
+                                                                                                                                                   memset((char *) bp->tx_cmds, 0,
+                                                                                                                                                          (N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
+/*     init_timer(&bp->tx_timeout); */
+/*     bp->timeout_active = 0; */
+    
+                                                                                                                                                   if (!bmac_reset_and_enable(dev, 0)) return EINVAL;
+
+#ifdef CONFIG_PROC_FS
+                                                                                                                                                   proc_net_register(&(struct proc_dir_entry) {
+                                                                                                                                                           PROC_NET_BMAC, 4, "bmac",
+                                                                                                                                                                   S_IFREG | S_IRUGO, 1, 0, 0,
+                                                                                                                                                                   0, &proc_net_inode_operations,
+                                                                                                                                                                   bmac_proc_info
+                                                                                                                                                                   });
+#endif
+
+                                                                                                                                                   return 0;
+                                                                                                                                           }
+
+                                                                                                                                                   static int bmac_open(struct device *dev)
+                                                                                                                                                   {
+/* XXDEBUG(("bmac: enter open\n")); */
+                                                                                                                                                           /* reset the chip */
+                                                                                                                                                           bmac_reset_and_enable(dev, 1);
+
+                                                                                                                                                           dev->flags |= IFF_UP | IFF_RUNNING;
+
+                                                                                                                                                           return 0;
+                                                                                                                                                   }
+
+                                                                                                                                                           static int bmac_close(struct device *dev)
+                                                                                                                                                           {
+                                                                                                                                                                   struct bmac_data *bp = (struct bmac_data *) dev->priv;
+                                                                                                                                                                   volatile struct dbdma_regs *rd = bp->rx_dma;
+                                                                                                                                                                   volatile struct dbdma_regs *td = bp->tx_dma;
+                                                                                                                                                                   unsigned short config;
+                                                                                                                                                                   int i;
+
+                                                                                                                                                                   dev->flags &= ~(IFF_UP | IFF_RUNNING);
+
+                                                                                                                                                                   /* disable rx and tx */
+                                                                                                                                                                   config = bmread(dev, RXCFG);
+                                                                                                                                                                   bmwrite(dev, RXCFG, (config & ~RxMACEnable));
+
+                                                                                                                                                                   config = bmread(dev, TXCFG);
+                                                                                                                                                                   bmwrite(dev, TXCFG, (config & ~TxMACEnable));
+
+                                                                                                                                                                   bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */
+
+                                                                                                                                                                   /* disable rx and tx dma */
+                                                                                                                                                                   st_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));   /* clear run bit */
+                                                                                                                                                                   st_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));   /* clear run bit */
+
+                                                                                                                                                                   /* free some skb's */
+                                                                                                                                                                   XXDEBUG(("bmac: free rx bufs\n"));
+                                                                                                                                                                   for (i=0; i<N_RX_RING; i++) {
+                                                                                                                                                                           if (bp->rx_bufs[i] != NULL) {
+                                                                                                                                                                                   dev_kfree_skb(bp->rx_bufs[i]);
+                                                                                                                                                                                   bp->rx_bufs[i] = NULL;
+                                                                                                                                                                           }
+                                                                                                                                                                   }
+                                                                                                                                                                   bp->rx_allocated = 0;
+                                                                                                                                                                   XXDEBUG(("bmac: free doubles\n"));/*MEMORY LEAK BELOW!!! FIX!!! */
+                                                                                                                                                                   if (bp->tx_double[0] != NULL) kfree(bp->tx_double[0]);
+                                                                                                                                                                   XXDEBUG(("bmac: free tx bufs\n"));
+                                                                                                                                                                   for (i = 0; i<N_TX_RING; i++) {
+                                                                                                                                                                           if (bp->tx_bufs[i] != NULL) {
+                                                                                                                                                                                   dev_kfree_skb(bp->tx_bufs[i]);
+                                                                                                                                                                                   bp->tx_bufs[i] = NULL;
+                                                                                                                                                                           }
+                                                                                                                                                                   }
+                                                                                                                                                                   bp->tx_allocated = 0;
+                                                                                                                                                                   bp->reset_and_enabled = 0;
+                                                                                                                                                                   XXDEBUG(("bmac: all bufs freed\n"));
+
+                                                                                                                                                                   return 0;
+                                                                                                                                                           }
+
+                                                                                                                                                                   static void
+                                                                                                                                                                   bmac_start(struct device *dev)
+                                                                                                                                                                   {
+                                                                                                                                                                           struct bmac_data *bp = dev->priv;
+                                                                                                                                                                           int i;
+                                                                                                                                                                           struct sk_buff *skb;
+                                                                                                                                                                           unsigned long flags;
+    
+                                                                                                                                                                           save_flags(flags); cli();
+                                                                                                                                                                           while (1) {
+                                                                                                                                                                                   i = bp->tx_fill + 1;
+                                                                                                                                                                                   if (i >= N_TX_RING) i = 0;
+                                                                                                                                                                                   if (i == bp->tx_empty) break;
+                                                                                                                                                                                   skb = skb_dequeue(bp->queue);
+                                                                                                                                                                                   if (skb == NULL) break;
+                                                                                                                                                                                   bmac_transmit_packet(skb, dev);
+                                                                                                                                                                           }
+                                                                                                                                                                           restore_flags(flags);
+                                                                                                                                                                   }
+
+                                                                                                                                                                           static int
+                                                                                                                                                                           bmac_output(struct sk_buff *skb, struct device *dev)
+                                                                                                                                                                           {
+                                                                                                                                                                                   struct bmac_data *bp = dev->priv;
+                                                                                                                                                                                   skb_queue_tail(bp->queue, skb);
+                                                                                                                                                                                   bmac_start(dev);
+                                                                                                                                                                                   return 0;
+                                                                                                                                                                           }
+
+                                                                                                                                                                                   static void bmac_tx_timeout(unsigned long data)
+                                                                                                                                                                                   {
+                                                                                                                                                                                           struct device *dev = (struct device *) data;
+                                                                                                                                                                                           struct bmac_data *bp = (struct bmac_data *) dev->priv;
+                                                                                                                                                                                           volatile struct dbdma_regs *td = bp->tx_dma;
+                                                                                                                                                                                           volatile struct dbdma_regs *rd = bp->rx_dma;
+                                                                                                                                                                                           volatile struct dbdma_cmd *cp;
+                                                                                                                                                                                           unsigned long flags;
+                                                                                                                                                                                           unsigned short config, oldConfig;
+                                                                                                                                                                                           int i;
+
+                                                                                                                                                                                           XXDEBUG(("bmac: tx_timeout called\n"));
+                                                                                                                                                                                           save_flags(flags); cli();
+                                                                                                                                                                                           bp->timeout_active = 0;
+
+                                                                                                                                                                                           /* update various counters */
+/*     bmac_handle_misc_intrs(bp, 0); */
+
+                                                                                                                                                                                           cp = &bp->tx_cmds[bp->tx_empty];
+/*     XXDEBUG((KERN_DEBUG "bmac: tx dmastat=%x %x runt=%d pr=%x fs=%x fc=%x\n", */
+/*        ld_le32(&td->status), ld_le16(&cp->xfer_status), bp->tx_bad_runt, */
+/*        mb->pr, mb->xmtfs, mb->fifofc)); */
+
+                                                                                                                                                                                           /* turn off both tx and rx and reset the chip */
+                                                                                                                                                                                           config = bmread(dev, RXCFG);
+                                                                                                                                                                                           bmwrite(dev, RXCFG, (config & ~RxMACEnable));
+                                                                                                                                                                                           config = bmread(dev, TXCFG);
+                                                                                                                                                                                           bmwrite(dev, TXCFG, (config & ~TxMACEnable));
+                                                                                                                                                                                           out_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD));
+                                                                                                                                                                                           printk(KERN_ERR "bmac: transmit timeout - resetting\n");
+                                                                                                                                                                                           bmac_reset_chip(dev);
+
+                                                                                                                                                                                           /* restart rx dma */
+                                                                                                                                                                                           cp = bus_to_virt(ld_le32(&rd->cmdptr));
+                                                                                                                                                                                           out_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD));
+                                                                                                                                                                                           out_le16(&cp->xfer_status, 0);
+                                                                                                                                                                                           out_le32(&rd->cmdptr, virt_to_bus(cp));
+                                                                                                                                                                                           out_le32(&rd->control, DBDMA_SET(RUN|WAKE));
+
+                                                                                                                                                                                           /* fix up the transmit side */
+                                                                                                                                                                                           XXDEBUG((KERN_DEBUG "bmac: tx empty=%d fill=%d fullup=%d\n",
+                                                                                                                                                                                                    bp->tx_empty, bp->tx_fill, bp->tx_fullup));
+                                                                                                                                                                                           i = bp->tx_empty;
+                                                                                                                                                                                           ++bp->stats.tx_errors;
+                                                                                                                                                                                           if (i != bp->tx_fill) {
+                                                                                                                                                                                                   dev_kfree_skb(bp->tx_bufs[i]);
+                                                                                                                                                                                                   bp->tx_bufs[i] = NULL;
+                                                                                                                                                                                                   if (++i >= N_TX_RING) i = 0;
+                                                                                                                                                                                                   bp->tx_empty = i;
+                                                                                                                                                                                           }
+                                                                                                                                                                                           bp->tx_fullup = 0;
+                                                                                                                                                                                           dev->tbusy = 0;
+                                                                                                                                                                                           mark_bh(NET_BH);
+                                                                                                                                                                                           XXDEBUG((KERN_DEBUG "bmac: clearing tbusy\n"));
+                                                                                                                                                                                           if (i != bp->tx_fill) {
+                                                                                                                                                                                                   cp = &bp->tx_cmds[i];
+                                                                                                                                                                                                   out_le16(&cp->xfer_status, 0);
+                                                                                                                                                                                                   out_le16(&cp->command, OUTPUT_LAST);
+                                                                                                                                                                                                   out_le32(&td->cmdptr, virt_to_bus(cp));
+                                                                                                                                                                                                   out_le32(&td->control, DBDMA_SET(RUN));
+/*     bmac_set_timeout(dev); */
+                                                                                                                                                                                                   XXDEBUG((KERN_DEBUG "bmac: starting %d\n", i));
+                                                                                                                                                                                           }
+
+                                                                                                                                                                                           /* turn it back on */
+                                                                                                                                                                                           oldConfig = bmread(dev, RXCFG);             
+                                                                                                                                                                                           bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); 
+                                                                                                                                                                                           oldConfig = bmread(dev, TXCFG);             
+                                                                                                                                                                                           bmwrite(dev, TXCFG, oldConfig | TxMACEnable );  
+
+                                                                                                                                                                                           restore_flags(flags);
+                                                                                                                                                                                   }
+
+#if 0
+                                                                                                                                                                                           static void dump_dbdma(volatile struct dbdma_cmd *cp,int count)
+                                                                                                                                                                                           {
+                                                                                                                                                                                                   int i,*ip;
+       
+                                                                                                                                                                                                   for (i=0;i< count;i++)
+                                                                                                                                                                                                   {
+                                                                                                                                                                                                           ip = (int*)(cp+i);
+       
+                                                                                                                                                                                                           printk("dbdma req 0x%x addr 0x%x baddr 0x%x xfer/res 0x%x\n",
+                                                                                                                                                                                                                  ld_le32(ip+0),
+                                                                                                                                                                                                                  ld_le32(ip+1),
+                                                                                                                                                                                                                  ld_le32(ip+2),
+                                                                                                                                                                                                                  ld_le32(ip+3));
+                                                                                                                                                                                                   }
+
+                                                                                                                                                                                           }
+#endif
+
+                                                                                                                                                                                                   static int
+                                                                                                                                                                                                   bmac_proc_info ( char *buffer, char **start, off_t offset, int length, int dummy)
+                                                                                                                                                                                                   {
+                                                                                                                                                                                                           int len = 0;
+                                                                                                                                                                                                           off_t pos   = 0;
+                                                                                                                                                                                                           off_t begin = 0;
+                                                                                                                                                                                                           int i;
+
+                                                                                                                                                                                                           if (bmac_devs == NULL) return (-ENOSYS);
+
+                                                                                                                                                                                                           len += sprintf(buffer, "BMAC counters & registers\n");
+
+                                                                                                                                                                                                           for (i = 0; i<N_REG_ENTRIES; i++) {
+                                                                                                                                                                                                                   len += sprintf(buffer + len, "%s: %#08x\n",
+                                                                                                                                                                                                                                  reg_entries[i].name,
+                                                                                                                                                                                                                                  bmread(bmac_devs, reg_entries[i].reg_offset));
+                                                                                                                                                                                                                   pos = begin + len;
+    
+                                                                                                                                                                                                                   if (pos < offset) {
+                                                                                                                                                                                                                           len = 0;
+                                                                                                                                                                                                                           begin = pos;
+                                                                                                                                                                                                                   }
+    
+                                                                                                                                                                                                                   if (pos > offset+length) break;
+                                                                                                                                                                                                           }
+  
+                                                                                                                                                                                                           *start = buffer + (offset - begin);
+                                                                                                                                                                                                           len -= (offset - begin);
+  
+                                                                                                                                                                                                           if (len > length) len = length;
+  
+                                                                                                                                                                                                           return len;
+                                                                                                                                                                                                   }
diff --git a/drivers/net/bmac.h b/drivers/net/bmac.h
new file mode 100644 (file)
index 0000000..df3b93d
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * mace.h - definitions for the registers in the "Big Mac"
+ *  Ethernet controller found in PowerMac G3 models.
+ *
+ * Copyright (C) 1998 Randy Gobbel.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/* The "Big MAC" appears to have some parts in common with the Sun "Happy Meal"
+ * (HME) controller.  See sunhme.h
+ */
+
+/* register offsets */
+
+/* global status and control */
+#define        XIFC            0x000   /* low-level interface control */
+#      define  TxOutputEnable  0x0001 /* output driver enable */
+#      define  XIFLoopback     0x0002 /* Loopback-mode XIF enable */
+#      define  MIILoopback     0x0004 /* Loopback-mode MII enable */
+#      define  MIILoopbackBits 0x0006
+#      define  MIIBuffDisable  0x0008 /* MII receive buffer disable */
+#      define  SQETestEnable   0x0010 /* SQE test enable */
+#      define  SQETimeWindow   0x03e0 /* SQE time window */
+#      define  XIFLanceMode    0x0010 /* Lance mode enable */
+#      define  XIFLanceIPG0    0x03e0 /* Lance mode IPG0 */
+#define        TXFIFOCSR       0x100   /* transmit FIFO control */
+#      define  TxFIFOEnable    0x0001
+#define        TXTH            0x110   /* transmit threshold */
+#      define  TxThreshold     0x0004
+#define RXFIFOCSR      0x120   /* receive FIFO control */
+#      define  RxFIFOEnable    0x0001
+#define MEMADD         0x130   /* memory address, unknown function */
+#define MEMDATAHI      0x140   /* memory data high, presently unused in driver */
+#define MEMDATALO      0x150   /* memory data low, presently unused in driver */
+#define XCVRIF         0x160   /* transceiver interface control */
+#      define  COLActiveLow    0x0002
+#      define  SerialMode      0x0004
+#      define  ClkBit          0x0008
+#      define  LinkStatus      0x0100
+#define CHIPID          0x170   /* chip ID */
+#define        MIFCSR          0x180   /* ??? */
+#define        SROMCSR         0x190   /* SROM control */
+#      define  ChipSelect      0x0001
+#      define  Clk             0x0002
+#define TXPNTR         0x1a0   /* transmit pointer */
+#define        RXPNTR          0x1b0   /* receive pointer */
+#define        STATUS          0x200   /* status--reading this clears it */
+#define        INTDISABLE      0x210   /* interrupt enable/disable control */
+/* bits below are the same in both STATUS and INTDISABLE registers */
+#      define  FrameReceived   0x00000001 /* Received a frame */
+#      define  RxFrameCntExp   0x00000002 /* Receive frame counter expired */
+#      define  RxAlignCntExp   0x00000004 /* Align-error counter expired */
+#      define  RxCRCCntExp     0x00000008 /* CRC-error counter expired */
+#      define  RxLenCntExp     0x00000010 /* Length-error counter expired */
+#      define  RxOverFlow      0x00000020 /* Receive FIFO overflow */
+#      define  RxCodeViolation 0x00000040 /* Code-violation counter expired */
+#      define  SQETestError    0x00000080 /* Test error in XIF for SQE */
+#      define  FrameSent       0x00000100 /* Transmitted a frame */
+#      define  TxUnderrun      0x00000200 /* Transmit FIFO underrun */
+#      define  TxMaxSizeError  0x00000400 /* Max-packet size error */
+#      define  TxNormalCollExp 0x00000800 /* Normal-collision counter expired */
+#      define  TxExcessCollExp 0x00001000 /* Excess-collision counter expired */
+#      define  TxLateCollExp   0x00002000 /* Late-collision counter expired */
+#      define  TxNetworkCollExp 0x00004000 /* First-collision counter expired */
+#      define  TxDeferTimerExp 0x00008000 /* Defer-timer expired */
+#      define  RxFIFOToHost    0x00010000 /* Data moved from FIFO to host */
+#      define  RxNoDescriptors 0x00020000 /* No more receive descriptors */
+#      define  RxDMAError      0x00040000 /* Error during receive DMA */
+#      define  RxDMALateErr    0x00080000 /* Receive DMA, data late */
+#      define  RxParityErr     0x00100000 /* Parity error during receive DMA */
+#      define  RxTagError      0x00200000 /* Tag error during receive DMA */
+#      define  TxEOPError      0x00400000 /* Tx descriptor did not have EOP set */
+#      define  MIFIntrEvent    0x00800000 /* MIF is signaling an interrupt */
+#      define  TxHostToFIFO    0x01000000 /* Data moved from host to FIFO  */
+#      define  TxFIFOAllSent   0x02000000 /* Transmitted all packets in FIFO */
+#      define  TxDMAError      0x04000000 /* Error during transmit DMA */
+#      define  TxDMALateError  0x08000000 /* Late error during transmit DMA */
+#      define  TxParityError   0x10000000 /* Parity error during transmit DMA */
+#      define  TxTagError      0x20000000 /* Tag error during transmit DMA */
+#      define  PIOError        0x40000000 /* PIO access got an error */
+#      define  PIOParityError  0x80000000 /* PIO access got a parity error  */
+#      define  DisableAll      0xffffffff
+#      define  EnableAll       0x00000000
+/* #   define  NormalIntEvents ~(FrameReceived | FrameSent | TxUnderrun) */
+#      define  EnableNormal    ~(FrameReceived | FrameSent)
+#      define  EnableErrors    (FrameReceived | FrameSent)
+#      define  RxErrorMask     (RxFrameCntExp | RxAlignCntExp | RxCRCCntExp | \
+                                RxLenCntExp | RxOverFlow | RxCodeViolation)
+#      define  TxErrorMask     (TxUnderrun | TxMaxSizeError | TxExcessCollExp | \
+                                TxLateCollExp | TxNetworkCollExp | TxDeferTimerExp)
+
+/* transmit control */
+#define        TXRST           0x420   /* transmit reset */
+#      define  TxResetBit      0x0001
+#define        TXCFG           0x430   /* transmit configuration control*/
+#      define  TxMACEnable     0x0001 /* output driver enable */
+#      define  TxSlowMode      0x0020 /* enable slow mode */
+#      define  TxIgnoreColl    0x0040 /* ignore transmit collisions */
+#      define  TxNoFCS         0x0080 /* do not emit FCS */
+#      define  TxNoBackoff     0x0100 /* no backoff in case of collisions */
+#      define  TxFullDuplex    0x0200 /* enable full-duplex */
+#      define  TxNeverGiveUp   0x0400 /* don't give up on transmits */
+#define IPG1           0x440   /* Inter-packet gap 1 */
+#define IPG2           0x450   /* Inter-packet gap 2 */
+#define ALIMIT         0x460   /* Transmit attempt limit */
+#define SLOT           0x470   /* Transmit slot time */
+#define PALEN          0x480   /* Size of transmit preamble */
+#define PAPAT          0x490   /* Pattern for transmit preamble */
+#define TXSFD          0x4a0   /* Transmit frame delimiter */
+#define JAM            0x4b0   /* Jam size */
+#define TXMAX          0x4c0   /* Transmit max pkt size */
+#define TXMIN          0x4d0   /* Transmit min pkt size */
+#define PAREG          0x4e0   /* Count of transmit peak attempts */
+#define DCNT           0x4f0   /* Transmit defer timer */
+#define NCCNT          0x500   /* Transmit normal-collision counter */
+#define NTCNT          0x510   /* Transmit first-collision counter */
+#define EXCNT          0x520   /* Transmit excess-collision counter */
+#define LTCNT          0x530   /* Transmit late-collision counter */
+#define RSEED          0x540   /* Transmit random number seed */
+#define TXSM           0x550   /* Transmit state machine */
+
+/* receive control */
+#define RXRST          0x620   /* receive reset */
+#      define  RxResetValue    0x0000
+#define RXCFG          0x630   /* receive configuration control */
+#      define  RxMACEnable     0x0001 /* receiver overall enable */
+#      define  RxCFGReserved   0x0004
+#      define  RxPadStripEnab  0x0020 /* enable pad byte stripping */
+#      define  RxPromiscEnable 0x0040 /* turn on promiscuous mode */
+#      define  RxNoErrCheck    0x0080 /* disable receive error checking */
+#      define  RxCRCNoStrip    0x0100 /* disable auto-CRC-stripping */
+#      define  RxRejectOwnPackets 0x0200 /* don't receive our own packets */
+#      define  RxGrpPromisck   0x0400 /* enable group promiscuous mode */
+#      define  RxHashFilterEnable 0x0800 /* enable hash filter */
+#      define  RxAddrFilterEnable 0x1000 /* enable address filter */
+#define RXMAX          0x640   /* Max receive packet size */
+#define RXMIN          0x650   /* Min receive packet size */
+#define MADD2          0x660   /* our enet address, high part */
+#define MADD1          0x670   /* our enet address, middle part */
+#define MADD0          0x680   /* our enet address, low part */
+#define FRCNT          0x690   /* receive frame counter */
+#define LECNT          0x6a0   /* Receive excess length error counter */
+#define AECNT          0x6b0   /* Receive misaligned error counter */
+#define FECNT          0x6c0   /* Receive CRC error counter */
+#define RXSM           0x6d0   /* Receive state machine */
+#define RXCV           0x6e0   /* Receive code violation */
+
+#define BHASH3         0x700   /* multicast hash register */
+#define BHASH2         0x710   /* multicast hash register */
+#define BHASH1         0x720   /* multicast hash register */
+#define BHASH0         0x730   /* multicast hash register */
+
+#define AFR2           0x740   /* address filtering setup? */
+#define AFR1           0x750   /* address filtering setup? */
+#define AFR0           0x760   /* address filtering setup? */
+#define AFCR           0x770   /* address filter compare register? */
+#      define  EnableAllCompares 0x0fff
+
+/* bits in XIFC */
diff --git a/drivers/net/daynaport.c b/drivers/net/daynaport.c
new file mode 100644 (file)
index 0000000..e15ade7
--- /dev/null
@@ -0,0 +1,603 @@
+/* mac_ns8390.c: A Macintosh 8390 based ethernet driver for linux. */
+/*
+       Derived from code:
+       
+       Written 1993-94 by Donald Becker.
+
+       Copyright 1993 United States Government as represented by the
+       Director, National Security Agency.
+
+       This software may be used and distributed according to the terms
+       of the GNU Public License, incorporated herein by reference.
+
+           TODO:
+
+           The block output routines may be wrong for non Dayna
+           cards
+
+           Reading MAC addresses
+*/
+
+static const char *version =
+       "mac_ns8390.c:v0.01 7/5/97 Alan Cox (Alan.Cox@linux.org)\n";
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/nubus.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include "8390.h"
+
+int ns8390_probe1(struct device *dev, int word16, char *name, int id, int prom);
+
+static int ns8390_open(struct device *dev);
+static void ns8390_no_reset(struct device *dev);
+static int ns8390_close_card(struct device *dev);
+
+static void interlan_reset(struct device *dev);
+
+static void dayna_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
+                                               int ring_page);
+static void dayna_block_input(struct device *dev, int count,
+                                                 struct sk_buff *skb, int ring_offset);
+static void dayna_block_output(struct device *dev, int count,
+                                                       const unsigned char *buf, const start_page);
+
+static void sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
+                                               int ring_page);
+static void sane_block_input(struct device *dev, int count,
+                                                 struct sk_buff *skb, int ring_offset);
+static void sane_block_output(struct device *dev, int count,
+                                                       const unsigned char *buf, const start_page);
+
+\f
+#define WD_START_PG    0x00    /* First page of TX buffer */
+#define WD03_STOP_PG   0x20    /* Last page +1 of RX ring */
+#define WD13_STOP_PG   0x40    /* Last page +1 of RX ring */
+
+
+#define DAYNA_MAC_BASE         0xf0007
+#define DAYNA_8390_BASE                0x80000 /* 3 */
+#define DAYNA_8390_MEM         0x00000
+#define DAYNA_MEMSIZE          0x04000 /* First word of each long ! */
+
+#define APPLE_8390_BASE                0xE0000
+#define APPLE_8390_MEM         0xD0000
+#define APPLE_MEMSIZE          8192    /* FIXME: need to dynamically check */
+
+#define KINETICS_8390_BASE     0x80003
+#define KINETICS_8390_MEM      0x00000
+#define KINETICS_MEMSIZE       8192    /* FIXME: need to dynamically check */
+
+static int test_8390(volatile char *ptr, int scale)
+{
+       int regd;
+       int v;
+       
+       if(nubus_hwreg_present(&ptr[0x00])==0)
+               return -EIO;
+       if(nubus_hwreg_present(&ptr[0x0D<<scale])==0)
+               return -EIO;
+       if(nubus_hwreg_present(&ptr[0x0D<<scale])==0)
+               return -EIO;
+       ptr[0x00]=E8390_NODMA+E8390_PAGE1+E8390_STOP;
+       regd=ptr[0x0D<<scale];
+       ptr[0x0D<<scale]=0xFF;
+       ptr[0x00]=E8390_NODMA+E8390_PAGE0;
+       v=ptr[0x0D<<scale];
+       if(ptr[0x0D<<scale]!=0)
+       {
+               ptr[0x0D<<scale]=regd;
+               return -ENODEV;
+       }
+/*     printk("NS8390 found at %p scaled %d\n", ptr,scale);*/
+       return 0;
+}
+/*
+ *    Identify the species of NS8390 card/driver we need
+ */
+
+#define NS8390_DAYNA           1
+#define NS8390_INTERLAN                2
+#define NS8390_KINETICS                3
+#define NS8390_APPLE           4
+#define NS8390_FARALLON                5
+#define NS8390_ASANTE          6
+
+int ns8390_ident(struct nubus_type *nb)
+{
+       /* It appears anything with a software type of 0 is an apple
+          compatible - even if the hardware matches others */
+          
+       if(nb->DrSW==0x0001 || nb->DrSW==0x0109 || nb->DrSW==0x0000 || nb->DrSW==0x0100)
+               return NS8390_APPLE;
+       
+       /* Dayna ex Kinetics board */
+       if(nb->DrHW==0x0103)
+               return NS8390_DAYNA;
+
+       /* Asante board */
+       if(nb->DrHW==0x0104)
+               return NS8390_ASANTE;
+       if(nb->DrHW==0x0100)
+               return NS8390_INTERLAN;
+       if(nb->DrHW==0x0106)
+               return NS8390_KINETICS;
+       if(nb->DrSW==0x010C)
+               return NS8390_FARALLON;
+       return -1;
+}
+
+/*
+ *    Probe for 8390 cards.  
+ *    The ns8390_probe1() routine initializes the card and fills the
+ *    station address field. On entry base_addr is set, irq is set
+ *    (These come from the nubus probe code). dev->mem_start points
+ *    at the memory ring, dev->mem_end gives the end of it.
+ */
+
+int ns8390_probe(struct nubus_device_specifier *d, int slot, struct nubus_type *match)
+{
+       struct device *dev;
+       volatile unsigned short *i;
+       volatile unsigned char *p;
+       int plen;
+       int id;
+
+       if(match->category!=NUBUS_CAT_NETWORK || match->type!=1)
+               return -ENODEV;         
+       /* Ok so it is an ethernet network device */
+       if((id=ns8390_ident(match))==-1)
+       {
+               printk("Ethernet but type unknown %d\n",match->DrHW);
+               return -ENODEV;
+       }
+       dev = init_etherdev(0, 0);
+       if(dev==NULL)
+               return -ENOMEM;
+
+       /*
+        *      Dayna specific init
+        */
+       if(id==NS8390_DAYNA)
+       {
+               dev->base_addr=(int)(nubus_slot_addr(slot)+DAYNA_8390_BASE);
+               dev->mem_start=(int)(nubus_slot_addr(slot)+DAYNA_8390_MEM);
+               dev->mem_end=dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */
+       
+               printk("daynaport: testing board: ");
+
+               printk("memory - ");    
+       
+               i=(void *)dev->mem_start;
+               memset((void *)i,0xAA, DAYNA_MEMSIZE);
+               while(i<(volatile unsigned short *)dev->mem_end)
+               {
+                       if(*i!=0xAAAA)
+                               goto membad;
+                       *i=0x5555;
+                       if(*i!=0x5555)
+                               goto membad;
+                       i+=2;   /* Skip a word */
+               }
+
+               printk("controller - ");
+       
+               p=(void *)dev->base_addr;
+               plen=0;
+       
+               while(plen<0x3FF00)
+               {
+                       if(test_8390(p,0)==0)
+                               break;
+                       if(test_8390(p,1)==0)
+                               break;
+                       if(test_8390(p,2)==0)
+                               break;
+                       if(test_8390(p,3)==0)
+                               break;
+                       plen++;
+                       p++;
+               }
+               if(plen==0x3FF00)
+                       goto membad;
+               printk("OK\n");
+               dev->irq=slot;
+               if(ns8390_probe1(dev, 0, "dayna", id, -1)==0)
+               return 0;
+       }
+       /* Apple, Farallon, Asante */
+       if(id==NS8390_APPLE|| id==NS8390_FARALLON || id==NS8390_ASANTE)
+       {
+               dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE);
+               dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM);
+               dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */
+               dev->irq=slot;
+               printk("apple/clone: testing board: ");
+
+               printk("memory - ");            
+
+               i=(void *)dev->mem_start;
+               memset((void *)i,0xAA, DAYNA_MEMSIZE);
+               while(i<(volatile unsigned short *)dev->mem_end)
+               {
+                       if(*i!=0xAAAA)
+                               goto membad;
+                       *i=0x5555;
+                       if(*i!=0x5555)
+                               goto membad;
+                       i+=2;   /* Skip a word */
+               }
+               printk("OK\n");
+
+               if(id==NS8390_FARALLON)
+               {
+                       if(ns8390_probe1(dev, 1, "farallon", id, -1)==0)
+                               return 0;
+               }
+               else
+               {
+                       if(ns8390_probe1(dev, 1, "apple/clone", id, -1)==0)
+                           return 0;
+               }
+       }
+       /* Interlan */
+       if(id==NS8390_INTERLAN)
+       {
+               /* As apple and asante */
+               dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE);
+               dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM);
+               dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */
+               dev->irq=slot;
+               if(ns8390_probe1(dev, 1, "interlan", id, -1)==0)
+                       return 0;
+       }
+       /* Kinetics */
+       if(id==NS8390_KINETICS)
+       {
+               dev->base_addr=(int)(nubus_slot_addr(slot)+KINETICS_8390_BASE);
+               dev->mem_start=(int)(nubus_slot_addr(slot)+KINETICS_8390_MEM);
+               dev->mem_end=dev->mem_start+KINETICS_MEMSIZE; /* 8K it seems */
+               dev->irq=slot;
+               if(ns8390_probe1(dev, 0, "kinetics", id, -1)==0)
+                       return 0;
+       }
+       kfree(dev);
+       return -ENODEV;
+membad:
+       printk("failed.\n");
+       kfree(dev);
+       return -ENODEV;
+}
+
+int ns8390_probe1(struct device *dev, int word16, char *model_name, int type, int promoff)
+{
+       static unsigned version_printed = 0;
+
+       static unsigned char fwrd4_offsets[16]={
+               0,      4,      8,      12,
+               16,     20,     24,     28,
+               32,     36,     40,     44,
+               48,     52,     56,     60
+       };
+       static unsigned char back4_offsets[16]={
+               60,     56,     52,     48,
+               44,     40,     36,     32,
+               28,     24,     20,     16,
+               12,     8,      4,      0
+       };
+
+       unsigned char *prom=((unsigned char *)nubus_slot_addr(dev->irq))+promoff;
+
+       if (ei_debug  &&  version_printed++ == 0)
+               printk(version);
+       
+       /* Snarf the interrupt now.  There's no point in waiting since we cannot
+          share a slot! and the board will usually be enabled. */
+       if (nubus_request_irq(dev->irq, dev, ei_interrupt)) 
+       {
+               printk (" unable to get nubus IRQ %d.\n", dev->irq);
+               return EAGAIN;
+       }
+       
+       /* Allocate dev->priv and fill in 8390 specific dev fields. */
+       if (ethdev_init(dev)) 
+       {       
+               printk (" unable to get memory for dev->priv.\n");
+               nubus_free_irq(dev->irq);
+               return -ENOMEM;
+       }
+
+       /* OK, we are certain this is going to work.  Setup the device. */
+
+       ei_status.name = model_name;
+       ei_status.word16 = word16;
+       ei_status.tx_start_page = WD_START_PG;
+       ei_status.rx_start_page = WD_START_PG + TX_PAGES;
+
+       dev->rmem_start = dev->mem_start + TX_PAGES*256;
+       ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
+       dev->rmem_end = dev->mem_end;
+       
+       if(promoff==-1)         /* Use nubus resources ? */
+       {
+               if(nubus_ethernet_addr(dev->irq /* slot */, dev->dev_addr))
+               {
+                 printk("mac_ns8390: MAC address not in resources!\n");
+                 return -ENODEV;
+               }
+       }
+       else                    /* Pull it off the card */
+       {
+               int i=0;
+               int x=1;
+               /* These should go in the end I hope */
+               if(type==NS8390_DAYNA)
+                       x=2;
+               if(type==NS8390_INTERLAN)
+                       x=4;
+               while(i<6)
+               {
+                       dev->dev_addr[i]=*prom;
+                       prom+=x;
+                       if(i)
+                               printk(":");
+                       printk("%02X",dev->dev_addr[i++]);
+               }
+       }
+
+       printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
+                  model_name, dev->irq, dev->mem_start, dev->mem_end-1);
+
+       switch(type)
+       {
+               case NS8390_DAYNA:      /* Dayna card */
+                       /* 16 bit, 4 word offsets */
+                       ei_status.reset_8390 = &ns8390_no_reset;
+                       ei_status.block_input = &dayna_block_input;
+                       ei_status.block_output = &dayna_block_output;
+                       ei_status.get_8390_hdr = &dayna_get_8390_hdr;
+                       ei_status.reg_offset = fwrd4_offsets;
+                       break;
+               case NS8390_APPLE:      /* Apple/Asante/Farallon */
+               case NS8390_FARALLON:
+               case NS8390_ASANTE:
+                       /*      16 bit card, register map is reversed */
+                       ei_status.reset_8390 = &ns8390_no_reset;
+                       ei_status.block_input = &sane_block_input;
+                       ei_status.block_output = &sane_block_output;
+                       ei_status.get_8390_hdr = &sane_get_8390_hdr;
+                       ei_status.reg_offset = back4_offsets;
+                       break;
+               case NS8390_INTERLAN:   /* Interlan */
+                       /*      16 bit card, map is forward */
+                       ei_status.reset_8390 = &interlan_reset;
+                       ei_status.block_input = &sane_block_input;
+                       ei_status.block_output = &sane_block_output;
+                       ei_status.get_8390_hdr = &sane_get_8390_hdr;
+                       ei_status.reg_offset = back4_offsets;
+                       break;
+               case NS8390_KINETICS:   /* Kinetics */
+                       /*      8bit card, map is forward */
+                       ei_status.reset_8390 = &ns8390_no_reset;
+                       ei_status.block_input = &sane_block_input;
+                       ei_status.block_output = &sane_block_output;
+                       ei_status.get_8390_hdr = &sane_get_8390_hdr;
+                       ei_status.reg_offset = back4_offsets;
+                       break;
+               default:
+                       panic("Detected a card I can't drive - whoops\n");
+       }
+       dev->open = &ns8390_open;
+       dev->stop = &ns8390_close_card;
+
+       NS8390_init(dev, 0);
+
+       return 0;
+}
+
+static int ns8390_open(struct device *dev)
+{
+       ei_open(dev);
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+static void ns8390_no_reset(struct device *dev)
+{
+       if (ei_debug > 1) 
+               printk("Need to reset the NS8390 t=%lu...", jiffies);
+       ei_status.txing = 0;
+       if (ei_debug > 1) printk("reset not supported\n");
+       return;
+}
+
+static int ns8390_close_card(struct device *dev)
+{
+       if (ei_debug > 1)
+               printk("%s: Shutting down ethercard.\n", dev->name);
+       ei_close(dev);
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+struct nubus_device_specifier nubus_8390={
+       ns8390_probe,
+       NULL
+};
+
+
+/*
+ *    Interlan Specific Code Starts Here
+ */
+
+static void interlan_reset(struct device *dev)
+{
+       unsigned char *target=nubus_slot_addr(dev->irq);
+       if (ei_debug > 1) 
+       printk("Need to reset the NS8390 t=%lu...", jiffies);
+       ei_status.txing = 0;
+       /* This write resets the card */
+       target[0xC0000]=0;
+       if (ei_debug > 1) printk("reset complete\n");
+       return;
+}
+
+/*
+ *    Daynaport code (some is used by other drivers)
+ */
+
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+   we don't need to be concerned with ring wrap as the header will be at
+   the start of a page, so we optimize accordingly. */
+
+
+/* Block input and output are easy on shared memory ethercards, and trivial
+   on the Daynaport card where there is no choice of how to do it.
+   The only complications are that the ring buffer wraps.
+*/
+
+static void dayna_cpu_memcpy(struct device *dev, void *to, int from, int count)
+{
+       volatile unsigned short *ptr;
+       unsigned short *target=to;
+       from<<=1;       /* word, skip overhead */
+       ptr=(unsigned short *)(dev->mem_start+from);
+       while(count>=2)
+       {
+               *target++=*ptr++;       /* Copy and */
+               ptr++;                  /* Cruft and */
+               count-=2;
+       }
+       /*
+        *      Trailing byte ?
+        */
+       if(count)
+       {
+               /* Big endian */
+               unsigned short v=*ptr;
+               *((char *)target)=v>>8;
+       }
+}
+
+static void cpu_dayna_memcpy(struct device *dev, int to, const void *from, int count)
+{
+       volatile unsigned short *ptr;
+       const unsigned short *src=from;
+       to<<=1; /* word, skip overhead */
+       ptr=(unsigned short *)(dev->mem_start+to);
+       while(count>=2)
+       {
+               *ptr++=*src++;          /* Copy and */
+               ptr++;                  /* Cruft and */
+               count-=2;
+       }
+       /*
+        *      Trailing byte ?
+        */
+       if(count)
+       {
+               /* Big endian */
+               unsigned short v=*src;
+               *((char *)ptr)=v>>8;
+       }
+}
+
+static void dayna_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+       unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
+       dayna_cpu_memcpy(dev, (void *)hdr, hdr_start, 4);
+       /* Register endianism - fix here rather than 8390.c */
+       hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
+}
+
+static void dayna_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+       unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+       unsigned long xfer_start = xfer_base+dev->mem_start;
+
+       /*
+        *      Note the offset maths is done in card memory space which
+        *      is word per long onto our space.
+        */
+        
+       if (xfer_start + count > dev->rmem_end) 
+       {
+               /* We must wrap the input move. */
+               int semi_count = dev->rmem_end - xfer_start;
+               dayna_cpu_memcpy(dev, skb->data, xfer_base, semi_count);
+               count -= semi_count;
+               dayna_cpu_memcpy(dev, skb->data + semi_count, 
+                       dev->rmem_start - dev->mem_start, count);
+       }
+       else
+       {
+               dayna_cpu_memcpy(dev, skb->data, xfer_base, count);
+       }
+}
+
+static void dayna_block_output(struct device *dev, int count, const unsigned char *buf,
+                               int start_page)
+{
+       long shmem = (start_page - WD_START_PG)<<8;
+       
+       cpu_dayna_memcpy(dev, shmem, buf, count);
+}
+
+/*
+ *     Cards with full width memory
+ */
+
+
+static void sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+       unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
+       memcpy((void *)hdr, (char *)dev->mem_start+hdr_start, 4);
+       /* Register endianism - fix here rather than 8390.c */
+       hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
+}
+
+static void sane_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+       unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+       unsigned long xfer_start = xfer_base+dev->mem_start;
+
+       if (xfer_start + count > dev->rmem_end) 
+       {
+               /* We must wrap the input move. */
+               int semi_count = dev->rmem_end - xfer_start;
+               memcpy(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
+               count -= semi_count;
+               memcpy(skb->data + semi_count, 
+                       (char *)dev->rmem_start, count);
+       }
+       else
+       {
+               memcpy(skb->data, (char *)dev->mem_start+xfer_base, count);
+       }
+}
+
+static void sane_block_output(struct device *dev, int count, const unsigned char *buf,
+                               int start_page)
+{
+       long shmem = (start_page - WD_START_PG)<<8;
+       
+       memcpy((char *)dev->mem_start+shmem, buf, count);
+}
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c daynaport.c"
+ *  version-control: t
+ *  tab-width: 4
+ *  kept-new-versions: 5
+ * End:
+ */
index 54a7ac5ef447d1e74008cb8bca004bbca82db4c1..b26a1bfc01165e869f03781db77e8e7e3068e16e 100644 (file)
@@ -1106,6 +1106,8 @@ hardware_send_packet(struct device *dev, void *buf, short length)
                        dev->tbusy = 0;
                }
 
+               lp->stats.tx_bytes += length;
+
                if (net_debug > 5)
                        printk("eepro: exiting hardware_send_packet routine.\n");
                return;
@@ -1164,6 +1166,7 @@ eepro_rx(struct device *dev)
                        skb->protocol = eth_type_trans(skb,dev);
                        netif_rx(skb);
                        lp->stats.rx_packets++;
+                       lp->stats.rx_bytes += rcv_size;
                }
                else { /* Not sure will ever reach here,
                          I set the 595 to discard bad received frames */
index 648ac8c7ab29c135b5f882b76fc89e8a7d9a0712..527cd044336ee9a46440c246d88598820ef03ea4 100644 (file)
  *     Changes by Christopher Turcksin <wabbit@rtfc.demon.co.uk>
  *     + Now compiles ok as a module again.
  *
- *     Changes by Paul Norton (pnorton@cts.com) :
+ *     Changes by Paul Norton (p.norton@computer.org) :
  *      + moved the header manipulation code in tr_tx and tr_rx to
  *        net/802/tr.c. (July 12 1997)
+ *      + add retry and timeout on open if cable disconnected. (May 5 1998)
  *      + lifted 2000 byte mtu limit. now depends on shared-RAM size.
  *        May 25 1998)
  */
@@ -929,9 +930,12 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
                                                              DPRINTK("No signal detected for Auto Speed Detection.\n");
                                                      else if (open_error_code==0x11)
                                                      {
-                                                             ti->open_status=FAILURE;
-                                                             DPRINTK("Ring broken/disconnected.\n");
-                                                             wake_up(&ti->wait_for_reset);
+                                                             if (ti->retry_count--) 
+                                                                     DPRINTK("Ring broken/disconnected, retrying...\n");
+                                                             else {
+                                                                     DPRINTK("Ring broken/disconnected, open failed.\n");
+                                                                     ti->open_status = FAILURE;
+                                                             }
                                                      }
                                                      else DPRINTK("Unrecoverable error: error code = %04x.\n",
                                                                   open_error_code);
index 6768a351fdf97ac5c5a73244f3ad3ea7f9151f76..07990773151b06489f811e63b3bc3e904747e9dc 100644 (file)
@@ -7,6 +7,7 @@
 #define TR_RESET_INTERVAL (HZ/20) /* 5 on PC = 50 ms */
 #define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */
 #define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */
+#define TR_RETRIES 6            /* number of open retries */ 
 
 #define TR_ISA 1
 #define TR_MCA 2
@@ -215,6 +216,7 @@ struct tok_info {
         struct timer_list tr_timer;
        unsigned char ring_speed;
        __u32 func_addr;
+       unsigned int retry_count;
 };
 
 /* token ring adapter commands */
index bc5f6895bd756ad8f4fa3674b609fa9f67ed5970..5a7d1fee51b1fded7af581833a165f8b5d241dae 100644 (file)
@@ -326,8 +326,7 @@ __initfunc(int lance_init(void))
            struct pci_dev *pdev = NULL;
                if (lance_debug > 1)
                        printk("lance.c: PCI is present, checking for devices...\n");
-               while (pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev)) {
-                       unsigned char pci_bus, pci_device_fn;
+               while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev))) {
                        unsigned int pci_ioaddr;
                        unsigned short pci_command;
 
index ea836aaa0f43971851ddcce171515d236850e925..1c7f3b9bca7899b47c81d71fbaf531ac7a0d5306 100644 (file)
@@ -573,6 +573,7 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        if ((fs & XMTSV) == 0) {
            printk(KERN_ERR "mace: xmtfs not valid! (fs=%x xc=%d ds=%x)\n",
                   fs, xcount, dstat);
+           return;
        }
        cp = mp->tx_cmds + NCMDS_TX * i;
        stat = ld_le16(&cp->xfer_status);
@@ -765,7 +766,14 @@ static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
                if (frame_status & RS_FCSERR)
                    ++mp->stats.rx_crc_errors;
            } else {
-               nb -= 8;
+               /* Mace feature AUTO_STRIP_RCV is on by default, dropping the
+                * FCS on frames with 802.3 headers. This means that Ethernet 
+                * frames have 8 extra octets at the end, while 802.3 frames 
+                * have only 4. We need to correctly account for this. */
+               if (*(unsigned short *)(data+12) < 1536) /* 802.3 header */
+                   nb -= 4;
+               else    /* Ethernet header; mace includes FCS */
+                   nb -= 8;
                skb_put(skb, nb);
                skb->dev = dev;
                skb->protocol = eth_type_trans(skb, dev);
index 52d3a5089b3006779692b3ce462b32487bec8cbd..bdc46d635e36ad66241afb0a3a3faa55243c476e 100644 (file)
@@ -1044,27 +1044,11 @@ static inline int myri_ether_init(struct device *dev, struct linux_sbus_device *
        dev->hard_start_xmit = &myri_start_xmit;
        dev->get_stats = &myri_get_stats;
        dev->set_multicast_list = &myri_set_multicast;
-       dev->irq = sdev->irqs[0].pri;
+       dev->irq = sdev->irqs[0];
        dev->dma = 0;
 
        /* Register interrupt handler now. */
        DET(("Requesting MYRIcom IRQ line.\n"));
-#ifdef __sparc_v9__
-       if(sparc_cpu_model == sun4u) {
-               struct devid_cookie dcookie;
-
-               dcookie.real_dev_id = dev;
-               dcookie.imap = dcookie.iclr = 0;
-               dcookie.pil = -1;
-               dcookie.bus_cookie = sdev->my_bus;
-               if(request_irq(dev->irq, &myri_interrupt,
-                              (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
-                              "MyriCOM Ethernet", &dcookie)) {
-                       printk("MyriCOM: Cannot register interrupt handler.\n");
-                       return ENODEV;
-               }
-       } else
-#endif
        if(request_irq(dev->irq, &myri_interrupt,
                       SA_SHIRQ, "MyriCOM Ethernet", (void *) dev)) {
                printk("MyriCOM: Cannot register interrupt handler.\n");
index 4341a34496189b0fed212ccca502f3884db222b4..bcadd467fd5b193c1b3c94cac521b46108a38d39 100644 (file)
@@ -574,6 +574,7 @@ plip_receive_packet(struct device *dev, struct net_local *nl,
                /* Inform the upper layer for the arrival of a packet. */
                rcv->skb->protocol=eth_type_trans(rcv->skb, dev);
                netif_rx(rcv->skb);
+               nl->enet_stats.rx_bytes += rcv->length.h;
                nl->enet_stats.rx_packets++;
                rcv->skb = NULL;
                if (net_debug > 2)
@@ -741,6 +742,7 @@ plip_send_packet(struct device *dev, struct net_local *nl,
                              &snd->nibble, snd->checksum))
                        return TIMEOUT;
 
+               nl->enet_stats.tx_bytes += snd->skb->len;
                dev_kfree_skb(snd->skb);
                nl->enet_stats.tx_packets++;
                snd->state = PLIP_PK_DONE;
index 6dbaec6d2ee3cae4e7676968d4d0f0f82d1d36bb..b571dc28c1f6dae9942e8eb4cf45329a16291ee0 100644 (file)
@@ -372,6 +372,7 @@ static int
 seeq8005_send_packet(struct sk_buff *skb, struct device *dev)
 {
        int ioaddr = dev->base_addr;
+       struct net_local *lp = (struct net_local *)dev->priv;
 
        if (dev->tbusy) {
                /* If we get here, some higher level has decided we are broken.
@@ -397,6 +398,7 @@ seeq8005_send_packet(struct sk_buff *skb, struct device *dev)
 
                hardware_send_packet(dev, buf, length); 
                dev->trans_start = jiffies;
+               lp->stats.tx_bytes += length;
        }
        dev_kfree_skb (skb);
 
@@ -547,6 +549,7 @@ seeq8005_rx(struct device *dev)
                        skb->protocol=eth_type_trans(skb,dev);
                        netif_rx(skb);
                        lp->stats.rx_packets++;
+                       lp->stats.rx_bytes += pkt_len;
                }
        } while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN));
 
index d05f113f27ee2955945a3e2da718a7ed4bc01287..ac6736cabfb44451111489a38c1f7292c94e4b95 100644 (file)
@@ -1250,6 +1250,8 @@ static int SK_send_packet(struct sk_buff *skb, struct device *dev)
            */
           dev->tbusy = 0;
        }
+
+       p->stats.tx_bytes += skb->len;
     }
     dev_kfree_skb(skb);
     return 0;  
@@ -1585,6 +1587,7 @@ static void SK_rxintr(struct device *dev)
 
            writeb(RX_OWN, rmdp->u.s.status);
            p->stats.rx_packets++;
+           p->stats.rx_bytes += len;
 
 
            p->rmdnum++;
index 8edb8706cb0c00ad10054e5d4875bd259d747c89..243ba687217258e48cdcaa6157598112cb0f02f8 100644 (file)
@@ -430,6 +430,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct device *dev)
        lp->tda[(lp->cur_tx-1) % SONIC_TDS_MASK].link &= ~SONIC_END_OF_LINKS;
     
     lp->cur_tx++;
+    lp->stats.tx_bytes += length;
     
     if (sonic_debug > 2)
       printk("sonic_send_packet: issueing Tx command\n");
@@ -610,6 +611,7 @@ sonic_rx(struct device *dev)
            skb->protocol=eth_type_trans(skb,dev);
            netif_rx(skb);                      /* pass the packet to upper layers */
            lp->stats.rx_packets++;
+           lp->stats.rx_bytes += pkt_len;
            
        } else {
            /* This should only happen, if we enable accepting broken packets. */
index c9273d538ee17dd778c57ce6afd9538ba30a7ff2..53bafee5548f10673470b1762d26a7bbf42551e4 100644 (file)
@@ -2098,6 +2098,7 @@ static void pci_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs
 }
 #endif
 
+#ifndef __sparc_v9__
 static void sun4c_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        struct device *dev            = (struct device *) dev_id;
@@ -2141,6 +2142,7 @@ static void sun4c_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *re
        dev->interrupt = 0;
        HMD(("done\n"));
 }
+#endif
 
 static int happy_meal_open(struct device *dev)
 {
@@ -2148,6 +2150,7 @@ static int happy_meal_open(struct device *dev)
        int res;
 
        HMD(("happy_meal_open: "));
+#ifndef __sparc_v9__
        if(sparc_cpu_model == sun4c) {
                if(request_irq(dev->irq, &sun4c_happy_meal_interrupt,
                               SA_SHIRQ, "HAPPY MEAL", (void *) dev)) {
@@ -2155,47 +2158,26 @@ static int happy_meal_open(struct device *dev)
                        printk("happy meal: Can't order irq %d to go.\n", dev->irq);
                        return -EAGAIN;
                }
-       }
-#ifdef __sparc_v9__
-       else if(sparc_cpu_model == sun4u) {
-               struct devid_cookie dcookie;
-
+       } else
+#else
 #ifdef CONFIG_PCI
-               if(hp->happy_flags & HFLAG_PCI) {
-                       if(request_irq(dev->irq, &pci_happy_meal_interrupt,
-                                      SA_SHIRQ, "HAPPY MEAL (PCI)", dev)) {
-                               HMD(("EAGAIN\n"));
-                               printk("happy_meal(PCI: Can't order irq %d to go.\n",
-                                      dev->irq);
-                               return -EAGAIN;
-                       }
-                       goto v9_done;
-               }
-#endif
-               dcookie.real_dev_id = dev;
-               dcookie.imap = dcookie.iclr = 0;
-               dcookie.pil = -1;
-               dcookie.bus_cookie = hp->happy_sbus_dev->my_bus;
-               if(request_irq(dev->irq, &happy_meal_interrupt,
-                              (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
-                              "HAPPY MEAL", &dcookie)) {
-                       HMD(("EAGAIN\n"));
-                       printk("happy_meal(SBUS): Can't order irq %d to go.\n",
-                              dev->irq);
+       if(hp->happy_flags & HFLAG_PCI) {
+               if(request_irq(dev->irq, &pci_happy_meal_interrupt,
+                              SA_SHIRQ, "HAPPY MEAL (PCI)", dev)) {
+               HMD(("EAGAIN\n"));
+               printk("happy_meal(PCI: Can't order irq %s to go.\n",
+                      __irq_itoa(dev->irq));
                        return -EAGAIN;
                }
-#ifdef CONFIG_PCI
-       v9_done:
+       } else
 #endif
-       }
 #endif
-       else {
-               if(request_irq(dev->irq, &happy_meal_interrupt,
-                              SA_SHIRQ, "HAPPY MEAL", (void *) dev)) {
-                       HMD(("EAGAIN\n"));
-                       printk("happy meal: Can't order irq %d to go.\n", dev->irq);
-                       return -EAGAIN;
-               }
+       if(request_irq(dev->irq, &happy_meal_interrupt,
+                      SA_SHIRQ, "HAPPY MEAL", (void *)dev)) {
+               HMD(("EAGAIN\n"));
+               printk("happy_meal(SBUS): Can't order irq %s to go.\n",
+                      __irq_itoa(dev->irq));
+               return -EAGAIN;
        }
        HMD(("Init happy timer\n"));
        init_timer(&hp->happy_timer);
@@ -2594,7 +2576,7 @@ static inline int happy_meal_ether_init(struct device *dev, struct linux_sbus_de
        dev->get_stats = &happy_meal_get_stats;
        dev->set_multicast_list = &happy_meal_set_multicast;
 
-       dev->irq = sdev->irqs[0].pri;
+       dev->irq = sdev->irqs[0];
        dev->dma = 0;
        ether_setup(dev);
 #ifdef MODULE
index c51bc4b19f7575cc8a0a6e892b4a4be35faef4f8..b0bfeb81399aec3dbd208da64540034f0f976559 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.75 1998/04/24 12:29:50 davem Exp $
+/* $Id: sunlance.c,v 1.79 1998/06/04 09:54:58 jj Exp $
  * lance.c: Linux/Sparc/Lance driver
  *
  *     Written 1995, 1996 by Miguel de Icaza
@@ -672,39 +672,11 @@ static int lance_open (struct device *dev)
 
        last_dev = dev;
 
-#ifdef __sparc_v9__
-       if (sparc_cpu_model == sun4u) {
-               struct devid_cookie dcookie;
-
-               dcookie.real_dev_id = dev;
-               dcookie.imap = dcookie.iclr = 0;
-               dcookie.pil = -1;
-               dcookie.bus_cookie = lp->sbus;
-               if(request_irq(dev->irq, &lance_interrupt,
-                              (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
-                              lancestr, &dcookie)) {
-                       printk ("Lance: Can't get irq %d\n", dev->irq);
-                       return -EAGAIN;
-               }
-       }
-#else
-       if (sparc_cpu_model == sun4d) {
-               struct devid_cookie dcookie;
-
-               dcookie.real_dev_id = dev;
-               dcookie.bus_cookie = (void *)dev->base_addr;
-               if(request_irq(dev->irq, &lance_interrupt,
-                              (SA_SHIRQ | SA_DCOOKIE),
-                              lancestr, &dcookie)) {
-                       printk ("Lance: Can't get irq %d\n", dev->irq);
-                       return -EAGAIN;
-               }
-       } else if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ,
+       if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ,
                         lancestr, (void *) dev)) {
-               printk ("Lance: Can't get irq %d\n", dev->irq);
+               printk ("Lance: Can't get irq %s\n", __irq_itoa(dev->irq));
                return -EAGAIN;
        }
-#endif 
 
        /* Stop the Lance */
        ll->rap = LE_CSR0;
@@ -1124,7 +1096,7 @@ no_link_test:
        dev->get_stats = &lance_get_stats;
        dev->set_multicast_list = &lance_set_multicast;
 
-       dev->irq = (unsigned char) sdev->irqs [0].pri;
+       dev->irq = sdev->irqs[0];
 
        dev->dma = 0;
        ether_setup (dev);
@@ -1166,7 +1138,7 @@ __initfunc(int sparc_lance_probe (struct device *dev))
        if (idprom->id_machtype == (SM_SUN4|SM_4_330)) {
                memset (&sdev, 0, sizeof(sdev));
                sdev.reg_addrs[0].phys_addr = SUN4_300_ETH_PHYSADDR;
-               sdev.irqs[0].pri = 6;
+               sdev.irqs[0] = 6;
                return sparc_lance_init(dev, &sdev, 0, 0);
        }
        return ENODEV;
index 2dd681439950292051807bdd756cbca2c61cf0d9..83b95a72ad484695e40603aa0e878221460f1106 100644 (file)
@@ -1103,7 +1103,7 @@ static inline int qec_ether_init(struct device *dev, struct linux_sbus_device *s
                        qe_devs[i]->hard_start_xmit = qe_start_xmit;
                qe_devs[i]->get_stats = qe_get_stats;
                qe_devs[i]->set_multicast_list = qe_set_multicast;
-               qe_devs[i]->irq = (unsigned char) sdev->irqs[0].pri;
+               qe_devs[i]->irq = sdev->irqs[0];
                qe_devs[i]->dma = 0;
                ether_setup(qe_devs[i]);
        }
@@ -1114,32 +1114,14 @@ static inline int qec_ether_init(struct device *dev, struct linux_sbus_device *s
         * for it now.
         */
        if(sparc_cpu_model == sun4c) {
-               if(request_irq(sdev->irqs[0].pri, &sun4c_qec_interrupt,
+               if(request_irq(sdev->irqs[0], &sun4c_qec_interrupt,
                               SA_SHIRQ, "QuadEther", (void *) qecp)) {
                        printk("QuadEther: Can't register QEC master irq handler.\n");
                        res = EAGAIN;
                        goto qec_free_devs;
                }
-       }
-#ifdef __sparc_v9__
-       else if(sparc_cpu_model == sun4u) {
-               struct devid_cookie dcookie;
-
-               dcookie.real_dev_id = qecp;
-               dcookie.imap = dcookie.iclr = 0;
-               dcookie.pil = -1;
-               dcookie.bus_cookie = sdev->my_bus;
-               if(request_irq(sdev->irqs[0].pri, &qec_interrupt,
-                              (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
-                              "QuadEther", &dcookie)) {
-                       printk("QuadEther: Can't register QEC master irq handler.\n");
-                       res = EAGAIN;
-                       goto qec_free_devs;
-               }
-       }
-#endif
-       else {
-               if(request_irq(sdev->irqs[0].pri, &qec_interrupt,
+       } else {
+               if(request_irq(sdev->irqs[0], &qec_interrupt,
                               SA_SHIRQ, "QuadEther", (void *) qecp)) {
                        printk("QuadEther: Can't register QEC master irq handler.\n");
                        res = EAGAIN;
@@ -1241,7 +1223,7 @@ cleanup_module(void)
                        unregister_netdev(root_qec_dev->qes[i]->dev);
                        kfree(root_qec_dev->qes[i]);
                }
-               free_irq(root_qec_dev->qec_sbus_dev->irqs[0].pri, (void *)root_qec_dev);
+               free_irq(root_qec_dev->qec_sbus_dev->irqs[0], (void *)root_qec_dev);
                kfree(root_qec_dev);
                root_qec_dev = next_qec;
        }
index 214fb7a993e3a8de8b22136d2e0f11f117ca5bab..0c46649d353eab28ef752febea1ccc2ef50a4ac3 100644 (file)
@@ -264,7 +264,7 @@ psa_read(u_long             ioaddr,
 static void
 psa_write(u_long       ioaddr,
          u_short       hacr,
-         int           o,      /* Offset in psa */
+         int           o,      /* Offset in PSA */
          u_char *      b,      /* Buffer in memory */
          int           n)      /* Length of buffer */
 {
@@ -403,7 +403,7 @@ mmc_read(u_long             ioaddr,
  * Get the type of encryption available.
  */
 static inline int
-mmc_encr(u_long                ioaddr) /* i/o port of the card */
+mmc_encr(u_long                ioaddr) /* I/O port of the card */
 {
   int  temp;
 
@@ -420,7 +420,7 @@ mmc_encr(u_long             ioaddr) /* i/o port of the card */
  * I hope this one will be optimally inlined.
  */
 static inline void
-fee_wait(u_long                ioaddr, /* i/o port of the card */
+fee_wait(u_long                ioaddr, /* I/O port of the card */
         int            delay,  /* Base delay to wait for */
         int            number) /* Number of time to wait */
 {
@@ -436,7 +436,7 @@ fee_wait(u_long             ioaddr, /* i/o port of the card */
  * Read bytes from the Frequency EEPROM (frequency select cards).
  */
 static void
-fee_read(u_long                ioaddr, /* i/o port of the card */
+fee_read(u_long                ioaddr, /* I/O port of the card */
         u_short        o,      /* destination offset */
         u_short *      b,      /* data buffer */
         int            n)      /* number of registers */
@@ -471,7 +471,7 @@ fee_read(u_long             ioaddr, /* i/o port of the card */
  * Jean II
  */
 static void
-fee_write(u_long       ioaddr, /* i/o port of the card */
+fee_write(u_long       ioaddr, /* I/O port of the card */
          u_short       o,      /* destination offset */
          u_short *     b,      /* data buffer */
          int           n)      /* number of registers */
@@ -486,7 +486,7 @@ fee_write(u_long    ioaddr, /* i/o port of the card */
   fee_wait(ioaddr, 10, 100);
 
   /* Read the protected register. */
-  printk("Protected 2 : %02X-%02X\n",
+  printk("Protected 2 %02X-%02X\n",
         mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)),
         mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
 #endif /* DOESNT_SEEM_TO_WORK */
@@ -501,7 +501,7 @@ fee_write(u_long    ioaddr, /* i/o port of the card */
   mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n);
   mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
 #ifdef DOESNT_SEEM_TO_WORK     /* disabled */
-  /* Or use : */
+  /* or use: */
   mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR);
 #endif /* DOESNT_SEEM_TO_WORK */
 
@@ -758,7 +758,7 @@ wv_complete(device *        dev,
       /* Read the first transmit buffer */
       obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), (unsigned char *)&tx_status, sizeof(tx_status));
 
-      /* Hack for reconfiguration... */
+      /* Hack for reconfiguration */
       if(tx_status == 0xFFFF)
        if(!wv_config_complete(dev, ioaddr, lp))
          break;        /* Not completed */
@@ -787,7 +787,7 @@ if (lp->tx_n_in_use > 0)
            lp->tx_first_in_use -= NTXBLOCKS * TXBLOCKZ;
        }
 
-      /* Hack for reconfiguration... */
+      /* Hack for reconfiguration */
       if(tx_status == 0xFFFF)
        continue;
 
@@ -921,7 +921,7 @@ wv_82586_reconfig(device *  dev)
 static void
 wv_psa_show(psa_t *    p)
 {
-  printk(KERN_DEBUG "##### WaveLAN psa contents: #####\n");
+  printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n");
   printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
         p->psa_io_base_addr_1,
         p->psa_io_base_addr_2,
@@ -1107,10 +1107,10 @@ wv_scb_show(u_long      ioaddr)
   printk(KERN_DEBUG "status: ");
   printk("stat 0x%x[%s%s%s%s] ",
         (scb.scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA | SCB_ST_RNR)) >> 12,
-        (scb.scb_status & SCB_ST_CX) ? "cmd completion interrupt," : "",
+        (scb.scb_status & SCB_ST_CX) ? "command completion interrupt," : "",
         (scb.scb_status & SCB_ST_FR) ? "frame received," : "",
-        (scb.scb_status & SCB_ST_CNA) ? "cmd unit not active," : "",
-        (scb.scb_status & SCB_ST_RNR) ? "rcv unit not ready," : "");
+        (scb.scb_status & SCB_ST_CNA) ? "command unit not active," : "",
+        (scb.scb_status & SCB_ST_RNR) ? "receiving unit not ready," : "");
   printk("cus 0x%x[%s%s%s] ",
         (scb.scb_status & SCB_ST_CUS) >> 8,
         ((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_IDLE) ? "idle" : "",
@@ -1166,7 +1166,7 @@ wv_ru_show(device *       dev)
   printk(KERN_DEBUG "##### WaveLAN i82586 receiver unit status: #####\n");
   printk(KERN_DEBUG "ru:");
   /*
-   * Not implemented yet...
+   * Not implemented yet
    */
   printk("\n");
 } /* wv_ru_show */
@@ -1335,7 +1335,7 @@ wv_init_info(device *     dev)
 #endif
 
 #ifdef DEBUG_BASIC_SHOW
-  /* Now, let's go for the basic stuff */
+  /* Now, let's go for the basic stuff. */
   printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr);
   for(i = 0; i < WAVELAN_ADDR_SIZE; i++)
     printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
@@ -1353,9 +1353,8 @@ wv_init_info(device *     dev)
     {
       unsigned short   freq;
 
-      /* Ask the EEPROM to read the frequency from the first area */
-      fee_read(ioaddr, 0x00 /* 1st area - frequency... */,
-              &freq, 1);
+      /* Ask the EEPROM to read the frequency from the first area. */
+      fee_read(ioaddr, 0x00, &freq, 1);
 
       /* Print frequency */
       printk(", 2.00, %ld", (freq >> 6) + 2400L);
@@ -1539,16 +1538,16 @@ wavelan_set_mac_address(device *        dev,
   return 0;
 }
 
-#ifdef WIRELESS_EXT    /* if wireless extension exists in the kernel */
+#ifdef WIRELESS_EXT    /* if wireless extensions exist in the kernel */
 
 /*------------------------------------------------------------------*/
 /*
- * Frequency setting (for hardware able of it)
- * It's a bit complicated and you don't really want to look into it...
+ * Frequency setting (for hardware capable of it)
+ * It's a bit complicated and you don't really want to look into it.
  * (called in wavelan_ioctl)
  */
 static inline int
-wv_set_frequency(u_long                ioaddr, /* i/o port of the card */
+wv_set_frequency(u_long                ioaddr, /* I/O port of the card */
                 iw_freq *      frequency)
 {
   const int    BAND_NUM = 10;  /* Number of bands */
@@ -1560,8 +1559,8 @@ wv_set_frequency(u_long           ioaddr, /* i/o port of the card */
   /* Setting by frequency */
   /* Theoretically, you may set any frequency between
    * the two limits with a 0.5 MHz precision. In practice,
-   * I don't want you to have trouble with local
-   * regulations. */
+   * I don't want you to have trouble with local regulations.
+   */
   if((frequency->e == 1) &&
      (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8))
     {
@@ -1587,8 +1586,7 @@ wv_set_frequency(u_long           ioaddr, /* i/o port of the card */
       u_short  table[10];      /* Authorized frequency table */
 
       /* Read the frequency table. */
-      fee_read(ioaddr, 0x71 /* frequency table */,
-              table, 10);
+      fee_read(ioaddr, 0x71, table, 10);
 
 #ifdef DEBUG_IOCTL_INFO
       printk(KERN_DEBUG "Frequency table: ");
@@ -1616,29 +1614,26 @@ wv_set_frequency(u_long         ioaddr, /* i/o port of the card */
       unsigned short   area_verify[16];
       unsigned short   dac_verify[2];
       /* Corresponding gain (in the power adjust value table)
-       * see AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8
-       * & WCIN062D.DOC, page 6.2.9 */
+       * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8
+       * and WCIN062D.DOC, page 6.2.9. */
       unsigned short   power_limit[] = { 40, 80, 120, 160, 0 };
       int              power_band = 0;         /* Selected band */
       unsigned short   power_adjust;           /* Correct value */
 
-      /* Search for the gain */
+      /* Search for the gain. */
       power_band = 0;
       while((freq > power_limit[power_band]) &&
            (power_limit[++power_band] != 0))
        ;
 
       /* Read the first area. */
-      fee_read(ioaddr, 0x00,
-              area, 16);
+      fee_read(ioaddr, 0x00, area, 16);
 
       /* Read the DAC. */
-      fee_read(ioaddr, 0x60,
-              dac, 2);
+      fee_read(ioaddr, 0x60, dac, 2);
 
       /* Read the new power adjust value. */
-      fee_read(ioaddr, 0x6B - (power_band >> 1),
-              &power_adjust, 1);
+      fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust, 1);
       if(power_band & 0x1)
        power_adjust >>= 8;
       else
@@ -1682,15 +1677,13 @@ wv_set_frequency(u_long         ioaddr, /* i/o port of the card */
       fee_write(ioaddr, 0x60,
                dac, 2);
 
-      /* We now should verify here that the writing of the EEPROM was OK. */
+      /* We now should verify here that the writing of the EEPROM went OK. */
 
       /* Reread the first area. */
-      fee_read(ioaddr, 0x00,
-              area_verify, 16);
+      fee_read(ioaddr, 0x00, area_verify, 16);
 
       /* Reread the DAC. */
-      fee_read(ioaddr, 0x60,
-              dac_verify, 2);
+      fee_read(ioaddr, 0x60, dac_verify, 2);
 
       /* Compare. */
       if(memcmp(area, area_verify, 16 * 2) ||
@@ -1710,16 +1703,16 @@ wv_set_frequency(u_long         ioaddr, /* i/o port of the card */
       mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
              MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
 
-      /* Wait until the download is finished */
+      /* Wait until the download is finished. */
       fee_wait(ioaddr, 100, 100);
 
       /* We must now download the power adjust value (gain) to
-       * the synthesizers (from the EEPROM - area 7 - DAC) */
+       * the synthesizers (from the EEPROM - area 7 - DAC). */
       mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61);
       mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
              MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
 
-      /* Wait until the download is finished */
+      /* Wait for the download to finish. */
       fee_wait(ioaddr, 100, 100);
 
 #ifdef DEBUG_IOCTL_INFO
@@ -1745,22 +1738,21 @@ wv_set_frequency(u_long         ioaddr, /* i/o port of the card */
 
 /*------------------------------------------------------------------*/
 /*
- * Give the list of available frequencies
+ * Give the list of available frequencies.
  */
 static inline int
-wv_frequency_list(u_long       ioaddr, /* i/o port of the card */
-                 iw_freq *     list,   /* List of frequency to fill */
+wv_frequency_list(u_long       ioaddr, /* I/O port of the card */
+                 iw_freq *     list,   /* List of frequencies to fill */
                  int           max)    /* Maximum number of frequencies */
 {
   u_short      table[10];      /* Authorized frequency table */
   long         freq = 0L;      /* offset to 2.4 GHz in .5 MHz + 12 MHz */
   int          i;              /* index in the table */
 
-  /* Read the frequency table */
-  fee_read(ioaddr, 0x71 /* frequency table */,
-          table, 10);
+  /* Read the frequency table. */
+  fee_read(ioaddr, 0x71 /* frequency table */, table, 10);
 
-  /* Check all frequencies */
+  /* Check all frequencies. */
   i = 0;
   for(freq = 0; freq < 150; freq++)
     /* Look in the table if the frequency is allowed */
@@ -1837,8 +1829,8 @@ wl_his_gather(device *    dev,
 
 /*------------------------------------------------------------------*/
 /*
- * Perform ioctl:  configuration and information
- * This is here that are treated the wireless extensions (iwconfig)
+ * Perform ioctl for configuration and information.
+ * It is here that the wireless extensions are treated (iwconfig).
  */
 static int
 wavelan_ioctl(struct device *  dev,    /* device on which the ioctl is applied */
@@ -1857,7 +1849,7 @@ wavelan_ioctl(struct device *     dev,    /* device on which the ioctl is applied */
   printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
 #endif
 
-  /* Disable interrupts & save flags */
+  /* Disable interrupts and save flags. */
   x = wv_splhi();
 
   /* Look what is the request */
@@ -1866,21 +1858,21 @@ wavelan_ioctl(struct device *   dev,    /* device on which the ioctl is applied */
       /* --------------- WIRELESS EXTENSIONS --------------- */
 
     case SIOCGIWNAME:
-      strcpy(wrq->u.name, "Wavelan");
+      strcpy(wrq->u.name, "WaveLAN");
       break;
 
     case SIOCSIWNWID:
       /* Set NWID in WaveLAN. */
       if(wrq->u.nwid.on)
        {
-         /* Set NWID in psa */
+         /* Set NWID in psa. */
          psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8;
          psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;
          psa.psa_nwid_select = 0x01;
          psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
                    (unsigned char *)psa.psa_nwid, 3);
 
-         /* Set NWID in mmc */
+         /* Set NWID in mmc. */
          m.w.mmw_netw_id_l = wrq->u.nwid.nwid & 0xFF;
          m.w.mmw_netw_id_h = (wrq->u.nwid.nwid & 0xFF00) >> 8;
          mmc_write(ioaddr, (char *)&m.w.mmw_netw_id_l - (char *)&m,
@@ -1925,9 +1917,8 @@ wavelan_ioctl(struct device *     dev,    /* device on which the ioctl is applied */
        {
          unsigned short        freq;
 
-         /* Ask the EEPROM to read the frequency from the first area */
-         fee_read(ioaddr, 0x00 /* 1st area - frequency... */,
-                  &freq, 1);
+         /* Ask the EEPROM to read the frequency from the first area. */
+         fee_read(ioaddr, 0x00, &freq, 1);
          wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
          wrq->u.freq.e = 1;
        }
@@ -2096,7 +2087,7 @@ wavelan_ioctl(struct device *     dev,    /* device on which the ioctl is applied */
            { SIOCGIPHISTO, 0,      IW_PRIV_TYPE_INT | 16, "gethisto" },
          };
 
-         /* Verify the user buffer */
+         /* Verify the user buffer. */
          ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
                            sizeof(priv));
          if(ret)
@@ -2149,7 +2140,7 @@ wavelan_ioctl(struct device *     dev,    /* device on which the ioctl is applied */
          memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
 
 #ifdef DEBUG_IOCTL_INFO
-         printk(KERN_DEBUG "SetSpy - Set of new addresses is: \n");
+         printk(KERN_DEBUG "SetSpy:  set of new addresses is: \n");
          for(i = 0; i < wrq->u.data.length; i++)
            printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X \n",
                   lp->spy_address[i][0],
@@ -2226,7 +2217,7 @@ wavelan_ioctl(struct device *     dev,    /* device on which the ioctl is applied */
 
 #ifdef HISTOGRAM
     case SIOCSIPHISTO:
-      /* Verif if the user is root */
+      /* Verify that the user is root. */
       if(!suser())
        return -EPERM;
 
@@ -2416,10 +2407,11 @@ wv_packet_read(device *         dev,
       u_char   stats[3];       /* signal level, noise level, signal quality */
 
       /* Read signal level, silence level and signal quality bytes. */
-      /* Note: in the PCMCIA hardware, these are part of the frame. It seems
+      /* Note: in the PCMCIA hardware, these are part of the frame.  It seems
        * that for the ISA hardware, it's nowhere to be found in the frame,
        * so I'm obliged to do this (it has a side effect on /proc/net/wireless).
-       * Any ideas? */
+       * Any ideas?
+       */
       mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
       mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3);
       mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
@@ -2631,14 +2623,14 @@ wv_receive(device *     dev)
  * The principle:
  * Each block contains a transmit command, a NOP command,
  * a transmit block descriptor and a buffer.
- * The CU reads the transmit block which points to the tbd,
- * reads the tbd and the content of the buffer.
- * When it has finished with it, it goes to the next command
+ * The CU read the transmit block which point to the tbd,
+ * read the tbd and the content of the buffer.
+ * When it has finish with it, it goes to the next command
  * which in our case is the NOP. The NOP points on itself,
- * so the CU stops here.
+ * so the CU stop here.
  * When we add the next block, we modify the previous nop
  * to make it point on the new tx command.
- * Simple, isn't it?
+ * Simple, isn't it ?
  *
  * (called in wavelan_packet_xmit())
  */
@@ -2772,8 +2764,8 @@ if (lp->tx_n_in_use > 0)
 /*------------------------------------------------------------------*/
 /*
  * This routine is called when we want to send a packet (NET3 callback)
- * In this routine, we check if the hardware is ready to accept
- * the packet. We also prevent reentrance. Then, we call the function
+ * In this routine, we check if the harware is ready to accept
+ * the packet.  We also prevent reentrance.  Then we call the function
  * to send the packet.
  */
 static int
@@ -2876,7 +2868,7 @@ wv_mmc_init(device *      dev)
       /* Disable encryption */
       psa.psa_encryption_select = 0;
 
-      /* Set to standard values
+      /* Set to standard values:
        * 0x04 for AT,
        * 0x01 for MCA,
        * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document)
@@ -2891,7 +2883,7 @@ wv_mmc_init(device *      dev)
       psa.psa_conf_status |= 1;
 
 #ifdef USE_PSA_CONFIG
-      /* Write the psa */
+      /* Write the psa. */
       psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
                (unsigned char *)psa.psa_nwid, 4);
       psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
@@ -2948,7 +2940,7 @@ wv_mmc_init(device *      dev)
   mmc_write(ioaddr, 0, (u_char *)&m, sizeof(m));
 
   /* The following code starts the modem of the 2.00 frequency
-   * selectable cards at power on. It's not strictly needed for the
+   * selectable cards at power on.  It's not strictly needed for the
    * following boots.
    * The original patch was by Joe Finney for the PCMCIA driver, but
    * I've cleaned it up a bit and added documentation.
index 2e92c798eaa8add14701be3c25aea42713e8dc60..ca67dbf6659a9879bc21144050a5343be605ba30 100644 (file)
@@ -1,34 +1,34 @@
 /*
- *     Wavelan ISA driver
+ *     WaveLAN ISA driver
  *
  *             Jean II - HPLB '96
  *
  * Reorganisation and extension of the driver.
- * Original copyrigth follow. See wavelan.p.h for details.
+ * Original copyright follows. See wavelan.p.h for details.
  *
- * This file contain the declarations of the Wavelan hardware. Note that
- * the Wavelan ISA include a i82586 controler (see definitions in
+ * This file contains the declarations for the WaveLAN hardware. Note that
+ * the WaveLAN ISA includes a i82586 controller (see definitions in
  * file i82586.h).
  *
- * The main difference between the ISA hardware and the pcmcia one is
- * the Ethernet Controler (i82586 instead of i82593).
- * The i82586 allow multiple transmit buffers. The PSA need to be accessed
+ * The main difference between the ISA hardware and the PCMCIA one is
+ * the Ethernet controller (i82586 instead of i82593).
+ * The i82586 allows multiple transmit buffers.  The PSA needs to be accessed
  * through the host interface.
  */
 
 #ifndef _WAVELAN_H
 #define        _WAVELAN_H
 
-/* The detection of the wavelan card is made by reading the MAC
- * address from the card and checking it. If you have a non AT&T
- * product (OEM, like DEC RoamAbout, or Digital Ocean, Epson, ...),
- * you might need to modify this part to accomodate your hardware...
+/* Detection of the WaveLAN card is done by reading the MAC
+ * address from the card and checking it.  If you have a non-AT&T
+ * product (OEM, like DEC RoamAbout, Digital Ocean, or Epson),
+ * you might need to modify this part to accommodate your hardware.
  */
 const char     MAC_ADDRESSES[][3] =
 {
-  { 0x08, 0x00, 0x0E },                /* AT&T Wavelan (standard) & DEC RoamAbout */
-  { 0x08, 0x00, 0x6A },                /* AT&T Wavelan (alternate) */
-  /* Add your card here and send me the patch ! */
+  { 0x08, 0x00, 0x0E },                /* AT&T WaveLAN (standard) & DEC RoamAbout */
+  { 0x08, 0x00, 0x6A },                /* AT&T WaveLAN (alternate) */
+  /* Add your card here and send me the patch! */
 };
 
 #define WAVELAN_ADDR_SIZE      6       /* Size of a MAC address */
@@ -49,7 +49,7 @@ union hacs_u
        unsigned short  hu_command;             /* Command register */
 #define                HACR_RESET              0x0001  /* Reset board */
 #define                HACR_CA                 0x0002  /* Set Channel Attention for 82586 */
-#define                HACR_16BITS             0x0004  /* 16 bits operation (0 => 8bits) */
+#define                HACR_16BITS             0x0004  /* 16-bit operation (0 => 8bits) */
 #define                HACR_OUT0               0x0008  /* General purpose output pin 0 */
                                                /* not used - must be 1 */
 #define                HACR_OUT1               0x0010  /* General purpose output pin 1 */
@@ -112,11 +112,11 @@ struct ha_t
 /************************** MEMORY LAYOUT **************************/
 
 /*
- * Onboard 64k RAM layout.
+ * Onboard 64 k RAM layout.
  * (Offsets from 0x0000.)
  */
-#define OFFSET_RU              0x0000          /* 75 % memory */
-#define OFFSET_CU              0xC000          /* 25 % memory */
+#define OFFSET_RU              0x0000          /* 75% memory */
+#define OFFSET_CU              0xC000          /* 25% memory */
 #define OFFSET_SCB             (OFFSET_ISCP - sizeof(scb_t))
 #define OFFSET_ISCP            (OFFSET_SCP - sizeof(iscp_t))
 #define OFFSET_SCP             I82586_SCP_ADDR
@@ -151,26 +151,26 @@ struct psa_t
   unsigned char        psa_univ_local_sel;     /* [0x1C] Universal Local Selection */
 #define                PSA_UNIVERSAL   0               /* Universal (factory) */
 #define                PSA_LOCAL       1               /* Local */
-  unsigned char        psa_comp_number;        /* [0x1D] Compatability Number: */
-#define                PSA_COMP_PC_AT_915      0       /* PC-AT 915 MHz        */
-#define                PSA_COMP_PC_MC_915      1       /* PC-MC 915 MHz        */
-#define                PSA_COMP_PC_AT_2400     2       /* PC-AT 2.4 GHz        */
-#define                PSA_COMP_PC_MC_2400     3       /* PC-MC 2.4 GHz        */
+  unsigned char        psa_comp_number;        /* [0x1D] Compatibility Number:  */
+#define                PSA_COMP_PC_AT_915      0       /* PC-AT 915 MHz         */
+#define                PSA_COMP_PC_MC_915      1       /* PC-MC 915 MHz         */
+#define                PSA_COMP_PC_AT_2400     2       /* PC-AT 2.4 GHz         */
+#define                PSA_COMP_PC_MC_2400     3       /* PC-MC 2.4 GHz         */
 #define                PSA_COMP_PCMCIA_915     4       /* PCMCIA 915 MHz or 2.0 */
   unsigned char        psa_thr_pre_set;        /* [0x1E] Modem Threshold Preset */
   unsigned char        psa_feature_select;     /* [0x1F] Call code required (1=on) */
 #define                PSA_FEATURE_CALL_CODE   0x01    /* Call code required (Japan) */
-  unsigned char        psa_subband;            /* [0x20] Subband       */
+  unsigned char        psa_subband;            /* [0x20] Subband         */
 #define                PSA_SUBBAND_915         0       /* 915 MHz or 2.0 */
-#define                PSA_SUBBAND_2425        1       /* 2425 MHz     */
-#define                PSA_SUBBAND_2460        2       /* 2460 MHz     */
-#define                PSA_SUBBAND_2484        3       /* 2484 MHz     */
-#define                PSA_SUBBAND_2430_5      4       /* 2430.5 MHz   */
+#define                PSA_SUBBAND_2425        1       /* 2425 MHz       */
+#define                PSA_SUBBAND_2460        2       /* 2460 MHz       */
+#define                PSA_SUBBAND_2484        3       /* 2484 MHz       */
+#define                PSA_SUBBAND_2430_5      4       /* 2430.5 MHz     */
   unsigned char        psa_quality_thr;        /* [0x21] Modem Quality Threshold */
-  unsigned char        psa_mod_delay;          /* [0x22] Modem Delay ??? (reserved) */
+  unsigned char        psa_mod_delay;          /* [0x22] Modem Delay (?) (reserved) */
   unsigned char        psa_nwid[2];            /* [0x23-0x24] Network ID */
-  unsigned char        psa_nwid_select;        /* [0x25] Network ID Select On Off */
-  unsigned char        psa_encryption_select;  /* [0x26] Encryption On Off */
+  unsigned char        psa_nwid_select;        /* [0x25] Network ID Select On/Off */
+  unsigned char        psa_encryption_select;  /* [0x26] Encryption On/Off */
   unsigned char        psa_encryption_key[8];  /* [0x27-0x2E] Encryption Key */
   unsigned char        psa_databus_width;      /* [0x2F] AT bus width select 8/16 */
   unsigned char        psa_call_code[8];       /* [0x30-0x37] (Japan) Call Code */
@@ -183,8 +183,8 @@ struct psa_t
 
 #define        PSA_SIZE        64
 
-/* Calculate offset of a field in the above structure
- * Warning : only even addresses are used */
+/* Calculate offset of a field in the above structure.
+ * Warning:  only even addresses are used. */
 #define        psaoff(p,f)     ((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL))
 
 /******************** MODEM MANAGEMENT INTERFACE ********************/
@@ -196,25 +196,25 @@ typedef struct mmw_t      mmw_t;
 struct mmw_t
 {
   unsigned char        mmw_encr_key[8];        /* encryption key */
-  unsigned char        mmw_encr_enable;        /* enable/disable encryption */
-#define        MMW_ENCR_ENABLE_MODE    0x02    /* Mode of security option */
-#define        MMW_ENCR_ENABLE_EN      0x01    /* Enable security option */
+  unsigned char        mmw_encr_enable;        /* Enable or disable encryption. */
+#define        MMW_ENCR_ENABLE_MODE    0x02    /* mode of security option */
+#define        MMW_ENCR_ENABLE_EN      0x01    /* Enable security option. */
   unsigned char        mmw_unused0[1];         /* unused */
-  unsigned char        mmw_des_io_invert;      /* Encryption option */
-#define        MMW_DES_IO_INVERT_RES   0x0F    /* Reserved */
-#define        MMW_DES_IO_INVERT_CTRL  0xF0    /* Control ??? (set to 0) */
+  unsigned char        mmw_des_io_invert;      /* encryption option */
+#define        MMW_DES_IO_INVERT_RES   0x0F    /* reserved */
+#define        MMW_DES_IO_INVERT_CTRL  0xF0    /* control (?) (set to 0) */
   unsigned char        mmw_unused1[5];         /* unused */
   unsigned char        mmw_loopt_sel;          /* looptest selection */
-#define        MMW_LOOPT_SEL_DIS_NWID  0x40    /* disable NWID filtering */
-#define        MMW_LOOPT_SEL_INT       0x20    /* activate Attention Request */
-#define        MMW_LOOPT_SEL_LS        0x10    /* looptest w/o collision avoidance */
+#define        MMW_LOOPT_SEL_DIS_NWID  0x40    /* Disable NWID filtering. */
+#define        MMW_LOOPT_SEL_INT       0x20    /* Activate Attention Request. */
+#define        MMW_LOOPT_SEL_LS        0x10    /* looptest, no collision avoidance */
 #define MMW_LOOPT_SEL_LT3A     0x08    /* looptest 3a */
 #define        MMW_LOOPT_SEL_LT3B      0x04    /* looptest 3b */
 #define        MMW_LOOPT_SEL_LT3C      0x02    /* looptest 3c */
 #define        MMW_LOOPT_SEL_LT3D      0x01    /* looptest 3d */
   unsigned char        mmw_jabber_enable;      /* jabber timer enable */
   /* Abort transmissions > 200 ms */
-  unsigned char        mmw_freeze;             /* freeze / unfreeeze signal level */
+  unsigned char        mmw_freeze;             /* freeze or unfreeze signal level */
   /* 0 : signal level & qual updated for every new message, 1 : frozen */
   unsigned char        mmw_anten_sel;          /* antenna selection */
 #define MMW_ANTEN_SEL_SEL      0x01    /* direct antenna selection */
@@ -227,7 +227,7 @@ struct mmw_t
   unsigned char        mmw_thr_pre_set;        /* level threshold preset */
   /* Discard all packet with signal < this value (4) */
   unsigned char        mmw_decay_prm;          /* decay parameters */
-  unsigned char        mmw_decay_updat_prm;    /* decay update parameterz */
+  unsigned char        mmw_decay_updat_prm;    /* decay update parameters */
   unsigned char        mmw_quality_thr;        /* quality (z-quotient) threshold */
   /* Discard all packet with quality < this value (3) */
   unsigned char        mmw_netw_id_l;          /* NWID low order byte */
@@ -237,31 +237,31 @@ struct mmw_t
   /* 2.0 Hardware extension - frequency selection support */
   unsigned char        mmw_mode_select;        /* for analog tests (set to 0) */
   unsigned char        mmw_unused3[1];         /* unused */
-  unsigned char        mmw_fee_ctrl;           /* frequency eeprom control */
-#define        MMW_FEE_CTRL_PRE        0x10    /* Enable protected instructions */
-#define        MMW_FEE_CTRL_DWLD       0x08    /* Download eeprom to mmc */
-#define        MMW_FEE_CTRL_CMD        0x07    /* EEprom commands : */
+  unsigned char        mmw_fee_ctrl;           /* frequency EEPROM control */
+#define        MMW_FEE_CTRL_PRE        0x10    /* Enable protected instructions. */
+#define        MMW_FEE_CTRL_DWLD       0x08    /* Download EEPROM to mmc. */
+#define        MMW_FEE_CTRL_CMD        0x07    /* EEPROM commands:  */
 #define        MMW_FEE_CTRL_READ       0x06    /* Read */
 #define        MMW_FEE_CTRL_WREN       0x04    /* Write enable */
-#define        MMW_FEE_CTRL_WRITE      0x05    /* Write data to address */
-#define        MMW_FEE_CTRL_WRALL      0x04    /* Write data to all addresses */
+#define        MMW_FEE_CTRL_WRITE      0x05    /* Write data to address. */
+#define        MMW_FEE_CTRL_WRALL      0x04    /* Write data to all addresses. */
 #define        MMW_FEE_CTRL_WDS        0x04    /* Write disable */
 #define        MMW_FEE_CTRL_PRREAD     0x16    /* Read addr from protect register */
 #define        MMW_FEE_CTRL_PREN       0x14    /* Protect register enable */
-#define        MMW_FEE_CTRL_PRCLEAR    0x17    /* Unprotect all registers */
-#define        MMW_FEE_CTRL_PRWRITE    0x15    /* Write addr in protect register */
+#define        MMW_FEE_CTRL_PRCLEAR    0x17    /* Unprotect all registers. */
+#define        MMW_FEE_CTRL_PRWRITE    0x15    /* Write address in protect register */
 #define        MMW_FEE_CTRL_PRDS       0x14    /* Protect register disable */
-  /* Never issue this command (PRDS) : it's irreversible !!! */
+  /* Never issue the PRDS command:  it's irreversible! */
 
-  unsigned char        mmw_fee_addr;           /* EEprom address */
-#define        MMW_FEE_ADDR_CHANNEL    0xF0    /* Select the channel */
+  unsigned char        mmw_fee_addr;           /* EEPROM address */
+#define        MMW_FEE_ADDR_CHANNEL    0xF0    /* Select the channel. */
 #define        MMW_FEE_ADDR_OFFSET     0x0F    /* Offset in channel data */
 #define        MMW_FEE_ADDR_EN         0xC0    /* FEE_CTRL enable operations */
 #define        MMW_FEE_ADDR_DS         0x00    /* FEE_CTRL disable operations */
 #define        MMW_FEE_ADDR_ALL        0x40    /* FEE_CTRL all operations */
 #define        MMW_FEE_ADDR_CLEAR      0xFF    /* FEE_CTRL clear operations */
 
-  unsigned char        mmw_fee_data_l;         /* Write data to EEprom */
+  unsigned char        mmw_fee_data_l;         /* Write data to EEPROM. */
   unsigned char        mmw_fee_data_h;         /* high octet */
   unsigned char        mmw_ext_ant;            /* Setting for external antenna */
 #define        MMW_EXT_ANT_EXTANT      0x01    /* Select external antenna */
@@ -293,13 +293,13 @@ struct mmr_t
 #define        MMR_DCE_STATUS_LOOPT_IND        0x02    /* loop test indicated */
 #define        MMR_DCE_STATUS_TX_BUSY          0x04    /* transmitter on */
 #define        MMR_DCE_STATUS_JBR_EXPIRED      0x08    /* jabber timer expired */
-  unsigned char        mmr_dsp_id;             /* DSP id (AA = Daedalus rev A) */
+  unsigned char        mmr_dsp_id;             /* DSP ID (AA = Daedalus rev A) */
   unsigned char        mmr_unused2[2];         /* unused */
-  unsigned char        mmr_correct_nwid_l;     /* # of correct NWID's rxd (low) */
-  unsigned char        mmr_correct_nwid_h;     /* # of correct NWID's rxd (high) */
-  /* Warning : Read high order octet first !!! */
-  unsigned char        mmr_wrong_nwid_l;       /* # of wrong NWID's rxd (low) */
-  unsigned char        mmr_wrong_nwid_h;       /* # of wrong NWID's rxd (high) */
+  unsigned char        mmr_correct_nwid_l;     /* # of correct NWIDs rxd (low) */
+  unsigned char        mmr_correct_nwid_h;     /* # of correct NWIDs rxd (high) */
+  /* Warning:  read high-order octet first! */
+  unsigned char        mmr_wrong_nwid_l;       /* # of wrong NWIDs rxd (low) */
+  unsigned char        mmr_wrong_nwid_h;       /* # of wrong NWIDs rxd (high) */
   unsigned char        mmr_thr_pre_set;        /* level threshold preset */
 #define        MMR_THR_PRE_SET         0x3F            /* level threshold preset */
 #define        MMR_THR_PRE_SET_CUR     0x80            /* Current signal above it */
@@ -312,17 +312,17 @@ struct mmr_t
   unsigned char        mmr_sgnl_qual;          /* signal quality */
 #define        MMR_SGNL_QUAL           0x0F            /* signal quality */
 #define        MMR_SGNL_QUAL_ANT       0x80            /* current antenna used */
-  unsigned char        mmr_netw_id_l;          /* NWID low order byte ??? */
+  unsigned char        mmr_netw_id_l;          /* NWID low order byte (?) */
   unsigned char        mmr_unused3[3];         /* unused */
 
   /* 2.0 Hardware extension - frequency selection support */
-  unsigned char        mmr_fee_status;         /* Status of frequency eeprom */
-#define        MMR_FEE_STATUS_ID       0xF0            /* Modem revision id */
+  unsigned char        mmr_fee_status;         /* Status of frequency EEPROM */
+#define        MMR_FEE_STATUS_ID       0xF0            /* Modem revision ID */
 #define        MMR_FEE_STATUS_DWLD     0x08            /* Download in progress */
-#define        MMR_FEE_STATUS_BUSY     0x04            /* EEprom busy */
+#define        MMR_FEE_STATUS_BUSY     0x04            /* EEPROM busy */
   unsigned char        mmr_unused4[1];         /* unused */
-  unsigned char        mmr_fee_data_l;         /* Read data from eeprom (low) */
-  unsigned char        mmr_fee_data_h;         /* Read data from eeprom (high) */
+  unsigned char        mmr_fee_data_l;         /* Read data from EEPROM (low) */
+  unsigned char        mmr_fee_data_h;         /* Read data from EEPROM (high) */
 };
 
 #define        MMR_SIZE        36
index 18320dcc44340801aecd62061fb04aa3f85dabf5..251f2b98e6fa850196df893b8f017efdff835824 100644 (file)
@@ -1,79 +1,79 @@
 /*
- *     Wavelan ISA driver
+ *     WaveLAN ISA driver
  *
  *             Jean II - HPLB '96
  *
  * Reorganisation and extension of the driver.
  *
- * This file contain all definition and declarations necessary for the
- * wavelan isa driver. This file is a private header, so it should
- * be included only on wavelan.c !!!
+ * This file contains all definitions and declarations necessary for the
+ * WaveLAN ISA driver.  This file is a private header, so it should
+ * be included only in wavelan.c!
  */
 
 #ifndef WAVELAN_P_H
 #define WAVELAN_P_H
 
-/************************** DOCUMENTATION **************************/
+/************************** DOCUMENTATION ***************************/
 /*
- * This driver provide a Linux interface to the Wavelan ISA hardware
- * The Wavelan is a product of Lucent ("http://wavelan.netland.nl/").
+ * This driver provides a Linux interface to the WaveLAN ISA hardware.
+ * The WaveLAN is a product of Lucent (http://www.wavelan.com/).
  * This division was formerly part of NCR and then AT&T.
- * Wavelan are also distributed by DEC (RoamAbout), Digital Ocean and
- * Aironet (Arlan). If you have one of those product, you will need to
- * make some changes below...
+ * WaveLANs are also distributed by DEC (RoamAbout), Digital Ocean and
+ * Aironet (Arlan).  If you have one of those products, you will need to
+ * make some changes below.
  *
- * This driver is still a beta software. A lot of bugs have been corrected,
- * a lot of functionalities are implemented, the whole appear pretty stable,
- * but there is still some area of improvement (encryption, performance...).
+ * This driver is still beta software.  A lot of bugs have been corrected,
+ * a lot of functionality is implemented, and the whole appears stable,
+ * but there is still room for improvement (encryption, performance).
  *
- * To know how to use this driver, read the NET3 HOWTO.
- * If you want to exploit the many other fonctionalities, look comments
- * in the code...
+ * To learn how to use this driver, read the NET3 HOWTO.
+ * If you want to exploit the many other functionalities, read the comments
+ * in the code.
  *
- * This driver is the result of the effort of many peoples (see below).
+ * This driver is the result of the effort of many people (see below).
  */
 
 /* ------------------------ SPECIFIC NOTES ------------------------ */
 /*
- * wavelan.o is darn too big
- * -------------------------
- *     That's true ! There is a very simple way to reduce the driver
- *     object by 33% (yes !). Comment out the following line :
+ * wavelan.o is too darned big
+ * ---------------------------
+ *     That's true There is a very simple way to reduce the driver
+ *     object by 33%!  Comment out the following line:
  *             #include <linux/wireless.h>
  *
- * MAC address and hardware detection :
- * ----------------------------------
- *     The detection code of the wavelan chech that the first 3
- *     octets of the MAC address fit the company code. This type of
- *     detection work well for AT&T cards (because the AT&T code is
+ * MAC address and hardware detection:
+ * -----------------------------------
+ *     The detection code for the WaveLAN checks that the first three
+ *     octets of the MAC address fit the company code.  This type of
+ *     detection works well for AT&T cards (because the AT&T code is
  *     hardcoded in wavelan.h), but of course will fail for other
- *     manufacturer.
+ *     manufacturers.
  *
- *     If you are sure that your card is derived from the wavelan,
- *     here is the way to configure it :
+ *     If you are sure that your card is derived from the WaveLAN,
+ *     here is the way to configure it:
  *     1) Get your MAC address
- *             a) With your card utilities (wfreqsel, instconf, ...)
- *             b) With the driver :
+ *             a) With your card utilities (wfreqsel, instconf, etc.)
+ *             b) With the driver:
  *                     o compile the kernel with DEBUG_CONFIG_INFO enabled
  *                     o Boot and look the card messages
  *     2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h)
- *     3) Compile & verify
- *     4) Send me the MAC code - I will include it in the next version...
+ *     3) Compile and verify
+ *     4) Send me the MAC code.  I will include it in the next version.
  *
- * "CU Inactive" message at boot up :
+ * "CU Inactive" message at boot up:
  * -----------------------------------
- *     It seem that there is some weird timings problems with the
- *     Intel microcontroler. In fact, this message is triggered by a
- *     bad reading of the on board ram the first time we read the
- *     control block. If you ignore this message, all is ok (but in
- *     fact, currently, it reset the wavelan hardware).
+ *     It seems that there is some weird timing problem with the
+ *     Intel microcontroller.  In fact, this message is triggered by a
+ *     bad reading of the onboard RAM the first time we read the
+ *     control block.  If you ignore this message, all is OK (but in
+ *     fact, currently, it resets the WaveLAN hardware).
  *
- *     To get rid of that problem, there is two solution. The first
+ *     There are two ways to get rid of that problem.  The first
  *     is to add a dummy read of the scb at the end of
- *     wv_82586_config. The second is to add the timers
+ *     wv_82586_config.  The second is to add the timers
  *     wv_synchronous_cmd and wv_ack (the udelay just after the
- *     waiting loops - seem that the controler is not totally ready
- *     when it say it is !).
+ *     waiting loops--it seems that the controller is not totally ready
+ *     when it says it is).
  *
  *     In the current code, I use the second solution (to be
  *     consistent with the original solution of Bruce Janson).
 
 /* --------------------- WIRELESS EXTENSIONS --------------------- */
 /*
- * This driver is the first one to support "wireless extensions".
- * This set of extensions provide you some way to control the wireless
- * caracteristics of the hardware in a standard way and support for
- * applications for taking advantage of it (like Mobile IP).
+ * This driver is the first to support "wireless extensions".
+ * This set of extensions provides a standard way to control the wireless
+ * characteristics of the hardware.  Applications such as mobile IP may
+ * take advantage of it.
  *
  * You will need to enable the CONFIG_NET_RADIO define in the kernel
  * configuration to enable the wireless extensions (this is the one
 
 /* ---------------------------- FILES ---------------------------- */
 /*
- * wavelan.c :         The actual code for the driver - C functions
+ * wavelan.c:          actual code for the driver:  C functions
  *
- * wavelan.p.h :       Private header : local types / vars for the driver
+ * wavelan.p.h:                private header:  local types and variables for driver
  *
- * wavelan.h :         Description of the hardware interface & structs
+ * wavelan.h:          description of the hardware interface and structs
  *
- * i82586.h :          Description if the Ethernet controler
+ * i82586.h:           description of the Ethernet controller
  */
 
 /* --------------------------- HISTORY --------------------------- */
 /*
- * (Made with information in drivers headers. It may not be accurate,
- * and I garantee nothing except my best effort...)
+ * This is based on information in the drivers' headers. It may not be
+ * accurate, and I guarantee only my best effort.
  *
- * The history of the Wavelan drivers is as complicated as history of
- * the Wavelan itself (NCR -> AT&T -> Lucent).
+ * The history of the WaveLAN drivers is as complicated as the history of
+ * the WaveLAN itself (NCR -> AT&T -> Lucent).
  *
- * All started with Anders Klemets <klemets@paul.rutgers.edu>,
- * writting a Wavelan ISA driver for the MACH microkernel. Girish
+ * It all started with Anders Klemets <klemets@paul.rutgers.edu>
+ * writing a WaveLAN ISA driver for the Mach microkernel.  Girish
  * Welling <welling@paul.rutgers.edu> had also worked on it.
- * Keith Moore modify this for the Pcmcia hardware.
+ * Keith Moore modified this for the PCMCIA hardware.
  * 
- * Robert Morris <rtm@das.harvard.edu> port these two drivers to BSDI
- * and add specific Pcmcia support (there is currently no equivalent
- * of the PCMCIA package under BSD...).
+ * Robert Morris <rtm@das.harvard.edu> ported these two drivers to BSDI
+ * and added specific PCMCIA support (there is currently no equivalent
+ * of the PCMCIA package under BSD).
  *
- * Jim Binkley <jrb@cs.pdx.edu> port both BSDI drivers to freeBSD.
+ * Jim Binkley <jrb@cs.pdx.edu> ported both BSDI drivers to FreeBSD.
  *
- * Bruce Janson <bruce@cs.usyd.edu.au> port the BSDI ISA driver to Linux.
+ * Bruce Janson <bruce@cs.usyd.edu.au> ported the BSDI ISA driver to Linux.
  *
- * Anthony D. Joseph <adj@lcs.mit.edu> started modify Bruce driver
+ * Anthony D. Joseph <adj@lcs.mit.edu> started to modify Bruce's driver
  * (with help of the BSDI PCMCIA driver) for PCMCIA.
- * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work.
+ * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished this work.
  * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
- * correctly 2.00 cards (2.4 GHz with frequency selection).
+ * 2.00 cards correctly (2.4 GHz with frequency selection).
  * David Hinds <dhinds@hyper.stanford.edu> integrated the whole in his
- * Pcmcia package (+ bug corrections).
+ * PCMCIA package (and bug corrections).
  *
  * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
- * patchs to the Pcmcia driver. After, I added code in the ISA driver
+ * patches to the PCMCIA driver.  Later, I added code in the ISA driver
  * for Wireless Extensions and full support of frequency selection
- * cards. Then, I've done the same to the Pcmcia driver + some
- * reorganisation. Finally, I came back to the ISA driver to
- * upgrade it at the same level as the Pcmcia one and reorganise
- * the code
+ * cards.  Then, I did the same to the PCMCIA driver, and did some
+ * reorganisation.  Finally, I came back to the ISA driver to
+ * upgrade it at the same level as the PCMCIA one and reorganise
+ * the code.
  * Loeke Brederveld <lbrederv@wavelan.com> from Lucent has given me
- * much needed informations on the Wavelan hardware.
+ * much needed information on the WaveLAN hardware.
  */
 
-/* The original copyrights and litteratures mention others names and
- * credits. I don't know what there part in this development was...
+/* The original copyrights and literature mention others' names and
+ * credits.  I don't know what their part in this development was.
  */
 
-/* By the way : for the copyright & legal stuff :
- * Almost everybody wrote code under GNU or BSD license (or alike),
- * and want that their original copyright remain somewhere in the
+/* By the way, for the copyright and legal stuff:
+ * almost everybody wrote code under the GNU or BSD license (or similar),
+ * and want their original copyright to remain somewhere in the
  * code (for myself, I go with the GPL).
- * Nobody want to take responsibility for anything, except the fame...
+ * Nobody wants to take responsibility for anything, except the fame.
  */
 
 /* --------------------------- CREDITS --------------------------- */
  * Linux operating system.
  * It is based on other device drivers and information
  * either written or supplied by:
- *     Ajay Bakre (bakre@paul.rutgers.edu),
- *     Donald Becker (becker@cesdis.gsfc.nasa.gov),
- *     Loeke Brederveld (Loeke.Brederveld@Utrecht.NCR.com),
+ *     Ajay Bakre <bakre@paul.rutgers.edu>,
+ *     Donald Becker <becker@cesdis.gsfc.nasa.gov>,
+ *     Loeke Brederveld <Loeke.Brederveld@Utrecht.NCR.com>,
  *     Brent Elphick <belphick@uwaterloo.ca>,
- *     Anders Klemets (klemets@it.kth.se),
- *     Vladimir V. Kolpakov (w@stier.koenig.ru),
- *     Marc Meertens (Marc.Meertens@Utrecht.NCR.com),
- *     Pauline Middelink (middelin@polyware.iaf.nl),
- *     Robert Morris (rtm@das.harvard.edu),
- *     Jean Tourrilhes (jt@hplb.hpl.hp.com),
- *     Girish Welling (welling@paul.rutgers.edu),
+ *     Anders Klemets <klemets@it.kth.se>,
+ *     Vladimir V. Kolpakov <w@stier.koenig.ru>,
+ *     Marc Meertens <Marc.Meertens@Utrecht.NCR.com>,
+ *     Pauline Middelink <middelin@polyware.iaf.nl>,
+ *     Robert Morris <rtm@das.harvard.edu>,
+ *     Jean Tourrilhes <jt@hplb.hpl.hp.com>,
+ *     Girish Welling <welling@paul.rutgers.edu>,
  *     Clark Woodworth <clark@hiway1.exit109.com>
- *     Yongguang Zhang <ygz@isl.hrl.hac.com>...
+ *     Yongguang Zhang <ygz@isl.hrl.hac.com>
  *
  * Thanks go also to:
- *     James Ashton (jaa101@syseng.anu.edu.au),
- *     Alan Cox (iialan@iiit.swan.ac.uk),
- *     Allan Creighton (allanc@cs.usyd.edu.au),
- *     Matthew Geier (matthew@cs.usyd.edu.au),
- *     Remo di Giovanni (remo@cs.usyd.edu.au),
- *     Eckhard Grah (grah@wrcs1.urz.uni-wuppertal.de),
- *     Vipul Gupta (vgupta@cs.binghamton.edu),
- *     Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
- *     Tim Nicholson (tim@cs.usyd.edu.au),
- *     Ian Parkin (ian@cs.usyd.edu.au),
- *     John Rosenberg (johnr@cs.usyd.edu.au),
- *     George Rossi (george@phm.gov.au),
- *     Arthur Scott (arthur@cs.usyd.edu.au),
+ *     James Ashton <jaa101@syseng.anu.edu.au>,
+ *     Alan Cox <iialan@iiit.swan.ac.uk>,
+ *     Allan Creighton <allanc@cs.usyd.edu.au>,
+ *     Matthew Geier <matthew@cs.usyd.edu.au>,
+ *     Remo di Giovanni <remo@cs.usyd.edu.au>,
+ *     Eckhard Grah <grah@wrcs1.urz.uni-wuppertal.de>,
+ *     Vipul Gupta <vgupta@cs.binghamton.edu>,
+ *     Mark Hagan <mhagan@wtcpost.daytonoh.NCR.COM>,
+ *     Tim Nicholson <tim@cs.usyd.edu.au>,
+ *     Ian Parkin <ian@cs.usyd.edu.au>,
+ *     John Rosenberg <johnr@cs.usyd.edu.au>,
+ *     George Rossi <george@phm.gov.au>,
+ *     Arthur Scott <arthur@cs.usyd.edu.au>,
  *     Stanislav Sinyagin <stas@isf.ru>
- *     Peter Storey,
- * for their assistance and advice.
+ *     and Peter Storey for their assistance and advice.
  *
  * Additional Credits:
  *
- * My developpement has been done under Linux 2.0.x (Debian 1.1) with
+ *     My development has been done under Linux 2.0.x (Debian 1.1) with
  *     an HP Vectra XP/60.
  *
  */
 
 /* ------------------------- IMPROVEMENTS ------------------------- */
 /*
- * I proudly present :
+ * I proudly present:
  *
- * Changes mades in first pre-release :
+ * Changes made in first pre-release:
  * ----------------------------------
- *     - Reorganisation of the code, function name change
- *     - Creation of private header (wavelan.p.h)
- *     - Reorganised debug messages
- *     - More comments, history, ...
- *     - mmc_init : configure the PSA if not done
- *     - mmc_init : correct default value of level threshold for pcmcia
- *     - mmc_init : 2.00 detection better code for 2.00 init
+ *     - reorganisation of the code, function name change
+ *     - creation of private header (wavelan.p.h)
+ *     - reorganised debug messages
+ *     - more comments, history, etc.
+ *     - mmc_init configure the PSA if not done
+ *     - mmc_init:  correct default value of level threshold for PCMCIA
+ *     - mmc_init:  2.00 detection better code for 2.00 initialization
  *     - better info at startup
- *     - irq setting (note : this setting is permanent...)
- *     - Watchdog : change strategy (+ solve module removal problems)
- *     - add wireless extensions (ioctl & get_wireless_stats)
+ *     - IRQ setting (note:  this setting is permanent)
+ *     - watchdog:  change strategy (and solve module removal problems)
+ *     - add wireless extensions (ioctl and get_wireless_stats)
  *       get/set nwid/frequency on fly, info for /proc/net/wireless
- *     - More wireless extension : SETSPY and GETSPY
- *     - Make wireless extensions optional
- *     - Private ioctl to set/get quality & level threshold, histogram
- *     - Remove /proc/net/wavelan
- *     - Supress useless stuff from lp (net_local)
+ *     - more wireless extensions:  SETSPY and GETSPY
+ *     - make wireless extensions optional
+ *     - private ioctl to set/get quality and level threshold, histogram
+ *     - remove /proc/net/wavelan
+ *     - suppress useless stuff from lp (net_local)
  *     - kernel 2.1 support (copy_to/from_user instead of memcpy_to/fromfs)
- *     - Add message level (debug stuff in /var/adm/debug & errors not
+ *     - add message level (debug stuff in /var/adm/debug and errors not
  *       displayed at console and still in /var/adm/messages)
  *     - multi device support
- *     - Start fixing the probe (init code)
- *     - More inlines
+ *     - start fixing the probe (init code)
+ *     - more inlines
  *     - man page
- *     - Lot of others minor details & cleanups
- *
- * Changes made in second pre-release :
- * ----------------------------------
- *     - Cleanup init code (probe & module init)
- *     - Better multi device support (module)
- *     - name assignement (module)
+ *     - many other minor details and cleanups
  *
- * Changes made in third pre-release :
- * ---------------------------------
- *     - Be more conservative on timers
- *     - Preliminary support for multicast (I still lack some details...)
+ * Changes made in second pre-release:
+ * -----------------------------------
+ *     - clean up init code (probe and module init)
+ *     - better multiple device support (module)
+ *     - name assignment (module)
  *
- * Changes made in fourth pre-release :
+ * Changes made in third pre-release:
  * ----------------------------------
+ *     - be more conservative on timers
+ *     - preliminary support for multicast (I still lack some details)
+ *
+ * Changes made in fourth pre-release:
+ * -----------------------------------
  *     - multicast (revisited and finished)
- *     - Avoid reset in set_multicast_list (a really big hack)
- *       if somebody could apply this code for other i82586 based driver...
- *     - Share on board memory 75% RU / 25% CU (instead of 50/50)
+ *     - avoid reset in set_multicast_list (a really big hack)
+ *       if somebody could apply this code for other i82586 based drivers
+ *     - share onboard memory 75% RU and 25% CU (instead of 50/50)
  *
- * Changes made for release in 2.1.15 :
- * ----------------------------------
- *     - Change the detection code for multi manufacturer code support
+ * Changes made for release in 2.1.15:
+ * -----------------------------------
+ *     - change the detection code for multi manufacturer code support
  *
- * Changes made for release in 2.1.17 :
- * ----------------------------------
- *     - Update to wireless extensions changes
- *     - Silly bug in card initial configuration (psa_conf_status)
- *
- * Changes made for release in 2.1.27 & 2.0.30 :
- * -------------------------------------------
- *     - Small bug in debug code (probably not the last one...)
- *     - Remove extern kerword for wavelan_probe()
- *     - Level threshold is now a standard wireless extension (version 4 !)
+ * Changes made for release in 2.1.17:
+ * -----------------------------------
+ *     - update to wireless extensions changes
+ *     - silly bug in card initial configuration (psa_conf_status)
+ *
+ * Changes made for release in 2.1.27 & 2.0.30:
+ * --------------------------------------------
+ *     - small bug in debug code (probably not the last one...)
+ *     - remove extern keyword for wavelan_probe()
+ *     - level threshold is now a standard wireless extension (version 4 !)
  *     - modules parameters types (new module interface)
  *
- * Changes made for release in 2.1.36 :
- * ----------------------------------
+ * Changes made for release in 2.1.36:
+ * -----------------------------------
  *     - byte count stats (courtesy of David Hinds)
- *     - Remove dev_tint stuff (courtesy of David Hinds)
- *     - Encryption setting from Brent Elphick (thanks a lot !)
+ *     - remove dev_tint stuff (courtesy of David Hinds)
+ *     - encryption setting from Brent Elphick (thanks a lot!)
  *     - 'ioaddr' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin)
  *
- * Wishes & dreams :
- * ---------------
- *     - Roaming
+ * Wishes & dreams:
+ * ----------------
+ *     - roaming
  */
 
 /***************************** INCLUDES *****************************/
 
 #include <linux/wireless.h>            /* Wireless extensions */
 
-/* Wavelan declarations */
+/* WaveLAN declarations */
 #include       "i82586.h"
 #include       "wavelan.h"
 
 /****************************** DEBUG ******************************/
 
-#undef DEBUG_MODULE_TRACE      /* Module insertion/removal */
-#undef DEBUG_CALLBACK_TRACE    /* Calls made by Linux */
-#undef DEBUG_INTERRUPT_TRACE   /* Calls to handler */
-#undef DEBUG_INTERRUPT_INFO    /* type of interrupt & so on */
+#undef DEBUG_MODULE_TRACE      /* module insertion/removal */
+#undef DEBUG_CALLBACK_TRACE    /* calls made by Linux */
+#undef DEBUG_INTERRUPT_TRACE   /* calls to handler */
+#undef DEBUG_INTERRUPT_INFO    /* type of interrupt and so on */
 #define DEBUG_INTERRUPT_ERROR  /* problems */
-#undef DEBUG_CONFIG_TRACE      /* Trace the config functions */
-#undef DEBUG_CONFIG_INFO       /* What's going on... */
-#define DEBUG_CONFIG_ERRORS    /* Errors on configuration */
-#undef DEBUG_TX_TRACE          /* Transmission calls */
-#undef DEBUG_TX_INFO           /* Header of the transmited packet */
+#undef DEBUG_CONFIG_TRACE      /* Trace the config functions. */
+#undef DEBUG_CONFIG_INFO       /* what's going on */
+#define DEBUG_CONFIG_ERRORS    /* errors on configuration */
+#undef DEBUG_TX_TRACE          /* transmission calls */
+#undef DEBUG_TX_INFO           /* header of the transmitted packet */
 #define DEBUG_TX_ERROR         /* unexpected conditions */
-#undef DEBUG_RX_TRACE          /* Transmission calls */
-#undef DEBUG_RX_INFO           /* Header of the transmited packet */
+#undef DEBUG_RX_TRACE          /* transmission calls */
+#undef DEBUG_RX_INFO           /* header of the transmitted packet */
 #define DEBUG_RX_ERROR         /* unexpected conditions */
-#undef DEBUG_PACKET_DUMP       16      /* Dump packet on the screen */
-#undef DEBUG_IOCTL_TRACE       /* Misc call by Linux */
-#undef DEBUG_IOCTL_INFO                /* Various debug info */
-#define DEBUG_IOCTL_ERROR      /* What's going wrong */
-#define DEBUG_BASIC_SHOW       /* Show basic startup info */
-#undef DEBUG_VERSION_SHOW      /* Print version info */
-#undef DEBUG_PSA_SHOW          /* Dump psa to screen */
-#undef DEBUG_MMC_SHOW          /* Dump mmc to screen */
-#undef DEBUG_SHOW_UNUSED       /* Show also unused fields */
-#undef DEBUG_I82586_SHOW       /* Show i82586 status */
-#undef DEBUG_DEVICE_SHOW       /* Show device parameters */
-
-/* Options */
-#define USE_PSA_CONFIG         /* Use info from the PSA */
-#define IGNORE_NORMAL_XMIT_ERRS        /* Don't bother with normal conditions */
-#undef STRUCT_CHECK            /* Verify padding of structures */
-#undef PSA_CRC                 /* Check CRC in PSA */
-#undef OLDIES                  /* Old code (to redo) */
-#undef RECORD_SNR              /* To redo */
-#undef EEPROM_IS_PROTECTED     /* Doesn't seem to be necessary */
-#define MULTICAST_AVOID                /* Avoid extra multicast (I'm sceptical) */
-
-#ifdef WIRELESS_EXT    /* If wireless extension exist in the kernel */
-/* Warning : these stuff will slow down the driver... */
-#define WIRELESS_SPY           /* Enable spying addresses */
-#undef HISTOGRAM               /* Enable histogram of sig level... */
+#undef DEBUG_PACKET_DUMP       16      /* Dump packet on the screen. */
+#undef DEBUG_IOCTL_TRACE       /* misc. call by Linux */
+#undef DEBUG_IOCTL_INFO                /* various debugging info */
+#define DEBUG_IOCTL_ERROR      /* what's going wrong */
+#define DEBUG_BASIC_SHOW       /* Show basic startup info. */
+#undef DEBUG_VERSION_SHOW      /* Print version info. */
+#undef DEBUG_PSA_SHOW          /* Dump PSA to screen. */
+#undef DEBUG_MMC_SHOW          /* Dump mmc to screen. */
+#undef DEBUG_SHOW_UNUSED       /* Show unused fields too. */
+#undef DEBUG_I82586_SHOW       /* Show i82586 status. */
+#undef DEBUG_DEVICE_SHOW       /* Show device parameters. */
+
+/* Options */
+#define USE_PSA_CONFIG         /* Use info from the PSA. */
+#define IGNORE_NORMAL_XMIT_ERRS        /* Don't bother with normal conditions. */
+#undef STRUCT_CHECK            /* Verify padding of structures. */
+#undef PSA_CRC                 /* Check CRC in PSA. */
+#undef OLDIES                  /* old code (to redo) */
+#undef RECORD_SNR              /* to redo */
+#undef EEPROM_IS_PROTECTED     /* doesn't seem to be necessary */
+#define MULTICAST_AVOID                /* Avoid extra multicast (I'm sceptical). */
+
+#ifdef WIRELESS_EXT    /* If wireless extensions exist in the kernel */
+/* Warning:  this stuff will slow down the driver. */
+#define WIRELESS_SPY           /* Enable spying addresses. */
+#undef HISTOGRAM               /* Enable histogram of signal level. */
 #endif
 
 /************************ CONSTANTS & MACROS ************************/
@@ -364,7 +363,7 @@ static const char   *version        = "wavelan.c : v16 (wireless extensions) 17/4/97\n";
 #endif
 
 /* Watchdog temporisation */
-#define        WATCHDOG_JIFFIES        32      /* TODO: express in HZ. */
+#define        WATCHDOG_JIFFIES        32      /* TODO:  express in HZ. */
 
 /* Macro to get the number of elements in an array */
 #define        NELS(a)                         (sizeof(a) / sizeof(a[0]))
@@ -396,23 +395,23 @@ typedef u_char            mac_addr[WAVELAN_ADDR_SIZE];    /* Hardware address */
 /*
  * Static specific data for the interface.
  *
- * For each network interface, Linux keep data in two structure. "device"
- * keep the generic data (same format for everybody) and "net_local" keep
- * the additional specific data.
+ * For each network interface, Linux keeps data in two structures:  "device"
+ * keeps the generic data (same format for everybody) and "net_local" keeps
+ * additional specific data.
  * Note that some of this specific data is in fact generic (en_stats, for
  * example).
  */
 struct net_local
 {
-  net_local *  next;           /* Linked list of the devices */
-  device *     dev;            /* Reverse link... */
+  net_local *  next;           /* linked list of the devices */
+  device *     dev;            /* reverse link */
   en_stats     stats;          /* Ethernet interface statistics */
-  int          nresets;        /* Number of hw resets */
-  u_char       reconfig_82586; /* Need to reconfigure the controler */
-  u_char       promiscuous;    /* Promiscuous mode */
-  int          mc_count;       /* Number of multicast addresses */
-  timer_list   watchdog;       /* To avoid blocking state */
-  u_short      hacr;           /* Current host interface state */
+  int          nresets;        /* number of hardware resets */
+  u_char       reconfig_82586; /* We need to reconfigure the controller. */
+  u_char       promiscuous;    /* promiscuous mode */
+  int          mc_count;       /* number of multicast addresses */
+  timer_list   watchdog;       /* to avoid blocking state */
+  u_short      hacr;           /* current host interface state */
 
   int          tx_n_in_use;
   u_short      rx_head;
@@ -421,82 +420,83 @@ struct net_local
   u_short      tx_first_in_use;
 
 #ifdef WIRELESS_EXT
-  iw_stats     wstats;         /* Wireless specific stats */
+  iw_stats     wstats;         /* Wireless-specific statistics */
 #endif
 
 #ifdef WIRELESS_SPY
-  int          spy_number;             /* Number of addresses to spy */
-  mac_addr     spy_address[IW_MAX_SPY];        /* The addresses to spy */
-  iw_qual      spy_stat[IW_MAX_SPY];           /* Statistics gathered */
+  int          spy_number;                     /* number of addresses to spy */
+  mac_addr     spy_address[IW_MAX_SPY];        /* the addresses to spy */
+  iw_qual      spy_stat[IW_MAX_SPY];           /* statistics gathered */
 #endif /* WIRELESS_SPY */
+
 #ifdef HISTOGRAM
-  int          his_number;             /* Number of intervals */
-  u_char       his_range[16];          /* Boundaries of interval ]n-1; n] */
-  u_long       his_sum[16];            /* Sum in interval */
+  int          his_number;             /* number of intervals */
+  u_char       his_range[16];          /* boundaries of interval ]n-1; n] */
+  u_long       his_sum[16];            /* sum in interval */
 #endif /* HISTOGRAM */
 };
 
 /**************************** PROTOTYPES ****************************/
 
-/* ----------------------- MISC SUBROUTINES ------------------------ */
+/* ----------------------- MISC. SUBROUTINES ------------------------ */
 static inline unsigned long    /* flags */
        wv_splhi(void);         /* Disable interrupts */
 static inline void
-       wv_splx(unsigned long); /* ReEnable interrupts : flags */
+       wv_splx(unsigned long); /* Enable interrupts:  flags */
 static u_char
        wv_irq_to_psa(int);
 static int
        wv_psa_to_irq(u_char);
 /* ------------------- HOST ADAPTER SUBROUTINES ------------------- */
 static inline u_short          /* data */
-       hasr_read(u_long);      /* Read the host interface : base address */
+       hasr_read(u_long);      /* Read the host interface base address */
 static inline void
-       hacr_write(u_long,      /* Write to host interface : base address */
+       hacr_write(u_long,      /* Write to host interface base address */
                   u_short),    /* data */
        hacr_write_slow(u_long,
                   u_short),
        set_chan_attn(u_long,   /* ioaddr */
-                     u_short), /* hacr */
+                     u_short), /* hacr   */
        wv_hacr_reset(u_long),  /* ioaddr */
        wv_16_off(u_long,       /* ioaddr */
-                 u_short),     /* hacr */
+                 u_short),     /* hacr   */
        wv_16_on(u_long,        /* ioaddr */
-                u_short),      /* hacr */
+                u_short),      /* hacr   */
        wv_ints_off(device *),
        wv_ints_on(device *);
 /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
 static void
-       psa_read(u_long,        /* Read the Parameter Storage Area */
+       psa_read(u_long,        /* Read the Parameter Storage Area. */
                 u_short,       /* hacr */
                 int,           /* offset in PSA */
                 u_char *,      /* buffer to fill */
                 int),          /* size to read */
-       psa_write(u_long,       /* Write to the PSA */
+       psa_write(u_long,       /* Write to the PSA. */
                  u_short,      /* hacr */
-                 int,          /* Offset in psa */
-                 u_char *,     /* Buffer in memory */
-                 int);         /* Length of buffer */
+                 int,          /* offset in PSA */
+                 u_char *,     /* buffer in memory */
+                 int);         /* length of buffer */
 static inline void
-       mmc_out(u_long,         /* Write 1 byte to the Modem Manag Control */
+       mmc_out(u_long,         /* Write 1 byte to the Modem Manag Control. */
                u_short,
                u_char),
-       mmc_write(u_long,       /* Write n bytes to the MMC */
+       mmc_write(u_long,       /* Write n bytes to the MMC. */
                  u_char,
                  u_char *,
                  int);
-static inline u_char           /* Read 1 byte from the MMC */
+static inline u_char           /* Read 1 byte from the MMC. */
        mmc_in(u_long,
               u_short);
 static inline void
-       mmc_read(u_long,        /* Read n bytes from the MMC */
+       mmc_read(u_long,        /* Read n bytes from the MMC. */
                 u_char,
                 u_char *,
                 int),
-       fee_wait(u_long,        /* Wait for frequency EEprom : base address */
-                int,           /* Base delay to wait for */
-                int);          /* Number of time to wait */
+       fee_wait(u_long,        /* Wait for frequency EEPROM:  base address */
+                int,           /* base delay to wait for */
+                int);          /* time to wait */
 static void
-       fee_read(u_long,        /* Read the frequency EEprom : base address */
+       fee_read(u_long,        /* Read the frequency EEPROM:  base address */
                 u_short,       /* destination offset */
                 u_short *,     /* data buffer */
                 int);          /* number of registers */
@@ -539,60 +539,59 @@ static void
        wavelan_set_multicast_list(device *);
 /* ----------------------- PACKET RECEPTION ----------------------- */
 static inline void
-       wv_packet_read(device *,        /* Read a packet from a frame */
+       wv_packet_read(device *,        /* Read a packet from a frame. */
                       u_short,
                       int),
-       wv_receive(device *);   /* Read all packets waiting */
+       wv_receive(device *);   /* Read all packets waiting. */
 /* --------------------- PACKET TRANSMISSION --------------------- */
 static inline void
-       wv_packet_write(device *,       /* Write a packet to the Tx buffer */
+       wv_packet_write(device *,       /* Write a packet to the Tx buffer. */
                        void *,
                        short);
 static int
-       wavelan_packet_xmit(struct sk_buff *,   /* Send a packet */
+       wavelan_packet_xmit(struct sk_buff *,   /* Send a packet. */
                            device *);
 /* -------------------- HARDWARE CONFIGURATION -------------------- */
 static inline int
-       wv_mmc_init(device *),          /* Initialize the modem */
-       wv_ru_start(device *),          /* Start the i82586 receiver unit */
-       wv_cu_start(device *),          /* Start the i82586 command unit */
-       wv_82586_start(device *);       /* Start the i82586 */
+       wv_mmc_init(device *),          /* Initialize the modem. */
+       wv_ru_start(device *),          /* Start the i82586 receiver unit. */
+       wv_cu_start(device *),          /* Start the i82586 command unit. */
+       wv_82586_start(device *);       /* Start the i82586. */
 static void
-       wv_82586_config(device *);      /* Configure the i82586 */
+       wv_82586_config(device *);      /* Configure the i82586. */
 static inline void
        wv_82586_stop(device *);
 static int
-       wv_hw_reset(device *),          /* Reset the wavelan hardware */
+       wv_hw_reset(device *),          /* Reset the WaveLAN hardware. */
        wv_check_ioaddr(u_long,         /* ioaddr */
                        u_char *);      /* mac address (read) */
 /* ---------------------- INTERRUPT HANDLING ---------------------- */
 static void
-       wavelan_interrupt(int,          /* Interrupt handler */
+       wavelan_interrupt(int,          /* interrupt handler */
                          void *,
                          struct pt_regs *);
 static void
-       wavelan_watchdog(u_long);       /* Transmission watchdog */
+       wavelan_watchdog(u_long);       /* transmission watchdog */
 /* ------------------- CONFIGURATION CALLBACKS ------------------- */
 static int
-       wavelan_open(device *),         /* Open the device */
-       wavelan_close(device *),        /* Close the device */
-       wavelan_config(device *);       /* Configure one device */
+       wavelan_open(device *),         /* Open the device. */
+       wavelan_close(device *),        /* Close the device. */
+       wavelan_config(device *);       /* Configure one device. */
 extern int
-       wavelan_probe(device *);        /* See Space.c */
+       wavelan_probe(device *);        /* See Space.c. */
 
 /**************************** VARIABLES ****************************/
 
 /*
- * This is the root of the linked list of wavelan drivers
+ * This is the root of the linked list of WaveLAN drivers
  * It is use to verify that we don't reuse the same base address
- * for two differents drivers and to make the cleanup when
- * removing the module.
+ * for two different drivers and to clean up when removing the module.
  */
 static net_local *     wavelan_list    = (net_local *) NULL;
 
 /*
- * This table is used to translate the psa value to irq number
- * and vice versa...
+ * This table is used to translate the PSA value to IRQ number
+ * and vice versa.
  */
 static u_char  irqvals[]       =
 {
@@ -603,7 +602,7 @@ static u_char       irqvals[]       =
 };
 
 /*
- * Table of the available i/o address (base address) for wavelan
+ * Table of the available I/O addresses (base addresses) for WaveLAN
  */
 static unsigned short  iobase[]        =
 {
@@ -612,7 +611,7 @@ static unsigned short       iobase[]        =
    * controllers.
    * Leave out the others too -- we will always use 0x390 and leave
    * 0x300 for the Ethernet device.
-   * Jean II : 0x3E0 is really fine as well...
+   * Jean II:  0x3E0 is fine as well.
    */
   0x300, 0x390, 0x3E0, 0x3C0
 #endif /* 0 */
index a3d3ea51647f2e73225aad392e5ce8438f4fe3f3..8d7ba08311cb781b3c7645f7fb5b4a5cb432082a 100644 (file)
@@ -1,6 +1,21 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
+ *      26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111
+ *        + Added command line option (rs:[y|n]) to reverse the scan order
+ *          of PCI boards. The default is rs:y, which reverses the BIOS order
+ *          while registering PCI boards. The default value rs:y generates
+ *          the same order of all previous revisions of this driver.
+ *          Pls. note that "BIOS order" might have been reversed itself
+ *          after the 2.1.9x PCI modifications in the linux kernel.
+ *          The rs value is ignored when the explicit list of addresses
+ *          is used by the "eata=port0,port1,..." command line option.
+ *        + Added command line option (et:[y|n]) to force use of extended
+ *          translation (255 heads, 63 sectors) as disk geometry.
+ *          The default is et:n, which uses the disk geometry returned
+ *          by scsicam_bios_param. The default value et:n is compatible with
+ *          all previous revisions of this driver.
+ *
  *      28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104
  *          Increased busy timeout from 10 msec. to 200 msec. while
  *          processing interrupts.
  *  PM3222     -  SmartRAID Adapter for EISA (PM3222W is 16-bit wide SCSI)
  *  PM3224     -  SmartRAID Adapter for PCI  (PM3224W is 16-bit wide SCSI)
  *
+ *  The above list is just an indication: as a matter of fact all DPT
+ *  boards using the EATA/DMA protocol are supported by this driver,
+ *  since they use exactely the same programming interface.
+ *
  *  The DPT PM2001 provides only the EATA/PIO interface and hence is not
  *  supported by this driver.
  *
  *
  *  eh:y  use new scsi code (linux 2.2 only);
  *  eh:n  use old scsi code;
+ *  et:y  force use of extended translation (255 heads, 63 sectors);
+ *  et:n  use disk geometry detected by scsicam_bios_param;
+ *  rs:y  reverse scan order while detecting PCI boards;
+ *  rs:n  use BIOS order while detecting PCI boards;
  *  lc:y  enables linked commands;
  *  lc:n  disables linked commands;
  *  tc:y  enables tagged commands;
  *  tm:3  use only ordered queue tags;
  *  mq:xx set the max queue depth to the value xx (2 <= xx <= 32).
  *
- *  The default value is: "eata=lc:n,tc:n,mq:16,tm:0". An example using
- *  the list of detection probes could be:
- *  "eata=0x7410,0x230,lc:y,tc:n,mq:4,eh:n".
+ *  The default value is: "eata=lc:n,tc:n,mq:16,tm:0,et:n,rs:n".
+ *  An example using the list of detection probes could be:
+ *  "eata=0x7410,0x230,lc:y,tc:n,mq:4,eh:n,et:n".
  *
  *  When loading as a module, parameters can be specified as well.
  *  The above example would be (use 1 in place of y and 0 in place of n):
  *
  *  modprobe eata io_port=0x7410,0x230 linked_comm=1 tagged_comm=0 \
- *                max_queue_depth=4 tag_mode=0 use_new_eh_code=0
+ *                max_queue_depth=4 tag_mode=0 use_new_eh_code=0 \
+ *                ext_tran=0 rev_scan=1
  *
  *  ----------------------------------------------------------------------------
  *  In this implementation, linked commands are designed to work with any DISK
  *        When the driver detects a batch including overlapping requests
  *        (a really rare event) strict serial (pid) order is enforced.
  *  ----------------------------------------------------------------------------
+ *  The extended translation option (et:y) is useful when using large physical
+ *  disks/arrays. It could also be useful when switching between Adaptec boards
+ *  and DPT boards without reformatting the disk.
+ *  When a boot disk is partitioned with extended translation, in order to
+ *  be able to boot it with a DPT board is could be necessary to add to
+ *  lilo.conf additional commands as in the following example:
+ *
+ *  fix-table
+ *  disk=/dev/sda bios=0x80 sectors=63 heads=128 cylindres=546
+ *
+ *  where the above geometry should be replaced with the one reported at
+ *  power up by the DPT controller.
+ *  ----------------------------------------------------------------------------
  *
  *  The boards are named EATA0, EATA1,... according to the detection order.
  *
@@ -330,6 +367,8 @@ MODULE_PARM(link_statistics, "i");
 MODULE_PARM(max_queue_depth, "i");
 MODULE_PARM(tag_mode, "i");
 MODULE_PARM(use_new_eh_code, "i");
+MODULE_PARM(ext_tran, "i");
+MODULE_PARM(rev_scan, "i");
 MODULE_AUTHOR("Dario Ballabio");
 #endif
 
@@ -413,6 +452,7 @@ struct proc_dir_entry proc_scsi_eata2x = {
 #undef  DEBUG_RESET
 #undef  DEBUG_GENERATE_ERRORS
 #undef  DEBUG_GENERATE_ABORTS
+#undef  DEBUG_GEOMETRY
 
 #define MAX_ISA 4
 #define MAX_VESA 0
@@ -663,6 +703,8 @@ static int do_trace = FALSE;
 static int setup_done = FALSE;
 static int link_statistics = 0;
 static int tag_mode = TAG_MIXED;
+static int ext_tran = FALSE;
+static int rev_scan = TRUE;
 
 #if defined(CONFIG_SCSI_EATA_TAGGED_QUEUE)
 static int tagged_comm = TRUE;
@@ -1067,9 +1109,9 @@ __initfunc (static inline int port_detect \
 
    if (j == 0) {
       printk("EATA/DMA 2.0x: Copyright (C) 1994-1998 Dario Ballabio.\n");
-      printk("%s config options -> tc:%c, lc:%c, mq:%d, eh:%c.\n",
-             driver_name, tag_type, YESNO(linked_comm),
-             max_queue_depth, YESNO(use_new_eh_code));
+      printk("%s config options -> tc:%c, lc:%c, mq:%d, eh:%c, rs:%c, et:%c.\n",
+             driver_name, tag_type, YESNO(linked_comm), max_queue_depth,
+             YESNO(use_new_eh_code), YESNO(rev_scan), YESNO(ext_tran));
       }
 
    printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d.\n",
@@ -1132,6 +1174,8 @@ __initfunc (void eata2x_setup(char *str, int *ints)) {
       else if (!strncmp(cur, "mq:", 3))  max_queue_depth = val;
       else if (!strncmp(cur, "ls:", 3))  link_statistics = val;
       else if (!strncmp(cur, "eh:", 3))  use_new_eh_code = val;
+      else if (!strncmp(cur, "et:", 3))  ext_tran = val;
+      else if (!strncmp(cur, "rs:", 3))  rev_scan = val;
 
       if ((cur = strchr(cur, ','))) ++cur;
       }
@@ -1165,8 +1209,8 @@ __initfunc (static void add_pci_ports(void)) {
       if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
              continue;
 
-      /* Reverse the returned address order */
-      io_port[MAX_INT_PARAM + MAX_PCI - k] =
+      /* Order addresses according to rev_scan value */
+      io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] =
              (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
       }
 
@@ -1193,8 +1237,8 @@ __initfunc (static void add_pci_ports(void)) {
       if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
              continue;
 
-      /* Reverse the returned address order */
-      io_port[MAX_INT_PARAM + MAX_PCI - k] =
+      /* Order addresses according to rev_scan value */
+      io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] =
              (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
       }
 
@@ -1846,6 +1890,23 @@ int eata2x_reset(Scsi_Cmnd *SCarg) {
 
 #endif /* new_eh_code */
 
+int eata2x_biosparam(Disk *disk, kdev_t dev, int *dkinfo) {
+   int size = disk->capacity;
+
+   if (ext_tran || (scsicam_bios_param(disk, dev, dkinfo) < 0)) {
+      dkinfo[0] = 255;
+      dkinfo[1] = 63;
+      dkinfo[2] = size / (dkinfo[0] * dkinfo[1]);
+      }
+
+#if defined (DEBUG_GEOMETRY)
+   printk ("%s: biosparam, head=%d, sec=%d, cyl=%d.\n", driver_name,
+           dkinfo[0], dkinfo[1], dkinfo[2]);
+#endif
+
+   return FALSE;
+}
+
 static void sort(unsigned long sk[], unsigned int da[], unsigned int n,
                  unsigned int rev) {
    unsigned int i, j, k, y;
index c45169f65af75d33765eaad9fe980a68530fc802..f1641f42d469269b0143b74f07ac26f13f1de1b8 100644 (file)
@@ -14,8 +14,9 @@ int eata2x_abort(Scsi_Cmnd *);
 int eata2x_old_abort(Scsi_Cmnd *);
 int eata2x_reset(Scsi_Cmnd *);
 int eata2x_old_reset(Scsi_Cmnd *, unsigned int);
+int eata2x_biosparam(Disk *, kdev_t, int *);
 
-#define EATA_VERSION "4.32.00"
+#define EATA_VERSION "4.33.00"
 
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 
@@ -32,7 +33,7 @@ int eata2x_old_reset(Scsi_Cmnd *, unsigned int);
                 eh_device_reset_handler: NULL,                               \
                 eh_bus_reset_handler:    NULL,                               \
                 eh_host_reset_handler:   eata2x_reset,                       \
-                bios_param:              scsicam_bios_param,                 \
+                bios_param:              eata2x_biosparam,                   \
                 this_id:                 7,                                  \
                 unchecked_isa_dma:       1,                                  \
                 use_clustering:          ENABLE_CLUSTERING,                  \
@@ -48,7 +49,7 @@ int eata2x_old_reset(Scsi_Cmnd *, unsigned int);
                 queuecommand:            eata2x_queuecommand,                \
                 abort:                   eata2x_old_abort,                   \
                 reset:                   eata2x_old_reset,                   \
-                bios_param:              scsicam_bios_param,                 \
+                bios_param:              eata2x_biosparam,                   \
                 this_id:                 7,                                  \
                 unchecked_isa_dma:       1,                                  \
                 use_clustering:          ENABLE_CLUSTERING                   \
index 0ebd939576104d48040c73eab5200c9a10126c7b..cad88bc29a731623e6f325ca1f77c4b4fc3323e6 100644 (file)
@@ -1,6 +1,14 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *      26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111
+ *          Added command line option (et:[y|n]) to use the existing
+ *          translation (returned by scsicam_bios_param) as disk geometry.
+ *          The default is et:n, which uses the disk geometry jumpered
+ *          on the board.
+ *          The default value et:n is compatible with all previous revisions
+ *          of this driver.
+ *
  *      28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104
  *          Increased busy timeout from 10 msec. to 200 msec. while
  *          processing interrupts.
  *
  *  eh:y  use new scsi code (linux 2.2 only);
  *  eh:n  use old scsi code;
+ *  et:y  use disk geometry returned by scsicam_bios_param;
+ *  et:n  use disk geometry jumpered on the board;
  *  lc:y  enables linked commands;
  *  lc:n  disables linked commands;
  *  of:y  enables old firmware support;
  *  of:n  disables old firmware support;
  *  mq:xx set the max queue depth to the value xx (2 <= xx <= 8).
  *
- *  The default value is: "u14-34f=lc:n,of:n,mq:8". An example using the list
- *  of detection probes could be: "u14-34f=0x230,0x340,lc:y,of:n,mq:4,eh:n".
+ *  The default value is: "u14-34f=lc:n,of:n,mq:8,et:n".
+ *  An example using the list of detection probes could be:
+ *  "u14-34f=0x230,0x340,lc:y,of:n,mq:4,eh:n,et:n".
  *
  *  When loading as a module, parameters can be specified as well.
  *  The above example would be (use 1 in place of y and 0 in place of n):
  *
  *  modprobe u14-34f io_port=0x230,0x340 linked_comm=1 have_old_firmware=0 \
- *                max_queue_depth=4 use_new_eh_code=0
+ *                max_queue_depth=4 use_new_eh_code=0 ext_tran=0
  *
  *  ----------------------------------------------------------------------------
  *  In this implementation, linked commands are designed to work with any DISK
@@ -314,6 +325,7 @@ MODULE_PARM(have_old_firmware, "i");
 MODULE_PARM(link_statistics, "i");
 MODULE_PARM(max_queue_depth, "i");
 MODULE_PARM(use_new_eh_code, "i");
+MODULE_PARM(ext_tran, "i");
 MODULE_AUTHOR("Dario Ballabio");
 #endif
 
@@ -405,6 +417,7 @@ struct proc_dir_entry proc_scsi_u14_34f = {
 #undef  DEBUG_RESET
 #undef  DEBUG_GENERATE_ERRORS
 #undef  DEBUG_GENERATE_ABORTS
+#undef  DEBUG_GEOMETRY
 
 #define MAX_ISA 3
 #define MAX_VESA 1
@@ -556,6 +569,7 @@ static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
 static int do_trace = FALSE;
 static int setup_done = FALSE;
 static int link_statistics = 0;
+static int ext_tran = FALSE;
 
 #if defined(HAVE_OLD_UX4F_FIRMWARE)
 static int have_old_firmware = TRUE;
@@ -876,9 +890,9 @@ __initfunc (static inline int port_detect \
 
    if (j == 0) {
       printk("UltraStor 14F/34F: Copyright (C) 1994-1998 Dario Ballabio.\n");
-      printk("%s config options -> of:%c, lc:%c, mq:%d, eh:%c.\n",
+      printk("%s config options -> of:%c, lc:%c, mq:%d, eh:%c, et:%c.\n",
              driver_name, YESNO(have_old_firmware), YESNO(linked_comm),
-             max_queue_depth, YESNO(use_new_eh_code));
+             max_queue_depth, YESNO(use_new_eh_code), YESNO(ext_tran));
       }
 
    printk("%s: %s 0x%03lx, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d.\n",
@@ -922,6 +936,7 @@ __initfunc (void u14_34f_setup(char *str, int *ints)) {
       else if (!strncmp(cur, "mq:", 3))  max_queue_depth = val;
       else if (!strncmp(cur, "ls:", 3))  link_statistics = val;
       else if (!strncmp(cur, "eh:", 3))  use_new_eh_code = val;
+      else if (!strncmp(cur, "et:", 3))  ext_tran = val;
 
       if ((cur = strchr(cur, ','))) ++cur;
       }
@@ -1555,6 +1570,18 @@ int u14_34f_biosparam(Disk *disk, kdev_t dev, int *dkinfo) {
    dkinfo[0] = HD(j)->heads;
    dkinfo[1] = HD(j)->sectors;
    dkinfo[2] = size / (HD(j)->heads * HD(j)->sectors);
+
+   if (ext_tran && (scsicam_bios_param(disk, dev, dkinfo) < 0)) {
+      dkinfo[0] = 255;
+      dkinfo[1] = 63;
+      dkinfo[2] = size / (dkinfo[0] * dkinfo[1]);
+      }
+
+#if defined (DEBUG_GEOMETRY)
+   printk ("%s: biosparam, head=%d, sec=%d, cyl=%d.\n", driver_name,
+           dkinfo[0], dkinfo[1], dkinfo[2]);
+#endif
+
    return FALSE;
 }
 
index f21aa63faf4dec6504537c2b9db1f04361a6bf22..943b8cbb3cc89aa6b9892e4b68eca28480136b65 100644 (file)
@@ -4,6 +4,7 @@
 #ifndef _U14_34F_H
 #define _U14_34F_H
 
+#include <scsi/scsicam.h>
 #include <linux/version.h>
 
 int u14_34f_detect(Scsi_Host_Template *);
@@ -15,7 +16,7 @@ int u14_34f_reset(Scsi_Cmnd *);
 int u14_34f_old_reset(Scsi_Cmnd *, unsigned int);
 int u14_34f_biosparam(Disk *, kdev_t, int *);
 
-#define U14_34F_VERSION "4.32.00"
+#define U14_34F_VERSION "4.33.00"
 
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 
index 1a04a9c585b1c17914e92290da42dd7f2b47d72a..82d77bd121a89d2f258481ec1abd76049e690dca 100644 (file)
@@ -23,6 +23,7 @@ if [ "$CONFIG_FB" = "y" ]; then
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       bool 'Amiga CyberVision3D support (experimental)' CONFIG_FB_VIRGE
       tristate 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3
+      tristate 'Amiga CLgen driver' CONFIG_FB_CLGEN
     fi
   fi
   if [ "$CONFIG_ATARI" = "y" ]; then
@@ -32,8 +33,8 @@ if [ "$CONFIG_FB" = "y" ]; then
   if [ "$CONFIG_PPC" = "y" ]; then
     bool 'Open Firmware frame buffer device support' CONFIG_FB_OF
     if [ "$CONFIG_FB_OF" = "y" ]; then
-#     bool 'Apple "control" display support' CONFIG_FB_CONTROL
-#     bool 'Apple "platinum" display support' CONFIG_FB_PLATINUM
+      bool 'Apple "control" display support' CONFIG_FB_CONTROL
+      bool 'Apple "platinum" display support' CONFIG_FB_PLATINUM
 #     bool 'Apple "valkyrie" display support' CONFIG_FB_VALKYRIE
       bool 'ATI Mach64 display support' CONFIG_FB_ATY
 #     bool 'IMS Twin Turbo display support' CONFIG_FB_IMSTT
@@ -69,7 +70,12 @@ if [ "$CONFIG_FB" = "y" ]; then
       if [ "$ARCH" = "sparc64" ]; then
        bool '  Creator/Creator3D support' CONFIG_FB_CREATOR
       fi
-      bool '  CGsix (GX,GXplus) support' CONFIG_FB_CGSIX
+      bool '  CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
+      bool '  BWtwo support' CONFIG_FB_BWTWO
+      bool '  CGthree support' CONFIG_FB_CGTHREE
+      if [ "$ARCH" = "sparc" ]; then
+        bool '  TCX (SS4/SS5 only) support' CONFIG_FB_TCX
+      fi
     fi
   fi
   if [ "$ARCH" = "sparc64" ]; then
@@ -104,13 +110,15 @@ if [ "$CONFIG_FB" = "y" ]; then
     if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_AMIGA" = "y" -o \
         "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
         "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \
-        "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
+        "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+        "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then
       define_bool CONFIG_FBCON_MFB y
     else
       if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \
           "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
           "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_RETINAZ3" = "m" -o \
-          "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+          "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+          "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then
        define_bool CONFIG_FBCON_MFB m
       fi
     fi
@@ -128,40 +136,50 @@ if [ "$CONFIG_FB" = "y" ]; then
     if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_ATARI" = "y" -o \
         "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
         "$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_TGA" = "y" -o \
-        "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
+        "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+        "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \
+        "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then
       define_bool CONFIG_FBCON_CFB8 y
     else
       if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
           "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
           "$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \
-          "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+          "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+          "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \
+          "$CONFIG_FB_CONTROL" = "m" ]; then
        define_bool CONFIG_FBCON_CFB8 m
       fi
     fi
     if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
         "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
-        "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" ]; then
+        "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \
+        "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "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" ]; then
+          "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \
+          "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then
        define_bool CONFIG_FBCON_CFB16 m
       fi
     fi
-    if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
+    if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+        "$CONFIG_FB_CLGEN" = "y" ]; then
       define_bool CONFIG_FBCON_CFB24 y
     else
-      if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+      if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+          "$CONFIG_FB_CLGEN" = "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" ]; then
+        "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+        "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "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" ]; then
+          "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+          "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then
        define_bool CONFIG_FBCON_CFB32 m
       fi
     fi
@@ -202,14 +220,19 @@ if [ "$CONFIG_FB" = "y" ]; then
       fi
     fi
   fi
+  bool 'Support only 8 pixels wide fonts' CONFIG_FBCON_FONTWIDTH8_ONLY
   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
     bool 'Sparc console 8x16 font' CONFIG_FONT_SUN8x16
-    bool 'Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
+    if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+      bool 'Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
+    fi
     bool 'Select other fonts' CONFIG_FBCON_FONTS
     if [ "$CONFIG_FBCON_FONTS" = "y" ]; then
       bool '  VGA 8x8 font' CONFIG_FONT_8x8
       bool '  VGA 8x16 font' CONFIG_FONT_8x16
-      bool '  Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+      if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+        bool '  Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+      fi
       bool '  Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8
       bool '  Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8
     fi
@@ -219,15 +242,19 @@ if [ "$CONFIG_FB" = "y" ]; then
       bool '  VGA 8x8 font' CONFIG_FONT_8x8
       bool '  VGA 8x16 font' CONFIG_FONT_8x16
       bool '  Sparc console 8x16 font' CONFIG_FONT_SUN8x16
-      bool '  Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
-      bool '  Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+      if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+        bool '  Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
+        bool '  Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+      fi
       bool '  Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8
       bool '  Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8
     else
       define_bool CONFIG_FONT_8x8 y
       define_bool CONFIG_FONT_8x16 y
       if [ "$CONFIG_MAC" = "y" ]; then
-        define_bool CONFIG_FONT_6x11 y
+       if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+          define_bool CONFIG_FONT_6x11 y
+        fi
       fi
       if [ "$CONFIG_AMIGA" = "y" ]; then
         define_bool CONFIG_FONT_PEARL_8x8 y
index 39138be35ac7d0140f9e707b94eb763e625827e8..2461fddc47e53292cf2fff786867ea52b3de5e99 100644 (file)
@@ -30,13 +30,13 @@ ifeq ($(CONFIG_DUMMY_CONSOLE),y)
 endif
 
 ifeq ($(CONFIG_PROM_CONSOLE),y)
-  L_OBJS += promcon.o
+  L_OBJS += promcon.o promcon_tbl.o
 endif
 
 ifeq ($(CONFIG_FB),y)
   L_OBJS += fonts.o
   OX_OBJS += fbcon.o fbcmap.o
-# fbgen is not compiled by default since nobody uses it yet
+# fbgen is not compiled by default since nobody uses it yet, except clgenfb
   ifeq ($(CONFIG_FONT_8x8),y)
     L_OBJS += font_8x8.o
   endif
@@ -94,6 +94,14 @@ ifeq ($(CONFIG_FB_ATY),y)
 L_OBJS += atyfb.o
 endif
 
+ifeq ($(CONFIG_FB_CONTROL),y)
+L_OBJS += controlfb.o
+endif
+
+ifeq ($(CONFIG_FB_PLATINUM),y)
+L_OBJS += platinumfb.o
+endif
+
 ifeq ($(CONFIG_FB_CT65550),y)
 L_OBJS += chipsfb.o
 endif
@@ -126,6 +134,16 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_FB_CLGEN),y)
+L_OBJS += clgenfb.o
+OX_OBJS += fbgen.o
+else
+  ifeq ($(CONFIG_FB_CLGEN),m)
+  M_OBJS += clgenfb.o
+  OX_OBJS += fbgen.o
+  endif
+endif
+
 ifeq ($(CONFIG_FB_S3TRIO),y)
 L_OBJS += S3triofb.o
 else
@@ -186,6 +204,27 @@ L_OBJS += sbusfb.o
     M_OBJS += cgsixfb.o
     endif
   endif
+  ifeq ($(CONFIG_FB_BWTWO),y)
+    L_OBJS += bwtwofb.o
+  else
+    ifeq ($(CONFIG_FB_BWTWO),m)
+    M_OBJS += bwtwofb.o
+    endif
+  endif
+  ifeq ($(CONFIG_FB_CGTHREE),y)
+    L_OBJS += cgthreefb.o
+  else
+    ifeq ($(CONFIG_FB_CGTHREE),m)
+    M_OBJS += cgthreefb.o
+    endif
+  endif
+  ifeq ($(CONFIG_FB_TCX),y)
+    L_OBJS += tcxfb.o
+  else
+    ifeq ($(CONFIG_FB_TCX),m)
+    M_OBJS += tcxfb.o
+    endif
+  endif
 else
   ifeq ($(CONFIG_FB_SBUS),m)
   M_OBJS += sbusfb.o
@@ -203,6 +242,27 @@ else
       M_OBJS += cgsixfb.o
       endif
     endif
+    ifeq ($(CONFIG_FB_BWTWO),y)
+      M_OBJS += bwtwofb.o
+    else
+      ifeq ($(CONFIG_FB_BWTWO),m)
+      M_OBJS += bwtwofb.o
+      endif
+    endif
+    ifeq ($(CONFIG_FB_CGTHREE),y)
+      M_OBJS += cgthreefb.o
+    else
+      ifeq ($(CONFIG_FB_CGTHREE),m)
+      M_OBJS += cgthreefb.o
+      endif
+    endif
+    ifeq ($(CONFIG_FB_TCX),y)
+      M_OBJS += tcxfb.o
+    else
+      ifeq ($(CONFIG_FB_TCX),m)
+      M_OBJS += tcxfb.o
+      endif
+    endif
   endif
 endif
 
@@ -353,3 +413,10 @@ include $(TOPDIR)/Rules.make
 gspcore.c: gspcore.gsp
        $(GSPA) $< > $*.hex
        $(GSPH2C) $*.hex > gspcore.c
+
+promcon_tbl.c: prom.uni
+       ../char/conmakehash prom.uni | \
+       sed -e '/#include <[^>]*>/p' -e 's/types/init/' \
+           -e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > promcon_tbl.c
+
+promcon_tbl.o: promcon_tbl.c $(TOPDIR)/include/linux/types.h
index a64eaf1fa19f6522f28adb078b59a1eee861b979..2b3de8ba50e76db8c998a1d30941c8917fd837b7 100644 (file)
@@ -47,6 +47,7 @@
 #define ATAFB_EXT
 #define ATAFB_FALCON
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
index 38570715e16897c2d3eaa3a79b4b30ce5b029288..7d271bc290deabafa12d3cc2554674dd8654407b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
  *
- *     Copyright (C) 1997 Geert Uytterhoeven
+ *     Copyright (C) 1997-1998 Geert Uytterhoeven
  *     Copyright (C) 1998 Bernd Harries
  *     Copyright (C) 1998 Eddie C. Dost
  *
 
   TODO:
 
-    - support arbitrary video modes
-
   (ecd):
 
-    - fix initialization and allocation of resources for cursor (and disp?).
-
     - fix initialization of cursor timer.
 
-    - add code to detect ramdac type on initialization.
-
     - add code to support cursor on all cards and all ramdacs.
 
     - make cursor parameters controllable via ioctl()s.
 
-    - handle arbitrary fonts.
-
                                                (Anyone to help with all this?)
 
 ******************************************************************************/
 
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/nvram.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+
 #ifdef CONFIG_FB_COMPAT_XPMAC
 #include <asm/vc_ioctl.h>
 #endif
+
 #include <asm/io.h>
+
 #if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
 #include "fbcon.h"
 #include "fbcon-cfb8.h"
 #include "fbcon-cfb16.h"
+#include "fbcon-cfb24.h"
 #include "fbcon-cfb32.h"
 
 
-#ifndef __powerpc__
-#define eieio()                /* Enforce In-order Execution of I/O */
-#endif
-
-static int currcon = 0;
-static struct display fb_disp;
-
-static char atyfb_name[16] = "ATY Mach64";
-
-struct atyfb_par {
-    union {
-       /* this should contain chipset specific mode information */
-       struct {
-           int vmode;
-           int cmode;
-       } gx, gt, vt;
-    } hw;
-    u_int vxres;       /* virtual screen size */
-    u_int vyres;
-    int xoffset;       /* virtual screen position */
-    int yoffset;
-    int accel;
-};
-
+#define GUI_RESERVE    0x00001000
 
-/*
- * Video mode values.
- * These are supposed to be the same as the values that
- * Apple uses in MacOS.
- */
-#define VMODE_NVRAM            0       /* use value stored in nvram */
-#define VMODE_512_384_60I      1       /* 512x384, 60Hz interlaced (NTSC) */
-#define VMODE_512_384_60       2       /* 512x384, 60Hz */
-#define VMODE_640_480_50I      3       /* 640x480, 50Hz interlaced (PAL) */
-#define VMODE_640_480_60I      4       /* 640x480, 60Hz interlaced (NTSC) */
-#define VMODE_640_480_60       5       /* 640x480, 60Hz (VGA) */
-#define VMODE_640_480_67       6       /* 640x480, 67Hz */
-#define VMODE_640_870_75P      7       /* 640x870, 75Hz (portrait) */
-#define VMODE_768_576_50I      8       /* 768x576, 50Hz (PAL full frame) */
-#define VMODE_800_600_56       9       /* 800x600, 56Hz */
-#define VMODE_800_600_60       10      /* 800x600, 60Hz */
-#define VMODE_800_600_72       11      /* 800x600, 72Hz */
-#define VMODE_800_600_75       12      /* 800x600, 75Hz */
-#define VMODE_832_624_75       13      /* 832x624, 75Hz */
-#define VMODE_1024_768_60      14      /* 1024x768, 60Hz */
-#define VMODE_1024_768_70      15      /* 1024x768, 70Hz (or 72Hz?) */
-#define VMODE_1024_768_75V     16      /* 1024x768, 75Hz (VESA) */
-#define VMODE_1024_768_75      17      /* 1024x768, 75Hz */
-#define VMODE_1152_870_75      18      /* 1152x870, 75Hz */
-#define VMODE_1280_960_75      19      /* 1280x960, 75Hz */
-#define VMODE_1280_1024_75     20      /* 1280x1024, 75Hz */
-#define VMODE_MAX              20
-#define VMODE_CHOOSE           99      /* choose based on monitor sense */
+#define CLASS_GX       1
+#define CLASS_CT       2
+#define CLASS_VT       3
+#define CLASS_GT       4
 
-/*
- * Color mode values, used to select number of bits/pixel.
- */
-#define CMODE_NVRAM            -1      /* use value stored in nvram */
-#define CMODE_8                        0       /* 8 bits/pixel */
-#define CMODE_16               1       /* 16 (actually 15) bits/pixel */
-#define CMODE_32               2       /* 32 (actually 24) bits/pixel */
 
+#ifndef __powerpc__
+#define eieio()                /* Enforce In-order Execution of I/O */
+#endif
 
-static int default_vmode = VMODE_NVRAM;
-static int default_cmode = CMODE_NVRAM;
+/* FIXME: remove the FAIL definition */
+#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
 
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
-/*
- * Addresses in NVRAM where video mode and pixel size are stored.
- */
-#define NV_VMODE       0x140f
-#define NV_CMODE       0x1410
-#endif /* CONFIG_PMAC || CONFIG_CHRP */
 
+    /*
+     *  Elements of the Hardware specific atyfb_par structure
+     */
 
-/*
- * Horizontal and vertical resolution for each mode.
- */
-static struct vmode_attr {
-       int     hres;
-       int     vres;
-       int     vfreq;
-       int     interlaced;
-} vmode_attrs[VMODE_MAX] = {
-    {512, 384, 60, 1},
-    {512, 384, 60},
-    {640, 480, 50, 1},
-    {640, 480, 60, 1},
-    {640, 480, 60},
-    {640, 480, 67},
-    {640, 870, 75},
-    {768, 576, 50, 1},
-    {800, 600, 56},
-    {800, 600, 60},
-    {800, 600, 72},
-    {800, 600, 75},
-    {832, 624, 75},
-    {1024, 768, 60},
-    {1024, 768, 72},
-    {1024, 768, 75},
-    {1024, 768, 75},
-    {1152, 870, 75},
-    {1280, 960, 75},
-    {1280, 1024, 75}
+struct crtc {
+    u32 vxres;
+    u32 vyres;
+    u32 xoffset;
+    u32 yoffset;
+    u32 bpp;
+    u32 h_tot_disp;
+    u32 h_sync_strt_wid;
+    u32 v_tot_disp;
+    u32 v_sync_strt_wid;
+    u32 off_pitch;
+    u32 gen_cntl;
+    u32 dp_pix_width;  /* acceleration */
+    u32 dp_chain_mask; /* acceleration */
 };
 
+struct pll_gx {
+    u8 m;
+    u8 n;
+};
 
-/*
- * We get a sense value from the monitor and use it to choose
- * what resolution to use.  This structure maps sense values
- * to display mode values (which determine the resolution and
- * frequencies).
- */
-static struct mon_map {
-       int     sense;
-       int     vmode;
-} monitor_map [] = {
-       {0x000, VMODE_1280_1024_75},    /* 21" RGB */
-       {0x114, VMODE_640_870_75P},     /* Portrait Monochrome */
-       {0x221, VMODE_512_384_60},      /* 12" RGB*/
-       {0x331, VMODE_1280_1024_75},    /* 21" RGB (Radius) */
-       {0x334, VMODE_1280_1024_75},    /* 21" mono (Radius) */
-       {0x335, VMODE_1280_1024_75},    /* 21" mono */
-       {0x40A, VMODE_640_480_60I},     /* NTSC */
-       {0x51E, VMODE_640_870_75P},     /* Portrait RGB */
-       {0x603, VMODE_832_624_75},      /* 12"-16" multiscan */
-       {0x60b, VMODE_1024_768_70},     /* 13"-19" multiscan */
-       {0x623, VMODE_1152_870_75},     /* 13"-21" multiscan */
-       {0x62b, VMODE_640_480_67},      /* 13"/14" RGB */
-       {0x700, VMODE_640_480_50I},     /* PAL */
-       {0x714, VMODE_640_480_60I},     /* NTSC */
-       {0x717, VMODE_800_600_75},      /* VGA */
-       {0x72d, VMODE_832_624_75},      /* 16" RGB (Goldfish) */
-       {0x730, VMODE_768_576_50I},     /* PAL (Alternate) */
-       {0x73a, VMODE_1152_870_75},     /* 3rd party 19" */
-       {0x73f, VMODE_640_480_67},      /* no sense lines connected at all */
-       {-1,    VMODE_640_480_60},      /* catch-all, must be last */
+struct pll_ct {
+    u8 pll_ref_div;
+    u8 pll_gen_cntl;
+    u8 mclk_fb_div;
+    u8 pll_vclk_cntl;
+    u8 vclk_post_div;
+    u8 vclk_fb_div;
+    u8 pll_ext_cntl;
+    u32 dsp_config;    /* Mach64 GTB DSP */
+    u32 dsp_on_off;    /* Mach64 GTB DSP */
 };
 
-static int map_monitor_sense(int sense)
-{
-       struct mon_map *map;
 
-       for (map = monitor_map; map->sense >= 0; ++map)
-               if (map->sense == sense)
-                       break;
-       return map->vmode;
-}
+    /*
+     *  The Hardware parameters for each card
+     */
+
+struct atyfb_par {
+    struct crtc crtc;
+    union {
+       struct pll_gx gx;
+       struct pll_ct ct;
+    } pll;
+    u32 accel_flags;
+};
 
 struct aty_cmap_regs {
     u8 windex;
@@ -240,27 +157,6 @@ struct aty_cmap_regs {
     u8 cntl;
 };
 
-typedef struct aty_regvals {
-    u32 offset[3];             /* first pixel address */
-
-    u32 crtc_h_sync_strt_wid[3];       /* depth dependent */
-    u32 crtc_gen_cntl[3];
-    u32 mem_cntl[3];
-
-    u32 crtc_h_tot_disp;       /* mode dependent */
-    u32 crtc_v_tot_disp;
-    u32 crtc_v_sync_strt_wid;
-    u32 crtc_off_pitch;
-
-    u8 clock_val[2];   /* vals for 20 and 21 */
-} aty_regvals;
-
-struct rage_regvals {
-    u32 h_total, h_sync_start, h_sync_width;
-    u32 v_total, v_sync_start, v_sync_width;
-    u32 h_sync_neg, v_sync_neg;
-};
-
 struct pci_mmap_map {
     unsigned long voff;
     unsigned long poff;
@@ -272,18 +168,18 @@ struct pci_mmap_map {
 #define DEFAULT_CURSOR_BLINK_RATE      (20)
 
 struct aty_cursor {
-       int                enable;
-       int                on;
-       int                vbl_cnt;
-       int                blink_rate;
-       u32                offset;
-       struct {
-           u16 x, y;
-       }                  pos, hot, size;
-       u32                color[2];
-       u8                 bits[8][64];
-       u8                 mask[8][64];
-       struct timer_list *timer;
+    int        enable;
+    int on;
+    int vbl_cnt;
+    int blink_rate;
+    u32 offset;
+    struct {
+        u16 x, y;
+    } pos, hot, size;
+    u32 color[2];
+    u8 bits[8][64];
+    u8 mask[8][64];
+    struct timer_list *timer;
 };
 
 struct fb_info_aty {
@@ -292,144 +188,49 @@ struct fb_info_aty {
     unsigned long ati_regbase;
     unsigned long frame_buffer_phys;
     unsigned long frame_buffer;
+    struct display disp;
+    struct display_switch dispsw;
     struct pci_mmap_map *mmap_map;
     struct aty_cursor *cursor;
-    u8 chip_class;
-    u8 pixclock_lim_8; /* ps, <= 8 bpp */
-    u8 pixclock_lim_hi;        /* ps, > 8 bpp */
-    u32 total_vram;
     struct aty_cmap_regs *aty_cmap_regs;
     struct { u8 red, green, blue, pad; } palette[256];
     struct atyfb_par default_par;
     struct atyfb_par current_par;
-};
-
-#ifdef CONFIG_ATARI
-static unsigned int mach64_count __initdata = 0;
-static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, };
-static unsigned long phys_size[FB_MAX] __initdata = { 0, };
-static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
-#endif
-
-static int aty_vram_reqd(const struct atyfb_par *par);
-static struct aty_regvals *get_aty_struct(int vmode, struct fb_info_aty *info);
-
-#include "ati-gx.h"
-#include "ati-gt.h"
-#include "ati-vt.h"
-
-static struct aty_regvals *aty_gt_reg_init[20] = {
-       NULL, NULL, NULL, NULL,
-       &aty_gt_reg_init_5,
-       &aty_gt_reg_init_6,
-       NULL, NULL,
-       &aty_gt_reg_init_9,
-       &aty_gt_reg_init_10,
-       &aty_gt_reg_init_11,
-       &aty_gt_reg_init_12,
-       &aty_gt_reg_init_13,
-       &aty_gt_reg_init_14,
-       &aty_gt_reg_init_15,
-       NULL,
-       &aty_gt_reg_init_17,
-       &aty_gt_reg_init_18,
-       NULL,
-       &aty_gt_reg_init_20
-};
-
-static struct aty_regvals *aty_gx_reg_init[20] = {
-       NULL, NULL, NULL, NULL,
-       &aty_gx_reg_init_6,
-       &aty_gx_reg_init_6,
-       NULL, NULL, NULL, NULL, NULL, NULL,
-       &aty_gx_reg_init_13,
-       &aty_gx_reg_init_14,
-       &aty_gx_reg_init_15,
-       NULL,
-       &aty_gx_reg_init_17,
-       &aty_gx_reg_init_18,
-       NULL,
-       &aty_gx_reg_init_20
-};
-
-static struct aty_regvals *aty_vt_reg_init[21] = {
-       NULL, NULL, NULL, NULL,
-       &aty_vt_reg_init_5,
-       &aty_vt_reg_init_6,
-       NULL, NULL, NULL,
-       &aty_vt_reg_init_10,
-       &aty_vt_reg_init_11,
-       &aty_vt_reg_init_12,
-       &aty_vt_reg_init_13,
-       &aty_vt_reg_init_14,
-       &aty_vt_reg_init_15,
-       NULL,
-       &aty_vt_reg_init_17,
-       &aty_vt_reg_init_18,
-       &aty_vt_reg_init_19,
-       &aty_vt_reg_init_20
-};
-
-
-#define CLASS_GX       1
-#define CLASS_CT       2
-#define CLASS_VT       3
-#define CLASS_GT       4
-
-struct aty_features {
-    u16 pci_id;
+    u32 total_vram;
+    u32 pll_per;
+    u32 mclk_per;
     u16 chip_type;
-    const char *name;
-    u8 chip_class;
-    u8 pixclock_lim_8; /* MHz, <= 8 bpp (not sure about these limits!) */
-    u8 pixclock_lim_hi;        /* MHz, > 8 bpp (not sure about these limits!) */
-} aty_features[] __initdata = {
-    /* mach64GX family */
-    { 0x4758, 0x00d7, "mach64GX (ATI888GX00)", CLASS_GX, 135, 80 },
-    { 0x4358, 0x0057, "mach64CX (ATI888CX00)", CLASS_GX, 135, 80 },
-
-    /* mach64CT family */
-    { 0x4354, 0x4354, "mach64CT (ATI264CT)", CLASS_CT, 135, 80 },
-    { 0x4554, 0x4554, "mach64ET (ATI264ET)", CLASS_CT, 135, 80 },
-
-    /* mach64CT family / mach64VT class */
-    { 0x5654, 0x5654, "mach64VT (ATI264VT)", CLASS_VT, 160, 135 },
-    { 0x5655, 0x5655, "mach64VTB (ATI264VTB)", CLASS_VT, 160, 135 },
-    { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)", CLASS_VT, 160, 135 },
-
-    /* mach64CT family / mach64GT (3D RAGE) class */
-    { 0x4742, 0x4742, "3D RAGE PRO (BGA, AGP)", CLASS_GT, 240, 240 },
-    { 0x4744, 0x4744, "3D RAGE PRO (BGA, AGP, 1x only)", CLASS_GT, 240, 240 },
-    { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)", CLASS_GT, 240, 240 },
-    { 0x4750, 0x4750, "3D RAGE PRO (PQFP, PCI)", CLASS_GT, 240, 240 },
-    { 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)", CLASS_GT, 240, 240 },
-    { 0x4754, 0x4754, "3D RAGE (GT)", CLASS_GT, 200, 200 },
-    { 0x4755, 0x4755, "3D RAGE II+ (GTB)", CLASS_GT, 200, 200 },
-    { 0x4756, 0x4756, "3D RAGE IIC", CLASS_GT, 200, 200 },
-    { 0x4c47, 0x4c47, "3D RAGE LT", CLASS_GT, 200, 200 },
+#define Gx info->chip_type
+    u8 chip_rev;
+#define Rev info->chip_rev
+    u8 bus_type;
+    u8 ram_type;
+    u8 dac_type;
+    u8 clk_type;
+    u8 mem_refresh_rate;
+#ifdef __sparc__
+    u8 open;
+    u8 mmaped;
+    int vtconsole;
+    int consolecnt;
+#endif
 };
 
 
     /*
-     *  Interface used by the world
+     *  Frame buffer device API
      */
 
-void atyfb_init(void);
-#ifdef CONFIG_FB_OF
-void atyfb_of_init(struct device_node *dp);
-#endif
-void atyfb_setup(char *options, int *ints);
-
 static int atyfb_open(struct fb_info *info, int user);
 static int atyfb_release(struct fb_info *info, int user);
 static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-                        struct fb_info *info);
+                        struct fb_info *fb);
 static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
-                        struct fb_info *info);
+                        struct fb_info *fb);
 static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
-                        struct fb_info *info);
+                        struct fb_info *fb);
 static int atyfb_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info);
+                            struct fb_info *fb);
 static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                          struct fb_info *info);
 static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
@@ -446,23 +247,50 @@ static int atyfb_mmap(struct fb_info *info, struct file *file,
      *  Interface to the low level console driver
      */
 
-static int atyfbcon_switch(int con, struct fb_info *info);
-static int atyfbcon_updatevar(int con, struct fb_info *info);
-static void atyfbcon_blank(int blank, struct fb_info *info);
+static int atyfbcon_switch(int con, struct fb_info *fb);
+static int atyfbcon_updatevar(int con, struct fb_info *fb);
+static void atyfbcon_blank(int blank, struct fb_info *fb);
 
 
     /*
      *  Text console acceleration
      */
 
+static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx,
+                           int height, int width);
+static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy,
+                           int sx, int height, int width);
 #ifdef FBCON_HAS_CFB8
 static struct display_switch fbcon_aty8;
+static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c,
+                           int yy, int xx);
+static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
+                            const unsigned short *s, int count, int yy,
+                            int xx);
 #endif
 #ifdef FBCON_HAS_CFB16
 static struct display_switch fbcon_aty16;
+static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, int c,
+                            int yy, int xx);
+static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p,
+                             const unsigned short *s, int count, int yy,
+                             int xx);
+#endif
+#ifdef FBCON_HAS_CFB24
+static struct display_switch fbcon_aty24;
+static void fbcon_aty24_putc(struct vc_data *conp, struct display *p, int c,
+                            int yy, int xx);
+static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p,
+                             const unsigned short *s, int count, int yy,
+                             int xx);
 #endif
 #ifdef FBCON_HAS_CFB32
 static struct display_switch fbcon_aty32;
+static void fbcon_aty32_putc(struct vc_data *conp, struct display *p, int c,
+                            int yy, int xx);
+static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p,
+                             const unsigned short *s, int count, int yy,
+                             int xx);
 #endif
 
 
@@ -476,13 +304,73 @@ static int store_video_par(char *videopar, unsigned char m64_num);
 static char *strtoke(char *s, const char *ct);
 #endif
 
+static void reset_engine(const struct fb_info_aty *info);
+static void init_engine(const struct atyfb_par *par,
+                       const struct fb_info_aty *info);
+static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info);
+static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info);
+static void aty_set_crtc(const struct fb_info_aty *info,
+                        const struct crtc *crtc);
+static int aty_var_to_crtc(const struct fb_info_aty *info,
+                          const struct fb_var_screeninfo *var,
+                          struct crtc *crtc);
+static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp);
+static int aty_crtc_to_var(const struct crtc *crtc,
+                          struct fb_var_screeninfo *var);
+static void aty_set_pll_gx(const struct fb_info_aty *info,
+                          const struct pll_gx *pll);
+static int aty_var_to_pll_18818(const struct fb_var_screeninfo *var,
+                               struct pll_gx *pll);
+static int aty_var_to_pll_514(const struct fb_var_screeninfo *var,
+                             struct pll_gx *pll);
+static int aty_pll_gx_to_var(const struct pll_gx *pll,
+                            struct fb_var_screeninfo *var);
+static void aty_set_pll_ct(const struct fb_info_aty *info,
+                          const struct pll_ct *pll);
+static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div,
+                     u8 mclk_post_div, u8 vclk_fb_div, u8 vclk_post_div,
+                     u8 bpp, struct pll_ct *pll);
+static int aty_var_to_pll_ct(const struct fb_info_aty *info,
+                            const struct fb_var_screeninfo *var,
+                            struct pll_ct *pll);
+static int aty_pll_ct_to_var(const struct pll_ct *pll,
+                            struct fb_var_screeninfo *var);
+static void atyfb_set_par(const struct atyfb_par *par,
+                         struct fb_info_aty *info);
+static int atyfb_decode_var(const struct fb_var_screeninfo *var,
+                           struct atyfb_par *par,
+                           const struct fb_info_aty *info);
+static int atyfb_encode_var(struct fb_var_screeninfo *var,
+                           const struct atyfb_par *par,
+                           const struct fb_info_aty *info);
+static void set_off_pitch(struct atyfb_par *par,
+                         const struct fb_info_aty *info);
+static int encode_fix(struct fb_fix_screeninfo *fix,
+                     const struct atyfb_par *par,
+                     const struct fb_info_aty *info);
 static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                        u_int *transp, struct fb_info *info);
+                        u_int *transp, struct fb_info *fb);
 static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                        u_int transp, struct fb_info *info);
+                        u_int transp, struct fb_info *fb);
 static void do_install_cmap(int con, struct fb_info *info);
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+static int read_aty_sense(const struct fb_info_aty *info);
+#endif
+
+
+    /*
+     *  Interface used by the world
+     */
+
+void atyfb_init(void);
+#ifdef CONFIG_FB_OF
+void atyfb_of_init(struct device_node *dp);
+#endif
+void atyfb_setup(char *options, int *ints);
 
 
+static int currcon = 0;
+
 static struct fb_ops atyfb_ops = {
     atyfb_open, atyfb_release, atyfb_get_fix, atyfb_get_var, atyfb_set_var,
     atyfb_get_cmap, atyfb_set_cmap, atyfb_pan_display, atyfb_ioctl,
@@ -493,64 +381,110 @@ static struct fb_ops atyfb_ops = {
 #endif
 };
 
+static char atyfb_name[16] = "ATY Mach64";
+static char fontname[40] __initdata = { 0 };
+
+static const u32 ref_clk_per = 1000000000000ULL/14318180;
+
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
+#endif
+
+#ifdef CONFIG_ATARI
+static unsigned int mach64_count __initdata = 0;
+static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, };
+static unsigned long phys_size[FB_MAX] __initdata = { 0, };
+static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
+#endif
+
+
+static struct aty_features {
+    u16 pci_id;
+    u16 chip_type;
+    const char *name;
+} aty_features[] __initdata = {
+    /* mach64GX family */
+    { 0x4758, 0x00d7, "mach64GX (ATI888GX00)" },
+    { 0x4358, 0x0057, "mach64CX (ATI888CX00)" },
+
+    /* mach64CT family */
+    { 0x4354, 0x4354, "mach64CT (ATI264CT)" },
+    { 0x4554, 0x4554, "mach64ET (ATI264ET)" },
+
+    /* mach64CT family / mach64VT class */
+    { 0x5654, 0x5654, "mach64VT (ATI264VT)" },
+    { 0x5655, 0x5655, "mach64VTB (ATI264VTB)" },
+/*  { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)" }, */
+
+    /* mach64CT family / mach64GT (3D RAGE) class */
+    { 0x4c54, 0x4c54, "3D RAGE LT" },
+    { 0x4c47, 0x4c47, "3D RAGE LG" },
+    { 0x4754, 0x4754, "3D RAGE (GT)" },
+    { 0x4755, 0x4755, "3D RAGE II+ (GTB)" },
+/*  { 0x4756, 0x4756, "3D RAGE IIC" }, */
+    { 0x4742, 0x4742, "3D RAGE PRO (BGA, AGP)" },
+    { 0x4744, 0x4744, "3D RAGE PRO (BGA, AGP, 1x only)" },
+    { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)" },
+    { 0x4750, 0x4750, "3D RAGE PRO (PQFP, PCI)" },
+    { 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)" },
+};
 
-static inline int aty_vram_reqd(const struct atyfb_par *par)
-{
-    return (par->vxres*par->vyres) << par->hw.gx.cmode;
-}
 
 static inline u32 aty_ld_le32(volatile unsigned int regindex,
-                             struct fb_info_aty *info)
+                             const struct fb_info_aty *info)
 {
     unsigned long temp;
     u32 val;
 
-#ifdef __powerpc__
+#if defined(__powerpc__)
     temp = info->ati_regbase;
-    asm("lwbrx %0,%1,%2": "=r"(val):"r"(regindex), "r"(temp));
-#else
-#ifdef __sparc__v9__
+    asm("lwbrx %0,%1,%2" : "=r"(val) : "r" (regindex), "r" (temp));
+#elif defined(__sparc_v9__)
     temp = info->ati_regbase + regindex;
     asm("lduwa [%1] %2, %0" : "=r" (val) : "r" (temp), "i" (ASI_PL));
 #else
     temp = info->ati_regbase+regindex;
     val = le32_to_cpu(*((volatile u32 *)(temp)));
-#endif
 #endif
     return val;
 }
 
 static inline void aty_st_le32(volatile unsigned int regindex, u32 val,
-                              struct fb_info_aty *info)
+                              const struct fb_info_aty *info)
 {
     unsigned long temp;
 
-#ifdef __powerpc__
+#if defined(__powerpc__)
     temp = info->ati_regbase;
-    asm("stwbrx %0,%1,%2": : "r"(val), "r"(regindex), "r"(temp):"memory");
-#else
-#ifdef __sparc__v9__
+    asm("stwbrx %0,%1,%2" : : "r" (val), "r" (regindex), "r" (temp) :
+       "memory");
+#elif defined(__sparc_v9__)
     temp = info->ati_regbase + regindex;
-    asm("stwa %0, [%1] %2" : "r" (val), "r" (temp), "i" (ASI_PL) : "memory");
+    asm("stwa %0, [%1] %2" : "r" (val), "r" (temp), "i" (ASI_PL) : "memory");
 #else
     temp = info->ati_regbase+regindex;
     *((volatile u32 *)(temp)) = cpu_to_le32(val);
 #endif
-#endif
 }
 
 static inline u8 aty_ld_8(volatile unsigned int regindex,
-                         struct fb_info_aty *info)
+                         const struct fb_info_aty *info)
 {
     return *(volatile u8 *)(info->ati_regbase+regindex);
 }
 
 static inline void aty_st_8(volatile unsigned int regindex, u8 val,
-                           struct fb_info_aty *info)
+                           const struct fb_info_aty *info)
 {
     *(volatile u8 *)(info->ati_regbase+regindex) = val;
 }
 
+
+    /*
+     *  Generic Mach64 routines
+     */
+
     /*
      *  All writes to draw engine registers are automatically routed through a
      *  32-bit-wide, 16-entry-deep command FIFO ...
@@ -559,19 +493,19 @@ static inline void aty_st_8(volatile unsigned int regindex, u8 val,
      *  (from Chapter 5 of the Mach64 Programmer's Guide)
      */
 
-static inline void wait_for_fifo(u16 entries, struct fb_info_aty *info)
+static inline void wait_for_fifo(u16 entries, const struct fb_info_aty *info)
 {
     while ((aty_ld_le32(FIFO_STAT, info) & 0xffff) >
           ((u32)(0x8000 >> entries)));
 }
 
-static inline void wait_for_idle(struct fb_info_aty *info)
+static inline void wait_for_idle(const struct fb_info_aty *info)
 {
     wait_for_fifo(16, info);
     while ((aty_ld_le32(GUI_STAT, info) & 1)!= 0);
 }
 
-static void reset_engine(struct fb_info_aty *info)
+static void reset_engine(const struct fb_info_aty *info)
 {
     /* reset engine */
     aty_st_le32(GEN_TEST_CNTL,
@@ -585,20 +519,19 @@ static void reset_engine(struct fb_info_aty *info)
                          BUS_FIFO_ERR_ACK, info);
 }
 
-static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info)
+static void init_engine(const struct atyfb_par *par,
+                       const struct fb_info_aty *info)
 {
     u32 pitch_value;
 
     /* determine modal information from global mode structure */
-    pitch_value = par->vxres;
+    pitch_value = par->crtc.vxres;
 
-#if 0
-    if (par->hw.gx.cmode == CMODE_24) {
+    if (par->crtc.bpp == 24) {
        /* In 24 bpp, the engine is in 8 bpp - this requires that all */
        /* horizontal coordinates and widths must be adjusted */
        pitch_value = pitch_value * 3;
     }
-#endif
 
     /* Reset engine, enable, and clear any engine errors */
     reset_engine(info);
@@ -655,7 +588,7 @@ static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info)
     /* set scissors to modal size */
     aty_st_le32(SC_LEFT, 0, info);
     aty_st_le32(SC_TOP, 0, info);
-    aty_st_le32(SC_BOTTOM, par->vyres-1, info);
+    aty_st_le32(SC_BOTTOM, par->crtc.vyres-1, info);
     aty_st_le32(SC_RIGHT, pitch_value-1, info);
 
     /* set background color to minimum value (usually BLACK) */
@@ -684,48 +617,18 @@ static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info)
 
     /* set pixel depth */
     wait_for_fifo(2, info);
-    switch(par->hw.gx.cmode) {
-#ifdef FBCON_HAS_CFB8
-       case CMODE_8:
-           aty_st_le32(DP_PIX_WIDTH, HOST_8BPP | SRC_8BPP | DST_8BPP |
-                                     BYTE_ORDER_LSB_TO_MSB,
-           info);
-           aty_st_le32(DP_CHAIN_MASK, 0x8080, info);
-           break;
-#endif
-#ifdef FBCON_HAS_CFB16
-       case CMODE_16:
-           aty_st_le32(DP_PIX_WIDTH, HOST_15BPP | SRC_15BPP | DST_15BPP |
-                                     BYTE_ORDER_LSB_TO_MSB,
-           info);
-           aty_st_le32(DP_CHAIN_MASK, 0x4210, info);
-           break;
-#endif
-#if 0
-       case CMODE_24:
-           aty_st_le32(DP_PIX_WIDTH, HOST_8BPP | SRC_8BPP | DST_8BPP |
-                                     BYTE_ORDER_LSB_TO_MSB,
-           info);
-           aty_st_le32(DP_CHAIN_MASK, 0x8080, info);
-           break;
-#endif
-#ifdef FBCON_HAS_CFB32
-       case CMODE_32:
-           aty_st_le32(DP_PIX_WIDTH, HOST_32BPP | SRC_32BPP | DST_32BPP |
-                                     BYTE_ORDER_LSB_TO_MSB, info);
-           aty_st_le32(DP_CHAIN_MASK, 0x8080, info);
-           break;
-#endif
-    }
+    aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, info);
+    aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, info);
+
     /* insure engine is idle before leaving */
     wait_for_idle(info);
 }
 
-static void aty_st_514(int offset, u8 val, struct fb_info_aty *info)
+static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info)
 {
     aty_st_8(DAC_CNTL, 1, info);
     /* right addr byte */
-    aty_st_8(DAC_W_INDEX, offset & 0xff, info);        
+    aty_st_8(DAC_W_INDEX, offset & 0xff, info);
     /* left addr byte */
     aty_st_8(DAC_DATA, (offset >> 8) & 0xff, info);
     eieio();
@@ -734,7 +637,7 @@ static void aty_st_514(int offset, u8 val, struct fb_info_aty *info)
     aty_st_8(DAC_CNTL, 0, info);
 }
 
-static void aty_st_pll(int offset, u8 val, struct fb_info_aty *info)
+static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info)
 {
     /* write addr byte */
     aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, info);
@@ -745,28 +648,28 @@ static void aty_st_pll(int offset, u8 val, struct fb_info_aty *info)
     aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info);
 }
 
-static struct aty_regvals *get_aty_struct(int vmode, struct fb_info_aty *info)
+#if 0 /* ecd debug */
+static u8 aty_ld_pll(int offset, const struct fb_info_aty *info)
 {
-    int v = vmode - 1;
+    u8 val;
 
-    switch (info->chip_class) {
-       case CLASS_GX:
-           return aty_gx_reg_init[v];
-           break;
-       case CLASS_CT:
-       case CLASS_VT:
-           return aty_vt_reg_init[v];
-           break;
-       case CLASS_GT:
-           return aty_gt_reg_init[v];
-           break;
-       default:
-           /* should NOT happen */
-           return NULL;
-    }
+    /* write addr byte */
+    aty_st_8(CLOCK_CNTL + 1, (offset << 2), info);
+    eieio();
+    /* read the register value */
+    val = aty_ld_8(CLOCK_CNTL + 2, info);
+    eieio();
+    return val;
 }
+#endif /* ecd debug */
+
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
 
-static int read_aty_sense(struct fb_info_aty *info)
+    /*
+     *  Apple monitor sense
+     */
+
+static int read_aty_sense(const struct fb_info_aty *info)
 {
     int sense, i;
 
@@ -800,50 +703,13 @@ static int read_aty_sense(struct fb_info_aty *info)
     return sense;
 }
 
-static void RGB514_Program(int cmode, struct fb_info_aty *info)
-{
-    typedef struct {
-       u8 pixel_dly;
-       u8 misc2_cntl;
-       u8 pixel_rep;
-       u8 pixel_cntl_index;
-       u8 pixel_cntl_v1;
-    } RGB514_DAC_Table;
-
-    static RGB514_DAC_Table RGB514DAC_Tab[8] = {
-       {0, 0x41, 0x03, 0x71, 0x45},    /* 8bpp */
-       {0, 0x45, 0x04, 0x0c, 0x01},    /* 555 */
-       {0, 0x45, 0x06, 0x0e, 0x00},    /* XRGB */
-    };
-    RGB514_DAC_Table *pDacProgTab;
-
-    pDacProgTab = &RGB514DAC_Tab[cmode];
-
-    aty_st_514(0x90, 0x00, info);
-    aty_st_514(0x04, pDacProgTab->pixel_dly, info);
-    aty_st_514(0x05, 0x00, info);
-
-    aty_st_514(0x2, 0x1, info);
-    aty_st_514(0x71, pDacProgTab->misc2_cntl, info);
-    aty_st_514(0x0a, pDacProgTab->pixel_rep, info);
-
-    aty_st_514(pDacProgTab->pixel_cntl_index, pDacProgTab->pixel_cntl_v1,
-              info);
-}
-
-static void set_off_pitch(const struct atyfb_par *par,
-                         struct fb_info_aty *info)
-{
-    u32 pitch, offset;
+#endif /* defined(CONFIG_PMAC) || defined(CONFIG_CHRP) */
 
-    pitch = par->vxres>>3;
-    offset = ((par->yoffset*par->vxres+par->xoffset)>>3)<<par->hw.gx.cmode;
-    aty_st_le32(CRTC_OFF_PITCH, pitch<<22 | offset, info);
-}
+/* ------------------------------------------------------------------------- */
 
-/*
* Hardware Cursor support.
- */
+    /*
    *  Hardware Cursor support.
    */
 
 static u8 cursor_pixel_map[2] = { 0, 15 };
 static u8 cursor_color_map[2] = { 0, 0xff };
@@ -870,6 +736,11 @@ aty_set_cursor_color(struct fb_info_aty *fb, u8 *pixel,
        if (!c)
                return;
 
+#ifdef __sparc__
+       if (fb->mmaped && currcon == fb->vtconsole)
+               return;
+#endif
+
        for (i = 0; i < 2; i++) {
                c->color[i] =  (u32)red[i] << 24;
                c->color[i] |= (u32)green[i] << 16;
@@ -880,7 +751,6 @@ aty_set_cursor_color(struct fb_info_aty *fb, u8 *pixel,
        wait_for_fifo(2, fb);
        aty_st_le32(CUR_CLR0, c->color[0], fb);
        aty_st_le32(CUR_CLR1, c->color[1], fb);
-       wait_for_idle(fb);
 }
 
 static void
@@ -893,6 +763,11 @@ aty_set_cursor_shape(struct fb_info_aty *fb)
        if (!c)
                return;
 
+#ifdef __sparc__
+       if (fb->mmaped && currcon == fb->vtconsole)
+               return;
+#endif
+
        ram = (u8 *)(fb->frame_buffer + c->offset);
 
        for (y = 0; y < c->size.y; y++) {
@@ -922,6 +797,11 @@ aty_set_cursor(struct fb_info_aty *fb)
        if (!c)
                return;
 
+#ifdef __sparc__
+       if (fb->mmaped && currcon == fb->vtconsole)
+               return;
+#endif
+
        if (c->on) {
                x = c->pos.x - c->hot.x;
                if (x < 0) {
@@ -952,7 +832,6 @@ aty_set_cursor(struct fb_info_aty *fb)
                            aty_ld_le32(GEN_TEST_CNTL, fb) & ~HWCURSOR_ENABLE,
                            fb);
        }
-       wait_for_idle(fb);
 }
 
 static void
@@ -986,6 +865,11 @@ atyfb_cursor(struct display *d, int mode, int x, int y)
        if (!c)
                return;
 
+#ifdef __sparc__
+       if (fb->mmaped && currcon == fb->vtconsole)
+               return;
+#endif
+
        x *= d->fontwidth;
        y *= d->fontheight;
        if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->on)
@@ -1061,249 +945,766 @@ atyfb_set_font(struct display *d, int width, int height)
 }
 
 
-static void atyfb_set_par(struct atyfb_par *par, struct fb_info_aty *info)
-{
-    int i, j = 0, hres;
-    struct aty_regvals *init = get_aty_struct(par->hw.gx.vmode, info);
-    int vram_type = aty_ld_le32(CONFIG_STAT0, info) & 7;
 
-    if (init == 0)     /* paranoia, shouldn't get here */
-       panic("aty: display mode %d not supported", par->hw.gx.vmode);
 
-    info->current_par = *par;
-    hres = vmode_attrs[par->hw.gx.vmode-1].hres;
+/* ------------------------------------------------------------------------- */
 
-    if (info->chip_class != CLASS_GT) {
-       i = aty_ld_le32(CRTC_GEN_CNTL, info);
-       aty_st_le32(CRTC_GEN_CNTL, i | CRTC_EXT_DISP_EN, info);
-    }
+    /*
+     *  CRTC programming
+     */
 
-    if (info->chip_class == CLASS_GX) {
-       i = aty_ld_le32(GEN_TEST_CNTL, info);
-       aty_st_le32(GEN_TEST_CNTL, i | GEN_OVR_OUTPUT_EN, info);
-    }
+static void aty_set_crtc(const struct fb_info_aty *info,
+                        const struct crtc *crtc)
+{
+    aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, info);
+    aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, info);
+    aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, info);
+    aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, info);
+    aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, info);
+    aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, info);
+    aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, info);
+}
 
-    switch (info->chip_class) {
-       case CLASS_GX:
-           RGB514_Program(par->hw.gx.cmode, info);
-           wait_for_idle(info);
-           aty_st_514(0x06, 0x02, info);
-           aty_st_514(0x10, 0x01, info);
-           aty_st_514(0x70, 0x01, info);
-           aty_st_514(0x8f, 0x1f, info);
-           aty_st_514(0x03, 0x00, info);
-           aty_st_514(0x05, 0x00, info);
-           aty_st_514(0x20, init->clock_val[0], info);
-           aty_st_514(0x21, init->clock_val[1], info);
-           break;
-       case CLASS_CT:
-       case CLASS_VT:
-           aty_st_pll(VPLL_CNTL, 0xb5, info);
-           aty_st_pll(PLL_REF_DIV, 0x2d, info);
-           aty_st_pll(PLL_GEN_CNTL, 0x14, info);
-           aty_st_pll(MCLK_FB_DIV, 0xbd, info);
-           aty_st_pll(PLL_VCLK_CNTL, 0x0b, info);
-           aty_st_pll(VCLK_POST_DIV, init->clock_val[0], info);
-           aty_st_pll(VCLK0_FB_DIV, init->clock_val[1], info);
-           aty_st_pll(VCLK1_FB_DIV, 0xd6, info);
-           aty_st_pll(VCLK2_FB_DIV, 0xee, info);
-           aty_st_pll(VCLK3_FB_DIV, 0xf8, info);
-           aty_st_pll(PLL_EXT_CNTL, 0x0, info);
-           aty_st_pll(PLL_TEST_CTRL, 0x0, info);
-           aty_st_pll(PLL_TEST_COUNT, 0x0, info);
-           break;
-       case CLASS_GT:
-           if (vram_type == 5) {
-               aty_st_pll(MPLL_CNTL, 0xcd, info);
-               aty_st_pll(VPLL_CNTL,
-                          par->hw.gx.vmode >= VMODE_1024_768_60 ? 0xd3
-                                                                : 0xd5,
-                          info);
-               aty_st_pll(PLL_REF_DIV, 0x21, info);
-               aty_st_pll(PLL_GEN_CNTL, 0x44, info);
-               aty_st_pll(MCLK_FB_DIV, 0xe8, info);
-               aty_st_pll(PLL_VCLK_CNTL, 0x03, info);
-               aty_st_pll(VCLK_POST_DIV, init->offset[0], info);
-               aty_st_pll(VCLK0_FB_DIV, init->offset[1], info);
-               aty_st_pll(VCLK1_FB_DIV, 0x8e, info);
-               aty_st_pll(VCLK2_FB_DIV, 0x9e, info);
-               aty_st_pll(VCLK3_FB_DIV, 0xc6, info);
-               aty_st_pll(PLL_EXT_CNTL, init->offset[2], info);
-               aty_st_pll(DLL_CNTL, 0xa6, info);
-               aty_st_pll(VFC_CNTL, 0x1b, info);
-           } else {
-               aty_st_pll(VPLL_CNTL, 0xd5, info);
-               aty_st_pll(PLL_REF_DIV, 0x21, info);
-               aty_st_pll(PLL_GEN_CNTL, 0xc4, info);
-               aty_st_pll(MCLK_FB_DIV, 0xda, info);
-               aty_st_pll(PLL_VCLK_CNTL, 0x03, info);
-               /* offset actually holds clock values */
-               aty_st_pll(VCLK_POST_DIV, init->offset[0], info);
-               aty_st_pll(VCLK0_FB_DIV, init->offset[1], info);
-               aty_st_pll(VCLK1_FB_DIV, 0x8e, info);
-               aty_st_pll(VCLK2_FB_DIV, 0x9e, info);
-               aty_st_pll(VCLK3_FB_DIV, 0xc6, info);
-               aty_st_pll(PLL_TEST_CTRL, 0x0, info);
-               aty_st_pll(PLL_EXT_CNTL, init->offset[2], info);
-               aty_st_pll(DLL_CNTL, 0xa0, info);
-               aty_st_pll(VFC_CNTL, 0x1b, info);
-           }
-           break;
+static int aty_var_to_crtc(const struct fb_info_aty *info,
+                          const struct fb_var_screeninfo *var,
+                          struct crtc *crtc)
+{
+    u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp;
+    u32 left, right, upper, lower, hslen, vslen, sync, vmode;
+    u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
+    u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol;
+    u32 pix_width, dp_pix_width, dp_chain_mask;
+
+    /* input */
+    xres = var->xres;
+    yres = var->yres;
+    vxres = var->xres_virtual;
+    vyres = var->yres_virtual;
+    xoffset = var->xoffset;
+    yoffset = var->yoffset;
+    bpp = var->bits_per_pixel;
+    left = var->left_margin;
+    right = var->right_margin;
+    upper = var->upper_margin;
+    lower = var->lower_margin;
+    hslen = var->hsync_len;
+    vslen = var->vsync_len;
+    sync = var->sync;
+    vmode = var->vmode;
+
+    /* convert (and round up) and validate */
+    xres = (xres+7) & ~7;
+    xoffset = (xoffset+7) & ~7;
+    vxres = (vxres+7) & ~7;
+    if (vxres < xres+xoffset)
+       vxres = xres+xoffset;
+    h_disp = xres/8-1;
+    if (h_disp > 0xff)
+       FAIL("h_disp too large");
+    h_sync_strt = h_disp+(right/8);
+    if (h_sync_strt > 0x1ff)
+       FAIL("h_sync_start too large");
+    h_sync_dly = right & 7;
+    h_sync_wid = (hslen+7)/8;
+    if (h_sync_wid > 0x1f)
+       FAIL("h_sync_wid too large");
+    h_total = h_sync_strt+h_sync_wid+(h_sync_dly+left+7)/8;
+    if (h_total > 0x1ff)
+       FAIL("h_total too large");
+    h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
+
+    if (vyres < yres+yoffset)
+       vyres = yres+yoffset;
+    v_disp = yres-1;
+    if (v_disp > 0x7ff)
+       FAIL("v_disp too large");
+    v_sync_strt = v_disp+lower;
+    if (v_sync_strt > 0x7ff)
+       FAIL("v_sync_strt too large");
+    v_sync_wid = vslen;
+    if (v_sync_wid > 0x1f)
+       FAIL("v_sync_wid too large");
+    v_total = v_sync_strt+v_sync_wid+upper;
+    if (v_total > 0x7ff)
+       FAIL("v_total too large");
+    v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
+
+    if (bpp <= 8) {
+       bpp = 8;
+       pix_width = CRTC_PIX_WIDTH_8BPP;
+       dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB;
+       dp_chain_mask = 0x8080;
+    } else if (bpp <= 16) {
+       bpp = 16;
+       pix_width = CRTC_PIX_WIDTH_15BPP;
+       dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP |
+                      BYTE_ORDER_LSB_TO_MSB;
+       dp_chain_mask = 0x4210;
+    } else if ((bpp <= 24) && (Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
+       bpp = 24;
+       pix_width = CRTC_PIX_WIDTH_24BPP;
+       dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB;
+       dp_chain_mask = 0x8080;
+    } else if (bpp <= 32) {
+       bpp = 32;
+       pix_width = CRTC_PIX_WIDTH_32BPP;
+       dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP |
+                      BYTE_ORDER_LSB_TO_MSB;
+       dp_chain_mask = 0x8080;
+    } else
+       FAIL("invalid bpp");
+
+    if (vxres*vyres*bpp/8 > info->total_vram)
+       FAIL("not enough video RAM");
+
+    if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+       FAIL("invalid vmode");
+
+    /* output */
+    crtc->vxres = vxres;
+    crtc->vyres = vyres;
+    crtc->xoffset = xoffset;
+    crtc->yoffset = yoffset;
+    crtc->bpp = bpp;
+    crtc->h_tot_disp = h_total | (h_disp<<16);
+    crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly<<8) |
+                           ((h_sync_strt & 0x100)<<4) | (h_sync_wid<<16) |
+                           (h_sync_pol<<21);
+    crtc->v_tot_disp = v_total | (v_disp<<16);
+    crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<21);
+    crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
+    crtc->gen_cntl = pix_width | CRTC_EXT_DISP_EN | CRTC_ENABLE;
+    if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID) ||
+       ((Gx == VT_CHIP_ID) && !(Rev & 0x03)) ||
+       ((Gx == GT_CHIP_ID) && !(Rev & 0x03))) {
+       /* Not VTB/GTB */
+       /* FIXME: magic FIFO values */
+       crtc->gen_cntl |= aty_ld_le32(CRTC_GEN_CNTL, info) & 0x000e0000;
     }
+    crtc->dp_pix_width = dp_pix_width;
+    crtc->dp_chain_mask = dp_chain_mask;
 
-    aty_ld_8(DAC_REGS, info);  /* clear counter */
-    wait_for_idle(info);
-
-    aty_st_le32(CRTC_H_TOTAL_DISP, init->crtc_h_tot_disp, info);
-    aty_st_le32(CRTC_H_SYNC_STRT_WID,
-               init->crtc_h_sync_strt_wid[par->hw.gx.cmode], info);
-    aty_st_le32(CRTC_V_TOTAL_DISP, init->crtc_v_tot_disp, info);
-    aty_st_le32(CRTC_V_SYNC_STRT_WID, init->crtc_v_sync_strt_wid, info);
+    return 0;
+}
 
-    aty_st_8(CLOCK_CNTL, 0, info);
-    aty_st_8(CLOCK_CNTL, CLOCK_STROBE, info);
-
-    aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, info);
+static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp)
+{
+    static struct {
+       u8 pixel_dly;
+       u8 misc2_cntl;
+       u8 pixel_rep;
+       u8 pixel_cntl_index;
+       u8 pixel_cntl_v1;
+    } tab[3] = {
+       { 0, 0x41, 0x03, 0x71, 0x45 },  /* 8 bpp */
+       { 0, 0x45, 0x04, 0x0c, 0x01 },  /* 555 */
+       { 0, 0x45, 0x06, 0x0e, 0x00 },  /* XRGB */
+    };
+    int i;
 
-    set_off_pitch(par, info);
+    switch (bpp) {
+       case 8:
+       default:
+           i = 0;
+           break;
+       case 16:
+           i = 1;
+           break;
+       case 32:
+           i = 2;
+           break;
+    }
+    aty_st_514(0x90, 0x00, info);              /* VRAM Mask Low */
+    aty_st_514(0x04, tab[i].pixel_dly, info);  /* Horizontal Sync Control */
+    aty_st_514(0x05, 0x00, info);              /* Power Management */
+    aty_st_514(0x02, 0x01, info);              /* Misc Clock Control */
+    aty_st_514(0x71, tab[i].misc2_cntl, info); /* Misc Control 2 */
+    aty_st_514(0x0a, tab[i].pixel_rep, info);  /* Pixel Format */
+    aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, info);
+                       /* Misc Control 2 / 16 BPP Control / 32 BPP Control */
+}
 
-    switch (info->chip_class) {
-       case CLASS_GX:
-           /* The magic constant below translates into:
-            * 5  = No RDY delay, 1 wait st for mem write, increment during
-            *      burst transfer
-            * 9  = DAC access delayed, 1 wait state for DAC
-            * 0  = Disables interupts for FIFO errors
-            * e  = Allows FIFO to generate 14 wait states before generating
-            *      error
-            * 1  = DAC snooping disabled, ROM disabled
-            * 0  = ROM page at 0 (disabled so doesn't matter)
-            * f  = 15 ROM wait states (disabled so doesn't matter)
-            * f  = 15 BUS wait states (I'm not sure this applies to PCI bus
-            *      types)
-            * at some point it would be good to experiment with bench marks to
-            * if we can gain some speed by fooling with the wait states etc.
-            */
-           aty_st_le32(BUS_CNTL, 0x890e20f1 /* 0x590e10ff */, info);
-           j = 0x47012100;
-           j = 0x47052100;
+static int aty_crtc_to_var(const struct crtc *crtc,
+                          struct fb_var_screeninfo *var)
+{
+    u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync;
+    u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
+    u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol;
+    u32 pix_width;
+
+    /* input */
+    h_total = crtc->h_tot_disp & 0x1ff;
+    h_disp = (crtc->h_tot_disp>>16) & 0xff;
+    h_sync_strt = (crtc->h_sync_strt_wid & 0xff) |
+                 ((crtc->h_sync_strt_wid>>4) & 0x100);
+    h_sync_dly = (crtc->h_sync_strt_wid>>8) & 0x7;
+    h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x1f;
+    h_sync_pol = (crtc->h_sync_strt_wid>>21) & 0x1;
+    v_total = crtc->v_tot_disp & 0x7ff;
+    v_disp = (crtc->v_tot_disp>>16) & 0x7ff;
+    v_sync_strt = crtc->v_sync_strt_wid & 0x7ff;
+    v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f;
+    v_sync_pol = (crtc->v_sync_strt_wid>>21) & 0x1;
+    pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;
+
+    /* convert */
+    xres = (h_disp+1)*8;
+    yres = v_disp+1;
+    left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly;
+    right = (h_sync_strt-h_disp)*8;
+    hslen = h_sync_wid*8;
+    upper = v_total-v_sync_strt-v_sync_wid;
+    lower = v_sync_strt-v_disp;
+    vslen = v_sync_wid;
+    sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
+          (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT);
+
+    switch (pix_width) {
+#if 0
+       case CRTC_PIX_WIDTH_4BPP:
+           bpp = 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;
+           break;
+#endif
+       case CRTC_PIX_WIDTH_8BPP:
+           bpp = 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;
+           break;
+       case CRTC_PIX_WIDTH_15BPP:      /* RGB 555 */
+           bpp = 16;
+           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 = 0;
+           var->transp.length = 0;
            break;
+#if 0
+       case CRTC_PIX_WIDTH_16BPP:      /* RGB 565 */
+           bpp = 16;
+           var->red.offset = 11;
+           var->red.length = 5;
+           var->green.offset = 6;
+           var->green.length = 6;
+           var->blue.offset = 0;
+           var->blue.length = 5;
+           var->transp.offset = 0;
+           var->transp.length = 0;
+           break;
+#endif
+       case CRTC_PIX_WIDTH_24BPP:      /* RGB 888 */
+           bpp = 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;
+           break;
+       case CRTC_PIX_WIDTH_32BPP:      /* ARGB 8888 */
+           bpp = 32;
+           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;
+           break;
+       default:
+           FAIL("Invalid pixel width");
+    }
 
-       case CLASS_VT:
-           if (vram_type == 4) {
-               /*
-                * What to do here? - The contents of MEM_CNTL do not
-                * seem to match my documentation, and touching this
-                * register makes the output unusable.
-                * (green bars across the screen and similar effects).
-                *
-                * Eddie C. Dost  (ecd@skynet.be)
-                */
-               j = 0x87010184;
-               break;
-            }
-            /* fallthrough */
+    /* output */
+    var->xres = xres;
+    var->yres = yres;
+    var->xres_virtual = crtc->vxres;
+    var->yres_virtual = crtc->vyres;
+    var->bits_per_pixel = bpp;
+    var->xoffset = crtc->xoffset;
+    var->yoffset = crtc->yoffset;
+    var->left_margin = left;
+    var->right_margin = right;
+    var->upper_margin = upper;
+    var->lower_margin = lower;
+    var->hsync_len = hslen;
+    var->vsync_len = vslen;
+    var->sync = sync;
+    var->vmode = FB_VMODE_NONINTERLACED;
 
-       case CLASS_CT:
-           aty_st_le32(BUS_CNTL, 0x680000f9, info);
-           switch (info->total_vram) {
-               case 0x00100000:
-                   aty_st_le32(MEM_CNTL, vt_mem_cntl[0][par->hw.gx.cmode],
-                               info);
-                   break;
-               case 0x00200000:
-                   aty_st_le32(MEM_CNTL, vt_mem_cntl[1][par->hw.gx.cmode],
-                               info);
-                   break;
-               case 0x00400000:
-                   aty_st_le32(MEM_CNTL, vt_mem_cntl[2][par->hw.gx.cmode],
-                               info);
-                   break;
-               default:
-                   i = aty_ld_le32(MEM_CNTL, info) & 0x000F;
-                   aty_st_le32(MEM_CNTL,
-                               (init->mem_cntl[par->hw.gx.cmode] &
-                                0xFFFFFFF0) | i,
-                               info);
-           }
-           j = 0x87010184;
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+    /*
+     *  PLL programming (Mach64 GX family)
+     *
+     *  FIXME: use function pointer tables instead of switch statements
+     */
+
+static void aty_set_pll_gx(const struct fb_info_aty *info,
+                          const struct pll_gx *pll)
+{
+    switch (info->clk_type) {
+       case CLK_ATI18818_1:
+           aty_st_8(CLOCK_CNTL, pll->m, info);
+           break;
+       case CLK_IBMRGB514:
+           aty_st_514(0x06, 0x02, info);       /* DAC Operation */
+           aty_st_514(0x10, 0x01, info);       /* PLL Control 1 */
+           aty_st_514(0x70, 0x01, info);       /* Misc Control 1 */
+           aty_st_514(0x8f, 0x1f, info);       /* PLL Ref. Divider Input */
+           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 */
            break;
+    }
+}
 
-       case CLASS_GT:
-           aty_st_le32(BUS_CNTL, 0x7b23a040, info);
+static int aty_var_to_pll_18818(const struct fb_var_screeninfo *var,
+                               struct pll_gx *pll)
+{
+    /*
+     *  FIXME: use real calculations instead of using fixed values from the old
+     *        driver
+     */
+    static struct {
+       u32 ps_lim;     /* pixclock period rounding limit (arbitrary) */
+       u8 mode;        /* (prescsaler << 4) | Select */
+       u8 prog;        /* ref_div_count */
+    } ATI18818_clocks[] = {
+       {  7500, 0x0B, 1 },     /*  7407.4 ps = 135.00 MHz */
+       {  9000, 0x0A, 1 },     /*  7936.5 ps = 126.00 MHz */
+       { 11000, 0x09, 1 },     /* 10000.0 ps = 100.00 MHz */
+       { 12800, 0x0D, 1 },     /* 12500.0 ps =  80.00 MHz */
+       { 13500, 0x0E, 1 },     /* 13333.3 ps =  75.00 MHz */
+/*     { 14000, 0x03, 2 },*/   /* 13888.8 ps =  72.00 MHz */
+       { 15000, 0x1B, 1 },     /* 14814.8 ps =  67.50 MHz */
+       { 15500, 0x0F, 1 },     /* 15384.6 ps =  65.00 MHz */
+       { 16000, 0x1A, 1 },     /* 15873.0 ps =  63.00 MHz */
+/*     { 16000, 0x02, 2 },*/   /* 15873.0 ps =  63.00 MHz */
+/*     { 18000, 0x01, 2 },*/   /* 17655.4 ps =  56.64 MHz */
+/*     { 19900, 0x00, 2 },*/   /* 19860.9 ps =  50.35 MHz */
+       { 20000, 0x07, 1 },     /* 20000.0 ps =  50.00 MHz */
+       { 20300, 0x06, 1 },     /* 20202.0 ps =  49.50 MHz */
+       { 22500, 0x05, 1 },     /* 22271.2 ps =  44.90 MHz */
+       { 25000, 0x04, 1 },     /* 25000.0 ps =  40.00 MHz */
+/*     { 28000, 0x03, 1 },*/   /* 27777.8 ps =  36.00 MHz */
+       { 30000, 0x2B, 1 },     /* 29629,6 ps =  33.75 MHz */
+       { 31000, 0x1F, 1 },     /* 30769.2 ps =  32.50 MHz */
+       { 32000, 0x2A, 1 },     /* 31746.0 ps =  31.50 MHz */
+/*     { 32000, 0x02, 1 },*/   /* 31746.0 ps =  31.50 MHz */
+/*     { 36000, 0x01, 1 },*/   /* 35310.7 ps =  28.32 MHz */
+/*     { 39900, 0x00, 1 },*/   /* 39714.1 ps =  25.18 MHz */
+       { 40000, 0x17, 1 },     /* 40000.0 ps =  25.00 MHz */
+       { 40600, 0x16, 1 },     /* 40404.0 ps =  24.75 MHz */
+       { 45000, 0x15, 1 },     /* 44543.4 ps =  22.45 MHz */
+       { 50000, 0x14, 1 },     /* 50000.0 ps =  20.00 MHz */
+/*     { 56000, 0x13, 1 },*/   /* 55555.5 ps =  18.00 MHz */
+       { 62000, 0x2F, 1 },     /* 61538.8 ps =  16.25 MHz */
+/*     { 64000, 0x12, 1 },*/   /* 63492.0 ps =  15.75 MHz */
+    };
+    int set;
+
+    for (set = 0; set < sizeof(ATI18818_clocks)/sizeof(*ATI18818_clocks);
+        set++)
+       if (var->pixclock <= ATI18818_clocks[set].ps_lim) {
+           pll->m = ATI18818_clocks[set].mode;
+           pll->n = ATI18818_clocks[set].prog;
+           return 0;
+       }
+    return -EINVAL;
+}
+
+static int aty_var_to_pll_514(const struct fb_var_screeninfo *var,
+                             struct pll_gx *pll)
+{
+    /*
+     *  FIXME: use real calculations instead of using fixed values from the old
+     *        driver
+     */
+    static struct {
+       u32 limit;      /* pixlock rounding limit (arbitrary) */
+       u8 m;           /* (df<<6) | vco_div_count */
+       u8 n;           /* ref_div_count */
+    } RGB514_clocks[7] = {
+       {  8000, (3<<6) | 20, 9 },      /*  7395 ps / 135.2273 MHz */
+       { 10000, (1<<6) | 19, 3 },      /*  9977 ps / 100.2273 MHz */
+       { 13000, (1<<6) |  2, 3 },      /* 12509 ps /  79.9432 MHz */
+       { 14000, (2<<6) |  8, 7 },      /* 13394 ps /  74.6591 MHz */
+       { 16000, (1<<6) | 44, 6 },      /* 15378 ps /  65.0284 MHz */
+       { 25000, (1<<6) | 15, 5 },      /* 17460 ps /  57.2727 MHz */
+       { 50000, (0<<6) | 53, 7 },      /* 33145 ps /  30.1705 MHz */
+    };
+    int i;
+
+    for (i = 0; i < sizeof(RGB514_clocks)/sizeof(*RGB514_clocks); i++)
+       if (var->pixclock <= RGB514_clocks[i].limit) {
+           pll->m = RGB514_clocks[i].m;
+           pll->n = RGB514_clocks[i].n;
+           return 0;
+       }
+    return -EINVAL;
+}
 
-           /* need to set DSP values !! assume sdram */
-           i = init->crtc_gen_cntl[0] - (0x100000 * par->hw.gx.cmode);
-           if ( vram_type == 5 )
-               i = init->crtc_gen_cntl[1] - (0x100000 * par->hw.gx.cmode);
-           aty_st_le32(DSP_CONFIG, i, info);
+    /* FIXME: ATI18818?? */
 
-           i = aty_ld_le32(MEM_CNTL, info) & MEM_SIZE_ALIAS;
-           if ( vram_type == 5 ) {
-               i |= ((1 * par->hw.gx.cmode) << 26) | 0x4215b0;
-               aty_st_le32(DSP_ON_OFF,
-                           sgram_dsp[par->hw.gx.vmode-1][par->hw.gx.cmode],
-                           info);
+static int aty_pll_gx_to_var(const struct pll_gx *pll,
+                            struct fb_var_screeninfo *var)
+{
+    u8 df, vco_div_count, ref_div_count;
 
-               /* aty_st_le32(CLOCK_CNTL, 8192, info); */
-           } else {
-               i |= ((1 * par->hw.gx.cmode) << 26) | 0x300090;
-               aty_st_le32(DSP_ON_OFF, init->mem_cntl[par->hw.gx.cmode],
-                           info);
-           }
-           aty_st_le32(MEM_CNTL, i, info);
-           aty_st_le32(EXT_MEM_CNTL, 0x5000001, info);
+    df = pll->m >> 6;
+    vco_div_count = pll->m & 0x3f;
+    ref_div_count = pll->n;
+
+    var->pixclock = (ref_clk_per*(vco_div_count+65)/ref_div_count)>>(3-df);
+
+    return 0;
+}
 
-           /* if (info->total_vram > 0x400000) 
-               i |= 0x538; this not been verified on > 4Megs!! */
 
-           j = 0x86010102;
+    /*
+     *  PLL programming (Mach64 CT family)
+     */
+
+static void aty_set_pll_ct(const struct fb_info_aty *info,
+                          const struct pll_ct *pll)
+{
+#if 0 /* ecd debug */
+printk("PLL_REF_DIV:   %02x (%02x)\n",
+       pll->pll_ref_div, aty_ld_pll(PLL_REF_DIV, info));
+printk("PLL_GEN_CNTL:  %02x (%02x)\n",
+       pll->pll_gen_cntl, aty_ld_pll(PLL_GEN_CNTL, info));
+printk("MCLK_FB_DIV:   %02x (%02x)\n",
+       pll->mclk_fb_div, aty_ld_pll(MCLK_FB_DIV, info));
+printk("PLL_VCLK_CNTL: %02x (%02x)\n",
+       pll->pll_vclk_cntl, aty_ld_pll(PLL_VCLK_CNTL, info));
+printk("VCLK_POST_DIV: %02x (%02x)\n",
+       pll->vclk_post_div, aty_ld_pll(VCLK_POST_DIV, info));
+printk("VCLK0_FB_DIV:  %02x (%02x)\n",
+       pll->vclk_fb_div, aty_ld_pll(VCLK0_FB_DIV, info));
+printk("PLL_EXT_CNTL:  %02x (%02x)\n",
+       pll->pll_ext_cntl, aty_ld_pll(PLL_EXT_CNTL, info));
+#endif /* ecd debug */
+    aty_st_pll(PLL_REF_DIV, pll->pll_ref_div, info);
+    aty_st_pll(PLL_GEN_CNTL, pll->pll_gen_cntl, info);
+    aty_st_pll(MCLK_FB_DIV, pll->mclk_fb_div, info);
+    aty_st_pll(PLL_VCLK_CNTL, pll->pll_vclk_cntl, info);
+    aty_st_pll(VCLK_POST_DIV, pll->vclk_post_div, info);
+    aty_st_pll(VCLK0_FB_DIV, pll->vclk_fb_div, info);
+    aty_st_pll(PLL_EXT_CNTL, pll->pll_ext_cntl, info);
+
+    if (((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_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) ||
+       (Gx == VU_CHIP_ID)) {
+       if (info->ram_type >= SDRAM)
+           aty_st_pll(DLL_CNTL, 0xa6, info);
+       else
+           aty_st_pll(DLL_CNTL, 0xa0, info);
+       aty_st_pll(VFC_CNTL, 0x1b, info);
+       aty_st_le32(DSP_CONFIG, pll->dsp_config, info);
+       aty_st_le32(DSP_ON_OFF, pll->dsp_on_off, info);
+    }
+}
+
+static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div,
+                     u8 mclk_post_div, u8 vclk_fb_div, u8 vclk_post_div,
+                     u8 bpp, struct pll_ct *pll)
+{
+    u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off, dsp_on;
+    u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size, page_size;
+
+    /* xclocks_per_row<<11 */
+    xclks_per_row = (mclk_fb_div*vclk_post_div*64<<11)/
+                   (vclk_fb_div*mclk_post_div*bpp);
+    if (xclks_per_row < (1<<11))
+       FAIL("Dotclock to high");
+    fifo_size = 24;
+    dsp_precision = 0;
+    y = (xclks_per_row*fifo_size)>>11;
+    while (y) {
+       y >>= 1;
+       dsp_precision++;
+    }
+    dsp_precision -= 5;
+    /* fifo_off<<6 */
+    fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(1<<6);
+
+    if (info->total_vram > 1*1024*1024) {
+       if (info->ram_type >= SDRAM) {
+           /* >1 MB SDRAM */
+           dsp_loop_latency = 8;
+           page_size = 8;
+       } else {
+           /* >1 MB DRAM */
+           dsp_loop_latency = 6;
+           page_size = 9;
+       }
+    } else {
+       if (info->ram_type >= SDRAM) {
+           /* <2 MB SDRAM */
+           dsp_loop_latency = 9;
+           page_size = 10;
+       } else {
+           /* <2 MB DRAM */
+           dsp_loop_latency = 8;
+           page_size = 10;
+       }
+    }
+    /* fifo_on<<6 */
+    if (xclks_per_row >= (page_size<<11))
+       fifo_on = ((2*page_size+1)<<6)+(xclks_per_row>>5);
+    else
+       fifo_on = (3*page_size)<<6;
+
+    dsp_xclks_per_row = xclks_per_row>>dsp_precision;
+    dsp_on = fifo_on>>dsp_precision;
+    dsp_off = fifo_off>>dsp_precision;
+
+    pll->dsp_config = (dsp_xclks_per_row & 0x3fff) |
+                     ((dsp_loop_latency & 0xf)<<16) |
+                     ((dsp_precision & 7)<<20);
+    pll->dsp_on_off = (dsp_on & 0x7ff) | ((dsp_off & 0x7ff)<<16);
+    return 0;
+}
+
+static int aty_var_to_pll_ct(const struct fb_info_aty *info,
+                            const struct fb_var_screeninfo *var,
+                            struct pll_ct *pll)
+{
+    u32 vclk_per, q, x;                /* x is a workaround for sparc64-linux-gcc */
+    u8 pll_ref_div, pll_gen_cntl, pll_ext_cntl;
+    u8 mclk_fb_div, mclk_post_div, mpostdiv = 0;
+    u8 vclk_fb_div, vclk_post_div, vpostdiv = 0;
+    int err;
+
+    x = x;                     /* x is a workaround for sparc64-linux-gcc */
+
+    pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
+
+    vclk_per = var->pixclock;
+    pll_ref_div = info->pll_per*2*255/ref_clk_per;
+
+    /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
+    q = ref_clk_per*pll_ref_div*4/info->mclk_per;      /* actually 8*q */
+    if (q < 16*8 || q > 255*8)
+       FAIL("mclk out of range");
+    else if (q < 32*8)
+       mclk_post_div = 8;
+    else if (q < 64*8)
+       mclk_post_div = 4;
+    else if (q < 128*8)
+       mclk_post_div = 2;
+    else
+       mclk_post_div = 1;
+    mclk_fb_div = q*mclk_post_div/8;
+
+    /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
+    q = ref_clk_per*pll_ref_div*4/vclk_per;    /* actually 8*q */
+    if (q < 16*8 || q > 255*8)
+       FAIL("vclk out of range");
+    else if (q < 32*8)
+       vclk_post_div = 8;
+    else if (q < 64*8)
+       vclk_post_div = 4;
+    else if (q < 128*8)
+       vclk_post_div = 2;
+    else
+       vclk_post_div = 1;
+    vclk_fb_div = q*vclk_post_div/8;
+
+    if ((err = aty_dsp_gt(info, mclk_fb_div, mclk_post_div, vclk_fb_div,
+                         vclk_post_div, var->bits_per_pixel, pll)))
+       return err;
+
+    if ((((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_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) ||
+        (Gx == VU_CHIP_ID)) && (info->ram_type >= SDRAM))
+       pll_gen_cntl = 0x04;
+    else
+       pll_gen_cntl = 0x84;
+
+    switch (mclk_post_div) {
+       case 1:
+           mpostdiv = 0;
+           break;
+       case 2:
+           mpostdiv = 1;
+           break;
+       case 3:
+           mpostdiv = 4;
+           break;
+       case 4:
+           mpostdiv = 2;
+           break;
+       case 8:
+           mpostdiv = 3;
            break;
     }
+    pll_gen_cntl |= mpostdiv<<4;       /* mclk */
 
-    /* These magic constants (variable j) are harder to figure out
-    * on the vt chipset bit 2 set makes the screen brighter
-    * and bit 15 makes the screen black! But nothing else
-    * seems to matter for the vt DAC_CNTL
-    */
-    aty_st_le32(DAC_CNTL, j, info);
-    aty_st_8(DAC_MASK, 0xff, info);
+    if (Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48))
+       pll_ext_cntl = 0;
+    else
+       pll_ext_cntl = mpostdiv;        /* xclk == mclk */
 
-    switch (par->hw.gx.cmode) {
-       case CMODE_16:
-           i = CRTC_PIX_WIDTH_15BPP; break;
-       /*case CMODE_24: */
-       case CMODE_32:
-           i = CRTC_PIX_WIDTH_32BPP; break;
-       case CMODE_8:
-       default:
-           i = CRTC_PIX_WIDTH_8BPP; break;
+    switch (vclk_post_div) {
+       case 1:
+           vpostdiv = 0;
+           break;
+       case 2:
+           vpostdiv = 1;
+           break;
+       case 3:
+           vpostdiv = 0;
+           pll_ext_cntl |= 0x10;
+           break;
+       case 4:
+           vpostdiv = 2;
+           break;
+       case 6:
+           vpostdiv = 2;
+           pll_ext_cntl |= 0x10;
+           break;
+       case 8:
+           vpostdiv = 3;
+           break;
+       case 12:
+           vpostdiv = 3;
+           pll_ext_cntl |= 0x10;
+           break;
     }
+    vclk_post_div = vpostdiv;
+
+    pll->pll_ref_div = pll_ref_div;
+    pll->pll_gen_cntl = pll_gen_cntl;
+    pll->mclk_fb_div = mclk_fb_div;
+    pll->vclk_post_div = vclk_post_div;
+    pll->vclk_fb_div = vclk_fb_div;
+    pll->pll_ext_cntl = pll_ext_cntl;
+    return 0;
+}
+
+static int aty_pll_ct_to_var(const struct pll_ct *pll,
+                            struct fb_var_screeninfo *var)
+{
+    u8 pll_ref_div = pll->pll_ref_div;
+    u8 vclk_fb_div = pll->vclk_fb_div;
+    u8 vclk_post_div = pll->vclk_post_div;
+    u8 pll_ext_cntl = pll->pll_ext_cntl;
+    static u8 vclk_post_div_tab[] = {
+       1, 2, 4, 8,
+       3, 0, 6, 12
+    };
+    u8 vpostdiv = vclk_post_div_tab[((pll_ext_cntl & 0x10) >> 1) |
+                                   (vclk_post_div & 3)];
+    if (vpostdiv == 0)
+       return -EINVAL;
+    var->pixclock = pll_ref_div*vpostdiv*ref_clk_per/vclk_fb_div/2;
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void atyfb_set_par(const struct atyfb_par *par,
+                         struct fb_info_aty *info)
+{
+    u32 i;
+
+    info->current_par = *par;
+
+    aty_set_crtc(info, &par->crtc);
+    aty_st_8(CLOCK_CNTL, 0, info);
+    aty_st_8(CLOCK_CNTL, CLOCK_STROBE, info);
 
-    if (info->chip_class != CLASS_GT) {
-       aty_st_le32(CRTC_INT_CNTL, 0x00000002, info);
-       aty_st_le32(GEN_TEST_CNTL, GUI_ENGINE_ENABLE | BLOCK_WRITE_ENABLE,
-                   info);      /* gui_en block_en */
-       i |= init->crtc_gen_cntl[par->hw.gx.cmode];
+    if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
+       switch (info->dac_type) {
+           case DAC_IBMRGB514:
+               aty_set_dac_514(info, par->crtc.bpp);
+               break;
+           case DAC_ATI68860_B:
+               /* FIXME */
+               break;
+       }
+       aty_set_pll_gx(info, &par->pll.gx);
+       aty_st_le32(BUS_CNTL, 0x890e20f1, info);
+       aty_st_le32(DAC_CNTL, 0x47052100, info);
+    } else {
+       aty_set_pll_ct(info, &par->pll.ct);
+       i = aty_ld_le32(MEM_CNTL, info) & 0xf30fffff;
+       if (!(Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48)))
+               i |= info->mem_refresh_rate << 20;
+       switch (par->crtc.bpp) {
+           case 8:
+           case 24:
+               i |= 0x00000000;
+               break;
+           case 16:
+               i |= 0x04000000;
+               break;
+           case 32:
+               i |= 0x08000000;
+               break;
+       }
+       if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
+           aty_st_le32(DAC_CNTL, 0x87010184, info);
+           aty_st_le32(BUS_CNTL, 0x680000f9, info);
+       } else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) {
+           aty_st_le32(DAC_CNTL, 0x87010184, info);
+           aty_st_le32(BUS_CNTL, 0x680000f9, info);
+       } else {
+           /* GT */
+           aty_st_le32(DAC_CNTL, 0x86010102, info);
+           aty_st_le32(BUS_CNTL, 0x7b23a040, info);
+           aty_st_le32(EXT_MEM_CNTL, 0x5000001, info);
+       }
+       aty_st_le32(MEM_CNTL, i, info);
     }
-    /* Gentlemen, start your crtc engine */
-    aty_st_le32(CRTC_GEN_CNTL, CRTC_EXT_DISP_EN | CRTC_ENABLE | i, info);
+    aty_st_8(DAC_MASK, 0xff, info);
 
     /* Initialize the graphics engine */
-    if (par->accel & FB_ACCELF_TEXT)
+    if (par->accel_flags & FB_ACCELF_TEXT)
        init_engine(par, info);
 
 #ifdef CONFIG_FB_COMPAT_XPMAC
     if (console_fb_info == &info->fb_info) {
-       display_info.height = vmode_attrs[par->hw.gx.vmode-1].vres;
-       display_info.width = vmode_attrs[par->hw.gx.vmode-1].hres;
-       display_info.depth = 8<<par->hw.gx.cmode;
-       display_info.pitch = par->vxres<<par->hw.gx.cmode;
-       display_info.mode = par->hw.gx.vmode;
+       struct fb_var_screeninfo var;
+       int vmode, cmode;
+       display_info.height = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1;
+       display_info.width = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8;
+       display_info.depth = par->crtc.bpp;
+       display_info.pitch = par->crtc.vxres*par->crtc.bpp/8;
+       atyfb_encode_var(&var, par, info);
+       if (mac_var_to_vmode(&var, &vmode, &cmode))
+           display_info.mode = 0;
+       else
+           display_info.mode = vmode;
        strcpy(display_info.name, atyfb_name);
        display_info.fb_address = info->frame_buffer_phys;
-       if (info->chip_class == CLASS_VT)
-           display_info.fb_address += init->offset[par->hw.gx.cmode];
        display_info.cmap_adr_address = info->ati_regbase_phys+0xc0;
        display_info.cmap_data_address = info->ati_regbase_phys+0xc1;
        display_info.disp_reg_address = info->ati_regbase_phys;
@@ -1311,6 +1712,79 @@ static void atyfb_set_par(struct atyfb_par *par, struct fb_info_aty *info)
 #endif /* CONFIG_FB_COMPAT_XPMAC */
 }
 
+static int atyfb_decode_var(const struct fb_var_screeninfo *var,
+                           struct atyfb_par *par,
+                           const struct fb_info_aty *info)
+{
+    int err;
+
+    if ((err = aty_var_to_crtc(info, var, &par->crtc)))
+       return err;
+    if ((Gx == GX_PCI_ID) || (Gx == CX_PCI_ID))
+       switch (info->clk_type) {
+           case CLK_ATI18818_1:
+               err = aty_var_to_pll_18818(var, &par->pll.gx);
+               break;
+           case CLK_IBMRGB514:
+               err = aty_var_to_pll_514(var, &par->pll.gx);
+               break;
+       }
+    else
+       err = aty_var_to_pll_ct(info, var, &par->pll.ct);
+    if (err)
+       return err;
+
+    if (var->accel_flags & FB_ACCELF_TEXT)
+       par->accel_flags = FB_ACCELF_TEXT;
+    else
+       par->accel_flags = 0;
+
+#if 0
+    if (!fbmon_valid_timings(pixclock, htotal, vtotal, info))
+       return -EINVAL;
+#endif
+
+    return 0;
+}
+
+static int atyfb_encode_var(struct fb_var_screeninfo *var,
+                           const struct atyfb_par *par,
+                           const struct fb_info_aty *info)
+{
+    int err;
+
+    memset(var, 0, sizeof(struct fb_var_screeninfo));
+
+    if ((err = aty_crtc_to_var(&par->crtc, var)))
+       return err;
+    if ((Gx == GX_PCI_ID) || (Gx == CX_PCI_ID))
+       err = aty_pll_gx_to_var(&par->pll.gx, var);
+    else
+       err = aty_pll_ct_to_var(&par->pll.ct, var);
+    if (err)
+       return err;
+
+    var->height = -1;
+    var->width = -1;
+    var->accel_flags = par->accel_flags;
+
+    return 0;
+}
+
+
+
+static void set_off_pitch(struct atyfb_par *par,
+                         const struct fb_info_aty *info)
+{
+    u32 xoffset = par->crtc.xoffset;
+    u32 yoffset = par->crtc.yoffset;
+    u32 vxres = par->crtc.vxres;
+    u32 bpp = par->crtc.bpp;
+
+    par->crtc.off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
+    aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, info);
+}
+
 
     /*
      *  Open/Release the frame buffer device
@@ -1319,350 +1793,129 @@ static void atyfb_set_par(struct atyfb_par *par, struct fb_info_aty *info)
 static int atyfb_open(struct fb_info *info, int user)
 
 {
-    /*
-     *  Nothing, only a usage count for the moment
-     */
-
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)info;
+
+    if (user) {
+       if (fb->open)
+           return -EBUSY;
+       fb->mmaped = 0;
+       fb->open = 1;
+       fb->vtconsole = -1;
+    } else {
+       fb->consolecnt++;
+    }
+#endif
     MOD_INC_USE_COUNT;
     return(0);
 }
 
 static int atyfb_release(struct fb_info *info, int user)
 {
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)info;
+
+    if (user) {
+       if (fb->vtconsole != -1)
+           vt_cons[fb->vtconsole]->vc_mode = KD_TEXT;
+       fb->open = 0;
+       fb->mmaped = 0;
+       fb->vtconsole = -1;
+    } else {
+       fb->consolecnt--;
+    }
+#endif
     MOD_DEC_USE_COUNT;
     return(0);
 }
 
 
 static int encode_fix(struct fb_fix_screeninfo *fix,
-                     const struct atyfb_par *par, struct fb_info_aty *info)
+                     const struct atyfb_par *par,
+                     const struct fb_info_aty *info)
 {
-    struct aty_regvals *init;
-
     memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 
     strcpy(fix->id, atyfb_name);
-    init = get_aty_struct(par->hw.gx.vmode, info);
-    /*
-     *  FIXME: This will cause problems on non-GT chips, because the frame
-     *  buffer must be aligned to a page
-     */
     fix->smem_start = (char *)info->frame_buffer_phys;
-    if (info->chip_class == CLASS_VT)
-       fix->smem_start += init->offset[par->hw.gx.cmode];
     fix->smem_len = (u32)info->total_vram;
 
 #ifdef __LITTLE_ENDIAN
     /*
      *  Last page of 8 MB little-endian aperture is MMIO
-     *  FIXME: we should use the auxillary aperture instead so we can acces the
+     *  FIXME: we should use the auxiliary aperture instead so we can acces the
      *  full 8 MB of video RAM on 8 MB boards
      */
-    if (fix->smem_len > 0x800000-PAGE_SIZE)
-       fix->smem_len = 0x800000-PAGE_SIZE;
+    if (fix->smem_len > 0x800000-GUI_RESERVE)
+       fix->smem_len = 0x800000-GUI_RESERVE;
 #endif
     /*
      *  Reg Block 0 (CT-compatible block) is at ati_regbase_phys
      *  Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400
-     */
-    switch (info->chip_class) {
-       case CLASS_GX:
-           fix->mmio_start = (char *)info->ati_regbase_phys;
-           fix->mmio_len = 0x400;
-           fix->accel = FB_ACCEL_ATI_MACH64GX;
-           break;
-       case CLASS_CT:
-           fix->mmio_start = (char *)info->ati_regbase_phys;
-           fix->mmio_len = 0x400;
-           fix->accel = FB_ACCEL_ATI_MACH64CT;
-           break;
-       case CLASS_VT:
-           fix->mmio_start = (char *)(info->ati_regbase_phys-0x400);
-           fix->mmio_len = 0x800;
-           fix->accel = FB_ACCEL_ATI_MACH64VT;
-           break;
-       case CLASS_GT:
-           fix->mmio_start = (char *)(info->ati_regbase_phys-0x400);
-           fix->mmio_len = 0x800;
-           fix->accel = FB_ACCEL_ATI_MACH64GT;
-           break;
-       default:
-           fix->mmio_start = NULL;
-           fix->mmio_len = 0;
-           fix->accel = 0;
-    }
-    fix->type = FB_TYPE_PACKED_PIXELS;
-    fix->type_aux = 0;
-    fix->line_length = par->vxres<<par->hw.gx.cmode;
-    fix->visual = par->hw.gx.cmode == CMODE_8 ? FB_VISUAL_PSEUDOCOLOR
-                                             : FB_VISUAL_TRUECOLOR;
-    fix->ywrapstep = 0;
-    fix->xpanstep = 8;
-    fix->ypanstep = 1;
-
-    return 0;
-}
-
-
-static int decode_var(struct fb_var_screeninfo *var,
-                     struct atyfb_par *par, struct fb_info_aty *info)
-{
-    int xres = var->xres;
-    int yres = var->yres;
-    int bpp = var->bits_per_pixel;
-    struct aty_regvals *init;
-
-    /* This should support more video modes */
-
-    if (xres <= 512 && yres <= 384)
-       par->hw.gx.vmode = VMODE_512_384_60;    /* 512x384, 60Hz */
-    else if (xres <= 640 && yres <= 480)
-       par->hw.gx.vmode = VMODE_640_480_67;    /* 640x480, 67Hz */
-    else if (xres <= 640 && yres <= 870)
-       par->hw.gx.vmode = VMODE_640_870_75P;   /* 640x870, 75Hz (portrait) */
-    else if (xres <= 768 && yres <= 576)
-       par->hw.gx.vmode = VMODE_768_576_50I;   /* 768x576, 50Hz (PAL full frame) */
-    else if (xres <= 800 && yres <= 600)
-       par->hw.gx.vmode = VMODE_800_600_75;    /* 800x600, 75Hz */
-    else if (xres <= 832 && yres <= 624)
-       par->hw.gx.vmode = VMODE_832_624_75;    /* 832x624, 75Hz */
-    else if (xres <= 1024 && yres <= 768)
-       par->hw.gx.vmode = VMODE_1024_768_75;   /* 1024x768, 75Hz */
-    else if (xres <= 1152 && yres <= 870)
-       par->hw.gx.vmode = VMODE_1152_870_75;   /* 1152x870, 75Hz */
-    else if (xres <= 1280 && yres <= 960)
-       par->hw.gx.vmode = VMODE_1280_960_75;   /* 1280x960, 75Hz */
-    else if (xres <= 1280 && yres <= 1024)
-       par->hw.gx.vmode = VMODE_1280_1024_75;  /* 1280x1024, 75Hz */
-    else
-       return -EINVAL;
-
-    xres = vmode_attrs[par->hw.gx.vmode-1].hres;
-    yres = vmode_attrs[par->hw.gx.vmode-1].vres;
-
-    if (var->xres_virtual <= xres)
-       par->vxres = xres;
-    else
-       par->vxres = (var->xres_virtual+7) & ~7;
-    if (var->yres_virtual <= yres)
-       par->vyres = yres;
-    else
-       par->vyres = var->yres_virtual;
-
-    par->xoffset = (var->xoffset+7) & ~7;
-    par->yoffset = var->yoffset;
-    if (par->xoffset+xres > par->vxres || par->yoffset+yres > par->vyres)
-       return -EINVAL;
-
-    if (bpp <= 8)
-       par->hw.gx.cmode = CMODE_8;
-    else if (bpp <= 16)
-       par->hw.gx.cmode = CMODE_16;
-    else if (bpp <= 32)
-       par->hw.gx.cmode = CMODE_32;
-    else
-       return -EINVAL;
-
-    if (var->accel_flags & FB_ACCELF_TEXT)
-       par->accel = FB_ACCELF_TEXT;
-    else
-       par->accel = 0;
-
-    if (aty_vram_reqd(par) > info->total_vram)
-       return -EINVAL;
-
-    /* Check if we know about the wanted video mode */
-    init = get_aty_struct(par->hw.gx.vmode, info);
-    if (init == NULL || init->crtc_h_sync_strt_wid[par->hw.gx.cmode] == 0 ||
-       (info->chip_class != CLASS_GT &&
-        init->crtc_gen_cntl[par->hw.gx.cmode] == 0) ||
-       (info->chip_class == CLASS_GT &&
-        (aty_ld_le32(CONFIG_STAT0, info) & 7) == 5 &&
-        init->crtc_gen_cntl[1] == 0))
-       return -EINVAL;
-
-#if 0
-    if (!fbmon_valid_timings(pixclock, htotal, vtotal, info))
-       return -EINVAL;
-#endif
+     */
+    if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
+       fix->mmio_start = (char *)info->ati_regbase_phys;
+       fix->mmio_len = 0x400;
+       fix->accel = FB_ACCEL_ATI_MACH64GX;
+    } else if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
+       fix->mmio_start = (char *)info->ati_regbase_phys;
+       fix->mmio_len = 0x400;
+       fix->accel = FB_ACCEL_ATI_MACH64CT;
+    } else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) {
+       fix->mmio_start = (char *)(info->ati_regbase_phys-0x400);
+       fix->mmio_len = 0x800;
+       fix->accel = FB_ACCEL_ATI_MACH64VT;
+    } else {
+       fix->mmio_start = (char *)(info->ati_regbase_phys-0x400);
+       fix->mmio_len = 0x800;
+       fix->accel = FB_ACCEL_ATI_MACH64GT;
+    }
+    fix->type = FB_TYPE_PACKED_PIXELS;
+    fix->type_aux = 0;
+    fix->line_length = par->crtc.vxres*par->crtc.bpp/8;
+    fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR
+                                    : FB_VISUAL_DIRECTCOLOR;
+    fix->ywrapstep = 0;
+    fix->xpanstep = 8;
+    fix->ypanstep = 1;
 
     return 0;
 }
 
-static int encode_var(struct fb_var_screeninfo *var,
-                     const struct atyfb_par *par,
-                     struct fb_info_aty *info)
-{
-    int vmode = par->hw.gx.vmode;
-    int cmode = par->hw.gx.cmode;
-    struct aty_regvals *init = get_aty_struct(vmode, info);
-    u_int h_total, h_disp;
-    u_int h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
-    u_int v_total, v_disp;
-    u_int v_sync_strt, v_sync_wid, v_sync_pol;
-    u_int xtalin, vclk = 0;
-    u8 pll_ref_div, vclk_fb_div, vclk_post_div, pll_ext_cntl;
-
-    memset(var, 0, sizeof(struct fb_var_screeninfo));
-    if (!init)
-       return -EINVAL;
 
-    var->xres = vmode_attrs[vmode-1].hres;
-    var->yres = vmode_attrs[vmode-1].vres;
-    var->xres_virtual = par->vxres;
-    var->yres_virtual = par->vyres;
-    var->xoffset = par->xoffset;
-    var->yoffset = par->yoffset;
-    var->grayscale = 0;
-    switch (cmode) {
-       case CMODE_8:
-           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;
-           break;
-       case CMODE_16:  /* RGB 555 */
-           var->bits_per_pixel = 16;
-           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 = 0;
-           var->transp.length = 0;
-           break;
-       case CMODE_32:  /* RGB 888 */
-           var->bits_per_pixel = 32;
-           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;
-           break;
-    }
-    var->red.msb_right = 0;
-    var->green.msb_right = 0;
-    var->blue.msb_right = 0;
-    var->transp.msb_right = 0;
-    var->nonstd = 0;
-    var->activate = 0;
-    var->height = -1;
-    var->width = -1;
-    var->vmode = FB_VMODE_NONINTERLACED;
-    var->accel_flags = par->accel;
-
-    h_total = (init->crtc_h_tot_disp<<3) & 0xff8;
-    h_disp = (init->crtc_h_tot_disp>>13) & 0x7f8;
-    h_sync_strt = ((init->crtc_h_sync_strt_wid[cmode]<<3) & 0x7f8) |
-                 ((init->crtc_h_sync_strt_wid[cmode]>>1) & 0x800);
-    h_sync_dly = (init->crtc_h_sync_strt_wid[cmode]>>8) & 0x7;
-    h_sync_wid = (init->crtc_h_sync_strt_wid[cmode]>>13) & 0xf8;
-    h_sync_pol = (init->crtc_h_sync_strt_wid[cmode]>>21) & 0x1;
-
-    v_total = init->crtc_v_tot_disp & 0x7ff;
-    v_disp = (init->crtc_v_tot_disp>>16) & 0x7ff;
-    v_sync_strt = init->crtc_v_sync_strt_wid & 0x7ff;
-    v_sync_wid = (init->crtc_v_sync_strt_wid>>16) & 0x1f;
-    v_sync_pol = (init->crtc_v_sync_strt_wid>>21) & 0x1;
-
-    var->left_margin = (h_total+8)-h_sync_strt-h_sync_wid;
-    var->right_margin = h_sync_strt-(h_disp+8);
-    var->upper_margin = (v_total+1)-v_sync_strt-v_sync_wid;
-    var->lower_margin = v_sync_strt-(v_disp+1);
-    var->hsync_len = h_sync_wid;
-    var->vsync_len = v_sync_wid;
-    var->sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
-               (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT);
-
-    xtalin = 69841;    /* 14.31818 MHz */
-    switch (info->chip_class) {
-       case CLASS_GX:
-           {
-               /* haven't read the IBM RGB514 PDF yet, so just guesses */
-               static u32 gx_vclk[VMODE_MAX] = {
-                       0,      /* vmode  1 */  
-                       0,      /* vmode  2 */  
-                       0,      /* vmode  3 */  
-                       0,      /* vmode  4 */  
-                   39722,      /* vmode  5 (25.175 MHz) */
-                   33333,      /* vmode  6 (30 MHz) */
-                       0,      /* vmode  7 */  
-                       0,      /* vmode  8 */  
-                   27778,      /* vmode  9 (36 MHz) */
-                   25000,      /* vmode 10 (40 MHz) */
-                   20000,      /* vmode 11 (50 MHz) */
-                   20000,      /* vmode 12 (50 MHz) */
-                   17544,      /* vmode 13 (57 MHz) */
-                   15385,      /* vmode 14 (65 MHz) */
-                   13333,      /* vmode 15 (75 MHz) */
-                       0,      /* vmode 16 */  
-                   12821,      /* vmode 17 (78 MHz) */
-                   10000,      /* vmode 18 (100 MHz) */
-                    7937,      /* vmode 19 (126 MHz) */
-                    7407       /* vmode 20 (135 MHz) */
-               };
-               vclk = gx_vclk[vmode-1];
-           }
-           break;
-       case CLASS_CT:
-       case CLASS_GT:
-       case CLASS_VT:
-           if (info->chip_class == CLASS_GT) {
-               pll_ref_div = 0x21;
-               vclk_post_div = init->offset[0];
-               vclk_fb_div = init->offset[1];
-               pll_ext_cntl = init->offset[2];
-           } else {
-               pll_ref_div = 0x2d;
-               vclk_post_div = init->clock_val[0];
-               vclk_fb_div = init->clock_val[1];
-               pll_ext_cntl = 0x0;
-           }
-           vclk = xtalin*pll_ref_div;
-           switch (vclk_post_div & 3) {
-               case 0:
-                   vclk *= (pll_ext_cntl & 0x10) ? 3 : 1;
-                   break;
-               case 1:
-                   if (pll_ext_cntl & 0x10)
-                       return -EINVAL;
-                   vclk *= 2;
-                   break;
-               case 2:
-                   vclk *= (pll_ext_cntl & 0x10) ? 6 : 4;
-                   break;
-               case 3:
-                   vclk *= (pll_ext_cntl & 0x10) ? 12 : 8;
-                   break;
-           }
-           vclk /= 2*vclk_fb_div;
-           break;
-    }
-    var->pixclock = vclk;
+struct fb_var_screeninfo default_var = {
+    /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+    640, 480, 640, 480, 0, 0, 8, 0,
+    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
+    0, FB_VMODE_NONINTERLACED
+};
 
-    return 0;
-}
+#ifdef __sparc__
+struct fb_var_screeninfo default_var_1024x768 __initdata = {
+    /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
+    1024, 768, 1024, 768, 0, 0, 8, 0,
+    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0, 12699, 176, 16, 28, 1, 96, 3,
+    FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
 
+struct fb_var_screeninfo default_var_1152x900 __initdata = {
+    /* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */
+    1152, 900, 1152, 900, 0, 0, 8, 0,
+    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0, 9091, 234, 24, 34, 3, 100, 3,
+    FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
 
-static void init_par(struct atyfb_par *par, int vmode, int cmode)
-{
-    par->hw.gx.vmode = vmode;
-    par->hw.gx.cmode = cmode;
-    par->vxres = vmode_attrs[vmode-1].hres;
-    par->vyres = vmode_attrs[vmode-1].vres;
-    par->xoffset = 0;
-    par->yoffset = 0;
-    par->accel = FB_ACCELF_TEXT;
-}
+struct fb_var_screeninfo default_var_1280x1024 __initdata = {
+    /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
+    1280, 1024, 1280, 1024, 0, 0, 8, 0,
+    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0, 7408, 248, 16, 38, 1, 144, 3,
+    FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+#endif
 
 
     /*
@@ -1670,16 +1923,16 @@ static void init_par(struct atyfb_par *par, int vmode, int cmode)
      */
 
 static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-                        struct fb_info *info)
+                        struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    const struct fb_info_aty *info = (struct fb_info_aty *)fb;
     struct atyfb_par par;
 
     if (con == -1)
-       par = info2->default_par;
+       par = info->default_par;
     else
-       decode_var(&fb_display[con].var, &par, info2);
-    encode_fix(fix, &par, info2);
+       atyfb_decode_var(&fb_display[con].var, &par, info);
+    encode_fix(fix, &par, info);
     return 0;
 }
 
@@ -1689,12 +1942,12 @@ static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
      */
 
 static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
-                        struct fb_info *info)
+                        struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    const struct fb_info_aty *info = (struct fb_info_aty *)fb;
 
     if (con == -1)
-       encode_var(var, &info2->default_par, (struct fb_info_aty *)info);
+       atyfb_encode_var(var, &info->default_par, info);
     else
        *var = fb_display[con].var;
     return 0;
@@ -1706,9 +1959,9 @@ static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
      */
 
 static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
-                        struct fb_info *info)
+                        struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
     struct atyfb_par par;
     struct display *display;
     int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err;
@@ -1717,12 +1970,12 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
     if (con >= 0)
        display = &fb_display[con];
     else
-       display = &fb_disp;     /* used during initialization */
+       display = fb->disp;     /* used during initialization */
 
-    if ((err = decode_var(var, &par, info2)))
+    if ((err = atyfb_decode_var(var, &par, info)))
        return err;
 
-    encode_var(var, &par, (struct fb_info_aty *)info);
+    atyfb_encode_var(var, &par, (struct fb_info_aty *)info);
 
     if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
        oldxres = display->var.xres;
@@ -1737,8 +1990,8 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
            oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) {
            struct fb_fix_screeninfo fix;
 
-           encode_fix(&fix, &par, info2);
-           display->screen_base = (char *)info2->frame_buffer;
+           encode_fix(&fix, &par, info);
+           display->screen_base = (char *)info->frame_buffer;
            display->visual = fix.visual;
            display->type = fix.type;
            display->type_aux = fix.type_aux;
@@ -1748,20 +2001,25 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
            display->can_soft_blank = 1;
            display->inverse = 0;
            accel = var->accel_flags & FB_ACCELF_TEXT;
-           switch (par.hw.gx.cmode) {
+           switch (par.crtc.bpp) {
 #ifdef FBCON_HAS_CFB8
-               case CMODE_8:
-                   display->dispsw = accel ? &fbcon_aty8 : &fbcon_cfb8;
+               case 8:
+                   *display->dispsw = accel ? fbcon_aty8 : fbcon_cfb8;
                    break;
 #endif
 #ifdef FBCON_HAS_CFB16
-               case CMODE_16:
-                   display->dispsw = accel ? &fbcon_aty16 : &fbcon_cfb16;
+               case 16:
+                   *display->dispsw = accel ? fbcon_aty16 : fbcon_cfb16;
+                   break;
+#endif
+#ifdef FBCON_HAS_CFB24
+               case 24:
+                   *display->dispsw = accel ? fbcon_aty24 : fbcon_cfb24;
                    break;
 #endif
 #ifdef FBCON_HAS_CFB32
-               case CMODE_32:
-                   display->dispsw = accel ? &fbcon_aty32 : &fbcon_cfb32;
+               case 32:
+                   *display->dispsw = accel ? fbcon_aty32 : fbcon_cfb32;
                    break;
 #endif
                default:
@@ -1769,19 +2027,19 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
                    break;
            }
            display->scrollmode = accel ? 0 : SCROLL_YREDRAW;
-           if (info->changevar)
-               (*info->changevar)(con);
-           if (info2->cursor) {
-               display->dispsw->cursor = atyfb_cursor;
-               display->dispsw->set_font = atyfb_set_font;
+           if (info->fb_info.changevar)
+               (*info->fb_info.changevar)(con);
+           if (info->cursor) {
+               display->dispsw->cursor = atyfb_cursor;
+               display->dispsw->set_font = atyfb_set_font;
            }
        }
        if (con == currcon)
-           atyfb_set_par(&par, info2);
+           atyfb_set_par(&par, info);
        if (oldbpp != var->bits_per_pixel) {
            if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
                return err;
-           do_install_cmap(con, info);
+           do_install_cmap(con, &info->fb_info);
        }
     }
 
@@ -1796,21 +2054,21 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
      */
 
 static int atyfb_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info)
+                            struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
     u32 xres, yres, xoffset, yoffset;
-    struct atyfb_par *par = &info2->current_par;
+    struct atyfb_par *par = &info->current_par;
 
-    xres = vmode_attrs[par->hw.gx.vmode-1].hres;
-    yres = vmode_attrs[par->hw.gx.vmode-1].vres;
+    xres = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8;
+    yres = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1;
     xoffset = (var->xoffset+7) & ~7;
     yoffset = var->yoffset;
-    if (xoffset+xres > par->vxres || yoffset+yres > par->vyres)
+    if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres)
        return -EINVAL;
-    par->xoffset = xoffset;
-    par->yoffset = yoffset;
-    set_off_pitch(par, info2);
+    par->crtc.xoffset = xoffset;
+    par->crtc.yoffset = yoffset;
+    set_off_pitch(par, info);
     return 0;
 }
 
@@ -1965,6 +2223,18 @@ static int atyfb_mmap(struct fb_info *info, struct file *file,
        vma->vm_file = file;
        file->f_count++;
        vma->vm_flags |= VM_IO;
+
+       if (!fb->mmaped) {
+               int lastconsole = 0;
+
+               if (info->display_fg)
+                       lastconsole = info->display_fg->vc_num;
+               fb->mmaped = 1;
+               if (fb->consolecnt && fb_display[lastconsole].fb_info == info) {
+                       fb->vtconsole = lastconsole;
+                       vt_cons[lastconsole]->vc_mode = KD_GRAPHICS;
+               }
+       }
        return 0;
 }
 #endif /* __sparc__ */
@@ -1977,179 +2247,206 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name))
 {
     u32 chip_id;
     u32 i;
-    int j, k, sense;
+    int j, k;
     struct fb_var_screeninfo var;
-    struct aty_regvals *init;
+    struct display *disp;
     const char *chipname = NULL;
-    u8 rev;
+    int pll, mclk;
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+    int sense;
+#endif
 
     info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0);
     chip_id = aty_ld_le32(CONFIG_CHIP_ID, info);
+    Gx = chip_id & CFG_CHIP_TYPE;
+    Rev = (chip_id & CFG_CHIP_REV)>>24;
     for (j = 0; j < (sizeof(aty_features)/sizeof(*aty_features)); j++)
-       if (aty_features[j].chip_type == (chip_id & CFG_CHIP_TYPE)) {
+       if (aty_features[j].chip_type == Gx) {
            chipname = aty_features[j].name;
-           info->chip_class = aty_features[j].chip_class;
-           info->pixclock_lim_8 = 1000000/aty_features[j].pixclock_lim_8;
-           info->pixclock_lim_hi = 1000000/aty_features[j].pixclock_lim_hi;
+           break;
        }
     if (!chipname) {
-       printk("atyfb: Unknown Mach64 0x%04x\n", chip_id & CFG_CHIP_TYPE);
+       printk("atyfb: Unknown mach64 0x%04x\n", Gx);
        return 0;
     } else
-       printk("atyfb: %s [", chipname);
-    rev = (chip_id & CFG_CHIP_REV)>>24;
-    switch ((rev>>3) & 7) {
-       case MACH64_FND_SGS:
-           printk("SGS");
-           break;
-       case MACH64_FND_NEC:
-           printk("NEC");
-           break;
-       case MACH64_FND_UMC:
-           printk("UMC");
-           break;
+       printk("atyfb: %s [0x%04x rev 0x%2x] ", chipname, Gx, Rev);
+    if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
+       info->bus_type = (aty_ld_le32(CONFIG_STAT0, info) >> 0) & 0x07;
+       info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) >> 3) & 0x07;
+       /* FIXME: clockchip/RAMDAC probing? */
+#ifdef CONFIG_ATARI
+       info->dac_type = DAC_ATI68860_B;
+       info->clk_type = CLK_ATI18818_1;
+#else
+       info->dac_type = DAC_IBMRGB514;
+       info->clk_type = CLK_IBMRGB514;
+#endif
+       /* FIXME */
+       pll = 135;
+       mclk = 50;
+    } else {
+       info->bus_type = PCI;
+       info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07);
+       info->dac_type = DAC_INTERNAL;
+       info->clk_type = CLK_INTERNAL;
+       if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
+           pll = 135;
+           mclk = 60;
+       } else {
+           mclk = info->ram_type >= SDRAM ? 67 : 63;
+           if ((Gx == VT_CHIP_ID) && (Rev == 0x08)) {
+               /* VTA3 */
+               pll = 170;
+           } else if (((Gx == VT_CHIP_ID) && ((Rev == 0x40) ||
+                                              (Rev == 0x48))) ||
+                      ((Gx == VT_CHIP_ID) && ((Rev == 0x01) ||
+                                              (Rev == 0x9a))) ||
+                      (Gx == VU_CHIP_ID)) {
+               /* VTA4 or VTB */
+               pll = 200;
+           } else if (Gx == VT_CHIP_ID) {
+               /* other VT */
+               pll = 135;
+               mclk = 63;
+           } else if ((Gx == GT_CHIP_ID) && (Rev & 0x01)) {
+               /* RAGE II */
+               pll = 170;
+           } else if (((Gx == GT_CHIP_ID) && (Rev & 0x02)) ||
+                      (Gx == GU_CHIP_ID)) {
+               /* RAGE II+ */
+               pll = 200;
+           } else if ((Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
+                      (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) ||
+                      (Gx == GQ_CHIP_ID)) {
+               /* RAGE PRO */
+               pll = 230;
+           } else {
+               /* other RAGE */
+               pll = 135;
+               mclk = 63;
+           }
+       }
     }
-    printk(" %c%d]\n", 'A'+(rev & 7), rev>>6);
+    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 */
+    printk("%d MHz PLL, %d Mhz MCLK\n", pll, mclk);
+    info->pll_per = 1000000/pll;
+    info->mclk_per = 1000000/mclk;
 
     i = aty_ld_le32(MEM_CNTL, info);
-    if (info->chip_class != CLASS_GT)
-       switch (i & MEM_SIZE_ALIAS) {
+    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))
+       switch (i & 0xF) {      /* 0xF used instead of MEM_SIZE_ALIAS */
            case MEM_SIZE_512K:
                info->total_vram = 0x80000;
                break;
            case MEM_SIZE_1M:
                info->total_vram = 0x100000;
                break;
-           case MEM_SIZE_2M:
+           case MEM_SIZE_2M_GTB:
                info->total_vram = 0x200000;
                break;
-           case MEM_SIZE_4M:
+           case MEM_SIZE_4M_GTB:
                info->total_vram = 0x400000;
                break;
-           case MEM_SIZE_6M:
+           case MEM_SIZE_6M_GTB:
                info->total_vram = 0x600000;
                break;
-           case MEM_SIZE_8M:
+           case MEM_SIZE_8M_GTB:
                info->total_vram = 0x800000;
                break;
            default:
                info->total_vram = 0x80000;
        }
     else
-       switch (i & 0xF) {      /* 0xF used instead of MEM_SIZE_ALIAS */
+       switch (i & MEM_SIZE_ALIAS) {
            case MEM_SIZE_512K:
                info->total_vram = 0x80000;
                break;
            case MEM_SIZE_1M:
                info->total_vram = 0x100000;
                break;
-           case MEM_SIZE_2M_GTB:
+           case MEM_SIZE_2M:
                info->total_vram = 0x200000;
                break;
-           case MEM_SIZE_4M_GTB:
+           case MEM_SIZE_4M:
                info->total_vram = 0x400000;
                break;
-           case MEM_SIZE_6M_GTB:
+           case MEM_SIZE_6M:
                info->total_vram = 0x600000;
                break;
-           case MEM_SIZE_8M_GTB:
+           case MEM_SIZE_8M:
                info->total_vram = 0x800000;
                break;
            default:
                info->total_vram = 0x80000;
        }
-#ifdef CONFIG_ATARI    /* this is definately not the wrong way to set this */
-    if ((info->total_vram == 0x400000) || (info->total_vram == 0x800000)) {
-       /* protect GUI-regs if complete Aperture is VRAM */
-       info->total_vram -= 0x00001000;
-    }
-#endif
 
-#if 0
-    printk("aty_init: regbase = %lx, frame_buffer = %lx, total_vram = %x\n",
-          info->ati_regbase, info->frame_buffer, info->total_vram);
-#endif
+    if (info->bus_type == ISA)
+       if ((info->total_vram == 0x400000) || (info->total_vram == 0x800000)) {
+           /* protect GUI-regs if complete Aperture is VRAM */
+           info->total_vram -= GUI_RESERVE;
+       }
 
-    sense = read_aty_sense(info);
-#if 0
-    printk("monitor sense = %x\n", sense);
-#endif
 #if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
     if (default_vmode == VMODE_NVRAM) {
        default_vmode = nvram_read_byte(NV_VMODE);
-       init = get_aty_struct(default_vmode, info);
-       if (default_vmode <= 0 || default_vmode > VMODE_MAX || init == 0)
+       if (default_vmode <= 0 || default_vmode > VMODE_MAX)
            default_vmode = VMODE_CHOOSE;
     }
-    if (default_vmode == VMODE_CHOOSE)
-       default_vmode = map_monitor_sense(sense);
-#else /* !CONFIG_PMAC && !CONFIG_CHRP */
-    if (default_vmode == VMODE_NVRAM)
-       default_vmode = map_monitor_sense(sense);
-#endif /* !CONFIG_PMAC && !CONFIG_CHRP */
-
-    if (!(init = get_aty_struct(default_vmode, info)))
+    if (default_vmode == VMODE_CHOOSE) {
+       sense = read_aty_sense(info);
+       default_vmode = mac_map_monitor_sense(sense);
+    }
+    if (default_vmode <= 0 || default_vmode > VMODE_MAX)
        default_vmode = VMODE_640_480_60;
-
-    /*
-     * Reduce the pixel size if we don't have enough VRAM.
-     */
-
     if (default_cmode == CMODE_NVRAM)
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
        default_cmode = nvram_read_byte(NV_CMODE);
-#else /* !CONFIG_PMAC && !CONFIG_CHRP */
-       default_cmode = CMODE_8;
-#endif /* !CONFIG_PMAC && !CONFIG_CHRP */
     if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
        default_cmode = CMODE_8;
-
-    init_par(&info->default_par, default_vmode, default_cmode);
-    while (aty_vram_reqd(&info->default_par) > info->total_vram) {
-       while (default_cmode > CMODE_8 &&
-              aty_vram_reqd(&info->default_par) > info->total_vram) {
-           --default_cmode;
-           init_par(&info->default_par, default_vmode, default_cmode);
-       }
-       /*
-        * Adjust the video mode smaller if there still is not enough VRAM
-        */
-       if (aty_vram_reqd(&info->default_par) > info->total_vram)
-           do {
-               default_vmode--;
-               init_par(&info->default_par, default_vmode, default_cmode);
-               init = get_aty_struct(default_vmode, info);
-           } while ((init == 0) &&
-                    (default_vmode > VMODE_640_480_60));
+    if (mac_vmode_to_var(default_vmode, default_cmode, &var))
+       var = default_var;
+#else /* !CONFIG_PMAC && !CONFIG_CHRP */
+    var = default_var;
+#endif /* !CONFIG_PMAC && !CONFIG_CHRP */
+    var.accel_flags |= FB_ACCELF_TEXT;
+    if (atyfb_decode_var(&var, &info->default_par, info)) {
+       printk("atyfb: can't set default video mode\n");
+       return 0;
     }
 
-    if (info->chip_class == CLASS_GT &&
-       (aty_ld_le32(CONFIG_STAT0, info) & 7) == 5
-       && init->crtc_gen_cntl[1] == 0) {
-           default_vmode = VMODE_640_480_67;
-           default_cmode = CMODE_8;
-           init_par(&info->default_par, default_vmode, default_cmode);
-    }
+    if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))
+       strcat(atyfb_name, "GX");
+    else if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID))
+       strcat(atyfb_name, "CT");
+    else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID))
+       strcat(atyfb_name, "VT");
+    else
+       strcat(atyfb_name, "GT");
+
+    disp = &info->disp;
 
-    switch (info->chip_class) {
-       case CLASS_GX:
-           strcat(atyfb_name, "GX");
-           break;
-       case CLASS_CT:
-           strcat(atyfb_name, "CT");
-           break;
-       case CLASS_VT:
-           strcat(atyfb_name, "VT");
-           break;
-       case CLASS_GT:
-           strcat(atyfb_name, "GT");
-           break;
-    }
     strcpy(info->fb_info.modename, atyfb_name);
     info->fb_info.node = -1;
     info->fb_info.fbops = &atyfb_ops;
-    info->fb_info.disp = &fb_disp;
-    info->fb_info.fontname[0] = '\0';
+    info->fb_info.disp = disp;
+    strcpy(info->fb_info.fontname, fontname);
     info->fb_info.changevar = NULL;
     info->fb_info.switch_con = &atyfbcon_switch;
     info->fb_info.updatevar = &atyfbcon_updatevar;
@@ -2162,13 +2459,16 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name))
        info->palette[j].blue = default_blu[k];
     }
 
-    if (info->chip_class == CLASS_VT || info->chip_class == CLASS_GT) {
+    if ((Gx == VT_CHIP_ID) || (Gx == GT_CHIP_ID) || (Gx == GU_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) ||
+       (Gx == VU_CHIP_ID)) {
        info->cursor = kmalloc(sizeof(struct aty_cursor), GFP_ATOMIC);
-       memset(info->cursor, 0, sizeof(*info->cursor));
+       if (info->cursor)
+           memset(info->cursor, 0, sizeof(*info->cursor));
     }
 
-    atyfb_set_par(&info->default_par, info);
-    encode_var(&var, &info->default_par, info);
+    disp->dispsw = &info->dispsw;
     atyfb_set_var(&var, -1, &info->fb_info);
 
     if (register_framebuffer(&info->fb_info) < 0)
@@ -2188,14 +2488,16 @@ __initfunc(void atyfb_init(void))
     struct pci_dev *pdev;
     struct fb_info_aty *info;
     unsigned long addr;
-    int i, j;
-    u16 tmp;
 #ifdef __sparc__
     extern int con_is_present(void);
+    u32 chip_id;
+    int i, j;
 
     /* Do not attach when we have a serial console. */
     if (!con_is_present())
-           return;
+       return;
+#else
+    u16 tmp;
 #endif
 
     for (pdev = pci_devices; pdev; pdev = pdev->next) {
@@ -2236,7 +2538,7 @@ __initfunc(void atyfb_init(void))
                /* nothing */;
            j = i + 1;
 
-            info->mmap_map = kmalloc(j * sizeof(*info->mmap_map), GFP_ATOMIC);
+           info->mmap_map = kmalloc(j * sizeof(*info->mmap_map), GFP_ATOMIC);
            if (!info->mmap_map) {
                printk("atyfb_init: can't alloc mmap_map\n");
                kfree(info);
@@ -2284,8 +2586,8 @@ __initfunc(void atyfb_init(void))
            /*
             * Fix PROMs idea of MEM_CNTL settings...
             */
-           tmp = aty_ld_le32(CONFIG_CHIP_ID, info) & CFG_CHIP_TYPE;
-           if (tmp == VT_CHIP_ID) {
+           chip_id = aty_ld_le32(CONFIG_CHIP_ID, info) & CFG_CHIP_TYPE;
+           if ((chip_id & 0xffff) == VT_CHIP_ID && !((chip_id >> 24) & 1)) {
                u32 mem = aty_ld_le32(MEM_CNTL, info);
                switch (mem & 0x0f) {
                    case 3:
@@ -2318,34 +2620,35 @@ __initfunc(void atyfb_init(void))
                int height = prom_getintdefault(node, "height", 768);
                int depth = prom_getintdefault(node, "depth", 8);
 
-               switch (depth) {
-                   case 8:
-                       default_cmode = CMODE_8;
+               switch (width) {
+                   case 1024:
+                       if (height == 768)
+                           default_var = default_var_1024x768;
                        break;
-                   case 16:
-                       default_cmode = CMODE_16;
+                   case 1152:
+                       if (height == 900)
+                           default_var = default_var_1152x900;
                        break;
-                   case 32:
-                       default_cmode = CMODE_32;
+                   case 1280:
+                       if (height == 1024)
+                           default_var = default_var_1280x1024;
                        break;
                    default:
                        break;
                }
 
-               switch (width) {
-                   case 1024:
-                       if (height == 768)
-                           default_vmode = VMODE_1024_768_75;
+               switch (depth) {
+                   case 8:
+                       default_var.bits_per_pixel = 8;
                        break;
-                   case 1152:
-                       if (height == 870)
-                           default_vmode = VMODE_1152_870_75;
+                   case 16:
+                       default_var.bits_per_pixel = 16;
                        break;
-                   case 1280:
-                       if (height == 960)
-                           default_vmode = VMODE_1280_960_75;
-                       else if (height == 1024)
-                           default_vmode = VMODE_1280_1024_75;
+                   case 24:
+                       default_var.bits_per_pixel = 24;
+                       break;
+                   case 32:
+                       default_var.bits_per_pixel = 32;
                        break;
                    default:
                        break;
@@ -2354,9 +2657,6 @@ __initfunc(void atyfb_init(void))
 
 #else /* __sparc__ */
 
-           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, 0x1000);
@@ -2388,7 +2688,7 @@ __initfunc(void atyfb_init(void))
            if (!aty_init(info, "PCI")) {
                if (info->mmap_map)
                    kfree(info->mmap_map);
-               kfree(info);
+               kfree(info);
            }
        }
     }
@@ -2500,39 +2800,51 @@ __initfunc(void atyfb_of_init(struct device_node *dp))
 __initfunc(void atyfb_setup(char *options, int *ints))
 {
     char *this_opt;
-    int vmode;
-    int depth;
+
     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 defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
        if (!strncmp(this_opt, "vmode:", 6)) {
-           vmode = simple_strtoul(this_opt+6, NULL, 0);
+           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)) {
-           depth = simple_strtoul(this_opt+6, NULL, 0);
+           int depth = simple_strtoul(this_opt+6, NULL, 0);
            switch (depth) {
                case 8:
-                   default_cmode = CMODE_8;
+                   default_cmode = 0;
                    break;
                case 15:
                case 16:
-                   default_cmode = CMODE_16;
+                   default_cmode = 1;
                    break;
                case 24:
                case 32:
-                   default_cmode = CMODE_32;
+                   default_cmode = 2;
                    break;
            }
        }
+#endif
 #ifdef CONFIG_ATARI
        /*
         * Why do we need this silly Mach64 argument?
         * We are already here because of mach64= so its redundant.
         */
-       else if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) {
+       if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) {
            static unsigned char m64_num;
            static char mach64_str[80];
            strncpy(mach64_str, this_opt+7, 80);
@@ -2595,39 +2907,48 @@ __initfunc(static char *strtoke(char *s, const char *ct))
 }
 #endif /* CONFIG_ATARI */
 
-static int atyfbcon_switch(int con, struct fb_info *info)
+static int atyfbcon_switch(int con, struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
     struct atyfb_par par;
 
     /* Do we have to save the colormap? */
     if (fb_display[currcon].cmap.len)
        fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1,
-                   atyfb_getcolreg, info);
+                   atyfb_getcolreg, fb);
+
+    /* Erase HW Cursor */
+    if (info->cursor)
+       atyfb_cursor(&fb_display[currcon], CM_ERASE,
+                    info->cursor->pos.x, info->cursor->pos.y);
+
     currcon = con;
-    decode_var(&fb_display[con].var, &par, info2);
-    atyfb_set_par(&par, info2);
+
+    atyfb_decode_var(&fb_display[con].var, &par, info);
+    atyfb_set_par(&par, info);
+
     /* Install new colormap */
-    do_install_cmap(con, info);
+    do_install_cmap(con, fb);
+
     /* Install hw cursor */
-    if (info2->cursor) {
-       aty_set_cursor_color(info2, cursor_pixel_map, cursor_color_map,
+    if (info->cursor) {
+       aty_set_cursor_color(info, cursor_pixel_map, cursor_color_map,
                             cursor_color_map, cursor_color_map);
-       aty_set_cursor_shape(info2);
+       aty_set_cursor_shape(info);
     }
-    return 0;
+    return 1;
 }
 
     /*
      *  Update the `var' structure (called by fbcon.c)
      */
 
-static int atyfbcon_updatevar(int con, struct fb_info *info)
+static int atyfbcon_updatevar(int con, struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
 
-    info2->current_par.yoffset = fb_display[con].var.yoffset;
-    set_off_pitch(&info2->current_par, info2);
+    info->current_par.crtc.yoffset = fb_display[con].var.yoffset;
+    set_off_pitch(&info->current_par, info);
     return 0;
 }
 
@@ -2635,12 +2956,12 @@ static int atyfbcon_updatevar(int con, struct fb_info *info)
      *  Blank the display.
      */
 
-static void atyfbcon_blank(int blank, struct fb_info *info)
+static void atyfbcon_blank(int blank, struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
     u8 gen_cntl;
 
-    gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info2);
+    gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info);
     if (blank > 0)
        switch (blank-1) {
            case VESA_NO_BLANKING:
@@ -2658,7 +2979,7 @@ static void atyfbcon_blank(int blank, struct fb_info *info)
        }
     else
        gen_cntl &= ~(0x4c);
-    aty_st_8(CRTC_GEN_CNTL, gen_cntl, info2);
+    aty_st_8(CRTC_GEN_CNTL, gen_cntl, info);
 }
 
 
@@ -2668,15 +2989,15 @@ static void atyfbcon_blank(int blank, struct fb_info *info)
      */
 
 static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                          u_int *transp, struct fb_info *info)
+                          u_int *transp, struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
 
     if (regno > 255)
        return 1;
-    *red = info2->palette[regno].red;
-    *green = info2->palette[regno].green;
-    *blue = info2->palette[regno].blue;
+    *red = info->palette[regno].red;
+    *green = info->palette[regno].green;
+    *blue = info->palette[regno].blue;
     return 0;
 }
 
@@ -2688,36 +3009,41 @@ static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
      */
 
 static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                          u_int transp, struct fb_info *info)
+                          u_int transp, struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
     int i, scale;
 
     if (regno > 255)
        return 1;
-    info2->palette[regno].red = red;
-    info2->palette[regno].green = green;
-    info2->palette[regno].blue = blue;
-    i = aty_ld_8(DAC_CNTL, info2) & 0xfc;
-    if (info2->chip_class == CLASS_GT)
+    info->palette[regno].red = red;
+    info->palette[regno].green = green;
+    info->palette[regno].blue = blue;
+    i = aty_ld_8(DAC_CNTL, info) & 0xfc;
+    if ((Gx == GT_CHIP_ID) || (Gx == GU_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))
        i |= 0x2;       /*DAC_CNTL|0x2 turns off the extra brightness for gt*/
-    aty_st_8(DAC_CNTL, i, info2);
-    aty_st_8(DAC_REGS + DAC_MASK, 0xff, info2);
+    aty_st_8(DAC_CNTL, i, info);
+    aty_st_8(DAC_REGS + DAC_MASK, 0xff, info);
     eieio();
-    scale = ((info2->chip_class != CLASS_GX) &&
-            (info2->current_par.hw.gx.cmode == CMODE_16)) ? 3 : 0;
-    info2->aty_cmap_regs->windex = regno << scale;
+    scale = ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID) &&
+            (info->current_par.crtc.bpp == 16)) ? 3 : 0;
+    info->aty_cmap_regs->windex = regno << scale;
     eieio();
-    info2->aty_cmap_regs->lut = red << scale;
+    info->aty_cmap_regs->lut = red << scale;
     eieio();
-    info2->aty_cmap_regs->lut = green << scale;
+    info->aty_cmap_regs->lut = green << scale;
     eieio();
-    info2->aty_cmap_regs->lut = blue << scale;
+    info->aty_cmap_regs->lut = blue << scale;
     eieio();
     if (regno < 16) {
 #ifdef FBCON_HAS_CFB16
        fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno;
 #endif
+#ifdef FBCON_HAS_CFB24
+       fbcon_cfb24_cmap[regno] = (regno << 16) | (regno << 8) | regno;
+#endif
 #ifdef FBCON_HAS_CFB32
        fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) |
                                  (regno << 8) | regno;
@@ -2765,14 +3091,15 @@ static inline void aty_rectcopy(int srcx, int srcy, int dstx, int dsty,
     if (!width || !height)
        return;
 
-    pitch_value = info->current_par.vxres;
-#if 0
-    if (par->hw.gx.cmode == CMODE_24) {
+    pitch_value = info->current_par.crtc.vxres;
+    if (info->current_par.crtc.bpp == 24) {
        /* In 24 bpp, the engine is in 8 bpp - this requires that all */
        /* horizontal coordinates and widths must be adjusted */
-       pitch_value = pitch_value * 3;
+       pitch_value *= 3;
+       srcx *= 3;
+       dstx *= 3;
+       width *= 3;
     }
-#endif
 
     if (srcy < dsty) {
        dsty += height - 1;
@@ -2806,6 +3133,13 @@ static inline void aty_rectfill(int dstx, int dsty, u_int width, u_int height,
     if (!width || !height)
        return;
 
+    if (info->current_par.crtc.bpp == 24) {
+       /* In 24 bpp, the engine is in 8 bpp - this requires that all */
+       /* horizontal coordinates and widths must be adjusted */
+       dstx *= 3;
+       width *= 3;
+    }
+
     wait_for_fifo(3, info);
     aty_st_le32(DP_FRGD_CLR, color, info);
     aty_st_le32(DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE,
@@ -2823,6 +3157,13 @@ static inline void aty_rectfill(int dstx, int dsty, u_int width, u_int height,
 static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx,
                            int height, int width)
 {
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+       return;
+#endif
+
     sx *= p->fontwidth;
     sy *= p->fontheight;
     dx *= p->fontwidth;
@@ -2837,7 +3178,15 @@ static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx,
 static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy,
                            int sx, int height, int width)
 {
-    u32 bgx = attr_bgcol_ec(p, conp);
+    u32 bgx;
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+       return;
+#endif
+
+    bgx = attr_bgcol_ec(p, conp);
     bgx |= (bgx << 8);
     bgx |= (bgx << 16);
 
@@ -2854,13 +3203,28 @@ static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy,
 static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c,
                            int yy, int xx)
 {
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+       return;
+#endif
+
     wait_for_idle((struct fb_info_aty *)p->fb_info);
     fbcon_cfb8_putc(conp, p, c, yy, xx);
 }
 
 static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
-                            const unsigned short *s, int count, int yy, int xx)
+                            const unsigned short *s, int count, int yy,
+                            int xx)
 {
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+       return;
+#endif
+
     wait_for_idle((struct fb_info_aty *)p->fb_info);
     fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
 }
@@ -2868,7 +3232,7 @@ static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
 static struct display_switch fbcon_aty8 = {
     fbcon_cfb8_setup, fbcon_aty_bmove, fbcon_aty_clear, fbcon_aty8_putc,
     fbcon_aty8_putcs, fbcon_cfb8_revc, NULL, NULL, fbcon_cfb8_clear_margins,
-    FONTWIDTH(8)
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 
@@ -2876,20 +3240,73 @@ static struct display_switch fbcon_aty8 = {
 static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, int c,
                             int yy, int xx)
 {
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+       return;
+#endif
+
     wait_for_idle((struct fb_info_aty *)p->fb_info);
     fbcon_cfb16_putc(conp, p, c, yy, xx);
 }
 
 static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p,
-                             const unsigned short *s, int count, int yy, int xx)
+                             const unsigned short *s, int count, int yy,
+                             int xx)
 {
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+       return;
+#endif
+
     wait_for_idle((struct fb_info_aty *)p->fb_info);
     fbcon_cfb16_putcs(conp, p, s, count, yy, xx);
 }
 
 static struct display_switch fbcon_aty16 = {
     fbcon_cfb16_setup, fbcon_aty_bmove, fbcon_aty_clear, fbcon_aty16_putc,
-    fbcon_aty16_putcs, fbcon_cfb16_revc, NULL, NULL, NULL, FONTWIDTH(8)
+    fbcon_aty16_putcs, fbcon_cfb16_revc, NULL, NULL, fbcon_cfb16_clear_margins,
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+#ifdef FBCON_HAS_CFB24
+static void fbcon_aty24_putc(struct vc_data *conp, struct display *p, int c,
+                            int yy, int xx)
+{
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+       return;
+#endif
+
+    wait_for_idle((struct fb_info_aty *)p->fb_info);
+    fbcon_cfb24_putc(conp, p, c, yy, xx);
+}
+
+static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p,
+                             const unsigned short *s, int count, int yy,
+                             int xx)
+{
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+       return;
+#endif
+
+    wait_for_idle((struct fb_info_aty *)p->fb_info);
+    fbcon_cfb24_putcs(conp, p, s, count, yy, xx);
+}
+
+static struct display_switch fbcon_aty24 = {
+    fbcon_cfb24_setup, fbcon_cfb24_bmove, fbcon_cfb24_clear, fbcon_aty24_putc,
+    fbcon_aty24_putcs, fbcon_cfb24_revc, NULL, NULL, fbcon_cfb24_clear_margins,
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 
@@ -2897,19 +3314,35 @@ static struct display_switch fbcon_aty16 = {
 static void fbcon_aty32_putc(struct vc_data *conp, struct display *p, int c,
                             int yy, int xx)
 {
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+       return;
+#endif
+
     wait_for_idle((struct fb_info_aty *)p->fb_info);
     fbcon_cfb32_putc(conp, p, c, yy, xx);
 }
 
 static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p,
-                             const unsigned short *s, int count, int yy, int xx)
+                             const unsigned short *s, int count, int yy,
+                             int xx)
 {
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+       return;
+#endif
+
     wait_for_idle((struct fb_info_aty *)p->fb_info);
     fbcon_cfb32_putcs(conp, p, s, count, yy, xx);
 }
 
 static struct display_switch fbcon_aty32 = {
     fbcon_cfb32_setup, fbcon_aty_bmove, fbcon_aty_clear, fbcon_aty32_putc,
-    fbcon_aty32_putcs, fbcon_cfb32_revc, NULL, NULL, NULL, FONTWIDTH(8)
+    fbcon_aty32_putcs, fbcon_cfb32_revc, NULL, NULL, fbcon_cfb32_clear_margins,
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
diff --git a/drivers/video/bwtwofb.c b/drivers/video/bwtwofb.c
new file mode 100644 (file)
index 0000000..a907fc2
--- /dev/null
@@ -0,0 +1,222 @@
+/* $Id: bwtwofb.c,v 1.1 1998/07/21 14:50:48 jj Exp $
+ * bwtwofb.c: BWtwo frame buffer driver
+ *
+ * Copyright (C) 1998 Jakub Jelinek   (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Eddie C. Dost   (ecd@skynet.be)
+ * Copyright (C) 1998 Pavel Machek    (pavel@ucw.cz)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/sched.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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/selection.h>
+
+#include "sbusfb.h"
+#include <asm/io.h>
+#ifndef __sparc_v9__
+#include <asm/sun4paddr.h>
+#endif
+
+#include "fbcon-mfb.h"
+
+/* OBio addresses for the bwtwo registers */
+#define BWTWO_REGISTER_OFFSET 0x400000
+
+struct bw2_regs {
+       struct bt_regs          bt;
+       volatile u8             control;
+       volatile u8             status;
+       volatile u8             cursor_start;
+       volatile u8             cursor_end;
+       volatile u8             h_blank_start;
+       volatile u8             h_blank_end;
+       volatile u8             h_sync_start;
+       volatile u8             h_sync_end;
+       volatile u8             comp_sync_end;
+       volatile u8             v_blank_start_high;
+       volatile u8             v_blank_start_low;
+       volatile u8             v_blank_end;
+       volatile u8             v_sync_start;
+       volatile u8             v_sync_end;
+       volatile u8             xfer_holdoff_start;
+       volatile u8             xfer_holdoff_end;
+};
+
+/* Status Register Constants */
+#define BWTWO_SR_RES_MASK      0x70
+#define BWTWO_SR_1600_1280     0x50
+#define BWTWO_SR_1152_900_76_A 0x40
+#define BWTWO_SR_1152_900_76_B 0x60
+#define BWTWO_SR_ID_MASK       0x0f
+#define BWTWO_SR_ID_MONO       0x02
+#define BWTWO_SR_ID_MONO_ECL   0x03
+#define BWTWO_SR_ID_MSYNC      0x04
+
+/* Control Register Constants */
+#define BWTWO_CTL_ENABLE_INTS   0x80
+#define BWTWO_CTL_ENABLE_VIDEO  0x40
+#define BWTWO_CTL_ENABLE_TIMING 0x20
+#define BWTWO_CTL_ENABLE_CURCMP 0x10
+#define BWTWO_CTL_XTAL_MASK     0x0C
+#define BWTWO_CTL_DIVISOR_MASK  0x03
+
+/* Status Register Constants */
+#define BWTWO_STAT_PENDING_INT  0x80
+#define BWTWO_STAT_MSENSE_MASK  0x70
+#define BWTWO_STAT_ID_MASK      0x0f
+
+static struct sbus_mmap_map bw2_mmap_map[] = {
+       { 0,                    0,                      SBUS_MMAP_FBSIZE(1) },
+       { 0,                    0,                      0                   }
+};
+
+static void bw2_blank (struct fb_info_sbusfb *fb)
+{
+       fb->s.bw2.regs->control &= ~BWTWO_CTL_ENABLE_VIDEO;
+}
+
+static void bw2_unblank (struct fb_info_sbusfb *fb)
+{
+       fb->s.bw2.regs->control |= BWTWO_CTL_ENABLE_VIDEO;
+}
+
+static void bw2_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
+{
+       p->screen_base += ((y_margin - fb->y_margin) * p->line_length + (x_margin - fb->x_margin)) >> 3;
+}
+
+static u8 bw2regs_1600[] __initdata = {
+       0x14, 0x8b,     0x15, 0x28,     0x16, 0x03,     0x17, 0x13,
+       0x18, 0x7b,     0x19, 0x05,     0x1a, 0x34,     0x1b, 0x2e,
+       0x1c, 0x00,     0x1d, 0x0a,     0x1e, 0xff,     0x1f, 0x01,
+       0x10, 0x21,     0
+};
+
+static u8 bw2regs_ecl[] __initdata = {
+       0x14, 0x65,     0x15, 0x1e,     0x16, 0x04,     0x17, 0x0c,
+       0x18, 0x5e,     0x19, 0x03,     0x1a, 0xa7,     0x1b, 0x23,
+       0x1c, 0x00,     0x1d, 0x08,     0x1e, 0xff,     0x1f, 0x01,
+       0x10, 0x20,     0
+};
+
+static u8 bw2regs_analog[] __initdata = {
+       0x14, 0xbb,     0x15, 0x2b,     0x16, 0x03,     0x17, 0x13,
+       0x18, 0xb0,     0x19, 0x03,     0x1a, 0xa6,     0x1b, 0x22,
+       0x1c, 0x01,     0x1d, 0x05,     0x1e, 0xff,     0x1f, 0x01,
+       0x10, 0x20,     0
+};
+
+static u8 bw2regs_76hz[] __initdata = {
+       0x14, 0xb7,     0x15, 0x27,     0x16, 0x03,     0x17, 0x0f,
+       0x18, 0xae,     0x19, 0x03,     0x1a, 0xae,     0x1b, 0x2a,
+       0x1c, 0x01,     0x1d, 0x09,     0x1e, 0xff,     0x1f, 0x01,
+       0x10, 0x24,     0
+};
+
+static u8 bw2regs_66hz[] __initdata = {
+       0x14, 0xbb,     0x15, 0x2b,     0x16, 0x04,     0x17, 0x14,
+       0x18, 0xae,     0x19, 0x03,     0x1a, 0xa8,     0x1b, 0x24,
+       0x1c, 0x01,     0x1d, 0x05,     0x1e, 0xff,     0x1f, 0x01,
+       0x10, 0x20,     0
+};
+
+static char idstring[60] __initdata = { 0 };
+
+__initfunc(char *bwtwofb_init(struct fb_info_sbusfb *fb))
+{
+       struct fb_fix_screeninfo *fix = &fb->fix;
+       struct display *disp = &fb->disp;
+       struct fbtype *type = &fb->type;
+#ifdef CONFIG_SUN4
+       unsigned long phys = SUN4_300_BWTWO_PHYSADDR;
+#else
+       unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr;
+#endif
+
+#ifndef FBCON_HAS_MFB
+       return NULL;
+#endif
+
+       if (!fb->s.bw2.regs) {
+               fb->s.bw2.regs = (struct bw2_regs *)sparc_alloc_io(phys+BWTWO_REGISTER_OFFSET, 0, 
+                               sizeof(struct bw2_regs), "bw2_regs", fb->iospace, 0);
+               if (!prom_getbool(fb->prom_node, "width")) {
+                       /* Ugh, broken PROM didn't initialize us.
+                        * Let's deal with this ourselves.
+                        */
+                       u8 status, mon;
+                       u8 *p;
+                       int sizechange = 0;
+
+                       status = fb->s.bw2.regs->status;
+                       mon = status & BWTWO_SR_RES_MASK;
+                       switch (status & BWTWO_SR_ID_MASK) {
+                               case BWTWO_SR_ID_MONO_ECL:
+                                       if (mon == BWTWO_SR_1600_1280) {
+                                               p = bw2regs_1600;
+                                               fb->type.fb_width = 1600;
+                                               fb->type.fb_height = 1280;
+                                               sizechange = 1;
+                                       } else
+                                               p = bw2regs_ecl;
+                                       break;
+                               case BWTWO_SR_ID_MONO:
+                                       p = bw2regs_analog;
+                                       break;
+                               case BWTWO_SR_ID_MSYNC:
+                                       if (mon == BWTWO_SR_1152_900_76_A ||
+                                           mon == BWTWO_SR_1152_900_76_B)
+                                               p = bw2regs_76hz;
+                                       else
+                                               p = bw2regs_66hz;
+                                       break;
+                               default:
+                                       prom_printf("bw2: can't handle SR %02x\n",
+                                                   status);
+                                       prom_halt();
+                                       return NULL; /* fool gcc. */
+                       }
+                       for ( ; *p; p += 2)
+                               ((u8 *)fb->s.bw2.regs)[p[0]] = p[1];
+               }
+       }
+
+       strcpy(fb->info.modename, "BWtwo");
+       strcpy(fix->id, "BWtwo");
+       fix->line_length = fb->var.xres_virtual>>3;
+       
+       disp->scrollmode = SCROLL_YREDRAW;
+       if (!disp->screen_base)
+               disp->screen_base = (char *)sparc_alloc_io(phys, 0, 
+                       type->fb_size, "bw2_ram", fb->iospace, 0);
+       disp->screen_base += (fix->line_length * fb->y_margin + fb->x_margin) >> 3;
+       fb->dispsw = fbcon_mfb;
+       fix->visual = FB_VISUAL_MONO01;
+
+       fb->blank = bw2_blank;
+       fb->unblank = bw2_unblank;
+       fb->margins = bw2_margins;
+       
+       fb->physbase = phys;
+       fb->mmap_map = bw2_mmap_map;
+
+#ifdef __sparc_v9__
+       sprintf(idstring, "bwtwo at %016lx", phys);
+#else  
+       sprintf(idstring, "bwtwo at %x.%08lx", fb->iospace, phys);
+#endif
+       
+       return idstring;
+}
index f1e7ece86ddd979bbe00dcf8d189add36364768a..0ef9e4dcb16c0170fc72403a7c2c4c71911e34ad 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: cgsixfb.c,v 1.4 1998/07/21 10:36:53 jj Exp $
+/* $Id: cgsixfb.c,v 1.7 1998/07/22 12:44:59 jj Exp $
  * cgsixfb.c: CGsix (GX,GXplus) frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
@@ -237,8 +237,8 @@ static void cg6_clear(struct vc_data *conp, struct display *p, int sy, int sx,
        do {
                i = fbc->s;
        } while (i & 0x10000000);
-       fbc->fg = attr_bg_col_ec(conp);
-       fbc->bg = attr_bg_col_ec(conp);
+       fbc->fg = attr_bgcol_ec(p,conp);
+       fbc->bg = attr_bgcol_ec(p,conp);
        fbc->pixelm = ~(0);
        fbc->alu = 0xea80ff00;
        fbc->s = 0;
@@ -264,7 +264,7 @@ static void cg6_clear(struct vc_data *conp, struct display *p, int sy, int sx,
        } while (i < 0 && (i & 0x20000000));
 }
 
-static void cg6_fill(struct fb_info_sbusfb *fb, int s,
+static void cg6_fill(struct fb_info_sbusfb *fb, struct display *p, int s,
                     int count, unsigned short *boxes)
 {
        int i;
@@ -273,8 +273,8 @@ static void cg6_fill(struct fb_info_sbusfb *fb, int s,
        do {
                i = fbc->s;
        } while (i & 0x10000000);
-       fbc->fg = attr_bg_col(s);
-       fbc->bg = attr_bg_col(s);
+       fbc->fg = attr_bgcol(p,s);
+       fbc->bg = attr_bgcol(p,s);
        fbc->pixelm = ~(0);
        fbc->alu = 0xea80ff00;
        fbc->s = 0;
@@ -301,11 +301,15 @@ static void cg6_putc(struct vc_data *conp, struct display *p, int c, int yy, int
 
        if (p->fontheightlog) {
                y = fb->y_margin + (yy << p->fontheightlog);
-               i = ((c & 0xff) << p->fontheightlog);
+               i = ((c & p->charmask) << p->fontheightlog);
        } else {
                y = fb->y_margin + (yy * p->fontheight);
-               i = (c & 0xff) * p->fontheight;
+               i = (c & p->charmask) * p->fontheight;
        }
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+       fd = p->fontdata + i;
+       x = fb->x_margin + xx * 8;
+#else
        if (p->fontwidth <= 8)
                fd = p->fontdata + i;
        else
@@ -314,11 +318,12 @@ static void cg6_putc(struct vc_data *conp, struct display *p, int c, int yy, int
                x = fb->x_margin + (xx << p->fontwidthlog);
        else
                x = fb->x_margin + (xx * p->fontwidth);
+#endif
        do {
                i = fbc->s;
        } while (i & 0x10000000);
-       fbc->fg = attr_fg_col(c);
-       fbc->bg = attr_bg_col(c);
+       fbc->fg = attr_fgcol(p,c);
+       fbc->bg = attr_bgcol(p,c);
        fbc->mode = 0x140000;
        fbc->alu = 0xe880fc30;
        fbc->pixelm = ~(0);
@@ -330,15 +335,19 @@ static void cg6_putc(struct vc_data *conp, struct display *p, int c, int yy, int
        fbc->x0 = x;
        fbc->x1 = x + p->fontwidth - 1;
        fbc->y0 = y;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
        if (p->fontwidth <= 8) {
+#endif
                for (i = 0; i < p->fontheight; i++)
                        fbc->font = *fd++ << 24;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
        } else {
                for (i = 0; i < p->fontheight; i++) {
                        fbc->font = *(u16 *)fd << 16;
                        fd += 2;
                }
        }
+#endif
 }
 
 static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
@@ -352,8 +361,8 @@ static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned sh
        do {
                i = fbc->s;
        } while (i & 0x10000000);
-       fbc->fg = attr_fg_col(*s);
-       fbc->bg = attr_bg_col(*s);
+       fbc->fg = attr_fgcol(p,*s);
+       fbc->bg = attr_bgcol(p,*s);
        fbc->mode = 0x140000;
        fbc->alu = 0xe880fc30;
        fbc->pixelm = ~(0);
@@ -362,15 +371,21 @@ static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned sh
        fbc->pm = 0xff;
        x = fb->x_margin;
        y = fb->y_margin;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+       x += xx * 8;
+#else
        if (p->fontwidthlog)
                x += (xx << p->fontwidthlog);
        else
                x += xx * p->fontwidth;
+#endif
        if (p->fontheightlog)
                y += (yy << p->fontheightlog);
        else
                y += (yy * p->fontheight);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
        if (p->fontwidth <= 8) {
+#endif
                while (count >= 4) {
                        count -= 4;
                        fbc->incx = 0;
@@ -379,20 +394,23 @@ static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned sh
                        fbc->x1 = (x += 4 * p->fontwidth) - 1;
                        fbc->y0 = y;
                        if (p->fontheightlog) {
-                               fd1 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
-                               fd2 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
-                               fd3 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
-                               fd4 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
+                               fd1 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+                               fd2 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+                               fd3 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+                               fd4 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
                        } else {
-                               fd1 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
-                               fd2 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
-                               fd3 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
-                               fd4 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
+                               fd1 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+                               fd2 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+                               fd3 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+                               fd4 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
                        }
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
                        if (p->fontwidth == 8) {
+#endif
                                for (i = 0; i < p->fontheight; i++)
                                        fbc->font = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) 
                                                << 8)) << 8)) << 8);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
                        } else {
                                for (i = 0; i < p->fontheight; i++)
                                        fbc->font = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) 
@@ -408,17 +426,18 @@ static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned sh
                        fbc->x1 = (x += 2 * p->fontwidth) - 1;
                        fbc->y0 = y;
                        if (p->fontheightlog) {
-                               fd1 = p->fontdata + ((*s++ & 0xff) << (p->fontheightlog + 1));
-                               fd2 = p->fontdata + ((*s++ & 0xff) << (p->fontheightlog + 1));
+                               fd1 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1));
+                               fd2 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1));
                        } else {
-                               fd1 = p->fontdata + (((*s++ & 0xff) * p->fontheight) << 1);
-                               fd2 = p->fontdata + (((*s++ & 0xff) * p->fontheight) << 1);
+                               fd1 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1);
+                               fd2 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1);
                        }
                        for (i = 0; i < p->fontheight; i++) {
                                fbc->font = ((((u32)*(u16 *)fd1) << p->fontwidth) | ((u32)*(u16 *)fd2)) << (16 - p->fontwidth);
                                fd1 += 2; fd2 += 2;
                        }
                }
+#endif
        }
        while (count) {
                count--;
@@ -428,13 +447,16 @@ static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned sh
                fbc->x1 = (x += p->fontwidth) - 1;
                fbc->y0 = y;
                if (p->fontheightlog)
-                       i = ((*s++ & 0xff) << p->fontheightlog);
+                       i = ((*s++ & p->charmask) << p->fontheightlog);
                else
-                       i = ((*s++ & 0xff) * p->fontheight);
+                       i = ((*s++ & p->charmask) * p->fontheight);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
                if (p->fontwidth <= 8) {
+#endif
                        fd1 = p->fontdata + i;
                        for (i = 0; i < p->fontheight; i++)
                                fbc->font = *fd1++ << 24;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
                } else {
                        fd1 = p->fontdata + (i << 1);
                        for (i = 0; i < p->fontheight; i++) {
@@ -442,6 +464,7 @@ static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned sh
                                fd1 += 2;
                        }
                }
+#endif
        }
 }
 
@@ -466,7 +489,6 @@ static void cg6_loadcmap (struct fb_info_sbusfb *fb, int index, int count)
 static void cg6_restore_palette (struct fb_info_sbusfb *fb)
 {
        struct bt_regs *bt = fb->s.cg6.bt;
-       int i;
                 
        bt->addr = 0;
        bt->color_map = 0xffffffff;
@@ -592,10 +614,7 @@ __initfunc(char *cgsixfb_init(struct fb_info_sbusfb *fb))
        strcpy(fb->info.modename, "CGsix");
                
        strcpy(fix->id, "CGsix");
-       fix->smem_start = (char *)phys + CG6_RAM_OFFSET;
        fix->line_length = fb->var.xres_virtual;
-       fix->mmio_start = (char *)phys + CG6_FBC_OFFSET;
-       fix->mmio_len = PAGE_SIZE;
        fix->accel = FB_ACCEL_SUN_CGSIX;
        
        var->accel_flags = FB_ACCELF_TEXT;
@@ -648,7 +667,12 @@ __initfunc(char *cgsixfb_init(struct fb_info_sbusfb *fb))
        default: p = "i386"; break;
        }
                                                                                
-       sprintf(idstring, "cgsix at %02x.%08lx TEC Rev %x CPU %s Rev %x", fb->iospace, phys, 
+       sprintf(idstring, 
+#ifdef __sparc_v9__
+                   "cgsix at %016lx TEC Rev %x CPU %s Rev %x", phys, 
+#else  
+                   "cgsix at %x.%08lx TEC Rev %x CPU %s Rev %x", fb->iospace, phys, 
+#endif
                    (fb->s.cg6.thc->thc_misc >> CG6_THC_MISC_REV_SHIFT) & CG6_THC_MISC_REV_MASK,
                    p, conf >> CG6_FHC_REV_SHIFT & CG6_FHC_REV_MASK);
                    
diff --git a/drivers/video/cgthreefb.c b/drivers/video/cgthreefb.c
new file mode 100644 (file)
index 0000000..2cab0fc
--- /dev/null
@@ -0,0 +1,247 @@
+/* $Id: cgthreefb.c,v 1.1 1998/07/21 14:50:47 jj Exp $
+ * cgthreefb.c: CGthree frame buffer driver
+ *
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#include <linux/module.h>
+#include <linux/sched.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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/selection.h>
+
+#include "sbusfb.h"
+#include <asm/io.h>
+
+#include "fbcon-cfb8.h"
+
+/* Control Register Constants */
+#define CG3_CR_ENABLE_INTS      0x80
+#define CG3_CR_ENABLE_VIDEO     0x40
+#define CG3_CR_ENABLE_TIMING    0x20
+#define CG3_CR_ENABLE_CURCMP    0x10
+#define CG3_CR_XTAL_MASK        0x0c
+#define CG3_CR_DIVISOR_MASK     0x03
+
+/* Status Register Constants */
+#define CG3_SR_PENDING_INT      0x80
+#define CG3_SR_RES_MASK         0x70
+#define CG3_SR_1152_900_76_A    0x40
+#define CG3_SR_1152_900_76_B    0x60
+#define CG3_SR_ID_MASK          0x0f
+#define CG3_SR_ID_COLOR         0x01
+#define CG3_SR_ID_MONO          0x02
+#define CG3_SR_ID_MONO_ECL      0x03
+
+enum cg3_type {
+       CG3_AT_66HZ = 0,
+       CG3_AT_76HZ,
+       CG3_RDI
+};
+
+struct cg3_regs {
+       struct bt_regs  cmap;
+       volatile u8     control;
+       volatile u8     status;
+       volatile u8     cursor_start;
+       volatile u8     cursor_end;
+       volatile u8     h_blank_start;
+       volatile u8     h_blank_end;
+       volatile u8     h_sync_start;
+       volatile u8     h_sync_end;
+       volatile u8     comp_sync_end;
+       volatile u8     v_blank_start_high;
+       volatile u8     v_blank_start_low;
+       volatile u8     v_blank_end;
+       volatile u8     v_sync_start;
+       volatile u8     v_sync_end;
+       volatile u8     xfer_holdoff_start;
+       volatile u8     xfer_holdoff_end;
+};
+
+/* Offset of interesting structures in the OBIO space */
+#define CG3_REGS_OFFSET             0x400000
+#define CG3_RAM_OFFSET      0x800000
+
+static struct sbus_mmap_map cg3_mmap_map[] = {
+       { CG3_MMAP_OFFSET,      CG3_RAM_OFFSET,         SBUS_MMAP_FBSIZE(1) },
+       { 0,                    0,                      0                   }
+};
+
+/* The cg3 palette is loaded with 4 color values at each time  */
+/* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on */
+
+#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2))      /* (x/4)*3 */
+#define D4M4(x) ((x)&~0x3)                      /* (x/4)*4 */
+
+static void cg3_loadcmap (struct fb_info_sbusfb *fb, int index, int count)
+{
+       struct bt_regs *bt = &fb->s.cg3.regs->cmap;
+       u32 *i;
+       int steps;
+               
+       i = (((u32 *)fb->color_map) + D4M3(index));
+       steps = D4M3(index+count-1) - D4M3(index)+3;
+                               
+       *(volatile u8 *)&bt->addr = (u8)D4M4(index);
+       while (steps--)
+               bt->color_map = *i++;
+}
+
+static void cg3_blank (struct fb_info_sbusfb *fb)
+{
+       fb->s.cg3.regs->control &= ~CG3_CR_ENABLE_VIDEO;
+}
+
+static void cg3_unblank (struct fb_info_sbusfb *fb)
+{
+       fb->s.cg3.regs->control |= CG3_CR_ENABLE_VIDEO;
+}
+
+static void cg3_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
+{
+       p->screen_base += (y_margin - fb->y_margin) * p->line_length + (x_margin - fb->x_margin);
+}
+
+static u8 cg3regvals_66hz[] __initdata = {     /* 1152 x 900, 66 Hz */
+       0x14, 0xbb,     0x15, 0x2b,     0x16, 0x04,     0x17, 0x14,
+       0x18, 0xae,     0x19, 0x03,     0x1a, 0xa8,     0x1b, 0x24,
+       0x1c, 0x01,     0x1d, 0x05,     0x1e, 0xff,     0x1f, 0x01,
+       0x10, 0x20,     0
+};
+
+static u8 cg3regvals_76hz[] __initdata = {     /* 1152 x 900, 76 Hz */
+       0x14, 0xb7,     0x15, 0x27,     0x16, 0x03,     0x17, 0x0f,
+       0x18, 0xae,     0x19, 0x03,     0x1a, 0xae,     0x1b, 0x2a,
+       0x1c, 0x01,     0x1d, 0x09,     0x1e, 0xff,     0x1f, 0x01,
+       0x10, 0x24,     0
+};
+
+static u8 cg3regvals_rdi[] __initdata = {      /* 640 x 480, cgRDI */
+       0x14, 0x70,     0x15, 0x20,     0x16, 0x08,     0x17, 0x10,
+       0x18, 0x06,     0x19, 0x02,     0x1a, 0x31,     0x1b, 0x51,
+       0x1c, 0x06,     0x1d, 0x0c,     0x1e, 0xff,     0x1f, 0x01,
+       0x10, 0x22,     0
+};
+
+static u8 *cg3_regvals[] __initdata = {
+       cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi
+};
+
+static u_char cg3_dacvals[] __initdata = {
+       4, 0xff,        5, 0x00,        6, 0x70,        7, 0x00,        0
+};
+
+static char idstring[60] __initdata = { 0 };
+
+__initfunc(char *cgthreefb_init(struct fb_info_sbusfb *fb))
+{
+       struct fb_fix_screeninfo *fix = &fb->fix;
+       struct display *disp = &fb->disp;
+       struct fbtype *type = &fb->type;
+       unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr;
+       int cgRDI = strstr(fb->sbdp->prom_name, "cgRDI") != NULL;
+
+#ifndef FBCON_HAS_CFB8
+       return NULL;
+#endif
+
+       if (!fb->s.cg3.regs) {
+               fb->s.cg3.regs = (struct cg3_regs *)sparc_alloc_io(phys+CG3_REGS_OFFSET, 0, 
+                               sizeof(struct cg3_regs), "cg3_regs", fb->iospace, 0);
+               if (cgRDI) {
+                       char buffer[40];
+                       char *p;
+                       int ww, hh;
+               
+                       *buffer = 0;
+                       prom_getstring (fb->prom_node, "params", buffer, sizeof(buffer));
+                       if (*buffer) {
+                               ww = simple_strtoul (buffer, &p, 10);
+                               if (ww && *p == 'x') {
+                                       hh = simple_strtoul (p + 1, &p, 10);
+                                       if (hh && *p == '-') {
+                                               if (type->fb_width != ww || type->fb_height != hh) {
+                                                       type->fb_width = ww;
+                                                       type->fb_height = hh;
+                                                       return SBUSFBINIT_SIZECHANGE;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       strcpy(fb->info.modename, "CGthree");
+       strcpy(fix->id, "CGthree");
+       fix->line_length = fb->var.xres_virtual;
+       
+       disp->scrollmode = SCROLL_YREDRAW;
+       if (!disp->screen_base)
+               disp->screen_base = (char *)sparc_alloc_io(phys+CG3_RAM_OFFSET, 0, 
+                       type->fb_size, "cg3_ram", fb->iospace, 0);
+       disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin;
+       fb->dispsw = fbcon_cfb8;
+
+       fb->margins = cg3_margins;
+       fb->loadcmap = cg3_loadcmap;
+       fb->blank = cg3_blank;
+       fb->unblank = cg3_unblank;
+       
+       fb->physbase = phys;
+       fb->mmap_map = cg3_mmap_map;
+       
+#ifdef __sparc_v9__    
+       sprintf(idstring, "%s at %016lx", cgRDI ? "cgRDI" : "cgthree", phys);
+#else
+       sprintf(idstring, "%s at %x.%08lx", cgRDI ? "cgRDI" : "cgthree", fb->iospace, phys);
+#endif
+       
+       if (!prom_getbool(fb->prom_node, "width")) {
+               /* Ugh, broken PROM didn't initialize us.
+                * Let's deal with this ourselves.
+                */
+               enum cg3_type type;
+               u8 *p;
+
+               if (cgRDI)
+                       type = CG3_RDI;
+               else {
+                       u8 status = fb->s.cg3.regs->status, mon;
+                       if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) {
+                               mon = status & CG3_SR_RES_MASK;
+                               if (mon == CG3_SR_1152_900_76_A ||
+                                   mon == CG3_SR_1152_900_76_B)
+                                       type = CG3_AT_76HZ;
+                               else
+                                       type = CG3_AT_66HZ;
+                       } else {
+                               prom_printf("cgthree: can't handle SR %02x\n",
+                                           status);
+                               prom_halt();
+                               return NULL; /* fool gcc. */
+                       }
+               }
+
+               for (p = cg3_regvals[type]; *p; p += 2)
+                       ((u8 *)fb->s.cg3.regs)[p[0]] = p[1];
+
+               for (p = cg3_dacvals; *p; p += 2) {
+                       *(volatile u8 *)&fb->s.cg3.regs->cmap.addr = p[0];
+                       *(volatile u8 *)&fb->s.cg3.regs->cmap.control = p[1];
+               }
+       }
+
+       return idstring;
+}
diff --git a/drivers/video/clgenfb.c b/drivers/video/clgenfb.c
new file mode 100644 (file)
index 0000000..8bf6cf9
--- /dev/null
@@ -0,0 +1,2122 @@
+/*
+ * Based on retz3fb.c and clgen.c
+ */
+#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/zorro.h>
+#include <linux/init.h>
+#include <asm/amigahw.h>
+#include <asm/pgtable.h>
+#include <asm/delay.h>
+#include "fbcon.h"
+
+#include "fbcon.h"
+#include "fbcon-mfb.h"
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb16.h"
+#include "fbcon-cfb24.h"
+#include "fbcon-cfb32.h"
+
+#include "clgenfb.h"
+
+#define CLGEN_VERSION "1.4 ?"
+/* #define DEBUG if(1) */
+#define DEBUG if(0)
+
+#define arraysize(x)    (sizeof(x)/sizeof(*(x)))
+
+/* zorro IDs */
+#define ZORRO_PROD_HELFRICH_SD64_RAM                           0x08930A00
+#define ZORRO_PROD_HELFRICH_SD64_REG                           0x08930B00
+#define ZORRO_PROD_HELFRICH_PICCOLO_RAM                                0x08930500
+#define ZORRO_PROD_HELFRICH_PICCOLO_REG                                0x08930600
+#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM       0x08770B00
+#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG       0x08770C00
+#define ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM                  0x08910200
+#define ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG                  0x08910100
+#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3                        0x08771800
+
+/* board types */
+#define BT_NONE     0
+#define BT_SD64     1
+#define BT_PICCOLO  2
+#define BT_PICASSO  3
+#define BT_SPECTRUM 4
+#define BT_PICASSO4 5
+
+#define MAX_NUM_BOARDS 7
+
+#define TRUE  1
+#define FALSE 0 
+
+struct clgenfb_par
+{
+    struct fb_var_screeninfo var;
+
+    __u32 line_length;  /* in BYTES! */
+    __u32 visual;
+    __u32 type;
+
+    long freq;
+    long nom;
+    long den;
+    long div;
+
+    long HorizRes;   /* The x resolution in pixel */
+    long HorizTotal;
+    long HorizDispEnd;
+    long HorizBlankStart;
+    long HorizBlankEnd;
+    long HorizSyncStart;
+    long HorizSyncEnd;
+
+    long VertRes;   /* the physical y resolution in scanlines */
+    long VertTotal;
+    long VertDispEnd;
+    long VertSyncStart;
+    long VertSyncEnd;
+    long VertBlankStart;
+    long VertBlankEnd;
+};
+
+/* info about board */
+struct clgenfb_info
+{
+    struct fb_info_gen gen;
+
+    int keyRAM;  /* RAM, REG zorro board keys */
+    int keyREG;
+    unsigned long fbmem;
+    volatile unsigned char *regs;
+    unsigned long mem;
+    unsigned long size;
+    int btype;
+    int smallboard;
+    unsigned char SFR; /* Shadow of special function register */
+    
+    struct clgenfb_par currentmode;
+};
+
+static struct display disp;
+
+static struct clgenfb_info boards[MAX_NUM_BOARDS];  /* the boards */
+static struct clgenfb_info *fb_info=NULL;  /* pointer to current board */
+
+/*
+ *    Predefined Video Modes
+ */
+
+static struct fb_videomode clgenfb_predefined[] __initdata =
+{
+       {   "Autodetect", /* autodetect mode */
+           { 0 }
+       },
+
+       {   "640x480", /* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */
+           { 
+               640, 480, 640, 480, 0, 0, 8, 0, 
+               {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 
+               0, 0, -1, -1, FB_ACCEL_NONE, 40000, 32, 32, 33, 10, 96, 2,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+           }
+       },
+
+       /* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */
+       /* 
+           Modeline from XF86Config:
+           Mode "1024x768" 80  1024 1136 1340 1432  768 770 774 805
+       */
+       {
+           "1024x768",
+           { 
+               1024, 768, 1024, 768, 0, 0, 8, 0, 
+               {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 
+               0, 0, -1, -1, FB_ACCEL_NONE, 12500, 92, 112, 31, 2, 204, 4,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+           }
+       }
+};
+
+#define NUM_TOTAL_MODES    arraysize(clgenfb_predefined)
+static struct fb_var_screeninfo clgenfb_default;
+
+/*
+ *    Frame Buffer Name
+ */
+
+static char clgenfb_name[16] = "CLgen";
+
+/****************************************************************************/
+/**** BEGIN PROTOTYPES ******************************************************/
+
+/*--- Interface used by the world ------------------------------------------*/
+void clgenfb_init(void);
+void clgenfb_setup(char *options, int *ints);
+int clgenfb_open(struct fb_info *info, int user);
+int clgenfb_release(struct fb_info *info, int user);
+int clgenfb_ioctl(struct inode *inode, struct file *file, 
+                 unsigned int cmd, unsigned long arg, int con, 
+                 struct fb_info *info);
+
+/* function table of the above functions */
+static struct fb_ops clgenfb_ops =
+{
+    clgenfb_open,
+    clgenfb_release,
+    fbgen_get_fix,   /* using the generic functions */
+    fbgen_get_var,   /* makes things much easier... */
+    fbgen_set_var,
+    fbgen_get_cmap,
+    fbgen_set_cmap,
+    fbgen_pan_display,
+    clgenfb_ioctl,
+    NULL
+};
+
+/*--- Hardware Specific Routines -------------------------------------------*/
+static void clgen_detect(void);
+static int  clgen_encode_fix(struct fb_fix_screeninfo *fix, const void *par,
+                            struct fb_info_gen *info);
+static int  clgen_decode_var(const struct fb_var_screeninfo *var, void *par,
+                            struct fb_info_gen *info);
+static int  clgen_encode_var(struct fb_var_screeninfo *var, const void *par,
+                            struct fb_info_gen *info);
+static void clgen_get_par(void *par, struct fb_info_gen *info);
+static void clgen_set_par(const void *par, struct fb_info_gen *info);
+static int  clgen_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+                          unsigned *blue, unsigned *transp,
+                          struct fb_info *info);
+static int  clgen_setcolreg(unsigned regno, unsigned red, unsigned green,
+                           unsigned blue, unsigned transp,
+                           struct fb_info *info);
+static int  clgen_pan_display(const struct fb_var_screeninfo *var,
+                             struct fb_info_gen *info);
+static int  clgen_blank(int blank_mode, struct fb_info_gen *info);
+
+static struct display_switch *clgen_get_dispsw(const void *par,
+                                              struct fb_info_gen *info);
+
+/* function table of the above functions */
+static struct fbgen_hwswitch clgen_hwswitch = 
+{
+    clgen_detect,
+    clgen_encode_fix,
+    clgen_decode_var,
+    clgen_encode_var,
+    clgen_get_par,
+    clgen_set_par,
+    clgen_getcolreg, 
+    clgen_setcolreg,
+    clgen_pan_display,
+    clgen_blank,
+    clgen_get_dispsw
+};
+
+/* Text console acceleration */
+
+#ifdef FBCON_HAS_CFB8
+static void fbcon_clgen8_bmove(struct display *p, int sy, int sx, 
+                               int dy, int dx, int height, int width);
+static void fbcon_clgen8_clear(struct vc_data *conp, struct display *p, 
+                               int sy, int sx, int height, int width);
+
+static struct display_switch fbcon_clgen_8 = {
+    fbcon_cfb8_setup,
+    fbcon_clgen8_bmove,
+    fbcon_clgen8_clear,
+    fbcon_cfb8_putc,
+    fbcon_cfb8_putcs,
+    fbcon_cfb8_revc,
+    NULL,
+    NULL,
+    fbcon_cfb8_clear_margins,
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+
+
+/*--- Internal routines ----------------------------------------------------*/
+static void init_vgachip(void);
+static void switch_monitor(int on);
+
+static void            WGen( int regnum, unsigned char val );
+static unsigned char   RGen( int regnum );
+static void            WSeq( unsigned char regnum, unsigned char val );
+static unsigned char   RSeq( unsigned char regnum );
+static void            WCrt( unsigned char regnum, unsigned char val );
+static unsigned char   RCrt( unsigned char regnum );
+static void            WGfx( unsigned char regnum, unsigned char val );
+static unsigned char   RGfx( unsigned char regnum );
+static void            WAttr( unsigned char regnum, unsigned char val );
+static void            AttrOn( void );
+static unsigned char   RAttr( unsigned char regnum );
+static void            WHDR( unsigned char val );
+static unsigned char   RHDR( void );
+static void            WSFR( unsigned char val );
+static void            WSFR2( unsigned char val );
+static void            WClut( unsigned char regnum, unsigned char red, 
+                                                    unsigned char green, 
+                                                    unsigned char blue );
+static void            RClut( unsigned char regnum, unsigned char *red, 
+                                                    unsigned char *green, 
+                                                    unsigned char *blue );
+static void            clgen_WaitBLT( void );
+static void            clgen_BitBLT (u_short curx, u_short cury,
+                                     u_short destx, u_short desty,
+                                     u_short width, u_short height, 
+                                     u_short line_length);
+static void            clgen_RectFill (u_short x, u_short y,
+                                       u_short width, u_short height,
+                                       u_char color, u_short line_length);
+
+static void            bestclock(long freq, long *best, 
+                                 long *nom, long *den, 
+                                 long *div, long maxfreq);
+
+/*** END   PROTOTYPES ********************************************************/
+/*****************************************************************************/
+/*** BEGIN Interface Used by the World ***************************************/
+
+static int opencount = 0;
+
+/*--- Open /dev/fbx ---------------------------------------------------------*/
+int clgenfb_open(struct fb_info *info, int user)
+{
+    MOD_INC_USE_COUNT;
+    if (opencount++ == 0) switch_monitor(1);
+    return 0;
+}
+
+/*--- Close /dev/fbx --------------------------------------------------------*/
+int clgenfb_release(struct fb_info *info, int user)
+{
+    if (--opencount == 0) switch_monitor(0);
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+/*--- handle /dev/fbx ioctl calls ------------------------------------------*/
+int clgenfb_ioctl(struct inode *inode, struct file *file,
+                  unsigned int cmd, unsigned long arg, int con,
+                  struct fb_info *info)
+{
+    printk(">clgenfb_ioctl()\n");
+    /* Nothing exciting here... */
+    printk("<clgenfb_ioctl()\n");
+    return -EINVAL;
+}
+
+/**** END   Interface used by the World *************************************/
+/****************************************************************************/
+/**** BEGIN Hardware specific Routines **************************************/
+
+static void clgen_detect(void)
+{
+    printk(">clgen_detect()\n");
+    printk("<clgen_detect()\n");
+}
+
+static int clgen_encode_fix(struct fb_fix_screeninfo *fix, const void *par,
+                           struct fb_info_gen *info)
+{
+    struct clgenfb_par  *_par  = (struct clgenfb_par*) par;
+    struct clgenfb_info *_info = (struct clgenfb_info*)info;
+    
+    memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+    strcpy(fix->id, clgenfb_name);
+       
+    fix->smem_start    = (char*)_info->fbmem;
+    
+    /* monochrome: only 1 memory plane */
+    /* 8 bit and above: Use whole memory area */
+    fix->smem_len       = _par->var.bits_per_pixel == 1 ? _info->size / 4 
+                                                       : _info->size;
+    fix->type          = _par->type;
+    fix->type_aux      = 0;
+    fix->visual                = _par->visual;
+    fix->xpanstep      = 1;
+    fix->ypanstep      = 1;
+    fix->ywrapstep     = 0;
+    fix->line_length   = _par->line_length;
+    fix->mmio_start    = (char *)_info->regs;
+    fix->mmio_len      = 0x10000;
+    fix->accel         = FB_ACCEL_NONE;
+
+    return 0;
+}
+
+static int clgen_decode_var(const struct fb_var_screeninfo *var, void *par,
+                           struct fb_info_gen *info)
+{
+    long freq;
+    int  xres, hfront, hsync, hback;
+    int  yres, vfront, vsync, vback;
+    int  nom,den; /* translyting from pixels->bytes */
+    int  i;
+    static struct
+    {
+       int xres,yres;
+    }
+    modes[] = { {1600,1280}, {1280,1024}, {1024,768}, 
+               {800,600}, {640,480}, {-1,-1} };
+
+    struct clgenfb_par *_par = (struct clgenfb_par *)par;
+
+    fb_info = (struct clgenfb_info*)info;
+    printk("clgen_decode_var()\n");
+
+    printk("Requested: %dx%dx%d\n", var->xres,var->yres,var->bits_per_pixel);
+    printk("  virtual: %dx%d\n", var->xres_virtual,var->yres_virtual);
+    printk("   offset: (%d,%d)\n", var->xoffset, var->yoffset);
+    printk("grayscale: %d\n", var->grayscale);
+#if 0
+    printk(" activate: 0x%x\n", var->activate);
+    printk(" pixclock: %d\n", var->pixclock);
+    printk("  htiming: %d;%d  %d\n", var->left_margin,var->right_margin,var->hsync_len);
+    printk("  vtiming: %d;%d  %d\n", var->upper_margin,var->lower_margin,var->vsync_len);
+    printk("     sync: 0x%x\n", var->sync);
+    printk("    vmode: 0x%x\n", var->vmode);
+#endif
+
+    _par->var = *var;
+
+    switch (var->bits_per_pixel)
+    {
+    case 1:  nom = 4; den = 8; break;   /* 8 pixel per byte, only 1/4th of mem usable */
+    case 8:  nom = 1; den = 1; break;   /* 1 pixel == 1 byte */
+    case 16: nom = 2; den = 1; break;   /* 2 bytes per pixel */
+    case 24: nom = 3; den = 1; break;   /* 3 bytes per pixel */
+    case 32: nom = 4; den = 1; break;  /* 4 bytes per pixel */
+    default:
+       printk("clgen: mode %dx%dx%d rejected...color depth not supported.\n",
+               var->xres, var->yres, var->bits_per_pixel);
+       return -EINVAL;
+    }
+
+    if (_par->var.xres*nom/den * _par->var.yres > fb_info->size)
+    {
+       printk("clgen: mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
+               var->xres, var->yres, var->bits_per_pixel);
+       return -EINVAL;
+    }
+    
+    /* use highest possible virtual resolution */
+    if (_par->var.xres_virtual == -1 &&
+       _par->var.xres_virtual == -1)
+    {
+       printk("clgen: using maximum available virtual resolution\n");
+       for (i=0; modes[i].xres != -1; i++)
+       {
+           if (modes[i].xres*nom/den * modes[i].yres < fb_info->size/2)
+               break;
+       }
+       if (modes[i].xres == -1)
+       {
+           printk("clgen: could not find a virtual resolution that fits into video memory!!\n");
+           return -EINVAL;
+       }
+       _par->var.xres_virtual = modes[i].xres;
+       _par->var.yres_virtual = modes[i].yres;
+
+       printk("clgen: virtual resolution set to maximum of %dx%d\n",
+               _par->var.xres_virtual, _par->var.yres_virtual);
+    }
+    else if (_par->var.xres_virtual == -1)
+    {
+    }
+    else if (_par->var.yres_virtual == -1)
+    {
+    }
+
+    if (_par->var.xoffset < 0) _par->var.xoffset = 0;
+    if (_par->var.yoffset < 0) _par->var.yoffset = 0;
+       
+    /* truncate xoffset and yoffset to maximum if too high */
+    if (_par->var.xoffset > _par->var.xres_virtual-_par->var.xres)
+       _par->var.xoffset = _par->var.xres_virtual-_par->var.xres -1;
+
+    if (_par->var.yoffset > _par->var.yres_virtual-_par->var.yres)
+       _par->var.yoffset = _par->var.yres_virtual-_par->var.yres -1;
+
+    switch (var->bits_per_pixel)
+    {
+    case 1:
+       _par->line_length       = _par->var.xres_virtual / 8;
+       _par->visual            = FB_VISUAL_MONO10;
+       break;
+
+    case 8:
+       _par->line_length       = _par->var.xres_virtual;
+       _par->visual            = FB_VISUAL_PSEUDOCOLOR;
+       break;
+
+    case 16:
+       _par->line_length       = _par->var.xres_virtual * 2;
+       _par->visual            = FB_VISUAL_DIRECTCOLOR;
+       break;
+
+    case 24:
+       _par->line_length       = _par->var.xres_virtual * 3;
+       _par->visual            = FB_VISUAL_DIRECTCOLOR;
+       break;
+
+    case 32:
+       _par->line_length       = _par->var.xres_virtual * 4;
+       _par->visual            = FB_VISUAL_DIRECTCOLOR;
+       break;
+    }
+    _par->type         = FB_TYPE_PACKED_PIXELS;
+
+    /* convert from ps to kHz */
+    freq = 1000000000 / var->pixclock;
+
+    DEBUG printk("desired pixclock: %ld kHz\n", freq); 
+
+    /* the SD64/P4 have a higher max. videoclock */
+    bestclock(freq, &_par->freq, &_par->nom, &_par->den, &_par->div, 
+               fb_info->btype == BT_SD64 || fb_info->btype == BT_PICASSO4
+               ? 140000 : 90000);
+
+    DEBUG printk("Best possible values for given frequency: best: %ld kHz  nom: %ld  den: %ld  div: %ld\n", 
+                _par->freq, _par->nom, _par->den, _par->div);
+
+    xres   = _par->var.xres;
+    hfront = _par->var.right_margin;
+    hsync  = _par->var.hsync_len;
+    hback  = _par->var.left_margin;
+
+    yres   = _par->var.yres;
+    vfront = _par->var.lower_margin;
+    vsync  = _par->var.vsync_len;
+    vback  = _par->var.upper_margin;
+    
+    if (_par->var.vmode & FB_VMODE_DOUBLE)
+    {
+       yres   *= 2;
+       vfront *= 2;
+       vsync  *= 2;
+       vback  *= 2;
+    }
+    else if (_par->var.vmode & FB_VMODE_INTERLACED)
+    {
+       yres   = ++yres   / 2;
+       vfront = ++vfront / 2;
+       vsync  = ++vsync  / 2;
+       vback  = ++vback  / 2;
+    }
+
+    _par->HorizRes        = xres;
+    _par->HorizTotal      = (xres + hfront + hsync + hback)/8 - 5;
+    _par->HorizDispEnd    = xres/8 - 1;
+    _par->HorizBlankStart = xres/8;
+    _par->HorizBlankEnd   = _par->HorizTotal+5; /* does not count with "-5" */
+    _par->HorizSyncStart  = (xres + hfront)/8 + 1;
+    _par->HorizSyncEnd    = (xres + hfront + hsync)/8 + 1;
+
+    _par->VertRes         = yres;
+    _par->VertTotal       = yres + vfront + vsync + vback -2;
+    _par->VertDispEnd     = yres - 1;
+    _par->VertBlankStart  = yres;
+    _par->VertBlankEnd    = _par->VertTotal;
+    _par->VertSyncStart   = yres + vfront - 1;
+    _par->VertSyncEnd     = yres + vfront + vsync - 1;
+
+    if (_par->VertTotal >= 1024)
+    {
+       printk(KERN_WARNING "clgen: ERROR: VerticalTotal >= 1024; special treatment required! (TODO)\n");
+       return -EINVAL;
+    }
+
+    return 0;
+}
+
+
+static int clgen_encode_var(struct fb_var_screeninfo *var, const void *par,
+                           struct fb_info_gen *info)
+{
+    *var = ((struct clgenfb_par*)par)->var;
+    return 0;
+}
+
+/* get current video mode */
+static void clgen_get_par(void *par, struct fb_info_gen *info)
+{
+    struct clgenfb_par *_par  = (struct clgenfb_par*)par;
+    struct clgenfb_info*_info = (struct clgenfb_info*)fb_info;
+
+    *_par = _info->currentmode;   
+}
+
+/*************************************************************************
+       clgen_set_par()
+
+       actually writes the values for a new video mode into the hardware,
+**************************************************************************/
+static void clgen_set_par(const void *par, struct fb_info_gen *info)
+{
+    unsigned char tmp;
+    int offset = 0;
+    struct clgenfb_par *_par = (struct clgenfb_par*)par;
+
+    printk(KERN_INFO">clgen_set_par()\n");
+    printk(KERN_INFO"Requested mode: %dx%dx%d\n",
+                   _par->var.xres, _par->var.yres, _par->var.bits_per_pixel);
+    printk(KERN_INFO"pixclock: %d\n", _par->var.pixclock);
+    
+    fb_info = (struct clgenfb_info *)info;
+
+    /* unlock register CRT0..CRT7 */
+    WCrt(CRT11, 0x20); /* previously: 0x00) */
+
+    /* if DEBUG is set, all parameters get output before writing */
+    DEBUG printk("CRT0: %ld\n", _par->HorizTotal); 
+    WCrt(CRT0, _par->HorizTotal);
+
+    DEBUG printk("CRT1: %ld\n", _par->HorizDispEnd); 
+    WCrt(CRT1, _par->HorizDispEnd);
+
+    DEBUG printk("CRT2: %ld\n", _par->HorizBlankStart); 
+    WCrt(CRT2, _par->HorizBlankStart);
+
+    DEBUG printk("CRT3: 128+%ld\n", _par->HorizBlankEnd % 32); /*  + 128: Compatible read */
+    WCrt(CRT3, 128 + (_par->HorizBlankEnd % 32));
+
+    DEBUG printk("CRT4: %ld\n", _par->HorizSyncStart);
+    WCrt(CRT4, _par->HorizSyncStart);
+
+    tmp = _par->HorizSyncEnd % 32;
+    if (_par->HorizBlankEnd & 32)      
+       tmp += 128;
+    DEBUG printk("CRT5: %d\n", tmp); 
+    WCrt(CRT5, tmp);
+
+    DEBUG printk("CRT6: %ld\n", _par->VertTotal & 0xff); 
+    WCrt(CRT6, (_par->VertTotal & 0xff));
+
+    tmp = 16;  /* LineCompare bit #9 */
+    if (_par->VertTotal      & 256) tmp |= 1;
+    if (_par->VertDispEnd    & 256) tmp |= 2;
+    if (_par->VertSyncStart  & 256) tmp |= 4;
+    if (_par->VertBlankStart & 256) tmp |= 8;
+    if (_par->VertTotal      & 512) tmp |= 32;
+    if (_par->VertDispEnd    & 512) tmp |= 64;
+    if (_par->VertSyncStart  & 512) tmp |= 128;
+    DEBUG printk("CRT7: %d\n", tmp);
+    WCrt(CRT7, tmp);
+
+    tmp = 0x40; /* LineCompare bit #8 */
+    if (_par->VertBlankStart & 512)            tmp |= 0x20;
+    if (_par->var.vmode & FB_VMODE_DOUBLE)     tmp |= 0x80;
+    DEBUG printk("CRT9: %d\n", tmp);
+    WCrt(CRT9, tmp);
+
+    DEBUG printk("CRT10: %ld\n", _par->VertSyncStart & 0xff);
+    WCrt(CRT10, (_par->VertSyncStart & 0xff));
+
+    DEBUG printk("CRT11: 64+32+%ld\n", _par->VertSyncEnd % 16);
+    WCrt(CRT11, (_par->VertSyncEnd % 16 + 64 + 32));
+
+    DEBUG printk("CRT12: %ld\n", _par->VertDispEnd & 0xff);
+    WCrt(CRT12, (_par->VertDispEnd & 0xff));
+
+    DEBUG printk("CRT15: %ld\n", _par->VertBlankStart & 0xff);
+    WCrt(CRT15, (_par->VertBlankStart & 0xff));
+
+    DEBUG printk("CRT16: %ld\n", _par->VertBlankEnd & 0xff);
+    WCrt(CRT16, (_par->VertBlankEnd & 0xff));
+
+    DEBUG printk("CRT18: 0xff\n");
+    WCrt(CRT18, 0xff);
+
+    tmp = 0;
+    if (_par->var.vmode & FB_VMODE_INTERLACED) tmp |= 1;
+    if (_par->HorizBlankEnd & 64)              tmp |= 16;
+    if (_par->HorizBlankEnd & 128)             tmp |= 32;
+    if (_par->VertBlankEnd  & 256)             tmp |= 64;
+    if (_par->VertBlankEnd  & 512)             tmp |= 128;
+    
+    DEBUG printk("CRT1a: %d\n", tmp);
+    WCrt(CRT1A, tmp);
+
+    /* set VCLK0 */
+    /* hardware RefClock: 14.31818 MHz */
+    /* formula: VClk = (OSC * N) / (D * (1+P)) */
+    /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
+
+    WSeq(SEQRB, _par->nom);
+    tmp = _par->den<<1; 
+    if (_par->div != 0) tmp |= 1;
+
+    if (fb_info->btype == BT_SD64)
+       tmp |= 0x80; /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
+    
+    WSeq(SEQR1B, tmp);
+
+    WCrt(CRT17, 0xc3); /* mode control: CRTC enable, ROTATE(?), 16bit address wrap, no compat. */
+
+/* HAEH?       WCrt(CRT11, 0x20);  * previously: 0x00  unlock CRT0..CRT7 */
+
+    /* don't know if it would hurt to also program this if no interlaced */
+    /* mode is used, but I feel better this way.. :-) */
+    if (_par->var.vmode & FB_VMODE_INTERLACED)
+       WCrt(CRT19, _par->HorizTotal / 2);
+    else
+       WCrt(CRT19, 0x00);      /* interlace control */
+
+    WSeq(SEQR3, 0);
+
+    /* adjust horizontal/vertical sync type (low/high) */
+    tmp = 0x03; /* enable display memory & CRTC I/O address for color mode */
+    if (_par->var.sync & FB_SYNC_HOR_HIGH_ACT)  tmp |= 0x40;
+    if (_par->var.sync & FB_SYNC_VERT_HIGH_ACT) tmp |= 0x80;
+    WGen(MISC_W, tmp);
+
+    WCrt(CRT8,    0);      /* Screen A Preset Row-Scan register */
+    WCrt(CRTA,    0);      /* text cursor on and start line */
+    WCrt(CRTB,   31);      /* text cursor end line */
+
+    /* programming for different color depths */
+    if (_par->var.bits_per_pixel == 1)
+    {
+       DEBUG printk(KERN_INFO "clgen: preparing for 1 bit deep display\n");
+#if 0
+       /* restore first 2 color registers for mono mode */
+       WClut( 0, 0x00, 0x00, 0x00);  /* background: black */
+       WClut( 1, 0xff, 0xff, 0xff);  /* foreground: white */
+#endif
+       WGfx(GR5,     0);      /* mode register */
+       
+       /* Extended Sequencer Mode */
+       switch(fb_info->btype)
+       {
+       case BT_SD64:
+           /* setting the SEQRF on SD64 is not necessary (only during init) */
+           DEBUG printk(KERN_INFO "(for SD64)\n");
+           WSeq(SEQR7,  0xf0);
+           WSeq(SEQR1F, 0x1a);     /*  MCLK select */
+           break;
+
+       case BT_PICCOLO:
+           DEBUG printk(KERN_INFO "(for Piccolo)\n");
+           WSeq(SEQR7, 0x80);
+/* ### ueberall 0x22? */
+           WSeq(SEQR1F, 0x22);     /* ##vorher 1c MCLK select */
+           WSeq(SEQRF, 0xb0);    /* evtl d0 bei 1 bit? avoid FIFO underruns..? */
+           break;
+
+       case BT_PICASSO:
+           DEBUG printk(KERN_INFO "(for Picasso)\n");
+           WSeq(SEQR7, 0x20);
+           WSeq(SEQR1F, 0x22);     /* ##vorher 22 MCLK select */
+           WSeq(SEQRF, 0xd0);    /* ## vorher d0 avoid FIFO underruns..? */
+           break;
+
+       case BT_SPECTRUM:
+           DEBUG printk(KERN_INFO "(for Spectrum)\n");
+           WSeq(SEQR7, 0x80);
+/* ### ueberall 0x22? */
+           WSeq(SEQR1F, 0x22);     /* ##vorher 1c MCLK select */
+           WSeq(SEQRF, 0xb0);    /* evtl d0? avoid FIFO underruns..? */
+           break;
+
+       case BT_PICASSO4:
+           DEBUG printk(KERN_INFO "(for Picasso 4)\n");
+           WSeq(SEQR7, 0x20);
+/*         WSeq(SEQR1F, 0x1c); */
+/* SEQRF not being set here... WSeq(SEQRF, 0xd0); */
+           break;
+
+       default:
+           printk(KERN_WARNING "clgen: unknown Board\n");
+           break;
+       }
+
+       WGen(M_3C6,0x01);     /* pixel mask: pass-through for first plane */
+       WHDR(0);              /* hidden dac reg: nothing special */
+       WSeq(SEQR4,  0x06);     /* memory mode: odd/even, ext. memory */
+       WSeq(SEQR2, 0x01);      /* plane mask: only write to first plane */
+       offset                  = _par->var.xres_virtual / 16;
+    }
+    else if (_par->var.bits_per_pixel == 8)
+    {
+       DEBUG printk(KERN_INFO "clgen: preparing for 8 bit deep display\n");
+       switch(fb_info->btype)
+       {
+       case BT_SD64:
+           WSeq(SEQR7,  0xf1); /* Extended Sequencer Mode: 256c col. mode */
+           WSeq(SEQR1F, 0x1d);     /* MCLK select */
+           break;
+
+       case BT_PICCOLO:
+           WSeq(SEQR7, 0x81);
+           WSeq(SEQR1F, 0x22);     /* ### vorher 1c MCLK select */
+           WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+           break;
+
+       case BT_PICASSO:
+           WSeq(SEQR7, 0x21);
+           WSeq(SEQR1F, 0x22);     /* ### vorher 1c MCLK select */
+           WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+           break;
+
+       case BT_SPECTRUM:
+           WSeq(SEQR7, 0x81);
+           WSeq(SEQR1F, 0x22);     /* ### vorher 1c MCLK select */
+           WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+           break;
+
+       case BT_PICASSO4:
+           WSeq(SEQR7, 0x21);
+           WSeq(SEQRF, 0xb8); /* ### INCOMPLETE!! */
+/*         WSeq(SEQR1F, 0x1c); */
+           break;
+
+       default:
+           printk(KERN_WARNING "clgen: unknown Board\n");
+           break;
+       }
+
+       WGfx(GR5,    64);     /* mode register: 256 color mode */
+       WGen(M_3C6,0xff);     /* pixel mask: pass-through all planes */
+       WHDR(0);              /* hidden dac reg: nothing special */
+       WSeq(SEQR4,  0x0a);     /* memory mode: chain4, ext. memory */
+       WSeq(SEQR2,  0xff);     /* plane mask: enable writing to all 4 planes */
+       offset                  = _par->var.xres_virtual / 8;
+    }
+    else if (_par->var.bits_per_pixel == 16)
+    {
+       DEBUG printk(KERN_INFO "clgen: preparing for 16 bit deep display\n");
+       switch(fb_info->btype)
+       {
+       case BT_SD64:
+           WSeq(SEQR7,  0xf7); /* Extended Sequencer Mode: 256c col. mode */
+           WSeq(SEQR1F, 0x1e);     /* MCLK select */
+           break;
+
+       case BT_PICCOLO:
+           WSeq(SEQR7, 0x87);
+           WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+           WSeq(SEQR1F, 0x22);     /* MCLK select */
+           break;
+
+       case BT_PICASSO:
+           WSeq(SEQR7, 0x27);
+           WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+           WSeq(SEQR1F, 0x22);     /* MCLK select */
+           break;
+
+       case BT_SPECTRUM:
+           WSeq(SEQR7, 0x87);
+           WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+           WSeq(SEQR1F, 0x22);     /* MCLK select */
+           break;
+
+       case BT_PICASSO4:
+           WSeq(SEQR7, 0x27);
+/*         WSeq(SEQR1F, 0x1c);  */
+           break;
+
+       default:
+           printk(KERN_WARNING "CLGEN: unknown Board\n");
+           break;
+       }
+
+       WGfx(GR5,    64);     /* mode register: 256 color mode */
+       WGen(M_3C6,0xff);     /* pixel mask: pass-through all planes */
+       WHDR(0xa0);           /* hidden dac reg: nothing special */
+       WSeq(SEQR4,  0x0a);     /* memory mode: chain4, ext. memory */
+       WSeq(SEQR2,  0xff);     /* plane mask: enable writing to all 4 planes */
+       offset                  = _par->var.xres_virtual / 4;
+    }
+    else if (_par->var.bits_per_pixel == 32)
+    {
+       DEBUG printk(KERN_INFO "clgen: preparing for 24/32 bit deep display\n");
+       switch(fb_info->btype)
+       {
+       case BT_SD64:
+           WSeq(SEQR7,  0xf9); /* Extended Sequencer Mode: 256c col. mode */
+           WSeq(SEQR1F, 0x1e);     /* MCLK select */
+           break;
+
+       case BT_PICCOLO:
+           WSeq(SEQR7, 0x85);
+           WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+           WSeq(SEQR1F, 0x22);     /* MCLK select */
+           break;
+
+       case BT_PICASSO:
+           WSeq(SEQR7, 0x25);
+           WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+           WSeq(SEQR1F, 0x22);     /* MCLK select */
+           break;
+
+       case BT_SPECTRUM:
+           WSeq(SEQR7, 0x85);
+           WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+           WSeq(SEQR1F, 0x22);     /* MCLK select */
+           break;
+
+       case BT_PICASSO4:
+           WSeq(SEQR7, 0x25);
+/*         WSeq(SEQR1F, 0x1c);  */
+           break;
+
+       default:
+           printk(KERN_WARNING "clgen: unknown Board\n");
+           break;
+       }
+
+       WGfx(GR5,    64);     /* mode register: 256 color mode */
+       WGen(M_3C6,0xff);     /* pixel mask: pass-through all planes */
+       WHDR(0xc5);           /* hidden dac reg: 8-8-8 mode (24 or 32) */
+       WSeq(SEQR4,  0x0a);     /* memory mode: chain4, ext. memory */
+       WSeq(SEQR2,  0xff);     /* plane mask: enable writing to all 4 planes */
+       offset                  = _par->var.xres_virtual / 4;
+    }
+    else
+       printk(KERN_ERR "clgen: What's this?? requested color depth == %d.\n",
+               _par->var.bits_per_pixel);
+
+    WCrt(CRT13, offset & 0xff);
+    tmp = 0x22;
+    if (offset & 0x100) tmp |= 0x10; /* offset overflow bit */
+       
+    WCrt(CRT1B,tmp);    /* screen start addr #16-18, fastpagemode cycles */
+
+    if (fb_info->btype == BT_SD64 || fb_info->btype == BT_PICASSO4)
+       WCrt(CRT1D, 0x00);   /* screen start address bit 19 */
+
+    WCrt(CRTE,    0);      /* text cursor location high */
+    WCrt(CRTF,    0);      /* text cursor location low */
+    WCrt(CRT14,   0);      /* underline row scanline = at very bottom */
+
+    WAttr(AR10,  1);      /* controller mode */
+    WAttr(AR11,  0);      /* overscan (border) color */
+    WAttr(AR12, 15);      /* color plane enable */
+    WAttr(AR33,  0);      /* pixel panning */
+    WAttr(AR14,  0);      /* color select */
+
+    /* [ EGS: SetOffset(); ] */
+    /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
+    AttrOn();
+
+    WGfx(GR0,    0);      /* set/reset register */
+    WGfx(GR1,    0);      /* set/reset enable */
+    WGfx(GR2,    0);      /* color compare */
+    WGfx(GR3,    0);      /* data rotate */
+    WGfx(GR4,    0);      /* read map select */
+    WGfx(GR6,    1);      /* miscellaneous register */
+    WGfx(GR7,   15);      /* color don't care */
+    WGfx(GR8,  255);      /* bit mask */
+
+    WSeq(SEQR12,  0x0);     /* graphics cursor attributes: nothing special */
+
+    /* finally, turn on everything - turn off "FullBandwidth" bit */
+    /* also, set "DotClock%2" bit where requested */
+    tmp = 0x01;
+
+/*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
+    if (var->vmode & FB_VMODE_CLOCK_HALVE)
+       tmp |= 0x08;
+*/
+
+    WSeq(SEQR1, tmp);
+    DEBUG printk("SEQR1: %d\n", tmp);
+
+#if 0
+    DEBUG printk(KERN_INFO "clgen: clearing display...");
+    clgen_RectFill(0, 0, _par->HorizRes, _par->VertRes, 0, _par->line_length);
+    clgen_WaitBLT();
+    DEBUG printk("done.\n");
+#endif
+
+    fb_info->currentmode = *_par;
+
+    printk("virtual offset: (%d,%d)\n", _par->var.xoffset,_par->var.yoffset);
+    /* pan to requested offset */
+    clgen_pan_display (&fb_info->currentmode.var, (struct fb_info_gen*)fb_info);
+
+    DEBUG printk("<clgen_set_par()\n");
+    return;
+}
+
+static int clgen_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+                          unsigned *blue, unsigned *transp,
+                          struct fb_info *info)
+{
+    unsigned char bred, bgreen, bblue;
+
+    if (regno > 255 || regno < 0)
+       return (1);
+
+    fb_info = (struct clgenfb_info *)info;
+
+    RClut(regno, &bred, &bgreen, &bblue);
+
+    *red    = (u_int)bred;
+    *green  = (u_int)bgreen;
+    *blue   = (u_int)bblue;
+    *transp = 0;
+    return (0);
+}
+
+static int clgen_setcolreg(unsigned regno, unsigned red, unsigned green,
+                          unsigned blue, unsigned transp, 
+                          struct fb_info *info)
+{
+    if (regno > 255 || regno < 0)
+       return (1);
+
+    fb_info = (struct clgenfb_info *)info;
+    
+    /* "transparent" stuff is completely ignored. */
+    WClut(regno, (red & 0xff), (green & 0xff), (blue & 0xff));
+
+    return (0);
+}
+
+/*************************************************************************
+       clgen_pan_display()
+
+       performs display panning - provided hardware permits this
+**************************************************************************/
+static int clgen_pan_display(const struct fb_var_screeninfo *var,
+                            struct fb_info_gen *info)
+{
+    int xoffset = 0;
+    int yoffset = 0;
+    unsigned long base;
+    unsigned char tmp = 0, tmp2 = 0, xpix;
+
+    fb_info = (struct clgenfb_info*)fb_info;
+
+    /* no range checks for xoffset and yoffset,   */
+    /* as fbgen_pan_display has already done this */
+
+    fb_info->currentmode.var.xoffset = var->xoffset;
+    fb_info->currentmode.var.yoffset = var->yoffset;
+
+    xoffset = var->xoffset * fb_info->currentmode.var.bits_per_pixel / 8;
+    yoffset = var->yoffset;
+
+    base = yoffset * fb_info->currentmode.line_length + xoffset;
+
+    if (fb_info->currentmode.var.bits_per_pixel == 1)
+    {
+       /* base is already correct */
+       xpix = (unsigned char)(var->xoffset % 8);
+    }
+    else
+    {
+       base /= 4;
+       xpix = (unsigned char)((xoffset % 4) * 2);
+    }
+
+    /* lower 8 + 8 bits of screen start address */
+    WCrt(CRTD, (unsigned char)(base & 0xff));
+    WCrt(CRTC, (unsigned char)(base >> 8));
+
+    /* construct bits 16, 17 and 18 of screen start address */
+    if (base & 0x10000) tmp |= 0x01;
+    if (base & 0x20000) tmp |= 0x04;
+    if (base & 0x40000) tmp |= 0x08;
+
+    tmp2 = (RCrt(CRT1B) & 0xf2) | tmp; /* 0xf2 is %11110010, exclude tmp bits */
+    WCrt(CRT1B, tmp2);
+    /* construct bit 19 of screen start address (only on SD64) */
+    if (fb_info->btype == BT_SD64 ||
+       fb_info->btype == BT_PICASSO4)
+    {
+       tmp2 = 0;
+       if (base & 0x80000) tmp2 = 0x80;
+       WCrt(CRT1D, tmp2);
+    }
+
+    /* write pixel panning value to AR33; this does not quite work in 8bpp */
+    /* ### Piccolo..? Will this work? */
+    if (fb_info->currentmode.var.bits_per_pixel == 1)
+       WAttr(AR33, xpix);
+
+    return(0);
+}
+
+
+static int clgen_blank(int blank_mode, struct fb_info_gen *info)
+{
+    unsigned char val;
+    printk(">clgen_blank(%d)\n",blank_mode);
+
+    fb_info = (struct clgenfb_info *)info;
+
+    val = RSeq(SEQR1);
+    if (blank_mode)
+       WSeq(SEQR1, val | 0x20); /* set "FullBandwidth" bit */
+    else
+       WSeq(SEQR1, val & 0xdf); /* clear "FullBandwidth" bit */
+
+    printk("<clgen_blank()\n");
+    return 0;
+}
+
+/**** END   Hardware specific Routines **************************************/
+/****************************************************************************/
+/**** BEGIN Internal Routines ***********************************************/
+
+static void init_vgachip(void)
+{
+    printk(">init_vgachip()\n");
+
+    /* reset board globally */
+    switch(fb_info->btype)
+    {
+    case BT_SD64:     WSFR(0x1f);  udelay(500); WSFR(0x4f); udelay(500); break;
+    case BT_PICCOLO:  WSFR(0x01);  udelay(500); WSFR(0x51); udelay(500); break;
+    case BT_PICASSO:  WSFR2(0xff); udelay(500);                                 break;
+    case BT_SPECTRUM: WSFR(0x1f);  udelay(500); WSFR(0x4f); udelay(500); break;
+    case BT_PICASSO4: 
+       WCrt(CRT51, 0x00); /* disable flickerfixer */
+       udelay(100000);
+       WGfx(GR2F, 0x00); /* from Klaus' NetBSD driver: */
+       WGfx(GR33, 0x00); /* put blitter into 542x compat */
+       WGfx(GR31, 0x00); /* mode */
+       break;
+
+    default:
+       printk(KERN_ERR "clgen: Warning: Unknown board type\n");
+       break;
+    }
+
+    /* "pre-set" a RAMsize; if the test succeeds, double it */
+    if (fb_info->btype == BT_SD64 ||
+        fb_info->btype == BT_PICASSO4)
+        fb_info->size = 0x400000;
+    else
+        fb_info->size = 0x200000;
+
+    /* assume it's a "large memory" board (2/4 MB) */
+    fb_info->smallboard = FALSE;
+
+    /* the P4 is not fully initialized here; I rely on it having been */
+    /* inited under AmigaOS already, which seems to work just fine    */
+    /* (Klaus advised to do it this way)                              */
+
+    if (fb_info->btype != BT_PICASSO4)
+    {
+       WGen(VSSM, 0x10);  /* EGS: 0x16 */
+       WGen(POS102, 0x01);
+       WGen(VSSM, 0x08);  /* EGS: 0x0e */
+
+       if(fb_info->btype != BT_SD64)
+               WGen(VSSM2, 0x01);
+
+       WSeq(SEQR0, 0x03);  /* reset sequencer logic */
+
+       WSeq(SEQR1, 0x21);  /* FullBandwidth (video off) and 8/9 dot clock */
+       WGen(MISC_W, 0xc1);  /* polarity (-/-), disable access to display memory, CRTC base address: color */
+
+/*     WGfx(GRA, 0xce);    "magic cookie" - doesn't make any sense to me.. */
+       WSeq(SEQR6, 0x12);   /* unlock all extension registers */
+
+       WGfx(GR31, 0x04);  /* reset blitter */
+
+       if (fb_info->btype == BT_SD64)
+       {
+           WSeq(SEQRF, 0xb8);  /* 4 MB Ram SD64, disable CRT fifo(!), 64 bit bus */
+       }
+       else
+       {
+           WSeq(SEQR16, 0x0f); /* Perf. Tuning: Fix value..(?) */
+           WSeq(SEQRF, 0xb0); /* 2 MB DRAM, 8level write buffer, 32bit bus */
+       }
+    }
+
+    WSeq(SEQR2, 0xff);  /* plane mask: nothing */
+    WSeq(SEQR3, 0x00);  /* character map select: doesn't even matter in gx mode */
+    WSeq(SEQR4, 0x0e);  /* memory mode: chain-4, no odd/even, ext. memory */
+
+    /* controller-internal base address of video memory */
+    switch(fb_info->btype)
+    {
+    case BT_SD64:     WSeq(SEQR7, 0xf0); break;
+    case BT_PICCOLO:  WSeq(SEQR7, 0x80); break;
+    case BT_SPECTRUM: WSeq(SEQR7, 0x80); break;
+    case BT_PICASSO:  WSeq(SEQR7, 0x20); break;
+    case BT_PICASSO4: WSeq(SEQR7, 0x20); break;
+    }
+
+/*  WSeq(SEQR8, 0x00);*/  /* EEPROM control: shouldn't be necessary to write to this at all.. */
+
+    WSeq(SEQR10, 0x00); /* graphics cursor X position (incomplete; position gives rem. 3 bits */
+    WSeq(SEQR11, 0x00); /* graphics cursor Y position (..."... ) */
+    WSeq(SEQR12, 0x00); /* graphics cursor attributes */
+    WSeq(SEQR13, 0x00); /* graphics cursor pattern address */
+
+    /* writing these on a P4 might give problems..  */
+    if (fb_info->btype != BT_PICASSO4)
+    {
+       WSeq(SEQR17, 0x00); /* configuration readback and ext. color */
+       WSeq(SEQR18, 0x02); /* signature generator */
+    }
+
+    /* MCLK select etc. */
+    switch(fb_info->btype)
+    {
+    case BT_PICCOLO:
+    case BT_PICASSO:
+    case BT_SPECTRUM:  WSeq(SEQR1F, 0x22); break;
+    case BT_SD64:      WSeq(SEQR1F, 0x20); break;
+    case BT_PICASSO4:/*WSeq(SEQR1F, 0x1c); */ break;
+    }
+
+    WCrt(CRT8, 0x00);  /* Screen A preset row scan: none */
+    WCrt(CRTA, 0x20);  /* Text cursor start: disable text cursor */
+    WCrt(CRTB, 0x00);  /* Text cursor end: - */
+    WCrt(CRTC, 0x00);  /* Screen start address high: 0 */
+    WCrt(CRTD, 0x00);  /* Screen start address low: 0 */
+    WCrt(CRTE, 0x00);  /* text cursor location high: 0 */
+    WCrt(CRTF, 0x00);  /* text cursor location low: 0 */
+
+    WCrt(CRT14, 0x00); /* Underline Row scanline: - */
+    WCrt(CRT17, 0xc3); /* mode control: timing enable, byte mode, no compat modes */
+    WCrt(CRT18, 0x00); /* Line Compare: not needed */
+    /* ### add 0x40 for text modes with > 30 MHz pixclock */
+    WCrt(CRT1B, 0x02); /* ext. display controls: ext.adr. wrap */
+
+    WGfx(GR0, 0x00); /* Set/Reset registes: - */
+    WGfx(GR1, 0x00); /* Set/Reset enable: - */
+    WGfx(GR2, 0x00); /* Color Compare: - */
+    WGfx(GR3, 0x00); /* Data Rotate: - */
+    WGfx(GR4, 0x00); /* Read Map Select: - */
+    WGfx(GR5, 0x00); /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
+    WGfx(GR6, 0x01); /* Miscellaneous: memory map base address, graphics mode */
+    WGfx(GR7, 0x0f); /* Color Don't care: involve all planes */
+    WGfx(GR8, 0xff); /* Bit Mask: no mask at all */
+    WGfx(GRB, 0x28); /* Graphics controller mode extensions: finer granularity, 8byte data latches */
+
+    WGfx(GRC, 0xff); /* Color Key compare: - */
+    WGfx(GRD, 0x00); /* Color Key compare mask: - */
+    WGfx(GRE, 0x00); /* Miscellaneous control: - */
+/*  WGfx(GR10, 0x00);*/ /* Background color byte 1: - */
+/*  WGfx(GR11, 0x00); */
+
+    WAttr(AR0, 0x00); /* Attribute Controller palette registers: "identity mapping" */
+    WAttr(AR1, 0x01);
+    WAttr(AR2, 0x02);
+    WAttr(AR3, 0x03);
+    WAttr(AR4, 0x04);
+    WAttr(AR5, 0x05);
+    WAttr(AR6, 0x06);
+    WAttr(AR7, 0x07);
+    WAttr(AR8, 0x08);
+    WAttr(AR9, 0x09);
+    WAttr(ARA, 0x0a);
+    WAttr(ARB, 0x0b);
+    WAttr(ARC, 0x0c);
+    WAttr(ARD, 0x0d);
+    WAttr(ARE, 0x0e);
+    WAttr(ARF, 0x0f);
+
+    WAttr(AR10, 0x01); /* Attribute Controller mode: graphics mode */
+    WAttr(AR11, 0x00); /* Overscan color reg.: reg. 0 */
+    WAttr(AR12, 0x0f); /* Color Plane enable: Enable all 4 planes */
+/* ###         WAttr(AR33, 0x00); * Pixel Panning: - */
+    WAttr(AR14, 0x00); /* Color Select: - */
+
+    WGen(M_3C6, 0xff); /* Pixel mask: no mask */
+
+    WGen(MISC_W, 0xc3); /* polarity (-/-), enable display mem, CRTC i/o base = color */
+
+    WGfx(GR31, 0x04); /* BLT Start/status: Blitter reset */
+    WGfx(GR31, 0x00); /* - " -           : "end-of-reset" */
+
+    /* CLUT setup */
+    WClut( 0, 0x00, 0x00, 0x00);  /* background: black */
+    WClut( 1, 0xff, 0xff, 0xff);  /* foreground: white */
+    WClut( 2, 0x00, 0x80, 0x00);
+    WClut( 3, 0x00, 0x80, 0x80);
+    WClut( 4, 0x80, 0x00, 0x00);
+    WClut( 5, 0x80, 0x00, 0x80);
+    WClut( 6, 0x80, 0x40, 0x00);
+    WClut( 7, 0x80, 0x80, 0x80);
+    WClut( 8, 0x40, 0x40, 0x40);
+    WClut( 9, 0x40, 0x40, 0xc0);
+    WClut(10, 0x40, 0xc0, 0x40);
+    WClut(11, 0x40, 0xc0, 0xc0);
+    WClut(12, 0xc0, 0x40, 0x40);
+    WClut(13, 0xc0, 0x40, 0xc0);
+    WClut(14, 0xc0, 0xc0, 0x40);
+    WClut(15, 0xc0, 0xc0, 0xc0);
+
+    /* the rest a grey ramp */
+    {
+       int i;
+
+       for (i = 16; i < 256; i++)
+           WClut(i, i, i, i);
+    }
+
+
+    /* misc... */
+    WHDR(0); /* Hidden DAC register: - */
+
+#if 0
+    /* check for 1/2 MB Piccolo/Picasso/Spectrum resp. 2/4 MB SD64 */
+    /* DRAM register has already been pre-set for "large", so it is*/
+    /* only modified if we find that this is a "small" version */
+    {
+       unsigned volatile char *ram = fb_info->fbmem;
+       int i, flag = 0;
+
+       ram += (fb_info->size >> 1);
+
+       for (i = 0; i < 256; i++)
+           ram[i] = (unsigned char)i;
+
+       for (i = 0; i < 256; i++)
+       {
+           if (ram[i] != i)
+               flag = 1;
+       }
+
+       /* if the DRAM test failed, halve RAM value */
+       if (flag)
+       {
+           fb_info->size /= 2;
+           fb_info->smallboard = TRUE;
+           switch(fb_info->btype)
+           {
+           case BT_SD64:     WSeq(SEQRF, 0x38); break; /* 2 MB Ram SD64 */
+           case BT_PICASSO4: WSeq(SEQRF, 0x38); break; /* ### like SD64? */
+           case BT_PICCOLO:
+           case BT_PICASSO:
+           case BT_SPECTRUM: WSeq(SEQRF, 0x30); break; /* 1 MB DRAM */
+           default:
+               printk(KERN_WARNING "clgen: Uuhh..could not determine RAM size!\n");
+           }
+       }
+
+    }
+#endif
+    printk(KERN_INFO "clgen: This board has %ld bytes of DRAM memory\n", fb_info->size);
+    printk("<init_vgachip()\n");
+    return;
+}
+
+static void switch_monitor(int on)
+{
+    static int IsOn = 0;    /* XXX not ok for multiple boards */
+
+    if (fb_info->btype == BT_PICASSO4) return; /* nothing to switch */
+    if (fb_info->btype == BT_PICASSO)
+    {
+       if ((on && !IsOn) || (!on && IsOn))
+           WSFR(0xff);
+       return;
+    }    
+    if (on)
+        switch(fb_info->btype)
+       {
+        case BT_SD64:     WSFR(fb_info->SFR | 0x21);   break;
+        case BT_PICCOLO:  WSFR(fb_info->SFR | 0x28);   break;
+        case BT_SPECTRUM: WSFR(0x6f);                  break;
+       }
+    else
+        switch(fb_info->btype)
+       {
+        case BT_SD64:     WSFR(fb_info->SFR & 0xde);   break;
+        case BT_PICCOLO:  WSFR(fb_info->SFR & 0xd7);   break;
+        case BT_SPECTRUM: WSFR(0x4f);                  break;
+       }
+}
+
+static struct display_switch *clgen_get_dispsw(const void *par,
+                                            struct fb_info_gen *info)
+{
+    struct clgenfb_par *_par = (struct clgenfb_par*) par;
+
+    printk("clgen_get_dispsw(): ");
+    switch (_par->var.bits_per_pixel)
+    {
+#ifdef FBCON_HAS_MFB
+    case 1:
+       printk("monochrome\n");
+       return &fbcon_mfb;
+#endif
+#ifdef FBCON_HAS_CFB8
+    case 8:
+       printk("8 bit color depth\n");
+       return &fbcon_clgen_8;
+#endif
+#ifdef FBCON_HAS_CFB16
+    case 16:
+       printk("16 bit color depth\n");
+       return &fbcon_cfb16;
+#endif
+#ifdef FBCON_HAS_CFB24
+    case 24:
+       printk("24 bit color depth\n");
+       return &fbcon_cfb24;
+#endif
+#ifdef FBCON_HAS_CFB32
+    case 32:
+       printk("32 bit color depth\n");
+       return &fbcon_cfb32;
+#endif
+
+    default:
+       printk("unsupported color depth\n");
+       return NULL;
+    }
+}
+
+static void fbcon_clgen8_bmove(struct display *p, int sy, int sx, 
+                               int dy, int dx, int height, int width)
+{
+    sx     *= p->fontwidth;
+    sy     *= p->fontheight;
+    dx     *= p->fontwidth;
+    dy     *= p->fontheight;
+    width  *= p->fontwidth;
+    height *= p->fontheight;
+
+    fb_info = (struct clgenfb_info*)p->fb_info;
+
+    clgen_BitBLT((unsigned short)sx, (unsigned short)sy,
+                (unsigned short)dx, (unsigned short)dy,
+                (unsigned short)width, (unsigned short)height,
+                fb_info->currentmode.line_length);
+    clgen_WaitBLT();
+}
+
+static void fbcon_clgen8_clear(struct vc_data *conp, struct display *p, 
+                               int sy, int sx, int height, int width)
+{
+    unsigned short col;
+    
+    fb_info = (struct clgenfb_info*)p->fb_info;
+
+    sx     *= p->fontwidth;
+    sy     *= p->fontheight;
+    width  *= p->fontwidth;
+    height *= p->fontheight;
+
+    col = attr_bgcol_ec(p, conp);
+    col &= 0xff;
+
+    clgen_RectFill((unsigned short)sx, (unsigned short)sy,
+                   (unsigned short)width,(unsigned short)height,
+                    col, fb_info->currentmode.line_length);
+    clgen_WaitBLT();
+}
+
+
+/********************************************************************/
+/* clgenfb_init() - master initialization function                  */
+/********************************************************************/
+__initfunc(void clgenfb_init(void))
+{
+    const struct ConfigDev *cd  = NULL;
+    const struct ConfigDev *cd2 = NULL;
+    int err;
+    int btype;
+    int key,key2;
+    unsigned long board_addr,board_size;
+
+    printk(">clgenfb_init()\n");
+    printk(KERN_INFO "clgen: Driver for Cirrus Logic based graphic boards, v" CLGEN_VERSION "\n");
+
+    btype = -1;
+
+    if ((key = zorro_find(ZORRO_PROD_HELFRICH_SD64_RAM, 0, 0)))
+    {
+       key2 = zorro_find(ZORRO_PROD_HELFRICH_SD64_REG, 0, 0);
+        btype = BT_SD64;
+        printk(KERN_INFO "clgen: SD64 board detected; ");
+    }
+    else if ((key = zorro_find(ZORRO_PROD_HELFRICH_PICCOLO_RAM, 0, 0)))
+    {
+        key2      = zorro_find(ZORRO_PROD_HELFRICH_PICCOLO_REG, 0, 0);
+       btype = BT_PICCOLO;
+       printk(KERN_INFO "clgen: Piccolo board detected; ");
+    }
+    else if ((key = zorro_find(ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, 0, 0)))
+    {
+        key2      = zorro_find(ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG, 0, 0);
+       btype = BT_PICASSO;
+       printk(KERN_INFO "clgen: Picasso II board detected; ");
+    }
+    else if ((key = zorro_find(ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, 0, 0)))
+    {
+        key2      = zorro_find(ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG, 0, 0);
+        btype = BT_SPECTRUM;
+        printk(KERN_INFO "clgen: Spectrum board detected; ");
+    }
+    else if ((key = zorro_find(ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3, 0, 0)))
+    {
+        btype = BT_PICASSO4;
+        printk(KERN_INFO "clgen: Picasso 4 board detected; ");
+    }
+    else
+    {
+       printk(KERN_NOTICE "clgen: no supported board found.\n");
+       return;
+    }
+    
+    fb_info = &boards[0]; /* FIXME support multiple boards ...*/
+    
+    fb_info->keyRAM = key;
+    fb_info->keyREG = key2;
+    fb_info->btype  = btype;
+    
+    cd = zorro_get_board(key);
+    board_addr = (unsigned long)cd->cd_BoardAddr;
+    board_size = (unsigned long)cd->cd_BoardSize;
+    printk(" RAM (%lu MB) at $%lx, ", board_size/0x100000, board_addr);
+
+    if (btype == BT_PICASSO4)
+    {
+       printk(" REG at $%lx\n", board_addr + 0x600000);
+
+        /* To be precise, for the P4 this is not the */
+        /* begin of the board, but the begin of RAM. */
+       /* for P4, map in its address space in 2 chunks (### TEST! ) */
+       /* (note the ugly hardcoded 16M number) */
+       fb_info->regs = (unsigned char *)kernel_map(board_addr, 16777216, 
+                                             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->fbmem = kernel_map(board_addr + 16777216, 16777216, 
+                             KERNELMAP_NOCACHE_SER, NULL);
+       DEBUG printk(KERN_INFO "clgen: (RAM start set to: $%lx)\n", fb_info->fbmem);
+    }
+    else
+    {
+        cd2 = zorro_get_board(key2);
+        printk(" REG at $%lx\n", (unsigned long)cd2->cd_BoardAddr);
+
+        if (board_addr > 0x01000000)
+           fb_info->fbmem = kernel_map(board_addr, board_size, 
+                                 KERNELMAP_NOCACHE_SER, NULL);
+       else
+           fb_info->fbmem = ZTWO_VADDR(board_addr);
+
+        /* set address for REG area of board */
+       fb_info->regs = (unsigned char *)ZTWO_VADDR(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);
+    }
+
+    init_vgachip();
+
+    /* set up a few more things, register framebuffer driver etc */
+    fb_info->gen.parsize         = sizeof(struct clgenfb_par);
+    fb_info->gen.fbhw            = &clgen_hwswitch;
+    strcpy (fb_info->gen.info.modename, clgenfb_name);
+    fb_info->gen.info.node       = -1;
+    fb_info->gen.info.fbops      = &clgenfb_ops;
+    fb_info->gen.info.disp       = &disp;
+    fb_info->gen.info.changevar  = NULL;
+    fb_info->gen.info.switch_con = &fbgen_switch;
+    fb_info->gen.info.updatevar  = &fbgen_update_var;
+    fb_info->gen.info.blank      = &fbgen_blank;
+    
+    /* mark this board as "autoconfigured" */
+    zorro_config_board(key, 0);
+    if (btype != BT_PICASSO4)
+       zorro_config_board(key2, 0);
+
+    /* now that we know the board has been registered n' stuff, we */
+    /* can finally initialize it to a default mode (640x480) */
+    clgenfb_default = clgenfb_predefined[1].var;
+    clgenfb_default.activate = FB_ACTIVATE_NOW;
+    clgenfb_default.yres_virtual = 480*3; /* for fast scrolling (YPAN-Mode) */
+    err = fbgen_do_set_var(&clgenfb_default, 1, &fb_info->gen);
+
+    if (err)
+       return;
+
+    disp.var = clgenfb_default;
+    fbgen_set_disp(-1, &fb_info->gen);
+    fbgen_install_cmap(0, &fb_info->gen);
+
+    err = register_framebuffer(&fb_info->gen.info);
+    if (err)
+    {
+       printk(KERN_ERR "clgen: ERROR - could not register fb device; err = %d!\n", err);
+       return;
+    }
+
+    printk("<clgenfb_init()\n");
+    return;
+}
+
+    /*
+     *  Cleanup
+     */
+
+void clgenfb_cleanup(struct clgenfb_info *info)
+{
+    printk(">clgenfb_cleanup()\n");
+
+    fb_info = info;
+
+    switch_monitor(0);
+
+    zorro_unconfig_board(info->keyRAM, 0);
+    if (fb_info->btype != BT_PICASSO4)
+       zorro_unconfig_board(info->keyREG, 0);
+
+    unregister_framebuffer(&info->gen.info);
+    printk("Framebuffer unregistered\n");
+    printk("<clgenfb_cleanup()\n");
+}
+
+
+/* A strtok which returns empty strings, too */
+static char *strtoke(char *s,const char *ct)
+{
+       char *sbegin, *send;
+       static char *ssave = NULL;
+
+       sbegin  = s ? s : ssave;
+       if (!sbegin)
+               return NULL;
+       if (*sbegin == '\0') {
+               ssave = NULL;
+               return NULL;
+       }
+       send = strpbrk(sbegin, ct);
+       if (send && *send != '\0')
+               *send++ = '\0';
+       ssave = send;
+       return sbegin;
+}
+
+/*****************************************************************/
+/* clgenfb_setup() might be used later for parsing possible      */
+/* arguments to the video= bootstrap parameter. Right now, there */
+/* is nothing I do here.                                         */
+/*****************************************************************/
+__initfunc(void clgenfb_setup(char *options, int *ints))
+{
+//    char *this_opt;
+
+//    printk("clgenfb_setup(): options: %s\n", options);       
+}
+
+
+    /*
+     *  Modularization
+     */
+
+#ifdef MODULE
+int init_module(void)
+{
+    printk("init_module()\n");
+    clgenfb_init(0);
+    return 0;
+}
+
+void cleanup_module(void)
+{
+    printk("module_cleanup()\n");
+    clgenfb_cleanup(fb_info);
+}
+#endif /* MODULE */
+
+
+
+/**********************************************************************/
+/* about the following functions - I have used the same names for the */
+/* functions as Markus Wild did in his Retina driver for NetBSD as    */
+/* they just made sense for this purpose. Apart from that, I wrote    */
+/* these functions myself.                                            */
+/**********************************************************************/
+
+/*** WGen() - write into one of the external/general registers ***/
+void WGen(int regnum, unsigned char val)
+{
+       unsigned volatile char *reg = fb_info->regs + regnum;
+
+       if(fb_info->btype == BT_PICASSO)
+       {
+               /* Picasso II specific hack */
+/*             if (regnum == M_3C7_W || regnum == M_3C9 || regnum == VSSM2) */
+               if (regnum == M_3C7_W || regnum == M_3C9)
+                       reg += 0xfff;
+       }
+
+       *reg = val;
+}
+
+/*** RGen() - read out one of the external/general registers ***/
+unsigned char RGen(int regnum)
+{
+       unsigned volatile char *reg = fb_info->regs + regnum;
+
+       if(fb_info->btype == BT_PICASSO)
+       {
+               /* Picasso II specific hack */
+/*             if (regnum == M_3C7_W || regnum == M_3C9 || regnum == VSSM2) */
+               if (regnum == M_3C7_W || regnum == M_3C9)
+                       reg += 0xfff;
+       }
+
+       return *reg;
+}
+
+/*** WSeq() - write into a register of the sequencer ***/
+void WSeq(unsigned char regnum, unsigned char val)
+{
+       fb_info->regs[SEQRX]   = regnum;
+       fb_info->regs[SEQRX+1] = val;
+}
+
+/*** RSeq() - read out one of the Sequencer registers ***/
+unsigned char RSeq(unsigned char regnum)
+{
+       fb_info->regs[SEQRX] = regnum;
+       return fb_info->regs[SEQRX+1];
+}
+
+/*** WCrt() - write into a register of the CRT controller ***/
+void WCrt(unsigned char regnum, unsigned char val)
+{
+       fb_info->regs[CRTX]   = regnum;
+       fb_info->regs[CRTX+1] = val;
+}
+
+/*** RCrt() - read out one of the CRT controller registers ***/
+unsigned char RCrt(unsigned char regnum)
+{
+       fb_info->regs[CRTX] = regnum;
+       return fb_info->regs[CRTX+1];
+}
+
+/*** WGfx() - write into a register of the Gfx controller ***/
+void WGfx(unsigned char regnum, unsigned char val)
+{
+       fb_info->regs[GRX]   = regnum;
+       fb_info->regs[GRX+1] = val;
+}
+
+/*** RGfx() - read out one of the Gfx controller registers ***/
+unsigned char RGfx(unsigned char regnum)
+{
+       fb_info->regs[GRX] = regnum;
+       return fb_info->regs[GRX+1];
+}
+
+/*** WAttr() - write into a register of the Attribute controller ***/
+void WAttr(unsigned char regnum, unsigned char val)
+{
+       /* if the next access to the attribute controller is a data write access, */
+       /* simply write back the information that was already there before, so that */
+       /* the next write access after that will be an index write. */
+       if (RCrt(CRT24) & 0x80)
+               /* can't use WAttr() here - we would go into a recursive loop otherwise */
+               fb_info->regs[ARX] = fb_info->regs[ARX+1];
+
+       if (RCrt(CRT24) & 0x80)
+               printk(KERN_WARNING "clgen: *** AttrIdx BAD!***\n");
+
+       /* now, first set index and after that the value - both to the same address (!) */
+       fb_info->regs[ARX] = regnum;
+       fb_info->regs[ARX] = val;
+}
+
+/*** AttrOn() - turn on VideoEnable for Attribute controller ***/
+void AttrOn()
+{
+       if (RCrt(CRT24) & 0x80)
+               /* if we're just in "write value" mode, write back the */
+               /* same value as before to not modify anything */
+               fb_info->regs[ARX] = fb_info->regs[ARX+1];
+
+       /* turn on video bit */
+/*     fb_info->regs[ARX] = 0x20; */
+       fb_info->regs[ARX] = 0x33;
+
+       /* dummy write on Reg0 to be on "write index" mode next time */
+       fb_info->regs[ARX] = 0x00;
+}
+
+/*** RAttr() - read out a register of the Attribute controller ***/
+unsigned char RAttr(unsigned char regnum)
+{
+       /* (explanation see above in WAttr() ) */
+       if (RCrt(CRT24) & 0x80)
+               fb_info->regs[ARX] = fb_info->regs[ARX+1];
+
+       fb_info->regs[ARX] = regnum;
+       return fb_info->regs[ARX+1];
+}
+
+
+/*** WHDR() - write into the Hidden DAC register ***/
+/* as the HDR is the only extension register that requires special treatment 
+ * (the other extension registers are accessible just like the "ordinary"
+ * registers of their functional group) here is a specialized routine for 
+ * accessing the HDR
+ */
+void WHDR(unsigned char val)
+{
+       unsigned char dummy;
+
+       if(fb_info->btype == BT_PICASSO)
+       {
+               /* Klaus' hint for correct access to HDR on some boards */
+               /* first write 0 to pixel mask (3c6) */
+               WGen(M_3C6, 0x00); udelay(200);
+               /* next read dummy from pixel address (3c8) */
+               dummy = RGen(M_3C8); udelay(200);
+       }
+
+       /* now do the usual stuff to access the HDR */
+
+       dummy = RGen(M_3C6); udelay(200);
+       dummy = RGen(M_3C6); udelay(200);
+       dummy = RGen(M_3C6); udelay(200);
+       dummy = RGen(M_3C6); udelay(200);
+
+       WGen(M_3C6, val); udelay(200);
+
+       if(fb_info->btype == BT_PICASSO)
+       {
+               /* now first reset HDR access counter */
+               dummy = RGen(M_3C8); udelay(200);
+
+               /* and at the end, restore the mask value */
+               /* ## is this mask always 0xff? */
+               WGen(M_3C6, 0xff); udelay(200);
+       }
+}
+
+/*** RHDR() - read out the Hidden DAC register ***/
+/* I hope this does not break on the GD5428 - cannot test it. */
+/* (Is there any board for the Amiga that uses the 5428 ?) */
+unsigned char RHDR()
+{
+       unsigned char dummy;
+
+       dummy = RGen(M_3C6);
+       dummy = RGen(M_3C6);
+       dummy = RGen(M_3C6);
+       dummy = RGen(M_3C6);
+
+       return RGen(M_3C6);
+}
+
+
+/*** WSFR() - write to the "special function register" (SFR) ***/
+void WSFR(unsigned char val)
+{
+       fb_info->SFR          = val;
+       fb_info->regs[0x8000] = val;
+}
+
+/* The Picasso has a second register for switching the monitor bit */
+void WSFR2(unsigned char val)
+{
+       /* writing an arbitrary value to this one causes the monitor switcher */
+       /* to flip to Amiga display */
+       fb_info->SFR          = val;
+       fb_info->regs[0x9000] = val;
+}
+
+/*** WClut - set CLUT entry (range: 0..255 is automat. shifted to 0..63) ***/
+void WClut(unsigned char regnum, unsigned char red, unsigned char green, unsigned char blue)
+{
+       unsigned int data = 0x3c9;
+
+       /* address write mode register is not translated.. */
+       fb_info->regs[0x3c8] = regnum;
+
+       if(fb_info->btype == BT_PICASSO || fb_info->btype == BT_PICASSO4)
+       {
+               /* but DAC data register IS, at least for Picasso II */
+               if(fb_info->btype == BT_PICASSO)
+                       data += 0xfff;
+               fb_info->regs[data] = (red   >> 2);
+               fb_info->regs[data] = (green >> 2);
+               fb_info->regs[data] = (blue  >> 2);
+       }
+       else
+       {
+               fb_info->regs[data] = (blue  >> 2);
+               fb_info->regs[data] = (green >> 2);
+               fb_info->regs[data] = (red   >> 2);
+       }
+}
+
+/*** RClut - read CLUT entry and convert to 0..255 range ***/
+void RClut(unsigned char regnum, unsigned char *red, unsigned char *green, unsigned char *blue)
+{
+       unsigned int data = 0x3c9;
+
+       fb_info->regs[0x3c7] = regnum;
+
+       if(fb_info->btype == BT_PICASSO || fb_info->btype == BT_PICASSO4)
+       {
+               if(fb_info->btype == BT_PICASSO)
+                       data += 0xfff;
+               *red   = fb_info->regs[data] << 2;
+               *green = fb_info->regs[data] << 2;
+               *blue  = fb_info->regs[data] << 2;
+       }
+       else
+       {
+               *blue  = fb_info->regs[data] << 2;
+               *green = fb_info->regs[data] << 2;
+               *red   = fb_info->regs[data] << 2;
+       }
+}
+
+
+/*******************************************************************
+       clgen_WaitBLT()
+
+       Wait for the BitBLT engine to complete a possible earlier job
+*********************************************************************/
+
+void clgen_WaitBLT()
+{
+       /* now busy-wait until we're done */
+       while (RGfx(GR31) & 0x08)
+               ;
+}
+
+/*******************************************************************
+       clgen_BitBLT()
+
+       perform accelerated "scrolling"
+********************************************************************/
+
+void clgen_BitBLT (u_short curx, u_short cury, u_short destx, u_short desty,
+               u_short width, u_short height, u_short line_length)
+{
+       u_short nwidth, nheight;
+       u_long nsrc, ndest;
+       u_char bltmode;
+
+       nwidth = width - 1;
+       nheight = height - 1;
+
+       bltmode = 0x00;
+       /* if source adr < dest addr, do the Blt backwards */
+       if (cury <= desty)
+       {
+               if (cury == desty)
+               {
+                       /* if src and dest are on the same line, check x */
+                       if (curx < destx)
+                               bltmode |= 0x01;
+               }
+               else
+                       bltmode |= 0x01;
+       }
+
+       if (!bltmode)
+       {
+               /* standard case: forward blitting */
+               nsrc = (cury * line_length) + curx;
+               ndest = (desty * line_length) + destx;
+       }
+       else
+       {
+               /* this means start addresses are at the end, counting backwards */
+               nsrc = cury * line_length + curx + nheight * line_length + nwidth;
+               ndest = desty * line_length + destx + nheight * line_length + nwidth;
+       }
+
+//     clgen_WaitBLT(); /* ### NOT OK for multiple boards! */
+
+       /*
+               run-down of registers to be programmed:
+               destination pitch
+               source pitch
+               BLT width/height
+               source start
+               destination start
+               BLT mode
+               BLT ROP
+               GR0 / GR1: "fill color"
+               start/stop
+       */
+
+       /* pitch: set to line_length */
+       WGfx(GR24, line_length & 0xff); /* dest pitch low */
+       WGfx(GR25, (line_length >> 8)); /* dest pitch hi */
+       WGfx(GR26, line_length & 0xff); /* source pitch low */
+       WGfx(GR27, (line_length >> 8)); /* source pitch hi */
+
+       /* BLT width: actual number of pixels - 1 */
+       WGfx(GR20, nwidth & 0xff);      /* BLT width low */
+       WGfx(GR21, (nwidth >> 8));      /* BLT width hi */
+
+       /* BLT height: actual number of lines -1 */
+       WGfx(GR22, nheight & 0xff);     /* BLT height low */
+       WGfx(GR23, (nheight >> 8));     /* BLT width hi */
+
+       /* BLT destination */
+       WGfx(GR28, (u_char)(ndest & 0xff));     /* BLT dest low */
+       WGfx(GR29, (u_char)(ndest >> 8));       /* BLT dest mid */
+       WGfx(GR2A, (u_char)(ndest >> 16));      /* BLT dest hi */
+
+       /* BLT source */
+       WGfx(GR2C, (u_char)(nsrc & 0xff));      /* BLT src low */
+       WGfx(GR2D, (u_char)(nsrc >> 8));        /* BLT src mid */
+       WGfx(GR2E, (u_char)(nsrc >> 16));       /* BLT src hi */
+
+       /* BLT mode */
+       WGfx(GR30, bltmode);    /* BLT mode */
+
+       /* BLT ROP: SrcCopy */
+       WGfx(GR32, 0x0d);       /* BLT ROP */
+
+       /* and finally: GO! */
+       WGfx(GR31, 0x02);       /* BLT Start/status */
+}
+
+/*******************************************************************
+       clgen_RectFill()
+
+       perform accelerated rectangle fill
+********************************************************************/
+
+void clgen_RectFill (u_short x, u_short y, u_short width, u_short height,
+                     u_char color, u_short line_length)
+{
+       u_short nwidth, nheight;
+       u_long ndest;
+
+       nwidth = width - 1;
+       nheight = height - 1;
+
+       ndest = (y * line_length) + x;
+
+//     clgen_WaitBLT(); /* ### NOT OK for multiple boards! */
+
+       /* pitch: set to line_length */
+       WGfx(GR24, line_length & 0xff); /* dest pitch low */
+       WGfx(GR25, (line_length >> 8)); /* dest pitch hi */
+       WGfx(GR26, line_length & 0xff); /* source pitch low */
+       WGfx(GR27, (line_length >> 8)); /* source pitch hi */
+
+       /* BLT width: actual number of pixels - 1 */
+       WGfx(GR20, nwidth & 0xff);      /* BLT width low */
+       WGfx(GR21, (nwidth >> 8));      /* BLT width hi */
+
+       /* BLT height: actual number of lines -1 */
+       WGfx(GR22, nheight & 0xff);     /* BLT height low */
+       WGfx(GR23, (nheight >> 8));     /* BLT width hi */
+
+       /* BLT destination */
+       WGfx(GR28, (u_char)(ndest & 0xff));     /* BLT dest low */
+       WGfx(GR29, (u_char)(ndest >> 8));       /* BLT dest mid */
+       WGfx(GR2A, (u_char)(ndest >> 16));      /* BLT dest hi */
+
+       /* BLT source: set to 0 (is a dummy here anyway) */
+       WGfx(GR2C, 0x00);       /* BLT src low */
+       WGfx(GR2D, 0x00);       /* BLT src mid */
+       WGfx(GR2E, 0x00);       /* BLT src hi */
+
+       /* This is a ColorExpand Blt, using the */
+       /* same color for foreground and background */
+       WGfx(GR0, color);       /* foreground color */
+       WGfx(GR1, color);       /* background color */
+
+       /* BLT mode: color expand, Enable 8x8 copy (faster?) */
+       WGfx(GR30, 0xc0);       /* BLT mode */
+
+       /* BLT ROP: SrcCopy */
+       WGfx(GR32, 0x0d);       /* BLT ROP */
+
+       /* and finally: GO! */
+       WGfx(GR31, 0x02);       /* BLT Start/status */
+}
+
+/**************************************************************************
+ * bestclock() - determine closest possible clock lower(?) than the
+ * desired pixel clock
+ **************************************************************************/
+#define abs(x) ((x)<0 ? -(x) : (x))
+static void bestclock(long freq, long *best, long *nom,
+                     long *den, long *div,  long maxfreq)
+{
+    long n, h, d, f;
+
+    *nom = 0;
+    *den = 0;
+    *div = 0;
+
+    if (freq < 8000)
+       freq = 8000;
+
+    if (freq > maxfreq)
+       freq = maxfreq;
+
+    *best = 0;
+    f = freq * 10;
+
+    for(n = 32; n < 128; n++)
+    {
+        d = (143181 * n) / f;
+       if ( (d >= 7) && (d <= 63) )
+        {
+            if (d > 31)
+               d = (d / 2) * 2;
+            h = (14318 * n) / d;
+            if ( abs(h - freq) < abs(*best - freq) )
+            {
+                *best = h;
+               *nom = n;
+               if (d < 32)
+               {
+                    *den = d;
+                    *div = 0;
+               }
+               else
+               {
+                    *den = d / 2;
+                   *div = 1;
+               }
+            }
+        }
+        d = ( (143181 * n)+f-1) / f;
+        if ( (d >= 7) && (d <= 63) )
+       {
+           if (d > 31)
+               d = (d / 2) * 2;
+           h = (14318 * n) / d;
+           if ( abs(h - freq) < abs(*best - freq) )
+           {
+               *best = h;
+               *nom = n;
+               if (d < 32)
+               {
+                   *den = d;
+                   *div = 0;
+               }
+               else
+               {
+                   *den = d / 2;
+                   *div = 1;
+               }
+           }
+       }
+    }
+}
+
diff --git a/drivers/video/clgenfb.h b/drivers/video/clgenfb.h
new file mode 100644 (file)
index 0000000..3f66ec2
--- /dev/null
@@ -0,0 +1,175 @@
+
+/* definitions for Piccolo/SD64 VGA controller chip   */
+/* these definitions might most of the time also work */
+/* for other CL-GD542x/543x based boards..            */
+
+/*** External/General Registers ***/
+#define POS102 0x102   /* POS102 register */
+#define VSSM   0x46e8  /* Adapter Sleep */
+#define VSSM2  0x3c3   /* Motherboard Sleep */
+#define MISC_W 0x3c2   /* Miscellaneous Output register, write */
+#define MISC_R 0x3cc   /* Miscellaneous Output register, read */
+#define FC_W   0x3da   /* Feature Control Register, write (color) */
+#define FC_R   0x3ca   /* Feature Control Register, read */
+#define FEAT   0x3c2   /* Input Status Register 0 */
+#define STAT   0x3da   /* Input Status Register 1, read-only */
+#define M_3C6  0x3c6   /* Pixel Mask */
+#define M_3C7_W        0x3c7   /* Pixel Address Read Mode (write) */
+#define M_3C7_R        0x3c7   /* DAC State (read-only */
+#define M_3C8  0x3c8   /* Pixel Address Write Mode */
+#define M_3C9  0x3c9   /* Pixel Data */
+
+/*** VGA Sequencer Registers ***/
+#define SEQRX  0x3c4   /* Sequencer Index */
+#define SEQR0  0x0     /* Reset */
+#define SEQR1     0x1  /* Clocking Mode */
+#define SEQR2  0x2     /* Plane Mask / Write Pixel Extension */
+#define SEQR3  0x3     /* Character Map Select */
+#define SEQR4  0x4     /* Memory Mode */
+/* the following are from the "extension registers" group */
+#define SEQR6  0x6     /* Unlock ALL Extensions */
+#define SEQR7  0x7     /* Extended Sequencer Mode */
+#define SEQR8  0x8     /* EEPROM Control */
+#define SEQR9  0x9     /* Scratch Pad 0 (do not access!) */
+#define SEQRA  0xa     /* Scratch Pad 1 (do not access!) */
+#define SEQRB  0xb     /* VCLK0 Numerator */
+#define SEQRC  0xc     /* VCLK1 Numerator */
+#define SEQRD  0xd     /* VCLK2 Numerator */
+#define SEQRE  0xe     /* VCLK3 Numerator */
+#define SEQRF  0xf     /* DRAM Control */
+#define SEQR10 0x10    /* Graphics Cursor X Position */
+#define SEQR11 0x11    /* Graphics Cursor Y Position */
+#define SEQR12 0x12    /* Graphics Cursor Attributes */
+#define SEQR13 0x13    /* Graphics Cursor Pattern Address Offset */
+#define SEQR14 0x14    /* Scratch Pad 2 (CL-GD5426/'28 Only) (do not access!) */
+#define SEQR15 0x15    /* Scratch Pad 3 (CL-GD5426/'28 Only) (do not access!) */
+#define SEQR16 0x16    /* Performance Tuning (CL-GD5424/'26/'28 Only) */
+#define SEQR17 0x17    /* Configuration ReadBack and Extended Control (CL-GF5428 Only) */
+#define SEQR18 0x18    /* Signature Generator Control (Not CL-GD5420) */
+#define SEQR19 0x19    /* Signature Generator Result Low Byte (Not CL-GD5420) */
+#define SEQR1A 0x1a    /* Signature Generator Result High Byte (Not CL-GD5420) */
+#define SEQR1B 0x1b    /* VCLK0 Denominator and Post-Scalar Value */
+#define SEQR1C 0x1c    /* VCLK1 Denominator and Post-Scalar Value */
+#define SEQR1D 0x1d    /* VCLK2 Denominator and Post-Scalar Value */
+#define SEQR1E 0x1e    /* VCLK3 Denominator and Post-Scalar Value */
+#define SEQR1F 0x1f    /* BIOS ROM write enable and MCLK Select */
+
+/*** CRT Controller Registers ***/
+#define CRTX   0x3d4   /* CRTC Index */
+#define        CRT0    0x0     /* Horizontal Total */
+#define CRT1   0x1     /* Horizontal Display End */
+#define CRT2   0x2     /* Horizontal Blanking Start */
+#define CRT3   0x3     /* Horizontal Blabking End */
+#define CRT4   0x4     /* Horizontal Sync Start */
+#define CRT5   0x5     /* Horizontal Sync End */
+#define CRT6   0x6     /* Vertical Total */
+#define CRT7   0x7     /* Overflow */
+#define CRT8   0x8     /* Screen A Preset Row Scan */
+#define CRT9   0x9     /* Character Cell Height */
+#define CRTA   0xa     /* Text Cursor Start */
+#define CRTB   0xb     /* Text Cursor End */
+#define CRTC   0xc     /* Screen Start Address High */
+#define CRTD   0xd     /* Screen Start Address Low */
+#define CRTE   0xe     /* Text Cursor Location High */
+#define CRTF   0xf     /* Text Cursor Location Low */
+#define CRT10  0x10    /* Vertical Sync Start */
+#define CRT11  0x11    /* Vertical Sync End */
+#define CRT12  0x12    /* Vertical Display End */
+#define CRT13  0x13    /* Offset */
+#define CRT14  0x14    /* Underline Row Scan */
+#define CRT15          0x15    /* Vertical Blanking Start */
+#define CRT16  0x16    /* Vertical Blanking End */
+#define CRT17  0x17    /* Mode Control */
+#define CRT18  0x18    /* Line Compare */
+#define CRT22  0x22    /* Graphics Data Latches ReadBack */
+#define CRT24  0x24    /* Attribute Controller Toggle ReadBack */
+#define CRT26  0x26    /* Attribute Controller Index ReadBack */
+/* the following are from the "extension registers" group */
+#define CRT19  0x19    /* Interlace End */
+#define CRT1A  0x1a    /* Interlace Control */
+#define CRT1B  0x1b    /* Extended Display Controls */
+#define CRT1C  0x1c    /* Sync adjust and genlock register */
+#define CRT1D  0x1d    /* Overlay Extended Control register */
+#define CRT25  0x25    /* Part Status Register */
+#define CRT27  0x27    /* ID Register */
+#define CRT51  0x51    /* P4 disable "flicker fixer" */
+
+/*** Graphics Controller Registers ***/
+#define GRX    0x3ce   /* Graphics Controller Index */
+#define GR0    0x0     /* Set/Reset, Write Mode 5 Background Extension */
+#define GR1    0x1     /* Set/Reset Enable, Write Mode 4, 5 Foreground Ext. */
+#define GR2    0x2     /* Color Compare */
+#define GR3    0x3     /* Data Rotate */
+#define GR4    0x4     /* Read Map Select */
+#define GR5    0x5     /* Mode */
+#define GR6    0x6     /* Miscellaneous */
+#define GR7    0x7     /* Color Don't Care */
+#define GR8    0x8     /* Bit Mask */
+/* the following are from the "extension registers" group */
+#define GR9    0x9     /* Offset Register 0 */
+#define GRA    0xa     /* Offset Register 1 */
+#define GRB    0xb     /* Graphics Controller Mode Extensions */
+#define GRC    0xc     /* Color Key (CL-GD5424/'26/'28 Only) */
+#define GRD    0xd     /* Color Key Mask (CL-GD5424/'26/'28 Only) */
+#define GRE    0xe     /* Miscellaneous Control (Cl-GD5428 Only) */
+#define GRF    0xf     /* Display Compression Control register */
+#define GR10   0x10    /* 16-bit Pixel BG Color High Byte (Not CL-GD5420) */
+#define GR11   0x11    /* 16-bit Pixel FG Color High Byte (Not CL-GD5420) */
+#define GR12   0x12    /* Background Color Byte 2 Register */
+#define GR13   0x13    /* Foreground Color Byte 2 Register */
+#define GR14   0x14    /* Background Color Byte 3 Register */
+#define GR15   0x15    /* Foreground Color Byte 3 Register */
+/* the following are CL-GD5426/'28 specific blitter registers */
+#define GR20   0x20    /* BLT Width Low */
+#define GR21   0x21    /* BLT Width High */
+#define GR22   0x22    /* BLT Height Low */
+#define GR23   0x23    /* BLT Height High */
+#define GR24   0x24    /* BLT Destination Pitch Low */
+#define GR25   0x25    /* BLT Destination Pitch High */
+#define GR26   0x26    /* BLT Source Pitch Low */
+#define GR27   0x27    /* BLT Source Pitch High */
+#define GR28   0x28    /* BLT Destination Start Low */
+#define GR29   0x29    /* BLT Destination Start Mid */
+#define GR2A    0x2a   /* BLT Destination Start High */
+#define GR2C   0x2c    /* BLT Source Start Low */
+#define GR2D   0x2d    /* BLT Source Start Mid */
+#define GR2E   0x2e    /* BLT Source Start High */
+#define GR2F   0x2f    /* Picasso IV Blitter compat mode..? */
+#define GR30   0x30    /* BLT Mode */
+#define GR31   0x31    /* BLT Start/Status */
+#define GR32   0x32    /* BLT Raster Operation */
+#define GR33   0x33    /* another P4 "compat" register.. */
+#define GR34   0x34    /* Transparent Color Select Low */
+#define GR35   0x35    /* Transparent Color Select High */
+#define GR38   0x38    /* Source Transparent Color Mask Low */
+#define GR39   0x39    /* Source Transparent Color Mask High */
+
+/*** Attribute Controller Registers ***/
+#define ARX    0x3c0   /* Attribute Controller Index */
+#define AR0     0x0    /* Attribute Controller Palette Register 0 */
+#define AR1     0x1    /* Attribute Controller Palette Register 1 */
+#define AR2     0x2    /* Attribute Controller Palette Register 2 */
+#define AR3     0x3    /* Attribute Controller Palette Register 3 */
+#define AR4     0x4    /* Attribute Controller Palette Register 4 */
+#define AR5     0x5    /* Attribute Controller Palette Register 5 */
+#define AR6     0x6    /* Attribute Controller Palette Register 6 */
+#define AR7     0x7    /* Attribute Controller Palette Register 7 */
+#define AR8     0x8    /* Attribute Controller Palette Register 8 */
+#define AR9     0x9    /* Attribute Controller Palette Register 9 */
+#define ARA     0xa    /* Attribute Controller Palette Register 10 */
+#define ARB     0xb    /* Attribute Controller Palette Register 11 */
+#define ARC     0xc    /* Attribute Controller Palette Register 12 */
+#define ARD     0xd    /* Attribute Controller Palette Register 13 */
+#define ARE     0xe    /* Attribute Controller Palette Register 14 */
+#define ARF     0xf    /* Attribute Controller Palette Register 15 */
+#define AR10   0x10    /* Attribute Controller Mode Register */
+#define AR11   0x11    /* Overscan (Border) Color Register */
+#define AR12   0x12    /* Color Plane Enable Register */
+#define AR13   0x13    /* Pixel Panning Register */
+#define AR14   0x14    /* Color Select Register */
+#define AR33   0x33    /* The "real" Pixel Panning register (?) */
+#define AR34   0x34    /* *TEST* */
+
+/*** Extension Registers ***/
+#define HDR    0x3c6   /* Hidden DAC Register (Not CL-GD5420) */
+
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
new file mode 100644 (file)
index 0000000..466bf52
--- /dev/null
@@ -0,0 +1,997 @@
+/*
+ *  controlfb.c -- frame buffer device for the PowerMac 'control' display
+ *
+ *  Created 12 July 1998 by Dan Jacobowitz <dan@debian.org>
+ *  Copyright (C) 1998 Dan Jacobowitz
+ *
+ *  Frame buffer structure from:
+ *    drivers/video/chipsfb.c -- frame buffer device for
+ *    Chips & Technologies 65550 chip.
+ *
+ *    Copyright (C) 1998 Paul Mackerras
+ *
+ *    This file is derived from the Powermac "chips" driver:
+ *    Copyright (C) 1997 Fabio Riccardi.
+ *    And from the frame buffer device for Open Firmware-initialized devices:
+ *    Copyright (C) 1997 Geert Uytterhoeven.
+ *
+ *  Hardware information from:
+ *    control.c: Console support for PowerMac "control" display adaptor.
+ *    Copyright (C) 1996 Paul Mackerras
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/selection.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/nvram.h>
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#include <asm/vc_ioctl.h>
+#endif
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/adb.h>
+#include <asm/cuda.h>
+
+#include "fbcon.h"
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb16.h"
+#include "fbcon-cfb32.h"
+
+#include "macmodes.h"
+#include "controlfb.h"
+
+static int currcon = 0;
+static int switching = 0;
+
+struct fb_par_control {
+       int     vmode, cmode;
+       int     xres, yres;
+       int     vxres, vyres;
+       int     xoffset, yoffset;
+};
+
+struct fb_info_control {
+       struct fb_info                  info;
+       struct fb_fix_screeninfo        fix;
+       struct fb_var_screeninfo        var;
+       struct display                  disp;
+       struct fb_par_control           par;
+       struct {
+               __u8 red, green, blue;
+       }                       palette[256];
+       
+       struct cmap_regs        *cmap_regs;
+       unsigned long           cmap_regs_phys;
+       
+       struct control_regs     *control_regs;
+       unsigned long           control_regs_phys;
+       
+       __u8                    *frame_buffer;
+       unsigned long           frame_buffer_phys;
+       
+       int                     sense, control_use_bank2;
+       unsigned long           total_vram;
+};
+
+/*
+ * Exported functions
+ */
+void control_init(void);
+void control_of_init(struct device_node *dp);
+
+static int control_open(struct fb_info *info, int user);
+static int control_release(struct fb_info *info, int user);
+static int control_get_fix(struct fb_fix_screeninfo *fix, int con,
+                        struct fb_info *info);
+static int control_get_var(struct fb_var_screeninfo *var, int con,
+                        struct fb_info *info);
+static int control_set_var(struct fb_var_screeninfo *var, int con,
+                        struct fb_info *info);
+static int control_pan_display(struct fb_var_screeninfo *var, int con,
+                            struct fb_info *info);
+static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+                         struct fb_info *info);
+static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+                         struct fb_info *info);
+static int control_ioctl(struct inode *inode, struct file *file, u_int cmd,
+                      u_long arg, int con, struct fb_info *info);
+
+static int read_control_sense(struct fb_info_control *p);
+static inline int control_vram_reqd(int video_mode, int color_mode);
+static void set_control_clock(unsigned char *params);
+static void control_set_hardware(struct fb_info_control *p);
+static void control_par_to_all(struct fb_info_control *p, int init);
+static inline void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var);
+static int control_var_to_par(struct fb_var_screeninfo *var,
+       struct fb_par_control *par, const struct fb_info *fb_info);
+
+static void control_init_info(struct fb_info *info, struct fb_info_control *p);
+static void control_par_to_display(struct fb_par_control *par,
+  struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_control *p);
+static void control_init_display(struct display *disp);
+static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix,
+       struct fb_info_control *p);
+static void control_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_control *p);
+
+static struct fb_ops controlfb_ops = {
+       control_open,
+       control_release,
+       control_get_fix,
+       control_get_var,
+       control_set_var,
+       control_get_cmap,
+       control_set_cmap,
+       control_pan_display,
+       control_ioctl
+};
+
+static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green,
+                            u_int *blue, u_int *transp, struct fb_info *info);
+static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                            u_int transp, struct fb_info *info);
+static void do_install_cmap(int con, struct fb_info *info);
+
+
+__openfirmware
+
+
+static int control_open(struct fb_info *info, int user)
+{
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+static int control_release(struct fb_info *info, int user)
+{
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+static int control_get_fix(struct fb_fix_screeninfo *fix, int con,
+                        struct fb_info *info)
+{
+       struct fb_info_control *cp = (struct fb_info_control *) info;
+
+       *fix = cp->fix;
+       return 0;
+}
+
+static int control_get_var(struct fb_var_screeninfo *var, int con,
+                        struct fb_info *info)
+{
+       struct fb_info_control *cp = (struct fb_info_control *) info;
+
+       *var = cp->var;
+       return 0;
+}
+
+/* Sets everything according to var */
+static int control_set_var(struct fb_var_screeninfo *var, int con,
+                        struct fb_info *info)
+{
+       struct fb_info_control *p = (struct fb_info_control *) info;
+       struct display *disp;
+       struct fb_par_control par;
+       int depthchange, err;
+
+       disp = (con >= 0) ? &fb_display[con] : &p->disp;
+       if((err = control_var_to_par(var, &par, info))) {
+               printk (KERN_ERR "Error in control_set_var, calling control_var_to_par: %d.\n", err);
+               return err;
+       }
+       
+       if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) {
+               printk("Not activating, in control_set_var.\n");
+               control_par_to_var(&par, var);
+               return 0;
+       }
+/* I know, we want to use fb_display[con], but grab certain info from p->var instead. */
+#define DIRTY(x) (p->var.x != var->x)
+       depthchange = DIRTY(bits_per_pixel);
+       if(!DIRTY(xres) && !DIRTY(yres) && !DIRTY(xres_virtual) &&
+          !DIRTY(yres_virtual) && !DIRTY(bits_per_pixel)) {
+               control_par_to_var(&par, var);
+               p->var = disp->var = *var;
+               return 0;
+       }
+printk("Original bpp is %d, new bpp %d.\n", p->var.bits_per_pixel, var->bits_per_pixel);
+       /* OK, we're getting here at the right times... */
+       p->par = par;
+       control_par_to_var(&par, var);
+       p->var = *var;
+       control_par_to_fix(&par, &p->fix, p);
+       control_par_to_display(&par, disp, &p->fix, p);
+       p->disp = *disp;
+       
+       if(info->changevar && !switching)       /* Don't want to do this if just switching consoles. */
+               (*info->changevar)(con);
+       if(con == currcon)
+               control_set_hardware(p);
+       if(depthchange)
+               if((err = fb_alloc_cmap(&disp->cmap, 0, 0)))
+                       return err;
+       if(depthchange || switching)
+               do_install_cmap(con, info);
+       return 0;
+}
+
+static int control_pan_display(struct fb_var_screeninfo *var, int con,
+                            struct fb_info *info)
+{
+       if (var->xoffset != 0 || var->yoffset != 0)
+               return -EINVAL;
+       return 0;
+}
+
+static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+                         struct fb_info *info)
+{
+       if (con == currcon)             /* current console? */
+               return fb_get_cmap(cmap, &fb_display[con].var, kspc,
+                                  controlfb_getcolreg, info);
+       if (fb_display[con].cmap.len)   /* non default colormap? */
+               fb_copy_cmap(&fb_display[con].cmap, cmap, kspc? 0: 2);
+       else {
+               int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+               fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+       }
+       return 0;
+}
+
+static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+                        struct fb_info *info)
+{
+       struct display *disp = &fb_display[con];
+       int err;
+
+       if (disp->cmap.len == 0) {
+               int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+               err = fb_alloc_cmap(&disp->cmap, size, 0);
+               if (err)
+                       return err;
+       }
+
+       if (con == currcon)
+               return fb_set_cmap(cmap, &disp->var, kspc, controlfb_setcolreg,
+                                  info);
+       fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
+       return 0;
+}
+
+static int control_ioctl(struct inode *inode, struct file *file, u_int cmd,
+                      u_long arg, int con, struct fb_info *info)
+{
+       return -EINVAL;
+}
+
+static int controlfb_switch(int con, struct fb_info *info)
+{
+       if (fb_display[currcon].cmap.len)
+               fb_get_cmap(&fb_display[currcon].cmap,
+                           &fb_display[currcon].var, 1, controlfb_getcolreg,
+                           info);
+       currcon = con;
+#if 0
+       control_var_to_par(&fb_display[currcon].var, &par, info);
+       control_set_par(&par, info); /*STOPPEDHERE - did i define that? */
+       do_install_cmap(con, info);
+#else
+       /* I see no reason not to do this.  Minus info->changevar(). */
+       /* DOH.  This makes control_set_var compare, you guessed it, */
+       /* fb_display[con].var (first param), and fb_display[con].var! */
+       /* Perhaps I just fixed that... */
+       switching = 1;
+       control_set_var(&fb_display[con].var, con, info);
+       switching = 0;
+#endif
+       return 0;
+}
+
+static int controlfb_updatevar(int con, struct fb_info *info)
+{
+       return 0;
+}
+
+static void controlfb_blank(int blank_mode, struct fb_info *info)
+{
+/*
+ *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
+ *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
+ *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
+ *  to e.g. a video mode which doesn't support it. Implements VESA suspend
+ *  and powerdown modes on hardware that supports disabling hsync/vsync:
+ *    blank_mode == 2: suspend vsync
+ *    blank_mode == 3: suspend hsync
+ *    blank_mode == 4: powerdown
+ */
+/* [danj] I think there's something fishy about those constants... */
+       struct fb_info_control *p = (struct fb_info_control *) info;
+       int     ctrl;
+
+       ctrl = ld_le32(&p->control_regs->ctrl.r) | 0x33;
+       if (blank_mode)
+               --blank_mode;
+       if (blank_mode & VESA_VSYNC_SUSPEND)
+               ctrl &= ~3;
+       if (blank_mode & VESA_HSYNC_SUSPEND)
+               ctrl &= ~0x30;
+       out_le32(&p->control_regs->ctrl.r, ctrl);
+
+/* TODO: Figure out how the heck to powerdown this thing! */
+
+    return;
+}
+
+static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green,
+                            u_int *blue, u_int *transp, struct fb_info *info)
+{
+       struct fb_info_control *p = (struct fb_info_control *) info;
+
+       if (regno > 255)
+               return 1;
+       *red = p->palette[regno].red;
+       *green = p->palette[regno].green;
+       *blue = p->palette[regno].blue;
+       return 0;
+}
+
+static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                            u_int transp, struct fb_info *info)
+{
+       struct fb_info_control *p = (struct fb_info_control *) info;
+
+       if (regno > 255 || regno < 0)
+               return 1;
+       p->palette[regno].red = red;
+       p->palette[regno].green = green;
+       p->palette[regno].blue = blue;
+
+       out_8(&p->cmap_regs->addr, regno);      /* tell clut what addr to fill  */
+       out_8(&p->cmap_regs->lut, red);         /* send one color channel at    */
+       out_8(&p->cmap_regs->lut, green);       /* a time...                    */
+       out_8(&p->cmap_regs->lut, blue);
+
+       if(regno < 16) {
+#if 0
+#ifdef FBCON_HAS_CFB16
+               fbcon_cfb16_cmap[regno] = (red << 10) | (green << 5) | blue;
+#endif
+#ifdef FBCON_HAS_CFB32
+               fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue;
+               /* I think. */
+#endif
+#else
+#ifdef FBCON_HAS_CFB16
+               fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno;
+#endif
+#ifdef FBCON_HAS_CFB32
+               fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) | (regno << 8) | regno;
+               /* I think. */
+#endif
+#endif
+       }
+       return 0;
+}
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+       if (con != currcon)
+               return;
+       if (fb_display[con].cmap.len)
+               fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1,
+                           controlfb_setcolreg, info);
+       else {
+               int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+               fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1,
+                           controlfb_setcolreg, info);
+       }
+}
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+extern struct vc_mode display_info;
+extern struct fb_info *console_fb_info;
+#if 0
+extern int (*console_setmode_ptr)(struct vc_mode *, int);
+extern int (*console_set_cmap_ptr)(struct fb_cmap *, int, int,
+                                  struct fb_info *);
+int console_setmode(struct vc_mode *, int);
+#endif
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+
+static inline int control_vram_reqd(int video_mode, int color_mode)
+{
+       return control_reg_init[video_mode-1]->vres
+               * control_reg_init[video_mode-1]->pitch[color_mode];
+}
+
+static void set_control_clock(unsigned char *params)
+{
+       struct adb_request req;
+       int i;
+
+       for (i = 0; i < 3; ++i) {
+               cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+                            0x50, i + 1, params[i]);
+               while (!req.complete)
+                       cuda_poll();
+       }
+}
+
+
+__initfunc(static void init_control(struct fb_info_control *p))
+{
+       struct fb_par_control *par = &p->par;
+
+       p->sense = read_control_sense(p);
+       printk("Monitor sense value = 0x%x, ", p->sense);
+       /* Try to pick a video mode out of NVRAM if we have one. */
+       par->vmode = nvram_read_byte(NV_VMODE);
+       if(par->vmode <= 0 || par->vmode > VMODE_MAX || !control_reg_init[par->vmode - 1])
+               par->vmode = VMODE_CHOOSE;
+       if(par->vmode == VMODE_CHOOSE)
+               par->vmode = mac_map_monitor_sense(p->sense);
+       if(!control_reg_init[par->vmode - 1])
+               par->vmode = VMODE_640_480_60;
+
+       par->cmode = nvram_read_byte(NV_CMODE);
+       if(par->cmode < CMODE_8 || par->cmode > CMODE_32)
+               par->cmode = CMODE_8;
+       /*
+        * Reduce the pixel size if we don't have enough VRAM.
+        */
+       while(par->cmode > CMODE_8 && control_vram_reqd(par->vmode, par->cmode) > p->total_vram)
+               par->cmode--;
+       
+       printk("using video mode %d and color mode %d.\n", par->vmode, par->cmode);
+       
+       par->vxres = par->xres = control_reg_init[par->vmode - 1]->hres;
+       par->vyres = par->yres = control_reg_init[par->vmode - 1]->vres;
+       par->xoffset = par->yoffset = 0;
+       
+       control_par_to_all(p, 1);
+       
+       if (register_framebuffer(&p->info) < 0) {
+               kfree(p);
+               return;
+       }
+       control_set_hardware(p);
+       
+       printk("fb%d: control display adapter\n", GET_FB_IDX(p->info.node));    
+}
+
+/* Now how about actually saying, Make it so! */
+/* Some things in here probably don't need to be done each time. */
+static void control_set_hardware(struct fb_info_control *p)
+{
+       struct control_regvals  *init;
+       struct preg             *rp;
+       int                     flags, ctrl, i;
+       int                     vmode, cmode;
+       
+       vmode = p->par.vmode;
+       cmode = p->par.cmode;
+       
+       init = control_reg_init[vmode - 1];
+       
+       if (control_vram_reqd(vmode, cmode) > 0x200000)
+               flags = 0x51;
+       else if (p->control_use_bank2)
+               flags = 0x39;
+       else
+               flags = 0x31;
+       if (vmode >= VMODE_1280_960_75 && cmode >= CMODE_16)
+               ctrl = 0x7f;
+       else
+               ctrl = 0x3b;
+
+       /* Initialize display timing registers */
+       out_le32(&p->control_regs->ctrl.r, 0x43b);
+       
+       set_control_clock(init->clock_params);
+       
+       p->cmap_regs->addr = 0x20; p->cmap_regs->d2 = init->radacal_ctrl[cmode];
+       p->cmap_regs->addr = 0x21; p->cmap_regs->d2 = p->control_use_bank2 ? 0: 1;
+       p->cmap_regs->addr = 0x10; p->cmap_regs->d2 = 0;
+       p->cmap_regs->addr = 0x11; p->cmap_regs->d2 = 0;
+
+       rp = &p->control_regs->vswin;
+       for (i = 0; i < 16; ++i, ++rp)
+               out_le32(&rp->r, init->regs[i]);
+       
+       out_le32(&p->control_regs->pitch.r, init->pitch[cmode]);
+       out_le32(&p->control_regs->mode.r, init->mode[cmode]);
+       out_le32(&p->control_regs->flags.r, flags);
+       out_le32(&p->control_regs->start_addr.r, 0);
+       out_le32(&p->control_regs->reg18.r, 0x1e5);
+       out_le32(&p->control_regs->reg19.r, 0);
+
+       for (i = 0; i < 16; ++i) {
+               controlfb_setcolreg(color_table[i], default_red[i], default_grn[i],
+                       default_blu[i], 0, (struct fb_info *)p);
+       }
+/* Does the above need to be here each time? -- danj */
+
+       /* Turn on display */
+       out_le32(&p->control_regs->ctrl.r, ctrl);
+       
+#ifdef CONFIG_FB_COMPAT_XPMAC
+       /* And let the world know the truth. */
+       if (!console_fb_info || console_fb_info == &p->info) {
+               display_info.height = p->var.yres;
+               display_info.width = p->var.xres;
+               display_info.depth = (cmode == CMODE_32) ? 32 :
+                       ((cmode == CMODE_16) ? 16 : 8);
+               display_info.pitch = p->fix.line_length;
+               display_info.mode = vmode;
+               strncpy(display_info.name, "control",
+                       sizeof(display_info.name));
+               display_info.fb_address = p->frame_buffer_phys
+                        + control_reg_init[vmode-1]->offset[cmode];
+               display_info.cmap_adr_address = p->cmap_regs_phys;
+               display_info.cmap_data_address = p->cmap_regs_phys + 0x30;
+               display_info.disp_reg_address = p->control_regs_phys;
+               console_fb_info = &p->info;
+       }
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+}
+
+__initfunc(void control_init(void))
+{
+#ifndef CONFIG_FB_OF
+       struct device_node *dp;
+
+       dp = find_devices("control");
+       if (dp != 0)
+               control_of_init(dp);
+#endif /* CONFIG_FB_OF */
+}
+
+__initfunc(void control_of_init(struct device_node *dp))
+{
+       struct fb_info_control  *p;
+       unsigned long           addr, size;
+       int                     i, bank1, bank2;
+       
+       if(dp->next != 0)
+               printk("Warning: only using first control display device.\n");
+               /* danj: I have a feeling this no longer applies - if we somehow *
+                * had two of them, they'd be two framebuffers, right?           */
+       if(dp->n_addrs != 2)
+               panic("expecting 2 address for control (got %d)", dp->n_addrs);
+       p = kmalloc(sizeof(*p), GFP_ATOMIC);
+       if (p == 0)
+               return;
+
+       /* Map in frame buffer and registers */
+       for (i = 0; i < dp->n_addrs; ++i) {
+               addr = dp->addrs[i].address;
+               size = dp->addrs[i].size;
+               if (size >= 0x800000) {
+                       /* use the big-endian aperture (??) */
+                       addr += 0x800000;
+                       /* map at most 8MB for the frame buffer */
+                       p->frame_buffer_phys = addr;
+                       p->frame_buffer = __ioremap(addr, 0x800000, _PAGE_WRITETHRU);
+               } else {
+                       p->control_regs_phys = addr;
+                       p->control_regs = ioremap(addr, size);
+               }
+       }
+       p->cmap_regs_phys = 0xf301b000;  /* XXX not in prom? */
+       p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000);
+
+       /* Work out which banks of VRAM we have installed. */
+       /* danj: I guess the card just ignores writes to nonexistant VRAM... */
+       p->frame_buffer[0] = 0x5a;
+       p->frame_buffer[1] = 0xc7;
+       bank1 = p->frame_buffer[0] == 0x5a && p->frame_buffer[1] == 0xc7;
+       p->frame_buffer[0x600000] = 0xa5;
+       p->frame_buffer[0x600001] = 0x38;
+       bank2 = p->frame_buffer[0x600000] == 0xa5 && p->frame_buffer[0x600001] == 0x38;
+       p->total_vram = (bank1 + bank2) * 0x200000;
+       /* If we don't have bank 1 installed, we hope we have bank 2 :-) */
+       p->control_use_bank2 = !bank1;
+       if (p->control_use_bank2)
+               p->frame_buffer += 0x600000;
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#if 0
+       console_set_cmap_ptr = control_set_cmap;
+       console_setmode_ptr = control_console_setmode;
+#endif
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+
+       init_control(p);
+}
+
+/*
+ * Get the monitor sense value.
+ * Note that this can be called before calibrate_delay,
+ * so we can't use udelay.
+ *
+ * Hmm - looking at platinum, should we be calling eieio() here?
+ */
+static int read_control_sense(struct fb_info_control *p)
+{
+       int sense;
+
+       out_le32(&p->control_regs->mon_sense.r, 7);     /* drive all lines high */
+       __delay(200);
+       out_le32(&p->control_regs->mon_sense.r, 077);   /* turn off drivers */
+       __delay(2000);
+       sense = (in_le32(&p->control_regs->mon_sense.r) & 0x1c0) << 2;
+
+       /* drive each sense line low in turn and collect the other 2 */
+       out_le32(&p->control_regs->mon_sense.r, 033);   /* drive A low */
+       __delay(2000);
+       sense |= (in_le32(&p->control_regs->mon_sense.r) & 0xc0) >> 2;
+       out_le32(&p->control_regs->mon_sense.r, 055);   /* drive B low */
+       __delay(2000);
+       sense |= ((in_le32(&p->control_regs->mon_sense.r) & 0x100) >> 5)
+               | ((in_le32(&p->control_regs->mon_sense.r) & 0x40) >> 4);
+       out_le32(&p->control_regs->mon_sense.r, 066);   /* drive C low */
+       __delay(2000);
+       sense |= (in_le32(&p->control_regs->mon_sense.r) & 0x180) >> 7;
+
+       out_le32(&p->control_regs->mon_sense.r, 077);   /* turn off drivers */
+       
+       return sense;
+}
+
+#if 1
+/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
+static int control_var_to_par(struct fb_var_screeninfo *var, 
+       struct fb_par_control *par, const struct fb_info *fb_info)
+{
+       int xres = var->xres;
+       int yres = var->yres;
+       int bpp = var->bits_per_pixel;
+       
+       struct control_regvals *init;
+       struct fb_info_control *p = (struct fb_info_control *) fb_info;
+
+    /*
+     *  Get the video params out of 'var'. If a value doesn't fit, round it up,
+     *  if it's too big, return -EINVAL.
+     *
+     *  Suggestion: Round up in the following order: bits_per_pixel, xres,
+     *  yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
+     *  bitfields, horizontal timing, vertical timing.
+     */
+       /* swiped by jonh from atyfb.c */
+       if (xres <= 512 && yres <= 384)
+               par->vmode = VMODE_512_384_60;           /* 512x384, 60Hz */
+       else if (xres <= 640 && yres <= 480)
+               par->vmode = VMODE_640_480_67;          /* 640x480, 67Hz */
+       else if (xres <= 640 && yres <= 870)
+               par->vmode = VMODE_640_870_75P;         /* 640x870, 75Hz (portrait) */
+       else if (xres <= 768 && yres <= 576)
+               par->vmode = VMODE_768_576_50I;         /* 768x576, 50Hz (PAL full frame) */
+       else if (xres <= 800 && yres <= 600)
+               par->vmode = VMODE_800_600_75;          /* 800x600, 75Hz */
+       else if (xres <= 832 && yres <= 624)
+               par->vmode = VMODE_832_624_75;          /* 832x624, 75Hz */
+       else if (xres <= 1024 && yres <= 768)
+               par->vmode = VMODE_1024_768_75;         /* 1024x768, 75Hz */
+       else if (xres <= 1152 && yres <= 870)
+               par->vmode = VMODE_1152_870_75;         /* 1152x870, 75Hz */
+       else if (xres <= 1280 && yres <= 960)
+               par->vmode = VMODE_1280_960_75;         /* 1280x960, 75Hz */
+       else if (xres <= 1280 && yres <= 1024)
+               par->vmode = VMODE_1280_1024_75;        /* 1280x1024, 75Hz */
+       else
+               return -EINVAL;
+
+       xres = control_reg_init[par->vmode-1]->hres;
+       yres = control_reg_init[par->vmode-1]->vres;
+
+/*
+       if (var->xres_virtual <= xres)
+               par->vxres = xres;
+       else
+               par->vxres = (var->xres_virtual+7) & ~7;
+       if (var->yres_virtual <= yres)
+               par->vyres = yres;
+       else
+               par->vyres = var->yres_virtual;
+
+       par->xoffset = (var->xoffset+7) & ~7;
+       par->yoffset = var->yoffset;
+       if (par->xoffset+xres > par->vxres || par->yoffset+yres > par->vyres)
+               return -EINVAL;
+*/
+
+       /* I'm too chicken to think about virtual       */
+       /* resolutions just yet. Bok bok.                       */
+       
+       /* And I'm too chicken to even figure out what they are.  Awk awk. [danj] */
+       if (var->xres_virtual > xres || var->yres_virtual > yres
+               || var->xoffset != 0 || var->yoffset != 0) {
+               return -EINVAL;
+       }
+
+       par->xres = xres;
+       par->yres = yres;
+       par->vxres = xres;
+       par->vyres = yres;
+       par->xoffset = 0;
+       par->yoffset = 0;
+
+       if (bpp <= 8)
+               par->cmode = CMODE_8;
+       else if (bpp <= 16)
+               par->cmode = CMODE_16;
+       else if (bpp <= 32)
+               par->cmode = CMODE_32;
+       else
+               return -EINVAL;
+
+       if (control_vram_reqd(par->vmode, par->cmode) > p->total_vram)
+               return -EINVAL;
+
+       /* Check if we know about the wanted video mode */
+       init = control_reg_init[par->vmode-1];
+       if (init == NULL) {
+               /* I'm not sure if control has any specific requirements --     */
+               /* if we have a regvals struct, we're good to go?               */
+               return -EINVAL;
+       }
+
+       return 0;
+}
+#else
+/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
+static int control_var_to_par(struct fb_var_screeninfo *var, 
+       struct fb_par_control *par, const struct fb_info *fb_info)
+{
+       struct fb_info_control *p = (struct fb_info_control *) fb_info;
+       
+       if(mac_var_to_vmode(var, &par->vmode, &par->cmode) != 0)
+               return -EINVAL;
+       par->xres = par->vxres = vmode_attrs[par->vmode - 1].hres;
+       par->yres = par->vyres = vmode_attrs[par->vmode - 1].vres;
+       par->xoffset = par->yoffset = 0;
+       
+       if (control_vram_reqd(par->vmode, par->cmode) > p->total_vram)
+               return -EINVAL;
+
+       /* Check if we know about the wanted video mode */
+       if(!control_reg_init[par->vmode-1]) {
+               /* I'm not sure if control has any specific requirements --     */
+               /* if we have a regvals struct, we're good to go?               */
+               return -EINVAL;
+       }
+       return 0;
+}
+#endif
+
+#if 1
+static void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var)
+{
+       memset(var, 0, sizeof(*var));
+       var->xres = control_reg_init[par->vmode - 1]->hres;
+       var->yres = control_reg_init[par->vmode - 1]->vres;
+       var->xres_virtual = var->xres;
+       var->yres_virtual = var->yres;  /* For now. */
+       var->xoffset = par->xoffset;
+       var->yoffset = par->yoffset;
+       var->grayscale = 0;
+       
+       if(par->cmode != CMODE_8 && par->cmode != CMODE_16 && par->cmode != CMODE_32) {
+               printk(KERN_ERR "Bad color mode in control_par_to_var()!\n");
+               par->cmode = CMODE_8;
+       }
+       switch(par->cmode) {
+       case CMODE_8:
+               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;
+               break;
+       case CMODE_16:  /* RGB 555 */
+               var->bits_per_pixel = 16;
+               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 = 0;
+               var->transp.length = 0;
+               break;
+       case CMODE_32:  /* RGB 888 */
+               var->bits_per_pixel = 32;
+               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;
+               break;
+       }
+       var->red.msb_right = 0;
+       var->green.msb_right = 0;
+       var->blue.msb_right = 0;
+       var->transp.msb_right = 0;
+       var->nonstd = 0;
+       var->activate = 0;
+       var->height = -1;
+       var->width = -1;
+       var->vmode = FB_VMODE_NONINTERLACED;
+
+       /* these are total guesses, copied right out of atyfb.c */
+       var->left_margin = var->right_margin = 64;
+       var->upper_margin = var->lower_margin = 32;
+       var->hsync_len = /*64*/8;
+       var->vsync_len = /*2*/8;
+       var->sync = 0;
+
+#if 0
+/* jonh's pixclocks...*/
+       /* no long long support in the kernel :-( */
+       /* this splittig trick will work if xres > 232 */
+       var->pixclock = 1000000000/
+       (var->left_margin+var->xres+var->right_margin+var->hsync_len);
+       var->pixclock *= 1000;
+       var->pixclock /= vmode_attrs[par->vmode-1].vfreq*
+        (var->upper_margin+var->yres+var->lower_margin+var->vsync_len);
+#else
+/* danj's */
+       /* 10^12 * clock_params[0] / (3906400 * clock_params[1] * 2^clock_params[2]) */
+       /* (10^12 * clock_params[0] / (3906400 * clock_params[1])) >> clock_params[2] */
+       /* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */
+       var->pixclock = 255990 * control_reg_init[par->vmode-1]->clock_params[0];
+       var->pixclock /= control_reg_init[par->vmode-1]->clock_params[1];
+       var->pixclock >>= control_reg_init[par->vmode-1]->clock_params[2];
+#endif
+}
+#else
+static inline void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var)
+{
+       mac_vmode_to_var(par->vmode, par->cmode, var);
+}
+#endif
+
+static void control_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_control *p)
+{
+       memset(fix, 0, sizeof(*fix));
+       strcpy(fix->id, "control");
+       fix->mmio_start = (char *)p->control_regs_phys;
+       fix->mmio_len = sizeof(struct control_regs);
+       fix->type = FB_TYPE_PACKED_PIXELS;
+       
+       /*
+               fix->type_aux = 0;
+               fix->ywrapstep = 0;
+               fix->ypanstep = 0;
+               fix->xpanstep = 0;
+       */
+}
+
+/* Fix must already be inited ^^^^^^^ */
+static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix,
+       struct fb_info_control *p)
+{
+       fix->smem_start = (void *)(p->frame_buffer_phys
+               + control_reg_init[par->vmode-1]->offset[par->cmode]);
+       p->fix.smem_len = control_vram_reqd(par->vmode, par->cmode);
+               /* Hmm, jonh used total_vram here. */
+       p->fix.visual = (par->cmode == CMODE_8) ?
+               FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+       p->fix.line_length = par->vxres << par->cmode;
+               /* ywrapstep, xpanstep, ypanstep */
+}
+
+static void control_init_display(struct display *disp)
+{
+       memset(disp, 0, sizeof(*disp));
+       disp->type = /* fix->type */ FB_TYPE_PACKED_PIXELS;
+       disp->can_soft_blank = 1;
+       disp->scrollmode = SCROLL_YREDRAW;
+#if 0
+               disp->type_aux = fix->type_aux;
+               disp->cmap.red = NULL;  /* ??? danj */
+               disp->cmap.green = NULL;
+               disp->cmap.blue = NULL;
+               disp->cmap.transp = NULL;
+                       /* Yeah, I realize I just set 0 = 0. */
+#endif
+}
+
+static void control_par_to_display(struct fb_par_control *par,
+  struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_control *p)
+{
+       disp->var = p->var;
+       disp->screen_base = (char *) p->frame_buffer
+                + control_reg_init[par->vmode-1]->offset[par->cmode];
+       disp->visual = fix->visual;
+       disp->line_length = fix->line_length;
+
+if(disp->scrollmode != SCROLL_YREDRAW) {
+       printk(KERN_ERR "Scroll mode not YREDRAW in control_par_to_display!!\n");
+       disp->scrollmode = SCROLL_YREDRAW;
+}
+       disp->dispsw = (par->cmode == CMODE_32) ? &fbcon_cfb32 :
+               ((par->cmode == CMODE_16) ? &fbcon_cfb16 : &fbcon_cfb8);
+}
+
+static void control_init_info(struct fb_info *info, struct fb_info_control *p)
+{
+       strcpy(info->modename, p->fix.id);
+       info->node = -1;        /* ??? danj */
+       info->fbops = &controlfb_ops;
+       info->disp = &p->disp;
+       info->fontname[0] = 0;
+       info->changevar = NULL;
+       info->switch_con = &controlfb_switch;
+       info->updatevar = &controlfb_updatevar;
+       info->blank = &controlfb_blank;
+}
+
+/* danj: Oh, I HOPE I didn't miss anything major in here... */
+static void control_par_to_all(struct fb_info_control *p, int init)
+{
+       if(init) {
+               control_init_fix(&p->fix, p);
+       }
+       control_par_to_fix(&p->par, &p->fix, p);
+
+       control_par_to_var(&p->par, &p->var);
+
+       if(init) {
+               control_init_display(&p->disp);
+       }
+       control_par_to_display(&p->par, &p->disp, &p->fix, p);
+       
+       if(init) {
+               control_init_info(&p->info, p);
+       }
+}
+
+#if 0
+__initfunc(void controlfb_setup(char *options, int *ints))
+{
+    /* Parse user speficied options (`video=controlfb:') */
+       FUNCID;
+}
+
+static int controlfb_pan_display(struct fb_var_screeninfo *var,
+                          struct controlfb_par *par,
+                          const struct fb_info *fb_info)
+{
+    /*
+     *  Pan (or wrap, depending on the `vmode' field) the display using the
+     *  `xoffset' and `yoffset' fields of the `var' structure.
+     *  If the values don't fit, return -EINVAL.
+     */
+
+       FUNCID;
+
+    return 0;
+}
+
+#endif
diff --git a/drivers/video/controlfb.h b/drivers/video/controlfb.h
new file mode 100644 (file)
index 0000000..2e138b7
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * controlfb_hw.h: Constants of all sorts for controlfb
+ *
+ * Copyright (C) 1998 Daniel Jacobowitz <dan@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Based on an awful lot of code, including:
+ *
+ * control.c: Console support for PowerMac "control" display adaptor.
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * The so far unpublished platinumfb.c
+ * Copyright (C) 1998 Jon Howell
+ */
+
+/*
+ * Structure of the registers for the RADACAL colormap device.
+ */
+struct cmap_regs {
+       unsigned char addr;
+       char pad1[15];
+       unsigned char d1;
+       char pad2[15];
+       unsigned char d2;
+       char pad3[15];
+       unsigned char lut;
+       char pad4[15];
+};
+
+/*
+ * Structure of the registers for the "control" display adaptor.
+ */
+#define PAD(x) char x[12]
+
+struct preg {                  /* padded register */
+       unsigned r;
+       char pad[12];
+};
+
+struct control_regs {
+       struct preg vcount;     /* vertical counter */
+       /* Vertical parameters are in units of 1/2 scan line */
+       struct preg vswin;      /* between vsblank and vssync */
+       struct preg vsblank;    /* vert start blank */
+       struct preg veblank;    /* vert end blank (display start) */
+       struct preg vewin;      /* between vesync and veblank */
+       struct preg vesync;     /* vert end sync */
+       struct preg vssync;     /* vert start sync */
+       struct preg vperiod;    /* vert period */
+       struct preg reg8;
+       /* Horizontal params are in units of 2 pixels */
+       struct preg hperiod;    /* horiz period - 2 */
+       struct preg hsblank;    /* horiz start blank */
+       struct preg heblank;    /* horiz end blank */
+       struct preg hesync;     /* horiz end sync */
+       struct preg hssync;     /* horiz start sync */
+       struct preg rege;
+       struct preg regf;
+       struct preg reg10;
+       struct preg reg11;
+       struct preg ctrl;       /* display control */
+       struct preg start_addr; /* start address: 5 lsbs zero */
+       struct preg pitch;      /* addrs diff between scan lines */
+       struct preg mon_sense;  /* monitor sense bits */
+       struct preg flags;
+       struct preg mode;
+       struct preg reg18;
+       struct preg reg19;
+       struct preg res[6];
+};
+
+/*
+ * Register initialization tables for the control display.
+ *
+ * Dot clock rate is
+ * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0].
+ *
+ * The values for vertical frequency (V) in the comments below
+ * are the values measured using the modes under MacOS.
+ */
+struct control_regvals {
+       int     pitch[3];               /* bytes/line, indexed by color_mode */
+       int     offset[3];              /* first pixel address */
+       unsigned regs[16];              /* for vswin .. reg10 */
+       unsigned char mode[3];          /* indexed by color_mode */
+       unsigned char radacal_ctrl[3];
+       unsigned char clock_params[3];
+       int     hres;
+       int     vres;
+};
+
+/* Register values for 1280x1024, 75Hz mode (20) */
+static struct control_regvals control_reg_init_20 = {
+       { 1280, 2560, 0 },
+       { 0x10, 0x20, 0 },
+       { 2129, 2128, 80, 42, 4, 2130, 2132, 88,
+         420, 411, 91, 35, 421, 18, 211, 386, },
+       { 1, 1, 1},
+       { 0x50, 0x64, 0x64 },
+       { 13, 56, 3 },  /* pixel clock = 134.61MHz for V=74.81Hz */
+       1280, 1024
+};
+
+/* Register values for 1280x960, 75Hz mode (19) */
+static struct control_regvals control_reg_init_19 = {
+       { 1280, 2560, 0 },
+       { 0x10, 0x20, 0 },
+       { 1997, 1996, 76, 40, 4, 1998, 2000, 86,
+         418, 409, 89, 35, 419, 18, 210, 384, },
+       { 1, 1, 1 },
+       { 0x50, 0x64, 0x64 },
+       { 31, 125, 3 }, /* pixel clock = 126.01MHz for V=75.01 Hz */
+       1280, 960
+};
+
+/* Register values for 1152x870, 75Hz mode (18) */
+static struct control_regvals control_reg_init_18 = {
+       { 1152, 2304, 4608 },
+       { 0x10, 0x28, 0x50 },
+       { 1825, 1822, 82, 43, 4, 1828, 1830, 120,
+         726, 705, 129, 63, 727, 32, 364, 664 },
+       { 2, 1, 1 },
+       { 0x10, 0x14, 0x28 },
+       { 19, 61, 3 },  /* pixel clock = 100.33MHz for V=75.31Hz */
+       1152, 870
+};
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct control_regvals control_reg_init_17 = {
+       { 1024, 2048, 4096 },
+       { 0x10, 0x28, 0x50 },
+       { 1603, 1600, 64, 34, 4, 1606, 1608, 120,
+         662, 641, 129, 47, 663, 24, 332, 616 },
+       { 2, 1, 1 },
+       { 0x10, 0x14, 0x28 },
+       { 11, 28, 3 },  /* pixel clock = 79.55MHz for V=74.50Hz */
+       1024, 768
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct control_regvals control_reg_init_15 = {
+       { 1024, 2048, 4096 },
+       { 0x10, 0x28, 0x50 },
+       { 1607, 1604, 68, 39, 10, 1610, 1612, 132,
+         670, 653, 141, 67, 671, 34, 336, 604, },
+       { 2, 1, 1 },
+       { 0x10, 0x14, 0x28 },
+       { 12, 30, 3 },  /* pixel clock = 78.12MHz for V=72.12Hz */
+       1024, 768
+};
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct control_regvals control_reg_init_14 = {
+       { 1024, 2048, 4096 },
+       { 0x10, 0x28, 0x50 },
+       { 1607, 1604, 68, 39, 10, 1610, 1612, 132,
+         670, 653, 141, 67, 671, 34, 336, 604, },
+       { 2, 1, 1 },
+       { 0x10, 0x14, 0x28 },
+       { 15, 31, 3 },  /* pixel clock = 64.58MHz for V=59.62Hz */
+       1024, 768
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct control_regvals control_reg_init_13 = {
+       { 832, 1664, 3328 },
+       { 0x10, 0x28, 0x50 },
+       { 1331, 1330, 82, 43, 4, 1332, 1334, 128,
+         574, 553, 137, 31, 575, 16, 288, 544 },
+       { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+       { 23, 42, 3 },  /* pixel clock = 57.07MHz for V=74.27Hz */
+       832, 624
+};
+
+/* Register values for 800x600, 75Hz mode (12) */
+static struct control_regvals control_reg_init_12 = {
+       { 800, 1600, 3200 },
+       { 0x10, 0x28, 0x50 },
+       { 1247, 1246, 46, 25, 4, 1248, 1250, 104,
+         526, 513, 113, 39, 527, 20, 264, 488, },
+       { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+       { 7, 11, 3 },   /* pixel clock = 49.11MHz for V=74.40Hz */
+       800, 600
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct control_regvals control_reg_init_11 = {
+       { 800, 1600, 3200 },
+       { 0x10, 0x28, 0x50 },
+       { 1293, 1256, 56, 33, 10, 1330, 1332, 76,
+         518, 485, 85, 59, 519, 30, 260, 460, },
+       { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+       { 17, 27, 3 },  /* pixel clock = 49.63MHz for V=71.66Hz */
+       800, 600
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct control_regvals control_reg_init_10 = {
+       { 800, 1600, 3200 },
+       { 0x10, 0x28, 0x50 },
+       { 1293, 1256, 56, 33, 10, 1330, 1332, 76,
+         518, 485, 85, 59, 519, 30, 260, 460, },
+       { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+       { 20, 53, 2 },  /* pixel clock = 41.41MHz for V=59.78Hz */
+       800, 600
+};
+
+/* Register values for 640x870, 75Hz Full Page Display (7) */
+static struct control_regvals control_reg_init_7 = {
+        { 640, 1280, 2560 },
+       { 0x10, 0x30, 0x68 },
+       { 0x727, 0x724, 0x58, 0x2e, 0x4, 0x72a, 0x72c, 0x40,
+         0x19e, 0x18c, 0x4c, 0x27, 0x19f, 0x14, 0xd0, 0x178 },
+       { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+       { 9, 33, 2 },   /* pixel clock = 57.29MHz for V=75.01Hz */
+       640, 870
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct control_regvals control_reg_init_6 = {
+       { 640, 1280, 2560 },
+       { 0, 8, 0x10 },
+       { 1045, 1042, 82, 43, 4, 1048, 1050, 72,
+         430, 393, 73, 31, 431, 16, 216, 400 },
+       { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+       { 14, 27, 2 },  /* pixel clock = 30.13MHz for V=66.43Hz */
+       640, 480
+};
+
+/* Register values for 640x480, 60Hz mode (5) */
+static struct control_regvals control_reg_init_5 = {
+       { 640, 1280, 2560 },
+       { 0x10, 0x28, 0x50 },
+       { 1037, 1026, 66, 34, 2, 1048, 1050, 56,
+         398, 385, 65, 47, 399, 24, 200, 352, },
+       { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+       { 23, 37, 2 },  /* pixel clock = 25.14MHz for V=59.85Hz */
+       640, 480
+};
+
+static struct control_regvals *control_reg_init[VMODE_MAX] = {
+       NULL, NULL, NULL, NULL,
+       &control_reg_init_5,
+       &control_reg_init_6,
+       &control_reg_init_7,
+       NULL, NULL,
+       &control_reg_init_10,
+       &control_reg_init_11,
+       &control_reg_init_12,
+       &control_reg_init_13,
+       &control_reg_init_14,
+       &control_reg_init_15,
+       NULL,
+       &control_reg_init_17,
+       &control_reg_init_18,
+       &control_reg_init_19,
+       &control_reg_init_20
+};
index 63e65bc8b9f910657db666b2f1543549fda06e3c..1dda1ef0e45903b758cefb81992349bba790fa09 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: creatorfb.c,v 1.7 1998/07/21 10:36:48 jj Exp $
+/* $Id: creatorfb.c,v 1.10 1998/07/25 22:54:37 davem Exp $
  * creatorfb.c: Creator/Creator3D frame buffer driver
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
@@ -185,7 +185,7 @@ static void ffb_clear(struct vc_data *conp, struct display *p, int sy, int sx,
        int x, y, w, h;
        
        fbc->ppc = 0x1803;
-       fbc->fg = ffb_cmap[attr_bg_col_ec(conp)];
+       fbc->fg = ffb_cmap[attr_bgcol_ec(p,conp)];
        fbc->fbc = 0x2000707f;
        fbc->rop = 0x83;
        fbc->pmask = 0xffffffff;
@@ -207,13 +207,13 @@ static void ffb_clear(struct vc_data *conp, struct display *p, int sy, int sx,
        fbc->bw = w;
 }
 
-static void ffb_fill(struct fb_info_sbusfb *fb, int s,
+static void ffb_fill(struct fb_info_sbusfb *fb, struct display *p, int s,
                     int count, unsigned short *boxes)
 {
        register struct ffb_fbc *fbc = fb->s.ffb.fbc;
 
        fbc->ppc = 0x1803;
-       fbc->fg = ffb_cmap[attr_bg_col(s)];
+       fbc->fg = ffb_cmap[attr_bgcol(p,s)];
        fbc->fbc = 0x2000707f;
        fbc->rop = 0x83;
        fbc->pmask = 0xffffffff;
@@ -236,11 +236,15 @@ static void ffb_putc(struct vc_data *conp, struct display *p, int c, int yy, int
 
        if (p->fontheightlog) {
                xy = (yy << (16 + p->fontheightlog));
-               i = ((c & 0xff) << p->fontheightlog);
+               i = ((c & p->charmask) << p->fontheightlog);
        } else {
                xy = ((yy * p->fontheight) << 16);
-               i = (c & 0xff) * p->fontheight;
+               i = (c & p->charmask) * p->fontheight;
        }
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+       fd = p->fontdata + i;
+       xy += (xx * 8) + fb->s.ffb.xy_margin;
+#else
        if (p->fontwidth <= 8)
                fd = p->fontdata + i;
        else
@@ -249,24 +253,29 @@ static void ffb_putc(struct vc_data *conp, struct display *p, int c, int yy, int
                xy += (xx << p->fontwidthlog) + fb->s.ffb.xy_margin;
        else
                xy += (xx * p->fontwidth) + fb->s.ffb.xy_margin;
+#endif
        fbc->ppc = 0x203;
-       fbc->fg = ffb_cmap[attr_fg_col(c)];
+       fbc->fg = ffb_cmap[attr_fgcol(p,c)];
        fbc->fbc = 0x2000707f;
        fbc->rop = 0x83;
        fbc->pmask = 0xffffffff;
-       fbc->bg = ffb_cmap[attr_bg_col(c)];
+       fbc->bg = ffb_cmap[attr_bgcol(p,c)];
        fbc->fontw = p->fontwidth;
        fbc->fontinc = 0x10000;
        fbc->fontxy = xy;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
        if (p->fontwidth <= 8) {
+#endif
                for (i = 0; i < p->fontheight; i++)
                        fbc->font = *fd++ << 24;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
        } else {
                for (i = 0; i < p->fontheight; i++) {
                        fbc->font = *(u16 *)fd << 16;
                        fd += 2;
                }
        }
+#endif
 }
 
 static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
@@ -278,42 +287,51 @@ static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned sh
        u8 *fd1, *fd2, *fd3, *fd4;
 
        fbc->ppc = 0x203;
-       fbc->fg = ffb_cmap[attr_fg_col(*s)];
+       fbc->fg = ffb_cmap[attr_fgcol(p,*s)];
        fbc->fbc = 0x2000707f;
        fbc->rop = 0x83;
        fbc->pmask = 0xffffffff;
-       fbc->bg = ffb_cmap[attr_bg_col(*s)];
+       fbc->bg = ffb_cmap[attr_bgcol(p,*s)];
        xy = fb->s.ffb.xy_margin;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+       xy += xx * 8;
+#else
        if (p->fontwidthlog)
                xy += (xx << p->fontwidthlog);
        else
                xy += xx * p->fontwidth;
+#endif
        if (p->fontheightlog)
                xy += (yy << (16 + p->fontheightlog));
        else
                xy += ((yy * p->fontheight) << 16);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
        if (p->fontwidth <= 8) {
+#endif
                while (count >= 4) {
                        count -= 4;
                        fbc->fontw = 4 * p->fontwidth;
                        fbc->fontinc = 0x10000;
                        fbc->fontxy = xy;
                        if (p->fontheightlog) {
-                               fd1 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
-                               fd2 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
-                               fd3 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
-                               fd4 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
+                               fd1 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+                               fd2 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+                               fd3 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+                               fd4 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
                        } else {
-                               fd1 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
-                               fd2 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
-                               fd3 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
-                               fd4 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
+                               fd1 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+                               fd2 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+                               fd3 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+                               fd4 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
                        }
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
                        if (p->fontwidth == 8) {
+#endif
                                for (i = 0; i < p->fontheight; i++)
                                        fbc->font = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) 
                                                << 8)) << 8)) << 8);
                                xy += 32;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
                        } else {
                                for (i = 0; i < p->fontheight; i++)
                                        fbc->font = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) 
@@ -328,11 +346,11 @@ static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned sh
                        fbc->fontinc = 0x10000;
                        fbc->fontxy = xy;
                        if (p->fontheightlog) {
-                               fd1 = p->fontdata + ((*s++ & 0xff) << (p->fontheightlog + 1));
-                               fd2 = p->fontdata + ((*s++ & 0xff) << (p->fontheightlog + 1));
+                               fd1 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1));
+                               fd2 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1));
                        } else {
-                               fd1 = p->fontdata + (((*s++ & 0xff) * p->fontheight) << 1);
-                               fd2 = p->fontdata + (((*s++ & 0xff) * p->fontheight) << 1);
+                               fd1 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1);
+                               fd2 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1);
                        }
                        for (i = 0; i < p->fontheight; i++) {
                                fbc->font = ((((u32)*(u16 *)fd1) << p->fontwidth) | ((u32)*(u16 *)fd2)) << (16 - p->fontwidth);
@@ -340,6 +358,7 @@ static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned sh
                        }
                        xy += 2 * p->fontwidth;
                }
+#endif
        }
        while (count) {
                count--;
@@ -347,13 +366,16 @@ static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned sh
                fbc->fontinc = 0x10000;
                fbc->fontxy = xy;
                if (p->fontheightlog)
-                       i = ((*s++ & 0xff) << p->fontheightlog);
+                       i = ((*s++ & p->charmask) << p->fontheightlog);
                else
-                       i = ((*s++ & 0xff) * p->fontheight);
+                       i = ((*s++ & p->charmask) * p->fontheight);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
                if (p->fontwidth <= 8) {
+#endif
                        fd1 = p->fontdata + i;
                        for (i = 0; i < p->fontheight; i++)
                                fbc->font = *fd1++ << 24;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
                } else {
                        fd1 = p->fontdata + (i << 1);
                        for (i = 0; i < p->fontheight; i++) {
@@ -361,6 +383,7 @@ static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned sh
                                fd1 += 2;
                        }
                }
+#endif
                xy += p->fontwidth;
        }
 }
@@ -471,11 +494,8 @@ __initfunc(char *creatorfb_init(struct fb_info_sbusfb *fb))
        strcpy(fb->info.modename, "Creator");
                
        strcpy(fix->id, "Creator");
-       fix->smem_start = (char *)(regs[0].phys_addr) + FFB_DFB24_POFF;
        fix->visual = FB_VISUAL_DIRECTCOLOR;
        fix->line_length = 8192;
-       fix->mmio_start = (char *)(regs[0].phys_addr) + FFB_FBC_REGS_POFF;
-       fix->mmio_len = PAGE_SIZE;
        fix->accel = FB_ACCEL_SUN_CREATOR;
        
        var->bits_per_pixel = 32;
index 510814478bea670e2c093749ad3b1cccba44ec17..34d023311cf44be10646a3b3f8b28a3619c7db4c 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
index 9065546417a5b3d5f97742f85ddc960896e14e6c..d8b993eedd8640776b384860832d13ca2f807d2b 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/tty.h>
 #include <linux/malloc.h>
 #include <linux/delay.h>
+#include <linux/config.h>
 #include <linux/interrupt.h>
 #include <asm/setup.h>
 #include <asm/segment.h>
index f97560214779304a8ff32f7a02611b16b31da583..6a577d259500a18983d057f10de67c54e3267d88 100644 (file)
@@ -5,7 +5,6 @@
  *  available, usually until fbcon takes console over.
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kdev_t.h>
 #include <linux/tty.h>
  *  Dummy console driver
  */
 
-#ifdef __sparc__
-/* Some reasonable defaults, so that we don't loose any text */
-#define DUMMY_COLUMNS  128
-#define DUMMY_ROWS     54
-#elif defined(CONFIG_ARM)
+#if defined(CONFIG_ARM)
 #define DUMMY_COLUMNS  ORIG_VIDEO_COLS
 #define DUMMY_ROWS     ORIG_VIDEO_LINES
 #else
index 146063b0560dde98981c078205b9dc1a3301d231..a8c01d6a0fd71ba6a2cdd8abc7f8a3dc7b373bc2 100644 (file)
@@ -251,7 +251,7 @@ void fbcon_afb_putc(struct vc_data *conp, struct display *p, int c, int yy,
     int fg, bg;
 
     dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx;
-    cdat0 = p->fontdata+(c&0xff)*p->fontheight;
+    cdat0 = p->fontdata+(c&p->charmask)*p->fontheight;
     fg = attr_fgcol(p,c);
     bg = attr_bgcol(p,c);
 
@@ -286,7 +286,7 @@ void fbcon_afb_putcs(struct vc_data *conp, struct display *p,
     u8 *dest, *dest0, *dest1, *expand;
     u8 *cdat1, *cdat2, *cdat3, *cdat4, *cdat10, *cdat20, *cdat30, *cdat40;
     u_short i, j;
-    u8 c1, c2, c3, c4;
+    u16 c1, c2, c3, c4;
     int fg0, bg0, fg, bg;
 
     dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx;
@@ -295,7 +295,7 @@ void fbcon_afb_putcs(struct vc_data *conp, struct display *p,
 
     while (count--)
        if (xx&3 || count < 3) {        /* Slow version */
-           c1 = *s++;
+           c1 = *s++ & p->charmask;
            dest1 = dest0++;
            xx++;
 
@@ -322,10 +322,10 @@ void fbcon_afb_putcs(struct vc_data *conp, struct display *p,
                dest1 += p->next_plane;
            } while (--i);
        } else {                        /* Fast version */
-           c1 = s[0];
-           c2 = s[1];
-           c3 = s[2];
-           c4 = s[3];
+           c1 = s[0] & p->charmask;
+           c2 = s[1] & p->charmask;
+           c3 = s[2] & p->charmask;
+           c4 = s[3] & p->charmask;
 
            dest1 = dest0;
            cdat10 = p->fontdata+c1*p->fontheight;
index c82d98c410ba74bce1423195fd0ecacb46bcbfa6..6eb0310e96d030cd07f5a90ae5b1b8ed6d6bee4c 100644 (file)
@@ -2,8 +2,6 @@
      *  Amiga bitplanes (afb)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_AFB_MODULE)
 #define FBCON_HAS_AFB
index 49a54643a9302007f3ffab53f6591f79cd21b1f0..24da1127767bbfd6ced065e84d40842e342b04ea 100644 (file)
@@ -47,23 +47,34 @@ void fbcon_cfb16_bmove(struct display *p, int sy, int sx, int dy, int dx,
     int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
     u8 *src, *dst;
 
-    if (sx == 0 && dx == 0 && width * 16 == bytes)
+    if (sx == 0 && dx == 0 && width * p->fontwidth * 2 == bytes) {
        mymemmove(p->screen_base + dy * linesize,
                  p->screen_base + sy * linesize,
                  height * linesize);
-    else if (dy < sy || (dy == sy && dx < sx)) {
-       src = p->screen_base + sy * linesize + sx * 16;
-       dst = p->screen_base + dy * linesize + dx * 16;
-       for (rows = height * p->fontheight ; rows-- ;) {
-           mymemmove(dst, src, width * 16);
+       return;
+    }
+    if (p->fontwidthlog) {
+       sx <<= p->fontwidthlog+1;
+       dx <<= p->fontwidthlog+1;
+       width <<= p->fontwidthlog+1;
+    } else {
+       sx *= p->fontwidth*2;
+       dx *= p->fontwidth*2;
+       width *= p->fontwidth*2;
+    }
+    if (dy < sy || (dy == sy && dx < sx)) {
+       src = p->screen_base + sy * linesize + sx;
+       dst = p->screen_base + dy * linesize + dx;
+       for (rows = height * p->fontheight; rows--;) {
+           mymemmove(dst, src, width);
            src += bytes;
            dst += bytes;
        }
     } else {
-       src = p->screen_base + (sy+height) * linesize + sx * 16 - bytes;
-       dst = p->screen_base + (dy+height) * linesize + dx * 16 - bytes;
-       for (rows = height * p->fontheight ; rows-- ;) {
-           mymemmove(dst, src, width * 16);
+       src = p->screen_base + (sy+height) * linesize + sx - bytes;
+       dst = p->screen_base + (dy+height) * linesize + dx - bytes;
+       for (rows = height * p->fontheight; rows--;) {
+           mymemmove(dst, src, width);
            src -= bytes;
            dst -= bytes;
        }
@@ -77,29 +88,26 @@ void fbcon_cfb16_clear(struct vc_data *conp, struct display *p, int sy, int sx,
     int bytes = p->next_line, lines = height * p->fontheight, rows, i;
     u32 bgx;
 
-    dest = p->screen_base + sy * p->fontheight * bytes + sx * 16;
+    dest = p->screen_base + sy * p->fontheight * bytes + sx * p->fontwidth * 2;
 
     bgx = fbcon_cfb16_cmap[attr_bgcol_ec(p, conp)];
     bgx |= (bgx << 16);
 
-    if (sx == 0 && width * 16 == bytes)
-       for (i = 0 ; i < lines * width ; i++) {
+    width *= p->fontwidth/4;
+    if (sx == 0 && width * 8 == bytes)
+       for (i = 0; i < lines * width; i++) {
            ((u32 *)dest)[0] = bgx;
            ((u32 *)dest)[1] = bgx;
-           ((u32 *)dest)[2] = bgx;
-           ((u32 *)dest)[3] = bgx;
-           dest += 16;
+           dest += 8;
        }
     else {
        dest0 = dest;
-       for (rows = lines; rows-- ; dest0 += bytes) {
+       for (rows = lines; rows--; dest0 += bytes) {
            dest = dest0;
-           for (i = 0 ; i < width ; i++) {
+           for (i = 0; i < width; i++) {
                ((u32 *)dest)[0] = bgx;
                ((u32 *)dest)[1] = bgx;
-               ((u32 *)dest)[2] = bgx;
-               ((u32 *)dest)[3] = bgx;
-               dest += 16;
+               dest += 8;
            }
        }
     }
@@ -108,12 +116,11 @@ void fbcon_cfb16_clear(struct vc_data *conp, struct display *p, int sy, int sx,
 void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c, int yy,
                      int xx)
 {
-    u8 *dest, *cdat;
+    u8 *dest, *cdat, bits;
     int bytes = p->next_line, rows;
     u32 eorx, fgx, bgx;
 
-    dest = p->screen_base + yy * p->fontheight * bytes + xx * 16;
-    cdat = p->fontdata + (c & 0xff) * p->fontheight;
+    dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 2;
 
     fgx = fbcon_cfb16_cmap[attr_fgcol(p, c)];
     bgx = fbcon_cfb16_cmap[attr_bgcol(p, c)];
@@ -121,41 +128,112 @@ void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c, int yy,
     bgx |= (bgx << 16);
     eorx = fgx ^ bgx;
 
-    for (rows = p->fontheight ; rows-- ; dest += bytes) {
-       u8 bits = *cdat++;
-       ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
-       ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
-       ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
-       ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+    switch (p->fontwidth) {
+    case 4:
+    case 8:
+#endif
+       cdat = p->fontdata + (c & p->charmask) * p->fontheight;
+       for (rows = p->fontheight; rows--; dest += bytes) {
+           bits = *cdat++;
+           ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+           ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+           if (p->fontwidth == 8)
+#endif
+           {
+               ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+               ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+           }
+       }
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+       break;
+    case 12:
+    case 16:
+       cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1);
+       for (rows = p->fontheight; rows--; dest += bytes) {
+           bits = *cdat++;
+           ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+           ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+           ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+           ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+           bits = *cdat++;
+           ((u32 *)dest)[4] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+           ((u32 *)dest)[5] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+           if (p->fontwidth == 16) {
+               ((u32 *)dest)[6] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+               ((u32 *)dest)[7] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+           }
+       }
+       break;
     }
+#endif
 }
 
-void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p, 
+void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p,
                       const unsigned short *s, int count, int yy, int xx)
 {
-    u8 *cdat, c, *dest, *dest0;
+    u8 *cdat, *dest, *dest0;
+    u16 c;
     int rows, bytes = p->next_line;
     u32 eorx, fgx, bgx;
 
-    dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 16;
+    dest0 = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 2;
     fgx = fbcon_cfb16_cmap[attr_fgcol(p, *s)];
     bgx = fbcon_cfb16_cmap[attr_bgcol(p, *s)];
     fgx |= (fgx << 16);
     bgx |= (bgx << 16);
     eorx = fgx ^ bgx;
-    while (count--) {
-       c = *s++;
-       cdat = p->fontdata + c * p->fontheight;
 
-       for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
-           u8 bits = *cdat++;
-           ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
-           ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
-           ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
-           ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+    switch (p->fontwidth) {
+    case 4:
+    case 8:
+#endif
+       while (count--) {
+           c = *s++ & p->charmask;
+           cdat = p->fontdata + c * p->fontheight;
+           for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) {
+               u8 bits = *cdat++;
+               ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+               ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+               if (p->fontwidth == 8)
+#endif
+               {
+               
+                   ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+                   ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+               }
+           }
+           dest0 += p->fontwidth*2;;
        }
-       dest0 += 16;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+       break;
+    case 12:
+    case 16:
+       while (count--) {
+           c = *s++ & p->charmask;
+           cdat = p->fontdata + (c * p->fontheight << 1);
+           for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) {
+               u8 bits = *cdat++;
+               ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+               ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+               ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+               ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+               bits = *cdat++;
+               ((u32 *)dest)[4] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+               ((u32 *)dest)[5] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+               if (p->fontwidth == 16) {
+                   ((u32 *)dest)[6] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+                   ((u32 *)dest)[7] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+               }
+           }
+           dest0 += p->fontwidth*2;
+       }
+       break;
     }
+#endif
 }
 
 void fbcon_cfb16_revc(struct display *p, int xx, int yy)
@@ -163,12 +241,60 @@ void fbcon_cfb16_revc(struct display *p, int xx, int yy)
     u8 *dest;
     int bytes = p->next_line, rows;
 
-    dest = p->screen_base + yy * p->fontheight * bytes + xx * 16;
-    for (rows = p->fontheight ; rows-- ; dest += bytes) {
-       ((u32 *)dest)[0] ^= 0xffffffff;
-       ((u32 *)dest)[1] ^= 0xffffffff;
-       ((u32 *)dest)[2] ^= 0xffffffff;
-       ((u32 *)dest)[3] ^= 0xffffffff;
+    dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth*2;
+    for (rows = p->fontheight; rows--; dest += bytes) {
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+       ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff;
+       ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+#else
+       switch (p->fontwidth) {
+       case 16:
+           ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
+           /* FALL THROUGH */
+       case 12:
+           ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff;
+           /* FALL THROUGH */
+       case 8:
+           ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff;
+           /* FALL THROUGH */
+       case 4:
+           ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+       }
+#endif
+    }
+}
+
+void fbcon_cfb16_clear_margins(struct vc_data *conp, struct display *p)
+{
+    u8 *dest0;
+    u32 *dest;
+    int bytes = p->next_line;
+    u32 bgx;
+    int i, j;
+
+    unsigned int right_start = conp->vc_cols*p->fontwidth;
+    unsigned int right_width = p->var.xres_virtual-right_start;
+    unsigned int bottom_start = conp->vc_rows*p->fontheight;
+    unsigned int bottom_width = p->var.yres_virtual-bottom_start;
+
+    bgx = fbcon_cfb16_cmap[attr_bgcol_ec(p, conp)];
+    bgx |= (bgx << 16);
+
+    if (right_width) {
+       dest0 = p->screen_base+right_start*2;
+       for (i = 0; i < bottom_start; i++, dest0 += bytes) {
+           for (j = 0, dest = (u32 *)dest0; j < right_width/2; j++)
+               *dest++ = bgx;
+           if (right_width & 1)
+               *(u16 *)dest = bgx;
+       }
+    }
+    if (bottom_width) {
+       dest = (u32 *)(p->screen_base+bottom_start*bytes);
+       for (i = 0; i < bytes*bottom_width/4; i++)
+           *dest++ = bgx;
+       if ((bytes*bottom_width) & 2)
+           *(u16 *)dest = bgx;
     }
 }
 
@@ -179,7 +305,8 @@ void fbcon_cfb16_revc(struct display *p, int xx, int yy)
 
 struct display_switch fbcon_cfb16 = {
     fbcon_cfb16_setup, fbcon_cfb16_bmove, fbcon_cfb16_clear, fbcon_cfb16_putc,
-    fbcon_cfb16_putcs, fbcon_cfb16_revc, NULL, NULL, NULL, FONTWIDTH(8)
+    fbcon_cfb16_putcs, fbcon_cfb16_revc, NULL, NULL, fbcon_cfb16_clear_margins,
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 
 
index 7419f81b7e85d5f3ad9448f203407713e39007a1..716f1f949e4c705b89564d555c48fd930c5943f6 100644 (file)
@@ -2,8 +2,6 @@
      *  16 bpp packed pixel (cfb16)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB16_MODULE)
 #define FBCON_HAS_CFB16
@@ -26,3 +24,4 @@ extern void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c,
 extern void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p,
                              const unsigned short *s, int count, int yy, int xx);
 extern void fbcon_cfb16_revc(struct display *p, int xx, int yy);
+extern void fbcon_cfb16_clear_margins(struct vc_data *conp, struct display *p);
index 707ccff846f09494d1ba5bc9b31645d9766099ce..60bed6275fb67c1ce843744b9004186d64e4b196 100644 (file)
@@ -129,7 +129,7 @@ void fbcon_cfb2_putc(struct vc_data *conp, struct display *p, int c, int yy,
        u32 eorx,fgx,bgx;
 
        dest = p->screen_base + yy * p->fontheight * bytes + xx * 2;
-       cdat = p->fontdata + (c & 0xff) * p->fontheight;
+       cdat = p->fontdata + (c & p->charmask) * p->fontheight;
 
        fgx=3;/*attr_fgcol(p,c);*/
        bgx=attr_bgcol(p,c);
@@ -150,7 +150,8 @@ void fbcon_cfb2_putc(struct vc_data *conp, struct display *p, int c, int yy,
 void fbcon_cfb2_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
                      int count, int yy, int xx)
 {
-       u8 *cdat, c, *dest, *dest0;
+       u8 *cdat, *dest, *dest0;
+       u16 c;
        int rows,bytes=p->next_line;
        u32 eorx, fgx, bgx;
 
@@ -163,7 +164,7 @@ void fbcon_cfb2_putcs(struct vc_data *conp, struct display *p, const unsigned sh
        bgx |= (bgx << 4);
        eorx = fgx ^ bgx;
        while (count--) {
-               c = *s++;
+               c = *s++ & p->charmask;
                cdat = p->fontdata + c * p->fontheight;
 
                for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
index 1cb29c5a98cbb1ff44ecb6abd44dbd51df196e1e..c66745e1b3b46e55724f3556e30a41731405612f 100644 (file)
@@ -2,8 +2,6 @@
      *  2 bpp packed pixel (cfb2)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB2) || defined(CONFIG_FBCON_CFB2_MODULE)
 #define FBCON_HAS_CFB2
index bfad93291081e559e7f8439991342a0da924ac85..875ad850cfe209e0cbc005c02c557e6d4e2adc83 100644 (file)
@@ -37,29 +37,56 @@ void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy, int dx,
     int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
     u8 *src, *dst;
 
-    if (sx == 0 && dx == 0 && width * 24 == bytes)
+    if (sx == 0 && dx == 0 && width * p->fontwidth * 3 == bytes) {
        mymemmove(p->screen_base + dy * linesize,
                  p->screen_base + sy * linesize,
                  height * linesize);
-    else if (dy < sy || (dy == sy && dx < sx)) {
-       src = p->screen_base + sy * linesize + sx * 24;
-       dst = p->screen_base + dy * linesize + dx * 24;
-       for (rows = height * p->fontheight ; rows-- ;) {
-           mymemmove(dst, src, width * 24);
+       return;
+    }
+    if (p->fontwidthlog) {
+       sx <<= p->fontwidthlog;
+       dx <<= p->fontwidthlog;
+       width <<= p->fontwidthlog;
+    } else {
+       sx *= p->fontwidth;
+       dx *= p->fontwidth;
+       width *= p->fontwidth;
+    }
+    sx *= 3; dx *= 3; width *= 3;
+    if (dy < sy || (dy == sy && dx < sx)) {
+       src = p->screen_base + sy * linesize + sx;
+       dst = p->screen_base + dy * linesize + dx;
+       for (rows = height * p->fontheight; rows--;) {
+           mymemmove(dst, src, width);
            src += bytes;
            dst += bytes;
        }
     } else {
-       src = p->screen_base + (sy+height) * linesize + sx * 24 - bytes;
-       dst = p->screen_base + (dy+height) * linesize + dx * 24 - bytes;
-       for (rows = height * p->fontheight ; rows-- ;) {
-           mymemmove(dst, src, width * 24);
+       src = p->screen_base + (sy+height) * linesize + sx - bytes;
+       dst = p->screen_base + (dy+height) * linesize + dx - bytes;
+       for (rows = height * p->fontheight; rows--;) {
+           mymemmove(dst, src, width);
            src -= bytes;
            dst -= bytes;
        }
     }
 }
 
+static inline void store4pixels(u32 d1, u32 d2, u32 d3, u32 d4, u32 *dest)
+{
+#if defined(__BIG_ENDIAN)
+    *dest++ = (d1<<8) | (d2>>16);
+    *dest++ = (d2<<16) | (d3>>8);
+    *dest++ = (d3<<24) | d4;
+#elif defined(__LITTLE_ENDIAN)
+    *dest++ = (d1<<8) | (d2>>16);
+    *dest++ = (d2<<16) | (d3>>8);
+    *dest++ = (d3<<24) | d4;
+#else
+#error FIXME: No endianness??
+#endif
+}
+
 void fbcon_cfb24_clear(struct vc_data *conp, struct display *p, int sy, int sx,
                       int height, int width)
 {
@@ -67,112 +94,139 @@ void fbcon_cfb24_clear(struct vc_data *conp, struct display *p, int sy, int sx,
     int bytes = p->next_line, lines = height * p->fontheight, rows, i;
     u32 bgx;
 
-    dest = p->screen_base + sy * p->fontheight * bytes + sx * 24;
+    dest = p->screen_base + sy * p->fontheight * bytes + sx * p->fontwidth * 3;
 
     bgx = fbcon_cfb24_cmap[attr_bgcol_ec(p, conp)];
 
-    if (sx == 0 && width * 24 == bytes)
-       for (i = 0 ; i < lines * width ; i++) {
-           ((u32 *)dest)[0] = bgx;
-           ((u32 *)dest)[1] = bgx;
-           ((u32 *)dest)[2] = bgx;
-           ((u32 *)dest)[3] = bgx;
-           ((u32 *)dest)[4] = bgx;
-           ((u32 *)dest)[5] = bgx;
-           dest += 24;
+    width *= p->fontwidth/4;
+    if (sx == 0 && width * 12 == bytes)
+       for (i = 0; i < lines * width; i++) {
+           store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest);
+           dest += 12;
        }
     else {
        dest0 = dest;
-       for (rows = lines; rows-- ; dest0 += bytes) {
+       for (rows = lines; rows--; dest0 += bytes) {
            dest = dest0;
-           for (i = 0 ; i < width ; i++) {
-               ((u32 *)dest)[0] = bgx;
-               ((u32 *)dest)[1] = bgx;
-               ((u32 *)dest)[2] = bgx;
-               ((u32 *)dest)[3] = bgx;
-               ((u32 *)dest)[4] = bgx;
-               ((u32 *)dest)[5] = bgx;
-               dest += 24;
+           for (i = 0; i < width; i++) {
+               store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest);
+               dest += 12;
            }
        }
     }
 }
 
-static inline void store4pixels(u32 d1, u32 d2, u32 d3, u32 d4, u32 *dest)
-{
-#if defined(__BIG_ENDIAN)
-    *dest++ = (d1<<8) | (d2>>16);
-    *dest++ = (d2<<16) | (d3>>8);
-    *dest++ = (d3<<24) | d4;
-#elif defined(__LITTLE_ENDIAN)
-    *dest++ = (d1<<8) | (d2>>16);
-    *dest++ = (d2<<16) | (d3>>8);
-    *dest++ = (d3<<24) | d4;
-#else
-#error FIXME: No endianness??
-#endif
-}
-
 void fbcon_cfb24_putc(struct vc_data *conp, struct display *p, int c, int yy,
                      int xx)
 {
-    u8 *dest, *cdat;
+    u8 *dest, *cdat, bits;
     int bytes = p->next_line, rows;
-    u32 eorx, fgx, bgx;
+    u32 eorx, fgx, bgx, d1, d2, d3, d4;
 
-    dest = p->screen_base + yy * p->fontheight * bytes + xx * 24;
-    cdat = p->fontdata + (c & 0xff) * p->fontheight;
+    dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 3;
+    if (p->fontwidth <= 8)
+       cdat = p->fontdata + (c & p->charmask) * p->fontheight;
+    else
+       cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1);
 
     fgx = fbcon_cfb24_cmap[attr_fgcol(p, c)];
     bgx = fbcon_cfb24_cmap[attr_bgcol(p, c)];
     eorx = fgx ^ bgx;
 
-    for (rows = p->fontheight ; rows-- ; dest += bytes) {
-       u8 bits = *cdat++;
-       u32 d1, d2, d3, d4;
+    for (rows = p->fontheight; rows--; dest += bytes) {
+       bits = *cdat++;
        d1 = (-(bits >> 7) & eorx) ^ bgx;
        d2 = (-(bits >> 6 & 1) & eorx) ^ bgx;
        d3 = (-(bits >> 5 & 1) & eorx) ^ bgx;
        d4 = (-(bits >> 4 & 1) & eorx) ^ bgx;
        store4pixels(d1, d2, d3, d4, (u32 *)dest);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+       if (p->fontwidth < 8)
+           continue;
+#endif
        d1 = (-(bits >> 3 & 1) & eorx) ^ bgx;
        d2 = (-(bits >> 2 & 1) & eorx) ^ bgx;
        d3 = (-(bits >> 1 & 1) & eorx) ^ bgx;
        d4 = (-(bits & 1) & eorx) ^ bgx;
        store4pixels(d1, d2, d3, d4, (u32 *)(dest+12));
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+       if (p->fontwidth < 12)
+           continue;
+       bits = *cdat++;
+       d1 = (-(bits >> 7) & eorx) ^ bgx;
+       d2 = (-(bits >> 6 & 1) & eorx) ^ bgx;
+       d3 = (-(bits >> 5 & 1) & eorx) ^ bgx;
+       d4 = (-(bits >> 4 & 1) & eorx) ^ bgx;
+       store4pixels(d1, d2, d3, d4, (u32 *)(dest+24));
+       if (p->fontwidth < 16)
+           continue;
+       d1 = (-(bits >> 3 & 1) & eorx) ^ bgx;
+       d2 = (-(bits >> 2 & 1) & eorx) ^ bgx;
+       d3 = (-(bits >> 1 & 1) & eorx) ^ bgx;
+       d4 = (-(bits & 1) & eorx) ^ bgx;
+       store4pixels(d1, d2, d3, d4, (u32 *)(dest+32));
+#endif
     }
 }
 
-void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p, 
+void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p,
                       const unsigned short *s, int count, int yy, int xx)
 {
-    u8 *cdat, c, *dest, *dest0;
+    u8 *cdat, *dest, *dest0, bits;
+    u16 c;
     int rows, bytes = p->next_line;
-    u32 eorx, fgx, bgx;
+    u32 eorx, fgx, bgx, d1, d2, d3, d4;
 
-    dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 24;
+    dest0 = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 3;
     fgx = fbcon_cfb24_cmap[attr_fgcol(p, *s)];
     bgx = fbcon_cfb24_cmap[attr_bgcol(p, *s)];
     eorx = fgx ^ bgx;
     while (count--) {
-       c = *s++;
+       c = *s++ & p->charmask;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
        cdat = p->fontdata + c * p->fontheight;
-
-       for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
-           u8 bits = *cdat++;
-           u32 d1, d2, d3, d4;
+#else
+       if (p->fontwidth <= 8)
+           cdat = p->fontdata + c * p->fontheight;
+         
+       else
+           cdat = p->fontdata + (c * p->fontheight << 1);
+#endif
+       for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) {
+           bits = *cdat++;
            d1 = (-(bits >> 7) & eorx) ^ bgx;
            d2 = (-(bits >> 6 & 1) & eorx) ^ bgx;
            d3 = (-(bits >> 5 & 1) & eorx) ^ bgx;
            d4 = (-(bits >> 4 & 1) & eorx) ^ bgx;
            store4pixels(d1, d2, d3, d4, (u32 *)dest);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+           if (p->fontwidth < 8)
+               continue;
+#endif
            d1 = (-(bits >> 3 & 1) & eorx) ^ bgx;
            d2 = (-(bits >> 2 & 1) & eorx) ^ bgx;
            d3 = (-(bits >> 1 & 1) & eorx) ^ bgx;
            d4 = (-(bits & 1) & eorx) ^ bgx;
            store4pixels(d1, d2, d3, d4, (u32 *)(dest+12));
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+           if (p->fontwidth < 12)
+               continue;
+           bits = *cdat++;
+           d1 = (-(bits >> 7) & eorx) ^ bgx;
+           d2 = (-(bits >> 6 & 1) & eorx) ^ bgx;
+           d3 = (-(bits >> 5 & 1) & eorx) ^ bgx;
+           d4 = (-(bits >> 4 & 1) & eorx) ^ bgx;
+           store4pixels(d1, d2, d3, d4, (u32 *)(dest+24));
+           if (p->fontwidth < 16)
+               continue;
+           d1 = (-(bits >> 3 & 1) & eorx) ^ bgx;
+           d2 = (-(bits >> 2 & 1) & eorx) ^ bgx;
+           d3 = (-(bits >> 1 & 1) & eorx) ^ bgx;
+           d4 = (-(bits & 1) & eorx) ^ bgx;
+           store4pixels(d1, d2, d3, d4, (u32 *)(dest+32));
+#endif
        }
-       dest0 += 24;
+       dest0 += p->fontwidth*3;
     }
 }
 
@@ -181,14 +235,60 @@ void fbcon_cfb24_revc(struct display *p, int xx, int yy)
     u8 *dest;
     int bytes = p->next_line, rows;
 
-    dest = p->screen_base + yy * p->fontheight * bytes + xx * 24;
-    for (rows = p->fontheight ; rows-- ; dest += bytes) {
-       ((u32 *)dest)[0] ^= 0xffffffff;
-       ((u32 *)dest)[1] ^= 0xffffffff;
-       ((u32 *)dest)[2] ^= 0xffffffff;
-       ((u32 *)dest)[3] ^= 0xffffffff;
-       ((u32 *)dest)[4] ^= 0xffffffff;
+    dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 3;
+    for (rows = p->fontheight; rows--; dest += bytes) {
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+       ((u32 *)dest)[3] ^= 0xffffffff; ((u32 *)dest)[4] ^= 0xffffffff;
        ((u32 *)dest)[5] ^= 0xffffffff;
+       ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+       ((u32 *)dest)[2] ^= 0xffffffff;
+#else
+       switch (p->fontwidth) {
+       case 16:
+           ((u32 *)dest)[9] ^= 0xffffffff; ((u32 *)dest)[10] ^= 0xffffffff;
+           ((u32 *)dest)[11] ^= 0xffffffff;    /* FALL THROUGH */
+       case 12:
+           ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
+           ((u32 *)dest)[8] ^= 0xffffffff;     /* FALL THROUGH */
+       case 8:
+           ((u32 *)dest)[3] ^= 0xffffffff; ((u32 *)dest)[4] ^= 0xffffffff;
+           ((u32 *)dest)[5] ^= 0xffffffff;     /* FALL THROUGH */
+       case 4:
+           ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+           ((u32 *)dest)[2] ^= 0xffffffff;
+       }
+#endif
+    }
+}
+
+void fbcon_cfb24_clear_margins(struct vc_data *conp, struct display *p)
+{
+    u8 *dest0, *dest;
+    int bytes = p->next_line;
+    u32 bgx;
+    int i, j;
+
+    unsigned int right_start = conp->vc_cols*p->fontwidth;
+    unsigned int right_width = p->var.xres_virtual-right_start;
+    unsigned int bottom_start = conp->vc_rows*p->fontheight;
+    unsigned int bottom_width = p->var.yres_virtual-bottom_start;
+
+    bgx = fbcon_cfb24_cmap[attr_bgcol_ec(p, conp)];
+
+    if (right_width) {
+       dest0 = p->screen_base+right_start*3;
+       for (i = 0; i < bottom_start; i++, dest0 += bytes)
+           for (j = 0, dest = dest0; j < right_width/4; j++) {
+               store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest);
+               dest += 12;
+           }
+    }
+    if (bottom_width) {
+       dest = p->screen_base+bottom_start*bytes;
+       for (i = 0; i < bytes*bottom_width/12; i++) {
+           store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest);
+           dest += 12;
+       }
     }
 }
 
@@ -199,7 +299,8 @@ void fbcon_cfb24_revc(struct display *p, int xx, int yy)
 
 struct display_switch fbcon_cfb24 = {
     fbcon_cfb24_setup, fbcon_cfb24_bmove, fbcon_cfb24_clear, fbcon_cfb24_putc,
-    fbcon_cfb24_putcs, fbcon_cfb24_revc, NULL, NULL, NULL, FONTWIDTH(8)
+    fbcon_cfb24_putcs, fbcon_cfb24_revc, NULL, NULL, fbcon_cfb24_clear_margins,
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 
 
index 738c9e62fadd0db826dfadaf2502edb84ca8dd01..c764ad029d08eca770f3e92ef8c788bf1573b92c 100644 (file)
@@ -2,8 +2,6 @@
      *  24 bpp packed pixel (cfb24)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB24) || defined(CONFIG_FBCON_CFB24_MODULE)
 #define FBCON_HAS_CFB24
@@ -26,3 +24,4 @@ extern void fbcon_cfb24_putc(struct vc_data *conp, struct display *p, int c,
 extern void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p,
                              const unsigned short *s, int count, int yy, int xx);
 extern void fbcon_cfb24_revc(struct display *p, int xx, int yy);
+extern void fbcon_cfb24_clear_margins(struct vc_data *conp, struct display *p);
index a0120c5a17d1ed32dce45133238c89763f349301..8a064e9cd3dfb9a55ec7462fbc1b66f29946f015 100644 (file)
@@ -37,23 +37,34 @@ void fbcon_cfb32_bmove(struct display *p, int sy, int sx, int dy, int dx,
     int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
     u8 *src, *dst;
 
-    if (sx == 0 && dx == 0 && width * 32 == bytes)
+    if (sx == 0 && dx == 0 && width * p->fontwidth * 4 == bytes) {
        mymemmove(p->screen_base + dy * linesize,
                  p->screen_base + sy * linesize,
                  height * linesize);
-    else if (dy < sy || (dy == sy && dx < sx)) {
-       src = p->screen_base + sy * linesize + sx * 32;
-       dst = p->screen_base + dy * linesize + dx * 32;
-       for (rows = height * p->fontheight ; rows-- ;) {
-           mymemmove(dst, src, width * 32);
+       return;
+    }
+    if (p->fontwidthlog) {
+       sx <<= p->fontwidthlog+2;
+       dx <<= p->fontwidthlog+2;
+       width <<= p->fontwidthlog+2;
+    } else {
+       sx *= p->fontwidth*4;
+       dx *= p->fontwidth*4;
+       width *= p->fontwidth*4;
+    }
+    if (dy < sy || (dy == sy && dx < sx)) {
+       src = p->screen_base + sy * linesize + sx;
+       dst = p->screen_base + dy * linesize + dx;
+       for (rows = height * p->fontheight; rows--;) {
+           mymemmove(dst, src, width);
            src += bytes;
            dst += bytes;
        }
     } else {
-       src = p->screen_base + (sy+height) * linesize + sx * 32 - bytes;
-       dst = p->screen_base + (dy+height) * linesize + dx * 32 - bytes;
-       for (rows = height * p->fontheight ; rows-- ;) {
-           mymemmove(dst, src, width * 32);
+       src = p->screen_base + (sy+height) * linesize + sx - bytes;
+       dst = p->screen_base + (dy+height) * linesize + dx - bytes;
+       for (rows = height * p->fontheight; rows--;) {
+           mymemmove(dst, src, width);
            src -= bytes;
            dst -= bytes;
        }
@@ -67,36 +78,29 @@ void fbcon_cfb32_clear(struct vc_data *conp, struct display *p, int sy, int sx,
     int bytes = p->next_line, lines = height * p->fontheight, rows, i;
     u32 bgx;
 
-    dest = p->screen_base + sy * p->fontheight * bytes + sx * 32;
+    dest = p->screen_base + sy * p->fontheight * bytes + sx * p->fontwidth * 4;
 
     bgx = fbcon_cfb32_cmap[attr_bgcol_ec(p, conp)];
 
-    if (sx == 0 && width * 32 == bytes)
-       for (i = 0 ; i < lines * width ; i++) {
+    width *= p->fontwidth/4;
+    if (sx == 0 && width * 16 == bytes)
+       for (i = 0; i < lines * width; i++) {
            ((u32 *)dest)[0] = bgx;
            ((u32 *)dest)[1] = bgx;
            ((u32 *)dest)[2] = bgx;
            ((u32 *)dest)[3] = bgx;
-           ((u32 *)dest)[4] = bgx;
-           ((u32 *)dest)[5] = bgx;
-           ((u32 *)dest)[6] = bgx;
-           ((u32 *)dest)[7] = bgx;
-           dest += 32;
+           dest += 16;
        }
     else {
        dest0 = dest;
-       for (rows = lines; rows-- ; dest0 += bytes) {
+       for (rows = lines; rows--; dest0 += bytes) {
            dest = dest0;
-           for (i = 0 ; i < width ; i++) {
+           for (i = 0; i < width; i++) {
                ((u32 *)dest)[0] = bgx;
                ((u32 *)dest)[1] = bgx;
                ((u32 *)dest)[2] = bgx;
                ((u32 *)dest)[3] = bgx;
-               ((u32 *)dest)[4] = bgx;
-               ((u32 *)dest)[5] = bgx;
-               ((u32 *)dest)[6] = bgx;
-               ((u32 *)dest)[7] = bgx;
-               dest += 32;
+               dest += 16;
            }
        }
     }
@@ -105,57 +109,108 @@ void fbcon_cfb32_clear(struct vc_data *conp, struct display *p, int sy, int sx,
 void fbcon_cfb32_putc(struct vc_data *conp, struct display *p, int c, int yy,
                      int xx)
 {
-    u8 *dest, *cdat;
+    u8 *dest, *cdat, bits;
     int bytes = p->next_line, rows;
     u32 eorx, fgx, bgx;
 
-    dest = p->screen_base + yy * p->fontheight * bytes + xx * 32;
-    cdat = p->fontdata + (c & 0xff) * p->fontheight;
-
+    dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 4;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+    cdat = p->fontdata + (c & p->charmask) * p->fontheight;
+#else
+    if (p->fontwidth <= 8)
+       cdat = p->fontdata + (c & p->charmask) * p->fontheight;
+    else
+       cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1);
+#endif
     fgx = fbcon_cfb32_cmap[attr_fgcol(p, c)];
     bgx = fbcon_cfb32_cmap[attr_bgcol(p, c)];
     eorx = fgx ^ bgx;
 
-    for (rows = p->fontheight ; rows-- ; dest += bytes) {
-       u8 bits = *cdat++;
+    for (rows = p->fontheight; rows--; dest += bytes) {
+       bits = *cdat++;
        ((u32 *)dest)[0] = (-(bits >> 7) & eorx) ^ bgx;
        ((u32 *)dest)[1] = (-(bits >> 6 & 1) & eorx) ^ bgx;
        ((u32 *)dest)[2] = (-(bits >> 5 & 1) & eorx) ^ bgx;
        ((u32 *)dest)[3] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+       if (p->fontwidth < 8)
+           continue;
+#endif
        ((u32 *)dest)[4] = (-(bits >> 3 & 1) & eorx) ^ bgx;
        ((u32 *)dest)[5] = (-(bits >> 2 & 1) & eorx) ^ bgx;
        ((u32 *)dest)[6] = (-(bits >> 1 & 1) & eorx) ^ bgx;
        ((u32 *)dest)[7] = (-(bits & 1) & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+       if (p->fontwidth < 12)
+           continue;
+       bits = *cdat++;
+       ((u32 *)dest)[8] = (-(bits >> 7) & eorx) ^ bgx;
+       ((u32 *)dest)[9] = (-(bits >> 6 & 1) & eorx) ^ bgx;
+       ((u32 *)dest)[10] = (-(bits >> 5 & 1) & eorx) ^ bgx;
+       ((u32 *)dest)[11] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+       if (p->fontwidth < 16)
+           continue;
+       ((u32 *)dest)[12] = (-(bits >> 3 & 1) & eorx) ^ bgx;
+       ((u32 *)dest)[13] = (-(bits >> 2 & 1) & eorx) ^ bgx;
+       ((u32 *)dest)[14] = (-(bits >> 1 & 1) & eorx) ^ bgx;
+       ((u32 *)dest)[15] = (-(bits & 1) & eorx) ^ bgx;
+#endif
     }
 }
 
-void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p, 
+void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p,
                       const unsigned short *s, int count, int yy, int xx)
 {
-    u8 *cdat, c, *dest, *dest0;
+    u8 *cdat, *dest, *dest0, bits;
+    u16 c;
     int rows, bytes = p->next_line;
     u32 eorx, fgx, bgx;
 
-    dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 32;
+    dest0 = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 4;
     fgx = fbcon_cfb32_cmap[attr_fgcol(p, *s)];
     bgx = fbcon_cfb32_cmap[attr_bgcol(p, *s)];
     eorx = fgx ^ bgx;
     while (count--) {
-       c = *s++;
+       c = *s++ & p->charmask;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
        cdat = p->fontdata + c * p->fontheight;
-
-       for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
-           u8 bits = *cdat++;
+#else
+       if (p->fontwidth <= 8)
+           cdat = p->fontdata + c * p->fontheight;
+       else
+           cdat = p->fontdata + (c * p->fontheight << 1);
+#endif
+       for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) {
+           bits = *cdat++;
            ((u32 *)dest)[0] = (-(bits >> 7) & eorx) ^ bgx;
            ((u32 *)dest)[1] = (-(bits >> 6 & 1) & eorx) ^ bgx;
            ((u32 *)dest)[2] = (-(bits >> 5 & 1) & eorx) ^ bgx;
            ((u32 *)dest)[3] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+           if (p->fontwidth < 8)
+               continue;
+#endif
            ((u32 *)dest)[4] = (-(bits >> 3 & 1) & eorx) ^ bgx;
            ((u32 *)dest)[5] = (-(bits >> 2 & 1) & eorx) ^ bgx;
            ((u32 *)dest)[6] = (-(bits >> 1 & 1) & eorx) ^ bgx;
            ((u32 *)dest)[7] = (-(bits & 1) & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+           if (p->fontwidth < 12)
+               continue;
+           bits = *cdat++;
+           ((u32 *)dest)[8] = (-(bits >> 7) & eorx) ^ bgx;
+           ((u32 *)dest)[9] = (-(bits >> 6 & 1) & eorx) ^ bgx;
+           ((u32 *)dest)[10] = (-(bits >> 5 & 1) & eorx) ^ bgx;
+           ((u32 *)dest)[11] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+           if (p->fontwidth < 16)
+               continue;
+           ((u32 *)dest)[12] = (-(bits >> 3 & 1) & eorx) ^ bgx;
+           ((u32 *)dest)[13] = (-(bits >> 2 & 1) & eorx) ^ bgx;
+           ((u32 *)dest)[14] = (-(bits >> 1 & 1) & eorx) ^ bgx;
+           ((u32 *)dest)[15] = (-(bits & 1) & eorx) ^ bgx;
+#endif
        }
-       dest0 += 32;
+       dest0 += p->fontwidth*4;
     }
 }
 
@@ -164,16 +219,61 @@ void fbcon_cfb32_revc(struct display *p, int xx, int yy)
     u8 *dest;
     int bytes = p->next_line, rows;
 
-    dest = p->screen_base + yy * p->fontheight * bytes + xx * 32;
-    for (rows = p->fontheight ; rows-- ; dest += bytes) {
-       ((u32 *)dest)[0] ^= 0xffffffff;
-       ((u32 *)dest)[1] ^= 0xffffffff;
-       ((u32 *)dest)[2] ^= 0xffffffff;
-       ((u32 *)dest)[3] ^= 0xffffffff;
-       ((u32 *)dest)[4] ^= 0xffffffff;
-       ((u32 *)dest)[5] ^= 0xffffffff;
-       ((u32 *)dest)[6] ^= 0xffffffff;
-       ((u32 *)dest)[7] ^= 0xffffffff;
+    dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 4;
+    for (rows = p->fontheight; rows--; dest += bytes) {
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+       ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff;
+       ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
+       ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+       ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff;
+#else
+       switch (p->fontwidth) {
+       case 16:
+           ((u32 *)dest)[12] ^= 0xffffffff; ((u32 *)dest)[13] ^= 0xffffffff;
+           ((u32 *)dest)[14] ^= 0xffffffff; ((u32 *)dest)[15] ^= 0xffffffff;
+           /* FALL THROUGH */
+       case 12:
+           ((u32 *)dest)[8] ^= 0xffffffff; ((u32 *)dest)[9] ^= 0xffffffff;
+           ((u32 *)dest)[10] ^= 0xffffffff; ((u32 *)dest)[11] ^= 0xffffffff;
+           /* FALL THROUGH */
+       case 8:
+           ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff;
+           ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
+           /* FALL THROUGH */
+       case 4:
+           ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+           ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff;
+           /* FALL THROUGH */
+       }
+#endif
+    }
+}
+
+void fbcon_cfb32_clear_margins(struct vc_data *conp, struct display *p)
+{
+    u8 *dest0;
+    u32 *dest;
+    int bytes = p->next_line;
+    u32 bgx;
+    int i, j;
+
+    unsigned int right_start = conp->vc_cols*p->fontwidth;
+    unsigned int right_width = p->var.xres_virtual-right_start;
+    unsigned int bottom_start = conp->vc_rows*p->fontheight;
+    unsigned int bottom_width = p->var.yres_virtual-bottom_start;
+
+    bgx = fbcon_cfb32_cmap[attr_bgcol_ec(p, conp)];
+
+    if (right_width) {
+       dest0 = p->screen_base+right_start*4;
+       for (i = 0; i < bottom_start; i++, dest0 += bytes)
+           for (j = 0, dest = (u32 *)dest0; j < right_width; j++)
+               *dest++ = bgx;
+    }
+    if (bottom_width) {
+       dest = (u32 *)(p->screen_base+bottom_start*bytes);
+       for (i = 0; i < bytes*bottom_width/4; i++)
+           *dest++ = bgx;
     }
 }
 
@@ -184,7 +284,8 @@ void fbcon_cfb32_revc(struct display *p, int xx, int yy)
 
 struct display_switch fbcon_cfb32 = {
     fbcon_cfb32_setup, fbcon_cfb32_bmove, fbcon_cfb32_clear, fbcon_cfb32_putc,
-    fbcon_cfb32_putcs, fbcon_cfb32_revc, NULL, NULL, NULL, FONTWIDTH(8)
+    fbcon_cfb32_putcs, fbcon_cfb32_revc, NULL, NULL, fbcon_cfb32_clear_margins,
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 
 
index ee22abb1464d8c8a475ca32e2eba8fa903739bf6..3d3eda626d6ad1cddfa03a2e8e5aec7a57065de8 100644 (file)
@@ -2,8 +2,6 @@
      *  32 bpp packed pixel (cfb32)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FBCON_CFB32_MODULE)
 #define FBCON_HAS_CFB32
@@ -26,3 +24,4 @@ extern void fbcon_cfb32_putc(struct vc_data *conp, struct display *p, int c,
 extern void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p,
                              const unsigned short *s, int count, int yy, int xx);
 extern void fbcon_cfb32_revc(struct display *p, int xx, int yy);
+extern void fbcon_cfb32_clear_margins(struct vc_data *conp, struct display *p);
index 4b7b54f0da528793a11e5a034d63ce9613711ce8..4d3f196bf3596dec96ebaec6fc5dd67d9d7d68be 100644 (file)
@@ -131,7 +131,7 @@ void fbcon_cfb4_putc(struct vc_data *conp, struct display *p, int c, int yy,
        u32 eorx,fgx,bgx;
 
        dest = p->screen_base + yy * p->fontheight * bytes + xx * 4;
-       cdat = p->fontdata + (c & 0xff) * p->fontheight;
+       cdat = p->fontdata + (c & p->charmask) * p->fontheight;
 
        fgx=15;/*attr_fgcol(p,c);*/
        bgx=attr_bgcol(p,c);
@@ -152,7 +152,8 @@ void fbcon_cfb4_putc(struct vc_data *conp, struct display *p, int c, int yy,
 void fbcon_cfb4_putcs(struct vc_data *conp, struct display *p, 
                      const unsigned short *s, int count, int yy, int xx)
 {
-       u8 *cdat, c, *dest, *dest0;
+       u8 *cdat, *dest, *dest0;
+       u16 c;
        int rows,bytes=p->next_line;
        u32 eorx, fgx, bgx;
 
@@ -167,7 +168,7 @@ void fbcon_cfb4_putcs(struct vc_data *conp, struct display *p,
        bgx |= (bgx << 16);
        eorx = fgx ^ bgx;
        while (count--) {
-               c = *s++;
+               c = *s++ & p->charmask;
                cdat = p->fontdata + c * p->fontheight;
 
                for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
index df08288cde24a5b0fab9267dcfccdb4aa00166d1..cc565efb3065bb40e6e8d92fb7cdbb45f3d772ca 100644 (file)
@@ -2,8 +2,6 @@
      *  4 bpp packed pixel (cfb4)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB4) || defined(CONFIG_FBCON_CFB4_MODULE)
 #define FBCON_HAS_CFB4
index cebf6bd23f3c9cbc3807f5cea470efdb6b3c9cc2..8ee2a83c82d2b060ae2e4977d557e01f021d6d2d 100644 (file)
@@ -110,9 +110,9 @@ void fbcon_cfb8_putc(struct vc_data *conp, struct display *p, int c, int yy,
 
     dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth;
     if (p->fontwidth <= 8)
-       cdat = p->fontdata + (c & 0xff) * p->fontheight;
+       cdat = p->fontdata + (c & p->charmask) * p->fontheight;
     else
-       cdat = p->fontdata + ((c & 0xff) * p->fontheight << 1);
+       cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1);
 
     fgx=attr_fgcol(p,c);
     bgx=attr_bgcol(p,c);
@@ -122,16 +122,19 @@ void fbcon_cfb8_putc(struct vc_data *conp, struct display *p, int c, int yy,
     bgx |= (bgx << 16);
     eorx = fgx ^ bgx;
 
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
     switch (p->fontwidth) {
     case 4:
        for (rows = p->fontheight ; rows-- ; dest += bytes)
            ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat++ >> 4] & eorx) ^ bgx;
         break;
     case 8:
+#endif
        for (rows = p->fontheight ; rows-- ; dest += bytes) {
            ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
            ((u32 *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx;
         }
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
         break;
     case 12:
     case 16:
@@ -145,12 +148,14 @@ void fbcon_cfb8_putc(struct vc_data *conp, struct display *p, int c, int yy,
         }
         break;
     }
+#endif
 }
 
 void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p, 
                      const unsigned short *s, int count, int yy, int xx)
 {
-    u8 *cdat, c, *dest, *dest0;
+    u8 *cdat, *dest, *dest0;
+    u16 c;
     int rows,bytes=p->next_line;
     u32 eorx, fgx, bgx;
 
@@ -162,10 +167,11 @@ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p,
     bgx |= (bgx << 8);
     bgx |= (bgx << 16);
     eorx = fgx ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
     switch (p->fontwidth) {
     case 4:
        while (count--) {
-           c = *s++;
+           c = *s++ & p->charmask;
            cdat = p->fontdata + c * p->fontheight;
 
            for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes)
@@ -174,8 +180,9 @@ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p,
         }
         break;
     case 8:
+#endif
        while (count--) {
-           c = *s++;
+           c = *s++ & p->charmask;
            cdat = p->fontdata + c * p->fontheight;
 
            for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
@@ -184,11 +191,12 @@ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p,
            }
            dest0+=8;
         }
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
         break;
     case 12:
     case 16:
        while (count--) {
-           c = *s++;
+           c = *s++ & p->charmask;
            cdat = p->fontdata + (c * p->fontheight << 1);
 
            for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
@@ -203,6 +211,7 @@ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p,
         }
         break;
     }
+#endif
 }
 
 void fbcon_cfb8_revc(struct display *p, int xx, int yy)
@@ -212,6 +221,10 @@ void fbcon_cfb8_revc(struct display *p, int xx, int yy)
 
     dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth;
     for (rows = p->fontheight ; rows-- ; dest += bytes) {
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+       ((u32 *)dest)[1] ^= 0x0f0f0f0f;
+       ((u32 *)dest)[0] ^= 0x0f0f0f0f;
+#else
        switch (p->fontwidth) {
        case 16: ((u32 *)dest)[3] ^= 0x0f0f0f0f; /* FALL THROUGH */
        case 12: ((u32 *)dest)[2] ^= 0x0f0f0f0f; /* FALL THROUGH */
@@ -219,6 +232,7 @@ void fbcon_cfb8_revc(struct display *p, int xx, int yy)
        case 4: ((u32 *)dest)[0] ^= 0x0f0f0f0f;  /* FALL THROUGH */
        default: break;
        }
+#endif
     }
 }
 
index e1d8170ed58560f11ffffee06a770fd56f7aa316..419de250d0dfa2ba7f94139fa789a02b1dff46f1 100644 (file)
@@ -2,8 +2,6 @@
      *  8 bpp packed pixel (cfb8)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FBCON_CFB8_MODULE)
 #define FBCON_HAS_CFB8
index 3bd98cde556c3ad73c6a00684a02c21c6c94e331..b87a1d10caaae70989926dd51eed2a3558030d45 100644 (file)
@@ -103,7 +103,7 @@ void fbcon_ilbm_putc(struct vc_data *conp, struct display *p, int c, int yy,
     int fg0, bg0, fg, bg;
 
     dest = p->screen_base+yy*p->fontheight*p->next_line+xx;
-    cdat = p->fontdata+(c&0xff)*p->fontheight;
+    cdat = p->fontdata+(c&p->charmask)*p->fontheight;
     fg0 = attr_fgcol(p,c);
     bg0 = attr_bgcol(p,c);
 
@@ -149,7 +149,7 @@ void fbcon_ilbm_putcs(struct vc_data *conp, struct display *p,
 {
     u8 *dest0, *dest, *cdat1, *cdat2, *cdat3, *cdat4;
     u_int rows, i;
-    u8 c1, c2, c3, c4;
+    u16 c1, c2, c3, c4;
     u32 d;
     int fg0, bg0, fg, bg;
 
@@ -159,7 +159,7 @@ void fbcon_ilbm_putcs(struct vc_data *conp, struct display *p,
 
     while (count--)
        if (xx&3 || count < 3) {        /* Slow version */
-           c1 = *s++;
+           c1 = *s++ & p->charmask;
            dest = dest0++;
            xx++;
 
@@ -185,10 +185,10 @@ void fbcon_ilbm_putcs(struct vc_data *conp, struct display *p,
                }
            }
        } else {                /* Fast version */
-           c1 = s[0];
-           c2 = s[1];
-           c3 = s[2];
-           c4 = s[3];
+           c1 = s[0] & p->charmask;
+           c2 = s[1] & p->charmask;
+           c3 = s[2] & p->charmask;
+           c4 = s[3] & p->charmask;
 
            dest = dest0;
            cdat1 = p->fontdata+c1*p->fontheight;
index 13292f28799f9bef2b5def956b2a8d6ccd679530..bd066f49b7a72ce910010edc3a60a353321ce8eb 100644 (file)
@@ -2,8 +2,6 @@
      *  Amiga interleaved bitplanes (ilbm)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_ILBM) || defined(CONFIG_FBCON_ILBM_MODULE)  
 #define FBCON_HAS_ILBM 
index 3e1e67607d178716cef80587682eeb49eb64eaab..3cd8ab81ea21345e4b4cbb729d93901f1ef3e11d 100644 (file)
@@ -307,7 +307,7 @@ void fbcon_iplan2p2_putc(struct vc_data *conp, struct display *p, int c,
     u16 eorx, fgx, bgx, fdx;
 
     dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*4 + (xx & 1);
-    cdat = p->fontdata + (c & 0xff) * p->fontheight;
+    cdat = p->fontdata + (c & p->charmask) * p->fontheight;
 
     fgx = expand2w(COLOR_2P(attr_fgcol(p,c)));
     bgx = expand2w(COLOR_2P(attr_bgcol(p,c)));
@@ -323,7 +323,8 @@ void fbcon_iplan2p2_putcs(struct vc_data *conp, struct display *p,
                          const unsigned short *s, int count, int yy, int xx)
 {
     u8 *dest, *dest0;
-    u8 *cdat, c;
+    u8 *cdat;
+    u16 c;
     int rows;
     int bytes;
     u16 eorx, fgx, bgx, fdx;
@@ -335,7 +336,7 @@ void fbcon_iplan2p2_putcs(struct vc_data *conp, struct display *p,
     eorx = fgx ^ bgx;
 
     while (count--) {
-       c = *s++;
+       c = *s++ & p->charmask;
        cdat  = p->fontdata + (c * p->fontheight);
 
        for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
index 07b5a0d31e5fc0d52785bff0d66fff25bf600475..4e8502c05e9dfd378d02853adbb1e2c992cc77f9 100644 (file)
@@ -2,8 +2,6 @@
      *  Atari interleaved bitplanes (2 planes) (iplan2p2)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P2_MODULE)
 #define FBCON_HAS_IPLAN2P2
index 844398127b158895cc5a24792319f9e4e2f5aa09..4bd21c36654569077e350f0aa0b6970ad04ea983 100644 (file)
@@ -317,7 +317,7 @@ void fbcon_iplan2p4_putc(struct vc_data *conp, struct display *p, int c,
     u32 eorx, fgx, bgx, fdx;
 
     dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*8 + (xx & 1);
-    cdat = p->fontdata + (c & 0xff) * p->fontheight;
+    cdat = p->fontdata + (c & p->charmask) * p->fontheight;
 
     fgx = expand4l(attr_fgcol(p,c));
     bgx = expand4l(attr_bgcol(p,c));
@@ -333,7 +333,8 @@ void fbcon_iplan2p4_putcs(struct vc_data *conp, struct display *p,
                          const unsigned short *s, int count, int yy, int xx)
 {
     u8 *dest, *dest0;
-    u8 *cdat, c;
+    u8 *cdat;
+    u16 c;
     int rows;
     int bytes;
     u32 eorx, fgx, bgx, fdx;
@@ -352,7 +353,7 @@ void fbcon_iplan2p4_putcs(struct vc_data *conp, struct display *p,
        * cache :-(
        */
 
-       c = *s++;
+       c = *s++ & p->charmask;
        cdat  = p->fontdata + (c * p->fontheight);
 
        for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
index 6d501a58e7377c7ca1f56a95db16a4442dd5c095..7dd3eded263000df5631cecff3553bea46d6cda5 100644 (file)
@@ -2,8 +2,6 @@
      *  Atari interleaved bitplanes (4 planes) (iplan2p4)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_IPLAN2P4) || defined(CONFIG_FBCON_IPLAN2P4_MODULE)
 #define FBCON_HAS_IPLAN2P4
index 2db180dd7c4d4d4e244acc8580e05c27fb8871ce..aa2f4d2f131bc631f99ce2643f5902f2e43a4d5a 100644 (file)
@@ -349,7 +349,7 @@ void fbcon_iplan2p8_putc(struct vc_data *conp, struct display *p, int c,
     u32 eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
 
     dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*16 + (xx & 1);
-    cdat = p->fontdata + (c & 0xff) * p->fontheight;
+    cdat = p->fontdata + (c & p->charmask) * p->fontheight;
 
     expand8dl(attr_fgcol(p,c), &fgx1, &fgx2);
     expand8dl(attr_bgcol(p,c), &bgx1, &bgx2);
@@ -365,7 +365,8 @@ void fbcon_iplan2p8_putcs(struct vc_data *conp, struct display *p,
                          const unsigned short *s, int count, int yy, int xx)
 {
     u8 *dest, *dest0;
-    u8 *cdat, c;
+    u8 *cdat;
+    u16 c;
     int rows;
     int bytes;
     u32 eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
@@ -387,7 +388,7 @@ void fbcon_iplan2p8_putcs(struct vc_data *conp, struct display *p,
        * cache :-(
        */
 
-       c = *s++;
+       c = *s++ & p->charmask;
        cdat  = p->fontdata + (c * p->fontheight);
 
        for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
index ba298f84c4d78e0bd749e14ceeac7b93e176381e..9e0f11f8df10cbef6c6cb4b420750c188b72cf25 100644 (file)
@@ -2,8 +2,6 @@
      *  Atari interleaved bitplanes (8 planes) (iplan2p8)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_IPLAN2P8) || defined(CONFIG_FBCON_IPLAN2P8_MODULE)
 #define FBCON_HAS_IPLAN2P8
index a1ba4ce9e5fc8464992509d29ab6b5cb74b42a67..a4bac8fae806271b7297d450dc178b835d54a349 100644 (file)
@@ -272,7 +272,7 @@ void fbcon_mac_putc(struct vc_data *conp, struct display *p, int c, int yy,
    u8 d;
    int j;
 
-   cdat = p->fontdata+(c&0xff)*p->fontheight;
+   cdat = p->fontdata+(c&p->charmask)*p->fontheight;
    bold = attr_bold(p,c);
    ch_reverse = attr_reverse(p,c);
    ch_underline = attr_underline(p,c);
index 62d2ae6d35053b1e987676794b65ae09560898d4..b19464d53b50ef008da7dbbdea7ea0275322df54 100644 (file)
@@ -2,8 +2,6 @@
      *  Mac variable bpp packed pixels (mac)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_MAC) || defined(CONFIG_FBCON_MAC_MODULE)
 #define FBCON_HAS_MAC
index dafa4ad5b53e416c64aad2954c37bd07507bac41..b8f575859997aab70899ee8fdacf84e25ae60042 100644 (file)
@@ -90,7 +90,7 @@ void fbcon_mfb_putc(struct vc_data *conp, struct display *p, int c, int yy,
     u8 d;
 
     dest = p->screen_base+yy*p->fontheight*p->next_line+xx;
-    cdat = p->fontdata+(c&0xff)*p->fontheight;
+    cdat = p->fontdata+(c&p->charmask)*p->fontheight;
     bold = attr_bold(p,c);
     revs = attr_reverse(p,c);
     underl = attr_underline(p,c);
@@ -112,7 +112,8 @@ void fbcon_mfb_putcs(struct vc_data *conp, struct display *p,
 {
     u8 *dest, *dest0, *cdat;
     u_int rows, bold, revs, underl;
-    u8 c, d;
+    u8 d;
+    u16 c;
 
     dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx;
     bold = attr_bold(p,*s);
@@ -120,7 +121,7 @@ void fbcon_mfb_putcs(struct vc_data *conp, struct display *p,
     underl = attr_underline(p,*s);
 
     while (count--) {
-       c = *s++;
+       c = *s++ & p->charmask;
        dest = dest0++;
        cdat = p->fontdata+c*p->fontheight;
        for (rows = p->fontheight; rows--; dest += p->next_line) {
index 77f312e31dbfede84d6b3361eafb260b4245e4b2..a300d8cc6796c8517db9924c74555807bc23b9e4 100644 (file)
@@ -2,8 +2,6 @@
      *  Monochrome (mfb)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_MFB_MODULE)
 #define FBCON_HAS_MFB
index 7d62e213c4da68f74304ffdd5e2a20b6ac62c5fc..259780247b5176a1f50076e09bcf107c4dd5aa4f 100644 (file)
@@ -2,8 +2,6 @@
      *  VGA characters/attributes
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_VGA) || defined(CONFIG_FBCON_VGA_MODULE)
 #define FBCON_HAS_VGA
index 1962f1b0aad25b6c27608a72e8c08b18983437f0..cdec5a29d932f14cff02ba12107ad0828a2a962d 100644 (file)
@@ -25,7 +25,8 @@
  *                        Andreas Schwab
  *
  *  Hardware cursor support added by Emmanuel Marty (core@ggi-project.org)
- *  Smart redraw scrolling, arbitrary font width support added by 
+ *  Smart redraw scrolling, arbitrary font width support, 512char font support
+ *  added by 
  *                         Jakub Jelinek (jj@ultra.linux.cz)
  *
  *
 #define LOGO_LINE      (LOGO_W/8)
 
 struct display fb_display[MAX_NR_CONSOLES];
-
+static int logo_lines;
+static int logo_shown = -1;
 
 /*
  * Emmanuel: fbcon will now use a hardware cursor if the
@@ -396,11 +398,9 @@ static void fbcon_setup(int con, int init, int logo)
     int nr_rows, nr_cols;
     int old_rows, old_cols;
     unsigned short *save = NULL, *r, *q;
-    int logo_lines = 0;
     /* Only if not module */
     extern int initmem_freed;
     struct fbcon_font_desc *font;
-    
     if (con != fg_console || initmem_freed || p->type == FB_TYPE_TEXT)
        logo = 0;
 
@@ -485,6 +485,10 @@ static void fbcon_setup(int con, int init, int logo)
     }
     p->vrows = p->var.yres_virtual/p->fontheight;
     conp->vc_can_do_color = p->var.bits_per_pixel != 1;
+    p->fgshift = 8;
+    p->bgshift = 12;
+    p->charmask = 0xff;
+    conp->vc_hi_font_mask = 0;
 
     if (!p->dispsw) {
        printk(KERN_WARNING "fbcon_setup: type %d (aux %d, depth %d) not "
@@ -512,8 +516,11 @@ static void fbcon_setup(int con, int init, int logo)
            update_screen(con); /* So that we set origin correctly */
     }
        
-    if (logo)
+    if (logo) {
+       logo_shown = fg_console;
        fbcon_show_logo(); /* This is protected above by initmem_freed */
+       conp->vc_top = logo_lines;
+    }
 }
 
 
@@ -1025,7 +1032,7 @@ static void fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
 {
     int unit = conp->vc_num;
     struct display *p = &fb_display[unit];
-
+    
     if (!p->can_soft_blank && console_blanked)
        return;
 
@@ -1033,9 +1040,9 @@ static void fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
        return;
 
     if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
-        (sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
-       ((dy <= p->cursor_y) && (p->cursor_y < dy+height) &&
-        (dx <= p->cursor_x) && (p->cursor_x < dx+width)))
+         (sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
+        ((dy <= p->cursor_y) && (p->cursor_y < dy+height) &&
+         (dx <= p->cursor_x) && (p->cursor_x < dx+width)))
        fbcon_cursor(conp, CM_ERASE);
 
     /*  Split blits that cross physical y_wrap case.
@@ -1048,7 +1055,6 @@ static void fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
     fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll);
 }
 
-
 static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
                            int height, int width, u_int y_break)
 {
@@ -1087,6 +1093,13 @@ static int fbcon_switch(struct vc_data *conp)
     struct display *p = &fb_display[unit];
     struct fb_info *info = p->fb_info;
 
+    if (logo_shown >= 0) {
+       struct vc_data *conp2 = vc_cons[logo_shown].d;
+       
+       if (conp2->vc_top == logo_lines && conp2->vc_bottom == conp2->vc_rows)
+               conp2->vc_top = 0;
+       logo_shown = -1;
+    }
     p->var.yoffset = p->yscroll*p->fontheight;
     switch (p->scrollmode) {
        case SCROLL_YWRAP:
@@ -1153,23 +1166,62 @@ static int fbcon_blank(struct vc_data *conp, int blank)
 static inline int fbcon_get_font(int unit, struct console_font_op *op)
 {
     struct display *p = &fb_display[unit];
-    char *data = op->data;
+    u8 *data = op->data;
     int i, j;
 
-    if (p->fontwidth != 8)             /* FIXME: Implement for wide fonts */
-        return -EINVAL;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+    if (p->fontwidth != 8) return -EINVAL;
+#endif
     op->width = p->fontwidth;
     op->height = p->fontheight;
-    op->charcount = 256;
-    for (i = 0; i < 256; i++)
-       for (j = 0; j < p->fontheight; j++)
-           data[i*32+j] = p->fontdata[i*p->fontheight+j];
+    op->charcount = (p->charmask == 0x1ff) ? 512 : 256;
+    if (!op->data) return 0;
+    
+    if (op->width <= 8) {
+       for (i = 0; i < op->charcount; i++) {
+           for (j = 0; j < p->fontheight; j++)
+               *data++ = p->fontdata[i*p->fontheight+j];
+           data += 32 - p->fontheight;
+       }
+    }
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+    else if (op->width <= 16) {
+       for (i = 0; i < op->charcount; i++) {
+           for (j = 0; j < p->fontheight; j++) {
+               *data++ = ((u16 *)p->fontdata)[i*p->fontheight+j] >> 8;
+               *data++ = ((u16 *)p->fontdata)[i*p->fontheight+j];
+           }
+           data += 2 * (32 - p->fontheight);
+       }
+    } else if (op->width <= 24) {
+       for (i = 0; i < op->charcount; i++) {
+           for (j = 0; j < p->fontheight; j++) {
+               *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 24;
+               *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 16;
+               *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 8;
+           }
+           data += 3 * (32 - p->fontheight);
+       }
+    } else {
+       for (i = 0; i < op->charcount; i++) {
+           for (j = 0; j < p->fontheight; j++) {
+               *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 24;
+               *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 16;
+               *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 8;
+               *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j];
+           }
+           data += 4 * (32 - p->fontheight);
+       }
+    }
+#endif
     return 0;
 }
 
 
 #define REFCOUNT(fd)   (((int *)(fd))[-1])
 #define FNTSIZE(fd)    (((int *)(fd))[-2])
+#define FNTCHARCNT(fd) (((int *)(fd))[-3])
+#define FNTSUM(fd)     (((int *)(fd))[-4])
 
 static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int userfont)
 {
@@ -1177,6 +1229,7 @@ static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int
     int resize;
     int w = op->width;
     int h = op->height;
+    int cnt;
     char *old_data = NULL;
 
     if (!fontwidthvalid(p,w)) {
@@ -1188,11 +1241,28 @@ static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int
     resize = (w != p->fontwidth) || (h != p->fontheight);
     if (p->userfont)
         old_data = p->fontdata;
+    if (userfont)
+        cnt = FNTCHARCNT(data);
+    else
+       cnt = 256;
     p->fontdata = data;
     if ((p->userfont = userfont))
         REFCOUNT(data)++;
     p->fontwidth = w;
     p->fontheight = h;
+    if (p->conp->vc_hi_font_mask && cnt == 256) {
+       p->conp->vc_hi_font_mask = 0;
+       p->conp->vc_complement_mask >>= 1;
+       p->fgshift--;
+       p->bgshift--;
+       p->charmask = 0xff;
+    } else if (!p->conp->vc_hi_font_mask && cnt == 512) {
+       p->conp->vc_hi_font_mask = 0x100;
+       p->conp->vc_complement_mask <<= 1;
+       p->fgshift++;
+       p->bgshift++;
+       p->charmask = 0x1ff;
+    }
     fbcon_font_widths(p);
 
     if (resize) {
@@ -1210,7 +1280,7 @@ static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int
        update_screen( unit );
 
     if (old_data && (--REFCOUNT(old_data) == 0))
-       kfree( old_data - 2*sizeof(int) );
+       kfree( old_data - 4*sizeof(int) );
 
     return 0;
 }
@@ -1227,6 +1297,8 @@ static inline int fbcon_copy_font(int unit, struct console_font_op *op)
     od = &fb_display[h];
     if (od->fontdata == p->fontdata)
         return 0; /* already the same font... */
+    op->width = od->fontwidth;
+    op->height = od->fontheight;
     return fbcon_do_set_font(unit, op, od->fontdata, od->userfont);
 }
 
@@ -1234,21 +1306,94 @@ static inline int fbcon_set_font(int unit, struct console_font_op *op)
 {
     int w = op->width;
     int h = op->height;
-    int size = (w+7)/8 * h * 256;
-    int i, j;
-    u8 *new_data, *data = op->data;
+    int size = h;
+    int i, j, k;
+    u8 *new_data, *data = op->data, c, *p;
+    u32 d;
 
-    if (w != 8 || op->charcount != 256)
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+    if (w != 8)
+       return -EINVAL;
+#endif
+
+    if (w > 32 || (op->charcount != 256 && op->charcount != 512))
         return -EINVAL;
+    
+    if (w > 8) { 
+       if (w <= 16)
+               size *= 2;
+       else
+               size *= 4;
+    }
+    size *= op->charcount;
        
-    if (!(new_data = kmalloc( 2*sizeof(int)+size, GFP_USER )))
+    if (!(new_data = kmalloc( 4*sizeof(int)+size, GFP_USER )))
         return -ENOMEM;
-    new_data += 2*sizeof(int);
+    new_data += 4*sizeof(int);
     FNTSIZE(new_data) = size;
+    FNTCHARCNT(new_data) = op->charcount;
     REFCOUNT(new_data) = 0; /* usage counter */
-    for (i = 0; i < 256; i++)
-       for (j = 0; j < h; j++)
-           new_data[i*h+j] = data[i*32+j];
+    k = 0;
+    p = data;
+    if (w <= 8) {
+       for (i = 0; i < op->charcount; i++) {
+           for (j = 0; j < h; j++) {
+               c = *p++;
+               k += c;
+               new_data[i*h+j] = c;
+           }
+           p += 32 - h;
+       }
+    }
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+    else if (w <= 16) {
+       for (i = 0; i < op->charcount; i++) {
+           for (j = 0; j < h; j++) {
+               d = (p[0] << 8) | p[1];
+               p += 2;
+               k += d;
+               ((u16 *)new_data)[i*h+j] = d;
+           }
+           p += 2*(32 - h);
+       }
+    } else {
+       for (i = 0; i < op->charcount; i++) {
+           for (j = 0; j < h; j++) {
+               if (w <= 24) {
+                   d = (p[0] << 24) | 
+                       (p[1] << 16) | 
+                       (p[2] << 8);
+                   p += 3;
+               } else {
+                   d = (p[0] << 24) | 
+                       (p[1] << 16) | 
+                       (p[2] << 8) |
+                       p[3];
+                   p += 4;
+               }
+               k += d;
+               ((u32 *)new_data)[i*h+j] = d;
+           }
+           if (w <= 24)
+               p += 3*(32 - h);
+           else
+               p += 4*(32 - h);
+       }
+    }
+#endif
+    FNTSUM(new_data) = k;
+    /* Check if the same font is on some other console already */
+    for (i = 0; i < MAX_NR_CONSOLES; i++) {
+       if (fb_display[i].userfont &&
+           fb_display[i].fontdata &&
+           FNTSUM(fb_display[i].fontdata) == k &&
+           FNTSIZE(fb_display[i].fontdata) == size &&
+           !memcmp(fb_display[i].fontdata, new_data, size)) {
+           kfree(new_data - 4*sizeof(int));
+           new_data = fb_display[i].fontdata;
+           break;
+       }
+    }
     return fbcon_do_set_font(unit, op, new_data, 1);
 }
 
@@ -1269,7 +1414,6 @@ static inline int fbcon_set_def_font(int unit, struct console_font_op *op)
     }
     op->width = f->width;
     op->height = f->height;
-    op->charcount = 256;
     return fbcon_do_set_font(unit, op, f->data, 0);
 }
 
@@ -1372,7 +1516,6 @@ static int fbcon_scrolldelta(struct vc_data *conp, int lines)
     return 0;
 }
 
-
 __initfunc(static int fbcon_show_logo( void ))
 {
     struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */
index 39a8b22434c21ac780aaa463e1a99a152ba9f4da..98091ba0c592b6e43a754ab0a7eac36065d8f94c 100644 (file)
@@ -11,6 +11,7 @@
 #ifndef __VIDEO_FBCON_H
 #define __VIDEO_FBCON_H
 
+#include <linux/config.h>
 #include <linux/console_struct.h>
 
 
@@ -35,11 +36,21 @@ struct display_switch {
     unsigned int fontwidthmask;      /* 1 at (1 << (width - 1)) if width is supported */
 }; 
 
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+
+/* fontwidth w is supported by dispsw */
+#define FONTWIDTH(w)   (1 << ((8) - 1))
+/* fontwidths w1-w2 inclusive are supported by dispsw */
+#define FONTWIDTHRANGE(w1,w2)  FONTWIDTH(8)
+
+#else
+
 /* fontwidth w is supported by dispsw */
 #define FONTWIDTH(w)   (1 << ((w) - 1))
 /* fontwidths w1-w2 inclusive are supported by dispsw */
 #define FONTWIDTHRANGE(w1,w2)  (FONTWIDTH(w2+1) - FONTWIDTH(w1))
 
+#endif
 
     /*
      *  Attribute Decoding
@@ -47,11 +58,11 @@ struct display_switch {
 
 /* Color */
 #define attr_fgcol(p,s)    \
-       (((s) >> ((p)->inverse ? 12 : 8)) & 0x0f)
+       (((s) >> ((p)->fgshift)) & 0x0f)
 #define attr_bgcol(p,s)    \
-       (((s) >> ((p)->inverse ? 8 : 12)) & 0x0f)
+       (((s) >> ((p)->bgshift)) & 0x0f)
 #define        attr_bgcol_ec(p,conp) \
-       (((conp)->vc_video_erase_char >> ((p)->inverse ? 8 : 12)) & 0x0f)
+       (((conp)->vc_video_erase_char >> ((p)->bgshift)) & 0x0f)
 
 /* Monochrome */
 #define attr_bold(p,s) \
index 730438d166a25ad2b47c458008aa55e49b5b1b6e..3ff6479803c7cf7677a3d1afc094a3a3cd8062da 100644 (file)
 #include <asm/uaccess.h>
 
 
-
 static int currcon = 0;
 
-static struct display disp;
-
-
-    /*
-     *  `Generic' versions of the frame buffer device operations
-     */
-
-extern int fbgen_get_fix(struct fb_fix_screeninfo *fix, int con,
-                        struct fb_info *info);
-extern int fbgen_get_var(struct fb_var_screeninfo *var, int con,
-                        struct fb_info *info);
-extern int fbgen_set_var(struct fb_var_screeninfo *var, int con,
-                        struct fb_info *info);
-extern int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-                         struct fb_info *info);
-extern int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-                         struct fb_info *info);
-extern int fbgen_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info);
-extern int fbgen_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg, int con,
-                      struct fb_info *info);
-
-
-    /*
-     *  Helper functions
-     */
-
-int fbgen_do_set_var(struct fb_var_screeninfo *var, int isactive,
-                    struct fb_info_gen *info);
-void fbgen_set_disp(int con, struct fb_info_gen *info);
-void fbgen_install_cmap(int con, struct fb_info_gen *info);
-int fbgen_update_var(int con, struct fb_info *info);
-int fbgen_switch(int con, struct fb_info *info);
-void fbgen_blank(int blank, struct fb_info *info);
-
 
 /* ---- `Generic' versions of the frame buffer device operations ----------- */
 
@@ -156,9 +119,10 @@ int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con,
     else
        if (fb_display[con].cmap.len)   /* non default colormap ? */
            fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-       else
-           fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
-                        cmap, kspc ? 0 : 2);
+       else {
+           int size = fb_display[con].var.bits_per_pixel == 16 ? 64 : 256;
+           fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+       }
     return 0;
 }
 
@@ -175,8 +139,8 @@ int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con,
     int err;
 
     if (!fb_display[con].cmap.len) {   /* no colormap allocated ? */
-       if ((err = fb_alloc_cmap(&fb_display[con].cmap,
-                                1 << fb_display[con].var.bits_per_pixel, 0)))
+       int size = fb_display[con].var.bits_per_pixel == 16 ? 64 : 256;
+       if ((err = fb_alloc_cmap(&fb_display[con].cmap, size, 0)))
            return err;
     }
     if (con == currcon)                        /* current console ? */
@@ -272,7 +236,7 @@ void fbgen_set_disp(int con, struct fb_info_gen *info)
     if (con >= 0)
        display = &fb_display[con];
     else
-       display = &disp;        /* used during initialization */
+       display = info->info.disp;      /* used during initialization */
 
     if (con == -1)
        fbhw->get_par(&par, info);
@@ -314,9 +278,11 @@ void fbgen_install_cmap(int con, struct fb_info_gen *info)
     if (fb_display[con].cmap.len)
        fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1,
                    fbhw->setcolreg, &info->info);
-    else
-       fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
-                   &fb_display[con].var, 1, fbhw->setcolreg, &info->info);
+    else {
+       int size = fb_display[con].var.bits_per_pixel == 16 ? 64 : 256;
+       fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1,
+                   fbhw->setcolreg, &info->info);
+    }
 }
 
 
index ace9a2c4b7047ff97fea46d7383ff5ea950d3495..007afe4af9c0f7f11050e5f2134b079f929faae3 100644 (file)
@@ -1,6 +1,5 @@
 /* Acorn-like font definition, with PC graphics characters */
 
-#include <linux/config.h>
 #include "font.h"
 
 static unsigned char acorndata_8x8[] = {
index aa09773bc95b14f5575f128d7cf80e151876ba14..72f29410a46b6991f3888288bcc11415c2249294 100644 (file)
@@ -30,7 +30,7 @@ static struct fbcon_font_desc *fbcon_fonts[] = {
     &font_vga_8x16,
 #endif
 #ifdef CONFIG_FONT_6x11
-#if !defined(CONFIG_MAC) && !defined(CONFIG_FB_SBUS)
+#if defined(CONFIG_MAC) || defined(CONFIG_FB_SBUS)
 #undef NO_FONTS
 #endif
     &font_vga_6x11,
@@ -40,7 +40,7 @@ static struct fbcon_font_desc *fbcon_fonts[] = {
     &font_sun_8x16,
 #endif
 #ifdef CONFIG_FONT_SUN12x22
-#if !defined(CONFIG_FB_SBUS) && !defined(CONFIG_FBCON_CFB8)
+#if defined(CONFIG_FB_SBUS) || defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || defined(CONFIG_FBCON_CFB32)
 #undef NO_FONTS
 #endif
     &font_sun_12x22,
index f1a8150b198023d40e0af8433b739de156e106c3..694f2df4d8b21daa9e66a97f9184fd06ce9d5715 100644 (file)
@@ -2,6 +2,7 @@
  *     We've been given MAC frame buffer info by the booter. Now go set it up
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -42,7 +43,7 @@ static struct fb_var_screeninfo macfb_defined={
        {0,0,0},        /* transparency */
        0,              /* standard pixel format */
        FB_ACTIVATE_NOW,
-       274,195,        /* 14" monitor - the late Mikael Nykvist's anyway */
+       274,195,        /* 14" monitor *Mikael Nykvist's anyway* */
        0,              /* The only way to accelerate a mac is .. */
        0L,0L,0L,0L,0L,
        0L,0L,0,        /* No sync info */
index da41fabdf401fd9459ee4a1f5e489211180901bd..2498162e7728ce18c08e3945cd891d23ae58026f 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 
+#include <linux/config.h>
 #include <linux/tty.h>
 #include <linux/fb.h>
 #include <linux/string.h>
index 29fb2593a9bbd976beda52abbd54a83fec7c88e6..e0e90c738422809107fc2b0e03950e914264411f 100644 (file)
@@ -50,3 +50,11 @@ extern int mac_vmode_to_var(int vmode, int cmode,
 extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
                            int *cmode);
 extern int mac_map_monitor_sense(int sense);
+
+
+    /*
+     *  Addresses in NVRAM where video mode and pixel size are stored.
+     */
+
+#define NV_VMODE               0x140f
+#define NV_CMODE               0x1410
index 01edad5cc791ad1ae39fc22527b48b0481338b4a..0e6e57f5665e31cedc9e03a42af61ece8d2d992c 100644 (file)
@@ -282,6 +282,13 @@ extern void s3triofb_init_of(struct device_node *dp);
 #ifdef CONFIG_FB_CT65550
 extern void chips_of_init(struct device_node *dp);
 #endif /* CONFIG_FB_CT65550 */
+#ifdef CONFIG_FB_CONTROL
+extern void control_of_init(struct device_node *dp);
+#endif /* CONFIG_FB_CONTROL */
+#ifdef CONFIG_FB_PLATINUM
+extern void platinum_of_init(struct device_node *dp);
+#endif /* CONFIG_FB_PLATINUM */
+
 
     /*
      *  Initialisation
@@ -318,6 +325,19 @@ __initfunc(void offb_init(void))
                continue;
            }
 #endif /* CONFIG_FB_CT65550 */
+#ifdef CONFIG_FB_CONTROL
+               if(!strcmp(dp->name, "control")) {
+                       control_of_init(dp);
+                       continue;
+               }
+#endif /* CONFIG_FB_CONTROL */
+#ifdef CONFIG_FB_PLATINUM
+           if (!strncmp(dp->name, "platinum",8)) {
+               printk("jonh: offb_init sees device node %s\n", dp->name);
+               platinum_of_init(dp);
+               continue;
+           }
+#endif /* CONFIG_FB_PLATINUM */
        }
 
        info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC);
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
new file mode 100644 (file)
index 0000000..f2a3e94
--- /dev/null
@@ -0,0 +1,1052 @@
+/*
+ *  platinumfb.c -- frame buffer device for the PowerMac 'platinum' display
+ *
+ *  Created 12 July 1998 by Dan Jacobowitz <dan@debian.org>
+ *  Copyright (C) 1998 Dan Jacobowitz
+ *
+ *  Frame buffer structure from:
+ *    drivers/video/chipsfb.c -- frame buffer device for
+ *    Chips & Technologies 65550 chip.
+ *
+ *    Copyright (C) 1998 Paul Mackerras
+ *
+ *    This file is derived from the Powermac "chips" driver:
+ *    Copyright (C) 1997 Fabio Riccardi.
+ *    And from the frame buffer device for Open Firmware-initialized devices:
+ *    Copyright (C) 1997 Geert Uytterhoeven.
+ *
+ *  Hardware information from:
+ *    platinum.c: Console support for PowerMac "platinum" display adaptor.
+ *    Copyright (C) 1996 Paul Mackerras
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/selection.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/nvram.h>
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#include <asm/vc_ioctl.h>
+#endif
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/adb.h>
+#include <asm/cuda.h>
+
+#include "fbcon.h"
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb16.h"
+#include "fbcon-cfb32.h"
+
+#include "macmodes.h"
+#include "platinumfb.h"
+
+static int currcon = 0;
+static int switching = 0;
+
+struct fb_par_platinum {
+       int     vmode, cmode;
+       int     xres, yres;
+       int     vxres, vyres;
+       int     xoffset, yoffset;
+};
+
+struct fb_info_platinum {
+       struct fb_info                  info;
+       struct fb_fix_screeninfo        fix;
+       struct fb_var_screeninfo        var;
+       struct display                  disp;
+       struct fb_par_platinum          par;
+       struct {
+               __u8 red, green, blue;
+       }                       palette[256];
+       
+       volatile struct cmap_regs       *cmap_regs;
+       unsigned long           cmap_regs_phys;
+       
+       volatile struct platinum_regs   *platinum_regs;
+       unsigned long           platinum_regs_phys;
+       
+       __u8                    *frame_buffer;
+       __u8                    *base_frame_buffer;
+       unsigned long           frame_buffer_phys;
+       
+       int                     sense;
+       unsigned long           total_vram;
+};
+
+/*
+ * Exported functions
+ */
+void platinum_init(void);
+void platinum_of_init(struct device_node *dp);
+
+static int platinum_open(struct fb_info *info, int user);
+static int platinum_release(struct fb_info *info, int user);
+static int platinum_get_fix(struct fb_fix_screeninfo *fix, int con,
+                        struct fb_info *info);
+static int platinum_get_var(struct fb_var_screeninfo *var, int con,
+                        struct fb_info *info);
+static int platinum_set_var(struct fb_var_screeninfo *var, int con,
+                        struct fb_info *info);
+static int platinum_pan_display(struct fb_var_screeninfo *var, int con,
+                            struct fb_info *info);
+static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+                         struct fb_info *info);
+static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+                         struct fb_info *info);
+static int platinum_ioctl(struct inode *inode, struct file *file, u_int cmd,
+                      u_long arg, int con, struct fb_info *info);
+
+static int read_platinum_sense(struct fb_info_platinum *p);
+static inline int platinum_vram_reqd(int video_mode, int color_mode);
+static void set_platinum_clock(struct fb_info_platinum *p, unsigned char *params);
+static void platinum_set_hardware(struct fb_info_platinum *p);
+static void platinum_par_to_all(struct fb_info_platinum *p, int init);
+static inline void platinum_par_to_var(struct fb_par_platinum *par, struct fb_var_screeninfo *var);
+static int platinum_var_to_par(struct fb_var_screeninfo *var,
+       struct fb_par_platinum *par, const struct fb_info *fb_info);
+
+static void platinum_init_info(struct fb_info *info, struct fb_info_platinum *p);
+static void platinum_par_to_display(struct fb_par_platinum *par,
+  struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_platinum *p);
+static void platinum_init_display(struct display *disp);
+static void platinum_par_to_fix(struct fb_par_platinum *par, struct fb_fix_screeninfo *fix,
+       struct fb_info_platinum *p);
+static void platinum_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_platinum *p);
+
+static struct fb_ops platinumfb_ops = {
+       platinum_open,
+       platinum_release,
+       platinum_get_fix,
+       platinum_get_var,
+       platinum_set_var,
+       platinum_get_cmap,
+       platinum_set_cmap,
+       platinum_pan_display,
+       platinum_ioctl
+};
+
+static int platinum_getcolreg(u_int regno, u_int *red, u_int *green,
+                            u_int *blue, u_int *transp, struct fb_info *info);
+static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                            u_int transp, struct fb_info *info);
+static void do_install_cmap(int con, struct fb_info *info);
+
+#define FUNCID { printk(KERN_INFO "entering %s\n", __FUNCTION__); }
+
+__openfirmware
+
+
+static int platinum_open(struct fb_info *info, int user)
+{
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+static int platinum_release(struct fb_info *info, int user)
+{
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+static int platinum_get_fix(struct fb_fix_screeninfo *fix, int con,
+                        struct fb_info *info)
+{
+       struct fb_info_platinum *cp = (struct fb_info_platinum *) info;
+
+       *fix = cp->fix;
+       return 0;
+}
+
+static int platinum_get_var(struct fb_var_screeninfo *var, int con,
+                        struct fb_info *info)
+{
+       struct fb_info_platinum *cp = (struct fb_info_platinum *) info;
+
+       *var = cp->var;
+       return 0;
+}
+
+/* Sets everything according to var */
+static int platinum_set_var(struct fb_var_screeninfo *var, int con,
+                        struct fb_info *info)
+{
+       struct fb_info_platinum *p = (struct fb_info_platinum *) info;
+       struct display *disp;
+       struct fb_par_platinum par;
+       int depthchange, err;
+
+//    FUNCID;
+       disp = (con >= 0) ? &fb_display[con] : &p->disp;
+       if((err = platinum_var_to_par(var, &par, info))) {
+               printk (KERN_ERR "Error in platinum_set_var, calling platinum_var_to_par: %d.\n", err);
+               return err;
+       }
+       
+       if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) {
+               printk("Not activating, in platinum_set_var.\n");
+               platinum_par_to_var(&par, var);
+               return 0;
+       }
+/* I know, we want to use fb_display[con], but grab certain info from p->var instead. */
+#define DIRTY(x) (p->var.x != var->x)
+       depthchange = DIRTY(bits_per_pixel);
+       if(!DIRTY(xres) && !DIRTY(yres) && !DIRTY(xres_virtual) &&
+          !DIRTY(yres_virtual) && !DIRTY(bits_per_pixel)) {
+               platinum_par_to_var(&par, var);
+               p->var = disp->var = *var;
+               return 0;
+       }
+       printk("Original bpp is %d, new bpp %d.\n", p->var.bits_per_pixel, var->bits_per_pixel);
+       /* OK, we're getting here at the right times... */
+       p->par = par;
+       platinum_par_to_var(&par, var);
+       p->var = *var;
+       platinum_par_to_fix(&par, &p->fix, p);
+       platinum_par_to_display(&par, disp, &p->fix, p);
+       p->disp = *disp;
+       
+       if(info->changevar && !switching)       /* Don't want to do this if just switching consoles. */
+               (*info->changevar)(con);
+       if(con == currcon)
+               platinum_set_hardware(p);
+       if(depthchange)
+               if((err = fb_alloc_cmap(&disp->cmap, 0, 0)))
+                       return err;
+       if(depthchange || switching)
+               do_install_cmap(con, info);
+       return 0;
+}
+
+static int platinum_pan_display(struct fb_var_screeninfo *var, int con,
+                            struct fb_info *info)
+{
+    /*
+     *  Pan (or wrap, depending on the `vmode' field) the display using the
+     *  `xoffset' and `yoffset' fields of the `var' structure.
+     *  If the values don't fit, return -EINVAL.
+     */
+
+//     FUNCID;
+       if (var->xoffset != 0 || var->yoffset != 0)
+               return -EINVAL;
+       return 0;
+}
+
+static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+                         struct fb_info *info)
+{
+//    FUNCID;
+       if (con == currcon)             /* current console? */
+               return fb_get_cmap(cmap, &fb_display[con].var, kspc,
+                                  platinum_getcolreg, info);
+       if (fb_display[con].cmap.len)   /* non default colormap? */
+               fb_copy_cmap(&fb_display[con].cmap, cmap, kspc? 0: 2);
+       else {
+               int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+               fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+       }
+       return 0;
+}
+
+static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+                        struct fb_info *info)
+{
+       struct display *disp = &fb_display[con];
+       int err;
+
+//    FUNCID;
+       if (disp->cmap.len == 0) {
+               int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+               err = fb_alloc_cmap(&disp->cmap, size, 0);
+               if (err)
+                       return err;
+       }
+
+       if (con == currcon)
+               return fb_set_cmap(cmap, &disp->var, kspc, platinum_setcolreg,
+                                  info);
+       fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
+       return 0;
+}
+
+static int platinum_ioctl(struct inode *inode, struct file *file, u_int cmd,
+                      u_long arg, int con, struct fb_info *info)
+{
+//     FUNCID;
+       return -EINVAL;
+}
+
+static int platinum_switch(int con, struct fb_info *info)
+{
+//    FUNCID;
+       if (fb_display[currcon].cmap.len)
+               fb_get_cmap(&fb_display[currcon].cmap,
+                           &fb_display[currcon].var, 1, platinum_getcolreg,
+                           info);
+       currcon = con;
+#if 0
+       platinum_var_to_par(&fb_display[currcon].var, &par, info);
+       platinum_set_par(&par, info); /*STOPPEDHERE - did i define that? */
+       do_install_cmap(con, info);
+#else
+       /* I see no reason not to do this.  Minus info->changevar(). */
+       /* DOH.  This makes platinum_set_var compare, you guessed it, */
+       /* fb_display[con].var (first param), and fb_display[con].var! */
+       /* Perhaps I just fixed that... */
+       switching = 1;
+       platinum_set_var(&fb_display[con].var, con, info);
+       switching = 0;
+#endif
+       return 0;
+}
+
+static int platinum_updatevar(int con, struct fb_info *info)
+{
+       return 0;
+}
+
+static void platinum_blank(int blank_mode, struct fb_info *info)
+{
+/*
+ *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
+ *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
+ *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
+ *  to e.g. a video mode which doesn't support it. Implements VESA suspend
+ *  and powerdown modes on hardware that supports disabling hsync/vsync:
+ *    blank_mode == 2: suspend vsync
+ *    blank_mode == 3: suspend hsync
+ *    blank_mode == 4: powerdown
+ */
+/* [danj] I think there's something fishy about those constants... */
+/*
+       struct fb_info_platinum *p = (struct fb_info_platinum *) info;
+       int     ctrl;
+
+       ctrl = ld_le32(&p->platinum_regs->ctrl.r) | 0x33;
+       if (blank_mode)
+               --blank_mode;
+       if (blank_mode & VESA_VSYNC_SUSPEND)
+               ctrl &= ~3;
+       if (blank_mode & VESA_HSYNC_SUSPEND)
+               ctrl &= ~0x30;
+       out_le32(&p->platinum_regs->ctrl.r, ctrl);
+*/
+/* TODO: Figure out how the heck to powerdown this thing! */
+//FUNCID;
+    return;
+}
+
+static int platinum_getcolreg(u_int regno, u_int *red, u_int *green,
+                            u_int *blue, u_int *transp, struct fb_info *info)
+{
+       struct fb_info_platinum *p = (struct fb_info_platinum *) info;
+
+//    FUNCID;
+       if (regno > 255 || regno < 0)
+               return 1;
+       *red = p->palette[regno].red;
+       *green = p->palette[regno].green;
+       *blue = p->palette[regno].blue;
+       return 0;
+}
+
+static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                            u_int transp, struct fb_info *info)
+{
+       struct fb_info_platinum *p = (struct fb_info_platinum *) info;
+
+//    FUNCID;
+       if (regno > 255 || regno < 0)
+               return 1;
+       p->palette[regno].red = red;
+       p->palette[regno].green = green;
+       p->palette[regno].blue = blue;
+
+       out_8(&p->cmap_regs->addr, regno);      /* tell clut what addr to fill  */
+       out_8(&p->cmap_regs->lut, red);         /* send one color channel at    */
+       out_8(&p->cmap_regs->lut, green);       /* a time...                    */
+       out_8(&p->cmap_regs->lut, blue);
+
+       if(regno < 16) {
+#if 0
+#ifdef FBCON_HAS_CFB16
+               fbcon_cfb16_cmap[regno] = (red << 10) | (green << 5) | blue;
+#endif
+#ifdef FBCON_HAS_CFB32
+               fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue;
+               /* I think. */
+#endif
+#else
+#ifdef FBCON_HAS_CFB16
+               fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno;
+#endif
+#ifdef FBCON_HAS_CFB32
+               fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) | (regno << 8) | regno;
+               /* I think. */
+#endif
+#endif
+       }
+       return 0;
+}
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+//    FUNCID;
+       if (con != currcon)
+               return;
+       if (fb_display[con].cmap.len)
+               fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1,
+                           platinum_setcolreg, info);
+       else {
+               int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+               fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1,
+                           platinum_setcolreg, info);
+       }
+}
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+extern struct vc_mode display_info;
+extern struct fb_info *console_fb_info;
+#if 0
+extern int (*console_setmode_ptr)(struct vc_mode *, int);
+extern int (*console_set_cmap_ptr)(struct fb_cmap *, int, int,
+                                  struct fb_info *);
+int console_setmode(struct vc_mode *, int);
+#endif
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+
+static inline int platinum_vram_reqd(int video_mode, int color_mode)
+{
+       return vmode_attrs[video_mode - 1].vres
+               * platinum_reg_init[video_mode-1]->pitch[color_mode];
+}
+
+#define STORE_D2(a, d) { \
+       out_8(&p->cmap_regs->addr, (a+32)); \
+       out_8(&p->cmap_regs->d2, (d)); \
+}
+
+static void set_platinum_clock(struct fb_info_platinum *p, unsigned char *clock_params)
+{
+//    FUNCID;
+       STORE_D2(6, 0xc6);
+       out_8(&p->cmap_regs->addr,3+32);
+       if (in_8(&p->cmap_regs->d2) == 2) {
+               STORE_D2(7, clock_params[0]);
+               STORE_D2(8, clock_params[1]);
+               STORE_D2(3, 3);
+       } else {
+               STORE_D2(4, clock_params[0]);
+               STORE_D2(5, clock_params[1]);
+               STORE_D2(3, 2);
+       }
+
+       __delay(5000);
+       STORE_D2(9, 0xa6);
+}
+
+
+__initfunc(static void init_platinum(struct fb_info_platinum *p))
+{
+       struct fb_par_platinum *par = &p->par;
+
+//    FUNCID;
+       p->sense = read_platinum_sense(p);
+       printk("Monitor sense value = 0x%x, ", p->sense);
+       /* Try to pick a video mode out of NVRAM if we have one. */
+       par->vmode = nvram_read_byte(NV_VMODE);
+       if(par->vmode <= 0 || par->vmode > VMODE_MAX || !platinum_reg_init[par->vmode - 1])
+               par->vmode = VMODE_CHOOSE;
+       if(par->vmode == VMODE_CHOOSE)
+               par->vmode = mac_map_monitor_sense(p->sense);
+       if(!platinum_reg_init[par->vmode - 1])
+               par->vmode = VMODE_640_480_67;
+
+       par->cmode = nvram_read_byte(NV_CMODE);
+       if(par->cmode < CMODE_8 || par->cmode > CMODE_32)
+               par->cmode = CMODE_8;
+       /*
+        * Reduce the pixel size if we don't have enough VRAM.
+        */
+       while(par->cmode > CMODE_8 && platinum_vram_reqd(par->vmode, par->cmode) > p->total_vram)
+               par->cmode--;
+       
+       printk("using video mode %d and color mode %d.\n", par->vmode, par->cmode);
+       
+       par->vxres = par->xres = vmode_attrs[par->vmode - 1].hres;
+       par->vyres = par->yres = vmode_attrs[par->vmode - 1].vres;
+       par->xoffset = par->yoffset = 0;
+       
+       platinum_par_to_all(p, 1);
+       
+       if (register_framebuffer(&p->info) < 0) {
+               kfree(p);
+               return;
+       }
+       platinum_set_hardware(p);
+       
+       printk("fb%d: platinum display adapter\n", GET_FB_IDX(p->info.node));   
+}
+
+/* Now how about actually saying, Make it so! */
+/* Some things in here probably don't need to be done each time. */
+static void platinum_set_hardware(struct fb_info_platinum *p)
+{
+       struct platinum_regvals *init;
+       int                     i, dtype, clkmode;
+       int                     vmode, cmode;
+       
+//    FUNCID;
+       vmode = p->par.vmode;
+       cmode = p->par.cmode;
+
+       init = platinum_reg_init[vmode - 1];
+
+       /* Initialize display timing registers */
+       out_be32(&p->platinum_regs->reg[24].r, 7);      /* turn display off */
+
+       for (i = 0; i < 26; ++i)
+               out_be32(&p->platinum_regs->reg[i+32].r, init->regs[i]);
+       out_be32(&p->platinum_regs->reg[26+32].r, (p->total_vram == 0x100000 ?
+                                                  init->offset[cmode] + 4 - cmode :
+                                                  init->offset[cmode]));
+       out_be32(&p->platinum_regs->reg[16].r, (unsigned) p->frame_buffer_phys + init->fb_offset);
+       out_be32(&p->platinum_regs->reg[18].r, init->pitch[cmode]);
+       out_be32(&p->platinum_regs->reg[19].r, (p->total_vram == 0x100000 ?
+                                               init->mode[cmode+1] :
+                                               init->mode[cmode]));
+       out_be32(&p->platinum_regs->reg[20].r, (p->total_vram == 0x100000 ? 0x11 : 0x1011));
+       out_be32(&p->platinum_regs->reg[21].r, 0x100);
+       out_be32(&p->platinum_regs->reg[22].r, 1);
+       out_be32(&p->platinum_regs->reg[23].r, 1);
+       out_be32(&p->platinum_regs->reg[26].r, 0xc00);
+       out_be32(&p->platinum_regs->reg[27].r, 0x235);
+       /* out_be32(&p->platinum_regs->reg[27].r, 0x2aa); */
+
+       STORE_D2(0, (p->total_vram == 0x100000 ?
+                    init->dacula_ctrl[cmode] & 0xf :
+                    init->dacula_ctrl[cmode]));
+       STORE_D2(1, 4);
+       STORE_D2(2, 0);
+       /*
+        * Try to determine whether we have an old or a new DACula.
+        */
+       out_8(&p->cmap_regs->addr, 0x40);
+       dtype = in_8(&p->cmap_regs->d2);
+       switch (dtype) {
+       case 0x3c:
+               clkmode = 1;
+               break;
+       case 0x84:
+               clkmode = 0;
+               break;
+       default:
+               clkmode = 0;
+               printk("Unknown DACula type: %x\n", dtype);
+       }
+
+       set_platinum_clock(p, init->clock_params[clkmode]);
+
+       out_be32(&p->platinum_regs->reg[24].r, 0);      /* turn display on */
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+       /* And let the world know the truth. */
+       if (!console_fb_info || console_fb_info == &p->info) {
+               display_info.height = p->var.yres;
+               display_info.width = p->var.xres;
+               display_info.depth = ( (cmode == CMODE_32) ? 32 :
+                                     ((cmode == CMODE_16) ? 16 : 8));
+               display_info.pitch = p->fix.line_length;
+               display_info.mode = vmode;
+               strncpy(display_info.name, "platinum",
+                       sizeof(display_info.name));
+               display_info.fb_address = p->frame_buffer_phys
+                                       + init->fb_offset
+                                       + 0x10;
+               display_info.cmap_adr_address = p->cmap_regs_phys;
+               display_info.cmap_data_address = p->cmap_regs_phys + 0x30;
+               display_info.disp_reg_address = p->platinum_regs_phys;
+               console_fb_info = &p->info;
+       }
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+}
+
+__initfunc(void platinum_init(void))
+{
+#ifndef CONFIG_FB_OF
+       struct device_node *dp;
+
+       dp = find_devices("platinum");
+       if (dp != 0)
+               platinum_of_init(dp);
+#endif /* CONFIG_FB_OF */
+}
+
+__initfunc(void platinum_of_init(struct device_node *dp))
+{
+       struct fb_info_platinum *p;
+       unsigned long           addr, size;
+       int                     i, bank0, bank1, bank2, bank3;
+//FUNCID;      
+       if(dp->n_addrs != 2)
+               panic("expecting 2 address for platinum (got %d)", dp->n_addrs);
+       p = kmalloc(sizeof(*p), GFP_ATOMIC);
+       if (p == 0)
+               return;
+
+       /* Map in frame buffer and registers */
+       for (i = 0; i < dp->n_addrs; ++i) {
+               addr = dp->addrs[i].address;
+               size = dp->addrs[i].size;
+               if (size >= 0x400000) {
+                       /* frame buffer - map only 4MB */
+                       p->frame_buffer_phys = addr;
+                       p->frame_buffer = __ioremap(addr, 0x400000, _PAGE_WRITETHRU);
+                       p->base_frame_buffer = p->frame_buffer;
+               } else {
+                       /* registers */
+                       p->platinum_regs_phys = addr;
+                       p->platinum_regs = ioremap(addr, size);
+               }
+       }
+       p->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */
+       p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000);
+
+       /* Grok total video ram */
+       out_be32(&p->platinum_regs->reg[16].r, (unsigned)p->frame_buffer_phys);
+       out_be32(&p->platinum_regs->reg[20].r, 0x1011); /* select max vram */
+       out_be32(&p->platinum_regs->reg[24].r, 0);      /* switch in vram */
+       eieio();
+       p->frame_buffer[0x100000] = 0x34;
+       asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x100000]) : "memory");
+       p->frame_buffer[0x200000] = 0x56;
+       asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x200000]) : "memory");
+       p->frame_buffer[0x300000] = 0x78;
+       asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x300000]) : "memory");
+       bank0 = 1; /* builtin 1MB vram, always there */
+       bank1 = p->frame_buffer[0x100000] == 0x34;
+       bank2 = p->frame_buffer[0x200000] == 0x56;
+       bank3 = p->frame_buffer[0x300000] == 0x78;
+       p->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000;
+       printk("Total VRAM = %dMB\n", p->total_vram / 1024 / 1024);
+
+//     p->frame_buffer = p->base_frame_buffer
+//                     + platinum_reg_init[p->par.vmode-1]->fb_offset;
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#if 0
+       console_set_cmap_ptr = platinum_set_cmap;
+       console_setmode_ptr = platinum_console_setmode;
+#endif
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+
+       init_platinum(p);
+}
+
+/*
+ * Get the monitor sense value.
+ * Note that this can be called before calibrate_delay,
+ * so we can't use udelay.
+ */
+static int read_platinum_sense(struct fb_info_platinum *p)
+{
+       int sense;
+
+       out_be32(&p->platinum_regs->reg[23].r, 7);      /* turn off drivers */
+       __delay(2000);
+       sense = (~in_be32(&p->platinum_regs->reg[23].r) & 7) << 8;
+
+       /* drive each sense line low in turn and collect the other 2 */
+       out_be32(&p->platinum_regs->reg[23].r, 3);      /* drive A low */
+       __delay(2000);
+       sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 3) << 4;
+       out_be32(&p->platinum_regs->reg[23].r, 5);      /* drive B low */
+       __delay(2000);
+       sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 4) << 1;
+       sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 1) << 2;
+       out_be32(&p->platinum_regs->reg[23].r, 6);      /* drive C low */
+       __delay(2000);
+       sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 6) >> 1;
+
+       out_be32(&p->platinum_regs->reg[23].r, 7);      /* turn off drivers */
+
+       return sense;
+}
+
+#if 0
+/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
+static int platinum_var_to_par(struct fb_var_screeninfo *var, 
+       struct fb_par_platinum *par, const struct fb_info *fb_info)
+{
+       int xres = var->xres;
+       int yres = var->yres;
+       int bpp = var->bits_per_pixel;
+       
+       struct platinum_regvals *init;
+       struct fb_info_platinum *p = (struct fb_info_platinum *) fb_info;
+
+//    FUNCID;
+    /*
+     *  Get the video params out of 'var'. If a value doesn't fit, round it up,
+     *  if it's too big, return -EINVAL.
+     *
+     *  Suggestion: Round up in the following order: bits_per_pixel, xres,
+     *  yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
+     *  bitfields, horizontal timing, vertical timing.
+     */
+       /* swiped by jonh from atyfb.c */
+       if (xres <= 512 && yres <= 384)
+               par->vmode = VMODE_512_384_60;           /* 512x384, 60Hz */
+       else if (xres <= 640 && yres <= 480)
+               par->vmode = VMODE_640_480_67;          /* 640x480, 67Hz */
+       else if (xres <= 640 && yres <= 870)
+               par->vmode = VMODE_640_870_75P;         /* 640x870, 75Hz (portrait) */
+       else if (xres <= 768 && yres <= 576)
+               par->vmode = VMODE_768_576_50I;         /* 768x576, 50Hz (PAL full frame) */
+       else if (xres <= 800 && yres <= 600)
+               par->vmode = VMODE_800_600_75;          /* 800x600, 75Hz */
+       else if (xres <= 832 && yres <= 624)
+               par->vmode = VMODE_832_624_75;          /* 832x624, 75Hz */
+       else if (xres <= 1024 && yres <= 768)
+               par->vmode = VMODE_1024_768_75;         /* 1024x768, 75Hz */
+       else if (xres <= 1152 && yres <= 870)
+               par->vmode = VMODE_1152_870_75;         /* 1152x870, 75Hz */
+       else if (xres <= 1280 && yres <= 960)
+               par->vmode = VMODE_1280_960_75;         /* 1280x960, 75Hz */
+       else if (xres <= 1280 && yres <= 1024)
+               par->vmode = VMODE_1280_1024_75;        /* 1280x1024, 75Hz */
+       else {
+               printk(KERN_ERR "Bad  resolution in platinum_var_to_par()!\n");
+               return -EINVAL;
+       }
+       xres = vmode_attrs[par->vmode - 1].hres;
+       yres = vmode_attrs[par->vmode - 1].vres;
+
+/*
+       if (var->xres_virtual <= xres)
+               par->vxres = xres;
+       else
+               par->vxres = (var->xres_virtual+7) & ~7;
+       if (var->yres_virtual <= yres)
+               par->vyres = yres;
+       else
+               par->vyres = var->yres_virtual;
+
+       par->xoffset = (var->xoffset+7) & ~7;
+       par->yoffset = var->yoffset;
+       if (par->xoffset+xres > par->vxres || par->yoffset+yres > par->vyres)
+               return -EINVAL;
+*/
+
+       /* I'm too chicken to think about virtual       */
+       /* resolutions just yet. Bok bok.                       */
+       
+       /* And I'm too chicken to even figure out what they are.  Awk awk. [danj] */
+       if (var->xres_virtual > xres || var->yres_virtual > yres
+               || var->xoffset != 0 || var->yoffset != 0) {
+               printk(KERN_ERR "Bad  virtual resolution in platinum_var_to_par()!\n");
+               return -EINVAL;
+       }
+
+       par->xres = xres;
+       par->yres = yres;
+       par->vxres = xres;
+       par->vyres = yres;
+       par->xoffset = 0;
+       par->yoffset = 0;
+
+       if (bpp <= 8)
+               par->cmode = CMODE_8;
+       else if (bpp <= 16)
+               par->cmode = CMODE_16;
+       else if (bpp <= 32)
+               par->cmode = CMODE_32;
+       else {
+               printk(KERN_ERR "Bad color mode in platinum_var_to_par()!\n");
+               return -EINVAL;
+       }
+
+       if (platinum_vram_reqd(par->vmode, par->cmode) > p->total_vram) {
+               printk(KERN_ERR "Bad vram size requested in platinum_var_to_par()!\n");
+               return -EINVAL;
+       }
+       /* Check if we know about the wanted video mode */
+       init = platinum_reg_init[par->vmode-1];
+       if (init == NULL) {
+               /* I'm not sure if platinum has any specific requirements --    */
+               /* if we have a regvals struct, we're good to go?               */
+               printk(KERN_ERR "platinum_reg_init failed platinum_var_to_par()!\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+#else
+/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
+static int platinum_var_to_par(struct fb_var_screeninfo *var, 
+       struct fb_par_platinum *par, const struct fb_info *fb_info)
+{
+       struct fb_info_platinum *p = (struct fb_info_platinum *) fb_info;
+       
+//    FUNCID;
+       if(mac_var_to_vmode(var, &par->vmode, &par->cmode) != 0)
+               return -EINVAL;
+       par->xres = par->vxres = vmode_attrs[par->vmode - 1].hres;
+       par->yres = par->vyres = vmode_attrs[par->vmode - 1].vres;
+       par->xoffset = par->yoffset = 0;
+       
+       if (platinum_vram_reqd(par->vmode, par->cmode) > p->total_vram)
+               return -EINVAL;
+
+       /* Check if we know about the wanted video mode */
+       if(!platinum_reg_init[par->vmode-1]) {
+               /* I'm not sure if platinum has any specific requirements --    */
+               /* if we have a regvals struct, we're good to go?               */
+               return -EINVAL;
+       }
+       return 0;
+}
+#endif
+
+#if 0
+static void platinum_par_to_var(struct fb_par_platinum *par, struct fb_var_screeninfo *var)
+{
+       memset(var, 0, sizeof(*var));
+       var->xres = vmode_attrs[par->vmode - 1].hres;
+       var->yres = vmode_attrs[par->vmode - 1].vres;
+       var->xres_virtual = var->xres;
+       var->yres_virtual = var->yres;  /* For now. */
+       var->xoffset = par->xoffset;
+       var->yoffset = par->yoffset;
+       var->grayscale = 0;
+       
+       if(par->cmode != CMODE_8 && par->cmode != CMODE_16 && par->cmode != CMODE_32) {
+               printk(KERN_ERR "Bad color mode in platinum_par_to_var()!\n");
+               par->cmode = CMODE_8;
+       }
+       switch(par->cmode) {
+       case CMODE_8:
+               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;
+               break;
+       case CMODE_16:  /* RGB 555 */
+               var->bits_per_pixel = 16;
+               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 = 0;
+               var->transp.length = 0;
+               break;
+       case CMODE_32:  /* RGB 888 */
+               var->bits_per_pixel = 32;
+               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;
+               break;
+       }
+       var->red.msb_right = 0;
+       var->green.msb_right = 0;
+       var->blue.msb_right = 0;
+       var->transp.msb_right = 0;
+       var->nonstd = 0;
+       var->activate = 0;
+       var->height = -1;
+       var->width = -1;
+       var->vmode = FB_VMODE_NONINTERLACED;
+
+       /* these are total guesses, copied right out of atyfb.c */
+       var->left_margin = var->right_margin = 64;
+       var->upper_margin = var->lower_margin = 32;
+       var->hsync_len = 8;
+       var->vsync_len = 8;
+       var->sync = 0;
+
+#if 1
+/* jonh's pixclocks...*/
+       /* no long long support in the kernel :-( */
+       /* this splittig trick will work if xres > 232 */
+       var->pixclock = 1000000000/
+       (var->left_margin+var->xres+var->right_margin+var->hsync_len);
+       var->pixclock *= 1000;
+       var->pixclock /= vmode_attrs[par->vmode-1].vfreq*
+        (var->upper_margin+var->yres+var->lower_margin+var->vsync_len);
+#else
+/* danj's */
+       /* 10^12 * clock_params[0] / (3906400 * clock_params[1] * 2^clock_params[2]) */
+       /* (10^12 * clock_params[0] / (3906400 * clock_params[1])) >> clock_params[2] */
+       /* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */
+       var->pixclock = 255990 * platinum_reg_init[par->vmode-1]->clock_params[0];
+       var->pixclock /= platinum_reg_init[par->vmode-1]->clock_params[1];
+       var->pixclock >>= platinum_reg_init[par->vmode-1]->clock_params[2];
+#endif
+}
+#else
+static inline void platinum_par_to_var(struct fb_par_platinum *par, struct fb_var_screeninfo *var)
+{
+//    FUNCID;
+       mac_vmode_to_var(par->vmode, par->cmode, var);
+}
+#endif
+
+static void platinum_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_platinum *p)
+{
+//    FUNCID;
+       memset(fix, 0, sizeof(*fix));
+       strcpy(fix->id, "platinum");
+       fix->mmio_start = (char *)p->platinum_regs_phys;
+       fix->mmio_len = 0x1000;
+       fix->type = FB_TYPE_PACKED_PIXELS;
+       
+       fix->type_aux = 0;
+       fix->ywrapstep = 0;
+       fix->xpanstep = 0;
+       fix->ypanstep = 0;
+}
+
+/* Fix must already be inited ^^^^^^^ */
+static void platinum_par_to_fix(struct fb_par_platinum *par, 
+                               struct fb_fix_screeninfo *fix,
+                               struct fb_info_platinum *p)
+{
+//    FUNCID;
+       fix->smem_start = (void *)(p->frame_buffer_phys);
+       fix->smem_len = platinum_vram_reqd(par->vmode, par->cmode);
+               /* Hmm, jonh used total_vram here. */
+       fix->visual = (par->cmode == CMODE_8) ?
+               FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+//     fix->line_length = par->vxres << par->cmode;
+       fix->line_length = platinum_reg_init[par->vmode-1]->pitch[par->cmode];
+
+}
+
+static void platinum_init_display(struct display *disp)
+{
+       memset(disp, 0, sizeof(*disp));
+       disp->type = /* fix->type */ FB_TYPE_PACKED_PIXELS;
+       disp->can_soft_blank = 1;
+       disp->scrollmode = SCROLL_YREDRAW;
+#if 0
+               disp->type_aux = fix->type_aux;
+               disp->cmap.red = NULL;  /* ??? danj */
+               disp->cmap.green = NULL;
+               disp->cmap.blue = NULL;
+               disp->cmap.transp = NULL;
+                       /* Yeah, I realize I just set 0 = 0. */
+#endif
+}
+
+static void platinum_par_to_display(struct fb_par_platinum *par,
+  struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_platinum *p)
+{
+//    FUNCID;
+       disp->var = p->var;
+       disp->screen_base = (char *) p->frame_buffer
+                         + platinum_reg_init[par->vmode-1]->fb_offset
+                         + ((par->yres % 16) / 2) * fix->line_length + 0x10;
+       disp->visual = fix->visual;
+       disp->line_length = fix->line_length;
+
+       if(disp->scrollmode != SCROLL_YREDRAW) {
+               printk(KERN_ERR "Scroll mode not YREDRAW in platinum_par_to_display!!\n");
+               disp->scrollmode = SCROLL_YREDRAW;
+       }
+
+       switch(par->cmode) {
+#ifdef FBCON_HAS_CFB8
+        case CMODE_8:
+           disp->dispsw = &fbcon_cfb8;
+           break;
+#endif
+#ifdef FBCON_HAS_CFB16
+        case CMODE_16:
+           disp->dispsw = &fbcon_cfb16;
+           break;
+#endif
+#ifdef FBCON_HAS_CFB32
+        case CMODE_32:
+           disp->dispsw = &fbcon_cfb32;
+           break;
+#endif
+        default:
+           disp->dispsw = NULL;
+           break;
+       }
+}
+
+static void platinum_init_info(struct fb_info *info, struct fb_info_platinum *p)
+{
+//    FUNCID;
+       strcpy(info->modename, p->fix.id);
+       info->node = -1;        /* ??? danj */
+       info->fbops = &platinumfb_ops;
+       info->disp = &p->disp;
+       info->fontname[0] = 0;
+       info->changevar = NULL;
+       info->switch_con = &platinum_switch;
+       info->updatevar = &platinum_updatevar;
+       info->blank = &platinum_blank;
+}
+
+/* danj: Oh, I HOPE I didn't miss anything major in here... */
+static void platinum_par_to_all(struct fb_info_platinum *p, int init)
+{
+//    FUNCID;
+       if(init) {
+               platinum_init_fix(&p->fix, p);
+       }
+       platinum_par_to_fix(&p->par, &p->fix, p);
+
+       platinum_par_to_var(&p->par, &p->var);
+
+       if(init) {
+               platinum_init_display(&p->disp);
+       }
+       platinum_par_to_display(&p->par, &p->disp, &p->fix, p);
+       
+       if(init) {
+               platinum_init_info(&p->info, p);
+       }
+}
+
+#if 0
+__initfunc(void platinum_setup(char *options, int *ints))
+{
+    /* Parse user speficied options (`video=platinumfb:') */
+       FUNCID;
+}
+
+#endif
+
diff --git a/drivers/video/platinumfb.h b/drivers/video/platinumfb.h
new file mode 100644 (file)
index 0000000..a9b4b1c
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * linux/drivers/video/platinumfb-hw.c -- Frame buffer device for the
+ * Platinum on-board video in PowerMac 7200s (and some clones based
+ * on the same motherboard.)
+ *
+ *  Created 09 Feb 1998 by Jon Howell <jonh@cs.dartmouth.edu>
+ *
+ * Copyright (C) 1998 Jon Howell
+ *
+ *  based on drivers/macintosh/platinum.c: Console support
+ *     for PowerMac "platinum" display adaptor.
+ *  Copyright (C) 1996 Paul Mackerras and Mark Abene.
+ *
+ *  based on skeletonfb.c:
+ *  Created 28 Dec 1997 by Geert Uytterhoeven
+ *
+ * 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.
+ */
+
+/*
+ * Structure of the registers for the DACula colormap device.
+ */
+struct cmap_regs {
+       unsigned char addr;
+       char pad1[15];
+       unsigned char d1;
+       char pad2[15];
+       unsigned char d2;
+       char pad3[15];
+       unsigned char lut;
+       char pad4[15];
+};
+
+/*
+ * Structure of the registers for the "platinum" display adaptor".
+ */
+struct preg {                  /* padded register */
+       unsigned r;                     /* notice this is 32 bits. */
+       char pad[12];
+};
+
+struct platinum_regs {
+       struct preg reg[128];
+};
+
+/*
+ * Register initialization tables for the platinum display.
+ *
+ * It seems that there are two different types of platinum display
+ * out there.  Older ones use the values in clocksel[1], for which
+ * the formula for the clock frequency seems to be
+ *     F = 14.3MHz * c0 / (c1 & 0x1f) / (1 << (c1 >> 5))
+ * Newer ones use the values in clocksel[0], for which the formula
+ * seems to be
+ *     F = 15MHz * c0 / ((c1 & 0x1f) + 2) / (1 << (c1 >> 5))
+ */
+struct platinum_regvals {
+       int     fb_offset;
+       int     pitch[3];
+       unsigned regs[26];
+       unsigned char offset[3];
+       unsigned char mode[3];
+       unsigned char dacula_ctrl[3];
+       unsigned char clock_params[2][2];
+};
+
+#define DIV2   0x20
+#define DIV4   0x40
+#define DIV8   0x60
+#define DIV16  0x80
+
+/* 1280x1024, 75Hz (20) */
+static struct platinum_regvals platinum_reg_init_20 = {
+       0x5c00,
+       { 1312, 2592, 2592 },
+       { 0xffc, 4, 0, 0, 0, 0, 0x428, 0,
+         0, 0xb3, 0xd3, 0x12, 0x1a5, 0x23, 0x28, 0x2d,
+         0x5e, 0x19e, 0x1a4, 0x854, 0x852, 4, 9, 0x50,
+         0x850, 0x851 }, { 0x58, 0x5d, 0x5d },
+       { 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 },
+       {{ 45, 3 }, { 66, 7 }}
+};
+
+/* 1280x960, 75Hz (19) */
+static struct platinum_regvals platinum_reg_init_19 = {
+       0x5c00,
+       { 1312, 2592, 2592 },
+       { 0xffc, 4, 0, 0, 0, 0, 0x428, 0,
+         0, 0xb2, 0xd2, 0x12, 0x1a3, 0x23, 0x28, 0x2d,
+         0x5c, 0x19c, 0x1a2, 0x7d0, 0x7ce, 4, 9, 0x4c,
+         0x7cc, 0x7cd }, { 0x56, 0x5b, 0x5b },
+       { 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 },
+       {{ 42, 3 }, { 44, 5 }}
+};
+
+/* 1152x870, 75Hz (18) */
+static struct platinum_regvals platinum_reg_init_18 = {
+       0x11b0,
+       { 1184, 2336, 4640 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x38f, 0,
+         0, 0x294, 0x16c, 0x20, 0x2d7, 0x3f, 0x49, 0x53,
+         0x82, 0x2c2, 0x2d6, 0x726, 0x724, 4, 9, 0x52,
+         0x71e, 0x722 }, { 0x74, 0x7c, 0x81 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 26, 0 + DIV2 }, { 42, 6 }}
+};
+
+/* 1024x768, 75Hz (17) */
+static struct platinum_regvals platinum_reg_init_17 = {
+       0x10b0,
+       { 1056, 2080, 4128 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x254, 0x14b, 0x18, 0x295, 0x2f, 0x32, 0x3b,
+         0x80, 0x280, 0x296, 0x648, 0x646, 4, 9, 0x40,
+         0x640, 0x644 }, { 0x72, 0x7a, 0x7f },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 54, 3 + DIV2 }, { 67, 12 }}
+};
+
+/* 1024x768, 75Hz (16) */
+static struct platinum_regvals platinum_reg_init_16 = {
+       0x10b0,
+       { 1056, 2080, 4128 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x250, 0x147, 0x17, 0x28f, 0x2f, 0x35, 0x47,
+         0x82, 0x282, 0x28e, 0x640, 0x63e, 4, 9, 0x3c,
+         0x63c, 0x63d }, { 0x74, 0x7c, 0x81 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 20, 0 + DIV2 }, { 11, 2 }}
+};
+
+/* 1024x768, 70Hz (15) */
+static struct platinum_regvals platinum_reg_init_15 = {
+       0x10b0,
+       { 1056, 2080, 4128 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x254, 0x14b, 0x22, 0x297, 0x43, 0x49, 0x5b,
+         0x86, 0x286, 0x296, 0x64c, 0x64a, 0xa, 0xf, 0x44,
+         0x644, 0x646 }, { 0x78, 0x80, 0x85 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 19, 0 + DIV2 }, { 110, 21 }}
+};
+
+/* 1024x768, 60Hz (14) */
+static struct platinum_regvals platinum_reg_init_14 = {
+       0x10b0,
+       { 1056, 2080, 4128 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x25a, 0x14f, 0x22, 0x29f, 0x43, 0x49, 0x5b,
+         0x8e, 0x28e, 0x29e, 0x64c, 0x64a, 0xa, 0xf, 0x44,
+         0x644, 0x646 }, { 0x80, 0x88, 0x8d },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 71, 6 + DIV2 }, { 118, 13 + DIV2 }}
+};
+
+/* 832x624, 75Hz (13) */
+static struct platinum_regvals platinum_reg_init_13 = {
+       0x70,
+       { 864, 1680, 3360 },    /* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB */
+       { 0xff0, 4, 0, 0, 0, 0, 0x299, 0,
+         0, 0x21e, 0x120, 0x10, 0x23f, 0x1f, 0x25, 0x37,
+         0x8a, 0x22a, 0x23e, 0x536, 0x534, 4, 9, 0x52,
+         0x532, 0x533 }, { 0x7c, 0x84, 0x89 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }}
+};
+
+/* 800x600, 75Hz (12) */
+static struct platinum_regvals platinum_reg_init_12 = {
+       0x1010,
+       { 832, 1632, 3232 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x1ce, 0x108, 0x14, 0x20f, 0x27, 0x30, 0x39,
+         0x72, 0x202, 0x20e, 0x4e2, 0x4e0, 4, 9, 0x2e,
+         0x4de, 0x4df }, { 0x64, 0x6c, 0x71 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 122, 7 + DIV4 }, { 62, 9 + DIV2 }}
+};
+
+/* 800x600, 72Hz (11) */
+static struct platinum_regvals platinum_reg_init_11 = {
+       0x1010,
+       { 832, 1632, 3232 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x1ca, 0x104, 0x1e, 0x207, 0x3b, 0x44, 0x4d,
+         0x56, 0x1e6, 0x206, 0x534, 0x532, 0xa, 0xe, 0x38,
+         0x4e8, 0x4ec }, { 0x48, 0x50, 0x55 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 26, 0 + DIV4 }, { 42, 6 + DIV2 }}
+};
+
+/* 800x600, 60Hz (10) */
+static struct platinum_regvals platinum_reg_init_10 = {
+       0x1010,
+       { 832, 1632, 3232 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d,
+         0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34,
+         0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 54, 3 + DIV4 }, { 95, 1 + DIV8 }}
+};
+
+/* 800x600, 56Hz (9) --unsupported? copy of mode 10 for now... */
+static struct platinum_regvals platinum_reg_init_9 = {
+       0x1010,
+       { 832, 1632, 3232 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d,
+         0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34,
+         0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 54, 3 + DIV4 }, { 88, 1 + DIV8 }}
+};
+
+/* 768x576, 50Hz Interlaced-PAL (8) */
+static struct platinum_regvals platinum_reg_init_8 = {
+       0x1010,
+       { 800, 1568, 3104 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36,
+         0x47, 0x1c7, 0x1d6, 0x271, 0x270, 4, 9, 0x27,
+         0x267, 0x26b }, { 0x39, 0x41, 0x46 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }}
+};
+
+/* 640x870, 75Hz Portrait (7) */
+static struct platinum_regvals platinum_reg_init_7 = {
+       0xb10,
+       { 672, 1312, 2592 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x176, 0xd0, 0x14, 0x19f, 0x27, 0x2d, 0x3f,
+         0x4a, 0x18a, 0x19e, 0x72c, 0x72a, 4, 9, 0x58,
+         0x724, 0x72a }, { 0x3c, 0x44, 0x49 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }}
+};
+
+/* 640x480, 67Hz (6) */
+static struct platinum_regvals platinum_reg_init_6 = {
+       0x1010,
+       { 672, 1312, 2592 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x209, 0,
+         0, 0x18e, 0xd8, 0x10, 0x1af, 0x1f, 0x25, 0x37,
+         0x4a, 0x18a, 0x1ae, 0x41a, 0x418, 4, 9, 0x52,
+         0x412, 0x416 }, { 0x3c, 0x44, 0x49 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 99, 4 + DIV8 }, { 42, 5 + DIV4 }}
+};
+
+/* 640x480, 60Hz (5) */
+static struct platinum_regvals platinum_reg_init_5 = {
+       0x1010,
+       { 672, 1312, 2592 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x15e, 0xc8, 0x18, 0x18f, 0x2f, 0x35, 0x3e,
+         0x42, 0x182, 0x18e, 0x41a, 0x418, 2, 7, 0x44,
+         0x404, 0x408 }, { 0x34, 0x3c, 0x41 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 26, 0 + DIV8 }, { 14, 2 + DIV4 }}
+};
+
+/* 640x480, 60Hz Interlaced-NTSC (4) */
+static struct platinum_regvals platinum_reg_init_4 = {
+       0x1010,
+       { 672, 1312, 2592 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30,
+         0x37, 0x177, 0x184, 0x20d, 0x20c, 5, 0xb, 0x23,
+         0x203, 0x206 }, { 0x29, 0x31, 0x36 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }}
+};
+
+/* 640x480, 50Hz Interlaced-PAL (3) */
+static struct platinum_regvals platinum_reg_init_3 = {
+       0x1010,
+       { 672, 1312, 2592 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36,
+         0x67, 0x1a7, 0x1d6, 0x271, 0x270, 4, 9, 0x57,
+         0x237, 0x26b }, { 0x59, 0x61, 0x66 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }}
+};
+
+/* 512x384, 60Hz (2) */
+static struct platinum_regvals platinum_reg_init_2 = {
+       0x1010,
+       { 544, 1056, 2080 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x25c, 0x140, 0x10, 0x27f, 0x1f, 0x2b, 0x4f,
+         0x68, 0x268, 0x27e, 0x32e, 0x32c, 4, 9, 0x2a,
+         0x32a, 0x32b }, { 0x5a, 0x62, 0x67 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 33, 2 + DIV8 }, { 79, 9 + DIV8 }}
+};
+
+/* 512x384, 60Hz Interlaced-NTSC (1) */
+static struct platinum_regvals platinum_reg_init_1 = {
+       0x1010,
+       { 544, 1056, 2080 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30,
+         0x57, 0x157, 0x184, 0x20d, 0x20c, 5, 0xb, 0x53,
+         0x1d3, 0x206 }, { 0x49, 0x51, 0x56 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }}
+};
+
+#define VMODE_MAX           20
+
+static struct platinum_regvals *platinum_reg_init[VMODE_MAX] = {
+       &platinum_reg_init_1,
+       &platinum_reg_init_2,
+       &platinum_reg_init_3,
+       &platinum_reg_init_4,
+       &platinum_reg_init_5,
+       &platinum_reg_init_6,
+       &platinum_reg_init_7,
+       &platinum_reg_init_8,
+       &platinum_reg_init_9,
+       &platinum_reg_init_10,
+       &platinum_reg_init_11,
+       &platinum_reg_init_12,
+       &platinum_reg_init_13,
+       &platinum_reg_init_14,
+       &platinum_reg_init_15,
+       &platinum_reg_init_16,
+       &platinum_reg_init_17,
+       &platinum_reg_init_18,
+       &platinum_reg_init_19,
+       &platinum_reg_init_20
+};
+
+struct vmode_attr {
+       int hres;
+       int vres;
+       int vfreq;
+       int interlaced;
+};
+
+struct vmode_attr vmode_attrs[VMODE_MAX] = {
+       {512, 384, 60, 1},
+       {512, 384, 60},
+       {640, 480, 50, 1},
+       {640, 480, 60, 1},
+       {640, 480, 60},
+       {640, 480, 67},
+       {640, 870, 75},
+       {768, 576, 50, 1},
+       {800, 600, 56},
+       {800, 600, 60},
+       {800, 600, 72},
+       {800, 600, 75},
+       {832, 624, 75},
+       {1024, 768, 60},
+       {1024, 768, 72},
+       {1024, 768, 75},
+       {1024, 768, 75},
+       {1152, 870, 75},
+       {1280, 960, 75},
+       {1280, 1024, 75}
+};
+
+/* this stuff should probably be shared by the various vmode-based     */
+/* drivers in a vmode.h header.                                                                                */
+
+#define VMODE_NVRAM            0       /* use value stored in nvram */
+#define VMODE_512_384_60I      1       /* 512x384, 60Hz interlaced (NTSC) */
+#define VMODE_512_384_60       2       /* 512x384, 60Hz */
+#define VMODE_640_480_50I      3       /* 640x480, 50Hz interlaced (PAL) */
+#define VMODE_640_480_60I      4       /* 640x480, 60Hz interlaced (NTSC) */
+#define VMODE_640_480_60       5       /* 640x480, 60Hz (VGA) */
+#define VMODE_640_480_67       6       /* 640x480, 67Hz */
+#define VMODE_640_870_75P      7       /* 640x870, 75Hz (portrait) */
+#define VMODE_768_576_50I      8       /* 768x576, 50Hz (PAL full frame) */
+#define VMODE_800_600_56       9       /* 800x600, 56Hz */
+#define VMODE_800_600_60       10      /* 800x600, 60Hz */
+#define VMODE_800_600_72       11      /* 800x600, 72Hz */
+#define VMODE_800_600_75       12      /* 800x600, 75Hz */
+#define VMODE_832_624_75       13      /* 832x624, 75Hz */
+#define VMODE_1024_768_60      14      /* 1024x768, 60Hz */
+#define VMODE_1024_768_70      15      /* 1024x768, 70Hz (or 72Hz?) */
+#define VMODE_1024_768_75V     16      /* 1024x768, 75Hz (VESA) */
+#define VMODE_1024_768_75      17      /* 1024x768, 75Hz */
+#define VMODE_1152_870_75      18      /* 1152x870, 75Hz */
+#define VMODE_1280_960_75      19      /* 1280x960, 75Hz */
+#define VMODE_1280_1024_75     20      /* 1280x1024, 75Hz */
+#define VMODE_MAX              20
+#define VMODE_CHOOSE           99      /* choose based on monitor sense */
+
+#define CMODE_NVRAM            -1      /* use value stored in nvram */
+#define CMODE_8                        0       /* 8 bits/pixel */
+#define CMODE_16               1       /* 16 (actually 15) bits/pixel */
+#define CMODE_32               2       /* 32 (actually 24) bits/pixel */
diff --git a/drivers/video/prom.uni b/drivers/video/prom.uni
new file mode 100644 (file)
index 0000000..58f9c04
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Unicode mapping table for font in Sun PROM
+# 
+#
+0x20-0x7e      idem
+0xa0-0xff      idem
+#
+0x7c           U+2502
+0x2d           U+2500
+0x2b           U+250c U+2510 U+2514 U+2518 U+251c U+2524 U+252c U+2534 U+253c
+0xa4           U+fffd
index d714b7f4b19c92b4fe01c2371501b1550d1bf2b3..e728b16abb6391e3618a8f307addf792b4491b75 100644 (file)
@@ -1,10 +1,11 @@
-/* $Id: promcon.c,v 1.6 1998/07/19 12:49:26 mj Exp $
+/* $Id: promcon.c,v 1.10 1998/07/24 15:31:53 jj Exp $
  * Console driver utilizing PROM sun terminal emulation
  *
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
  * Copyright (C) 1998  Jakub Jelinek  (jj@ultra.linux.cz)
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/console.h>
 #include <linux/console_struct.h>
+#include <linux/vt_kern.h>
 #include <linux/selection.h>
 #include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/kd.h>
 
 #include <asm/oplib.h>
+#include <asm/uaccess.h>
 
 static short pw = 80 - 1, ph = 34 - 1;
 static short px, py;
+static unsigned long promcon_uni_pagedir[2];
 
-#define PROMCON_COLOR 1
+extern u8 promfont_unicount[];
+extern u16 promfont_unitable[];
+
+#define PROMCON_COLOR 0
 
 #if PROMCON_COLOR
 #define inverted(s)    ((((s) & 0x7700) == 0x0700) ? 0 : 1)
@@ -119,12 +128,70 @@ __initfunc(const char *promcon_startup(void))
        return display_desc;
 }
 
+__initfunc(static void
+promcon_init_unimap(struct vc_data *conp))
+{
+       mm_segment_t old_fs = get_fs();
+       struct unipair *p, *p1;
+       u16 *q;
+       int i, j, k;
+       
+       p = kmalloc(256*sizeof(struct unipair), GFP_KERNEL);
+       if (!p) return;
+       
+       q = promfont_unitable;
+       p1 = p;
+       k = 0;
+       for (i = 0; i < 256; i++)
+               for (j = promfont_unicount[i]; j; j--) {
+                       p1->unicode = *q++;
+                       p1->fontpos = i;
+                       p1++;
+                       k++;
+               }
+       set_fs(KERNEL_DS);
+       con_clear_unimap(conp->vc_num, NULL);
+       con_set_unimap(conp->vc_num, k, p);
+       con_protect_unimap(conp->vc_num, 1);
+       set_fs(old_fs);
+       kfree(p);
+}
+
 static void
 promcon_init(struct vc_data *conp, int init)
 {
+       unsigned long p;
+       
        conp->vc_can_do_color = PROMCON_COLOR;
-       conp->vc_cols = pw + 1;
-       conp->vc_rows = ph + 1;
+       if (init) {
+               conp->vc_cols = pw + 1;
+               conp->vc_rows = ph + 1;
+       }
+       p = *conp->vc_uni_pagedir_loc;
+       if (conp->vc_uni_pagedir_loc == &conp->vc_uni_pagedir ||
+           !--conp->vc_uni_pagedir_loc[1])
+               con_free_unimap(conp->vc_num);
+       conp->vc_uni_pagedir_loc = promcon_uni_pagedir;
+       promcon_uni_pagedir[1]++;
+       if (!promcon_uni_pagedir[0] && p) {
+               promcon_init_unimap(conp);
+       }
+       if (!init) {
+               if (conp->vc_cols != pw + 1 || conp->vc_rows != ph + 1)
+                       vc_resize_con(ph + 1, pw + 1, conp->vc_num);
+               else if (conp->vc_num == fg_console)
+                       update_screen(fg_console);
+       }
+}
+
+static void
+promcon_deinit(struct vc_data *conp)
+{
+       /* When closing the last console, reset video origin */
+       if (!--promcon_uni_pagedir[1])
+               con_free_unimap(conp->vc_num);
+       conp->vc_uni_pagedir_loc = &conp->vc_uni_pagedir;
+       con_set_default_unimap(conp->vc_num);
 }
 
 static int
@@ -482,6 +549,13 @@ promcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
        return 0;
 }
 
+#if !(PROMCON_COLOR)
+static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
+{
+       return (_reverse) ? 0xf : 0x7;
+}
+#endif
+
 /*
  *  The console 'switch' structure for the VGA based console
  */
@@ -496,7 +570,7 @@ static int promcon_dummy(void)
 struct consw prom_con = {
        con_startup:            promcon_startup,
        con_init:               promcon_init,
-       con_deinit:             DUMMY,
+       con_deinit:             promcon_deinit,
        con_clear:              promcon_clear,
        con_putc:               promcon_putc,
        con_putcs:              promcon_putcs,
@@ -510,6 +584,18 @@ struct consw prom_con = {
        con_scrolldelta:        DUMMY,
        con_set_origin:         NULL,
        con_save_screen:        NULL,
+#if PROMCON_COLOR
        con_build_attr:         NULL,
+#else
+       con_build_attr:         promcon_build_attr,
+#endif
        con_invert_region:      NULL,
 };
+
+__initfunc(void prom_con_init(void))
+{
+       if (conswitchp == &dummy_con)
+               take_over_console(&prom_con, 0, MAX_NR_CONSOLES-1, 1);
+       else if (conswitchp == &prom_con)
+               promcon_init_unimap(vc_cons[fg_console].d);
+}
index 9673cb9ae1057693f68203ccbc5f57828b101ea2..94b5797bbcda9a6c21220017f8349f8588f76fe0 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
index 009e1f5a4e80b654fc91d37899270a2dcdbf3622..a771c37bd1fb2a1a7722f1bd67e30370de515c69 100644 (file)
@@ -277,7 +277,7 @@ static void sbusfb_clear_margin(struct display *p, int s)
                rects [13] = fb->var.yres_virtual - fb->y_margin;
                rects [14] = fb->var.xres_virtual - fb->x_margin;
                rects [15] = fb->var.yres_virtual;
-               (*fb->fill)(fb, s, 4, rects);
+               (*fb->fill)(fb, p, s, 4, rects);
        } else {
                unsigned char *fb_base = p->screen_base, *q;
                int skip_bytes = fb->y_margin * fb->var.xres_virtual;
@@ -298,13 +298,13 @@ static void sbusfb_clear_margin(struct display *p, int s)
                                memset (q, ~0, size);
                } else {
                        fb_base -= (skip_bytes + fb->x_margin);
-                       memset (fb_base, attr_bg_col(s), skip_bytes - fb->x_margin);
-                       memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bg_col(s), skip_bytes - fb->x_margin);
+                       memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin);
+                       memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bgcol(p,s), skip_bytes - fb->x_margin);
                        incr = fb->var.xres_virtual;
                        size = fb->x_margin * 2;
                        for (q = fb_base + skip_bytes - fb->x_margin, h = 0;
                             h <= he; q += incr, h++)
-                               memset (q, attr_bg_col(s), size);
+                               memset (q, attr_bgcol(p,s), size);
                }
        }
        if (fb->switch_from_graph)
@@ -942,6 +942,7 @@ __initfunc(static void sbusfb_init_fb(int node, int parent, int fbtype,
        
        type->fb_height = h = prom_getintdefault(node, "height", 900);
        type->fb_width  = w = prom_getintdefault(node, "width", 1152);
+sizechange:
        type->fb_depth  = depth = (fbtype == FBTYPE_SUN2BW) ? 1 : 8;
        linebytes = prom_getintdefault(node, "linebytes", w * depth / 8);
        type->fb_size   = PAGE_ALIGN((linebytes) * h);
@@ -990,7 +991,7 @@ __initfunc(static void sbusfb_init_fb(int node, int parent, int fbtype,
        fb->cursor.hwsize.fbx = 32;
        fb->cursor.hwsize.fby = 32;
        
-       if (depth > 1)
+       if (depth > 1 && !fb->color_map)
                fb->color_map = kmalloc(256 * 3, GFP_ATOMIC);
                
        switch(fbtype) {
@@ -1028,6 +1029,9 @@ __initfunc(static void sbusfb_init_fb(int node, int parent, int fbtype,
                kfree(fb);
                return;
        }
+       
+       if (p == SBUSFBINIT_SIZECHANGE)
+               goto sizechange;
 
        disp->dispsw = &fb->dispsw;
        if (fb->setcursor)
index b17a1cf9cfe1eefc08ae28a2f8328e6f1b07ba46..f65ca1d716b716453e225d00b6a1f5ce0b6f6f9c 100644 (file)
@@ -24,6 +24,18 @@ struct fb_info_cgsix {
        struct cg6_tec *tec;
        volatile u32 *fhc;
 };
+struct fb_info_bwtwo {
+       struct bw2_regs *regs;
+};
+struct fb_info_cgthree {
+       struct cg3_regs *regs;
+};
+struct fb_info_tcx {
+       struct bt_regs *bt;
+       struct tcx_thc *thc;
+       struct tcx_tec *tec;
+       u32 *cplane;
+};
 
 struct cg_cursor {
        short   enable;         /* cursor is enabled */
@@ -56,6 +68,9 @@ struct fb_info_sbusfb {
        union {
                struct fb_info_creator ffb;
                struct fb_info_cgsix cg6;
+               struct fb_info_bwtwo bw2;
+               struct fb_info_cgthree cg3;
+               struct fb_info_tcx tcx;
        } s;
        unsigned char *color_map;
        struct cg_cursor cursor;
@@ -81,7 +96,7 @@ struct fb_info_sbusfb {
        void (*unblank)(struct fb_info_sbusfb *);
        void (*margins)(struct fb_info_sbusfb *, struct display *, int, int);
        void (*reset)(struct fb_info_sbusfb *);
-       void (*fill)(struct fb_info_sbusfb *, int, int, unsigned short *);
+       void (*fill)(struct fb_info_sbusfb *, struct display *, int, int, unsigned short *);
        void (*switch_from_graph)(struct fb_info_sbusfb *);
        void (*restore_palette)(struct fb_info_sbusfb *);
 };
@@ -94,13 +109,8 @@ extern char *leofb_init(struct fb_info_sbusfb *);
 extern char *bwtwofb_init(struct fb_info_sbusfb *);
 extern char *cgfourteenfb_init(struct fb_info_sbusfb *);
 
-#define attr_fg_col(s)    \
-       (((s) >> 8) & 0x0f)
-#define attr_bg_col(s)    \
-       (((s) >> 12) & 0x0f)
-#define attr_bg_col_ec(conp) \
-       (((conp)->vc_video_erase_char >> 12) & 0x0f)
-
 #define sbusfbinfod(disp) ((struct fb_info_sbusfb *)(disp->fb_info))
 #define sbusfbinfo(info) ((struct fb_info_sbusfb *)(info))
 #define CM(i, j) [3*(i)+(j)]
+
+#define SBUSFBINIT_SIZECHANGE ((char *)-1)
index 1831e6b33de2214cc9a868e9db6650102d73e84b..e0aebeb42658570b761303c63b1e1a3322ac3c38 100644 (file)
@@ -8,6 +8,7 @@
  * for more details.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff --git a/drivers/video/tcxfb.c b/drivers/video/tcxfb.c
new file mode 100644 (file)
index 0000000..181b6c5
--- /dev/null
@@ -0,0 +1,290 @@
+/* $Id: tcxfb.c,v 1.1 1998/07/21 14:50:44 jj Exp $
+ * tcxfb.c: TCX 24/8bit frame buffer driver
+ *
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#include <linux/module.h>
+#include <linux/sched.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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/selection.h>
+
+#include "sbusfb.h"
+#include <asm/io.h>
+
+#include "fbcon-cfb8.h"
+
+/* THC definitions */
+#define TCX_THC_MISC_REV_SHIFT       16
+#define TCX_THC_MISC_REV_MASK        15
+#define TCX_THC_MISC_VSYNC_DIS       (1 << 25)
+#define TCX_THC_MISC_HSYNC_DIS       (1 << 24)
+#define TCX_THC_MISC_RESET           (1 << 12)
+#define TCX_THC_MISC_VIDEO           (1 << 10)
+#define TCX_THC_MISC_SYNC            (1 << 9)
+#define TCX_THC_MISC_VSYNC           (1 << 8)
+#define TCX_THC_MISC_SYNC_ENAB       (1 << 7)
+#define TCX_THC_MISC_CURS_RES        (1 << 6)
+#define TCX_THC_MISC_INT_ENAB        (1 << 5)
+#define TCX_THC_MISC_INT             (1 << 4)
+#define TCX_THC_MISC_INIT            0x9f
+#define TCX_THC_REV_REV_SHIFT        20
+#define TCX_THC_REV_REV_MASK         15
+#define TCX_THC_REV_MINREV_SHIFT     28
+#define TCX_THC_REV_MINREV_MASK      15
+
+/* The contents are unknown */
+struct tcx_tec {
+       volatile u32 tec_matrix;
+       volatile u32 tec_clip;
+       volatile u32 tec_vdc;
+};
+
+struct tcx_thc {
+       volatile u32 thc_rev;
+        u32 thc_pad0[511];
+       volatile u32 thc_hs;            /* hsync timing */
+       volatile u32 thc_hsdvs;
+       volatile u32 thc_hd;
+       volatile u32 thc_vs;            /* vsync timing */
+       volatile u32 thc_vd;
+       volatile u32 thc_refresh;
+       volatile u32 thc_misc;
+       u32 thc_pad1[56];
+       volatile u32 thc_cursxy;        /* cursor x,y position (16 bits each) */
+       volatile u32 thc_cursmask[32];  /* cursor mask bits */
+       volatile u32 thc_cursbits[32];  /* what to show where mask enabled */
+};
+
+static struct sbus_mmap_map tcx_mmap_map[] = {
+       { TCX_RAM8BIT,          0,              SBUS_MMAP_FBSIZE(1) },
+       { TCX_RAM24BIT,         0,              SBUS_MMAP_FBSIZE(4) },
+       { TCX_UNK3,             0,              SBUS_MMAP_FBSIZE(8) },
+       { TCX_UNK4,             0,              SBUS_MMAP_FBSIZE(8) },
+       { TCX_CONTROLPLANE,     0,              SBUS_MMAP_FBSIZE(4) },
+       { TCX_UNK6,             0,              SBUS_MMAP_FBSIZE(8) },
+       { TCX_UNK7,             0,              SBUS_MMAP_FBSIZE(8) },
+       { TCX_TEC,              0,              PAGE_SIZE           },
+       { TCX_BTREGS,           0,              PAGE_SIZE           },
+       { TCX_THC,              0,              PAGE_SIZE           },
+       { TCX_DHC,              0,              PAGE_SIZE           },
+       { TCX_ALT,              0,              PAGE_SIZE           },
+       { TCX_UNK2,             0,              0x20000             },
+       { 0,                    0,              0                   }
+};
+
+static void tcx_set_control_plane (struct fb_info_sbusfb *fb)
+{
+       u32 *p, *pend;
+        
+       p = fb->s.tcx.cplane;
+       if (!p) return;
+       for (pend = p + fb->type.fb_size; p < pend; p++)
+               *p &= 0xffffff;
+}
+                                                
+static void tcx_switch_from_graph (struct fb_info_sbusfb *fb)
+{
+       /* Reset control plane to 8bit mode if necessary */
+       if (fb->open && fb->mmaped)
+               tcx_set_control_plane (fb);
+}
+
+static void tcx_loadcmap (struct fb_info_sbusfb *fb, int index, int count)
+{
+       struct bt_regs *bt = fb->s.tcx.bt;
+       int i;
+                
+       bt->addr = index << 24;
+       for (i = index; count--; i++){
+               bt->color_map = fb->color_map CM(i,0) << 24;
+               bt->color_map = fb->color_map CM(i,1) << 24;
+               bt->color_map = fb->color_map CM(i,2) << 24;
+       }
+}
+
+static void tcx_restore_palette (struct fb_info_sbusfb *fb)
+{
+       struct bt_regs *bt = fb->s.tcx.bt;
+                
+       bt->addr = 0;
+       bt->color_map = 0xffffffff;
+       bt->color_map = 0xffffffff;
+       bt->color_map = 0xffffffff;
+}
+
+static void tcx_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
+{
+        struct bt_regs *bt = fb->s.tcx.bt;
+
+       /* Note the 2 << 24 is different from cg6's 1 << 24 */
+       bt->addr = 2 << 24;
+       bt->cursor = red[0] << 24;
+       bt->cursor = green[0] << 24;
+       bt->cursor = blue[0] << 24;
+       bt->addr = 3 << 24;
+       bt->cursor = red[1] << 24;
+       bt->cursor = green[1] << 24;
+       bt->cursor = blue[1] << 24;
+       bt->addr = 0;
+}
+
+/* Set cursor shape */
+static void tcx_setcurshape (struct fb_info_sbusfb *fb)
+{
+       struct tcx_thc *thc = fb->s.tcx.thc;
+       int i;
+
+       for (i = 0; i < 32; i++){
+               thc->thc_cursmask [i] = fb->cursor.bits[0][i];
+               thc->thc_cursbits [i] = fb->cursor.bits[1][i];
+       }
+}
+
+/* Load cursor information */
+static void tcx_setcursor (struct fb_info_sbusfb *fb)
+{
+       unsigned int v;
+       struct cg_cursor *c = &fb->cursor;
+
+       if (c->enable)
+               v = ((c->cpos.fbx - c->chot.fbx) << 16)
+                   |((c->cpos.fby - c->chot.fby) & 0xffff);
+       else
+               /* Magic constant to turn off the cursor */
+               v = ((65536-32) << 16) | (65536-32);
+       fb->s.tcx.thc->thc_cursxy = v;
+}
+
+static void tcx_blank (struct fb_info_sbusfb *fb)
+{
+       fb->s.tcx.thc->thc_misc &= ~TCX_THC_MISC_VIDEO;
+       /* This should put us in power-save */
+       fb->s.tcx.thc->thc_misc |= TCX_THC_MISC_VSYNC_DIS;
+        fb->s.tcx.thc->thc_misc |= TCX_THC_MISC_HSYNC_DIS;
+}
+
+static void tcx_unblank (struct fb_info_sbusfb *fb)
+{
+       fb->s.tcx.thc->thc_misc &= ~TCX_THC_MISC_VSYNC_DIS;
+       fb->s.tcx.thc->thc_misc &= ~TCX_THC_MISC_HSYNC_DIS;
+       fb->s.tcx.thc->thc_misc |= TCX_THC_MISC_VIDEO;
+}
+
+static void tcx_reset (struct fb_info_sbusfb *fb)
+{
+       if (fb->open && fb->mmaped)
+               tcx_set_control_plane(fb);
+       
+       /* Turn off stuff in the Transform Engine. */
+       fb->s.tcx.tec->tec_matrix = 0;
+       fb->s.tcx.tec->tec_clip = 0;
+       fb->s.tcx.tec->tec_vdc = 0;
+
+       /* Enable cursor in Brooktree DAC. */
+       fb->s.tcx.bt->addr = 0x06 << 24;
+       fb->s.tcx.bt->control |= 0x03 << 24;
+}
+
+static void tcx_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
+{
+       p->screen_base += (y_margin - fb->y_margin) * p->line_length + (x_margin - fb->x_margin);
+}
+
+static char idstring[60] __initdata = { 0 };
+
+__initfunc(char *tcxfb_init(struct fb_info_sbusfb *fb))
+{
+       struct fb_fix_screeninfo *fix = &fb->fix;
+       struct display *disp = &fb->disp;
+       struct fbtype *type = &fb->type;
+       unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr;
+       int lowdepth;
+
+#ifndef FBCON_HAS_CFB8
+       return NULL;
+#endif
+
+       lowdepth = prom_getbool (fb->prom_node, "tcx-8-bit");
+       
+       if (lowdepth) {
+               strcpy(fb->info.modename, "TCX8");
+               strcpy(fix->id, "TCX8");
+       } else {
+               strcpy(fb->info.modename, "TCX24");
+               strcpy(fix->id, "TCX24");
+       }
+       fix->line_length = fb->var.xres_virtual;
+       
+       disp->scrollmode = SCROLL_YREDRAW;
+       if (!disp->screen_base)
+               disp->screen_base = (char *)sparc_alloc_io(phys, 0, 
+                       type->fb_size, "tcx_ram", fb->iospace, 0);
+       disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin;
+       fb->s.tcx.tec = (struct tcx_tec *)sparc_alloc_io(fb->sbdp->reg_addrs[7].phys_addr, 0, 
+                       sizeof(struct tcx_tec), "tcx_tec", fb->iospace, 0);
+       fb->s.tcx.thc = (struct tcx_thc *)sparc_alloc_io(fb->sbdp->reg_addrs[9].phys_addr, 0, 
+                       sizeof(struct tcx_thc), "tcx_thc", fb->iospace, 0);
+       fb->s.tcx.bt = (struct bt_regs *)sparc_alloc_io(fb->sbdp->reg_addrs[8].phys_addr, 0, 
+                       sizeof(struct bt_regs), "tcx_dac", fb->iospace, 0);
+       if (!lowdepth) {
+               fb->s.tcx.cplane = (u32 *)sparc_alloc_io(fb->sbdp->reg_addrs[4].phys_addr, 0, 
+                               type->fb_size*4, "tcx_cplane", fb->iospace, 0);
+               type->fb_depth = 24;
+               fb->switch_from_graph = tcx_switch_from_graph;
+       } else {
+               /* As there can be one tcx in a machine only, we can write directly into
+                  tcx_mmap_map */
+               tcx_mmap_map[1].size = SBUS_MMAP_EMPTY;
+               tcx_mmap_map[4].size = SBUS_MMAP_EMPTY;
+               tcx_mmap_map[5].size = SBUS_MMAP_EMPTY;
+               tcx_mmap_map[6].size = SBUS_MMAP_EMPTY;
+       }
+       fb->dispsw = fbcon_cfb8;
+
+       fb->margins = tcx_margins;
+       fb->loadcmap = tcx_loadcmap;
+       if (prom_getbool (fb->prom_node, "hw-cursor")) {
+               fb->setcursor = tcx_setcursor;
+               fb->setcursormap = tcx_setcursormap;
+               fb->setcurshape = tcx_setcurshape;
+       }
+       fb->restore_palette = tcx_restore_palette;
+       fb->blank = tcx_blank;
+       fb->unblank = tcx_unblank;
+       fb->reset = tcx_reset;
+       
+       fb->physbase = 0;
+       fb->mmap_map = tcx_mmap_map;
+       
+       /* Initialize Brooktree DAC */
+       fb->s.tcx.bt->addr = 0x04 << 24;         /* color planes */
+       fb->s.tcx.bt->control = 0xff << 24;
+       fb->s.tcx.bt->addr = 0x05 << 24;
+       fb->s.tcx.bt->control = 0x00 << 24;
+       fb->s.tcx.bt->addr = 0x06 << 24;         /* overlay plane */
+       fb->s.tcx.bt->control = 0x73 << 24;
+       fb->s.tcx.bt->addr = 0x07 << 24;
+       fb->s.tcx.bt->control = 0x00 << 24;
+       
+       sprintf(idstring, "tcx at %x.%08lx Rev %d.%d %s", fb->iospace, phys,
+                   (fb->s.tcx.thc->thc_rev >> TCX_THC_REV_REV_SHIFT) & TCX_THC_REV_REV_MASK,
+                    (fb->s.tcx.thc->thc_rev >> TCX_THC_REV_MINREV_SHIFT) & TCX_THC_REV_MINREV_MASK,
+                   lowdepth ? "8-bit only" : "24-bit depth");
+                   
+       tcx_reset(fb);
+                   
+       return idstring;
+}
index ef3f9b1359663708936706528cf91f8bfdd71435..f2a357e7e22315e67b31eb15abb83b1d32a422fe 100644 (file)
@@ -22,6 +22,7 @@
  * KNOWN PROBLEMS/TO DO ==================================================== */
 
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
index cf1534a9ae04905c047b5a92cd14895e562fc676..97d65ef8c26186c1546be43191721bdd28ea8c11 100644 (file)
@@ -8,6 +8,7 @@
  *
  */ 
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
index f2bc39cd091ca57feb167e005ea1cea1078ea695..bb1102d9368578946dff47c0287ba600f62e2fcf 100644 (file)
@@ -8,6 +8,7 @@
  *  more details.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
index 5ed8b668abd4f77fb8c3342ca99d2e0dc12ccd57..5a4b21859551061593748e7d88ffa7ba4b18f950 100644 (file)
@@ -33,7 +33,7 @@
  *  more details.
  */
 
-#include <linux/config.h>
+
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
@@ -94,6 +94,7 @@ static void vgacon_save_screen(struct vc_data *c);
 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines);
 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse);
 static void vgacon_invert_region(struct vc_data *c, u16 *p, int count);
+static unsigned long vgacon_uni_pagedir[2];
 
 
 /* Description of the hardware situation */
@@ -292,16 +293,23 @@ __initfunc(static const char *vgacon_startup(void))
        return display_desc;
 }
 
-static int vga_use_count;
-
 static void vgacon_init(struct vc_data *c, int init)
 {
+       unsigned long p;
+       
        /* We cannot be loaded as a module, therefore init is always 1 */
        c->vc_can_do_color = vga_can_do_color;
        c->vc_cols = vga_video_num_columns;
        c->vc_rows = vga_video_num_lines;
        c->vc_complement_mask = 0x7700;
-       vga_use_count++;
+       p = *c->vc_uni_pagedir_loc;
+       if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
+           !--c->vc_uni_pagedir_loc[1])
+               con_free_unimap(c->vc_num);
+       c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
+       vgacon_uni_pagedir[1]++;
+       if (!vgacon_uni_pagedir[0] && p)
+               con_set_default_unimap(c->vc_num);
 }
 
 static inline void vga_set_mem_top(struct vc_data *c)
@@ -312,10 +320,13 @@ static inline void vga_set_mem_top(struct vc_data *c)
 static void vgacon_deinit(struct vc_data *c)
 {
        /* When closing the last console, reset video origin */
-       if (!--vga_use_count) {
+       if (!--vgacon_uni_pagedir[1]) {
                c->vc_visible_origin = vga_vram_base;
                vga_set_mem_top(c);
+               con_free_unimap(c->vc_num);
        }
+       c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
+       con_set_default_unimap(c->vc_num);
 }
 
 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse)
@@ -345,15 +356,19 @@ static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink,
 
 static void vgacon_invert_region(struct vc_data *c, u16 *p, int count)
 {
-       int col = vga_can_do_color;
-
-       while (count--) {
-               u16 a = *p;
-               if (col)
-                       a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
-               else
+       if (vga_can_do_color) {
+               while (count--) {
+                       u16 a = scr_readw(p);
+                       a = (((a) & 0x88ff) | (((a) & 0x7000) >> 4)
+                            | (((a) & 0x0700) << 4));
+                       scr_writew(a, p++);
+               }
+       } else {
+               while (count--) {
+                       u16 a = scr_readw(p);
                        a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
-               *p++ = a;
+                       scr_writew(a, p++);
+               }
        }
 }
 
@@ -862,6 +877,7 @@ static int vgacon_font_op(struct vc_data *c, struct console_font_op *op)
                op->width = 8;
                op->height = vga_video_font_height;
                op->charcount = vga_512_chars ? 512 : 256;
+               if (!op->data) return 0;
                rc = vgacon_do_font_op(op->data, 0, 0);
        } else
                rc = -ENOSYS;
index 927fbb46d3be54d0ee87647391c30ea9cd393da4..09884fb515f8258732dfc4117f5ed308cdc612cd 100644 (file)
@@ -16,6 +16,7 @@
 
 #undef VIRGEFBDEBUG
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
index 7b1676836c4acaac182c9e27b73313f85bba0a90..c6dca7358c25d53024be3ec0021bcb5a5f614ca3 100644 (file)
@@ -267,7 +267,7 @@ next:
        for (i = 0; i < uspi->s_apb; i++)
                if (SWAB32(*ubh_get_addr32(ind_ubh,i)))
                        break;
-       if (i >= uspi->s_apb)
+       if (i >= uspi->s_apb) {
                if (ubh_max_bcount(ind_ubh) != 1) {
                        retry = 1;
                }
@@ -280,6 +280,7 @@ next:
                        ubh_bforget(ind_ubh);
                        ind_ubh = NULL;
                }
+       }
        if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) {
                ubh_ll_rw_block (WRITE, 1, &ind_ubh);
                ubh_wait_on_buffer (ind_ubh);
index f669b764286e152254261bbd4613deb4d7853853..b1807bf3a9bf586e34a8e6a5d7ef828b68c5120b 100644 (file)
@@ -15,6 +15,8 @@
  */
 #define CUR_DEFAULT CUR_UNDERLINE
 
+#include <linux/config.h>
+
 #define NPAR 16
 
 struct vc_data {
@@ -33,7 +35,7 @@ struct vc_data {
        unsigned char   vc_ulcolor;             /* Color for underline mode */
        unsigned char   vc_halfcolor;           /* Color for half intensity mode */
        unsigned short  vc_complement_mask;     /* [#] Xor mask for mouse pointer */
-       unsigned short  vc_hi_font_mask;        /* [#] Attribute set for upper 256 chars or font or 0 if not supported */
+       unsigned short  vc_hi_font_mask;        /* [#] Attribute set for upper 256 chars of font or 0 if not supported */
        unsigned int    vc_x, vc_y;             /* Cursor position */
        unsigned int    vc_top, vc_bottom;      /* Scrolling region */
        unsigned int    vc_state;               /* Escape sequence parser state */
@@ -84,6 +86,8 @@ struct vc_data {
        unsigned int    vc_bell_duration;       /* Console bell duration */
        unsigned int    vc_cursor_type;
        struct vc_data **vc_display_fg;         /* [!] Ptr to var holding fg console for this display */
+       unsigned long   vc_uni_pagedir;
+       unsigned long   *vc_uni_pagedir_loc;  /* [!] Location of uni_pagedir variable for this console */
        /* additional information is in vt_kern.h */
 };
 
index 9aba19db33b9f11e148609ec9852d07b2c23f4c2..fd0bcd43fdba0cb1df5682a9806218949a923eda 100644 (file)
@@ -8,7 +8,8 @@
 #define IBMPC_MAP 2
 #define USER_MAP 3
 
-extern int hashtable_contents_valid;
-extern unsigned char inverse_translate(int glyph);
+struct vc_data;
+
+extern unsigned char inverse_translate(struct vc_data *conp, int glyph);
 extern unsigned short *set_translate(int m);
-extern int conv_uni_to_pc(long ucs);
+extern int conv_uni_to_pc(struct vc_data *conp, long ucs);
index 2c7fc1de1c516420ca5ee8013b003e7691383b46..7c631b44ae6a9230884081901e2c23140b862c7a 100644 (file)
@@ -272,6 +272,8 @@ struct display {
    struct display_switch *dispsw;   /* low level operations */
    u_short scrollmode;              /* Scroll Method */
    short yscroll;                   /* Hardware scrolling */
+   unsigned char fgshift, bgshift;
+   unsigned short charmask;        /* 0xff or 0x1ff */
 };
 
 
@@ -334,6 +336,38 @@ struct fb_info_gen {
    /* From here on everything is device dependent */
 };
 
+    /*
+     *  `Generic' versions of the frame buffer device operations
+     */
+
+extern int fbgen_get_fix(struct fb_fix_screeninfo *fix, int con,
+                        struct fb_info *info);
+extern int fbgen_get_var(struct fb_var_screeninfo *var, int con,
+                        struct fb_info *info);
+extern int fbgen_set_var(struct fb_var_screeninfo *var, int con,
+                        struct fb_info *info);
+extern int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+                         struct fb_info *info);
+extern int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+                         struct fb_info *info);
+extern int fbgen_pan_display(struct fb_var_screeninfo *var, int con,
+                            struct fb_info *info);
+extern int fbgen_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, unsigned long arg, int con,
+                      struct fb_info *info);
+
+    /*
+     *  Helper functions
+     */
+
+extern int fbgen_do_set_var(struct fb_var_screeninfo *var, int isactive,
+                           struct fb_info_gen *info);
+extern void fbgen_set_disp(int con, struct fb_info_gen *info);
+extern void fbgen_install_cmap(int con, struct fb_info_gen *info);
+extern int fbgen_update_var(int con, struct fb_info *info);
+extern int fbgen_switch(int con, struct fb_info *info);
+extern void fbgen_blank(int blank, struct fb_info *info);
+
 
 struct fb_videomode {
     const char *name;
index 0ebec6ba37d9244106a99f976cd2b76d626ca4bf..37f0e066d6f6ce505d48b29d91b8f9d1b62e80f2 100644 (file)
@@ -126,5 +126,6 @@ struct ipv6_mreq {
 #define IPV6_MULTICAST_LOOP    19
 #define IPV6_ADD_MEMBERSHIP    20
 #define IPV6_DROP_MEMBERSHIP   21
+#define IPV6_ROUTER_ALERT      22
 
 #endif
index c4a3febfedaf2790db225482c9ec32da515e2a0b..5a4c620dc0e329239762a2bdde370b401120cb63 100644 (file)
@@ -149,6 +149,9 @@ struct console_font_op {
 
 #define KD_FONT_FLAG_GLOBAL            1       /* Change on _all_ consoles */
 #define KD_FONT_FLAG_DONT_RECALC       2       /* Don't recalculate hw charcell size [compat] */
+#ifdef __KERNEL__
+#define KD_FONT_FLAG_NEW               0x80000000      /* Indicate new KDFONTOP interface, which should be more strict */
+#endif
 
 /* note: 0x4B00-0x4B4E all have had a value at some time;
    don't reuse for the time being */
index e1e108a65503452efda4cd3f7f8802826a537773..6f1901b424551e1bdd5aaa4ad4057b4424fe2e0a 100644 (file)
@@ -109,6 +109,7 @@ enum net_directory_inos {
        PROC_NET_AX25_ROUTE,
        PROC_NET_AX25,
        PROC_NET_AX25_CALLS,
+       PROC_NET_BMAC,
        PROC_NET_NR_NODES,
        PROC_NET_NR_NEIGH,
        PROC_NET_NR,
index 640fd41678ff26e024a461be54b21ec2e77d60f2..45a14a4b3db00f4c800646d4d5cc09be6ae55673 100644 (file)
@@ -40,4 +40,7 @@ extern void invert_screen(int currcons, int offset, int count, int shift);
 extern void getconsxy(int currcons, char *p);
 extern void putconsxy(int currcons, char *p);
 
+extern u16 vcs_scr_readw(int currcons, u16 *org);
+extern void vcs_scr_writew(int currcons, u16 val, u16 *org);
+
 #endif
diff --git a/include/linux/simp.h b/include/linux/simp.h
deleted file mode 100644 (file)
index bf838f8..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * include/linux/simp.h  -- simple allocator for cached objects
- *
- * This is meant as a faster and simpler (not full-featured) replacement
- * for SLAB, thus the name "simp" :-)
- *
- * (C) 1997 Thomas Schoebel-Theuer
- */
-
-#ifndef SIMP_H
-#define SIMP_H
-
-/* used for constructors / destructors */
-typedef void (*structor)(void *);
-
-/* create an object cache */
-/* positive clearable_offset means the next two pointers at that offset
- * can be internally used for freelist pointers when the object is
- * deallocated / not in use;
- * if there is no space inside the element that can be reused for
- * this purpose, supply -1. Using positive offsets is essential for
- * saving space with very small-sized objects.
- *
- * Note for big-sized objects in the range of whole pages, use
- * the fast Linux page allocator instead, directly.
- */
-extern struct simp * simp_create(char * name, long size,
-                                structor first_ctor, 
-                                structor again_ctor, 
-                                structor dtor);
-
-/* alloc / dealloc routines */
-extern void * simp_alloc(struct simp * simp);
-extern void simp_free(void * objp);
-
-/* garbage collection */
-extern long simp_garbage(void);
-
-#endif
index 561d74d8097ca6b738b3670147a8cbfe953cab54..ee6c79970cad91e31ef08093293b351629e125d1 100644 (file)
@@ -151,6 +151,8 @@ extern int                  skb_headroom(struct sk_buff *skb);
 extern int                     skb_tailroom(struct sk_buff *skb);
 extern void                    skb_reserve(struct sk_buff *skb, unsigned int len);
 extern void                    skb_trim(struct sk_buff *skb, unsigned int len);
+extern void    skb_over_panic(struct sk_buff *skb, int len, void *here);
+extern void    skb_under_panic(struct sk_buff *skb, int len, void *here);
 
 /* Internal */
 extern __inline__ atomic_t *skb_datarefp(struct sk_buff *skb)
@@ -437,10 +439,6 @@ extern __inline__ struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list)
        return result;
 }
 
-
-extern const char skb_put_errstr[];
-extern const char skb_push_errstr[];
-
 /*
  *     Add data to an sk_buff
  */
@@ -452,9 +450,9 @@ extern __inline__ unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
        skb->len+=len;
        if(skb->tail>skb->end)
        {
-               __label__ here;
-               panic(skb_put_errstr,&&here,len);
-here:          ;
+               __label__ here; 
+               skb_over_panic(skb, len, &&here); 
+here:          ;
        }
        return tmp;
 }
@@ -466,8 +464,8 @@ extern __inline__ unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
        if(skb->data<skb->head)
        {
                __label__ here;
-               panic(skb_push_errstr, &&here,len);
-here:          ;
+               skb_under_panic(skb, len, &&here);
+here:          ;
        }
        return skb->data;
 }
index 87b175b994d4ad0ebbb2da92d08d7edd5f125ad9..a6e306381517c268d3376d2dd8eb0e258549eece 100644 (file)
@@ -183,6 +183,7 @@ struct ucred {
 #define PF_ROUTE       AF_ROUTE
 #define PF_PACKET      AF_PACKET
 #define PF_ASH         AF_ASH
+#define PF_ECONET      AF_ECONET
 #define PF_ATMSVC      AF_ATMSVC
 #define PF_SNA         AF_SNA
 
index bdc9f8763a5efdb7b7da7b363ddf0ba3bd459b5d..e4f48e908d30e7aaecc399338e36395c0f280d25 100644 (file)
@@ -6,6 +6,7 @@
  * with information needed by the vt package
  */
 
+#include <linux/config.h>
 #include <linux/vt.h>
 
 /*
@@ -16,7 +17,9 @@
  * fixed.  The linux/Documentation directory includes a code snippet
  * to save and restore the text font.
  */
+#ifdef CONFIG_VGA_CONSOLE
 #define BROKEN_GRAPHICS_PROGRAMS 1
+#endif
 
 extern struct vt_struct {
        int vc_num;                             /* The console number */
@@ -66,10 +69,12 @@ int con_set_trans_old(unsigned char * table);
 int con_get_trans_old(unsigned char * table);
 int con_set_trans_new(unsigned short * table);
 int con_get_trans_new(unsigned short * table);
-void con_clear_unimap(struct unimapinit *ui);
-int con_set_unimap(ushort ct, struct unipair *list);
-int con_get_unimap(ushort ct, ushort *uct, struct unipair *list);
-void con_set_default_unimap(void);
+int con_clear_unimap(int currcons, struct unimapinit *ui);
+int con_set_unimap(int currcons, ushort ct, struct unipair *list);
+int con_get_unimap(int currcons, ushort ct, ushort *uct, struct unipair *list);
+int con_set_default_unimap(int currcons);
+void con_free_unimap(int currcons);
+void con_protect_unimap(int currcons, int rdonly);
 
 /* vt.c */
 
index 8fb0fbed7616e7e59ebec1e51f62c971e2ce5c4c..8ca62a7edcc769a0808fb1dd1cdb31e6feebd105 100644 (file)
@@ -100,6 +100,7 @@ struct netlink_callback;
 extern int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb);
 extern int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
 extern int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+extern int inet6_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
 
 extern void rt6_ifdown(struct device *dev);
 
index 47705c923cd5f137762c12d52a1169afed28ce9e..acf37b3579ca7b3f102ddaa719b53047cc26e92a 100644 (file)
@@ -4,7 +4,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>
  *
- *     $Id: ipv6.h,v 1.11 1998/05/07 15:42:46 davem Exp $
+ *     $Id: ipv6.h,v 1.12 1998/07/15 05:05:02 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -118,6 +118,31 @@ struct frag_queue {
        __u8                    *nhptr;
 };
 
+struct ipv6_tlvtype
+{
+       u8 type;
+       u8 len;
+};
+
+struct ip6_ra_chain
+{
+       struct ip6_ra_chain     *next;
+       struct sock             *sk;
+       int                     sel;
+       void                    (*destructor)(struct sock *);
+};
+
+extern struct ip6_ra_chain     *ip6_ra_chain;
+
+extern int                     ip6_ra_control(struct sock *sk, int sel,
+                                              void (*destructor)(struct sock *));
+
+
+extern int                     ip6_call_ra_chain(struct sk_buff *skb, int sel);
+
+extern int                     ip6_dstopt_unknown(struct sk_buff *skb,
+                                                  struct ipv6_tlvtype *hdr);
+
 extern int                     ipv6_routing_header(struct sk_buff **skb, 
                                                    struct device *dev,
                                                    __u8 *nhptr, 
index 4b6d2d5ee89560ca9500160163fad3a1620cb1c8..ed05e12bea37ce5e5c910a62d364a8ecc2dbda7d 100644 (file)
@@ -468,6 +468,9 @@ struct sock {
 #endif
 #ifdef CONFIG_NETLINK
                struct netlink_opt      af_netlink;
+#endif
+#if defined(CONFIG_ECONET) || defined(CONFIG_ECONET_MODULE)
+               struct econet_opt       *af_econet;
 #endif
        } protinfo;             
 
index a72bd04265dd448749e067d9789d8c4ef839aad2..5ac507bd52f547699a3cd571711c575db8e13f2c 100644 (file)
@@ -147,6 +147,7 @@ extern unsigned int x25_new_lci(struct x25_neigh *);
 extern struct sock *x25_find_socket(unsigned int, struct x25_neigh *);
 extern void x25_destroy_socket(struct sock *);
 extern int  x25_rx_call_request(struct sk_buff *, struct x25_neigh *, unsigned int);
+extern void x25_kill_by_neigh(struct x25_neigh *);
 
 #include <net/x25call.h>
 
@@ -161,6 +162,7 @@ extern void x25_terminate_link(struct x25_neigh *);
 extern int  x25_parse_facilities(struct sk_buff *, struct x25_facilities *);
 extern int  x25_create_facilities(unsigned char *, struct x25_facilities *);
 extern int  x25_negotiate_facilities(struct sk_buff *, struct sock *, struct x25_facilities *);
+extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *);
 
 /* x25_in.c */
 extern int  x25_process_rx_frame(struct sock *, struct sk_buff *);
index fc0de9b60064bf6ba5836587d863e163673392e3..c7c0e91af53c9e45dbf2d248547701f4aa9c31c9 100644 (file)
@@ -127,16 +127,23 @@ static inline void free_one_pgd(pgd_t * dir)
  */
 void clear_page_tables(struct task_struct * tsk)
 {
+       pgd_t * page_dir = tsk->mm->pgd;
        int i;
-       pgd_t * page_dir;
 
-       page_dir = tsk->mm->pgd;
-       if (!page_dir || page_dir == swapper_pg_dir) {
-               printk("%s trying to clear kernel page-directory: not good\n", tsk->comm);
-               return;
-       }
+       if (!page_dir || page_dir == swapper_pg_dir)
+               goto out_bad;
        for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
                free_one_pgd(page_dir + i);
+
+       /* keep the page table cache within bounds */
+       check_pgt_cache();
+       return;
+
+out_bad:
+       printk(KERN_ERR 
+               "clear_page_tables: %s trying to clear kernel pgd\n",
+               tsk->comm);
+       return;
 }
 
 /*
@@ -146,19 +153,26 @@ void clear_page_tables(struct task_struct * tsk)
  */
 void free_page_tables(struct mm_struct * mm)
 {
+       pgd_t * page_dir = mm->pgd;
        int i;
-       pgd_t * page_dir;
 
-       page_dir = mm->pgd;
-       if (page_dir) {
-               if (page_dir == swapper_pg_dir) {
-                       printk("free_page_tables: Trying to free kernel pgd\n");
-                       return;
-               }
-               for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
-                       free_one_pgd(page_dir + i);
-               pgd_free(page_dir);
-       }
+       if (!page_dir)
+               goto out;
+       if (page_dir == swapper_pg_dir)
+               goto out_bad;
+       for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
+               free_one_pgd(page_dir + i);
+       pgd_free(page_dir);
+
+       /* keep the page table cache within bounds */
+       check_pgt_cache();
+out:
+       return;
+
+out_bad:
+       printk(KERN_ERR
+               "free_page_tables: Trying to free kernel pgd\n");
+       return;
 }
 
 int new_page_tables(struct task_struct * tsk)
index 3ea31f2037b35326257a651be7185509a1407731..172bcd8f11e62d083081a192b173b74db4b40a8e 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -196,9 +196,14 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
                        if ((prot & PROT_WRITE) && !(file->f_mode & 2))
                                return -EACCES;
 
+                       /* Make sure we don't allow writing to an append-only file.. */
+                       if (IS_APPEND(file->f_dentry->d_inode) && (file->f_mode & 2))
+                               return -EACCES;
+
                        /* make sure there are no mandatory locks on the file. */
                        if (locks_verify_locked(file->f_dentry->d_inode))
                                return -EAGAIN;
+
                        /* fall through */
                case MAP_PRIVATE:
                        if (!(file->f_mode & 1))
diff --git a/mm/simp.c b/mm/simp.c
deleted file mode 100644 (file)
index 581cde3..0000000
--- a/mm/simp.c
+++ /dev/null
@@ -1,435 +0,0 @@
-#define NULL 0
-/*
- * mm/simp.c  -- simple allocator for cached objects
- *
- * (C) 1997 Thomas Schoebel-Theuer
- */
-
-#include <linux/simp.h>
-#include <linux/tasks.h>
-#include <linux/smp.h>
-#include <linux/mm.h>
-#include <asm/spinlock.h>
-
-/* The next two defines can be independently enabled for debugging */
-/*#define DEBUG*/
-/*#define DEAD_BEEF*/
-
-#ifdef DEAD_BEEF
-#define DEBUG_BEEF 1
-#else
-#define DEBUG_BEEF 0
-#endif
-
-#ifdef __SMP__
-#define NR_PROCESSORS  NR_CPUS
-#define GLOBAL_SIZE CHUNK_SIZE
-#else
-#define NR_PROCESSORS  1
-#define GLOBAL_SIZE PAGE_SIZE
-#endif
-
-#define POSTBUFFER_SIZE 63
-#define ORDER 2
-#define CHUNK_SIZE (PAGE_SIZE*(1<<ORDER))
-#define CHUNK_BASE(ptr) (struct header*)(((unsigned long)(ptr)) & ~(CHUNK_SIZE-1))
-#define CHUNK_END(hdr) (void**)((char*)(hdr) + CHUNK_SIZE)
-
-#define COLOR_INCREMENT (8*sizeof(void*)) /* should be 1 cache line */
-#define ALIGN_CACHE(adr) ((((((unsigned long)adr) - 1) / COLOR_INCREMENT) + 1) * COLOR_INCREMENT)
-#define HEADER_SIZE ALIGN_CACHE(sizeof(struct header))
-#define ELEM_SIZE ALIGN_CACHE(sizeof(struct elem))
-#define FILL_TYPE(name,wrongsize) char name[ALIGN_CACHE(wrongsize)-(wrongsize)]
-
-#define MAX_SIMPS ((GLOBAL_SIZE / sizeof(struct simp)) - 1)
-
-struct header { /* this is at the beginning of each memory region */
-       /* 1st cache line */
-       void ** index;
-       void ** fresh;
-       struct simp * father;
-       void ** emptypos;
-       struct header * next;
-       structor again_ctor;
-       structor first_ctor;
-       void * fill[1];
-#ifdef DEBUG
-       /* 2nd cache line */
-       char magic[32];
-#endif
-};
-
-struct per_processor {
-       void ** buffer_pos;
-       void * postbuffer[POSTBUFFER_SIZE];
-};
-
-struct simp {
-       /* 1st cache lines */
-       struct per_processor private[NR_PROCESSORS];
-       /* next cache line */
-       struct header * usable_list;
-       spinlock_t lock;
-       /* This value is negative on Alpha SMP.  */
-       /* char fill[sizeof(void*) - sizeof(spinlock_t)]; */
-       long real_size;
-       long max_elems;
-       structor again_ctor;
-       structor first_ctor;
-       structor dtor;
-       long fill2;
-       /* next cache line */
-       long create_offset;
-       long color;
-       long max_color;
-       long size;
-       long fill3[4];
-       /* next cache line */
-       char name[32];
-};
-
-struct global_data {
-       /* 1st cache line */
-       long changed_flag;
-       long nr_simps;
-       spinlock_t lock;
-       char fill[(6+8)*sizeof(void*)+sizeof(void*)-sizeof(spinlock_t)];
-       /* rest */
-       struct simp simps[MAX_SIMPS];
-};
-
-static struct global_data * global = NULL;
-
-#ifdef DEBUG
-static char global_magic[32] = "SIMP header SdC581oi9rY20051962\n";
-#endif
-
-struct simp * simp_create(char * name, long size,
-                         structor first_ctor, 
-                         structor again_ctor, 
-                         structor dtor)
-{
-       struct simp * simp;
-       long fraction;
-       long real_size;
-       int cpu;
-
-       if(!global) {
-#ifdef __SMP__
-               global = (struct global_data*)__get_free_pages(GFP_KERNEL, ORDER);
-               memset(global, 0, CHUNK_SIZE);
-#else
-               global = (struct global_data*)get_free_page(GFP_KERNEL);
-#endif
-               spin_lock_init(&global->lock);
-       }
-
-       spin_lock(&global->lock);
-       simp = &global->simps[global->nr_simps++];
-       spin_unlock(&global->lock);
-
-       if(global->nr_simps >= MAX_SIMPS) {
-               printk("SIMP: too many simps allocated\n");
-               return NULL;
-       }
-       memset(simp, 0, sizeof(struct simp));
-       spin_lock_init(&simp->lock);
-       strncpy(simp->name, name, 15);
-       simp->size = size;
-       simp->real_size = real_size = ALIGN_CACHE(size);
-       /* allow aggregation of very small objects in 2-power fractions of
-        * cachelines */
-       fraction = COLOR_INCREMENT / 2;
-       while(size <= fraction && fraction >= sizeof(void*)) {
-               simp->real_size = fraction;
-               fraction >>= 1;
-       }
-       simp->first_ctor = first_ctor;
-       simp->again_ctor = again_ctor;
-       simp->dtor = dtor;
-       
-       real_size += sizeof(void*);
-       simp->max_elems = (CHUNK_SIZE - HEADER_SIZE) / real_size;
-       simp->max_color = (CHUNK_SIZE - HEADER_SIZE) % real_size;
-       for(cpu = 0; cpu < NR_PROCESSORS; cpu++) {
-               struct per_processor * private = &simp->private[cpu];
-               private->buffer_pos = private->postbuffer;
-       }
-       return simp;
-}
-
-/* Do *not* inline this, it clobbers too many registers... */
-static void alloc_header(struct simp * simp)
-{
-       struct header * hdr;
-       char * ptr;
-       void ** index;
-       long count;
-
-       spin_unlock(&simp->lock);
-       for(;;) {
-               hdr = (struct header*)__get_free_pages(GFP_KERNEL, ORDER);
-               if(hdr)
-                       break;
-               if(!simp_garbage())
-                       return;
-       }
-#ifdef DEBUG
-       if(CHUNK_BASE(hdr) != hdr)
-               panic("simp: bad kernel page alignment");
-#endif
-
-       memset(hdr, 0, HEADER_SIZE);
-#ifdef DEBUG
-       memcpy(hdr->magic, global_magic, sizeof(global_magic));
-#endif
-       hdr->father = simp;
-       hdr->again_ctor = simp->again_ctor;
-       hdr->first_ctor = simp->first_ctor;
-       
-       /* note: races on simp->color don't produce any error :-) */
-       ptr = ((char*)hdr) + HEADER_SIZE + simp->color;
-       index = CHUNK_END(hdr);
-       for(count = 0; count < simp->max_elems; count++) {
-               *--index = ptr;
-               ptr += simp->real_size;
-               /* note: constructors are not called here in bunch but
-                * instead at each single simp_alloc(), in order
-                * to maximize chances that the cache will be
-                * polluted after a simp_alloc() anyway,
-                * and not here. */
-       }
-       hdr->index = hdr->fresh = hdr->emptypos = index;
-
-       spin_lock(&simp->lock);
-       simp->color += COLOR_INCREMENT;
-       if(simp->color >= simp->max_color)
-               simp->color = 0;
-       hdr->next = simp->usable_list;
-       simp->usable_list = hdr;
-}
-
-/* current x86 memcpy() is horribly moving around registers for nothing,
- * is doing unnecessary work if the size is dividable by a power-of-two,
- * and it clobbers way too many registers.
- * This results in nearly any other register being transfered to stack.
- * Fixing this would be a major win for the whole kernel!
- */
-static void ** bunch_alloc(struct simp * simp, void ** buffer)
-{
-       struct header * hdr;
-       void ** index;
-       void ** to;
-       void ** end;
-       structor todo;
-       long length;
-
-       spin_lock(&simp->lock);
-       hdr = simp->usable_list;
-       if(!hdr) {
-               alloc_header(simp);
-               hdr = simp->usable_list;
-               if(!hdr) {
-                       spin_unlock(&simp->lock);
-                       *buffer = NULL;
-                       return buffer+1;
-               }
-       }
-       
-       index = hdr->index;
-       end = hdr->fresh;
-       todo = hdr->again_ctor;
-       if(index == end) {
-               end = CHUNK_END(hdr);
-               todo = hdr->first_ctor;
-       }
-       to = index + POSTBUFFER_SIZE/2;
-       if(to >= end) {
-               to = end;
-               if(to == CHUNK_END(hdr)) {
-                       simp->usable_list = hdr->next;
-                       hdr->next = NULL;
-               }
-       }
-       if(to > hdr->fresh)
-               hdr->fresh = to;
-       hdr->index = to;
-       length = ((unsigned long)to) - (unsigned long)index;
-       to = buffer + (length/sizeof(void**));
-
-       memcpy(buffer, index, length);
-
-       spin_unlock(&simp->lock);
-
-       if(todo) {
-               do {
-                       todo(*buffer++);
-               } while(buffer < to);
-       }
-       return to;
-}
-
-void * simp_alloc(struct simp * simp)
-{
-#ifdef __SMP__
-       const long cpu = smp_processor_id();
-       struct per_processor * priv = &simp->private[cpu];
-#else
-#define priv (&simp->private[0]) /*fool gcc to use no extra register*/
-#endif
-       void ** buffer_pos = priv->buffer_pos;
-       void * res;
-
-       if(buffer_pos == priv->postbuffer) {
-               buffer_pos = bunch_alloc(simp, buffer_pos);
-       }
-       buffer_pos--;
-       res = *buffer_pos;
-       priv->buffer_pos = buffer_pos;
-       return res;
-}
-
-#ifdef DEBUG
-long check_header(struct header * hdr, void * ptr)
-{
-       void ** test;
-
-       if(!hdr) {
-               printk("SIMP: simp_free() with NULL pointer\n");
-               return 1;
-       }
-       if(strncmp(hdr->magic, global_magic, 32)) {
-               printk("SIMP: simpe_free() with bad ptr %p, or header corruption\n", ptr);
-               return 1;
-       }
-       /* This is brute force, but I don't want to pay for any
-        * overhead if debugging is not enabled, in particular
-        * no space overhead for keeping hashtables etc. */
-       test = hdr->index;
-       while(test < CHUNK_END(hdr)) {
-               if(*test++ == ptr) {
-                       printk("SIMP: trying to simp_free(%p) again\n", ptr);
-                       return 1;
-               }
-       }
-       return 0;
-}
-#endif
-
-static void ** bunch_free(struct simp * simp, void ** buffer)
-{
-       void ** stop;
-
-       stop = buffer - POSTBUFFER_SIZE/3;
-
-       spin_lock(&simp->lock);
-       while(buffer > stop) {
-               void * elem = buffer[-1];
-               struct header * hdr = CHUNK_BASE(elem);
-               void ** index = hdr->index;
-               index--;
-               hdr->index = index;
-               *index = elem;
-               if(!hdr->next) {
-                       hdr->next = simp->usable_list;
-                       simp->usable_list = hdr;
-               }
-
-               buffer -= 2;
-               elem = *buffer;
-               hdr = CHUNK_BASE(elem);
-               index = hdr->index;
-               index--;
-               hdr->index = index;
-               *index = elem;
-               if(!hdr->next) {
-                       hdr->next = simp->usable_list;
-                       simp->usable_list = hdr;
-               }
-       }
-       spin_unlock(&simp->lock);
-       global->changed_flag = 1;
-       return buffer;
-}
-
-void simp_free(void * objp)
-{
-       struct header * hdr;
-       void ** buffer_pos;
-       struct per_processor * private;
-#ifdef __SMP__
-       const long cpu = smp_processor_id();
-#else
-       const long cpu = 0;
-#endif
-
-       hdr = CHUNK_BASE(objp);
-#ifdef DEBUG
-       if(check_header(hdr, objp))
-               return;
-#endif
-
-       private = &hdr->father->private[cpu];
-       buffer_pos = private->buffer_pos;
-       if(buffer_pos >= private->postbuffer+POSTBUFFER_SIZE) {
-               buffer_pos = bunch_free(hdr->father, buffer_pos);
-       }
-
-       *buffer_pos++ = objp;
-       private->buffer_pos = buffer_pos;
-
-#ifdef DEAD_BEEF
-       {
-               unsigned int * ptr = (unsigned int*)objp;
-               int count = (hdr->father->real_size - ELEM_SIZE) / sizeof(unsigned int);
-               while(count--)
-                       *ptr++ = 0xdeadbeef;
-       }
-#endif
-}
-
-long simp_garbage(void)
-{
-       int i;
-       int res;
-
-       if(!global->changed_flag)
-               return 0; /* shortcut */
-       /* Note: costs do not matter here. Any heavy thrashing of
-        * simp chunks that could be caused by pools stealing each
-        * other's memory has to be considered a BUG :-)
-        * Simply avoid memory shortages by conservative allocating
-        * policies.
-        */
-       global->changed_flag = 0;
-       res = 0;
-       for(i = 0; i < global->nr_simps; i++) {
-               struct simp * simp = &global->simps[i];
-               struct header ** base = &simp->usable_list;
-               struct header * del;
-
-               spin_lock(&simp->lock);
-               del = *base;
-               while(del) {
-                       if(del->index == del->emptypos) {
-                               if(simp->dtor) {
-                                       void ** ptr = del->index;
-                                       while(ptr < CHUNK_END(del)) {
-                                               simp->dtor(*ptr++);
-                                       }
-                               }
-                               *base = del->next;
-#ifdef DEBUG
-                               memset(del, 0, CHUNK_SIZE);
-#endif
-                               free_pages((unsigned long)del, ORDER);
-                               res++;
-                       } else
-                               base = &del->next;
-                       del = *base;
-               }
-               spin_unlock(&simp->lock);
-       }
-       return res;
-}
-
index 0f32c8397a302b4ca5a0ff99c7fa00d2f89e5294..0bbf171fa6610fddb6d0b7ad3c526a00c81a73a9 100644 (file)
@@ -9,7 +9,8 @@
 
 MOD_SUB_DIRS := ipv4
 ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \
-               netrom rose lapb x25 wanrouter netlink sched packet sunrpc #decnet
+               netrom rose lapb x25 wanrouter netlink sched packet sunrpc \
+               econet #decnet
 SUB_DIRS     := core ethernet sched
 MOD_LIST_NAME := NET_MISC_MODULES
 
@@ -140,6 +141,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_ECONET),y)
+SUB_DIRS += econet
+else
+  ifeq ($(CONFIG_ECONET),m)
+  MOD_SUB_DIRS += econet
+  endif
+endif
+
 # We must attach netsyms.o to socket.o, as otherwise there is nothing
 # to pull the object file from the archive.
 
index 44ad2189d39a295b15f50eb1e0c8d8a81d45f9f7..3edee0168d65913b0064d1b4b3f9b16338533304 100644 (file)
@@ -91,7 +91,7 @@
  *                     Jonathan(G4KLX)         Support for packet forwarding.
  *     AX.25 036       Jonathan(G4KLX)         Major restructuring.
  *                     Joerg(DL1BKE)           Fixed DAMA Slave.
- *                     Jonathan(G4KLX)         Fix widlcard listen parameter setting.
+ *                     Jonathan(G4KLX)         Fix wildcard listen parameter setting.
  *     AX.25 037       Jonathan(G4KLX)         New timer architecture.
  *      AX.25 038       Matthias(DG2FEF)        Small fixes to the syscall interface to make kernel
  *                                              independent of AX25_MAX_DIGIS used by applications.
index c49fbeb200684c16ac485f3bb513afaa3a1b2b63..a366acfbad300312e8ac701915c3eae46ed30c24 100644 (file)
@@ -77,11 +77,22 @@ extern atomic_t ip_frag_mem;
 static kmem_cache_t *skbuff_head_cache;
 
 /*
- *     Strings we don't want inline's duplicating
+ *     Keep out-of-line to prevent kernel bloat.
+ *     __builtin_return_address is not used because it is not always
+ *     reliable. 
  */
-const char skb_push_errstr[]="skpush:under: %p:%d";
-const char skb_put_errstr[] ="skput:over: %p:%d";
+
+void skb_over_panic(struct sk_buff *skb, int sz, void *here)
+{
+       panic("skput:over: %p:%d put:%d dev:%s", 
+               here, skb->len, sz, skb->dev ? skb->dev->name : "<NULL>");
+}
+
+void skb_under_panic(struct sk_buff *skb, int sz, void *here)
+{
+        panic("skput:over: %p:%d put:%d dev:%s",
+                here, skb->len, sz, skb->dev ? skb->dev->name : "<NULL>");
+}
 
 void show_net_buffers(void)
 {
index e1d1379aa30b955e59c5194c18c1096e5dd3484b..54d1c0a5462877ea4228b823f5c3470f1635a3a4 100644 (file)
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/poll.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -212,7 +213,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                           are treated in BSD as hints */
                           
                        if (val > sysctl_wmem_max)
-                               return 0;
+                               val = sysctl_wmem_max;
 
                        sk->sndbuf = max(val*2,2048);
 
@@ -230,7 +231,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                           are treated in BSD as hints */
                          
                        if (val > sysctl_rmem_max)
-                               return 0;
+                               val = sysctl_rmem_max;
 
                        /* FIXME: is this lower bound the right one? */
                        sk->rcvbuf = max(val*2,256);
@@ -495,10 +496,11 @@ void sk_free(struct sock *sk)
        kmem_cache_free(sk_cachep, sk);
 }
 
-void sk_init(void)
+__initfunc(void sk_init(void))
 {
        sk_cachep = kmem_cache_create("sock", sizeof(struct sock), 0,
                                      SLAB_HWCACHE_ALIGN, 0, 0);
+
 }
 
 /*
index 5d83716a82a1a1f06d9a3b26f7486d77f05ed9c4..5b5a543357f07c9a5d53e4486701d9d38e642582 100644 (file)
@@ -738,8 +738,8 @@ static struct proto_ops econet_ops = {
        econet_release,
        econet_bind,
        sock_no_connect,
-       NULL,
-       NULL,
+       sock_no_socketpair,
+       sock_no_accept,
        econet_getname, 
        datagram_poll,
        econet_ioctl,
index 4fcdc2622ef72c9c995fe6da1be5e1392010a17c..39ed076ed511ccd505e829638fcf945847402546 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/net/inet/arp.c
  *
- * Version:    $Id: arp.c,v 1.66 1998/05/08 01:54:55 davem Exp $
+ * Version:    $Id: arp.c,v 1.67 1998/06/19 13:22:31 davem Exp $
  *
  * Copyright (C) 1994 by Florian  La Roche
  *
@@ -15,7 +15,7 @@
  * 2 of the License, or (at your option) any later version.
  *
  * Fixes:
- *             Alan Cox        :       Removed the ethernet assumptions in 
+ *             Alan Cox        :       Removed the Ethernet assumptions in 
  *                                     Florian's code
  *             Alan Cox        :       Fixed some small errors in the ARP 
  *                                     logic
@@ -230,7 +230,7 @@ static int arp_constructor(struct neighbour *neigh)
                neigh->ops = &arp_direct_ops;
                neigh->output = neigh->ops->queue_xmit;
        } else {
-               /* Good devices (checked by reading texts, but only ethernet is
+               /* Good devices (checked by reading texts, but only Ethernet is
                   tested)
 
                   ARPHRD_ETHER: (ethernet, apfddi)
@@ -240,7 +240,7 @@ static int arp_constructor(struct neighbour *neigh)
                   ARPHRD_ARCNET:
                   etc. etc. etc.
 
-                  ARPHRD_IPDDP will also work, if author repaires it.
+                  ARPHRD_IPDDP will also work, if author repairs it.
                   I did not it, because this driver does not work even
                   in old paradigm.
                 */
@@ -1099,7 +1099,7 @@ __initfunc(void arp_init (void))
 #ifdef CONFIG_AX25_MODULE
 
 /*
- *     ax25 -> ascii conversion
+ *     ax25 -> ASCII conversion
  */
 char *ax2asc(ax25_address *a)
 {
index 4b89ab6767bc1ba02306f27408b74f8964a6a5f4..3e13671a287f3aafc46fd4cbf6c877cfe0ca1825 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             IPv4 FIB: lookup engine and maintenance routines.
  *
- * Version:    $Id: fib_hash.c,v 1.3 1998/03/08 05:56:16 davem Exp $
+ * Version:    $Id: fib_hash.c,v 1.4 1998/07/15 05:05:08 davem Exp $
  *
  * Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -274,7 +274,7 @@ fn_hash_lookup(struct fib_table *tb, const struct rt_key *key, struct fib_result
 #endif
                            ) {
                                if (matched)
-                                       return 1;
+                                       break;
                                continue;
                        }
                        matched = 1;
index 2ec5fcc3de6ef7b20f77b1f3c74e07249eee0cc0..4e947337ad477379f859ba8d855b86eeca6b2ac9 100644 (file)
@@ -3,7 +3,7 @@
  *     
  *             Alan Cox, <alan@cymru.net>
  *
- *     Version: $Id: icmp.c,v 1.43 1998/06/11 03:15:43 davem Exp $
+ *     Version: $Id: icmp.c,v 1.44 1998/06/16 04:38:27 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
index dad449980c3b677027271d48aba6f2bc51f54f5c..838498c21b4d05bc544b47ff1d9f7d6fb7e4699d 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The IP fragmentation functionality.
  *             
- * Version:    $Id: ip_fragment.c,v 1.37 1998/06/10 00:22:00 davem Exp $
+ * Version:    $Id: ip_fragment.c,v 1.38 1998/06/16 04:38:29 davem Exp $
  *
  * Authors:    Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
  *             Alan Cox <Alan.Cox@linux.org>
index 41c66f2c3f6f291a9c2708c5e401a28e71308bcf..0527c1b0bc87bc9a41eed9b6348dd2291eb12881 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The Internet Protocol (IP) output module.
  *
- * Version:    $Id: ip_output.c,v 1.58 1998/05/15 15:21:36 davem Exp $
+ * Version:    $Id: ip_output.c,v 1.59 1998/07/15 05:05:15 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -814,7 +814,7 @@ void ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
                 * will inherit fixed options.
                 */
                if (offset == 0)
-                       ip_options_fragment(skb2);
+                       ip_options_fragment(skb);
 
                /*
                 *      Added AC : If we are fragmenting a fragment that's not the
index 318e3624ff59e308553e6506188dd729674e31ac..8f712c801c7a5dfe2cc430708d86d8f6eb01d4cc 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The IP to API glue.
  *             
- * Version:    $Id: ip_sockglue.c,v 1.35 1998/05/08 21:06:28 davem Exp $
+ * Version:    $Id: ip_sockglue.c,v 1.36 1998/07/15 05:05:06 davem Exp $
  *
  * Authors:    see ip.c
  *
@@ -70,17 +70,11 @@ static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
 
 static void ip_cmsg_recv_ttl(struct msghdr *msg, struct sk_buff *skb)
 {
-       if (IPCB(skb)->opt.optlen == 0)
-               return;
-
        put_cmsg(msg, SOL_IP, IP_TTL, 1, &skb->nh.iph->ttl);
 }
 
 static void ip_cmsg_recv_tos(struct msghdr *msg, struct sk_buff *skb)
 {
-       if (IPCB(skb)->opt.optlen == 0)
-               return;
-
        put_cmsg(msg, SOL_IP, IP_TOS, 1, &skb->nh.iph->tos);
 }
 
index 155b4162d40c443959f606065dd28d4c5fd13b27..76372b4ab4e473be903b0aa964dbe9a1d1c7ca24 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.c,v 1.13 1998/06/09 03:40:47 zaitcev Exp $
+ *  $Id: ipconfig.c,v 1.15 1998/06/19 13:22:33 davem Exp $
  *
  *  Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
  *  information to configure own IP address and routes.
@@ -323,7 +323,7 @@ ic_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt))
        if (rarp->ar_op != htons(ARPOP_RREPLY))
                goto drop;
 
-       /* If it's not ethernet, delete it. */
+       /* If it's not Ethernet, delete it. */
        if (rarp->ar_pro != htons(ETH_P_IP))
                goto drop;
 
index 9fd174b68a298f77e2be5d5d3a8dde5748284741..7f7c7e3f2674523c0ec7da4b083f6e74076f6480 100644 (file)
@@ -3,11 +3,11 @@
  * Copyright (C) 1994 by Ross Martin
  * Based on linux/net/inet/arp.c, Copyright (C) 1994 by Florian La Roche
  *
- * $Id: rarp.c,v 1.24 1998/03/08 05:56:30 davem Exp $
+ * $Id: rarp.c,v 1.25 1998/06/19 13:22:34 davem Exp $
  *
  * This module implements the Reverse Address Resolution Protocol 
  * (RARP, RFC 903), which is used to convert low level addresses such
- * as ethernet addresses into high level addresses such as IP addresses.
+ * as Ethernet addresses into high level addresses such as IP addresses.
  * The most common use of RARP is as a means for a diskless workstation 
  * to discover its IP address during a network boot.
  *
@@ -19,7 +19,7 @@
  ***   unless you have all the rest to boot the box from it. 
  **
  * 
- * Currently, only ethernet address -> IP address is likely to work.
+ * Currently, only Ethernet address -> IP address is likely to work.
  * (Is RARP ever used for anything else?)
  *
  * This code is free software; you can redistribute it and/or
index 902c3983b8f86e66c87b9d9c6fcd5317853056b6..e10f65c68f726f790991ed24728021bbd05ca08a 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             ROUTE - implementation of the IP router.
  *
- * Version:    $Id: route.c,v 1.52 1998/06/11 03:15:47 davem Exp $
+ * Version:    $Id: route.c,v 1.54 1998/07/15 05:05:22 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1166,7 +1166,7 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
        }
 
        /* Multicast recognition logic is moved from route cache to here.
-          The problem was that too many ethernet cards have broken/missing
+          The problem was that too many Ethernet cards have broken/missing
           hardware multicast filters :-( As result the host on multicasting
           network acquires a lot of useless route cache entries, sort of
           SDR messages from all the world. Now we try to get rid of them.
@@ -1496,7 +1496,7 @@ static int rt_fill_info(struct sk_buff *skb, pid_t pid, u32 seq, int event, int
        nlh->nlmsg_flags = nowait ? NLM_F_MULTI : 0;
        r->rtm_family = AF_INET;
        r->rtm_dst_len = 32;
-       r->rtm_src_len = 32;
+       r->rtm_src_len = 0;
        r->rtm_tos = rt->key.tos;
        r->rtm_table = RT_TABLE_MAIN;
        r->rtm_type = rt->rt_type;
@@ -1509,9 +1509,16 @@ static int rt_fill_info(struct sk_buff *skb, pid_t pid, u32 seq, int event, int
        o = skb->tail;
 #endif
        RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst);
-       RTA_PUT(skb, RTA_SRC, 4, &rt->rt_src);
+       if (rt->key.src) {
+               r->rtm_src_len = 32;
+               RTA_PUT(skb, RTA_SRC, 4, &rt->key.src);
+       }
        if (rt->u.dst.dev)
                RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex);
+       if (rt->key.iif)
+               RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst);
+       else if (rt->rt_src != rt->key.src)
+               RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src);
        if (rt->rt_dst != rt->rt_gateway)
                RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway);
 #ifdef CONFIG_RTNL_OLD_IFINFO
@@ -1533,7 +1540,6 @@ static int rt_fill_info(struct sk_buff *skb, pid_t pid, u32 seq, int event, int
        if (mx->rta_len == RTA_LENGTH(0))
                skb_trim(skb, (u8*)mx - skb->data);
 #endif
-       RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst);
        ci.rta_lastuse = jiffies - rt->u.dst.lastuse;
        ci.rta_used = atomic_read(&rt->u.dst.refcnt);
        ci.rta_clntref = atomic_read(&rt->u.dst.use);
index d161344da7a69f0e403be93f079f79c9bfc0a919..3d6f188e7effe29f1ba801603271e7a576c06a47 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp.c,v 1.115 1998/05/13 13:44:13 alan Exp $
+ * Version:    $Id: tcp.c,v 1.116 1998/07/26 03:06:54 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
index 6b62622e6f41cf1a075ee2c88abfe421e9efea57..a4ad2dc3cae6aaed9e970e65c77651c7579989c9 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_input.c,v 1.119 1998/05/23 13:10:24 davem Exp $
+ * Version:    $Id: tcp_input.c,v 1.121 1998/07/15 04:39:12 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -156,8 +156,8 @@ static __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt)
        }
 }
 
-/* Calculate rto without backoff. This is the second half of Van Jacobsons
- * routine refered to above.
+/* Calculate rto without backoff.  This is the second half of Van Jacobson's
+ * routine referred to above.
  */
 
 static __inline__ void tcp_set_rto(struct tcp_opt *tp)
@@ -186,13 +186,21 @@ static __inline__ void tcp_bound_rto(struct tcp_opt *tp)
 }
 
 /* WARNING: this must not be called if tp->saw_timestamp was false. */
-extern __inline__ void tcp_replace_ts_recent(struct tcp_opt *tp, __u32 end_seq)
+extern __inline__ void tcp_replace_ts_recent(struct sock *sk, struct tcp_opt *tp,
+                                            __u32 start_seq, __u32 end_seq)
 {
        /* From draft-ietf-tcplw-high-performance: the correct
         * test is last_ack_sent <= end_seq.
         * (RFC1323 stated last_ack_sent < end_seq.)
+        *
+        * HOWEVER: The current check contradicts the draft statements.
+        * It has been done for good reasons.
+        * The implemented check improves security and eliminates
+        * unnecessary RTT overestimation.
+        *              1998/06/27  Andrey V. Savochkin <saw@msu.ru>
         */
-       if (!before(end_seq, tp->last_ack_sent)) {
+       if (!before(end_seq, tp->last_ack_sent - sk->rcvbuf) &&
+           !after(start_seq, tp->rcv_wup + tp->rcv_wnd)) {
                /* PAWS bug workaround wrt. ACK frames, the PAWS discard
                 * extra check below makes sure this can only happen
                 * for pure ACK frames.  -DaveM
@@ -1657,7 +1665,9 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                                        goto discard;
                                }
                        }
-                       tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->end_seq);
+                       tcp_replace_ts_recent(sk, tp,
+                                             TCP_SKB_CB(skb)->seq,
+                                             TCP_SKB_CB(skb)->end_seq);
                }
        }
 
@@ -2031,7 +2041,9 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                                        goto discard;
                                }
                        }
-                       tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->end_seq);
+                       tcp_replace_ts_recent(sk, tp,
+                                             TCP_SKB_CB(skb)->seq,
+                                             TCP_SKB_CB(skb)->end_seq);
                }
        }
 
index 26a623a1fb21569c4ed7ee0cb621211b728e42f3..ad08655b6c151373775e89ba5feb25aa895a0271 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_ipv4.c,v 1.147 1998/05/06 13:25:00 freitag Exp $
+ * Version:    $Id: tcp_ipv4.c,v 1.148 1998/07/23 12:28:25 freitag Exp $
  *
  *             IPv4 specific functions
  *
@@ -1033,7 +1033,14 @@ tcp_v4_save_options(struct sock *sk, struct sk_buff *skb,
        return dopt;
 }
 
-int sysctl_max_syn_backlog = 1024; 
+/* 
+ * Maximum number of SYN_RECV sockets in queue per LISTEN socket.
+ * One SYN_RECV socket costs about 80bytes on a 32bit machine.
+ * It would be better to replace it with a global counter for all sockets
+ * but then some measure against one socket starving all other sockets
+ * would be needed.
+ */
+int sysctl_max_syn_backlog = 128; 
 
 struct or_calltable or_ipv4 = {
        tcp_v4_send_synack,
index 4a925bd0f8e37f6137841292f1cc3af9aa25ffeb..84535341fb0334d47a3547616eefe49a5351b5f5 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_output.c,v 1.91 1998/05/23 13:10:21 davem Exp $
+ * Version:    $Id: tcp_output.c,v 1.92 1998/06/19 13:22:44 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -166,10 +166,10 @@ void tcp_send_skb(struct sock *sk, struct sk_buff *skb, int force_queue)
        }
 }
 
-/* Function to create two new tcp segments.  Shrinks the given segment
+/* Function to create two new TCP segments.  Shrinks the given segment
  * to the specified size and appends a new segment with the rest of the
- * packet to the list. This won't be called frenquently, I hope..
- * Remember, these are still header-less SKB's at this point.
+ * packet to the list.  This won't be called frequently, I hope
+ * Remember, these are still headerless SKBs at this point.
  */
 static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len)
 {
@@ -256,7 +256,7 @@ void tcp_write_xmit(struct sock *sk)
                 *
                 * a) following SWS avoidance [and Nagle algorithm]
                 * b) not exceeding our congestion window.
-                * c) not retransmiting [Nagle]
+                * c) not retransmitting [Nagle]
                 */
                while((skb = tp->send_head) && tcp_snd_test(sk, skb)) {
                        if (skb->len > mss_now) {
@@ -288,14 +288,14 @@ void tcp_write_xmit(struct sock *sk)
  * 2. We limit memory per socket
  *
  * RFC 1122:
- * "the suggested [SWS] avoidance algoritm for the receiver is to keep
+ * "the suggested [SWS] avoidance algorithm for the receiver is to keep
  *  RECV.NEXT + RCV.WIN fixed until:
  *  RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)"
  *
  * i.e. don't raise the right edge of the window until you can raise
  * it at least MSS bytes.
  *
- * Unfortunately, the recomended algorithm breaks header prediction,
+ * Unfortunately, the recommended algorithm breaks header prediction,
  * since header prediction assumes th->window stays fixed.
  *
  * Strictly speaking, keeping th->window fixed violates the receiver
@@ -474,7 +474,7 @@ static __inline__ void update_retrans_head(struct sock *sk)
 
 /* This retransmits one SKB.  Policy decisions and retransmit queue
  * state updates are done by the caller.  Returns non-zero if an
- * error occured which prevented the send.
+ * error occurred which prevented the send.
  */
 int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
 {
@@ -505,7 +505,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
        tp->retrans_out++;
 
        /* Make a copy, if the first transmission SKB clone we made
-        * is still in somebodies hands, else make a clone.
+        * is still in somebody's hands, else make a clone.
         */
        TCP_SKB_CB(skb)->when = jiffies;
        if(skb_cloned(skb))
@@ -827,7 +827,7 @@ void tcp_connect(struct sock *sk, struct sk_buff *buff, int mss)
                mss = min(mss, sk->user_mss);
 
        if (mss < 1) {
-               printk(KERN_DEBUG "intial sk->mss below 1\n");
+               printk(KERN_DEBUG "initial sk->mss below 1\n");
                mss = 1;        /* Sanity limit */
        }
 
index 4dd0155fb9795590046188780489ad390d7d08e3..329807093335189da231bbd8d74c72981c60ecd3 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: addrconf.c,v 1.41 1998/05/08 21:06:31 davem Exp $
+ *     $Id: addrconf.c,v 1.43 1998/07/15 05:05:32 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -1034,7 +1034,7 @@ static void addrconf_dev_config(struct device *dev)
        struct inet6_dev    * idev;
 
        if (dev->type != ARPHRD_ETHER) {
-               /* Alas, we support only ethernet autoconfiguration. */
+               /* Alas, we support only Ethernet autoconfiguration. */
                return;
        }
 
@@ -1609,7 +1609,7 @@ static struct rtnetlink_link inet6_rtnetlink_table[RTM_MAX-RTM_BASE+1] =
 
        { inet6_rtm_newroute,   NULL,                   },
        { inet6_rtm_delroute,   NULL,                   },
-       { NULL,                 inet6_dump_fib,         },
+       { inet6_rtm_getroute,   inet6_dump_fib,         },
        { NULL,                 NULL,                   },
 };
 #endif
index 5f024dddbd700af723234829eaad253b216d016b..6ab4d2c083952f621c1e129ba7becf6273ff14ec 100644 (file)
@@ -6,7 +6,7 @@
  *     Pedro Roque             <roque@di.fc.ul.pt>
  *     Ian P. Morris           <I.P.Morris@soton.ac.uk>
  *
- *     $Id: ip6_input.c,v 1.9 1998/04/30 16:24:24 freitag Exp $
+ *     $Id: ip6_input.c,v 1.10 1998/07/15 05:05:34 davem Exp $
  *
  *     Based in linux/net/ipv4/ip_input.c
  *
@@ -65,11 +65,6 @@ struct hdrtype_proc {
 /* New header structures */
 
 
-struct ipv6_tlvtype {
-       u8 type;
-       u8 len;
-};
-
 struct tlvtype_proc {
        u8      type;
        int     (*func) (struct sk_buff *, struct device *dev, __u8 *ptr,
@@ -82,7 +77,7 @@ struct tlvtype_proc {
        {255,                   NULL}
 };
 
-static int ip6_dstopt_unknown(struct sk_buff *skb, struct ipv6_tlvtype *hdr)
+int ip6_dstopt_unknown(struct sk_buff *skb, struct ipv6_tlvtype *hdr)
 {
        struct in6_addr *daddr;
        int pos;
@@ -91,7 +86,7 @@ static int ip6_dstopt_unknown(struct sk_buff *skb, struct ipv6_tlvtype *hdr)
         *      unkown destination option type
         */
        
-       pos = (__u8 *) skb->h.raw - (__u8 *) skb->nh.raw;
+       pos = (__u8 *) hdr - (__u8 *) skb->nh.raw;
        
        /* I think this is correct please check - IPM */
 
index eb3984f5574bdc2af123654e147ab796b9b0d4f7..aa13c20747da336a4988fffae4a7bf1f50c0774b 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: ip6_output.c,v 1.12 1998/04/11 22:11:06 davem Exp $
+ *     $Id: ip6_output.c,v 1.13 1998/07/15 05:05:38 davem Exp $
  *
  *     Based on linux/net/ipv4/ip_output.c
  *
@@ -32,6 +32,7 @@
 #include <net/protocol.h>
 #include <net/ip6_route.h>
 #include <net/addrconf.h>
+#include <net/rawv6.h>
 
 static u32     ipv6_fragmentation_id = 1;
 
@@ -519,25 +520,104 @@ int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data,
        return err;
 }
 
+int ip6_call_ra_chain(struct sk_buff *skb, int sel)
+{
+       struct ip6_ra_chain *ra;
+       struct sock *last = NULL;
+
+       for (ra = ip6_ra_chain; ra; ra = ra->next) {
+               struct sock *sk = ra->sk;
+               if (sk && ra->sel == sel) {
+                       if (last) {
+                               struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+                               if (skb2) {
+                                       skb2->sk = last;
+                                       rawv6_rcv(skb2, skb2->dev, &skb2->nh.ipv6h->saddr,
+                                                 &skb2->nh.ipv6h->daddr, NULL, skb2->len);
+                               }
+                       }
+                       last = sk;
+               }
+       }
+
+       if (last) {
+               skb->sk = last;
+               rawv6_rcv(skb, skb->dev, &skb->nh.ipv6h->saddr,
+                         &skb->nh.ipv6h->daddr, NULL, skb->len);
+               return 1;
+       }
+       return 0;
+}
+
 int ip6_forward(struct sk_buff *skb)
 {
        struct dst_entry *dst = skb->dst;
        struct ipv6hdr *hdr = skb->nh.ipv6h;
        int size;
        
-       if (ipv6_devconf.forwarding == 0) {
-               kfree_skb(skb);
-               return -EINVAL;
-       }
+       if (ipv6_devconf.forwarding == 0)
+               goto drop;
 
        /*
         *      check hop-by-hop options present
         */
-#if 0
-       if (hdr->nexthdr == NEXTHDR_HOP)
-       {
+       /*
+        *      Note, that NEXTHDR_HOP header must be checked
+        *      always at the most beginning of ipv6_rcv.
+        *      The result should be saved somewhere, but
+        *      we do not it for now. Alas. Let's do it here. --ANK
+        *
+        *      Second note: we DO NOT make any processing on
+        *      RA packets, pushing them to user level AS IS
+        *      without ane WARRANTY that application will able
+        *      to interpret them. The reson is that we
+        *      cannot make anything clever here.
+        *
+        *      We are not end-node, so that if packet contains
+        *      AH/ESP, we cannot make anything.
+        *      Defragmentation also would be mistake, RA packets
+        *      cannot be fragmented, because there is no warranty
+        *      that different fragments will go along one path. --ANK
+        */
+       if (hdr->nexthdr == NEXTHDR_HOP) {
+               int ra_value = -1;
+               u8 *ptr = (u8*)(skb->nh.ipv6h+1);
+               int len = (ptr[1]+1)<<3;
+
+               if (len + sizeof(struct ipv6hdr) > skb->len)
+                       goto drop;
+
+               ptr += 2;
+               len -= 2;
+               while (len > 0) {
+                       u8 *opt;
+                       int optlen;
+
+                       if (ptr[0] == 0) {
+                               len--;
+                               ptr++;
+                               continue;
+                       }
+                       opt = ptr;
+                       optlen = ptr[1]+1;
+
+                       len -= optlen;
+                       ptr += optlen;
+                       if (len < 0)
+                               goto drop;
+
+                       if (opt[0] == 20) {
+                               /* Router Alert as of draft-ietf-ipngwg-ipv6router-alert-04 */
+                               if (optlen < 4)
+                                       goto drop;
+                               ra_value = opt[2] + (opt[3]<<8);
+                       } else if (!ip6_dstopt_unknown(skb, (struct ipv6_tlvtype*)opt))
+                               goto drop;
+               }
+               if (ra_value>=0 && ip6_call_ra_chain(skb, ra_value))
+                       return 0;
        }
-#endif
+
        /*
         *      check and decrement ttl
         */
@@ -589,4 +669,8 @@ int ip6_forward(struct sk_buff *skb)
        dst->output(skb);
 
        return 0;
+
+drop:
+       kfree_skb(skb);
+       return -EINVAL;
 }
index f409cbb156828511db49ff6aeeac445fe8cdbc85..b31c07c00bceb26f9485096fb8f7cae9a4e29f62 100644 (file)
@@ -7,7 +7,7 @@
  *
  *     Based on linux/net/ipv4/ip_sockglue.c
  *
- *     $Id: ipv6_sockglue.c,v 1.21 1998/05/07 15:43:13 davem Exp $
+ *     $Id: ipv6_sockglue.c,v 1.22 1998/07/15 05:05:39 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -67,6 +67,45 @@ static struct notifier_block ipv6_dev_notf = {
        0
 };
 
+struct ip6_ra_chain *ip6_ra_chain;
+
+int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
+{
+       struct ip6_ra_chain *ra, *new_ra, **rap;
+
+       /* RA packet may be delivered ONLY to IPPROTO_RAW socket */
+       if (sk->type != SOCK_RAW || sk->num != IPPROTO_RAW)
+               return -EINVAL;
+
+       new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
+
+       for (rap = &ip6_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {
+               if (ra->sk == sk) {
+                       if (sel>=0) {
+                               if (new_ra)
+                                       kfree(new_ra);
+                               return -EADDRINUSE;
+                       }
+                       *rap = ra->next;
+                       if (ra->destructor)
+                               ra->destructor(sk);
+                       kfree(ra);
+                       return 0;
+               }
+       }
+       if (new_ra == NULL)
+               return -ENOBUFS;
+       new_ra->sk = sk;
+       new_ra->sel = sel;
+       new_ra->destructor = destructor;
+       start_bh_atomic();
+       new_ra->next = ra;
+       *rap = new_ra;
+       end_bh_atomic();
+       return 0;
+}
+
+
 int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval, 
                    int optlen)
 {
@@ -74,6 +113,9 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
        int val, err;
        int retv = -ENOPROTOOPT;
 
+       if(level==SOL_IP && sk->type != SOCK_RAW)
+               return udp_prot.setsockopt(sk, level, optname, optval, optlen);
+
        if(level!=SOL_IPV6)
                goto out;
 
@@ -197,7 +239,11 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
                        retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
                else
                        retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
+               break;
        }
+       case IPV6_ROUTER_ALERT:
+               retv = ip6_ra_control(sk, val, NULL);
+               break;
        };
 
 out:
@@ -207,7 +253,11 @@ out:
 int ipv6_getsockopt(struct sock *sk, int level, int optname, char *optval, 
                    int *optlen)
 {
-       return 0;
+       if(level==SOL_IP && sk->type != SOCK_RAW)
+               return udp_prot.getsockopt(sk, level, optname, optval, optlen);
+       if(level!=SOL_IPV6)
+               return -ENOPROTOOPT;
+       return -EINVAL;
 }
 
 #if defined(MODULE) && defined(CONFIG_SYSCTL)
index 7429a9210e673f4e0f046d1578a4c698d4f4b6ae..659ec59ccf1b230624c6f4d5e8ccce9ab34e09be 100644 (file)
@@ -7,7 +7,7 @@
  *
  *     Adapted from linux/net/ipv4/raw.c
  *
- *     $Id: raw.c,v 1.19 1998/03/20 09:12:20 davem Exp $
+ *     $Id: raw.c,v 1.20 1998/07/15 05:05:41 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -596,6 +596,8 @@ static void rawv6_close(struct sock *sk, unsigned long timeout)
 {
        sk->state = TCP_CLOSE;
        ipv6_sock_mc_close(sk);
+       if (sk->num == IPPROTO_RAW)
+               ip6_ra_control(sk, -1, NULL);
        sk->dead = 1;
        destroy_sock(sk);
 }
index c3eac939569145894781aee3d3c4f88492f3101d..9d159fe36ece706c1549ca321fa589c006c7bcd9 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: route.c,v 1.30 1998/05/08 21:06:33 davem Exp $
+ *     $Id: route.c,v 1.32 1998/07/25 23:28:52 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -1722,7 +1722,6 @@ int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
        return err;
 }
 
-
 struct rt6_rtnl_dump_arg
 {
        struct sk_buff *skb;
@@ -1733,6 +1732,9 @@ struct rt6_rtnl_dump_arg
 };
 
 static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
+                        struct in6_addr *dst,
+                        struct in6_addr *src,
+                        int iif,
                         int type, pid_t pid, u32 seq)
 {
        struct rtmsg *rtm;
@@ -1777,10 +1779,23 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
 #ifdef CONFIG_RTNL_OLD_IFINFO
        o = skb->tail;
 #endif
-       if (rtm->rtm_dst_len)
+       if (dst) {
+               RTA_PUT(skb, RTA_DST, 16, dst);
+               rtm->rtm_dst_len = 128;
+       } else if (rtm->rtm_dst_len)
                RTA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr);
-       if (rtm->rtm_src_len)
+       if (src) {
+               RTA_PUT(skb, RTA_SRC, 16, src);
+               rtm->rtm_src_len = 128;
+       } else if (rtm->rtm_src_len)
                RTA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr);
+       if (iif)
+               RTA_PUT(skb, RTA_IIF, 4, &iif);
+       else if (dst) {
+               struct inet6_ifaddr *ifp = ipv6_get_saddr(&rt->u.dst, dst);
+               if (ifp)
+                       RTA_PUT(skb, RTA_PREFSRC, 16, &ifp->addr);
+       }
 #ifdef CONFIG_RTNL_OLD_IFINFO
        if (rt->u.dst.pmtu)
                RTA_PUT(skb, RTA_MTU, sizeof(unsigned), &rt->u.dst.pmtu);
@@ -1842,7 +1857,7 @@ static void rt6_dump_node(struct fib6_node *fn, void *p_arg)
                        arg->count++;
                        continue;
                }
-               if (rt6_fill_node(arg->skb, rt, RTM_NEWROUTE,
+               if (rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
                                  NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq) <= 0) {
                        arg->stop = 1;
                        break;
@@ -1870,6 +1885,68 @@ int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
        return skb->len;
 }
 
+int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
+{
+       struct rtattr **rta = arg;
+       int iif = 0;
+       int err;
+       struct sk_buff *skb;
+       struct flowi fl;
+       struct rt6_info *rt;
+
+       skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (skb == NULL)
+               return -ENOBUFS;
+
+       /* Reserve room for dummy headers, this skb can pass
+          through good chunk of routing engine.
+        */
+       skb->mac.raw = skb->data;
+       skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
+
+       fl.proto = 0;
+       fl.nl_u.ip6_u.daddr = NULL;
+       fl.nl_u.ip6_u.saddr = NULL;
+       fl.uli_u.icmpt.type = 0;
+       fl.uli_u.icmpt.code = 0;
+       if (rta[RTA_SRC-1])
+               fl.nl_u.ip6_u.saddr = (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1]);
+       if (rta[RTA_DST-1])
+               fl.nl_u.ip6_u.daddr = (struct in6_addr*)RTA_DATA(rta[RTA_DST-1]);
+
+       if (rta[RTA_IIF-1])
+               memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int));
+
+       if (iif) {
+               struct device *dev;
+               dev = dev_get_by_index(iif);
+               if (!dev)
+                       return -ENODEV;
+       }
+
+       fl.oif = 0;
+       if (rta[RTA_OIF-1])
+               memcpy(&fl.oif, RTA_DATA(rta[RTA_OIF-1]), sizeof(int));
+
+       rt = (struct rt6_info*)ip6_route_output(NULL, &fl);
+
+       skb->dst = &rt->u.dst;
+
+       NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
+       err = rt6_fill_node(skb, rt, 
+                           fl.nl_u.ip6_u.daddr,
+                           fl.nl_u.ip6_u.saddr,
+                           iif,
+                           RTM_NEWROUTE, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq);
+       if (err < 0)
+               return -EMSGSIZE;
+
+       err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
 void inet6_rt_notify(int event, struct rt6_info *rt)
 {
        struct sk_buff *skb;
@@ -1880,7 +1957,7 @@ void inet6_rt_notify(int event, struct rt6_info *rt)
                netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, ENOBUFS);
                return;
        }
-       if (rt6_fill_node(skb, rt, event, 0, 0) < 0) {
+       if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0) < 0) {
                kfree_skb(skb);
                netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL);
                return;
index 90a59266c61d392ce3df83f08292bb06b7c93821..2dac0570f6542137ef88f0451d37d03393506e3b 100644 (file)
@@ -7,7 +7,7 @@
  *
  *     Based on linux/ipv4/udp.c
  *
- *     $Id: udp.c,v 1.29 1998/05/15 15:21:39 davem Exp $
+ *     $Id: udp.c,v 1.31 1998/07/15 05:05:45 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -185,12 +185,18 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport,
 int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
        struct sockaddr_in6     *usin = (struct sockaddr_in6 *) uaddr;
+       struct ipv6_pinfo       *np = &sk->net_pinfo.af_inet6;
        struct in6_addr         *daddr;
        struct dst_entry        *dst;
-       struct ipv6_pinfo       *np;
        struct inet6_ifaddr     *ifa;
        struct flowi            fl;
        int                     addr_type;
+       int                     err;
+
+       if (usin->sin6_family == AF_INET) {
+               err = udp_connect(sk, uaddr, addr_len);
+               goto ipv4_connected;
+       }
 
        if (addr_len < sizeof(*usin)) 
                return(-EINVAL);
@@ -199,7 +205,6 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                return(-EAFNOSUPPORT);
 
        addr_type = ipv6_addr_type(&usin->sin6_addr);
-       np = &sk->net_pinfo.af_inet6;
 
        if (addr_type == IPV6_ADDR_ANY) {
                /*
@@ -212,18 +217,21 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 
        if (addr_type == IPV6_ADDR_MAPPED) {
                struct sockaddr_in sin;
-               int err;
 
                sin.sin_family = AF_INET;
                sin.sin_addr.s_addr = daddr->s6_addr32[3];
+               sin.sin_port = usin->sin6_port;
 
                err = udp_connect(sk, (struct sockaddr*) &sin, sizeof(sin));
-               
+
+ipv4_connected:
                if (err < 0)
                        return err;
                
-               ipv6_addr_copy(&np->daddr, daddr);
-               
+               ipv6_addr_set(&np->daddr, 0, 0, 
+                             __constant_htonl(0x0000ffff),
+                             sk->daddr);
+
                if(ipv6_addr_any(&np->saddr)) {
                        ipv6_addr_set(&np->saddr, 0, 0, 
                                      __constant_htonl(0x0000ffff),
@@ -236,7 +244,7 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                                      __constant_htonl(0x0000ffff),
                                      sk->rcv_saddr);
                }
-
+               return 0;
        }
 
        ipv6_addr_copy(&np->daddr, daddr);
@@ -347,6 +355,8 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
                if (skb->protocol == __constant_htons(ETH_P_IP)) {
                        ipv6_addr_set(&sin6->sin6_addr, 0, 0,
                                      __constant_htonl(0xffff), skb->nh.iph->saddr);
+                       if (sk->ip_cmsg_flags)
+                               ip_cmsg_recv(msg, skb);
                } else {
                        memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr,
                               sizeof(struct in6_addr));
@@ -668,6 +678,9 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
                return(-EINVAL);
 
        if (sin6) {
+               if (sin6->sin6_family == AF_INET)
+                       return udp_sendmsg(sk, msg, ulen);
+
                if (addr_len < sizeof(*sin6))
                        return(-EINVAL);
                
@@ -702,8 +715,10 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
                
                sin.sin_family = AF_INET;
                sin.sin_addr.s_addr = daddr->s6_addr32[3];
+               sin.sin_port = udh.uh.dest;
+               msg->msg_name = (struct sockaddr *)(&sin);
 
-               return udp_sendmsg(sk, msg, len);
+               return udp_sendmsg(sk, msg, ulen);
        }
 
        udh.daddr = NULL;
index 407e5eaa125aa7e729be4a7ffcf727dd314e8e20..c57d793c07cd474d5167d6d02d6d10423b724165 100644 (file)
@@ -986,15 +986,15 @@ struct proto_ops netlink_ops = {
        netlink_release,
        netlink_bind,
        netlink_connect,
-       NULL,
-       NULL,
+       sock_no_socketpair,
+       sock_no_accept,
        netlink_getname,
        datagram_poll,
        sock_no_ioctl,
        sock_no_listen,
        sock_no_shutdown,
-       NULL,
-       NULL,
+       sock_no_setsockopt,
+       sock_no_getsockopt,
        sock_no_fcntl,
        netlink_sendmsg,
        netlink_recvmsg
index 7cd274478e2992585148029d986bbd8acfe7efee..d9767a09ec9308013390e1ed2e21d88d1c1f75ea 100644 (file)
@@ -60,8 +60,7 @@ extern int tcp_tw_death_row_slot;
        defined(CONFIG_EL2)     ||      defined(CONFIG_NE2000)          || \
        defined(CONFIG_E2100)   ||      defined(CONFIG_HPLAN_PLUS)      || \
        defined(CONFIG_HPLAN)   ||      defined(CONFIG_AC3200)          || \
-       defined(CONFIG_ES3210)  ||      defined(CONFIG_ULTRA32)         || \
-       defined(CONFIG_LNE390)
+       defined(CONFIG_ES3210)
 #include "../drivers/net/8390.h"
 #endif
 
@@ -85,8 +84,8 @@ extern int sysctl_max_syn_backlog;
 EXPORT_SYMBOL(dev_lockct);
 
 /* Skbuff symbols. */
-EXPORT_SYMBOL(skb_push_errstr);
-EXPORT_SYMBOL(skb_put_errstr);
+EXPORT_SYMBOL(skb_over_panic);
+EXPORT_SYMBOL(skb_under_panic);
 
 /* Socket layer registration */
 EXPORT_SYMBOL(sock_register);
@@ -222,6 +221,7 @@ EXPORT_SYMBOL(ip_mc_inc_group);
 EXPORT_SYMBOL(ip_mc_dec_group);
 EXPORT_SYMBOL(__ip_finish_output);
 EXPORT_SYMBOL(inet_dgram_ops);
+EXPORT_SYMBOL(ip_cmsg_recv);
 EXPORT_SYMBOL(__release_sock);
 
 /* needed for ip_gre -cw */
@@ -358,8 +358,7 @@ EXPORT_SYMBOL(sock_rmalloc);
        defined(CONFIG_EL2)     ||      defined(CONFIG_NE2000)          || \
        defined(CONFIG_E2100)   ||      defined(CONFIG_HPLAN_PLUS)      || \
        defined(CONFIG_HPLAN)   ||      defined(CONFIG_AC3200)          || \
-       defined(CONFIG_ES3210)  ||      defined(CONFIG_ULTRA32)         || \
-       defined(CONFIG_LNE390)
+       defined(CONFIG_ES3210)
 /* If 8390 NIC support is built in, we will need these. */
 EXPORT_SYMBOL(ei_open);
 EXPORT_SYMBOL(ei_close);
index e8ebbcb7a0847bc48de0d74b2cbde41452f6d0be..5f760d394fb620fab9d172d7eeb9e20ed2eeeda8 100644 (file)
@@ -1182,8 +1182,8 @@ struct proto_ops packet_ops_spkt = {
        packet_release,
        packet_bind_spkt,
        sock_no_connect,
-       NULL,
-       NULL,
+       sock_no_socketpair,
+       sock_no_accept,
        packet_getname_spkt,
        datagram_poll,
        packet_ioctl,
index 514f64e1b52f4f4a65383800e6760f561fb85f02..60a3581e59428a40990eb4abdbffee3d43f1d49d 100644 (file)
@@ -174,7 +174,8 @@ static void x25_kill_by_device(struct device *dev)
        struct sock *s;
 
        for (s = x25_list; s != NULL; s = s->next)
-               if (s->protinfo.x25->neighbour->dev == dev)
+               if (s->protinfo.x25->neighbour &&
+                   s->protinfo.x25->neighbour->dev == dev)
                        x25_disconnect(s, ENETUNREACH, 0, 0);
 }
 
@@ -621,6 +622,9 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
        if ((sk->protinfo.x25->neighbour = x25_get_neigh(dev)) == NULL)
                return -ENETUNREACH;
 
+       x25_limit_facilities(&sk->protinfo.x25->facilities,
+                            sk->protinfo.x25->neighbour);
+
        if ((sk->protinfo.x25->lci = x25_new_lci(sk->protinfo.x25->neighbour)) == 0)
                return -ENETUNREACH;
 
@@ -786,6 +790,13 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
                return 0;
        }
 
+       /*
+        * current neighbour/link might impose additional limits
+        * on certain facilties
+        */
+
+       x25_limit_facilities(&facilities,neigh);
+
        /*
         *      Try to create a new socket.
         */
@@ -1124,18 +1135,8 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                                return -EINVAL;
                        if (facilities.pacsize_out < X25_PS16 || facilities.pacsize_out > X25_PS4096)
                                return -EINVAL;
-                       if (sk->state == TCP_CLOSE || sk->protinfo.x25->neighbour->extended) 
-                       {
-                               if (facilities.winsize_in < 1 || facilities.winsize_in > 127)
-                                       return -EINVAL;
-                               if (facilities.winsize_out < 1 || facilities.winsize_out > 127)
-                                       return -EINVAL;
-                       } else {
-                               if (facilities.winsize_in < 1 || facilities.winsize_in > 7)
-                                       return -EINVAL;
-                               if (facilities.winsize_out < 1 || facilities.winsize_out > 7)
-                                       return -EINVAL;
-                       }
+                       if (facilities.winsize_in < 1 || facilities.winsize_in > 127)
+                               return -EINVAL;
                        if (facilities.throughput < 0x03 || facilities.throughput > 0x2C)
                                return -EINVAL;
                        if (facilities.reverse != 0 && facilities.reverse != 1)
@@ -1276,6 +1277,16 @@ struct notifier_block x25_dev_notifier = {
        0
 };
 
+void x25_kill_by_neigh(struct x25_neigh *neigh)
+{
+       struct sock *s;
+
+       for( s=x25_list; s != NULL; s=s->next){
+               if( s->protinfo.x25->neighbour == neigh )
+                       x25_disconnect(s, ENETUNREACH, 0, 0);
+       } 
+}
+
 #ifdef CONFIG_PROC_FS
 static struct proc_dir_entry proc_net_x25 = {
        PROC_NET_X25, 3, "x25",
index 16fc3677d3cc7605abc232baa6d2a191f245ea27..bcbf31b0dfca2cb26b538b02dccc16b939c0b00e 100644 (file)
@@ -98,6 +98,7 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh)
 int x25_lapb_receive_frame(struct sk_buff *skb, struct device *dev, struct packet_type *ptype)
 {
        struct x25_neigh *neigh;
+       int queued;
 
        skb->sk = NULL;
 
@@ -113,7 +114,13 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct device *dev, struct packe
        switch (skb->data[0]) {
                case 0x00:
                        skb_pull(skb, 1);
-                       return x25_receive_data(skb, neigh);
+                       queued = x25_receive_data(skb, neigh);
+                       if( ! queued )
+                               /* We need to free the skb ourselves because
+                                * net_bh() won't care about our return code.
+                                */
+                               kfree_skb(skb);
+                       return 0;
 
                case 0x01:
                        x25_link_established(neigh);
@@ -215,6 +222,8 @@ void x25_send_frame(struct sk_buff *skb, struct x25_neigh *neigh)
 {
        unsigned char *dptr;
 
+       skb->nh.raw = skb->data;
+
        switch (neigh->dev->type) {
                case ARPHRD_X25:
                        dptr  = skb_push(skb, 1);
@@ -238,3 +247,6 @@ void x25_send_frame(struct sk_buff *skb, struct x25_neigh *neigh)
 }
 
 #endif
+
+
+
index af072ce22dbe2b59d08d963937c2d9602f83a2c1..18de2da1a9c0ee3846b614e85271de08ed2b847e 100644 (file)
@@ -200,4 +200,26 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, struct x25_fa
        return len;
 }
 
+/*
+ *     Limit values of certain facilities according to the capability of the 
+ *      currently attached x25 link.
+ */
+void x25_limit_facilities(struct x25_facilities *facilities,
+                         struct x25_neigh *neighbour)
+{
+
+       if( ! neighbour->extended ){
+               if( facilities->winsize_in  > 7 ){
+                       printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n");
+                       facilities->winsize_in = 7;
+               }
+               if( facilities->winsize_out > 7 ){
+                       facilities->winsize_out = 7;
+                       printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n");
+               }
+       }
+}
+
 #endif
+
+
index ae98e95ec34e90828c60dab8b0616c1ce51f8613..ad7adb7ea558d1a8f8783a022661b0803bd06f90 100644 (file)
@@ -49,17 +49,20 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
        if (more) {
                sk->protinfo.x25->fraglen += skb->len;
                skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb);
+               skb_set_owner_r(skb, sk);
                return 0;
        }
 
        if (!more && sk->protinfo.x25->fraglen > 0) {   /* End of fragment */
-               sk->protinfo.x25->fraglen += skb->len;
-               skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb);
+               int len = sk->protinfo.x25->fraglen + skb->len;
 
-               if ((skbn = alloc_skb(sk->protinfo.x25->fraglen, GFP_ATOMIC)) == NULL)
+               if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){
+                       kfree_skb(skb);
                        return 1;
+               }
+
+               skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb);
 
-               skb_set_owner_r(skbn, sk);
                skbn->h.raw = skbn->data;
 
                skbo = skb_dequeue(&sk->protinfo.x25->fragment_queue);
@@ -75,7 +78,12 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
                sk->protinfo.x25->fraglen = 0;          
        }
 
-       return sock_queue_rcv_skb(sk, skbn);
+       skb_set_owner_r(skbn, sk);
+       skb_queue_tail(&sk->receive_queue, skbn);
+       if (!sk->dead)
+               sk->data_ready(sk,skbn->len);
+
+       return 0;
 }
 
 /*
index f27fa4f4aeaa0152c03216cb91272d6869055297..96168270244867223303c544e0412fd74550b68b 100644 (file)
@@ -264,11 +264,14 @@ void x25_link_established(struct x25_neigh *neigh)
 
 /*
  *     Called when the link layer has terminated, or an establishment
- *     request has failed. XXX should tell sockets.
+ *     request has failed.
  */
+
 void x25_link_terminated(struct x25_neigh *neigh)
 {
        neigh->state = X25_LINK_STATE_0;
+       /* Out of order: clear existing virtual calls (X.25 03/93 4.6.3) */
+       x25_kill_by_neigh(neigh);
 }
 
 /*