]> git.neil.brown.name Git - history.git/commitdiff
Import 1.3.96 1.3.96
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:54 +0000 (15:10 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:54 +0000 (15:10 -0500)
246 files changed:
CREDITS
Documentation/Changes
Documentation/Configure.help
Documentation/filesystems/affs.txt [new file with mode: 0644]
Documentation/ramdisk.txt
Documentation/riscom8.txt
Makefile
arch/alpha/kernel/entry.S
arch/alpha/kernel/traps.c
arch/alpha/mm/fault.c
arch/i386/kernel/traps.c
arch/i386/mm/fault.c
arch/m68k/amiga/amifb.c
arch/m68k/amiga/config.c
arch/m68k/amiga/ksyms.c
arch/m68k/atari/atafb.c
arch/m68k/atari/ataints.c
arch/m68k/atari/atakeyb.c
arch/m68k/atari/atapart.c
arch/m68k/atari/atasound.c
arch/m68k/atari/config.c
arch/m68k/atari/stdma.c
arch/m68k/boot/amiga/bootstrap.c
arch/m68k/boot/atari/bootstrap.c
arch/m68k/console/fbcon.c
arch/m68k/defconfig
arch/m68k/fpsp040/bindec.S
arch/m68k/fpsp040/decbin.S
arch/m68k/fpsp040/fpsp.h
arch/m68k/fpsp040/gen_except.S
arch/m68k/fpsp040/get_op.S
arch/m68k/fpsp040/res_func.S
arch/m68k/fpsp040/round.S
arch/m68k/fpsp040/satan.S
arch/m68k/fpsp040/scale.S
arch/m68k/fpsp040/sint.S
arch/m68k/fpsp040/skeleton.S
arch/m68k/fpsp040/slogn.S
arch/m68k/fpsp040/ssin.S
arch/m68k/fpsp040/stan.S
arch/m68k/fpsp040/tbldo.S
arch/m68k/fpsp040/util.S
arch/m68k/fpsp040/x_bsun.S
arch/m68k/fpsp040/x_operr.S
arch/m68k/fpsp040/x_ovfl.S
arch/m68k/fpsp040/x_snan.S
arch/m68k/fpsp040/x_store.S
arch/m68k/fpsp040/x_unfl.S
arch/m68k/ifpsp060/TEST.DOC
arch/m68k/ifpsp060/fpsp.doc
arch/m68k/ifpsp060/iskeleton.S
arch/m68k/kernel/console.c
arch/m68k/kernel/entry.S
arch/m68k/kernel/head.S
arch/m68k/kernel/sys_m68k.c
arch/m68k/kernel/traps.c
arch/m68k/mm/init.c
arch/m68k/mm/memory.c
arch/sparc/boot/bare.S
arch/sparc/boot/empirical.h
arch/sparc/config.in
arch/sparc/defconfig
arch/sparc/kernel/Makefile
arch/sparc/kernel/entry.S
arch/sparc/kernel/etrap.S
arch/sparc/kernel/head.S
arch/sparc/kernel/idprom.c
arch/sparc/kernel/ioport.c
arch/sparc/kernel/irq.c
arch/sparc/kernel/process.c
arch/sparc/kernel/ptrace.c [new file with mode: 0644]
arch/sparc/kernel/setup.c
arch/sparc/kernel/signal.c
arch/sparc/kernel/smp.c
arch/sparc/kernel/sparc-stub.c
arch/sparc/kernel/sunos_ioctl.c
arch/sparc/kernel/sys_sparc.c
arch/sparc/kernel/sys_sunos.c
arch/sparc/kernel/systbls.S
arch/sparc/kernel/traps.c
arch/sparc/kernel/wuf.S
arch/sparc/mm/fault.c
arch/sparc/mm/generic.c
arch/sparc/mm/init.c
arch/sparc/mm/srmmu.c
arch/sparc/prom/memory.c
arch/sparc/prom/palloc.c
drivers/block/amiflop.c
drivers/block/ataflop.c
drivers/block/floppy.c
drivers/block/genhd.c
drivers/block/rd.c
drivers/char/Makefile
drivers/char/amigamouse.c
drivers/char/lp_intern.c
drivers/char/lp_m68k.c
drivers/char/mem.c
drivers/char/misc.c
drivers/char/pty.c
drivers/char/riscom8.c
drivers/char/riscom8.h
drivers/char/riscom8_reg.h
drivers/char/suncons.c [deleted file]
drivers/char/sunmouse.c [deleted file]
drivers/net/3c509.c
drivers/net/Config.in
drivers/net/Makefile
drivers/net/Space.c
drivers/net/a2065.c
drivers/net/ariadne.c
drivers/net/ariadne.h
drivers/net/atarilance.c
drivers/net/de4x5.c
drivers/net/de4x5.h
drivers/sbus/Makefile
drivers/sbus/char/Makefile [new file with mode: 0644]
drivers/sbus/char/suncons.c [new file with mode: 0644]
drivers/sbus/char/sunkbd.c [new file with mode: 0644]
drivers/sbus/char/sunkeymap.c [new file with mode: 0644]
drivers/sbus/char/sunkeymap.map [new file with mode: 0644]
drivers/sbus/char/sunmouse.c [new file with mode: 0644]
drivers/sbus/char/sunserial.c [new file with mode: 0644]
drivers/sbus/char/sunserial.h [new file with mode: 0644]
drivers/scsi/Makefile
drivers/scsi/NCR5380.h
drivers/scsi/a2091.c
drivers/scsi/a2091.h
drivers/scsi/a3000.c
drivers/scsi/a3000.h
drivers/scsi/atari_NCR5380.c
drivers/scsi/atari_scsi.c
drivers/scsi/atari_scsi.h
drivers/scsi/gvp11.c
drivers/scsi/gvp11.h
drivers/scsi/hosts.c
drivers/scsi/scsi.c
drivers/scsi/wd33c93.c
drivers/scsi/wd33c93.h
drivers/sound/dmasound.c
fs/Config.in
fs/Makefile
fs/affs/amigaffs.c
fs/affs/amigaffs.h
fs/affs/file.c
fs/affs/inode.c
fs/binfmt_aout.c
fs/buffer.c
fs/fat/buffer.c
fs/fat/cache.c
fs/fat/misc.c
fs/fat/msbuffer.h
fs/fcntl.c
fs/filesystems.c
fs/isofs/inode.c
fs/locks.c
fs/nfs/README
fs/nfs/dir.c
fs/nfs/inode.c
fs/proc/array.c
fs/proc/inode.c
fs/proc/mem.c
fs/ufs/ufs_dir.c
fs/ufs/ufs_file.c
fs/ufs/ufs_inode.c
fs/ufs/ufs_namei.c
fs/ufs/ufs_super.c
fs/ufs/ufs_symlink.c
include/asm-i386/smp.h
include/asm-m68k/atarihw.h
include/asm-m68k/atariints.h
include/asm-m68k/atomic.h
include/asm-m68k/bitops.h
include/asm-m68k/bootinfo.h
include/asm-m68k/dma.h
include/asm-m68k/font.h
include/asm-m68k/pgtable.h
include/asm-m68k/system.h
include/asm-m68k/traps.h
include/asm-sparc/asi.h
include/asm-sparc/auxio.h
include/asm-sparc/bsderrno.h
include/asm-sparc/cache.h
include/asm-sparc/cypress.h
include/asm-sparc/dma.h
include/asm-sparc/ecc.h
include/asm-sparc/elf.h
include/asm-sparc/head.h
include/asm-sparc/irq.h
include/asm-sparc/mbus.h
include/asm-sparc/memreg.h
include/asm-sparc/mman.h
include/asm-sparc/mostek.h
include/asm-sparc/mp.h [deleted file]
include/asm-sparc/mpmbox.h
include/asm-sparc/mxcc.h
include/asm-sparc/openprom.h
include/asm-sparc/oplib.h
include/asm-sparc/pconf.h
include/asm-sparc/pgtsrmmu.h
include/asm-sparc/ptrace.h
include/asm-sparc/signal.h
include/asm-sparc/solerrno.h
include/asm-sparc/traps.h
include/asm-sparc/unistd.h
include/asm-sparc/vac-ops.h
include/asm-sparc/vaddrs.h
include/asm-sparc/viking.h
include/linux/blk.h
include/linux/config.h
include/linux/console.h
include/linux/fb.h
include/linux/genhd.h
include/linux/if_arp.h
include/linux/major.h
include/linux/miscdevice.h
include/linux/mm.h
include/linux/proc_fs.h
include/linux/sched.h
include/linux/skbuff.h
include/linux/timex.h
include/linux/ufs_fs.h
include/net/tcp.h
init/main.c
ipc/shm.c
kernel/exit.c
kernel/sched.c
kernel/time.c
mm/filemap.c
mm/memory.c
net/README
net/ax25/af_ax25.c
net/ax25/ax25_in.c
net/ax25/ax25_out.c
net/ax25/ax25_timer.c
net/bridge/br.c
net/core/dev.c
net/core/iovec.c
net/core/skbuff.c
net/ipv4/Config.in
net/ipv4/icmp.c
net/ipv4/ip_fragment.c
net/ipv4/ip_sockglue.c
net/ipv4/tcp.c
net/socket.c
scripts/lxdialog/menubox.c
scripts/lxdialog/util.c

diff --git a/CREDITS b/CREDITS
index 918ed487717972d6790eacae4b4ea8d114c305d5..aee049e9f0ec7920b7c15f16fbf0190f6574615c 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1372,3 +1372,7 @@ D: Miscellaneous kernel fixes
 S: 3078 Sulphur Spring Court
 S: San Jose, California 95148
 S: USA
+
+# Don't add your name here, unless you really _are_ after Leonard
+# alphabetically.  Leonard is very proud of being the last entry,
+# and this file really _is_ supposed to be in alphabetic order.
index 667dd82b52021c87f8cf69bccfa67ae930013c02..d8c525eb1aecd5529ff2f0e8003ef4a541f37a8f 100644 (file)
@@ -2,9 +2,9 @@ This document contains a list of the latest releases of the most
 important packages for Linux as well as instructions for newcomers to
 the 1.3.x series of kernels.
 
-Last updated: Apr 17, 1996.
-Authors: Alessandro Sigala (ssigala@globalnet.it) and Chris Ricker
-(gt1355b@prism.gatech.edu).
+Last updated: Apr 27, 1996.
+Author: Chris Ricker (gt1355b@prism.gatech.edu), based on the original by
+Alessandro Sigala (ssigala@globalnet.it.
 
 Note:  Due to time constraints, Alessandro is getting out of the Changes
 business and I'll be picking up the job.  Be gentle while I get my feet
@@ -14,11 +14,11 @@ Current Releases
 ****************
 
 - Kernel modules        Stable: 1.3.57, Exp: 1.3.69f
-- PPP daemon            Stable: 2.2.0e, Exp: 2.2.0f-BETA6
+- PPP daemon            Stable: 2.2.0f
 - Dynamic linker (ld.so) 1.7.14
 - GNU CC                2.7.2
 - Binutils              2.6.0.12
-- Linux C Library       Stable:  5.2.18, Exp:  5.3.9, Alpha:  5.3.11
+- Linux C Library       Stable:  5.2.18, Exp:  5.3.9, Alpha:  5.3.12
 - Linux C++ Library     2.7.1.4
 - Termcap               2.0.8
 - Procps                0.99a
@@ -45,13 +45,17 @@ PPP daemon and utilities
 ========================
 
    To use the PPP protocol with the 1.3.x linux kernel, you need to
-upgrade the PPP package to version 2.2.0e or the experimental 2.2.0f.
+upgrade the PPP package to version 2.2.0f.
 
 Procps utilities
 ================
 
    In the latest 1.3.x kernel releases the /proc filesystem structure
-was changed, so you need to upgrade the Procps package to version 0.99a.
+was changed, so you need to upgrade the Procps package to version
+0.99a.  In the very latest kernels, /proc has changed again.  There's
+not yet an officially updated version of procps, so make due with
+0.99a; you might want to look for one of the patches floating around to
+update 0.99a for use with 1.3.94 and later kernels.
 
 Installation notes
 ******************
@@ -83,6 +87,27 @@ and recompile those programs (a patch for make is included in the file
 `release.libc-.5.3.9', and the address to obtain a precompiled binary
 is at the end of this file).
 
+   Also, the libc-5.3.x line has a known security hole relating to
+rlogin.  Unless you really need to upgrade for some reason, just stick
+with 5.2.18 for now.
+
+   If you're getting an error message that is something to the effect of
+
+   `fcntl_setlk() called by process 123 with broken flock() emulation'
+
+   then you need to upgrade to libc-5.2.18 as well.  A proper (in other
+words, BSD-style ;-) flock system call was added in 1.3.x, and older
+libc's will now give this error.  It doesn't *really* matter, so you
+can just ignore it.  If it really annoys you, upgrade libc (and
+recompile any static binaries you might have that are linked against
+the old libc).  If you're feeling lazy, just comment out
+
+   `                printk(KERN_WARNING
+"fcntl_setlk() called by process %d with broken flock()
+  emulation\n",                        current->pid);'
+
+   in linux/fs/locks.c and recompile.
+
 The Termcap Library
 ===================
 
@@ -152,9 +177,8 @@ PPP driver
 ==========
 
    You need to be running a pppd from ppp-2.2.0.tar.gz or greater.  The
-latest stable release is 2.2.0e and is available at
-ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp-2.2.0e.tar.gz,
-along with a patch necessary to make it compile.
+latest stable release is 2.2.0f and is available at
+ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp/ppp-2.2.0f.tar.gz.
 
 Named pipes
 ===========
@@ -168,6 +192,16 @@ words to that effect scroll across your screen hundreds of times.  To
 fix, upgrade to
 ftp://ftp.cistron.nl/pub/people/miquels/debian/sysvinit-2.60.tar.gz.
 
+   If you're trying to run NCSA httpd, you have to set pre-spawning of
+daemons to zero, as it incorrectly assumes SunOS behavior.  Some people
+have said that the Apache httpd has problems with the new named pipes,
+but I've never noticed any.
+
+   The new named pipe behavior also causes problems with Hylafax.  If
+you're running the hylafax daemon, it will just keep eating up CPU time
+until you have no idle time free.  I'm not currently aware of any
+patches that eliminate this behavior.
+
 Uugetty
 =======
 
@@ -283,6 +317,25 @@ ftp://ftp.funet.fi/pub/Linux/PEOPLE/Linus/subsystems/quota/all.tar.gz.
 This will compile just fine after you copy its mntent.h over to
 /usr/include/mntent.h.
 
+APM support
+===========
+
+   Advanced Power Management (APM) support has been added to the kernel
+as well.  APM, which is primarily of use in laptops, provides access to
+battery status information and may help to conserve battery power.  The
+support files can be found in
+ftp://tsx-11.mit.edu/pub/linux/packages/laptops/apm/apmd-2.2.tar.gz
+
+iBCS and Dosemu
+===============
+
+   For a version of iBCS that works with 1.3.x kernels, grab
+ftp://tsx-11.mit.edu/pub/linux/BETA/ibcs2/ibcs-1.3-960404-ALPHA.tar.gz
+
+   For a version of Dosemu that works (well, at least as well as DOS
+ever works ;-), get
+ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.63.1.8.tgz.
+
 Please send info about any other packages that 1.3.x "broke" or about
 any new features of 1.3.x that require extra packages for use to Chris
 Ricker (gt1355b@prism.gatech.edu).
@@ -333,7 +386,7 @@ ftp://sunsite.unc.edu/pub/Linux/devel/make/make-3.74.patched.tar.gz
 Patched make binary:
 ftp://sunsite.unc.edu/pub/Linux/devel/make/make-3.74-direntfix-elf.tgz
 
-The 5.2.18 release:
+The stable 5.2.18 release:
 ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.2.18.bin.tar.gz
 Installation notes:
 ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.2.18
@@ -367,9 +420,7 @@ PPP Daemon and utilities
 ========================
 
 The latest public release:
-ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp-2.2.0e.tar.gz
-The latest experimental release:
-ftp://ftp.sii.com/pub/linux/ppp-2.2/ppp-2.2.0f.BETA6.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp/ppp-2.2.0f.tar.gz
 
 Procps utilities
 ================
@@ -386,8 +437,6 @@ SysVinit utilities
 ==================
 
 At the time of writing:
-ftp://sunsite.unc.edu/pub/Linux/Incoming/sysvinit-2.60.tar.gz
-Next location:
 ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.60.tar.gz
 
 Util-linux
index 9cdc643e1d0e36040c4b643f0c684e9dc5a50864..8e5850e69251fb636ce2483010f60fe1f035db66 100644 (file)
@@ -1155,7 +1155,8 @@ CONFIG_SCSI_MULTI_LUN
   Unit Number), e.g. a CD jukebox, you should say Y here so that all
   will be found by the SCSI driver. An SCSI device with multiple LUNs
   acts logically like multiple SCSI devices. The vast majority of SCSI
-  devices have only one LUN, and so most people can say N here.
+  devices have only one LUN, and so most people can say N here and
+  should in fact do so, because it is safer.
 
 Verbose SCSI error reporting (kernel size +=12K)
 CONFIG_SCSI_CONSTANTS
@@ -1163,16 +1164,6 @@ CONFIG_SCSI_CONSTANTS
   understand if you enable this; it will enlarge your kernel by about
   12KB. If in doubt, say Y.
 
-Automatic Disk Geometry Translation 
-CONFIG_SCSI_AUTO_BIOSP
-  When this is set to Y, Linux will examine the partition table to
-  determine the mapping used under the other operating systems (e.g.
-  DOS), and set these parameters to the determined values, or if the
-  disk has no valid partition table, to an optimal value.
-###
-### What are the advantages/disadvantages? What is a safe value?
-###
-
 AdvanSys SCSI support
 CONFIG_SCSI_ADVANSYS
   This is a driver for all SCSI host adaptors manufactured by
@@ -1607,18 +1598,19 @@ CONFIG_PPP_LOTS
 
 STRIP (Starmode Radio IP) support
 CONFIG_STRIP
-  Say Y if you have a Metricom radio and intend to use Starmode Radio IP.
-  STRIP is a radio protocol developed for the MosquitoNet project
-  (http://mosquitonet.stanford.edu/) to send Internet traffic using Metricom
-  radios.  Metricom radios are small, battery powered, 100kbit/sec packet
-  radio transceivers, about the size and weight of a cellular telephone.
-  (You may also have heard them called "Metricom modems" but we avoid the
-  term "modem" because it misleads many people into thinking that you can
-  plug a Metricom modem into a phone line and use it as a modem.)
-  You can use STRIP on any Linux machine with a serial port, although
-  it is obviously most useful for people with laptop computers. If you
-  think you might get a Metricom radio in the future, there is no harm in
-  saying yes to STRIP now, except that it makes the kernel a bit bigger.
+  Say Y if you have a Metricom radio and intend to use Starmode Radio
+  IP.  STRIP is a radio protocol developed for the MosquitoNet project
+  (http://mosquitonet.stanford.edu/) to send Internet traffic using
+  Metricom radios.  Metricom radios are small, battery powered,
+  100kbit/sec packet radio transceivers, about the size and weight of
+  a cellular telephone.  (You may also have heard them called
+  "Metricom modems" but we avoid the term "modem" because it misleads
+  many people into thinking that you can plug a Metricom modem into a
+  phone line and use it as a modem.)  You can use STRIP on any Linux
+  machine with a serial port, although it is obviously most useful for
+  people with laptop computers. If you think you might get a Metricom
+  radio in the future, there is no harm in saying yes to STRIP now,
+  except that it makes the kernel a bit bigger.
 
 WIC (Radio IP bridge)
 CONFIG_WIC
@@ -1632,37 +1624,51 @@ Z8530 SCC kiss emulation driver for AX.2
 CONFIG_SCC
   These cards are used to connect your Linux box to an amateur radio
   and communicate with other computers.  If you want to use this, read
-  Documentation/networking/z8530drv.txt and the HAM-HOWTO, available via
-  ftp (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.
+  Documentation/networking/z8530drv.txt and the HAM-HOWTO, available
+  via ftp (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt.
 
 PLIP (parallel port) support
 CONFIG_PLIP
-  PLIP (Parallel Line Internet Protocol) is mainly used to create a
-  mini network consisting of two local machines. The parallel ports
-  are connected using a "null printer" or "Turbo Laplink" cable (you
-  can find the wiring in drivers/net/README?.plip).  This works also
-  if one of the two machines runs DOS and has some PLIP software
-  installed, e.g. NCSA telnet.  If you want to use this, say Y and
-  read the NET-2-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  You need to say N or M to
-  "parallel printer support" below if you say Y here. Also, you might
-  have to edit the file drivers/net/Space.c and adjust the parallel
-  port's IRQ (there is a small number of Interrupt ReQuest lines in
-  your computer that are used by the periphery to gain the CPU's
-  attention - often a source of trouble if two different devices are
-  mistakenly configured to use the same IRQ. If you have the /proc
-  filesystem installed (see below), you can say "cat /proc/interrupts"
-  to see what the different IRQs are currently used for.)  This option
-  enlarges your kernel by about 8kB. If unsure, say N.  If you want to
-  compile this as a module ( = code which can be inserted in and
-  removed from the running kernel whenever you want), say M here and
-  read Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt. If you want to use both a
-  parallel printer and PLIP, it is best to compile both drivers as
-  modules.
+  PLIP (Parallel Line Internet Protocol) is used to create a mini
+  network consisting of two (or, rarely, more) local machines. The
+  parallel ports (the connectors at the computers with 25 holes) are
+  connected using "null printer" or "Turbo Laplink" cables which can
+  transmit 4 bits at a time or using special PLIP cables, to be used
+  on bidirectional parallel ports only, which can transmit 8 bits at a
+  time (you can find the wiring of these cables in
+  drivers/net/README?.plip). The cables can be up to 15m long. This
+  works also if one of the machines runs DOS and has some PLIP
+  software installed, e.g. NCSA telnet.  If you want to use this, say
+  Y and read the PLIP mini-HOWTO, available via ftp (user: anonymous)
+  in sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini as well as the
+  NET-2-HOWTO in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the
+  PLIP protocol was changed and this PLIP driver won't work together
+  with the PLIP support in Linux versions 1.0.x.  This option enlarges
+  your kernel by about 8kB. If you want to compile this as a module (
+  = code which can be inserted in and removed from the running kernel
+  whenever you want), say M here and read Documentation/modules.txt as
+  well as Documentation/networking/net-modules.txt. If you want to use
+  both a parallel printer and PLIP, there are two cases: 1) If the
+  printer and the PLIP cable are to use the same parallel port
+  (presumably because you have just one), it is best to compile both
+  drivers as modules and load and unload them as needed. 2) To use
+  different parallel ports for the printer and the PLIP cable, you can
+  say Y to the printer driver, specify the base address of the
+  parallel port(s) to use for the printer(s) with the "lp" kernel
+  command line option. (See the documentation of your boot loader
+  (lilo or loadlin) about how to pass options to the kernel at boot
+  time. The lilo procedure is also explained in the SCSI-HOWTO,
+  available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.) The standard base addresses
+  as well as the syntax of the "lp" command line option can be found
+  in drivers/char/lp.c. You can then say Y to this PLIP driver or,
+  preferably, M in which case Documentation/networking/net-modules.txt
+  tells you how to specify the port and IRQ to be used by PLIP at
+  module load time.
+  It's safe to say N here.
 
 EQL (serial line load balancing) support
 CONFIG_EQUALIZER
@@ -2052,8 +2058,8 @@ CONFIG_EEXPRESS_PRO
 
 EtherExpress support
 CONFIG_EEXPRESS
-  If you have a network (ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via ftp (user: anonymous) in
+  If you have an EtherExpress16 network (ethernet) card, say Y and
+  read the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the Intel
   EtherExpress16 card used to be regarded as a very poor choice
   because the driver was very unreliable. We now have a new driver
@@ -2523,7 +2529,7 @@ CONFIG_QUOTA
   usage (also called diskquotas). Currently, it works only for the
   ext2 filesystem; you need the software available via ftp (user:
   anonymous) in
-  ftp.funet.fi:/pub/Linux/People/Linux/subsystems/quota/ in order to
+  ftp.funet.fi:/pub/Linux/PEOPLE/Linus/subsystems/quota/ in order to
   use it. Probably this is only useful for multi user systems. If
   unsure, say N.
 
@@ -2784,6 +2790,61 @@ CONFIG_SYSV_FS
   Documentation/modules.txt. If you haven't heard about all of this
   before, it's safe to say N.
 
+BSD UFS filesystem support (read only)
+CONFIG_UFS_FS
+  BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD
+  and NeXTstep) use a filesystem called UFS. Some System V Unixes can
+  create and mount partitions and diskettes using this filesystem
+  as well. Enabling this option allows you to mount these partitions
+  and diskettes read-only. If you only intend to mount files from
+  some other Unix over the network using NFS, you don't need the
+  UFS filesystem support (but you need nfs filesystem support
+  obviously). Note that this option is generally not needed for
+  floppies, since a good portable way to transport files and
+  directories between unixes (and even other operating systems)
+  is given by the tar program ("man tar"). When accessing NeXTstep
+  files, you may need to convert them from the NeXT character set
+  to the Latin1 character set; use GNU recode for this purpose.
+  Say Y to build UFS support into your kernel. If you want to compile
+  this as a module ( = code which can be inserted in and removed from
+  the running kernel whenever you want), say M here and read
+  Documentation/modules.txt. If you haven't heard about all of this
+  before, it's safe to say N.
+
+BSD disklabel (FreeBSD partition tables) support
+CONFIG_BSD_DISKLABEL
+  FreeBSD uses its own partition scheme on your PC. It requires only
+  one entry in the primary partition table of your disk and manages it
+  similarly to DOS extended partitions, putting in its first sector a
+  new partition table in disklabel format. Enabling this option allow
+  you to read these disklabels and further mount FreeBSD partitions on
+  your Linux box if you also have configured BSD ufs filesystem
+  support. If you don't know what all this is about, say N.
+
+SMD disklabel (Sun partition tables) support
+CONFIG_SMD_DISKLABEL
+  Like most systems, SunOS uses its own partition table format,
+  incompatible with each other. Enabling this option allow you to read
+  these partition tables and further mount SunOS disks on your Linux
+  box if you also have configured BSD ufs filesystem support. This is
+  mainly used to carry data from a Sparc under SunOS to your Linux box
+  via a removable medium like magneto-optical or ZIP drives. If you
+  don't know what all this is about, say N.
+
+AFFS filesystem support
+CONFIG_AFFS_FS
+  AFFS is the filesystem used on Commodore Amiga computers. People
+  running Linux on other systems can say N here.
+
+UFS filesystem support (read only)
+CONFIG_UFS_FS
+  UFS (Unix File System) is the way files are organized on Sun Solaris
+  harddisks and floppies. If you want to be able to read those, say Y
+  here. Note that this option is generally not needed for floppies,
+  since a good portable way to transport files and directories between
+  unixes (and even other operating systems) is given by the tar
+  program ("man tar").
+
 SMB filesystem support (to mount WfW shares etc..)
 CONFIG_SMB_FS
   SMB (Server Message Buffer) is the protocol Windows for Workgroups
@@ -2817,6 +2878,24 @@ CONFIG_NCP_FS
   removed from the running kernel whenever you want), say M here and
   read Documentation/modules.txt.
 
+Amiga FFS filesystem support (read only)
+CONFIG_AFFS_FS
+  The Fast File System (FFS) is the common filesystem used on harddisks
+  by Amiga (tm) Systems since AmigaOS Version 1.3 (34.20). It's also
+  possible to mount Diskfiles used by the Un*X Amiga Emulator by Bernd
+  Schmidt (http://www-users.informatik.rwth-aachen.de/~crux/uae.html)
+  If you want to do this, you will also need the loopback device
+  support. Because it's in an early development state, the AFFS is 
+  read only. Say Y if you want to be able to read files from an Amiga
+  FFS partition of your harddrive. Amiga floppies however cannot be
+  read with this driver due to an incompatibility of the floppy
+  controller used in an Amiga and the standard floppy controller in
+  PCs and workstations. Read Documentation/filesystems/affs.txt. This
+  filesystem is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you
+  want). If you want to compile it as a module, say M here and read
+  Documentation/modules.txt. If unsure, say N.
+
 Standard/generic serial support
 CONFIG_SERIAL
   This selects whether you want to include the driver for the standard
@@ -2896,12 +2975,23 @@ CONFIG_PRINTER
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you want to compile this
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
-  Documentation/modules.txt. If you intend to use PLIP (Parallel Line
-  Internet Protocol is mainly used to create a mini network by
-  connecting the parallel ports of two local machines) or a ethernet
-  network pocket adaptor attaching to the parallel port and a parallel
-  printer as well, you should compile both drivers as modules because
-  the drivers both want the same resources.
+  Documentation/modules.txt. If you want to use both a parallel
+  printer and PLIP, there are two cases: 1) If the printer and the
+  PLIP cable are to use the same parallel port (presumably because you
+  have just one), it is best to compile both drivers as modules and
+  load and unload them as needed. 2) To use different parallel ports
+  for the printer and the PLIP cable, you can say Y to this printer
+  driver, specify the base address of the parallel port(s) to use for
+  the printer(s) with the "lp" kernel command line option. (See the
+  documentation of your boot loader (lilo or loadlin) about how to
+  pass options to the kernel at boot time. The lilo procedure is also
+  explained in the SCSI-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.) The standard base addresses
+  as well as the syntax of the "lp" command line option can be found
+  in drivers/char/lp.c. You can then say Y to the PLIP driver or,
+  preferably, M in which case Documentation/networking/net-modules.txt
+  tells you how to specify the port and IRQ to be used by PLIP at
+  module load time.
 
 Logitech busmouse support
 CONFIG_BUSMOUSE
@@ -2975,10 +3065,11 @@ CONFIG_ATIXL_BUSMOUSE
 
 Support for user miscellaneous modules
 CONFIG_UMISC
-  This option forces generic miscellaneous minor device  support in the
-  kernel, and allows later loading of user miscellaneous device  modules,
-  such as drivers for optic pens and touchscreens. Unless you need such
-  specific modules, or are willing to write/test one, just say N.
+  This option forces generic miscellaneous minor device support in the
+  kernel, and allows later loading of user miscellaneous device
+  modules, such as drivers for optic pens and touchscreens. Unless you
+  need such specific modules, or are willing to write/test one, just
+  say N.
 
 QIC-02 tape support
 CONFIG_QIC02_TAPE
@@ -3196,7 +3287,8 @@ CONFIG_ISDN_PPP
   This enables synchronous PPP via ISDN. This protocol is used by
   Cisco or Sun for example. You will need a special version of pppd
   (called ipppd) for using this feature. See
-  Documentation/isdn/README.syncppp for more information.
+  Documentation/isdn/README.syncppp and Documentation/isdn/syncPPP.FAQ
+  for more information.
 
 Support generic MP (RFC 1717)
 CONFIG_ISDN_MPP
@@ -3230,10 +3322,11 @@ CONFIG_ISDN_DRV_TELES
 PCBIT-D support
 CONFIG_ISDN_DRV_PCBIT
   This enables support for the PCBIT ISDN-cards. This card is
-  manufactured in Portugal by Octal. For running this card, 
-  additional firmware is necessary, which has to be downloaded into
-  the card using a utility which is distributed separately.  
-  See Documentation/isdn/README for more information.  
+  manufactured in Portugal by Octal. For running this card, additional
+  firmware is necessary, which has to be downloaded into the card
+  using a utility which is distributed separately.  See
+  Documentation/isdn/README and Documentation/isdn/README.pcbit for
+  more information.
 
 Support for AP1000 multicomputer
 CONFIG_AP1000
@@ -3311,4 +3404,5 @@ CONFIG_AP1000
 # LocalWords:  Starmode Metricom MosquitoNet mosquitonet kbit nfsroot Digiboard
 # LocalWords:  DIGI Xe Xeve digiboard UMISC touchscreens mtu ethernets HBAs MEX
 # LocalWords:  Shifflett netcom js jshiffle WIC DECchip ELCP EtherPower dst RTC
-# LocalWords:  rtc SMP
+# LocalWords:  rtc SMP lp Digi Intl RightSwitch DGRS dgrs AFFS Amiga UFS SDL AP
+# LocalWords:  Solaris RISCom riscom syncPPP PCBIT pcbit sparc anu au
diff --git a/Documentation/filesystems/affs.txt b/Documentation/filesystems/affs.txt
new file mode 100644 (file)
index 0000000..996769f
--- /dev/null
@@ -0,0 +1,23 @@
+Linux can read, but not write, Amiga FFS partitions.
+
+Mount options are
+    size       has the size in 512 byte blocks of the mounted medium. 
+
+Case is significant in filename matching, different to real AFFS.
+
+
+Command line example
+    mount  Archive/Amiga/Workbench3.1.adf /mnt -t affs -o loop,size=1760
+    mount  /dev/sda3 /Amiga -t affs
+
+/etc/fstab example
+    /dev/sdb5  /d/f    affs    ro
+
+This file system will probably be writeable in future releases.
+
+It's not possible to read floppy disks with a normal PC or workstation
+due to an incompatibility to the Amiga floppy controller.
+
+If you are interested in an Amiga Emulator for Linux, look at
+
+http://www-users.informatik.rwth-aachen.de/~crux/uae.html
index eacc911bd58f69f354ed2469802aa1a24e6d38c7..05a42ee9fa0aa353c39edc5dce577edbce280b7a 100644 (file)
@@ -28,10 +28,15 @@ is no longer used, new command line parameters exist, and the behavior
 of the "rdev -r" or "ramsize" (usually a symbolic link to "rdev")
 command has changed.
 
-The old "ramdisk=<ram_size>" is now obsolete. The kernel will ignore
-such old commands, and thus they will be passed on through to the init
-program, which will then complain. You should remove any of these old
-style commands from config files such as "/etc/lilo.config".
+Also, the new ramdisk supports up to 16 ramdisks out of the box, and can
+be reconfigured in rd.c to support up to 255 ramdisks.  To use multiple
+ramdisk support with your system, run 'mknod /dev/ramX b 1 X' and chmod
+(to change it's permissions) it to your liking.  The default /dev/ram(disk)
+uses minor #1, so start with ram2 and go from there.
+
+The old "ramdisk=<ram_size>" has been changed to "ramdisk_size=<ram_size>"
+to make it clearer.  The original "ramdisk=<ram_size>" has been kept around
+for compatiblity reasons, but it will probably be removed in 2.1.x.
 
 The new ramdisk also has the ability to load compressed ramdisk images,
 allowing one to squeeze more programs onto an average installation or 
@@ -92,6 +97,11 @@ two floppy configuration, you will need the chance to switch disks,
 and thus "prompt_ramdisk=1" can be used. Since this is the default 
 value, it doesn't really need to be specified.
 
+       ramdisk_size=N
+       ==============
+
+This parameter tells the ramdisk driver to set up ramdisks of Nk size.  The
+default is 4096 (4MB). 
 
 3) Using "rdev -r" With New Kernels
 -----------------------------------
index 69ed969bbf9d76c2557341d3b4fd8d2c1428afcd..6157bb11d70ffe59ffcd3f5d81af7b1e75128c66 100644 (file)
@@ -5,7 +5,7 @@
 NOTE: English is not my native language. 
       I'm sorry for any mistakes in this text.
 
-Misc. notes for RISCom/8 serial driver, in no particule order :)
+Misc. notes for RISCom/8 serial driver, in no particular order :)
 
 1) This driver can support up to 4 boards at time.
    Use string "riscom8=0xXXX,0xXXX,0xXXX,0xXXX" at LILO prompt, for
index 19718a2e015cd36a1f54ce0bce80c7bd1369df6a..5224ca1e6ed617647ae3bd3ba39d05a594ecfd5c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 95
+SUBLEVEL = 96
 
 ARCH = i386
 
@@ -142,6 +142,10 @@ ifdef CONFIG_PCI
 DRIVERS := $(DRIVERS) drivers/pci/pci.a
 endif
 
+ifdef CONFIG_SBUS
+DRIVERS := $(DRIVERS) drivers/sbus/sbus.a
+endif
+
 include arch/$(ARCH)/Makefile
 
 ifdef SMP
@@ -202,7 +206,7 @@ newversion:
        @if [ ! -f .version ]; then \
                echo 1 > .version; \
        else \
-               expr `cat .version` + 1 > .version; \
+               expr 0`cat .version` + 1 > .version; \
        fi
 
 include/linux/compile.h: $(CONFIGURATION) include/linux/version.h newversion
@@ -326,7 +330,7 @@ mrproper: clean
        rm -f .hdepend
        rm -f $(TOPDIR)/include/linux/modversions.h
        rm -f $(TOPDIR)/include/linux/modules/*
-       
+
 
 distclean: mrproper
        rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
index 1eb9c84169b83033a928ad22cc8889e6757a8f14..a483e41af6d0a9e245f9a3908e4203e07738ff43 100644 (file)
@@ -541,7 +541,7 @@ strace:
        jsr     $26,($27),syscall_trace
        bsr     $1,undo_switch_stack
 
-       /* get the system call number and the argments back.. */
+       /* get the system call number and the arguments back.. */
        ldq     $0,0($30)
        ldq     $16,SP_OFF+24($30)
        ldq     $17,SP_OFF+32($30)
@@ -574,9 +574,9 @@ strace_success:
 
        .align  3
 strace_error:
-       ldq     $9,0($30)       /* old syscall nr (zero if success) */
-       beq     $9,strace_success
-       ldq     $10,72($30)     /* .. and this a3 */
+       ldq     $19,0($30)      /* old syscall nr (zero if success) */
+       beq     $19,strace_success
+       ldq     $20,72($30)     /* .. and this a3 */
 
        subq    $31,$0,$0       /* with error in v0 */
        addq    $31,1,$1        /* set a3 for errno return */
@@ -584,13 +584,15 @@ strace_error:
        stq     $1,72($30)      /* a3 for return */
 
        bsr     $1,do_switch_stack
+       bis     $19,$19,$9      /* save old syscall number */
+       bis     $20,$20,$10     /* save old a3 */
        lda     $27,syscall_trace
        jsr     $26,($27),syscall_trace
+       bis     $9,$9,$19
+       bis     $10,$10,$20     
        bsr     $1,undo_switch_stack
 
        bis     $31,$31,$26     /* tell "ret_from_sys_call" that we can restart */
-       bis     $9,$9,$19       /*  .. old syscall nr */
-       bis     $10,$10,$20     /*  .. old a3 */
        br      $31,ret_from_sys_call
 
        .align 3
index 45bc114f8698cebd7ca007a99a7cf7dd9b7dcd5f..fd4575af7a0ea3bc6070ac6aa1f6bf665ae4ab3b 100644 (file)
@@ -67,7 +67,7 @@ asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask,
        printk("%s: arithmetic trap at %016lx: %02lx %016lx\n",
                current->comm, regs.pc, summary, write_mask);
        die_if_kernel("Arithmetic fault", &regs, 0);
-       send_sig(SIGFPE, current, 1);
+       force_sig(SIGFPE, current);
 }
 
 asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2,
@@ -82,7 +82,7 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2,
                if (ptrace_cancel_bpt(current)) {
                        regs.pc -= 4;   /* make pc point to former bpt */
                }
-               send_sig(SIGTRAP, current, 1);
+               force_sig(SIGTRAP, current);
                break;
 
              case 2: /* gentrap */
@@ -97,7 +97,7 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2,
                      case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF:
                      case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV:
                      case GEN_FLTINE:
-                       send_sig(SIGFPE, current, 1);
+                       force_sig(SIGFPE, current);
                        break;
 
                      case GEN_DECOVF:
@@ -118,14 +118,14 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2,
                      case GEN_SUBRNG5:
                      case GEN_SUBRNG6:
                      case GEN_SUBRNG7:
-                       send_sig(SIGILL, current, 1);
+                       force_sig(SIGILL, current);
                        break;
                }
                break;
 
              case 1: /* bugcheck */
              case 3: /* FEN fault */
-               send_sig(SIGILL, current, 1);
+               force_sig(SIGILL, current);
                break;
 
              case 4: /* opDEC */
@@ -142,12 +142,12 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2,
                                 * (we don't do no stinkin' VAX fp...)
                                 */
                                if (!alpha_fp_emul(regs.pc - 4))
-                                       send_sig(SIGFPE, current, 1);
+                                       force_sig(SIGFPE, current);
                                break;
                        }
                }
 #endif
-               send_sig(SIGILL, current, 1);
+               force_sig(SIGILL, current);
                break;
 
              default:
@@ -314,7 +314,7 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg
        }
        if (verify_area(dir, va, size)) {
                *pc_addr -= 4;  /* make pc point to faulting insn */
-               send_sig(SIGSEGV, current, 1);
+               force_sig(SIGSEGV, current);
                return;
        }
 
@@ -362,7 +362,7 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg
              case 0x2d: stq_u(*reg_addr, va);               break;     /* stq */
              default:
                *pc_addr -= 4;  /* make pc point to faulting insn */
-               send_sig(SIGBUS, current, 1);
+               force_sig(SIGBUS, current);
                return;
        }
 
index 33331dca03a59c7d5e74e93c47887530094feecd..ba4d99e5162617a50dba61e398b85b2a3e081862 100644 (file)
@@ -97,7 +97,7 @@ bad_area:
                printk("%s: memory violation at pc=%08lx rp=%08lx (bad address = %08lx)\n",
                        current->comm, regs.pc, regs.r26, address);
                die_if_kernel("oops", &regs, cause);
-               send_sig(SIGSEGV, current, 1);
+               force_sig(SIGSEGV, current);
                return;
        }
 /*
index 4557b285f519cafaf9b2f22c8db631e0f4265662..31210b5b3276963a1985412450a078ed5e605a65 100644 (file)
@@ -40,9 +40,7 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
        tsk->tss.error_code = error_code; \
        tsk->tss.trap_no = trapnr; \
-       if (signr == SIGTRAP && current->flags & PF_PTRACED) \
-               current->blocked &= ~(1 << (SIGTRAP-1)); \
-       send_sig(signr, tsk, 1); \
+       force_sig(signr, tsk); \
        die_if_kernel(str,regs,error_code); \
 }
 
@@ -187,7 +185,7 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
        die_if_kernel("general protection",regs,error_code);
        current->tss.error_code = error_code;
        current->tss.trap_no = 13;
-       send_sig(SIGSEGV, current, 1);  
+       force_sig(SIGSEGV, current);    
 }
 
 asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
@@ -209,9 +207,7 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code)
                handle_vm86_debug((struct vm86_regs *) regs, error_code);
                return;
        }
-       if (current->flags & PF_PTRACED)
-               current->blocked &= ~(1 << (SIGTRAP-1));
-       send_sig(SIGTRAP, current, 1);
+       force_sig(SIGTRAP, current);
        current->tss.trap_no = 1;
        current->tss.error_code = error_code;
        if ((regs->cs & 3) == 0) {
@@ -260,7 +256,7 @@ void math_error(void)
        __asm__ __volatile__("fnsave %0":"=m" (task->tss.i387.hard));
        task->flags&=~PF_USEDFPU;
 
-       send_sig(SIGFPE, task, 1);
+       force_sig(SIGFPE, task);
        task->tss.trap_no = 16;
        task->tss.error_code = 0;
 
@@ -327,7 +323,7 @@ asmlinkage void math_emulate(long arg)
 {
   printk("math-emulation not enabled and no coprocessor found.\n");
   printk("killing %s.\n",current->comm);
-  send_sig(SIGFPE,current,1);
+  force_sig(SIGFPE,current);
   schedule();
 }
 
index 623344bee8391f835f9925890a991419fff6c4c9..76556f8cfc5448735a296a1047cd519d4016b40c 100644 (file)
@@ -104,7 +104,7 @@ bad_area:
                current->tss.cr2 = address;
                current->tss.error_code = error_code;
                current->tss.trap_no = 14;
-               send_sig(SIGSEGV, current, 1);
+               force_sig(SIGSEGV, current);
                return;
        }
 /*
index 7efd8143ca5bc3ec44a4113be5f3ea3755b83e1f..0e74040f98f31d99bc55f143375481b115a3f69f 100644 (file)
    -------------------------------------------
 
    Since there are much more parameters for the Amiga display than for the
-   frame buffer interface, there must be some depencies among the Amiga display
+   frame buffer interface, there must be some dependencies among the Amiga display
    parameters. Here's what I found out:
 
       - ddfstrt and ddfstop are best aligned to 64 pixels.
@@ -1138,13 +1138,13 @@ static void check_default_mode(void);
  *
  * History:
  *   - 03 Jan 95: Original version my Martin Schaller: The TT driver and
- *                all the device independant stuff
+ *                all the device independent stuff
  *   - 09 Jan 95: Roman: I've added the hardware abstraction (hw_switch)
  *                and wrote the Falcon, ST(E), and External drivers
  *                based on the original TT driver.
  *   - 26 Jan 95: Geert: Amiga version
  *   - 19 Feb 95: Hamish: added Jes Sorensen's ECS patches to the Amiga
- *               frame buffer device.  This provdes ECS support and the
+ *               frame buffer device.  This provides ECS support and the
  *               following screen-modes: multiscan, multiscan-lace,
  *               super72, super72-lace, dblntsc, dblpal & euro72.
  *               He suggests that we remove the old AGA screenmodes,
@@ -1255,7 +1255,7 @@ static __inline__ void mono_init_vblank(void)
  * bplcon0, diwstrt, diwstop, ddfstrt, ddfstop registers (a few others could
  * be used as well). -wjr
  *
- * The code now supports ECS aswell, except for FMODE all control registers
+ * The code now supports ECS as well, except for FMODE all control registers
  * are the same under ECS. A special color-table has to be generated though.
  * -Jes
  */
@@ -1782,7 +1782,7 @@ static void mono_video_setup (char *options, int *ints)
  *    0x02c -> 0x12c. NTSC overscan uses values > 256 too. However counter
  *    is 8 bit, will wrap. RKM 1.1 suggests use of a WAIT(0x00,0xff),
  *    WAIT(x,y-0x100) pair to handle this case. This is WRONG - must use
- *    WAIT(0xe2,0xff) to ensure that wrap occures by next copper
+ *    WAIT(0xe2,0xff) to ensure that wrap occurred by next copper
  *    instruction. Argghh!
  *
  * 4. RKM 1.1 suggests Copper-wait x positions are in range [0,0xe2].
@@ -2392,7 +2392,7 @@ static void mono_amifb_interrupt(int irq, struct pt_regs *fp, void *data)
        static ushort cursorstate = 0;
 
        /* I *think* that you should only change display lists on long frame.
-        * At least it goes awfully perculiar on my A500 without the following
+        * At least it goes awfully peculiar on my A500 without the following
         * test. Not really in a position to test this hypothesis, so sorry
         * for the slow scrolling, all you flicker-fixed souls
         */
@@ -2490,6 +2490,7 @@ static int mono_amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
        fix->ypanstep = 0;
        fix->ywrapstep = 1;
 
+       fix->line_length = 0;
        for (i = 0; i < arraysize(fix->reserved); i++)
                fix->reserved[i] = 0;
        return(0);
@@ -2567,6 +2568,7 @@ static void mono_amiga_fb_set_disp(int con)
        disp[con].type_aux = fix.type_aux;
        disp[con].ypanstep = fix.ypanstep;
        disp[con].ywrapstep = fix.ywrapstep;
+       disp[con].line_length = fix.line_length;
        disp[con].can_soft_blank = 1;
        disp[con].inverse = mono_amifb_inverse;
 }
@@ -3164,6 +3166,7 @@ static int aga_encode_fix(struct fb_fix_screeninfo *fix,
    else
       fix->ywrapstep = 0;
 
+   fix->line_length = 0;
    for (i = 0; i < arraysize(fix->reserved); i++)
       fix->reserved[i] = 0;
 
@@ -4460,6 +4463,7 @@ static void amiga_fb_set_disp(int con)
    disp[con].type_aux = fix.type_aux;
    disp[con].ypanstep = fix.ypanstep;
    disp[con].ywrapstep = fix.ywrapstep;
+   disp[con].line_length = fix.line_length;
    disp[con].can_soft_blank = 1;
    disp[con].inverse = amifb_inverse;
 }
index a4e4f01e8ce5864c1e7067ed9354fc41e6281158..6637407d28034939511e48f377433a695e21df52 100644 (file)
@@ -370,7 +370,7 @@ void amiga_sched_init (isrfunc timer_routine)
     time_finetune = finetune+0.5;
 #endif
 
-    ciab.cra &= 0xC0;   /* turn off timer A, continous mode, from Eclk */
+    ciab.cra &= 0xC0;   /* turn off timer A, continuous mode, from Eclk */
     ciab.talo = jiffy_ticks % 256;
     ciab.tahi = jiffy_ticks / 256;
     /* CIA interrupts when counter underflows, so adjust ticks by 1 */
@@ -378,7 +378,7 @@ void amiga_sched_init (isrfunc timer_routine)
 
     /* install interrupt service routine for CIAB Timer A */
     /*
-     * Please don't change this to use ciaa, as it interfers with the
+     * Please don't change this to use ciaa, as it interferes with the
      * SCSI code. We'll have to take a look at this later
      */
 #if 0
index d100f668f573eb27f5ad2c975536cae156b65c3a..2dd68450b3ca7e34455426c88fadb6695ba08329 100644 (file)
@@ -7,7 +7,7 @@ static struct symbol_table mach_amiga_symbol_table = {
    * Add things here when you find the need for it.
    */
 
-  /* examble
+  /* example
   X(something_you_need),
   */
 
index 34cccce532c1fdc7f876a438607183b1ea4c041c..3320795e0eaa3a2e504d47f39efa5196844e92bf 100644 (file)
@@ -118,7 +118,7 @@ static struct atari_fb_par {
        } hw;
 } current_par;
 
-/* Don't calculate an own resoltion, and thus don't change the one found when
+/* Don't calculate an own resolution, and thus don't change the one found when
  * booting (currently used for the Falcon to keep settings for internal video
  * hardware extensions (e.g. ScreenBlaster)  */
 static int DontCalcRes = 0; 
@@ -786,7 +786,7 @@ static struct pixel_clock {
        short right, hsync, left;       /* standard timing in clock cycles, not pixel */
                /* hsync initialized in falcon_detect() */
        short sync_mask;        /* or-mask for hw.falcon.sync to set this clock */
-       short control_mask; /* dito, for hw.falcon.vid_control */
+       short control_mask; /* ditto, for hw.falcon.vid_control */
 }
 f25  = {25175000, 39722, 18, 0, 42, 0x0, VCO_CLOCK25},
 f32  = {32000000, 31250, 18, 0, 42, 0x0, 0},
@@ -1683,7 +1683,7 @@ static int falcon_detect( void )
        falcon_get_par(&par);
        falcon_encode_var(&atari_fb_predefined[0], &par);
 
-       /* Detectet mode is always the "autodetect" slot */
+       /* Detected mode is always the "autodetect" slot */
        return 1;
 }
 
@@ -2303,7 +2303,7 @@ static void atari_fb_set_par( struct atari_fb_par *par )
 
 
 /* =========================================================== */
-/* ============== Hardware Independant Functions ============= */
+/* ============== Hardware Independent Functions ============= */
 /* =========================================================== */
 
 
@@ -2992,7 +2992,7 @@ void atari_video_setup( char *options, int *ints )
     }
 
     if (*int_str) {
-       /* Format to config extendet internal video hardware like OverScan:
+       /* Format to config extended internal video hardware like OverScan:
        "<switch-type>,internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
        Explanation:
        <switch-type> type to switch on higher resolution
index 3e9e6a3e986e69f488c68d99570163c3cfea9355..497d176039850239abcd2aa0016c6f3f1e33f47f 100644 (file)
@@ -5,7 +5,7 @@
  *  Added support for TT interrupts; setup for TT SCU (may someone has
  *  twiddled there and we won't get the right interrupts :-()
  *
- *  Major change: The device-independant code in m68k/ints.c didn't know
+ *  Major change: The device-independent code in m68k/ints.c didn't know
  *  about non-autovec ints yet. It hardcoded the number of possible ints to
  *  7 (IRQ1...IRQ7). But the Atari has lots of non-autovec ints! I made the
  *  number of possible ints a constant defined in interrupt.h, which is
@@ -321,7 +321,7 @@ SYMBOL_NAME_STR(falcon_hblhandler) ":
        movel   %sp@+,%d0
        rte");
 
-/* Defined in entry.S; only increments 'num_suprious' */
+/* Defined in entry.S; only increments 'num_spurious' */
 asmlinkage void bad_interrupt(void);
 
 extern void atari_microwire_cmd( int cmd );
index 337f2700e138c676ea3bd98c9c4d549560926b82..124eb403ce7be4be91df177766f15bfcc7af9e4b 100644 (file)
@@ -302,7 +302,7 @@ static void atakeyb_rep( unsigned long ignore )
  * it's really hard to decide whether they're mouse or keyboard bytes. Since
  * overruns usually occur when moving the Atari mouse rapidly, they're seen as
  * mouse bytes here. If this is wrong, only a make code of the keyboard gets
- * lost, which isn't too bad. Loosing a break code would be desasterous,
+ * lost, which isn't too bad. Loosing a break code would be disastrous,
  * because then the keyboard repeat strikes...
  */
 
@@ -541,7 +541,7 @@ void ikbd_reset(void)
     
     ikbd_write(cmd, 2);
 
-    /* if allswell code 0xF1 is returned, else the break codes of
+    /* if all's well code 0xF1 is returned, else the break codes of
        all keys making contact */
 }
 
index 64e3bdb65a5a4f42d2d52683d9f57d60a9dc9d94..72ba09b975d6de3ef91960dc643c68feba034cb2 100644 (file)
@@ -98,7 +98,7 @@ atari_check_partition (struct gendisk *hd, unsigned int dev)
                        break;
                }
                if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) {
-                       printk( "\nID of extended partion is not XGM!\n" );
+                       printk( "\nID of extended partition is not XGM!\n" );
                        brelse( xbh );
                        break;
                }
@@ -128,7 +128,7 @@ atari_check_partition (struct gendisk *hd, unsigned int dev)
   if ( part_fmt!=1 ) /* no extended partitions -> test ICD-format */
   {
     pi = &rs->icdpart[0];
-    /* sanity check: no ICD format if first partion invalid */
+    /* sanity check: no ICD format if first partition invalid */
     if (memcmp (pi->id, "GEM", 3) == 0 ||
         memcmp (pi->id, "BGM", 3) == 0 ||
         memcmp (pi->id, "RAW", 3) == 0 )
index 555cf30bb00d914555042252cf59ab77ca55dd73..0d8df381d07023dd64046664157d2f47f6d636fb 100644 (file)
@@ -81,7 +81,7 @@ void atari_mksound (unsigned int count, unsigned int ticks)
 
        if (count == 750 && ticks == HZ/8) {
                /* Special case: These values are used by console.c to
-                * generate the console bell. They are catched here and the
+                * generate the console bell. They are cached here and the
                 * sound actually generated is somehow special: it uses the
                 * generator B and an envelope. No timer is needed therefore
                 * and the bell doesn't disturb an other ongoing sound.
index a8ac7cdb89b8ee0b31b2418483634527c30ce8e7..fc7ad0cd65aa86694ee889fb2ce7a2ed7d10172a 100644 (file)
@@ -650,7 +650,7 @@ int atari_hwclk( int op, struct hwclk_time *t )
     tos_version = is_medusa ? 0xfff : *(unsigned short *)0xff000002;
 
     ctrl = RTC_READ(RTC_CONTROL); /* control registers are
-                                   * independant from the UIP */
+                                   * independent from the UIP */
 
     if (op) {
         /* write: prepare values */
@@ -1109,7 +1109,7 @@ void atari_get_model(char *model)
 
 int atari_get_hardware_list(char *buffer)
 {
-    int len = 0;
+    int len = 0, i;
 
     for (i = 0; i < boot_info.num_memory; i++)
        len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n",
index af387a9340c9313c9f1eb2ed571441d168799748..356068b622633884ba874e0b89dbaa2bd2c63fe2 100644 (file)
@@ -59,13 +59,13 @@ static void stdma_int (int irq, struct pt_regs *fp, void *dummy);
 /*
  * Function: void stdma_lock( isrfunc isr, void *data )
  *
- * Purpose: Trys to get a lock on the ST-DMA chip that is used by more
+ * Purpose: Tries to get a lock on the ST-DMA chip that is used by more
  *   then one device driver. Waits on stdma_wait until lock is free.
  *   stdma_lock() may not be called from an interrupt! You have to
  *   get the lock in your main routine and release it when your
  *   request is finished.
  *
- * Inputs: A interupt function that is called until the lock is
+ * Inputs: A interrupt function that is called until the lock is
  *   released.
  *
  * Returns: nothing
@@ -126,7 +126,7 @@ void stdma_release(void)
  *
  * Inputs: none
  *
- * Returns: 0 if noone is waiting, != 0 otherwise
+ * Returns: 0 if no one is waiting, != 0 otherwise
  *
  */
 
@@ -182,7 +182,7 @@ void stdma_init(void)
 /*
  * Function: void stdma_int()
  *
- * Purpose: The interupt routine for the ST-DMA. It calls the isr
+ * Purpose: The interrupt routine for the ST-DMA. It calls the isr
  *   registered by stdma_lock().
  *
  */
index ffd38365214c9d17cd760341a68011ddb280a689..54b2534d9c4e60cf1ac0d70161956ef9c9531b8d 100644 (file)
@@ -290,7 +290,7 @@ int main(int argc, char *argv[])
                        }
 
                /* if we suspect that Kickstart is zkicked,
-                  modify the entry to show 512K more at the botton of RAM */
+                  modify the entry to show 512K more at the bottom of RAM */
                if (mh.mh_Lower == (void *)0x00280020) {
                    mh.mh_Lower =  (void *)0x00200000;
                    printf("ZKick detected.\n");
index 6ace8d2a0c88a916acd58ca456db33056d40a92b..fc0a7473ee601daa12202976f8b85e880f932e7e 100644 (file)
@@ -15,7 +15,7 @@
 **                 (Andreas)
 **      14 Nov 1994 YANML (Yet Another New Memory Layout :-) kernel
 **                 start address is KSTART_ADDR + PAGE_SIZE, this
-**                 does not need the ugly klugde with
+**                 does not need the ugly kludge with
 **                 -fwritable-strings (++andreas)
 **      09 Sep 1994 Adapted to the new memory layout: All the boot_info entry
 **                  mentions all ST-Ram and the mover is located somewhere
@@ -684,7 +684,7 @@ int main(int argc, char *argv[])
            && memcmp (&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)
          {
            elf_kernel = 1;
-           /* A few plausability checks */
+           /* A few plausibility checks */
            if (kexec_elf.e_type != ET_EXEC || kexec_elf.e_machine != EM_68K
                || kexec_elf.e_version != EV_CURRENT)
              {
@@ -703,7 +703,7 @@ int main(int argc, char *argv[])
                      kexec_elf.e_phnum * sizeof (*kernel_phdrs))
                != kexec_elf.e_phnum * sizeof (*kernel_phdrs))
              {
-               fprintf (stderr, "Unable to read programm headers from %s\n",
+               fprintf (stderr, "Unable to read program headers from %s\n",
                         kernel_name);
                boot_exit (EXIT_FAILURE);
              }
index 347db03301752eee8c06ee3b0a5c873c3c00d666..77e81b2172dd0ffd1a6f17bf169812b90363a51c 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/string.h>
 #include <linux/config.h>
 #include <linux/kd.h>
+#include <linux/malloc.h>
 
 #include <asm/bootinfo.h>
 #include <asm/irq.h>
@@ -578,7 +579,7 @@ static void fbcon_setup(int con, int setcol, int cls)
    if (p->fontwidth != 8)
       panic("fbcon_setup: No support for fontwidth != 8");
 
-   if (divides(p->ywrapstep, p->fontheight))
+   if (divides(p->ywrapstep, p->fontheight) && divides(p->fontheight, p->var.yres_virtual))
       p->scrollmode = SCROLL_YWRAP;
    else if (divides(p->ypanstep, p->fontheight) &&
             p->var.yres_virtual >= p->var.yres+p->fontheight)
@@ -588,11 +589,15 @@ static void fbcon_setup(int con, int setcol, int cls)
 
    conp->vc_cols = p->var.xres/p->fontwidth;
    conp->vc_rows = p->var.yres/p->fontheight;
+   p->vrows = p->var.yres_virtual/p->fontheight;
    conp->vc_can_do_color = p->var.bits_per_pixel != 1;
 
 #ifdef CONFIG_FBCON_MONO
    if (p->var.bits_per_pixel == 1) {
-      p->next_line = p->var.xres_virtual>>3;
+      if (p->line_length)
+         p->next_line = p->line_length;
+      else
+         p->next_line = p->var.xres_virtual>>3;
       p->next_plane = 0;
       p->dispsw = &dispsw_mono;
    } else
@@ -621,14 +626,22 @@ static void fbcon_setup(int con, int setcol, int cls)
 #endif /* CONFIG_FBCON_IPLAN2 */
 #ifdef CONFIG_FBCON_ILBM
    if (p->type == FB_TYPE_INTERLEAVED_PLANES && p->type_aux != 2) {
-      p->next_line = p->type_aux;
-      p->next_plane = p->type_aux/p->var.bits_per_pixel;
+      if (p->line_length) {
+         p->next_line = p->line_length*p->var.bits_per_pixel;
+         p->next_plane = p->line_length;
+      } else {
+         p->next_line = p->type_aux;
+         p->next_plane = p->type_aux/p->var.bits_per_pixel;
+      }
       p->dispsw = &dispsw_ilbm;
    } else
 #endif /* CONFIG_FBCON_ILBM */
 #ifdef CONFIG_FBCON_PLANES
    if (p->type == FB_TYPE_PLANES) {
-      p->next_line = p->var.xres_virtual>>3;
+      if (p->line_length)
+         p->next_line = p->line_length;
+      else
+         p->next_line = p->var.xres_virtual>>3;
       p->next_plane = p->var.yres_virtual*p->next_line;
       p->dispsw = &dispsw_plan;
    } else
@@ -670,7 +683,10 @@ fail:
 #ifdef CONFIG_FBCON_MONO
       printk("fbcon_setup: type %d (aux %d) not supported, trying mono\n",
              p->type, p->type_aux);
-      p->next_line = (p->var.xres_virtual)>>3;
+      if (p->line_length)
+         p->next_line = p->line_length;
+      else
+         p->next_line = p->var.xres_virtual>>3;
       p->next_plane = 0;
       p->var.bits_per_pixel = 1;
       p->dispsw = &dispsw_mono;
@@ -708,7 +724,7 @@ fail:
  * equivalents for large blits, and thats important to the lowest level of
  * a graphics driver. Question is whether some scheme with the blitter
  * would be faster. I suspect not for simple text system - not much
- * asynchronisity.
+ * asynchrony.
  *
  * Code is very simple, just gruesome expansion. Basic strategy is to
  * increase data moved/cleared at each step to 16 bytes to reduce
@@ -732,7 +748,7 @@ fail:
    subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc
    addal is faster than addaw
    movep is rather expensive compared to ordinary move's
-   some functions rewritten in C for clearity, no speed loss */
+   some functions rewritten in C for clarity, no speed loss */
 
 static __inline__ void *mymemclear_small(void *s, size_t count)
 {
@@ -1375,10 +1391,10 @@ static __inline__ u_short dup2w(u_char c)
 
 static __inline__ int real_y(struct display *p, int y)
 {
-   int rows = p->conp->vc_rows;
+   int rows = p->vrows;
 
    y += p->yscroll;
-   return(y < rows || p->scrollmode != SCROLL_YWRAP ? y : y-rows);
+   return(y < rows ? y : y-rows);
 }
 
 
@@ -1398,7 +1414,7 @@ static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
 
    /* Split blits that cross physical y_wrap boundary */
 
-   y_break = conp->vc_rows-p->yscroll;
+   y_break = p->vrows-p->yscroll;
    if (sy < y_break && sy+height-1 >= y_break) {
       u_int b = y_break-sy;
       p->dispsw->clear(conp, p, real_y(p, sy), sx, b, width);
@@ -1513,8 +1529,8 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
             switch (p->scrollmode) {
                case SCROLL_YWRAP:
                   p->yscroll += count;
-                  if (p->yscroll >= conp->vc_rows) /* Deal with wrap */
-                     p->yscroll -= conp->vc_rows;
+                  if (p->yscroll >= p->vrows) /* Deal with wrap */
+                     p->yscroll -= p->vrows;
                   p->var.xoffset = 0;
                   p->var.yoffset = p->yscroll*p->fontheight;
                   p->var.vmode |= FB_VMODE_YWRAP;
@@ -1523,8 +1539,7 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
 
                case SCROLL_YPAN:
                   p->yscroll += count;
-                  if (p->yscroll*p->fontheight+p->var.yres >
-                      p->var.yres_virtual) {
+                  if (p->yscroll+conp->vc_rows > p->vrows) {
                      p->dispsw->bmove(p, p->yscroll, 0, 0, 0, b-count,
                                       conp->vc_cols);
                      p->yscroll = 0;
@@ -1553,7 +1568,7 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
                case SCROLL_YWRAP:
                   p->yscroll -= count;
                   if (p->yscroll < 0)              /* Deal with wrap */
-                     p->yscroll += conp->vc_rows;
+                     p->yscroll += p->vrows;
                   p->var.xoffset = 0;
                   p->var.yoffset = p->yscroll*p->fontheight;
                   p->var.vmode |= FB_VMODE_YWRAP;
@@ -1563,8 +1578,7 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
                case SCROLL_YPAN:
                   p->yscroll -= count;
                   if (p->yscroll < 0) {
-                     p->yscroll = (p->var.yres_virtual-p->var.yres)/
-                                  p->fontheight;
+                     p->yscroll = p->vrows-conp->vc_rows;
                      p->dispsw->bmove(p, 0, 0, p->yscroll+count, 0, b-count,
                                       conp->vc_cols);
                   }
@@ -1582,7 +1596,7 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
             fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols);
 
          /* Fixed bmove() should end Arno's frustration with copying?
-          * Confusius says:
+          * Confucius says:
           *    Man who copies in wrong direction, end up with trashed data
           */
          fbcon_clear(conp, t, 0, count, conp->vc_cols);
@@ -1625,7 +1639,7 @@ static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
     * Recursive invocations don't need to erase the cursor over and
     * over again, so we use fbcon_bmove_rec()
     */
-   fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, conp->vc_rows-p->yscroll);
+   fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll);
 
    return(0);
 }
@@ -1695,6 +1709,134 @@ static int fbcon_blank(int blank)
 }
 
 
+static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data)
+{
+       int unit = conp->vc_num;
+       struct display *p = &disp[unit];
+       int i, size, alloc;
+
+       size = (p->fontwidth+7)/8 * p->fontheight * 256;
+       alloc = (*w+7)/8 * *h * 256;
+       *w = p->fontwidth;
+       *h = p->fontheight;
+   
+       if (alloc < size)
+               /* allocation length not sufficient */
+               return( -ENAMETOOLONG );
+
+       if ((i = verify_area( VERIFY_WRITE, (void *)data, size )))
+               return i;
+
+       memcpy_tofs( data, p->fontdata, size );
+       return( 0 );
+}
+
+
+#define REFCOUNT(fd)   (((int *)(fd))[-1])
+
+static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data)
+{
+       int unit = conp->vc_num;
+       struct display *p = &disp[unit];
+       int i, size, userspace = 1, resize;
+       char *old_data = NULL, *new_data;
+
+       if (w < 0)
+               w = p->fontwidth;
+       if (h < 0)
+               h = p->fontheight;
+       
+       if (w == 0) {
+               /* engage predefined font, name in 'data' */
+               char name[MAX_FONT_NAME+1];
+          
+               if ((i = verify_area( VERIFY_READ, (void *)data, MAX_FONT_NAME )))
+                       return i;
+               memcpy_fromfs( name, data, MAX_FONT_NAME );
+               name[sizeof(name)-1] = 0;
+               
+               if (!findsoftfont( name, &w, &h, (u_char **)&data ))
+                       return( -ENOENT );
+               userspace = 0;
+       }
+       else if (w == 1) {
+               /* copy font from some other console in 'h'*/
+               struct display *op;
+
+               if (h < 0 || !vc_cons_allocated( h ))
+                       return( -ENOTTY );
+               if (h == unit)
+                       return( 0 ); /* nothing to do */
+               op = &disp[h];
+               if (op->fontdata == p->fontdata)
+                       return( 0 ); /* already the same font... */
+
+               resize = (op->fontwidth != p->fontwidth) ||
+                            (op->fontheight != p->fontheight);
+               if (p->userfont)
+                       old_data = p->fontdata;
+               p->fontdata = op->fontdata;
+               w = p->fontwidth = op->fontwidth;
+               h = p->fontheight = op->fontheight;
+               if ((p->userfont = op->userfont))
+                       REFCOUNT(p->fontdata)++; /* increment usage counter */
+               goto activate;
+       }
+
+       if (w != 8)
+               /* Currently only fontwidth == 8 supported */
+               return( -ENXIO );
+       
+       resize = (w != p->fontwidth) || (h != p->fontheight);
+       size = (w+7)/8 * h * 256;
+       
+       if (p->userfont)
+               old_data = p->fontdata;
+       
+       if (userspace) {
+               if ((i = verify_area( VERIFY_READ, (void *)data, size )))
+                       return i;
+               if (!(new_data = kmalloc( sizeof(int)+size, GFP_USER )))
+                       return( -ENOMEM );
+               new_data += sizeof(int);
+               REFCOUNT(new_data) = 1; /* usage counter */
+               memcpy_fromfs( new_data, data, size );
+               p->fontdata = new_data;
+               p->userfont = 1;
+       }
+       else {
+               p->fontdata = data;
+               p->userfont = 0;
+       }
+       p->fontwidth = w;
+       p->fontheight = h;
+
+  activate:
+       if (resize) {
+               p->var.xoffset = p->var.yoffset = p->yscroll = 0;  /* reset wrap/pan */
+               if (divides(p->ywrapstep, p->fontheight))
+                       p->scrollmode = SCROLL_YWRAP;
+               else if (divides(p->ypanstep, p->fontheight) &&
+                                p->var.yres_virtual >= p->var.yres+p->fontheight)
+                       p->scrollmode = SCROLL_YPAN;
+               else
+                       p->scrollmode = SCROLL_YMOVE;
+
+               vc_resize_con( p->var.yres/h, p->var.xres/w, unit );
+       }
+       else if (unit == fg_console)
+               update_screen( unit );
+       
+       if (old_data) {
+               if (--REFCOUNT(old_data) == 0) {
+                       kfree( old_data - sizeof(int) );
+               }
+       }
+       
+       return( 0 );
+}
+
+
 /* ====================================================================== */
 
 /*
@@ -1946,7 +2088,7 @@ static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int y,
 
 
 /*
- *    I splitted the console character loop in two parts:
+ *    I split the console character loop in two parts:
  *
  *      - slow version: this blits one character at a time
  *
@@ -2179,7 +2321,7 @@ static void putc_plan(struct vc_data *conp, struct display *p, int c, int y,
 
 
 /*
- *    I splitted the console character loop in two parts
+ *    I split the console character loop in two parts
  *    (cfr. fbcon_putcs_ilbm())
  */
 
@@ -2326,7 +2468,7 @@ static void bmove_2_plane(struct display *p, int sy, int sx, int dy, int dx,
         * destination, start at even addresses or both are at odd
         * addresses, just the first odd and last even column (if present)
         * require special treatment (memmove_col()). The rest between
-        * then can be copied by normal operations, because all adjancent
+        * then can be copied by normal operations, because all adjacent
         * bytes are affected and are to be stored in the same order.
         *   The pathological case is when the move should go from an odd
         * address to an even or vice versa. Since the bytes in the plane
@@ -2590,7 +2732,7 @@ static void bmove_4_plane(struct display *p, int sy, int sx, int dy, int dx,
         * destination, start at even addresses or both are at odd
         * addresses, just the first odd and last even column (if present)
         * require special treatment (memmove_col()). The rest between
-        * then can be copied by normal operations, because all adjancent
+        * then can be copied by normal operations, because all adjacent
         * bytes are affected and are to be stored in the same order.
         *   The pathological case is when the move should go from an odd
         * address to an even or vice versa. Since the bytes in the plane
@@ -3614,5 +3756,5 @@ static void rev_char_cyber(struct display *p, int x, int y)
 struct consw fb_con = {
    fbcon_startup, fbcon_init, fbcon_deinit, fbcon_clear, fbcon_putc,
    fbcon_putcs, fbcon_cursor, fbcon_scroll, fbcon_bmove, fbcon_switch,
-   fbcon_blank
+   fbcon_blank, fbcon_get_font, fbcon_set_font
 };
index bdf989533b5d6eb08651e81dbabb3c10e66aa9e4..8f23f7ea3c9ce77816652f2a79ba7fa1ce02c97f 100644 (file)
@@ -123,6 +123,7 @@ CONFIG_NFS_FS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
+# CONFIG_UFS_FS is not set
 
 #
 # Character devices
index 6321ca22ab8d5f59303b38924ac406a4d2f1359a..ef3a627bf895bb7d187ab089f06786b7d293f607 100644 (file)
@@ -70,7 +70,7 @@
 |              in INEX2.
 |
 |      A10.    Or in INEX.
-|              If INEX is set, round error occured.  This is
+|              If INEX is set, round error occurred.  This is
 |              compensated for by 'or-ing' in the INEX2 flag to
 |              the lsb of Y.
 |
@@ -518,7 +518,7 @@ A9_con:
 
 
 | A10. Or in INEX.
-|      If INEX is set, round error occured.  This is compensated
+|      If INEX is set, round error occurred.  This is compensated
 |      for by 'or-ing' in the INEX2 flag to the lsb of Y.
 |
 | Register usage:
index f09b5146feba73c2a5cbee1341b11be59b745a44..af1279a4ab6e69d699e1f31bc193fb3173a5a178 100644 (file)
@@ -63,7 +63,7 @@
 |      in an inex2 exception.  If so, set inex1 in the fpsr and 
 |      check if the inex1 exception is enabled.  If so, set d7 upper
 |      word to $0100.  This will signal unimp.sa that an enabled inex1
-|      exception occured.  Unimp will fix the stack.
+|      exception occurred.  Unimp will fix the stack.
 |      
 
 |              Copyright (C) Motorola, Inc. 1990
@@ -204,7 +204,7 @@ calc_m:
 |  Get the rest of the mantissa.
 |
 loadlw:
-       movel   (%a0,%d1.L*4),%d4       |load mantissa lonqword into d4
+       movel   (%a0,%d1.L*4),%d4       |load mantissa longword into d4
        moveql  #FSTRT,%d3      |counter to pick up digits
        moveql  #FNIBS,%d2      |reset number of digits per a0 ptr
 md2b:
@@ -245,21 +245,21 @@ m_sign:
 |
 |  1. Branch on the sign of the adjusted exponent.
 |  2p.(positive exp)
-|   2. Check M16 and the digits in lwords 2 and 3 in decending order.
+|   2. Check M16 and the digits in lwords 2 and 3 in descending order.
 |   3. Add one for each zero encountered until a non-zero digit.
 |   4. Subtract the count from the exp.
 |   5. Check if the exp has crossed zero in #3 above; make the exp abs
 |         and set SE.
 |      6. Multiply the mantissa by 10**count.
 |  2n.(negative exp)
-|   2. Check the digits in lwords 3 and 2 in decending order.
+|   2. Check the digits in lwords 3 and 2 in descending order.
 |   3. Add one for each zero encountered until a non-zero digit.
 |   4. Add the count to the exp.
 |   5. Check if the exp has crossed zero in #3 above; clear SE.
 |   6. Divide the mantissa by 10**count.
 |
 |  *Why 27?  If the adjusted exponent is within -28 < expA < 28, than
-|   any adjustment due to append/strip zeros will drive the resultane
+|   any adjustment due to append/strip zeros will drive the resultant
 |   exponent towards zero.  Since all pwrten constants with a power
 |   of 27 or less are exact, there is no need to use this routine to
 |   attempt to lessen the resultant exponent.
index 512912f14da4b2477edd475984a7d3fe40988528..9ebe3c4904395ac51e84d6e7c26d02758ad7ec9b 100644 (file)
        .set    guard_bit,1             | guard bit is bit number 1
        .set    round_bit,0             | round bit is bit number 0
        .set    stag_mask,0xE0          | upper 3 bits are source tag type
-       .set    denorm_bit,7            | bit determins if denorm or unnorm
+       .set    denorm_bit,7            | bit determines if denorm or unnorm
        .set    etemp15_bit,4           | etemp exponent bit #15
        .set    wbtemp66_bit,2          | wbtemp mantissa bit #66
        .set    wbtemp1_bit,1           | wbtemp mantissa bit #1
index 0fd6a52cf191401fe3d807b22acc10ab86188e1e..edd8108d02ec25c95f643dc05638633726c05a3a 100644 (file)
@@ -296,7 +296,7 @@ loop1:
        moveb   #BUSY_SIZE-4,1(%a7)             |write busy fmt word.
 busy_fr:
        movel   FP_SCR1(%a6),WBTEMP_EX(%a6)     |write
-       movel   FP_SCR1+4(%a6),WBTEMP_HI(%a6)   |execptional op to
+       movel   FP_SCR1+4(%a6),WBTEMP_HI(%a6)   |exceptional op to
        movel   FP_SCR1+8(%a6),WBTEMP_LO(%a6)   |wbtemp
        bsetb   #E3,E_BYTE(%a6)                 |set E3 flag
        bclrb   #E1,E_BYTE(%a6)                 |make sure E1 is clear
index 0aa01f3160874f1513e4536ba9d4c653dc8e4cb6..2bd236d455f620d08248319ee07e8195d78f444f 100644 (file)
@@ -14,7 +14,7 @@
 | UNIMPLEMENTED instructions (exception vector 11) the following
 | applies:
 |
-| - For unnormormalized numbers (opclass 0, 2, or 3) the
+| - For unnormalized numbers (opclass 0, 2, or 3) the
 | number(s) is normalized and the operand type tag is updated.
 |              
 | - For a packed number (opclass 2) the number is unpacked and the
@@ -48,7 +48,7 @@
 | detects this and tags the number as a denorm.  The routine
 | res_func sees the denorm tag and converts the denorm to a
 | norm.  The instruction is then restored back into the '040
-| which re_executess the instruction.
+| which re_executes the instruction.
 |
 |
 |              Copyright (C) Motorola, Inc. 1990
@@ -354,7 +354,7 @@ end_getop:
 
 |
 | Sets the DY_MO_FLG correctly. This is used only on if it is an
-| unuspported data type exception.  Set if dyadic.
+| unsupported data type exception.  Set if dyadic.
 |
 chk_dy_mo:
        movew   CMDREG1B(%a6),%d0       
index 87ff571c205b12b1d7ae956f90a93c9dbea6e75d..9a81bde1deb8c9136257b46959839c14c498de69 100644 (file)
@@ -83,7 +83,7 @@ monadic:
        btstb   #direction_bit,CMDREG1B(%a6)    |check direction
        bne     opclass3                        |it is a mv out
 |
-| At this point, only oplcass 0 and 2 possible
+| At this point, only opclass 0 and 2 possible
 |
        btstb   #7,STAG(%a6)    |if sop = norm=000, zero=001,
 |                              ;inf=010 or nan=011
@@ -299,7 +299,7 @@ cu_nuninx:
        bnes    cu_nunzro
 |
 | The mantissa is zero from the denorm loop.  Check sign and rmode
-| to see if rounding should have occured which would leave the lsb.
+| to see if rounding should have occurred which would leave the lsb.
 |
        movel   USER_FPCR(%a6),%d0
        andil   #0x30,%d0               |isolate rmode
@@ -413,7 +413,7 @@ fix_stk:
 
 |
 | cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
-| ftst) completly in software without an frestore to the 040. 
+| ftst) completely in software without an frestore to the 040. 
 |
 cu_dnrm:
        st      CU_ONLY(%a6)
@@ -610,7 +610,7 @@ cu_sndr:
 |      DNRM_FLG contains $00 for neither op denormalized
 |                        $0f for the destination op denormalized
 |                        $f0 for the source op denormalized
-|                        $ff for both ops denormalzed
+|                        $ff for both ops denormalized
 |
 | The wrap-around condition occurs for add, sub, div, and cmp
 | when 
@@ -828,7 +828,7 @@ add_srcd:
 | precision.  We can then call round with no sticky and the result
 | will be correct for the user's rounding mode and precision.  If
 | the signs are the same, we call round with the sticky bit set
-| and the result will be correctfor the user's rounding mode and
+| and the result will be correct for the user's rounding mode and
 | precision.
 |
 add_wrap:
@@ -1003,7 +1003,7 @@ sub_srcd:
 | precision.  We can then call round with no sticky and the result
 | will be correct for the user's rounding mode and precision.  If
 | the signs are unlike, we call round with the sticky bit set
-| and the result will be correctfor the user's rounding mode and
+| and the result will be correct for the user's rounding mode and
 | precision.
 |
 sub_wrap:
index 1479e246619f8d5580faeb5ecc8ebd07ae33e8e1..b1030fde7ae0d7f19eb9cf677bedc4bff677f478 100644 (file)
@@ -212,7 +212,7 @@ sgl_done:
 add_ext:
        addql  #1,LOCAL_LO(%a0)         |add 1 to l-bit
        bccs    xcc_clr                 |test for carry out
-       addql  #1,LOCAL_HI(%a0)         |propogate carry
+       addql  #1,LOCAL_HI(%a0)         |propagate carry
        bccs    xcc_clr
        roxrw  LOCAL_HI(%a0)            |mant is 0 so restore v-bit
        roxrw  LOCAL_HI+2(%a0)          |mant is 0 so restore v-bit
@@ -231,7 +231,7 @@ add_ext_done:
 add_dbl:
        addl    #ad_1_dbl,LOCAL_LO(%a0)
        bccs    dcc_clr
-       addql   #1,LOCAL_HI(%a0)                |propogate carry
+       addql   #1,LOCAL_HI(%a0)                |propagate carry
        bccs    dcc_clr
        roxrw   LOCAL_HI(%a0)           |mant is 0 so restore v-bit
        roxrw   LOCAL_HI+2(%a0)         |mant is 0 so restore v-bit
@@ -483,7 +483,7 @@ no_inex:
        rts
 
 |
-|      dnrm_lp --- normalize exponent/mantissa to specified threshhold
+|      dnrm_lp --- normalize exponent/mantissa to specified threshold
 |
 | Input:
 |      a0              points to the operand to be denormalized
@@ -506,7 +506,7 @@ dnrm_lp:
        beqs    not_E3                  |not type E3 exception
        bfextu  WBTEMP_GRS(%a6){#6:#3},%d2      |extract guard,round, sticky  bit
        movel   #29,%d0
-       lsll    %d0,%d2                 |shift g,r,s to their postions
+       lsll    %d0,%d2                 |shift g,r,s to their positions
        movel   %d2,%d0
 not_E3:
        movel   (%sp)+,%d2              |restore d2
index c38ab6969d6422a5c0e0e490a4b3437744b38567..282c462b08dbfe2aa9873df05a3bad85ca67571a 100644 (file)
@@ -1,7 +1,7 @@
 |
 |      satan.sa 3.3 12/19/90
 |
-|      The entry point satan computes the arctagent of an
+|      The entry point satan computes the arctangent of an
 |      input value. satand does the same except the input value is a
 |      denormalized number.
 |
index 808e76276170e685e36dabee0443c6249c20a36a..1f01fb1d509c9a0edfe412bc0b705ca0a0018507 100644 (file)
@@ -2,7 +2,7 @@
 |      scale.sa 3.3 7/30/91
 |
 |      The entry point sSCALE computes the destination operand
-|      scaled by the source operand.  If the absoulute value of
+|      scaled by the source operand.  If the absolute value of
 |      the source operand is (>= 2^14) an overflow or underflow
 |      is returned.
 |
index 7e3603a7fc43169d86b6a974569c51621aab2869..9ca3fb6c4d6792a79f50591def5460c82bd47353 100644 (file)
@@ -77,7 +77,7 @@
        .global sint
 sint:
        bfextu  FPCR_MODE(%a6){#2:#2},%d1       |use user's mode for rounding
-|                                      ;implicity has extend precision
+|                                      ;implicitly has extend precision
 |                                      ;in upper word. 
        movel   %d1,L_SCR1(%a6)         |save mode bits
        bras    sintexc                 
@@ -114,7 +114,7 @@ sintmz:
        .global sintrz
 sintrz:
        movel   #1,L_SCR1(%a6)          |use rz mode for rounding
-|                                      ;implicity has extend precision
+|                                      ;implicitly has extend precision
 |                                      ;in upper word. 
        bras    sintexc                 
 |
@@ -123,7 +123,7 @@ sintrz:
 |      Input:  a0 points to an IEEE extended format operand
 |      Output: fp0 has the result 
 |
-| Exeptions:
+| Exceptions:
 |
 | If the subroutine results in an inexact operation, the inx2 and
 | ainx bits in the USER_FPSR are set.
index 74d2ac379b421c4f6a6d3376e58e80229cd182ca..7dbf253bea6a8fdf354259c42a1e2736b7652463 100644 (file)
@@ -107,7 +107,7 @@ real_dz:
 |      necessary for E1 exceptions.
 |
 | Code following the 'inex' label is to handle bug #1232.  In this
-| bug, if an E1 snan, ovfl, or unfl occured, and the process was
+| bug, if an E1 snan, ovfl, or unfl occurred, and the process was
 | swapped out before taking the exception, the exception taken on
 | return was inex, rather than the correct exception.  The snan, ovfl,
 | and unfl exception to be taken must not have been enabled.  The
index 4e7dddcb03fc1df9cc98123c6b6bf2e307774835..b660acd0d16208ed83aa6387e4fedc7496f09825 100644 (file)
@@ -383,7 +383,7 @@ LP1CONT1:
        fmulx   LOGOF2,%fp1     | ...GET K*LOG2 WHILE FP0 IS NOT READY
        fmovex  %fp0,%fp2
        fmulx   %fp2,%fp2               | ...FP2 IS V=U*U
-       fmovex  %fp1,KLOG2(%a6) | ...PUT K*LOG2 IN MEMEORY, FREE FP1
+       fmovex  %fp1,KLOG2(%a6) | ...PUT K*LOG2 IN MEMORY, FREE FP1
 
 |--LOG(1+U) IS APPROXIMATED BY
 |--U + V*(A1+U*(A2+U*(A3+U*(A4+U*(A5+U*A6))))) WHICH IS
index 5c0c1dd5fd5be51341f5ae3cd6242621e2db1a39..978941f4e97dc269a155518aba00e8b7e53d83a7 100644 (file)
@@ -9,7 +9,7 @@
 |      Input: Double-extended number X in location pointed to
 |              by address register a0.
 |
-|      Output: The funtion value sin(X) or cos(X) returned in Fp0 if SIN or
+|      Output: The function value sin(X) or cos(X) returned in Fp0 if SIN or
 |              COS is requested. Otherwise, for SINCOS, sin(X) is returned
 |              in Fp0, and cos(X) is returned in Fp1.
 |
@@ -32,7 +32,7 @@
 |      2. If |X| >= 15Pi or |X| < 2**(-40), go to 7.
 |
 |      3. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let
-|              k = N mod 4, so in particular, k = 0,1,2,or 3. Overwirte
+|              k = N mod 4, so in particular, k = 0,1,2,or 3. Overwrite
 |              k by k := k + AdjN.
 |
 |      4. If k is even, go to 6.
@@ -409,7 +409,7 @@ red_neg:
 
 |--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4.
 |--integer quotient will be stored in N
-|--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1)
+|--Intermediate remainder is 66-bit long; (R,r) in (FP0,FP1)
 
 LOOP:
        fmovex          %fp0,INARG(%a6) | ...+-2**K * F, 1 <= F < 2
index d0729140f683964f29821b4e506510b0b76cddb3..b7a880a2a0e3628535098016d7fc839fe67f6023 100644 (file)
@@ -299,7 +299,7 @@ TANSM:
 
        fmovex          %fp0,-(%sp)
        fmovel          %d1,%fpcr                |restore users exceptions
-       fmovex          (%sp)+,%fp0     |last inst - posibble exception set
+       fmovex          (%sp)+,%fp0     |last inst - possible exception set
 
        bra             t_frcinx
 
@@ -340,7 +340,7 @@ red_neg:
 
 |--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4.
 |--integer quotient will be stored in N
-|--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1)
+|--Intermediate remainder is 66-bit long; (R,r) in (FP0,FP1)
 
 LOOP:
        fmovex          %fp0,INARG(%a6) | ...+-2**K * F, 1 <= F < 2
index 4db8126a28f719fd0b1d44f8152a7219ffdf6b6e..b80bef99e655997a14a2c4f54bb4bdc6f87c4eb9 100644 (file)
@@ -3,7 +3,7 @@
 |
 | Modified:
 |      8/16/90 chinds  The table was constructed to use only one level
-|                      of indirection in do_func for monoadic
+|                      of indirection in do_func for monadic
 |                      functions.  Dyadic functions require two
 |                      levels, and the tables are still contained
 |                      in do_func.  The table is arranged for 
index a73baeaff63694bf09e704cdff9ea27915a60946..e59b352ab7dc5a3eca1716027ffdd4e1819dff74 100644 (file)
@@ -256,7 +256,7 @@ SGL_RN:
        bsetb   #inf_bit,FPSR_CC(%a6)
        bras    set_sign
 SGL_RZ:
-       leal    SGL_PLRG,%a1    |anwer is +/- large number
+       leal    SGL_PLRG,%a1    |answer is +/- large number
        bras    set_sign
 SGL_RM:
        tstb    LOCAL_SGN(%a0)  |if negative overflow
@@ -276,7 +276,7 @@ s_rp_neg:
        bsetb   #neg_bit,FPSR_CC(%a6)
        bras    end_ovfr
 s_rp_pos:
-       leal    EXT_PINF,%a1    |answer is postive infinity
+       leal    EXT_PINF,%a1    |answer is positive infinity
        bsetb   #inf_bit,FPSR_CC(%a6)
        bras    end_ovfr
 
index e13cb7ced0a9f206f5b4c068c34b5a00c17a3173..42faf9bf08f6fc9c656d2768d9e604589c3c26f1 100644 (file)
@@ -3,7 +3,7 @@
 |
 |      fpsp_bsun --- FPSP handler for branch/set on unordered exception
 |
-|      Copy the PC to FPIAR to maintain 881/882 compatability
+|      Copy the PC to FPIAR to maintain 881/882 compatibility
 |
 |      The real_bsun handler will need to perform further corrective
 |      measures as outlined in the 040 User's Manual on pages
index cfe0621bd7ef293cc10785fb3eac53d2c49745c6..99d1a843052b7e622d16e559d959a40d7f8aaf37 100644 (file)
@@ -25,7 +25,7 @@
 |
 |                      where exp = (true exp) - 1
 |
-|  So, wbtemp and fptemp will contain the following on erroneoulsy
+|  So, wbtemp and fptemp will contain the following on erroneously
 |        signalled operr:
 |                      fpts = 1
 |                      fpte = $4000  (15 bit externally)
@@ -321,7 +321,7 @@ not_enabled:
 |
 | It is possible to have either inex2 or inex1 exceptions with the
 | operr.  If the inex enable bit is set in the FPCR, and either
-| inex2 or inex1 occured, we must clean up and branch to the
+| inex2 or inex1 occurred, we must clean up and branch to the
 | real inex handler.
 |
 ck_inex:
index f0818a2c561399f245786f4f7c7929fab1ca1ec2..e311508cac7d6828f32999d41de95e47645dc8e9 100644 (file)
@@ -92,7 +92,7 @@ no_e3_1:
 |
 | It is possible to have either inex2 or inex1 exceptions with the
 | ovfl.  If the inex enable bit is set in the FPCR, and either
-| inex2 or inex1 occured, we must clean up and branch to the
+| inex2 or inex1 occurred, we must clean up and branch to the
 | real inex handler.
 |
 ck_inex:
index cc73c848e523e5636a1eacf4fc91a9bdc2be8082..aaba75c1803dd7995313c43c3cbc6f7f9af1c3f4 100644 (file)
@@ -57,7 +57,7 @@ fpsp_snan:
 |
 | It is possible to have an inex1 exception with the
 | snan.  If the inex enable bit is set in the FPCR, and either
-| inex2 or inex1 occured, we must clean up and branch to the
+| inex2 or inex1 occurred, we must clean up and branch to the
 | real inex handler.
 |
 ck_inex:
index 782acb28cbf231145408a41cc67e10a306678d31..a3468f3386e98bd7ce62749dc481a49e55285771 100644 (file)
@@ -138,7 +138,7 @@ dest_dbl:
        swap    %d0             |d0 now in upper word
        lsll    #4,%d0          |d0 now in proper place for dbl prec exp
        tstb    LOCAL_SGN(%a1)  
-       beqs    get_mant        |if postive, go process mantissa
+       beqs    get_mant        |if positive, go process mantissa
        bsetl   #31,%d0         |if negative, put in sign information
 |                              ; before continuing
        bras    get_mant        |go process mantissa
index b3acda0edecabae1af56ad3b80c99805bb2321e5..f9bd1d0d6493718afdf285b30d76dc22915819c2 100644 (file)
@@ -9,7 +9,7 @@
 | by taking the intermediate result (which is always normalized) and 
 | shifting the mantissa right while incrementing the exponent until 
 | it is equal to the denormalized exponent for the destination 
-| format.  After denormalizatoin, the result is rounded to the 
+| format.  After denormalization, the result is rounded to the 
 | destination format.
 |              
 | Trap enabled results
@@ -80,7 +80,7 @@ no_e3_1:
 |
 | It is possible to have either inex2 or inex1 exceptions with the
 | unfl.  If the inex enable bit is set in the FPCR, and either
-| inex2 or inex1 occured, we must clean up and branch to the
+| inex2 or inex1 occurred, we must clean up and branch to the
 | real inex handler.
 |
 ck_inex:
index aa06cec29073a18099f3460c87cbc6f20e166a19..3a96b4b2060fb9dacfd4feb049a082c5df73aae2 100644 (file)
@@ -45,7 +45,7 @@ converted to other assembly syntaxes by using any word processor
 with a global search and replace function.
 
 To assist in assembling and linking these modules with other modules,
-the instaler should add symbolic labels to the top of the files.
+the installer should add symbolic labels to the top of the files.
 This will allow the calling routines to access the entry points
 of these packages.
 
@@ -159,7 +159,7 @@ FP unimplemented: tests FP unimplemented exception. this one is
 FP enabled: tests enabled snan/operr/ovfl/unfl/dz/inex.
            basically, it enables each of these exceptions and forces
            each using an implemented FP instruction. this process
-           exercizes _fpsp_{snan,operr,ovfl,unfl,dz,inex}() and
+           exercises _fpsp_{snan,operr,ovfl,unfl,dz,inex}() and
            _real_{snan,operr,ovfl,unfl,dz,inex}(). the test expects
            _real_XXXX() to do nothing except clear the exception
            and "rte". if a system's _real_XXXX() handler creates an
index 96878dd6fe0bb831a0d293eeb4b661d150924ddc..1a66c16c4ed6cb00dc2e04180154362773d0dc5d 100644 (file)
@@ -254,7 +254,7 @@ _060_fpsp_fline:
             |
             |----> may exit through _060_real_trap
             |
-            |----> may exit thorugh _060_real_bsun
+            |----> may exit through _060_real_bsun
             |
             |----> may exit through _060_fpsp_done
 
index a01de1c0649fcc92f59922670d27652977bae9e4..a355e2904bf3bf82d720f6d6d1fbf00256b52170 100644 (file)
@@ -71,7 +71,7 @@ _060_isp_done:
 | This is an alternate exit point for the Unimplemented Integer
 | Instruction exception handler. If the instruction was a "chk2"
 | and the operand was out of bounds, then _isp_unimp() creates
-| a CHK exception stack frame from the Unimplemented Integer Instrcution
+| a CHK exception stack frame from the Unimplemented Integer Instruction
 | stack frame and branches to this routine.
 |
        .global         _060_real_chk
index 47774ecad669742b9f11d21929ef4ec87111cea6..d922a14a968e263613b62d1f45a2bde8c2977666 100644 (file)
@@ -1561,7 +1561,7 @@ static int con_write(struct tty_struct * tty, int from_user,
                            where we really draw the chars */
 
                         if (count > 2 &&
-                           !decim && currcons == fg_console) { 
+                           !decim && !utf && currcons == fg_console) { 
                                static char putcs_buf[256];
                                char   *p     = putcs_buf;
                                int putcs_count  = 1;
@@ -1582,14 +1582,25 @@ static int con_write(struct tty_struct * tty, int from_user,
                                
                                while (count)
                                {
+                                       enable_bh(CONSOLE_BH);
                                        c = from_user ? get_user(buf) : *buf;
+                                       disable_bh(CONSOLE_BH);
                                        tc = translate[toggle_meta ? (c|0x80) : c];
                                        if (!tc ||
                                            !(c >= 32
-                                             || (disp_ctrl && c != 0x1b)
-                                             || !((CTRL_ACTION >> c) & 1)))
+                                             || !(((disp_ctrl ? CTRL_ALWAYS
+                                                  : CTRL_ACTION) >> c) & 1)))
                                          break;
+                                       tc = conv_uni_to_pc(tc);
+                                       if (tc == -4)
+                                         tc = conv_uni_to_pc(0xfffd);
+                                       else if (tc == -3)
+                                         tc = c;
+
                                        buf++; n++; count--;
+                                       if (tc & ~console_charmask)
+                                         continue; /* Conversion failed */
+
                                        *p++ = tc;
                                        *pos++ = tc | (attr << 8);
                                        ++putcs_count;
index 26e76f6101c5a29dc422f42bbbd608439709211e..58f4e06fe4507488a0a69739a6ebc34b3023a717 100644 (file)
@@ -234,7 +234,6 @@ SYMBOL_NAME_LABEL(ret_from_exception)
        cmpl    %a0@(LTASK_COUNTER),%d0   | counter
        jeq     SYMBOL_NAME(reschedule)
 
-       .word   0xf4f8
        movel   %a0@(LTASK_BLOCKED),%d0
        movel   %d0,%d1                 | save blocked in d1 for sig handling
        notl    %d0
@@ -356,9 +355,6 @@ SYMBOL_NAME_LABEL(resume)
 
        /* offset of tss struct (processor state) from beginning
           of task struct */
-/*
-       movel   %sp@(8),%a1
-*/
        addl    %a1,%a0
 
        /* save sr */
index 75ce89a86b88c2dd77a0d2697c1ecaf9c53016ce..8c90db20918c53b77f6ce683fce5309e24502376 100644 (file)
@@ -313,7 +313,7 @@ ENTRY(_start)
         * on the 68040, pages used to hold mmu tables should
         * be initialized as noncachable; the '060 allows write-through.
         * Do this for the root table page (which also contains
-        * all pointer tables utilitized thus far) and the
+        * all pointer tables utilized thus far) and the
         * kernel page table.
         */
        lea     %pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0
@@ -469,9 +469,9 @@ Lnotami:    /* other machines specific mappings go here! */
    is done by writing to the byte at phys. 0x0. This should result
    in a bus error on all other machines.
 
-   ...should, but doesn't. The Atferburner040 for the Falcon has the
+   ...should, but doesn't. The Afterburner040 for the Falcon has the
    same behaviour (0x0..0x7 are no ROM shadow). So we have to do
-   another test to distinuish Medusa and AB040. This is a
+   another test to distinguish Medusa and AB040. This is a
    read attempt for 0x00ff82fe phys. that should bus error on a Falcon
    (+AB040), but is in the range where the Medusa always asserts DTACK.
 */
index 4ea117b6bf9eab91ac5e94256771b9062c72009b..4db18f142b7202975800f48816ef4d6163032b04 100644 (file)
@@ -20,7 +20,7 @@
 
 /*
  * sys_pipe() is the normal C calling standard for creating
- * a pipe. It's not the way unix tranditionally does this, though.
+ * a pipe. It's not the way unix traditionally does this, though.
  */
 asmlinkage int sys_pipe(unsigned long * fildes)
 {
index a67a8d14246e83a0e16ed3113b9838c8147b1bf8..97e010dbae8f5e5a39b2209f1dddf2cc8a4b7160 100644 (file)
@@ -261,7 +261,7 @@ static void do_040writeback (unsigned short ssw,
        /*
         * No special handling for the second writeback anymore.
         * It misinterpreted the misaligned status sometimes.
-        * This way an extra pgae-fault may be caused (Martin Apel).
+        * This way an extra page-fault may be caused (Martin Apel).
         */
 
        mmusr = probe040 (1, wbs & WBTM_040,  wba);
index 86304e7faea1fbf2265d067969ac1e48f3da79f6..dbdfa15160231c8b592166feb1275ad012a3925b 100644 (file)
@@ -448,7 +448,6 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
 void mem_init(unsigned long start_mem, unsigned long end_mem)
 {
        int codepages = 0;
-       int reservedpages = 0;
        int datapages = 0;
        unsigned long tmp;
        extern int _etext;
@@ -514,11 +513,10 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
                        free_page(tmp);
        }
        tmp = nr_free_pages << PAGE_SHIFT;
-       printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n",
+       printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n",
               tmp >> 10,
               high_memory >> 10,
               codepages << (PAGE_SHIFT-10),
-              reservedpages << (PAGE_SHIFT-10),
               datapages << (PAGE_SHIFT-10));
 }
 
index fb3e9eff91767920242ba38cf25259fed706d576..49aa454b96895c9586ca588175677353ad0867d1 100644 (file)
@@ -378,7 +378,7 @@ void cache_clear (unsigned long paddr, int len)
 {
     if (m68k_is040or060) {
        /* ++roman: There have been too many problems with the CINV, it seems
-        * to break the cache maintainance of DMAing drivers. I don't expect
+        * to break the cache maintenance of DMAing drivers. I don't expect
         * too much overhead by using CPUSH instead.
         */
        while (len > PAGE_SIZE) {
@@ -461,7 +461,7 @@ void cache_push (unsigned long paddr, int len)
                      "movec %/d0,%/cacr"
                      : : "i" (FLUSH_I)
                      : "d0");
-    }
+}
 
 void cache_push_v (unsigned long vaddr, int len)
 {
@@ -489,15 +489,44 @@ void cache_push_v (unsigned long vaddr, int len)
            pushv060(vaddr);
            len -= PAGE_SIZE;
            vaddr += PAGE_SIZE;
-           }
+       }
        if (len > 0) {
            pushv060(vaddr);
            if (((vaddr + len - 1) ^ vaddr) & PAGE_MASK) {
                /* a page boundary gets crossed at the end */
                pushv060(vaddr + len - 1);
-               }
            }
        }
+    }
+    /* 68030/68020 have no writeback cache; still need to clear icache. */
+    else /* 68030 or 68020 */
+       asm volatile ("movec %/cacr,%/d0\n\t"
+                     "oriw %0,%/d0\n\t"
+                     "movec %/d0,%/cacr"
+                     : : "i" (FLUSH_I)
+                     : "d0");
+}
+
+void flush_cache_all(void)
+{
+    if (m68k_is040or060 >= 4)
+        __asm__ __volatile__ (".word 0xf478\n" ::);
+    else /* 68030 or 68020 */
+       asm volatile ("movec %/cacr,%/d0\n\t"
+                     "oriw %0,%/d0\n\t"
+                     "movec %/d0,%/cacr"
+                     : : "i" (FLUSH_I)
+                     : "d0");
+}
+
+void flush_page_to_ram (unsigned long addr)
+{
+    if (m68k_is040or060 == 4)
+        pushv040(addr);
+
+    else if (m68k_is040or060 == 6)
+        push040(VTOP(addr)); /* someone mentioned that pushv060 doesn't work */
+
     /* 68030/68020 have no writeback cache; still need to clear icache. */
     else /* 68030 or 68020 */
        asm volatile ("movec %/cacr,%/d0\n\t"
index 046b276431a6ba479ee1ce572c400c96c41f8db1..ab350859193d8a8fd543d8e56ba8b8fd802cd30a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: bare.S,v 1.3 1995/11/27 02:42:50 davem Exp $
+/* $Id: bare.S,v 1.4 1996/04/23 01:53:40 davem Exp $
  * base.S:      Ugly low-level boot program entry code.  The job of this
  *              module is to parse the boot flags, try to mount the remote
  *              root filesystem and load the kernel into virtual memory.
index aaa16f57785d0e9c1bd8477cfffaca603aac418d..e13b8c80aa06b70c45e59a0bc7b13e6c61f363bb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: empirical.h,v 1.1 1996/04/21 10:17:46 davem Exp $
+/* $Id: empirical.h,v 1.2 1996/04/23 01:53:42 davem Exp $
  * empirical.h:  Nasty hacks....
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 0d5d042b9601c81faa188b0c2eb125931fafa06b..9829bbb17ad58e8068a387a2ff142a5c81dcad9a 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.9 1996/04/04 16:30:03 tridge Exp $
+# $Id: config.in,v 1.12 1996/04/24 03:15:38 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -12,6 +12,7 @@ bool 'Support for AP1000 multicomputer' CONFIG_AP1000
 if [ "$CONFIG_AP1000" = "n" ]; then
        # Global things across all Sun machines.
        define_bool CONFIG_SBUS y
+       define_bool CONFIG_SBUSCHAR y
        define_bool CONFIG_SUN_MOUSE y
        define_bool CONFIG_SERIAL y
        define_bool CONFIG_SUN_SERIAL y
@@ -30,7 +31,23 @@ bool 'System V IPC' CONFIG_SYSVIPC
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 endmenu
 
-source drivers/block/Config.in
+mainmenu_option next_comment
+comment 'Floppy, IDE, and other block devices'
+
+tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD
+
+bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
+if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
+  tristate '   Linear (append) mode' CONFIG_MD_LINEAR
+  tristate '   RAID-0 (striping) mode' CONFIG_MD_STRIPED
+fi
+
+tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
+if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
+  bool '   Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
+fi
+
+tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
 
 if [ "$CONFIG_NET" = "y" ]; then
        source net/Config.in
@@ -42,7 +59,23 @@ comment 'SCSI support'
 tristate 'SCSI support' CONFIG_SCSI
 
 if [ "$CONFIG_SCSI" != "n" ]; then
-       source drivers/scsi/Config.in
+       comment 'SCSI support type (disk, tape, CDrom)'
+
+       dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
+       dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
+       dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
+       dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
+
+       comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
+
+       bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
+
+       bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
+
+       mainmenu_option next_comment
+       comment 'SCSI low-level drivers'
+
+       dep_tristate 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
 fi
 endmenu
 
@@ -52,7 +85,17 @@ if [ "$CONFIG_NET" = "y" ]; then
 
        bool 'Network device support' CONFIG_NETDEVICES
        if [ "$CONFIG_NETDEVICES" = "y" ]; then
-               source drivers/net/Config.in
+               tristate 'Dummy net driver support' CONFIG_DUMMY
+               tristate 'SLIP (serial line) support' CONFIG_SLIP
+               if [ "$CONFIG_SLIP" != "n" ]; then
+                 bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
+                 bool ' Keepalive and linefill' CONFIG_SLIP_SMART
+               fi
+               tristate 'PPP (point-to-point) support' CONFIG_PPP
+               if [ ! "$CONFIG_PPP" = "n" ]; then
+                 comment 'CCP compressors for PPP are only built as modules.'
+               fi
+               bool 'Sun LANCE support' CONFIG_SUNLANCE
        fi
        endmenu
 fi
index e6f2b3ccd7ae649f65f037942041197f2c506112..df03b88d6f576ef6bfe50d22a26578435c6a4cee 100644 (file)
@@ -7,6 +7,7 @@
 #
 # CONFIG_AP1000 is not set
 CONFIG_SBUS=y
+CONFIG_SBUSCHAR=y
 CONFIG_SUN_MOUSE=y
 CONFIG_SERIAL=y
 CONFIG_SUN_SERIAL=y
@@ -23,7 +24,8 @@ CONFIG_BINFMT_ELF=y
 #
 # Floppy, IDE, and other block devices
 #
-# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
 # CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_BLK_DEV_LOOP is not set
@@ -32,6 +34,7 @@ CONFIG_BLK_DEV_RAM=y
 # Networking options
 #
 # CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
 CONFIG_INET=y
 # CONFIG_IP_FORWARD is not set
 # CONFIG_IP_MULTICAST is not set
@@ -74,7 +77,6 @@ CONFIG_BLK_DEV_SR=y
 #
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
-# CONFIG_SCSI_AUTO_BIOSP is not set
 
 #
 # SCSI low-level drivers
@@ -111,6 +113,8 @@ CONFIG_RNFS_RARP=y
 CONFIG_ISO9660_FS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_UFS_FS=y
 
 #
 # Kernel hacking
index 41de109291b053f454407309de4a62de0d3a3227..0078fcb1ad4d3a1c81b43b19f7fef2c707f6f312 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.29 1996/04/04 16:30:17 tridge Exp $
+# $Id: Makefile,v 1.30 1996/04/22 10:37:53 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -35,7 +35,7 @@ O_OBJS   := entry.o wof.o wuf.o etrap.o rtrap.o switch.o traps.o ${IRQ_OBJS} \
            process.o signal.o ioport.o setup.o idprom.o \
            sys_sparc.o sunos_asm.o sparc-stub.o systbls.o sys_sunos.o  \
            sunos_ioctl.o time.o windows.o cpu.o devices.o ksyms.o \
-           sclow.o solaris.o tadpole.o tick14.o
+           sclow.o solaris.o tadpole.o tick14.o ptrace.o
 
 ifdef SMP
 O_OBJS += trampoline.o smp.o rirq.o
index 2028470c9c6cf7b043086147f322983f4f5ac163..758b73a7372f9f01f66b43f725264848e3519e66 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.90 1996/04/18 01:00:37 davem Exp $
+/* $Id: entry.S,v 1.93 1996/04/25 06:08:32 davem Exp $
  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -990,15 +990,27 @@ C_LABEL(sunos_indir):
        jmp     %l5 + 0x8               /* so stupid... */
         nop
 
-#if 0 /* work in progress */
+       /* Note how we really return to ret_syscall because we share the
+        * register window with our caller.
+        */
+
        .align 4
        .globl  C_LABEL(sys_ptrace)
 C_LABEL(sys_ptrace):
        call    C_LABEL(do_ptrace)
         add    %sp, REGWIN_SZ, %o0
 
+       LOAD_CURRENT(l4, l5)
+       ld      [%l4 + 0x14], %l5
+       andcc   %l5, 0x20, %g0
+       be      1f
+        nop
+
+       call    C_LABEL(syscall_trace)
+        nop
+
+1:
        RESTORE_ALL
-#endif
 
        .align  4
        .globl  C_LABEL(sys_execve)
@@ -1028,6 +1040,16 @@ C_LABEL(sys_sigpause):
        call    C_LABEL(do_sigpause)
         add    %sp, REGWIN_SZ, %o1
 
+       LOAD_CURRENT(l4, l5)
+       ld      [%l4 + 0x14], %l5
+       andcc   %l5, 0x20, %g0
+       be      1f
+        nop
+
+       call    C_LABEL(syscall_trace)
+        nop
+
+1:
        /* We are returning to a signal handler. */
        RESTORE_ALL
 
@@ -1037,6 +1059,16 @@ C_LABEL(sys_sigsuspend):
        call    C_LABEL(do_sigsuspend)
         add    %sp, REGWIN_SZ, %o0
 
+       LOAD_CURRENT(l4, l5)
+       ld      [%l4 + 0x14], %l5
+       andcc   %l5, 0x20, %g0
+       be      1f
+        nop
+
+       call    C_LABEL(syscall_trace)
+        nop
+
+1:
        /* We are returning to a signal handler. */
        RESTORE_ALL
 
@@ -1046,6 +1078,16 @@ C_LABEL(sys_sigreturn):
        call    C_LABEL(do_sigreturn)
         add    %sp, REGWIN_SZ, %o0
 
+       LOAD_CURRENT(l4, l5)
+       ld      [%l4 + 0x14], %l5
+       andcc   %l5, 0x20, %g0
+       be      1f
+        nop
+
+       call    C_LABEL(syscall_trace)
+        nop
+
+1:
        /* We don't want to muck with user registers like a
         * normal syscall, just return.
         */
@@ -1153,6 +1195,15 @@ syscall_is_too_hard:
        wr      %l0, PSR_ET, %psr
        WRITE_PAUSE
 
+       LOAD_CURRENT(l4, l5)
+       ld      [%l4 + 0x14], %l5
+       andcc   %l5, 0x20, %g0
+       be      2f
+        nop
+
+       call    C_LABEL(syscall_trace)
+        nop
+
 2:
        ldd     [%sp + REGWIN_SZ + PT_I0], %o0
        st      %o0, [%sp + REGWIN_SZ + PT_G0]  ! for restarting syscalls
@@ -1184,8 +1235,18 @@ C_LABEL(ret_sys_call):
        or      %l5, %l6, %l5
        st      %l5, [%sp + REGWIN_SZ + PT_PSR]
 
-       /* Advance the pc and npc over the trap instruction. */
 2:
+       LOAD_CURRENT(l4, l5)
+       ld      [%l4 + 0x14], %l5
+       andcc   %l5, 0x20, %g0
+       be      3f
+        nop
+
+       call    C_LABEL(syscall_trace)
+        nop
+
+       /* Advance the pc and npc over the trap instruction. */
+3:
        ld      [%sp + REGWIN_SZ + PT_NPC], %l1 /* pc  = npc   */
        add     %l1, 0x4, %l2                   /* npc = npc+4 */
        st      %l1, [%sp + REGWIN_SZ + PT_PC]
index 71928330fca5b034def42fe708a058fa37131493..43494a5562517cc0fdb7d097e470dffba1a7361f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.17 1996/03/07 06:26:43 davem Exp $
+/* $Id: etrap.S,v 1.18 1996/04/25 06:08:35 davem Exp $
  * etrap.S: Sparc trap window preparation for entry into the
  *          Linux kernel.
  *
index b57190b28f4393a55a2abb7c2e2ef98b566d1317..c6cffe4258b7446ff60e10621c335b37504de2aa 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.56 1996/04/04 16:30:22 tridge Exp $
+/* $Id: head.S,v 1.57 1996/04/25 06:08:38 davem Exp $
  * head.S: The initial boot code for the Sparc port of Linux.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 5c6b63a48b6644779100fa9f6cd7a2d68bbeb3ff..cc7c085cee0fda97b553b03d6a090af17fce2a41 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: idprom.c,v 1.18 1995/11/25 00:58:05 davem Exp $
+/* $Id: idprom.c,v 1.19 1996/04/25 06:08:41 davem Exp $
  * idprom.c: Routines to load the idprom into kernel addresses and
  *           interpret the data contained within.
  *
index 93ae2ffa53b0414707ea81c6d592e12378cbcf2e..cb2990d1840b1e67983ccf5db148d7f3d424e36f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.17 1996/03/23 02:39:13 davem Exp $
+/* $Id: ioport.c,v 1.18 1996/04/25 06:08:44 davem Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index a00f93831562c6f0f608ca6ae9eae0012a9fb352..edf500152b2df8fc1382ea9d8fc3ee6145b291ae 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.43 1996/04/17 12:37:45 zaitcev Exp $
+/*  $Id: irq.c,v 1.44 1996/04/25 06:08:46 davem Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
index 26b2dd02204ba57f2e6a6129934dbf4945e840b5..cee3e95b31eb87668658ffe99ad34a7b7eed0956 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.49 1996/04/20 07:37:20 davem Exp $
+/*  $Id: process.c,v 1.51 1996/04/25 06:08:49 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -78,12 +78,9 @@ int cpu_idle(void *unused)
        volatile int *spap = &smp_process_available;
        volatile int cval;
 
-       current->priority = -50;
        while(1) {
                 if(0==read_smp_counter(spap))
                        continue;
-               while(*spap == -1)
-                       ;
                cli();
                /* Acquire exclusive access. */
                while((cval = smp_swap(spap, -1)) == -1)
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
new file mode 100644 (file)
index 0000000..ceb464a
--- /dev/null
@@ -0,0 +1,801 @@
+/* ptrace.c: Sparc process tracing support.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
+ *
+ * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
+ * and David Mosberger.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+/* change a pid into a task struct. */
+static inline struct task_struct * get_task(int pid)
+{
+       int i;
+
+       for (i = 1; i < NR_TASKS; i++) {
+               if (task[i] != NULL && (task[i]->pid == pid))
+                       return task[i];
+       }
+       return NULL;
+}
+
+/*
+ * This routine gets a long from any process space by following the page
+ * tables. NOTE! You should check that the long isn't on a page boundary,
+ * and that it is in the task area before calling this: this routine does
+ * no checking.
+ */
+static unsigned long get_long(struct task_struct * tsk,
+       struct vm_area_struct * vma, unsigned long addr)
+{
+       pgd_t * pgdir;
+       pmd_t * pgmiddle;
+       pte_t * pgtable;
+       unsigned long page, retval;
+
+repeat:
+       pgdir = pgd_offset(vma->vm_mm, addr);
+       if (pgd_none(*pgdir)) {
+               do_no_page(tsk, vma, addr, 0);
+               goto repeat;
+       }
+       if (pgd_bad(*pgdir)) {
+               printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+               pgd_clear(pgdir);
+               return 0;
+       }
+       pgmiddle = pmd_offset(pgdir, addr);
+       if (pmd_none(*pgmiddle)) {
+               do_no_page(tsk, vma, addr, 0);
+               goto repeat;
+       }
+       if (pmd_bad(*pgmiddle)) {
+               printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
+               pmd_clear(pgmiddle);
+               return 0;
+       }
+       pgtable = pte_offset(pgmiddle, addr);
+       if (!pte_present(*pgtable)) {
+               do_no_page(tsk, vma, addr, 0);
+               goto repeat;
+       }
+       page = pte_page(*pgtable);
+/* this is a hack for non-kernel-mapped video buffers and similar */
+       if (page >= high_memory)
+               return 0;
+       page += addr & ~PAGE_MASK;
+       retval = *(unsigned long *) page;
+       flush_page_to_ram(page);
+       return retval;
+}
+
+/*
+ * This routine puts a long into any process space by following the page
+ * tables. NOTE! You should check that the long isn't on a page boundary,
+ * and that it is in the task area before calling this: this routine does
+ * no checking.
+ *
+ * Now keeps R/W state of page so that a text page stays readonly
+ * even if a debugger scribbles breakpoints into it.  -M.U-
+ */
+static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
+       unsigned long addr, unsigned long data)
+{
+       pgd_t *pgdir;
+       pmd_t *pgmiddle;
+       pte_t *pgtable;
+       unsigned long page;
+
+repeat:
+       pgdir = pgd_offset(vma->vm_mm, addr);
+       if (!pgd_present(*pgdir)) {
+               do_no_page(tsk, vma, addr, 1);
+               goto repeat;
+       }
+       if (pgd_bad(*pgdir)) {
+               printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+               pgd_clear(pgdir);
+               return;
+       }
+       pgmiddle = pmd_offset(pgdir, addr);
+       if (pmd_none(*pgmiddle)) {
+               do_no_page(tsk, vma, addr, 1);
+               goto repeat;
+       }
+       if (pmd_bad(*pgmiddle)) {
+               printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
+               pmd_clear(pgmiddle);
+               return;
+       }
+       pgtable = pte_offset(pgmiddle, addr);
+       if (!pte_present(*pgtable)) {
+               do_no_page(tsk, vma, addr, 1);
+               goto repeat;
+       }
+       page = pte_page(*pgtable);
+       if (!pte_write(*pgtable)) {
+               do_wp_page(tsk, vma, addr, 1);
+               goto repeat;
+       }
+/* this is a hack for non-kernel-mapped video buffers and similar */
+       flush_cache_page(vma, page);
+       if (page < high_memory) {
+               *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
+               flush_page_to_ram(page);
+       }
+/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
+/* this should also re-instate whatever read-only mode there was before */
+       set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
+       flush_tlb_page(vma, page);
+}
+
+static struct vm_area_struct * find_extend_vma(struct task_struct * tsk,
+                                              unsigned long addr)
+{
+       struct vm_area_struct * vma;
+
+       addr &= PAGE_MASK;
+       vma = find_vma(tsk,addr);
+       if (!vma)
+               return NULL;
+       if (vma->vm_start <= addr)
+               return vma;
+       if (!(vma->vm_flags & VM_GROWSDOWN))
+               return NULL;
+       if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
+               return NULL;
+       vma->vm_offset -= vma->vm_start - addr;
+       vma->vm_start = addr;
+       return vma;
+}
+
+/*
+ * This routine checks the page boundaries, and that the offset is
+ * within the task area. It then calls get_long() to read a long.
+ */
+static int read_long(struct task_struct * tsk, unsigned long addr,
+                    unsigned long * result)
+{
+       struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+
+       if (!vma)
+               return -EIO;
+       *result = get_long(tsk, vma, addr);
+       return 0;
+}
+
+static int read_byte(struct task_struct *tsk, unsigned long addr,
+                    unsigned char *result)
+{
+       struct vm_area_struct *vma = find_extend_vma(tsk, addr&~3);
+       unsigned long tmp;
+
+       if(!vma)
+               return -EIO;
+       tmp = get_long(tsk, vma, (addr & ~3));
+       switch(addr & 3) {
+       case 0:
+               *result = (tmp & 0xff000000)>>24;
+               break;
+       case 1:
+               *result = (tmp & 0x00ff0000)>>16;
+               break;
+       case 2:
+               *result = (tmp & 0x0000ff00)>>8;
+               break;
+       case 3:
+               *result = (tmp & 0x000000ff);
+               break;
+       }
+       return 0;
+}
+
+/*
+ * This routine checks the page boundaries, and that the offset is
+ * within the task area. It then calls put_long() to write a long.
+ */
+static int write_long(struct task_struct * tsk, unsigned long addr,
+                     unsigned long data)
+{
+       struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+
+       if (!vma)
+               return -EIO;
+       put_long(tsk, vma, addr, data);
+       return 0;
+}
+
+static int write_byte(struct task_struct * tsk, unsigned long addr,
+                     unsigned char data)
+{
+       struct vm_area_struct * vma = find_extend_vma(tsk, (addr & ~3));
+       unsigned long tmp;
+
+       if (!vma)
+               return -EIO;
+       tmp = get_long(tsk, vma, (addr & ~3));
+       switch(addr & 3) {
+       case 0:
+               tmp &= 0x00ffffff;
+               tmp |= (data << 24);
+               break;
+       case 1:
+               tmp &= 0xff00ffff;
+               tmp |= ((data << 16) & 0x00ff0000);
+               break;
+       case 2:
+               tmp &= 0xffff00ff;
+               tmp |= ((data << 8) & 0x0000ff00);
+               break;
+       case 3:
+               tmp &= 0xffffff00;
+               tmp |= (data & 0x000000ff);
+               break;
+       }
+       put_long(tsk, vma, (addr & ~3), tmp);
+       return 0;
+}
+
+/* Returning from ptrace is a bit tricky because the syscall return
+ * low level code assumes any value returned which is negative and
+ * is a valid errno will mean setting the condition codes to indicate
+ * an error return.  This doesn't work, so we have this hook.
+ */
+static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
+{
+       regs->u_regs[UREG_I0] = error;
+       regs->psr |= PSR_C;
+       regs->pc = regs->npc;
+       regs->npc += 4;
+}
+
+static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
+{
+       regs->u_regs[UREG_I0] = value;
+       regs->psr &= ~PSR_C;
+       regs->pc = regs->npc;
+       regs->npc += 4;
+}
+
+/* Fuck me gently with a chainsaw... */
+static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
+                                  struct task_struct *tsk)
+{
+       struct pt_regs *cregs = tsk->tss.kregs;
+       struct thread_struct *t = &tsk->tss;
+
+       if(offset >= 1024)
+               offset -= 1024; /* whee... */
+       if(offset & ((sizeof(unsigned long) - 1))) {
+               pt_error_return(regs, EIO);
+               return;
+       }
+       if(offset >= 16 && offset < 784) {
+               offset -= 16; offset >>= 2;
+               pt_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset)); 
+               return;
+       }
+       if(offset >= 784 && offset < 832) {
+               offset -= 784; offset >>= 2;
+               pt_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset));
+               return;
+       }
+       switch(offset) {
+       case 0:
+               regs->u_regs[UREG_I0] = t->ksp;
+               break;
+       case 4:
+               regs->u_regs[UREG_I0] = t->kpc;
+               break;
+       case 8:
+               regs->u_regs[UREG_I0] = t->kpsr;
+               break;
+       case 12:
+               regs->u_regs[UREG_I0] = t->uwinmask;
+               break;
+       case 832:
+               regs->u_regs[UREG_I0] = t->w_saved;
+               break;
+       case 896:
+               regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I0];
+               break;
+       case 900:
+               regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I1];
+               break;
+       case 904:
+               regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I2];
+               break;
+       case 908:
+               regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I3];
+               break;
+       case 912:
+               regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I4];
+               break;
+       case 916:
+               regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I5];
+               break;
+       case 920:
+               regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I6];
+               break;
+       case 924:
+               if(tsk->tss.flags & 0x80000000)
+                       regs->u_regs[UREG_I0] = cregs->u_regs[UREG_G1];
+               else
+                       regs->u_regs[UREG_I0] = 0;
+               break;
+       case 940:
+               regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I0];
+               break;
+       case 944:
+               regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I1];
+               break;
+
+       case 948:
+               /* Isn't binary compatability _fun_??? */
+               if(cregs->psr & PSR_C)
+                       regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I0] << 24;
+               else
+                       regs->u_regs[UREG_I0] = 0;
+               break;
+
+               /* Rest of them are completely unsupported. */
+       default:
+               printk("%s [%d]: Wants to read user offset %d\n",
+                      current->comm, current->pid, offset);
+               pt_error_return(regs, EIO);
+               return;
+       }
+       regs->psr &= ~PSR_C;
+       regs->pc = regs->npc;
+       regs->npc += 4;
+       return;
+}
+
+static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset,
+                                   struct task_struct *tsk)
+{
+       struct pt_regs *cregs = tsk->tss.kregs;
+       struct thread_struct *t = &tsk->tss;
+       unsigned long value = regs->u_regs[UREG_I3];
+
+       if(offset >= 1024)
+               offset -= 1024; /* whee... */
+       if(offset & ((sizeof(unsigned long) - 1)))
+               goto failure;
+       if(offset >= 16 && offset < 784) {
+               offset -= 16; offset >>= 2;
+               *(((unsigned long *)(&t->reg_window[0]))+offset) = value;
+               goto success;
+       }
+       if(offset >= 784 && offset < 832) {
+               offset -= 784; offset >>= 2;
+               *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
+               goto success;
+       }
+       switch(offset) {
+       case 896:
+               cregs->u_regs[UREG_I0] = value;
+               break;
+       case 900:
+               cregs->u_regs[UREG_I1] = value;
+               break;
+       case 904:
+               cregs->u_regs[UREG_I2] = value;
+               break;
+       case 908:
+               cregs->u_regs[UREG_I3] = value;
+               break;
+       case 912:
+               cregs->u_regs[UREG_I4] = value;
+               break;
+       case 916:
+               cregs->u_regs[UREG_I5] = value;
+               break;
+       case 920:
+               cregs->u_regs[UREG_I6] = value;
+               break;
+       case 924:
+               cregs->u_regs[UREG_I7] = value;
+               break;
+       case 940:
+               cregs->u_regs[UREG_I0] = value;
+               break;
+       case 944:
+               cregs->u_regs[UREG_I1] = value;
+               break;
+
+               /* Rest of them are completely unsupported or "no-touch". */
+       default:
+               printk("%s [%d]: Wants to write user offset %d\n",
+                      current->comm, current->pid, offset);
+               goto failure;
+       }
+success:
+       pt_succ_return(regs, 0);
+       return;
+failure:
+       pt_error_return(regs, EIO);
+       return;
+}
+
+/* #define ALLOW_INIT_TRACING */
+/* #define DEBUG_PTRACE */
+
+asmlinkage void do_ptrace(struct pt_regs *regs)
+{
+       unsigned long request = regs->u_regs[UREG_I0];
+       unsigned long pid = regs->u_regs[UREG_I1];
+       unsigned long addr = regs->u_regs[UREG_I2];
+       unsigned long data = regs->u_regs[UREG_I3];
+       unsigned long addr2 = regs->u_regs[UREG_I4];
+       struct task_struct *child;
+
+#ifdef DEBUG_PTRACE
+       printk("do_ptrace: rq=%d pid=%d addr=%08lx data=%08lx addr2=%08lx\n",
+              (int) request, (int) pid, addr, data, addr2);
+#endif
+       if(request == PTRACE_TRACEME) {
+               /* are we already being traced? */
+               if (current->flags & PF_PTRACED) {
+                       pt_error_return(regs, EPERM);
+                       return;
+               }
+               /* set the ptrace bit in the process flags. */
+               current->flags |= PF_PTRACED;
+               pt_succ_return(regs, 0);
+               return;
+       }
+#ifndef ALLOW_INIT_TRACING
+       if(pid == 1) {
+               /* Can't dork with init. */
+               pt_error_return(regs, EPERM);
+               return;
+       }
+#endif
+       if(!(child = get_task(pid))) {
+               pt_error_return(regs, ESRCH);
+               return;
+       }
+
+       if(request == PTRACE_SUNATTACH) {
+               if(child == current) {
+                       /* Try this under SunOS/Solaris, bwa haha
+                        * You'll never be able to kill the process. ;-)
+                        */
+                       pt_error_return(regs, EPERM);
+                       return;
+               }
+               if((!child->dumpable ||
+                   (current->uid != child->euid) ||
+                   (current->uid != child->uid) ||
+                   (current->gid != child->egid) ||
+                   (current->gid != child->gid)) && !suser()) {
+                       pt_error_return(regs, EPERM);
+                       return;
+               }
+               /* the same process cannot be attached many times */
+               if (child->flags & PF_PTRACED) {
+                       pt_error_return(regs, EPERM);
+                       return;
+               }
+               child->flags |= PF_PTRACED;
+               if(child->p_pptr != current) {
+                       REMOVE_LINKS(child);
+                       child->p_pptr = current;
+                       SET_LINKS(child);
+               }
+               send_sig(SIGSTOP, child, 1);
+               pt_succ_return(regs, 0);
+               return;
+       }
+       if(!(child->flags & PF_PTRACED)) {
+               pt_error_return(regs, ESRCH);
+               return;
+       }
+       if(child->state != TASK_STOPPED) {
+               if(request != PTRACE_KILL) {
+                       pt_error_return(regs, ESRCH);
+                       return;
+               }
+       }
+       if(child->p_pptr != current) {
+               pt_error_return(regs, ESRCH);
+               return;
+       }
+       switch(request) {
+       case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+       case PTRACE_PEEKDATA: {
+               unsigned long tmp;
+               int res;
+
+               /* Non-word alignment _not_ allowed on Sparc. */
+               if(addr & (sizeof(unsigned long) - 1)) {
+                       pt_error_return(regs, EINVAL);
+                       return;
+               }
+               res = read_long(child, addr, &tmp);
+               if (res < 0) {
+                       pt_error_return(regs, -res);
+                       return;
+               }
+               pt_succ_return(regs, tmp);
+               return;
+       }
+
+       case PTRACE_PEEKUSR:
+               read_sunos_user(regs, addr, child);
+               return;
+
+       case PTRACE_POKEUSR:
+               write_sunos_user(regs, addr, child);
+               return;
+
+       case PTRACE_POKETEXT: /* write the word at location addr. */
+       case PTRACE_POKEDATA: {
+               struct vm_area_struct *vma;
+               int res;
+
+               /* Non-word alignment _not_ allowed on Sparc. */
+               if(addr & (sizeof(unsigned long) - 1)) {
+                       pt_error_return(regs, EINVAL);
+                       return;
+               }
+               vma = find_extend_vma(child, addr);
+               if(vma && request == PTRACE_POKEDATA && (vma->vm_flags & VM_EXEC)) {
+                       pt_error_return(regs, EIO);
+                       return;
+               }
+               res = write_long(child, addr, data);
+               if(res < 0)
+                       pt_error_return(regs, -res);
+               else
+                       pt_succ_return(regs, res);
+               return;
+       }
+
+       case PTRACE_GETREGS: {
+               struct pt_regs *pregs = (struct pt_regs *) addr;
+               struct pt_regs *cregs = child->tss.kregs;
+               int rval;
+
+               rval = verify_area(VERIFY_WRITE, pregs, sizeof(struct pt_regs) - 4);
+               if(rval) {
+                       pt_error_return(regs, rval);
+                       return;
+               }
+               pregs->psr = cregs->psr;
+               pregs->pc = cregs->pc;
+               pregs->npc = cregs->npc;
+               pregs->y = cregs->y;
+               for(rval = 1; rval < 16; rval++)
+                       pregs->u_regs[rval - 1] = cregs->u_regs[rval];
+               pt_succ_return(regs, 0);
+               return;
+       }
+
+       case PTRACE_SETREGS: {
+               struct pt_regs *pregs = (struct pt_regs *) addr;
+               struct pt_regs *cregs = child->tss.kregs;
+               unsigned long psr;
+               int rval, i;
+
+               rval = verify_area(VERIFY_READ, pregs, sizeof(struct pt_regs) - 4);
+               if(rval) {
+                       pt_error_return(regs, rval);
+                       return;
+               }
+               /* Must be careful, tracing process can only set certain
+                * bits in the psr.
+                */
+               psr = (pregs->psr) & PSR_ICC;
+               cregs->psr &= ~PSR_ICC;
+               cregs->psr |= psr;
+               if(!((pregs->pc | pregs->npc) & 3)) {
+                       cregs->pc = pregs->pc;
+                       cregs->npc = pregs->npc;
+               }
+               cregs->y = pregs->y;
+               for(i = 1; i < 16; i++)
+                       cregs->u_regs[i] = pregs->u_regs[i-1];
+               pt_succ_return(regs, 0);
+               return;
+       }
+
+       case PTRACE_GETFPREGS: {
+               struct fps {
+                       unsigned long regs[32];
+                       unsigned long fsr;
+                       unsigned long flags;
+                       unsigned long extra;
+                       unsigned long fpqd;
+                       struct fq {
+                               unsigned long *insnaddr;
+                               unsigned long insn;
+                       } fpq[16];
+               } *fps = (struct fps *) addr;
+               int rval, i;
+
+               rval = verify_area(VERIFY_WRITE, fps, sizeof(struct fps));
+               if(rval) { pt_error_return(regs, rval); return; }
+               for(i = 0; i < 32; i++)
+                       fps->regs[i] = child->tss.float_regs[i];
+               fps->fsr = child->tss.fsr;
+               fps->fpqd = child->tss.fpqdepth;
+               fps->flags = fps->extra = 0;
+               for(i = 0; i < 16; i++) {
+                       fps->fpq[i].insnaddr = child->tss.fpqueue[i].insn_addr;
+                       fps->fpq[i].insn = child->tss.fpqueue[i].insn;
+               }
+               pt_succ_return(regs, 0);
+               return;
+       }
+
+       case PTRACE_SETFPREGS: {
+               struct fps {
+                       unsigned long regs[32];
+                       unsigned long fsr;
+                       unsigned long flags;
+                       unsigned long extra;
+                       unsigned long fpqd;
+                       struct fq {
+                               unsigned long *insnaddr;
+                               unsigned long insn;
+                       } fpq[16];
+               } *fps = (struct fps *) addr;
+               int rval, i;
+
+               rval = verify_area(VERIFY_READ, fps, sizeof(struct fps));
+               if(rval) { pt_error_return(regs, rval); return; }
+               for(i = 0; i < 32; i++)
+                       child->tss.float_regs[i] = fps->regs[i];
+               child->tss.fsr = fps->fsr;
+               child->tss.fpqdepth = fps->fpqd;
+               for(i = 0; i < 16; i++) {
+                       child->tss.fpqueue[i].insn_addr = fps->fpq[i].insnaddr;
+                       child->tss.fpqueue[i].insn = fps->fpq[i].insn;
+               }
+               pt_succ_return(regs, 0);
+               return;
+       }
+
+       case PTRACE_READTEXT:
+       case PTRACE_READDATA: {
+               unsigned char *dest = (unsigned char *) addr2;
+               unsigned long src = addr;
+               unsigned char tmp;
+               int res, len = data;
+
+               res = verify_area(VERIFY_WRITE, (void *) dest, len);
+               if(res) {
+                       pt_error_return(regs, -res);
+                       return;
+               }
+               while(len) {
+                       res = read_byte(child, src, &tmp);
+                       if(res < 0) {
+                               pt_error_return(regs, -res);
+                               return;
+                       }
+                       *dest = tmp;
+                       src++; dest++; len--;
+               }
+               pt_succ_return(regs, 0);
+               return;
+       }
+
+       case PTRACE_WRITETEXT:
+       case PTRACE_WRITEDATA: {
+               unsigned char *src = (unsigned char *) addr2;
+               unsigned long dest = addr;
+               int res, len = data;
+
+               res = verify_area(VERIFY_READ, (void *) src, len);
+               if(res) {
+                       pt_error_return(regs, -res);
+                       return;
+               }
+               while(len) {
+                       res = write_byte(child, dest, *src);
+                       if(res < 0) {
+                               pt_error_return(regs, -res);
+                               return;
+                       }
+                       src++; dest++; len--;
+               }
+               pt_succ_return(regs, 0);
+               return;
+       }
+
+       case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
+               data = 0;
+               addr = 1;
+
+       case PTRACE_CONT: { /* restart after signal. */
+               if ((unsigned long) data > NSIG) {
+                       pt_error_return(regs, EIO);
+                       return;
+               }
+               if (request == PTRACE_SYSCALL)
+                       child->flags |= PF_TRACESYS;
+               else
+                       child->flags &= ~PF_TRACESYS;
+               child->exit_code = data;
+               if((addr != 1) & !(addr & 3)) {
+                       child->tss.kregs->pc = addr;
+                       child->tss.kregs->npc = addr + 4;
+               }
+               wake_up_process(child);
+               pt_succ_return(regs, 0);
+               return;
+       }
+
+/*
+ * make the child exit.  Best I can do is send it a sigkill. 
+ * perhaps it should be put in the status that it wants to 
+ * exit.
+ */
+       case PTRACE_KILL: {
+               if (child->state == TASK_ZOMBIE) {      /* already dead */
+                       pt_succ_return(regs, 0);
+                       return;
+               }
+               wake_up_process(child);
+               child->exit_code = SIGKILL;
+               pt_succ_return(regs, 0);
+               return;
+       }
+
+       case PTRACE_SUNDETACH: { /* detach a process that was attached. */
+               if ((unsigned long) data > NSIG) {
+                       pt_error_return(regs, EIO);
+                       return;
+               }
+               child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+               wake_up_process(child);
+               child->exit_code = data;
+               REMOVE_LINKS(child);
+               child->p_pptr = child->p_opptr;
+               SET_LINKS(child);
+               pt_succ_return(regs, 0);
+               return;
+       }
+
+       /* PTRACE_DUMPCORE unsupported... */
+
+       default:
+               pt_error_return(regs, EIO);
+               return;
+       }
+}
+
+asmlinkage void syscall_trace(void)
+{
+#ifdef DEBUG_PTRACE
+       printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
+#endif
+       if ((current->flags & (PF_PTRACED|PF_TRACESYS))
+                       != (PF_PTRACED|PF_TRACESYS))
+               return;
+       current->exit_code = SIGTRAP;
+       current->state = TASK_STOPPED;
+       current->tss.flags ^= 0x80000000;
+       notify_parent(current);
+       schedule();
+       /*
+        * this isn't the same as continuing with a signal, but it will do
+        * for normal use.  strace only continues with a signal if the
+        * stopping signal is not SIGTRAP.  -brl
+        */
+       if (current->exit_code)
+               current->signal |= (1 << (current->exit_code - 1));
+       current->exit_code = 0;
+}
index bf6fbc844f6169018fc9f71f39cca0f6df371ded..58200bb4d9de01537980ddf5760b20275fdccc3e 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.60 1996/04/04 16:30:28 tridge Exp $
+/*  $Id: setup.c,v 1.62 1996/04/25 09:11:33 davem Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
@@ -212,22 +212,13 @@ static struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } };
 void setup_arch(char **cmdline_p,
        unsigned long * memory_start_p, unsigned long * memory_end_p)
 {
-       int total, i, panic_stuff[2], packed;
+       int total, i, packed;
 
 #if CONFIG_AP1000
         register_console(prom_printf);
        ((char *)(&cputypval))[4] = 'm'; /* ugly :-( */
 #endif
 
-#if 0
-       /* Always reboot on panic, but give 5 seconds to hit L1-A
-        * and look at debugging info if desired.
-        */
-       panic_stuff[0] = 1;
-       panic_stuff[1] = 5;
-       panic_setup(0, panic_stuff);
-#endif
-
        sparc_ttable = (struct tt_entry *) &start;
 
        /* Initialize PROM console and command line. */
index 9f12ac964171532bde08ad9c86749e194e180766..8987d6cf7e255ba34472a5b838555c08ff5ace64 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.31 1996/04/18 01:00:41 davem Exp $
+/*  $Id: signal.c,v 1.32 1996/04/22 19:37:48 davem Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -232,6 +232,22 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
                clear_bit(signr, &current->signal);
                sa = current->sig->action + signr;
                signr++;
+               if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+                       current->exit_code = signr;
+                       current->state = TASK_STOPPED;
+                       notify_parent(current);
+                       schedule();
+                       if (!(signr = current->exit_code))
+                               continue;
+                       current->exit_code = 0;
+                       if (signr == SIGSTOP)
+                               continue;
+                       if (_S(signr) & current->blocked) {
+                               current->signal |= _S(signr);
+                               continue;
+                       }
+                       sa = current->sig->action + signr - 1;
+               }
                if(sa->sa_handler == SIG_IGN) {
                        if(signr != SIGCHLD)
                                continue;
index 60c538bb1ea8cd2e5307961b1970d8b7cfe95bf1..8a4d1604cdf432dc872bf1bb6b0d1d67c245b8e1 100644 (file)
@@ -93,7 +93,7 @@ char *smp_info(void)
        sprintf(smp_buf,
 "\n        CPU0\t\tCPU1\t\tCPU2\t\tCPU3\n"
 "State: %s\t\t%s\t\t%s\t\t%s\n"
-"Lock:  %08lx\t\t%08lx\t%08lx\t\t%08lx\n"
+"Lock:  %08lx\t\t%08lx\t%08lx\t%08lx\n"
 "\n"
 "klock: %x\n",
                (cpu_present_map & 1) ? ((active_kernel_processor == 0) ? "akp" : "online") : "offline",
@@ -236,7 +236,6 @@ void smp_boot_cpus(void)
                        /* whirrr, whirrr, whirrrrrrrrr... */
                        printk("Starting CPU %d at %p\n", i, entry);
                        mid_xlate[i] = (linux_cpus[i].mid & ~8);
-                       current_set[i] = &init_task;
                        local_flush_cache_all();
                        prom_startcpu(linux_cpus[i].prom_node,
                                      &penguin_ctable, 0, (char *)entry);
@@ -255,7 +254,6 @@ void smp_boot_cpus(void)
                        } else {
                                printk("Penguin %d is stuck in the bottle.\n", i);
                        }
-                       current_set[i] = 0;
                }
                if(!(cpu_callin_map[i])) {
                        cpu_present_map &= ~(1 << i);
index 9e18e53e60c6e31f2f021e8c5046fde5fccb1082..5e10f57c5ad12924060383e94ce5c8a227ed405e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc-stub.c,v 1.15 1996/04/04 12:41:35 davem Exp $
+/* $Id: sparc-stub.c,v 1.16 1996/04/25 06:09:01 davem Exp $
  * sparc-stub.c:  KGDB support for the Linux kernel.
  *
  * Modifications to run under Linux
index 5e523bf8f2b5729e430de5e306ed7d5e961355b3..7b2fb486e3c9b1dedb43d3c328c720b16e93e8b5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl.c,v 1.18 1996/04/04 12:41:38 davem Exp $
+/* $Id: sunos_ioctl.c,v 1.20 1996/04/25 06:09:08 davem Exp $
  * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility.
  * 
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -139,8 +139,43 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
                 */
                return 0;
        /* Non posix grp */
-       case _IOR('t', 119, int):
-               return -EIO;
+       case _IOW('t', 118, int): {
+               int oldval, *ptr;
+
+               cmd = TIOCSPGRP;
+               ptr = (int *) arg;
+               oldval = verify_area(VERIFY_WRITE, ptr, sizeof(int));
+               if(oldval)
+                       return oldval;
+               oldval = *ptr;
+               foo = sys_ioctl(fd, cmd, arg);
+               if(*ptr == -1) {
+                       *ptr = oldval;
+                       foo = -EIO;
+               }
+               if(foo == -ENOTTY)
+                       foo = -EIO;
+               return foo;
+       }
+
+       case _IOR('t', 119, int): {
+               int oldval, *ptr;
+
+               cmd = TIOCGPGRP;
+               ptr = (int *) arg;
+               oldval = verify_area(VERIFY_WRITE, ptr, sizeof(int));
+               if(oldval)
+                       return oldval;
+               oldval = *ptr;
+               foo = sys_ioctl(fd, cmd, arg);
+               if(*ptr == -1) {
+                       *ptr = oldval;
+                       foo = -EIO;
+               }
+               if(foo == -ENOTTY)
+                       foo = -EIO;
+               return foo;
+       }
        }
 
 #if 0
index da7d187d03ddd609bf1b2f96e073bd5f6ce230c7..d9fa43e0f32d9b869adbb67e9b8c18c49487e80e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.10 1996/04/20 08:33:55 davem Exp $
+/* $Id: sys_sparc.c,v 1.11 1996/04/25 06:09:10 davem Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
index 8f3e2c05f8fcafb96b68665d70bdab09b0c052e2..af9a480d0ca221d7e077112ffe33bb72f336289e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.37 1996/04/19 16:52:38 miguel Exp $
+/* $Id: sys_sunos.c,v 1.40 1996/04/25 09:11:36 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -35,6 +35,8 @@
 #include <linux/swap.h>
 #include <linux/fs.h>
 #include <linux/resource.h>
+#include <linux/ipc.h>
+#include <linux/shm.h>
 #include <linux/signal.h>
 #include <linux/uio.h>
 #include <linux/utsname.h>
@@ -565,7 +567,7 @@ asmlinkage int sunos_fpathconf(int fd, int name)
        case _PCONF_NOTRUNC:
                return 0; /* XXX Investigate XXX */
        case _PCONF_VDISABLE:
-               return 30; /* XXX Investigate XXX */
+               return 0;
        default:
                return -EINVAL;
        }
@@ -1011,3 +1013,34 @@ repeat:
        return fdcount;
 }
 
+extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr);
+extern asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
+extern asmlinkage int sys_shmdt (char *shmaddr);
+extern asmlinkage int sys_shmget (key_t key, int size, int shmflg);
+
+asmlinkage int sunos_shmsys(int op, unsigned long arg1, unsigned long arg2,
+                           unsigned long arg3)
+{
+       unsigned long raddr;
+       int rval;
+
+       switch(op) {
+       case 0:
+               /* sys_shmat(): attach a shared memory area */
+               rval = sys_shmat((int)arg1,(char *)arg2,(int)arg3,&raddr);
+               if(rval != 0)
+                       return rval;
+               return (int) raddr;
+       case 1:
+               /* sys_shmctl(): modify shared memory area attr. */
+               return sys_shmctl((int)arg1,(int)arg2,(struct shmid_ds *)arg3);
+       case 2:
+               /* sys_shmdt(): detach a shared memory area */
+               return sys_shmdt((char *)arg1);
+       case 3:
+               /* sys_shmget(): get a shared memory area */
+               return sys_shmget((key_t)arg1,(int)arg2,(int)arg3);
+       default:
+               return -EINVAL;
+       }
+}
index 7816f53f232d538f6c5f23ab8f170ccf76a42bcf..92b6eda7ccdc4c62be4fe320fded0e31dfb6e777 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.38 1996/04/20 08:43:26 davem Exp $
+/* $Id: systbls.S,v 1.41 1996/04/25 09:11:39 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -147,7 +147,7 @@ C_LABEL(sunos_sys_table):
        .long C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sunos_brk)
        .long C_LABEL(sunos_nosys), C_LABEL(sys_lseek), C_LABEL(sunos_getpid)
        .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_getuid), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_getuid), C_LABEL(sunos_nosys), C_LABEL(sys_ptrace)
        .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
        .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
        .long C_LABEL(sys_access), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
@@ -197,7 +197,7 @@ C_LABEL(sunos_sys_table):
        .long C_LABEL(sunos_getdomainname), C_LABEL(sys_setdomainname)
        .long C_LABEL(sunos_nosys), C_LABEL(sys_quotactl), C_LABEL(sunos_nosys)
        .long C_LABEL(sunos_mount), C_LABEL(sys_ustat), C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_audit)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit)
        .long C_LABEL(sunos_nosys), C_LABEL(sunos_getdents), C_LABEL(sys_setsid)
        .long C_LABEL(sys_fchdir), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
        .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
index 614cd9c5b7ac3f2c4b6cecd59345702313549441..1b9c46ba3a9e774a41d77f093c077ccf244634fb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.42 1996/04/16 08:24:44 davem Exp $
+/* $Id: traps.c,v 1.43 1996/04/24 09:09:42 davem Exp $
  * arch/sparc/kernel/traps.c
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -21,6 +21,7 @@
 #include <asm/pgtable.h>
 #include <asm/kdebug.h>
 #include <asm/unistd.h>
+#include <asm/traps.h>
 #include <asm/smp.h>
 
 /* #define TRAP_DEBUG */
@@ -95,6 +96,10 @@ void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc)
                printk("Unimplemented Sparc TRAP, type = %02lx\n", type);
                die_if_kernel("Whee... Hello Mr. Penguin", current->tss.kregs);
        }       
+       if(type == SP_TRAP_SBPT) {
+               send_sig(SIGTRAP, current, 1);
+               return;
+       }
        current->tss.sig_desc = SUBSIG_BADTRAP(type - 0x80);
        current->tss.sig_address = pc;
        send_sig(SIGILL, current, 1);
index cb92857d378f786062057a5eb6975791c059b983..a667fed7980f1fe7bba3a63ea6144da13e7049f4 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: wuf.S,v 1.22 1996/04/03 02:15:13 davem Exp $
+/* $Id: wuf.S,v 1.23 1996/04/25 06:09:18 davem Exp $
  * wuf.S: Window underflow trap handler for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller
index 16b085d34815061b481c76b4e92620e8f2aaa0b0..e0367faeefa66e05b1167a7fae2b46a7a3308963 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.61 1996/04/12 06:52:35 davem Exp $
+/* $Id: fault.c,v 1.62 1996/04/25 06:09:26 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 7a9093246d4a37a3cf0c0fc6501910a2caf0fdbc..d8d7e519622059e27abce5589714858dc78bf959 100644 (file)
@@ -1,4 +1,5 @@
-/* generic.c: Generic Sparc mm routines that are not dependent upon
+/* $Id: generic.c,v 1.2 1996/04/25 06:09:30 davem Exp $
+ * generic.c: Generic Sparc mm routines that are not dependent upon
  *            MMU type but are Sparc specific.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
index 9e0203457cbca8046e17707abd13fd2417b9a356..cc9cffa79a01ee965fe8c5419fd64f2165662f9d 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.36 1996/04/16 08:02:54 davem Exp $
+/*  $Id: init.c,v 1.37 1996/04/25 06:09:33 davem Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index c7b7f4c446b343fe35e0dcbff55c5f3478436cd1..6725145e746130e65420d0bd7dd1395370bb2024 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.59 1996/04/21 10:32:21 davem Exp $
+/* $Id: srmmu.c,v 1.62 1996/04/25 09:11:47 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -604,11 +604,14 @@ static void tsunami_flush_cache_page_to_uncache(unsigned long page)
 /* Tsunami does not have a Copy-back style virtual cache. */
 static void tsunami_flush_page_to_ram(unsigned long page)
 {
+       tsunami_flush_icache();
+       tsunami_flush_dcache();
 }
 
 /* However, Tsunami is not IO coherent. */
 static void tsunami_flush_page_for_dma(unsigned long page)
 {
+       tsunami_flush_icache();
        tsunami_flush_dcache();
 }
 
@@ -805,7 +808,6 @@ static void swift_flush_tlb_page_for_cbit(unsigned long page)
 
 static void viking_flush_cache_all(void)
 {
-       viking_flush_icache();
 }
 
 static void viking_flush_cache_mm(struct mm_struct *mm)
@@ -814,7 +816,6 @@ static void viking_flush_cache_mm(struct mm_struct *mm)
        if(mm->context != NO_CONTEXT) {
 #endif
                flush_user_windows();
-               viking_flush_icache();
 #ifndef __SMP__
        }
 #endif
@@ -826,7 +827,6 @@ static void viking_flush_cache_range(struct mm_struct *mm, unsigned long start,
        if(mm->context != NO_CONTEXT) {
 #endif
                flush_user_windows();
-               viking_flush_icache();
 #ifndef __SMP__
        }
 #endif
@@ -839,8 +839,6 @@ static void viking_flush_cache_page(struct vm_area_struct *vma, unsigned long pa
        if(mm->context != NO_CONTEXT) {
 #endif
                flush_user_windows();
-               if(vma->vm_flags & VM_EXEC)
-                       viking_flush_icache();
 #ifndef __SMP__
        }
 #endif
index 82dfa6d70bddb1c587291b5ad71423d93c62cbb1..805c1bded197d14f8a9e4c7a00b7de9306d5f432 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: memory.c,v 1.6 1996/04/08 09:02:27 davem Exp $
+/* $Id: memory.c,v 1.7 1996/04/25 06:09:46 davem Exp $
  * memory.c: Prom routine for acquiring various bits of information
  *           about RAM on the machine, both virtual and physical.
  *
index 388f71a3c59f9239ab7a1342590b7b2db9211bd8..84ce8bc544735794c189a6746d10b3efe9e985a6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: palloc.c,v 1.3 1995/11/25 01:00:08 davem Exp $
+/* $Id: palloc.c,v 1.4 1996/04/25 06:09:48 davem Exp $
  * palloc.c:  Memory allocation from the Sun PROM.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 58ffd45a2f4031683fa256c8bdbd774639ad57cc..0d580061b8cce2b62e075a94c446bcd72e5015c4 100644 (file)
@@ -677,7 +677,7 @@ unsigned short crc;     /* on 68000 we got an alignment problem,
                            but this compiler solves it  by adding silently 
                            adding a pad byte so data wont fit
                            and this cost about 3h to discover.... */
-unsigned char gap1[22];     /* for longword-aligndness (0x4e) */
+unsigned char gap1[22];     /* for longword-alignedness (0x4e) */
 };
 
 /* crc routines are borrowed from the messydos-handler  */
@@ -702,7 +702,7 @@ return dos_crc(data, 0xe2, 0x95 ,511); /* precomputed magic */
 ; How CRCs "really" work:
 ;
 ; First, you should regard a bitstring as a series of coefficients of
-; polymomials. We calculate with these polynomials in modulo-2
+; polynomials. We calculate with these polynomials in modulo-2
 ; arithmetic, in which both add and subtract are done the same as
 ; exclusive-or. Now, we modify our data (a very long polynomial) in
 ; such a way that it becomes divisible by the CCITT-standard 16-bit
@@ -1637,7 +1637,7 @@ static int floppy_open(struct inode *inode, struct file *filp)
   unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks*
         unit[drive].sects;
 
-printk("fd%d: accesing %s-disk with %s-layout\n",drive,unit[drive].type->name,
+printk("fd%d: accessing %s-disk with %s-layout\n",drive,unit[drive].type->name,
   data_types[system].name);
 
   return 0;
index b52816f440233bb19f71adfb7784a3066e8cd3bd..20de5095167d2b318d4937db6862c23083f40dca 100644 (file)
@@ -38,7 +38,7 @@
  *  - for medusa, the step rate is always 3ms
  *  - on medusa, use only cache_push()
  * Roman:
- *  - Make disk format numbering independant from minors
+ *  - Make disk format numbering independent from minors
  *  - Let user set max. supported drive type (speeds up format
  *    detection, saves buffer space)
  *
@@ -244,7 +244,7 @@ static struct atari_floppy_struct {
 /* Buffering variables:
  * First, there is a DMA buffer in ST-RAM that is used for floppy DMA
  * operations. Second, a track buffer is used to cache a whole track
- * of the disk to save read operations. These are two seperate buffers
+ * of the disk to save read operations. These are two separate buffers
  * because that allows write operations without clearing the track buffer.
  */
 
@@ -299,7 +299,7 @@ static unsigned int changed_floppies = 0xff, fake_change = 0;
 #define        FD_MOTOR_OFF_MAXTRY     (10*20)
 
 #define FLOPPY_TIMEOUT         (6*HZ)
-#define RECALIBRATE_ERRORS     4       /* Atfer this many errors the drive
+#define RECALIBRATE_ERRORS     4       /* After this many errors the drive
                                         * will be recalibrated. */
 #define MAX_ERRORS             8       /* After this many errors the driver
                                         * will give up. */
@@ -338,7 +338,7 @@ static unsigned int changed_floppies = 0xff, fake_change = 0;
  */
 static int Probing = 0;
 
-/* This flag is set when a dummy seek is necesary to make the WP
+/* This flag is set when a dummy seek is necessary to make the WP
  * status bit accessible.
  */
 static int NeedSeek = 0;
@@ -550,7 +550,7 @@ static void check_change( void )
 
  
 /* Handling of the Head Settling Flag: This flag should be set after each
- * seek operation, because we dont't use seeks with verify.
+ * seek operation, because we don't use seeks with verify.
  */
 
 static __inline__ void set_head_settle_flag( void )
@@ -880,7 +880,7 @@ static void fd_rwsec( void )
                        copy_buffer( ReqData, DMABuffer );
                        paddr = PhysDMABuffer;
                }
-               dma_cache_maintainance( paddr, 512, 1 );
+               dma_cache_maintenance( paddr, 512, 1 );
                rwflag = 0x100;
        }
        else {
@@ -949,7 +949,7 @@ static void fd_rwsec( void )
        if (read_track) {
                /* If reading a whole track, wait about one disk rotation and
                 * then check if all sectors are read. The FDC will even
-                * search for the first non-existant sector and need 1 sec to
+                * search for the first non-existent sector and need 1 sec to
                 * recognise that it isn't present :-(
                 */
                readtrack_timer.expires =
@@ -1061,7 +1061,7 @@ static void fd_rwsec_done( int status )
        }       
        if ((status & FDCSTAT_RECNF) &&
            /* RECNF is no error after a multiple read when the FDC
-              searched for a non-existant sector! */
+              searched for a non-existent sector! */
            !(read_track && FDC_READ(FDCREG_SECTOR) > SUDT->spt)) {
                if (Probing) {
                        if (SUDT > disk_type) {
@@ -1115,11 +1115,11 @@ static void fd_rwsec_done( int status )
                if (!read_track) {
                        void *addr;
                        addr = ATARIHW_PRESENT( EXTD_DMA ) ? ReqData : DMABuffer;
-                       dma_cache_maintainance( VTOP(addr), 512, 0 );
+                       dma_cache_maintenance( VTOP(addr), 512, 0 );
                        if (!ATARIHW_PRESENT( EXTD_DMA ))
                                copy_buffer (addr, ReqData);
                } else {
-                       dma_cache_maintainance( PhysTrackBuffer, MAX_SECTORS * 512, 0 );
+                       dma_cache_maintenance( PhysTrackBuffer, MAX_SECTORS * 512, 0 );
                        BufferDrive = SelectedDrive;
                        BufferSide  = ReqSide;
                        BufferTrack = ReqTrack;
@@ -1155,7 +1155,7 @@ static void fd_writetrack( void )
        DPRINT(("fd_writetrack() Tr=%d Si=%d\n", ReqTrack, ReqSide ));
 
        paddr = PhysTrackBuffer;
-       dma_cache_maintainance( paddr, BUFFER_SIZE, 1 );
+       dma_cache_maintenance( paddr, BUFFER_SIZE, 1 );
 
        fd_select_side( ReqSide );
   
@@ -1233,11 +1233,11 @@ static void fd_writetrack_done( int status )
 static void fd_times_out( unsigned long dummy )
 {
        atari_disable_irq( IRQ_MFP_FDC );
-       if (!FloppyIRQHandler) goto end; /* int occured after timer was fired, but
+       if (!FloppyIRQHandler) goto end; /* int occurred after timer was fired, but
                                          * before we came here... */
 
        SET_IRQ_HANDLER( NULL );
-       /* If the timeout occured while the readtrack_check timer was
+       /* If the timeout occurred while the readtrack_check timer was
         * active, we need to cancel it, else bad things will happen */
        if (UseTrackbuffer)
                del_timer( &readtrack_timer );
@@ -1271,7 +1271,7 @@ static void finish_fdc( void )
                MotorOn = 1;
                START_TIMEOUT();
                /* we must wait for the IRQ here, because the ST-DMA
-                  is released immediatly afterwards and the interrupt
+                  is released immediately afterwards and the interrupt
                   may be delivered to the wrong driver. */
          }
 }
@@ -1333,7 +1333,7 @@ static void floppy_off( unsigned int nr) {}
  * looking at the serial number in block 0. This isn't possible for
  * Linux, since the floppy driver can't make assumptions about the
  * filesystem used on the disk and thus the contents of block 0. I've
- * choosen the method to always say "The disk was changed" if it is
+ * chosen the method to always say "The disk was changed" if it is
  * unsure whether it was. This implies that every open or mount
  * invalidates the disk buffers if you work with write protected
  * disks. But at least this is better than working with incorrect data
index 1982953e9ec3e29b6f50aa15028928cc85f8c13f..d46db8ff0050c91139a5d91dac3b751de36a7311 100644 (file)
@@ -294,7 +294,7 @@ static inline int DRIVE(kdev_t x) {
 /*
  * globals used by 'result()'
  */
-#define MAX_REPLIES 17
+#define MAX_REPLIES 16
 static unsigned char reply_buffer[MAX_REPLIES];
 static int inr; /* size of reply buffer, when called from interrupt */
 #define ST0 (reply_buffer[0])
index 8d09a68dfa1e4f35e816984093545b748e2034b1..f31f9a70ed70d29b999da0b0d725d834118e0cdf 100644 (file)
@@ -208,6 +208,43 @@ done:
        brelse(bh);
 }
 
+#ifdef CONFIG_BSD_DISKLABEL
+/* 
+ * Create devices for BSD partitions listed in a disklabel, under a
+ * dos-like partition. See extended_partition() for more information.
+ */
+static void bsd_disklabel_partition(struct gendisk *hd, int dev)
+{
+       struct buffer_head *bh;
+       struct bsd_disklabel *l;
+       struct bsd_partition *p;
+       int mask = (1 << hd->minor_shift) - 1;
+
+       if (!(bh = bread(dev,0,1024)))
+               return;
+       bh->b_state = 0;
+       l = (struct bsd_disklabel *) (bh->b_data+512);
+       if (l->d_magic != BSD_DISKMAGIC) {
+               brelse(bh);
+               return;
+       }
+
+       p = &l->d_partitions[0];
+       while (p - &l->d_partitions[0] <= BSD_MAXPARTITIONS) {
+               if ((current_minor & mask) >= (4 + hd->max_p))
+                       break;
+
+               if (p->p_fstype != BSD_FS_UNUSED) {
+                       add_partition(hd, current_minor, p->p_offset, p->p_size);
+                       current_minor++;
+               }
+               p++;
+       }
+       brelse(bh);
+
+}
+#endif
+
 static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
 {
        int i, minor = current_minor;
@@ -329,6 +366,13 @@ check_table:
                        if (hd->part[minor].nr_sects > 2)
                                hd->part[minor].nr_sects = 2;
                }
+#ifdef CONFIG_BSD_DISKLABEL
+               if (p->sys_ind == BSD_PARTITION) {
+                       printk(" <");
+                       bsd_disklabel_partition(hd, MKDEV(hd->major, minor));
+                       printk(" >");
+               }
+#endif
        }
        /*
         *  Check for old-style Disk Manager partition table
@@ -445,15 +489,27 @@ static int sun_partition(struct gendisk *hd, unsigned int dev, unsigned long fir
                unsigned short nsect;      /* Sectors per track */
                unsigned char spare3[4];   /* Even more magic... */
                struct sun_partition {
-                       unsigned long start_cylinder;
-                       unsigned long num_sectors;
+                       __u32 start_cylinder;
+                       __u32 num_sectors;
                } partitions[8];
                unsigned short magic;      /* Magic number */
                unsigned short csum;       /* Label xor'd checksum */
        } * label;              
        struct sun_partition *p;
+       int other_endian;
        unsigned long spc;
-#define SUN_LABEL_MAGIC  0xDABE
+#define SUN_LABEL_MAGIC          0xDABE
+#define SUN_LABEL_MAGIC_SWAPPED  0xBEDA
+/* No need to optimize these macros since they are called only when reading
+ * the partition table. This occurs only at each disk change. */
+#define SWAP16(x)  (other_endian ? (((__u16)(x) & 0xFF) << 8) \
+                                | (((__u16)(x) & 0xFF00) >> 8) \
+                                : (__u16)(x))
+#define SWAP32(x)  (other_endian ? (((__u32)(x) & 0xFF) << 24) \
+                                | (((__u32)(x) & 0xFF00) << 8) \
+                                | (((__u32)(x) & 0xFF0000) >> 8) \
+                                | (((__u32)(x) & 0xFF000000) >> 24) \
+                                : (__u32)(x))
 
        if(!(bh = bread(dev, 0, 1024))) {
                printk("Dev %d: unable to read partition table\n", dev);
@@ -461,11 +517,12 @@ static int sun_partition(struct gendisk *hd, unsigned int dev, unsigned long fir
        }
        label = (struct sun_disklabel *) bh->b_data;
        p = label->partitions;
-       if(label->magic != SUN_LABEL_MAGIC) {
-               printk("Dev %d Sun disklabel: bad magic %08x\n", dev, label->magic);
+       if (label->magic != SUN_LABEL_MAGIC && label->magic != SUN_LABEL_MAGIC_SWAPPED) {
+               printk("Dev %d Sun disklabel: bad magic %04x\n", dev, label->magic);
                brelse(bh);
                return 0;
        }
+       other_endian = (label->magic == SUN_LABEL_MAGIC_SWAPPED);
        /* Look at the checksum */
        ush = ((unsigned short *) (label+1)) - 1;
        for(csum = 0; ush >= ((unsigned short *) label);)
@@ -476,20 +533,22 @@ static int sun_partition(struct gendisk *hd, unsigned int dev, unsigned long fir
                return 0;
        }
        /* All Sun disks have 8 partition entries */
-       spc = (label->ntrks * label->nsect);
+       spc = SWAP16(label->ntrks) * SWAP16(label->nsect);
        for(i=0; i < 8; i++, p++) {
                unsigned long st_sector;
 
                /* We register all partitions, even if zero size, so that
                 * the minor numbers end up ok as per SunOS interpretation.
                 */
-               st_sector = first_sector + (p->start_cylinder * spc);
-               add_partition(hd, current_minor, st_sector, p->num_sectors);
+               st_sector = first_sector + SWAP32(p->start_cylinder) * spc;
+               add_partition(hd, current_minor, st_sector, SWAP32(p->num_sectors));
                current_minor++;
        }
        printk("\n");
        brelse(bh);
        return 1;
+#undef SWAP16
+#undef SWAP32
 }
 
 #endif /* CONFIG_SUN_PARTITION */
index b63b1562339c9b5123219c2e135bcd873b9376e6..0ec6e0d960b89031c9653831b8d8b0ad7aacb133 100644 (file)
@@ -32,6 +32,9 @@
  *     Default ramdisk size changed to 2.88MB
  *
  *  Added initrd: Werner Almesberger & Hans Lermen, Feb '96
+ *
+ * 4/25/96 : Made ramdisk size a parameter (default is now 4MB) 
+ *             - Chad Page
  */
 
 #include <linux/config.h>
@@ -60,9 +63,8 @@ extern void wait_for_keypress(void);
 #define MAJOR_NR RAMDISK_MAJOR
 #include <linux/blk.h>
 
-/* These *should* be defined as parameters */
-#define NUM_RAMDISKS 8
-#define RD_DEFAULTSIZE 2880    /* 2.88 MB */
+/* The ramdisk size is now a parameter */
+#define NUM_RAMDISKS 16                /* This cannot be overridden (yet) */ 
 
 #ifndef MODULE
 /* We don't have to load ramdisks or gunzip them in a module... */
@@ -92,6 +94,7 @@ static int rd_blocksizes[NUM_RAMDISKS];
 int rd_doload = 0;             /* 1 = load ramdisk, 0 = don't load */
 int rd_prompt = 1;             /* 1 = prompt for ramdisk, 0 = don't prompt */
 int rd_image_start = 0;                /* starting block # of image */
+int rd_size = 4096;            /* Size of the ramdisks */
 #ifdef CONFIG_BLK_DEV_INITRD
 unsigned long initrd_start,initrd_end;
 int mount_initrd = 1;          /* zero if initrd should not be mounted */
@@ -272,12 +275,15 @@ int rd_init(void)
        blk_dev[MAJOR_NR].request_fn = &rd_request;
 
        for (i = 0; i < NUM_RAMDISKS; i++) {
-               rd_length[i] = (RD_DEFAULTSIZE * 1024);
+               rd_length[i] = (rd_size * 1024);
                rd_blocksizes[i] = 1024;
        }
 
        blksize_size[MAJOR_NR] = rd_blocksizes;
 
+       printk("Ramdisk driver initialized : %d ramdisks of %dK size\n",
+                                                       NUM_RAMDISKS, rd_size);
+
        return 0;
 }
 
index 86359ae633696c80b91ed4ac89bac8aff3355df8..91c2a7049e0623fb25c0bc633b67794ee4b8a0e7 100644 (file)
@@ -20,18 +20,24 @@ FONTMAPFILE = cp437.uni
 
 L_TARGET := char.a
 M_OBJS   :=
-L_OBJS   := tty_io.o n_tty.o console.o keyboard.o \
+L_OBJS   := tty_io.o n_tty.o console.o \
        tty_ioctl.o pty.o vt.o mem.o vc_screen.o random.o \
-       defkeymap.o consolemap.o selection.o
+       consolemap.o selection.o
+
 ifeq ($(CONFIG_SERIAL),y)
-LX_OBJS += serial.o
+  ifndef CONFIG_SUN_SERIAL
+  LX_OBJS += serial.o
+  endif
 else
   ifeq ($(CONFIG_SERIAL),m)
   MX_OBJS += serial.o
   endif
 endif
 
+ifndef CONFIG_SUN_KEYBOARD
+L_OBJS += keyboard.o defkeymap.o
+endif
+
 ifeq ($(CONFIG_DIGI),y)
 L_OBJS += pcxx.o
 endif
@@ -127,6 +133,10 @@ M = y
 # This is not modularized, so if configured then "misc.c" will be resident
 endif
 
+ifdef CONFIG_SUN_MOUSE
+M = y
+endif
+
 ifeq ($(CONFIG_WDT),y)
 M = y
 L_OBJS += wdt.o
@@ -167,7 +177,7 @@ else
   MX_OBJS += misc.o
   endif
 endif
-
+  
 ifeq ($(CONFIG_SCC),y)
 L_OBJS += scc.o
 else
@@ -179,7 +189,9 @@ endif
 ifdef CONFIG_TGA_CONSOLE
 L_OBJS += tga.o
 else
-L_OBJS += vga.o vesa_blank.o
+ ifndef CONFIG_SUN_CONSOLE
+ L_OBJS += vga.o vesa_blank.o
+ endif
 endif
 
 include $(TOPDIR)/Rules.make
index f8261ee3ec84f05896e41f60be049ec227bc6df1..60b968ff606d09575db6ce8aa4608b2dcd0834f0 100644 (file)
@@ -25,7 +25,7 @@
  *   renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
  *   renamed this file mouse.c => busmouse.c
  *
- * Modfied for use in the 1.3 kernels by Jes Sorensen.
+ * Modified for use in the 1.3 kernels by Jes Sorensen.
  */
 
 #include <linux/module.h>
index f6d00f3522ea318db11cd8af19d01038ba1e9547..efd4393bd9fb5a396a61ababfc68ec381126fefc 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * split into mid and low-level for better support of diffent hardware
+ * split into mid and low-level for better support of different hardware
  * by Joerg Dorchain (dorchain@mpi-sb.mpg.de)
  *
  * Amiga printer device by Michael Rausch (linux@uni-koblenz.de);
index e58448585bd0b1a16aa978c271a3eedc7c68d59f..42eeed3a571b0e6018d23aaaf6ccab41eb324e6b 100644 (file)
@@ -29,7 +29,7 @@
  *  with a certain priority is executed, all requests with lower or same
  *  priority get locked out. executing the sti()-macro allows ANY interrupt
  *  to be served. this really causes BIG trouble!
- *  to protect an interrupt driven routine against beeing interrupted 
+ *  to protect an interrupt driven routine against being interrupted 
  *  (if absolutely needed!) one should use save_flags();cli()/restore_flags()!
  *
  */
@@ -231,7 +231,7 @@ static int lp_write_interrupt(struct inode *inode, struct file *file,
       }
       if (lp_error) {
 
-       /* an error has occured, maybe in lp_interrupt().
+       /* an error has occurred, maybe in lp_interrupt().
           figure out the type of error, exit on request or if nothing has 
           been printed at all. */
        
index 30df1b2396c0bcadb8c1100fca7ed9415408e76d..ffec3f924571562c12a3fcec3894acbebf9ab846 100644 (file)
@@ -53,7 +53,7 @@ static int read_mem(struct inode * inode, struct file * file, char * buf, int co
        if (count > high_memory - p)
                count = high_memory - p;
        read = 0;
-#if defined(__i386__)          /* we don't have page 0 mapped on x86.. */
+#if defined(__i386__) || defined(__sparc__) /* we don't have page 0 mapped on x86/sparc.. */
        while (p < PAGE_OFFSET + PAGE_SIZE && count > 0) {
                put_user(0,buf);
                buf++;
@@ -81,7 +81,7 @@ static int write_mem(struct inode * inode, struct file * file, const char * buf,
        if (count > high_memory - p)
                count = high_memory - p;
        written = 0;
-#if defined(__i386__)          /* we don't have page 0 mapped on x86.. */
+#if defined(__i386__) || defined(__sparc__) /* we don't have page 0 mapped on x86/sparc.. */
        while (PAGE_OFFSET + p < PAGE_SIZE && count > 0) {
                /* Hmm. Do something? */
                buf++;
@@ -390,7 +390,7 @@ int chr_dev_init(void)
 #if defined (CONFIG_BUSMOUSE) || defined(CONFIG_UMISC) || \
     defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
     defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG) || \
-    defined (CONFIG_APM) || defined (CONFIG_RTC)
+    defined (CONFIG_APM) || defined (CONFIG_RTC) || defined (CONFIG_SUN_MOUSE)
        misc_init();
 #endif
 #ifdef CONFIG_SOUND
index 738845ec874e8bfeb88e38e9852b6deb64d69b45..46577b62b99832d38b06f14305ae4876c93fdf47 100644 (file)
@@ -65,6 +65,7 @@ extern int bus_mouse_init(void);
 extern int psaux_init(void);
 extern int ms_bus_mouse_init(void);
 extern int atixl_busmouse_init(void);
+extern int sun_mouse_init(void);
 extern void watchdog_init(void);
 extern int rtc_init(void);
 
@@ -205,6 +206,15 @@ int misc_init(void)
 #ifdef CONFIG_ATIXL_BUSMOUSE
        atixl_busmouse_init();
 #endif
+#ifdef CONFIG_AMIGAMOUSE
+       amiga_mouse_init();
+#endif
+#ifdef CONFIG_ATARIMOUSE
+       atari_mouse_init();
+#endif
+#ifdef CONFIG_SUN_MOUSE
+       sun_mouse_init();
+#endif
 #ifdef CONFIG_SOFT_WATCHDOG
        watchdog_init();
 #endif 
index c262b85ab4fe4ef607dbbaf55d8a9672abcacc08..2066fa83ae3c7f9cba94082a1984d0b467466955 100644 (file)
@@ -216,8 +216,9 @@ int pty_open(struct tty_struct *tty, struct file * filp)
         */
        if (tty->driver.subtype == PTY_TYPE_MASTER)
                return 0;
-       add_wait_queue(&pty->open_wait, &wait);
        retval = 0;
+#if PTY_SLAVE_WAITS_ON_OPEN
+       add_wait_queue(&pty->open_wait, &wait);
        while (1) {
                if (current->signal & ~current->blocked) {
                        retval = -ERESTARTSYS;
@@ -226,6 +227,7 @@ int pty_open(struct tty_struct *tty, struct file * filp)
                /*
                 * Block until the master is open...
                 */
+               current->state = TASK_INTERRUPTIBLE;
                if (tty->link->count &&
                    !test_bit(TTY_OTHER_CLOSED, &tty->flags))
                        break;
@@ -233,6 +235,10 @@ int pty_open(struct tty_struct *tty, struct file * filp)
        }
        current->state = TASK_RUNNING;
        remove_wait_queue(&pty->open_wait, &wait);
+#else
+       if (!tty->link->count || test_bit(TTY_OTHER_CLOSED, &tty->flags))
+               retval = -EPERM;
+#endif
        return retval;
 }
 
index 51b5a72a33f48a9dff77ad802bec69ca5db4ccf7..7475b339ac90340505f4528160581856a5ffc034 100644 (file)
@@ -7,7 +7,7 @@
  *      Linus Torvalds, Theodore T'so and others. The RISCom/8 card 
  *      programming info was obtained from various drivers for other OSes 
  *     (FreeBSD, ISC, etc), but no source code from those drivers were 
- *     directly included in this drvier.
+ *     directly included in this driver.
  *
  *
  *      This program is free software; you can redistribute it and/or modify
@@ -173,7 +173,7 @@ extern inline void rc_out(struct riscom_board const * bp, unsigned short reg,
        outb(val, bp->base + RC_TO_ISA(reg));
 }
 
-/* Wait for Chanel Command Register ready */
+/* Wait for Channel Command Register ready */
 extern inline void rc_wait_CCR(struct riscom_board const * bp)
 {
        unsigned long delay;
@@ -196,7 +196,7 @@ extern inline int rc_check_io_range(struct riscom_board * const bp)
        
        for (i = 0; i < RC_NIOPORT; i++)  
                if (check_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1))  {
-                       printk("rc%d: Skipping probe at 0x%03x. I/O adress in use.\n",
+                       printk("rc%d: Skipping probe at 0x%03x. I/O address in use.\n",
                               board_No(bp), bp->base);
                        return 1;
                }
@@ -319,7 +319,7 @@ static int rc_probe(struct riscom_board *bp)
 
 /* 
  * 
- *  Inerrupt processing routines.
+ *  Interrupt processing routines.
  * 
  */
 
@@ -328,7 +328,7 @@ extern inline void rc_mark_event(struct riscom_port * port, int event)
        /* 
          * I'm not quite happy with current scheme all serial
         * drivers use their own BH routine.
-         * It seem's this easily can be done with one BH routine
+         * It seems this easily can be done with one BH routine
         * serving for all serial drivers.
         * For now I must introduce another one - RISCOM8_BH.
         * Still hope this will be changed in near future.
@@ -673,7 +673,7 @@ extern inline void rc_shutdown_board(struct riscom_board *bp)
 
 /*
  * Setting up port characteristics. 
- * Must be called with disabled interupts
+ * Must be called with disabled interrupts
  */
 static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
 {
@@ -785,7 +785,7 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
                        /* Real raw mode. Ignore all */
                        port->mark_mask &= ~RCSR_OE;
        }
-       /* Enable Hardware FLow Control */
+       /* Enable Hardware Flow Control */
        if (C_CRTSCTS(tty))  {
 #ifdef RISCOM_BRAIN_DAMAGED_CTS
                port->IER |= IER_DSR | IER_CTS;
@@ -831,12 +831,12 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
        /* Setting up modem option registers */
        rc_out(bp, CD180_MCOR1, mcor1);
        rc_out(bp, CD180_MCOR2, mcor2);
-       /* Enable CD180 trasmitter & receiver */
+       /* Enable CD180 transmitter & receiver */
        rc_wait_CCR(bp);
        rc_out(bp, CD180_CCR, CCR_TXEN | CCR_RXEN);
        /* Enable interrupts */
        rc_out(bp, CD180_IER, port->IER);
-       /* And finaly set RTS on */
+       /* And finally set RTS on */
        rc_out(bp, CD180_MSVR, port->MSVR);
 }
 
@@ -927,7 +927,7 @@ static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port)
        port->flags &= ~ASYNC_INITIALIZED;
        
        if (--bp->count < 0)  {
-               printk("rc%d: rc_shutdow_port: bad board count: %d\n",
+               printk("rc%d: rc_shutdown_port: bad board count: %d\n",
                       board_No(bp), bp->count);
                bp->count = 0;
        }
@@ -1812,7 +1812,7 @@ static void rc_release_drivers(void)
  * 
  * You can specify IO base for up to RC_NBOARD cards,
  * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt.
- * Note that there wiil be no probing at default
+ * Note that there will be no probing at default
  * addresses in this case.
  *
  */ 
@@ -1862,7 +1862,7 @@ int iobase3 = 0;
 
 /*
  * You can setup up to 4 boards (current value of RC_NBOARD)
- * by specifying "iobase=0xXXX iobase1=0xXXX ..." as isnmod parametr.
+ * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter.
  *
  */
 int init_module(void) 
index 8bdce318f2c7df0855d14c7f140e4d157d8aa604..1d014a9217284db18138d87ffaf8badd7c43bc97 100644 (file)
@@ -7,7 +7,7 @@
  *      Linus Torvalds, Theodore T'so and others. The RISCom/8 card 
  *      programming info was obtained from various drivers for other OSes 
  *     (FreeBSD, ISC, etc), but no source code from those drivers were 
- *     directly included in this drvier.
+ *     directly included in this driver.
  *
  *
  *      This program is free software; you can redistribute it and/or modify
index 4c69250c3852587042bcdb23118abb7f97f67883..a32475ed0d1885a5c7edecbaf47a9a9e3dd03bb9 100644 (file)
 /* Channel Address Register (R/W) */
 
 #define CAR_CHAN        0x07    /* Channel Number Mask                     */
-#define CAR_A7          0x08    /* A7 Address Extention (unused)           */
+#define CAR_A7          0x08    /* A7 Address Extension (unused)           */
 
 
 /* Receive Character Status Register (R/O) */
diff --git a/drivers/char/suncons.c b/drivers/char/suncons.c
deleted file mode 100644 (file)
index da70ff4..0000000
+++ /dev/null
@@ -1,1874 +0,0 @@
-/* suncons.c: Sun SparcStation console support.
- *
- * Copyright (C) 1995 Peter Zaitcev (zaitcev@lab.ipmce.su)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
- *
- * Added font loading Nov/21, Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Added render_screen and faster scrolling Nov/27, miguel
- * Added console palette code for cg6 Dec/13/95, miguel
- * Added generic frame buffer support Dec/14/95, miguel
- * Added cgsix and bwtwo drivers Jan/96, miguel
- * Added 4m, and cg3 driver Feb/96, miguel
- * Fixed the cursor on color displays Feb/96, miguel.
- *
- * Cleaned up the detection code, generic 8bit depth display 
- * code, Mar/96 miguel
- * 
- * This file contains the frame buffer device drivers.
- * Each driver is kept together in case we would like to
- * split this file.
- *
- * Much of this driver is derived from the DEC TGA driver by
- * Jay Estabrook who has done a nice job with the console
- * driver abstraction btw.
- *
- * We try to make everything a power of two if possible to
- * speed up the bit blit.  Doing multiplies, divides, and
- * remainder routines end up calling software library routines
- * since not all Sparcs have the hardware to do it.
- *
- * TODO:
- * do not use minor to index into instances of the frame buffer,
- * since the numbers assigned to us are not consecutive.
- *
- * do not blank the screen when frame buffer is mapped.
- *
- * Change the detection loop to use more than one video card.
- */
-
-
-/* Define this one if you are debugging something in X, it will not disable the console output */
-/* #define DEBUGGING_X */
-/* See also: sparc/keyboard.c: CODING_NEW_DRIVER */
-
-#define GRAPHDEV_MAJOR 29
-
-#define FRAME_BUFFERS 1
-
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/kd.h>
-#include <linux/malloc.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/types.h>
-
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/bitops.h>
-#include <asm/oplib.h>
-#include <asm/sbus.h>
-#include <asm/fbio.h>
-#include <asm/io.h>
-#include <asm/pgtsun4c.h>      /* for the sun4c_nocache */
-
-#include "kbd_kern.h"
-#include "vt_kern.h"
-#include "consolemap.h"
-#include "selection.h"
-#include "console_struct.h"
-
-#define cmapsz 8192
-
-extern void register_console(void (*proc)(const char *));
-extern void console_print(const char *);
-extern unsigned char vga_font[];
-extern int graphics_on;
-extern int serial_console;
-
-/* Based upon what the PROM tells us, we can figure out where
- * the console is currently located.  The situation can be either
- * of the following two scenarios:
- *
- * 1) Console i/o is done over the serial line, ttya or ttyb
- * 2) Console output on frame buffer (video card) and input
- *    coming from the keyboard/mouse which each use a zilog8530
- *    serial channel a piece.
- */
-
-/* The following variables describe a Sparc console. */
-
-/* From the PROM */
-static char con_name[40];
-
-/* Screen dimensions and color depth. */
-static int con_depth, con_width, con_height, con_type;
-
-static int con_linebytes;
-
-/* Base address of first line. */
-static unsigned char *con_fb_base;
-
-/* Screen parameters: we compute those at startup to make the code faster */
-static int chars_per_line;     /* number of bytes per line */
-static int ints_per_line;      /* number of ints per  line */
-static int skip_bytes;         /* number of bytes we skip for the y margin */
-static int x_margin, y_margin; /* the x and y margins */
-static int bytes_per_row;      /* bytes used by one screen line (of 16 scan lines)  */
-
-/* Functions used by the SPARC dependent console code
- * to perform the restore_palette function.
- */
-static void (*restore_palette)(void);
-void set_palette (void);
-
-
- /* Our screen looks like at 1152 X 900:
- *
- *  0,0
- *      ------------------------------------------------------------------
- *      |                          ^^^^^^^^^^^                           |
- *      |                          18 y-pixels                           |
- *      |                          ^^^^^^^^^^^                           |
- *   13 | <-64 pixels->|  <-- 128 8x16 characters -->    | <-64 pixels-> |
- *    ....
- *                         54 chars from top to bottom
- *    ....
- *  888 | <-64 pixels->|  <-- 128 8x16 characters -->    | <-64 pixels-> |
- *      |                          ^^^^^^^^^^^                           |
- *      |                          18 y-pixels                           |
- *      |                          ^^^^^^^^^^^                           |
- *      ------------------------------------------------------------------
- */
-/* First for MONO displays. */
-#define SCREEN_WIDTH     1152     /* Screen width in pixels  */
-#define SCREEN_HEIGHT    900      /* Screen height in pixels */
-#define CHARS_PER_LINE   144      /* Make this empirical for speed */
-#define NICE_Y_MARGIN    18       /* We skip 18 y-pixels at top/bottom */
-#define NICE_X_MARGIN    8        /* We skip 64 x-pixels at left/right */
-#define FBUF_TOP_SKIP    2592     /* Empirical, (CHARS_PER_LINE * NICE_Y_MARGIN) */
-#define CHAR_HEIGHT      16
-#define ONE_ROW          2304     /* CHARS_PER_LINE * CHAR_HEIGHT */
-
-/* Now we have this, to compute the base frame buffer position
- * for a new character to be rendered. 1 and 8 bit depth.
- */
-#define FBUF_OFFSET(cindex) \
-        (((FBUF_TOP_SKIP) + (((cindex)>>7) * ONE_ROW)) + \
-        ((NICE_X_MARGIN) + (((cindex)&127))))
-
-
-#define COLOR_FBUF_OFFSET(cindex) \
-        (((skip_bytes) + (((cindex)>>7) * bytes_per_row)) + \
-        ((x_margin) + (((cindex)&127) << 3)))
-
-void
-__set_origin(unsigned short offset)
-{
-       /*
-        * should not be called, but if so, do nothing...
-        */
-}
-
-/* For the cursor, we just invert the 8x16 block at the cursor
- * location.  Easy enough...
- *
- * Hide the cursor from view, during blanking, usually...
- */
-static int cursor_pos = -1;
-void
-hide_cursor(void)
-{
-       unsigned long flags;
-       int j;
-
-       save_flags(flags); cli();
-
-       if(cursor_pos == -1) {
-               restore_flags (flags);
-               return;
-       }
-       /* We just zero out the area for now.  Certain graphics
-        * cards like the cg6 have a hardware cursor that we could
-        * use, but this is an optimization for some time later.
-        */
-       switch (con_depth){
-       case 1: {
-               unsigned char *dst;
-               dst = (unsigned char *)((unsigned long)con_fb_base +
-                                       FBUF_OFFSET(cursor_pos));
-               for(j = 0; j < CHAR_HEIGHT; j++, dst += CHARS_PER_LINE)
-                       *dst = ~(0);
-               break;
-       }
-       case 8: {
-               unsigned long *dst;
-               const    int ipl = ints_per_line;
-               
-               dst = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(cursor_pos));
-               for(j = 0; j < CHAR_HEIGHT; j++, dst += ipl) {
-                       *dst = ~(0UL);
-                       *(dst + 1) = ~(0UL);
-               }
-               break;
-       }
-       default:
-               break;
-       }
-       restore_flags(flags);
-}
-
-/* The idea is the following:
- * we only use the colors in the range 0..15, and we only
- * setup the palette on that range, so we better keep the
- * pixel inversion using those colors, that's why we have
- * those constants below.
- */
-inline static void
-cursor_reverse (long *dst, int height, const int ints_on_line)
-{
-    int j;
-
-    for (j = 0; j < height; j++){
-       *dst     = ~(*dst)     & 0x0f0f0f0f;
-       *(dst+1) = ~(*(dst+1)) & 0x0f0f0f0f;
-       dst += ints_on_line;
-    }
-}
-
-void
-set_cursor(int currcons)
-{
-       int j, idx, oldpos;
-       unsigned long flags;
-
-       if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
-               return;
-
-       if (__real_origin != __origin)
-               __set_origin(__real_origin);
-
-       save_flags(flags); cli();
-
-       idx = (pos - video_mem_base) >> 1;
-       oldpos = cursor_pos;
-       cursor_pos = idx;
-       if (!deccm) {
-               hide_cursor ();
-               restore_flags (flags);
-               return;
-       }
-       switch (con_depth){
-       case 1: {
-               unsigned char *dst, *opos;
-               
-               dst = (unsigned char *)((unsigned long)con_fb_base + FBUF_OFFSET(idx));
-               opos = (unsigned char *)((unsigned long)con_fb_base + FBUF_OFFSET(oldpos));
-               if(oldpos != -1) {
-                       /* Restore what was at the old position */
-                       for(j=0; j < CHAR_HEIGHT; j++, opos += CHARS_PER_LINE) {
-                               *opos = ~*opos;
-                       }
-               }
-               for(j=0; j < 16; j++, dst+=CHARS_PER_LINE) {
-                       *dst = ~*dst;
-               }
-               break;
-       }
-       case 8: {
-               unsigned long *dst, *opos;
-               dst = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(idx));
-               opos = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(oldpos));
-                       
-               if(oldpos != -1) 
-                       cursor_reverse(opos, CHAR_HEIGHT, ints_per_line);
-               cursor_reverse (dst, CHAR_HEIGHT, ints_per_line);
-               break;
-       }
-       default:
-       }
-       restore_flags(flags);
-}
-
-/*
- * Render the current screen
- * Only used at startup to avoid the caching that is being done in selection.h
- */
-static void
-render_screen(void)
-{
-    int count;
-    unsigned short *contents;
-
-    count = video_num_columns * video_num_lines;
-    contents = (unsigned short *) video_mem_base;
-    
-    for (;count--; contents++)
-       sun_blitc (*contents, (unsigned long) contents);
-}
-
-unsigned long
-con_type_init(unsigned long kmem_start, const char **display_desc)
-{
-        can_do_color = (con_type != FBTYPE_SUN2BW);
-
-        video_type = VIDEO_TYPE_SUN;
-        *display_desc = "SUN";
-
-       if (!serial_console) {
-               /* If we fall back to PROM than our output have to remain readable. */
-               prom_putchar('\033');  prom_putchar('[');  prom_putchar('H');
-
-               /*
-                * fake the screen memory with some CPU memory
-                */
-               video_mem_base = kmem_start;
-               kmem_start += video_screen_size;
-               video_mem_term = kmem_start;
-
-               render_screen();
-       }
-       return kmem_start;
-}
-
-/*
- * NOTE: get_scrmem() and set_scrmem() are here only because
- * the VGA version of set_scrmem() has some direct VGA references.
- */
-void
-get_scrmem(int currcons)
-{
-       memcpyw((unsigned short *)vc_scrbuf[currcons],
-               (unsigned short *)origin, video_screen_size);
-       origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
-       scr_end = video_mem_end = video_mem_start + video_screen_size;
-       pos = origin + y*video_size_row + (x<<1);
-}
-
-void
-set_scrmem(int currcons, long offset)
-{
-       if (video_mem_term - video_mem_base < offset + video_screen_size)
-               offset = 0;
-       memcpyw((unsigned short *)(video_mem_base + offset),
-               (unsigned short *) origin, video_screen_size);
-       video_mem_start = video_mem_base;
-       video_mem_end = video_mem_term;
-       origin = video_mem_base + offset;
-       scr_end = origin + video_screen_size;
-       pos = origin + y*video_size_row + (x<<1);
-}
-
-/*
- * PIO_FONT support.
- */
-int
-set_get_font(char * arg, int set, int ch512)
-{
-       int error, i, line;
-
-       if (!arg)
-               return -EINVAL;
-       error = verify_area (set ? VERIFY_READ : VERIFY_WRITE, (void *) arg,
-                            ch512 ? 2* cmapsz : cmapsz);
-       if (error)
-               return error;
-
-       /* download the current font */
-       if (!set){
-               memset (arg, 0, cmapsz);
-               for (i = 0; i < 256; i++)
-                   for (line = 0; line < CHAR_HEIGHT; line++)
-                       put_user (vga_font [i], arg+(i*32+line));
-               return 0;
-       }
-       
-        /* set the font */
-       for (i = 0; i < 256; i++)
-               for (line = 0; line < CHAR_HEIGHT; line++){
-                       vga_font [i*CHAR_HEIGHT + line] = (get_user (arg + (i * 32 + line)));
-                       if (con_depth == 1)
-                               vga_font [i*CHAR_HEIGHT + line] = vga_font [i*CHAR_HEIGHT + line];
-               }
-       return 0;
-}
-
-/*
- * Adjust the screen to fit a font of a certain height
- *
- * Returns < 0 for error, 0 if nothing changed, and the number
- * of lines on the adjusted console if changed.
- *
- * for now, we only support the built-in font...
- */
-int
-con_adjust_height(unsigned long fontheight)
-{
-       return -EINVAL;
-}
-
-int
-set_get_cmap(unsigned char * arg, int set)
-{
-       int i;
-
-       i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
-       if (i)
-               return i;
-
-       for (i=0; i<16; i++) {
-               if (set) {
-                       default_red[i] = get_user(arg++) ;
-                       default_grn[i] = get_user(arg++) ;
-                       default_blu[i] = get_user(arg++) ;
-               } else {
-                       put_user (default_red[i], arg++) ;
-                       put_user (default_grn[i], arg++) ;
-                       put_user (default_blu[i], arg++) ;
-               }
-       }
-       if (set) {
-               for (i=0; i<MAX_NR_CONSOLES; i++)
-                       if (vc_cons_allocated(i)) {
-                               int j, k ;
-                               for (j=k=0; j<16; j++) {
-                                       vc_cons[i].d->vc_palette[k++] = default_red[j];
-                                       vc_cons[i].d->vc_palette[k++] = default_grn[j];
-                                       vc_cons[i].d->vc_palette[k++] = default_blu[j];
-                               }
-                       }
-               set_palette();
-       }
-
-       return 0;
-}
-
-
-void
-sun_clear_screen(void)
-{
-       memset (con_fb_base, (con_depth == 1 ? ~(0) : (0)),
-               (con_depth * con_height * con_width) / 8);
-       /* also clear out the "shadow" screen memory */
-       memset((char *)video_mem_base, 0, (video_mem_term - video_mem_base));
-}
-
-/*
- * dummy routines for the VESA blanking code, which is VGA only,
- * so we don't have to carry that stuff around for the Sparc...
- */
-void vesa_blank(void)
-{
-}
-void vesa_unblank(void)
-{
-}
-void set_vesa_blanking(const unsigned long arg)
-{
-}
-
-void vesa_powerdown(void)
-{
-}
-
-#undef color
-/* cg6 cursor status, kernel tracked copy */
-struct cg6_cursor {
-        short   enable;                /* cursor is enabled */
-        struct  fbcurpos cpos; /* position */
-        struct  fbcurpos chot; /* hot-spot */
-        struct  fbcurpos size; /* size of mask & image fields */
-        int     bits[2][32];   /* space for mask & image bits */
-       char    color [6];      /* cursor colors */
-};
-
-struct cg6_info {
-       struct bt_regs *bt;     /* color control */
-       void *fbc;
-       struct cg6_fhc *fhc;
-       struct cg6_tec *tec;
-       struct cg6_thc *thc;
-       struct cg6_cursor cursor; /* cursor control */
-       void *dhc;
-};
-
-struct bwtwo_info {
-        struct bwtwo_regs *regs;
-};
-
-struct cg3_info {
-       struct bt_regs *bt;     /* brooktree (color) registers */
-};
-
-/* Array holding the information for the frame buffers */
-typedef struct {
-       union {
-               struct bwtwo_info bwtwo;
-               struct cg3_info   cg3;
-               struct cg6_info   cg6;
-       } info;                 /* per frame information */
-       int    space;           /* I/O space this card resides in */
-       int    blanked;         /* true if video blanked */
-       int    open;            /* is this fb open? */
-       int    mmaped;          /* has this fb been mmapped? */
-       int    vtconsole;       /* virtual console where it is opened */
-       long   base;            /* frame buffer base    */
-       struct fbtype type;     /* frame buffer type    */
-       int    (*mmap)(struct inode *, struct file *, struct vm_area_struct *, long fb_base, void *);
-       void   (*loadcmap)(void *this, int index, int count);
-       void   (*blank)(void *this);
-       void   (*unblank)(void *this);
-       int    (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long, void *);
-} fbinfo_t;
-
-static fbinfo_t fbinfo [FRAME_BUFFERS];
-
-/* We need to keep a copy of the color map to answer ioctl requests */
-static union {
-       unsigned char   map[256][3];    /* reasonable way to access */
-        unsigned int    raw[256*3/4];   /* hardware wants it like this */
-} color_map;
-
-#define FB_MMAP_VM_FLAGS (VM_SHM| VM_LOCKED)
-
-static int
-fb_open (struct inode * inode, struct file * file)
-{
-       int minor = MINOR (inode->i_rdev);
-
-       if (minor >= FRAME_BUFFERS)
-               return -EBADF;
-       if (fbinfo [minor].open)
-               return -EBUSY;
-       fbinfo [minor].open = 1;
-       fbinfo [minor].mmaped = 0;
-       return 0;
-}
-
-static int
-fb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-       int minor = MINOR (inode->i_rdev);
-       fbinfo_t *fb;
-       struct fbcmap *cmap;
-       int i;
-       
-       if (minor >= FRAME_BUFFERS)
-               return -EBADF;
-       fb = &fbinfo [minor];
-       
-       switch (cmd){
-       case FBIOGTYPE:         /* return frame buffer type */
-               i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbtype));
-               if (i) return i;
-               *(struct fbtype *)arg = (fb->type);
-               break;
-       case FBIOGATTR:{
-               struct fbgattr *fba = (struct fbgattr *) arg;
-               
-               i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbgattr));
-               if (i) return i;
-               fba->real_type = fb->type.fb_type;
-               fba->owner = 0;
-               fba->fbtype = fb->type;
-               fba->sattr.flags = 0;
-               fba->sattr.emu_type = fb->type.fb_type;
-               fba->sattr.dev_specific [0] = -1;
-               fba->emu_types [0] = fb->type.fb_type;
-               fba->emu_types [1] = -1;
-               break;
-       }
-       case FBIOSVIDEO:
-               i = verify_area(VERIFY_READ, (void *)arg, sizeof(int));
-               if (i) return i;
-               
-               if (*(int *)arg){
-                       if (!fb->blanked || !fb->unblank)
-                               break;
-                       (*fb->unblank)(fb);
-                       fb->blanked = 0;
-               } else {
-                       if (fb->blanked || !fb->blank)
-                               break;
-                       (*fb->blank)(fb);
-                       fb->blanked = 1;
-               }
-               break;
-       case FBIOGVIDEO:
-               i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (int));
-               if (i) return i;
-               *(int *) arg = fb->blanked;
-               break;
-       case FBIOPUTCMAP: {     /* load color map entries */
-               char *rp, *gp, *bp;
-               int end, count;;
-               
-               if (!fb->loadcmap)
-                       return -EINVAL;
-               i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap));
-               if (i) return i;
-               cmap = (struct fbcmap *) arg;
-               count = cmap->count;
-               if ((cmap->index < 0) || (cmap->index > 255))
-                       return -EINVAL;
-               if (cmap->index + count > 256)
-                       count = 256 - cmap->index;
-               i = verify_area (VERIFY_READ, rp = cmap->red, cmap->count);
-               if (i) return i;
-               i = verify_area (VERIFY_READ, gp = cmap->green, cmap->count);
-               if (i) return i;
-               i = verify_area (VERIFY_READ, bp = cmap->blue, cmap->count);
-               if (i) return i;
-
-               end = cmap->index + count;
-               for (i = cmap->index; i < end; i++){
-                       color_map.map [i][0] = *rp++;
-                       color_map.map [i][1] = *gp++;
-                       color_map.map [i][2] = *bp++;
-               }
-               (*fb->loadcmap)(fb, cmap->index, count);
-                break;                 
-       }
-
-       default:
-               if (fb->ioctl){
-                       i = fb->ioctl (inode, file, cmd, arg, fb);
-                       if (i == -EINVAL)
-                               printk ("[[FBIO: %8.8x]]\n", cmd);
-                       return i;
-               }
-               printk ("[[FBIO: %8.8x]]\n", cmd);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static void
-fb_close (struct inode * inode, struct file *filp)
-{
-       int minor = MINOR(inode->i_rdev);
-       struct fbcursor cursor;
-       
-       if (minor >= FRAME_BUFFERS)
-               return;
-       if (fbinfo [minor].open)
-               fbinfo [minor].open = 0;
-       vt_cons [fbinfo [minor].vtconsole]->vc_mode = KD_TEXT;
-
-       /* Leaving graphics mode, turn off the cursor */
-       graphics_on = 0;
-       if (fbinfo [minor].mmaped)
-               sun_clear_screen ();
-       cursor.set    = FB_CUR_SETCUR;
-       cursor.enable = 0;
-       fb_ioctl (inode, filp, FBIOSCURPOS, (unsigned long) &cursor);
-       set_palette ();
-       render_screen ();
-       return;
-}
-
-static int
-fb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma)
-{
-       int minor = MINOR (inode->i_rdev);
-       fbinfo_t *fb;
-
-       if (minor >= FRAME_BUFFERS)
-               return -ENXIO;
-       /* FIXME: the fg_console below should actually be the
-        * console on which the invoking process is running
-        */
-       if (vt_cons [fg_console]->vc_mode == KD_GRAPHICS)
-               return -ENXIO;
-       fbinfo [minor].vtconsole = fg_console;
-       fb = &fbinfo [minor];
-
-       if (fb->mmap){
-               int v;
-               
-               v = (*fb->mmap)(inode, file, vma, fb->base, fb);
-               if (v) return v;
-               fbinfo [minor].mmaped = 1;
-               vt_cons [fg_console]->vc_mode = KD_GRAPHICS;
-               graphics_on = 1;
-               return 0;
-       } else
-               return -ENXIO;
-}
-
-static struct file_operations graphdev_fops =
-{
-       NULL,                   /* lseek */
-       NULL,                   /* read */
-       NULL,                   /* write */
-       NULL,                   /* readdir */
-       NULL,                   /* select */
-       fb_ioctl,
-       fb_mmap,
-       fb_open,                /* open */
-       fb_close,               /* close */
-};
-
-/* Call the frame buffer routine for setting the palette */
-void
-set_palette (void)
-{
-       if (console_blanked || vt_cons [fg_console]->vc_mode == KD_GRAPHICS)
-               return;
-
-       if (fbinfo [0].loadcmap){
-               int i, j;
-       
-               /* First keep color_map with the palette colors */
-               for (i = 0; i < 16; i++){
-                       j = color_table [i];
-                       color_map.map [i][0] = default_red [j];
-                       color_map.map [i][1] = default_grn [j];
-                       color_map.map [i][2] = default_blu [j];
-               }
-               (*fbinfo [0].loadcmap)(&fbinfo [0], 0, 16);
-       }
-}
-
-/* Called when returning to prom */
-void
-console_restore_palette (void)
-{
-        if (restore_palette)
-               (*restore_palette) ();
-}
-
-/* This routine should be moved to srmmu.c */
-static __inline__ unsigned int
-srmmu_get_pte (unsigned long addr)
-{
-       register unsigned long entry;
-
-       __asm__ __volatile__("\n\tlda [%1] %2,%0\n\t" :
-                            "=r" (entry):
-                            "r" ((addr & 0xfffff000) | 0x400), "i" (ASI_M_FLUSH_PROBE));
-       return entry;
-}
-
-unsigned int
-get_phys (unsigned int addr)
-{
-       switch (sparc_cpu_model){
-       case sun4c:
-               return sun4c_get_pte (addr) << PAGE_SHIFT;
-       case sun4m:
-               return ((srmmu_get_pte (addr) & 0xffffff00) << 4);
-       default:
-               panic ("get_phys called for unsupported cpu model\n");
-               return 0;
-       }
-}
-
-/* CG6 support code */
-
-/* Offset of interesting structures in the OBIO space */
-/*
- * Brooktree is the video dac and is funny to program on the cg6.
- * (it's even funnier on the cg3)
- * The FBC could be the the frame buffer control
- * The FHC could be the frame buffer hardware control.
- */
-#define CG6_ROM_OFFSET       0x0
-#define CG6_BROOKTREE_OFFSET 0x200000
-#define CG6_DHC_OFFSET       0x240000
-#define CG6_ALT_OFFSET       0x280000
-#define CG6_FHC_OFFSET       0x300000
-#define CG6_THC_OFFSET       0x301000
-#define CG6_FBC_OFFSET       0x700000
-#define CG6_TEC_OFFSET       0x701000
-#define CG6_RAM_OFFSET       0x800000
-
-struct bt_regs {
-       unsigned int  addr;     /* address register */
-       unsigned int  color_map; /* color map */
-       unsigned int  control;  /* control register */
-       unsigned int  cursor;   /* cursor map register */
-};
-
-/* The contents are unknown */
-struct cg6_tec {
-       int tec_matrix;
-       int tec_clip;
-       int tec_vdc;
-};
-
-struct cg6_thc {
-        unsigned int thc_xxx0[512];  /* ??? */
-        unsigned int thc_hsync1;     /* hsync timing */
-        unsigned int thc_hsync2;
-        unsigned int thc_hsync3;
-        unsigned int thc_vsync1;     /* vsync timing */
-        unsigned int thc_vsync2;
-        unsigned int thc_refresh;
-        unsigned int thc_misc;
-        unsigned int thc_xxx1[56];
-        unsigned int thc_cursxy;             /* cursor x,y position (16 bits each) */
-        unsigned int thc_cursmask[32];       /* cursor mask bits */
-        unsigned int thc_cursbits[32];       /* what to show where mask enabled */
-};
-
-static void
-cg6_restore_palette (void)
-{
-       volatile struct bt_regs *bt;
-
-       bt = fbinfo [0].info.cg6.bt;
-       bt->addr = 0;
-       bt->color_map = 0xffffffff;
-       bt->color_map = 0xffffffff;
-       bt->color_map = 0xffffffff;
-}
-
-/* Ugh: X wants to mmap a bunch of cute stuff at the same time :-( */
-/* So, we just mmap the things that are being asked for */
-static int
-cg6_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
-{
-       unsigned int size, page, r, map_size;
-       unsigned int map_offset = 0;
-       fbinfo_t *fb = (fbinfo_t *) xx;
-       
-       size = vma->vm_end - vma->vm_start;
-        if (vma->vm_offset & ~PAGE_MASK)
-                return -ENXIO;
-
-       /* To stop the swapper from even considering these pages */
-       vma->vm_flags |= FB_MMAP_VM_FLAGS;
-       
-       /* Each page, see which map applies */
-       for (page = 0; page < size; ){
-               switch (vma->vm_offset+page){
-               case CG6_TEC:
-                       map_size = PAGE_SIZE;
-                       map_offset = get_phys ((uint)fb->info.cg6.tec);
-                       break;
-               case CG6_FBC:
-                       map_size = PAGE_SIZE;
-                       map_offset = get_phys ((uint)fb->info.cg6.fbc);
-                       break;
-               case CG6_FHC:
-                       map_size = PAGE_SIZE;
-                       map_offset = get_phys ((uint)fb->info.cg6.fhc);
-                       break;
-               case CG6_THC:
-                       map_size = PAGE_SIZE;
-                       map_offset = get_phys ((uint)fb->info.cg6.thc);
-                       break;
-               case CG6_BTREGS:
-                       map_size = PAGE_SIZE;
-                       map_offset = get_phys ((uint)fb->info.cg6.bt);
-                       break;
-                       
-               case CG6_DHC:
-                       map_size = PAGE_SIZE * 40;
-                       map_offset = get_phys ((uint)fb->info.cg6.dhc);
-                       break;
-                       
-               case CG6_ROM:
-                       map_size = 0;
-                       break;
-
-               case CG6_RAM:
-                       map_size = size-page;
-                       map_offset = get_phys ((uint) con_fb_base);
-                       if (map_size < fb->type.fb_size)
-                               map_size = fb->type.fb_size;
-                       break;
-               default:
-                       map_size = 0;
-                       break;
-               }
-               if (!map_size){
-                       page += PAGE_SIZE;
-                       continue;
-               }
-               r = io_remap_page_range (vma->vm_start+page,
-                                        map_offset,
-                                        map_size, vma->vm_page_prot,
-                                        fb->space);
-               if (r) return -EAGAIN;
-               page += map_size;
-       }
-        vma->vm_inode = inode;
-        inode->i_count++;
-        return 0;
-}
-
-#define BT_D4M3(x) ((((x) >> 2) << 1) + ((x) >> 2))     /* (x / 4) * 3 */
-#define BT_D4M4(x) ((x) & ~3)                           /* (x / 4) * 4 */
-
-static void
-cg6_loadcmap (void *fbinfo, int index, int count)
-{
-       fbinfo_t *fb = (fbinfo_t *) fbinfo;
-       struct bt_regs *bt = fb->info.cg6.bt;
-       int i;
-       
-       bt->addr = index << 24;
-       for (i = index; count--; i++){
-               bt->color_map = color_map.map [i][0] << 24;
-               bt->color_map = color_map.map [i][1] << 24;
-               bt->color_map = color_map.map [i][2] << 24;
-       }
-}
-
-/* Load cursor information */
-static void
-cg6_setcursor (struct cg6_info *info)
-{
-       unsigned int v;
-       struct cg6_cursor *c = &info->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);
-       }
-       info->thc->thc_cursxy = v;
-}
-
-#undef pos
-static int
-cg6_scursor (struct fbcursor *cursor, fbinfo_t *fb)
-{
-       int op = cursor->set;
-       volatile struct cg6_thc *thc = fb->info.cg6.thc;
-       struct cg6_cursor *cursor_info = &fb->info.cg6.cursor;
-       int i, bytes = 0;
-       
-       if (op & FB_CUR_SETSHAPE){
-               if ((unsigned int) cursor->size.fbx > 32)
-                       return -EINVAL;
-               if ((unsigned int) cursor->size.fby > 32)
-                       return -EINVAL;
-               bytes = (cursor->size.fby * 32)/8;
-               i = verify_area (VERIFY_READ, cursor->image, bytes);
-               if (i) return i;
-               i = verify_area (VERIFY_READ, cursor->mask, bytes);
-               if (i) return i;
-       }
-       if (op & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)){
-               if (op & FB_CUR_SETCUR)
-                       cursor_info->enable = cursor->enable;
-               if (op & FB_CUR_SETPOS)
-                       cursor_info->cpos = cursor->pos;
-               if (op & FB_CUR_SETHOT)
-                       cursor_info->chot = cursor->hot;
-               cg6_setcursor (&fb->info.cg6);
-       }
-       if (op & FB_CUR_SETSHAPE){
-               unsigned int u;
-               
-               cursor_info->size = cursor->size;
-               memset ((void *)&cursor_info->bits, 0, sizeof (cursor_info->size));
-               memcpy (cursor_info->bits [0], cursor->mask, bytes);
-               memcpy (cursor_info->bits [1], cursor->image, bytes);
-               u = ~0;
-               if (cursor_info->size.fbx < 32)
-                       u = ~(u  >> cursor_info->size.fbx);
-               for (i = 0; i < 32; i++){
-                       int m = cursor_info->bits [0][i] & u;
-                       thc->thc_cursmask [i] = m;
-                       thc->thc_cursbits [i] = m & cursor_info->bits [1][i];
-               }
-       }
-       return 0;
-}
-
-/* Handle cg6-specific ioctls */
-static int
-cg6_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb)
-{
-       int i;
-
-       switch (cmd){
-       case FBIOGCURMAX:
-               i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbcurpos));
-               if (i) return i;
-               ((struct fbcurpos *) arg)->fbx = 32;
-               ((struct fbcurpos *) arg)->fby = 32;
-               break;
-
-       case FBIOSVIDEO:
-               /* vesa_blank and vesa_unblank could do the job on fb [0] */
-               break;
-
-       case FBIOSCURSOR:
-               return cg6_scursor ((struct fbcursor *) arg, fb);
-
-       case FBIOSCURPOS:
-               /*
-               i= verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcurpos));
-               if (i) return i;
-               */
-               fb->info.cg6.cursor.cpos = *(struct fbcurpos *)arg;
-               cg6_setcursor (&fb->info.cg6);
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static void
-cg6_setup (int slot, unsigned int cg6, int cg6_io)
-{
-       struct cg6_info *cg6info;
-
-       printk ("cgsix%d at 0x%8.8x\n", slot, (unsigned int) cg6);
-       
-       /* Fill in parameters we left out */
-       fbinfo [slot].type.fb_cmsize = 256;
-       fbinfo [slot].mmap = cg6_mmap;
-       fbinfo [slot].loadcmap = cg6_loadcmap;
-       fbinfo [slot].ioctl = (void *) cg6_ioctl;
-       fbinfo [slot].blank = 0;
-       fbinfo [slot].unblank = 0;
-       
-       cg6info = (struct cg6_info *) &fbinfo [slot].info.cg6;
-
-       /* Map the hardware registers */
-       cg6info->bt = sparc_alloc_io ((void *) cg6+CG6_BROOKTREE_OFFSET, 0,
-                sizeof (struct bt_regs),"cgsix_dac", cg6_io, 0);
-       cg6info->fhc = sparc_alloc_io ((void *) cg6+CG6_FHC_OFFSET, 0,
-                sizeof (int), "cgsix_fhc", cg6_io, 0);
-       cg6info->thc = sparc_alloc_io ((void *) cg6+CG6_THC_OFFSET, 0,
-                sizeof (struct cg6_thc), "cgsix_thc", cg6_io, 0);
-       cg6info->tec = sparc_alloc_io ((void *) cg6+CG6_TEC_OFFSET, 0,
-                sizeof (struct cg6_tec), "cgsix_tec", cg6_io, 0);
-       cg6info->dhc = sparc_alloc_io ((void *) cg6+CG6_DHC_OFFSET, 0,
-                0x40000, "cgsix_dhc", cg6_io, 0);
-       cg6info->fbc = sparc_alloc_io ((void *) cg6+CG6_FBC_OFFSET, 0,
-                0x1000, "cgsix_fbc", cg6_io, 0);
-       if (!con_fb_base){
-               con_fb_base = sparc_alloc_io ((void *) cg6+CG6_RAM_OFFSET, 0,
-                    fbinfo [slot].type.fb_size, "cgsix_ram", cg6_io, 0);
-       }
-       if (!slot)
-               restore_palette = cg6_restore_palette;
-}
-
-/* The cg3 driver, obio space addresses for mapping the cg3 stuff */
-#define CG3_REGS 0x400000
-#define CG3_RAM  0x800000
-#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2))      /* (x/4)*3 */
-#define D4M4(x) ((x)&~0x3)                      /* (x/4)*4 */
-
-/* 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 */
-static void
-cg3_loadcmap (void *fbinfo, int index, int count)
-{
-       fbinfo_t *fb = (fbinfo_t *) fbinfo;
-       struct bt_regs *bt = fb->info.cg3.bt;
-       int *i, steps;
-
-       i = &color_map.raw [D4M3(index)];
-       steps = D4M3(index+count-1) - D4M3(index)+3;
-       bt->addr = D4M4(index);
-       while (steps--)
-               bt->color_map = *i++;
-}
-
-/* The cg3 is presumed to emulate a cg4, I guess older programs will want that */
-/* addresses above 0x4000000 are for cg3, below that it's cg4 emulation          */
-static int
-cg3_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
-{
-       unsigned int size, page, r, map_size;
-       unsigned int map_offset = 0;
-       fbinfo_t *fb = (fbinfo_t *) xx;
-       
-       size = vma->vm_end - vma->vm_start;
-        if (vma->vm_offset & ~PAGE_MASK)
-                return -ENXIO;
-
-       /* To stop the swapper from even considering these pages */
-       vma->vm_flags |= FB_MMAP_VM_FLAGS; 
-       
-       /* Each page, see which map applies */
-       for (page = 0; page < size; ){
-               switch (vma->vm_offset+page){
-               case CG3_MMAP_OFFSET:
-                       map_size = size-page;
-                       map_offset = get_phys ((uint) con_fb_base);
-                       if (map_size > fb->type.fb_size)
-                               map_size = fb->type.fb_size;
-                       break;
-               default:
-                       map_size = 0;
-                       break;
-               }
-               if (!map_size){
-                       page += PAGE_SIZE;
-                       continue;
-               }
-               r = io_remap_page_range (vma->vm_start+page,
-                                        map_offset,
-                                        map_size, vma->vm_page_prot,
-                                        fb->space);
-               if (r) return -EAGAIN;
-               page += map_size;
-       }
-        vma->vm_inode = inode;
-        inode->i_count++;
-        return 0;
-}
-
-static void
-cg3_setup (int slot, unsigned int cg3, int cg3_io)
-{
-       struct cg3_info *cg3info;
-
-       printk ("cgthree%d at 0x%8.8x\n", slot, cg3);
-       
-       /* Fill in parameters we left out */
-       fbinfo [slot].type.fb_cmsize = 256;
-       fbinfo [slot].mmap = cg3_mmap;
-       fbinfo [slot].loadcmap = cg3_loadcmap;
-       fbinfo [slot].ioctl = 0; /* no special ioctls */
-
-       cg3info = (struct cg3_info *) &fbinfo [slot].info.cg3;
-
-       /* Map the card registers */
-       cg3info->bt = sparc_alloc_io ((void *) cg3+CG3_REGS, 0,
-                sizeof (struct bt_regs),"cg3_bt", cg3_io, 0);
-       
-       if (!con_fb_base){
-               con_fb_base=sparc_alloc_io ((void*) cg3+CG3_RAM, 0,
-                    fbinfo [slot].type.fb_size, "cg3_ram", cg3_io, 0);
-       }
-}
-
-/* OBio addresses for the bwtwo registers */
-#define BWTWO_REGISTER_OFFSET 0x400000
-
-struct bwtwo_regs {
-       char          unknown [16];
-#define BWTWO_ENABLE_VIDEO 0x40
-       unsigned char control;
-       char          unknown2 [15];
-};
-
-static int
-bwtwo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
-{
-       unsigned int size, map_offset, r;
-       fbinfo_t *fb = (fbinfo_t *) xx;
-       int map_size;
-       
-       map_size = size = vma->vm_end - vma->vm_start;
-       
-       if (vma->vm_offset & ~PAGE_MASK)
-               return -ENXIO;
-
-       /* To stop the swapper from even considering these pages */
-       vma->vm_flags |= FB_MMAP_VM_FLAGS;
-       printk ("base=%8.8xl start=%8.8xl size=%x offset=%8.8x\n",
-               (unsigned int) base,
-               (unsigned int) vma->vm_start, size,
-               (unsigned int) vma->vm_offset);
-
-       /* This routine should also map the register if asked for, but we don't do that yet */
-       map_offset = get_phys ((uint) con_fb_base);
-       r = io_remap_page_range (vma->vm_start, map_offset, map_size, vma->vm_page_prot,
-                                fb->space);
-       if (r) return -EAGAIN;
-       vma->vm_inode = inode;
-       inode->i_count++;
-       return 0;
-}
-
-static void
-bwtwo_blank (void *xx)
-{
-       fbinfo_t *fb = (fbinfo_t *) xx;
-
-       fb->info.bwtwo.regs->control &= ~BWTWO_ENABLE_VIDEO;
-}
-
-static void
-bwtwo_unblank (void *xx)
-{
-       fbinfo_t *fb = (fbinfo_t *) xx;
-       fb->info.bwtwo.regs->control |= BWTWO_ENABLE_VIDEO;
-}
-
-static void
-bwtwo_setup (int slot, unsigned int bwtwo, int bw2_io)
-{
-       printk ("bwtwo%d at 0x%8.8x\n", slot, bwtwo);
-       fbinfo [slot].type.fb_cmsize = 2;
-       fbinfo [slot].mmap = bwtwo_mmap;
-       fbinfo [slot].loadcmap = 0;
-       fbinfo [slot].ioctl = 0;
-       fbinfo [slot].blank = bwtwo_blank;
-       fbinfo [slot].unblank = bwtwo_unblank;
-       fbinfo [slot].info.bwtwo.regs = sparc_alloc_io ((void *) bwtwo+BWTWO_REGISTER_OFFSET,
-               0, sizeof (struct bwtwo_regs), "bwtwo_regs", bw2_io, 0);
-}
-
-static char *known_cards [] = {
-       "cgsix", "cgthree", "bwtwo", "SUNW,tcx", 0
-};
-
-static int
-known_card (char *name)
-{
-       int i;
-
-       for (i = 0; known_cards [i]; i++)
-               if (strcmp (name, known_cards [i]) == 0)
-                       return 1;
-       return 0;
-}
-
-static struct {
-       int depth;
-       int resx, resy;
-       int x_margin, y_margin;
-} scr_def [] = {
-       { 1, 1152, 900,  8,  18 },
-       { 8, 1152, 900,  64, 18 },
-       { 8, 1280, 1024, 96, 80 },
-       { 8, 1024, 768,  0,  0 },
-       { 0 },
-};
-
-static int
-sparc_console_probe(void)
-{
-       int propl, con_node, i;
-       struct linux_sbus_device *sbdp;
-       unsigned int fbbase = 0xb001b001;
-       int fbiospace = 0;
-
-       /* XXX The detection code needs to support multiple video cards in one system */
-       con_node = 0;
-       switch(prom_vers) {
-       case PROM_V0:
-               /* V0 proms are at sun4c only. Can skip many checks. */
-               con_type = FBTYPE_NOTYPE;
-               if(SBus_chain == 0) {
-                       prom_printf("SBUS chain is NULL, bailing out...\n");
-                       prom_halt();
-               }
-               for_each_sbusdev(sbdp, SBus_chain) {
-                       con_node = sbdp->prom_node;
-
-                       /* If no "address" than it is not the PROM console. */
-                       if(sbdp->num_vaddrs) {
-                               if(!strncmp(sbdp->prom_name, "cgsix", 5)) {
-                                       con_type = FBTYPE_SUNFAST_COLOR;
-                                       fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
-                                       fbiospace = sbdp->reg_addrs[0].which_io;
-                                       break;
-                               } else if(!strncmp(sbdp->prom_name, "cgthree", 7)) {
-                                       con_type = FBTYPE_SUN3COLOR;
-                                       fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
-                                       fbiospace = sbdp->reg_addrs[0].which_io;
-                                       break;
-                               } else if (!strncmp(sbdp->prom_name, "bwtwo", 5)) {
-                                       con_type = FBTYPE_SUN2BW;
-                                       fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
-                                       fbiospace = sbdp->reg_addrs[0].which_io;
-                                       break;
-                               }
-                       }
-               }
-               if(con_type == FBTYPE_NOTYPE) return -1;
-               con_fb_base = (unsigned char *) sbdp->sbus_vaddrs[0];
-               strncpy(con_name, sbdp->prom_name, sizeof (con_name));
-               break;
-       case PROM_V2:
-       case PROM_V3:
-       case PROM_P1275:
-               for_each_sbusdev(sbdp, SBus_chain) {
-                       if (known_card (sbdp->prom_name))
-                               break;
-               }
-               if (!sbdp){
-                       prom_printf ("Could not find a know video card on this machine\n");
-                       prom_halt ();
-               }
-               prom_apply_sbus_ranges (&sbdp->reg_addrs [0], sbdp->num_registers);
-               fbbase = (long) sbdp->reg_addrs [0].phys_addr;
-               fbiospace = sbdp->reg_addrs[0].which_io;
-               con_node = (*romvec->pv_v2devops.v2_inst2pkg)
-                       (*romvec->pv_v2bootargs.fd_stdout);
-               /*
-                * Determine the type of hardware accelerator.
-                */
-               propl = prom_getproperty(con_node, "emulation", con_name, sizeof (con_name));
-               if (propl < 0 || propl >= sizeof (con_name)) {
-                       /* Early cg3s had no "emulation". */
-                       propl = prom_getproperty(con_node, "name", con_name, sizeof (con_name));
-                       if (propl < 0) {
-                               prom_printf("console: no device name!!\n");
-                               return -1;
-                       }
-               }
-               if(!strncmp(con_name, "cgsix", sizeof (con_name))) {
-                       con_type = FBTYPE_SUNFAST_COLOR;
-               } else if(!strncmp(con_name, "cgthree", sizeof (con_name))) {
-                       con_type = FBTYPE_SUN3COLOR;
-               } else if(!strncmp(con_name, "cgfourteen", sizeof (con_name))) {
-                       con_type = FBTYPE_MDICOLOR;
-               } else if(!strncmp(con_name, "bwtwo", sizeof (con_name))) {
-                       con_type = FBTYPE_SUN2BW;
-               } else if(!strncmp(con_name,"SUNW,tcx", sizeof (con_name))){
-                       con_type = FBTYPE_SUN3COLOR;
-               } else {
-                       prom_printf("console: \"%s\" is unsupported\n", con_name);
-                       return -1;
-               }
-               propl = prom_getproperty(con_node, "address", (char *) &con_fb_base, 4);
-               if (propl != 4) {
-                   con_fb_base = 0;
-               }
-               break;
-       default:
-               return -1;
-       };
-
-       /* Get the device geometry */
-       con_linebytes = prom_getintdefault(con_node, "linebytes", 1152);
-       con_width = prom_getintdefault(con_node, "width", 1152);
-       con_height = prom_getintdefault(con_node, "height", 900);
-
-       /* Currently we just support 1-bit and 8-bit depth displays */
-       if (con_type == FBTYPE_SUN2BW) {
-               con_depth = 1;
-       } else {
-               con_depth = 8;
-       }
-       for (i = 0; scr_def [i].depth; i++){
-               if (scr_def [i].resx != con_width || scr_def [i].resy != con_height)
-                       continue;
-               if (scr_def [i].depth != con_depth)
-                       continue;
-               x_margin = scr_def [i].x_margin;
-               y_margin = scr_def [i].y_margin;
-               chars_per_line = (con_width * con_depth) / 8;
-               skip_bytes = chars_per_line * y_margin;
-               ints_per_line = chars_per_line / 4;
-               bytes_per_row = CHAR_HEIGHT * chars_per_line;
-               break;
-       }
-       if (!scr_def [i].depth){
-               x_margin = y_margin = 0;
-               prom_printf ("PenguinCon: unknown video resolution %dx%d may be slow\n", con_width, con_height);
-               prom_halt ();
-       }
-       /* P3: I fear this strips 15inch 1024/768 PC-like monitors out. */
-       if ((con_linebytes*8) / con_depth != con_width) {
-               prom_printf("console: UNUSUAL VIDEO, linebytes=%d, width=%d, depth=%d\n",
-                       con_linebytes, con_width, con_depth);
-               return -1;
-       }
-
-       /* Negate the font table on 1 bit depth cards so we have white on black */
-       if (con_depth == 1)
-               for(i=0; i<(16 * 256); i++)
-                       vga_font[i] = ~vga_font[i];
-
-       /* Fill in common fb information */
-       fbinfo [0].type.fb_type   = con_type;
-       fbinfo [0].type.fb_height = con_height;
-       fbinfo [0].type.fb_width  = con_width;
-       fbinfo [0].type.fb_depth  = con_depth;
-       fbinfo [0].type.fb_size   = PAGE_ALIGN((con_linebytes) * (con_height));
-       fbinfo [0].space = fbiospace;
-       fbinfo [0].blanked = 0;
-
-       /* Should be filled in for supported video cards */
-       fbinfo [0].mmap = 0; 
-       fbinfo [0].loadcmap = 0;
-       fbinfo [0].ioctl = 0;
-       fbinfo [0].blank = 0;
-       fbinfo [0].unblank = 0;
-
-       if (fbbase == 0xb001b001){
-               printk ("Mail miguel@nuclecu.unam.mx video_card=%d (%s)\n", con_type, con_name);
-       }
-
-       /* Per card setup */
-       switch (con_type){
-       case FBTYPE_SUN3COLOR:
-               cg3_setup (0, fbbase, fbiospace);
-               break;
-       case FBTYPE_SUNFAST_COLOR:
-               cg6_setup (0, fbbase, fbiospace);
-               break;
-       case FBTYPE_SUN2BW:
-               bwtwo_setup (0, fbbase, fbiospace);
-               break;
-       default:
-               break;
-       }
-       if (!con_fb_base){
-               prom_printf ("PROM does not have an 'address' property for this\n"
-                            "frame buffer and the Linux drivers do not know how\n"
-                            "to map the video of this device\n");
-               prom_halt ();
-       }
-       fbinfo [0].base = (long) con_fb_base;
-       
-       /* Register the frame buffer device */
-       if (register_chrdev (GRAPHDEV_MAJOR, "graphics", &graphdev_fops)){
-               printk ("Could not register graphics device\n");
-               return -EIO;
-       }
-       return 0; /* success */
-}
-
-/* video init code, called from within the SBUS bus scanner at
- * boot time.
- */
-void
-sun_console_init(void)
-{
-       if(serial_console)
-               return;
-
-       if(sparc_console_probe()) {
-               prom_printf("Could not probe console, bailing out...\n");
-               prom_halt();
-       }
-       sun_clear_screen();
-}
-
-/*
- * sun_blitc
- *
- * Displays an ASCII character at a specified character cell
- *  position.
- *
- * Called from scr_writew() when the destination is
- *  the "shadow" screen
- */
-static unsigned int
-fontmask_bits[16] = {
-    0x00000000,
-    0x000000ff,
-    0x0000ff00,
-    0x0000ffff,
-    0x00ff0000,
-    0x00ff00ff,
-    0x00ffff00,
-    0x00ffffff,
-    0xff000000,
-    0xff0000ff,
-    0xff00ff00,
-    0xff00ffff,
-    0xffff0000,
-    0xffff00ff,
-    0xffffff00,
-    0xffffffff
-};
-
-int
-sun_blitc(unsigned int charattr, unsigned long addr)
-{
-       int j, idx;
-       unsigned char *font_row;
-
-#ifndef DEBUGGING_X
-       if (graphics_on)
-               return 0;
-#endif
-       idx = (addr - video_mem_base) >> 1;
-
-       /* Invalidate the cursor position if necessary. */
-       if(idx == cursor_pos)
-               cursor_pos = -1;
-       font_row = &vga_font[(charattr & 0xff) << 4];
-
-       switch (con_depth){
-       case 1: {
-               register unsigned char *dst;
-               
-               dst = (unsigned char *)(((unsigned long)con_fb_base) + FBUF_OFFSET(idx));
-               for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst+=CHARS_PER_LINE)
-                       *dst = *font_row;
-               break;
-       }
-       case 8: {
-               register unsigned long *dst;
-               unsigned long fgmask, bgmask, data, rowbits, attrib;
-               const int ipl = ints_per_line;
-               
-               dst = (unsigned long *)(((unsigned long)con_fb_base) + COLOR_FBUF_OFFSET(idx));
-               attrib = (charattr >> 8) & 0x0ff;
-               fgmask = attrib & 0x0f;
-               bgmask = (attrib >> 4) & 0x0f;
-               fgmask = fgmask << 8 | fgmask;
-               fgmask |= fgmask << 16;
-               bgmask = bgmask << 8 | bgmask;
-               bgmask |= bgmask << 16;
-               
-               for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst += ipl) {
-                       rowbits = *font_row;
-                       data = fontmask_bits[(rowbits>>4)&0xf];
-                       data = (data & fgmask) | (~data & bgmask);
-                       *dst = data;
-                       data = fontmask_bits[rowbits&0xf];
-                       data = (data & fgmask) | (~data & bgmask);
-                       *(dst+1) = data;
-               }
-               break;
-       } /* case */
-       } /* switch */
-       return (0);
-}
-
-unsigned char vga_font[cmapsz] = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 
-0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 
-0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 
-0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
-0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
-0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
-0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 
-0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, 
-0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 
-0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 
-0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 
-0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 
-0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 
-0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, 
-0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 
-0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
-0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 
-0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 
-0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 
-0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 
-0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 
-0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 
-0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 
-0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 
-0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
-0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 
-0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 
-0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 
-0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 
-0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 
-0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 
-0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 
-0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 
-0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 
-0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
-0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, 
-0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 
-0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, 
-0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 
-0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 
-0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 
-0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
-0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 
-0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
-0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 
-0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
-0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 
-0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 
-0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 
-0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 
-0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 
-0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 
-0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 
-0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 
-0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 
-0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
-0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 
-0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 
-0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 
-0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 
-0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 
-0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 
-0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
-0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 
-0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 
-0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 
-0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 
-0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, 
-0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 
-0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
-0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 
-0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
-0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 
-0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 
-0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 
-0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 
-0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
-0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
-0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 
-0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 
-0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
-0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 
-0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, 
-0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 
-0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 
-0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 
-0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 
-0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 
-0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
-0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 
-0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 
-0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 
-0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 
-0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 
-0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 
-0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 
-0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 
-0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 
-0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 
-0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
-0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 
-0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-};
diff --git a/drivers/char/sunmouse.c b/drivers/char/sunmouse.c
deleted file mode 100644 (file)
index 9b32cf5..0000000
+++ /dev/null
@@ -1,420 +0,0 @@
-/* sunmouse.c: Sun mouse driver for the Sparc
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
- *
- * Parts based on the psaux.c driver written by:
- * Johan Myreen.
- *
- * Dec/19/95 Added SunOS mouse ioctls - miguel.
- * Jan/5/96  Added VUID support, sigio support - miguel.
- * Mar/5/96  Added proper mouse stream support - miguel.
- */
-
-/* The mouse is run off of one of the Zilog serial ports.  On
- * that port is the mouse and the keyboard, each gets a zs channel.
- * The mouse itself is mouse-systems in nature.  So the protocol is:
- *
- * Byte 1) Button state which is bit-encoded as
- *            0x4 == left-button down, else up
- *            0x2 == middle-button down, else up
- *            0x1 == right-button down, else up
- *
- * Byte 2) Delta-x
- * Byte 3) Delta-y
- * Byte 4) Delta-x again
- * Byte 5) Delta-y again
- *
- * One day this driver will have to support more than one mouse in the system.
- *
- * This driver has two modes of operation: the default VUID_NATIVE is
- * set when the device is opened and allows the application to see the
- * mouse character stream as we get it from the serial (for gpm for
- * example).  The second method, VUID_FIRM_EVENT will provide cooked
- * events in Firm_event records.
- * */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fcntl.h>
-#include <linux/signal.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/mm.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <asm/vuid_event.h>
-#include <linux/random.h>
-/* The following keeps track of software state for the Sun
- * mouse.
- */
-#define STREAM_SIZE   2048
-#define EV_SIZE       (STREAM_SIZE/sizeof (Firm_event))
-#define BUTTON_LEFT   4
-#define BUTTON_MIDDLE 2
-#define BUTTON_RIGHT  1
-
-struct sun_mouse {
-       unsigned char transaction[5];  /* Each protocol transaction */
-       unsigned char byte;            /* Counter, starts at 0 */
-       unsigned char button_state;    /* Current button state */
-       unsigned char prev_state;      /* Previous button state */
-       int delta_x;                   /* Current delta-x */
-       int delta_y;                   /* Current delta-y */
-       int present;
-       int ready;                     /* set if there if data is available */
-       int active;                    /* set if device is open */
-        int vuid_mode;                /* VUID_NATIVE or VUID_FIRM_EVENT */
-       struct wait_queue *proc_list;
-       struct fasync_struct *fasync;
-       
-       /* The event/stream queue */
-       unsigned int head;
-       unsigned int tail;
-       union {
-               char stream [STREAM_SIZE];
-               Firm_event ev [0];
-       } queue;
-};
-
-static struct sun_mouse sunmouse;
-#define gen_events (sunmouse.vuid_mode != VUID_NATIVE)
-#define bstate sunmouse.button_state
-#define pstate sunmouse.prev_state
-
-extern void mouse_put_char(char ch);
-
-/* #define SMOUSE_DEBUG */
-
-static void
-push_event (Firm_event *ev)
-{
-       int next = (sunmouse.head + 1) % EV_SIZE;
-       
-       if (next != sunmouse.tail){
-               sunmouse.queue.ev [sunmouse.head] = *ev;
-               sunmouse.head = next;
-       }
-}
-
-static int
-queue_empty (void)
-{
-       return sunmouse.head == sunmouse.tail;
-}
-
-static Firm_event *
-get_from_queue (void)
-{
-       Firm_event *result;
-       
-       result = &sunmouse.queue.ev [sunmouse.tail];
-       sunmouse.tail = (sunmouse.tail + 1) % EV_SIZE;
-       return result;
-}
-
-static void
-push_char (char c)
-{
-       int next = (sunmouse.head + 1) % STREAM_SIZE;
-
-       if (next != sunmouse.tail){
-               sunmouse.queue.stream [sunmouse.head] = c;
-               sunmouse.head = next;
-       }
-       sunmouse.ready = 1;
-       if (sunmouse.fasync)
-               kill_fasync (sunmouse.fasync, SIGIO);
-       wake_up_interruptible (&sunmouse.proc_list);
-}
-
-/* The following is called from the zs driver when bytes are received on
- * the Mouse zs8530 channel.
- */
-void
-sun_mouse_inbyte(unsigned char byte, unsigned char status)
-{
-       signed char mvalue;
-       int d;
-       Firm_event ev;
-
-       add_mouse_randomness (byte);
-       if(!sunmouse.active)
-               return;
-
-       if (!gen_events){
-               push_char (byte);
-               return;
-       }
-       /* Check for framing errors and parity errors */
-       /* XXX TODO XXX */
-
-       /* If the mouse sends us a byte from 0x80 to 0x87
-        * we are starting at byte zero in the transaction
-        * protocol.
-        */
-       if(byte >= 0x80 && byte <= 0x87)
-               sunmouse.byte = 0;
-
-       mvalue = (signed char) byte;
-       switch(sunmouse.byte) {
-       case 0:
-               /* Button state */
-               sunmouse.button_state = (~byte) & 0x7;
-#ifdef SMOUSE_DEBUG
-               printk("B<Left %s, Middle %s, Right %s>",
-                      ((sunmouse.button_state & 0x4) ? "DOWN" : "UP"),
-                      ((sunmouse.button_state & 0x2) ? "DOWN" : "UP"),
-                      ((sunmouse.button_state & 0x1) ? "DOWN" : "UP"));
-#endif
-               sunmouse.byte++;
-               return;
-       case 1:
-               /* Delta-x 1 */
-#ifdef SMOUSE_DEBUG
-               printk("DX1<%d>", mvalue);
-#endif
-               sunmouse.delta_x = mvalue;
-               sunmouse.byte++;
-               return;
-       case 2:
-               /* Delta-y 1 */
-#ifdef SMOUSE_DEBUG
-               printk("DY1<%d>", mvalue);
-#endif
-               sunmouse.delta_y = mvalue;
-               sunmouse.byte++;
-               return;
-       case 3:
-               /* Delta-x 2 */
-#ifdef SMOUSE_DEBUG
-               printk("DX2<%d>", mvalue);
-#endif
-               sunmouse.delta_x += mvalue;
-               sunmouse.byte++;
-               return;
-       case 4:
-               /* Last byte, Delta-y 2 */
-#ifdef SMOUSE_DEBUG
-               printk("DY2<%d>", mvalue);
-#endif
-               sunmouse.delta_y += mvalue;
-               sunmouse.byte = 69;  /* Some ridiculous value */
-               break;
-       case 69:
-               /* Until we get the (0x80 -> 0x87) value we aren't
-                * in the middle of a real transaction, so just
-                * return.
-                */
-               return;
-       default:
-               printk("sunmouse: bogon transaction state\n");
-               sunmouse.byte = 69;  /* What could cause this? */
-               return;
-       };
-       d = bstate ^ pstate;
-       pstate = bstate;
-       if (d){
-               if (d & BUTTON_LEFT){
-                       ev.id = MS_LEFT;
-                       ev.value = bstate & BUTTON_LEFT;
-               }
-               if (d & BUTTON_RIGHT){
-                       ev.id = MS_RIGHT;
-                       ev.value = bstate & BUTTON_RIGHT;
-               }
-               if (d & BUTTON_MIDDLE){
-                       ev.id = MS_MIDDLE;
-                       ev.value = bstate & BUTTON_MIDDLE;
-               }
-               ev.time = xtime;
-               ev.value = ev.value ? VKEY_DOWN : VKEY_UP;
-               push_event (&ev);
-       }
-       if (sunmouse.delta_x){
-               ev.id = LOC_X_DELTA;
-               ev.time = xtime;
-               ev.value = sunmouse.delta_x;
-               push_event (&ev);
-               sunmouse.delta_x = 0;
-       }
-       if (sunmouse.delta_y){
-               ev.id = LOC_Y_DELTA;
-               ev.time = xtime;
-               ev.value = sunmouse.delta_y;
-               push_event (&ev);
-       }
-       
-        /* We just completed a transaction, wake up whoever is awaiting
-        * this event.
-        */
-       sunmouse.ready = 1;
-       if (sunmouse.fasync)
-               kill_fasync (sunmouse.fasync, SIGIO);
-       wake_up_interruptible(&sunmouse.proc_list);
-       return;
-}
-
-static int
-sun_mouse_open(struct inode * inode, struct file * file)
-{
-       if(!sunmouse.present)
-               return -EINVAL;
-       if(sunmouse.active)
-               return -EBUSY;
-       sunmouse.active = 1;
-       sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0;
-       sunmouse.button_state = 0x80;
-       sunmouse.vuid_mode = VUID_NATIVE;
-       return 0;
-}
-
-static int
-sun_mouse_fasync (struct inode *inode, struct file *filp, int on)
-{
-       int retval;
-
-       retval = fasync_helper (inode, filp, on, &sunmouse.fasync);
-       if (retval < 0)
-               return retval;
-       return 0;
-}
-
-static void
-sun_mouse_close(struct inode *inode, struct file *file)
-{
-       sunmouse.active = sunmouse.ready = 0;
-       sun_mouse_fasync (inode, file, 0);
-}
-
-static int
-sun_mouse_write(struct inode *inode, struct file *file, const char *buffer,
-               int count)
-{
-       return -EINVAL;  /* foo on you */
-}
-
-static int
-sun_mouse_read(struct inode *inode, struct file *file, char *buffer,
-              int count)
-{
-       struct wait_queue wait = { current, NULL };
-
-       if (queue_empty ()){
-               if (file->f_flags & O_NONBLOCK)
-                       return -EWOULDBLOCK;
-               add_wait_queue (&sunmouse.proc_list, &wait);
-               while (queue_empty () && !(current->signal & ~current->blocked)){
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule ();
-               }
-               current->state = TASK_RUNNING;
-               remove_wait_queue (&sunmouse.proc_list, &wait);
-       }
-       if (gen_events){
-               char *p = buffer, *end = buffer+count;
-               
-               while (p < end && !queue_empty ()){
-                       *(Firm_event *)p = *get_from_queue ();
-                       p += sizeof (Firm_event);
-               }
-               sunmouse.ready = !queue_empty ();
-               inode->i_atime = CURRENT_TIME;
-               return p-buffer;
-       } else {
-               int c;
-               
-               for (c = count; !queue_empty () && c; c--){
-                       *buffer++ = sunmouse.queue.stream [sunmouse.tail];
-                       sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE;
-               }
-               sunmouse.ready = !queue_empty ();
-               inode->i_atime = CURRENT_TIME;
-               return count-c;
-       }
-       /* Only called if nothing was sent */
-       if (current->signal & ~current->blocked)
-               return -ERESTARTSYS;
-       return 0;
-}
-
-static int
-sun_mouse_select(struct inode *inode, struct file *file, int sel_type,
-                           select_table *wait)
-{
-       if(sel_type != SEL_IN)
-               return 0;
-       if(sunmouse.ready)
-               return 1;
-       select_wait(&sunmouse.proc_list, wait);
-       return 0;
-}
-int
-sun_mouse_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-       int i;
-       
-       switch (cmd){
-               /* VUIDGFORMAT - Get input device byte stream format */
-       case _IOR('v', 2, int):
-               i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (int));
-               if (i) return i;
-               *(int *)arg = sunmouse.vuid_mode;
-               break;
-
-               /* VUIDSFORMAT - Set input device byte stream format*/
-       case _IOW('v', 1, int):
-               i = verify_area (VERIFY_READ, (void *)arg, sizeof (int));
-               if (i) return i;
-               i = *(int *) arg;
-               if (i == VUID_NATIVE || i == VUID_FIRM_EVENT){
-                       sunmouse.vuid_mode = *(int *)arg;
-                       sunmouse.head = sunmouse.tail = 0;
-               } else
-                       return -EINVAL;
-               break;
-               
-       default:
-               printk ("[MOUSE-ioctl: %8.8x]\n", cmd);
-               return -1;
-       }
-       return 0;
-}
-
-struct file_operations sun_mouse_fops = {
-       NULL,
-       sun_mouse_read,
-       sun_mouse_write,
-       NULL,
-       sun_mouse_select,
-       sun_mouse_ioctl,
-       NULL,
-       sun_mouse_open,
-       sun_mouse_close,
-       NULL,
-       sun_mouse_fasync,
-};
-
-static struct miscdevice sun_mouse_mouse = {
-       SUN_MOUSE_MINOR, "sunmouse", &sun_mouse_fops
-};
-
-int
-sun_mouse_init(void)
-{
-       printk("Sun Mouse-Systems mouse driver version 1.00\n");
-       sunmouse.present = 1;
-       sunmouse.ready = sunmouse.active = 0;
-       misc_register (&sun_mouse_mouse);
-       sunmouse.delta_x = sunmouse.delta_y = 0;
-       sunmouse.button_state = 0x80;
-       sunmouse.proc_list = NULL;
-       return 0;
-}
-
-void
-sun_mouse_zsinit(void)
-{
-       sunmouse.ready = 1;
-}
index a96ee074ad03d5cff3c9c9acdde0c2c9000cea79..e8517c89da16b741cd163525427c03cf9805cda3 100644 (file)
@@ -221,7 +221,6 @@ int el3_probe(struct device *dev)
                lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state;
        }
 
-       current_tag = dev->name[3]-'0';
        /* For the first probe, clear all board's tag registers. */
        if (current_tag == 0)
                outb(0xd0, id_port);
@@ -266,10 +265,6 @@ int el3_probe(struct device *dev)
 
        /* Free the interrupt so that some other card can use it. */
        outw(0x0f00, ioaddr + WN0_IRQ);
-
-       if( check_region(ioaddr, EL3_IO_EXTENT) )
-               return -ENODEV;
-
  found:
        dev->base_addr = ioaddr;
        dev->irq = irq;
index 7947aaa82708a25440ee3b987b0af9797f835c84..5c9012559558975c85a590b82eba6aca3c381270 100644 (file)
@@ -51,12 +51,12 @@ if [ "$CONFIG_NET_ISA" = "y" ]; then
   tristate 'Cabletron E21xx support' CONFIG_E2100
   tristate 'DEPCA support' CONFIG_DEPCA
   tristate 'EtherWorks 3 support' CONFIG_EWRK3
+  tristate 'EtherExpress 16 support' CONFIG_EEXPRESS
   if [ "$CONFIG_NET_ALPHA" = "y" ]; then
     bool 'SEEQ8005 support' CONFIG_SEEQ8005
     tristate 'AT1700 support' CONFIG_AT1700
     tristate 'FMV-181/182 support' CONFIG_FMV18X
     tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO
-    tristate 'EtherExpress support' CONFIG_EEXPRESS
     tristate 'NI5210 support' CONFIG_NI52
     bool 'NI6510 support' CONFIG_NI65
     tristate 'WaveLAN support' CONFIG_WAVELAN
index e59afeb94a63bd65f5ce81df40b50511066f6a38..bd81722a83307f39782f4edd7469201024253a82 100644 (file)
@@ -450,6 +450,22 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_ATARILANCE),y)
+L_OBJS += atarilance.o
+else
+  ifeq ($(CONFIG_ATARILANCE),m)
+  M_OBJS += atarilance.o
+  endif
+endif
+
+ifeq ($(CONFIG_A2065),y)
+L_OBJS += a2065.o
+else
+  ifeq ($(CONFIG_A2065),m)
+  M_OBJS += a2065.o
+  endif
+endif
+
 ifeq ($(CONFIG_SDLA),y)
 L_OBJS += sdla.o
 else
@@ -466,6 +482,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_ARIADNE),y)
+L_OBJS += ariadne.o
+else
+  ifeq ($(CONFIG_ARIADNE),m)
+  M_OBJS += ariadne.o
+  endif
+endif
+
 ifeq ($(CONFIG_DGRS),y)
 L_OBJS += dgrs.o
 else
index 8ccd863fdf52643c3567d4d9154edceca2292449..c6c146ed7aae0ff2a382ee178a7fbdcda761d013 100644 (file)
@@ -74,6 +74,9 @@ extern int tc59x_probe(struct device *);
 extern int dgrs_probe(struct device *);
 extern int smc_init( struct device * );
 extern int sparc_lance_probe(struct device *);
+extern int atarilance_probe(struct device *);
+extern int a2065_probe(struct device *);
+extern int ariadne_probe(struct device *);
 
 /* Detachable devices ("pocket adaptors") */
 extern int atp_init(struct device *);
@@ -191,6 +194,15 @@ ethif_probe(struct device *dev)
 #ifdef CONFIG_NI52
        && ni52_probe(dev)
 #endif
+#ifdef CONFIG_ATARILANCE       /* Lance-based Atari ethernet boards */
+       && atarilance_probe(dev)
+#endif
+#ifdef CONFIG_A2065            /* Commodore/Ameristar A2065 Ethernet Board */
+       && a2065_probe(dev)
+#endif
+#ifdef CONFIG_ARIADNE          /* Village Tronic Ariadne Ethernet Board */
+       && ariadne_probe(dev)
+#endif
 #ifdef CONFIG_SUNLANCE
        && sparc_lance_probe(dev)
 #endif
index df974b73e1ad9a795b0f17f31a254e7bee4d8fb6..85d0eb813d74335c0cb04eacc79dbad90dd449e1 100644 (file)
@@ -346,7 +346,7 @@ static void a2065_interrupt(int irq, struct pt_regs *fp, void *data)
 
        board->Lance.RAP = CSR0;        /* LANCE Controller Status */
 
-       if (!(board->Lance.RDP & INTR)) /* Check if any interrrupt has
+       if (!(board->Lance.RDP & INTR)) /* Check if any interrupt has
                                           been generated by the board. */
                return;
 
index 7282150bf300f72317263a6d048be87992875c8f..e44ab8026c80386570522494328a331181f5e169 100644 (file)
@@ -394,7 +394,7 @@ static void ariadne_interrupt(int irq, struct pt_regs *fp, void *data)
 
     board->Lance.RAP = CSR0;   /* PCnet-ISA Controller Status */
 
-    if (!(board->Lance.RDP & INTR))    /* Check if any interrrupt has been
+    if (!(board->Lance.RDP & INTR))    /* Check if any interrupt has been
        return;                            generated by the board. */
 
     if (dev->interrupt)
index ebd47ae2b16e6a9a73b1baf1df7c5aaaaa33b3bc..6b04e450b2032731c904450f128dc3522529b65b 100644 (file)
@@ -122,8 +122,8 @@ struct Am79C960 {
 #define CSR61          0x3d00  /*   Previous Transmit Descriptor Address */
 #define CSR62          0x3e00  /*   Previous Transmit Status and Byte Count */
 #define CSR63          0x3f00  /*   Previous Transmit Status and Byte Count */
-#define CSR64          0x4000  /*   Next Transmit Buffer Addres */
-#define CSR65          0x4100  /*   Next Transmit Buffer Addres */
+#define CSR64          0x4000  /*   Next Transmit Buffer Address */
+#define CSR65          0x4100  /*   Next Transmit Buffer Address */
 #define CSR66          0x4200  /*   Next Transmit Status and Byte Count */
 #define CSR67          0x4300  /*   Next Transmit Status and Byte Count */
 #define CSR68          0x4400  /*   Transmit Status Temporary Storage */
index 8daeee2a7dd398d37f2fd8ef64f8029f570823cd..2e843537f03c8669fa2550b7ce35aa1a7023fb98 100644 (file)
@@ -219,7 +219,7 @@ struct lance_private {
        struct lance_ioreg      *iobase;
        struct lance_memory     *mem;
        int                                     cur_rx, cur_tx; /* The next free ring entry */
-       int                                     dirty_tx;               /* Ring entries to be freeed. */
+       int                                     dirty_tx;               /* Ring entries to be freed. */
                                                /* copy function */
        void                            *(*memcpy_f)( void *, const void *, size_t );
        struct enet_statistics stats;
@@ -303,7 +303,7 @@ struct lance_addr {
 #define CSR2   2               /* init block addr (high) */
 #define CSR3   3               /* misc */
 #define CSR8   8               /* address filter */
-#define CSR15  15              /* promiscous mode */
+#define CSR15  15              /* promiscuous mode */
 
 /* CSR0 */
 /* (R=readable, W=writeable, S=set on write, C=clear on write) */
index 6fe2dec65362227af6c770f2f5ac7fa69f91c5c5..402b3302394b2d99f03b42696b2495efdebefc4a 100644 (file)
     patched this  driver to detect it  because the SROM format used complies
     to a previous DEC-STD format.
 
+    I have removed the buffer copies needed for receive on Intels.  I cannot
+    remove them for   Alphas since  the  Tulip hardware   only does longword
+    aligned  DMA transfers  and  the  Alphas get   alignment traps with  non
+    longword aligned data copies (which makes them really slow). No comment.
+
     TO DO:
     ------
 
                          Duh, put the SA_SHIRQ flag into request_interrupt().
                          Fix SMC ethernet address in enet_det[].
                          Print chip name instead of "UNKNOWN" during boot.
+      0.42    26-Apr-96   Fix MII write TA bit error.
+                          Fix bug in dc21040 and dc21041 autosense code.
+                         Remove buffer copies on receive for Intels.
+                         Change sk_buff handling during media disconnects to
+                         eliminate DUP packets.
+                         Add dynamic TX thresholding.
+                         Change all chips to use perfect multicast filtering.
+                         Fix alloc_device() bug <jari@markkus2.fimr.fi>
 
     =========================================================================
 */
 
-static const char *version = "de4x5.c:v0.41 96/3/21 davies@wanton.lkg.dec.com\n";
+static const char *version = "de4x5.c:v0.42 96/4/26 davies@wanton.lkg.dec.com\n";
 
 #include <linux/module.h>
 
@@ -298,6 +311,7 @@ static s32 de4x5_full_duplex = 0;
 ** Ethernet Info
 */
 #define PKT_BUF_SZ     1536            /* Buffer size for each Tx/Rx buffer */
+#define IEEE802_3_SZ    1518            /* Packet + CRC */
 #define MAX_PKT_SZ     1514            /* Maximum ethernet packet length */
 #define MAX_DAT_SZ     1500            /* Maximum ethernet data length */
 #define MIN_DAT_SZ     1               /* Minimum ethernet data length */
@@ -418,6 +432,7 @@ struct de4x5_srom {
     char info[100];
     short chksum;
 };
+#define SUB_VENDOR_ID 0x500a
 
 /*
 ** DE4X5 Descriptors. Make sure that all the RX buffers are contiguous
@@ -451,7 +466,8 @@ struct de4x5_private {
     char adapter_name[80];                  /* Adapter name                 */
     struct de4x5_desc rx_ring[NUM_RX_DESC]; /* RX descriptor ring           */
     struct de4x5_desc tx_ring[NUM_TX_DESC]; /* TX descriptor ring           */
-    struct sk_buff *skb[NUM_TX_DESC];       /* TX skb for freeing when sent */
+    struct sk_buff *tx_skb[NUM_TX_DESC];    /* TX skb for freeing when sent */
+    struct sk_buff *rx_skb[NUM_RX_DESC];    /* RX skb's                     */
     int rx_new, rx_old;                     /* RX descriptor ring pointers  */
     int tx_new, tx_old;                     /* TX descriptor ring pointers  */
     char setup_frame[SETUP_FRAME_LEN];      /* Holds MCA and PA info.       */
@@ -531,6 +547,8 @@ static struct bus_type {
                        lp->tx_old+lp->txRingSize-lp->tx_new-1:\
                        lp->tx_old               -lp->tx_new-1)
 
+#define TX_PKT_PENDING (lp->tx_old != lp->tx_new)
+
 /*
 ** Public Functions
 */
@@ -551,6 +569,7 @@ static int     de4x5_sw_reset(struct device *dev);
 static int     de4x5_rx(struct device *dev);
 static int     de4x5_tx(struct device *dev);
 static int     de4x5_ast(struct device *dev);
+static int     de4x5_txur(struct device *dev);
 
 static int     autoconf_media(struct device *dev);
 static void    create_packet(struct device *dev, char *frame, int len);
@@ -563,13 +582,16 @@ static int     dc21140m_autoconf(struct device *dev);
 static int     de4x5_suspect_state(struct device *dev, int timeout, int prev_state, int (*fn)(struct device *, int), int (*asfn)(struct device *));
 static int     dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout, int next_state, int suspect_state, int (*fn)(struct device *, int));
 static int     test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec);
-/*static int     test_sym_link(struct device *dev, u32 msec);*/
+static int     test_sym_link(struct device *dev, int msec);
 static int     test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec);
 static int     is_spd_100(struct device *dev);
 static int     is_100_up(struct device *dev);
 static int     is_10_up(struct device *dev);
 static int     is_anc_capable(struct device *dev);
 static int     ping_media(struct device *dev, int msec);
+static struct sk_buff *de4x5_alloc_rx_buff(struct device *dev, int index, int len);
+static void    de4x5_free_rx_buffs(struct device *dev);
+static void    de4x5_free_tx_buffs(struct device *dev);
 static void    de4x5_save_skbs(struct device *dev);
 static void    de4x5_restore_skbs(struct device *dev);
 static void    de4x5_cache_state(struct device *dev, int flag);
@@ -621,6 +643,7 @@ static void    de4x5_dbg_open(struct device *dev);
 static void    de4x5_dbg_mii(struct device *dev, int k);
 static void    de4x5_dbg_media(struct device *dev);
 static void    de4x5_dbg_srom(struct de4x5_srom *p);
+static void    de4x5_dbg_rx(struct sk_buff *skb, int len);
 static int     de4x5_strncmp(char *a, char *b, int n);
 
 #ifdef MODULE
@@ -655,7 +678,8 @@ static int num_de4x5s = 0, num_eth = 0;
 ** more info. Until I fix (un)register_netdevice() we won't be able to use it
 ** though.
 */
-int de4x5_probe(struct device *dev)
+int
+de4x5_probe(struct device *dev)
 {
     int tmp = num_de4x5s, status = -ENODEV;
     u_long iobase = dev->base_addr;
@@ -793,62 +817,66 @@ de4x5_hw_init(struct device *dev, u_long iobase)
        sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
        
        /*
-       ** Allocate contiguous receive buffers, long word aligned. 
+       ** Set up the RX descriptor ring (Intels)
+       ** Allocate contiguous receive buffers, long word aligned (Alphas) 
        */
+#ifndef __alpha__
+       for (i=0; i<NUM_RX_DESC; i++) {
+           lp->rx_ring[i].status = 0;
+           lp->rx_ring[i].des1 = RX_BUFF_SZ;
+           lp->rx_ring[i].buf = 0;
+           lp->rx_ring[i].next = 0;
+           lp->rx_skb[i] = (struct sk_buff *) 1;     /* Dummy entry */
+       }
+
+#else
        if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN, 
-                                  GFP_KERNEL)) != NULL) {
-           lp->cache.buf = tmp;
-           tmp = (char *)(((u_long) tmp + ALIGN) & ~ALIGN);
-           for (i=0; i<NUM_RX_DESC; i++) {
-               lp->rx_ring[i].status = 0;
-               lp->rx_ring[i].des1 = RX_BUFF_SZ;
-               lp->rx_ring[i].buf = virt_to_bus(tmp + i * RX_BUFF_SZ);
-               lp->rx_ring[i].next = (u32)NULL;
-           }
-           barrier();
+                                  GFP_KERNEL)) == NULL) {
+           kfree(lp->cache.priv);
+           return -ENOMEM;
+       }
+
+       lp->cache.buf = tmp;
+       tmp = (char *)(((u_long) tmp + ALIGN) & ~ALIGN);
+       for (i=0; i<NUM_RX_DESC; i++) {
+           lp->rx_ring[i].status = 0;
+           lp->rx_ring[i].des1 = RX_BUFF_SZ;
+           lp->rx_ring[i].buf = virt_to_bus(tmp + i * RX_BUFF_SZ);
+           lp->rx_ring[i].next = 0;
+           lp->rx_skb[i] = (struct sk_buff *) 1;     /* Dummy entry */
+       }
+#endif
+
+       barrier();
            
-           request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE :
-                                   DE4X5_EISA_TOTAL_SIZE), 
-                          lp->adapter_name);
+       request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE :
+                               DE4X5_EISA_TOTAL_SIZE), 
+                      lp->adapter_name);
            
-           lp->rxRingSize = NUM_RX_DESC;
-           lp->txRingSize = NUM_TX_DESC;
+       lp->rxRingSize = NUM_RX_DESC;
+       lp->txRingSize = NUM_TX_DESC;
            
-           /* Write the end of list marker to the descriptor lists */
-           lp->rx_ring[lp->rxRingSize - 1].des1 |= RD_RER;
-           lp->tx_ring[lp->txRingSize - 1].des1 |= TD_TER;
+       /* Write the end of list marker to the descriptor lists */
+       lp->rx_ring[lp->rxRingSize - 1].des1 |= RD_RER;
+       lp->tx_ring[lp->txRingSize - 1].des1 |= TD_TER;
            
-           /* Tell the adapter where the TX/RX rings are located. */
-           outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
-           outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
+       /* Tell the adapter where the TX/RX rings are located. */
+       outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
+       outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
            
-           /* Initialise the IRQ mask and Enable/Disable */
-           lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM ;
-           lp->irq_en   = IMR_NIM | IMR_AIM;
+       /* Initialise the IRQ mask and Enable/Disable */
+       lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM | IMR_UNM;
+       lp->irq_en   = IMR_NIM | IMR_AIM;
 
-           /* Create a loopback packet frame for later media probing */
-           create_packet(dev, lp->frame, sizeof(lp->frame));
+       /* Create a loopback packet frame for later media probing */
+       create_packet(dev, lp->frame, sizeof(lp->frame));
 
-           /* Initialise the adapter state */
-           lp->state = CLOSED;
+       /* Initialise the adapter state */
+       lp->state = CLOSED;
+
+       printk("      and requires IRQ%d (provided by %s).\n", dev->irq,
+              ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
 
-           printk("      and requires IRQ%d (provided by %s).\n", dev->irq,
-                  ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
-       } else {
-           printk("%s: Kernel could not allocate RX buffer memory.\n", dev->name);
-       }
-       if (status) {
-           release_region(iobase, (lp->bus == PCI ? 
-                                   DE4X5_PCI_TOTAL_SIZE :
-                                   DE4X5_EISA_TOTAL_SIZE));
-           if (lp->rx_ring[0].buf) {
-               kfree(bus_to_virt(lp->rx_ring[0].buf));
-           }
-           kfree(dev->priv);
-           dev->priv = NULL;
-           
-           return -ENXIO;
-       }
     }
     
     if (de4x5_debug > 0) {
@@ -883,9 +911,17 @@ de4x5_open(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-    int status = 0;
+    int i, status = 0;
     s32 omr;
     
+    /* Allocate the RX buffers */
+    for (i=0; i<lp->rxRingSize; i++) {
+       if (de4x5_alloc_rx_buff(dev, i, 0) == NULL) {
+           de4x5_free_rx_buffs(dev);
+           return -EAGAIN;
+       }
+    }
+
     /*
     ** Wake up the adapter
     */
@@ -893,14 +929,13 @@ de4x5_open(struct device *dev)
        outl(0, PCI_CFDA);
        de4x5_ms_delay(10);
     }
-    
-    lp->state = OPEN;
-    
+
     /* 
     ** Re-initialize the DE4X5... 
     */
     status = de4x5_init(dev);
     
+    lp->state = OPEN;
     de4x5_dbg_open(dev);
     
     if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ, 
@@ -937,7 +972,7 @@ de4x5_open(struct device *dev)
 /*
 ** Initialize the DE4X5 operating conditions. NB: a chip problem with the
 ** DC21140 requires using perfect filtering mode for that chip. Since I can't
-** see why I'd want > 14 multicast addresses, I may change all chips to use
+** see why I'd want > 14 multicast addresses, I have changed all chips to use
 ** the perfect filtering mode. Keep the DMA burst length at 8: there seems
 ** to be data corruption problems if it is larger (UDP errors seen from a
 ** ttcp source).
@@ -956,7 +991,8 @@ de4x5_init(struct device *dev)
     return 0;
 }
 
-static int de4x5_sw_reset(struct device *dev)
+static int
+de4x5_sw_reset(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -978,14 +1014,11 @@ static int de4x5_sw_reset(struct device *dev)
     bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | CACHE_ALIGN;
     outl(bmr, DE4X5_BMR);
     
-    omr = inl(DE4X5_OMR) & ~OMR_PR;             /* Turn of promiscuous mode */
-    if (lp->chipset != DC21140) {
-       omr |= TR_96;
-       lp->setup_f = HASH_PERF;
-    } else {
-       omr |= OMR_SDP | OMR_SB | (!lp->phy[lp->active].id ? OMR_SF : 0);
-       lp->setup_f = PERFECT;
+    omr = inl(DE4X5_OMR) & ~OMR_PR;             /* Turn off promiscuous mode */
+    if (lp->chipset == DC21140) {
+       omr |= (OMR_SDP | OMR_SB);
     }
+    lp->setup_f = PERFECT;
     outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
     outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
     
@@ -1005,11 +1038,7 @@ static int de4x5_sw_reset(struct device *dev)
     /* Build the setup frame depending on filtering mode */
     SetMulticastFilter(dev);
     
-    if (lp->chipset != DC21140) {
-       load_packet(dev, lp->setup_frame, HASH_F|TD_SET|SETUP_FRAME_LEN, NULL);
-    } else {
-       load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL);
-    }
+    load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL);
     outl(omr|OMR_ST, DE4X5_OMR);
     
     /* Poll for setup frame completion (adapter interrupts are disabled now) */
@@ -1041,15 +1070,14 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     int status = 0;
-    
+
     if (skb == NULL) {
        dev_tint(dev);
        return 0;
     }
 
     if (lp->tx_enable == NO) {                   /* Cannot send for now */
-       de4x5_put_cache(dev, skb);               /* Queue the buffer locally */
-       return 0;                                
+       return -1;                                
     }
     
     /*
@@ -1063,14 +1091,14 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
     sti();
     
     /* Transmit descriptor ring full or stale skb */
-    if (dev->tbusy || lp->skb[lp->tx_new]) {
+    if (dev->tbusy || lp->tx_skb[lp->tx_new]) {
        if (dev->interrupt) {
            de4x5_putb_cache(dev, skb);          /* Requeue the buffer */
        } else {
            de4x5_put_cache(dev, skb);
        }
        if (de4x5_debug > 1) {
-           printk("%s: transmit busy, lost media or stale skb found:\n  STS:%08x\n  tbusy:%ld\n  lostMedia:%d\n  IMR:%08x\n  OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->skb[lp->tx_new] ? "YES" : "NO"));
+           printk("%s: transmit busy, lost media or stale skb found:\n  STS:%08x\n  tbusy:%ld\n  lostMedia:%d\n  IMR:%08x\n  OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO"));
        }
     } else if (skb->len > 0) {
        /* If we already have stuff queued locally, use that first */
@@ -1079,7 +1107,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
            skb = de4x5_get_cache(dev);
        }
 
-       while (skb && !dev->tbusy && !lp->skb[lp->tx_new]) {
+       while (skb && !dev->tbusy && !lp->tx_skb[lp->tx_new]) {
            set_bit(0, (void*)&dev->tbusy);
            cli();
            if (TX_BUFFS_AVAIL) {           /* Fill in a Tx ring entry */
@@ -1097,7 +1125,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
            }
            sti();
        }
-       if (skb && (dev->tbusy || lp->skb[lp->tx_new])) {
+       if (skb && (dev->tbusy || lp->tx_skb[lp->tx_new])) {
            de4x5_putb_cache(dev, skb);
        }
     }
@@ -1121,7 +1149,7 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
     struct device *dev = (struct device *)dev_id;
     struct de4x5_private *lp;
-    s32 imr, omr, sts;
+    s32 imr, omr, sts, limit;
     u_long iobase;
     
     if (dev == NULL) {
@@ -1137,7 +1165,7 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
     DISABLE_IRQs;                        /* Ensure non re-entrancy */
     dev->interrupt = MASK_INTERRUPTS;
        
-    for (;;) {
+    for (limit=0; limit<8; limit++) {
        sts = inl(DE4X5_STS);            /* Read IRQ status */
        outl(sts, DE4X5_STS);            /* Reset the board interrupts */
            
@@ -1154,6 +1182,10 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
            lp->irq_mask &= ~IMR_LFM;
        }
            
+       if (sts & STS_UNF) {             /* Transmit underrun */
+           de4x5_txur(dev);
+       }
+           
        if (sts & STS_SE) {              /* Bus Error */
            STOP_DE4X5;
            printk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n",
@@ -1204,24 +1236,15 @@ de4x5_rx(struct device *dev)
                struct sk_buff *skb;
                short pkt_len = (short)(lp->rx_ring[entry].status >> 16) - 4;
                
-               if ((skb = dev_alloc_skb(pkt_len+2)) == NULL) {
+               if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) {
                    printk("%s: Insufficient memory; nuking packet.\n", 
                                                                    dev->name);
                    lp->stats.rx_dropped++;   /* Really, deferred. */
                    break;
                }
+               de4x5_dbg_rx(skb, pkt_len);
 
-               skb->dev = dev;
-               skb_reserve(skb,2);           /* Align */
-               if (entry < lp->rx_old) {     /* Wrapped buffer */
-                   short len = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ;
-                   memcpy(skb_put(skb,len), bus_to_virt(lp->rx_ring[lp->rx_old].buf), len);
-                   memcpy(skb_put(skb,pkt_len-len), bus_to_virt(lp->rx_ring[0].buf), pkt_len - len);
-               } else {                      /* Linear buffer */
-                   memcpy(skb_put(skb,pkt_len), bus_to_virt(lp->rx_ring[lp->rx_old].buf), pkt_len);
-               }
-                   
-               /* Push up the protocol stack */
+       /* Push up the protocol stack */
                skb->protocol=eth_type_trans(skb,dev);
                netif_rx(skb);
                    
@@ -1284,29 +1307,32 @@ de4x5_tx(struct device *dev)
        status = lp->tx_ring[entry].status;
        if (status < 0) {                     /* Buffer not sent yet */
            break;
-       } else if (status & TD_ES) {          /* An error happened */
-           lp->stats.tx_errors++; 
-           if (status & TD_NC)  lp->stats.tx_carrier_errors++;
-           if (status & TD_LC)  lp->stats.tx_window_errors++;
-           if (status & TD_UF)  lp->stats.tx_fifo_errors++;
-           if (status & TD_LC)  lp->stats.collisions++;
-           if (status & TD_EC)  lp->pktStats.excessive_collisions++;
-           if (status & TD_DE)  lp->stats.tx_aborted_errors++;
+       } else if (status != 0x7fffffff) {    /* Not setup frame */
+           if (status & TD_ES) {             /* An error happened */
+               lp->stats.tx_errors++; 
+               if (status & TD_NC) lp->stats.tx_carrier_errors++;
+               if (status & TD_LC) lp->stats.tx_window_errors++;
+               if (status & TD_UF) lp->stats.tx_fifo_errors++;
+               if (status & TD_LC) lp->stats.collisions++;
+               if (status & TD_EC) lp->pktStats.excessive_collisions++;
+               if (status & TD_DE) lp->stats.tx_aborted_errors++;
            
-           if ((status != 0x7fffffff) &&     /* Not setup frame */
-               (status & (TD_LO | TD_NC | TD_EC | TD_LF))) {
-               lp->lostMedia++;
-           } else {
-               outl(POLL_DEMAND, DE4X5_TPD); /* Restart a stalled TX */
+               if (status & (TD_LO | TD_NC | TD_EC | TD_LF)) {
+                   lp->lostMedia++;
+               }
+               if (TX_PKT_PENDING) {
+                   outl(POLL_DEMAND, DE4X5_TPD);/* Restart a stalled TX */
+               }
+           } else {                      /* Packet sent */
+               lp->stats.tx_packets++;
+               lp->lostMedia = 0;        /* Remove transient problem */
+               lp->linkOK++;
+           }
+           /* Free the buffer. */
+           if (lp->tx_skb[entry] != NULL) {
+               dev_kfree_skb(lp->tx_skb[entry], FREE_WRITE);
+               lp->tx_skb[entry] = NULL;
            }
-       } else {                              /* Packet sent */
-           lp->stats.tx_packets++;
-           lp->lostMedia = 0;                /* Remove transient problem */
-       }
-       /* Free the buffer if it's not a setup frame. */
-       if (lp->skb[entry] != NULL) {
-           dev_kfree_skb(lp->skb[entry], FREE_WRITE);
-           lp->skb[entry] = NULL;
        }
        
        /* Update all the pointers */
@@ -1342,6 +1368,29 @@ de4x5_ast(struct device *dev)
     return 0;
 }
 
+static int
+de4x5_txur(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int iobase = dev->base_addr;
+    int omr;
+
+    omr = inl(DE4X5_OMR);
+    if (!(omr & OMR_SF)) {
+       omr &= ~(OMR_ST|OMR_SR);
+       outl(omr, DE4X5_OMR);
+       while (inl(DE4X5_STS) & STS_TS);
+       if ((omr & OMR_TR) < OMR_TR) {
+           omr += 0x4000;
+       } else {
+           omr |= OMR_SF;
+       }
+       outl(omr | OMR_ST | OMR_SR, DE4X5_OMR);
+    }
+    
+    return 0;
+}
+
 static int
 de4x5_close(struct device *dev)
 {
@@ -1362,14 +1411,15 @@ de4x5_close(struct device *dev)
     ** We stop the DE4X5 here... mask interrupts and stop TX & RX
     */
     DISABLE_IRQs;
-    
     STOP_DE4X5;
     
-    /*
-    ** Free the associated irq
-    */
+    /* Free the associated irq */
     free_irq(dev->irq, dev);
     lp->state = CLOSED;
+
+    /* Free any socket buffers */
+    de4x5_free_rx_buffs(dev);
+    de4x5_free_tx_buffs(dev);
     
     MOD_DEC_USE_COUNT;
     
@@ -1393,14 +1443,15 @@ de4x5_get_stats(struct device *dev)
     return &lp->stats;
 }
 
-static void load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb)
+static void
+load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     
     lp->tx_ring[lp->tx_new].buf = virt_to_bus(buf);
     lp->tx_ring[lp->tx_new].des1 &= TD_TER;
     lp->tx_ring[lp->tx_new].des1 |= flags;
-    lp->skb[lp->tx_new] = skb;
+    lp->tx_skb[lp->tx_new] = skb;
     barrier();
     lp->tx_ring[lp->tx_new].status = T_OWN;
     barrier();
@@ -1426,13 +1477,8 @@ set_multicast_list(struct device *dev)
            outl(omr, DE4X5_OMR);
        } else { 
            SetMulticastFilter(dev);
-           if (lp->setup_f == HASH_PERF) {
-               load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | 
-                           SETUP_FRAME_LEN, NULL);
-           } else {
-               load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
-                           SETUP_FRAME_LEN, NULL);
-           }
+           load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
+                                                       SETUP_FRAME_LEN, NULL);
            
            lp->tx_new = (++lp->tx_new) % lp->txRingSize;
            outl(POLL_DEMAND, DE4X5_TPD);       /* Start the TX */
@@ -1448,7 +1494,8 @@ set_multicast_list(struct device *dev)
 ** from a list of ethernet multicast addresses.
 ** Little endian crc one liner from Matt Thomas, DEC.
 */
-static void SetMulticastFilter(struct device *dev)
+static void
+SetMulticastFilter(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct dev_mc_list *dmi=dev->mc_list;
@@ -1508,7 +1555,8 @@ static void SetMulticastFilter(struct device *dev)
 ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
 ** the motherboard. Upto 15 EISA devices are supported.
 */
-static void eisa_probe(struct device *dev, u_long ioaddr)
+static void
+eisa_probe(struct device *dev, u_long ioaddr)
 {
     int i, maxSlots, status;
     u_short vendor, device;
@@ -1575,7 +1623,8 @@ static void eisa_probe(struct device *dev, u_long ioaddr)
 #define PCI_DEVICE    (dev_num << 3)
 #define PCI_LAST_DEV  32
 
-static void pci_probe(struct device *dev, u_long ioaddr)
+static void
+pci_probe(struct device *dev, u_long ioaddr)
 {
     u_char irq;
     u_char pb, pbus, dev_num, dnum, dev_fn;
@@ -1583,7 +1632,7 @@ static void pci_probe(struct device *dev, u_long ioaddr)
     u_int class = DE4X5_CLASS_CODE;
     u_int iobase;
     struct bus_type *lp = &bus;
-    
+
     if ((!ioaddr || !loading_module) && autoprobed) return;
     
     if (!pcibios_present()) return;          /* No PCI bus in this machine! */
@@ -1607,7 +1656,7 @@ static void pci_probe(struct device *dev, u_long ioaddr)
            pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
            pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &device);
            if (!(is_DC21040 || is_DC21041 || is_DC21140)) continue;
-           
+
            /* Set the device number information */
            lp->device = dev_num;
            lp->bus_num = pb;
@@ -1626,14 +1675,13 @@ static void pci_probe(struct device *dev, u_long ioaddr)
            /* Check if I/O accesses and Bus Mastering are enabled */
            pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
            if (!(status & PCI_COMMAND_IO)) continue;
-           
            if (!(status & PCI_COMMAND_MASTER)) {
                status |= PCI_COMMAND_MASTER;
                pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
                pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
            }
            if (!(status & PCI_COMMAND_MASTER)) continue;
-           
+
            DevicePresent(DE4X5_APROM);
            if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
                if ((dev = alloc_device(dev, iobase)) != NULL) {
@@ -1657,7 +1705,8 @@ static void pci_probe(struct device *dev, u_long ioaddr)
 ** Allocate the device by pointing to the next available space in the
 ** device structure. Should one not be available, it is created.
 */
-static struct device *alloc_device(struct device *dev, u_long iobase)
+static struct device *
+alloc_device(struct device *dev, u_long iobase)
 {
     int addAutoProbe = 0;
     struct device *tmp = NULL, *ret;
@@ -1700,7 +1749,7 @@ static struct device *alloc_device(struct device *dev, u_long iobase)
            ** and initialize it (name, I/O address, next device (NULL) and
            ** initialisation probe routine).
            */
-           dev->name = (char *)(dev + sizeof(struct device));
+           dev->name = (char *)(dev + 1);
            if (num_eth > 9999) {
                sprintf(dev->name,"eth????");/* New device name */
            } else {
@@ -1739,7 +1788,7 @@ static struct device *alloc_device(struct device *dev, u_long iobase)
                    ** area and initialize it (name, I/O address, next device
                    ** (NULL) and initialisation probe routine).
                    */
-                   tmp->name = (char *)(tmp + sizeof(struct device));
+                   tmp->name = (char *)(tmp + 1);
                    if (num_eth > 9999) {
                        sprintf(tmp->name,"eth????");
                    } else {               /* New device name */
@@ -1765,7 +1814,8 @@ static struct device *alloc_device(struct device *dev, u_long iobase)
 ** [TP] or no recent receive activity) to check whether the user has been 
 ** sneaky and changed the port on us.
 */
-static int autoconf_media(struct device *dev)
+static int
+autoconf_media(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -1783,7 +1833,7 @@ static int autoconf_media(struct device *dev)
     } else if (lp->chipset == DC21140) {
        next_tick = dc21140m_autoconf(dev);
     }
-    if (lp->autosense == AUTO) enable_ast(dev, next_tick);
+    enable_ast(dev, next_tick);
     
     return (lp->media);
 }
@@ -1800,7 +1850,8 @@ static int autoconf_media(struct device *dev)
 ** I may have to "age out" locally queued packets so that the higher layer
 ** timeouts don't effectively duplicate packets on the network.
 */
-static int dc21040_autoconf(struct device *dev)
+static int
+dc21040_autoconf(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -1827,32 +1878,32 @@ static int dc21040_autoconf(struct device *dev)
        break;
        
       case TP:
-       dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, 
+       next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, 
                                                         TP_SUSPECT, test_tp);
        break;
        
       case TP_SUSPECT:
-       de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf);
+       next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf);
        break;
        
       case BNC:
       case AUI:
       case BNC_AUI:
-       dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, 
+       next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, 
                                                  BNC_AUI_SUSPECT, ping_media);
        break;
        
       case BNC_AUI_SUSPECT:
-       de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf);
+       next_tick = de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf);
        break;
        
       case EXT_SIA:
-       dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, 
+       next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, 
                                              NC, EXT_SIA_SUSPECT, ping_media);
        break;
        
       case EXT_SIA_SUSPECT:
-       de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf);
+       next_tick = de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf);
        break;
        
       case NC:
@@ -1862,7 +1913,10 @@ static int dc21040_autoconf(struct device *dev)
        /* JAE: for Alpha, default to BNC/AUI, *not* TP */
        reset_init_sia(dev, 0x8f09, 0x0705, 0x0006);
 #endif  /* i386 */
-       de4x5_dbg_media(dev);
+       if (lp->media != lp->c_media) {
+           de4x5_dbg_media(dev);
+           lp->c_media = lp->media;
+       }
        lp->media = INIT;
        lp->tx_enable = NO;
        break;
@@ -1953,7 +2007,8 @@ de4x5_suspect_state(struct device *dev, int timeout, int prev_state,
 ** any more packets to be queued to the hardware. Re-enable everything only
 ** when the media is found.
 */
-static int dc21041_autoconf(struct device *dev)
+static int
+dc21041_autoconf(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2013,6 +2068,7 @@ static int dc21041_autoconf(struct device *dev)
                    lp->media = TP;
                    next_tick = dc21041_autoconf(dev);
                } else {
+                   lp->local_state = 1;
                    de4x5_init_connection(dev);
                }
            }
@@ -2023,7 +2079,7 @@ static int dc21041_autoconf(struct device *dev)
        break;
        
       case ANS_SUSPECT:
-       de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf);
+       next_tick = de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf);
        break;
        
       case TP:
@@ -2046,6 +2102,7 @@ static int dc21041_autoconf(struct device *dev)
                    }
                    next_tick = dc21041_autoconf(dev);
                } else {
+                   lp->local_state = 1;
                    de4x5_init_connection(dev);
                }
            }
@@ -2056,7 +2113,7 @@ static int dc21041_autoconf(struct device *dev)
        break;
        
       case TP_SUSPECT:
-       de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf);
+       next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf);
        break;
        
       case AUI:
@@ -2067,7 +2124,7 @@ static int dc21041_autoconf(struct device *dev)
            }
            irqs = 0;
            irq_mask = 0;
-           sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf7fd, 0x000e, 1000);
+           sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf73d, 0x000e, 1000);
            if (sts < 0) {
                next_tick = sts & ~TIMER_CB;
            } else {
@@ -2075,6 +2132,7 @@ static int dc21041_autoconf(struct device *dev)
                    lp->media = BNC;
                    next_tick = dc21041_autoconf(dev);
                } else {
+                   lp->local_state = 1;
                    de4x5_init_connection(dev);
                }
            }
@@ -2085,7 +2143,7 @@ static int dc21041_autoconf(struct device *dev)
        break;
        
       case AUI_SUSPECT:
-       de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf);
+       next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf);
        break;
        
       case BNC:
@@ -2097,7 +2155,7 @@ static int dc21041_autoconf(struct device *dev)
            }
            irqs = 0;
            irq_mask = 0;
-           sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf7fd, 0x0006, 1000);
+           sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf73d, 0x0006, 1000);
            if (sts < 0) {
                next_tick = sts & ~TIMER_CB;
            } else {
@@ -2131,14 +2189,17 @@ static int dc21041_autoconf(struct device *dev)
        break;
        
       case BNC_SUSPECT:
-       de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf);
+       next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf);
        break;
        
       case NC:
        omr = inl(DE4X5_OMR);    /* Set up full duplex for the autonegotiate */
        outl(omr | OMR_FD, DE4X5_OMR);
        reset_init_sia(dev, 0xef01, 0xffff, 0x0008);/* Initialise the SIA */
-       de4x5_dbg_media(dev);
+       if (lp->media != lp->c_media) {
+           de4x5_dbg_media(dev);
+           lp->c_media = lp->media;
+       }
        lp->media = INIT;
        lp->tx_enable = NO;
        break;
@@ -2147,10 +2208,16 @@ static int dc21041_autoconf(struct device *dev)
     return next_tick;
 }
 
-static int dc21140m_autoconf(struct device *dev)
+/*
+** Some autonegotiation chips are broken in that they do not return the
+** acknowledge bit (anlpa & MII_ANLPA_ACK) in the link partner advertisement
+** register, except at the first power up negotiation.
+*/
+static int
+dc21140m_autoconf(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int ana, anlpa, cap, cr, sr, iobase = dev->base_addr;
+    int ana, anlpa, cap, cr, slnk, sr, iobase = dev->base_addr;
     int next_tick = DE4X5_AUTOSENSE_MS;
     u_long imr, omr;
     
@@ -2163,12 +2230,14 @@ static int dc21140m_autoconf(struct device *dev)
            next_tick &= ~TIMER_CB;
        } else {
            de4x5_save_skbs(dev);          /* Save non transmitted skb's */
+           lp->tmp = MII_SR_ASSC;         /* Fake out the MII speed set */
            SET_10Mb;
            if (lp->autosense == _100Mb) {
                lp->media = _100Mb;
            } else if (lp->autosense == _10Mb) {
                lp->media = _10Mb;
-           } else if ((lp->autosense == AUTO) && (sr=is_anc_capable(dev))) {
+           } else if ((lp->autosense == AUTO) && 
+                                    ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
                ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
                ana &= (de4x5_full_duplex ? ~0 : ~MII_ANA_FDAM);
                mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
@@ -2206,21 +2275,23 @@ static int dc21140m_autoconf(struct device *dev)
            break;
            
          case 1:
-           if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 3000)) < 0) {
+           if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
                next_tick = sr & ~TIMER_CB;
            } else {
                lp->media = SPD_DET;
                lp->local_state = 0;
                if (sr) {                         /* Success! */
+                   lp->tmp = MII_SR_ASSC;
                    anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII);
                    ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
-                   if ((anlpa & MII_ANLPA_ACK) && !(anlpa & MII_ANLPA_RF) &&
-                       (cap = anlpa & MII_ANLPA_TAF & ana)) {
+                   if (!(anlpa & MII_ANLPA_RF) && 
+                        (cap = anlpa & MII_ANLPA_TAF & ana)) {
                        if (cap & MII_ANA_100M) {
                            de4x5_full_duplex = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
                            lp->media = _100Mb;
                        } else if (cap & MII_ANA_10M) {
                            de4x5_full_duplex = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
+
                            lp->media = _10Mb;
                        }
                    }
@@ -2232,17 +2303,23 @@ static int dc21140m_autoconf(struct device *dev)
        break;
        
       case SPD_DET:                              /* Choose 10Mb/s or 100Mb/s */
-       if (!lp->phy[lp->active].id) {
-           outl(GEP_FDXD | GEP_MODE, DE4X5_GEP);
+        if (lp->timeout < 0) {
+           lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS :
+                                                 (~inl(DE4X5_GEP) & GEP_LNP));
+           SET_100Mb_PDET;
        }
-       if (is_spd_100(dev) && is_100_up(dev)) {
-           lp->media = _100Mb;
-       } else if (!is_spd_100(dev) && is_10_up(dev)) {
-           lp->media = _10Mb;
+        if ((slnk = test_sym_link(dev, 6200)) < 0) {
+           next_tick = slnk & ~TIMER_CB;
        } else {
-           lp->media = NC;
+           if (is_spd_100(dev) && is_100_up(dev)) {
+               lp->media = _100Mb;
+           } else if ((!is_spd_100(dev) && (is_10_up(dev) & lp->tmp))) {
+               lp->media = _10Mb;
+           } else {
+               lp->media = NC;
+           }
+           next_tick = dc21140m_autoconf(dev);
        }
-       next_tick = dc21140m_autoconf(dev);
        break;
        
       case _100Mb:                               /* Set 100Mb/s */
@@ -2276,8 +2353,10 @@ static int dc21140m_autoconf(struct device *dev)
        break;
        
       case NC:
-       SET_10Mb;
-       de4x5_dbg_media(dev);
+        if (lp->media != lp->c_media) {
+           de4x5_dbg_media(dev);
+           lp->c_media = lp->media;
+       }
        lp->media = INIT;
        lp->tx_enable = FALSE;
        break;
@@ -2286,12 +2365,16 @@ static int dc21140m_autoconf(struct device *dev)
     return next_tick;
 }
 
-static void de4x5_init_connection(struct device *dev)
+static void
+de4x5_init_connection(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
 
-    de4x5_dbg_media(dev);
+    if (lp->media != lp->c_media) {
+        de4x5_dbg_media(dev);
+       lp->c_media = lp->media;          /* Stop scrolling media messages */
+    }
     de4x5_restore_skbs(dev);
     cli();
     de4x5_rx(dev);
@@ -2304,7 +2387,8 @@ static void de4x5_init_connection(struct device *dev)
     return;
 }
 
-static int de4x5_reset_phy(struct device *dev)
+static int
+de4x5_reset_phy(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2360,7 +2444,8 @@ test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32
     return sts;
 }
 
-static int test_tp(struct device *dev, s32 msec)
+static int
+test_tp(struct device *dev, s32 msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2381,11 +2466,37 @@ static int test_tp(struct device *dev, s32 msec)
     return sisr;
 }
 
+static int
+test_sym_link(struct device *dev, int msec)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int iobase = dev->base_addr;
+    int gep = 0;
+    
+    if (lp->timeout < 0) {
+       lp->timeout = msec/100;
+    }
+    
+    if (lp->phy[lp->active].id) {
+       gep = ((is_100_up(dev) && is_spd_100(dev)) ? GEP_SLNK : 0);
+    } else {
+       gep = (~inl(DE4X5_GEP) & (GEP_SLNK | GEP_LNP));
+    }
+    if (!(gep & GEP_SLNK) && --lp->timeout) {
+       gep = 100 | TIMER_CB;
+    } else {
+       lp->timeout = -1;
+    }
+    
+    return gep;
+}
+
 /*
 **
 **
 */
-static int test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec)
+static int
+test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int test, iobase = dev->base_addr;
@@ -2395,7 +2506,7 @@ static int test_mii_reg(struct device *dev, int reg, int mask, int pol, long mse
     }
     
     if (pol) pol = ~0;
-    reg = mii_rd(reg, lp->phy[lp->active].addr, DE4X5_MII) & mask;
+    reg = mii_rd((u_char)reg, lp->phy[lp->active].addr, DE4X5_MII) & mask;
     test = (reg ^ pol) & mask;
     
     if (test && --lp->timeout) {
@@ -2407,7 +2518,8 @@ static int test_mii_reg(struct device *dev, int reg, int mask, int pol, long mse
     return reg;
 }
 
-static int is_spd_100(struct device *dev)
+static int
+is_spd_100(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2424,7 +2536,8 @@ static int is_spd_100(struct device *dev)
     return spd;
 }
 
-static int is_100_up(struct device *dev)
+static int
+is_100_up(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2438,7 +2551,8 @@ static int is_100_up(struct device *dev)
     }
 }
 
-static int is_10_up(struct device *dev)
+static int
+is_10_up(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2452,13 +2566,14 @@ static int is_10_up(struct device *dev)
     }
 }
 
-static int is_anc_capable(struct device *dev)
+static int
+is_anc_capable(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     
     if (lp->phy[lp->active].id) {
-       return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_ANC);
+       return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII));
     } else {
        return 0;
     }
@@ -2468,7 +2583,8 @@ static int is_anc_capable(struct device *dev)
 ** Send a packet onto the media and watch for send errors that indicate the
 ** media is bad or unconnected.
 */
-static int ping_media(struct device *dev, int msec)
+static int
+ping_media(struct device *dev, int msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2500,6 +2616,95 @@ static int ping_media(struct device *dev, int msec)
     return sisr;
 }
 
+/*
+** This function does 2 things: on Intels it kmalloc's another buffer to
+** replace the one about to be passed up. On Alpha's it kmallocs a buffer
+** into which the packet is copied.
+*/
+static struct sk_buff *
+de4x5_alloc_rx_buff(struct device *dev, int index, int len)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct sk_buff *p;
+
+#ifndef __alpha__
+    struct sk_buff *ret;
+    u_long i=0, tmp;
+
+    p = dev_alloc_skb(IEEE802_3_SZ + ALIGN + 2);
+    if (!p) return NULL;
+
+    p->dev = dev;
+    tmp = virt_to_bus(p->data);
+    i = ((tmp + ALIGN) & ~ALIGN) - tmp;
+    skb_reserve(p, i);
+    lp->rx_ring[index].buf = tmp + i;
+
+    ret = lp->rx_skb[index];
+    lp->rx_skb[index] = p;
+    skb_put(ret, len);
+
+    return ret;
+
+#else
+    if (lp->state != OPEN) return (struct sk_buff *)1; /* Fake out the open */
+
+    p = dev_alloc_skb(len + 2);
+    if (!p) return NULL;
+
+    p->dev = dev;
+    skb_reserve(p, 2);                                /* Align */
+    if (index < lp->rx_old) {                          /* Wrapped buffer */
+       short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ;
+       memcpy(skb_put(p,tlen), bus_to_virt(lp->rx_ring[lp->rx_old].buf),tlen);
+       memcpy(skb_put(p,len-tlen), bus_to_virt(lp->rx_ring[0].buf), len-tlen);
+    } else {                                           /* Linear buffer */
+       memcpy(skb_put(p,len), bus_to_virt(lp->rx_ring[lp->rx_old].buf),len);
+    }
+                   
+    return p;
+#endif
+}
+
+static void
+de4x5_free_rx_buffs(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int i;
+
+    for (i=0; i<lp->rxRingSize; i++) {
+       if (lp->rx_skb[i]) {
+           dev_kfree_skb(lp->rx_skb[i], FREE_WRITE);
+       }
+       lp->rx_ring[i].status = 0;
+       lp->rx_skb[i] = (struct sk_buff *)1;    /* Dummy entry */
+    }
+
+    return;
+}
+
+static void
+de4x5_free_tx_buffs(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int i;
+
+    for (i=0; i<lp->txRingSize; i++) {
+       if (lp->tx_skb[i]) {
+           dev_kfree_skb(lp->tx_skb[i], FREE_WRITE);
+           lp->tx_skb[i] = NULL;
+       }
+       lp->tx_ring[i].status = 0;
+    }
+
+    /* Unload the locally queued packets */
+    while (lp->cache.skb) {
+       dev_kfree_skb(de4x5_get_cache(dev), FREE_WRITE);
+    }
+
+    return;
+}
+
 /*
 ** When a user pulls a connection, the DECchip can end up in a
 ** 'running - waiting for end of transmission' state. This means that we
@@ -2507,28 +2712,17 @@ static int ping_media(struct device *dev, int msec)
 ** the hardware and software and make any media probes using a loopback
 ** packet meaningful.
 */
-static void de4x5_save_skbs(struct device *dev)
+static void
+de4x5_save_skbs(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-    int i;
     s32 omr;
 
     if (!lp->cache.save_cnt) {
        STOP_DE4X5;
        de4x5_tx(dev);                          /* Flush any sent skb's */
-       for (i=lp->tx_new; i!=lp->tx_old; i--) {
-           if (lp->skb[i]) {
-               de4x5_putb_cache(dev, lp->skb[i]);
-               lp->skb[i] = NULL;
-           }
-           if (i==0) i=lp->txRingSize;
-       }
-        if (lp->skb[i]) {
-           de4x5_putb_cache(dev, lp->skb[i]);
-           lp->skb[i] = NULL;
-       }
-
+       de4x5_free_tx_buffs(dev);
        de4x5_cache_state(dev, DE4X5_SAVE_STATE);
        de4x5_sw_reset(dev);
        de4x5_cache_state(dev, DE4X5_RESTORE_STATE);
@@ -2540,12 +2734,11 @@ static void de4x5_save_skbs(struct device *dev)
     return;
 }
 
-static void de4x5_restore_skbs(struct device *dev)
+static void
+de4x5_restore_skbs(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-    struct sk_buff *skb;
-    int i;
     s32 omr;
 
     if (lp->cache.save_cnt) {
@@ -2553,16 +2746,7 @@ static void de4x5_restore_skbs(struct device *dev)
        de4x5_cache_state(dev, DE4X5_SAVE_STATE);
        de4x5_sw_reset(dev);
        de4x5_cache_state(dev, DE4X5_RESTORE_STATE);
-       dev->tbusy = 1;
-
-       for (i=0; TX_BUFFS_AVAIL && lp->cache.skb; i++) {
-           skb = de4x5_get_cache(dev);
-           load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
-           lp->tx_new = (++lp->tx_new) % lp->txRingSize;
-       }
-       if (TX_BUFFS_AVAIL) {
-           dev->tbusy = 0;
-       }
+       dev->tbusy = 0;
        lp->cache.save_cnt--;
        START_DE4X5;
     }
@@ -2570,7 +2754,8 @@ static void de4x5_restore_skbs(struct device *dev)
     return;
 }
 
-static void de4x5_cache_state(struct device *dev, int flag)
+static void
+de4x5_cache_state(struct device *dev, int flag)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2609,7 +2794,8 @@ static void de4x5_cache_state(struct device *dev, int flag)
     return;
 }
 
-static void de4x5_put_cache(struct device *dev, struct sk_buff *skb)
+static void
+de4x5_put_cache(struct device *dev, struct sk_buff *skb)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct sk_buff *p;
@@ -2625,7 +2811,8 @@ static void de4x5_put_cache(struct device *dev, struct sk_buff *skb)
     return;
 }
 
-static void de4x5_putb_cache(struct device *dev, struct sk_buff *skb)
+static void
+de4x5_putb_cache(struct device *dev, struct sk_buff *skb)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct sk_buff *p = lp->cache.skb;
@@ -2636,7 +2823,8 @@ static void de4x5_putb_cache(struct device *dev, struct sk_buff *skb)
     return;
 }
 
-static struct sk_buff *de4x5_get_cache(struct device *dev)
+static struct sk_buff *
+de4x5_get_cache(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct sk_buff *p = lp->cache.skb;
@@ -2653,7 +2841,8 @@ static struct sk_buff *de4x5_get_cache(struct device *dev)
 ** Check the Auto Negotiation State. Return OK when a link pass interrupt
 ** is received and the auto-negotiation status is NWAY OK.
 */
-static int test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec)
+static int
+test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2680,7 +2869,8 @@ static int test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec)
     return sts;
 }
 
-static void de4x5_setup_intr(struct device *dev)
+static void
+de4x5_setup_intr(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2700,7 +2890,8 @@ static void de4x5_setup_intr(struct device *dev)
 /*
 **
 */
-static void reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr)
+static void
+reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2716,7 +2907,8 @@ static void reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr)
 /*
 ** Create a loopback ethernet packet with an invalid CRC
 */
-static void create_packet(struct device *dev, char *frame, int len)
+static void
+create_packet(struct device *dev, char *frame, int len)
 {
     int i;
     char *buf = frame;
@@ -2737,7 +2929,8 @@ static void create_packet(struct device *dev, char *frame, int len)
 /*
 ** Known delay in microseconds
 */
-static void de4x5_us_delay(u32 usec)
+static void
+de4x5_us_delay(u32 usec)
 {
     udelay(usec);
     
@@ -2747,7 +2940,8 @@ static void de4x5_us_delay(u32 usec)
 /*
 ** Known delay in milliseconds, in millisecond steps.
 */
-static void de4x5_ms_delay(u32 msec)
+static void
+de4x5_ms_delay(u32 msec)
 {
     u_int i;
     
@@ -2762,7 +2956,8 @@ static void de4x5_ms_delay(u32 msec)
 /*
 ** Look for a particular board name in the EISA configuration space
 */
-static int EISA_signature(char *name, s32 eisa_id)
+static int
+EISA_signature(char *name, s32 eisa_id)
 {
     c_char *signatures[] = DE4X5_SIGNATURE;
     char ManCode[DE4X5_STRLEN];
@@ -2796,7 +2991,8 @@ static int EISA_signature(char *name, s32 eisa_id)
 /*
 ** Look for a particular board name in the PCI configuration space
 */
-static int PCI_signature(char *name, struct bus_type *lp)
+static int
+PCI_signature(char *name, struct bus_type *lp)
 {
     c_char *de4x5_signatures[] = DE4X5_SIGNATURE;
     int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
@@ -2833,7 +3029,8 @@ static int PCI_signature(char *name, struct bus_type *lp)
 ** Set up the Ethernet PROM counter to the start of the Ethernet address on
 ** the DC21040, else  read the SROM for the other chips.
 */
-static void DevicePresent(u_long aprom_addr)
+static void
+DevicePresent(u_long aprom_addr)
 {
     int i;
     struct bus_type *lp = &bus;
@@ -2851,7 +3048,8 @@ static void DevicePresent(u_long aprom_addr)
     return;
 }
 
-static int get_hw_addr(struct device *dev)
+static int
+get_hw_addr(struct device *dev)
 {
     u_long iobase = dev->base_addr;
     int broken, i, k, tmp, status = 0;
@@ -2902,7 +3100,7 @@ static int get_hw_addr(struct device *dev)
        chksum |= (u_short) (inb(EISA_APROM) << 8);
        if ((k != chksum) && (dec_only)) status = -1;
     }
-    
+
     return status;
 }
 
@@ -2910,7 +3108,8 @@ static int get_hw_addr(struct device *dev)
 ** Test for enet addresses in the first 32 bytes. The built-in strncmp
 ** didn't seem to work here...?
 */
-static int de4x5_bad_srom(struct bus_type *lp)
+static int
+de4x5_bad_srom(struct bus_type *lp)
 {
     int i, status = 0;
 
@@ -2925,7 +3124,8 @@ static int de4x5_bad_srom(struct bus_type *lp)
     return status;
 }
 
-static int de4x5_strncmp(char *a, char *b, int n)
+static int
+de4x5_strncmp(char *a, char *b, int n)
 {
     int ret=0;
 
@@ -2939,7 +3139,8 @@ static int de4x5_strncmp(char *a, char *b, int n)
 /*
 ** SROM Read
 */
-static short srom_rd(u_long addr, u_char offset)
+static short
+srom_rd(u_long addr, u_char offset)
 {
     sendto_srom(SROM_RD | SROM_SR, addr);
     
@@ -2950,7 +3151,8 @@ static short srom_rd(u_long addr, u_char offset)
     return srom_data(SROM_RD | SROM_SR | DT_CS, addr);
 }
 
-static void srom_latch(u_int command, u_long addr)
+static void
+srom_latch(u_int command, u_long addr)
 {
     sendto_srom(command, addr);
     sendto_srom(command | DT_CLK, addr);
@@ -2959,7 +3161,8 @@ static void srom_latch(u_int command, u_long addr)
     return;
 }
 
-static void srom_command(u_int command, u_long addr)
+static void
+srom_command(u_int command, u_long addr)
 {
     srom_latch(command, addr);
     srom_latch(command, addr);
@@ -2968,7 +3171,8 @@ static void srom_command(u_int command, u_long addr)
     return;
 }
 
-static void srom_address(u_int command, u_long addr, u_char offset)
+static void
+srom_address(u_int command, u_long addr, u_char offset)
 {
     int i;
     char a;
@@ -2987,7 +3191,8 @@ static void srom_address(u_int command, u_long addr, u_char offset)
     return;
 }
 
-static short srom_data(u_int command, u_long addr)
+static short
+srom_data(u_int command, u_long addr)
 {
     int i;
     short word = 0;
@@ -3007,7 +3212,8 @@ static short srom_data(u_int command, u_long addr)
 }
 
 /*
-static void srom_busy(u_int command, u_long addr)
+static void
+srom_busy(u_int command, u_long addr)
 {
    sendto_srom((command & 0x0000ff00) | DT_CS, addr);
    
@@ -3021,7 +3227,8 @@ static void srom_busy(u_int command, u_long addr)
 }
 */
 
-static void sendto_srom(u_int command, u_long addr)
+static void
+sendto_srom(u_int command, u_long addr)
 {
     outl(command, addr);
     udelay(1);
@@ -3029,7 +3236,8 @@ static void sendto_srom(u_int command, u_long addr)
     return;
 }
 
-static int getfrom_srom(u_long addr)
+static int
+getfrom_srom(u_long addr)
 {
     s32 tmp;
     
@@ -3043,7 +3251,8 @@ static int getfrom_srom(u_long addr)
 ** MII Read/Write
 */
 
-static int mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr)
+static int
+mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr)
 {
     mii_wdata(MII_PREAMBLE,  2, ioaddr);   /* Start of 34 bit preamble...    */
     mii_wdata(MII_PREAMBLE, 32, ioaddr);   /* ...continued                   */
@@ -3055,7 +3264,8 @@ static int mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr)
     return mii_rdata(ioaddr);              /* Read data                      */
 }
 
-static void mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr)
+static void
+mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr)
 {
     mii_wdata(MII_PREAMBLE,  2, ioaddr);   /* Start of 34 bit preamble...    */
     mii_wdata(MII_PREAMBLE, 32, ioaddr);   /* ...continued                   */
@@ -3069,7 +3279,8 @@ static void mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr)
     return;
 }
 
-static int mii_rdata(u_long ioaddr)
+static int
+mii_rdata(u_long ioaddr)
 {
     int i;
     s32 tmp = 0;
@@ -3082,7 +3293,8 @@ static int mii_rdata(u_long ioaddr)
     return tmp;
 }
 
-static void mii_wdata(int data, int len, u_long ioaddr)
+static void
+mii_wdata(int data, int len, u_long ioaddr)
 {
     int i;
     
@@ -3094,7 +3306,8 @@ static void mii_wdata(int data, int len, u_long ioaddr)
     return;
 }
 
-static void mii_address(u_char addr, u_long ioaddr)
+static void
+mii_address(u_char addr, u_long ioaddr)
 {
     int i;
     
@@ -3107,11 +3320,12 @@ static void mii_address(u_char addr, u_long ioaddr)
     return;
 }
 
-static void mii_ta(u_long rw, u_long ioaddr)
+static void
+mii_ta(u_long rw, u_long ioaddr)
 {
     if (rw == MII_STWR) {
        sendto_mii(MII_MWR | MII_WR, 1, ioaddr);  
-       getfrom_mii(MII_MRD | MII_RD, ioaddr);
+       sendto_mii(MII_MWR | MII_WR, 0, ioaddr);  
     } else {
        getfrom_mii(MII_MRD | MII_RD, ioaddr);        /* Tri-state MDIO */
     }
@@ -3119,7 +3333,8 @@ static void mii_ta(u_long rw, u_long ioaddr)
     return;
 }
 
-static int mii_swap(int data, int len)
+static int
+mii_swap(int data, int len)
 {
     int i, tmp = 0;
     
@@ -3132,7 +3347,8 @@ static int mii_swap(int data, int len)
     return tmp;
 }
 
-static void sendto_mii(u32 command, int data, u_long ioaddr)
+static void
+sendto_mii(u32 command, int data, u_long ioaddr)
 {
     u32 j;
     
@@ -3145,7 +3361,8 @@ static void sendto_mii(u32 command, int data, u_long ioaddr)
     return;
 }
 
-static int getfrom_mii(u32 command, u_long ioaddr)
+static int
+getfrom_mii(u32 command, u_long ioaddr)
 {
     outl(command, ioaddr);
     udelay(1);
@@ -3159,7 +3376,8 @@ static int getfrom_mii(u32 command, u_long ioaddr)
 ** Here's 3 ways to calculate the OUI from the ID registers. One's a brain
 ** dead approach, 2 aren't (clue: mine isn't!).
 */
-static int mii_get_oui(u_char phyaddr, u_long ioaddr)
+static int
+mii_get_oui(u_char phyaddr, u_long ioaddr)
 {
 /*
     union {
@@ -3202,7 +3420,8 @@ static int mii_get_oui(u_char phyaddr, u_long ioaddr)
     return r2;                                  /* (I did it) My way */
 }
 
-static int mii_get_phy(struct device *dev)
+static int
+mii_get_phy(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
@@ -3246,7 +3465,8 @@ static int mii_get_phy(struct device *dev)
     return lp->mii_cnt;
 }
 
-static char *build_setup_frame(struct device *dev, int mode)
+static char *
+build_setup_frame(struct device *dev, int mode)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int i;
@@ -3277,14 +3497,16 @@ static char *build_setup_frame(struct device *dev, int mode)
     return pa;                     /* Points to the next entry */
 }
 
-static void enable_ast(struct device *dev, u32 time_out)
+static void
+enable_ast(struct device *dev, u32 time_out)
 {
     timeout(dev, (void *)&de4x5_ast, (u_long)dev, time_out);
     
     return;
 }
 
-static void disable_ast(struct device *dev)
+static void
+disable_ast(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     
@@ -3293,7 +3515,8 @@ static void disable_ast(struct device *dev)
     return;
 }
 
-static long de4x5_switch_to_mii(struct device *dev)
+static long
+de4x5_switch_to_mii(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
@@ -3319,7 +3542,8 @@ static long de4x5_switch_to_mii(struct device *dev)
     return omr;
 }
 
-static long de4x5_switch_to_srl(struct device *dev)
+static long
+de4x5_switch_to_srl(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
@@ -3327,7 +3551,6 @@ static long de4x5_switch_to_srl(struct device *dev)
     
     /* Deassert the OMR_PS bit in CSR6 */
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
-    outl(omr | OMR_TTM, DE4X5_OMR);
     outl(omr, DE4X5_OMR);
     
     /* Soft Reset */
@@ -3345,7 +3568,8 @@ static long de4x5_switch_to_srl(struct device *dev)
     return omr;
 }
 
-static void timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec)
+static void
+timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int dt;
@@ -3366,7 +3590,8 @@ static void timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_
     return;
 }
 
-static void de4x5_dbg_open(struct device *dev)
+static void
+de4x5_dbg_open(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int i;
@@ -3416,7 +3641,8 @@ static void de4x5_dbg_open(struct device *dev)
     return;
 }
 
-static void de4x5_dbg_mii(struct device *dev, int k)
+static void
+de4x5_dbg_mii(struct device *dev, int k)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
@@ -3442,7 +3668,8 @@ static void de4x5_dbg_mii(struct device *dev, int k)
     return;
 }
 
-static void de4x5_dbg_media(struct device *dev)
+static void
+de4x5_dbg_media(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     
@@ -3473,7 +3700,8 @@ static void de4x5_dbg_media(struct device *dev)
     return;
 }
 
-static void de4x5_dbg_srom(struct de4x5_srom *p)
+static void
+de4x5_dbg_srom(struct de4x5_srom *p)
 {
     int i;
 
@@ -3496,11 +3724,48 @@ static void de4x5_dbg_srom(struct de4x5_srom *p)
     return;
 }
 
+static void
+de4x5_dbg_rx(struct sk_buff *skb, int len)
+{
+    int i, j;
+
+    if (de4x5_debug > 2) {
+       printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n",
+              (u_char)skb->data[0],
+              (u_char)skb->data[1],
+              (u_char)skb->data[2],
+              (u_char)skb->data[3],
+              (u_char)skb->data[4],
+              (u_char)skb->data[5],
+              (u_char)skb->data[6],
+              (u_char)skb->data[7],
+              (u_char)skb->data[8],
+              (u_char)skb->data[9],
+              (u_char)skb->data[10],
+              (u_char)skb->data[11],
+              (u_char)skb->data[12],
+              (u_char)skb->data[13],
+              len);
+       if (de4x5_debug > 3) {
+           for (j=0; len>0;j+=16, len-=16) {
+               printk("    %03x: ",j);
+               for (i=0; i<16 && i<len; i++) {
+                   printk("%02x ",(u_char)skb->data[i+j]);
+               }
+               printk("\n");
+           }
+       }
+    }
+
+    return;
+}
+
 /*
 ** Perform IOCTL call functions here. Some are privileged operations and the
 ** effective uid is checked in those cases.
 */
-static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+static int
+de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data;
@@ -3540,13 +3805,8 @@ static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        build_setup_frame(dev, PHYS_ADDR_ONLY);
        /* Set up the descriptor and give ownership to the card */
        while (set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/
-       if (lp->setup_f == HASH_PERF) {
-           load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | 
-                       SETUP_FRAME_LEN, NULL);
-       } else {
-           load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
-                       SETUP_FRAME_LEN, NULL);
-       }
+       load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
+                                                       SETUP_FRAME_LEN, NULL);
        lp->tx_new = (++lp->tx_new) % lp->txRingSize;
        outl(POLL_DEMAND, DE4X5_TPD);                /* Start the TX */
        dev->tbusy = 0;                              /* Unlock the TX ring */
index ada3ce1b806c7dc320b62a25a6fc06a4a2a2347c..0342a484017880abbe78642389942e45eba4ed69 100644 (file)
 #define EXT_SIA_SUSPECT 0x0805     /* Suspect the EXT SIA port is down */
 #define BNC_SUSPECT     0x0806     /* Suspect the BNC port is down */
 #define AUI_SUSPECT     0x0807     /* Suspect the AUI port is down */
-#define _10Mb_SUSPECT   0x0808     /* Suspect 10Mb/s is down */
-#define _100Mb_SUSPECT  0x0809     /* Suspect 100Mb/s is down */
-#define LINK_RESET      0x080a     /* Reset the PHY and re-init auto sense */
 
 #define AUTO            0x4000     /* Auto sense the media or speed */
 #define TIMER_CB        0x80000000 /* Timer callback detection */
 */
 #define SET_10Mb {\
   if (lp->phy[lp->active].id) {\
-    mii_wr(MII_CR_10|MII_CR_ASSE,MII_CR,lp->phy[lp->active].addr,DE4X5_MII);\
-    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR);\
-    omr |= (de4x5_full_duplex ? OMR_FD : 0) | OMR_TTM;\
+    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD);\
+    if ((lp->tmp != MII_SR_ASSC) || (lp->autosense != AUTO)) {\
+      mii_wr(MII_CR_10|(de4x5_full_duplex?MII_CR_FDM:0), MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
+    }\
+    omr |= ((de4x5_full_duplex ? OMR_FD : 0) | OMR_TTM);\
     outl(omr, DE4X5_OMR);\
     outl(0, DE4X5_GEP);\
   } else {\
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\
     omr |= (de4x5_full_duplex ? OMR_FD : 0);\
     outl(omr | OMR_TTM, DE4X5_OMR);\
     outl((de4x5_full_duplex ? 0 : GEP_FDXD), DE4X5_GEP);\
 
 #define SET_100Mb {\
   if (lp->phy[lp->active].id) {\
-    mii_wr(MII_CR_100|MII_CR_ASSE, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
-    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR);\
+    int fdx=0;\
+    if (lp->phy[lp->active].id == NATIONAL_TX) {\
+        mii_wr(mii_rd(0x18, lp->phy[lp->active].addr, DE4X5_MII) & ~0x2000,\
+                      0x18, lp->phy[lp->active].addr, DE4X5_MII);\
+    }\
+    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD);\
     sr = mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);\
-    if (!(sr & MII_ANA_T4AM) && de4x5_full_duplex) omr |= OMR_FD;\
+    if (!(sr & MII_ANA_T4AM) && de4x5_full_duplex) fdx=1;\
+    if ((lp->tmp != MII_SR_ASSC) || (lp->autosense != AUTO)) {\
+      mii_wr(MII_CR_100|(fdx?MII_CR_FDM:0), MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
+    }\
+    if (fdx) omr |= OMR_FD;\
     outl(omr, DE4X5_OMR);\
-    outl(((!(sr & MII_ANA_T4AM) && de4x5_full_duplex) ? 0:GEP_FDXD)|GEP_MODE,\
-                                                                 DE4X5_GEP);\
   } else {\
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\
     omr |= (de4x5_full_duplex ? OMR_FD : 0);\
     outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\
     outl((de4x5_full_duplex ? 0 : GEP_FDXD) | GEP_MODE, DE4X5_GEP);\
   }\
 }
 
+/* FIX ME so I don't jam 10Mb networks */
+#define SET_100Mb_PDET {\
+  if (lp->phy[lp->active].id) {\
+    mii_wr(MII_CR_100|MII_CR_ASSE, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
+    omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\
+    outl(omr, DE4X5_OMR);\
+  } else {\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\
+    outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\
+    outl(GEP_FDXD | GEP_MODE, DE4X5_GEP);\
+  }\
+}
+
 /*
 ** Include the IOCTL stuff
 */
index b452fa9277f0205680195d34a0b1b684bedd8978..08bd0462e6cd5923092246d8a4697434cbc7e8a7 100644 (file)
@@ -7,7 +7,18 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
+SUB_DIRS     :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS) char
+
 L_OBJS   := sbus.o dvma.o
 L_TARGET := sbus.a
 
+# Character devices for SBUS-based machines.
+#
+ifeq ($(CONFIG_SBUSCHAR),y)
+SUB_DIRS += char
+L_OBJS += char/sunchar.o
+endif
+
 include $(TOPDIR)/Rules.make
diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile
new file mode 100644 (file)
index 0000000..5f3bd97
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := sunchar.o
+O_OBJS   := suncons.o sunkbd.o sunkeymap.o sunmouse.o sunserial.o
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/sbus/char/suncons.c b/drivers/sbus/char/suncons.c
new file mode 100644 (file)
index 0000000..48adfd1
--- /dev/null
@@ -0,0 +1,1922 @@
+/* suncons.c: Sun SparcStation console support.
+ *
+ * Copyright (C) 1995 Peter Zaitcev (zaitcev@lab.ipmce.su)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Added font loading Nov/21, Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Added render_screen and faster scrolling Nov/27, miguel
+ * Added console palette code for cg6 Dec/13/95, miguel
+ * Added generic frame buffer support Dec/14/95, miguel
+ * Added cgsix and bwtwo drivers Jan/96, miguel
+ * Added 4m, and cg3 driver Feb/96, miguel
+ * Fixed the cursor on color displays Feb/96, miguel.
+ *
+ * Cleaned up the detection code, generic 8bit depth display 
+ * code, Mar/96 miguel
+ * 
+ * This file contains the frame buffer device drivers.
+ * Each driver is kept together in case we would like to
+ * split this file.
+ *
+ * Much of this driver is derived from the DEC TGA driver by
+ * Jay Estabrook who has done a nice job with the console
+ * driver abstraction btw.
+ *
+ * We try to make everything a power of two if possible to
+ * speed up the bit blit.  Doing multiplies, divides, and
+ * remainder routines end up calling software library routines
+ * since not all Sparcs have the hardware to do it.
+ *
+ * TODO:
+ * do not use minor to index into instances of the frame buffer,
+ * since the numbers assigned to us are not consecutive.
+ *
+ * do not blank the screen when frame buffer is mapped.
+ *
+ * Change the detection loop to use more than one video card.
+ */
+
+
+/* Define this one if you are debugging something in X, it will not disable the console output */
+/* #define DEBUGGING_X */
+/* See also: sparc/keyboard.c: CODING_NEW_DRIVER */
+
+#define GRAPHDEV_MAJOR 29
+
+#define FRAME_BUFFERS 1
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kd.h>
+#include <linux/malloc.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/oplib.h>
+#include <asm/sbus.h>
+#include <asm/fbio.h>
+#include <asm/io.h>
+#include <asm/pgtsun4c.h>      /* for the sun4c_nocache */
+
+#include "../../char/kbd_kern.h"
+#include "../../char/vt_kern.h"
+#include "../../char/consolemap.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+
+#define cmapsz 8192
+
+extern void register_console(void (*proc)(const char *));
+extern void console_print(const char *);
+extern unsigned char vga_font[];
+extern int graphics_on;
+extern int serial_console;
+
+/* Based upon what the PROM tells us, we can figure out where
+ * the console is currently located.  The situation can be either
+ * of the following two scenarios:
+ *
+ * 1) Console i/o is done over the serial line, ttya or ttyb
+ * 2) Console output on frame buffer (video card) and input
+ *    coming from the keyboard/mouse which each use a zilog8530
+ *    serial channel a piece.
+ */
+
+/* The following variables describe a Sparc console. */
+
+/* From the PROM */
+static char con_name[40];
+
+/* Screen dimensions and color depth. */
+static int con_depth, con_width, con_height, con_type;
+
+static int con_linebytes;
+
+/* Base address of first line. */
+static unsigned char *con_fb_base;
+
+/* Screen parameters: we compute those at startup to make the code faster */
+static int chars_per_line;     /* number of bytes per line */
+static int ints_per_line;      /* number of ints per  line */
+static int skip_bytes;         /* number of bytes we skip for the y margin */
+static int x_margin, y_margin; /* the x and y margins */
+static int bytes_per_row;      /* bytes used by one screen line (of 16 scan lines)  */
+
+/* Functions used by the SPARC dependent console code
+ * to perform the restore_palette function.
+ */
+static void (*restore_palette)(void);
+void set_palette (void);
+
+
+ /* Our screen looks like at 1152 X 900:
+ *
+ *  0,0
+ *      ------------------------------------------------------------------
+ *      |                          ^^^^^^^^^^^                           |
+ *      |                          18 y-pixels                           |
+ *      |                          ^^^^^^^^^^^                           |
+ *   13 | <-64 pixels->|  <-- 128 8x16 characters -->    | <-64 pixels-> |
+ *    ....
+ *                         54 chars from top to bottom
+ *    ....
+ *  888 | <-64 pixels->|  <-- 128 8x16 characters -->    | <-64 pixels-> |
+ *      |                          ^^^^^^^^^^^                           |
+ *      |                          18 y-pixels                           |
+ *      |                          ^^^^^^^^^^^                           |
+ *      ------------------------------------------------------------------
+ */
+/* First for MONO displays. */
+#define SCREEN_WIDTH     1152     /* Screen width in pixels  */
+#define SCREEN_HEIGHT    900      /* Screen height in pixels */
+#define CHARS_PER_LINE   144      /* Make this empirical for speed */
+#define NICE_Y_MARGIN    18       /* We skip 18 y-pixels at top/bottom */
+#define NICE_X_MARGIN    8        /* We skip 64 x-pixels at left/right */
+#define FBUF_TOP_SKIP    2592     /* Empirical, (CHARS_PER_LINE * NICE_Y_MARGIN) */
+#define CHAR_HEIGHT      16
+#define ONE_ROW          2304     /* CHARS_PER_LINE * CHAR_HEIGHT */
+
+/* Now we have this, to compute the base frame buffer position
+ * for a new character to be rendered. 1 and 8 bit depth.
+ */
+#define FBUF_OFFSET(cindex) \
+        (((FBUF_TOP_SKIP) + (((cindex)>>7) * ONE_ROW)) + \
+        ((NICE_X_MARGIN) + (((cindex)&127))))
+
+
+#define COLOR_FBUF_OFFSET(cindex) \
+        (((skip_bytes) + (((cindex)>>7) * bytes_per_row)) + \
+        ((x_margin) + (((cindex)&127) << 3)))
+
+void
+__set_origin(unsigned short offset)
+{
+       /*
+        * should not be called, but if so, do nothing...
+        */
+}
+
+/* For the cursor, we just invert the 8x16 block at the cursor
+ * location.  Easy enough...
+ *
+ * Hide the cursor from view, during blanking, usually...
+ */
+static int cursor_pos = -1;
+void
+hide_cursor(void)
+{
+       unsigned long flags;
+       int j;
+
+       save_flags(flags); cli();
+
+       if(cursor_pos == -1) {
+               restore_flags (flags);
+               return;
+       }
+       /* We just zero out the area for now.  Certain graphics
+        * cards like the cg6 have a hardware cursor that we could
+        * use, but this is an optimization for some time later.
+        */
+       switch (con_depth){
+       case 1: {
+               unsigned char *dst;
+               dst = (unsigned char *)((unsigned long)con_fb_base +
+                                       FBUF_OFFSET(cursor_pos));
+               for(j = 0; j < CHAR_HEIGHT; j++, dst += CHARS_PER_LINE)
+                       *dst = ~(0);
+               break;
+       }
+       case 8: {
+               unsigned long *dst;
+               const    int ipl = ints_per_line;
+               
+               dst = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(cursor_pos));
+               for(j = 0; j < CHAR_HEIGHT; j++, dst += ipl) {
+                       *dst = ~(0UL);
+                       *(dst + 1) = ~(0UL);
+               }
+               break;
+       }
+       default:
+               break;
+       }
+       restore_flags(flags);
+}
+
+/* The idea is the following:
+ * we only use the colors in the range 0..15, and we only
+ * setup the palette on that range, so we better keep the
+ * pixel inversion using those colors, that's why we have
+ * those constants below.
+ */
+inline static void
+cursor_reverse (long *dst, int height, const int ints_on_line)
+{
+    int j;
+
+    for (j = 0; j < height; j++){
+       *dst     = ~(*dst)     & 0x0f0f0f0f;
+       *(dst+1) = ~(*(dst+1)) & 0x0f0f0f0f;
+       dst += ints_on_line;
+    }
+}
+
+void
+set_cursor(int currcons)
+{
+       int j, idx, oldpos;
+       unsigned long flags;
+
+       if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
+               return;
+
+       if (__real_origin != __origin)
+               __set_origin(__real_origin);
+
+       save_flags(flags); cli();
+
+       idx = (pos - video_mem_base) >> 1;
+       oldpos = cursor_pos;
+       cursor_pos = idx;
+       if (!deccm) {
+               hide_cursor ();
+               restore_flags (flags);
+               return;
+       }
+       switch (con_depth){
+       case 1: {
+               unsigned char *dst, *opos;
+               
+               dst = (unsigned char *)((unsigned long)con_fb_base + FBUF_OFFSET(idx));
+               opos = (unsigned char *)((unsigned long)con_fb_base + FBUF_OFFSET(oldpos));
+               if(oldpos != -1) {
+                       /* Restore what was at the old position */
+                       for(j=0; j < CHAR_HEIGHT; j++, opos += CHARS_PER_LINE) {
+                               *opos = ~*opos;
+                       }
+               }
+               for(j=0; j < 16; j++, dst+=CHARS_PER_LINE) {
+                       *dst = ~*dst;
+               }
+               break;
+       }
+       case 8: {
+               unsigned long *dst, *opos;
+               dst = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(idx));
+               opos = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(oldpos));
+                       
+               if(oldpos != -1) 
+                       cursor_reverse(opos, CHAR_HEIGHT, ints_per_line);
+               cursor_reverse (dst, CHAR_HEIGHT, ints_per_line);
+               break;
+       }
+       default:
+       }
+       restore_flags(flags);
+}
+
+/*
+ * Render the current screen
+ * Only used at startup to avoid the caching that is being done in selection.h
+ */
+static void
+render_screen(void)
+{
+    int count;
+    unsigned short *contents;
+
+    count = video_num_columns * video_num_lines;
+    contents = (unsigned short *) video_mem_base;
+    
+    for (;count--; contents++)
+       sun_blitc (*contents, (unsigned long) contents);
+}
+
+unsigned long
+con_type_init(unsigned long kmem_start, const char **display_desc)
+{
+        can_do_color = (con_type != FBTYPE_SUN2BW);
+
+        video_type = VIDEO_TYPE_SUN;
+        *display_desc = "SUN";
+
+       if (!serial_console) {
+               /* If we fall back to PROM than our output have to remain readable. */
+               prom_putchar('\033');  prom_putchar('[');  prom_putchar('H');
+
+               /*
+                * fake the screen memory with some CPU memory
+                */
+               video_mem_base = kmem_start;
+               kmem_start += video_screen_size;
+               video_mem_term = kmem_start;
+
+               render_screen();
+       }
+       return kmem_start;
+}
+
+/*
+ * NOTE: get_scrmem() and set_scrmem() are here only because
+ * the VGA version of set_scrmem() has some direct VGA references.
+ */
+void
+get_scrmem(int currcons)
+{
+       memcpyw((unsigned short *)vc_scrbuf[currcons],
+               (unsigned short *)origin, video_screen_size);
+       origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
+       scr_end = video_mem_end = video_mem_start + video_screen_size;
+       pos = origin + y*video_size_row + (x<<1);
+}
+
+void
+set_scrmem(int currcons, long offset)
+{
+       if (video_mem_term - video_mem_base < offset + video_screen_size)
+               offset = 0;
+       memcpyw((unsigned short *)(video_mem_base + offset),
+               (unsigned short *) origin, video_screen_size);
+       video_mem_start = video_mem_base;
+       video_mem_end = video_mem_term;
+       origin = video_mem_base + offset;
+       scr_end = origin + video_screen_size;
+       pos = origin + y*video_size_row + (x<<1);
+}
+
+/*
+ * PIO_FONT support.
+ */
+int
+set_get_font(char * arg, int set, int ch512)
+{
+       int error, i, line;
+
+       if (!arg)
+               return -EINVAL;
+       error = verify_area (set ? VERIFY_READ : VERIFY_WRITE, (void *) arg,
+                            ch512 ? 2* cmapsz : cmapsz);
+       if (error)
+               return error;
+
+       /* download the current font */
+       if (!set){
+               memset (arg, 0, cmapsz);
+               for (i = 0; i < 256; i++)
+                   for (line = 0; line < CHAR_HEIGHT; line++)
+                       put_user (vga_font [i], arg+(i*32+line));
+               return 0;
+       }
+       
+        /* set the font */
+       for (i = 0; i < 256; i++)
+               for (line = 0; line < CHAR_HEIGHT; line++){
+                       vga_font [i*CHAR_HEIGHT + line] = (get_user (arg + (i * 32 + line)));
+                       if (con_depth == 1)
+                               vga_font [i*CHAR_HEIGHT + line] = vga_font [i*CHAR_HEIGHT + line];
+               }
+       return 0;
+}
+
+/*
+ * Adjust the screen to fit a font of a certain height
+ *
+ * Returns < 0 for error, 0 if nothing changed, and the number
+ * of lines on the adjusted console if changed.
+ *
+ * for now, we only support the built-in font...
+ */
+int
+con_adjust_height(unsigned long fontheight)
+{
+       return -EINVAL;
+}
+
+int
+set_get_cmap(unsigned char * arg, int set)
+{
+       int i;
+
+       i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
+       if (i)
+               return i;
+
+       for (i=0; i<16; i++) {
+               if (set) {
+                       default_red[i] = get_user(arg++) ;
+                       default_grn[i] = get_user(arg++) ;
+                       default_blu[i] = get_user(arg++) ;
+               } else {
+                       put_user (default_red[i], arg++) ;
+                       put_user (default_grn[i], arg++) ;
+                       put_user (default_blu[i], arg++) ;
+               }
+       }
+       if (set) {
+               for (i=0; i<MAX_NR_CONSOLES; i++)
+                       if (vc_cons_allocated(i)) {
+                               int j, k ;
+                               for (j=k=0; j<16; j++) {
+                                       vc_cons[i].d->vc_palette[k++] = default_red[j];
+                                       vc_cons[i].d->vc_palette[k++] = default_grn[j];
+                                       vc_cons[i].d->vc_palette[k++] = default_blu[j];
+                               }
+                       }
+               set_palette();
+       }
+
+       return 0;
+}
+
+
+void
+sun_clear_screen(void)
+{
+       memset (con_fb_base, (con_depth == 1 ? ~(0) : (0)),
+               (con_depth * con_height * con_width) / 8);
+       /* also clear out the "shadow" screen memory */
+       memset((char *)video_mem_base, 0, (video_mem_term - video_mem_base));
+}
+
+/*
+ * dummy routines for the VESA blanking code, which is VGA only,
+ * so we don't have to carry that stuff around for the Sparc...
+ */
+void vesa_blank(void)
+{
+}
+void vesa_unblank(void)
+{
+}
+void set_vesa_blanking(const unsigned long arg)
+{
+}
+
+void vesa_powerdown(void)
+{
+}
+
+#undef color
+/* cg6 cursor status, kernel tracked copy */
+struct cg6_cursor {
+        short   enable;                /* cursor is enabled */
+        struct  fbcurpos cpos; /* position */
+        struct  fbcurpos chot; /* hot-spot */
+        struct  fbcurpos size; /* size of mask & image fields */
+        int     bits[2][32];   /* space for mask & image bits */
+       char    color [6];      /* cursor colors */
+};
+
+struct cg6_info {
+       struct bt_regs *bt;     /* color control */
+       void *fbc;
+       struct cg6_fhc *fhc;
+       struct cg6_tec *tec;
+       struct cg6_thc *thc;
+       struct cg6_cursor cursor; /* cursor control */
+       void *dhc;
+};
+
+struct bwtwo_info {
+        struct bwtwo_regs *regs;
+};
+
+struct cg3_info {
+       struct bt_regs *bt;     /* brooktree (color) registers */
+};
+
+/* Array holding the information for the frame buffers */
+typedef struct {
+       union {
+               struct bwtwo_info bwtwo;
+               struct cg3_info   cg3;
+               struct cg6_info   cg6;
+       } info;                 /* per frame information */
+       int    space;           /* I/O space this card resides in */
+       int    blanked;         /* true if video blanked */
+       int    open;            /* is this fb open? */
+       int    mmaped;          /* has this fb been mmapped? */
+       int    vtconsole;       /* virtual console where it is opened */
+       long   base;            /* frame buffer base    */
+       struct fbtype type;     /* frame buffer type    */
+       int    (*mmap)(struct inode *, struct file *, struct vm_area_struct *, long fb_base, void *);
+       void   (*loadcmap)(void *this, int index, int count);
+       void   (*blank)(void *this);
+       void   (*unblank)(void *this);
+       int    (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long, void *);
+} fbinfo_t;
+
+static fbinfo_t fbinfo [FRAME_BUFFERS];
+
+/* We need to keep a copy of the color map to answer ioctl requests */
+static union {
+       unsigned char   map[256][3];    /* reasonable way to access */
+        unsigned int    raw[256*3/4];   /* hardware wants it like this */
+} color_map;
+
+#define FB_MMAP_VM_FLAGS (VM_SHM| VM_LOCKED)
+
+static int
+fb_open (struct inode * inode, struct file * file)
+{
+       int minor = MINOR (inode->i_rdev);
+
+       if (minor >= FRAME_BUFFERS)
+               return -EBADF;
+       if (fbinfo [minor].open)
+               return -EBUSY;
+       fbinfo [minor].open = 1;
+       fbinfo [minor].mmaped = 0;
+       return 0;
+}
+
+static int
+fb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int minor = MINOR (inode->i_rdev);
+       fbinfo_t *fb;
+       struct fbcmap *cmap;
+       int i;
+       
+       if (minor >= FRAME_BUFFERS)
+               return -EBADF;
+       fb = &fbinfo [minor];
+       
+       switch (cmd){
+       case FBIOGTYPE:         /* return frame buffer type */
+               i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbtype));
+               if (i) return i;
+               *(struct fbtype *)arg = (fb->type);
+               break;
+       case FBIOGATTR:{
+               struct fbgattr *fba = (struct fbgattr *) arg;
+               
+               i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbgattr));
+               if (i) return i;
+               fba->real_type = fb->type.fb_type;
+               fba->owner = 0;
+               fba->fbtype = fb->type;
+               fba->sattr.flags = 0;
+               fba->sattr.emu_type = fb->type.fb_type;
+               fba->sattr.dev_specific [0] = -1;
+               fba->emu_types [0] = fb->type.fb_type;
+               fba->emu_types [1] = -1;
+               break;
+       }
+       case FBIOSVIDEO:
+               i = verify_area(VERIFY_READ, (void *)arg, sizeof(int));
+               if (i) return i;
+               
+               if (*(int *)arg){
+                       if (!fb->blanked || !fb->unblank)
+                               break;
+                       (*fb->unblank)(fb);
+                       fb->blanked = 0;
+               } else {
+                       if (fb->blanked || !fb->blank)
+                               break;
+                       (*fb->blank)(fb);
+                       fb->blanked = 1;
+               }
+               break;
+       case FBIOGVIDEO:
+               i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (int));
+               if (i) return i;
+               *(int *) arg = fb->blanked;
+               break;
+       case FBIOPUTCMAP: {     /* load color map entries */
+               char *rp, *gp, *bp;
+               int end, count;;
+               
+               if (!fb->loadcmap)
+                       return -EINVAL;
+               i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap));
+               if (i) return i;
+               cmap = (struct fbcmap *) arg;
+               count = cmap->count;
+               if ((cmap->index < 0) || (cmap->index > 255))
+                       return -EINVAL;
+               if (cmap->index + count > 256)
+                       count = 256 - cmap->index;
+               i = verify_area (VERIFY_READ, rp = cmap->red, cmap->count);
+               if (i) return i;
+               i = verify_area (VERIFY_READ, gp = cmap->green, cmap->count);
+               if (i) return i;
+               i = verify_area (VERIFY_READ, bp = cmap->blue, cmap->count);
+               if (i) return i;
+
+               end = cmap->index + count;
+               for (i = cmap->index; i < end; i++){
+                       color_map.map [i][0] = *rp++;
+                       color_map.map [i][1] = *gp++;
+                       color_map.map [i][2] = *bp++;
+               }
+               (*fb->loadcmap)(fb, cmap->index, count);
+                break;                 
+       }
+
+       default:
+               if (fb->ioctl){
+                       i = fb->ioctl (inode, file, cmd, arg, fb);
+                       if (i == -EINVAL)
+                               printk ("[[FBIO: %8.8x]]\n", cmd);
+                       return i;
+               }
+               printk ("[[FBIO: %8.8x]]\n", cmd);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void
+fb_close (struct inode * inode, struct file *filp)
+{
+       int minor = MINOR(inode->i_rdev);
+       struct fbcursor cursor;
+       
+       if (minor >= FRAME_BUFFERS)
+               return;
+       if (fbinfo [minor].open)
+               fbinfo [minor].open = 0;
+       vt_cons [fbinfo [minor].vtconsole]->vc_mode = KD_TEXT;
+
+       /* Leaving graphics mode, turn off the cursor */
+       graphics_on = 0;
+       if (fbinfo [minor].mmaped)
+               sun_clear_screen ();
+       cursor.set    = FB_CUR_SETCUR;
+       cursor.enable = 0;
+       fb_ioctl (inode, filp, FBIOSCURPOS, (unsigned long) &cursor);
+       set_palette ();
+       render_screen ();
+       return;
+}
+
+static int
+fb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma)
+{
+       int minor = MINOR (inode->i_rdev);
+       fbinfo_t *fb;
+
+       if (minor >= FRAME_BUFFERS)
+               return -ENXIO;
+       /* FIXME: the fg_console below should actually be the
+        * console on which the invoking process is running
+        */
+       if (vt_cons [fg_console]->vc_mode == KD_GRAPHICS)
+               return -ENXIO;
+       fbinfo [minor].vtconsole = fg_console;
+       fb = &fbinfo [minor];
+
+       if (fb->mmap){
+               int v;
+               
+               v = (*fb->mmap)(inode, file, vma, fb->base, fb);
+               if (v) return v;
+               fbinfo [minor].mmaped = 1;
+               vt_cons [fg_console]->vc_mode = KD_GRAPHICS;
+               graphics_on = 1;
+               return 0;
+       } else
+               return -ENXIO;
+}
+
+static struct file_operations graphdev_fops =
+{
+       NULL,                   /* lseek */
+       NULL,                   /* read */
+       NULL,                   /* write */
+       NULL,                   /* readdir */
+       NULL,                   /* select */
+       fb_ioctl,
+       fb_mmap,
+       fb_open,                /* open */
+       fb_close,               /* close */
+};
+
+/* Call the frame buffer routine for setting the palette */
+void
+set_palette (void)
+{
+       if (console_blanked || vt_cons [fg_console]->vc_mode == KD_GRAPHICS)
+               return;
+
+       if (fbinfo [0].loadcmap){
+               int i, j;
+       
+               /* First keep color_map with the palette colors */
+               for (i = 0; i < 16; i++){
+                       j = color_table [i];
+                       color_map.map [i][0] = default_red [j];
+                       color_map.map [i][1] = default_grn [j];
+                       color_map.map [i][2] = default_blu [j];
+               }
+               (*fbinfo [0].loadcmap)(&fbinfo [0], 0, 16);
+       }
+}
+
+/* Called when returning to prom */
+void
+console_restore_palette (void)
+{
+        if (restore_palette)
+               (*restore_palette) ();
+}
+
+/* This routine should be moved to srmmu.c */
+static __inline__ unsigned int
+srmmu_get_pte (unsigned long addr)
+{
+       register unsigned long entry;
+
+       __asm__ __volatile__("\n\tlda [%1] %2,%0\n\t" :
+                            "=r" (entry):
+                            "r" ((addr & 0xfffff000) | 0x400), "i" (ASI_M_FLUSH_PROBE));
+       return entry;
+}
+
+unsigned int
+get_phys (unsigned int addr)
+{
+       switch (sparc_cpu_model){
+       case sun4c:
+               return sun4c_get_pte (addr) << PAGE_SHIFT;
+       case sun4m:
+               return ((srmmu_get_pte (addr) & 0xffffff00) << 4);
+       default:
+               panic ("get_phys called for unsupported cpu model\n");
+               return 0;
+       }
+}
+
+/* CG6 support code */
+
+/* Offset of interesting structures in the OBIO space */
+/*
+ * Brooktree is the video dac and is funny to program on the cg6.
+ * (it's even funnier on the cg3)
+ * The FBC could be the the frame buffer control
+ * The FHC could be the frame buffer hardware control.
+ */
+#define CG6_ROM_OFFSET       0x0
+#define CG6_BROOKTREE_OFFSET 0x200000
+#define CG6_DHC_OFFSET       0x240000
+#define CG6_ALT_OFFSET       0x280000
+#define CG6_FHC_OFFSET       0x300000
+#define CG6_THC_OFFSET       0x301000
+#define CG6_FBC_OFFSET       0x700000
+#define CG6_TEC_OFFSET       0x701000
+#define CG6_RAM_OFFSET       0x800000
+
+struct bt_regs {
+       unsigned int  addr;     /* address register */
+       unsigned int  color_map; /* color map */
+       unsigned int  control;  /* control register */
+       unsigned int  cursor;   /* cursor map register */
+};
+
+/* The contents are unknown */
+struct cg6_tec {
+       int tec_matrix;
+       int tec_clip;
+       int tec_vdc;
+};
+
+struct cg6_thc {
+        unsigned int thc_xxx0[512];  /* ??? */
+        unsigned int thc_hsync1;     /* hsync timing */
+        unsigned int thc_hsync2;
+        unsigned int thc_hsync3;
+        unsigned int thc_vsync1;     /* vsync timing */
+        unsigned int thc_vsync2;
+        unsigned int thc_refresh;
+        unsigned int thc_misc;
+        unsigned int thc_xxx1[56];
+        unsigned int thc_cursxy;             /* cursor x,y position (16 bits each) */
+        unsigned int thc_cursmask[32];       /* cursor mask bits */
+        unsigned int thc_cursbits[32];       /* what to show where mask enabled */
+};
+
+static void
+cg6_restore_palette (void)
+{
+       volatile struct bt_regs *bt;
+
+       bt = fbinfo [0].info.cg6.bt;
+       bt->addr = 0;
+       bt->color_map = 0xffffffff;
+       bt->color_map = 0xffffffff;
+       bt->color_map = 0xffffffff;
+}
+
+/* Ugh: X wants to mmap a bunch of cute stuff at the same time :-( */
+/* So, we just mmap the things that are being asked for */
+static int
+cg6_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
+{
+       unsigned int size, page, r, map_size;
+       unsigned int map_offset = 0;
+       fbinfo_t *fb = (fbinfo_t *) xx;
+       
+       size = vma->vm_end - vma->vm_start;
+        if (vma->vm_offset & ~PAGE_MASK)
+                return -ENXIO;
+
+       /* To stop the swapper from even considering these pages */
+       vma->vm_flags |= FB_MMAP_VM_FLAGS;
+       
+       /* Each page, see which map applies */
+       for (page = 0; page < size; ){
+               switch (vma->vm_offset+page){
+               case CG6_TEC:
+                       map_size = PAGE_SIZE;
+                       map_offset = get_phys ((uint)fb->info.cg6.tec);
+                       break;
+               case CG6_FBC:
+                       map_size = PAGE_SIZE;
+                       map_offset = get_phys ((uint)fb->info.cg6.fbc);
+                       break;
+               case CG6_FHC:
+                       map_size = PAGE_SIZE;
+                       map_offset = get_phys ((uint)fb->info.cg6.fhc);
+                       break;
+               case CG6_THC:
+                       map_size = PAGE_SIZE;
+                       map_offset = get_phys ((uint)fb->info.cg6.thc);
+                       break;
+               case CG6_BTREGS:
+                       map_size = PAGE_SIZE;
+                       map_offset = get_phys ((uint)fb->info.cg6.bt);
+                       break;
+                       
+               case CG6_DHC:
+                       map_size = PAGE_SIZE * 40;
+                       map_offset = get_phys ((uint)fb->info.cg6.dhc);
+                       break;
+                       
+               case CG6_ROM:
+                       map_size = 0;
+                       break;
+
+               case CG6_RAM:
+                       map_size = size-page;
+                       map_offset = get_phys ((uint) con_fb_base);
+                       if (map_size < fb->type.fb_size)
+                               map_size = fb->type.fb_size;
+                       break;
+               default:
+                       map_size = 0;
+                       break;
+               }
+               if (!map_size){
+                       page += PAGE_SIZE;
+                       continue;
+               }
+               r = io_remap_page_range (vma->vm_start+page,
+                                        map_offset,
+                                        map_size, vma->vm_page_prot,
+                                        fb->space);
+               if (r) return -EAGAIN;
+               page += map_size;
+       }
+        vma->vm_inode = inode;
+        inode->i_count++;
+        return 0;
+}
+
+#define BT_D4M3(x) ((((x) >> 2) << 1) + ((x) >> 2))     /* (x / 4) * 3 */
+#define BT_D4M4(x) ((x) & ~3)                           /* (x / 4) * 4 */
+
+static void
+cg6_loadcmap (void *fbinfo, int index, int count)
+{
+       fbinfo_t *fb = (fbinfo_t *) fbinfo;
+       struct bt_regs *bt = fb->info.cg6.bt;
+       int i;
+       
+       bt->addr = index << 24;
+       for (i = index; count--; i++){
+               bt->color_map = color_map.map [i][0] << 24;
+               bt->color_map = color_map.map [i][1] << 24;
+               bt->color_map = color_map.map [i][2] << 24;
+       }
+}
+
+/* Load cursor information */
+static void
+cg6_setcursor (struct cg6_info *info)
+{
+       unsigned int v;
+       struct cg6_cursor *c = &info->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);
+       }
+       info->thc->thc_cursxy = v;
+}
+
+#undef pos
+static int
+cg6_scursor (struct fbcursor *cursor, fbinfo_t *fb)
+{
+       int op = cursor->set;
+       volatile struct cg6_thc *thc = fb->info.cg6.thc;
+       struct cg6_cursor *cursor_info = &fb->info.cg6.cursor;
+       int i, bytes = 0;
+       
+       if (op & FB_CUR_SETSHAPE){
+               if ((unsigned int) cursor->size.fbx > 32)
+                       return -EINVAL;
+               if ((unsigned int) cursor->size.fby > 32)
+                       return -EINVAL;
+               bytes = (cursor->size.fby * 32)/8;
+               i = verify_area (VERIFY_READ, cursor->image, bytes);
+               if (i) return i;
+               i = verify_area (VERIFY_READ, cursor->mask, bytes);
+               if (i) return i;
+       }
+       if (op & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)){
+               if (op & FB_CUR_SETCUR)
+                       cursor_info->enable = cursor->enable;
+               if (op & FB_CUR_SETPOS)
+                       cursor_info->cpos = cursor->pos;
+               if (op & FB_CUR_SETHOT)
+                       cursor_info->chot = cursor->hot;
+               cg6_setcursor (&fb->info.cg6);
+       }
+       if (op & FB_CUR_SETSHAPE){
+               unsigned int u;
+               
+               cursor_info->size = cursor->size;
+               memset ((void *)&cursor_info->bits, 0, sizeof (cursor_info->size));
+               memcpy (cursor_info->bits [0], cursor->mask, bytes);
+               memcpy (cursor_info->bits [1], cursor->image, bytes);
+               u = ~0;
+               if (cursor_info->size.fbx < 32)
+                       u = ~(u  >> cursor_info->size.fbx);
+               for (i = 0; i < 32; i++){
+                       int m = cursor_info->bits [0][i] & u;
+                       thc->thc_cursmask [i] = m;
+                       thc->thc_cursbits [i] = m & cursor_info->bits [1][i];
+               }
+       }
+       return 0;
+}
+
+/* Handle cg6-specific ioctls */
+static int
+cg6_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb)
+{
+       int i;
+
+       switch (cmd){
+       case FBIOGCURMAX:
+               i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbcurpos));
+               if (i) return i;
+               ((struct fbcurpos *) arg)->fbx = 32;
+               ((struct fbcurpos *) arg)->fby = 32;
+               break;
+
+       case FBIOSVIDEO:
+               /* vesa_blank and vesa_unblank could do the job on fb [0] */
+               break;
+
+       case FBIOSCURSOR:
+               return cg6_scursor ((struct fbcursor *) arg, fb);
+
+       case FBIOSCURPOS:
+               /*
+               i= verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcurpos));
+               if (i) return i;
+               */
+               fb->info.cg6.cursor.cpos = *(struct fbcurpos *)arg;
+               cg6_setcursor (&fb->info.cg6);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void
+cg6_setup (int slot, unsigned int cg6, int cg6_io)
+{
+       struct cg6_info *cg6info;
+
+       printk ("cgsix%d at 0x%8.8x\n", slot, (unsigned int) cg6);
+       
+       /* Fill in parameters we left out */
+       fbinfo [slot].type.fb_cmsize = 256;
+       fbinfo [slot].mmap = cg6_mmap;
+       fbinfo [slot].loadcmap = cg6_loadcmap;
+       fbinfo [slot].ioctl = (void *) cg6_ioctl;
+       fbinfo [slot].blank = 0;
+       fbinfo [slot].unblank = 0;
+       
+       cg6info = (struct cg6_info *) &fbinfo [slot].info.cg6;
+
+       /* Map the hardware registers */
+       cg6info->bt = sparc_alloc_io ((void *) cg6+CG6_BROOKTREE_OFFSET, 0,
+                sizeof (struct bt_regs),"cgsix_dac", cg6_io, 0);
+       cg6info->fhc = sparc_alloc_io ((void *) cg6+CG6_FHC_OFFSET, 0,
+                sizeof (int), "cgsix_fhc", cg6_io, 0);
+       cg6info->thc = sparc_alloc_io ((void *) cg6+CG6_THC_OFFSET, 0,
+                sizeof (struct cg6_thc), "cgsix_thc", cg6_io, 0);
+       cg6info->tec = sparc_alloc_io ((void *) cg6+CG6_TEC_OFFSET, 0,
+                sizeof (struct cg6_tec), "cgsix_tec", cg6_io, 0);
+       cg6info->dhc = sparc_alloc_io ((void *) cg6+CG6_DHC_OFFSET, 0,
+                0x40000, "cgsix_dhc", cg6_io, 0);
+       cg6info->fbc = sparc_alloc_io ((void *) cg6+CG6_FBC_OFFSET, 0,
+                0x1000, "cgsix_fbc", cg6_io, 0);
+       if (!con_fb_base){
+               con_fb_base = sparc_alloc_io ((void *) cg6+CG6_RAM_OFFSET, 0,
+                    fbinfo [slot].type.fb_size, "cgsix_ram", cg6_io, 0);
+       }
+       if (!slot)
+               restore_palette = cg6_restore_palette;
+}
+
+/* The cg3 driver, obio space addresses for mapping the cg3 stuff */
+#define CG3_REGS 0x400000
+#define CG3_RAM  0x800000
+#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2))      /* (x/4)*3 */
+#define D4M4(x) ((x)&~0x3)                      /* (x/4)*4 */
+
+/* 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 */
+static void
+cg3_loadcmap (void *fbinfo, int index, int count)
+{
+       fbinfo_t *fb = (fbinfo_t *) fbinfo;
+       struct bt_regs *bt = fb->info.cg3.bt;
+       int *i, steps;
+
+       i = &color_map.raw [D4M3(index)];
+       steps = D4M3(index+count-1) - D4M3(index)+3;
+       bt->addr = D4M4(index);
+       while (steps--)
+               bt->color_map = *i++;
+}
+
+/* The cg3 is presumed to emulate a cg4, I guess older programs will want that */
+/* addresses above 0x4000000 are for cg3, below that it's cg4 emulation          */
+static int
+cg3_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
+{
+       unsigned int size, page, r, map_size;
+       unsigned int map_offset = 0;
+       fbinfo_t *fb = (fbinfo_t *) xx;
+       
+       size = vma->vm_end - vma->vm_start;
+        if (vma->vm_offset & ~PAGE_MASK)
+                return -ENXIO;
+
+       /* To stop the swapper from even considering these pages */
+       vma->vm_flags |= FB_MMAP_VM_FLAGS; 
+       
+       /* Each page, see which map applies */
+       for (page = 0; page < size; ){
+               switch (vma->vm_offset+page){
+               case CG3_MMAP_OFFSET:
+                       map_size = size-page;
+                       map_offset = get_phys ((uint) con_fb_base);
+                       if (map_size > fb->type.fb_size)
+                               map_size = fb->type.fb_size;
+                       break;
+               default:
+                       map_size = 0;
+                       break;
+               }
+               if (!map_size){
+                       page += PAGE_SIZE;
+                       continue;
+               }
+               r = io_remap_page_range (vma->vm_start+page,
+                                        map_offset,
+                                        map_size, vma->vm_page_prot,
+                                        fb->space);
+               if (r) return -EAGAIN;
+               page += map_size;
+       }
+        vma->vm_inode = inode;
+        inode->i_count++;
+        return 0;
+}
+
+static void
+cg3_setup (int slot, unsigned int cg3, int cg3_io)
+{
+       struct cg3_info *cg3info;
+
+       printk ("cgthree%d at 0x%8.8x\n", slot, cg3);
+       
+       /* Fill in parameters we left out */
+       fbinfo [slot].type.fb_cmsize = 256;
+       fbinfo [slot].mmap = cg3_mmap;
+       fbinfo [slot].loadcmap = cg3_loadcmap;
+       fbinfo [slot].ioctl = 0; /* no special ioctls */
+
+       cg3info = (struct cg3_info *) &fbinfo [slot].info.cg3;
+
+       /* Map the card registers */
+       cg3info->bt = sparc_alloc_io ((void *) cg3+CG3_REGS, 0,
+                sizeof (struct bt_regs),"cg3_bt", cg3_io, 0);
+       
+       if (!con_fb_base){
+               con_fb_base=sparc_alloc_io ((void*) cg3+CG3_RAM, 0,
+                    fbinfo [slot].type.fb_size, "cg3_ram", cg3_io, 0);
+       }
+}
+
+/* OBio addresses for the bwtwo registers */
+#define BWTWO_REGISTER_OFFSET 0x400000
+
+struct bwtwo_regs {
+       char          unknown [16];
+#define BWTWO_ENABLE_VIDEO 0x40
+       unsigned char control;
+       char          unknown2 [15];
+};
+
+static int
+bwtwo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
+{
+       unsigned int size, map_offset, r;
+       fbinfo_t *fb = (fbinfo_t *) xx;
+       int map_size;
+       
+       map_size = size = vma->vm_end - vma->vm_start;
+       
+       if (vma->vm_offset & ~PAGE_MASK)
+               return -ENXIO;
+
+       /* To stop the swapper from even considering these pages */
+       vma->vm_flags |= FB_MMAP_VM_FLAGS;
+       printk ("base=%8.8xl start=%8.8xl size=%x offset=%8.8x\n",
+               (unsigned int) base,
+               (unsigned int) vma->vm_start, size,
+               (unsigned int) vma->vm_offset);
+
+       /* This routine should also map the register if asked for, but we don't do that yet */
+       map_offset = get_phys ((uint) con_fb_base);
+       r = io_remap_page_range (vma->vm_start, map_offset, map_size, vma->vm_page_prot,
+                                fb->space);
+       if (r) return -EAGAIN;
+       vma->vm_inode = inode;
+       inode->i_count++;
+       return 0;
+}
+
+static void
+bwtwo_blank (void *xx)
+{
+       fbinfo_t *fb = (fbinfo_t *) xx;
+
+       fb->info.bwtwo.regs->control &= ~BWTWO_ENABLE_VIDEO;
+}
+
+static void
+bwtwo_unblank (void *xx)
+{
+       fbinfo_t *fb = (fbinfo_t *) xx;
+       fb->info.bwtwo.regs->control |= BWTWO_ENABLE_VIDEO;
+}
+
+static void
+bwtwo_setup (int slot, unsigned int bwtwo, int bw2_io)
+{
+       printk ("bwtwo%d at 0x%8.8x\n", slot, bwtwo);
+       fbinfo [slot].type.fb_cmsize = 2;
+       fbinfo [slot].mmap = bwtwo_mmap;
+       fbinfo [slot].loadcmap = 0;
+       fbinfo [slot].ioctl = 0;
+       fbinfo [slot].blank = bwtwo_blank;
+       fbinfo [slot].unblank = bwtwo_unblank;
+       fbinfo [slot].info.bwtwo.regs = sparc_alloc_io ((void *) bwtwo+BWTWO_REGISTER_OFFSET,
+               0, sizeof (struct bwtwo_regs), "bwtwo_regs", bw2_io, 0);
+}
+
+static void
+cg14_setup (int slot, unsigned int cg14, int cg14_io)
+{
+       printk ("cgfourteen%d at 0x%8.8x\n", slot, cg14);
+       fbinfo [slot].type.fb_cmsize = 256;
+       fbinfo [slot].mmap =  0;
+       fbinfo [slot].loadcmap = 0;
+       fbinfo [slot].ioctl = 0;
+       fbinfo [slot].blank = 0;
+       fbinfo [slot].unblank = 0;
+}
+
+static char *known_cards [] = {
+       "cgsix", "cgthree", "bwtwo", "SUNW,tcx", "cgfourteen", 0
+};
+
+static int
+known_card (char *name)
+{
+       int i;
+
+       for (i = 0; known_cards [i]; i++)
+               if (strcmp (name, known_cards [i]) == 0)
+                       return 1;
+       return 0;
+}
+
+static struct {
+       int depth;
+       int resx, resy;
+       int x_margin, y_margin;
+} scr_def [] = {
+       { 1, 1152, 900,  8,  18 },
+       { 8, 1152, 900,  64, 18 },
+       { 8, 1280, 1024, 96, 80 },
+       { 8, 1024, 768,  0,  0 },
+       { 0 },
+};
+
+static int
+cg14_present(void)
+{
+       int root, n;
+
+       prom_printf ("Looking for cg14\n");
+       root = prom_getchild (prom_root_node);
+       if ((n = prom_searchsiblings (root, "obio")) == 0)
+               return 0;
+
+       n = prom_getchild (n);
+       if ((n = prom_searchsiblings (n, "cgfourteen")) == 0)
+               return 0;
+       prom_printf ("Cg14 found!\n");
+       return n;
+}
+
+static int
+sparc_console_probe(void)
+{
+       int propl, con_node, i;
+       struct linux_sbus_device *sbdp;
+       unsigned int fbbase = 0xb001b001;
+       int fbiospace = 0;
+       int cg14 = 0;
+
+       /* XXX The detection code needs to support multiple video cards in one system */
+       con_node = 0;
+       switch(prom_vers) {
+       case PROM_V0:
+               /* V0 proms are at sun4c only. Can skip many checks. */
+               con_type = FBTYPE_NOTYPE;
+               if(SBus_chain == 0) {
+                       prom_printf("SBUS chain is NULL, bailing out...\n");
+                       prom_halt();
+               }
+               for_each_sbusdev(sbdp, SBus_chain) {
+                       con_node = sbdp->prom_node;
+
+                       /* If no "address" than it is not the PROM console. */
+                       if(sbdp->num_vaddrs) {
+                               if(!strncmp(sbdp->prom_name, "cgsix", 5)) {
+                                       con_type = FBTYPE_SUNFAST_COLOR;
+                                       fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
+                                       fbiospace = sbdp->reg_addrs[0].which_io;
+                                       break;
+                               } else if(!strncmp(sbdp->prom_name, "cgthree", 7)) {
+                                       con_type = FBTYPE_SUN3COLOR;
+                                       fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
+                                       fbiospace = sbdp->reg_addrs[0].which_io;
+                                       break;
+                               } else if (!strncmp(sbdp->prom_name, "bwtwo", 5)) {
+                                       con_type = FBTYPE_SUN2BW;
+                                       fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
+                                       fbiospace = sbdp->reg_addrs[0].which_io;
+                                       break;
+                               }
+                       }
+               }
+               if(con_type == FBTYPE_NOTYPE) return -1;
+               con_fb_base = (unsigned char *) sbdp->sbus_vaddrs[0];
+               strncpy(con_name, sbdp->prom_name, sizeof (con_name));
+               break;
+       case PROM_V2:
+       case PROM_V3:
+       case PROM_P1275:
+               for_each_sbusdev(sbdp, SBus_chain) {
+                       prom_printf ("Trying: %s\n", sbdp->prom_name);
+                       if (known_card (sbdp->prom_name))
+                               break;
+               }
+               if (!sbdp){
+                       if (!(cg14 = cg14_present ())){
+                               prom_printf ("Could not find a known video card on this machine\n");
+                               prom_halt ();
+                       } 
+               }
+               if (!cg14){
+                       prom_apply_sbus_ranges (&sbdp->reg_addrs [0], sbdp->num_registers);
+                       fbbase = (long) sbdp->reg_addrs [0].phys_addr;
+                       fbiospace = sbdp->reg_addrs[0].which_io;
+                       con_node = (*romvec->pv_v2devops.v2_inst2pkg)
+                               (*romvec->pv_v2bootargs.fd_stdout);
+                       /*
+                        * Determine the type of hardware accelerator.
+                        */
+                       propl = prom_getproperty(con_node, "emulation", con_name, sizeof (con_name));
+                       if (propl < 0 || propl >= sizeof (con_name)) {
+                               /* Early cg3s had no "emulation". */
+                               propl = prom_getproperty(con_node, "name", con_name, sizeof (con_name));
+                               if (propl < 0) {
+                                       prom_printf("console: no device name!!\n");
+                                       return -1;
+                               }
+                       }
+                       if(!strncmp(con_name, "cgsix", sizeof (con_name))) {
+                               con_type = FBTYPE_SUNFAST_COLOR;
+                       } else if(!strncmp(con_name, "cgthree", sizeof (con_name))) {
+                               con_type = FBTYPE_SUN3COLOR;
+                       } else if(!strncmp(con_name, "cgfourteen", sizeof (con_name))) {
+                               con_type = FBTYPE_MDICOLOR;
+                       } else if(!strncmp(con_name, "bwtwo", sizeof (con_name))) {
+                               con_type = FBTYPE_SUN2BW;
+                       } else if(!strncmp(con_name,"SUNW,tcx", sizeof (con_name))){
+                               con_type = FBTYPE_SUN3COLOR;
+                       } else {
+                               prom_printf("console: \"%s\" is unsupported\n", con_name);
+                               return -1;
+                       }
+                       propl = prom_getproperty(con_node, "address", (char *) &con_fb_base, 4);
+                       if (propl != 4) {
+                               con_fb_base = 0;
+                       }
+               } else {
+                       int bases [2];
+
+                       con_node = cg14;
+                       prom_printf ("Found a cg14\n");
+                       propl = prom_getproperty (cg14, "address",
+                                                 (char *) &bases[0], 8);
+                       prom_printf ("Size=%d, %x\n", propl, bases [1]);
+                       con_fb_base = (unsigned char *) bases [1];
+                       con_type = FBTYPE_MDICOLOR;
+               }
+               break;
+       default:
+               return -1;
+       };
+
+       /* Get the device geometry */
+       con_linebytes = prom_getintdefault(con_node, "linebytes", 1152);
+       con_width = prom_getintdefault(con_node, "width", 1152);
+       con_height = prom_getintdefault(con_node, "height", 900);
+
+       /* Currently we just support 1-bit and 8-bit depth displays */
+       if (con_type == FBTYPE_SUN2BW) {
+               con_depth = 1;
+       } else {
+               con_depth = 8;
+       }
+       for (i = 0; scr_def [i].depth; i++){
+               if (scr_def [i].resx != con_width || scr_def [i].resy != con_height)
+                       continue;
+               if (scr_def [i].depth != con_depth)
+                       continue;
+               x_margin = scr_def [i].x_margin;
+               y_margin = scr_def [i].y_margin;
+               chars_per_line = (con_width * con_depth) / 8;
+               skip_bytes = chars_per_line * y_margin;
+               ints_per_line = chars_per_line / 4;
+               bytes_per_row = CHAR_HEIGHT * chars_per_line;
+               break;
+       }
+       if (!scr_def [i].depth){
+               x_margin = y_margin = 0;
+               prom_printf ("PenguinCon: unknown video resolution %dx%d may be slow\n", con_width, con_height);
+               prom_halt ();
+       }
+       /* P3: I fear this strips 15inch 1024/768 PC-like monitors out. */
+       if ((con_linebytes*8) / con_depth != con_width) {
+               prom_printf("console: UNUSUAL VIDEO, linebytes=%d, width=%d, depth=%d\n",
+                       con_linebytes, con_width, con_depth);
+               return -1;
+       }
+
+       /* Negate the font table on 1 bit depth cards so we have white on black */
+       if (con_depth == 1)
+               for(i=0; i<(16 * 256); i++)
+                       vga_font[i] = ~vga_font[i];
+
+       /* Fill in common fb information */
+       fbinfo [0].type.fb_type   = con_type;
+       fbinfo [0].type.fb_height = con_height;
+       fbinfo [0].type.fb_width  = con_width;
+       fbinfo [0].type.fb_depth  = con_depth;
+       fbinfo [0].type.fb_size   = PAGE_ALIGN((con_linebytes) * (con_height));
+       fbinfo [0].space = fbiospace;
+       fbinfo [0].blanked = 0;
+
+       /* Should be filled in for supported video cards */
+       fbinfo [0].mmap = 0; 
+       fbinfo [0].loadcmap = 0;
+       fbinfo [0].ioctl = 0;
+       fbinfo [0].blank = 0;
+       fbinfo [0].unblank = 0;
+
+       if (fbbase == 0xb001b001){
+               printk ("Mail miguel@nuclecu.unam.mx video_card=%d (%s)\n", con_type, con_name);
+       }
+
+       /* Per card setup */
+       switch (con_type){
+       case FBTYPE_SUN3COLOR:
+               cg3_setup (0, fbbase, fbiospace);
+               break;
+       case FBTYPE_SUNFAST_COLOR:
+               cg6_setup (0, fbbase, fbiospace);
+               break;
+       case FBTYPE_SUN2BW:
+               bwtwo_setup (0, fbbase, fbiospace);
+               break;
+       case FBTYPE_MDICOLOR:
+               cg14_setup (0, fbbase, fbiospace);
+               break;
+       default:
+               break;
+       }
+       if (!con_fb_base){
+               prom_printf ("PROM does not have an 'address' property for this\n"
+                            "frame buffer and the Linux drivers do not know how\n"
+                            "to map the video of this device\n");
+               prom_halt ();
+       }
+       fbinfo [0].base = (long) con_fb_base;
+       
+       /* Register the frame buffer device */
+       if (register_chrdev (GRAPHDEV_MAJOR, "graphics", &graphdev_fops)){
+               printk ("Could not register graphics device\n");
+               return -EIO;
+       }
+       return 0; /* success */
+}
+
+/* video init code, called from within the SBUS bus scanner at
+ * boot time.
+ */
+void
+sun_console_init(void)
+{
+       if(serial_console)
+               return;
+
+       if(sparc_console_probe()) {
+               prom_printf("Could not probe console, bailing out...\n");
+               prom_halt();
+       }
+       sun_clear_screen();
+}
+
+/*
+ * sun_blitc
+ *
+ * Displays an ASCII character at a specified character cell
+ *  position.
+ *
+ * Called from scr_writew() when the destination is
+ *  the "shadow" screen
+ */
+static unsigned int
+fontmask_bits[16] = {
+    0x00000000,
+    0x000000ff,
+    0x0000ff00,
+    0x0000ffff,
+    0x00ff0000,
+    0x00ff00ff,
+    0x00ffff00,
+    0x00ffffff,
+    0xff000000,
+    0xff0000ff,
+    0xff00ff00,
+    0xff00ffff,
+    0xffff0000,
+    0xffff00ff,
+    0xffffff00,
+    0xffffffff
+};
+
+int
+sun_blitc(unsigned int charattr, unsigned long addr)
+{
+       int j, idx;
+       unsigned char *font_row;
+
+#ifndef DEBUGGING_X
+       if (graphics_on)
+               return 0;
+#endif
+       idx = (addr - video_mem_base) >> 1;
+
+       /* Invalidate the cursor position if necessary. */
+       if(idx == cursor_pos)
+               cursor_pos = -1;
+       font_row = &vga_font[(charattr & 0xff) << 4];
+
+       switch (con_depth){
+       case 1: {
+               register unsigned char *dst;
+               
+               dst = (unsigned char *)(((unsigned long)con_fb_base) + FBUF_OFFSET(idx));
+               for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst+=CHARS_PER_LINE)
+                       *dst = *font_row;
+               break;
+       }
+       case 8: {
+               register unsigned long *dst;
+               unsigned long fgmask, bgmask, data, rowbits, attrib;
+               const int ipl = ints_per_line;
+               
+               dst = (unsigned long *)(((unsigned long)con_fb_base) + COLOR_FBUF_OFFSET(idx));
+               attrib = (charattr >> 8) & 0x0ff;
+               fgmask = attrib & 0x0f;
+               bgmask = (attrib >> 4) & 0x0f;
+               fgmask = fgmask << 8 | fgmask;
+               fgmask |= fgmask << 16;
+               bgmask = bgmask << 8 | bgmask;
+               bgmask |= bgmask << 16;
+               
+               for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst += ipl) {
+                       rowbits = *font_row;
+                       data = fontmask_bits[(rowbits>>4)&0xf];
+                       data = (data & fgmask) | (~data & bgmask);
+                       *dst = data;
+                       data = fontmask_bits[rowbits&0xf];
+                       data = (data & fgmask) | (~data & bgmask);
+                       *(dst+1) = data;
+               }
+               break;
+       } /* case */
+       } /* switch */
+       return (0);
+}
+
+unsigned char vga_font[cmapsz] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 
+0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 
+0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 
+0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
+0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
+0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
+0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 
+0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, 
+0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 
+0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 
+0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 
+0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 
+0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 
+0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, 
+0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 
+0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
+0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 
+0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 
+0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 
+0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 
+0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 
+0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 
+0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 
+0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 
+0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
+0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 
+0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 
+0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 
+0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 
+0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 
+0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 
+0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 
+0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 
+0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
+0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, 
+0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 
+0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, 
+0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 
+0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 
+0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 
+0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
+0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 
+0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
+0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 
+0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
+0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 
+0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 
+0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 
+0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 
+0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 
+0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 
+0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 
+0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 
+0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 
+0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
+0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 
+0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 
+0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 
+0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 
+0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 
+0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, 
+0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 
+0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
+0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 
+0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
+0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 
+0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 
+0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
+0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
+0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 
+0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 
+0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
+0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 
+0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, 
+0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 
+0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 
+0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 
+0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 
+0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 
+0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
+0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 
+0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 
+0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 
+0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 
+0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 
+0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 
+0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 
+0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 
+0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 
+0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
+0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 
+0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+};
diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c
new file mode 100644 (file)
index 0000000..890b45a
--- /dev/null
@@ -0,0 +1,1317 @@
+/* keyboard.c: Sun keyboard driver.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Added vuid event generation and /dev/kbd device for SunOS
+ * compatibility - Miguel (miguel@nuclecu.unam.mx)
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/ptrace.h>
+#include <linux/signal.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <asm/kbio.h>
+#include <asm/vuid_event.h>
+#include <asm/delay.h>
+#include <asm/bitops.h>
+#include <asm/oplib.h>
+
+#include "../../char/kbd_kern.h"
+#include "../../char/diacr.h"
+#include "../../char/vt_kern.h"
+
+#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+/* Define this one if you are making a new frame buffer driver */
+/* it will not block the keyboard */
+/* #define CODING_NEW_DRIVER */
+
+/* KBD device number, temporal */
+#define KBD_MAJOR 11
+
+#define KBD_REPORT_ERR
+#define KBD_REPORT_UNKN
+
+#ifndef KBD_DEFMODE
+#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
+#endif
+
+#ifndef KBD_DEFLEDS
+/*
+ * Some laptops take the 789uiojklm,. keys as number pad when NumLock
+ * is on. This seems a good reason to start with NumLock off.
+ */
+#define KBD_DEFLEDS 0
+#endif
+
+#ifndef KBD_DEFLOCK
+#define KBD_DEFLOCK 0
+#endif
+
+extern void poke_blanked_console(void);
+extern void ctrl_alt_del(void);
+extern void reset_vc(unsigned int new_console);
+extern void scrollback(int);
+extern void scrollfront(int);
+
+unsigned char kbd_read_mask = 0x01;    /* modified by psaux.c */
+
+/*
+ * global state includes the following, and various static variables
+ * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next.
+ * (last_console is now a global variable)
+ */
+
+/* shift state counters.. */
+static unsigned char k_down[NR_SHIFT] = {0, };
+/* keyboard key bitmap */
+#define BITS_PER_LONG (8*sizeof(unsigned long))
+static unsigned long key_down[256/BITS_PER_LONG] = { 0, };
+
+void push_kbd (int scan);
+int kbd_redirected = 0;
+
+static int dead_key_next = 0;
+/* 
+ * In order to retrieve the shift_state (for the mouse server), either
+ * the variable must be global, or a new procedure must be created to 
+ * return the value. I chose the former way.
+ */
+/*static*/ int shift_state = 0;
+static int npadch = -1;                        /* -1 or number assembled on pad */
+static unsigned char diacr = 0;
+static char rep = 0;                   /* flag telling character repeat */
+struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+static struct tty_struct **ttytab;
+static struct kbd_struct * kbd = kbd_table;
+static struct tty_struct * tty = NULL;
+
+extern void compute_shiftstate(void);
+
+typedef void (*k_hand)(unsigned char value, char up_flag);
+typedef void (k_handfn)(unsigned char value, char up_flag);
+
+static k_handfn
+       do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
+       do_meta, do_ascii, do_lock, do_lowercase, do_ignore;
+
+static k_hand key_handler[16] = {
+       do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
+       do_meta, do_ascii, do_lock, do_lowercase,
+       do_ignore, do_ignore, do_ignore, do_ignore
+};
+
+typedef void (*void_fnp)(void);
+typedef void (void_fn)(void);
+
+static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle,
+       num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose,
+       SAK, decr_console, incr_console, spawn_console, bare_num;
+
+static void_fnp spec_fn_table[] = {
+       do_null,        enter,          show_ptregs,    show_mem,
+       show_state,     send_intr,      lastcons,       caps_toggle,
+       num,            hold,           scroll_forw,    scroll_back,
+       boot_it,        caps_on,        compose,        SAK,
+       decr_console,   incr_console,   spawn_console,  bare_num
+};
+
+/* maximum values each key_handler can handle */
+const int max_vals[] = {
+       255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
+       NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
+       255, NR_ASCII - 1, NR_LOCK - 1, 255
+};
+
+const int NR_TYPES = SIZE(max_vals);
+
+static void put_queue(int);
+static unsigned char handle_diacr(unsigned char);
+
+/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
+static struct pt_regs * pt_regs;
+
+volatile unsigned char sunkbd_layout;
+volatile unsigned char sunkbd_type;
+#define SUNKBD_TYPE2        0x02
+#define SUNKBD_TYPE3        0x03
+#define SUNKBD_TYPE4        0x04
+
+#define SUNKBD_LOUT_TYP4    0x00
+#define SUNKBD_LOUT_TYP5    0x22
+
+volatile int kbd_reset_pending;
+volatile int kbd_layout_pending;
+
+/* commands */
+#define SKBDCMD_RESET       0x1
+#define SKBDCMD_GLAYOUT     0xf
+#define SKBDCMD_BELLON      0x2
+#define SKBDCMD_BELLOFF     0x3
+#define SKBDCMD_SETLED      0xe
+#define SKBDCMD_NOCLICK     0xb
+#define SKBDCMD_CLICK       0xa
+
+static unsigned char sunkbd_clickp;
+
+/* The led set commands require sending the SETLED byte then
+ * a byte encoding which led's to have set.  Here are the bit
+ * values, a bit set = led-on.
+ */
+#define LED_NLOCK           0x1   /* Num-lock */
+#define LED_CMPOSE          0x2   /* Compose */
+#define LED_SCRLCK          0x4   /* Scroll-lock */
+#define LED_CLOCK           0x8   /* Caps-lock */
+
+/* Special state characters */
+#define SKBD_RESET          0xff
+#define SKBD_ALLUP          0x7f
+#define SKBD_LYOUT          0xfe
+
+/* On the Sparc the keyboard could be one of two things.
+ * It could be a real keyboard speaking over one of the
+ * channels of the second zs8530 chip (other channel is
+ * used by the Sun mouse).  Else we have serial console
+ * going, and thus the other zs8530 chip is who we speak
+ * to.  Either way, we communicate through the zs8530
+ * driver for all our I/O.
+ */
+
+#define SUNKBD_UBIT     0x80      /* If set, key went up */
+#define SUNKBD_KMASK    0x7f      /* Other bits are the keycode */
+
+#define KEY_LSHIFT      0x81
+#define KEY_RSHIFT      0x82
+#define KEY_CONTROL     0x83
+#define KEY_NILL        0x84
+#define KEY_CAPSLOCK    0x85
+#define KEY_ALT         0x86
+#define KEY_L1          0x87
+
+extern void kbd_put_char(unsigned char ch);
+static inline void send_cmd(unsigned char c)
+{
+       kbd_put_char(c);
+}
+
+/* kbd_bh() calls this to send the SKBDCMD_SETLED to the sun keyboard
+ * with the proper bit pattern for the leds to be set.  It basically
+ * converts the kbd->ledflagstate values to corresponding sun kbd led
+ * bit value.
+ */
+static inline unsigned char vcleds_to_sunkbd(unsigned char vcleds)
+{
+       unsigned char retval = 0;
+
+       if(vcleds & (1<<VC_SCROLLOCK))
+               retval |= LED_SCRLCK;
+       if(vcleds & (1<<VC_NUMLOCK))
+               retval |= LED_NLOCK;
+       if(vcleds & (1<<VC_CAPSLOCK))
+               retval |= LED_CLOCK;
+       return retval;
+}
+
+/*
+ * Translation of escaped scancodes to keycodes.
+ * This is now user-settable.
+ * The keycodes 1-88,96-111,119 are fairly standard, and
+ * should probably not be changed - changing might confuse X.
+ * X also interprets scancode 0x5d (KEY_Begin).
+ *
+ * For 1-88 keycode equals scancode.
+ */
+
+#define E0_KPENTER 96
+#define E0_RCTRL   97
+#define E0_KPSLASH 98
+#define E0_PRSCR   99
+#define E0_RALT    100
+#define E0_BREAK   101  /* (control-pause) */
+#define E0_HOME    102
+#define E0_UP      103
+#define E0_PGUP    104
+#define E0_LEFT    105
+#define E0_RIGHT   106
+#define E0_END     107
+#define E0_DOWN    108
+#define E0_PGDN    109
+#define E0_INS     110
+#define E0_DEL     111
+
+#define E1_PAUSE   119
+
+/*
+ * The keycodes below are randomly located in 89-95,112-118,120-127.
+ * They could be thrown away (and all occurrences below replaced by 0),
+ * but that would force many users to use the `setkeycodes' utility, where
+ * they needed not before. It does not matter that there are duplicates, as
+ * long as no duplication occurs for any single keyboard.
+ */
+#define SC_LIM 89
+
+#define FOCUS_PF1 85           /* actual code! */
+#define FOCUS_PF2 89
+#define FOCUS_PF3 90
+#define FOCUS_PF4 91
+#define FOCUS_PF5 92
+#define FOCUS_PF6 93
+#define FOCUS_PF7 94
+#define FOCUS_PF8 95
+#define FOCUS_PF9 120
+#define FOCUS_PF10 121
+#define FOCUS_PF11 122
+#define FOCUS_PF12 123
+
+#define JAP_86     124
+/* tfj@olivia.ping.dk:
+ * The four keys are located over the numeric keypad, and are
+ * labelled A1-A4. It's an rc930 keyboard, from
+ * Regnecentralen/RC International, Now ICL.
+ * Scancodes: 59, 5a, 5b, 5c.
+ */
+#define RGN1 124
+#define RGN2 125
+#define RGN3 126
+#define RGN4 127
+
+static unsigned char high_keys[128 - SC_LIM] = {
+  RGN1, RGN2, RGN3, RGN4, 0, 0, 0,                   /* 0x59-0x5f */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x60-0x67 */
+  0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12,          /* 0x68-0x6f */
+  0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3,    /* 0x70-0x77 */
+  FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7,        /* 0x78-0x7b */
+  FOCUS_PF8, JAP_86, FOCUS_PF10, 0                   /* 0x7c-0x7f */
+};
+
+/* BTC */
+#define E0_MACRO   112
+/* LK450 */
+#define E0_F13     113
+#define E0_F14     114
+#define E0_HELP    115
+#define E0_DO      116
+#define E0_F17     117
+#define E0_KPMINPLUS 118
+/*
+ * My OmniKey generates e0 4c for  the "OMNI" key and the
+ * right alt key does nada. [kkoller@nyx10.cs.du.edu]
+ */
+#define E0_OK  124
+/*
+ * New microsoft keyboard is rumoured to have
+ * e0 5b (left window button), e0 5c (right window button),
+ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
+ * [or: Windows_L, Windows_R, TaskMan]
+ */
+#define E0_MSLW        125
+#define E0_MSRW        126
+#define E0_MSTM        127
+
+static unsigned char e0_keys[128] = {
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x00-0x07 */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x08-0x0f */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x10-0x17 */
+  0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,            /* 0x18-0x1f */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x20-0x27 */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x28-0x2f */
+  0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,            /* 0x30-0x37 */
+  E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,              /* 0x38-0x3f */
+  E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,              /* 0x40-0x47 */
+  E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
+  E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,              /* 0x50-0x57 */
+  0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0,          /* 0x58-0x5f */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x60-0x67 */
+  0, 0, 0, 0, 0, 0, 0, E0_MACRO,                     /* 0x68-0x6f */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x70-0x77 */
+  0, 0, 0, 0, 0, 0, 0, 0                             /* 0x78-0x7f */
+};
+
+int setkeycode(unsigned int scancode, unsigned int keycode)
+{
+       if (scancode < SC_LIM || scancode > 255 || keycode > 127)
+         return -EINVAL;
+       if (scancode < 128)
+         high_keys[scancode - SC_LIM] = keycode;
+       else
+         e0_keys[scancode - 128] = keycode;
+       return 0;
+}
+
+int getkeycode(unsigned int scancode)
+{
+       return
+         (scancode < SC_LIM || scancode > 255) ? -EINVAL :
+         (scancode < 128) ? high_keys[scancode - SC_LIM] :
+           e0_keys[scancode - 128];
+}
+
+void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs);
+static void keyboard_timer (unsigned long ignored);
+
+static struct timer_list
+auto_repeat_timer = { NULL, NULL, 0, 0, keyboard_timer };
+
+/* Keeps track of the last pressed key */
+static unsigned char last_keycode;
+
+static void
+keyboard_timer (unsigned long ignored)
+{
+       unsigned long flags;
+
+       save_flags(flags); cli();
+
+       /* Auto repeat: send regs = 0 to indicate autorepeat */
+       sunkbd_inchar (last_keycode, 0, 0);
+       del_timer (&auto_repeat_timer);
+       auto_repeat_timer.expires = jiffies + HZ/20;
+       add_timer (&auto_repeat_timer);
+       restore_flags(flags);
+}
+
+/* #define SKBD_DEBUG */
+/* This is our keyboard 'interrupt' routine. */
+void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs)
+{
+       unsigned char keycode;
+       char up_flag;                          /* 0 or SUNKBD_UBIT */
+       char raw_mode;
+
+       if(ch == SKBD_RESET) {
+               kbd_reset_pending = 1;
+               return;
+       }
+       if(ch == SKBD_LYOUT) {
+               kbd_layout_pending = 1;
+               return;
+       }
+       if(kbd_reset_pending) {
+               sunkbd_type = ch;
+               kbd_reset_pending = 0;
+               if(ch == SUNKBD_TYPE4)
+                       send_cmd(SKBDCMD_GLAYOUT);
+               return;
+       } else if(kbd_layout_pending) {
+               sunkbd_layout = ch;
+               kbd_layout_pending = 0;
+               return;
+       } else if(ch == SKBD_ALLUP) {
+               /* eat it */
+               return;
+       }
+#ifdef SKBD_DEBUG
+       if(ch == 0x7f)
+               printk("KBD<ALL KEYS UP>");
+       else
+               printk("KBD<%x %s>", ch,
+                      ((ch&0x80) ? "UP" : "DOWN"));
+#endif
+
+       /* Whee, a real character. */
+       if (regs){
+               pt_regs = regs;
+               last_keycode = keycode = ch;
+       } else
+               keycode = ch;
+       
+       mark_bh(KEYBOARD_BH);
+       do_poke_blanked_console = 1;
+       mark_bh(CONSOLE_BH);
+       kbd = kbd_table + fg_console;
+       tty = ttytab[fg_console];
+       if((raw_mode = (kbd->kbdmode == VC_RAW))) {
+               if (kbd_redirected == fg_console+1)
+                       push_kbd (keycode);
+               else
+                       put_queue(keycode);
+               /* we do not return yet, because we want to maintain
+                * the key_down array, so that we have the correct
+                * values  when finishing RAW mode or when changing VT's.
+                */
+       }
+       up_flag = (keycode & SUNKBD_UBIT);  /* The 'up' bit */
+       keycode &= SUNKBD_KMASK;            /* all the rest */
+       del_timer (&auto_repeat_timer);
+       if(up_flag) {
+               rep = 0;
+               clear_bit(keycode, key_down);
+       } else {
+               auto_repeat_timer.expires = jiffies+HZ/5;
+               add_timer (&auto_repeat_timer);
+               rep = set_bit(keycode, key_down);
+       }
+
+       if(raw_mode)
+               return;
+
+       if(kbd->kbdmode == VC_MEDIUMRAW) {
+               put_queue(keycode + up_flag);
+               return;
+       }
+
+       /*
+        * Small change in philosophy: earlier we defined repetition by
+        *       rep = keycode == prev_keycode;
+        *       prev_keycode = keycode;
+        * but now by the fact that the depressed key was down already.
+        * Does this ever make a difference? Yes.
+        */
+
+       /*
+        *  Repeat a key only if the input buffers are empty or the
+        *  characters get echoed locally. This makes key repeat usable
+        *  with slow applications and under heavy loads.
+        */
+       if (!rep ||
+           (vc_kbd_mode(kbd,VC_REPEAT) && tty &&
+            (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) {
+               u_short keysym;
+               u_char type;
+
+               /* the XOR below used to be an OR */
+               int shift_final = shift_state ^ kbd->lockstate;
+               ushort *key_map = key_maps[shift_final];
+
+               if (key_map != NULL) {
+                       keysym = key_map[keycode];
+                       type = KTYP(keysym);
+
+                       if (type >= 0xf0) {
+                           type -= 0xf0;
+                           if (type == KT_LETTER) {
+                               type = KT_LATIN;
+                               if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
+                                   key_map = key_maps[shift_final ^ (1<<KG_SHIFT)];
+                                   if (key_map)
+                                     keysym = key_map[keycode];
+                               }
+                           }
+                           (*key_handler[type])(keysym & 0xff, up_flag);
+                           if (type != KT_SLOCK)
+                             kbd->slockstate = 0;
+                       }
+               } else {
+                       /* maybe beep? */
+                       /* we have at least to update shift_state */
+                       compute_shiftstate();
+               }
+       }
+}
+
+static void put_queue(int ch)
+{
+       wake_up(&keypress_wait);
+       if (tty) {
+               tty_insert_flip_char(tty, ch, 0);
+               tty_schedule_flip(tty);
+       }
+}
+
+static void puts_queue(char *cp)
+{
+       wake_up(&keypress_wait);
+       if (!tty)
+               return;
+
+       while (*cp) {
+               tty_insert_flip_char(tty, *cp, 0);
+               cp++;
+       }
+       tty_schedule_flip(tty);
+}
+
+static void applkey(int key, char mode)
+{
+       static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
+
+       buf[1] = (mode ? 'O' : '[');
+       buf[2] = key;
+       puts_queue(buf);
+}
+
+static void enter(void)
+{
+       put_queue(13);
+       if (vc_kbd_mode(kbd,VC_CRLF))
+               put_queue(10);
+}
+
+static void caps_toggle(void)
+{
+       if (rep)
+               return;
+       chg_vc_kbd_led(kbd, VC_CAPSLOCK);
+}
+
+static void caps_on(void)
+{
+       if (rep)
+               return;
+       set_vc_kbd_led(kbd, VC_CAPSLOCK);
+}
+
+static void show_ptregs(void)
+{
+       if (pt_regs)
+               show_regs(pt_regs);
+}
+
+static void hold(void)
+{
+       if (rep || !tty)
+               return;
+
+       /*
+        * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
+        * these routines are also activated by ^S/^Q.
+        * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
+        */
+       if (tty->stopped)
+               start_tty(tty);
+       else
+               stop_tty(tty);
+}
+
+static void num(void)
+{
+       if (vc_kbd_mode(kbd,VC_APPLIC))
+               applkey('P', 1);
+       else
+               bare_num();
+}
+
+/*
+ * Bind this to Shift-NumLock if you work in application keypad mode
+ * but want to be able to change the NumLock flag.
+ * Bind this to NumLock if you prefer that the NumLock key always
+ * changes the NumLock flag.
+ */
+static void bare_num(void)
+{
+       if (!rep)
+               chg_vc_kbd_led(kbd,VC_NUMLOCK);
+}
+
+static void lastcons(void)
+{
+       /* switch to the last used console, ChN */
+       set_console(last_console);
+}
+
+static void decr_console(void)
+{
+       int i;
+       for (i = fg_console-1; i != fg_console; i--) {
+               if (i == -1)
+                       i = MAX_NR_CONSOLES-1;
+               if (vc_cons_allocated(i))
+                       break;
+       }
+       set_console(i);
+}
+
+static void incr_console(void)
+{
+       int i;
+
+       for (i = fg_console+1; i != fg_console; i++) {
+               if (i == MAX_NR_CONSOLES)
+                       i = 0;
+               if (vc_cons_allocated(i))
+                       break;
+       }
+       set_console(i);
+}
+
+static void send_intr(void)
+{
+       if (!tty)
+               return;
+       tty_insert_flip_char(tty, 0, TTY_BREAK);
+       tty_schedule_flip(tty);
+}
+
+static void scroll_forw(void)
+{
+       scrollfront(0);
+}
+
+static void scroll_back(void)
+{
+       scrollback(0);
+}
+
+static void boot_it(void)
+{
+       extern int obp_system_intr(void);
+
+       if (!obp_system_intr())
+               ctrl_alt_del();
+       /* sigh.. atempt to prevent multiple entry */
+       last_keycode=1;
+       rep = 0;
+}
+
+static void compose(void)
+{
+       dead_key_next = 1;
+}
+
+int spawnpid, spawnsig;
+
+static void spawn_console(void)
+{
+        if (spawnpid)
+          if(kill_proc(spawnpid, spawnsig, 1))
+            spawnpid = 0;
+}
+
+static void SAK(void)
+{
+       do_SAK(tty);
+#if 0
+       /*
+        * Need to fix SAK handling to fix up RAW/MEDIUM_RAW and
+        * vt_cons modes before we can enable RAW/MEDIUM_RAW SAK
+        * handling.
+        * 
+        * We should do this some day --- the whole point of a secure
+        * attention key is that it should be guaranteed to always
+        * work.
+        */
+       reset_vc(fg_console);
+       do_unblank_screen();    /* not in interrupt routine? */
+#endif
+}
+
+static void do_ignore(unsigned char value, char up_flag)
+{
+}
+
+static void do_null()
+{
+       compute_shiftstate();
+}
+
+static void do_spec(unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+       if (value >= SIZE(spec_fn_table))
+               return;
+       spec_fn_table[value]();
+}
+
+static void do_lowercase(unsigned char value, char up_flag)
+{
+       printk("keyboard.c: do_lowercase was called - impossible\n");
+}
+
+static void do_self(unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;         /* no action, if this is a key release */
+
+       if (diacr)
+               value = handle_diacr(value);
+
+       if (dead_key_next) {
+               dead_key_next = 0;
+               diacr = value;
+               return;
+       }
+
+       put_queue(value);
+}
+
+#define A_GRAVE  '`'
+#define A_ACUTE  '\''
+#define A_CFLEX  '^'
+#define A_TILDE  '~'
+#define A_DIAER  '"'
+static unsigned char ret_diacr[] =
+       {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER };
+
+/* If a dead key pressed twice, output a character corresponding to it,        */
+/* otherwise just remember the dead key.                               */
+
+static void do_dead(unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+
+       value = ret_diacr[value];
+       if (diacr == value) {   /* pressed twice */
+               diacr = 0;
+               put_queue(value);
+               return;
+       }
+       diacr = value;
+}
+
+
+/* If space is pressed, return the character corresponding the pending */
+/* dead key, otherwise try to combine the two.                         */
+
+unsigned char handle_diacr(unsigned char ch)
+{
+       int d = diacr;
+       int i;
+
+       diacr = 0;
+       if (ch == ' ')
+               return d;
+
+       for (i = 0; i < accent_table_size; i++) {
+               if (accent_table[i].diacr == d && accent_table[i].base == ch)
+                       return accent_table[i].result;
+       }
+
+       put_queue(d);
+       return ch;
+}
+
+static void do_cons(unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+       want_console = value;
+}
+
+static void do_fn(unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+       if (value < SIZE(func_table)) {
+               if (func_table[value])
+                       puts_queue(func_table[value]);
+       } else
+               printk("do_fn called with value=%d\n", value);
+}
+
+static void do_pad(unsigned char value, char up_flag)
+{
+       static const char *pad_chars = "0123456789+-*/\015,.?";
+       static const char *app_map = "pqrstuvwxylSRQMnn?";
+
+       if (up_flag)
+               return;         /* no action, if this is a key release */
+
+       /* kludge... shift forces cursor/number keys */
+       if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) {
+               applkey(app_map[value], 1);
+               return;
+       }
+
+       if (!vc_kbd_led(kbd,VC_NUMLOCK))
+               switch (value) {
+                       case KVAL(K_PCOMMA):
+                       case KVAL(K_PDOT):
+                               do_fn(KVAL(K_REMOVE), 0);
+                               return;
+                       case KVAL(K_P0):
+                               do_fn(KVAL(K_INSERT), 0);
+                               return;
+                       case KVAL(K_P1):
+                               do_fn(KVAL(K_SELECT), 0);
+                               return;
+                       case KVAL(K_P2):
+                               do_cur(KVAL(K_DOWN), 0);
+                               return;
+                       case KVAL(K_P3):
+                               do_fn(KVAL(K_PGDN), 0);
+                               return;
+                       case KVAL(K_P4):
+                               do_cur(KVAL(K_LEFT), 0);
+                               return;
+                       case KVAL(K_P6):
+                               do_cur(KVAL(K_RIGHT), 0);
+                               return;
+                       case KVAL(K_P7):
+                               do_fn(KVAL(K_FIND), 0);
+                               return;
+                       case KVAL(K_P8):
+                               do_cur(KVAL(K_UP), 0);
+                               return;
+                       case KVAL(K_P9):
+                               do_fn(KVAL(K_PGUP), 0);
+                               return;
+                       case KVAL(K_P5):
+                               applkey('G', vc_kbd_mode(kbd, VC_APPLIC));
+                               return;
+               }
+
+       put_queue(pad_chars[value]);
+       if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
+               put_queue(10);
+}
+
+static void do_cur(unsigned char value, char up_flag)
+{
+       static const char *cur_chars = "BDCA";
+       if (up_flag)
+               return;
+
+       applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE));
+}
+
+static void do_shift(unsigned char value, char up_flag)
+{
+       int old_state = shift_state;
+
+       if (rep)
+               return;
+
+       /* Mimic typewriter:
+          a CapsShift key acts like Shift but undoes CapsLock */
+       if (value == KVAL(K_CAPSSHIFT)) {
+               value = KVAL(K_SHIFT);
+               if (!up_flag)
+                       clr_vc_kbd_led(kbd, VC_CAPSLOCK);
+       }
+
+       if (up_flag) {
+               /* handle the case that two shift or control
+                  keys are depressed simultaneously */
+               if (k_down[value])
+                       k_down[value]--;
+       } else
+               k_down[value]++;
+
+       if (k_down[value])
+               shift_state |= (1 << value);
+       else
+               shift_state &= ~ (1 << value);
+
+       /* kludge, no joke... */
+       if (up_flag && shift_state != old_state && npadch != -1) {
+               put_queue(npadch & 0xff);
+               npadch = -1;
+       }
+}
+
+/* called after returning from RAW mode or when changing consoles -
+   recompute k_down[] and shift_state from key_down[] */
+/* maybe called when keymap is undefined, so that shiftkey release is seen */
+void compute_shiftstate(void)
+{
+       int i, j, k, sym, val;
+
+       shift_state = 0;
+       for(i=0; i < SIZE(k_down); i++)
+         k_down[i] = 0;
+
+       for(i=0; i < SIZE(key_down); i++)
+         if(key_down[i]) {     /* skip this word if not a single bit on */
+           k = i*BITS_PER_LONG;
+           for(j=0; j<BITS_PER_LONG; j++,k++)
+             if(test_bit(k, key_down)) {
+               sym = U(plain_map[k]);
+               if(KTYP(sym) == KT_SHIFT) {
+                 val = KVAL(sym);
+                 if (val == KVAL(K_CAPSSHIFT))
+                   val = KVAL(K_SHIFT);
+                 k_down[val]++;
+                 shift_state |= (1<<val);
+               }
+             }
+         }
+}
+
+static void do_meta(unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+
+       if (vc_kbd_mode(kbd, VC_META)) {
+               put_queue('\033');
+               put_queue(value);
+       } else
+               put_queue(value | 0x80);
+}
+
+static void do_ascii(unsigned char value, char up_flag)
+{
+       int base;
+
+       if (up_flag)
+               return;
+
+       if (value < 10)    /* decimal input of code, while Alt depressed */
+           base = 10;
+       else {       /* hexadecimal input of code, while AltGr depressed */
+           value -= 10;
+           base = 16;
+       }
+
+       if (npadch == -1)
+         npadch = value;
+       else
+         npadch = npadch * base + value;
+}
+
+static void do_lock(unsigned char value, char up_flag)
+{
+       if (up_flag || rep)
+               return;
+       chg_vc_kbd_lock(kbd, value);
+}
+
+/*
+ * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
+ * or (ii) whatever pattern of lights people want to show using KDSETLED,
+ * or (iii) specified bits of specified words in kernel memory.
+ */
+
+static unsigned char ledstate = 0xff; /* undefined */
+static unsigned char ledioctl;
+
+unsigned char getledstate(void) {
+    return ledstate;
+}
+
+void setledstate(struct kbd_struct *kbd, unsigned int led) {
+    if (!(led & ~7)) {
+       ledioctl = led;
+       kbd->ledmode = LED_SHOW_IOCTL;
+    } else
+       kbd->ledmode = LED_SHOW_FLAGS;
+    set_leds();
+}
+
+static struct ledptr {
+    unsigned int *addr;
+    unsigned int mask;
+    unsigned char valid:1;
+} ledptrs[3];
+
+void register_leds(int console, unsigned int led,
+                  unsigned int *addr, unsigned int mask) {
+    struct kbd_struct *kbd = kbd_table + console;
+    if (led < 3) {
+       ledptrs[led].addr = addr;
+       ledptrs[led].mask = mask;
+       ledptrs[led].valid = 1;
+       kbd->ledmode = LED_SHOW_MEM;
+    } else
+       kbd->ledmode = LED_SHOW_FLAGS;
+}
+
+static inline unsigned char getleds(void){
+    struct kbd_struct *kbd = kbd_table + fg_console;
+    unsigned char leds;
+
+    if (kbd->ledmode == LED_SHOW_IOCTL)
+      return ledioctl;
+    leds = kbd->ledflagstate;
+    if (kbd->ledmode == LED_SHOW_MEM) {
+       if (ledptrs[0].valid) {
+           if (*ledptrs[0].addr & ledptrs[0].mask)
+             leds |= 1;
+           else
+             leds &= ~1;
+       }
+       if (ledptrs[1].valid) {
+           if (*ledptrs[1].addr & ledptrs[1].mask)
+             leds |= 2;
+           else
+             leds &= ~2;
+       }
+       if (ledptrs[2].valid) {
+           if (*ledptrs[2].addr & ledptrs[2].mask)
+             leds |= 4;
+           else
+             leds &= ~4;
+       }
+    }
+    return leds;
+}
+
+/*
+ * This routine is the bottom half of the keyboard interrupt
+ * routine, and runs with all interrupts enabled. It does
+ * console changing, led setting and copy_to_cooked, which can
+ * take a reasonably long time.
+ *
+ * Aside from timing (which isn't really that important for
+ * keyboard interrupts as they happen often), using the software
+ * interrupt routines for this thing allows us to easily mask
+ * this when we don't want any of the above to happen. Not yet
+ * used, but this allows for easy and efficient race-condition
+ * prevention later on.
+ */
+static void kbd_bh(void)
+{
+       unsigned char leds = getleds();
+
+       if (leds != ledstate) {
+               ledstate = leds;
+               send_cmd(SKBDCMD_SETLED);
+               send_cmd(vcleds_to_sunkbd(leds));
+       }
+}
+
+int kbd_init(void)
+{
+       int i, opt_node;
+       struct kbd_struct kbd0;
+       extern struct tty_driver console_driver;
+
+       kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS;
+       kbd0.ledmode = LED_SHOW_FLAGS;
+       kbd0.lockstate = KBD_DEFLOCK;
+       kbd0.modeflags = KBD_DEFMODE;
+       kbd0.kbdmode = VC_XLATE;
+       for (i = 0 ; i < MAX_NR_CONSOLES ; i++)
+               kbd_table[i] = kbd0;
+
+       ttytab = console_driver.table;
+
+       /* XXX Check keyboard-click? property in 'options' PROM node XXX */
+       if(sparc_cpu_model != sun4) {
+               opt_node = prom_getchild(prom_root_node);
+               opt_node = prom_searchsiblings(opt_node, "options");
+               i = prom_getintdefault(opt_node, "keyboard-click?", -1);
+               if(i != -1)
+                       sunkbd_clickp = 1;
+               else
+                       sunkbd_clickp = 0;
+       } else {
+               sunkbd_clickp = 0;
+       }
+       init_bh(KEYBOARD_BH, kbd_bh);
+       mark_bh(KEYBOARD_BH);
+       return 0;
+}
+
+/* /dev/kbd support */
+
+#define KBD_QSIZE 32
+static Firm_event kbd_queue [KBD_QSIZE];
+static int kbd_head, kbd_tail;
+char kbd_opened;
+static struct wait_queue *kbd_wait;
+static struct fasync_struct *kb_fasync;
+
+void
+push_kbd (int scan)
+{
+       int next = (kbd_head + 1) % KBD_QSIZE;
+
+       if (scan == KBD_IDLE)
+               return;
+       if (next != kbd_tail){
+               kbd_queue [kbd_head].id = scan & KBD_KEYMASK;
+               kbd_queue [kbd_head].value=scan & KBD_UP ? VKEY_UP : VKEY_DOWN;
+               kbd_queue [kbd_head].time = xtime;
+               kbd_head = next;
+       }
+       if (kb_fasync)
+               kill_fasync (kb_fasync, SIGIO);
+       wake_up_interruptible (&kbd_wait);
+}
+
+static int
+kbd_read (struct inode *inode, struct file *f, char *buffer, int count)
+{
+       struct wait_queue wait = { current, NULL };
+       char *end, *p;
+
+       /* Return EWOULDBLOCK, because this is what the X server expects */
+       if (kbd_head == kbd_tail){
+               if (f->f_flags & O_NONBLOCK)
+                       return -EWOULDBLOCK;
+               add_wait_queue (&kbd_wait, &wait);
+               while (kbd_head == kbd_tail && !(current->signal & ~current->blocked)){
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule ();
+               }
+               current->state = TASK_RUNNING;
+               remove_wait_queue (&kbd_wait, &wait);
+       }
+       /* There is data in the keyboard, fill the user buffer */
+       end = buffer+count;
+       p = buffer;
+       for (; p < end && kbd_head != kbd_tail; p += sizeof (Firm_event)){
+               *(Firm_event *)p = kbd_queue [kbd_tail];
+#ifdef KBD_DEBUG
+               printk ("[%s]", kbd_queue [kbd_tail].value == VKEY_UP ? "UP" : "DOWN");
+#endif
+               kbd_tail++;
+               kbd_tail %= KBD_QSIZE;
+       }
+       return p-buffer;
+}
+
+/* Needed by X */
+static int
+kbd_fasync (struct inode *inode, struct file *filp, int on)
+{
+       int retval;
+
+       retval = fasync_helper (inode, filp, on, &kb_fasync);
+       if (retval < 0)
+               return retval;
+       return 0;
+}
+
+static int
+kbd_select (struct inode *i, struct file *f, int sel_type, select_table *wait)
+{
+       if (sel_type != SEL_IN)
+               return 0;
+       if (kbd_head != kbd_tail)
+               return 1;
+       select_wait (&kbd_wait, wait);
+       return 0;
+}
+
+static int
+kbd_ioctl (struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
+{
+       switch (cmd){
+       case KIOCTYPE:            /* return keyboard type */
+               if (verify_area (VERIFY_WRITE, (void *)arg, sizeof (int)))
+                       return -EFAULT;
+               *(int *) arg = sunkbd_type;
+               break;
+       case KIOCGTRANS:
+               if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)))
+                       return -EFAULT;
+               *(int *) arg = TR_UNTRANS_EVENT;
+               break;
+       case KIOCTRANS:
+               if (verify_area (VERIFY_READ, (void *) arg, sizeof (int)))
+                       return -EFAULT;
+               if (*(int *) arg != TR_UNTRANS_EVENT)
+                       return -EINVAL;
+               break;
+       case KIOCLAYOUT:
+               if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)))
+                       return -EFAULT;
+               *(int *) arg = sunkbd_layout;
+               break;
+       case KIOCSDIRECT:
+               if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)))
+                       return -EFAULT;
+#ifndef CODING_NEW_DRIVER
+               if (*(int *) arg)
+                       kbd_redirected = fg_console + 1;
+               else
+                       kbd_redirected = 0;
+               kbd_table [fg_console].kbdmode = kbd_redirected ? VC_RAW : VC_XLATE;
+#endif
+               break;
+       case KIOCCMD:
+               /* Need to support beep on/off, keyclick on/off */
+               return 0;
+       case FIONREAD:          /* return number of bytes in kbd queue */
+       {
+               int count;
+               
+               if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)))
+                       return -EFAULT;
+               count = kbd_head - kbd_tail;
+               * (int *)arg = (count < 0) ? KBD_QSIZE - count : count;
+               return 0;
+       }
+       default:
+               printk ("Unknown Keyboard ioctl: %8.8x\n", cmd);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int
+kbd_open (struct inode *i, struct file *f)
+{
+       if (kbd_opened)
+               return 0;
+       kbd_opened = fg_console + 1;
+       kbd_head = kbd_tail = 0;
+       return 0;
+}
+
+static void
+kbd_close (struct inode *i, struct file *f)
+{
+       if (kbd_redirected)
+               kbd_table [kbd_opened-1].kbdmode = VC_XLATE;
+       kbd_redirected = 0;
+       kbd_opened = 0;
+
+       kbd_fasync (i, f, 0);
+}
+
+static struct
+file_operations kbd_fops =
+{
+       NULL,                   /* seek */
+       kbd_read,               /* read */
+       NULL,                   /* write */
+       NULL,                   /* readdir */
+       kbd_select,             /* select */
+       kbd_ioctl,              /* ioctl */
+       NULL,                   /* mmap */
+       kbd_open,               /* open */
+       kbd_close,              /* close */
+       NULL,                   /* fsync */
+       kbd_fasync,             /* fasync */
+       NULL,                   /* check_media_change */
+       NULL,                   /* revalidate */
+};
+
+void
+keyboard_zsinit(void)
+{
+       int timeout = 0;
+
+       /* Test out the leds */
+       sunkbd_type = 255;
+       send_cmd(SKBDCMD_RESET);
+       while((sunkbd_type==255) && timeout < 500000) {
+               udelay(100);
+               timeout += 20;
+       }
+
+       if(timeout>=500000) {
+               printk("keyboard: not present\n");
+               return;
+       }
+
+       if(sunkbd_type != SUNKBD_TYPE4) {
+               printk("Sun TYPE %d keyboard detected ", sunkbd_type);
+       } else {
+               udelay(200);
+               timeout=0;
+               while(timeout++ < 500000)
+                       barrier();
+               printk("Sun TYPE %d keyboard detected ",
+                      ((sunkbd_layout==SUNKBD_LOUT_TYP5) ? 5 : 4));
+       }
+       if(sunkbd_type == SUNKBD_TYPE2)
+               sunkbd_clickp = 0;
+
+       if(sunkbd_clickp)
+               printk("with keyclick\n");
+       else
+               printk("without keyclick\n");
+
+       /* Dork with led lights, then turn them all off */
+       send_cmd(SKBDCMD_SETLED); send_cmd(0xf); /* All on */
+       send_cmd(SKBDCMD_SETLED); send_cmd(0x0); /* All off */
+
+       /* Register the /dev/kbd interface */
+       if (register_chrdev (KBD_MAJOR, "kbd", &kbd_fops)){
+               printk ("Could not register /dev/kbd device\n");
+               return;
+       }
+       return;
+}
diff --git a/drivers/sbus/char/sunkeymap.c b/drivers/sbus/char/sunkeymap.c
new file mode 100644 (file)
index 0000000..17b2f57
--- /dev/null
@@ -0,0 +1,262 @@
+/* Do not edit this file! It was automatically generated by   */
+/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+u_short plain_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf100, 0xf101, 0xf109,
+       0xf102, 0xf10a, 0xf103, 0xf10b, 0xf104, 0xf701, 0xf105, 0xf200,
+       0xf106, 0xf107, 0xf108, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf209,
+       0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf01b, 0xf031, 0xf032,
+       0xf033, 0xf034, 0xf035, 0xf036, 0xf037, 0xf038, 0xf039, 0xf030,
+       0xf02d, 0xf03d, 0xf060, 0xf07f, 0xf115, 0xf03d, 0xf30d, 0xf30c,
+       0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf009, 0xfb71, 0xfb77,
+       0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, 0xfb6f, 0xfb70,
+       0xf05b, 0xf05d, 0xf07f, 0xf20e, 0xf307, 0xf308, 0xf309, 0xf30b,
+       0xf200, 0xf200, 0xf117, 0xf200, 0xf702, 0xfb61, 0xfb73, 0xfb64,
+       0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b, 0xf027,
+       0xf05c, 0xf201, 0xf30e, 0xf304, 0xf305, 0xf306, 0xf300, 0xf200,
+       0xf118, 0xf200, 0xf208, 0xf700, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
+       0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf00a,
+       0xf301, 0xf302, 0xf303, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207,
+       0xf200, 0xf020, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200,
+};
+
+u_short shift_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf10a, 0xf10b, 0xf113,
+       0xf10c, 0xf10a, 0xf10d, 0xf10b, 0xf10e, 0xf701, 0xf105, 0xf200,
+       0xf110, 0xf107, 0xf112, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf203,
+       0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf01b, 0xf021, 0xf040,
+       0xf023, 0xf024, 0xf025, 0xf05e, 0xf026, 0xf02a, 0xf028, 0xf029,
+       0xf05f, 0xf02b, 0xf07e, 0xf07f, 0xf115, 0xf200, 0xf30d, 0xf30c,
+       0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf009, 0xfb51, 0xfb57,
+       0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49, 0xfb4f, 0xfb50,
+       0xf07b, 0xf07d, 0xf07f, 0xf20e, 0xf307, 0xf308, 0xf309, 0xf30b,
+       0xf200, 0xf200, 0xf117, 0xf200, 0xf702, 0xfb41, 0xfb53, 0xfb44,
+       0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a, 0xf022,
+       0xf07c, 0xf201, 0xf30e, 0xf304, 0xf305, 0xf306, 0xf300, 0xf200,
+       0xf20b, 0xf200, 0xf208, 0xf700, 0xfb5a, 0xfb58, 0xfb43, 0xfb56,
+       0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf200,
+       0xf301, 0xf302, 0xf303, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207,
+       0xf200, 0xf020, 0xf200, 0xf20a, 0xf200, 0xf30a, 0xf200, 0xf200,
+};
+
+u_short altgr_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf50c, 0xf50d, 0xf515,
+       0xf50e, 0xf516, 0xf50f, 0xf517, 0xf510, 0xf701, 0xf200, 0xf200,
+       0xf512, 0xf513, 0xf514, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf202,
+       0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf200, 0xf200, 0xf040,
+       0xf200, 0xf024, 0xf200, 0xf200, 0xf07b, 0xf05b, 0xf05d, 0xf07d,
+       0xf05c, 0xf200, 0xf200, 0xf200, 0xf115, 0xf200, 0xf30d, 0xf30c,
+       0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf200, 0xfb71, 0xfb77,
+       0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, 0xfb6f, 0xfb70,
+       0xf200, 0xf07e, 0xf200, 0xf20e, 0xf911, 0xf912, 0xf913, 0xf30b,
+       0xf200, 0xf200, 0xf117, 0xf200, 0xf702, 0xf914, 0xfb73, 0xf917,
+       0xf919, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf200, 0xf200,
+       0xf200, 0xf201, 0xf30e, 0xf90e, 0xf90f, 0xf910, 0xf90a, 0xf200,
+       0xf118, 0xf200, 0xf208, 0xf700, 0xfb7a, 0xfb78, 0xf916, 0xfb76,
+       0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200,
+       0xf90b, 0xf90c, 0xf90d, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207,
+       0xf200, 0xf200, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200,
+};
+
+u_short ctrl_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf100, 0xf101, 0xf109,
+       0xf102, 0xf10a, 0xf103, 0xf10b, 0xf104, 0xf701, 0xf200, 0xf200,
+       0xf107, 0xf200, 0xf108, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf204,
+       0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf200, 0xf200, 0xf000,
+       0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f, 0xf07f, 0xf200, 0xf200,
+       0xf01f, 0xf200, 0xf000, 0xf008, 0xf115, 0xf200, 0xf30d, 0xf30c,
+       0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf200, 0xf011, 0xf017,
+       0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, 0xf00f, 0xf010,
+       0xf01b, 0xf01d, 0xf008, 0xf20e, 0xf307, 0xf308, 0xf309, 0xf30b,
+       0xf200, 0xf200, 0xf117, 0xf200, 0xf702, 0xf001, 0xf013, 0xf004,
+       0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, 0xf007,
+       0xf01c, 0xf201, 0xf30e, 0xf304, 0xf305, 0xf306, 0xf300, 0xf200,
+       0xf118, 0xf200, 0xf208, 0xf700, 0xf01a, 0xf018, 0xf003, 0xf016,
+       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf700, 0xf200,
+       0xf301, 0xf302, 0xf303, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207,
+       0xf200, 0xf000, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200,
+};
+
+u_short shift_ctrl_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf701, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf200,
+       0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf200, 0xf200, 0xf000,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf01f, 0xf200, 0xf200, 0xf200, 0xf115, 0xf200, 0xf30d, 0xf30c,
+       0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf200, 0xf011, 0xf017,
+       0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, 0xf00f, 0xf010,
+       0xf200, 0xf200, 0xf200, 0xf20e, 0xf307, 0xf308, 0xf309, 0xf30b,
+       0xf200, 0xf200, 0xf117, 0xf200, 0xf702, 0xf001, 0xf013, 0xf004,
+       0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, 0xf200,
+       0xf200, 0xf201, 0xf30e, 0xf304, 0xf305, 0xf306, 0xf300, 0xf200,
+       0xf118, 0xf200, 0xf208, 0xf700, 0xf01a, 0xf018, 0xf003, 0xf016,
+       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200,
+       0xf301, 0xf302, 0xf303, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207,
+       0xf200, 0xf200, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200,
+};
+
+u_short alt_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf500, 0xf501, 0xf509,
+       0xf502, 0xf50a, 0xf503, 0xf50b, 0xf504, 0xf701, 0xf505, 0xf200,
+       0xf507, 0xf200, 0xf508, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf209,
+       0xf210, 0xf200, 0xf200, 0xf600, 0xf211, 0xf81b, 0xf831, 0xf832,
+       0xf833, 0xf834, 0xf835, 0xf836, 0xf837, 0xf838, 0xf839, 0xf830,
+       0xf82d, 0xf83d, 0xf860, 0xf87f, 0xf115, 0xf200, 0xf30d, 0xf30c,
+       0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf809, 0xf871, 0xf877,
+       0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869, 0xf86f, 0xf870,
+       0xf85b, 0xf85d, 0xf200, 0xf87f, 0xf907, 0xf908, 0xf909, 0xf30b,
+       0xf200, 0xf200, 0xf117, 0xf200, 0xf702, 0xf861, 0xf873, 0xf864,
+       0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b, 0xf827,
+       0xf85c, 0xf80d, 0xf30e, 0xf904, 0xf905, 0xf906, 0xf900, 0xf200,
+       0xf118, 0xf200, 0xf208, 0xf700, 0xf87a, 0xf878, 0xf863, 0xf876,
+       0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf200,
+       0xf901, 0xf902, 0xf903, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207,
+       0xf200, 0xf820, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200,
+};
+
+u_short ctrl_alt_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf500, 0xf501, 0xf509,
+       0xf502, 0xf50a, 0xf503, 0xf50b, 0xf504, 0xf701, 0xf200, 0xf200,
+       0xf507, 0xf200, 0xf508, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf200,
+       0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf115, 0xf200, 0xf30d, 0xf30c,
+       0xf200, 0xf200, 0xf20c, 0xf200, 0xf114, 0xf200, 0xf811, 0xf817,
+       0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809, 0xf80f, 0xf810,
+       0xf200, 0xf200, 0xf200, 0xf20e, 0xf307, 0xf308, 0xf309, 0xf30b,
+       0xf200, 0xf200, 0xf117, 0xf200, 0xf702, 0xf801, 0xf813, 0xf804,
+       0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200, 0xf200,
+       0xf200, 0xf201, 0xf30e, 0xf304, 0xf305, 0xf306, 0xf300, 0xf200,
+       0xf118, 0xf200, 0xf208, 0xf700, 0xf81a, 0xf818, 0xf803, 0xf816,
+       0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200,
+       0xf301, 0xf302, 0xf303, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207,
+       0xf200, 0xf200, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+       plain_map, shift_map, altgr_map, 0,
+       ctrl_map, shift_ctrl_map, 0, 0,
+       alt_map, 0, 0, 0,
+       ctrl_alt_map,   0
+};
+
+unsigned int keymap_count = 7;
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+       '\033', '[', '[', 'A', 0, 
+       '\033', '[', '[', 'B', 0, 
+       '\033', '[', '[', 'C', 0, 
+       '\033', '[', '[', 'D', 0, 
+       '\033', '[', '[', 'E', 0, 
+       '\033', '[', '1', '7', '~', 0, 
+       '\033', '[', '1', '8', '~', 0, 
+       '\033', '[', '1', '9', '~', 0, 
+       '\033', '[', '2', '0', '~', 0, 
+       '\033', '[', '2', '1', '~', 0, 
+       '\033', '[', '2', '3', '~', 0, 
+       '\033', '[', '2', '4', '~', 0, 
+       '\033', '[', '2', '5', '~', 0, 
+       '\033', '[', '2', '6', '~', 0, 
+       '\033', '[', '2', '8', '~', 0, 
+       '\033', '[', '2', '9', '~', 0, 
+       '\033', '[', '3', '1', '~', 0, 
+       '\033', '[', '3', '2', '~', 0, 
+       '\033', '[', '3', '3', '~', 0, 
+       '\033', '[', '3', '4', '~', 0, 
+       '\033', '[', '1', '~', 0, 
+       '\033', '[', '2', '~', 0, 
+       '\033', '[', '3', '~', 0, 
+       '\033', '[', '4', '~', 0, 
+       '\033', '[', '5', '~', 0, 
+       '\033', '[', '6', '~', 0, 
+       '\033', '[', 'M', 0, 
+       '\033', '[', 'P', 0, 
+};
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0;          /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+       func_buf + 0,
+       func_buf + 5,
+       func_buf + 10,
+       func_buf + 15,
+       func_buf + 20,
+       func_buf + 25,
+       func_buf + 31,
+       func_buf + 37,
+       func_buf + 43,
+       func_buf + 49,
+       func_buf + 55,
+       func_buf + 61,
+       func_buf + 67,
+       func_buf + 73,
+       func_buf + 79,
+       func_buf + 85,
+       func_buf + 91,
+       func_buf + 97,
+       func_buf + 103,
+       func_buf + 109,
+       func_buf + 115,
+       func_buf + 120,
+       func_buf + 125,
+       func_buf + 130,
+       func_buf + 135,
+       func_buf + 140,
+       func_buf + 145,
+       0,
+       0,
+       func_buf + 149,
+       0,
+};
+
+struct kbdiacr accent_table[MAX_DIACR] = {
+       {'`', 'A', '\300'},     {'`', 'a', '\340'},
+       {'\'', 'A', '\301'},    {'\'', 'a', '\341'},
+       {'^', 'A', '\302'},     {'^', 'a', '\342'},
+       {'~', 'A', '\303'},     {'~', 'a', '\343'},
+       {'"', 'A', '\304'},     {'"', 'a', '\344'},
+       {'O', 'A', '\305'},     {'o', 'a', '\345'},
+       {'0', 'A', '\305'},     {'0', 'a', '\345'},
+       {'A', 'A', '\305'},     {'a', 'a', '\345'},
+       {'A', 'E', '\306'},     {'a', 'e', '\346'},
+       {',', 'C', '\307'},     {',', 'c', '\347'},
+       {'`', 'E', '\310'},     {'`', 'e', '\350'},
+       {'\'', 'E', '\311'},    {'\'', 'e', '\351'},
+       {'^', 'E', '\312'},     {'^', 'e', '\352'},
+       {'"', 'E', '\313'},     {'"', 'e', '\353'},
+       {'`', 'I', '\314'},     {'`', 'i', '\354'},
+       {'\'', 'I', '\315'},    {'\'', 'i', '\355'},
+       {'^', 'I', '\316'},     {'^', 'i', '\356'},
+       {'"', 'I', '\317'},     {'"', 'i', '\357'},
+       {'-', 'D', '\320'},     {'-', 'd', '\360'},
+       {'~', 'N', '\321'},     {'~', 'n', '\361'},
+       {'`', 'O', '\322'},     {'`', 'o', '\362'},
+       {'\'', 'O', '\323'},    {'\'', 'o', '\363'},
+       {'^', 'O', '\324'},     {'^', 'o', '\364'},
+       {'~', 'O', '\325'},     {'~', 'o', '\365'},
+       {'"', 'O', '\326'},     {'"', 'o', '\366'},
+       {'/', 'O', '\330'},     {'/', 'o', '\370'},
+       {'`', 'U', '\331'},     {'`', 'u', '\371'},
+       {'\'', 'U', '\332'},    {'\'', 'u', '\372'},
+       {'^', 'U', '\333'},     {'^', 'u', '\373'},
+       {'"', 'U', '\334'},     {'"', 'u', '\374'},
+       {'\'', 'Y', '\335'},    {'\'', 'y', '\375'},
+       {'T', 'H', '\336'},     {'t', 'h', '\376'},
+       {'s', 's', '\337'},     {'"', 'y', '\377'},
+       {'s', 'z', '\337'},     {'i', 'j', '\377'},
+};
+
+unsigned int accent_table_size = 68;
diff --git a/drivers/sbus/char/sunkeymap.map b/drivers/sbus/char/sunkeymap.map
new file mode 100644 (file)
index 0000000..3b03ef5
--- /dev/null
@@ -0,0 +1,372 @@
+# Keyboard map for the Sun Type4/Type5 keyboards
+# found on SparcStations
+keymaps 0-2,4-5,8,12
+#
+#
+# Stop/L1
+keycode        0x01 =
+# SND_LOWER
+keycode        0x02 =
+# Again/L2
+keycode        0x03 =
+# SND_LOUDER
+keycode        0x04 =
+keycode        0x05 = F1                       F11     Console_13
+       control keycode                 0x05 = F1
+       alt     keycode                 0x05 = Console_1
+       control alt     keycode         0x05 = Console_1
+keycode        0x06 = F2                       F12     Console_14
+       control keycode                 0x06 = F2
+       alt     keycode                 0x06 = Console_2
+       control alt     keycode         0x06 = Console_2
+keycode        0x07 = F10                      F20     Console_22
+       control keycode                 0x07 = F10
+       alt     keycode                 0x07 = Console_10
+       control alt     keycode         0x07 = Console_10
+keycode        0x08 = F3                       F13     Console_15
+       control keycode                 0x08 = F3
+       alt     keycode                 0x08 = Console_3
+       control alt     keycode         0x08 = Console_3
+keycode        0x09 = F11                      F11     Console_23
+       control keycode                 0x09 = F11
+       alt     keycode                 0x09 = Console_11
+       control alt     keycode         0x09 = Console_11
+keycode        0x0a = F4                       F14     Console_16
+       control keycode                 0x0a = F4
+       alt     keycode                 0x0a = Console_4
+       control alt     keycode         0x0a = Console_4
+keycode        0x0b = F12                      F12     Console_24
+       control keycode                 0x0b = F12
+       alt     keycode                 0x0b = Console_12
+       control alt     keycode         0x0b = Console_12
+keycode        0x0c = F5                       F15     Console_17
+       control Keycode                 0x0c = F5
+       alt     keycode                 0x0c = Console_5
+       control alt     keycode         0x0c = Console_5
+keycode        0x0d = AltGr
+keycode 0x0e = F6                      F6
+       alt     keycode                 0x0e = Console_6
+# BLANK KEY on type 5 keyboards
+keycode 0x0f =
+keycode 0x10 = F7                      F17     Console_19
+       control Keycode                 0x10 = F7
+       alt     keycode                 0x10 = Console_7
+       control alt     keycode         0x10 = Console_7
+keycode 0x11 = F8                      F8      Console_20
+       control keycode                 0x10 = F8
+       alt     keycode                 0x10 = Console_8
+       control alt     keycode         0x10 = Console_8
+keycode 0x12 = F9                      F19     Console_21
+       control keycode                 0x12 = F9
+       alt     keycode                 0x12 = Console_9
+       control alt     keycode         0x12 = Console_9
+keycode 0x13 = Alt
+keycode 0x14 = Up
+keycode 0x15 = Pause
+# Print Screen
+keycode 0x16 = 
+keycode 0x17 = Scroll_Lock     Show_Memory     Show_Registers
+       control keycode                         0x17 = Show_State
+       alt     keycode                         0x17 = Scroll_Lock
+keycode 0x18 = Left
+       alt     keycode                         0x18 = Decr_Console
+# Props/L3
+keycode 0x19 =
+# UNDO/L4
+keycode 0x1a =
+keycode 0x1b = Down
+keycode 0x1c = Right
+       alt     keycode                         0x1c = Incr_Console
+keycode 0x1d = Escape          Escape
+       alt     keycode                         0x1d = Meta_Escape
+keycode 0x1e = one             exclam
+       alt     keycode                         0x1e = Meta_one
+keycode 0x1f = two             at              at
+       control keycode                         0x1f = nul
+       shift   control keycode                 0x1f = nul
+       alt     keycode                         0x1f = Meta_two
+keycode 0x20 = three           numbersign
+       control keycode                         0x20 = Escape
+       alt     keycode                         0x20 = Meta_three
+keycode 0x21 = four            dollar          dollar
+       control keycode                         0x21 = Control_backslash
+       alt     keycode                         0x21 = Meta_four
+keycode 0x22 = five            percent
+       control keycode                         0x22 = Control_bracketright
+       alt     keycode                         0x22 = Meta_five
+keycode 0x23 = six             asciicircum
+       control keycode                         0x23 = Control_asciicircum
+       alt     keycode                         0x23 = Meta_six
+keycode 0x24 = seven           ampersand       braceleft
+       control keycode                         0x24 = Control_underscore
+       alt     keycode                         0x24 = Meta_seven
+keycode 0x25 = eight           asterisk        bracketleft
+       control keycode                         0x25 = Delete
+       alt     keycode                         0x25 = Meta_eight
+keycode 0x26 = nine            parenleft       bracketright
+       alt     keycode                         0x26 = Meta_nine
+keycode 0x27 = zero            parenright      braceright
+       alt     keycode                         0x27 = Meta_zero
+keycode 0x28 = minus           underscore      backslash
+       control keycode                         0x28 = Control_underscore
+       shift   control keycode                 0x28 = Control_underscore
+       alt     keycode                         0x28 = Meta_minus
+keycode 0x29 = equal           plus
+       alt     keycode                         0x29 = Meta_equal
+keycode 0x2a = grave           asciitilde
+       control keycode                         0x2a = nul
+       alt     keycode                         0x2a = Meta_grave
+# Is marked as BackSpace but we define it as delete just like the i386
+# keyboard maps does
+keycode 0x2b = Delete          Delete
+       control keycode                         0x2b = BackSpace
+       alt     keycode                         0x2b = Meta_Delete
+keycode 0x2c = Insert
+# This is really keypad = on type 4 keyboards
+keycode 0x2d = equal
+keycode 0x2e = KP_Divide
+keycode 0x2f = KP_Multiply
+# Power ON/OFF key on type 5 keyboard
+keycode 0x30 =
+# FRONT/L5
+keycode 0x31 = 
+keycode 0x32 = KP_Period
+#      altgr   control keycode                 0x32 = Boot
+       control alt     keycode                 0x32 = Boot
+# COPY/L6
+keycode 0x33 =
+# Home key, same difference
+keycode 0x34 = Find
+keycode 0x35 = Tab             Tab
+       alt     keycode                         0x35 = Meta_Tab
+keycode 0x36 = q
+keycode 0x37 = w
+keycode 0x38 = e
+       altgr   keycode                         0x38 = Hex_E
+keycode 0x39 = r
+keycode 0x3a = t
+keycode 0x3b = y
+keycode 0x3c = u
+keycode 0x3d = i
+keycode 0x3e = o
+keycode 0x3f = p
+keycode 0x40 = bracketleft     braceleft
+       control keycode                         0x40 = Escape
+       alt     keycode                         0x40 = Meta_bracketleft
+keycode 0x41 = bracketright    braceright      asciitilde
+       control keycode                         0x41 = Control_bracketright
+       alt     keycode                         0x41 = Meta_bracketright
+keycode 0x42 = Delete          Delete
+       control keycode                         0x42 = BackSpace
+       alt     keycode                         0x43 = Meta_Delete
+keycode 0x43 = Compose
+keycode 0x44 = KP_7
+       alt     keycode                         0x44 = Ascii_7
+       altgr   keycode                         0x44 = Hex_7
+keycode 0x45 = KP_8
+       alt     keycode                         0x45 = Ascii_8
+       altgr   keycode                         0x45 = Hex_8
+keycode 0x46 = KP_9
+       alt     keycode                         0x46 = Ascii_9
+       altgr   keycode                         0x46 = Hex_9
+keycode 0x47 = KP_Subtract
+# OPEN/L6
+keycode 0x48 = 
+# PASTE/L8
+keycode 0x49 =
+keycode 0x4a = Select
+# No key produces 0x4b to my knowledge
+keycode 0x4b =
+keycode 0x4c = Control
+keycode 0x4d = a
+       altgr   keycode                         0x4d = Hex_A
+keycode 0x4e = s
+keycode 0x4f = d
+       altgr   keycode                         0x4f = Hex_D
+keycode 0x50 = f
+       altgr   keycode                         0x50 = Hex_F
+keycode 0x51 = g
+keycode 0x52 = h
+keycode 0x53 = j
+keycode 0x54 = k
+keycode 0x55 = l
+keycode 0x56 = semicolon       colon
+       alt     keycode                         0x56 = Meta_semicolon
+keycode 0x57 = apostrophe      quotedbl
+       control keycode                         0x57 = Control_g
+       alt     keycode                         0x57 = Meta_apostrophe
+keycode 0x58 = backslash       bar
+       control keycode                         0x58 = Control_backslash
+       alt     keycode                         0x58 = Meta_backslash
+keycode 0x59 = Return
+       alt     keycode                         0x59 = Meta_Control_m
+keycode 0x5a = KP_Enter
+keycode 0x5b = KP_4
+       alt     keycode                         0x5b = Ascii_4
+       altgr   keycode                         0x5b = Hex_4
+keycode 0x5c = KP_5
+       alt     keycode                         0x5c = Ascii_5
+       altgr   keycode                         0x5c = Hex_5
+keycode 0x5d = KP_6
+       alt     keycode                         0x5d = Ascii_6
+       altgr   keycode                         0x5d = Hex_6
+keycode 0x5e = KP_0
+       alt     keycode                         0x5e = Ascii_0
+       altgr   keycode                         0x5e = Hex_0
+# FIND/L9
+keycode 0x5f =
+keycode 0x60 = Prior
+       shift   keycode                         0x60 = Scroll_Backward
+# CUT/L10
+keycode 0x61 =
+keycode 0x62 = Num_Lock
+# Linux/i386 console makes no distinction between right/left shift
+# so neither do we.
+keycode 0x63 = Shift
+keycode 0x64 = z
+keycode 0x65 = x
+keycode 0x66 = c
+       altgr   keycode                         0x66 = Hex_C
+keycode 0x67 = v
+keycode 0x68 = b
+       altgr   keycode                         0x68 = Hex_B
+keycode 0x69 = n
+keycode 0x6a = m
+keycode 0x6b = comma           less
+       alt     keycode                         0x6b = Meta_comma
+keycode 0x6c = period          greater
+       control keycode                         0x6c = Compose
+       alt     keycode                         0x6c = Meta_period
+keycode 0x6d = slash           question
+       control keycode                         0x6d = Delete
+       alt     keycode                         0x6d = Meta_slash
+keycode 0x6e = Shift
+keycode 0x6f = Linefeed
+keycode 0x70 = KP_1
+       alt     keycode                         0x70 = Ascii_1
+       altgr   keycode                         0x70 = Hex_1
+keycode 0x71 = KP_2
+       alt     keycode                         0x71 = Ascii_2
+       altgr   keycode                         0x71 = Hex_2
+keycode 0x72 = KP_3
+       alt     keycode                         0x72 = Ascii_3
+       altgr   keycode                         0x72 = Hex_3
+# To my knowledge no key produces 0x73, 0x74, or 0x75
+keycode 0x73 =
+keycode 0x74 =
+keycode 0x75 =
+keycode 0x76 = Help
+keycode 0x77 = Caps_Lock
+# A True Meta-key, unused at this time
+keycode 0x78 =
+keycode 0x79 = space           space
+       control keycode                         0x79 = nul
+       alt     keycode                         0x79 = Meta_space
+# Another real Meta-key, again unused
+keycode 0x7a =
+keycode 0x7b = Next
+       shift   keycode                         0x7b = Scroll_Forward
+# No keys produce the following
+keycode 0x7c =
+keycode 0x7d = KP_Add
+keycode 0x7e =
+# keycode 0x7f is special and it means 'all keys released' and is
+# taken care of within the sun keyboard driver itself
+keycode 0x7f =
+# Thats all folks...
+string F1 = "\033[[A"
+string F2 = "\033[[B"
+string F3 = "\033[[C"
+string F4 = "\033[[D"
+string F5 = "\033[[E"
+string F6 = "\033[17~"
+string F7 = "\033[18~"
+string F8 = "\033[19~"
+string F9 = "\033[20~"
+string F10 = "\033[21~"
+string F11 = "\033[23~"
+string F12 = "\033[24~"
+string F13 = "\033[25~"
+string F14 = "\033[26~"
+string F15 = "\033[28~"
+string F16 = "\033[29~"
+string F17 = "\033[31~"
+string F18 = "\033[32~"
+string F19 = "\033[33~"
+string F20 = "\033[34~"
+string Find = "\033[1~"
+string Insert = "\033[2~"
+string Remove = "\033[3~"
+string Select = "\033[4~"
+string Prior = "\033[5~"
+string Next = "\033[6~"
+string Macro = "\033[M"
+string Pause = "\033[P"
+compose '`' 'A' to 'À'
+compose '`' 'a' to 'à'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ã'
+compose '~' 'a' to 'ã'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Å'
+compose 'o' 'a' to 'å'
+compose '0' 'A' to 'Å'
+compose '0' 'a' to 'å'
+compose 'A' 'A' to 'Å'
+compose 'a' 'a' to 'å'
+compose 'A' 'E' to 'Æ'
+compose 'a' 'e' to 'æ'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'È'
+compose '`' 'e' to 'è'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ê'
+compose '^' 'e' to 'ê'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ì'
+compose '`' 'i' to 'ì'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ï'
+compose '"' 'i' to 'ï'
+compose '-' 'D' to 'Ð'
+compose '-' 'd' to 'ð'
+compose '~' 'N' to 'Ñ'
+compose '~' 'n' to 'ñ'
+compose '`' 'O' to 'Ò'
+compose '`' 'o' to 'ò'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Õ'
+compose '~' 'o' to 'õ'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ø'
+compose '/' 'o' to 'ø'
+compose '`' 'U' to 'Ù'
+compose '`' 'u' to 'ù'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Û'
+compose '^' 'u' to 'û'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Þ'
+compose 't' 'h' to 'þ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to 'ÿ'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to 'ÿ'
diff --git a/drivers/sbus/char/sunmouse.c b/drivers/sbus/char/sunmouse.c
new file mode 100644 (file)
index 0000000..9b32cf5
--- /dev/null
@@ -0,0 +1,420 @@
+/* sunmouse.c: Sun mouse driver for the Sparc
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Parts based on the psaux.c driver written by:
+ * Johan Myreen.
+ *
+ * Dec/19/95 Added SunOS mouse ioctls - miguel.
+ * Jan/5/96  Added VUID support, sigio support - miguel.
+ * Mar/5/96  Added proper mouse stream support - miguel.
+ */
+
+/* The mouse is run off of one of the Zilog serial ports.  On
+ * that port is the mouse and the keyboard, each gets a zs channel.
+ * The mouse itself is mouse-systems in nature.  So the protocol is:
+ *
+ * Byte 1) Button state which is bit-encoded as
+ *            0x4 == left-button down, else up
+ *            0x2 == middle-button down, else up
+ *            0x1 == right-button down, else up
+ *
+ * Byte 2) Delta-x
+ * Byte 3) Delta-y
+ * Byte 4) Delta-x again
+ * Byte 5) Delta-y again
+ *
+ * One day this driver will have to support more than one mouse in the system.
+ *
+ * This driver has two modes of operation: the default VUID_NATIVE is
+ * set when the device is opened and allows the application to see the
+ * mouse character stream as we get it from the serial (for gpm for
+ * example).  The second method, VUID_FIRM_EVENT will provide cooked
+ * events in Firm_event records.
+ * */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fcntl.h>
+#include <linux/signal.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/vuid_event.h>
+#include <linux/random.h>
+/* The following keeps track of software state for the Sun
+ * mouse.
+ */
+#define STREAM_SIZE   2048
+#define EV_SIZE       (STREAM_SIZE/sizeof (Firm_event))
+#define BUTTON_LEFT   4
+#define BUTTON_MIDDLE 2
+#define BUTTON_RIGHT  1
+
+struct sun_mouse {
+       unsigned char transaction[5];  /* Each protocol transaction */
+       unsigned char byte;            /* Counter, starts at 0 */
+       unsigned char button_state;    /* Current button state */
+       unsigned char prev_state;      /* Previous button state */
+       int delta_x;                   /* Current delta-x */
+       int delta_y;                   /* Current delta-y */
+       int present;
+       int ready;                     /* set if there if data is available */
+       int active;                    /* set if device is open */
+        int vuid_mode;                /* VUID_NATIVE or VUID_FIRM_EVENT */
+       struct wait_queue *proc_list;
+       struct fasync_struct *fasync;
+       
+       /* The event/stream queue */
+       unsigned int head;
+       unsigned int tail;
+       union {
+               char stream [STREAM_SIZE];
+               Firm_event ev [0];
+       } queue;
+};
+
+static struct sun_mouse sunmouse;
+#define gen_events (sunmouse.vuid_mode != VUID_NATIVE)
+#define bstate sunmouse.button_state
+#define pstate sunmouse.prev_state
+
+extern void mouse_put_char(char ch);
+
+/* #define SMOUSE_DEBUG */
+
+static void
+push_event (Firm_event *ev)
+{
+       int next = (sunmouse.head + 1) % EV_SIZE;
+       
+       if (next != sunmouse.tail){
+               sunmouse.queue.ev [sunmouse.head] = *ev;
+               sunmouse.head = next;
+       }
+}
+
+static int
+queue_empty (void)
+{
+       return sunmouse.head == sunmouse.tail;
+}
+
+static Firm_event *
+get_from_queue (void)
+{
+       Firm_event *result;
+       
+       result = &sunmouse.queue.ev [sunmouse.tail];
+       sunmouse.tail = (sunmouse.tail + 1) % EV_SIZE;
+       return result;
+}
+
+static void
+push_char (char c)
+{
+       int next = (sunmouse.head + 1) % STREAM_SIZE;
+
+       if (next != sunmouse.tail){
+               sunmouse.queue.stream [sunmouse.head] = c;
+               sunmouse.head = next;
+       }
+       sunmouse.ready = 1;
+       if (sunmouse.fasync)
+               kill_fasync (sunmouse.fasync, SIGIO);
+       wake_up_interruptible (&sunmouse.proc_list);
+}
+
+/* The following is called from the zs driver when bytes are received on
+ * the Mouse zs8530 channel.
+ */
+void
+sun_mouse_inbyte(unsigned char byte, unsigned char status)
+{
+       signed char mvalue;
+       int d;
+       Firm_event ev;
+
+       add_mouse_randomness (byte);
+       if(!sunmouse.active)
+               return;
+
+       if (!gen_events){
+               push_char (byte);
+               return;
+       }
+       /* Check for framing errors and parity errors */
+       /* XXX TODO XXX */
+
+       /* If the mouse sends us a byte from 0x80 to 0x87
+        * we are starting at byte zero in the transaction
+        * protocol.
+        */
+       if(byte >= 0x80 && byte <= 0x87)
+               sunmouse.byte = 0;
+
+       mvalue = (signed char) byte;
+       switch(sunmouse.byte) {
+       case 0:
+               /* Button state */
+               sunmouse.button_state = (~byte) & 0x7;
+#ifdef SMOUSE_DEBUG
+               printk("B<Left %s, Middle %s, Right %s>",
+                      ((sunmouse.button_state & 0x4) ? "DOWN" : "UP"),
+                      ((sunmouse.button_state & 0x2) ? "DOWN" : "UP"),
+                      ((sunmouse.button_state & 0x1) ? "DOWN" : "UP"));
+#endif
+               sunmouse.byte++;
+               return;
+       case 1:
+               /* Delta-x 1 */
+#ifdef SMOUSE_DEBUG
+               printk("DX1<%d>", mvalue);
+#endif
+               sunmouse.delta_x = mvalue;
+               sunmouse.byte++;
+               return;
+       case 2:
+               /* Delta-y 1 */
+#ifdef SMOUSE_DEBUG
+               printk("DY1<%d>", mvalue);
+#endif
+               sunmouse.delta_y = mvalue;
+               sunmouse.byte++;
+               return;
+       case 3:
+               /* Delta-x 2 */
+#ifdef SMOUSE_DEBUG
+               printk("DX2<%d>", mvalue);
+#endif
+               sunmouse.delta_x += mvalue;
+               sunmouse.byte++;
+               return;
+       case 4:
+               /* Last byte, Delta-y 2 */
+#ifdef SMOUSE_DEBUG
+               printk("DY2<%d>", mvalue);
+#endif
+               sunmouse.delta_y += mvalue;
+               sunmouse.byte = 69;  /* Some ridiculous value */
+               break;
+       case 69:
+               /* Until we get the (0x80 -> 0x87) value we aren't
+                * in the middle of a real transaction, so just
+                * return.
+                */
+               return;
+       default:
+               printk("sunmouse: bogon transaction state\n");
+               sunmouse.byte = 69;  /* What could cause this? */
+               return;
+       };
+       d = bstate ^ pstate;
+       pstate = bstate;
+       if (d){
+               if (d & BUTTON_LEFT){
+                       ev.id = MS_LEFT;
+                       ev.value = bstate & BUTTON_LEFT;
+               }
+               if (d & BUTTON_RIGHT){
+                       ev.id = MS_RIGHT;
+                       ev.value = bstate & BUTTON_RIGHT;
+               }
+               if (d & BUTTON_MIDDLE){
+                       ev.id = MS_MIDDLE;
+                       ev.value = bstate & BUTTON_MIDDLE;
+               }
+               ev.time = xtime;
+               ev.value = ev.value ? VKEY_DOWN : VKEY_UP;
+               push_event (&ev);
+       }
+       if (sunmouse.delta_x){
+               ev.id = LOC_X_DELTA;
+               ev.time = xtime;
+               ev.value = sunmouse.delta_x;
+               push_event (&ev);
+               sunmouse.delta_x = 0;
+       }
+       if (sunmouse.delta_y){
+               ev.id = LOC_Y_DELTA;
+               ev.time = xtime;
+               ev.value = sunmouse.delta_y;
+               push_event (&ev);
+       }
+       
+        /* We just completed a transaction, wake up whoever is awaiting
+        * this event.
+        */
+       sunmouse.ready = 1;
+       if (sunmouse.fasync)
+               kill_fasync (sunmouse.fasync, SIGIO);
+       wake_up_interruptible(&sunmouse.proc_list);
+       return;
+}
+
+static int
+sun_mouse_open(struct inode * inode, struct file * file)
+{
+       if(!sunmouse.present)
+               return -EINVAL;
+       if(sunmouse.active)
+               return -EBUSY;
+       sunmouse.active = 1;
+       sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0;
+       sunmouse.button_state = 0x80;
+       sunmouse.vuid_mode = VUID_NATIVE;
+       return 0;
+}
+
+static int
+sun_mouse_fasync (struct inode *inode, struct file *filp, int on)
+{
+       int retval;
+
+       retval = fasync_helper (inode, filp, on, &sunmouse.fasync);
+       if (retval < 0)
+               return retval;
+       return 0;
+}
+
+static void
+sun_mouse_close(struct inode *inode, struct file *file)
+{
+       sunmouse.active = sunmouse.ready = 0;
+       sun_mouse_fasync (inode, file, 0);
+}
+
+static int
+sun_mouse_write(struct inode *inode, struct file *file, const char *buffer,
+               int count)
+{
+       return -EINVAL;  /* foo on you */
+}
+
+static int
+sun_mouse_read(struct inode *inode, struct file *file, char *buffer,
+              int count)
+{
+       struct wait_queue wait = { current, NULL };
+
+       if (queue_empty ()){
+               if (file->f_flags & O_NONBLOCK)
+                       return -EWOULDBLOCK;
+               add_wait_queue (&sunmouse.proc_list, &wait);
+               while (queue_empty () && !(current->signal & ~current->blocked)){
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule ();
+               }
+               current->state = TASK_RUNNING;
+               remove_wait_queue (&sunmouse.proc_list, &wait);
+       }
+       if (gen_events){
+               char *p = buffer, *end = buffer+count;
+               
+               while (p < end && !queue_empty ()){
+                       *(Firm_event *)p = *get_from_queue ();
+                       p += sizeof (Firm_event);
+               }
+               sunmouse.ready = !queue_empty ();
+               inode->i_atime = CURRENT_TIME;
+               return p-buffer;
+       } else {
+               int c;
+               
+               for (c = count; !queue_empty () && c; c--){
+                       *buffer++ = sunmouse.queue.stream [sunmouse.tail];
+                       sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE;
+               }
+               sunmouse.ready = !queue_empty ();
+               inode->i_atime = CURRENT_TIME;
+               return count-c;
+       }
+       /* Only called if nothing was sent */
+       if (current->signal & ~current->blocked)
+               return -ERESTARTSYS;
+       return 0;
+}
+
+static int
+sun_mouse_select(struct inode *inode, struct file *file, int sel_type,
+                           select_table *wait)
+{
+       if(sel_type != SEL_IN)
+               return 0;
+       if(sunmouse.ready)
+               return 1;
+       select_wait(&sunmouse.proc_list, wait);
+       return 0;
+}
+int
+sun_mouse_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int i;
+       
+       switch (cmd){
+               /* VUIDGFORMAT - Get input device byte stream format */
+       case _IOR('v', 2, int):
+               i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (int));
+               if (i) return i;
+               *(int *)arg = sunmouse.vuid_mode;
+               break;
+
+               /* VUIDSFORMAT - Set input device byte stream format*/
+       case _IOW('v', 1, int):
+               i = verify_area (VERIFY_READ, (void *)arg, sizeof (int));
+               if (i) return i;
+               i = *(int *) arg;
+               if (i == VUID_NATIVE || i == VUID_FIRM_EVENT){
+                       sunmouse.vuid_mode = *(int *)arg;
+                       sunmouse.head = sunmouse.tail = 0;
+               } else
+                       return -EINVAL;
+               break;
+               
+       default:
+               printk ("[MOUSE-ioctl: %8.8x]\n", cmd);
+               return -1;
+       }
+       return 0;
+}
+
+struct file_operations sun_mouse_fops = {
+       NULL,
+       sun_mouse_read,
+       sun_mouse_write,
+       NULL,
+       sun_mouse_select,
+       sun_mouse_ioctl,
+       NULL,
+       sun_mouse_open,
+       sun_mouse_close,
+       NULL,
+       sun_mouse_fasync,
+};
+
+static struct miscdevice sun_mouse_mouse = {
+       SUN_MOUSE_MINOR, "sunmouse", &sun_mouse_fops
+};
+
+int
+sun_mouse_init(void)
+{
+       printk("Sun Mouse-Systems mouse driver version 1.00\n");
+       sunmouse.present = 1;
+       sunmouse.ready = sunmouse.active = 0;
+       misc_register (&sun_mouse_mouse);
+       sunmouse.delta_x = sunmouse.delta_y = 0;
+       sunmouse.button_state = 0x80;
+       sunmouse.proc_list = NULL;
+       return 0;
+}
+
+void
+sun_mouse_zsinit(void)
+{
+       sunmouse.ready = 1;
+}
diff --git a/drivers/sbus/char/sunserial.c b/drivers/sbus/char/sunserial.c
new file mode 100644 (file)
index 0000000..6f5d9fc
--- /dev/null
@@ -0,0 +1,2196 @@
+/* serial.c: Serial port driver for the Sparc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/oplib.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/delay.h>
+#include <asm/kdebug.h>
+
+#include "sunserial.h"
+
+#define NUM_SERIAL 2     /* Two chips on board. */
+#define NUM_CHANNELS (NUM_SERIAL * 2)
+
+#define KEYBOARD_LINE 0x2
+#define MOUSE_LINE    0x3
+
+struct sun_zslayout *zs_chips[NUM_SERIAL] = { 0, 0, };
+struct sun_zschannel *zs_channels[NUM_CHANNELS] = { 0, 0, 0, 0, };
+struct sun_zschannel *zs_conschan;
+struct sun_zschannel *zs_mousechan;
+struct sun_zschannel *zs_kbdchan;
+struct sun_zschannel *zs_kgdbchan;
+int zs_nodes[NUM_SERIAL] = { 0, 0, };
+
+struct sun_serial zs_soft[NUM_CHANNELS];
+struct sun_serial *zs_chain;  /* IRQ servicing chain */
+int zilog_irq;
+
+struct tty_struct zs_ttys[NUM_CHANNELS];
+/** struct tty_struct *zs_constty; **/
+
+/* Console hooks... */
+static int zs_cons_chanout = 0;
+static int zs_cons_chanin = 0;
+static struct l1a_kbd_state l1a_state = { 0, 0 };
+struct sun_serial *zs_consinfo = 0;
+
+/* Keyboard defines for L1-A processing... */
+#define SUNKBD_RESET   0xff
+#define SUNKBD_L1      0x01
+#define SUNKBD_UP      0x80
+#define SUNKBD_A       0x4d
+
+extern void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs);
+extern void sun_mouse_inbyte(unsigned char byte, unsigned char status);
+
+static unsigned char kgdb_regs[16] = {
+       0, 0, 0,                     /* write 0, 1, 2 */
+       (Rx8 | RxENABLE),            /* write 3 */
+       (X16CLK | SB1 | PAR_EVEN),   /* write 4 */
+       (Tx8 | TxENAB),              /* write 5 */
+       0, 0, 0,                     /* write 6, 7, 8 */
+       (NV),                        /* write 9 */
+       (NRZ),                       /* write 10 */
+       (TCBR | RCBR),               /* write 11 */
+       0, 0,                        /* BRG time constant, write 12 + 13 */
+       (BRSRC | BRENABL),           /* write 14 */
+       (DCDIE)                      /* write 15 */
+};
+
+#define ZS_CLOCK         4915200   /* Zilog input clock rate */
+
+DECLARE_TASK_QUEUE(tq_serial);
+
+struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* serial subtype definitions */
+#define SERIAL_TYPE_NORMAL     1
+#define SERIAL_TYPE_CALLOUT    2
+  
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/* Debugging... DEBUG_INTR is bad to use when one of the zs
+ * lines is your console ;(
+ */
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+
+#define RS_STROBE_TIME 10
+#define RS_ISR_PASS_LIMIT 256
+
+#define _INLINE_ inline
+
+static void change_speed(struct sun_serial *info);
+
+static struct tty_struct *serial_table[NUM_CHANNELS];
+static struct termios *serial_termios[NUM_CHANNELS];
+static struct termios *serial_termios_locked[NUM_CHANNELS];
+
+#ifndef MIN
+#define MIN(a,b)       ((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the memcpy_fromfs blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char tmp_buf[4096]; /* This is cheating */
+static struct semaphore tmp_buf_sem = MUTEX;
+
+static inline int serial_paranoia_check(struct sun_serial *info,
+                                       dev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+       static const char *badmagic =
+               "Warning: bad magic number for serial struct (%d, %d) in %s\n";
+       static const char *badinfo =
+               "Warning: null sun_serial for (%d, %d) in %s\n";
+
+       if (!info) {
+               printk(badinfo, MAJOR(device), MINOR(device), routine);
+               return 1;
+       }
+       if (info->magic != SERIAL_MAGIC) {
+               printk(badmagic, MAJOR(device), MINOR(device), routine);
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int baud_table[] = {
+       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+       9600, 19200, 38400, 57600, 115200, 0 };
+
+/* Reading and writing Zilog8530 registers.  The delays are to make this
+ * driver work on the Sun4 which needs a settling delay after each chip
+ * register access, other machines handle this in hardware via auxiliary
+ * flip-flops which implement the settle time we do in software.
+ */
+static inline unsigned char read_zsreg(struct sun_zschannel *channel, unsigned char reg)
+{
+       unsigned char retval;
+
+       channel->control = reg;
+       udelay(5);
+       retval = channel->control;
+       udelay(5);
+       return retval;
+}
+
+static inline void write_zsreg(struct sun_zschannel *channel, unsigned char reg, unsigned char value)
+{
+       channel->control = reg;
+       udelay(5);
+       channel->control = value;
+       udelay(5);
+       return;
+}
+
+static inline void load_zsregs(struct sun_zschannel *channel, unsigned char *regs)
+{
+       ZS_CLEARERR(channel);
+       ZS_CLEARFIFO(channel);
+       /* Load 'em up */
+       write_zsreg(channel, R4, regs[R4]);
+       write_zsreg(channel, R10, regs[R10]);
+       write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
+       write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+       write_zsreg(channel, R1, regs[R1]);
+       write_zsreg(channel, R9, regs[R9]);
+       write_zsreg(channel, R11, regs[R11]);
+       write_zsreg(channel, R12, regs[R12]);
+       write_zsreg(channel, R13, regs[R13]);
+       write_zsreg(channel, R14, regs[R14]);
+       write_zsreg(channel, R15, regs[R15]);
+       write_zsreg(channel, R3, regs[R3]);
+       write_zsreg(channel, R5, regs[R5]);
+       return;
+}
+
+/* Sets or clears DTR/RTS on the requested line */
+static inline void zs_rtsdtr(struct sun_serial *ss, int set)
+{
+       if(set) {
+               ss->curregs[5] |= (RTS | DTR);
+               ss->pendregs[5] = ss->curregs[5];
+               write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
+       } else {
+               ss->curregs[5] &= ~(RTS | DTR);
+               ss->pendregs[5] = ss->curregs[5];
+               write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
+       }
+       return;
+}
+
+static inline void kgdb_chaninit(struct sun_serial *ss, int intson, int bps)
+{
+       int brg;
+
+       if(intson) {
+               kgdb_regs[R1] = INT_ALL_Rx;
+               kgdb_regs[R9] |= MIE;
+       } else {
+               kgdb_regs[R1] = 0;
+               kgdb_regs[R9] &= ~MIE;
+       }
+       brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+       kgdb_regs[R12] = (brg & 255);
+       kgdb_regs[R13] = ((brg >> 8) & 255);
+       load_zsregs(ss->zs_channel, kgdb_regs);
+}
+
+/* Utility routines for the Zilog */
+static inline int get_zsbaud(struct sun_serial *ss)
+{
+       struct sun_zschannel *channel = ss->zs_channel;
+       int brg;
+
+       /* The baud rate is split up between two 8-bit registers in
+        * what is termed 'BRG time constant' format in my docs for
+        * the chip, it is a function of the clk rate the chip is
+        * receiving which happens to be constant.
+        */
+       brg = ((read_zsreg(channel, 13)&0xff) << 8);
+       brg |= (read_zsreg(channel, 12)&0xff);
+       return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+       struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->device, "rs_stop"))
+               return;
+       
+       save_flags(flags); cli();
+       if (info->curregs[5] & TxENAB) {
+               info->curregs[5] &= ~TxENAB;
+               info->pendregs[5] &= ~TxENAB;
+               write_zsreg(info->zs_channel, 5, info->curregs[5]);
+       }
+       restore_flags(flags);
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+       struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+       unsigned long flags;
+       
+       if (serial_paranoia_check(info, tty->device, "rs_start"))
+               return;
+       
+       save_flags(flags); cli();
+       if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
+               info->curregs[5] |= TxENAB;
+               info->pendregs[5] = info->curregs[5];
+               write_zsreg(info->zs_channel, 5, info->curregs[5]);
+       }
+       restore_flags(flags);
+}
+
+/* Drop into either the boot monitor or kadb upon receiving a break
+ * from keyboard/console input.
+ */
+static void batten_down_hatches(void)
+{
+       /* If we are doing kadb, we call the debugger
+        * else we just drop into the boot monitor.
+        * Note that we must flush the user windows
+        * first before giving up control.
+        */
+       printk("\n");
+       flush_user_windows();
+       if((((unsigned long)linux_dbvec)>=DEBUG_FIRSTVADDR) &&
+          (((unsigned long)linux_dbvec)<=DEBUG_LASTVADDR))
+               sp_enter_debugger();
+       else
+               prom_halt();
+
+       /* XXX We want to notify the keyboard driver that all
+        * XXX keys are in the up state or else weird things
+        * XXX happen...
+        */
+
+       return;
+}
+
+/* On receive, this clears errors and the receiver interrupts */
+static inline void rs_recv_clear(struct sun_zschannel *zsc)
+{
+       zsc->control = ERR_RES;
+       udelay(5);
+       zsc->control = RES_H_IUS;
+       udelay(5);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void rs_sched_event(struct sun_serial *info,
+                                 int event)
+{
+       info->event |= 1 << event;
+       queue_task_irq_off(&info->tqueue, &tq_serial);
+       mark_bh(SERIAL_BH);
+}
+
+extern void breakpoint(void);  /* For the KGDB frame character */
+
+static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs)
+{
+       struct tty_struct *tty = info->tty;
+       unsigned char ch, stat;
+
+       ch = info->zs_channel->data;
+       udelay(5);
+       stat = read_zsreg(info->zs_channel, R1);
+       udelay(5);
+
+       /* If this is the console keyboard, we need to handle
+        * L1-A's here.
+        */
+       if(info->cons_keyb) {
+               if(ch == SUNKBD_RESET) {
+                       l1a_state.kbd_id = 1;
+                       l1a_state.l1_down = 0;
+               } else if(l1a_state.kbd_id) {
+                       l1a_state.kbd_id = 0;
+               } else if(ch == SUNKBD_L1) {
+                       l1a_state.l1_down = 1;
+               } else if(ch == (SUNKBD_L1|SUNKBD_UP)) {
+                       l1a_state.l1_down = 0;
+               } else if(ch == SUNKBD_A && l1a_state.l1_down) {
+                       /* whee... */
+                       batten_down_hatches();
+                       /* Clear the line and continue execution... */
+                       rs_recv_clear(info->zs_channel);
+                       l1a_state.l1_down = 0;
+                       l1a_state.kbd_id = 0;
+                       return;
+               }
+               rs_recv_clear(info->zs_channel);
+               sunkbd_inchar(ch, stat, regs);
+
+               return;
+       }
+       if(info->cons_mouse) {
+               rs_recv_clear(info->zs_channel);
+               sun_mouse_inbyte(ch, stat);
+               return;
+       }
+       if(info->is_cons) {
+               if(ch==0) { /* whee, break received */
+                       batten_down_hatches();
+                       rs_recv_clear(info->zs_channel);
+                       return;
+               } else if (ch == 1) {
+                       show_state();
+                       return;
+               } else if (ch == 2) {
+                       show_buffers();
+                       return;
+               }
+               /* It is a 'keyboard interrupt' ;-) */
+               wake_up(&keypress_wait);
+       }
+       /* Look for kgdb 'stop' character, consult the gdb documentation
+        * for remote target debugging and arch/sparc/kernel/sparc-stub.c
+        * to see how all this works.
+        */
+       if((info->kgdb_channel) && (ch =='\003')) {
+               breakpoint();
+               goto clear_and_exit;
+       }
+
+       if(!tty)
+               goto clear_and_exit;
+
+       if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+               queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+       tty->flip.count++;
+       if(stat & PAR_ERR)
+               *tty->flip.flag_buf_ptr++ = TTY_PARITY;
+       else if(stat & Rx_OVR)
+               *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+       else if(stat & CRC_ERR)
+               *tty->flip.flag_buf_ptr++ = TTY_FRAME;
+       else
+               *tty->flip.flag_buf_ptr++ = 0; /* XXX */
+       *tty->flip.char_buf_ptr++ = ch;
+
+       queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+
+clear_and_exit:
+       rs_recv_clear(info->zs_channel);
+       return;
+}
+
+static _INLINE_ void transmit_chars(struct sun_serial *info)
+{
+       /* P3: In theory we have to test readiness here because a
+        * serial console can clog the chip through rs_put_char().
+        * David did not do this. I think he relies on 3-chars FIFO in 8530.
+        * Let's watch for lost _output_ characters. XXX
+        */
+
+       if (info->x_char) {
+               /* Send next char */
+               info->zs_channel->data = info->x_char;
+               udelay(5);
+               info->x_char = 0;
+               goto clear_and_return;
+       }
+
+       if((info->xmit_cnt <= 0) || info->tty->stopped) {
+               /* Thats peculiar... */
+               info->zs_channel->control = RES_Tx_P;
+               udelay(5);
+               goto clear_and_return;
+       }
+
+       /* Send char */
+       info->zs_channel->data = info->xmit_buf[info->xmit_tail++];
+       udelay(5);
+       info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+       info->xmit_cnt--;
+
+       if (info->xmit_cnt < WAKEUP_CHARS)
+               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+       if(info->xmit_cnt <= 0) {
+               info->zs_channel->control = RES_Tx_P;
+               udelay(5);
+               goto clear_and_return;
+       }
+
+clear_and_return:
+       /* Clear interrupt */
+       info->zs_channel->control = RES_H_IUS;
+       udelay(5);
+       return;
+}
+
+static _INLINE_ void status_handle(struct sun_serial *info)
+{
+       unsigned char status;
+
+       /* Get status from Read Register 0 */
+       status = info->zs_channel->control;
+       udelay(5);
+       /* Clear status condition... */
+       info->zs_channel->control = RES_EXT_INT;
+       udelay(5);
+       /* Clear the interrupt */
+       info->zs_channel->control = RES_H_IUS;
+       udelay(5);
+
+#if 0
+       if(status & DCD) {
+               if((info->tty->termios->c_cflag & CRTSCTS) &&
+                  ((info->curregs[3] & AUTO_ENAB)==0)) {
+                       info->curregs[3] |= AUTO_ENAB;
+                       info->pendregs[3] |= AUTO_ENAB;
+                       write_zsreg(info->zs_channel, 3, info->curregs[3]);
+               }
+       } else {
+               if((info->curregs[3] & AUTO_ENAB)) {
+                       info->curregs[3] &= ~AUTO_ENAB;
+                       info->pendregs[3] &= ~AUTO_ENAB;
+                       write_zsreg(info->zs_channel, 3, info->curregs[3]);
+               }
+       }
+#endif
+       /* Whee, if this is console input and this is a
+        * 'break asserted' status change interrupt, call
+        * the boot prom.
+        */
+       if((status & BRK_ABRT) && info->break_abort)
+               batten_down_hatches();
+
+       /* XXX Whee, put in a buffer somewhere, the status information
+        * XXX whee whee whee... Where does the information go...
+        */
+       return;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       struct sun_serial * info;
+       unsigned char zs_intreg;
+
+       info = zs_chain;
+       if (!info)
+               return;
+
+       zs_intreg = read_zsreg(info->zs_channel, 3);
+
+       /* NOTE: The read register 3, which holds the irq status,
+        *       does so for both channels on each chip.  Although
+        *       the status value itself must be read from the A
+        *       channel and is only valid when read from channel A.
+        *       Yes... broken hardware...
+        */
+#define CHAN_A_IRQMASK (CHARxIP | CHATxIP | CHAEXT)
+#define CHAN_B_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
+
+       /* *** Chip 1 *** */
+       /* Channel A -- /dev/ttya, could be the console */
+       if(zs_intreg & CHAN_A_IRQMASK) {
+               if (zs_intreg & CHARxIP)
+                       receive_chars(info, regs);
+               if (zs_intreg & CHATxIP)
+                       transmit_chars(info);
+               if (zs_intreg & CHAEXT)
+                       status_handle(info);
+       }
+
+       info=info->zs_next;
+
+       /* Channel B -- /dev/ttyb, could be the console */
+       if(zs_intreg & CHAN_B_IRQMASK) {
+               if (zs_intreg & CHBRxIP)
+                       receive_chars(info, regs);
+               if (zs_intreg & CHBTxIP)
+                       transmit_chars(info);
+               if (zs_intreg & CHBEXT)
+                       status_handle(info);
+       }
+
+       info = info->zs_next;
+
+       zs_intreg = read_zsreg(info->zs_channel, 3);
+       /* *** Chip 2 *** */
+       /* Channel A -- /dev/kbd, pass communication to keyboard driver */
+       if(zs_intreg & CHAN_A_IRQMASK) {
+               if (zs_intreg & CHARxIP)
+                       receive_chars(info, regs);
+               if (zs_intreg & CHATxIP)
+                       transmit_chars(info);
+               if (zs_intreg & CHAEXT)
+                       status_handle(info);
+       }
+
+       info=info->zs_next;
+
+       /* Channel B -- /dev/mouse, pass communication to mouse driver */
+       if(zs_intreg & CHAN_B_IRQMASK) {
+               if (zs_intreg & CHBRxIP)
+                       receive_chars(info, regs);
+               if (zs_intreg & CHBTxIP)
+                       transmit_chars(info);
+               if (zs_intreg & CHBEXT)
+                       status_handle(info);
+       }
+
+       return;
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+       run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+       struct sun_serial       *info = (struct sun_serial *) private_;
+       struct tty_struct       *tty;
+       
+       tty = info->tty;
+       if (!tty)
+               return;
+
+       if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+                   tty->ldisc.write_wakeup)
+                       (tty->ldisc.write_wakeup)(tty);
+               wake_up_interruptible(&tty->write_wait);
+       }
+}
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred.  The path of
+ * hangup processing is:
+ *
+ *     serial interrupt routine -> (scheduler tqueue) ->
+ *     do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ * 
+ */
+static void do_serial_hangup(void *private_)
+{
+       struct sun_serial       *info = (struct sun_serial *) private_;
+       struct tty_struct       *tty;
+       
+       tty = info->tty;
+       if (!tty)
+               return;
+
+       tty_hangup(tty);
+}
+
+
+/*
+ * This subroutine is called when the RS_TIMER goes off.  It is used
+ * by the serial driver to handle ports that do not have an interrupt
+ * (irq=0).  This doesn't work very well for 16450's, but gives barely
+ * passable results for a 16550A.  (Although at the expense of much
+ * CPU overhead).
+ */
+static void rs_timer(void)
+{
+       printk("rs_timer called\n");
+       prom_halt();
+       return;
+}
+
+static int startup(struct sun_serial * info)
+{
+       unsigned long flags;
+
+       if (info->flags & ZILOG_INITIALIZED)
+               return 0;
+
+       if (!info->xmit_buf) {
+               info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+               if (!info->xmit_buf)
+                       return -ENOMEM;
+       }
+
+       save_flags(flags); cli();
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("starting up ttys%d (irq %d)...", info->line, info->irq);
+#endif
+
+       /*
+        * Clear the FIFO buffers and disable them
+        * (they will be reenabled in change_speed())
+        */
+       ZS_CLEARFIFO(info->zs_channel);
+       info->xmit_fifo_size = 1;
+
+       /*
+        * Clear the interrupt registers.
+        */
+       info->zs_channel->control = ERR_RES;
+       udelay(5);
+       info->zs_channel->control = RES_H_IUS;
+       udelay(5);
+
+       /*
+        * Now, initialize the Zilog
+        */
+       zs_rtsdtr(info, 1);
+
+       /*
+        * Finally, enable sequencing and interrupts
+        */
+       info->curregs[1] |= (info->curregs[1] & ~0x18) | (EXT_INT_ENAB|INT_ALL_Rx);
+       info->pendregs[1] = info->curregs[1];
+       info->curregs[3] |= (RxENABLE | Rx8);
+       info->pendregs[3] = info->curregs[3];
+       /* We enable Tx interrupts as needed. */
+       info->curregs[5] |= (TxENAB | Tx8);
+       info->pendregs[5] = info->curregs[5];
+       info->curregs[9] |= (NV | MIE);
+       info->pendregs[9] = info->curregs[9];
+       write_zsreg(info->zs_channel, 3, info->curregs[3]);
+       write_zsreg(info->zs_channel, 5, info->curregs[5]);
+       write_zsreg(info->zs_channel, 9, info->curregs[9]);
+       
+       /*
+        * And clear the interrupt registers again for luck.
+        */
+       info->zs_channel->control = ERR_RES;
+       udelay(5);
+       info->zs_channel->control = RES_H_IUS;
+       udelay(5);
+
+       if (info->tty)
+               clear_bit(TTY_IO_ERROR, &info->tty->flags);
+       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+       /*
+        * Set up serial timers...
+        */
+#if 0  /* Works well and stops the machine. */
+       timer_table[RS_TIMER].expires = jiffies + 2;
+       timer_active |= 1 << RS_TIMER;
+#endif
+
+       /*
+        * and set the speed of the serial port
+        */
+       change_speed(info);
+
+       info->flags |= ZILOG_INITIALIZED;
+       restore_flags(flags);
+       return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct sun_serial * info)
+{
+       unsigned long   flags;
+
+       if (!(info->flags & ZILOG_INITIALIZED))
+               return;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("Shutting down serial port %d (irq %d)....", info->line,
+              info->irq);
+#endif
+       
+       save_flags(flags); cli(); /* Disable interrupts */
+       
+       if (info->xmit_buf) {
+               free_page((unsigned long) info->xmit_buf);
+               info->xmit_buf = 0;
+       }
+
+       if (info->tty)
+               set_bit(TTY_IO_ERROR, &info->tty->flags);
+       
+       info->flags &= ~ZILOG_INITIALIZED;
+       restore_flags(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct sun_serial *info)
+{
+       unsigned short port;
+       unsigned cflag;
+       int     i;
+       int     brg;
+
+       if (!info->tty || !info->tty->termios)
+               return;
+       cflag = info->tty->termios->c_cflag;
+       if (!(port = info->port))
+               return;
+       i = cflag & CBAUD;
+       if (i & CBAUDEX) {
+               /* XXX CBAUDEX is not obeyed.
+                * It is impossible at a 32bits SPARC.
+                * But we have to report this to user ... someday.
+                */
+               i = B9600;
+       }
+       info->zs_baud = baud_table[i];
+       info->clk_divisor = 16;
+
+       info->curregs[4] = X16CLK;
+       info->curregs[11] = TCBR | RCBR;
+       brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
+       info->curregs[12] = (brg & 255);
+       info->curregs[13] = ((brg >> 8) & 255);
+       info->curregs[14] = BRSRC | BRENABL;
+
+       /* byte size and parity */
+       switch (cflag & CSIZE) {
+       case CS5:
+               info->curregs[3] &= ~(0xc0);
+               info->curregs[3] |= Rx5;
+               info->pendregs[3] = info->curregs[3];
+               info->curregs[5] &= ~(0xe0);
+               info->curregs[5] |= Tx5;
+               info->pendregs[5] = info->curregs[5];
+               break;
+       case CS6:
+               info->curregs[3] &= ~(0xc0);
+               info->curregs[3] |= Rx6;
+               info->pendregs[3] = info->curregs[3];
+               info->curregs[5] &= ~(0xe0);
+               info->curregs[5] |= Tx6;
+               info->pendregs[5] = info->curregs[5];
+               break;
+       case CS7:
+               info->curregs[3] &= ~(0xc0);
+               info->curregs[3] |= Rx7;
+               info->pendregs[3] = info->curregs[3];
+               info->curregs[5] &= ~(0xe0);
+               info->curregs[5] |= Tx7;
+               info->pendregs[5] = info->curregs[5];
+               break;
+       case CS8:
+       default: /* defaults to 8 bits */
+               info->curregs[3] &= ~(0xc0);
+               info->curregs[3] |= Rx8;
+               info->pendregs[3] = info->curregs[3];
+               info->curregs[5] &= ~(0xe0);
+               info->curregs[5] |= Tx8;
+               info->pendregs[5] = info->curregs[5];
+               break;
+       }
+       info->curregs[4] &= ~(0x0c);
+       if (cflag & CSTOPB) {
+               info->curregs[4] |= SB2;
+       } else {
+               info->curregs[4] |= SB1;
+       }
+       info->pendregs[4] = info->curregs[4];
+       if (cflag & PARENB) {
+               info->curregs[4] |= PAR_ENA;
+               info->pendregs[4] |= PAR_ENA;
+       } else {
+               info->curregs[4] &= ~PAR_ENA;
+               info->pendregs[4] &= ~PAR_ENA;
+       }
+       if (!(cflag & PARODD)) {
+               info->curregs[4] |= PAR_EVEN;
+               info->pendregs[4] |= PAR_EVEN;
+       } else {
+               info->curregs[4] &= ~PAR_EVEN;
+               info->pendregs[4] &= ~PAR_EVEN;
+       }
+
+       /* Load up the new values */
+       load_zsregs(info->zs_channel, info->curregs);
+
+       return;
+}
+
+/* This is for mouse/keyboard output.
+ * XXX mouse output??? can we send it commands??? XXX
+ */
+void kbd_put_char(unsigned char ch)
+{
+       struct sun_zschannel *chan = zs_kbdchan;
+       int flags, loops = 0;
+
+       if(!chan)
+               return;
+
+       save_flags(flags); cli();
+       while((chan->control & Tx_BUF_EMP)==0 && loops < 10000) {
+               loops++;
+               udelay(5);
+       }
+
+       chan->data = ch;
+       udelay(5);
+       restore_flags(flags);
+}
+
+void mouse_put_char(char ch)
+{
+       struct sun_zschannel *chan = zs_mousechan;
+       int flags, loops = 0;
+
+       if(!chan)
+               return;
+
+       save_flags(flags); cli();
+       while((chan->control & Tx_BUF_EMP)==0 && loops < 10000) {
+               loops++;
+               udelay(5);
+       }
+
+       chan->data = ch;
+       udelay(5);
+       restore_flags(flags);
+}
+
+
+/* This is for console output over ttya/ttyb */
+static void rs_put_char(char ch)
+{
+       struct sun_zschannel *chan = zs_conschan;
+       int flags, loops = 0;
+
+       if(!chan)
+               return;
+
+       save_flags(flags); cli();
+       while((chan->control & Tx_BUF_EMP)==0 && loops < 10000) {
+               loops++;
+               udelay(5);
+       }
+
+       chan->data = ch;
+       udelay(5);
+       restore_flags(flags);
+}
+
+/* These are for receiving and sending characters under the kgdb
+ * source level kernel debugger.
+ */
+void putDebugChar(char kgdb_char)
+{
+       struct sun_zschannel *chan = zs_kgdbchan;
+
+       while((chan->control & Tx_BUF_EMP)==0)
+               udelay(5);
+
+       chan->data = kgdb_char;
+}
+
+char getDebugChar(void)
+{
+       struct sun_zschannel *chan = zs_kgdbchan;
+
+       while((chan->control & Rx_CH_AV)==0)
+               barrier();
+       return chan->data;
+}
+
+/*
+ * Fair output driver allows a process to speak.
+ */
+static void rs_fair_output(void)
+{
+       int left;               /* Output no more than that */
+       unsigned long flags;
+       struct sun_serial *info = zs_consinfo;
+       char c;
+
+       if (info == 0) return;
+       if (info->xmit_buf == 0) return;
+
+       save_flags(flags);  cli();
+       left = info->xmit_cnt;
+       while (left != 0) {
+               c = info->xmit_buf[info->xmit_tail];
+               info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
+               info->xmit_cnt--;
+               restore_flags(flags);
+
+               rs_put_char(c);
+
+               save_flags(flags);  cli();
+               left = MIN(info->xmit_cnt, left-1);
+       }
+
+       /* Last character is being transmitted now (hopefuly). */
+       zs_conschan->control = RES_Tx_P;
+       udelay(5);
+
+       restore_flags(flags);
+       return;
+}
+
+/*
+ * zs_console_print is registered for printk.
+ */
+static void zs_console_print(const char *p)
+{
+       char c;
+
+       while((c=*(p++)) != 0) {
+               if(c == '\n')
+                       rs_put_char('\r');
+               rs_put_char(c);
+       }
+
+       /* Comment this if you want to have a strict interrupt-driven output */
+       rs_fair_output();
+
+       return;
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+       struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+               return;
+
+       if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+           !info->xmit_buf)
+               return;
+
+       /* Enable transmitter */
+       save_flags(flags); cli();
+       info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+       info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+       write_zsreg(info->zs_channel, 1, info->curregs[1]);
+       info->curregs[5] |= TxENAB;
+       info->pendregs[5] |= TxENAB;
+       write_zsreg(info->zs_channel, 5, info->curregs[5]);
+
+       /*
+        * Send a first (bootstrapping) character. A best solution is
+        * to call transmit_chars() here which handles output in a
+        * generic way. Current transmit_chars() not only transmits,
+        * but resets interrupts also what we do not desire here.
+        * XXX Discuss with David.
+        */
+       if (info->zs_channel->control & Tx_BUF_EMP) {
+               /* Send char */
+               info->zs_channel->data = info->xmit_buf[info->xmit_tail++];
+               udelay(5);
+               info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+               info->xmit_cnt--;
+       }
+       restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+                   const unsigned char *buf, int count)
+{
+       int     c, total = 0;
+       struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->device, "rs_write"))
+               return 0;
+
+       if (!tty || !info->xmit_buf)
+               return 0;
+
+       save_flags(flags);
+       while (1) {
+               cli();          
+               c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                  SERIAL_XMIT_SIZE - info->xmit_head));
+               if (c <= 0)
+                       break;
+
+               if (from_user) {
+                       down(&tmp_buf_sem);
+                       memcpy_fromfs(tmp_buf, buf, c);
+                       c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                      SERIAL_XMIT_SIZE - info->xmit_head));
+                       memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+                       up(&tmp_buf_sem);
+               } else
+                       memcpy(info->xmit_buf + info->xmit_head, buf, c);
+               info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+               info->xmit_cnt += c;
+               restore_flags(flags);
+               buf += c;
+               count -= c;
+               total += c;
+       }
+       if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
+           !(info->curregs[5] & TxENAB)) {
+               /* Enable transmitter */
+               info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+               info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+               write_zsreg(info->zs_channel, 1, info->curregs[1]);
+               info->curregs[5] |= TxENAB;
+               info->pendregs[5] |= TxENAB;
+               write_zsreg(info->zs_channel, 5, info->curregs[5]);
+       }
+       restore_flags(flags);
+       return total;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+       struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+       int     ret;
+                               
+       if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+               return 0;
+       ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+       if (ret < 0)
+               ret = 0;
+       return ret;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+       struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+                               
+       if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+               return 0;
+       return info->xmit_cnt;
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+       struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+                               
+       if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+               return;
+       cli();
+       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+       sti();
+       wake_up_interruptible(&tty->write_wait);
+       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+           tty->ldisc.write_wakeup)
+               (tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+       struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+       
+       printk("throttle %s: %d....\n", _tty_name(tty, buf),
+              tty->ldisc.chars_in_buffer(tty));
+#endif
+
+       if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+               return;
+       
+       if (I_IXOFF(tty))
+               info->x_char = STOP_CHAR(tty);
+
+       /* Turn off RTS line */
+       cli();
+       info->curregs[5] &= ~RTS;
+       info->pendregs[5] &= ~RTS;
+       write_zsreg(info->zs_channel, 5, info->curregs[5]);
+       sti();
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+       struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+       
+       printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+              tty->ldisc.chars_in_buffer(tty));
+#endif
+
+       if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+               return;
+       
+       if (I_IXOFF(tty)) {
+               if (info->x_char)
+                       info->x_char = 0;
+               else
+                       info->x_char = START_CHAR(tty);
+       }
+
+       /* Assert RTS line */
+       cli();
+       info->curregs[5] |= RTS;
+       info->pendregs[5] |= RTS;
+       write_zsreg(info->zs_channel, 5, info->curregs[5]);
+       sti();
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct sun_serial * info,
+                          struct serial_struct * retinfo)
+{
+       struct serial_struct tmp;
+  
+       if (!retinfo)
+               return -EFAULT;
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.type = info->type;
+       tmp.line = info->line;
+       tmp.port = info->port;
+       tmp.irq = info->irq;
+       tmp.flags = info->flags;
+       tmp.baud_base = info->baud_base;
+       tmp.close_delay = info->close_delay;
+       tmp.closing_wait = info->closing_wait;
+       tmp.custom_divisor = info->custom_divisor;
+       memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
+       return 0;
+}
+
+static int set_serial_info(struct sun_serial * info,
+                          struct serial_struct * new_info)
+{
+       struct serial_struct new_serial;
+       struct sun_serial old_info;
+       int                     retval = 0;
+
+       if (!new_info)
+               return -EFAULT;
+       memcpy_fromfs(&new_serial,new_info,sizeof(new_serial));
+       old_info = *info;
+
+       if (!suser()) {
+               if ((new_serial.baud_base != info->baud_base) ||
+                   (new_serial.type != info->type) ||
+                   (new_serial.close_delay != info->close_delay) ||
+                   ((new_serial.flags & ~ZILOG_USR_MASK) !=
+                    (info->flags & ~ZILOG_USR_MASK)))
+                       return -EPERM;
+               info->flags = ((info->flags & ~ZILOG_USR_MASK) |
+                              (new_serial.flags & ZILOG_USR_MASK));
+               info->custom_divisor = new_serial.custom_divisor;
+               goto check_and_exit;
+       }
+
+       if (info->count > 1)
+               return -EBUSY;
+
+       /*
+        * OK, past this point, all the error checking has been done.
+        * At this point, we start making changes.....
+        */
+
+       info->baud_base = new_serial.baud_base;
+       info->flags = ((info->flags & ~ZILOG_FLAGS) |
+                       (new_serial.flags & ZILOG_FLAGS));
+       info->type = new_serial.type;
+       info->close_delay = new_serial.close_delay;
+       info->closing_wait = new_serial.closing_wait;
+
+check_and_exit:
+       retval = startup(info);
+       return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *         is emptied.  On bus types like RS485, the transmitter must
+ *         release the bus after transmitting. This must be done when
+ *         the transmit shift register is empty, not be done when the
+ *         transmit holding register is empty.  This functionality
+ *         allows RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct sun_serial * info, unsigned int *value)
+{
+       unsigned char status;
+
+       cli();
+       status = info->zs_channel->control;
+       sti();
+       put_user(status,value);
+       return 0;
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break(        struct sun_serial * info, int duration)
+{
+       if (!info->port)
+               return;
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + duration;
+       cli();
+       write_zsreg(info->zs_channel, 5, (info->curregs[5] | SND_BRK));
+       schedule();
+       write_zsreg(info->zs_channel, 5, info->curregs[5]);
+       sti();
+}
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+                   unsigned int cmd, unsigned long arg)
+{
+       int error;
+       struct sun_serial * info = (struct sun_serial *)tty->driver_data;
+       int retval;
+
+       if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+               return -ENODEV;
+
+       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
+           (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+               if (tty->flags & (1 << TTY_IO_ERROR))
+                   return -EIO;
+       }
+       
+       switch (cmd) {
+               case TCSBRK:    /* SVID version: non-zero arg --> no break */
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       if (!arg)
+                               send_break(info, HZ/4); /* 1/4 second */
+                       return 0;
+               case TCSBRKP:   /* support for POSIX tcsendbreak() */
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       send_break(info, arg ? arg*(HZ/10) : HZ/4);
+                       return 0;
+               case TIOCGSOFTCAR:
+                       error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
+                       if (error)
+                               return error;
+                       put_fs_long(C_CLOCAL(tty) ? 1 : 0,
+                                   (unsigned long *) arg);
+                       return 0;
+               case TIOCSSOFTCAR:
+                       arg = get_fs_long((unsigned long *) arg);
+                       tty->termios->c_cflag =
+                               ((tty->termios->c_cflag & ~CLOCAL) |
+                                (arg ? CLOCAL : 0));
+                       return 0;
+               case TIOCGSERIAL:
+                       error = verify_area(VERIFY_WRITE, (void *) arg,
+                                               sizeof(struct serial_struct));
+                       if (error)
+                               return error;
+                       return get_serial_info(info,
+                                              (struct serial_struct *) arg);
+               case TIOCSSERIAL:
+                       return set_serial_info(info,
+                                              (struct serial_struct *) arg);
+               case TIOCSERGETLSR: /* Get line status register */
+                       error = verify_area(VERIFY_WRITE, (void *) arg,
+                               sizeof(unsigned int));
+                       if (error)
+                               return error;
+                       else
+                           return get_lsr_info(info, (unsigned int *) arg);
+
+               case TIOCSERGSTRUCT:
+                       error = verify_area(VERIFY_WRITE, (void *) arg,
+                                               sizeof(struct sun_serial));
+                       if (error)
+                               return error;
+                       memcpy_tofs((struct sun_serial *) arg,
+                                   info, sizeof(struct sun_serial));
+                       return 0;
+                       
+               default:
+                       return -ENOIOCTLCMD;
+               }
+       return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+       struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+
+       if (tty->termios->c_cflag == old_termios->c_cflag)
+               return;
+
+       change_speed(info);
+
+       if ((old_termios->c_cflag & CRTSCTS) &&
+           !(tty->termios->c_cflag & CRTSCTS)) {
+               tty->hw_stopped = 0;
+               rs_start(tty);
+       }
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * ZILOG structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+       struct sun_serial * info = (struct sun_serial *)tty->driver_data;
+       unsigned long flags;
+
+       if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+               return;
+       
+       save_flags(flags); cli();
+       
+       if (tty_hung_up_p(filp)) {
+               restore_flags(flags);
+               return;
+       }
+       
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_close ttys%d, count = %d\n", info->line, info->count);
+#endif
+       if ((tty->count == 1) && (info->count != 1)) {
+               /*
+                * Uh, oh.  tty->count is 1, which means that the tty
+                * structure will be freed.  Info->count should always
+                * be one in these conditions.  If it's greater than
+                * one, we've got real problems, since it means the
+                * serial port won't be shutdown.
+                */
+               printk("rs_close: bad serial port count; tty->count is 1, "
+                      "info->count is %d\n", info->count);
+               info->count = 1;
+       }
+       if (--info->count < 0) {
+               printk("rs_close: bad serial port count for ttys%d: %d\n",
+                      info->line, info->count);
+               info->count = 0;
+       }
+       if (info->count) {
+               restore_flags(flags);
+               return;
+       }
+       info->flags |= ZILOG_CLOSING;
+       /*
+        * Save the termios structure, since this port may have
+        * separate termios for callout and dialin.
+        */
+       if (info->flags & ZILOG_NORMAL_ACTIVE)
+               info->normal_termios = *tty->termios;
+       if (info->flags & ZILOG_CALLOUT_ACTIVE)
+               info->callout_termios = *tty->termios;
+       /*
+        * Now we wait for the transmit buffer to clear; and we notify 
+        * the line discipline to only process XON/XOFF characters.
+        */
+       tty->closing = 1;
+       if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, info->closing_wait);
+       /*
+        * At this point we stop accepting input.  To do this, we
+        * disable the receive line status interrupts, and tell the
+        * interrupt driver to stop checking the data ready bit in the
+        * line status register.
+        */
+       /** if (!info->iscons) ... **/
+       info->curregs[3] &= ~RxENABLE;
+       info->pendregs[3] = info->curregs[3];
+       write_zsreg(info->zs_channel, 3, info->curregs[3]);
+       info->curregs[1] &= ~(0x18);
+       info->pendregs[1] = info->curregs[1];
+       write_zsreg(info->zs_channel, 1, info->curregs[1]);
+       ZS_CLEARFIFO(info->zs_channel);
+
+       shutdown(info);
+       if (tty->driver.flush_buffer)
+               tty->driver.flush_buffer(tty);
+       if (tty->ldisc.flush_buffer)
+               tty->ldisc.flush_buffer(tty);
+       tty->closing = 0;
+       info->event = 0;
+       info->tty = 0;
+       if (tty->ldisc.num != ldiscs[N_TTY].num) {
+               if (tty->ldisc.close)
+                       (tty->ldisc.close)(tty);
+               tty->ldisc = ldiscs[N_TTY];
+               tty->termios->c_line = N_TTY;
+               if (tty->ldisc.open)
+                       (tty->ldisc.open)(tty);
+       }
+       if (info->blocked_open) {
+               if (info->close_delay) {
+                       current->state = TASK_INTERRUPTIBLE;
+                       current->timeout = jiffies + info->close_delay;
+                       schedule();
+               }
+               wake_up_interruptible(&info->open_wait);
+       }
+       info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
+                        ZILOG_CLOSING);
+       wake_up_interruptible(&info->close_wait);
+       restore_flags(flags);
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void rs_hangup(struct tty_struct *tty)
+{
+       struct sun_serial * info = (struct sun_serial *)tty->driver_data;
+       
+       if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+               return;
+       
+       rs_flush_buffer(tty);
+       shutdown(info);
+       info->event = 0;
+       info->count = 0;
+       info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE);
+       info->tty = 0;
+       wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+                          struct sun_serial *info)
+{
+       struct wait_queue wait = { current, NULL };
+       int             retval;
+       int             do_clocal = 0;
+
+       /*
+        * If the device is in the middle of being closed, then block
+        * until it's done, and then try again.
+        */
+       if (info->flags & ZILOG_CLOSING) {
+               interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+               if (info->flags & ZILOG_HUP_NOTIFY)
+                       return -EAGAIN;
+               else
+                       return -ERESTARTSYS;
+#else
+               return -EAGAIN;
+#endif
+       }
+
+       /*
+        * If this is a callout device, then just make sure the normal
+        * device isn't being used.
+        */
+       if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+               if (info->flags & ZILOG_NORMAL_ACTIVE)
+                       return -EBUSY;
+               if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+                   (info->flags & ZILOG_SESSION_LOCKOUT) &&
+                   (info->session != current->session))
+                   return -EBUSY;
+               if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+                   (info->flags & ZILOG_PGRP_LOCKOUT) &&
+                   (info->pgrp != current->pgrp))
+                   return -EBUSY;
+               info->flags |= ZILOG_CALLOUT_ACTIVE;
+               return 0;
+       }
+       
+       /*
+        * If non-blocking mode is set, or the port is not enabled,
+        * then make the check up front and then exit.
+        */
+       if ((filp->f_flags & O_NONBLOCK) ||
+           (tty->flags & (1 << TTY_IO_ERROR))) {
+               if (info->flags & ZILOG_CALLOUT_ACTIVE)
+                       return -EBUSY;
+               info->flags |= ZILOG_NORMAL_ACTIVE;
+               return 0;
+       }
+
+       if (info->flags & ZILOG_CALLOUT_ACTIVE) {
+               if (info->normal_termios.c_cflag & CLOCAL)
+                       do_clocal = 1;
+       } else {
+               if (tty->termios->c_cflag & CLOCAL)
+                       do_clocal = 1;
+       }
+       
+       /*
+        * Block waiting for the carrier detect and the line to become
+        * free (i.e., not in use by the callout).  While we are in
+        * this loop, info->count is dropped by one, so that
+        * rs_close() knows when to free things.  We restore it upon
+        * exit, either normal or abnormal.
+        */
+       retval = 0;
+       add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready before block: ttys%d, count = %d\n",
+              info->line, info->count);
+#endif
+       info->count--;
+       info->blocked_open++;
+       while (1) {
+               cli();
+               if (!(info->flags & ZILOG_CALLOUT_ACTIVE))
+                       zs_rtsdtr(info, 1);
+               sti();
+               current->state = TASK_INTERRUPTIBLE;
+               if (tty_hung_up_p(filp) ||
+                   !(info->flags & ZILOG_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+                       if (info->flags & ZILOG_HUP_NOTIFY)
+                               retval = -EAGAIN;
+                       else
+                               retval = -ERESTARTSYS;  
+#else
+                       retval = -EAGAIN;
+#endif
+                       break;
+               }
+               if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
+                   !(info->flags & ZILOG_CLOSING) && do_clocal)
+                       break;
+               if (current->signal & ~current->blocked) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+#ifdef SERIAL_DEBUG_OPEN
+               printk("block_til_ready blocking: ttys%d, count = %d\n",
+                      info->line, info->count);
+#endif
+               schedule();
+       }
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&info->open_wait, &wait);
+       if (!tty_hung_up_p(filp))
+               info->count++;
+       info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready after blocking: ttys%d, count = %d\n",
+              info->line, info->count);
+#endif
+       if (retval)
+               return retval;
+       info->flags |= ZILOG_NORMAL_ACTIVE;
+       return 0;
+}      
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its ZILOG structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+int rs_open(struct tty_struct *tty, struct file * filp)
+{
+       struct sun_serial       *info;
+       int                     retval, line;
+
+       line = MINOR(tty->device) - tty->driver.minor_start;
+       /* The zilog lines for the mouse/keyboard must be
+        * opened using their respective drivers.
+        */
+       if ((line < 0) || (line >= NUM_CHANNELS))
+               return -ENODEV;
+       if((line == KEYBOARD_LINE) || (line == MOUSE_LINE))
+               return -ENODEV;
+       info = zs_soft + line;
+       /* Is the kgdb running over this line? */
+       if (info->kgdb_channel)
+               return -ENODEV;
+       if (serial_paranoia_check(info, tty->device, "rs_open"))
+               return -ENODEV;
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+              info->count);
+#endif
+       info->count++;
+       tty->driver_data = info;
+       info->tty = tty;
+
+       /*
+        * Start up serial port
+        */
+       retval = startup(info);
+       if (retval)
+               return retval;
+
+       retval = block_til_ready(tty, filp, info);
+       if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+               printk("rs_open returning after block_til_ready with %d\n",
+                      retval);
+#endif
+               return retval;
+       }
+
+       if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) {
+               if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+                       *tty->termios = info->normal_termios;
+               else 
+                       *tty->termios = info->callout_termios;
+               change_speed(info);
+       }
+
+       info->session = current->session;
+       info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_open ttys%d successful...", info->line);
+#endif
+       return 0;
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+static void show_serial_version(void)
+{
+       printk("Sparc Zilog8530 serial driver version 1.00\n");
+}
+
+/* Probe the PROM for the request zs chip number. */
+static inline struct sun_zslayout *get_zs(int chip)
+{
+       struct linux_prom_irqs tmp_irq;
+       unsigned long paddr = 0;
+       unsigned long vaddr = 0;
+       int zsnode, tmpnode, iospace, slave;
+       static int irq = 0;
+
+#if CONFIG_AP1000
+        printk("No zs chip\n");
+        return NULL;
+#endif
+
+       iospace = 0;
+       if(chip < 0 || chip >= NUM_SERIAL)
+               panic("get_zs bogon zs chip number");
+
+       if(sparc_cpu_model == sun4) {
+               /* Grrr, these have to be hardcoded aieee */
+               switch(chip) {
+               case 0:
+                       paddr = 0xf1000000;
+                       break;
+               case 1:
+                       paddr = 0xf0000000;
+                       break;
+               };
+               iospace = 0;
+               zs_nodes[chip] = 0;
+               if(!irq)
+                       zilog_irq = irq = 12;
+               vaddr = (unsigned long)
+                       sparc_alloc_io((char *) paddr, 0, 8,
+                                      "Zilog Serial", iospace, 0);
+       } else {
+               /* Can use the prom for other machine types */
+               zsnode = prom_getchild(prom_root_node);
+               tmpnode = prom_searchsiblings(zsnode, "obio");
+               if(tmpnode)
+                       zsnode = prom_getchild(tmpnode);
+               if(!zsnode)
+                       panic("get_zs no zs serial prom node");
+               while(zsnode) {
+                       zsnode = prom_searchsiblings(zsnode, "zs");
+                       slave = prom_getintdefault(zsnode, "slave", -1);
+                       if(slave==chip) {
+                               /* The one we want */
+                               vaddr = (unsigned long)
+                                       prom_getintdefault(zsnode, "address",
+                                                              0xdeadbeef);
+                               if(vaddr == 0xdeadbeef)
+                                       prom_halt();
+                               zs_nodes[chip] = zsnode;
+                               prom_getproperty(zsnode, "intr",
+                                                (char *) &tmp_irq,
+                                                sizeof(tmp_irq));
+#ifdef OLD_STYLE_IRQ
+                               tmp_irq.pri &= 0xf;
+#endif
+                               if(!irq) {
+                                       irq = zilog_irq = tmp_irq.pri;
+                               } else {
+                                       if(tmp_irq.pri != irq)
+                                               panic("zilog: bogon irqs");
+                               }
+                               break;
+                       }
+                       zsnode = prom_getsibling(zsnode);
+               }
+               if(!zsnode)
+                       panic("get_zs whee chip not found");
+       }
+       if(!vaddr)
+               panic("get_zs whee no serial chip mappable");
+
+       return (struct sun_zslayout *) vaddr;
+
+}
+
+
+extern void register_console(void (*proc)(const char *));
+
+static inline void
+rs_cons_check(struct sun_serial *ss, int channel)
+{
+       int i, o, io;
+       static consout_registered = 0;
+       static msg_printed = 0;
+
+       i = o = io = 0;
+
+       /* Is this one of the serial console lines? */
+       if((zs_cons_chanout != channel) &&
+          (zs_cons_chanin != channel))
+               return;
+       zs_conschan = ss->zs_channel;
+       zs_consinfo = ss;
+
+       /* Register the console output putchar, if necessary */
+       if((zs_cons_chanout == channel)) {
+               o = 1;
+               /* double whee.. */
+               if(!consout_registered) {
+                       register_console(zs_console_print);
+                       consout_registered = 1;
+               }
+       }
+
+       /* If this is console input, we handle the break received
+        * status interrupt on this line to mean prom_halt().
+        */
+       if(zs_cons_chanin == channel) {
+               ss->break_abort = 1;
+               i = 1;
+       }
+       if(o && i)
+               io = 1;
+       if(ss->zs_baud != 9600)
+               panic("Console baud rate weirdness");
+
+       /* Set flag variable for this port so that it cannot be
+        * opened for other uses by accident.
+        */
+       ss->is_cons = 1;
+
+       if(io) {
+               if(!msg_printed) {
+                       printk("zs%d: console I/O\n", ((channel>>1)&1));
+                       msg_printed = 1;
+               }
+       } else {
+               printk("zs%d: console %s\n", ((channel>>1)&1),
+                      (i==1 ? "input" : (o==1 ? "output" : "WEIRD")));
+       }
+}
+
+volatile int test_done;
+extern void keyboard_zsinit(void);
+extern void sun_mouse_zsinit(void);
+
+/* rs_init inits the driver */
+int rs_init(void)
+{
+       int chip, channel, i, flags;
+       struct sun_serial *info;
+
+#if CONFIG_AP1000
+        printk("not doing rs_init()\n");
+        return 0;
+#endif
+
+       /* Setup base handler, and timer table. */
+       init_bh(SERIAL_BH, do_serial_bh);
+       timer_table[RS_TIMER].fn = rs_timer;
+       timer_table[RS_TIMER].expires = 0;
+
+       show_serial_version();
+
+       /* Initialize the tty_driver structure */
+       /* SPARC: Not all of this is exactly right for us. */
+       
+       memset(&serial_driver, 0, sizeof(struct tty_driver));
+       serial_driver.magic = TTY_DRIVER_MAGIC;
+       serial_driver.name = "ttyS";
+       serial_driver.major = TTY_MAJOR;
+       serial_driver.minor_start = 64;
+       serial_driver.num = NUM_CHANNELS;
+       serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+       serial_driver.subtype = SERIAL_TYPE_NORMAL;
+       serial_driver.init_termios = tty_std_termios;
+
+       serial_driver.init_termios.c_cflag =
+               B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       serial_driver.flags = TTY_DRIVER_REAL_RAW;
+       serial_driver.refcount = &serial_refcount;
+       serial_driver.table = serial_table;
+       serial_driver.termios = serial_termios;
+       serial_driver.termios_locked = serial_termios_locked;
+
+       serial_driver.open = rs_open;
+       serial_driver.close = rs_close;
+       serial_driver.write = rs_write;
+       serial_driver.flush_chars = rs_flush_chars;
+       serial_driver.write_room = rs_write_room;
+       serial_driver.chars_in_buffer = rs_chars_in_buffer;
+       serial_driver.flush_buffer = rs_flush_buffer;
+       serial_driver.ioctl = rs_ioctl;
+       serial_driver.throttle = rs_throttle;
+       serial_driver.unthrottle = rs_unthrottle;
+       serial_driver.set_termios = rs_set_termios;
+       serial_driver.stop = rs_stop;
+       serial_driver.start = rs_start;
+       serial_driver.hangup = rs_hangup;
+
+       /*
+        * The callout device is just like normal device except for
+        * major number and the subtype code.
+        */
+       callout_driver = serial_driver;
+       callout_driver.name = "cua";
+       callout_driver.major = TTYAUX_MAJOR;
+       callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+       if (tty_register_driver(&serial_driver))
+               panic("Couldn't register serial driver\n");
+       if (tty_register_driver(&callout_driver))
+               panic("Couldn't register callout driver\n");
+       
+       save_flags(flags); cli();
+
+       /* Set up our interrupt linked list */
+       zs_chain = &zs_soft[0];
+       zs_soft[0].zs_next = &zs_soft[1];
+       zs_soft[1].zs_next = &zs_soft[2];
+       zs_soft[2].zs_next = &zs_soft[3];
+       zs_soft[3].zs_next = 0;
+
+       for(chip = 0; chip < NUM_SERIAL; chip++) {
+               /* If we are doing kgdb over one of the channels on
+                * chip zero, kgdb_channel will be set to 1 by the
+                * rs_kgdb_hook() routine below.
+                */
+               if(!zs_chips[chip]) {
+                       zs_chips[chip] = get_zs(chip);
+                       /* Two channels per chip */
+                       zs_channels[(chip*2)] = &zs_chips[chip]->channelA;
+                       zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB;
+                       zs_soft[(chip*2)].kgdb_channel = 0;
+                       zs_soft[(chip*2)+1].kgdb_channel = 0;
+               }
+               /* First, set up channel A on this chip. */
+               channel = chip * 2;
+               zs_soft[channel].zs_channel = zs_channels[channel];
+               zs_soft[channel].change_needed = 0;
+               zs_soft[channel].clk_divisor = 16;
+               zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+               zs_soft[channel].cons_mouse = 0;
+               /* If not keyboard/mouse and is console serial
+                * line, then enable receiver interrupts.
+                */
+               if((channel<KEYBOARD_LINE) && (zs_soft[channel].is_cons)) {
+                       write_zsreg(zs_soft[channel].zs_channel, R1,
+                                   (EXT_INT_ENAB | INT_ALL_Rx));
+                       write_zsreg(zs_soft[channel].zs_channel, R9, (NV | MIE));
+                       write_zsreg(zs_soft[channel].zs_channel, R10, (NRZ));
+                       write_zsreg(zs_soft[channel].zs_channel, R3, (Rx8|RxENABLE));
+                       write_zsreg(zs_soft[channel].zs_channel, R5, (Tx8 | TxENAB));
+               }
+               /* If this is the kgdb line, enable interrupts because we
+                * now want to receive the 'control-c' character from the
+                * client attached to us asynchronously.
+                */
+               if(zs_soft[channel].kgdb_channel)
+                       kgdb_chaninit(&zs_soft[channel], 1, zs_soft[channel].zs_baud);
+
+               if(channel == KEYBOARD_LINE) {
+                       /* Tell keyboard driver about our presence. */
+                       if(zs_soft[channel].zs_baud != 1200)
+                               panic("Weird keyboard serial baud rate");
+                       zs_soft[channel].cons_keyb = 1;
+                       zs_kbdchan = zs_soft[channel].zs_channel;
+                       /* Enable Rx/Tx, IRQs, and inform kbd driver */
+                       write_zsreg(zs_soft[channel].zs_channel, R1,
+                                   (EXT_INT_ENAB | INT_ALL_Rx));
+                       write_zsreg(zs_soft[channel].zs_channel, R4,
+                                   (PAR_EVEN | X16CLK | SB1));
+                       write_zsreg(zs_soft[channel].zs_channel, R9, (NV|MIE));
+                       write_zsreg(zs_soft[channel].zs_channel, R10, (NRZ));
+                       write_zsreg(zs_soft[channel].zs_channel, R11,
+                                   (TCBR | RCBR));
+                       write_zsreg(zs_soft[channel].zs_channel, R14,
+                                   (BRSRC | BRENABL));
+                       write_zsreg(zs_soft[channel].zs_channel, R3, (Rx8|RxENABLE));
+                       write_zsreg(zs_soft[channel].zs_channel, R5,
+                                   (Tx8 | TxENAB | DTR | RTS));
+#if 0
+                       write_zsreg(zs_soft[channel].zs_channel, R15,
+                                   (DCDIE | CTSIE | TxUIE | BRKIE));
+#endif
+                       ZS_CLEARERR(zs_soft[channel].zs_channel);
+                       ZS_CLEARFIFO(zs_soft[channel].zs_channel);
+               }
+
+               /* Now, channel B */
+               channel++;
+               zs_soft[channel].zs_channel = zs_channels[channel];
+               zs_soft[channel].change_needed = 0;
+               zs_soft[channel].clk_divisor = 16;
+               zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+               zs_soft[channel].cons_keyb = 0;
+               /* If not keyboard/mouse and is console serial
+                * line, then enable receiver interrupts.
+                */
+               if(channel<KEYBOARD_LINE && zs_soft[channel].is_cons) {
+                       write_zsreg(zs_soft[channel].zs_channel, R1,
+                                   (EXT_INT_ENAB | INT_ALL_Rx));
+                       write_zsreg(zs_soft[channel].zs_channel, R9,
+                                   (NV | MIE));
+                       write_zsreg(zs_soft[channel].zs_channel, R10,
+                                   (NRZ));
+                       write_zsreg(zs_soft[channel].zs_channel, R3,
+                                   (Rx8|RxENABLE));
+                       write_zsreg(zs_soft[channel].zs_channel, R5,
+                                   (Tx8 | TxENAB | RTS | DTR));
+               }
+               if(channel == MOUSE_LINE) {
+                       /* Tell mouse driver about our presence. */
+                       if(zs_soft[channel].zs_baud != 1200)
+                               panic("Weird mouse serial baud rate");
+                       zs_soft[channel].cons_mouse = 1;
+                       zs_mousechan = zs_soft[channel].zs_channel;
+                       /* Enable Rx, IRQs, and inform mouse driver */
+                       write_zsreg(zs_soft[channel].zs_channel, R1, (INT_ALL_Rx));
+                       write_zsreg(zs_soft[channel].zs_channel, R9, (NV|MIE));
+                       write_zsreg(zs_soft[channel].zs_channel, R3, (Rx8|RxENABLE));
+#if 0 /* XXX hangs sun4c's sometimes */
+                       write_zsreg(zs_soft[channel].zs_channel, R15,
+                                   (DCDIE | CTSIE | TxUIE | BRKIE));
+#endif
+                       sun_mouse_zsinit();
+               } else {
+                       zs_soft[channel].cons_mouse = 0;
+               }
+       }
+
+       for(info=zs_chain, i=0; info; info = info->zs_next, i++)
+       {
+               info->magic = SERIAL_MAGIC;
+               info->port = (int) info->zs_channel;
+               info->line = i;
+               info->tty = 0;
+               info->irq = zilog_irq;
+               info->custom_divisor = 16;
+               info->close_delay = 50;
+               info->closing_wait = 3000;
+               info->x_char = 0;
+               info->event = 0;
+               info->count = 0;
+               info->blocked_open = 0;
+               info->tqueue.routine = do_softint;
+               info->tqueue.data = info;
+               info->tqueue_hangup.routine = do_serial_hangup;
+               info->tqueue_hangup.data = info;
+               info->callout_termios =callout_driver.init_termios;
+               info->normal_termios = serial_driver.init_termios;
+               info->open_wait = 0;
+               info->close_wait = 0;
+               printk("tty%02d at 0x%04x (irq = %d)", info->line, 
+                      info->port, info->irq);
+               printk(" is a Zilog8530\n");
+       }
+
+       if (request_irq(zilog_irq,
+                       rs_interrupt,
+                       (SA_INTERRUPT | SA_STATIC_ALLOC),
+                       "Zilog8530", NULL))
+               panic("Unable to attach zs intr\n");
+       restore_flags(flags);
+
+       keyboard_zsinit();
+
+       return 0;
+}
+
+/*
+ * register_serial and unregister_serial allows for serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+/* SPARC: Unused at this time, just here to make things link. */
+int register_serial(struct serial_struct *req)
+{
+       return -1;
+}
+
+void unregister_serial(int line)
+{
+       return;
+}
+
+/* Hooks for running a serial console.  con_init() calls this if the
+ * console is being run over one of the ttya/ttyb serial ports.
+ * 'chip' should be zero, as chip 1 drives the mouse/keyboard.
+ * 'channel' is decoded as 0=TTYA 1=TTYB, note that the channels
+ * are addressed backwards, channel B is first, then channel A.
+ */
+void
+rs_cons_hook(int chip, int out, int channel)
+{
+       if(chip)
+               panic("rs_cons_hook called with chip not zero");
+       if(!zs_chips[chip]) {
+               zs_chips[chip] = get_zs(chip);
+               /* Two channels per chip */
+               zs_channels[(chip*2)] = &zs_chips[chip]->channelA;
+               zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB;
+       }
+       zs_soft[channel].zs_channel = zs_channels[channel];
+       zs_soft[channel].change_needed = 0;
+       zs_soft[channel].clk_divisor = 16;
+       zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+       rs_cons_check(&zs_soft[channel], channel);
+       if(out)
+               zs_cons_chanout = ((chip * 2) + channel);
+       else
+               zs_cons_chanin = ((chip * 2) + channel);
+
+}
+
+/* This is called at boot time to prime the kgdb serial debugging
+ * serial line.  The 'tty_num' argument is 0 for /dev/ttya and 1
+ * for /dev/ttyb which is determined in setup_arch() from the
+ * boot command line flags.
+ */
+void
+rs_kgdb_hook(int tty_num)
+{
+       int chip = 0;
+
+       if(!zs_chips[chip]) {
+               zs_chips[chip] = get_zs(chip);
+               /* Two channels per chip */
+               zs_channels[(chip*2)] = &zs_chips[chip]->channelA;
+               zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB;
+       }
+       zs_soft[tty_num].zs_channel = zs_channels[tty_num];
+       zs_kgdbchan = zs_soft[tty_num].zs_channel;
+       zs_soft[tty_num].change_needed = 0;
+       zs_soft[tty_num].clk_divisor = 16;
+       zs_soft[tty_num].zs_baud = get_zsbaud(&zs_soft[tty_num]);
+       zs_soft[tty_num].kgdb_channel = 1;     /* This runs kgdb */
+       zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
+       /* Turn on transmitter/receiver at 8-bits/char */
+       kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
+       ZS_CLEARERR(zs_kgdbchan);
+       udelay(5);
+       ZS_CLEARFIFO(zs_kgdbchan);
+}
diff --git a/drivers/sbus/char/sunserial.h b/drivers/sbus/char/sunserial.h
new file mode 100644 (file)
index 0000000..8fb0296
--- /dev/null
@@ -0,0 +1,420 @@
+/* serial.h: Definitions for the Sparc Zilog serial driver.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_SERIAL_H
+#define _SPARC_SERIAL_H
+
+/* Just one channel */
+struct sun_zschannel {
+       volatile unsigned char control;
+       volatile unsigned char pad1;
+       volatile unsigned char data;
+       volatile unsigned char pad2;
+};
+
+/* The address space layout for each zs chip.  Yes they are
+ * backwards.
+ */
+struct sun_zslayout {
+       struct sun_zschannel channelB;
+       struct sun_zschannel channelA;
+};
+
+/* We need to keep track of the keyboard state, *ahead* of what
+ * the keyboard driver sees, which will be later on after the
+ * interrupt via tqueue wait queues and/or base-handler processing.
+ */
+struct l1a_kbd_state {
+       unsigned char kbd_id;
+       unsigned char l1_down;
+};
+
+#define NUM_ZSREGS    16
+
+struct serial_struct {
+       int     type;
+       int     line;
+       int     port;
+       int     irq;
+       int     flags;
+       int     xmit_fifo_size;
+       int     custom_divisor;
+       int     baud_base;
+       unsigned short  close_delay;
+       char    reserved_char[2];
+       int     hub6;
+       unsigned short  closing_wait; /* time to wait before closing */
+       unsigned short  closing_wait2; /* no longer used... */
+       int     reserved[4];
+};
+
+/*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output.  65535 means don't wait at all.
+ */
+#define ZILOG_CLOSING_WAIT_INF 0
+#define ZILOG_CLOSING_WAIT_NONE        65535
+
+/*
+ * Definitions for ZILOG_struct (and serial_struct) flags field
+ */
+#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
+                                  on the callout port */
+#define ZILOG_FOURPORT  0x0002 /* Set OU1, OUT2 per AST Fourport settings */
+#define ZILOG_SAK      0x0004  /* Secure Attention Key (Orange book) */
+#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define ZILOG_SPD_MASK 0x0030
+#define ZILOG_SPD_HI   0x0010  /* Use 56000 instead of 38400 bps */
+
+#define ZILOG_SPD_VHI  0x0020  /* Use 115200 instead of 38400 bps */
+#define ZILOG_SPD_CUST 0x0030  /* Use user-specified divisor */
+
+#define ZILOG_SKIP_TEST        0x0040 /* Skip UART test during autoconfiguration */
+#define ZILOG_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
+#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define ZILOG_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
+#define ZILOG_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
+
+#define ZILOG_FLAGS    0x0FFF  /* Possible legal ZILOG flags */
+#define ZILOG_USR_MASK 0x0430  /* Legal flags that non-privileged
+                                * users can set or reset */
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define ZILOG_INITIALIZED      0x80000000 /* Serial port was initialized */
+#define ZILOG_CALLOUT_ACTIVE   0x40000000 /* Call out device is active */
+#define ZILOG_NORMAL_ACTIVE    0x20000000 /* Normal device is active */
+#define ZILOG_BOOT_AUTOCONF    0x10000000 /* Autoconfigure port on bootup */
+#define ZILOG_CLOSING          0x08000000 /* Serial port is closing */
+#define ZILOG_CTS_FLOW         0x04000000 /* Do CTS flow control */
+#define ZILOG_CHECK_CD         0x02000000 /* i.e., CLOCAL */
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ * 
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+struct sun_serial {
+       struct sun_serial *zs_next;       /* For IRQ servicing chain */
+       struct sun_zschannel *zs_channel; /* Channel registers */
+       unsigned char read_reg_zero;
+
+       char soft_carrier;  /* Use soft carrier on this channel */
+       char cons_keyb;     /* Channel runs the keyboard */
+       char cons_mouse;    /* Channel runs the mouse */
+       char break_abort;   /* Is serial console in, so process brk/abrt */
+       char kgdb_channel;  /* Kgdb is running on this channel */
+       char is_cons;       /* Is this our console. */
+
+       /* We need to know the current clock divisor
+        * to read the bps rate the chip has currently
+        * loaded.
+        */
+       unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
+       int zs_baud;
+
+       /* Current write register values */
+       unsigned char curregs[NUM_ZSREGS];
+
+       /* Values we need to set next opportunity */
+       unsigned char pendregs[NUM_ZSREGS];
+
+       char change_needed;
+
+       int                     magic;
+       int                     baud_base;
+       int                     port;
+       int                     irq;
+       int                     flags;          /* defined in tty.h */
+       int                     type;           /* UART type */
+       struct tty_struct       *tty;
+       int                     read_status_mask;
+       int                     ignore_status_mask;
+       int                     timeout;
+       int                     xmit_fifo_size;
+       int                     custom_divisor;
+       int                     x_char; /* xon/xoff character */
+       int                     close_delay;
+       unsigned short          closing_wait;
+       unsigned short          closing_wait2;
+       unsigned long           event;
+       unsigned long           last_active;
+       int                     line;
+       int                     count;      /* # of fd on device */
+       int                     blocked_open; /* # of blocked opens */
+       long                    session; /* Session of opening process */
+       long                    pgrp; /* pgrp of opening process */
+       unsigned char           *xmit_buf;
+       int                     xmit_head;
+       int                     xmit_tail;
+       int                     xmit_cnt;
+       struct tq_struct        tqueue;
+       struct tq_struct        tqueue_hangup;
+       struct termios          normal_termios;
+       struct termios          callout_termios;
+       struct wait_queue       *open_wait;
+       struct wait_queue       *close_wait;
+};
+
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP  0
+
+#endif /* __KERNEL__ */
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define        FLAG    0x7e
+
+/* Write Register 0 */
+#define        R0      0               /* Register selects */
+#define        R1      1
+#define        R2      2
+#define        R3      3
+#define        R4      4
+#define        R5      5
+#define        R6      6
+#define        R7      7
+#define        R8      8
+#define        R9      9
+#define        R10     10
+#define        R11     11
+#define        R12     12
+#define        R13     13
+#define        R14     14
+#define        R15     15
+
+#define        NULLCODE        0       /* Null Code */
+#define        POINT_HIGH      0x8     /* Select upper half of registers */
+#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
+#define        SEND_ABORT      0x18    /* HDLC Abort */
+#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
+#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
+#define        ERR_RES         0x30    /* Error Reset */
+#define        RES_H_IUS       0x38    /* Reset highest IUS */
+
+#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
+#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
+#define        RES_EOM_L       0xC0    /* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
+#define        TxINT_ENAB      0x2     /* Tx Int Enable */
+#define        PAR_SPEC        0x4     /* Parity is special condition */
+
+#define        RxINT_DISAB     0       /* Rx Int Disable */
+#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
+#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
+#define        INT_ERR_Rx      0x18    /* Int on error only */
+
+#define        WT_RDY_RT       0x20    /* Wait/Ready on R/T */
+#define        WT_FN_RDYFN     0x40    /* Wait/FN/Ready FN */
+#define        WT_RDY_ENAB     0x80    /* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define        RxENABLE        0x1     /* Rx Enable */
+#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
+#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
+#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
+#define        ENT_HM          0x10    /* Enter Hunt Mode */
+#define        AUTO_ENAB       0x20    /* Auto Enables */
+#define        Rx5             0x0     /* Rx 5 Bits/Character */
+#define        Rx7             0x40    /* Rx 7 Bits/Character */
+#define        Rx6             0x80    /* Rx 6 Bits/Character */
+#define        Rx8             0xc0    /* Rx 8 Bits/Character */
+
+/* Write Register 4 */
+
+#define        PAR_ENA         0x1     /* Parity Enable */
+#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
+
+#define        SYNC_ENAB       0       /* Sync Modes Enable */
+#define        SB1             0x4     /* 1 stop bit/char */
+#define        SB15            0x8     /* 1.5 stop bits/char */
+#define        SB2             0xc     /* 2 stop bits/char */
+
+#define        MONSYNC         0       /* 8 Bit Sync character */
+#define        BISYNC          0x10    /* 16 bit sync character */
+#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
+#define        EXTSYNC         0x30    /* External Sync Mode */
+
+#define        X1CLK           0x0     /* x1 clock mode */
+#define        X16CLK          0x40    /* x16 clock mode */
+#define        X32CLK          0x80    /* x32 clock mode */
+#define        X64CLK          0xC0    /* x64 clock mode */
+
+/* Write Register 5 */
+
+#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
+#define        RTS             0x2     /* RTS */
+#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
+#define        TxENAB          0x8     /* Tx Enable */
+#define        SND_BRK         0x10    /* Send Break */
+#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
+#define        Tx7             0x20    /* Tx 7 bits/character */
+#define        Tx6             0x40    /* Tx 6 bits/character */
+#define        Tx8             0x60    /* Tx 8 bits/character */
+#define        DTR             0x80    /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define        VIS     1       /* Vector Includes Status */
+#define        NV      2       /* No Vector */
+#define        DLC     4       /* Disable Lower Chain */
+#define        MIE     8       /* Master Interrupt Enable */
+#define        STATHI  0x10    /* Status high */
+#define        NORESET 0       /* No reset on write to R9 */
+#define        CHRB    0x40    /* Reset channel B */
+#define        CHRA    0x80    /* Reset channel A */
+#define        FHWRES  0xc0    /* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define        BIT6    1       /* 6 bit/8bit sync */
+#define        LOOPMODE 2      /* SDLC Loop mode */
+#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
+#define        MARKIDLE 8      /* Mark/flag on idle */
+#define        GAOP    0x10    /* Go active on poll */
+#define        NRZ     0       /* NRZ mode */
+#define        NRZI    0x20    /* NRZI mode */
+#define        FM1     0x40    /* FM1 (transition = 1) */
+#define        FM0     0x60    /* FM0 (transition = 0) */
+#define        CRCPS   0x80    /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define        TRxCXT  0       /* TRxC = Xtal output */
+#define        TRxCTC  1       /* TRxC = Transmit clock */
+#define        TRxCBR  2       /* TRxC = BR Generator Output */
+#define        TRxCDP  3       /* TRxC = DPLL output */
+#define        TRxCOI  4       /* TRxC O/I */
+#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
+#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
+#define        TCBR    0x10    /* Transmit clock = BR Generator output */
+#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
+#define        RCRTxCP 0       /* Receive clock = RTxC pin */
+#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
+#define        RCBR    0x40    /* Receive clock = BR Generator output */
+#define        RCDPLL  0x60    /* Receive clock = DPLL output */
+#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define        BRENABL 1       /* Baud rate generator enable */
+#define        BRSRC   2       /* Baud rate generator source */
+#define        DTRREQ  4       /* DTR/Request function */
+#define        AUTOECHO 8      /* Auto Echo */
+#define        LOOPBAK 0x10    /* Local loopback */
+#define        SEARCH  0x20    /* Enter search mode */
+#define        RMC     0x40    /* Reset missing clock */
+#define        DISDPLL 0x60    /* Disable DPLL */
+#define        SSBR    0x80    /* Set DPLL source = BR generator */
+#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
+#define        SFMM    0xc0    /* Set FM mode */
+#define        SNRZI   0xe0    /* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define        ZCIE    2       /* Zero count IE */
+#define        DCDIE   8       /* DCD IE */
+#define        SYNCIE  0x10    /* Sync/hunt IE */
+#define        CTSIE   0x20    /* CTS IE */
+#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
+#define        BRKIE   0x80    /* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define        Rx_CH_AV        0x1     /* Rx Character Available */
+#define        ZCOUNT          0x2     /* Zero count */
+#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
+#define        DCD             0x8     /* DCD */
+#define        SYNC_HUNT       0x10    /* Sync/hunt */
+#define        CTS             0x20    /* CTS */
+#define        TxEOM           0x40    /* Tx underrun */
+#define        BRK_ABRT        0x80    /* Break/Abort */
+
+/* Read Register 1 */
+#define        ALL_SNT         0x1     /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define        RES3            0x8     /* 0/3 */
+#define        RES4            0x4     /* 0/4 */
+#define        RES5            0xc     /* 0/5 */
+#define        RES6            0x2     /* 0/6 */
+#define        RES7            0xa     /* 0/7 */
+#define        RES8            0x6     /* 0/8 */
+#define        RES18           0xe     /* 1/8 */
+#define        RES28           0x0     /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define        PAR_ERR         0x10    /* Parity error */
+#define        Rx_OVR          0x20    /* Rx Overrun Error */
+#define        CRC_ERR         0x40    /* CRC/Framing Error */
+#define        END_FR          0x80    /* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
+#define        CHBTxIP 0x2             /* Channel B Tx IP */
+#define        CHBRxIP 0x4             /* Channel B Rx IP */
+#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
+#define        CHATxIP 0x10            /* Channel A Tx IP */
+#define        CHARxIP 0x20            /* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10  (misc status bits) */
+#define        ONLOOP  2               /* On loop */
+#define        LOOPSEND 0x10           /* Loop sending */
+#define        CLK2MIS 0x40            /* Two clocks missing */
+#define        CLK1MIS 0x80            /* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(channel)    (channel->control = ERR_RES)
+#define ZS_CLEARFIFO(channel)   do { volatile unsigned char garbage; \
+                                    garbage = channel->data; \
+                                    udelay(2); \
+                                    garbage = channel->data; \
+                                    udelay(2); \
+                                    garbage = channel->data; \
+                                    udelay(2); } while(0)
+
+#endif /* !(_SPARC_SERIAL_H) */
index d91ceb2b430f79a06f0c19f767fcdc556ea7e698..bfdbb86e9b8c546e5153865767b81f8f2cf57703 100644 (file)
@@ -84,6 +84,38 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_A3000_SCSI),y)
+L_OBJS += a3000.o wd33c93.o
+else
+  ifeq ($(CONFIG_A3000_SCSI),m)
+  M_OBJS += a3000.o wd33c93.o
+  endif
+endif
+
+ifeq ($(CONFIG_A2091_SCSI),y)
+L_OBJS += a2091.o wd33c93.o
+else
+  ifeq ($(CONFIG_A2091_SCSI),m)
+  M_OBJS += a2091.o wd33c93.o
+  endif
+endif
+
+ifeq ($(CONFIG_GVP11_SCSI),y)
+L_OBJS += gvp11.o wd33c93.o
+else
+  ifeq ($(CONFIG_GVP11_SCSI),m)
+  M_OBJS += gvp11.o wd33c93.o
+  endif
+endif
+
+ifeq ($(CONFIG_ATARI_SCSI),y)
+L_OBJS += atari_scsi.o
+else
+  ifeq ($(CONFIG_ATARI_SCSI),m)
+  M_OBJS += atari_scsi.o
+  endif
+endif
+
 ifeq ($(CONFIG_SCSI_PPA),y)
 L_OBJS += ppa.o
 else
@@ -168,6 +200,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_SUNESP),y)
+L_OBJS += esp.o
+else
+  ifeq ($(CONFIG_SCSI_SUNESP),m)
+  M_OBJS += esp.o
+  endif
+endif
+
 ifeq ($(CONFIG_SCSI_DEBUG),y)
 L_OBJS += scsi_debug.o
 else
index fd0ccf81cefd072a926405f77c9c39701bde1227..ad86a96065a544c8485ba6c532be297f03e58eb2 100644 (file)
@@ -298,7 +298,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd);
 #ifndef NCR5380_reset
 static
 #endif
-int NCR5380_reset (Scsi_Cmnd *cmd);
+int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int);
 #ifndef NCR5380_queue_command
 static 
 #endif
index dd1d6fefd2b7a157b8e38d913cce78442ad82aab..5a470fac38c770ffce84cfae81d1081b96a30fe9 100644 (file)
@@ -1,6 +1,7 @@
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/blk.h>
+#include <linux/version.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
index 08f398e2c79a22f214ae9b9bda9447b8da25e45f..9067f6d97eee762a4f94893d5709a3f8c5871e21 100644 (file)
@@ -1,6 +1,6 @@
 #ifndef A2091_H
 
-/* $Id: a2091.h,v 1.3 1996/03/12 20:41:46 root Exp root $
+/* $Id: a2091.h,v 1.4 1996/04/25 20:57:48 root Exp root $
  *
  * Header file for the Commodore A2091 Zorro II SCSI controller for Linux
  *
@@ -14,7 +14,7 @@ int a2091_detect(Scsi_Host_Template *);
 const char *wd33c93_info(void);
 int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int wd33c93_abort(Scsi_Cmnd *);
-int wd33c93_reset(Scsi_Cmnd *);
+int wd33c93_reset(Scsi_Cmnd *, unsigned int);
 
 #ifndef NULL
 #define NULL 0
index 5293d3cf199b9b3f06b96abc60860711d280e5c9..2139d5abad66ea383f6732a16c90eb18837997b6 100644 (file)
@@ -1,6 +1,7 @@
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/blk.h>
+#include <linux/version.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
index b36d52b22eb81949b604ac4f28052837c009784d..a29fa97d8a0ba5d9f9bd875b0b45091b24ac6471 100644 (file)
@@ -1,6 +1,6 @@
 #ifndef A3000_H
 
-/* $Id: a3000.h,v 1.2 1996/02/29 22:10:29 root Exp root $
+/* $Id: a3000.h,v 1.3 1996/04/25 20:58:09 root Exp root $
  *
  * Header file for the Amiga 3000 built-in SCSI controller for Linux
  *
@@ -14,7 +14,7 @@ int a3000_detect(Scsi_Host_Template *);
 const char *wd33c93_info(void);
 int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int wd33c93_abort(Scsi_Cmnd *);
-int wd33c93_reset(Scsi_Cmnd *);
+int wd33c93_reset(Scsi_Cmnd *, unsigned int);
 
 #ifndef NULL
 #define NULL 0
index 0cffe26b37e137f0390f10d95d47005a56310dcc..fee15cf12e9a685ac4d48a29fe539060c6655b42 100644 (file)
@@ -47,7 +47,7 @@
  *    inside the execution of NCR5380_intr(), leading to recursive
  *    calls.
  *
- *  - I've added a function merge_consecutive_buffers() that trys to
+ *  - I've added a function merge_consecutive_buffers() that tries to
  *    merge scatter-gather buffers that are located at consecutive
  *    physical addresses and can be processed with the same DMA setup.
  *    Since most scatter-gather operations work on a page (4K) of
@@ -1995,7 +1995,7 @@ static int do_abort (struct Scsi_Host *host)
      * other phase and will have to source/sink data.
      * 
      * We really don't care what value was on the bus or what value
-     * the target see's, so we just handshake.
+     * the target sees, so we just handshake.
      */
     
     while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
@@ -2280,7 +2280,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
                    printk("scsi%d: target %d lun %d linked command complete.\n",
                        HOSTNO, cmd->target, cmd->lun);
 #endif
-                   /* Enable reselect interupts */
+                   /* Enable reselect interrupts */
                    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
                    /*
                     * Sanity check : A linked command should only terminate
@@ -2348,7 +2348,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
 #else
                    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
 #endif
-                   /* Enable reselect interupts */
+                   /* Enable reselect interrupts */
                    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 
                    /* 
@@ -2429,7 +2429,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
                case MESSAGE_REJECT:
                    /* Accept message by clearing ACK */
                    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-                   /* Enable reselect interupts */
+                   /* Enable reselect interrupts */
                    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
                    switch (hostdata->last_message) {
                    case HEAD_OF_QUEUE_TAG:
@@ -2439,7 +2439,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
                         * queuing, even though it announced this ability in
                         * its INQUIRY data ?!? (maybe only this LUN?) Ok,
                         * clear 'tagged_supported' and lock the LUN, since
-                        * the command is treated as untagged furtheron.
+                        * the command is treated as untagged further on.
                         */
                        cmd->device->tagged_supported = 0;
                        hostdata->busy[cmd->target] |= (1 << cmd->lun);
@@ -2494,7 +2494,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
                case RESTORE_POINTERS:
                    /* Accept message by clearing ACK */
                    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-                   /* Enable reselect interupts */
+                   /* Enable reselect interrupts */
                    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
                    break;
                case EXTENDED_MESSAGE:
@@ -2713,7 +2713,7 @@ static void NCR5380_reselect (struct Scsi_Host *instance)
 #ifdef SUPPORT_TAGS
     /* If the phase is still MSGIN, the target wants to send some more
      * messages. In case it supports tagged queuing, this is probably a
-     * SIMPLE_QEUE_TAG for the I_T_L_Q nexus.
+     * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
      */
     tag = TAG_NONE;
     if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
@@ -3002,7 +3002,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
 
 
 /* 
- * Function : int NCR5380_reset (Scsi_Cmnd *cmd)
+ * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags)
  * 
  * Purpose : reset the SCSI bus.
  *
@@ -3010,7 +3010,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
  *
  */ 
 
-static int NCR5380_reset( Scsi_Cmnd *cmd )
+static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
 {
 #if 0
     SETUP_HOSTDATA(cmd->host);
@@ -3045,7 +3045,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd )
     /* After the reset, there are no more connected or disconnected commands
      * and no busy units; to avoid problems with re-inserting the commands
      * into the issue_queue (via scsi_done()), the aborted commands are
-     * remebered in local variables first.
+     * remembered in local variables first.
      */
     save_flags(flags);
     cli();
index 101aa871f6124303ac858d44d5217fe9b9ffb1ed..01aa7372cef91ef7b14cf3aec7e272a683e3e54a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * atari_scsi.c -- Device dependant functions for the Atari generic SCSI port
+ * atari_scsi.c -- Device dependent functions for the Atari generic SCSI port
  *
  * Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
  *
 /* totally empty if there is a lot of disk traffic.                       */
 /*                                                                        */
 /* For this reasons I decided to employ a more elaborate scheme:          */
-/*  - First, we give up the lock everytime we can (for fairness), this    */
+/*  - First, we give up the lock every time we can (for fairness), this    */
 /*    means every time a command finishes and there are no other commands */
 /*    on the disconnected queue.                                          */
 /*  - If there are others waiting to lock the DMA chip, we stop           */
-/*    issueing commands, i.e. moving them onto the issue queue.           */
+/*    issuing commands, i.e. moving them onto the issue queue.           */
 /*    Because of that, the disconnected queue will run empty in a         */
 /*    while. Instead we go to sleep on a 'fairness_queue'.                */
 /*  - If the lock is released, all processes waiting on the fairness      */
-/*    queue will be woken. The first of them trys to re-lock the DMA,     */
+/*    queue will be woken. The first of them tries to re-lock the DMA,     */
 /*    the others wait for the first to finish this task. After that,      */
 /*    they can all run on and do their commands...                        */
 /* This sounds complicated (and it is it :-(), but it seems to be a       */
-/* good compromise between fairness and performance: As long as noone     */
+/* good compromise between fairness and performance: As long as no one     */
 /* else wants to work with the ST-DMA chip, SCSI can go along as          */
 /* usual. If now someone else comes, this behaviour is changed to a       */
 /* "fairness mode": just already initiated commands are finished and      */
@@ -324,7 +324,7 @@ static void scsi_tt_intr (int irq, struct pt_regs *fp, void *dummy)
 #endif
 
        /* Look if it was the DMA that has interrupted: First possibility
-        * is that a bus error occured...
+        * is that a bus error occurred...
         */
        if (dma_stat & 0x80) {
                if (!scsi_dma_is_ignored_buserr( dma_stat )) {
@@ -335,7 +335,7 @@ static void scsi_tt_intr (int irq, struct pt_regs *fp, void *dummy)
        }
 
        /* If the DMA is active but not finished, we have the the case
-        * that some other 5380 interrupt occured within the DMA transfer.
+        * that some other 5380 interrupt occurred within the DMA transfer.
         * This means we have residual bytes, if the desired end address
         * is not yet reached. Maybe we have to fetch some bytes from the
         * rest data register, too. The residual must be calculated from
@@ -537,7 +537,7 @@ falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
 }
 
 /* This function manages the locking of the ST-DMA.
- * If the DMA isn't locked already for SCSI, it trys to lock it by
+ * If the DMA isn't locked already for SCSI, it tries to lock it by
  * calling stdma_lock(). But if the DMA is locked by the SCSI code and
  * there are other drivers waiting for the chip, we do not issue the
  * command immediately but wait on 'falcon_fairness_queue'. We will be
@@ -585,7 +585,7 @@ static void falcon_get_lock( void )
 
 
 /* This is the wrapper function for NCR5380_queue_command(). It just
- * trys to get the lock on the ST-DMA (see above) and then calls the
+ * tries to get the lock on the ST-DMA (see above) and then calls the
  * original function.
  */
 
@@ -772,7 +772,7 @@ int atari_scsi_release (struct Scsi_Host *sh)
                remove_isr (IRQ_TT_MFP_SCSIDMA, scsi_dma_buserr);
 #endif
        }
-       if (atari_dma_bufffer)
+       if (atari_dma_buffer)
                scsi_init_free (atari_dma_buffer, STRAM_BUFFER_SIZE);
        return 1;
 }
@@ -840,7 +840,7 @@ void atari_scsi_setup( char *str, int *ints )
 #endif
 }
 
-int atari_scsi_reset( Scsi_Cmnd *cmd )
+int atari_scsi_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
 {
        int             rv;
        struct NCR5380_hostdata *hostdata =
@@ -866,7 +866,7 @@ int atari_scsi_reset( Scsi_Cmnd *cmd )
 #endif /* REAL_DMA */
        }
 
-       rv = NCR5380_reset( cmd );
+       rv = NCR5380_reset(cmd, reset_flags);
 
        /* Re-enable ints */
        if (IS_A_TT()) {
@@ -955,7 +955,7 @@ unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data,
         * ++roman: For the Medusa, there's no need at all for that cache stuff,
         * because the hardware does bus snooping (fine!).
         */
-       dma_cache_maintainance( addr, count, dir );
+       dma_cache_maintenance( addr, count, dir );
 
        if (count == 0)
                printk("SCSI warning: DMA programmed for 0 bytes !\n");
index 85546de9f228769b4e5b5157063a503f1353dd10..4ead7ed9de46ce5226711d09c75e9d8551c708e1 100644 (file)
@@ -22,7 +22,7 @@ int atari_scsi_abort (Scsi_Cmnd *);
 int atari_scsi_detect (Scsi_Host_Template *);
 const char *atari_scsi_info (struct Scsi_Host *);
 int atari_scsi_queue_command (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-int atari_scsi_reset (Scsi_Cmnd *);
+int atari_scsi_reset (Scsi_Cmnd *, unsigned int);
 int atari_scsi_proc_info (char *, char **, off_t, int, int, int);
 #ifdef MODULE
 int atari_scsi_release (struct Scsi_Host *);
@@ -34,7 +34,7 @@ int atari_scsi_release (struct Scsi_Host *);
  * values should work, too; try it! (but cmd_per_lun costs memory!) */
 
 /* But there seems to be a bug somewhere that requires CAN_QUEUE to be
- * 2*CMD_OER_LUN. At least on a TT, no suprious timeouts seen since
+ * 2*CMD_OER_LUN. At least on a TT, no spurious timeouts seen since
  * changed CMD_PER_LUN... */
 
 /* Note: The Falcon currently uses 8/1 setting due to unsolved problems with
index b3c67d9e1081af41d79fd970a074d42b6e814e66..a81977919e08d3de525c35d289084d1fc9ce311d 100644 (file)
@@ -1,6 +1,7 @@
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/blk.h>
+#include <linux/version.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
index 35ad1d2c76d96d184ce4ce5af76ed3c7c9cb88e3..00bbfb5d4b336231f6d4ba765e6ce720d5355c7c 100644 (file)
@@ -1,6 +1,6 @@
 #ifndef GVP11_H
 
-/* $Id: gvp11.h,v 1.4 1996/03/12 20:42:40 root Exp root $
+/* $Id: gvp11.h,v 1.5 1996/04/25 20:58:31 root Exp root $
  *
  * Header file for the GVP Series II SCSI controller for Linux
  *
@@ -15,7 +15,7 @@ int gvp11_detect(Scsi_Host_Template *);
 const char *wd33c93_info(void);
 int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int wd33c93_abort(Scsi_Cmnd *);
-int wd33c93_reset(Scsi_Cmnd *);
+int wd33c93_reset(Scsi_Cmnd *, unsigned int);
 
 #ifndef NULL
 #define NULL 0
index b728ea9dbcc1b37ec82154b70f6eedd6d4f582b9..9c2076c5c9dc8d384d07869f90d2471cf0e747e9 100644 (file)
 
 #include "hosts.h"
 
+#ifdef CONFIG_A3000_SCSI
+#include "a3000.h"
+#endif
+
+#ifdef CONFIG_A2091_SCSI
+#include "a2091.h"
+#endif
+
+#ifdef CONFIG_GVP11_SCSI
+#include "gvp11.h"
+#endif
+
+#ifdef CONFIG_ATARI_SCSI
+#include "atari_scsi.h"
+#endif
+
 #ifdef CONFIG_SCSI_ADVANSYS
 #include "advansys.h"
 #endif
 
 
 /*
-static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.c,v 1.10 1996/04/16 08:09:36 davem Exp $";
+static const char RCSid[] = "$Header: /usr/src/linux-1.3.95/drivers/scsi/RCS/hosts.c,v 1.7 1996/04/25 22:21:56 root Exp root $";
 */
 
 /*
@@ -179,6 +195,24 @@ Scsi_Host_Template * scsi_hosts = NULL;
 
 static Scsi_Host_Template builtin_scsi_hosts[] =
 {
+#ifdef CONFIG_AMIGA
+#ifdef CONFIG_A3000_SCSI
+       A3000_SCSI,
+#endif
+#ifdef CONFIG_A2091_SCSI
+       A2091_SCSI,
+#endif
+#ifdef CONFIG_GVP11_SCSI
+       GVP11_SCSI,
+#endif
+#endif
+
+#ifdef CONFIG_ATARI
+#ifdef CONFIG_ATARI_SCSI
+       ATARI_SCSI,
+#endif
+#endif
+
 #ifdef CONFIG_SCSI_ADVANSYS
        ADVANSYS,
 #endif
index 72957c487c7ecbc44c3a257819a2068a526a92e5..57bc3fc500a4c05884ed6b8b60a96d73364f8ffe 100644 (file)
@@ -288,7 +288,7 @@ static struct dev_info device_list[] =
 {"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"PIONEER","CD-ROM DRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
-{"EMULEX","MD21/S2     ESDI","*",BLIST_FORCELUN | BLIST_SINGLELUN},
+{"EMULEX","MD21/S2     ESDI","*",BLIST_SINGLELUN},
 /*
  * Must be at end of list...
  */
index 678bebfad3b7931b5a26651f8764596d8fab5de9..c0cafa5a88e05790b3c57da7e1d6064898e59656 100644 (file)
  *
  *    -  Target Disconnection/Reconnection  is now supported. Any
  *          system with more than one device active on the SCSI bus
- *          will benefit from this.
+ *          will benefit from this. The driver defaults to what I'm
+ *          'adaptive disconnect' - meaning that each command is
+ *          evaluated individually as to whether or not it should
+ *          be run with the option to disconnect/reslect (if the
+ *          device chooses), or as a "SCSI-bus-hog".
  *
- *    -  Synchronous data transfers are now supported. The driver
- *          automatically uses this faster protocol with any device
- *          able to handle it.
+ *    -  Synchronous data transfers are now supported. Because of
+ *          a few devices that choke after telling the driver that
+ *          they can do sync transfers, we don't automatically use
+ *          this faster protocol - it can be enabled via the command-
+ *          line on a device-by-device basis.
  *
  *    -  Runtime operating parameters can now be specified through
- *       either the 'amiboot' or the LILO command line. Something
- *       like:
- *          "wd33c93=0x0000"
- *       The value 0x0000 results in the defaults being used; bits
- *       are defined in wd33c93.h.
+ *       the 'amiboot' or the 'insmod' command line. For amiboot do:
+ *          "amiboot [usual stuff] wd33c93=blah,blah,blah"
+ *       The defaults should be good for most people. See the comment
+ *       for 'setup_strings' below for more details.
  *
  *    -  The old driver relied exclusively on what the Western Digital
  *          docs call "Combination Level 2 Commands", which are a great
@@ -52,7 +57,7 @@
  *
  *
  * TODO:
- *       more speed. tagged queuing.
+ *       more speed. linked commands.
  *
  *
  * People with bug reports, wish-lists, complaints, comments,
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/delay.h>
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= 0x010300
 #include <linux/blk.h>
+#else
+#include "../block/blk.h"
+#endif
+
 #include "scsi.h"
 #include "hosts.h"
 #include "wd33c93.h"
 
+#ifdef MODULE
+#include <linux/module.h>
+#endif
 
-#define SYNC_DEBUG
+/* Leave this undefined for now - need to make some changes in the
+ * a3000/a2019/gvp11 files to get it working right
+ */
+/*#define PROC_INTERFACE*/     /* add code for /proc/scsi/wd33c93/xxx interface */
 
-#define DEBUGGING_ON
+#define SYNC_DEBUG         /* extra info on sync negotiation printed */
+#define DEBUGGING_ON       /* enable command-line debugging bitmask */
+#define DEBUG_DEFAULTS 0   /* default debugging bitmask */
 
-#define WD33C93_VERSION    "1.17"
-#define WD33C93_DATE       "06/Feb/1996"
+#define WD33C93_VERSION    "1.21"
+#define WD33C93_DATE       "20/Apr/1996"
 
 #ifdef DEBUGGING_ON
 #define DB(f,a) if (hostdata->args & (f)) a;
 
 
 /*
- * setup_default is a bunch of bits that define some of the operating
- * parameters and settings for this driver. It is used unless a LILO
- * or insmod command line has been specified, in which case setup_default
- * is _completely_ ignored. Take a look at the "defines for hostdata->args"
- * section in wd33c93.h - that stuff is what you'd use here if you want
- * to change the defaults.
+ * setup_strings is an array of strings that define some of the operating
+ * parameters and settings for this driver. It is used unless an amiboot
+ * or insmod command line has been specified, in which case those settings
+ * are combined with the ones here. The driver recognizes the following
+ * keywords (lower case required) and arguments:
+ *
+ * -  nosync:bitmask -bitmask is a byte where the 1st 7 bits correspond with
+ *                    the 7 possible SCSI devices. Set a bit to prevent sync
+ *                    negotiation on that device. To maintain backwards
+ *                    compatability, a command-line such as "wd33c93=255" will
+ *                    be automatically translated to "wd33c93=nosync:0xff".
+ * -  period:ns      -ns is the minimum # of nanoseconds in a SCSI data transfer
+ *                    period. Default is 500; acceptable values are 250 - 1000.
+ * -  disconnect:x   -x = 0 to never allow disconnects, 2 to always allow them.
+ *                    x = 1 does 'adaptive' disconnects, which is the default
+ *                    and generally the best choice.
+ * -  debug:x        -If 'DEBUGGING_ON' is defined, x is a bit mask that causes
+ *                    various types of debug output to printed - see the DB_xxx
+ *                    defines in wd33c93.h
+ * -  clock:x        -x = clock input in MHz for WD33c93 chip. Normal values
+ *                    would be from 8 through 20. Default is 8.
+ * -  next           -No argument. Used to separate blocks of keywords when
+ *                    there's more than one host adapter in the system.
+ *
+ * Syntax Notes:
+ * -  Numeric arguments can be decimal or the '0x' form of hex notation. There
+ *    _must_ be a colon between a keyword and its numeric argument, with no
+ *    spaces.
+ * -  Keywords are separated by commas, no spaces, in the standard kernel
+ *    command-line manner, except in the case of 'setup_strings[]' (see
+ *    below), which is simply a C array of pointers to char. Each element
+ *    in the array is a string comprising one keyword & argument.
+ * -  A keyword in the 'nth' comma-separated command-line member will overwrite
+ *    the 'nth' element of setup_strings[]. A blank command-line member (in
+ *    other words, a comma with no preceding keyword) will _not_ overwrite
+ *    the corresponding setup_strings[] element.
+ * -  If a keyword is used more than once, the first one applies to the first
+ *    SCSI host found, the second to the second card, etc, unless the 'next'
+ *    keyword is used to change the order.
+ *
+ * Some amiboot examples (for insmod, use 'setup_strings' instead of 'wd33c93'):
+ * -  wd33c93=nosync:255
+ * -  wd33c93=disconnect:2,nosync:0x08,period:250
+ * -  wd33c93=debug:0x1c
  */
 
-static unsigned int setup_default = 0;
+static char *setup_strings[] =
+      {"","","","","","","","","","","",""};
+
+#ifdef PROC_INTERFACE
+unsigned long disc_allowed_total;
+unsigned long disc_taken_total;
+#endif
 
 
 inline uchar read_wd33c93(wd33c93_regs *regp,uchar reg_num)
@@ -176,27 +240,32 @@ static struct sx_period sx_table[] = {
    {1000,0x00},
    {0,   0} };
 
-uchar calc_sync_xfer(unsigned int period, unsigned int offset)
+int round_period(unsigned int period)
 {
-uchar result;
 int x;
 
-   period *= 4;   /* convert SDTR code to ns */
-   result = 0x00;
    for (x=1; sx_table[x].period_ns; x++) {
       if ((period <= sx_table[x-0].period_ns) &&
           (period >  sx_table[x-1].period_ns)) {
-         result = sx_table[x].reg_value;
-         break;
+         return x;
          }
       }
+   return 7;
+}
+
+uchar calc_sync_xfer(unsigned int period, unsigned int offset)
+{
+uchar result;
+
+   period *= 4;   /* convert SDTR code to ns */
+   result = sx_table[round_period(period)].reg_value;
    result |= (offset < OPTIMUM_SX_OFF)?offset:OPTIMUM_SX_OFF;
    return result;
 }
 
 
 
-static void wd33c93_execute(struct Scsi_Host *instance);
+void wd33c93_execute(struct Scsi_Host *instance);
 
 int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
@@ -204,13 +273,14 @@ struct WD33C93_hostdata *hostdata;
 Scsi_Cmnd *tmp;
 unsigned long flags;
 
+
+   save_flags(flags);
+   cli();
    hostdata = (struct WD33C93_hostdata *)cmd->host->hostdata;
 
 DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid))
 
-
-/*
- * Set up a few fields in the Scsi_Cmnd structure for our own use:
+/* Set up a few fields in the Scsi_Cmnd structure for our own use:
  *  - host_scribble is the pointer to the next cmd in the input queue
  *  - scsi_done points to the routine we call when a cmd is finished
  *  - result is what you'd expect
@@ -230,6 +300,9 @@ DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid))
  *  - SCp.this_residual is the size of that buffer
  *  - SCp.buffer points to the current scatter-gather buffer
  *  - SCp.buffers_residual tells us how many S.G. buffers there are
+ *  - SCp.have_data_in is not used
+ *  - SCp.sent_command is not used
+ *  - SCp.phase records this command's SRCID_ER bit setting
  */
 
    if (cmd->use_sg) {
@@ -255,19 +328,16 @@ DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid))
     * sense data is not lost before REQUEST_SENSE executes.
     */
 
-   save_flags(flags);
-   cli();
    if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) {
       cmd->host_scribble = (uchar *)hostdata->input_Q;
       hostdata->input_Q = cmd;
       }
-   else {
+   else {   /* find the end of the queue */
       for (tmp=(Scsi_Cmnd *)hostdata->input_Q; tmp->host_scribble;
             tmp=(Scsi_Cmnd *)tmp->host_scribble)
          ;
       tmp->host_scribble = (uchar *)cmd;
       }
-   restore_flags(flags);
 
 /* We know that there's at least one command in 'input_Q' now.
  * Go see if any of them are runnable!
@@ -275,7 +345,9 @@ DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid))
 
    wd33c93_execute(cmd->host);
 
-DB(DB_QUEUE_COMMAND,printk(")Q-%d-%02x-%ld ",cmd->target,cmd->cmnd[0],cmd->pid))
+DB(DB_QUEUE_COMMAND,printk(")Q-%ld ",cmd->pid))
+
+   restore_flags(flags);
    return 0;
 }
 
@@ -287,7 +359,7 @@ DB(DB_QUEUE_COMMAND,printk(")Q-%d-%02x-%ld ",cmd->target,cmd->cmnd[0],cmd->pid))
  * the input_Q, using the first command we find that's intended
  * for a currently non-busy target/lun.
  */
-static void wd33c93_execute (struct Scsi_Host *instance)
+void wd33c93_execute (struct Scsi_Host *instance)
 {
 struct WD33C93_hostdata *hostdata;
 wd33c93_regs *regp;
@@ -301,10 +373,12 @@ int i;
    hostdata = (struct WD33C93_hostdata *)instance->hostdata;
    regp = hostdata->regp;
 
-DB(DB_EXECUTE,printk("EX( "))
+DB(DB_EXECUTE,printk("EX("))
 
    if (hostdata->selecting || hostdata->connected) {
+
 DB(DB_EXECUTE,printk(")EX-0 "))
+
       restore_flags(flags);
       return;
       }
@@ -326,18 +400,19 @@ DB(DB_EXECUTE,printk(")EX-0 "))
    /* quit if queue empty or all possible targets are busy */
 
    if (!cmd) {
+
 DB(DB_EXECUTE,printk(")EX-1 "))
+
       restore_flags(flags);
       return;
       }
 
-   /*  remove command from queue, put it in selecting */
+   /*  remove command from queue */
    
    if (prev)
       prev->host_scribble = cmd->host_scribble;
    else
       hostdata->input_Q = (Scsi_Cmnd *)cmd->host_scribble;
-   hostdata->selecting = cmd;
 
    /*
     * Start the selection process
@@ -348,22 +423,78 @@ DB(DB_EXECUTE,printk(")EX-1 "))
    else
       write_wd33c93(regp, WD_DESTINATION_ID, cmd->target | DSTID_DPD);
 
+/* Now we need to figure out whether or not this command is a good
+ * candidate for disconnect/reselect. We guess to the best of our
+ * ability, based on a set of hierarchical rules. When several
+ * devices are operating simultaneously, disconnects are usually
+ * an advantage. In a single device system, or if only 1 device
+ * is being accessed, transfers usually go faster if disconnects
+ * are not allowed:
+ *
+ * + Commands should NEVER disconnect if hostdata->disconnect =
+ *   DIS_NEVER (this holds for tape drives also), and ALWAYS
+ *   disconnect if hostdata->disconnect = DIS_ALWAYS.
+ * + Tape drive commands should always be allowed to disconnect.
+ * + Disconnect should be allowed if disconnected_Q isn't empty.
+ * + Commands should NOT disconnect if input_Q is empty.
+ * + Disconnect should be allowed if there are commands in input_Q
+ *   for a different target/lun. In this case, the other commands
+ *   should be made disconnect-able, if not already.
+ *
+ * I know, I know - this code would flunk me out of any
+ * "C Programming 101" class ever offered. But it's easy
+ * to change around and experiment with for now.
+ */
+
+   cmd->SCp.phase = 0;  /* assume no disconnect */
+   if (hostdata->disconnect == DIS_NEVER)
+      goto no;
+   if (hostdata->disconnect == DIS_ALWAYS)
+      goto yes;
+   if (cmd->device->type == 1)   /* tape drive? */
+      goto yes;
+   if (hostdata->disconnected_Q) /* other commands disconnected? */
+      goto yes;
+   if (!(hostdata->input_Q))     /* input_Q empty? */
+      goto no;
+   for (prev=(Scsi_Cmnd *)hostdata->input_Q; prev;
+         prev=(Scsi_Cmnd *)prev->host_scribble) {
+      if ((prev->target != cmd->target) || (prev->lun != cmd->lun)) {
+         for (prev=(Scsi_Cmnd *)hostdata->input_Q; prev;
+               prev=(Scsi_Cmnd *)prev->host_scribble)
+            prev->SCp.phase = 1;
+         goto yes;
+         }
+      }
+   goto no;
+
+yes:
+   cmd->SCp.phase = 1;
+
+#ifdef PROC_INTERFACE
+   disc_allowed_total++;
+#endif
+
+no:
+   write_wd33c93(regp, WD_SOURCE_ID, ((cmd->SCp.phase)?SRCID_ER:0));
+
    write_wd33c93(regp, WD_TARGET_LUN, cmd->lun);
-   write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
-   write_wd33c93_count(regp, 0); /* this guarantees a DATA_PHASE interrupt */
+   write_wd33c93(regp,WD_SYNCHRONOUS_TRANSFER,hostdata->sync_xfer[cmd->target]);
    hostdata->busy[cmd->target] |= (1 << cmd->lun);
 
    if ((hostdata->level2 == L2_NONE) ||
        (hostdata->sync_stat[cmd->target] == SS_UNSET)) {
 
          /*
-          * Now do a 'Select-With-ATN' command. This will end with
+          * Do a 'Select-With-ATN' command. This will end with
           * one of the following interrupts:
           *    CSR_RESEL_AM:  failure - can try again later.
           *    CSR_TIMEOUT:   failure - give up.
           *    CSR_SELECT:    success - proceed.
           */
 
+      hostdata->selecting = cmd;
+
 /* Every target has its own synchronous transfer setting, kept in the
  * sync_xfer array, and a corresponding status byte in sync_stat[].
  * Each target's sync_stat[] entry is initialized to SX_UNSET, and its
@@ -376,19 +507,20 @@ DB(DB_EXECUTE,printk(")EX-1 "))
  * make the defaults final.
  */
       if (hostdata->sync_stat[cmd->target] == SS_UNSET) {
-         if (hostdata->args & (1 << cmd->target))
+         if (hostdata->no_sync & (1 << cmd->target))
             hostdata->sync_stat[cmd->target] = SS_SET;
          else
             hostdata->sync_stat[cmd->target] = SS_FIRST;
          }
       hostdata->state = S_SELECTING;
+      write_wd33c93_count(regp,0); /* guarantee a DATA_PHASE interrupt */
       write_wd33c93_cmd(regp, WD_CMD_SEL_ATN);
       }
 
    else {
 
          /*
-          * Now do a 'Select-With-ATN-Xfer' command. This will end with
+          * Do a 'Select-With-ATN-Xfer' command. This will end with
           * one of the following interrupts:
           *    CSR_RESEL_AM:  failure - can try again later.
           *    CSR_TIMEOUT:   failure - give up.
@@ -396,13 +528,15 @@ DB(DB_EXECUTE,printk(")EX-1 "))
           */
 
       hostdata->connected = cmd;
-      hostdata->selecting = NULL;
       write_wd33c93(regp, WD_COMMAND_PHASE, 0);
 
-   /* copy command_descriptor_block into WD chip */
+   /* copy command_descriptor_block into WD chip
+    * (take advantage of auto-incrementing)
+    */
 
+      regp->SASR = WD_CDB_1;
       for (i=0; i<cmd->cmd_len; i++)
-         write_wd33c93(regp, WD_CDB_1+i, cmd->cmnd[i]);
+         regp->SCMD = cmd->cmnd[i];
 
    /* The wd33c93 only knows about Group 0, 1, and 5 commands when
     * it's doing a 'select-and-transfer'. To be safe, we write the
@@ -412,6 +546,23 @@ DB(DB_EXECUTE,printk(")EX-1 "))
 
       write_wd33c93(regp, WD_OWN_ID, cmd->cmd_len);
 
+   /* When doing a non-disconnect command, we can save ourselves a DATA
+    * phase interrupt later by setting everything up now.
+    */
+
+      if (cmd->SCp.phase == 0) {
+         if (hostdata->dma_setup(cmd,
+                     (IS_DIR_OUT(cmd))?DATA_OUT_DIR:DATA_IN_DIR))
+            write_wd33c93_count(regp,0); /* guarantee a DATA_PHASE interrupt */
+         else {
+            write_wd33c93_count(regp, cmd->SCp.this_residual);
+            write_wd33c93(regp,WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA);
+            hostdata->dma = D_DMA_RUNNING;
+            }
+         }
+      else
+         write_wd33c93_count(regp,0); /* guarantee a DATA_PHASE interrupt */
+
       hostdata->state = S_RUNNING_LEVEL2;
       write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
       }
@@ -423,47 +574,38 @@ DB(DB_EXECUTE,printk(")EX-1 "))
     * to search the input_Q again...
     */
       
-DB(DB_EXECUTE,printk(")EX-2 "))
+DB(DB_EXECUTE,printk("%s%ld)EX-2 ",(cmd->SCp.phase)?"d:":"",cmd->pid))
+
    restore_flags(flags);
 }
 
 
 
-void transfer_pio(wd33c93_regs *regp, uchar **buf, int *cnt,
+void transfer_pio(wd33c93_regs *regp, uchar *buf, int cnt,
                   int data_in_dir, struct WD33C93_hostdata *hostdata)
 {
-uchar *b, asr;
-int c;
+uchar asr;
+
+DB(DB_TRANSFER,printk("(%p,%d,%s)",buf,cnt,data_in_dir?"in":"out"))
 
    write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
-   b = *buf;
-   c = *cnt;
-DB(DB_TRANSFER_DATA,printk("[[%p/%d]]",b,c))
-   write_wd33c93_count(regp,c);
+   write_wd33c93_count(regp,cnt);
    write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO);
    if (data_in_dir) {
       do {
          asr = READ_AUX_STAT();
          if (asr & ASR_DBR)
-            *b++ = read_wd33c93(regp, WD_DATA);
+            *buf++ = read_wd33c93(regp, WD_DATA);
          } while (!(asr & ASR_INT));
       }
    else {
       do {
          asr = READ_AUX_STAT();
          if (asr & ASR_DBR)
-            write_wd33c93(regp, WD_DATA, *b++);
+            write_wd33c93(regp, WD_DATA, *buf++);
          } while (!(asr & ASR_INT));
       }
 
-/* update original buffer pointer and original count */
-
-   *cnt = read_wd33c93_count(regp);
-   if (data_in_dir)
-      *buf = b;
-   else
-      *buf += (c - *cnt);
-
    /* Note: we are returning with the interrupt UN-cleared.
    * Since (presumably) an entire I/O operation has
    * completed, the bus phase is probably different, and
@@ -501,7 +643,7 @@ struct WD33C93_hostdata *hostdata;
 /* 'dma_setup()' will return TRUE if we can't do DMA. */
 
    if (hostdata->dma_setup(cmd, data_in_dir)) {
-      transfer_pio(regp, (uchar **)&cmd->SCp.ptr, &cmd->SCp.this_residual,
+      transfer_pio(regp, (uchar *)&cmd->SCp.ptr, cmd->SCp.this_residual,
                          data_in_dir, hostdata);
       }
 
@@ -516,11 +658,10 @@ struct WD33C93_hostdata *hostdata;
 
    else {
       write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA);
-DB(DB_TRANSFER_DATA,printk("[%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual))
       write_wd33c93_count(regp,cmd->SCp.this_residual);
 
-      if (hostdata->level2 >= L2_DATA) {
-         write_wd33c93(regp, WD_COMMAND_PHASE, 0x41);
+      if ((hostdata->level2 >= L2_DATA) || (cmd->SCp.phase == 0)) {
+         write_wd33c93(regp, WD_COMMAND_PHASE, 0x45);
          write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
          hostdata->state = S_RUNNING_LEVEL2;
          }
@@ -538,9 +679,9 @@ void wd33c93_intr (struct Scsi_Host *instance)
 struct WD33C93_hostdata *hostdata;
 Scsi_Cmnd *patch, *cmd;
 wd33c93_regs *regp;
+unsigned long flags;
 uchar asr, sr, phs, id, lun, *ucp, msg;
 unsigned long length;
-int i;
 
 
    hostdata = (struct WD33C93_hostdata *)instance->hostdata;
@@ -550,6 +691,11 @@ int i;
    if (!(asr & ASR_INT) || (asr & ASR_BSY))
       return;
 
+/* OK - it should be safe to re-enable system interrupts */
+
+   save_flags(flags);
+   sti();
+
    cmd = (Scsi_Cmnd *)hostdata->connected;   /* assume we're connected */
    sr = read_wd33c93(regp, WD_SCSI_STATUS);  /* clear the interrupt */
    phs = read_wd33c93(regp, WD_COMMAND_PHASE);
@@ -572,13 +718,13 @@ DB(DB_INTR,printk("{%02x:%02x-",asr,sr))
  */
 
    if (hostdata->dma == D_DMA_RUNNING) {
-DB(DB_TRANSFER_DATA,printk("[%p/%d:",cmd->SCp.ptr,cmd->SCp.this_residual))
+DB(DB_TRANSFER,printk("[%p/%d:",cmd->SCp.ptr,cmd->SCp.this_residual))
       hostdata->dma_stop(cmd->host, cmd, 1);
       hostdata->dma = D_DMA_OFF;
       length = cmd->SCp.this_residual;
       cmd->SCp.this_residual = read_wd33c93_count(regp);
       cmd->SCp.ptr += (length - cmd->SCp.this_residual);
-DB(DB_TRANSFER_DATA,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual))
+DB(DB_TRANSFER,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual))
       }
 
 /* Respond to the specific WD3393 interrupt - there are quite a few! */
@@ -586,26 +732,26 @@ DB(DB_TRANSFER_DATA,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual))
    switch (sr) {
 
       case CSR_TIMEOUT:
-         cli();
 DB(DB_INTR,printk("TIMEOUT"))
-         if (hostdata->state == S_RUNNING_LEVEL2) {
+
+         cli();
+         if (hostdata->state == S_RUNNING_LEVEL2)
             hostdata->connected = NULL;
-            hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
-            }
          else {
             cmd = (Scsi_Cmnd *)hostdata->selecting;   /* get a valid cmd */
             hostdata->selecting = NULL;
             }
 
          cmd->result = DID_NO_CONNECT << 16;
-         hostdata->selecting = NULL;
+         hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
          hostdata->state = S_UNCONNECTED;
-         cmd->scsi_done(cmd);    /* I think scsi_done() enables ints */
+         cmd->scsi_done(cmd);
 
 /* We are not connected to a target - check to see if there
  * are commands waiting to be executed.
  */
 
+         sti();
          wd33c93_execute(instance);
          break;
 
@@ -620,10 +766,9 @@ DB(DB_INTR,printk("SELECT"))
 
       /* construct an IDENTIFY message with correct disconnect bit */
 
-         if (hostdata->args & A_NO_DISCONNECT)
-            hostdata->outgoing_msg[0] = (0x80 | cmd->lun);
-         else
-            hostdata->outgoing_msg[0] = (0x80 | 0x40 | cmd->lun);
+         hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->lun);
+         if (cmd->SCp.phase)
+            hostdata->outgoing_msg[0] |= 0x40;
 
          if (hostdata->sync_stat[cmd->target] == SS_FIRST) {
 #ifdef SYNC_DEBUG
@@ -671,11 +816,10 @@ DB(DB_INTR,printk("OUT-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual))
 /* Note: this interrupt should not occur in a LEVEL2 command */
 
       case CSR_XFER_DONE|PHS_COMMAND:
+      case CSR_UNEXP    |PHS_COMMAND:
       case CSR_SRV_REQ  |PHS_COMMAND:
 DB(DB_INTR,printk("CMND-%02x,%ld",cmd->cmnd[0],cmd->pid))
-         ucp = cmd->cmnd;
-         i = cmd->cmd_len;
-         transfer_pio(regp, &ucp, &i, DATA_OUT_DIR, hostdata);
+         transfer_pio(regp, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata);
          hostdata->state = S_CONNECTED;
          break;
 
@@ -704,6 +848,7 @@ DB(DB_INTR,printk("=%02x",cmd->SCp.Status))
       case CSR_SRV_REQ  |PHS_MESS_IN:
 DB(DB_INTR,printk("MSG_IN="))
 
+         cli();
          msg = read_1_byte(regp);
          sr = read_wd33c93(regp, WD_SCSI_STATUS);  /* clear interrupt */
 
@@ -730,7 +875,6 @@ DB(DB_INTR,printk("SDP"))
 
             case RESTORE_POINTERS:
 DB(DB_INTR,printk("RDP"))
-
                if (hostdata->level2 >= L2_BASIC) {
                   write_wd33c93(regp, WD_COMMAND_PHASE, 0x45);
                   write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
@@ -777,24 +921,50 @@ printk("%02x",ucp[hostdata->incoming_ptr]);
                      case EXTENDED_SDTR:
                         id = calc_sync_xfer(ucp[3],ucp[4]);
                         if (hostdata->sync_stat[cmd->target] != SS_WAITING) {
-                           printk("Rejecting target's SDTR message ");
+
+/* A device has sent an unsolicited SDTR message; rather than go
+ * through the effort of decoding it and then figuring out what
+ * our reply should be, we're just gonna say that we have a
+ * synchronous fifo depth of 0. This will result in asynchronous
+ * transfers - not ideal but so much easier.
+ * Actually, this is OK because it assures us that if we don't
+ * specifically ask for sync transfers, we won't do any.
+ */
+
                            write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */
-                           hostdata->outgoing_msg[0] = MESSAGE_REJECT;
-                           hostdata->outgoing_len = 1;
+                           hostdata->outgoing_msg[0] = EXTENDED_MESSAGE;
+                           hostdata->outgoing_msg[1] = 3;
+                           hostdata->outgoing_msg[2] = EXTENDED_SDTR;
+                           hostdata->outgoing_msg[3] = hostdata->default_sx_per/4;
+                           hostdata->outgoing_msg[4] = 0;
+                           hostdata->outgoing_len = 5;
+                           hostdata->sync_xfer[cmd->target] =
+                                       calc_sync_xfer(hostdata->default_sx_per/4,0);
                            }
                         else {
                            hostdata->sync_xfer[cmd->target] = id;
-                           hostdata->sync_stat[cmd->target] = SS_SET;
                            }
 #ifdef SYNC_DEBUG
-printk("sync_xfer=%02x",id);
+printk("sync_xfer=%02x",hostdata->sync_xfer[cmd->target]);
 #endif
+                        hostdata->sync_stat[cmd->target] = SS_SET;
+                        write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
+                        hostdata->state = S_CONNECTED;
+                        break;
+                     case EXTENDED_WDTR:
+                        write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */
+                        printk("sending WDTR ");
+                        hostdata->outgoing_msg[0] = EXTENDED_MESSAGE;
+                        hostdata->outgoing_msg[1] = 2;
+                        hostdata->outgoing_msg[2] = EXTENDED_WDTR;
+                        hostdata->outgoing_msg[3] = 0;   /* 8 bit transfer width */
+                        hostdata->outgoing_len = 4;
                         write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
                         hostdata->state = S_CONNECTED;
                         break;
                      default:
-                        printk("Rejecting Unknown Extended Message(%02x). ",ucp[2]);
                         write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */
+                        printk("Rejecting Unknown Extended Message(%02x). ",ucp[2]);
                         hostdata->outgoing_msg[0] = MESSAGE_REJECT;
                         hostdata->outgoing_len = 1;
                         write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
@@ -814,7 +984,7 @@ printk("sync_xfer=%02x",id);
                break;
 
             default:
-               printk("Rejecting Unknown Message(%02x) ",ucp[0]);
+               printk("Rejecting Unknown Message(%02x) ",msg);
                write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */
                hostdata->outgoing_msg[0] = MESSAGE_REJECT;
                hostdata->outgoing_len = 1;
@@ -828,6 +998,12 @@ printk("sync_xfer=%02x",id);
 
       case CSR_SEL_XFER_DONE:
          cli();
+
+/* Make sure that reselection is enabled at this point - it may
+ * have been turned off for the command that just completed.
+ */
+
+         write_wd33c93(regp,WD_SOURCE_ID, SRCID_ER);
          if (phs == 0x60) {
 DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid))
             cmd->SCp.Message = COMMAND_COMPLETE;
@@ -841,7 +1017,7 @@ DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid))
                cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
             hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
             hostdata->state = S_UNCONNECTED;
-            cmd->scsi_done(cmd);    /* I think scsi_done() enables ints */
+            cmd->scsi_done(cmd);
 
 /* We are no longer  connected to a target - check to see if
  * there are commands waiting to be executed.
@@ -877,8 +1053,8 @@ DB(DB_INTR,printk("MSG_OUT="))
  * it - like when our SDTR message is rejected by a target. Some
  * targets send the REJECT before receiving all of the extended
  * message, and then seem to go back to MESSAGE_OUT for a byte
- * or two. Not sure why, ot if I'm doing something wrong to
- * casue this to happen. Regardless, it seems that sending
+ * or two. Not sure why, or if I'm doing something wrong to
+ * cause this to happen. Regardless, it seems that sending
  * NOP messages in these situations results in no harm and
  * makes everyone happy.
  */
@@ -887,22 +1063,67 @@ DB(DB_INTR,printk("MSG_OUT="))
             hostdata->outgoing_len = 1;
             hostdata->outgoing_msg[0] = NOP;
             }
-         ucp = hostdata->outgoing_msg;
-         i = hostdata->outgoing_len;
-         transfer_pio(regp, &ucp, &i, DATA_OUT_DIR, hostdata);
+         transfer_pio(regp, hostdata->outgoing_msg, hostdata->outgoing_len,
+                            DATA_OUT_DIR, hostdata);
 DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0]))
          hostdata->outgoing_len = 0;
          hostdata->state = S_CONNECTED;
          break;
 
 
-      case CSR_DISC:
-DB(DB_INTR,printk("DISC"))
+      case CSR_UNEXP_DISC:
+
+/* I think I've seen this after a request-sense that was in response
+ * to an error condition, but not sure. We certainly need to do
+ * something when we get this interrupt - the question is 'what?'.
+ * Let's think positively, and assume some command has finished
+ * in a legal manner (like a command that provokes a request-sense),
+ * so we treat it as a normal command-complete-disconnect.
+ */
+
+         cli();
+
+/* Make sure that reselection is enabled at this point - it may
+ * have been turned off for the command that just completed.
+ */
+
+         write_wd33c93(regp,WD_SOURCE_ID, SRCID_ER);
          if (cmd == NULL) {
             printk(" - Already disconnected! ");
             hostdata->state = S_UNCONNECTED;
             return;
             }
+DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid))
+         hostdata->connected = NULL;
+         hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+         hostdata->state = S_UNCONNECTED;
+         if (cmd->cmnd[0] != REQUEST_SENSE)
+            cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+         else if (cmd->SCp.Status != GOOD)
+            cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+         cmd->scsi_done(cmd);
+
+/* We are no longer connected to a target - check to see if
+ * there are commands waiting to be executed.
+ */
+
+         wd33c93_execute(instance);
+         break;
+
+
+      case CSR_DISC:
+         cli();
+
+/* Make sure that reselection is enabled at this point - it may
+ * have been turned off for the command that just completed.
+ */
+
+         write_wd33c93(regp,WD_SOURCE_ID, SRCID_ER);
+DB(DB_INTR,printk("DISC-%ld",cmd->pid))
+         if (cmd == NULL) {
+            printk(" - Already disconnected! ");
+            hostdata->state = S_UNCONNECTED;
+            }
          switch (hostdata->state) {
             case S_PRE_CMP_DISC:
                hostdata->connected = NULL;
@@ -912,7 +1133,7 @@ DB(DB_INTR,printk("DISC"))
                   cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
                else if (cmd->SCp.Status != GOOD)
                   cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
-               cmd->scsi_done(cmd);    /* I think scsi_done() enables ints */
+               cmd->scsi_done(cmd);
                break;
             case S_PRE_TMP_DISC:
             case S_RUNNING_LEVEL2:
@@ -920,6 +1141,11 @@ DB(DB_INTR,printk("DISC"))
                hostdata->disconnected_Q = cmd;
                hostdata->connected = NULL;
                hostdata->state = S_UNCONNECTED;
+
+#ifdef PROC_INTERFACE
+               disc_taken_total++;
+#endif
+
                break;
             default:
                printk("*** Unexpected DISCONNECT interrupt! ***");
@@ -943,7 +1169,7 @@ DB(DB_INTR,printk("RESEL"))
    /* happen during Arbitration/Selection of some other device. */
    /* If yes, put losing command back on top of input_Q. */
 
-         if (hostdata->level2 == L2_NONE) {
+         if (hostdata->level2 <= L2_NONE) {
 
             if (hostdata->selecting) {
                cmd = (Scsi_Cmnd *)hostdata->selecting;
@@ -971,7 +1197,7 @@ DB(DB_INTR,printk("RESEL"))
 
             }
 
-   /* OK - find out which device reslected us. */
+   /* OK - find out which device reselected us. */
 
          id = read_wd33c93(regp, WD_SOURCE_ID);
          id &= SRCID_MASK;
@@ -1034,9 +1260,11 @@ DB(DB_INTR,printk("-%ld",cmd->pid))
          break;
          
       default:
-         printk("\n---UNKNOWN INTERRUPT:%02x:%02x:%02x!!---",asr,sr,phs);
+         printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--",asr,sr,phs);
       }
 
+   restore_flags(flags);
+
 DB(DB_INTR,printk("} "))
 
 }
@@ -1056,7 +1284,7 @@ uchar sr;
                  instance->this_id | hostdata->clock_freq);
    write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
    write_wd33c93(regp, WD_SYNCHRONOUS_TRANSFER,
-                 calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF));
+                 calc_sync_xfer(hostdata->default_sx_per/4,DEFAULT_SX_OFF));
    write_wd33c93(regp, WD_COMMAND, WD_CMD_RESET);
 
    while (!(READ_AUX_STAT() & ASR_INT))
@@ -1080,26 +1308,44 @@ uchar sr;
       hostdata->chip = C_UNKNOWN_CHIP;
 
    write_wd33c93(regp, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE);
-   if (hostdata->args & A_NO_DISCONNECT)
-      write_wd33c93(regp, WD_SOURCE_ID, 0);
-   else
-      write_wd33c93(regp, WD_SOURCE_ID, SRCID_ER);
    write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
 }
 
 
 
+#if LINUX_VERSION_CODE >= 0x010300
+int wd33c93_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+#else
 int wd33c93_reset(Scsi_Cmnd *SCpnt)
+#endif
 {
 unsigned long flags;
 struct Scsi_Host *instance;
+struct WD33C93_hostdata *hostdata;
+int i;
 
    instance = SCpnt->host;
+   hostdata = (struct WD33C93_hostdata *)instance->hostdata;
 
    printk("scsi%d: reset. ", instance->host_no);
    save_flags(flags);
    cli();
+
    ((struct WD33C93_hostdata *)instance->hostdata)->dma_stop(instance,NULL,0);
+   for (i = 0; i < 8; i++) {
+      hostdata->busy[i] = 0;
+      hostdata->sync_xfer[i] = calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF);
+      hostdata->sync_stat[i] = SS_UNSET;  /* using default sync values */
+      }
+   hostdata->input_Q = NULL;
+   hostdata->selecting = NULL;
+   hostdata->connected = NULL;
+   hostdata->disconnected_Q = NULL;
+   hostdata->state = S_UNCONNECTED;
+   hostdata->dma = D_DMA_OFF;
+   hostdata->incoming_ptr = 0;
+   hostdata->outgoing_len = 0;
+
    reset_wd33c93(instance);
    SCpnt->result = DID_RESET << 16;
    restore_flags(flags);
@@ -1113,38 +1359,41 @@ int wd33c93_abort (Scsi_Cmnd *cmd)
 struct Scsi_Host *instance;
 struct WD33C93_hostdata *hostdata;
 wd33c93_regs *regp;
-Scsi_Cmnd *tmp, **prev;
+Scsi_Cmnd *tmp, *prev;
 unsigned long flags;
 
+   save_flags (flags);
+   cli();
+
    instance = cmd->host;
    hostdata = (struct WD33C93_hostdata *)instance->hostdata;
    regp = hostdata->regp;
 
-   printk ("scsi%d: abort. ", instance->host_no);
-
-   save_flags (flags);
-   cli();
-
 /*
  * Case 1 : If the command hasn't been issued yet, we simply remove it
- *     from the issue queue.
+ *     from the input_Q.
  */
-   for (prev=(Scsi_Cmnd **)&(hostdata->input_Q),tmp=(Scsi_Cmnd *)hostdata->input_Q;
-         tmp;
-         prev=(Scsi_Cmnd **)&(tmp->host_scribble),tmp=(Scsi_Cmnd *)tmp->host_scribble)
-      if (cmd == tmp) {
-         (*prev) = (Scsi_Cmnd *)tmp->host_scribble;
-         tmp->host_scribble = NULL;
-         tmp->result = DID_ABORT << 16;
+
+   tmp = (Scsi_Cmnd *)hostdata->input_Q;
+   prev = 0;
+   while (tmp) {
+      if (tmp == cmd) {
+         if (prev)
+            prev->host_scribble = cmd->host_scribble;
+         cmd->host_scribble = NULL;
+         cmd->result = DID_ABORT << 16;
+         printk("scsi%d: Abort - removing command %ld from input_Q. ",
+           instance->host_no, cmd->pid);
+         cmd->scsi_done(cmd);
          restore_flags(flags);
-         printk("scsi%d : abort removed command from issue queue. ",
-           instance->host_no);
-         tmp->scsi_done(tmp);
          return SCSI_ABORT_SUCCESS;
          }
+      prev = tmp;
+      tmp = (Scsi_Cmnd *)tmp->host_scribble;
+      }
 
 /*
- * Case 2 : If any commands are connected, we're going to fail the abort
+ * Case 2 : If the command is connected, we're going to fail the abort
  *     and let the high level SCSI driver retry at a later time or
  *     issue a reset.
  *
@@ -1158,20 +1407,22 @@ unsigned long flags;
       uchar sr, asr;
       unsigned long timeout;
 
-      printk("scsi%d : aborting connected command. ", instance->host_no);
+      printk("scsi%d: Aborting connected command %ld - ",
+              instance->host_no, cmd->pid);
 
+      printk("stopping DMA - ");
       if (hostdata->dma == D_DMA_RUNNING) {
          hostdata->dma_stop(instance, cmd, 0);
          hostdata->dma = D_DMA_OFF;
          }
 
-         printk("scsi%d : wd33c93 asr is %x. ", instance->host_no, READ_AUX_STAT());
-
+      printk("sending wd33c93 ABORT command - ");
       write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
       write_wd33c93_cmd(regp, WD_CMD_ABORT);
 
 /* Now we have to attempt to flush out the FIFO... */
 
+      printk("flushing fifo - ");
       timeout = 1000000;
       do {
          asr = READ_AUX_STAT();
@@ -1179,46 +1430,34 @@ unsigned long flags;
             read_wd33c93(regp, WD_DATA);
          } while (!(asr & ASR_INT) && timeout-- > 0);
       sr = read_wd33c93(regp, WD_SCSI_STATUS);
-      printk("scsi%d : wd33c93 sr is %x. ", instance->host_no,
-         read_wd33c93(regp, WD_SCSI_STATUS));
+      printk("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ",
+             asr, sr, read_wd33c93_count(regp), timeout);
 
-      if (sr >= (CSR_ABORT|PHS_DATA_OUT) && sr <= (CSR_ABORT|PHS_MESS_IN)) {
    /*
     * Abort command processed.
     * Still connected.
     * We must disconnect.
     */
-         printk("scsi%d : count was %ld. ", instance->host_no,
-            read_wd33c93_count(regp));
 
-         timeout = 1000000;
-         while ((asr & ASR_CIP) && timeout-- > 0)
-            asr = READ_AUX_STAT();
-         write_wd33c93_cmd(regp, WD_CMD_DISCONNECT);
-         asr = READ_AUX_STAT();
-         if (asr & ASR_LCI)
-            printk ("scsi%d: disconnect command ignored. ",
-               instance->host_no);
-         timeout = 1000000;
-         while ((asr & ASR_CIP) && timeout-- > 0)
-            asr = READ_AUX_STAT();
-         }
-      asr = READ_AUX_STAT();
-      sr = read_wd33c93(regp, WD_SCSI_STATUS);
-      printk("scsi%d : asr is %x, sr is %x. ",instance->host_no,asr,sr);
+      printk("sending wd33c93 DISCONNECT command - ");
       write_wd33c93_cmd(regp, WD_CMD_DISCONNECT);
+
       timeout = 1000000;
+      asr = READ_AUX_STAT();
       while ((asr & ASR_CIP) && timeout-- > 0)
          asr = READ_AUX_STAT();
       sr = read_wd33c93(regp, WD_SCSI_STATUS);
-      printk("scsi%d : asr is %x, sr is %x. ",instance->host_no,asr,sr);
-      reset_wd33c93(instance);
-      cmd->result = DID_ABORT << 16;
-      cmd->scsi_done(cmd);
+      printk("asr=%02x, sr=%02x.",asr,sr);
+
       hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
       hostdata->connected = NULL;
       hostdata->state = S_UNCONNECTED;
+      cmd->result = DID_ABORT << 16;
+      cmd->scsi_done(cmd);
+
+/*      sti();*/
       wd33c93_execute (instance);
+
       restore_flags(flags);
       return SCSI_ABORT_SUCCESS;
       }
@@ -1229,12 +1468,17 @@ unsigned long flags;
  * an ABORT_SNOOZE and hope for the best...
  */
 
-   for (tmp=(Scsi_Cmnd *)hostdata->disconnected_Q; tmp;
-         tmp=(Scsi_Cmnd *)tmp->host_scribble)
-      if (cmd == tmp) {
+   tmp = (Scsi_Cmnd *)hostdata->disconnected_Q;
+   while (tmp) {
+      if (tmp == cmd) {
+         printk("scsi%d: Abort - command %ld found on disconnected_Q - ",
+                 instance->host_no, cmd->pid);
+         printk("returning ABORT_SNOOZE. ");
          restore_flags(flags);
          return SCSI_ABORT_SNOOZE;
          }
+      tmp = (Scsi_Cmnd *)tmp->host_scribble;
+      }
 
 /*
  * Case 4 : If we reached this point, the command was not found in any of
@@ -1242,29 +1486,101 @@ unsigned long flags;
  *
  * We probably reached this point because of an unlikely race condition
  * between the command completing successfully and the abortion code,
- * so we won't panic, but we will notify the user in case somethign really
+ * so we won't panic, but we will notify the user in case something really
  * broke.
  */
 
+/*   sti();*/
+   wd33c93_execute (instance);
+
    restore_flags(flags);
-   printk("scsi%d : warning : SCSI command probably completed successfully\n"
+   printk("scsi%d: warning : SCSI command probably completed successfully"
       "         before abortion. ", instance->host_no);
    return SCSI_ABORT_NOT_RUNNING;
 }
 
 
 
-#define MAX_WD33C93_HOSTS 8
-static unsigned int setup_args_array[MAX_WD33C93_HOSTS];
-static int setup_args_array_x = 0;
+#define MAX_WD33C93_HOSTS 4
+#define MAX_SETUP_STRINGS (sizeof(setup_strings) / sizeof(char *))
+#define SETUP_BUFFER_SIZE 200
+static char setup_buffer[SETUP_BUFFER_SIZE];
+static char setup_used[MAX_SETUP_STRINGS];
 
 void wd33c93_setup (char *str, int *ints)
 {
-int i;
+int i,x;
+char *p1,*p2;
+
+   /* The kernel does some processing of the command-line before calling
+    * this function: If it begins with any decimal or hex number arguments,
+    * ints[0] = how many numbers found and ints[1] through [n] are the values
+    * themselves. str points to where the non-numeric arguments (if any)
+    * start: We do our own parsing of those. We construct synthetic 'nosync'
+    * keywords out of numeric args (to maintain compatibility with older
+    * versions) and then add the rest of the arguments.
+    */
+
+   p1 = setup_buffer;
+   *p1 = '\0';
+   if (ints[0]) {
+      for (i=0; i<ints[0]; i++) {
+         x = vsprintf(p1,"nosync:0x%02x,",&(ints[i+1]));
+         p1 += x;
+         }
+      }
+   if (str)
+      strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer));
+   setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
+   p1 = setup_buffer;
+   i = 0;
+   while (*p1 && (i < MAX_SETUP_STRINGS)) {
+      p2 = strchr(p1, ',');
+      if (p2) {
+         *p2 = '\0';
+         if (p1 != p2)
+            setup_strings[i] = p1;
+         p1 = p2 + 1;
+         i++;
+         }
+      else {
+         setup_strings[i] = p1;
+         break;
+         }
+      }
+   for (i=0; i<MAX_SETUP_STRINGS; i++)
+      setup_used[i] = 0;
+}
+
+
+/* check_setup_strings() returns index if key found, 0 if not
+ */
+
+int check_setup_strings(char *key, int *flags, int *val, char *buf)
+{
+int x;
+char *cp;
 
-   for (i=0; i<ints[0]; i++) {
-      setup_args_array[i] = ints[i+1];
+   for  (x=0; x<MAX_SETUP_STRINGS; x++) {
+      if (setup_used[x])
+         continue;
+      if (!strncmp(setup_strings[x], key, strlen(key)))
+         break;
+      if (!strncmp(setup_strings[x], "next", strlen("next")))
+         return 0;
+      }
+   if (x == MAX_SETUP_STRINGS)
+      return 0;
+   setup_used[x] = 1;
+   cp = setup_strings[x] + strlen(key);
+   *val = -1;
+   if (*cp != ':')
+      return ++x;
+   cp++;
+   if ((*cp >= '0') && (*cp <= '9')) {
+      *val = simple_strtoul(cp,NULL,0);
       }
+   return ++x;
 }
 
 
@@ -1274,6 +1590,9 @@ void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs,
 {
 struct WD33C93_hostdata *hostdata;
 int i;
+int flags;
+int val;
+char buf[32];
 
    hostdata = (struct WD33C93_hostdata *)instance->hostdata;
 
@@ -1294,46 +1613,226 @@ int i;
    hostdata->disconnected_Q = NULL;
    hostdata->state = S_UNCONNECTED;
    hostdata->dma = D_DMA_OFF;
+   hostdata->level2 = L2_BASIC;
+   hostdata->disconnect = DIS_ADAPTIVE;
+   hostdata->args = DEBUG_DEFAULTS;
    hostdata->incoming_ptr = 0;
    hostdata->outgoing_len = 0;
+   hostdata->default_sx_per = DEFAULT_SX_PER;
+   hostdata->no_sync = 0xff;     /* sync defaults to off */
+
+#ifdef PROC_INTERFACE
+   hostdata->proc = PR_VERSION|PR_INFO|PR_TOTALS|
+                    PR_CONNECTED|PR_INPUTQ|PR_DISCQ|
+                    PR_STOP;
+
+   disc_allowed_total = 0;
+   disc_taken_total = 0;
+#endif
+
 
-   hostdata->args = setup_default;
-   if ((setup_args_array_x < MAX_WD33C93_HOSTS) &&
-       (setup_args_array[setup_args_array_x]))
-      hostdata->args = setup_args_array[setup_args_array_x];
-   setup_args_array_x++;
+   if (check_setup_strings("nosync",&flags,&val,buf))
+      hostdata->no_sync = val;
+
+   if (check_setup_strings("period",&flags,&val,buf))
+      hostdata->default_sx_per = sx_table[round_period((unsigned int)val)].period_ns;
+
+   if (check_setup_strings("disconnect",&flags,&val,buf)) {
+      if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS))
+         hostdata->disconnect = val;
+      else
+         hostdata->disconnect = DIS_ADAPTIVE;
+      }
+
+   if (check_setup_strings("debug",&flags,&val,buf))
+      hostdata->args = val & DB_MASK;
+
+   if (check_setup_strings("clock",&flags,&val,buf)) {
+      if (val>7 && val<11)
+         val = WD33C93_FS_8_10;
+      else if (val>11 && val<16)
+         val = WD33C93_FS_12_15;
+      else if (val>15 && val<21)
+         val = WD33C93_FS_16_20;
+      else
+         val = WD33C93_FS_8_10;
+      hostdata->clock_freq = val;
+      }
+
+   if ((i = check_setup_strings("next",&flags,&val,buf))) {
+      while (i)
+         setup_used[--i] = 1;
+      }
+
+#ifdef PROC_INTERFACE
+   if (check_setup_strings("proc",&flags,&val,buf))
+      hostdata->proc = val;
+#endif
 
-   i = hostdata->args & (A_LEVEL2_0 | A_LEVEL2_1 | A_LEVEL2_2);
-   i >>= 8;
-   if (i == 0)
-      i = L2_DEFAULT;
-   hostdata->level2 = i;
 
    cli();
    reset_wd33c93(instance);
    sti();
 
-   printk("wd33c93-%d: ",instance->host_no);
-   switch (hostdata->chip) {
-      case C_WD33C93:
-         printk("Found WD33c93 chip! This driver probably needs at least the 'A' version!\n");
-         break;
-      case C_WD33C93A:
-         printk("Found WD33c93A chip: microcode=%02x\n",hostdata->microcode);
-         break;
-      case C_WD33C93B:
-         printk("Found WD33c93B chip: microcode=%02x\n",hostdata->microcode);
-         break;
-      default:
-         printk("Unknown 3393 chip!\n");
-      }
-   printk("wd33c93-%d: LEVEL2 commands %s (%d)\n",instance->host_no,
-            (hostdata->level2 == L2_NONE)?"disabled":"enabled",
-            hostdata->level2);
+   printk("wd33c93-%d: chip=%s microcode=%02x\n",instance->host_no,
+         (hostdata->chip==C_WD33C93)?"WD33c93":
+         (hostdata->chip==C_WD33C93A)?"WD33c93A":
+         (hostdata->chip==C_WD33C93B)?"WD33c93B":"unknown",
+         hostdata->microcode);
+
 #ifdef DEBUGGING_ON
+   printk("wd33c93-%d: setup_strings=",instance->host_no);
+   for (i=0; i<MAX_SETUP_STRINGS; i++)
+      printk("%s,",setup_strings[i]);
+   printk("\n");
    printk("wd33c93-%d: debug_flags = %04x\n",instance->host_no,hostdata->args);
 #endif
    printk("wd33c93-%d: driver version %s - %s\n",instance->host_no,
                      WD33C93_VERSION,WD33C93_DATE);
+   printk("wd33c93-%d: compiled on %s at %s\n",instance->host_no,
+                     __DATE__,__TIME__);
+}
+
+
+int wd33c93_proc_info(char *buf, char **start, off_t off, int len, int hn, int in)
+{
+
+#ifdef PROC_INTERFACE
+
+char *bp;
+char tbuf[128];
+unsigned long flags;
+struct Scsi_Host *instance;
+struct WD33C93_hostdata *hd;
+Scsi_Cmnd *cmd;
+int x,i;
+static int stop = 0;
+
+   for (instance=instance_list; instance; instance=instance->next) {
+      if (instance->host_no == hn)
+         break;
+      }
+   if (!instance) {
+      printk("*** Hmm... Can't find host #%d!\n",hn);
+      return (-ESRCH);
+      }
+   hd = (struct WD33C93_hostdata *)instance->hostdata;
+
+/* If 'in' is TRUE we need to _read_ the proc file. We accept the following
+ * keywords (same format as command-line, but only ONE per read):
+ *    debug
+ *    disconnect
+ *    period
+ *    resync
+ *    proc
+ */
+
+   if (in) {
+      buf[len] = '\0';
+      bp = buf;
+      if (!strncmp(bp,"debug:",6)) {
+         bp += 6;
+         hd->args = simple_strtoul(bp,NULL,0) & DB_MASK;
+         }
+      else if (!strncmp(bp,"disconnect:",11)) {
+         bp += 11;
+         x = simple_strtoul(bp,NULL,0);
+         if (x < DIS_NEVER || x > DIS_ALWAYS)
+            x = DIS_ADAPTIVE;
+         hd->disconnect = x;
+         }
+      else if (!strncmp(bp,"period:",7)) {
+         bp += 7;
+         x = simple_strtoul(bp,NULL,0);
+         hd->default_sx_per = sx_table[round_period((unsigned int)x)].period_ns;
+         }
+      else if (!strncmp(bp,"resync:",7)) {
+         bp += 7;
+         x = simple_strtoul(bp,NULL,0);
+         for (i=0; i<7; i++)
+            if (x & (1<<i))
+               hd->sync_stat[i] = SS_UNSET;
+         }
+      else if (!strncmp(bp,"proc:",5)) {
+         bp += 5;
+         hd->proc = simple_strtoul(bp,NULL,0);
+         }
+      return len;
+      }
+
+   save_flags(flags);
+   cli();
+   bp = buf;
+   *bp = '\0';
+   if (hd->proc & PR_VERSION) {
+      sprintf(tbuf,"\nVersion %s - %s. Compiled %s %s",
+            WD33C93_VERSION,WD33C93_DATE,__DATE__,__TIME__);
+      strcat(bp,tbuf);
+      }
+   if (hd->proc & PR_INFO) {
+      ;
+      }
+   if (hd->proc & PR_TOTALS) {
+      sprintf(tbuf,"\n%ld disc_allowed, %ld disc_taken",
+            disc_allowed_total,disc_taken_total);
+      strcat(bp,tbuf);
+      }
+   if (hd->proc & PR_CONNECTED) {
+      strcat(bp,"\nconnected:     ");
+      if (hd->connected) {
+         cmd = (Scsi_Cmnd *)hd->connected;
+         sprintf(tbuf," %ld-%d:%d(%02x)",
+               cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]);
+         strcat(bp,tbuf);
+         }
+      }
+   if (hd->proc & PR_INPUTQ) {
+      strcat(bp,"\ninput_Q:       ");
+      cmd = (Scsi_Cmnd *)hd->input_Q;
+      while (cmd) {
+         sprintf(tbuf," %ld-%d:%d(%02x)",
+               cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]);
+         strcat(bp,tbuf);
+         cmd = (Scsi_Cmnd *)cmd->host_scribble;
+         }
+      }
+   if (hd->proc & PR_DISCQ) {
+      strcat(bp,"\ndisconnected_Q:");
+      cmd = (Scsi_Cmnd *)hd->disconnected_Q;
+      while (cmd) {
+         sprintf(tbuf," %ld-%d:%d(%02x)",
+               cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]);
+         strcat(bp,tbuf);
+         cmd = (Scsi_Cmnd *)cmd->host_scribble;
+         }
+      }
+   strcat(bp,"\n");
+   restore_flags(flags);
+   *start = buf;
+   if (stop) {
+      stop = 0;
+      return 0;
+      }
+   if (off > 0x40000)   /* ALWAYS stop after 256k bytes have been read */
+      stop = 1;;
+   if (hd->proc & PR_STOP)    /* stop every other time */
+      stop = 1;
+   return strlen(bp);
+
+#else    /* PROC_INTERFACE */
+
+   return 0;
+
+#endif   /* PROC_INTERFACE */
+
 }
 
+
+#ifdef MODULE
+
+Scsi_Host_Template driver_template = WD33C93;
+
+#include "scsi_module.c"
+
+#endif
+
index 4436badc85e401fca3b49e3428b0bbfa5326bdaf..5dcdc13af2b96f6f171482d20056196f8dbb69d9 100644 (file)
@@ -1,10 +1,9 @@
-#ifndef WD33C93_H
-#define WD33C93_H
-
 /*
  *    wd33c93.h -  Linux device driver definitions for the
  *                 Commodore Amiga A2091/590 SCSI controller card
  *
+ *    IMPORTANT: This file is for version 1.21 - 20/Mar/1996
+ *
  * Copyright (c) 1996 John Shifflett, GeoLog Consulting
  *    john@geolog.com
  *    jshiffle@netcom.com
@@ -21,6 +20,8 @@
  *
  */
 
+#ifndef WD33C93_H
+#define WD33C93_H
 
 
 #define uchar unsigned char
 #define CTRL_DMA     0x80
 
    /* Timeout Period register */
-#define TIMEOUT_PERIOD_VALUE  20    /* results in 200 ms. */
+#define TIMEOUT_PERIOD_VALUE  20    /* 20 = 200 ms */
 
    /* Synchronous Transfer Register */
 #define STR_FSS      0x80
@@ -193,18 +194,23 @@ struct sx_period {
    uchar          reg_value;
    };
 
+/* FEF: defines for hostdata->dma_buffer_pool */
+
+#define BUF_CHIP_ALLOCED 0
+#define BUF_SCSI_ALLOCED 1
 
 struct WD33C93_hostdata {
     struct Scsi_Host *next;
     wd33c93_regs     *regp;
     uchar            clock_freq;
     uchar            chip;             /* what kind of wd33c93? */
-    uchar            microcode;        /* microcode rev if 'B' */
+    uchar            microcode;        /* microcode rev */
     int              dma_dir;          /* data transfer dir. */
     dma_setup_t      dma_setup;
     dma_stop_t       dma_stop;
     uchar            *dma_bounce_buffer;
     unsigned int     dma_bounce_len;
+    uchar            dma_buffer_pool;  /* FEF: buffer from chip_ram? */
     volatile uchar   busy[8];          /* index = target, bit = lun */
     volatile Scsi_Cmnd *input_Q;       /* commands waiting to be started */
     volatile Scsi_Cmnd *selecting;     /* trying to select this command */
@@ -213,13 +219,19 @@ struct WD33C93_hostdata {
     uchar            state;            /* what we are currently doing */
     uchar            dma;              /* current state of DMA (on/off) */
     uchar            level2;           /* extent to which Level-2 commands are used */
+    uchar            disconnect;       /* disconnect/reselect policy */
     unsigned int     args;             /* set from command-line argument */
     uchar            incoming_msg[8];  /* filled during message_in phase */
     int              incoming_ptr;     /* mainly used with EXTENDED messages */
     uchar            outgoing_msg[8];  /* send this during next message_out */
     int              outgoing_len;     /* length of outgoing message */
+    unsigned int     default_sx_per;   /* default transfer period for SCSI bus */
     uchar            sync_xfer[8];     /* sync_xfer reg settings per target */
     uchar            sync_stat[8];     /* status of sync negotiation per target */
+    uchar            no_sync;          /* bitmask: don't do sync on these targets */
+#if 0
+    uchar            proc;             /* bitmask: what's in proc output */
+#endif
     };
 
 
@@ -245,34 +257,31 @@ struct WD33C93_hostdata {
 #define D_DMA_RUNNING      1
 
 /* defines for hostdata->level2 */
-/* NOTE: only the first 3 are implemented so far - having trouble
- * when more than 1 device is reading/writing at the same time...
- */
+/* NOTE: only the first 3 are implemented so far */
 
-#define L2_NONE      1  /* no combination commands - we get lots of ints */
+/*  (The first 8 bits are reserved for compatibility. They function
 #define L2_SELECT    2  /* start with SEL_ATN_XFER, but never resume it */
 #define L2_BASIC     3  /* resume after STATUS ints & RDP messages */
 #define L2_DATA      4  /* resume after DATA_IN/OUT ints */
 #define L2_MOST      5  /* resume after anything except a RESELECT int */
 #define L2_RESELECT  6  /* resume after everything, including RESELECT ints */
 #define L2_ALL       7  /* always resume */
-#define L2_DEFAULT   L2_BASIC
 
-/* defines for hostdata->args */
-/*  (The first 8 bits are reserved for compatability. They function
- *   as they did in the old driver - note that turning off sync_xfer
- *   on a target affects all LUNs at that SCSI id.)
- */
+/* defines for hostdata->disconnect */
+
+#define DIS_NEVER    0
+#define DIS_ADAPTIVE 1
+#define DIS_ALWAYS   2
 
-#define A_LEVEL2_0            1<<8
-#define A_LEVEL2_1            1<<9
-#define A_LEVEL2_2            1<<10
-#define A_NO_DISCONNECT       1<<11
+/* defines for hostdata->args */
 
-#define DB_QUEUE_COMMAND      1<<12
-#define DB_EXECUTE            1<<13
-#define DB_INTR               1<<14
-#define DB_TRANSFER_DATA      1<<15
+#define DB_TEST1              1<<0
+#define DB_TEST2              1<<1
+#define DB_QUEUE_COMMAND      1<<2
+#define DB_EXECUTE            1<<3
+#define DB_INTR               1<<4
+#define DB_TRANSFER           1<<5
+#define DB_MASK               0x3f
 
 /* defines for hostdata->sync_stat[] */
 
@@ -281,12 +290,33 @@ struct WD33C93_hostdata {
 #define SS_WAITING   2
 #define SS_SET       3
 
+/* defines for hostdata->proc */
+
+#define PR_VERSION   1<<0
+#define PR_INFO      1<<1
+#define PR_TOTALS    1<<2
+#define PR_CONNECTED 1<<3
+#define PR_INPUTQ    1<<4
+#define PR_DISCQ     1<<5
+#define PR_TEST      1<<6
+#define PR_STOP      1<<7
+
 
 void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs,
          dma_setup_t setup, dma_stop_t stop, int clock_freq);
 int wd33c93_abort (Scsi_Cmnd *cmd);
-int wd33c93_reset (Scsi_Cmnd *);
 int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
 void wd33c93_intr (struct Scsi_Host *instance);
+int wd33c93_proc_info(char *, char **, off_t, int, int, int);
+
+#if LINUX_VERSION_CODE >= 0x010300
+int wd33c93_reset (Scsi_Cmnd *, unsigned int);
+#else
+int wd33c93_reset (Scsi_Cmnd *);
+#endif
+
+#if 0
+struct proc_dir_entry proc_scsi_wd33c93;
+#endif
 
 #endif /* WD33C93_H */
index 7ad74e135cd7039215b22e4b7fcf26b035752759..13f76b6b199387dbea25c9fdc0e0a1ab8db53a99 100644 (file)
@@ -475,7 +475,7 @@ typedef struct {
 } TRANS;
 
 struct sound_settings {
-    MACHINE mach;      /* machine dependend things */
+    MACHINE mach;      /* machine dependent things */
     SETTINGS hard;     /* hardware settings */
     SETTINGS soft;     /* software settings */
     SETTINGS dsp;      /* /dev/dsp default settings */
@@ -676,11 +676,11 @@ void sound_setup(char *str, int *ints);           /* ++Martin: stub for now */
  * I think I've optimized anything as far as one can do in plain C, all
  * variables should fit in registers and the loops are really short. There's
  * one loop for every possible situation. Writing a more generalized and thus
- * parametrized loop would only produce slower code. Feel free to optimize
+ * parameterized loop would only produce slower code. Feel free to optimize
  * this in assembler if you like. :)
  *
  * I think these routines belong here because they're not yet really hardware
- * independend, especially the fact that the Falcon can play 16bit samples
+ * independent, especially the fact that the Falcon can play 16bit samples
  * only in stereo is hardcoded in both of them!
  *
  * ++geert: split in even more functions (one per format)
@@ -1872,7 +1872,7 @@ static void AtaPlay(void)
      * than considering all possible situations. But the point is that
      * disabling the irq doesn't have any bad influence on this version of
      * the driver as we benefit from having pre-programmed the DMA
-     * whereever possible: There's no need to reload the DMA at the exact
+     * wherever possible: There's no need to reload the DMA at the exact
      * time of an interrupt but only at some time while the pre-programmed
      * frame is playing!
      */
@@ -2755,7 +2755,7 @@ static int sq_sync(void)
     while (sq.playing) {
        SLEEP(sq.sync_queue, ONE_SECOND);
        if (SIGNAL_RECEIVED) {
-           /* While waiting for audio output to drain, an interrupt occured.
+           /* While waiting for audio output to drain, an interrupt occurred.
               Stop audio output immediately and clear the queue. */
            sq_reset();
            rc = -EINTR;
@@ -2775,7 +2775,7 @@ static int sq_release(void)
        rc = sq_sync();
        sq.busy = 0;
        WAKE_UP(sq.open_queue);
-       /* Wake up a process waiting for the queue beeing released.
+       /* Wake up a process waiting for the queue being released.
           Note: There may be several processes waiting for a call to open()
                 returning. */
     }
index 3816fb1935f593f3d979a3a5a01ddebab32c87de..0447a9c5da445f71df29910a4a4fa32705af9a19 100644 (file)
@@ -34,6 +34,10 @@ fi
 tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS
 tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS
 tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
-bool 'AFFS filesystem support' CONFIG_AFFS_FS
-bool 'UFS filesystem support (read only)' CONFIG_UFS_FS
+tristate 'AFFS filesystem support (read only)' CONFIG_AFFS_FS
+tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS
+if [ "$CONFIG_UFS_FS" != "n" ]; then
+  bool "BSD disklabel (FreeBSD partition tables) support" CONFIG_BSD_DISKLABEL
+  bool "SMD disklabel (Sun partition tables) support" CONFIG_SMD_DISKLABEL
+fi
 endmenu
index c58ab034d96145c387f233766d02a018d438ea0d..5ec162671d61abaab059c78d85fdd5cce09d240f 100644 (file)
@@ -143,10 +143,18 @@ endif
 
 ifeq ($(CONFIG_UFS_FS),y)
 SUB_DIRS += ufs
+else
+  ifeq ($(CONFIG_UFS_FS),m)
+  MOD_SUB_DIRS += ufs
+  endif
 endif
 
 ifeq ($(CONFIG_AFFS_FS),y)
 SUB_DIRS += affs
+else
+  ifeq ($(CONFIG_AFFS_FS),m)
+  MOD_SUB_DIRS += affs
+  endif
 endif
 
 ifeq ($(CONFIG_BINFMT_ELF),y)
index 6443a63035f61a89f8b4cfed489dd37b884e3dc9..0a0ce359ec8541c81064784db7b949939fcabeff 100644 (file)
@@ -1,10 +1,15 @@
 /*
  *  linux/fs/affs/amigaffs.c
  *
+ *  (C) 1996  Stefan Reinauer - Modified to compile as Module
+ *
  *  (C) 1993  Ray Burr - Amiga FFS filesystem.
  *
  */
 
+
+#include <linux/module.h>
+
 #include <linux/fs.h>
 #include <linux/affs_fs.h>
 #include <linux/mm.h>
@@ -91,7 +96,7 @@ int affs_get_file_name (int bsize, void *fh_data, char **name)
         return file_end->file_name[0];
 }
 
-/* Get the key number of the first extention block for the file
+/* Get the key number of the first extension block for the file
    header pointed to by FH_DATA. */
 
 int affs_get_extension (int bsize, void *fh_data)
@@ -128,3 +133,20 @@ int init_affs_fs(void)
         return register_filesystem(&affs_fs_type);
 }
 
+#ifdef MODULE
+int init_module(void)
+{
+       int status;
+
+       if ((status = init_affs_fs()) == 0)
+               register_symtab(0);
+       return status;
+}
+
+void cleanup_module(void)
+{
+       unregister_filesystem(&affs_fs_type);
+}
+
+#endif
+
index c8c2b62699576e40aa570c7791bf311e06ec0acd..457a32c90a4b7fcdaebe92842b8be8f50aa60e94 100644 (file)
@@ -180,7 +180,7 @@ struct hardlink_front
   LONG primary_type;
   ULONG own_key;
   LONG unused[3];
-  ULONG checkksum;
+  ULONG checksum;
 };
 
 struct hardlink_end
index 5afc42c8434605b4ab8adc1cb2d5cd44d89b69f9..50f126e7ee49ce53e41b8b64ba97ce1f998981a6 100644 (file)
@@ -115,7 +115,7 @@ static int affs_smap(struct inode *inode, int block)
 /*
  * affs_file_read() is also needed by the directory read-routine,
  * so it's not static. NOTE! reading directories directly is a bad idea,
- * but has to be supported for now for compatability reasons with older
+ * but has to be supported for now for compatibility reasons with older
  * versions.
  */
 int affs_file_read(struct inode * inode, struct file * filp,
index 23acfe0b2a4fdb198dcd38d20522acbfc1fa1601..82ed07cce2739363f2b87ba7ce6bfe8ae8287e84 100644 (file)
@@ -294,7 +294,7 @@ void affs_read_inode(struct inode * inode)
                }
 
                file_front = (struct file_front *) fh_data;
-               file_end = GET_END_PTR (struct file_end, fh_data, /* coincidendly the same as  dir_end */
+               file_end = GET_END_PTR (struct file_end, fh_data, /* coincidently the same as  dir_end */
                                        AFFS_I2BSIZE (inode));
 
                /* don't use bitmap data for mode, uid & gid of the rootblock */
@@ -305,7 +305,7 @@ void affs_read_inode(struct inode * inode)
                        inode->i_mode = S_IRWXUGO | S_IFDIR | S_ISVTX ;  /* drwxrwxrwt */
                        inode->i_nlink = 2; /* at least ..... */
 
-                       inode->i_size = 0;  /* some differrent idea ? */
+                       inode->i_size = 0;  /* some different idea ? */
 
                        inode->i_uid = 0;
                        inode->i_gid = 0;
@@ -340,7 +340,7 @@ void affs_read_inode(struct inode * inode)
                                     probably spend some time on this */
                                        link_end = (struct hardlink_end *)file_end;
                                        inode->i_ino = link_end->original;
-                                       inode->i_nlink += 2; /* It's hard to say whats correct */
+                                       inode->i_nlink += 2; /* It's hard to say what's correct */
                                        brelse(bh);
                                        link = 1;
                                break;
index e66d3e17cc97e5f4ffab71be2a7f1295fd030e10..c8dc68deb07f9d83cf3e4bc1224bd40a1af683ec 100644 (file)
@@ -227,7 +227,7 @@ static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm)
        envp = sp;
        sp -= argc+1;
        argv = sp;
-#ifdef __i386__
+#if defined(__i386__) || defined(__mc68000__)
        put_user(envp,--sp);
        put_user(argv,--sp);
 #endif
index 241698709aabaca0e4e85076a5f85e6946158bb6..bd2c299a6c6dca07a315a45bf81447420c33cb3e 100644 (file)
@@ -211,7 +211,7 @@ static int sync_buffers(kdev_t dev, int wait)
                                 printk("[%d %s %ld] ", nlist,
                                        kdevname(bh->b_dev), bh->b_blocknr);
                                 ncount++;
-                        };
+                        }
                         bh->b_count--;
                         retry = 1;
                 }
@@ -373,7 +373,7 @@ static inline void remove_from_queues(struct buffer_head * bh)
                remove_from_free_list(bh); /* Free list entries should not be
                                              in the hash queue */
                return;
-       };
+       }
        nr_buffers_type[bh->b_list]--;
        nr_buffers_st[BUFSIZE_INDEX(bh->b_size)][bh->b_list]--;
        remove_from_hash_queue(bh);
@@ -420,7 +420,7 @@ static inline void put_last_free(struct buffer_head * bh)
        if(!free_list[isize]) {
                free_list[isize] = bh;
                bh->b_prev_free = bh;
-       };
+       }
 
        nr_free[isize]++;
        bh->b_next_free = free_list[isize];
@@ -919,15 +919,19 @@ struct buffer_head * breada(kdev_t dev, int block, int bufsize,
        index = BUFSIZE_INDEX(bh->b_size);
 
        if (buffer_uptodate(bh))
-               return bh;
+               return(bh);   
+       else ll_rw_block(READ, 1, &bh);
 
-       blocks = ((filesize & (bufsize - 1)) - (pos & (bufsize - 1))) >> (9+index);
+       blocks = (filesize - pos) >> (9+index);
 
-       if (blocks > (read_ahead[MAJOR(dev)] >> index))
+       if (blocks < (read_ahead[MAJOR(dev)] >> index))
                blocks = read_ahead[MAJOR(dev)] >> index;
-       if (blocks > NBUF)
+       if (blocks > NBUF) 
                blocks = NBUF;
-       
+
+/*     if (blocks) printk("breada (new) %d blocks\n",blocks); */
+
+
        bhlist[0] = bh;
        j = 1;
        for(i=1; i<blocks; i++) {
@@ -936,14 +940,14 @@ struct buffer_head * breada(kdev_t dev, int block, int bufsize,
                        brelse(bh);
                        break;
                }
-               bhlist[j++] = bh;
+               else bhlist[j++] = bh;
        }
 
        /* Request the read for these buffers, and then release them */
-       ll_rw_block(READ, j, bhlist);
-
+       if (j>1)  
+               ll_rw_block(READA, (j-1), bhlist+1); 
        for(i=1; i<j; i++)
-               brelse(bhlist[i]);
+               brelse(bhlist[i]);
 
        /* Wait for this buffer, and then continue on */
        bh = bhlist[0];
@@ -1928,7 +1932,7 @@ asmlinkage int sync_old_buffers(void)
        for(isize = 0; isize<NR_SIZES; isize++){
                CALC_LOAD(buffers_lav[isize], bdf_prm.b_un.lav_const, buffer_usage[isize]);
                buffer_usage[isize] = 0;
-       };
+       }
        return 0;
 }
 
@@ -1964,7 +1968,7 @@ asmlinkage int sys_bdflush(int func, long data)
                        return -EINVAL;
                bdf_prm.data[i] = data;
                return 0;
-       }
+       };
 
        /* Having func 0 used to launch the actual bdflush and then never
        return (unless explicitly killed). We return zero here to 
index 2c0eaadbb7af68763d34b8207768343e4774bbbd..73aa2fd60ad3aa678d9d9406f85229067d37ea4a 100644 (file)
@@ -16,9 +16,11 @@ struct buffer_head *fat_bread (
 {
        struct buffer_head *ret = NULL;
        if (sb->s_blocksize == 512){
-               ret = bread (sb->s_dev,block,512);
+/*             ret = bread (sb->s_dev,block,512); */
+               ret = breada (sb->s_dev,block,512,0,18*1024); 
        }else{
-               struct buffer_head *real = bread (sb->s_dev,block>>1,1024);
+/*             struct buffer_head *real = bread (sb->s_dev,block>>1,1024); */
+               struct buffer_head *real = breada (sb->s_dev,block>>1,1024,0,18*1024); 
                if (real != NULL){
                        ret = (struct buffer_head *)kmalloc (sizeof(struct buffer_head)
                                ,GFP_KERNEL);
index cb05f26c581caf0bf87bfe653921adbaa8494e4c..54badbeadb7724e96a61f4c0585b7050715ba4f9 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "msbuffer.h"
 
+
 static struct fat_cache *fat_cache,cache[FAT_CACHE];
 
 /* Returns the this'th FAT entry, -1 if it is an end-of-file entry. If
@@ -29,18 +30,18 @@ int fat_access(struct super_block *sb,int nr,int new_value)
                first = nr*3/2;
                last = first+1;
        }
-       if (!(bh = bread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >>
-           SECTOR_BITS),SECTOR_SIZE))) {
-               printk("bread in fat_access failed\n");
+       if (!(bh = breada(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >>
+           SECTOR_BITS),SECTOR_SIZE,0,FAT_READAHEAD))) {
+               printk("breada in fat_access failed\n");
                return 0;
        }
        if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS))
                bh2 = bh;
        else {
-               if (!(bh2 = bread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last
-                   >> SECTOR_BITS),SECTOR_SIZE))) {
+               if (!(bh2 = breada(sb->s_dev,MSDOS_SB(sb)->fat_start+(last
+                   >> SECTOR_BITS),SECTOR_SIZE,0,FAT_READAHEAD))) {
                        brelse(bh);
-                       printk("bread in fat_access failed\n");
+                       printk("breada in fat_access failed\n");
                        return 0;
                }
        }
@@ -75,16 +76,16 @@ int fat_access(struct super_block *sb,int nr,int new_value)
                }
                mark_buffer_dirty(bh, 1);
                for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) {
-                       if (!(c_bh = bread(sb->s_dev,MSDOS_SB(sb)->
+                       if (!(c_bh = breada(sb->s_dev,MSDOS_SB(sb)->
                            fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)->
-                           fat_length*copy,SECTOR_SIZE))) break;
+                           fat_length*copy,SECTOR_SIZE,0,FAT_READAHEAD))) break;
                        memcpy(c_bh->b_data,bh->b_data,SECTOR_SIZE);
                        mark_buffer_dirty(c_bh, 1);
                        if (bh != bh2) {
-                               if (!(c_bh2 = bread(sb->s_dev,
+                               if (!(c_bh2 = breada(sb->s_dev,
                                    MSDOS_SB(sb)->fat_start+(first >>
                                    SECTOR_BITS)+MSDOS_SB(sb)->fat_length*copy
-                                   +1,SECTOR_SIZE))) {
+                                   +1,SECTOR_SIZE,0,FAT_READAHEAD))) {
                                        brelse(c_bh);
                                        break;
                                }
index b01f07a9aaa913fc3345585dbe703fdf75e95113..5d865f4d20eae82616b5dff9e954da086b5ce9ab 100644 (file)
@@ -298,7 +298,7 @@ int fat_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
                if (*bh)
                        brelse(*bh);
                PRINTK (("get_entry sector apres brelse\n"));
-               if (!(*bh = bread(dir->i_dev,sector,SECTOR_SIZE))) {
+               if (!(*bh = breada(dir->i_dev,sector,SECTOR_SIZE,0,FAT_READAHEAD))) {
                        printk("Directory sread (sector %d) failed\n",sector);
                        continue;
                }
@@ -372,7 +372,7 @@ static int raw_scan_sector(struct super_block *sb,int sector,const char *name,
        struct inode *inode;
        int entry,start,done;
 
-       if (!(bh = bread(sb->s_dev,sector,SECTOR_SIZE))) return -EIO;
+       if (!(bh = breada(sb->s_dev,sector,SECTOR_SIZE,0,FAT_READAHEAD))) return -EIO;
        data = (struct msdos_dir_entry *) bh->b_data;
        for (entry = 0; entry < MSDOS_DPS; entry++) {
 /* RSS_COUNT:  if (data[entry].name == name) done=true else done=false. */
index d5d29970a3705eecb261a16b58b9793fc356ebde..5b386afe3689d402d0bd32f9a03214c0e9bacad5 100644 (file)
@@ -1,3 +1,5 @@
+/* Number of bytes to readahead on disc access */
+#define FAT_READAHEAD (18*1024)
 
 struct buffer_head *fat_bread (struct super_block *sb, int block);
 struct buffer_head *fat_getblk (struct super_block *sb, int block);
index 9de3284b8c88297815756d01afb70b3e4977e0c2..6f19c71fd5b5787185bdf52d1e4073debd581d98 100644 (file)
@@ -85,6 +85,10 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
                        if (!(arg & FASYNC) && (filp->f_flags & FASYNC) &&
                            filp->f_op->fasync)
                                filp->f_op->fasync(filp->f_inode, filp, 0);
+                       /* requiered for SunOS emulation */
+                       if (O_NONBLOCK != O_NDELAY)
+                              if (arg & O_NDELAY)
+                                  arg |= O_NONBLOCK;
                        filp->f_flags &= ~(O_APPEND | O_NONBLOCK | FASYNC);
                        filp->f_flags |= arg & (O_APPEND | O_NONBLOCK |
                                                FASYNC);
index 278cb396b855866e9dcab574aa52793d3ffe1030..dacda9315ab441073733bd748d4aa5721514d9c2 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/hpfs_fs.h>
 #include <linux/smb_fs.h>
 #include <linux/ncp_fs.h>
+#include <linux/affs_fs.h>
 #include <linux/ufs_fs.h>
 #include <linux/major.h>
 
@@ -101,6 +102,10 @@ asmlinkage int sys_setup(void)
        init_hpfs_fs();
 #endif
 
+#ifdef CONFIG_AFFS_FS
+       init_affs_fs();
+#endif
+
 #ifdef CONFIG_UFS_FS
        init_ufs_fs();
 #endif
index f19e2357836b24cdf893da9dd9523c1a2f2e81dd..2d1d20ea26cba8bf19db8679e8739827ce815d82 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/system.h>
 #include <asm/segment.h>
 
+#define MULTI_VOLUME
 #ifdef LEAK_CHECK
 static int check_malloc = 0;
 static int check_bread = 0;
@@ -306,8 +307,10 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
        if(high_sierra){
          rootp = (struct iso_directory_record *) h_pri->root_directory_record;
          if (isonum_723 (h_pri->volume_set_size) != 1) {
+#ifndef  MULTI_VOLUME 
            printk("Multi-volume disks not (yet) supported.\n");
            goto out;
+#endif
          };
          s->u.isofs_sb.s_nzones = isonum_733 (h_pri->volume_space_size);
          s->u.isofs_sb.s_log_zone_size = isonum_723 (h_pri->logical_block_size);
@@ -315,8 +318,10 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
        } else {
          rootp = (struct iso_directory_record *) pri->root_directory_record;
          if (isonum_723 (pri->volume_set_size) != 1) {
+#ifndef MULTI_VOLUME
            printk("Multi-volume disks not (yet) supported.\n");
            goto out;
+#endif
          };
          s->u.isofs_sb.s_nzones = isonum_733 (pri->volume_space_size);
          s->u.isofs_sb.s_log_zone_size = isonum_723 (pri->logical_block_size);
@@ -614,10 +619,13 @@ void isofs_read_inode(struct inode * inode)
          inode->i_sb->u.isofs_sb.s_cruft = 'y';
        }
 
+#ifndef MULTI_VOLUME
        if (inode->i_sb->u.isofs_sb.s_cruft != 'y' && 
            (volume_seq_no != 0) && (volume_seq_no != 1)) {
                printk("Multi volume CD somehow got mounted.\n");
-       } else {
+       } else
+#endif 
+       {
          if (S_ISREG(inode->i_mode))
            inode->i_op = &isofs_file_inode_operations;
          else if (S_ISDIR(inode->i_mode))
index fd5aa6a2bf49e6bf74a6726c88fb93254fbff0aa..d73d26bd1b74c53f44ccd8cd1e08924c290e56dd 100644 (file)
@@ -273,9 +273,18 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
                break;
        case F_SHLCK :
        case F_EXLCK :
+#if 1
+/* warn a bit for now, but don't overdo it */
+{
+       static int count = 0;
+       if (count < 5) {
+               count++;
                printk(KERN_WARNING
                       "fcntl_setlk() called by process %d with broken flock() emulation\n",
                       current->pid);
+       }
+}
+#endif
                if (!(filp->f_mode & 3))
                        return (-EBADF);
                break;
index 553af1f5b57bf64804e8388aec474fa6e99ee607..f87cb3629ceabc5ed9210e1b2b0d1f224aa6d21c 100644 (file)
@@ -13,7 +13,7 @@
     HOW TO USE
 
     This stuff compiles as a loadable module (I developed it on 1.3.77).
-    Simply type mkmodule, and insmod nfs.o. This will start for nfsiod's
+    Simply type mkmodule, and insmod nfs.o. This will start four nfsiod's
     at the same time (which will show up under the pseudonym of insmod in
     ps-style listings).
 
index e6cc98b8288246a19df87bf05d904f59ec35d4a4..bd36ea1e5f3fd15d35cd5778444de4b703008179 100644 (file)
 
 #include <asm/segment.h>       /* for fs functions */
 
-static int nfs_dir_read(struct inode *, struct file *filp, char *buf,
-                       int count);
+static int nfs_dir_open(struct inode * inode, struct file * file);
+static int nfs_dir_read(struct inode *, struct file *, char *, int);
 static int nfs_readdir(struct inode *, struct file *, void *, filldir_t);
-static int nfs_lookup(struct inode *dir, const char *name, int len,
-                     struct inode **result);
-static int nfs_create(struct inode *dir, const char *name, int len, int mode,
-                     struct inode **result);
-static int nfs_mkdir(struct inode *dir, const char *name, int len, int mode);
-static int nfs_rmdir(struct inode *dir, const char *name, int len);
-static int nfs_unlink(struct inode *dir, const char *name, int len);
-static int nfs_symlink(struct inode *inode, const char *name, int len,
-                      const char *symname);
-static int nfs_link(struct inode *oldinode, struct inode *dir,
-                   const char *name, int len);
-static int nfs_mknod(struct inode *dir, const char *name, int len, int mode,
-                    int rdev);
-static int nfs_rename(struct inode *old_dir, const char *old_name,
-                     int old_len, struct inode *new_dir, const char *new_name,
-                     int new_len);
+static int nfs_lookup(struct inode *, const char *, int, struct inode **);
+static int nfs_create(struct inode *, const char *, int, int, struct inode **);
+static int nfs_mkdir(struct inode *, const char *, int, int);
+static int nfs_rmdir(struct inode *, const char *, int);
+static int nfs_unlink(struct inode *, const char *, int);
+static int nfs_symlink(struct inode *, const char *, int, const char *);
+static int nfs_link(struct inode *, struct inode *, const char *, int);
+static int nfs_mknod(struct inode *, const char *, int, int, int);
+static int nfs_rename(struct inode *, const char *, int,
+                     struct inode *, const char *, int);
 
 static struct file_operations nfs_dir_operations = {
        NULL,                   /* lseek - default */
@@ -48,7 +42,7 @@ static struct file_operations nfs_dir_operations = {
        NULL,                   /* select - default */
        NULL,                   /* ioctl - default */
        NULL,                   /* mmap */
-       NULL,                   /* no special open code */
+       nfs_dir_open,           /* open - revalidate */
        NULL,                   /* no special release code */
        NULL                    /* fsync */
 };
@@ -73,6 +67,29 @@ struct inode_operations nfs_dir_inode_operations = {
        NULL                    /* permission */
 };
 
+static inline void revalidate_dir(struct nfs_server * server, struct inode * dir)
+{
+       struct nfs_fattr fattr;
+
+       if (jiffies - NFS_READTIME(dir) < server->acdirmax)
+               return;
+
+       NFS_READTIME(dir) = jiffies;
+       if (nfs_proc_getattr(server, NFS_FH(dir), &fattr) == 0) {
+               nfs_refresh_inode(dir, &fattr);
+               if (fattr.mtime.seconds == NFS_OLDMTIME(dir))
+                       return;
+               NFS_OLDMTIME(dir) = fattr.mtime.seconds;
+       }
+       /* invalidate directory cache here when we _really_ start caching */
+}
+
+static int nfs_dir_open(struct inode * dir, struct file * file)
+{
+       revalidate_dir(NFS_SERVER(dir), dir);
+       return 0;
+}
+
 static int nfs_dir_read(struct inode *inode, struct file *filp, char *buf,
                        int count)
 {
@@ -105,6 +122,8 @@ static int nfs_readdir(struct inode *inode, struct file *filp,
                return -EBADF;
        }
 
+       revalidate_dir(NFS_SERVER(inode), inode);
+
        /* initialize cache memory if it hasn't been used before */
 
        if (c_entry == NULL) {
@@ -190,7 +209,7 @@ static int nfs_readdir(struct inode *inode, struct file *filp,
 
 void nfs_kfree_cache(void)
 {
-        int i;
+       int i;
 
        if (c_entry == NULL)
                return;
index f84d12fa037dcd88af47bf33b62a87bcb48a8e9d..d5a414eccb9987e7290928c23a9668d1c4d03046 100644 (file)
@@ -340,6 +340,7 @@ static int run_nfsiod(void *dummy)
 #endif
 
        MOD_INC_USE_COUNT;
+       exit_mm(current);
        current->session = 1;
        current->pgrp = 1;
        sprintf(current->comm, "nfsiod");
index 6b2cd9e7328944cae4dad00ee38126fcc1c4cf51..f63ab6af239c408db54da566a15af16fe4a520af 100644 (file)
@@ -470,6 +470,11 @@ static unsigned long get_wchan(struct task_struct *p)
                                 + (long)&((struct pt_regs *)0)->reg)
 # define KSTK_EIP(tsk) (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(pc)))
 # define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp)
+#elif defined(__sparc__)
+# define PT_REG(reg)            (PAGE_SIZE - sizeof(struct pt_regs)     \
+                                 + (long)&((struct pt_regs *)0)->reg)
+# define KSTK_EIP(tsk)  (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(pc)))
+# define KSTK_ESP(tsk)  (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(u_regs[UREG_FP])))
 #endif
 
 /* Gcc optimizes away "strlen(x)" for constant x */
@@ -607,7 +612,7 @@ static inline char * task_sig(struct task_struct *p, char *buffer)
                        bit <<= 1;
                        action++;
                }
-               
+
                buffer += sprintf(buffer,
                        "SigIgn:\t%08lx\n"
                        "SigCgt:\t%08lx\n",
index 99b2712ec49b3600ce4dff55a3ce490655605b15..27aee98f000b80332be6f0054b003fefe5c27556 100644 (file)
@@ -74,7 +74,7 @@ static int parse_options(char *options,uid_t *uid,gid_t *gid)
 struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_entry * de)
 {
        struct inode * inode = iget(s, ino);
-       if (inode) {
+       if (inode && inode->i_sb == s) {
                inode->u.generic_ip = (void *) de;
                if (de) {
                        if (de->mode) {
index 8ae07ac009f50e4c6070793f2a0d533ba12bef45..8e3969ca798b05ff3b140fefff3327631cf4a436 100644 (file)
@@ -65,14 +65,9 @@ static int mem_read(struct inode * inode, struct file * file,char * buf, int cou
                return -EINVAL;
        pid = inode->i_ino;
        pid >>= 16;
-       tsk = NULL;
-       for (i = 1 ; i < NR_TASKS ; i++)
-               if (task[i] && task[i]->pid == pid) {
-                       tsk = task[i];
-                       break;
-               }
-       if (!tsk)
+       if (pid != current->pid)
                return -EACCES;
+       tsk = current;
        addr = file->f_pos;
        count = check_range(tsk, addr, count);
        if (count < 0)
@@ -131,14 +126,9 @@ static int mem_write(struct inode * inode, struct file * file,char * buf, int co
        addr = file->f_pos;
        pid = inode->i_ino;
        pid >>= 16;
-       tsk = NULL;
-       for (i = 1 ; i < NR_TASKS ; i++)
-               if (task[i] && task[i]->pid == pid) {
-                       tsk = task[i];
-                       break;
-               }
-       if (!tsk)
+       if (pid != current->pid)
                return -EACCES;
+       tsk = current;
        tmp = buf;
        while (count > 0) {
                if (current->signal & ~current->blocked)
index f4817be4a8bafcfd7f72800657da109a7386de97..1cbc59a022267befcd378650b935736078229964 100644 (file)
@@ -6,22 +6,16 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_dir.c,v 1.1 1996/04/21 14:41:04 davem Exp $
+ * $Id: ufs_dir.c,v 1.3 1996/04/25 09:12:00 davem Exp $
  *
  */
 
 #include <linux/fs.h>
 
 /* XXX */
-extern int ufs_lookup();
-extern int ufs_bmap();
-
-static int ufs_dir_read (struct inode * inode, struct file * filp,
-                        char * buf, int count)
-{
-       /* XXX - probably allow this for root, EISDIR for normal users */
-       return -EISDIR;
-}
+extern int ufs_lookup (struct inode *, const char *, int, struct inode **);
+extern int ufs_bmap (struct inode *, int);
+extern void ufs_print_inode (struct inode *);
 
 /*
  * This is blatantly stolen from ext2fs
@@ -43,7 +37,7 @@ ufs_readdir (struct inode * inode, struct file * filp, void * dirent,
 
        if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
                printk("ufs_readdir: ino %lu  f_pos %lu\n",
-                      inode->i_ino, filp->f_pos);
+                      inode->i_ino, (unsigned long) filp->f_pos);
                ufs_print_inode(inode);
        }
 
@@ -95,7 +89,7 @@ revalidate:
                        de = (struct direct *) (bh->b_data + offset);
                        /* XXX - put in a real ufs_check_dir_entry() */
                        if ((de->d_reclen == 0) || (de->d_namlen == 0)) {
-                               filp->f_pos = filp->f_pos & (sb->s_blocksize - 1) + sb->s_blocksize;
+                               filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + sb->s_blocksize;
                                brelse(bh);
                                return stored;
                        }
@@ -123,7 +117,7 @@ revalidate:
                                           de->d_ino);
                                version = inode->i_version;
                                if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
-                                       printk("ufs_readdir: filldir(%s,%lu)\n",
+                                       printk("ufs_readdir: filldir(%s,%u)\n",
                                               de->d_name, de->d_ino);
                                }
                                error = filldir(dirent, de->d_name, de->d_namlen, filp->f_pos, de->d_ino);
@@ -147,18 +141,17 @@ revalidate:
        return 0;
 }
 
-
 static struct file_operations ufs_dir_operations = {
        NULL,                   /* lseek */
-       &ufs_dir_read,          /* read */
+       NULL,                   /* read */
        NULL,                   /* write */
-       &ufs_readdir,           /* readdir */
+       ufs_readdir,            /* readdir */
        NULL,                   /* select */
        NULL,                   /* ioctl */
        NULL,                   /* mmap */
        NULL,                   /* open */
        NULL,                   /* release */
-       &file_fsync,            /* fsync */
+       file_fsync,             /* fsync */
        NULL,                   /* fasync */
        NULL,                   /* check_media_change */
        NULL,                   /* revalidate */
@@ -167,7 +160,7 @@ static struct file_operations ufs_dir_operations = {
 struct inode_operations ufs_dir_inode_operations = {
        &ufs_dir_operations,    /* default directory file operations */
        NULL,                   /* create */
-       &ufs_lookup,            /* lookup */
+       ufs_lookup,             /* lookup */
        NULL,                   /* link */
        NULL,                   /* unlink */
        NULL,                   /* symlink */
index 0b6b759a29350c0557c9c470b1aa9b3c8f4d7787..0b0b5e0b4643ce21da1a68bbce16ddaa079db9c5 100644 (file)
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_file.c,v 1.1 1996/04/21 14:41:08 davem Exp $
+ * $Id: ufs_file.c,v 1.3 1996/04/25 09:12:02 davem Exp $
  *
  */
 
@@ -75,13 +75,13 @@ int ufs_bmap (struct inode * inode, int block)
                        bh = bread(inode->i_dev, inode->u.ufs_i.ui_ib[0],
                                   BLOCK_SIZE);
                        if (bh == NULL) {
-                               printk("ufs_bmap: can't map block %lu, ino %lu\n",
+                               printk("ufs_bmap: can't map block %u, ino %lu\n",
                                       block + UFS_NDADDR, inode->i_ino);
                                return(0);
                        }
                        phys_block = ((__u32 *)bh->b_data)[block];
                        brelse(bh);
-                       printk("ufs_bmap: imap ino %lu block %lu phys %lu\n",
+                       printk("ufs_bmap: imap ino %lu block %u phys %lu\n",
                               inode->i_ino, block + UFS_NDADDR, phys_block);
                        return(phys_block);
                } else {
@@ -94,18 +94,17 @@ int ufs_bmap (struct inode * inode, int block)
        return(0);
 }
 
-
 static struct file_operations ufs_file_operations = {
        NULL,                   /* lseek */
-       &generic_file_read,     /* read */
+       generic_file_read,      /* read */
        NULL,                   /* write */
        NULL,                   /* readdir */
        NULL,                   /* select */
        NULL,                   /* ioctl */
-       &generic_file_mmap,     /* mmap */
+       generic_file_mmap,      /* mmap */
        NULL,                   /* open */
        NULL,                   /* release */
-       &file_fsync,            /* fsync */  /* XXX - is this ok? */
+       file_fsync,             /* fsync */
        NULL,                   /* fasync */
        NULL,                   /* check_media_change */
        NULL,                   /* revalidate */
@@ -124,9 +123,9 @@ struct inode_operations ufs_file_inode_operations = {
        NULL,                   /* rename */
        NULL,                   /* readlink */
        NULL,                   /* follow_link */
-       &generic_readpage,      /* readpage */
+       generic_readpage,       /* readpage */
        NULL,                   /* writepage */
-       &ufs_bmap,              /* bmap */
+       ufs_bmap,               /* bmap */
        NULL,                   /* truncate */
        NULL,                   /* permission */
        NULL,                   /* smap */
index d80d172ffdf0814986e7b21561dba91150c92ea8..ec568f5026e8753c8fc1da25f8bbc503bf9d1fd1 100644 (file)
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_inode.c,v 1.1 1996/04/21 14:41:12 davem Exp $
+ * $Id: ufs_inode.c,v 1.3 1996/04/25 09:12:05 davem Exp $
  *
  */
 
index dbe0579862f78b0d3fcd2853811f651bc18a8b7f..0cfe1285ec3ae52f257eb1b0aab1af2f63e040b2 100644 (file)
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_namei.c,v 1.1 1996/04/21 14:41:15 davem Exp $
+ * $Id: ufs_namei.c,v 1.3 1996/04/25 09:12:07 davem Exp $
  *
  */
 
@@ -103,7 +103,7 @@ int ufs_lookup (struct inode * dir, const char * name, int len,
                }
                bh = bread(dir->i_dev, fragno, dir->i_sb->s_blocksize);
                if (bh == NULL) {
-                       printk("ufs_lookup: bread failed: ino %lu, lfragno %u",
+                       printk("ufs_lookup: bread failed: ino %lu, lfragno %lu",
                               dir->i_ino, lfragno);
                        return(-EIO);
                }
@@ -119,7 +119,7 @@ int ufs_lookup (struct inode * dir, const char * name, int len,
                                break;
                        }
                        if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
-                               printk("lfragno 0x%x  direct d 0x%x  d_ino %u  d_reclen %u  d_namlen %u  d_name `%s'\n",
+                               printk("lfragno 0x%lx  direct d 0x%x  d_ino %u  d_reclen %u  d_namlen %u  d_name `%s'\n",
                                       lfragno, (unsigned int)d, d->d_ino, d->d_reclen, d->d_namlen, d->d_name);
                        }
                        if ((d->d_namlen == len) &&
index 340336c021bfbb9ad3e8b0da5c07daadb9fe710e..f44fd20c8f84975d89d5f71c4315bc1e7a289541 100644 (file)
@@ -6,10 +6,17 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_super.c,v 1.1 1996/04/21 14:41:19 davem Exp $
+ * $Id: ufs_super.c,v 1.3 1996/04/25 09:12:09 davem Exp $
  *
  */
 
+/*
+ * Kernel module support added on 96/04/26 by
+ * Stefan Reinauer <stepan@home.culture.mipt.ru>
+ */
+
+#include <linux/module.h>
+
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
@@ -26,18 +33,18 @@ extern void ufs_read_inode(struct inode * inode);
 extern void ufs_put_inode(struct inode * inode);
 
 static struct super_operations ufs_super_ops = {
-       &ufs_read_inode,
+       ufs_read_inode,
        NULL,                   /* notify_change() */
        NULL,                   /* XXX - ufs_write_inode() */
-       &ufs_put_inode,
-       &ufs_put_super,
+       ufs_put_inode,
+       ufs_put_super,
        NULL,                   /* XXX - ufs_write_super() */
-       &ufs_statfs,
+       ufs_statfs,
        NULL,                   /* XXX - ufs_remount() */
 };
 
 static struct file_system_type ufs_fs_type = {
-       &ufs_read_super, "ufs", 1, NULL
+       ufs_read_super, "ufs", 1, NULL
 };
 
 int
@@ -46,6 +53,23 @@ init_ufs_fs(void)
        return(register_filesystem(&ufs_fs_type));
 }
 
+#ifdef MODULE
+int init_module(void)
+{
+       int status;
+
+       if ((status = init_ufs_fs()) == 0)
+               register_symtab(0);
+       return status;
+}
+
+void cleanup_module(void)
+{
+       unregister_filesystem(&ufs_fs_type);
+}
+#endif
+
+#if 0 /* unused */
 static void
 ufs_print_super_stuff(struct super_block * sb, struct ufs_superblock * usb)
 {
@@ -65,6 +89,7 @@ ufs_print_super_stuff(struct super_block * sb, struct ufs_superblock * usb)
 
        return;
 }
+#endif
 
 struct super_block *
 ufs_read_super(struct super_block * sb, void * data, int silent)
@@ -203,7 +228,7 @@ ufs_read_super(struct super_block * sb, void * data, int silent)
        sb->u.ufs_sb.s_fsfrag = usb->fs_frag; /* XXX - rename this later */
        sb->s_mounted = iget(sb, UFS_ROOTINO);
 
-       printk("ufs_read_super: inopb %lu\n", sb->u.ufs_sb.s_inopb);
+       printk("ufs_read_super: inopb %u\n", sb->u.ufs_sb.s_inopb);
        /*
         * XXX - read cg structs?
         */
index b31a6f8cb96a41486d95cf331328e6b20c9bc498..83cd9e1c3d515d56b4f44ddbf7d7761f1fdd5277 100644 (file)
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_symlink.c,v 1.1 1996/04/21 14:41:23 davem Exp $
+ * $Id: ufs_symlink.c,v 1.3 1996/04/25 09:12:11 davem Exp $
  *
  */
 
 
 #include <asm/segment.h>
 
+extern int ufs_bmap (struct inode *, int);
+
 static int
 ufs_readlink(struct inode * inode, char * buffer, int buflen)
 {
        unsigned long int block;
        struct buffer_head * bh = NULL;
        char * link;
-       int i, err;
+       int i;
        char c;
 
        if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) {
@@ -64,8 +66,6 @@ ufs_readlink(struct inode * inode, char * buffer, int buflen)
        if (bh)
                brelse (bh);
        return i;
-
-       return(0);
 }
 
 /*
index 566b09c235dba5d73dd5dde4de44795f9420f4ac..ff0caafe07dae523a806b34ca0db619671629577 100644 (file)
@@ -19,7 +19,7 @@
  *     information is. 
  */
  
-#define SMP_MAGIC_IDENT        ('_'<<24)|('P'<<16)|('M'<<8)|'_'
+#define SMP_MAGIC_IDENT        (('_'<<24)|('P'<<16)|('M'<<8)|'_')
 
 struct intel_mp_floating
 {
index 3ec5655604525d12965bfdfdffc66ad93f649f70..24ae1e220cdff661714cc8427cabc823409b52e3 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <linux/types.h>
 
-/* Reading the MFP port register gives a machine independant delay, since the
+/* Reading the MFP port register gives a machine independent delay, since the
  * MFP always has a 8 MHz clock. This avoids problems with the varying length
  * of nops on various machines. Somebody claimed that the tstb takes 600 ns.
  */
@@ -42,7 +42,7 @@ extern int is_medusa;
 #include <linux/mm.h>
 #include <asm/pgtable.h>
 
-static inline void dma_cache_maintainance( unsigned long paddr,
+static inline void dma_cache_maintenance( unsigned long paddr,
                                          unsigned long len,
                                          int writeflag )
 
@@ -293,7 +293,7 @@ struct BLITTER
   u_short endmask3;
   u_short dst_x_inc;
   u_short dst_y_inc;
-  u_long dst_adress;
+  u_long dst_address;
   u_short wd_per_line;
   u_short ln_per_bb;
   u_short hlf_op_reg;
@@ -448,7 +448,7 @@ struct TT_RTC {
  */
 /* constants for the ACIA registers */
 
-/* baudrate selection and reset (Baudrte = clock/factor) */
+/* baudrate selection and reset (Baudrate = clock/factor) */
 #define ACIA_DIV1  0
 #define ACIA_DIV16 1
 #define ACIA_DIV64 2
index 0318a0f9d56a4df6a36c712cd7cfe27774221dc9..bc23d25f1f00982a59a37819a92f4521a7f2dc05 100644 (file)
@@ -4,7 +4,7 @@
 ** Copyright 1994 by Bj\94rn Brauel
 **
 ** 5/2/94 Roman Hodek:
-**   TT interupt definitions added.
+**   TT interrupt definitions added.
 **
 ** 12/02/96: (Roman)
 **   Adapted to new int handling scheme (see ataints.c); revised numbering
@@ -45,7 +45,7 @@
 #define IRQ_TYPE_FAST     1
 #define IRQ_TYPE_PRIO     2
 
-#define        IRQ_SUPRIOUS      (IRQ_MACHSPEC | 0)
+#define        IRQ_SPURIOUS      (IRQ_MACHSPEC | 0)
 
 /* auto-vector interrupts */
 #define IRQ_AUTO_1        (IRQ_MACHSPEC | 1)
index 7c39167384c026c0d4a1377e9ea8ccdcb99787d6..d65198fca729a10eaaf65a7c04e096d5109f0436 100644 (file)
@@ -24,7 +24,7 @@ static __inline__ void atomic_add(atomic_t i, atomic_t *v)
        __asm__ __volatile__(
                "addl %1,%0"
                :"=m" (__atomic_fool_gcc(v))
-               :"ir" (i), "m" (__atomic_fool_gcc(v)));
+               :"ir" (i), "0" (__atomic_fool_gcc(v)));
 }
 
 static __inline__ void atomic_sub(atomic_t i, atomic_t *v)
@@ -32,7 +32,7 @@ static __inline__ void atomic_sub(atomic_t i, atomic_t *v)
        __asm__ __volatile__(
                "subl  %1,%0"
                :"=m" (__atomic_fool_gcc(v))
-               :"ir" (i), "m" (__atomic_fool_gcc(v)));
+               :"ir" (i), "0" (__atomic_fool_gcc(v)));
 }
 
 static __inline__ void atomic_inc(atomic_t *v)
@@ -40,7 +40,7 @@ static __inline__ void atomic_inc(atomic_t *v)
        __asm__ __volatile__(
                "addql #1,%0"
                :"=m" (__atomic_fool_gcc(v))
-               :"m" (__atomic_fool_gcc(v)));
+               :"0" (__atomic_fool_gcc(v)));
 }
 
 static __inline__ void atomic_dec(atomic_t *v)
@@ -48,16 +48,17 @@ static __inline__ void atomic_dec(atomic_t *v)
        __asm__ __volatile__(
                "subql #1,%0"
                :"=m" (__atomic_fool_gcc(v))
-               :"m" (__atomic_fool_gcc(v)));
+               :"0" (__atomic_fool_gcc(v)));
 }
 
 static __inline__ int atomic_dec_and_test(atomic_t *v)
 {
+       char c;
        __asm__ __volatile__(
-               "subql #1,%0"
-               :"=m" (__atomic_fool_gcc(v))
-               :"m" (__atomic_fool_gcc(v)));
-       return (*v <= 0);
+               "subql #1,%0; seq %1"
+               :"=m" (__atomic_fool_gcc(v)), "=d" (c)
+               :"0" (__atomic_fool_gcc(v)));
+       return c != 0;
 }
 
 #endif /* __ARCH_M68K_ATOMIC __ */
index 0a91c8110f17116b5b50be9a023db4c0e9aeab94..5b618801c8c46cb899aaf51e4d83954cc4a16090 100644 (file)
@@ -46,12 +46,7 @@ extern __inline__ int change_bit(int nr, void * vaddr)
 
 extern __inline__ int test_bit(int nr, const void * vaddr)
 {
-       char retval;
-
-       __asm__ __volatile__ ("bftst %2@{%1:#1}; sne %0"
-            : "=d" (retval) : "d" (nr^31), "a" (vaddr));
-
-       return retval;
+       return ((1UL << (nr & 31)) & (((const unsigned int *) vaddr)[nr >> 5])) != 0;
 }
 
 extern __inline__ int find_first_zero_bit(void * vaddr, unsigned size)
@@ -166,12 +161,7 @@ minix_clear_bit (int nr, void *vaddr)
 extern __inline__ int
 minix_test_bit (int nr, const void *vaddr)
 {
-       char retval;
-
-       __asm__ __volatile__ ("bftst %2{%1:#1}; sne %0"
-            : "=d" (retval) : "d" (nr^15), "m" (*(const char *) vaddr));
-
-       return retval;
+       return ((1U << (nr & 15)) & (((const unsigned short *) vaddr)[nr >> 4])) != 0;
 }
 
 /* Bitmap functions for the ext2 filesystem. */
@@ -201,12 +191,7 @@ ext2_clear_bit (int nr, void *vaddr)
 extern __inline__ int
 ext2_test_bit (int nr, const void *vaddr)
 {
-       char retval;
-
-       __asm__ __volatile__ ("bftst %2{%1,#1}; sne %0"
-            : "=d" (retval) : "d" (nr^7), "m" (*(const char *) vaddr));
-
-       return retval;
+       return ((1U << (nr & 7)) & (((const unsigned char *) vaddr)[nr >> 3])) != 0;
 }
 
 extern __inline__ int
index 638c7b3c828ab34692384b0080809055e8ac533c..08e4b6dee1acdab0a4c244291e65af9bff1cc71c 100644 (file)
@@ -10,7 +10,7 @@
 ** Created 09/29/92 by Greg Harp
 **
 ** 5/2/94 Roman Hodek:
-**   Added bi_atari part of the machine dependant union bi_un; for now it
+**   Added bi_atari part of the machine dependent union bi_un; for now it
 **      contains just a model field to distinguish between TT and Falcon.
 */
 
@@ -98,7 +98,7 @@ struct bi_Atari {
   struct {
     /* video hardware */
     ATARIHW_DECLARE(STND_SHIFTER);     /* ST-Shifter - no base low ! */
-    ATARIHW_DECLARE(EXTD_SHIFTER);     /* STe-Shifter - 24 bit adress */
+    ATARIHW_DECLARE(EXTD_SHIFTER);     /* STe-Shifter - 24 bit address */
     ATARIHW_DECLARE(TT_SHIFTER);       /* TT-Shifter */
     ATARIHW_DECLARE(VIDEL_SHIFTER);    /* Falcon-Shifter */
     /* sound hardware */
index 08f792fc36822424e424a02bc89053072aa184cf..af73a0f6fa3463c8eea7c877d7e0743cc2a3010c 100644 (file)
@@ -2,7 +2,7 @@
 #define _M68K_DMA_H 1
 
 /* Don't define MAX_DMA_ADDRESS; it's useless on the m68k and any
-   occurence should be flagged as an error.  */
+   occurrence should be flagged as an error.  */
 
 #define MAX_DMA_CHANNELS 8
 
index 1151255b837eee6e4062d8de9ab475812f408c35..0b189d6d879c10524f8d6763439fb3e834d04224 100644 (file)
@@ -18,7 +18,7 @@
     *    Find a font with a specific name
     */
 
-extern int findsoftfont(char *name, int *width, int *heigth, u_char *data[]);
+extern int findsoftfont(char *name, int *width, int *height, u_char *data[]);
 
 
    /*
@@ -29,4 +29,7 @@ extern void getdefaultfont(int xres, int yres, char *name[], int *width,
                            int *height, u_char *data[]);
 
 
+/* Max. length for the name of a predefined font */
+#define MAX_FONT_NAME  32
+
 #endif /* _ASM_M68K_FONT_H_ */
index bad53470da2f96f995c8ed4500f77b38c4f3222a..00c52e8745fd8841093897c532099e761918b1f5 100644 (file)
@@ -141,7 +141,7 @@ static inline void flush_tlb_range(struct mm_struct *mm,
 #define __S110 PAGE_SHARED
 #define __S111 PAGE_SHARED
 
-/* zero page used for unitialized stuff */
+/* zero page used for uninitialized stuff */
 extern unsigned long empty_zero_page;
 
 /*
@@ -525,22 +525,14 @@ extern void cache_push (unsigned long paddr, int len);
  */
 extern void cache_push_v (unsigned long vaddr, int len);
 
-#if 0
-#define flush_cache_all()                  do { \
-                   if (m68k_is040or060 >= 4) \
-                     __asm__ __volatile__ (".word 0xf478\n" ::); \
-                                            } while (0)
+/*
+ * Could someone take a look at these?
+ */
+extern void flush_cache_all(void);
 #define flush_cache_mm(mm)                flush_cache_all()
 #define flush_cache_range(mm, start, end)  flush_cache_all()
-#define flush_cache_page(vma, vmaddr)     flush_cache_all()
-#define flush_page_to_ram(page)                   flush_cache_all()
-#else
-#define flush_cache_all()                      do { } while (0)
-#define flush_cache_mm(mm)                     do { } while (0)
-#define flush_cache_range(mm, start, end)      do { } while (0)
-#define flush_cache_page(vma, vmaddr)          do { } while (0)
-#define flush_page_to_ram(page)                        do { } while (0)
-#endif
+#define flush_cache_page(vma, addr)       flush_cache_all()
+extern void flush_page_to_ram(unsigned long addr);
 
 /* cache code */
 #define FLUSH_I_AND_D  (0x00000808)
@@ -579,8 +571,19 @@ extern inline void update_mmu_cache(struct vm_area_struct * vma,
 {
 }
 
+/*
+ * I don't know what is going on here, but since these were changed,
+ * swapping haven't been working on the 68040.
+ */
+
+#if 0
 #define SWP_TYPE(entry)  (((entry) >> 2) & 0x7f)
 #define SWP_OFFSET(entry) ((entry) >> 9)
 #define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 9))
+#else
+#define SWP_TYPE(entry)  (((entry) & 0x1fc) >> 2)
+#define SWP_OFFSET(entry) ((entry) >> PAGE_SHIFT)
+#define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << PAGE_SHIFT))
+#endif
 
 #endif /* _M68K_PGTABLE_H */
index 65f844534e55a884b5ee6c9e3ace5b57e22c7a1f..a7563e5ab7a18bacacaa9a763d82ce168fd17e30 100644 (file)
@@ -32,7 +32,7 @@ extern inline void wrusp(unsigned long usp) {
  * and so we might get see unexpected behaviors when a task returns
  * with unexpected register values.
  *
- * syscall stores these regsiters itself and none of them are used
+ * syscall stores these registers itself and none of them are used
  * by syscall after the function in the syscall has been called.
  *
  * Beware that resume now expects *next to be in d1 and the offset of
index cd6f7eacb10ccc4dd18cbbafd841b1ee93539578..661c303e8f2b56469d39406bbe42c00e5347e577 100644 (file)
@@ -148,7 +148,7 @@ extern e_vector vectors[];
 #define        MMU060_SIZ      (0x00600000)    /* transfer size */
 #define        MMU060_TT       (0x00180000)    /* transfer type (TT) bits */
 #define        MMU060_TM       (0x00070000)    /* transfer modifier (TM) bits */
-#define        MMU060_IO       (0x00008000)    /* intruction or operand */
+#define        MMU060_IO       (0x00008000)    /* instruction or operand */
 #define        MMU060_PBE      (0x00004000)    /* push buffer bus error */
 #define        MMU060_SBE      (0x00002000)    /* store buffer bus error */
 #define        MMU060_PTA      (0x00001000)    /* pointer A fault */
index 653776c37bfce760699a58d5947524e8dddb3f83..f81ab33b9cb08ea932649808e5f2f0613a8e1f13 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: asi.h,v 1.15 1996/04/17 22:45:52 davem Exp $ */
+/* $Id: asi.h,v 1.16 1996/04/25 06:12:43 davem Exp $ */
 #ifndef _SPARC_ASI_H
 #define _SPARC_ASI_H
 
index 619f3b22574534418b577caec00781a302e8e72b..1989642ce4e906583c6186be6a5e96fe59958cbc 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: auxio.h,v 1.10 1996/01/03 03:52:58 davem Exp $
+/* $Id: auxio.h,v 1.11 1996/04/25 06:12:45 davem Exp $
  * auxio.h:  Definitions and code for the Auxiliary I/O register.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 663b61d1a2b9ad15371ab0316bebc6bbc9022c71..54a75be43abbcba45d53d87e532d08311773ee5e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: bsderrno.h,v 1.2 1995/11/25 02:31:17 davem Exp $
+/* $Id: bsderrno.h,v 1.3 1996/04/25 06:12:47 davem Exp $
  * bsderrno.h: Error numbers for NetBSD binary compatibility
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 9ad2ad54264efa5bf1f075ef7d2e9cc56e0fb0d0..eef46a21743180fbdc69fbf1102616e5732ecc13 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: cache.h,v 1.3 1995/11/25 02:31:22 davem Exp $
+/* $Id: cache.h,v 1.4 1996/04/25 06:12:49 davem Exp $
  * cache.h:  Cache specific code for the Sparc.  These include flushing
  *           and direct tag/data line access.
  *
index 0b58c7486086f371447fb8577d0cf64912b243d8..b9704b6c7a2b6c6ad3824cb9bd37a2ee6ec12bc5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: cypress.h,v 1.4 1996/03/12 17:48:12 davem Exp $
+/* $Id: cypress.h,v 1.5 1996/04/25 06:12:51 davem Exp $
  * cypress.h: Cypress module specific definitions and defines.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 29bb7c9d392403c22d224a155902c95e7b3eedfe..b7281ca99efc06d2ca1fed78a3673a9c04ba83d5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.15 1996/03/23 02:40:00 davem Exp $
+/* $Id: dma.h,v 1.16 1996/04/25 06:12:54 davem Exp $
  * include/asm-sparc/dma.h
  *
  * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
index 1bd3e0bc5935d5eb0cf71f8606d82158d5ac817d..8e27ceccb76d7e9401e5099103d66a69b7801914 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ecc.h,v 1.2 1995/11/25 02:31:37 davem Exp $
+/* $Id: ecc.h,v 1.3 1996/04/25 06:12:57 davem Exp $
  * ecc.h: Definitions and defines for the external cache/memory
  *        controller on the sun4m.
  *
index cfeeef6af52156646360096166c2c92b4ed598fd..ca8e00807843636385edd7d5dfa162592f6aa84f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: elf.h,v 1.2 1995/11/25 02:31:40 davem Exp $ */
+/* $Id: elf.h,v 1.3 1996/04/22 15:48:48 miguel Exp $ */
 #ifndef __ASMSPARC_ELF_H
 #define __ASMSPARC_ELF_H
 
@@ -15,4 +15,6 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
 typedef unsigned long elf_fpregset_t;
 
+#define elf_check_arch(x) ((x) == EM_SPARC)
+#define ELF_ARCH EM_SPARC
 #endif
index 19e6113b35047d12e6f38a5b3db191a05be90f5d..8e6aec9e65ffcff0ece5cf4cf1f85cba1cd9edec 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: head.h,v 1.26 1996/03/25 20:21:08 davem Exp $ */
+/* $Id: head.h,v 1.27 1996/04/25 06:13:06 davem Exp $ */
 #ifndef __SPARC_HEAD_H
 #define __SPARC_HEAD_H
 
index 0344433856bfce445fcda26be61860f799d52c80..6ba760db61e76322a7f5ec90aca428404d399edb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: irq.h,v 1.12 1996/04/03 02:17:34 davem Exp $
+/* $Id: irq.h,v 1.13 1996/04/25 06:13:09 davem Exp $
  * irq.h: IRQ registers on the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 52d34944e402f08c54e5258d5c5a579f04b5cba2..8301ecce164aa274897b1107fe3e17deb2ca21b7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mbus.h,v 1.6 1996/04/16 09:34:31 zaitcev Exp $
+/* $Id: mbus.h,v 1.7 1996/04/25 06:13:12 davem Exp $
  * mbus.h:  Various defines for MBUS modules.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 6f9adf6ba2d074429ca1658ca58e78c4f7bf6ca2..215e39fe2fe616ae68bdfba755e9eaf810ba1638 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: memreg.h,v 1.5 1995/12/02 20:05:25 davem Exp $ */
+/* $Id: memreg.h,v 1.6 1996/04/25 06:13:13 davem Exp $ */
 #ifndef _SPARC_MEMREG_H
 #define _SPARC_MEMREG_H
 /* memreg.h:  Definitions of the values found in the synchronous
index 2198ef59af243c584d78803d87068beb8aadac28..c69d6771ef8983ebb2579fa8182617f31633e65c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mman.h,v 1.6 1996/01/03 03:53:05 davem Exp $ */
+/* $Id: mman.h,v 1.7 1996/04/25 06:13:15 davem Exp $ */
 #ifndef __SPARC_MMAN_H__
 #define __SPARC_MMAN_H__
 
index e90aa01132a7cef25a70cfd08ebb667bd8efdcef..4cabb6a7d4580b904033d6af98b16b8f6d463daf 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mostek.h,v 1.4 1995/11/25 02:32:05 davem Exp $
+/* $Id: mostek.h,v 1.5 1996/04/25 06:13:17 davem Exp $
  * mostek.h:  Describes the various Mostek time of day clock registers.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff --git a/include/asm-sparc/mp.h b/include/asm-sparc/mp.h
deleted file mode 100644 (file)
index fc4c8a6..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* $Id: mp.h,v 1.3 1996/03/25 20:21:09 davem Exp $
- * mp.h:  Multiprocessing definitions for the Sparc.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-#ifndef _SPARC_MP_H
-#define _SPARC_MP_H
-
-#include <asm/traps.h>
-#include <asm/page.h>
-#include <asm/vaddrs.h>
-
-struct sparc_percpu {
-       struct tt_entry *trap_table;
-       char *kernel_stack[PAGE_SIZE<<1];
-       int cpuid;          /* Who am I? */
-       int cpu_is_alive;   /* Linux has fired it up. */
-       int cpu_is_idling;  /* Is sitting in the idle loop. */
-       /* More to come... */
-       char filler[PERCPU_ENTSIZE-(PAGE_SIZE*2)-0xc];
-};
-
-extern struct sparc_percpu *percpu_table;
-
-struct prom_cpuinfo {
-       int prom_node;
-       int mid;
-};
-
-extern struct prom_cpuinfo linux_cpus[NCPUS];
-
-#endif /* !(_SPARC_MP_H) */
index a8fa3240f33530d0e248e939dae9f060057f5e32..0e1bc5801d8a6806de81cac2e6c11f7fa09c8463 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mpmbox.h,v 1.3 1995/11/25 02:32:09 davem Exp $
+/* $Id: mpmbox.h,v 1.4 1996/04/25 06:13:19 davem Exp $
  * mpmbox.h:  Interface and defines for the OpenProm mailbox
  *               facilities for MP machines under Linux.
  *
index 63c31b6f2b28f87357a52a86ef3efed06d290fc2..7b273b650e88d4501e9ec9dd18a408aee51fecf6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mxcc.h,v 1.3 1996/04/20 10:15:44 davem Exp $
+/* $Id: mxcc.h,v 1.4 1996/04/25 06:13:21 davem Exp $
  * mxcc.h:  Definitions of the Viking MXCC registers
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 8362e02d2332193012075c86bd32617fde46884f..e30f681e403d0a5c111d9bef22113719db8c6468 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: openprom.h,v 1.15 1995/11/25 02:32:13 davem Exp $ */
+/* $Id: openprom.h,v 1.16 1996/04/23 01:54:46 davem Exp $ */
 #ifndef __SPARC_OPENPROM_H
 #define __SPARC_OPENPROM_H
 
index 51b2dc83d191046ffee8db6060df355c0f4d50ae..3504ef1faf0767a6492e5ef41b57680263f42338 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.7 1996/04/04 16:31:25 tridge Exp $
+/* $Id: oplib.h,v 1.8 1996/04/25 06:13:23 davem Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
index 84cc8dd242dad918b4f86583c2ffe636acb23947..d73c1f1c49dc99ad28f36099a5ddcf6e1e32b0ad 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pconf.h,v 1.2 1995/11/25 02:32:20 davem Exp $
+/* $Id: pconf.h,v 1.3 1996/04/25 06:13:25 davem Exp $
  * pconf.h: pathconf() and fpathconf() defines for SunOS
  *          system call compatibility.
  *
index 4ec29493e3c5ba436a45b7174a0d429a799b98a4..cb31df128d6d80679dc953d22e8be1cf560a0da9 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pgtsrmmu.h,v 1.16 1996/04/04 16:31:32 tridge Exp $
+/* $Id: pgtsrmmu.h,v 1.17 1996/04/25 06:13:26 davem Exp $
  * pgtsrmmu.h:  SRMMU page table defines and code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 758fc39ca58410531f805d523e37895aeadfb13c..b16592363a3a211e911ccf66e5ba6c2196c9bb48 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ptrace.h,v 1.19 1996/01/24 02:33:50 davem Exp $ */
+/* $Id: ptrace.h,v 1.20 1996/04/24 09:10:02 davem Exp $ */
 #ifndef _SPARC_PTRACE_H
 #define _SPARC_PTRACE_H
 
@@ -171,12 +171,8 @@ extern void show_regs(struct pt_regs *);
 #define SF_XXARG  0x5c
 
 /* Stuff for the ptrace system call */
-#if 0 /* Need to fix the header files a bit... */
-#undef PTRACE_ATTACH
-#undef PTRACE_DETACH
-#define PTRACE_ATTACH            10
-#define PTRACE_DETACH            11
-#endif
+#define PTRACE_SUNATTACH         10
+#define PTRACE_SUNDETACH         11
 #define PTRACE_GETREGS            12
 #define PTRACE_SETREGS            13
 #define PTRACE_GETFPREGS          14
index ee8295d3b8751be134863b8c7c84a850e1391ec2..0b2351d8215b61f9c3df456e92aaf8b2cea9a132 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: signal.h,v 1.20 1996/03/24 20:21:27 davem Exp $ */
+/* $Id: signal.h,v 1.21 1996/04/25 06:13:28 davem Exp $ */
 #ifndef _ASMSPARC_SIGNAL_H
 #define _ASMSPARC_SIGNAL_H
 
index 6a388efc11fa672f1ae6c759803f996f0b216e74..8abce7e4639f9362369c0668954057c0be6df201 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: solerrno.h,v 1.4 1996/03/23 02:40:09 davem Exp $
+/* $Id: solerrno.h,v 1.5 1996/04/25 06:13:32 davem Exp $
  * solerrno.h: Solaris error return codes for compatibility.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 8bdc39f3c17c10f621deeec96dd0a3bcf353bd4c..84673a3dba22d12f89c4ed3cd42ccc83dfac6513 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: traps.h,v 1.5 1995/11/25 02:33:05 davem Exp $
+/* $Id: traps.h,v 1.6 1996/04/25 06:13:33 davem Exp $
  * traps.h:  Format of entries for the Sparc trap table.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 2de3db6cbdccb64119cecda08c3cc4fb5c8b9b37..2c32f2276e47cf0e5ba97761d4f6b14b76606ec2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.20 1996/04/20 07:54:39 davem Exp $ */
+/* $Id: unistd.h,v 1.21 1996/04/25 06:13:35 davem Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
index 800ce142cf70f22b97640a55599501ff02d68172..ac434d40bdd1752f88f7bc8982387f22c3f7c160 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: vac-ops.h,v 1.10 1996/04/04 12:51:36 davem Exp $ */
+/* $Id: vac-ops.h,v 1.11 1996/04/25 06:13:38 davem Exp $ */
 #ifndef _SPARC_VAC_OPS_H
 #define _SPARC_VAC_OPS_H
 
index c7deddc72a79d3d553121d3f45a5a159e86f883f..6b0000c3c3551c37e6e14ff924a4d84772edea24 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: vaddrs.h,v 1.19 1996/03/26 06:51:58 miguel Exp $ */
+/* $Id: vaddrs.h,v 1.20 1996/04/25 06:13:40 davem Exp $ */
 #ifndef _SPARC_VADDRS_H
 #define _SPARC_VADDRS_H
 
index be3bf654df1e8a33fbd3ad46bf780679ff9a3e29..10253172734c250bed65610e77cf5b817ca9fe2e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: viking.h,v 1.12 1996/04/20 10:15:46 davem Exp $
+/* $Id: viking.h,v 1.13 1996/04/25 06:13:43 davem Exp $
  * viking.h:  Defines specific to the GNU/Viking MBUS module.
  *            This is SRMMU stuff.
  *
index b1e66ce622edc76135137c80e411b5a2634964cd..d2f5b562ef40e492a604721cd4e0455baa3c64af 100644 (file)
@@ -318,7 +318,7 @@ static void floppy_off(unsigned int nr);
 #define CURRENT_DEV DEVICE_NR(CURRENT->rq_dev)
 
 #ifdef DEVICE_INTR
-void (*DEVICE_INTR)(void) = NULL;
+static void (*DEVICE_INTR)(void) = NULL;
 #endif
 #ifdef DEVICE_TIMEOUT
 
index add2f6bb53bf25b3f1c749d8bbbb17366ec1766f..da47f8c399742ab9897ca2ebe5bd7d7a0bb5e7a9 100644 (file)
@@ -27,6 +27,8 @@
  * in linux/version.h, and should only be used by linux/version.c
  */
 
+/* Shouldn't these be defined somewhere in a i386 definition? */
+
 /* Don't touch these, unless you really know what you're doing. */
 #define DEF_INITSEG    0x9000
 #define DEF_SYSSEG     0x1000
index 102d60f32b6baad41d05a57266c778a0a07fde9b..f879fde222f187a91b5dd838d5106776ef785f7e 100644 (file)
@@ -101,6 +101,8 @@ struct consw {
     int    (*con_bmove)(struct vc_data *, int, int, int, int, int, int);
     int    (*con_switch)(struct vc_data *);
     int    (*con_blank)(int);
+    int    (*con_get_font)(struct vc_data *, int *, int *, char *);
+    int    (*con_set_font)(struct vc_data *, int, int, char *);
 };
 
 extern struct consw *conswitchp;
index 322c330512dce183a24a7ebd42a7cc9b2a1cf343..f97a313c60fea5fe877f9e46d4f218d8337b1dbd 100644 (file)
@@ -3,11 +3,6 @@
 
 /* Definitions of frame buffers                                                */
 
-#ifdef __KERNEL__
-#include <linux/config.h>
-#include <linux/fs.h>
-#endif
-
 /* ioctls
    0x46 is 'F'                                                         */
 #define FBIOGET_VSCREENINFO    0x4600
@@ -39,7 +34,8 @@ struct fb_fix_screeninfo {
        u_short xpanstep;               /* zero if no hardware panning  */
         u_short ypanstep;               /* zero if no hardware panning  */
         u_short ywrapstep;              /* zero if no hardware ywrap    */
-        short reserved[11];             /* Reserved for future compatibility */
+        u_long line_length;             /* length of a line in bytes    */
+        short reserved[9];              /* Reserved for future compatibility */
 };
 
 struct fb_bitfield {
@@ -78,6 +74,8 @@ struct fb_bitfield {
 #define FB_VMODE_MASK          255
 
 #define FB_VMODE_YWRAP         256     /* ywrap instead of panning     */
+#define FB_VMODE_SMOOTH_XPAN   512     /* smooth xpan possible (internally used) */
+#define FB_VMODE_CONUPDATE     512     /* don't update x/yoffset       */
 
 struct fb_var_screeninfo {
        int xres;                       /* visible resolution           */
@@ -128,12 +126,14 @@ struct fb_cmap {
 
 #ifdef __KERNEL__
 
+#include <linux/fs.h>
+
 struct fb_ops {
-       /* get non setable parameters   */
+       /* get non settable parameters  */
        int (*fb_get_fix) (struct fb_fix_screeninfo *, int); 
-       /* get setable parameters       */
+       /* get settable parameters      */
        int (*fb_get_var) (struct fb_var_screeninfo *, int);            
-       /* set setable parameters       */
+       /* set settable parameters      */
        int (*fb_set_var) (struct fb_var_screeninfo *, int);            
        /* get colormap                 */
        int (*fb_get_cmap) (struct fb_cmap *, int, int);
@@ -156,43 +156,6 @@ int unregister_framebuffer(int);
     */
 
 struct display {
-/*
- * As long as the old Amiga screen driver is being used, we have to
- * include these old parameters.
- */
-#if defined(CONFIG_AMIGA)
-  ushort scr_max_height;       /* screen dimensions */
-  ushort scr_max_width;
-  ushort scr_height;
-  ushort scr_width;
-  ushort scr_depth;
-  int bytes_per_row;           /* offset to one line below */
-  
-  ulong crsrcol;
-
-  ushort scroll_latch;         /* Vblank support for hardware scroll */
-  ushort y_wrap;
-  ushort cursor_latch;         /* Hardware cursor */
-  ushort *cursor, *dummy;
-  ushort cursor_flash;
-  ushort cursor_visible;
-
-  /* Some chipreg values we need to rebuild copper lists */
-  ushort diwstrt_v, diwstrt_h; /* display window control */
-  ushort diwstop_v, diwstop_h;
-  ushort bplcon0;              /* display mode */
-  ushort htotal;
-
-  u_char *bitplane[8];         /* pointers to display bitplanes */
-  ulong plane_size;
-
-  ushort *coplist1hdr;         /* List 1 static  component */
-  ushort *coplist1dyn;         /* List 1 dynamic component */
-  ushort *coplist2hdr;         /* List 2 static  component */
-  ushort *coplist2dyn;         /* List 2 dynamic component */
-
-#endif
-
    /* Filled in by the frame buffer device */
 
    struct fb_var_screeninfo var;    /* variable infos. yoffset and vmode */
@@ -204,6 +167,7 @@ struct display {
    int type_aux;                    /* Interleave for interleaved Planes */
    u_short ypanstep;                /* zero if no hardware ypan */
    u_short ywrapstep;               /* zero if no hardware ywrap */
+   u_long line_length;              /* length of a line in bytes */
    u_short can_soft_blank;          /* zero if no hardware blanking */
    u_short inverse;                 /* != 0 text black on white as default */
 
@@ -216,6 +180,7 @@ struct display {
    /* Filled in by the low-level console driver */
 
    struct vc_data *conp;            /* pointer to console data */
+   int vrows;                       /* number of virtual rows */
    int cursor_x;                    /* current cursor position */
    int cursor_y;
    int fgcol;                       /* text colors */
@@ -225,6 +190,7 @@ struct display {
    u_char *fontdata;                /* Font associated to this display */
    int fontheight;
    int fontwidth;
+   int userfont;                    /* != 0 if fontdata kmalloc()ed */
    struct display_switch *dispsw;   /* low level operations */
    u_short scrollmode;              /* Scroll Method */
    short yscroll;                   /* Hardware scrolling */
@@ -274,7 +240,11 @@ struct fb_fix_cursorinfo {
 };
 
 struct fb_var_cursorinfo {
-       u_long data[256];              /* max. 64x64 (ilbm, 2 planes)   */
+        u_short width;
+        u_short height;
+        u_short xspot;
+        u_short yspot;
+        u_char data[1];                 /* field with [height][width]        */
 };
 
 struct fb_cursorstate {
@@ -287,6 +257,31 @@ struct fb_cursorstate {
 #define FB_CURSOR_ON           1
 #define FB_CURSOR_FLASH                2
 
+#define FBCMD_DRAWLINE         0x4621
+#define FBCMD_MOVE             0x4622
+
+#define FB_LINE_XOR    1
+#define FB_LINE_BOX    2
+#define FB_LINE_FILLED 4
+
+struct fb_line {
+       int start_x;
+       int start_y;
+       int end_x;
+       int end_y;
+       int color;
+       int option;
+};
+
+struct fb_move {
+       int src_x;
+       int src_y;
+       int dest_x;
+       int dest_y;
+       int height;
+       int width;
+};
+
 #endif /* Preliminary */
 
 
index 75d1dd598c586c2f685368668cdb1afca35fb71d..a028fb2514ad26641ec8ddfcab333cd4cefc9f52 100644 (file)
@@ -9,13 +9,15 @@
  *             <drew@colorado.edu>
  */
 
+#include <linux/config.h>
+
 #define CONFIG_MSDOS_PARTITION 1
 
 #ifdef __alpha__
 #define CONFIG_OSF_PARTITION 1
 #endif
 
-#ifdef __sparc__
+#if defined(__sparc__) || defined(CONFIG_SMD_DISKLABEL)
 #define CONFIG_SUN_PARTITION 1
 #endif
 
@@ -64,6 +66,61 @@ struct gendisk {
        struct gendisk *next;
 };
 
+#ifdef CONFIG_BSD_DISKLABEL
+/*
+ * BSD disklabel support by Yossi Gottlieb <yogo@math.tau.ac.il>
+ */
+
+#define BSD_PARTITION          0xa5    /* Partition ID */
+
+#define BSD_DISKMAGIC  (0x82564557UL)  /* The disk magic number */
+#define BSD_MAXPARTITIONS      8
+#define BSD_FS_UNUSED          0       /* disklabel unused partition entry ID */
+struct bsd_disklabel {
+       __u32   d_magic;                /* the magic number */
+       __s16   d_type;                 /* drive type */
+       __s16   d_subtype;              /* controller/d_type specific */
+       char    d_typename[16];         /* type name, e.g. "eagle" */
+       char    d_packname[16];                 /* pack identifier */ 
+       __u32   d_secsize;              /* # of bytes per sector */
+       __u32   d_nsectors;             /* # of data sectors per track */
+       __u32   d_ntracks;              /* # of tracks per cylinder */
+       __u32   d_ncylinders;           /* # of data cylinders per unit */
+       __u32   d_secpercyl;            /* # of data sectors per cylinder */
+       __u32   d_secperunit;           /* # of data sectors per unit */
+       __u16   d_sparespertrack;       /* # of spare sectors per track */
+       __u16   d_sparespercyl;         /* # of spare sectors per cylinder */
+       __u32   d_acylinders;           /* # of alt. cylinders per unit */
+       __u16   d_rpm;                  /* rotational speed */
+       __u16   d_interleave;           /* hardware sector interleave */
+       __u16   d_trackskew;            /* sector 0 skew, per track */
+       __u16   d_cylskew;              /* sector 0 skew, per cylinder */
+       __u32   d_headswitch;           /* head switch time, usec */
+       __u32   d_trkseek;              /* track-to-track seek, usec */
+       __u32   d_flags;                /* generic flags */
+#define NDDATA 5
+       __u32   d_drivedata[NDDATA];    /* drive-type specific information */
+#define NSPARE 5
+       __u32   d_spare[NSPARE];        /* reserved for future use */
+       __u32   d_magic2;               /* the magic number (again) */
+       __u16   d_checksum;             /* xor of data incl. partitions */
+
+                       /* filesystem and partition information: */
+       __u16   d_npartitions;          /* number of partitions in following */
+       __u32   d_bbsize;               /* size of boot area at sn0, bytes */
+       __u32   d_sbsize;               /* max size of fs superblock, bytes */
+       struct  bsd_partition {         /* the partition table */
+               __u32   p_size;         /* number of sectors in partition */
+               __u32   p_offset;       /* starting sector */
+               __u32   p_fsize;        /* filesystem basic fragment size */
+               __u8    p_fstype;       /* filesystem type, see below */
+               __u8    p_frag;         /* filesystem fragments per block */
+               __u16   p_cpg;          /* filesystem cylinders per group */
+       } d_partitions[BSD_MAXPARTITIONS];      /* actually may be more */
+};
+
+#endif /* CONFIG_BSD_DISKLABEL */
+
 extern struct gendisk *gendisk_head;   /* linked list of disks */
 
 /*
index f52aad01df006f2d843aada573dde4e90816fafb..7f972a51b0e21117f13e5c49791b382ec363cac1 100644 (file)
@@ -22,6 +22,7 @@
 #ifndef _LINUX_IF_ARP_H
 #define _LINUX_IF_ARP_H
 
+
 /* ARP protocol HARDWARE identifiers. */
 #define ARPHRD_NETROM  0               /* from KA9Q: NET/ROM pseudo    */
 #define ARPHRD_ETHER   1               /* Ethernet 10Mbps              */
index a1af9b745ff3492d014be06199ac63ff4213b6da..906874b95bcc148cf509008b3c6276cef1f2fe88 100644 (file)
@@ -33,6 +33,7 @@
 #define XT_DISK_MAJOR  13
 #define SOUND_MAJOR    14
 #define CDU31A_CDROM_MAJOR 15
+#define JOYSTICK_MAJOR 15
 #define GOLDSTAR_CDROM_MAJOR 16
 #define OPTICS_CDROM_MAJOR 17
 #define SANYO_CDROM_MAJOR 18
 #define MATSUSHITA_CDROM3_MAJOR 27
 #define MATSUSHITA_CDROM4_MAJOR 28
 #define STL_SIOMEMMAJOR 28
+#define ACSI_MAJOR     28
 #define AZTECH_CDROM_MAJOR 29
-#define GRAPHDEV_MAJOR 29      /* SparcLinux /dev/fb */
+#define GRAPHDEV_MAJOR 29      /* SparcLinux & Linux/68k /dev/fb */
 #define CM206_CDROM_MAJOR 32
 #define IDE2_MAJOR     33
 #define IDE3_MAJOR     34
 #define NETLINK_MAJOR  36
 #define IDETAPE_MAJOR  37
+#define Z2RAM_MAJOR    37
 #define RISCOM8_NORMAL_MAJOR 48
 #define RISCOM8_CALLOUT_MAJOR 49
 #define APBLOCK_MAJOR   60   /* AP1000 Block device */
 #define DDV_MAJOR       61   /* AP1000 DDV block device */
+
 /*
  * Tests for SCSI devices.
  */
index 07c74e1165dad5ebe04b12a980d25d810727cf9e..f8ea74922e30c185b93308a6faf9c9701f9a546e 100644 (file)
@@ -5,6 +5,8 @@
 #define PSMOUSE_MINOR  1
 #define MS_BUSMOUSE_MINOR 2
 #define ATIXL_BUSMOUSE_MINOR 3
+#define AMIGAMOUSE_MINOR 4
+#define ATARIMOUSE_MINOR 5
 #define SUN_MOUSE_MINOR 6
 #define MISC_DYNAMIC_MINOR 255
 
index 8733a8a886d8683f109afc45707905535da986f9..0e936afe9175e245828f992eba3e25a29954e041 100644 (file)
@@ -4,6 +4,9 @@
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
+
+#ifdef __KERNEL__
+
 #include <linux/string.h>
 
 extern unsigned long high_memory;
@@ -11,8 +14,6 @@ extern unsigned long high_memory;
 #include <asm/page.h>
 #include <asm/atomic.h>
 
-#ifdef __KERNEL__
-
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1
 
index 267c33f30024e1446f756c24e772bfac6f2d7def..9164d5553a9484de754196639cf89b5397056a0c 100644 (file)
@@ -131,6 +131,10 @@ enum scsi_directory_inos {
        PROC_SCSI_NCR53C406A,
        PROC_SCSI_PPA,
        PROC_SCSI_ESP,
+       PROC_SCSI_A3000,
+       PROC_SCSI_A2091,
+       PROC_SCSI_GVP11,
+       PROC_SCSI_ATARI,
        PROC_SCSI_SCSI_DEBUG,   
        PROC_SCSI_NOT_PRESENT,
        PROC_SCSI_FILE,                        /* I'm assuming here that we */
index e6f60fb46bb0e4f03700742fc182135293e799e3..fd2d8a1783fec5a72b18f1ad78576acfad07d376 100644 (file)
@@ -269,6 +269,7 @@ struct task_struct {
 #define PF_EXITING     0x00000200      /* getting shut down */
 
 #define PF_USEDFPU     0x00100000      /* Process used the FPU this quantum (SMP only) */
+#define PF_DTRACE      0x00200000      /* delayed trace (used on m68k) */
 
 /*
  * Limit the stack by to some sane default: root can always
@@ -344,6 +345,7 @@ extern void wake_up_interruptible(struct wait_queue ** p);
 extern void wake_up_process(struct task_struct * tsk);
 
 extern void notify_parent(struct task_struct * tsk);
+extern void force_sig(unsigned long sig,struct task_struct * p);
 extern int send_sig(unsigned long sig,struct task_struct * p,int priv);
 extern int in_group_p(gid_t grp);
 
@@ -373,6 +375,7 @@ extern void copy_thread(int, unsigned long, unsigned long, struct task_struct *,
 extern void flush_thread(void);
 extern void exit_thread(void);
 
+extern void exit_mm(struct task_struct *);
 extern void exit_fs(struct task_struct *);
 extern void exit_files(struct task_struct *);
 extern void exit_sighand(struct task_struct *);
index cd3bdc4da6d9745ea1a48536ededcbd425eaf9f0..d61c6fb2514c36ee188ac2dd4a00ffc985ae9747 100644 (file)
  
 #ifndef _LINUX_SKBUFF_H
 #define _LINUX_SKBUFF_H
-#include <linux/malloc.h>
-#include <linux/wait.h>
-#include <linux/time.h>
+
 #include <linux/config.h>
+#include <linux/time.h>
 
 #include <asm/atomic.h>
 
@@ -131,6 +130,7 @@ struct sk_buff
 /*
  *     Handling routines are only of interest to the kernel
  */
+#include <linux/malloc.h>
 
 #include <asm/system.h>
 
index 0de6d4f557493825b61f649fd59c4809ce72fbb0..c532629e318d678f1e07ab85c3d2365a200562b5 100644 (file)
 /*
  * Modification history timex.h
  *
+ * 26 Sep 94   David L. Mills
+ *     Added defines for hybrid phase/frequency-lock loop.
+ *
+ * 19 Mar 94   David L. Mills
+ *     Moved defines from kernel routines to header file and added new
+ *     defines for PPS phase-lock loop.
+ *
+ * 20 Feb 94   David L. Mills
+ *     Revised status codes and structures for external clock and PPS
+ *     signal discipline.
+ *
+ * 28 Nov 93   David L. Mills
+ *     Adjusted parameters to improve stability and increase poll
+ *     interval.
+ *
  * 17 Sep 93    David L. Mills
  *      Created file $NTP/include/sys/timex.h
  * 07 Oct 93    Torsten Duwe
  *      Derived linux/timex.h
  * 1995-08-13    Torsten Duwe
- *      kernel PLL updated to 1994-12-13 specs (rfc-1489)
+ *      kernel PLL updated to 1994-12-13 specs (rfc-1589)
  */
 #ifndef _LINUX_TIMEX_H
 #define _LINUX_TIMEX_H
  * SHIFT_USEC defines the scaling (shift) of the time_freq and
  * time_tolerance variables, which represent the current frequency
  * offset and maximum frequency tolerance.
+ *
+ * FINEUSEC is 1 us in SHIFT_UPDATE units of the time_phase variable.
  */
-#define SHIFT_SCALE 22         /* shift for phase scale factor */
-#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* shift for offset scale factor */
+#define SHIFT_SCALE 22         /* phase scale (shift) */
+#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* time offset scale (shift) */
 #define SHIFT_USEC 16          /* frequency offset scale (shift) */
 #define FINEUSEC (1L << SHIFT_SCALE) /* 1 us in phase units */
 
 #define MAXPHASE 512000L        /* max phase error (us) */
-#define MAXFREQ (100L << SHIFT_USEC)  /* max frequency error (ppm) */
+#define MAXFREQ (512L << SHIFT_USEC)  /* max frequency error (ppm) */
 #define MAXTIME (200L << PPS_AVG) /* max PPS error (jitter) (200 us) */
 #define MINSEC 16L              /* min interval between updates (s) */
 #define MAXSEC 1200L            /* max interval between updates (s) */
@@ -171,6 +188,9 @@ struct timex {
 #define MOD_ESTERROR   ADJ_ESTERROR
 #define MOD_STATUS     ADJ_STATUS
 #define MOD_TIMECONST  ADJ_TIMECONST
+#define MOD_CLKB       ADJ_TICK
+#define MOD_CLKA       ADJ_OFFSET_SINGLESHOT /* 0x8000 in original */
+
 
 /*
  * Status codes (timex.status)
@@ -198,17 +218,19 @@ struct timex {
 /*
  * Clock states (time_state)
  */
-#define TIME_OK                0       /* clock synchronized */
+#define TIME_OK                0       /* clock synchronized, no leap second */
 #define TIME_INS       1       /* insert leap second */
 #define TIME_DEL       2       /* delete leap second */
 #define TIME_OOP       3       /* leap second in progress */
-#define TIME_WAIT      4       /* leap second has occurred */
+#define TIME_WAIT      4       /* leap second has occured */
 #define TIME_ERROR     5       /* clock not synchronized */
 #define TIME_BAD       TIME_ERROR /* bw compat */
 
 #ifdef __KERNEL__
 /*
  * kernel variables
+ * Note: maximum error = NTP synch distance = dispersion + delay / 2;
+ * estimated error = NTP dispersion.
  */
 extern long tick;                      /* timer interrupt period */
 extern int tickadj;                    /* amount of adjustment per tick */
index 5dc8fc6e3fde7fc137501a833696bf8a63318520..3688fa5942d62d33c179fddbb4899ef451dd513a 100644 (file)
@@ -153,7 +153,7 @@ struct ufs_superblock {
        ufsquad fs_qbmask;              /* ~usb_bmask - for use with __s64 size */
        ufsquad fs_qfmask;              /* ~usb_fmask - for use with __s64 size */
        __s32   fs_postblformat;        /* format of positional layout tables */
-       __s32   fs_nrpos;               /* number of rotaional positions */
+       __s32   fs_nrpos;               /* number of rotational positions */
        __s32   fs_postbloff;           /* (__s16) rotation block list head */
        __s32   fs_rotbloff;            /* (__u8) blocks for each rotation */
        __s32   fs_magic;               /* magic number */
index a4a0333dfad3562fb8edb6a4b064a79e80f899d8..fd0a4248a9a6bf08dc12a90f512a2bd6c86a7a55 100644 (file)
@@ -127,7 +127,6 @@ static __inline__ int max(unsigned int a, unsigned int b)
 
 extern struct proto tcp_prot;
 extern struct tcp_mib tcp_statistics;
-extern struct wait_queue *master_select_wakeup;
 
 extern void    tcp_err(int type, int code, unsigned char *header, __u32 daddr,
                        __u32, struct inet_protocol *protocol);
@@ -311,10 +310,6 @@ static __inline__ void tcp_set_state(struct sock *sk, int state)
        case TCP_ESTABLISHED:
                if (oldstate != TCP_ESTABLISHED) {
                        tcp_statistics.TcpCurrEstab++;
-                       /* This is a hack but it doesn't occur often and it's going to
-                          be a real        to fix nicely */
-                       if (oldstate == TCP_SYN_RECV)
-                               wake_up_interruptible(&master_select_wakeup);
                }
                break;
 
index 01042217029ebfbcd4335dd1d2a741319e06bd26..3175251b6e9ccb23691e327dc72fcbdd71c8645a 100644 (file)
@@ -121,6 +121,7 @@ extern void isp16_setup(char *str, int *ints);
 static void ramdisk_start_setup(char *str, int *ints);
 static void load_ramdisk(char *str, int *ints);
 static void prompt_ramdisk(char *str, int *ints);
+static void ramdisk_size(char *str, int *ints);
 #ifdef CONFIG_BLK_DEV_INITRD
 static void no_initrd(char *s,int *ints);
 #endif
@@ -132,6 +133,18 @@ extern void icn_setup(char *str, int *ints);
 extern void teles_setup(char *str, int *ints);
 #endif
 
+#ifdef CONFIG_ATARIMOUSE
+extern void atari_mouse_setup (char *str, int *ints);
+#endif
+#ifdef CONFIG_DMASOUND
+extern void dmasound_setup (char *str, int *ints);
+#endif
+#ifdef CONFIG_ATARI_SCSI
+extern void atari_scsi_setup (char *str, int *ints);
+#endif
+extern void wd33c93_setup (char *str, int *ints);
+extern void gvp11_setup (char *str, int *ints);
+
 #ifdef CONFIG_DIGI
 extern void pcxx_setup(char *str, int *ints);
 #endif
@@ -163,6 +176,7 @@ int rows, cols;
 #ifdef CONFIG_BLK_DEV_RAM
 extern int rd_doload;          /* 1 = load ramdisk, 0 = don't load */
 extern int rd_prompt;          /* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_size;            /* Size of the ramdisk(s) */
 extern int rd_image_start;     /* starting block # of image */
 #ifdef CONFIG_BLK_DEV_INITRD
 kdev_t real_root_dev;
@@ -224,6 +238,8 @@ struct {
        { "ramdisk_start=", ramdisk_start_setup },
        { "load_ramdisk=", load_ramdisk },
        { "prompt_ramdisk=", prompt_ramdisk },
+       { "ramdisk=", ramdisk_size },
+       { "ramdisk_size=", ramdisk_size },
 #ifdef CONFIG_BLK_DEV_INITRD
        { "noinitrd", no_initrd },
 #endif
@@ -346,6 +362,22 @@ struct {
 #ifdef CONFIG_ISDN_DRV_PCBIT
        { "pcbit=", pcbit_setup },
 #endif
+#ifdef CONFIG_ATARIMOUSE
+       { "atamouse=", atari_mouse_setup },
+#endif
+#ifdef CONFIG_DMASOUND
+       { "dmasound=", dmasound_setup },
+#endif
+#ifdef CONFIG_ATARI_SCSI
+       { "atascsi=", atari_scsi_setup },
+#endif
+#if defined(CONFIG_A3000_SCSI) || defined(CONFIG_A2091_SCSI) \
+           || defined(CONFIG_GVP11_SCSI)
+       { "wd33c93=", wd33c93_setup },
+#endif
+#if defined(CONFIG_GVP11_SCSI)
+       { "gvp11=", gvp11_setup },
+#endif
 #ifdef CONFIG_DIGI
        { "digi=", pcxx_setup },
 #endif
@@ -373,6 +405,13 @@ static void prompt_ramdisk(char *str, int *ints)
    if (ints[0] > 0 && ints[1] >= 0)
       rd_prompt = ints[1] & 1;
 }
+
+static void ramdisk_size(char *str, int *ints)
+{
+       if (ints[0] > 0 && ints[1] >= 0)
+               rd_size = ints[1];
+}
+
 #endif
 
 static int checksetup(char *line)
index 91eabfcb80e07cd12a39240d5fbf979fd8b1d626..396d20ad513c338ff8b94ac8c8cf4b079d01a140 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -454,7 +454,7 @@ static int shm_map (struct vm_area_struct *shmd)
                set_pte(page_table, __pte(shm_sgn));
        }
        flush_tlb_range(shmd->vm_mm, shmd->vm_start, shmd->vm_end);
-       return 0;
+       return error;
 }
 
 /*
index f8e6c439dfc8245c6e192b5ec3a1560bd0bcd037..d483a0b388ce4c3a8dd5ce18ac950b69aa687175 100644 (file)
@@ -49,6 +49,26 @@ static inline void generate(unsigned long sig, struct task_struct * p)
                wake_up_process(p);
 }
 
+/*
+ * Force a signal that the process can't ignore: if necessary
+ * we unblock the signal and change any SIG_IGN to SIG_DFL.
+ */
+void force_sig(unsigned long sig, struct task_struct * p)
+{
+       sig--;
+       if (p->sig) {
+               unsigned long mask = 1UL << sig;
+               struct sigaction *sa = p->sig->action + sig;
+               p->signal |= mask;
+               p->blocked &= ~mask;
+               if (sa->sa_handler == SIG_IGN)
+                       sa->sa_handler = SIG_DFL;
+               if (p->state == TASK_INTERRUPTIBLE)
+                       wake_up_process(p);
+       }
+}
+               
+
 int send_sig(unsigned long sig,struct task_struct * p,int priv)
 {
        if (!p || sig > 32)
@@ -428,17 +448,17 @@ void exit_sighand(struct task_struct *tsk)
        __exit_sighand(tsk);
 }
 
-static inline void exit_mm(void)
+static inline void __exit_mm(struct task_struct * tsk)
 {
-       struct mm_struct * mm = current->mm;
+       struct mm_struct * mm = tsk->mm;
 
        /* Set us up to use the kernel mm state */
        if (mm != &init_mm) {
                flush_cache_mm(mm);
                flush_tlb_mm(mm);
-               current->mm = &init_mm;
-               current->swappable = 0;
-               SET_PAGE_DIR(current, swapper_pg_dir);
+               tsk->mm = &init_mm;
+               tsk->swappable = 0;
+               SET_PAGE_DIR(tsk, swapper_pg_dir);
 
                /* free the old state - not used any more */
                if (!--mm->count) {
@@ -449,6 +469,11 @@ static inline void exit_mm(void)
        }
 }
 
+void exit_mm(struct task_struct *tsk)
+{
+       __exit_mm(tsk);
+}
+
 /* 
  * Send signals to all our closest relatives so that they know
  * to properly mourn us..
@@ -528,7 +553,7 @@ fake_volatile:
        del_timer(&current->real_timer);
        sem_exit();
        kerneld_exit();
-       exit_mm();
+       __exit_mm(current);
        __exit_files(current);
        __exit_fs(current);
        __exit_sighand(current);
index f1059dc15632e5ee5dfe7cfd3a6a7dc455800213..f58e7cea37ca3f79a6f9fe39963972e0e2fb4da7 100644 (file)
@@ -2,6 +2,8 @@
  *  linux/kernel/sched.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  1996-04-21 Modified by Ulrich Windl to make NTP work
  */
 
 /*
@@ -52,14 +54,15 @@ DECLARE_TASK_QUEUE(tq_scheduler);
 /*
  * phase-lock loop variables
  */
-int time_state = TIME_BAD;     /* clock synchronization status */
-int time_status = STA_UNSYNC | STA_PLL;        /* clock status bits */
+/* TIME_ERROR prevents overwriting the CMOS clock */
+int time_state = TIME_ERROR;   /* clock synchronization status */
+int time_status = STA_UNSYNC;  /* clock status bits */
 long time_offset = 0;          /* time adjustment (us) */
 long time_constant = 2;                /* pll time constant */
 long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */
 long time_precision = 1;       /* clock precision (us) */
-long time_maxerror = 0x70000000;/* maximum error */
-long time_esterror = 0x70000000;/* estimated error */
+long time_maxerror = MAXPHASE; /* maximum error (us) */
+long time_esterror = MAXPHASE; /* estimated error (us) */
 long time_phase = 0;           /* phase offset (scaled us) */
 long time_freq = 0;            /* frequency offset (scaled ppm) */
 long time_adj = 0;             /* tick adjust (scaled 1 / HZ) */
@@ -396,7 +399,8 @@ asmlinkage void schedule(void)
        return;
 
 scheduling_in_interrupt:
-       printk("Aiee: scheduling in interrupt\n");
+       printk("Aiee: scheduling in interrupt %p\n",
+               __builtin_return_address(0));
 }
 
 #ifndef __alpha__
@@ -665,9 +669,9 @@ static void second_overflow(void)
     long ltemp;
 
     /* Bump the maxerror field */
-    time_maxerror = (0x70000000-time_maxerror <
-                    time_tolerance >> SHIFT_USEC) ?
-       0x70000000 : (time_maxerror + (time_tolerance >> SHIFT_USEC));
+    time_maxerror += time_tolerance >> SHIFT_USEC;
+    if ( time_maxerror > MAXPHASE )
+        time_maxerror = MAXPHASE;
 
     /*
      * Leap second processing. If in leap-insert state at
@@ -704,7 +708,6 @@ static void second_overflow(void)
        break;
 
     case TIME_OOP:
-
        time_state = TIME_WAIT;
        break;
 
@@ -727,21 +730,17 @@ static void second_overflow(void)
        if (!(time_status & STA_FLL))
            ltemp >>= SHIFT_KG + time_constant;
        if (ltemp > (MAXPHASE / MINSEC) << SHIFT_UPDATE)
-           ltemp = (MAXPHASE / MINSEC) <<
-               SHIFT_UPDATE;
+           ltemp = (MAXPHASE / MINSEC) << SHIFT_UPDATE;
        time_offset += ltemp;
-       time_adj = -ltemp << (SHIFT_SCALE - SHIFT_HZ -
-                             SHIFT_UPDATE);
+       time_adj = -ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
     } else {
        ltemp = time_offset;
        if (!(time_status & STA_FLL))
            ltemp >>= SHIFT_KG + time_constant;
        if (ltemp > (MAXPHASE / MINSEC) << SHIFT_UPDATE)
-           ltemp = (MAXPHASE / MINSEC) <<
-               SHIFT_UPDATE;
+           ltemp = (MAXPHASE / MINSEC) << SHIFT_UPDATE;
        time_offset -= ltemp;
-       time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ -
-                            SHIFT_UPDATE);
+       time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
     }
 
     /*
@@ -775,6 +774,7 @@ static void second_overflow(void)
 #endif
 }
 
+/* in the NTP reference this is called "hardclock()" */
 static void update_wall_time_one_tick(void)
 {
        /*
index 331747c159725b9c28604ef1460700d10f7d07e1..931b52b4c785595a3e9899bffc72169e072b4b7a 100644 (file)
@@ -75,9 +75,9 @@ asmlinkage int sys_stime(int * tptr)
        cli();
        xtime.tv_sec = value;
        xtime.tv_usec = 0;
-       time_state = TIME_BAD;
-       time_maxerror = 0x70000000;
-       time_esterror = 0x70000000;
+       time_state = TIME_ERROR;
+       time_maxerror = MAXPHASE;
+       time_esterror = MAXPHASE;
        sti();
        return 0;
 }
@@ -317,7 +317,7 @@ asmlinkage int sys_adjtimex(struct timex *txc_p)
                    time_freq = time_tolerance;
                  else if (time_freq < -time_tolerance)
                    time_freq = -time_tolerance;
-               }
+               } /* STA_PLL || STA_PPSTIME */
            if (txc.modes & ADJ_TICK)
              tick = txc.tick;
 
index c8616b7ba98c1e81e28b99dff414ab4d3d5b009d..8bae43ef5f362b48b9e7e7e107ac7fb2a471dada 100644 (file)
@@ -424,8 +424,8 @@ static void profile_readahead(int async, struct file *filp)
  *   We try to have a limit of MAX_READWINDOW = 48K.
  */
 
-#define MAX_READWINDOW (PAGE_SIZE*32)
-#define MAX_READAHEAD (PAGE_SIZE*16)
+#define MAX_READWINDOW (PAGE_SIZE*12)
+#define MAX_READAHEAD (PAGE_SIZE*7)
 #define MIN_READAHEAD (PAGE_SIZE)
 
 static inline unsigned long generic_file_readahead(struct file * filp, struct inode * inode,
@@ -987,7 +987,7 @@ static int filemap_sync(struct vm_area_struct * vma, unsigned long address,
        unsigned long end = address + size;
        int error = 0;
 
-       dir = pgd_offset(current->mm, address);
+       dir = pgd_offset(vma->vm_mm, address);
        flush_cache_range(vma->vm_mm, end - size, end);
        while (address < end) {
                error |= filemap_sync_pmd_range(dir, address, end - address, vma, flags);
index 8fe9d3e54f2c49f4eaac2aea8bb19855ed96e34c..7957bb28645492124efb0a4a85f0dc176793c453 100644 (file)
@@ -931,7 +931,7 @@ void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
         */
        page = vma->vm_ops->nopage(vma, address, write_access && !(vma->vm_flags & VM_SHARED));
        if (!page) {
-               send_sig(SIGBUS, current, 1);
+               force_sig(SIGBUS, current);
                flush_cache_page(vma, address);
                put_page(page_table, BAD_PAGE);
                flush_tlb_page(vma, address);
index 7c9432a948b32d06d1fb2de50edfc7f364a3ec3a..69ba2561c6ecb7e8b1c033762e54d5b2b9a6812e 100644 (file)
@@ -6,12 +6,12 @@ Code Section          Bug Report Contact
 802 [other     ]       alan@cymru.net  
     [token ring        ]       needs a maintainer/debugger
 appletalk              alan@cymru.net and netatalk@umich.edu
-ax25                   g4klx@g4klx.demon.co.uk
+ax25                   jsn@cs.nott.ac.uk
 core                   alan@cymru.net
 ethernet               alan@cymru.net
 ipv4                   alan@cymru.net
 ipx                    alan@cymru.net,greg@caldera.com
-netrom                 g4klx@g4klx.demon.co.uk
+netrom                 jsn@cs.nott.ac.uk
 unix                   alan@cymru.net
 
 
index 187600fe2889e97c4b9bc2665066c2da8adff912..dd9f41ea1df5a9103961936fd49238e5e281de81 100644 (file)
@@ -614,7 +614,7 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
                        break;
 
                case AX25_T3:
-                       if (ax25_ctl.arg < 1
+                       if (ax25_ctl.arg < 0
                                return -EINVAL;
                        save_flags(flags); cli();
                        ax25->t3 = ax25_ctl.arg * PR_SLOWHZ;
@@ -624,10 +624,8 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
                        break;
 
                case AX25_IDLE:
-                       if (ax25_ctl.arg < 1
+                       if (ax25_ctl.arg < 0
                                return -EINVAL;
-                       if (ax25->idle == 0)
-                               return 0;
                        save_flags(flags); cli();
                        ax25->idle = ax25_ctl.arg * PR_SLOWHZ * 60;
                        if (ax25->idletimer != 0)
@@ -682,7 +680,7 @@ static ax25_cb *ax25_create_cb(void)
        ax25->n2      = AX25_DEF_N2;
        ax25->paclen  = AX25_DEF_PACLEN;
        ax25->maxqueue= AX25_DEF_IPMAXQUEUE;
-       ax25->idle    = 0;
+       ax25->idle    = AX25_DEF_IDLE;
 
        ax25->modulus   = AX25_DEF_AXDEFMODE;
        ax25->fragno    = 0;
@@ -753,9 +751,9 @@ static void ax25_fillin_cb(ax25_cb *ax25, struct device *dev)
        ax25->n2       = ax25_dev_get_value(dev, AX25_VALUES_N2);
        ax25->paclen   = ax25_dev_get_value(dev, AX25_VALUES_PACLEN);
        ax25->maxqueue = ax25_dev_get_value(dev, AX25_VALUES_IPMAXQUEUE);
+       ax25->idle     = ax25_dev_get_value(dev, AX25_VALUES_IDLE);
 
        ax25->dama_slave = 0;
-       ax25->idle = 0;
 
        ax25->modulus = ax25_dev_get_value(dev, AX25_VALUES_AXDEFMODE);
 
@@ -819,7 +817,7 @@ int ax25_send_frame(struct sk_buff *skb, ax25_address *src, ax25_address *dest,
 
        /* idle timeouts only for mode vc connections */
 
-       ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE);
+       ax25->idletimer = ax25->idle;
                
        ax25_insert_socket(ax25);
 
@@ -1196,7 +1194,8 @@ static struct sock *ax25_make_new(struct sock *osk, struct device *dev)
        ax25->idle    = osk->ax25->idle;
        ax25->paclen  = osk->ax25->paclen;
 
-       ax25->window  = osk->ax25->window;
+       ax25->window   = osk->ax25->window;
+       ax25->maxqueue = osk->ax25->maxqueue;
 
        ax25->source_addr = osk->ax25->source_addr;
        
@@ -1823,7 +1822,7 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a
                }
 
                ax25_fillin_cb(ax25, dev);
-               ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE);
+               ax25->idletimer = ax25->idle;
 #else
                if (mine) {
                        ax25_rt_rx_frame(&src, dev, &dp);
@@ -2272,7 +2271,6 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length, i
        int len = 0;
        off_t pos = 0;
        off_t begin = 0;
-       int idletimer;
 
        cli();
 
@@ -2283,9 +2281,6 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length, i
                        devname = "???";
                else
                        devname = dev->name;
-                       
-               idletimer = ax25->idletimer / (PR_SLOWHZ * 60);
-               idletimer += (ax25->idletimer && ax25->idletimer < ax25->idle)? 1:0;
 
                len += sprintf(buffer + len, "%-9s ",
                        ax2asc(&ax25->dest_addr));
@@ -2299,8 +2294,8 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length, i
                        ax25->t2      / PR_SLOWHZ,
                        ax25->t3timer / PR_SLOWHZ,
                        ax25->t3      / PR_SLOWHZ,
-                       idletimer,
-                       ax25->idle      / (PR_SLOWHZ*60),
+                       ax25->idletimer / (PR_SLOWHZ * 60),
+                       ax25->idle      / (PR_SLOWHZ * 60),
                        ax25->n2count, ax25->n2,
                        ax25->rtt     / PR_SLOWHZ,
                        ax25->window,
index 9757347af049ac24bf883b32931b599d2bbd7aee..d3053e19a1bad13856770cb9cc20c343437e44b0 100644 (file)
@@ -163,13 +163,14 @@ static int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
        unsigned char pid;
        
        if (skb == NULL) return 0;
+
+       ax25->idletimer = ax25->idle;
        
        pid = *skb->data;
 
        switch (pid) {
 #ifdef CONFIG_NETROM
                case AX25_P_NETROM:
-                       ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE);
                        if (ax25_dev_get_value(ax25->device, AX25_VALUES_NETROM)) {
                                skb_pull(skb, 1);       /* Remove PID */
                                queued = nr_route_frame(skb, ax25);
@@ -178,23 +179,19 @@ static int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
 #endif
 #ifdef CONFIG_INET
                case AX25_P_IP:
-                       ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE);
                        skb_pull(skb, 1);       /* Remove PID */
                        skb->h.raw = skb->data;
                        ax25_ip_mode_set(&ax25->dest_addr, ax25->device, 'V');
                        ip_rcv(skb, ax25->device, NULL);        /* Wrong ptype */
                        queued = 1;
-                       
                        break;
 #endif
                case AX25_P_SEGMENT:
-                       ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE);
                        skb_pull(skb, 1);       /* Remove PID */
                        queued = ax25_rx_fragment(ax25, skb);
                        break;
 
                default:
-                       ax25->idletimer = ax25->idle = 0;
                        if (ax25->sk != NULL && ax25_dev_get_value(ax25->device, AX25_VALUES_TEXT) && ax25->sk->protocol == pid) {
                                if (sock_queue_rcv_skb(ax25->sk, skb) == 0) {
                                        queued = 1;
index 823d682223b0fb1bf2e67bd74c1d6a913d2b6202..fd0f7cfa4bbff8baacf8bbe880020b032897341b 100644 (file)
@@ -77,21 +77,12 @@ void ax25_output(ax25_cb *ax25, struct sk_buff *skb)
        mtu = ax25->paclen;
        
        if ((skb->len - 1) > mtu) {
-               switch (*skb->data) {
-                       case AX25_P_SEGMENT:
-                               /* this is an error, but... */
-                               printk("ax25_output(): woops, fragmentation of fragment?!\n");
-                               /* okay, let's fragment it further (tss, tss...) */
-                       case AX25_P_NETROM:     /* err, is this a good idea? */
-                       case AX25_P_IP:
-                               mtu -= 2;       /* Allow for fragment control info */
-                               ka9qfrag = 1;
-                               break;
-                       default:
-                               ka9qfrag = 0;
-                               skb_pull(skb, 1); /* skip PID */
-                               break;
-
+               if (*skb->data == AX25_P_TEXT) {
+                       skb_pull(skb, 1); /* skip PID */
+                       ka9qfrag = 0;
+               } else {
+                       mtu -= 2;       /* Allow for fragment control info */
+                       ka9qfrag = 1;
                }
                
                fragno = skb->len / mtu;
@@ -105,11 +96,10 @@ void ax25_output(ax25_cb *ax25, struct sk_buff *skb)
                        /* 
                         * do _not_ use sock_alloc_send_skb, our socket may have
                         * sk->shutdown set...
-                        *
                         */
                        if ((skbn = alloc_skb(mtu + 2 + frontlen, GFP_ATOMIC)) == NULL) {
                                restore_flags(flags);
-                               printk("ax25_output(): alloc_skb returned NULL\n");
+                               printk("ax25_output: alloc_skb returned NULL\n");
                                if (skb_device_locked(skb))
                                        skb_device_unlock(skb);
                                return;
index 3b5237b8c2e1ef303eaefcbd87ed73e13c6baeba..aa34d77675a1b8e3c396c1f73ba724cf66e817da 100644 (file)
@@ -197,8 +197,7 @@ static void ax25_timer(unsigned long param)
 
                ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
 
-               if (ax25->sk != NULL)
-               {
+               if (ax25->sk != NULL) {
                        ax25->sk->state = TCP_CLOSE;
                        ax25->sk->err = 0;
                        if (!ax25->sk->dead)
@@ -208,7 +207,6 @@ static void ax25_timer(unsigned long param)
                }
        }
                                                                                                                                                                                                                                                                                                                                                        
-
        /* dl1bke 960114: DAMA T1 timeouts are handled in ax25_dama_slave_transmit */
        /*                nevertheless we have to re-enqueue the timer struct...   */
        
index e6fd0bea590965d2c295e2c4252435123eaf463f..2d9a0863fa99109ea642ef58f6d3fe20261fa8ab 100644 (file)
@@ -1065,6 +1065,8 @@ int br_receive_frame(struct sk_buff *skb) /* 3.5 */
                return(0);
 
        port = find_port(skb->dev);
+       
+       skb->arp = 1;           /* Received frame so it is resolved */
        skb->h.raw = skb->mac.raw;
        if (br_stats.flags & BR_DEBUG)
                printk("port %i src %02x:%02x:%02x:%02x:%02x:%02x\
index 166a3cc2165f7c40b46a05337f6af4ac96f0138b..7ada1a7b4447d9d8888fdd7c9894cc0fa2ae3155 100644 (file)
@@ -605,9 +605,21 @@ void net_bh(void)
                 
                if (br_stats.flags & BR_UP)
                {
+                       /*
+                        *      We pass the bridge a complete frame. This means
+                        *      recovering the MAC header first.
+                        */
+                        
+                       int offset=skb->data-skb->mac.raw;
                        cli();
+                       skb_push(skb,offset);   /* Put header back on for bridge */
                        if(br_receive_frame(skb))
                                continue;
+                       /*
+                        *      Pull the MAC header off for the copy going to
+                        *      the upper layers.
+                        */
+                       skb_pull(skb,offset);
                        sti();
                }
 #endif
@@ -621,9 +633,9 @@ void net_bh(void)
 
                skb->h.raw = skb->data;
 
-              /*
-                     Fetch the packet protocol ID. 
-               */
+               /*
+                *      Fetch the packet protocol ID. 
+                */
                
                type = skb->protocol;
 
index 2601f103392b7fee5340217f7b152c5e6f8dfd60..2e4f3265c608f6ab36a37f4afe72b1468445efd8 100644 (file)
@@ -35,11 +35,11 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode)
        {
                if(mode==VERIFY_READ) {
                        err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address);
-                       m->msg_name = address;
                } else
                        err=verify_area(mode, m->msg_name, m->msg_namelen);
                if(err<0)
                        return err;
+               m->msg_name = address;
        }
        if(m->msg_accrights!=NULL)
        {
index 96d054de246374f5675cbcf2c4866bff55637400..63ead6139bba3309ea3df23c29954d4a43e044e8 100644 (file)
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
-#include <asm/system.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/in.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+
 #include <net/ip.h>
 #include <net/protocol.h>
-#include <linux/string.h>
 #include <net/route.h>
 #include <net/tcp.h>
 #include <net/udp.h>
-#include <linux/skbuff.h>
 #include <net/sock.h>
 
+#include <asm/segment.h>
+#include <asm/system.h>
 
 /*
  *     Resource tracking variables
index 66a64e0fcfe4ed1e282945f4a79178424abd83c4..7b87d8934b46d77cec2ffc1c67f91b43736f6b81 100644 (file)
@@ -22,7 +22,7 @@ if [ "$CONFIG_NET_ALIAS" = "y" ]; then
        tristate 'IP: aliasing support' CONFIG_IP_ALIAS
 fi
 if [ "$CONFIG_KERNELD" = "y" ]; then
-       bool 'IP: ARP daemon support (experimental)' CONFIG_ARPD
+#      bool 'IP: ARP daemon support (experimental)' CONFIG_ARPD
 fi
 comment '(it is safe to leave these untouched)'
 bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP
index 953bc40a6242d11362f42cd165fc7311ee60ad70..5c4f4da75d3446ddc2c80a7f2124a8904ea130bf 100644 (file)
  *             Alan Cox        :       Multicast ping reply as self.
  *             Alan Cox        :       Fix atomicity lockup in ip_build_xmit call
  *             Alan Cox        :       Added 216,128 byte paths to the MTU code.
+ *             Martin Mares    :       RFC1812 checks.
+ *             Martin Mares    :       Can be configured to follow redirects if acting
+ *                                     as a router _without_ a routing protocol (RFC 1812).
+ *             Martin Mares    :       Echo requests may be configured to be ignored (RFC 1812).
+ *             Martin Mares    :       Limitation of ICMP error message transmit rate (RFC 1812).
+ *             Martin Mares    :       TOS and Precedence set correctly (RFC 1812).
  *
  *
  *
- * RFC1122 Status: (boy, are there a lot of rules for ICMP)
+ * RFC1122 (Host Requirements -- Comm. Layer) Status:
+ * (boy, are there a lot of rules for ICMP)
  *  3.2.2 (Generic ICMP stuff)
  *   MUST discard messages of unknown type. (OK)
  *   MUST copy at least the first 8 bytes from the offending packet
- *     when sending ICMP errors. (OK)
+ *     when sending ICMP errors. (OBSOLETE -- see RFC1812)
  *   MUST pass received ICMP errors up to protocol level. (OK)
- *   SHOULD send ICMP errors with TOS == 0. (OK)
+ *   SHOULD send ICMP errors with TOS == 0. (OBSOLETE -- see RFC1812)
  *   MUST NOT send ICMP errors in reply to:
  *     ICMP errors (OK)
  *     Broadcast/multicast datagrams (OK)
@@ -38,8 +45,8 @@
  *   All the rules govern the IP layer, and are dealt with in ip.c, not here.
  *  3.2.2.2 (Redirect)
  *   Host SHOULD NOT send ICMP_REDIRECTs.  (OK)
- *   MUST update routing table in response to host or network redirects. 
- *     (host OK, network NOT YET) [Intentionally -- AC]
+ *   MUST update routing table in response to host or network redirects.
+ *     (host OK, network OBSOLETE)
  *   SHOULD drop redirects if they're not from directly connected gateway
  *     (OK -- we drop it if it's not from our old gateway, which is close
  *      enough)
@@ -50,7 +57,7 @@
  *   MUST pass TIME_EXCEEDED to transport layer (OK)
  *   Other requirements dealt with at IP (generating TIME_EXCEEDED).
  * 3.2.2.5 (Parameter Problem)
- *   SHOULD generate these, but it doesn't say for what.  So we're OK. =)
+ *   SHOULD generate these (OK)
  *   MUST pass received PARAMPROBLEM to transport layer (NOT YET)
  *     [Solaris 2.X seems to assert EPROTO when this occurs] -- AC
  * 3.2.2.6 (Echo Request/Reply)
@@ -60,7 +67,7 @@
  *     We're OK for unicast ECHOs, and it doesn't say anything about
  *     how to handle broadcast ones, since it's optional.
  *   MUST copy data from REQUEST to REPLY (OK)
- *     unless it would require illegal fragmentation (N/A)
+ *     unless it would require illegal fragmentation (OK)
  *   MUST pass REPLYs to transport/user layer (OK)
  *   MUST use any provided source route (reversed) for REPLY. (NOT YET)
  * 3.2.2.7 (Information Request/Reply)
  *   MUST discard received REPLYs if not using this system (OK)
  *   MUST NOT send replies unless specifically made agent for this sort
  *     of thing. (OK)
+ *
+ *
+ * RFC 1812 (IPv4 Router Requirements) Status (even longer):
+ *  4.3.2.1 (Unknown Message Types)
+ *   MUST pass messages of unknown type to ICMP user iface or silently discard
+ *     them (OK)
+ *  4.3.2.2 (ICMP Message TTL)
+ *   MUST initialize TTL when originating an ICMP message (OK)
+ *  4.3.2.3 (Original Message Header)
+ *   SHOULD copy as much data from the offending packet as possible without
+ *     the length of the ICMP datagram exceeding 576 bytes (NOT YET)
+ *   MUST leave original IP header of the offending packet, but we're not
+ *     required to undo modifications made (OK)
+ *  4.3.2.4 (Original Message Source Address)
+ *   MUST use one of addresses for the interface the orig. packet arrived as
+ *     source address (OK)
+ *  4.3.2.5 (TOS and Precedence)
+ *   SHOULD leave TOS set to the same value unless the packet would be discarded
+ *     for that reason (OK)
+ *   MUST use TOS=0 if not possible to leave original value (OK)
+ *   MUST leave IP Precedence for Source Quench messages (OK -- not sent at all)
+ *   SHOULD use IP Precedence = 6 (Internetwork Control) or 7 (Network Control)
+ *     for all other error messages (OK, we use 6)
+ *   MAY allow configuration of IP Precedence (OK -- not done)
+ *   MUST leave IP Precedence and TOS for reply messages (OK)
+ *  4.3.2.6 (Source Route)
+ *   SHOULD use reverse source route UNLESS sending Parameter Problem on source
+ *     routing and UNLESS the packet would be immediately discarded (NOT YET)
+ *  4.3.2.7 (When Not to Send ICMP Errors)
+ *   MUST NOT send ICMP errors in reply to:
+ *     ICMP errors (OK)
+ *     Packets failing IP header validation tests unless otherwise noted (OK)
+ *     Broadcast/multicast datagrams (OK)
+ *     MAC broadcasts (OK)
+ *     Non-initial fragments (OK)
+ *     Datagram with a source address that isn't a single host. (OK)
+ *  4.3.2.8 (Rate Limiting)
+ *   SHOULD be able to limit error message rate (OK)
+ *   SHOULD allow setting of rate limits (OK, in the source)
+ *  4.3.3.1 (Destination Unreachable)
+ *   All the rules govern the IP layer, and are dealt with in ip.c, not here.
+ *  4.3.3.2 (Redirect)
+ *   MAY ignore ICMP Redirects if running a routing protocol or if forwarding
+ *     is enabled on the interface (OK -- ignores)
+ *  4.3.3.3 (Source Quench)
+ *   SHOULD NOT originate SQ messages (OK)
+ *   MUST be able to limit SQ rate if originates them (OK as we don't send them)
+ *   MAY ignore SQ messages it receives (OK -- we don't)
+ *  4.3.3.4 (Time Exceeded)
+ *   Requirements dealt with at IP (generating TIME_EXCEEDED).
+ *  4.3.3.5 (Parameter Problem)
+ *   MUST generate these for all errors not covered by other messages (OK)
+ *   MUST include original value of the value pointed by (OK)
+ *  4.3.3.6 (Echo Request)
+ *   MUST implement echo server function (OK)
+ *   MUST process at ER of at least max(576, MTU) (OK)
+ *   MAY reject broadcast/multicast ER's (We don't, but that's OK)
+ *   SHOULD have a config option for silently ignoring ER's (OK)
+ *   MUST have a default value for the above switch = NO (OK)
+ *   MUST have application layer interface for Echo Request/Reply (OK)
+ *   MUST reply using same source address as the request was sent to.
+ *     We're OK for unicast ECHOs, and it doesn't say anything about
+ *     how to handle broadcast ones, since it's optional.
+ *   MUST copy data from Request to Reply (OK)
+ *   SHOULD update Record Route / Timestamp options (??)
+ *   MUST use reversed Source Route for Reply if possible (NOT YET)
+ *  4.3.3.7 (Information Request/Reply)
+ *   SHOULD NOT originate or respond to these (OK)
+ *  4.3.3.8 (Timestamp / Timestamp Reply)
+ *   MAY implement (OK)
+ *   MUST reply to every Timestamp message received (OK)
+ *   MAY discard broadcast REQUESTs.  (OK, but see source for inconsistency)
+ *   MUST reply using same source address as the request was sent to. (OK)
+ *   MUST use reversed Source Route if possible (NOT YET)
+ *   SHOULD update Record Route / Timestamp options (??)
+ *   MUST pass REPLYs to transport/user layer (requires RAW, just like ECHO) (OK)
+ *   MUST update clock for timestamp at least 16 times/sec (OK)
+ *   MUST be "correct within a few minutes" (OK)
+ * 4.3.3.9 (Address Mask Request/Reply)
+ *   MUST have support for receiving AMRq and responding with AMRe (OK, but only as a
+ *     compile-time option)
+ *   SHOULD have option for each interface for AMRe's, MUST default to NO (NOT YET)
+ *   MUST NOT reply to AMRq before knows the correct AM (OK)
+ *   MUST NOT respond to AMRq with source address 0.0.0.0 and the AM's for
+ *     logical i-faces for the physical i-face are not the same (NOT YET)
+ *   SHOULD examine all AMRe's it receives and check them (NOT YET)
+ *   SHOULD log invalid AMRe's (AM+sender) (NOT YET)
+ *   MUST NOT use contents of AMRe to determine correct AM (OK)
+ *   MAY broadcast AMRe's after having configured address masks (OK -- doesn't)
+ *   MUST NOT do broadcast AMRe's if not set by extra option (OK, no option)
+ *   MUST use the { <NetPrefix>, -1 } form of broadcast addresses (OK)
+ * 4.3.3.10 (Router Advertisement and Solicitations)
+ *   MUST support router part of Router Discovery Protocol on all networks we
+ *     support broadcast or multicast addressing. (OK -- done by gated)
+ *   MUST have all config parameters with the respective defaults (OK)
+ * 5.2.7.1 (Destination Unreachable)
+ *   MUST generate DU's (OK)
+ *   SHOULD choose a best-match response code (OK)
+ *   SHOULD NOT generate Host Isolated codes (OK)
+ *   SHOULD use Communication Administratively Prohibited when administratively
+ *     filtering packets (NOT YET)
+ *   MAY include config option for not generating the above and silently discard
+ *     the packets instead (OK)
+ *   MAY include config option for not generating Precedence Violation and
+ *     Precedence Cutoff messages (OK as we don't generate them at all)
+ *   MUST use Host Unreachable or Dest. Host Unknown codes whenever other hosts
+ *     on the same network might be reachable (OK -- no net unreach's at all)
+ *   MUST use new form of Fragmentation Needed and DF Set messages (OK)
+ * 5.2.7.2 (Redirect)
+ *   MUST NOT generate network redirects (OK)
+ *   MUST be able to generate host redirects (OK)
+ *   SHOULD be able to generate Host+TOS redirects (NO as we don't use TOS)
+ *   MUST have an option to use Host redirects instead of Host+TOS ones (OK as
+ *     no Host+TOS Redirects are used)
+ *   MUST NOT generate redirects unless forwarding to the same i-face and the
+ *     dest. address is on the same subnet as the src. address and no source
+ *     routing is in use. (OK)
+ *   MUST NOT follow redirects when using a routing protocol (OK)
+ *   MAY use redirects if not using a routing protocol (OK, compile-time option)
+ *   MUST comply to Host Requirements when not acting as a router (OK)
+ *  5.2.7.3 (Time Exceeded)
+ *   MUST generate Time Exceeded Code 0 when discarding packet due to TTL=0 (OK)
+ *   MAY have a per-interface option to disable origination of TE messages, but
+ *     it MUST default to "originate" (OK -- we don't support it)
  */
 
 #include <linux/config.h>
@@ -141,6 +272,34 @@ struct icmp_err icmp_err_convert[] = {
  
 unsigned long dummy;
 
+/*
+ *     ICMP transmit rate limit control structures. We use a relatively simple
+ *     approach to the problem: For each type of ICMP message with rate limit
+ *     we count the number of messages sent during some time quantum. If this
+ *     count exceeds given maximal value, we ignore all messages not separated
+ *     from the last message sent at least by specified time.
+ */
+
+#define XRLIM_CACHE_SIZE 16            /* How many destination hosts do we cache */
+
+struct icmp_xrl_cache                  /* One entry of the ICMP rate cache */
+{
+       __u32 daddr;                    /* Destination address */
+       unsigned long counter;          /* Message counter */
+       unsigned long next_reset;       /* Time of next reset of the counter */
+       unsigned long last_access;      /* Time of last access to this entry (LRU) */
+       unsigned int restricted;        /* Set if we're in restricted mode */
+       unsigned long next_packet;      /* When we'll allow a next packet if restricted */
+};
+
+struct icmp_xrlim
+{
+       unsigned long timeout;          /* Time quantum for rate measuring */
+       unsigned long limit;            /* Maximal number of messages per time quantum allowed */
+       unsigned long delay;            /* How long we wait between packets when restricting */
+       struct icmp_xrl_cache cache[XRLIM_CACHE_SIZE];  /* Rate cache */
+};
+
 /*
  *     ICMP control array. This specifies what to do with each ICMP.
  */
@@ -150,7 +309,8 @@ struct icmp_control
        unsigned long *output;          /* Address to increment on output */
        unsigned long *input;           /* Address to increment on input */
        void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len);
-       unsigned long error;            /* This ICMP is classed as an error message */  
+       unsigned long error;            /* This ICMP is classed as an error message */
+       struct icmp_xrlim *xrlim;       /* Transmit rate limit control structure or NULL for no limits */
 };
 
 static struct icmp_control icmp_pointers[19];
@@ -182,6 +342,97 @@ struct socket icmp_socket;
  */
  
 
+/*
+ *     Initialize the transmit rate limitation mechanism.
+ */
+
+#ifndef CONFIG_NO_ICMP_LIMIT
+
+static void xrlim_init(void)
+{
+       int type, entry;
+       struct icmp_xrlim *xr;
+
+       for (type=0; type<=18; type++) {
+               xr = icmp_pointers[type].xrlim;
+               if (xr) {
+                       for (entry=0; entry<XRLIM_CACHE_SIZE; entry++)
+                               xr->cache[entry].daddr = INADDR_NONE;
+               }
+       }
+}
+
+/*
+ *     Check transmit rate limitation for given message.
+ *
+ *     RFC 1812: 4.3.2.8 SHOULD be able to limit error message rate
+ *                       SHOULD allow setting of rate limits (we allow in the source)
+ */
+
+static int xrlim_allow(int type, __u32 addr)
+{
+       struct icmp_xrlim *r;
+       struct icmp_xrl_cache *c;
+       unsigned long now;
+
+       if (type > 18)                  /* No time limit present */
+               return 1;
+       r = icmp_pointers[type].xrlim;
+       if (!r)
+               return 1;
+
+       for (c = r->cache; c < &r->cache[XRLIM_CACHE_SIZE]; c++)        /* Cache lookup */
+               if (c->daddr == addr)
+                       break;
+
+       now = jiffies;          /* Cache current time (saves accesses to volatile variable) */
+
+       if (c == &r->cache[XRLIM_CACHE_SIZE]) {         /* Cache miss */
+               unsigned long oldest = now;             /* Find the oldest entry to replace */
+               struct icmp_xrl_cache *d;
+               c = r->cache;
+               for (d = r->cache; d < &r->cache[XRLIM_CACHE_SIZE]; d++)
+                       if (!d->daddr) {                /* Unused entry */
+                               c = d;
+                               break;
+                       } else if (d->last_access < oldest) {
+                               oldest = d->last_access;
+                               c = d;
+                       }
+               c->last_access = now;                   /* Fill the entry with new data */
+               c->daddr = addr;
+               c->counter = 1;
+               c->next_reset = now + r->timeout;
+               c->restricted = 0;
+               return 1;
+       }
+
+       c->last_access = now;
+       if (c->next_reset > now) {                      /* Let's increment the counter */
+               c->counter++;
+               if (c->counter == r->limit) {           /* Limit exceeded, start restrictions */
+                       c->restricted = 1;
+                       c->next_packet = now + r->delay;
+                       return 0;
+               }
+               if (c->restricted) {                    /* Any restrictions pending? */
+                       if (c->next_packet > now)
+                               return 0;
+                       c->next_packet = now + r->delay;
+                       return 1;
+               }
+       } else {                                        /* Reset the counter */
+               if (c->counter < r->limit)              /* Switch off all restrictions */
+                       c->restricted = 0;
+               c->next_reset = now + r->timeout;
+               c->counter = 0;
+       }
+
+       return 1;                                       /* Send the packet */
+}
+
+#endif /* CONFIG_NO_ICMP_LIMIT */
+
 /*
  *     Maintain the counters used in the SNMP statistics for outgoing ICMP
  */
@@ -229,12 +480,13 @@ static void icmp_glue_bits(const void *p, __u32 saddr, char *to, unsigned int of
  *     Driving logic for building and sending ICMP messages.
  */
 
-static void icmp_build_xmit(struct icmp_bxm *icmp_param, __u32 saddr, __u32 daddr)
+static void icmp_build_xmit(struct icmp_bxm *icmp_param, __u32 saddr, __u32 daddr, __u8 tos)
 {
        struct sock *sk=icmp_socket.data;
        icmp_param->icmph.checksum=0;
        icmp_param->csum=0;
        icmp_out_count(icmp_param->icmph.type);
+       sk->ip_tos = tos;
        ip_build_xmit(sk, icmp_glue_bits, icmp_param, 
                icmp_param->data_len+sizeof(struct icmphdr),
                daddr, saddr, &icmp_param->replyopts, 0, IPPROTO_ICMP, 1);
@@ -309,7 +561,16 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info, s
                                return;
                }
        }
-       
+
+       /*
+        *      Check the rate limit
+        */
+
+#ifndef CONFIG_NO_ICMP_LIMIT
+       if (!xrlim_allow(type, iph->saddr))
+               return;
+#endif 
+
        /*
         *      Tell our driver what to send
         */
@@ -329,7 +590,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info, s
         */
 
        if (ip_options_echo(&icmp_param.replyopts, NULL, saddr, iph->saddr, skb_in) == 0)
-         icmp_build_xmit(&icmp_param, saddr, iph->saddr);
+         icmp_build_xmit(&icmp_param, saddr, iph->saddr, ((iph->tos & 0x38) | 6));
 }
 
 
@@ -491,10 +752,12 @@ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct dev
        iph = (struct iphdr *) (icmph + 1);
        ip = iph->daddr;
 
-#ifdef CONFIG_IP_FORWARD
        /*
-        *      We are a router. Routers should not respond to ICMP_REDIRECT messages.
+        *      If we are a router and we run a routing protocol, we MUST NOT follow redirects.
+        *      When using no routing protocol, we MAY follow redirects. (RFC 1812, 5.2.7.2)
         */
+
+#if defined(CONFIG_IP_FORWARD) && !defined(CONFIG_IP_DUMB_ROUTER)
        printk(KERN_INFO "icmp: ICMP redirect ignored. dest = %s, "
               "orig gw = %s, \"new\" gw = %s, device = %s.\n", in_ntoa(ip),
                in_ntoa(source), in_ntoa(icmph->un.gateway), dev->name);
@@ -505,7 +768,8 @@ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct dev
                        /*
                         *      This causes a problem with subnetted networks. What we should do
                         *      is use ICMP_ADDRESS to get the subnet mask of the problem route
-                        *      and set both. But we don't..
+                        *      and set both. But we don't.. [RFC1812 says routers MUST NOT
+                        *      generate Network Redirects]
                         */
 #ifdef not_a_good_idea
                        ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
@@ -548,18 +812,21 @@ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct dev
  *
  *     RFC 1122: 3.2.2.6 MUST have an echo server that answers ICMP echo requests.
  *     RFC 1122: 3.2.2.6 Data received in the ICMP_ECHO request MUST be included in the reply.
+ *     RFC 1812: 4.3.3.6 SHOULD have a config option for silently ignoring echo requests, MUST have default=NOT.
  *     See also WRT handling of options once they are done and working.
  */
  
 static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len)
 {
+#ifndef CONFIG_IP_IGNORE_ECHO_REQUESTS
        struct icmp_bxm icmp_param;
        icmp_param.icmph=*icmph;
        icmp_param.icmph.type=ICMP_ECHOREPLY;
        icmp_param.data_ptr=(icmph+1);
        icmp_param.data_len=len;
        if (ip_options_echo(&icmp_param.replyopts, NULL, daddr, saddr, skb)==0)
-               icmp_build_xmit(&icmp_param, daddr, saddr);
+               icmp_build_xmit(&icmp_param, daddr, saddr, skb->ip_hdr->tos);
+#endif
        kfree_skb(skb, FREE_READ);
 }
 
@@ -604,7 +871,7 @@ static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct de
        icmp_param.data_ptr=&times;
        icmp_param.data_len=12;
        if (ip_options_echo(&icmp_param.replyopts, NULL, daddr, saddr, skb)==0)
-               icmp_build_xmit(&icmp_param, daddr, saddr);
+               icmp_build_xmit(&icmp_param, daddr, saddr, skb->ip_hdr->tos);
        kfree_skb(skb,FREE_READ);
 }
 
@@ -623,8 +890,7 @@ static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct de
  
 static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len)
 {
-#ifdef CONFIG_IP_ADDR_AGENT
-       __u32 answer;
+#ifdef CONFIG_IP_ADDR_AGENT    /* Don't use, broken */
        struct icmp_bxm icmp_param;
        icmp_param.icmph.type=ICMP_ADDRESSREPLY;
        icmp_param.icmph.code=0;
@@ -633,7 +899,7 @@ static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct devi
        icmp_param.data_ptr=&dev->pa_mask;
        icmp_param.data_len=4;
        if (ip_options_echo(&icmp_param.replyopts, NULL, daddr, saddr, skb)==0)
-               icmp_build_xmit(&icmp_param, daddr, saddr);
+               icmp_build_xmit(&icmp_param, daddr, saddr, skb->iph->tos);
 #endif 
        kfree_skb(skb, FREE_READ);      
 }
@@ -668,7 +934,7 @@ int icmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
        }
        
        /*
-        *      18 is the highest 'known' icmp type. Anything else is a mystery
+        *      18 is the highest 'known' ICMP type. Anything else is a mystery
         *
         *      RFC 1122: 3.2.2  Unknown ICMP messages types MUST be silently discarded.
         */
@@ -711,44 +977,53 @@ int icmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
        return 0;
 }
 
+/*
+ *     This table defined limits of ICMP sending rate for various ICMP messages.
+ */
+
+static struct icmp_xrlim
+       xrl_unreach = { 4*HZ, 80, HZ/4 },               /* Host Unreachable */
+       xrl_redirect = { 2*HZ, 10, HZ/2 },              /* Redirect */
+       xrl_generic = { 3*HZ, 30, HZ/4 };               /* All other errors */
+
 /*
  *     This table is the definition of how we handle ICMP.
  */
  
 static struct icmp_control icmp_pointers[19] = {
 /* ECHO REPLY (0) */
- { &icmp_statistics.IcmpOutEchoReps, &icmp_statistics.IcmpInEchoReps, icmp_discard, 0 },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
+ { &icmp_statistics.IcmpOutEchoReps, &icmp_statistics.IcmpInEchoReps, icmp_discard, 0, NULL },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL },
 /* DEST UNREACH (3) */
- { &icmp_statistics.IcmpOutDestUnreachs, &icmp_statistics.IcmpInDestUnreachs, icmp_unreach, 1 },
+ { &icmp_statistics.IcmpOutDestUnreachs, &icmp_statistics.IcmpInDestUnreachs, icmp_unreach, 1, &xrl_unreach },
 /* SOURCE QUENCH (4) */
- { &icmp_statistics.IcmpOutSrcQuenchs, &icmp_statistics.IcmpInSrcQuenchs, icmp_unreach, 1 },
+ { &icmp_statistics.IcmpOutSrcQuenchs, &icmp_statistics.IcmpInSrcQuenchs, icmp_unreach, 1, NULL },
 /* REDIRECT (5) */
- { &icmp_statistics.IcmpOutRedirects, &icmp_statistics.IcmpInRedirects, icmp_redirect, 1 },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
+ { &icmp_statistics.IcmpOutRedirects, &icmp_statistics.IcmpInRedirects, icmp_redirect, 1, &xrl_redirect },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL },
 /* ECHO (8) */
- { &icmp_statistics.IcmpOutEchos, &icmp_statistics.IcmpInEchos, icmp_echo, 0 },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
+ { &icmp_statistics.IcmpOutEchos, &icmp_statistics.IcmpInEchos, icmp_echo, 0, NULL },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL },
 /* TIME EXCEEDED (11) */
- { &icmp_statistics.IcmpOutTimeExcds, &icmp_statistics.IcmpInTimeExcds, icmp_unreach, 1 },
+ { &icmp_statistics.IcmpOutTimeExcds, &icmp_statistics.IcmpInTimeExcds, icmp_unreach, 1, &xrl_generic },
 /* PARAMETER PROBLEM (12) */
 /* FIXME: RFC1122 3.2.2.5 - MUST pass PARAM_PROB messages to transport layer */
- { &icmp_statistics.IcmpOutParmProbs, &icmp_statistics.IcmpInParmProbs, icmp_discard, 1 },
+ { &icmp_statistics.IcmpOutParmProbs, &icmp_statistics.IcmpInParmProbs, icmp_discard, 1, &xrl_generic },
 /* TIMESTAMP (13) */
- { &icmp_statistics.IcmpOutTimestamps, &icmp_statistics.IcmpInTimestamps, icmp_timestamp, 0 },
+ { &icmp_statistics.IcmpOutTimestamps, &icmp_statistics.IcmpInTimestamps, icmp_timestamp, 0, NULL },
 /* TIMESTAMP REPLY (14) */
- { &icmp_statistics.IcmpOutTimestampReps, &icmp_statistics.IcmpInTimestampReps, icmp_discard, 0 },
+ { &icmp_statistics.IcmpOutTimestampReps, &icmp_statistics.IcmpInTimestampReps, icmp_discard, 0, NULL },
 /* INFO (15) */
- { &dummy, &dummy, icmp_discard, 0 },
+ { &dummy, &dummy, icmp_discard, 0, NULL },
 /* INFO REPLY (16) */
- { &dummy, &dummy, icmp_discard, 0 },
+ { &dummy, &dummy, icmp_discard, 0, NULL },
 /* ADDR MASK (17) */
- { &icmp_statistics.IcmpOutAddrMasks, &icmp_statistics.IcmpInAddrMasks, icmp_address, 0 },
+ { &icmp_statistics.IcmpOutAddrMasks, &icmp_statistics.IcmpInAddrMasks, icmp_address, 0, NULL },
 /* ADDR MASK REPLY (18) */
- { &icmp_statistics.IcmpOutAddrMaskReps, &icmp_statistics.IcmpInAddrMaskReps, icmp_discard, 0 }
+ { &icmp_statistics.IcmpOutAddrMaskReps, &icmp_statistics.IcmpInAddrMaskReps, icmp_discard, 0, NULL }
 };
 
 void icmp_init(struct proto_ops *ops)
@@ -762,5 +1037,8 @@ void icmp_init(struct proto_ops *ops)
        sk=icmp_socket.data;
        sk->allocation=GFP_ATOMIC;
        sk->num = 256;                  /* Don't receive any data */
+#ifndef CONFIG_NO_ICMP_LIMIT
+       xrlim_init();
+#endif
 }
 
index 741c235084a3cd771e18c467a814d8359f4dc473..919af64c8669062948790901d1239f43cbb3c9d7 100644 (file)
@@ -248,7 +248,6 @@ static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph, struct devi
        {
                NETDEBUG(printk("IP: create: no memory left !\n"));
                return(NULL);
-               skb->dev = qp->dev;
        }
        memset(qp, 0, sizeof(struct ipq));
 
index cec17ede68274d5adda22e372ee76f07ab52d9b3..713d141fd36f42fcfcdabe7b4d8fda233cef9397 100644 (file)
@@ -9,6 +9,9 @@
  *
  * Fixes:
  *             Many            :       Split from ip.c , see ip.c for history.
+ *             Martin Mares    :       TOS setting fixed.
+ *             Alan Cox        :       Fixed a couple of oopses in Martins 
+ *                                     TOS tweaks.
  */
 
 #include <linux/config.h>
@@ -89,8 +92,6 @@ int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length, int dum
  *     an IP socket.
  *
  *     We implement IP_TOS (type of service), IP_TTL (time to live).
- *
- *     Next release we will sort out IP_OPTIONS since for some people are kind of important.
  */
 
 static struct device *ip_mc_find_devfor(unsigned long addr)
@@ -177,14 +178,23 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
                                kfree_s(old_opt, sizeof(struct optlen) + old_opt->optlen);
                          return 0;
                  }
-               case IP_TOS:
-                       if(val<0||val>255)
+               case IP_TOS:            /* This sets both TOS and Precedence */
+                       if (val<0 || val>63)    /* Reject setting of unused bits */
                                return -EINVAL;
+                       if ((val&3) > 4 && !suser())    /* Only root can set Prec>4 */
+                               return -EPERM;
                        sk->ip_tos=val;
-                       if(val==IPTOS_LOWDELAY)
-                               sk->priority=SOPRI_INTERACTIVE;
-                       if(val==IPTOS_THROUGHPUT)
-                               sk->priority=SOPRI_BACKGROUND;
+                       switch (val & 0x38) {
+                               case IPTOS_LOWDELAY:
+                                       sk->priority=SOPRI_INTERACTIVE;
+                                       break;
+                               case IPTOS_THROUGHPUT:
+                                       sk->priority=SOPRI_BACKGROUND;
+                                       break;
+                               default:
+                                       sk->priority=SOPRI_NORMAL;
+                                       break;
+                       }
                        return 0;
                case IP_TTL:
                        if(val<1||val>255)
index 64b74eddc8d206a083b92de4c4f30560685587eb..f572acad455542a86339a3a4f52446232303040c 100644 (file)
@@ -436,12 +436,6 @@ struct tcp_mib     tcp_statistics;
 
 static void tcp_close(struct sock *sk, unsigned long timeout);
 
-/*
- *     The less said about this the better, but it works and will do for 1.2  (and 1.4 ;))
- */
-
-struct wait_queue *master_select_wakeup;
-
 /*
  *     Find someone to 'accept'. Must be called with
  *     the socket locked or with interrupts disabled
@@ -462,24 +456,6 @@ static struct sk_buff *tcp_find_established(struct sock *s)
        return NULL;
 }
 
-/*
- *     Remove a completed connection and return it. This is used by
- *     tcp_accept() to get connections from the queue.
- */
-
-static struct sk_buff *tcp_dequeue_established(struct sock *s)
-{
-       struct sk_buff *skb;
-       unsigned long flags;
-       save_flags(flags);
-       cli();
-       skb=tcp_find_established(s);
-       if(skb!=NULL)
-               skb_unlink(skb);        /* Take it off the queue */
-       restore_flags(flags);
-       return skb;
-}
-
 /*
  *     This routine closes sockets which have been at least partially
  *     opened, but not yet accepted. Currently it is only called by
@@ -685,14 +661,15 @@ static int tcp_readable(struct sock *sk)
 static int tcp_listen_select(struct sock *sk, int sel_type, select_table *wait)
 {
        if (sel_type == SEL_IN) {
-               int retval;
+               struct sk_buff * skb;
 
                lock_sock(sk);
-               retval = (tcp_find_established(sk) != NULL);
+               skb = tcp_find_established(sk);
                release_sock(sk);
-               if (!retval)
-                       select_wait(&master_select_wakeup,wait);
-               return retval;
+               if (skb)
+                       return 1;
+               select_wait(sk->sleep,wait);
+               return 0;
        }
        return 0;
 }
@@ -895,31 +872,53 @@ static void wait_for_tcp_memory(struct sock * sk)
  *     and starts the transmit system.
  */
 
-static int do_tcp_sendmsg(struct sock *sk, struct msghdr *msg,
-         int len, int nonblock, int flags)
+static int do_tcp_sendmsg(struct sock *sk,
+       int iovlen, struct iovec *iov,
+       int len, int nonblock, int flags)
 {
        int copied = 0;
-       int copy;
-       int tmp;
-       int seglen;
-       int iovct=0;
-       struct sk_buff *skb;
-       struct sk_buff *send_tmp;
-       struct proto *prot;
        struct device *dev = NULL;
-       unsigned char *from;
+
+       /*
+        *      Wait for a connection to finish.
+        */
+       while (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
+       {
+               if (sk->err)
+                       return sock_error(sk);
+
+               if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV)
+               {
+                       if (sk->keepopen)
+                               send_sig(SIGPIPE, current, 0);
+                       return -EPIPE;
+               }
+
+               if (nonblock)
+                       return -EAGAIN;
+
+               if (current->signal & ~current->blocked)
+                       return -ERESTARTSYS;
+
+               wait_for_tcp_connect(sk);
+       }
 
        /*
         *      Ok commence sending
         */
 
-       while(iovct<msg->msg_iovlen)
+       while (--iovlen >= 0)
        {
-               seglen=msg->msg_iov[iovct].iov_len;
-               from=msg->msg_iov[iovct++].iov_base;
-               prot = sk->prot;
+               int seglen=iov->iov_len;
+               unsigned char * from=iov->iov_base;
+               iov++;
+
                while(seglen > 0)
                {
+                       int copy, delay;
+                       int tmp;
+                       struct sk_buff *skb;
+
                        /*
                         * Stop on errors
                         */
@@ -940,33 +939,6 @@ static int do_tcp_sendmsg(struct sock *sk, struct msghdr *msg,
                                return -EPIPE;
                        }
 
-                       /*
-                        *      Wait for a connection to finish.
-                        */
-                       while (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
-                       {
-                               if (copied)
-                                       return copied;
-
-                               if (sk->err)
-                                       return sock_error(sk);
-
-                               if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV)
-                               {
-                                       if (sk->keepopen)
-                                               send_sig(SIGPIPE, current, 0);
-                                       return -EPIPE;
-                               }
-
-                               if (nonblock)
-                                       return -EAGAIN;
-
-                               if (current->signal & ~current->blocked)
-                                       return -ERESTARTSYS;
-
-                               wait_for_tcp_connect(sk);
-                       }
-
                /*
                 * The following code can result in copy <= if sk->mss is ever
                 * decreased.  It shouldn't be.  sk->mss is min(sk->mtu, sk->max_window).
@@ -1055,20 +1027,18 @@ static int do_tcp_sendmsg(struct sock *sk, struct msghdr *msg,
                                return -EFAULT;
                        }
 
-               /*
-                *      We should really check the window here also.
-                */
+                       /*
+                        *      We should really check the window here also.
+                        */
 
-                       send_tmp = NULL;
+                       delay = 0;
+                       tmp = copy + sk->prot->max_header + 15;
                        if (copy < sk->mss && !(flags & MSG_OOB) && sk->packets_out)
                        {
-                               skb = sock_wmalloc(sk, sk->mtu + 128 + prot->max_header + 15, 0, GFP_KERNEL);
-                               send_tmp = skb;
-                       }
-                       else
-                       {
-                               skb = sock_wmalloc(sk, copy + prot->max_header + 15 , 0, GFP_KERNEL);
+                               tmp = tmp - copy + sk->mtu + 128;
+                               delay = 1;
                        }
+                       skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL);
 
                        /*
                         *      If we didn't get any memory, we need to sleep.
@@ -1104,7 +1074,7 @@ static int do_tcp_sendmsg(struct sock *sk, struct msghdr *msg,
                         * Perhaps some hints here would be good.
                         */
 
-                       tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev,
+                       tmp = sk->prot->build_header(skb, sk->saddr, sk->daddr, &dev,
                                 IPPROTO_TCP, sk->opt, skb->truesize,sk->ip_tos,sk->ip_ttl,&sk->ip_route_cache);
                        if (tmp < 0 )
                        {
@@ -1143,9 +1113,9 @@ static int do_tcp_sendmsg(struct sock *sk, struct msghdr *msg,
                        skb->free = 0;
                        sk->write_seq += copy;
 
-                       if (send_tmp != NULL)
+                       if (delay)
                        {
-                               tcp_enqueue_partial(send_tmp, sk);
+                               tcp_enqueue_partial(skb, sk);
                                continue;
                        }
                        tcp_send_skb(sk, skb);
@@ -1186,7 +1156,7 @@ static int tcp_sendmsg(struct sock *sk, struct msghdr *msg,
        }
 
        lock_sock(sk);
-       retval = do_tcp_sendmsg(sk, msg, len, nonblock, flags);
+       retval = do_tcp_sendmsg(sk, msg->msg_iovlen, msg->msg_iov, len, nonblock, flags);
 
 /*
  *     Nagle's rule. Turn Nagle off with TCP_NODELAY for highly
@@ -1797,64 +1767,81 @@ static void tcp_close(struct sock *sk, unsigned long timeout)
 }
 
 
+/*
+ * Wait for a incoming connection, avoid race
+ * conditions. This must be called with the socket
+ * locked.
+ */
+static struct sk_buff * wait_for_connect(struct sock * sk)
+{
+       struct wait_queue wait = { current, NULL };
+       struct sk_buff * skb = NULL;
+
+       add_wait_queue(sk->sleep, &wait);
+       for (;;) {
+               current->state = TASK_INTERRUPTIBLE;
+               release_sock(sk);
+               schedule();
+               lock_sock(sk);
+               skb = tcp_find_established(sk);
+               if (skb)
+                       break;
+               if (current->signal & ~current->blocked)
+                       break;
+       }
+       remove_wait_queue(sk->sleep, &wait);
+       return skb;
+}
+
 /*
  *     This will accept the next outstanding connection.
+ *
+ *     Be careful about race conditions here - this is subtle.
  */
 
 static struct sock *tcp_accept(struct sock *sk, int flags)
 {
-       struct sock *newsk;
+       int error;
        struct sk_buff *skb;
+       struct sock *newsk = NULL;
 
   /*
    * We need to make sure that this socket is listening,
    * and that it has something pending.
    */
 
+       error = EINVAL;
        if (sk->state != TCP_LISTEN)
-       {
-               sk->err = EINVAL;
-               return(NULL);
-       }
+               goto no_listen;
 
-       /* Avoid the race. */
-       cli();
        lock_sock(sk);
 
-       while((skb = tcp_dequeue_established(sk)) == NULL)
-       {
-               if (flags & O_NONBLOCK)
-               {
-                       sti();
-                       release_sock(sk);
-                       sk->err = EAGAIN;
-                       return(NULL);
-               }
-
+       skb = tcp_find_established(sk);
+       if (skb) {
+got_new_connect:
+               __skb_unlink(skb, &sk->receive_queue);
+               newsk = skb->sk;
+               kfree_skb(skb, FREE_READ);
+               sk->ack_backlog--;
+               error = 0;
+out:
                release_sock(sk);
-               interruptible_sleep_on(sk->sleep);
-               if (current->signal & ~current->blocked)
-               {
-                       sti();
-                       sk->err = ERESTARTSYS;
-                       return(NULL);
-               }
-               lock_sock(sk);
-       }
-       sti();
-
-       /*
-        *      Now all we need to do is return skb->sk.
-        */
-
-       newsk = skb->sk;
+no_listen:
+               sk->err = error;
+               return newsk;
+       }
 
-       kfree_skb(skb, FREE_READ);
-       sk->ack_backlog--;
-       release_sock(sk);
-       return(newsk);
+       error = EAGAIN;
+       if (flags & O_NONBLOCK)
+               goto out;
+       skb = wait_for_connect(sk);
+       if (skb)
+               goto got_new_connect;
+       error = ERESTARTSYS;
+       goto out;
 }
 
+
 /*
  *     This will initiate an outgoing connection.
  */
index 4e83574836f1573d69ee4fc9b8edbebce8a7ff32..f5e9efb0a8da8fba0361b9eca6156f82e47f526b 100644 (file)
@@ -1137,8 +1137,9 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned int flags)
        if(msg_sys.msg_iovlen>MAX_IOVEC)
                return -EINVAL;
 
-       err=verify_iovec(&msg_sys,iov,address, VERIFY_READ);
-       if(err<0)
+       /* This will also move the address data into kernel space */
+       err = verify_iovec(&msg_sys, iov, address, VERIFY_READ);
+       if (err < 0)
                return err;
        total_len=err;
 
@@ -1153,13 +1154,19 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
 {
        struct socket *sock;
        struct file *file;
-       char address[MAX_SOCK_ADDR];
        struct iovec iov[MAX_IOVEC];
        struct msghdr msg_sys;
        int err;
        int total_len;
-       int addr_len;
        int len;
+
+       /* kernel mode address */
+       char addr[MAX_SOCK_ADDR];
+       int addr_len;
+
+       /* user mode address pointers */
+       struct sockaddr *uaddr;
+       int *uaddr_len;
        
        if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL))
                return(-EBADF);
@@ -1172,9 +1179,17 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
        memcpy_fromfs(&msg_sys,msg,sizeof(struct msghdr));
        if(msg_sys.msg_iovlen>MAX_IOVEC)
                return -EINVAL;
-       err=verify_iovec(&msg_sys,iov,address, VERIFY_WRITE);
+
+       /*
+        * save the user-mode address (verify_iovec will change the
+        * kernel msghdr to use the kernel address space)
+        */
+       uaddr = msg_sys.msg_name;
+       uaddr_len = &msg->msg_namelen;
+       err=verify_iovec(&msg_sys,iov,addr, VERIFY_WRITE);
        if(err<0)
                return err;
+
        total_len=err;
        
        if(sock->ops->recvmsg==NULL)
@@ -1182,11 +1197,12 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
        len=sock->ops->recvmsg(sock, &msg_sys, total_len, (file->f_flags&O_NONBLOCK), flags, &addr_len);
        if(len<0)
                return len;
-       /*
-        *      Fixme: writing actual length into original msghdr.
-        */
-       if(msg_sys.msg_name!=NULL && (err=move_addr_to_user(address,addr_len, msg_sys.msg_name, &msg_sys.msg_namelen))<0)
-               return err;
+
+       if (uaddr != NULL) {
+               err = move_addr_to_user(addr, addr_len, uaddr, uaddr_len);
+               if (err)
+                       return err;
+       }
        return len;
 }
 
index a227ec58117dcf65ce0b12c8e5001d41011cfb7c..ad4380870380cccc8bb79606db5f2ecec59b0d24 100644 (file)
@@ -199,7 +199,7 @@ dialog_menu (const char *title, const char *prompt, int height, int width,
     while (key != ESC) {
        key = wgetch(dialog);
 
-       if (isalpha(key)) key = tolower(key);
+       if (key < 256 && isalpha(key)) key = tolower(key);
 
        if (strchr("ynm", key))
                i = max_choice;
index 41274d870ab18fe24e1f00c776294b26531d9673..b3a7af9d2ddaa1ea9057c2dbf958b155007e8f99 100644 (file)
@@ -347,8 +347,8 @@ first_alpha(const char *string, const char *exempt)
        for (i = 0; i < strlen(string); i++) {
                c = tolower(string[i]);
 
-               if (c == '(') ++in_paren;
-               if (c == ')') --in_paren;
+               if (strchr("<[(", c)) ++in_paren;
+               if (strchr(">])", c)) --in_paren;
 
                if ((! in_paren) && isalpha(c) && 
                     strchr(exempt, c) == 0)